[med-svn] [unanimity] 01/04: Imported Upstream version 2.0.4+dfsg

Afif Elghraoui afif at moszumanska.debian.org
Mon Dec 19 06:16:08 UTC 2016


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

afif pushed a commit to branch master
in repository unanimity.

commit 61ac353ccc8e1746a722adb43003e693fb1a6fc5
Author: Afif Elghraoui <afif at debian.org>
Date:   Wed Dec 14 21:46:08 2016 -0800

    Imported Upstream version 2.0.4+dfsg
---
 .gitmodules                                        |  20 +-
 CHANGELOG.md                                       |  12 +
 CMakeLists.txt                                     |   2 +-
 README.md                                          |   4 +-
 build.sh                                           | 103 +++
 cmake/uny-dependencies.cmake                       |  14 +-
 .../ZScoreMath.rst                                 | 267 ++++++
 .../img/consensus-modalities.pdf                   | Bin 0 -> 184757 bytes
 .../img/consensus-modalities.png                   | Bin 0 -> 270181 bytes
 .../img/hmms.pdf                                   | Bin 0 -> 194111 bytes
 .../img/hmms.png                                   | Bin 0 -> 373013 bytes
 .../index.rst                                      | 281 +++++-
 .../pacbioHMM.svg.png                              | Bin 0 -> 61715 bytes
 doc/INSTALL.md                                     |  13 +-
 include/pacbio/ccs/Consensus.h                     |  87 +-
 .../pacbio/ccs/ConsensusSettings.h                 |  64 +-
 include/pacbio/consensus/AbstractIntegrator.h      |  24 +-
 include/pacbio/consensus/AbstractMatrix.h          |  19 +-
 include/pacbio/consensus/Evaluator.h               |  68 +-
 .../pacbio/consensus/MatrixViewConvention.h        |  29 +-
 include/pacbio/consensus/MonoMolecularIntegrator.h |  15 +-
 .../pacbio/consensus/MultiMolecularIntegrator.h    |  11 +-
 include/pacbio/consensus/Mutation.h                |   8 +
 include/pacbio/consensus/Polish.h                  |  10 +
 include/pacbio/consensus/Template.h                |   2 +-
 .../pacbio/data/PlainOption.h                      |  48 +-
 include/pacbio/data/Read.h                         |   4 +
 include/pacbio/denovo/PoaGraph.h                   |   2 +
 include/pacbio/denovo/SparsePoa.h                  |   2 +
 scripts/task_pbccs_ccs                             | 218 -----
 src/AbstractIntegrator.cpp                         |   2 +-
 src/CMakeLists.txt                                 |   4 +-
 src/ConsensusSettings.cpp                          | 300 +++++++
 src/Evaluator.cpp                                  |  18 +
 src/EvaluatorImpl.cpp                              |  55 +-
 src/EvaluatorImpl.h                                |   5 +
 src/ModelSelection.cpp                             |   5 +-
 src/Read.cpp                                       |   6 +-
 src/Recursor.h                                     | 201 +++--
 src/Sequence.cpp                                   |   2 +-
 src/SparsePoa.cpp                                  |   7 +-
 src/Timer.cpp                                      |   2 +-
 src/Utility.cpp                                    |   5 +-
 src/align/AlignConfig.cpp                          |   2 +-
 src/main/ccs.cpp                                   | 236 ++---
 .../Polish.h => src/matrix/BasicDenseMatrix.cpp    |  50 +-
 src/{EvaluatorImpl.h => matrix/BasicDenseMatrix.h} |  94 +-
 src/matrix/ScaledMatrix.h                          |  14 +
 src/matrix/SparseMatrix.h                          |  23 +-
 src/poa/PoaGraph.cpp                               |   5 +
 src/poa/PoaGraphImpl.cpp                           |  17 +
 src/poa/PoaGraphImpl.h                             |   1 +
 swig/Matrix.i                                      |   2 +
 swig/Mutation.i                                    |  10 +
 swig/State.i                                       |   6 +-
 tests/CMakeLists.txt                               |   1 -
 tests/cram/100zmws.t                               |  25 +-
 tests/cram/100zmws_byStrand.t                      | 113 +--
 tests/cram/tiny.t                                  |   2 +-
 tests/python/test_tool_contract.py                 |   2 +-
 tests/unit/TestConsensus.cpp                       |  10 +-
 tests/unit/TestIntegrator.cpp                      |   9 +-
 tests/unit/TestLoadModels.cpp                      |   4 +-
 tests/unit/TestPolish.cpp                          |   2 +-
 third-party/cpp-optparse/OptionParser.cpp          | 959 ++++++++++-----------
 third-party/cpp-optparse/OptionParser.h            | 279 ++++--
 third-party/cpp-optparse/test.cpp                  | 277 +++---
 third-party/cram-0.7/cram/__init__.py              |   6 +
 third-party/cram-0.7/cram/__main__.py              |  10 +
 third-party/cram-0.7/cram/_cli.py                  | 134 +++
 third-party/cram-0.7/cram/_diff.py                 | 158 ++++
 third-party/cram-0.7/cram/_encoding.py             | 106 +++
 third-party/cram-0.7/cram/_main.py                 | 211 +++++
 third-party/cram-0.7/cram/_process.py              |  54 ++
 third-party/cram-0.7/cram/_run.py                  |  77 ++
 third-party/cram-0.7/cram/_test.py                 | 230 +++++
 third-party/cram-0.7/cram/_xunit.py                | 173 ++++
 third-party/cram-0.7/scripts/cram                  |   9 +
 tools/Darwin/clang-format                          | Bin 2490044 -> 0 bytes
 tools/Linux/clang-format                           | Bin 2754467 -> 0 bytes
 tools/check-formatting                             |  33 -
 tools/format-all                                   |   8 -
 tools/git-clang-format                             | 485 -----------
 tools/win32/clang-format.exe                       | Bin 1315328 -> 0 bytes
 84 files changed, 3716 insertions(+), 2060 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index fae5e39..461a8eb 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,12 +1,16 @@
-[submodule "third-party/htslib"]
-	path = third-party/htslib
-	url = https://github.com/PacificBiosciences/htslib
-	branch = pb
 [submodule "third-party/pbbam"]
     path = third-party/pbbam
-    url = https://github.com/PacificBiosciences/pbbam
+    url = ../pbbam.git
     branch = master
 [submodule "third-party/seqan"]
-	path = third-party/seqan
-	url = https://github.com/PacificBiosciences/seqan.git
-    branch = master
\ No newline at end of file
+    path = third-party/seqan
+    url = ../seqan.git
+    branch = master
+[submodule "third-party/pbcopper"]
+    path = third-party/pbcopper
+    url = ../pbcopper.git
+    branch = master
+[submodule "third-party/htslib"]
+	path = third-party/htslib
+	url = ../htslib.git
+	branch = pb
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 870750f..e172305 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
 # UNANIMITY - CHANGELOG
 
+## [2.0.4]
+
+### Added
+ - Add pbcopper's ToolContract, summary is no longer a second output file
+ - Differentiate between .xml and .bam output type
+ - Enforce .pbi generation
+
+## [2.0.3]
+
+### Added
+ - Switch from cpp-optparse to pbcopper, use pbcopper's CLI parsing
+
 ## [2.0.2]
 
 ### Added
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 96ed9fe..264241d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@
 ##############################################
 
 cmake_policy(SET CMP0048 NEW)
-project(UNANIMITY VERSION 2.0.2 LANGUAGES CXX C)
+project(UNANIMITY VERSION 2.0.4 LANGUAGES CXX C)
 cmake_minimum_required(VERSION 3.2)
 
 set(ROOT_PROJECT_NAME ${PROJECT_NAME} CACHE STRING "root project name")
diff --git a/README.md b/README.md
index 721bced..faf66de 100644
--- a/README.md
+++ b/README.md
@@ -41,4 +41,6 @@ This tool will be able to precisely call single-nucleotide variants from consens
 
 ## Help
 
-Issues? Bugs? Please create a github issue.
+Support is only provided for official and stable
+[SMRT Analysis builds](http://www.pacb.com/products-and-services/analytical-software/)
+provided by PacBio and not for source builds.
\ No newline at end of file
diff --git a/build.sh b/build.sh
new file mode 100644
index 0000000..2595f77
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+# Function definitions
+GetBBRepo () {
+    echo "## $1"
+    if [ ! -d $2/$1 ]; then
+        echo "### Clone"
+        ( cd $2 && git clone ssh://git@bitbucket.nanofluidics.com:7999/sat/$1)
+    else
+        echo "### Update"
+        ( cd $2/$1 && git pull)
+    fi
+}
+
+GetGHRepo () {
+    echo "## $1"
+    if [ ! -d $2/$1 ]; then
+        echo "### Clone"
+        ( cd $2 && git clone https://github.com/PacificBiosciences/$1)
+    else
+        echo "### Update"
+        ( cd $2/$1 && git pull)
+    fi
+}
+
+# Main script
+
+echo "#############################"
+echo "# LOAD MODULES"
+source /mnt/software/Modules/current/init/bash
+module load git gcc/5.3.0 python/2.7.9 cmake cram swig ccache virtualenv zlib/1.2.5 ninja boost
+
+echo "#############################"
+echo "# EXTERNAL DEPENDENCIES"
+echo "## Create external dependency directory"
+if [ ! -d _deps ] ; then mkdir _deps ; fi 
+echo "## Create reverse external dependency directory"
+if [ ! -d _rev_deps ] ; then mkdir _rev_deps ; fi 
+
+GetBBRepo GenomicConsensus _rev_deps
+GetBBRepo ConsensusCore _deps
+GetGHRepo pbcommand _deps
+GetGHRepo pbcore _deps
+GetGHRepo PacBioTestData _deps
+
+echo "## Fetch submodules"
+git submodule update --init --remote
+
+echo "#############################"
+echo "# PRE-BUILD HOOK"
+echo "## Check formatting"
+./tools/check-formatting --all
+
+echo "#############################"
+echo "# VIRTUALENV"
+echo "## Create missing virtualenv"
+if [ ! -d unyve ] ; then /mnt/software/v/virtualenv/13.0.1/virtualenv.py unyve ; fi
+
+echo "## Get into virtualenv"
+source unyve/bin/activate
+
+echo "## Install pip modules"
+pip install --upgrade pip
+pip install numpy cython h5py pysam cram nose jsonschema avro
+( cd _deps/pbcommand && pip install --no-deps . )
+( cd _deps/pbcore && pip install --no-deps . )
+
+echo "## Install PacBioTestData"
+( cd _deps/PacBioTestData && git lfs pull && make python )
+
+echo "#############################"
+echo "# BUILD"
+echo "## Create build directory "
+if [ ! -d build ] ; then mkdir build ; fi
+
+echo "## Build source"
+( cd build &&\
+  rm -rf * &&\
+  CMAKE_BUILD_TYPE=ReleaseWithAssert cmake -DZLIB_INCLUDE_DIR=/mnt/software/z/zlib/1.2.5/include -DZLIB_LIBRARY=/mnt/software/z/zlib/1.2.5/lib/libz.so -DCMAKE_EXE_LINKER_FLAGS="-static-libstdc++" -GNinja .. )
+( cd build && ninja htslibSrc )
+( cd build && ninja )
+
+echo "## pip install CC2"
+CMAKE_BUILD_TYPE=ReleaseWithAssert CMAKE_COMMAND=cmake ZLIB_INCLUDE_DIR=/mnt/software/z/zlib/1.2.5/include ZLIB_LIBRARY=/mnt/software/z/zlib/1.2.5/lib/libz.so VERBOSE=1 pip install --verbose --upgrade --no-deps .
+
+echo "## Install ConsensusCore"
+( cd _deps/ConsensusCore && python setup.py install --boost=$BOOST_ROOT )
+
+echo "## Install GC"
+( cd _rev_deps/GenomicConsensus && pip install --upgrade --no-deps --verbose . )
+
+echo "#############################"
+echo "# TEST"
+echo "## Unanimity tests"
+( cd build && ninja check )
+
+echo "## CC2 version test"
+python -c "import ConsensusCore2 ; print ConsensusCore2.__version__"
+
+echo "## Test CC2 via GC"
+( cd _rev_deps/GenomicConsensus && make check )
+
+deactivate
\ No newline at end of file
diff --git a/cmake/uny-dependencies.cmake b/cmake/uny-dependencies.cmake
index 6721d96..a7a7409 100644
--- a/cmake/uny-dependencies.cmake
+++ b/cmake/uny-dependencies.cmake
@@ -4,11 +4,6 @@
 # Get static libraries
 SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
 
-# pbcopper
-# if (NOT pbcopper)
-# 	add_subdirectory(${UNY_ThirdPartyDir}/pbcopper external/pbcopper/build)
-# endif()
-
 # Boost
 if(NOT Boost_INCLUDE_DIRS)
     find_package(Boost REQUIRED)
@@ -59,4 +54,13 @@ if (NOT PYTHON_SWIG)
     if (NOT SEQAN_INCLUDE_DIRS)
         set(SEQAN_INCLUDE_DIRS ${UNY_ThirdPartyDir}/seqan/include CACHE INTERNAL "" FORCE)
     endif()
+
+    # pbcopper
+    if (NOT pbcopper_INCLUDE_DIRS OR 
+        NOT pbcopper_LIBRARIES)
+        set(pbcopper_build_tests OFF CACHE INTERNAL "" FORCE)
+        set(pbcopper_build_docs OFF CACHE INTERNAL "" FORCE)
+        set(pbcopper_build_examples OFF CACHE INTERNAL "" FORCE)
+        add_subdirectory(${UNY_ThirdPartyDir}/pbcopper external/pbcopper/build)
+    endif()
 endif()
diff --git a/doc/ConsensusCore2-DesignAndImplementation/ZScoreMath.rst b/doc/ConsensusCore2-DesignAndImplementation/ZScoreMath.rst
new file mode 100644
index 0000000..14d13b9
--- /dev/null
+++ b/doc/ConsensusCore2-DesignAndImplementation/ZScoreMath.rst
@@ -0,0 +1,267 @@
+
+.. _zscore-math:
+
+"Z-Score": when is a read completely garbage?
+---------------------------------------------
+
+Garbage-In-Garbage-Out: It is not always useful to estimate fine-scale
+distinctions when looking at examples that have excessively high
+noise. Estimation is likely to be improved by simplying filtering away
+all examples that are irrecoverably "broken" as long as you still have
+sufficient sample size on which to make estimates.
+
+With "single-molecule-weirdness" such as long bursty inserts,
+individual reads (or subsections of them) might contain very high
+levels of noise. The current record for bursty insert is about 5.7kb
+of inserted sequence that has nothing to do with the reference
+template being sequenced. This can throw off alignments and consensus
+models (CCS2) that do not explicitly model these bursty insert
+behaviours.
+
+While it would be best to solve these behaviors upstream at the
+chemical/polymerase level, we must have defenses in place to at least
+identify when these undesirable behaviors present themselves so we
+might at least try to filter them away before they wreak havoc on
+estimates.
+
+
+Z-Score Motivation
+------------------
+
+The idea is to compute the expected mean and variance of the log
+likelihood (LL) of sequences output by a given HMM. Thus when
+presented with a sequence that has a certain log probability, we can
+reason how far removed it is to "normal" such that outliers can be
+filtered away.
+
+An HMM is a series of Markov steps: transition and emisson. Each step
+will additively change the LL. In a simple left-to-right profile HMM
+with length, :math:`T`, each match/delete will be visited once.  It is
+reasonable that sums of log probabilities might be close to normal
+under certain conditions.
+
+Here is the basic HMM structure with match, branch (same match base
+insert), stick (different match base insert), delete:
+
+.. figure:: pacbioHMM.svg.png
+
+   The basic HMM structure of a single match state with match, branch,
+   stick, and delete substates.
+
+For each "substate" (match, delete, branchIns, stickIns) we might
+compute that substate's average contribtuion to the the LL over the
+distribution of outputs induced by the HMM: E[LL] and Var[LL]. Then
+:math:`E[LL] = E[ \sum_{substates} LL] = \sum_{substates} E[LL]` by
+linearity of expectation. For IID substates this is :math:`T*E[LL]`. Var[LL]
+= :math:`Var[ \sum_{substates} LL] = \sum_{substates} Var[LL]` because each
+substate is independent so all covariances are 0. For IID substates
+this is :math:`T*Var[LL]`.
+
+For a motivational example, consider an "HMM" with a single
+multinomial :math:`p=(p_1,p_2,p_3,p_4)`. Here :math:`E[LL] =
+p*log(p).` :math:`E[LL^2] = p*log^2(p).` :math:`Var[LL]=
+E[LL^2]-E^2[LL]` :math:`= p*log^2(p) - (p*log(p))^2`. These are
+expected mean and variance of the LL by this simple multinomial. By
+stringing together multinomial emissions and transitions, we can
+estimate these quantities for an HMM.
+
+An HMM emits a string by entering a state, emitting an output
+according to an emission probability, making a random choice about
+what state to transition to next, transitioning to that new state, and
+repeating.
+
+Consider a single HMM state that has emission probabilities
+:math:`e_j`, transistion probabilities :math:`t_i`, and next state
+:math:`R_i` that outputs the rest of the output. The probability of
+this state is :math:`P=(e_j t_i \prod_k R_{ik})` where the product is
+the rest of the states multiplying their contributions. The log
+likelihood is :math:`LL=\log e_j + \log t_i + \sum_k \log
+R_{ik}`. Define :math:`\log e = \sum_j e_j \log(e_j)` and
+:math:`\log^2 e = \sum_j e_j \log^2(e_j)` be the expectations over the
+possible emission possibitilties.
+
+The expectation of log likelihood is :math:`EXP_{t_i} [(\log e + \log
+t_i + \sum_k \log R_{ik})]`. Note the expecation of the
+log-likelikhood of the rest of the derivation represented by the sum
+is :math:`EXP[ LL(R_i) ]` so we get :math:`EXP_{t_i} [(\log e + \log
+t_i + EXP[ LL(R_i)] ]`
+
+The expectation of log likelihood squared is :math:`EXP_{t_i}[ (\log
+e + \log t_i + \sum_k \log R_{ik})^2]`. Expand the square. The only
+complicating term is :math:`EXP_{t_i}[(\sum_k \log R_{ik})^2]` but we
+realize this to be the expectation of the log-likelihood squared of
+the rest of the derivation, :math:`EXP[ LL^2(R_i) ]`.
+
+Given this, we can write a dynamic program that computes the expected
+log-likelihood and expected log-likelihood squared of
+:math:`thisstate` derving a string of :math:`length` for every state
+and every length up to some maximum. With a large enough maximum
+length computed, contributions from possibly infinite self-loops in
+the insert states will be properly summed as the trailing terms become
+so small as to be negligible.
+
+The relvant python code that computes the expectation over the
+different choices of next rest state (nexts) with transition
+probabilities (nextp) and expected emissions (expEmLL, expEmLL2):
+
+.. code-block:: python
+
+   # cycle through choices
+   overallresult = [0.0, 0.0, 0.0]
+   for ch in range(len(this.nexts)):
+       transp = this.nextp[ch]
+       rhs = self.derive( this.nexts[ch], newlength)
+       A = self.mylog(transp) # log transition
+       A2 = A*A               # log transistion squared
+       B = expEmLL            # expected log emission likelihood
+       B2= expEmLL2           # expected log squared emission likelihood
+       C = rhs[1]             # EXP[LL] of next
+       C2= rhs[2]             # EXP[LL^2] of next
+       thisll =  transp*(A+B+C)
+       thisll2 = transp*( A2 + B2 + C2 + 2*A*B + 2*A*C +2*B*C)
+       thisprob = transp*rhs[0]
+       if thisprob>0.0:
+	   overallresult[0]=overallresult[0]+thisprob
+	   overallresult[1]=overallresult[1]+thisll
+	   overallresult[2]=overallresult[2]+thisll2
+   self.memo[self.key(thisstate,length)]=overallresult
+   return(overallresult)
+
+
+Z-Score for Filtering
+---------------------
+
+One method for identifying garbage reads is the "Z-Score" described
+here [PBEP_4.pdf]. This result sums out the infinite sums caused by
+the looping insert states analytically to get an analytic result
+rather than a dynamic programming one.
+
+Here is the result verbatim from PBEF_4.pdf:
+
++-------------------------+-----------------------------------------+
+| term                    | meaning                                 |
++=========================+=========================================+
+| :math:`p_m`             | match transistion probability           |
++-------------------------+-----------------------------------------+
+| :math:`p_d`             | deletion transistion probability        |
++-------------------------+-----------------------------------------+
+| :math:`p_s`             | stick transition probability            |
++-------------------------+-----------------------------------------+
+| :math:`p_b`             | branch transition probability           |
++-------------------------+-----------------------------------------+
+| :math:`l_m,l_d,l_s,l_b` | log of transition probabilities         |
++-------------------------+-----------------------------------------+
+| :math:`E[\rightarrow]`  | expected LL from match or deletion      |
++-------------------------+-----------------------------------------+
+| :math:`E[\downarrow]`   | expected LL from all insertions         | 
++-------------------------+-----------------------------------------+
+| :math:`E[NN]`           | mean LL from context                    |
++-------------------------+-----------------------------------------+
+| :math:`E[M]`            | mean logged match emission probability  |
++-------------------------+-----------------------------------------+
+| :math:`E[B]`            | mean logged branch emission probability |
++-------------------------+-----------------------------------------+
+| :math:`E[S]`            | mean logged stick emission probability  |
++-------------------------+-----------------------------------------+
+| :math:`E[I]`            | mean logged trans,emiss ins probability |
++-------------------------+-----------------------------------------+
+
+Derivation: 
+
+- :math:`E[NN] = E[\downarrow] + E[\rightarrow]`
+
+Break into simple match/delete and insert chains. Expected LL from
+context = expected LL from match/delete + expected LL from insertions
+
+- :math:`E[\rightarrow] = (l_m + E[M]) \frac{p_m}{p_m+p_d} + (l_d) \frac{p_d}{p_m+p_d}`
+
+Transistion weighted (LL from match trans+emis) and (LL from delete
+trans)
+
+- :math:`E[\downarrow]= E[I] \frac{p_s+p_b}{p_m+p_d}`
+
+Expected insertion LL weighted by expected length of insertion where
+:math:`(p_s+p_b)` is the probablity of looping in the insertion and
+:math:`(p_m+p_d)` is the probability of looping out.
+
+- :math:`E[I] = (l_b+E[B]+E[\rightarrow]) \frac{p_b}{p_b+p_s} + (l_s+E[S]+E[\rightarrow]) \frac{p_s}{p_b+p_s}`
+
+Transition weighted LL branch transition/emission and LL stick
+transition/emission within insertion. (Note this updates to three
+terms versus to two in the PBEP)
+
+For the second moment, we replace :math:`LL^2` for :math:`LL` in the
+above equations and are careful to carry the expectation of the
+likelihood or the expectation of the likelihood squared forward.
+
+
++----------------------------------------------------------------------------+
+| Classic Identities:                                                        |
++============================================================================+
+| :math:`E[X+Y]=E[X]+E[Y]`                                                   |
++----------------------------------------------------------------------------+
+| :math:`Var(X) = E[X^2]-E^2[X]`                                             |
++----------------------------------------------------------------------------+
+| :math:`Var(X+Y) = Var(X) + Var(Y) + 2Cov(X,Y)`                             |
++----------------------------------------------------------------------------+
+| :math:`E[a*X] = aE[X]`                                                     |
++----------------------------------------------------------------------------+
+| :math:`Var(a*X) = a^2Var(X)`                                               |
++----------------------------------------------------------------------------+
+| :math:`E[XY]=E[X]E[Y]` if independent                                      |
++----------------------------------------------------------------------------+
+| :math:`\sum_{k=0}^\infty (1-p)^k*p*k*ll = ll*\frac{1-p}{p}`                |
++----------------------------------------------------------------------------+
+| :math:`\sum_{k=0}^\infty (1-p)^k*p*(k*ll)^2 = ll^2 \frac{(p-2)(p-1)}{p^2}` |
++----------------------------------------------------------------------------+
+
+Z-Score Sanity Check
+--------------------
+
+As a sanity check we generated random deviates using a simple HMM with
+varying number of substates, computed means and variances, and
+compared to the computed expected values.
+
+The means and variances are close computed versus estimated.
+
++-------+----------+---------+----------+--------+
+|  size |     mean |     var | compmean | compvar|
++=======+==========+=========+==========+========+
+|    32 |-26.65075 |59.80562 |-27.13874 |68.15969|
++-------+----------+---------+----------+--------+
+|    60 |-50.99983 | 121.535 |-50.88515 |127.7994|
++-------+----------+---------+----------+--------+
+|   120 |-101.8052 |256.4235 |-101.7703 |255.5988|
++-------+----------+---------+----------+--------+
+|   240 |-202.6475 |473.0255 |-203.5406 |511.1977|
++-------+----------+---------+----------+--------+
+|   480 |-407.2655 |1073.169 |-407.0812 |1022.395|
++-------+----------+---------+----------+--------+
+
+Real-world performance on RSII data shows that the Z-score does have
+good performance in filtering garbage reads. Because we are able to
+adjust the Z-Score threshold, good performance is obtained.
+
+Z-Score Shortcomings
+--------------------
+
+The bursty errors occur in localized regions. For a long read, these
+localized bursts might not be detected by the Z-score metric.  Overall
+the number of errors, if they were randomly distributed across the
+read, might be within what might be expected normally. The fact that
+they are all localized is what makes it abnormal.
+
+An HMM can identify these localized bursts. The Viterbi path assigns
+each match/delete state to a position in the read
+:math:`(ref_i->read_j \mbox{ with } prob_i)`. Because the HMM is a
+regular language, we know if :math:`ref_i` derives the string starting
+at :math:`read_j` with :math:`prob_i` and :math:`ref_{i+1}` derives
+with :math:`prob_{i+1}` then :math:`ref_i` derives it's portion with
+probability (:math:`prob_i / prob_{i+1}`) (or differences in log
+probability if using log probability). This is the part of the HMM
+that accounts for a single reference base. We can use the same Z-Score
+ideas to determine outliers. If the substate HMM derives 4 or less
+bases 99.999% of the time, then if in the Viterbi path a derivation of
+200 bases is observed, then we can conclude this is an outlier bursty
+insert between this and then next reference base. (Similar ideas exist
+for forward / backward / posterior.)
diff --git a/doc/ConsensusCore2-DesignAndImplementation/img/consensus-modalities.pdf b/doc/ConsensusCore2-DesignAndImplementation/img/consensus-modalities.pdf
new file mode 100644
index 0000000..8834069
Binary files /dev/null and b/doc/ConsensusCore2-DesignAndImplementation/img/consensus-modalities.pdf differ
diff --git a/doc/ConsensusCore2-DesignAndImplementation/img/consensus-modalities.png b/doc/ConsensusCore2-DesignAndImplementation/img/consensus-modalities.png
new file mode 100644
index 0000000..262cb2f
Binary files /dev/null and b/doc/ConsensusCore2-DesignAndImplementation/img/consensus-modalities.png differ
diff --git a/doc/ConsensusCore2-DesignAndImplementation/img/hmms.pdf b/doc/ConsensusCore2-DesignAndImplementation/img/hmms.pdf
new file mode 100644
index 0000000..f4c2b6f
Binary files /dev/null and b/doc/ConsensusCore2-DesignAndImplementation/img/hmms.pdf differ
diff --git a/doc/ConsensusCore2-DesignAndImplementation/img/hmms.png b/doc/ConsensusCore2-DesignAndImplementation/img/hmms.png
new file mode 100644
index 0000000..205f72f
Binary files /dev/null and b/doc/ConsensusCore2-DesignAndImplementation/img/hmms.png differ
diff --git a/doc/ConsensusCore2-DesignAndImplementation/index.rst b/doc/ConsensusCore2-DesignAndImplementation/index.rst
index 7d7dc44..241572c 100644
--- a/doc/ConsensusCore2-DesignAndImplementation/index.rst
+++ b/doc/ConsensusCore2-DesignAndImplementation/index.rst
@@ -2,8 +2,9 @@
 ``ConsensusCore2``: design and implementation
 ===========================================
 
-Authors: David Alexander, Nigel Delaney, Lance Hepler, Armin Töpfer
-Last modified: July 27, 2016
+
+| **Authors:** David Alexander, Michael Brown, Nigel Delaney, Lance Hepler, Armin Töpfer
+| **Last modified:** August 10, 2016
 
 
 Motivation
@@ -32,9 +33,9 @@ framework, asking the question "what is the probability that an
 underlying *template* sequence T generated an observed read sequence
 R?", and then using the model :math:`\Pr(R \mid T)` to answer the
 multi-read consensus problem via maximum likelihood---the consensus
-sequence then mathematically defined as :math:`\arg\max_T \Pr(T \mid
-\mathbf{R})`, where :math:`\mathbf{R}` represents the vector of
-multiple reads.
+sequence then mathematically defined as :math:`\arg\max_T
+\Pr(\mathbf{R} \mid T)`, where :math:`\mathbf{R}` represents the
+vector of multiple reads.
 
 Such a likelihood model is implemented using standard techniques from
 the hidden Markov model (HMM) literature.  The likelihood model is
@@ -42,8 +43,8 @@ made tractable by approximating full dynamic programming using
 banding, and, critically, the maximum likelihood search is made
 tractable using a greedy search and a core routine using a
 forward-backward identity that enables fast (:math:`O(1)`)
-recalculation of the likelihood when the template is mutated pointwise
-from :math:`T` to :math:`T+\mu`.
+recalculation of the likelihood when the template is mutated pointwise,
+:math:`T \to T+\mu`.
 
 The consensus problem has multiple guises, as we have mentioned.  In
 the *circular consensus sequence* application (*CCS*), multiple
@@ -60,7 +61,11 @@ the reference genome.  In the context of a "draft" assembly, the
 application is referred to as "polishing" and the goal is simply to
 produce the most accurate sequence of the genome as possible.
 
-[add picture here]
+.. figure:: img/consensus-modalities.*
+   :width: 100%
+
+   *Consensus can applied in a single-molecule or multi-molecule
+   context, for different applications.*
 
 Additionally, the mathematical model of :math:`Pr(T \mid \mathbf{R})`
 has immediate applications even beyond the single-template consensus
@@ -73,70 +78,292 @@ estimation, as well as haplotype phasing.  The latter problem is
 History
 -------
 
-An initial consensus model (names `Quiver` in 2012) was originated in
+An initial consensus model (named `Quiver` in 2012) was originated in
 the original CCS implementation (ca. 2010) and proved capable of
 generating consensus sequences with accuracy near Q25 provided enough
 evidence---enough "passes" of the insert DNA.  The initial codebase
 was in C# with some routines in C/C++.  In 2012-2013, the core of the
 Quiver consensus algorithm was exported to a C++ library,
-`ConsensusCore`, which provided SWIG bindings to higher-level host
+``ConsensusCore``, which provided SWIG bindings to higher-level host
 languages (Python and C#, in chief), enabling use from other
 applications .  The C# algorithm implementation was replaced by calls
-to the `ConsensusCore` library; simultaneously, a Python application
+to the ``ConsensusCore`` library; simultaneously, a Python application
 (``GenomicConsenus``) was developed for applications in genome
 assembly polishing, yielding very successful results: over Q50 (and in
 some cases, over Q60) accuracy achieved on bacterial genome
 assemblies.
 
-The arrival of the ``GenomicConsensus" application coincided roughly
+The arrival of the ``GenomicConsensus`` application coincided roughly
 with the initial development of HGAP (the Hierarchical Genome Assembly
 Program), thus offering fast end-to-end genome assembly with
 exceptionally high quality results, establishing PacBio as a player in
 the fields of "sequence finishing" and microbiology in 2013.
-Throughput improvements would
+Throughput improvements over time then made PacBio assembly appealing
+for larger genomes, including fungi, plants, and animals.
 
 Analyses of CCS results using the Quiver model showed evidence that
 CCS was far from a solved problem.  First of all, the accuracy of CCS
 results were found to fall short of the accuracy from multi-molecule
 consensus sequences with comparable "coverage" in multiple controlled
 experiments.  Perhaps more troubling, it was observed that consensus
-accuracy "saturated", failing to increase beyond a certain point when
+accuracy "saturated", failing to increase beyond a certain number of
+passes.
+
+Experiments suggested that part of this problem was due to a failure
+to account for ZMW-specific variables in the Quiver model; "genomic"
+consensus was not subject to this problem because multiple molecules
+would counterbalance each other.  Another defect of the Quiver model
+was that it was trained in a "discriminative" fashion, which we
+believe biased the model in a manner that prevented convergence to
+perfect accuracy as the number of CCS passes increased.
+
+In addition to the deficiencies in accuracy, the Quiver model also was
+burdensome from the a software engineering perspective.  It was
+unusable as an "inference" tool---there was no way to use it to
+estimate underlying physical sequencing HMM parameters (merge rates,
+for example); a completely separate codebase and tool (EDNA) was used
+for this purpose---imposing a maintenance burden.  Furthermore, the
+nonstandard derivative-free optimization method that was used to train
+Quiver was slow and unreliable, making it unsuitable for use in an
+automated training pipeline.
+
+These observations motivated the development of a new model, based on
+standard likelihood theory and standard training techniques, and
+suitable as an inference tool to replace EDNA.  This was the "UniteEM"
+effort led by Nigel Delaney, resulting in the "Arrow" model.
+
 
 
 The Arrow model
 ---------------
 
-Differences from Quiver...
-
+The Quiver model was effectively a "conditional random field" over
+multivariate observations that encompassed the base calls and multiple
+additional "QV" tracks emitted by the basecaller.  However it was not
+trained in a standard manner; rather it was trained using an
+unreliable and slow derivative-free optimizaton and with an objective
+function that reflected a non-standard likelihood function more akin
+to a classification accuracy.  Furthermore, its ability to adapt to
+the
+
+The Arrow model is a complete reboot.  It is a left-right HMM model,
+very similar to the standard textbook left-right sequence "profile"
+HMM.  Arrow differs from those models in a few key ways.  First, while
+the standard profile HMM just models sequence alignment moves (Match,
+Insert, Delete), Arrow models the enzymatic and photophysical events
+(Sticks, Branches, (Mis)incorporations, Merges, and "dark" pulses)
+underlying such moves in SMRT sequencing.  Secondly, emission and
+transition parameters are not estimated independently for every state;
+rather the states are "tied" by the dinucleotide template context.
+Third, the transition parameters are "tied", depending only on the
+template position and not on the state the model is in; this
+simplification enables computing the model using a single matrix
+matrix instead of one per state type.
+
+.. figure:: img/hmms.*
+   :width: 100%
+
+   *The standard profile HMM (A) uses states to model alignment moves
+   (Match, Insert, Delete), while the Arrow HMM (B) models the
+   underlying physical events (which themselves give rise to
+   "alignment" moves).  Otherwise, the models are quite similar.*
+
+While the Arrow model can be used to estimate transition and emission
+parameters freely for each read (the "EDNA" use case), in the more
+common case emission parameters are only estimated per dinucleotide
+context, combining all reads, while the transition probability
+parameters are expected to follow a regression model on a few scalar
+read covariates (at present, the only covariate used in this manner is
+the read's SNR).
+
+The Arrow model is trained using the standard Baum-Welch EM algorithm
+procedure; the only extension here is that when the SNR is used as a
+covariate, the M step requires maximum likelihood estimation of
+a multinomial logistic model.
+
+.. todo:: probably wise to include some actual math here!
+
+
+
+Algorithm overview
+------------------
 
 
 Implementation
 --------------
 
 Draft consensus by partial-order alignment
-``````````````````````````````````````````
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
 
 The essence: calculating, and re-calculating, likelihood
-````````````````````````````````````````````````````````
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Indexing conventions and matrix display convention (tpl on top, read
+  on side)
+
+
+
+
+Practical and numerical aspects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Scaling vs log-domain math
+``````````````````````````
+
+The naive approach to computing likelihoods in an HMM inevitably runs
+afoul of numerical underflow, as many probabilities are multiplied
+together.  The standard practical solutions are to compute all matrix
+entries (probabilities) in the log-domain, or to scale each row or
+column
+
+The choice of scaling or log-domain math has implications for the math
+required in the different calculations we need to perform.  For the
+Sum-Product recursion...
+
+
+Banding
+```````
+
+Computing the entire dynamic-programming matrices is prohibitively
+expensive in memory and CPU time, given the number and size of
+matrices we need to compute.  Rather, we use a *banded dynamic
+programming* approach where we only compute and retain a high-scoring
+band in each matrix column; these bands should capture all of the
+plausible alignment paths describing how T induces R.
+
+Banding is presently performed "on the fly", as the matrix (alpha or
+beta) itself is filled.  The column is filled, starting from the first
+filled row of the previous column, and we continue to fill it until it
+falls below the maximum score in the column by more than
+``scoreDiff``.  Finally, we scan back to identify the first row in the
+column within ``scoreDiff`` of the max.  This interval is then
+recorded as the nominally "filled"  band of the column.
+
+An important requirement of the banding is that the bands of the
+forward (alpha) and backward (beta) matrices must be concordant,
+meaning that they overlap sufficiently such that the forward-backward
+identity can still hold despite the bands.  Another way of looking at
+this is that *all* high probability paths in alpha must be calculated
+in beta, and vice versa, so that the "link" operation can find a path.
+
+In practice, we check for correct "mating" of the alpha and beta
+matrices by first
+
+check whether the
+
+
+In the future we hope to adopt a *pre-banding* approach where we
+identify the likely high-scoring bands by a preliminary SDP step.
+Ideally, this will eliminate the need for flip-flopping, simplify the
+inner loop of the recursions, and
 
-Numerical aspects
-`````````````````
 
-Scaling vs log-domain math.
+Counterweights
+``````````````
 
-The counterweights.
+It is interesting to consider the score of the path that proceeds
+through the alpha matrix along the top row, then finally moving down
+to the bottom-right entry when it reaches the last column.  This can
+be thought of as an "alignment" that "deletes" all the template bases,
+then "inserts" the read bases in at the end.  This is a poor alignment
+by any estimation, but it defeats our "on the fly" banding procedure.
 
+.. todo:: picture here, showing the path and its two segments
 
-Setup for calling consensus: the `Integrator` classes
-`````````````````````````````````````````````````````
+In particular, note that the segment 1 describes a path through the
+Markov model that produces no emissions.  The likelihood for this
+segment then has many fewer multiplicative probability factors than
+segments that move downward.  Unless the transition probability into
+or from the delete state is sufficiently low---which is in no way
+guaranteed by the HMM or its training---then, these paths to the right
+will seem locally favorable---the penalty is not felt until the
+emissions must be made later.  The greedy "on the fly" banding
+procedure thus may
+
+This problem presents itself as excessively wide bands, spanning from
+near the diagonal to the path 1->2.
+
+Presently, we avoid this problem by artificially penalizing deletions
+(or, alternately, by encouraging emissions) using what we term a
+*counterweight*: a constant positive value added to the score of each
+matrix cell for each emission, used for purposes of band calculation
+only.
+
+If we adopt pre-banding, we can eliminate the need for using
+counterweights.
+
+
+Batching of mutations
+`````````````````````
+
+
+Coding conventions
+~~~~~~~~~~~~~~~~~~
+
+Setup for calling consensus: the ``Integrator`` classes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The basic setup for computing a consensus sequence from reads (and a
+draft consensus) is to build an ``Integrator`` object.  There are two
+``Integrator`` classes: the ``MultiMolecularIntegrator`` and the
+``MonoMolecularIntegrator``, which are optimized, respectively, for
+the multimolecule and CCS use cases.  An abstract base class
+``AbstractIntegrator`` factors out some common functionality and
+simplifies life for client code.  After creating an integrator for a
+given model configuration and template DNA sequence hypothesis, client
+code then adds ``MappedRead`` objects to the integrator;
+``MappedRead`` objects represent the read data (including covariates)
+and also indicate the start/end positions where it is anchored on the
+template sequence.  Once this is done, client code then calls the
+``Polish`` function, which performs the iterative greedy search
+procedure, returning a ``PolishResult`` object recording iteration
+count and other metrics, while as a side effect updating the
+``Integrator`` object to point at the maximum likelihood consensus.
+
+``Integrator`` objects support polishing by exposing methods that
+enable testing, and commiting, mutations to the underlying template.
+This requires a good deal of bookkeeping internally, as each mutation
+applied requires potential updates to the read-to-template anchor
+mappings.
+
+
+The workhorse: the Recursor class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The template classes
+~~~~~~~~~~~~~~~~~~~~
 
 
 Model lookup
-````````````
+~~~~~~~~~~~~
 
 
 Model parameter lookup
-``````````````````````
+~~~~~~~~~~~~~~~~~~~~~~
 
 Training
-````````
+~~~~~~~~
+
+
+
+
+Identifying (and removing) abberant reads: the "ZScore" concept
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Basic explanation goes here.
+
+For the mathematical details of how the variance and expectation are
+calculated, see :ref:`zscore-math`.
+
+
+
+Appendices: the gory details
+----------------------------
+
+.. toctree::
+   :maxdepth: 1
+
+   ZScoreMath
+   CounterWeightMath
diff --git a/doc/ConsensusCore2-DesignAndImplementation/pacbioHMM.svg.png b/doc/ConsensusCore2-DesignAndImplementation/pacbioHMM.svg.png
new file mode 100644
index 0000000..998015f
Binary files /dev/null and b/doc/ConsensusCore2-DesignAndImplementation/pacbioHMM.svg.png differ
diff --git a/doc/INSTALL.md b/doc/INSTALL.md
index 443c1e7..b7ad820 100644
--- a/doc/INSTALL.md
+++ b/doc/INSTALL.md
@@ -17,7 +17,7 @@ automates dependency fetching/resolution:
 
 ### All tools: manually
 
-Building from scratch requires system-wide installed boost (>=1.5.8), 
+Building from scratch requires system-wide installed boost (>=1.58.0), 
 cmake (3.2), and a c++11 compiler (>=gcc-5.3.0, clang):
 
   ```sh
@@ -36,12 +36,19 @@ cmake (3.2), and a c++11 compiler (>=gcc-5.3.0, clang):
 Invoke the different `make` targets, currently available
 
   ```sh
-  $ make pbccs
+  git clone https://github.com/PacificBiosciences/unanimity && \
+  cd unanimity                                              && \
+  git submodule update --init --remote                      && \
+  mkdir build                                               && \
+  cd build                                                  && \
+  cmake ..                                                  && \
+  make ccs                                                  && \
+  ./ccs
   ```
 
 ### Install ConsensusCore2 python library for GenomicConsensus
 
-Building from scratch requires system-wide installed boost (>=1.5.8), 
+Building from scratch requires system-wide installed boost (>=1.58.0), 
 cmake (3.2), python 2.x, and a c++11 compiler (>=gcc-5.3.0, clang):
 
   ```sh
diff --git a/include/pacbio/ccs/Consensus.h b/include/pacbio/ccs/Consensus.h
index d2a5110..5cf998c 100644
--- a/include/pacbio/ccs/Consensus.h
+++ b/include/pacbio/ccs/Consensus.h
@@ -49,8 +49,7 @@
 
 #include <boost/optional.hpp>
 
-#include <OptionParser.h>
-
+#include <pacbio/ccs/ConsensusSettings.h>
 #include <pacbio/consensus/MonoMolecularIntegrator.h>
 #include <pacbio/consensus/Polish.h>
 #include <pacbio/data/State.h>
@@ -86,90 +85,6 @@ using SparsePoa = PacBio::Poa::SparsePoa;
 using AlignConfig = PacBio::Align::AlignConfig;
 using AlignMode = PacBio::Align::AlignMode;
 
-namespace OptionNames {
-// constexpr auto MaxPoaCoverage       = "maxPoaCoverage";
-constexpr auto MaxLength = "maxLength";
-constexpr auto MinLength = "minLength";
-constexpr auto MinPasses = "minPasses";
-constexpr auto MinPredictedAccuracy = "minPredictedAccuracy";
-constexpr auto MinZScore = "minZScore";
-constexpr auto MaxDropFraction = "maxDropFraction";
-constexpr auto NoPolish = "noPolish";
-constexpr auto MinReadScore = "minReadScore";
-constexpr auto MinSnr = "minSnr";
-constexpr auto ByStrand = "byStrand";
-}  // namespace OptionNames
-
-struct ConsensusSettings
-{
-    size_t MaxPoaCoverage;
-    size_t MaxLength;
-    size_t MinLength;
-    size_t MinPasses;
-    double MinPredictedAccuracy;
-    double MinZScore;
-    double MaxDropFraction;
-    bool ByStrand;
-    bool NoPolish;
-    double MinReadScore;
-    double MinSNR;
-
-    ConsensusSettings(const optparse::Values& options);
-
-    static void AddOptions(optparse::OptionParser* const parser)
-    {
-        const std::string em = "--";
-        // TODO(lhepler) implement alignment to POA
-        // parser->add_option(em +
-        // OptionNames::MaxPoaCoverage).type("int").set_default(1024).help("Maximum number of
-        // subreads to use when building POA. Default = %default");
-        parser->add_option(em + OptionNames::MaxLength)
-            .type("int")
-            .set_default(7000)
-            .help("Maximum length of subreads to use for generating CCS. Default = %default");
-        parser->add_option(em + OptionNames::MinLength)
-            .type("int")
-            .set_default(10)
-            .help("Minimum length of subreads to use for generating CCS. Default = %default");
-        parser->add_option(em + OptionNames::MinPasses)
-            .type("int")
-            .set_default(3)
-            .help("Minimum number of subreads required to generate CCS. Default = %default");
-        parser->add_option(em + OptionNames::MinPredictedAccuracy)
-            .type("float")
-            .set_default(0.90)
-            .help("Minimum predicted accuracy in [0, 1]. Default = %default");
-        parser->add_option(em + OptionNames::MinZScore)
-            .type("float")
-            .set_default(-3.5)
-            .help("Minimum z-score to use a subread. NaN disables this filter. Default = %default");
-        parser->add_option(em + OptionNames::MaxDropFraction)
-            .type("float")
-            .set_default(0.34)
-            .help(
-                "Maximum fraction of subreads that can be dropped before giving up. Default = "
-                "%default");
-        parser->add_option(em + OptionNames::MinSnr)
-            .type("float")
-            .set_default(
-                3.75)  // See https://github.com/PacificBiosciences/pbccs/issues/86 for a more
-                       // detailed discussion of this default.
-            .help("Minimum SNR of input subreads. Default = %default");
-        parser->add_option(em + OptionNames::MinReadScore)
-            .type("float")
-            .set_default(0.75)
-            .help("Minimum read score of input subreads. Default = %default");
-        parser->add_option(em + OptionNames::ByStrand)
-            .action("store_true")
-            .help("Generate a consensus for each strand. Default = false");
-        parser->add_option(em + OptionNames::NoPolish)
-            .action("store_true")
-            .help(
-                "Only output the initial template derived from the POA (faster, less accurate). "
-                "Default = false");
-    }
-};
-
 template <typename TId>
 struct ReadType
 {
diff --git a/src/Consensus.cpp b/include/pacbio/ccs/ConsensusSettings.h
similarity index 55%
copy from src/Consensus.cpp
copy to include/pacbio/ccs/ConsensusSettings.h
index a74e0f8..3e298c4 100644
--- a/src/Consensus.cpp
+++ b/include/pacbio/ccs/ConsensusSettings.h
@@ -33,29 +33,57 @@
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
-// Author: Lance Hepler
+// Author: Lance Hepler, Armin Töpfer
+#pragma once
 
-#include <limits>
+#include <algorithm>
+#include <string>
+#include <thread>
 
-#include <pacbio/ccs/Consensus.h>
+#include <pbcopper/cli/CLI.h>
+
+#include <pacbio/data/PlainOption.h>
 
 namespace PacBio {
 namespace CCS {
 
-ConsensusSettings::ConsensusSettings(const optparse::Values& options)
-    : MaxPoaCoverage{std::numeric_limits<size_t>::max()}
-    , MaxLength{options.get(OptionNames::MaxLength)}
-    , MinLength{options.get(OptionNames::MinLength)}
-    , MinPasses{options.get(OptionNames::MinPasses)}
-    , MinPredictedAccuracy{options.get(OptionNames::MinPredictedAccuracy)}
-    , MinZScore{options.get(OptionNames::MinZScore)}
-    , MaxDropFraction{options.get(OptionNames::MaxDropFraction)}
-    , ByStrand{options.get(OptionNames::ByStrand)}
-    , NoPolish{options.get(OptionNames::NoPolish)}
-    , MinReadScore{static_cast<float>(options.get(OptionNames::MinReadScore))}
-    , MinSNR{static_cast<double>(options.get(OptionNames::MinSnr))}
+/// This class contains all command-line provided arguments and additional
+/// constants. Provides a static function to create the CLI pbcopper Interface
+/// and the constructor resovlves the CLI::Results automatically.
+struct ConsensusSettings
 {
-}
+    bool ByStrand;
+    const size_t ChunkSize = 1;
+    bool ForceOutput;
+    std::string LogFile;
+    std::string LogLevel;
+    double MaxDropFraction;
+    size_t MaxLength;
+    const size_t MaxPoaCoverage = std::numeric_limits<size_t>::max();
+    size_t MinLength;
+    size_t MinPasses;
+    double MinPredictedAccuracy;
+    double MinReadScore;
+    double MinSNR;
+    double MinZScore;
+    std::string ModelPath;
+    std::string ModelSpec;
+    bool NoPolish;
+    size_t NThreads;
+    bool PbIndex;
+    std::string ReportFile;
+    bool RichQVs;
+    std::string WlSpec;
+
+    /// Parses the provided CLI::Results and retrieves a defined set of options.
+    ConsensusSettings(const PacBio::CLI::Results& options);
 
-}  // namespace CCS
-}  // namespace PacBio
+    size_t ThreadCount(int n);
+
+    /// Given the description of the tool and its version, create all
+    /// necessary CLI::Options for the ccs executable.
+    static PacBio::CLI::Interface CreateCLI(const std::string& description,
+                                            const std::string& version);
+};
+}
+}  // ::PacBio::CCS
\ No newline at end of file
diff --git a/include/pacbio/consensus/AbstractIntegrator.h b/include/pacbio/consensus/AbstractIntegrator.h
index 6ed3fd8..536ff33 100644
--- a/include/pacbio/consensus/AbstractIntegrator.h
+++ b/include/pacbio/consensus/AbstractIntegrator.h
@@ -49,9 +49,10 @@
 
 namespace PacBio {
 namespace Consensus {
-
+// Forward decl
 class AbstractMatrix;
 
+/// Contains user-provided filtering information for the Evaluators.
 struct IntegratorConfig
 {
     double MinZScore;
@@ -60,6 +61,8 @@ struct IntegratorConfig
     IntegratorConfig(double minZScore = -3.5, double scoreDiff = 12.5);
 };
 
+/// At its core, this class holds a vector of Evaluators and provides helper
+/// functions to execute certain actions on each Evaluator.
 class AbstractIntegrator
 {
 public:
@@ -83,21 +86,30 @@ public:
 
     virtual PacBio::Data::State AddRead(const PacBio::Data::MappedRead& read) = 0;
 
-    // For debugging purposes
-    // (Note that these include results include all evaluators, even the inactive ones)
+    /// Given a Mutation of interest, returns a vector of LLs,
+    /// one LL per Evaluator, even for inactive ones.
     std::vector<double> LLs(const Mutation& mut);
+    /// Using the current template, returns a vector of LLs,
+    /// one LL per Evaluator, even for inactive ones.
     std::vector<double> LLs() const;
+    /// For each Evaluator, returns the read name.
     std::vector<std::string> ReadNames() const;
-
+    /// Returns the number of flip flop events for each Evaluator.
     std::vector<int> NumFlipFlops() const;
+    /// Returns the maximal number of flip flop events of all Evaluators.
     int MaxNumFlipFlops() const;
-
+    /// Computes the ratio of populated cells in the alpha matrix for each
+    /// Evaluator and returns the maximal ratio.
     float MaxAlphaPopulated() const;
+    /// Computes the ratio of populated cells in the beta matrix for each
+    /// Evaluator and returns the maximal ratio.
     float MaxBetaPopulated() const;
-
+    /// Returns the state of each Evaluator.
     std::vector<PacBio::Data::State> States() const;
+    /// Returns the strand of each Evaluator.
     std::vector<PacBio::Data::StrandType> StrandTypes() const;
 
+    /// Returns read-only access to Evaluator idx.
     const Evaluator& GetEvaluator(size_t idx) const;
 
 public:
diff --git a/include/pacbio/consensus/AbstractMatrix.h b/include/pacbio/consensus/AbstractMatrix.h
index dc67585..cc2ac51 100644
--- a/include/pacbio/consensus/AbstractMatrix.h
+++ b/include/pacbio/consensus/AbstractMatrix.h
@@ -38,19 +38,18 @@
 namespace PacBio {
 namespace Consensus {
 
-// AbstractMatrix is a superclass of the matrix types used in the arrow
-// banded dynamic programming.  It exposes a minimal interface only
-// intended for diagnostic purposes (looking at a matrix from Python,
-// seeing how well the banding is working, ...).  No matrix implementation
-// details are exposed---one can think of this as effectively an opaque
-// data type.
+/// AbstractMatrix is a superclass of the matrix types used in the arrow
+/// banded dynamic programming.  It exposes a minimal interface only
+/// intended for diagnostic purposes (looking at a matrix from Python,
+/// seeing how well the banding is working, ...).  No matrix implementation
+/// details are exposed---one can think of this as effectively an opaque
+/// data type.
 class AbstractMatrix
 {
 public:
-    // Method SWIG clients can use to get a native matrix (e.g. Numpy)
-    // mat must be filled as a ROW major matrix, and the understanding
-    // is that the entries represent natural-logs of probabilities.
-    // N.B.: Needs int, not size_t dimensions, for SWIG/numpy
+    /// Method SWIG clients can use to get a native matrix (e.g. Numpy)
+    /// mat must be filled as a ROW major matrix.
+    /// N.B.: Needs int, not size_t dimensions, for SWIG/numpy
     virtual void ToHostMatrix(double** mat, int* rows, int* cols) const = 0;
 
 public:
diff --git a/include/pacbio/consensus/Evaluator.h b/include/pacbio/consensus/Evaluator.h
index 71e6125..2804343 100644
--- a/include/pacbio/consensus/Evaluator.h
+++ b/include/pacbio/consensus/Evaluator.h
@@ -39,6 +39,7 @@
 #include <utility>
 #include <vector>
 
+#include <pacbio/consensus/MatrixViewConvention.h>
 #include <pacbio/consensus/Template.h>
 #include <pacbio/data/Read.h>
 #include <pacbio/data/State.h>
@@ -50,56 +51,117 @@ namespace Consensus {
 class EvaluatorImpl;
 class AbstractMatrix;
 
+/// Each Evaluator holds one reference to a MappedRead and its Template.
+/// An Evaluator can compute the LL that its MappedRead stems from the Template.
+/// Core functionality: compute the LL given a temporary mutated Template
+/// and apply mutations to the Template.
+///
+/// A PIMPL wrapper around the implementation of the Evaluator allows to
+/// deactivate the instance, either implicitly by an error or
+/// expliciltly by releasing the implementation pointer.
+///
+/// If a function gets called on an deactivated Evaluator, it returns -INF!
 class Evaluator
 {
 public:
     Evaluator() = delete;
+
+    /// Initializes an empty instance as a placeholder.
     explicit Evaluator(PacBio::Data::State);
+
+    /// Default constructor.
+    ///
+    /// \param tpl        The respective template.
+    /// \param mr         The MappedRead
+    /// \param minZScore  The minimum z-score
+    /// \param scoreDiff  The score difference
     Evaluator(std::unique_ptr<AbstractTemplate>&& tpl, const PacBio::Data::MappedRead& mr,
               double minZScore, double scoreDiff);
 
-    // copying is verboten
+    /// Copying is verboten
     Evaluator(const Evaluator&) = delete;
     Evaluator& operator=(const Evaluator&) = delete;
 
-    // move constructor
+    /// Move constructor
     Evaluator(Evaluator&&);
-    // move assign operator
+    /// Move assign operator
     Evaluator& operator=(Evaluator&&);
 
+    /// Destructor
     ~Evaluator();
 
     size_t Length() const;  // TODO: is this used anywhere?  If not, delete it.
+
+    /// Returns the strand if Evaluator.
+    /// Return StrandType::UNMAPPED if deactivated.
     PacBio::Data::StrandType Strand() const;
 
+    /// Returns if the Evaluator is valid.
     operator bool() const { return IsValid(); }
+
+    /// Returns if the Evaluator is still valid and active.
     bool IsValid() const { return curState_ == PacBio::Data::State::VALID; }
 
+    /// TODO: Attention, not implemented, thus can be removed.
     operator std::string() const;
+
+    /// Returns the read name.
+    /// Returns *Inactive evaluator* if deactivated.
     std::string ReadName() const;
 
+    /// Returns the LL of the Read, given the mutated template.
+    /// Returns -INF if deactivated.
     double LL(const Mutation& mut);
+
+    /// Returns the LL of the Read, given the current template.
+    /// Returns -INF if deactivated.
     double LL() const;
 
+    /// Returns the mean and variance over all site-wise normal parameters.
+    /// Returns {-INF, -INF} if deactivated.
     std::pair<double, double> NormalParameters() const;
 
+    /// Returns the ZScore of this Evaluator's LL, given all Evaluators of
+    /// the template.
+    /// Returns -INF if deactivated.
     double ZScore() const;
 
+    /// Applies a single mutation to the template.
+    /// Returns if mutation has been applied
+    /// and deactivates the Evaluator if not.
     bool ApplyMutation(const Mutation& mut);
+
+    /// Applies a vector of mutations to the template.
+    /// Returns if all mutations have been applied
+    /// and deactivates the Evaluator if not.
     bool ApplyMutations(std::vector<Mutation>* muts);
 
+    /// Returns the current state of the Evaluator.
     PacBio::Data::State Status() const { return curState_; }
+
+    /// Returns number of flip flop events from the initial alpha/beta fill.
+    /// Returns -INF if deactivated.
     int NumFlipFlops() const;
 
+    /// Invalides this Evaluator and releases its implementation.
     void Release();
 
 public:
     const AbstractMatrix& Alpha() const;
     const AbstractMatrix& Beta() const;
 
+    const AbstractMatrix* AlphaView(MatrixViewConvention c) const;
+    const AbstractMatrix* BetaView(MatrixViewConvention c) const;
+
 private:
+    /// Checks the z-score and disables the Evaluator if does not pass
+    /// the threshold.
+    /// This filter noops for Sequel models.
     void CheckZScore(const double minZScore, const std::string& model);
 
+    /// Sets the state of the Evaluator.
+    /// Allows transition from VALID to anything and from anything to DISABLED.
+    /// Disables the Evaluator if not VALID.
     void Status(PacBio::Data::State nextState);
 
 private:
diff --git a/src/align/AlignConfig.cpp b/include/pacbio/consensus/MatrixViewConvention.h
similarity index 76%
copy from src/align/AlignConfig.cpp
copy to include/pacbio/consensus/MatrixViewConvention.h
index 7f24eeb..14cdd41 100644
--- a/src/align/AlignConfig.cpp
+++ b/include/pacbio/consensus/MatrixViewConvention.h
@@ -33,26 +33,27 @@
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
-// Authors: David Alexander, Lance Hepler
+// Author: David Alexander
 
-#include <pacbio/align/AlignConfig.h>
+#pragma once
 
 namespace PacBio {
-namespace Align {
+namespace Consensus {
 
-AlignParams::AlignParams(int match, int mismatch, int insert, int delete_)
-    : Match(match), Mismatch(mismatch), Insert(insert), Delete(delete_)
+enum class MatrixViewConvention
 {
-}
 
-AlignParams AlignParams::Default() { return AlignParams(0, -1, -1, -1); }
+    AS_IS,  // View the matrix entries exactly as
+            // stored.
 
-AlignConfig::AlignConfig(AlignParams params, AlignMode mode) : Params(params), Mode(mode) {}
+    LOGSPACE,  // View matrix entries in logspace;
+               // includes column scaling factors.
 
-AlignConfig AlignConfig::Default()
-{
-    return AlignConfig(AlignParams::Default(), AlignMode::GLOBAL);
-}
+    LOGPROBABILITY,  // View matrix entries as log-scaled
+                     // probabilities.  This entails scaling
+                     // per-column and per-row
+                     // (counterweights...).
 
-}  // namespace Consensus
-}  // namespace PacBio
+};
+}
+}
diff --git a/include/pacbio/consensus/MonoMolecularIntegrator.h b/include/pacbio/consensus/MonoMolecularIntegrator.h
index b9d521f..1209d02 100644
--- a/include/pacbio/consensus/MonoMolecularIntegrator.h
+++ b/include/pacbio/consensus/MonoMolecularIntegrator.h
@@ -50,9 +50,17 @@
 namespace PacBio {
 namespace Consensus {
 
+/// The MONO-molecular integrator holds all Evaluators of a single ZMW,
+/// sharing the one Template, the CCS consensus sequence.
 class MonoMolecularIntegrator : public AbstractIntegrator
 {
 public:
+    /// \brief Initialize the MonoMolecularIntegrator.
+    ///
+    /// \param tpl    The draft template as a string
+    /// \param cfg    The configuration used to initialize the AbstractIntegrator.
+    /// \param snr    The snr
+    /// \param model  The model
     MonoMolecularIntegrator(const std::string& tpl, const IntegratorConfig& cfg,
                             const PacBio::Data::SNR& snr, const std::string& model);
 
@@ -61,14 +69,19 @@ public:
 
     size_t TemplateLength() const override;
 
+    /// Returns base i of the template
     char operator[](size_t i) const override;
     operator std::string() const override;
 
+    /// Computes the LL sum of all Evaluators, given a templated mutated by mut.
     double LL(const Mutation& mut) override;
+    /// Computes the LL sum of all Evaluators, given the current template.
     inline double LL() const override { return AbstractIntegrator::LL(); }
+    /// Applies a mutation to the template of each Evaluator.
     void ApplyMutation(const Mutation& mut) override;
+    /// Applies a vector of murations to the template of each Evaluator.
     void ApplyMutations(std::vector<Mutation>* muts) override;
-
+    /// Encapsulate the read in an Evaluator and stores it.
     PacBio::Data::State AddRead(const PacBio::Data::MappedRead& read) override;
 
 protected:
diff --git a/include/pacbio/consensus/MultiMolecularIntegrator.h b/include/pacbio/consensus/MultiMolecularIntegrator.h
index a97dcf3..8b07aca 100644
--- a/include/pacbio/consensus/MultiMolecularIntegrator.h
+++ b/include/pacbio/consensus/MultiMolecularIntegrator.h
@@ -51,19 +51,28 @@
 namespace PacBio {
 namespace Consensus {
 
+/// The MULTI-molecular integrator holds those Evaluators, whose MappedReads
+/// belong to the same genomic region, but do not share the same template.
 class MultiMolecularIntegrator : public AbstractIntegrator
 {
 public:
+    /// \brief Initialize the MultiMolecularIntegrator.
+    ///
+    /// \param tpl    The draft template as a string
+    /// \param cfg    The configuration used to initialize the AbstractIntegrator.
     MultiMolecularIntegrator(const std::string& tpl, const IntegratorConfig& cfg);
 
     size_t TemplateLength() const override;
 
+    /// Returns base i of the template
     char operator[](size_t i) const override;
     operator std::string() const override;
 
+    /// Applies a mutation to the template of each Evaluator.
     void ApplyMutation(const Mutation& mut) override;
+    /// Applies a vector of murations to the template of each Evaluator.
     void ApplyMutations(std::vector<Mutation>* muts) override;
-
+    /// Encapsulate the read in an Evaluator and stores it.
     PacBio::Data::State AddRead(const PacBio::Data::MappedRead& read) override;
 
 protected:
diff --git a/include/pacbio/consensus/Mutation.h b/include/pacbio/consensus/Mutation.h
index a965f2b..e51e472 100644
--- a/include/pacbio/consensus/Mutation.h
+++ b/include/pacbio/consensus/Mutation.h
@@ -45,6 +45,7 @@
 namespace PacBio {
 namespace Consensus {
 
+/// Enum with all possible mutation types
 enum struct MutationType : uint8_t
 {
     DELETION,
@@ -57,6 +58,8 @@ enum struct MutationType : uint8_t
 // forward decl
 class ScoredMutation;
 
+/// Encapsulates the type of the mutation, the start position, and an
+/// alternative base.
 class Mutation
 {
 public:
@@ -73,15 +76,20 @@ public:
     bool IsAnySubstitution() const;
 
     size_t Start() const;
+    /// Returns the end position of the mutation that is start + 1,
+    /// except for insertions.
     size_t End() const;
 
+    /// Returns the length difference introduced by this mutation.
     int LengthDiff() const;
 
     bool operator==(const Mutation& other) const;
     operator std::string() const;
 
+    /// Uses this and the provided score to create and return a ScoredMutation.
     ScoredMutation WithScore(double score) const;
 
+    /// Comparer to sort mutations by start/end.
     static bool SiteComparer(const Mutation& lhs, const Mutation& rhs)
     {
         // perform a lexicographic sort on End, Start, IsDeletion
diff --git a/include/pacbio/consensus/Polish.h b/include/pacbio/consensus/Polish.h
index 5eedc1a..9a47e22 100644
--- a/include/pacbio/consensus/Polish.h
+++ b/include/pacbio/consensus/Polish.h
@@ -56,8 +56,14 @@ struct PolishConfig
     PolishConfig(size_t iterations = 40, size_t separation = 10, size_t neighborhood = 20);
 };
 
+/// Given an AbstractIntegrator and a PolishConfig,
+/// iteratively polish the template,
+/// and return meta information about the procedure.
+///
+/// The template will be polished within the AbstractIntegrator.
 PolishResult Polish(AbstractIntegrator* ai, const PolishConfig& cfg);
 
+/// Struct that contains vectors for the base-wise individual and compound QVs.
 struct QualityValues
 {
     std::vector<int> Qualities;
@@ -66,10 +72,14 @@ struct QualityValues
     std::vector<int> SubstitutionQVs;
 };
 
+/// Generates phred qualities of the current template.
 std::vector<int> ConsensusQualities(AbstractIntegrator& ai);
 
+/// Generates individual and compound phred qualities of the current template.
 QualityValues ConsensusQVs(AbstractIntegrator& ai);
 
+/// Returns a list of all possible mutations that can be applied to the template
+/// of the provided integrator.
 std::vector<Mutation> Mutations(const AbstractIntegrator& ai);
 
 }  // namespace Consensus
diff --git a/include/pacbio/consensus/Template.h b/include/pacbio/consensus/Template.h
index f4b0b8c..1b013be 100644
--- a/include/pacbio/consensus/Template.h
+++ b/include/pacbio/consensus/Template.h
@@ -173,7 +173,7 @@ public:
     AbstractRecursor(std::unique_ptr<AbstractTemplate>&& tpl, const PacBio::Data::MappedRead& mr,
                      double scoreDiff);
     virtual ~AbstractRecursor() {}
-    virtual size_t FillAlphaBeta(M& alpha, M& beta) const = 0;
+    virtual size_t FillAlphaBeta(M& alpha, M& beta, double tol) const = 0;
     virtual void FillAlpha(const M& guide, M& alpha) const = 0;
     virtual void FillBeta(const M& guide, M& beta) const = 0;
     virtual double LinkAlphaBeta(const M& alpha, size_t alphaColumn, const M& beta,
diff --git a/src/Consensus.cpp b/include/pacbio/data/PlainOption.h
similarity index 67%
rename from src/Consensus.cpp
rename to include/pacbio/data/PlainOption.h
index a74e0f8..a0b26ee 100644
--- a/src/Consensus.cpp
+++ b/include/pacbio/data/PlainOption.h
@@ -33,29 +33,37 @@
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
-// Author: Lance Hepler
+// Author: Armin Töpfer
+#pragma once
 
-#include <limits>
+#include <string>
+#include <vector>
 
-#include <pacbio/ccs/Consensus.h>
+#include <pbcopper/cli/CLI.h>
 
 namespace PacBio {
-namespace CCS {
-
-ConsensusSettings::ConsensusSettings(const optparse::Values& options)
-    : MaxPoaCoverage{std::numeric_limits<size_t>::max()}
-    , MaxLength{options.get(OptionNames::MaxLength)}
-    , MinLength{options.get(OptionNames::MinLength)}
-    , MinPasses{options.get(OptionNames::MinPasses)}
-    , MinPredictedAccuracy{options.get(OptionNames::MinPredictedAccuracy)}
-    , MinZScore{options.get(OptionNames::MinZScore)}
-    , MaxDropFraction{options.get(OptionNames::MaxDropFraction)}
-    , ByStrand{options.get(OptionNames::ByStrand)}
-    , NoPolish{options.get(OptionNames::NoPolish)}
-    , MinReadScore{static_cast<float>(options.get(OptionNames::MinReadScore))}
-    , MinSNR{static_cast<double>(options.get(OptionNames::MinSnr))}
+namespace Data {
+struct PlainOption
 {
-}
+    std::string id;
+    std::vector<std::string> cliOptions;
+    std::string name;
+    std::string description;
+    JSON::Json defaultValue;
 
-}  // namespace CCS
-}  // namespace PacBio
+    PlainOption(std::string id, std::vector<std::string> cliOptions, std::string name,
+                std::string description, JSON::Json defaultValue)
+        : id(id)
+        , cliOptions(cliOptions)
+        , name(name)
+        , description(description)
+        , defaultValue(defaultValue)
+    {
+    }
+
+    operator CLI::Option() const { return {id, cliOptions, description, defaultValue}; }
+    operator std::pair<std::string, std::string>() const { return std::make_pair(id, name); }
+    operator std::string() const { return id; }
+};
+}
+}  // :: PacBio::CLI
\ No newline at end of file
diff --git a/include/pacbio/data/Read.h b/include/pacbio/data/Read.h
index 7cc5b70..05d45b8 100644
--- a/include/pacbio/data/Read.h
+++ b/include/pacbio/data/Read.h
@@ -46,6 +46,7 @@
 namespace PacBio {
 namespace Data {
 
+/// Stores nucleotide-wise signal to noise ratios.
 struct SNR
 {
     double A;
@@ -75,6 +76,7 @@ struct SNR
 
 SNR ClampSNR(const SNR& val, const SNR& min, const SNR& max);
 
+/// A Read contains the name, sequence, covariates, SNR, and associated model.
 struct Read
 {
     Read(const std::string& name, const std::string& seq, const std::vector<uint8_t>& ipd,
@@ -92,6 +94,8 @@ struct Read
     inline size_t Length() const { return Seq.length(); }
 };
 
+/// A MappedRead extends Read by the strand information and template anchoring
+/// positions.
 struct MappedRead : public Read
 {
     MappedRead(const Read& read, StrandType strand, size_t templateStart, size_t templateEnd,
diff --git a/include/pacbio/denovo/PoaGraph.h b/include/pacbio/denovo/PoaGraph.h
index 36a3751..d651d83 100644
--- a/include/pacbio/denovo/PoaGraph.h
+++ b/include/pacbio/denovo/PoaGraph.h
@@ -116,6 +116,8 @@ public:
     void WriteGraphVizFile(const std::string& filename, int flags = 0,
                            const PoaConsensus* pc = NULL) const;
 
+    void WriteGraphCsvFile(const std::string& filename) const;
+
     const PoaConsensus* FindConsensus(const PacBio::Align::AlignConfig& config,
                                       int minCoverage = -INT_MAX) const;
 
diff --git a/include/pacbio/denovo/SparsePoa.h b/include/pacbio/denovo/SparsePoa.h
index 3ade174..fdc6371 100644
--- a/include/pacbio/denovo/SparsePoa.h
+++ b/include/pacbio/denovo/SparsePoa.h
@@ -140,6 +140,8 @@ public:
     void WriteGraphVizFile(const std::string& filename, int flags = 0,
                            const PacBio::Poa::PoaConsensus* pc = nullptr) const;
 
+    void WriteGraphCsvFile(const std::string& filename) const;
+
     //
     // Clean up the POA graph, pruning minority paths, to speed up
     // successive AddRead operations.
diff --git a/scripts/task_pbccs_ccs b/scripts/task_pbccs_ccs
deleted file mode 100755
index 7768e6f..0000000
--- a/scripts/task_pbccs_ccs
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/env python
-
-# TODO replace this with native C++ implementation.
-
-"""
-Wrapper for 'ccs' executable to provide tool contract interface support (and
-incidentally, using DataSet XML as input).  Note that this will *not* currently
-support chunking, since it access the individual .bam files en masse.
-"""
-
-import logging
-import re
-import os
-import sys
-
-from pbcommand.models import FileTypes, SymbolTypes, get_pbparser
-from pbcommand.models.report import Report, Attribute
-from pbcommand.cli import pbparser_runner
-from pbcommand.utils import setup_log
-from pbcommand.engine import run_cmd
-from pbcore.io import ConsensusReadSet, SubreadSet
-
-__version__ = "0.1"
-log = logging.getLogger(__name__)
-
-class Constants(object):
-    TOOL_ID = "pbccs.tasks.ccs"
-    TOOL_NAME = "ccs"
-    DRIVER_EXE = "task_pbccs_ccs --resolved-tool-contract "
-    CCS_EXE = os.environ.get("__PBTEST_CCS_EXE", "ccs")
-    #
-    MIN_SNR_ID = "pbccs.task_options.min_snr"
-    MIN_SNR_DEFAULT = 3.75
-    MIN_READ_SCORE_ID = "pbccs.task_options.min_read_score"
-    MIN_READ_SCORE_DEFAULT = 0.65
-    MAX_LENGTH_ID = "pbccs.task_options.max_length"
-    MAX_LENGTH_DEFAULT = 7000
-    MIN_LENGTH_ID = "pbccs.task_options.min_length"
-    MIN_LENGTH_DEFAULT = 10
-    MIN_PASSES_ID = "pbccs.task_options.min_passes"
-    MIN_PASSES_DEFAULT = 3
-    MIN_PREDICTED_ACCURACY_ID = "pbccs.task_options.min_predicted_accuracy"
-    MIN_PREDICTED_ACCURACY_DEFAULT = 0.9
-    MIN_ZSCORE_ID = "pbccs.task_options.min_zscore"
-    MIN_ZSCORE_DEFAULT = -5
-    MAX_DROP_FRAC_ID = "pbccs.task_options.max_drop_fraction"
-    MAX_DROP_FRAC_DEFAULT = 0.34
-    NO_POLISH_ID="pbccs.task_options.no_polish"
-    NO_POLISH_DEFAULT=False
-    BY_STRAND_ID="pbccs.task_options.by_strand"
-    BY_STRAND_DEFAULT=False
-    MODEL_PATH_ID="pbccs.task_options.model_path"
-    MODEL_PATH_DEFAULT=""
-    MODEL_SPEC_ID="pbccs.task_options.model_spec"
-    MODEL_SPEC_DEFAULT=""
-    #
-    REPORT_FIELDS = {
-        "CCS generated": "num_ccs_reads",
-        "Below SNR threshold": "num_below_snr_threshold",
-        "No usable subreads": "num_no_usable_subreads",
-        "Insert size too long": "num_insert_size_too_long",
-        "Insert size too small": "num_insert_size_too_small",
-        "Not enough full passes": "num_not_enough_full_passes",
-        "Too many unusable subreads": "num_too_many_unusable_subreads",
-        "CCS did not converge": "num_not_converged",
-        "CCS below minimum predicted accuracy": "num_below_min_accuracy",
-    }
-
-
-def args_runner(args):
-    raise NotImplementedError("Please call 'ccs' directly.")
-
-
-def resolved_tool_contract_runner(rtc):
-    """
-    Run the ccs binary from the resolved tool contract, and generate an XML
-    dataset around the resulting .bam file.
-    """
-    subreads_file = rtc.task.input_files[0]
-    # XXX checking to make sure we don't propagate nonsense
-    barcode_sets = set()
-    with SubreadSet(subreads_file) as ds_in:
-        for ext_res in ds_in.externalResources:
-            if ext_res.barcodes is not None:
-                barcode_sets.add(ext_res.barcodes)
-    if len(barcode_sets) > 1:
-        raise RuntimeError("The input SubreadSet contains multiple distinct "+
-                           "BarcodeSets.")
-    output_file = rtc.task.output_files[0]
-    if output_file.endswith(".consensusreadset.xml"):
-        output_file = re.sub(".consensusreadset.xml", ".bam", output_file)
-    assert output_file.endswith(".bam")
-    report_file = rtc.task.output_files[1]
-    log.info("CCS_EXE = {e}".format(e=Constants.CCS_EXE))
-    args = [
-        Constants.CCS_EXE,
-        "--pbi",
-        "--force",
-        "--logLevel=DEBUG",
-        "--reportFile=%s" % report_file,
-        "--numThreads=%d" % rtc.task.nproc,
-        "--minSnr=%g" % rtc.task.options[Constants.MIN_SNR_ID],
-        "--minReadScore=%g" % rtc.task.options[Constants.MIN_READ_SCORE_ID],
-        "--maxLength=%d" % rtc.task.options[Constants.MAX_LENGTH_ID],
-        "--minLength=%d" % rtc.task.options[Constants.MIN_LENGTH_ID],
-        "--minPasses=%d" % rtc.task.options[Constants.MIN_PASSES_ID],
-        "--minZScore=%g" % rtc.task.options[Constants.MIN_ZSCORE_ID],
-        "--maxDropFraction=%g" % rtc.task.options[Constants.MAX_DROP_FRAC_ID],
-        "--minPredictedAccuracy=%g" % \
-            rtc.task.options[Constants.MIN_PREDICTED_ACCURACY_ID],
-        "--noPolish" if rtc.task.options[Constants.NO_POLISH_ID] else "",
-        "--byStrand" if rtc.task.options[Constants.BY_STRAND_ID] else "",
-        ("--modelPath=%s" % rtc.task.options[Constants.MODEL_PATH_ID]) if \
-                rtc.task.options[Constants.MODEL_PATH_ID] else "",
-        ("--modelSpec=%s" % rtc.task.options[Constants.MODEL_SPEC_ID]) if \
-                rtc.task.options[Constants.MODEL_SPEC_ID] else "",
-        subreads_file,
-        output_file
-    ]
-    log.info(" ".join(args))
-    result = run_cmd(
-        cmd=" ".join(args),
-        stdout_fh=sys.stdout,
-        stderr_fh=sys.stderr)
-    if result.exit_code != 0:
-        return result.exit_code
-    assert os.path.isfile(output_file)
-    ccs_ds = ConsensusReadSet(output_file, strict=True)
-    if len(barcode_sets) == 1:
-        for ext_res in ccs_ds.externalResources:
-            ext_res.barcodes = list(barcode_sets)[0]
-    ccs_ds.write(rtc.task.output_files[0])
-    ccs_ds.close()
-    return 0
-
-
-def get_parser():
-    p = get_pbparser(
-        tool_id=Constants.TOOL_ID,
-        version=__version__,
-        name=Constants.TOOL_NAME,
-        description=__doc__,
-        driver_exe=Constants.DRIVER_EXE,
-        nproc=SymbolTypes.MAX_NPROC,
-        default_level="INFO")
-    p.add_input_file_type(FileTypes.DS_SUBREADS, "subread_set",
-                          "SubreadSet", "Subread DataSet or .bam file")
-    p.add_output_file_type(FileTypes.DS_CCS, "bam_output",
-                           name="ConsensusReadSet",
-                           description="Output DataSet XML file",
-                           default_name="ccs")
-    p.add_output_file_type(FileTypes.TXT, "ccs_summary_txt",
-                           name="CCS run summary",
-                           description="Text report summarizing run statistics",
-                           default_name="ccs_summary")
-    p.add_float(Constants.MIN_SNR_ID, "minSnr",
-                default=Constants.MIN_SNR_DEFAULT,
-                name="Minimum SNR",
-                description="Minimum SNR of input subreads")
-    p.add_float(Constants.MIN_READ_SCORE_ID, "minReadScore",
-                default=Constants.MIN_READ_SCORE_DEFAULT,
-                name="Minimum Read Score",
-                description="Minimum read score of input subreads")
-    p.add_int(Constants.MAX_LENGTH_ID, "maxLength",
-              default=Constants.MAX_LENGTH_DEFAULT,
-              name="Maximum Subread Length",
-              description="Maximum length of subreads to use for generating CCS")
-    p.add_int(Constants.MIN_LENGTH_ID, "minLength",
-              default=Constants.MIN_LENGTH_DEFAULT,
-              name="Minimum Subread Length",
-              description="Minimum length of subreads to use for generating CCS")
-    p.add_int(Constants.MIN_PASSES_ID, "minPasses",
-              default=Constants.MIN_PASSES_DEFAULT,
-              name="Minimum Number of Passes",
-              description="Minimum number of subreads required to generate CCS")
-    p.add_float(Constants.MIN_PREDICTED_ACCURACY_ID, "minPredictedAccuracy",
-                default=Constants.MIN_PREDICTED_ACCURACY_DEFAULT,
-                name="Minimum Predicted Accuracy",
-                description="Minimum predicted accuracy in [0, 1]")
-    p.add_float(Constants.MIN_ZSCORE_ID, "minZScore",
-                default=Constants.MIN_ZSCORE_DEFAULT,
-                name="Minimum Z Score",
-                description="Minimum Z score to use a subread")
-    p.add_float(Constants.MAX_DROP_FRAC_ID, "maxDropFraction",
-                default=Constants.MAX_DROP_FRAC_DEFAULT,
-                name="Maximum Dropped Fraction",
-                description="Maximum fraction of subreads that can be dropped before " +
-                "giving up")
-    p.add_boolean(Constants.NO_POLISH_ID, "noPolish",
-                  default=Constants.NO_POLISH_DEFAULT,
-                  name="No Polish CCS",
-                  description="Only output the initial template derived from the POA")
-    p.add_boolean(Constants.BY_STRAND_ID, "byStrand",
-                  default=Constants.BY_STRAND_DEFAULT,
-                  name="By Strand CCS",
-                  description="For each ZMW, generate two CCS sequences, one for each strand")
-    p.add_str(Constants.MODEL_PATH_ID, "modelPath",
-              default=Constants.MODEL_PATH_DEFAULT,
-              name="Model(s) Path",
-              description="Path to model parameter file(s)")
-    p.add_str(Constants.MODEL_SPEC_ID, "modelSpec",
-              default=Constants.MODEL_SPEC_DEFAULT,
-              name="Model Override",
-              description="Override default model selection with a provided model specification")
-    return p
-
-
-def main(argv=sys.argv):
-    return pbparser_runner(
-        argv=argv[1:],
-        parser=get_parser(),
-        args_runner_func=args_runner,
-        contract_runner_func=resolved_tool_contract_runner,
-        alog=log,
-        setup_log_func=setup_log)
-
-if __name__ == "__main__":
-    sys.exit(main())
diff --git a/src/AbstractIntegrator.cpp b/src/AbstractIntegrator.cpp
index 00adf87..9a28404 100644
--- a/src/AbstractIntegrator.cpp
+++ b/src/AbstractIntegrator.cpp
@@ -199,5 +199,5 @@ Mutation AbstractIntegrator::ReverseComplement(const Mutation& mut) const
     return Mutation(mut.Type, TemplateLength() - mut.End(), Complement(mut.Base));
 }
 
-}  // namespace Align
+}  // namespace Consensus
 }  // namespace PacBio
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5113729..6231ddc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -20,6 +20,7 @@ set(UNY_INCLUDE_DIRS
     ${SEQAN_INCLUDE_DIRS}
     ${CPPOPTPARSE_IncludeDir}
     ${PacBioBAM_INCLUDE_DIRS}
+    ${pbcopper_INCLUDE_DIRS}
     CACHE INTERNAL
     "${PROJECT_NAME}: Include Directories"
     FORCE
@@ -62,7 +63,7 @@ add_library(unanimity STATIC
     ChainSeeds.cpp
     ChemistryMapping.cpp
     ChemistryTriple.cpp
-    Consensus.cpp
+    ConsensusSettings.cpp
     Interval.cpp
     ReadId.cpp
     SparsePoa.cpp
@@ -83,6 +84,7 @@ set(UNY_LIBRARIES
     ${ZLIB_LIBRARIES}
     ${HTSLIB_LIBRARIES}
     ${PacBioBAM_LIBRARIES}
+    ${pbcopper_LIBRARIES}
     CACHE INTERNAL
     "${PROJECT_NAME}: Libraries"
     FORCE
diff --git a/src/ConsensusSettings.cpp b/src/ConsensusSettings.cpp
new file mode 100644
index 0000000..34244b5
--- /dev/null
+++ b/src/ConsensusSettings.cpp
@@ -0,0 +1,300 @@
+// Copyright (c) 2014-2015, Pacific Biosciences of California, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted (subject to the limitations in the
+// disclaimer below) provided that the following conditions are met:
+//
+//  * Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//  * Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//  * Neither the name of Pacific Biosciences nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+// GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY PACIFIC
+// BIOSCIENCES AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL PACIFIC BIOSCIENCES OR ITS
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+
+// Author: Armin Töpfer
+
+#include <pacbio/ccs/ConsensusSettings.h>
+
+namespace PacBio {
+namespace CCS {
+namespace OptionNames {
+using PlainOption = Data::PlainOption;
+// clang-format off
+const PlainOption MaxLength{
+    "max_length",
+    { "maxLength" },
+    "Maximum Subread Length",
+    "Maximum length of subreads to use for generating CCS.",
+    CLI::Option::IntType(7000)
+};
+const PlainOption MinLength{
+    "min_length",
+    { "minLength" },
+    "Minimum Subread Length",
+    "Minimum length of subreads to use for generating CCS.",
+    CLI::Option::IntType(10)
+};
+const PlainOption MinPasses{
+    "min_passes",
+    { "minPasses" },
+    "Minimum Number of Passes",
+    "Minimum number of subreads required to generate CCS.",
+    CLI::Option::IntType(3)
+};
+const PlainOption MinPredictedAccuracy{
+    "min_predicted_accuracy",
+    { "minPredictedAccuracy" },
+    "Minimum Predicted Accuracy",
+    "Minimum predicted accuracy in [0, 1].",
+    CLI::Option::FloatType(0.9)
+};
+const PlainOption MinZScore{
+    "min_zscore",
+    { "minZScore" },
+    "Minimum Z Score",
+    "Minimum z-score to use a subread. NaN disables this filter.",
+    CLI::Option::FloatType(-3.5)
+};
+const PlainOption MaxDropFraction{
+    "max_drop_fraction",
+    { "maxDropFraction" },
+    "Maximum Dropped Fraction",
+    "Maximum fraction of subreads that can be dropped before giving up.",
+    CLI::Option::FloatType(0.34)
+};
+const PlainOption NoPolish{
+    "no_polish",
+    { "noPolish" },
+    "No Polish CCS",
+    "Only output the initial template derived from the POA (faster, less accurate).",
+    CLI::Option::BoolType()
+};
+const PlainOption MinReadScore{
+    "min_read_score",
+    { "minReadScore" },
+    "Minimal Read Score",
+    "Minimum read score of input subreads.",
+    CLI::Option::FloatType(0.75)
+};
+const PlainOption MinSnr{
+    "min_snr",
+    { "minSnr" },
+    "Minimum SNR",
+    "Minimum SNR of input subreads.",
+    CLI::Option::FloatType(3.75)
+    // See https://github.com/PacificBiosciences/pbccs/issues/86 for a more
+    // detailed discussion of this default.)
+};
+const PlainOption ByStrand{
+    "by_strand",
+    { "byStrand" },
+    "By Strand CCS",
+    "Generate a consensus for each strand.",
+    CLI::Option::BoolType()
+};
+const PlainOption ForceOutput{
+    "force",
+    { "force" },
+    "Force overwrite output",
+    "Overwrite OUTPUT file if present.",
+    CLI::Option::BoolType()
+};
+const PlainOption Zmws{
+    "zmws",
+    { "zmws" },
+    "Whitelist ZMWs",
+    "Generate CCS for the provided comma-separated holenumber ranges only. Default = all",
+    CLI::Option::StringType("")
+};
+const PlainOption ReportFile{
+    "report_file",
+    { "reportFile" },
+    "Report File Output",
+    "Where to write the results report.",
+    CLI::Option::StringType("ccs_report.txt")
+};
+const PlainOption NumThreads{
+    "num_threads",
+    { "numThreads" },
+    "Number of Threads",
+    "Number of threads to use, 0 means autodetection.",
+    CLI::Option::IntType(0)
+};
+const PlainOption LogFile{
+    "log_file",
+    { "logFile" },
+    "Log to a File",
+    "Log to a file, instead of STDERR.",
+    CLI::Option::StringType("")
+};
+const PlainOption LogLevel{
+    "log_level",
+    { "logLevel" },
+    "Set Log Level",
+    "Set log level.",
+    CLI::Option::StringType("INFO")
+};
+const PlainOption RichQVs{
+    "rich_qvs",
+    { "richQVs" },
+    "Emit individual QVs",
+    "Emit dq, iq, and sq \"rich\" quality tracks.",
+    CLI::Option::BoolType()
+};
+const PlainOption ModelPath{
+    "model_path",
+    { "modelPath" },
+    "Model(s) Path",
+    "Path to a model file or directory containing model files.",
+    CLI::Option::StringType("")
+};
+const PlainOption ModelSpec{
+    "model_spec",
+    { "modelSpec" },
+    "Model Override",
+    "Name of chemistry or model to use, overriding default selection.",
+    CLI::Option::StringType("")
+};
+// clang-format on
+}  // namespace OptionNames
+
+ConsensusSettings::ConsensusSettings(const PacBio::CLI::Results& options)
+    : ByStrand(options[OptionNames::ByStrand])
+    , ForceOutput(options[OptionNames::ForceOutput])
+    , LogFile(std::forward<std::string>(options[OptionNames::LogFile]))
+    , LogLevel(std::forward<std::string>(options[OptionNames::LogLevel]))
+    , MaxDropFraction(options[OptionNames::MaxDropFraction])
+    , MaxLength(options[OptionNames::MaxLength])
+    , MinLength(options[OptionNames::MinLength])
+    , MinPasses(options[OptionNames::MinPasses])
+    , MinPredictedAccuracy(options[OptionNames::MinPredictedAccuracy])
+    , MinReadScore(options[OptionNames::MinReadScore])
+    , MinSNR(options[OptionNames::MinSnr])
+
+    , MinZScore(options[OptionNames::MinZScore] == nullptr
+                    ? NAN
+                    : static_cast<float>(options[OptionNames::MinZScore]))
+    , ModelPath(std::forward<std::string>(options[OptionNames::ModelPath]))
+    , ModelSpec(std::forward<std::string>(options[OptionNames::ModelSpec]))
+    , NoPolish(options[OptionNames::NoPolish])
+    , NThreads(ThreadCount(options[OptionNames::NumThreads]))
+    , ReportFile(std::forward<std::string>(options[OptionNames::ReportFile]))
+    , RichQVs(options[OptionNames::RichQVs])
+    , WlSpec(std::forward<std::string>(options[OptionNames::Zmws]))
+{
+}
+
+size_t ConsensusSettings::ThreadCount(int n)
+{
+    const int m = std::thread::hardware_concurrency();
+
+    if (n < 1) return std::max(1, m + n);
+
+    return std::min(m, n);
+}
+
+PacBio::CLI::Interface ConsensusSettings::CreateCLI(const std::string& description,
+                                                    const std::string& version)
+{
+    using Option = PacBio::CLI::Option;
+    PacBio::CLI::Interface i{"ccs", description, version};
+
+    i.AlternativeToolContractName("pbccs");
+
+    i.AddHelpOption();     // use built-in help output
+    i.AddVersionOption();  // use built-in version output
+
+    // clang-format off
+    i.AddPositionalArguments({
+        {"input",  "Input file.",  "INPUT"},
+        {"output", "Output file.", "OUTPUT"}
+    });
+
+    i.AddOptions(
+    {
+        OptionNames::ForceOutput,
+        OptionNames::Zmws,
+        OptionNames::MaxLength,
+        OptionNames::MinLength,
+        OptionNames::MinPasses,
+        OptionNames::MinPredictedAccuracy,
+        OptionNames::MinZScore,
+        OptionNames::MaxDropFraction,
+        OptionNames::MinSnr,
+        OptionNames::MinReadScore,
+        OptionNames::ByStrand,
+        OptionNames::NoPolish,
+        OptionNames::RichQVs,
+        OptionNames::ReportFile,
+        OptionNames::ModelPath,
+        OptionNames::ModelSpec,
+        OptionNames::NumThreads,
+        OptionNames::LogFile,
+        OptionNames::LogLevel
+    });
+
+    const std::string id = "pbccs.tasks.ccs";
+    CLI::ToolContract::Task tcTask(id);
+    tcTask.AddOption(OptionNames::MinSnr);
+    tcTask.AddOption(OptionNames::MinReadScore);
+    tcTask.AddOption(OptionNames::MaxLength);
+    tcTask.AddOption(OptionNames::MinLength);
+    tcTask.AddOption(OptionNames::MinPasses);
+    tcTask.AddOption(OptionNames::MinPredictedAccuracy);
+    tcTask.AddOption(OptionNames::MinZScore);
+    tcTask.AddOption(OptionNames::MaxDropFraction);
+    tcTask.AddOption(OptionNames::NoPolish);
+    tcTask.AddOption(OptionNames::ByStrand);
+    tcTask.AddOption(OptionNames::ModelPath);
+    tcTask.AddOption(OptionNames::ModelSpec);
+    tcTask.AddOption(OptionNames::ReportFile);
+
+    tcTask.InputFileTypes({
+        {
+            "subread_set",
+            "SubreadSet",
+            "Subread DataSet or .bam file",
+            "PacBio.DataSet.SubreadSet"
+        }
+    });
+
+    tcTask.OutputFileTypes({
+        {
+            "bam_output",
+            "ConsensusReadSet",
+            "Output DataSet XML file",
+            "PacBio.DataSet.ConsensusReadSet",
+            "ccs"
+        }
+    });
+
+    CLI::ToolContract::Config tcConfig(tcTask);
+    i.EnableToolContract(tcConfig);
+    // clang-format on
+
+    return i;
+}
+}
+}  // ::PacBio::CCS
\ No newline at end of file
diff --git a/src/Evaluator.cpp b/src/Evaluator.cpp
index e7508ab..e258ee9 100644
--- a/src/Evaluator.cpp
+++ b/src/Evaluator.cpp
@@ -193,6 +193,24 @@ const AbstractMatrix& Evaluator::Beta() const
     }
 }
 
+const AbstractMatrix* Evaluator::AlphaView(MatrixViewConvention c) const
+{
+    if (IsValid()) {
+        return impl_->AlphaView(c);
+    } else {
+        return nullptr;
+    }
+}
+
+const AbstractMatrix* Evaluator::BetaView(MatrixViewConvention c) const
+{
+    if (IsValid()) {
+        return impl_->BetaView(c);
+    } else {
+        return nullptr;
+    }
+}
+
 void Evaluator::CheckZScore(const double minZScore, const std::string& model)
 {
     // the zscore filter is disabled under the following conditions
diff --git a/src/EvaluatorImpl.cpp b/src/EvaluatorImpl.cpp
index 88f918b..4f4fefa 100644
--- a/src/EvaluatorImpl.cpp
+++ b/src/EvaluatorImpl.cpp
@@ -38,6 +38,7 @@
 #include <boost/optional.hpp>
 
 #include "EvaluatorImpl.h"
+#include "matrix/BasicDenseMatrix.h"
 
 using namespace PacBio::Data;
 
@@ -45,6 +46,8 @@ namespace PacBio {
 namespace Consensus {
 namespace {  // anonymous
 
+constexpr double ALPHA_BETA_MISMATCH_TOLERANCE = 0.001;
+constexpr double EARLY_ALPHA_BETA_MISMATCH_TOLERANCE = 0.0001;
 constexpr size_t EXTEND_BUFFER_COLUMNS = 8;
 
 #if 0
@@ -92,7 +95,7 @@ EvaluatorImpl::EvaluatorImpl(std::unique_ptr<AbstractTemplate>&& tpl, const Mapp
     , beta_(mr.Length() + 1, recursor_->tpl_->Length() + 1, ScaledMatrix::REVERSE)
     , extendBuffer_(mr.Length() + 1, EXTEND_BUFFER_COLUMNS, ScaledMatrix::FORWARD)
 {
-    numFlipFlops_ = recursor_->FillAlphaBeta(alpha_, beta_);
+    numFlipFlops_ = recursor_->FillAlphaBeta(alpha_, beta_, EARLY_ALPHA_BETA_MISMATCH_TOLERANCE);
 }
 
 std::string EvaluatorImpl::ReadName() const { return recursor_->read_.Name; }
@@ -215,7 +218,7 @@ inline void EvaluatorImpl::Recalculate()
     alpha_.Reset(I, J);
     beta_.Reset(I, J);
     extendBuffer_.Reset(I, EXTEND_BUFFER_COLUMNS);
-    recursor_->FillAlphaBeta(alpha_, beta_);
+    recursor_->FillAlphaBeta(alpha_, beta_, ALPHA_BETA_MISMATCH_TOLERANCE);
 }
 
 bool EvaluatorImpl::ApplyMutation(const Mutation& mut)
@@ -240,5 +243,53 @@ const AbstractMatrix& EvaluatorImpl::Alpha() const { return alpha_; }
 
 const AbstractMatrix& EvaluatorImpl::Beta() const { return beta_; }
 
+const AbstractMatrix* EvaluatorImpl::AlphaView(MatrixViewConvention c) const
+{
+    BasicDenseMatrix* m = new BasicDenseMatrix(alpha_.Rows(), alpha_.Columns());
+
+    for (size_t i = 0; i < alpha_.Rows(); ++i) {
+        for (size_t j = 0; j < alpha_.Columns(); ++j) {
+            switch (c) {
+                case MatrixViewConvention::AS_IS:
+                    (*m)(i, j) = alpha_(i, j);
+                    break;
+                case MatrixViewConvention::LOGSPACE:
+                    (*m)(i, j) = std::log(alpha_(i, j)) + alpha_.GetLogScale(j);
+                    break;
+                case MatrixViewConvention::LOGPROBABILITY:
+                    (*m)(i, j) = std::log(alpha_(i, j)) + alpha_.GetLogScale(j) +
+                                 recursor_->UndoCounterWeights(i);
+                    break;
+            }
+        }
+    }
+
+    return m;
+}
+
+const AbstractMatrix* EvaluatorImpl::BetaView(MatrixViewConvention c) const
+{
+    BasicDenseMatrix* m = new BasicDenseMatrix(beta_.Rows(), beta_.Columns());
+
+    for (size_t i = 0; i < beta_.Rows(); ++i) {
+        for (size_t j = 0; j < beta_.Columns(); ++j) {
+            switch (c) {
+                case MatrixViewConvention::AS_IS:
+                    (*m)(i, j) = beta_(i, j);
+                    break;
+                case MatrixViewConvention::LOGSPACE:
+                    (*m)(i, j) = std::log(beta_(i, j)) + beta_.GetLogScale(j);
+                    break;
+                case MatrixViewConvention::LOGPROBABILITY:
+                    (*m)(i, j) = std::log(beta_(i, j)) + beta_.GetLogScale(j) +
+                                 recursor_->UndoCounterWeights(beta_.Rows() - 1 - i);
+                    break;
+            }
+        }
+    }
+
+    return m;
+}
+
 }  // namespace Consensus
 }  // namespace PacBio
diff --git a/src/EvaluatorImpl.h b/src/EvaluatorImpl.h
index 28524d8..abdaa0c 100644
--- a/src/EvaluatorImpl.h
+++ b/src/EvaluatorImpl.h
@@ -40,6 +40,7 @@
 #include <vector>
 
 #include <pacbio/consensus/Evaluator.h>
+#include <pacbio/consensus/MatrixViewConvention.h>
 #include <pacbio/consensus/Template.h>
 #include <pacbio/data/Read.h>
 
@@ -74,6 +75,10 @@ public:
     const AbstractMatrix& Alpha() const;
     const AbstractMatrix& Beta() const;
 
+public:
+    const AbstractMatrix* AlphaView(MatrixViewConvention c) const;
+    const AbstractMatrix* BetaView(MatrixViewConvention c) const;
+
 private:
     void Recalculate();
 
diff --git a/src/ModelSelection.cpp b/src/ModelSelection.cpp
index 660bf19..77c6951 100644
--- a/src/ModelSelection.cpp
+++ b/src/ModelSelection.cpp
@@ -96,11 +96,12 @@ size_t LoadModelsFromDirectory(const std::string& dirPath)
     // iterate through .json files in directory,
     //   loading any into ModelFactory
     bool ret = true;
-    size_t nModels = 0;
+    size_t nModels = 0, dot;
     struct dirent* ep;
     while ((ep = readdir(dp)) != nullptr) {
         std::string path = dirPath + '/' + ep->d_name;
-        if (path.substr(path.find_last_of('.')) != ".json") continue;
+        if ((dot = path.find_last_of('.')) == std::string::npos || path.substr(dot) != ".json")
+            continue;
         if (!(ret &= (stat(path.c_str(), &st) == 0))) break;
         if (S_ISREG(st.st_mode)) {
             if ((ret &= LoadModelFromFile(path)))
diff --git a/src/Read.cpp b/src/Read.cpp
index 882eaf0..6284a9f 100644
--- a/src/Read.cpp
+++ b/src/Read.cpp
@@ -64,6 +64,10 @@ Read::Read(const std::string& name, const std::string& seq, const std::vector<ui
            const std::vector<uint8_t>& pw, const SNR& snr, const std::string& model)
     : Name{name}, Seq{seq}, IPD{ipd}, PulseWidth{pw}, SignalToNoise{snr}, Model{model}
 {
+    if (ipd.size() != seq.size() || pw.size() != seq.size()) {
+        throw new std::invalid_argument("Invalid Read (name=" + name +
+                                        "): features IPD/PW/seq are of mismatched length");
+    }
 }
 
 MappedRead::MappedRead(const Read& read, StrandType strand, size_t templateStart,
@@ -98,5 +102,5 @@ std::ostream& operator<<(std::ostream& os, const MappedRead& mr)
     return os;
 }
 
-}  // namespace Consensus
+}  // namespace Data
 }  // namespace PacBio
diff --git a/src/Recursor.h b/src/Recursor.h
index 9932151..7d5480a 100644
--- a/src/Recursor.h
+++ b/src/Recursor.h
@@ -54,72 +54,89 @@ namespace Consensus {
 // AbstractRecursor is in Template.h
 
 // TODO(lhepler) comment about use of CRTP
+
+/// The recursor is the heart of ConsensusCore. Via dynamic programming,
+/// it computes the log probability that the MappedRead stems from the Template.
+///
+/// In a traditional fashion the forward matrix is being computed and instead of
+/// takin the Viterbi path, the backward matrix is computed.
+/// Both combined provide the posterior probabilities that the optimal path goes
+/// through this cell.
+///
+/// The trick is, after each mutation, only the affected column itself and its
+/// neighbors need to be recomputed. This allows a rapid exploration of the
+/// likelihood surface to find the next best mutations to generate a template
+/// that is more likely to generate the observed MappedRead.
 template <typename Derived>
 class Recursor : public AbstractRecursor
 {
 public:
-    // \brief Construct a Recursor from a Template and a MappedRead,
-    // The scoreDiff here is passed in negative logScale and converted
-    // to the appropriate divisor.
+    /// \brief Construct a Recursor from a Template and a MappedRead.
+    /// The scoreDiff here is passed in negative logScale and converted
+    /// to the appropriate divisor.
     Recursor(std::unique_ptr<AbstractTemplate>&& tpl, const PacBio::Data::MappedRead& mr,
              double scoreDiff = 12.5);
 
     /// \brief Fill the alpha and beta matrices.
+    ///
     /// This routine will fill the alpha and beta matrices, ensuring
     /// that the score computed from the alpha and beta recursions are
     /// identical, refilling back-and-forth if necessary.
-    size_t FillAlphaBeta(M& alpha, M& beta) const;
-
-    /**
-     Fill in the alpha matrix.  This matrix has the read run along the rows, and
-     the template run along the columns.  The first row and column do not correspond
-     to a template position.  Therefore the match represented at position (i,j)
-     corresponds to a match between template positions (i+1, j+1).
-
-     The alpha matrix is the "Forward" matrix used in the forward/backward
-     algorithm.
-     The i,j position of the matrix represents the probability of all paths up
-     to the point where the ith read position and jth template have been
-     "emitted."
-     The matrix is calculated recursively by examining all possible transitions
-     into (i,j), and calculating the probability we were in the previous state,
-     times the probability of a transition into (i,j) times the probability of
-     emitting the observation that corresponds to (i,j). All probabilities are
-     calculated and stored as LOG values.
-
-     Note that in doing this calculation, in order to work with di-nucleotide
-     contexts, we require that the first and last transition be a match.  In other words the
-     start and end of the read and template are "pinned" to each other.
-
-     //TODO: Verify memory is initialized to 0!
-
-     @param guide An object that helps inform how to select the size of "bands"
-     for the banded algorithm used.  This is typically the beta matrix if we are
-     "repopulating" the matrix.
-     @param alpha The matrix to be filled.
-     */
-
+    ///
+    /// Returns the number of flip flop events (refilling events).
+    size_t FillAlphaBeta(M& alpha, M& beta, double tol) const;
+
+    /// \brief Fill in the alpha matrix.
+    ///
+    /// This matrix has the read run along the rows and the template run along
+    /// the columns. The first row and column do not correspond to a template
+    /// position. Therefore the match represented at position (i,j) corresponds
+    /// to a match between template positions (i+1, j+1).
+    ///
+    /// The alpha matrix is the "Forward" matrix used in the forward/backward
+    /// algorithm.
+    ///
+    /// The (i,j) position of the matrix represents the probability of all paths
+    /// up to the point where the i-th read position and j-th template have been
+    /// "emitted."
+    ///
+    /// The matrix is calculated recursively by examining all possible
+    /// transitions into (i,j), and calculating the probability we were in the
+    /// previous state, times the probability of a transition into (i,j) times
+    /// the probability of emitting the observation that corresponds to (i,j).
+    /// All probabilities are calculated and stored as LOG values.
+    ///
+    /// Note that in doing this calculation, in order to work with di-nucleotide
+    /// contexts, we require that the first and last transition be a match.
+    /// In other words the start and end of the read and template are "pinned"
+    /// to each other.
+    ///
+    /// TODO: Verify memory is initialized to 0!
+    ///
+    /// \param guide An object that helps inform how to select the size of
+    ///              "bands" for the banded algorithm used. This is typically
+    ///              the beta matrix if we are "repopulating" the matrix.
+    /// \param alpha The matrix to be filled.
     void FillAlpha(const M& guide, M& alpha) const;
 
-    /**
-     Fill the Beta matrix, the backwards half of the forward-backward algorithm.
-     This represents the probability that starting from the (i,j) state, the
-     combined probability of transitioning out and following all paths through to the
-     end. That is, we need to calculate transition from state and emit from next
-     state for each
-
-     In combination with the Alpha matrix, this allows us to calculate all paths
-     that pass through the (i,j) element, as exp(Alpha(i,j) + Beta(i,j))
-
-     All probabilities stored in the matrix are stored as NON-LOGGED
-     probabilities.
-
-     @param e The evaluator, such as QvEvaluator
-     @param M the guide matrix for banding (this needs more documentation)
-     @param beta The Beta matrix, stored as either a DenseMatrix or a
-     SparseMatrix.
-     */
-
+    /// \brief Fill the Beta matrix.
+    /// That is the backwards half of the forward-backward algorithm.
+    /// This represents the probability that starting from the (i,j) state, the
+    /// combined probability of transitioning out and following all paths
+    /// through to the end. That is, we need to calculate transition from state
+    /// and emit from next state for each
+    ///
+    /// In combination with the Alpha matrix, this allows us to calculate all
+    /// paths that pass through the (i,j) element,
+    /// as exp(Alpha(i,j) + Beta(i,j))
+    ///
+    /// All probabilities stored in the matrix are stored as NON-LOGGED
+    /// probabilities.
+    ///
+    /// \param e    The evaluator, such as QvEvaluator
+    /// \param M    the guide matrix for banding (this needs more documentation)
+    /// \param beta The Beta matrix, stored as either a DenseMatrix or a
+    ///             SparseMatrix.
     void FillBeta(const M& guide, M& beta) const;
 
     /// \brief Calculate the recursion score by "linking" partial alpha and/or
@@ -127,8 +144,21 @@ public:
     double LinkAlphaBeta(const M& alpha, size_t alphaColumn, const M& beta, size_t betaColumn,
                          size_t absoluteColumn) const;
 
+    /// This method extends the Alpha matrix into a temporary matrix given by
+    /// ext. It extends the region [beginColumn, beginColumn + numExtColumns)
+    ///
+    /// \param alpha         The alpha matrix
+    /// \param beginColumn   The column where extension should start
+    /// \param ext           The matrix to be extended
+    /// \param numExtColumns The number of columns to be extended
     void ExtendAlpha(const M& alpha, size_t beginColumn, M& ext, size_t numExtColumns = 2) const;
 
+    /// This method extends the Beta matrix into a temporary matrix given by ext.
+    ///
+    /// \param beta       The beta matrix
+    /// \param endColumn  The right-hand side where extension should start
+    /// \param ext        The matrix to be extended
+    /// \param lengthDiff The length difference of the mutation
     void ExtendBeta(const M& beta, size_t endColumn, M& ext, int lengthDiff = 0) const;
 
 private:
@@ -139,7 +169,6 @@ private:
     /// of the maximum path through each and the inputs for column j.
     bool RangeGuide(size_t j, const M& guide, const M& matrix, size_t* beginRow,
                     size_t* endRow) const;
-    // The RangeGuide function determines the minimum score by dividing out scoreDiff_
 
 private:
     std::vector<uint8_t> emissions_;
@@ -152,7 +181,6 @@ typedef std::pair<size_t, size_t> Interval;
 // TODO(dalexander): put these into a RecursorConfig struct
 // TODO(anybody): Hmmm... not sure what the heck to do about these...
 constexpr int MAX_FLIP_FLOPS = 5;
-constexpr double ALPHA_BETA_MISMATCH_TOLERANCE = 0.001;
 constexpr double REBANDING_THRESHOLD = 0.04;
 
 constexpr uint8_t kDefaultBase = 0;  // corresponding to A, usually
@@ -456,19 +484,13 @@ double Recursor<Derived>::LinkAlphaBeta(const M& alpha, size_t alphaColumn, cons
             beta.GetLogProdScales(betaColumn, beta.Columns()));
 }
 
-/**
- This method extends that Alpha matrix into a temporary matrix given by
- ext.  It extends the region [beginColumn, beginColumn + numExtColumns)
-
- Note that this method is used EXCLUSIVELY for testing mutations, and so
- we don't get the actual parameters and positions from the template, but we
- get them after a "virtual" mutation has been applied.
-
- All new data is placed in the extension matrix.  The guesses for start/end
- rows in the banding are determined by evaluating neighbors of each position.
- @param <#parameter#>
- @returns <#retval#>
- */
+/// Note that this method is used EXCLUSIVELY for testing mutations, and so
+/// we don't get the actual parameters and positions from the template, but
+/// we get them after a "virtual" mutation has been applied.
+///
+/// All new data is placed in the extension matrix. The guesses for
+/// start/end rows in the banding are determined by evaluating neighbors of
+/// each position.
 template <typename Derived>
 void Recursor<Derived>::ExtendAlpha(const M& alpha, size_t beginColumn, M& ext,
                                     size_t numExtColumns) const
@@ -564,25 +586,23 @@ void Recursor<Derived>::ExtendAlpha(const M& alpha, size_t beginColumn, M& ext,
     }
 }
 
-// Semantic: After ExtendBeta(B, j), we have
-//    ext(:, numExtColumns-1) = B'(:,j)
-//    ext(:, numExtColumns-2) = B'(:,j-1) ...
-//
-// Note: lastColumn is the numerically largest column number that
-// will be filled, but it is filled first since beta fill is done
-// backwards.
-//
-// Accesses B(:, ..(j+2))
-
-/* Note this is a very confusing routine in order to avoid recomputing and
-   additional memory allocations.  This routine tries to stick on a beta matrix
-   to the original and back trace to the 0,0 position of this extension matrix.
-   matrix from the original.  Note that the original beta
-   matrix is indexed by the original template positions, while the template
-   bases and parameters are now indexed according the the "virtual" template
-   to which mutations have been applied.
- */
-// @param lastColumn - Where we
+/// Semantic: After ExtendBeta(B, j), we have
+///    ext(:, numExtColumns-1) = B'(:,j)
+///    ext(:, numExtColumns-2) = B'(:,j-1) ...
+///
+/// Note: lastColumn is the numerically largest column number that
+/// will be filled, but it is filled first since beta fill is done
+/// backwards.
+///
+/// Accesses B(:, ..(j+2))
+///
+/// Note this is a very confusing routine in order to avoid recomputing and
+/// additional memory allocations.  This routine tries to stick on a beta matrix
+/// to the original and back trace to the 0,0 position of this extension matrix.
+/// matrix from the original.  Note that the original beta
+/// matrix is indexed by the original template positions, while the template
+/// bases and parameters are now indexed according the the "virtual" template
+/// to which mutations have been applied.
 template <typename Derived>
 void Recursor<Derived>::ExtendBeta(const M& beta, size_t lastColumn, M& ext, int lengthDiff) const
 {
@@ -697,7 +717,7 @@ Recursor<Derived>::Recursor(std::unique_ptr<AbstractTemplate>&& tpl,
 }
 
 template <typename Derived>
-size_t Recursor<Derived>::FillAlphaBeta(M& a, M& b) const
+size_t Recursor<Derived>::FillAlphaBeta(M& a, M& b, const double tol) const
 {
     if (tpl_->Length() == 0) throw std::runtime_error("template length is 0, invalid state!");
 
@@ -725,7 +745,7 @@ size_t Recursor<Derived>::FillAlphaBeta(M& a, M& b) const
         alphaV = std::log(a(I, J)) + a.GetLogProdScales() + unweight;
         betaV = std::log(b(0, 0)) + b.GetLogProdScales() + unweight;
 
-        if (std::abs(1.0 - alphaV / betaV) <= ALPHA_BETA_MISMATCH_TOLERANCE) break;
+        if (std::abs(1.0 - alphaV / betaV) <= tol) break;
 
         if (flipflops % 2 == 0)
             FillAlpha(b, a);
@@ -735,7 +755,7 @@ size_t Recursor<Derived>::FillAlphaBeta(M& a, M& b) const
         ++flipflops;
     }
 
-    if (std::abs(1.0 - alphaV / betaV) > ALPHA_BETA_MISMATCH_TOLERANCE || !std::isfinite(betaV))
+    if (std::abs(1.0 - alphaV / betaV) > tol || !std::isfinite(betaV))
         throw PacBio::Exception::AlphaBetaMismatch();
 
     return flipflops;
@@ -772,6 +792,7 @@ inline Interval Recursor<Derived>::RowRange(size_t j, const M& matrix) const
     return Interval(beginRow, endRow);
 }
 
+// The RangeGuide function determines the minimum score by dividing out scoreDiff_.
 template <typename Derived>
 inline bool Recursor<Derived>::RangeGuide(size_t j, const M& guide, const M& matrix,
                                           size_t* beginRow, size_t* endRow) const
diff --git a/src/Sequence.cpp b/src/Sequence.cpp
index 09a53df..4c5071e 100644
--- a/src/Sequence.cpp
+++ b/src/Sequence.cpp
@@ -94,5 +94,5 @@ std::string ReverseComplement(const std::string& input)
     return output;
 }
 
-}  // namespace Consensus
+}  // namespace Data
 }  // namespace PacBio
diff --git a/src/SparsePoa.cpp b/src/SparsePoa.cpp
index 10067c5..189944e 100644
--- a/src/SparsePoa.cpp
+++ b/src/SparsePoa.cpp
@@ -215,6 +215,11 @@ void SparsePoa::WriteGraphVizFile(const std::string& filename, int flags,
     graph_->WriteGraphVizFile(filename, flags, pc);
 }
 
+void SparsePoa::WriteGraphCsvFile(const std::string& filename) const
+{
+    graph_->WriteGraphCsvFile(filename);
+}
+
 void SparsePoa::PruneGraph(float /* minCoverageFraction */) {}
 void SparsePoa::repCheck()
 {
@@ -222,5 +227,5 @@ void SparsePoa::repCheck()
     assert(graph_->NumReads() == reverseComplemented_.size());
 }
 
-}  // namespace CCS
+}  // namespace Poa
 }  // namespace PacBio
diff --git a/src/Timer.cpp b/src/Timer.cpp
index f43ca94..f4e2d06 100644
--- a/src/Timer.cpp
+++ b/src/Timer.cpp
@@ -57,5 +57,5 @@ float Timer::ElapsedSeconds() const { return ElapsedMilliseconds() / 1000; }
 
 void Timer::Restart() { tick = steady_clock::now(); }
 
-}  // namespace CCS
+}  // namespace Util
 }  // namespace PacBio
diff --git a/src/Utility.cpp b/src/Utility.cpp
index b409aa1..f969ec8 100644
--- a/src/Utility.cpp
+++ b/src/Utility.cpp
@@ -71,6 +71,9 @@ bool FileExists(const string& path)
 
 string FileExtension(const string& path)
 {
+    auto pathLower = path;
+    std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), ::tolower);
+
     size_t fileStart = path.find_last_of("/");
 
     if (fileStart == string::npos) fileStart = 0;
@@ -133,5 +136,5 @@ bool ValidBaseFeatures(const PacBio::BAM::DataSet& ds)
     return true;
 }
 
-}  // namespace CCS
+}  // namespace IO
 }  // namespace PacBio
diff --git a/src/align/AlignConfig.cpp b/src/align/AlignConfig.cpp
index 7f24eeb..c6ee5cb 100644
--- a/src/align/AlignConfig.cpp
+++ b/src/align/AlignConfig.cpp
@@ -54,5 +54,5 @@ AlignConfig AlignConfig::Default()
     return AlignConfig(AlignParams::Default(), AlignMode::GLOBAL);
 }
 
-}  // namespace Consensus
+}  // namespace Align
 }  // namespace PacBio
diff --git a/src/main/ccs.cpp b/src/main/ccs.cpp
index 17114d7..7d76dee 100644
--- a/src/main/ccs.cpp
+++ b/src/main/ccs.cpp
@@ -46,11 +46,13 @@
 #include <string>
 #include <vector>
 
+#include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include <boost/numeric/conversion/cast.hpp>
 #include <boost/optional.hpp>
 
-#include <OptionParser.h>
+#include <pbcopper/cli/CLI.h>
 
 #include <pbbam/BamWriter.h>
 #include <pbbam/EntireFileQuery.h>
@@ -85,27 +87,10 @@ using namespace PacBio::Logging;
 using boost::none;
 using boost::numeric_cast;
 using boost::optional;
-using optparse::OptionParser;
 
 // these strings are part of the BAM header, they CANNOT contain newlines
-#define DESCRIPTION "Generate circular consensus sequences (ccs) from subreads."
-
-namespace PacBio {
-namespace CCS {
-namespace OptionNames {
-constexpr auto ForceOutput = "force";
-constexpr auto PbIndex = "pbi";
-constexpr auto Zmws = "zmws";
-constexpr auto ReportFile = "reportFile";
-constexpr auto NumThreads = "numThreads";
-constexpr auto LogFile = "logFile";
-constexpr auto LogLevel = "logLevel";
-constexpr auto RichQVs = "richQVs";
-constexpr auto ModelPath = "modelPath";
-constexpr auto ModelSpec = "modelSpec";
-}  // namespace OptionNames
-}  // namespace CCS
-}  // namespace PacBio
+const std::string DESCRIPTION = "Generate circular consensus sequences (ccs) from subreads.";
+const std::string APPNAME = "ccs";
 
 typedef ReadType<ReadId> Subread;
 typedef ChunkType<ReadId, Subread> Chunk;
@@ -251,13 +236,13 @@ Results FastqWriterThread(WorkQueue<Results>& queue, const string& fname)
     return counts;
 }
 
-BamHeader PrepareHeader(const OptionParser& parser, int argc, char** argv, const DataSet& ds)
+BamHeader PrepareHeader(const std::string& cmdLine, const DataSet& ds)
 {
     using boost::algorithm::join;
 
-    ProgramInfo program(parser.prog() + "-" + PacBio::UnanimityVersion());
-    program.Name(parser.prog())
-        .CommandLine(parser.prog() + " " + join(vector<string>(argv + 1, argv + argc), " "))
+    ProgramInfo program(APPNAME + "-" + PacBio::UnanimityVersion());
+    program.Name(APPNAME)
+        .CommandLine(APPNAME + " " + cmdLine)
         .Description(DESCRIPTION)
         .Version(PacBio::UnanimityVersion());
 
@@ -267,7 +252,7 @@ BamHeader PrepareHeader(const OptionParser& parser, int argc, char** argv, const
     for (const auto& bam : ds.BamFiles()) {
         for (const auto& rg : bam.Header().ReadGroups()) {
             if (rg.ReadType() != "SUBREAD")
-                parser.error("invalid input file, READTYPE must be SUBREAD");
+                std::cerr << "invalid input file, READTYPE must be SUBREAD" << std::endl;
 
             ReadGroupInfo readGroup(rg.MovieName(), "CCS");
             readGroup.BindingKit(rg.BindingKit())
@@ -287,15 +272,6 @@ BamHeader PrepareHeader(const OptionParser& parser, int argc, char** argv, const
     return header;
 }
 
-size_t ThreadCount(int n)
-{
-    const int m = thread::hardware_concurrency();
-
-    if (n < 1) return max(1, m + n);
-
-    return min(m, n);
-}
-
 void WriteResultsReport(ostream& report, const Results& counts)
 {
     size_t total = counts.Total();
@@ -339,117 +315,57 @@ void WriteResultsReport(ostream& report, const Results& counts)
     counts.SubreadCounter.WriteResultsReport(report);
 }
 
-int main(int argc, char** argv)
+static int Runner(const PacBio::CLI::Results& args)
 {
     using boost::algorithm::join;
     using boost::make_optional;
 
     SetColumns();
 
-    // args and options
-    //
-    //
-    // clang-format off
-    //   clang messes with the way the arg to version() is formatted..
-    auto parser =
-        OptionParser()
-            .usage("usage: %prog [OPTIONS] INPUT OUTPUT")
-            .version("%prog " + PacBio::UnanimityVersion() + " (commit " + PacBio::UnanimityGitSha1() + ")" +
-                     "\nunanimity " + PacBio::UnanimityVersion() + " (commit " + PacBio::UnanimityGitSha1() + ")" +
-                     "\nCopyright (c) 2014-2016 Pacific Biosciences, Inc.\nLicense: 3-BSD")
-            .description(DESCRIPTION
-                         "\nAdditional documentation: http://github.com/PacificBiosciences/unanimity");
-    // clang-format on
-    //
-    const vector<string> logLevels = {"TRACE", "DEBUG", "INFO",     "NOTICE",
-                                      "WARN",  "ERROR", "CRITICAL", "FATAL"};
-    const string em = "--";
-
-    parser.add_option(em + OptionNames::ForceOutput)
-        .action("store_true")
-        .help("Overwrite OUTPUT file if present.");
-    parser.add_option(em + OptionNames::PbIndex)
-        .action("store_true")
-        .help("Generate a .pbi file for the OUTPUT file.");
-    parser.add_option(em + OptionNames::Zmws)
-        .help(
-            "Generate CCS for the provided comma-separated holenumber ranges only. Default = all");
-
-    ConsensusSettings::AddOptions(&parser);
-
-    parser.add_option(em + OptionNames::RichQVs)
-        .action("store_true")
-        .help("Emit dq, iq, and sq \"rich\" quality tracks. Default = false");
-    parser.add_option(em + OptionNames::ReportFile)
-        .set_default("ccs_report.txt")
-        .help("Where to write the results report. Default = %default");
-    parser.add_option("-M", em + OptionNames::ModelPath)
-        .help("Path to a model file or directory containing model files. Default = none");
-    parser.add_option("-m", em + OptionNames::ModelSpec)
-        .help("Name of chemistry or model to use, overriding default selection. Default = none");
-    parser.add_option(em + OptionNames::NumThreads)
-        .type("int")
-        .set_default(0)
-        .help("Number of threads to use, 0 means autodetection. Default = %default");
-    parser.add_option(em + OptionNames::LogFile).help("Log to a file, instead of STDERR.");
-    parser.add_option(em + OptionNames::LogLevel)
-        .choices(logLevels.begin(), logLevels.end())
-        .set_default("INFO")
-        .help("Set log level. Default = %default");
-
-    const auto options = parser.parse_args(argc, argv);
-    const auto files = parser.args();
-
-    const ConsensusSettings settings(options);
-
-    const bool richQVs = options.get(OptionNames::RichQVs);
-    const bool forceOutput = options.get(OptionNames::ForceOutput);
-    const bool pbIndex = options.get(OptionNames::PbIndex);
-    const size_t nThreads = ThreadCount(options.get(OptionNames::NumThreads));
-    const size_t chunkSize = 1;
+    // Get source args
+    const std::vector<std::string> files = args.PositionalArguments();
+
+    // input validation
+    if (files.size() != 2) {
+        std::cerr << "ERROR: Please provide the INPUT and OUTPUT files.\n"
+                  << "       See --help for more info about positional arguments." << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    const string inputFile = files.front();
+    string outputFile = files.back();
+
+    const ConsensusSettings settings(args);
 
     // handle --zmws
     //
     //
     optional<Whitelist> whitelist(none);
-    const string wlspec(options.get(OptionNames::Zmws));
+    const std::string& wlSpec = settings.WlSpec;
     try {
-        if (!wlspec.empty()) whitelist = Whitelist(wlspec);
+        if (!wlSpec.empty()) whitelist = Whitelist(wlSpec);
     } catch (...) {
-        parser.error("option --zmws: invalid specification: '" + wlspec + "'");
+        std::cerr << "option --zmws: invalid specification: '" + wlSpec + "'" << std::endl;
     }
 
-    // input validation
-    //
-    //
-    if (files.size() < 1)
-        parser.error("missing INPUT and OUTPUT");
-    else if (files.size() < 2)
-        parser.error("missing OUTPUT");
-    else if (files.size() > 2)
-        parser.error("too many arguments for INPUT and OUTPUT");
-
-    // pop first file off the list, is OUTPUT file
-    const string inputFile = files.front();
-    const string outputFile = files.back();
-
     // verify input file exists
-    if (!FileExists(inputFile)) parser.error("INPUT: file does not exist: '" + inputFile + "'");
+    if (!FileExists(inputFile))
+        std::cerr << "INPUT: file does not exist: '" + inputFile + "'" << std::endl;
 
     // verify output file does not already exist
-    if (FileExists(outputFile) && !forceOutput)
-        parser.error("OUTPUT: file already exists: '" + outputFile + "'");
+    if (FileExists(outputFile) && !settings.ForceOutput)
+        std::cerr << "OUTPUT: file already exists: '" + outputFile + "'" << std::endl;
 
     if (settings.ByStrand && settings.NoPolish)
-        parser.error("option --byStrand: incompatible with --noPolish");
+        std::cerr << "option --byStrand: incompatible with --noPolish" << std::endl;
 
     // logging
     //
     //
     ofstream logStream;
     {
-        string logLevel(options.get(OptionNames::LogLevel));
-        string logFile(options.get(OptionNames::LogFile));
+        const std::string& logLevel = settings.LogLevel;
+        const std::string& logFile = settings.LogFile;
 
         if (!logFile.empty()) {
             logStream.open(logFile);
@@ -464,7 +380,7 @@ int main(int argc, char** argv)
     //
     //
     {
-        string modelPath(options.get(OptionNames::ModelPath));
+        const std::string& modelPath = settings.ModelPath;
         if (!modelPath.empty()) {
             PBLOG_INFO << "Loading model parameters from: '" << modelPath << "'";
             if (!LoadModels(modelPath)) {
@@ -486,7 +402,7 @@ int main(int argc, char** argv)
     // test that all input chemistries are supported
     {
         set<string> used;
-        string modelSpec(options.get(OptionNames::ModelSpec));
+        const std::string& modelSpec = settings.ModelSpec;
         if (!modelSpec.empty()) {
             PBLOG_INFO << "Overriding model selection with: '" << modelSpec << "'";
             if (!(OverrideModel(modelSpec) && used.insert(modelSpec).second)) {
@@ -527,43 +443,52 @@ int main(int argc, char** argv)
     else
         query.reset(new PbiFilterQuery(filter, ds));
 
-    WorkQueue<Results> workQueue(nThreads);
+    WorkQueue<Results> workQueue(settings.NThreads);
     future<Results> writer;
 
+    // Check if output type is a dataset
     const string outputExt = FileExtension(outputFile);
-    if (outputExt == "bam") {
+    bool isXml = outputExt == "xml";
+    bool isBam = isXml || outputExt == "bam";
+
+    if (isXml) boost::ireplace_all(outputFile, ".consensusreadset.xml", ".bam");
+
+    if (isBam) {
         unique_ptr<BamWriter> ccsBam(
-            new BamWriter(outputFile, PrepareHeader(parser, argc, argv, ds)));
+            new BamWriter(outputFile, PrepareHeader(args.InputCommandLine(), ds)));
         const std::string pbiFileName = outputFile + ".pbi";
-        unique_ptr<PbiBuilder> ccsPbi(pbIndex ? new PbiBuilder(pbiFileName) : nullptr);
+        unique_ptr<PbiBuilder> ccsPbi(settings.PbIndex ? new PbiBuilder(pbiFileName) : nullptr);
         writer = async(launch::async, BamWriterThread, ref(workQueue), move(ccsBam), move(ccsPbi),
-                       richQVs);
-
-        // Prepare dataset
-        const std::string desc =
-            "Points to the ccs bam file generated by pbccs " + PacBio::UnanimityVersion();
-        const std::string name = "ccs bam";
-        const std::string metatype = "PacBio.DataSet.ConsensusReadSet";
-        DataSet ccsSet(DataSet::TypeEnum::CONSENSUS_READ);
-        ExternalResource resource(metatype, outputFile);
-        resource.Name(name).Description(desc);
-
-        if (pbIndex) {
-            FileIndex pbi("PacBio.Index.PacBioIndex", pbiFileName);
+                       settings.RichQVs);
+
+        // Always generate pbi file
+        FileIndex pbi("PacBio.Index.PacBioIndex", pbiFileName);
+
+        if (isXml) {
+            // Prepare dataset
+            const std::string desc =
+                "Points to the ccs bam file generated by pbccs " + PacBio::UnanimityVersion();
+            const std::string name = "ccs bam";
+            const std::string metatype = "PacBio.DataSet.ConsensusReadSet";
+            DataSet ccsSet(DataSet::TypeEnum::CONSENSUS_READ);
+            ExternalResource resource(metatype, outputFile);
+            resource.Name(name).Description(desc);
+
             resource.FileIndices().Add(pbi);
-        }
 
-        ccsSet.ExternalResources().Add(resource);
+            ccsSet.ExternalResources().Add(resource);
 
-        // File path without .bam suffix
-        const auto outputPrefix = outputFile.substr(0, outputFile.size() - 4);
-        // Save dataset
-        std::ofstream ccsOut(outputPrefix + ".consensusreadset.xml");
-        ccsSet.SaveToStream(ccsOut);
-    } else if (outputExt == "fastq" || outputExt == "fq")
+            // File path without .bam suffix
+            const auto outputPrefix = outputFile.substr(0, outputFile.size() - 4);
+            // Save dataset
+            std::ofstream ccsOut(outputPrefix + ".consensusreadset.xml");
+            ccsSet.SaveToStream(ccsOut);
+        }
+    } else if (outputExt == "fastq" || outputExt == "fq") {
         writer = async(launch::async, FastqWriterThread, ref(workQueue), ref(outputFile));
-    else
-        parser.error("OUTPUT: invalid file extension: '" + outputExt + "'");
+    } else {
+        std::cerr << "OUTPUT: invalid file extension: '" + outputExt + "'" << std::endl;
+    }
 
     unique_ptr<vector<Chunk>> chunk(new vector<Chunk>());
     map<string, shared_ptr<string>> movieNames;
@@ -579,7 +504,7 @@ int main(int argc, char** argv)
 
         // check if we've started a new ZMW
         if (!holeNumber || *holeNumber != read.HoleNumber()) {
-            if (chunk && chunk->size() >= chunkSize) {
+            if (chunk && chunk->size() >= settings.ChunkSize) {
                 workQueue.ProduceWith(CircularConsensus, move(chunk), settings);
                 chunk.reset(new vector<Chunk>());
             }
@@ -645,7 +570,7 @@ int main(int argc, char** argv)
     // wait for the writer thread and get the results counter
     //   then add in the snr/minPasses counts and write the report
     auto counts = writer.get();
-    const string reportFile(options.get(OptionNames::ReportFile));
+    const std::string& reportFile = settings.ReportFile;
 
     if (reportFile == "-")
         WriteResultsReport(cout, counts);
@@ -654,5 +579,14 @@ int main(int argc, char** argv)
         WriteResultsReport(stream, counts);
     }
 
-    return 0;
+    return EXIT_SUCCESS;
+}
+
+// Entry point
+int main(int argc, char* argv[])
+{
+    const auto version =
+        PacBio::UnanimityVersion() + " (commit " + PacBio::UnanimityGitSha1() + ")";
+    return PacBio::CLI::Run(argc, argv, ConsensusSettings::CreateCLI(DESCRIPTION, version),
+                            &Runner);
 }
diff --git a/include/pacbio/consensus/Polish.h b/src/matrix/BasicDenseMatrix.cpp
similarity index 67%
copy from include/pacbio/consensus/Polish.h
copy to src/matrix/BasicDenseMatrix.cpp
index 5eedc1a..9504ed5 100644
--- a/include/pacbio/consensus/Polish.h
+++ b/src/matrix/BasicDenseMatrix.cpp
@@ -33,44 +33,38 @@
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
-#pragma once
+// Author: David Alexander
 
-#include <tuple>
-#include <vector>
+#include "BasicDenseMatrix.h"
 
-#include <pacbio/consensus/Mutation.h>
-#include <pacbio/consensus/PolishResult.h>
+#include <stdexcept>
 
 namespace PacBio {
 namespace Consensus {
 
-// forward declaration
-class AbstractIntegrator;
-
-struct PolishConfig
+BasicDenseMatrix::BasicDenseMatrix(size_t rows, size_t cols)
+    : nCols_(cols), nRows_(rows), entries_(new double[nRows_ * nCols_])
 {
-    size_t MaximumIterations;
-    size_t MutationSeparation;
-    size_t MutationNeighborhood;
-
-    PolishConfig(size_t iterations = 40, size_t separation = 10, size_t neighborhood = 20);
-};
+}
 
-PolishResult Polish(AbstractIntegrator* ai, const PolishConfig& cfg);
+BasicDenseMatrix::~BasicDenseMatrix() { delete[] entries_; }
 
-struct QualityValues
+void BasicDenseMatrix::ToHostMatrix(double **mat, int *rows, int *cols) const
 {
-    std::vector<int> Qualities;
-    std::vector<int> DeletionQVs;
-    std::vector<int> InsertionQVs;
-    std::vector<int> SubstitutionQVs;
-};
-
-std::vector<int> ConsensusQualities(AbstractIntegrator& ai);
+    *mat = new double[Rows() * Columns()];
+    *rows = Rows();
+    *cols = Columns();
+    for (size_t i = 0; i < Rows(); i++) {
+        for (size_t j = 0; j < Columns(); j++) {
+            (*mat)[i * Columns() + j] = (*this)(i, j);
+        }
+    }
+}
 
-QualityValues ConsensusQVs(AbstractIntegrator& ai);
+size_t BasicDenseMatrix::UsedEntries() const { throw std::runtime_error("Unimplemented!"); }
 
-std::vector<Mutation> Mutations(const AbstractIntegrator& ai);
+float BasicDenseMatrix::UsedEntriesRatio() const { throw std::runtime_error("Unimplemented!"); }
 
-}  // namespace Consensus
-}  // namespace PacBio
+size_t BasicDenseMatrix::AllocatedEntries() const { throw std::runtime_error("Unimplemented!"); }
+}
+}
diff --git a/src/EvaluatorImpl.h b/src/matrix/BasicDenseMatrix.h
similarity index 56%
copy from src/EvaluatorImpl.h
copy to src/matrix/BasicDenseMatrix.h
index 28524d8..46f850d 100644
--- a/src/EvaluatorImpl.h
+++ b/src/matrix/BasicDenseMatrix.h
@@ -33,63 +33,59 @@
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
-#pragma once
-
-#include <memory>
-#include <utility>
-#include <vector>
+// Author: David Alexander
 
-#include <pacbio/consensus/Evaluator.h>
-#include <pacbio/consensus/Template.h>
-#include <pacbio/data/Read.h>
+#pragma once
 
-#include "Recursor.h"
-#include "matrix/ScaledMatrix.h"
+#include <cstddef>
+#include "pacbio/consensus/AbstractMatrix.h"
 
 namespace PacBio {
 namespace Consensus {
 
-class EvaluatorImpl
+//
+// BasicDenseMatrix is a *basic* dense matrix, for use as an
+// intermediate in matrix viewing operations (not in production code).
+//
+// It does not fully implement the interface that would be required to
+// drop it in as a replacement for ScaledMatrix in the production code
+// (i.e. for the recursor, etc.).  ConsensusCore did offer such a
+// matrix, "DenseMatrix", and we could consider resurrecting such a
+// class in the future.
+//
+class BasicDenseMatrix : public AbstractMatrix
 {
-public:
-    EvaluatorImpl(std::unique_ptr<AbstractTemplate>&& tpl, const PacBio::Data::MappedRead& mr,
-                  double scoreDiff = 12.5);
-
-    std::string ReadName() const;
-
-    double LL(const Mutation& mut);
-    double LL() const;
-
-    // TODO: Comments are nice!  Explain what this is about---ZScore calculation?
-    std::pair<double, double> NormalParameters() const;
-
-    double ZScore() const;
-
-    bool ApplyMutation(const Mutation& mut);
-    bool ApplyMutations(std::vector<Mutation>* muts);
-
-    int NumFlipFlops() const { return numFlipFlops_; }
-
-public:
-    const AbstractMatrix& Alpha() const;
-    const AbstractMatrix& Beta() const;
-
 private:
-    void Recalculate();
-
-private:
-    std::unique_ptr<AbstractRecursor>
-        recursor_;  // TODO: does this need to be a pointer?  is it always non-null?
-                    // are we making it a UP just so we can do a fwd decl and still have
-                    // RAII semantics?
-    ScaledMatrix alpha_;
-    ScaledMatrix beta_;
-    ScaledMatrix extendBuffer_;
+    size_t nCols_;
+    size_t nRows_;
+    double* entries_;
+
+public:  // structors
+    BasicDenseMatrix(size_t rows, size_t cols);
+    BasicDenseMatrix(const BasicDenseMatrix& other) = delete;
+    ~BasicDenseMatrix();
+
+public:  // Size information
+    size_t Rows() const;
+    size_t Columns() const;
+
+public:  // accessors
+    double& operator()(size_t i, size_t j) const;
+
+public:  // AbstractMatrix interface
+    void ToHostMatrix(double** mat, int* rows, int* cols) const;
+    size_t UsedEntries() const;
+    float UsedEntriesRatio() const;
+    size_t AllocatedEntries() const;
+};
 
-    int numFlipFlops_;
+inline size_t BasicDenseMatrix::Rows() const { return nRows_; }
 
-    friend class Evaluator;
-};
+inline size_t BasicDenseMatrix::Columns() const { return nCols_; }
 
-}  // namespace Consensus
-}  // namespace PacBio
+inline double& BasicDenseMatrix::operator()(size_t i, size_t j) const
+{
+    return entries_[i * Columns() + j];
+}
+}
+}
diff --git a/src/matrix/ScaledMatrix.h b/src/matrix/ScaledMatrix.h
index 2a37758..a3c872a 100644
--- a/src/matrix/ScaledMatrix.h
+++ b/src/matrix/ScaledMatrix.h
@@ -46,6 +46,8 @@
 namespace PacBio {
 namespace Consensus {
 
+/// This class inherits from SparseMatrix and extends it by having a
+/// column-wise scaling factor.
 class ScaledMatrix : public SparseMatrix
 {
 public:
@@ -56,27 +58,39 @@ public:
     };
 
 public:  // constructor/destructor
+    /// Constructor with explicit dimensions.
     ScaledMatrix(size_t rows, size_t cols, Direction dir);
+    /// Copy constructor.
     ScaledMatrix(const ScaledMatrix& other);
+    /// Destructor.
     ~ScaledMatrix(void) override = default;
 
 public:
+    /// Clears and resizes the internal data structures.
     void Reset(size_t rows, size_t cols) override;
+    /// Set direction and reset column-wise log scalars.
     Direction SetDirection(Direction dir);
 
 public:  // nullability
+    /// Returns a ScaledMatrix representing null.
     static const ScaledMatrix& Null();
 
 public:  // information about entries filled by column
+    /// Rescale column j by max_val.
+    /// If maxProvided is false, determine max_val.
     template <bool maxProvided>
     void FinishEditingColumn(size_t j, size_t usedBegin, size_t usedEnd, double max_val = 0.0);
 
 public:  // Scaling and normalization
+    /// Get the log scale for column j.
     double GetLogScale(size_t j) const;
+    /// Get the log scales from colum s to e
     double GetLogProdScales(size_t s, size_t e) const;
+    /// Get the log scale
     double GetLogProdScales() const;
 
 public:  // Convenient matrix access for SWIG
+    /// Convert sparse to full matrix.
     void ToHostMatrix(double** mat, int* rows, int* cols) const override;
 
 private:
diff --git a/src/matrix/SparseMatrix.h b/src/matrix/SparseMatrix.h
index cb9cf4d..02ab03e 100644
--- a/src/matrix/SparseMatrix.h
+++ b/src/matrix/SparseMatrix.h
@@ -49,18 +49,25 @@
 namespace PacBio {
 namespace Consensus {
 
+/// The SparseMatrix is based on a vector of SparseVectors.
 class SparseMatrix : public AbstractMatrix
 {
 public:  // Constructor, destructor
+    /// Constructor with explicit dimensions.
     SparseMatrix(size_t rows, size_t cols);
+    /// Copy constructor.
     SparseMatrix(const SparseMatrix& other);
+    /// Destructor.
     virtual ~SparseMatrix();
 
 public:
+    /// Clears and resizes the internal data structures.
     virtual void Reset(size_t rows, size_t cols);
 
 public:  // Nullability
+    /// Returns a SparseMatrix representing null.
     static const SparseMatrix& Null();
+    /// Returns if the both dimensions are zero.
     bool IsNull() const;
 
 public:  // Size information
@@ -68,22 +75,36 @@ public:  // Size information
     size_t Columns() const;
 
 public:  // Information about entries filled by column
+    /// Prepared the underlying SparseVector of column j
+    /// from rows hintBegin to hintEnd.
     void StartEditingColumn(size_t j, size_t hintBegin, size_t hintEnd);
+    /// Finish editing column j and store the used rows in usedRanges_.
     void FinishEditingColumn(size_t j, size_t usedBegin, size_t usedEnd);
+    /// Retreive the row range for column j.
     std::pair<size_t, size_t> UsedRowRange(size_t j) const;
+    // Checks if no rows are set for column j.
     bool IsColumnEmpty(size_t j) const;
+    /// Computes the number of filled cells.
     size_t UsedEntries() const override;
+    /// Computes the ratio of filled cells.
     float UsedEntriesRatio() const override;
-    size_t AllocatedEntries() const override;  // an entry may be allocated but not used
+    /// Computes the number of allocated cells.
+    /// An entry may be allocated but not used.
+    size_t AllocatedEntries() const override;
 
 public:  // Accessors
+    /// Access cell at row i and column j.
+    /// If not allocated, return 0.
     const double& operator()(size_t i, size_t j) const;
+    /// Checks if cell is allocated.
     bool IsAllocated(size_t i, size_t j) const;
     double Get(size_t i, size_t j) const;
     void Set(size_t i, size_t j, double v);
+    /// Clear content of column j and reset respective row range.
     void ClearColumn(size_t j);
 
 public:
+    /// Convert sparse to full matrix.
     void ToHostMatrix(double** mat, int* rows, int* cols) const override;
 
 private:
diff --git a/src/poa/PoaGraph.cpp b/src/poa/PoaGraph.cpp
index 7e7abcc..c663fd3 100644
--- a/src/poa/PoaGraph.cpp
+++ b/src/poa/PoaGraph.cpp
@@ -91,6 +91,11 @@ void PoaGraph::WriteGraphVizFile(const string& filename, int flags, const PoaCon
     impl->WriteGraphVizFile(filename, flags, pc);
 }
 
+void PoaGraph::WriteGraphCsvFile(const string& filename) const
+{
+    impl->WriteGraphCsvFile(filename);
+}
+
 PoaGraph::PoaGraph() { impl = new detail::PoaGraphImpl(); }
 
 PoaGraph::PoaGraph(const PoaGraph& other) { impl = new detail::PoaGraphImpl(*other.impl); }
diff --git a/src/poa/PoaGraphImpl.cpp b/src/poa/PoaGraphImpl.cpp
index 9a7d68c..789e1ec 100644
--- a/src/poa/PoaGraphImpl.cpp
+++ b/src/poa/PoaGraphImpl.cpp
@@ -448,6 +448,23 @@ void PoaGraphImpl::WriteGraphVizFile(const string& filename, int flags,
     outfile.close();
 }
 
+void PoaGraphImpl::WriteGraphCsvFile(const string& filename) const
+{
+    std::ofstream outfile(filename.c_str());
+
+    std::list<VD> sortedVertices(num_vertices(g_));
+    topological_sort(g_, sortedVertices.rbegin());
+
+    outfile << "Id,Base,Reads,SpanningReads,Score,ReachingScore" << std::endl;
+    for (const VD v : sortedVertices) {
+        PoaNode& vi = vertexInfoMap_[v];
+        outfile << vi.Id << "," << vi.Base << "," << vi.Reads << "," << vi.SpanningReads << ","
+                << vi.Score << "," << vi.ReachingScore << std::endl;
+    }
+
+    outfile.close();
+}
+
 }  // namespace detail
 }  // namespace Poa
 }  // namespace PacBio
diff --git a/src/poa/PoaGraphImpl.h b/src/poa/PoaGraphImpl.h
index 00a73d1..93e6d5b 100644
--- a/src/poa/PoaGraphImpl.h
+++ b/src/poa/PoaGraphImpl.h
@@ -256,6 +256,7 @@ public:
     size_t NumReads() const;
     string ToGraphViz(int flags, const PoaConsensus* pc) const;
     void WriteGraphVizFile(const string& filename, int flags, const PoaConsensus* pc) const;
+    void WriteGraphCsvFile(const string& filename) const;
 };
 
 // free functions, we should put these all in traversals
diff --git a/swig/Matrix.i b/swig/Matrix.i
index 6ff6c94..ef854e8 100644
--- a/swig/Matrix.i
+++ b/swig/Matrix.i
@@ -1,6 +1,7 @@
 %{
 /* Includes the header in the wrapper code */
 #include <pacbio/consensus/AbstractMatrix.h>
+#include <pacbio/consensus/MatrixViewConvention.h>
 %}
 
 #ifdef SWIGPYTHON
@@ -10,3 +11,4 @@
 #endif // SWIGPYTHON
 
 %include <pacbio/consensus/AbstractMatrix.h>
+%include <pacbio/consensus/MatrixViewConvention.h>
diff --git a/swig/Mutation.i b/swig/Mutation.i
index 92754da..ca10f04 100644
--- a/swig/Mutation.i
+++ b/swig/Mutation.i
@@ -7,3 +7,13 @@ py_tp_str(PacBio::Consensus::Mutation);
 py_tp_str(PacBio::Consensus::ScoredMutation);
 
 %include <pacbio/consensus/Mutation.h>
+
+namespace std {
+    %ignore vector<PacBio::Consensus::Mutation>::vector(size_type);
+    %ignore vector<PacBio::Consensus::Mutation>::resize;
+    %template(MutationVector) vector<PacBio::Consensus::Mutation>;
+
+    %ignore vector<PacBio::Consensus::ScoredMutation>::vector(size_type);
+    %ignore vector<PacBio::Consensus::ScoredMutation>::resize;
+    %template(ScoredMutationVector) vector<PacBio::Consensus::ScoredMutation>;
+ }
diff --git a/swig/State.i b/swig/State.i
index 161788e..948603f 100644
--- a/swig/State.i
+++ b/swig/State.i
@@ -3,4 +3,8 @@
 #include <pacbio/data/State.h>
 %}
 
-%include <pacbio/data/State.h>
\ No newline at end of file
+%include <pacbio/data/State.h>
+
+namespace std {
+    %template(StateVector) vector<PacBio::Data::State>;
+}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 605ff2b..9816257 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -29,7 +29,6 @@ include_directories(SYSTEM
     ${ZLIB_INCLUDE_DIRS}
     ${HTSLIB_INCLUDE_DIRS}
     ${UNY_ThirdPartyDir}/seqan/include
-    ${CPPOPTPARSE_IncludeDir}
     unit/
     ${PacBioBAM_INCLUDE_DIRS}
 )
diff --git a/tests/cram/100zmws.t b/tests/cram/100zmws.t
index 77a8634..4727181 100644
--- a/tests/cram/100zmws.t
+++ b/tests/cram/100zmws.t
@@ -1,11 +1,12 @@
 
 Test ccs on 100 zmws from the lexogen-SIRV dataset
 
-  $ $__PBTEST_CCS_EXE --logLevel=DEBUG --minZScore -100 --maxDropFrac 0.8 $TESTDIR/../data/100zmws.bam test.fq
+  $ $__PBTEST_CCS_EXE --logLevel=DEBUG --minZScore -100 --maxDropFraction 0.8 $TESTDIR/../data/100zmws.bam test.fq
   >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- main -|- [0-9,a-f,x]+|| -|- Found consensus models for: (P6-C4, S/P1-C1) (re)
   >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- main -|- [0-9,a-f,x]+|| -|- Using consensus models for: (P6-C4) (re)
-  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- Consensus -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/413/9570_12297, ALPHA/BETA MISMATCH (re)
-  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- Consensus -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2359/6103_8488, ALPHA/BETA MISMATCH (re)
+  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- operator() -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/413/9570_12297, ALPHA/BETA MISMATCH (re)
+  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- operator() -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/429/4100_6514, ALPHA/BETA MISMATCH (re)
+  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- operator() -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2359/6103_8488, ALPHA/BETA MISMATCH (re)
   $ grep -c ^@ test.fq
   100
   $ cat test.fq
@@ -33,10 +34,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset
   AAGCAGTGGTATCAACGCAGAGTACGGGGATTGGATTAAAAAAGTTGTAGTAAACCACAACGAAGTTAGGTAGCTGGTAAGGTTATAGATGCGTTCTGTCGTTGTAGTCCCAATGAACATAGTATGGTTTCGCATAGTAACTGACCTAAAAGACCGCCACATAGTGAAAATACTTAAAACGCAAGTTTCATAGGATTAAGTGGTAGAGGCTATAGAAAATGATATCATAACTATAACGAATATAACAGCAAATTAAAATGCACTGGAAGTGGAAAATTTCAGCAAGAGAGTCGAAGTCGTCATAGATTAGCATGGACGAAAGAAAAGTCGCAAAGATCGGAAATCAAGACGCAAAACAAAACGGAGAAGTTCAAATCGAACTCGTAGAACATATCGCTGGAACATATTAAACTCTTGGTATCGCTCAGTTACAAAAGGAGACACGTAGACACGAAAGAAACTGGAACAACAGACATATTTGTGGATAATG [...]
   +
   ~~~~~~~b~~~~~~~sxw~~~b~~~T~~~~~~p~~~~D~~~~~~h~~~~t~\~~_~~u~~~~~~tx~~~~~~~~~q~~~~u~~~~~~~~~~~~~~~~~~~~q~~~d~~Y~~~~~~|~X~~~~^x~r~~~~~xy}~~~~]~~~r~m~~R~~~~~o~~X~}~zw~~~uX~~~~~~~~^~~~u~~~~~~~~~~~~v~~~~~~~~r~~~~~a~~~~~~z^~~~~~~~~~~~~~~~~~~o~~~z~~~~~~~~~~|~~~~]~~~~~~~~~x~~~~~p~c~~~o~~~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~k~~~~~~~e~~~~~~~~~~~~u~~~~~~b~~~~~~~~~~v~~e~~~~b~~~~~~~|~~~z~~`~~~~zA~~~~O~~~~~~~~~~~~~~p~~~~~~~~~l~~~~~~~h~~~~~~c~~~~i~~}t~~~q~~~~|~~~~~~~~~~~S~~~Y~~~~~~~~S~~~~~~~~~~_~~~~~~~~~~~~ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/418/ccs np:i:10 rq:f:0.999163
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTGATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCTAGTCCCGGACTCACCGAACCTACACCGTTCCCTTCAGTGTGTTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTTGTGGGCTAGGGCACCGCGTTTTGAAGTAAATAGATGTAACCTACCACCCATAAACTGCTCTAAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGACGAATTTACGGTGGTAATTTCGCACACTTCGCACGTTT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/418/ccs np:i:10 rq:f:0.998932
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTGATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCTAGTCCCGGACTCACCGAACCTACACCGTTCCCTTCAGTGTGTTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTTGTGGGCTAGGGCACCGCGTTTTGAAGTAAATAGATGTAACCTACCACCCATAAACTGCTCTAAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGACGAATTTACGGTGGTAATTTCGCACACTTCGCACGTTT [...]
   +
-  I~~}~~tX~~~~jf~|~k~|~~O~q'~~~~~~~~~~~~~~~~~~~~~~~~~idrv~c{mjY~h~~we}~dF~b~~i~@~x~~T~~~~~~m~~~tT~~~m~K~~I~`x~n~Y~~o~]~~~m~Y~~X~&~[[~~~q~~~l'~~~Z~ifN~dH~~~~~E~~~~~t~{~T~~~X~M~~i~z~~~m~~~d~}~z|k~~~MeH~~l~~Q~~~~~~~~;~wa~V~~@~~j~J~~~qq\~~~n~~~~~d~|~U~~~~~W~~y~T~ym~F~~~}c~j~^~~}~~~~pNV~Y~ob[~kV~~^q@~~~~~]~sX%Mk~~~%~oAmW[~zp~pdf~~:VYsW@}~~~f~~e}~~~k~l~n~n~i~f~L~\~~~~~~{O~~Z~S~~k~~~~~~~}~~~~X~~itbX~QU~wS~~j~j~~f~f|h~ukpii~b`g~~tphY~j~~bTp~~~~t~~k~~p~o~rn~~~s_~^~~ImU~rk~~_~i~~~^~n\h~f~qnoi]rE~~ [...]
+  I~~}~~tX~~~~jf~|~k~|~~O~q'~~~~~~~~~~~~~~~~~~~~~~~~~idrv~c{mjY~h~~we}~dF~b~~i~@~x~~T~~~~~~m~~~tT~~~m~K~~I~`x~n~Y~~o~]~~~m~Y~~X~&~[[~~~q~~~l'~~~Z~ifN~dH~~~~~E~~~~~t~{~T~~~X~M~~i~z~~~m~~~d~}~z|k~~~MeH~~l~~Q~~~~~~~~;~wa~V~~@~~j~J~~~qq\~~~n~~~~~d~|~U~~~~~W~~y~T~ym~F~~~}c~j~^~~}~~~~pNV~Y~ob[~kV~~^q@~~~~~]~sX%Mk~~~%~oAmW[~zp~pdf~~:VYsW@}~~~f~~e}~~~k~l~n~n~i~f~L~\~~~~~~{O~~Z~S~~k~~~~~~~}~~~~X~~itbX~QU~wS~~j~j~~f~f|h~ukpii~b`g~~tphY~j~~bTp~~~~t~~k~~p~o~rn~~~s_~^~~ImU~rk~~_~i~~~^~n\h~f~qnoi]rE~~ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/420/ccs np:i:20 rq:f:0.999865
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGGTAAAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCT [...]
   +
@@ -45,10 +46,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset
   AAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACTA [...]
   +
   i~~d~~~b~~~[~}~~Vizw~~~~~M~~~~e~b~~~~~}F~~t~~v~D~~i~~~~zi~~s~r~~~H~~~~~~~~~~2~~~~~~~~f~r~o~~~~i~~~~~u~~u~~~~~~~~~~~b~~uuuz~~~U~~~~~~k~~~~~~s~~~~~~~~y~~m~~~~|r~~~~~~~~~~~~~x~~w~z~~~~~~~}~~uj~~j~~~z~~~\~~~~~~~~~~~~~X~~c~]~9~~~g~~~~~~~~~~~rj~~~~uv]~~~~~~~~~~~~~~~m~v~~~v~~~~~~~R~V~~akn~~w~~w^~~~~~~~~z~\~~~n~~~~~~~~~}~~~~~~~~b~~~~h~~~~Y~~~~~l~~y~~~~~~~~~~~ym~~~~~~}~~~}~~i}~~~~~p~x~~~~~~~~~~~t~~~~w~~nr~~~k~~~~~~z~~~v~~~~~uW~w~~~~~~~~~w~~{~~hW~^~~c~c~H~W}~~~~x~w~~r~~~~~p~~~j~|~~~~y~~M~~~m~~~~ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/429/ccs np:i:10 rq:f:0.999251
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAAT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/429/ccs np:i:10 rq:f:0.9993
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAAT [...]
   +
-  {~~~~~~o~~~~mk~n~~~yn~~~~b~~~~~z~~~~d^~~~{X~z~~~||z{~~o~z~~k~~~~|~~z~~~k~~~~~rQ~~~~]~~~~~~~~~o~~~~~~~U~l~Q~~~~|~~H~~~~~~]~~o~~~~~~~z~u~~~~~^~~}r~~~[~~~m~~U~~x~~~~~u~~~~~~~~~n~~~~~~~]~~~~~F~~~~l~~~~}~\~~x~X~~~~~~~e~o~~~~~~)~~~~~~g~{~D~~~~eW~~~~~~~~~~~~~~~~}~~~{~~~r~~z~{~m~v~~~~~y~`L~~w~~~_~~~~~~d~~~~~~x~C~~~~~~~J~j~v~~~~{~~~~~~j~~~d~~~~~n~~~~~v~~~j~~l~~~~r~~~\~~~p~~~~~~\~~~~~~N{lcm~o~~~o~~~~~~~~~f~~~~~|~~~c~~~~Z~zLy~~~~~~~~~~~]~w~~~~~~~D~~~~~~~~~m~~~~~~q~~y~~~|~~~~~w~~{~~~~~~~~~~~nuqz~~ [...]
+  n~~}~~~d~~~~`r~ww~~on~~~~X~~~~~v~~~~dN~~~lP~s~~~p~ps~~q~m~~b~u~~q~~v~~~a~~w~~mV~~v~V~~~~~~u~~c~~~~~~~Q~q~E~~~~o~u:~~~~~~O~~a~~~~~~{s~s~~~~sP~~~r~~~c~~~a~~L~~~~~~~sp~w~~~w~~~d~~~~~~~f~~~~~F~~~~a~~~~qoS~~o~Q~~~~~~~_~f~~~u~~/~~~~~~a~o~7~~~~nO~~~r~~~u~~~~~~~u~~~~p~~~l~~p~q~p~u~~~}}~~fP~~v~~~f~~~~~~W~~v~~~l~7~~~~~w~=~]~q~~~{p~~~~~~c~~va~t~~~a~~~~~p~~~j~~^~~u~f~~~Q~~~m~r~~~~N~~~~~|Gqtlazr~{~d~~~~~t~~~^~~~~~p~u~W~~~~a~~Nm~~~~~~~~~z~Q~q~~~~~~~H~~~~tr~~xc~~psu~e~~r~~s~~~~v~g~y~~~~q~~~~~~~crbv~~ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/456/ccs np:i:17 rq:f:0.999773
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGGTAACTATCTTAAAAACTTCTAAACTGCTGCTTAGTAGGCAATAATCGACTAAATCCATAATTTTTGCGACCAAACGCAAACTTCAAGAATTTTAGACTTTGAAGACCGCATCGGCAAACCCCATTTTAGATACCACTTTAATTTCCAGTTAATCTACGACGCAAGTCACTTCTTTGTCGTTAAGTTTTATTTAACTGTCGCAAACAACAAAATGGTTTTCTAAATTTACTAAAACCAGGACGCACCTAACTTTCTAAACAAGCACAAGTTTAGCTTCTTCGTAAACGTCACCGCGAACTTTGACGCAAGAATTTTCCATGACCATTTCTGGTTGGTTAGCCGAATTTGGCAGTTCATGTTTTTCCACATAGCCATTGACTCCCACGAATAGGTCTCTTTCTTCTTGTTCCATGCGAATGTAAACGATTAGGCG [...]
   +
@@ -229,10 +230,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTCGCCACGTCTCCTTAGATAACTGGCAAATCTTCACAATTACGCAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTGCACTCCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAATAGCCATTCTTCCTGAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGAGTGCGAAGCCACTAGGTTTGCACTGTTGACCACCAGCACGCAATCGCAAGATACGCAGTAATGCTAAACCATACTTATTTGACTTTGATGTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGCTACACATATGCTGTTGGGAATGTTTTTTACACTTATTATG [...]
   +
   ~~~~~~~N~~~~~~~~~~~~~~~~~*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s~~~~~~~~~~~~~~~~{v~~~~~~~~~~~~~~~\~~~~~~~~~~~~~~~~~~~~~Y~k~e~~~~~~~~~~~~~~~~~~~x~~j~~~]~~~r~~~~~~~~~~~~~~~~~~x~~~~~x~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~V~~~~~~~~~~~~~~~~~~~s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~m~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~f~~z~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]~~~~~~~~~~~~~~~~~ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1999/ccs np:i:10 rq:f:0.999526
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATTGACCCAAATAATAAACTCGTTCCAATAGTTGAAGTGTTGATTAACACATTGAGACAAGTTGTCCGTACTTTAATCATCAAAGTTTTGGACTGACCTATAAATGAAATATTCGCGTTGTCTTCAGTTTAAGAAGTGATATTATTTTCGGTTTCAAGCCTATGTGGAGAGATACAGGAAATAGGTAAACTATAACTAATATAAATATACGCAGACGAAGCCTGTTAACTTTACCAAATCCAAATAGCGGGAGAC [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1999/ccs np:i:10 rq:f:0.999415
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATTGACCCAAATAATAAACTCGTTCCAATAGTTGAAGTGTTGATTAACACATTGAGACAAGTTGTCCGTACTTTAATCATCAAAGTTTTGGACTGACCTATAAATGAAATATTCGCGTTGTCTTCAGTTTAAGAAGTGATATTATTTTCGGTTTCAAGCCTATGTGGAGAGATACAGGAAATAGGTAAACTATAACTAATATAAATATACGCAGACGAAGCCTGTTAACTTTACCAAATCCAAATAGCGGGAGAC [...]
   +
-  r~~~~~~`~~~~~~~~~s~~~~~~~d~~~~m~~~~d~~~~~~~~v~~~~~~~~ji~~~~~~q~e~2~~r~~~Y~~~~~~~~~~~~~~~h~~~~U~~~~~|~~~~~~~\~~~~~~|~~_~~~~~~r~~~P~~~~~G~~~~~~~~v~~~k~~~~~~~~_~~~~~~~y~~~ov~~~y~h~v~~~j~~~~~~~m~~~~~~~a~~~~~~~u~u~~~~~U~~~~~~~~~j~~~~~~~~M~~~~~~~`~~f~~~~~ce~~q~~~~~`~~~~~~b~|\~~~lt~~~}~_~~~~~t~~~~~~j~p~~f~~~~~~~R~~~~~~~Z~q~~~F~~~o~~~~~~j~~~~W~~~~k~~~p~~v~~~U~~~~U~~~~W~~p~~j~~p~~~~n~~@~~~~|~h~~~s~~~~~k~~~f~|G~w~~~n~`~A~~~~~~~U~~~|~~~~~~~~~~~{~~~~~~~s~~~~~~~~~o~~[^~~~~s~~~~~p~~~z~l~~~~~~P~~~~~~ [...]
+  r~~~~~~`~~~~~~~~~s~~~~~~~d~~~~m~~~~d~~~~~~~~v~~~~~~~~ji~~~~~~q~e~2~~r~~~Y~~~~~~~~~~~~~~~h~~~~U~~~~~|~~~~~~~\~~~~~~|~~_~~~~~~r~~~P~~~~~G~~~~~~~~v~~~k~~~~~~~~_~~~~~~~y~~~ov~~~y~h~v~~~j~~~~~~~m~~~~~~~a~~~~~~~u~u~~~~~U~~~~~~~~~j~~~~~~~~M~~~~~~~`~~f~~~~~ce~~q~~~~~`~~~~~~b~|\~~~lt~~~}~_~~~~~t~~~~~~j~p~~f~~~~~~~R~~~~~~~Z~q~~~F~~~o~~~~~~j~~~~W~~~~k~~~p~~v~~~U~~~~U~~~~W~~p~~j~~p~~~~n~~@~~~~|~h~~~s~~~~~k~~~f~|G~w~~~n~`~A~~~~~~~U~~~|~~~~~~~~~~~{~~~~~~~s~~~~~~~~~o~~[^~~~~s~~~~~p~~~z~l~~~~~~P~~~~~~ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2012/ccs np:i:11 rq:f:0.999194
   AAGCAGTGGTATCAACGCAGAGTACGGGGCTTGTCCGCGAGTGTCAACCGGGTTTTACAAAGGAGAACTTCCAACATCAGTGTATGGGATGTTTCAAACACCCCCAGAGACGGAGACAATAGTGTGGTCACGTACATTTAGGAAGATAAAAATAACAACAACAGAAGGTGTGAGGCGCAAGGTACATGCTCTTACCCCACTCTCAGCACGTAGGGAGCGGAGTGTGGAAGACCAACAAGCCCGTCGCCTCTACCAAATACAGCTATCCTGAGGTGCCAGGTTAGAATAGGCCCTACCACATCTAAGCCTTGAAACGGTCTGTTCCTCGTGTCAAGTTCTTGTCCGCTTATACCGCCATCTCTCGTTGTGGTACAAGAGTTGGTTACTCTCAGTCCCATTCCCAACACATCACTGAGAAGTATAGAGCCTAGTGGTCATTAGAAGGTCAACATGGAGTAGGTGTTTAGGTGTGTCGGAGGGCAGAAACCAA [...]
   +
diff --git a/tests/cram/100zmws_byStrand.t b/tests/cram/100zmws_byStrand.t
index 680d151..81f8f5f 100644
--- a/tests/cram/100zmws_byStrand.t
+++ b/tests/cram/100zmws_byStrand.t
@@ -1,11 +1,12 @@
 
 Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
 
-  $ $__PBTEST_CCS_EXE --logLevel=DEBUG --minZScore -100 --maxDropFrac 0.8 --byStrand $TESTDIR/../data/100zmws.bam test.fq
+  $ $__PBTEST_CCS_EXE --logLevel=DEBUG --minZScore -100 --maxDropFraction 0.8 --byStrand $TESTDIR/../data/100zmws.bam test.fq
   >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- main -|- [0-9,a-f,x]+|| -|- Found consensus models for: (P6-C4, S/P1-C1) (re)
   >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- main -|- [0-9,a-f,x]+|| -|- Using consensus models for: (P6-C4) (re)
   >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- Consensus -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/413/9570_12297, ALPHA/BETA MISMATCH (re)
-  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- Consensus -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2359/6103_8488, ALPHA/BETA MISMATCH (re)
+  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- operator() -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/429/4100_6514, ALPHA/BETA MISMATCH (re)
+  >|> \d{8} \d{2}:\d{2}:\d{2}\.\d{3} -|- DEBUG      -|- operator() -|- [0-9,a-f,x]+|| -|- Skipping read m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2359/6103_8488, ALPHA/BETA MISMATCH (re)
 
   $ grep -c ^+$ test.fq
   200
@@ -87,10 +88,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAAACAGCAATAATTGTAGAAGGTAGCAATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGAC [...]
   +
   H|_GO;,R}fcL+C`AJV`[P`ePWA|||V|QoO`^a=amKH*y`WgfXbfR}fR{Pe`DwA`aR{fgaW`FzV`OT:HofA\@eyffffWaU4tL[[gff)`0D5~|efGfJ&wwYUM_VFxdG^WzagfaW}R}ff`B,d`ecDN^\H~af`P_9}eOVgfUIG|`fJWA`fa6~]K`Y}aE~|a_a$xx`adJdfadJe2|H;C:pfrUPed6|<t`bR~c3fjgVW|Jb<M/YDXePO|}dAdW|HU`fWfaa?MVe`E{eaJTf^hQ}fMP~W}abbbHAzVacR`agWK~ae6~vTjWbMJ0Zbc`dA^4_7jP]fcFR|fW}^IIznAFyVfbY at zfaa`fOhN:U_3w^@NO||U:vc]O{RmUQ`9~eafTQ'?^OEO8O_N<~f`YOVea`;L``eWcXW{:ljm`=emIDz_NUPeagfae>yDz]\VRSR2__vO?8W|_2jF6@`e:~e at vaWKzW_Aea\aT|TaY}faY}_OK>D [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/429/ccs/rev np:i:5 rq:f:0.992297
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTGACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAAT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/429/ccs/rev np:i:5 rq:f:0.991542
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAATG [...]
   +
-  IhWbcRV>rdg\cH}NWT^>@W_\_+Vg[MjFtbV]&?imXQO_9bhfF;4Hhh<z at _KH{cdQB^H5SMYGgZDbcY$PcdY>q\WeUbKXc[xhFaRWWMyVd<TbRXUlY'kabcYa8h?:jVyWchG9X*TSeZdhUN>QISO4tUL.?G3}g)QaPgbWQsCQiYdWRUB}yiZNlY9aYHMHGzzZYDdaY[T73h_^]6op_PUUQP]9hhhLqc2kw]Rp>OJW6hjk\7*ZnXPZM`ZcZUdiYicRbQUQndSHiY<>GC)aDgOWHI8/8-^Y6QNA]49ZmQXMolHpaGKJ4gDfIXQK7tSiGTYacJi<TkPU=Shb at kLU@WMlgA^Z1K_FP*KUqP`\ClgbClp`@`Hlbc^DpdTT]PI\.5IWXgGLSwQRNOKVN`LTeIU^9YBdGgggd3\.&RmT``^CVEcEC?ZIsNS\hjb2~og``i:TEYsXjbA`GlaT}RKC`AS_L7]DGz]WFOhZSgY^DYNQwQ [...]
+  FiMW[NY3oY[[WOmWNWX4?K[[R0MZWMkCpZNV&2dgXBFU4U[X:B+AdZ>f5TM?lVYB at jO0IPM<kT8YWT+R`VM7lfWXXV?LVOm[KSIWIGiJi0OeY[JmM/laV[NU+i.+iMlN[Z;1O/OFYNWZXA at QPXN<fJQ%GK2c5/UDYVKId8BXNWMBL8kkZNNmLA``DUKEhhNY8YZMQH,6UkUZ7mmkVZ[[Jm?nmZApY'jjUMf8WPZ*jjjh?$edMLOHONWN[W[N[W[WYKJk[ZAkO3@@N+VBkHS><?:?0RS5XT>'1>OmN[Amk<jUF at R)hN[KSUM*iHkBL[[V?m at NmNZ:WjV<k?XDLAmkAVX,ITLQ)IKlNWZ8kkU8llY=R<jV[Y6iYN[ZMBS7>=L[Z=WIlDYOV?YOZDZX=VR.S=\<lmm[;[<'JiIYRPCLDT:O5XLlLPWY[S2ll`QV[BS:NlN[T5OHm[IlB>Hc1NV@(S8NkWM9SZNNmMU9U?JnY6 [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/456/ccs/fwd np:i:8 rq:f:0.999079
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGGTAACTATCTTAAAAACTTCTAAACTGCTGCTTAGTAGGCAATAATCGACTAAATCCATAATTTTTGCGACCAAACGCAAACTTCAAGAATTTTAGACTTTGAAGACCGCATCGGCAAACCCCATTTTAGATACCACTTTAATTTCCAGTTAATCTACGACGCAAGTCACTTCTTTGTCGTTAAGTTTTATTTAACTGTCGCAAACAACAAAATGGTTTTCTAAATTTACTAAAACCAGGACGCACCTAACTTTCTAAACAAGCACAAGTTTAGCTTCTTCGTAAACGTCACCGCGAACTTTGACGCAAGAATTTTCCATGACCATTTCTGGTTGGTTAGCCGAATTTGGCAGTTCATGTTTTTCCACATAGCCATTGACTCCCACGAATAGGTCTCTTTCTTCTTGTTCCATGCGAATGTAAACGATTAGGC [...]
   +
@@ -143,10 +144,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACTA [...]
   +
   v~|KTskS~~y~`OvMPLi}h{}{d4~~m^U~B~~~}maX~~<~~w~Z~h0~~cc{@~}P~|~]UE~~~bf{c~~~'~~~PN~~bQ~i~h~h~mL~i~a~g~sJxP~xUxA~~^~J~~~OuB~~\(n~~Nd~7~yL~N~9FryQ|X~{z~xm{cyy_Xz~\gtz~krvbk~^s_~bj*~~O_g~W~zvCzmNz~~~~~~c~~~|bimb~igL}I~uJ~h}2~~{T~`cc~dWyjm]|N~y|~zcIl~~b~~b~~~la~\|y_bz~\N~}[}d~Q|~A~|afO~fOs~~T~Tp]yx}~~~8~zyK~Y~nbif~OY~~~b}aeMV|{~PC{~b}.~~}uee~~g~cu~y~i~M\~~M~~g~c~c~~b~~~|M|hk~bkzJ~~aYd~~~~SqL~~~`~~~~i~~}@z~wnCgU~~d_~a~~~~P~b~~e~~~~~9|~~=~f^\~2~~e~ez]{xz~d~cd~O~~g~y~j`?~~~h{QL~_jMwgO~~;i~e~h [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/705/ccs/rev np:i:9 rq:f:0.997386
-  AAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACTA [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/705/ccs/rev np:i:9 rq:f:0.997074
+  AAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACTA [...]
   +
-  X~HL~<[:vd~wS[Y<Ze~_~N{~i3cgviZ~K~~u;hiE~~`t~gw3~w8v~_g`h~Oh~k~ey.^$ST~QhOb=-_df}b)zgo~RpMk%|vh~cxvwO~y`aT~~_~~vd~~F~~Wffh~mz8~~si\~h~dz}coYx~_~c~~b`vcX~C~~~U~~|~^U|`t6LMkU~~~bk\~~P|}~:~RJY~~p~~^z}9~~l`~a~`hi~_kfOQ~~M~~aFz~~yuU]~~~q~c~{Rf~~GTa~M~~{qOxi~~x~e:dQ~iM~gu[~~b~e]d`~f~~c`X~~g|]]z}|gj~wa}~`L~g~i~l~~}^Jx(SAw{|<cwfWzb~~8~B{aI~~~^Q@~b'~b~kWr\a|c~\-~{rzg`N|vMU~M~S~N~\j~bN~{byWa~ad~LRwbZpJeP[EzsRBk{~mY\Q~~~ia}g~ZOY~~~gxc>L~uqGFLY|RkBdGXT~zQ~|g~L~bg~>~[~sQ~~BM{}~P~]PK|Xhbi~{N~~|~~hf~ [...]
+  X~HL~<[:vd~wS[Y<Ze~_~N{~i3cgviZ~K~~u;hiE~~`t~gw3~w8v~_g`h~Oh~k~ey.^$ST~QhOb=-_df}b)zgo~RpMk%|vh~cxvwO~y`aT~~_~~vd~~F~~Wffh~mz8~~si\~h~dz}coYx~_~c~~b`vcX~C~~~U~~|~^U|`t6LMkU~~~bk\~~P|}~:~RJY~~p~~^z}9~~l`~a~`hi~_kfOQ~~M~~aFz~~yuU]~~~q~c~{Rf~~GTa~M~~{qOxi~~x~e:dQ~iM~gu[~~b~e]d`~f~~c`X~~g|]]z}|gj~wa}~`L~g~i~l~~}^Jx(SAw{|<cwfWzb~~8~B{aI~~~^Q@~b'~b~kWr\a|c~\-~{rzg`N|vMU~M~S~N~\j~bN~{byWa~ad~LRwbZpJeP[EzsRBk{~mY\Q~~~ia}g~ZOY~~~gxc>L~uqGFLY|RkBdGXT~zQ~|g~L~bg~>~[~sQ~~BM{}~P~]PK|Xhbi~{N~~|~~hf~ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/734/ccs/fwd np:i:12 rq:f:0.998898
   AAGCAGTGGTATCAACGCAGAGTACGGGGTGCTCGCCATTTCAACTAGTGCAGTTGCTAAAGTGCCAACTAAGGTTCGTCTTGAAGCAATCGGTAGTATCTGCAGTCAAGTCGTAGTCGTAGGTATGGCACTTGTCGTGCGTCTAGGACGCGTTGAAGCTATCTTATTGCCCGAAGGAGCCGAAAGTCTGGGACACGTCGTGGGACGTATCGTTAGGACTATGGGACTAGTCGTCTTCGGTCTTACAAATGTTGCAATGCCCTGTGAGCTACTTATGAAACATGAATGGTCGGTCTTGTGGTCGCTTTTGTCGAAATCACCGAAGTGCGTATAATTGATGAACGAGTCGAAGTCGAAGTTGTTCAACAAGAGAGTTAGGTAGTGCCGCTTGAAAAAGTAATAGTGCAAATAAGAAAGTAAGACTGTATCGGAGACGACTTTTTAATAGTAGTAATTCTCGGTACAACTAAACCAGTAATTTCAGACACTG [...]
   +
@@ -271,10 +272,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTGCTAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCTAGTGT [...]
   +
   N~e_zd~D~~j~JT~`r\zwituUL%~~~~~~~~~~~~~}{|~~~~~~~}|\R^y[puB~v]J~~_tzMw~`~xv_^o*^`NywsxNt~`t~v~cx\~]x~`whk[d~gI~he^~~`~T~[~gxxxwM~x~iP~lao-~b}^uV~~U~_~sxO~xbh~w:~w]Zt]~ZQz|\xL~y~M~?_iKuu~_YlMx:~e~tq]~d~O~~M~t~Q~~B~~~xvjw~zm_smAfX}zw_s}xfB~|L~ywH~pMc~}J~U~_aNQ~~uP~|iH\~hs@~m~nz`Sg[g<uc~J*~ke~tZ~`e~g~savQ~|r~V~}uDattax~A]C~\vR~~rD~*~vW~\~<~~`s~B~~<~_~~m~aY~W~~Mu~R~aQ`~Ya~Mu|w~@~e~~`X~yx|_{q~b~hvys,~~IvM~Xz7~tdu~e~c~~zwSq@~~~\yt[Tsb3k~]Md/poscU~~c\,~tUKT`^L~uL^|i~utI~~~~Vkx<~bK~~^|fJx~t~Go [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1334/ccs/rev np:i:9 rq:f:0.997849
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTATAAAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCTAGTG [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1334/ccs/rev np:i:9 rq:f:0.997545
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTATAAAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCTAGTG [...]
   +
-  _~`ugXp7~yrybr~]LsrGo]d~t%~{~~~~~~~iUIEIYmy~~~~{z|~~yssgDrVZ~x~i_T~}uy~a[e2m]0nI~N~vv~|>|vPfuZ?aq}~}~}T~~g~u~q~~I~~Rjp|~~~~D~tc~h~|zCn~'~@}[~b~~w>~~W~E~peZ~~|V~NDu|yadyk~~~~~~g~b~~~V~~L~~~~m~|sa~V~Y_F~X~>~i~~QoD~c,~~~~[b=W~X~h~`~f~~^|}~g~D~mN~~~G~~j]~~C~[~nWpm~iKGnzSS~_jgg~3|~hyOyh~jeRovF~~c~e~~~7~v~ojdY~{M~ux~B~~d~~Oky}}~ma;{~}d~{~dk~}qg~ny:~b~~c~M~~a~~?~`~~E~~o~xkrqkn~|u~gsg~6~}~c~~i~~~`~H~iS|RS~~m~g~;~H~~N\~z~@~~~Rh~H~~~~~d~~~dS~~~~?~~~j<~n\~Y~~z_y~eY~~j3~gp~e5~~~~j~QV~~h~s~~g~~~VoW [...]
+  _~`ugXp7~yrybr~]LsrGo]d~t%~{~~~~~~~iUIEIYmy~~~~{z|~~yssgDrVZ~x~i_T~}uy~a[e2m]0nI~N~vv~|>|vPfuZ?aq}~}~}T~~g~u~q~~I~~Rjp|~~~~D~tc~h~|zCn~'~@}[~b~~w>~~W~E~peZ~~|V~NDu|yadyk~~~~~~g~b~~~V~~L~~~~m~|sa~V~Y_F~X~>~i~~QoD~c,~~~~[b=W~X~h~`~f~~^|}~g~D~mN~~~G~~j]~~C~[~nWpm~iKGnzSS~_jgg~3|~hyOyh~jeRovF~~c~e~~~7~v~ojdY~{M~ux~B~~d~~Oky}}~ma;{~}d~{~dk~}qg~ny:~b~~c~M~~a~~?~`~~E~~o~xkrqkn~|u~gsg~6~}~c~~i~~~`~H~iS|RS~~m~g~;~H~~N\~z~@~~~Rh~H~~~~~d~~~dS~~~~?~~~j<~n\~Y~~z_y~eY~~j3~gp~e5~~~~j~QV~~h~s~~g~~~VoW [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1378/ccs/fwd np:i:5 rq:f:0.996097
   AAGCAGTGGTATCAACGCAGAGTACGGGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAATGTT [...]
   +
@@ -283,10 +284,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTTAAACTAAAACATACAAATGGTAAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGGTTCATCCAGTTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAATGT [...]
   +
   WuS at D8A1RFATWBc:PU_TLQAFB7i]iFLTW8xpO0GqS at D[XQBAZGDlSYTIuV^E6ZW0=JTHtXUUW[+gKS<t\C,P^LULEm7RWUFWHsLmBt_AAEqT<toXaT<QmFTt?kT\bTIfD[G`TYb[UDX\CRFoRDNXTFuubYVRV>?jSB at PYTbTFuubTMuTKulE^>ErnO+Qb\T\T*@;ssWF8iulYb\]&<mI/@8D)prrW=rSX*\;euvuaDiTaWF+nQU(ZA_T_XaYbT=q^1Fe_>ZGvb\GwVuT\SFR=pV>_Y\T+^W?m9]2qqNuY\`FLsZGQ\YS1pFcGQ\aRBoFUtPX=[\A at rXbYTCwvbSPZG\>IJ>ToTYb;vcN;Vo[/dK:cU`D7p`R)eWTbYTbW:SSSVBKE]9DA_TIXb\T\TZV,h1Zso`;wiTQWSFXbY=C`KGBN1T>5K6]A2svviX`=@+?kSTYT\HwbHgFU*pVTKQ^YUPrQ=?q^S+A>MSbYVu\T) [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1407/ccs/fwd np:i:5 rq:f:0.987519
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTGAGCTACTTATGAAACATGAATGGTCGGTCTTGTGGTCGCTTTTGTCGAAATCACCGGAAACATTAAATCAAAGAAGTTTATCAACCAATTAGTACAGTGGCATGTTAAGTAAAACAGAAAGAACGCCAAGTGGCAACAAATGACGTAATTATTTAAGCAAAAAGCGTAAACGCTTACAAAGGCCTATTTAAATATCAGTAAATCGTTGGAAATTGGGGTATGTGCTGCCTTCATACGCAAAAATGGATGCGACAGAAACGAGTTGTATGGCCTCCCACTACGCTCGCCTGCCGCGGACCCTAAAACGACAGTCGTTTGCCCAACTACGGCTACCGGCATCGCTCAGAACTTCGGGTCTTGGCCCACCTTTCTGACGCCTAGTCAACGTGCGTCGCCTCAAGTCCTTGGACAAAAAGAAGAAATATCAATTGCAAAAATAACTATAGGTACTTCTTTGAA [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1407/ccs/fwd np:i:5 rq:f:0.987528
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTGAGCTACTTATGAAACATGAATGGTCGGTCTTGTGGTCGCTTTTGTCGAAATCACCGGAAACATTAAATCAAAGAAGTTTATCAACCAATTAGTACAGTGGCATGTTAAGTAAAACAGAAAGAACGCCAAGTGGCAACAAATGACGTAATTATTTAAGCAAAAAGCGTAAACGCTTACAAAGGCCTATTTAAATATCAGTAAATCGTTGGAAATTGGGGTATGTGCTGCCTTCATACGCAAAAATGGATGCGACAGAAACGAGTTGTATGGCCTCCCACTACGCTCGCCTGCCGCGGACCCTAAAACGACAGTCGTTTGCCCAACTACGGCTACCGGCATCGCTCAGAACTTCGGGTCTTGGCCCACCTTTCTGACGCCTAGTCAACGTGCGTCGCCTCAAGTCCTTGGACAAAAAGAAGAAATATCAATTGCAAAAATAACTATAGGTACTTCTTTGAA [...]
   +
-  QlRNXNPFlV+T8<g<QNYRZQYYN5MbeLRYRNXCL;jXXR4cNMVXO([O3hSJFnYNMlRYFmYNRN5kkhRYL;4bNUMR0M5V.RQLCLk7iiXM*hgQIP<Dj[.VL6L at i8fIiYRYUJW<WFkNT'9Kg:g;V'hhgMPH<`RL at U8Q@j;iRYD[5LhM7OcXRYMNMJNJeC6^hJNRK6MFOaP7IKCkM%K9LiTF.eI=P0^N->j]=LQOGQ:>OQEikYNRMl5J6LX1O$ff??AU<U<LVN(35\I+CWDH70ZhigU-CG<P69BIN,AiU/2A?;TQRDV3H7OT&???5I;4L/;7<BXW==^KEBJ<(OGH$?I59;6$K;F.M?^hQ'ILCG.S?95G8=.$ABOL>EHLJMLCQJhHMgN?mmSNIO3e9eMQ(R-GNGBK;D0=dM<H<9BSIRW<MQAMR;JM9-LRY%:=fFkTI(g\QRKEQM8TTYSXN:]8ZN61gkjeW?K<WDYYG]SFN=jM:hkR>h [...]
+  QlRNXNPFlV+T8<g<QNYRZQYYN5MbeLRYRNXCL;jXXR4cNMVXO([O3hSJFnYNMlRYFmYNRN5kkhRYL;4bNUMR0M5V.RQLCLk7iiXM*hgQIP<Dj[.VL6L at i8fIiYRYUJW<WFkNT'9Kg:g;V'hhgMPH<`RL at U8Q@j;iRYD[5LhM7OcXRYMNMJNJeC6^hJNRK6MFOaP7IKCkM%K9LiTF.eI=P0^N->j]=LQOGQ:>OQEikYNRMl5J6LX1O$ff??AU<U<LVN(35\I+CWDH70ZhigU-CG<P69BIN,AiU/2A?;TQRDV3H7OT&???5I;4L/;7<BXW==^KEBJ<(OGH$?I59;6$K;F.M?^hQ'ILCG.S?95G8=.$ABOL>EHLJMLCQJhHMgN?mmSNIO3e9eMQ(R-GNGBK;D0=dM<H<9BSIRW<MQAMR;JM9-LRY%:=fFkTI(g\QRKEQM8TTYSXN:]8ZN61gkjeW?K<WDYYG]SFN=jM:hkR>h [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1407/ccs/rev np:i:4 rq:f:0.990503
   AAGCAGTGGTATCAACGCAGAGTACGGGGTGAGCTACTTATGAAACATGAATGGTCGGTCTTGTGGTCGCTTTTGTCGAAATCACCGGAAACATTAAATCAAAGAAGTTTATCAACCAATTAGTACAGTGGCATGTTAAGTAAAACAGAAAGAACGCCAAGTGGCAACAAATGACGTAATTATTTAAGCAAAAAGCGTAAACGCTTACAAAGGCTATTTAAATATCAGTAAATCGTTGGAAATTGGGTATGTGCTGCCTTCATACGCAAAAATGGATGCGACAGAAACGAGTTGTATGGCCTCCACTACGCTCGCCTGCCGCGGACCCTAAACGACAGTCGTTTGCCCAACTACGGCTACGGCATCGCTCAGAACTTCGGGTCTTGGCCCACCTTTCTGACGCCTAGTCAACGTGCGTCGCCTCAGTCTTGGACAAAAAGAAGAAATATCAATTTGCAAAAATAACTATAGGTACTTCTTTGAAGAAACC [...]
   +
@@ -351,10 +352,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGCCAACGTCTCCTTAGATAACTGGCAAATCTTCACAATTACGACAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTGCACTCCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAATAGCCATTCTTCCTGAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGAGTGCGAAGCCACTAGGTTTGCACTGTTGACCACCAGCACGCAATCGCAAGATACGCAGTAATGCTAAACCATAACTTATTTGACTTTGATGTTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGCTACACATATGCTGTTGGGAATTGTTTTTTACA [...]
   +
   Rz[RbIfJaA\SK;TL?OGULZc7P$ZVQSadYY]chnrrssssssssssssssssrZY6u$ACZ\AHB{Wu]Ybd1qQf at mRKvvfRXvRaQ?qF`N;,$M?XTB3WN`a[Sv`UZ`Cce<6D=8P>J0a`ZCgFQ`];ZN6]H_rfRIB:_N?UmZRaNQBgMY=.raJBfJYBtc=YeYLNFR5OaX`_[RAdcVNV2qP[QAJYK_MHC6GM'%@LSW at rI=YM[TTI3BXKY_:X_XC]c_FE|bXvRWt8ydZCtR_LKQ[VwbY.\ZfbZ2rKvXv7C0V;1qYb>]VNV<ZrVNXcALUA^ACsVK^:<uGkWFPaRfZHvZbDh7DsLY=[)2=>VXEZR6l[T^A<?$PZd.YcZOL/n[3\JN%*7EeM;rYB`QAuqU35Q'nSM;BKC]Dd5tgTkKx_RAxeF;_[O]_4YKYbRA_rvb[fR[LUTXRbQAlMVP3rP5oMmN]aRbRbfbeA'IYTt<q^J]0DA4hVgudNPL [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1549/ccs/rev np:i:6 rq:f:0.993149
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGCCACGTCTCCTTAGATAACTGGCAAATCTTCACAATTACGCAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTGCACTCCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAATAGCCATTCTTCCTGAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGAGTGCGAAGCCACTAGGTTTGCACTGTGACCACCAGCACGCAATCGCAAGATACGCAGTAATGCTAAACCATACTTATTTGACTTTGATGTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGCTACACATATGCTGTTGGGAATGTTTTTTACACTTATT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1549/ccs/rev np:i:6 rq:f:0.993243
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGCCACGTCTCCTTAGATAACTGGCAAATCTTCACAATTACGCAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTGCACTCCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAATAGCCATTCTTCCTGAAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGAGTGCGAAGCCACTAGGTTTGCACTGTGACCACCAGCACGCAATCGCAAGATACGCAGTAATGCTAAACCATACTTATTTGACTTTGATGTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGCTACACATATGCTGTTGGGAATGTTTTTTACACTTAT [...]
   +
-  CgRHSSNEcKQd]Yw^SGd<*L0BE%clbVPOX\bltvvumc]ZZ_hruvvtk_[enD><sg]SO\c<uUxfTOJO_TE7q[BwwbGRd]OGTnOzh]SGEq>cNvfPd=NN__T<LYcHwSFDHZb0V\P>vU\gO\SN:uAvv`Zhb<r\:vbO\gXX;sFv[-trOLXPRDrH[R^TcF`;eZ^bXgT\.zs7EROWYFWOwTKO[V`Z5UMOQWOgGxg]@[dSw\OMxdTh]ThTYv9eTPzhRW[OS<h6P$sEeeh]T0q[S3uRMfS7S7`;Q at Q:S]OuTd\Of]g?wjNaLOPZ;SVN:cIWFaEg=mXQ\bT]P5QKJ^cLuhU[QFS[4uM[RXXfTheh\@W:JOFuKAG`Aws9pVdhLSw^<_sTh]9tH6K`S2p[bgbYOYM=dn&34XbTCR7RCOQZ^IK_`PhZBauq[SLSU[OA?EKYFZZ;RAt\G^2q at Kf]h\P:UPTZJ9E=7XfJib at +hm\^OHVBX0]d>d [...]
+  CgRHSSNEcKQd]Yw^SGd<*L0BE%clbVPOX\bltvvumc]ZZ_hruvvtk_[enD><sg]SO\c<uUxfTOJO_TE7q[BwwbGRd]OGTnOzh]SGEq>cNvfPd=NN__T<LYcHwSFDHZb0V\P>vU\gO\SN:uAvv`Zhb<r\:vbO\gXX;sFv[-trOLXPRDrH[R^TcF`;eZ^bXgT\.zs7EROWYFWOwTKO[V`Z5UMOQWOgGxg]@[dSw\OMxdTh]ThTYv9eTPzhRW[OS<h7Q&rGGfeh]T0q[S3uRMfS7S7`;Q at Q:S]OuTd\Of]g?wjNaLOPZ;SVN:cIWFaEg=mXQ\bT]P5QKJ^cLuhU[QFS[4uM[RXXfTheh\@W:JOFuKAG`Aws9pVdhLSw^<_sTh]9tH6K`S2p[bgbYOYM=dn&34XbTCR7RCOQZ^IK_`PhZBauq[SLSU[OA?EKYFZZ;RAt\G^2q at Kf]h\P:UPTZJ9E=7XfJib at +hm\^OHVBX0]d> [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1608/ccs/fwd np:i:10 rq:f:0.998309
   AAGCAGTGGTATCAACGCAGAGTACGGGGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGGACTATGGGACTAGTCGTCTTCGGTCTTACAAATGTTGCAATGCCCTGTGAGCTACTTATGAAACATGAATGGTCGGTCTTGTGGTCGCTTTTGTCGAAATCACCGAAGTGCGTATAATTGATGAACGAGTCGAAGTCGAAGTTGTTCAACAAGAGAGTTAGGTAGTGCCGCTTGAAAAAGTAATAGTGCAAATAAGAAAAAGAAGCGAAACGGCATTCGTTTAACAAAACGTCACATA [...]
   +
@@ -383,10 +384,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTAATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACT [...]
   +
   mxPKr3NBoNfbi,qRUnzW~Xdir7jl~sU}@zyLX`]A~kCyuS|6~h-t_UXSZrXIvRs0a.LKhS4RsVic6~~~~q=z\W{I[UQC~JHaTL1pe7~eW^]{fRQFdWsf?~~xlJ;hU`:kkdqG}[pTXNd]7csSnS6_HTqU/wFzyV<ygPb1/TadThWeGyrcT?&cvWsKzJ~dWAxu>coUZ5U8iH<8UnTvWgXc]U=ytSt<XHzzyBvKV$sae>^Sw[UNyRR|VsAq^d`WN1azVvsWreRZ5a]BO||Xz[UXFbRq_haX`2[fcTW[C^Z^dWcTSKfbxLxJ~{sU2QC6qo[nHg7jbzDb^F{_EVAM`kPY4_M-:\gQxaBNnFzWXtEFfrVK||pLITWIxPc:mRRF^cn^oUfVbwDHu]Yk&POBtdVJv|w^SW%zzfnSMaPU85eSudseXexcW@^B2v?cTL2x`NOH~YFOOrDb^Hd;ucIa8LXqGyQsTNURLTVIsgFt_qUz0M [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1688/ccs/rev np:i:7 rq:f:0.996824
-  AAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACTA [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1688/ccs/rev np:i:7 rq:f:0.996883
+  AAAGCAGTGGTATCAACGCAGAGTACGGGGCTTAAATGTCGGGAAATTGGGTTTGCGCCGCCTTCAGGGGCAGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACT [...]
   +
-  '~R_Ih:J~xopbZ~aUMrzC_fscB~~Y at YyPe~sjaaS~~J~k3~Z~qA~~~c~Q~~T~O~^rAE9X8ioXRW}4~~~~_jZKY]L~juWx_>~|4;_WxK]o;~X>~p]}c~>r~na~P~lXF~~47?`Alb_q]y:~~|_iP~gJTBb~AZC\1ae^km?~Vq[BpdbvQN]U1~~\K\~f~~}F~gE~~|ymhV\Kgof`hY_o~w`k<neJ~XR:~~[5KXeF~`^~jn`~Q~ob~QJB~~pO{x`]VFULl_FUUSmY^T~~~oLh^>~Hpd0J<MlVnq~_v_v`k[}ikoQ~~^M~A~oa~PrTSsq^^jOnPP{_lLg~pM~D~~rd]^]vW~bf_Yp;_`U]Q=n~FoTjSeh]le=W.|x at D]li=~~_nM}r~~ojA~~~b`ba8I?1X=|~X~mgI~~jH`HookwRq?~~_v}`j\^~~y=~~^alj~vo^V~\vm`u}a[E~J]?V~km}LJ~/~{~b`s9y0~lGSc^:~N~o [...]
+  )~Sf`Jh:J~xopbZ~aUMrzC_fscB~~Y at YyPe~sjaaS~~J~k3~Z~qA~~~c~Q~~T~O~^rAE9X8ioXRW}4~~~~_jZKY]L~juWx_>~|4;_WxK]o;~X>~p]}c~>r~na~P~lXF~~47?`Alb_q]y:~~|_iP~gJTBb~AZC\1ae^km?~Vq[BpdbvQN]U1~~\K\~f~~}F~gE~~|ymhV\Kgof`hY_o~w`k<neJ~XR:~~[5KXeF~`^~jn`~Q~ob~QJB~~pO{x`]VFULl_FUUSmY^T~~~oLh^>~Hpd0J<MlVnq~_v_v`k[}ikoQ~~^M~A~oa~PrTSsq^^jOnPP{_lLg~pM~D~~rd]^]vW~bf_Yp;_`U]Q=n~FoTjSeh]le=W.|x at D]li=~~_nM}r~~ojA~~~b`ba8I?1X=|~X~mgI~~jH`HookwRq?~~_v}`j\^~~y=~~^alj~vo^V~\vm`u}a[E~J]?V~km}LJ~/~{~b`s9y0~lGSc^:~N~ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1757/ccs/fwd np:i:6 rq:f:0.997228
   AAGCAGTGGTATCAACGCAGAGTACGGGGCATACTGCAAGACTTGTAGGCCCATGAATTACCCGCTTAGGCAATGGGTAGACCTTTCCTTGCCGCGTGGAACAAACCGCCATGAGTGTTTTTACGTTTACGGTCGGCGACCGGAGTCACAGCGCGACCAACGGGGCCAGGCAAAGGCCCATAGGCTTTTCCATCGGCACCGCGACCGATTCCATCAAGTGTTAGGTGCAATCCCCATTCGGGACGGACACGCGAGAGCGTTAGTCCGGCGCGTGCGCGGGACTATTTAGCGAAGGTCGCCGATCGTTTGCCCGTAAAACTAACTGGCAAAAGCCTAAGTGCTGTTTCGGGTGCAATGGTATAACTTCCCACATTTAGCCGAATAGCGCCAACAGCGTTATTATTTGGAACCAAGCAGTGGGCGATGTCAGCGACAATTCCACTTTGGTAGAGGTCGTTCTTTTGTAGAAAACAATCTAACATAACTATGA [...]
   +
@@ -427,10 +428,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGTTGGTTCGTACAGCGGTAAATGACTTGTTGAGTCTTGACGTCGACGACCAAAGCGACCACTTTGACCCAATTGCGAACTACTAAATCCTAAGCAAAGACTATTAGGTAGTAGCCAACTTCGTTAATTCCGTTCAGTACTTTTAAATTCTAACCGACCATCTTTCCGAGTTGCTTCAAACCCTCGTCCTAATGATTTACATCGAATAGAACGTCGTACAAACGCACTACTACATGGAATAGATTCTCTTGTCAAATCGTTTTGTTTTGGCTTTACCCTTGGTAACAAACTTCGACTACGTTCGTACAATTCAGAATAACCTCTACCTCGTTAATTTGAGTTAGTTCGTTAAGGGCTTAAGTAGTTATTTCTATGATAAGCACTAAATTGACCTTAATTTCCTCGACTTATTGTTACATCTCGATTTCCCTTGATAT [...]
   +
   4~{~~~~z~~~~~~~~~~~~~~~~~$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~i~x~y~~s~~~~~pS~~J~~~s~~h~~{~u~~Mwd~h{~~~~~q_~~W~1~~~~~ob~~ps~~~~a~~~~v~`~~L~~s~~~a~~~p~~~~Z~n~~~~~|br~ke~~~~~~e/pl~~r~~et~s~~~j~~~~~k~z~~9~~~f~~f~~~s~QnW~~~~~~`~~n~~~~~~~~}~cb~n8~~~~hme~rfe~~~b~~~~~~~ln~Z~~{~~i~~~_~~g~~~~d~~q~~~~s~~h~`~~~~~q~~~~y~~~~t~~~~hK~~~zW~~~b~~a~~~q~~d~}~~~~~y~~~z~~~~c_~~~V~qsT~a~~~~~~~t~s~~a~~~~~i~~~~s~~~i~~~~~~~~~~~~~~~~~a~~u~~~~~e~~~~~d~~~~~x~~~~~~~~~~x~~~~~~7~~~~~T~~V~~~~~~~~~l~~~~~u~~~~~~~f~~\~~j~~~~~~ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1948/ccs/fwd np:i:9 rq:f:0.998158
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTGAGGCTTGTCCGCGAGTGTCAACCGGGTTTTACAAAGGAGAACTTCCAACATCAGTGTATGGGATGTTTCAAACACCCCCAGAGACGGAGACAATAGTGTGGTCACGTACATTTAGGAAGATAAAAATAACAACAACAGAAGGTACAAGAGTTGGTTACTCTCAGTCCCATTCCCAACACATCACTGAGAAGTATAGAGCCTAGTGGTCATTAGAAGGTCAACATGGAGTAGGTGTTTAGGTGTGTCGGAGGGCAGAAACCAACGAAAGAAAGGAAACGATCAACACTTATATAGTGTCCTGTCGGGCCCAAATCCTAAGAGACCTTAGGTTTACCACATTAGTAACTAAACAGCCTGTTGTATACCGTGAGCCCCCACTTCGATCTGTAAATGGTAATCCCTTGTAAAACCTCATCTCCAAAAACAGTATACGCAGGTACAGCTGATGTGATCCTCTCT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1948/ccs/fwd np:i:9 rq:f:0.998231
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTGAGGCTTGTCCGCGAGTGTCAACCGGGTTTTACAAAGGAGAACTTCCAACATCAGTGTATGGGATGTTTCAAACACCCCCAGAGACGGAGACAATAGTGTGGTCACGTACATTTAGGAAGATAAAAATAACAACAACAGAAGGTACAAGAGTTGGTTACTCTCAGTCCCATTCCCAACACATCACTGAGAAGTATAGAGCCTAGTGGTCATTAGAAGGTCAACATGGAGTAGGTGTTTAGGTGTGTCGGAGGGCAGAAACCAACGAAAGAAAGGAAACGATCAACACTTATATAGTGTCCTGTCGGGCCCAAATCCTAAGAGACCTTAGGTTTACCACATTAGTAACTAAACAGCCTGTTGTATACCGTGAGCCCCCACTTCGATCTGTAAATGGTAATCCCTTGTAAAACCTCATCTCCAAAAACAGTATACGCAGGTACAGCTGATGTGATCCTCTCT [...]
   +
-  c~zJVQmW~~X~QI~h~ghxozrAfM~~~lh~e~fS~}~B~~e}mxFz~gX~@~[~~=~~ySiL~~^~hwL~gh~R~h~fyximq~i~m~U~~~~kf~~g=~}a].x~~wl|l}}_c~~~vVh~\V{~R~X~~ekPt~mh~b~~~c~h~zT}7zaaq~cSQM{FZ~clwW~Q~{mcg~{hcO~i~h~~g~Mqj~~~I~~~V~<~qX~g}i|~YUX~d|ig~}~eUppcsQ~~{x~h~~>\_~ZkX~f~yhd~h~~d~Tg~X`x|OE~~kb~~|~i~Wh~oZ~~i~}X~{F~X{gkQ~~}B~~c~[~~j~{^gl~T~ie~ffin}z~~~2~~i~[I~lG~~G~~~F~x]~~m}mP~i~Xe~Z~~U8~}e\e{m}w<~j~:~pc~{2~~z^~y}~l^W~~~~|x4~~~s[iw~ceh~hu|pMg|~R~wR~~C~~q~s}?~oUHheNe~c~R~)~~~PMxtmw~P=u`t`~~s^pGb~]9Xvq`yuN~n`wLf [...]
+  c~zJVQmW~~X~QI~h~ghxozrAfM~~~lh~e~fS~}~B~~e}mxFz~gX~@~[~~=~~ySiL~~^~hwL~gh~R~h~fyximq~i~m~U~~~~kf~~g=~}a].x~~wl|l}}_c~~~vVh~\V{~R~X~~ekPt~mh~b~~~c~h~zT}7zaaq~cSQM{FZ~clwW~Q~{mcg~{hcO~i~h~~g~Mqj~~~I~~~V~<~qX~g}i|~YUX~d|ig~}~eUppcsQ~~{x~h~~>\_~ZkX~f~yhd~h~~d~Tg~X`x|OE~~kb~~|~i~Wh~oZ~~i~}X~{F~X{gkQ~~}B~~c~[~~j~{^gl~T~ie~ffin}z~~~2~~i~[I~lG~~G~~~F~x]~~m}mP~i~Xe~Z~~U8~}e\e{m}w<~j~:~pc~{2~~z^~y}~l^W~~~~|x4~~~s[iw~ceh~hu|pMg|~R~wR~~C~~q~s}?~oUHheNe~c~R~)~~~PMxtmw~P=u`t`~~s^pGb~]9Xvq`yuN~n`wLf [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1948/ccs/rev np:i:8 rq:f:0.995017
   AAGCAGTGGTATCAACGCAGAGTACGGGGTGAGGCTTGTCCGCGAGTGTCAACCGGGTTTTACAAAGGAGAACTTCCAACATCAGTGTATGGGATGTTTCAAACACCCCCAGAGACGGAGACAATAGTGTGGTCACGTACATTTAGGAAGATAAAAATAACAACAACAGAAGGTACAAGAGTTGGTTACTCTCAGTCCCATTCCCAACACATCACTGAGAAGTATAGAGCCTAGTGGTCATTAGAAGGGTCAACATGGAGTAGGTGTTTAGGTGTGTCGGAGGGCAGAAACCAACGAAAGAAAGGAAACGATCAACACTTATATAGTGTCCTGTCGGGCCCAAATCCTAAGAGACCTTAGGTTTACCACATTAGTACTAAACAGCCTGTTGTATACCGTGAGCCCCCACTTCGATCTGTAAATGGTAATCCCTTGTAAACCTCATCTCCAAAAACAGTATACGCAGGTACAGCTGATGTGATCCTCTCTA [...]
   +
@@ -455,10 +456,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATTGACCCAAATAATTAACTCGTTCCAATAGTTGAAGTGTTGATTAACACATTGAGACAAGTTGTCCGTACTTTAATCATCAAAGTTTTGGACTGACCTATAAATGAAATATTCGCGTTGTCTTCAGTTTAAGAAGTGATATTATTTTCGGTTTCAAGCCTATGTGGAGAGATACAGGAAATAGGTAAACTATAACTAATATAAATATACGCAGACGAAGCCTGTTAACTTTACCAAATCCAAATAGCGGGAGACA [...]
   +
   W~e]henC~hbp\H~\_MZcRcnOE=~~~pCucWd6hVbkK~7TIdMhheZEHEG_mFcpeU`4Y3zRA~fW6xcd]lMX~[YY_H8>J]>ch>~sZ=VIXPm\EkZFjwcmcaR`JI`WfV_nFdTt-cu_[c/c_^epUn__`~OI~\ep]KjeA~`P~PLc;NW;,%VdOX0>3eJk9ZLbR\gYIBI6BbheL~~~[>ne`~Md?X_n)rmWcheh[Z=UHNYVMJC(B`cWddR9~\@~~oX~'$$zBn]e[g>oKmhLcBPQ/vPlMVB`VU~7|ZQ\fM~O;AH\+LL_~ELL~emIUCzXCw_\eV[F~nM1w_sA~f\i]^-`[\_2~bUc3~f_'Ta2]]a5}HQXVu]Mc6b~Sd_0xaUcglgYnR=VYq\QwF~jF2/MM~nQUcnCud;cSRl:XO1f0z[OfQ~_8nmYUeiFk]pK~nK^LycoeSMCL[idhZMRsd<~lLHzJ~]R~lXL~>~oOJm:97jbcE6i`GR]CL [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1999/ccs/rev np:i:5 rq:f:0.994586
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATTGACCCAAATAATAAACTCGTTCCAATAGTTGAAGTGTTGATTAACACATTGAGACAAGTTGTCCGTACTTTAATCATCAAAGTTTTGGACTGACCTATAAATGAAATATTCGCGTTGTCTCAGTTTAAGAAGTGATATTATTTCGGTTTCAAGCCTATGTGGAGAGATACAGGAAATAGGTAAACTATAACTAATATAAATATACGCAGACGAAGCCTGTTAACTTTACCAAATCCAAATAGCGGGAGACACT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/1999/ccs/rev np:i:5 rq:f:0.993133
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTGACGATCCCTGAGACTATATCATACAAAATTGACCCAAATAATAAACTCGTTCCAATAGTTGAAGTGTTGATTAACACATTGAGACAAGTTGTCCGTACTTTAATCATCAAAGTTTTGGACTGACCTATAAATGAAATATTCGCGTTGTCTCAGTTTAAGAAGTGATATTATTTCGGTTTCAAGCCTATGTGGAGAGATACAGGAAATAGGTAAACTATAACTAATATAAATATACGCAGACGAAGCCTGTTAACTTTACCAAATCCAAATAGCGGGAGACACTA [...]
   +
-  <aOGW[]-lfnQd`~MXFEP^Ygj_:~|_aF^Z`X8ycj_U~KrM[Zgi`FahEAaNZ>GA;;>S%m)]adCyoQa:[a~]pcFcVl=no]m&|h8MhQ~X~`Z~S5cXIdEfJBj6uKne\RL~NrDz`g`U8xuQ[h]rT5MagAfJEdM[tg>~f?|hnQS|Wg^M~dcHiOyX~]gL~2i`hlLDc\pe[OR1XgwdnLRM at Hne]nJI~~bT:VneaLeohephp_0[byX~]pEsWD{~e`}bC{~Lfe]KgC~a~hp[$DFNvJY@'CGdBEH_^peoG~XiYc\0YDLcAbR~[;md0qh\gddf&`G~yX5pSnN}SKg]pU~hhRE~qR[J~~feImdZ`\@J[ca&apX8[F=uY:GQ;YUQl5nd1jJ7EFAZzeb~WP|c:_EaCg8,ODdKi5kO~2~shp:\:2xsQGmhZaZZGb\TQDnuhphjcG[nFkMZL~EO}\/6qIg]@~~oQ}Q|lRQ~GZyfk\e*~rhSjepec [...]
+  <aOGW[]-lfnQd`~MXFEP^Ygj_:~|_aF^Z`X8ycj_U~KrM[Zgi`FahEAaNZ>GA;;>S%m)]adCyoQa:[a~]pcFcVl=no]m&|h8MhQ~X~`Z~S5cXIdEfJBj6uKne\RL~NrDz`g`U8xuQ[h]rT5MagAfJEdM[tg>~f?|hnQS|Wg^M~dcHiOyX~]gL~2i`hlLDc\pe[OR1XgwdnKP%Bme]nJI~~bT:VneaLeohephp_0[byX~]pEsWD{~e`}bC{~Lfe]KgC~a~hp[$DFNvJY@'CGdBEH_^peoG~XiYc\0YDLcAbR~[;md0qh\gddf&`G~yX5pSnN}SKg]pU~hhRE~qR[J~~feImdZ`\@J[ca&apX8[F=uY:GQ;YUQl5nd1jJ7EFAZzeb~WP|c:_EaCg8,ODdKi5kO~2~shp:\:2xsQGmhZaZZGb\TQDnuhphjcG[nFkMZL~EO}\/6qIg]@~~oQ}Q|lRQ~GZyfk\e*~rhSjepec@ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2012/ccs/fwd np:i:6 rq:f:0.993131
   AAGCAGTGGTATCAACGCAGAGTACGGGGCTTGTCCGCGAGTGTCACCGGGTTTTACAAAGGAGAACTTCCAAACATCAAGTGTATGGGATGTTTCAAACACCCCCAGAGACGGAGACAATAGTGTGGTCACGTACATTTAGGAAGATAAAAATAACAACAACAGAAGGTGTGAGGCGCAAGGTACATGCTCTTACCCCACTCTCAGCACGTAGGGAGCGGAGTGTGGAAGACAACAAGCCCGTCGCCTCTACCAAATACAGCTATCCTGAGGTGCCAGGTTAGAATAGGCCCTACCACATCTAAGCCTTGAAACGGTCTGTTCCTCGTGTCAAGTTCTTGTCCGCTTATACCGCCATCTCTCGTTGTGGTACAAGAGTTGGTTACTCTCAGTCCCATTCCCAACACATCACTGAGAAGTATAGAGCCTAGTGGTCATTAGAAGGTCAACATGGAGTAGGTGTTTTAGGTGTGTCGGAGGGCAGAAACCA [...]
   +
@@ -495,10 +496,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGACGCAAATGCCACCAATACATATGTGTCCTCTTAATGTTTGCATGCTTAATTCTTTTGATTATTATTTCCTCTTTCTTTCTATTACTAACTTTGTAACTCTCGCTAACCGAATCAACATAAATACGTCAACGAATCAAATGTTGATCTCAAATATCTGTGTCCATGAAATTTTCGGATCGTAATCTGCTCTACTTTTGTTATTACAACAAGAACTTCGACTAAAGAACGGACTATCTTGTCTAATAATAATGGCACTAAGTGCATACTTTCTCGACTACATTGACGACTCAAAATAAGAAAGGGAGTTTTTATACATTGACCTAACTCACTACTACGCCCTTGGTTACCTTTGAACCTTTCGTTGTCAAAGTTCGTACGATGGTAAGTGCTTTCTTACTCCTACCGCTATTTGGTTGAGAACCTGTTAAATGA [...]
   +
   p~y]httc~jM~\8zdfZ|xix~Nh$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``ZRw\@~~~yM~yZ~G~~zp~~h~mlx~X~j]Y~F~~yZ~~xVuj_YF~e~%lq@~~~rRc~~f~}I~~a~~lY~~sY~~mQb_~{niI~ra~cred~m|t{Oqn~Y~Xk^T~|j1qYul?~~htih^bNzaiJn(a7ys\gH~nnE\pa/|~|s|iyWzozH~h$c'T76~~u`6gn_gWwS~ycuodGc^PM<~~~mU~r`z at B7q_[~o=zbK~UPmfx)~~lN~S\~]hy]Y_b~jse]W~_S~\T~{]~hrcp.~jtR`VrmT]~~QxbjpNyqWTY~m]Wm[M[\0pTWpZhn?~nR~~snD~~~rDrXcsg~n]NlXN~Y<O:ZLDTx\ad&tWW~\~W~]U~Kh}VM~OZ1uoSb<~`IeNymgT~dl|djk)CZ~f1|j\hG9~~<+3/d{T~t]<`/bWm0~xIxO~gTi\~W~|nV~C~t]ms [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2164/ccs/rev np:i:7 rq:f:0.996833
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGACGCAAATGCCACCAATACATATGTGTCCTCTTAATGTTTGCATGCTTAATCTTTTGATTATTATTTCCTCTTTCTTTCTATTACTAACTTTGTAACTCTCGCTAACCGAATCAACATAAATACGTCAACGAATCAAATGTTGATCTCAAATATCTGTGTCCATGAAATTTCGGATCGTAATCTGCTCTACTTTTGTTATTACAACAAGAACTTCGACTAAAGAACGGACTATCTTGTCTAATAATAATGGCACTAAGTGCATACTTTCTCGACTACATTGACGACTCAAAATAAGAAAGGGAGTTTTTAATACATTGACCTAACTCACTACTACGCCTTGGTACCTTTGAACCTTTCGTTGTCAAAGTTCGTACGATGGTAAGTGCTTTCTACTCCTACCGCTATTATGGTTGAGAACCTGTTAAATGAGATGG [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2164/ccs/rev np:i:7 rq:f:0.996992
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGACGCAAATGCCACCAATACATATGTGTCCTCTTAATGTTTGCATGCTTAATCTTTTGATTATTATTTCCTCTTTCTTTCTATTACTAACTTTGTAACTCTCGCTAACCGAATCAACATAAATACGTCAACGAATCAAATGTTGATCTCAAATATCTGTGTCCATGAAATTTCGGATCGTAATCTGCTCTACTTTTGTTATTACAACAAGAACTTCGACTAAAGAACGGACTATCTTGTCTAATAATAATGGCACTAAGTGCATACTTTCTCGACTACATTGACGACTCAAAATAAGAAAGGGAGTTTTTAATACATTGACCTAACTCACTACTACGCCTTGGTACCTTTGAACCTTTCGTTGTCAAAGTTCGTACGATGGTAAGTGCTTTCTACTCCTACCGCTATTATGGTTGAGAACCTGTTAAATGAGATGG [...]
   +
-  X~\xjquU~PP9sH~\V6L>gp~~|&~~~~~~}tz~~~~~~~~~~~~~~~~~~rrkuqv3~~}tJ~YVg8~cydefJ[Ly`{f~~xZ~T~}mH~dGO2;Lj_~W~wtGqf~t~P~~i~~Y~~`~jtH~~vV~~xI0A}~{jZ~p9~~l}5~\;adLj^i+SRk)@;Azs~yjgU~~;}a:_r:~x_v~~{L~xQrK~r~[s{u1~}Kcx||WZUKZ~ui\V~~H~~uZ~~|vl_Zzyv{bW=kZev<~~aK8maU~~s9~ab~[a~{K~z]mvp7{~qr~j>~j{~oh{N~pPsjk~pf~[S~WU~c~{j[~i}Hswghm4~~jig0'Y`kwiLzZ]qdJ[Kx=~~qcZ~V:~~S~~Np;~~~oJoqLw~T~o|=~cv~{irhzR~wwi`kY~R~[~A~g~X~bkm~_iF~~roNw\hdi~~p\~vWubpS~~Z}Mu~r|rxM~~|~pxhN~NlR~lmKbOE+SOy^{dYj4~_~oGB~F~~yi=[ExS~ [...]
+  X~\xjquU~PP9sH~\V6L>gp~~|&~~~~~~}tz~~~~~~~~~~~~~~~~~~rrkuqv3~~}tJ~YVg8~cydefJ[Ly`{f~~xZ~T~}mH~dGO2;Lj_~W~wtGqf~t~P~~i~~Y~~`~jtH~~vV~~xI0A}~{jZ~p9~~l}5~\;adLj^i+SRk)@;Azs~yjgU~~;}a:_r:~x_v~~{L~xQrK~r~[s{u1~}Kcx||WZUKZ~ui\V~~H~~uZ~~|vl_Zzyv{bW=kZev<~~aK8maU~~s9~ab~[a~{K~z]mvp7{~qr~j>~j{~oh{N~pPsjk~pf~[S~WU~c~{j[~i}Hswghm4~~jig0'Y`kwiLzZ]qdJ[Kx=~~qcZ~V:~~S~~Np;~~~oJoqLw~T~o|=~cv~{irhzR~wwi`kY~R~[~A~g~X~bkm~_iF~~roNw\hdi~~p\~vWubpS~~Z}Mu~r|rxM~~|~pxhN~NlR~lmKbOE+SOy^{dYj4~_~oGB~F~~yi=[ExS~ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2225/ccs/fwd np:i:6 rq:f:0.995244
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGTAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTTCGCAATGAAAAGAATATCCTTATAGACACGAAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCT [...]
   +
@@ -519,14 +520,14 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTACTATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCTAGTCCCGGACTCACCGAACCTACACCGTTCCCTTCAGTGTGTTCTTTCGGAGTAGTGAAAAAAACGTTGGTCTTCCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCCTTCAACAATTTTACAAAGCAATGCTTGTGGGCTAGGGCACCGCGTTTTGAAGTAAATAGATGTAACCTACCACCCATAAACTGCTCTAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGACGAAATTTACGGTGGTAATTTCGCACACTTCG [...]
   +
   e~b]k^bS~gZeY9jW^Ll`X^MUY$W_kyyrmlnpaWSV`igiowuqqu}~~~|kgZcSd`/V@\^lP~i@(9IC>QMYdLkS~fHeK~bkVkfN~lYX7z`YWd@~~A~k]dG=H~KJ~N|fFWU:|^7L9~xSj]d[[Ca[BlV5bmDP~mbfmba^$~~~~~\]]E~O~MT).,_j6rb^dWZcX`L~jPZKDj[UILYtXGXC.~~oALLn_D~V)}PI}]CfJUo<~~~l\2{g_\M~ec]X~WRD~f4eVG~i3U(S^Za;|iy^6\[d?~}KjbmeaNAlN~`A<iX7]LVK0y~\fb]f]b3 at G@j1~WJiaM~]bdH``E_:|G{\2lq~fWejeZAEdY~[bfbfm8xfj;mOwXLWa]bN~a2u2ey_PfJjeZfWZf_kL~~]fX.oebflN~~P<=~c1jXb]f]hb\FaJEaFbYMZW~bjOJ3`hVwIYkH@~z^g^eg=h(CY)RRL~~lZ-}dRy`7yBrvPH[SYgHUo]` [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2286/ccs/rev np:i:7 rq:f:0.996434
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTACTATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCTAGTCCCGGACTCACCGAACCTACACCGTTCCCTTCAGTGTGTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTTGTGGGCTAGGGCACCGCGTTTTGAAGTAAATAGATGTAACCTACCACCCATAAACTGCTCTAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGACGAATTTACGGTGGTAATTTCGCACACTTCGCACG [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2286/ccs/rev np:i:7 rq:f:0.996436
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTACTATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCTAGTCCCGGACTCACCGAACCTACACCGTTCCCTTCAGTGTGTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTTGTGGGGCTAGGGCACCGCGTTTTGAAGTAAATAGATGTAACCTACCACCCATAAACTGCTCTAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGACGAATTTACGGTGGTAATTTCGCACACTTCGCAC [...]
   +
-  :RH at PCW;qnhncG~[_deZi\nhc%~tc_gmnmnniefmu{mQ at 8;IbxsiYST\LcRdfdne]Yf?}gd_nai@~gep^QO~i`PO}Ga`aYO~SbhR~nh^Y;~eP~fNWbhU~_N|U~YeNfQ~JWt>zdL~`:Z\XPNJ~MQy~bHf]^;E_n\+Wx~~jbDJdJ~C`,~CfO&O_KfQ_fiXT~fVa_XpaRW]M~_N~c at gs~h`T~VDdM?VWiMW~dX~>~~Q:KBjfI4D~kJbYs\f%uoWad;~ua<Pq_c]=jfsIV~JWP~~nh]dm^YW~C~mhU~g;wcOQ=~~am_dncYG~cW~9~~U~\O~[NWc^Y`5Kx,^K5U[QZ\\HG7UUhTsaGB[egR~oiR~VQgXR?7F]~jR~'~[[TgefXekQO`_]H]{_ndX~n_l8CvvZhQlYK~`j_ncY^bXlncncT^XbX~PclQc^YY~JXia?kvXM]nhNqhd_X~Bqq_L>mZ<x^Tg>zj_^Nfchb4fD^ahK] [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2295/ccs/fwd np:i:4 rq:f:0.992925
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTAGTCTGGCAGATTAGATACAGCTATAGAGCGAATCACCACGTCTCCTTAGATAACTGGCAAATCTTCACAATTACGCAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTGCACTCCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAAATAGCCATTCTTCCTGAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGAGTGCGAAGCCACTAGTGGTTTGCACTGTTGACCACCAGCAACGCAATCGCAAGATACGCAGTAATGCTAAACCATACTTATTTGACTTTGATGTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGC [...]
+  :RH at PCW;qnhncG~[_deZi\nhc%~tc_gmnmnniefmu{mQ at 8;IbxsiYST\LcRdfdne]Yf?}gd_nai@~gep^QO~i`PO}Ga`aYO~SbhR~nh^Y;~eP~fNWbhU~_N|U~YeNfQ~JWt>zdL~`:Z\XPNJ~MQy~bHf]^;E_n\+Wx~~jbDJdJ~C`,~CfO&O_KfQ_fiXT~fVa_XpaRW]M~_N~c at gs~h`T~VDdM?VWiMW~dX~>~~Q:KBjfI4D~kJbY~\f%umaXjg:~ua<Pq_c]=jfsIV~JWP~~nh]dm^YW~C~mhU~g;wcOQ=~~am_dncYG~cW~9~~U~\O~[NWc^Y`5Kx,^K5U[QZ\\HG7UUhTsaGB[egR~oiR~VQgXR?7F]~jR~'~[[TgefXekQO`_]H]{_ndX~n_l8CvvZhQlYK~`j_ncY^bXlncncT^XbX~PclQc^YY~JXia?kvXM]nhNqhd_X~Bqq_L>mZ<x^Tg>zj_^Nfchb4fD^ahK [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2295/ccs/fwd np:i:4 rq:f:0.992462
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTAGTCTGGCAGATTAGATACAGCTATAGAGCGAATCACCACGTCTCCTTAGATAACTGGCAAATCTTCACAATTACGCAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTGCACTCCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAAATAGCCATTCTTCCTGAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGAGTGCGAAGCCACTAGTGGTTTGCACTGTTGACCACCAGCAACGCAATCGCAAGATACGCAGTAATGCTAAACCATACTTATTTGACTTTGATGTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGC [...]
   +
-  S_GKVGB?[TFSL,ZRKRFJ[KR/B$PV_ddddb\WTSRNKJMRVXMIKPTLHNWU3M:T=fKCJZEcGJ\VU9X6O>YTEIEJSKLaGS\E\@@FLNQ2\IeFISD>cSV at mR6d_FSKfP.;NeJfFO7B at N;\EdFUYLMfV\I=4bU at dKQ1RAI4deJEXHFZTQ5ZFd>RSS;DU?lR/_F9=DJUEc;bP4EKJE`VKNfTR;V;R8CA*CU\UFJQ%_HI=I9dRK\EdBSAQREOVS[BFO=L7MH1F<ZKfS\FdVJD<IAF'^ZD8J4OUFGSJfFdVJ>cQADPRKKf\K>bKPEJH`>SJeOfVKSKfKVSVWGS<PVKC4=ISKM]G5bZNQZ7,2RBf^F9UGR%:L7V at _FFi\KR,D<H<NeVRJQ>XJAOUGJ<VKU:PUI:<9_P:VXTAMHf\CffK\SBf\F at TJ;cP<CTAH>D:eeEI:BSJ4aRF(SKQ=UDcVJWG8g[WQ:>O4<H\KSQQ>eRKL7QRJc1hR [...]
+  S_GKVGB?[TFSL,ZRKRFJ[KR/B$PV_ddddb\WTSRNKJMRVXMIKPTLHNWU3M:T=fKCJZEcGJ\VU9X6O>YTEIEJSKLaGS\E\@@FLNQ2\IeFISD>cSV at mR6d_FSKfP.;NeJfFO7B at N;\EdFUYLMfV\I=4bU at dKQ1RAI4deJEXHFZTQ5ZFd>RSS;DU?lR/_F9=DJUEc;bP4EKJE`VKNfTR;V;R8CA*CU\UFJQ%_HI=I9dRK\EdBSAQREOVS[BFO=L7MH1F<ZKfS\FdVJD<IAF'^ZD8J4OUFGSJfFdVJ>cQADPRKKf\K>bKPEJH`>SJeOfVKSKfKVSVWGS<PVKC4=ISKM]G5bZNQZ7,2RBf^F9UGR%:L7V at _FFi\KR,D<H<NeVRJQ>XJAOUGJ<VKU:PUI:<9_P:VXTAMHf\CffK\SBf\F at TJ;cP<CTAH>D:eeEI:BSJ4aRF(SKQ=UDcVJWG8g[WQ:>O4<H\KSQQ>eRKL7QRJc1hR [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2295/ccs/rev np:i:4 rq:f:0.976003
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTAGTCTGGCAGATTAGATACAGCTATAGGAGCGAATCACCACGTCTCCTTAGATAACTGGCAAATTCTTCACAATTACGCAAGACCATAGAATAGTCCTAAGCAACATTTGCCGCATCGACCAAATCATGGCTTTTGCACTCAACTTTGCCTGAATCGTGTCAGACTATAGCGGGACGTTCGACCATACTACTCATTCGATTACGCATTCACCTGACGAGAATAGCCATTCTTCCTGAACATACGTTAGAAGTAGTTGGTTAATGCTTGTCTACATTTGACGTGCGAAGCCACTAGGTTTGCACTGTTGACCACCAGCACGCAATCGCAAGATACGCAAGTAATGCTAAACCATACTTATTTGACTTTGATGTTCTATCACTGGGTTAATGCCTGCTGCTACCTGACTTTTAGTCGCGAGCACAACGCTTCTTGGCTA [...]
   +
@@ -543,18 +544,18 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCAAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCTA [...]
   +
   ~~~~~~~a~~a~~f~|ge~{~}~u~%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}z_~zys~~}u~~~~~~}~d~}~~@~q~vb~~S~||~vd~gxz~~~~z_ty~y{|~~f~~}~~~~~f~c~d~cy~;~}~~V~~f~t~g~O~J~~u~Q~~fa~]~O~}F~~~{~~~Dq~~~~t~}~y~f~~,~~~~h~~zu~b~q~e~c~h~~~vdvG~~>~~~~{v|~~~~{~v~}~~uzx\{HUzxK~~~Z~~~h~rc~a~~T~~~~gU~~}s~~~~u~f~~a~|Z~~~{<~~J~~`~|M~~h~r~c~|R~~i~`~~Xsrfj'zya~~q~~}U~~~a~N~gY~~~`~~~g~<~mb~h~~v~`G~I~}W~~V~~~w~ze~~~~}{%~ld~~~>~~{~~~x~M~~h~I0|~hzd~x~B~~jz~l~g~~~|e~[~~~~~t~u{|W~~e~H~~~~U~b|~]~\}YO~~f~~~1~~~~~F~~~oK~ch~~g~~~~{~~r [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2319/ccs/rev np:i:10 rq:f:0.998414
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCAAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGGAACCGACTGGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCTAG [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2319/ccs/rev np:i:10 rq:f:0.998476
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCAAGTAATGCCTCTACGTCAGTCGGAACAATGTCGTCGTGTAACTCGACGATCTTAGGAGCTACTAAGGAGAGTCTGTAGGGAACCGACTGGAAGGTGCCACAAGTTTTCTCTACTACTCCGTCTCCTAAAACAACTCCAAGTGGAAGGTCTGTGGGTTTTTGAGTATAGTCCGTATCTAGACCCAAAAGGGCTTACCTTCGCAATGAAAGAATATCCTTATAGACACGAACGGGAAGAACGGAATCGTTATTAATGACGTCGTACAACGTTTTCCAAGTTCTCCTCTTCCTCCGGATTCGGTTTGGGTTATCTCAACTAGTCCTTTCAAAGACATTGGAGAGTTTCACCTTCCCGTTAAGGTAGAACCCTCAGCATGTTTCACCCCCGGTGACCACTCAGTTACGGAATGTTTTTAAGCCACCTCAGCTAGT [...]
   +
-  O~VSb~~a~t~u}|~~~Q~x{~C_z&~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}y~~\b~~{G~~{~y{_~fxy~~e~W~hz~~o~|tg}~~~~U~}~~~~~~~~}g~~w~~~~a~z~W~c~~f~~w|~~~~c~~g~h~~~]~$~|MvR~={a~~fV~~V~~~{~wS~~~~}wb~uo~oc~~D~~~}g~}~g|S~~~d~\~q~u{J~~[~~>~~~~K~~~wE~~rc~~~xmx~~~{U~~T~~~K~~gh~~U~^~}~~|~~}W~~fw~~x~a~{{~t~}~~~~~{~|W~~S~~x~~h~j~~hwr~vS~{~uw~~~)q~~~~y~i~B~~~Z~{~~u~}Qe~~{B~S~^h~y~{t~|c~f~~G~~K~~~~~{x~~wy~~c~e~~RO~~g~~~o~b~g~t}O~~g~g~o~J~~~`~|~v~\vyc~G~~~~~}z~~d4~~fy/~~~sjh~}~U~~|sf~~w~xfR~T~~~,~~~~x~QT~~X~~}Ku}_~} [...]
+  O~VSb~~a~t~u}|~~~Q~x{~C_z&~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}y~~\b~~{G~~{~y{_~fxy~~e~W~hz~~o~|tg}~~~~U~}~~~~~~~~}g~~w~~~~a~z~W~c~~f~~w|~~~~c~~g~h~~~`~%~LxR~={a~~fV~~V~~~{~wS~~~~}wb~uo~oc~~D~~~}g~}~g|S~~~d~\~q~u{J~~[~~>~~~~K~~~wE~~rc~~~xmx~~~{U~~T~~~K~~gh~~U~^~}~~|~~}W~~fw~~x~a~{{~t~}~~~~~{~|W~~S~~x~~h~j~~hwr~vS~{~uw~~~)q~~~~y~i~B~~~Z~{~~u~}Qe~~{B~S~^h~y~{t~|c~f~~G~~K~~~~~{x~~wy~~c~e~~RO~~g~~~o~b~g~t}O~~g~g~o~J~~~`~|~v~\vyc~G~~~~~}z~~d4~~fy/~~~sjh~}~U~~|sf~~w~xfR~T~~~,~~~~x~QT~~X~~}Ku}_~}| [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2333/ccs/fwd np:i:5 rq:f:0.992602
   AAGCAGTGGTATCAACGCAGAGTACGGGGAATTTAGAGGCCATAGGTTATGGAAAAAGTCAGTGGATTAAGATAGTAAAAGTCGAAATCTTTATATTCGGTTCGATGTACTACGTTATTCGCGACTGTTCTGTCATGATAGTTTTTTATATAGTCCTAATAAAAGGAGTTTTTAAAGTAAATGACATTTCAGTAGTAAAAGTTTAAAGAGCTTTTTGTTCTGCCAGACGTTCTGATAGTTGAGGAAAACGTGTGGTCAGCTAATAACTTGTGGTATGGAGTAAACGAAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATT [...]
   +
   c~YLTIh?~krh]PxOZdYV[Xmsf4~wh6u?k~\ZrJ~RlYeWL~[~Fc;c9y~~qXUfqGkGsPTj+^ZakaZj)o`dXmgZI~~dPB~~mh_V^&J~M|eYYiYTmMZTZWK{EF~bVaXC9?WHsPlZkN[UYIefX/~p`pbDipkp[jCsWL|j7{u_H~ZE'ksn::ii at hE_g>IFTBAr`IPEdWVf)K'.@;no%W?E3Yf7~~~oZCoWm[FwUW0bGYlafY]krY[_YsI~BuwwQYlZk9~iP\XciNhj`~f]~WnG~g`lL~\Zm6~xfZ'tW]oYR~T|UrZkIhUcB;.2SNFX<ZM^LEdm4_]]I|~l^aX:sTSLYqgTG~nV]6~ZGXlQm1ycQmHE}~YnUVmXECdPqfZmb~G~Fs~lfY4t^SYh.dZsUj[7vfYSMMqaEjs=iVqgSzZI^N~e]erT~V~ZlP~\~ogQRXPDAMZsW<`pZ8+^Z5|DO\CDUE{~lZlX[b`G]FeNhVk6;_IZYe [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2333/ccs/rev np:i:6 rq:f:0.994191
-  AAGCAGTGGTATTCAACGCAGAGTACGGGGAATTTAGAGGCATAGGTTATGGAAAAAGTCAGTGGATTAGATAGTAAAAGTCGAAATCTTTATATTCGGTTCGATGTACTACGTTATTCGCGACTGTTCTGTCATTGATAGTTTTTTATATAGTCCTAATAAAAGGAGTTTTTAAAGTAAATGACATTTCAGTAGTAAAAGTTTAAGAGCTTTTTTGTTCTGCCAGACGTTCTGATAGTTGAGGAAAACGTGTGGTCAGCTAATAACTTGTGGTATGGAGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATTG [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2333/ccs/rev np:i:6 rq:f:0.994298
+  AAGCAGTGGTATCAACGCAGAGTACGGGGAATTTAGAGGCATAGGTTATGGAAAAAGTCAGTGGATTAGATAGTAAAAGTCGAAATCTTTATATTCGGTTCGATGTACTACGTTATTCGCGACTGTTCTGTCATTGATAGTTTTTTATATAGTCCTAATAAAAGGAGTTTTTAAAGTAAATGACATTTCAGTAGTAAAAGTTTAAGAGCTTTTTTGTTCTGCCAGACGTTCTGATAGTTGAGGAAAACGTGTGGTCAGCTAATAACTTGTGGTATGGAGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCCTGAGACTATATCATACAAAATTGA [...]
   +
-  4VXVOZR=KC<%RVBkPZ>c^M^XeV9vr^Iq)X_cJ`Ln-XcN?rChLU/[50?d\MENMNZAJZD\HLPSaXV>`Y_^?T`LwwkVDslLOLEVSRw[uVa`aGKdU>]RXMdcNiLTJRRHTL7T at DA-HE3UGQQ=K9`defWegaOd^P9V<VvkEww_?sa[<[RTcKthRiMY^V[_26:NF>b^:KIPFfkgXAH]WqYIDR*^WF6:R)\UVH)xaJbA]*=:DBLbMG4aYM>rEvo\SOYNC5acVf`UUUrXXvWIt^QOuSdd;r`D<BvuU`VtBakGbBfUe_PbP^jfVXvkV`fVk`f`LmV?sdV;u]KU83TlCJ@^fkeLwe`e=vud^O8dEoUEs_Svv_U`fk``EWSfV_?SV+X(_LLOJNvvk`kYv]XYvbEURFgVXviA]dMiW_)UtJPVGoUeVeJyXv]PWvNwd9RV`UJdV`f`5vvdVffUNhD`,YWkB~oRM;5bViaXJPT8<TUDivtNx` [...]
+  4VXVAZQ<EC=(UDjSX>c^M^XeV9vr^Iq)X_cJ`Ln-XcN?rChLU/[50?d\MENMNZAJZD\HLPSaXV>`Y_^?T`LwwkVDslLOLEVSRw[uVa`aGKdU>]RXMdcNiLTJRRHTL7T at DA-HE3UGQQ=K9`defWegaOd^P9V<VvkEww_?sa[<[RTcKthRiMY^V[_26:NF>b^:KIPFfkgXAH]WqYIDR*^WF6:R)\UVH)xaJbA]*=:DBLbMG4aYM>rEvo\SOYNC5acVf`UUUrXXvWIt^QOuSdd;r`D<BvuU`VtBakGbBfUe_PbP^jfVXvkV`fVk`f`LmV?sdV;u]KU83TlCJ@^fkeLwe`e=vud^O8dEoUEs_Svv_U`fk``EWSfV_?SV+X(_LLOJNvvk`kYv]XYvbEURFgVXviA]dMiW_)UtJPVGoUeVeJyXv]PWvNwd9RV`UJdV`f`5vvdVffUNhD`,YWkB~oRM;5bViaXJPT8<TUDivtNx`e [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2334/ccs/fwd np:i:10 rq:f:0.999086
   AAGCAGTGGTATCAACGCAGAGTACGGGGTGGAGAAGCAAATACTTGGATACCGAATTTAGAGGCCATAGGTTATGGAAAAAGTCAGTGGATTAGATAGTAAAAGTCGAAATCTTTATATTCGGTTCGATGTACTACGTTATTCGCGACTGTTCTGTCATGATAGTTTTTTATATAGTCCTAATAAAAGGAGTTTTTAAAGTAAATGACATTTCAGTAGTAAAAGTTTAAGAGCTTTTTGTTCTGCCAGACGTTCTGATAGTTGAGGAAAACGTGTGGTCAGCTAATAACTTGTGGTATGGAGTAAACGAACATCCAACAGTATGTACAATCGTATGAGAAAGGACAAATCTGAAGACGATATTAGAGGGAGTCCAACAAGTTTGTGATGATTCACGTAAGGAAATCGAAATGTAAGATTATTCGTCAATGGAGGTATAAGACAACACACCAAGTAATTATACGCGACGAGTTTTCATGTTGACGATCCC [...]
   +
@@ -667,10 +668,10 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGGAGTACGGGGCTTGTCCGCGAGTGTCAACCGGGTTTTACAAAGGAGAACTTCCAACATCAGTGTATGGGATGTTTCAAACACCCCCAGAGACGGAGACAATAGTGTGGTCACGTACATTTAGGAAGATAAAAATAACAACAACAGAAGGTGTGAGGCGCAAGGTACATGCTCTTACCCCACTCTCAGCACGTAGGGAGCGGAGTGTGGGAAGACCAACAAGCCCGTCGCCTCTACCAAATACAGTGTTTAGGTGTGTCGGAGGGCAGAAACCAACGAAAGAAAGGAAACGATCAACACTTATATAGTGTCCTGTCGGGCCCAAATCCTAAGAGACCTTAGGTTTACCACATTAGTACTAAACAGCCTGTTGTATACCGTGAGCCCCCCACTTCGATCTGTAAAATGGTAATCCCTTGTAAAACCTCATCTCCAAAAACAGTATACGCAGGTACAGCTGATGTGATCCTCT [...]
   +
   KZA<P=@CqUIXXKtXSYV0WE?B/3$?XqKIX4H:kOV9H?cV^kR~Gy?~~<\~~yWN~vT~zPMsS*kJ~M~o|smads^]xlH~~s at b5~yj<~qh[D~~~~abHbzjJ`lOrmV~VYOCVC:SV[p_N\fGd5~yzU~PbKgm2~~~j]g~nUsnl~o|fV~D~XKYc{B~lbk?j:`C(9sGa*mnP~z=~}qyX^V^Zx_Szoblv1{ccN_LuschfG%ngazM{[~Aw:Jnb1ttOZ[PV|RWk^J~D~rm`QqbZ`2vzxEeCSL=ZYU~o3~zladL~uZzj~XdNuue7nfS~0ne[M^YUOtns)Kp\SmZugk^r]~pLm`?~~E~~N~~s\~Zf~gyQz]~b~|V~D~|yI~zox@~yblxn\P~~nzPIzmh^~di|sxW~`[`vc$s~~qkq?EI)LzrYrfo%v^0<;~Ve~qC~sLkdX9~tnZ~VTU_UQ0~9~~~~n|gpZT`ngotO~r{ozQl\f|sfqd3p]~mi\ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2772/ccs/fwd np:i:6 rq:f:0.993765
-  AGCAGTGGTATCAACGCAGAGTACGGGGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCCTGGATGCAATTGTGCTCGCCATTTCAACTTAGTGCAGTTGCTAAAGTGCCAACTAAGGTTCGTCTTGAAGC [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2772/ccs/fwd np:i:6 rq:f:0.994156
+  AGCAGTGGTATCAACGCAGAGTACGGGGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCCTGGATGCAATTGTGCTCGCCATTTCAACTTAGTGCAGTTGCTAAAGTGCCAACTAAGGTTCGTCTTGAAGC [...]
   +
-  .JYcL?>gfedL0rW_S2C_]d7K4||yX]Mf4r]_Q@]aUSdEz?69p83\ELcf at e:TJ7yaFadeHR\Cw}OX`5rbS+aVRXN^6YHViXPL~|\YI?[C.DID8<N^V2^aZS\F{Ph^C_i>kWQ[`-ixj`ZG~S~j`0~KA|~aib\cXi_;_[ah[hafE`F~O,WJZ;nra>bb].]YXy[MVaK~gZ~JX+s`rBEZXfQhgZaVIB;R~f2@`z_QW\XWxB_<JN<\'89Q]BcBeTEd1M[0LnhN>jX|cVJ?SH0x|fC^R8,AfGdQ)^=BQ+Z_BHCQNnY7jU`f9N_i[BxaK~aS_UI0|}YhIDQ<HYIhYQ`J~QV4OEd`jh`:~ha[Y~ajR~j`@~s]NVUIrtM,GYhQ`eF_.o7YhahQeX^KK&WES<nOdjhjR~[ifE~`gEP|2gsiR~b_]WVfY|Jh_5`E\E^JGdXOG}Y-ea[f5V9OU~`TLHInJh_HfF}Zf5zQ~Z~E^NZXy83aWY [...]
+  .JYcL?>gfedL0rW_S2C_]d7K4||yX]Mf4r]_Q@]aUSdEz?69p83\ELcf at e:TJ7yaFadeHR\Cw}OX`5rbS+aVRXN^6YHViXPL~|\YI?[C.DID8<N^V2^aZS\F{Ph^C_i>kWQ[`-ixj`ZG~S~j`0~KA|~aib\cXi_;_[ah[hafE`F~O,WJZ;nra>bb].]YXy[MVaK~gZ~JX+s`rBEZXfQhgZaVIB;R~f2@`z_QW\XWxB_<JN<\'89Q]BcBeTEd1M[0LnhN>jX|cVJ?SH0x|fC^R8,AfGdQ)^=BQ+Z_BHCQNnY7jU`f9N_i[BxaK~aS_UI0|}YhIDQ<HYIhYQ`J~QV4OEd`jh`:~ha[Y~ajR~j`@~s]NVUIrtM,GYhQ`eF_.o7YhahQeX^KK&WES<nOdjhjR~[ifE~`gEP|2gsiR~b_]WVfY|Jh_5`E\E^JGdXOG}Y-ea[f5V9OU~`TLHInJh_HfF}Zf5zQ~Z~E^NZXy83aWY [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2772/ccs/rev np:i:5 rq:f:0.992486
   AAGCAGTTGGTATCAACGCAGAGTACGGGGCGATGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGCTCGCCACAGCGGTGGCATATGTCCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGTGTGTTATAGTTTACGCTAGTCCAATCTGTATCGTGGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAATTGTGCTCGCCATTTCAACTAGTGCAGTTGCTAAAGTGCCAACTAAGGTTCGTCTTGAA [...]
   +
@@ -723,18 +724,18 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATTGAACATGGATGCGAACGACATTTCGAAATATACGCAATGAATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTGAGACAATG [...]
   +
   BhRXXM:<`J^]EQw[RH^R]>^_L/^WEIU6\OCK>*c\EHBW'ENHEGO/]M-U=,PKMaC[IAY=J91LPc[S^[_;ttYN=]h]Z_GHS[E_DA&Y_G]9q>tFvw`\)YNA;c[ZNQ;q_Pt'B@[ZN?]=UW]O at D\G^[_KR;dD7MG<Grp\SIV[RC`AKZS[S[O7_YHF2$$DnpW^A4]IOFGZRMR_8wp[\3luqHB\^?eGww\?>Y5wwVEBs+I[^/ZX`\F:qs[TGQtRER]E[=FWSY]@Md^_;w^E`BtXKFvPt=LO;M2]X>\Y5P`[RuS^Ewk>nS^G^Qv`\.^YSN\JqUNG\FEy`QvRK9uuD at uWX^?BfE=S\5;m,JSM>L*X^8.5Y(ta]@\Oj[^OLu^Q6[RGZS_[PG_R_<tW\S_[^Ta[^`RIV]X1F(Yp\9mY>NnT`[^`Sa^P[CvCoM`[`]E=uq_[[]0pP?tR^[PGJbBKt`ZAcDPDY[]RBuZRAs\=6PZMGZQv`S [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2903/ccs/fwd np:i:6 rq:f:0.993546
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTACTGGTTCGTACAGCGGTAAATGACTTGTTGAGTCTTGACGTCGACGACCAAAGCGACCACTTTGACCCAATTGCGAACTACTAAATCCTAAGCAAAGACTATTAGGTAGTAGCCAACTTCGTTAATTCCGTTCAGTACTTTTAAAATTCTAAACCGACCATCTTTCCGAGTTGCTTCAAACCCTCGTCCTAATGATTTTACATCGAATAGAACGTCGTAACAAACGCACTACTACATGGAATAGATTCTCTTGTCAAATCGTTTTGTTTTGGCTTTACCCTTGGTAACAAACTTCGACTACGTTCGTACAATTCAGAATAACCTCTACCTCGTTAATTTGAGTTAGTTCGTTAAGGGCTTAAGTAGTTTATTTCTATGATAAGCACTAAATTGACCCTTAATTTCCTCGACTTATTGTTACATCTCGATTTCCCT [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2903/ccs/fwd np:i:6 rq:f:0.993549
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTACTGGTTCGTACAGCGGTAAATGACTTGTTGAGTCTTGACGTCGACGACCAAAGCGACCACTTTGACCCAATTGCGAACTACTAAATCCTAAGCAAAGACTATTAGGTAGTAGCCAACTTCGTTAATTCCGTTCAGTACTTTTAAAATTCTAAACCGACCATCTTTCCGAGTTGCTTCAAACCCTCGTCCTAATGATTTTACATCGAATAGAACGTCGTAACAAACGCACTACTACATGGAATAGATTCTCTTGTCAAATCGTTTTGTTTTGGCTTTACCCTTGGTAACAAACTTCGACTACGTTCGTACAATTCAGAATAACCTCTACCTCGTTAATTTGAGTTAGTTCGTTAAGGGCTTAAGTAGTTTATTTCTATGATAAGCACTAAATTGACCCTTAATTTCCTCGACTTATTGTTACATCTCGATTTCCCT [...]
   +
-  a~lTShT2xea`TU`RQ at ejRWnRU$|}}}}}}}}}}}}}}}}}}}}}{qjkmSL>nVy:zRjogSUiUZ~oN~~ng_I]tfL{iSkiVK}khSSlDT`Sif>IMp~kUkd+^>AQz~kg2~rStNxSUi3xTnSUp=ccjG~oG|kUMq{RPBMXYtNY~qhll?iEiDnS7{Rg\{UvYpE~OBb=WUU>G/WHF&d`IG['^)D1,O;J$U6>>FZ\0h)MSYa]0IWQ>sN,MenTjT1uPPXJQ\&p{dbS9iP>Dznfj7zVioViR&CR?]`@kSM?lhVoe at MiV}5yS>PWOyUlV]xTnV>||WUk:~~}kM~~zF{U@}xa,kg_~IonBcB>v{TO{UfPTob*cYwQ>Z=SVg^|VhkE~iQVF}oVk*)poQeM{U`.}lc;hM}gl\fTT[zD_>WwS6qUlkgf[6LVQ>{}TTOjiF>F]RReVn=||McSQ/mg\yTw6||D~kSkhV\}T\~fEaLC_PSQ?ihP~n;~t[ [...]
+  a~lTShT2xea`TU`RQ at ejRWnRU$|}}}}}}}}}}}}}}}}}}}}}{qjkmSL>nVy:zRjogSUiUZ~oN~~ng_I]tfL{iSkiVK}khSSlDT`Sif>IMp~kUkd+^>AQz~kg2~rStNxSUi3xTnSUp=ccjG~oG|kUMq{RPBMXYtNY~qhll?iEiDnS7{Rg\{UvYpE~OBb=WUU>G/WHF&d`IG['^)D1,O;J$U6>>FZ\0h)MSYa]0IWQ>sN,MenTjT1uPPXJQ\&p{dbS9iP>Dznfj7zVioViR&CR?]`@kSM?lhVoe at MiV}5yS>PWOyUlV]xTnV>||WUk:~~}kM~~zF{U@}xa,kg_~IonBcB>v{TO{UfPTob*cYwQ>Z=SVg^|VhkE~iQVF}oVk*)poQeM{U`.}lc;hM}gl\fTT[zD_>WwS6qUlkgf[6LVQ>{}TTOjiF>F]RReVn=||McSQ/mg\yTw6||D~kSkhV\}T\~fEaLC_PSQ?ihP~n;~t[ [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2903/ccs/rev np:i:6 rq:f:0.991972
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTACTGGTTCGTACAGCGGTAAATGACTTGTTGAGTCTTGACGTCGACGACCAAAGCGACCACTTTGACCCAATTGCGAACTACTAAATCCTAAGCAAAGGACTATTAGGTAGTAGCCAACTTCGTTAATTCCGTTCAGTACTTTTAAATTCTAACCGACCATCTTTTCCGAGTTGCTTCAAACCCTCGTCCTAATGATTTACATCGAATAGAACGTCGTACAAACGCACTACTACATGGAATAGATTCTCTTGTCAAATCGTTTTGTTTTGGCTTTACCCTTGGTAACAAACTTCGACTACGTTCGTACAATTCAGAATAACCTCTACCTCGTTAATTTGAGTTAGTTCGTTAAGGGCTTAAGTAGTTATTTTCTATGATAAGCACTAAATTGACCTTAATTTCCTCGACTTATTGTTACATCTCGATTTCCCTT [...]
   +
   1[UloCP1PcU:Q\yQTkmVVTSjj%||{whSKOXZY_b`XPKMVdqrja[UOQiqneI>cU}lDRTjoUP?haCu^gVo`9GCOvQOShl/_VojTTiAWjWnIpG~qAjSgIlnkB~{RTI`v\tR`Oh+YZjNPi`Agg`XpgM}Uj8sp'V^Y\TF_nD~dkWhkRZ~`~R8sgQ+]L]7zV~QClOPOQmk:uV_BtvE^PdHo0`WoZ~k^k$wlRD^BOUQrVlW~SC~pK{macA_W~_[MQUWNSg`RcEPNTd5BNVpaOI`N^bJIp_D7Q(H at O_VD__J?xTm]cMXJsa\INlM4^:r]I`M7bojM at kraBu`0n_RIim9]0g^Ur`1YeN+7N(IKIc`;+R]N[^`VpLsadNQd_TpRq^_XEB\5OL.kUpFrnNdNMq^NLraNM[Rf7jcI9iUnO]`D8.J-`Sc^HaHHE[MdN]Xa\;3d'9;KPn)h=Q7noMn3TLLZKhaLqGHi`^DZa^aO`DYkHqqK^ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2944/ccs/fwd np:i:8 rq:f:0.995773
-  AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATAATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCCACCTCAACGCTATGAACGTTAGTTGAGACA [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2944/ccs/fwd np:i:8 rq:f:0.995775
+  AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGTAAAACTTGTCACCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATAATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCTAGACAGTCATGTCTCTTCCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCCACCTCAACGCTATGAACGTTAGTTGAGACA [...]
   +
-  dpZCn[[Z~qH[@.tOWBaj_mZZLAm~~d~K~viX_E~~^p2~ZCb]QkrJ~tN~svn`}R\_Z~an1Pa@|Tj%I4Td~VmEgguswm at mDQg\jL[bt,vTNn7m~[W*ZYQ~aTtYT_{`FvV~mvpXO{L~ttlPYG_sUS\Z$s\eiijm9~~vNj=EMWcenj`B_gKFwwleXubAuumhWDpuPfSXjRfdgGU`=f.[f5,gjR+|@kumRqlIwvuOWuPWLV'qs~i at nY/Lg;A9LbBNheiJEJjP4_hjGpDWjQuW[DeG^AVCfSMuPadLjdYLKtfg8ugKmMjijJugVTe;SUk;WlfYXI=8hKvdlGwvMHqNdic,rjfW(hg<^QjNeYveNf at ltM0qrk@s6WKZS9~^PWDF3JaiNeeTM='bdcjNkeSJQUd`KeI0>/e\fj6uvdYvgmK1ifmk`=Qu,VShNmgL*tvsVNWZu^QqekQgi%~ZX6VUBGj:aLjEDe+QKeLmje^wcfYU8U [...]
+  dpZCn[[Z~qH[@.tOWBaj_mZZLAm~~d~K~viX_E~~^p2~ZCb]QkrJ~tN~svn`}R\_Z~an1Pa@|Tj%I4Td~VmEgguswm at mDQg\jL[bt,vTNn7m~[W*ZYQ~aTtYT_{`FvV~mvpXO{L~ttlPYG_sUS\Z$s\eiijm9~~vNj=EMWcenj`B_gKFwwleXubAuumhWDpuPfSXjRfdgGU`=f.[f5,gjR+|@kumRqlIwvuOWuPWLV'qs~i at nY/Lg;A9LbBNheiJEJjP4_hjGpDWjQuW[DeG^AVCfSMuPadLjdYLKtfg8ugKmMjijJugVTe;SUk;WlfYXI=8hKvdlGwvMHqNdic,rjfW(hg<^QjNeYveNf at ltM0qrk@s6WKZS9~^PWDF3JaiNeeTM='bdcjNkeSJQUd`KeI0>/e\fj6uvdYvgmK1ifmk`=Qu,VShNmgL*tvsVNWZu^QqekQgi%~ZX6VUBGj:aLjEDe+QKeLmje^wcfYU8U [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/2944/ccs/rev np:i:8 rq:f:0.996531
   AAGCAGTGGTATCAACGCAGAGTACGGGGTTGGTGTATTTATCCGCTACGTGGGTGGATGAACATGGATGCGAACGACATTTCGAAATATACGCAATGATATCCAACCCTACCGAAACAGCAATAATTGTAGAAGGTAGCATATCATGCCGAGAGTTTACTACGTTGTAGCGAGTTTAGTTGAAATAGTTTGTGATGTGTAAACTAAAACATACCAAATGGGTAAACTTGTCACCCCCATTTACATTGCGACAGACACAGTTATGGAGTGGATGGAAGTGTGTTCGACTGTCAAGACCCTTCTATAATAGTCGAACCAGTACGGTAAGTGGGCAACATGCCCATATAAGTCGAAGCATTTCAAATGGTTCATCCAGTAGACGACGATGTCCTAGACAGTCATGTCTCTTCCCATTTGAAGTCATGTAGTGGTTGTCTACTTTTTCATTGAAGACGTCCACCTCAACGCTATGAACGTTAGTTGAGACAAT [...]
   +
@@ -787,18 +788,18 @@ Test ccs on 100 zmws from the lexogen-SIRV dataset, using --byStrand
   AAGCAGTGGTATCAACGCAGAGTACGGGGGGCGACAATTGTGGACCGTATGGACTCCATTATGCTGGACTCCTCGGGTCAACCGCTCTAAAGCGAAGTTGTTGGACAAACAGTTATGCGTAACTGTAAAGCAAGGTGCCCAAAGTAGACTGAGCGACAGTCGAAACCAGCCCCAATGAACAAGACGCCATTGCAAAACGTCTATACGCTACGGTCAAAGACGCTTCCACACCACATGCTCTCATGTAGCCTACCTTACGAAGAAATCGCACAAGTCGGTCGCCCAGCGGTGGCATATGTCTTGCCTAACGTTTCTAGACCGATCAGCCTCACGAGTAGCCTGCTTGTGGTGTTTATAGTTTACGCTAGTCCAATCTGTATCGTGCCGCTTGGTATGGCTATTGTCGGCCTGGATGCAAGCACTAACGTGGTCATCAGACTGGTCTGCGCTATAATCTACGCAATAGAGGCACCAGCGGTCGTTTGAAGCC [...]
   +
   C~]h]`0 at wkVZdS~e_Wuduer]i4~wowp`_\gGy:~S\GytX~foqGDw\eqG~l1{OEVip3~rho6~rfE^I\hR~Y~dRYRY?~|ehP`~_Vxe_~Pxoh7~~_ccO~q.Zgb\d~hW2kJ~~Lge~Q~VKN~~@~hNF^boeoHV\<Isiteaed=~vU~[b6~~`UWS]Q~gBr_UN`CvbJ~Jd9~~|hN^c at R=dhdhsuhQupQK~~dte_i^~Vztg\Y~uit\baAfrivpOmULW~]sV~LwnRcJnNI~~rieeXba~bZSDgXbdGyb\WcDnaG~aflnYcnRV~PM|[S~ie>~{gEn9lU~fVriueW~\gefeucFpM6j\ch:eJC&=ANKpvSVk^F~~\eMbfl`WY~c~qjoOn\ph_SfY~eiV~PsGq`3yNmVO~drh?mF~[U~rGbhQ~eh\dkP~hcF?~TcmriZJjaDQ~qhZSSTiilZNnUcoWfdRP~VretD~dmM~sLdQqrgK,~kdb~KMn [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/3119/ccs/fwd np:i:6 rq:f:0.99553
-  AAGCAGTGGTATCAACGCAGAGTACGGGGCATACTGCAAGACTTGTAGGCCCATGAATTACCCGCTTAGGCAATGGGTAGACCTTTCCTTGCCGCGTGGAACAAACCGCCATGAGTGTTTTACGTTTACGGTCGGCGACCGGAGTCACAGCGCGACCAACGGGGCCAGGCAAAGGCCCATAGGCCTTTTCCATCGGCACGCGACCGATTCCATCAAGTGTTAGGTGCAATCCCATTCGGGGACGGACACGCGAGAGCGTTAGTCGGCGCGTGCGCGGACTATTTAGCGAAGGTCGCCGATCGTTTGCCCGTAAAACTAACTGGCAAAAGCCTAAGTGCTGTTTCGGGTGCAATGGTATAACTTCCCACATTTAGCCGAATAGCGCCAACAGCGTTATTATTTGGAACCAAGCAGTGGGCGATGTCAGCGACAATTCCACTTTGGTAGAGGTCGTTCTTTTGTAGAAAACAATCTAACATAACTATGACAC [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/3119/ccs/fwd np:i:6 rq:f:0.995712
+  AAGCAGTGGTATCAACGCAGAGTACGGGGCATACTGCAAGACTTGTAGGCCCATGAATTACCCGCTTAGGCAATGGGTAGACCTTTCCTTGCCGCGTGGAACAAACCGCCATGAGTGTTTTACGTTTACGGTCGGCGACCGGAGTCACAGCGCGACCAACGGGGCCAGGCAAAGGCCCATAGGCCTTTTCCATCGGCACGCGACCGATTCCATCAAGTGTTAGGTGCAATCCCATTCGGGGACGGACACGCGAGAGCGTTAGTCGGCGCGTGCGCGGACTATTTAGCGAAGGTCGCCGATCGTTTGCCCGTAAAACTAACTGGCAAAAGCCTAAGTGCTGTTTCGGGTGCAATGGTATAACTTCCCACATTTAGCCGAATAGCGCCAACAGCGTTATTATTTGGAACCAAGCAGTGGGCGATGTCAGCGACAATTCCACTTTGGTAGAGGTCGTTCTTTTGTAGAAAACAATCTAACATAACTATGACAC [...]
   +
-  [~FD^E_ at zfMOX4yE[F_YP]d6VA~~~ZNMd\d. at 5k]ODE}]he7w2nx]h]F~V~dD~{Z\Z~gO~\X~f6~y\L^bK|>x`Mx*JN/XW\]c8'>NZ3p_Ls^KS7e[%X`Y=y~~f\]>~~f\Q~h]O~\]I(]El,\d/cZP]\\F[MKgAr;=icP3kCMrNCbcNq.[`SVFMh'F;bafEfOWMFLLQPXNA at 3o\RY~A~edFW~^hX0yOOyPEGB`b%=RMIp[$p[Y]FEB%ETK]YGd]NF[\A~P]h[BfIOI>c5W4B)]LZcN8SScEK<EbOuOZ[*eGeh\]9[eC7at^g<~~fEeFfDfCaEAr~{^JfeCdUE\ULEGz|[6~a3D[X~hO~U>UHeZFj6eVJW^Fyzg];|[/_Ld[X]=tGuZJX\^X~:Go:JmaP~NlKw4_HWOYc7}}VZbZc`R;dVgF`E}_~N~WMJ{b/~bBajT~neQ^qO%~~~PjKOB~~Y:Lql`nU~fpYN~eoDndm`[] [...]
+  [~FD^E_ at zfMOX4yE[F_YP]d6VA~~~ZNMd\d. at 5k]ODE}]he7w2nx]h]F~V~dD~{Z\Z~gO~\X~f6~y\L^bK|>x`Mx*JN/XW\]c8'>NZ3p_Ls^KS7e[%X`Y=y~~f\]>~~f\Q~h]O~\]I(]El,\d/cZP]\\F[MKgAr;=icP3kCMrNCbcNq.[`SVFMh'F;bafEfOWMFLLQPXNA at 3o\RY~A~edFW~^hX0yOOyPEGB`b%=RMIp[$p[Y]FEB%ETK]YGd]NF[\A~P]h[BfIOI>c5W4B)]LZcN8SScEK<EbOuOZ[*eGeh\]9[eC7at^g<~~fEeFfDfCaEAr~{^JfeCdUE\ULEGz|[6~a3D[X~hO~U>UHeZFj6eVJW^Fyzg];|[/_Ld[X]=tGuZJX\^X~:Go:JmaP~NlKw4_HWOYc7}}VZbZc`R;dVgF`E}_~N~WMJ{b/~bBajT~neQ^qO%~~~PjKOB~~Y:Lql`nU~fpYN~eoDndm`[] [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/3119/ccs/rev np:i:6 rq:f:0.992635
   AAGCAGTGGTATCAACGCAGAGTACGGGGCAATACTGCAAGACTTGTAGGCCCATGAATTACCCGCTTAGGCAATGGGTAGACCTTTCCTTGCCGCGTGGAACAAACCGCCATGAGTGTTTTACGTTTACGGTCGGCGACCGGAGTCACAGCGCGACCAACGGGGCCAGGCAAAGGCCCATAGGCTTTTCCATCGGCACGCGACCGATTCCATCAAGTGTTAGGTGCAATCCCCATTCGGGACGGACACGCGAAGAGCGTTAGTCGGCGCGTGCGCGGGACTATTTAGCGAAGGTCGCCGATCGTTTGCCCGTAAAAACTAACTGGCAAAAGCCTAAGTTGCTGTTTCGGGTGCAATGGTATAACTTCCCACATTTAGCCGGAATAGCGCCAACAGCGTTATTATTTGGAACCAAGCAGTGGGCGATGTCAGCGACAATTCCACTTTGGTAGAGGTCGTTCTTTTGTAGAAAACAATCTAACATAACTAT [...]
   +
   %a+DcWa<]=df]I~]XYTENJegP(cy|]&OPJZPYGW~\h_JgHegFr<YcXf\Un>h03v{DX,t[Lz]VadCyeQb-4Nl9v^MdAtUO{[QIQKfZ~\;liDbTN~gPZa<[ZGt~~h^\J~qZBM~g^M~^\b;Q8wIXbYh^hYGX\BeL|?X]<~~~P~eJdZ9Yo:z6~z^ehM~^<zbX=_'JN;Z\hZVTYR8UCcRYKaceGW|[>,>LV=id[\C^b?uatfFh]D~maHMnO\fSVXG9,DQCO[UcgKf]L}]JHDdF\XY5}~g^bd=UV_W^[UyM~gZG=kW5K\F7Vm[>~mVf,]btaZgF|(N7yB,t^pC:gNTvI$SYZg[4}p\,]LMV.Vxb,=2=`RaARzD~hJVA7YZfW:x.ZVf&aC/TI\MiZX[^ZM`=8\T2{H*ySwJv3yVVMOd8~~ZRJCCI/bF[EeIDkMlO}f\;bbJ}Lf\hMe;\[A}U/MAQHMMY3ziZ]Ipf^gX}EegV~]OeJ [...]
-  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/3147/ccs/fwd np:i:7 rq:f:0.995375
-  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCTATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCCTAGTCCCGGACTCACCGAACCTACACCGTTCCTTCAGTGTGTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTGTGGGCTAGGGCACCGCGTTTTGAAGTAATAGATGTAACCTACCACCCATAAACTGCTCTAAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGAGAATTTACGGTGGTAATTTCGCACACTTCGCACGTTTA [...]
+  @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/3147/ccs/fwd np:i:7 rq:f:0.99463
+  AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCTATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCCTAGTCCCGGACTCACCGAACCTACACCGTTCCTTCAGTGTGTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCGGTCTACTATCCATCGTTCATGTTCGGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTGTGGGCTAGGGCACCGCGTTTTGAAGTAATAGATGTAACCTACACCCATAAACTGCTCTAAACAATTTAAGTTCGTCGTCGGCCTTCTTTTTATATCACTAACGTGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGAGAATTTACGGTGGTAATTTCGCACACTTCGCACGTTTA [...]
   +
-  Ar:GV<i>pQ]f9Kh7FJZY^]kIG%hllllllllllkfabgllllllllllk60r`Zb[Hm^G\^Kh^MY_L^>rKKjV^M]UJj=y\ZJWRNp[GK%nmn_Wf&^RKhBCXDF;\WPm.^U at 2R6_HNh.yJWF5X`\e]YeHCl]KHe^]j\[PJ0mfVUYK\[jHgT;MO/m7Zc9T\<Z6h?{^lK][PHYSZ]cG*;6IcOSG8OS\9kX1ZZbIB^<PZ>cPe]I5kkYJNmb]E'WU at mmKo]2kkK^<xWKW:oom\LmYg,LIWY\X[kEc>xkH7G\7^hV`4n[Jo\HdFV4V7.CABmlMo]Y`J\lK\lFw;r_lJ6iln]Jj\VKNLd?kIGi]k_6b][=r^j^J`EJXKlJ0S7dhYeYKWfQP45WTGAe[HMHDkk\j7 at co\Z.aZMmKiB_5Y96>hbLlJkFF95VZWX]FYk7[RFKINPgJ^ZR^MoB2NSEmlZHKml;ukAlHnnG[7[D at 97E8X5H9]Arqb [...]
+  Ar:GV<i>pQ]f9Kh7FJZY^]kIG%hllllllllllkfabgllllllllllk60r`Zb[Hm^G\^Kh^MY_L^>rKKjV^M]UJj=y\ZJWRNp[GK%nmn_Wf&^RKhBCXDF;\WPm.^U at 2R6_HNh.yJWF5X`\e]YeHCl]KHe^]j\[PJ0mfVUYK\[jHgT;MO/m7Zc9T\<Z6h?{^lK][PHYSZ]cG*;6IcOSG8OS\9kX1ZZbIB^<PZ>cPe]I5kkYJNmb]E'WU at mmKo]2kkK^<xWKW:oom\LmYg,LIWY\X[kEb>wjD$Y6I_V\4n[Jo\HdFV4V7.CABmlMo]Y`J\lK\lJ&><|_lJ6iln]Jj\VKNLd?kIGi]k_6b][=r^j^J`EJXKlJ0S7dhYeYKWfQP45WTGAe[HMHDkk\j7 at co\Z.aZMmKiB_5Y96>hbLlJkFF95VZWX]FYk7[RFKINPgJ^ZR^MoB2NSEmlZHKml;ukAlHnnG[7[D at 97E8X5H9]Arqb [...]
   @m150825_055401_42161_c100844482550000001823159012311525_s1_p0/3147/ccs/rev np:i:6 rq:f:0.993731
   AAGCAGTGGTATCAACGCAGAGTACTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCTATACTACGAGGACGTCACCACTGAGGTCTCCGACATGGACACCTAGTCCCGGACTCACCGAACCTACACCGTTCCCTTCAGTGTGTTCTTTCGGAGTAGTGAAAAAACGTTGGTCTTCCCGGTCTACTATCCATCGTTCATGTTCGCTTTTACAAGTTACCTTCAACAATTTTACAAAGCAATGCTTGTGGGCTAGGCACCGCGTTTTGAAGTAAATAGATGTAACCTACCACCCATAAACTGCTCTAACAATTTAAGTTCGTCGTCGCCTTCTTTTTATATCACTAACGATGTACCTACCTTAGAGCGTTACCAAAGTACATATACAGATTTCTCAATGTATTTGACCTGGCTCTCTGCAATCTCTCTCAAGATGCGTAAGCACTTTCAGTAGGACGAATTTACGGTGGTAATTTCGCACACTTCGCACGT [...]
   +
diff --git a/tests/cram/tiny.t b/tests/cram/tiny.t
index a997a8d..7464a84 100644
--- a/tests/cram/tiny.t
+++ b/tests/cram/tiny.t
@@ -9,7 +9,7 @@ Test a tiny collection of a few ZMWs, write to FASTQ for inspection
   @m150404_101626_42267_c100807920800000001823174110291514_s1_p0/109700/ccs np:i:18 rq:f:0.999452
   GCGTGCTTGTGGTGGGTAACCGTCGTATTCCCGGCGCGTTTATTCAGCAACTGAAAAATGGCCGGTGGCATGTCATGCAGCGTGTGGCTGGGAAAAACCGTTACCCCATTGATGTGGTGAAAATCCCGATGGCGGTGCCGCTGACCACGGCGTTTAAACAAAATATTGAGCGGATACGGCGTGAACGTCTTCCGAAAGAGCTGGGCTATGCGCTGCAGCATCAACTGAGGATGGTAATAAAGCGATGAAACATACTGAACTCCGTGCAGCCGTACTGGATGCACTGGAGAAGCATGACACCGGGGCGACGTTTTTTGATGGTCGCCCCGCTGTTTTTGATGAGGCGGATTTTCCGGCAGTTGCCGTTTATCTCACCGGCGCTGAATACACGGGCGAAGAGCTGGACAGCGATACCTGGCAGGCGGAGCTGCATATCGAAGTTTTCCTGCCTGCTCAGGTGCCGGATTCAGAGCTGGATGCGTGGATGGAG [...]
   +
-  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|~~~~~~~~~{~~~~:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2~~~~~~~~~~m~~~~~~~~~~~~~~~d~~~~m~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Y~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~u~~~~~~~~%~~~~~~~~~~~~~a~~~~~~~3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [...]
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|~~~~~~~~~{~~~~:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2~~~~~~~~~~m~~~~~~~~~~~~~~~d~~~~l~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Y~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~u~~~~~~~~%~~~~~~~~~~~~~a~~~~~~~3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [...]
   @m150404_101626_42267_c100807920800000001823174110291514_s1_p0/110513/ccs np:i:25 rq:f:0.999989
   AAAACTGTACGATAAACGGTACGCTGAGGGCGGAAAAAATCGTCGGGGACATTGTAAAGGCGGCGAGCGCGGCTTTTCCGCGCCAGCGTGAAAGCAGTGTGGACTGGCCGTCAGGTACCCGTACTGTCACCGTGACCGATGACCATCCTTTTGATCGCCAGATAGTGGTGCTTCCGCTGACGTTTCGCGGAAGTAAGCGTACTGTCAGCGGCAGGACAACGTATTCGATGTGTTATCTGAAAGTACTGATGAACGGTGCGGTGATTTATGATGGCGCGGCGAACGAGGCGGTACAGGTGTTCTCCCGTATTGTTGACATGCCAGCGGGTCGGGGAAACGTGATCCTGACGTTCACGCTTACGTCCACACGGCATTCGGCAGATATTCCGCCGTATACGTTTGCCAGCGATGTGCAGGTTATGGTGATTAAGAAACAGGCGCTGGGCATCAGCGTGGTCTGAGTGTGTTACAGAGGTTCGTCCGGGAACGG [...]
   +
diff --git a/tests/python/test_tool_contract.py b/tests/python/test_tool_contract.py
index de47ca1..30a41cd 100755
--- a/tests/python/test_tool_contract.py
+++ b/tests/python/test_tool_contract.py
@@ -22,7 +22,7 @@ CHUNK_INDEX = 1
 
 class TestCCSApp(pbcommand.testkit.PbTestApp):
     # FIXME eventually the 'ccs' binary should handle TCI directly
-    DRIVER_BASE = op.join(CCS_DIR, "scripts", "task_pbccs_ccs")
+    DRIVER_BASE = os.environ['__PBTEST_CCS_EXE']
     REQUIRES_PBCORE = True
     INPUT_FILES = [tempfile.NamedTemporaryFile(suffix=".subreadset.xml").name]
     TASK_OPTIONS = {
diff --git a/tests/unit/TestConsensus.cpp b/tests/unit/TestConsensus.cpp
index 17a8ca8..f2ea29b 100644
--- a/tests/unit/TestConsensus.cpp
+++ b/tests/unit/TestConsensus.cpp
@@ -41,12 +41,13 @@
 #include <pbbam/Accuracy.h>
 #include <pbbam/LocalContextFlags.h>
 
+#include <pbcopper/cli/CLI.h>
+
 #include <pacbio/ccs/Consensus.h>
+#include <pacbio/ccs/ConsensusSettings.h>
 #include <pacbio/data/ReadId.h>
 #include <pacbio/data/SubreadResultCounter.h>
 
-#include <OptionParser.h>
-
 using namespace PacBio::CCS;
 typedef ReadType<ReadId> Subread;
 
@@ -63,10 +64,7 @@ TEST(ConsensusTest, TestReadFilter)
                                   std::vector<uint8_t>(seq.size(), 0), flags, .99});
     }
 
-    auto parser = optparse::OptionParser();
-    ConsensusSettings::AddOptions(&parser);
-    const auto options = parser.parse_args({});
-    ConsensusSettings settings(options);
+    ConsensusSettings settings(PacBio::CLI::Results(ConsensusSettings::CreateCLI("", "")));
     settings.MinLength = 10;
     settings.MinReadScore = 0.0;
 
diff --git a/tests/unit/TestIntegrator.cpp b/tests/unit/TestIntegrator.cpp
index 6ac09b7..09f6ea4 100644
--- a/tests/unit/TestIntegrator.cpp
+++ b/tests/unit/TestIntegrator.cpp
@@ -111,7 +111,7 @@ const IntegratorConfig cfg(std::numeric_limits<double>::quiet_NaN());
 
 Read MkRead(const string& seq, const SNR& snr, const string& mdl, const vector<uint8_t>& pw)
 {
-    vector<uint8_t> ipd(0, seq.length());
+    vector<uint8_t> ipd(seq.length(), 0);
     return Read("NA", seq, ipd, pw, snr, mdl);
 }
 
@@ -120,7 +120,7 @@ TEST(IntegratorTest, TestLongTemplate)
 {
     // TODO: Write a test for a longer molecule
     const string mdl = P6C4;
-    vector<uint8_t> pw(longTpl.length(), 1);
+    vector<uint8_t> pw(longRead.length(), 1);
     MonoMolecularIntegrator ai(longTpl, cfg, snr, mdl);
     EXPECT_EQ(State::VALID,
               ai.AddRead(MappedRead(MkRead(longRead, snr, mdl, pw), StrandType::FORWARD, 0,
@@ -130,7 +130,7 @@ TEST(IntegratorTest, TestLongTemplate)
 
 void TestTiming(const string& mdl)
 {
-    const vector<uint8_t> pws(longTpl.length(), 2);
+    const vector<uint8_t> pws(longRead.length(), 2);
     const size_t nsamp = 5000;
     MonoMolecularIntegrator ai(longTpl, cfg, snr, mdl);
     const auto stime = std::chrono::high_resolution_clock::now();
@@ -331,10 +331,11 @@ TEST(IntegratorTest, TestMultiMutationEquivalenceSP1C1v2) { MultiEquivalence(SP1
 TEST(IntegratorTest, TestP6C4NoCovAgainstCSharpModel)
 {
     const string tpl = "ACGTCGT";
-    const vector<uint8_t> pw(tpl.length(), 1);
     auto mdl = P6C4;
     MultiMolecularIntegrator ai(tpl, cfg);
 
+    const string readSeq = "ACGTACGT";
+    const vector<uint8_t> pw(readSeq.length(), 1);
     EXPECT_EQ(State::VALID,
               ai.AddRead(MappedRead(MkRead("ACGTACGT", snr, mdl, pw), StrandType::FORWARD, 0,
                                     tpl.length(), true, true)));
diff --git a/tests/unit/TestLoadModels.cpp b/tests/unit/TestLoadModels.cpp
index 0a57f44..1d73655 100644
--- a/tests/unit/TestLoadModels.cpp
+++ b/tests/unit/TestLoadModels.cpp
@@ -91,12 +91,12 @@ const string longRead =
     "CTGCGGCATTTTGTCCGCGCCGGGCTTCGCTCACTGTTCAGGCCGGAGCCACAGACCGCCGTTGAACGGATGCT"
     "AATTACTATCTCCCGAAAGAATC";
 
-const std::vector<uint8_t> longPws(837, 2);
+const std::vector<uint8_t> longPws(longRead.size(), 2);
 const IntegratorConfig cfg(-100.0);  // disable zscore filtering
 
 Read MkRead(const string& seq, const SNR& snr, const string& mdl, const vector<uint8_t>& pw)
 {
-    vector<uint8_t> ipd(0, seq.length());
+    vector<uint8_t> ipd(seq.length(), 0);
     return Read("NA", seq, ipd, pw, snr, mdl);
 }
 }
diff --git a/tests/unit/TestPolish.cpp b/tests/unit/TestPolish.cpp
index bd5e441..1c5fd6e 100644
--- a/tests/unit/TestPolish.cpp
+++ b/tests/unit/TestPolish.cpp
@@ -54,7 +54,7 @@ namespace {
 
 Read MkRead(const std::string& seq, const SNR& snr, const std::string& mdl)
 {
-    std::vector<uint8_t> cov(0, seq.length());
+    std::vector<uint8_t> cov(seq.length(), 0);
     return Read("NA", seq, cov, cov, snr, mdl);
 }
 
diff --git a/third-party/cpp-optparse/OptionParser.cpp b/third-party/cpp-optparse/OptionParser.cpp
index 359b7a9..2b9077f 100644
--- a/third-party/cpp-optparse/OptionParser.cpp
+++ b/third-party/cpp-optparse/OptionParser.cpp
@@ -7,16 +7,16 @@
 
 #include "OptionParser.h"
 
-#include <cstdlib>
 #include <algorithm>
-#include <complex>
 #include <ciso646>
+#include <complex>
+#include <cstdlib>
 
 #if defined(ENABLE_NLS) && ENABLE_NLS
-# include <libintl.h>
-# define _(s) gettext(s)
+#include <libintl.h>
+#define _(s) gettext(s)
 #else
-# define _(s) ((const char *) (s))
+#define _(s) ((const char*)(s))
 #endif
 
 using namespace std;
@@ -24,554 +24,541 @@ using namespace std;
 namespace optparse {
 
 ////////// auxiliary (string) functions { //////////
-class str_wrap {
+class str_wrap
+{
 public:
-  str_wrap(const string& l, const string& r) : lwrap(l), rwrap(r) {}
-  str_wrap(const string& w) : lwrap(w), rwrap(w) {}
-  string operator() (const string& s) { return lwrap + s + rwrap; }
-  const string lwrap, rwrap;
+    str_wrap(const string& l, const string& r) : lwrap(l), rwrap(r) {}
+    str_wrap(const string& w) : lwrap(w), rwrap(w) {}
+    string operator()(const string& s) { return lwrap + s + rwrap; }
+    const string lwrap, rwrap;
 };
-template<typename InputIterator, typename UnaryOperator>
-static string str_join_trans(const string& sep, InputIterator begin, InputIterator end, UnaryOperator op) {
-  string buf;
-  for (InputIterator it = begin; it != end; ++it) {
-    if (it != begin)
-      buf += sep;
-    buf += op(*it);
-  }
-  return buf;
-}
-template<class InputIterator>
-static string str_join(const string& sep, InputIterator begin, InputIterator end) {
-  return str_join_trans(sep, begin, end, str_wrap(""));
-}
-static string& str_replace(string& s, const string& patt, const string& repl) {
-  size_t pos = 0, n = patt.length();
-  while (true) {
-    pos = s.find(patt, pos);
-    if (pos == string::npos)
-      break;
-    s.replace(pos, n, repl);
-    pos += repl.size();
-  }
-  return s;
-}
-static string str_replace(const string& s, const string& patt, const string& repl) {
-  string tmp = s;
-  str_replace(tmp, patt, repl);
-  return tmp;
-}
-static string str_format(const string& s, size_t pre, size_t len, bool indent_first = true) {
-  stringstream ss;
-  string p;
-  if (indent_first)
-    p = string(pre, ' ');
-
-  size_t pos = 0, linestart = 0;
-  size_t line = 0;
-  while (true) {
-    bool wrap = false;
-
-    size_t new_pos = s.find_first_of(" \n\t", pos);
-    if (new_pos == string::npos)
-      break;
-    if (s[new_pos] == '\n') {
-      pos = new_pos + 1;
-      wrap = true;
+template <typename InputIterator, typename UnaryOperator>
+static string str_join_trans(const string& sep, InputIterator begin, InputIterator end,
+                             UnaryOperator op)
+{
+    string buf;
+    for (InputIterator it = begin; it != end; ++it) {
+        if (it != begin) buf += sep;
+        buf += op(*it);
+    }
+    return buf;
+}
+template <class InputIterator>
+static string str_join(const string& sep, InputIterator begin, InputIterator end)
+{
+    return str_join_trans(sep, begin, end, str_wrap(""));
+}
+static string& str_replace(string& s, const string& patt, const string& repl)
+{
+    size_t pos = 0, n = patt.length();
+    while (true) {
+        pos = s.find(patt, pos);
+        if (pos == string::npos) break;
+        s.replace(pos, n, repl);
+        pos += repl.size();
     }
-    if (line == 1)
-      p = string(pre, ' ');
-    if (wrap || new_pos + pre > linestart + len) {
-      ss << p << s.substr(linestart, pos - linestart - 1) << endl;
-      linestart = pos;
-      line++;
+    return s;
+}
+static string str_replace(const string& s, const string& patt, const string& repl)
+{
+    string tmp = s;
+    str_replace(tmp, patt, repl);
+    return tmp;
+}
+static string str_format(const string& s, size_t pre, size_t len, bool indent_first = true)
+{
+    stringstream ss;
+    string p;
+    if (indent_first) p = string(pre, ' ');
+
+    size_t pos = 0, linestart = 0;
+    size_t line = 0;
+    while (true) {
+        bool wrap = false;
+
+        size_t new_pos = s.find_first_of(" \n\t", pos);
+        if (new_pos == string::npos) break;
+        if (s[new_pos] == '\n') {
+            pos = new_pos + 1;
+            wrap = true;
+        }
+        if (line == 1) p = string(pre, ' ');
+        if (wrap || new_pos + pre > linestart + len) {
+            ss << p << s.substr(linestart, pos - linestart - 1) << endl;
+            linestart = pos;
+            line++;
+        }
+        pos = new_pos + 1;
     }
-    pos = new_pos + 1;
-  }
-  ss << p << s.substr(linestart) << endl;
-  return ss.str();
-}
-static string str_inc(const string& s) {
-  stringstream ss;
-  string v = (s != "") ? s : "0";
-  long i;
-  istringstream(v) >> i;
-  ss << i+1;
-  return ss.str();
-}
-static unsigned int cols() {
-  unsigned int n = 80;
+    ss << p << s.substr(linestart) << endl;
+    return ss.str();
+}
+static string str_inc(const string& s)
+{
+    stringstream ss;
+    string v = (s != "") ? s : "0";
+    long i;
+    istringstream(v) >> i;
+    ss << i + 1;
+    return ss.str();
+}
+static unsigned int cols()
+{
+    unsigned int n = 80;
 #ifndef _WIN32
-  const char *s = getenv("COLUMNS");
-  if (s)
-    istringstream(s) >> n;
+    const char* s = getenv("COLUMNS");
+    if (s) istringstream(s) >> n;
 #endif
-  return n;
-}
-static string basename(const string& s) {
-  string b = s;
-  size_t i = b.find_last_not_of('/');
-  if (i == string::npos) {
-    if (b[0] == '/')
-      b.erase(1);
+    return n;
+}
+static string basename(const string& s)
+{
+    string b = s;
+    size_t i = b.find_last_not_of('/');
+    if (i == string::npos) {
+        if (b[0] == '/') b.erase(1);
+        return b;
+    }
+    b.erase(i + 1, b.length() - i - 1);
+    i = b.find_last_of("/");
+    if (i != string::npos) b.erase(0, i + 1);
     return b;
-  }
-  b.erase(i+1, b.length()-i-1);
-  i = b.find_last_of("/");
-  if (i != string::npos)
-    b.erase(0, i+1);
-  return b;
 }
 ////////// } auxiliary (string) functions //////////
 
-
 ////////// class OptionParser { //////////
-OptionParser::OptionParser() :
-  _usage(_("%prog [options]")),
-  _add_help_option(true),
-  _add_version_option(true),
-  _interspersed_args(true) {}
-
-Option& OptionParser::add_option(const string& opt) {
-  const string tmp[1] = { opt };
-  return add_option(vector<string>(&tmp[0], &tmp[1]));
-}
-Option& OptionParser::add_option(const string& opt1, const string& opt2) {
-  const string tmp[2] = { opt1, opt2 };
-  return add_option(vector<string>(&tmp[0], &tmp[2]));
-}
-Option& OptionParser::add_option(const string& opt1, const string& opt2, const string& opt3) {
-  const string tmp[3] = { opt1, opt2, opt3 };
-  return add_option(vector<string>(&tmp[0], &tmp[3]));
-}
-Option& OptionParser::add_option(const vector<string>& v) {
-  _opts.resize(_opts.size()+1);
-  Option& option = _opts.back();
-  string dest_fallback;
-  for (vector<string>::const_iterator it = v.begin(); it != v.end(); ++it) {
-    if (it->substr(0,2) == "--") {
-      const string s = it->substr(2);
-      if (option.dest() == "")
-        option.dest(str_replace(s, "-", "_"));
-      option._long_opts.insert(s);
-      _optmap_l[s] = &option;
-    } else {
-      const string s = it->substr(1,1);
-      if (dest_fallback == "")
-        dest_fallback = s;
-      option._short_opts.insert(s);
-      _optmap_s[s] = &option;
+OptionParser::OptionParser()
+    : _usage(_("%prog [options]"))
+    , _add_help_option(true)
+    , _add_version_option(true)
+    , _interspersed_args(true)
+{
+}
+
+Option& OptionParser::add_option(const string& opt)
+{
+    const string tmp[1] = {opt};
+    return add_option(vector<string>(&tmp[0], &tmp[1]));
+}
+Option& OptionParser::add_option(const string& opt1, const string& opt2)
+{
+    const string tmp[2] = {opt1, opt2};
+    return add_option(vector<string>(&tmp[0], &tmp[2]));
+}
+Option& OptionParser::add_option(const string& opt1, const string& opt2, const string& opt3)
+{
+    const string tmp[3] = {opt1, opt2, opt3};
+    return add_option(vector<string>(&tmp[0], &tmp[3]));
+}
+Option& OptionParser::add_option(const vector<string>& v)
+{
+    _opts.resize(_opts.size() + 1);
+    Option& option = _opts.back();
+    string dest_fallback;
+    for (vector<string>::const_iterator it = v.begin(); it != v.end(); ++it) {
+        if (it->substr(0, 2) == "--") {
+            const string s = it->substr(2);
+            if (option.dest() == "") option.dest(str_replace(s, "-", "_"));
+            option._long_opts.insert(s);
+            _optmap_l[s] = &option;
+        } else {
+            const string s = it->substr(1, 1);
+            if (dest_fallback == "") dest_fallback = s;
+            option._short_opts.insert(s);
+            _optmap_s[s] = &option;
+        }
+    }
+    if (option.dest() == "") option.dest(dest_fallback);
+    return option;
+}
+
+OptionParser& OptionParser::add_option_group(const OptionGroup& group)
+{
+    _groups.push_back(group);
+    OptionGroup& currentGroup = _groups.back();
+
+    for (list<Option>::const_iterator oit = currentGroup._opts.begin();
+         oit != currentGroup._opts.end(); ++oit) {
+        const Option& option = *oit;
+        for (set<string>::const_iterator it = option._short_opts.begin();
+             it != option._short_opts.end(); ++it)
+            _optmap_s[*it] = &option;
+        for (set<string>::const_iterator it = option._long_opts.begin();
+             it != option._long_opts.end(); ++it)
+            _optmap_l[*it] = &option;
     }
-  }
-  if (option.dest() == "")
-    option.dest(dest_fallback);
-  return option;
-}
-
-OptionParser& OptionParser::add_option_group(const OptionGroup& group) {
-  _groups.push_back(group);
-  OptionGroup& currentGroup = _groups.back();
-
-  for (list<Option>::const_iterator oit = currentGroup._opts.begin(); oit != currentGroup._opts.end(); ++oit) {
-    const Option& option = *oit;
-    for (set<string>::const_iterator it = option._short_opts.begin(); it != option._short_opts.end(); ++it)
-      _optmap_s[*it] = &option;
-    for (set<string>::const_iterator it = option._long_opts.begin(); it != option._long_opts.end(); ++it)
-      _optmap_l[*it] = &option;
-  }
 
-  return *this;
+    return *this;
 }
 
-const Option& OptionParser::lookup_short_opt(const string& opt) const {
-  optMap::const_iterator it = _optmap_s.find(opt);
-  if (it == _optmap_s.end())
-    error(_("no such option") + string(": -") + opt);
-  return *it->second;
+const Option& OptionParser::lookup_short_opt(const string& opt) const
+{
+    optMap::const_iterator it = _optmap_s.find(opt);
+    if (it == _optmap_s.end()) error(_("no such option") + string(": -") + opt);
+    return *it->second;
 }
 
-void OptionParser::handle_short_opt(const string& opt, const string& arg) {
+void OptionParser::handle_short_opt(const string& opt, const string& arg)
+{
 
-  _remaining.pop_front();
-  string value;
-
-  const Option& option = lookup_short_opt(opt);
-  if (option._nargs == 1) {
-    value = arg.substr(2);
-    if (value == "") {
-      if (_remaining.empty())
-        error("-" + opt + " " + _("option requires an argument"));
-      value = _remaining.front();
-      _remaining.pop_front();
+    _remaining.pop_front();
+    string value;
+
+    const Option& option = lookup_short_opt(opt);
+    if (option._nargs == 1) {
+        value = arg.substr(2);
+        if (value == "") {
+            if (_remaining.empty()) error("-" + opt + " " + _("option requires an argument"));
+            value = _remaining.front();
+            _remaining.pop_front();
+        }
+    } else {
+        if (arg.length() > 2) _remaining.push_front(string("-") + arg.substr(2));
     }
-  } else {
-    if (arg.length() > 2)
-      _remaining.push_front(string("-") + arg.substr(2));
-  }
 
-  process_opt(option, string("-") + opt, value);
+    process_opt(option, string("-") + opt, value);
 }
 
-const Option& OptionParser::lookup_long_opt(const string& opt) const {
+const Option& OptionParser::lookup_long_opt(const string& opt) const
+{
 
-  list<string> matching;
-  for (optMap::const_iterator it = _optmap_l.begin(); it != _optmap_l.end(); ++it) {
-    if (it->first.compare(0, opt.length(), opt) == 0)
-      matching.push_back(it->first);
-  }
-  if (matching.size() > 1) {
-    string x = str_join(", ", matching.begin(), matching.end());
-    error(_("ambiguous option") + string(": --") + opt + " (" + x + "?)");
-  }
-  if (matching.size() == 0)
-    error(_("no such option") + string(": --") + opt);
+    list<string> matching;
+    for (optMap::const_iterator it = _optmap_l.begin(); it != _optmap_l.end(); ++it) {
+        if (it->first.compare(0, opt.length(), opt) == 0) matching.push_back(it->first);
+    }
+    if (matching.size() > 1) {
+        string x = str_join(", ", matching.begin(), matching.end());
+        error(_("ambiguous option") + string(": --") + opt + " (" + x + "?)");
+    }
+    if (matching.size() == 0) error(_("no such option") + string(": --") + opt);
 
-  return *_optmap_l.find(matching.front())->second;
+    return *_optmap_l.find(matching.front())->second;
 }
 
-void OptionParser::handle_long_opt(const string& optstr) {
-
-  _remaining.pop_front();
-  string opt, value;
-
-  size_t delim = optstr.find("=");
-  if (delim != string::npos) {
-    opt = optstr.substr(0, delim);
-    value = optstr.substr(delim+1);
-  } else
-    opt = optstr;
+void OptionParser::handle_long_opt(const string& optstr)
+{
 
-  const Option& option = lookup_long_opt(opt);
-  if (option._nargs == 1 and delim == string::npos) {
-    if (not _remaining.empty()) {
-      value = _remaining.front();
-      _remaining.pop_front();
+    _remaining.pop_front();
+    string opt, value;
+
+    size_t delim = optstr.find("=");
+    if (delim != string::npos) {
+        opt = optstr.substr(0, delim);
+        value = optstr.substr(delim + 1);
+    } else
+        opt = optstr;
+
+    const Option& option = lookup_long_opt(opt);
+    if (option._nargs == 1 and delim == string::npos) {
+        if (not _remaining.empty()) {
+            value = _remaining.front();
+            _remaining.pop_front();
+        }
     }
-  }
 
-  if (option._nargs == 1 and value == "")
-    error("--" + opt + " " + _("option requires an argument"));
+    if (option._nargs == 1 and value == "")
+        error("--" + opt + " " + _("option requires an argument"));
 
-  process_opt(option, string("--") + opt, value);
+    process_opt(option, string("--") + opt, value);
 }
 
-Values& OptionParser::parse_args(const int argc, char const* const* const argv) {
-  if (prog() == "")
-    prog(basename(argv[0]));
-  return parse_args(&argv[1], &argv[argc]);
+Values& OptionParser::parse_args(const int argc, char const* const* const argv)
+{
+    if (prog() == "") prog(basename(argv[0]));
+    return parse_args(&argv[1], &argv[argc]);
 }
-Values& OptionParser::parse_args(const vector<string>& v) {
+Values& OptionParser::parse_args(const vector<string>& v)
+{
 
-  _remaining.assign(v.begin(), v.end());
+    _remaining.assign(v.begin(), v.end());
 
-  if (add_version_option() and version() != "") {
-    add_option("--version") .action("version") .help(_("Show program's version number and exit."));
-    _opts.splice(_opts.begin(), _opts, --(_opts.end()));
-  }
-  if (add_help_option()) {
-    add_option("-h", "--help") .action("help") .help(_("Show this help message and exit."));
-    _opts.splice(_opts.begin(), _opts, --(_opts.end()));
-  }
+    if (add_version_option() and version() != "") {
+        add_option("--version")
+            .action("version")
+            .help(_("Show program's version number and exit."));
+        _opts.splice(_opts.begin(), _opts, --(_opts.end()));
+    }
+    if (add_help_option()) {
+        add_option("-h", "--help").action("help").help(_("Show this help message and exit."));
+        _opts.splice(_opts.begin(), _opts, --(_opts.end()));
+    }
 
-  while (not _remaining.empty()) {
-    const string arg = _remaining.front();
+    while (not _remaining.empty()) {
+        const string arg = _remaining.front();
+
+        if (arg == "--") {
+            _remaining.pop_front();
+            break;
+        }
+
+        if (arg.substr(0, 2) == "--") {
+            handle_long_opt(arg.substr(2));
+        } else if (arg.substr(0, 1) == "-" and arg.length() > 1) {
+            handle_short_opt(arg.substr(1, 1), arg);
+        } else {
+            _remaining.pop_front();
+            _leftover.push_back(arg);
+            if (not interspersed_args()) break;
+        }
+    }
+    while (not _remaining.empty()) {
+        const string arg = _remaining.front();
+        _remaining.pop_front();
+        _leftover.push_back(arg);
+    }
 
-    if (arg == "--") {
-      _remaining.pop_front();
-      break;
+    for (strMap::const_iterator it = _defaults.begin(); it != _defaults.end(); ++it) {
+        if (not _values.is_set(it->first)) _values[it->first] = it->second;
     }
 
-    if (arg.substr(0,2) == "--") {
-      handle_long_opt(arg.substr(2));
-    } else if (arg.substr(0,1) == "-" and arg.length() > 1) {
-      handle_short_opt(arg.substr(1,1), arg);
-    } else {
-      _remaining.pop_front();
-      _leftover.push_back(arg);
-      if (not interspersed_args())
-        break;
+    for (list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it) {
+        if (not _values.is_set(it->dest())) _values[it->dest()] = it->get_default();
     }
-  }
-  while (not _remaining.empty()) {
-    const string arg = _remaining.front();
-    _remaining.pop_front();
-    _leftover.push_back(arg);
-  }
-
-  for (strMap::const_iterator it = _defaults.begin(); it != _defaults.end(); ++it) {
-    if (not _values.is_set(it->first))
-      _values[it->first] = it->second;
-  }
-
-  for (list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it) {
-    if (not _values.is_set(it->dest()))
-        _values[it->dest()] = it->get_default();
-  }
-
-  for (list<OptionGroup>::iterator group_it = _groups.begin(); group_it != _groups.end(); ++group_it) {
-      for (strMap::const_iterator it = group_it->_defaults.begin(); it != group_it->_defaults.end(); ++it) {
-          if (not _values.is_set(it->first))
-              _values[it->first] = it->second;
-      }
-      
-      for (list<Option>::const_iterator it = group_it->_opts.begin(); it != group_it->_opts.end(); ++it) {
-          if (it->get_default() != "" and not _values.is_set(it->dest()))
-              _values[it->dest()] = it->get_default();
-      }
-  }
-
-  return _values;
-}
-
-void OptionParser::process_opt(const Option& o, const string& opt, const string& value) {
-  if (o.action() == "store") {
-    string err = o.check_type(opt, value);
-    if (err != "")
-      error(err);
-    _values[o.dest()] = value;
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "store_const") {
-    _values[o.dest()] = o.get_const();
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "store_true") {
-    _values[o.dest()] = "1";
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "store_false") {
-    _values[o.dest()] = "0";
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "append") {
-    string err = o.check_type(opt, value);
-    if (err != "")
-      error(err);
-    _values[o.dest()] = value;
-    _values.all(o.dest()).push_back(value);
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "append_const") {
-    _values[o.dest()] = o.get_const();
-    _values.all(o.dest()).push_back(o.get_const());
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "count") {
-    _values[o.dest()] = str_inc(_values[o.dest()]);
-    _values.is_set_by_user(o.dest(), true);
-  }
-  else if (o.action() == "help") {
-    print_help();
-    std::exit(0);
-  }
-  else if (o.action() == "version") {
-    print_version();
-    std::exit(0);
-  }
-  else if (o.action() == "callback" && o.callback()) {
-    (*o.callback())(o, opt, value, *this);
-  }
-}
-
-string OptionParser::format_option_help(unsigned int indent /* = 2 */) const {
-  stringstream ss;
-
-  if (_opts.empty())
-    return ss.str();
 
-  for (list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it) {
-    if (it->help() != SUPPRESS_HELP)
-      ss << it->format_help(indent);
-  }
+    for (list<OptionGroup>::iterator group_it = _groups.begin(); group_it != _groups.end();
+         ++group_it) {
+        for (strMap::const_iterator it = group_it->_defaults.begin();
+             it != group_it->_defaults.end(); ++it) {
+            if (not _values.is_set(it->first)) _values[it->first] = it->second;
+        }
+
+        for (list<Option>::const_iterator it = group_it->_opts.begin(); it != group_it->_opts.end();
+             ++it) {
+            if (it->get_default() != "" and not _values.is_set(it->dest()))
+                _values[it->dest()] = it->get_default();
+        }
+    }
 
-  return ss.str();
+    return _values;
+}
+
+void OptionParser::process_opt(const Option& o, const string& opt, const string& value)
+{
+    if (o.action() == "store") {
+        string err = o.check_type(opt, value);
+        if (err != "") error(err);
+        _values[o.dest()] = value;
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "store_const") {
+        _values[o.dest()] = o.get_const();
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "store_true") {
+        _values[o.dest()] = "1";
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "store_false") {
+        _values[o.dest()] = "0";
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "append") {
+        string err = o.check_type(opt, value);
+        if (err != "") error(err);
+        _values[o.dest()] = value;
+        _values.all(o.dest()).push_back(value);
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "append_const") {
+        _values[o.dest()] = o.get_const();
+        _values.all(o.dest()).push_back(o.get_const());
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "count") {
+        _values[o.dest()] = str_inc(_values[o.dest()]);
+        _values.is_set_by_user(o.dest(), true);
+    } else if (o.action() == "help") {
+        print_help();
+        std::exit(0);
+    } else if (o.action() == "version") {
+        print_version();
+        std::exit(0);
+    } else if (o.action() == "callback" && o.callback()) {
+        (*o.callback())(o, opt, value, *this);
+    }
 }
 
-string OptionParser::format_help() const {
-  stringstream ss;
+string OptionParser::format_option_help(unsigned int indent /* = 2 */) const
+{
+    stringstream ss;
 
-  if (usage() != SUPPRESS_USAGE)
-    ss << get_usage() << endl;
+    if (_opts.empty()) return ss.str();
 
-  if (description() != "")
-    ss << str_format(description(), 0, cols()) << endl;
+    for (list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it) {
+        if (it->help() != SUPPRESS_HELP) ss << it->format_help(indent);
+    }
 
-  ss << _("Options") << ":" << endl;
-  ss << format_option_help();
+    return ss.str();
+}
 
-  for (list<OptionGroup>::const_iterator it = _groups.begin(); it != _groups.end(); ++it) {
-    const OptionGroup& group = *it;
-    ss << endl << "  " << group.title() << ":" << endl;
-    if (group.group_description() != "")
-      ss << str_format(group.group_description(), 4, cols()) << endl;
-    ss << group.format_option_help(4);
-  }
+string OptionParser::format_help() const
+{
+    stringstream ss;
 
-  if (epilog() != "")
-    ss << endl << str_format(epilog(), 0, cols());
+    if (usage() != SUPPRESS_USAGE) ss << get_usage() << endl;
 
-  return ss.str();
-}
-void OptionParser::print_help() const {
-  cout << format_help();
-}
+    if (description() != "") ss << str_format(description(), 0, cols()) << endl;
 
-void OptionParser::set_usage(const string& u) {
-  string lower = u;
-  transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
-  if (lower.compare(0, 7, "usage: ") == 0)
-    _usage = u.substr(7);
-  else
-    _usage = u;
-}
-string OptionParser::format_usage(const string& u) const {
-  stringstream ss;
-  ss << _("Usage") << ": " << u << endl;
-  return ss.str();
+    ss << _("Options") << ":" << endl;
+    ss << format_option_help();
+
+    for (list<OptionGroup>::const_iterator it = _groups.begin(); it != _groups.end(); ++it) {
+        const OptionGroup& group = *it;
+        ss << endl << "  " << group.title() << ":" << endl;
+        if (group.group_description() != "")
+            ss << str_format(group.group_description(), 4, cols()) << endl;
+        ss << group.format_option_help(4);
+    }
+
+    if (epilog() != "") ss << endl << str_format(epilog(), 0, cols());
+
+    return ss.str();
 }
-string OptionParser::get_usage() const {
-  if (usage() == SUPPRESS_USAGE)
-    return string("");
-  return format_usage(str_replace(usage(), "%prog", prog()));
+void OptionParser::print_help() const { cout << format_help(); }
+
+void OptionParser::set_usage(const string& u)
+{
+    string lower = u;
+    transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+    if (lower.compare(0, 7, "usage: ") == 0)
+        _usage = u.substr(7);
+    else
+        _usage = u;
+}
+string OptionParser::format_usage(const string& u) const
+{
+    stringstream ss;
+    ss << _("Usage") << ": " << u << endl;
+    return ss.str();
 }
-void OptionParser::print_usage(ostream& out) const {
-  string u = get_usage();
-  if (u != "")
-    out << u << endl;
+string OptionParser::get_usage() const
+{
+    if (usage() == SUPPRESS_USAGE) return string("");
+    return format_usage(str_replace(usage(), "%prog", prog()));
 }
-void OptionParser::print_usage() const {
-  print_usage(cout);
+void OptionParser::print_usage(ostream& out) const
+{
+    string u = get_usage();
+    if (u != "") out << u << endl;
 }
+void OptionParser::print_usage() const { print_usage(cout); }
 
-string OptionParser::get_version() const {
-  return str_replace(_version, "%prog", prog());
-}
-void OptionParser::print_version(ostream& out) const {
-  out << get_version() << endl;
-}
-void OptionParser::print_version() const {
-  print_version(cout);
-}
+string OptionParser::get_version() const { return str_replace(_version, "%prog", prog()); }
+void OptionParser::print_version(ostream& out) const { out << get_version() << endl; }
+void OptionParser::print_version() const { print_version(cout); }
 
-void OptionParser::exit() const {
-  std::exit(2);
-}
-void OptionParser::error(const string& msg) const {
-  print_usage(cerr);
-  cerr << prog() << ": " << _("error") << ": " << msg << endl;
-  exit();
+void OptionParser::exit() const { std::exit(2); }
+void OptionParser::error(const string& msg) const
+{
+    print_usage(cerr);
+    cerr << prog() << ": " << _("error") << ": " << msg << endl;
+    exit();
 }
 ////////// } class OptionParser //////////
 
 ////////// class Values { //////////
-void Values::is_set_by_user(const string& d, bool yes) {
-  if (yes)
-    _userSet.insert(d);
-  else
-    _userSet.erase(d);
+void Values::is_set_by_user(const string& d, bool yes)
+{
+    if (yes)
+        _userSet.insert(d);
+    else
+        _userSet.erase(d);
 }
 ////////// } class Values //////////
 
 ////////// class Option { //////////
-string Option::check_type(const string& opt, const string& val) const {
-  istringstream ss(val);
-  stringstream err;
-
-  if (type() == "int" || type() == "long") {
-    long t;
-    if (not (ss >> t))
-      err << _("option") << " " << opt << ": " << _("invalid integer value") << ": '" << val << "'";
-  }
-  else if (type() == "float" || type() == "double") {
-    double t;
-    if (not (ss >> t) && ss.str() != "NaN" && ss.str() != "nan" )
-      err << _("option") << " " << opt << ": " << _("invalid floating-point value") << ": '" << val << "'";
-  }
-  else if (type() == "choice") {
-    if (find(choices().begin(), choices().end(), val) == choices().end()) {
-      list<string> tmp = choices();
-      transform(tmp.begin(), tmp.end(), tmp.begin(), str_wrap("'"));
-      err << _("option") << " " << opt << ": " << _("invalid choice") << ": '" << val << "'"
-        << " (" << _("choose from") << " " << str_join(", ", tmp.begin(), tmp.end()) << ")";
+string Option::check_type(const string& opt, const string& val) const
+{
+    istringstream ss(val);
+    stringstream err;
+
+    if (type() == "int" || type() == "long") {
+        long t;
+        if (not(ss >> t))
+            err << _("option") << " " << opt << ": " << _("invalid integer value") << ": '" << val
+                << "'";
+    } else if (type() == "float" || type() == "double") {
+        double t;
+        if (not(ss >> t) && ss.str() != "NaN" && ss.str() != "nan")
+            err << _("option") << " " << opt << ": " << _("invalid floating-point value") << ": '"
+                << val << "'";
+    } else if (type() == "choice") {
+        if (find(choices().begin(), choices().end(), val) == choices().end()) {
+            list<string> tmp = choices();
+            transform(tmp.begin(), tmp.end(), tmp.begin(), str_wrap("'"));
+            err << _("option") << " " << opt << ": " << _("invalid choice") << ": '" << val << "'"
+                << " (" << _("choose from") << " " << str_join(", ", tmp.begin(), tmp.end()) << ")";
+        }
+    } else if (type() == "complex") {
+        complex<double> t;
+        if (not(ss >> t))
+            err << _("option") << " " << opt << ": " << _("invalid complex value") << ": '" << val
+                << "'";
+    }
+
+    return err.str();
+}
+
+string Option::format_option_help(unsigned int indent /* = 2 */) const
+{
+
+    string mvar_short, mvar_long;
+    if (nargs() == 1) {
+        string mvar = metavar();
+        if (mvar == "") {
+            mvar = type();
+            transform(mvar.begin(), mvar.end(), mvar.begin(), ::toupper);
+        }
+        mvar_short = " " + mvar;
+        mvar_long = "=" + mvar;
+    }
+
+    stringstream ss;
+    ss << string(indent, ' ');
+
+    if (not _short_opts.empty()) {
+        ss << str_join_trans(", ", _short_opts.begin(), _short_opts.end(),
+                             str_wrap("-", mvar_short));
+        if (not _long_opts.empty()) ss << ", ";
     }
-  }
-  else if (type() == "complex") {
-    complex<double> t;
-    if (not (ss >> t))
-      err << _("option") << " " << opt << ": " << _("invalid complex value") << ": '" << val << "'";
-  }
-
-  return err.str();
-}
-
-string Option::format_option_help(unsigned int indent /* = 2 */) const {
-
-  string mvar_short, mvar_long;
-  if (nargs() == 1) {
-    string mvar = metavar();
-    if (mvar == "") {
-      mvar = type();
-      transform(mvar.begin(), mvar.end(), mvar.begin(), ::toupper);
-     }
-    mvar_short = " " + mvar;
-    mvar_long = "=" + mvar;
-  }
-
-  stringstream ss;
-  ss << string(indent, ' ');
-
-  if (not _short_opts.empty()) {
-    ss << str_join_trans(", ", _short_opts.begin(), _short_opts.end(), str_wrap("-", mvar_short));
     if (not _long_opts.empty())
-      ss << ", ";
-  }
-  if (not _long_opts.empty())
-    ss << str_join_trans(", ", _long_opts.begin(), _long_opts.end(), str_wrap("--", mvar_long));
-
-  return ss.str();
-}
-
-string Option::format_help(unsigned int indent /* = 2 */) const {
-  stringstream ss;
-  string h = format_option_help(indent);
-  unsigned int width = cols();
-  unsigned int opt_width = min(width*3/10, 36u);
-  bool indent_first = false;
-  ss << h;
-  // if the option list is too long, start a new paragraph
-  if (h.length() >= (opt_width-1)) {
-    ss << endl;
-    indent_first = true;
-  } else {
-    ss << string(opt_width - h.length(), ' ');
-    if (help() == "")
-      ss << endl;
-  }
-  if (help() != "") {
-    string help_str = (get_default() != "") ? str_replace(help(), "%default", get_default()) : help();
-    ss << str_format(help_str, opt_width, width, indent_first);
-  }
-  return ss.str();
-}
-
-Option& Option::action(const string& a) {
-  _action = a;
-  if (a == "store_true")
-  {
-    _default = "0";
-    nargs(0);
-  }
-  else if (a == "store_false")
-  {
-    _default = "1";
-    nargs(0);
-  }
-  else if (a == "store_const" || a == "append_const" || a == "count" || a == "help" || a == "version")
-  {
-    nargs(0);
-  }
-  return *this;
+        ss << str_join_trans(", ", _long_opts.begin(), _long_opts.end(), str_wrap("--", mvar_long));
+
+    return ss.str();
 }
-////////// } class Option //////////
 
+string Option::format_help(unsigned int indent /* = 2 */) const
+{
+    stringstream ss;
+    string h = format_option_help(indent);
+    unsigned int width = cols();
+    unsigned int opt_width = min(width * 3 / 10, 36u);
+    bool indent_first = false;
+    ss << h;
+    // if the option list is too long, start a new paragraph
+    if (h.length() >= (opt_width - 1)) {
+        ss << endl;
+        indent_first = true;
+    } else {
+        ss << string(opt_width - h.length(), ' ');
+        if (help() == "") ss << endl;
+    }
+    if (help() != "") {
+        string help_str =
+            (get_default() != "") ? str_replace(help(), "%default", get_default()) : help();
+        ss << str_format(help_str, opt_width, width, indent_first);
+    }
+    return ss.str();
+}
+
+Option& Option::action(const string& a)
+{
+    _action = a;
+    if (a == "store_true") {
+        _default = "0";
+        nargs(0);
+    } else if (a == "store_false") {
+        _default = "1";
+        nargs(0);
+    } else if (a == "store_const" || a == "append_const" || a == "count" || a == "help" ||
+               a == "version") {
+        nargs(0);
+    }
+    return *this;
+}
+////////// } class Option //////////
 }
diff --git a/third-party/cpp-optparse/OptionParser.h b/third-party/cpp-optparse/OptionParser.h
index 5e316a1..f1f5052 100644
--- a/third-party/cpp-optparse/OptionParser.h
+++ b/third-party/cpp-optparse/OptionParser.h
@@ -82,26 +82,30 @@ class Values;
 class Value;
 class Callback;
 
-typedef std::map<std::string,std::string> strMap;
-typedef std::map<std::string,std::list<std::string> > lstMap;
-typedef std::map<std::string,Option const*> optMap;
+typedef std::map<std::string, std::string> strMap;
+typedef std::map<std::string, std::list<std::string> > lstMap;
+typedef std::map<std::string, Option const*> optMap;
 
-const char* const SUPPRESS_HELP = "SUPPRESS" "HELP";
-const char* const SUPPRESS_USAGE = "SUPPRESS" "USAGE";
+const char* const SUPPRESS_HELP =
+    "SUPPRESS"
+    "HELP";
+const char* const SUPPRESS_USAGE =
+    "SUPPRESS"
+    "USAGE";
 
 //Exception classes for error conditions
-class InvalidValueCast : public std::runtime_error {
-  public:
+class InvalidValueCast : public std::runtime_error
+{
+public:
     InvalidValueCast() : std::runtime_error("invalid cast of Value") {}
 };
 
-class InvalidOption : public std::runtime_error {
-  public:
+class InvalidOption : public std::runtime_error
+{
+public:
     InvalidOption() : std::runtime_error("invalid Option") {}
 };
 
-
-
 namespace {
 
 template <typename T>
@@ -131,52 +135,53 @@ T floatingPointConvert(bool valid, const std::string& s)
     throw InvalidValueCast();
 }
 
-} // anon namespace
-
-
+}  // anon namespace
 
 //! Class for automatic conversion from string -> anytype
-class Value {
-  public:
+class Value
+{
+public:
     Value() : str(), valid(false) {}
     Value(const std::string& v) : str(v), valid(true) {}
 
-    operator const char*()          { return str.c_str(); }
-    operator bool()                 { return integralConvert<bool>(valid, str); }
-    operator bool()           const { return integralConvert<bool>(valid, str); }
-    operator short()                { return integralConvert<short>(valid, str); }
-    operator short()          const { return integralConvert<short>(valid, str); }
-    operator unsigned short()       { return integralConvert<unsigned short>(valid, str); }
+    operator const char*() { return str.c_str(); }
+    operator bool() { return integralConvert<bool>(valid, str); }
+    operator bool() const { return integralConvert<bool>(valid, str); }
+    operator short() { return integralConvert<short>(valid, str); }
+    operator short() const { return integralConvert<short>(valid, str); }
+    operator unsigned short() { return integralConvert<unsigned short>(valid, str); }
     operator unsigned short() const { return integralConvert<unsigned short>(valid, str); }
-    operator int()                  { return integralConvert<int>(valid, str); }
-    operator int()            const { return integralConvert<int>(valid, str); }
-    operator unsigned int()         { return integralConvert<unsigned int>(valid, str); }
-    operator unsigned int()   const { return integralConvert<unsigned int>(valid, str); }
-    operator long()                 { return integralConvert<long>(valid, str); }
-    operator long()           const { return integralConvert<long>(valid, str); }
-    operator unsigned long()        { return integralConvert<unsigned long>(valid, str); }
-    operator unsigned long()  const { return integralConvert<unsigned long>(valid, str); }
-    operator float()                { return floatingPointConvert<float>(valid, str); }
-    operator float()          const { return floatingPointConvert<float>(valid, str); }
-    operator double()               { return floatingPointConvert<double>(valid, str); }
-    operator double()         const { return floatingPointConvert<double>(valid, str); }
-    operator long double()          { return floatingPointConvert<long double>(valid, str); }
-    operator long double()    const { return floatingPointConvert<long double>(valid, str); }
+    operator int() { return integralConvert<int>(valid, str); }
+    operator int() const { return integralConvert<int>(valid, str); }
+    operator unsigned int() { return integralConvert<unsigned int>(valid, str); }
+    operator unsigned int() const { return integralConvert<unsigned int>(valid, str); }
+    operator long() { return integralConvert<long>(valid, str); }
+    operator long() const { return integralConvert<long>(valid, str); }
+    operator unsigned long() { return integralConvert<unsigned long>(valid, str); }
+    operator unsigned long() const { return integralConvert<unsigned long>(valid, str); }
+    operator float() { return floatingPointConvert<float>(valid, str); }
+    operator float() const { return floatingPointConvert<float>(valid, str); }
+    operator double() { return floatingPointConvert<double>(valid, str); }
+    operator double() const { return floatingPointConvert<double>(valid, str); }
+    operator long double() { return floatingPointConvert<long double>(valid, str); }
+    operator long double() const { return floatingPointConvert<long double>(valid, str); }
 
 private:
     const std::string str;
     bool valid;
 };
 
-class Values {
-  public:
+class Values
+{
+public:
     Values() : _map() {}
-    const std::string& operator[] (const std::string& d) const {
+    const std::string& operator[](const std::string& d) const
+    {
         strMap::const_iterator it = _map.find(d);
         if (it != _map.end()) return it->second;
         throw InvalidOption();
     }
-    std::string& operator[] (const std::string& d) { return _map[d]; }
+    std::string& operator[](const std::string& d) { return _map[d]; }
     bool is_set(const std::string& d) const { return _map.find(d) != _map.end(); }
     bool is_set_by_user(const std::string& d) const { return _userSet.find(d) != _userSet.end(); }
     void is_set_by_user(const std::string& d, bool yes);
@@ -185,31 +190,73 @@ class Values {
     typedef std::list<std::string>::iterator iterator;
     typedef std::list<std::string>::const_iterator const_iterator;
     std::list<std::string>& all(const std::string& d) { return _appendMap[d]; }
-    const std::list<std::string>& all(const std::string& d) const { return _appendMap.find(d)->second; }
+    const std::list<std::string>& all(const std::string& d) const
+    {
+        return _appendMap.find(d)->second;
+    }
 
-  private:
+private:
     strMap _map;
     lstMap _appendMap;
     std::set<std::string> _userSet;
 };
 
-class OptionParser {
-  public:
+class OptionParser
+{
+public:
     OptionParser();
     virtual ~OptionParser() {}
 
-    OptionParser& usage(const std::string& u) { set_usage(u); return *this; }
-    OptionParser& version(const std::string& v) { _version = v; return *this; }
-    OptionParser& description(const std::string& d) { _description = d; return *this; }
-    OptionParser& add_help_option(bool h) { _add_help_option = h; return *this; }
-    OptionParser& add_version_option(bool v) { _add_version_option = v; return *this; }
-    OptionParser& prog(const std::string& p) { _prog = p; return *this; }
-    OptionParser& epilog(const std::string& e) { _epilog = e; return *this; }
-    OptionParser& set_defaults(const std::string& dest, const std::string& val) {
-      _defaults[dest] = val; return *this;
+    OptionParser& usage(const std::string& u)
+    {
+        set_usage(u);
+        return *this;
+    }
+    OptionParser& version(const std::string& v)
+    {
+        _version = v;
+        return *this;
+    }
+    OptionParser& description(const std::string& d)
+    {
+        _description = d;
+        return *this;
+    }
+    OptionParser& add_help_option(bool h)
+    {
+        _add_help_option = h;
+        return *this;
+    }
+    OptionParser& add_version_option(bool v)
+    {
+        _add_version_option = v;
+        return *this;
+    }
+    OptionParser& prog(const std::string& p)
+    {
+        _prog = p;
+        return *this;
+    }
+    OptionParser& epilog(const std::string& e)
+    {
+        _epilog = e;
+        return *this;
+    }
+    OptionParser& set_defaults(const std::string& dest, const std::string& val)
+    {
+        _defaults[dest] = val;
+        return *this;
+    }
+    OptionParser& enable_interspersed_args()
+    {
+        _interspersed_args = true;
+        return *this;
+    }
+    OptionParser& disable_interspersed_args()
+    {
+        _interspersed_args = false;
+        return *this;
     }
-    OptionParser& enable_interspersed_args() { _interspersed_args = true; return *this; }
-    OptionParser& disable_interspersed_args() { _interspersed_args = false; return *this; }
     OptionParser& add_option_group(const OptionGroup& group);
 
     const std::string& usage() const { return _usage; }
@@ -228,14 +275,16 @@ class OptionParser {
 
     Values& parse_args(int argc, char const* const* argv);
     Values& parse_args(const std::vector<std::string>& args);
-    template<typename InputIterator>
-    Values& parse_args(InputIterator begin, InputIterator end) {
-      return parse_args(std::vector<std::string>(begin, end));
+    template <typename InputIterator>
+    Values& parse_args(InputIterator begin, InputIterator end)
+    {
+        return parse_args(std::vector<std::string>(begin, end));
     }
 
     const std::list<std::string>& args() const { return _leftover; }
-    std::vector<std::string> args() {
-      return std::vector<std::string>(_leftover.begin(), _leftover.end());
+    std::vector<std::string> args()
+    {
+        return std::vector<std::string>(_leftover.begin(), _leftover.end());
     }
 
     std::string format_help() const;
@@ -254,7 +303,7 @@ class OptionParser {
     void error(const std::string& msg) const;
     void exit() const;
 
-  private:
+private:
     const Option& lookup_short_opt(const std::string& opt) const;
     const Option& lookup_long_opt(const std::string& opt) const;
 
@@ -286,42 +335,95 @@ class OptionParser {
     std::list<std::string> _leftover;
 };
 
-class OptionGroup : public OptionParser {
-  public:
-    OptionGroup(const OptionParser&, const std::string& t, const std::string& d = "") :
-      _title(t), _group_description(d) {}
+class OptionGroup : public OptionParser
+{
+public:
+    OptionGroup(const OptionParser&, const std::string& t, const std::string& d = "")
+        : _title(t), _group_description(d)
+    {
+    }
     virtual ~OptionGroup() {}
 
-    OptionGroup& title(const std::string& t) { _title = t; return *this; }
-    OptionGroup& group_description(const std::string& d) { _group_description = d; return *this; }
+    OptionGroup& title(const std::string& t)
+    {
+        _title = t;
+        return *this;
+    }
+    OptionGroup& group_description(const std::string& d)
+    {
+        _group_description = d;
+        return *this;
+    }
     const std::string& title() const { return _title; }
     const std::string& group_description() const { return _group_description; }
 
-  private:
+private:
     std::string _title;
     std::string _group_description;
 };
 
-class Option {
-  public:
+class Option
+{
+public:
     Option() : _action("store"), _type("string"), _nargs(1), _callback(0) {}
     virtual ~Option() {}
 
     Option& action(const std::string& a);
-    Option& type(const std::string& t) { _type = t; return *this; }
-    Option& dest(const std::string& d) { _dest = d; return *this; }
-    Option& set_default(const std::string& d) { _default = d; return *this; }
-    template<typename T>
-    Option& set_default(T t) { std::ostringstream ss; ss << t; _default = ss.str(); return *this; }
-    Option& nargs(size_t n) { _nargs = n; return *this; }
-    Option& set_const(const std::string& c) { _const = c; return *this; }
-    template<typename InputIterator>
-    Option& choices(InputIterator begin, InputIterator end) {
-      _choices.assign(begin, end); type("choice"); return *this;
+    Option& type(const std::string& t)
+    {
+        _type = t;
+        return *this;
+    }
+    Option& dest(const std::string& d)
+    {
+        _dest = d;
+        return *this;
+    }
+    Option& set_default(const std::string& d)
+    {
+        _default = d;
+        return *this;
+    }
+    template <typename T>
+    Option& set_default(T t)
+    {
+        std::ostringstream ss;
+        ss << t;
+        _default = ss.str();
+        return *this;
+    }
+    Option& nargs(size_t n)
+    {
+        _nargs = n;
+        return *this;
+    }
+    Option& set_const(const std::string& c)
+    {
+        _const = c;
+        return *this;
+    }
+    template <typename InputIterator>
+    Option& choices(InputIterator begin, InputIterator end)
+    {
+        _choices.assign(begin, end);
+        type("choice");
+        return *this;
+    }
+    Option& help(const std::string& h)
+    {
+        _help = h;
+        return *this;
+    }
+    Option& metavar(const std::string& m)
+    {
+        _metavar = m;
+        return *this;
+    }
+    Option& callback(Callback& c)
+    {
+        _callback = &c;
+        return *this;
     }
-    Option& help(const std::string& h) { _help = h; return *this; }
-    Option& metavar(const std::string& m) { _metavar = m; return *this; }
-    Option& callback(Callback& c) { _callback = &c; return *this; }
 
     const std::string& action() const { return _action; }
     const std::string& type() const { return _type; }
@@ -334,7 +436,7 @@ class Option {
     const std::string& metavar() const { return _metavar; }
     Callback* callback() const { return _callback; }
 
-  private:
+private:
     std::string check_type(const std::string& opt, const std::string& val) const;
     std::string format_option_help(unsigned int indent = 2) const;
     std::string format_help(unsigned int indent = 2) const;
@@ -356,12 +458,13 @@ class Option {
     friend class OptionParser;
 };
 
-class Callback {
+class Callback
+{
 public:
-  virtual void operator() (const Option& option, const std::string& opt, const std::string& val, const OptionParser& parser) = 0;
-  virtual ~Callback() {}
+    virtual void operator()(const Option& option, const std::string& opt, const std::string& val,
+                            const OptionParser& parser) = 0;
+    virtual ~Callback() {}
 };
-
 }
 
 #endif
diff --git a/third-party/cpp-optparse/test.cpp b/third-party/cpp-optparse/test.cpp
index b0a85cc..bbbbe10 100644
--- a/third-party/cpp-optparse/test.cpp
+++ b/third-party/cpp-optparse/test.cpp
@@ -1,153 +1,188 @@
 #include "OptionParser.h"
 
+#include <algorithm>
+#include <complex>
 #include <iostream>
 #include <sstream>
 #include <string>
-#include <complex>
-#include <algorithm>
 
 using namespace std;
 
 using namespace optparse;
 
-class Output {
+class Output
+{
 public:
-  Output(const string& d) : delim(d), first(true) {}
-  void operator() (const string& s) {
-    if (first)
-      first = false;
-    else
-      cout << delim;
-    cout << s;
-  }
-  ~Output() { cout << endl; }
-  const string& delim;
-  bool first;
+    Output(const string& d) : delim(d), first(true) {}
+    void operator()(const string& s)
+    {
+        if (first)
+            first = false;
+        else
+            cout << delim;
+        cout << s;
+    }
+    ~Output() { cout << endl; }
+    const string& delim;
+    bool first;
 };
 
-class MyCallback : public optparse::Callback {
+class MyCallback : public optparse::Callback
+{
 public:
-  MyCallback() : counter(0) {}
-  void operator() (const Option& option, const string& opt, const string& val, const OptionParser& parser) {
-    counter++;
-    cout << "--- MyCallback --- " << counter << ". time called" << endl;
-    cout << "--- MyCallback --- option.action(): " << option.action() << endl;
-    cout << "--- MyCallback --- opt: " << opt << endl;
-    cout << "--- MyCallback --- val: " << val << endl;
-    cout << "--- MyCallback --- parser.usage(): " << parser.usage() << endl;
-    cout << endl;
-  }
-  int counter;
+    MyCallback() : counter(0) {}
+    void operator()(const Option& option, const string& opt, const string& val,
+                    const OptionParser& parser)
+    {
+        counter++;
+        cout << "--- MyCallback --- " << counter << ". time called" << endl;
+        cout << "--- MyCallback --- option.action(): " << option.action() << endl;
+        cout << "--- MyCallback --- opt: " << opt << endl;
+        cout << "--- MyCallback --- val: " << val << endl;
+        cout << "--- MyCallback --- parser.usage(): " << parser.usage() << endl;
+        cout << endl;
+    }
+    int counter;
 };
 
-int main(int argc, char *argv[])
+int main(int argc, char* argv[])
 {
 #ifndef DISABLE_USAGE
-  const string usage = "usage: %prog [OPTION]... DIR [FILE]...";
+    const string usage = "usage: %prog [OPTION]... DIR [FILE]...";
 #else
-  const string usage = SUPPRESS_USAGE;
+    const string usage = SUPPRESS_USAGE;
 #endif
-  const string version = "%prog 1.0\nCopyright (C) 2010 Johannes Weißl\n"
-    "License GPLv3+: GNU GPL version 3 or later "
-    "<http://gnu.org/licenses/gpl.html>.\n"
-    "This is free software: you are free to change and redistribute it.\n"
-    "There is NO WARRANTY, to the extent permitted by law.";
-  const string desc = "Lorem ipsum dolor sit amet, consectetur adipisicing"
-    " elit, sed do eiusmod tempor incididunt ut labore et dolore magna"
-    " aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco"
-    " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor"
-    " in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla"
-    " pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa"
-    " qui officia deserunt mollit anim id est laborum.";
-  const string epilog = "Sed ut perspiciatis unde omnis iste natus error sit"
-    " voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque"
-    " ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae"
-    " dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit"
-    " aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos"
-    " qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui"
-    " dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia"
-    " non numquam eius modi tempora incidunt ut labore et dolore magnam"
-    " aliquam quaerat voluptatem.";
+    const string version =
+        "%prog 1.0\nCopyright (C) 2010 Johannes Weißl\n"
+        "License GPLv3+: GNU GPL version 3 or later "
+        "<http://gnu.org/licenses/gpl.html>.\n"
+        "This is free software: you are free to change and redistribute it.\n"
+        "There is NO WARRANTY, to the extent permitted by law.";
+    const string desc =
+        "Lorem ipsum dolor sit amet, consectetur adipisicing"
+        " elit, sed do eiusmod tempor incididunt ut labore et dolore magna"
+        " aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco"
+        " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor"
+        " in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla"
+        " pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa"
+        " qui officia deserunt mollit anim id est laborum.";
+    const string epilog =
+        "Sed ut perspiciatis unde omnis iste natus error sit"
+        " voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque"
+        " ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae"
+        " dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit"
+        " aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos"
+        " qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui"
+        " dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia"
+        " non numquam eius modi tempora incidunt ut labore et dolore magnam"
+        " aliquam quaerat voluptatem.";
 
-  OptionParser parser = OptionParser()
-    .usage(usage)
-    .version(version)
-    .description(desc)
-    .epilog(epilog)
+    OptionParser parser = OptionParser()
+                              .usage(usage)
+                              .version(version)
+                              .description(desc)
+                              .epilog(epilog)
 #ifdef DISABLE_INTERSPERSED_ARGS
-    .disable_interspersed_args()
+                              .disable_interspersed_args()
 #endif
-  ;
+        ;
 
-  parser.set_defaults("verbosity", "50");
-  parser.set_defaults("no_clear", "0");
+    parser.set_defaults("verbosity", "50");
+    parser.set_defaults("no_clear", "0");
 
-  // test all actions
-  parser.add_option("--clear") .action("store_false") .dest("no_clear") .help("clear (default)");
-  parser.add_option("--no-clear") .action("store_true") .help("not clear");
-  parser.add_option("--string")
-    .help("This is a really long text... very long indeed! It must be wrapped on normal terminals.");
-  parser.add_option("-x", "--clause", "--sentence") .metavar("SENTENCE") .set_default("I'm a sentence")
-    .help("This is a really long text... very long indeed! It must be wrapped on normal terminals. "
-          "Also it should appear not on the same line as the option.");
-  parser.add_option("-k") .action("count") .help("how many times?");
-  parser.add_option("-v", "--verbose") .action("store_const") .set_const("100") .dest("verbosity") .help("be verbose!");
-  parser.add_option("-s", "--silent") .action("store_const") .set_const("0") .dest("verbosity") .help("be silent!");
-  parser.add_option("-n", "--number") .type("int") .set_default("1") .metavar("NUM") .help("number of files (default: %default)");
-  parser.add_option("-H") .action("help") .help("alternative help");
-  parser.add_option("-V") .action("version") .help("alternative version");
-  parser.add_option("-i", "--int") .action("store") .type("int") .set_default(3) .help("default: %default");
-  parser.add_option("-f", "--float") .action("store") .type("float") .set_default(5.3) .help("default: %default");
-  parser.add_option("-c", "--complex") .action("store") .type("complex");
-  char const* const choices[] = { "foo", "bar", "baz" };
-  parser.add_option("-C", "--choices") .choices(&choices[0], &choices[3]);
-  parser.add_option("-m", "--more") .action("append");
-  parser.add_option("--more-milk") .action("append_const") .set_const("milk");
-  parser.add_option("--hidden") .help(SUPPRESS_HELP);
+    // test all actions
+    parser.add_option("--clear").action("store_false").dest("no_clear").help("clear (default)");
+    parser.add_option("--no-clear").action("store_true").help("not clear");
+    parser.add_option("--string")
+        .help(
+            "This is a really long text... very long indeed! It must be wrapped on normal "
+            "terminals.");
+    parser.add_option("-x", "--clause", "--sentence")
+        .metavar("SENTENCE")
+        .set_default("I'm a sentence")
+        .help(
+            "This is a really long text... very long indeed! It must be wrapped on normal "
+            "terminals. "
+            "Also it should appear not on the same line as the option.");
+    parser.add_option("-k").action("count").help("how many times?");
+    parser.add_option("-v", "--verbose")
+        .action("store_const")
+        .set_const("100")
+        .dest("verbosity")
+        .help("be verbose!");
+    parser.add_option("-s", "--silent")
+        .action("store_const")
+        .set_const("0")
+        .dest("verbosity")
+        .help("be silent!");
+    parser.add_option("-n", "--number")
+        .type("int")
+        .set_default("1")
+        .metavar("NUM")
+        .help("number of files (default: %default)");
+    parser.add_option("-H").action("help").help("alternative help");
+    parser.add_option("-V").action("version").help("alternative version");
+    parser.add_option("-i", "--int")
+        .action("store")
+        .type("int")
+        .set_default(3)
+        .help("default: %default");
+    parser.add_option("-f", "--float")
+        .action("store")
+        .type("float")
+        .set_default(5.3)
+        .help("default: %default");
+    parser.add_option("-c", "--complex").action("store").type("complex");
+    char const* const choices[] = {"foo", "bar", "baz"};
+    parser.add_option("-C", "--choices").choices(&choices[0], &choices[3]);
+    parser.add_option("-m", "--more").action("append");
+    parser.add_option("--more-milk").action("append_const").set_const("milk");
+    parser.add_option("--hidden").help(SUPPRESS_HELP);
 
-  MyCallback mc;
-  parser.add_option("-K", "--callback") .action("callback") .callback(mc) .help("callback test");
+    MyCallback mc;
+    parser.add_option("-K", "--callback").action("callback").callback(mc).help("callback test");
 
-  OptionGroup group = OptionGroup(parser, "Dangerous Options",
-      "Caution: use these options at your own risk. "
-      "It is believed that some of them bite.");
-  group.add_option("-g") .action("store_true") .help("Group option.") .set_default("0");
-  parser.add_option_group(group);
+    OptionGroup group = OptionGroup(parser, "Dangerous Options",
+                                    "Caution: use these options at your own risk. "
+                                    "It is believed that some of them bite.");
+    group.add_option("-g").action("store_true").help("Group option.").set_default("0");
+    parser.add_option_group(group);
 
-  Values& options = parser.parse_args(argc, argv);
-  vector<string> args = parser.args();
+    Values& options = parser.parse_args(argc, argv);
+    vector<string> args = parser.args();
 
-  cout << "clear: " << (options.get("no_clear") ? "false" : "true") << endl;
-  cout << "string: " << options["string"] << endl;
-  cout << "clause: " << options["clause"] << endl;
-  cout << "k: " << options["k"] << endl;
-  cout << "verbosity: " << options["verbosity"] << endl;
-  cout << "number: " << (int) options.get("number") << endl;
-  cout << "int: " << (int) options.get("int") << endl;
-  cout << "float: " << (float) options.get("float") << endl;
-  complex<double> c = 0;
-  if (options.is_set("complex")) {
-    stringstream ss;
-    ss << options["complex"];
-    ss >> c;
-  }
-  cout << "complex: " << c << endl;
-  cout << "choices: " << (const char*) options.get("choices") << endl;
-  cout << "more: ";
-  for_each(options.all("more").begin(), options.all("more").end(), Output(", "));
-  cout << "more_milk: ";
-  {
-    Output out(", ");
-    for (Values::iterator it = options.all("more_milk").begin(); it != options.all("more_milk").end(); ++it)
-      out(*it);
-  }
-  cout << "hidden: " << options["hidden"] << endl;
-  cout << "group: " << (options.get("g") ? "true" : "false") << endl;
+    cout << "clear: " << (options.get("no_clear") ? "false" : "true") << endl;
+    cout << "string: " << options["string"] << endl;
+    cout << "clause: " << options["clause"] << endl;
+    cout << "k: " << options["k"] << endl;
+    cout << "verbosity: " << options["verbosity"] << endl;
+    cout << "number: " << (int)options.get("number") << endl;
+    cout << "int: " << (int)options.get("int") << endl;
+    cout << "float: " << (float)options.get("float") << endl;
+    complex<double> c = 0;
+    if (options.is_set("complex")) {
+        stringstream ss;
+        ss << options["complex"];
+        ss >> c;
+    }
+    cout << "complex: " << c << endl;
+    cout << "choices: " << (const char*)options.get("choices") << endl;
+    cout << "more: ";
+    for_each(options.all("more").begin(), options.all("more").end(), Output(", "));
+    cout << "more_milk: ";
+    {
+        Output out(", ");
+        for (Values::iterator it = options.all("more_milk").begin();
+             it != options.all("more_milk").end(); ++it)
+            out(*it);
+    }
+    cout << "hidden: " << options["hidden"] << endl;
+    cout << "group: " << (options.get("g") ? "true" : "false") << endl;
 
-  cout << endl << "leftover arguments: " << endl;
-  for (vector<string>::const_iterator it = args.begin(); it != args.end(); ++it) {
-    cout << "arg: " << *it << endl;
-  }
+    cout << endl << "leftover arguments: " << endl;
+    for (vector<string>::const_iterator it = args.begin(); it != args.end(); ++it) {
+        cout << "arg: " << *it << endl;
+    }
 
-  return 0;
+    return 0;
 }
diff --git a/third-party/cram-0.7/cram/__init__.py b/third-party/cram-0.7/cram/__init__.py
new file mode 100644
index 0000000..4b626c4
--- /dev/null
+++ b/third-party/cram-0.7/cram/__init__.py
@@ -0,0 +1,6 @@
+"""Functional testing framework for command line applications"""
+
+from cram._main import main
+from cram._test import test, testfile
+
+__all__ = ['main', 'test', 'testfile']
diff --git a/third-party/cram-0.7/cram/__main__.py b/third-party/cram-0.7/cram/__main__.py
new file mode 100644
index 0000000..e6b0aef
--- /dev/null
+++ b/third-party/cram-0.7/cram/__main__.py
@@ -0,0 +1,10 @@
+"""Main module (invoked by "python -m cram")"""
+
+import sys
+
+import cram
+
+try:
+    sys.exit(cram.main(sys.argv[1:]))
+except KeyboardInterrupt:
+    pass
diff --git a/third-party/cram-0.7/cram/_cli.py b/third-party/cram-0.7/cram/_cli.py
new file mode 100644
index 0000000..8333b6b
--- /dev/null
+++ b/third-party/cram-0.7/cram/_cli.py
@@ -0,0 +1,134 @@
+"""The command line interface implementation"""
+
+import os
+import sys
+
+from cram._encoding import b, bytestype, stdoutb
+from cram._process import execute
+
+__all__ = ['runcli']
+
+def _prompt(question, answers, auto=None):
+    """Write a prompt to stdout and ask for answer in stdin.
+
+    answers should be a string, with each character a single
+    answer. An uppercase letter is considered the default answer.
+
+    If an invalid answer is given, this asks again until it gets a
+    valid one.
+
+    If auto is set, the question is answered automatically with the
+    specified value.
+    """
+    default = [c for c in answers if c.isupper()]
+    while True:
+        sys.stdout.write('%s [%s] ' % (question, answers))
+        sys.stdout.flush()
+        if auto is not None:
+            sys.stdout.write(auto + '\n')
+            sys.stdout.flush()
+            return auto
+
+        answer = sys.stdin.readline().strip().lower()
+        if not answer and default:
+            return default[0]
+        elif answer and answer in answers.lower():
+            return answer
+
+def _log(msg=None, verbosemsg=None, verbose=False):
+    """Write msg to standard out and flush.
+
+    If verbose is True, write verbosemsg instead.
+    """
+    if verbose:
+        msg = verbosemsg
+    if msg:
+        if isinstance(msg, bytestype):
+            stdoutb.write(msg)
+        else: # pragma: nocover
+            sys.stdout.write(msg)
+        sys.stdout.flush()
+
+def _patch(cmd, diff):
+    """Run echo [lines from diff] | cmd -p0"""
+    out, retcode = execute([cmd, '-p0'], stdin=b('').join(diff))
+    return retcode == 0
+
+def runcli(tests, quiet=False, verbose=False, patchcmd=None, answer=None):
+    """Run tests with command line interface input/output.
+
+    tests should be a sequence of 2-tuples containing the following:
+
+        (test path, test function)
+
+    This function yields a new sequence where each test function is wrapped
+    with a function that handles CLI input/output.
+
+    If quiet is True, diffs aren't printed. If verbose is True,
+    filenames and status information are printed.
+
+    If patchcmd is set, a prompt is written to stdout asking if
+    changed output should be merged back into the original test. The
+    answer is read from stdin. If 'y', the test is patched using patch
+    based on the changed output.
+    """
+    total, skipped, failed = [0], [0], [0]
+
+    for path, test in tests:
+        def testwrapper():
+            """Test function that adds CLI output"""
+            total[0] += 1
+            _log(None, path + b(': '), verbose)
+
+            refout, postout, diff = test()
+            if refout is None:
+                skipped[0] += 1
+                _log('s', 'empty\n', verbose)
+                return refout, postout, diff
+
+            abspath = os.path.abspath(path)
+            errpath = abspath + b('.err')
+
+            if postout is None:
+                skipped[0] += 1
+                _log('s', 'skipped\n', verbose)
+            elif not diff:
+                _log('.', 'passed\n', verbose)
+                if os.path.exists(errpath):
+                    os.remove(errpath)
+            else:
+                failed[0] += 1
+                _log('!', 'failed\n', verbose)
+                if not quiet:
+                    _log('\n', None, verbose)
+
+                errfile = open(errpath, 'wb')
+                try:
+                    for line in postout:
+                        errfile.write(line)
+                finally:
+                    errfile.close()
+
+                if not quiet:
+                    origdiff = diff
+                    diff = []
+                    for line in origdiff:
+                        stdoutb.write(line)
+                        diff.append(line)
+
+                    if (patchcmd and
+                        _prompt('Accept this change?', 'yN', answer) == 'y'):
+                        if _patch(patchcmd, diff):
+                            _log(None, path + b(': merged output\n'), verbose)
+                            os.remove(errpath)
+                        else:
+                            _log(path + b(': merge failed\n'))
+
+            return refout, postout, diff
+
+        yield (path, testwrapper)
+
+    if total[0] > 0:
+        _log('\n', None, verbose)
+        _log('# Ran %s tests, %s skipped, %s failed.\n'
+             % (total[0], skipped[0], failed[0]))
diff --git a/third-party/cram-0.7/cram/_diff.py b/third-party/cram-0.7/cram/_diff.py
new file mode 100644
index 0000000..4877305
--- /dev/null
+++ b/third-party/cram-0.7/cram/_diff.py
@@ -0,0 +1,158 @@
+"""Utilities for diffing test files and their output"""
+
+import codecs
+import difflib
+import re
+
+from cram._encoding import b
+
+__all__ = ['esc', 'glob', 'regex', 'unified_diff']
+
+def _regex(pattern, s):
+    """Match a regular expression or return False if invalid.
+
+    >>> from cram._encoding import b
+    >>> [bool(_regex(r, b('foobar'))) for r in (b('foo.*'), b('***'))]
+    [True, False]
+    """
+    try:
+        return re.match(pattern + b(r'\Z'), s)
+    except re.error:
+        return False
+
+def _glob(el, l):
+    r"""Match a glob-like pattern.
+
+    The only supported special characters are * and ?. Escaping is
+    supported.
+
+    >>> from cram._encoding import b
+    >>> bool(_glob(b(r'\* \\ \? fo?b*'), b('* \\ ? foobar')))
+    True
+    """
+    i, n = 0, len(el)
+    res = b('')
+    while i < n:
+        c = el[i:i + 1]
+        i += 1
+        if c == b('\\') and el[i] in b('*?\\'):
+            res += el[i - 1:i + 1]
+            i += 1
+        elif c == b('*'):
+            res += b('.*')
+        elif c == b('?'):
+            res += b('.')
+        else:
+            res += re.escape(c)
+    return _regex(res, l)
+
+def _matchannotation(keyword, matchfunc, el, l):
+    """Apply match function based on annotation keyword"""
+    ann = b(' (%s)\n' % keyword)
+    return el.endswith(ann) and matchfunc(el[:-len(ann)], l[:-1])
+
+def regex(el, l):
+    """Apply a regular expression match to a line annotated with '(re)'"""
+    return _matchannotation('re', _regex, el, l)
+
+def glob(el, l):
+    """Apply a glob match to a line annotated with '(glob)'"""
+    return _matchannotation('glob', _glob, el, l)
+
+def esc(el, l):
+    """Apply an escape match to a line annotated with '(esc)'"""
+    ann = b(' (esc)\n')
+
+    if el.endswith(ann):
+        el = codecs.escape_decode(el[:-len(ann)])[0] + b('\n')
+    if el == l:
+        return True
+
+    if l.endswith(ann):
+        l = codecs.escape_decode(l[:-len(ann)])[0] + b('\n')
+    return el == l
+
+class _SequenceMatcher(difflib.SequenceMatcher, object):
+    """Like difflib.SequenceMatcher, but supports custom match functions"""
+    def __init__(self, *args, **kwargs):
+        self._matchers = kwargs.pop('matchers', [])
+        super(_SequenceMatcher, self).__init__(*args, **kwargs)
+
+    def _match(self, el, l):
+        """Tests for matching lines using custom matchers"""
+        for matcher in self._matchers:
+            if matcher(el, l):
+                return True
+        return False
+
+    def find_longest_match(self, alo, ahi, blo, bhi):
+        """Find longest matching block in a[alo:ahi] and b[blo:bhi]"""
+        # SequenceMatcher uses find_longest_match() to slowly whittle down
+        # the differences between a and b until it has each matching block.
+        # Because of this, we can end up doing the same matches many times.
+        matches = []
+        for n, (el, line) in enumerate(zip(self.a[alo:ahi], self.b[blo:bhi])):
+            if el != line and self._match(el, line):
+                # This fools the superclass's method into thinking that the
+                # regex/glob in a is identical to b by replacing a's line (the
+                # expected output) with b's line (the actual output).
+                self.a[alo + n] = line
+                matches.append((n, el))
+        ret = super(_SequenceMatcher, self).find_longest_match(alo, ahi,
+                                                               blo, bhi)
+        # Restore the lines replaced above. Otherwise, the diff output
+        # would seem to imply that the tests never had any regexes/globs.
+        for n, el in matches:
+            self.a[alo + n] = el
+        return ret
+
+def unified_diff(l1, l2, fromfile=b(''), tofile=b(''), fromfiledate=b(''),
+                 tofiledate=b(''), n=3, lineterm=b('\n'), matchers=None):
+    r"""Compare two sequences of lines; generate the delta as a unified diff.
+
+    This is like difflib.unified_diff(), but allows custom matchers.
+
+    >>> from cram._encoding import b
+    >>> l1 = [b('a\n'), b('? (glob)\n')]
+    >>> l2 = [b('a\n'), b('b\n')]
+    >>> (list(unified_diff(l1, l2, b('f1'), b('f2'), b('1970-01-01'),
+    ...                    b('1970-01-02'))) ==
+    ...  [b('--- f1\t1970-01-01\n'), b('+++ f2\t1970-01-02\n'),
+    ...   b('@@ -1,2 +1,2 @@\n'), b(' a\n'), b('-? (glob)\n'), b('+b\n')])
+    True
+
+    >>> from cram._diff import glob
+    >>> list(unified_diff(l1, l2, matchers=[glob]))
+    []
+    """
+    if matchers is None:
+        matchers = []
+    started = False
+    matcher = _SequenceMatcher(None, l1, l2, matchers=matchers)
+    for group in matcher.get_grouped_opcodes(n):
+        if not started:
+            if fromfiledate:
+                fromdate = b('\t') + fromfiledate
+            else:
+                fromdate = b('')
+            if tofiledate:
+                todate = b('\t') + tofiledate
+            else:
+                todate = b('')
+            yield b('--- ') + fromfile + fromdate + lineterm
+            yield b('+++ ') + tofile + todate + lineterm
+            started = True
+        i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]
+        yield (b("@@ -%d,%d +%d,%d @@" % (i1 + 1, i2 - i1, j1 + 1, j2 - j1)) +
+               lineterm)
+        for tag, i1, i2, j1, j2 in group:
+            if tag == 'equal':
+                for line in l1[i1:i2]:
+                    yield b(' ') + line
+                continue
+            if tag == 'replace' or tag == 'delete':
+                for line in l1[i1:i2]:
+                    yield b('-') + line
+            if tag == 'replace' or tag == 'insert':
+                for line in l2[j1:j2]:
+                    yield b('+') + line
diff --git a/third-party/cram-0.7/cram/_encoding.py b/third-party/cram-0.7/cram/_encoding.py
new file mode 100644
index 0000000..d639cce
--- /dev/null
+++ b/third-party/cram-0.7/cram/_encoding.py
@@ -0,0 +1,106 @@
+"""Encoding utilities"""
+
+import os
+import sys
+
+try:
+    import builtins
+except ImportError:
+    import __builtin__ as builtins
+
+__all__ = ['b', 'bchr', 'bytestype', 'envencode', 'fsdecode', 'fsencode',
+           'stdoutb', 'stderrb', 'u', 'ul', 'unicodetype']
+
+bytestype = getattr(builtins, 'bytes', str)
+unicodetype = getattr(builtins, 'unicode', str)
+
+if getattr(os, 'fsdecode', None) is not None:
+    fsdecode = os.fsdecode
+    fsencode = os.fsencode
+elif bytestype is not str:
+    if sys.platform == 'win32':
+        def fsdecode(s):
+            """Decode a filename from the filesystem encoding"""
+            if isinstance(s, unicodetype):
+                return s
+            encoding = sys.getfilesystemencoding()
+            if encoding == 'mbcs':
+                return s.decode(encoding)
+            else:
+                return s.decode(encoding, 'surrogateescape')
+
+        def fsencode(s):
+            """Encode a filename to the filesystem encoding"""
+            if isinstance(s, bytestype):
+                return s
+            encoding = sys.getfilesystemencoding()
+            if encoding == 'mbcs':
+                return s.encode(encoding)
+            else:
+                return s.encode(encoding, 'surrogateescape')
+    else:
+        def fsdecode(s):
+            """Decode a filename from the filesystem encoding"""
+            if isinstance(s, unicodetype):
+                return s
+            return s.decode(sys.getfilesystemencoding(), 'surrogateescape')
+
+        def fsencode(s):
+            """Encode a filename to the filesystem encoding"""
+            if isinstance(s, bytestype):
+                return s
+            return s.encode(sys.getfilesystemencoding(), 'surrogateescape')
+else:
+    def fsdecode(s):
+        """Decode a filename from the filesystem encoding"""
+        return s
+
+    def fsencode(s):
+        """Encode a filename to the filesystem encoding"""
+        return s
+
+if bytestype is str:
+    def envencode(s):
+        """Encode a byte string to the os.environ encoding"""
+        return s
+else:
+    envencode = fsdecode
+
+if getattr(sys.stdout, 'buffer', None) is not None:
+    stdoutb = sys.stdout.buffer
+    stderrb = sys.stderr.buffer
+else:
+    stdoutb = sys.stdout
+    stderrb = sys.stderr
+
+if bytestype is str:
+    def b(s):
+        """Convert an ASCII string literal into a bytes object"""
+        return s
+
+    bchr = chr
+
+    def u(s):
+        """Convert an ASCII string literal into a unicode object"""
+        return s.decode('ascii')
+else:
+    def b(s):
+        """Convert an ASCII string literal into a bytes object"""
+        return s.encode('ascii')
+
+    def bchr(i):
+        """Return a bytes character for a given integer value"""
+        return bytestype([i])
+
+    def u(s):
+        """Convert an ASCII string literal into a unicode object"""
+        return s
+
+try:
+    eval(r'u""')
+except SyntaxError:
+    ul = eval
+else:
+    def ul(e):
+        """Evaluate e as a unicode string literal"""
+        return eval('u' + e)
diff --git a/third-party/cram-0.7/cram/_main.py b/third-party/cram-0.7/cram/_main.py
new file mode 100644
index 0000000..11d457b
--- /dev/null
+++ b/third-party/cram-0.7/cram/_main.py
@@ -0,0 +1,211 @@
+"""Main entry point"""
+
+import optparse
+import os
+import shlex
+import shutil
+import sys
+import tempfile
+
+try:
+    import configparser
+except ImportError: # pragma: nocover
+    import ConfigParser as configparser
+
+from cram._cli import runcli
+from cram._encoding import b, fsencode, stderrb, stdoutb
+from cram._run import runtests
+from cram._xunit import runxunit
+
+def _which(cmd):
+    """Return the path to cmd or None if not found"""
+    cmd = fsencode(cmd)
+    for p in os.environ['PATH'].split(os.pathsep):
+        path = os.path.join(fsencode(p), cmd)
+        if os.path.isfile(path) and os.access(path, os.X_OK):
+            return os.path.abspath(path)
+    return None
+
+def _expandpath(path):
+    """Expands ~ and environment variables in path"""
+    return os.path.expanduser(os.path.expandvars(path))
+
+class _OptionParser(optparse.OptionParser):
+    """Like optparse.OptionParser, but supports setting values through
+    CRAM= and .cramrc."""
+
+    def __init__(self, *args, **kwargs):
+        self._config_opts = {}
+        optparse.OptionParser.__init__(self, *args, **kwargs)
+
+    def add_option(self, *args, **kwargs):
+        option = optparse.OptionParser.add_option(self, *args, **kwargs)
+        if option.dest and option.dest != 'version':
+            key = option.dest.replace('_', '-')
+            self._config_opts[key] = option.action == 'store_true'
+        return option
+
+    def parse_args(self, args=None, values=None):
+        config = configparser.RawConfigParser()
+        config.read(_expandpath(os.environ.get('CRAMRC', '.cramrc')))
+        defaults = {}
+        for key, isbool in self._config_opts.items():
+            try:
+                if isbool:
+                    try:
+                        value = config.getboolean('cram', key)
+                    except ValueError:
+                        value = config.get('cram', key)
+                        self.error('--%s: invalid boolean value: %r'
+                                   % (key, value))
+                else:
+                    value = config.get('cram', key)
+            except (configparser.NoSectionError, configparser.NoOptionError):
+                pass
+            else:
+                defaults[key] = value
+        self.set_defaults(**defaults)
+
+        eargs = os.environ.get('CRAM', '').strip()
+        if eargs:
+            args = args or []
+            args += shlex.split(eargs)
+
+        try:
+            return optparse.OptionParser.parse_args(self, args, values)
+        except optparse.OptionValueError:
+            self.error(str(sys.exc_info()[1]))
+
+def _parseopts(args):
+    """Parse command line arguments"""
+    p = _OptionParser(usage='cram [OPTIONS] TESTS...', prog='cram')
+    p.add_option('-V', '--version', action='store_true',
+                 help='show version information and exit')
+    p.add_option('-q', '--quiet', action='store_true',
+                 help="don't print diffs")
+    p.add_option('-v', '--verbose', action='store_true',
+                 help='show filenames and test status')
+    p.add_option('-i', '--interactive', action='store_true',
+                 help='interactively merge changed test output')
+    p.add_option('-d', '--debug', action='store_true',
+                 help='write script output directly to the terminal')
+    p.add_option('-y', '--yes', action='store_true',
+                 help='answer yes to all questions')
+    p.add_option('-n', '--no', action='store_true',
+                 help='answer no to all questions')
+    p.add_option('-E', '--preserve-env', action='store_true',
+                 help="don't reset common environment variables")
+    p.add_option('--keep-tmpdir', action='store_true',
+                 help='keep temporary directories')
+    p.add_option('--shell', action='store', default='/bin/sh', metavar='PATH',
+                 help='shell to use for running tests (default: %default)')
+    p.add_option('--shell-opts', action='store', metavar='OPTS',
+                 help='arguments to invoke shell with')
+    p.add_option('--indent', action='store', default=2, metavar='NUM',
+                 type='int', help=('number of spaces to use for indentation '
+                                   '(default: %default)'))
+    p.add_option('--xunit-file', action='store', metavar='PATH',
+                 help='path to write xUnit XML output')
+    opts, paths = p.parse_args(args)
+    paths = [fsencode(path) for path in paths]
+    return opts, paths, p.get_usage
+
+def main(args):
+    """Main entry point.
+
+    If you're thinking of using Cram in other Python code (e.g., unit tests),
+    consider using the test() or testfile() functions instead.
+
+    :param args: Script arguments (excluding script name)
+    :type args: str
+    :return: Exit code (non-zero on failure)
+    :rtype: int
+    """
+    opts, paths, getusage = _parseopts(args)
+    if opts.version:
+        sys.stdout.write("""Cram CLI testing framework (version 0.7)
+
+Copyright (C) 2010-2016 Brodie Rao <brodie at bitheap.org> and others
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+""")
+        return
+
+    conflicts = [('--yes', opts.yes, '--no', opts.no),
+                 ('--quiet', opts.quiet, '--interactive', opts.interactive),
+                 ('--debug', opts.debug, '--quiet', opts.quiet),
+                 ('--debug', opts.debug, '--interactive', opts.interactive),
+                 ('--debug', opts.debug, '--verbose', opts.verbose),
+                 ('--debug', opts.debug, '--xunit-file', opts.xunit_file)]
+    for s1, o1, s2, o2 in conflicts:
+        if o1 and o2:
+            sys.stderr.write('options %s and %s are mutually exclusive\n'
+                             % (s1, s2))
+            return 2
+
+    shellcmd = _which(opts.shell)
+    if not shellcmd:
+        stderrb.write(b('shell not found: ') + fsencode(opts.shell) + b('\n'))
+        return 2
+    shell = [shellcmd]
+    if opts.shell_opts:
+        shell += shlex.split(opts.shell_opts)
+
+    patchcmd = None
+    if opts.interactive:
+        patchcmd = _which('patch')
+        if not patchcmd:
+            sys.stderr.write('patch(1) required for -i\n')
+            return 2
+
+    if not paths:
+        sys.stdout.write(getusage())
+        return 2
+
+    badpaths = [path for path in paths if not os.path.exists(path)]
+    if badpaths:
+        stderrb.write(b('no such file: ') + badpaths[0] + b('\n'))
+        return 2
+
+    if opts.yes:
+        answer = 'y'
+    elif opts.no:
+        answer = 'n'
+    else:
+        answer = None
+
+    tmpdir = os.environ['CRAMTMP'] = tempfile.mkdtemp('', 'cramtests-')
+    tmpdirb = fsencode(tmpdir)
+    proctmp = os.path.join(tmpdir, 'tmp')
+    for s in ('TMPDIR', 'TEMP', 'TMP'):
+        os.environ[s] = proctmp
+
+    os.mkdir(proctmp)
+    try:
+        tests = runtests(paths, tmpdirb, shell, indent=opts.indent,
+                         cleanenv=not opts.preserve_env, debug=opts.debug)
+        if not opts.debug:
+            tests = runcli(tests, quiet=opts.quiet, verbose=opts.verbose,
+                           patchcmd=patchcmd, answer=answer)
+            if opts.xunit_file is not None:
+                tests = runxunit(tests, opts.xunit_file)
+
+        hastests = False
+        failed = False
+        for path, test in tests:
+            hastests = True
+            refout, postout, diff = test()
+            if diff:
+                failed = True
+
+        if not hastests:
+            sys.stderr.write('no tests found\n')
+            return 2
+
+        return int(failed)
+    finally:
+        if opts.keep_tmpdir:
+            stdoutb.write(b('# Kept temporary directory: ') + tmpdirb +
+                          b('\n'))
+        else:
+            shutil.rmtree(tmpdir)
diff --git a/third-party/cram-0.7/cram/_process.py b/third-party/cram-0.7/cram/_process.py
new file mode 100644
index 0000000..decdfbc
--- /dev/null
+++ b/third-party/cram-0.7/cram/_process.py
@@ -0,0 +1,54 @@
+"""Utilities for running subprocesses"""
+
+import os
+import signal
+import subprocess
+import sys
+
+from cram._encoding import fsdecode
+
+__all__ = ['PIPE', 'STDOUT', 'execute']
+
+PIPE = subprocess.PIPE
+STDOUT = subprocess.STDOUT
+
+def _makeresetsigpipe():
+    """Make a function to reset SIGPIPE to SIG_DFL (for use in subprocesses).
+
+    Doing subprocess.Popen(..., preexec_fn=makeresetsigpipe()) will prevent
+    Python's SIGPIPE handler (SIG_IGN) from being inherited by the
+    child process.
+    """
+    if (sys.platform == 'win32' or
+        getattr(signal, 'SIGPIPE', None) is None): # pragma: nocover
+        return None
+    return lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+def execute(args, stdin=None, stdout=None, stderr=None, cwd=None, env=None):
+    """Run a process and return its output and return code.
+
+    stdin may either be None or a string to send to the process.
+
+    stdout may either be None or PIPE. If set to PIPE, the process's output
+    is returned as a string.
+
+    stderr may either be None or STDOUT. If stdout is set to PIPE and stderr
+    is set to STDOUT, the process's stderr output will be interleaved with
+    stdout and returned as a string.
+
+    cwd sets the process's current working directory.
+
+    env can be set to a dictionary to override the process's environment
+    variables.
+
+    This function returns a 2-tuple of (output, returncode).
+    """
+    if sys.platform == 'win32': # pragma: nocover
+        args = [fsdecode(arg) for arg in args]
+
+    p = subprocess.Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr,
+                         cwd=cwd, env=env, bufsize=-1,
+                         preexec_fn=_makeresetsigpipe(),
+                         close_fds=os.name == 'posix')
+    out, err = p.communicate(stdin)
+    return out, p.returncode
diff --git a/third-party/cram-0.7/cram/_run.py b/third-party/cram-0.7/cram/_run.py
new file mode 100644
index 0000000..9111c0f
--- /dev/null
+++ b/third-party/cram-0.7/cram/_run.py
@@ -0,0 +1,77 @@
+"""The test runner"""
+
+import os
+import sys
+
+from cram._encoding import b, fsdecode, fsencode
+from cram._test import testfile
+
+__all__ = ['runtests']
+
+if sys.platform == 'win32': # pragma: nocover
+    def _walk(top):
+        top = fsdecode(top)
+        for root, dirs, files in os.walk(top):
+            yield (fsencode(root),
+                   [fsencode(p) for p in dirs],
+                   [fsencode(p) for p in files])
+else:
+    _walk = os.walk
+
+def _findtests(paths):
+    """Yield tests in paths in sorted order"""
+    for p in paths:
+        if os.path.isdir(p):
+            for root, dirs, files in _walk(p):
+                if os.path.basename(root).startswith(b('.')):
+                    continue
+                for f in sorted(files):
+                    if not f.startswith(b('.')) and f.endswith(b('.t')):
+                        yield os.path.normpath(os.path.join(root, f))
+        else:
+            yield os.path.normpath(p)
+
+def runtests(paths, tmpdir, shell, indent=2, cleanenv=True, debug=False):
+    """Run tests and yield results.
+
+    This yields a sequence of 2-tuples containing the following:
+
+        (test path, test function)
+
+    The test function, when called, runs the test in a temporary directory
+    and returns a 3-tuple:
+
+        (list of lines in the test, same list with actual output, diff)
+    """
+    cwd = os.getcwd()
+    seen = set()
+    basenames = set()
+    for i, path in enumerate(_findtests(paths)):
+        abspath = os.path.abspath(path)
+        if abspath in seen:
+            continue
+        seen.add(abspath)
+
+        if not os.stat(path).st_size:
+            yield (path, lambda: (None, None, None))
+            continue
+
+        basename = os.path.basename(path)
+        if basename in basenames:
+            basename = basename + b('-%s' % i)
+        else:
+            basenames.add(basename)
+
+        def test():
+            """Run test file"""
+            testdir = os.path.join(tmpdir, basename)
+            os.mkdir(testdir)
+            try:
+                os.chdir(testdir)
+                return testfile(abspath, shell, indent=indent,
+                                cleanenv=cleanenv, debug=debug,
+                                testname=path)
+            finally:
+                os.chdir(cwd)
+
+        yield (path, test)
diff --git a/third-party/cram-0.7/cram/_test.py b/third-party/cram-0.7/cram/_test.py
new file mode 100644
index 0000000..27ef99c
--- /dev/null
+++ b/third-party/cram-0.7/cram/_test.py
@@ -0,0 +1,230 @@
+"""Utilities for running individual tests"""
+
+import itertools
+import os
+import re
+import time
+
+from cram._encoding import b, bchr, bytestype, envencode, unicodetype
+from cram._diff import esc, glob, regex, unified_diff
+from cram._process import PIPE, STDOUT, execute
+
+__all__ = ['test', 'testfile']
+
+_needescape = re.compile(b(r'[\x00-\x09\x0b-\x1f\x7f-\xff]')).search
+_escapesub = re.compile(b(r'[\x00-\x09\x0b-\x1f\\\x7f-\xff]')).sub
+_escapemap = dict((bchr(i), b(r'\x%02x' % i)) for i in range(256))
+_escapemap.update({b('\\'): b('\\\\'), b('\r'): b(r'\r'), b('\t'): b(r'\t')})
+
+def _escape(s):
+    """Like the string-escape codec, but doesn't escape quotes"""
+    return (_escapesub(lambda m: _escapemap[m.group(0)], s[:-1]) +
+            b(' (esc)\n'))
+
+def test(lines, shell='/bin/sh', indent=2, testname=None, env=None,
+         cleanenv=True, debug=False):
+    r"""Run test lines and return input, output, and diff.
+
+    This returns a 3-tuple containing the following:
+
+        (list of lines in test, same list with actual output, diff)
+
+    diff is a generator that yields the diff between the two lists.
+
+    If a test exits with return code 80, the actual output is set to
+    None and diff is set to [].
+
+    Note that the TESTSHELL environment variable is available in the
+    test (set to the specified shell). However, the TESTDIR and
+    TESTFILE environment variables are not available. To run actual
+    test files, see testfile().
+
+    Example usage:
+
+    >>> from cram._encoding import b
+    >>> refout, postout, diff = test([b('  $ echo hi\n'),
+    ...                               b('  [a-z]{2} (re)\n')])
+    >>> refout == [b('  $ echo hi\n'), b('  [a-z]{2} (re)\n')]
+    True
+    >>> postout == [b('  $ echo hi\n'), b('  hi\n')]
+    True
+    >>> bool(diff)
+    False
+
+    lines may also be a single bytes string:
+
+    >>> refout, postout, diff = test(b('  $ echo hi\n  bye\n'))
+    >>> refout == [b('  $ echo hi\n'), b('  bye\n')]
+    True
+    >>> postout == [b('  $ echo hi\n'), b('  hi\n')]
+    True
+    >>> bool(diff)
+    True
+    >>> (b('').join(diff) ==
+    ...  b('--- \n+++ \n@@ -1,2 +1,2 @@\n   $ echo hi\n-  bye\n+  hi\n'))
+    True
+
+    Note that the b() function is internal to Cram. If you're using Python 2,
+    use normal string literals instead. If you're using Python 3, use bytes
+    literals.
+
+    :param lines: Test input
+    :type lines: bytes or collections.Iterable[bytes]
+    :param shell: Shell to run test in
+    :type shell: bytes or str or list[bytes] or list[str]
+    :param indent: Amount of indentation to use for shell commands
+    :type indent: int
+    :param testname: Optional test file name (used in diff output)
+    :type testname: bytes or None
+    :param env: Optional environment variables for the test shell
+    :type env: dict or None
+    :param cleanenv: Whether or not to sanitize the environment
+    :type cleanenv: bool
+    :param debug: Whether or not to run in debug mode (don't capture stdout)
+    :type debug: bool
+    :return: Input, output, and diff iterables
+    :rtype: (list[bytes], list[bytes], collections.Iterable[bytes])
+    """
+    indent = b(' ') * indent
+    cmdline = indent + b('$ ')
+    conline = indent + b('> ')
+    usalt = 'CRAM%s' % time.time()
+    salt = b(usalt)
+
+    if env is None:
+        env = os.environ.copy()
+
+    if cleanenv:
+        for s in ('LANG', 'LC_ALL', 'LANGUAGE'):
+            env[s] = 'C'
+        env['TZ'] = 'GMT'
+        env['CDPATH'] = ''
+        env['COLUMNS'] = '80'
+        env['GREP_OPTIONS'] = ''
+
+    if isinstance(lines, bytestype):
+        lines = lines.splitlines(True)
+
+    if isinstance(shell, (bytestype, unicodetype)):
+        shell = [shell]
+    env['TESTSHELL'] = shell[0]
+
+    if debug:
+        stdin = []
+        for line in lines:
+            if not line.endswith(b('\n')):
+                line += b('\n')
+            if line.startswith(cmdline):
+                stdin.append(line[len(cmdline):])
+            elif line.startswith(conline):
+                stdin.append(line[len(conline):])
+
+        execute(shell + ['-'], stdin=b('').join(stdin), env=env)
+        return ([], [], [])
+
+    after = {}
+    refout, postout = [], []
+    i = pos = prepos = -1
+    stdin = []
+    for i, line in enumerate(lines):
+        if not line.endswith(b('\n')):
+            line += b('\n')
+        refout.append(line)
+        if line.startswith(cmdline):
+            after.setdefault(pos, []).append(line)
+            prepos = pos
+            pos = i
+            stdin.append(b('echo %s %s $?\n' % (usalt, i)))
+            stdin.append(line[len(cmdline):])
+        elif line.startswith(conline):
+            after.setdefault(prepos, []).append(line)
+            stdin.append(line[len(conline):])
+        elif not line.startswith(indent):
+            after.setdefault(pos, []).append(line)
+    stdin.append(b('echo %s %s $?\n' % (usalt, i + 1)))
+
+    output, retcode = execute(shell + ['-'], stdin=b('').join(stdin),
+                              stdout=PIPE, stderr=STDOUT, env=env)
+    if retcode == 80:
+        return (refout, None, [])
+
+    pos = -1
+    ret = 0
+    for i, line in enumerate(output[:-1].splitlines(True)):
+        out, cmd = line, None
+        if salt in line:
+            out, cmd = line.split(salt, 1)
+
+        if out:
+            if not out.endswith(b('\n')):
+                out += b(' (no-eol)\n')
+
+            if _needescape(out):
+                out = _escape(out)
+            postout.append(indent + out)
+
+        if cmd:
+            ret = int(cmd.split()[1])
+            if ret != 0:
+                postout.append(indent + b('[%s]\n' % (ret)))
+            postout += after.pop(pos, [])
+            pos = int(cmd.split()[0])
+
+    postout += after.pop(pos, [])
+
+    if testname:
+        diffpath = testname
+        errpath = diffpath + b('.err')
+    else:
+        diffpath = errpath = b('')
+    diff = unified_diff(refout, postout, diffpath, errpath,
+                        matchers=[esc, glob, regex])
+    for firstline in diff:
+        return refout, postout, itertools.chain([firstline], diff)
+    return refout, postout, []
+
+def testfile(path, shell='/bin/sh', indent=2, env=None, cleanenv=True,
+             debug=False, testname=None):
+    """Run test at path and return input, output, and diff.
+
+    This returns a 3-tuple containing the following:
+
+        (list of lines in test, same list with actual output, diff)
+
+    diff is a generator that yields the diff between the two lists.
+
+    If a test exits with return code 80, the actual output is set to
+    None and diff is set to [].
+
+    Note that the TESTDIR, TESTFILE, and TESTSHELL environment
+    variables are available to use in the test.
+
+    :param path: Path to test file
+    :type path: bytes or str
+    :param shell: Shell to run test in
+    :type shell: bytes or str or list[bytes] or list[str]
+    :param indent: Amount of indentation to use for shell commands
+    :type indent: int
+    :param env: Optional environment variables for the test shell
+    :type env: dict or None
+    :param cleanenv: Whether or not to sanitize the environment
+    :type cleanenv: bool
+    :param debug: Whether or not to run in debug mode (don't capture stdout)
+    :type debug: bool
+    :param testname: Optional test file name (used in diff output)
+    :type testname: bytes or None
+    :return: Input, output, and diff iterables
+    :rtype: (list[bytes], list[bytes], collections.Iterable[bytes])
+    """
+    f = open(path, 'rb')
+    try:
+        abspath = os.path.abspath(path)
+        env = env or os.environ.copy()
+        env['TESTDIR'] = envencode(os.path.dirname(abspath))
+        env['TESTFILE'] = envencode(os.path.basename(abspath))
+        if testname is None: # pragma: nocover
+            testname = os.path.basename(abspath)
+        return test(f, shell, indent=indent, testname=testname, env=env,
+                    cleanenv=cleanenv, debug=debug)
+    finally:
+        f.close()
diff --git a/third-party/cram-0.7/cram/_xunit.py b/third-party/cram-0.7/cram/_xunit.py
new file mode 100644
index 0000000..0b3cb49
--- /dev/null
+++ b/third-party/cram-0.7/cram/_xunit.py
@@ -0,0 +1,173 @@
+"""xUnit XML output"""
+
+import locale
+import os
+import re
+import socket
+import sys
+import time
+
+from cram._encoding import u, ul
+
+__all__ = ['runxunit']
+
+_widecdataregex = ul(r"'(?:[^\x09\x0a\x0d\x20-\ud7ff\ue000-\ufffd"
+                     r"\U00010000-\U0010ffff]|]]>)'")
+_narrowcdataregex = ul(r"'(?:[^\x09\x0a\x0d\x20-\ud7ff\ue000-\ufffd]"
+                       r"|]]>)'")
+_widequoteattrregex = ul(r"'[^\x20\x21\x23-\x25\x27-\x3b\x3d"
+                         r"\x3f-\ud7ff\ue000-\ufffd"
+                         r"\U00010000-\U0010ffff]'")
+_narrowquoteattrregex = ul(r"'[^\x20\x21\x23-\x25\x27-\x3b\x3d"
+                           r"\x3f-\ud7ff\ue000-\ufffd]'")
+_replacementchar = ul(r"'\N{REPLACEMENT CHARACTER}'")
+
+if sys.maxunicode >= 0x10ffff: # pragma: nocover
+    _cdatasub = re.compile(_widecdataregex).sub
+    _quoteattrsub = re.compile(_widequoteattrregex).sub
+else: # pragma: nocover
+    _cdatasub = re.compile(_narrowcdataregex).sub
+    _quoteattrsub = re.compile(_narrowquoteattrregex).sub
+
+def _cdatareplace(m):
+    """Replace _cdatasub() regex match"""
+    if m.group(0) == u(']]>'):
+        return u(']]>]]><![CDATA[')
+    else:
+        return _replacementchar
+
+def _cdata(s):
+    r"""Escape a string as an XML CDATA block.
+
+    >>> from cram._encoding import ul
+    >>> (_cdata('1<\'2\'>&"3\x00]]>\t\r\n') ==
+    ...  ul(r"'<![CDATA[1<\'2\'>&\"3\ufffd]]>]]><![CDATA[\t\r\n]]>'"))
+    True
+    """
+    return u('<![CDATA[%s]]>') % _cdatasub(_cdatareplace, s)
+
+def _quoteattrreplace(m):
+    """Replace _quoteattrsub() regex match"""
+    return {u('\t'): u('	'),
+            u('\n'): u('
'),
+            u('\r'): u('
'),
+            u('"'): u('"'),
+            u('&'): u('&'),
+            u('<'): u('<'),
+            u('>'): u('>')}.get(m.group(0), _replacementchar)
+
+def _quoteattr(s):
+    r"""Escape a string for use as an XML attribute value.
+
+    >>> from cram._encoding import ul
+    >>> (_quoteattr('1<\'2\'>&"3\x00]]>\t\r\n') ==
+    ...  ul(r"'\"1<\'2\'>&"3\ufffd]]>	
\"'"))
+    True
+    """
+    return u('"%s"') % _quoteattrsub(_quoteattrreplace, s)
+
+def _timestamp():
+    """Return the current time in ISO 8601 format"""
+    tm = time.localtime()
+    if tm.tm_isdst == 1: # pragma: nocover
+        tz = time.altzone
+    else: # pragma: nocover
+        tz = time.timezone
+
+    timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', tm)
+    tzhours = int(-tz / 60 / 60)
+    tzmins = int(abs(tz) / 60 % 60)
+    timestamp += u('%+03d:%02d') % (tzhours, tzmins)
+    return timestamp
+
+def runxunit(tests, xmlpath):
+    """Run tests with xUnit XML output.
+
+    tests should be a sequence of 2-tuples containing the following:
+
+        (test path, test function)
+
+    This function yields a new sequence where each test function is wrapped
+    with a function that writes test results to an xUnit XML file.
+    """
+    suitestart = time.time()
+    timestamp = _timestamp()
+    hostname = socket.gethostname()
+    total, skipped, failed = [0], [0], [0]
+    testcases = []
+
+    for path, test in tests:
+        def testwrapper():
+            """Run test and collect XML output"""
+            total[0] += 1
+
+            start = time.time()
+            refout, postout, diff = test()
+            testtime = time.time() - start
+
+            classname = path.decode(locale.getpreferredencoding(), 'replace')
+            name = os.path.basename(classname)
+
+            if postout is None:
+                skipped[0] += 1
+                testcase = (u('  <testcase classname=%(classname)s\n'
+                              '            name=%(name)s\n'
+                              '            time="%(time).6f">\n'
+                              '    <skipped/>\n'
+                              '  </testcase>\n') %
+                            {'classname': _quoteattr(classname),
+                             'name': _quoteattr(name),
+                             'time': testtime})
+            elif diff:
+                failed[0] += 1
+                diff = list(diff)
+                diffu = u('').join(l.decode(locale.getpreferredencoding(),
+                                            'replace')
+                                   for l in diff)
+                testcase = (u('  <testcase classname=%(classname)s\n'
+                              '            name=%(name)s\n'
+                              '            time="%(time).6f">\n'
+                              '    <failure>%(diff)s</failure>\n'
+                              '  </testcase>\n') %
+                            {'classname': _quoteattr(classname),
+                             'name': _quoteattr(name),
+                             'time': testtime,
+                             'diff': _cdata(diffu)})
+            else:
+                testcase = (u('  <testcase classname=%(classname)s\n'
+                              '            name=%(name)s\n'
+                              '            time="%(time).6f"/>\n') %
+                            {'classname': _quoteattr(classname),
+                             'name': _quoteattr(name),
+                             'time': testtime})
+            testcases.append(testcase)
+
+            return refout, postout, diff
+
+        yield path, testwrapper
+
+    suitetime = time.time() - suitestart
+    header = (u('<?xml version="1.0" encoding="utf-8"?>\n'
+                '<testsuite name="cram"\n'
+                '           tests="%(total)d"\n'
+                '           failures="%(failed)d"\n'
+                '           skipped="%(skipped)d"\n'
+                '           timestamp=%(timestamp)s\n'
+                '           hostname=%(hostname)s\n'
+                '           time="%(time).6f">\n') %
+              {'total': total[0],
+               'failed': failed[0],
+               'skipped': skipped[0],
+               'timestamp': _quoteattr(timestamp),
+               'hostname': _quoteattr(hostname),
+               'time': suitetime})
+    footer = u('</testsuite>\n')
+
+    xmlfile = open(xmlpath, 'wb')
+    try:
+        xmlfile.write(header.encode('utf-8'))
+        for testcase in testcases:
+            xmlfile.write(testcase.encode('utf-8'))
+        xmlfile.write(footer.encode('utf-8'))
+    finally:
+        xmlfile.close()
diff --git a/third-party/cram-0.7/scripts/cram b/third-party/cram-0.7/scripts/cram
new file mode 100755
index 0000000..33f118e
--- /dev/null
+++ b/third-party/cram-0.7/scripts/cram
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+import sys
+
+import cram
+
+try:
+    sys.exit(cram.main(sys.argv[1:]))
+except KeyboardInterrupt:
+    pass
diff --git a/tools/Darwin/clang-format b/tools/Darwin/clang-format
deleted file mode 100755
index 33201aa..0000000
Binary files a/tools/Darwin/clang-format and /dev/null differ
diff --git a/tools/Linux/clang-format b/tools/Linux/clang-format
deleted file mode 100755
index c450691..0000000
Binary files a/tools/Linux/clang-format and /dev/null differ
diff --git a/tools/check-formatting b/tools/check-formatting
deleted file mode 100755
index dccf458..0000000
--- a/tools/check-formatting
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-
-PLATFORM=$(uname)
-CLANGFORMAT="./tools/${PLATFORM}/clang-format -style=file"
-
-if [ "$1" == "--all" ]
-then
-    find include src tests/unit \( -name *.cpp -or -name *.h \) -print0 \
-    | xargs -n1 -0 ${CLANGFORMAT} -output-replacements-xml \
-    | grep -c "<replacement " > /dev/null
-    grepCode=$?
-elif [ "$1" == "--staged" ]
-then
-    git diff --cached --name-only --diff-filter=ACMRT | grep -e '.*\.h' -e '.*\.cpp' \
-    | xargs -n1 ${CLANGFORMAT} -output-replacements-xml \
-    | grep -c "<replacement " >/dev/null
-    grepCode=$?
-else
-    echo "Please specify --all or --staged"
-    exit 1
-fi
-
-# grep exits 0 => found needed formatting changes
-if [ $grepCode -ne 0 ]
-then
-    echo "Formatting looks good!"
-    exit 0
-else
-    echo "****************************************************"
-    echo "Code needs formatting!  Please use 'tools/format-all'"
-    echo "****************************************************"
-    exit 1
-fi
diff --git a/tools/format-all b/tools/format-all
deleted file mode 100755
index 919f82f..0000000
--- a/tools/format-all
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-# This command can be run by the user to clang-format everything.
-
-PLATFORM=$(uname)
-CLANGFORMAT="./tools/${PLATFORM}/clang-format -style=file"
-
-find include src tests/unit \( -name *.cpp -or -name *.h \) -print0 | xargs -n1 -0 ${CLANGFORMAT} -i
diff --git a/tools/git-clang-format b/tools/git-clang-format
deleted file mode 100755
index 0c45762..0000000
--- a/tools/git-clang-format
+++ /dev/null
@@ -1,485 +0,0 @@
-#!/usr/bin/env python
-#
-#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===#
-#
-#                     The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-r"""                                                                             
-clang-format git integration                                                     
-============================                                                     
-                                                                                 
-This file provides a clang-format integration for git. Put it somewhere in your  
-path and ensure that it is executable. Then, "git clang-format" will invoke      
-clang-format on the changes in current files or a specific commit.               
-                                                                                 
-For further details, run:                                                        
-git clang-format -h                                                              
-                                                                                 
-Requires Python 2.7                                                              
-"""               
-
-import argparse
-import collections
-import contextlib
-import errno
-import os
-import re
-import subprocess
-import sys
-
-usage = 'git clang-format [OPTIONS] [<commit>] [--] [<file>...]'
-
-desc = '''
-Run clang-format on all lines that differ between the working directory
-and <commit>, which defaults to HEAD.  Changes are only applied to the working
-directory.
-
-The following git-config settings set the default of the corresponding option:
-  clangFormat.binary
-  clangFormat.commit
-  clangFormat.extension
-  clangFormat.style
-'''
-
-# Name of the temporary index file in which save the output of clang-format.
-# This file is created within the .git directory.
-temp_index_basename = 'clang-format-index'
-
-
-Range = collections.namedtuple('Range', 'start, count')
-
-
-def main():
-  config = load_git_config()
-
-  # In order to keep '--' yet allow options after positionals, we need to
-  # check for '--' ourselves.  (Setting nargs='*' throws away the '--', while
-  # nargs=argparse.REMAINDER disallows options after positionals.)
-  argv = sys.argv[1:]
-  try:
-    idx = argv.index('--')
-  except ValueError:
-    dash_dash = []
-  else:
-    dash_dash = argv[idx:]
-    argv = argv[:idx]
-
-  default_extensions = ','.join([
-      # From clang/lib/Frontend/FrontendOptions.cpp, all lower case
-      'c', 'h',  # C
-      'm',  # ObjC
-      'mm',  # ObjC++
-      'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp',  # C++
-      # Other languages that clang-format supports
-      'proto', 'protodevel',  # Protocol Buffers
-      'js',  # JavaScript
-      'ts',  # TypeScript
-      ])
-
-  p = argparse.ArgumentParser(
-    usage=usage, formatter_class=argparse.RawDescriptionHelpFormatter,
-    description=desc)
-  p.add_argument('--binary',
-                 default=config.get('clangformat.binary', 'clang-format'),
-                 help='path to clang-format'),
-  p.add_argument('--commit',
-                 default=config.get('clangformat.commit', 'HEAD'),
-                 help='default commit to use if none is specified'),
-  p.add_argument('--diff', action='store_true',
-                 help='print a diff instead of applying the changes')
-  p.add_argument('--extensions',
-                 default=config.get('clangformat.extensions',
-                                    default_extensions),
-                 help=('comma-separated list of file extensions to format, '
-                       'excluding the period and case-insensitive')),
-  p.add_argument('-f', '--force', action='store_true',
-                 help='allow changes to unstaged files')
-  p.add_argument('-p', '--patch', action='store_true',
-                 help='select hunks interactively')
-  p.add_argument('-q', '--quiet', action='count', default=0,
-                 help='print less information')
-  p.add_argument('--style',
-                 default=config.get('clangformat.style', None),
-                 help='passed to clang-format'),
-  p.add_argument('-v', '--verbose', action='count', default=0,
-                 help='print extra information')
-  # We gather all the remaining positional arguments into 'args' since we need
-  # to use some heuristics to determine whether or not <commit> was present.
-  # However, to print pretty messages, we make use of metavar and help.
-  p.add_argument('args', nargs='*', metavar='<commit>',
-                 help='revision from which to compute the diff')
-  p.add_argument('ignored', nargs='*', metavar='<file>...',
-                 help='if specified, only consider differences in these files')
-  opts = p.parse_args(argv)
-
-  opts.verbose -= opts.quiet
-  del opts.quiet
-
-  commit, files = interpret_args(opts.args, dash_dash, opts.commit)
-  changed_lines = compute_diff_and_extract_lines(commit, files)
-  if opts.verbose >= 1:
-    ignored_files = set(changed_lines)
-  filter_by_extension(changed_lines, opts.extensions.lower().split(','))
-  if opts.verbose >= 1:
-    ignored_files.difference_update(changed_lines)
-    if ignored_files:
-      print 'Ignoring changes in the following files (wrong extension):'
-      for filename in ignored_files:
-        print '   ', filename
-    if changed_lines:
-      print 'Running clang-format on the following files:'
-      for filename in changed_lines:
-        print '   ', filename
-  if not changed_lines:
-    print 'no modified files to format'
-    return
-  # The computed diff outputs absolute paths, so we must cd before accessing
-  # those files.
-  cd_to_toplevel()
-  old_tree = create_tree_from_workdir(changed_lines)
-  new_tree = run_clang_format_and_save_to_tree(changed_lines,
-                                               binary=opts.binary,
-                                               style=opts.style)
-  if opts.verbose >= 1:
-    print 'old tree:', old_tree
-    print 'new tree:', new_tree
-  if old_tree == new_tree:
-    if opts.verbose >= 0:
-      print 'clang-format did not modify any files'
-  elif opts.diff:
-    print_diff(old_tree, new_tree)
-  else:
-    changed_files = apply_changes(old_tree, new_tree, force=opts.force,
-                                  patch_mode=opts.patch)
-    if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
-      print 'changed files:'
-      for filename in changed_files:
-        print '   ', filename
-
-
-def load_git_config(non_string_options=None):
-  """Return the git configuration as a dictionary.
-
-  All options are assumed to be strings unless in `non_string_options`, in which
-  is a dictionary mapping option name (in lower case) to either "--bool" or
-  "--int"."""
-  if non_string_options is None:
-    non_string_options = {}
-  out = {}
-  for entry in run('git', 'config', '--list', '--null').split('\0'):
-    if entry:
-      name, value = entry.split('\n', 1)
-      if name in non_string_options:
-        value = run('git', 'config', non_string_options[name], name)
-      out[name] = value
-  return out
-
-
-def interpret_args(args, dash_dash, default_commit):
-  """Interpret `args` as "[commit] [--] [files...]" and return (commit, files).
-
-  It is assumed that "--" and everything that follows has been removed from
-  args and placed in `dash_dash`.
-
-  If "--" is present (i.e., `dash_dash` is non-empty), the argument to its
-  left (if present) is taken as commit.  Otherwise, the first argument is
-  checked if it is a commit or a file.  If commit is not given,
-  `default_commit` is used."""
-  if dash_dash:
-    if len(args) == 0:
-      commit = default_commit
-    elif len(args) > 1:
-      die('at most one commit allowed; %d given' % len(args))
-    else:
-      commit = args[0]
-    object_type = get_object_type(commit)
-    if object_type not in ('commit', 'tag'):
-      if object_type is None:
-        die("'%s' is not a commit" % commit)
-      else:
-        die("'%s' is a %s, but a commit was expected" % (commit, object_type))
-    files = dash_dash[1:]
-  elif args:
-    if disambiguate_revision(args[0]):
-      commit = args[0]
-      files = args[1:]
-    else:
-      commit = default_commit
-      files = args
-  else:
-    commit = default_commit
-    files = []
-  return commit, files
-
-
-def disambiguate_revision(value):
-  """Returns True if `value` is a revision, False if it is a file, or dies."""
-  # If `value` is ambiguous (neither a commit nor a file), the following
-  # command will die with an appropriate error message.
-  run('git', 'rev-parse', value, verbose=False)
-  object_type = get_object_type(value)
-  if object_type is None:
-    return False
-  if object_type in ('commit', 'tag'):
-    return True
-  die('`%s` is a %s, but a commit or filename was expected' %
-      (value, object_type))
-
-
-def get_object_type(value):
-  """Returns a string description of an object's type, or None if it is not
-  a valid git object."""
-  cmd = ['git', 'cat-file', '-t', value]
-  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-  stdout, stderr = p.communicate()
-  if p.returncode != 0:
-    return None
-  return stdout.strip()
-
-
-def compute_diff_and_extract_lines(commit, files):
-  """Calls compute_diff() followed by extract_lines()."""
-  diff_process = compute_diff(commit, files)
-  changed_lines = extract_lines(diff_process.stdout)
-  diff_process.stdout.close()
-  diff_process.wait()
-  if diff_process.returncode != 0:
-    # Assume error was already printed to stderr.
-    sys.exit(2)
-  return changed_lines
-
-
-def compute_diff(commit, files):
-  """Return a subprocess object producing the diff from `commit`.
-
-  The return value's `stdin` file object will produce a patch with the
-  differences between the working directory and `commit`, filtered on `files`
-  (if non-empty).  Zero context lines are used in the patch."""
-  cmd = ['git', 'diff-index', '-p', '-U0', commit, '--']
-  cmd.extend(files)
-  p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
-  p.stdin.close()
-  return p
-
-
-def extract_lines(patch_file):
-  """Extract the changed lines in `patch_file`.
-
-  The return value is a dictionary mapping filename to a list of (start_line,
-  line_count) pairs.
-
-  The input must have been produced with ``-U0``, meaning unidiff format with
-  zero lines of context.  The return value is a dict mapping filename to a
-  list of line `Range`s."""
-  matches = {}
-  for line in patch_file:
-    match = re.search(r'^\+\+\+\ [^/]+/(.*)', line)
-    if match:
-      filename = match.group(1).rstrip('\r\n')
-    match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line)
-    if match:
-      start_line = int(match.group(1))
-      line_count = 1
-      if match.group(3):
-        line_count = int(match.group(3))
-      if line_count > 0:
-        matches.setdefault(filename, []).append(Range(start_line, line_count))
-  return matches
-
-
-def filter_by_extension(dictionary, allowed_extensions):
-  """Delete every key in `dictionary` that doesn't have an allowed extension.
-
-  `allowed_extensions` must be a collection of lowercase file extensions,
-  excluding the period."""
-  allowed_extensions = frozenset(allowed_extensions)
-  for filename in dictionary.keys():
-    base_ext = filename.rsplit('.', 1)
-    if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions:
-      del dictionary[filename]
-
-
-def cd_to_toplevel():
-  """Change to the top level of the git repository."""
-  toplevel = run('git', 'rev-parse', '--show-toplevel')
-  os.chdir(toplevel)
-
-
-def create_tree_from_workdir(filenames):
-  """Create a new git tree with the given files from the working directory.
-
-  Returns the object ID (SHA-1) of the created tree."""
-  return create_tree(filenames, '--stdin')
-
-
-def run_clang_format_and_save_to_tree(changed_lines, binary='clang-format',
-                                      style=None):
-  """Run clang-format on each file and save the result to a git tree.
-
-  Returns the object ID (SHA-1) of the created tree."""
-  def index_info_generator():
-    for filename, line_ranges in changed_lines.iteritems():
-      mode = oct(os.stat(filename).st_mode)
-      blob_id = clang_format_to_blob(filename, line_ranges, binary=binary,
-                                     style=style)
-      yield '%s %s\t%s' % (mode, blob_id, filename)
-  return create_tree(index_info_generator(), '--index-info')
-
-
-def create_tree(input_lines, mode):
-  """Create a tree object from the given input.
-
-  If mode is '--stdin', it must be a list of filenames.  If mode is
-  '--index-info' is must be a list of values suitable for "git update-index
-  --index-info", such as "<mode> <SP> <sha1> <TAB> <filename>".  Any other mode
-  is invalid."""
-  assert mode in ('--stdin', '--index-info')
-  cmd = ['git', 'update-index', '--add', '-z', mode]
-  with temporary_index_file():
-    p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-    for line in input_lines:
-      p.stdin.write('%s\0' % line)
-    p.stdin.close()
-    if p.wait() != 0:
-      die('`%s` failed' % ' '.join(cmd))
-    tree_id = run('git', 'write-tree')
-    return tree_id
-
-
-def clang_format_to_blob(filename, line_ranges, binary='clang-format',
-                         style=None):
-  """Run clang-format on the given file and save the result to a git blob.
-
-  Returns the object ID (SHA-1) of the created blob."""
-  clang_format_cmd = [binary, filename]
-  if style:
-    clang_format_cmd.extend(['-style='+style])
-  clang_format_cmd.extend([
-      '-lines=%s:%s' % (start_line, start_line+line_count-1)
-      for start_line, line_count in line_ranges])
-  try:
-    clang_format = subprocess.Popen(clang_format_cmd, stdin=subprocess.PIPE,
-                                    stdout=subprocess.PIPE)
-  except OSError as e:
-    if e.errno == errno.ENOENT:
-      die('cannot find executable "%s"' % binary)
-    else:
-      raise
-  clang_format.stdin.close()
-  hash_object_cmd = ['git', 'hash-object', '-w', '--path='+filename, '--stdin']
-  hash_object = subprocess.Popen(hash_object_cmd, stdin=clang_format.stdout,
-                                 stdout=subprocess.PIPE)
-  clang_format.stdout.close()
-  stdout = hash_object.communicate()[0]
-  if hash_object.returncode != 0:
-    die('`%s` failed' % ' '.join(hash_object_cmd))
-  if clang_format.wait() != 0:
-    die('`%s` failed' % ' '.join(clang_format_cmd))
-  return stdout.rstrip('\r\n')
-
-
- at contextlib.contextmanager
-def temporary_index_file(tree=None):
-  """Context manager for setting GIT_INDEX_FILE to a temporary file and deleting
-  the file afterward."""
-  index_path = create_temporary_index(tree)
-  old_index_path = os.environ.get('GIT_INDEX_FILE')
-  os.environ['GIT_INDEX_FILE'] = index_path
-  try:
-    yield
-  finally:
-    if old_index_path is None:
-      del os.environ['GIT_INDEX_FILE']
-    else:
-      os.environ['GIT_INDEX_FILE'] = old_index_path
-    os.remove(index_path)
-
-
-def create_temporary_index(tree=None):
-  """Create a temporary index file and return the created file's path.
-
-  If `tree` is not None, use that as the tree to read in.  Otherwise, an
-  empty index is created."""
-  gitdir = run('git', 'rev-parse', '--git-dir')
-  path = os.path.join(gitdir, temp_index_basename)
-  if tree is None:
-    tree = '--empty'
-  run('git', 'read-tree', '--index-output='+path, tree)
-  return path
-
-
-def print_diff(old_tree, new_tree):
-  """Print the diff between the two trees to stdout."""
-  # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
-  # is expected to be viewed by the user, and only the former does nice things
-  # like color and pagination.
-  subprocess.check_call(['git', 'diff', old_tree, new_tree, '--'])
-
-
-def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
-  """Apply the changes in `new_tree` to the working directory.
-
-  Bails if there are local changes in those files and not `force`.  If
-  `patch_mode`, runs `git checkout --patch` to select hunks interactively."""
-  changed_files = run('git', 'diff-tree', '-r', '-z', '--name-only', old_tree,
-                      new_tree).rstrip('\0').split('\0')
-  if not force:
-    unstaged_files = run('git', 'diff-files', '--name-status', *changed_files)
-    if unstaged_files:
-      print >>sys.stderr, ('The following files would be modified but '
-                           'have unstaged changes:')
-      print >>sys.stderr, unstaged_files
-      print >>sys.stderr, 'Please commit, stage, or stash them first.'
-      sys.exit(2)
-  if patch_mode:
-    # In patch mode, we could just as well create an index from the new tree
-    # and checkout from that, but then the user will be presented with a
-    # message saying "Discard ... from worktree".  Instead, we use the old
-    # tree as the index and checkout from new_tree, which gives the slightly
-    # better message, "Apply ... to index and worktree".  This is not quite
-    # right, since it won't be applied to the user's index, but oh well.
-    with temporary_index_file(old_tree):
-      subprocess.check_call(['git', 'checkout', '--patch', new_tree])
-    index_tree = old_tree
-  else:
-    with temporary_index_file(new_tree):
-      run('git', 'checkout-index', '-a', '-f')
-  return changed_files
-
-
-def run(*args, **kwargs):
-  stdin = kwargs.pop('stdin', '')
-  verbose = kwargs.pop('verbose', True)
-  strip = kwargs.pop('strip', True)
-  for name in kwargs:
-    raise TypeError("run() got an unexpected keyword argument '%s'" % name)
-  p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                       stdin=subprocess.PIPE)
-  stdout, stderr = p.communicate(input=stdin)
-  if p.returncode == 0:
-    if stderr:
-      if verbose:
-        print >>sys.stderr, '`%s` printed to stderr:' % ' '.join(args)
-      print >>sys.stderr, stderr.rstrip()
-    if strip:
-      stdout = stdout.rstrip('\r\n')
-    return stdout
-  if verbose:
-    print >>sys.stderr, '`%s` returned %s' % (' '.join(args), p.returncode)
-  if stderr:
-    print >>sys.stderr, stderr.rstrip()
-  sys.exit(2)
-
-
-def die(message):
-  print >>sys.stderr, 'error:', message
-  sys.exit(2)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/tools/win32/clang-format.exe b/tools/win32/clang-format.exe
deleted file mode 100644
index d42fb80..0000000
Binary files a/tools/win32/clang-format.exe and /dev/null differ

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



More information about the debian-med-commit mailing list