[med-svn] [nanopolish] 01/04: Imported Upstream version 0.4.0

Afif Elghraoui afif-guest at moszumanska.debian.org
Tue Jan 19 09:04:58 UTC 2016


This is an automated email from the git hooks/post-receive script.

afif-guest pushed a commit to branch master
in repository nanopolish.

commit cd31d651d8e7543e7190f6e04d6667c017ffac02
Author: Afif Elghraoui <afif at ghraoui.name>
Date:   Mon Jan 18 18:24:28 2016 -0800

    Imported Upstream version 0.4.0
---
 .gitignore                                         |   18 +
 .gitmodules                                        |    6 +
 .travis.yml                                        |   11 +
 Dockerfile                                         |    8 +
 LICENSE                                            |   21 +
 Makefile                                           |  112 +
 README.md                                          |   59 +
 scripts/consensus-preprocess.pl                    |   26 +
 scripts/consensus.make                             |   50 +
 scripts/nanopolish_makerange.py                    |   19 +
 scripts/nanopolish_merge.py                        |  107 +
 src/alignment/nanopolish_alignment_db.cpp          |  445 +
 src/alignment/nanopolish_alignment_db.h            |  118 +
 src/alignment/nanopolish_anchor.cpp                |  314 +
 src/alignment/nanopolish_anchor.h                  |  105 +
 src/alignment/nanopolish_eventalign.cpp            |  891 ++
 src/alignment/nanopolish_eventalign.h              |   84 +
 src/common/logsum.cpp                              |  384 +
 src/common/logsum.h                                |   68 +
 src/common/nanopolish_alphabet.cpp                 |   55 +
 src/common/nanopolish_alphabet.h                   |  192 +
 src/common/nanopolish_common.cpp                   |   30 +
 src/common/nanopolish_common.h                     |  111 +
 src/common/nanopolish_fast5_map.cpp                |  135 +
 src/common/nanopolish_fast5_map.h                  |   39 +
 src/common/nanopolish_iupac.cpp                    |   92 +
 src/common/nanopolish_iupac.h                      |   30 +
 src/common/nanopolish_klcs.cpp                     |   86 +
 src/common/nanopolish_klcs.h                       |   27 +
 src/common/nanopolish_matrix.h                     |  102 +
 src/common/nanopolish_variant.cpp                  |  298 +
 src/common/nanopolish_variant.h                    |  115 +
 src/common/profiler.h                              |   70 +
 src/common/progress.h                              |   82 +
 src/hmm/nanopolish_emissions.h                     |  109 +
 src/hmm/nanopolish_hmm_input_sequence.h            |   85 +
 src/hmm/nanopolish_profile_hmm.cpp                 |  271 +
 src/hmm/nanopolish_profile_hmm.h                   |  103 +
 src/hmm/nanopolish_profile_hmm.inl                 |  403 +
 src/hmm/nanopolish_transition_parameters.cpp       |  376 +
 src/hmm/nanopolish_transition_parameters.h         |  112 +
 src/main/nanopolish.cpp                            |   63 +
 src/nanopolish_call_variants.cpp                   |  410 +
 src/nanopolish_call_variants.h                     |   13 +
 src/nanopolish_consensus.cpp                       |  875 ++
 src/nanopolish_consensus.h                         |   14 +
 src/nanopolish_getmodel.cpp                        |  123 +
 src/nanopolish_getmodel.h                          |   14 +
 src/nanopolish_haplotype.cpp                       |  123 +
 src/nanopolish_haplotype.h                         |   75 +
 src/nanopolish_methyltest.cpp                      |  539 ++
 src/nanopolish_methyltest.h                        |   13 +
 src/nanopolish_methyltrain.cpp                     |  770 ++
 src/nanopolish_methyltrain.h                       |   25 +
 src/nanopolish_poremodel.cpp                       |  169 +
 src/nanopolish_poremodel.h                         |   93 +
 src/nanopolish_squiggle_read.cpp                   |  209 +
 src/nanopolish_squiggle_read.h                     |  133 +
 src/test/catch.hpp                                 | 9460 ++++++++++++++++++++
 src/test/nanopolish_test.cpp                       |  179 +
 src/thirdparty/stdaln.c                            | 1071 +++
 src/thirdparty/stdaln.h                            |  162 +
 ...C_Ecoli_K12_R7.3_2549_1_ch8_file30_strand.fast5 |  Bin 0 -> 1850695 bytes
 63 files changed, 20302 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3b87bc6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+
+# Backup files
+.*swp
+.*swo
+.*swm
+
+# Generated files
+*.o
+.depend
+nanopolish
+nanopolish_test
+
+# libhdf5 directories
+bin/
+hdf5-*/
+include/
+lib/
+share/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..5e1035e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "htslib"]
+	path = htslib
+	url = https://github.com/samtools/htslib
+[submodule "fast5"]
+	path = fast5
+	url = https://github.com/mateidavid/fast5
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..41963ab
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+# travis.yml for github.com/jts/nanopolish
+
+language: cpp
+
+# Install and export newer gcc
+before_install:
+    - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+    - sudo apt-get update -qq
+    - sudo apt-get install -qq g++-4.8
+
+script: make CXX=g++-4.8 nanopolish && make CXX=g++-4.8 test
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..320e34f
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,8 @@
+FROM centos:7
+WORKDIR /
+RUN yum group install "Development Tools" -y
+RUN yum install git wget tar zlib-devel -y
+RUN git clone --recursive https://github.com/jts/nanopolish.git
+WORKDIR /nanopolish
+RUN make libhdf5.install nanopolish
+CMD ./nanopolish
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8037261
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Ontario Institute for Cancer Research
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. 
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..40670fc
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,112 @@
+#
+
+# Sub directories containing source code, except for the main programs
+SUBDIRS := src src/hmm src/thirdparty src/common src/alignment
+
+#
+# Set libraries, paths, flags and options
+#
+
+#Basic flags every build needs
+LIBS=-lz
+CXXFLAGS = -g -O3
+CXXFLAGS += -std=c++11 -fopenmp
+CFLAGS=-O3
+CXX=g++
+CC=gcc
+HDF5=install
+
+# Check operating system, OSX doesn't have -lrt
+UNAME_S := $(shell uname -s)
+ifeq ($(UNAME_S),Linux)
+    LIBS += -lrt
+endif
+
+# Default to automatically installing hdf5
+ifeq ($(HDF5), install)
+    H5_LIB=./lib/libhdf5.a
+    H5_INCLUDE=-I./include
+    LIBS += -ldl
+else
+    # Use system-wide hdf5
+    H5_LIB=
+    H5_INCLUDE=
+    LIBS += -lhdf5
+endif
+
+# Bulild and link the libhts submodule
+HTS_LIB=./htslib/libhts.a
+HTS_INCLUDE=-I./htslib
+
+# Include the header-only fast5 library
+FAST5_INCLUDE=-I./fast5
+
+# Include the src subdirectories
+NP_INCLUDE=$(addprefix -I./, $(SUBDIRS))
+
+# Add include flags
+CPPFLAGS += $(H5_INCLUDE) $(HTS_INCLUDE) $(FAST5_INCLUDE) $(NP_INCLUDE)
+
+# Main programs to build
+PROGRAM=nanopolish
+TEST_PROGRAM=nanopolish_test
+
+all: $(PROGRAM) $(TEST_PROGRAM)
+
+#
+# Build libhts
+#
+htslib/libhts.a:
+	cd htslib; make
+
+#
+# If this library is a dependency the user wants HDF5 to be downloaded and built.
+#
+lib/libhdf5.a:
+	wget https://www.hdfgroup.org/ftp/HDF5/releases/hdf5-1.8.14/src/hdf5-1.8.14.tar.gz
+	tar -xzf hdf5-1.8.14.tar.gz
+	cd hdf5-1.8.14; ./configure --enable-threadsafe --prefix=`pwd`/..; make; make install
+
+#
+# Source files
+#
+
+# Find the source files by searching subdirectories
+CPP_SRC := $(foreach dir, $(SUBDIRS), $(wildcard $(dir)/*.cpp))
+C_SRC := $(foreach dir, $(SUBDIRS), $(wildcard $(dir)/*.c))
+EXE_SRC=src/main/nanopolish.cpp src/test/nanopolish_test.cpp
+
+# Automatically generated object names
+CPP_OBJ=$(CPP_SRC:.cpp=.o)
+C_OBJ=$(C_SRC:.c=.o)
+
+# Generate dependencies
+PHONY=depend
+depend: .depend
+
+.depend: $(CPP_SRC) $(C_SRC) $(EXE_SRC) $(H5_LIB)
+	rm -f ./.depend
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $(CPP_SRC) $(C_SRC) > ./.depend;
+
+include .depend
+
+# Compile objects
+.cpp.o:
+	$(CXX) -o $@ -c $(CXXFLAGS) $(CPPFLAGS) -fPIC $<
+
+.c.o:
+	$(CC) -o $@ -c $(CFLAGS) -fPIC $<
+
+# Link main executable
+$(PROGRAM): src/main/nanopolish.o $(CPP_OBJ) $(C_OBJ) $(HTS_LIB) $(H5_LIB)
+	$(CXX) -o $@ $(CXXFLAGS) $(CPPFLAGS) -fPIC $< $(CPP_OBJ) $(C_OBJ) $(HTS_LIB) $(H5_LIB) $(LIBS)
+
+# Link test executable
+$(TEST_PROGRAM): src/test/nanopolish_test.o $(CPP_OBJ) $(C_OBJ) $(HTS_LIB) $(H5_LIB)
+	$(CXX) -o $@ $(CXXFLAGS) $(CPPFLAGS) -fPIC $< $(CPP_OBJ) $(C_OBJ) $(HTS_LIB) $(H5_LIB) $(LIBS)
+
+test: $(TEST_PROGRAM)
+	./$(TEST_PROGRAM)
+
+clean:
+	rm -f nanopolish nanopolish_test $(CPP_OBJ) $(C_OBJ) src/main/nanopolish.o src/test/nanopolish_test.o
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..64ecc46
--- /dev/null
+++ b/README.md
@@ -0,0 +1,59 @@
+# Nanopolish
+
+[![Build Status](https://travis-ci.org/jts/nanopolish.svg?branch=master)](https://travis-ci.org/jts/nanopolish)
+
+A nanopore consensus algorithm using a signal-level hidden Markov model.
+
+## Dependencies
+
+The program requires [libhdf5](http://www.hdfgroup.org/HDF5/release/obtain5.html) and a compiler that supports C++11. Development of the code is performed using [gcc-4.8](https://gcc.gnu.org/gcc-4.8/). libhdf5 can be automatically installed by the Makefile if you do not have it already (see below).
+
+## Installation instructions
+
+You will need to run ```git clone --recursive https://github.com/jts/nanopolish.git``` to get the source code and submodules. You can then compile nanopolish by running:
+
+```
+make
+```
+
+This will automatically download and install libhdf5.
+
+## Brief usage instructions
+
+The reads that are input into the HMM must be output as a ```.fa``` file  by ```poretools```. This is important as ```poretools``` writes the path to the original ```.fast5``` file (containing the signal data) in the fasta header. These paths must be correct or nanopolish cannot find the events for each read. Let's say you have exported your reads to ```reads.fa``` and you want to polish ```draft.fa```. You should run:
+
+```
+make -f scripts/consensus.make READS=reads.fa ASSEMBLY=draft.fa
+```
+
+This will map the reads to the assembly with ```bwa mem -x ont2d``` and export a file mapping read names to fast5 files.
+
+You can then run ```nanopolish consensus```. It is recommended that you run this in parallel.
+
+```
+python nanopolish_makerange.py draft.fa | parallel --results nanopolish.results -P 8 nanopolish consensus -o nanopolish.{1}.fa -w {1} --r reads.pp.fa -b reads.pp.sorted.bam -g draft.fa -t 4
+```
+
+This command will run the consensus algorithm on eight 100kbp segments of the genome at a time, using 4 threads each. Change the ```-P``` and ```--threads``` options as appropriate for the machines you have available.
+
+After all polishing jobs are complete, you can merge the individual segments together into the final assembly:
+
+```
+python nanopolish_merge.py draft.fa nanopolish.*.fa > polished.fa
+```
+
+## To run using docker
+
+First build the image from the dockerfile:
+```
+docker build .
+```
+Note the uuid given upon successful build. 
+Then you can run nanopolish from the image:
+```
+docker run -v /path/to/local/data/data/:/data/ -it :image_id  ./nanopolish eventalign -r /data/reads.fa -b /data/alignments.sorted.bam -g /data/ref.fa
+```
+
+## Credits and Thanks
+
+The fast table-driven logsum implementation was provided by Sean Eddy as public domain code. This code was originally part of [hmmer3](http://hmmer.janelia.org/).
diff --git a/scripts/consensus-preprocess.pl b/scripts/consensus-preprocess.pl
new file mode 100755
index 0000000..193bdcb
--- /dev/null
+++ b/scripts/consensus-preprocess.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/env perl
+#
+# Extract fast5 file names from a poretools fasta file and prepend an index to uniquify names
+#
+use strict;
+use Bio::Perl;
+use Getopt::Long;
+
+my $inFile  = Bio::SeqIO->new(-file => $ARGV[0], '-format' => 'Fasta');
+my $outFile = Bio::SeqIO->new(-fh => \*STDOUT, '-format' => 'Fasta');
+open(FM, ">consensus_fast5.fofn");
+
+my $id = 0;
+
+while(my $seq = $inFile->next_seq())
+{
+    my $in_name = $seq->display_id();
+    my $out_name = "$id.$in_name";
+    my $desc = $seq->desc();
+    
+    print FM "$desc\n";
+
+    $seq->display_id($out_name);
+    $outFile->write_seq($seq);
+    $id++;
+}
diff --git a/scripts/consensus.make b/scripts/consensus.make
new file mode 100755
index 0000000..ad818e2
--- /dev/null
+++ b/scripts/consensus.make
@@ -0,0 +1,50 @@
+SHELL=/bin/bash -o pipefail
+.SECONDARY:
+
+BWA=bwa
+
+# Get the path to the Makefile
+ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+
+# Get the name of the input file without a suffix
+READS_BASE=$(basename $(READS))
+
+#
+# A pipeline to recompute a consensus sequence for an assembly
+#
+all: $(READS_BASE).pp.sorted.bam $(READS_BASE).pp.sorted.bam.bai
+
+#
+# Preprocess the reads to make a name map
+# and uniquify names
+#
+%.pp.fa: %.fa
+	$(ROOT_DIR)/consensus-preprocess.pl $^ > $@
+
+# handle .fasta too
+%.pp.fa: %.fasta
+	$(ROOT_DIR)/consensus-preprocess.pl $^ > $@
+
+#
+# Make bwa index files for the assembly
+#
+$(ASSEMBLY).bwt: $(ASSEMBLY)
+	$(BWA) index $^
+
+#
+# Map reads to the assembly using bwa
+#
+%.pp.bam: %.pp.fa $(ASSEMBLY).bwt
+	$(BWA) mem -x ont2d -t 8 $(ASSEMBLY) $< | samtools view -Sb - > $@
+
+#
+# Sort BAM
+#
+%.sorted.bam: %.bam
+	samtools sort -f $^ $@
+
+#
+# Index BAM
+#
+%.sorted.bam.bai: %.sorted.bam
+	samtools index $^
diff --git a/scripts/nanopolish_makerange.py b/scripts/nanopolish_makerange.py
new file mode 100644
index 0000000..72737aa
--- /dev/null
+++ b/scripts/nanopolish_makerange.py
@@ -0,0 +1,19 @@
+import sys
+from Bio import SeqIO
+
+recs = [ (rec.name, len(rec.seq)) for rec in SeqIO.parse(open(sys.argv[1]), "fasta")]
+
+# Do not change, must match nanopolish segment lengths
+SEGMENT_LENGTH = 10000
+
+# Ok to change this
+SEGMENTS_PER_BATCH = 10
+
+for name, length in recs:
+    n_segments = (length / SEGMENT_LENGTH) + 1
+
+    for n in xrange(0, n_segments, SEGMENTS_PER_BATCH):
+        if ( n + SEGMENTS_PER_BATCH) > n_segments:
+            print "%s:%d-%d" % (name, n, n_segments)
+        else:
+            print "%s:%d-%d" % (name, n, n + SEGMENTS_PER_BATCH)
diff --git a/scripts/nanopolish_merge.py b/scripts/nanopolish_merge.py
new file mode 100644
index 0000000..0440aca
--- /dev/null
+++ b/scripts/nanopolish_merge.py
@@ -0,0 +1,107 @@
+import sys
+import glob
+from Bio import SeqIO
+from Bio import pairwise2
+
+def merge_into_consensus(consensus, incoming, overlap_length):
+
+    # if first segment, no overlapping needs to be done
+    if consensus == "":
+        return incoming
+
+    or_con = consensus[-overlap_length:]
+    or_inc = incoming[0:overlap_length]
+
+    # These parameters are designed to give us the region of highest similarity
+    # between the two sequences
+    alignments = pairwise2.align.globalms(or_con, or_inc, 2, -10, -10, -3)
+
+    best = alignments[0]
+    aln_con, aln_inc, score, begin, end = best
+
+    # We merge at the midpoint between the two aligned segments
+    m_con = 0
+    m_inc = 0
+
+    assert(len(aln_con) == len(aln_inc))
+
+    for i in xrange(0, len(aln_con) / 2):
+        a = aln_con[i]
+        b = aln_inc[i]
+
+        if a != '-':
+            m_con += 1
+        if b != '-':
+            m_inc += 1
+
+    
+    #merged = or_con[0:m_con] + or_inc[m_inc:]
+    debug_segment_merge = False
+    if debug_segment_merge:
+        print 'OR', or_con
+        print 'OR', or_inc
+
+        print 'Before trim'
+        print aln_con
+        print aln_inc
+
+        print 'After trim'
+        print aln_con[begin:end]
+        print aln_inc[begin:end]
+        print score, begin, end, m_con, m_inc
+
+        print 'Merging:'
+        print or_con[0:m_con]
+        print or_inc[m_inc:]
+
+    m_con += len(consensus) - overlap_length
+    merged = consensus[0:m_con] + incoming[m_inc:]
+
+    return merged
+
+# Make placeholder segments using the original assembly as a guide
+original_assembly = sys.argv[1]
+recs = [ (rec.name, len(rec.seq)) for rec in SeqIO.parse(open(original_assembly), "fasta")]
+
+# Do not change, must match nanopolish segment lengths
+SEGMENT_LENGTH = 10000
+OVERLAP_LENGTH = 200
+
+segments_by_name = dict()
+for name, length in recs:
+
+    n_segments = (length / SEGMENT_LENGTH) + 1
+    segments_by_name[name] = [""] * n_segments
+
+for fn in sys.argv[2:]:
+    for rec in SeqIO.parse(open(fn), "fasta"):
+        (contig, segment) = rec.name.split(":")
+        segments_by_name[contig][int(segment)] = str(rec.seq)
+
+# Confirm all segments are present
+segment_not_found = False
+for contig_name in sorted(segments_by_name.keys()):
+    for (segment_id, sequence) in enumerate(segments_by_name[contig_name]):
+        
+        if sequence is "":
+            sys.stderr.write("ERROR_MISSING %s %d\n" % (contig_name, segment_id))
+            segment_not_found = True
+
+if segment_not_found:            
+	sys.exit(1)
+
+# Assemble while making sure every segment is present
+for contig_name in sorted(segments_by_name.keys()):
+    assembly = ""
+    for (segment_id, sequence) in enumerate(segments_by_name[contig_name]):
+        
+        if sequence is "":
+            print "ERROR, segment %d of contig %s is missing" % (segment_id, contig_name)
+            sys.exit(1)
+
+        sys.stderr.write('Merging %s %d\n' % (contig_name, segment_id))
+
+        assembly = merge_into_consensus(assembly, sequence, OVERLAP_LENGTH)
+    
+    # Write final assembly
+    print(">%s\n%s\n" % (contig_name, assembly))
diff --git a/src/alignment/nanopolish_alignment_db.cpp b/src/alignment/nanopolish_alignment_db.cpp
new file mode 100644
index 0000000..1b7bd62
--- /dev/null
+++ b/src/alignment/nanopolish_alignment_db.cpp
@@ -0,0 +1,445 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_alignment_db -- abstraction for working
+// with sets of reads/events aligned to a reference genome
+//
+#include <assert.h>
+#include <algorithm>
+#include "nanopolish_alignment_db.h"
+#include "htslib/faidx.h"
+#include "htslib/hts.h"
+#include "htslib/sam.h"
+
+// Various file handle and structures
+// needed to traverse a bam file
+struct BamHandles
+{
+    htsFile* bam_fh;
+    bam1_t* bam_record;
+    hts_itr_t* itr;
+};
+
+AlignmentDB::AlignmentDB(const std::string& reads_file,
+                         const std::string& reference_file,
+                         const std::string& sequence_bam,
+                         const std::string& event_bam) :
+                            m_fast5_name_map(reads_file),
+                            m_reference_file(reference_file),
+                            m_sequence_bam(sequence_bam),
+                            m_event_bam(event_bam)
+{
+    _clear_region();
+}
+
+AlignmentDB::~AlignmentDB()
+{
+    _clear_region();
+}
+
+std::string AlignmentDB::get_reference_substring(const std::string& contig,
+                                                 int start_position,
+                                                 int stop_position) const
+{
+    assert(m_region_contig == contig);
+    assert(m_region_start <= start_position);
+    assert(m_region_end >= stop_position);
+
+    return m_region_ref_sequence.substr(start_position - m_region_start, stop_position - start_position + 1);
+}
+
+
+std::vector<std::string> AlignmentDB::get_read_substrings(const std::string& contig,
+                                                          int start_position,
+                                                          int stop_position) const
+{
+    assert(m_region_contig == contig);
+    assert(m_region_start <= start_position);
+    assert(m_region_end >= stop_position);
+
+    std::vector<std::string> out;
+    for(size_t i = 0; i < m_sequence_records.size(); ++i) {
+        const SequenceAlignmentRecord& record = m_sequence_records[i];
+        if(record.aligned_bases.empty())
+            continue;
+        
+        int r1, r2;
+        bool bounded = _find_by_ref_bounds(record.aligned_bases, 
+                                           start_position, 
+                                           stop_position,
+                                           r1,
+                                           r2);
+        
+        if(bounded) {
+            out.push_back(record.sequence.substr(r1, r2 - r1 + 1));
+        }
+    }
+    return out;
+}
+
+std::vector<HMMInputData> AlignmentDB::get_event_subsequences(const std::string& contig,
+                                                              int start_position,
+                                                              int stop_position) const
+{
+    assert(m_region_contig == contig);
+    assert(m_region_start <= start_position);
+    assert(m_region_end >= stop_position);
+
+    std::vector<HMMInputData> out;
+    for(size_t i = 0; i < m_event_records.size(); ++i) {
+        const EventAlignmentRecord& record = m_event_records[i];
+        if(record.aligned_events.empty())
+            continue;
+
+        HMMInputData data;
+        data.read = record.sr;
+        data.anchor_index = -1; // unused
+        data.strand = record.strand;
+        data.rc = record.rc;
+        data.event_stride = record.stride;
+        
+        int e1,e2;
+        bool bounded = _find_by_ref_bounds(record.aligned_events, 
+                                           start_position, 
+                                           stop_position,
+                                           e1,
+                                           e2);
+        if(bounded) {
+            assert(e1 >= 0);
+            assert(e2 >= 0);
+            data.event_start_idx = e1;
+            data.event_stop_idx = e2;
+            out.push_back(data);
+        }
+    }
+
+    return out;
+}
+
+std::vector<HMMInputData> AlignmentDB::get_events_aligned_to(const std::string& contig,
+                                                             int position) const
+{
+    assert(m_region_contig == contig);
+    assert(m_region_start <= position);
+    assert(m_region_end >= position);
+
+    std::vector<HMMInputData> out;
+    for(size_t i = 0; i < m_event_records.size(); ++i) {
+        const EventAlignmentRecord& record = m_event_records[i];
+        if(record.aligned_events.empty())
+            continue;
+
+        HMMInputData data;
+        data.read = record.sr;
+        data.anchor_index = -1; // unused
+        data.strand = record.strand;
+        data.rc = record.rc;
+        data.event_stride = record.stride;
+    
+        AlignedPairConstIter start_iter;
+        AlignedPairConstIter stop_iter;
+        bool bounded = _find_iter_by_ref_bounds(record.aligned_events, position, position, start_iter, stop_iter);
+        if(bounded && start_iter->ref_pos == position) {
+            data.event_start_idx = start_iter->read_pos;
+            data.event_stop_idx = start_iter->read_pos;
+            out.push_back(data);
+        }
+    }
+    return out;
+}
+
+std::vector<Variant> AlignmentDB::get_variants_in_region(const std::string& contig,
+                                                         int start_position,
+                                                         int stop_position,
+                                                         double min_frequency,
+                                                         int min_depth) const
+{
+    std::vector<Variant> variants;
+    std::map<std::string, std::pair<Variant, int>> map;
+    std::vector<int> depth(stop_position - start_position + 1, 0);
+
+    size_t num_aligned_reads = 0;
+
+    for(size_t i = 0; i < m_sequence_records.size(); ++i) {
+        const SequenceAlignmentRecord& record = m_sequence_records[i];
+        if(record.aligned_bases.empty())
+            continue;
+
+        AlignedPairConstIter start_iter;
+        AlignedPairConstIter stop_iter;
+        _find_iter_by_ref_bounds(record.aligned_bases, start_position, stop_position, start_iter, stop_iter);
+        
+        //printf("[%zu] iter: [%d %d] [%d %d] first: %d last: %d\n", i, start_iter->ref_pos, start_iter->read_pos, stop_iter->ref_pos, stop_iter->read_pos, 
+        //            record.aligned_bases.front().ref_pos, record.aligned_bases.back().ref_pos);
+        for(; start_iter != stop_iter; ++start_iter) {
+            
+            int rp = start_iter->ref_pos;
+            char rb = m_region_ref_sequence[start_iter->ref_pos - m_region_start];
+            char ab = record.sequence[start_iter->read_pos];
+
+            if(rp < start_position || rp > stop_position) {
+                continue;
+            }
+            
+            // Increment depth
+            depth[rp - start_position]++;
+
+            if(rb != ab) {
+                Variant v;
+                v.ref_name = contig;
+                v.ref_position = start_iter->ref_pos;
+                v.ref_seq = rb;
+                v.alt_seq = ab;
+
+                std::string key = v.key();
+                auto iter = map.find(key);
+                if(iter == map.end()) {
+                    map.insert(std::make_pair(key, std::make_pair(v, 1)));
+                } else {
+                    iter->second.second += 1;
+                }
+            }
+        }
+    }
+
+    for(auto iter = map.begin(); iter != map.end(); ++iter) {
+        Variant& v = iter->second.first;
+        size_t count = iter->second.second;
+        size_t d = depth[v.ref_position - start_position];
+        double f = (double)count / d;
+        if(f >= min_frequency && d >= min_depth) {
+            v.add_info("BaseCalledReadsWithVariant", count);
+            v.add_info("BaseCalledFrequency", f);
+            variants.push_back(v);
+        }
+    }
+
+    std::sort(variants.begin(), variants.end(), sortByPosition);
+    return variants;
+}
+        
+void AlignmentDB::load_region(const std::string& contig,
+                              int start_position,
+                              int stop_position)
+{
+
+    // load reference fai file
+    faidx_t *fai = fai_load(m_reference_file.c_str());
+
+    // Adjust end position to make sure we don't go out-of-range
+    m_region_contig = contig;
+    m_region_start = start_position;
+    m_region_end = std::min(stop_position, faidx_seq_len(fai, contig.c_str()));
+
+    // load the reference sequence for this region
+    // its ok to use the unthreadsafe fetch_seq here since we have our own fai
+    int fetched_len = 0;
+    char* ref_segment = faidx_fetch_seq(fai, m_region_contig.c_str(), m_region_start, m_region_end, &fetched_len);
+    m_region_ref_sequence = ref_segment;
+    
+    // load base-space alignments
+    _load_sequence_by_region();
+
+    // load event-space alignments
+    _load_events_by_region();
+
+    free(ref_segment);
+    fai_destroy(fai);
+}
+
+void AlignmentDB::_clear_region()
+{
+    // Delete the SquiggleReads
+    for(SquiggleReadMap::iterator iter = m_squiggle_read_map.begin();
+        iter != m_squiggle_read_map.end(); ++iter) 
+    {
+        delete iter->second;
+        iter->second = NULL;
+    }
+
+    m_squiggle_read_map.clear();
+    m_sequence_records.clear();
+    m_event_records.clear();
+
+    m_region_contig = "";
+    m_region_start = -1;
+    m_region_end = -1;
+}
+
+BamHandles _initialize_bam_itr(const std::string& bam_filename,
+                               const std::string& contig,
+                               int start_position,
+                               int stop_position)
+{
+    BamHandles handles;
+
+    // load bam file
+    handles.bam_fh = sam_open(bam_filename.c_str(), "r");
+    assert(handles.bam_fh != NULL);
+
+    // load bam index file
+    std::string index_filename = bam_filename + ".bai";
+    hts_idx_t* bam_idx = bam_index_load(index_filename.c_str());
+    assert(bam_idx != NULL);
+
+    // read the bam header to get the contig ID
+    bam_hdr_t* hdr = sam_hdr_read(handles.bam_fh);
+    int contig_id = bam_name2id(hdr, contig.c_str());
+    
+    // Initialize iteration
+    handles.bam_record = bam_init1();
+    handles.itr = sam_itr_queryi(bam_idx, contig_id, start_position, stop_position);
+
+    hts_idx_destroy(bam_idx);
+    bam_hdr_destroy(hdr);
+    return handles;
+}
+
+void AlignmentDB::_load_sequence_by_region()
+{
+    assert(!m_region_contig.empty());
+    assert(m_region_start >= 0);
+    assert(m_region_end >= 0);
+
+    BamHandles handles = _initialize_bam_itr(m_sequence_bam, m_region_contig, m_region_start, m_region_end);
+
+    int result;
+    while((result = sam_itr_next(handles.bam_fh, handles.itr, handles.bam_record)) >= 0) {
+        SequenceAlignmentRecord seq_record;
+
+        // copy sequence out of the record
+        uint8_t* pseq = bam_get_seq(handles.bam_record);
+        seq_record.sequence.resize(handles.bam_record->core.l_qseq);
+        for(int i = 0; i < handles.bam_record->core.l_qseq; ++i) {
+            seq_record.sequence[i] = seq_nt16_str[bam_seqi(pseq, i)];
+        }
+        
+        // copy read base-to-reference alignment
+        seq_record.aligned_bases = get_aligned_pairs(handles.bam_record);
+        m_sequence_records.push_back(seq_record);
+        
+        /*
+        printf("sequence_record[%zu] prefix: %s alignstart: [%d %d]\n", 
+            m_sequence_records.size() - 1,
+            m_sequence_records.back().sequence.substr(0, 20).c_str(),
+            m_sequence_records.back().aligned_bases.front().ref_pos,
+            m_sequence_records.back().aligned_bases.front().read_pos);
+        */
+    }
+
+    // cleanup
+    sam_itr_destroy(handles.itr);
+    bam_destroy1(handles.bam_record);
+    sam_close(handles.bam_fh);
+}
+
+void AlignmentDB::_load_events_by_region()
+{
+    assert(!m_region_contig.empty());
+    assert(m_region_start >= 0);
+    assert(m_region_end >= 0);
+
+    BamHandles handles = _initialize_bam_itr(m_event_bam, m_region_contig, m_region_start, m_region_end);
+
+    int result;
+    while((result = sam_itr_next(handles.bam_fh, handles.itr, handles.bam_record)) >= 0) {
+        EventAlignmentRecord event_record;
+
+        std::string full_name = bam_get_qname(handles.bam_record);
+        
+        // Check for the template/complement suffix
+        bool is_template = true;
+        size_t suffix_pos = 0;
+        suffix_pos = full_name.find(".template");
+        if(suffix_pos == std::string::npos) {
+            suffix_pos = full_name.find(".complement");
+            assert(suffix_pos != std::string::npos);
+            is_template = false;
+        }
+
+        std::string read_name = full_name.substr(0, suffix_pos);
+        std::string fast5_path = m_fast5_name_map.get_path(read_name);
+
+        // Do we need to load this fast5 file?
+        if(m_squiggle_read_map.find(read_name) == m_squiggle_read_map.end()) {
+            m_squiggle_read_map[read_name] = new SquiggleRead(read_name, fast5_path);
+        }
+        event_record.sr = m_squiggle_read_map[read_name];
+
+        // extract the event stride tag which tells us whether the
+        // event indices are increasing or decreasing
+        assert(bam_aux_get(handles.bam_record, "ES") != NULL);
+        int event_stride = bam_aux2i(bam_aux_get(handles.bam_record, "ES"));
+
+        // copy event alignments
+        event_record.aligned_events = get_aligned_pairs(handles.bam_record, event_stride);
+
+        event_record.rc = bam_is_rev(handles.bam_record);
+        event_record.stride = event_stride;
+        event_record.strand = is_template ? T_IDX : C_IDX;
+        m_event_records.push_back(event_record);
+        
+        /*
+        printf("event_record[%zu] name: %s stride: %d align bounds [%d %d] [%d %d]\n", 
+            m_event_records.size() - 1,
+            bam_get_qname(handles.bam_record),
+            event_stride,
+            m_event_records.back().aligned_events.front().ref_pos,
+            m_event_records.back().aligned_events.front().read_pos,
+            m_event_records.back().aligned_events.back().ref_pos,
+            m_event_records.back().aligned_events.back().read_pos);
+        */
+    }
+
+    // cleanup
+    sam_itr_destroy(handles.itr);
+    bam_destroy1(handles.bam_record);
+    sam_close(handles.bam_fh);
+}
+
+bool AlignmentDB::_find_iter_by_ref_bounds(const std::vector<AlignedPair>& pairs,
+                                      int ref_start,
+                                      int ref_stop,
+                                      AlignedPairConstIter& start_iter,
+                                      AlignedPairConstIter& stop_iter) const
+{
+    AlignedPairRefLBComp lb_comp;
+    start_iter = std::lower_bound(pairs.begin(), pairs.end(),
+                                  ref_start, lb_comp);
+
+    stop_iter = std::lower_bound(pairs.begin(), pairs.end(),
+                                 ref_stop, lb_comp);
+    
+    if(start_iter == pairs.end() || stop_iter == pairs.end())
+        return false;
+    
+    // require at least one aligned reference base at or outside the boundary
+    bool left_bounded = start_iter->ref_pos <= ref_start ||
+                        (start_iter != pairs.begin() && (start_iter - 1)->ref_pos <= ref_start);
+    
+    bool right_bounded = stop_iter->ref_pos >= ref_stop ||
+                        (stop_iter != pairs.end() && (stop_iter + 1)->ref_pos >= ref_start);
+
+    return left_bounded && right_bounded;
+}
+
+
+bool AlignmentDB::_find_by_ref_bounds(const std::vector<AlignedPair>& pairs,
+                                      int ref_start,
+                                      int ref_stop,
+                                      int& read_start,
+                                      int& read_stop) const
+{
+    AlignedPairConstIter start_iter;
+    AlignedPairConstIter stop_iter;
+    bool bounded = _find_iter_by_ref_bounds(pairs, ref_start, ref_stop, start_iter, stop_iter);
+    if(bounded) {
+        read_start = start_iter->read_pos;
+        read_stop = stop_iter->read_pos;
+        return true;
+    } else {
+        return false;
+    }
+}
diff --git a/src/alignment/nanopolish_alignment_db.h b/src/alignment/nanopolish_alignment_db.h
new file mode 100644
index 0000000..c6179f4
--- /dev/null
+++ b/src/alignment/nanopolish_alignment_db.h
@@ -0,0 +1,118 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_alignment_db -- abstraction for working
+// with sets of reads/events aligned to a reference genome
+//
+#ifndef ALIGNMENT_DB
+#define ALIGNMENT_DB
+
+#include <string>
+#include <vector>
+#include <map>
+#include "nanopolish_anchor.h"
+#include "nanopolish_variant.h"
+
+// structs
+struct SequenceAlignmentRecord
+{
+    std::string sequence;
+    std::vector<AlignedPair> aligned_bases;
+};
+
+struct EventAlignmentRecord
+{
+    SquiggleRead* sr;
+    uint8_t rc; // with respect to reference genome
+    uint8_t strand; // 0 = template, 1 = complement
+    uint8_t stride; // whether event indices increase or decrease along the reference
+    std::vector<AlignedPair> aligned_events;
+};
+
+// typedefs
+typedef std::map<std::string, SquiggleRead*> SquiggleReadMap;
+
+class AlignmentDB
+{
+    public:
+        AlignmentDB(const std::string& reads_file,
+                    const std::string& reference_file,
+                    const std::string& sequence_bam,
+                    const std::string& event_bam);
+
+        ~AlignmentDB();
+
+        void load_region(const std::string& contig,
+                         int start_position,
+                         int stop_position);
+        
+        const std::string& get_reference() const { return m_region_ref_sequence; }
+
+        std::string get_reference_substring(const std::string& contig,
+                                            int start_position,
+                                            int stop_position) const;
+
+        std::vector<std::string> get_read_substrings(const std::string& contig,
+                                                     int start_position,
+                                                     int stop_position) const;
+
+        std::vector<HMMInputData> get_event_subsequences(const std::string& contig,
+                                                         int start_position,
+                                                         int stop_position) const;
+
+        std::vector<HMMInputData> get_events_aligned_to(const std::string& contig, int position) const;
+
+        std::vector<Variant> get_variants_in_region(const std::string& contig,
+                                                    int start_position,
+                                                    int stop_position,
+                                                    double min_frequency,
+                                                    int min_depth) const;
+
+        int get_region_start() const { return m_region_start; }
+        int get_region_end() const { return m_region_end; }
+
+    private:
+        
+        void _load_sequence_by_region();
+        void _load_events_by_region();
+        void _clear_region();
+
+        // Search the vector of AlignedPairs using lower_bound/upper_bound
+        // and the input reference coordinates. If the search succeeds,
+        // set read_start/read_stop to be the read_pos of the bounding elements
+        // and return true. 
+        bool _find_by_ref_bounds(const std::vector<AlignedPair>& pairs,
+                                 int ref_start,
+                                 int ref_stop,
+                                 int& read_start,
+                                 int& read_stop) const;
+
+        bool _find_iter_by_ref_bounds(const std::vector<AlignedPair>& pairs,
+                                      int ref_start,
+                                      int ref_stop,
+                                      AlignedPairConstIter& start_iter,
+                                      AlignedPairConstIter& stop_iter) const;
+
+        //
+        // data
+        //
+        std::string m_reference_file;
+        std::string m_sequence_bam;
+        std::string m_event_bam;
+
+        // loaded region
+        std::string m_region_ref_sequence;
+        std::string m_region_contig;
+        int m_region_start;
+        int m_region_end;
+
+        // cached alignments for a region
+        Fast5Map m_fast5_name_map;
+        std::vector<SequenceAlignmentRecord> m_sequence_records;
+        std::vector<EventAlignmentRecord> m_event_records;
+        SquiggleReadMap m_squiggle_read_map;
+};
+
+#endif
diff --git a/src/alignment/nanopolish_anchor.cpp b/src/alignment/nanopolish_anchor.cpp
new file mode 100644
index 0000000..be0bb35
--- /dev/null
+++ b/src/alignment/nanopolish_anchor.cpp
@@ -0,0 +1,314 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_anchor - a collection of data types
+// for representing a set of event-to-sequence
+// mappings.
+#include <vector>
+#include <string>
+#include <stdio.h>
+#include <assert.h>
+#include "htslib/faidx.h"
+#include "nanopolish_common.h"
+#include "nanopolish_anchor.h"
+#include "nanopolish_squiggle_read.h"
+
+HMMRealignmentInput build_input_for_region(const std::string& bam_filename, 
+                                           const std::string& ref_filename, 
+                                           const Fast5Map& read_name_map, 
+                                           const std::string& contig_name,
+                                           int start, 
+                                           int end, 
+                                           int stride)
+{
+    // Initialize return data
+    HMMRealignmentInput ret;
+
+    // load bam file
+    htsFile* bam_fh = sam_open(bam_filename.c_str(), "r");
+    assert(bam_fh != NULL);
+
+    // load bam index file
+    std::string index_filename = bam_filename + ".bai";
+    hts_idx_t* bam_idx = bam_index_load(index_filename.c_str());
+    assert(bam_idx != NULL);
+
+    // read the bam header
+    bam_hdr_t* hdr = sam_hdr_read(bam_fh);
+    int contig_id = bam_name2id(hdr, contig_name.c_str());
+    
+    // load reference fai file
+    faidx_t *fai = fai_load(ref_filename.c_str());
+
+    // Adjust end position to make sure we don't go out-of-range
+    end = std::min(end, faidx_seq_len(fai, contig_name.c_str()));
+
+    // load the reference sequence for this region
+    int fetched_len = 0;
+    char* ref_segment = faidx_fetch_seq(fai, contig_name.c_str(), start, end, &fetched_len);
+    ret.original_sequence = ref_segment;
+
+    // Initialize iteration
+    bam1_t* record = bam_init1();
+    hts_itr_t* itr = sam_itr_queryi(bam_idx, contig_id, start, end);
+    
+    // Iterate over reads aligned here
+    std::vector<HMMReadAnchorSet> read_anchors;
+    std::vector<std::vector<std::string>> read_substrings;
+
+    // kmer size of pore model
+    uint32_t k;
+
+    // Load the SquiggleReads aligned to this region and the bases
+    // that are mapped to our reference anchoring positions
+    int result;
+    while((result = sam_itr_next(bam_fh, itr, record)) >= 0) {
+
+        // Load a squiggle read for the mapped read
+        std::string read_name = bam_get_qname(record);
+        std::string fast5_path = read_name_map.get_path(read_name);
+
+        // load read
+        ret.reads.push_back(std::unique_ptr<SquiggleRead>(new SquiggleRead(read_name, fast5_path)));
+        const SquiggleRead& sr = *ret.reads.back();
+        k = sr.pore_model[T_IDX].k;
+
+        // parse alignments to reference
+        std::vector<AlignedPair> aligned_pairs = get_aligned_pairs(record);
+        std::vector<int> read_bases_for_anchors = 
+            uniformally_sample_read_positions(aligned_pairs, start, end, stride);
+
+        /*
+        for(size_t i = 0; i < read_bases_for_anchors.size(); ++i) {
+            printf("%d ", read_bases_for_anchors[i]);
+        }
+        printf("\n");
+        */
+
+        // Convert the read base positions into event indices for both strands
+        HMMReadAnchorSet event_anchors;
+        event_anchors.strand_anchors[T_IDX].resize(read_bases_for_anchors.size());
+        event_anchors.strand_anchors[C_IDX].resize(read_bases_for_anchors.size());
+
+        bool do_base_rc = bam_is_rev(record);
+        bool template_rc = do_base_rc;
+        bool complement_rc = !do_base_rc;
+
+        for(size_t ai = 0; ai < read_bases_for_anchors.size(); ++ai) {
+
+            int read_kidx = read_bases_for_anchors[ai];
+
+            // read not aligned to this reference position
+            if(read_kidx == -1) {
+                continue;
+            }
+
+            if(do_base_rc)
+                read_kidx = sr.flip_k_strand(read_kidx);
+
+            // If the aligned base is beyong the start of the last k-mer of the read, skip
+            if(read_kidx >= sr.read_sequence.size() - k + 1) {
+                continue;
+            }
+
+            int template_idx = sr.get_closest_event_to(read_kidx, T_IDX);
+            int complement_idx = sr.get_closest_event_to(read_kidx, C_IDX);
+
+            assert(template_idx != -1 && complement_idx != -1);
+            assert(template_idx < sr.events[T_IDX].size());
+            assert(complement_idx < sr.events[C_IDX].size());
+
+            event_anchors.strand_anchors[T_IDX][ai] = { template_idx, template_rc };
+            event_anchors.strand_anchors[C_IDX][ai] = { complement_idx, complement_rc };
+            
+            // If this is not the last anchor, extract the sequence of the read
+            // from this anchor to the next anchor as an alternative assembly
+            if(ai < read_bases_for_anchors.size() - 1) {
+                int start_kidx = read_bases_for_anchors[ai];
+                int end_kidx = read_bases_for_anchors[ai + 1];
+                int max_kidx = sr.read_sequence.size() - k;
+
+                // flip
+                if(do_base_rc) {
+                    start_kidx = sr.flip_k_strand(start_kidx);
+                    end_kidx = sr.flip_k_strand(end_kidx);
+                    
+                    // swap
+                    int tmp = end_kidx;
+                    end_kidx = start_kidx;
+                    start_kidx = tmp;
+                }
+
+                // clamp values within range
+                start_kidx = start_kidx >= 0 ? start_kidx : 0;
+                end_kidx = end_kidx <= max_kidx ? end_kidx : max_kidx;
+                
+                std::string s = sr.read_sequence.substr(start_kidx, end_kidx - start_kidx + k);
+
+                if(do_base_rc) {
+                    s = gDNAAlphabet.reverse_complement(s);
+                }
+
+                if(ai >= read_substrings.size())
+                    read_substrings.resize(ai + 1);
+
+                read_substrings[ai].push_back(s);
+            }
+        }
+
+        read_anchors.push_back(event_anchors);
+    }
+
+    // If there are no reads aligned to this segment return empty data
+    if(read_anchors.empty()) {
+        return ret;
+    }
+
+    // The HMMReadAnchorSet contains anchors for each strand of a read
+    // laid out in a vector. Transpose this data so we have one anchor
+    // for every read column-wise.
+    assert(read_anchors.front().strand_anchors[T_IDX].size() == 
+           read_anchors.back().strand_anchors[T_IDX].size());
+
+    // same for all anchors, so we use the first
+    size_t num_anchors = read_anchors.front().strand_anchors[T_IDX].size(); 
+    size_t num_strands = read_anchors.size() * 2;
+    
+    ret.anchored_columns.resize(num_anchors);
+    for(size_t ai = 0; ai < num_anchors; ++ai) {
+        
+        HMMAnchoredColumn& column = ret.anchored_columns[ai];
+
+        for(size_t rai = 0; rai < read_anchors.size(); ++rai) {
+            HMMReadAnchorSet& ras = read_anchors[rai];
+            assert(ai < ras.strand_anchors[T_IDX].size());
+            assert(ai < ras.strand_anchors[C_IDX].size());
+
+            column.anchors.push_back(ras.strand_anchors[T_IDX][ai]);
+            column.anchors.push_back(ras.strand_anchors[C_IDX][ai]);
+        }
+        assert(column.anchors.size() == num_strands);
+
+        // Add sequences except for last anchor
+        if(ai != num_anchors - 1) {
+            
+            // base, these sequences need to overlap by k - 1 bases
+            int base_length = stride + k;
+            if(ai * stride + base_length > fetched_len)
+                base_length = fetched_len - ai * stride;
+
+            column.base_sequence = std::string(ref_segment + ai * stride, base_length);
+            column.base_contig = contig_name;
+            column.base_start_position = start + ai * stride;
+            assert(column.base_sequence.back() != '\0');
+
+            // alts
+            if(ai < read_substrings.size())
+                column.alt_sequences = read_substrings[ai];
+        }
+    }
+
+    // cleanup
+    sam_itr_destroy(itr);
+    bam_hdr_destroy(hdr);
+    bam_destroy1(record);
+    fai_destroy(fai);
+    sam_close(bam_fh);
+    hts_idx_destroy(bam_idx);
+    free(ref_segment);
+
+    return ret;
+}
+
+std::vector<AlignedPair> get_aligned_pairs(const bam1_t* record, int read_stride)
+{
+    std::vector<AlignedPair> out;
+
+    // This code is derived from bam_fillmd1_core
+    uint8_t *ref = NULL;
+    uint8_t *seq = bam_get_seq(record);
+    uint32_t *cigar = bam_get_cigar(record);
+    const bam1_core_t *c = &record->core;
+
+    // read pos is an index into the original sequence that is present in the FASTQ
+    // on the strand matching the reference
+    int read_pos = 0;
+
+    // query pos is an index in the query string that is recorded in the bam
+    // we record this as a sanity check
+    int query_pos = 0;
+    
+    int ref_pos = c->pos;
+
+    for (int ci = 0; ci < c->n_cigar; ++ci) {
+        
+        int cigar_len = cigar[ci] >> 4;
+        int cigar_op = cigar[ci] & 0xf;
+
+        // Set the amount that the ref/read positions should be incremented
+        // based on the cigar operation
+        int read_inc = 0;
+        int ref_inc = 0;
+        
+        // Process match between the read and the reference
+        bool is_aligned = false;
+        if(cigar_op == BAM_CMATCH || cigar_op == BAM_CEQUAL || cigar_op == BAM_CDIFF) {
+            is_aligned = true;
+            read_inc = read_stride;
+            ref_inc = 1;
+        } else if(cigar_op == BAM_CDEL || cigar_op == BAM_CREF_SKIP) {
+            ref_inc = 1;   
+        } else if(cigar_op == BAM_CINS) {
+            read_inc = read_stride;
+        } else if(cigar_op == BAM_CSOFT_CLIP) {
+            read_inc = 1; // special case, do not use read_stride
+        } else if(cigar_op == BAM_CHARD_CLIP) {
+            read_inc = 0;
+        } else {
+            printf("Cigar: %d\n", cigar_op);
+            assert(false && "Unhandled cigar operation");
+        }
+
+        // Iterate over the pairs of aligned bases
+        for(int j = 0; j < cigar_len; ++j) {
+            if(is_aligned) {
+                out.push_back({ref_pos, read_pos});
+            }
+
+            // increment
+            read_pos += read_inc;
+            ref_pos += ref_inc;
+        }
+    }
+    return out;
+}
+
+std::vector<int> uniformally_sample_read_positions(const std::vector<AlignedPair>& aligned_pairs,
+                                                   int ref_start,
+                                                   int ref_end,
+                                                   int ref_stride)
+{
+    uint32_t num_anchors = ((ref_end - ref_start) / ref_stride) + 1;
+    std::vector<int> out(num_anchors, -1);
+
+    for(size_t pair_idx = 0; pair_idx < aligned_pairs.size(); ++pair_idx) {
+
+        // We use a loop here in case there is no read base
+        // aligned to one of the anchor positions we are interested in.
+        // In this situation the loop will catch it and emit the last seen
+        // read position
+        int ref_pos = aligned_pairs[pair_idx].ref_pos;
+        int end_pos = pair_idx + 1 != aligned_pairs.size() ? aligned_pairs[pair_idx + 1].ref_pos : ref_pos + 1;
+
+        for(; ref_pos < end_pos; ++ref_pos) {
+            if(ref_pos >= ref_start && ref_pos <= ref_end && ref_pos % ref_stride == 0) {
+                uint32_t anchor_id = (ref_pos - ref_start) / ref_stride;
+                assert(anchor_id < num_anchors);
+                out[anchor_id] = aligned_pairs[pair_idx].read_pos;
+            }
+        }
+    }
+    return out;
+}
diff --git a/src/alignment/nanopolish_anchor.h b/src/alignment/nanopolish_anchor.h
new file mode 100644
index 0000000..818635e
--- /dev/null
+++ b/src/alignment/nanopolish_anchor.h
@@ -0,0 +1,105 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_anchor - a collection of data types
+// for representing a set of event-to-sequence
+// mappings.
+#ifndef NANOPOLISH_ANCHOR_H
+#define NANOPOLISH_ANCHOR_H
+
+#include <memory>
+#include "htslib/hts.h"
+#include "htslib/sam.h"
+#include "nanopolish_common.h"
+#include "nanopolish_squiggle_read.h"
+#include "nanopolish_fast5_map.h"
+
+struct AlignedPair
+{
+    int ref_pos;
+    int read_pos;
+};
+
+struct AlignedPairRefLBComp
+{
+    bool operator()(const AlignedPair& o, int v) { return o.ref_pos < v; }
+};
+
+struct AlignedPairRefUBComp
+{
+    bool operator()(int v, const AlignedPair& o) { return v < o.ref_pos; }
+};
+
+// typedefs
+typedef std::vector<AlignedPair>::iterator AlignedPairIter;
+typedef std::vector<AlignedPair>::const_iterator AlignedPairConstIter;
+
+// An event index and orientation that gives us a handle
+// into the event sequence for some SquiggleRead
+struct HMMStrandAnchor
+{
+    //
+    HMMStrandAnchor() : event_idx(-1), rc(false) {}
+    HMMStrandAnchor(int ei, bool f) : event_idx(ei), rc(f) {}
+
+    //
+    int event_idx;
+    bool rc; // with respect to consensus
+};
+
+// A pair of vectors containing all of the anchors
+// for both strands of a SquiggleRead
+struct HMMReadAnchorSet
+{
+    std::vector<HMMStrandAnchor> strand_anchors[NUM_STRANDS];
+};
+
+// This data structure represents a column of a 
+// multiple alignment where the base sequence
+// is a subsequence of a contig that we
+// we have mapped events to. It also holds alternative
+// sequences sampled from the reads at starting at this column.
+struct HMMAnchoredColumn
+{
+    std::string base_sequence;
+    std::vector<HMMStrandAnchor> anchors;
+    std::vector<std::string> alt_sequences;
+
+    // reference name and coordinate for the segment
+    std::string base_contig;
+    size_t base_start_position;
+};
+
+//
+struct HMMRealignmentInput
+{
+    std::vector<std::unique_ptr<SquiggleRead> > reads;
+    std::vector<HMMAnchoredColumn> anchored_columns;
+    std::string original_sequence;
+};
+
+// functions
+HMMRealignmentInput build_input_for_region(const std::string& bam_filename, 
+                                           const std::string& ref_filename, 
+                                           const Fast5Map& read_name_map, 
+                                           const std::string& contig_name,
+                                           int start, 
+                                           int end, 
+                                           int stride);
+
+
+
+// Return a vector specifying pairs of bases that have been aligned to each other
+// This function can handle an "event cigar" bam record, which requires the ability
+// for event indices to be in ascending or descending order. In the latter case
+// read_stride should be -1
+std::vector<AlignedPair> get_aligned_pairs(const bam1_t* record, int read_stride = 1);
+
+std::vector<int> uniformally_sample_read_positions(const std::vector<AlignedPair>& aligned_pairs,
+                                                   int ref_start,
+                                                   int ref_end,
+                                                   int ref_stride);
+
+#endif
diff --git a/src/alignment/nanopolish_eventalign.cpp b/src/alignment/nanopolish_eventalign.cpp
new file mode 100644
index 0000000..465580f
--- /dev/null
+++ b/src/alignment/nanopolish_eventalign.cpp
@@ -0,0 +1,891 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_consensus.cpp -- entry point to consensus functions
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <sys/time.h>
+#include <algorithm>
+#include <sstream>
+#include <set>
+#include <omp.h>
+#include <getopt.h>
+#include "htslib/faidx.h"
+#include "nanopolish_eventalign.h"
+#include "nanopolish_iupac.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_transition_parameters.h"
+#include "nanopolish_matrix.h"
+#include "nanopolish_profile_hmm.h"
+#include "nanopolish_anchor.h"
+#include "nanopolish_fast5_map.h"
+#include "nanopolish_hmm_input_sequence.h"
+#include "H5pubconf.h"
+#include "profiler.h"
+#include "progress.h"
+
+//
+// Getopt
+//
+#define SUBPROGRAM "eventalign"
+
+static const char *EVENTALIGN_VERSION_MESSAGE =
+SUBPROGRAM " Version " PACKAGE_VERSION "\n"
+"Written by Jared Simpson.\n"
+"\n"
+"Copyright 2015 Ontario Institute for Cancer Research\n";
+
+static const char *EVENTALIGN_USAGE_MESSAGE =
+"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
+"Align nanopore events to reference k-mers\n"
+"\n"
+"  -v, --verbose                        display verbose output\n"
+"      --version                        display version\n"
+"      --help                           display this help and exit\n"
+"      --sam                            write output in SAM format\n"
+"  -w, --window=STR                     compute the consensus for window STR (format: ctg:start_id-end_id)\n"
+"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
+"  -b, --bam=FILE                       the reads aligned to the genome assembly are in bam FILE\n"
+"  -g, --genome=FILE                    the genome we are computing a consensus for is in FILE\n"
+"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
+"      --scale-events                   scale events to the model, rather than vice-versa\n"
+"      --progress                       print out a progress message\n"
+"  -n, --print-read-names               print read names instead of indexes\n"
+"      --summary=FILE                   summarize the alignment of each read/strand in FILE\n"
+"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";
+
+namespace opt
+{
+    static unsigned int verbose;
+    static std::string reads_file;
+    static std::string bam_file;
+    static std::string genome_file;
+    static std::string region;
+    static std::string summary_file;
+    static int output_sam = 0;
+    static int progress = 0;
+    static int num_threads = 1;
+    static int scale_events = 0;
+    static int batch_size = 128;
+    static bool print_read_names;
+}
+
+static const char* shortopts = "r:b:g:t:w:vn";
+
+enum { OPT_HELP = 1, OPT_VERSION, OPT_PROGRESS, OPT_SAM, OPT_SUMMARY, OPT_SCALE_EVENTS };
+
+static const struct option longopts[] = {
+    { "verbose",          no_argument,       NULL, 'v' },
+    { "reads",            required_argument, NULL, 'r' },
+    { "bam",              required_argument, NULL, 'b' },
+    { "genome",           required_argument, NULL, 'g' },
+    { "window",           required_argument, NULL, 'w' },
+    { "threads",          required_argument, NULL, 't' },
+    { "summary",          required_argument, NULL, OPT_SUMMARY },
+    { "print-read-names", no_argument,       NULL, 'n' },
+    { "scale-events",     no_argument,       NULL, OPT_SCALE_EVENTS },
+    { "sam",              no_argument,       NULL, OPT_SAM },
+    { "progress",         no_argument,       NULL, OPT_PROGRESS },
+    { "help",             no_argument,       NULL, OPT_HELP },
+    { "version",          no_argument,       NULL, OPT_VERSION },
+    { NULL, 0, NULL, 0 }
+};
+
+// convenience wrapper for the two output modes
+struct EventalignWriter
+{
+    FILE* tsv_fp;
+    htsFile* sam_fp;
+    FILE* summary_fp;
+};
+
+// Summarize the event alignment for a read strand
+struct EventalignSummary
+{
+    EventalignSummary() {
+        num_events = 0;
+        num_matches = 0;
+        num_stays = 0;
+        num_skips = 0;
+        sum_z_score = 0;
+        sum_duration = 0;
+        alignment_edit_distance = 0;
+        reference_span = 0;
+    }
+
+    int num_events;
+    int num_matches;
+    int num_stays;
+    int num_skips;
+
+    double sum_duration;
+    double sum_z_score;
+    int alignment_edit_distance;
+    int reference_span;
+};
+
+// Modify the aligned_pairs vector to ensure the highest read position
+// does not exceed max_kmer
+void trim_aligned_pairs_to_kmer(std::vector<AlignedPair>& aligned_pairs, int max_kmer_idx)
+{
+    int idx = aligned_pairs.size() - 1;
+    while(idx >= 0 && aligned_pairs[idx].read_pos > max_kmer_idx)
+        idx -= 1;
+
+    if(idx < 0)
+        aligned_pairs.clear(); // no valid data
+    else
+        aligned_pairs.resize(idx + 1);
+}
+
+// Modify the aligned_pairs vector to ensure there are no alignments
+// outside of the given reference coordinates
+void trim_aligned_pairs_to_ref_region(std::vector<AlignedPair>& aligned_pairs, int ref_start, int ref_end)
+{
+    std::vector<AlignedPair> trimmed;
+    for(size_t i = 0; i < aligned_pairs.size(); ++i) {
+        if(aligned_pairs[i].ref_pos >= ref_start && 
+           aligned_pairs[i].ref_pos <= ref_end) {
+            trimmed.push_back(aligned_pairs[i]);
+        }
+    }
+    
+    aligned_pairs.swap(trimmed);
+}
+
+// Returns the index into the aligned_pairs vector that has the highest ref_pos
+// that is not greater than ref_pos_max. It starts the search at pair_idx
+int get_end_pair(const std::vector<AlignedPair>& aligned_pairs, int ref_pos_max, int pair_idx)
+{
+    while(pair_idx < aligned_pairs.size()) {
+        if(aligned_pairs[pair_idx].ref_pos > ref_pos_max)
+            return pair_idx - 1;
+        pair_idx += 1;
+    }
+    
+    return aligned_pairs.size() - 1;
+}
+
+// get the specified reference region, threadsafe
+std::string get_reference_region_ts(const faidx_t* fai, const char* ref_name, int start, int end, int* fetched_len)
+{
+
+    // faidx_fetch_seq is not threadsafe
+    char* cref_seq;
+    #pragma omp critical
+    cref_seq = faidx_fetch_seq(fai, ref_name, start, end, fetched_len);
+    
+    assert(cref_seq != NULL);
+
+    std::string out(cref_seq);
+    free(cref_seq);
+    return out;
+}
+
+//
+//
+//
+
+void emit_tsv_header(FILE* fp)
+{
+    fprintf(fp, "%s\t%s\t%s\t%s\t%s\t", "contig", "position", "reference_kmer",
+            (not opt::print_read_names? "read_index" : "read_name"), "strand");
+    fprintf(fp, "%s\t%s\t%s\t%s\t", "event_index", "event_level_mean", "event_stdv", "event_length");
+    fprintf(fp, "%s\t%s\t%s\t%s\n", "model_kmer", "model_mean", "model_stdv");
+
+}
+
+void emit_sam_header(samFile* fp, const bam_hdr_t* hdr)
+{
+    sam_hdr_write(fp, hdr);
+}
+
+std::string cigar_ops_to_string(const std::vector<uint32_t>& ops)
+{
+    std::stringstream ss;
+    for(size_t i = 0; i < ops.size(); ++i) {
+        ss << bam_cigar_oplen(ops[i]);
+        ss << BAM_CIGAR_STR[bam_cigar_op(ops[i])];
+    }
+    return ss.str();
+}
+
+std::vector<uint32_t> event_alignment_to_cigar(const std::vector<EventAlignment>& alignments)
+{
+    std::vector<uint32_t> out;
+
+    // add a softclip tag to account for unaligned events at the beginning/end of the read
+    if(alignments[0].event_idx > 0) {
+        out.push_back(alignments[0].event_idx << BAM_CIGAR_SHIFT | BAM_CSOFT_CLIP);
+    }
+
+    // we always start with a match
+    out.push_back(1 << BAM_CIGAR_SHIFT | BAM_CMATCH);
+
+    int prev_r_idx = alignments[0].ref_position;
+    int prev_e_idx = alignments[0].event_idx;
+    size_t ai = 1;
+
+    while(ai < alignments.size()) {
+
+        int r_idx = alignments[ai].ref_position;
+        int e_idx = alignments[ai].event_idx;
+
+        int r_step = abs(r_idx - prev_r_idx);
+        int e_step = abs(e_idx - prev_e_idx);
+
+        uint32_t incoming;
+        if(r_step == 1 && e_step == 1) {
+
+            // regular match
+            incoming = 1 << BAM_CIGAR_SHIFT;
+            incoming |= BAM_CMATCH;
+
+        } else if(r_step > 1) {
+            assert(e_step == 1);
+            // reference jump of more than 1, this is how deletions are represented
+            // we push the deletion onto the output then start a new match
+            incoming = (r_step - 1) << BAM_CIGAR_SHIFT;
+            incoming |= BAM_CDEL;
+            out.push_back(incoming);
+            
+            incoming = 1 << BAM_CIGAR_SHIFT;
+            incoming |= BAM_CMATCH;
+        } else {
+            assert(e_step == 1 && r_step == 0);
+            incoming = 1 << BAM_CIGAR_SHIFT;
+            incoming |= BAM_CINS;
+        }
+
+        // If the operation matches the previous, extend the length
+        // otherwise append a new op
+        if(bam_cigar_op(out.back()) == bam_cigar_op(incoming)) {
+            uint32_t sum = bam_cigar_oplen(out.back()) + 
+                           bam_cigar_oplen(incoming);
+            out.back() = sum << BAM_CIGAR_SHIFT | bam_cigar_op(incoming);
+        } else {
+            out.push_back(incoming);
+        }
+
+        prev_r_idx = r_idx;
+        prev_e_idx = e_idx;
+        ai++;
+    }
+    return out;
+}
+
+void emit_event_alignment_sam(htsFile* fp,
+                              const SquiggleRead& sr,
+                              const bam_hdr_t* base_hdr,
+                              const bam1_t* base_record, 
+                              const std::vector<EventAlignment>& alignments)
+{
+    assert(!alignments.empty());
+    bam1_t* event_record = bam_init1();
+    
+    // Variable-length data
+    std::string qname = sr.read_name + (alignments.front().strand_idx == 0 ? ".template" : ".complement");
+
+    // basic stats
+    event_record->core.tid = base_record->core.tid;
+    event_record->core.pos = alignments.front().ref_position;
+    event_record->core.qual = base_record->core.qual;
+    event_record->core.l_qname = qname.length() + 1; // must be null-terminated
+
+    event_record->core.flag = alignments.front().rc ? 16 : 0;
+
+    event_record->core.l_qseq = 0;
+    
+    event_record->core.mtid = -1;
+    event_record->core.mpos = -1;
+    event_record->core.isize = 0;
+
+    std::vector<uint32_t> cigar = event_alignment_to_cigar(alignments);
+    event_record->core.n_cigar = cigar.size();
+
+    // calculate length of incoming data
+    event_record->m_data = event_record->core.l_qname + // query name
+                           event_record->core.n_cigar * 4 + // 4 bytes per cigar op
+                           event_record->core.l_qseq + // query seq
+                           event_record->core.l_qseq; // query quality
+        
+    // nothing copied yet
+    event_record->l_data = 0;
+    
+    // allocate data
+    event_record->data = (uint8_t*)malloc(event_record->m_data);
+
+    // copy q name
+    assert(event_record->core.l_qname <= event_record->m_data);
+    strncpy(bam_get_qname(event_record), 
+            qname.c_str(),
+            event_record->core.l_qname);
+    event_record->l_data += event_record->core.l_qname;
+    
+    // cigar
+    assert(event_record->l_data + event_record->core.n_cigar * 4 <= event_record->m_data);
+    memcpy(bam_get_cigar(event_record), 
+           &cigar[0],
+           event_record->core.n_cigar * 4);
+    event_record->l_data += event_record->core.n_cigar * 4;
+
+    // no copy for seq and qual
+    assert(event_record->l_data <= event_record->m_data);
+
+    int stride = alignments.front().event_idx < alignments.back().event_idx ? 1 : -1;
+    bam_aux_append(event_record, "ES", 'i', 4, reinterpret_cast<uint8_t*>(&stride));
+
+    sam_write1(fp, base_hdr, event_record);
+    bam_destroy1(event_record); // automatically frees malloc'd segment
+}
+
+void emit_event_alignment_tsv(FILE* fp,
+                              const SquiggleRead& sr,
+                              uint32_t strand_idx,
+                              const EventAlignmentParameters& params,
+                              const std::vector<EventAlignment>& alignments)
+{
+    uint32_t k = sr.pore_model[strand_idx].k;
+    for(size_t i = 0; i < alignments.size(); ++i) {
+
+        const EventAlignment& ea = alignments[i];
+
+        // basic information
+        if (not opt::print_read_names)
+        {
+            fprintf(fp, "%s\t%d\t%s\t%zu\t%c\t",
+                    ea.ref_name.c_str(),
+                    ea.ref_position,
+                    ea.ref_kmer.c_str(),
+                    ea.read_idx,
+                    "tc"[ea.strand_idx]);
+        }
+        else
+        {
+            fprintf(fp, "%s\t%d\t%s\t%s\t%c\t",
+                    ea.ref_name.c_str(),
+                    ea.ref_position,
+                    ea.ref_kmer.c_str(),
+                    sr.read_name.c_str(),
+                    "tc"[ea.strand_idx]);
+        }
+
+        // event information
+        float event_mean = sr.get_drift_corrected_level(ea.event_idx, ea.strand_idx);
+        float event_stdv = sr.get_event_stdv(ea.event_idx, ea.strand_idx);
+        float event_duration = sr.get_duration(ea.event_idx, ea.strand_idx);
+        if(opt::scale_events) {
+
+            // scale reads to the model
+            event_mean = (event_mean - sr.pore_model[ea.strand_idx].shift) / sr.pore_model[ea.strand_idx].scale;
+            fprintf(fp, "%d\t%.2lf\t%.3lf\t%.3lf\t", ea.event_idx, event_mean, event_stdv, event_duration);
+
+            // unscaled parameters
+            uint32_t rank = params.alphabet->kmer_rank(ea.model_kmer.c_str(), k);
+            PoreModelStateParams model = sr.pore_model[ea.strand_idx].get_parameters(rank);
+            fprintf(fp, "%s\t%.2lf\t%.2lf\n", ea.model_kmer.c_str(), 
+                                              model.level_mean, 
+                                              model.level_stdv);
+
+        } else {
+
+            // scale model to the reads
+            float event_mean = sr.get_drift_corrected_level(ea.event_idx, ea.strand_idx);
+            float event_duration = sr.get_duration(ea.event_idx, ea.strand_idx);
+            fprintf(fp, "%d\t%.2lf\t%.3lf\t%.3lf\t", ea.event_idx, event_mean, event_stdv, event_duration);
+
+            uint32_t rank = params.alphabet->kmer_rank(ea.model_kmer.c_str(), k);
+            GaussianParameters model = sr.pore_model[ea.strand_idx].get_scaled_parameters(rank);
+            fprintf(fp, "%s\t%.2lf\t%.2lf\n", ea.model_kmer.c_str(), 
+                                              model.mean, 
+                                              model.stdv);
+        }
+    }
+}
+
+EventalignSummary summarize_alignment(const SquiggleRead& sr,
+                                      uint32_t strand_idx,
+                                      const EventAlignmentParameters& params,
+                                      const std::vector<EventAlignment>& alignments)
+{
+    EventalignSummary summary;
+
+    uint32_t k = sr.pore_model[strand_idx].k;
+
+    size_t prev_ref_pos = std::string::npos;
+    
+    // the number of unique reference positions seen in the alignment
+    size_t num_unique_ref_pos = 0;
+
+    for(size_t i = 0; i < alignments.size(); ++i) {
+
+        const EventAlignment& ea = alignments[i];
+
+        summary.num_events += 1;
+
+        // movement information
+        size_t ref_move = ea.ref_position - prev_ref_pos;
+        if(ref_move == 0) {
+            assert(ea.hmm_state == 'E');
+            summary.num_stays += 1;
+        } else if(i != 0 && ref_move > 1) {
+            summary.num_skips += 1;
+        }
+
+        // event information
+        summary.sum_duration += sr.get_duration(ea.event_idx, ea.strand_idx);
+
+        if(ea.hmm_state == 'M') {
+            summary.num_matches += 1;
+            
+            uint32_t rank = params.alphabet->kmer_rank(ea.model_kmer.c_str(), k);
+            GaussianParameters model = sr.pore_model[ea.strand_idx].get_scaled_parameters(rank);
+            float event_mean = sr.get_drift_corrected_level(ea.event_idx, ea.strand_idx);
+            double z = (event_mean - model.mean) / model.stdv;
+            summary.sum_z_score += z;
+        }
+
+        prev_ref_pos = ea.ref_position;
+    }
+
+    int nm = bam_aux2i(bam_aux_get(params.record, "NM"));
+    summary.alignment_edit_distance = nm;
+    if(!alignments.empty()) {
+        summary.reference_span = alignments.back().ref_position - alignments.front().ref_position + 1;
+    }
+    return summary;
+}
+
+// Realign the read in event space
+void realign_read(EventalignWriter writer,
+                  const Fast5Map& name_map, 
+                  const faidx_t* fai, 
+                  const bam_hdr_t* hdr, 
+                  const bam1_t* record, 
+                  size_t read_idx,
+                  int region_start,
+                  int region_end)
+{
+    // Load a squiggle read for the mapped read
+    std::string read_name = bam_get_qname(record);
+    std::string fast5_path = name_map.get_path(read_name);
+
+    // load read
+    SquiggleRead sr(read_name, fast5_path);
+    
+    if(opt::verbose > 1) {
+        fprintf(stderr, "Realigning %s [%zu %zu]\n", 
+                read_name.c_str(), sr.events[0].size(), sr.events[1].size());
+    }
+    
+    for(int strand_idx = 0; strand_idx < 2; ++strand_idx) {
+        EventAlignmentParameters params;
+        params.sr = &sr;
+        params.fai = fai;
+        params.hdr = hdr;
+        params.record = record;
+        params.strand_idx = strand_idx;
+        
+        params.read_idx = read_idx;
+        params.region_start = region_start;
+        params.region_end = region_end;
+
+        std::vector<EventAlignment> alignment = align_read_to_ref(params);
+
+        EventalignSummary summary;
+        if(writer.summary_fp != NULL) {
+            summary = summarize_alignment(sr, strand_idx, params, alignment);
+        }
+
+        // write to disk
+        #pragma omp critical
+        {
+            if(opt::output_sam) {
+                emit_event_alignment_sam(writer.sam_fp, sr, hdr, record, alignment);
+            } else {
+                emit_event_alignment_tsv(writer.tsv_fp, sr, strand_idx, params, alignment);
+            }
+
+            if(writer.summary_fp != NULL && summary.num_events > 0) {
+                fprintf(writer.summary_fp, "%zu\t%s\t%s\t", read_idx, read_name.c_str(), sr.fast5_path.c_str());
+                fprintf(writer.summary_fp, "%s\t%s\t", sr.pore_model[strand_idx].name.c_str(), strand_idx == 0 ? "template" : "complement");
+                fprintf(writer.summary_fp, "%d\t%d\t%d\t%d\t", summary.num_events, summary.num_matches, summary.num_skips, summary.num_stays);
+                fprintf(writer.summary_fp, "%.2lf\n", summary.sum_duration);
+            }
+        }
+    }
+}
+
+std::vector<EventAlignment> align_read_to_ref(const EventAlignmentParameters& params)
+{
+    // Sanity check input parameters
+    assert(params.sr != NULL);
+    assert(params.fai != NULL);
+    assert(params.hdr != NULL);
+    assert(params.record != NULL);
+    assert(params.strand_idx < NUM_STRANDS);
+    assert( (params.region_start == -1 && params.region_end == -1) || (params.region_start <= params.region_end));
+
+    std::vector<EventAlignment> alignment_output;
+
+    // Extract the reference subsequence for the entire alignment
+    int fetched_len = 0;
+    int ref_offset = params.record->core.pos;
+    std::string ref_name(params.hdr->target_name[params.record->core.tid]);
+    std::string ref_seq = get_reference_region_ts(params.fai, ref_name.c_str(), ref_offset, 
+                                                  bam_endpos(params.record), &fetched_len);
+
+    // k from read pore model
+    const uint32_t k = params.sr->pore_model[params.strand_idx].k;
+
+    // If the reference sequence contains ambiguity codes
+    // switch them to the lexicographically lowest base
+    ref_seq = params.alphabet->disambiguate(ref_seq);
+    std::string rc_ref_seq = params.alphabet->reverse_complement(ref_seq);
+
+    if(ref_offset == 0)
+        return alignment_output;
+
+    // Make a vector of aligned (ref_pos, read_pos) pairs
+    std::vector<AlignedPair> aligned_pairs = get_aligned_pairs(params.record);
+
+    if(params.region_start != -1 && params.region_end != -1) {
+        trim_aligned_pairs_to_ref_region(aligned_pairs, params.region_start, params.region_end);
+    }
+
+    // Trim the aligned pairs to be within the range of the maximum kmer index
+    int max_kmer_idx = params.sr->read_sequence.size() - k;
+    trim_aligned_pairs_to_kmer(aligned_pairs, max_kmer_idx);
+
+    if(aligned_pairs.empty())
+        return alignment_output;
+
+    bool do_base_rc = bam_is_rev(params.record);
+    bool rc_flags[2] = { do_base_rc, !do_base_rc }; // indexed by strand
+    const int align_stride = 100; // approximately how many reference bases to align to at once
+    const int output_stride = 50; // approximately how many event alignments to output at once
+
+    // get the event range of the read to re-align
+    int read_kidx_start = aligned_pairs.front().read_pos;
+    int read_kidx_end = aligned_pairs.back().read_pos;
+    
+    if(do_base_rc) {
+        read_kidx_start = params.sr->flip_k_strand(read_kidx_start);
+        read_kidx_end = params.sr->flip_k_strand(read_kidx_end);
+    }
+    
+    assert(read_kidx_start >= 0);
+    assert(read_kidx_end >= 0);
+
+    int first_event = params.sr->get_closest_event_to(read_kidx_start, params.strand_idx);
+    int last_event = params.sr->get_closest_event_to(read_kidx_end, params.strand_idx);
+    bool forward = first_event < last_event;
+
+    int last_event_output = -1;
+    int curr_start_event = first_event;
+    int curr_start_ref = aligned_pairs.front().ref_pos;
+    int curr_pair_idx = 0;
+
+    while( (forward && curr_start_event < last_event) ||
+           (!forward && curr_start_event > last_event)) {
+
+        // Get the index of the aligned pair approximately align_stride away
+        int end_pair_idx = get_end_pair(aligned_pairs, curr_start_ref + align_stride, curr_pair_idx);
+    
+        int curr_end_ref = aligned_pairs[end_pair_idx].ref_pos;
+        int curr_end_read = aligned_pairs[end_pair_idx].read_pos;
+
+        if(do_base_rc) {
+            curr_end_read = params.sr->flip_k_strand(curr_end_read);
+        }
+        assert(curr_end_read >= 0);
+
+        int s = curr_start_ref - ref_offset;
+        int l = curr_end_ref - curr_start_ref + 1;
+
+        std::string fwd_subseq = ref_seq.substr(s, l);
+        std::string rc_subseq = rc_ref_seq.substr(ref_seq.length() - s - l, l);
+        assert(fwd_subseq.length() == rc_subseq.length());
+
+        HMMInputSequence hmm_sequence(fwd_subseq, rc_subseq, params.alphabet);
+        
+        // Nothing to align to
+        if(hmm_sequence.length() < k)
+            break;
+
+        // Set up HMM input
+        HMMInputData input;
+        input.read = params.sr;
+        input.anchor_index = 0; // not used here
+        input.event_start_idx = curr_start_event;
+        input.event_stop_idx = params.sr->get_closest_event_to(curr_end_read, params.strand_idx);
+
+        // A limitation of the segment-by-segment alignment is that we can't jump
+        // over very large deletions wrt to the reference. The effect of this
+        // is that we can get segments that have very few alignable events. We
+        // just stop processing them for now
+        if(abs(input.event_start_idx - input.event_stop_idx) < 2)
+            break;
+
+        input.strand = params.strand_idx;
+        input.event_stride = input.event_start_idx < input.event_stop_idx ? 1 : -1;
+        input.rc = rc_flags[params.strand_idx];
+        
+        std::vector<HMMAlignmentState> event_alignment = profile_hmm_align(hmm_sequence, input);
+        
+        // Output alignment
+        size_t num_output = 0;
+        size_t event_align_idx = 0;
+
+        // If we aligned to the last event, output everything and stop
+        bool last_section = end_pair_idx == aligned_pairs.size() - 1;
+
+        int last_event_output = 0;
+        int last_ref_kmer_output = 0;
+
+        for(; event_align_idx < event_alignment.size() && 
+              (num_output < output_stride || last_section); event_align_idx++) {
+
+            HMMAlignmentState& as = event_alignment[event_align_idx];
+            if(as.state != 'K' && as.event_idx != curr_start_event) {
+
+                EventAlignment ea;
+                
+                // ref
+                ea.ref_name = ref_name;
+                ea.ref_position = curr_start_ref + as.kmer_idx;
+                ea.ref_kmer = ref_seq.substr(ea.ref_position - ref_offset, k);
+
+                // event
+                ea.read_idx = params.read_idx;
+                ea.strand_idx = params.strand_idx;
+                ea.event_idx = as.event_idx;
+                ea.rc = input.rc;
+
+                // hmm
+                ea.model_kmer = hmm_sequence.get_kmer(as.kmer_idx, k, input.rc);
+                ea.hmm_state = as.state;
+
+                // store
+                alignment_output.push_back(ea);
+
+                // update
+                last_event_output = as.event_idx;
+                last_ref_kmer_output = curr_start_ref + as.kmer_idx;
+                num_output += 1;
+            }
+        }
+
+        // Advance the pair iterator to the ref base
+        curr_start_event = last_event_output;
+        curr_start_ref = last_ref_kmer_output;
+        curr_pair_idx = get_end_pair(aligned_pairs, curr_start_ref, curr_pair_idx);
+
+#if EVENTALIGN_TRAIN
+        // update training data for read
+        params.sr->parameters[params.strand_idx].add_training_from_alignment(hmm_sequence, input, event_alignment);
+        global_training[params.strand_idx].add_training_from_alignment(hmm_sequence, input, event_alignment);
+#endif
+    } // for segment
+    
+    return alignment_output;
+}
+
+void parse_eventalign_options(int argc, char** argv)
+{
+    bool die = false;
+    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
+        std::istringstream arg(optarg != NULL ? optarg : "");
+        switch (c) {
+            case 'r': arg >> opt::reads_file; break;
+            case 'g': arg >> opt::genome_file; break;
+            case 'b': arg >> opt::bam_file; break;
+            case '?': die = true; break;
+            case 't': arg >> opt::num_threads; break;
+            case 'n': opt::print_read_names = true; break;
+            case 'v': opt::verbose++; break;
+            case OPT_SCALE_EVENTS: opt::scale_events = true; break;
+            case OPT_SUMMARY: arg >> opt::summary_file; break;
+            case OPT_SAM: opt::output_sam = true; break;
+            case OPT_PROGRESS: opt::progress = true; break;
+            case OPT_HELP:
+                std::cout << EVENTALIGN_USAGE_MESSAGE;
+                exit(EXIT_SUCCESS);
+            case OPT_VERSION:
+                std::cout << EVENTALIGN_VERSION_MESSAGE;
+                exit(EXIT_SUCCESS);
+        }
+    }
+
+    if(argc - optind > 0) {
+        opt::region = argv[optind++];
+    }
+
+    if (argc - optind > 0) {
+        std::cerr << SUBPROGRAM ": too many arguments\n";
+        die = true;
+    }
+
+    if(opt::num_threads <= 0) {
+        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
+        die = true;
+    }
+
+    if(opt::reads_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::genome_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
+        die = true;
+    }
+
+    if(opt::bam_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
+        die = true;
+    }
+
+    if (die) 
+    {
+        std::cout << "\n" << EVENTALIGN_USAGE_MESSAGE;
+        exit(EXIT_FAILURE);
+    }
+}
+
+int eventalign_main(int argc, char** argv)
+{
+    parse_eventalign_options(argc, argv);
+    omp_set_num_threads(opt::num_threads);
+
+    Fast5Map name_map(opt::reads_file);
+
+    // Open the BAM and iterate over reads
+
+    // load bam file
+    htsFile* bam_fh = sam_open(opt::bam_file.c_str(), "r");
+    assert(bam_fh != NULL);
+
+    // load bam index file
+    std::string index_filename = opt::bam_file + ".bai";
+    hts_idx_t* bam_idx = bam_index_load(index_filename.c_str());
+    assert(bam_idx != NULL);
+
+    // read the bam header
+    bam_hdr_t* hdr = sam_hdr_read(bam_fh);
+    
+    // load reference fai file
+    faidx_t *fai = fai_load(opt::genome_file.c_str());
+
+    hts_itr_t* itr;
+
+    // If processing a region of the genome, only emit events aligned to this window
+    int clip_start = -1;
+    int clip_end = -1;
+
+    if(opt::region.empty()) {
+        // TODO: is this valid?
+        itr = sam_itr_queryi(bam_idx, HTS_IDX_START, 0, 0);
+    } else {
+
+        fprintf(stderr, "Region: %s\n", opt::region.c_str());
+        itr = sam_itr_querys(bam_idx, hdr, opt::region.c_str());
+        hts_parse_reg(opt::region.c_str(), &clip_start, &clip_end);
+    }
+
+#ifndef H5_HAVE_THREADSAFE
+    if(opt::num_threads > 1) {
+        fprintf(stderr, "You enabled multi-threading but you do not have a threadsafe HDF5\n");
+        fprintf(stderr, "Please recompile nanopolish's built-in libhdf5 or run with -t 1\n");
+        exit(1);
+    }
+#endif
+
+    // Initialize output
+    EventalignWriter writer = { NULL, NULL, NULL };
+
+    if(opt::output_sam) {
+        writer.sam_fp = hts_open("-", "w");
+        emit_sam_header(writer.sam_fp, hdr);
+    } else {
+        writer.tsv_fp = stdout;
+        emit_tsv_header(writer.tsv_fp);
+    }
+
+    if(!opt::summary_file.empty()) {
+        writer.summary_fp = fopen(opt::summary_file.c_str(), "w");
+        // header
+        fprintf(writer.summary_fp, "read_index\tread_name\tfast5_path\tmodel_name\tstrand\tnum_events\t");
+        fprintf(writer.summary_fp, "num_matches\tnum_skips\tnum_stays\ttotal_duration\n");
+    }
+    
+    // Initialize iteration
+    std::vector<bam1_t*> records(opt::batch_size, NULL);
+    for(size_t i = 0; i < records.size(); ++i) {
+        records[i] = bam_init1();
+    }
+
+    int result;
+    size_t num_reads_realigned = 0;
+    size_t num_records_buffered = 0;
+    Progress progress("[eventalign]");
+
+    do {
+        assert(num_records_buffered < records.size());
+        
+        // read a record into the next slot in the buffer
+        result = sam_itr_next(bam_fh, itr, records[num_records_buffered]);
+        num_records_buffered += result >= 0;
+
+        // realign if we've hit the max buffer size or reached the end of file
+        if(num_records_buffered == records.size() || result < 0) {
+            #pragma omp parallel for            
+            for(size_t i = 0; i < num_records_buffered; ++i) {
+                bam1_t* record = records[i];
+                size_t read_idx = num_reads_realigned + i;
+                if( (record->core.flag & BAM_FUNMAP) == 0) {
+                    realign_read(writer, name_map, fai, hdr, record, read_idx, clip_start, clip_end);
+                }
+            }
+
+            num_reads_realigned += num_records_buffered;
+            num_records_buffered = 0;
+        }
+
+        if(opt::progress) {
+            fprintf(stderr, "Realigned %zu reads in %.1lfs\r", num_reads_realigned, progress.get_elapsed_seconds());
+        }
+    } while(result >= 0);
+ 
+    assert(num_records_buffered == 0);
+
+    // cleanup records
+    for(size_t i = 0; i < records.size(); ++i) {
+        bam_destroy1(records[i]);
+    }
+
+    // cleanup
+    sam_itr_destroy(itr);
+    bam_hdr_destroy(hdr);
+    fai_destroy(fai);
+    sam_close(bam_fh);
+    hts_idx_destroy(bam_idx);
+
+    if(writer.sam_fp != NULL) {
+        hts_close(writer.sam_fp);
+    }
+
+    if(writer.summary_fp != NULL) {
+        fclose(writer.summary_fp);
+    }
+    return EXIT_SUCCESS;
+}
diff --git a/src/alignment/nanopolish_eventalign.h b/src/alignment/nanopolish_eventalign.h
new file mode 100644
index 0000000..4364359
--- /dev/null
+++ b/src/alignment/nanopolish_eventalign.h
@@ -0,0 +1,84 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_eventalign.cpp -- align squiggle events
+// to kmers of a sequence
+//
+#ifndef NANOPOLISH_EVENTALIGN_H
+#define NANOPOLISH_EVENTALIGN_H
+
+#include "htslib/faidx.h"
+#include "htslib/sam.h"
+#include "nanopolish_alphabet.h"
+#include "nanopolish_common.h"
+
+//
+// Structs
+//
+struct EventAlignmentParameters
+{
+    EventAlignmentParameters()
+    {
+        sr = NULL;
+        fai = NULL;
+        hdr = NULL;
+        record = NULL;
+        strand_idx = NUM_STRANDS;
+        
+        alphabet = &gDNAAlphabet;
+        read_idx = -1;
+        region_start = -1;
+        region_end = -1;
+    }
+
+    // Mandatory
+    SquiggleRead* sr;
+    const faidx_t* fai;
+    const bam_hdr_t* hdr;
+    const bam1_t* record;
+    size_t strand_idx;
+    
+    // optional
+    Alphabet* alphabet;
+    int read_idx;
+    int region_start;
+    int region_end;
+};
+
+struct EventAlignment
+{
+    // ref data
+    std::string ref_name;
+    std::string ref_kmer;
+    int ref_position;
+
+    // event data
+    size_t read_idx;
+    int strand_idx;
+    int event_idx;
+    bool rc;
+
+    // hmm data
+    std::string model_kmer;
+    char hmm_state;
+};
+
+// Entry point from nanopolish.cpp
+int eventalign_main(int argc, char** argv);
+
+// print the alignment as a tab-separated table
+void emit_event_alignment_tsv(FILE* fp,
+                              const SquiggleRead& sr,
+                              uint32_t strand_idx,
+                              const EventAlignmentParameters& params,
+                              const std::vector<EventAlignment>& alignments);
+
+// The main function to realign a read
+std::vector<EventAlignment> align_read_to_ref(const EventAlignmentParameters& params);
+
+// get the specified reference region, threadsafe
+std::string get_reference_region_ts(const faidx_t* fai, const char* ref_name, int start, int end, int* fetched_len);
+
+#endif
diff --git a/src/common/logsum.cpp b/src/common/logsum.cpp
new file mode 100644
index 0000000..0c5b21a
--- /dev/null
+++ b/src/common/logsum.cpp
@@ -0,0 +1,384 @@
+/* p7_FLogsum() function used in the Forward() algorithm.
+ * 
+ * Contents:
+ *    1. Floating point log sum.
+ *    2. Benchmark driver.
+ *    3. Unit tests.
+ *    4. Test driver.
+ *    5. Example.
+ *    6. Copyright and license information.
+ *
+ * Exegesis:
+ * 
+ * Internally, HMMER3 profile scores are in nats: floating point
+ * log-odds probabilities, with the log odds taken relative to
+ * background residue frequencies, and the log to the base e.
+ * 
+ * The Forward algorithm needs to calculate sums of probabilities.
+ * Given two log probabilities A and B, where s1 = \log
+ * \frac{a}{f}, and s2 = \log \frac{b}{g}, we need to
+ * calculate C = \log \frac{a + b}{h}.
+ * 
+ * The Forward algorithm guarantees that the null model denominator
+ * terms f = g = h, because it is always concerned with summing terms
+ * that describe different parses of the same target sequence prefix,
+ * and the product of the background frequencies for the same sequence
+ * prefix is a constant.
+ * 
+ * The naive solution is C = log(e^{A} + e^{B}), but this requires
+ * expensive calls to log() and exp().
+ * 
+ * A better solution is C = A + log(1 + e^{-(A-B)}), for A >= B.  For
+ * sufficiently small B << A, e^-{A-B} becomes less than the
+ * machine's FLT_EPSILON, and C ~= A. (This is at about (A-B) >
+ * -15.9, for the typical FLT_EPSILON of 1.2e-7.)
+ * 
+ * With some loss of accuracy [1], we can precalculate log(1 +
+ * e^{-(A-B)}) for a discretized range of differences (A-B), and
+ * compute C = A + table_lookup(A-B). This is what HMMER's
+ * p7_FLogsum() function does.
+ *
+ * This only applies to the generic (serial) implementation.
+ * See footnote [2] for discussion of why we remain unable to 
+ * implement an efficient log-space SIMD vector implementation of
+ * Forward.
+ */
+#include <math.h>
+#include "logsum.h"
+
+// storage
+float flogsum_lookup[p7_LOGSUM_TBL]; /* p7_LOGSUM_TBL=16000: (A-B) = 0..16 nats, steps of 0.001 */
+
+/*****************************************************************
+ *# 1. floating point log sum
+ *****************************************************************/
+
+// Initialize the lookup table used in p7_FLogsum
+int p7_FLogsumInit(void)
+{
+  static int firsttime = TRUE;
+  if (!firsttime) return eslOK;
+  firsttime = FALSE;
+
+  int i;
+  for (i = 0; i < p7_LOGSUM_TBL; i++) {
+    flogsum_lookup[i] = log(1. + exp((double) -i / p7_LOGSUM_SCALE));
+  }
+
+  return eslOK;
+}
+
+/* Function:  p7_FLogsumError()
+ * Synopsis:  Compute absolute error in probability from Logsum.
+ *
+ * Purpose:   Compute the absolute error in probability space
+ *            resulting from <p7_FLogsum()>'s table lookup 
+ *            approximation: approximation result - exact result.
+ *                                                  
+ *            This is of course computable analytically for
+ *            any <a,b> given <p7_LOGSUM_TBL>; but the function
+ *            is useful for some routines that want to determine
+ *            if <p7_FLogsum()> has been compiled in its
+ *            exact slow mode for debugging purposes. Testing
+ *            <p7_FLogsumError(-0.4, -0.5) > 0.0001>
+ *            for example, suffices to detect that the function
+ *            is compiled in its fast approximation mode given
+ *            the defaults. 
+ */
+float
+p7_FLogsumError(float a, float b)
+{
+  float approx = p7_FLogsum(a,b);
+  float exact  = log(exp(a) + exp(b));
+  return (exp(approx) - exp(exact));
+}
+
+/*****************************************************************
+ * 2. Benchmark driver.
+ *****************************************************************/
+#ifdef p7LOGSUM_BENCHMARK
+/* gcc -o logsum_benchmark -g -O2 -I. -L. -I../easel -L../easel -Dp7LOGSUM_BENCHMARK logsum.c -leasel -lm
+ * ./logsum_benchmark
+ */
+
+/* A table-driven FLogsum() is about 20x faster than a direct
+ * C = A + log(1+e^{-(A-B)}) implementation, "naive2()":
+ *             time/call   clocks/call
+ *  naive1:     110 nsec      250          SRE:J8/71 10 Aug 2011
+ *  naive2:      87 nsec      200          MacOS/X desktop, default build (gcc -O3), 2.26 GHz Xeon
+ *  FLogsum():    4 nsec        9 
+ *
+ * Times in units of nanoseconds/iteration: cpu time * 10
+ * based on default 1e8 iterations (-N 100000000).
+ * Clocks based on 2.26GHz = 2.26 clocks/nsec
+ */
+#include "p7_config.h"
+
+#include <math.h>
+
+#include "easel.h"
+#include "esl_getopts.h"
+#include "esl_random.h"
+#include "esl_stopwatch.h"
+
+#include "hmmer.h"
+
+static ESL_OPTIONS options[] = {
+  /* name           type      default  env  range toggles reqs incomp  help                                       docgroup*/
+  { "-h",        eslARG_NONE,    NULL, NULL, NULL,  NULL,  NULL, NULL, "show brief help on version and usage",    0 },
+  { "-n",        eslARG_NONE,    NULL, NULL, NULL,  NULL,  NULL, NULL, "naive time: A + log(1+exp(-(A-B)))",      0 },
+  { "-r",        eslARG_NONE,    NULL, NULL, NULL,  NULL,  NULL, NULL, "really naive time: log(exp(A)+exp(B))",   0 },
+  { "-s",        eslARG_INT,     "42", NULL, NULL,  NULL,  NULL, NULL, "set random number seed to <n>",           0 },
+  { "-v",        eslARG_NONE,    NULL, NULL, NULL,  NULL,  NULL, NULL, "be verbose: show individual results",     0 },
+  { "-N",        eslARG_INT,"100000000",NULL,"n>0", NULL,  NULL, NULL, "number of trials",                        0 },
+  {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+static char usage[]  = "[-options]";
+static char banner[] = "benchmark driver for logsum functions()";
+
+static float 
+naive1(float s1, float s2)
+{
+  return log(exp(s1) + exp(s2));
+}
+
+static float 
+naive2(float s1, float s2)
+{
+  if (s1 > s2) return s1 + log(1 + exp(s2-s1));
+  else         return s2 + log(1 + exp(s1-s2));
+}
+
+int 
+main(int argc, char **argv)
+{
+  ESL_GETOPTS    *go      = p7_CreateDefaultApp(options, 0, argc, argv, banner, usage);
+  ESL_RANDOMNESS *r       = esl_randomness_CreateFast(esl_opt_GetInteger(go, "-s"));
+  ESL_STOPWATCH  *w       = esl_stopwatch_Create();
+  int             N       = esl_opt_GetInteger(go, "-N");
+  int             i;
+  float          *A, *B, *C;
+
+  p7_FLogsumInit();
+
+  /* Create the problem: sample N values A,B on interval -1000,1000: about the range of H3 scores */
+  A = malloc(sizeof(float) * N);
+  B = malloc(sizeof(float) * N);
+  C = malloc(sizeof(float) * N);
+  for (i = 0; i < N; i++)
+    {
+      A[i] = esl_random(r) * 2000. - 1000.;
+      B[i] = esl_random(r) * 2000. - 1000.;
+    }
+  
+  /* Run */
+  esl_stopwatch_Start(w);
+
+  if (esl_opt_GetBoolean(go, "-n"))
+    {
+      for (i = 0; i < N; i++)
+	C[i] = naive2(A[i], B[i]);
+    }
+  else if (esl_opt_GetBoolean(go, "-r"))
+    {
+      for (i = 0; i < N; i++)
+	C[i] = naive1(A[i], B[i]);
+    }
+  else
+    {
+      for (i = 0; i < N; i++)
+	C[i] = p7_FLogsum(A[i], B[i]);       
+    }
+
+  esl_stopwatch_Stop(w);
+  esl_stopwatch_Display(stdout, w, "# CPU time: ");
+
+  esl_stopwatch_Destroy(w);
+  esl_randomness_Destroy(r);
+  esl_getopts_Destroy(go);
+  return 0;
+}
+#endif /*p7LOGSUM_BENCHMARK*/
+/*-------------------- end, benchmark ---------------------------*/
+
+
+/*****************************************************************
+ * 3. Unit tests
+ *****************************************************************/
+#ifdef p7LOGSUM_TESTDRIVE
+
+#include "easel.h"
+#include "esl_getopts.h"
+#include "esl_random.h"
+
+static void
+utest_FLogsumError(ESL_GETOPTS *go, ESL_RANDOMNESS *r)
+{
+  int     N          = esl_opt_GetInteger(go, "-N");
+  float   maxval     = esl_opt_GetReal(go, "-S");
+  int     be_verbose = esl_opt_GetBoolean(go, "-v");
+  float   maxerr = 0.0;
+  float   avgerr = 0.0;
+  int     i;
+  float   a,b,result,exact,err;
+
+  for (i = 0; i < N; i++)
+    {
+      a = (esl_random(r) - 0.5) * maxval * 2.; /* uniform draws on -maxval..maxval */
+      b = (esl_random(r) - 0.5) * maxval * 2.; 
+
+      exact  = log(exp(a) + exp(b));
+      result = p7_FLogsum(a,b);
+      err    = fabs(exact-result) / maxval;
+
+      avgerr += err;
+      maxerr = ESL_MAX(maxerr, err);
+
+      if (be_verbose)
+	printf("%8.4f %8.4f %8.4f %8.4f %8.4f\n", a, b, exact, result, err);
+    }
+  avgerr /= (float) N;
+
+  if (be_verbose) {
+    printf("average error = %f\n", avgerr);
+    printf("max error     = %f\n", maxerr);
+  }
+
+  if (maxerr > 0.0001) esl_fatal("maximum error of %f is too high: logsum unit test fails", maxerr);
+  if (avgerr > 0.0001) esl_fatal("average error of %f is too high: logsum unit test fails", avgerr);
+}
+
+static void
+utest_FLogsumSpecials(void)
+{
+  char *msg = "logsum specials unit test failed";
+
+  if (p7_FLogsum(0.0,          -eslINFINITY) !=          0.0) esl_fatal(msg);
+  if (p7_FLogsum(-eslINFINITY,          0.0) !=          0.0) esl_fatal(msg);
+  if (p7_FLogsum(-eslINFINITY, -eslINFINITY) != -eslINFINITY) esl_fatal(msg);
+}
+#endif /*p7LOGSUM_TESTDRIVE*/
+/*------------------- end, unit tests ---------------------------*/
+
+/*****************************************************************
+ * 4. Test driver.
+ *****************************************************************/
+#ifdef p7LOGSUM_TESTDRIVE
+/*
+  gcc -o logsum_utest -msse2 -g -Wall -I. -L. -I../easel -L../easel -Dp7LOGSUM_TESTDRIVE logsum.c -leasel -lm
+  ./logsum_utest
+ */
+#include "p7_config.h"
+
+#include <stdio.h>
+#include <math.h>
+
+#include "easel.h"
+#include "esl_getopts.h"
+#include "esl_random.h"
+
+#include "hmmer.h"
+
+static ESL_OPTIONS options[] = {
+  /* name  type         default  env   range togs  reqs  incomp  help                docgrp */
+  {"-h",  eslARG_NONE,    FALSE, NULL, NULL, NULL, NULL, NULL, "show help and usage",               0},
+  {"-N",  eslARG_INT,    "1000", NULL, "n>0",NULL, NULL, NULL, "number of samples",                 0},
+  {"-S",  eslARG_REAL,   "20.0", NULL, "x>0",NULL, NULL, NULL, "maximum operand value",             0},
+  {"-s",  eslARG_INT,      "42", NULL,"n>=0",NULL, NULL, NULL, "random number seed",                0},
+  {"-v",  eslARG_NONE,    FALSE, NULL, NULL, NULL, NULL, NULL, "show verbose output",               0},
+  { 0,0,0,0,0,0,0,0,0,0},
+};
+static char usage[]  = "[-options]";
+static char banner[] = "test driver for logsum.c";
+
+int 
+main(int argc, char **argv)
+{
+  ESL_GETOPTS    *go     = p7_CreateDefaultApp(options, 0, argc, argv, banner, usage);
+  ESL_RANDOMNESS *r      = esl_randomness_CreateFast(esl_opt_GetInteger(go, "-s"));
+
+  p7_FLogsumInit();
+
+  utest_FLogsumError(go, r);
+  utest_FLogsumSpecials();
+
+  esl_randomness_Destroy(r);
+  esl_getopts_Destroy(go);
+  return eslOK;
+}
+#endif /*p7LOGSUM_TESTDRIVE*/
+/*------------------ end, test driver ---------------------------*/
+
+
+/*****************************************************************
+ * 5. Example.
+ *****************************************************************/
+#ifdef p7LOGSUM_EXAMPLE
+/* gcc -o example -g -O2 -I. -L. -I../easel -L../easel -Dp7LOGSUM_EXAMPLE logsum.c -leasel -lm
+ * ./example -0.5 -0.5
+ */
+#include "p7_config.h"
+#include "easel.h"
+#include "hmmer.h"
+
+int
+main(int argc, char **argv)
+{
+  float a = atof(argv[1]);
+  float b = atof(argv[2]);
+  float result;
+
+  p7_FLogsumInit();
+  result = p7_FLogsum(a, b);
+  printf("p7_FLogsum(%f,%f) = %f\n", a, b, result);
+
+  result = log(exp(a) + exp(b));
+  printf("log(e^%f + e^%f) = %f\n", a, b, result);
+
+  printf("Absolute error in probability: %f\n", p7_FLogsumError(a,b));
+  return eslOK;
+}
+#endif /*p7LOGSUM_EXAMPLE*/
+/*--------------------- end, example ----------------------------*/
+
+/*****************************************************************
+ * HMMER - Biological sequence analysis with profile HMMs
+ * Version 3.1b2; February 2015
+ * Copyright (C) 2015 Howard Hughes Medical Institute.
+ * Other copyrights also apply. See HMMER's COPYRIGHT
+ * file for a full list.
+ *
+ * This file was originally part of HMMER. This version is used with
+ * Sean Eddy's permission as public domain code.
+ *
+ * Original version control information:
+ * SVN $URL: https://svn.janelia.org/eddylab/eddys/src/hmmer/branches/3.1/src/logsum.c $
+ * SVN $Id: logsum.c 3474 2011-01-17 13:25:32Z eddys $
+ *****************************************************************/
+
+/* Footnotes.
+ * 
+ * [1] The maximum relative error is on the order of 1/SCALE, or 0.001.
+ *     [xref SRE:J8/71].
+ *     
+ * [2] SIMD vectorization of a log-space Forward remains vexing.
+ *     Sparse-rescaled probability-space Forward vector
+ *     implemementation only works for local; glocal or global may
+ *     underflow long delete paths. Would be desirable to use a
+ *     log-space implementation if we could make it fast. Problem is
+ *     implementing the p7_FLogsum() lookup table in SIMD; lookup
+ *     tables of this size in current SSE, Altivec appear to be
+ *     infeasible. I considered the possibility of using a functional
+ *     fit to f(x) = log(1+e^{-x}) for x >=0, for example with a
+ *     Chebyshev polynomial, because a numerical f(x) would vectorize.
+ *     Decided that this computation would necessarily be expensive on
+ *     the order of log(x) or exp(x), so replacing log(1+exp(-x)) with
+ *     f(x) doesn't look like compelling -- might as well compute
+ *     log(1+exp(-x)) directly! The table-driven approach is about 20x
+ *     faster (about 9 clocks, compared to about 200 for the direct
+ *     log,exp calculation), and even if we could get an f(x)
+ *     calculation to be as efficient as log(x) -- say 100 clocks --
+ *     the 4x SIMD vectorization does not compensate for the 10x hit
+ *     in speed. [xref SRE:J8/71]
+ */
+
diff --git a/src/common/logsum.h b/src/common/logsum.h
new file mode 100644
index 0000000..d4ce12e
--- /dev/null
+++ b/src/common/logsum.h
@@ -0,0 +1,68 @@
+//
+// logsum -- a port of Sean Eddy's fast table-driven log sum
+// This code was originally part of HMMER. This version is used with 
+// Sean Eddy's permission as public domain code.
+//
+#ifndef LOGSUM_H
+#define LOGSUM_H
+#include <assert.h>
+#include <stdio.h>
+#include <cmath>
+
+/* p7_LOGSUM_SCALE defines the precision of the calculation; the
+ * default of 1000.0 means rounding differences to the nearest 0.001
+ * nat. p7_LOGSUM_TBL defines the size of the lookup table; the
+ * default of 16000 means entries are calculated for differences of 0
+ * to 16.000 nats (when p7_LOGSUM_SCALE is 1000.0).  e^{-p7_LOGSUM_TBL /
+ * p7_LOGSUM_SCALE} should be on the order of the machine FLT_EPSILON,
+ * typically 1.2e-7.
+ */
+#define p7_LOGSUM_TBL   16000
+#define p7_LOGSUM_SCALE 1000.f
+#define ESL_MAX(a,b)    (((a)>(b))?(a):(b))
+#define ESL_MIN(a,b)    (((a)<(b))?(a):(b))
+#define eslINFINITY     INFINITY
+#define TRUE            1
+#define FALSE           0
+#define eslOK           1
+
+/* Function:  p7_FLogsumInit()
+ * Synopsis:  Initialize the p7_Logsum() function.
+ *
+ * Purpose:   Initialize the lookup table for <p7_FLogsum()>. 
+ *            This function must be called once before any
+ *            call to <p7_FLogsum()>.
+ *            
+ *            The precision of the lookup table is determined
+ *            by the compile-time <p7_LOGSUM_TBL> constant.
+ *
+ * Returns:   <eslOK> on success.
+ */
+int p7_FLogsumInit(void);
+
+/* Function:  p7_FLogsum()
+ * Synopsis:  Approximate $\log(e^a + e^b)$.
+ *
+ * Purpose:   Returns a fast table-driven approximation to
+ *            $\log(e^a + e^b)$.
+ *            
+ *            Either <a> or <b> (or both) may be $-\infty$,
+ *            but neither may be $+\infty$ or <NaN>.
+ *
+ * Note:      This function is a critical optimization target, because
+ *            it's in the inner loop of generic Forward() algorithms.
+ */
+inline float
+p7_FLogsum(float a, float b)
+{
+  extern float flogsum_lookup[p7_LOGSUM_TBL]; /* p7_LOGSUM_TBL=16000: (A-B) = 0..16 nats, steps of 0.001 */
+
+  const float max = ESL_MAX(a, b);
+  const float min = ESL_MIN(a, b);
+
+  //return (min == -eslINFINITY || (max-min) >= 15.7f) ? max : max + log(1.0 + exp(min-max));  /* SRE: While debugging SSE impl. Remember to remove! */
+  
+  return (min == -eslINFINITY || (max-min) >= 15.7f) ? max : max + flogsum_lookup[(int)((max-min)*p7_LOGSUM_SCALE)];
+} 
+
+#endif
diff --git a/src/common/nanopolish_alphabet.cpp b/src/common/nanopolish_alphabet.cpp
new file mode 100644
index 0000000..500108c
--- /dev/null
+++ b/src/common/nanopolish_alphabet.cpp
@@ -0,0 +1,55 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_alphabet -- support for multiple alphabets
+//
+#include <assert.h>
+#include "nanopolish_alphabet.h"
+
+const uint8_t DNAAlphabet::_rank[256] = {
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,0,
+    0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+const char* DNAAlphabet::_base = "ACGT";
+const char* DNAAlphabet::_complement = "TGCA";
+const uint32_t DNAAlphabet::_size = 4;
+
+const uint8_t MethylCpGAlphabet::_rank[256] = {
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,1,0,0,0,2,0,0,0,0,0,3,0,0,
+    0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+const char* MethylCpGAlphabet::_base = "ACGMT";
+const uint32_t MethylCpGAlphabet::_size = 5;
+
+DNAAlphabet gDNAAlphabet;
+MethylCpGAlphabet gMCpGAlphabet;
diff --git a/src/common/nanopolish_alphabet.h b/src/common/nanopolish_alphabet.h
new file mode 100644
index 0000000..22824dd
--- /dev/null
+++ b/src/common/nanopolish_alphabet.h
@@ -0,0 +1,192 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_alphabet -- support for multiple alphabets
+//
+#ifndef NANOPOLISH_ALPHABET_H
+#define NANOPOLISH_ALPHABET_H
+
+#include <string>
+#include <inttypes.h>
+#include <assert.h>
+#include "nanopolish_iupac.h"
+
+// A table to map { A, C, G, T } => { 0, 1, 2, 3 }
+extern const uint8_t dna_base_rank[];
+
+// Abstract base class for alphabets
+class Alphabet
+{
+    public:
+        // basic functions
+        virtual uint8_t rank(char b) const = 0;
+        virtual char base(uint8_t r) const = 0;
+        virtual uint32_t size() const = 0;
+
+        // return the lexicographic rank of the kmer amongst all strings of 
+        // length k for this alphabet
+        inline uint32_t kmer_rank(const char* str, uint32_t k) const
+        {
+            uint32_t p = 1;
+            uint32_t r = 0;
+
+            // from last base to first
+            for(uint32_t i = 0; i < k; ++i) {
+                r += rank(str[k - i - 1]) * p;
+                p *= size();
+            }
+            return r;
+        }
+        
+        // Increment the input string to be the next sequence in lexicographic order
+        inline void lexicographic_next(std::string& str) const
+        {
+            int carry = 1;
+            int i = str.size() - 1;
+            do {
+                uint32_t r = rank(str[i]) + carry;
+                str[i] = base(r % size());
+                carry = r / size();
+                i -= 1;
+            } while(carry > 0 && i >= 0);
+        }
+
+        // returns the number of unique strings of length l for this alphabet
+        inline size_t get_num_strings(size_t l) const
+        {
+            size_t s = size();
+            size_t n = 1;
+            for(size_t i = 0; i < l; ++i) {
+                n *= s;
+            }
+            return n;
+        }
+
+        // reverse complement a string over this alphabet
+        virtual std::string reverse_complement(const std::string& seq) const = 0;
+
+        // remove ambiguous nucleotides from the string
+        virtual std::string disambiguate(const std::string& seq) const = 0; 
+};
+
+struct DNAAlphabet : public Alphabet
+{
+    static const uint8_t _rank[256];
+    static const char* _base;
+    static const char* _complement;
+    static const uint32_t _size;
+
+    virtual uint8_t rank(char b) const { return _rank[b]; }
+    virtual char base(uint8_t r) const { return _base[r]; }
+    virtual uint32_t size() const { return _size; }
+
+    virtual std::string reverse_complement(const std::string& seq) const
+    {
+        std::string out(seq.length(), 'A');
+        size_t last_pos = seq.length() - 1;
+        for(int i = last_pos; i >= 0; --i) {
+            out[last_pos - i] = _complement[_rank[seq[i]]];
+        }
+        return out;
+    }
+
+    // return a new copy of the string with ambiguous characters changed
+    virtual std::string disambiguate(const std::string& str) const
+    {
+        std::string out(str);
+        for(size_t i = 0; i < str.length(); ++i) {
+            assert(IUPAC::isValid(str[i]));
+            out[i] = IUPAC::getPossibleSymbols(str[i])[0];
+        }
+        return out;
+    }
+
+};
+
+// DNABaseMap with methyl-cytosine
+struct MethylCpGAlphabet : public Alphabet
+{
+    static const uint8_t _rank[256];
+    static const char* _base;
+    static const char* _complement;
+    static const uint32_t _size;
+
+    virtual uint8_t rank(char b) const { return _rank[b]; }
+    virtual char base(uint8_t r) const { return _base[r]; }
+    virtual uint32_t size() const { return _size; }
+
+    virtual std::string reverse_complement(const std::string& seq) const
+    {
+        std::string out(seq.length(), 'A');
+        size_t i = 0; // input
+        int j = seq.length() - 1; // output
+        while(i < seq.length()) {
+            if(seq[i] == 'M') {
+                
+                out[j--] = 'G';
+                i += 1;
+
+                // CpG methylation model requires M to be followed by G
+                // (if there is space)
+                if(j >= 0) {
+                    assert(i < seq.length());
+                    assert(seq[i] == 'G');
+                    out[j--] = 'M';
+                    ++i;
+                }
+            } else {
+                out[j--] = DNAAlphabet::_complement[DNAAlphabet::_rank[seq[i++]]];
+            }
+        }
+        return out;
+    }
+
+    // return a new copy of the string with ambiguous characters changed
+    virtual std::string disambiguate(const std::string& str) const
+    {
+        std::string out(str);
+        for(size_t i = 0; i < str.length(); ++i) {
+            if(str[i] == 'M' && i != str.length() - 1 && str[i + 1] == 'G') {
+                // CpG site, assume its methylated not an ambiguity symbol
+                out[i] = 'M';
+            } else {
+                assert(IUPAC::isValid(str[i]));
+                out[i] = IUPAC::getPossibleSymbols(str[i])[0];
+            }
+        }
+        return out;
+    }
+
+    // Convert CpGs of the sequence to mCpG
+    std::string methylate(const std::string& str) const
+    {
+        std::string out(str);
+        for(size_t i = 0; i < out.length() - 1; ++i) {
+            if(out[i] == 'C' && out[i + 1] == 'G') {
+                out[i] = 'M';
+            }
+        }
+        return out;
+    }
+
+    // Convert methylated bases to C
+    std::string unmethylate(const std::string& str) const
+    {
+        std::string out(str);
+        for(size_t i = 0; i < out.length(); ++i) {
+            if(out[i] == 'M') {
+                out[i] = 'C';
+            }
+        }
+        return out;
+    }
+
+};
+
+// Global alphabet objects that can be re-used
+extern DNAAlphabet gDNAAlphabet;
+extern MethylCpGAlphabet gMCpGAlphabet;
+
+#endif
diff --git a/src/common/nanopolish_common.cpp b/src/common/nanopolish_common.cpp
new file mode 100644
index 0000000..e9c163c
--- /dev/null
+++ b/src/common/nanopolish_common.cpp
@@ -0,0 +1,30 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_common -- Data structures and definitions
+// shared across files
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "nanopolish_common.h"
+#include "nanopolish_squiggle_read.h"
+
+// Split a string into parts based on the delimiter
+std::vector<std::string> split(std::string in, char delimiter)
+{
+    std::vector<std::string> out;
+    size_t lastPos = 0;
+    size_t pos = in.find_first_of(delimiter);
+
+    while(pos != std::string::npos)
+    {
+        out.push_back(in.substr(lastPos, pos - lastPos));
+        lastPos = pos + 1;
+        pos = in.find_first_of(delimiter, lastPos);
+    }
+    out.push_back(in.substr(lastPos));
+    return out;
+}
diff --git a/src/common/nanopolish_common.h b/src/common/nanopolish_common.h
new file mode 100644
index 0000000..dae1cc9
--- /dev/null
+++ b/src/common/nanopolish_common.h
@@ -0,0 +1,111 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_common -- Data structures and definitions
+// shared across files
+//
+#ifndef NANOPOLISH_COMMON_H
+#define NANOPOLISH_COMMON_H
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <math.h>
+#include "nanopolish_alphabet.h"
+#include "profiler.h"
+#include "logsum.h"
+
+#define PACKAGE_NAME "nanopolish"
+#define PACKAGE_VERSION "0.4.0"
+#define PACKAGE_BUGREPORT "https://github.com/jts/nanopolish/issues"
+
+//
+// Enumerated types
+//
+enum AlignmentPolicy
+{
+    AP_GLOBAL,
+    AP_SEMI_KMER
+};
+
+//
+// Constants
+//
+
+// strands
+const uint8_t T_IDX = 0;
+const uint8_t C_IDX = 1;
+const uint8_t NUM_STRANDS = 2;
+
+//
+// Data structures
+//
+
+class SquiggleRead;
+
+// This struct is used as input into the HMM
+// It tracks where the event stream starts/stops
+// for the partial consensus sequence under consideration
+struct HMMInputData
+{
+    SquiggleRead* read;
+    uint32_t anchor_index;
+    uint32_t event_start_idx;
+    uint32_t event_stop_idx;
+    uint8_t strand;
+    int8_t event_stride;
+    uint8_t rc;
+};
+
+// A representation of an event->kmer alignment
+struct HMMAlignmentState
+{
+    uint32_t event_idx;
+    uint32_t kmer_idx;
+    double l_posterior;
+    double l_fm;
+    double log_transition_probability;
+    char state;
+};
+
+// The parameters of a gaussian distribution
+struct GaussianParameters
+{
+    GaussianParameters() : mean(0.0f), stdv(1.0f) { log_stdv = log(stdv); }
+    GaussianParameters(float m, float s) : mean(m), stdv(s) { log_stdv = log(stdv); }
+
+    float mean;
+    float stdv;
+    float log_stdv; // == log(stdv), pre-computed for efficiency
+};
+
+//
+// Functions
+//
+#define ESL_LOG_SUM 1
+
+// Add the log-scaled values a and b using a transform to avoid precision errors
+inline double add_logs(const double a, const double b)
+{
+#if ESL_LOG_SUM
+    return p7_FLogsum(a, b);
+#else
+    if(a == -INFINITY && b == -INFINITY)
+        return -INFINITY;
+
+    if(a > b) {
+        double diff = b - a;
+        return a + log(1.0 + exp(diff));
+    } else {
+        double diff = a - b;
+        return b + log(1.0 + exp(diff));
+    }
+#endif
+}
+
+// split a string based on a delimiter
+std::vector<std::string> split(std::string in, char delimiter);
+
+#endif
diff --git a/src/common/nanopolish_fast5_map.cpp b/src/common/nanopolish_fast5_map.cpp
new file mode 100644
index 0000000..c2530e8
--- /dev/null
+++ b/src/common/nanopolish_fast5_map.cpp
@@ -0,0 +1,135 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_fast5_map - a simple map from a read
+// name to a fast5 file path
+#include <stdio.h>
+#include <inttypes.h>
+#include <zlib.h>
+#include <fstream>
+#include <ostream>
+#include <iostream>
+#include <sys/stat.h>
+#include "nanopolish_fast5_map.h"
+#include "nanopolish_common.h"
+#include "htslib/kseq.h"
+
+//
+#define FOFN_SUFFIX ".fast5.fofn"
+
+KSEQ_INIT(gzFile, gzread);
+
+Fast5Map::Fast5Map(const std::string& fasta_filename)
+{
+    // If the fofn file exists, load from it
+    // otherwise parse the entire fasta file
+    std::string fofn_filename = fasta_filename + FOFN_SUFFIX;
+    struct stat fofn_file_s;
+    struct stat fasta_file_s;
+    int fofn_ret = stat(fofn_filename.c_str(), &fofn_file_s);
+    int fasta_ret = stat(fasta_filename.c_str(), &fasta_file_s);
+
+    // Use the stored fofn if its available and newer than the fasta
+    if(fofn_ret == 0 && fofn_file_s.st_mtime > fasta_file_s.st_mtime) {
+        load_from_fofn(fofn_filename);
+    } else {
+        load_from_fasta(fasta_filename);
+    }
+}
+
+std::string Fast5Map::get_path(const std::string& read_name) const
+{
+    std::map<std::string, std::string>::const_iterator 
+        iter = read_to_path_map.find(read_name);
+
+    if(iter == read_to_path_map.end()) {
+        fprintf(stderr, "error: could not find fast5 path for %s\n", read_name.c_str());
+        exit(EXIT_FAILURE);
+    }
+
+    return iter->second;
+}
+
+//
+void Fast5Map::load_from_fasta(std::string fasta_filename)
+{
+    gzFile gz_fp;
+
+    FILE* fp = fopen(fasta_filename.c_str(), "r");
+    if(fp == NULL) {
+        fprintf(stderr, "error: could not open %s for read\n", fasta_filename.c_str());
+        exit(EXIT_FAILURE);
+    }
+
+    gz_fp = gzdopen(fileno(fp), "r");
+    if(gz_fp == NULL) {
+        fprintf(stderr, "error: could not open %s using gzdopen\n", fasta_filename.c_str());
+        exit(EXIT_FAILURE);
+    }
+
+    kseq_t* seq = kseq_init(gz_fp);
+    
+    while(kseq_read(seq) >= 0) {
+        if(seq->comment.l == 0) {
+            fprintf(stderr, "error: no path associated with read %s\n", seq->name.s);
+            exit(EXIT_FAILURE);
+        }
+
+        // This splitting code implicitly handles both the 2 and 3 field
+        // fasta format that poretools will output. The FAST5 path
+        // is always the last field.
+        std::vector<std::string> fields = split(seq->comment.s, ' ');
+        assert(read_to_path_map.find(seq->name.s) == read_to_path_map.end());
+        read_to_path_map[seq->name.s] = fields.back();
+    }
+
+    kseq_destroy(seq);
+    gzclose(gz_fp);
+    fclose(fp);
+    
+    // Sanity check that the first path actually points to a file
+    if(read_to_path_map.size() > 0) {
+        std::string first_read = read_to_path_map.begin()->first;
+        std::string first_path = read_to_path_map.begin()->second;
+        struct stat file_s;
+        int ret = stat(first_path.c_str(), &file_s);
+        if(ret != 0) {
+            fprintf(stderr, "Error: could not find path to FAST5 for read %s\n", first_read.c_str());
+            fprintf(stderr, "Please make sure that this path is accessible: %s\n", first_path.c_str());
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // Write the map as a fofn file so next time we don't have to parse
+    // the entire fasta
+    write_to_fofn(fasta_filename + FOFN_SUFFIX);
+}
+
+void Fast5Map::write_to_fofn(std::string fofn_filename)
+{
+    std::ofstream outfile(fofn_filename.c_str());
+
+    for(std::map<std::string, std::string>::iterator iter = read_to_path_map.begin();
+        iter != read_to_path_map.end(); ++iter) {
+        outfile << iter->first << "\t" << iter->second << "\n";
+    }
+}
+
+//
+void Fast5Map::load_from_fofn(std::string fofn_filename)
+{
+    std::ifstream infile(fofn_filename.c_str());
+
+    if(infile.bad()) {
+        fprintf(stderr, "error: could not read fofn %s\n", fofn_filename.c_str());
+        exit(EXIT_FAILURE);
+    }
+
+    std::string name;
+    std::string path;
+    while(infile >> name >> path) {
+        read_to_path_map[name] = path;
+    }
+}
diff --git a/src/common/nanopolish_fast5_map.h b/src/common/nanopolish_fast5_map.h
new file mode 100644
index 0000000..614829a
--- /dev/null
+++ b/src/common/nanopolish_fast5_map.h
@@ -0,0 +1,39 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_fast5_map - a simple map from a read
+// name to a fast5 file path
+#ifndef NANOPOLISH_FAST5_MAP
+#define NANOPOLISH_FAST5_MAP
+
+#include <string>
+#include <map>
+
+class Fast5Map
+{
+    public:
+        Fast5Map(const std::string& fasta_filename);
+        
+        // return the path for the given read name
+        // if the read does not exist in the map, emits an error
+        // and exits
+        std::string get_path(const std::string& read_name) const;
+
+    private:
+
+        // Read the read -> path map from the header of a fasta file
+        void load_from_fasta(std::string fasta_filename);
+
+        // Read the map from a pre-computed .fofn file
+        void load_from_fofn(std::string fofn_filename);
+        
+        // Write the map to the .fofn file
+        void write_to_fofn(std::string fofn_filename);
+
+        std::map<std::string, std::string> read_to_path_map;
+
+};
+
+#endif
diff --git a/src/common/nanopolish_iupac.cpp b/src/common/nanopolish_iupac.cpp
new file mode 100644
index 0000000..ba5bc50
--- /dev/null
+++ b/src/common/nanopolish_iupac.cpp
@@ -0,0 +1,92 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_iupac -- handle iupac ambiguity codes
+//
+#include <assert.h>
+#include "nanopolish_iupac.h"
+
+// IUPAC alphabet
+bool IUPAC::isUnambiguous(char c)
+{
+    switch(c)
+    {
+        case 'A':
+        case 'C':
+        case 'G':
+        case 'T':
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Returns true if c is a valid ambiguity code
+bool IUPAC::isAmbiguous(char c)
+{
+    switch(c)
+    {
+        case 'M':
+        case 'R':
+        case 'W':
+        case 'S':
+        case 'Y':
+        case 'K':
+        case 'V':
+        case 'H':
+        case 'D':
+        case 'B':
+        case 'N':
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Returns true if c is a valid symbol in this alphabet
+bool IUPAC::isValid(char c)
+{
+    return isUnambiguous(c) || isAmbiguous(c);
+}
+
+//
+std::string IUPAC::getPossibleSymbols(char c)
+{
+    switch(c)
+    {
+        case 'A':
+            return "A";
+        case 'C':
+            return "C";
+        case 'G':
+            return "G";
+        case 'T':
+            return "T";
+        case 'M':
+            return "AC";
+        case 'R':
+            return "AG";
+        case 'W':
+            return "AT";
+        case 'S':
+            return "CG";
+        case 'Y':
+            return "CT";
+        case 'K':
+            return "GT";
+        case 'V':
+            return "ACG";
+        case 'H':
+            return "ACT";
+        case 'D':
+            return "AGT";
+        case 'B':
+            return "CGT";
+        case 'N':
+            return "ACGT";
+        default:
+            return "";
+    }
+}
diff --git a/src/common/nanopolish_iupac.h b/src/common/nanopolish_iupac.h
new file mode 100644
index 0000000..4466213
--- /dev/null
+++ b/src/common/nanopolish_iupac.h
@@ -0,0 +1,30 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_iupac -- handle iupac ambiguity codes
+//
+#ifndef NANOPOLISH_IUPAC_H
+#define NANOPOLISH_IUPAC_H
+
+#include <string>
+
+// IUPAC ambiguity alphabet
+namespace IUPAC
+{
+    // Returns true if c is [ACGT]
+    bool isUnambiguous(char c);
+
+    // Returns true if c is a valid ambiguity code
+    bool isAmbiguous(char c);
+
+    // Returns true if c is a valid symbol in this alphabet
+    bool isValid(char c);
+
+    // Returns a string defining the possible unambiguous bases for each symbol
+    // in the alphabet
+    std::string getPossibleSymbols(char c);
+};
+
+#endif
diff --git a/src/common/nanopolish_klcs.cpp b/src/common/nanopolish_klcs.cpp
new file mode 100644
index 0000000..6d4c252
--- /dev/null
+++ b/src/common/nanopolish_klcs.cpp
@@ -0,0 +1,86 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_klcs -- function to compute the longest
+// common subsequence of k-mers for two strings
+//
+#include <algorithm>
+#include "nanopolish_klcs.h"
+
+// Helper to backtrack through the kLCS matrix
+void _kLCSBacktrack(const UInt32Matrix& m,
+                    const std::string& a, 
+                    const std::string& b,
+                    const int k,
+                    uint32_t row,
+                    uint32_t col,
+                    kLCSResult& result)
+{
+    if(row == 0 || col == 0)
+        return;
+
+    const char* ka = a.c_str() + row - 1;
+    const char* kb = b.c_str() + col - 1;
+
+    if(strncmp(ka, kb, k) == 0) {
+        kLCSPair p = { row - 1, col - 1 };
+        result.push_back(p);
+        return _kLCSBacktrack(m, a, b, k, row - 1, col - 1, result);
+    } else {
+
+        if(get(m, row - 1, col) > get(m, row, col - 1)) {
+            return _kLCSBacktrack(m, a, b, k, row - 1, col, result);
+        } else {
+            return _kLCSBacktrack(m, a, b, k, row, col - 1, result);
+        }
+    }
+}
+
+// Return the longest common subseuqence of k-mers between the two strings
+kLCSResult kLCS(const std::string& a, const std::string& b, const int k)
+{
+    uint32_t n_kmers_a = a.size() - k + 1;
+    uint32_t n_kmers_b = b.size() - k + 1;
+
+    uint32_t n_rows = n_kmers_a + 1;
+    uint32_t n_cols = n_kmers_b + 1;
+
+    UInt32Matrix m;
+    allocate_matrix(m, n_rows, n_cols);
+
+    // Initialize first row/col to zero
+    for(uint32_t row = 0; row < m.n_rows; ++row)
+        set(m, row, 0, 0);
+    for(uint32_t col = 0; col < m.n_cols; ++col)
+        set(m, 0, col, 0);
+    
+    // Fill matrix
+    for(uint32_t row = 1; row < m.n_rows; ++row) {
+        for(uint32_t col = 1; col < m.n_cols; ++col) {
+    
+            const char* ka = a.c_str() + row - 1;
+            const char* kb = b.c_str() + col - 1;
+
+            uint32_t score = 0;
+            if(strncmp(ka, kb, k) == 0) {
+                uint32_t diag = get(m, row - 1, col - 1);
+                score = diag + 1;
+            } else {
+                uint32_t left = get(m, row, col - 1);
+                uint32_t up = get(m, row - 1, col);
+                score = std::max(left, up);
+            }
+            set(m, row, col, score);
+        }
+    }
+
+    kLCSResult result;
+    _kLCSBacktrack(m, a, b, k, n_rows - 1, n_cols -  1, result);
+
+    // Backtrack appends from the end to the start, reverse the vector of matches
+    std::reverse(result.begin(), result.end());
+    free_matrix(m);
+    return result;
+}
diff --git a/src/common/nanopolish_klcs.h b/src/common/nanopolish_klcs.h
new file mode 100644
index 0000000..2df62eb
--- /dev/null
+++ b/src/common/nanopolish_klcs.h
@@ -0,0 +1,27 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_klcs -- function to compute the longest
+// common subsequence of k-mers for two strings
+//
+#ifndef NANOPOLISH_KLCS_H
+#define NANOPOLISH_KLCS_H
+
+#include <stdint.h>
+#include <vector>
+#include <string>
+#include "nanopolish_matrix.h"
+
+// The indices of a k-mer match in a pair of sequences
+struct kLCSPair
+{
+    uint32_t i;
+    uint32_t j;
+};
+typedef std::vector<kLCSPair> kLCSResult;
+
+kLCSResult kLCS(const std::string& a, const std::string& b, const int k);
+
+#endif
diff --git a/src/common/nanopolish_matrix.h b/src/common/nanopolish_matrix.h
new file mode 100644
index 0000000..0bd8ca0
--- /dev/null
+++ b/src/common/nanopolish_matrix.h
@@ -0,0 +1,102 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_matrix -- matrix manipulation functions
+//
+#ifndef NANOPOLISH_MATRIX_H
+#define NANOPOLISH_MATRIX_H
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "nanopolish_matrix.h"
+
+//
+// Template Matrix for POD types
+//
+template<typename T>
+struct Matrix
+{
+    T* cells;
+    uint32_t n_rows;
+    uint32_t n_cols;
+};
+
+typedef Matrix<double> DoubleMatrix;
+typedef Matrix<float> FloatMatrix;
+typedef Matrix<uint32_t> UInt32Matrix;
+typedef Matrix<uint8_t> UInt8Matrix;
+
+//
+template<typename T>
+void allocate_matrix(Matrix<T>& matrix, uint32_t n_rows, uint32_t n_cols)
+{
+    matrix.n_rows = n_rows;
+    matrix.n_cols = n_cols;
+    
+    uint32_t N = matrix.n_rows * matrix.n_cols;
+    matrix.cells = (T*)malloc(N * sizeof(T));
+    memset(matrix.cells, 0, N * sizeof(T));
+}
+
+//
+template<typename T>
+void free_matrix(Matrix<T>& matrix)
+{
+    assert(matrix.cells != NULL);
+    free(matrix.cells);
+    matrix.cells = NULL;
+}
+
+// Copy a matrix and its contents
+template<typename T>
+void copy_matrix(Matrix<T>& new_matrix, const Matrix<T>& old_matrix)
+{
+    allocate_matrix(new_matrix, old_matrix.n_rows, old_matrix.n_cols);
+    uint32_t bytes = sizeof(T) * new_matrix.n_rows * new_matrix.n_cols;
+    memcpy(new_matrix.cells, old_matrix.cells, bytes);
+}
+
+//
+template<typename T>
+inline uint32_t cell(const Matrix<T>& matrix, uint32_t row, uint32_t col)
+{
+    return row * matrix.n_cols + col;
+}
+
+//
+template<typename T, typename U>
+inline void set(Matrix<T>& matrix, uint32_t row, uint32_t col, U v)
+{
+    uint32_t c = cell(matrix, row, col);
+    matrix.cells[c] = v;
+}
+
+// 
+template<typename T>
+inline T get(const Matrix<T>& matrix, uint32_t row, uint32_t col)
+{
+    uint32_t c = cell(matrix, row, col);
+    return matrix.cells[c];
+}
+
+//
+inline void print_matrix(const DoubleMatrix& matrix, bool do_exp = false)
+{
+    for(uint32_t i = 0; i < matrix.n_rows; ++i) {
+        for(uint32_t j = 0; j < matrix.n_cols; ++j) {
+            uint32_t c = cell(matrix, i, j);
+            double v = matrix.cells[c];
+            if(do_exp)
+                v = exp(v);
+            printf("%.3lf\t", v);
+        }
+        printf("\n");
+    }
+}
+
+#endif
diff --git a/src/common/nanopolish_variant.cpp b/src/common/nanopolish_variant.cpp
new file mode 100644
index 0000000..bcd3d31
--- /dev/null
+++ b/src/common/nanopolish_variant.cpp
@@ -0,0 +1,298 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_variants -- tools for calling variants
+//
+#include <algorithm>
+#include <map>
+#include "nanopolish_profile_hmm.h"
+#include "nanopolish_variant.h"
+#include "nanopolish_haplotype.h"
+
+// return a new copy of the string with gap symbols removed
+std::string remove_gaps(const std::string& str)
+{
+    std::string ret = str;
+    ret.erase( std::remove(ret.begin(), ret.end(), '-'), ret.end());
+    return ret;
+}
+
+// extract differences between the pair of strings
+std::vector<Variant> extract_variants(const std::string& reference, 
+                                      const std::string& haplotype)
+{
+    AlnParam par = aln_param_nt2nt;
+    par.band_width = std::max(20, abs(reference.size() - haplotype.size()) * 2);
+    AlnAln* aln = aln_stdaln(reference.c_str(), haplotype.c_str(), &par, 1, 1);
+    
+    // Make aligned strings where gaps are padded with '-'
+    std::string pad_ref(aln->out1);
+    std::string pad_hap(aln->out2);
+
+    assert(pad_ref.size() == pad_hap.size());
+    
+    //std::cout << "PR: " << pad_ref << "\n";
+    //std::cout << "PH: " << pad_hap << "\n";
+
+    // parse variants from the alignment
+    std::vector<Variant> variants;
+
+    // generate a map from padded bases to positions in the original reference sequence
+    std::vector<size_t> ref_positions(pad_ref.size(), 0);
+    size_t pos = 0;
+    for(size_t i = 0; i < pad_ref.size(); ++i) {
+        ref_positions[i] = pad_ref[i] != '-' ? pos : std::string::npos;
+        pos += pad_ref[i] != '-';
+    }
+
+    // diff_start iterates over the places where these sequences are different
+    size_t diff_start = 0;
+    while(1) {
+        
+        // find the start point of the next difference between the strings
+        while(diff_start < pad_ref.size() && pad_ref[diff_start] == pad_hap[diff_start]) {
+            diff_start++;
+        }
+ 
+        // check for end of alignment
+        if(diff_start == pad_ref.size())
+            break;
+
+        // find the end point of the difference
+        bool is_indel = false;
+        size_t diff_end = diff_start;
+        while(diff_end < pad_ref.size() && pad_ref[diff_end] != pad_hap[diff_end]) {
+            is_indel = is_indel || pad_ref[diff_end] == '-' || pad_hap[diff_end] == '-';
+            diff_end++;
+        }
+
+        // If the difference is an indel, we include the previous matching reference base
+        diff_start -= is_indel;
+    
+        Variant v;
+        v.ref_name = "noctg";
+
+        assert(ref_positions[diff_start] != std::string::npos);
+        v.ref_position = ref_positions[diff_start];
+        v.ref_seq = remove_gaps(pad_ref.substr(diff_start, diff_end - diff_start).c_str());
+        v.alt_seq = remove_gaps(pad_hap.substr(diff_start, diff_end - diff_start).c_str());
+        
+        variants.push_back(v);
+        diff_start = diff_end;
+    }
+
+    aln_free_AlnAln(aln);
+    return variants;
+}
+
+void filter_variants_by_count(std::vector<Variant>& variants, int min_count)
+{
+    std::map<std::string, std::pair<Variant, int>> map;
+
+    for(size_t i = 0; i < variants.size(); ++i) {
+        std::string key = variants[i].key();
+        auto iter = map.find(key);
+        if(iter == map.end()) {
+            map.insert(std::make_pair(key, std::make_pair(variants[i], 1)));
+        } else {
+            iter->second.second += 1;
+        }
+    }
+
+    variants.clear();
+
+    for(auto iter = map.begin(); iter != map.end(); ++iter) {
+        Variant& v = iter->second.first;
+        if(iter->second.second >= min_count) {
+            v.add_info("BaseCalledReadsWithVariant", iter->second.second);
+            variants.push_back(v);
+        }
+    }
+}
+
+void filter_out_non_snp_variants(std::vector<Variant>& variants)
+{
+    std::vector<Variant> tmp;
+    for(size_t i = 0; i < variants.size(); ++i) {
+        bool is_snp = variants[i].ref_seq.length() == 
+                      variants[i].alt_seq.length();
+        if(is_snp) {
+            tmp.push_back(variants[i]);
+        }
+    }
+    variants.swap(tmp);
+}
+
+std::vector<Variant> select_variants(const std::vector<Variant>& candidate_variants,
+                                     Haplotype base_haplotype,
+                                     const std::vector<HMMInputData>& input)
+{
+    // make a copy of the variant set to modify
+    std::vector<Variant> all_variants = candidate_variants;
+
+    // Calculate baseline probablilty
+    std::vector<Variant> selected_variants;
+
+    double base_lp = profile_hmm_score(base_haplotype.get_sequence(), input);
+
+    while(!all_variants.empty()) {
+ 
+        double best_variant_lp = -INFINITY;
+        size_t best_variant_idx = 0;
+        size_t best_supporting_reads = 0;
+
+        std::vector<double> base_lp_by_read; 
+        for(size_t j = 0; j < input.size(); ++j) {
+            double tmp = profile_hmm_score(base_haplotype.get_sequence(), input[j]);
+            base_lp_by_read.push_back(tmp);
+        }
+
+        for(size_t i = 0; i < all_variants.size(); ++i) {
+        
+            // apply the variant to get a new haplotype
+            Variant& v = all_variants[i];
+            Haplotype derived = base_haplotype;
+            derived.apply_variant(v);
+
+            // score the haplotype
+            double variant_lp = 0.0f;
+            size_t supporting_reads = 0;
+            #pragma omp parallel for
+            for(size_t j = 0; j < input.size(); ++j) {
+                double tmp = profile_hmm_score(derived.get_sequence(), input[j]);
+                #pragma omp critical
+                {
+                    variant_lp += tmp;
+                    supporting_reads += tmp > base_lp_by_read[j];
+                }
+            }
+            
+            if(variant_lp > best_variant_lp) {
+                best_variant_lp = variant_lp;
+                best_variant_idx = i;
+                best_supporting_reads = supporting_reads;
+            }
+        }
+
+        if(best_variant_lp - base_lp > 1.0) {
+            // move the best variant from the all list to the selected list
+            Variant& best_variant = all_variants[best_variant_idx];
+            best_variant.add_info("TotalReads", input.size());
+            best_variant.add_info("SupportingReads", best_supporting_reads);
+            best_variant.add_info("SupportFraction", (double)best_supporting_reads / input.size());
+            best_variant.quality = best_variant_lp - base_lp;
+            selected_variants.push_back(best_variant);
+
+            //printf("SELECTED %zu from %zu: \n\t", best_variant_idx, all_variants.size() + 1);
+
+            // apply the variant to the base haplotype
+            base_haplotype.apply_variant(selected_variants.back());
+            base_lp = best_variant_lp;
+        } else {
+            // no variant improved upon the base haplotype, stop
+            break;
+        }
+    }
+
+    return selected_variants;
+}
+
+std::vector<Variant> select_variant_set(const std::vector<Variant>& candidate_variants,
+                                        Haplotype base_haplotype, 
+                                        const std::vector<HMMInputData>& input,
+                                        const uint32_t alignment_flags)
+{
+    size_t num_variants = candidate_variants.size();
+    size_t num_haplotypes = 1 << num_variants;
+    
+    double base_lp_by_strand[2] = { 0.0f, 0.0f };
+    double base_lp_by_rc[2] = { 0.0f, 0.0f };
+    double base_lp = 0.0f;
+    std::vector<double> base_lp_by_read(input.size()); 
+    
+    #pragma omp parallel for
+    for(size_t j = 0; j < input.size(); ++j) {
+
+        double tmp = profile_hmm_score(base_haplotype.get_sequence(), input[j], alignment_flags);
+
+        #pragma omp critical
+        {
+            base_lp_by_read[j] = tmp;
+            base_lp += tmp;
+            base_lp_by_strand[input[j].strand] += tmp;
+            base_lp_by_rc[input[j].rc] += tmp;
+        }
+    }
+
+    double best_lp = -INFINITY;
+    std::vector<Variant> best_variant_set;
+
+    // The haplotype id is a bitmask indicating which variants
+    // to apply to get the haplotype. We skip the empty
+    // variant set.
+    for(size_t hi = 1; hi < num_haplotypes; ++hi) {
+
+        Haplotype current_haplotype = base_haplotype;
+        std::vector<Variant> current_variant_set;
+
+        for(size_t vi = 0; vi < num_variants; vi++) {
+            // if bit vi is set in the haplotype id, apply this variant
+            if( (hi & (1 << vi)) == 0) {
+                continue;
+            }
+
+            current_variant_set.push_back(candidate_variants[vi]);
+            current_haplotype.apply_variant(current_variant_set.back());
+        }
+        
+        // score the haplotype
+        double current_lp = 0.0f;
+        double current_lp_by_strand[2] = { 0.0f, 0.0f };
+        double current_lp_by_rc[2] = { 0.0f, 0.0f };
+
+        size_t supporting_reads = 0;
+
+        #pragma omp parallel for
+        for(size_t j = 0; j < input.size(); ++j) {
+            double tmp = profile_hmm_score(current_haplotype.get_sequence(), input[j], alignment_flags);
+            #pragma omp critical
+            {
+                current_lp += tmp;
+                supporting_reads += tmp > base_lp_by_read[j];
+                current_lp_by_strand[input[j].strand] += tmp;
+                current_lp_by_rc[input[j].rc] += tmp;
+            }
+        }
+
+        if(current_lp > best_lp && current_lp - base_lp > 1.0) {
+            best_lp = current_lp;
+            best_variant_set = current_variant_set;
+
+            // Annotate variants
+            for(size_t vi = 0; vi < best_variant_set.size(); ++vi) {
+                Variant& v = best_variant_set[vi];
+                v.add_info("TotalReads", input.size());
+                v.add_info("SupportingReads", supporting_reads);
+                v.add_info("SupportFraction", (double)supporting_reads / input.size());
+                v.add_info("TemplateQuality", current_lp_by_strand[0] - base_lp_by_strand[0]);
+                v.add_info("ComplementQuality", current_lp_by_strand[1] - base_lp_by_strand[1]);
+                v.add_info("ForwardQuality", current_lp_by_rc[0] - base_lp_by_rc[0]);
+                v.add_info("ReverseQuality", current_lp_by_rc[1] - base_lp_by_rc[1]);
+                v.quality = best_lp - base_lp;
+            }
+        }
+
+#ifdef DEBUG_HAPLOTYPE_SELECTION
+        std::stringstream ss;
+        for(size_t vi = 0; vi < current_variant_set.size(); ++vi) {
+            const Variant& v = current_variant_set[vi];
+            ss << (vi > 0 ? "," : "") << v.key();
+        }
+        fprintf(stderr, "haplotype: %zu variants: %s relative score: %.2lf\n", hi, ss.str().c_str(), current_lp - base_lp);
+#endif
+    }
+    return best_variant_set;
+}
+
diff --git a/src/common/nanopolish_variant.h b/src/common/nanopolish_variant.h
new file mode 100644
index 0000000..e99c97d
--- /dev/null
+++ b/src/common/nanopolish_variant.h
@@ -0,0 +1,115 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_variant -- tools for calling variants
+//
+#ifndef NANOPOLISH_VARIANT_H
+#define NANOPOLISH_VARIANT_H
+
+#include <sstream>
+#include "stdaln.h"
+#include "nanopolish_common.h"
+
+// forward declare
+class Haplotype;
+
+struct Variant
+{
+    static void write_vcf_header(FILE* fp) {
+        fprintf(fp, "#CHROM	POS	ID	REF	ALT	QUAL	FILTER	INFO\n");
+    }
+
+    Variant() { }
+    Variant(const std::string& line) { read_vcf(line); }
+
+    // generate a unique identifier for this variant
+    std::string key() const
+    {
+        std::stringstream out;
+        out << ref_name << ':' << ref_position << ':' << ref_seq << ':' << alt_seq;
+        return out.str();
+    }
+
+    void write_vcf(FILE* fp)
+    {
+        fprintf(fp, "%s\t%zu\t%s\t", ref_name.c_str(), ref_position + 1, ".");
+        fprintf(fp, "%s\t%s\t%.1lf\t", ref_seq.c_str(), alt_seq.c_str(), quality);
+        fprintf(fp, "%s\t%s\n", "PASS", info.c_str());
+    }
+
+    void read_vcf(const std::string& line)
+    {
+        std::stringstream ss(line);
+        std::string dummy;
+        ss >> ref_name;
+        ss >> ref_position;
+        ss >> dummy; // ID, not used
+        ss >> ref_seq;
+        ss >> alt_seq;
+        ss >> quality;
+        ss >> dummy; // FILTER, not used
+        ss >> info;
+
+        // VCF is 1-based but we internally represent a variant as 0-based
+        ref_position -= 1;
+
+        assert(!ref_name.empty());
+        assert(!ref_seq.empty());
+        assert(!alt_seq.empty());
+        assert(ref_position >= 0);
+        assert(quality >= 0.0f);
+    }
+
+    template<typename T>
+    void add_info(const std::string& key, T value)
+    {
+        std::stringstream ss;
+        ss << key << "=" << value;
+        if(info.empty()) {
+            info = ss.str();
+        } else {
+            info.append(1, ';');
+            info.append(ss.str());
+        }
+    }
+
+    std::string ref_name;
+    size_t ref_position;
+    std::string ref_seq;
+    std::string alt_seq;
+    double quality;
+    std::string info;
+};
+
+inline bool sortByPosition(const Variant& a, const Variant& b) 
+{ 
+    return a.ref_name == b.ref_name ? 
+        a.ref_position < b.ref_position : 
+        a.ref_name < b.ref_name; 
+}
+
+// Determine potential variants between the reference and haplotype string
+std::vector<Variant> extract_variants(const std::string& reference, 
+                                      const std::string& haplotype);
+
+// Remove variants that are in the vector fewer than min_count times
+void filter_variants_by_count(std::vector<Variant>& variants, int min_count);
+
+// Remove snps or indels 
+void filter_out_non_snp_variants(std::vector<Variant>& variants);
+
+// Select variants to add to the base haplotype one-by-one
+std::vector<Variant> select_variants(const std::vector<Variant>& candidate_variants,
+                                     Haplotype base_haplotype, 
+                                     const std::vector<HMMInputData>& input);
+
+// Select groups of variants to add to the base haplotype
+std::vector<Variant> select_variant_set(const std::vector<Variant>& candidate_variants,
+                                        Haplotype base_haplotype, 
+                                        const std::vector<HMMInputData>& input,
+                                        const uint32_t alignment_flags);
+
+
+#endif
diff --git a/src/common/profiler.h b/src/common/profiler.h
new file mode 100644
index 0000000..3068ddb
--- /dev/null
+++ b/src/common/profiler.h
@@ -0,0 +1,70 @@
+///----------------------------------------------
+// Copyright 2011 Wellcome Trust Sanger Institute
+// Written by Jared Simpson (js18 at sanger.ac.uk)
+// Released under the GPL
+//-----------------------------------------------
+//
+// Profiler.h -- Lightweight macro-based function profiler.
+//
+#ifndef PROFILER_H
+#define PROFILER_H
+
+#include <time.h>
+#include <iostream>
+
+//#define USE_PROFILER 1
+
+#if USE_PROFILER
+
+// Change this to determine how often the profile should print
+#define PROFILE_TICKS_BEFORE_PRINT 1000
+
+// This class writes the lifespan of the object
+// to the output variable, in nanoseconds
+class TimeTracker
+{
+    public:
+        TimeTracker(size_t & output) : m_output(output)
+        {
+             timespec start;
+             clock_gettime(CLOCK_REALTIME, &start);
+             m_start_ns = start.tv_sec * 1000000000 + start.tv_nsec;
+        }
+
+        ~TimeTracker()
+        {
+             timespec end;
+             clock_gettime(CLOCK_REALTIME, &end);
+             size_t end_ns = end.tv_sec * 1000000000 + end.tv_nsec;
+
+             // Update the result using an atomic compare and swap
+             size_t diff = end_ns - m_start_ns;
+             while(!__sync_bool_compare_and_swap(&m_output, m_output, m_output + diff)) {}
+        }
+
+    private:
+        size_t m_start_ns;
+        size_t& m_output;
+};
+
+// Place this macros at the start of the function you wish the profile
+// The static variable updates are done via atomic compare and swaps so
+// the profiling should be threadsafe
+#define PROFILE_FUNC(x) static std::string __profile_name = x; \
+                        static size_t __profile_iterations = 0; \
+                        static size_t __profile_total_nanoseconds = 0; \
+                        double micro_seconds = (double)__profile_total_nanoseconds / 1000.0f; \
+                        double avg_per_iteration = micro_seconds / __profile_iterations; \
+                        while(!__sync_bool_compare_and_swap(&__profile_iterations, __profile_iterations, __profile_iterations + 1)) { } \
+                        if(__profile_iterations % PROFILE_TICKS_BEFORE_PRINT == 0) \
+                            fprintf(stderr, "[Profile] count: %zu time: %.0lf ms avg: %.0lf us func: %s\n", __profile_iterations, micro_seconds / 1000, avg_per_iteration, __profile_name.c_str()); \
+                        TimeTracker __profile_timer(__profile_total_nanoseconds);
+                         
+#else
+
+// Eliminate the macro
+#define PROFILE_FUNC(x)
+
+#endif // #ifdef HAVE_CLOCK_GETTIME
+
+#endif // #ifndef PROFILER_H
diff --git a/src/common/progress.h b/src/common/progress.h
new file mode 100644
index 0000000..e4f3aeb
--- /dev/null
+++ b/src/common/progress.h
@@ -0,0 +1,82 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// progress -- Small class to write the progress
+// of a long running task to stderr
+//
+#ifndef PROGRESS_H
+#define PROGRESS_H
+
+#include <time.h>
+
+class Progress
+{
+    public:
+        
+        Progress(const std::string message) : m_message(message), m_os(std::cerr)
+        {
+#if HAVE_CLOCK_GETTIME            
+            timespec start;
+            clock_gettime(CLOCK_REALTIME, &start);
+            m_start_time = start.tv_sec;
+#else
+            m_start_time = 0;
+#endif
+        }
+
+        // derived from: http://stackoverflow.com/a/14539953/378881
+        void print(float progress) const
+        {
+
+            // print 
+            int max_leader = 40;
+            int bar_width = 50;
+
+            std::string leader;
+            if(m_message.size() > max_leader) {
+                leader = m_message.substr(0, max_leader - 3) + "..."; // truncate
+            } else {
+                leader = m_message + std::string(max_leader - m_message.size(), ' '); // pad
+            }
+            
+            m_os << leader << " [";
+            
+            int pos = bar_width * progress;
+            for (int i = 0; i < bar_width; ++i) {
+                if (i < pos) m_os << "=";
+                else if (i == pos) m_os << ">";
+                else m_os << " ";
+            }
+            m_os << "] " << int(progress * 100.0) << "% in " << get_elapsed_seconds() << "s\r";
+            m_os.flush();
+        }
+        
+        // 
+        void end() const
+        {
+            print(1.0);
+            std::cerr << std::endl;
+        }
+
+        double get_elapsed_seconds() const
+        {
+            // get current time
+#if HAVE_CLOCK_GETTIME            
+            timespec now;
+            clock_gettime(CLOCK_REALTIME, &now);
+            return now.tv_sec - m_start_time;
+#else
+            return 0;
+#endif
+        }
+
+    private:
+
+        std::ostream& m_os;
+        std::string m_message;
+        size_t m_start_time;
+};
+
+#endif
diff --git a/src/hmm/nanopolish_emissions.h b/src/hmm/nanopolish_emissions.h
new file mode 100644
index 0000000..e90462d
--- /dev/null
+++ b/src/hmm/nanopolish_emissions.h
@@ -0,0 +1,109 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_emissions -- Emission distributions and
+// related functions for the HMMs
+//
+#ifndef NANOPOLISH_EMISSIONS_H
+#define NANOPOLISH_EMISSIONS_H
+
+#include <math.h>
+#include "nanopolish_common.h"
+#include "nanopolish_squiggle_read.h"
+
+//#define MODEL_STDV
+//#define DEBUG_HMM_EMISSION 1
+
+// From SO: http://stackoverflow.com/questions/10847007/using-the-gaussian-probability-density-function-in-c
+inline float normal_pdf(float x, const GaussianParameters& g)
+{
+    static const float inv_sqrt_2pi = 0.3989422804014327;
+    float a = (x - g.mean) / g.stdv;
+    return inv_sqrt_2pi / g.stdv * exp(-0.5f * a * a);
+}
+
+inline float log_normal_pdf(float x, const GaussianParameters& g)
+{
+    static const float log_inv_sqrt_2pi = log(0.3989422804014327);
+    float a = (x - g.mean) / g.stdv;
+    return log_inv_sqrt_2pi - g.log_stdv + (-0.5f * a * a);
+}
+
+inline float z_score(const SquiggleRead& read,
+                     uint32_t kmer_rank,
+                     uint32_t event_idx,
+                     uint8_t strand)
+{
+    const PoreModel& pm = read.pore_model[strand];
+    float level = read.get_drift_corrected_level(event_idx, strand);
+    GaussianParameters model = pm.get_scaled_parameters(kmer_rank);
+    return (level - model.mean) / model.stdv;
+}
+
+inline float log_probability_match(const SquiggleRead& read,
+                                   uint32_t kmer_rank,
+                                   uint32_t event_idx,
+                                   uint8_t strand,
+                                   float state_scale = 1.0f,
+                                   float log_state_scale = 0.0f)
+{
+    const PoreModel& pm = read.pore_model[strand];
+
+    // event level mean
+    float level = read.get_drift_corrected_level(event_idx, strand);
+
+    GaussianParameters model = pm.get_scaled_parameters(kmer_rank);
+
+    // we go to great lengths to avoid calling log() in the inner loop of the HMM
+    // for this reason we duplicate data here and require the caller to pass
+    // in the scale and log(scale), presumably these are cached
+    model.stdv *= state_scale;
+    model.log_stdv += log_state_scale;
+    float lp = log_normal_pdf(level, model);
+
+#if MODEL_STDV
+    // event level stdv
+    float stdv = read.events[strand].stdv[event_idx];
+    float model_sd_mean = pm.state[kmer_rank].sd_mean * pm.scale_sd;
+    float model_sd_stdv = pm.state[kmer_rank].sd_stdv * sqrt(pow(pm.scale_sd, 3.0) / pm.var_sd);
+    lp += log_normal_pdf(stdv, model_sd_mean, model_sd_stdv);
+#endif
+
+#if DEBUG_HMM_EMISSION
+    printf("Event[%d] Kmer: %d -- L:%.1lf m: %.1lf s: %.1lf p: %.3lf p_old: %.3lf\n", event_idx, kmer_rank, level, model.mean, model.stdv, exp(lp), normal_pdf(level, model));
+#endif
+
+    return lp;
+}
+
+inline float log_probability_event_insert(const SquiggleRead& read,
+                                          uint32_t kmer_rank,
+                                          uint32_t event_idx,
+                                          uint8_t strand)
+{
+    static const float scale = 1.75f;
+    static const float log_scale = log(scale);
+
+    return log_probability_match(read, kmer_rank, event_idx, strand, scale, log_scale);
+}
+
+inline float log_probability_background(const SquiggleRead& read,
+                                        uint32_t event_idx,
+                                        uint8_t strand)
+{
+    return -3.0f;
+}
+
+
+inline float log_probability_kmer_insert(const SquiggleRead& read,
+                                         uint32_t kmer_rank,
+                                         uint32_t event_idx,
+                                         uint8_t strand)
+
+{
+    return log_probability_match(read, kmer_rank, event_idx, strand);
+}
+
+#endif
diff --git a/src/hmm/nanopolish_hmm_input_sequence.h b/src/hmm/nanopolish_hmm_input_sequence.h
new file mode 100644
index 0000000..e121780
--- /dev/null
+++ b/src/hmm/nanopolish_hmm_input_sequence.h
@@ -0,0 +1,85 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_hmm_input_sequence -- a nucleotide sequence
+// that is input into the hidden Markov model
+//
+#ifndef NANOPOLISH_HMM_INPUT_SEQUENCE
+#define NANOPOLISH_HMM_INPUT_SEQUENCE
+
+#include <string>
+#include "nanopolish_common.h"
+#include "nanopolish_alphabet.h"
+
+//
+// This class is a general wrapper around a string
+// that allows different alphabets to be used.
+// 
+class HMMInputSequence
+{
+    public:
+    
+        // constructors
+        HMMInputSequence(const std::string& seq) : 
+                             m_seq(seq),
+                             m_alphabet(&gDNAAlphabet)
+        {
+            m_rc_seq = m_alphabet->reverse_complement(seq);
+        }
+
+        HMMInputSequence(const std::string& fwd,
+                         const std::string& rc,
+                         const Alphabet* alphabet) : 
+                             m_seq(fwd),
+                             m_rc_seq(rc),
+                             m_alphabet(alphabet)
+        {
+
+        }
+
+
+        //
+        size_t length() const { return m_seq.length(); }
+
+
+        // returns the i-th kmer of the sequence
+        inline std::string get_kmer(uint32_t i, uint32_t k, bool do_rc) const
+        {
+            return ! do_rc ? m_seq.substr(i, k) : 
+                             m_rc_seq.substr(m_rc_seq.length() - i - k, k);
+        }
+        
+        // get the number of kmer ranks supported by the alphabet for this sequence
+        size_t get_num_kmer_ranks(size_t k) const { return m_alphabet->get_num_strings(k); }
+
+        // get the lexicographic rank of the i-th kmer
+        // if the do_rc flag is set, return the rank of
+        // reverse-complemented version of the ki-th kmer
+        // NOT the ki-th kmer of the reverse-complemented sequence
+        inline uint32_t get_kmer_rank(uint32_t i, uint32_t k, bool do_rc) const
+        {
+            return ! do_rc ? _kmer_rank(i, k) : _rc_kmer_rank(i, k);
+        }
+
+    private:
+
+        inline uint32_t _kmer_rank(uint32_t i, uint32_t k) const
+        {
+            return m_alphabet->kmer_rank(m_seq.c_str() + i, k);
+        }
+
+        inline uint32_t _rc_kmer_rank(uint32_t i, uint32_t k) const
+        {
+            return m_alphabet->kmer_rank(m_rc_seq.c_str() + (length() - i - k), k);
+        }
+
+        HMMInputSequence(); // not allowed
+        const Alphabet* m_alphabet;
+
+        std::string m_seq;
+        std::string m_rc_seq;
+};
+
+#endif
diff --git a/src/hmm/nanopolish_profile_hmm.cpp b/src/hmm/nanopolish_profile_hmm.cpp
new file mode 100644
index 0000000..f51c4b1
--- /dev/null
+++ b/src/hmm/nanopolish_profile_hmm.cpp
@@ -0,0 +1,271 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_profile_hmm -- Profile Hidden Markov Model
+//
+#include <algorithm>
+#include "nanopolish_profile_hmm.h"
+
+//#define DEBUG_FILL
+//#define PRINT_TRAINING_MESSAGES 1
+
+void profile_hmm_forward_initialize(FloatMatrix& fm)
+{
+    // initialize forward calculation
+    for(uint32_t si = 0; si < fm.n_cols; si++) {
+        set(fm, 0, si, -INFINITY);
+    }
+
+    for(uint32_t ri = 0; ri < fm.n_rows; ri++) {
+        set(fm, ri, PS_KMER_SKIP, -INFINITY);
+        set(fm, ri, PS_EVENT_SPLIT, -INFINITY);
+        set(fm, ri, PS_MATCH, -INFINITY);
+    }
+}
+
+// Terminate the forward algorithm by calculating
+// the probability of transitioning to the end state
+// for all columns and a given row
+float profile_hmm_forward_terminate(const FloatMatrix& fm,
+                                    const FloatMatrix& tm,
+                                    uint32_t row)
+{
+    assert(false);
+    return -INFINITY;
+
+    /*
+    float sum = -INFINITY;
+    uint32_t tcol = fm.n_cols - 1;
+    for(uint32_t sk = 0; sk < fm.n_cols - 1; sk++) {
+        // transition probability from state k to state l
+        float t_kl = get(tm, sk, tcol);
+        float fm_k = get(fm, row, sk);
+        sum = add_logs(sum, t_kl + fm_k);
+    }
+    return sum;
+    */
+}
+
+// convenience function to run the HMM over multiple inputs and sum the result
+float profile_hmm_score(const HMMInputSequence& sequence, const std::vector<HMMInputData>& data, const uint32_t flags)
+{
+    float score = 0.0f;
+    for(size_t i = 0; i < data.size(); ++i) {
+        score += profile_hmm_score(sequence, data[i], flags);
+    }
+    return score;
+}
+
+float profile_hmm_score(const HMMInputSequence& sequence, const HMMInputData& data, const uint32_t flags)
+{
+    const uint32_t k = data.read->pore_model[data.strand].k;
+    uint32_t n_kmers = sequence.length() - k + 1;
+
+    uint32_t n_states = PS_NUM_STATES * (n_kmers + 2); // + 2 for explicit terminal states
+
+    uint32_t e_start = data.event_start_idx;
+    uint32_t e_end = data.event_stop_idx;
+    uint32_t n_events = 0;
+    if(e_end > e_start)
+        n_events = e_end - e_start + 1;
+    else
+        n_events = e_start - e_end + 1;
+
+    uint32_t n_rows = n_events + 1;
+
+    // Allocate a matrix to hold the HMM result
+    FloatMatrix fm;
+    allocate_matrix(fm, n_rows, n_states);
+
+    profile_hmm_forward_initialize(fm);
+
+    ProfileHMMForwardOutput output(&fm);
+
+    float score = profile_hmm_fill_generic(sequence, data, e_start, flags, output);
+
+    // cleanup
+    free_matrix(fm);
+    return score;
+}
+
+void profile_hmm_viterbi_initialize(FloatMatrix& m)
+{
+    // Same as forward initialization
+    profile_hmm_forward_initialize(m);
+}
+
+std::vector<HMMAlignmentState> profile_hmm_align(const HMMInputSequence& sequence, const HMMInputData& data, const uint32_t flags)
+{
+    std::vector<HMMAlignmentState> alignment;
+    const uint32_t k = data.read->pore_model[data.strand].k;
+
+    uint32_t n_kmers = sequence.length() - k + 1;
+    uint32_t n_states = PS_NUM_STATES * (n_kmers + 2); // + 2 for explicit terminal states
+
+    uint32_t e_start = data.event_start_idx;
+    uint32_t e_end = data.event_stop_idx;
+    uint32_t n_events = 0;
+    if(e_end > e_start)
+        n_events = e_end - e_start + 1;
+    else
+        n_events = e_start - e_end + 1;
+    assert(n_events >= 2);
+
+    uint32_t n_rows = n_events + 1;
+    
+    // Allocate matrices to hold the HMM result
+    FloatMatrix vm;
+    allocate_matrix(vm, n_rows, n_states);
+    
+    UInt8Matrix bm;
+    allocate_matrix(bm, n_rows, n_states);
+
+    ProfileHMMViterbiOutput output(&vm, &bm);
+
+    profile_hmm_viterbi_initialize(vm);
+    profile_hmm_fill_generic(sequence, data, e_start, flags, output);
+
+    // Traverse the backtrack matrix to compute the results
+    
+    // start from the last event matched to the last kmer
+    uint32_t row = n_rows - 1;
+    uint32_t col = PS_NUM_STATES * n_kmers + PS_MATCH;
+
+    while(row > 0) {
+        
+        uint32_t event_idx = e_start + (row - 1) * data.event_stride;
+        uint32_t block = col / PS_NUM_STATES;
+        assert(block > 0);
+        assert(get(vm, row, col) != -INFINITY);
+
+        uint32_t kmer_idx = block - 1;
+        
+        ProfileState curr_ps = (ProfileState) (col % PS_NUM_STATES);
+
+        HMMAlignmentState as;
+        as.event_idx = event_idx;
+        as.kmer_idx = kmer_idx;
+        as.l_posterior = -INFINITY; // not computed
+        as.l_fm = get(vm, row, col);
+        as.log_transition_probability = -INFINITY; // not computed
+        as.state = ps2char(curr_ps);
+        alignment.push_back(as);
+
+        // Update the event (row) and k-mer using the current state
+        // The next state is encoded in the backtrack matrix for the current cell
+        ProfileState next_ps = (ProfileState)get(bm, row, col);
+        
+        // If we hit the softclip state we are done aligning
+        if(next_ps == PS_PRE_SOFT) {
+            break;
+        }
+
+#if DEBUG_BACKTRACK
+        printf("Backtrack [%zu %zu] k: %zu block: %zu curr_ps: %c next_ps: %c\n", row, col, kmer_idx, block, ps2char(curr_ps), ps2char(next_ps));
+#endif
+
+        if(curr_ps == PS_MATCH) {
+            row -= 1;
+            kmer_idx -= 1;
+        } else if(curr_ps == PS_EVENT_SPLIT) {
+            row -= 1;
+            // kmer stays the same
+        } else {
+            assert(curr_ps == PS_KMER_SKIP);
+            // row stays the same
+            kmer_idx -= 1;
+        }
+
+        col = PS_NUM_STATES * (kmer_idx + 1) + next_ps;
+    }
+
+    //
+    std::reverse(alignment.begin(), alignment.end());
+
+    //
+    free_matrix(vm);
+    free_matrix(bm);
+
+    return alignment;
+}
+
+// Print the alignment between the read-strand and a sequence
+void print_alignment(const std::string& name,
+                     uint32_t seq_id,
+                     uint32_t read_id,
+                     const HMMInputSequence& sequence, 
+                     const HMMInputData& data,
+                     const std::vector<HMMAlignmentState>& alignment)
+{
+    size_t n_matches = 0;
+    size_t n_merges = 0;
+    size_t n_skips = 0;
+    size_t n_mergeskips = 0;
+    
+    const uint32_t k = data.read->pore_model[data.strand].k;
+
+    char prev_s = '\0';
+    for(size_t pi = 0; pi < alignment.size(); ++pi) {
+
+        uint32_t ei = alignment[pi].event_idx;
+        uint32_t ki = alignment[pi].kmer_idx;
+        char s = alignment[pi].state;
+    
+        double level = data.read->get_drift_corrected_level(ei, data.strand);
+        double sd = data.read->events[data.strand][ei].stdv;
+        double duration = data.read->get_duration(ei, data.strand);
+        uint32_t rank = sequence.get_kmer_rank(ki, k, data.rc);
+        
+        const PoreModel& pm = data.read->pore_model[data.strand];
+        GaussianParameters model = pm.get_scaled_parameters(rank);
+
+        double norm_level = (level - model.mean) / model.stdv;
+        
+        double model_sd_mean = 0.0f;
+        double model_sd_stdv = 0.0f;
+
+        n_matches += (s == 'M');
+        n_merges += (s == 'E');
+        n_skips += (s == 'K');
+        n_mergeskips += (s == 'K' && prev_s == 'E');
+
+        double lp_diff = 0.0f;
+        if(pi > 0) {
+            lp_diff = alignment[pi].l_fm - alignment[pi - 1].l_fm;
+        } else {
+            lp_diff = alignment[pi].l_fm;
+        }
+        std::string kmer = sequence.get_kmer(ki, k, false);
+ 
+        printf("DEBUG\t%s\t%d\t%d\t%c\t", name.c_str(), read_id, data.rc, "tc"[data.strand]);
+        printf("%c\t%d\t%d\t", s, ei, ki);
+        printf("%s\t%.3lf\t", kmer.c_str(), duration);
+        printf("%.1lf\t%.1lf\t%.1lf\t", level, model.mean, norm_level);
+        printf("\t%.1lf\t%.1lf\t%.1lf\t", sd, model_sd_mean, (sd - model_sd_mean) / model_sd_stdv);
+        printf("%.2lf\t%.2lf\t%.2lf\n", exp(alignment[pi].l_posterior), alignment[pi].l_fm, lp_diff);
+        prev_s = s;
+    }
+
+    // Summarize alignment
+    double time_start = data.read->events[data.strand][data.event_start_idx].start_time;
+    double time_end = data.read->events[data.strand][data.event_stop_idx].start_time;
+    double total_duration = fabs(time_start - time_end);
+    double num_events = abs(data.event_start_idx - data.event_stop_idx) + 1;
+    double final_lp = alignment[alignment.size() - 1].l_fm;
+    double mean_lp = final_lp / num_events;
+
+    // Print summary header on first entry
+    static int once = 1;
+    if(once) {
+        printf("SUMMARY\tseq_name\tseq_id\tread_id\tis_rc\tstrand\t");
+        printf("lp\tmean_lp\tnum_events\t");
+        printf("n_matches\tn_merges\tn_skips\tn_mergeskips\ttotal_duration\n");
+        once = 0;
+    }
+
+    printf("SUMMARY\t%s\t%d\t%d\t%d\t%c\t", name.c_str(), seq_id, read_id, data.rc, data.strand ? 't' : 'c');
+    printf("%.2lf\t%.2lf\t%.0lf\t", final_lp, mean_lp, num_events);
+    printf("%zu\t%zu\t%zu\t%zu\t%.2lf\n", n_matches, n_merges, n_skips, n_mergeskips, total_duration);
+}
diff --git a/src/hmm/nanopolish_profile_hmm.h b/src/hmm/nanopolish_profile_hmm.h
new file mode 100644
index 0000000..dc0afe0
--- /dev/null
+++ b/src/hmm/nanopolish_profile_hmm.h
@@ -0,0 +1,103 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_profile_hmm -- Profile Hidden Markov Model
+//
+#ifndef NANOPOLISH_PROFILE_HMM_H
+#define NANOPOLISH_PROFILE_HMM_H
+
+#include <stdint.h>
+#include <vector>
+#include <string>
+#include "nanopolish_matrix.h"
+#include "nanopolish_common.h"
+#include "nanopolish_emissions.h"
+#include "nanopolish_hmm_input_sequence.h"
+
+//
+// High level algorithms
+//
+
+// Calculate the probability of the nanopore events given a sequence
+float profile_hmm_score(const HMMInputSequence& sequence, const HMMInputData& data, const uint32_t flags = 0);
+float profile_hmm_score(const HMMInputSequence& sequence, const std::vector<HMMInputData>& data, const uint32_t flags = 0);
+
+// Run viterbi to align events to kmers
+std::vector<HMMAlignmentState> profile_hmm_align(const HMMInputSequence& sequence, const HMMInputData& data, const uint32_t flags = 0);
+
+// Print the alignment between the read-strand and a sequence
+void print_alignment(const std::string& name,
+                     uint32_t seq_id,
+                     uint32_t read_id,
+                     const HMMInputSequence& consensus, 
+                     const HMMInputData& data,
+                     const std::vector<HMMAlignmentState>& alignment);
+
+//
+// Forward algorithm
+//
+
+// Initialize the forward algorithm
+void profile_hmm_forward_initialize(FloatMatrix& fm);
+
+// Terminate the forward algorithm
+float profile_hmm_forward_terminate(const FloatMatrix& fm, uint32_t row);
+
+//
+// Viterbi
+// 
+
+// initialize viterbi
+void profile_hmm_viterbi_initialize(FloatMatrix& m);
+
+//
+// Training
+//
+void profile_hmm_update_training(const HMMInputSequence& sequence, 
+                                 const HMMInputData& data);
+
+
+// Convenience enum for keeping track of the states in the profile HMM
+enum ProfileState
+{
+    PS_KMER_SKIP = 0,
+    PS_EVENT_SPLIT,
+    PS_MATCH,
+    PS_NUM_STATES = 3,
+    PS_PRE_SOFT // intentionally after PS_NUM_STATES
+};
+
+// Flags to modify the behaviour of the HMM
+enum HMMAlignmentFlags
+{
+    HAF_ALLOW_PRE_CLIP = 1, // allow events to go unmatched before the aligning region
+    HAF_ALLOW_POST_CLIP = 2 // allow events to go unmatched after the aligning region
+};
+
+// Convert an enumerated state into a symbol
+inline char ps2char(ProfileState ps) { return "KEMNS"[ps]; }
+
+// Pre-computed transitions from the previous block
+// into the current block of states. Log-scaled.
+struct BlockTransitions
+{
+    // Transition from m state
+    float lp_me;
+    float lp_mk;
+    float lp_mm;
+
+    // Transitions from e state
+    float lp_ee;
+    float lp_em;
+
+    // Transitions from k state
+    float lp_kk;
+    float lp_km;
+};
+
+//
+#include "nanopolish_profile_hmm.inl"
+
+#endif
diff --git a/src/hmm/nanopolish_profile_hmm.inl b/src/hmm/nanopolish_profile_hmm.inl
new file mode 100644
index 0000000..38a7449
--- /dev/null
+++ b/src/hmm/nanopolish_profile_hmm.inl
@@ -0,0 +1,403 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_profile_hmm -- Profile Hidden Markov Model
+//
+inline float calculate_skip_probability(const HMMInputSequence& sequence,
+                                        const HMMInputData& data,
+                                        uint32_t ki,
+                                        uint32_t kj)
+{
+    const PoreModel& pm = data.read->pore_model[data.strand];
+    const TransitionParameters& parameters = data.read->parameters[data.strand];
+
+    uint32_t rank_i = sequence.get_kmer_rank(ki, pm.k, data.rc);
+    uint32_t rank_j = sequence.get_kmer_rank(kj, pm.k, data.rc);
+
+    GaussianParameters level_i = pm.get_scaled_parameters(rank_i);
+    GaussianParameters level_j = pm.get_scaled_parameters(rank_j);
+
+    return parameters.get_skip_probability(level_i.mean, level_j.mean);
+}
+
+inline std::vector<BlockTransitions> calculate_transitions(uint32_t num_kmers, const HMMInputSequence& sequence, const HMMInputData& data)
+{
+    const TransitionParameters& parameters = data.read->parameters[data.strand];
+
+    std::vector<BlockTransitions> transitions(num_kmers);
+    
+    for(uint32_t ki = 0; ki < num_kmers; ++ki) {
+
+        // probability of skipping k_i from k_(i - 1)
+        float p_skip = ki > 0 ? calculate_skip_probability(sequence, data, ki - 1, ki) : 0.0f;
+
+        // transitions from match state in previous block
+        float p_mk = p_skip;
+        float p_me = (1 - p_skip) * parameters.trans_m_to_e_not_k;
+        float p_mm = 1.0f - p_me - p_mk;
+
+        // transitions from event split state in previous block
+        float p_ee = parameters.trans_e_to_e;
+        float p_em = 1.0f - p_ee;
+        // p_ie not allowed
+
+        // transitions from kmer skip state in previous block
+        float p_kk = p_skip;
+        float p_km = 1 - p_skip;
+        // p_ei not allowed    
+
+        // log-transform and store
+        BlockTransitions& bt = transitions[ki];
+
+        bt.lp_me = log(p_me);
+        bt.lp_mk = log(p_mk);
+        bt.lp_mm = log(p_mm);
+
+        bt.lp_ee = log(p_ee);
+        bt.lp_em = log(p_em);
+        
+        bt.lp_kk = log(p_kk);
+        bt.lp_km = log(p_km);
+    }
+
+    return transitions;
+}
+
+// Output writer for the Forward Algorithm
+class ProfileHMMForwardOutput
+{
+    public:
+        ProfileHMMForwardOutput(FloatMatrix* p) : p_fm(p), lp_end(-INFINITY) {}
+        
+        //
+        inline void update_4(uint32_t row, uint32_t col, float m, float e, float k, float s, float lp_emission)
+        {
+            float sum_1 = add_logs(m, e);
+            float sum_2 = add_logs(k, s);
+            float sum = add_logs(sum_1, sum_2) + lp_emission;
+            set(*p_fm, row, col, sum);
+        }
+
+        // add in the probability of ending the alignment at row,col
+        inline void update_end(float v, uint32_t row, uint32_t col)
+        {
+            lp_end = add_logs(lp_end, v);
+        }
+
+        // get the log probability stored at a particular row/column
+        inline float get(uint32_t row, uint32_t col) const
+        {
+            return ::get(*p_fm, row, col);
+        }
+
+        // get the log probability for the end state
+        inline float get_end() const
+        {
+            return lp_end;
+        }
+
+        inline size_t get_num_columns() const
+        {
+            return p_fm->n_cols;
+        }
+
+        inline size_t get_num_rows() const
+        {
+            return p_fm->n_rows;
+        }
+    
+    private:
+        ProfileHMMForwardOutput(); // not allowed
+        FloatMatrix* p_fm;
+        float lp_end;
+};
+
+// Output writer for the Viterbi Algorithm
+class ProfileHMMViterbiOutput
+{
+    public:
+        ProfileHMMViterbiOutput(FloatMatrix* pf, UInt8Matrix* pb) : p_fm(pf), p_bm(pb), lp_end(-INFINITY) {}
+        
+        inline void update_4(uint32_t row, uint32_t col, float m, float e, float k, float s, float lp_emission)
+        {
+            // probability update
+            float max = std::max(std::max(m, e), 
+                                 std::max(k, s));
+
+            set(*p_fm, row, col, max + lp_emission);
+
+            // backtrack update
+            uint8_t from;
+            if(max == m)
+                from = PS_MATCH;
+            else if(max == e)
+                from = PS_EVENT_SPLIT;
+            else if(max == k)
+                from = PS_KMER_SKIP;
+            else if(max == s)
+                from = PS_PRE_SOFT;
+            set(*p_bm, row, col, from);
+        }
+        
+        // add in the probability of ending the alignment at row,col
+        inline void update_end(float v, uint32_t row, uint32_t col)
+        {
+            if(v > lp_end) {
+                lp_end = v;
+                end_row = row;
+                end_col = col;
+            }
+        }
+
+        // get the log probability stored at a particular row/column
+        inline float get(uint32_t row, uint32_t col) const
+        {
+            return ::get(*p_fm, row, col);
+        }
+
+        // get the log probability for the end state
+        inline float get_end() const
+        {
+            return lp_end;
+        }
+        
+        // get the row/col that lead to the end state
+        inline void get_end_cell(uint32_t& row, uint32_t& col)
+        {
+            row = end_row;
+            col = end_col;
+        }
+
+        inline size_t get_num_columns() const
+        {
+            return p_fm->n_cols;
+        }
+
+        inline size_t get_num_rows() const
+        {
+            return p_fm->n_rows;
+        }
+    
+    private:
+        ProfileHMMViterbiOutput(); // not allowed
+
+        FloatMatrix* p_fm;
+        UInt8Matrix* p_bm;
+
+        float lp_end;
+        uint32_t end_row;
+        uint32_t end_col;
+};
+
+// Allocate a vector with the model probabilities of skipping the first i events
+inline std::vector<float> make_pre_flanking(const HMMInputData& data,
+                                            const TransitionParameters& parameters,
+                                            const uint32_t e_start,
+                                            const uint32_t num_events)
+{
+    std::vector<float> pre_flank(num_events + 1, 0.0f);
+    
+    // base cases
+
+    // no skipping
+    pre_flank[0] = log(1 - parameters.trans_start_to_clip);
+
+    // skipping the first event
+    // this includes the transition probability into and out of the skip state
+    pre_flank[1] = log(parameters.trans_start_to_clip) + // transition from start to the background state
+                   log_probability_background(*data.read, e_start, data.strand) + // emit from background
+                   log(1 - parameters.trans_clip_self); // transition to silent pre state
+
+    // skip the remaining events
+    for(size_t i = 2; i < pre_flank.size(); ++i) {
+        uint32_t event_idx = e_start + (i - 1) * data.event_stride;
+        pre_flank[i] = log(parameters.trans_clip_self) +
+                       log_probability_background(*data.read, event_idx, data.strand) + // emit from background
+                       pre_flank[i - 1]; // this accounts for the transition from the start & to the silent pre
+    
+    }
+
+    return pre_flank;
+}
+
+// Allocate a vector with the model probabilities of skipping the remaining
+// events after the alignment of event i
+inline std::vector<float> make_post_flanking(const HMMInputData& data,
+                                             const TransitionParameters& parameters,
+                                             const uint32_t e_start,
+                                             const uint32_t num_events)
+{
+    // post_flank[i] means that the i-th event was the last one
+    // aligned and the remainder should be emitted from the background model
+    std::vector<float> post_flank(num_events, 0.0f);
+
+    // base case, all events aligned
+    post_flank[num_events - 1] = log(1 - parameters.trans_start_to_clip);
+
+    if(num_events > 1) {
+        // base case, all events aligned but 1
+        {
+            uint32_t event_idx = e_start + (num_events - 1) * data.event_stride; // last event
+            assert(event_idx == data.event_stop_idx);
+            post_flank[num_events - 2] = log(parameters.trans_start_to_clip) + // transition from pre to background state
+                                         log_probability_background(*data.read, event_idx, data.strand) + // emit from background
+                                         log(1 - parameters.trans_clip_self); // transition to silent pre state
+        }
+
+        for(int i = num_events - 3; i >= 0; --i) {
+            uint32_t event_idx = e_start + (i + 1) * data.event_stride;
+            post_flank[i] = log(parameters.trans_clip_self) +
+                            log_probability_background(*data.read, event_idx, data.strand) + // emit from background
+                            post_flank[i + 1]; // this accounts for the transition from start, and to silent pre
+        }
+    }
+    return post_flank;
+}
+
+// This function fills in a matrix with the result of running the HMM.
+// The templated ProfileHMMOutput class allows one to run either Viterbi
+// or the Forward algorithm.
+template<class ProfileHMMOutput>
+inline float profile_hmm_fill_generic(const HMMInputSequence& sequence,
+                                      const HMMInputData& data,
+                                      const uint32_t e_start,
+                                      uint32_t flags,
+                                      ProfileHMMOutput& output)
+{
+    PROFILE_FUNC("profile_hmm_fill_generic")
+
+    const TransitionParameters& parameters = data.read->parameters[data.strand];
+
+    // Calculate number of blocks
+    // A block of the HMM is a set of PS_KMER_SKIP, PS_EVENT_SPLIT, PS_MATCH
+    // events for one kmer
+    uint32_t num_blocks = output.get_num_columns() / PS_NUM_STATES;
+    uint32_t last_event_row_idx = output.get_num_rows() - 1;
+
+    // Precompute the transition probabilites for each kmer block
+    uint32_t num_kmers = num_blocks - 2; // two terminal blocks
+    uint32_t last_kmer_idx = num_kmers - 1;
+    
+    std::vector<BlockTransitions> transitions = calculate_transitions(num_kmers, sequence, data);
+ 
+    // Precompute kmer ranks
+    uint32_t k = data.read->pore_model[data.strand].k;
+
+    // Make sure the HMMInputSequence's alphabet matches the state space of the read
+    assert( data.read->pore_model[data.strand].states.size() == sequence.get_num_kmer_ranks(k) );
+
+    std::vector<uint32_t> kmer_ranks(num_kmers);
+    for(size_t ki = 0; ki < num_kmers; ++ki)
+        kmer_ranks[ki] = sequence.get_kmer_rank(ki, k, data.rc);
+
+    size_t num_events = output.get_num_rows() - 1;
+
+    std::vector<float> pre_flank = make_pre_flanking(data, parameters, e_start, num_events);
+    std::vector<float> post_flank = make_post_flanking(data, parameters, e_start, num_events);
+    
+    // The model is currently constrainted to always transition
+    // from the terminal/clipped state to the first kmer (and from the
+    // last kmer to the terminal/clipping state so these are log(1.0).
+    // They are kept as variables as it might be relaxed later.
+    float lp_sm, lp_ms;
+    lp_sm = lp_ms = 0.0f;
+
+    // Fill in matrix
+    for(uint32_t row = 1; row < output.get_num_rows(); row++) {
+
+        // Skip the first block which is the start state, it was initialized above
+        // Similarily skip the last block, which is calculated in the terminate() function
+        for(uint32_t block = 1; block < num_blocks - 1; block++) {
+
+            // retrieve transitions
+            uint32_t kmer_idx = block - 1;
+            BlockTransitions& bt = transitions[kmer_idx];
+
+            uint32_t prev_block = block - 1;
+            uint32_t prev_block_offset = PS_NUM_STATES * prev_block;
+            uint32_t curr_block_offset = PS_NUM_STATES * block;
+            
+            // Emission probabilities
+            uint32_t event_idx = e_start + (row - 1) * data.event_stride;
+            uint32_t rank = kmer_ranks[kmer_idx];
+            float lp_emission_m = log_probability_match(*data.read, rank, event_idx, data.strand);
+            float lp_emission_e = log_probability_event_insert(*data.read, rank, event_idx, data.strand);
+            
+            // state PS_MATCH
+            float m_m = bt.lp_mm + output.get(row - 1, prev_block_offset + PS_MATCH);
+            float m_e = bt.lp_em + output.get(row - 1, prev_block_offset + PS_EVENT_SPLIT);
+            float m_k = bt.lp_km + output.get(row - 1, prev_block_offset + PS_KMER_SKIP);
+
+            // m_s is the probability of going from the start state
+            // to this kmer. The start state is (currently) only 
+            // allowed to go to the first kmer. If ALLOW_PRE_CLIP
+            // is defined, we allow all events before this one to be skipped,
+            // with a penalty;
+            float m_s = (kmer_idx == 0 &&
+                            (event_idx == e_start ||
+                             (flags & HAF_ALLOW_PRE_CLIP))) ? lp_sm + pre_flank[row - 1] : -INFINITY;
+            
+            output.update_4(row, curr_block_offset + PS_MATCH, m_m, m_e, m_k, m_s, lp_emission_m);
+
+            // state PS_EVENT_SPLIT
+            float e_m = bt.lp_me + output.get(row - 1, curr_block_offset + PS_MATCH);
+            float e_e = bt.lp_ee + output.get(row - 1, curr_block_offset + PS_EVENT_SPLIT);
+            output.update_4(row, curr_block_offset + PS_EVENT_SPLIT, e_m, e_e, -INFINITY, -INFINITY, lp_emission_e);
+
+            // state PS_KMER_SKIP
+            float k_m = bt.lp_mk + output.get(row, prev_block_offset + PS_MATCH);
+            float k_k = bt.lp_kk + output.get(row, prev_block_offset + PS_KMER_SKIP);
+            output.update_4(row, curr_block_offset + PS_KMER_SKIP, k_m, -INFINITY, k_k, -INFINITY, 0.0f); // no emission
+
+            // If POST_CLIP is enabled we allow the last kmer to transition directly
+            // to the end after any event. Otherwise we only allow it from the 
+            // last kmer/event match.
+            if(kmer_idx == last_kmer_idx && ( (flags & HAF_ALLOW_POST_CLIP) || row == last_event_row_idx)) {
+                float lp1 = lp_ms + output.get(row, curr_block_offset + PS_MATCH) + post_flank[row - 1];
+                float lp2 = lp_ms + output.get(row, curr_block_offset + PS_EVENT_SPLIT) + post_flank[row - 1];
+                float lp3 = lp_ms + output.get(row, curr_block_offset + PS_KMER_SKIP) + post_flank[row - 1];
+
+                output.update_end(lp1, row, curr_block_offset + PS_MATCH);
+                output.update_end(lp2, row, curr_block_offset + PS_EVENT_SPLIT);
+                output.update_end(lp3, row, curr_block_offset + PS_KMER_SKIP);
+            }
+
+#ifdef DEBUG_LOCAL_ALIGNMENT
+            printf("[%d %d] start: %.2lf  pre: %.2lf fm: %.2lf\n", event_idx, kmer_idx, m_s + lp_emission_m, pre_flank[row - 1], output.get(row, curr_block_offset + PS_MATCH));
+            printf("[%d %d]   end: %.2lf post: %.2lf\n", event_idx, kmer_idx, lp_end, post_flank[row - 1]);
+#endif
+
+#ifdef DEBUG_FILL    
+            printf("Row %u block %u\n", row, block);
+            printf("\tTransitions: p_mx [%.3lf %.3lf %.3lf]\n", bt.lp_mm, bt.lp_me, bt.lp_mk);
+            printf("\t             p_ex [%.3lf %.3lf %.3lf]\n", bt.lp_em, bt.lp_ee, 0.0f);
+            printf("\t             p_lx [%.3lf %.3lf %.3lf]\n", bt.lp_km, 0.0, bt.lp_kk);
+
+            printf("\tPS_MATCH -- Transitions: [%.3lf %.3lf %.3lf] Prev: [%.2lf %.2lf %.2lf] sum: %.2lf\n", 
+                    bt.lp_mm, bt.lp_em, bt.lp_km, 
+                    output.get(row - 1, prev_block_offset + PS_MATCH),
+                    output.get(row - 1, prev_block_offset + PS_EVENT_SPLIT),
+                    output.get(row - 1, prev_block_offset + PS_KMER_SKIP),
+                    0.0f);
+            printf("\tPS_EVENT_SPLIT -- Transitions: [%.3lf %.3lf] Prev: [%.2lf %.2lf] sum: %.2lf\n", 
+                    bt.lp_me, bt.lp_ee,
+                    output.get(row - 1, curr_block_offset + PS_MATCH),
+                    output.get(row - 1, curr_block_offset + PS_EVENT_SPLIT),
+                    0.0f);
+
+            printf("\tPS_KMER_SKIP -- Transitions: [%.3lf %.3lf] Prev: [%.2lf %.2lf] sum: %.2lf\n", 
+                    bt.lp_mk, bt.lp_kk,
+                    output.get(row, prev_block_offset + PS_MATCH),
+                    output.get(row, prev_block_offset + PS_KMER_SKIP),
+                    0.0f);
+
+            printf("\tEMISSION: %.2lf %.2lf\n", lp_emission_m, lp_emission_e);
+#endif
+        }
+    }
+    
+    return output.get_end();
+}
+
diff --git a/src/hmm/nanopolish_transition_parameters.cpp b/src/hmm/nanopolish_transition_parameters.cpp
new file mode 100644
index 0000000..8999d62
--- /dev/null
+++ b/src/hmm/nanopolish_transition_parameters.cpp
@@ -0,0 +1,376 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_transition_parameters -- parameters for khmm model
+//
+#include <math.h>
+#include <assert.h>
+#include <stdio.h>
+#include "nanopolish_transition_parameters.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_squiggle_read.h"
+
+TransitionParameters::TransitionParameters()
+{
+    // initialize training data
+    TransitionTrainingData& td = training_data;
+    td.n_matches = 0;
+    td.n_merges = 0;
+    td.n_skips = 0;
+
+    //
+    allocate_matrix(td.state_transitions, 3, 3);
+    for(int i = 0; i < td.state_transitions.n_rows; ++i) {
+        for(int j = 0; j < td.state_transitions.n_cols; ++j) {
+            set(td.state_transitions, i, j, 0);
+        }
+    }
+
+    //
+    // Initialize transition parameters
+    //
+
+    // these are fixed across all models
+    skip_bin_width = 0.5;
+    skip_probabilities.resize(30);
+ 
+    trans_start_to_clip = 0.5f;
+    trans_clip_self = 0.90f;
+}
+
+//
+TransitionParameters::~TransitionParameters()
+{
+    free_matrix(training_data.state_transitions);
+}
+
+void TransitionParameters::initialize(const std::string& model_name)
+{
+    is_initialized = true;
+
+    if(model_name == "r7.3_template_median68pA.model" ||
+       model_name == "r7.3_complement_median68pA_pop1.model" || 
+       model_name == "r7.3_complement_median68pA_pop2.model") 
+    {
+        initialize_sqkmap005();
+    } 
+    else if(model_name == "r7.3_e6_70bps_6mer_template_median68pA.model")
+    {
+        initialize_sqkmap006_template();
+    } 
+    else if(model_name == "r7.3_e6_70bps_6mer_complement_median68pA_pop1.model" ||
+            model_name == "r7.3_e6_70bps_6mer_complement_median68pA_pop2.model")
+    {
+        initialize_sqkmap006_complement();
+    } else {
+        printf("Error: unknown model: %s\n", model_name.c_str());
+        exit(EXIT_FAILURE);
+    }
+}
+
+void TransitionParameters::initialize_sqkmap005()
+{
+    assert(!skip_probabilities.empty());
+    trans_m_to_e_not_k = 0.15f;
+    trans_e_to_e = 0.33f;
+
+    skip_probabilities[0] = 0.51268137;
+    skip_probabilities[1] = 0.47243219;
+    skip_probabilities[2] = 0.42888741;
+    skip_probabilities[3] = 0.34932588;
+    skip_probabilities[4] = 0.27427068;
+    skip_probabilities[5] = 0.22297225;
+    skip_probabilities[6] = 0.17585147;
+    skip_probabilities[7] = 0.14705882;
+    skip_probabilities[8] = 0.12183525;
+    skip_probabilities[9] = 0.11344997;
+    skip_probabilities[10] = 0.10069393;
+    skip_probabilities[11] = 0.09153005;
+    skip_probabilities[12] = 0.08765206;
+    skip_probabilities[13] = 0.08491435;
+    skip_probabilities[14] = 0.08272553;
+    skip_probabilities[15] = 0.07747396;
+    skip_probabilities[16] = 0.08439116;
+    skip_probabilities[17] = 0.07819045;
+    skip_probabilities[18] = 0.07337461;
+    skip_probabilities[19] = 0.07020490;
+    skip_probabilities[20] = 0.06869961;
+    skip_probabilities[21] = 0.06576609;
+    skip_probabilities[22] = 0.06923376;
+    skip_probabilities[23] = 0.06239092;
+    skip_probabilities[24] = 0.06586513;
+    skip_probabilities[25] = 0.07372986;
+    skip_probabilities[26] = 0.07050360;
+    skip_probabilities[27] = 0.07228916;
+    skip_probabilities[28] = 0.05855856;
+    skip_probabilities[29] = 0.06842737;
+
+}
+
+void TransitionParameters::initialize_sqkmap006_template()
+{
+    assert(!skip_probabilities.empty());
+    trans_m_to_e_not_k = 0.17f;
+    trans_e_to_e = 0.55f;
+
+    skip_probabilities[0] = 0.487;
+    skip_probabilities[1] = 0.412;
+    skip_probabilities[2] = 0.311;
+    skip_probabilities[3] = 0.229;
+    skip_probabilities[4] = 0.174;
+    skip_probabilities[5] = 0.134;
+    skip_probabilities[6] = 0.115;
+    skip_probabilities[7] = 0.103;
+    skip_probabilities[8] = 0.096;
+    skip_probabilities[9] = 0.092;
+    skip_probabilities[10] = 0.088;
+    skip_probabilities[11] = 0.087;
+    skip_probabilities[12] = 0.084;
+    skip_probabilities[13] = 0.085;
+    skip_probabilities[14] = 0.083;
+    skip_probabilities[15] = 0.082;
+    skip_probabilities[16] = 0.085;
+    skip_probabilities[17] = 0.083;
+    skip_probabilities[18] = 0.084;
+    skip_probabilities[19] = 0.082;
+    skip_probabilities[20] = 0.080;
+    skip_probabilities[21] = 0.085;
+    skip_probabilities[22] = 0.088;
+    skip_probabilities[23] = 0.086;
+    skip_probabilities[24] = 0.087;
+    skip_probabilities[25] = 0.089;
+    skip_probabilities[26] = 0.085;
+    skip_probabilities[27] = 0.090;
+    skip_probabilities[28] = 0.087;
+    skip_probabilities[29] = 0.096;
+}
+
+void TransitionParameters::initialize_sqkmap006_complement()
+{
+    assert(!skip_probabilities.empty());
+    trans_m_to_e_not_k = 0.14f;
+    trans_e_to_e = 0.49f;
+
+    skip_probabilities[0] = 0.531;
+    skip_probabilities[1] = 0.478;
+    skip_probabilities[2] = 0.405;
+    skip_probabilities[3] = 0.327;
+    skip_probabilities[4] = 0.257;
+    skip_probabilities[5] = 0.207;
+    skip_probabilities[6] = 0.172;
+    skip_probabilities[7] = 0.154;
+    skip_probabilities[8] = 0.138;
+    skip_probabilities[9] = 0.132;
+    skip_probabilities[10] = 0.127;
+    skip_probabilities[11] = 0.123;
+    skip_probabilities[12] = 0.117;
+    skip_probabilities[13] = 0.115;
+    skip_probabilities[14] = 0.113;
+    skip_probabilities[15] = 0.113;
+    skip_probabilities[16] = 0.115;
+    skip_probabilities[17] = 0.109;
+    skip_probabilities[18] = 0.109;
+    skip_probabilities[19] = 0.107;
+    skip_probabilities[20] = 0.104;
+    skip_probabilities[21] = 0.105;
+    skip_probabilities[22] = 0.108;
+    skip_probabilities[23] = 0.106;
+    skip_probabilities[24] = 0.111;
+    skip_probabilities[25] = 0.114;
+    skip_probabilities[26] = 0.118;
+    skip_probabilities[27] = 0.119;
+    skip_probabilities[28] = 0.110;
+    skip_probabilities[29] = 0.119;
+}
+
+// 
+double TransitionParameters::get_skip_probability(double k_level1, double k_level2) const
+{
+    assert(is_initialized);
+    size_t bin = get_skip_bin(k_level1, k_level2);
+    assert(bin < skip_probabilities.size());
+    return skip_probabilities[bin];
+}
+
+//
+int statechar2index(char s)
+{
+    switch(s) {
+        case 'M': return 0;
+        case 'E': return 1;
+        case 'K': return 2;
+    }
+    assert(false);
+    return 0;
+}
+
+//
+void TransitionParameters::add_transition_observation(char state_from, char state_to)
+{
+    int f_idx = statechar2index(state_from);
+    int t_idx = statechar2index(state_to);
+
+    int count = get(training_data.state_transitions, f_idx, t_idx);
+    set(training_data.state_transitions, f_idx, t_idx, count + 1);
+}
+
+void TransitionParameters::add_training_from_alignment(const HMMInputSequence& sequence,
+                                                       const HMMInputData& data,
+                                                       const std::vector<HMMAlignmentState>& alignment,
+                                                       size_t ignore_edge_length)
+{
+    // do nothing if the alignment is too short
+    if(alignment.size() <= ignore_edge_length) {
+        return;
+    }
+
+    const PoreModel& pm = data.read->pore_model[data.strand];
+    const uint32_t k = pm.k;
+
+    size_t n_kmers = sequence.length() - k + 1;
+    uint32_t strand_idx = 0;
+    char prev_s = 'M';
+
+    for(size_t pi = 0; pi < alignment.size(); ++pi) {
+
+        uint32_t ei = alignment[pi].event_idx;
+        uint32_t ki = alignment[pi].kmer_idx;
+        char s = alignment[pi].state;
+    
+        // Record transition observations
+        // We do not record observations for merge states as there was no kmer transitions
+        // We also do not record observations for the beginning of the matches as the
+        // alignment may be poor due to edge effects
+        if(pi > ignore_edge_length && pi < alignment.size() - ignore_edge_length) {
+ 
+            // skip transition training data
+            // we do not process the E state here as no k-mer move was made
+            if(s != 'E') {
+                uint32_t transition_kmer_from = alignment[pi - 1].kmer_idx;
+                uint32_t transition_kmer_to = alignment[pi].kmer_idx;
+
+                // Specially handle skips
+                // We only want to record the first k-mer skipped if multiple were skipped
+                if(s == 'K') {
+                    transition_kmer_from = alignment[pi - 1].kmer_idx;
+                    transition_kmer_to = transition_kmer_from + 1;
+                }
+                
+                assert(transition_kmer_from < n_kmers && transition_kmer_to < n_kmers);
+
+                uint32_t rank_1 = sequence.get_kmer_rank(transition_kmer_from, k, data.rc);
+                uint32_t rank_2 = sequence.get_kmer_rank(transition_kmer_to, k, data.rc);
+            
+                GaussianParameters level_1 = pm.get_scaled_parameters(rank_1);
+                GaussianParameters level_2 = pm.get_scaled_parameters(rank_2);
+            
+#ifdef PRINT_TRAINING_MESSAGES
+                printf("TRAIN_SKIP\t%d\t%.3lf\t%.3lf\t%c\n", strand_idx, level_1.mean, level_2.mean, s);
+#endif
+                KmerTransitionObservation to = { level_1.mean, level_2.mean, s };
+                training_data.kmer_transitions.push_back(to);
+            }
+
+            // State-to-state transition
+            add_transition_observation(prev_s, s);
+
+            // emission
+            float level = data.read->get_drift_corrected_level(ei, data.strand);
+            float sd = data.read->events[data.strand][ei].stdv;
+            float duration = data.read->get_duration(ei, data.strand);
+            if(ki >= n_kmers)
+                printf("%zu %d %d %zu %.2lf %c\n", pi, ei, ki, n_kmers, alignment[pi].l_fm, s);
+            
+            assert(ki < n_kmers);
+            uint32_t rank = sequence.get_kmer_rank(ki, k, data.rc);
+        
+            GaussianParameters model = pm.get_scaled_parameters(rank);
+            float norm_level = (level - model.mean) / model.stdv;
+
+            prev_s = s;
+        }
+
+        // summary
+        training_data.n_matches += (s == 'M');
+        training_data.n_merges += (s == 'E');
+        training_data.n_skips += (s == 'K');
+    }
+}
+
+void TransitionParameters::train()
+{
+    TransitionTrainingData& td = training_data;
+
+    //
+    // Profile HMM transitions
+    //
+
+    size_t sum_m_not_k = get(td.state_transitions, statechar2index('M'), statechar2index('M')) + 
+                         get(td.state_transitions, statechar2index('M'), statechar2index('E'));
+
+    size_t me = get(td.state_transitions, statechar2index('M'), statechar2index('E'));
+    double p_me_not_k = (double)me / sum_m_not_k;
+
+    size_t sum_e = 0;
+    for(int j = 0; j < td.state_transitions.n_cols; ++j) {
+        sum_e += get(td.state_transitions, statechar2index('E'), j);
+    }
+    
+    size_t ee = get(td.state_transitions, statechar2index('E'), statechar2index('E'));
+    double p_ee = (double)ee / sum_e;
+
+#ifdef SHOW_TRAINING_RESULT
+    fprintf(stderr, "TRANSITIONS\n");
+    fprintf(stderr, "M->E|not_k: %lf\n", p_me_not_k);
+    fprintf(stderr, "E->E: %lf\n", p_ee);
+    for(int i = 0; i < td.state_transitions.n_rows; ++i) {
+        fprintf(stderr, "\t%c: ", "MEK"[i]);
+        for(int j = 0; j < td.state_transitions.n_cols; ++j) {
+            fprintf(stderr, "%d ", get(td.state_transitions, i, j));
+        }
+        fprintf(stderr, "\n");
+    }
+#endif
+
+    if(sum_e == 0 || sum_m_not_k == 0) {
+        // insufficient data to train, use defaults
+        return;
+    }
+
+    trans_m_to_e_not_k = p_me_not_k;
+    trans_e_to_e = p_ee;
+
+    //
+    // Signal-dependent skip probability
+    //
+
+    // Initialize observations with pseudocounts from the current model
+    size_t num_bins = skip_probabilities.size();
+    uint32_t pseudocount = 100;
+    std::vector<double> total_observations(num_bins, 0.0f);
+    std::vector<double> skip_observations(num_bins, 0.0f);
+
+    for(size_t bin = 0; bin < num_bins; bin++) {
+        skip_observations[bin] = skip_probabilities[bin] * pseudocount;
+        total_observations[bin] = pseudocount;
+    }
+
+    for(size_t oi = 0; oi < td.kmer_transitions.size(); ++oi) {
+        const KmerTransitionObservation& to = td.kmer_transitions[oi];
+        bool is_skip = to.state == 'K';
+        size_t bin = get_skip_bin(to.level_1, to.level_2);
+
+        skip_observations[bin] += is_skip;
+        total_observations[bin] += 1;
+    }
+
+    // Update probabilities
+    for(size_t bin = 0; bin < num_bins; bin++) {
+        skip_probabilities[bin] = skip_observations[bin] / total_observations[bin];
+#ifdef SHOW_TRAINING_RESULT
+        fprintf(stderr, "SKIPLEARN -- %zu %.3lf %.3lf %.3lf\n", bin, skip_observations[bin], total_observations[bin], skip_probabilities[bin]);
+#endif
+    }
+}
diff --git a/src/hmm/nanopolish_transition_parameters.h b/src/hmm/nanopolish_transition_parameters.h
new file mode 100644
index 0000000..f4b9bed
--- /dev/null
+++ b/src/hmm/nanopolish_transition_parameters.h
@@ -0,0 +1,112 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_transitions_parameters -- transition
+// parameters for profile HMM
+//
+#ifndef NANOPOLISH_TRANSITION_PARAMETERS
+#define NANOPOLISH_TRANSITION_PARAMETERS
+
+#include <vector>
+#include <stdint.h>
+#include "nanopolish_matrix.h"
+#include "nanopolish_hmm_input_sequence.h"
+
+// 
+struct KmerTransitionObservation
+{
+    double level_1;
+    double level_2;
+    char state;
+};
+
+// This struct holds observations used to learn the parameters
+struct TransitionTrainingData
+{
+    uint32_t n_matches;
+    uint32_t n_merges;
+    uint32_t n_skips;
+
+    std::vector<KmerTransitionObservation> kmer_transitions;
+    UInt32Matrix state_transitions;
+};
+
+//
+class TransitionParameters
+{
+    public:
+
+        //
+        // functions
+        //
+        TransitionParameters();
+        ~TransitionParameters();
+
+        void initialize(const std::string& model_name);
+
+        // update transition parameters from training data
+        void train();
+
+        // Get the probability of skipping a kmer observation given the pair of expected levels
+        double get_skip_probability(double k_level1, double k_level2) const;
+
+        // add an observation of a state transition to the training data
+        void add_transition_observation(char hmm_state_from, char hmm_state_to);
+
+        // update the training data using the alignment
+        void add_training_from_alignment(const HMMInputSequence& sequence,
+                                         const HMMInputData& data,
+                                         const std::vector<HMMAlignmentState>& alignment,
+                                         size_t ignore_edge_length = 5);
+
+        //
+        // data
+        //
+        double trans_m_to_e_not_k;
+        double trans_e_to_e;
+
+        double trans_start_to_clip;
+        double trans_clip_self;
+        
+        bool is_initialized = false;
+
+        // This is a vector that maps from discretized absolute difference
+        // between expected signals to a probability that the transition
+        // will be observed by the pore. Access to the skip probabilities
+        // for a pair of k-mer levels is through get_skip_probability()
+        std::vector<double> skip_probabilities;
+        double skip_bin_width;
+
+        // Data used to train the model
+        TransitionTrainingData training_data;
+
+
+    private:
+
+        // Model-specific transition initialization
+        void initialize_sqkmap005();
+        void initialize_sqkmap006_template();
+        void initialize_sqkmap006_complement();
+
+        // Not allowed
+        TransitionParameters(const TransitionParameters& other) {}
+
+        // Calculate which bin of the skip probability table this level difference falls in
+        inline size_t get_skip_bin(double k_level1, double k_level2) const
+        {
+            assert(!skip_probabilities.empty());
+
+            double d = fabs(k_level1 - k_level2);
+            size_t bin = d / skip_bin_width;
+
+            // clamp out-of-range to last value
+            bin = bin >= skip_probabilities.size() ? skip_probabilities.size() - 1 : bin;
+            return bin;
+        }
+
+};
+
+
+#endif
diff --git a/src/main/nanopolish.cpp b/src/main/nanopolish.cpp
new file mode 100644
index 0000000..8c99379
--- /dev/null
+++ b/src/main/nanopolish.cpp
@@ -0,0 +1,63 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish.cpp -- main driver program
+//
+#include <stdio.h>
+#include <string>
+#include "logsum.h"
+#include "nanopolish_call_variants.h"
+#include "nanopolish_consensus.h"
+#include "nanopolish_eventalign.h"
+#include "nanopolish_getmodel.h"
+#include "nanopolish_methyltrain.h"
+#include "nanopolish_methyltest.h"
+
+// This code needs to be run before any of the program logic
+// It sets up pre-computed values and caches
+void initialize()
+{
+    p7_FLogsumInit();
+}
+
+void print_usage()
+{
+    printf("usage: nanopolish [command] [options]\n");
+}
+
+int main(int argc, char** argv)
+{
+    initialize();
+
+    if(argc <= 1) {
+        printf("error: no command provided\n");
+        print_usage();
+        return 0;
+    } else {
+        std::string command(argv[1]);
+        if(command == "help" || command == "--help") {
+            print_usage();
+            return 0;
+        } else if(command == "consensus") {
+            consensus_main(argc - 1, argv + 1);
+            return 0;
+        } else if(command == "eventalign") {
+            eventalign_main(argc - 1, argv + 1);
+            return 0;
+        } else if(command == "getmodel") {
+            getmodel_main(argc - 1, argv + 1);
+            return 0;
+        } else if(command == "variants") {
+            call_variants_main(argc - 1, argv + 1);
+            return 0;
+        } else if(command == "methyltrain") {
+            methyltrain_main(argc - 1, argv + 1);
+            return 0;
+        } else if(command == "methyltest") {
+            methyltest_main(argc - 1, argv + 1);
+            return 0;
+        }
+    }
+}
diff --git a/src/nanopolish_call_variants.cpp b/src/nanopolish_call_variants.cpp
new file mode 100644
index 0000000..e7b2515
--- /dev/null
+++ b/src/nanopolish_call_variants.cpp
@@ -0,0 +1,410 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_call_variants -- find variants wrt a reference
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <sys/time.h>
+#include <algorithm>
+#include <queue>
+#include <sstream>
+#include <fstream>
+#include <set>
+#include <omp.h>
+#include <getopt.h>
+#include "htslib/faidx.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_transition_parameters.h"
+#include "nanopolish_matrix.h"
+#include "nanopolish_klcs.h"
+#include "nanopolish_profile_hmm.h"
+#include "nanopolish_alignment_db.h"
+#include "nanopolish_anchor.h"
+#include "nanopolish_fast5_map.h"
+#include "nanopolish_variant.h"
+#include "nanopolish_haplotype.h"
+#include "profiler.h"
+#include "progress.h"
+#include "stdaln.h"
+
+// Macros
+#define max3(x,y,z) std::max(std::max(x,y), z)
+
+// Flags to turn on/off debugging information
+
+//#define DEBUG_HMM_UPDATE 1
+//#define DEBUG_HMM_EMISSION 1
+//#define DEBUG_TRANSITION 1
+//#define DEBUG_PATH_SELECTION 1
+//#define DEBUG_SINGLE_SEGMENT 1
+//#define DEBUG_SHOW_TOP_TWO 1
+//#define DEBUG_SEGMENT_ID 193
+//#define DEBUG_BENCHMARK 1
+
+//
+// Getopt
+//
+#define SUBPROGRAM "variants"
+
+static const char *CONSENSUS_VERSION_MESSAGE =
+SUBPROGRAM " Version " PACKAGE_VERSION "\n"
+"Written by Jared Simpson.\n"
+"\n"
+"Copyright 2015 Ontario Institute for Cancer Research\n";
+
+static const char *CONSENSUS_USAGE_MESSAGE =
+"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
+"Find SNPs using a signal-level HMM\n"
+"\n"
+"  -v, --verbose                        display verbose output\n"
+"      --version                        display version\n"
+"      --help                           display this help and exit\n"
+"      --snps                           only call SNPs\n"
+"  -w, --window=STR                     find variants in window STR (format: ctg:start-end)\n"
+"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
+"  -b, --bam=FILE                       the reads aligned to the reference genome are in bam FILE\n"
+"  -e, --event-bam=FILE                 the events aligned to the reference genome are in bam FILE\n"
+"  -g, --genome=FILE                    the reference genome is in FILE\n"
+"  -o, --outfile=FILE                   write result to FILE [default: stdout]\n"
+"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
+"  -m, --min-candidate-frequency=F      alternative bases in F proporation of aligned reads are candidate variants (default 0.2)\n"
+"  -c, --candidates=VCF                 read variant candidates from VCF, rather than discovering them from aligned reads\n"
+"      --calculate-all-support          when making a call, also calculate the support of the 3 other possible bases\n"
+"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";
+
+namespace opt
+{
+    static unsigned int verbose;
+    static std::string reads_file;
+    static std::string bam_file;
+    static std::string event_bam_file;
+    static std::string genome_file;
+    static std::string output_file;
+    static std::string candidates_file;
+    static std::string window;
+    static double min_candidate_frequency = 0.2f;
+    static int calculate_all_support = false;
+    static int snps_only = 0;
+    static int show_progress = 0;
+    static int num_threads = 1;
+}
+
+static const char* shortopts = "r:b:g:t:w:o:e:m:c:v";
+
+enum { OPT_HELP = 1, OPT_VERSION, OPT_VCF, OPT_PROGRESS, OPT_SNPS_ONLY, OPT_CALC_ALL_SUPPORT };
+
+static const struct option longopts[] = {
+    { "verbose",                 no_argument,       NULL, 'v' },
+    { "reads",                   required_argument, NULL, 'r' },
+    { "bam",                     required_argument, NULL, 'b' },
+    { "event-bam",               required_argument, NULL, 'e' },
+    { "genome",                  required_argument, NULL, 'g' },
+    { "window",                  required_argument, NULL, 'w' },
+    { "outfile",                 required_argument, NULL, 'o' },
+    { "threads",                 required_argument, NULL, 't' },
+    { "min-candidate-frequency", required_argument, NULL, 'm' },
+    { "candidates",              required_argument, NULL, 'c' },
+    { "calculate-all-support",   no_argument,       NULL, OPT_CALC_ALL_SUPPORT },
+    { "snps",                    no_argument,       NULL, OPT_SNPS_ONLY },
+    { "progress",                no_argument,       NULL, OPT_PROGRESS },
+    { "help",                    no_argument,       NULL, OPT_HELP },
+    { "version",                 no_argument,       NULL, OPT_VERSION },
+    { NULL, 0, NULL, 0 }
+};
+
+int get_contig_length(const std::string& contig)
+{
+    faidx_t *fai = fai_load(opt::genome_file.c_str());
+    int len = faidx_seq_len(fai, contig.c_str());
+    fai_destroy(fai);
+    return len;
+}
+
+void annotate_with_all_support(std::vector<Variant>& variants,
+                               Haplotype base_haplotype,
+                               const std::vector<HMMInputData>& input,
+                               const uint32_t alignment_flags)
+
+{
+    for(size_t vi = 0; vi < variants.size(); vi++) {
+        
+        // Generate a haplotype containing every variant in the set except for vi
+        Haplotype test_haplotype = base_haplotype;
+        for(size_t vj = 0; vj < variants.size(); vj++) {
+
+            // do not apply the variant we are testing
+            if(vj == vi) {
+                continue;
+            }
+            test_haplotype.apply_variant(variants[vj]);
+        }
+        
+        // Make a vector of four haplotypes, one per base
+        std::vector<Haplotype> curr_haplotypes;
+        Variant tmp_variant = variants[vi];
+        for(size_t bi = 0; bi < 4; ++bi) {
+            tmp_variant.alt_seq = "ACGT"[bi];
+            Haplotype tmp = test_haplotype;
+            tmp.apply_variant(tmp_variant);
+            curr_haplotypes.push_back(tmp);
+        }
+
+        // Test all reads against the 4 haplotypes
+        std::vector<int> support_count(4, 0);
+
+        for(size_t input_idx = 0; input_idx < input.size(); ++input_idx) {
+            double best_score = -INFINITY;
+            size_t best_hap_idx = 0;
+
+            // calculate which haplotype this read supports best
+            for(size_t hap_idx = 0; hap_idx < curr_haplotypes.size(); ++hap_idx) {
+                double score = profile_hmm_score(curr_haplotypes[hap_idx].get_sequence(), input[input_idx], alignment_flags);
+                if(score > best_score) {
+                    best_score = score;
+                    best_hap_idx = hap_idx;
+                }
+            }
+            support_count[best_hap_idx] += 1;
+        }
+
+        std::stringstream ss;
+        for(size_t bi = 0; bi < 4; ++bi) {
+            ss << support_count[bi] / (double)input.size() << (bi != 3 ? "," : "");
+        }
+
+        variants[vi].add_info("AllSupportFractions", ss.str());
+    }
+}
+
+std::vector<Variant> get_variants_from_vcf(const std::string& filename, 
+                                           const std::string& contig,
+                                           int region_start,
+                                           int region_end)
+{
+    std::vector<Variant> out;
+    std::ifstream infile(filename);
+    std::string line;
+    while(getline(infile, line)) {
+        
+        // skip headers
+        if(line[0] == '#') {
+            continue;
+        }
+        
+        // parse variant
+        Variant v(line);
+
+        if(v.ref_name == contig &&
+           v.ref_position >= region_start &&
+           v.ref_position <= region_end) 
+        {
+            out.push_back(v);
+        }
+    }
+    return out;
+}
+
+Haplotype call_variants_for_region(const std::string& contig, int region_start, int region_end)
+{
+    const int BUFFER = 20;
+    uint32_t alignment_flags = HAF_ALLOW_PRE_CLIP | HAF_ALLOW_POST_CLIP;
+    if(region_start < BUFFER)
+        region_start = BUFFER;
+
+    // load the region, accounting for the buffering
+    AlignmentDB alignments(opt::reads_file, opt::genome_file, opt::bam_file, opt::event_bam_file);
+    alignments.load_region(contig, region_start - BUFFER, region_end + BUFFER);
+    Haplotype derived_haplotype(contig,
+                                alignments.get_region_start(),
+                                alignments.get_reference());
+
+    // Step 1. Discover putative variants across the whole region
+    std::vector<Variant> candidate_variants;
+    if(opt::candidates_file.empty()) {
+        candidate_variants = alignments.get_variants_in_region(contig, region_start, region_end, opt::min_candidate_frequency, 20);
+    } else {
+        candidate_variants = get_variants_from_vcf(opt::candidates_file, contig, region_start, region_end);
+    }
+
+    // Step 2. Add variants to the haplotypes
+    size_t calling_span = 10;
+    size_t curr_variant_idx = 0;
+    while(curr_variant_idx < candidate_variants.size()) {
+ 
+        // Group the variants that are within calling_span bases of each other       
+        size_t end_variant_idx = curr_variant_idx + 1;
+        while(end_variant_idx < candidate_variants.size()) {
+            int distance = candidate_variants[end_variant_idx].ref_position - 
+                           candidate_variants[end_variant_idx - 1].ref_position;
+            if(distance > calling_span)
+                break;
+            end_variant_idx++;
+        }
+    
+        size_t num_variants = end_variant_idx - curr_variant_idx;
+        int calling_start = candidate_variants[curr_variant_idx].ref_position - calling_span;
+        int calling_end = candidate_variants[end_variant_idx - 1].ref_position +
+                          candidate_variants[end_variant_idx - 1].ref_seq.length() +
+                          calling_span;
+        int calling_size = calling_end - calling_start;
+
+        if(opt::verbose > 2) {
+            fprintf(stderr, "%zu variants in span [%d %d]\n", num_variants, calling_start, calling_end);
+        }
+        
+        // Only try to call variants if there is a reasonable amount and the window is not too large
+        if(num_variants <= 10 && calling_size <= 100) {
+
+            // Subset the haplotype to the region we are calling
+            Haplotype calling_haplotype = 
+                derived_haplotype.substr_by_reference(calling_start, calling_end);
+            
+            // Get the events for the calling region
+            std::vector<HMMInputData> event_sequences = 
+                alignments.get_event_subsequences(contig, calling_start, calling_end);
+            
+            // Subset the variants
+            std::vector<Variant> calling_variants(candidate_variants.begin() + curr_variant_idx, 
+                                                  candidate_variants.begin() + end_variant_idx);
+            
+            // Select the best set of variants
+            std::vector<Variant> selected_variants = 
+                select_variant_set(calling_variants, calling_haplotype, event_sequences, alignment_flags);
+
+            // optionally annotate each variant with fraction of reads supporting A,C,G,T at this position
+            if(opt::calculate_all_support) {
+                annotate_with_all_support(selected_variants, calling_haplotype, event_sequences, alignment_flags);
+            }
+
+            // Apply them to the final haplotype
+            for(size_t vi = 0; vi < selected_variants.size(); vi++) {
+
+                derived_haplotype.apply_variant(selected_variants[vi]);
+
+                if(opt::verbose > 1) {
+                    selected_variants[vi].write_vcf(stderr);
+                }
+            }
+        }
+
+        // advance to start of next region
+        curr_variant_idx = end_variant_idx;
+    }
+
+    return derived_haplotype;
+}
+
+void parse_call_variants_options(int argc, char** argv)
+{
+    bool die = false;
+    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
+        std::istringstream arg(optarg != NULL ? optarg : "");
+        switch (c) {
+            case 'r': arg >> opt::reads_file; break;
+            case 'g': arg >> opt::genome_file; break;
+            case 'b': arg >> opt::bam_file; break;
+            case 'e': arg >> opt::event_bam_file; break;
+            case 'w': arg >> opt::window; break;
+            case 'o': arg >> opt::output_file; break;
+            case 'm': arg >> opt::min_candidate_frequency; break;
+            case 'c': arg >> opt::candidates_file; break;
+            case '?': die = true; break;
+            case 't': arg >> opt::num_threads; break;
+            case 'v': opt::verbose++; break;
+            case OPT_CALC_ALL_SUPPORT: opt::calculate_all_support = 1; break;
+            case OPT_SNPS_ONLY: opt::snps_only = 1; break;
+            case OPT_PROGRESS: opt::show_progress = 1; break;
+            case OPT_HELP:
+                std::cout << CONSENSUS_USAGE_MESSAGE;
+                exit(EXIT_SUCCESS);
+            case OPT_VERSION:
+                std::cout << CONSENSUS_VERSION_MESSAGE;
+                exit(EXIT_SUCCESS);
+        }
+    }
+
+    if (argc - optind < 0) {
+        std::cerr << SUBPROGRAM ": missing arguments\n";
+        die = true;
+    } else if (argc - optind > 0) {
+        std::cerr << SUBPROGRAM ": too many arguments\n";
+        die = true;
+    }
+
+    if(opt::num_threads <= 0) {
+        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
+        die = true;
+    }
+
+    if(opt::reads_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::genome_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
+        die = true;
+    }
+
+    if(opt::bam_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
+        die = true;
+    }
+
+    if (die) 
+    {
+        std::cout << "\n" << CONSENSUS_USAGE_MESSAGE;
+        exit(EXIT_FAILURE);
+    }
+}
+
+int call_variants_main(int argc, char** argv)
+{
+    parse_call_variants_options(argc, argv);
+    omp_set_num_threads(opt::num_threads);
+
+    // Parse the window string
+    // Replace ":" and "-" with spaces to make it parseable with stringstream
+    std::replace(opt::window.begin(), opt::window.end(), ':', ' ');
+    std::replace(opt::window.begin(), opt::window.end(), '-', ' ');
+
+    std::stringstream parser(opt::window);
+    std::string contig;
+    int start_base;
+    int end_base;
+    
+    parser >> contig >> start_base >> end_base;
+    end_base = std::min(end_base, get_contig_length(contig) - 1);
+
+    FILE* out_fp;
+    if(!opt::output_file.empty()) {
+        out_fp = fopen(opt::output_file.c_str(), "w");
+    } else {
+        out_fp = stdout;
+    }
+
+    Variant::write_vcf_header(out_fp);
+
+    fprintf(stderr, "TODO: train model\n");
+    fprintf(stderr, "TODO: filter data\n");
+
+    Haplotype haplotype = call_variants_for_region(contig, start_base, end_base);
+
+    std::vector<Variant> variants = haplotype.get_variants();
+    for(size_t vi = 0; vi < variants.size(); vi++) {
+        variants[vi].write_vcf(out_fp);
+    }
+
+    if(out_fp != stdout) {
+        fclose(out_fp);
+    }
+}
diff --git a/src/nanopolish_call_variants.h b/src/nanopolish_call_variants.h
new file mode 100644
index 0000000..4566524
--- /dev/null
+++ b/src/nanopolish_call_variants.h
@@ -0,0 +1,13 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_call_variants -- find variants wrt a reference
+//
+#ifndef NANOPOLISH_CALL_VARIANTS_H
+#define NANOPOLISH_CALL_VARIANTS_H
+
+void call_variants_main(int argc, char** argv);
+
+#endif
diff --git a/src/nanopolish_consensus.cpp b/src/nanopolish_consensus.cpp
new file mode 100644
index 0000000..785cf9e
--- /dev/null
+++ b/src/nanopolish_consensus.cpp
@@ -0,0 +1,875 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_consensus.cpp -- entry point to consensus functions
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <sys/time.h>
+#include <algorithm>
+#include <sstream>
+#include <set>
+#include <omp.h>
+#include <getopt.h>
+#include "nanopolish_poremodel.h"
+#include "nanopolish_transition_parameters.h"
+#include "nanopolish_matrix.h"
+#include "nanopolish_klcs.h"
+#include "nanopolish_profile_hmm.h"
+#include "nanopolish_anchor.h"
+#include "nanopolish_fast5_map.h"
+#include "nanopolish_hmm_input_sequence.h"
+#include "profiler.h"
+#include "progress.h"
+#include "stdaln.h"
+
+// Macros
+#define max3(x,y,z) std::max(std::max(x,y), z)
+
+// Flags to turn on/off debugging information
+
+//#define DEBUG_HMM_UPDATE 1
+//#define DEBUG_HMM_EMISSION 1
+//#define DEBUG_TRANSITION 1
+//#define DEBUG_PATH_SELECTION 1
+//#define DEBUG_SINGLE_SEGMENT 1
+//#define DEBUG_SHOW_TOP_TWO 1
+//#define DEBUG_SEGMENT_ID 193
+//#define DEBUG_BENCHMARK 1
+
+//
+// Getopt
+//
+#define SUBPROGRAM "consensus"
+
+static const char *CONSENSUS_VERSION_MESSAGE =
+SUBPROGRAM " Version " PACKAGE_VERSION "\n"
+"Written by Jared Simpson.\n"
+"\n"
+"Copyright 2015 Ontario Institute for Cancer Research\n";
+
+static const char *CONSENSUS_USAGE_MESSAGE =
+"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
+"Compute a new consensus sequence for an assembly using a signal-level HMM\n"
+"\n"
+"  -v, --verbose                        display verbose output\n"
+"      --version                        display version\n"
+"      --help                           display this help and exit\n"
+"  -w, --window=STR                     compute the consensus for window STR (format: ctg:start_id-end_id)\n"
+"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
+"  -b, --bam=FILE                       the reads aligned to the genome assembly are in bam FILE\n"
+"  -g, --genome=FILE                    the genome we are computing a consensus for is in FILE\n"
+"  -o, --outfile=FILE                   write result to FILE [default: stdout]\n"
+"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
+"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";
+
+namespace opt
+{
+    static unsigned int verbose;
+    static std::string reads_file;
+    static std::string bam_file;
+    static std::string genome_file;
+    static std::string output_file;
+    static std::string window;
+    static int show_progress = 0;
+    static int num_threads = 1;
+}
+
+static const char* shortopts = "r:b:g:t:w:o:v";
+
+enum { OPT_HELP = 1, OPT_VERSION, OPT_VCF, OPT_PROGRESS };
+
+static const struct option longopts[] = {
+    { "verbose",     no_argument,       NULL, 'v' },
+    { "reads",       required_argument, NULL, 'r' },
+    { "bam",         required_argument, NULL, 'b' },
+    { "genome",      required_argument, NULL, 'g' },
+    { "window",      required_argument, NULL, 'w' },
+    { "outfile",     required_argument, NULL, 'o' },
+    { "threads",     required_argument, NULL, 't' },
+    { "progress",    no_argument,       NULL, OPT_PROGRESS },
+    { "help",        no_argument,       NULL, OPT_HELP },
+    { "version",     no_argument,       NULL, OPT_VERSION },
+    { NULL, 0, NULL, 0 }
+};
+
+std::vector<HMMInputData> get_input_for_columns(HMMRealignmentInput& window,
+                                                const HMMAnchoredColumn& start_column,
+                                                const HMMAnchoredColumn& end_column)
+{
+    assert(start_column.anchors.size() == end_column.anchors.size());
+
+    std::vector<HMMInputData> input;
+    for(uint32_t rsi = 0; rsi < start_column.anchors.size(); ++rsi) {
+
+        HMMStrandAnchor start_sa = start_column.anchors[rsi];
+        HMMStrandAnchor end_sa = end_column.anchors[rsi];
+
+        // sanity checks
+        // This read strand does not have events at both anchors
+        if(start_sa.event_idx == -1 || end_sa.event_idx == -1)
+            continue;
+
+        // require a minimum number of events
+        uint32_t n_events = abs(start_sa.event_idx - end_sa.event_idx);
+        if(n_events < 20 || n_events > 500)
+            continue;
+
+        if(start_sa.rc != end_sa.rc)
+            continue;
+
+        HMMInputData data;
+
+        uint32_t read_idx = rsi / 2;
+        assert(read_idx < window.reads.size());
+        data.anchor_index = rsi;
+        data.read = window.reads[read_idx].get();
+        data.strand = rsi % 2;
+        data.event_start_idx = start_sa.event_idx;
+        data.event_stop_idx = end_sa.event_idx;
+        if(data.event_start_idx < data.event_stop_idx)
+            data.event_stride = 1;
+        else
+            data.event_stride = -1;
+        data.rc = start_sa.rc;
+
+        input.push_back(data);
+    }
+    return input;
+}
+
+// Handy wrappers for scoring/debugging functions
+// The consensus algorithms call into these so we can switch
+// scoring functions without writing a bunch of code
+double score_sequence(const std::string& sequence, const HMMInputData& data)
+{
+    //return score_skip_merge(sequence, state);
+    //return score_khmm_model_postmerge(sequence, state);
+    //return khmm_score(sequence, state, AP_GLOBAL);
+    return profile_hmm_score(sequence, data);
+    //return score_emission_dp(sequence, state);
+}
+
+
+
+void debug_sequence(const std::string& name, uint32_t seq_id, uint32_t read_id, const HMMInputSequence& sequence, const HMMInputData& data)
+{
+    std::vector<HMMAlignmentState> alignment = profile_hmm_align(sequence, data);
+    print_alignment(name, seq_id, read_id, sequence, data, alignment);
+}
+
+void update_training_with_segment(const HMMInputSequence& sequence, const HMMInputData& data)
+{
+    std::vector<HMMAlignmentState> alignment = profile_hmm_align(sequence, data);
+    data.read->parameters[data.strand].add_training_from_alignment(sequence, data, alignment);
+}
+
+struct PathCons
+{
+    // default constructor
+    PathCons(const std::string& s) : path(s), score(0.0f), sum_rank(0) {}
+
+    std::string path;
+    
+    double score;
+    size_t sum_rank;
+    size_t num_improved;
+    size_t num_scored;
+    
+    std::string mutdesc;
+    
+};
+typedef std::vector<PathCons> PathConsVector;
+
+bool sortPathConsScoreDesc(const PathCons& a, const PathCons& b)
+{
+    return a.score > b.score;
+}
+
+bool sortPathConsRankAsc(const PathCons& a, const PathCons& b)
+{
+    return a.sum_rank < b.sum_rank;
+}
+
+bool sortPathConsRankDesc(const PathCons& a, const PathCons& b)
+{
+    return a.sum_rank > b.sum_rank;
+}
+
+struct IndexedPathScore
+{
+    double score;
+    uint32_t path_index;
+};
+
+bool sortIndexedPathScoreDesc(const IndexedPathScore& a, const IndexedPathScore& b)
+{
+    return a.score > b.score;
+}
+
+// This scores each path using the HMM and 
+// sorts the paths into ascending order by score
+void score_paths(PathConsVector& paths, const std::vector<HMMInputData>& input)
+{
+    PROFILE_FUNC("score_paths")
+    double MIN_FIT = INFINITY;
+    size_t CULL_RATE = 5;
+    double CULL_MIN_SCORE = -30.0f;
+    double CULL_MIN_IMPROVED_FRACTION = 0.2f;
+
+    // cache the initial sequence
+    std::string first = paths[0].path;
+    
+    PathConsVector dedup_paths;
+
+    // initialize and deduplicate paths to avoid redundant computation
+    std::set<std::string> path_string_set;
+    for(size_t pi = 0; pi < paths.size(); ++pi) {
+
+        if(path_string_set.find(paths[pi].path) == path_string_set.end()) {
+            paths[pi].score = 0;
+            paths[pi].sum_rank = 0;
+            paths[pi].num_improved = 0;
+            paths[pi].num_scored = 0;
+            dedup_paths.push_back(paths[pi]);
+            path_string_set.insert(paths[pi].path);
+        }
+    }
+    paths.clear();
+    paths.swap(dedup_paths);
+    
+
+    // Score all reads
+    for(uint32_t ri = 0; ri < input.size(); ++ri) {
+
+        if(opt::verbose > 2) {
+            fprintf(stderr, "Scoring %d\n", ri);
+        }
+
+        const HMMInputData& data = input[ri];
+        std::vector<IndexedPathScore> result(paths.size());
+
+        // Score all paths
+        #pragma omp parallel for
+        for(size_t pi = 0; pi < paths.size(); ++pi) {
+            double curr = score_sequence(paths[pi].path, input[ri]);
+            result[pi].score = curr;
+            result[pi].path_index = pi;
+        }
+
+        // Save score of first path
+        double first_path_score = result[0].score;
+
+        // Sort result by score
+        std::stable_sort(result.begin(), result.end(), sortIndexedPathScoreDesc);
+
+        for(size_t pri = 0; pri < result.size(); ++pri) {
+            size_t pi = result[pri].path_index;
+
+            paths[pi].score += (result[pri].score - first_path_score);
+            uint32_t rank_score = pri;
+            paths[pi].sum_rank += rank_score;
+            paths[pi].num_improved += (result[pri].score > first_path_score);
+            paths[pi].num_scored += 1;
+        }
+
+        // Cull paths
+        if(ri > 0 && ri % CULL_RATE == 0) {
+            PathConsVector retained_paths;
+            for(size_t pi = 0; pi < paths.size(); ++pi) {
+                
+                // We keep a path if any of these conditions are met:
+                //  1) it is the original unmodified sequence
+                //  2) its score is greater than CULL_MIN_SCORE
+                //  3) the fraction of reads that score better on this
+                //     path compared to the original sequence is greater
+                //     than CULL_MIN_IMPROVED_FRACTION
+                double f = (double)paths[pi].num_improved / (double)paths[pi].num_scored;
+                if(pi == 0 || paths[pi].score > CULL_MIN_SCORE || f >= CULL_MIN_IMPROVED_FRACTION) {
+                    retained_paths.push_back(paths[pi]);
+                }
+            }
+            paths.swap(retained_paths);
+        }
+    }
+
+    // select new sequence
+    //std::stable_sort(paths.begin(), paths.end(), sortPathConsRankAsc);
+    std::stable_sort(paths.begin(), paths.end(), sortPathConsScoreDesc);
+
+#if DEBUG_PATH_SELECTION
+    for(size_t pi = 0; pi < paths.size(); ++pi) {
+
+        // Calculate the length of the matching prefix with the initial sequence
+        const std::string& s = paths[pi].path;
+
+        char initial = s == first ? 'I' : ' ';
+
+        printf("%zu\t%s\t%.1lf\t%zu %c %s", pi, paths[pi].path.c_str(), paths[pi].score, paths[pi].sum_rank, initial, paths[pi].mutdesc.c_str());
+        // If this is the truth path or the best path, show the scores for all reads
+        if(pi <= 1 || initial == 'I') {
+            for(uint32_t ri = 0; ri < input.size(); ++ri) {
+                const HMMInputData& data = input[ri];
+                const KHMMParameters& parameters = data.read->parameters[data.strand];
+                if( fabs(parameters.fit_quality) > MIN_FIT)
+                    continue;
+
+                double curr = score_sequence(paths[pi].path, input[ri]);
+                printf("%.1lf,%.2lf ", parameters.fit_quality, curr);
+            }
+        }
+        printf("\n");
+    }
+#endif
+
+}
+
+void extend_paths(PathConsVector& paths, int maxk = 2)
+{
+    // Insert all possible extensions into the path sequence
+    // for k in 1 to maxk
+    PathConsVector new_paths;
+
+    for(int k = 1; k <= maxk; ++k) {
+
+        for(int pi = 0; pi < paths.size(); ++pi) {
+    
+            std::string first(k, 'A');
+            std::string extension = first;
+
+            do {
+                std::string current = paths[pi].path;
+                std::string ns = current.insert(current.size() - 5, extension);
+                PathCons ps(ns);
+                new_paths.push_back(ps);
+                gDNAAlphabet.lexicographic_next(extension);
+            } while(extension != first);
+        }
+    }
+
+    paths.swap(new_paths);
+}
+
+PathConsVector generate_mutations(const std::string& sequence, const uint32_t k)
+{
+    PathConsVector mutations;
+
+    // Add the unmutated sequence
+    {
+        PathCons pc(sequence);
+        mutations.push_back(pc);
+    }
+
+    // Mutate every base except for in the first/last k-mer
+    for(size_t si = k; si < sequence.size() - k; ++si) {
+        
+        // All subs
+        for(size_t bi = 0; bi < 4; bi++) {
+            char b = "ACGT"[bi];
+            if(sequence[si] == b)
+                continue;
+            PathCons pc(sequence);
+            pc.path[si] = b;
+            std::stringstream ss;
+            ss << "sub-" << si << "-" << b;
+            pc.mutdesc = ss.str();
+            mutations.push_back(pc);
+        }
+
+        // 1bp del at this position
+        {
+            PathCons pc(sequence);
+            pc.path.erase(si, 1);
+            
+            std::stringstream ss;
+            ss << "del-" << si;
+            pc.mutdesc = ss.str();
+            
+            mutations.push_back(pc);
+        }
+
+        // All 1bp ins before this position
+        for(size_t bi = 0; bi < 4; bi++) {
+            char b = "ACGT"[bi];
+            PathCons pc(sequence);
+            pc.path.insert(si, 1, b);
+            
+            std::stringstream ss;
+            ss << "ins-" << si << "-" << b;
+            pc.mutdesc = ss.str();
+            
+            mutations.push_back(pc);
+        }
+    }
+
+    return mutations;
+}
+
+// Run the mutation algorithm to generate an improved consensus sequence
+std::string run_mutation(const std::string& base, const std::vector<HMMInputData>& input)
+{
+    PROFILE_FUNC("run_mutation")
+    std::string result = base;
+
+    // assume models for all the reads have the same k
+    assert(!input.empty());
+    const uint32_t k = input[0].read->pore_model[input[0].strand].k;
+
+    int iteration = 0;
+    while(iteration++ < 10) {
+
+        // Generate possible sequences
+        PathConsVector paths = generate_mutations(result, k);
+
+        // score them in the HMM
+        score_paths(paths, input);
+
+        // check if no improvement was made
+        if(paths[0].path == result)
+            break;
+        result = paths[0].path;
+    }
+
+    return result;
+}
+
+void generate_alt_paths(PathConsVector& paths, const std::string& base, const std::vector<std::string>& alts, 
+                        const uint32_t k)
+{
+    // Generate alternatives
+    for(uint32_t ai = 0; ai < alts.size(); ++ai) {
+        const std::string& alt = alts[ai];
+
+        if(alt.size() < k)
+            continue;
+
+        kLCSResult result = kLCS(base, alt, k);
+
+#ifdef DEBUG_ALT_GENERATION
+        printf("Match to alt %s\n", alt.c_str());
+        for(size_t mi = 0; mi < result.size(); ++mi) {
+            std::string extend = "";
+            if(mi < result.size() - 1 && result[mi].j + 1 != result[mi + 1].j) {
+                extend = alt.substr(result[mi].j, result[mi + 1].j - result[mi].j + k);
+            }
+            printf("\t%zu %zu %s %s\n", result[mi].i, result[mi].j, base.substr(result[mi].i, k).c_str(), extend.c_str());
+        }
+#endif
+
+        uint32_t match_idx = 0;
+        while(match_idx < result.size()) {
+            uint32_t last_idx = result.size() - 1;
+
+            // advance the match to the next point of divergence
+            while(match_idx != last_idx && 
+                  result[match_idx].i == result[match_idx + 1].i - 1 &&
+                  result[match_idx].j == result[match_idx + 1].j - 1) {
+                match_idx++;
+            }
+            // no more divergences to process
+            if(match_idx == last_idx)
+                break;
+
+            uint32_t bl = result[match_idx + 1].i - result[match_idx].i;
+            uint32_t rl = result[match_idx + 1].j - result[match_idx].j;
+
+            std::string base_subseq = base.substr(result[match_idx].i, bl);
+            std::string alt_subseq = alt.substr(result[match_idx].j, rl);
+            
+            // Perform the splice
+            PathCons new_path(base);
+            new_path.path.replace(result[match_idx].i, bl, alt_subseq);
+            paths.push_back(new_path);
+            
+            match_idx += 1;
+        }
+    }
+}
+
+// Run the block substitution algorithm to generate an improved consensus sequence
+std::string run_block_substitution(const std::string& base,
+                                   const std::vector<HMMInputData>& input,
+                                   const std::vector<std::string>& alts)
+{
+    std::string result = base;
+
+    // assume models for all the reads have the same k
+    assert(!input.empty());
+    const uint32_t k = input[0].read->pore_model[input[0].strand].k;
+
+    uint32_t max_rounds = 6;
+    uint32_t round = 0;
+    while(round++ < max_rounds) {
+        
+        PathConsVector paths;
+        PathCons initial_path(result);
+        paths.push_back(initial_path);
+        
+        generate_alt_paths(paths, result, alts, k);
+        score_paths(paths, input);
+
+        if(paths[0].path == result)
+            break;
+        result = paths[0].path;
+    }
+    return result;
+}
+
+//
+// Outlier filtering
+//
+void filter_outlier_data(std::vector<HMMInputData>& input, const std::string& sequence)
+{
+    std::vector<HMMInputData> out_rs;
+    for(uint32_t ri = 0; ri < input.size(); ++ri) {
+        const HMMInputData& rs = input[ri];
+
+        double curr = score_sequence(sequence, rs);
+        double n_events = abs(rs.event_start_idx - rs.event_stop_idx) + 1.0f;
+        double lp_per_event = curr / n_events;
+
+        if(opt::verbose >= 1) {
+            fprintf(stderr, "OUTLIER_FILTER %d %.2lf %.2lf %.2lf\n", ri, curr, n_events, lp_per_event);
+        }
+
+        if(fabs(lp_per_event) < 3.5f) {
+            out_rs.push_back(rs);
+        }
+    }
+    input.swap(out_rs);
+}
+
+std::string join_sequences_at_kmer(const std::string& a, const std::string& b, const uint32_t k)
+{
+    // this is a special case to make the calling code cleaner
+    if(a.empty())
+        return b;
+
+    // These sequences must have a k-mer match at the start/end
+    std::string a_last_kmer = a.substr(a.size() - k);
+    std::string b_last_kmer = b.substr(0, k);
+    assert(a_last_kmer == b_last_kmer);
+    return a + b.substr(k);
+}
+
+void run_splice_segment(HMMRealignmentInput& window, uint32_t segment_id)
+{
+    // The structure of the data looks like this:
+
+    // --------------------------------------------------------
+    // S                       M                              E
+    // where is the start column, M is the middle column and E
+    // is the end column. We want to call a new consensus from S
+    // to E. We do this by generating the base sequence from S to E
+    // and then applying all of the alternatives indicated by the
+    // start and middle column. We score these alternatives using
+    // the read strands spanning from S to E. After a new consensus
+    // has been selected, we re-calculate the alignments of events to
+    // the middle anchor.
+
+    // Get the segments
+    assert(segment_id + 2 < window.anchored_columns.size());
+    HMMAnchoredColumn& start_column = window.anchored_columns[segment_id];
+    HMMAnchoredColumn& middle_column = window.anchored_columns[segment_id + 1];
+    HMMAnchoredColumn& end_column = window.anchored_columns[segment_id + 2];
+
+    std::string s_m_base = start_column.base_sequence;
+    std::string m_e_base = middle_column.base_sequence;
+
+    // The collection of alternative sequences
+    std::vector<std::string> alts;
+
+    for(uint32_t ai = 0; ai < start_column.alt_sequences.size(); ++ai) {
+        alts.push_back(start_column.alt_sequences[ai]);
+    }
+
+    // set up the input data for the HMM
+    std::vector<HMMInputData> data = get_input_for_columns(window, start_column, end_column);
+    
+    // assume models for all the reads have the same k
+    assert(!data.empty());
+    const uint32_t k = data[0].read->pore_model[data[0].strand].k;
+
+    // The current consensus sequence
+    std::string original = join_sequences_at_kmer(s_m_base, m_e_base, k);
+    std::string base = original;
+
+    // filter out poor quality reads
+    filter_outlier_data(data, base);
+
+    // Only attempt correction if there are any reads here
+    if(!data.empty()) {
+        
+        std::string bs_result = run_block_substitution(base, data, alts);
+        std::string mut_result = run_mutation(bs_result, data);
+        base = mut_result;
+    }
+
+    if(opt::verbose > 0) {
+        fprintf(stderr, "ORIGINAL[%d] %s\n", segment_id, original.c_str());
+        fprintf(stderr, "RESULT[%d]   %s\n", segment_id, base.c_str());
+    }
+        
+    // Update the sequences for the start and middle segments
+    // by cutting the new consensus in the middle
+    // We maintain the k-mer match invariant by requiring the
+    // sequences to overlap by k-bp
+    assert(base.length() >= k);
+    uint32_t midpoint_kmer = (base.length() - k + 1) / 2;
+
+    std::string s_m_fixed = base.substr(0, midpoint_kmer + k);
+    std::string m_e_fixed = base.substr(midpoint_kmer);
+
+    assert(s_m_fixed.substr(s_m_fixed.size() - k) == m_e_fixed.substr(0, k));
+
+    start_column.base_sequence = s_m_fixed;
+    middle_column.base_sequence = m_e_fixed;
+
+    // Update the event indices in the first column to match 
+    for(uint32_t ri = 0; ri < data.size(); ++ri) {
+
+        // Realign to the consensus sequence
+        std::vector<HMMAlignmentState> decodes = profile_hmm_align(base, data[ri]);
+
+        // Get the closest event aligned to the target kmer
+        int32_t min_k_dist = base.length();
+        uint32_t event_idx = 0;
+        for(uint32_t di = 0; di < decodes.size(); ++di) {
+            int32_t dist = abs(decodes[di].kmer_idx - midpoint_kmer);
+            if(dist <= min_k_dist) {
+                min_k_dist = dist;
+                event_idx = decodes[di].event_idx;
+            }
+        }
+
+        middle_column.anchors[data[ri].anchor_index].event_idx = event_idx;
+    }
+}
+
+// update the training data on the current segment
+void train_segment(HMMRealignmentInput& window, uint32_t segment_id)
+{
+    // Get the segments
+    assert(segment_id + 2 < window.anchored_columns.size());
+    HMMAnchoredColumn& start_column = window.anchored_columns[segment_id];
+    HMMAnchoredColumn& middle_column = window.anchored_columns[segment_id + 1];
+    HMMAnchoredColumn& end_column = window.anchored_columns[segment_id + 2];
+
+    std::string s_m_base = start_column.base_sequence;
+    std::string m_e_base = middle_column.base_sequence;
+
+    // Set up the the input data for the HMM
+    std::vector<HMMInputData> input = get_input_for_columns(window, start_column, end_column);
+
+    // assume models for all the reads have the same k
+    assert(!input.empty());
+    const uint32_t k = input[0].read->pore_model[input[0].strand].k;
+
+    std::string segment_sequence = join_sequences_at_kmer(s_m_base, m_e_base, k);
+     
+    for(uint32_t ri = 0; ri < input.size(); ++ri) {
+        std::vector<HMMAlignmentState> decodes = profile_hmm_align(segment_sequence, input[ri]);
+        update_training_with_segment(segment_sequence, input[ri]);
+    }
+}
+
+void train(HMMRealignmentInput& window)
+{
+    // train on current consensus
+    uint32_t num_segments = window.anchored_columns.size();
+    for(uint32_t segment_id = 0; segment_id < num_segments - 2; ++segment_id) {
+        train_segment(window, segment_id);
+    }
+
+    // Update model parameters
+    for(uint32_t ri = 0; ri < window.reads.size(); ++ri) {
+        window.reads[ri]->parameters[0].train();
+        window.reads[ri]->parameters[1].train();
+    }
+}
+
+std::string call_consensus_for_window(const Fast5Map& name_map, const std::string& contig, int start_base, int end_base)
+{
+    const int minor_segment_stride = 50;
+    HMMRealignmentInput window = build_input_for_region(opt::bam_file, opt::genome_file, name_map, contig, start_base, end_base, minor_segment_stride);
+
+    if(window.reads.empty()) {
+        // No data for this window, just return the original sequence as the consensus
+        assert(!window.original_sequence.empty());
+        return window.original_sequence;
+    }
+
+    //
+    // Train the HMM
+    //
+    train(window);
+
+    // assume models for all the reads have the same k
+    const uint32_t k = window.reads[0]->pore_model[T_IDX].k;
+
+    //
+    // Compute the new consensus sequence
+    //
+    std::string reference = "";
+    std::string consensus = "";
+
+    uint32_t num_segments = window.anchored_columns.size();
+    uint32_t start_segment_id = 0;
+
+    // Copy the base segments before they are updated
+    // by the consensus algorithm
+    std::vector<std::string> ref_segments;
+    for(uint32_t segment_id = 0; segment_id < num_segments; ++segment_id) {
+        ref_segments.push_back(window.anchored_columns[segment_id].base_sequence);
+    }
+
+    // Initialize progress status
+    std::stringstream message;
+    message << "[consensus] " << contig << ":" << start_base << "-" << end_base;
+    Progress progress(message.str());
+
+    for(uint32_t segment_id = start_segment_id; segment_id < num_segments - 2; ++segment_id) {
+
+        // update progress
+        if(opt::show_progress) {
+            progress.print((float)segment_id / (num_segments - 2));
+        }
+
+        // run the consensus algorithm for this segment
+        run_splice_segment(window, segment_id);
+
+        // run_splice_segment updates the base_sequence of the current anchor, grab it and append
+        std::string base = window.anchored_columns[segment_id].base_sequence;
+
+        // append the new sequences in, respecting the K overlap
+        reference = join_sequences_at_kmer(reference, ref_segments[segment_id], k);
+        consensus = join_sequences_at_kmer(consensus, base, k);
+
+        if(opt::verbose > 0) {
+            fprintf(stderr, "UNCORRECT[%d]: %s\n", segment_id, reference.c_str());
+            fprintf(stderr, "CONSENSUS[%d]: %s\n", segment_id, consensus.c_str());
+        }
+    }
+
+    // Append segment that ends at the last anchor
+    reference = join_sequences_at_kmer(reference, ref_segments[num_segments - 2], k);
+    const std::string& last_segment = 
+        window.anchored_columns[num_segments - 2].base_sequence;
+    consensus = join_sequences_at_kmer(consensus, last_segment, k);
+
+    if(opt::show_progress) {
+        progress.end();
+    }
+
+    return consensus;
+}
+
+void parse_consensus_options(int argc, char** argv)
+{
+    bool die = false;
+    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
+        std::istringstream arg(optarg != NULL ? optarg : "");
+        switch (c) {
+            case 'r': arg >> opt::reads_file; break;
+            case 'g': arg >> opt::genome_file; break;
+            case 'b': arg >> opt::bam_file; break;
+            case 'w': arg >> opt::window; break;
+            case 'o': arg >> opt::output_file; break;
+            case '?': die = true; break;
+            case 't': arg >> opt::num_threads; break;
+            case 'v': opt::verbose++; break;
+            case OPT_PROGRESS: opt::show_progress = 1; break;
+            case OPT_HELP:
+                std::cout << CONSENSUS_USAGE_MESSAGE;
+                exit(EXIT_SUCCESS);
+            case OPT_VERSION:
+                std::cout << CONSENSUS_VERSION_MESSAGE;
+                exit(EXIT_SUCCESS);
+        }
+    }
+
+    if (argc - optind < 0) {
+        std::cerr << SUBPROGRAM ": missing arguments\n";
+        die = true;
+    } else if (argc - optind > 0) {
+        std::cerr << SUBPROGRAM ": too many arguments\n";
+        die = true;
+    }
+
+    if(opt::num_threads <= 0) {
+        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
+        die = true;
+    }
+
+    if(opt::reads_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::genome_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
+        die = true;
+    }
+
+    if(opt::bam_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
+        die = true;
+    }
+
+    if (die) 
+    {
+        std::cout << "\n" << CONSENSUS_USAGE_MESSAGE;
+        exit(EXIT_FAILURE);
+    }
+}
+
+int consensus_main(int argc, char** argv)
+{
+    parse_consensus_options(argc, argv);
+    omp_set_num_threads(opt::num_threads);
+
+    Fast5Map name_map(opt::reads_file);
+
+    // Parse the window string
+    // Replace ":" and "-" with spaces to make it parseable with stringstream
+    std::replace(opt::window.begin(), opt::window.end(), ':', ' ');
+    std::replace(opt::window.begin(), opt::window.end(), '-', ' ');
+
+    const int WINDOW_LENGTH = 10000;
+    const int WINDOW_OVERLAP = 200;
+
+    std::stringstream parser(opt::window);
+    std::string contig;
+    int start_window_id;
+    int end_window_id;
+    
+    parser >> contig >> start_window_id >> end_window_id;
+
+    FILE* out_fp = NULL;
+
+    if(!opt::output_file.empty()) {
+        out_fp = fopen(opt::output_file.c_str(), "w");
+    } else {
+        out_fp = stdout;
+    }
+
+    for(int window_id = start_window_id; window_id < end_window_id; ++window_id) {
+        int start_base = window_id * WINDOW_LENGTH;
+        int end_base = start_base + WINDOW_LENGTH + WINDOW_OVERLAP;
+        
+        std::string window_consensus = call_consensus_for_window(name_map, contig, start_base, end_base);
+        fprintf(out_fp, ">%s:%d\n%s\n", contig.c_str(), window_id, window_consensus.c_str());
+    }
+
+    if(out_fp != stdout) {
+        fclose(out_fp);
+    }
+}
diff --git a/src/nanopolish_consensus.h b/src/nanopolish_consensus.h
new file mode 100644
index 0000000..38afea1
--- /dev/null
+++ b/src/nanopolish_consensus.h
@@ -0,0 +1,14 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_consensus.cpp -- compute a new consensus sequence
+// for an assembly
+//
+#ifndef NANOPOLISH_CONSENSUS_H
+#define NANOPOLISH_CONSENSUS_H
+
+void consensus_main(int argc, char** argv);
+
+#endif
diff --git a/src/nanopolish_getmodel.cpp b/src/nanopolish_getmodel.cpp
new file mode 100644
index 0000000..6f44689
--- /dev/null
+++ b/src/nanopolish_getmodel.cpp
@@ -0,0 +1,123 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_getmodel.h - write the pore model for a read
+// to stdout
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <sys/time.h>
+#include <algorithm>
+#include <sstream>
+#include <set>
+#include <omp.h>
+#include <getopt.h>
+#include "htslib/faidx.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_squiggle_read.h"
+#include "profiler.h"
+
+//
+// Getopt
+//
+#define SUBPROGRAM "getmodel"
+
+static const char *GETMODEL_VERSION_MESSAGE =
+SUBPROGRAM " Version " PACKAGE_VERSION "\n"
+"Written by Jared Simpson.\n"
+"\n"
+"Copyright 2015 Ontario Institute for Cancer Research\n";
+
+static const char *GETMODEL_USAGE_MESSAGE =
+"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] read.fast5\n"
+"Write the pore models for the given read to stdout\n"
+"\n"
+"  -v, --verbose                        display verbose output\n"
+"      --version                        display version\n"
+"      --help                           display this help and exit\n"
+"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";
+
+namespace opt
+{
+    static unsigned int verbose;
+    static std::string input_file;
+}
+
+static const char* shortopts = "v";
+
+enum { OPT_HELP = 1, OPT_VERSION };
+
+static const struct option longopts[] = {
+    { "verbose",     no_argument,       NULL, 'v' },
+    { "help",        no_argument,       NULL, OPT_HELP },
+    { "version",     no_argument,       NULL, OPT_VERSION },
+    { NULL, 0, NULL, 0 }
+};
+
+void parse_getmodel_options(int argc, char** argv)
+{
+    bool die = false;
+    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
+        std::istringstream arg(optarg != NULL ? optarg : "");
+        switch (c) {
+            case '?': die = true; break;
+            case 'v': opt::verbose++; break;
+            case OPT_HELP:
+                std::cout << GETMODEL_USAGE_MESSAGE;
+                exit(EXIT_SUCCESS);
+            case OPT_VERSION:
+                std::cout << GETMODEL_VERSION_MESSAGE;
+                exit(EXIT_SUCCESS);
+        }
+    }
+    
+    if (argc - optind < 1) {
+        std::cerr << SUBPROGRAM ": not enough arguments\n";
+        die = true;
+    }
+
+    if (argc - optind > 1) {
+        std::cerr << SUBPROGRAM ": too many arguments\n";
+        die = true;
+    }
+
+    opt::input_file = argv[optind++];
+
+    if (die) 
+    {
+        std::cout << "\n" << GETMODEL_USAGE_MESSAGE;
+        exit(EXIT_FAILURE);
+    }
+}
+
+int getmodel_main(int argc, char** argv)
+{
+    parse_getmodel_options(argc, argv);
+
+    SquiggleRead sr("input", opt::input_file);
+
+    printf("strand\tkmer\tmodel_mean\tmodel_stdv\n");
+
+    for(size_t si = 0; si < 2; ++si) {
+
+        char strand = si == 0 ? 't' : 'c';
+        
+        uint32_t k = sr.pore_model[si].k;
+        std::string kmer(k, 'A');
+        assert(sr.pore_model[si].get_num_states() == gDNAAlphabet.get_num_strings(k));
+
+        for(size_t ki = 0; ki < sr.pore_model[si].get_num_states(); ++ki) {
+            PoreModelStateParams params = sr.pore_model[si].get_parameters(ki);
+            printf("%c\t%s\t%.2lf\t%.2lf\n", strand, kmer.c_str(), params.level_mean, params.level_stdv);
+            gDNAAlphabet.lexicographic_next(kmer); // advance kmer
+        }
+    }
+}
diff --git a/src/nanopolish_getmodel.h b/src/nanopolish_getmodel.h
new file mode 100644
index 0000000..c2d3aab
--- /dev/null
+++ b/src/nanopolish_getmodel.h
@@ -0,0 +1,14 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_getmodel.h - write the pore model for a read
+// to stdout
+//
+#ifndef NANOPOLISH_GETMODEL_H
+#define NANOPOLISH_GETMODEL_H
+
+void getmodel_main(int argc, char** argv);
+
+#endif
diff --git a/src/nanopolish_haplotype.cpp b/src/nanopolish_haplotype.cpp
new file mode 100644
index 0000000..df01957
--- /dev/null
+++ b/src/nanopolish_haplotype.cpp
@@ -0,0 +1,123 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_haplotype - a haplotype derived from 
+// a reference sequence and a set of variants
+//
+#include "nanopolish_haplotype.h"
+
+// Definitions
+const size_t Haplotype::INSERTED_POSITION = std::string::npos;
+
+Haplotype::Haplotype(const std::string& ref_name,
+                     const size_t ref_position,
+                     const std::string& ref_sequence) : 
+                        m_ref_name(ref_name),
+                        m_ref_position(ref_position),
+                        m_reference(ref_sequence)
+{
+    m_sequence = m_reference;
+    m_coordinate_map.resize(m_reference.size());
+    for(size_t i = 0; i < m_coordinate_map.size(); ++i) {
+        m_coordinate_map[i] = m_ref_position + i;
+    }
+}
+ 
+//       
+void Haplotype::apply_variant(const Variant& v)
+{
+    // Search the coordinate map for the reference position
+    size_t derived_idx = _find_derived_index_by_ref_lower_bound(v.ref_position);
+
+    // if we could not find the reference position in the map
+    // this variant is incompatable with the haplotype, do nothing
+    if(derived_idx == m_coordinate_map.size() || 
+       m_coordinate_map[derived_idx] != v.ref_position) 
+    {
+        return;
+    }
+
+    // Check that the string matches
+    size_t rl = v.ref_seq.length();
+    size_t al = v.alt_seq.length();
+
+    // no match, variant conflicts with haplotype sequence
+    if(m_sequence.substr(derived_idx, rl) != v.ref_seq) {
+        return;
+    }
+
+    // update sequence
+    m_sequence.replace(derived_idx, rl, v.alt_seq);
+
+    // update coordinate map
+    
+    // make a pair of iterators that bound the changed sequence
+    std::vector<size_t>::iterator fi = m_coordinate_map.begin() + derived_idx;
+    std::vector<size_t>::iterator li = fi + rl;
+    
+    // erase the positions of the changed bases
+    std::vector<size_t>::iterator ii = m_coordinate_map.erase(fi, li);
+
+    // insert new positions for the alt bases with invalid indices
+    m_coordinate_map.insert(ii, al, INSERTED_POSITION);
+    
+    // sanity check
+    assert(m_coordinate_map.size() == m_sequence.size());
+
+    m_variants.push_back(v);
+}
+
+// return a new haplotype subsetted by reference coordinates
+Haplotype Haplotype::substr_by_reference(size_t start, size_t end)
+{
+    assert(start >= m_ref_position);
+    assert(start <= m_ref_position + m_reference.length());
+    
+    assert(end >= m_ref_position);
+    assert(end <= m_ref_position + m_reference.length());
+
+    size_t derived_base_start = _find_derived_index_by_ref_lower_bound(start);
+    size_t derived_base_end = _find_derived_index_by_ref_lower_bound(end);
+    
+    // Bump out the reference coordinate to encompass the complete range (start, end)
+    while(m_coordinate_map[derived_base_start] > start ||
+          m_coordinate_map[derived_base_start] == INSERTED_POSITION)
+    { 
+        derived_base_start -= 1;
+    }
+
+    assert(derived_base_start != m_coordinate_map.size());
+    assert(derived_base_end != m_coordinate_map.size());
+    assert(m_coordinate_map[derived_base_start] <= start);
+    assert(m_coordinate_map[derived_base_end] >= end);
+
+    start = m_coordinate_map[derived_base_start];
+    end = m_coordinate_map[derived_base_end];
+    
+    Haplotype ret(m_ref_name,
+                  start,
+                  m_reference.substr(start - m_ref_position, end - start + 1));
+
+    ret.m_sequence = m_sequence.substr(derived_base_start, derived_base_end - derived_base_start + 1);
+    ret.m_coordinate_map = std::vector<size_t>(m_coordinate_map.begin() + derived_base_start,
+                                               m_coordinate_map.begin() + derived_base_end + 1);
+
+    assert(ret.m_coordinate_map.front() == start);
+    assert(ret.m_coordinate_map.back() == end);
+    assert(ret.m_coordinate_map.size() == ret.m_sequence.size());
+
+    return ret;
+}
+
+size_t Haplotype::_find_derived_index_by_ref_lower_bound(size_t ref_index)
+{
+    for(size_t i = 0; i < m_coordinate_map.size(); ++i) {
+        if(m_coordinate_map[i] != INSERTED_POSITION && m_coordinate_map[i] >= ref_index) {
+            return i;
+        }
+    }
+    return m_coordinate_map.size();
+}
+
diff --git a/src/nanopolish_haplotype.h b/src/nanopolish_haplotype.h
new file mode 100644
index 0000000..1943fdf
--- /dev/null
+++ b/src/nanopolish_haplotype.h
@@ -0,0 +1,75 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_haplotype - a haplotype derived from 
+// a reference sequence and a set of variants
+//
+#ifndef NANOPOLISH_HAPLOTYPE_H
+#define NANOPOLISH_HAPLOTYPE_H
+
+#include "nanopolish_variant.h"
+
+class Haplotype
+{
+    public:
+
+        // constructor
+        Haplotype(const std::string& ref_name,
+                  const size_t ref_position,
+                  const std::string& ref_sequence);
+        
+        // get the sequence of the haplotype
+        const std::string& get_sequence() const { return m_sequence; } 
+        
+        // get the sequence of the reference
+        const std::string& get_reference() const { return m_reference; } 
+    
+        // add a variant into the haplotype
+        void apply_variant(const Variant& v);
+
+        // return all the variants on this haplotype
+        std::vector<Variant> get_variants() const { return m_variants; }
+
+        // return a new haplotype subsetted by reference coordinates
+        Haplotype substr_by_reference(size_t start, size_t end);
+
+    private:
+        
+        // functions
+        Haplotype(); // not allowed
+        
+        // Find the first derived index that has a corresponding
+        // reference position which is not less than ref_index.
+        // This mimics std::lower_bound
+        size_t _find_derived_index_by_ref_lower_bound(size_t ref_index);
+
+        //
+        // data
+        //
+
+        // the name of the reference contig/chromosome this haplotype is from
+        std::string m_ref_name;
+
+        // the start position of the reference sequence on the ref contig/chromosome
+        size_t m_ref_position;
+
+        // the original sequence this haplotype is based on
+        std::string m_reference;
+        
+        // the sequence of the haplotype
+        std::string m_sequence;
+
+        // the set of variants this haplotype contains
+        std::vector<Variant> m_variants;
+
+        // a mapping from bases of the derived sequence
+        // to their original reference position
+        std::vector<size_t> m_coordinate_map;
+
+        // a constant value indicating inserted sequence in the coordinate map
+        static const size_t INSERTED_POSITION;
+};
+
+#endif
diff --git a/src/nanopolish_methyltest.cpp b/src/nanopolish_methyltest.cpp
new file mode 100644
index 0000000..fe1a022
--- /dev/null
+++ b/src/nanopolish_methyltest.cpp
@@ -0,0 +1,539 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_methyltrain -- train a methylation model
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <sys/time.h>
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <set>
+#include <omp.h>
+#include <getopt.h>
+#include "htslib/faidx.h"
+#include "nanopolish_eventalign.h"
+#include "nanopolish_iupac.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_transition_parameters.h"
+#include "nanopolish_matrix.h"
+#include "nanopolish_profile_hmm.h"
+#include "nanopolish_anchor.h"
+#include "nanopolish_fast5_map.h"
+#include "nanopolish_methyltrain.h"
+#include "H5pubconf.h"
+#include "profiler.h"
+#include "progress.h"
+
+//
+// Structs
+//
+struct OutputHandles
+{
+    FILE* site_writer;
+    FILE* read_writer;
+    FILE* strand_writer;
+};
+
+struct ScoredSite
+{
+    ScoredSite() 
+    { 
+        ll_unmethylated[0] = 0;
+        ll_unmethylated[1] = 0;
+        ll_methylated[0] = 0;
+        ll_methylated[1] = 0;
+    }
+
+    std::string chromosome;
+    int start_position;
+    int end_position;
+    int n_cpg;
+    std::string sequence;
+
+    // scores per strand
+    double ll_unmethylated[2];
+    double ll_methylated[2];
+
+    //
+    static bool sort_by_position(const ScoredSite& a, const ScoredSite& b) { return a.start_position < b.start_position; }
+
+};
+
+//
+Alphabet* mtest_alphabet = &gMCpGAlphabet;
+
+//
+// Getopt
+//
+#define SUBPROGRAM "methyltest"
+
+static const char *METHYLTEST_VERSION_MESSAGE =
+SUBPROGRAM " Version " PACKAGE_VERSION "\n"
+"Written by Jared Simpson.\n"
+"\n"
+"Copyright 2015 Ontario Institute for Cancer Research\n";
+
+static const char *METHYLTEST_USAGE_MESSAGE =
+"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
+"Train a methylation model\n"
+"\n"
+"  -v, --verbose                        display verbose output\n"
+"      --version                        display version\n"
+"      --help                           display this help and exit\n"
+"  -m, --models-fofn=FILE               read the models from the FOFN\n"
+"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
+"  -b, --bam=FILE                       the reads aligned to the genome assembly are in bam FILE\n"
+"  -g, --genome=FILE                    the genome we are computing a consensus for is in FILE\n"
+"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
+"      --progress                       print out a progress message\n"
+"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";
+
+namespace opt
+{
+    static unsigned int verbose;
+    static std::string reads_file;
+    static std::string bam_file;
+    static std::string genome_file;
+    static std::string models_fofn;
+    static std::string region;
+    static int progress = 0;
+    static int num_threads = 1;
+    static int batch_size = 128;
+}
+
+static const char* shortopts = "r:b:g:t:w:m:vn";
+
+enum { OPT_HELP = 1, OPT_VERSION, OPT_PROGRESS };
+
+static const struct option longopts[] = {
+    { "verbose",          no_argument,       NULL, 'v' },
+    { "reads",            required_argument, NULL, 'r' },
+    { "bam",              required_argument, NULL, 'b' },
+    { "genome",           required_argument, NULL, 'g' },
+    { "window",           required_argument, NULL, 'w' },
+    { "threads",          required_argument, NULL, 't' },
+    { "models-fofn",      required_argument, NULL, 'm' },
+    { "progress",         no_argument,       NULL, OPT_PROGRESS },
+    { "help",             no_argument,       NULL, OPT_HELP },
+    { "version",          no_argument,       NULL, OPT_VERSION },
+    { NULL, 0, NULL, 0 }
+};
+
+// Expand the event indices outwards
+void bump(HMMInputData& data, int amount)
+{
+    if(data.event_start_idx < data.event_stop_idx) {
+        data.event_start_idx -= amount;
+        data.event_stop_idx += amount;
+    } else {
+        data.event_start_idx += amount;
+        data.event_stop_idx -= amount;
+    }
+}
+// Realign the read in event space
+void test_read(const ModelMap& model_map,
+               const Fast5Map& name_map, 
+               const faidx_t* fai, 
+               const bam_hdr_t* hdr, 
+               const bam1_t* record, 
+               size_t read_idx,
+               const OutputHandles& handles)
+{
+    // Load a squiggle read for the mapped read
+    std::string read_name = bam_get_qname(record);
+    std::string fast5_path = name_map.get_path(read_name);
+
+    // load read
+    SquiggleRead sr(read_name, fast5_path);
+    double read_score = 0.0f;
+    size_t num_sites_tested = 0;
+
+    std::map<int, ScoredSite> site_score_map;
+
+    for(size_t strand_idx = 0; strand_idx < NUM_STRANDS; ++strand_idx) {
+        std::vector<double> site_scores;
+        std::vector<int> site_starts;
+        std::vector<int> site_ends;
+        std::vector<int> site_count;
+
+        double strand_score = 0.0f;
+
+        // replace model 
+        std::string curr_model = sr.pore_model[strand_idx].name;
+
+        std::string methyl_model = curr_model + ".methyltrain";
+        auto model_iter = model_map.find(methyl_model);
+
+        if(model_iter != model_map.end()) {
+            sr.pore_model[strand_idx].update_states( model_iter->second );
+        } else {
+            fprintf(stderr, "Error, methylated model %s not found\n", methyl_model.c_str());
+            exit(EXIT_FAILURE);
+        }
+
+        // Align to the new model
+        EventAlignmentParameters params;
+        params.sr = &sr;
+        params.fai = fai;
+        params.hdr = hdr;
+        params.record = record;
+        params.strand_idx = strand_idx;
+        params.read_idx = read_idx;
+        params.alphabet = mtest_alphabet;
+
+        std::vector<EventAlignment> alignment_output = align_read_to_ref(params);
+        if(alignment_output.empty())
+            continue;
+        std::string contig = alignment_output.front().ref_name.c_str();
+        
+        //emit_event_alignment_tsv(stdout, sr, params, alignment_output);
+        
+        // Convert the EventAlignment to a map between reference positions and events
+        std::vector<AlignedPair> event_aligned_pairs;
+        for(size_t i = 0; i < alignment_output.size(); ++i) {
+
+            AlignedPair ap = { alignment_output[i].ref_position,
+                               alignment_output[i].event_idx };
+            event_aligned_pairs.push_back(ap);
+        }
+
+        int ref_start_pos = event_aligned_pairs.front().ref_pos;
+        int ref_end_pos = event_aligned_pairs.back().ref_pos;
+
+        int fetched_len = 0;
+        assert(ref_end_pos >= ref_start_pos);
+
+        // Extract the reference sequence for this region
+        std::string ref_seq = get_reference_region_ts(params.fai, contig.c_str(), ref_start_pos, 
+                                                  ref_end_pos, &fetched_len);
+        
+        ref_seq = gDNAAlphabet.disambiguate(ref_seq);
+
+        // Scan the sequence for CpGs
+        std::vector<int> cpg_sites;
+        assert(ref_seq.size() != 0);
+        for(size_t i = 0; i < ref_seq.size() - 1; ++i) {
+            if(ref_seq[i] == 'C' && ref_seq[i+1] == 'G') {
+                cpg_sites.push_back(i);
+            }
+        }
+        
+        // Batch the CpGs together
+        int min_separation = 10;
+        size_t curr_idx = 0;
+        while(curr_idx < cpg_sites.size()) {
+
+            size_t end_idx = curr_idx + 1;
+            while(end_idx < cpg_sites.size()) {
+                if(cpg_sites[end_idx] - cpg_sites[end_idx - 1] > min_separation)
+                    break;
+                end_idx += 1; 
+            }
+
+            int sub_start_pos = cpg_sites[curr_idx] - min_separation;
+            int sub_end_pos = cpg_sites[end_idx - 1] + min_separation;
+
+            if(sub_start_pos > min_separation && cpg_sites[end_idx - 1] - cpg_sites[curr_idx] < 200) {
+    
+                std::string subseq = ref_seq.substr(sub_start_pos, sub_end_pos - sub_start_pos + 1);
+                std::string rc_subseq = mtest_alphabet->reverse_complement(subseq);
+
+                AlignedPairRefLBComp lb_comp;
+                AlignedPairConstIter start_iter = std::lower_bound(event_aligned_pairs.begin(), event_aligned_pairs.end(),
+                                                                   sub_start_pos + ref_start_pos, lb_comp);
+
+                AlignedPairConstIter stop_iter = std::lower_bound(event_aligned_pairs.begin(), event_aligned_pairs.end(),
+                                                                   sub_end_pos + ref_start_pos, lb_comp);
+
+                if(start_iter != event_aligned_pairs.end() && stop_iter != event_aligned_pairs.end()) {
+
+                    std::string site_string = ref_seq.substr(cpg_sites[curr_idx] - 3, 5);
+                    
+                    uint32_t hmm_flags = HAF_ALLOW_PRE_CLIP | HAF_ALLOW_POST_CLIP;
+
+                    // Set up event data
+                    HMMInputData data;
+                    data.read = &sr;
+                    data.anchor_index = -1; // unused
+                    data.strand = strand_idx;
+                    data.rc = alignment_output.front().rc;
+                    data.event_start_idx = start_iter->read_pos;
+                    data.event_stop_idx = stop_iter->read_pos;
+                    data.event_stride = data.event_start_idx < data.event_stop_idx ? 1 : -1;
+                    
+                    HMMInputSequence unmethylated(subseq, rc_subseq, mtest_alphabet);
+                    double unmethylated_score = profile_hmm_score(unmethylated, data, hmm_flags);
+
+                    // Methylate the CpGs in the sequence and score again
+                    std::string mcpg_subseq = gMCpGAlphabet.methylate(subseq);
+                    std::string rc_mcpg_subseq = gMCpGAlphabet.reverse_complement(mcpg_subseq);
+                    
+                    //printf("m_subs: %s\n", mcpg_subseq.c_str());
+                    //printf("m_rc_s: %s\n", rc_mcpg_subseq.c_str());
+                    
+                    HMMInputSequence methylated(mcpg_subseq, rc_mcpg_subseq, mtest_alphabet);
+                    double methylated_score = profile_hmm_score(methylated, data, hmm_flags);
+                    double diff = methylated_score - unmethylated_score;
+
+                    ScoredSite ss;
+                    int start_position = cpg_sites[curr_idx] + ref_start_pos;
+                    auto iter = site_score_map.find(start_position);
+                    if(iter == site_score_map.end()) {
+                        // insert new score into the map
+                        ScoredSite ss;
+                        ss.chromosome = contig;
+                        ss.start_position = start_position;
+                        ss.end_position = cpg_sites[end_idx - 1] + ref_start_pos;
+                        ss.n_cpg = end_idx - curr_idx;
+                        ss.sequence = site_string;
+                        iter = site_score_map.insert(std::make_pair(start_position, ss)).first;
+                    }
+                    
+                    iter->second.ll_unmethylated[strand_idx] = unmethylated_score;
+                    iter->second.ll_methylated[strand_idx] = methylated_score;
+
+                    /*
+                    // Debug alignments
+                    printf("Forward unmethylated: %.2lf\n", unmethylated_score);
+                    printf("Forward methylated: %.2lf\n", methylated_score);
+                    std::vector<HMMAlignmentState> um_align = profile_hmm_align(unmethylated, data, hmm_flags);
+                    print_alignment("unmethylated", start_position, 0, unmethylated, data, um_align);
+                    
+                    std::vector<HMMAlignmentState> m_align = profile_hmm_align(methylated, data, hmm_flags);
+                    print_alignment("methylated", start_position, 0, methylated, data, m_align);
+                    */
+                }
+            }
+
+            curr_idx = end_idx;
+        }
+    } // for strands
+    
+    #pragma omp critical(methyltest_write)
+    {
+        double ll_ratio_sum_strand[2] = { 0.0f, 0.0f };
+        double ll_ratio_sum_both = 0;
+        size_t num_positive = 0;
+
+        for(auto iter = site_score_map.begin(); iter != site_score_map.end(); ++iter) {
+
+            const ScoredSite& ss = iter->second;
+
+            double sum_ll_m = ss.ll_methylated[0] + ss.ll_methylated[1];
+            double sum_ll_u = ss.ll_unmethylated[0] + ss.ll_unmethylated[1];
+
+            double diff = sum_ll_m - sum_ll_u;
+            num_positive += diff > 0;
+
+            fprintf(handles.site_writer, "%s\t%d\t%d\t", ss.chromosome.c_str(), ss.start_position, ss.end_position);
+            fprintf(handles.site_writer, "LL_METH=%.2lf;LL_UNMETH=%.2lf;LL_RATIO=%.2lf;", sum_ll_m, sum_ll_u, diff);
+            fprintf(handles.site_writer, "N_CPG=%d;SEQUENCE=%s\n", ss.n_cpg, ss.sequence.c_str());
+
+            ll_ratio_sum_strand[0] += ss.ll_methylated[0] - ss.ll_unmethylated[0];
+            ll_ratio_sum_strand[1] += ss.ll_methylated[1] - ss.ll_unmethylated[1];
+            ll_ratio_sum_both += diff;
+        }
+        std::string complement_model = sr.pore_model[C_IDX].name;
+        fprintf(handles.read_writer, "%s\t%.2lf\t%zu\t%s\tNUM_POSITIVE=%zu\n", fast5_path.c_str(), ll_ratio_sum_both, site_score_map.size(), complement_model.c_str(), num_positive);
+    
+        for(size_t si = 0; si < NUM_STRANDS; ++si) {
+            std::string model = sr.pore_model[si].name;
+            fprintf(handles.strand_writer, "%s\t%.2lf\t%zu\t%s\n", fast5_path.c_str(), ll_ratio_sum_strand[si], site_score_map.size(), model.c_str());
+        }
+    }
+}
+
+void parse_methyltest_options(int argc, char** argv)
+{
+    bool die = false;
+    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
+        std::istringstream arg(optarg != NULL ? optarg : "");
+        switch (c) {
+            case 'r': arg >> opt::reads_file; break;
+            case 'g': arg >> opt::genome_file; break;
+            case 'b': arg >> opt::bam_file; break;
+            case '?': die = true; break;
+            case 't': arg >> opt::num_threads; break;
+            case 'm': arg >> opt::models_fofn; break;
+            case 'v': opt::verbose++; break;
+            case OPT_PROGRESS: opt::progress = true; break;
+            case OPT_HELP:
+                std::cout << METHYLTEST_USAGE_MESSAGE;
+                exit(EXIT_SUCCESS);
+            case OPT_VERSION:
+                std::cout << METHYLTEST_VERSION_MESSAGE;
+                exit(EXIT_SUCCESS);
+        }
+    }
+
+    if(argc - optind > 0) {
+        opt::region = argv[optind++];
+    }
+
+    if (argc - optind > 0) {
+        std::cerr << SUBPROGRAM ": too many arguments\n";
+        die = true;
+    }
+
+    if(opt::num_threads <= 0) {
+        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
+        die = true;
+    }
+
+    if(opt::reads_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::genome_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
+        die = true;
+    }
+
+    if(opt::bam_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::models_fofn.empty()) {
+        std::cerr << SUBPROGRAM ": a --models-fofn file must be provided\n";
+        die = true;
+    }
+
+    if (die) 
+    {
+        std::cout << "\n" << METHYLTEST_USAGE_MESSAGE;
+        exit(EXIT_FAILURE);
+    }
+}
+
+int methyltest_main(int argc, char** argv)
+{
+    parse_methyltest_options(argc, argv);
+    omp_set_num_threads(opt::num_threads);
+
+    Fast5Map name_map(opt::reads_file);
+    ModelMap models = read_models_fofn(opt::models_fofn);
+    
+    // Open the BAM and iterate over reads
+
+    // load bam file
+    htsFile* bam_fh = sam_open(opt::bam_file.c_str(), "r");
+    assert(bam_fh != NULL);
+
+    // load bam index file
+    std::string index_filename = opt::bam_file + ".bai";
+    hts_idx_t* bam_idx = bam_index_load(index_filename.c_str());
+    assert(bam_idx != NULL);
+
+    // read the bam header
+    bam_hdr_t* hdr = sam_hdr_read(bam_fh);
+    
+    // load reference fai file
+    faidx_t *fai = fai_load(opt::genome_file.c_str());
+
+    hts_itr_t* itr;
+
+    // If processing a region of the genome, only emit events aligned to this window
+    int clip_start = -1;
+    int clip_end = -1;
+
+    if(opt::region.empty()) {
+        // TODO: is this valid?
+        itr = sam_itr_queryi(bam_idx, HTS_IDX_START, 0, 0);
+    } else {
+
+        fprintf(stderr, "Region: %s\n", opt::region.c_str());
+        itr = sam_itr_querys(bam_idx, hdr, opt::region.c_str());
+        hts_parse_reg(opt::region.c_str(), &clip_start, &clip_end);
+    }
+
+#ifndef H5_HAVE_THREADSAFE
+    if(opt::num_threads > 1) {
+        fprintf(stderr, "You enabled multi-threading but you do not have a threadsafe HDF5\n");
+        fprintf(stderr, "Please recompile nanopolish's built-in libhdf5 or run with -t 1\n");
+        exit(1);
+    }
+#endif
+
+    // Initialize writers
+    OutputHandles handles;
+    handles.site_writer = fopen(std::string(opt::bam_file + ".methyltest.sites.bed").c_str(), "w");
+    handles.read_writer = fopen(std::string(opt::bam_file + ".methyltest.reads.tsv").c_str(), "w");
+    handles.strand_writer = fopen(std::string(opt::bam_file + ".methyltest.strand.tsv").c_str(), "w");
+
+    // Write a header to the reads.tsv file
+    fprintf(handles.read_writer, "name\tsum_ll_ratio\tn_cpg\tcomplement_model\ttags\n");
+    
+    // strand header
+    fprintf(handles.strand_writer, "name\tsum_ll_ratio\tn_cpg\tmodel\n");
+
+
+    // Initialize iteration
+    std::vector<bam1_t*> records(opt::batch_size, NULL);
+    for(size_t i = 0; i < records.size(); ++i) {
+        records[i] = bam_init1();
+    }
+
+    int result;
+    size_t num_reads_processed = 0;
+    size_t num_records_buffered = 0;
+    Progress progress("[methyltest]");
+
+    do {
+        assert(num_records_buffered < records.size());
+        
+        // read a record into the next slot in the buffer
+        result = sam_itr_next(bam_fh, itr, records[num_records_buffered]);
+        num_records_buffered += result >= 0;
+
+        // realign if we've hit the max buffer size or reached the end of file
+        if(num_records_buffered == records.size() || result < 0) {
+            
+            #pragma omp parallel for
+            for(size_t i = 0; i < num_records_buffered; ++i) {
+                bam1_t* record = records[i];
+                size_t read_idx = num_reads_processed + i;
+                if( (record->core.flag & BAM_FUNMAP) == 0) {
+                    test_read(models, name_map, fai, hdr, record, read_idx, handles);
+                }
+            }
+
+            num_reads_processed += num_records_buffered;
+            num_records_buffered = 0;
+
+        }
+    } while(result >= 0);
+    
+    assert(num_records_buffered == 0);
+    progress.end();
+
+    // cleanup records
+    for(size_t i = 0; i < records.size(); ++i) {
+        bam_destroy1(records[i]);
+    }
+
+    // cleanup
+    fclose(handles.site_writer);
+    fclose(handles.read_writer);
+    fclose(handles.strand_writer);
+
+    sam_itr_destroy(itr);
+    bam_hdr_destroy(hdr);
+    fai_destroy(fai);
+    sam_close(bam_fh);
+    hts_idx_destroy(bam_idx);
+    
+    return EXIT_SUCCESS;
+}
+
diff --git a/src/nanopolish_methyltest.h b/src/nanopolish_methyltest.h
new file mode 100644
index 0000000..1405ba5
--- /dev/null
+++ b/src/nanopolish_methyltest.h
@@ -0,0 +1,13 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_methyltest -- test a methylation model
+//
+#ifndef NANOPOLISH_METHYLTEST_H
+#define NANOPOLISH_METHYLTEST_H
+
+int methyltest_main(int argc, char** argv);
+
+#endif
diff --git a/src/nanopolish_methyltrain.cpp b/src/nanopolish_methyltrain.cpp
new file mode 100644
index 0000000..d17d637
--- /dev/null
+++ b/src/nanopolish_methyltrain.cpp
@@ -0,0 +1,770 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_methyltrain -- train a methylation model
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+#include <sys/time.h>
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <set>
+#include <omp.h>
+#include <getopt.h>
+#include "htslib/faidx.h"
+#include "nanopolish_methyltrain.h"
+#include "nanopolish_eventalign.h"
+#include "nanopolish_iupac.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_transition_parameters.h"
+#include "nanopolish_matrix.h"
+#include "nanopolish_profile_hmm.h"
+#include "nanopolish_anchor.h"
+#include "nanopolish_fast5_map.h"
+#include "H5pubconf.h"
+#include "profiler.h"
+#include "progress.h"
+
+//
+// Structs
+//
+
+// The state training data comes in two different
+// sizes Full and Minimal. The model training functions
+// only actually need the Minimal data but for exploration
+// the Full data is useful so left as an option.
+struct FullStateTrainingData
+{
+    //
+    // Functions
+    //
+    FullStateTrainingData(const SquiggleRead& sr,
+                          const EventAlignment& ea,
+                          uint32_t rank,
+                          const std::string& prev_kmer,
+                          const std::string& next_kmer)
+    {
+        // scale the observation to the expected pore model
+        this->level_mean = sr.get_fully_scaled_level(ea.event_idx, ea.strand_idx);
+        //this->event_stdv = sr.events[strand_idx][ea.event_idx].stdv / sr.pore_model[strand_idx].scale_sd;
+        this->level_stdv = 0;
+        this->duration = sr.events[ea.strand_idx][ea.event_idx].duration;
+        
+        this->read_var = (float)sr.pore_model[ea.strand_idx].var;
+        this->ref_position = ea.ref_position;
+        this->ref_strand = ea.rc;
+        
+        GaussianParameters model = sr.pore_model[ea.strand_idx].get_scaled_parameters(rank);
+        this->z = (sr.get_drift_corrected_level(ea.event_idx, ea.strand_idx) -  model.mean ) / model.stdv;
+        this->prev_kmer = prev_kmer;
+        this->next_kmer = next_kmer;
+    }
+
+    static void write_header(FILE* fp)
+    {
+        fprintf(fp, "model\tmodel_kmer\tlevel_mean\tlevel_stdv\tduration\tref_pos\tref_strand\tz\tread_var\tprev_kmer\tnext_kmer\n");
+    }
+
+    void write_tsv(FILE* fp, const std::string& model_name, const std::string& kmer) const
+    {
+        fprintf(fp, "%s\t%s\t%.2lf\t%.2lf\t%.3lf\t%d\t%d\t%.2lf\t%.2lf\t%s\t%s\n", 
+                    model_name.c_str(), 
+                    kmer.c_str(), 
+                    level_mean, 
+                    level_stdv,
+                    duration,
+                    ref_position,
+                    ref_strand,
+                    z,
+                    read_var,
+                    prev_kmer.c_str(),
+                    next_kmer.c_str());
+    }
+
+    //
+    // Data
+    //
+
+    float level_mean;
+    float level_stdv;
+    float duration;
+    float read_var;
+
+    int ref_position;
+    int ref_strand;
+
+    float z;
+    std::string prev_kmer;
+    std::string next_kmer;
+};
+
+struct MinimalStateTrainingData
+{
+    //
+    // Functions
+    //
+    MinimalStateTrainingData(const SquiggleRead& sr,
+                             const EventAlignment& ea,
+                             uint32_t rank,
+                             const std::string& prev_kmer,
+                             const std::string& next_kmer)
+    {
+        // scale the observation to the expected pore model
+        this->level_mean = sr.get_fully_scaled_level(ea.event_idx, ea.strand_idx);
+        this->read_var = (float)sr.pore_model[ea.strand_idx].var;
+    }
+
+    static void write_header(FILE* fp)
+    {
+        fprintf(fp, "model\tmodel_kmer\tlevel_mean\tread_var\n");
+    }
+
+    void write_tsv(FILE* fp, const std::string& model_name, const std::string& kmer) const
+    {
+        fprintf(fp, "%s\t%s\t%.2lf\t%.2lf\n",
+                    model_name.c_str(), 
+                    kmer.c_str(), 
+                    level_mean, 
+                    read_var);
+    }
+
+    //
+    // Data
+    //
+    float level_mean;
+    float read_var;
+};
+
+typedef MinimalStateTrainingData StateTrainingData;
+
+struct StateSummary
+{
+    StateSummary() { num_matches = 0; num_skips = 0; num_stays = 0; }
+    std::vector<StateTrainingData> events;
+
+    int num_matches;
+    int num_skips;
+    int num_stays;
+};
+
+struct GaussianMixture
+{
+    std::vector<float> weights;
+    std::vector<GaussianParameters> params;
+};
+
+//
+Alphabet* mtrain_alphabet = &gMCpGAlphabet;
+
+//
+// Typedefs
+//
+typedef std::map<std::string, std::vector<StateSummary>> ModelTrainingMap;
+
+//
+// Getopt
+//
+#define SUBPROGRAM "methyltrain"
+
+static const char *METHYLTRAIN_VERSION_MESSAGE =
+SUBPROGRAM " Version " PACKAGE_VERSION "\n"
+"Written by Jared Simpson.\n"
+"\n"
+"Copyright 2015 Ontario Institute for Cancer Research\n";
+
+static const char *METHYLTRAIN_USAGE_MESSAGE =
+"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] --reads reads.fa --bam alignments.bam --genome genome.fa\n"
+"Train a methylation model\n"
+"\n"
+"  -v, --verbose                        display verbose output\n"
+"      --version                        display version\n"
+"      --help                           display this help and exit\n"
+"  -m, --models-fofn=FILE               read the models to be trained from the FOFN\n"
+"      --train-unmethylated             train unmethylated 5-mers instead of methylated\n"
+"      --no-update-models               do not write out trained models\n"
+"  -r, --reads=FILE                     the 2D ONT reads are in fasta FILE\n"
+"  -b, --bam=FILE                       the reads aligned to the genome assembly are in bam FILE\n"
+"  -g, --genome=FILE                    the genome we are computing a consensus for is in FILE\n"
+"  -t, --threads=NUM                    use NUM threads (default: 1)\n"
+"  -s, --out-suffix=STR                 name output files like model.out_suffix\n"
+"      --progress                       print out a progress message\n"
+"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";
+
+namespace opt
+{
+    static unsigned int verbose;
+    static std::string reads_file;
+    static std::string bam_file;
+    static std::string genome_file;
+    static std::string models_fofn;
+    static std::string region;
+    static std::string out_suffix = ".methyltrain";
+    static bool write_models = true;
+    static bool train_unmethylated = false;
+    static int progress = 0;
+    static int num_threads = 1;
+    static int batch_size = 128;
+}
+
+static const char* shortopts = "r:b:g:t:m:vn";
+
+enum { OPT_HELP = 1, OPT_VERSION, OPT_PROGRESS, OPT_NO_UPDATE_MODELS, OPT_TRAIN_UNMETHYLATED };
+
+static const struct option longopts[] = {
+    { "verbose",            no_argument,       NULL, 'v' },
+    { "reads",              required_argument, NULL, 'r' },
+    { "bam",                required_argument, NULL, 'b' },
+    { "genome",             required_argument, NULL, 'g' },
+    { "window",             required_argument, NULL, 'w' },
+    { "threads",            required_argument, NULL, 't' },
+    { "models-fofn",        required_argument, NULL, 'm' },
+    { "out-suffix",         required_argument, NULL, 's' },
+    { "no-update-models",   no_argument,       NULL, OPT_NO_UPDATE_MODELS },
+    { "train-unmethylated", no_argument,       NULL, OPT_TRAIN_UNMETHYLATED },
+    { "progress",           no_argument,       NULL, OPT_PROGRESS },
+    { "help",               no_argument,       NULL, OPT_HELP },
+    { "version",            no_argument,       NULL, OPT_VERSION },
+    { NULL, 0, NULL, 0 }
+};
+
+GaussianMixture train_gaussian_mixture(const std::vector<StateTrainingData>& data,
+                                       const GaussianMixture& input_mixture)
+{
+
+    size_t n_components = input_mixture.params.size();
+    size_t n_data = data.size();
+    assert(input_mixture.weights.size() == n_components);
+    GaussianMixture curr_mixture = input_mixture;   
+
+    for(size_t iteration = 0; iteration < 10; ++iteration) {
+        std::vector<double> mean_sum(n_components, 0.0f);
+        std::vector<double> var_sum(n_components, 0.0f);
+        
+        GaussianMixture new_mixture = curr_mixture;
+        for(size_t j = 0; j < n_components; ++j) {
+            new_mixture.weights[j] = 0.0f;
+        }
+
+        std::vector<std::vector<double> > resp;
+
+        for(size_t i = 0; i < n_data; ++i) {
+            // Calculate the posterior probability that
+            // data i came from each component of the mixture
+            
+            // P(data i | component j) P(component j)
+            std::vector<double> t(n_components, 0.0f);
+            double t_sum = -INFINITY;
+            for(size_t j = 0; j < n_components; ++j) {
+                t[j] = log_normal_pdf(data[i].level_mean, curr_mixture.params[j]) + log(curr_mixture.weights[j]);
+                if(t[j] != -INFINITY && ! std::isnan(t[j])) {
+                    t_sum = add_logs(t_sum, t[j]);
+                }
+            }
+
+            // store P(component j | data i)
+            for(size_t j = 0; j < n_components; ++j) {
+                t[j] = exp(t[j] - t_sum);
+                new_mixture.weights[j] += t[j];
+            }
+            resp.push_back(t);
+        }
+        
+        for(size_t j = 0; j < n_components; ++j) {
+            new_mixture.weights[j] /= n_data;
+        }
+
+        // Calculate mean
+        for(size_t i = 0; i < n_data; ++i) {
+            for(size_t j = 0; j < n_components; ++j) {
+                double w_ij = resp[i][j];
+                mean_sum[j] += w_ij * data[i].level_mean;
+            }
+        }
+        
+        std::vector<double> new_mean(2);
+        for(size_t j = 0; j < n_components; ++j) {
+            new_mean[j] = mean_sum[j] / (n_data * new_mixture.weights[j]);
+        }
+
+        // Calculate variance
+        for(size_t i = 0; i < n_data; ++i) {
+            for(size_t j = 0; j < n_components; ++j) {
+                double w_ij = resp[i][j];
+                var_sum[j] += w_ij * pow( (data[i].level_mean - new_mean[j]) / data[i].read_var, 2.0);
+            }
+        }
+        
+        std::vector<double> new_var(2);
+        for(size_t j = 0; j < n_components; ++j) {
+            new_var[j] = var_sum[j] / (n_data * new_mixture.weights[j]);
+        }
+
+        for(size_t j = 0; j < n_components; ++j) {
+            new_mixture.params[j] = GaussianParameters(new_mean[j], sqrt(new_var[j]));
+            //fprintf(stderr, "MIXTURE\t%zu\t%.2lf\t%.2lf\t%.2lf\n", j, curr_mixture.weights[j], curr_mixture.params[j].mean, curr_mixture.params[j].stdv);
+        }
+
+        curr_mixture = new_mixture;
+    }
+    return curr_mixture;
+}
+
+// Realign the read in event space
+void train_read(const ModelMap& model_map,
+                const Fast5Map& name_map, 
+                const faidx_t* fai, 
+                const bam_hdr_t* hdr, 
+                const bam1_t* record, 
+                size_t read_idx,
+                int region_start,
+                int region_end,
+                size_t round,
+                ModelTrainingMap& training)
+{
+    // Load a squiggle read for the mapped read
+    std::string read_name = bam_get_qname(record);
+    std::string fast5_path = name_map.get_path(read_name);
+
+    // load read
+    SquiggleRead sr(read_name, fast5_path);
+
+    for(size_t strand_idx = 0; strand_idx < NUM_STRANDS; ++strand_idx) {
+        
+        // replace model with the training model
+        std::string curr_model = sr.pore_model[strand_idx].name;
+        auto model_iter = model_map.find(curr_model);
+
+        if(model_iter != model_map.end()) {
+            sr.pore_model[strand_idx].update_states(model_iter->second);
+        } else {
+            printf("Error: model %s not found\n", curr_model.c_str());
+            assert(false && "Model not found");
+        }
+        
+        // set k
+        uint32_t k = sr.pore_model[strand_idx].k;
+
+        // Align to the new model
+        EventAlignmentParameters params;
+        params.sr = &sr;
+        params.fai = fai;
+        params.hdr = hdr;
+        params.record = record;
+        params.strand_idx = strand_idx;
+ 
+        params.alphabet = mtrain_alphabet;
+        params.read_idx = read_idx;
+        params.region_start = region_start;
+        params.region_end = region_end;
+        std::vector<EventAlignment> alignment_output = align_read_to_ref(params);
+
+        // Update model observations
+        #pragma omp critical
+        {
+            //emit_event_alignment_tsv(stdout, sr, params, alignment_output);
+
+            // Get the training data for this model
+            auto& emission_map = training[curr_model];
+
+            for(size_t i = 0; i < alignment_output.size(); ++i) {
+                const EventAlignment& ea = alignment_output[i];
+                std::string model_kmer = ea.model_kmer;
+
+                // Grab the previous/next model kmer
+                // If the read is from the same strand as the reference
+                // the next kmer comes from the next alignment_output (and vice-versa)
+                // other the indices are swapped
+                int next_stride = ea.rc ? -1 : 1;
+
+                std::string prev_kmer = "";
+                std::string next_kmer = "";
+
+                if(i > 0 && i < alignment_output.size() - 1) {
+                    assert(alignment_output[i + next_stride].event_idx - ea.event_idx == 1);
+                    assert(alignment_output[i - next_stride].event_idx - ea.event_idx == -1);
+
+                    // check for exactly one base of movement along the reference
+                    if( abs(alignment_output[i + next_stride].ref_position - ea.ref_position) == 1) {
+                        next_kmer = alignment_output[i + next_stride].model_kmer;
+                    }
+
+                    if( abs(alignment_output[i - next_stride].ref_position - ea.ref_position) == 1) {
+                        prev_kmer = alignment_output[i - next_stride].model_kmer;
+                    }
+                }
+
+                uint32_t rank = mtrain_alphabet->kmer_rank(model_kmer.c_str(), k);
+                auto& kmer_summary = emission_map[rank];
+                
+                // Should we use this event for training?
+                bool use_for_training = i > 5 && 
+                                        i + 5 < alignment_output.size() &&
+                                        alignment_output[i].hmm_state == 'M' &&
+                                        prev_kmer != "" &&
+                                        next_kmer != "";
+
+                if(use_for_training) {
+
+                    StateTrainingData std(sr, ea, rank, prev_kmer, next_kmer);
+                    kmer_summary.events.push_back(std);
+                }
+
+                if(ea.hmm_state == 'M')  {
+                    kmer_summary.num_matches += 1;
+                } else if(ea.hmm_state == 'E') {
+                    kmer_summary.num_stays += 1;
+                }
+
+            }
+        }
+    } // for strands
+}
+
+ModelMap read_models_fofn(const std::string& fofn_name)
+{
+    ModelMap out;
+    std::ifstream fofn_reader(fofn_name);
+    std::string model_filename;
+
+    while(getline(fofn_reader, model_filename)) {
+        printf("reading %s\n", model_filename.c_str());
+        PoreModel p(model_filename, *mtrain_alphabet);
+        assert(!p.name.empty());
+
+        out[p.name] = p;
+    }
+    return out;
+}
+
+void parse_methyltrain_options(int argc, char** argv)
+{
+    bool die = false;
+    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
+        std::istringstream arg(optarg != NULL ? optarg : "");
+        switch (c) {
+            case 'r': arg >> opt::reads_file; break;
+            case 'g': arg >> opt::genome_file; break;
+            case 'b': arg >> opt::bam_file; break;
+            case '?': die = true; break;
+            case 't': arg >> opt::num_threads; break;
+            case 'm': arg >> opt::models_fofn; break;
+            case 's': arg >> opt::out_suffix; break;
+            case 'v': opt::verbose++; break;
+            case OPT_TRAIN_UNMETHYLATED: opt::train_unmethylated = true; break;
+            case OPT_NO_UPDATE_MODELS: opt::write_models = false; break;
+            case OPT_PROGRESS: opt::progress = true; break;
+            case OPT_HELP:
+                std::cout << METHYLTRAIN_USAGE_MESSAGE;
+                exit(EXIT_SUCCESS);
+            case OPT_VERSION:
+                std::cout << METHYLTRAIN_VERSION_MESSAGE;
+                exit(EXIT_SUCCESS);
+        }
+    }
+
+    if(argc - optind > 0) {
+        opt::region = argv[optind++];
+    }
+
+    if (argc - optind > 0) {
+        std::cerr << SUBPROGRAM ": too many arguments\n";
+        die = true;
+    }
+
+    if(opt::num_threads <= 0) {
+        std::cerr << SUBPROGRAM ": invalid number of threads: " << opt::num_threads << "\n";
+        die = true;
+    }
+
+    if(opt::reads_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --reads file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::genome_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --genome file must be provided\n";
+        die = true;
+    }
+
+    if(opt::bam_file.empty()) {
+        std::cerr << SUBPROGRAM ": a --bam file must be provided\n";
+        die = true;
+    }
+    
+    if(opt::models_fofn.empty()) {
+        std::cerr << SUBPROGRAM ": a --models-fofn file must be provided\n";
+        die = true;
+    }
+
+    if (die) 
+    {
+        std::cout << "\n" << METHYLTRAIN_USAGE_MESSAGE;
+        exit(EXIT_FAILURE);
+    }
+}
+
+ModelMap train_one_round(const ModelMap& models, const Fast5Map& name_map, size_t round)
+{
+    // Initialize the training summary stats for each kmer for each model
+    ModelTrainingMap model_training_data;
+    for(auto model_iter = models.begin(); model_iter != models.end(); model_iter++) {
+        std::vector<StateSummary> summaries(model_iter->second.get_num_states()); // one per kmer in the model
+        model_training_data[model_iter->first] = summaries;
+    }
+
+    // Open the BAM and iterate over reads
+
+    // load bam file
+    htsFile* bam_fh = sam_open(opt::bam_file.c_str(), "r");
+    assert(bam_fh != NULL);
+
+    // load bam index file
+    std::string index_filename = opt::bam_file + ".bai";
+    hts_idx_t* bam_idx = bam_index_load(index_filename.c_str());
+    assert(bam_idx != NULL);
+
+    // read the bam header
+    bam_hdr_t* hdr = sam_hdr_read(bam_fh);
+    
+    // load reference fai file
+    faidx_t *fai = fai_load(opt::genome_file.c_str());
+
+    hts_itr_t* itr;
+
+    // If processing a region of the genome, only emit events aligned to this window
+    int clip_start = -1;
+    int clip_end = -1;
+
+    if(opt::region.empty()) {
+        // TODO: is this valid?
+        itr = sam_itr_queryi(bam_idx, HTS_IDX_START, 0, 0);
+    } else {
+
+        fprintf(stderr, "Region: %s\n", opt::region.c_str());
+        itr = sam_itr_querys(bam_idx, hdr, opt::region.c_str());
+        hts_parse_reg(opt::region.c_str(), &clip_start, &clip_end);
+    }
+
+#ifndef H5_HAVE_THREADSAFE
+    if(opt::num_threads > 1) {
+        fprintf(stderr, "You enabled multi-threading but you do not have a threadsafe HDF5\n");
+        fprintf(stderr, "Please recompile nanopolish's built-in libhdf5 or run with -t 1\n");
+        exit(1);
+    }
+#endif
+
+    // Initialize iteration
+    std::vector<bam1_t*> records(opt::batch_size, NULL);
+    for(size_t i = 0; i < records.size(); ++i) {
+        records[i] = bam_init1();
+    }
+
+    int result;
+    size_t num_reads_realigned = 0;
+    size_t num_records_buffered = 0;
+    Progress progress("[methyltrain]");
+
+    do {
+        assert(num_records_buffered < records.size());
+        
+        // read a record into the next slot in the buffer
+        result = sam_itr_next(bam_fh, itr, records[num_records_buffered]);
+        num_records_buffered += result >= 0;
+
+        // realign if we've hit the max buffer size or reached the end of file
+        if(num_records_buffered == records.size() || result < 0) {
+            #pragma omp parallel for            
+            for(size_t i = 0; i < num_records_buffered; ++i) {
+                bam1_t* record = records[i];
+                size_t read_idx = num_reads_realigned + i;
+                if( (record->core.flag & BAM_FUNMAP) == 0) {
+                    train_read(models, name_map, fai, hdr, record, read_idx, clip_start, clip_end, round, model_training_data);
+                }
+            }
+
+            num_reads_realigned += num_records_buffered;
+            num_records_buffered = 0;
+        }
+
+        if(opt::progress) {
+            fprintf(stderr, "Realigned %zu reads in %.1lfs\r", num_reads_realigned, progress.get_elapsed_seconds());
+        }
+    } while(result >= 0);
+    
+    assert(num_records_buffered == 0);
+    progress.end();
+
+    std::stringstream training_fn;
+    training_fn << opt::bam_file << ".methyltrain.tsv";
+    
+    std::stringstream summary_fn;
+    summary_fn << opt::bam_file << ".methyltrain.summary";
+
+    FILE* summary_fp = fopen(summary_fn.str().c_str(), "w");
+    FILE* training_fp = fopen(training_fn.str().c_str(), "w");
+
+    // training header
+    StateTrainingData::write_header(training_fp);
+    
+    // Process the training results
+    ModelMap trained_models;
+    
+    for(auto model_training_iter = model_training_data.begin(); 
+             model_training_iter != model_training_data.end(); model_training_iter++) {
+        
+        // Initialize trained model from input model
+        auto model_iter = models.find(model_training_iter->first);
+        assert(model_iter != models.end());
+
+        std::string model_name = model_training_iter->first;
+        std::string model_short_name = "";
+
+        if(model_name == "r7.3_template_median68pA.model") {
+            model_short_name = "t";
+        } else if(model_name == "r7.3_complement_median68pA_pop1.model") {
+            model_short_name = "c.p1";
+        } else if(model_name == "r7.3_complement_median68pA_pop2.model") {
+            model_short_name = "c.p2";
+        } else if(model_name == "r7.3_e6_70bps_6mer_template_median68pA.model") {
+            model_short_name = "t.006";
+        } else if(model_name == "r7.3_e6_70bps_6mer_complement_median68pA_pop1.model") {
+            model_short_name = "c.p1.006";
+        } else if(model_name == "r7.3_e6_70bps_6mer_complement_median68pA_pop2.model") {
+            model_short_name = "c.p2.006";
+        } else {
+            printf("Unknown model: %s\n", model_name.c_str());
+            assert(false);
+        }
+
+        trained_models[model_training_iter->first] = model_iter->second;
+        PoreModel& new_pm = trained_models[model_training_iter->first];
+
+        // Update means for each kmer
+        uint32_t k = new_pm.k;
+        std::string kmer(k, 'A');
+        const std::vector<StateSummary>& summaries = model_training_iter->second;
+        for(size_t ki = 0; ki < summaries.size(); ++ki) {
+
+            // write a training file
+            for(size_t ei = 0; ei < summaries[ki].events.size(); ++ei) {
+                summaries[ki].events[ei].write_tsv(training_fp, model_short_name, kmer);
+            }
+
+            // write to the summary file
+            fprintf(summary_fp, "%s\t%s\t%d\t%d\t%d\n", model_short_name.c_str(), kmer.c_str(), summaries[ki].num_matches, summaries[ki].num_skips, summaries[ki].num_stays);
+
+            GaussianMixture mixture;
+
+            // train a mixture model where a minority of k-mers aren't methylated
+            
+            // unmethylated component
+            double um_rate = 0.05f;
+            std::string um_kmer = gMCpGAlphabet.unmethylate(kmer);
+            size_t um_ki = gMCpGAlphabet.kmer_rank(um_kmer.c_str(), k);
+            GaussianParameters um_params(model_iter->second.get_parameters(um_ki).level_mean, 
+                                           model_iter->second.get_parameters(um_ki).level_stdv);
+
+            mixture.weights.push_back(um_rate);
+            mixture.params.push_back(um_params);
+
+            GaussianParameters m_params(model_iter->second.get_parameters(ki).level_mean, 
+                                           model_iter->second.get_parameters(ki).level_stdv);
+
+            mixture.weights.push_back(1 - um_rate);
+            mixture.params.push_back(m_params);
+ 
+            if(opt::verbose > 1) {
+                           
+                fprintf(stderr, "INIT__MIX %s\t%s\t[%.2lf %.2lf %.2lf]\t[%.2lf %.2lf %.2lf]\n", model_training_iter->first.c_str(), kmer.c_str(), 
+                                                                  mixture.weights[0], mixture.params[0].mean, mixture.params[0].stdv,
+                                                                  mixture.weights[1], mixture.params[1].mean, mixture.params[1].stdv);
+            }
+
+            GaussianMixture trained_mixture = train_gaussian_mixture(summaries[ki].events, mixture);
+            
+            if(opt::verbose > 1) {
+                fprintf(stderr, "TRAIN_MIX %s\t%s\t[%.2lf %.2lf %.2lf]\t[%.2lf %.2lf %.2lf]\n", model_training_iter->first.c_str(), kmer.c_str(), 
+                                                                  trained_mixture.weights[0], trained_mixture.params[0].mean, trained_mixture.params[0].stdv,
+                                                                  trained_mixture.weights[1], trained_mixture.params[1].mean, trained_mixture.params[1].stdv);
+            }
+                
+            bool is_m_kmer = kmer.find('M') != std::string::npos;
+            bool update_kmer = (is_m_kmer == !opt::train_unmethylated); 
+            if(update_kmer && summaries[ki].events.size() > 100) {
+                new_pm.states[ki].level_mean = trained_mixture.params[1].mean;
+                new_pm.states[ki].level_stdv = trained_mixture.params[1].stdv;
+            }
+
+            /*
+            if(kmer.find("CG") != std::string::npos) {
+                float mu_prime = summaries[ki].mean_sum / summaries[ki].n;
+                float var_prime = summaries[ki].var_sum / summaries[ki].n;
+                new_pm[ki].level_mean = mu_prime;
+                new_pm[ki].level_stdv = sqrt(var_prime);
+                fprintf(stderr, "%s %s %.2lf %.2lf\n", model_training_iter->first.c_str(), kmer.c_str(), new_pm[ki].level_mean, new_pm[ki].level_stdv);
+            }
+            */
+            mtrain_alphabet->lexicographic_next(kmer);
+        }
+    }
+
+
+    // cleanup records
+    for(size_t i = 0; i < records.size(); ++i) {
+        bam_destroy1(records[i]);
+    }
+
+    // cleanup
+    sam_itr_destroy(itr);
+    bam_hdr_destroy(hdr);
+    fai_destroy(fai);
+    sam_close(bam_fh);
+    hts_idx_destroy(bam_idx);
+    fclose(training_fp);
+    fclose(summary_fp);
+    return trained_models;
+}
+
+void write_models(ModelMap& models)
+{
+    // Write the model
+    for(auto model_iter = models.begin(); 
+             model_iter != models.end(); model_iter++) {
+
+        assert(!model_iter->second.model_filename.empty());
+        std::string outname   =  model_iter->second.model_filename + opt::out_suffix;
+        std::string modelname =  model_iter->first + (!opt::train_unmethylated ? opt::out_suffix : "");
+        models[model_iter->first].write( outname, *mtrain_alphabet, modelname );
+    }
+}
+
+int methyltrain_main(int argc, char** argv)
+{
+    parse_methyltrain_options(argc, argv);
+    omp_set_num_threads(opt::num_threads);
+
+    Fast5Map name_map(opt::reads_file);
+    ModelMap models = read_models_fofn(opt::models_fofn);
+    
+    static size_t TRAINING_ROUNDS = 10;
+
+    for(size_t round = 0; round < TRAINING_ROUNDS; round++) {
+        fprintf(stderr, "Starting round %zu\n", round);
+        ModelMap trained_models = train_one_round(models, name_map, round);
+        if(opt::write_models) {
+            write_models(trained_models);
+        }
+        models = trained_models;
+    }
+    return EXIT_SUCCESS;
+}
+
diff --git a/src/nanopolish_methyltrain.h b/src/nanopolish_methyltrain.h
new file mode 100644
index 0000000..c57960b
--- /dev/null
+++ b/src/nanopolish_methyltrain.h
@@ -0,0 +1,25 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_methyltrain -- train a methylation model
+//
+#ifndef NANOPOLISH_METHYLTRAIN_H
+#define NANOPOLISH_METHYLTRAIN_H
+
+#include <string>
+#include <map>
+#include "nanopolish_poremodel.h"
+
+//
+// Typedefs
+//
+typedef std::map<std::string, PoreModel> ModelMap;
+
+// read models from a file
+ModelMap read_models_fofn(const std::string& fofn_name);
+
+int methyltrain_main(int argc, char** argv);
+
+#endif
diff --git a/src/nanopolish_poremodel.cpp b/src/nanopolish_poremodel.cpp
new file mode 100644
index 0000000..411795a
--- /dev/null
+++ b/src/nanopolish_poremodel.cpp
@@ -0,0 +1,169 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_poremodel -- Representation of the Oxford
+// Nanopore sequencing model, as described in a FAST5 file
+//
+#include "nanopolish_poremodel.h"
+#include <fstream>
+#include <sstream>
+#include <cstring>
+#include <bits/stl_algo.h>
+#include "../fast5/src/fast5.hpp"
+
+void PoreModel::bake_gaussian_parameters()
+{
+    scaled_params.resize(states.size());
+
+    for(int i = 0; i < states.size(); ++i) {
+
+        // these functions are provided by ONT
+        scaled_params[i].mean = states[i].level_mean * scale + shift;
+        scaled_params[i].stdv = states[i].level_stdv * var;
+        scaled_params[i].log_stdv = log(scaled_params[i].stdv); // pre-computed for efficiency
+
+        // These are not used, for now
+        //scaled_state[i].sd_mean = state[i].sd_mean * scale_sd;
+        //scaled_state[i].sd_stdv = state[i].sd_stdv * sqrt(pow(scale_sd, 3.0) / var_sd);
+    }
+    is_scaled = true;
+}
+
+PoreModel::PoreModel(const std::string filename, const Alphabet& alphabet) 
+{
+    model_filename = filename;
+    std::ifstream model_reader(filename);
+    std::string model_line;
+
+    bool firstKmer = true;
+    int ninserted = 0;
+
+    shift_offset = 0.0f;
+
+    while (getline(model_reader, model_line)) {
+        std::stringstream parser(model_line);
+
+        // Extract the model name from the header
+        if (model_line.find("#model_name") != std::string::npos) {
+            std::string dummy;
+            parser >> dummy >> name;
+        }
+
+        // Extract shift offset from the header
+        // This will be applied to the per-read shift values
+        // to allow switching between models with different averages
+        if (model_line.find("#shift_offset") != std::string::npos) {
+            std::string dummy;
+            parser >> dummy >> shift_offset;
+            printf("found shift offset of %.2lf\n", shift_offset);
+        }
+
+        // skip the rest of the header
+        if (model_line[0] == '#' || model_line.find("kmer") == 0) {
+            continue;
+        }
+
+        std::string kmer;
+        PoreModelStateParams params;
+        parser >> kmer >> params.level_mean >> params.level_stdv >> params.sd_mean >> params.sd_stdv;
+
+        if (firstKmer) {
+            k = kmer.length();
+            states.resize( alphabet.get_num_strings(k) );
+
+            firstKmer = false;
+        }
+
+        states[ alphabet.kmer_rank(kmer.c_str(), k) ] = params;
+        ninserted++;
+    }
+
+    assert( ninserted == states.size() );
+}
+
+PoreModel::PoreModel(fast5::File *f_p, const size_t strand, const Alphabet& alphabet) 
+{
+
+    std::vector<fast5::Model_Entry> model = f_p->get_model(strand);
+    k = (uint32_t) strlen(model[0].kmer);
+    states.resize( alphabet.get_num_strings(k) );
+    assert(states.size() == model.size());
+
+    // Copy into the pore model for this read
+    for(size_t mi = 0; mi < model.size(); ++mi) {
+        const fast5::Model_Entry& curr = model[mi];
+
+        size_t rank = alphabet.kmer_rank(curr.kmer, k);
+        states[rank] = { static_cast<float>(curr.level_mean),
+                         static_cast<float>(curr.level_stdv),
+                         static_cast<float>(curr.sd_mean),
+                         static_cast<float>(curr.sd_stdv) };
+    }
+
+    // Load the scaling parameters for the pore model
+    fast5::Model_Parameters params = f_p->get_model_parameters(strand);
+    drift = params.drift;
+    scale = params.scale;
+    scale_sd = params.scale_sd;
+    shift = params.shift;
+    var = params.var;
+    var_sd = params.var_sd;
+
+    // no offset needed when loading directly from the fast5
+    shift_offset = 0.0f;
+
+    // apply shift/scale transformation to the pore model states
+    bake_gaussian_parameters();
+
+    // Read and shorten the model name
+    std::string temp_name = f_p->get_model_file(strand);
+    std::string leader = "/opt/chimaera/model/";
+
+    size_t lp = temp_name.find(leader);
+    // leader not found
+    if(lp == std::string::npos) {
+        name = temp_name;
+    } else {
+        name = temp_name.substr(leader.size());
+    }
+
+    std::replace(name.begin(), name.end(), '/', '_');
+}
+
+void PoreModel::write(const std::string filename, const Alphabet& alphabet, const std::string modelname) 
+{
+    std::string outmodelname = modelname;
+    if(modelname.empty())
+        outmodelname = name;
+
+    std::ofstream writer(filename);
+    writer << "#model_name\t" << outmodelname << std::endl;
+
+    printf("SHIFT OFFSET: %.lf\n", shift_offset);
+    writer << "#shift_offset\t" << shift_offset << std::endl;
+
+    std::string curr_kmer(k,alphabet.base(0));
+    for(size_t ki = 0; ki < states.size(); ++ki) {
+        writer << curr_kmer << "\t" << states[ki].level_mean << "\t" << states[ki].level_stdv << "\t"
+               << states[ki].sd_mean << "\t" << states[ki].sd_stdv << std::endl;
+        alphabet.lexicographic_next(curr_kmer);
+    }
+    writer.close();
+}
+
+void PoreModel::update_states( const PoreModel &other ) 
+{
+    k = other.k;
+    shift += other.shift_offset;
+    update_states( other.states );
+}
+
+void PoreModel::update_states( const std::vector<PoreModelStateParams> &otherstates ) 
+{
+    states = otherstates;
+    if (is_scaled) {
+        bake_gaussian_parameters();
+    }
+}
diff --git a/src/nanopolish_poremodel.h b/src/nanopolish_poremodel.h
new file mode 100644
index 0000000..d9659f9
--- /dev/null
+++ b/src/nanopolish_poremodel.h
@@ -0,0 +1,93 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_poremodel -- Representation of the Oxford
+// Nanopore sequencing model, as described in a FAST5 file
+//
+#ifndef NANOPOLISH_POREMODEL_H
+#define NANOPOLISH_POREMODEL_H
+
+#include <assert.h>
+#include "nanopolish_common.h"
+#include <inttypes.h>
+#include <string>
+#include "../fast5/src/fast5.hpp"
+
+//
+struct PoreModelStateParams
+{
+    double level_mean;
+    double level_stdv;
+    
+    double sd_mean;
+    double sd_stdv;
+};
+
+//
+class PoreModel
+{
+    public:
+        PoreModel(uint32_t _k=5) : is_scaled(false), k(_k) {}
+
+        // These constructors and the output routine take an alphabet 
+        // so that kmers are inserted/written in order
+        // nicer might be to store the states as a map from kmer -> state
+
+        PoreModel(const std::string filename, const Alphabet& alphabet=gDNAAlphabet);
+        PoreModel(fast5::File *f_p, const size_t strand, const Alphabet& alphabet=gDNAAlphabet);
+
+        void write(const std::string filename, const Alphabet& alphabet, const std::string modelname="");
+
+        inline GaussianParameters get_scaled_parameters(const uint32_t kmer_rank) const
+        {
+            assert(is_scaled);
+            return scaled_params[kmer_rank];
+        }
+
+        inline PoreModelStateParams get_parameters(const uint32_t kmer_rank) const
+        {
+            return states[kmer_rank];
+        }
+        
+        inline size_t get_num_states() const { return states.size(); }
+
+        // Pre-compute the GaussianParameters to avoid
+        // taking numerous logs in the emission calculations
+        void bake_gaussian_parameters();
+
+        // update states with those given, or from another model
+        void update_states( const PoreModel &other );
+        void update_states( const std::vector<PoreModelStateParams> &otherstates );
+
+        //
+        // Data
+        //
+
+        // model metadata
+        std::string model_filename;
+        std::string name;
+        uint32_t k;
+
+        // per-read scaling parameters
+        double scale;
+        double shift;
+        double drift;
+        double var;
+        double scale_sd;
+        double var_sd;
+
+        // to support swapping models, a .model file might contain a shift_offset field
+        // which describes how to change the per-read shift values to match the incoming
+        // model. This field stores this data, which might be 0.
+        double shift_offset;
+
+        //
+        bool is_scaled;
+
+        std::vector<PoreModelStateParams> states;
+        std::vector<GaussianParameters> scaled_params;
+};
+
+#endif
diff --git a/src/nanopolish_squiggle_read.cpp b/src/nanopolish_squiggle_read.cpp
new file mode 100644
index 0000000..91b7cd6
--- /dev/null
+++ b/src/nanopolish_squiggle_read.cpp
@@ -0,0 +1,209 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_squiggle_read -- Class holding a squiggle (event)
+// space nanopore read
+//
+#include <algorithm>
+#include "nanopolish_common.h"
+#include "nanopolish_squiggle_read.h"
+#include "src/fast5.hpp"
+
+//
+SquiggleRead::SquiggleRead(const std::string& name, const std::string& path) :
+    read_name(name),
+    drift_correction_performed(false)
+{
+    load_from_fast5(path);
+
+    // perform drift correction and other scalings
+    transform();
+}
+
+SquiggleRead::~SquiggleRead()
+{
+}
+
+// helper for get_closest_event_to
+int SquiggleRead::get_next_event(int start, int stop, int stride, uint32_t strand) const
+{
+    while(start != stop) {
+        
+        int ei = base_to_event_map[start].indices[strand].start;
+        if(ei != -1)
+            return ei;
+        start += stride;
+    }
+    return -1;
+}
+
+//
+int SquiggleRead::get_closest_event_to(int k_idx, uint32_t strand) const
+{
+    uint32_t k = pore_model[T_IDX].k;
+
+    int stop_before = std::max(0, k_idx - 1000);
+    int stop_after = std::min(k_idx + 1000, (int32_t)read_sequence.size() - (int32_t)k + 1);
+    
+    int event_before = get_next_event(k_idx, stop_before, -1, strand);
+    int event_after = get_next_event(k_idx, stop_after, 1, strand);
+
+    // TODO: better selection of "best" event to return
+    if(event_before == -1)
+        return event_after;
+    return event_before;
+}
+
+//
+void SquiggleRead::transform()
+{
+    for (size_t si = 0; si < 2; ++si) {
+        for(size_t ei = 0; ei < events[si].size(); ++ei) {
+
+            SquiggleEvent& event = events[si][ei];
+
+            // correct level by drift
+            double time = event.start_time - events[si][0].start_time;
+            event.mean -= (time * pore_model[si].drift);
+        }
+    }
+
+    drift_correction_performed = true;
+}
+
+//
+void SquiggleRead::load_from_fast5(const std::string& fast5_path)
+{
+    fast5::File* f_p;
+    this->fast5_path = fast5_path;
+
+    f_p = new fast5::File(fast5_path);
+    assert(f_p->is_open());
+
+    // Check if an alternative analysis group is present in the read name
+    int group_id = -1;
+    size_t bc_2d_pos = read_name.find("Basecall_2D");
+    if(bc_2d_pos != std::string::npos) {
+        int ret = sscanf(read_name.substr(bc_2d_pos).c_str(), "Basecall_2D_%03d_2d", &group_id);
+    } 
+    
+    // default to 0 group
+    if(group_id == -1) {
+        group_id = 0;
+    }
+    
+    f_p->set_basecalled_group_id(group_id);
+
+    // Load PoreModel for both strands
+    for (size_t si = 0; si < 2; ++si) {
+        pore_model[si] = PoreModel( f_p, si );
+
+        // initialize transition parameters
+        parameters[si].initialize(pore_model[si].name);
+    }
+    
+    // Load events for both strands
+    for (size_t si = 0; si < 2; ++si) {
+        std::vector<fast5::Event_Entry> f5_events = f_p->get_events(si);
+        
+        // copy events
+        events[si].resize(f5_events.size());
+        for(size_t ei = 0; ei < f5_events.size(); ++ei) {
+            const fast5::Event_Entry& f5_event = f5_events[ei];
+            events[si][ei] = { static_cast<float>(f5_event.mean), 
+                               static_cast<float>(f5_event.stdv), 
+                               static_cast<float>(f5_event.start), 
+                               static_cast<float>(f5_event.length) }; 
+        }
+    }
+
+    //
+    // Load basecalled sequence
+    //
+    read_sequence = f_p->basecalled_2D();
+    
+    //
+    // Build the map from read k-mers to events
+    //
+    std::vector<fast5::Event_Alignment_Entry> event_alignments = f_p->get_event_alignments();
+    assert(!read_sequence.empty());
+
+    const uint32_t k = pore_model[T_IDX].k;
+    assert(pore_model[C_IDX].k == k);
+
+    uint32_t n_read_kmers = read_sequence.size() - k + 1;
+    base_to_event_map.resize(n_read_kmers);
+
+    uint32_t read_kidx = 0;
+
+    // The alignment format in the fast5 file is slightly bizarre in that it is
+    // (template_idx, complement_idx, kmer) tuples. Some read kmers may not have a
+    // tuple and some might have multiple tuples. We need to use the read kmer
+    // sequences to work out which read base each entry is referring to
+    uint32_t start_ea_idx = 0;
+    uint32_t end_ea_idx = 0;
+
+    while(start_ea_idx < event_alignments.size()) {
+
+hack:
+        uint32_t prev_kidx = read_kidx;
+
+        // Advance the kmer index until we have found the read kmer
+        // this tuple refers to
+        while(read_kidx < n_read_kmers && 
+              strncmp(event_alignments[start_ea_idx].kmer, 
+                     read_sequence.c_str() + read_kidx, k) != 0) {
+            read_kidx += 1;
+        }
+
+        // In the most recent version of metrichor occasionally
+        // a kmer will be present in the alignment table
+        // that is not in the 2D read. This awful hack
+        // will skip such k-mers. It is not a long-term
+        // solution, only until metrichor is fixed.
+        if(read_kidx - prev_kidx > 10) {
+            start_ea_idx += 1;
+            read_kidx = prev_kidx;
+            goto hack;
+        }
+
+        // Advance the event alignment end index to the last tuple
+        // with the same kmer as the start of this range
+        end_ea_idx = start_ea_idx;
+        while(end_ea_idx < event_alignments.size() &&
+                strcmp(event_alignments[start_ea_idx].kmer,
+                    event_alignments[end_ea_idx].kmer) == 0) {
+            end_ea_idx += 1;
+        }
+
+        //printf("Base-to-event map kidx: %d %s event_tuple [%d %d]\n", read_kidx, read_sequence.substr(read_kidx, k).c_str(), start_ea_idx, end_ea_idx);
+        EventRangeForBase& erfb =  base_to_event_map[read_kidx];
+        for(uint32_t i = start_ea_idx; i < end_ea_idx; ++i) {
+
+            fast5::Event_Alignment_Entry& eae = event_alignments[i];
+            
+            for(uint32_t si = 0; si <= 1; ++si) {
+                uint32_t incoming_idx = si == 0 ? eae.template_index : eae.complement_index;
+                
+                // no event for this strand, nothing to update
+                if(incoming_idx == -1)
+                    continue;
+
+                if(erfb.indices[si].start == -1) {
+                    erfb.indices[si].start = incoming_idx;        
+                }
+                erfb.indices[si].stop = incoming_idx;
+
+                assert(erfb.indices[si].start < events[si].size());
+                assert(erfb.indices[si].stop < events[si].size());
+            }
+        }
+        //printf("\t[%d %d] [%d %d]\n", erfb.indices[0].start, erfb.indices[0].stop, erfb.indices[1].start, erfb.indices[1].stop);
+        start_ea_idx = end_ea_idx;
+    }
+
+    delete f_p;
+}
+
diff --git a/src/nanopolish_squiggle_read.h b/src/nanopolish_squiggle_read.h
new file mode 100644
index 0000000..9bde393
--- /dev/null
+++ b/src/nanopolish_squiggle_read.h
@@ -0,0 +1,133 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_squiggle_read -- Class holding a squiggle (event)
+// space nanopore read
+//
+#ifndef NANOPOLISH_SQUIGGLE_READ_H
+#define NANOPOLISH_SQUIGGLE_READ_H
+
+#include "nanopolish_common.h"
+#include "nanopolish_poremodel.h"
+#include "nanopolish_transition_parameters.h"
+#include <string>
+
+// The raw event data for a read
+struct SquiggleEvent
+{
+    float mean;       // current level mean in picoamps
+    float stdv;       // current level stdv
+    float start_time; // start time of the event in seconds
+    float duration;     // duration of the event in seconds
+};
+
+struct IndexPair
+{
+    IndexPair() : start(-1), stop(-1) {}
+    int32_t start;
+    int32_t stop; // inclusive
+};
+
+// This struct maps from base-space k-mers to the range of template/complement
+// events used to call it. 
+struct EventRangeForBase
+{
+    IndexPair indices[2]; // one per strand
+};
+
+//
+class SquiggleRead
+{
+    public:
+
+        SquiggleRead() : drift_correction_performed(false) {} // legacy TODO remove
+        SquiggleRead(const std::string& name, const std::string& path);
+        ~SquiggleRead();
+
+        //
+        // I/O
+        // 
+
+        // Load all the read data from a fast5 file
+        void load_from_fast5(const std::string& fast5_path);
+
+        //
+        // Access to data
+        //
+
+        // Return the duration of the specified event for one strand
+        inline float get_duration(uint32_t event_idx, uint32_t strand) const
+        {
+            assert(event_idx < events[strand].size());
+            return events[strand][event_idx].duration;
+        }
+
+
+        // Return the observed current level after correcting for drift
+        inline float get_drift_corrected_level(uint32_t event_idx, uint32_t strand) const
+        {
+            assert(drift_correction_performed);
+            return events[strand][event_idx].mean;
+        }
+        
+        // Return the observed current level after correcting for drift
+        inline float get_event_stdv(uint32_t event_idx, uint32_t strand) const
+        {
+            return events[strand][event_idx].stdv;
+        }
+
+        // Return the observed current level after correcting for drift, shift and scale
+        inline float get_fully_scaled_level(uint32_t event_idx, uint32_t strand) const
+        {
+            assert(drift_correction_performed);
+            float level = get_drift_corrected_level(event_idx, strand);
+            return (level - pore_model[strand].shift) / pore_model[strand].scale;
+        }
+        
+        // Calculate the index of this k-mer on the other strand
+        inline int32_t flip_k_strand(int32_t k_idx) const
+        {
+            assert(!read_sequence.empty());
+            return read_sequence.size() - k_idx - pore_model[T_IDX].k;
+        }
+
+        // Transform each event by correcting for current drift
+        void transform();
+
+        // get the index of the event tht is nearest to the given kmer 
+        int get_closest_event_to(int k_idx, uint32_t strand) const;
+
+        //
+        // Data
+        //
+
+        // unique identifier of the read
+        std::string read_name;
+        std::string fast5_path;
+        uint32_t read_id;
+        std::string read_sequence;
+        bool drift_correction_performed;
+
+        // one model for each strand
+        PoreModel pore_model[2];
+
+        // one event sequence for each strand
+        std::vector<SquiggleEvent> events[2];
+
+        //
+        std::vector<EventRangeForBase> base_to_event_map;
+
+        // one set of parameters per strand
+        TransitionParameters parameters[2];
+
+    private:
+        
+        SquiggleRead(const SquiggleRead& other) {}
+
+        // helper for get_closest_event_to
+        int get_next_event(int start, int stop, int stride, uint32_t strand) const;
+};
+
+#endif
diff --git a/src/test/catch.hpp b/src/test/catch.hpp
new file mode 100644
index 0000000..391c7ab
--- /dev/null
+++ b/src/test/catch.hpp
@@ -0,0 +1,9460 @@
+/*
+ *  CATCH v1.1 build 3 (master branch)
+ *  Generated: 2015-05-21 06:16:00.388118
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+#ifdef __clang__
+#    pragma clang system_header
+#elif defined __GNUC__
+#    pragma GCC system_header
+#endif
+
+// #included from: internal/catch_suppress_warnings.h
+
+#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#   ifdef __ICC // icpc defines the __clang__ macro
+#       pragma warning(push)
+#       pragma warning(disable: 161 1682)
+#   else // __ICC
+#       pragma clang diagnostic ignored "-Wglobal-constructors"
+#       pragma clang diagnostic ignored "-Wvariadic-macros"
+#       pragma clang diagnostic ignored "-Wc99-extensions"
+#       pragma clang diagnostic ignored "-Wunused-variable"
+#       pragma clang diagnostic push
+#       pragma clang diagnostic ignored "-Wpadded"
+#       pragma clang diagnostic ignored "-Wc++98-compat"
+#       pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#       pragma clang diagnostic ignored "-Wswitch-enum"
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic ignored "-Wvariadic-macros"
+#    pragma GCC diagnostic ignored "-Wunused-variable"
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wpadded"
+#endif
+
+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
+#  define CATCH_IMPL
+#endif
+
+#ifdef CATCH_IMPL
+#  ifndef CLARA_CONFIG_MAIN
+#    define CLARA_CONFIG_MAIN_NOT_DEFINED
+#    define CLARA_CONFIG_MAIN
+#  endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+
+#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
+#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
+
+#include <sstream>
+#include <stdexcept>
+#include <algorithm>
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
+// The following features are defined:
+//
+// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported?
+// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
+// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
+// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported?
+// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported
+
+// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
+
+// CATCH_CONFIG_SFINAE : is basic (C++03) SFINAE supported?
+// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
+
+// A lot of this code is based on Boost (1.53)
+
+#ifdef __clang__
+
+#  if __has_feature(cxx_nullptr)
+#    define CATCH_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  if __has_feature(cxx_noexcept)
+#    define CATCH_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#if (__BORLANDC__ > 0x582 )
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#if (__EDG_VERSION__ > 238 )
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#if (__DMC__ > 0x840 )
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ < 3
+
+#if (__GNUC_MINOR__ >= 96 )
+//#define CATCH_CONFIG_SFINAE
+#endif
+
+#elif __GNUC__ >= 3
+
+// #define CATCH_CONFIG_SFINAE // Taking this out completely for now
+
+#endif // __GNUC__ < 3
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
+
+#define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#if (_MSC_VER >= 1600)
+#define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+
+#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
+#define CATCH_CONFIG_CPP11_NOEXCEPT
+#define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#endif
+
+#endif // _MSC_VER
+
+// Use variadic macros if the compiler supports them
+#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+    ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
+    ( defined __GNUC__ && __GNUC__ >= 3 ) || \
+    ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
+
+#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
+#define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// catch all support for C++11
+#if (__cplusplus >= 201103L)
+
+#  define CATCH_CPP11_OR_GREATER
+
+#  ifndef CATCH_CONFIG_CPP11_NULLPTR
+#    define CATCH_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  ifndef CATCH_CONFIG_CPP11_NOEXCEPT
+#    define CATCH_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#  ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+#    define CATCH_CONFIG_CPP11_GENERATED_METHODS
+#  endif
+
+#  ifndef CATCH_CONFIG_CPP11_IS_ENUM
+#    define CATCH_CONFIG_CPP11_IS_ENUM
+#  endif
+
+#  ifndef CATCH_CONFIG_CPP11_TUPLE
+#    define CATCH_CONFIG_CPP11_TUPLE
+#  endif
+
+#  ifndef CATCH_CONFIG_SFINAE
+//#    define CATCH_CONFIG_SFINAE // Don't use, for now
+#  endif
+
+#  ifndef CATCH_CONFIG_VARIADIC_MACROS
+#    define CATCH_CONFIG_VARIADIC_MACROS
+#  endif
+
+#endif // __cplusplus >= 201103L
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#  define CATCH_NOEXCEPT noexcept
+#  define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#  define CATCH_NOEXCEPT throw()
+#  define CATCH_NOEXCEPT_IS(x)
+#endif
+
+namespace Catch {
+
+    class NonCopyable {
+#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        NonCopyable( NonCopyable const& )              = delete;
+        NonCopyable( NonCopyable && )                  = delete;
+        NonCopyable& operator = ( NonCopyable const& ) = delete;
+        NonCopyable& operator = ( NonCopyable && )     = delete;
+#else
+        NonCopyable( NonCopyable const& info );
+        NonCopyable& operator = ( NonCopyable const& );
+#endif
+
+    protected:
+        NonCopyable() {}
+        virtual ~NonCopyable();
+    };
+
+    class SafeBool {
+    public:
+        typedef void (SafeBool::*type)() const;
+
+        static type makeSafe( bool value ) {
+            return value ? &SafeBool::trueValue : 0;
+        }
+    private:
+        void trueValue() const {}
+    };
+
+    template<typename ContainerT>
+    inline void deleteAll( ContainerT& container ) {
+        typename ContainerT::const_iterator it = container.begin();
+        typename ContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete *it;
+    }
+    template<typename AssociativeContainerT>
+    inline void deleteAllValues( AssociativeContainerT& container ) {
+        typename AssociativeContainerT::const_iterator it = container.begin();
+        typename AssociativeContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete it->second;
+    }
+
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    std::string trim( std::string const& str );
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
+
+    struct pluralise {
+        pluralise( std::size_t count, std::string const& label );
+
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+        std::size_t m_count;
+        std::string m_label;
+    };
+
+    struct SourceLineInfo {
+
+        SourceLineInfo();
+        SourceLineInfo( char const* _file, std::size_t _line );
+        SourceLineInfo( SourceLineInfo const& other );
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SourceLineInfo( SourceLineInfo && )                  = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
+#  endif
+        bool empty() const;
+        bool operator == ( SourceLineInfo const& other ) const;
+        bool operator < ( SourceLineInfo const& other ) const;
+
+        std::string file;
+        std::size_t line;
+    };
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+    // This is just here to avoid compiler warnings with macro constants and boolean literals
+    inline bool isTrue( bool value ){ return value; }
+    inline bool alwaysTrue() { return true; }
+    inline bool alwaysFalse() { return false; }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
+
+    // Use this in variadic streaming macros to allow
+    //    >> +StreamEndStop
+    // as well as
+    //    >> stuff +StreamEndStop
+    struct StreamEndStop {
+        std::string operator+() {
+            return std::string();
+        }
+    };
+    template<typename T>
+    T const& operator + ( T const& value, StreamEndStop ) {
+        return value;
+    }
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
+
+#include <ostream>
+
+namespace Catch {
+
+    class NotImplementedException : public std::exception
+    {
+    public:
+        NotImplementedException( SourceLineInfo const& lineInfo );
+        NotImplementedException( NotImplementedException const& ) {}
+
+        virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+        virtual const char* what() const CATCH_NOEXCEPT;
+
+    private:
+        std::string m_what;
+        SourceLineInfo m_lineInfo;
+    };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct IGeneratorInfo {
+        virtual ~IGeneratorInfo();
+        virtual bool moveNext() = 0;
+        virtual std::size_t getCurrentIndex() const = 0;
+    };
+
+    struct IGeneratorsForTest {
+        virtual ~IGeneratorsForTest();
+
+        virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
+        virtual bool moveNext() = 0;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    // An intrusive reference counting smart pointer.
+    // T must implement addRef() and release() methods
+    // typically implementing the IShared interface
+    template<typename T>
+    class Ptr {
+    public:
+        Ptr() : m_p( NULL ){}
+        Ptr( T* p ) : m_p( p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        Ptr( Ptr const& other ) : m_p( other.m_p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        ~Ptr(){
+            if( m_p )
+                m_p->release();
+        }
+        void reset() {
+            if( m_p )
+                m_p->release();
+            m_p = NULL;
+        }
+        Ptr& operator = ( T* p ){
+            Ptr temp( p );
+            swap( temp );
+            return *this;
+        }
+        Ptr& operator = ( Ptr const& other ){
+            Ptr temp( other );
+            swap( temp );
+            return *this;
+        }
+        void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
+        T* get() { return m_p; }
+        const T* get() const{ return m_p; }
+        T& operator*() const { return *m_p; }
+        T* operator->() const { return m_p; }
+        bool operator !() const { return m_p == NULL; }
+        operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
+
+    private:
+        T* m_p;
+    };
+
+    struct IShared : NonCopyable {
+        virtual ~IShared();
+        virtual void addRef() const = 0;
+        virtual void release() const = 0;
+    };
+
+    template<typename T = IShared>
+    struct SharedImpl : T {
+
+        SharedImpl() : m_rc( 0 ){}
+
+        virtual void addRef() const {
+            ++m_rc;
+        }
+        virtual void release() const {
+            if( --m_rc == 0 )
+                delete this;
+        }
+
+        mutable unsigned int m_rc;
+    };
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <memory>
+#include <vector>
+#include <stdlib.h>
+
+namespace Catch {
+
+    class TestCase;
+    class Stream;
+    struct IResultCapture;
+    struct IRunner;
+    struct IGeneratorsForTest;
+    struct IConfig;
+
+    struct IContext
+    {
+        virtual ~IContext();
+
+        virtual IResultCapture* getResultCapture() = 0;
+        virtual IRunner* getRunner() = 0;
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
+        virtual bool advanceGeneratorsForCurrentTest() = 0;
+        virtual Ptr<IConfig const> getConfig() const = 0;
+    };
+
+    struct IMutableContext : IContext
+    {
+        virtual ~IMutableContext();
+        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+        virtual void setRunner( IRunner* runner ) = 0;
+        virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
+    };
+
+    IContext& getCurrentContext();
+    IMutableContext& getCurrentMutableContext();
+    void cleanUpContext();
+    Stream createStream( std::string const& streamName );
+
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec;
+
+    struct ITestCase : IShared {
+        virtual void invoke () const = 0;
+    protected:
+        virtual ~ITestCase();
+    };
+
+    class TestCase;
+    struct IConfig;
+
+    struct ITestCaseRegistry {
+        virtual ~ITestCaseRegistry();
+        virtual std::vector<TestCase> const& getAllTests() const = 0;
+        virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const = 0;
+
+    };
+}
+
+namespace Catch {
+
+template<typename C>
+class MethodTestCase : public SharedImpl<ITestCase> {
+
+public:
+    MethodTestCase( void (C::*method)() ) : m_method( method ) {}
+
+    virtual void invoke() const {
+        C obj;
+        (obj.*m_method)();
+    }
+
+private:
+    virtual ~MethodTestCase() {}
+
+    void (C::*m_method)();
+};
+
+typedef void(*TestFunction)();
+
+struct NameAndDesc {
+    NameAndDesc( const char* _name = "", const char* _description= "" )
+    : name( _name ), description( _description )
+    {}
+
+    const char* name;
+    const char* description;
+};
+
+struct AutoReg {
+
+    AutoReg(    TestFunction function,
+                SourceLineInfo const& lineInfo,
+                NameAndDesc const& nameAndDesc );
+
+    template<typename C>
+    AutoReg(    void (C::*method)(),
+                char const* className,
+                NameAndDesc const& nameAndDesc,
+                SourceLineInfo const& lineInfo ) {
+        registerTestCase(   new MethodTestCase<C>( method ),
+                            className,
+                            nameAndDesc,
+                            lineInfo );
+    }
+
+    void registerTestCase(  ITestCase* testCase,
+                            char const* className,
+                            NameAndDesc const& nameAndDesc,
+                            SourceLineInfo const& lineInfo );
+
+    ~AutoReg();
+
+private:
+    AutoReg( AutoReg const& );
+    void operator= ( AutoReg const& );
+};
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE( ... ) \
+        static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
+        static void INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ )()
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
+        namespace{ \
+            struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
+        } \
+        void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
+
+#else
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
+        static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+        static void INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ )()
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
+        namespace{ \
+            struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
+        } \
+        void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
+
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+    // ResultWas::OfType enum
+    struct ResultWas { enum OfType {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2,
+
+        FatalErrorCondition = 0x200 | FailureBit
+
+    }; };
+
+    inline bool isOk( ResultWas::OfType resultType ) {
+        return ( resultType & ResultWas::FailureBit ) == 0;
+    }
+    inline bool isJustInfo( int flags ) {
+        return flags == ResultWas::Info;
+    }
+
+    // ResultDisposition::Flags enum
+    struct ResultDisposition { enum Flags {
+        Normal = 0x01,
+
+        ContinueOnFailure = 0x02,   // Failures fail test, but execution continues
+        FalseTest = 0x04,           // Prefix expression with !
+        SuppressFail = 0x08         // Failures are reported but do not fail the test
+    }; };
+
+    inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+    }
+
+    inline bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+    inline bool isFalseTest( int flags )                { return ( flags & ResultDisposition::FalseTest ) != 0; }
+    inline bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct AssertionInfo
+    {
+        AssertionInfo() {}
+        AssertionInfo(  std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        std::string const& _capturedExpression,
+                        ResultDisposition::Flags _resultDisposition );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        std::string capturedExpression;
+        ResultDisposition::Flags resultDisposition;
+    };
+
+    struct AssertionResultData
+    {
+        AssertionResultData() : resultType( ResultWas::Unknown ) {}
+
+        std::string reconstructedExpression;
+        std::string message;
+        ResultWas::OfType resultType;
+    };
+
+    class AssertionResult {
+    public:
+        AssertionResult();
+        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+        ~AssertionResult();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+         AssertionResult( AssertionResult const& )              = default;
+         AssertionResult( AssertionResult && )                  = default;
+         AssertionResult& operator = ( AssertionResult const& ) = default;
+         AssertionResult& operator = ( AssertionResult && )     = default;
+#  endif
+
+        bool isOk() const;
+        bool succeeded() const;
+        ResultWas::OfType getResultType() const;
+        bool hasExpression() const;
+        bool hasMessage() const;
+        std::string getExpression() const;
+        std::string getExpressionInMacro() const;
+        bool hasExpandedExpression() const;
+        std::string getExpandedExpression() const;
+        std::string getMessage() const;
+        SourceLineInfo getSourceInfo() const;
+        std::string getTestMacroName() const;
+
+    protected:
+        AssertionInfo m_info;
+        AssertionResultData m_resultData;
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct TestFailureException{};
+
+    template<typename T> class ExpressionLhs;
+
+    struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+    struct CopyableStream {
+        CopyableStream() {}
+        CopyableStream( CopyableStream const& other ) {
+            oss << other.oss.str();
+        }
+        CopyableStream& operator=( CopyableStream const& other ) {
+            oss.str("");
+            oss << other.oss.str();
+            return *this;
+        }
+        std::ostringstream oss;
+    };
+
+    class ResultBuilder {
+    public:
+        ResultBuilder(  char const* macroName,
+                        SourceLineInfo const& lineInfo,
+                        char const* capturedExpression,
+                        ResultDisposition::Flags resultDisposition );
+
+        template<typename T>
+        ExpressionLhs<T const&> operator->* ( T const& operand );
+        ExpressionLhs<bool> operator->* ( bool value );
+
+        template<typename T>
+        ResultBuilder& operator << ( T const& value ) {
+            m_stream.oss << value;
+            return *this;
+        }
+
+        template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
+        template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
+
+        ResultBuilder& setResultType( ResultWas::OfType result );
+        ResultBuilder& setResultType( bool result );
+        ResultBuilder& setLhs( std::string const& lhs );
+        ResultBuilder& setRhs( std::string const& rhs );
+        ResultBuilder& setOp( std::string const& op );
+
+        void endExpression();
+
+        std::string reconstructExpression() const;
+        AssertionResult build() const;
+
+        void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
+        void captureResult( ResultWas::OfType resultType );
+        void captureExpression();
+        void react();
+        bool shouldDebugBreak() const;
+        bool allowThrows() const;
+
+    private:
+        AssertionInfo m_assertionInfo;
+        AssertionResultData m_data;
+        struct ExprComponents {
+            ExprComponents() : testFalse( false ) {}
+            bool testFalse;
+            std::string lhs, rhs, op;
+        } m_exprComponents;
+        CopyableStream m_stream;
+
+        bool m_shouldDebugBreak;
+        bool m_shouldThrow;
+    };
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+    enum Operator {
+        IsEqualTo,
+        IsNotEqualTo,
+        IsLessThan,
+        IsGreaterThan,
+        IsLessThanOrEqualTo,
+        IsGreaterThanOrEqualTo
+    };
+
+    template<Operator Op> struct OperatorTraits             { static const char* getName(){ return "*error*"; } };
+    template<> struct OperatorTraits<IsEqualTo>             { static const char* getName(){ return "=="; } };
+    template<> struct OperatorTraits<IsNotEqualTo>          { static const char* getName(){ return "!="; } };
+    template<> struct OperatorTraits<IsLessThan>            { static const char* getName(){ return "<"; } };
+    template<> struct OperatorTraits<IsGreaterThan>         { static const char* getName(){ return ">"; } };
+    template<> struct OperatorTraits<IsLessThanOrEqualTo>   { static const char* getName(){ return "<="; } };
+    template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
+
+    template<typename T>
+    inline T& opCast(T const& t) { return const_cast<T&>(t); }
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+    // So the compare overloads can be operator agnostic we convey the operator as a template
+    // enum, which is used to specialise an Evaluator for doing the comparison.
+    template<typename T1, typename T2, Operator Op>
+    class Evaluator{};
+
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs) {
+            return opCast( lhs ) ==  opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsNotEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) != opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) < opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) > opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) >= opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) <= opCast( rhs );
+        }
+    };
+
+    template<Operator Op, typename T1, typename T2>
+    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // This level of indirection allows us to specialise for integer types
+    // to avoid signed/ unsigned warnings
+
+    // "base" overload
+    template<Operator Op, typename T1, typename T2>
+    bool compare( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // unsigned X to int
+    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+
+    // unsigned X to long
+    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+
+    // int to unsigned X
+    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+
+    // long to unsigned X
+    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // pointer to long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+    // pointer to int (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    // pointer to nullptr_t (when comparing against nullptr)
+    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
+    }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+// #included from: catch_sfinae.hpp
+#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
+
+// Try to detect if the current compiler supports SFINAE
+
+namespace Catch {
+
+    struct TrueType {
+        static const bool value = true;
+        typedef void Enable;
+        char sizer[1];
+    };
+    struct FalseType {
+        static const bool value = false;
+        typedef void Disable;
+        char sizer[2];
+    };
+
+#ifdef CATCH_CONFIG_SFINAE
+
+    template<bool> struct NotABooleanExpression;
+
+    template<bool c> struct If : NotABooleanExpression<c> {};
+    template<> struct If<true> : TrueType {};
+    template<> struct If<false> : FalseType {};
+
+    template<int size> struct SizedIf;
+    template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
+    template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
+
+#endif // CATCH_CONFIG_SFINAE
+
+} // end namespace Catch
+
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <vector>
+#include <cstddef>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+    [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+#include <tuple>
+#endif
+
+#ifdef CATCH_CONFIG_CPP11_IS_ENUM
+#include <type_traits>
+#endif
+
+namespace Catch {
+
+// Why we're here.
+template<typename T>
+std::string toString( T const& value );
+
+// Built in overloads
+
+std::string toString( std::string const& value );
+std::string toString( std::wstring const& value );
+std::string toString( const char* const value );
+std::string toString( char* const value );
+std::string toString( const wchar_t* const value );
+std::string toString( wchar_t* const value );
+std::string toString( int value );
+std::string toString( unsigned long value );
+std::string toString( unsigned int value );
+std::string toString( const double value );
+std::string toString( const float value );
+std::string toString( bool value );
+std::string toString( char value );
+std::string toString( signed char value );
+std::string toString( unsigned char value );
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t );
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring );
+    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
+    std::string toString( NSObject* const& nsObject );
+#endif
+
+namespace Detail {
+
+    extern std::string unprintableString;
+
+// SFINAE is currently disabled by default for all compilers.
+// If the non SFINAE version of IsStreamInsertable is ambiguous for you
+// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
+#ifdef CATCH_CONFIG_SFINAE
+
+    template<typename T>
+    class IsStreamInsertableHelper {
+        template<int N> struct TrueIfSizeable : TrueType {};
+
+        template<typename T2>
+        static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
+        static FalseType dummy(...);
+
+    public:
+        typedef SizedIf<sizeof(dummy((T*)0))> type;
+    };
+
+    template<typename T>
+    struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
+
+#else
+
+    struct BorgType {
+        template<typename T> BorgType( T const& );
+    };
+
+    TrueType& testStreamable( std::ostream& );
+    FalseType testStreamable( FalseType );
+
+    FalseType operator<<( std::ostream const&, BorgType const& );
+
+    template<typename T>
+    struct IsStreamInsertable {
+        static std::ostream &s;
+        static T  const&t;
+        enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
+    };
+
+#endif
+
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+    template<typename T,
+             bool IsEnum = std::is_enum<T>::value
+             >
+    struct EnumStringMaker
+    {
+        static std::string convert( T const& ) { return unprintableString; }
+    };
+
+    template<typename T>
+    struct EnumStringMaker<T,true>
+    {
+        static std::string convert( T const& v )
+        {
+            return ::Catch::toString(
+                static_cast<typename std::underlying_type<T>::type>(v)
+                );
+        }
+    };
+#endif
+    template<bool C>
+    struct StringMakerBase {
+#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
+        template<typename T>
+        static std::string convert( T const& v )
+        {
+            return EnumStringMaker<T>::convert( v );
+        }
+#else
+        template<typename T>
+        static std::string convert( T const& ) { return unprintableString; }
+#endif
+    };
+
+    template<>
+    struct StringMakerBase<true> {
+        template<typename T>
+        static std::string convert( T const& _value ) {
+            std::ostringstream oss;
+            oss << _value;
+            return oss.str();
+        }
+    };
+
+    std::string rawMemoryToString( const void *object, std::size_t size );
+
+    template<typename T>
+    inline std::string rawMemoryToString( const T& object ) {
+      return rawMemoryToString( &object, sizeof(object) );
+    }
+
+} // end namespace Detail
+
+template<typename T>
+struct StringMaker :
+    Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
+
+template<typename T>
+struct StringMaker<T*> {
+    template<typename U>
+    static std::string convert( U* p ) {
+        if( !p )
+            return INTERNAL_CATCH_STRINGIFY( NULL );
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+template<typename R, typename C>
+struct StringMaker<R C::*> {
+    static std::string convert( R C::* p ) {
+        if( !p )
+            return INTERNAL_CATCH_STRINGIFY( NULL );
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last );
+}
+
+//template<typename T, typename Allocator>
+//struct StringMaker<std::vector<T, Allocator> > {
+//    static std::string convert( std::vector<T,Allocator> const& v ) {
+//        return Detail::rangeToString( v.begin(), v.end() );
+//    }
+//};
+
+template<typename T, typename Allocator>
+std::string toString( std::vector<T,Allocator> const& v ) {
+    return Detail::rangeToString( v.begin(), v.end() );
+}
+
+#ifdef CATCH_CONFIG_CPP11_TUPLE
+
+// toString for tuples
+namespace TupleDetail {
+  template<
+      typename Tuple,
+      std::size_t N = 0,
+      bool = (N < std::tuple_size<Tuple>::value)
+      >
+  struct ElementPrinter {
+      static void print( const Tuple& tuple, std::ostream& os )
+      {
+          os << ( N ? ", " : " " )
+             << Catch::toString(std::get<N>(tuple));
+          ElementPrinter<Tuple,N+1>::print(tuple,os);
+      }
+  };
+
+  template<
+      typename Tuple,
+      std::size_t N
+      >
+  struct ElementPrinter<Tuple,N,false> {
+      static void print( const Tuple&, std::ostream& ) {}
+  };
+
+}
+
+template<typename ...Types>
+struct StringMaker<std::tuple<Types...>> {
+
+    static std::string convert( const std::tuple<Types...>& tuple )
+    {
+        std::ostringstream os;
+        os << '{';
+        TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os );
+        os << " }";
+        return os.str();
+    }
+};
+#endif // CATCH_CONFIG_CPP11_TUPLE
+
+namespace Detail {
+    template<typename T>
+    std::string makeString( T const& value ) {
+        return StringMaker<T>::convert( value );
+    }
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template<typename T>
+std::string toString( T const& value ) {
+    return StringMaker<T>::convert( value );
+}
+
+    namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last ) {
+        std::ostringstream oss;
+        oss << "{ ";
+        if( first != last ) {
+            oss << Catch::toString( *first );
+            for( ++first ; first != last ; ++first )
+                oss << ", " << Catch::toString( *first );
+        }
+        oss << " }";
+        return oss.str();
+    }
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+// Wraps the LHS of an expression and captures the operator and RHS (if any) -
+// wrapping them all in a ResultBuilder object
+template<typename T>
+class ExpressionLhs {
+    ExpressionLhs& operator = ( ExpressionLhs const& );
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
+#  endif
+
+public:
+    ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+    ExpressionLhs( ExpressionLhs const& ) = default;
+    ExpressionLhs( ExpressionLhs && )     = default;
+#  endif
+
+    template<typename RhsT>
+    ResultBuilder& operator == ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator != ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator < ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThan>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator > ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThan>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator <= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator >= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
+    }
+
+    ResultBuilder& operator == ( bool rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    ResultBuilder& operator != ( bool rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    void endExpression() {
+        bool value = m_lhs ? true : false;
+        m_rb
+            .setLhs( Catch::toString( value ) )
+            .setResultType( value )
+            .endExpression();
+    }
+
+    // Only simple binary expressions are allowed on the LHS.
+    // If more complex compositions are required then place the sub expression in parentheses
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
+
+private:
+    template<Internal::Operator Op, typename RhsT>
+    ResultBuilder& captureExpression( RhsT const& rhs ) {
+        return m_rb
+            .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
+            .setLhs( Catch::toString( m_lhs ) )
+            .setRhs( Catch::toString( rhs ) )
+            .setOp( Internal::OperatorTraits<Op>::getName() );
+    }
+
+private:
+    ResultBuilder& m_rb;
+    T m_lhs;
+};
+
+} // end namespace Catch
+
+
+namespace Catch {
+
+    template<typename T>
+    inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) {
+        return ExpressionLhs<T const&>( *this, operand );
+    }
+
+    inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) {
+        return ExpressionLhs<bool>( *this, value );
+    }
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct MessageInfo {
+        MessageInfo(    std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        ResultWas::OfType _type );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        ResultWas::OfType type;
+        std::string message;
+        unsigned int sequence;
+
+        bool operator == ( MessageInfo const& other ) const {
+            return sequence == other.sequence;
+        }
+        bool operator < ( MessageInfo const& other ) const {
+            return sequence < other.sequence;
+        }
+    private:
+        static unsigned int globalCount;
+    };
+
+    struct MessageBuilder {
+        MessageBuilder( std::string const& macroName,
+                        SourceLineInfo const& lineInfo,
+                        ResultWas::OfType type )
+        : m_info( macroName, lineInfo, type )
+        {}
+
+        template<typename T>
+        MessageBuilder& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        MessageInfo m_info;
+        std::ostringstream m_stream;
+    };
+
+    class ScopedMessage {
+    public:
+        ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage const& other );
+        ~ScopedMessage();
+
+        MessageInfo m_info;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    class AssertionResult;
+    struct AssertionInfo;
+    struct SectionInfo;
+    struct MessageInfo;
+    class ScopedMessageBuilder;
+    struct Counts;
+
+    struct IResultCapture {
+
+        virtual ~IResultCapture();
+
+        virtual void assertionEnded( AssertionResult const& result ) = 0;
+        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
+                                        Counts& assertions ) = 0;
+        virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
+        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+        virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+        virtual std::string getCurrentTestName() const = 0;
+        virtual const AssertionResult* getLastResult() const = 0;
+
+        virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+    };
+
+    IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_MAC
+#elif  defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_IPHONE
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+#include <string>
+
+namespace Catch{
+
+    bool isDebuggerActive();
+    void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    // The following code snippet based on:
+    // http://cocoawithlove.com/2008/03/break-into-debugger.html
+    #ifdef DEBUG
+        #if defined(__ppc64__) || defined(__ppc__)
+            #define CATCH_BREAK_INTO_DEBUGGER() \
+                if( Catch::isDebuggerActive() ) { \
+                    __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                    : : : "memory","r0","r3","r4" ); \
+                }
+        #else
+            #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
+        #endif
+    #endif
+
+#elif defined(_MSC_VER)
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+    class TestCase;
+
+    struct IRunner {
+        virtual ~IRunner();
+        virtual bool aborting() const = 0;
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
+    resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        try { \
+            ( __catchResult->*expr ).endExpression(); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
+    INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+    if( Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
+    INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+    if( !Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        try { \
+            expr; \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                expr; \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( ... ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                expr; \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( exceptionType ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+            catch( ... ) { \
+                __catchResult.useActiveException( resultDisposition ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#else
+    #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << log + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( log, macroName ) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
+        try { \
+            std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
+            __catchResult \
+                .setLhs( Catch::toString( arg ) ) \
+                .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
+                .setOp( "matches" ) \
+                .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
+            __catchResult.captureExpression(); \
+        } catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& _description = std::string() );
+
+        std::string name;
+        std::string description;
+        SourceLineInfo lineInfo;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+    struct Counts {
+        Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
+
+        Counts operator - ( Counts const& other ) const {
+            Counts diff;
+            diff.passed = passed - other.passed;
+            diff.failed = failed - other.failed;
+            diff.failedButOk = failedButOk - other.failedButOk;
+            return diff;
+        }
+        Counts& operator += ( Counts const& other ) {
+            passed += other.passed;
+            failed += other.failed;
+            failedButOk += other.failedButOk;
+            return *this;
+        }
+
+        std::size_t total() const {
+            return passed + failed + failedButOk;
+        }
+        bool allPassed() const {
+            return failed == 0 && failedButOk == 0;
+        }
+        bool allOk() const {
+            return failed == 0;
+        }
+
+        std::size_t passed;
+        std::size_t failed;
+        std::size_t failedButOk;
+    };
+
+    struct Totals {
+
+        Totals operator - ( Totals const& other ) const {
+            Totals diff;
+            diff.assertions = assertions - other.assertions;
+            diff.testCases = testCases - other.testCases;
+            return diff;
+        }
+
+        Totals delta( Totals const& prevTotals ) const {
+            Totals diff = *this - prevTotals;
+            if( diff.assertions.failed > 0 )
+                ++diff.testCases.failed;
+            else if( diff.assertions.failedButOk > 0 )
+                ++diff.testCases.failedButOk;
+            else
+                ++diff.testCases.passed;
+            return diff;
+        }
+
+        Totals& operator += ( Totals const& other ) {
+            assertions += other.assertions;
+            testCases += other.testCases;
+            return *this;
+        }
+
+        Counts assertions;
+        Counts testCases;
+    };
+}
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef CATCH_PLATFORM_WINDOWS
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace Catch {
+
+    class Timer {
+    public:
+        Timer() : m_ticks( 0 ) {}
+        void start();
+        unsigned int getElapsedMicroseconds() const;
+        unsigned int getElapsedMilliseconds() const;
+        double getElapsedSeconds() const;
+
+    private:
+        uint64_t m_ticks;
+    };
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+    class Section : NonCopyable {
+    public:
+        Section( SectionInfo const& info );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        operator bool() const;
+
+    private:
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_SECTION( ... ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+    #define INTERNAL_CATCH_SECTION( name, desc ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <iterator>
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+namespace Catch {
+
+template<typename T>
+struct IGenerator {
+    virtual ~IGenerator() {}
+    virtual T getValue( std::size_t index ) const = 0;
+    virtual std::size_t size () const = 0;
+};
+
+template<typename T>
+class BetweenGenerator : public IGenerator<T> {
+public:
+    BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
+
+    virtual T getValue( std::size_t index ) const {
+        return m_from+static_cast<int>( index );
+    }
+
+    virtual std::size_t size() const {
+        return static_cast<std::size_t>( 1+m_to-m_from );
+    }
+
+private:
+
+    T m_from;
+    T m_to;
+};
+
+template<typename T>
+class ValuesGenerator : public IGenerator<T> {
+public:
+    ValuesGenerator(){}
+
+    void add( T value ) {
+        m_values.push_back( value );
+    }
+
+    virtual T getValue( std::size_t index ) const {
+        return m_values[index];
+    }
+
+    virtual std::size_t size() const {
+        return m_values.size();
+    }
+
+private:
+    std::vector<T> m_values;
+};
+
+template<typename T>
+class CompositeGenerator {
+public:
+    CompositeGenerator() : m_totalSize( 0 ) {}
+
+    // *** Move semantics, similar to auto_ptr ***
+    CompositeGenerator( CompositeGenerator& other )
+    :   m_fileInfo( other.m_fileInfo ),
+        m_totalSize( 0 )
+    {
+        move( other );
+    }
+
+    CompositeGenerator& setFileInfo( const char* fileInfo ) {
+        m_fileInfo = fileInfo;
+        return *this;
+    }
+
+    ~CompositeGenerator() {
+        deleteAll( m_composed );
+    }
+
+    operator T () const {
+        size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
+
+        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+        for( size_t index = 0; it != itEnd; ++it )
+        {
+            const IGenerator<T>* generator = *it;
+            if( overallIndex >= index && overallIndex < index + generator->size() )
+            {
+                return generator->getValue( overallIndex-index );
+            }
+            index += generator->size();
+        }
+        CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
+        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+    }
+
+    void add( const IGenerator<T>* generator ) {
+        m_totalSize += generator->size();
+        m_composed.push_back( generator );
+    }
+
+    CompositeGenerator& then( CompositeGenerator& other ) {
+        move( other );
+        return *this;
+    }
+
+    CompositeGenerator& then( T value ) {
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( value );
+        add( valuesGen );
+        return *this;
+    }
+
+private:
+
+    void move( CompositeGenerator& other ) {
+        std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
+        m_totalSize += other.m_totalSize;
+        other.m_composed.clear();
+    }
+
+    std::vector<const IGenerator<T>*> m_composed;
+    std::string m_fileInfo;
+    size_t m_totalSize;
+};
+
+namespace Generators
+{
+    template<typename T>
+    CompositeGenerator<T> between( T from, T to ) {
+        CompositeGenerator<T> generators;
+        generators.add( new BetweenGenerator<T>( from, to ) );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3 ){
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        valuesGen->add( val4 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2( line ) #line
+#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
+
+#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    struct ITestCaseRegistry;
+    struct IExceptionTranslatorRegistry;
+    struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
+
+    struct IRegistryHub {
+        virtual ~IRegistryHub();
+
+        virtual IReporterRegistry const& getReporterRegistry() const = 0;
+        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+    };
+
+    struct IMutableRegistryHub {
+        virtual ~IMutableRegistryHub();
+        virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
+        virtual void registerTest( TestCase const& testInfo ) = 0;
+        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+    };
+
+    IRegistryHub& getRegistryHub();
+    IMutableRegistryHub& getMutableRegistryHub();
+    void cleanUp();
+    std::string translateActiveException();
+
+}
+
+
+namespace Catch {
+
+    typedef std::string(*exceptionTranslateFunction)();
+
+    struct IExceptionTranslator {
+        virtual ~IExceptionTranslator();
+        virtual std::string translate() const = 0;
+    };
+
+    struct IExceptionTranslatorRegistry {
+        virtual ~IExceptionTranslatorRegistry();
+
+        virtual std::string translateActiveException() const = 0;
+    };
+
+    class ExceptionTranslatorRegistrar {
+        template<typename T>
+        class ExceptionTranslator : public IExceptionTranslator {
+        public:
+
+            ExceptionTranslator( std::string(*translateFunction)( T& ) )
+            : m_translateFunction( translateFunction )
+            {}
+
+            virtual std::string translate() const {
+                try {
+                    throw;
+                }
+                catch( T& ex ) {
+                    return m_translateFunction( ex );
+                }
+            }
+
+        protected:
+            std::string(*m_translateFunction)( T& );
+        };
+
+    public:
+        template<typename T>
+        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+            getMutableRegistryHub().registerTranslator
+                ( new ExceptionTranslator<T>( translateFunction ) );
+        }
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
+    static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
+    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
+    static std::string INTERNAL_CATCH_UNIQUE_NAME(  catch_internal_ExceptionTranslator )( signature )
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+namespace Catch {
+namespace Detail {
+
+    class Approx {
+    public:
+        explicit Approx ( double value )
+        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+            m_scale( 1.0 ),
+            m_value( value )
+        {}
+
+        Approx( Approx const& other )
+        :   m_epsilon( other.m_epsilon ),
+            m_scale( other.m_scale ),
+            m_value( other.m_value )
+        {}
+
+        static Approx custom() {
+            return Approx( 0 );
+        }
+
+        Approx operator()( double value ) {
+            Approx approx( value );
+            approx.epsilon( m_epsilon );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        friend bool operator == ( double lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
+        }
+
+        friend bool operator == ( Approx const& lhs, double rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        friend bool operator != ( double lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        friend bool operator != ( Approx const& lhs, double rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        Approx& epsilon( double newEpsilon ) {
+            m_epsilon = newEpsilon;
+            return *this;
+        }
+
+        Approx& scale( double newScale ) {
+            m_scale = newScale;
+            return *this;
+        }
+
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << "Approx( " << Catch::toString( m_value ) << " )";
+            return oss.str();
+        }
+
+    private:
+        double m_epsilon;
+        double m_scale;
+        double m_value;
+    };
+}
+
+template<>
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
+    return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+    template<typename ExpressionT>
+    struct Matcher : SharedImpl<IShared>
+    {
+        typedef ExpressionT ExpressionType;
+
+        virtual ~Matcher() {}
+        virtual Ptr<Matcher> clone() const = 0;
+        virtual bool match( ExpressionT const& expr ) const = 0;
+        virtual std::string toString() const = 0;
+    };
+
+    template<typename DerivedT, typename ExpressionT>
+    struct MatcherImpl : Matcher<ExpressionT> {
+
+        virtual Ptr<Matcher<ExpressionT> > clone() const {
+            return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
+        }
+    };
+
+    namespace Generic {
+
+        template<typename ExpressionT>
+        class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
+        public:
+
+            AllOf() {}
+            AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
+
+            AllOf& add( Matcher<ExpressionT> const& matcher ) {
+                m_matchers.push_back( matcher.clone() );
+                return *this;
+            }
+            virtual bool match( ExpressionT const& expr ) const
+            {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i )
+                    if( !m_matchers[i]->match( expr ) )
+                        return false;
+                return true;
+            }
+            virtual std::string toString() const {
+                std::ostringstream oss;
+                oss << "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        oss << " and ";
+                    oss << m_matchers[i]->toString();
+                }
+                oss << " )";
+                return oss.str();
+            }
+
+        private:
+            std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
+        };
+
+        template<typename ExpressionT>
+        class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
+        public:
+
+            AnyOf() {}
+            AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
+
+            AnyOf& add( Matcher<ExpressionT> const& matcher ) {
+                m_matchers.push_back( matcher.clone() );
+                return *this;
+            }
+            virtual bool match( ExpressionT const& expr ) const
+            {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i )
+                    if( m_matchers[i]->match( expr ) )
+                        return true;
+                return false;
+            }
+            virtual std::string toString() const {
+                std::ostringstream oss;
+                oss << "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        oss << " or ";
+                    oss << m_matchers[i]->toString();
+                }
+                oss << " )";
+                return oss.str();
+            }
+
+        private:
+            std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
+        };
+
+    }
+
+    namespace StdString {
+
+        inline std::string makeString( std::string const& str ) { return str; }
+        inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
+
+        struct Equals : MatcherImpl<Equals, std::string> {
+            Equals( std::string const& str ) : m_str( str ){}
+            Equals( Equals const& other ) : m_str( other.m_str ){}
+
+            virtual ~Equals();
+
+            virtual bool match( std::string const& expr ) const {
+                return m_str == expr;
+            }
+            virtual std::string toString() const {
+                return "equals: \"" + m_str + "\"";
+            }
+
+            std::string m_str;
+        };
+
+        struct Contains : MatcherImpl<Contains, std::string> {
+            Contains( std::string const& substr ) : m_substr( substr ){}
+            Contains( Contains const& other ) : m_substr( other.m_substr ){}
+
+            virtual ~Contains();
+
+            virtual bool match( std::string const& expr ) const {
+                return expr.find( m_substr ) != std::string::npos;
+            }
+            virtual std::string toString() const {
+                return "contains: \"" + m_substr + "\"";
+            }
+
+            std::string m_substr;
+        };
+
+        struct StartsWith : MatcherImpl<StartsWith, std::string> {
+            StartsWith( std::string const& substr ) : m_substr( substr ){}
+            StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
+
+            virtual ~StartsWith();
+
+            virtual bool match( std::string const& expr ) const {
+                return expr.find( m_substr ) == 0;
+            }
+            virtual std::string toString() const {
+                return "starts with: \"" + m_substr + "\"";
+            }
+
+            std::string m_substr;
+        };
+
+        struct EndsWith : MatcherImpl<EndsWith, std::string> {
+            EndsWith( std::string const& substr ) : m_substr( substr ){}
+            EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
+
+            virtual ~EndsWith();
+
+            virtual bool match( std::string const& expr ) const {
+                return expr.find( m_substr ) == expr.size() - m_substr.size();
+            }
+            virtual std::string toString() const {
+                return "ends with: \"" + m_substr + "\"";
+            }
+
+            std::string m_substr;
+        };
+    } // namespace StdString
+    } // namespace Impl
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+    template<typename ExpressionT>
+    inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2 ) {
+        return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
+    }
+    template<typename ExpressionT>
+    inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2,
+                                                    Impl::Matcher<ExpressionT> const& m3 ) {
+        return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
+    }
+    template<typename ExpressionT>
+    inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2 ) {
+        return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
+    }
+    template<typename ExpressionT>
+    inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2,
+                                                    Impl::Matcher<ExpressionT> const& m3 ) {
+        return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
+    }
+
+    inline Impl::StdString::Equals      Equals( std::string const& str ) {
+        return Impl::StdString::Equals( str );
+    }
+    inline Impl::StdString::Equals      Equals( const char* str ) {
+        return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
+    }
+    inline Impl::StdString::Contains    Contains( std::string const& substr ) {
+        return Impl::StdString::Contains( substr );
+    }
+    inline Impl::StdString::Contains    Contains( const char* substr ) {
+        return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
+    }
+    inline Impl::StdString::StartsWith  StartsWith( std::string const& substr ) {
+        return Impl::StdString::StartsWith( substr );
+    }
+    inline Impl::StdString::StartsWith  StartsWith( const char* substr ) {
+        return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
+    }
+    inline Impl::StdString::EndsWith    EndsWith( std::string const& substr ) {
+        return Impl::StdString::EndsWith( substr );
+    }
+    inline Impl::StdString::EndsWith    EndsWith( const char* substr ) {
+        return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
+    }
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias {
+        TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+
+        std::string tag;
+        SourceLineInfo lineInfo;
+    };
+
+    struct RegistrarForTagAliases {
+        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+    };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+    // An optional type
+    template<typename T>
+    class Option {
+    public:
+        Option() : nullableValue( NULL ) {}
+        Option( T const& _value )
+        : nullableValue( new( storage ) T( _value ) )
+        {}
+        Option( Option const& _other )
+        : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
+        {}
+
+        ~Option() {
+            reset();
+        }
+
+        Option& operator= ( Option const& _other ) {
+            if( &_other != this ) {
+                reset();
+                if( _other )
+                    nullableValue = new( storage ) T( *_other );
+            }
+            return *this;
+        }
+        Option& operator = ( T const& _value ) {
+            reset();
+            nullableValue = new( storage ) T( _value );
+            return *this;
+        }
+
+        void reset() {
+            if( nullableValue )
+                nullableValue->~T();
+            nullableValue = NULL;
+        }
+
+        T& operator*() { return *nullableValue; }
+        T const& operator*() const { return *nullableValue; }
+        T* operator->() { return nullableValue; }
+        const T* operator->() const { return nullableValue; }
+
+        T valueOr( T const& defaultValue ) const {
+            return nullableValue ? *nullableValue : defaultValue;
+        }
+
+        bool some() const { return nullableValue != NULL; }
+        bool none() const { return nullableValue == NULL; }
+
+        bool operator !() const { return nullableValue == NULL; }
+        operator SafeBool::type() const {
+            return SafeBool::makeSafe( some() );
+        }
+
+    private:
+        T* nullableValue;
+        char storage[sizeof(T)];
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct ITagAliasRegistry {
+        virtual ~ITagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const = 0;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+        static ITagAliasRegistry const& get();
+    };
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <string>
+#include <set>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    struct ITestCase;
+
+    struct TestCaseInfo {
+        enum SpecialProperties{
+            None = 0,
+            IsHidden = 1 << 1,
+            ShouldFail = 1 << 2,
+            MayFail = 1 << 3,
+            Throws = 1 << 4
+        };
+
+        TestCaseInfo(   std::string const& _name,
+                        std::string const& _className,
+                        std::string const& _description,
+                        std::set<std::string> const& _tags,
+                        SourceLineInfo const& _lineInfo );
+
+        TestCaseInfo( TestCaseInfo const& other );
+
+        bool isHidden() const;
+        bool throws() const;
+        bool okToFail() const;
+        bool expectedToFail() const;
+
+        std::string name;
+        std::string className;
+        std::string description;
+        std::set<std::string> tags;
+        std::set<std::string> lcaseTags;
+        std::string tagsAsString;
+        SourceLineInfo lineInfo;
+        SpecialProperties properties;
+    };
+
+    class TestCase : public TestCaseInfo {
+    public:
+
+        TestCase( ITestCase* testCase, TestCaseInfo const& info );
+        TestCase( TestCase const& other );
+
+        TestCase withName( std::string const& _newName ) const;
+
+        void invoke() const;
+
+        TestCaseInfo const& getTestCaseInfo() const;
+
+        void swap( TestCase& other );
+        bool operator == ( TestCase const& other ) const;
+        bool operator < ( TestCase const& other ) const;
+        TestCase& operator = ( TestCase const& other );
+
+    private:
+        Ptr<ITestCase> test;
+    };
+
+    TestCase makeTestCase(  ITestCase* testCase,
+                            std::string const& className,
+                            std::string const& name,
+                            std::string const& description,
+                            SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+ at protocol OcFixture
+
+ at optional
+
+-(void) setUp;
+-(void) tearDown;
+
+ at end
+
+namespace Catch {
+
+    class OcMethod : public SharedImpl<ITestCase> {
+
+    public:
+        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+        virtual void invoke() const {
+            id obj = [[m_cls alloc] init];
+
+            performOptionalSelector( obj, @selector(setUp)  );
+            performOptionalSelector( obj, m_sel );
+            performOptionalSelector( obj, @selector(tearDown)  );
+
+            arcSafeRelease( obj );
+        }
+    private:
+        virtual ~OcMethod() {}
+
+        Class m_cls;
+        SEL m_sel;
+    };
+
+    namespace Detail{
+
+        inline std::string getAnnotation(   Class cls,
+                                            std::string const& annotationName,
+                                            std::string const& testCaseName ) {
+            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+            SEL sel = NSSelectorFromString( selStr );
+            arcSafeRelease( selStr );
+            id value = performOptionalSelector( cls, sel );
+            if( value )
+                return [(NSString*)value UTF8String];
+            return "";
+        }
+    }
+
+    inline size_t registerTestMethods() {
+        size_t noTestMethods = 0;
+        int noClasses = objc_getClassList( NULL, 0 );
+
+        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+        objc_getClassList( classes, noClasses );
+
+        for( int c = 0; c < noClasses; c++ ) {
+            Class cls = classes[c];
+            {
+                u_int count;
+                Method* methods = class_copyMethodList( cls, &count );
+                for( u_int m = 0; m < count ; m++ ) {
+                    SEL selector = method_getName(methods[m]);
+                    std::string methodName = sel_getName(selector);
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
+                        std::string testCaseName = methodName.substr( 15 );
+                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+                        const char* className = class_getName( cls );
+
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
+                        noTestMethods++;
+                    }
+                }
+                free(methods);
+            }
+        }
+        return noTestMethods;
+    }
+
+    namespace Matchers {
+        namespace Impl {
+        namespace NSStringMatchers {
+
+            template<typename MatcherT>
+            struct StringHolder : MatcherImpl<MatcherT, NSString*>{
+                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+                StringHolder() {
+                    arcSafeRelease( m_substr );
+                }
+
+                NSString* m_substr;
+            };
+
+            struct Equals : StringHolder<Equals> {
+                Equals( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str isEqualToString:m_substr];
+                }
+
+                virtual std::string toString() const {
+                    return "equals string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct Contains : StringHolder<Contains> {
+                Contains( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location != NSNotFound;
+                }
+
+                virtual std::string toString() const {
+                    return "contains string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct StartsWith : StringHolder<StartsWith> {
+                StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == 0;
+                }
+
+                virtual std::string toString() const {
+                    return "starts with: " + Catch::toString( m_substr );
+                }
+            };
+            struct EndsWith : StringHolder<EndsWith> {
+                EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                }
+
+                virtual std::string toString() const {
+                    return "ends with: " + Catch::toString( m_substr );
+                }
+            };
+
+        } // namespace NSStringMatchers
+        } // namespace Impl
+
+        inline Impl::NSStringMatchers::Equals
+            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+        inline Impl::NSStringMatchers::Contains
+            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+        inline Impl::NSStringMatchers::StartsWith
+            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+        inline Impl::NSStringMatchers::EndsWith
+            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+    } // namespace Matchers
+
+    using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE( name, desc )\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
+{\
+return @ name; \
+}\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
+{ \
+return @ desc; \
+} \
+-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
+
+#endif
+
+#ifdef CATCH_IMPL
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: ../catch_runner.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec {
+        struct Pattern : SharedImpl<> {
+            virtual ~Pattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+        };
+        class NamePattern : public Pattern {
+            enum WildcardPosition {
+                NoWildcard = 0,
+                WildcardAtStart = 1,
+                WildcardAtEnd = 2,
+                WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+            };
+
+        public:
+            NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
+                if( startsWith( m_name, "*" ) ) {
+                    m_name = m_name.substr( 1 );
+                    m_wildcard = WildcardAtStart;
+                }
+                if( endsWith( m_name, "*" ) ) {
+                    m_name = m_name.substr( 0, m_name.size()-1 );
+                    m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+                }
+            }
+            virtual ~NamePattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                switch( m_wildcard ) {
+                    case NoWildcard:
+                        return m_name == toLower( testCase.name );
+                    case WildcardAtStart:
+                        return endsWith( toLower( testCase.name ), m_name );
+                    case WildcardAtEnd:
+                        return startsWith( toLower( testCase.name ), m_name );
+                    case WildcardAtBothEnds:
+                        return contains( toLower( testCase.name ), m_name );
+                }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+                throw std::logic_error( "Unknown enum" );
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+            }
+        private:
+            std::string m_name;
+            WildcardPosition m_wildcard;
+        };
+        class TagPattern : public Pattern {
+        public:
+            TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+            virtual ~TagPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
+            }
+        private:
+            std::string m_tag;
+        };
+        class ExcludedPattern : public Pattern {
+        public:
+            ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+            virtual ~ExcludedPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+        private:
+            Ptr<Pattern> m_underlyingPattern;
+        };
+
+        struct Filter {
+            std::vector<Ptr<Pattern> > m_patterns;
+
+            bool matches( TestCaseInfo const& testCase ) const {
+                // All patterns in a filter must match for the filter to be a match
+                for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
+                    if( !(*it)->matches( testCase ) )
+                        return false;
+                    return true;
+            }
+        };
+
+    public:
+        bool hasFilters() const {
+            return !m_filters.empty();
+        }
+        bool matches( TestCaseInfo const& testCase ) const {
+            // A TestSpec matches if any filter matches
+            for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
+                if( it->matches( testCase ) )
+                    return true;
+            return false;
+        }
+
+    private:
+        std::vector<Filter> m_filters;
+
+        friend class TestSpecParser;
+    };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestSpecParser {
+        enum Mode{ None, Name, QuotedName, Tag };
+        Mode m_mode;
+        bool m_exclusion;
+        std::size_t m_start, m_pos;
+        std::string m_arg;
+        TestSpec::Filter m_currentFilter;
+        TestSpec m_testSpec;
+        ITagAliasRegistry const* m_tagAliases;
+
+    public:
+        TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+        TestSpecParser& parse( std::string const& arg ) {
+            m_mode = None;
+            m_exclusion = false;
+            m_start = std::string::npos;
+            m_arg = m_tagAliases->expandAliases( arg );
+            for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+                visitChar( m_arg[m_pos] );
+            if( m_mode == Name )
+                addPattern<TestSpec::NamePattern>();
+            return *this;
+        }
+        TestSpec testSpec() {
+            addFilter();
+            return m_testSpec;
+        }
+    private:
+        void visitChar( char c ) {
+            if( m_mode == None ) {
+                switch( c ) {
+                case ' ': return;
+                case '~': m_exclusion = true; return;
+                case '[': return startNewMode( Tag, ++m_pos );
+                case '"': return startNewMode( QuotedName, ++m_pos );
+                default: startNewMode( Name, m_pos ); break;
+                }
+            }
+            if( m_mode == Name ) {
+                if( c == ',' ) {
+                    addPattern<TestSpec::NamePattern>();
+                    addFilter();
+                }
+                else if( c == '[' ) {
+                    if( subString() == "exclude:" )
+                        m_exclusion = true;
+                    else
+                        addPattern<TestSpec::NamePattern>();
+                    startNewMode( Tag, ++m_pos );
+                }
+            }
+            else if( m_mode == QuotedName && c == '"' )
+                addPattern<TestSpec::NamePattern>();
+            else if( m_mode == Tag && c == ']' )
+                addPattern<TestSpec::TagPattern>();
+        }
+        void startNewMode( Mode mode, std::size_t start ) {
+            m_mode = mode;
+            m_start = start;
+        }
+        std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+        template<typename T>
+        void addPattern() {
+            std::string token = subString();
+            if( startsWith( token, "exclude:" ) ) {
+                m_exclusion = true;
+                token = token.substr( 8 );
+            }
+            if( !token.empty() ) {
+                Ptr<TestSpec::Pattern> pattern = new T( token );
+                if( m_exclusion )
+                    pattern = new TestSpec::ExcludedPattern( pattern );
+                m_currentFilter.m_patterns.push_back( pattern );
+            }
+            m_exclusion = false;
+            m_mode = None;
+        }
+        void addFilter() {
+            if( !m_currentFilter.m_patterns.empty() ) {
+                m_testSpec.m_filters.push_back( m_currentFilter );
+                m_currentFilter = TestSpec::Filter();
+            }
+        }
+    };
+    inline TestSpec parseTestSpec( std::string const& arg ) {
+        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    struct Verbosity { enum Level {
+        NoOutput = 0,
+        Quiet,
+        Normal
+    }; };
+
+    struct WarnAbout { enum What {
+        Nothing = 0x00,
+        NoAssertions = 0x01
+    }; };
+
+    struct ShowDurations { enum OrNot {
+        DefaultForReporter,
+        Always,
+        Never
+    }; };
+    struct RunTests { enum InWhatOrder {
+        InDeclarationOrder,
+        InLexicographicalOrder,
+        InRandomOrder
+    }; };
+
+    class TestSpec;
+
+    struct IConfig : IShared {
+
+        virtual ~IConfig();
+
+        virtual bool allowThrows() const = 0;
+        virtual std::ostream& stream() const = 0;
+        virtual std::string name() const = 0;
+        virtual bool includeSuccessfulResults() const = 0;
+        virtual bool shouldDebugBreak() const = 0;
+        virtual bool warnAboutMissingAssertions() const = 0;
+        virtual int abortAfter() const = 0;
+        virtual bool showInvisibles() const = 0;
+        virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual TestSpec const& testSpec() const = 0;
+        virtual RunTests::InWhatOrder runOrder() const = 0;
+        virtual unsigned int rngSeed() const = 0;
+        virtual bool forceColour() const = 0;
+    };
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+#include <streambuf>
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    class Stream {
+    public:
+        Stream();
+        Stream( std::streambuf* _streamBuf, bool _isOwned );
+        void release();
+
+        std::streambuf* streamBuf;
+
+    private:
+        bool isOwned;
+    };
+
+    std::ostream& cout();
+    std::ostream& cerr();
+}
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <iostream>
+#include <ctime>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+    struct ConfigData {
+
+        ConfigData()
+        :   listTests( false ),
+            listTags( false ),
+            listReporters( false ),
+            listTestNamesOnly( false ),
+            showSuccessfulTests( false ),
+            shouldDebugBreak( false ),
+            noThrow( false ),
+            showHelp( false ),
+            showInvisibles( false ),
+            forceColour( false ),
+            abortAfter( -1 ),
+            rngSeed( 0 ),
+            verbosity( Verbosity::Normal ),
+            warnings( WarnAbout::Nothing ),
+            showDurations( ShowDurations::DefaultForReporter ),
+            runOrder( RunTests::InDeclarationOrder )
+        {}
+
+        bool listTests;
+        bool listTags;
+        bool listReporters;
+        bool listTestNamesOnly;
+
+        bool showSuccessfulTests;
+        bool shouldDebugBreak;
+        bool noThrow;
+        bool showHelp;
+        bool showInvisibles;
+        bool forceColour;
+
+        int abortAfter;
+        unsigned int rngSeed;
+
+        Verbosity::Level verbosity;
+        WarnAbout::What warnings;
+        ShowDurations::OrNot showDurations;
+        RunTests::InWhatOrder runOrder;
+
+        std::string reporterName;
+        std::string outputFilename;
+        std::string name;
+        std::string processName;
+
+        std::vector<std::string> testsOrTags;
+    };
+
+    class Config : public SharedImpl<IConfig> {
+    private:
+        Config( Config const& other );
+        Config& operator = ( Config const& other );
+        virtual void dummy();
+    public:
+
+        Config()
+        :   m_os( Catch::cout().rdbuf() )
+        {}
+
+        Config( ConfigData const& data )
+        :   m_data( data ),
+            m_os( Catch::cout().rdbuf() )
+        {
+            if( !data.testsOrTags.empty() ) {
+                TestSpecParser parser( ITagAliasRegistry::get() );
+                for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
+                    parser.parse( data.testsOrTags[i] );
+                m_testSpec = parser.testSpec();
+            }
+        }
+
+        virtual ~Config() {
+            m_os.rdbuf( Catch::cout().rdbuf() );
+            m_stream.release();
+        }
+
+        void setFilename( std::string const& filename ) {
+            m_data.outputFilename = filename;
+        }
+
+        std::string const& getFilename() const {
+            return m_data.outputFilename ;
+        }
+
+        bool listTests() const { return m_data.listTests; }
+        bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+        bool listTags() const { return m_data.listTags; }
+        bool listReporters() const { return m_data.listReporters; }
+
+        std::string getProcessName() const { return m_data.processName; }
+
+        bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+
+        void setStreamBuf( std::streambuf* buf ) {
+            m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() );
+        }
+
+        void useStream( std::string const& streamName ) {
+            Stream stream = createStream( streamName );
+            setStreamBuf( stream.streamBuf );
+            m_stream.release();
+            m_stream = stream;
+        }
+
+        std::string getReporterName() const { return m_data.reporterName; }
+
+        int abortAfter() const { return m_data.abortAfter; }
+
+        TestSpec const& testSpec() const { return m_testSpec; }
+
+        bool showHelp() const { return m_data.showHelp; }
+        bool showInvisibles() const { return m_data.showInvisibles; }
+
+        // IConfig interface
+        virtual bool allowThrows() const        { return !m_data.noThrow; }
+        virtual std::ostream& stream() const    { return m_os; }
+        virtual std::string name() const        { return m_data.name.empty() ? m_data.processName : m_data.name; }
+        virtual bool includeSuccessfulResults() const   { return m_data.showSuccessfulTests; }
+        virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
+        virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
+        virtual RunTests::InWhatOrder runOrder() const  { return m_data.runOrder; }
+        virtual unsigned int rngSeed() const    { return m_data.rngSeed; }
+        virtual bool forceColour() const { return m_data.forceColour; }
+
+    private:
+        ConfigData m_data;
+
+        Stream m_stream;
+        mutable std::ostream m_os;
+        TestSpec m_testSpec;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+#include <map>
+#include <algorithm>
+#include <stdexcept>
+#include <memory>
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+    struct UnpositionalTag {};
+
+    extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+    UnpositionalTag _;
+#endif
+
+    namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+    const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+        using namespace Tbc;
+
+        inline bool startsWith( std::string const& str, std::string const& prefix ) {
+            return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
+        }
+
+        template<typename T> struct RemoveConstRef{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
+
+        template<typename T>    struct IsBool       { static const bool value = false; };
+        template<>              struct IsBool<bool> { static const bool value = true; };
+
+        template<typename T>
+        void convertInto( std::string const& _source, T& _dest ) {
+            std::stringstream ss;
+            ss << _source;
+            ss >> _dest;
+            if( ss.fail() )
+                throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
+        }
+        inline void convertInto( std::string const& _source, std::string& _dest ) {
+            _dest = _source;
+        }
+        inline void convertInto( std::string const& _source, bool& _dest ) {
+            std::string sourceLC = _source;
+            std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
+            if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
+                _dest = true;
+            else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
+                _dest = false;
+            else
+                throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" );
+        }
+        inline void convertInto( bool _source, bool& _dest ) {
+            _dest = _source;
+        }
+        template<typename T>
+        inline void convertInto( bool, T& ) {
+            throw std::runtime_error( "Invalid conversion" );
+        }
+
+        template<typename ConfigT>
+        struct IArgFunction {
+            virtual ~IArgFunction() {}
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+            IArgFunction()                      = default;
+            IArgFunction( IArgFunction const& ) = default;
+#  endif
+            virtual void set( ConfigT& config, std::string const& value ) const = 0;
+            virtual void setFlag( ConfigT& config ) const = 0;
+            virtual bool takesArg() const = 0;
+            virtual IArgFunction* clone() const = 0;
+        };
+
+        template<typename ConfigT>
+        class BoundArgFunction {
+        public:
+            BoundArgFunction() : functionObj( NULL ) {}
+            BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
+            BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
+            BoundArgFunction& operator = ( BoundArgFunction const& other ) {
+                IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
+                delete functionObj;
+                functionObj = newFunctionObj;
+                return *this;
+            }
+            ~BoundArgFunction() { delete functionObj; }
+
+            void set( ConfigT& config, std::string const& value ) const {
+                functionObj->set( config, value );
+            }
+            void setFlag( ConfigT& config ) const {
+                functionObj->setFlag( config );
+            }
+            bool takesArg() const { return functionObj->takesArg(); }
+
+            bool isSet() const {
+                return functionObj != NULL;
+            }
+        private:
+            IArgFunction<ConfigT>* functionObj;
+        };
+
+        template<typename C>
+        struct NullBinder : IArgFunction<C>{
+            virtual void set( C&, std::string const& ) const {}
+            virtual void setFlag( C& ) const {}
+            virtual bool takesArg() const { return true; }
+            virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
+        };
+
+        template<typename C, typename M>
+        struct BoundDataMember : IArgFunction<C>{
+            BoundDataMember( M C::* _member ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                convertInto( stringValue, p.*member );
+            }
+            virtual void setFlag( C& p ) const {
+                convertInto( true, p.*member );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
+            M C::* member;
+        };
+        template<typename C, typename M>
+        struct BoundUnaryMethod : IArgFunction<C>{
+            BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( stringValue, value );
+                (p.*member)( value );
+            }
+            virtual void setFlag( C& p ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( true, value );
+                (p.*member)( value );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
+            void (C::*member)( M );
+        };
+        template<typename C>
+        struct BoundNullaryMethod : IArgFunction<C>{
+            BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    (p.*member)();
+            }
+            virtual void setFlag( C& p ) const {
+                (p.*member)();
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
+            void (C::*member)();
+        };
+
+        template<typename C>
+        struct BoundUnaryFunction : IArgFunction<C>{
+            BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    function( obj );
+            }
+            virtual void setFlag( C& p ) const {
+                function( p );
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
+            void (*function)( C& );
+        };
+
+        template<typename C, typename T>
+        struct BoundBinaryFunction : IArgFunction<C>{
+            BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( stringValue, value );
+                function( obj, value );
+            }
+            virtual void setFlag( C& obj ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( true, value );
+                function( obj, value );
+            }
+            virtual bool takesArg() const { return !IsBool<T>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
+            void (*function)( C&, T );
+        };
+
+    } // namespace Detail
+
+    struct Parser {
+        Parser() : separators( " \t=:" ) {}
+
+        struct Token {
+            enum Type { Positional, ShortOpt, LongOpt };
+            Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
+            Type type;
+            std::string data;
+        };
+
+        void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
+            const std::string doubleDash = "--";
+            for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
+                parseIntoTokens( argv[i] , tokens);
+        }
+        void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
+            while( !arg.empty() ) {
+                Parser::Token token( Parser::Token::Positional, arg );
+                arg = "";
+                if( token.data[0] == '-' ) {
+                    if( token.data.size() > 1 && token.data[1] == '-' ) {
+                        token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
+                    }
+                    else {
+                        token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
+                        if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
+                            arg = "-" + token.data.substr( 1 );
+                            token.data = token.data.substr( 0, 1 );
+                        }
+                    }
+                }
+                if( token.type != Parser::Token::Positional ) {
+                    std::size_t pos = token.data.find_first_of( separators );
+                    if( pos != std::string::npos ) {
+                        arg = token.data.substr( pos+1 );
+                        token.data = token.data.substr( 0, pos );
+                    }
+                }
+                tokens.push_back( token );
+            }
+        }
+        std::string separators;
+    };
+
+    template<typename ConfigT>
+    struct CommonArgProperties {
+        CommonArgProperties() {}
+        CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
+
+        Detail::BoundArgFunction<ConfigT> boundField;
+        std::string description;
+        std::string detail;
+        std::string placeholder; // Only value if boundField takes an arg
+
+        bool takesArg() const {
+            return !placeholder.empty();
+        }
+        void validate() const {
+            if( !boundField.isSet() )
+                throw std::logic_error( "option not bound" );
+        }
+    };
+    struct OptionArgProperties {
+        std::vector<std::string> shortNames;
+        std::string longName;
+
+        bool hasShortName( std::string const& shortName ) const {
+            return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
+        }
+        bool hasLongName( std::string const& _longName ) const {
+            return _longName == longName;
+        }
+    };
+    struct PositionalArgProperties {
+        PositionalArgProperties() : position( -1 ) {}
+        int position; // -1 means non-positional (floating)
+
+        bool isFixedPositional() const {
+            return position != -1;
+        }
+    };
+
+    template<typename ConfigT>
+    class CommandLine {
+
+        struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
+            Arg() {}
+            Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
+
+            using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+            std::string dbgName() const {
+                if( !longName.empty() )
+                    return "--" + longName;
+                if( !shortNames.empty() )
+                    return "-" + shortNames[0];
+                return "positional args";
+            }
+            std::string commands() const {
+                std::ostringstream oss;
+                bool first = true;
+                std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+                for(; it != itEnd; ++it ) {
+                    if( first )
+                        first = false;
+                    else
+                        oss << ", ";
+                    oss << "-" << *it;
+                }
+                if( !longName.empty() ) {
+                    if( !first )
+                        oss << ", ";
+                    oss << "--" << longName;
+                }
+                if( !placeholder.empty() )
+                    oss << " <" << placeholder << ">";
+                return oss.str();
+            }
+        };
+
+        // NOTE: std::auto_ptr is deprecated in c++11/c++0x
+#if defined(__cplusplus) && __cplusplus > 199711L
+        typedef std::unique_ptr<Arg> ArgAutoPtr;
+#else
+        typedef std::auto_ptr<Arg> ArgAutoPtr;
+#endif
+
+        friend void addOptName( Arg& arg, std::string const& optName )
+        {
+            if( optName.empty() )
+                return;
+            if( Detail::startsWith( optName, "--" ) ) {
+                if( !arg.longName.empty() )
+                    throw std::logic_error( "Only one long opt may be specified. '"
+                        + arg.longName
+                        + "' already specified, now attempting to add '"
+                        + optName + "'" );
+                arg.longName = optName.substr( 2 );
+            }
+            else if( Detail::startsWith( optName, "-" ) )
+                arg.shortNames.push_back( optName.substr( 1 ) );
+            else
+                throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
+        }
+        friend void setPositionalArg( Arg& arg, int position )
+        {
+            arg.position = position;
+        }
+
+        class ArgBuilder {
+        public:
+            ArgBuilder( Arg* arg ) : m_arg( arg ) {}
+
+            // Bind a non-boolean data member (requires placeholder string)
+            template<typename C, typename M>
+            void bind( M C::* field, std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
+                m_arg->placeholder = placeholder;
+            }
+            // Bind a boolean data member (no placeholder required)
+            template<typename C>
+            void bind( bool C::* field ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
+            }
+
+            // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+            template<typename C, typename M>
+            void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
+                m_arg->placeholder = placeholder;
+            }
+
+            // Bind a method taking a single, boolean argument (no placeholder string required)
+            template<typename C>
+            void bind( void (C::* unaryMethod)( bool ) ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
+            }
+
+            // Bind a method that takes no arguments (will be called if opt is present)
+            template<typename C>
+            void bind( void (C::* nullaryMethod)() ) {
+                m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+            template<typename C>
+            void bind( void (* unaryFunction)( C& ) ) {
+                m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+            template<typename C, typename T>
+            void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
+                m_arg->placeholder = placeholder;
+            }
+
+            ArgBuilder& describe( std::string const& description ) {
+                m_arg->description = description;
+                return *this;
+            }
+            ArgBuilder& detail( std::string const& detail ) {
+                m_arg->detail = detail;
+                return *this;
+            }
+
+        protected:
+            Arg* m_arg;
+        };
+
+        class OptBuilder : public ArgBuilder {
+        public:
+            OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
+            OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
+
+            OptBuilder& operator[]( std::string const& optName ) {
+                addOptName( *ArgBuilder::m_arg, optName );
+                return *this;
+            }
+        };
+
+    public:
+
+        CommandLine()
+        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
+            m_highestSpecifiedArgPosition( 0 ),
+            m_throwOnUnrecognisedTokens( false )
+        {}
+        CommandLine( CommandLine const& other )
+        :   m_boundProcessName( other.m_boundProcessName ),
+            m_options ( other.m_options ),
+            m_positionalArgs( other.m_positionalArgs ),
+            m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
+            m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
+        {
+            if( other.m_floatingArg.get() )
+                m_floatingArg.reset( new Arg( *other.m_floatingArg ) );
+        }
+
+        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
+            m_throwOnUnrecognisedTokens = shouldThrow;
+            return *this;
+        }
+
+        OptBuilder operator[]( std::string const& optName ) {
+            m_options.push_back( Arg() );
+            addOptName( m_options.back(), optName );
+            OptBuilder builder( &m_options.back() );
+            return builder;
+        }
+
+        ArgBuilder operator[]( int position ) {
+            m_positionalArgs.insert( std::make_pair( position, Arg() ) );
+            if( position > m_highestSpecifiedArgPosition )
+                m_highestSpecifiedArgPosition = position;
+            setPositionalArg( m_positionalArgs[position], position );
+            ArgBuilder builder( &m_positionalArgs[position] );
+            return builder;
+        }
+
+        // Invoke this with the _ instance
+        ArgBuilder operator[]( UnpositionalTag ) {
+            if( m_floatingArg.get() )
+                throw std::logic_error( "Only one unpositional argument can be added" );
+            m_floatingArg.reset( new Arg() );
+            ArgBuilder builder( m_floatingArg.get() );
+            return builder;
+        }
+
+        template<typename C, typename M>
+        void bindProcessName( M C::* field ) {
+            m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
+        }
+        template<typename C, typename M>
+        void bindProcessName( void (C::*_unaryMethod)( M ) ) {
+            m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
+        }
+
+        void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
+            typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+            std::size_t maxWidth = 0;
+            for( it = itBegin; it != itEnd; ++it )
+                maxWidth = (std::max)( maxWidth, it->commands().size() );
+
+            for( it = itBegin; it != itEnd; ++it ) {
+                Detail::Text usage( it->commands(), Detail::TextAttributes()
+                                                        .setWidth( maxWidth+indent )
+                                                        .setIndent( indent ) );
+                Detail::Text desc( it->description, Detail::TextAttributes()
+                                                        .setWidth( width - maxWidth - 3 ) );
+
+                for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
+                    std::string usageCol = i < usage.size() ? usage[i] : "";
+                    os << usageCol;
+
+                    if( i < desc.size() && !desc[i].empty() )
+                        os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
+                            << desc[i];
+                    os << "\n";
+                }
+            }
+        }
+        std::string optUsage() const {
+            std::ostringstream oss;
+            optUsage( oss );
+            return oss.str();
+        }
+
+        void argSynopsis( std::ostream& os ) const {
+            for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
+                if( i > 1 )
+                    os << " ";
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
+                if( it != m_positionalArgs.end() )
+                    os << "<" << it->second.placeholder << ">";
+                else if( m_floatingArg.get() )
+                    os << "<" << m_floatingArg->placeholder << ">";
+                else
+                    throw std::logic_error( "non consecutive positional arguments with no floating args" );
+            }
+            // !TBD No indication of mandatory args
+            if( m_floatingArg.get() ) {
+                if( m_highestSpecifiedArgPosition > 1 )
+                    os << " ";
+                os << "[<" << m_floatingArg->placeholder << "> ...]";
+            }
+        }
+        std::string argSynopsis() const {
+            std::ostringstream oss;
+            argSynopsis( oss );
+            return oss.str();
+        }
+
+        void usage( std::ostream& os, std::string const& procName ) const {
+            validate();
+            os << "usage:\n  " << procName << " ";
+            argSynopsis( os );
+            if( !m_options.empty() ) {
+                os << " [options]\n\nwhere options are: \n";
+                optUsage( os, 2 );
+            }
+            os << "\n";
+        }
+        std::string usage( std::string const& procName ) const {
+            std::ostringstream oss;
+            usage( oss, procName );
+            return oss.str();
+        }
+
+        ConfigT parse( int argc, char const * const * argv ) const {
+            ConfigT config;
+            parseInto( argc, argv, config );
+            return config;
+        }
+
+        std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
+            std::string processName = argv[0];
+            std::size_t lastSlash = processName.find_last_of( "/\\" );
+            if( lastSlash != std::string::npos )
+                processName = processName.substr( lastSlash+1 );
+            m_boundProcessName.set( config, processName );
+            std::vector<Parser::Token> tokens;
+            Parser parser;
+            parser.parseIntoTokens( argc, argv, tokens );
+            return populate( tokens, config );
+        }
+
+        std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            validate();
+            std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
+            unusedTokens = populateFixedArgs( unusedTokens, config );
+            unusedTokens = populateFloatingArgs( unusedTokens, config );
+            return unusedTokens;
+        }
+
+        std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            std::vector<std::string> errors;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+                for(; it != itEnd; ++it ) {
+                    Arg const& arg = *it;
+
+                    try {
+                        if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
+                            ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
+                            if( arg.takesArg() ) {
+                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
+                                    errors.push_back( "Expected argument to option: " + token.data );
+                                else
+                                    arg.boundField.set( config, tokens[++i].data );
+                            }
+                            else {
+                                arg.boundField.setFlag( config );
+                            }
+                            break;
+                        }
+                    }
+                    catch( std::exception& ex ) {
+                        errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
+                    }
+                }
+                if( it == itEnd ) {
+                    if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
+                        unusedTokens.push_back( token );
+                    else if( errors.empty() && m_throwOnUnrecognisedTokens )
+                        errors.push_back( "unrecognised option: " + token.data );
+                }
+            }
+            if( !errors.empty() ) {
+                std::ostringstream oss;
+                for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+                        it != itEnd;
+                        ++it ) {
+                    if( it != errors.begin() )
+                        oss << "\n";
+                    oss << *it;
+                }
+                throw std::runtime_error( oss.str() );
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            int position = 1;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
+                if( it != m_positionalArgs.end() )
+                    it->second.boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+                if( token.type == Parser::Token::Positional )
+                    position++;
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            if( !m_floatingArg.get() )
+                return tokens;
+            std::vector<Parser::Token> unusedTokens;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                if( token.type == Parser::Token::Positional )
+                    m_floatingArg->boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+            }
+            return unusedTokens;
+        }
+
+        void validate() const
+        {
+            if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
+                throw std::logic_error( "No options or arguments specified" );
+
+            for( typename std::vector<Arg>::const_iterator  it = m_options.begin(),
+                                                            itEnd = m_options.end();
+                    it != itEnd; ++it )
+                it->validate();
+        }
+
+    private:
+        Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+        std::vector<Arg> m_options;
+        std::map<int, Arg> m_positionalArgs;
+        ArgAutoPtr m_floatingArg;
+        int m_highestSpecifiedArgPosition;
+        bool m_throwOnUnrecognisedTokens;
+    };
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+
+namespace Catch {
+
+    inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
+    inline void abortAfterX( ConfigData& config, int x ) {
+        if( x < 1 )
+            throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
+        config.abortAfter = x;
+    }
+    inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+
+    inline void addWarning( ConfigData& config, std::string const& _warning ) {
+        if( _warning == "NoAssertions" )
+            config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+        else
+            throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
+    }
+    inline void setOrder( ConfigData& config, std::string const& order ) {
+        if( startsWith( "declared", order ) )
+            config.runOrder = RunTests::InDeclarationOrder;
+        else if( startsWith( "lexical", order ) )
+            config.runOrder = RunTests::InLexicographicalOrder;
+        else if( startsWith( "random", order ) )
+            config.runOrder = RunTests::InRandomOrder;
+        else
+            throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
+    }
+    inline void setRngSeed( ConfigData& config, std::string const& seed ) {
+        if( seed == "time" ) {
+            config.rngSeed = static_cast<unsigned int>( std::time(0) );
+        }
+        else {
+            std::stringstream ss;
+            ss << seed;
+            ss >> config.rngSeed;
+            if( ss.fail() )
+                throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
+        }
+    }
+    inline void setVerbosity( ConfigData& config, int level ) {
+        // !TBD: accept strings?
+        config.verbosity = static_cast<Verbosity::Level>( level );
+    }
+    inline void setShowDurations( ConfigData& config, bool _showDurations ) {
+        config.showDurations = _showDurations
+            ? ShowDurations::Always
+            : ShowDurations::Never;
+    }
+    inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
+        std::ifstream f( _filename.c_str() );
+        if( !f.is_open() )
+            throw std::domain_error( "Unable to load input file: " + _filename );
+
+        std::string line;
+        while( std::getline( f, line ) ) {
+            line = trim(line);
+            if( !line.empty() && !startsWith( line, "#" ) )
+                addTestOrTags( config, "\"" + line + "\"," );
+        }
+    }
+
+    inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
+
+        using namespace Clara;
+        CommandLine<ConfigData> cli;
+
+        cli.bindProcessName( &ConfigData::processName );
+
+        cli["-?"]["-h"]["--help"]
+            .describe( "display usage information" )
+            .bind( &ConfigData::showHelp );
+
+        cli["-l"]["--list-tests"]
+            .describe( "list all/matching test cases" )
+            .bind( &ConfigData::listTests );
+
+        cli["-t"]["--list-tags"]
+            .describe( "list all/matching tags" )
+            .bind( &ConfigData::listTags );
+
+        cli["-s"]["--success"]
+            .describe( "include successful tests in output" )
+            .bind( &ConfigData::showSuccessfulTests );
+
+        cli["-b"]["--break"]
+            .describe( "break into debugger on failure" )
+            .bind( &ConfigData::shouldDebugBreak );
+
+        cli["-e"]["--nothrow"]
+            .describe( "skip exception tests" )
+            .bind( &ConfigData::noThrow );
+
+        cli["-i"]["--invisibles"]
+            .describe( "show invisibles (tabs, newlines)" )
+            .bind( &ConfigData::showInvisibles );
+
+        cli["-o"]["--out"]
+            .describe( "output filename" )
+            .bind( &ConfigData::outputFilename, "filename" );
+
+        cli["-r"]["--reporter"]
+//            .placeholder( "name[:filename]" )
+            .describe( "reporter to use (defaults to console)" )
+            .bind( &ConfigData::reporterName, "name" );
+
+        cli["-n"]["--name"]
+            .describe( "suite name" )
+            .bind( &ConfigData::name, "name" );
+
+        cli["-a"]["--abort"]
+            .describe( "abort at first failure" )
+            .bind( &abortAfterFirst );
+
+        cli["-x"]["--abortx"]
+            .describe( "abort after x failures" )
+            .bind( &abortAfterX, "no. failures" );
+
+        cli["-w"]["--warn"]
+            .describe( "enable warnings" )
+            .bind( &addWarning, "warning name" );
+
+// - needs updating if reinstated
+//        cli.into( &setVerbosity )
+//            .describe( "level of verbosity (0=no output)" )
+//            .shortOpt( "v")
+//            .longOpt( "verbosity" )
+//            .placeholder( "level" );
+
+        cli[_]
+            .describe( "which test or tests to use" )
+            .bind( &addTestOrTags, "test name, pattern or tags" );
+
+        cli["-d"]["--durations"]
+            .describe( "show test durations" )
+            .bind( &setShowDurations, "yes/no" );
+
+        cli["-f"]["--input-file"]
+            .describe( "load test names to run from a file" )
+            .bind( &loadTestNamesFromFile, "filename" );
+
+        // Less common commands which don't have a short form
+        cli["--list-test-names-only"]
+            .describe( "list all/matching test cases names only" )
+            .bind( &ConfigData::listTestNamesOnly );
+
+        cli["--list-reporters"]
+            .describe( "list all reporters" )
+            .bind( &ConfigData::listReporters );
+
+        cli["--order"]
+            .describe( "test case order (defaults to decl)" )
+            .bind( &setOrder, "decl|lex|rand" );
+
+        cli["--rng-seed"]
+            .describe( "set a specific seed for random numbers" )
+            .bind( &setRngSeed, "'time'|number" );
+
+        cli["--force-colour"]
+            .describe( "force colourised output" )
+            .bind( &ConfigData::forceColour );
+
+        return cli;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#  ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#   define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#  endif
+# else
+#  define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+    using Tbc::Text;
+    using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+    struct Colour {
+        enum Code {
+            None = 0,
+
+            White,
+            Red,
+            Green,
+            Blue,
+            Cyan,
+            Yellow,
+            Grey,
+
+            Bright = 0x10,
+
+            BrightRed = Bright | Red,
+            BrightGreen = Bright | Green,
+            LightGrey = Bright | Grey,
+            BrightWhite = Bright | White,
+
+            // By intention
+            FileName = LightGrey,
+            Warning = Yellow,
+            ResultError = BrightRed,
+            ResultSuccess = BrightGreen,
+            ResultExpectedFailure = Warning,
+
+            Error = BrightRed,
+            Success = Green,
+
+            OriginalExpression = Cyan,
+            ReconstructedExpression = Yellow,
+
+            SecondaryText = LightGrey,
+            Headers = White
+        };
+
+        // Use constructed object for RAII guard
+        Colour( Code _colourCode );
+        Colour( Colour const& other );
+        ~Colour();
+
+        // Use static method for one-shot changes
+        static void use( Code _colourCode );
+
+    private:
+        bool m_moved;
+    };
+
+    inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <string>
+#include <ostream>
+#include <map>
+#include <assert.h>
+
+namespace Catch
+{
+    struct ReporterConfig {
+        explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
+        :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+        ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
+        :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+        std::ostream& stream() const    { return *m_stream; }
+        Ptr<IConfig> fullConfig() const { return m_fullConfig; }
+
+    private:
+        std::ostream* m_stream;
+        Ptr<IConfig> m_fullConfig;
+    };
+
+    struct ReporterPreferences {
+        ReporterPreferences()
+        : shouldRedirectStdOut( false )
+        {}
+
+        bool shouldRedirectStdOut;
+    };
+
+    template<typename T>
+    struct LazyStat : Option<T> {
+        LazyStat() : used( false ) {}
+        LazyStat& operator=( T const& _value ) {
+            Option<T>::operator=( _value );
+            used = false;
+            return *this;
+        }
+        void reset() {
+            Option<T>::reset();
+            used = false;
+        }
+        bool used;
+    };
+
+    struct TestRunInfo {
+        TestRunInfo( std::string const& _name ) : name( _name ) {}
+        std::string name;
+    };
+    struct GroupInfo {
+        GroupInfo(  std::string const& _name,
+                    std::size_t _groupIndex,
+                    std::size_t _groupsCount )
+        :   name( _name ),
+            groupIndex( _groupIndex ),
+            groupsCounts( _groupsCount )
+        {}
+
+        std::string name;
+        std::size_t groupIndex;
+        std::size_t groupsCounts;
+    };
+
+    struct AssertionStats {
+        AssertionStats( AssertionResult const& _assertionResult,
+                        std::vector<MessageInfo> const& _infoMessages,
+                        Totals const& _totals )
+        :   assertionResult( _assertionResult ),
+            infoMessages( _infoMessages ),
+            totals( _totals )
+        {
+            if( assertionResult.hasMessage() ) {
+                // Copy message into messages list.
+                // !TBD This should have been done earlier, somewhere
+                MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+                builder << assertionResult.getMessage();
+                builder.m_info.message = builder.m_stream.str();
+
+                infoMessages.push_back( builder.m_info );
+            }
+        }
+        virtual ~AssertionStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        AssertionStats( AssertionStats const& )              = default;
+        AssertionStats( AssertionStats && )                  = default;
+        AssertionStats& operator = ( AssertionStats const& ) = default;
+        AssertionStats& operator = ( AssertionStats && )     = default;
+#  endif
+
+        AssertionResult assertionResult;
+        std::vector<MessageInfo> infoMessages;
+        Totals totals;
+    };
+
+    struct SectionStats {
+        SectionStats(   SectionInfo const& _sectionInfo,
+                        Counts const& _assertions,
+                        double _durationInSeconds,
+                        bool _missingAssertions )
+        :   sectionInfo( _sectionInfo ),
+            assertions( _assertions ),
+            durationInSeconds( _durationInSeconds ),
+            missingAssertions( _missingAssertions )
+        {}
+        virtual ~SectionStats();
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        SectionStats( SectionStats const& )              = default;
+        SectionStats( SectionStats && )                  = default;
+        SectionStats& operator = ( SectionStats const& ) = default;
+        SectionStats& operator = ( SectionStats && )     = default;
+#  endif
+
+        SectionInfo sectionInfo;
+        Counts assertions;
+        double durationInSeconds;
+        bool missingAssertions;
+    };
+
+    struct TestCaseStats {
+        TestCaseStats(  TestCaseInfo const& _testInfo,
+                        Totals const& _totals,
+                        std::string const& _stdOut,
+                        std::string const& _stdErr,
+                        bool _aborting )
+        : testInfo( _testInfo ),
+            totals( _totals ),
+            stdOut( _stdOut ),
+            stdErr( _stdErr ),
+            aborting( _aborting )
+        {}
+        virtual ~TestCaseStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestCaseStats( TestCaseStats const& )              = default;
+        TestCaseStats( TestCaseStats && )                  = default;
+        TestCaseStats& operator = ( TestCaseStats const& ) = default;
+        TestCaseStats& operator = ( TestCaseStats && )     = default;
+#  endif
+
+        TestCaseInfo testInfo;
+        Totals totals;
+        std::string stdOut;
+        std::string stdErr;
+        bool aborting;
+    };
+
+    struct TestGroupStats {
+        TestGroupStats( GroupInfo const& _groupInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   groupInfo( _groupInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        TestGroupStats( GroupInfo const& _groupInfo )
+        :   groupInfo( _groupInfo ),
+            aborting( false )
+        {}
+        virtual ~TestGroupStats();
+
+#  ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestGroupStats( TestGroupStats const& )              = default;
+        TestGroupStats( TestGroupStats && )                  = default;
+        TestGroupStats& operator = ( TestGroupStats const& ) = default;
+        TestGroupStats& operator = ( TestGroupStats && )     = default;
+#  endif
+
+        GroupInfo groupInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct TestRunStats {
+        TestRunStats(   TestRunInfo const& _runInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   runInfo( _runInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        virtual ~TestRunStats();
+
+#  ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS
+        TestRunStats( TestRunStats const& _other )
+        :   runInfo( _other.runInfo ),
+            totals( _other.totals ),
+            aborting( _other.aborting )
+        {}
+#  else
+        TestRunStats( TestRunStats const& )              = default;
+        TestRunStats( TestRunStats && )                  = default;
+        TestRunStats& operator = ( TestRunStats const& ) = default;
+        TestRunStats& operator = ( TestRunStats && )     = default;
+#  endif
+
+        TestRunInfo runInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct IStreamingReporter : IShared {
+        virtual ~IStreamingReporter();
+
+        // Implementing class must also provide the following static method:
+        // static std::string getDescription();
+
+        virtual ReporterPreferences getPreferences() const = 0;
+
+        virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+        // The return value indicates if the messages buffer should be cleared:
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+        virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
+    };
+
+    struct IReporterFactory {
+        virtual ~IReporterFactory();
+        virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
+        virtual std::string getDescription() const = 0;
+    };
+
+    struct IReporterRegistry {
+        typedef std::map<std::string, IReporterFactory*> FactoryMap;
+
+        virtual ~IReporterRegistry();
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
+        virtual FactoryMap const& getFactories() const = 0;
+    };
+
+}
+
+#include <limits>
+#include <algorithm>
+
+namespace Catch {
+
+    inline std::size_t listTests( Config const& config ) {
+
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Matching test cases:\n";
+        else {
+            Catch::cout() << "All available test cases:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::size_t matchedTests = 0;
+        TextAttributes nameAttr, tagsAttr;
+        nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+        tagsAttr.setIndent( 6 );
+
+        std::vector<TestCase> matchedTestCases;
+        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            Colour::Code colour = testCaseInfo.isHidden()
+                ? Colour::SecondaryText
+                : Colour::None;
+            Colour colourGuard( colour );
+
+            Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
+            if( !testCaseInfo.tags.empty() )
+                Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
+        }
+
+        if( !config.testSpec().hasFilters() )
+            Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
+        else
+            Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
+        return matchedTests;
+    }
+
+    inline std::size_t listTestsNamesOnly( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( !config.testSpec().hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        std::size_t matchedTests = 0;
+        std::vector<TestCase> matchedTestCases;
+        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            Catch::cout() << testCaseInfo.name << std::endl;
+        }
+        return matchedTests;
+    }
+
+    struct TagInfo {
+        TagInfo() : count ( 0 ) {}
+        void add( std::string const& spelling ) {
+            ++count;
+            spellings.insert( spelling );
+        }
+        std::string all() const {
+            std::string out;
+            for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+                        it != itEnd;
+                        ++it )
+                out += "[" + *it + "]";
+            return out;
+        }
+        std::set<std::string> spellings;
+        std::size_t count;
+    };
+
+    inline std::size_t listTags( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            Catch::cout() << "Tags for matching test cases:\n";
+        else {
+            Catch::cout() << "All available tags:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::map<std::string, TagInfo> tagCounts;
+
+        std::vector<TestCase> matchedTestCases;
+        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
+                                                        tagItEnd = it->getTestCaseInfo().tags.end();
+                    tagIt != tagItEnd;
+                    ++tagIt ) {
+                std::string tagName = *tagIt;
+                std::string lcaseTagName = toLower( tagName );
+                std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
+                if( countIt == tagCounts.end() )
+                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+                countIt->second.add( tagName );
+            }
+        }
+
+        for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+                                                            countItEnd = tagCounts.end();
+                countIt != countItEnd;
+                ++countIt ) {
+            std::ostringstream oss;
+            oss << "  " << std::setw(2) << countIt->second.count << "  ";
+            Text wrapper( countIt->second.all(), TextAttributes()
+                                                    .setInitialIndent( 0 )
+                                                    .setIndent( oss.str().size() )
+                                                    .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
+            Catch::cout() << oss.str() << wrapper << "\n";
+        }
+        Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
+        return tagCounts.size();
+    }
+
+    inline std::size_t listReporters( Config const& /*config*/ ) {
+        Catch::cout() << "Available reporters:\n";
+        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+        IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+        std::size_t maxNameLen = 0;
+        for(it = itBegin; it != itEnd; ++it )
+            maxNameLen = (std::max)( maxNameLen, it->first.size() );
+
+        for(it = itBegin; it != itEnd; ++it ) {
+            Text wrapper( it->second->getDescription(), TextAttributes()
+                                                        .setInitialIndent( 0 )
+                                                        .setIndent( 7+maxNameLen )
+                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
+            Catch::cout() << "  "
+                    << it->first
+                    << ":"
+                    << std::string( maxNameLen - it->first.size() + 2, ' ' )
+                    << wrapper << "\n";
+        }
+        Catch::cout() << std::endl;
+        return factories.size();
+    }
+
+    inline Option<std::size_t> list( Config const& config ) {
+        Option<std::size_t> listedCount;
+        if( config.listTests() )
+            listedCount = listedCount.valueOr(0) + listTests( config );
+        if( config.listTestNamesOnly() )
+            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+        if( config.listTags() )
+            listedCount = listedCount.valueOr(0) + listTags( config );
+        if( config.listReporters() )
+            listedCount = listedCount.valueOr(0) + listReporters( config );
+        return listedCount;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_runner_impl.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <assert.h>
+
+namespace Catch {
+namespace SectionTracking {
+
+    class TrackedSection {
+
+        typedef std::map<std::string, TrackedSection> TrackedSections;
+
+    public:
+        enum RunState {
+            NotStarted,
+            Executing,
+            ExecutingChildren,
+            Completed
+        };
+
+        TrackedSection( std::string const& name, TrackedSection* parent )
+        :   m_name( name ), m_runState( NotStarted ), m_parent( parent )
+        {}
+
+        RunState runState() const { return m_runState; }
+
+        TrackedSection* findChild( std::string const& childName ) {
+            TrackedSections::iterator it = m_children.find( childName );
+            return it != m_children.end()
+                ? &it->second
+                : NULL;
+        }
+        TrackedSection* acquireChild( std::string const& childName ) {
+            if( TrackedSection* child = findChild( childName ) )
+                return child;
+            m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
+            return findChild( childName );
+        }
+        void enter() {
+            if( m_runState == NotStarted )
+                m_runState = Executing;
+        }
+        void leave() {
+            for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
+                    it != itEnd;
+                    ++it )
+                if( it->second.runState() != Completed ) {
+                    m_runState = ExecutingChildren;
+                    return;
+                }
+            m_runState = Completed;
+        }
+        TrackedSection* getParent() {
+            return m_parent;
+        }
+        bool hasChildren() const {
+            return !m_children.empty();
+        }
+
+    private:
+        std::string m_name;
+        RunState m_runState;
+        TrackedSections m_children;
+        TrackedSection* m_parent;
+
+    };
+
+    class TestCaseTracker {
+    public:
+        TestCaseTracker( std::string const& testCaseName )
+        :   m_testCase( testCaseName, NULL ),
+            m_currentSection( &m_testCase ),
+            m_completedASectionThisRun( false )
+        {}
+
+        bool enterSection( std::string const& name ) {
+            TrackedSection* child = m_currentSection->acquireChild( name );
+            if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
+                return false;
+
+            m_currentSection = child;
+            m_currentSection->enter();
+            return true;
+        }
+        void leaveSection() {
+            m_currentSection->leave();
+            m_currentSection = m_currentSection->getParent();
+            assert( m_currentSection != NULL );
+            m_completedASectionThisRun = true;
+        }
+
+        bool currentSectionHasChildren() const {
+            return m_currentSection->hasChildren();
+        }
+        bool isCompleted() const {
+            return m_testCase.runState() == TrackedSection::Completed;
+        }
+
+        class Guard {
+        public:
+            Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
+                m_tracker.enterTestCase();
+            }
+            ~Guard() {
+                m_tracker.leaveTestCase();
+            }
+        private:
+            Guard( Guard const& );
+            void operator = ( Guard const& );
+            TestCaseTracker& m_tracker;
+        };
+
+    private:
+        void enterTestCase() {
+            m_currentSection = &m_testCase;
+            m_completedASectionThisRun = false;
+            m_testCase.enter();
+        }
+        void leaveTestCase() {
+            m_testCase.leave();
+        }
+
+        TrackedSection m_testCase;
+        TrackedSection* m_currentSection;
+        bool m_completedASectionThisRun;
+    };
+
+} // namespace SectionTracking
+
+using SectionTracking::TestCaseTracker;
+
+} // namespace Catch
+
+// #included from: catch_fatal_condition.hpp
+#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
+
+namespace Catch {
+
+    // Report the error condition then exit the process
+    inline void fatal( std::string const& message, int exitCode ) {
+        IContext& context = Catch::getCurrentContext();
+        IResultCapture* resultCapture = context.getResultCapture();
+        resultCapture->handleFatalErrorCondition( message );
+
+		if( Catch::alwaysTrue() ) // avoids "no return" warnings
+            exit( exitCode );
+    }
+
+} // namespace Catch
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+
+namespace Catch {
+
+    struct FatalConditionHandler {
+		void reset() {}
+	};
+
+} // namespace Catch
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#include <signal.h>
+
+namespace Catch {
+
+    struct SignalDefs { int id; const char* name; };
+    extern SignalDefs signalDefs[];
+    SignalDefs signalDefs[] = {
+            { SIGINT,  "SIGINT - Terminal interrupt signal" },
+            { SIGILL,  "SIGILL - Illegal instruction signal" },
+            { SIGFPE,  "SIGFPE - Floating point error signal" },
+            { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
+            { SIGTERM, "SIGTERM - Termination request signal" },
+            { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
+        };
+
+    struct FatalConditionHandler {
+
+        static void handleSignal( int sig ) {
+            for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
+                if( sig == signalDefs[i].id )
+                    fatal( signalDefs[i].name, -sig );
+            fatal( "<unknown signal>", -sig );
+        }
+
+        FatalConditionHandler() : m_isSet( true ) {
+            for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
+                signal( signalDefs[i].id, handleSignal );
+        }
+        ~FatalConditionHandler() {
+            reset();
+        }
+        void reset() {
+            if( m_isSet ) {
+                for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
+                    signal( signalDefs[i].id, SIG_DFL );
+                m_isSet = false;
+            }
+        }
+
+        bool m_isSet;
+    };
+
+} // namespace Catch
+
+#endif // not Windows
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+    class StreamRedirect {
+
+    public:
+        StreamRedirect( std::ostream& stream, std::string& targetString )
+        :   m_stream( stream ),
+            m_prevBuf( stream.rdbuf() ),
+            m_targetString( targetString )
+        {
+            stream.rdbuf( m_oss.rdbuf() );
+        }
+
+        ~StreamRedirect() {
+            m_targetString += m_oss.str();
+            m_stream.rdbuf( m_prevBuf );
+        }
+
+    private:
+        std::ostream& m_stream;
+        std::streambuf* m_prevBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class RunContext : public IResultCapture, public IRunner {
+
+        RunContext( RunContext const& );
+        void operator =( RunContext const& );
+
+    public:
+
+        explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
+        :   m_runInfo( config->name() ),
+            m_context( getCurrentMutableContext() ),
+            m_activeTestCase( NULL ),
+            m_config( config ),
+            m_reporter( reporter ),
+            m_prevRunner( m_context.getRunner() ),
+            m_prevResultCapture( m_context.getResultCapture() ),
+            m_prevConfig( m_context.getConfig() )
+        {
+            m_context.setRunner( this );
+            m_context.setConfig( m_config );
+            m_context.setResultCapture( this );
+            m_reporter->testRunStarting( m_runInfo );
+        }
+
+        virtual ~RunContext() {
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
+            m_context.setRunner( m_prevRunner );
+            m_context.setConfig( NULL );
+            m_context.setResultCapture( m_prevResultCapture );
+            m_context.setConfig( m_prevConfig );
+        }
+
+        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
+        }
+        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
+        }
+
+        Totals runTest( TestCase const& testCase ) {
+            Totals prevTotals = m_totals;
+
+            std::string redirectedCout;
+            std::string redirectedCerr;
+
+            TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+            m_reporter->testCaseStarting( testInfo );
+
+            m_activeTestCase = &testCase;
+            m_testCaseTracker = TestCaseTracker( testInfo.name );
+
+            do {
+                do {
+                    runCurrentTest( redirectedCout, redirectedCerr );
+                }
+                while( !m_testCaseTracker->isCompleted() && !aborting() );
+            }
+            while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
+
+            Totals deltaTotals = m_totals.delta( prevTotals );
+            m_totals.testCases += deltaTotals.testCases;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        redirectedCout,
+                                                        redirectedCerr,
+                                                        aborting() ) );
+
+            m_activeTestCase = NULL;
+            m_testCaseTracker.reset();
+
+            return deltaTotals;
+        }
+
+        Ptr<IConfig const> config() const {
+            return m_config;
+        }
+
+    private: // IResultCapture
+
+        virtual void assertionEnded( AssertionResult const& result ) {
+            if( result.getResultType() == ResultWas::Ok ) {
+                m_totals.assertions.passed++;
+            }
+            else if( !result.isOk() ) {
+                m_totals.assertions.failed++;
+            }
+
+            if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
+                m_messages.clear();
+
+            // Reset working state
+            m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+            m_lastResult = result;
+        }
+
+        virtual bool sectionStarted (
+            SectionInfo const& sectionInfo,
+            Counts& assertions
+        )
+        {
+            std::ostringstream oss;
+            oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
+
+            if( !m_testCaseTracker->enterSection( oss.str() ) )
+                return false;
+
+            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+            m_reporter->sectionStarting( sectionInfo );
+
+            assertions = m_totals.assertions;
+
+            return true;
+        }
+        bool testForMissingAssertions( Counts& assertions ) {
+            if( assertions.total() != 0 ||
+                    !m_config->warnAboutMissingAssertions() ||
+                    m_testCaseTracker->currentSectionHasChildren() )
+                return false;
+            m_totals.assertions.failed++;
+            assertions.failed++;
+            return true;
+        }
+
+        virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
+            if( std::uncaught_exception() ) {
+                m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
+                return;
+            }
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            m_testCaseTracker->leaveSection();
+
+            m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
+            m_messages.clear();
+        }
+
+        virtual void pushScopedMessage( MessageInfo const& message ) {
+            m_messages.push_back( message );
+        }
+
+        virtual void popScopedMessage( MessageInfo const& message ) {
+            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
+        }
+
+        virtual std::string getCurrentTestName() const {
+            return m_activeTestCase
+                ? m_activeTestCase->getTestCaseInfo().name
+                : "";
+        }
+
+        virtual const AssertionResult* getLastResult() const {
+            return &m_lastResult;
+        }
+
+        virtual void handleFatalErrorCondition( std::string const& message ) {
+            ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
+            resultBuilder.setResultType( ResultWas::FatalErrorCondition );
+            resultBuilder << message;
+            resultBuilder.captureExpression();
+
+            handleUnfinishedSections();
+
+            // Recreate section for test case (as we will lose the one that was in scope)
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+
+            Counts assertions;
+            assertions.failed = 1;
+            SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
+            m_reporter->sectionEnded( testCaseSectionStats );
+
+            TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
+
+            Totals deltaTotals;
+            deltaTotals.testCases.failed = 1;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        "",
+                                                        "",
+                                                        false ) );
+            m_totals.testCases.failed++;
+            testGroupEnded( "", m_totals, 1, 1 );
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
+        }
+
+    public:
+        // !TBD We need to do this another way!
+        bool aborting() const {
+            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
+        }
+
+    private:
+
+        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+            m_reporter->sectionStarting( testCaseSection );
+            Counts prevAssertions = m_totals.assertions;
+            double duration = 0;
+            try {
+                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
+                TestCaseTracker::Guard guard( *m_testCaseTracker );
+
+                Timer timer;
+                timer.start();
+                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
+                    StreamRedirect coutRedir( Catch::cout(), redirectedCout );
+                    StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
+                    invokeActiveTestCase();
+                }
+                else {
+                    invokeActiveTestCase();
+                }
+                duration = timer.getElapsedSeconds();
+            }
+            catch( TestFailureException& ) {
+                // This just means the test was aborted due to failure
+            }
+            catch(...) {
+                makeUnexpectedResultBuilder().useActiveException();
+            }
+            handleUnfinishedSections();
+            m_messages.clear();
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            if( testCaseInfo.okToFail() ) {
+                std::swap( assertions.failedButOk, assertions.failed );
+                m_totals.assertions.failed -= assertions.failedButOk;
+                m_totals.assertions.failedButOk += assertions.failedButOk;
+            }
+
+            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
+            m_reporter->sectionEnded( testCaseSectionStats );
+        }
+
+        void invokeActiveTestCase() {
+            FatalConditionHandler fatalConditionHandler; // Handle signals
+            m_activeTestCase->invoke();
+            fatalConditionHandler.reset();
+        }
+
+    private:
+
+        ResultBuilder makeUnexpectedResultBuilder() const {
+            return ResultBuilder(   m_lastAssertionInfo.macroName.c_str(),
+                                    m_lastAssertionInfo.lineInfo,
+                                    m_lastAssertionInfo.capturedExpression.c_str(),
+                                    m_lastAssertionInfo.resultDisposition );
+        }
+
+        void handleUnfinishedSections() {
+            // If sections ended prematurely due to an exception we stored their
+            // infos here so we can tear them down outside the unwind process.
+            for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+                        itEnd = m_unfinishedSections.rend();
+                    it != itEnd;
+                    ++it )
+                sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
+            m_unfinishedSections.clear();
+        }
+
+        struct UnfinishedSections {
+            UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
+            : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
+            {}
+
+            SectionInfo info;
+            Counts prevAssertions;
+            double durationInSeconds;
+        };
+
+        TestRunInfo m_runInfo;
+        IMutableContext& m_context;
+        TestCase const* m_activeTestCase;
+        Option<TestCaseTracker> m_testCaseTracker;
+        AssertionResult m_lastResult;
+
+        Ptr<IConfig const> m_config;
+        Totals m_totals;
+        Ptr<IStreamingReporter> m_reporter;
+        std::vector<MessageInfo> m_messages;
+        IRunner* m_prevRunner;
+        IResultCapture* m_prevResultCapture;
+        Ptr<IConfig const> m_prevConfig;
+        AssertionInfo m_lastAssertionInfo;
+        std::vector<UnfinishedSections> m_unfinishedSections;
+    };
+
+    IResultCapture& getResultCapture() {
+        if( IResultCapture* capture = getCurrentContext().getResultCapture() )
+            return *capture;
+        else
+            throw std::logic_error( "No result capture instance" );
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+    // Versioning information
+    struct Version {
+        Version(    unsigned int _majorVersion,
+                    unsigned int _minorVersion,
+                    unsigned int _buildNumber,
+                    char const* const _branchName )
+        :   majorVersion( _majorVersion ),
+            minorVersion( _minorVersion ),
+            buildNumber( _buildNumber ),
+            branchName( _branchName )
+        {}
+
+        unsigned int const majorVersion;
+        unsigned int const minorVersion;
+        unsigned int const buildNumber;
+        char const* const branchName;
+
+    private:
+        void operator=( Version const& );
+    };
+
+    extern Version libraryVersion;
+}
+
+#include <fstream>
+#include <stdlib.h>
+#include <limits>
+
+namespace Catch {
+
+    class Runner {
+
+    public:
+        Runner( Ptr<Config> const& config )
+        :   m_config( config )
+        {
+            openStream();
+            makeReporter();
+        }
+
+        Totals runTests() {
+
+            RunContext context( m_config.get(), m_reporter );
+
+            Totals totals;
+
+            context.testGroupStarting( "all tests", 1, 1 ); // deprecated?
+
+            TestSpec testSpec = m_config->testSpec();
+            if( !testSpec.hasFilters() )
+                testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
+
+            std::vector<TestCase> testCases;
+            getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
+
+            int testsRunForGroup = 0;
+            for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+                    it != itEnd;
+                    ++it ) {
+                testsRunForGroup++;
+                if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
+
+                    if( context.aborting() )
+                        break;
+
+                    totals += context.runTest( *it );
+                    m_testsAlreadyRun.insert( *it );
+                }
+            }
+            std::vector<TestCase> skippedTestCases;
+            getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true );
+
+            for( std::vector<TestCase>::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end();
+                    it != itEnd;
+                    ++it )
+                m_reporter->skipTest( *it );
+
+            context.testGroupEnded( "all tests", totals, 1, 1 );
+            return totals;
+        }
+
+    private:
+        void openStream() {
+            // Open output file, if specified
+            if( !m_config->getFilename().empty() ) {
+                m_ofs.open( m_config->getFilename().c_str() );
+                if( m_ofs.fail() ) {
+                    std::ostringstream oss;
+                    oss << "Unable to open file: '" << m_config->getFilename() << "'";
+                    throw std::domain_error( oss.str() );
+                }
+                m_config->setStreamBuf( m_ofs.rdbuf() );
+            }
+        }
+        void makeReporter() {
+            std::string reporterName = m_config->getReporterName().empty()
+                ? "console"
+                : m_config->getReporterName();
+
+            m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
+            if( !m_reporter ) {
+                std::ostringstream oss;
+                oss << "No reporter registered with name: '" << reporterName << "'";
+                throw std::domain_error( oss.str() );
+            }
+        }
+
+    private:
+        Ptr<Config> m_config;
+        std::ofstream m_ofs;
+        Ptr<IStreamingReporter> m_reporter;
+        std::set<TestCase> m_testsAlreadyRun;
+    };
+
+    class Session : NonCopyable {
+        static bool alreadyInstantiated;
+
+    public:
+
+        struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
+
+        Session()
+        : m_cli( makeCommandLineParser() ) {
+            if( alreadyInstantiated ) {
+                std::string msg = "Only one instance of Catch::Session can ever be used";
+                Catch::cerr() << msg << std::endl;
+                throw std::logic_error( msg );
+            }
+            alreadyInstantiated = true;
+        }
+        ~Session() {
+            Catch::cleanUp();
+        }
+
+        void showHelp( std::string const& processName ) {
+            Catch::cout() << "\nCatch v"    << libraryVersion.majorVersion << "."
+                                        << libraryVersion.minorVersion << " build "
+                                        << libraryVersion.buildNumber;
+            if( libraryVersion.branchName != std::string( "master" ) )
+                Catch::cout() << " (" << libraryVersion.branchName << " branch)";
+            Catch::cout() << "\n";
+
+            m_cli.usage( Catch::cout(), processName );
+            Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
+        }
+
+        int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
+            try {
+                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
+                m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
+                if( m_configData.showHelp )
+                    showHelp( m_configData.processName );
+                m_config.reset();
+            }
+            catch( std::exception& ex ) {
+                {
+                    Colour colourGuard( Colour::Red );
+                    Catch::cerr()   << "\nError(s) in input:\n"
+                                << Text( ex.what(), TextAttributes().setIndent(2) )
+                                << "\n\n";
+                }
+                m_cli.usage( Catch::cout(), m_configData.processName );
+                return (std::numeric_limits<int>::max)();
+            }
+            return 0;
+        }
+
+        void useConfigData( ConfigData const& _configData ) {
+            m_configData = _configData;
+            m_config.reset();
+        }
+
+        int run( int argc, char* const argv[] ) {
+
+            int returnCode = applyCommandLine( argc, argv );
+            if( returnCode == 0 )
+                returnCode = run();
+            return returnCode;
+        }
+
+        int run() {
+            if( m_configData.showHelp )
+                return 0;
+
+            try
+            {
+                config(); // Force config to be constructed
+
+                std::srand( m_configData.rngSeed );
+
+                Runner runner( m_config );
+
+                // Handle list request
+                if( Option<std::size_t> listed = list( config() ) )
+                    return static_cast<int>( *listed );
+
+                return static_cast<int>( runner.runTests().assertions.failed );
+            }
+            catch( std::exception& ex ) {
+                Catch::cerr() << ex.what() << std::endl;
+                return (std::numeric_limits<int>::max)();
+            }
+        }
+
+        Clara::CommandLine<ConfigData> const& cli() const {
+            return m_cli;
+        }
+        std::vector<Clara::Parser::Token> const& unusedTokens() const {
+            return m_unusedTokens;
+        }
+        ConfigData& configData() {
+            return m_configData;
+        }
+        Config& config() {
+            if( !m_config )
+                m_config = new Config( m_configData );
+            return *m_config;
+        }
+
+    private:
+        Clara::CommandLine<ConfigData> m_cli;
+        std::vector<Clara::Parser::Token> m_unusedTokens;
+        ConfigData m_configData;
+        Ptr<Config> m_config;
+    };
+
+    bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+
+namespace Catch {
+
+    class TestRegistry : public ITestCaseRegistry {
+        struct LexSort {
+            bool operator() (TestCase i,TestCase j) const { return (i<j);}
+        };
+        struct RandomNumberGenerator {
+            int operator()( int n ) const { return std::rand() % n; }
+        };
+
+    public:
+        TestRegistry() : m_unnamedCount( 0 ) {}
+        virtual ~TestRegistry();
+
+        virtual void registerTest( TestCase const& testCase ) {
+            std::string name = testCase.getTestCaseInfo().name;
+            if( name == "" ) {
+                std::ostringstream oss;
+                oss << "Anonymous test case " << ++m_unnamedCount;
+                return registerTest( testCase.withName( oss.str() ) );
+            }
+
+            if( m_functions.find( testCase ) == m_functions.end() ) {
+                m_functions.insert( testCase );
+                m_functionsInOrder.push_back( testCase );
+                if( !testCase.isHidden() )
+                    m_nonHiddenFunctions.push_back( testCase );
+            }
+            else {
+                TestCase const& prev = *m_functions.find( testCase );
+                {
+                    Colour colourGuard( Colour::Red );
+                    Catch::cerr()   << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
+                                << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
+                                << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
+                }
+                exit(1);
+            }
+        }
+
+        virtual std::vector<TestCase> const& getAllTests() const {
+            return m_functionsInOrder;
+        }
+
+        virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
+            return m_nonHiddenFunctions;
+        }
+
+        virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const {
+
+            for( std::vector<TestCase>::const_iterator  it = m_functionsInOrder.begin(),
+                                                        itEnd = m_functionsInOrder.end();
+                    it != itEnd;
+                    ++it ) {
+                bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() );
+                if( includeTest != negated )
+                    matchingTestCases.push_back( *it );
+            }
+            sortTests( config, matchingTestCases );
+        }
+
+    private:
+
+        static void sortTests( IConfig const& config, std::vector<TestCase>& matchingTestCases ) {
+
+            switch( config.runOrder() ) {
+                case RunTests::InLexicographicalOrder:
+                    std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() );
+                    break;
+                case RunTests::InRandomOrder:
+                {
+                    RandomNumberGenerator rng;
+                    std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng );
+                }
+                    break;
+                case RunTests::InDeclarationOrder:
+                    // already in declaration order
+                    break;
+            }
+        }
+        std::set<TestCase> m_functions;
+        std::vector<TestCase> m_functionsInOrder;
+        std::vector<TestCase> m_nonHiddenFunctions;
+        size_t m_unnamedCount;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class FreeFunctionTestCase : public SharedImpl<ITestCase> {
+    public:
+
+        FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
+
+        virtual void invoke() const {
+            m_fun();
+        }
+
+    private:
+        virtual ~FreeFunctionTestCase();
+
+        TestFunction m_fun;
+    };
+
+    inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+        std::string className = classOrQualifiedMethodName;
+        if( startsWith( className, "&" ) )
+        {
+            std::size_t lastColons = className.rfind( "::" );
+            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+            if( penultimateColons == std::string::npos )
+                penultimateColons = 1;
+            className = className.substr( penultimateColons, lastColons-penultimateColons );
+        }
+        return className;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    AutoReg::AutoReg(   TestFunction function,
+                        SourceLineInfo const& lineInfo,
+                        NameAndDesc const& nameAndDesc ) {
+        registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
+    }
+
+    AutoReg::~AutoReg() {}
+
+    void AutoReg::registerTestCase( ITestCase* testCase,
+                                    char const* classOrQualifiedMethodName,
+                                    NameAndDesc const& nameAndDesc,
+                                    SourceLineInfo const& lineInfo ) {
+
+        getMutableRegistryHub().registerTest
+            ( makeTestCase( testCase,
+                            extractClassName( classOrQualifiedMethodName ),
+                            nameAndDesc.name,
+                            nameAndDesc.description,
+                            lineInfo ) );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class ReporterRegistry : public IReporterRegistry {
+
+    public:
+
+        virtual ~ReporterRegistry() {
+            deleteAllValues( m_factories );
+        }
+
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
+            FactoryMap::const_iterator it =  m_factories.find( name );
+            if( it == m_factories.end() )
+                return NULL;
+            return it->second->create( ReporterConfig( config ) );
+        }
+
+        void registerReporter( std::string const& name, IReporterFactory* factory ) {
+            m_factories.insert( std::make_pair( name, factory ) );
+        }
+
+        FactoryMap const& getFactories() const {
+            return m_factories;
+        }
+
+    private:
+        FactoryMap m_factories;
+    };
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+    public:
+        ~ExceptionTranslatorRegistry() {
+            deleteAll( m_translators );
+        }
+
+        virtual void registerTranslator( const IExceptionTranslator* translator ) {
+            m_translators.push_back( translator );
+        }
+
+        virtual std::string translateActiveException() const {
+            try {
+#ifdef __OBJC__
+                // In Objective-C try objective-c exceptions first
+                @try {
+                    throw;
+                }
+                @catch (NSException *exception) {
+                    return Catch::toString( [exception description] );
+                }
+#else
+                throw;
+#endif
+            }
+            catch( TestFailureException& ) {
+                throw;
+            }
+            catch( std::exception& ex ) {
+                return ex.what();
+            }
+            catch( std::string& msg ) {
+                return msg;
+            }
+            catch( const char* msg ) {
+                return msg;
+            }
+            catch(...) {
+                return tryTranslators( m_translators.begin() );
+            }
+        }
+
+        std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
+            if( it == m_translators.end() )
+                return "Unknown exception";
+
+            try {
+                return (*it)->translate();
+            }
+            catch(...) {
+                return tryTranslators( it+1 );
+            }
+        }
+
+    private:
+        std::vector<const IExceptionTranslator*> m_translators;
+    };
+}
+
+namespace Catch {
+
+    namespace {
+
+        class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
+
+            RegistryHub( RegistryHub const& );
+            void operator=( RegistryHub const& );
+
+        public: // IRegistryHub
+            RegistryHub() {
+            }
+            virtual IReporterRegistry const& getReporterRegistry() const {
+                return m_reporterRegistry;
+            }
+            virtual ITestCaseRegistry const& getTestCaseRegistry() const {
+                return m_testCaseRegistry;
+            }
+            virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
+                return m_exceptionTranslatorRegistry;
+            }
+
+        public: // IMutableRegistryHub
+            virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
+                m_reporterRegistry.registerReporter( name, factory );
+            }
+            virtual void registerTest( TestCase const& testInfo ) {
+                m_testCaseRegistry.registerTest( testInfo );
+            }
+            virtual void registerTranslator( const IExceptionTranslator* translator ) {
+                m_exceptionTranslatorRegistry.registerTranslator( translator );
+            }
+
+        private:
+            TestRegistry m_testCaseRegistry;
+            ReporterRegistry m_reporterRegistry;
+            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+        };
+
+        // Single, global, instance
+        inline RegistryHub*& getTheRegistryHub() {
+            static RegistryHub* theRegistryHub = NULL;
+            if( !theRegistryHub )
+                theRegistryHub = new RegistryHub();
+            return theRegistryHub;
+        }
+    }
+
+    IRegistryHub& getRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    IMutableRegistryHub& getMutableRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    void cleanUp() {
+        delete getTheRegistryHub();
+        getTheRegistryHub() = NULL;
+        cleanUpContext();
+    }
+    std::string translateActiveException() {
+        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <ostream>
+
+namespace Catch {
+
+    NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
+    :   m_lineInfo( lineInfo ) {
+        std::ostringstream oss;
+        oss << lineInfo << ": function ";
+        oss << "not implemented";
+        m_what = oss.str();
+    }
+
+    const char* NotImplementedException::what() const CATCH_NOEXCEPT {
+        return m_what.c_str();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+    class StreamBufBase : public std::streambuf {
+    public:
+        virtual ~StreamBufBase() CATCH_NOEXCEPT;
+    };
+}
+
+#include <stdexcept>
+#include <cstdio>
+#include <iostream>
+
+namespace Catch {
+
+    template<typename WriterF, size_t bufferSize=256>
+    class StreamBufImpl : public StreamBufBase {
+        char data[bufferSize];
+        WriterF m_writer;
+
+    public:
+        StreamBufImpl() {
+            setp( data, data + sizeof(data) );
+        }
+
+        ~StreamBufImpl() CATCH_NOEXCEPT {
+            sync();
+        }
+
+    private:
+        int overflow( int c ) {
+            sync();
+
+            if( c != EOF ) {
+                if( pbase() == epptr() )
+                    m_writer( std::string( 1, static_cast<char>( c ) ) );
+                else
+                    sputc( static_cast<char>( c ) );
+            }
+            return 0;
+        }
+
+        int sync() {
+            if( pbase() != pptr() ) {
+                m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+                setp( pbase(), epptr() );
+            }
+            return 0;
+        }
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    struct OutputDebugWriter {
+
+        void operator()( std::string const&str ) {
+            writeToDebugConsole( str );
+        }
+    };
+
+    Stream::Stream()
+    : streamBuf( NULL ), isOwned( false )
+    {}
+
+    Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
+    : streamBuf( _streamBuf ), isOwned( _isOwned )
+    {}
+
+    void Stream::release() {
+        if( isOwned ) {
+            delete streamBuf;
+            streamBuf = NULL;
+            isOwned = false;
+        }
+    }
+
+#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions
+    std::ostream& cout() {
+        return std::cout;
+    }
+    std::ostream& cerr() {
+        return std::cerr;
+    }
+#endif
+}
+
+namespace Catch {
+
+    class Context : public IMutableContext {
+
+        Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
+        Context( Context const& );
+        void operator=( Context const& );
+
+    public: // IContext
+        virtual IResultCapture* getResultCapture() {
+            return m_resultCapture;
+        }
+        virtual IRunner* getRunner() {
+            return m_runner;
+        }
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
+            return getGeneratorsForCurrentTest()
+            .getGeneratorInfo( fileInfo, totalSize )
+            .getCurrentIndex();
+        }
+        virtual bool advanceGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            return generators && generators->moveNext();
+        }
+
+        virtual Ptr<IConfig const> getConfig() const {
+            return m_config;
+        }
+
+    public: // IMutableContext
+        virtual void setResultCapture( IResultCapture* resultCapture ) {
+            m_resultCapture = resultCapture;
+        }
+        virtual void setRunner( IRunner* runner ) {
+            m_runner = runner;
+        }
+        virtual void setConfig( Ptr<IConfig const> const& config ) {
+            m_config = config;
+        }
+
+        friend IMutableContext& getCurrentMutableContext();
+
+    private:
+        IGeneratorsForTest* findGeneratorsForCurrentTest() {
+            std::string testName = getResultCapture()->getCurrentTestName();
+
+            std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+                m_generatorsByTestName.find( testName );
+            return it != m_generatorsByTestName.end()
+                ? it->second
+                : NULL;
+        }
+
+        IGeneratorsForTest& getGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            if( !generators ) {
+                std::string testName = getResultCapture()->getCurrentTestName();
+                generators = createGeneratorsForTest();
+                m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
+            }
+            return *generators;
+        }
+
+    private:
+        Ptr<IConfig const> m_config;
+        IRunner* m_runner;
+        IResultCapture* m_resultCapture;
+        std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+    };
+
+    namespace {
+        Context* currentContext = NULL;
+    }
+    IMutableContext& getCurrentMutableContext() {
+        if( !currentContext )
+            currentContext = new Context();
+        return *currentContext;
+    }
+    IContext& getCurrentContext() {
+        return getCurrentMutableContext();
+    }
+
+    Stream createStream( std::string const& streamName ) {
+        if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false );
+        if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false );
+        if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
+
+        throw std::domain_error( "Unknown stream: " + streamName );
+    }
+
+    void cleanUpContext() {
+        delete currentContext;
+        currentContext = NULL;
+    }
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+namespace Catch {
+    namespace {
+
+        struct IColourImpl {
+            virtual ~IColourImpl() {}
+            virtual void use( Colour::Code _colourCode ) = 0;
+        };
+
+        struct NoColourImpl : IColourImpl {
+            void use( Colour::Code ) {}
+
+            static IColourImpl* instance() {
+                static NoColourImpl s_instance;
+                return &s_instance;
+            }
+        };
+
+    } // anon namespace
+} // namespace Catch
+
+#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
+#   ifdef CATCH_PLATFORM_WINDOWS
+#       define CATCH_CONFIG_COLOUR_WINDOWS
+#   else
+#       define CATCH_CONFIG_COLOUR_ANSI
+#   endif
+#endif
+
+#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+namespace Catch {
+namespace {
+
+    class Win32ColourImpl : public IColourImpl {
+    public:
+        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+        {
+            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+            originalAttributes = csbiInfo.wAttributes;
+        }
+
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:      return setTextAttribute( originalAttributes );
+                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
+                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
+                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
+                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+                case Colour::Grey:      return setTextAttribute( 0 );
+
+                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
+                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+
+    private:
+        void setTextAttribute( WORD _textAttribute ) {
+            SetConsoleTextAttribute( stdoutHandle, _textAttribute );
+        }
+        HANDLE stdoutHandle;
+        WORD originalAttributes;
+    };
+
+    IColourImpl* platformColourInstance() {
+        static Win32ColourImpl s_instance;
+        return &s_instance;
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+    // use POSIX/ ANSI console terminal codes
+    // Thanks to Adam Strzelecki for original contribution
+    // (http://github.com/nanoant)
+    // https://github.com/philsquared/Catch/pull/131
+    class PosixColourImpl : public IColourImpl {
+    public:
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:
+                case Colour::White:     return setColour( "[0m" );
+                case Colour::Red:       return setColour( "[0;31m" );
+                case Colour::Green:     return setColour( "[0;32m" );
+                case Colour::Blue:      return setColour( "[0:34m" );
+                case Colour::Cyan:      return setColour( "[0;36m" );
+                case Colour::Yellow:    return setColour( "[0;33m" );
+                case Colour::Grey:      return setColour( "[1;30m" );
+
+                case Colour::LightGrey:     return setColour( "[0;37m" );
+                case Colour::BrightRed:     return setColour( "[1;31m" );
+                case Colour::BrightGreen:   return setColour( "[1;32m" );
+                case Colour::BrightWhite:   return setColour( "[1;37m" );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+        static IColourImpl* instance() {
+            static PosixColourImpl s_instance;
+            return &s_instance;
+        }
+
+    private:
+        void setColour( const char* _escapeCode ) {
+            Catch::cout() << '\033' << _escapeCode;
+        }
+    };
+
+    IColourImpl* platformColourInstance() {
+        Ptr<IConfig const> config = getCurrentContext().getConfig();
+        return (config && config->forceColour()) || isatty(STDOUT_FILENO)
+            ? PosixColourImpl::instance()
+            : NoColourImpl::instance();
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else  // not Windows or ANSI ///////////////////////////////////////////////
+
+namespace Catch {
+
+    static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
+
+} // end namespace Catch
+
+#endif // Windows/ ANSI/ None
+
+namespace Catch {
+
+    Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
+    Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
+    Colour::~Colour(){ if( !m_moved ) use( None ); }
+
+    void Colour::use( Code _colourCode ) {
+        static IColourImpl* impl = isDebuggerActive()
+            ? NoColourImpl::instance()
+            : platformColourInstance();
+        impl->use( _colourCode );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Catch {
+
+    struct GeneratorInfo : IGeneratorInfo {
+
+        GeneratorInfo( std::size_t size )
+        :   m_size( size ),
+            m_currentIndex( 0 )
+        {}
+
+        bool moveNext() {
+            if( ++m_currentIndex == m_size ) {
+                m_currentIndex = 0;
+                return false;
+            }
+            return true;
+        }
+
+        std::size_t getCurrentIndex() const {
+            return m_currentIndex;
+        }
+
+        std::size_t m_size;
+        std::size_t m_currentIndex;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class GeneratorsForTest : public IGeneratorsForTest {
+
+    public:
+        ~GeneratorsForTest() {
+            deleteAll( m_generatorsInOrder );
+        }
+
+        IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
+            std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
+            if( it == m_generatorsByName.end() ) {
+                IGeneratorInfo* info = new GeneratorInfo( size );
+                m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
+                m_generatorsInOrder.push_back( info );
+                return *info;
+            }
+            return *it->second;
+        }
+
+        bool moveNext() {
+            std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+            std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+            for(; it != itEnd; ++it ) {
+                if( (*it)->moveNext() )
+                    return true;
+            }
+            return false;
+        }
+
+    private:
+        std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+        std::vector<IGeneratorInfo*> m_generatorsInOrder;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest()
+    {
+        return new GeneratorsForTest();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+    AssertionInfo::AssertionInfo(   std::string const& _macroName,
+                                    SourceLineInfo const& _lineInfo,
+                                    std::string const& _capturedExpression,
+                                    ResultDisposition::Flags _resultDisposition )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        capturedExpression( _capturedExpression ),
+        resultDisposition( _resultDisposition )
+    {}
+
+    AssertionResult::AssertionResult() {}
+
+    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+    :   m_info( info ),
+        m_resultData( data )
+    {}
+
+    AssertionResult::~AssertionResult() {}
+
+    // Result was a success
+    bool AssertionResult::succeeded() const {
+        return Catch::isOk( m_resultData.resultType );
+    }
+
+    // Result was a success, or failure is suppressed
+    bool AssertionResult::isOk() const {
+        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+    }
+
+    ResultWas::OfType AssertionResult::getResultType() const {
+        return m_resultData.resultType;
+    }
+
+    bool AssertionResult::hasExpression() const {
+        return !m_info.capturedExpression.empty();
+    }
+
+    bool AssertionResult::hasMessage() const {
+        return !m_resultData.message.empty();
+    }
+
+    std::string AssertionResult::getExpression() const {
+        if( isFalseTest( m_info.resultDisposition ) )
+            return "!" + m_info.capturedExpression;
+        else
+            return m_info.capturedExpression;
+    }
+    std::string AssertionResult::getExpressionInMacro() const {
+        if( m_info.macroName.empty() )
+            return m_info.capturedExpression;
+        else
+            return m_info.macroName + "( " + m_info.capturedExpression + " )";
+    }
+
+    bool AssertionResult::hasExpandedExpression() const {
+        return hasExpression() && getExpandedExpression() != getExpression();
+    }
+
+    std::string AssertionResult::getExpandedExpression() const {
+        return m_resultData.reconstructedExpression;
+    }
+
+    std::string AssertionResult::getMessage() const {
+        return m_resultData.message;
+    }
+    SourceLineInfo AssertionResult::getSourceInfo() const {
+        return m_info.lineInfo;
+    }
+
+    std::string AssertionResult::getTestMacroName() const {
+        return m_info.macroName;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+namespace Catch {
+
+    inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+        if( startsWith( tag, "." ) ||
+            tag == "hide" ||
+            tag == "!hide" )
+            return TestCaseInfo::IsHidden;
+        else if( tag == "!throws" )
+            return TestCaseInfo::Throws;
+        else if( tag == "!shouldfail" )
+            return TestCaseInfo::ShouldFail;
+        else if( tag == "!mayfail" )
+            return TestCaseInfo::MayFail;
+        else
+            return TestCaseInfo::None;
+    }
+    inline bool isReservedTag( std::string const& tag ) {
+        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] );
+    }
+    inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+        if( isReservedTag( tag ) ) {
+            {
+                Colour colourGuard( Colour::Red );
+                Catch::cerr()
+                    << "Tag name [" << tag << "] not allowed.\n"
+                    << "Tag names starting with non alpha-numeric characters are reserved\n";
+            }
+            {
+                Colour colourGuard( Colour::FileName );
+                Catch::cerr() << _lineInfo << std::endl;
+            }
+            exit(1);
+        }
+    }
+
+    TestCase makeTestCase(  ITestCase* _testCase,
+                            std::string const& _className,
+                            std::string const& _name,
+                            std::string const& _descOrTags,
+                            SourceLineInfo const& _lineInfo )
+    {
+        bool isHidden( startsWith( _name, "./" ) ); // Legacy support
+
+        // Parse out tags
+        std::set<std::string> tags;
+        std::string desc, tag;
+        bool inTag = false;
+        for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
+            char c = _descOrTags[i];
+            if( !inTag ) {
+                if( c == '[' )
+                    inTag = true;
+                else
+                    desc += c;
+            }
+            else {
+                if( c == ']' ) {
+                    TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
+                    if( prop == TestCaseInfo::IsHidden )
+                        isHidden = true;
+                    else if( prop == TestCaseInfo::None )
+                        enforceNotReservedTag( tag, _lineInfo );
+
+                    tags.insert( tag );
+                    tag.clear();
+                    inTag = false;
+                }
+                else
+                    tag += c;
+            }
+        }
+        if( isHidden ) {
+            tags.insert( "hide" );
+            tags.insert( "." );
+        }
+
+        TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, info );
+    }
+
+    TestCaseInfo::TestCaseInfo( std::string const& _name,
+                                std::string const& _className,
+                                std::string const& _description,
+                                std::set<std::string> const& _tags,
+                                SourceLineInfo const& _lineInfo )
+    :   name( _name ),
+        className( _className ),
+        description( _description ),
+        tags( _tags ),
+        lineInfo( _lineInfo ),
+        properties( None )
+    {
+        std::ostringstream oss;
+        for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
+            oss << "[" << *it << "]";
+            std::string lcaseTag = toLower( *it );
+            properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
+            lcaseTags.insert( lcaseTag );
+        }
+        tagsAsString = oss.str();
+    }
+
+    TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
+    :   name( other.name ),
+        className( other.className ),
+        description( other.description ),
+        tags( other.tags ),
+        lcaseTags( other.lcaseTags ),
+        tagsAsString( other.tagsAsString ),
+        lineInfo( other.lineInfo ),
+        properties( other.properties )
+    {}
+
+    bool TestCaseInfo::isHidden() const {
+        return ( properties & IsHidden ) != 0;
+    }
+    bool TestCaseInfo::throws() const {
+        return ( properties & Throws ) != 0;
+    }
+    bool TestCaseInfo::okToFail() const {
+        return ( properties & (ShouldFail | MayFail ) ) != 0;
+    }
+    bool TestCaseInfo::expectedToFail() const {
+        return ( properties & (ShouldFail ) ) != 0;
+    }
+
+    TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+
+    TestCase::TestCase( TestCase const& other )
+    :   TestCaseInfo( other ),
+        test( other.test )
+    {}
+
+    TestCase TestCase::withName( std::string const& _newName ) const {
+        TestCase other( *this );
+        other.name = _newName;
+        return other;
+    }
+
+    void TestCase::swap( TestCase& other ) {
+        test.swap( other.test );
+        name.swap( other.name );
+        className.swap( other.className );
+        description.swap( other.description );
+        tags.swap( other.tags );
+        lcaseTags.swap( other.lcaseTags );
+        tagsAsString.swap( other.tagsAsString );
+        std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
+        std::swap( lineInfo, other.lineInfo );
+    }
+
+    void TestCase::invoke() const {
+        test->invoke();
+    }
+
+    bool TestCase::operator == ( TestCase const& other ) const {
+        return  test.get() == other.test.get() &&
+                name == other.name &&
+                className == other.className;
+    }
+
+    bool TestCase::operator < ( TestCase const& other ) const {
+        return name < other.name;
+    }
+    TestCase& TestCase::operator = ( TestCase const& other ) {
+        TestCase temp( other );
+        swap( temp );
+        return *this;
+    }
+
+    TestCaseInfo const& TestCase::getTestCaseInfo() const
+    {
+        return *this;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+    // These numbers are maintained by a script
+    Version libraryVersion( 1, 1, 3, "master" );
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+    MessageInfo::MessageInfo(   std::string const& _macroName,
+                                SourceLineInfo const& _lineInfo,
+                                ResultWas::OfType _type )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        type( _type ),
+        sequence( ++globalCount )
+    {}
+
+    // This may need protecting if threading support is added
+    unsigned int MessageInfo::globalCount = 0;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+    : m_info( builder.m_info )
+    {
+        m_info.message = builder.m_stream.str();
+        getResultCapture().pushScopedMessage( m_info );
+    }
+    ScopedMessage::ScopedMessage( ScopedMessage const& other )
+    : m_info( other.m_info )
+    {}
+
+    ScopedMessage::~ScopedMessage() {
+        getResultCapture().popScopedMessage( m_info );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch
+{
+    // Deprecated
+    struct IReporter : IShared {
+        virtual ~IReporter();
+
+        virtual bool shouldRedirectStdout() const = 0;
+
+        virtual void StartTesting() = 0;
+        virtual void EndTesting( Totals const& totals ) = 0;
+        virtual void StartGroup( std::string const& groupName ) = 0;
+        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+        virtual void Aborted() = 0;
+        virtual void Result( AssertionResult const& result ) = 0;
+    };
+
+    class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+    {
+    public:
+        LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
+        virtual ~LegacyReporterAdapter();
+
+        virtual ReporterPreferences getPreferences() const;
+        virtual void noMatchingTestCases( std::string const& );
+        virtual void testRunStarting( TestRunInfo const& );
+        virtual void testGroupStarting( GroupInfo const& groupInfo );
+        virtual void testCaseStarting( TestCaseInfo const& testInfo );
+        virtual void sectionStarting( SectionInfo const& sectionInfo );
+        virtual void assertionStarting( AssertionInfo const& );
+        virtual bool assertionEnded( AssertionStats const& assertionStats );
+        virtual void sectionEnded( SectionStats const& sectionStats );
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats );
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats );
+        virtual void testRunEnded( TestRunStats const& testRunStats );
+        virtual void skipTest( TestCaseInfo const& );
+
+    private:
+        Ptr<IReporter> m_legacyReporter;
+    };
+}
+
+namespace Catch
+{
+    LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
+    :   m_legacyReporter( legacyReporter )
+    {}
+    LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+    ReporterPreferences LegacyReporterAdapter::getPreferences() const {
+        ReporterPreferences prefs;
+        prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+        return prefs;
+    }
+
+    void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
+    void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
+        m_legacyReporter->StartTesting();
+    }
+    void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
+        m_legacyReporter->StartGroup( groupInfo.name );
+    }
+    void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        m_legacyReporter->StartTestCase( testInfo );
+    }
+    void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
+        m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
+    }
+    void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
+        // Not on legacy interface
+    }
+
+    bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
+        if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+            for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                    it != itEnd;
+                    ++it ) {
+                if( it->type == ResultWas::Info ) {
+                    ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
+                    rb << it->message;
+                    rb.setResultType( ResultWas::Info );
+                    AssertionResult result = rb.build();
+                    m_legacyReporter->Result( result );
+                }
+            }
+        }
+        m_legacyReporter->Result( assertionStats.assertionResult );
+        return true;
+    }
+    void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
+        if( sectionStats.missingAssertions )
+            m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
+        m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
+    }
+    void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        m_legacyReporter->EndTestCase
+            (   testCaseStats.testInfo,
+                testCaseStats.totals,
+                testCaseStats.stdOut,
+                testCaseStats.stdErr );
+    }
+    void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        if( testGroupStats.aborting )
+            m_legacyReporter->Aborted();
+        m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
+    }
+    void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
+        m_legacyReporter->EndTesting( testRunStats.totals );
+    }
+    void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) {
+    }
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace Catch {
+
+    namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+        uint64_t getCurrentTicks() {
+            static uint64_t hz=0, hzo=0;
+            if (!hz) {
+                QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
+                QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
+            }
+            uint64_t t;
+            QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
+            return ((t-hzo)*1000000)/hz;
+        }
+#else
+        uint64_t getCurrentTicks() {
+            timeval t;
+            gettimeofday(&t,NULL);
+            return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
+        }
+#endif
+    }
+
+    void Timer::start() {
+        m_ticks = getCurrentTicks();
+    }
+    unsigned int Timer::getElapsedMicroseconds() const {
+        return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+    }
+    unsigned int Timer::getElapsedMilliseconds() const {
+        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
+    }
+    double Timer::getElapsedSeconds() const {
+        return getElapsedMicroseconds()/1000000.0;
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), ::tolower );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
+    }
+
+    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
+        bool replaced = false;
+        std::size_t i = str.find( replaceThis );
+        while( i != std::string::npos ) {
+            replaced = true;
+            str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
+            if( i < str.size()-withThis.size() )
+                i = str.find( replaceThis, i+withThis.size() );
+            else
+                i = std::string::npos;
+        }
+        return replaced;
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << " " << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << "s";
+        return os;
+    }
+
+    SourceLineInfo::SourceLineInfo() : line( 0 ){}
+    SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
+    :   file( _file ),
+        line( _line )
+    {}
+    SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
+    :   file( other.file ),
+        line( other.line )
+    {}
+    bool SourceLineInfo::empty() const {
+        return file.empty();
+    }
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+        return line == other.line && file == other.file;
+    }
+    bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
+        return line < other.line || ( line == other.line  && file < other.file );
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << "(" << info.line << ")";
+#else
+        os << info.file << ":" << info.line;
+#endif
+        return os;
+    }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+        std::ostringstream oss;
+        oss << locationInfo << ": Internal Catch error: '" << message << "'";
+        if( alwaysTrue() )
+            throw std::logic_error( oss.str() );
+    }
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+    SectionInfo::SectionInfo
+        (   SourceLineInfo const& _lineInfo,
+            std::string const& _name,
+            std::string const& _description )
+    :   name( _name ),
+        description( _description ),
+        lineInfo( _lineInfo )
+    {}
+
+    Section::Section( SectionInfo const& info )
+    :   m_info( info ),
+        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
+
+    Section::~Section() {
+        if( m_sectionIncluded )
+            getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
+    }
+
+    // This indicates whether the section should be executed or not
+    Section::operator bool() const {
+        return m_sectionIncluded;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#include <iostream>
+
+#ifdef CATCH_PLATFORM_MAC
+
+    #include <assert.h>
+    #include <stdbool.h>
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <sys/sysctl.h>
+
+    namespace Catch{
+
+        // The following function is taken directly from the following technical note:
+        // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+        // Returns true if the current process is being debugged (either
+        // running under the debugger or has a debugger attached post facto).
+        bool isDebuggerActive(){
+
+            int                 mib[4];
+            struct kinfo_proc   info;
+            size_t              size;
+
+            // Initialize the flags so that, if sysctl fails for some bizarre
+            // reason, we get a predictable result.
+
+            info.kp_proc.p_flag = 0;
+
+            // Initialize mib, which tells sysctl the info we want, in this case
+            // we're looking for information about a specific process ID.
+
+            mib[0] = CTL_KERN;
+            mib[1] = KERN_PROC;
+            mib[2] = KERN_PROC_PID;
+            mib[3] = getpid();
+
+            // Call sysctl.
+
+            size = sizeof(info);
+            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
+                Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+                return false;
+            }
+
+            // We're being debugged if the P_TRACED flag is set.
+
+            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+        }
+    } // namespace Catch
+
+#elif defined(_MSC_VER)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#else
+    namespace Catch {
+       inline bool isDebuggerActive() { return false; }
+    }
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+    extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
+#else
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            Catch::cout() << text;
+        }
+    }
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+    std::string unprintableString = "{?}";
+
+    namespace {
+        struct Endianness {
+            enum Arch { Big, Little };
+
+            static Arch which() {
+                union _{
+                    int asInt;
+                    char asChar[sizeof (int)];
+                } u;
+
+                u.asInt = 1;
+                return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+            }
+        };
+    }
+
+    std::string rawMemoryToString( const void *object, std::size_t size )
+    {
+        // Reverse order for little endian architectures
+        int i = 0, end = static_cast<int>( size ), inc = 1;
+        if( Endianness::which() == Endianness::Little ) {
+            i = end-1;
+            end = inc = -1;
+        }
+
+        unsigned char const *bytes = static_cast<unsigned char const *>(object);
+        std::ostringstream os;
+        os << "0x" << std::setfill('0') << std::hex;
+        for( ; i != end; i += inc )
+             os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+       return os.str();
+    }
+}
+
+std::string toString( std::string const& value ) {
+    std::string s = value;
+    if( getCurrentContext().getConfig()->showInvisibles() ) {
+        for(size_t i = 0; i < s.size(); ++i ) {
+            std::string subs;
+            switch( s[i] ) {
+            case '\n': subs = "\\n"; break;
+            case '\t': subs = "\\t"; break;
+            default: break;
+            }
+            if( !subs.empty() ) {
+                s = s.substr( 0, i ) + subs + s.substr( i+1 );
+                ++i;
+            }
+        }
+    }
+    return "\"" + s + "\"";
+}
+std::string toString( std::wstring const& value ) {
+
+    std::string s;
+    s.reserve( value.size() );
+    for(size_t i = 0; i < value.size(); ++i )
+        s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
+    return Catch::toString( s );
+}
+
+std::string toString( const char* const value ) {
+    return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
+}
+
+std::string toString( char* const value ) {
+    return Catch::toString( static_cast<const char*>( value ) );
+}
+
+std::string toString( const wchar_t* const value )
+{
+	return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+}
+
+std::string toString( wchar_t* const value )
+{
+	return Catch::toString( static_cast<const wchar_t*>( value ) );
+}
+
+std::string toString( int value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value >= 255 )
+        oss << " (0x" << std::hex << value << ")";
+    return oss.str();
+}
+
+std::string toString( unsigned long value ) {
+    std::ostringstream oss;
+    oss << value;
+    if( value >= 255 )
+        oss << " (0x" << std::hex << value << ")";
+    return oss.str();
+}
+
+std::string toString( unsigned int value ) {
+    return Catch::toString( static_cast<unsigned long>( value ) );
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+    std::ostringstream oss;
+    oss << std::setprecision( precision )
+        << std::fixed
+        << value;
+    std::string d = oss.str();
+    std::size_t i = d.find_last_not_of( '0' );
+    if( i != std::string::npos && i != d.size()-1 ) {
+        if( d[i] == '.' )
+            i++;
+        d = d.substr( 0, i+1 );
+    }
+    return d;
+}
+
+std::string toString( const double value ) {
+    return fpToString( value, 10 );
+}
+std::string toString( const float value ) {
+    return fpToString( value, 5 ) + "f";
+}
+
+std::string toString( bool value ) {
+    return value ? "true" : "false";
+}
+
+std::string toString( char value ) {
+    return value < ' '
+        ? toString( static_cast<unsigned int>( value ) )
+        : Detail::makeString( value );
+}
+
+std::string toString( signed char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+std::string toString( unsigned char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t ) {
+    return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSObject* const& nsObject ) {
+        return toString( [nsObject description] );
+    }
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+    ResultBuilder::ResultBuilder(   char const* macroName,
+                                    SourceLineInfo const& lineInfo,
+                                    char const* capturedExpression,
+                                    ResultDisposition::Flags resultDisposition )
+    :   m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ),
+        m_shouldDebugBreak( false ),
+        m_shouldThrow( false )
+    {}
+
+    ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
+        m_data.resultType = result;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setResultType( bool result ) {
+        m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
+        m_exprComponents.lhs = lhs;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
+        m_exprComponents.rhs = rhs;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
+        m_exprComponents.op = op;
+        return *this;
+    }
+
+    void ResultBuilder::endExpression() {
+        m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
+        captureExpression();
+    }
+
+    void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
+        m_assertionInfo.resultDisposition = resultDisposition;
+        m_stream.oss << Catch::translateActiveException();
+        captureResult( ResultWas::ThrewException );
+    }
+
+    void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
+        setResultType( resultType );
+        captureExpression();
+    }
+
+    void ResultBuilder::captureExpression() {
+        AssertionResult result = build();
+        getResultCapture().assertionEnded( result );
+
+        if( !result.isOk() ) {
+            if( getCurrentContext().getConfig()->shouldDebugBreak() )
+                m_shouldDebugBreak = true;
+            if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) )
+                m_shouldThrow = true;
+        }
+    }
+    void ResultBuilder::react() {
+        if( m_shouldThrow )
+            throw Catch::TestFailureException();
+    }
+
+    bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+    bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+    AssertionResult ResultBuilder::build() const
+    {
+        assert( m_data.resultType != ResultWas::Unknown );
+
+        AssertionResultData data = m_data;
+
+        // Flip bool results if testFalse is set
+        if( m_exprComponents.testFalse ) {
+            if( data.resultType == ResultWas::Ok )
+                data.resultType = ResultWas::ExpressionFailed;
+            else if( data.resultType == ResultWas::ExpressionFailed )
+                data.resultType = ResultWas::Ok;
+        }
+
+        data.message = m_stream.oss.str();
+        data.reconstructedExpression = reconstructExpression();
+        if( m_exprComponents.testFalse ) {
+            if( m_exprComponents.op == "" )
+                data.reconstructedExpression = "!" + data.reconstructedExpression;
+            else
+                data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
+        }
+        return AssertionResult( m_assertionInfo, data );
+    }
+    std::string ResultBuilder::reconstructExpression() const {
+        if( m_exprComponents.op == "" )
+            return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
+        else if( m_exprComponents.op == "matches" )
+            return m_exprComponents.lhs + " " + m_exprComponents.rhs;
+        else if( m_exprComponents.op != "!" ) {
+            if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
+                m_exprComponents.lhs.find("\n") == std::string::npos &&
+                m_exprComponents.rhs.find("\n") == std::string::npos )
+                return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
+            else
+                return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
+        }
+        else
+            return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
+    }
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class TagAliasRegistry : public ITagAliasRegistry {
+    public:
+        virtual ~TagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+        void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+        static TagAliasRegistry& get();
+
+    private:
+        std::map<std::string, TagAlias> m_registry;
+    };
+
+} // end namespace Catch
+
+#include <map>
+#include <iostream>
+
+namespace Catch {
+
+    TagAliasRegistry::~TagAliasRegistry() {}
+
+    Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
+        std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
+        if( it != m_registry.end() )
+            return it->second;
+        else
+            return Option<TagAlias>();
+    }
+
+    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+        std::string expandedTestSpec = unexpandedTestSpec;
+        for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+                it != itEnd;
+                ++it ) {
+            std::size_t pos = expandedTestSpec.find( it->first );
+            if( pos != std::string::npos ) {
+                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +
+                                    it->second.tag +
+                                    expandedTestSpec.substr( pos + it->first.size() );
+            }
+        }
+        return expandedTestSpec;
+    }
+
+    void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+
+        if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
+            std::ostringstream oss;
+            oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
+            throw std::domain_error( oss.str().c_str() );
+        }
+        if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
+            std::ostringstream oss;
+            oss << "error: tag alias, \"" << alias << "\" already registered.\n"
+                << "\tFirst seen at " << find(alias)->lineInfo << "\n"
+                << "\tRedefined at " << lineInfo;
+            throw std::domain_error( oss.str().c_str() );
+        }
+    }
+
+    TagAliasRegistry& TagAliasRegistry::get() {
+        static TagAliasRegistry instance;
+        return instance;
+
+    }
+
+    ITagAliasRegistry::~ITagAliasRegistry() {}
+    ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
+
+    RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+        try {
+            TagAliasRegistry::get().add( alias, tag, lineInfo );
+        }
+        catch( std::exception& ex ) {
+            Colour colourGuard( Colour::Red );
+            Catch::cerr() << ex.what() << std::endl;
+            exit(1);
+        }
+    }
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+#include <cstring>
+
+namespace Catch {
+
+    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {}
+
+        virtual ~StreamingReporterBase();
+
+        virtual void noMatchingTestCases( std::string const& ) {}
+
+        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
+            currentTestRunInfo = _testRunInfo;
+        }
+        virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
+            currentGroupInfo = _groupInfo;
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
+            currentTestCaseInfo = _testInfo;
+        }
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
+            m_sectionStack.push_back( _sectionInfo );
+        }
+
+        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
+            currentTestCaseInfo.reset();
+        }
+        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
+            currentGroupInfo.reset();
+        }
+        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        virtual void skipTest( TestCaseInfo const& ) {
+            // Don't do anything with this by default.
+            // It can optionally be overridden in the derived class.
+        }
+
+        Ptr<IConfig> m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+    };
+
+    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+        template<typename T, typename ChildNodeT>
+        struct Node : SharedImpl<> {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode : SharedImpl<> {
+            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+            virtual ~SectionNode();
+
+            bool operator == ( SectionNode const& other ) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == ( Ptr<SectionNode> const& other ) const {
+                return operator==( *other );
+            }
+
+            SectionStats stats;
+            typedef std::vector<Ptr<SectionNode> > ChildSections;
+            typedef std::vector<AssertionStats> Assertions;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+
+        struct BySectionInfo {
+            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+			BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+            bool operator() ( Ptr<SectionNode> const& node ) const {
+                return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+            }
+        private:
+			void operator=( BySectionInfo const& );
+            SectionInfo const& m_other;
+        };
+
+        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {}
+        ~CumulativeReporterBase();
+
+        virtual void testRunStarting( TestRunInfo const& ) {}
+        virtual void testGroupStarting( GroupInfo const& ) {}
+
+        virtual void testCaseStarting( TestCaseInfo const& ) {}
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            Ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = new SectionNode( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                SectionNode::ChildSections::const_iterator it =
+                    std::find_if(   parentNode.childSections.begin(),
+                                    parentNode.childSections.end(),
+                                    BySectionInfo( sectionInfo ) );
+                if( it == parentNode.childSections.end() ) {
+                    node = new SectionNode( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = node;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {}
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
+            assert( !m_sectionStack.empty() );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back( assertionStats );
+            return true;
+        }
+        virtual void sectionEnded( SectionStats const& sectionStats ) {
+            assert( !m_sectionStack.empty() );
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
+            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+            assert( m_sectionStack.size() == 0 );
+            node->children.push_back( m_rootSection );
+            m_testCases.push_back( node );
+            m_rootSection.reset();
+
+            assert( m_deepestSection );
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
+            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+            node->children.swap( m_testCases );
+            m_testGroups.push_back( node );
+        }
+        virtual void testRunEnded( TestRunStats const& testRunStats ) {
+            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+            node->children.swap( m_testGroups );
+            m_testRuns.push_back( node );
+            testRunEndedCumulative();
+        }
+        virtual void testRunEndedCumulative() = 0;
+
+        virtual void skipTest( TestCaseInfo const& ) {}
+
+        Ptr<IConfig> m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+        std::vector<Ptr<TestCaseNode> > m_testCases;
+        std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+        std::vector<Ptr<TestRunNode> > m_testRuns;
+
+        Ptr<SectionNode> m_rootSection;
+        Ptr<SectionNode> m_deepestSection;
+        std::vector<Ptr<SectionNode> > m_sectionStack;
+
+    };
+
+    template<char C>
+    char const* getLineOfChars() {
+        static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+        if( !*line ) {
+            memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+            line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+        }
+        return line;
+    }
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+    template<typename T>
+    class LegacyReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new LegacyReporterAdapter( new T( config ) );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        LegacyReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+
+            // *** Please Note ***:
+            // - If you end up here looking at a compiler error because it's trying to register
+            // your custom reporter class be aware that the native reporter interface has changed
+            // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+            // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+            // However please consider updating to the new interface as the old one is now
+            // deprecated and will probably be removed quite soon!
+            // Please contact me via github if you have any questions at all about this.
+            // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+            // no idea who is actually using custom reporters at all (possibly no-one!).
+            // The new interface is designed to minimise exposure to interface changes in the future.
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        ReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
+    namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
+    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class XmlWriter {
+    public:
+
+        class ScopedElement {
+        public:
+            ScopedElement( XmlWriter* writer )
+            :   m_writer( writer )
+            {}
+
+            ScopedElement( ScopedElement const& other )
+            :   m_writer( other.m_writer ){
+                other.m_writer = NULL;
+            }
+
+            ~ScopedElement() {
+                if( m_writer )
+                    m_writer->endElement();
+            }
+
+            ScopedElement& writeText( std::string const& text, bool indent = true ) {
+                m_writer->writeText( text, indent );
+                return *this;
+            }
+
+            template<typename T>
+            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+                m_writer->writeAttribute( name, attribute );
+                return *this;
+            }
+
+        private:
+            mutable XmlWriter* m_writer;
+        };
+
+        XmlWriter()
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( &Catch::cout() )
+        {}
+
+        XmlWriter( std::ostream& os )
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( &os )
+        {}
+
+        ~XmlWriter() {
+            while( !m_tags.empty() )
+                endElement();
+        }
+
+        XmlWriter& startElement( std::string const& name ) {
+            ensureTagClosed();
+            newlineIfNecessary();
+            stream() << m_indent << "<" << name;
+            m_tags.push_back( name );
+            m_indent += "  ";
+            m_tagIsOpen = true;
+            return *this;
+        }
+
+        ScopedElement scopedElement( std::string const& name ) {
+            ScopedElement scoped( this );
+            startElement( name );
+            return scoped;
+        }
+
+        XmlWriter& endElement() {
+            newlineIfNecessary();
+            m_indent = m_indent.substr( 0, m_indent.size()-2 );
+            if( m_tagIsOpen ) {
+                stream() << "/>\n";
+                m_tagIsOpen = false;
+            }
+            else {
+                stream() << m_indent << "</" << m_tags.back() << ">\n";
+            }
+            m_tags.pop_back();
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
+            if( !name.empty() && !attribute.empty() ) {
+                stream() << " " << name << "=\"";
+                writeEncodedText( attribute );
+                stream() << "\"";
+            }
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
+            stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
+            return *this;
+        }
+
+        template<typename T>
+        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+            if( !name.empty() )
+                stream() << " " << name << "=\"" << attribute << "\"";
+            return *this;
+        }
+
+        XmlWriter& writeText( std::string const& text, bool indent = true ) {
+            if( !text.empty() ){
+                bool tagWasOpen = m_tagIsOpen;
+                ensureTagClosed();
+                if( tagWasOpen && indent )
+                    stream() << m_indent;
+                writeEncodedText( text );
+                m_needsNewline = true;
+            }
+            return *this;
+        }
+
+        XmlWriter& writeComment( std::string const& text ) {
+            ensureTagClosed();
+            stream() << m_indent << "<!--" << text << "-->";
+            m_needsNewline = true;
+            return *this;
+        }
+
+        XmlWriter& writeBlankLine() {
+            ensureTagClosed();
+            stream() << "\n";
+            return *this;
+        }
+
+        void setStream( std::ostream& os ) {
+            m_os = &os;
+        }
+
+    private:
+        XmlWriter( XmlWriter const& );
+        void operator=( XmlWriter const& );
+
+        std::ostream& stream() {
+            return *m_os;
+        }
+
+        void ensureTagClosed() {
+            if( m_tagIsOpen ) {
+                stream() << ">\n";
+                m_tagIsOpen = false;
+            }
+        }
+
+        void newlineIfNecessary() {
+            if( m_needsNewline ) {
+                stream() << "\n";
+                m_needsNewline = false;
+            }
+        }
+
+        void writeEncodedText( std::string const& text ) {
+            static const char* charsToEncode = "<&\"";
+            std::string mtext = text;
+            std::string::size_type pos = mtext.find_first_of( charsToEncode );
+            while( pos != std::string::npos ) {
+                stream() << mtext.substr( 0, pos );
+
+                switch( mtext[pos] ) {
+                    case '<':
+                        stream() << "<";
+                        break;
+                    case '&':
+                        stream() << "&";
+                        break;
+                    case '\"':
+                        stream() << """;
+                        break;
+                }
+                mtext = mtext.substr( pos+1 );
+                pos = mtext.find_first_of( charsToEncode );
+            }
+            stream() << mtext;
+        }
+
+        bool m_tagIsOpen;
+        bool m_needsNewline;
+        std::vector<std::string> m_tags;
+        std::string m_indent;
+        std::ostream* m_os;
+    };
+
+}
+namespace Catch {
+    class XmlReporter : public StreamingReporterBase {
+    public:
+        XmlReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_sectionDepth( 0 )
+        {}
+
+        virtual ~XmlReporter();
+
+        static std::string getDescription() {
+            return "Reports test results as an XML document";
+        }
+
+    public: // StreamingReporterBase
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = true;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& s ) {
+            StreamingReporterBase::noMatchingTestCases( s );
+        }
+
+        virtual void testRunStarting( TestRunInfo const& testInfo ) {
+            StreamingReporterBase::testRunStarting( testInfo );
+            m_xml.setStream( stream );
+            m_xml.startElement( "Catch" );
+            if( !m_config->name().empty() )
+                m_xml.writeAttribute( "name", m_config->name() );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) {
+            StreamingReporterBase::testGroupStarting( groupInfo );
+            m_xml.startElement( "Group" )
+                .writeAttribute( "name", groupInfo.name );
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) {
+            StreamingReporterBase::testCaseStarting(testInfo);
+            m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                m_testCaseTimer.start();
+        }
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) {
+            StreamingReporterBase::sectionStarting( sectionInfo );
+            if( m_sectionDepth++ > 0 ) {
+                m_xml.startElement( "Section" )
+                    .writeAttribute( "name", trim( sectionInfo.name ) )
+                    .writeAttribute( "description", sectionInfo.description );
+            }
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) { }
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
+            const AssertionResult& assertionResult = assertionStats.assertionResult;
+
+            // Print any info messages in <Info> tags.
+            if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+                for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                        it != itEnd;
+                        ++it ) {
+                    if( it->type == ResultWas::Info ) {
+                        m_xml.scopedElement( "Info" )
+                            .writeText( it->message );
+                    } else if ( it->type == ResultWas::Warning ) {
+                        m_xml.scopedElement( "Warning" )
+                            .writeText( it->message );
+                    }
+                }
+            }
+
+            // Drop out if result was successful but we're not printing them.
+            if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
+                return true;
+
+            // Print the expression if there is one.
+            if( assertionResult.hasExpression() ) {
+                m_xml.startElement( "Expression" )
+                    .writeAttribute( "success", assertionResult.succeeded() )
+					.writeAttribute( "type", assertionResult.getTestMacroName() )
+                    .writeAttribute( "filename", assertionResult.getSourceInfo().file )
+                    .writeAttribute( "line", assertionResult.getSourceInfo().line );
+
+                m_xml.scopedElement( "Original" )
+                    .writeText( assertionResult.getExpression() );
+                m_xml.scopedElement( "Expanded" )
+                    .writeText( assertionResult.getExpandedExpression() );
+            }
+
+            // And... Print a result applicable to each result type.
+            switch( assertionResult.getResultType() ) {
+                case ResultWas::ThrewException:
+                    m_xml.scopedElement( "Exception" )
+                        .writeAttribute( "filename", assertionResult.getSourceInfo().file )
+                        .writeAttribute( "line", assertionResult.getSourceInfo().line )
+                        .writeText( assertionResult.getMessage() );
+                    break;
+                case ResultWas::FatalErrorCondition:
+                    m_xml.scopedElement( "Fatal Error Condition" )
+                        .writeAttribute( "filename", assertionResult.getSourceInfo().file )
+                        .writeAttribute( "line", assertionResult.getSourceInfo().line )
+                        .writeText( assertionResult.getMessage() );
+                    break;
+                case ResultWas::Info:
+                    m_xml.scopedElement( "Info" )
+                        .writeText( assertionResult.getMessage() );
+                    break;
+                case ResultWas::Warning:
+                    // Warning will already have been written
+                    break;
+                case ResultWas::ExplicitFailure:
+                    m_xml.scopedElement( "Failure" )
+                        .writeText( assertionResult.getMessage() );
+                    break;
+                default:
+                    break;
+            }
+
+            if( assertionResult.hasExpression() )
+                m_xml.endElement();
+
+            return true;
+        }
+
+        virtual void sectionEnded( SectionStats const& sectionStats ) {
+            StreamingReporterBase::sectionEnded( sectionStats );
+            if( --m_sectionDepth > 0 ) {
+                XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+                e.writeAttribute( "successes", sectionStats.assertions.passed );
+                e.writeAttribute( "failures", sectionStats.assertions.failed );
+                e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
+
+                if ( m_config->showDurations() == ShowDurations::Always )
+                    e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
+
+                m_xml.endElement();
+            }
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
+            StreamingReporterBase::testCaseEnded( testCaseStats );
+            XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
+            e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
+
+            if ( m_config->showDurations() == ShowDurations::Always )
+                e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
+
+            m_xml.endElement();
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
+            StreamingReporterBase::testGroupEnded( testGroupStats );
+            // TODO: Check testGroupStats.aborting and act accordingly.
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
+                .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+        virtual void testRunEnded( TestRunStats const& testRunStats ) {
+            StreamingReporterBase::testRunEnded( testRunStats );
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", testRunStats.totals.assertions.passed )
+                .writeAttribute( "failures", testRunStats.totals.assertions.failed )
+                .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+    private:
+        Timer m_testCaseTimer;
+        XmlWriter m_xml;
+        int m_sectionDepth;
+    };
+
+     INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+    class JunitReporter : public CumulativeReporterBase {
+    public:
+        JunitReporter( ReporterConfig const& _config )
+        :   CumulativeReporterBase( _config ),
+            xml( _config.stream() )
+        {}
+
+        ~JunitReporter();
+
+        static std::string getDescription() {
+            return "Reports test results in an XML format that looks like Ant's junitreport target";
+        }
+
+        virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = true;
+            return prefs;
+        }
+
+        virtual void testRunStarting( TestRunInfo const& runInfo ) {
+            CumulativeReporterBase::testRunStarting( runInfo );
+            xml.startElement( "testsuites" );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) {
+            suiteTimer.start();
+            stdOutForSuite.str("");
+            stdErrForSuite.str("");
+            unexpectedExceptions = 0;
+            CumulativeReporterBase::testGroupStarting( groupInfo );
+        }
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
+            if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
+                unexpectedExceptions++;
+            return CumulativeReporterBase::assertionEnded( assertionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
+            stdOutForSuite << testCaseStats.stdOut;
+            stdErrForSuite << testCaseStats.stdErr;
+            CumulativeReporterBase::testCaseEnded( testCaseStats );
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
+            double suiteTime = suiteTimer.getElapsedSeconds();
+            CumulativeReporterBase::testGroupEnded( testGroupStats );
+            writeGroup( *m_testGroups.back(), suiteTime );
+        }
+
+        virtual void testRunEndedCumulative() {
+            xml.endElement();
+        }
+
+        void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+            XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+            TestGroupStats const& stats = groupNode.value;
+            xml.writeAttribute( "name", stats.groupInfo.name );
+            xml.writeAttribute( "errors", unexpectedExceptions );
+            xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+            xml.writeAttribute( "tests", stats.totals.assertions.total() );
+            xml.writeAttribute( "hostname", "tbd" ); // !TBD
+            if( m_config->showDurations() == ShowDurations::Never )
+                xml.writeAttribute( "time", "" );
+            else
+                xml.writeAttribute( "time", suiteTime );
+            xml.writeAttribute( "timestamp", "tbd" ); // !TBD
+
+            // Write test cases
+            for( TestGroupNode::ChildNodes::const_iterator
+                    it = groupNode.children.begin(), itEnd = groupNode.children.end();
+                    it != itEnd;
+                    ++it )
+                writeTestCase( **it );
+
+            xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
+            xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
+        }
+
+        void writeTestCase( TestCaseNode const& testCaseNode ) {
+            TestCaseStats const& stats = testCaseNode.value;
+
+            // All test cases have exactly one section - which represents the
+            // test case itself. That section may have 0-n nested sections
+            assert( testCaseNode.children.size() == 1 );
+            SectionNode const& rootSection = *testCaseNode.children.front();
+
+            std::string className = stats.testInfo.className;
+
+            if( className.empty() ) {
+                if( rootSection.childSections.empty() )
+                    className = "global";
+            }
+            writeSection( className, "", rootSection );
+        }
+
+        void writeSection(  std::string const& className,
+                            std::string const& rootName,
+                            SectionNode const& sectionNode ) {
+            std::string name = trim( sectionNode.stats.sectionInfo.name );
+            if( !rootName.empty() )
+                name = rootName + "/" + name;
+
+            if( !sectionNode.assertions.empty() ||
+                !sectionNode.stdOut.empty() ||
+                !sectionNode.stdErr.empty() ) {
+                XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+                if( className.empty() ) {
+                    xml.writeAttribute( "classname", name );
+                    xml.writeAttribute( "name", "root" );
+                }
+                else {
+                    xml.writeAttribute( "classname", className );
+                    xml.writeAttribute( "name", name );
+                }
+                xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) );
+
+                writeAssertions( sectionNode );
+
+                if( !sectionNode.stdOut.empty() )
+                    xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+                if( !sectionNode.stdErr.empty() )
+                    xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+            }
+            for( SectionNode::ChildSections::const_iterator
+                    it = sectionNode.childSections.begin(),
+                    itEnd = sectionNode.childSections.end();
+                    it != itEnd;
+                    ++it )
+                if( className.empty() )
+                    writeSection( name, "", **it );
+                else
+                    writeSection( className, name, **it );
+        }
+
+        void writeAssertions( SectionNode const& sectionNode ) {
+            for( SectionNode::Assertions::const_iterator
+                    it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
+                    it != itEnd;
+                    ++it )
+                writeAssertion( *it );
+        }
+        void writeAssertion( AssertionStats const& stats ) {
+            AssertionResult const& result = stats.assertionResult;
+            if( !result.isOk() ) {
+                std::string elementName;
+                switch( result.getResultType() ) {
+                    case ResultWas::ThrewException:
+                    case ResultWas::FatalErrorCondition:
+                        elementName = "error";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        elementName = "failure";
+                        break;
+
+                    // We should never see these here:
+                    case ResultWas::Info:
+                    case ResultWas::Warning:
+                    case ResultWas::Ok:
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        elementName = "internalError";
+                        break;
+                }
+
+                XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+                xml.writeAttribute( "message", result.getExpandedExpression() );
+                xml.writeAttribute( "type", result.getTestMacroName() );
+
+                std::ostringstream oss;
+                if( !result.getMessage().empty() )
+                    oss << result.getMessage() << "\n";
+                for( std::vector<MessageInfo>::const_iterator
+                        it = stats.infoMessages.begin(),
+                        itEnd = stats.infoMessages.end();
+                            it != itEnd;
+                            ++it )
+                    if( it->type == ResultWas::Info )
+                        oss << it->message << "\n";
+
+                oss << "at " << result.getSourceInfo();
+                xml.writeText( oss.str(), false );
+            }
+        }
+
+        XmlWriter xml;
+        Timer suiteTimer;
+        std::ostringstream stdOutForSuite;
+        std::ostringstream stdErrForSuite;
+        unsigned int unexpectedExceptions;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+namespace Catch {
+
+    struct ConsoleReporter : StreamingReporterBase {
+        ConsoleReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_headerPrinted( false )
+        {}
+
+        virtual ~ConsoleReporter();
+        static std::string getDescription() {
+            return "Reports test results as plain lines of text";
+        }
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << "'" << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            lazyPrint();
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
+            m_headerPrinted = false;
+            StreamingReporterBase::sectionStarting( _sectionInfo );
+        }
+        virtual void sectionEnded( SectionStats const& _sectionStats ) {
+            if( _sectionStats.missingAssertions ) {
+                lazyPrint();
+                Colour colour( Colour::ResultError );
+                if( m_sectionStack.size() > 1 )
+                    stream << "\nNo assertions in section";
+                else
+                    stream << "\nNo assertions in test case";
+                stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+            }
+            if( m_headerPrinted ) {
+                if( m_config->showDurations() == ShowDurations::Always )
+                    stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+                m_headerPrinted = false;
+            }
+            else {
+                if( m_config->showDurations() == ShowDurations::Always )
+                    stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+            }
+            StreamingReporterBase::sectionEnded( _sectionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
+            StreamingReporterBase::testCaseEnded( _testCaseStats );
+            m_headerPrinted = false;
+        }
+        virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
+            if( currentGroupInfo.used ) {
+                printSummaryDivider();
+                stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+                printTotals( _testGroupStats.totals );
+                stream << "\n" << std::endl;
+            }
+            StreamingReporterBase::testGroupEnded( _testGroupStats );
+        }
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotalsDivider( _testRunStats.totals );
+            printTotals( _testRunStats.totals );
+            stream << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            :   stream( _stream ),
+                stats( _stats ),
+                result( _stats.assertionResult ),
+                colour( Colour::None ),
+                message( result.getMessage() ),
+                messages( _stats.infoMessages ),
+                printInfoMessages( _printInfoMessages )
+            {
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        colour = Colour::Success;
+                        passOrFail = "PASSED";
+                        //if( result.hasMessage() )
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() ) {
+                            colour = Colour::Success;
+                            passOrFail = "FAILED - but was ok";
+                        }
+                        else {
+                            colour = Colour::Error;
+                            passOrFail = "FAILED";
+                        }
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ThrewException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to unexpected exception with message";
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to a fatal error condition";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "because no exception was thrown where one was expected";
+                        break;
+                    case ResultWas::Info:
+                        messageLabel = "info";
+                        break;
+                    case ResultWas::Warning:
+                        messageLabel = "warning";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        passOrFail = "FAILED";
+                        colour = Colour::Error;
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "explicitly with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "explicitly with messages";
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        passOrFail = "** internal error **";
+                        colour = Colour::Error;
+                        break;
+                }
+            }
+
+            void print() const {
+                printSourceInfo();
+                if( stats.totals.assertions.total() > 0 ) {
+                    if( result.isOk() )
+                        stream << "\n";
+                    printResultType();
+                    printOriginalExpression();
+                    printReconstructedExpression();
+                }
+                else {
+                    stream << "\n";
+                }
+                printMessage();
+            }
+
+        private:
+            void printResultType() const {
+                if( !passOrFail.empty() ) {
+                    Colour colourGuard( colour );
+                    stream << passOrFail << ":\n";
+                }
+            }
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    Colour colourGuard( Colour::OriginalExpression );
+                    stream  << "  ";
+                    stream << result.getExpressionInMacro();
+                    stream << "\n";
+                }
+            }
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    stream << "with expansion:\n";
+                    Colour colourGuard( Colour::ReconstructedExpression );
+                    stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
+                }
+            }
+            void printMessage() const {
+                if( !messageLabel.empty() )
+                    stream << messageLabel << ":" << "\n";
+                for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+                        it != itEnd;
+                        ++it ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || it->type != ResultWas::Info )
+                        stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
+                }
+            }
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ": ";
+            }
+
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            Colour::Code colour;
+            std::string passOrFail;
+            std::string messageLabel;
+            std::string message;
+            std::vector<MessageInfo> messages;
+            bool printInfoMessages;
+        };
+
+        void lazyPrint() {
+
+            if( !currentTestRunInfo.used )
+                lazyPrintRunInfo();
+            if( !currentGroupInfo.used )
+                lazyPrintGroupInfo();
+
+            if( !m_headerPrinted ) {
+                printTestCaseAndSectionHeader();
+                m_headerPrinted = true;
+            }
+        }
+        void lazyPrintRunInfo() {
+            stream  << "\n" << getLineOfChars<'~'>() << "\n";
+            Colour colour( Colour::SecondaryText );
+            stream  << currentTestRunInfo->name
+                    << " is a Catch v"  << libraryVersion.majorVersion << "."
+                    << libraryVersion.minorVersion << " b"
+                    << libraryVersion.buildNumber;
+            if( libraryVersion.branchName != std::string( "master" ) )
+                stream << " (" << libraryVersion.branchName << ")";
+            stream  << " host application.\n"
+                    << "Run with -? for options\n\n";
+
+            if( m_config->rngSeed() != 0 )
+                stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
+
+            currentTestRunInfo.used = true;
+        }
+        void lazyPrintGroupInfo() {
+            if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
+                printClosedHeader( "Group: " + currentGroupInfo->name );
+                currentGroupInfo.used = true;
+            }
+        }
+        void printTestCaseAndSectionHeader() {
+            assert( !m_sectionStack.empty() );
+            printOpenHeader( currentTestCaseInfo->name );
+
+            if( m_sectionStack.size() > 1 ) {
+                Colour colourGuard( Colour::Headers );
+
+                std::vector<SectionInfo>::const_iterator
+                    it = m_sectionStack.begin()+1, // Skip first section (test case)
+                    itEnd = m_sectionStack.end();
+                for( ; it != itEnd; ++it )
+                    printHeaderString( it->name, 2 );
+            }
+
+            SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+
+            if( !lineInfo.empty() ){
+                stream << getLineOfChars<'-'>() << "\n";
+                Colour colourGuard( Colour::FileName );
+                stream << lineInfo << "\n";
+            }
+            stream << getLineOfChars<'.'>() << "\n" << std::endl;
+        }
+
+        void printClosedHeader( std::string const& _name ) {
+            printOpenHeader( _name );
+            stream << getLineOfChars<'.'>() << "\n";
+        }
+        void printOpenHeader( std::string const& _name ) {
+            stream  << getLineOfChars<'-'>() << "\n";
+            {
+                Colour colourGuard( Colour::Headers );
+                printHeaderString( _name );
+            }
+        }
+
+        // if string has a : in first line will set indent to follow it on
+        // subsequent lines
+        void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
+            std::size_t i = _string.find( ": " );
+            if( i != std::string::npos )
+                i+=2;
+            else
+                i = 0;
+            stream << Text( _string, TextAttributes()
+                                        .setIndent( indent+i)
+                                        .setInitialIndent( indent ) ) << "\n";
+        }
+
+        struct SummaryColumn {
+
+            SummaryColumn( std::string const& _label, Colour::Code _colour )
+            :   label( _label ),
+                colour( _colour )
+            {}
+            SummaryColumn addRow( std::size_t count ) {
+                std::ostringstream oss;
+                oss << count;
+                std::string row = oss.str();
+                for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
+                    while( it->size() < row.size() )
+                        *it = " " + *it;
+                    while( it->size() > row.size() )
+                        row = " " + row;
+                }
+                rows.push_back( row );
+                return *this;
+            }
+
+            std::string label;
+            Colour::Code colour;
+            std::vector<std::string> rows;
+
+        };
+
+        void printTotals( Totals const& totals ) {
+            if( totals.testCases.total() == 0 ) {
+                stream << Colour( Colour::Warning ) << "No tests ran\n";
+            }
+            else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) {
+                stream << Colour( Colour::ResultSuccess ) << "All tests passed";
+                stream << " ("
+                        << pluralise( totals.assertions.passed, "assertion" ) << " in "
+                        << pluralise( totals.testCases.passed, "test case" ) << ")"
+                        << "\n";
+            }
+            else {
+
+                std::vector<SummaryColumn> columns;
+                columns.push_back( SummaryColumn( "", Colour::None )
+                                        .addRow( totals.testCases.total() )
+                                        .addRow( totals.assertions.total() ) );
+                columns.push_back( SummaryColumn( "passed", Colour::Success )
+                                        .addRow( totals.testCases.passed )
+                                        .addRow( totals.assertions.passed ) );
+                columns.push_back( SummaryColumn( "failed", Colour::ResultError )
+                                        .addRow( totals.testCases.failed )
+                                        .addRow( totals.assertions.failed ) );
+                columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
+                                        .addRow( totals.testCases.failedButOk )
+                                        .addRow( totals.assertions.failedButOk ) );
+
+                printSummaryRow( "test cases", columns, 0 );
+                printSummaryRow( "assertions", columns, 1 );
+            }
+        }
+        void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
+            for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
+                std::string value = it->rows[row];
+                if( it->label.empty() ) {
+                    stream << label << ": ";
+                    if( value != "0" )
+                        stream << value;
+                    else
+                        stream << Colour( Colour::Warning ) << "- none -";
+                }
+                else if( value != "0" ) {
+                    stream  << Colour( Colour::LightGrey ) << " | ";
+                    stream  << Colour( it->colour )
+                            << value << " " << it->label;
+                }
+            }
+            stream << "\n";
+        }
+
+        static std::size_t makeRatio( std::size_t number, std::size_t total ) {
+            std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
+            return ( ratio == 0 && number > 0 ) ? 1 : ratio;
+        }
+        static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+            if( i > j && i > k )
+                return i;
+            else if( j > k )
+                return j;
+            else
+                return k;
+        }
+
+        void printTotalsDivider( Totals const& totals ) {
+            if( totals.testCases.total() > 0 ) {
+                std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
+                std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
+                std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
+                while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )++;
+                while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )--;
+
+                stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
+                stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
+                if( totals.testCases.allPassed() )
+                    stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
+                else
+                    stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
+            }
+            else {
+                stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
+            }
+            stream << "\n";
+        }
+        void printSummaryDivider() {
+            stream << getLineOfChars<'-'>() << "\n";
+        }
+
+    private:
+        bool m_headerPrinted;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+    struct CompactReporter : StreamingReporterBase {
+
+        CompactReporter( ReporterConfig const& _config )
+        : StreamingReporterBase( _config )
+        {}
+
+        virtual ~CompactReporter();
+
+        static std::string getDescription() {
+            return "Reports test results on a single line, suitable for IDEs";
+        }
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << "'" << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotals( _testRunStats.totals );
+            stream << "\n" << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            : stream( _stream )
+            , stats( _stats )
+            , result( _stats.assertionResult )
+            , messages( _stats.infoMessages )
+            , itMessage( _stats.infoMessages.begin() )
+            , printInfoMessages( _printInfoMessages )
+            {}
+
+            void print() {
+                printSourceInfo();
+
+                itMessage = messages.begin();
+
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        printResultType( Colour::ResultSuccess, passedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        if ( ! result.hasExpression() )
+                            printRemainingMessages( Colour::None );
+                        else
+                            printRemainingMessages();
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() )
+                            printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
+                        else
+                            printResultType( Colour::Error, failedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ThrewException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "unexpected exception with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::FatalErrorCondition:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "fatal error condition with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::DidntThrowException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "expected exception, got none" );
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Info:
+                        printResultType( Colour::None, "info" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Warning:
+                        printResultType( Colour::None, "warning" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "explicitly" );
+                        printRemainingMessages( Colour::None );
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        printResultType( Colour::Error, "** internal error **" );
+                        break;
+                }
+            }
+
+        private:
+            // Colour::LightGrey
+
+            static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+            static const char* failedString() { return "FAILED"; }
+            static const char* passedString() { return "PASSED"; }
+#else
+            static const char* failedString() { return "failed"; }
+            static const char* passedString() { return "passed"; }
+#endif
+
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ":";
+            }
+
+            void printResultType( Colour::Code colour, std::string passOrFail ) const {
+                if( !passOrFail.empty() ) {
+                    {
+                        Colour colourGuard( colour );
+                        stream << " " << passOrFail;
+                    }
+                    stream << ":";
+                }
+            }
+
+            void printIssue( std::string issue ) const {
+                stream << " " << issue;
+            }
+
+            void printExpressionWas() {
+                if( result.hasExpression() ) {
+                    stream << ";";
+                    {
+                        Colour colour( dimColour() );
+                        stream << " expression was:";
+                    }
+                    printOriginalExpression();
+                }
+            }
+
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    stream << " " << result.getExpression();
+                }
+            }
+
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    {
+                        Colour colour( dimColour() );
+                        stream << " for: ";
+                    }
+                    stream << result.getExpandedExpression();
+                }
+            }
+
+            void printMessage() {
+                if ( itMessage != messages.end() ) {
+                    stream << " '" << itMessage->message << "'";
+                    ++itMessage;
+                }
+            }
+
+            void printRemainingMessages( Colour::Code colour = dimColour() ) {
+                if ( itMessage == messages.end() )
+                    return;
+
+                // using messages.end() directly yields compilation error:
+                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+
+                {
+                    Colour colourGuard( colour );
+                    stream << " with " << pluralise( N, "message" ) << ":";
+                }
+
+                for(; itMessage != itEnd; ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || itMessage->type != ResultWas::Info ) {
+                        stream << " '" << itMessage->message << "'";
+                        if ( ++itMessage != itEnd ) {
+                            Colour colourGuard( dimColour() );
+                            stream << " and";
+                        }
+                    }
+                }
+            }
+
+        private:
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            std::vector<MessageInfo> messages;
+            std::vector<MessageInfo>::const_iterator itMessage;
+            bool printInfoMessages;
+        };
+
+        // Colour, message variants:
+        // - white: No tests ran.
+        // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+        // - white: Passed [both/all] N test cases (no assertions).
+        // -   red: Failed N tests cases, failed M assertions.
+        // - green: Passed [both/all] N tests cases with M assertions.
+
+        std::string bothOrAll( std::size_t count ) const {
+            return count == 1 ? "" : count == 2 ? "both " : "all " ;
+        }
+
+        void printTotals( const Totals& totals ) const {
+            if( totals.testCases.total() == 0 ) {
+                stream << "No tests ran.";
+            }
+            else if( totals.testCases.failed == totals.testCases.total() ) {
+                Colour colour( Colour::ResultError );
+                const std::string qualify_assertions_failed =
+                    totals.assertions.failed == totals.assertions.total() ?
+                        bothOrAll( totals.assertions.failed ) : "";
+                stream <<
+                    "Failed " << bothOrAll( totals.testCases.failed )
+                              << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << qualify_assertions_failed <<
+                                 pluralise( totals.assertions.failed, "assertion" ) << ".";
+            }
+            else if( totals.assertions.total() == 0 ) {
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.total() )
+                              << pluralise( totals.testCases.total(), "test case" )
+                              << " (no assertions).";
+            }
+            else if( totals.assertions.failed ) {
+                Colour colour( Colour::ResultError );
+                stream <<
+                    "Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
+            }
+            else {
+                Colour colour( Colour::ResultSuccess );
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.passed )
+                              << pluralise( totals.testCases.passed, "test case"  ) <<
+                    " with "  << pluralise( totals.assertions.passed, "assertion" ) << ".";
+            }
+        }
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+
+namespace Catch {
+    NonCopyable::~NonCopyable() {}
+    IShared::~IShared() {}
+    StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+    IContext::~IContext() {}
+    IResultCapture::~IResultCapture() {}
+    ITestCase::~ITestCase() {}
+    ITestCaseRegistry::~ITestCaseRegistry() {}
+    IRegistryHub::~IRegistryHub() {}
+    IMutableRegistryHub::~IMutableRegistryHub() {}
+    IExceptionTranslator::~IExceptionTranslator() {}
+    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+    IReporter::~IReporter() {}
+    IReporterFactory::~IReporterFactory() {}
+    IReporterRegistry::~IReporterRegistry() {}
+    IStreamingReporter::~IStreamingReporter() {}
+    AssertionStats::~AssertionStats() {}
+    SectionStats::~SectionStats() {}
+    TestCaseStats::~TestCaseStats() {}
+    TestGroupStats::~TestGroupStats() {}
+    TestRunStats::~TestRunStats() {}
+    CumulativeReporterBase::SectionNode::~SectionNode() {}
+    CumulativeReporterBase::~CumulativeReporterBase() {}
+
+    StreamingReporterBase::~StreamingReporterBase() {}
+    ConsoleReporter::~ConsoleReporter() {}
+    CompactReporter::~CompactReporter() {}
+    IRunner::~IRunner() {}
+    IMutableContext::~IMutableContext() {}
+    IConfig::~IConfig() {}
+    XmlReporter::~XmlReporter() {}
+    JunitReporter::~JunitReporter() {}
+    TestRegistry::~TestRegistry() {}
+    FreeFunctionTestCase::~FreeFunctionTestCase() {}
+    IGeneratorInfo::~IGeneratorInfo() {}
+    IGeneratorsForTest::~IGeneratorsForTest() {}
+    TestSpec::Pattern::~Pattern() {}
+    TestSpec::NamePattern::~NamePattern() {}
+    TestSpec::TagPattern::~TagPattern() {}
+    TestSpec::ExcludedPattern::~ExcludedPattern() {}
+
+    Matchers::Impl::StdString::Equals::~Equals() {}
+    Matchers::Impl::StdString::Contains::~Contains() {}
+    Matchers::Impl::StdString::StartsWith::~StartsWith() {}
+    Matchers::Impl::StdString::EndsWith::~EndsWith() {}
+
+    void Config::dummy() {}
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+// Standard C/C++ main entry point
+int main (int argc, char * const argv[]) {
+    return Catch::Session().run( argc, argv );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run( argc, (char* const*)argv );
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return result;
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#  undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
+
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
+
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
+
+#define CATCH_CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
+    #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
+#else
+    #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
+    #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
+#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define CATCH_GIVEN( desc )    CATCH_SECTION( "Given: " desc, "" )
+#define CATCH_WHEN( desc )     CATCH_SECTION( " When: " desc, "" )
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( "  And: " desc, "" )
+#define CATCH_THEN( desc )     CATCH_SECTION( " Then: " desc, "" )
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( "  And: " desc, "" )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
+
+#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
+
+#define CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
+#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
+    #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
+#else
+    #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
+    #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
+#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define GIVEN( desc )    SECTION( "   Given: " desc, "" )
+#define WHEN( desc )     SECTION( "    When: " desc, "" )
+#define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
+#define THEN( desc )     SECTION( "    Then: " desc, "" )
+#define AND_THEN( desc ) SECTION( "     And: " desc, "" )
+
+using Catch::Detail::Approx;
+
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#    ifdef __ICC // icpc defines the __clang__ macro
+#        pragma warning(pop)
+#    else
+#        pragma clang diagnostic pop
+#    endif
+#elif defined __GNUC__
+#    pragma GCC diagnostic pop
+#endif
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/src/test/nanopolish_test.cpp b/src/test/nanopolish_test.cpp
new file mode 100644
index 0000000..f414b39
--- /dev/null
+++ b/src/test/nanopolish_test.cpp
@@ -0,0 +1,179 @@
+//---------------------------------------------------------
+// Copyright 2015 Ontario Institute for Cancer Research
+// Written by Jared Simpson (jared.simpson at oicr.on.ca)
+//---------------------------------------------------------
+//
+// nanopolish_test -- test driver program
+//
+#define CATCH_CONFIG_MAIN
+#include <stdio.h>
+#include <string>
+#include "logsum.h"
+#include "catch.hpp"
+#include "nanopolish_common.h"
+#include "nanopolish_alphabet.h"
+#include "nanopolish_emissions.h"
+#include "nanopolish_profile_hmm.h"
+
+// This code needs to be run before any of the program logic
+// It sets up pre-computed values and caches
+void initialize()
+{
+    p7_FLogsumInit();
+}
+
+TEST_CASE( "alphabet", "[alphabet]" ) {
+
+    // DNA alphabet
+    DNAAlphabet dna_alphabet;
+    MethylCpGAlphabet mc_alphabet;
+
+    REQUIRE( dna_alphabet.rank('A') == 0 );
+    REQUIRE( dna_alphabet.rank('C') == 1 );
+    REQUIRE( dna_alphabet.rank('G') == 2 );
+    REQUIRE( dna_alphabet.rank('T') == 3 );
+
+    REQUIRE( dna_alphabet.base(0) == 'A' );
+    REQUIRE( dna_alphabet.base(1) == 'C' );
+    REQUIRE( dna_alphabet.base(2) == 'G' );
+    REQUIRE( dna_alphabet.base(3) == 'T' );
+
+    // MethylCpG alphabet
+    REQUIRE( mc_alphabet.rank('A') == 0 );
+    REQUIRE( mc_alphabet.rank('C') == 1 );
+    REQUIRE( mc_alphabet.rank('G') == 2 );
+    REQUIRE( mc_alphabet.rank('M') == 3 );
+    REQUIRE( mc_alphabet.rank('T') == 4 );
+
+    REQUIRE( mc_alphabet.base(0) == 'A' );
+    REQUIRE( mc_alphabet.base(1) == 'C' );
+    REQUIRE( mc_alphabet.base(2) == 'G' );
+    REQUIRE( mc_alphabet.base(3) == 'M' );
+    REQUIRE( mc_alphabet.base(4) == 'T' );
+
+    // Collectively test lexicographic_next and kmer_rank 
+    uint8_t k = 3;
+    uint32_t num_strings = pow((double)mc_alphabet.size(), (double)k);
+    
+    std::string kmer(k, 'A');
+    for(size_t i = 0; i < num_strings - 1; ++i) {
+
+        // check lexicographic next
+        std::string next = kmer;
+        mc_alphabet.lexicographic_next(next);
+        REQUIRE( next > kmer );
+        int rank_diff = mc_alphabet.kmer_rank(next.c_str(), k) - 
+                        mc_alphabet.kmer_rank(kmer.c_str(), k);
+        REQUIRE( rank_diff == 1);
+        kmer = next;
+    }
+    REQUIRE(kmer == "TTT");
+
+    // Test the special reverse complement model
+    // for the CpG alphabet
+    REQUIRE( mc_alphabet.reverse_complement("M") == "G");
+    REQUIRE( mc_alphabet.reverse_complement("C") == "G");
+    REQUIRE( mc_alphabet.reverse_complement("MG") == "MG");
+    REQUIRE( mc_alphabet.reverse_complement("AM") == "GT");
+    REQUIRE( mc_alphabet.reverse_complement("AMG") == "MGT");
+    REQUIRE( mc_alphabet.reverse_complement("GTACATG") == dna_alphabet.reverse_complement("GTACATG"));
+}
+
+TEST_CASE( "string functions", "[string_functions]" ) {
+    DNAAlphabet dna_alphabet;
+
+    // kmer rank
+    REQUIRE( dna_alphabet.kmer_rank("AAAAA", 5) == 0 );
+    REQUIRE( dna_alphabet.kmer_rank("GATGA", 5) == 568 );
+    REQUIRE( dna_alphabet.kmer_rank("TTTTT", 5) == 1023 );
+
+    // lexicographic increment
+    std::string str = "AAAAA";
+    dna_alphabet.lexicographic_next(str);
+    REQUIRE( str == "AAAAC" );
+
+    str = "AAAAT";
+    dna_alphabet.lexicographic_next(str);
+    REQUIRE( str == "AAACA" );
+
+    // complement, reverse complement
+    REQUIRE( dna_alphabet.reverse_complement("GATGA") == "TCATC" );
+}
+
+TEST_CASE( "math", "[math]") {
+    GaussianParameters params;
+    params.mean = 4;
+    params.stdv = 2;
+    params.log_stdv = log(params.stdv);
+
+    REQUIRE( normal_pdf(2.25, params) == Approx(0.1360275) );
+    REQUIRE( log_normal_pdf(2.25, params) == Approx(log(normal_pdf(2.25, params))) );
+}
+
+std::string event_alignment_to_string(const std::vector<HMMAlignmentState>& alignment)
+{
+    std::string out;
+    for(size_t i = 0; i < alignment.size(); ++i) {
+        out.append(1, alignment[i].state);
+    }
+    return out;
+}
+
+TEST_CASE( "hmm", "[hmm]") {
+
+    // read the FAST5
+    SquiggleRead sr("test_read", "test/data/LomanLabz_PC_Ecoli_K12_R7.3_2549_1_ch8_file30_strand.fast5");
+    sr.transform();
+
+    // The reference sequence to align to:
+    std::string ref_subseq = "ATCAGTAAAATAACGTAGAGCGGTAACCTTGCCATAAAGGTCGAGTTTA"
+                             "TTACCATCCTTGTTATAGACTTCGGCAGCGTGTGCTACGTTCGCAGCT";
+
+    // Generate a HMMInputData structure to tell the HMM
+    // which part of the read to align
+    HMMInputData input[2];
+    
+    // template strand
+    input[0].read = &sr;
+    input[0].event_start_idx = 3;
+    input[0].event_stop_idx = 88;
+    input[0].event_stride = 1;
+    input[0].rc = false;
+    input[0].strand = 0;
+    
+    // complement strand
+    input[1].read = &sr;
+    input[1].event_start_idx = 6788;
+    input[1].event_stop_idx = 6697;
+    input[1].event_stride = -1;
+    input[1].rc = true;
+    input[1].strand = 1;
+
+    // expected output
+    std::string expected_alignment[2];
+    expected_alignment[0] = 
+        "MMMMMEMKMKMMMMMMMKMMMKMMMKMMMMMMMMMKKMMEEEMMMMMMKMMMM" 
+        "MMMKMMMMMKMKMKMEMKKMKMKKMMMMMMEMMMMKMKMEEMMMMKMEEEEEM";
+
+    expected_alignment[1] = 
+        "MMKMMMKMEEMMKMKMKMEMMMKMMMKMEMMMKMMMKMMMMMMMMMKKMEMMMM"
+        "EMMMMMMMMKMKKMMMMMMMEMMMMMKMMMMMKMEMMMMMKMMMMMEEEEEEEEM";
+
+    double expected_viterbi_last_state[2] = { -237.7690734863, -266.2348022461 };
+    double expected_forward[2] = { -221.1331481934, -262.7491455078 };
+
+    for(int si = 0; si <= 1; ++si) {
+
+        // viterbi align
+        std::vector<HMMAlignmentState> event_alignment = profile_hmm_align(ref_subseq, input[si]);
+        std::string ea_str = event_alignment_to_string(event_alignment);
+    
+        // check
+        REQUIRE( ea_str == expected_alignment[si]);
+        REQUIRE( event_alignment.back().l_fm == Approx(expected_viterbi_last_state[si]));
+
+        // forward algorithm
+        double lp = profile_hmm_score(ref_subseq, input[si]);
+        REQUIRE(lp == Approx(expected_forward[si]));
+    }
+}
diff --git a/src/thirdparty/stdaln.c b/src/thirdparty/stdaln.c
new file mode 100644
index 0000000..8546b3e
--- /dev/null
+++ b/src/thirdparty/stdaln.c
@@ -0,0 +1,1071 @@
+/* The MIT License
+
+   Copyright (c) 2003-2006, 2008, 2009, by Heng Li <lh3lh3 at gmail.com>
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "stdaln.h"
+
+/* char -> 17 (=16+1) nucleotides */
+unsigned char aln_nt16_table[256] = {
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,16 /*'-'*/,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15, 1,14, 4, 11,15,15, 2, 13,15,15,10, 15, 5,15,15,
+	15,15, 3, 6,  8,15, 7, 9,  0,12,15,15, 15,15,15,15,
+	15, 1,14, 4, 11,15,15, 2, 13,15,15,10, 15, 5,15,15,
+	15,15, 3, 6,  8,15, 7, 9,  0,12,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
+	15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15
+};
+char *aln_nt16_rev_table = "XAGRCMSVTWKDYHBN-";
+
+/* char -> 5 (=4+1) nucleotides */
+unsigned char aln_nt4_table[256] = {
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 5 /*'-'*/, 4, 4,
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 0, 4, 2,  4, 4, 4, 1,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  3, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 0, 4, 2,  4, 4, 4, 1,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  3, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4, 
+	4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4,  4, 4, 4, 4
+};
+char *aln_nt4_rev_table = "AGCTN-";
+
+/* char -> 22 (=20+1+1) amino acids */
+unsigned char aln_aa_table[256] = {
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,20,21, 21,22 /*'-'*/,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21, 0,21, 4,  3, 6,13, 7,  8, 9,21,11, 10,12, 2,21,
+	14, 5, 1,15, 16,21,19,17, 21,18,21,21, 21,21,21,21,
+	21, 0,21, 4,  3, 6,13, 7,  8, 9,21,11, 10,12, 2,21,
+	14, 5, 1,15, 16,21,19,17, 21,18,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21,
+	21,21,21,21, 21,21,21,21, 21,21,21,21, 21,21,21,21
+};
+char *aln_aa_rev_table = "ARNDCQEGHILKMFPSTWYV*X-";
+                       /* 01234567890123456789012 */
+
+/* translation table. They are useless in stdaln.c, but when you realize you need it, you need not write the table again. */
+unsigned char aln_trans_table_eu[66] = {
+	11,11, 2, 2,  1, 1,15,15, 16,16,16,16,  9,12, 9, 9,
+	 6, 6, 3, 3,  7, 7, 7, 7,  0, 0, 0, 0, 19,19,19,19,
+	 5, 5, 8, 8,  1, 1, 1, 1, 14,14,14,14, 10,10,10,10,
+	20,20,18,18, 20,17, 4, 4, 15,15,15,15, 10,10,13,13, 21, 22
+};
+char *aln_trans_table_eu_char = "KKNNRRSSTTTTIMIIEEDDGGGGAAAAVVVVQQHHRRRRPPPPLLLL**YY*WCCSSSSLLFFX";
+                              /* 01234567890123456789012345678901234567890123456789012345678901234 */
+int aln_sm_blosum62[] = {
+/*	 A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V  *  X */
+	 4,-1,-2,-2, 0,-1,-1, 0,-2,-1,-1,-1,-1,-2,-1, 1, 0,-3,-2, 0,-4, 0,
+	-1, 5, 0,-2,-3, 1, 0,-2, 0,-3,-2, 2,-1,-3,-2,-1,-1,-3,-2,-3,-4,-1,
+	-2, 0, 6, 1,-3, 0, 0, 0, 1,-3,-3, 0,-2,-3,-2, 1, 0,-4,-2,-3,-4,-1,
+	-2,-2, 1, 6,-3, 0, 2,-1,-1,-3,-4,-1,-3,-3,-1, 0,-1,-4,-3,-3,-4,-1,
+	 0,-3,-3,-3, 9,-3,-4,-3,-3,-1,-1,-3,-1,-2,-3,-1,-1,-2,-2,-1,-4,-2,
+	-1, 1, 0, 0,-3, 5, 2,-2, 0,-3,-2, 1, 0,-3,-1, 0,-1,-2,-1,-2,-4,-1,
+	-1, 0, 0, 2,-4, 2, 5,-2, 0,-3,-3, 1,-2,-3,-1, 0,-1,-3,-2,-2,-4,-1,
+	 0,-2, 0,-1,-3,-2,-2, 6,-2,-4,-4,-2,-3,-3,-2, 0,-2,-2,-3,-3,-4,-1,
+	-2, 0, 1,-1,-3, 0, 0,-2, 8,-3,-3,-1,-2,-1,-2,-1,-2,-2, 2,-3,-4,-1,
+	-1,-3,-3,-3,-1,-3,-3,-4,-3, 4, 2,-3, 1, 0,-3,-2,-1,-3,-1, 3,-4,-1,
+	-1,-2,-3,-4,-1,-2,-3,-4,-3, 2, 4,-2, 2, 0,-3,-2,-1,-2,-1, 1,-4,-1,
+	-1, 2, 0,-1,-3, 1, 1,-2,-1,-3,-2, 5,-1,-3,-1, 0,-1,-3,-2,-2,-4,-1,
+	-1,-1,-2,-3,-1, 0,-2,-3,-2, 1, 2,-1, 5, 0,-2,-1,-1,-1,-1, 1,-4,-1,
+	-2,-3,-3,-3,-2,-3,-3,-3,-1, 0, 0,-3, 0, 6,-4,-2,-2, 1, 3,-1,-4,-1,
+	-1,-2,-2,-1,-3,-1,-1,-2,-2,-3,-3,-1,-2,-4, 7,-1,-1,-4,-3,-2,-4,-2,
+	 1,-1, 1, 0,-1, 0, 0, 0,-1,-2,-2, 0,-1,-2,-1, 4, 1,-3,-2,-2,-4, 0,
+	 0,-1, 0,-1,-1,-1,-1,-2,-2,-1,-1,-1,-1,-2,-1, 1, 5,-2,-2, 0,-4, 0,
+	-3,-3,-4,-4,-2,-2,-3,-2,-2,-3,-2,-3,-1, 1,-4,-3,-2,11, 2,-3,-4,-2,
+	-2,-2,-2,-3,-2,-1,-2,-3, 2,-1,-1,-2,-1, 3,-3,-2,-2, 2, 7,-1,-4,-1,
+	 0,-3,-3,-3,-1,-2,-2,-3,-3, 3, 1,-2, 1,-1,-2,-2, 0,-3,-1, 4,-4,-1,
+	-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4, 1,-4,
+	 0,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2, 0, 0,-2,-1,-1,-4,-1
+};
+
+int aln_sm_blosum45[] = {
+/*	 A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V  *  X */
+	 5,-2,-1,-2,-1,-1,-1, 0,-2,-1,-1,-1,-1,-2,-1, 1, 0,-2,-2, 0,-5, 0,
+	-2, 7, 0,-1,-3, 1, 0,-2, 0,-3,-2, 3,-1,-2,-2,-1,-1,-2,-1,-2,-5,-1,
+	-1, 0, 6, 2,-2, 0, 0, 0, 1,-2,-3, 0,-2,-2,-2, 1, 0,-4,-2,-3,-5,-1,
+	-2,-1, 2, 7,-3, 0, 2,-1, 0,-4,-3, 0,-3,-4,-1, 0,-1,-4,-2,-3,-5,-1,
+	-1,-3,-2,-3,12,-3,-3,-3,-3,-3,-2,-3,-2,-2,-4,-1,-1,-5,-3,-1,-5,-2,
+	-1, 1, 0, 0,-3, 6, 2,-2, 1,-2,-2, 1, 0,-4,-1, 0,-1,-2,-1,-3,-5,-1,
+	-1, 0, 0, 2,-3, 2, 6,-2, 0,-3,-2, 1,-2,-3, 0, 0,-1,-3,-2,-3,-5,-1,
+	 0,-2, 0,-1,-3,-2,-2, 7,-2,-4,-3,-2,-2,-3,-2, 0,-2,-2,-3,-3,-5,-1,
+	-2, 0, 1, 0,-3, 1, 0,-2,10,-3,-2,-1, 0,-2,-2,-1,-2,-3, 2,-3,-5,-1,
+	-1,-3,-2,-4,-3,-2,-3,-4,-3, 5, 2,-3, 2, 0,-2,-2,-1,-2, 0, 3,-5,-1,
+	-1,-2,-3,-3,-2,-2,-2,-3,-2, 2, 5,-3, 2, 1,-3,-3,-1,-2, 0, 1,-5,-1,
+	-1, 3, 0, 0,-3, 1, 1,-2,-1,-3,-3, 5,-1,-3,-1,-1,-1,-2,-1,-2,-5,-1,
+	-1,-1,-2,-3,-2, 0,-2,-2, 0, 2, 2,-1, 6, 0,-2,-2,-1,-2, 0, 1,-5,-1,
+	-2,-2,-2,-4,-2,-4,-3,-3,-2, 0, 1,-3, 0, 8,-3,-2,-1, 1, 3, 0,-5,-1,
+	-1,-2,-2,-1,-4,-1, 0,-2,-2,-2,-3,-1,-2,-3, 9,-1,-1,-3,-3,-3,-5,-1,
+	 1,-1, 1, 0,-1, 0, 0, 0,-1,-2,-3,-1,-2,-2,-1, 4, 2,-4,-2,-1,-5, 0,
+	 0,-1, 0,-1,-1,-1,-1,-2,-2,-1,-1,-1,-1,-1,-1, 2, 5,-3,-1, 0,-5, 0,
+	-2,-2,-4,-4,-5,-2,-3,-2,-3,-2,-2,-2,-2, 1,-3,-4,-3,15, 3,-3,-5,-2,
+	-2,-1,-2,-2,-3,-1,-2,-3, 2, 0, 0,-1, 0, 3,-3,-2,-1, 3, 8,-1,-5,-1,
+	 0,-2,-3,-3,-1,-3,-3,-3,-3, 3, 1,-2, 1, 0,-3,-1, 0,-3,-1, 5,-5,-1,
+	-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5, 1,-5,
+	 0,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 0,-2,-1,-1,-5,-1
+};
+
+int aln_sm_nt[] = {
+/*	 X  A  G  R  C  M  S  V  T  W  K  D  Y  H  B  N */
+	-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
+	-2, 2,-1, 1,-2, 1,-2, 0,-2, 1,-2, 0,-2, 0,-2, 0,
+	-2,-1, 2, 1,-2,-2, 1, 0,-2,-2, 1, 0,-2,-2, 0, 0,
+	-2, 1, 1, 1,-2,-1,-1, 0,-2,-1,-1, 0,-2, 0, 0, 0,
+	-2,-2,-2,-2, 2, 1, 1, 0,-1,-2,-2,-2, 1, 0, 0, 0,
+	-2, 1,-2,-1, 1, 1,-1, 0,-2,-1,-2, 0,-1, 0, 0, 0,
+	-2,-2, 1,-1, 1,-1, 1, 0,-2,-2,-1, 0,-1, 0, 0, 0,
+	-2, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0,
+	-2,-2,-2,-2,-1,-2,-2,-2, 2, 1, 1, 0, 1, 0, 0, 0,
+	-2, 1,-2,-1,-2,-1,-2, 0, 1, 1,-1, 0,-1, 0, 0, 0,
+	-2,-2, 1,-1,-2,-2,-1, 0, 1,-1, 1, 0,-1, 0, 0, 0,
+	-2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	-2,-2,-2,-2, 1,-1,-1, 0, 1,-1,-1, 0, 1, 0, 0, 0,
+	-2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+int aln_sm_read[] = {
+/*	  X   A   G   R   C   M   S   V   T   W   K   D   Y   H   B   N  */
+	-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,
+	-17,  2,-17,  1,-17,  1,-17,  0,-17,  1,-17,  0,-17,  0,-17,  0,
+	-17,-17,  2,  1,-17,-17,  1,  0,-17,-17,  1,  0,-17,-17,  0,  0,
+	-17,  1,  1,  1,-17,-17,-17,  0,-17,-17,-17,  0,-17,  0,  0,  0,
+	-17,-17,-17,-17,  2,  1,  1,  0,-17,-17,-17,-17,  1,  0,  0,  0,
+	-17,  1,-17,-17,  1,  1,-17,  0,-17,-17,-17,  0,-17,  0,  0,  0,
+	-17,-17,  1,-17,  1,-17,  1,  0,-17,-17,-17,  0,-17,  0,  0,  0,
+	-17,  0,  0,  0,  0,  0,  0,  0,-17,  0,  0,  0,  0,  0,  0,  0,
+	-17,-17,-17,-17,-17,-17,-17,-17,  2,  1,  1,  0,  1,  0,  0,  0,
+	-17,  1,-17,-17,-17,-17,-17,  0,  1,  1,-17,  0,-17,  0,  0,  0,
+	-17,-17,  1,-17,-17,-17,-17,  0,  1,-17,  1,  0,-17,  0,  0,  0,
+	-17,  0,  0,  0,-17,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	-17,-17,-17,-17,  1,-17,-17,  0,  1,-17,-17,  0,  1,  0,  0,  0,
+	-17,  0,-17,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	-17,-17,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	-17,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
+};
+
+int aln_sm_hs[] = {
+/*     A    G    C    T    N */
+	  91, -31,-114,-123, -44,
+	 -31, 100,-125,-114, -42,
+	-123,-125, 100, -31, -42,
+	-114,-114, -31,  91, -42,
+	 -44, -42, -42, -42, -43
+};
+
+int aln_sm_maq[] = {
+	11, -19, -19, -19, -13,
+	-19, 11, -19, -19, -13,
+	-19, -19, 11, -19, -13,
+	-19, -19, -19, 11, -13,
+	-13, -13, -13, -13, -13
+};
+
+int aln_sm_blast[] = {
+	1, -3, -3, -3, -2,
+	-3, 1, -3, -3, -2,
+	-3, -3, 1, -3, -2,
+	-3, -3, -3, 1, -2,
+	-2, -2, -2, -2, -2
+};
+
+/********************/
+/* START OF align.c */
+/********************/
+
+AlnParam aln_param_blast   = {  5,  2,  2, aln_sm_blast, 5, 50 };
+AlnParam aln_param_bwa     = { 26,  9,  5, aln_sm_maq, 5, 50 };
+AlnParam aln_param_nt2nt   = {  8,  2,  2, aln_sm_nt, 16, 75 };
+AlnParam aln_param_rd2rd   = {  1, 19, 19, aln_sm_read, 16, 75 };
+AlnParam aln_param_aa2aa   = { 10,  2,  2, aln_sm_blosum62, 22, 50 };
+
+AlnAln *aln_init_AlnAln()
+{
+	AlnAln *aa;
+	aa = (AlnAln*)malloc(sizeof(AlnAln));
+	aa->path = 0;
+	aa->out1 = aa->out2 = aa->outm = 0;
+	aa->path_len = 0;
+	return aa;
+}
+void aln_free_AlnAln(AlnAln *aa)
+{
+	free(aa->path); free(aa->cigar32);
+	free(aa->out1); free(aa->out2); free(aa->outm);
+	free(aa);
+}
+
+/***************************/
+/* START OF common_align.c */
+/***************************/
+
+#define LOCAL_OVERFLOW_THRESHOLD 32000
+#define LOCAL_OVERFLOW_REDUCE 16000
+#define NT_LOCAL_SCORE int
+#define NT_LOCAL_SHIFT 16
+#define NT_LOCAL_MASK 0xffff
+
+#define SET_INF(s) (s).M = (s).I = (s).D = MINOR_INF;
+
+#define set_M(MM, cur, p, sc)							\
+{														\
+	if ((p)->M >= (p)->I) {								\
+		if ((p)->M >= (p)->D) {							\
+			(MM) = (p)->M + (sc); (cur)->Mt = FROM_M;	\
+		} else {										\
+			(MM) = (p)->D + (sc); (cur)->Mt = FROM_D;	\
+		}												\
+	} else {											\
+		if ((p)->I > (p)->D) {							\
+			(MM) = (p)->I + (sc); (cur)->Mt = FROM_I;	\
+		} else {										\
+			(MM) = (p)->D + (sc); (cur)->Mt = FROM_D;	\
+		}												\
+	}													\
+}
+#define set_I(II, cur, p)								\
+{														\
+	if ((p)->M - gap_open > (p)->I) {					\
+		(cur)->It = FROM_M;								\
+		(II) = (p)->M - gap_open - gap_ext;				\
+	} else {											\
+		(cur)->It = FROM_I;								\
+		(II) = (p)->I - gap_ext;						\
+	}													\
+}
+#define set_end_I(II, cur, p)							\
+{														\
+	if (gap_end >= 0) {									\
+		if ((p)->M - gap_open > (p)->I) {				\
+			(cur)->It = FROM_M;							\
+			(II) = (p)->M - gap_open - gap_end;			\
+		} else {										\
+			(cur)->It = FROM_I;							\
+			(II) = (p)->I - gap_end;					\
+		}												\
+	} else set_I(II, cur, p);							\
+}
+#define set_D(DD, cur, p)								\
+{														\
+	if ((p)->M - gap_open > (p)->D) {					\
+		(cur)->Dt = FROM_M;								\
+		(DD) = (p)->M - gap_open - gap_ext;				\
+	} else {											\
+		(cur)->Dt = FROM_D;								\
+		(DD) = (p)->D - gap_ext;						\
+	}													\
+}
+#define set_end_D(DD, cur, p)							\
+{														\
+	if (gap_end >= 0) {									\
+		if ((p)->M - gap_open > (p)->D) {				\
+			(cur)->Dt = FROM_M;							\
+			(DD) = (p)->M - gap_open - gap_end;			\
+		} else {										\
+			(cur)->Dt = FROM_D;							\
+			(DD) = (p)->D - gap_end;					\
+		}												\
+	} else set_D(DD, cur, p);							\
+}
+
+typedef struct
+{
+	unsigned char Mt:3, It:2, Dt:2;
+} dpcell_t;
+
+typedef struct
+{
+	int M, I, D;
+} dpscore_t;
+
+/* build score profile for accelerating alignment, in theory */
+void aln_init_score_array(unsigned char *seq, int len, int row, int *score_matrix, int **s_array)
+{
+	int *tmp, *tmp2, i, k;
+	for (i = 0; i != row; ++i) {
+		tmp = score_matrix + i * row;
+		tmp2 = s_array[i];
+		for (k = 0; k != len; ++k)
+			tmp2[k] = tmp[seq[k]];
+	}
+}
+/***************************
+ * banded global alignment *
+ ***************************/
+int aln_global_core(unsigned char *seq1, int len1, unsigned char *seq2, int len2, const AlnParam *ap,
+					path_t *path, int *path_len)
+{
+	register int i, j;
+	dpcell_t **dpcell, *q;
+	dpscore_t *curr, *last, *s;
+	path_t *p;
+	int b1, b2, tmp_end;
+	int *mat, end, max;
+	unsigned char type, ctype;
+
+	int gap_open, gap_ext, gap_end, b;
+	int *score_matrix, N_MATRIX_ROW;
+
+	/* initialize some align-related parameters. just for compatibility */
+	gap_open = ap->gap_open;
+	gap_ext = ap->gap_ext;
+	gap_end = ap->gap_end;
+	b = ap->band_width;
+	score_matrix = ap->matrix;
+	N_MATRIX_ROW = ap->row;
+	
+	if (len1 == 0 || len2 == 0) {
+		*path_len = 0;
+		return 0;
+	}
+	/* calculate b1 and b2 */
+	if (len1 > len2) {
+		b1 = len1 - len2 + b;
+		b2 = b;
+	} else {
+		b1 = b;
+		b2 = len2 - len1 + b;
+	}
+	if (b1 > len1) b1 = len1;
+	if (b2 > len2) b2 = len2;
+	--seq1; --seq2;
+
+	/* allocate memory */
+	end = (b1 + b2 <= len1)? (b1 + b2 + 1) : (len1 + 1);
+	dpcell = (dpcell_t**)malloc(sizeof(dpcell_t*) * (len2 + 1));
+	for (j = 0; j <= len2; ++j)
+		dpcell[j] = (dpcell_t*)malloc(sizeof(dpcell_t) * end);
+	for (j = b2 + 1; j <= len2; ++j)
+		dpcell[j] -= j - b2;
+	curr = (dpscore_t*)malloc(sizeof(dpscore_t) * (len1 + 1));
+	last = (dpscore_t*)malloc(sizeof(dpscore_t) * (len1 + 1));
+	
+	/* set first row */
+	SET_INF(*curr); curr->M = 0;
+	for (i = 1, s = curr + 1; i < b1; ++i, ++s) {
+		SET_INF(*s);
+		set_end_D(s->D, dpcell[0] + i, s - 1);
+	}
+	s = curr; curr = last; last = s;
+
+	/* core dynamic programming, part 1 */
+	tmp_end = (b2 < len2)? b2 : len2 - 1;
+	for (j = 1; j <= tmp_end; ++j) {
+		q = dpcell[j]; s = curr; SET_INF(*s);
+		set_end_I(s->I, q, last);
+		end = (j + b1 <= len1 + 1)? (j + b1 - 1) : len1;
+		mat = score_matrix + seq2[j] * N_MATRIX_ROW;
+		++s; ++q;
+		for (i = 1; i != end; ++i, ++s, ++q) {
+			set_M(s->M, q, last + i - 1, mat[seq1[i]]); /* this will change s->M ! */
+			set_I(s->I, q, last + i);
+			set_D(s->D, q, s - 1);
+		}
+		set_M(s->M, q, last + i - 1, mat[seq1[i]]);
+		set_D(s->D, q, s - 1);
+		if (j + b1 - 1 > len1) { /* bug fixed, 040227 */
+			set_end_I(s->I, q, last + i);
+		} else s->I = MINOR_INF;
+		s = curr; curr = last; last = s;
+	}
+	/* last row for part 1, use set_end_D() instead of set_D() */
+	if (j == len2 && b2 != len2 - 1) {
+		q = dpcell[j]; s = curr; SET_INF(*s);
+		set_end_I(s->I, q, last);
+		end = (j + b1 <= len1 + 1)? (j + b1 - 1) : len1;
+		mat = score_matrix + seq2[j] * N_MATRIX_ROW;
+		++s; ++q;
+		for (i = 1; i != end; ++i, ++s, ++q) {
+			set_M(s->M, q, last + i - 1, mat[seq1[i]]); /* this will change s->M ! */
+			set_I(s->I, q, last + i);
+			set_end_D(s->D, q, s - 1);
+		}
+		set_M(s->M, q, last + i - 1, mat[seq1[i]]);
+		set_end_D(s->D, q, s - 1);
+		if (j + b1 - 1 > len1) { /* bug fixed, 040227 */
+			set_end_I(s->I, q, last + i);
+		} else s->I = MINOR_INF;
+		s = curr; curr = last; last = s;
+		++j;
+	}
+
+	/* core dynamic programming, part 2 */
+	for (; j <= len2 - b2 + 1; ++j) {
+		SET_INF(curr[j - b2]);
+		mat = score_matrix + seq2[j] * N_MATRIX_ROW;
+		end = j + b1 - 1;
+		for (i = j - b2 + 1, q = dpcell[j] + i, s = curr + i; i != end; ++i, ++s, ++q) {
+			set_M(s->M, q, last + i - 1, mat[seq1[i]]);
+			set_I(s->I, q, last + i);
+			set_D(s->D, q, s - 1);
+		}
+		set_M(s->M, q, last + i - 1, mat[seq1[i]]);
+		set_D(s->D, q, s - 1);
+		s->I = MINOR_INF;
+		s = curr; curr = last; last = s;
+	}
+
+	/* core dynamic programming, part 3 */
+	for (; j < len2; ++j) {
+		SET_INF(curr[j - b2]);
+		mat = score_matrix + seq2[j] * N_MATRIX_ROW;
+		for (i = j - b2 + 1, q = dpcell[j] + i, s = curr + i; i < len1; ++i, ++s, ++q) {
+			set_M(s->M, q, last + i - 1, mat[seq1[i]]);
+			set_I(s->I, q, last + i);
+			set_D(s->D, q, s - 1);
+		}
+		set_M(s->M, q, last + len1 - 1, mat[seq1[i]]);
+		set_end_I(s->I, q, last + i);
+		set_D(s->D, q, s - 1);
+		s = curr; curr = last; last = s;
+	}
+	/* last row */
+	if (j == len2) {
+		SET_INF(curr[j - b2]);
+		mat = score_matrix + seq2[j] * N_MATRIX_ROW;
+		for (i = j - b2 + 1, q = dpcell[j] + i, s = curr + i; i < len1; ++i, ++s, ++q) {
+			set_M(s->M, q, last + i - 1, mat[seq1[i]]);
+			set_I(s->I, q, last + i);
+			set_end_D(s->D, q, s - 1);
+		}
+		set_M(s->M, q, last + len1 - 1, mat[seq1[i]]);
+		set_end_I(s->I, q, last + i);
+		set_end_D(s->D, q, s - 1);
+		s = curr; curr = last; last = s;
+	}
+
+	/* backtrace */
+	i = len1; j = len2;
+	q = dpcell[j] + i;
+	s = last + len1;
+	max = s->M; type = q->Mt; ctype = FROM_M;
+	if (s->I > max) { max = s->I; type = q->It; ctype = FROM_I; }
+	if (s->D > max) { max = s->D; type = q->Dt; ctype = FROM_D; }
+
+	p = path;
+	p->ctype = ctype; p->i = i; p->j = j; /* bug fixed 040408 */
+	++p;
+	do {
+		switch (ctype) {
+			case FROM_M: --i; --j; break;
+			case FROM_I: --j; break;
+			case FROM_D: --i; break;
+		}
+		q = dpcell[j] + i;
+		ctype = type;
+		switch (type) {
+			case FROM_M: type = q->Mt; break;
+			case FROM_I: type = q->It; break;
+			case FROM_D: type = q->Dt; break;
+		}
+		p->ctype = ctype; p->i = i; p->j = j;
+		++p;
+	} while (i || j);
+	*path_len = p - path - 1;
+	/* free memory */
+	for (j = b2 + 1; j <= len2; ++j)
+		dpcell[j] += j - b2;
+	for (j = 0; j <= len2; ++j)
+		free(dpcell[j]);
+	free(dpcell);
+	free(curr); free(last);
+	
+	return max;
+}
+/*************************************************
+ * local alignment combined with banded strategy *
+ *************************************************/
+int aln_local_core(unsigned char *seq1, int len1, unsigned char *seq2, int len2, const AlnParam *ap,
+				   path_t *path, int *path_len, int _thres, int *_subo)
+{
+	register NT_LOCAL_SCORE *s;
+	register int i;
+	int q, r, qr, tmp_len, qr_shift;
+	int **s_array, *score_array;
+	int e, f;
+	int is_overflow, of_base;
+	NT_LOCAL_SCORE *eh, curr_h, last_h, curr_last_h;
+	int j, start_i, start_j, end_i, end_j;
+	path_t *p;
+	int score_f, score_r, score_g;
+	int start, end, max_score;
+	int thres, *suba, *ss;
+
+	int gap_open, gap_ext, b;
+	int *score_matrix, N_MATRIX_ROW;
+
+	/* initialize some align-related parameters. just for compatibility */
+	gap_open = ap->gap_open;
+	gap_ext = ap->gap_ext;
+	b = ap->band_width;
+	score_matrix = ap->matrix;
+	N_MATRIX_ROW = ap->row;
+	thres = _thres > 0? _thres : -_thres;
+
+	if (len1 == 0 || len2 == 0) return -1;
+
+	/* allocate memory */
+	suba = (int*)malloc(sizeof(int) * (len2 + 1));
+	eh = (NT_LOCAL_SCORE*)malloc(sizeof(NT_LOCAL_SCORE) * (len1 + 1));
+	s_array = (int**)malloc(sizeof(int*) * N_MATRIX_ROW);
+	for (i = 0; i != N_MATRIX_ROW; ++i)
+		s_array[i] = (int*)malloc(sizeof(int) * len1);
+	/* initialization */
+	aln_init_score_array(seq1, len1, N_MATRIX_ROW, score_matrix, s_array);
+	q = gap_open;
+	r = gap_ext;
+	qr = q + r;
+	qr_shift = (qr+1) << NT_LOCAL_SHIFT;
+	tmp_len = len1 + 1;
+	start_i = start_j = end_i = end_j = 0;
+	for (i = 0, max_score = 0; i != N_MATRIX_ROW * N_MATRIX_ROW; ++i)
+		if (max_score < score_matrix[i]) max_score = score_matrix[i];
+	/* convert the coordinate */
+	--seq1; --seq2;
+	for (i = 0; i != N_MATRIX_ROW; ++i) --s_array[i];
+
+	/* forward dynamic programming */
+	for (i = 0, s = eh; i != tmp_len; ++i, ++s) *s = 0;
+	score_f = 0;
+	is_overflow = of_base = 0;
+	suba[0] = 0;
+	for (j = 1, ss = suba + 1; j <= len2; ++j, ++ss) {
+		int subo = 0;
+		last_h = f = 0;
+		score_array = s_array[seq2[j]];
+		if (is_overflow) { /* adjust eh[] array if overflow occurs. */
+			/* If LOCAL_OVERFLOW_REDUCE is too small, optimal alignment might be missed.
+			 * If it is too large, this block will be excuted frequently and therefore
+			 * slow down the whole program.
+			 * Acually, smaller LOCAL_OVERFLOW_REDUCE might also help to reduce the
+			 * number of assignments because it sets some cells to zero when overflow
+			 * happens. */
+			int tmp, tmp2;
+			score_f -= LOCAL_OVERFLOW_REDUCE;
+			of_base += LOCAL_OVERFLOW_REDUCE;
+			is_overflow = 0;
+			for (i = 1, s = eh; i <= tmp_len; ++i, ++s) {
+				tmp = *s >> NT_LOCAL_SHIFT; tmp2 = *s & NT_LOCAL_MASK;
+				if (tmp2 < LOCAL_OVERFLOW_REDUCE) tmp2 = 0;
+				else tmp2 -= LOCAL_OVERFLOW_REDUCE;
+				if (tmp < LOCAL_OVERFLOW_REDUCE) tmp = 0;
+				else tmp -= LOCAL_OVERFLOW_REDUCE;
+				*s = (tmp << NT_LOCAL_SHIFT) | tmp2;
+			}
+		}
+		for (i = 1, s = eh; i != tmp_len; ++i, ++s) {
+			/* prepare for calculate current h */
+			curr_h = (*s >> NT_LOCAL_SHIFT) + score_array[i];
+			if (curr_h < 0) curr_h = 0;
+			if (last_h > 0) { /* initialize f */
+				f = (f > last_h - q)? f - r : last_h - qr;
+				if (curr_h < f) curr_h = f;
+			}
+			if (*(s+1) >= qr_shift) { /* initialize e */
+				curr_last_h = *(s+1) >> NT_LOCAL_SHIFT;
+				e = ((*s & NT_LOCAL_MASK) > curr_last_h - q)? (*s & NT_LOCAL_MASK) - r : curr_last_h - qr;
+				if (curr_h < e) curr_h = e;
+				*s = (last_h << NT_LOCAL_SHIFT) | e;
+			} else *s = last_h << NT_LOCAL_SHIFT; /* e = 0 */
+			last_h = curr_h;
+			if (subo < curr_h) subo = curr_h;
+			if (score_f < curr_h) {
+				score_f = curr_h; end_i = i; end_j = j;
+				if (score_f > LOCAL_OVERFLOW_THRESHOLD) is_overflow = 1;
+			}
+		}
+		*s = last_h << NT_LOCAL_SHIFT;
+		*ss = subo + of_base;
+	}
+	score_f += of_base;
+
+	if (score_f < thres) { /* no matching residue at all, 090218 */
+		*path_len = 0;
+		goto end_func;
+	}
+	if (path == 0) goto end_func; /* skip path-filling */
+
+	/* reverse dynamic programming */
+	for (i = end_i, s = eh + end_i; i >= 0; --i, --s) *s = 0;
+	if (end_i == 0 || end_j == 0) goto end_func; /* no local match */
+	score_r = score_matrix[seq1[end_i] * N_MATRIX_ROW + seq2[end_j]];
+	is_overflow = of_base = 0;
+	start_i = end_i; start_j = end_j;
+	eh[end_i] = ((NT_LOCAL_SCORE)(qr + score_r)) << NT_LOCAL_SHIFT; /* in order to initialize f and e, 040408 */
+	start = end_i - 1;
+	end = end_i - 3;
+	if (end <= 0) end = 0;
+
+	/* second pass DP can be done in a band, speed will thus be enhanced */
+	for (j = end_j - 1; j != 0; --j) {
+		last_h = f = 0;
+		score_array = s_array[seq2[j]];
+		if (is_overflow) { /* adjust eh[] array if overflow occurs. */
+			int tmp, tmp2;
+			score_r -= LOCAL_OVERFLOW_REDUCE;
+			of_base += LOCAL_OVERFLOW_REDUCE;
+			is_overflow = 0;
+			for (i = start, s = eh + start + 1; i >= end; --i, --s) {
+				tmp = *s >> NT_LOCAL_SHIFT; tmp2 = *s & NT_LOCAL_MASK;
+				if (tmp2 < LOCAL_OVERFLOW_REDUCE) tmp2 = 0;
+				else tmp2 -= LOCAL_OVERFLOW_REDUCE;
+				if (tmp < LOCAL_OVERFLOW_REDUCE) tmp = 0;
+				else tmp -= LOCAL_OVERFLOW_REDUCE;
+				*s = (tmp << NT_LOCAL_SHIFT) | tmp2;
+			}
+		}
+		for (i = start, s = eh + start + 1; i != end; --i, --s) {
+			/* prepare for calculate current h */
+			curr_h = (*s >> NT_LOCAL_SHIFT) + score_array[i];
+			if (curr_h < 0) curr_h = 0;
+			if (last_h > 0) { /* initialize f */
+				f = (f > last_h - q)? f - r : last_h - qr;
+				if (curr_h < f) curr_h = f;
+			}
+			curr_last_h = *(s-1) >> NT_LOCAL_SHIFT;
+			e = ((*s & NT_LOCAL_MASK) > curr_last_h - q)? (*s & NT_LOCAL_MASK) - r : curr_last_h - qr;
+			if (e < 0) e = 0;
+			if (curr_h < e) curr_h = e;
+			*s = (last_h << NT_LOCAL_SHIFT) | e;
+			last_h = curr_h;
+			if (score_r < curr_h) {
+				score_r = curr_h; start_i = i; start_j = j;
+				if (score_r + of_base - qr == score_f) {
+					j = 1; break;
+				}
+				if (score_r > LOCAL_OVERFLOW_THRESHOLD) is_overflow = 1;
+			}
+		}
+		*s = last_h << NT_LOCAL_SHIFT;
+		/* recalculate start and end, the boundaries of the band */
+		if ((eh[start] >> NT_LOCAL_SHIFT) <= qr) --start;
+		if (start <= 0) start = 0;
+		end = start_i - (start_j - j) - (score_r + of_base + (start_j - j) * max_score) / r - 1;
+		if (end <= 0) end = 0;
+	}
+
+	if (_subo) {
+		int tmp2 = 0, tmp = (int)(start_j - .33 * (end_j - start_j) + .499);
+		for (j = 1; j <= tmp; ++j)
+			if (tmp2 < suba[j]) tmp2 = suba[j];
+		tmp = (int)(end_j + .33 * (end_j - start_j) + .499);
+		for (j = tmp; j <= len2; ++j)
+			if (tmp2 < suba[j]) tmp2 = suba[j];
+		*_subo = tmp2;
+	}
+
+	if (path_len == 0) {
+		path[0].i = start_i; path[0].j = start_j;
+		path[1].i = end_i; path[1].j = end_j;
+		goto end_func;
+	}
+
+	score_r += of_base;
+	score_r -= qr;
+
+#ifdef DEBUG
+	/* this seems not a bug */
+	if (score_f != score_r)
+		fprintf(stderr, "[aln_local_core] unknown flaw occurs: score_f(%d) != score_r(%d)\n", score_f, score_r);
+#endif
+
+	if (_thres > 0) { /* call global alignment to fill the path */
+		score_g = 0;
+		j = (end_i - start_i > end_j - start_j)? end_i - start_i : end_j - start_j;
+		++j; /* j is the maximum band_width */
+		for (i = ap->band_width;; i <<= 1) {
+			AlnParam ap_real = *ap;
+			ap_real.gap_end = -1;
+			ap_real.band_width = i;
+			score_g = aln_global_core(seq1 + start_i, end_i - start_i + 1, seq2 + start_j,
+									  end_j - start_j + 1, &ap_real, path, path_len);
+			if (score_g == score_r || score_f == score_g) break;
+			if (i > j) break;
+		}
+		if (score_r > score_g && score_f > score_g) {
+			fprintf(stderr, "[aln_local_core] Potential bug: (%d,%d) > %d\n", score_f, score_r, score_g);
+			score_f = score_r = -1;
+		} else score_f = score_g;
+
+		/* convert coordinate */
+		for (p = path + *path_len - 1; p >= path; --p) {
+			p->i += start_i - 1;
+			p->j += start_j - 1;
+		}
+	} else { /* just store the start and end */
+		*path_len = 2;
+		path[1].i = start_i; path[1].j = start_j;
+		path->i = end_i; path->j = end_j;
+	}
+
+end_func:
+	/* free */
+	free(eh); free(suba);
+	for (i = 0; i != N_MATRIX_ROW; ++i) {
+		++s_array[i];
+		free(s_array[i]);
+	}
+	free(s_array);
+	return score_f;
+}
+AlnAln *aln_stdaln_aux(const char *seq1, const char *seq2, const AlnParam *ap,
+					   int type, int thres, int len1, int len2)
+{
+	unsigned char *seq11, *seq22;
+	int score;
+	int i, j, l;
+	path_t *p;
+	char *out1, *out2, *outm;
+	AlnAln *aa;
+
+	if (len1 < 0) len1 = strlen(seq1);
+	if (len2 < 0) len2 = strlen(seq2);
+
+	aa = aln_init_AlnAln();
+	seq11 = (unsigned char*)malloc(sizeof(unsigned char) * len1);
+	seq22 = (unsigned char*)malloc(sizeof(unsigned char) * len2);
+	aa->path = (path_t*)malloc(sizeof(path_t) * (len1 + len2 + 1));
+
+	if (ap->row < 10) { /* 4-nucleotide alignment */
+		for (i = 0; i < len1; ++i)
+			seq11[i] = aln_nt4_table[(int)seq1[i]];
+		for (j = 0; j < len2; ++j)
+			seq22[j] = aln_nt4_table[(int)seq2[j]];
+	} else if (ap->row < 20) { /* 16-nucleotide alignment */
+		for (i = 0; i < len1; ++i)
+			seq11[i] = aln_nt16_table[(int)seq1[i]];
+		for (j = 0; j < len2; ++j)
+			seq22[j] = aln_nt16_table[(int)seq2[j]];
+	} else { /* amino acids */
+		for (i = 0; i < len1; ++i)
+			seq11[i] = aln_aa_table[(int)seq1[i]];
+		for (j = 0; j < len2; ++j)
+			seq22[j] = aln_aa_table[(int)seq2[j]];
+	}
+	
+	if (type == ALN_TYPE_GLOBAL) score = aln_global_core(seq11, len1, seq22, len2, ap, aa->path, &aa->path_len);
+	else if (type == ALN_TYPE_LOCAL) score = aln_local_core(seq11, len1, seq22, len2, ap, aa->path, &aa->path_len, thres, &aa->subo);
+	else if (type == ALN_TYPE_EXTEND)  score = aln_extend_core(seq11, len1, seq22, len2, ap, aa->path, &aa->path_len, 1, 0);
+	else {
+		free(seq11); free(seq22); free(aa->path);
+		aln_free_AlnAln(aa);
+		return 0;
+	}
+	aa->score = score;
+
+	if (thres > 0) {
+		out1 = aa->out1 = (char*)malloc(sizeof(char) * (aa->path_len + 1));
+		out2 = aa->out2 = (char*)malloc(sizeof(char) * (aa->path_len + 1));
+		outm = aa->outm = (char*)malloc(sizeof(char) * (aa->path_len + 1));
+
+		--seq1; --seq2;
+		--seq11; --seq22;
+
+		p = aa->path + aa->path_len - 1;
+
+		for (l = 0; p >= aa->path; --p, ++l) {
+			switch (p->ctype) {
+			case FROM_M: out1[l] = seq1[p->i]; out2[l] = seq2[p->j];
+				outm[l] = (seq11[p->i] == seq22[p->j] && seq11[p->i] != ap->row)? '|' : ' ';
+				break;
+			case FROM_I: out1[l] = '-'; out2[l] = seq2[p->j]; outm[l] = ' '; break;
+			case FROM_D: out1[l] = seq1[p->i]; out2[l] = '-'; outm[l] = ' '; break;
+			}
+		}
+		out1[l] = out2[l] = outm[l] = '\0';
+		++seq11; ++seq22;
+	}
+
+	free(seq11);
+	free(seq22);
+
+	p = aa->path + aa->path_len - 1;
+	aa->start1 = p->i? p->i : 1;
+	aa->end1 = aa->path->i;
+	aa->start2 = p->j? p->j : 1;
+	aa->end2 = aa->path->j;
+	aa->cigar32 = aln_path2cigar32(aa->path, aa->path_len, &aa->n_cigar);
+
+	return aa;
+}
+AlnAln *aln_stdaln(const char *seq1, const char *seq2, const AlnParam *ap, int type, int thres)
+{
+	return aln_stdaln_aux(seq1, seq2, ap, type, thres, -1, -1);
+}
+
+/* for backward compatibility */
+uint16_t *aln_path2cigar(const path_t *path, int path_len, int *n_cigar)
+{
+	uint32_t *cigar32;
+	uint16_t *cigar;
+	int i;
+	cigar32 = aln_path2cigar32(path, path_len, n_cigar);
+	cigar = (uint16_t*)cigar32;
+	for (i = 0; i < *n_cigar; ++i)
+		cigar[i] = (cigar32[i]&0xf)<<14 | (cigar32[i]>>4&0x3fff);
+	return cigar;
+}
+
+/* newly added functions (2009-07-21) */
+
+int aln_extend_core(unsigned char *seq1, int len1, unsigned char *seq2, int len2, const AlnParam *ap,
+					path_t *path, int *path_len, int G0, uint8_t *_mem)
+{
+	int q, r, qr, tmp_len;
+	int32_t **s_array, *score_array;
+	int is_overflow, of_base;
+	uint32_t *eh;
+	int i, j, end_i, end_j;
+	int score, start, end;
+	int *score_matrix, N_MATRIX_ROW;
+	uint8_t *mem, *_p;
+
+	/* initialize some align-related parameters. just for compatibility */
+	q = ap->gap_open;
+	r = ap->gap_ext;
+	qr = q + r;
+	score_matrix = ap->matrix;
+	N_MATRIX_ROW = ap->row;
+
+	if (len1 == 0 || len2 == 0) return -1;
+
+	/* allocate memory */
+	mem = _mem? _mem : calloc((len1 + 2) * (N_MATRIX_ROW + 1), 4);
+	_p = mem;
+	eh = (uint32_t*)_p, _p += 4 * (len1 + 2);
+	s_array = calloc(N_MATRIX_ROW, sizeof(void*));
+	for (i = 0; i != N_MATRIX_ROW; ++i)
+		s_array[i] = (int32_t*)_p, _p += 4 * len1;
+	/* initialization */
+	aln_init_score_array(seq1, len1, N_MATRIX_ROW, score_matrix, s_array);
+	tmp_len = len1 + 1;
+	start = 1; end = 2;
+	end_i = end_j = 0;
+	score = 0;
+	is_overflow = of_base = 0;
+	/* convert the coordinate */
+	--seq1; --seq2;
+	for (i = 0; i != N_MATRIX_ROW; ++i) --s_array[i];
+
+	/* dynamic programming */
+	memset(eh, 0, 4 * (len1 + 2));
+	eh[1] = (uint32_t)G0<<16;
+	for (j = 1; j <= len2; ++j) {
+		int _start, _end;
+		int h1 = 0, f = 0;
+		score_array = s_array[seq2[j]];
+		/* set start and end */
+		_start = j - ap->band_width;
+		if (_start < 1) _start = 1;
+		if (_start > start) start = _start;
+		_end = j + ap->band_width;
+		if (_end > len1 + 1) _end = len1 + 1;
+		if (_end < end) end = _end;
+		if (start == end) break;
+		/* adjust eh[] array if overflow occurs. */
+		if (is_overflow) {
+			int tmp, tmp2;
+			score -= LOCAL_OVERFLOW_REDUCE;
+			of_base += LOCAL_OVERFLOW_REDUCE;
+			is_overflow = 0;
+			for (i = start; i <= end; ++i) {
+				uint32_t *s = &eh[i];
+				tmp = *s >> 16; tmp2 = *s & 0xffff;
+				if (tmp2 < LOCAL_OVERFLOW_REDUCE) tmp2 = 0;
+				else tmp2 -= LOCAL_OVERFLOW_REDUCE;
+				if (tmp < LOCAL_OVERFLOW_REDUCE) tmp = 0;
+				else tmp -= LOCAL_OVERFLOW_REDUCE;
+				*s = (tmp << 16) | tmp2;
+			}
+		}
+		_start = _end = 0;
+		/* the inner loop */
+		for (i = start; i < end; ++i) {
+			/* At the beginning of each cycle:
+			     eh[i] -> h[j-1,i-1]<<16 | e[j,i]
+				 f     -> f[j,i]
+				 h1    -> h[j,i-1]
+			*/
+			uint32_t *s = &eh[i];
+			int h = (int)(*s >> 16);
+			int e = *s & 0xffff; /* this is e[j,i] */
+			*s = (uint32_t)h1 << 16; /* eh[i] now stores h[j,i-1]<<16 */
+			h += h? score_array[i] : 0; /* this is left_core() specific */
+			/* calculate h[j,i]; don't need to test 0, as {e,f}>=0 */
+			h = h > e? h : e;
+			h = h > f? h : f; /* h now is h[j,i] */
+			h1 = h;
+			if (h > 0) {
+				if (_start == 0) _start = i;
+				_end = i;
+				if (score < h) {
+					score = h; end_i = i; end_j = j;
+					if (score > LOCAL_OVERFLOW_THRESHOLD) is_overflow = 1;
+				}
+			}
+			/* calculate e[j+1,i] and f[j,i+1] */
+			h -= qr;
+			h = h > 0? h : 0;
+			e -= r;
+			e = e > h? e : h;
+			f -= r;
+			f = f > h? f : h;
+			*s |= e;
+		}			
+		eh[end] = h1 << 16;
+		/* recalculate start and end, the boundaries of the band */
+		if (_end <= 0) break; /* no cell in this row has a positive score */
+		start = _start;
+		end = _end + 3;
+	}
+
+	score += of_base - 1;
+	if (score <= 0) {
+		if (path_len) *path_len = 0;
+		goto end_left_func;
+	}
+
+	if (path == 0) goto end_left_func;
+
+	if (path_len == 0) {
+		path[0].i = end_i; path[0].j = end_j;
+		goto end_left_func;
+	}
+
+	{ /* call global alignment to fill the path */
+		int score_g = 0;
+		j = (end_i - 1 > end_j - 1)? end_i - 1 : end_j - 1;
+		++j; /* j is the maximum band_width */
+		for (i = ap->band_width;; i <<= 1) {
+			AlnParam ap_real = *ap;
+			ap_real.gap_end = -1;
+			ap_real.band_width = i;
+			score_g = aln_global_core(seq1 + 1, end_i, seq2 + 1, end_j, &ap_real, path, path_len);
+			if (score == score_g) break;
+			if (i > j) break;
+		}
+		if (score > score_g)
+			fprintf(stderr, "[aln_left_core] no suitable bandwidth: %d < %d\n", score_g, score);
+		score = score_g;
+	}
+
+end_left_func:
+	/* free */
+	free(s_array);
+	if (!_mem) free(mem);
+	return score;
+}
+
+uint32_t *aln_path2cigar32(const path_t *path, int path_len, int *n_cigar)
+{
+	int i, n;
+	uint32_t *cigar;
+	unsigned char last_type;
+
+	if (path_len == 0 || path == 0) {
+		*n_cigar = 0;
+		return 0;
+	}
+
+	last_type = path->ctype;
+	for (i = n = 1; i < path_len; ++i) {
+		if (last_type != path[i].ctype) ++n;
+		last_type = path[i].ctype;
+	}
+	*n_cigar = n;
+	cigar = (uint32_t*)malloc(*n_cigar * 4);
+
+	cigar[0] = 1u << 4 | path[path_len-1].ctype;
+	last_type = path[path_len-1].ctype;
+	for (i = path_len - 2, n = 0; i >= 0; --i) {
+		if (path[i].ctype == last_type) cigar[n] += 1u << 4;
+		else {
+			cigar[++n] = 1u << 4 | path[i].ctype;
+			last_type = path[i].ctype;
+		}
+	}
+
+	return cigar;
+}
+
+#ifdef STDALN_MAIN
+int main()
+{
+	AlnAln *aln_local, *aln_global, *aln_left;
+	int i;
+
+	aln_local  = aln_stdaln("CGTGCGATGCactgCATACGGCTCGCCTAGATCA", "AAGGGATGCTCTGCATCgCTCGGCTAGCTGT", &aln_param_blast, 0, 1);
+	aln_global = aln_stdaln("CGTGCGATGCactgCATACGGCTCGCCTAGATCA", "AAGGGATGCTCTGCATCGgCTCGGCTAGCTGT", &aln_param_blast, 1, 1);
+//	aln_left   = aln_stdaln(     "GATGCACTGCATACGGCTCGCCTAGATCA",     "GATGCTCTGCATCGgCTCGGCTAGCTGT", &aln_param_blast, 2, 1);
+	aln_left   = aln_stdaln("CACCTTCGACTCACGTCTCATTCTCGGAGTCGAGTGGACGGTCCCTCATACACGAACAGGTTC",
+							"CACCTTCGACTTTCACCTCTCATTCTCGGACTCGAGTGGACGGTCCCTCATCCAAGAACAGGGTCTGTGAAA", &aln_param_blast, 2, 1);
+
+	printf(">%d,%d\t%d,%d\n", aln_local->start1, aln_local->end1, aln_local->start2, aln_local->end2);
+	printf("%s\n%s\n%s\n", aln_local->out1, aln_local->outm, aln_local->out2);
+
+	printf(">%d,%d\t%d,%d\t", aln_global->start1, aln_global->end1, aln_global->start2, aln_global->end2);
+	for (i = 0; i != aln_global->n_cigar; ++i)
+		printf("%d%c", aln_global->cigar32[i]>>4, "MID"[aln_global->cigar32[i]&0xf]);
+	printf("\n%s\n%s\n%s\n", aln_global->out1, aln_global->outm, aln_global->out2);
+
+	printf(">%d\t%d,%d\t%d,%d\t", aln_left->score, aln_left->start1, aln_left->end1, aln_left->start2, aln_left->end2);
+	for (i = 0; i != aln_left->n_cigar; ++i)
+		printf("%d%c", aln_left->cigar32[i]>>4, "MID"[aln_left->cigar32[i]&0xf]);
+	printf("\n%s\n%s\n%s\n", aln_left->out1, aln_left->outm, aln_left->out2);
+
+	aln_free_AlnAln(aln_local);
+	aln_free_AlnAln(aln_global);
+	aln_free_AlnAln(aln_left);
+	return 0;
+}
+#endif
diff --git a/src/thirdparty/stdaln.h b/src/thirdparty/stdaln.h
new file mode 100644
index 0000000..f0048b3
--- /dev/null
+++ b/src/thirdparty/stdaln.h
@@ -0,0 +1,162 @@
+/* The MIT License
+
+   Copyright (c) 2003-2006, 2008, by Heng Li <lh3lh3 at gmail.com>
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be
+   included in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+   SOFTWARE.
+*/
+
+/*
+  2009-07-23, 0.10.0
+
+  - Use 32-bit to store CIGAR
+
+  - Report suboptimal aligments
+
+  - Implemented half-fixed-half-open DP
+
+  2009-04-26, 0.9.10
+
+  - Allow to set a threshold for local alignment
+
+  2009-02-18, 0.9.9
+
+  - Fixed a bug when no residue matches
+
+  2008-08-04, 0.9.8
+
+  - Fixed the wrong declaration of aln_stdaln_aux()
+
+  - Avoid 0 coordinate for global alignment
+
+  2008-08-01, 0.9.7
+
+  - Change gap_end penalty to 5 in aln_param_bwa
+
+  - Add function to convert path_t to the CIGAR format
+
+  2008-08-01, 0.9.6
+
+  - The first gap now costs (gap_open+gap_ext), instead of
+    gap_open. Scoring systems are modified accordingly.
+
+  - Gap end is now correctly handled. Previously it is not correct.
+
+  - Change license to MIT.
+
+ */
+
+#ifndef LH3_STDALN_H_
+#define LH3_STDALN_H_
+
+
+#define STDALN_VERSION 0.11.0
+
+#include <stdint.h>
+
+#define FROM_M 0
+#define FROM_I 1
+#define FROM_D 2
+#define FROM_S 3
+
+#define ALN_TYPE_LOCAL  0
+#define ALN_TYPE_GLOBAL 1
+#define ALN_TYPE_EXTEND 2
+
+/* This is the smallest integer. It might be CPU-dependent in very RARE cases. */
+#define MINOR_INF -1073741823
+
+typedef struct
+{
+	int gap_open;
+	int gap_ext;
+	int gap_end;
+
+	int *matrix;
+	int row;
+	int band_width;
+} AlnParam;
+
+typedef struct
+{
+	int i, j;
+	unsigned char ctype;
+} path_t;
+
+typedef struct
+{
+	path_t *path; /* for advanced users... :-) */
+	int path_len; /* for advanced users... :-) */
+	int start1, end1; /* start and end of the first sequence, coordinations are 1-based */
+	int start2, end2; /* start and end of the second sequence, coordinations are 1-based */
+	int score, subo; /* score */
+
+	char *out1, *out2; /* print them, and then you will know */
+	char *outm;
+
+	int n_cigar;
+	uint32_t *cigar32;
+} AlnAln;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	AlnAln *aln_stdaln_aux(const char *seq1, const char *seq2, const AlnParam *ap,
+						   int type, int do_align, int len1, int len2);
+	AlnAln *aln_stdaln(const char *seq1, const char *seq2, const AlnParam *ap, int type, int do_align);
+	void aln_free_AlnAln(AlnAln *aa);
+
+	int aln_global_core(unsigned char *seq1, int len1, unsigned char *seq2, int len2, const AlnParam *ap,
+						path_t *path, int *path_len);
+	int aln_local_core(unsigned char *seq1, int len1, unsigned char *seq2, int len2, const AlnParam *ap,
+					   path_t *path, int *path_len, int _thres, int *_subo);
+	int aln_extend_core(unsigned char *seq1, int len1, unsigned char *seq2, int len2, const AlnParam *ap,
+						path_t *path, int *path_len, int G0, uint8_t *_mem);
+	uint16_t *aln_path2cigar(const path_t *path, int path_len, int *n_cigar);
+	uint32_t *aln_path2cigar32(const path_t *path, int path_len, int *n_cigar);
+
+#ifdef __cplusplus
+}
+#endif
+
+/********************
+ * global variables *
+ ********************/
+
+extern AlnParam aln_param_bwa;   /* = { 37,  9,  0, aln_sm_maq, 5, 50 }; */
+extern AlnParam aln_param_blast; /* = {  5,  2,  2, aln_sm_blast, 5, 50 }; */
+extern AlnParam aln_param_nt2nt; /* = { 10,  2,  2, aln_sm_nt, 16, 75 }; */
+extern AlnParam aln_param_aa2aa; /* = { 20, 19, 19, aln_sm_read, 16, 75 }; */
+extern AlnParam aln_param_rd2rd; /* = { 12,  2,  2, aln_sm_blosum62, 22, 50 }; */
+
+/* common nucleotide score matrix for 16 bases */
+extern int           aln_sm_nt[], aln_sm_bwa[];
+
+/* BLOSUM62 and BLOSUM45 */
+extern int           aln_sm_blosum62[], aln_sm_blosum45[];
+
+/* common read for 16 bases. note that read alignment is quite different from common nucleotide alignment */
+extern int           aln_sm_read[];
+
+/* human-mouse score matrix for 4 bases */
+extern int           aln_sm_hs[];
+
+#endif
diff --git a/test/data/LomanLabz_PC_Ecoli_K12_R7.3_2549_1_ch8_file30_strand.fast5 b/test/data/LomanLabz_PC_Ecoli_K12_R7.3_2549_1_ch8_file30_strand.fast5
new file mode 100755
index 0000000..8bd087a
Binary files /dev/null and b/test/data/LomanLabz_PC_Ecoli_K12_R7.3_2549_1_ch8_file30_strand.fast5 differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/nanopolish.git



More information about the debian-med-commit mailing list