[med-svn] [abyss] 01/10: Imported Upstream version 1.9.0

Andreas Tille tille at debian.org
Thu Jul 16 09:42:32 UTC 2015


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

tille pushed a commit to branch master
in repository abyss.

commit ca88ee12b49db61eb70fc8fcdc2327e0f33565a6
Author: Andreas Tille <tille at debian.org>
Date:   Tue Jul 14 22:30:09 2015 +0200

    Imported Upstream version 1.9.0
---
 .travis.yml                                        |   10 +-
 ABYSS/Makefile.am                                  |    9 +-
 ABYSS/{Abyss.cpp => abyss.cc}                      |   58 +-
 AdjList/AdjList.cpp                                |  229 +-
 AdjList/Makefile.am                                |   13 +
 Align/mergepairs.cc                                |    4 +-
 Assembly/AdjacencyAlgorithm.h                      |   50 +
 Assembly/AssembleAlgorithm.h                       |  146 +
 Assembly/AssemblyAlgorithms.cc                     |   20 +
 Assembly/AssemblyAlgorithms.cpp                    | 1049 ----
 Assembly/AssemblyAlgorithms.h                      |  214 +-
 Assembly/BranchGroup.cpp                           |   86 -
 Assembly/BranchGroup.h                             |  105 +-
 Assembly/BranchRecord.cpp                          |   59 -
 Assembly/BranchRecord.h                            |  149 +-
 Assembly/{BranchRecord.h => BranchRecordBase.h}    |   65 +-
 Assembly/BubbleAlgorithm.h                         |  279 ++
 Assembly/CoverageAlgorithm.h                       |  117 +
 Assembly/DBG.h                                     |  913 ++++
 Assembly/DotWriter.cpp                             |   70 -
 Assembly/DotWriter.h                               |  217 +-
 Assembly/ErodeAlgorithm.h                          |  117 +
 Assembly/ISequenceCollection.h                     |   88 -
 Assembly/LoadAlgorithm.h                           |  182 +
 Assembly/Makefile.am                               |   32 +-
 Assembly/{Options.cpp => Options.cc}               |   82 +-
 Assembly/Options.h                                 |    8 +
 {Common => Assembly}/SeqExt.h                      |   36 +-
 Assembly/SequenceCollection.cpp                    |  291 --
 Assembly/SequenceCollection.h                      |  353 +-
 Assembly/SplitAlgorithm.h                          |   97 +
 Assembly/TrimAlgorithm.h                           |  203 +
 Assembly/{KmerData.h => VertexData.h}              |   75 +-
 Bloom/Bloom.h                                      |  162 +-
 Bloom/BloomFilter.h                                |   89 +-
 Bloom/BloomFilterWindow.h                          |   42 +-
 Bloom/CascadingBloomFilter.h                       |   16 +-
 Bloom/CascadingBloomFilterWindow.h                 |   11 +-
 Bloom/bloom.cc                                     |   58 +-
 CITATION.bib                                       |   10 +
 CITATION.md                                        |   39 +
 ChangeLog                                          |   42 +
 Common/BitUtil.h                                   |  107 +
 Common/ContigProperties.h                          |    6 +-
 Common/Estimate.h                                  |    7 +
 Common/Histogram.h                                 |   44 +-
 Common/InsOrderedMap.h                             |   88 +
 Common/Kmer.cpp                                    |   10 +-
 Common/Kmer.h                                      |   25 +-
 Common/KmerSet.h                                   |   47 +
 Common/Makefile.am                                 |    5 +-
 Common/MemUtils.h                                  |    4 +-
 Common/SAM.h                                       |    3 +-
 Common/SeqExt.cpp                                  |   16 -
 Common/Sequence.cpp                                |    4 +-
 Common/Sequence.h                                  |   82 +
 Common/StringUtil.h                                |   78 +-
 Common/VectorUtil.h                                |   35 +
 Common/Warnings.h                                  |    6 -
 DataBase/DB.cc                                     |  208 +
 DataBase/DB.h                                      |  227 +
 DataBase/Makefile.am                               |   11 +
 DataBase/Options.h                                 |   22 +
 DataBase/abyss-db-txt                              |   35 +
 DataBase/db-csv.cc                                 |  124 +
 DataLayer/FastaReader.cpp                          |    4 +-
 DataLayer/FastaReader.h                            |    4 +-
 DataLayer/FastaWriter.h                            |    2 +-
 DataLayer/Makefile.am                              |    9 +-
 DataLayer/abyss-tofastq.cc                         |    8 +-
 DataLayer/fac.cc                                   |    6 +-
 DistanceEst/DistanceEst.cpp                        |  111 +-
 DistanceEst/MLE.cpp                                |   64 +-
 DistanceEst/Makefile.am                            |    2 +
 FilterGraph/{FilterGraph.cpp => FilterGraph.cc}    |  286 +-
 FilterGraph/Makefile.am                            |    2 +-
 Graph/AllPathsSearch.h                             |    1 -
 Graph/AsqgIO.h                                     |   24 +-
 Graph/BidirectionalBFSVisitor.h                    |   48 +-
 Graph/ConstrainedBidiBFSVisitor.h                  |   14 +-
 Graph/ConstrainedSearch.h                          |    8 +-
 Graph/ContigGraph.h                                |    2 +-
 Graph/ContigGraphAlgorithms.h                      |   14 +-
 Graph/DirectedGraph.h                              |    9 +-
 Graph/ExtendPath.h                                 |  296 ++
 Graph/{AsqgIO.h => GfaIO.h}                        |  118 +-
 Graph/GraphAlgorithms.h                            |   25 +-
 Graph/GraphIO.h                                    |   21 +-
 Graph/GraphUtil.h                                  |   52 +-
 Graph/HashGraph.h                                  |   24 +-
 Graph/Makefile.am                                  |    2 +
 Graph/Options.h                                    |    2 +-
 Graph/Path.h                                       |    6 +-
 Graph/SAMIO.h                                      |    2 +-
 Graph/todot.cc                                     |   19 +-
 IntegrationTest/DIDA/alignment-test.mk             |   84 +
 IntegrationTest/DIDA/assembly-test.mk              |   83 +
 IntegrationTest/DIDA/compare-fastx                 |   14 +
 IntegrationTest/DIDA/compare-sam                   |  110 +
 Konnector/DBGBloom.h                               |    4 +-
 Konnector/DBGBloomAlgorithms.h                     |  122 +-
 Konnector/konnector.cc                             |  683 ++-
 Konnector/konnector.h                              |  485 +-
 LogKmerCount/logcounter.cc                         |    4 +-
 Makefile.am                                        |   31 +-
 Map/Makefile.am                                    |    4 +-
 Map/index.cc                                       |   18 +-
 Map/map.cc                                         |  109 +-
 Map/overlap.cc                                     |    4 +-
 MergePaths/Makefile.am                             |    6 +
 MergePaths/MergeContigs.cpp                        |   84 +-
 MergePaths/MergePaths.cpp                          |   74 +-
 MergePaths/PathConsensus.cpp                       |   77 +-
 Overlap/Overlap.cpp                                |   15 +-
 PairedDBG/BranchRecord.h                           |   43 +
 PairedDBG/Dinuc.h                                  |  167 +
 PairedDBG/KmerPair.cc                              |    4 +
 PairedDBG/KmerPair.h                               |  229 +
 PairedDBG/Makefile.am                              |   26 +
 PairedDBG/PairedDBGAlgorithms.h                    |   42 +
 PairedDBG/SequenceCollection.h                     |   24 +
 PairedDBG/abyss-paired-dbg.cc                      |    1 +
 Parallel/CommLayer.cpp                             |    4 +-
 Parallel/Makefile.am                               |   20 +-
 Parallel/MessageBuffer.cpp                         |   16 +-
 Parallel/MessageBuffer.h                           |   22 +-
 Parallel/Messages.h                                |   45 +-
 Parallel/NetworkSequenceCollection.cpp             |  171 +-
 Parallel/NetworkSequenceCollection.h               |  118 +-
 Parallel/SequenceCollection.h                      |   10 +
 Parallel/parallelAbyss.cpp                         |   37 +-
 ParseAligns/Makefile.am                            |    2 +
 ParseAligns/abyss-fixmate.cc                       |   98 +-
 PathOverlap/Makefile.am                            |    2 +
 PathOverlap/PathOverlap.cpp                        |   58 +-
 PopBubbles/PopBubbles.cpp                          |   38 +-
 README.md                                          |  111 +-
 Scaffold/Makefile.am                               |    2 +
 Scaffold/drawgraph.cc                              |   89 +-
 Scaffold/junction.cc                               |    2 +-
 Scaffold/scaffold.cc                               |  152 +-
 Sealer/Makefile.am                                 |   29 +
 Sealer/README.md                                   |  171 +
 Sealer/sealer.cc                                   | 1025 ++++
 SimpleGraph/Makefile.am                            |    2 +
 SimpleGraph/SimpleGraph.cpp                        |   84 +-
 Unittest/Common/BitUtilTest.cpp                    |  230 +
 Unittest/Common/StringUtilTest.cpp                 |   30 +-
 Unittest/DBG/LoadAlgorithmTest.cpp                 |   43 +
 Unittest/Graph/AllPathsSearchTest.cpp              |    1 -
 Unittest/Graph/BidirectionalBFSTest.cpp            |   31 +-
 Unittest/Graph/ConstrainedBidiBFSVisitorTest.cpp   |    1 -
 Unittest/Graph/ExtendPathTest.cpp                  |  345 ++
 Unittest/Konnector/BloomFilter.cc                  |   41 +-
 Unittest/Konnector/DBGBloomAlgorithmsTest.cpp      |   77 +-
 Unittest/Konnector/DBGBloomTest.cpp                |    2 +-
 Unittest/Konnector/integration-tests.mk            |    8 +-
 Unittest/Makefile.am                               |  213 +-
 Unittest/PairedDBG/BranchRecordTest.cpp            |   58 +
 Unittest/PairedDBG/DinucTest.cc                    |   82 +
 Unittest/PairedDBG/KmerPairTest.cc                 |   96 +
 Unittest/PairedDBG/LoadAlgorithmTest.cpp           |   53 +
 Unittest/PairedDBG/test.fa                         |    2 +
 Unittest/PairedDBG/test.png                        |  Bin 0 -> 156866 bytes
 Unittest/PairedDBG/test.svg                        |  859 ++++
 bin/Makefile.am                                    |   14 +-
 bin/abyss-dida                                     |  107 +
 bin/abyss-fac.pl                                   |    4 +-
 bin/abyss-fatoagp                                  |    2 +
 bin/abyss-nompi                                    |    6 +
 bin/abyss-pe                                       |  254 +-
 circle.yml                                         |   11 +
 configure.ac                                       |  110 +-
 doc/ABYSS.1                                        |    4 +-
 doc/abyss-pe.1                                     |   55 +-
 doc/abyss-tofastq.1                                |    4 +-
 doc/flowchart.graffle                              |    2 +-
 lib/gtest-1.7.0/CHANGES                            |  157 +
 lib/gtest-1.7.0/CONTRIBUTORS                       |   37 +
 lib/gtest-1.7.0/LICENSE                            |   28 +
 lib/gtest-1.7.0/Makefile.am                        |   42 +
 lib/gtest-1.7.0/README                             |  435 ++
 lib/gtest-1.7.0/include/gtest/gtest-death-test.h   |  294 ++
 lib/gtest-1.7.0/include/gtest/gtest-message.h      |  250 +
 lib/gtest-1.7.0/include/gtest/gtest-param-test.h   | 1421 ++++++
 .../include/gtest/gtest-param-test.h.pump          |  487 ++
 lib/gtest-1.7.0/include/gtest/gtest-printers.h     |  855 ++++
 lib/gtest-1.7.0/include/gtest/gtest-spi.h          |  232 +
 lib/gtest-1.7.0/include/gtest/gtest-test-part.h    |  179 +
 lib/gtest-1.7.0/include/gtest/gtest-typed-test.h   |  259 +
 lib/gtest-1.7.0/include/gtest/gtest.h              | 2291 +++++++++
 lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h    |  358 ++
 lib/gtest-1.7.0/include/gtest/gtest_prod.h         |   58 +
 .../gtest/internal/gtest-death-test-internal.h     |  319 ++
 .../include/gtest/internal/gtest-filepath.h        |  206 +
 .../include/gtest/internal/gtest-internal.h        | 1158 +++++
 .../include/gtest/internal/gtest-linked_ptr.h      |  233 +
 .../gtest/internal/gtest-param-util-generated.h    | 5143 ++++++++++++++++++++
 .../internal/gtest-param-util-generated.h.pump     |  301 ++
 .../include/gtest/internal/gtest-param-util.h      |  619 +++
 .../include/gtest/internal/gtest-port.h            | 1947 ++++++++
 .../include/gtest/internal/gtest-string.h          |  167 +
 .../include/gtest/internal/gtest-tuple.h           | 1012 ++++
 .../include/gtest/internal/gtest-tuple.h.pump      |  339 ++
 .../include/gtest/internal/gtest-type-util.h       | 3331 +++++++++++++
 .../include/gtest/internal/gtest-type-util.h.pump  |  297 ++
 lib/gtest-1.7.0/src/gtest-all.cc                   |   48 +
 lib/gtest-1.7.0/src/gtest-death-test.cc            | 1344 +++++
 lib/gtest-1.7.0/src/gtest-filepath.cc              |  382 ++
 lib/gtest-1.7.0/src/gtest-internal-inl.h           | 1218 +++++
 lib/gtest-1.7.0/src/gtest-port.cc                  |  805 +++
 lib/gtest-1.7.0/src/gtest-printers.cc              |  363 ++
 lib/gtest-1.7.0/src/gtest-test-part.cc             |  110 +
 lib/gtest-1.7.0/src/gtest-typed-test.cc            |  110 +
 lib/gtest-1.7.0/src/gtest.cc                       | 5015 +++++++++++++++++++
 lib/gtest-1.7.0/src/gtest_main.cc                  |   38 +
 m4/m4_ax_pthread.m4                                |  332 ++
 217 files changed, 44455 insertions(+), 3639 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 3e5e539..46bc1ac 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,10 @@ compiler:
   - gcc
   - clang
 before_install:
- - sudo apt-get update -qq
- - sudo apt-get install -qq libboost-dev libopenmpi-dev libsparsehash-dev
-script: ./autogen.sh && ./configure --with-mpi=/usr/lib/openmpi && make
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev
+script:
+  - ./autogen.sh
+  - ./configure --with-mpi=/usr/lib/openmpi
+  - make
+  - make check
diff --git a/ABYSS/Makefile.am b/ABYSS/Makefile.am
index 3ff28e1..830eee0 100644
--- a/ABYSS/Makefile.am
+++ b/ABYSS/Makefile.am
@@ -1,13 +1,12 @@
 bin_PROGRAMS = ABYSS
 
-ABYSS_CPPFLAGS = -I$(top_srcdir) \
-	-I$(top_srcdir)/Assembly \
-	-I$(top_srcdir)/Common \
-	-I$(top_srcdir)/DataLayer
+ABYSS_CPPFLAGS = -I$(top_srcdir)
 
 ABYSS_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/Assembly/libassembly.a \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
-ABYSS_SOURCES = Abyss.cpp
+ABYSS_SOURCES = abyss.cc
diff --git a/ABYSS/Abyss.cpp b/ABYSS/abyss.cc
similarity index 75%
rename from ABYSS/Abyss.cpp
rename to ABYSS/abyss.cc
index 2b68741..e3aa061 100644
--- a/ABYSS/Abyss.cpp
+++ b/ABYSS/abyss.cc
@@ -1,20 +1,22 @@
-#include "Assembly/Options.h"
-#include "AssemblyAlgorithms.h"
-#include "DotWriter.h"
-#include "FastaWriter.h"
-#include "Histogram.h"
-#include "ISequenceCollection.h"
-#include "SequenceCollection.h"
-#include "Timer.h"
-#include "Uncompress.h"
+#if PAIRED_DBG
+# include "PairedDBG/SequenceCollection.h"
+# include "PairedDBG/PairedDBGAlgorithms.h"
+#else
+# include "Assembly/SequenceCollection.h"
+#endif
+#include "Assembly/AssemblyAlgorithms.h"
+#include "Assembly/DotWriter.h"
 #include <algorithm>
 #include <cstdio> // for setvbuf
 #include <fstream>
 #include <iostream>
 #include <sstream>
+#include "DataBase/DB.h"
 
 using namespace std;
 
+DB db;
+
 static void removeLowCoverageContigs(SequenceCollectionHash& g)
 {
 	AssemblyAlgorithms::markAmbiguous(&g);
@@ -54,9 +56,12 @@ static void assemble(const string& pathIn, const string& pathOut)
 
 	if (!pathIn.empty())
 		AssemblyAlgorithms::loadSequences(&g, pathIn.c_str());
-	for_each(opt::inFiles.begin(), opt::inFiles.end(),
-			bind1st(ptr_fun(AssemblyAlgorithms::loadSequences), &g));
+	for_each(opt::inFiles.begin(), opt::inFiles.end(), bind1st(
+			ptr_fun(AssemblyAlgorithms::loadSequences<SequenceCollectionHash>),
+			&g));
 	size_t numLoaded = g.size();
+	if (!opt::db.empty())
+		addToDb(db, "loadedKmer", numLoaded);
 	cout << "Loaded " << numLoaded << " k-mer\n";
 	g.setDeletedKey();
 	g.shrink();
@@ -71,6 +76,10 @@ static void assemble(const string& pathIn, const string& pathOut)
 	cout << "Generating adjacency" << endl;
 	AssemblyAlgorithms::generateAdjacency(&g);
 
+#if PAIRED_DBG
+	removePairedDBGInconsistentEdges(g);
+#endif
+
 erode:
 	if (opt::erode > 0) {
 		cout << "Eroding tips" << endl;
@@ -95,7 +104,6 @@ erode:
 	write_graph(opt::graphPath, g);
 
 	AssemblyAlgorithms::markAmbiguous(&g);
-
 	FastaWriter writer(pathOut.c_str());
 	unsigned nContigs = AssemblyAlgorithms::assemble(&g, &writer);
 	if (nContigs == 0) {
@@ -118,6 +126,9 @@ int main(int argc, char* const* argv)
 	// Set stdout to be line buffered.
 	setvbuf(stdout, NULL, _IOLBF, 0);
 
+#if PAIRED_DBG
+	opt::singleKmerSize = -1;
+#endif
 	opt::parse(argc, argv);
 
 	bool krange = opt::kMin != opt::kMax;
@@ -125,11 +136,29 @@ int main(int argc, char* const* argv)
 		cout << "Assembling k=" << opt::kMin << "-" << opt::kMax
 				<< ":" << opt::kStep << endl;
 
+	if (!opt::db.empty()) {
+		init(db,
+				opt::getUvalue(),
+				opt::getVvalue(),
+				"ABYSS",
+				opt::getCommand(),
+				opt::getMetaValue());
+		addToDb(db, "SS", opt::ss);
+		addToDb(db, "k", opt::kmerSize);
+		addToDb(db, "singleK", opt::singleKmerSize);
+		addToDb(db, "numProc", 1);
+	}
+
 	for (unsigned k = opt::kMin; k <= opt::kMax; k += opt::kStep) {
 		if (krange)
 			cout << "Assembling k=" << k << endl;
 		opt::kmerSize = k;
-		Kmer::setLength(k);
+#if PAIRED_DBG
+		Kmer::setLength(opt::singleKmerSize);
+		KmerPair::setLength(opt::kmerSize);
+#else
+		Kmer::setLength(opt::kmerSize);
+#endif
 
 		if (k > opt::kMin) {
 			// Reset the assembly options to defaults.
@@ -149,5 +178,8 @@ int main(int argc, char* const* argv)
 			k1 << opt::contigsPath.c_str();
 		assemble(k0.str(), k1.str());
 	}
+
+	if (!opt::db.empty())
+		addToDb(db, AssemblyAlgorithms::tempStatMap);
 	return 0;
 }
diff --git a/AdjList/AdjList.cpp b/AdjList/AdjList.cpp
index 521d338..3135b9c 100644
--- a/AdjList/AdjList.cpp
+++ b/AdjList/AdjList.cpp
@@ -1,4 +1,5 @@
 #include "Common/Options.h"
+#include "Common/Sequence.h"
 #include "DataLayer/Options.h"
 #include "ContigNode.h"
 #include "ContigProperties.h"
@@ -18,15 +19,21 @@
 #include <cstdlib>
 #include <getopt.h>
 #include <iostream>
-#include <iterator>
 #include <set>
-#include <sstream>
 #include <vector>
 
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
+
+#if PAIRED_DBG
+#include "PairedDBG/KmerPair.h"
+#endif
+
 using namespace std;
 
 #define PROGRAM "AdjList"
 
+DB db;
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Shaun Jackman.\n"
@@ -42,21 +49,36 @@ static const char USAGE_MESSAGE[] =
 "\n"
 " Options:\n"
 "\n"
-"  -k, --kmer=K          find overlaps of up to K-1 bases\n"
+"  -k, --kmer=N          the length of a k-mer (when -K is not set)\n"
+"                        or the span of a k-mer pair (when -K is set)\n"
+"  -K, --single-kmer=N   the length of a single k-mer in a k-mer pair\n"
 "  -m, --min-overlap=M   require a minimum overlap of M bases [50]\n"
-"      --adj             output the results in adj format [default]\n"
-"      --dot             output the results in dot format\n"
-"      --sam             output the results in SAM format\n"
+"      --adj             output the graph in ADJ format [default]\n"
+"      --asqg            output the graph in ASQG format\n"
+"      --dot             output the graph in GraphViz format\n"
+"      --gv              output the graph in GraphViz format\n"
+"      --gfa             output the graph in GFA format\n"
+"      --sam             output the graph in SAM format\n"
 "      --SS              expect contigs to be oriented correctly\n"
 "      --no-SS           no assumption about contig orientation\n"
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for database\n"
+"      --strain=NAME     specify strain NAME for database\n"
+"      --species=NAME    specify species NAME for database\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k; // used by GraphIO
+
+	/** Length of a single-kmer in a kmer pair */
+	unsigned singleKmerSize = 0;
+
 	int format; // used by GraphIO
 
 	/** Run a strand-specific RNA-Seq assembly. */
@@ -66,21 +88,30 @@ namespace opt {
 	static unsigned minOverlap = 50;
 }
 
-static const char shortopts[] = "k:m:v";
+static const char shortopts[] = "k:K:m:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "kmer",    required_argument, NULL, 'k' },
+	{ "single-kmer", required_argument, NULL, 'K' },
 	{ "min-overlap", required_argument, NULL, 'm' },
 	{ "adj",     no_argument,       &opt::format, ADJ },
+	{ "asqg",    no_argument,       &opt::format, ASQG },
 	{ "dot",     no_argument,       &opt::format, DOT },
+	{ "gv",      no_argument,       &opt::format, DOT },
+	{ "gfa",     no_argument,       &opt::format, GFA },
 	{ "sam",     no_argument,       &opt::format, SAM },
 	{ "SS",      no_argument,       &opt::ss, 1 },
 	{ "no-SS",   no_argument,       &opt::ss, 0 },
 	{ "verbose", no_argument,       NULL, 'v' },
 	{ "help",    no_argument,       NULL, OPT_HELP },
 	{ "version", no_argument,       NULL, OPT_VERSION },
+	{ "db",      required_argument, NULL, OPT_DB },
+	{ "library", required_argument, NULL, OPT_LIBRARY },
+	{ "strain",  required_argument, NULL, OPT_STRAIN },
+	{ "species", required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -155,15 +186,13 @@ static void addOverlapsSA(Graph& g, const vector<Kmer>& prefixes)
 	}
 }
 
-/** An index of suffixes of k-1 bp. */
-typedef unordered_map<Kmer, vector<ContigNode>, hash<Kmer> >
-	SuffixMap;
-
 /** Read contigs. Add contig properties to the graph. Add prefixes to
  * the collection and add suffixes to their index.
  */
+template <class KmerType>
 static void readContigs(const string& path,
-		Graph& g, vector<Kmer>& prefixes, SuffixMap& suffixMap)
+		Graph& g, vector<KmerType>& prefixes,
+		unordered_map<KmerType, vector<ContigNode> >& suffixMap)
 {
 	if (opt::verbose > 0)
 		cerr << "Reading `" << path << "'...\n";
@@ -171,7 +200,7 @@ static void readContigs(const string& path,
 	unsigned count = 0;
 	FastaReader in(path.c_str(), FastaReader::FOLD_CASE);
 	for (FastaRecord rec; in >> rec;) {
-		const Sequence& seq = rec.seq;
+		Sequence& seq = rec.seq;
 		if (count++ == 0) {
 			// Detect colour-space contigs.
 			opt::colourSpace = isdigit(seq[0]);
@@ -182,11 +211,13 @@ static void readContigs(const string& path,
 				assert(isalpha(seq[0]));
 		}
 
+		flattenAmbiguityCodes(seq);
+
 		// Add the prefix to the collection.
 		unsigned overlap = opt::k - 1;
 		assert(seq.length() > overlap);
-		Kmer prefix(seq.substr(0, overlap));
-		Kmer suffix(seq.substr(seq.length() - overlap));
+		KmerType prefix(seq.substr(0, overlap));
+		KmerType suffix(seq.substr(seq.length() - overlap));
 		prefixes.push_back(prefix);
 		prefixes.push_back(reverseComplement(suffix));
 
@@ -201,6 +232,89 @@ static void readContigs(const string& path,
 	assert(in.eof());
 }
 
+/** Build contig overlap graph. */
+template <class KmerType>
+static void buildOverlapGraph(Graph& g, vector<KmerType>& prefixes,
+	unordered_map<KmerType, vector<ContigNode> >& suffixMap)
+{
+	// Add the overlap edges of exactly k-1 bp.
+
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	typedef unordered_map<KmerType, vector<ContigNode> > SuffixMap;
+	typedef typename vector<KmerType>::const_iterator PrefixIterator;
+	typedef const typename SuffixMap::mapped_type Edges;
+	typedef typename SuffixMap::mapped_type::const_iterator SuffixIterator;
+
+	if (opt::verbose > 0)
+		cerr << "Finding overlaps of exactly k-1 bp...\n";
+	for (PrefixIterator it = prefixes.begin(); it != prefixes.end(); ++it) {
+		ContigNode v(it - prefixes.begin());
+		Edges& edges = suffixMap[*it];
+		for (SuffixIterator itu = edges.begin(); itu != edges.end(); ++itu) {
+			V uc = get(vertex_complement, g, *itu);
+			V vc = get(vertex_complement, g, v);
+			if (opt::ss && uc.sense() != vc.sense())
+				continue;
+			add_edge(vc, uc, -(int)opt::k + 1, static_cast<DG&>(g));
+		}
+	}
+	SuffixMap().swap(suffixMap);
+
+	if (opt::verbose > 0)
+		printGraphStats(cerr, g);
+}
+
+template <class KmerType>
+void loadDataStructures(Graph& g, vector<KmerType>& prefixes,
+	unordered_map<KmerType, vector<ContigNode> >& suffixMap,
+	int argc, char** argv)
+{
+	if (optind < argc) {
+		for (; optind < argc; optind++)
+			readContigs(argv[optind], g, prefixes, suffixMap);
+	} else
+		readContigs("-", g, prefixes, suffixMap);
+	g_contigNames.lock();
+}
+
+/** Build contig overlap graph for standard de Bruijn graph */
+void buildOverlapGraph(Graph& g, int argc, char** argv)
+{
+	Kmer::setLength(opt::k - 1);
+
+	vector<Kmer> prefixes;
+	unordered_map<Kmer, vector<ContigNode> >
+		suffixMap(prefixes.size());
+
+	loadDataStructures(g, prefixes, suffixMap, argc, argv);
+	buildOverlapGraph(g, prefixes, suffixMap);
+
+	if (opt::minOverlap < opt::k - 1) {
+		// Add the overlap edges of fewer than k-1 bp.
+		if (opt::verbose > 0)
+			cerr << "Finding overlaps of fewer than k-1 bp...\n";
+		addOverlapsSA(g, prefixes);
+		if (opt::verbose > 0)
+			printGraphStats(cerr, g);
+	}
+}
+
+#if PAIRED_DBG
+/** Build contig overlap graph for paired de Bruijn graph */
+void buildPairedOverlapGraph(Graph& g, int argc, char** argv)
+{
+	Kmer::setLength(opt::singleKmerSize - 1);
+	KmerPair::setLength(opt::k - 1);
+
+	vector<KmerPair> prefixes;
+	unordered_map<KmerPair, vector<ContigNode> >
+		suffixMap(prefixes.size());
+
+	loadDataStructures(g, prefixes, suffixMap, argc, argv);
+	buildOverlapGraph(g, prefixes, suffixMap);
+}
+#endif
+
 int main(int argc, char** argv)
 {
 	string commandLine;
@@ -212,6 +326,9 @@ int main(int argc, char** argv)
 		commandLine = ss.str();
 	}
 
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -219,6 +336,7 @@ int main(int argc, char** argv)
 		switch (c) {
 			case '?': die = true; break;
 			case 'k': arg >> opt::k; break;
+			case 'K': arg >> opt::singleKmerSize; break;
 			case 'm': arg >> opt::minOverlap; break;
 			case 'v': opt::verbose++; break;
 			case OPT_HELP:
@@ -227,6 +345,14 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db; break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0]; break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1]; break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -250,52 +376,45 @@ int main(int argc, char** argv)
 		opt::minOverlap = opt::k - 1;
 	opt::minOverlap = min(opt::minOverlap, opt::k - 1);
 
+	if (!opt::db.empty())
+		init (db, opt::db, opt::verbose, PROGRAM, opt::getCommand(argc, argv), opt::metaVars);
 	opt::trimMasked = false;
-	Kmer::setLength(opt::k - 1);
-	Graph g;
-	vector<Kmer> prefixes;
-	SuffixMap suffixMap(prefixes.size());
-	if (optind < argc) {
-		for (; optind < argc; optind++)
-			readContigs(argv[optind], g, prefixes, suffixMap);
-	} else
-		readContigs("-", g, prefixes, suffixMap);
-	g_contigNames.lock();
-
-	// Add the overlap edges of exactly k-1 bp.
-	typedef graph_traits<Graph>::vertex_descriptor V;
-	if (opt::verbose > 0)
-		cerr << "Finding overlaps of exactly k-1 bp...\n";
-	for (vector<Kmer>::const_iterator it = prefixes.begin();
-			it != prefixes.end(); ++it) {
-		ContigNode v(it - prefixes.begin());
-		const SuffixMap::mapped_type& edges = suffixMap[*it];
-		for (SuffixMap::mapped_type::const_iterator
-				itu = edges.begin(); itu != edges.end(); ++itu) {
-			V uc = get(vertex_complement, g, *itu);
-			V vc = get(vertex_complement, g, v);
-			if (opt::ss && uc.sense() != vc.sense())
-				continue;
-			add_edge(vc, uc, -(int)opt::k + 1, static_cast<DG&>(g));
-		}
-	}
-	SuffixMap().swap(suffixMap);
 
-	if (opt::verbose > 0)
-		printGraphStats(cerr, g);
+	// contig overlap graph
+	Graph g;
 
-	if (opt::minOverlap < opt::k - 1) {
-		// Add the overlap edges of fewer than k-1 bp.
-		if (opt::verbose > 0)
-			cerr << "Finding overlaps of fewer than k-1 bp...\n";
-		addOverlapsSA(g, prefixes);
-		if (opt::verbose > 0)
-			printGraphStats(cerr, g);
-	}
+#if PAIRED_DBG
+	if (opt::singleKmerSize > 0)
+		buildPairedOverlapGraph(g, argc, argv);
+	else
+		buildOverlapGraph(g, argc, argv);
+#else
+	buildOverlapGraph(g, argc, argv);
+#endif
 
 	// Output the graph.
 	write_graph(cout, g, PROGRAM, commandLine);
 	assert(cout.good());
+	vector<int> vals = make_vector<int>()
+		<< opt::ss
+		<< opt::k;
+	vector<int> new_vals = passGraphStatsVal(g);
+	vals.insert(vals.end(), new_vals.begin(), new_vals.end());
+
+	vector<string> keys = make_vector<string>()
+		<< "SS"
+		<< "K"
+		<< "V"
+		<< "E"
+		<< "degree0pctg"
+		<< "degree1pctg"
+		<< "degree234pctg"
+		<< "degree5pctg"
+		<< "degree_max";
+	if (!opt::db.empty()) {
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
 
 	return 0;
 }
diff --git a/AdjList/Makefile.am b/AdjList/Makefile.am
index e92cb81..195adb8 100644
--- a/AdjList/Makefile.am
+++ b/AdjList/Makefile.am
@@ -4,9 +4,22 @@ AdjList_CPPFLAGS = -I$(top_srcdir) \
 	-I$(top_srcdir)/Common \
 	-I$(top_srcdir)/DataLayer
 
+if PAIRED_DBG
+AdjList_CPPFLAGS += -DPAIRED_DBG
+endif
+
 AdjList_LDADD = \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
+if PAIRED_DBG
+AdjList_LDADD += \
+	$(top_builddir)/PairedDBG/libpaireddbg.a
+endif
+
+AdjList_LDADD += \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS)
+
 AdjList_SOURCES = \
 	AdjList.cpp
diff --git a/Align/mergepairs.cc b/Align/mergepairs.cc
index 1f104e9..af54f29 100644
--- a/Align/mergepairs.cc
+++ b/Align/mergepairs.cc
@@ -289,10 +289,10 @@ int main(int argc, char** argv)
 			case '2': arg >> opt::max_len_2; break;
 			case 'v': opt::verbose++; break;
 			case OPT_HELP:
-					  cerr << USAGE_MESSAGE;
+					  cout << USAGE_MESSAGE;
 					  exit(EXIT_SUCCESS);
 			case OPT_VERSION:
-					  cerr << VERSION_MESSAGE;
+					  cout << VERSION_MESSAGE;
 					  exit(EXIT_SUCCESS);
 		}
 		if (optarg != NULL && !arg.eof()) {
diff --git a/Assembly/AdjacencyAlgorithm.h b/Assembly/AdjacencyAlgorithm.h
new file mode 100644
index 0000000..60fab06
--- /dev/null
+++ b/Assembly/AdjacencyAlgorithm.h
@@ -0,0 +1,50 @@
+#ifndef ASSEMBLY_ADJACENCYALGORITHM_H
+#define ASSEMBLY_ADJACENCYALGORITHM_H 1
+
+namespace AssemblyAlgorithms {
+
+/** Generate the adjacency information for each sequence in the
+ * collection. */
+template <typename Graph>
+size_t generateAdjacency(Graph* seqCollection)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+	typedef typename Graph::Symbol Symbol;
+	typedef typename Graph::SymbolSet SymbolSet;
+
+	Timer timer("GenerateAdjacency");
+
+	size_t count = 0;
+	size_t numBasesSet = 0;
+	for (typename Graph::iterator iter = seqCollection->begin();
+			iter != seqCollection->end(); ++iter) {
+		if (iter->second.deleted())
+			continue;
+
+		if (++count % 1000000 == 0)
+			logger(1) << "Finding adjacent k-mer: " << count << '\n';
+
+		for (extDirection dir = SENSE; dir <= ANTISENSE; ++dir) {
+			V testSeq(iter->first);
+			Symbol adjBase = testSeq.shift(dir);
+			for (unsigned i = 0; i < SymbolSet::NUM; ++i) {
+				testSeq.setLastBase(dir, Symbol(i));
+				if (seqCollection->setBaseExtension(
+							testSeq, !dir, adjBase))
+					numBasesSet++;
+			}
+		}
+		seqCollection->pumpNetwork();
+	}
+
+	if (numBasesSet > 0) {
+		logger(0) << "Added " << numBasesSet << " edges.\n";
+		if (!opt::db.empty())
+			addToDb("EdgesGenerated", numBasesSet);
+	}
+	return numBasesSet;
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/AssembleAlgorithm.h b/Assembly/AssembleAlgorithm.h
new file mode 100644
index 0000000..230dec1
--- /dev/null
+++ b/Assembly/AssembleAlgorithm.h
@@ -0,0 +1,146 @@
+#ifndef ASSEMBLY_ASSEMBLEALGORITHM_H
+#define ASSEMBLY_ASSEMBLEALGORITHM_H 1
+
+#include "DataLayer/FastaWriter.h"
+#include <iostream>
+#include <climits>
+
+namespace AssemblyAlgorithms {
+
+/** Assemble a contig.
+ * @return the number of k-mer below the coverage threshold
+ */
+template <typename Graph>
+size_t assembleContig(
+		Graph* seqCollection, FastaWriter* writer,
+		BranchRecord& branch, unsigned id)
+{
+	assert(!branch.isActive());
+	assert(branch.getState() == BS_NOEXT
+			|| branch.getState() == BS_AMBI_SAME
+			|| branch.getState() == BS_AMBI_OPP);
+
+	// Assemble the contig.
+	Sequence contig(branch);
+
+	size_t kmerCount = branch.calculateBranchMultiplicity();
+	if (writer != NULL)
+		writer->WriteSequence(contig, id, kmerCount);
+
+	// Remove low-coverage contigs.
+	float coverage = (float)kmerCount / branch.size();
+	if (opt::coverage > 0 && coverage < opt::coverage) {
+		for (BranchRecord::iterator it = branch.begin();
+				it != branch.end(); ++it)
+			seqCollection->remove(it->first);
+		return branch.size();
+	}
+	return 0;
+}
+
+/** Assemble contigs.
+ * @return the number of contigs assembled
+ */
+static inline
+size_t assemble(SequenceCollectionHash* seqCollection,
+		FastaWriter* fileWriter = NULL)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	typedef Graph::SymbolSetPair SymbolSetPair;
+
+	Timer timer("Assemble");
+
+	size_t kmerCount = 0;
+	unsigned contigID = 0;
+	size_t assembledKmer = 0;
+	size_t lowCoverageKmer = 0;
+	size_t lowCoverageContigs = 0;
+
+	for (Graph::iterator iter = seqCollection->begin();
+			iter != seqCollection->end(); ++iter) {
+		if (iter->second.deleted())
+			continue;
+		kmerCount++;
+
+		extDirection dir;
+		SeqContiguity status = checkSeqContiguity(*iter, dir, true);
+		if (status == SC_CONTIGUOUS)
+			continue;
+		else if(status == SC_ISLAND)
+		{
+			BranchRecord currBranch(SENSE);
+			currBranch.push_back(*iter);
+			currBranch.terminate(BS_NOEXT);
+			size_t removed = assembleContig(seqCollection,
+					fileWriter, currBranch, contigID++);
+			assembledKmer += currBranch.size();
+			if (removed > 0) {
+				lowCoverageContigs++;
+				lowCoverageKmer += removed;
+			}
+			continue;
+		}
+		assert(status == SC_ENDPOINT);
+
+		BranchRecord currBranch(dir);
+		currBranch.push_back(*iter);
+		V currSeq = iter->first;
+		extendBranch(currBranch, currSeq,
+				iter->second.getExtension(dir));
+		assert(currBranch.isActive());
+		while(currBranch.isActive())
+		{
+			SymbolSetPair extRec;
+			int multiplicity = -1;
+			bool success = seqCollection->getSeqData(
+					currSeq, extRec, multiplicity);
+			assert(success);
+			(void)success;
+			processLinearExtensionForBranch(currBranch,
+					currSeq, extRec, multiplicity, UINT_MAX);
+		}
+
+		if ((opt::ss && currBranch.getDirection() == SENSE)
+				|| (!opt::ss && currBranch.isCanonical())) {
+			size_t removed = assembleContig(seqCollection,
+					fileWriter, currBranch, contigID++);
+			assembledKmer += currBranch.size();
+			if (removed > 0) {
+				lowCoverageContigs++;
+				lowCoverageKmer += removed;
+			}
+		}
+
+		seqCollection->pumpNetwork();
+	}
+
+	if (opt::coverage > 0) {
+		std::cout << "Found " << assembledKmer << " k-mer in " << contigID
+			<< " contigs before removing low-coverage contigs.\n"
+			"Removed " << lowCoverageKmer << " k-mer in "
+				<< lowCoverageContigs << " low-coverage contigs.\n";
+		tempCounter[3] += lowCoverageContigs;
+		tempCounter[4] += lowCoverageKmer;
+	} else {
+		assert(assembledKmer <= kmerCount);
+		size_t circularKmer = kmerCount - assembledKmer;
+		if (circularKmer > 0)
+			std::cout << "Left " << circularKmer
+				<< " unassembled k-mer in circular contigs.\n";
+		std::cout << "Assembled " << assembledKmer << " k-mer in "
+			<< contigID << " contigs.\n";
+		if (!opt::db.empty()) {
+			addToDb("finalAmbgVertices", tempCounter[5]);
+			//addToDb("finalAmbgEdges", tempCounter[6]);
+			tempCounter.assign(16,0);
+			addToDb("assembledKmerNum", assembledKmer);
+			addToDb("assembledCntg", contigID);
+		}
+	}
+	return contigID;
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/AssemblyAlgorithms.cc b/Assembly/AssemblyAlgorithms.cc
new file mode 100644
index 0000000..c79388f
--- /dev/null
+++ b/Assembly/AssemblyAlgorithms.cc
@@ -0,0 +1,20 @@
+#include "config.h"
+#include "Common/InsOrderedMap.h"
+#include <string>
+#include <vector>
+
+namespace AssemblyAlgorithms
+{
+
+/** The number of k-mer that have been eroded. */
+size_t g_numEroded;
+
+std::vector<size_t> tempCounter(16,0);
+InsOrderedMap<std::string,int> tempStatMap;
+
+void addToDb(const std::string& key, const int& value)
+{
+	tempStatMap.push_back(key, value);
+}
+
+};
diff --git a/Assembly/AssemblyAlgorithms.cpp b/Assembly/AssemblyAlgorithms.cpp
deleted file mode 100644
index d50b360..0000000
--- a/Assembly/AssemblyAlgorithms.cpp
+++ /dev/null
@@ -1,1049 +0,0 @@
-#include "AssemblyAlgorithms.h"
-#include "Assembly/Options.h"
-#include "Common/Options.h"
-#include "FastaReader.h"
-#include "FastaWriter.h"
-#include "Histogram.h"
-#include "IOUtil.h"
-#include "Log.h"
-#include "SequenceCollection.h"
-#include "StringUtil.h"
-#include "Timer.h"
-#include <algorithm>
-#include <cctype>
-#include <climits> // for UINT_MAX
-#include <cmath>
-#include <iostream>
-#include <sstream>
-#include <vector>
-
-using namespace std;
-
-namespace AssemblyAlgorithms
-{
-
-/** Return the kmer which are adjacent to this kmer. */
-void generateSequencesFromExtension(const Kmer& currSeq,
-		extDirection dir, SeqExt extension, vector<Kmer>& outseqs)
-{
-	vector<Kmer> extensions;
-	Kmer extSeq(currSeq);
-	extSeq.shift(dir);
-
-	// Check for the existance of the 4 possible extensions
-	for (unsigned i = 0; i < NUM_BASES; i++) {
-		// Does this sequence have an extension?
-		if(extension.checkBase(i))
-		{
-			extSeq.setLastBase(dir, i);
-			outseqs.push_back(extSeq);
-		}
-	}
-}
-
-/** Load k-mer with coverage data.
- * @return the number of k-mer loaded
- */
-static size_t loadKmer(ISequenceCollection& g, FastaReader& in)
-{
-	assert(opt::rank == -1);
-	size_t count = 0;
-	for (FastaRecord rec; in >> rec;) {
-		assert(rec.seq.size() == opt::kmerSize);
-		istringstream iss(rec.id);
-		float coverage = 1;
-		iss >> coverage;
-		assert(iss);
-		assert(iss.eof());
-		g.add(Kmer(rec.seq), max(1, (int)ceilf(coverage)));
-
-		if (++count % 1000000 == 0) {
-			logger(1) << "Read " << count << " k-mer. ";
-			g.printLoad();
-		}
-		g.pumpNetwork();
-	}
-	assert(in.eof());
-	return count;
-}
-
-/** Load sequence data into the collection. */
-void loadSequences(ISequenceCollection* seqCollection, string inFile)
-{
-	Timer timer("LoadSequences " + inFile);
-
-	logger(0) << "Reading `" << inFile << "'...\n";
-
-	if (inFile.find(".kmer") != string::npos) {
-		if (opt::rank <= 0)
-			seqCollection->setColourSpace(false);
-		seqCollection->load(inFile.c_str());
-		return;
-	}
-
-	size_t count = 0, count_good = 0,
-			 count_small = 0, count_nonACGT = 0,
-			 count_reversed = 0;
-	int fastaFlags = opt::maskCov ?  FastaReader::NO_FOLD_CASE :
-			FastaReader::FOLD_CASE;
-	FastaReader reader(inFile.c_str(), fastaFlags);
-	if (endsWith(inFile, ".jf") || endsWith(inFile, ".jfq")) {
-		// Load k-mer with coverage data.
-		count = loadKmer(*seqCollection, reader);
-		count_good = count;
-	} else
-	for (FastaRecord rec; reader >> rec;) {
-		Sequence seq = rec.seq;
-		size_t len = seq.length();
-		if (opt::kmerSize > len) {
-			count_small++;
-			continue;
-		}
-
-		if (opt::rank <= 0
-				&& count == 0 && seqCollection->empty()) {
-			// Detect colour-space reads.
-			bool colourSpace
-				= seq.find_first_of("0123") != string::npos;
-			seqCollection->setColourSpace(colourSpace);
-			if (colourSpace)
-				cout << "Colour-space assembly\n";
-		}
-
-		if (isalnum(seq[0])) {
-			if (opt::colourSpace)
-				assert(isdigit(seq[0]));
-			else
-				assert(isalpha(seq[0]));
-		}
-
-		bool good = seq.find_first_not_of("ACGT0123") == string::npos;
-		bool discarded = true;
-
-		if (opt::ss && rec.id.size() > 2
-				&& rec.id.substr(rec.id.size()-2) == "/1") {
-			seq = reverseComplement(seq);
-			count_reversed++;
-		}
-
-		for (unsigned i = 0; i < len - opt::kmerSize + 1; i++) {
-			Sequence kmer(seq, i, opt::kmerSize);
-			if (good || kmer.find_first_not_of("acgtACGT0123")
-					== string::npos) {
-				if (good || kmer.find_first_of("acgt") == string::npos)
-					seqCollection->add(Kmer(kmer));
-				else {
-					transform(kmer.begin(), kmer.end(), kmer.begin(),
-							::toupper);
-					seqCollection->add(Kmer(kmer), 0);
-				}
-				discarded = false;
-			}
-		}
-		if (discarded)
-			count_nonACGT++;
-		else
-			count_good++;
-
-		if (++count % 100000 == 0) {
-			logger(1) << "Read " << count << " reads. ";
-			seqCollection->printLoad();
-		}
-		seqCollection->pumpNetwork();
-	}
-	assert(reader.eof());
-
-	logger(1) << "Read " << count << " reads. ";
-	seqCollection->printLoad();
-
-	if (count_reversed > 0)
-		cerr << "`" << inFile << "': "
-			"reversed " << count_reversed << " reads\n";
-	if (count_small > 0)
-		cerr << "`" << inFile << "': "
-			"discarded " << count_small << " reads "
-			"shorter than " << opt::kmerSize << " bases\n";
-	if (reader.unchaste() > 0)
-		cerr << "`" << inFile << "': "
-			"discarded " << reader.unchaste() << " unchaste reads\n";
-	if (count_nonACGT > 0)
-		cerr << "`" << inFile << "': "
-			"discarded " << count_nonACGT << " reads "
-			"containing non-ACGT characters\n";
-	if (count_good == 0)
-		cerr << "warning: `" << inFile << "': "
-			"contains no usable sequence\n";
-
-	if (opt::rank <= 0 && count == 0 && seqCollection->empty()) {
-		/* The master process did not load any data, which means that
-		 * it hasn't told the slave processes whether this assembly is
-		 * in colour-space. Rather than fail right now, assume that
-		 * the assembly is not colour space. If the assumption is
-		 * incorrect, the assembly will fail pretty quickly as soon as
-		 * one of the slave processes sees a colour-space read.
-		 */
-		assert(!opt::colourSpace);
-		seqCollection->setColourSpace(false);
-	}
-}
-
-/** Generate the adjacency information for each sequence in the
- * collection. */
-void generateAdjacency(ISequenceCollection* seqCollection)
-{
-	Timer timer("GenerateAdjacency");
-
-	size_t count = 0;
-	size_t numBasesSet = 0;
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
-			iter != seqCollection->end(); ++iter) {
-		if (iter->second.deleted())
-			continue;
-
-		if (++count % 1000000 == 0)
-			logger(1) << "Finding adjacent k-mer: " << count << '\n';
-
-		for (extDirection dir = SENSE; dir <= ANTISENSE; ++dir) {
-			Kmer testSeq(iter->first);
-			uint8_t adjBase = testSeq.shift(dir);
-			for (unsigned i = 0; i < NUM_BASES; i++) {
-				testSeq.setLastBase(dir, i);
-				if (seqCollection->setBaseExtension(
-							testSeq, !dir, adjBase))
-					numBasesSet++;
-			}
-		}
-		seqCollection->pumpNetwork();
-	}
-
-	if (numBasesSet > 0)
-		logger(0) << "Added " << numBasesSet << " edges.\n";
-}
-
-/** Mark the specified vertex and its neighbours.
- * @return the number of marked edges
- */
-static size_t markNeighbours(ISequenceCollection* g,
-		const ISequenceCollection::value_type& u, extDirection sense)
-{
-	vector<Kmer> adj;
-	generateSequencesFromExtension(u.first, sense,
-			u.second.getExtension(sense), adj);
-	for (vector<Kmer>::iterator v = adj.begin(); v != adj.end(); ++v)
-		g->mark(*v, !sense);
-	return adj.size();
-}
-
-/** Mark ambiguous branches and branches from palindromes for removal.
- * @return the number of branches marked
- */
-size_t markAmbiguous(ISequenceCollection* g)
-{
-	Timer timer(__func__);
-	size_t progress = 0;
-	size_t countv = 0, counte = 0;
-	for (ISequenceCollection::iterator it = g->begin();
-			it != g->end(); ++it) {
-		if (it->second.deleted())
-			continue;
-
-		if (++progress % 1000000 == 0)
-			logger(1) << "Splitting: " << progress << '\n';
-
-		if (!opt::ss && it->first.isPalindrome()) {
-			countv += 2;
-			g->mark(it->first);
-			counte += markNeighbours(g, *it, SENSE);
-		} else {
-			for (extDirection sense = SENSE;
-					sense <= ANTISENSE; ++sense) {
-				if (it->second.getExtension(sense).isAmbiguous()
-						|| (!opt::ss && it->first.isPalindrome(sense))) {
-					countv++;
-					g->mark(it->first, sense);
-					counte += markNeighbours(g, *it, sense);
-				}
-			}
-		}
-
-		g->pumpNetwork();
-	}
-	logger(0) << "Marked " << counte << " edges of " << countv
-		<< " ambiguous vertices." << endl;
-	return countv;
-}
-
-/** Remove the edges of marked and deleted vertices.
- * @return the number of branches removed
- */
-size_t splitAmbiguous(ISequenceCollection* pSC)
-{
-	Timer timer(__func__);
-	size_t count = 0;
-	for (ISequenceCollection::iterator it = pSC->begin();
-			it != pSC->end(); ++it) {
-		if (!it->second.deleted())
-			continue;
-		for (extDirection sense = SENSE;
-				sense <= ANTISENSE; ++sense) {
-			if (it->second.marked(sense)) {
-				removeExtensionsToSequence(pSC, *it, sense);
-				count++;
-			}
-		}
-		pSC->pumpNetwork();
-	}
-	logger(0) << "Split " << count << " ambigiuous branches.\n";
-	return count;
-}
-
-/** Open the bubble file. */
-void openBubbleFile(ofstream& out)
-{
-	if (opt::snpPath.empty())
-		return;
-	string path;
-	if (opt::rank < 0) {
-		path = opt::snpPath;
-	} else {
-		ostringstream s;
-		s << "snp-" << opt::rank << ".fa";
-		path = s.str();
-	}
-	out.open(path.c_str());
-	assert_good(out, path);
-}
-
-/** Pop bubbles. */
-size_t popBubbles(SequenceCollectionHash* seqCollection, ostream& out)
-{
-	Timer timer("PopBubbles");
-	size_t numPopped = 0;
-
-	// Set the cutoffs
-	const unsigned maxNumBranches = 3;
-	const unsigned maxLength = opt::bubbleLen - opt::kmerSize + 1;
-
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
-			iter != seqCollection->end(); ++iter) {
-		if (iter->second.deleted())
-			continue;
-
-		ExtensionRecord extRec = iter->second.extension();
-		for (extDirection dir = SENSE; dir <= ANTISENSE; ++dir) {
-			if (extRec.dir[dir].isAmbiguous()) {
-				// Found a potential bubble, examine each branch
-				bool stop = false;
-
-				// Create the branch group
-				BranchGroup branchGroup(dir, maxNumBranches,
-						iter->first);
-				initiateBranchGroup(branchGroup, iter->first,
-						extRec.dir[dir]);
-
-				// Iterate over the branches
-				while(!stop)
-				{
-					size_t numBranches = branchGroup.size();
-					for (unsigned j = 0; j < numBranches; ++j) {
-						// Get the extensions of this branch
-						ExtensionRecord extRec;
-						int multiplicity = -1;
-
-						const Kmer& lastKmer
-							= branchGroup[j].back().first;
-						bool success = seqCollection->getSeqData(
-								lastKmer, extRec, multiplicity);
-						assert(success);
-						(void)success;
-						processBranchGroupExtension(branchGroup, j,
-								lastKmer, extRec, multiplicity,
-								maxLength);
-					}
-
-					// At this point all branches should have the same
-					// length or one will be a noext.
-					branchGroup.updateStatus(maxLength);
-					BranchGroupStatus status
-						= branchGroup.getStatus();
-					if (status == BGS_TOOLONG
-							|| status == BGS_TOOMANYBRANCHES
-							|| status == BGS_NOEXT) {
-						stop = true;
-					}
-					else if(status == BGS_JOINED)
-					{
-						static unsigned snpID;
-						writeBubble(out, branchGroup, ++snpID);
-						assert(branchGroup.isAmbiguous(
-									*seqCollection));
-						collapseJoinedBranches(seqCollection,
-								branchGroup);
-						assert(!branchGroup.isAmbiguous(
-									*seqCollection));
-						numPopped++;
-						stop = true;
-					} else
-						assert(status == BGS_ACTIVE);
-				}
-			}
-		}
-		seqCollection->pumpNetwork();
-	}
-
-	if (numPopped > 0)
-		cout << "Removed " << numPopped << " bubbles.\n";
-	return numPopped;
-}
-
-// Populate a branch group with the inital branches from a sequence
-void initiateBranchGroup(BranchGroup& group, const Kmer& seq,
-		const SeqExt& extension)
-{
-	vector<Kmer> extSeqs;
-	generateSequencesFromExtension(seq, group.getDirection(),
-			extension, extSeqs);
-	assert(extSeqs.size() > 1);
-	for (vector<Kmer>::iterator seqIter = extSeqs.begin();
-			seqIter != extSeqs.end(); ++seqIter)
-		group.addBranch(BranchRecord(group.getDirection()), *seqIter);
-}
-
-/** Process an a branch group extension. */
-bool processBranchGroupExtension(BranchGroup& group,
-		size_t branchIndex, const Kmer& seq,
-		ExtensionRecord ext, int multiplicity,
-		unsigned maxLength)
-{
-	BranchRecord& branch = group[branchIndex];
-	branch.setData(make_pair(seq, KmerData(multiplicity, ext)));
-
-	extDirection dir = group.getDirection();
-	if (ext.dir[!dir].isAmbiguous()) {
-		// Check that this fork is due to branches of our bubble
-		// merging back together. If not, stop this bubble.
-		if (branch.size() < 2) {
-			group.setNoExtension();
-			return false;
-		}
-
-		vector<Kmer> extKmer;
-		generateSequencesFromExtension(seq, !dir,
-				ext.dir[!dir], extKmer);
-		assert(extKmer.size() > 1);
-		for (vector<Kmer>::iterator it = extKmer.begin();
-				it != extKmer.end(); ++it) {
-			assert(branch.size() > 1);
-			if (!group.exists(branch.size() - 2, *it)) {
-				group.setNoExtension();
-				return false;
-			}
-		}
-		// Ignore the ambiguity.
-		ext.dir[!dir].clear();
-	}
-
-	if (ext.dir[dir].isAmbiguous()) {
-		// Create a new branch to follow the fork.
-		vector<Kmer> extKmer;
-		generateSequencesFromExtension(seq, dir,
-				ext.dir[dir], extKmer);
-		assert(extKmer.size() > 1);
-		BranchRecord original = branch;
-		vector<Kmer>::iterator it = extKmer.begin();
-		branch.push_back(make_pair(*it++, KmerData()));
-		for (; it != extKmer.end(); ++it)
-			group.addBranch(original, *it);
-		return group.isExtendable();
-	}
-
-	Kmer nextKmer = seq;
-	if (processLinearExtensionForBranch(branch,
-			nextKmer, ext, multiplicity,
-			maxLength, false))
-		branch.push_back(make_pair(nextKmer, KmerData()));
-	else
-		group.setNoExtension();
-	return group.isExtendable();
-}
-
-/** Write a bubble to the specified file. */
-void writeBubble(ostream& out, const BranchGroup& group, unsigned id)
-{
-	if (opt::snpPath.empty())
-		return;
-
-	char allele = 'A';
-	for (BranchGroup::const_iterator it = group.begin();
-			it != group.end(); ++it) {
-		const BranchRecord& currBranch = *it;
-		Sequence contig(currBranch);
-		out << '>' << id << allele++ << ' '
-			<< contig.length() << ' '
-			<< currBranch.calculateBranchMultiplicity() << '\n'
-			<< contig.c_str() << '\n';
-	}
-	assert(out.good());
-}
-
-/** Collapse a bubble to a single path. */
-void collapseJoinedBranches(ISequenceCollection* collection,
-		BranchGroup& group)
-{
-	const BranchRecord& best = group[0];
-	logger(5) << "Popping " << best.size() << ' '
-		<< best.front().first << '\n';
-
-	// Add the k-mer from the dead branches.
-	map<Kmer, KmerData> doomed;
-	for (BranchGroup::const_iterator branchIt = group.begin() + 1;
-			branchIt != group.end(); ++branchIt) {
-		const BranchRecord& branch = *branchIt;
-		for (BranchRecord::const_iterator it = branch.begin();
-				it != branch.end(); ++it)
-			doomed.insert(*it);
-	}
-
-	// Remove the k-mer that are in the good branch.
-	for (BranchRecord::const_iterator it = best.begin();
-			it != best.end(); ++it)
-		doomed.erase(it->first);
-
-	// Remove the dead k-mer from the assembly.
-	for (map<Kmer, KmerData>::const_iterator it = doomed.begin();
-			it != doomed.end(); ++it)
-		removeSequenceAndExtensions(collection, *it);
-}
-
-/**
- * Remove a k-mer and update the extension records of the k-mer that
- * extend to it.
- */
-void removeSequenceAndExtensions(ISequenceCollection* seqCollection,
-		const ISequenceCollection::value_type& seq)
-{
-	// This removes the reverse complement as well
-	seqCollection->remove(seq.first);
-	removeExtensionsToSequence(seqCollection, seq, SENSE);
-	removeExtensionsToSequence(seqCollection, seq, ANTISENSE);
-}
-
-/** Remove all the extensions to this sequence. */
-void removeExtensionsToSequence(ISequenceCollection* seqCollection,
-		const ISequenceCollection::value_type& seq, extDirection dir)
-{
-	SeqExt extension(seq.second.getExtension(dir));
-	Kmer testSeq(seq.first);
-	uint8_t extBase = testSeq.shift(dir);
-	for (unsigned i = 0; i < NUM_BASES; i++) {
-		if (extension.checkBase(i)) {
-			testSeq.setLastBase(dir, i);
-			seqCollection->removeExtension(testSeq, !dir, extBase);
-		}
-	}
-}
-
-/** The number of k-mer that have been eroded. */
-static size_t g_numEroded;
-
-/** Return the number of k-mer that have been eroded. */
-size_t getNumEroded()
-{
-	size_t numEroded = g_numEroded;
-	g_numEroded = 0;
-	logger(0) << "Eroded " << numEroded << " tips.\n";
-	return numEroded;
-}
-
-/** Consider the specified k-mer for erosion.
- * @return the number of k-mer eroded, zero or one
- */
-size_t erode(ISequenceCollection* c,
-		const ISequenceCollection::value_type& seq)
-{
-	if (seq.second.deleted())
-		return 0;
-	extDirection dir;
-	SeqContiguity contiguity = checkSeqContiguity(seq, dir);
-	if (contiguity == SC_CONTIGUOUS)
-		return 0;
-
-	const KmerData& data = seq.second;
-	if (data.getMultiplicity() < opt::erode
-			|| data.getMultiplicity(SENSE) < opt::erodeStrand
-			|| data.getMultiplicity(ANTISENSE) < opt::erodeStrand) {
-		removeSequenceAndExtensions(c, seq);
-		g_numEroded++;
-		return 1;
-	} else
-		return 0;
-}
-
-/** The given sequence has changed. */
-static void erosionObserver(ISequenceCollection* c,
-		const ISequenceCollection::value_type& seq)
-{
-	erode(c, seq);
-}
-
-//
-// Erode data off the ends of the graph, one by one
-//
-size_t erodeEnds(ISequenceCollection* seqCollection)
-{
-	Timer erodeEndsTimer("Erode");
-	assert(g_numEroded == 0);
-	seqCollection->attach(erosionObserver);
-
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
-			iter != seqCollection->end(); ++iter) {
-		erode(seqCollection, *iter);
-		seqCollection->pumpNetwork();
-	}
-
-	seqCollection->detach(erosionObserver);
-	return getNumEroded();
-}
-
-static size_t trimSequences(SequenceCollectionHash* seqCollection,
-		unsigned maxBranchCull);
-
-/** Trimming driver function */
-void performTrim(SequenceCollectionHash* seqCollection)
-{
-	if (opt::trimLen == 0)
-		return;
-	unsigned rounds = 0;
-	size_t total = 0;
-	for (unsigned trim = 1; trim < opt::trimLen; trim *= 2) {
-		rounds++;
-		total += trimSequences(seqCollection, trim);
-	}
-	size_t count;
-	while ((count = trimSequences(seqCollection, opt::trimLen)) > 0) {
-		rounds++;
-		total += count;
-	}
-	cout << "Pruned " << total << " tips in "
-		<< rounds << " rounds.\n";
-}
-
-/** Return the adjacency of this sequence.
- * @param considerMarks when true, treat a marked vertex as having
- * no edges
- */
-SeqContiguity checkSeqContiguity(
-		const ISequenceCollection::value_type& seq,
-		extDirection& outDir, bool considerMarks)
-{
-	assert(!seq.second.deleted());
-	bool child = seq.second.hasExtension(SENSE)
-		&& !(considerMarks && seq.second.marked(SENSE));
-	bool parent = seq.second.hasExtension(ANTISENSE)
-		&& !(considerMarks && seq.second.marked(ANTISENSE));
-	if(!child && !parent)
-	{
-		//this sequence is completely isolated
-		return SC_ISLAND;
-	}
-	else if(!child)
-	{
-		outDir = ANTISENSE;
-		return SC_ENDPOINT;
-	}
-	else if(!parent)
-	{
-		outDir = SENSE;
-		return SC_ENDPOINT;
-	}
-	else
-	{
-		// sequence is contiguous
-		return SC_CONTIGUOUS;
-	}
-}
-
-/** Prune tips shorter than maxBranchCull. */
-static size_t trimSequences(SequenceCollectionHash* seqCollection,
-		unsigned maxBranchCull)
-{
-	Timer timer("TrimSequences");
-	cout << "Pruning tips shorter than "
-		<< maxBranchCull << " bp...\n";
-	size_t numBranchesRemoved = 0;
-
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
-			iter != seqCollection->end(); ++iter) {
-		if (iter->second.deleted())
-			continue;
-
-		extDirection dir;
-		// dir will be set to the trimming direction if the sequence
-		// can be trimmed.
-		SeqContiguity status = checkSeqContiguity(*iter, dir);
-
-		if (status == SC_CONTIGUOUS)
-			continue;
-		else if(status == SC_ISLAND)
-		{
-			// remove this sequence, it has no extensions
-			seqCollection->mark(iter->first);
-			numBranchesRemoved++;
-			continue;
-		}
-
-		BranchRecord currBranch(dir);
-		Kmer currSeq = iter->first;
-		while(currBranch.isActive())
-		{
-			ExtensionRecord extRec;
-			int multiplicity = -1;
-			bool success = seqCollection->getSeqData(
-					currSeq, extRec, multiplicity);
-			assert(success);
-			(void)success;
-			processLinearExtensionForBranch(currBranch,
-					currSeq, extRec, multiplicity, maxBranchCull);
-		}
-
-		// The branch has ended check it for removal, returns true if
-		// it was removed.
-		if(processTerminatedBranchTrim(seqCollection, currBranch))
-		{
-			numBranchesRemoved++;
-		}
-		seqCollection->pumpNetwork();
-	}
-
-	size_t numSweeped = removeMarked(seqCollection);
-
-	if (numBranchesRemoved > 0)
-		logger(0) << "Pruned " << numSweeped << " k-mer in "
-			<< numBranchesRemoved << " tips.\n";
-	return numBranchesRemoved;
-}
-
-/** Extend this branch. */
-bool extendBranch(BranchRecord& branch, Kmer& kmer, SeqExt ext)
-{
-	if (!ext.hasExtension()) {
-		branch.terminate(BS_NOEXT);
-		return false;
-	} else if (ext.isAmbiguous()) {
-		branch.terminate(BS_AMBI_SAME);
-		return false;
-	} else {
-		vector<Kmer> adj;
-		generateSequencesFromExtension(kmer, branch.getDirection(),
-				ext, adj);
-		assert(adj.size() == 1);
-		kmer = adj.front();
-		return true;
-	}
-}
-
-/**
- * Process the extension for this branch for the trimming algorithm
- * CurrSeq is the current sequence being inspected (the next member to
- * be added to the branch). The extension record is the extensions of
- * that sequence and multiplicity is the number of times that kmer
- * appears in the data set. After processing currSeq is unchanged if
- * the branch is no longer active or else it is the generated
- * extension. If the parameter addKmer is true, add the k-mer to the
- * branch.
- */
-bool processLinearExtensionForBranch(BranchRecord& branch,
-		Kmer& currSeq, ExtensionRecord extensions, int multiplicity,
-		unsigned maxLength, bool addKmer)
-{
-	/** Stop contig assembly at palindromes. */
-	const bool stopAtPalindromes = !opt::ss && maxLength == UINT_MAX;
-
-	extDirection dir = branch.getDirection();
-	if (branch.isTooLong(maxLength)) {
-		// Too long.
-		branch.terminate(BS_TOO_LONG);
-		return false;
-	} else if (extensions.dir[!dir].isAmbiguous()) {
-		// Ambiguous.
-		branch.terminate(BS_AMBI_OPP);
-		return false;
-	} else if (stopAtPalindromes && currSeq.isPalindrome()) {
-		// Palindrome.
-		branch.terminate(BS_AMBI_SAME);
-		return false;
-	}
-
-	if (addKmer)
-		branch.push_back(make_pair(currSeq,
-					KmerData(multiplicity, extensions)));
-
-	if (branch.isTooLong(maxLength)) {
-		// Too long.
-		branch.terminate(BS_TOO_LONG);
-		return false;
-	} else if (stopAtPalindromes && currSeq.isPalindrome(dir)) {
-		// Palindrome.
-		branch.terminate(BS_AMBI_SAME);
-		return false;
-	}
-
-	return extendBranch(branch, currSeq, extensions.dir[dir]);
-}
-
-/** Trim the specified branch if it meets trimming criteria.
- * @return true if the specified branch was trimmed
- */
-bool processTerminatedBranchTrim(ISequenceCollection* seqCollection,
-		BranchRecord& branch)
-{
-	assert(!branch.isActive());
-	assert(!branch.empty());
-	if (branch.getState() == BS_NOEXT
-			|| branch.getState() == BS_AMBI_OPP) {
-		logger(5) << "Pruning " << branch.size() << ' '
-			<< branch.front().first << '\n';
-		for (BranchRecord::iterator it = branch.begin();
-				it != branch.end(); ++it)
-			seqCollection->mark(it->first);
-		return true;
-	} else
-		return false;
-}
-
-/** Remove all marked k-mer.
- * @return the number of removed k-mer
- */
-size_t removeMarked(ISequenceCollection* pSC)
-{
-	Timer timer(__func__);
-	size_t count = 0;
-	for (ISequenceCollection::iterator it = pSC->begin();
-			it != pSC->end(); ++it) {
-		if (it->second.deleted())
-			continue;
-		if (it->second.marked()) {
-			removeSequenceAndExtensions(pSC, *it);
-			count++;
-		}
-		pSC->pumpNetwork();
-	}
-	if (count > 0)
-		logger(1) << "Removed " << count << " marked k-mer.\n";
-	return count;
-}
-
-/** Assemble a contig.
- * @return the number of k-mer below the coverage threshold
- */
-size_t assembleContig(
-		ISequenceCollection* seqCollection, FastaWriter* writer,
-		BranchRecord& branch, unsigned id)
-{
-	assert(!branch.isActive());
-	assert(branch.getState() == BS_NOEXT
-			|| branch.getState() == BS_AMBI_SAME
-			|| branch.getState() == BS_AMBI_OPP);
-
-	// Assemble the contig.
-	Sequence contig(branch);
-
-	size_t kmerCount = branch.calculateBranchMultiplicity();
-	if (writer != NULL)
-		writer->WriteSequence(contig, id, kmerCount);
-
-	// Remove low-coverage contigs.
-	float coverage = (float)kmerCount / branch.size();
-	if (opt::coverage > 0 && coverage < opt::coverage) {
-		for (BranchRecord::iterator it = branch.begin();
-				it != branch.end(); ++it)
-			seqCollection->remove(it->first);
-		return branch.size();
-	}
-	return 0;
-}
-
-/** Assemble contigs.
- * @return the number of contigs assembled
- */
-size_t assemble(SequenceCollectionHash* seqCollection,
-		FastaWriter* fileWriter)
-{
-	Timer timer("Assemble");
-
-	size_t kmerCount = 0;
-	unsigned contigID = 0;
-	size_t assembledKmer = 0;
-	size_t lowCoverageKmer = 0;
-	size_t lowCoverageContigs = 0;
-
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
-			iter != seqCollection->end(); ++iter) {
-		if (iter->second.deleted())
-			continue;
-		kmerCount++;
-
-		extDirection dir;
-		SeqContiguity status = checkSeqContiguity(*iter, dir, true);
-		if (status == SC_CONTIGUOUS)
-			continue;
-		else if(status == SC_ISLAND)
-		{
-			BranchRecord currBranch(SENSE);
-			currBranch.push_back(*iter);
-			currBranch.terminate(BS_NOEXT);
-			size_t removed = assembleContig(seqCollection,
-					fileWriter, currBranch, contigID++);
-			assembledKmer += currBranch.size();
-			if (removed > 0) {
-				lowCoverageContigs++;
-				lowCoverageKmer += removed;
-			}
-			continue;
-		}
-		assert(status == SC_ENDPOINT);
-
-		BranchRecord currBranch(dir);
-		currBranch.push_back(*iter);
-		Kmer currSeq = iter->first;
-		extendBranch(currBranch, currSeq,
-				iter->second.getExtension(dir));
-		assert(currBranch.isActive());
-		while(currBranch.isActive())
-		{
-			ExtensionRecord extRec;
-			int multiplicity = -1;
-			bool success = seqCollection->getSeqData(
-					currSeq, extRec, multiplicity);
-			assert(success);
-			(void)success;
-			processLinearExtensionForBranch(currBranch,
-					currSeq, extRec, multiplicity, UINT_MAX);
-		}
-
-		if ((opt::ss && currBranch.getDirection() == SENSE)
-				|| (!opt::ss && currBranch.isCanonical())) {
-			size_t removed = assembleContig(seqCollection,
-					fileWriter, currBranch, contigID++);
-			assembledKmer += currBranch.size();
-			if (removed > 0) {
-				lowCoverageContigs++;
-				lowCoverageKmer += removed;
-			}
-		}
-
-		seqCollection->pumpNetwork();
-	}
-
-	if (opt::coverage > 0) {
-		cout << "Found " << assembledKmer << " k-mer in " << contigID
-			<< " contigs before removing low-coverage contigs.\n"
-			"Removed " << lowCoverageKmer << " k-mer in "
-				<< lowCoverageContigs << " low-coverage contigs.\n";
-	} else {
-		assert(assembledKmer <= kmerCount);
-		size_t circularKmer = kmerCount - assembledKmer;
-		if (circularKmer > 0)
-			cout << "Left " << circularKmer
-				<< " unassembled k-mer in circular contigs.\n";
-		cout << "Assembled " << assembledKmer << " k-mer in "
-			<< contigID << " contigs.\n";
-	}
-	return contigID;
-}
-
-/** Return the k-mer coverage histogram. */
-Histogram coverageHistogram(const ISequenceCollection& c)
-{
-	Histogram h;
-	for (ISequenceCollection::const_iterator it = c.begin();
-			it != c.end(); ++it) {
-		if (it->second.deleted())
-			continue;
-		h.insert(it->second.getMultiplicity());
-	}
-	return h;
-}
-
-/** Calculate a k-mer coverage threshold from the given k-mer coverage
- * histogram. */
-static float calculateCoverageThreshold(const Histogram& h)
-{
-	float cov = h.firstLocalMinimum();
-	if (opt::rank <= 0) {
-		if (cov == 0)
-			cout << "Unable to determine minimum k-mer coverage\n";
-		else
-			cout << "Minimum k-mer coverage is " << cov << endl;
-	}
-
-	for (unsigned iteration = 0; iteration < 100; iteration++) {
-		Histogram trimmed = h.trimLow((unsigned)roundf(cov));
-		if (opt::rank <= 0)
-			logger(1) << "Coverage: " << cov << "\t"
-				"Reconstruction: " << trimmed.size() << endl;
-
-		unsigned median = trimmed.median();
-		float cov1 = sqrt(median);
-		if (cov1 == cov) {
-			// The coverage threshold has converged.
-			if (opt::rank <= 0)
-				cout << "Using a coverage threshold of "
-					<< (unsigned)roundf(cov) << "...\n"
-					"The median k-mer coverage is " << median << "\n"
-					"The reconstruction is " << trimmed.size()
-					<< endl;
-			return cov;
-		}
-		cov = cov1;
-	}
-	if (opt::rank <= 0)
-		cerr << "warning: coverage threshold did not converge"
-			<< endl;
-	return 0;
-}
-
-/** Set the coverage-related parameters e and c from the given k-mer
- * coverage histogram. */
-void setCoverageParameters(const Histogram& h)
-{
-	if (!opt::coverageHistPath.empty() && opt::rank <= 0) {
-		ofstream histFile(opt::coverageHistPath.c_str());
-		assert_good(histFile, opt::coverageHistPath);
-		histFile << h;
-		assert(histFile.good());
-	}
-
-	float minCov = calculateCoverageThreshold(h);
-	if (opt::rank <= 0) {
-		if (minCov == 0)
-			cout << "Unable to determine the "
-				"k-mer coverage threshold" << endl;
-		else
-			cout << "The k-mer coverage threshold is " << minCov
-				<< endl;
-	}
-	if (minCov < 2)
-		minCov = 2;
-
-	if ((int)opt::erode < 0) {
-		opt::erode = (unsigned)roundf(minCov);
-		if (opt::rank <= 0)
-			cout << "Setting parameter e (erode) to "
-				<< opt::erode << endl;
-	}
-	if ((int)opt::erodeStrand < 0) {
-		opt::erodeStrand = minCov <= 2 ? 0 : 1;
-		if (opt::rank <= 0)
-			cout << "Setting parameter E (erodeStrand) to "
-				<< opt::erodeStrand << endl;
-	}
-	if (opt::coverage < 0) {
-		opt::coverage = minCov;
-		if (opt::rank <= 0)
-			cout << "Setting parameter c (coverage) to "
-				<< opt::coverage << endl;
-	}
-}
-
-};
diff --git a/Assembly/AssemblyAlgorithms.h b/Assembly/AssemblyAlgorithms.h
index d88b6e3..e96e3ff 100644
--- a/Assembly/AssemblyAlgorithms.h
+++ b/Assembly/AssemblyAlgorithms.h
@@ -1,12 +1,13 @@
-#ifndef ASSEMBLYALGORITHMS_H
-#define ASSEMBLYALGORITHMS_H 1
-
-#include "BranchGroup.h"
-#include "BranchRecord.h"
-#include "FastaWriter.h"
-#include "SequenceCollection.h"
-#include <ostream>
+#ifndef ASSEMBLY_ASSEMBLYALGORITHMS_H
+#define ASSEMBLY_ASSEMBLYALGORITHMS_H 1
+
+#include "Assembly/BranchGroup.h"
+#include "Assembly/Options.h"
+#include "Common/Log.h"
+#include "Common/Timer.h"
 #include <vector>
+#include <string>
+#include "Common/InsOrderedMap.h"
 
 class Histogram;
 
@@ -19,88 +20,127 @@ enum SeqContiguity
 };
 
 /** De Bruijn graph assembly algorithms. */
-namespace AssemblyAlgorithms
-{
-
-// Read a sequence file and load them into the collection
-void loadSequences(ISequenceCollection* seqCollection,
-		std::string inFile);
+namespace AssemblyAlgorithms {
+
+extern std::vector<size_t> tempCounter;
+extern InsOrderedMap<std::string,int> tempStatMap;
+extern void addToDb(const std::string&, const int&);
+
+static inline
+bool extendBranch(BranchRecord& branch,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor& kmer,
+		SequenceCollectionHash::SymbolSet ext);
+
+static inline bool
+processLinearExtensionForBranch(BranchRecord& branch,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor& currSeq,
+		SequenceCollectionHash::SymbolSetPair extensions,
+		int multiplicity,
+		unsigned maxLength, bool addKmer = true);
 
-/** Generate the adjacency information for all the sequences in the
- * collection. This is required before any other algorithm can run.
+static inline void
+initiateBranchGroup(BranchGroup& group,
+		const graph_traits<SequenceCollectionHash>::vertex_descriptor& seq,
+		const SequenceCollectionHash::SymbolSet& extension);
+
+template <typename Graph>
+void removeSequenceAndExtensions(Graph* seqCollection,
+		const typename Graph::value_type& seq);
+
+/** Return the kmer which are adjacent to this kmer. */
+template <typename V, typename SymbolSet>
+void generateSequencesFromExtension(
+		const V& currSeq,
+		extDirection dir,
+		SymbolSet extension,
+		std::vector<V>& outseqs)
+{
+	typedef typename SymbolSet::Symbol Symbol;
+
+	std::vector<V> extensions;
+	V extSeq(currSeq);
+	extSeq.shift(dir);
+
+	// Check for the existance of the 4 possible extensions
+	for (unsigned i = 0; i < SymbolSet::NUM; ++i) {
+		// Does this sequence have an extension?
+		Symbol x(i);
+		if (extension.checkBase(x)) {
+			extSeq.setLastBase(dir, x);
+			outseqs.push_back(extSeq);
+		}
+	}
+}
+
+/** Return the adjacency of this sequence.
+ * @param considerMarks when true, treat a marked vertex as having
+ * no edges
  */
-void generateAdjacency(ISequenceCollection* seqCollection);
-
-Histogram coverageHistogram(const ISequenceCollection& c);
-void setCoverageParameters(const Histogram& h);
-
-/* Erosion. Remove k-mer from the ends of blunt contigs. */
-size_t erodeEnds(ISequenceCollection* seqCollection);
-size_t erode(ISequenceCollection* c,
-		const ISequenceCollection::value_type& seq);
-size_t getNumEroded();
-
-size_t removeMarked(ISequenceCollection* pSC);
-
-// Check whether a sequence can be trimmed
+static inline
 SeqContiguity checkSeqContiguity(
-		const ISequenceCollection::value_type& seq,
-		extDirection& outDir, bool considerMarks = false);
-
-// process a terminated branch for trimming
-bool processTerminatedBranchTrim(
-		ISequenceCollection* seqCollection, BranchRecord& branch);
-
-bool extendBranch(BranchRecord& branch, Kmer& kmer, SeqExt ext);
-
-// Process the extensions of the current sequence for trimming
-bool processLinearExtensionForBranch(BranchRecord& branch,
-		Kmer& currSeq, ExtensionRecord extensions, int multiplicity,
-		unsigned maxLength, bool addKmer = true);
-
-/** Populate the branch group with the initial extensions to this
- * sequence. */
-void initiateBranchGroup(BranchGroup& group, const Kmer& seq,
-		const SeqExt& extension);
-
-// process an a branch group extension
-bool processBranchGroupExtension(BranchGroup& group,
-		size_t branchIndex, const Kmer& seq,
-		ExtensionRecord extensions, int multiplicity,
-		unsigned maxLength);
-
-void openBubbleFile(std::ofstream& out);
-void writeBubble(std::ostream& out, const BranchGroup& group,
-		unsigned id);
-void collapseJoinedBranches(
-		ISequenceCollection* seqCollection, BranchGroup& group);
-
-/* Split the remaining ambiguous nodes to allow for a non-redundant
- * assembly. Remove extensions to/from ambiguous sequences to avoid
- * generating redundant/wrong contigs.
+		const SequenceCollectionHash::value_type& seq,
+		extDirection& outDir, bool considerMarks = false)
+{
+	assert(!seq.second.deleted());
+	bool child = seq.second.hasExtension(SENSE)
+		&& !(considerMarks && seq.second.marked(SENSE));
+	bool parent = seq.second.hasExtension(ANTISENSE)
+		&& !(considerMarks && seq.second.marked(ANTISENSE));
+	if(!child && !parent)
+	{
+		//this sequence is completely isolated
+		return SC_ISLAND;
+	}
+	else if(!child)
+	{
+		outDir = ANTISENSE;
+		return SC_ENDPOINT;
+	}
+	else if(!parent)
+	{
+		outDir = SENSE;
+		return SC_ENDPOINT;
+	}
+	else
+	{
+		// sequence is contiguous
+		return SC_CONTIGUOUS;
+	}
+}
+
+/** Remove all marked k-mer.
+ * @return the number of removed k-mer
  */
-size_t markAmbiguous(ISequenceCollection* seqCollection);
-size_t splitAmbiguous(ISequenceCollection* seqCollection);
-
-size_t assembleContig(ISequenceCollection* seqCollection,
-		FastaWriter* writer, BranchRecord& branch, unsigned id);
-
-void removeSequenceAndExtensions(ISequenceCollection* seqCollection,
-		const ISequenceCollection::value_type& seq);
-void removeExtensionsToSequence(ISequenceCollection* seqCollection,
-		const ISequenceCollection::value_type& seq, extDirection dir);
-
-void generateSequencesFromExtension(const Kmer& currSeq,
-		extDirection dir, SeqExt extension,
-		std::vector<Kmer>& outseqs);
-
-/* Non-distributed graph algorithms. */
-
-void performTrim(SequenceCollectionHash* seqCollection);
-size_t popBubbles(SequenceCollectionHash* pSC, std::ostream& out);
-size_t assemble(SequenceCollectionHash* seqCollection,
-		FastaWriter* fileWriter = NULL);
-
-};
+template <typename Graph>
+size_t removeMarked(Graph* pSC)
+{
+	typedef typename Graph::iterator iterator;
+
+	Timer timer(__func__);
+	size_t count = 0;
+	for (iterator it = pSC->begin(); it != pSC->end(); ++it) {
+		if (it->second.deleted())
+			continue;
+		if (it->second.marked()) {
+			removeSequenceAndExtensions(pSC, *it);
+			count++;
+		}
+		pSC->pumpNetwork();
+	}
+	if (count > 0)
+		logger(1) << "Removed " << count << " marked k-mer.\n";
+	return count;
+}
+
+} // namespace AssemblyAlgorithms
+
+#include "AdjacencyAlgorithm.h"
+#include "AssembleAlgorithm.h"
+#include "BubbleAlgorithm.h"
+#include "CoverageAlgorithm.h"
+#include "ErodeAlgorithm.h"
+#include "LoadAlgorithm.h"
+#include "SplitAlgorithm.h"
+#include "TrimAlgorithm.h"
 
 #endif
diff --git a/Assembly/BranchGroup.cpp b/Assembly/BranchGroup.cpp
deleted file mode 100644
index 12cdb1c..0000000
--- a/Assembly/BranchGroup.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "BranchGroup.h"
-#include "Algorithms.h"
-#include <algorithm>
-#include <functional>
-
-using namespace std;
-
-// Check the stop conditions for the bubble growth
-BranchGroupStatus BranchGroup::updateStatus(unsigned maxLength)
-{
-	assert(m_branches.size() <= m_maxNumBranches);
-
-	if (m_status != BGS_ACTIVE)
-		return m_status;
-
-	// Check if the no extension flag is set
-	if(m_noExt)
-	{
-		m_status = BGS_NOEXT;
-		return m_status;
-	}
-
-	// Check if any branches are too long or any sequence has a loop
-	for (BranchGroupData::const_iterator iter = m_branches.begin();
-			iter != m_branches.end(); ++iter) {
-		if (iter->isTooLong(maxLength)) {
-			m_status = BGS_TOOLONG;
-			return m_status;
-		}
-	}
-
-	BranchGroupData::const_iterator it = m_branches.begin();
-	const Kmer& lastSeq = it->back().first;
-	while (++it != m_branches.end())
-		if (it->back().first != lastSeq)
-			return m_status = BGS_ACTIVE;
-
-	// All the branches of the bubble have joined.
-	// Remove the last base, which is identical for every branch.
-	for_each(m_branches.begin(), m_branches.end(),
-			mem_fun_ref(&BranchRecord::pop_back));
-
-	// Sort the branches by coverage.
-	sort_by_transform(m_branches.begin(), m_branches.end(),
-			mem_fun_ref(&BranchRecord::calculateBranchMultiplicity));
-	reverse(m_branches.begin(), m_branches.end());
-
-	return m_status = BGS_JOINED;
-}
-
-/** Return whether any branches of this group are active. */
-bool BranchGroup::isActive() const
-{
-	for (BranchGroupData::const_iterator it = m_branches.begin();
-			it != m_branches.end(); ++it)
-		if (it->isActive())
-			return true;
-	return false;
-}
-
-/** Return whether this branch is extendable. */
-bool BranchGroup::isExtendable()
-{
-	if (m_noExt)
-		return false;
-
-	// A group is extendable when all the branches are the same
-	// length. All the branches are lockstepped for growth.
-	BranchGroupData::iterator it = m_branches.begin();
-	unsigned length = it++->size();
-	for (; it != m_branches.end(); ++it)
-		if (it->size() != length)
-			return false;
-	return true;
-}
-
-/** Return whether this branch is ambiguous at its origin. Also
- * returns false if the origin of the branch has since been deleted.
- */
-bool BranchGroup::isAmbiguous(const SequenceCollectionHash& g) const
-{
-	// Get fresh data from the collection to check that this bubble
-	// does in fact still exist.
-	const KmerData& data = g.getSeqAndData(m_origin).second;
-	return data.deleted() ? false : data.isAmbiguous(m_dir);
-}
diff --git a/Assembly/BranchGroup.h b/Assembly/BranchGroup.h
index 6288f8c..c333ebf 100644
--- a/Assembly/BranchGroup.h
+++ b/Assembly/BranchGroup.h
@@ -1,8 +1,7 @@
 #ifndef BRANCHGROUP_H
 #define BRANCHGROUP_H 1
 
-#include "BranchRecord.h"
-#include "SequenceCollection.h"
+#include "Common/Algorithms.h"
 #include <algorithm> // for swap
 #include <map>
 #include <utility>
@@ -30,7 +29,7 @@ class BranchGroup
 			{ }
 
 		BranchGroup(extDirection dir, size_t maxNumBranches,
-				const Kmer &origin)
+				const BranchRecord::V &origin)
 			: m_dir(dir), m_origin(origin),
 			m_maxNumBranches(maxNumBranches), m_noExt(false),
 			m_status(BGS_ACTIVE)
@@ -39,7 +38,7 @@ class BranchGroup
 		}
 
 		BranchGroup(extDirection dir, size_t maxNumBranches,
-				const Kmer &origin, const BranchRecord& branch)
+				const BranchRecord::V &origin, const BranchRecord& branch)
 			: m_dir(dir), m_origin(origin),
 			m_maxNumBranches(maxNumBranches), m_noExt(false),
 			m_status(BGS_ACTIVE)
@@ -68,11 +67,11 @@ class BranchGroup
 		/** Add a branch to this group and extend the new branch with
 		 * the given k-mer. */
 		void addBranch(const BranchRecord& branch,
-				const Kmer& kmer)
+				const BranchRecord::V& kmer)
 		{
 			if (m_branches.size() < m_maxNumBranches)
 				addBranch(branch).push_back(
-						std::make_pair(kmer, KmerData()));
+						std::make_pair(kmer, BranchRecord::VP()));
 			else
 				m_status = BGS_TOOMANYBRANCHES;
 		}
@@ -88,7 +87,7 @@ class BranchGroup
 
 		/** Return whether a branch contains the specified k-mer at
 		 * the index i. */
-		bool exists(unsigned i, const Kmer& kmer) const
+		bool exists(unsigned i, const BranchRecord::V& kmer) const
 		{
 			for (BranchGroupData::const_iterator it
 					= m_branches.begin();
@@ -98,21 +97,15 @@ class BranchGroup
 			return false;
 		}
 
-		BranchGroupStatus updateStatus(unsigned maxLength);
-
 		// return the current status of the branch
 		BranchGroupStatus getStatus() const { return m_status; }
 
 		// set the no extension flag
 		void setNoExtension() { m_noExt = true; }
 
-		bool isActive() const;
-
 		// is the no extension flag set?
 		bool isNoExt() const { return m_noExt; }
 
-		bool isExtendable();
-
 		// return the direction of growth
 		extDirection getDirection() const { return m_dir; }
 
@@ -121,14 +114,96 @@ class BranchGroup
 		const_iterator begin() const { return m_branches.begin(); }
 		const_iterator end() const { return m_branches.end(); }
 
-		bool isAmbiguous(const SequenceCollectionHash& c) const;
+// Check the stop conditions for the bubble growth
+BranchGroupStatus
+updateStatus(unsigned maxLength)
+{
+	assert(m_branches.size() <= m_maxNumBranches);
+
+	if (m_status != BGS_ACTIVE)
+		return m_status;
+
+	// Check if the no extension flag is set
+	if(m_noExt)
+	{
+		m_status = BGS_NOEXT;
+		return m_status;
+	}
+
+	// Check if any branches are too long or any sequence has a loop
+	for (BranchGroupData::const_iterator iter = m_branches.begin();
+			iter != m_branches.end(); ++iter) {
+		if (iter->isTooLong(maxLength)) {
+			m_status = BGS_TOOLONG;
+			return m_status;
+		}
+	}
+
+	BranchGroupData::const_iterator it = m_branches.begin();
+	const BranchRecord::V& lastSeq = it->back().first;
+	while (++it != m_branches.end())
+		if (it->back().first != lastSeq)
+			return m_status = BGS_ACTIVE;
+
+	// All the branches of the bubble have joined.
+	// Remove the last base, which is identical for every branch.
+	std::for_each(m_branches.begin(), m_branches.end(),
+			std::mem_fun_ref(&BranchRecord::pop_back));
+
+	// Sort the branches by coverage.
+	sort_by_transform(m_branches.begin(), m_branches.end(),
+			std::mem_fun_ref(&BranchRecord::calculateBranchMultiplicity));
+	reverse(m_branches.begin(), m_branches.end());
+
+	return m_status = BGS_JOINED;
+}
+
+/** Return whether any branches of this group are active. */
+bool
+isActive() const
+{
+	for (BranchGroupData::const_iterator it = m_branches.begin();
+			it != m_branches.end(); ++it)
+		if (it->isActive())
+			return true;
+	return false;
+}
+
+/** Return whether this branch is extendable. */
+bool
+isExtendable()
+{
+	if (m_noExt)
+		return false;
+
+	// A group is extendable when all the branches are the same
+	// length. All the branches are lockstepped for growth.
+	BranchGroupData::iterator it = m_branches.begin();
+	unsigned length = it++->size();
+	for (; it != m_branches.end(); ++it)
+		if (it->size() != length)
+			return false;
+	return true;
+}
+
+/** Return whether this branch is ambiguous at its origin. Also
+ * returns false if the origin of the branch has since been deleted.
+ */
+bool
+isAmbiguous(const SequenceCollectionHash& g) const
+{
+	// Get fresh data from the collection to check that this bubble
+	// does in fact still exist.
+	const BranchRecord::VP& data = g.getSeqAndData(m_origin).second;
+	return data.deleted() ? false : data.isAmbiguous(m_dir);
+}
 
 	private:
 		BranchGroup& operator =(const BranchGroup& o);
 
 		BranchGroupData m_branches;
 		extDirection m_dir;
- 		Kmer m_origin;
+		BranchRecord::V m_origin;
 		size_t m_maxNumBranches;
 		bool m_noExt;
 		BranchGroupStatus m_status;
diff --git a/Assembly/BranchRecord.cpp b/Assembly/BranchRecord.cpp
deleted file mode 100644
index 1074a1a..0000000
--- a/Assembly/BranchRecord.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "BranchRecord.h"
-
-using namespace std;
-
-/** Calculate the total multiplicity of this branch. */
-int BranchRecord::calculateBranchMultiplicity() const
-{
-	assert(!m_data.empty());
-	int total = 0;
-	for (BranchData::const_iterator it = m_data.begin();
-			it != m_data.end(); ++it) {
-		int m = it->second.getMultiplicity();
-		assert(m >= 0);
-		total += m;
-	}
-	assert(total >= 0);
-	return total;
-}
-
-/** Build a contig from a branch. */
-BranchRecord::operator Sequence() const
-{
-	assert(!m_data.empty());
-	Sequence outseq;
-	outseq.reserve(m_data.front().first.length() + m_data.size() - 1);
-
-	if (m_dir == SENSE) {
-		BranchData::const_iterator iter = m_data.begin();
-		outseq = iter->first.str();
-		++iter;
-		for (; iter != m_data.end(); ++iter)
-			outseq.append(1, iter->first.getLastBaseChar());
-	} else {
-		BranchData::const_reverse_iterator iter = m_data.rbegin();
-		outseq = iter->first.str();
-		++iter;
-		for (; iter != m_data.rend(); ++iter)
-			outseq.append(1, iter->first.getLastBaseChar());
-	}
-	return outseq;
-}
-
-/**
- * Return whether this branch is the canonical representation of the
- * contig that it represents. A contig has two ends, and the contig
- * is output starting from the lexicographically smaller end.
- */
-bool BranchRecord::isCanonical() const
-{
-	assert(size() > 1);
-	Kmer first = front().first;
-	Kmer last = back().first;
-	if (getDirection() == SENSE)
-		last.reverseComplement();
-	else
-		first.reverseComplement();
-	assert(first != last);
-	return first < last;
-}
diff --git a/Assembly/BranchRecord.h b/Assembly/BranchRecord.h
index 2b8f9f1..7766bcb 100644
--- a/Assembly/BranchRecord.h
+++ b/Assembly/BranchRecord.h
@@ -1,140 +1,21 @@
-#ifndef BRANCHRECORD_H
-#define BRANCHRECORD_H 1
+#ifndef ASSEMBLY_BRANCHRECORD_H
+#define ASSEMBLY_BRANCHRECORD_H 1
 
-#include "Kmer.h"
-#include "KmerData.h"
-#include <algorithm> // for swap
-#include <cassert>
-#include <utility>
-#include <vector>
-
-enum BranchState
-{
-	// The branch can be extended.
-	BS_ACTIVE,
-	// The branch has ended because of a lack of sequence to extend to
-	BS_NOEXT,
-	// The branch has ended because the extension from this branch is
-	// ambigious.
-	BS_AMBI_SAME,
-	// The branch has ended because the extension to this branch is
-	// ambigiuous.
-	BS_AMBI_OPP,
-	// The branch is too long.
-	BS_TOO_LONG,
-};
-
-/** A sequence of Kmer. */
-class BranchRecord
+/** Generate the sequence of this contig. */
+template <typename It, typename OutIt>
+void branchRecordToStr(It it, It last, OutIt out)
 {
-	public:
-		typedef std::pair<Kmer, KmerData> value_type;
-		typedef std::vector<value_type> BranchData;
-		typedef BranchData::iterator iterator;
-		typedef BranchData::const_iterator const_iterator;
-
-		BranchRecord() : m_dir(SENSE), m_state(BS_ACTIVE) { }
-
-		explicit BranchRecord(extDirection dir)
-			: m_dir(dir), m_state(BS_ACTIVE) { }
-
-		void swap(BranchRecord& o)
-		{
-			std::swap(m_data, o.m_data);
-			std::swap(m_dir, o.m_dir);
-			std::swap(m_state, o.m_state);
-		}
-
-		operator Sequence() const;
-
-		/** Return true if this sequence has no elements. */
-		bool empty() const { return m_data.empty(); }
-
-		/** Return the number of elements. */
-		size_t size() const { return m_data.size(); }
-
-		/** Add the element x at the end. */
-		void push_back(const value_type& x) { m_data.push_back(x); }
-
-		/** Remove the last k-mer. */
-		void pop_back()
-		{
-			assert(!m_data.empty());
-			m_data.pop_back();
-		}
-
-		/** Return the first element. */
-		const value_type& front() const
-		{
-			assert(!m_data.empty());
-			return m_data.front();
-		}
-
-		/** Return the last element. */
-		const value_type& back() const
-		{
-			assert(!m_data.empty());
-			return m_data.back();
-		}
-
-		/** Terminate this branch with the specified reason. */
-		void terminate(BranchState reason)
-		{
-			assert(reason != BS_ACTIVE);
-			m_state = reason;
-		}
-
-		/** Return whether this branch is active. */
-		bool isActive() const { return m_state == BS_ACTIVE; }
-
-		/** Return the state of this branch. */
-		BranchState getState() const { return m_state;	}
-
-		/** Return the direction of this branch. */
-		extDirection getDirection() const { return m_dir; }
-
-		/** Set the properties of the last element. */
-		void setData(const value_type& o)
-		{
-			assert(m_data.back().first == o.first);
-			m_data.back().second = o.second;
-		}
-
-		iterator begin() { return m_data.begin(); }
-		iterator end() { return m_data.end(); }
-		const_iterator begin() const { return m_data.begin(); }
-		const_iterator end() const { return m_data.end(); }
-
-		/** Return true if the k-mer at position i is the specified
-		 * k-mer. */
-		bool exists(unsigned i, const Kmer& kmer) const
-		{
-			assert(i < m_data.size());
-			return m_data[i].first == kmer;
-		}
-
-		/** Return true if this branch is longer than maxLength. */
-		bool isTooLong(unsigned maxLength) const
-		{
-			return size() > maxLength;
-		}
-
-		int calculateBranchMultiplicity() const;
-
-		bool isCanonical() const;
-
-	private:
-		BranchData m_data;
-		extDirection m_dir;
-		BranchState m_state;
-};
-
-namespace std {
-	template <>
-	inline void swap(BranchRecord& a, BranchRecord& b)
-	{
-		a.swap(b);
+	assert(it < last);
+	std::string k0 = it->first.str();
+	std::copy(k0.begin(), k0.end(), out);
+	out += k0.length();
+	++it;
+	for (; it != last; ++it) {
+		*out = it->first.getLastBaseChar();
+		++out;
 	}
 }
 
+#include "Assembly/BranchRecordBase.h"
+
 #endif
diff --git a/Assembly/BranchRecord.h b/Assembly/BranchRecordBase.h
similarity index 65%
copy from Assembly/BranchRecord.h
copy to Assembly/BranchRecordBase.h
index 2b8f9f1..936bda1 100644
--- a/Assembly/BranchRecord.h
+++ b/Assembly/BranchRecordBase.h
@@ -1,12 +1,11 @@
-#ifndef BRANCHRECORD_H
-#define BRANCHRECORD_H 1
+#ifndef ASSEMBLY_BRANCHRECORDBASE_H
+#define ASSEMBLY_BRANCHRECORDBASE_H 1
 
-#include "Kmer.h"
-#include "KmerData.h"
-#include <algorithm> // for swap
+#include <algorithm>
 #include <cassert>
 #include <utility>
 #include <vector>
+#include <iterator>
 
 enum BranchState
 {
@@ -24,11 +23,15 @@ enum BranchState
 	BS_TOO_LONG,
 };
 
-/** A sequence of Kmer. */
+/** A sequence of vertices. */
 class BranchRecord
 {
 	public:
-		typedef std::pair<Kmer, KmerData> value_type;
+		typedef SequenceCollectionHash Graph;
+		typedef graph_traits<Graph>::vertex_descriptor V;
+		typedef vertex_bundle_type<Graph>::type VP;
+
+		typedef std::pair<V, VP> value_type;
 		typedef std::vector<value_type> BranchData;
 		typedef BranchData::iterator iterator;
 		typedef BranchData::const_iterator const_iterator;
@@ -45,8 +48,6 @@ class BranchRecord
 			std::swap(m_state, o.m_state);
 		}
 
-		operator Sequence() const;
-
 		/** Return true if this sequence has no elements. */
 		bool empty() const { return m_data.empty(); }
 
@@ -107,7 +108,7 @@ class BranchRecord
 
 		/** Return true if the k-mer at position i is the specified
 		 * k-mer. */
-		bool exists(unsigned i, const Kmer& kmer) const
+		bool exists(unsigned i, const V& kmer) const
 		{
 			assert(i < m_data.size());
 			return m_data[i].first == kmer;
@@ -119,9 +120,49 @@ class BranchRecord
 			return size() > maxLength;
 		}
 
-		int calculateBranchMultiplicity() const;
+/** Calculate the total multiplicity of this branch. */
+int calculateBranchMultiplicity() const
+{
+	assert(!m_data.empty());
+	int total = 0;
+	for (BranchData::const_iterator it = m_data.begin();
+			it != m_data.end(); ++it) {
+		int m = it->second.getMultiplicity();
+		assert(m >= 0);
+		total += m;
+	}
+	assert(total >= 0);
+	return total;
+}
+
+/**
+ * Return whether this branch is the canonical representation of the
+ * contig that it represents. A contig has two ends, and the contig
+ * is output starting from the lexicographically smaller end.
+ */
+bool isCanonical() const
+{
+	assert(size() > 1);
+	V first = front().first;
+	V last = back().first;
+	if (getDirection() == SENSE)
+		last.reverseComplement();
+	else
+		first.reverseComplement();
+	assert(first != last);
+	return first < last;
+}
 
-		bool isCanonical() const;
+/** Return the sequence of this contig. */
+operator Sequence() const
+{
+	assert(!m_data.empty());
+	Sequence s(m_data.front().first.length() + m_data.size() - 1, 'N');
+	m_dir == SENSE
+		? branchRecordToStr(m_data.begin(), m_data.end(), s.begin())
+		: branchRecordToStr(m_data.rbegin(), m_data.rend(), s.begin());
+	return s;
+}
 
 	private:
 		BranchData m_data;
diff --git a/Assembly/BubbleAlgorithm.h b/Assembly/BubbleAlgorithm.h
new file mode 100644
index 0000000..94a8309
--- /dev/null
+++ b/Assembly/BubbleAlgorithm.h
@@ -0,0 +1,279 @@
+#ifndef ASSEMBLY_BUBBLEALGORITHM_H
+#define ASSEMBLY_BUBBLEALGORITHM_H 1
+
+#include "Common/IOUtil.h"
+#include "Common/Options.h" // for opt::rank
+#include <fstream>
+#include <sstream>
+
+namespace AssemblyAlgorithms {
+
+static inline bool
+processBranchGroupExtension(BranchGroup& group,
+		size_t branchIndex,
+		const graph_traits<SequenceCollectionHash>::vertex_descriptor& seq,
+		SequenceCollectionHash::SymbolSetPair ext,
+		int multiplicity,
+		unsigned maxLength);
+
+template <typename Graph>
+void collapseJoinedBranches(Graph* collection,
+		BranchGroup& group);
+
+static inline
+void writeBubble(std::ostream& out, const BranchGroup& group, unsigned id);
+
+/** Open the bubble file. */
+static inline
+void openBubbleFile(std::ofstream& out)
+{
+	if (opt::snpPath.empty())
+		return;
+	std::string path;
+	if (opt::rank < 0) {
+		path = opt::snpPath;
+	} else {
+		std::ostringstream s;
+		s << "snp-" << opt::rank << ".fa";
+		path = s.str();
+	}
+	out.open(path.c_str());
+	assert_good(out, path);
+}
+
+/** Pop bubbles. */
+static inline
+size_t popBubbles(SequenceCollectionHash* seqCollection, std::ostream& out)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	typedef Graph::SymbolSetPair SymbolSetPair;
+
+	Timer timer("PopBubbles");
+	size_t numPopped = 0;
+
+	// Set the cutoffs
+	const unsigned maxNumBranches = 3;
+	const unsigned maxLength = opt::bubbleLen - V::length() + 1;
+
+	for (Graph::iterator iter = seqCollection->begin();
+			iter != seqCollection->end(); ++iter) {
+		if (iter->second.deleted())
+			continue;
+
+		SymbolSetPair extRec = iter->second.extension();
+		for (extDirection dir = SENSE; dir <= ANTISENSE; ++dir) {
+			if (extRec.dir[dir].isAmbiguous()) {
+				// Found a potential bubble, examine each branch
+				bool stop = false;
+
+				// Create the branch group
+				BranchGroup branchGroup(dir, maxNumBranches,
+						iter->first);
+				initiateBranchGroup(branchGroup, iter->first,
+						extRec.dir[dir]);
+
+				// Iterate over the branches
+				while(!stop)
+				{
+					size_t numBranches = branchGroup.size();
+					for (unsigned j = 0; j < numBranches; ++j) {
+						// Get the extensions of this branch
+						SymbolSetPair extRec;
+						int multiplicity = -1;
+
+						const V& lastKmer
+							= branchGroup[j].back().first;
+						bool success = seqCollection->getSeqData(
+								lastKmer, extRec, multiplicity);
+						assert(success);
+						(void)success;
+						processBranchGroupExtension(branchGroup, j,
+								lastKmer, extRec, multiplicity,
+								maxLength);
+					}
+
+					// At this point all branches should have the same
+					// length or one will be a noext.
+					branchGroup.updateStatus(maxLength);
+					BranchGroupStatus status
+						= branchGroup.getStatus();
+					if (status == BGS_TOOLONG
+							|| status == BGS_TOOMANYBRANCHES
+							|| status == BGS_NOEXT) {
+						stop = true;
+					}
+					else if(status == BGS_JOINED)
+					{
+						static unsigned snpID;
+						writeBubble(out, branchGroup, ++snpID);
+						assert(branchGroup.isAmbiguous(
+									*seqCollection));
+						collapseJoinedBranches(seqCollection,
+								branchGroup);
+						assert(!branchGroup.isAmbiguous(
+									*seqCollection));
+						numPopped++;
+						stop = true;
+					} else
+						assert(status == BGS_ACTIVE);
+				}
+			}
+		}
+		seqCollection->pumpNetwork();
+	}
+
+	if (numPopped > 0)
+		std::cout << "Removed " << numPopped << " bubbles.\n";
+	if (!opt::db.empty()) {
+		addToDb("totalErodedTips", tempCounter[0]);
+		addToDb("totalPrunedTips", tempCounter[1]);
+		addToDb("totalLowCovCntg", tempCounter[3]);
+		addToDb("totalLowCovKmer", tempCounter[4]);
+		addToDb("totalSplitAmbg", tempCounter[7]);
+		addToDb("poppedBubbles", numPopped);
+		tempCounter.assign(16,0);
+	}
+	return numPopped;
+}
+
+// Populate a branch group with the inital branches from a sequence
+static inline void
+initiateBranchGroup(BranchGroup& group,
+		const graph_traits<SequenceCollectionHash>::vertex_descriptor& seq,
+		const SequenceCollectionHash::SymbolSet& extension)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+
+	std::vector<V> extSeqs;
+	generateSequencesFromExtension(seq, group.getDirection(),
+			extension, extSeqs);
+	assert(extSeqs.size() > 1);
+	for (std::vector<V>::iterator seqIter = extSeqs.begin();
+			seqIter != extSeqs.end(); ++seqIter)
+		group.addBranch(BranchRecord(group.getDirection()), *seqIter);
+}
+
+/** Process an a branch group extension. */
+static inline bool
+processBranchGroupExtension(BranchGroup& group,
+		size_t branchIndex,
+		const graph_traits<SequenceCollectionHash>::vertex_descriptor& seq,
+		SequenceCollectionHash::SymbolSetPair ext,
+		int multiplicity,
+		unsigned maxLength)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	typedef vertex_bundle_type<Graph>::type VP;
+
+	BranchRecord& branch = group[branchIndex];
+	branch.setData(std::make_pair(seq, VP(multiplicity, ext)));
+
+	extDirection dir = group.getDirection();
+	if (ext.dir[!dir].isAmbiguous()) {
+		// Check that this fork is due to branches of our bubble
+		// merging back together. If not, stop this bubble.
+		if (branch.size() < 2) {
+			group.setNoExtension();
+			return false;
+		}
+
+		std::vector<V> extKmer;
+		generateSequencesFromExtension(seq, !dir,
+				ext.dir[!dir], extKmer);
+		assert(extKmer.size() > 1);
+		for (std::vector<V>::iterator it = extKmer.begin();
+				it != extKmer.end(); ++it) {
+			assert(branch.size() > 1);
+			if (!group.exists(branch.size() - 2, *it)) {
+				group.setNoExtension();
+				return false;
+			}
+		}
+		// Ignore the ambiguity.
+		ext.dir[!dir].clear();
+	}
+
+	if (ext.dir[dir].isAmbiguous()) {
+		// Create a new branch to follow the fork.
+		std::vector<V> extKmer;
+		generateSequencesFromExtension(seq, dir,
+				ext.dir[dir], extKmer);
+		assert(extKmer.size() > 1);
+		BranchRecord original = branch;
+		std::vector<V>::iterator it = extKmer.begin();
+		branch.push_back(std::make_pair(*it++, VP()));
+		for (; it != extKmer.end(); ++it)
+			group.addBranch(original, *it);
+		return group.isExtendable();
+	}
+
+	V nextKmer = seq;
+	if (processLinearExtensionForBranch(branch,
+			nextKmer, ext, multiplicity,
+			maxLength, false))
+		branch.push_back(std::make_pair(nextKmer, VP()));
+	else
+		group.setNoExtension();
+	return group.isExtendable();
+}
+
+/** Write a bubble to the specified file. */
+static inline
+void writeBubble(std::ostream& out, const BranchGroup& group, unsigned id)
+{
+	if (opt::snpPath.empty())
+		return;
+
+	char allele = 'A';
+	for (BranchGroup::const_iterator it = group.begin();
+			it != group.end(); ++it) {
+		const BranchRecord& currBranch = *it;
+		Sequence contig(currBranch);
+		out << '>' << id << allele++ << ' '
+			<< contig.length() << ' '
+			<< currBranch.calculateBranchMultiplicity() << '\n'
+			<< contig.c_str() << '\n';
+	}
+	assert(out.good());
+}
+
+/** Collapse a bubble to a single path. */
+template <typename Graph>
+void collapseJoinedBranches(Graph* collection,
+		BranchGroup& group)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+	typedef typename vertex_bundle_type<Graph>::type VP;
+	typedef typename std::map<V, VP> Map;
+
+	const BranchRecord& best = group[0];
+	logger(5) << "Popping " << best.size() << ' '
+		<< best.front().first << '\n';
+
+	// Add the k-mer from the dead branches.
+	Map doomed;
+	for (BranchGroup::const_iterator branchIt = group.begin() + 1;
+			branchIt != group.end(); ++branchIt) {
+		const BranchRecord& branch = *branchIt;
+		for (BranchRecord::const_iterator it = branch.begin();
+				it != branch.end(); ++it)
+			doomed.insert(*it);
+	}
+
+	// Remove the k-mer that are in the good branch.
+	for (BranchRecord::const_iterator it = best.begin();
+			it != best.end(); ++it)
+		doomed.erase(it->first);
+
+	// Remove the dead k-mer from the assembly.
+	for (typename Map::const_iterator it = doomed.begin();
+			it != doomed.end(); ++it)
+		removeSequenceAndExtensions(collection, *it);
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/CoverageAlgorithm.h b/Assembly/CoverageAlgorithm.h
new file mode 100644
index 0000000..fd5904d
--- /dev/null
+++ b/Assembly/CoverageAlgorithm.h
@@ -0,0 +1,117 @@
+#ifndef ASSEMBLY_COVERAGEALGORITHM_H
+#define ASSEMBLY_COVERAGEALGORITHM_H 1
+
+#include "Common/Histogram.h"
+#include "Common/IOUtil.h"
+#include "Common/Options.h" // for opt::rank
+#include <fstream>
+
+namespace AssemblyAlgorithms {
+
+/** Return the k-mer coverage histogram. */
+static inline
+Histogram coverageHistogram(const SequenceCollectionHash& c)
+{
+	typedef SequenceCollectionHash Graph;
+
+	Histogram h;
+	for (Graph::const_iterator it = c.begin();
+			it != c.end(); ++it) {
+		if (it->second.deleted())
+			continue;
+		h.insert(it->second.getMultiplicity());
+	}
+	return h;
+}
+
+/** Calculate a k-mer coverage threshold from the given k-mer coverage
+ * histogram. */
+static inline
+float calculateCoverageThreshold(const Histogram& h)
+{
+	float cov = h.firstLocalMinimum();
+	if (opt::rank <= 0) {
+		if (cov == 0)
+			std::cout << "Unable to determine minimum k-mer coverage\n";
+		else
+			std::cout << "Minimum k-mer coverage is " << cov << std::endl;
+	}
+
+	for (unsigned iteration = 0; iteration < 100; iteration++) {
+		Histogram trimmed = h.trimLow((unsigned)roundf(cov));
+		if (opt::rank <= 0)
+			logger(1) << "Coverage: " << cov << "\t"
+				"Reconstruction: " << trimmed.size() << std::endl;
+
+		unsigned median = trimmed.median();
+		float cov1 = sqrt(median);
+		if (cov1 == cov) {
+			// The coverage threshold has converged.
+			if (opt::rank <= 0)
+				std::cout << "Using a coverage threshold of "
+					<< (unsigned)roundf(cov) << "...\n"
+					"The median k-mer coverage is " << median << "\n"
+					"The reconstruction is " << trimmed.size()
+					<< std::endl;
+			if (!opt::db.empty()) {
+				addToDb("coverageThreshold", (unsigned)roundf(cov));
+				addToDb("medianKcoverage", median);
+				addToDb("restruction", trimmed.size());
+			}
+			return cov;
+		}
+		cov = cov1;
+	}
+	if (opt::rank <= 0)
+		std::cerr << "warning: coverage threshold did not converge"
+			<< std::endl;
+	return 0;
+}
+
+/** Set the coverage-related parameters e and c from the given k-mer
+ * coverage histogram. */
+static inline
+void setCoverageParameters(const Histogram& h)
+{
+	if (!opt::coverageHistPath.empty() && opt::rank <= 0) {
+		std::ofstream histFile(opt::coverageHistPath.c_str());
+		assert_good(histFile, opt::coverageHistPath);
+		histFile << h;
+		assert(histFile.good());
+	}
+
+	float minCov = calculateCoverageThreshold(h);
+	if (opt::rank <= 0) {
+		if (minCov == 0)
+			std::cout << "Unable to determine the "
+				"k-mer coverage threshold" << std::endl;
+		else
+			std::cout << "The k-mer coverage threshold is " << minCov
+				<< std::endl;
+	}
+	if (minCov < 2)
+		minCov = 2;
+
+	if ((int)opt::erode < 0) {
+		opt::erode = (unsigned)roundf(minCov);
+		if (opt::rank <= 0)
+			std::cout << "Setting parameter e (erode) to "
+				<< opt::erode << std::endl;
+	}
+	if ((int)opt::erodeStrand < 0) {
+		opt::erodeStrand = minCov <= 2 ? 0 : 1;
+		if (opt::rank <= 0)
+			std::cout << "Setting parameter E (erodeStrand) to "
+				<< opt::erodeStrand << std::endl;
+	}
+	if (opt::coverage < 0) {
+		opt::coverage = minCov;
+		if (opt::rank <= 0)
+			std::cout << "Setting parameter c (coverage) to "
+				<< opt::coverage << std::endl;
+	}
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/DBG.h b/Assembly/DBG.h
new file mode 100644
index 0000000..20eb44d
--- /dev/null
+++ b/Assembly/DBG.h
@@ -0,0 +1,913 @@
+#ifndef ASSEMBLY_DBG_H
+#define ASSEMBLY_DBG_H 1
+
+#include "config.h"
+#include "Assembly/Options.h"
+#include "Common/Log.h"
+#include "Common/MemoryUtil.h"
+#include "Common/Options.h"
+#include "Common/StringUtil.h" // for toSI
+#include "Common/Timer.h"
+#include "Graph/Properties.h"
+
+#include <boost/graph/graph_traits.hpp>
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <iomanip>
+#include <sstream>
+#include <utility>
+
+using boost::graph_traits;
+
+/** A hash table mapping vertices to vertex properties. */
+class SequenceCollectionHash
+{
+	public:
+		typedef SequenceDataHash::key_type key_type;
+		typedef SequenceDataHash::mapped_type mapped_type;
+		typedef SequenceDataHash::value_type value_type;
+		typedef SequenceDataHash::iterator iterator;
+		typedef SequenceDataHash::const_iterator const_iterator;
+
+		typedef mapped_type::Symbol Symbol;
+		typedef mapped_type::SymbolSet SymbolSet;
+		typedef mapped_type::SymbolSetPair SymbolSetPair;
+
+		typedef key_type vertex_descriptor;
+		typedef mapped_type vertex_bundled;
+		typedef std::pair<key_type, key_type> edge_descriptor;
+
+		/** Remove the specified sequence if it exists. */
+		void remove(const key_type& seq)
+		{
+			setFlag(seq, SF_DELETE);
+		}
+
+		/** Shrink the hash table. */
+		void shrink() {
+			m_data.rehash(0);
+			printLoad();
+		}
+
+		/** Return the data associated with the specified key. */
+		const mapped_type operator[](const key_type& key) const
+		{
+			bool rc;
+			const_iterator it = find(key, rc);
+			assert(it != m_data.end());
+			return rc ? ~it->second : it->second;
+		}
+
+		iterator begin() { return m_data.begin(); }
+		const_iterator begin() const { return m_data.begin(); }
+		iterator end() { return m_data.end(); }
+		const_iterator end() const { return m_data.end(); }
+
+		/** Return true if this collection is empty. */
+		bool empty() const { return m_data.empty(); }
+
+		/** Return the number of sequences in this collection. */
+		size_t size() const { return m_data.size(); }
+
+		// Not a network sequence collection. Nothing to do.
+		size_t pumpNetwork() { return 0; }
+
+		/** The observer callback function. */
+		typedef void (*SeqObserver)(SequenceCollectionHash* c,
+				const value_type& seq);
+
+		/** Attach the specified observer. */
+		void attach(SeqObserver f)
+		{
+			assert(m_seqObserver == NULL);
+			m_seqObserver = f;
+		}
+
+		/** Detach the specified observer. */
+		void detach(SeqObserver f)
+		{
+			assert(m_seqObserver == f);
+			(void)f;
+			m_seqObserver = NULL;
+		}
+
+		bool isAdjacencyLoaded() const { return m_adjacencyLoaded; }
+
+SequenceCollectionHash()
+	: m_seqObserver(NULL), m_adjacencyLoaded(false)
+{
+#if HAVE_GOOGLE_SPARSE_HASH_MAP
+	// sparse_hash_set uses 2.67 bits per element on a 64-bit
+	// architecture and 2 bits per element on a 32-bit architecture.
+	// The number of elements is rounded up to a power of two.
+	if (opt::rank >= 0) {
+		// Make room for 200 million k-mers. Approximately 58 million
+		// 96-mers fit into 2 GB of ram, which results in a hash load
+		// of 0.216, and approximately 116 million 32-mers, which
+		// results in a hash load of 0.432.
+		m_data.rehash(200000000);
+		m_data.min_load_factor(0.2);
+	} else {
+		// Allocate a big hash for a single processor.
+		m_data.rehash(1<<29);
+		m_data.max_load_factor(0.4);
+	}
+#endif
+}
+
+/** sparse_hash_set requires that set_deleted_key()
+ * is called before calling erase(). This key cannot
+ * be an existing kmer in m_data. This function sets
+ * the deleted key and should be called after all
+ * data has been loaded.
+ */
+void setDeletedKey()
+{
+#if HAVE_GOOGLE_SPARSE_HASH_MAP
+	for (SequenceDataHash::iterator it = m_data.begin();
+			it != m_data.end(); it++) {
+		key_type rc(reverseComplement(it->first));
+		bool isrc;
+		SequenceDataHash::iterator search = find(rc, isrc);
+		// If this is false, we should have a palindrome or we're
+		// doing a SS assembly.
+		if (isrc || search == m_data.end()) {
+			m_data.set_deleted_key(rc);
+			return;
+		}
+	}
+	logger(1) << "error: unable to set deleted key.\n";
+	exit(EXIT_FAILURE);
+#else
+	return;
+#endif
+}
+
+/** Add the specified k-mer to this collection. */
+void add(const key_type& seq, unsigned coverage = 1)
+{
+	bool rc;
+	iterator it = find(seq, rc);
+	if (it == m_data.end()) {
+		m_data.insert(std::make_pair(seq, mapped_type(SENSE, coverage)));
+	} else if (coverage > 0) {
+		assert(!rc || !opt::ss);
+		it->second.addMultiplicity(rc ? ANTISENSE : SENSE, coverage);
+	}
+}
+
+/** Clean up by erasing sequences flagged as deleted.
+ * @return the number of sequences erased
+ */
+size_t cleanup()
+{
+	Timer(__func__);
+	size_t count = 0;
+	for (iterator it = m_data.begin(); it != m_data.end();) {
+		if (it->second.deleted()) {
+			m_data.erase(it++);
+			count++;
+		} else
+			++it;
+	}
+	shrink();
+	return count;
+}
+
+/** Add an edge to this k-mer. */
+bool setBaseExtension(
+		const key_type& kmer, extDirection dir, Symbol base)
+{
+	bool rc;
+	iterator it = find(kmer, rc);
+	if (it == m_data.end())
+		return false;
+	if (opt::ss) {
+		assert(!rc);
+		it->second.setBaseExtension(dir, base);
+	} else {
+		bool palindrome = kmer.isPalindrome();
+		if (!rc || palindrome)
+			it->second.setBaseExtension(dir, base);
+		if (rc || palindrome)
+			it->second.setBaseExtension(!dir, reverseComplement(base));
+	}
+	return true;
+}
+
+/** Remove the specified extensions from this k-mer. */
+void removeExtension(const key_type& kmer,
+		extDirection dir, SymbolSet ext)
+{
+	bool rc;
+	iterator it = find(kmer, rc);
+	assert(it != m_data.end());
+	if (opt::ss) {
+		assert(!rc);
+		it->second.removeExtension(dir, ext);
+	} else {
+		bool palindrome = kmer.isPalindrome();
+		if (!rc || palindrome)
+			it->second.removeExtension(dir, ext);
+		if (rc || palindrome)
+			it->second.removeExtension(!dir, ext.complement());
+	}
+	notify(*it);
+}
+
+/** Remove the specified edge of this vertex. */
+void removeExtension(const key_type& seq, extDirection dir, Symbol base)
+{
+	removeExtension(seq, dir, SymbolSet(base));
+}
+
+void setFlag(const key_type& key, SeqFlag flag)
+{
+	bool rc;
+	iterator it = find(key, rc);
+	assert(it != m_data.end());
+	it->second.setFlag(rc ? complement(flag) : flag);
+}
+
+/** Mark the specified sequence in both directions. */
+void mark(const key_type& seq)
+{
+	setFlag(seq, SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE));
+}
+
+/** Mark the specified sequence. */
+void mark(const key_type& seq, extDirection sense)
+{
+	setFlag(seq, sense == SENSE
+			? SF_MARK_SENSE : SF_MARK_ANTISENSE);
+}
+
+/** Clear the specified flag for all vertices. */
+void wipeFlag(SeqFlag flag)
+{
+	for (iterator it = m_data.begin();
+			it != m_data.end(); ++it)
+		it->second.clearFlag(flag);
+}
+
+/** Print the load of the hash table. */
+void printLoad() const
+{
+	size_t size = m_data.size();
+	size_t buckets = m_data.bucket_count();
+	logger(1) << "Hash load: " << size << " / " << buckets << " = "
+		<< std::setprecision(3) << (float)size / buckets
+		<< " using " << toSI(getMemoryUsage()) << "B" << std::endl;
+}
+
+private:
+
+const_iterator
+find(const key_type& key) const
+{
+	return m_data.find(key);
+}
+
+iterator
+find(const key_type& key)
+{
+	return m_data.find(key);
+}
+
+/** Return an iterator pointing to the specified k-mer or its
+ * reverse complement. Return in rc whether the sequence is reversed.
+ */
+iterator
+find(const key_type& key, bool& rc)
+{
+	iterator it = find(key);
+	if (opt::ss || it != m_data.end()) {
+		rc = false;
+		return it;
+	} else {
+		rc = true;
+		return find(reverseComplement(key));
+	}
+}
+
+public:
+
+/** Return an iterator pointing to the specified k-mer or its
+ * reverse complement. Return in rc whether the sequence is reversed.
+ */
+const_iterator
+find(const key_type& key, bool& rc) const
+{
+	const_iterator it = find(key);
+	if (opt::ss || it != m_data.end()) {
+		rc = false;
+		return it;
+	} else {
+		rc = true;
+		return find(reverseComplement(key));
+	}
+}
+
+/** Return the sequence and data of the specified key.
+ * The key sequence may not contain data. The returned sequence will
+ * contain data.
+ */
+const value_type&
+getSeqAndData(const key_type& key) const
+{
+	bool rc;
+	const_iterator it = find(key, rc);
+	// rc should not be ignored. This seems quite dubious.
+	// The edges of this k-mer should be complemented.
+	assert(it != m_data.end());
+	return *it;
+}
+
+/** Return the data of the specified key. */
+bool getSeqData(const key_type& key,
+		SymbolSetPair& extRecord, int& multiplicity) const
+{
+	bool rc;
+	const_iterator it = find(key, rc);
+	assert(!rc || !opt::ss);
+	if (it == m_data.end())
+		return false;
+	const mapped_type data = it->second;
+	extRecord = rc ? data.extension().complement() : data.extension();
+	multiplicity = data.getMultiplicity();
+	return true;
+}
+
+/** Write this collection to disk.
+ * @param path does not include the extension
+ */
+void store(const char* path)
+{
+	assert(path != NULL);
+#if HAVE_GOOGLE_SPARSE_HASH_MAP
+	std::ostringstream s;
+	s << path;
+	if (opt::rank >= 0)
+		s << '-' << std::setfill('0') << std::setw(3) << opt::rank;
+	s << ".kmer";
+	FILE* f = fopen(s.str().c_str(), "w");
+	if (f == NULL) {
+		perror(s.str().c_str());
+		exit(EXIT_FAILURE);
+	}
+	shrink();
+	m_data.write_metadata(f);
+	m_data.write_nopointer_data(f);
+	fclose(f);
+#else
+	// Not supported.
+	assert(false);
+	exit(EXIT_FAILURE);
+#endif
+}
+
+/** Load this collection from disk. */
+void load(const char* path)
+{
+#if HAVE_GOOGLE_SPARSE_HASH_MAP
+	FILE* f = fopen(path, "r");
+	if (f == NULL) {
+		perror(path);
+		exit(EXIT_FAILURE);
+	}
+	m_data.read_metadata(f);
+	m_data.read_nopointer_data(f);
+	fclose(f);
+	m_adjacencyLoaded = true;
+#else
+	(void)path;
+	// Not supported.
+	assert(false);
+	exit(EXIT_FAILURE);
+#endif
+}
+
+/** Indicate that this is a colour-space collection. */
+void setColourSpace(bool flag)
+{
+	if (!m_data.empty())
+		assert(opt::colourSpace == flag);
+	opt::colourSpace = flag;
+}
+
+	private:
+		/** Call the observers of the specified sequence. */
+		void notify(const value_type& seq)
+		{
+			if (m_seqObserver != NULL)
+				m_seqObserver(this, seq);
+		}
+
+		/** The underlying collection. */
+		SequenceDataHash m_data;
+
+		/** The observers. Only a single observer is implemented.*/
+		SeqObserver m_seqObserver;
+
+		/** Whether adjacency information has been loaded. */
+		bool m_adjacencyLoaded;
+};
+
+// Forward declaration
+class DBGEdgeIterator;
+
+// Graph
+
+namespace boost {
+
+template <>
+struct graph_traits<SequenceCollectionHash> {
+	// Graph
+	typedef SequenceCollectionHash Graph;
+	typedef Graph::key_type vertex_descriptor;
+	typedef boost::directed_tag directed_category;
+	struct traversal_category
+		: boost::adjacency_graph_tag, boost::vertex_list_graph_tag
+		{ };
+	typedef boost::disallow_parallel_edge_tag edge_parallel_category;
+
+	// IncidenceGraph
+	typedef std::pair<vertex_descriptor, vertex_descriptor>
+		edge_descriptor;
+	typedef unsigned degree_size_type;
+
+	// VertexListGraph
+	typedef size_t vertices_size_type;
+
+	// EdgeListGraph
+	typedef size_t edges_size_type;
+	typedef DBGEdgeIterator edge_iterator;
+
+	// Other
+	typedef Graph::Symbol Symbol;
+	typedef Graph::SymbolSet SymbolSet;
+	static const unsigned NUM_SYMBOLS = SymbolSet::NUM;
+
+// AdjacencyGraph
+/** Iterate through the adjacent vertices of a vertex. */
+struct adjacency_iterator
+	: public std::iterator<std::input_iterator_tag, vertex_descriptor>
+{
+	/** Skip to the next edge that is present. */
+	void next()
+	{
+		for (; m_i < NUM_SYMBOLS && !m_adj.checkBase(Symbol(m_i)); ++m_i) {
+		}
+		if (m_i < NUM_SYMBOLS)
+			m_v.setLastBase(SENSE, Symbol(m_i));
+	}
+
+  public:
+	adjacency_iterator() : m_i(NUM_SYMBOLS) { }
+
+	adjacency_iterator(
+			vertex_descriptor u, SymbolSet adj)
+		: m_v(u), m_adj(adj), m_i(0)
+	{
+		m_v.shift(SENSE);
+		next();
+	}
+
+	const vertex_descriptor& operator*() const
+	{
+		assert(m_i < NUM_SYMBOLS);
+		return m_v;
+	}
+
+	bool operator==(const adjacency_iterator& it) const
+	{
+		return m_i == it.m_i;
+	}
+
+	bool operator!=(const adjacency_iterator& it) const
+	{
+		return !(*this == it);
+	}
+
+	adjacency_iterator& operator++()
+	{
+		assert(m_i < NUM_SYMBOLS);
+		++m_i;
+		next();
+		return *this;
+	}
+
+  private:
+	vertex_descriptor m_v;
+	SymbolSet m_adj;
+	short unsigned m_i;
+}; // adjacency_iterator
+
+// IncidenceGraph
+
+/** Iterate through the out edges of a vertex. */
+struct out_edge_iterator
+	: public std::iterator<std::input_iterator_tag, edge_descriptor>
+{
+	/** Skip to the next edge that is present. */
+	void next()
+	{
+		for (; m_i < NUM_SYMBOLS && !m_adj.checkBase(Symbol(m_i)); ++m_i) {
+		}
+		if (m_i < NUM_SYMBOLS)
+			m_e.second.setLastBase(SENSE, Symbol(m_i));
+	}
+
+  public:
+	out_edge_iterator() : m_i(NUM_SYMBOLS) { }
+
+	out_edge_iterator(
+			vertex_descriptor u, SymbolSet adj)
+		: m_e(u, u), m_adj(adj), m_i(0)
+	{
+		m_e.second.shift(SENSE);
+		next();
+	}
+
+	const edge_descriptor& operator*() const
+	{
+		assert(m_i < NUM_SYMBOLS);
+		return m_e;
+	}
+
+	bool operator==(const out_edge_iterator& it) const
+	{
+		return m_i == it.m_i;
+	}
+
+	bool operator!=(const out_edge_iterator& it) const
+	{
+		return !(*this == it);
+	}
+
+	out_edge_iterator& operator++()
+	{
+		assert(m_i < NUM_SYMBOLS);
+		++m_i;
+		next();
+		return *this;
+	}
+
+  private:
+	edge_descriptor m_e;
+	SymbolSet m_adj;
+	short unsigned m_i;
+}; // out_edge_iterator
+
+// BidirectionalGraph
+
+/** Iterate through the in-edges of a vertex. */
+struct in_edge_iterator
+	: public std::iterator<std::input_iterator_tag, edge_descriptor>
+{
+	/** Skip to the next edge that is present. */
+	void next()
+	{
+		for (; m_i < NUM_SYMBOLS && !m_adj.checkBase(Symbol(m_i)); ++m_i) {
+		}
+		if (m_i < NUM_SYMBOLS)
+			m_e.first.setLastBase(ANTISENSE, Symbol(m_i));
+	}
+
+  public:
+	in_edge_iterator() : m_i(NUM_SYMBOLS) { }
+
+	in_edge_iterator(
+			vertex_descriptor u, SymbolSet adj)
+		: m_e(u, u), m_adj(adj), m_i(0)
+	{
+		m_e.first.shift(ANTISENSE);
+		next();
+	}
+
+	const edge_descriptor& operator*() const
+	{
+		assert(m_i < NUM_SYMBOLS);
+		return m_e;
+	}
+
+	bool operator==(const in_edge_iterator& it) const
+	{
+		return m_i == it.m_i;
+	}
+
+	bool operator!=(const in_edge_iterator& it) const
+	{
+		return !(*this == it);
+	}
+
+	in_edge_iterator& operator++()
+	{
+		assert(m_i < NUM_SYMBOLS);
+		++m_i;
+		next();
+		return *this;
+	}
+
+  private:
+	edge_descriptor m_e;
+	SymbolSet m_adj;
+	short unsigned m_i;
+}; // in_edge_iterator
+
+// VertexListGraph
+/** Iterate through the vertices of this graph. */
+struct vertex_iterator
+	: public std::iterator<std::input_iterator_tag, vertex_descriptor>
+{
+	typedef Graph::const_iterator It;
+
+  public:
+	vertex_iterator(const It& it) : m_it(it), m_sense(false) { }
+
+	const vertex_descriptor operator*() const
+	{
+		return m_sense ? reverseComplement(m_it->first) : m_it->first;
+	}
+
+	bool operator==(const vertex_iterator& it) const
+	{
+		return m_it == it.m_it && m_sense == it.m_sense;
+	}
+
+	bool operator!=(const vertex_iterator& it) const
+	{
+		return !(*this == it);
+	}
+
+	vertex_iterator& operator++()
+	{
+		if (m_sense) {
+			++m_it;
+			m_sense = false;
+		} else
+			m_sense = true;
+		return *this;
+	}
+
+  private:
+	It m_it;
+	bool m_sense;
+}; // vertex_iterator
+
+}; // graph_traits<SequenceCollectionHash>
+
+} // namespace boost
+
+// IncidenceGraph
+
+static inline
+std::pair<
+	graph_traits<SequenceCollectionHash>::out_edge_iterator,
+	graph_traits<SequenceCollectionHash>::out_edge_iterator>
+out_edges(
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u,
+		const SequenceCollectionHash& g)
+{
+	typedef graph_traits<SequenceCollectionHash> GTraits;
+	typedef GTraits::out_edge_iterator out_edge_iterator;
+	typedef GTraits::SymbolSet SymbolSet;
+	SymbolSet adj = g[u].getExtension(SENSE);
+	return std::make_pair(
+			out_edge_iterator(u, adj),
+			out_edge_iterator());
+}
+
+static inline
+graph_traits<SequenceCollectionHash>::degree_size_type
+out_degree(
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u,
+		const SequenceCollectionHash& g)
+{
+	return g[u].getExtension(SENSE).outDegree();
+}
+
+// BidirectionalGraph
+
+static inline
+std::pair<
+	graph_traits<SequenceCollectionHash>::in_edge_iterator,
+	graph_traits<SequenceCollectionHash>::in_edge_iterator>
+in_edges(
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u,
+		const SequenceCollectionHash& g)
+{
+	typedef graph_traits<SequenceCollectionHash> GTraits;
+	typedef GTraits::in_edge_iterator in_edge_iterator;
+	typedef GTraits::SymbolSet SymbolSet;
+	SymbolSet adj = g[u].getExtension(ANTISENSE);
+	return std::make_pair(
+			in_edge_iterator(u, adj),
+			in_edge_iterator());
+}
+
+static inline
+graph_traits<SequenceCollectionHash>::degree_size_type
+in_degree(graph_traits<SequenceCollectionHash>::vertex_descriptor u,
+		const SequenceCollectionHash& g)
+{
+	return g[u].getExtension(ANTISENSE).outDegree();
+}
+
+// AdjacencyGraph
+
+static inline
+std::pair<graph_traits<SequenceCollectionHash>::adjacency_iterator,
+	graph_traits<SequenceCollectionHash>::adjacency_iterator>
+adjacent_vertices(
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u,
+		const SequenceCollectionHash& g)
+{
+	typedef graph_traits<SequenceCollectionHash>::adjacency_iterator
+		adjacency_iterator;
+	typedef graph_traits<SequenceCollectionHash>::SymbolSet SymbolSet;
+	SymbolSet adj = g[u].getExtension(SENSE);
+	return std::make_pair(adjacency_iterator(u, adj),
+			adjacency_iterator());
+}
+
+// VertexListGraph
+
+static inline
+std::pair<graph_traits<SequenceCollectionHash>::vertex_iterator,
+	graph_traits<SequenceCollectionHash>::vertex_iterator>
+vertices(const SequenceCollectionHash& g)
+{
+	return std::make_pair(g.begin(), g.end());
+}
+
+// EdgeListGraph
+
+/** Iterate through the edges of this graph. */
+class DBGEdgeIterator
+	: public std::iterator<std::input_iterator_tag,
+		graph_traits<SequenceCollectionHash>::edge_descriptor>
+{
+	typedef graph_traits<SequenceCollectionHash> GTraits;
+	typedef GTraits::adjacency_iterator adjacency_iterator;
+	typedef GTraits::edge_descriptor edge_descriptor;
+	typedef GTraits::edge_iterator edge_iterator;
+	typedef GTraits::vertex_iterator vertex_iterator;
+
+	void nextVertex()
+	{
+		vertex_iterator vlast = vertices(*m_g).second;
+		for (; m_vit != vlast; ++m_vit) {
+			std::pair<adjacency_iterator, adjacency_iterator>
+				adj = adjacent_vertices(*m_vit, *m_g);
+			if (adj.first != adj.second) {
+				m_eit = adj.first;
+				return;
+			}
+		}
+		// Set m_eit to a known value.
+		static const adjacency_iterator s_eitNULL;
+		m_eit = s_eitNULL;
+	}
+
+  public:
+	DBGEdgeIterator(const SequenceCollectionHash* g, const vertex_iterator& vit)
+		: m_g(g), m_vit(vit)
+	{
+		nextVertex();
+	}
+
+	edge_descriptor operator*() const
+	{
+		return edge_descriptor(*m_vit, *m_eit);
+	}
+
+	bool operator==(const edge_iterator& it) const
+	{
+		return m_vit == it.m_vit && m_eit == it.m_eit;
+	}
+
+	bool operator!=(const edge_iterator& it) const
+	{
+		return !(*this == it);
+	}
+
+	edge_iterator& operator++()
+	{
+		if (++m_eit == adjacent_vertices(*m_vit, *m_g).second) {
+			++m_vit;
+			nextVertex();
+		}
+		return *this;
+	}
+
+	edge_iterator operator++(int)
+	{
+		edge_iterator it = *this;
+		++*this;
+		return it;
+	}
+
+  private:
+	const SequenceCollectionHash* m_g;
+	vertex_iterator m_vit;
+	adjacency_iterator m_eit;
+}; // DBGEdgeIterator
+
+/** Iterate through the edges of this graph. */
+static inline
+std::pair<
+	graph_traits<SequenceCollectionHash>::edge_iterator,
+	graph_traits<SequenceCollectionHash>::edge_iterator>
+edges(const SequenceCollectionHash& g)
+{
+	
+	typedef graph_traits<SequenceCollectionHash> GTraits;
+	typedef GTraits::vertex_iterator vertex_iterator;
+	typedef GTraits::edge_iterator edge_iterator;
+	std::pair<vertex_iterator, vertex_iterator> uit = vertices(g);
+	return std::make_pair(
+			edge_iterator(&g, uit.first),
+			edge_iterator(&g, uit.second));
+}
+
+// EdgeMutableGraph
+
+/** Remove the edge (u,v) from the graph. */
+static inline
+void
+remove_edge(
+	graph_traits<SequenceCollectionHash>::vertex_descriptor u,
+	graph_traits<SequenceCollectionHash>::vertex_descriptor v,
+	SequenceCollectionHash& g)
+{
+	g.removeExtension(u, SENSE, v.back());
+}
+
+/** Remove the edge e from the graph. */
+static inline
+void
+remove_edge(
+		graph_traits<SequenceCollectionHash>::edge_descriptor e,
+		SequenceCollectionHash& g)
+{
+	remove_edge(source(e, g), target(e, g), g);
+}
+
+// PropertyGraph
+
+/** Return the reverse complement of the specified k-mer. */
+static inline
+graph_traits<SequenceCollectionHash>::vertex_descriptor
+get(vertex_complement_t, const SequenceCollectionHash&,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
+{
+	return reverseComplement(u);
+}
+
+/** Return whether this vertex has been removed. */
+static inline
+bool get(vertex_removed_t, const SequenceCollectionHash& g,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
+{
+	return g.getSeqAndData(u).second.deleted();
+}
+
+/** Return the name of this vertex. */
+static inline
+std::string
+get(vertex_name_t, const SequenceCollectionHash&,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
+{
+	return u.str();
+}
+
+/** Return the properties of this vertex. */
+static inline
+vertex_bundle_type<SequenceCollectionHash>::type
+get(vertex_bundle_t, const SequenceCollectionHash& g,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
+{
+	return g[u];
+}
+
+/** Return the coverage of this vertex. */
+static inline
+unsigned
+get(vertex_coverage_t, const SequenceCollectionHash& g,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
+{
+	return g[u].getMultiplicity();
+}
+
+/** Return the properties of this edge. */
+static inline
+no_property get(edge_bundle_t, const SequenceCollectionHash&,
+		graph_traits<SequenceCollectionHash>::edge_descriptor)
+{
+	return no_property();
+}
+
+#endif
diff --git a/Assembly/DotWriter.cpp b/Assembly/DotWriter.cpp
deleted file mode 100644
index f66a858..0000000
--- a/Assembly/DotWriter.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/** Written by Shaun Jackman <sjackman at bcgsc.ca>. */
-
-#include "DotWriter.h"
-#include "SequenceCollection.h"
-#include "Graph/ContigGraphAlgorithms.h"
-#include <cassert>
-#include <ostream>
-
-using namespace std;
-
-typedef SequenceCollectionHash Graph;
-typedef graph_traits<Graph>::vertex_iterator vertex_iterator;
-typedef graph_traits<Graph>::adjacency_iterator adjacency_iterator;
-
-/** Write out the specified contig. */
-static void writeContig(ostream& out, const Graph& g, const Kmer& u)
-{
-	if (contiguous_in(g, u))
-		return;
-	unsigned n = 1;
-	Kmer v = u;
-	while (contiguous_out(g, v)) {
-		n++;
-		v = *adjacent_vertices(v, g).first;
-	}
-	out << u << " -> " << v;
-	if (n > 2)
-		out << " [label=" << n << ']';
-	out << '\n';
-}
-
-/** Write out the contigs that split at the specified sequence. */
-static void writeEdges(ostream& out, const Graph& g, const Kmer& u)
-{
-	unsigned outdeg = out_degree(u, g);
-	if (outdeg == 0)
-		return;
-	out << u << " ->";
-	if (outdeg > 1)
-		out << " {";
-	std::pair<adjacency_iterator, adjacency_iterator>
-		adj = adjacent_vertices(u, g);
-	for (adjacency_iterator v = adj.first; v != adj.second; ++v)
-		out << ' ' << *v;
-	if (outdeg > 1)
-		out << " }";
-	out << '\n';
-}
-
-/** Write out a dot graph around the specified sequence. */
-static void write_vertex(ostream& out, const Graph& g, const Kmer& u)
-{
-	if (contiguous_out(g, u))
-		writeContig(out, g, u);
-	else
-		writeEdges(out, g, u);
-}
-
-/** Write out a dot graph for the specified collection. */
-void DotWriter::write(ostream& out, const Graph& g)
-{
-	out << "digraph g {\n";
-	std::pair<vertex_iterator, vertex_iterator> vit = vertices(g);
-	for (vertex_iterator u = vit.first; u != vit.second; ++u) {
-		if (get(vertex_removed, g, *u))
-			continue;
-		write_vertex(out, g, *u);
-	}
-	out << "}" << endl;
-}
diff --git a/Assembly/DotWriter.h b/Assembly/DotWriter.h
index 3357246..d86cde5 100644
--- a/Assembly/DotWriter.h
+++ b/Assembly/DotWriter.h
@@ -1,13 +1,214 @@
-#ifndef DOTWRITER_H
-#define DOTWRITER_H 1
+#ifndef ASSEMBLY_DOTWRITER_H
+#define ASSEMBLY_DOTWRITER_H 1
 
-#include "SequenceCollection.h"
-#include <ostream>
+/** Written by Shaun Jackman <sjackman at bcgsc.ca>. */
 
-class DotWriter {
-  public:
-	static void write(std::ostream& out,
-			const SequenceCollectionHash& c);
+#include "Common/UnorderedMap.h"
+#include "Graph/ContigGraphAlgorithms.h"
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+class DotWriter
+{
+private:
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	typedef graph_traits<Graph>::vertex_iterator Vit;
+	typedef graph_traits<Graph>::adjacency_iterator Ait;
+	typedef std::string VertexName;
+
+	DotWriter() : m_id(0) { }
+
+/** Complement the specified name. */
+static std::string
+complementName(std::string s)
+{
+	char c = *s.rbegin();
+	assert(c == '+' || c == '-');
+	*s.rbegin() = c == '+' ? '-' : '+';
+	return s;
+}
+
+/** Return the name of the specified vertex. */
+const VertexName&
+getName(const V& u) const
+{
+	Names::const_iterator it = m_names.find(u);
+	if (it == m_names.end())
+		std::cerr << "error: cannot find vertex " << u << '\n';
+	assert(it != m_names.end());
+	return it->second;
+}
+
+/** Set the name of the specified vertex. */
+void setName(const V& u, const VertexName& uname)
+{
+	std::pair<Names::const_iterator, bool> inserted
+		= m_names.insert(Names::value_type(u, uname));
+	if (!inserted.second)
+		std::cerr << "error: duplicate vertex " << u << '\n';
+	assert(inserted.second);
+	(void)inserted;
+}
+
+/** Return whether this vertex is contiguous and not palindromic. */
+bool contiguousOut(const Graph& g, const V& u)
+{
+	return contiguous_out(g, u)
+		&& !u.isPalindrome()
+		&& !u.isPalindrome(SENSE)
+		&& !(*adjacent_vertices(u, g).first).isPalindrome();
+}
+
+/** Return the in-adjacent vertex. */
+V adjacentVertexIn(const V& u, const Graph& g)
+{
+	return source(*in_edges(u, g).first, g);
+}
+
+/** Return whether this vertex is contiguous and not palindromic. */
+bool contiguousIn(const Graph& g, const V& u)
+{
+	return contiguous_in(g, u)
+		&& !u.isPalindrome()
+		&& !u.isPalindrome(ANTISENSE)
+		&& !adjacentVertexIn(u, g).isPalindrome();
+}
+
+/** Write out the specified contig. */
+void writeContig(std::ostream& out, const Graph& g, const V& u)
+{
+	unsigned n = 0;
+	unsigned c = 0;
+	V v;
+	for (v = u; contiguousOut(g, v); v = *adjacent_vertices(v, g).first) {
+		++n;
+		c += get(vertex_coverage, g, v);
+	}
+	++n;
+	c += get(vertex_coverage, g, v);
+
+	// Output the canonical orientation of the contig.
+	V vrc = get(vertex_complement, g, v);
+	if (vrc < u)
+		return;
+
+	std::ostringstream ss;
+	ss << m_id << '+';
+	VertexName uname = ss.str();
+	VertexName vname(uname);
+	*vname.rbegin() = '-';
+	++m_id;
+
+	// Reorient the contig to agree with assembleContig.
+	bool rc;
+	Graph::const_iterator it = g.find(u, rc);
+	assert(it != g.end());
+	(void)it;
+	if (rc)
+		std::swap(uname, vname);
+
+	setName(u, uname);
+	if (u == vrc) {
+		// Palindrome
+		assert(n == 1);
+	} else
+		setName(vrc, vname);
+
+	unsigned l = n + V::length() - 1;
+	out << '"' << uname << "\" [l=" << l << " C=" << c << "]\n"
+		"\"" << vname << "\" [l=" << l << " C=" << c << "]\n";
+}
+
+/** Write out the contigs that split at the specified sequence. */
+void
+writeEdges(std::ostream& out, const Graph& g,
+		const V& u, const VertexName& uname) const
+{
+	if (out_degree(u, g) == 0)
+		return;
+	out << '"' << uname << "\" -> {";
+	std::pair<Ait, Ait> adj = adjacent_vertices(u, g);
+	for (Ait vit = adj.first; vit != adj.second; ++vit) {
+		V v = *vit;
+		const VertexName& vname = getName(v);
+		out << " \"" << vname << '"';
+		if (v.isPalindrome())
+			out << " \"" << complementName(vname) << '"';
+	}
+	out << " }\n";
+}
+
+/** Output the edges of the specified vertex. */
+void
+writeEdges(std::ostream& out, const Graph& g, const V& u) const
+{
+	std::string uname = complementName(getName(get(vertex_complement, g, u)));
+	writeEdges(out, g, u, uname);
+	if (u.isPalindrome()) {
+		uname = complementName(uname);
+		writeEdges(out, g, u, uname);
+	}
+}
+
+/** Write out a dot graph for the specified collection. */
+void writeGraph(std::ostream& out, const Graph& g)
+{
+	out << "digraph g {\n"
+		"graph [k=" << V::length() << "]\n"
+		"edge [d=" << -int(V::length() - 1) << "]\n";
+	std::pair<Vit, Vit> uits = vertices(g);
+
+	// Output the vertices.
+	for (Vit uit = uits.first; uit != uits.second; ++uit) {
+		V u = *uit;
+		if (get(vertex_removed, g, u))
+			continue;
+		if (!contiguousIn(g, u))
+			writeContig(out, g, u);
+		// Skip the second occurence of the palindrome.
+		if (u.isPalindrome()) {
+			assert(uit != uits.second);
+			++uit;
+		}
+	}
+
+	// Output the edges.
+	for (Vit uit = uits.first; uit != uits.second; ++uit) {
+		V u = *uit;
+		if (get(vertex_removed, g, u))
+			continue;
+		if (!contiguousOut(g, u))
+			writeEdges(out, g, u);
+		// Skip the second occurence of the palindrome.
+		if (u.isPalindrome()) {
+			assert(uit != uits.second);
+			++uit;
+		}
+	}
+
+	out << "}" << std::endl;
+}
+
+public:
+
+/** Write out a dot graph for the specified collection. */
+static
+void write(std::ostream& out, const Graph& g)
+{
+	DotWriter dotWriter;
+	dotWriter.writeGraph(out, g);
+}
+
+private:
+	typedef unordered_map<V, VertexName> Names;
+
+	/** A map of terminal k-mers to contig names. */
+	Names m_names;
+
+	/** The current contig name. */
+	unsigned m_id;
 };
 
 #endif
diff --git a/Assembly/ErodeAlgorithm.h b/Assembly/ErodeAlgorithm.h
new file mode 100644
index 0000000..1b0f245
--- /dev/null
+++ b/Assembly/ErodeAlgorithm.h
@@ -0,0 +1,117 @@
+#ifndef ASSEMBLY_ERODE_ALGORITHM
+#define ASSEMBLY_ERODE_ALGORITHM 1
+
+namespace AssemblyAlgorithms {
+
+/** The number of k-mer that have been eroded. */
+extern size_t g_numEroded;
+
+template <typename Graph>
+void removeExtensionsToSequence(Graph* seqCollection,
+		const typename Graph::value_type& seq, extDirection dir);
+
+/**
+ * Remove a k-mer and update the extension records of the k-mer that
+ * extend to it.
+ */
+template <typename Graph>
+void removeSequenceAndExtensions(Graph* seqCollection,
+		const typename Graph::value_type& seq)
+{
+	// This removes the reverse complement as well
+	seqCollection->remove(seq.first);
+	removeExtensionsToSequence(seqCollection, seq, SENSE);
+	removeExtensionsToSequence(seqCollection, seq, ANTISENSE);
+}
+
+/** Remove all the extensions to this sequence. */
+template <typename Graph>
+void removeExtensionsToSequence(Graph* seqCollection,
+		const typename Graph::value_type& seq, extDirection dir)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+	typedef typename Graph::Symbol Symbol;
+	typedef typename Graph::SymbolSet SymbolSet;
+
+	SymbolSet extension(seq.second.getExtension(dir));
+	V testSeq(seq.first);
+	Symbol extBase = testSeq.shift(dir);
+	for (unsigned i = 0; i < extension.NUM; ++i) {
+		Symbol x(i);
+		if (extension.checkBase(x)) {
+			testSeq.setLastBase(dir, x);
+			seqCollection->removeExtension(testSeq, !dir, extBase);
+		}
+	}
+}
+
+/** Return the number of k-mer that have been eroded. */
+static inline
+size_t getNumEroded()
+{
+	size_t numEroded = g_numEroded;
+	g_numEroded = 0;
+	tempCounter[0] += numEroded;
+	logger(0) << "Eroded " << numEroded << " tips.\n";
+	return numEroded;
+}
+
+/** Consider the specified k-mer for erosion.
+ * @return the number of k-mer eroded, zero or one
+ */
+template <typename Graph>
+size_t erode(Graph* c, const typename Graph::value_type& seq)
+{
+	typedef typename vertex_bundle_type<Graph>::type VP;
+
+	if (seq.second.deleted())
+		return 0;
+	extDirection dir;
+	SeqContiguity contiguity = checkSeqContiguity(seq, dir);
+	if (contiguity == SC_CONTIGUOUS)
+		return 0;
+
+	const VP& data = seq.second;
+	if (data.getMultiplicity() < opt::erode
+			|| data.getMultiplicity(SENSE) < opt::erodeStrand
+			|| data.getMultiplicity(ANTISENSE) < opt::erodeStrand) {
+		removeSequenceAndExtensions(c, seq);
+		g_numEroded++;
+		return 1;
+	} else
+		return 0;
+}
+
+/** The given sequence has changed. */
+static inline
+void erosionObserver(SequenceCollectionHash* c,
+		const SequenceCollectionHash::value_type& seq)
+{
+	erode(c, seq);
+}
+
+//
+// Erode data off the ends of the graph, one by one
+//
+template <typename Graph>
+size_t erodeEnds(Graph* seqCollection)
+{
+	typedef typename Graph::iterator iterator;
+
+	Timer erodeEndsTimer("Erode");
+	assert(g_numEroded == 0);
+	seqCollection->attach(erosionObserver);
+
+	for (iterator iter = seqCollection->begin();
+			iter != seqCollection->end(); ++iter) {
+		erode(seqCollection, *iter);
+		seqCollection->pumpNetwork();
+	}
+
+	seqCollection->detach(erosionObserver);
+	return getNumEroded();
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/ISequenceCollection.h b/Assembly/ISequenceCollection.h
deleted file mode 100644
index d015203..0000000
--- a/Assembly/ISequenceCollection.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef ISEQUENCECOLLECTION_H
-#define ISEQUENCECOLLECTION_H 1
-
-#include "config.h"
-#include "Kmer.h"
-#include "KmerData.h"
-
-#if HAVE_GOOGLE_SPARSE_HASH_MAP
-# include <google/sparse_hash_map>
-typedef google::sparse_hash_map<Kmer, KmerData, hash<Kmer> >
-	SequenceDataHash;
-#else
-# include "UnorderedMap.h"
-typedef unordered_map<Kmer, KmerData, hash<Kmer> >
-	SequenceDataHash;
-#endif
-
-/** The interface of a map of Kmer to KmerData. */
-class ISequenceCollection
-{
-	public:
-		typedef SequenceDataHash::value_type value_type;
-		typedef SequenceDataHash::iterator iterator;
-		typedef SequenceDataHash::const_iterator const_iterator;
-
-		virtual ~ISequenceCollection() { }
-
-		virtual void add(const Kmer& seq, unsigned coverage = 1) = 0;
-		virtual void remove(const Kmer& seq) = 0;
-
-		virtual void setFlag(const Kmer& seq, SeqFlag flag) = 0;
-
-		/** Mark the specified sequence in both directions. */
-		void mark(const Kmer& seq)
-		{
-			setFlag(seq, SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE));
-		}
-
-		/** Mark the specified sequence. */
-		void mark(const Kmer& seq, extDirection sense)
-		{
-			setFlag(seq, sense == SENSE
-					? SF_MARK_SENSE : SF_MARK_ANTISENSE);
-		}
-
-		virtual bool empty() const = 0;
-
-		virtual void printLoad() const = 0;
-
-		virtual void removeExtension(const Kmer& seq,
-				extDirection dir, SeqExt ext) = 0;
-
-		/** Remove the specified edge of this k-mer. */
-		void removeExtension(const Kmer& seq,
-				extDirection dir, uint8_t base)
-		{
-			removeExtension(seq, dir, SeqExt(base));
-		}
-
-		/** Remove all the edges of this k-mer. */
-		void clearExtensions(const Kmer& seq, extDirection dir)
-		{
-			removeExtension(seq, dir, SeqExt::mask(0xf));
-		}
-
-		virtual bool setBaseExtension(const Kmer& seq,
-				extDirection dir, uint8_t base) = 0;
-
-		// Receive and dispatch packets if necessary.
-		virtual size_t pumpNetwork() = 0;
-
-		virtual iterator begin() = 0;
-		virtual const_iterator begin() const = 0;
-		virtual iterator end() = 0;
-		virtual const_iterator end() const = 0;
-
-		// Observer pattern
-		typedef void (*SeqObserver)(ISequenceCollection* c,
-				const value_type& seq);
-		virtual void attach(SeqObserver f) = 0;
-		virtual void detach(SeqObserver f) = 0;
-
-		virtual void load(const char *path) = 0;
-
-		virtual void setColourSpace(bool flag) = 0;
-};
-
-#endif
diff --git a/Assembly/LoadAlgorithm.h b/Assembly/LoadAlgorithm.h
new file mode 100644
index 0000000..f6f694b
--- /dev/null
+++ b/Assembly/LoadAlgorithm.h
@@ -0,0 +1,182 @@
+#ifndef ASSEMBLY_LOADALGORITHM_H
+#define ASSEMBLY_LOADALGORITHM_H 1
+
+#include "DataLayer/FastaReader.h"
+
+namespace AssemblyAlgorithms {
+
+/** Load k-mer with coverage data.
+ * @return the number of k-mer loaded
+ */
+template <typename Graph>
+size_t loadKmer(Graph& g, FastaReader& in)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+
+	assert(opt::rank == -1);
+	size_t count = 0;
+	for (FastaRecord rec; in >> rec;) {
+		assert(rec.seq.size() == V::length());
+		std::istringstream iss(rec.id);
+		float coverage = 1;
+		iss >> coverage;
+		assert(iss);
+		assert(iss.eof());
+		g.add(V(rec.seq), std::max(1, (int)ceilf(coverage)));
+
+		if (++count % 1000000 == 0) {
+			logger(1) << "Read " << count << " k-mer. ";
+			g.printLoad();
+		}
+		g.pumpNetwork();
+	}
+	assert(in.eof());
+	return count;
+}
+
+template <typename Graph>
+bool loadSequence(Graph* seqCollection, Sequence& seq)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+
+	size_t len = seq.length();
+
+	if (isalnum(seq[0])) {
+		if (opt::colourSpace)
+			assert(isdigit(seq[0]));
+		else
+			assert(isalpha(seq[0]));
+	}
+
+	bool good = seq.find_first_not_of("ACGT0123") == std::string::npos;
+	bool discarded = true;
+
+	for (unsigned i = 0; i < len - V::length() + 1; ++i) {
+		Sequence kmer(seq, i, V::length());
+		if (good || kmer.find_first_not_of("acgtACGT0123")
+				== std::string::npos) {
+			if (good || kmer.find_first_of("acgt") == std::string::npos)
+				seqCollection->add(V(kmer));
+			else {
+				transform(kmer.begin(), kmer.end(), kmer.begin(),
+						::toupper);
+				seqCollection->add(V(kmer), 0);
+			}
+			discarded = false;
+		}
+	}
+
+	return discarded;
+}
+
+/** Load sequence data into the collection. */
+template <typename Graph>
+void loadSequences(Graph* seqCollection, std::string inFile)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+
+	Timer timer("LoadSequences " + inFile);
+
+	logger(0) << "Reading `" << inFile << "'...\n";
+
+	if (inFile.find(".kmer") != std::string::npos) {
+		if (opt::rank <= 0)
+			seqCollection->setColourSpace(false);
+		seqCollection->load(inFile.c_str());
+		return;
+	}
+
+	size_t count = 0, count_good = 0,
+			 count_small = 0, count_nonACGT = 0,
+			 count_reversed = 0;
+	int fastaFlags = opt::maskCov ?  FastaReader::NO_FOLD_CASE :
+			FastaReader::FOLD_CASE;
+	FastaReader reader(inFile.c_str(), fastaFlags);
+	if (endsWith(inFile, ".jf") || endsWith(inFile, ".jfq")) {
+		// Load k-mer with coverage data.
+		count = loadKmer(*seqCollection, reader);
+		count_good = count;
+	} else
+	for (FastaRecord rec; reader >> rec;) {
+		Sequence seq = rec.seq;
+		size_t len = seq.length();
+		if (V::length() > len) {
+			count_small++;
+			continue;
+		}
+
+		if (opt::rank <= 0
+				&& count == 0 && seqCollection->empty()) {
+			// Detect colour-space reads.
+			bool colourSpace
+				= seq.find_first_of("0123") != std::string::npos;
+			seqCollection->setColourSpace(colourSpace);
+			if (colourSpace)
+				std::cout << "Colour-space assembly\n";
+		}
+
+		if (opt::ss && rec.id.size() > 2
+				&& rec.id.substr(rec.id.size()-2) == "/1") {
+			seq = reverseComplement(seq);
+			count_reversed++;
+		}
+
+		bool discarded = loadSequence(seqCollection, seq);
+
+		if (discarded)
+			count_nonACGT++;
+		else
+			count_good++;
+
+		if (++count % 100000 == 0) {
+			logger(1) << "Read " << count << " reads. ";
+			seqCollection->printLoad();
+		}
+		seqCollection->pumpNetwork();
+	}
+	assert(reader.eof());
+
+	logger(1) << "Read " << count << " reads. ";
+	seqCollection->printLoad();
+
+	if (count_reversed > 0)
+		std::cerr << "`" << inFile << "': "
+			"reversed " << count_reversed << " reads\n";
+	if (count_small > 0)
+		std::cerr << "`" << inFile << "': "
+			"discarded " << count_small << " reads "
+			"shorter than " << V::length() << " bases\n";
+	if (reader.unchaste() > 0)
+		std::cerr << "`" << inFile << "': "
+			"discarded " << reader.unchaste() << " unchaste reads\n";
+	if (count_nonACGT > 0)
+		std::cerr << "`" << inFile << "': "
+			"discarded " << count_nonACGT << " reads "
+			"containing non-ACGT characters\n";
+			tempCounter[0] += count_reversed;
+			tempCounter[1] += (count_small + reader.unchaste() + count_nonACGT);
+	if (count_good == 0)
+		std::cerr << "warning: `" << inFile << "': "
+			"contains no usable sequence\n";
+
+	if (opt::rank <= 0 && count == 0 && seqCollection->empty()) {
+		/* The master process did not load any data, which means that
+		 * it hasn't told the slave processes whether this assembly is
+		 * in colour-space. Rather than fail right now, assume that
+		 * the assembly is not colour space. If the assumption is
+		 * incorrect, the assembly will fail pretty quickly as soon as
+		 * one of the slave processes sees a colour-space read.
+		 */
+		assert(!opt::colourSpace);
+		seqCollection->setColourSpace(false);
+	}
+	if (!opt::db.empty()) {
+		addToDb("reversedReads", tempCounter[0]);
+		addToDb("totalDiscardedReads", tempCounter[1]);
+	}
+	tempCounter.assign(2,0);
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/Makefile.am b/Assembly/Makefile.am
index 245f80d..50c04a7 100644
--- a/Assembly/Makefile.am
+++ b/Assembly/Makefile.am
@@ -1,15 +1,25 @@
 noinst_LIBRARIES = libassembly.a
 
-libassembly_a_CPPFLAGS = -I$(top_srcdir) \
-	-I$(top_srcdir)/Common \
-	-I$(top_srcdir)/DataLayer
+libassembly_a_CPPFLAGS = -I$(top_srcdir)
 
 libassembly_a_SOURCES = \
-	AssemblyAlgorithms.cpp AssemblyAlgorithms.h \
-	BranchGroup.cpp BranchGroup.h \
-	BranchRecord.cpp BranchRecord.h \
-	DotWriter.cpp DotWriter.h \
-	ISequenceCollection.h \
-	KmerData.h \
-	Options.cpp Options.h \
-	SequenceCollection.cpp SequenceCollection.h
+	AssemblyAlgorithms.cc AssemblyAlgorithms.h \
+	BranchGroup.h \
+	BranchRecord.h \
+	BranchRecordBase.h \
+	DBG.h \
+	DotWriter.h \
+	Options.cc Options.h \
+	SequenceCollection.h \
+	VertexData.h \
+	AdjacencyAlgorithm.h \
+	AssembleAlgorithm.h \
+	BubbleAlgorithm.h \
+	CoverageAlgorithm.h \
+	ErodeAlgorithm.h \
+	LoadAlgorithm.h \
+	SeqExt.h \
+	SplitAlgorithm.h \
+	TrimAlgorithm.h
+
+libassembly_a_LIBADD = $(top_builddir)/Common/libcommon.a
diff --git a/Assembly/Options.cpp b/Assembly/Options.cc
similarity index 80%
rename from Assembly/Options.cpp
rename to Assembly/Options.cc
index 8cbb455..379dd1f 100644
--- a/Assembly/Options.cpp
+++ b/Assembly/Options.cc
@@ -3,14 +3,15 @@
 #include "config.h"
 #include "Common/Options.h"
 #include "DataLayer/Options.h"
-#include "Kmer.h"
 #include <algorithm>
+#include <cassert>
 #include <climits> // for INT_MAX
 #include <getopt.h>
 #include <iostream>
-#include <iterator>
-#include <sstream>
 #include <vector>
+#include "DataBase/Options.h"
+#include <sstream>
+#include <iterator>
 
 using namespace std;
 
@@ -47,7 +48,9 @@ static const char USAGE_MESSAGE[] =
 "      --SS              assemble in strand-specific mode\n"
 "      --no-SS           do not assemble in strand-specific mode\n"
 "  -o, --out=FILE        write the contigs to FILE\n"
-"  -k, --kmer=N          k-mer size\n"
+"  -k, --kmer=N          the length of a k-mer (when -K is not set)\n"
+"                        or the span of a k-mer pair (when -K is set)\n"
+"  -K, --single-kmer=N   the length of a single k-mer in a k-mer pair\n"
 "  -t, --trim-length=N   maximum length of dangling edges to trim\n"
 "  -c, --coverage=FLOAT  remove contigs with mean k-mer coverage\n"
 "                        less than this threshold\n"
@@ -65,6 +68,10 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for database\n"
+"      --strain=NAME     specify strain NAME for database\n"
+"      --species=NAME    specify species NAME for database\n"
 "\n"
 " ABYSS Options: (won't work with ABYSS-P)\n"
 "\n"
@@ -72,7 +79,14 @@ static const char USAGE_MESSAGE[] =
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
-/** k-mer length */
+/** The length of a single k-mer.
+ * When singleKmerSize == 0, paired dBG is disabled [default].
+ * When singleKmerSize == -1, paired dBG is enabled and is an error.
+ * The caller of opt::parse should set singleKmerSize = -1 to enable paired dBG.
+ */
+int singleKmerSize = 0;
+
+/** The length of a k-mer pair, including the gap. */
 int kmerSize = -1;
 int k; // used by Graph
 
@@ -125,13 +139,20 @@ string snpPath;
 /** input FASTA files */
 vector<string> inFiles;
 
-static const char shortopts[] = "b:c:e:E:g:k:mo:Q:q:s:t:v";
+string db;
+vector<string> metaVars;
+
+/** commandline specific to assembly */
+string assemblyCmd;
 
-enum { OPT_HELP = 1, OPT_VERSION, COVERAGE_HIST };
+static const char shortopts[] = "b:c:e:E:g:k:K:mo:Q:q:s:t:v";
+
+enum { OPT_HELP = 1, OPT_VERSION, COVERAGE_HIST, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
 
 static const struct option longopts[] = {
 	{ "out",         required_argument, NULL, 'o' },
 	{ "kmer",        required_argument, NULL, 'k' },
+	{ "single-kmer", required_argument, NULL, 'K' },
 	{ "trim-length", required_argument, NULL, 't' },
 	{ "chastity",    no_argument,       &opt::chastityFilter, 1 },
 	{ "no-chastity", no_argument,       &opt::chastityFilter, 0 },
@@ -155,9 +176,33 @@ static const struct option longopts[] = {
 	{ "verbose",     no_argument,       NULL, 'v' },
 	{ "help",        no_argument,       NULL, OPT_HELP },
 	{ "version",     no_argument,       NULL, OPT_VERSION },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
+int getVvalue()
+{
+	return opt::verbose;
+}
+
+string getUvalue()
+{
+	return opt::db;
+}
+
+string getCommand()
+{
+	return opt::assemblyCmd;
+}
+
+vector<string> getMetaValue()
+{
+	return opt::metaVars;
+}
+
 /** Parse the specified command line. */
 void parse(int argc, char* const* argv)
 {
@@ -168,6 +213,8 @@ void parse(int argc, char* const* argv)
 		sargv << *last;
 	}
 
+	opt::assemblyCmd = sargv.str();
+	opt::metaVars.resize(3);
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -201,6 +248,9 @@ void parse(int argc, char* const* argv)
 				}
 				assert(kMin <= kMax);
 				break;
+			case 'K':
+				arg >> singleKmerSize;
+				break;
 			case COVERAGE_HIST:
 				getline(arg, coverageHistPath);
 				break;
@@ -240,6 +290,18 @@ void parse(int argc, char* const* argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> db;
+				break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0];
+				break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1];
+				break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2];
+				break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -248,6 +310,10 @@ void parse(int argc, char* const* argv)
 		}
 	}
 
+	if (singleKmerSize < 0) {
+		cerr << PROGRAM ": missing -K,--single-kmer option\n";
+		die = true;
+	}
 	if (kmerSize <= 0) {
 		cerr << PROGRAM ": missing -k,--kmer option\n";
 		die = true;
@@ -282,8 +348,6 @@ void parse(int argc, char* const* argv)
 	if (bubbleLen == 0)
 		snpPath.clear();
 
-	Kmer::setLength(kmerSize);
-
 	inFiles.resize(argc - optind);
 	copy(&argv[optind], &argv[argc], inFiles.begin());
 
diff --git a/Assembly/Options.h b/Assembly/Options.h
index db40a1b..fe3b5dd 100644
--- a/Assembly/Options.h
+++ b/Assembly/Options.h
@@ -6,6 +6,7 @@
 
 namespace opt {
 	extern unsigned kmerSize;
+	extern unsigned singleKmerSize;
 	extern unsigned kMin;
 	extern unsigned kMax;
 	extern unsigned kStep;
@@ -23,7 +24,14 @@ namespace opt {
 	extern std::string snpPath;
 	extern std::vector<std::string> inFiles;
 
+	extern std::string db;
+
 	void parse(int argc, char* const* argv);
+	extern std::string assemblyCmd;
+	std::vector<std::string> getMetaValue();
+	int getVvalue();
+	std::string getUvalue();
+	std::string getCommand();
 }
 
 #endif
diff --git a/Common/SeqExt.h b/Assembly/SeqExt.h
similarity index 64%
rename from Common/SeqExt.h
rename to Assembly/SeqExt.h
index 01c0a40..f88d52a 100644
--- a/Common/SeqExt.h
+++ b/Assembly/SeqExt.h
@@ -1,17 +1,32 @@
 #ifndef SEQEXT_H
 #define SEQEXT_H 1
 
-#include "Sequence.h" // for codeToBase
+#include "Common/Options.h" // for opt::colourSpace
+#include "Common/Sequence.h" // for codeToBase
 #include <cassert>
 #include <ostream>
 #include <stdint.h>
 
 static const unsigned NUM_BASES = 4;
 
+/** Return the complement of the specified base.
+ * The reverse of a single base is a no-op.
+ * If the assembly is in colour space, this is a no-op.
+ */
+static inline uint8_t reverseComplement(uint8_t base)
+{
+	return opt::colourSpace ? base : ~base & 0x3;
+}
+
 /** The adjacent vertices of a Kmer. */
 class SeqExt
 {
 	public:
+		typedef uint8_t Symbol;
+
+		/** The number of symbols. */
+		static const unsigned NUM = NUM_BASES;
+
 		SeqExt() : m_record(0) { };
 		explicit SeqExt(uint8_t base) : m_record(1<<base) { };
 
@@ -77,15 +92,24 @@ class SeqExt
 			return m_record > 0 && powerOfTwo;
 		}
 
-		/** Return the complementary adjacency. */
-		SeqExt complement() const;
-		SeqExt operator ~() const { return complement(); }
+		/** Return the complementary adjacency.
+		 * If the assembly is in colour space, this is a no-op.
+		 */
+		SeqExt complement() const
+		{
+			static const uint8_t complements[16] = {
+				0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+				0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
+			};
+			assert(m_record < 1 << NUM);
+			return opt::colourSpace ? *this : mask(complements[m_record]);
+		}
 
 		friend std::ostream& operator <<(std::ostream& out,
 				const SeqExt& o)
 		{
-			assert(o.m_record < 1<<NUM_BASES);
-			for (unsigned i = 0; i < NUM_BASES; ++i)
+			assert(o.m_record < 1 << NUM);
+			for (unsigned i = 0; i  << NUM; ++i)
 				if (o.checkBase(i))
 					out << codeToBase(i);
 			return out;
diff --git a/Assembly/SequenceCollection.cpp b/Assembly/SequenceCollection.cpp
deleted file mode 100644
index 7c2311f..0000000
--- a/Assembly/SequenceCollection.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-#include "config.h"
-#include "SequenceCollection.h"
-#include "Log.h"
-#include "Common/Options.h"
-#include "Assembly/Options.h"
-#include "MemoryUtil.h"
-#include "StringUtil.h" // for toSI
-#include "Timer.h"
-#include <algorithm>
-#include <cassert>
-#include <cstdlib>
-#include <iomanip>
-#include <sstream>
-
-using namespace std;
-
-SequenceCollectionHash::SequenceCollectionHash()
-	: m_seqObserver(NULL), m_adjacencyLoaded(false)
-{
-#if HAVE_GOOGLE_SPARSE_HASH_MAP
-	// sparse_hash_set uses 2.67 bits per element on a 64-bit
-	// architecture and 2 bits per element on a 32-bit architecture.
-	// The number of elements is rounded up to a power of two.
-	if (opt::rank >= 0) {
-		// Make room for 200 million k-mers. Approximately 58 million
-		// 96-mers fit into 2 GB of ram, which results in a hash load
-		// of 0.216, and approximately 116 million 32-mers, which
-		// results in a hash load of 0.432.
-		m_data.rehash(200000000);
-		m_data.min_load_factor(0.2);
-	} else {
-		// Allocate a big hash for a single processor.
-		m_data.rehash(1<<29);
-		m_data.max_load_factor(0.4);
-	}
-#endif
-}
-
-/** sparse_hash_set requires that set_deleted_key()
- * is called before calling erase(). This key cannot
- * be an existing kmer in m_data. This function sets
- * the deleted key and should be called after all
- * data has been loaded.
- */
-void SequenceCollectionHash::setDeletedKey()
-{
-#if HAVE_GOOGLE_SPARSE_HASH_MAP
-	for (SequenceDataHash::iterator it = m_data.begin();
-			it != m_data.end(); it++) {
-		Kmer rc(reverseComplement(it->first));
-		bool isrc;
-		SequenceDataHash::iterator search = find(rc, isrc);
-		// If this is false, we should have a palindrome or we're
-		// doing a SS assembly.
-		if (isrc || search == m_data.end()) {
-			m_data.set_deleted_key(rc);
-			return;
-		}
-	}
-	logger(1) << "error: unable to set deleted key.\n";
-	exit(EXIT_FAILURE);
-#else
-	return;
-#endif
-}
-
-/** Add the specified k-mer to this collection. */
-void SequenceCollectionHash::add(const Kmer& seq, unsigned coverage)
-{
-	bool rc;
-	SequenceCollectionHash::iterator it = find(seq, rc);
-	if (it == m_data.end()) {
-		m_data.insert(make_pair(seq, KmerData(SENSE, coverage)));
-	} else if (coverage > 0) {
-		assert(!rc || !opt::ss);
-		it->second.addMultiplicity(rc ? ANTISENSE : SENSE, coverage);
-	}
-}
-
-/** Clean up by erasing sequences flagged as deleted.
- * @return the number of sequences erased
- */
-size_t SequenceCollectionHash::cleanup()
-{
-	Timer(__func__);
-	size_t count = 0;
-	for (iterator it = m_data.begin(); it != m_data.end();) {
-		if (it->second.deleted()) {
-			m_data.erase(it++);
-			count++;
-		} else
-			++it;
-	}
-	shrink();
-	return count;
-}
-
-/** Return the complement of the specified base.
- * If the assembly is in colour space, this is a no-op.
- */
-static inline uint8_t complementBaseCode(uint8_t base)
-{
-	return opt::colourSpace ? base : ~base & 0x3;
-}
-
-/** Add an edge to this k-mer. */
-bool SequenceCollectionHash::setBaseExtension(
-		const Kmer& kmer, extDirection dir, uint8_t base)
-{
-	bool rc;
-	SequenceCollectionHash::iterator it = find(kmer, rc);
-	if (it == m_data.end())
-		return false;
-	if (opt::ss) {
-		assert(!rc);
-		it->second.setBaseExtension(dir, base);
-	} else {
-		bool palindrome = kmer.isPalindrome();
-		if (!rc || palindrome)
-			it->second.setBaseExtension(dir, base);
-		if (rc || palindrome)
-			it->second.setBaseExtension(!dir, complementBaseCode(base));
-	}
-	return true;
-}
-
-/** Remove the specified extensions from this k-mer. */
-void SequenceCollectionHash::removeExtension(const Kmer& kmer,
-		extDirection dir, SeqExt ext)
-{
-	bool rc;
-	SequenceCollectionHash::iterator it = find(kmer, rc);
-	assert(it != m_data.end());
-	if (opt::ss) {
-		assert(!rc);
-		it->second.removeExtension(dir, ext);
-	} else {
-		bool palindrome = kmer.isPalindrome();
-		if (!rc || palindrome)
-			it->second.removeExtension(dir, ext);
-		if (rc || palindrome)
-			it->second.removeExtension(!dir, ~ext);
-	}
-	notify(*it);
-}
-
-void SequenceCollectionHash::setFlag(const Kmer& key, SeqFlag flag)
-{
-	bool rc;
-	SequenceCollectionHash::iterator it = find(key, rc);
-	assert(it != m_data.end());
-	it->second.setFlag(rc ? complement(flag) : flag);
-}
-
-void SequenceCollectionHash::wipeFlag(SeqFlag flag)
-{
-	for (SequenceCollectionHash::iterator it = m_data.begin();
-			it != m_data.end(); ++it)
-		it->second.clearFlag(flag);
-}
-
-/** Print the load of the hash table. */
-void SequenceCollectionHash::printLoad() const
-{
-	size_t size = m_data.size();
-	size_t buckets = m_data.bucket_count();
-	logger(1) << "Hash load: " << size << " / " << buckets << " = "
-		<< setprecision(3) << (float)size / buckets
-		<< " using " << toSI(getMemoryUsage()) << "B" << endl;
-}
-
-/** Return an iterator pointing to the specified k-mer or its
- * reverse complement. Return in rc whether the sequence is reversed.
- */
-SequenceCollectionHash::iterator SequenceCollectionHash::find(
-		const Kmer& key, bool& rc)
-{
-	SequenceCollectionHash::iterator it = find(key);
-	if (opt::ss || it != m_data.end()) {
-		rc = false;
-		return it;
-	} else {
-		rc = true;
-		return find(reverseComplement(key));
-	}
-}
-
-/** Return an iterator pointing to the specified k-mer or its
- * reverse complement. Return in rc whether the sequence is reversed.
- */
-SequenceCollectionHash::const_iterator SequenceCollectionHash::find(
-		const Kmer& key, bool& rc) const
-{
-	SequenceCollectionHash::const_iterator it = find(key);
-	if (opt::ss || it != m_data.end()) {
-		rc = false;
-		return it;
-	} else {
-		rc = true;
-		return find(reverseComplement(key));
-	}
-}
-
-/** Return the sequence and data of the specified key.
- * The key sequence may not contain data. The returned sequence will
- * contain data.
- */
-const SequenceCollectionHash::value_type& SequenceCollectionHash::
-getSeqAndData(const Kmer& key) const
-{
-	bool rc;
-	SequenceCollectionHash::const_iterator it = find(key, rc);
-	// rc should not be ignored. This seems quite dubious.
-	// The edges of this k-mer should be complemented.
-	assert(it != m_data.end());
-	return *it;
-}
-
-/** Return the data of the specified key. */
-bool SequenceCollectionHash::getSeqData(const Kmer& key,
-		ExtensionRecord& extRecord, int& multiplicity) const
-{
-	bool rc;
-	SequenceCollectionHash::const_iterator it = find(key, rc);
-	assert(!rc || !opt::ss);
-	if (it == m_data.end())
-		return false;
-	const KmerData data = it->second;
-	extRecord = rc ? ~data.extension() : data.extension();
-	multiplicity = data.getMultiplicity();
-	return true;
-}
-
-#include <cstdio>
-
-/** Write this collection to disk.
- * @param path does not include the extension
- */
-void SequenceCollectionHash::store(const char* path)
-{
-	assert(path != NULL);
-#if HAVE_GOOGLE_SPARSE_HASH_MAP
-	ostringstream s;
-	s << path;
-	if (opt::rank >= 0)
-		s << '-' << setfill('0') << setw(3) << opt::rank;
-	s << ".kmer";
-	FILE* f = fopen(s.str().c_str(), "w");
-	if (f == NULL) {
-		perror(s.str().c_str());
-		exit(EXIT_FAILURE);
-	}
-	shrink();
-	m_data.write_metadata(f);
-	m_data.write_nopointer_data(f);
-	fclose(f);
-#else
-	// Not supported.
-	assert(false);
-	exit(EXIT_FAILURE);
-#endif
-}
-
-/** Load this collection from disk. */
-void SequenceCollectionHash::load(const char* path)
-{
-#if HAVE_GOOGLE_SPARSE_HASH_MAP
-	FILE* f = fopen(path, "r");
-	if (f == NULL) {
-		perror(path);
-		exit(EXIT_FAILURE);
-	}
-	m_data.read_metadata(f);
-	m_data.read_nopointer_data(f);
-	fclose(f);
-	m_adjacencyLoaded = true;
-#else
-	(void)path;
-	// Not supported.
-	assert(false);
-	exit(EXIT_FAILURE);
-#endif
-}
-
-/** Indicate that this is a colour-space collection. */
-void SequenceCollectionHash::setColourSpace(bool flag)
-{
-	if (!m_data.empty())
-		assert(opt::colourSpace == flag);
-	opt::colourSpace = flag;
-}
diff --git a/Assembly/SequenceCollection.h b/Assembly/SequenceCollection.h
index d83d20e..62b1c44 100644
--- a/Assembly/SequenceCollection.h
+++ b/Assembly/SequenceCollection.h
@@ -1,334 +1,25 @@
-#ifndef SEQUENCECOLLECTION_H
-#define SEQUENCECOLLECTION_H 1
-
-#include "Graph/Properties.h"
-#include "ISequenceCollection.h"
-#include <boost/graph/graph_traits.hpp>
-#include <cassert>
-#include <utility>
-
-using boost::graph_traits;
-
-/** A map of Kmer to KmerData. */
-class SequenceCollectionHash : public ISequenceCollection
-{
-	public:
-		typedef SequenceDataHash::key_type key_type;
-		typedef SequenceDataHash::mapped_type mapped_type;
-		typedef SequenceDataHash::value_type value_type;
-		typedef mapped_type vertex_property_type;
-		typedef no_property edge_property_type;
-
-		SequenceCollectionHash();
-
-		void add(const Kmer& seq, unsigned coverage = 1);
-
-		/** Remove the specified sequence if it exists. */
-		void remove(const Kmer& seq)
-		{
-			setFlag(seq, SF_DELETE);
-		}
-
-		// Clean up by erasing sequences flagged as deleted.
-		size_t cleanup();
-
-		/** Shrink the hash table. */
-		void shrink() {
-			m_data.rehash(0);
-			printLoad();
-		}
-
-		// Print the load of the hash table.
-		void printLoad() const;
-
-		// Set flag for sequence seq
-		void setFlag(const Kmer& seq, SeqFlag flag);
-
-		// Clear the specified flag from every sequence in the
-		// collection.
-		void wipeFlag(SeqFlag flag);
-
-		bool setBaseExtension(const Kmer& seq, extDirection dir,
-				uint8_t base);
-		void removeExtension(const Kmer& seq,
-				extDirection dir, SeqExt ext);
-
-		// get the extensions of a sequence
-		bool getSeqData(const Kmer& seq,
-				ExtensionRecord& extRecord, int& multiplicity) const;
-
-		const value_type& getSeqAndData(const Kmer& key) const;
-
-		/** Return the data associated with the specified key. */
-		const mapped_type operator[](const key_type& key) const
-		{
-			bool rc;
-			SequenceCollectionHash::const_iterator it = find(key, rc);
-			assert(it != m_data.end());
-			return rc ? ~it->second : it->second;
-		}
-
-		iterator begin() { return m_data.begin(); }
-		const_iterator begin() const { return m_data.begin(); }
-		iterator end() { return m_data.end(); }
-		const_iterator end() const { return m_data.end(); }
-
-		/** Return true if this collection is empty. */
-		bool empty() const { return m_data.empty(); }
-
-		/** Return the number of sequences in this collection. */
-		size_t size() const { return m_data.size(); }
-
-		// Not a network sequence collection. Nothing to do.
-		size_t pumpNetwork() { return 0; }
-
-		/** Attach the specified observer. */
-		void attach(SeqObserver f)
-		{
-			assert(m_seqObserver == NULL);
-			m_seqObserver = f;
-		}
-
-		/** Detach the specified observer. */
-		void detach(SeqObserver f)
-		{
-			assert(m_seqObserver == f);
-			(void)f;
-			m_seqObserver = NULL;
-		}
-
-		void load(const char *path);
-		void store(const char* path);
-		bool isAdjacencyLoaded() const { return m_adjacencyLoaded; }
-		void setColourSpace(bool flag);
-		void setDeletedKey();
-
-	private:
-		iterator find(const Kmer& key) { return m_data.find(key); }
-		const_iterator find(const Kmer& key) const
-		{
-			return m_data.find(key);
-		}
-
-		iterator find(const Kmer& key, bool& rc);
-		const_iterator find(const Kmer& key, bool& rc) const;
-
-		/** Call the observers of the specified sequence. */
-		void notify(const value_type& seq)
-		{
-			if (m_seqObserver != NULL)
-				m_seqObserver(this, seq);
-		}
-
-		/** The underlying collection. */
-		SequenceDataHash m_data;
-
-		/** The observers. Only a single observer is implemented.*/
-		SeqObserver m_seqObserver;
-
-		/** Whether adjacency information has been loaded. */
-		bool m_adjacencyLoaded;
-};
-
-// Graph
-
-namespace boost {
-
-template <>
-struct graph_traits<SequenceCollectionHash> {
-	// Graph
-	typedef SequenceCollectionHash::key_type vertex_descriptor;
-	typedef boost::directed_tag directed_category;
-	struct traversal_category
-		: boost::adjacency_graph_tag, boost::vertex_list_graph_tag
-		{ };
-	typedef boost::disallow_parallel_edge_tag edge_parallel_category;
-
-	// IncidenceGraph
-	typedef std::pair<vertex_descriptor, vertex_descriptor>
-		edge_descriptor;
-	typedef unsigned degree_size_type;
-	typedef void out_edge_iterator;
-
-	// BidirectionalGraph
-	typedef void in_edge_iterator;
-
-	// VertexListGraph
-	typedef size_t vertices_size_type;
-
-	// EdgeListGraph
-	typedef void edge_iterator;
-	typedef void edges_size_type;
-
-// AdjacencyGraph
-/** Iterate through the adjacent vertices of a vertex. */
-struct adjacency_iterator
-	: public std::iterator<std::input_iterator_tag, vertex_descriptor>
-{
-	/** Skip to the next edge that is present. */
-	void next()
-	{
-		for (; m_i < NUM_BASES && !m_adj.checkBase(m_i); m_i++) {
-		}
-		if (m_i < NUM_BASES)
-			m_v.setLastBase(SENSE, m_i);
-	}
-
-  public:
-	adjacency_iterator() : m_i(NUM_BASES) { }
-
-	adjacency_iterator(
-			vertex_descriptor u, SeqExt adj)
-		: m_v(u), m_adj(adj), m_i(0)
-	{
-		m_v.shift(SENSE);
-		next();
-	}
-
-	const vertex_descriptor& operator*() const
-	{
-		assert(m_i < NUM_BASES);
-		return m_v;
-	}
-
-	bool operator==(const adjacency_iterator& it) const
-	{
-		return m_i == it.m_i;
-	}
-
-	bool operator!=(const adjacency_iterator& it) const
-	{
-		return !(*this == it);
-	}
-
-	adjacency_iterator& operator++()
-	{
-		assert(m_i < NUM_BASES);
-		++m_i;
-		next();
-		return *this;
-	}
-
-  private:
-	vertex_descriptor m_v;
-	SeqExt m_adj;
-	short unsigned m_i;
-}; // adjacency_iterator
-
-// VertexListGraph
-/** Iterate through the vertices of this graph. */
-struct vertex_iterator
-	: public std::iterator<std::input_iterator_tag, vertex_descriptor>
-{
-	typedef SequenceCollectionHash::const_iterator It;
-
-  public:
-	vertex_iterator(const It& it) : m_it(it), m_sense(false) { }
-
-	const vertex_descriptor operator*() const
-	{
-		return m_sense ? reverseComplement(m_it->first) : m_it->first;
-	}
-
-	bool operator==(const vertex_iterator& it) const
-	{
-		return m_it == it.m_it && m_sense == it.m_sense;
-	}
-
-	bool operator!=(const vertex_iterator& it) const
-	{
-		return !(*this == it);
-	}
-
-	vertex_iterator& operator++()
-	{
-		if (m_sense) {
-			++m_it;
-			m_sense = false;
-		} else
-			m_sense = true;
-		return *this;
-	}
-
-  private:
-	It m_it;
-	bool m_sense;
-}; // vertex_iterator
-
-}; // graph_traits<SequenceCollectionHash>
-
-} // namespace boost
-
-// IncidenceGraph
-
-static inline
-graph_traits<SequenceCollectionHash>::degree_size_type
-out_degree(
-		graph_traits<SequenceCollectionHash>::vertex_descriptor u,
-		const SequenceCollectionHash& g)
-{
-	return g[u].getExtension(SENSE).outDegree();
-}
-
-// BidirectionalGraph
-
-static inline
-graph_traits<SequenceCollectionHash>::degree_size_type
-in_degree(graph_traits<SequenceCollectionHash>::vertex_descriptor u,
-		const SequenceCollectionHash& g)
-{
-	return g[u].getExtension(ANTISENSE).outDegree();
-}
-
-// AdjacencyGraph
-
-static inline
-std::pair<graph_traits<SequenceCollectionHash>::adjacency_iterator,
-	graph_traits<SequenceCollectionHash>::adjacency_iterator>
-adjacent_vertices(
-		graph_traits<SequenceCollectionHash>::vertex_descriptor u,
-		const SequenceCollectionHash& g)
-{
-	typedef graph_traits<SequenceCollectionHash>::adjacency_iterator
-		adjacency_iterator;
-	SeqExt adj = g[u].getExtension(SENSE);
-	return std::make_pair(adjacency_iterator(u, adj),
-			adjacency_iterator());
-}
-
-// VertexListGraph
-
-static inline
-std::pair<graph_traits<SequenceCollectionHash>::vertex_iterator,
-	graph_traits<SequenceCollectionHash>::vertex_iterator>
-vertices(const SequenceCollectionHash& g)
-{
-	return std::make_pair(g.begin(), g.end());
-}
-
-// PropertyGraph
-
-/** Return the reverse complement of the specified k-mer. */
-static inline
-graph_traits<SequenceCollectionHash>::vertex_descriptor
-get(vertex_complement_t, const SequenceCollectionHash&,
-		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
-{
-	return reverseComplement(u);
-}
-
-static inline
-bool get(vertex_removed_t, const SequenceCollectionHash& g,
-		graph_traits<SequenceCollectionHash>::vertex_descriptor u)
-{
-	return g.getSeqAndData(u).second.deleted();
-}
+#ifndef ASSEMBLY_SEQUENCECOLLECTION_H
+#define ASSEMBLY_SEQUENCECOLLECTION_H 1
+
+#include "config.h"
+#include "SeqExt.h"
+#include "VertexData.h"
+#include "Common/Kmer.h"
+
+typedef VertexData<uint8_t, SeqExt> KmerData;
+typedef KmerData::SymbolSetPair ExtensionRecord;
+
+#if HAVE_GOOGLE_SPARSE_HASH_MAP
+# include <google/sparse_hash_map>
+typedef google::sparse_hash_map<Kmer, KmerData, hash<Kmer> >
+	SequenceDataHash;
+#else
+# include "Common/UnorderedMap.h"
+typedef unordered_map<Kmer, KmerData, hash<Kmer> >
+	SequenceDataHash;
+#endif
 
-static inline
-no_property get(edge_bundle_t, const SequenceCollectionHash&,
-		graph_traits<SequenceCollectionHash>::edge_descriptor)
-{
-	return no_property();
-}
+#include "Assembly/DBG.h"
+#include "Assembly/BranchRecord.h"
 
 #endif
diff --git a/Assembly/SplitAlgorithm.h b/Assembly/SplitAlgorithm.h
new file mode 100644
index 0000000..9f9db7f
--- /dev/null
+++ b/Assembly/SplitAlgorithm.h
@@ -0,0 +1,97 @@
+#ifndef ASSEMBLY_SPLITALGORITHM_H
+#define ASSEMBLY_SPLITALGORITHM_H 1
+
+namespace AssemblyAlgorithms {
+
+/** Mark the specified vertex and its neighbours.
+ * @return the number of marked edges
+ */
+template <typename Graph>
+size_t markNeighbours(Graph* g,
+		const typename Graph::value_type& u, extDirection sense)
+{
+	typedef typename graph_traits<Graph>::vertex_descriptor V;
+	typedef typename std::vector<V> Vector;
+
+	Vector adj;
+	generateSequencesFromExtension(u.first, sense,
+			u.second.getExtension(sense), adj);
+	for (typename Vector::iterator v = adj.begin(); v != adj.end(); ++v)
+		g->mark(*v, !sense);
+	return adj.size();
+}
+
+/** Mark ambiguous branches and branches from palindromes for removal.
+ * @return the number of branches marked
+ */
+template <typename Graph>
+size_t markAmbiguous(Graph* g)
+{
+	typedef typename Graph::iterator iterator;
+
+	Timer timer(__func__);
+	size_t progress = 0;
+	size_t countv = 0, counte = 0;
+	for (iterator it = g->begin(); it != g->end(); ++it) {
+		if (it->second.deleted())
+			continue;
+
+		if (++progress % 1000000 == 0)
+			logger(1) << "Splitting: " << progress << '\n';
+
+		if (!opt::ss && it->first.isPalindrome()) {
+			countv += 2;
+			g->mark(it->first);
+			counte += markNeighbours(g, *it, SENSE);
+		} else {
+			for (extDirection sense = SENSE;
+					sense <= ANTISENSE; ++sense) {
+				if (it->second.getExtension(sense).isAmbiguous()
+						|| (!opt::ss && it->first.isPalindrome(sense))) {
+					countv++;
+					g->mark(it->first, sense);
+					counte += markNeighbours(g, *it, sense);
+				}
+			}
+		}
+
+		g->pumpNetwork();
+	}
+	tempCounter[5] = countv;
+	logger(0) << "Marked " << counte << " edges of " << countv
+		<< " ambiguous vertices." << std::endl;
+
+	return countv;
+}
+
+/** Remove the edges of marked and deleted vertices.
+ * @return the number of branches removed
+ */
+template <typename Graph>
+size_t splitAmbiguous(Graph* pSC)
+{
+	typedef typename Graph::iterator iterator;
+
+	Timer timer(__func__);
+	size_t count = 0;
+	for (iterator it = pSC->begin();
+			it != pSC->end(); ++it) {
+		if (!it->second.deleted())
+			continue;
+		for (extDirection sense = SENSE;
+				sense <= ANTISENSE; ++sense) {
+			if (it->second.marked(sense)) {
+				removeExtensionsToSequence(pSC, *it, sense);
+				count++;
+			}
+		}
+		pSC->pumpNetwork();
+	}
+	tempCounter[7] += count;
+	logger(0) << "Split " << count << " ambigiuous branches.\n";
+	return count;
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/TrimAlgorithm.h b/Assembly/TrimAlgorithm.h
new file mode 100644
index 0000000..2873c1a
--- /dev/null
+++ b/Assembly/TrimAlgorithm.h
@@ -0,0 +1,203 @@
+#ifndef ASSEMBLY_TRIMALGORITHM_H
+#define ASSEMBLY_TRIMALGORITHM_H 1
+
+namespace AssemblyAlgorithms {
+
+template <typename Graph>
+bool processTerminatedBranchTrim(Graph* seqCollection, BranchRecord& branch);
+
+static inline
+size_t trimSequences(SequenceCollectionHash* seqCollection,
+		unsigned maxBranchCull);
+
+/** Trimming driver function */
+static inline
+void performTrim(SequenceCollectionHash* seqCollection)
+{
+	if (opt::trimLen == 0)
+		return;
+	unsigned rounds = 0;
+	size_t total = 0;
+	for (unsigned trim = 1; trim < opt::trimLen; trim *= 2) {
+		rounds++;
+		total += trimSequences(seqCollection, trim);
+	}
+	size_t count;
+	while ((count = trimSequences(seqCollection, opt::trimLen)) > 0) {
+		rounds++;
+		total += count;
+	}
+	std::cout << "Pruned " << total << " tips in "
+		<< rounds << " rounds.\n";
+	tempCounter[1] += total;
+	tempCounter[2] = rounds;
+}
+
+/** Prune tips shorter than maxBranchCull. */
+static inline
+size_t trimSequences(SequenceCollectionHash* seqCollection,
+		unsigned maxBranchCull)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	typedef Graph::SymbolSetPair SymbolSetPair;
+
+	Timer timer("TrimSequences");
+	std::cout << "Pruning tips shorter than "
+		<< maxBranchCull << " bp...\n";
+	size_t numBranchesRemoved = 0;
+
+	for (Graph::iterator iter = seqCollection->begin();
+			iter != seqCollection->end(); ++iter) {
+		if (iter->second.deleted())
+			continue;
+
+		extDirection dir;
+		// dir will be set to the trimming direction if the sequence
+		// can be trimmed.
+		SeqContiguity status = checkSeqContiguity(*iter, dir);
+
+		if (status == SC_CONTIGUOUS)
+			continue;
+		else if(status == SC_ISLAND)
+		{
+			// remove this sequence, it has no extensions
+			seqCollection->mark(iter->first);
+			numBranchesRemoved++;
+			continue;
+		}
+
+		BranchRecord currBranch(dir);
+		V currSeq = iter->first;
+		while(currBranch.isActive())
+		{
+			SymbolSetPair extRec;
+			int multiplicity = -1;
+			bool success = seqCollection->getSeqData(
+					currSeq, extRec, multiplicity);
+			assert(success);
+			(void)success;
+			processLinearExtensionForBranch(currBranch,
+					currSeq, extRec, multiplicity, maxBranchCull);
+		}
+
+		// The branch has ended check it for removal, returns true if
+		// it was removed.
+		if(processTerminatedBranchTrim(seqCollection, currBranch))
+		{
+			numBranchesRemoved++;
+		}
+		seqCollection->pumpNetwork();
+	}
+
+	size_t numSweeped = removeMarked(seqCollection);
+
+	if (numBranchesRemoved > 0)
+		logger(0) << "Pruned " << numSweeped << " k-mer in "
+			<< numBranchesRemoved << " tips.\n";
+	return numBranchesRemoved;
+}
+
+/** Extend this branch. */
+static inline
+bool extendBranch(BranchRecord& branch,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor& kmer,
+		SequenceCollectionHash::SymbolSet ext)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef graph_traits<Graph>::vertex_descriptor V;
+	
+	if (!ext.hasExtension()) {
+		branch.terminate(BS_NOEXT);
+		return false;
+	} else if (ext.isAmbiguous()) {
+		branch.terminate(BS_AMBI_SAME);
+		return false;
+	} else {
+		std::vector<V> adj;
+		generateSequencesFromExtension(kmer, branch.getDirection(),
+				ext, adj);
+		assert(adj.size() == 1);
+		kmer = adj.front();
+		return true;
+	}
+}
+
+/**
+ * Process the extension for this branch for the trimming algorithm
+ * CurrSeq is the current sequence being inspected (the next member to
+ * be added to the branch). The extension record is the extensions of
+ * that sequence and multiplicity is the number of times that kmer
+ * appears in the data set. After processing currSeq is unchanged if
+ * the branch is no longer active or else it is the generated
+ * extension. If the parameter addKmer is true, add the k-mer to the
+ * branch.
+ */
+static inline bool
+processLinearExtensionForBranch(BranchRecord& branch,
+		graph_traits<SequenceCollectionHash>::vertex_descriptor& currSeq,
+		SequenceCollectionHash::SymbolSetPair extensions,
+		int multiplicity,
+		unsigned maxLength, bool addKmer)
+{
+	typedef SequenceCollectionHash Graph;
+	typedef vertex_bundle_type<Graph>::type VP;
+
+	/** Stop contig assembly at palindromes. */
+	const bool stopAtPalindromes = !opt::ss && maxLength == UINT_MAX;
+
+	extDirection dir = branch.getDirection();
+	if (branch.isTooLong(maxLength)) {
+		// Too long.
+		branch.terminate(BS_TOO_LONG);
+		return false;
+	} else if (extensions.dir[!dir].isAmbiguous()) {
+		// Ambiguous.
+		branch.terminate(BS_AMBI_OPP);
+		return false;
+	} else if (stopAtPalindromes && currSeq.isPalindrome()) {
+		// Palindrome.
+		branch.terminate(BS_AMBI_SAME);
+		return false;
+	}
+
+	if (addKmer)
+		branch.push_back(std::make_pair(currSeq,
+					VP(multiplicity, extensions)));
+
+	if (branch.isTooLong(maxLength)) {
+		// Too long.
+		branch.terminate(BS_TOO_LONG);
+		return false;
+	} else if (stopAtPalindromes && currSeq.isPalindrome(dir)) {
+		// Palindrome.
+		branch.terminate(BS_AMBI_SAME);
+		return false;
+	}
+
+	return extendBranch(branch, currSeq, extensions.dir[dir]);
+}
+
+/** Trim the specified branch if it meets trimming criteria.
+ * @return true if the specified branch was trimmed
+ */
+template <typename Graph>
+bool processTerminatedBranchTrim(Graph* seqCollection, BranchRecord& branch)
+{
+	assert(!branch.isActive());
+	assert(!branch.empty());
+	if (branch.getState() == BS_NOEXT
+			|| branch.getState() == BS_AMBI_OPP) {
+		logger(5) << "Pruning " << branch.size() << ' '
+			<< branch.front().first << '\n';
+		for (BranchRecord::iterator it = branch.begin();
+				it != branch.end(); ++it)
+			seqCollection->mark(it->first);
+		return true;
+	} else
+		return false;
+}
+
+} // namespace AssemblyAlgorithms
+
+#endif
diff --git a/Assembly/KmerData.h b/Assembly/VertexData.h
similarity index 69%
rename from Assembly/KmerData.h
rename to Assembly/VertexData.h
index 6a38980..da3e5bc 100644
--- a/Assembly/KmerData.h
+++ b/Assembly/VertexData.h
@@ -1,8 +1,7 @@
-#ifndef KMERDATA_H
-#define KMERDATA_H 1
+#ifndef ASSEMBLY_VERTEXDATA_H
+#define ASSEMBLY_VERTEXDATA_H 1
 
-#include "Sense.h"
-#include "SeqExt.h"
+#include "Common/Sense.h"
 #include <cassert>
 #include <stdint.h>
 #include <ostream>
@@ -26,43 +25,47 @@ static inline SeqFlag complement(SeqFlag flag)
 	return SeqFlag(out);
 }
 
-/** A pair of SeqExt; one for out edges and one for in edges. */
-struct ExtensionRecord
-{
-	SeqExt dir[2];
-	ExtensionRecord operator ~() const
-	{
-		ExtensionRecord o;
-		o.dir[SENSE] = dir[ANTISENSE].complement();
-		o.dir[ANTISENSE] = dir[SENSE].complement();
-		return o;
-	}
-};
-
-/**
- * The data associated with a Kmer, including its coverage, flags
- * and adjacent Kmer.
- */
-class KmerData
+/** Vertex properties of a de Bruijn Graph vertex. */
+template <typename S, typename Set>
+class VertexData
 {
 /** Maximum value of k-mer coverage. */
 #define COVERAGE_MAX 32767U
 
   public:
-	KmerData() : m_flags(0)
+	/** A symbol, such as a nucleotide or amino acid. */
+	typedef S Symbol;
+
+	/** A set of symbols. */
+	typedef Set SymbolSet;
+
+	/** A pair of edge sets; one for out edges and one for in edges. */
+	struct SymbolSetPair
+	{
+		SymbolSet dir[2];
+		SymbolSetPair complement() const
+		{
+			SymbolSetPair o;
+			o.dir[SENSE] = dir[ANTISENSE].complement();
+			o.dir[ANTISENSE] = dir[SENSE].complement();
+			return o;
+		}
+	};
+
+	VertexData() : m_flags(0)
 	{
 		m_multiplicity[SENSE] = 1;
 		m_multiplicity[ANTISENSE] = 0;
 	}
 
-	KmerData(extDirection dir, unsigned multiplicity) : m_flags(0)
+	VertexData(extDirection dir, unsigned multiplicity) : m_flags(0)
 	{
 		assert(multiplicity <= COVERAGE_MAX);
 		m_multiplicity[dir] = multiplicity;
 		m_multiplicity[!dir] = 0;
 	}
 
-	KmerData(unsigned multiplicity, ExtensionRecord ext)
+	VertexData(unsigned multiplicity, SymbolSetPair ext)
 		: m_flags(0), m_ext(ext)
 	{
 		setMultiplicity(multiplicity);
@@ -115,19 +118,19 @@ class KmerData
 		return isFlagSet(SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE));
 	}
 
-	ExtensionRecord extension() const { return m_ext; }
+	SymbolSetPair extension() const { return m_ext; }
 
-	SeqExt getExtension(extDirection dir) const
+	SymbolSet getExtension(extDirection dir) const
 	{
 		return m_ext.dir[dir];
 	}
 
-	void setBaseExtension(extDirection dir, uint8_t base)
+	void setBaseExtension(extDirection dir, Symbol x)
 	{
-		m_ext.dir[dir].setBase(base);
+		m_ext.dir[dir].setBase(x);
 	}
 
-	void removeExtension(extDirection dir, SeqExt ext)
+	void removeExtension(extDirection dir, SymbolSet ext)
 	{
 		m_ext.dir[dir].clear(ext);
 	}
@@ -143,27 +146,27 @@ class KmerData
 	}
 
 	/** Return the complement of this data. */
-	KmerData operator~() const
+	VertexData operator~() const
 	{
-		KmerData o;
+		VertexData o;
 		o.m_flags = complement(SeqFlag(m_flags));
 		o.m_multiplicity[0] = m_multiplicity[1];
 		o.m_multiplicity[1] = m_multiplicity[0];
-		o.m_ext = ~m_ext;
+		o.m_ext = m_ext.complement();
 		return o;
 	}
 
 	friend std::ostream& operator<<(
-			std::ostream& out, const KmerData& o)
+			std::ostream& out, const VertexData& o)
 	{
 		return out << "C="
 			<< o.m_multiplicity[0] + o.m_multiplicity[1];
 	}
 
-  protected:
+  private:
 	uint8_t m_flags;
 	uint16_t m_multiplicity[2];
-	ExtensionRecord m_ext;
+	SymbolSetPair m_ext;
 };
 
 #endif
diff --git a/Bloom/Bloom.h b/Bloom/Bloom.h
index 4fd018b..3b1c6fe 100644
--- a/Bloom/Bloom.h
+++ b/Bloom/Bloom.h
@@ -23,6 +23,7 @@
 #include "Common/IOUtil.h"
 #include "DataLayer/FastaReader.h"
 #include <iostream>
+#include <vector>
 
 #if _OPENMP
 # include <omp.h>
@@ -41,27 +42,10 @@ namespace Bloom {
 		size_t endBitPos;
 	};
 
-	/**
-	 * Number of seqs to read in during each iteration of an
-	 * OpenMP bloom filter loading task
-	 */
-	static const unsigned LOAD_CHUNK_SIZE = 1000;
 	/** Print a progress message after loading this many seqs */
 	static const unsigned LOAD_PROGRESS_STEP = 100000;
 	/** file format version number */
 	static const unsigned BLOOM_VERSION = 2;
-	/** I/O buffer size when reading/writing bloom filter files */
-	static const unsigned long IO_BUFFER_SIZE = 32*1024;
-
-	/**
-	 * How to treat existing bits in the bloom filter when
-	 * reading in new data.
-	 */
-	enum LoadType {
-		LOAD_OVERWRITE,
-		LOAD_UNION,
-		LOAD_INTERSECT
-	};
 
 	/** Return the hash value of this object. */
 	inline static size_t hash(const key_type& key)
@@ -91,27 +75,31 @@ namespace Bloom {
 	/** Load a sequence file into a bloom filter */
 	template <typename BF>
 	inline static void loadFile(BF& bloomFilter, unsigned k, const std::string& path,
-			bool verbose = false)
+			bool verbose = false, size_t taskIOBufferSize = 100000)
 	{
 		assert(!path.empty());
 		if (verbose)
 			std::cerr << "Reading `" << path << "'...\n";
 		FastaReader in(path.c_str(), FastaReader::FOLD_CASE);
 		uint64_t count = 0;
-		const size_t CHUNK_SIZE = 1000;
 #pragma omp parallel
-		for (std::string seq[CHUNK_SIZE];;) {
+		for (std::vector<std::string> buffer(taskIOBufferSize);;) {
+			buffer.clear();
+			size_t bufferSize = 0;
 			bool good = true;
-			size_t i = 0;
 #pragma omp critical(in)
-			for (; good && i < CHUNK_SIZE; i++)
-				good = in >> seq[i];
-			if (!good)
-				i--;
-			if (i == 0)
+			for (; good && bufferSize < taskIOBufferSize;) {
+				std::string seq;
+				good = in >> seq;
+				if (good) {
+					buffer.push_back(seq);
+					bufferSize += seq.length();
+				}
+			}
+			if (buffer.size() == 0)
 				break;
-			for (size_t j = 0; j < i; j++) {
-				loadSeq(bloomFilter, k, seq[j]);
+			for (size_t j = 0; j < buffer.size(); j++) {
+				loadSeq(bloomFilter, k, buffer.at(j));
 				if (verbose)
 #pragma omp critical(cerr)
 				{
@@ -144,52 +132,19 @@ namespace Bloom {
 		}
 	}
 
-	/** Write a bloom filter to a stream */
-	template <typename BF>
-	static void write(const BF& bloomFilter, size_t fullBloomSize,
-		size_t startBitPos, size_t endBitPos, std::ostream& out)
+	inline static void writeHeader(std::ostream& out, const FileHeader& header)
 	{
-
-		// file header
+		(void)writeHeader;
 
 		out << BLOOM_VERSION << '\n';
 		assert(out);
 		out << Kmer::length() << '\n';
 		assert(out);
-		out << fullBloomSize
-			<< '\t' << startBitPos
-			<< '\t' << endBitPos
+		out << header.fullBloomSize
+			<< '\t' << header.startBitPos
+			<< '\t' << header.endBitPos
 			<< '\n';
 		assert(out);
-
-		// bloom filter bits
-
-		size_t bits = endBitPos - startBitPos + 1;
-		size_t bytes = (bits + 7) / 8;
-		char buf[IO_BUFFER_SIZE];
-		for (size_t i = 0, j = 0; i < bytes;) {
-			size_t writeSize = std::min(IO_BUFFER_SIZE, bytes - i);
-			for (size_t k = 0; k < writeSize; k++) {
-				buf[k] = 0;
-				for (unsigned l = 0; l < 8; l++, j++) {
-					buf[k] <<= 1;
-					if (j < bits && bloomFilter[j]) {
-						buf[k] |= 1;
-					}
-				}
-			}
-			out.write(buf, writeSize);
-			assert(out);
-			i += writeSize;
-		}
-	}
-
-	/** Write a bloom filter to a stream */
-	template <typename BF>
-	static void write(const BF& bloomFilter, std::ostream& out)
-	{
-		Bloom::write(bloomFilter, bloomFilter.size(), 0,
-			bloomFilter.size() - 1, out);
 	}
 
 	FileHeader readHeader(std::istream& in)
@@ -233,81 +188,6 @@ namespace Bloom {
 		return header;
 	}
 
-	/** Read the bloom filter bit array from a stream */
-	template <typename BF>
-	static void readData(BF& bloomFilter, const Bloom::FileHeader& header,
-			std::istream& in, LoadType loadType = LOAD_OVERWRITE,
-			unsigned shrinkFactor = 1)
-	{
-
-		// shrink factor allows building a smaller
-		// bloom filter from a larger one
-
-		size_t size = header.fullBloomSize;
-
-		if (size % shrinkFactor != 0) {
-			std::cerr << "error: the number of bits in the original bloom "
-				"filter must be evenly divisible by the shrink factor (`"
-				<< shrinkFactor << "')\n";
-			exit(EXIT_FAILURE);
-		}
-
-		size /= shrinkFactor;
-
-		if((loadType == LOAD_UNION || loadType == LOAD_INTERSECT)
-			&& size != bloomFilter.size()) {
-			std::cerr << "error: can't union/intersect two bloom filters "
-				"with different sizes.\n";
-			exit(EXIT_FAILURE);
-		} else {
-			bloomFilter.resize(size);
-		}
-
-		// read bit vector
-
-		if (loadType == LOAD_OVERWRITE)
-			bloomFilter.reset();
-
-		size_t offset = header.startBitPos;
-		size_t bits = header.endBitPos - header.startBitPos + 1;
-		size_t bytes = (bits + 7) / 8;
-
-		char buf[IO_BUFFER_SIZE];
-		for (size_t i = 0, j = offset; i < bytes; ) {
-			size_t readSize = std::min(IO_BUFFER_SIZE, bytes - i);
-			in.read(buf, readSize);
-			assert(in);
-			for (size_t k = 0; k < readSize; k++) {
-				for (unsigned l = 0; l < 8 && j < offset + bits; l++, j++) {
-					bool bit = buf[k] & (1 << (7 - l));
-					size_t index = j % size;
-					switch (loadType)
-					{
-					case LOAD_OVERWRITE:
-					case LOAD_UNION:
-						bloomFilter[index] |= bit;
-						break;
-					case LOAD_INTERSECT:
-						bloomFilter[index] &= bit;
-						break;
-					}
-				}
-			}
-			i += readSize;
-		}
-
-	}
-
-	/** Read a bloom filter from a stream */
-	template <typename BF>
-	static void read(BF& bloomFilter, std::istream& in,
-			LoadType loadType = LOAD_OVERWRITE,
-			unsigned shrinkFactor = 1)
-	{
-		FileHeader header = readHeader(in);
-		readData(bloomFilter, header, in, loadType, shrinkFactor);
-	}
-
 	//TODO: Bloom filter calculation methods
 	//static double calcApproxFPR(size_t numBucket, size_t numEntr,
 	//		unsigned numHash) const;
diff --git a/Bloom/BloomFilter.h b/Bloom/BloomFilter.h
index 42b8a07..620f045 100644
--- a/Bloom/BloomFilter.h
+++ b/Bloom/BloomFilter.h
@@ -8,6 +8,7 @@
 #include "Bloom/Bloom.h"
 #include "Common/Kmer.h"
 #include "Common/IOUtil.h"
+#include "Common/BitUtil.h"
 #include <algorithm>
 #include <vector>
 #include <iostream>
@@ -19,18 +20,38 @@ class BloomFilter
   public:
 
 	/** Constructor. */
-	BloomFilter() { }
+	BloomFilter() : m_size(0), m_array(NULL) { }
 
 	/** Constructor. */
-	BloomFilter(size_t n) : m_array(n) { }
+	BloomFilter(size_t n) : m_size(n)
+	{
+		m_array = new char[(n + 7)/8]();
+	}
+
+	~BloomFilter()
+	{
+		delete[] m_array;
+	}
 
 	/** Return the size of the bit array. */
-	size_t size() const { return m_array.size(); }
+	size_t size() const { return m_size; }
 
 	/** Return the population count, i.e. the number of set bits. */
 	size_t popcount() const
 	{
-		return m_array.count();
+		size_t count = 0;
+		size_t bytes = (m_size + 7) / 8;
+		size_t numInts = bytes / sizeof(uint64_t);
+		size_t leftOverBytes = bytes % sizeof(uint64_t);
+		uint64_t* intPtr = reinterpret_cast<uint64_t*>(m_array);
+		for (size_t i = 0; i < numInts; i++) {
+			count += ::popcount(intPtr[i]);
+		}
+		for (size_t i = (bytes - leftOverBytes)*8; i < m_size; i++) {
+			if ((*this)[i])
+				count++;
+		}
+		return count;
 	}
 
 	/** Return the estimated false positive rate */
@@ -42,33 +63,33 @@ class BloomFilter
 	/** Return whether the specified bit is set. */
 	bool operator[](size_t i) const
 	{
-		assert(i < m_array.size());
-		return m_array[i];
+		assert(i < m_size);
+		return m_array[i / 8] & 1 << (7 - i % 8);
 	}
 
 	/** Return whether the object is present in this set. */
 	bool operator[](const Bloom::key_type& key) const
 	{
-		return m_array[Bloom::hash(key) % m_array.size()];
+		return (*this)[Bloom::hash(key) % m_size];
 	}
 
 	/** Add the object with the specified index to this set. */
-	void insert(size_t index)
+	void insert(size_t i)
 	{
-		assert(index < m_array.size());
-		m_array[index] = true;
+		assert(i < m_size);
+		m_array[i / 8] |= 1 << (7 - i % 8);
 	}
 
 	/** Add the object to this set. */
 	void insert(const Bloom::key_type& key)
 	{
-		m_array[Bloom::hash(key) % m_array.size()] = true;
+		insert(Bloom::hash(key) % m_size);
 	}
 
 	/** Operator for reading a bloom filter from a stream. */
 	friend std::istream& operator>>(std::istream& in, BloomFilter& o)
 	{
-		o.read(in, Bloom::LOAD_OVERWRITE);
+		o.read(in, BITWISE_OVERWRITE);
 		return in;
 	}
 
@@ -80,21 +101,55 @@ class BloomFilter
 	}
 
 	/** Read a bloom filter from a stream. */
-	void read(std::istream& in, Bloom::LoadType loadType = Bloom::LOAD_OVERWRITE,
-		unsigned shrinkFactor = 1)
+	void read(std::istream& in, BitwiseOp readOp = BITWISE_OVERWRITE)
 	{
-		Bloom::read(m_array, in, loadType, shrinkFactor);
+		Bloom::FileHeader header = Bloom::readHeader(in);
+		assert(in);
+
+		if (m_size != header.fullBloomSize) {
+			if (readOp == BITWISE_OVERWRITE) {
+				resize(header.fullBloomSize);
+			} else {
+				std::cerr << "error: can't union/intersect bloom filters with "
+					<< "different sizes\n";
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		size_t bits = header.endBitPos - header.startBitPos + 1;
+		readBits(in, m_array, bits, header.startBitPos, readOp);
+		assert(in);
 	}
 
 	/** Write a bloom filter to a stream. */
 	void write(std::ostream& out) const
 	{
-		Bloom::write(m_array, out);
+		Bloom::FileHeader header;
+		header.fullBloomSize = m_size;
+		header.startBitPos = 0;
+		header.endBitPos = m_size - 1;
+
+		Bloom::writeHeader(out, header);
+		assert(out);
+
+		out.write(m_array, (m_size + 7)/8);
+		assert(out);
+	}
+
+	/** Resize the bloom filter (wipes the current data) */
+	void resize(size_t size)
+	{
+		if (m_size > 0 && m_array != NULL)
+			delete[] m_array;
+
+		m_array = new char[(size + 7)/8]();
+		m_size = size;
 	}
 
   protected:
 
-	boost::dynamic_bitset<> m_array;
+	size_t m_size;
+	char* m_array;
 };
 
 #endif
diff --git a/Bloom/BloomFilterWindow.h b/Bloom/BloomFilterWindow.h
index 723be88..c16f8dd 100644
--- a/Bloom/BloomFilterWindow.h
+++ b/Bloom/BloomFilterWindow.h
@@ -65,7 +65,7 @@ public:
 		return BloomFilter::size();
 	}
 
-	/** Return the number of elements with count >= MAX_COUNT. */
+	/** Return the number of elements with count >= max_count. */
 	size_t popcount() const
 	{
 		return BloomFilter::popcount();
@@ -107,7 +107,7 @@ public:
 	/** Operator for reading a bloom filter from a stream. */
 	friend std::istream& operator>>(std::istream& in, BloomFilterWindow& o)
 	{
-		o.read(in, Bloom::LOAD_OVERWRITE);
+		o.read(in, BITWISE_OVERWRITE);
 		return in;
 	}
 
@@ -119,33 +119,45 @@ public:
 	}
 
 	/** Read a bloom filter window from a stream. */
-	void read(std::istream& in,
-			Bloom::LoadType loadType = Bloom::LOAD_OVERWRITE,
-			unsigned shrinkFactor = 1)
+	void read(std::istream& in, BitwiseOp readOp = BITWISE_OVERWRITE)
 	{
 		Bloom::FileHeader header = Bloom::readHeader(in);
+		assert(in);
 
 		m_fullBloomSize = header.fullBloomSize;
 		m_startBitPos = header.startBitPos;
 		m_endBitPos = header.endBitPos;
 
-		// alter the dimensions that we pass into Bloom::readData
-		// so that we load the data into a bit array that is
-		// exactly the size of the window (not the full size of the
-		// containing bloom filter)
+		size_t bits = header.endBitPos - header.startBitPos + 1;
 
-		header.fullBloomSize = header.endBitPos - header.startBitPos + 1;
-		header.startBitPos = 0;
-		header.endBitPos = header.fullBloomSize - 1;
+		if (m_size != bits) {
+			if (readOp == BITWISE_OVERWRITE) {
+				BloomFilter::resize(bits);
+			} else {
+				std::cerr << "error: can't union/intersect bloom filters with "
+					<< "different sizes\n";
+				exit(EXIT_FAILURE);
+			}
+		}
 
-		Bloom::readData(m_array, header, in, loadType, shrinkFactor);
+		readBits(in, m_array, bits, 0, readOp);
+
+		assert(in);
 	}
 
 	/** Write a bloom filter window to a stream. */
 	void write(std::ostream& out) const
 	{
-		Bloom::write(m_array, m_fullBloomSize, m_startBitPos,
-			m_endBitPos, out);
+		Bloom::FileHeader header;
+		header.fullBloomSize = m_fullBloomSize;
+		header.startBitPos = m_startBitPos;
+		header.endBitPos = m_endBitPos;
+		Bloom::writeHeader(out, header);
+		assert(out);
+
+		size_t windowSize = m_endBitPos - m_startBitPos + 1;
+		out.write(m_array, (windowSize + 7)/8);
+		assert(out);
 	}
 
 private:
diff --git a/Bloom/CascadingBloomFilter.h b/Bloom/CascadingBloomFilter.h
index 4b3569c..1cf3f93 100644
--- a/Bloom/CascadingBloomFilter.h
+++ b/Bloom/CascadingBloomFilter.h
@@ -14,16 +14,14 @@ class CascadingBloomFilter
 {
   public:
 
-	/** The maximum count of an element in this multiset. */
-	static const unsigned MAX_COUNT = 2;
-
 	/** Constructor */
 	CascadingBloomFilter() {}
 
 	/** Constructor */
-	CascadingBloomFilter(size_t n)
+	CascadingBloomFilter(size_t n, size_t max_count)
 	{
-		for (unsigned i = 0; i < MAX_COUNT; i++)
+		m_data.reserve(max_count);
+		for (unsigned i = 0; i < max_count; i++)
 			m_data.push_back(new BloomFilter(n));
 	}
 
@@ -44,7 +42,7 @@ class CascadingBloomFilter
 		return m_data.back()->size();
 	}
 
-	/** Return the number of elements with count >= MAX_COUNT. */
+	/** Return the number of elements with count >= max_count. */
 	size_t popcount() const
 	{
 		assert(m_data.back() != NULL);
@@ -58,7 +56,7 @@ class CascadingBloomFilter
 	}
 
 	/** Return whether the element with this index has count >=
-	 * MAX_COUNT.
+	 * max_count.
 	 */
 	bool operator[](size_t i) const
 	{
@@ -66,7 +64,7 @@ class CascadingBloomFilter
 		return (*m_data.back())[i];
 	}
 
-	/** Return whether this element has count >= MAX_COUNT. */
+	/** Return whether this element has count >= max_count. */
 	bool operator[](const Bloom::key_type& key) const
 	{
 		assert(m_data.back() != NULL);
@@ -76,7 +74,7 @@ class CascadingBloomFilter
 	/** Add the object with the specified index to this multiset. */
 	void insert(size_t index)
 	{
-		for (unsigned i = 0; i < MAX_COUNT; ++i) {
+		for (unsigned i = 0; i < m_data.size(); ++i) {
 			assert(m_data.at(i) != NULL);
 			if (!(*m_data[i])[index]) {
 				m_data[i]->insert(index);
diff --git a/Bloom/CascadingBloomFilterWindow.h b/Bloom/CascadingBloomFilterWindow.h
index 19bd9e7..8aa4106 100644
--- a/Bloom/CascadingBloomFilterWindow.h
+++ b/Bloom/CascadingBloomFilterWindow.h
@@ -15,11 +15,14 @@ class CascadingBloomFilterWindow : private CascadingBloomFilter
 	 * @param fullBloomSize size in bits of the containing counting bloom filter
 	 * @param startBitPos index of first bit in the window
 	 * @param endBitPos index of last bit in the window
+	 * @param max_count the maximum count value of the Bloom filter
 	 */
-	CascadingBloomFilterWindow(size_t fullBloomSize, size_t startBitPos, size_t endBitPos)
+	CascadingBloomFilterWindow(size_t fullBloomSize, size_t startBitPos, size_t endBitPos,
+			unsigned max_count)
 		: m_fullBloomSize(fullBloomSize)
 	{
-		for (unsigned i = 0; i < MAX_COUNT; i++)
+		m_data.reserve(max_count);
+		for (unsigned i = 0; i < max_count; ++i)
 			m_data.push_back(new BloomFilterWindow(fullBloomSize, startBitPos, endBitPos));
 	}
 
@@ -30,7 +33,7 @@ class CascadingBloomFilterWindow : private CascadingBloomFilter
 		return m_data.back()->size();
 	}
 
-	/** Return the number of elements with count >= MAX_COUNT. */
+	/** Return the number of elements with count >= max_count. */
 	size_t popcount() const
 	{
 		assert(m_data.back() != NULL);
@@ -46,7 +49,7 @@ class CascadingBloomFilterWindow : private CascadingBloomFilter
 	/** Add the object with the specified index to this multiset. */
 	void insert(size_t index)
 	{
-		for (unsigned i = 0; i < MAX_COUNT; ++i) {
+		for (unsigned i = 0; i < m_data.size(); ++i) {
 			assert(m_data.at(i) != NULL);
 			if (!(*m_data[i])[index]) {
 				m_data[i]->insert(index);
diff --git a/Bloom/bloom.cc b/Bloom/bloom.cc
index 29c050d..31f7eaa 100644
--- a/Bloom/bloom.cc
+++ b/Bloom/bloom.cc
@@ -5,6 +5,7 @@
 #include "config.h"
 #include "Common/Options.h"
 #include "Common/Kmer.h"
+#include "Common/BitUtil.h"
 #include "DataLayer/Options.h"
 #include "Common/StringUtil.h"
 #include "Bloom/Bloom.h"
@@ -52,6 +53,7 @@ static const char USAGE_MESSAGE[] =
 " Options for `" PROGRAM " build':\n"
 "\n"
 "  -b, --bloom-size=N         size of bloom filter [500M]\n"
+"  -B, --buffer-size=N        size of I/O buffer for each thread, in bytes [100000]\n"
 "  -j, --threads=N            use N parallel threads [1]\n"
 "  -l, --levels=N             build a cascading bloom filter with N levels\n"
 "                             and output the last level\n"
@@ -62,7 +64,7 @@ static const char USAGE_MESSAGE[] =
 "      --trim-masked          trim masked bases from the ends of reads\n"
 "      --no-trim-masked       do not trim masked bases from the ends\n"
 "                             of reads [default]\n"
-"  -n, --num-locks=N          number of write locks on bloom filter\n"
+"  -n, --num-locks=N          number of write locks on bloom filter [1000]\n"
 "  -q, --trim-quality=N       trim bases from the ends of reads whose\n"
 "                             quality is less than the threshold\n"
 "      --standard-quality     zero quality is `!' (33)\n"
@@ -78,9 +80,13 @@ static const char USAGE_MESSAGE[] =
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+
 	/** The size of the bloom filter in bytes. */
 	size_t bloomSize = 500 * 1024 * 1024;
 
+	/** The size of the I/O buffer of each thread, in bytes  */
+	size_t bufferSize = 100000;
+
 	/** The number of parallel threads. */
 	unsigned threads = 1;
 
@@ -111,12 +117,13 @@ namespace opt {
 	unsigned windows = 0;
 }
 
-static const char shortopts[] = "b:j:k:l:L:n:q:vw:";
+static const char shortopts[] = "b:B:j:k:l:L:n:q:vw:";
 
 enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "bloom-size",       required_argument, NULL, 'b' },
+	{ "buffer-size",      required_argument, NULL, 'B' },
 	{ "threads",          required_argument, NULL, 'j' },
 	{ "kmer",             required_argument, NULL, 'k' },
 	{ "levels",           required_argument, NULL, 'l' },
@@ -163,7 +170,7 @@ void parseGlobalOpts(int argc, char** argv)
 			cout << USAGE_MESSAGE;
 			exit(EXIT_SUCCESS);
 		  case OPT_VERSION:
-			cerr << VERSION_MESSAGE;
+			cout << VERSION_MESSAGE;
 			exit(EXIT_SUCCESS);
 		  default:
 			// end of global opts
@@ -238,9 +245,8 @@ void initBloomFilterLevels(CBF& bf)
 				<< i + 1 << " of cascading bloom filter...\n";
 			istream* in = openInputStream(path);
 			assert(*in);
-			Bloom::LoadType loadType = (j > 0) ?
-				Bloom::LOAD_UNION : Bloom::LOAD_OVERWRITE;
-			bf.getBloomFilter(i).read(*in, loadType);
+			BitwiseOp readOp = (j > 0) ? BITWISE_OR : BITWISE_OVERWRITE;
+			bf.getBloomFilter(i).read(*in, readOp);
 			assert(*in);
 			closeInputStream(in, path);
 		}
@@ -251,7 +257,7 @@ template <typename BF>
 void loadFilters(BF& bf, int argc, char** argv)
 {
 	for (int i = optind; i < argc; i++)
-		Bloom::loadFile(bf, opt::k, argv[i], opt::verbose);
+		Bloom::loadFile(bf, opt::k, argv[i], opt::verbose, opt::bufferSize);
 
 	if (opt::verbose)
 		cerr << "Successfully loaded bloom filter.\n";
@@ -310,6 +316,8 @@ int build(int argc, char** argv)
 			dieWithUsageError();
 		  case 'b':
 			opt::bloomSize = SIToBytes(arg); break;
+		  case 'B':
+			arg >> opt::bufferSize; break;
 		  case 'j':
 			arg >> opt::threads; break;
 		  case 'l':
@@ -346,12 +354,6 @@ int build(int argc, char** argv)
 		}
 	}
 
-	if (opt::levels > 2)
-	{
-		cerr << PROGRAM ": -l > 2 is not currently supported\n";
-		dieWithUsageError();
-	}
-
 	if (!opt::levelInitPaths.empty() && opt::levels < 2)
 	{
 		cerr << PROGRAM ": -L can only be used with cascading bloom "
@@ -414,7 +416,7 @@ int build(int argc, char** argv)
 			writeBloom(bloom, outputPath);
 		}
 		else {
-			CascadingBloomFilter cascadingBloom(bits);
+			CascadingBloomFilter cascadingBloom(bits, opt::levels);
 			initBloomFilterLevels(cascadingBloom);
 #ifdef _OPENMP
 			ConcurrentBloomFilter<CascadingBloomFilter>
@@ -445,7 +447,8 @@ int build(int argc, char** argv)
 			writeBloom(bloom, outputPath);
 		}
 		else {
-			CascadingBloomFilterWindow cascadingBloom(bits, startBitPos, endBitPos);
+			CascadingBloomFilterWindow cascadingBloom(
+				bits, startBitPos, endBitPos, opt::levels);
 			initBloomFilterLevels(cascadingBloom);
 			loadFilters(cascadingBloom, argc, argv);
 			printCascadingBloomStats(cerr, cascadingBloom);
@@ -456,7 +459,7 @@ int build(int argc, char** argv)
 	return 0;
 }
 
-int combine(int argc, char** argv, Bloom::LoadType loadType)
+int combine(int argc, char** argv, BitwiseOp readOp)
 {
 	parseGlobalOpts(argc, argv);
 
@@ -477,9 +480,8 @@ int combine(int argc, char** argv, Bloom::LoadType loadType)
 				<< path << "'...\n";
 		istream* in = openInputStream(path);
 		assert_good(*in, path);
-		Bloom::LoadType loadOp = (i > optind) ?
-				loadType : Bloom::LOAD_OVERWRITE;
-		bloom.read(*in, loadOp);
+		BitwiseOp op = (i > optind) ? readOp : BITWISE_OVERWRITE;
+		bloom.read(*in, op);
 		assert_good(*in, path);
 		closeInputStream(in, path);
 	}
@@ -487,17 +489,17 @@ int combine(int argc, char** argv, Bloom::LoadType loadType)
 	if (opt::verbose) {
 		cerr << "Successfully loaded bloom filter.\n";
 		printBloomStats(cerr, bloom);
-		switch(loadType) {
-			case Bloom::LOAD_UNION:
+		switch(readOp) {
+			case BITWISE_OR:
 				std::cerr << "Writing union of bloom filters to `"
 					<< outputPath << "'...\n";
 				break;
-			case Bloom::LOAD_INTERSECT:
+			case BITWISE_AND:
 				std::cerr << "Writing intersection of bloom filters to `"
 					<< outputPath << "'...\n";
 				break;
 			default:
-				std::cerr << "error: expected LOAD_UNION or LOAD_INTERSECT\n";
+				std::cerr << "error: expected BITWISE_OR or BITWISE_AND\n";
 				assert(false);
 				break;
 		}
@@ -552,16 +554,20 @@ int main(int argc, char** argv)
 
 	if (command == "--help" || command == "-h") {
 		cout << USAGE_MESSAGE;
-		return EXIT_SUCCESS;
+		exit(EXIT_SUCCESS);
+	}
+	if (command == "--version") {
+		cout << VERSION_MESSAGE;
+		exit(EXIT_SUCCESS);
 	}
 	else if (command == "build") {
 		return build(argc, argv);
 	}
 	else if (command == "union") {
-		return combine(argc, argv, Bloom::LOAD_UNION);
+		return combine(argc, argv, BITWISE_OR);
 	}
 	else if (command == "intersect") {
-		return combine(argc, argv, Bloom::LOAD_INTERSECT);
+		return combine(argc, argv, BITWISE_AND);
 	}
 	else if (command == "info") {
 		return info(argc, argv);
diff --git a/CITATION.bib b/CITATION.bib
new file mode 100644
index 0000000..35ec000
--- /dev/null
+++ b/CITATION.bib
@@ -0,0 +1,10 @@
+ at article{simpson2009abyss,
+  title={ABySS: a parallel assembler for short read sequence data},
+  author={Simpson, Jared T and Wong, Kim and Jackman, Shaun D and Schein, Jacqueline E and Jones, Steven JM and Birol, Inan{\c{c}}},
+  journal={Genome research},
+  volume={19},
+  number={6},
+  pages={1117--1123},
+  year={2009},
+  publisher={Cold Spring Harbor Lab}
+}
diff --git a/CITATION.md b/CITATION.md
new file mode 100644
index 0000000..6fdea0c
--- /dev/null
+++ b/CITATION.md
@@ -0,0 +1,39 @@
+Citation
+================================================================================
+
++ [doi:10.1101/gr.089532.108](http://dx.doi.org/10.1101/gr.089532.108)
++ [PubMed PMID: 19251739](http://www.ncbi.nlm.nih.gov/pubmed/19251739)
++ [Google Scholar](http://scholar.google.ca/scholar?q=doi%3A10.1101%2Fgr.089532.108)
++ [Genome Research](http://genome.cshlp.org/content/19/6/1117.short)
++ [PDF](http://genome.cshlp.org/content/19/6/1117.full.pdf)
+
+BibTeX
+------------------------------------------------------------
+
+```bibtex
+ at article{simpson2009abyss,
+  title={ABySS: a parallel assembler for short read sequence data},
+  author={Simpson, Jared T and Wong, Kim and Jackman, Shaun D and Schein, Jacqueline E and Jones, Steven JM and Birol, Inan{\c{c}}},
+  journal={Genome research},
+  volume={19},
+  number={6},
+  pages={1117--1123},
+  year={2009},
+  publisher={Cold Spring Harbor Lab}
+}
+```
+
+MLA
+------------------------------------------------------------
+
+Simpson, Jared T., et al. "ABySS: a parallel assembler for short read sequence data." *Genome research* 19.6 (2009): 1117-1123.
+
+APA
+------------------------------------------------------------
+
+Simpson, J. T., Wong, K., Jackman, S. D., Schein, J. E., Jones, S. J., & Birol, I. (2009). ABySS: a parallel assembler for short read sequence data. *Genome research*, 19(6), 1117-1123.
+
+Chicago
+------------------------------------------------------------
+
+Simpson, Jared T., Kim Wong, Shaun D. Jackman, Jacqueline E. Schein, Steven JM Jones, and Inanç Birol. "ABySS: a parallel assembler for short read sequence data." *Genome research* 19, no. 6 (2009): 1117-1123.
diff --git a/ChangeLog b/ChangeLog
index 589c8a4..8316e1c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2015-05-28  Ben Vandervalk <benv at bcgsc.ca>
+
+	* Release version 1.9.0
+	* New paired de Bruijn graph mode for assembly.
+	* First official release of Sealer, a tool for closing
+	scaffold gaps by navigating a Bloom filter de Bruijn graph.
+	* New outward extension feature for Konnector to generate
+	long pseudo-reads.
+	* Support for the DIDA (Distributed Indexing Dispatched
+	Alignment) framework, for computing sequence alignments
+	in parallel across multiple machines.
+	* Unit tests can now be run easily with 'make check', without
+	external dependencies.
+
+	abyss-bloom:
+	* abyss-bloom 'build' command now supports -j option for
+	multi-threaded Bloom filter construction.
+
+	abyss-map:
+	* New --protein option for mapping protein sequences.
+
+	abyss-pe:
+	* New paired de Bruijn graph mode for assembly. Enable by
+	setting `k` to the k-mer pair span and `K` to size of an
+	individual k-mer in a k-mer pair. See README.md for further
+	details.
+	* New `aligner=dida` option for using the DIDA parallel alignment
+	framework. See the DIDA section of the abyss-pe man page
+	for usage details.
+	* New `graph=gfa` option to use the GFA (Graphical
+	Fragment Assembly) format for intermediate graph files.
+
+	abyss-sealer:
+	* New tool for closing scaffold gaps by navigating a Bloom
+	filter de Bruijn graph
+	* See Sealer/README.md or abyss-sealer man page for details
+	and examples.
+
+	konnector:
+	* New --extend option for extending merged and unmerged
+	reads outwards in the de Bruijn graph.
+
 2014-07-09  Anthony Raymond  <traymond at bcgsc.ca>
 
 	* Release version 1.5.2
diff --git a/Common/BitUtil.h b/Common/BitUtil.h
index 3839297..cc992e1 100644
--- a/Common/BitUtil.h
+++ b/Common/BitUtil.h
@@ -4,6 +4,10 @@
 #include "config.h"
 #include <cstdlib> // for exit
 #include <stdint.h>
+#include <cassert>
+#include <iostream>
+
+enum BitwiseOp { BITWISE_OVERWRITE, BITWISE_OR, BITWISE_AND };
 
 /** The return value of the CPUID instruction. */
 struct CPUID { unsigned a, b, c, d; };
@@ -50,4 +54,107 @@ static inline uint64_t popcount(uint64_t x)
 	return x & 0x7FLLU;
 }
 
+/**
+ * Memory copy with bit-level resolution.
+ *
+ * @param src source data to copy (byte array)
+ * @param dest destination of copied data (byte array)
+ * @param bits number of bits to copy from src, starting from
+ *        first bit of first byte of src
+ * @param bitOffset bit offset into dest
+ * @param op how to combine existing bits in dest with bits
+ *        src (options: BITWISE_OVERWRITE, BITWISE_OR,
+ *        BITWISE_AND)
+ */
+static inline void copyBits(char* src, char* dest, size_t bits,
+	size_t bitOffset = 0, BitwiseOp op = BITWISE_OVERWRITE)
+{
+	size_t bytes = (bits + 7) / 8;
+	size_t fullBytes = (bits % 8 == 0) ? bytes : bytes - 1;
+	size_t byteOffset = bitOffset / 8;
+	unsigned char shift = bitOffset % 8;
+	unsigned char carryMask = 0xFF << (8 - shift);
+	for (size_t i = 0; i < fullBytes; i++) {
+		if (op == BITWISE_OVERWRITE) {
+			dest[byteOffset + i] &= carryMask;
+			dest[byteOffset + i + 1] &= ~carryMask;
+		}
+		if (op == BITWISE_AND) {
+			dest[byteOffset + i] &= src[i] >> shift | carryMask;
+			dest[byteOffset + i + 1] &= src[i] << (8 - shift) | ~carryMask;
+		}
+		else {
+			dest[byteOffset + i] |= src[i] >> shift;
+			dest[byteOffset + i + 1] |= src[i] << (8 - shift);
+		}
+	}
+	if (fullBytes < bytes) {
+		unsigned char bitsInLastByte = bits % 8;
+		unsigned char lastByteMask = 0xFF << (8 - bitsInLastByte);
+		unsigned char lastCarryMask = lastByteMask << (8 - shift);
+		char lastByte = src[bytes - 1];
+		lastByte &= lastByteMask;
+		size_t lastByteIndex = byteOffset + bytes - 1;
+		if (op == BITWISE_OVERWRITE)
+			dest[lastByteIndex] &= ~(lastByteMask >> shift);
+		if (op == BITWISE_AND)
+			dest[lastByteIndex] &= lastByte >> shift | ~(lastByteMask >> shift);
+		else
+			dest[lastByteIndex] |= lastByte >> shift;
+		if (lastCarryMask > 0) {
+			if (op == BITWISE_OVERWRITE)
+				dest[lastByteIndex + 1] &= ~lastCarryMask;
+			if (op == BITWISE_AND)
+				dest[lastByteIndex + 1] &= lastByte << (8 - shift) | ~lastCarryMask;
+			else
+				dest[lastByteIndex + 1] |= lastByte << (8 - shift);
+		}
+	}
+}
+
+/**
+ * Read data from a stream with bit-level resolution.
+ *
+ * @param in input byte stream
+ * @param dest destination of copied data (byte array)
+ * @param bits number of bits to read from in, starting from
+ *        first bit of first byte of in
+ * @param bitOffset bit offset into dest
+ */
+static inline void readBits(std::istream& in, char* dest, size_t bits,
+	size_t bitOffset = 0, BitwiseOp op = BITWISE_OVERWRITE)
+{
+	(void)readBits;
+
+	const size_t IO_BUFFER_SIZE = 32 * 1024;
+	size_t byteOffset = bitOffset / 8;
+	unsigned char shift = bitOffset % 8;
+
+	if (op == BITWISE_OVERWRITE && shift == 0) {
+		// Simple byte-aligned copy.
+		size_t bytes = (bits + 7) / 8;
+		size_t fullBytes = (bits % 8 == 0) ? bytes : bytes - 1;
+		in.read(dest + byteOffset, fullBytes);
+		assert(in);
+		if (fullBytes < bytes) {
+			char lastByte;
+			in.read(&lastByte, 1);
+			assert(in);
+			copyBits(&lastByte, dest + byteOffset + fullBytes, bits % 8);
+		}
+	} else {
+		// Non-byte-aligned copy. A portion of each src byte is
+		// carried over into the next dest byte.
+		char buffer[IO_BUFFER_SIZE];
+		for(size_t i = 0; i < bits;) {
+			size_t bitsRead = std::min(IO_BUFFER_SIZE * 8, bits - i);
+			size_t bytesRead = (bitsRead + 7)/8;
+			in.read(buffer, bytesRead);
+			assert(in);
+			copyBits(buffer, dest + byteOffset, bitsRead, i + shift, op);
+			i += bitsRead;
+		}
+	}
+}
+
 #endif
diff --git a/Common/ContigProperties.h b/Common/ContigProperties.h
index 73fb0bd..215b140 100644
--- a/Common/ContigProperties.h
+++ b/Common/ContigProperties.h
@@ -31,7 +31,7 @@ struct Length
 	template <typename T>
 	Length& operator+=(const T& o)
 	{
-		assert((int)length + (int)o.distance > 0);
+		assert((int)length + (int)o.distance >= 0);
 		length += o.distance;
 		return *this;
 	}
@@ -220,11 +220,11 @@ struct EdgeWeightMap {
 	reference operator[](const key_type& e) const
 	{
 		int weight = m_g[e].distance + m_g[target(e, m_g)].length;
-		if (weight <= 0)
+		if (weight < 0)
 			std::cerr << "error: invalid edge: "
 				<< get(edge_name, m_g, e)
 				<< " [" << get(edge_bundle, m_g, e) << "]\n";
-		assert(weight > 0);
+		assert(weight >= 0);
 		return weight;
 	}
 
diff --git a/Common/Estimate.h b/Common/Estimate.h
index 4e1201b..66152e1 100644
--- a/Common/Estimate.h
+++ b/Common/Estimate.h
@@ -1,6 +1,7 @@
 #ifndef ESTIMATE_H
 #define ESTIMATE_H 1
 
+#include "Common/ContigProperties.h" // for Distance
 #include "ContigID.h"
 #include "ContigNode.h"
 #include "Graph/Options.h" // for opt::k
@@ -91,6 +92,12 @@ struct BetterDistanceEst
 		return a;
 	}
 
+	Distance operator()(
+			const Distance& a, const Distance& b) const
+	{
+		return a.distance > b.distance ? a : b;
+	}
+
 	DistanceEst operator()(
 			const DistanceEst& a, const DistanceEst& b) const
 	{
diff --git a/Common/Histogram.h b/Common/Histogram.h
index b466fb5..d89ea50 100644
--- a/Common/Histogram.h
+++ b/Common/Histogram.h
@@ -2,6 +2,7 @@
 #define HISTOGRAM_H 1
 
 #include "StringUtil.h" // for toEng
+#include "VectorUtil.h" // for make_vector
 #include <cassert>
 #include <climits> // for INT_MAX
 #include <cmath>
@@ -325,9 +326,9 @@ static inline std::ostream& printContiguityStats(
 	if (printHeader) {
 		out << "n" << sep
 			<< "n:" << minSize << sep
-			<< "n:N50" << sep;
+			<< "L50" << sep;
 		if (expSize > 0)
-			out << "n:NG50" << sep
+			out << "LG50" << sep
 				<< "NG50" << sep;
 		out << "min" << sep
 			<< "N80" << sep
@@ -362,4 +363,43 @@ static inline std::ostream& printContiguityStats(
 		<< toEng(sum);
 }
 
+/** Pass assembly contiguity statistics -- values only. */
+static inline std::vector<int> passContiguityStatsVal(
+		const Histogram& h0, unsigned minSize, const long long unsigned expSize = 0)
+{
+#if _SQL
+	Histogram h = h0.trimLow(minSize);
+	unsigned n50 = h.n50();
+	long long unsigned sum = h.sum();
+
+	std::vector<int> vec = make_vector<int>()
+		<< h0.size()
+		<< h.size()
+		<< h.count(n50, INT_MAX)
+		<< h.minimum()
+		<< h.weightedPercentile(1 - 0.8)
+		<< n50
+		<< h.weightedPercentile(1 - 0.2)
+		<< (unsigned)h.expectedValue()
+		<< h.maximum()
+		<< sum;
+
+	if (expSize > 0) {
+		unsigned ng50;
+		if (sum < expSize/2)
+			ng50 = h.minimum();
+		else
+			ng50 = h.argMin(sum - expSize/2);
+		vec.push_back(h.count(ng50, INT_MAX));
+		vec.push_back(ng50);
+	}
+
+	return vec;
+#else
+	(void)h0;
+	(void)minSize;
+	(void)expSize;
+	return make_vector<int>();
+#endif
+}
 #endif
diff --git a/Common/InsOrderedMap.h b/Common/InsOrderedMap.h
new file mode 100644
index 0000000..a1f5089
--- /dev/null
+++ b/Common/InsOrderedMap.h
@@ -0,0 +1,88 @@
+/**
+ * Partial implementation of a map class
+ * read in multiple ways of ordering.
+ *
+ * index<0>: insertion order
+ */
+
+#ifndef INS_ORDERED_MAP_H
+#define INS_ORDERED_MAP_H 1
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/random_access_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/member.hpp>
+
+using namespace boost::multi_index;
+
+template <class F, class S>
+class InsOrderedMap
+{
+private:
+
+	struct aMap
+	{
+		F first;
+		S second;
+		aMap(const F first, const S second) : first(first), second(second) { }
+	};
+
+	typedef multi_index_container<
+		aMap,
+		indexed_by<
+			random_access<>, // ra
+			ordered_unique<member<aMap, F, &aMap::first> > // on
+		>
+	> aMap_cont;
+
+	typedef typename aMap_cont::template nth_index<0>::type idx;
+	typedef typename idx::iterator iit;
+
+	aMap_cont ac;
+
+	void insert_by_ra(const aMap_cont& other_ac)
+	{
+		const idx& i = other_ac.template get<0>();
+		for (iit it = i.begin(), e=i.end(); it!=e; ++it)
+			ac.push_back(aMap(it->first, it->second));
+	}
+
+public:
+
+	InsOrderedMap() { }
+
+	~InsOrderedMap() { }
+
+	void push_back(const F& first, const S& second)
+	{
+		ac.push_back(aMap(first, second));
+	}
+
+	void insert(aMap_cont other_ac)
+	{
+		insert_by_ra(other_ac);
+		other_ac.clear();
+	}
+
+	iit begin()
+	{
+		const idx& i = ac.template get<0>();
+		return i.begin();
+	}
+
+	std::size_t size() { return ac.size(); }
+
+	void erase(iit pair) { ac.erase(pair); }
+
+	void clear() { ac.clear(); }
+
+	bool empty() { return ac.empty(); }
+
+	const F& getFirst(const iit& pair) { return pair->first; }
+
+	const S& getSecond(const iit& pair) { return pair->second; }
+
+	const aMap_cont& getAC() { return ac; }
+};
+
+#endif
diff --git a/Common/Kmer.cpp b/Common/Kmer.cpp
index 7466b78..de8bfcf 100644
--- a/Common/Kmer.cpp
+++ b/Common/Kmer.cpp
@@ -48,7 +48,10 @@ unsigned Kmer::getCode() const
 	/* At k=19, this hash function always returns an even number due
 	 * to the sequence and its reverse complement overlapping when the
 	 * xor is calculated. A more general solution is needed. */
-	const unsigned NUM_BYTES = s_length < 20 ? s_length/8 : 4;
+	const unsigned NUM_BYTES
+		= s_length < 8 ? 1
+		: s_length < 20 ? s_length/8
+		: 4;
 	Kmer rc = *this;
 	rc.reverseComplement();
 
@@ -424,11 +427,6 @@ void Kmer::set(unsigned i, uint8_t base)
 			seqIndexToByteNumber(i), seqIndexToBaseIndex(i), base);
 }
 
-uint8_t Kmer::getLastBaseChar() const
-{
-	return codeToBase(at(s_length - 1));
-}
-
 // get a base code by the byte number and sub index
 static uint8_t getBaseCode(const char* pSeq,
 		unsigned byteNum, unsigned index)
diff --git a/Common/Kmer.h b/Common/Kmer.h
index a1a6a25..f1a58a3 100644
--- a/Common/Kmer.h
+++ b/Common/Kmer.h
@@ -58,7 +58,30 @@ class Kmer
 	bool isPalindrome() const;
 	bool isPalindrome(extDirection dir) const;
 	void setLastBase(extDirection dir, uint8_t base);
-	uint8_t getLastBaseChar() const;
+
+	/** Return the first nucleotide. */
+	uint8_t front() const
+	{
+		return at(0);
+	}
+
+	/** Return the terminal nucleotide. */
+	uint8_t back() const
+	{
+		return at(s_length - 1);
+	}
+
+	/** Return the terminal nucleotide as a character. */
+	char getLastBaseChar() const
+	{
+		return codeToBase(at(s_length - 1));
+	}
+
+	/** Return the first nucleotide as a character. */
+	char getFirstBaseChar() const
+	{
+		return codeToBase(at(0));
+	}
 
 	uint8_t shift(extDirection dir, uint8_t base = 0)
 	{
diff --git a/Common/KmerSet.h b/Common/KmerSet.h
new file mode 100644
index 0000000..541317b
--- /dev/null
+++ b/Common/KmerSet.h
@@ -0,0 +1,47 @@
+#ifndef _KMER_SET_H_
+#define _KMER_SET_H_
+
+#include "Common/Kmer.h"
+#include "Graph/Path.h"
+#include "Common/Sequence.h"
+
+class KmerSet
+{
+protected:
+
+	unordered_set<Kmer> m_set;
+	unsigned m_k;
+
+public:
+
+	KmerSet(unsigned k) : m_k(k) { }
+
+	bool containsKmer(const Kmer& kmer)
+	{
+		return m_set.find(kmer) != m_set.end();
+	}
+
+	void addKmer(const Kmer& kmer)
+	{
+		m_set.insert(kmer);
+	}
+
+	void loadSeq(Sequence seq)
+	{
+		if (seq.length() < m_k)
+			return;
+
+		flattenAmbiguityCodes(seq);
+		for (unsigned i = 0; i < seq.length() - m_k + 1; ++i) {
+			std::string kmerStr = seq.substr(i, m_k);
+			size_t pos = kmerStr.find_first_not_of("AGCTagct");
+			if (pos != std::string::npos) {
+				i += pos;
+				continue;
+			}
+			m_set.insert(Kmer(kmerStr));
+		}
+	}
+};
+
+#endif
diff --git a/Common/Makefile.am b/Common/Makefile.am
index c4ea89e..a4c0f4f 100644
--- a/Common/Makefile.am
+++ b/Common/Makefile.am
@@ -18,25 +18,26 @@ libcommon_a_SOURCES = \
 	Hash.h \
 	HashFunction.h \
 	Histogram.cpp Histogram.h \
+	InsOrderedMap.h \
 	IOUtil.h \
 	Iterator.h \
 	Kmer.cpp Kmer.h \
+	KmerSet.h \
 	Log.cpp Log.h \
 	MemoryUtil.h \
 	Options.cpp Options.h \
 	PMF.h \
 	SAM.h \
 	Sense.h \
-	SeqExt.cpp SeqExt.h \
 	Sequence.cpp Sequence.h \
 	SignalHandler.cpp SignalHandler.h \
 	StringUtil.h \
+	VectorUtil.h \
 	SuffixArray.h \
 	Timer.cpp Timer.h \
 	Uncompress.cpp Uncompress.h \
 	UnorderedMap.h \
 	UnorderedSet.h \
-	Warnings.h \
 	cholesky.hpp \
 	KmerIterator.h \
 	MemUtils.h \
diff --git a/Common/MemUtils.h b/Common/MemUtils.h
index a2505d0..69bd061 100644
--- a/Common/MemUtils.h
+++ b/Common/MemUtils.h
@@ -10,8 +10,8 @@ approxMemSize(const UnorderedMap& map)
 	typedef typename UnorderedMap::value_type Entry;
 	size_t filled_bucket_bytes = map.size() *
 		(sizeof(Entry) + 3 * sizeof(Entry *));
-	size_t empty_bucket_bytes = (1.0 - map.load_factor()) *
-		map.bucket_count() * sizeof(Entry *);
+	size_t empty_bucket_bytes = size_t((1.0 - map.load_factor()) *
+		map.bucket_count() * sizeof(Entry *));
 	return filled_bucket_bytes + empty_bucket_bytes;
 }
 
diff --git a/Common/SAM.h b/Common/SAM.h
index 4286a79..42ce0f4 100644
--- a/Common/SAM.h
+++ b/Common/SAM.h
@@ -372,7 +372,7 @@ static inline void fixMate(SAMRecord& a0, SAMRecord& a1)
 }
 
 /** Read contig lengths from SAM headers. */
-static inline void readContigLengths(std::istream& in, std::vector<unsigned>& lengths)
+static inline unsigned readContigLengths(std::istream& in, std::vector<unsigned>& lengths)
 {
 	assert(in);
 	assert(lengths.empty());
@@ -396,6 +396,7 @@ static inline void readContigLengths(std::istream& in, std::vector<unsigned>& le
 		std::cerr << "error: no @SQ records in the SAM header\n";
 		exit(EXIT_FAILURE);
 	}
+	return lengths.size();
 }
 
 #endif
diff --git a/Common/SeqExt.cpp b/Common/SeqExt.cpp
deleted file mode 100644
index 6e92b80..0000000
--- a/Common/SeqExt.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "SeqExt.h"
-#include "Common/Options.h"
-#include <cassert>
-
-/** Return the complementary adjacency.
- * If the assembly is in colour space, this is a no-op.
- */
-SeqExt SeqExt::complement() const
-{
-	static const uint8_t complements[16] = {
-		0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
-		0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
-	};
-	assert(m_record < 1<<NUM_BASES);
-	return opt::colourSpace ? *this : mask(complements[m_record]);
-}
diff --git a/Common/Sequence.cpp b/Common/Sequence.cpp
index 01ff305..2d2907e 100644
--- a/Common/Sequence.cpp
+++ b/Common/Sequence.cpp
@@ -70,9 +70,9 @@ static const uint8_t b2C[256] = {
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 	0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, //5   T
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //6
+	0xFF, 0x00, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x02, //6   a c g
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //7
+	0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, //7   t
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //8
 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
diff --git a/Common/Sequence.h b/Common/Sequence.h
index c104695..b9283b9 100644
--- a/Common/Sequence.h
+++ b/Common/Sequence.h
@@ -3,6 +3,7 @@
 
 #include <stdint.h>
 #include <string>
+#include <cassert>
 
 typedef std::string Sequence;
 
@@ -21,6 +22,50 @@ static inline bool isACGT(char c)
 		|| c == 'a' || c == 'c' || c == 'g' || c == 't';
 }
 
+/**
+ * Convert each ambiguity code to the lexicographically smallest
+ * matching base.
+ */
+static inline void
+flattenAmbiguityCodes(Sequence& seq, bool skipNs=true)
+{
+	for (Sequence::iterator it = seq.begin(); it != seq.end(); ++it) {
+		switch (toupper(*it)) {
+			case 'N':
+				if (!skipNs)
+					*it = 'A';
+				break;
+			case 'M': *it = 'A'; break;
+			case 'R': *it = 'A'; break;
+			case 'W': *it = 'A'; break;
+			case 'S': *it = 'C'; break;
+			case 'Y': *it = 'C'; break;
+			case 'K': *it = 'G'; break;
+			case 'V': *it = 'A'; break;
+			case 'H': *it = 'A'; break;
+			case 'D': *it = 'A'; break;
+			case 'B': *it = 'C'; break;
+			default:
+				break;
+		}
+	}
+}
+
+/**
+ * Return true if the given sequence contains ambiguity codes.
+ */
+static inline bool
+containsAmbiguityCodes(const Sequence& seq, bool allowN=true)
+{
+	if (allowN) {
+		return seq.find_first_of("MRWSYKVHDBmrwsykvhdbNn")
+			!= std::string::npos;
+	} else {
+		return seq.find_first_of("MRWSYKVHDBmrwsykvhdb")
+			!= std::string::npos;
+	}
+}
+
 unsigned ambiguityToBitmask(char c);
 unsigned bitmaskToAmbiguity(unsigned x);
 
@@ -48,4 +93,41 @@ static inline bool ambiguityIsSubset(char a, char b)
 	return intersection == a || intersection == b;
 }
 
+/**
+ * Overlay one sequence on top of another to create a new sequence.
+ * In the cases of differences, the bases in the overlaid sequence
+ * take precedence.
+ *
+ * @param overlay the sequence to be overlaid on target
+ * @param target the sequence to be modified/extended
+ * @param shift position of overlay sequence relative to target
+ * @param maskNew output bases that have been changed or added
+ * to target in lowercase.
+ */
+static inline void overlaySeq(Sequence& overlay, Sequence& target,
+	int shift, bool maskNew = false)
+{
+	Sequence::iterator src = overlay.begin();
+	Sequence::iterator dest;
+
+	if (shift < 0) {
+		target.insert(0, -shift, 'N');
+		dest = target.begin();
+	} else {
+		assert(shift >= 0);
+		if (shift + overlay.length() > target.length()) {
+			unsigned suffixLen = shift + overlay.length() -
+				target.length();
+			target.insert(target.length(), suffixLen, 'N');
+		}
+		dest = target.begin() + shift;
+	}
+	for (; src != overlay.end(); ++src, ++dest) {
+		assert(dest != target.end());
+		if (maskNew && *src != *dest)
+			*src = tolower(*src);
+		*dest = *src;
+	}
+}
+
 #endif
diff --git a/Common/StringUtil.h b/Common/StringUtil.h
index 03e2a07..3a28258 100644
--- a/Common/StringUtil.h
+++ b/Common/StringUtil.h
@@ -46,6 +46,78 @@ static inline std::string toSI(double n)
 	return s.str();
 }
 
+/** Return the SI representation of a number in bytes. */
+static inline std::string bytesToSI(size_t n)
+{
+	std::ostringstream s;
+	s << std::setprecision(3);
+	if (n < 1024)
+		s << n;
+	else if (n < (1ULL<<20))
+		s << (double)n/(1ULL<<10) << "k";
+	else if (n < (1ULL<<30))
+		s << (double)n/(1ULL<<20) << "M";
+	else
+		s << (double)n/(1ULL<<30) << "G";
+	return s.str();
+}
+
+/**
+ * Convert a quantity with SI units to the equivalent floating
+ * point number.
+ */
+static inline double fromSI(std::istringstream& iss)
+{
+	double size;
+	std::string units;
+
+	iss >> size;
+	if (iss.fail()) {
+		// not prefixed by a number
+		return 0;
+	}
+
+	iss >> units;
+	if (iss.fail() && iss.eof()) {
+		// no units given; clear fail flag
+		// and just return the number
+		iss.clear(std::ios::eofbit);
+		return size;
+	}
+
+	if (units.size() > 1) {
+		// unrecognized multichar suffix
+		iss.setstate(std::ios::failbit);
+		return 0;
+	}
+
+	switch(tolower(units[0])) {
+		case 'k':
+			size *= 1000ULL; break;
+		case 'm':
+			size *= 1000ULL*1000; break;
+		case 'g':
+			size *= 1000ULL*1000*1000; break;
+		case 't':
+			size *= 1000ULL*1000*1000*1000; break;
+		default:
+			iss.setstate(std::ios::failbit);
+			return 0;
+	}
+
+	return size;
+}
+
+/**
+ * Convert a quantity with SI units to the equivalent floating
+ * point number.
+ */
+static inline double fromSI(const std::string& str)
+{
+	std::istringstream iss(str);
+	return fromSI(iss);
+}
+
 /** Return the engineering string representation of n. */
 template <typename T>
 static inline std::string toEng(T n)
@@ -88,8 +160,8 @@ bool endsWith(const std::string& s, const std::string& suffix)
 			suffix.begin());
 }
 
-static inline 
-bool isReadNamePair(const std::string& name1, const std::string& name2) 
+static inline
+bool isReadNamePair(const std::string& name1, const std::string& name2)
 {
 	assert(!name1.empty() && !name2.empty());
 
@@ -138,8 +210,6 @@ static inline size_t SIToBytes(std::istringstream& iss)
 			size *= (size_t)1<<20; break;
 		case 'g':
 			size *= (size_t)1<<30; break;
-		case 't':
-			size *= (size_t)1<<40; break;
 		default:
 			iss.setstate(std::ios::failbit);
 			return 0;
diff --git a/Common/VectorUtil.h b/Common/VectorUtil.h
new file mode 100644
index 0000000..4ea1129
--- /dev/null
+++ b/Common/VectorUtil.h
@@ -0,0 +1,35 @@
+#ifndef VECTOR_UTIL_H
+#define VECTOR_UTIL_H 1
+
+#include <vector>
+
+template <typename T>
+class make_vector
+{
+private:
+
+	std::vector<T> vec;
+
+public:
+
+	typedef make_vector<T> mv;
+	typedef std::vector<T> sv;
+
+	mv& operator<< (const T& val)
+	{
+		vec.push_back(val);
+		return *this;
+	}
+
+	operator const sv&() const { return vec; }
+
+	friend sv& operator+= (
+			sv& vec1, const mv& vec2)
+	{
+		sv temp_vec = vec2;
+		vec1.insert(vec1.end(), temp_vec.begin(), temp_vec.end());
+		return vec1;
+	}
+};
+
+#endif
diff --git a/Common/Warnings.h b/Common/Warnings.h
deleted file mode 100644
index 9dffe51..0000000
--- a/Common/Warnings.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef WARNINGS_H_
-#define WARNINGS_H_
-
-#define SUPPRESS_UNUSED_WARNING(a) (void)a
-
-#endif
diff --git a/DataBase/DB.cc b/DataBase/DB.cc
new file mode 100644
index 0000000..16a03e6
--- /dev/null
+++ b/DataBase/DB.cc
@@ -0,0 +1,208 @@
+#include "DB.h"
+
+using namespace std;
+
+dbVec DB::readSqlToVec(const string& s)
+{
+#if _SQL
+	int cols, step;
+	dbVec results;
+	if (sqlite3_prepare(db, (const char*)s.c_str(), -1, &stmt, NULL) != SQLITE_OK)
+		exit(EXIT_FAILURE);
+	cols = sqlite3_column_count(stmt);
+	while (true) {
+		dbVars temp;
+		step = sqlite3_step(stmt);
+		if (step == SQLITE_ROW) {
+			for (int i=0; i<cols; i++)
+				temp.push_back(
+					(sqlite3_column_text(stmt, i) != NULL) ? string((const char*)sqlite3_column_text(stmt, i)) : ""
+				);
+			results.push_back(temp);
+		} else if (step == SQLITE_DONE) {
+			break;
+		} else {
+			exit(EXIT_FAILURE);
+		}
+	}
+	sqlite3_finalize(stmt);
+	return results;
+#else
+	(void)s;
+	return dbVec();
+#endif
+}
+
+string DB::getProperTableName(const string& table)
+{
+	string temp = table;
+	replace(temp.begin(), temp.end(), '-', '_');
+	return temp;
+}
+
+void DB::createTables()
+{
+	stringstream sst;
+	sst
+		<< "\
+create table if not exists Species (\
+species_name text primary key);\
+create table if not exists Strains (\
+strain_name text primary key,species_name text,\
+foreign key(species_name) references Species(species_name));\
+create table if not exists Libraries (\
+library_name text primary key,strain_name text,\
+foreign key(strain_name) references Strains(strain_name));\
+create table if not exists Run_pe (\
+run_id text primary key,species_name text,strain_name text,library_name text,abyss_version text,\
+pe_name text,pe_k integer,pe_lib text,\
+time_start_run not null default (datetime(current_timestamp,'localtime')),stage integer default 0,\
+foreign key(library_name) references Libraries(library_name));";
+
+	if (query(sst.str()) && verbose_val > 2)
+		cerr << sst.str() << endl;
+}
+
+void DB::insertToMetaTables(const dbVars& v)
+{
+	stringstream sst;
+	sst
+		<< "\
+insert or ignore into species values('" << v[3] << "');\
+insert or ignore into strains values('" << v[2] << "','" << v[3] << "');\
+insert or ignore into libraries values('" << v[1] << "','" << v[2] << "');\
+insert into run_pe(run_id,species_name,strain_name,library_name,abyss_version,pe_name,pe_k,pe_lib) \
+values('" << v[0] << "','" << v[3] << "','" << v[2] << "','" << v[1] << "','" << VERSION << "','" << v[4] <<
+ "','" << v[5] << "','" << v[6] << "');";
+
+	if (query(sst.str()) && verbose_val > 1)
+		cerr << sst.str() << endl;
+}
+
+string DB::initializeRun()
+{
+	string id("");
+	createTables();
+	ifstream ifile("db.txt");
+	if (ifile) {
+		dbVars iV;
+		string eachLine;
+		while (getline(ifile, eachLine)) iV.push_back(eachLine);
+		if (iV.size() == 7) {
+			insertToMetaTables(iV);
+			ofstream ofile("db.txt");
+			ofile << iV[0] << "\n";
+		}
+		stringstream uStream;
+		uStream
+			<< "update Run_pe set stage=stage+1 where run_id = '" << iV[0] << "';";
+		if (query (uStream.str()) && verbose_val > 2)
+			cerr << uStream.str() << endl;
+		id = iV[0];
+	}
+	return id;
+}
+
+/** Execute the specified shell command and exit if it fails. */
+static inline void systemOrExit(const char* s)
+{
+	int status = system(s);
+	if (status != 0) {
+		std::cerr << "error: status " << status << ": " << s << '\n';
+		exit(EXIT_FAILURE);
+	}
+}
+
+string DB::getPath(const string& program)
+{
+	stringstream echoStream, pathStream;
+	echoStream
+		<< "echo `which " << program << "` > temp.txt";
+	systemOrExit(echoStream.str().c_str());
+	ifstream ifile("temp.txt");
+	if (ifile) {
+		string line;
+		while (getline (ifile, line)) pathStream << line;
+	}
+	systemOrExit("rm -f temp.txt");
+	return pathStream.str();
+}
+
+bool DB::definePeVars(const string& id)
+{
+	bool defined = false;
+	stringstream select_cmd;
+	select_cmd
+		<< "select species_name, strain_name, library_name from Run_pe where run_id = '" << id << "';";
+	dbVec v;
+	v = readSqlToVec(select_cmd.str());
+	if (v[0].size() == peVars.size()) {
+		unsigned i = 0;
+		while (i<v[0].size()) {
+			peVars[i] = v[0][i];
+			i++;
+		}
+		defined = true;
+	}
+	return defined;
+}
+
+void DB::assemblyStatsToDb()
+{
+	string temp = getProperTableName(prog);
+	stringstream sqlStream, mapKeys, mapValues;
+	string id = initializeRun();
+
+	if (temp == "ABYSS" || temp == "ABYSS_P")
+		temp = "ABYSS_assembly";
+
+	sqlStream
+		<< "\
+create table if not exists " << temp << " (\
+run_id text default null, run_stage integer default null, species_name text, strain_name text, library_name text, \
+exec_path text, command_line text, time_finish_" << temp << " not null default (datetime(current_timestamp,'localtime')), ";
+
+	mapKeys
+		<< "run_id, run_stage, species_name, strain_name, library_name, exec_path, command_line, ";
+
+	if (id.length() == 0)
+		mapValues
+			<< "null,null,";
+	else
+		mapValues
+			<< "'" << id << "',(select stage from Run_pe where run_id = '" << id << "'),";
+
+	if ((id.length() > 0) && definePeVars(id))
+		mapValues
+			<< "'" << peVars[0] << "', '" << peVars[1] << "', '" << peVars[2] << "', '";
+	else
+		mapValues
+			<< "'" << initVars[2] << "', '" << initVars[1] << "', '" << initVars[0] << "', '";
+
+	mapValues
+		<< getPath(prog)
+		<< "', '" << cmd << "', ";
+
+	while (!statMap.empty()) {
+		mapKeys
+			<< statMap.getFirst(statMap.begin())
+			<< (statMap.size() == 1 ? "" : ", ");
+		mapValues
+			<< statMap.getSecond(statMap.begin())
+			<< (statMap.size() == 1 ? "" : ", ");
+		sqlStream
+			<< statMap.getFirst(statMap.begin())
+			<< (statMap.size() == 1 ? " int, foreign key(run_id) references Run_pe(run_id));" : " int, ");
+		statMap.erase(statMap.begin());
+	}
+
+	if (query(sqlStream.str()) && verbose_val > 1)
+		cerr << sqlStream.str() << endl;
+
+	sqlStream.str("");
+	sqlStream
+		<< "insert into "<< temp << " (" << mapKeys.str() << ") values (" << mapValues.str() << ");";
+
+	if (query(sqlStream.str()) && verbose_val > 0)
+		cerr << sqlStream.str() << endl;
+}
diff --git a/DataBase/DB.h b/DataBase/DB.h
new file mode 100644
index 0000000..438c89e
--- /dev/null
+++ b/DataBase/DB.h
@@ -0,0 +1,227 @@
+/**
+ * A SQLite3 interface
+ */
+
+#ifndef DB_H
+#define DB_H 1
+
+#include "Common/InsOrderedMap.h"
+#include "config.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+#if _SQL
+# include <sqlite3.h>
+#endif
+
+typedef std::vector<std::vector<std::string> > dbVec; // for output
+typedef InsOrderedMap<std::string,int> dbMap; // for input
+typedef std::vector<std::string> dbVars;
+
+class DB {
+private:
+
+	dbMap statMap;
+	dbVars initVars, peVars;
+#if _SQL
+	sqlite3* db;
+	sqlite3_stmt* stmt;
+#else
+	void* db;
+	void* stmt;
+#endif
+	std::string prog, cmd;
+	int exp;
+
+	// Verbosity inherited from the equivalent abyss-pe option.
+	int verbose_val;
+
+	std::string getSqliteName()
+	{
+		std::string name("dummy"); // for a program running outside of abyss-pe
+		std::fstream fl("name.txt");
+		if (fl)
+			fl >> name;
+		return name;
+	}
+
+	void openDB(
+			const char* c, const int& v)
+	{
+#if _SQL
+		verbose_val = v;
+		if (sqlite3_open(c, &db)) {
+			std::cerr << "[" << prog << "] Can't open DB.\n";
+			exit(EXIT_FAILURE);
+		} else {
+			if (verbose_val >= 2 && exp != READ)
+				std::cerr << "[" << prog << "] DB opened.\n";
+		}
+#else
+		(void)v;
+		(void)c;
+#endif
+	}
+
+	static int callback(
+			void* info, int argc, char** argv, char** colName)
+	{
+		int i;
+		std::cerr << (const char*)info << std::endl;
+		for (i=0; i<argc; i++) {
+			std::cerr << "%s = %s\n" << colName[i] << (argv[i] ? argv[i] : "NULL");
+		}
+		std::cerr << "\n";
+		return 0;
+	}
+
+	static unsigned int getRand()
+	{
+		srand(time(NULL));
+		return(rand() % 2000 + 200); // milliseconds
+	}
+
+	void closeDB()
+	{
+#if _SQL
+		if (sqlite3_close(db)) {
+			std::cerr << "[" << prog << "] Can't close DB.\n";
+			exit(EXIT_FAILURE);
+		} else {
+			if (verbose_val >= 2 && exp != READ)
+				std::cerr << "[" << prog << "] DB closed.\n";
+		}
+#else
+		return;
+#endif
+	}
+
+	void createTables();
+	void insertToMetaTables(const dbVars&);
+	std::string initializeRun();
+	std::string getPath(const std::string&);
+	bool definePeVars(const std::string&);
+	void assemblyStatsToDb();
+
+public:
+
+	enum { NO_INIT, INIT, READ };
+
+	DB()
+	{
+		initVars.resize(3);
+		peVars.resize(3);
+		exp = NO_INIT;
+	}
+
+	~DB()
+	{
+		if (exp == INIT)
+			assemblyStatsToDb();
+		if (exp != NO_INIT)
+			closeDB();
+	}
+
+	friend void init(
+			DB& d, const std::string& path)
+	{
+#if _SQL
+		d.exp = READ;
+		d.openDB(path.c_str(), 0);
+#else
+		(void)d;
+		(void)path;
+		std::cerr << "error: `db` parameter has been used, but ABySS has not been configured to support SQLite.\n";
+		exit(EXIT_FAILURE);
+#endif
+	}
+
+	friend void init(
+			DB& d,
+			const std::string& path,
+			const int& v,
+			const std::string& program,
+			const std::string& command,
+			const dbVars& vars)
+	{
+#if _SQL
+		d.prog = program;
+		d.cmd = command;
+		d.initVars = vars;
+		d.exp = INIT;
+
+		std::string name(d.getSqliteName());
+		d.openDB(path.empty() ? name.c_str() : path.c_str(), v);
+#else
+		(void)d;
+		(void)path;
+		(void)v;
+		(void)program;
+		(void)command;
+		(void)vars;
+		std::cerr << "error: `db` parameter has been used, but ABySS has not been configured to support SQLite.\n";
+		exit(EXIT_FAILURE);
+#endif
+	}
+
+	std::string activateForeignKey(const std::string& s)
+	{
+		std::string s_pragma("pragma foreign_keys=on; ");
+		return s_pragma += s;
+	}
+
+	bool query(const std::string& s)
+	{
+#if _SQL
+		int rc;
+		unsigned long int n;
+		char* errMsg = 0;
+		std::string new_s(activateForeignKey(s));
+		const char* statement = new_s.c_str();
+		n = 1;
+		do {
+			rc = sqlite3_exec(db, statement, callback, 0, &errMsg);
+			if (rc == SQLITE_OK)
+				return true;
+			n++;
+			usleep(getRand());
+		} while (rc == SQLITE_BUSY && n < 30000000); // adhoc timeout
+		if (rc != SQLITE_OK) {
+			std::cerr << "[" << prog << "] SQL error: " << errMsg << std::endl;
+			sqlite3_free(errMsg);
+			exit(EXIT_FAILURE);
+		}
+#else
+	(void)s;
+#endif
+		return true;
+	}
+
+	friend void addToDb(
+			DB& d, const std::string& key, const int& value)
+	{
+		d.statMap.push_back(key, value);
+	}
+
+	friend void addToDb(
+			DB& d, dbMap m)
+	{
+		d.statMap.insert(m.getAC());
+		m.clear();
+	}
+
+	dbVec readSqlToVec(const std::string&);
+	std::string getProperTableName(const std::string&);
+};
+
+#endif
diff --git a/DataBase/Makefile.am b/DataBase/Makefile.am
new file mode 100644
index 0000000..e4c7cca
--- /dev/null
+++ b/DataBase/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LIBRARIES = libdb.a
+libdb_a_SOURCES = DB.cc DB.h Options.h
+libdb_a_CPPFLAGS = -I$(top_srcdir)
+libdb_a_LIBADD = $(top_builddir)/Common/libcommon.a
+
+bin_PROGRAMS = abyss-db-csv
+abyss_db_csv_SOURCES = DB.cc DB.h db-csv.cc
+abyss_db_csv_CPPFLAGS = -I$(top_srcdir)
+abyss_db_csv_LDADD = -lsqlite3
+
+dist_bin_SCRIPTS = abyss-db-txt
diff --git a/DataBase/Options.h b/DataBase/Options.h
new file mode 100644
index 0000000..b225c85
--- /dev/null
+++ b/DataBase/Options.h
@@ -0,0 +1,22 @@
+#ifndef OPTIONS_H
+#define OPTIONS_H 1
+
+#include <string>
+#include <sstream>
+#include <iterator>
+
+namespace opt {
+	extern std::string db;
+
+	std::string getCommand(
+			int argc, char* const* argv)
+	{
+		std::ostringstream command;
+		char* const* last = argv + argc -1;
+		copy(argv, last, std::ostream_iterator<const char*>(command, " "));
+		command << *last;
+		return command.str();
+	}
+}
+
+#endif
diff --git a/DataBase/abyss-db-txt b/DataBase/abyss-db-txt
new file mode 100755
index 0000000..56d0776
--- /dev/null
+++ b/DataBase/abyss-db-txt
@@ -0,0 +1,35 @@
+#! /bin/sh
+
+set -eu
+
+if [ $# != 1 ]
+then
+	echo -e "usage:\nabyss-db-txt SQLite_repository"
+	exit 1
+fi
+
+txt_filename=$1.txt
+rm -f $txt_filename
+
+tableArray=()
+sqlite3 $1 "select name from sqlite_master where type='table' order by rootpage;" > temp
+while read line
+do
+	tableArray+=(`echo ${line} | tr " " "\n"`)
+done < temp
+rm -f temp
+
+if [ ${#tableArray[@]} -gt 0 ]
+then
+	for table in ${tableArray[@]}
+	do
+		echo -e "${table}\n" >> $txt_filename
+		echo -e ".mode column\n.headers on\n.output ${table}\nselect * from ${table};\n.q" > $table
+		sqlite3 $1 < $table
+		cat $table >> $txt_filename
+		echo -e "\n\n" >> $txt_filename
+		rm -f $table
+	done
+	echo -e "Done! Check ${txt_filename} now."
+	exit 0
+fi
diff --git a/DataBase/db-csv.cc b/DataBase/db-csv.cc
new file mode 100644
index 0000000..05cac19
--- /dev/null
+++ b/DataBase/db-csv.cc
@@ -0,0 +1,124 @@
+/**
+ * Populate SQLite database table(s) and export to CSV
+ */
+
+#include "DB.h"
+#include <string.h>
+
+using namespace std;
+
+static const char USAGE_MESSAGE[] =
+"usage:\
+\nabyss-db-csv SQLite_repository table_name(s)\
+\nabyss-db-csv SQLite_repository --all\n";
+
+static const char TABLE_LIST[] =
+"select name from sqlite_master where type='table';";
+
+typedef vector<string> vs;
+
+static bool existFile(const char* f)
+{
+	ifstream file(f);
+	return file;
+}
+
+template <typename D>
+static bool existTable(
+		D& db, const string& t)
+{
+	dbVec v = db.readSqlToVec(TABLE_LIST);
+	unsigned i = 0;
+
+	while (i<v.size()) {
+		if (t == v[i][0])
+			return true;
+		i++;
+	}
+	return false;
+}
+
+template  <typename D>
+static string createCSV(
+		D& db, const string& t, const string& csv)
+{
+	ofstream csvf(csv.c_str());
+	stringstream ps, ss, msg;
+	string pstr, sstr;
+	dbVec head, val;
+
+	ps << "pragma table_info (" << t << ");";
+	pstr = ps.str();
+	head = db.readSqlToVec(pstr.c_str());
+
+	for (unsigned i=0; i<head.size(); i++)
+		csvf << head[i][1] << ((i == (head.size()-1)) ? "" : ",");
+	csvf << endl;
+
+	ss << "select * from " << t << ";";
+	sstr = ss.str();
+	val = db.readSqlToVec(sstr.c_str());
+
+	for (unsigned i=0; i<val.size(); i++) {
+		for (unsigned j=0; j<val[i].size(); j++)
+			csvf << val[i][j] << ((j == (val[i].size()-1)) ? "" : ",");
+		csvf << endl;
+	}
+	msg << csv << " has been created.\n";
+	return msg.str();
+}
+
+template <typename D>
+static void populateOneTable(
+		D& db, const string& repo, const string& t)
+{
+	string tt(db.getProperTableName(t));
+	stringstream csv;
+	csv << "db." << tt << ".csv";
+
+	if (!existTable(db, tt)) {
+		cout << "Table " << "'" <<
+			tt << "' doesn't exist in " << repo << "." << endl;
+		cout << USAGE_MESSAGE;
+		exit(EXIT_FAILURE);
+	}
+	cout << createCSV(db, tt, csv.str());
+}
+
+template <typename D>
+static void populateAll(
+		D& db, const string& repo)
+{
+	dbVec v = db.readSqlToVec(TABLE_LIST);
+
+	for (unsigned i=0; i<v.size(); i++)
+		populateOneTable(db, repo, v[i][0]);
+}
+
+int main(int argc, char** argv)
+{
+	if (argc < 3) {
+		cout << USAGE_MESSAGE;
+		exit(EXIT_FAILURE);
+	} else if (!existFile(argv[1])) {
+		cout << "Database file " << "'" <<
+			argv[1] << "' doesn't exist." << endl;
+		cout << USAGE_MESSAGE;
+		exit(EXIT_FAILURE);
+	} else {
+		DB db;
+		init(db, argv[1]);
+
+		if (argc == 3 && strcmp(argv[2], "--all") == 0) {
+			populateAll(db, argv[1]);
+			exit(EXIT_SUCCESS);
+		}
+
+		vs t(argc-2);
+		char** last = argv + argc;
+		copy(argv+2, last, t.begin());
+
+		for (unsigned i=0; i<t.size(); i++)
+			populateOneTable(db, argv[1], t[i]);
+	}
+}
diff --git a/DataLayer/FastaReader.cpp b/DataLayer/FastaReader.cpp
index a0626bb..be49e21 100644
--- a/DataLayer/FastaReader.cpp
+++ b/DataLayer/FastaReader.cpp
@@ -1,6 +1,6 @@
-#include "FastaReader.h"
+#include "Common/IOUtil.h"
+#include "DataLayer/FastaReader.h"
 #include "DataLayer/Options.h"
-#include "IOUtil.h"
 #include <algorithm>
 #include <cassert>
 #include <cctype>
diff --git a/DataLayer/FastaReader.h b/DataLayer/FastaReader.h
index c0cafeb..d9ce16f 100644
--- a/DataLayer/FastaReader.h
+++ b/DataLayer/FastaReader.h
@@ -1,8 +1,8 @@
 #ifndef FASTAREADER_H
 #define FASTAREADER_H 1
 
-#include "Sequence.h"
-#include "StringUtil.h" // for chomp
+#include "Common/Sequence.h"
+#include "Common/StringUtil.h" // for chomp
 #include <cassert>
 #include <cstdlib> // for exit
 #include <fstream>
diff --git a/DataLayer/FastaWriter.h b/DataLayer/FastaWriter.h
index 6dc68fe..b13b365 100644
--- a/DataLayer/FastaWriter.h
+++ b/DataLayer/FastaWriter.h
@@ -1,7 +1,7 @@
 #ifndef FASTAWRITER_H
 #define FASTAWRITER_H 1
 
-#include "Sequence.h"
+#include "Common/Sequence.h"
 #include <cstdio>
 
 /** Output a FASTA file. */
diff --git a/DataLayer/Makefile.am b/DataLayer/Makefile.am
index 3106695..5edac70 100644
--- a/DataLayer/Makefile.am
+++ b/DataLayer/Makefile.am
@@ -1,24 +1,21 @@
 bin_PROGRAMS = abyss-fac abyss-tofastq
 noinst_LIBRARIES = libdatalayer.a
 
-abyss_fac_CPPFLAGS = -I$(top_srcdir) \
-	-I$(top_srcdir)/Common
+abyss_fac_CPPFLAGS = -I$(top_srcdir)
 
 abyss_fac_LDADD = libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
 abyss_fac_SOURCES = fac.cc
 
-abyss_tofastq_CPPFLAGS = -I$(top_srcdir) \
-	-I$(top_srcdir)/Common
+abyss_tofastq_CPPFLAGS = -I$(top_srcdir)
 
 abyss_tofastq_LDADD = libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
 abyss_tofastq_SOURCES = abyss-tofastq.cc
 
-libdatalayer_a_CPPFLAGS = -I$(top_srcdir) \
-	-I$(top_srcdir)/Common
+libdatalayer_a_CPPFLAGS = -I$(top_srcdir)
 
 libdatalayer_a_SOURCES = \
 	FastaIndex.h \
diff --git a/DataLayer/abyss-tofastq.cc b/DataLayer/abyss-tofastq.cc
index 1b88232..b1dd393 100644
--- a/DataLayer/abyss-tofastq.cc
+++ b/DataLayer/abyss-tofastq.cc
@@ -2,11 +2,11 @@
  * Written by Shaun Jackman <sjackman at bcgsc.ca>.
  */
 #include "config.h"
+#include "Common/IOUtil.h"
+#include "Common/Uncompress.h"
+#include "DataLayer/FastaInterleave.h"
+#include "DataLayer/FastaReader.h"
 #include "DataLayer/Options.h"
-#include "FastaInterleave.h"
-#include "FastaReader.h"
-#include "IOUtil.h"
-#include "Uncompress.h"
 #include <algorithm>
 #include <cassert>
 #include <cstdlib>
diff --git a/DataLayer/fac.cc b/DataLayer/fac.cc
index 4d26c0b..f03af8f 100644
--- a/DataLayer/fac.cc
+++ b/DataLayer/fac.cc
@@ -5,9 +5,9 @@
 #include "Common/Histogram.h"
 #include "Common/IOUtil.h"
 #include "Common/Sequence.h" // for isACGT
+#include "Common/Uncompress.h"
 #include "DataLayer/FastaReader.h"
 #include "DataLayer/Options.h"
-#include "Uncompress.h"
 #include <algorithm>
 #include <getopt.h>
 #include <iostream>
@@ -108,7 +108,7 @@ static void printContiguityStatistics(const char* path)
 		cout << "||"
 			<< "n" << sep
 			<< "n:" << opt::minLength << sep
-			<< "n:N50" << sep;
+			<< "L50" << sep;
 		if (opt::expSize > 0)
 			cout << "n:NG50" << sep
 				<< "NG50" << sep;
@@ -125,7 +125,7 @@ static void printContiguityStatistics(const char* path)
 		const char* sep = "\t|";
 		cout << "n" << sep
 			<< "n:" << opt::minLength << sep
-			<< "n:N50" << sep;
+			<< "L50" << sep;
 		if (opt::expSize > 0)
 			cout << "n:NG50" << sep
 				<< "NG50" << sep;
diff --git a/DistanceEst/DistanceEst.cpp b/DistanceEst/DistanceEst.cpp
index f366d5a..472b462 100644
--- a/DistanceEst/DistanceEst.cpp
+++ b/DistanceEst/DistanceEst.cpp
@@ -15,19 +15,20 @@
 #include <getopt.h>
 #include <iomanip>
 #include <iostream>
-#include <iterator> // for istream_iterator
 #include <limits> // for numeric_limits
-#include <sstream>
-#include <string>
 #include <vector>
 #if _OPENMP
 # include <omp.h>
 #endif
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 
 #define PROGRAM "DistanceEst"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Jared Simpson and Shaun Jackman.\n"
@@ -66,6 +67,10 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for sqlite\n"
+"      --strain=NAME     specify strain NAME for sqlite\n"
+"      --species=NAME    specify species NAME for sqlite\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
@@ -73,6 +78,8 @@ static const char USAGE_MESSAGE[] =
 enum { MLE, MEAN };
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k; // used by Estimate.h
 
 	/** Output graph format. */
@@ -102,8 +109,12 @@ namespace opt {
 static const char shortopts[] = "j:k:l:n:o:q:s:v";
 
 enum { OPT_HELP = 1, OPT_VERSION,
-	OPT_MIND, OPT_MAXD, OPT_FR, OPT_RF
+	OPT_MIND, OPT_MAXD, OPT_FR, OPT_RF,
+	OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES
 };
+//enum { OPT_HELP = 1, OPT_VERSION,
+//	OPT_MIND, OPT_MAXD, OPT_FR, OPT_RF
+//};
 
 static const struct option longopts[] = {
 	{ "dist",        no_argument,       &opt::format, DIST, },
@@ -120,10 +131,14 @@ static const struct option longopts[] = {
 	{ "out",         required_argument, NULL, 'o' },
 	{ "min-mapq",    required_argument, NULL, 'q' },
 	{ "seed-length", required_argument, NULL, 's' },
-	{ "threads",     required_argument,	NULL, 'j' },
+	{ "threads",     required_argument, NULL, 'j' },
 	{ "verbose",     no_argument,       NULL, 'v' },
 	{ "help",        no_argument,       NULL, OPT_HELP },
 	{ "version",     no_argument,       NULL, OPT_VERSION },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -210,7 +225,7 @@ static int estimateDistance(unsigned len0, unsigned len1,
 	for (Fragments::const_iterator it = fragments.begin();
 			it != fragments.end(); ++it) {
 		int x = it->second - it->first;
-		if (!opt::rf && opt::method == MLE 
+		if (!opt::rf && opt::method == MLE
 				&& x <= 2 * int(ma - 1)) {
 			unsigned align = x / 2;
 			if (opt::verbose > 0)
@@ -369,6 +384,9 @@ static void readPairs(It& it, const It& last, vector<SAMRecord>& out)
 
 int main(int argc, char** argv)
 {
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -397,6 +415,14 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db; break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0]; break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1]; break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -445,6 +471,16 @@ int main(int argc, char** argv)
 		omp_set_num_threads(opt::threads);
 #endif
 
+	if (!opt::db.empty()) {
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars
+		);
+	}
+
 	string distanceCountFile(argv[optind++]);
 	string alignFile(argv[optind] == NULL ? "-" : argv[optind++]);
 
@@ -467,6 +503,16 @@ int main(int argc, char** argv)
 			"s=" << opt::seedLen << " "
 			"n=" << opt::npairs << "]\n";
 
+	vector<int> vals = make_vector<int>()
+		<< opt::k
+		<< opt::seedLen
+		<< opt::npairs;
+
+	vector<string> keys = make_vector<string>()
+		<< "K"
+		<< "SeedLen"
+		<< "NumPairs";
+
 	// The fragment size histogram may not be written out until after
 	// the alignments complete. Wait for the alignments to complete.
 	in.peek();
@@ -488,6 +534,14 @@ int main(int argc, char** argv)
 			<< ".\n";
 	}
 
+	vals += make_vector<int>()
+		<< numFR
+		<< numRF;
+
+	keys += make_vector<string>()
+		<< "FR_orientation"
+		<< "RF_orientation";
+
 	// Determine the orientation of the library.
 	if (opt::rf == -1)
 		opt::rf = libRF;
@@ -521,9 +575,37 @@ int main(int argc, char** argv)
 			<< opt::minDist << " and " << opt::maxDist << " bp.\n";
 	assert(opt::minDist < opt::maxDist);
 
+	vals += make_vector<int>()
+		<< opt::minDist
+		<< opt::maxDist
+		<< (int)round(h.mean())
+		<< h.median()
+		<< (int)round(h.sd())
+		<< h.size()
+		<< h.minimum()
+		<< h.maximum();
+
+	keys += make_vector<string>()
+		<< "minDist"
+		<< "maxDist"
+		<< "mean"
+		<< "median"
+		<< "sd"
+		<< "n"
+		<< "min"
+		<< "max";
+
 	// Read the contig lengths.
 	vector<unsigned> contigLens;
-	readContigLengths(in, contigLens);
+
+	vals += make_vector<int>()
+		<< readContigLengths(in, contigLens);
+
+	keys += make_vector<string>()
+		<< "CntgCounted";
+
+//	readContigLengths(in, contigLens);
+
 	g_contigNames.lock();
 
 	// Estimate the distances between contigs.
@@ -553,11 +635,24 @@ int main(int argc, char** argv)
 			<< stats.dup_frags << "/"
 			<< stats.total_frags << " ("
 			<< setprecision(3) << prop_dups << "%)\n";
-		if (prop_dups > 0.5)
+		if (prop_dups > 50)
 			cerr << PROGRAM << ": warning: duplicate rate of fragments "
 				"spanning more than one contig is high.\n";
 	}
 
+	vals += make_vector<int>()
+		<< stats.total_frags
+		<< stats.dup_frags;
+
+		keys += make_vector<string>()
+			<< "total_frags"
+			<< "dupl_frags";
+
+	if (!opt::db.empty()) {
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
+
 	if (opt::verbose > 0 && g_recMA != opt::minAlign)
 		cerr << PROGRAM << ": warning: MLE will be more accurate if "
 			"l is decreased to " << g_recMA << ".\n";
diff --git a/DistanceEst/MLE.cpp b/DistanceEst/MLE.cpp
index 9898e2e..d7562c2 100644
--- a/DistanceEst/MLE.cpp
+++ b/DistanceEst/MLE.cpp
@@ -37,6 +37,43 @@ class WindowFunction {
 		int x1, x2, x3;
 };
 
+/** This is a normalized zero-phase Hann window function with
+ * specified size. */
+class HannWindow {
+	public:
+		HannWindow(int size) : size(size)
+		{
+			sum = getSum();
+		}
+
+		/** Return normalized Hann window value at i centered at 0. */
+		double operator()(int i) const
+		{
+			return value(i + size/2) / sum;
+		}
+
+		/** Return the Hann window value at i. */
+		double value(int i) const
+		{
+			if (i < 0 || i >= size)
+				return 0;
+			return 0.5 * (1 - cos(2 * M_PI * i/(size - 1)));
+		}
+
+		/** Get the sum of all values in this window. */
+		double getSum()
+		{
+			double sum = 0;
+			for (int i = 0; i < size; i++)
+				sum += value(i);
+			return sum;
+		}
+
+	private:
+		double sum;
+		int size;
+};
+
 /** Compute the log likelihood that these samples came from the
  * specified distribution shifted by the parameter theta.
  * @param theta the parameter of the PMF, f_theta(x)
@@ -68,8 +105,9 @@ maximumLikelihoodEstimate(int first, int last,
 		const PMF& pmf,
 		unsigned len0, unsigned len1)
 {
-	first = max(first, (int)pmf.minValue() - samples.maximum());
-	last = min(last, (int)pmf.maxValue() - samples.minimum());
+	int filterSize = 2 * (int)(0.05 * pmf.mean()) + 3; // want an odd filter size
+	first = max(first, (int)pmf.minValue() - samples.maximum()) - filterSize/2;
+	last = min(last, (int)pmf.maxValue() - samples.minimum()) + filterSize/2 + 1;
 
 	/* When randomly selecting fragments that span a given point,
 	 * longer fragments are more likely to be selected than
@@ -81,6 +119,9 @@ maximumLikelihoodEstimate(int first, int last,
 	double bestLikelihood = -numeric_limits<double>::max();
 	int bestTheta = first;
 	unsigned bestn = 0;
+	vector<double> le;
+	vector<unsigned> le_n;
+	vector<int> le_theta;
 	for (int theta = first; theta <= last; theta++) {
 		// Calculate the normalizing constant of the PMF, f_theta(x).
 		double c = 0;
@@ -91,10 +132,23 @@ maximumLikelihoodEstimate(int first, int last,
 		unsigned n;
 	   	tie(likelihood, n) = computeLikelihood(theta, samples, pmf);
 		likelihood -= nsamples * log(c);
-		if (n > 0 && likelihood > bestLikelihood) {
+		le.push_back(likelihood);
+		le_n.push_back(n);
+		le_theta.push_back(theta);
+	}
+
+	HannWindow filter(filterSize);
+	for (int i = filterSize / 2; i < (int)le.size()-(filterSize / 2); i++) {
+		double likelihood = 0;
+		for (int j = -filterSize / 2; j <= filterSize / 2; j++) {
+			assert((unsigned)(i + j) < le.size() && i + j >= 0);
+			likelihood += filter(j) * le[i + j];
+		}
+
+		if (le_n[i] > 0 && likelihood > bestLikelihood) {
 			bestLikelihood = likelihood;
-			bestTheta = theta;
-			bestn = n;
+			bestTheta = le_theta[i];
+			bestn = le_n[i];
 		}
 	}
 	return make_pair(bestTheta, bestn);
diff --git a/DistanceEst/Makefile.am b/DistanceEst/Makefile.am
index d8edde0..b0ef627 100644
--- a/DistanceEst/Makefile.am
+++ b/DistanceEst/Makefile.am
@@ -6,6 +6,8 @@ DistanceEst_CPPFLAGS = -I$(top_srcdir) \
 DistanceEst_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
 
 DistanceEst_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/Common/libcommon.a
 
 DistanceEst_SOURCES = DistanceEst.cpp MLE.cpp MLE.h
diff --git a/FilterGraph/FilterGraph.cpp b/FilterGraph/FilterGraph.cc
similarity index 65%
rename from FilterGraph/FilterGraph.cpp
rename to FilterGraph/FilterGraph.cc
index 2067894..423a0f3 100644
--- a/FilterGraph/FilterGraph.cpp
+++ b/FilterGraph/FilterGraph.cc
@@ -43,40 +43,46 @@ PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n";
 
 static const char USAGE_MESSAGE[] =
-"Usage: " PROGRAM " -k<kmer> [OPTION]... ADJ\n"
+"Usage: " PROGRAM " -k<kmer> [OPTION]... ADJ [FASTA]\n"
 "Remove short contigs that do not contribute any relevant\n"
 "information to the assembly.\n"
 "\n"
 " Arguments:\n"
 "\n"
 "  ADJ    contig adjacency graph\n"
+"  FASTA  contigs to check consistency of ADJ edges\n"
 "\n"
 " Options:\n"
 "\n"
-"  -k, --kmer=N          k-mer size\n"
-"      --SS              expect contigs to be oriented correctly\n"
-"      --no-SS           no assumption about contig orientation\n"
-"  -T, --island=N        remove islands shorter than N [0]\n"
-"  -t, --tip=N           remove tips shorter than N [0]\n"
-"  -l, --length=N        remove contigs shorter than N [0]\n"
-"  -L, --max-length=N    remove contigs longer than N [0]\n"
-"      --shim            remove filler contigs that only contribute\n"
-"                        to adjacency [default]\n"
-"      --no-shim         disable filler contigs removal\n"
-"  -m, --min-overlap=N   require a minimum overlap of N bases [10]\n"
-"      --assemble        assemble unambiguous paths\n"
-"      --no-assemble     disable assembling of paths [default]\n"
-"  -g, --graph=FILE      write the contig adjacency graph to FILE\n"
-"  -i, --ignore=FILE     ignore contigs seen in FILE\n"
-"  -r, --remove=FILE     remove contigs seen in FILE\n"
-"      --adj             output the graph in adj format [default]\n"
-"      --asqg            output the graph in asqg format\n"
-"      --dot             output the graph in dot format\n"
-"      --dot-meancov     same as above but give the mean coverage\n"
-"      --sam             output the graph in SAM format\n"
-"  -v, --verbose         display verbose output\n"
-"      --help            display this help and exit\n"
-"      --version         output version information and exit\n"
+"  -k, --kmer=N            k-mer size\n"
+"      --SS                expect contigs to be oriented correctly\n"
+"      --no-SS             no assumption about contig orientation\n"
+"  -T, --island=N          remove islands shorter than N [0]\n"
+"  -t, --tip=N             remove tips shorter than N [0]\n"
+"  -l, --length=N          remove contigs shorter than N [0]\n"
+"  -L, --max-length=N      remove contigs longer than N [0]\n"
+"  -c, --coverage=FLOAT    remove contigs with mean k-mer coverage less than FLOAT [0]\n"
+"  -C, --max-coverage=FLOAT remove contigs with mean k-mer coverage at least FLOAT [0]\n"
+"      --shim              remove filler contigs that only contribute\n"
+"                          to adjacency [default]\n"
+"      --no-shim           disable filler contigs removal\n"
+"      --shim-max-degree=N only remove shims where the smaller of \n"
+"                          in/out degree is smaller than N [1]\n"
+"  -m, --min-overlap=N     require a minimum overlap of N bases [10]\n"
+"      --assemble          assemble unambiguous paths\n"
+"      --no-assemble       disable assembling of paths [default]\n"
+"  -g, --graph=FILE        write the contig adjacency graph to FILE\n"
+"  -i, --ignore=FILE       ignore contigs seen in FILE\n"
+"  -r, --remove=FILE       remove contigs seen in FILE\n"
+"      --adj               output the graph in ADJ format [default]\n"
+"      --asqg              output the graph in ASQG format\n"
+"      --dot               output the graph in GraphViz format\n"
+"      --gv                output the graph in GraphViz format\n"
+"      --gfa               output the graph in GFA format\n"
+"      --sam               output the graph in SAM format\n"
+"  -v, --verbose           display verbose output\n"
+"      --help              display this help and exit\n"
+"      --version           output version information and exit\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
@@ -98,9 +104,19 @@ namespace opt {
 	/** Remove all contigs more than this length. */
 	static unsigned maxLen = 0;
 
+	/** Remove contigs with mean k-mer coverage less than this threshold. */
+	static float minCoverage = 0;
+
+	/** Remove contigs with mean k-mer coverage at least this threshold. */
+	static float maxCoverage = 0;
+
 	/** Remove short contigs that don't contribute any sequence. */
 	static int shim = 1;
 
+	/** Only remove shims where the smaller of in/out degree is small
+	 * enough. */
+	static unsigned shimMaxDegree = 1;
+
 	/** Assemble unambiguous paths. */
 	static int assemble = 0;
 
@@ -120,34 +136,38 @@ namespace opt {
 	int format = ADJ; // used by ContigProperties
 }
 
-static const char shortopts[] = "g:i:r:k:l:L:m:t:T:v";
+static const char shortopts[] = "c:C:g:i:r:k:l:L:m:t:T:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_SHIM_MAX_DEG };
 
 static const struct option longopts[] = {
-	{ "adj",           no_argument,       &opt::format, ADJ },
-	{ "asqg",          no_argument,       &opt::format, ASQG },
-	{ "dot",           no_argument,       &opt::format, DOT },
-	{ "dot-meancov",   no_argument,       &opt::format, DOT_MEANCOV },
-	{ "sam",           no_argument,       &opt::format, SAM },
-	{ "graph",         required_argument, NULL, 'g' },
-	{ "ignore",        required_argument, NULL, 'i' },
-	{ "remove",        required_argument, NULL, 'r' },
-	{ "SS",            no_argument,       &opt::ss, 1 },
-	{ "no-SS",         no_argument,       &opt::ss, 0 },
-	{ "kmer",          required_argument, NULL, 'k' },
-	{ "island",        required_argument, NULL, 'T' },
-	{ "tip",           required_argument, NULL, 't' },
-	{ "length",        required_argument, NULL, 'l' },
-	{ "max-length",    required_argument, NULL, 'L' },
-	{ "shim",          no_argument,       &opt::shim, 1 },
-	{ "no-shim",       no_argument,       &opt::shim, 0 },
-	{ "assemble",      no_argument,       &opt::assemble, 1 },
-	{ "no-assemble",   no_argument,       &opt::assemble, 0 },
-	{ "min-overlap",   required_argument, NULL, 'm' },
-	{ "verbose",       no_argument,       NULL, 'v' },
-	{ "help",          no_argument,       NULL, OPT_HELP },
-	{ "version",       no_argument,       NULL, OPT_VERSION },
+	{ "adj",             no_argument,       &opt::format, ADJ },
+	{ "asqg",            no_argument,       &opt::format, ASQG },
+	{ "dot",             no_argument,       &opt::format, DOT },
+	{ "gv",              no_argument,       &opt::format, DOT },
+	{ "gfa",             no_argument,       &opt::format, GFA },
+	{ "sam",             no_argument,       &opt::format, SAM },
+	{ "graph",           required_argument, NULL, 'g' },
+	{ "ignore",          required_argument, NULL, 'i' },
+	{ "remove",          required_argument, NULL, 'r' },
+	{ "SS",              no_argument,       &opt::ss, 1 },
+	{ "no-SS",           no_argument,       &opt::ss, 0 },
+	{ "kmer",            required_argument, NULL, 'k' },
+	{ "island",          required_argument, NULL, 'T' },
+	{ "tip",             required_argument, NULL, 't' },
+	{ "length",          required_argument, NULL, 'l' },
+	{ "max-length",      required_argument, NULL, 'L' },
+	{ "coverage",        required_argument, NULL, 'c' },
+	{ "max-coverage",    required_argument, NULL, 'C' },
+	{ "shim",            no_argument,       &opt::shim, 1 },
+	{ "no-shim",         no_argument,       &opt::shim, 0 },
+	{ "shim-max-degree", required_argument, NULL, OPT_SHIM_MAX_DEG },
+	{ "assemble",        no_argument,       &opt::assemble, 1 },
+	{ "no-assemble",     no_argument,       &opt::assemble, 0 },
+	{ "min-overlap",     required_argument, NULL, 'm' },
+	{ "verbose",         no_argument,       NULL, 'v' },
+	{ "help",            no_argument,       NULL, OPT_HELP },
+	{ "version",         no_argument,       NULL, OPT_VERSION },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -156,6 +176,7 @@ static vector<ContigID> g_removed;
 /** Contig adjacency graph. */
 typedef ContigGraph<DirectedGraph<ContigProperties, Distance> > Graph;
 typedef Graph::vertex_descriptor vertex_descriptor;
+typedef Graph::edge_descriptor edge_descriptor;
 
 /** Data for verbose output. */
 static struct {
@@ -184,15 +205,16 @@ static bool removable(const Graph* pg, vertex_descriptor v)
 		return false;
 	}
 
+	unsigned min_degree = min(out_degree(v, g), in_degree(v, g));
+
 	// Check for tails
-	if (out_degree(v, g) == 0 || in_degree(v, g) == 0) {
+	if (min_degree == 0) {
 		g_count.tails++;
 		return false;
 	}
 
 	// Check that the result will be less complex that the original
-	if (!(out_degree(v, g) == 1 && in_degree(v, g) > 1)
-			&& !(out_degree(v, g) > 1 && in_degree(v, g) == 1)) {
+	if (min_degree > opt::shimMaxDegree) {
 		g_count.too_complex++;
 		return false;
 	}
@@ -271,12 +293,6 @@ static bool findNewEdges(const Graph& g, vertex_descriptor v,
 				marked.push_back(ed.u);
 			if (in_degree(v, g) > 1)
 				marked.push_back(ed.w);
-
-			// Don't remove a vertex if the result is a parallel edge.
-			if (edge(ed.u, ed.w, g).second) {
-				g_count.parallel_edge++;
-				return false;
-			}
 		}
 	}
 	for (vector<V>::const_iterator it = marked.begin();
@@ -290,7 +306,11 @@ static void addNewEdges(Graph& g, const vector<EdgeInfo>& eds)
 {
 	for (vector<EdgeInfo>::const_iterator edsit = eds.begin();
 			edsit != eds.end(); ++edsit) {
-		assert(!edge(edsit->u, edsit->w, g).second);
+		// Don't add parallel edges! This can happen when removing a palindrome.
+		if (edge(edsit->u, edsit->w, g).second) {
+			g_count.parallel_edge++;
+			continue;
+		}
 		assert(edsit->ep.distance <= -opt::minOverlap);
 		add_edge(edsit->u, edsit->w, edsit->ep, g);
 	}
@@ -364,7 +384,7 @@ static void findShortContigs(const Graph& g, const vector<bool>& seen,
 	Vit first, second;
 	tie(first, second) = vertices(g);
 	::copy_if(first, second, back_inserter(sc),
-			!bind(Marked(g, seen), _1) && bind(removable, &g, _1));
+			!boost::lambda::bind(Marked(g, seen), _1) && boost::lambda::bind(removable, &g, _1));
 }
 
 /** Functor used for sorting contigs based on degree, then size,
@@ -419,6 +439,23 @@ struct LongerThanX : unary_function<vertex_descriptor, bool> {
 	}
 };
 
+struct CoverageLessThan : unary_function<vertex_descriptor, bool> {
+	const Graph& g;
+	const vector<bool>& seen;
+	float minCov;
+
+	CoverageLessThan(const Graph& g, const vector<bool>& seen, float minCov)
+		: g(g), seen(seen), minCov(minCov) { }
+
+	bool operator()(vertex_descriptor u) const
+	{
+		assert(opt::k > 0);
+		float meanCoverage = (float)g[u].coverage / (g[u].length - opt::k + 1);
+		return meanCoverage < minCov && !get(vertex_removed, g, u)
+			&& !seen[get(vertex_contig_index, g, u)];
+	}
+};
+
 static void removeShims(Graph& g, const vector<bool>& seen)
 {
 	if (opt::verbose > 0)
@@ -458,7 +495,70 @@ static void removeContigs_if(Graph& g, pred p)
 	transform(sc.begin(), sc.end(), back_inserter(g_removed),
 			mem_fun_ref(&ContigNode::contigIndex));
 	if (opt::verbose > 0)
-		cerr << "Removed " << sc.size()/2 << " short contigs.\n";
+		cerr << "Removed " << sc.size()/2 << " contigs.\n";
+}
+
+/** Contig sequences. */
+typedef vector<const_string> Contigs;
+static Contigs g_contigs;
+
+/** Return the sequence of vertex u. */
+static string getSequence(const Graph& g, vertex_descriptor u)
+{
+	size_t i = get(vertex_contig_index, g, u);
+	assert(i < g_contigs.size());
+	string seq(g_contigs[i]);
+	return get(vertex_sense, g, u) ? reverseComplement(seq) : seq;
+}
+
+/** Return whether the specified edge is inconsistent. */
+struct is_edge_inconsistent : unary_function<edge_descriptor, bool> {
+	const Graph& g;
+
+	is_edge_inconsistent(const Graph& g)
+		: g(g) { }
+
+	bool operator()(edge_descriptor e) const
+	{
+		vertex_descriptor u = source(e, g);
+		vertex_descriptor v = target(e, g);
+
+		int overlap = g[e].distance;
+		assert(overlap < 0);
+
+		string su = getSequence(g, u);
+		string sv = getSequence(g, v);
+		const unsigned u_start = su.length() + overlap;
+
+		for (unsigned i = 0; i < (unsigned)-overlap; i++)
+			if (!(ambiguityToBitmask(su[u_start + i]) & ambiguityToBitmask(sv[i])))
+				return true;
+		return false;
+	}
+};
+
+template <typename It>
+static void remove_edge(Graph& g, It first, It last)
+{
+	for (; first != last; first++)
+		remove_edge(*first, g);
+}
+
+template<typename pred>
+static void removeEdges_if(Graph& g, pred p)
+{
+	typedef graph_traits<Graph> GTraits;
+	typedef GTraits::edge_iterator Eit;
+	typedef GTraits::edge_descriptor E;
+	Eit first, second;
+	tie(first, second) = edges(g);
+	vector<E> sc;
+	::copy_if(first, second, back_inserter(sc), p);
+	remove_edge(g, sc.begin(), sc.end());
+	if (opt::verbose > 0) {
+		cerr << "Edge removal stats:\n";
+		cerr << "Removed: " << sc.size() << '\n';
+	}
 }
 
 int main(int argc, char** argv)
@@ -480,6 +580,12 @@ int main(int argc, char** argv)
 		  case '?':
 			die = true;
 			break;
+		  case 'c':
+			arg >> opt::minCoverage;
+			break;
+		  case 'C':
+			arg >> opt::maxCoverage;
+			break;
 		  case 'l':
 			arg >> opt::minLen;
 			break;
@@ -510,6 +616,9 @@ int main(int argc, char** argv)
 		  case 'v':
 			opt::verbose++;
 			break;
+		  case OPT_SHIM_MAX_DEG:
+			arg >> opt::shimMaxDegree;
+			break;
 		  case OPT_HELP:
 			cout << USAGE_MESSAGE;
 			exit(EXIT_SUCCESS);
@@ -540,7 +649,7 @@ int main(int argc, char** argv)
 		die = true;
 	}
 
-	if (argc - optind > 1) {
+	if (argc - optind > 2) {
 		cerr << PROGRAM ": too many arguments\n";
 		die = true;
 	}
@@ -629,19 +738,48 @@ int main(int argc, char** argv)
 	if (opt::maxLen > 0)
 		removeContigs_if(g, LongerThanX(g, seen, opt::maxLen));
 
+	// Remove contigs with low mean k-mer coverage.
+	if (opt::minCoverage > 0)
+		removeContigs_if(g, CoverageLessThan(g, seen, opt::minCoverage));
+
+	// Remove contigs with high mean k-mer coverage.
+	if (opt::maxCoverage > 0)
+		removeContigs_if(g,
+				std::not1(CoverageLessThan(g, seen, opt::maxCoverage)));
+
+	// Remove inconsistent edges of spaceseeds
+	if (argc - optind == 1) {
+		const char* contigsPath(argv[optind++]);
+		Contigs& contigs = g_contigs;
+		if (opt::verbose > 0)
+			cerr << "Reading `" << contigsPath << "'...\n";
+		FastaReader in(contigsPath, FastaReader::NO_FOLD_CASE);
+		for (FastaRecord rec; in >> rec;) {
+			if (g_contigNames.count(rec.id) == 0)
+				continue;
+			assert(contigs.size() == get(g_contigNames, rec.id));
+			contigs.push_back(rec.seq);
+		}
+		assert(in.eof());
+
+		removeEdges_if(g, is_edge_inconsistent(g));
+	}
+
 	if (opt::verbose > 0) {
 		cerr << "Graph stats after:\n";
 		printGraphStats(cerr, g);
 	}
 
-	sort(g_removed.begin(), g_removed.end());
-	g_removed.erase(unique(g_removed.begin(), g_removed.end()),
-			g_removed.end());
-	for (vector<ContigID>::const_iterator it = g_removed.begin();
-			it != g_removed.end(); ++it)
-		cout << get(g_contigNames, *it) << '\n';
+	// Output the updated adjacency graph.
+	if (!opt::graphPath.empty()) {
+		ofstream fout(opt::graphPath.c_str());
+		assert_good(fout, opt::graphPath);
+		write_graph(fout, g, PROGRAM, commandLine);
+		assert_good(fout, opt::graphPath);
+	}
 
-	// Assemble unambiguous paths.
+	// Assemble unambiguous paths. These need to be assembled by
+	// MergeContigs before being processed by other applications.
 	if (opt::assemble) {
 		size_t numContigs = num_vertices(g) / 2;
 		typedef vector<ContigPath> ContigPaths;
@@ -661,13 +799,5 @@ int main(int argc, char** argv)
 		g_contigNames.lock();
 	}
 
-	// Output the updated adjacency graph.
-	if (!opt::graphPath.empty()) {
-		ofstream fout(opt::graphPath.c_str());
-		assert_good(fout, opt::graphPath);
-		write_graph(fout, g, PROGRAM, commandLine);
-		assert_good(fout, opt::graphPath);
-	}
-
 	return 0;
 }
diff --git a/FilterGraph/Makefile.am b/FilterGraph/Makefile.am
index 61fdb13..a73cb4f 100644
--- a/FilterGraph/Makefile.am
+++ b/FilterGraph/Makefile.am
@@ -10,4 +10,4 @@ abyss_filtergraph_LDADD = \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
-abyss_filtergraph_SOURCES = FilterGraph.cpp
+abyss_filtergraph_SOURCES = FilterGraph.cc
diff --git a/Graph/AllPathsSearch.h b/Graph/AllPathsSearch.h
index af736f7..c7e1296 100644
--- a/Graph/AllPathsSearch.h
+++ b/Graph/AllPathsSearch.h
@@ -1,7 +1,6 @@
 #ifndef ALLPATHS_SEARCH_H_
 #define ALLPATHS_SEARCH_H_
 
-#include "Common/Warnings.h"
 #include "Common/UnorderedSet.h"
 #include "Graph/Path.h"
 #include <boost/tuple/tuple.hpp> // for boost::tie
diff --git a/Graph/AsqgIO.h b/Graph/AsqgIO.h
index a3bc142..8f67e79 100644
--- a/Graph/AsqgIO.h
+++ b/Graph/AsqgIO.h
@@ -33,7 +33,7 @@ std::ostream& write_asqg(std::ostream& out, Graph& g)
 		out << "VT\t" << get(vertex_contig_name, g, u)
 			<< "\t*\tLN:i:" << vp.length;
 		if (vp.coverage > 0)
-			out << "\tXC:i:" << vp.coverage;
+			out << "\tKC:i:" << vp.coverage;
 		out << '\n';
 	}
 
@@ -42,11 +42,16 @@ std::ostream& write_asqg(std::ostream& out, Graph& g)
 		E e = *eit;
 		V u = source(e, g);
 		V v = target(e, g);
-		if (v < u || get(vertex_removed, g, u))
+		if (get(vertex_removed, g, u))
+			continue;
+
+		// Output only the canonical edge.
+		if (u > get(vertex_complement, g, v))
 			continue;
+
 		assert(!get(vertex_removed, g, v));
 		int distance = g[e].distance;
-		assert(distance < 0);
+		assert(distance <= 0);
 		unsigned overlap = -distance;
 		unsigned ulen = g[u].length;
 		unsigned vlen = g[v].length;
@@ -55,10 +60,10 @@ std::ostream& write_asqg(std::ostream& out, Graph& g)
 		out << "ED\t" << get(vertex_contig_name, g, u)
 			<< ' ' << get(vertex_contig_name, g, v)
 			<< ' ' << (usense ? 0 : ulen - overlap)
-			<< ' ' << (usense ? overlap : ulen) - 1
+			<< ' ' << int((usense ? overlap : ulen) - 1)
 			<< ' ' << ulen
 			<< ' ' << (!vsense ? 0 : vlen - overlap)
-			<< ' ' << (!vsense ? overlap : vlen) - 1
+			<< ' ' << int((!vsense ? overlap : vlen) - 1)
 			<< ' ' << vlen
 			<< ' ' << (usense != vsense)
 			<< " -1\n"; // number of mismatches
@@ -98,11 +103,20 @@ std::istream& read_asqg(std::istream& in, Graph& g)
 				assert(in);
 			} else
 				length = seq.size();
+
+			unsigned coverage = 0;
+			if (in.peek() == '\t' && in.get() == '\t' && in.peek() == 'K') {
+				in >> expect("KC:i:") >> coverage;
+				assert(in);
+			}
+
 			in >> Ignore('\n');
+			assert(in);
 
 			if (addVertices) {
 				VP vp;
 				put(vertex_length, vp, length);
+				put(vertex_coverage, vp, coverage);
 				V u = add_vertex(vp, g);
 				put(vertex_name, g, u, uname);
 			} else {
diff --git a/Graph/BidirectionalBFSVisitor.h b/Graph/BidirectionalBFSVisitor.h
index 0e02549..4282f29 100644
--- a/Graph/BidirectionalBFSVisitor.h
+++ b/Graph/BidirectionalBFSVisitor.h
@@ -2,7 +2,6 @@
 #define BIDIRECTION_BFS_VISITOR_H 1
 
 #include "Graph/Path.h"
-#include "Common/Warnings.h"
 
 enum BFSVisitorResult { SUCCESS, ABORT_SEARCH, SKIP_ELEMENT };
 
@@ -13,76 +12,49 @@ public:
 
 	typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
 	typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
+	typedef unsigned NumFrontierNodes;
 
 	BidirectionalBFSVisitor() { }
 	virtual ~BidirectionalBFSVisitor() { }
 
-	virtual BFSVisitorResult discover_vertex(const Vertex& u, const Graph& g, Direction dir, unsigned numFrontierNodes)
+	virtual BFSVisitorResult discover_vertex(const Vertex&, const Graph&, Direction, NumFrontierNodes)
 	{
-		SUPPRESS_UNUSED_WARNING(u);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
-		SUPPRESS_UNUSED_WARNING(numFrontierNodes);
 		return SUCCESS;
 	}
 
-	virtual void examine_vertex(const Vertex& u, const Graph& g, Direction dir)
+	virtual void examine_vertex(const Vertex&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(u);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 	}
 
-	virtual void finish_vertex(const Vertex& u, const Graph& g, Direction dir)
+	virtual void finish_vertex(const Vertex&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(u);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 	}
 
-	virtual void examine_edge(const Edge& e, const Graph& g, Direction dir)
+	virtual void examine_edge(const Edge&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(e);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 	}
 
-	virtual BFSVisitorResult common_edge(const Edge& e, const Graph& g, Direction dir)
+	virtual BFSVisitorResult common_edge(const Edge&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(e);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 		return SUCCESS;
 	}
 
-	virtual BFSVisitorResult tree_edge(const Edge& e, const Graph& g, Direction dir)
+	virtual BFSVisitorResult tree_edge(const Edge&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(e);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 		return SUCCESS;
 	}
 
-	virtual BFSVisitorResult non_tree_edge(const Edge& e, const Graph& g, Direction dir)
+	virtual BFSVisitorResult non_tree_edge(const Edge&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(e);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 		return SUCCESS;
 	}
 
-	virtual void gray_target(const Edge& e, const Graph& g, Direction dir)
+	virtual void gray_target(const Edge&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(e);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 	}
 
-	virtual void black_target(const Edge& e, const Graph& g, Direction dir)
+	virtual void black_target(const Edge&, const Graph&, Direction)
 	{
-		SUPPRESS_UNUSED_WARNING(e);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
 	}
 
 };
diff --git a/Graph/ConstrainedBidiBFSVisitor.h b/Graph/ConstrainedBidiBFSVisitor.h
index 2e030a0..de0c1ad 100644
--- a/Graph/ConstrainedBidiBFSVisitor.h
+++ b/Graph/ConstrainedBidiBFSVisitor.h
@@ -133,15 +133,13 @@ public:
 
 #if 0
 	// for debugging
-	void examine_vertex(const V& v, const G& g, Direction dir)
+	void examine_vertex(const V& v, const G&, Direction dir)
 	{
-		SUPPRESS_UNUSED_WARNING(g);
 		std::cout << "visiting vertex: " << v << " from dir: " << dir << "\n";
 	}
 
 	void examine_edge(const E& e, const G& g, Direction dir)
 	{
-		SUPPRESS_UNUSED_WARNING(g);
 		V u = source(e, g);
 		V v = target(e, g);
 		std::cout << "visiting edge: (" << u << "," << v
@@ -149,13 +147,9 @@ public:
 	}
 #endif
 
-	BFSVisitorResult discover_vertex(const V& v, const G& g,
-			Direction dir, unsigned numActiveBranches)
+	BFSVisitorResult discover_vertex(const V&, const G&,
+			Direction, unsigned numActiveBranches)
 	{
-		SUPPRESS_UNUSED_WARNING(v);
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(dir);
-
 		if (m_maxBranches != NO_LIMIT &&
 			numActiveBranches >= m_maxBranches) {
 			m_tooManyBranches = true;
@@ -312,7 +306,7 @@ protected:
 
 	BFSVisitorResult checkMemLimit()
 	{
-		const size_t MEM_COUNTER_ROLLOVER = 1 / 0.001;
+		const size_t MEM_COUNTER_ROLLOVER = 1000;
 		m_memCheckCounter++;
 		if (m_memCheckCounter >= MEM_COUNTER_ROLLOVER) {
 			m_memCheckCounter = 0;
diff --git a/Graph/ConstrainedSearch.h b/Graph/ConstrainedSearch.h
index 04bd5da..d0c4c45 100644
--- a/Graph/ConstrainedSearch.h
+++ b/Graph/ConstrainedSearch.h
@@ -1,10 +1,10 @@
 #ifndef CONSTRAINEDSEARCH_H
 #define CONSTRAINEDSEARCH_H 1
 
-#include "ContigGraph.h"
-#include "ContigPath.h"
-#include "ContigProperties.h"
-#include "DirectedGraph.h"
+#include "Common/ContigPath.h"
+#include "Common/ContigProperties.h"
+#include "Graph/ContigGraph.h"
+#include "Graph/DirectedGraph.h"
 #include "Graph/Properties.h"
 #include <algorithm>
 #include <climits> // for INT_MIN
diff --git a/Graph/ContigGraph.h b/Graph/ContigGraph.h
index 4c51f79..19d20ab 100644
--- a/Graph/ContigGraph.h
+++ b/Graph/ContigGraph.h
@@ -1,7 +1,7 @@
 #ifndef CONTIGGRAPH_H
 #define CONTIGGRAPH_H 1
 
-#include "ContigID.h"
+#include "Common/ContigID.h"
 #include "Graph/Properties.h"
 #include <boost/graph/graph_traits.hpp>
 #include <cassert>
diff --git a/Graph/ContigGraphAlgorithms.h b/Graph/ContigGraphAlgorithms.h
index 7ac4332..dd98fd5 100644
--- a/Graph/ContigGraphAlgorithms.h
+++ b/Graph/ContigGraphAlgorithms.h
@@ -1,12 +1,12 @@
 #ifndef CONTIGGRAPHALGORITHMS_H
 #define CONTIGGRAPHALGORITHMS_H 1
 
-#include "Algorithms.h"
-#include "ContigGraph.h"
-#include "ContigNode.h"
-#include "Estimate.h" // for BetterDistanceEst
-#include "Functional.h"
-#include "Iterator.h"
+#include "Common/Algorithms.h"
+#include "Common/ContigNode.h"
+#include "Common/Estimate.h" // for BetterDistanceEst
+#include "Common/Functional.h"
+#include "Common/Iterator.h"
+#include "Graph/ContigGraph.h"
 #include <boost/graph/graph_traits.hpp>
 #include <algorithm>
 #include <cassert>
@@ -362,7 +362,7 @@ size_t addComplementaryEdges(ContigGraph<DG>& g)
 		V vc = get(vertex_complement, g, v);
 		E f;
 		bool found;
-		tie(f, found) = edge(vc, uc, g);
+		boost::tie(f, found) = edge(vc, uc, g);
 		if (!found) {
 			add_edge(vc, uc, g[e], static_cast<DG&>(g));
 			numAdded++;
diff --git a/Graph/DirectedGraph.h b/Graph/DirectedGraph.h
index eec9682..bd56d03 100644
--- a/Graph/DirectedGraph.h
+++ b/Graph/DirectedGraph.h
@@ -1,7 +1,7 @@
 #ifndef DIRECTEDGRAPH_H
 #define DIRECTEDGRAPH_H 1
 
-#include "ContigNode.h"
+#include "Common/ContigNode.h"
 #include "Graph/Properties.h"
 #include <algorithm>
 #include <cassert>
@@ -595,6 +595,13 @@ num_vertices(const DirectedGraph<VP, EP>& g)
 }
 
 template <typename VP, typename EP>
+typename DirectedGraph<VP, EP>::vertex_descriptor
+vertex(typename DirectedGraph<VP, EP>::vertices_size_type ui, const DirectedGraph<VP, EP>& g)
+{
+	return g.vertex(ui);
+}
+
+template <typename VP, typename EP>
 std::pair<typename DirectedGraph<VP, EP>::vertex_iterator,
 	typename DirectedGraph<VP, EP>::vertex_iterator>
 vertices(const DirectedGraph<VP, EP>& g)
diff --git a/Graph/ExtendPath.h b/Graph/ExtendPath.h
new file mode 100644
index 0000000..acef178
--- /dev/null
+++ b/Graph/ExtendPath.h
@@ -0,0 +1,296 @@
+#ifndef _EXTENDPATH_H_
+#define _EXTENDPATH_H_
+
+#include "Graph/Path.h"
+#include "Common/UnorderedSet.h"
+#include "Common/UnorderedMap.h"
+#include "Common/Hash.h"
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/graph_concepts.hpp>
+#include <cassert>
+#include <cstdio>
+#include <iostream>
+
+/**
+ * The result of attempting to extend a path.
+ */
+enum PathExtensionResult {
+	DEAD_END,
+	BRANCHING_POINT,
+	CYCLE,
+	LENGTH_LIMIT,
+	EXTENDED_TO_DEAD_END,
+	EXTENDED_TO_BRANCHING_POINT,
+	EXTENDED_TO_CYCLE,
+	EXTENDED_TO_LENGTH_LIMIT
+};
+
+/**
+ * The result of attempting to extend a path
+ * by a single neighbouring vertex.
+ */
+enum SingleExtensionResult {
+	SE_DEAD_END,
+	SE_BRANCHING_POINT,
+	SE_EXTENDED
+};
+
+/**
+ * Return true if there is a path of at least 'depth' vertices
+ * that extends from given vertex v, otherwise return false.
+ * Implemented using a bounded breadth first search.
+ *
+ * @param start starting vertex for traversal
+ * @param dir direction for traversal (FORWARD or REVERSE)
+ * @param depth length of path to test for
+ * @param g graph to use for traversal
+ * @return true if at least one path with length >= len
+ * extends from v in direction dir, false otherwise
+ */
+template <class BidirectionalGraph>
+static inline bool lookAhead(
+	typename boost::graph_traits<BidirectionalGraph>::vertex_descriptor start,
+	Direction dir, unsigned depth, const BidirectionalGraph& g)
+{
+    typedef typename boost::graph_traits<BidirectionalGraph>::vertex_descriptor V;
+    typedef typename boost::graph_traits<BidirectionalGraph>::out_edge_iterator OutEdgeIter;
+    typedef typename boost::graph_traits<BidirectionalGraph>::in_edge_iterator InEdgeIter;
+
+	OutEdgeIter oei, oei_end;
+	InEdgeIter iei, iei_end;
+
+	unordered_set<V, hash<V> > visited;
+	typedef unordered_map<V, unsigned> DepthMap;
+	DepthMap depthMap;
+	std::deque<V> q;
+
+	q.push_back(start);
+
+	visited.insert(start);
+	std::pair<typename DepthMap::iterator, bool> inserted =
+		depthMap.insert(std::make_pair(start, 0));
+	assert(inserted.second);
+
+	while (!q.empty()) {
+		V u = q.front();
+		q.pop_front();
+		visited.insert(u);
+		typename DepthMap::const_iterator it = depthMap.find(u);
+		assert(it != depthMap.end());
+		unsigned uDepth = it->second;
+		if (uDepth == depth)
+			return true;
+		if (dir == FORWARD) {
+			for (boost::tie(oei, oei_end) = out_edges(u, g);
+				oei != oei_end; ++oei) {
+				V v = target(*oei, g);
+				if (visited.find(v) == visited.end()) {
+					visited.insert(v);
+					std::pair<typename DepthMap::iterator, bool> inserted =
+						depthMap.insert(std::make_pair(v, uDepth+1));
+					assert(inserted.second);
+					q.push_back(v);
+				}
+			}
+		} else {
+			assert(dir == REVERSE);
+			for (boost::tie(iei, iei_end) = in_edges(u, g);
+				iei != iei_end; ++iei) {
+				V v = source(*iei, g);
+				if (visited.find(v) == visited.end()) {
+					visited.insert(v);
+					std::pair<typename DepthMap::iterator, bool> inserted =
+						depthMap.insert(std::make_pair(v, uDepth+1));
+					assert(inserted.second);
+					q.push_back(v);
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+template <class BidirectionalGraph>
+static inline std::vector<typename boost::graph_traits<BidirectionalGraph>::vertex_descriptor>
+trueBranches(typename boost::graph_traits<BidirectionalGraph>::vertex_descriptor& u,
+	Direction dir, const BidirectionalGraph& g, unsigned trimLen=0)
+{
+	typedef BidirectionalGraph G;
+	typedef boost::graph_traits<G> graph_traits;
+	typedef typename graph_traits::vertex_descriptor V;
+
+	typename graph_traits::out_edge_iterator oei, oei_end;
+	typename graph_traits::in_edge_iterator iei, iei_end;
+
+	std::vector<V> branchRoots;
+
+	if (dir == FORWARD) {
+		for (boost::tie(oei, oei_end) = out_edges(u, g);
+				oei != oei_end; ++oei) {
+			const V& v = target(*oei, g);
+			if (lookAhead(v, dir, trimLen, g))
+				branchRoots.push_back(v);
+		}
+	} else {
+		assert(dir == REVERSE);
+		for (boost::tie(iei, iei_end) = in_edges(u, g);
+			iei != iei_end; ++iei) {
+			const V& v = source(*iei, g);
+			if (lookAhead(v, dir, trimLen, g)) {
+				branchRoots.push_back(v);
+			}
+		}
+	}
+
+	return branchRoots;
+}
+
+/**
+ * If the given path has only one possible next/prev vertex in the graph,
+ * append/prepend that vertex to the path.
+ *
+ * @param path the path to extend (a list of vertices)
+ * @param dir direction of extension (FORWARD or REVERSE)
+ * @param g the graph to use for traversal
+ * @param trimLen ignore neighbour vertices with branches
+ * shorter than this length [0]
+ * @return PathExtensionResult: NO_EXTENSION, HIT_BRANCHING_POINT, or EXTENDED
+ */
+template <class BidirectionalGraph>
+static inline SingleExtensionResult extendPathBySingleVertex(
+	Path<typename boost::graph_traits<BidirectionalGraph>::vertex_descriptor>& path,
+	Direction dir, const BidirectionalGraph& g, unsigned trimLen = 0)
+{
+	typedef BidirectionalGraph G;
+	typedef boost::graph_traits<G> graph_traits;
+	typedef typename graph_traits::vertex_descriptor V;
+
+	typename graph_traits::out_edge_iterator oei, oei_end;
+	typename graph_traits::in_edge_iterator iei, iei_end;
+
+	assert(dir == FORWARD || dir == REVERSE);
+
+	V& u = (dir == FORWARD) ? path.back() : path.front();
+	unsigned degree = (dir == FORWARD) ? out_degree(u, g) : in_degree(u, g);
+
+	if (degree == 0) {
+		return SE_DEAD_END;
+	} else if (degree == 1) {
+		const V& v = (dir == FORWARD) ?
+			target(*(out_edges(u, g).first), g) :
+			source(*(in_edges(u, g).first), g);
+		if (dir == FORWARD) {
+			path.push_back(v);
+		} else {
+			assert(dir == REVERSE);
+			path.push_front(v);
+		}
+		return SE_EXTENDED;
+	} else {
+		std::vector<V> neighbours = trueBranches(u, dir, g, trimLen);
+		if (neighbours.empty()) {
+			return SE_DEAD_END;
+		} else if (neighbours.size() == 1) {
+			if (dir == FORWARD) {
+				path.push_back(neighbours.front());
+			} else {
+				assert(dir == REVERSE);
+				path.push_front(neighbours.front());
+			}
+			return SE_EXTENDED;
+		} else {
+			assert(neighbours.size() > 1);
+			return SE_BRANCHING_POINT;
+		}
+	}
+}
+
+/**
+ * Extend a path up to the next branching point in the graph.
+ *
+ * @param path path to extend (modified by this function)
+ * @param dir direction to extend path (FORWARD or REVERSE)
+ * @param g graph in which to perform the extension
+ * @param trimLen ignore branches less than this length when
+ * detecting branch points [0]
+ * @return PathExtensionResult: NO_EXTENSION, HIT_BRANCHING_POINT,
+ * or EXTENDED.
+ */
+template <class BidirectionalGraph>
+PathExtensionResult extendPath(
+	Path<typename boost::graph_traits<BidirectionalGraph>::vertex_descriptor>& path,
+	Direction dir, const BidirectionalGraph& g, unsigned trimLen = 0,
+	unsigned maxLen = NO_LIMIT)
+{
+	typedef BidirectionalGraph G;
+	typedef boost::graph_traits<G> graph_traits;
+	typedef typename graph_traits::vertex_descriptor V;
+	typename graph_traits::out_edge_iterator oei, oei_end;
+	typename graph_traits::in_edge_iterator iei, iei_end;
+
+	assert(path.size() > 0 && path.size() <= maxLen);
+	size_t origPathLen = path.size();
+
+	/* track visited nodes to avoid infinite traversal of cycles */
+	unordered_set<V> visited;
+	visited.insert(path.begin(), path.end());
+
+	SingleExtensionResult result = SE_EXTENDED;
+	bool detectedCycle = false;
+
+	while (result == SE_EXTENDED && !detectedCycle &&
+		path.size() < maxLen)
+	{
+		result = extendPathBySingleVertex(path, dir, g, trimLen);
+		if (result == SE_EXTENDED) {
+			std::pair<typename unordered_set<V>::iterator,bool> inserted;
+			if (dir == FORWARD) {
+				inserted = visited.insert(path.back());
+			} else {
+				assert(dir == REVERSE);
+				inserted = visited.insert(path.front());
+			}
+			if (!inserted.second)
+				detectedCycle = true;
+		}
+	}
+
+	/** the last kmer we added is a repeat, so remove it */
+	if (detectedCycle) {
+		if (dir == FORWARD) {
+			path.pop_back();
+		} else {
+			assert(dir == REVERSE);
+			path.pop_front();
+		}
+	}
+
+	if (path.size() > origPathLen) {
+		if (detectedCycle) {
+			return EXTENDED_TO_CYCLE;
+		} else if (result == SE_DEAD_END) {
+			return EXTENDED_TO_DEAD_END;
+		} else if (result == SE_BRANCHING_POINT) {
+			return EXTENDED_TO_BRANCHING_POINT;
+		} else {
+			assert(result == SE_EXTENDED &&
+				path.size() == maxLen);
+			return EXTENDED_TO_LENGTH_LIMIT;
+		}
+	} else {
+		assert(path.size() == origPathLen);
+		if (detectedCycle) {
+			return CYCLE;
+		} else if (result == SE_DEAD_END) {
+			return DEAD_END;
+		} else if (result == SE_BRANCHING_POINT) {
+			return BRANCHING_POINT;
+		} else {
+			assert(origPathLen >= maxLen);
+			return LENGTH_LIMIT;
+		}
+	}
+}
+
+#endif
diff --git a/Graph/AsqgIO.h b/Graph/GfaIO.h
similarity index 55%
copy from Graph/AsqgIO.h
copy to Graph/GfaIO.h
index a3bc142..32b90f7 100644
--- a/Graph/AsqgIO.h
+++ b/Graph/GfaIO.h
@@ -1,5 +1,5 @@
-#ifndef ASQGIO_H
-#define ASQGIO_H 1
+#ifndef GFAIO_H
+#define GFAIO_H 1
 
 #include "Common/IOUtil.h"
 #include "Graph/Properties.h"
@@ -11,9 +11,9 @@
 
 using boost::graph_traits;
 
-/** Write a graph in ASQG format. */
+/** Write a graph in GFA format. */
 template <typename Graph>
-std::ostream& write_asqg(std::ostream& out, Graph& g)
+std::ostream& write_gfa(std::ostream& out, Graph& g)
 {
 	typedef typename graph_traits<Graph>::edge_descriptor E;
 	typedef typename graph_traits<Graph>::edge_iterator Eit;
@@ -21,7 +21,7 @@ std::ostream& write_asqg(std::ostream& out, Graph& g)
 	typedef typename graph_traits<Graph>::vertex_iterator Vit;
 	typedef typename vertex_bundle_type<Graph>::type VP;
 
-	out << "HT\tVN:i:1\n";
+	out << "H\tVN:Z:1.0\n";
 	assert(out);
 
 	std::pair<Vit, Vit> vrange = vertices(g);
@@ -30,10 +30,10 @@ std::ostream& write_asqg(std::ostream& out, Graph& g)
 		if (get(vertex_removed, g, u))
 			continue;
 		const VP& vp = g[u];
-		out << "VT\t" << get(vertex_contig_name, g, u)
+		out << "S\t" << get(vertex_contig_name, g, u)
 			<< "\t*\tLN:i:" << vp.length;
 		if (vp.coverage > 0)
-			out << "\tXC:i:" << vp.coverage;
+			out << "\tKC:i:" << vp.coverage;
 		out << '\n';
 	}
 
@@ -42,38 +42,36 @@ std::ostream& write_asqg(std::ostream& out, Graph& g)
 		E e = *eit;
 		V u = source(e, g);
 		V v = target(e, g);
-		if (v < u || get(vertex_removed, g, u))
+		if (get(vertex_removed, g, u))
+			continue;
+
+		// Output only the canonical edge.
+		if (u > get(vertex_complement, g, v))
 			continue;
+
 		assert(!get(vertex_removed, g, v));
 		int distance = g[e].distance;
-		assert(distance < 0);
-		unsigned overlap = -distance;
-		unsigned ulen = g[u].length;
-		unsigned vlen = g[v].length;
-		bool usense = get(vertex_sense, g, u);
-		bool vsense = get(vertex_sense, g, v);
-		out << "ED\t" << get(vertex_contig_name, g, u)
-			<< ' ' << get(vertex_contig_name, g, v)
-			<< ' ' << (usense ? 0 : ulen - overlap)
-			<< ' ' << (usense ? overlap : ulen) - 1
-			<< ' ' << ulen
-			<< ' ' << (!vsense ? 0 : vlen - overlap)
-			<< ' ' << (!vsense ? overlap : vlen) - 1
-			<< ' ' << vlen
-			<< ' ' << (usense != vsense)
-			<< " -1\n"; // number of mismatches
+		out << 'L'
+			<< '\t' << get(vertex_contig_name, g, u)
+			<< '\t' << (get(vertex_sense, g, u) ? '-' : '+')
+			<< '\t' << get(vertex_contig_name, g, v)
+			<< '\t' << (get(vertex_sense, g, v) ? '-' : '+');
+		if (distance <= 0)
+			out << '\t' << -distance << "M\n";
+		else
+			out << "\t*\n";
+		assert(out);
 	}
 	return out;
 }
 
-/** Read a graph in ASQG format. */
+/** Read a graph in GFA format. */
 template <typename Graph>
-std::istream& read_asqg(std::istream& in, Graph& g)
+std::istream& read_gfa(std::istream& in, Graph& g)
 {
 	assert(in);
 
 	typedef typename graph_traits<Graph>::vertex_descriptor V;
-	typedef typename graph_traits<Graph>::edge_descriptor E;
 	typedef typename vertex_property<Graph>::type VP;
 	typedef typename edge_property<Graph>::type EP;
 
@@ -83,12 +81,13 @@ std::istream& read_asqg(std::istream& in, Graph& g)
 	while (in && in.peek() != EOF) {
 		switch (in.peek()) {
 		  case 'H':
-			in >> expect("HT") >> Ignore('\n');
+			in >> expect("H\tVN:Z:1.0\n");
 			assert(in);
 			break;
-		  case 'V': {
+
+		  case 'S': {
 			std::string uname, seq;
-			in >> expect("VT") >> uname >> seq;
+			in >> expect("S\t") >> uname >> seq;
 			assert(in);
 			assert(!seq.empty());
 
@@ -98,11 +97,20 @@ std::istream& read_asqg(std::istream& in, Graph& g)
 				assert(in);
 			} else
 				length = seq.size();
+
+			unsigned coverage = 0;
+			if (in.peek() == '\t' && in.get() == '\t' && in.peek() == 'K') {
+				in >> expect("KC:i:") >> coverage;
+				assert(in);
+			}
+
 			in >> Ignore('\n');
+			assert(in);
 
 			if (addVertices) {
 				VP vp;
 				put(vertex_length, vp, length);
+				put(vertex_coverage, vp, coverage);
 				V u = add_vertex(vp, g);
 				put(vertex_name, g, u, uname);
 			} else {
@@ -112,34 +120,38 @@ std::istream& read_asqg(std::istream& in, Graph& g)
 			}
 			break;
 		  }
-		  case 'E': {
+
+		  case 'L': {
 			std::string uname, vname;
-			unsigned s1, e1, l1, s2, e2, l2;
-			bool rc;
-			int nd;
-			in >> expect("ED") >> uname >> vname
-				>> s1 >> e1 >> l1
-				>> s2 >> e2 >> l2
-				>> rc >> nd >> Ignore('\n');
+			char usense, vsense;
+			int overlap;
+			in >> expect("L\t")
+				>> uname >> usense
+				>> vname >> vsense >> std::ws;
+			if (in.peek() == '*') {
+				in.get();
+				overlap = -1;
+			} else {
+				in >> overlap >> expect("M");
+			}
+			in >> Ignore('\n');
 			assert(in);
-			assert(s1 < e1 && e1 < l1 && s2 < e2 && e2 < l2);
-			assert(e1 - s1 == e2 - s2);
-			assert(e1 - s1 + 1 < l1 && e2 - s2 + 1 < l2);
-			assert(((s1 > 0) == (s2 > 0)) == rc);
-			int d = -(e1 - s1 + 1);
-			assert(d < 0);
-			EP ep(d);
-			V u = find_vertex(uname, s1 == 0, g);
-			V v = find_vertex(vname, s2 > 0, g);
-			std::pair<E, bool> e = edge(u, v, g);
-			if (e.second) {
-				// Ignore duplicate edges that are self loops.
-				assert(g[e.first] == ep);
-				assert(u == v);
-			} else
+			assert(!uname.empty());
+			assert(!vname.empty());
+			assert(usense == '+' || usense == '-');
+			assert(vsense == '+' || vsense == '-');
+
+			V u = find_vertex(uname, usense == '-', g);
+			V v = find_vertex(vname, vsense == '-', g);
+			if (overlap >= 0) {
+				int d = -overlap;
+				EP ep(d);
 				add_edge(u, v, ep, g);
+			} else
+				add_edge(u, v, g);
 			break;
 		  }
+
 		  default: {
 			std::string s;
 			in >> s;
diff --git a/Graph/GraphAlgorithms.h b/Graph/GraphAlgorithms.h
index 8f5f722..4fbdb27 100644
--- a/Graph/GraphAlgorithms.h
+++ b/Graph/GraphAlgorithms.h
@@ -2,7 +2,7 @@
 #define GRAPHALGORITHMS_H 1
 
 #include "Graph/Properties.h"
-#include "ConstrainedSearch.h"
+#include "ConstrainedSearch.h" // for constrainedSearch
 #include <boost/graph/graph_traits.hpp>
 #include <cassert>
 #include <vector>
@@ -75,6 +75,29 @@ void find_transitive_edges(const Graph& g, OutIt out)
 	}
 }
 
+/** Remove edges from the graph that satisfy the predicate.
+ * @return the number of edges removed
+ */
+template <typename Graph, typename Predicate>
+size_t
+removeEdgeIf(Predicate predicate, Graph& g)
+{
+	typedef graph_traits<Graph> GTraits;
+	typedef typename GTraits::edge_descriptor edge_descriptor;
+	typedef typename GTraits::edge_iterator edge_iterator;
+
+	size_t n = 0;
+	std::pair<edge_iterator, edge_iterator> erange = edges(g);
+	for (edge_iterator eit = erange.first; eit != erange.second; ++eit) {
+		edge_descriptor e = *eit;
+		if (predicate(e)) {
+			remove_edge(e, g);
+			++n;
+		}
+	}
+	return n;
+}
+
 /** Remove the edges [first,last) from g.
  * @return the number of removed edges
  */
diff --git a/Graph/GraphIO.h b/Graph/GraphIO.h
index fa6c441..78370e3 100644
--- a/Graph/GraphIO.h
+++ b/Graph/GraphIO.h
@@ -7,6 +7,7 @@
 #include "DistIO.h"
 #include "DotIO.h"
 #include "FastaIO.h"
+#include "GfaIO.h"
 #include "SAMIO.h"
 #include <cassert>
 #include <cstdlib> // for abort
@@ -30,6 +31,8 @@ std::ostream& write_graph(std::ostream& out, const Graph& g,
 		return write_dist(out, g);
 	  case DOT: case DOT_MEANCOV:
 		return out << dot_writer(g);
+	  case GFA:
+		return write_gfa(out, g);
 	  case SAM:
 		return write_sam(out, g, program, commandLine);
 	  default:
@@ -52,8 +55,22 @@ std::istream& read_graph(std::istream& in, ContigGraph<Graph>& g,
 		return read_sam_header(in, g);
 	  case 'd': // digraph: GraphViz dot format
 		return read_dot<Graph>(in, g, betterEP);
-	  case 'H': // HT: ASQG format
-		return read_asqg(in, g);
+	  case 'H': {
+		in.get();
+		char c = in.peek();
+		in.unget();
+		assert(in);
+		switch (c) {
+		  case 'T': // HT: ASQG format
+			return read_asqg(in, g);
+		  case '\t': // H: GAF format
+			return read_gfa(in, g);
+		  default:
+			std::cerr << "Unknown file format: `H" << c << "'\n";
+			exit(EXIT_FAILURE);
+		}
+		break;
+	  }
 	  case '>': // FASTA format for vertices
 		return read_fasta(in, g);
 	  default: // adj format
diff --git a/Graph/GraphUtil.h b/Graph/GraphUtil.h
index ef34c43..eedae97 100644
--- a/Graph/GraphUtil.h
+++ b/Graph/GraphUtil.h
@@ -24,27 +24,32 @@ num_vertices_removed(const Graph& g)
 	return n;
 }
 
+/** Print a histogram of the degree. */
+template <typename Graph>
+Histogram printHistogram(const Graph& g)
+{
+	typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
+	Histogram h;
+	std::pair<vertex_iterator, vertex_iterator> vit = vertices(g);
+	for (vertex_iterator u = vit.first; u != vit.second; ++u) {
+		if (get(vertex_removed, g, *u))
+			continue;
+		h.insert(out_degree(*u, g));
+	}
+	return h;
+}
+
 /** Print statistics of the number of vertices and edges. */
 template <typename Graph>
 std::ostream& printGraphStats(std::ostream& out, const Graph& g)
 {
 	using std::setprecision;
-	typedef typename graph_traits<Graph>::vertex_iterator
-		vertex_iterator;
-
 	unsigned v = num_vertices(g) - num_vertices_removed(g);
 	unsigned e = num_edges(g);
 	out << "V=" << v << " E=" << e
 		<< " E/V=" << setprecision(3) << (float)e / v << std::endl;
 
-	// Print a histogram of the degree.
-	Histogram h;
-	std::pair<vertex_iterator, vertex_iterator> vit = vertices(g);
-	for (vertex_iterator u = vit.first; u != vit.second; ++u) {
-		if (get(vertex_removed, g, *u))
-			continue;
-		h.insert(out_degree(*u, g));
-	}
+	Histogram h = printHistogram(g);
 	unsigned n = h.size();
 	unsigned n0 = h.count(0), n1 = h.count(1), n234 = h.count(2, 4);
 	unsigned n5 = n - (n0 + n1 + n234);
@@ -58,4 +63,29 @@ std::ostream& printGraphStats(std::ostream& out, const Graph& g)
 		"max: " << h.maximum() << std::endl;
 }
 
+/** Pass graph statistics  -- values only . */
+template <typename Graph>
+std::vector<int> passGraphStatsVal(const Graph& g)
+{
+#if _SQL
+	Histogram h = printHistogram(g);
+	unsigned n = h.size(),
+			 n0 = h.count(0),
+			 n1 = h.count(1),
+			 n234 = h.count(2, 4),
+			 n5 = n - (n0 + n1 + n234);
+
+	return make_vector<int>()
+		<< num_vertices(g) - num_vertices_removed(g)
+		<< num_edges(g)
+		<< (int)round(100.0 * n0 / n)
+		<< (int)round(100.0 * n1 / n)
+		<< (int)round(100.0 * n234 / n)
+		<< (int)round(100.0 * n5 / n)
+		<< h.maximum();
+#else
+	(void)g;
+	return make_vector<int>();
+#endif
+}
 #endif
diff --git a/Graph/HashGraph.h b/Graph/HashGraph.h
index 4ba791a..cc8f0d4 100644
--- a/Graph/HashGraph.h
+++ b/Graph/HashGraph.h
@@ -3,7 +3,6 @@
 
 #include "Common/UnorderedMap.h"
 #include "Common/UnorderedSet.h"
-#include "Common/Warnings.h"
 #include "Graph/Properties.h"
 #include <boost/graph/graph_traits.hpp>
 #include <vector>
@@ -57,8 +56,8 @@ public:
 		size_t filled_bucket_bytes = m_vertices.size() *
 			(sizeof(typename VertexMap::value_type) +
 			 3 * pointer_size);
-		size_t empty_bucket_bytes = (1.0 - m_vertices.load_factor()) *
-			m_vertices.bucket_count() * pointer_size;
+		size_t empty_bucket_bytes = size_t((1.0 - m_vertices.load_factor()) *
+			m_vertices.bucket_count() * pointer_size);
 		return entry_bytes + filled_bucket_bytes + empty_bucket_bytes;
 	}
 
@@ -441,32 +440,25 @@ add_edge(
 // works with DotIO.h routines)
 
 template <class VertexType>
-bool get(vertex_removed_t, const HashGraph<VertexType>& g,
-		typename HashGraph<VertexType>::vertex_descriptor v)
+bool get(vertex_removed_t, const HashGraph<VertexType>&,
+		typename HashGraph<VertexType>::vertex_descriptor)
 {
-	SUPPRESS_UNUSED_WARNING(g);
-	SUPPRESS_UNUSED_WARNING(v);
 	return false;
 }
 
 template <class VertexType>
-void put(vertex_removed_t tag, HashGraph<VertexType>& g,
-		typename HashGraph<VertexType>::vertex_descriptor v,
-		bool flag)
+void put(vertex_removed_t, HashGraph<VertexType>&,
+		typename HashGraph<VertexType>::vertex_descriptor,
+		bool)
 {
-	SUPPRESS_UNUSED_WARNING(tag);
-	SUPPRESS_UNUSED_WARNING(g);
-	SUPPRESS_UNUSED_WARNING(v);
-	SUPPRESS_UNUSED_WARNING(flag);
 	return;
 }
 
 template <class VertexType>
 typename HashGraph<VertexType>::vertex_descriptor
-get(vertex_name_t, const HashGraph<VertexType>& g,
+get(vertex_name_t, const HashGraph<VertexType>&,
 		typename HashGraph<VertexType>::vertex_descriptor v)
 {
-	SUPPRESS_UNUSED_WARNING(g);
 	return v;
 }
 
diff --git a/Graph/Makefile.am b/Graph/Makefile.am
index e92ea5c..cce5dd0 100644
--- a/Graph/Makefile.am
+++ b/Graph/Makefile.am
@@ -24,7 +24,9 @@ EXTRA_DIST = \
 	DirectedGraph.h \
 	DistIO.h \
 	DotIO.h \
+	ExtendPath.h \
 	FastaIO.h \
+	GfaIO.h \
 	GraphAlgorithms.h \
 	GraphIO.h \
 	GraphUtil.h \
diff --git a/Graph/Options.h b/Graph/Options.h
index 23cf054..c5c7b0d 100644
--- a/Graph/Options.h
+++ b/Graph/Options.h
@@ -10,6 +10,6 @@ namespace opt {
 }
 
 /** Enumeration of output formats */
-enum { ADJ, ASQG, DIST, DOT, DOT_MEANCOV, SAM };
+enum { ADJ, ASQG, DIST, DOT, DOT_MEANCOV, GFA, SAM, TSV };
 
 #endif
diff --git a/Graph/Path.h b/Graph/Path.h
index 9962b42..33c893d 100644
--- a/Graph/Path.h
+++ b/Graph/Path.h
@@ -1,10 +1,10 @@
 #ifndef PATH_H_
 #define PATH_H_
 
-#include <vector>
 #include <string>
 #include <sstream>
 #include <climits>
+#include <deque>
 
 enum PathSearchResult {
 	FOUND_PATH = 0,
@@ -28,13 +28,13 @@ enum Direction { FORWARD = 0, REVERSE };
 
 const unsigned NO_LIMIT = UINT_MAX;
 
-template <class Vertex> class Path : public std::vector<Vertex>
+template <class Vertex> class Path : public std::deque<Vertex>
 {
 public:
 
 	std::string str() {
 		std::stringstream s;
-		typename std::vector<Vertex>::iterator i = this->begin();
+		typename std::deque<Vertex>::iterator i = this->begin();
 		for (; i != this->end(); i++) {
 			if (i != this->begin())
 				s << ",";
diff --git a/Graph/SAMIO.h b/Graph/SAMIO.h
index abfd5ee..5a20270 100644
--- a/Graph/SAMIO.h
+++ b/Graph/SAMIO.h
@@ -46,7 +46,7 @@ std::ostream& write_sam(std::ostream& out, const Graph& g,
 		ContigNode u = source(*e, g), v = target(*e, g);
 		assert(!get(vertex_removed, g, v));
 		int distance = get(edge_distance, g, *e);
-		if (get(vertex_removed, g, u) || distance >= 0)
+		if (get(vertex_removed, g, u) || distance > 0)
 			continue;
 		unsigned flag = u.sense() == v.sense() ? 0 : 0x10; //FREVERSE
 		unsigned alen = -distance;
diff --git a/Graph/todot.cc b/Graph/todot.cc
index 6ac2b46..7599a12 100644
--- a/Graph/todot.cc
+++ b/Graph/todot.cc
@@ -5,6 +5,7 @@
 #include "ContigProperties.h"
 #include "DirectedGraph.h"
 #include "Estimate.h"
+#include "Graph/ContigGraphAlgorithms.h" // for addComplementaryEdges
 #include "GraphIO.h"
 #include "GraphUtil.h"
 #include "IOUtil.h"
@@ -37,8 +38,10 @@ static const char USAGE_MESSAGE[] =
 "      --adj             output the graph in adj format\n"
 "      --asqg            output the graph in asqg format\n"
 "      --dist            output the graph in dist format\n"
-"      --dot             output the graph in dot format [default]\n"
+"      --dot             output the graph in GraphViz format [default]\n"
+"      --gv              output the graph in GraphViz format\n"
 "      --dot-meancov     same as above but give the mean coverage\n"
+"      --gfa             output the graph in GFA format\n"
 "      --sam             output the graph in SAM format\n"
 "  -e, --estimate output distance estimates\n"
 "  -v, --verbose  display verbose output\n"
@@ -54,6 +57,9 @@ namespace opt {
 	/** Output distance estimates. */
 	bool estimate;
 
+	/** Add missing complementary edges. */
+	bool addComplementaryEdges;
+
 	/** Output format */
 	int format = DOT; // used by ContigProperties
 }
@@ -67,7 +73,9 @@ static const struct option longopts[] = {
 	{ "asqg",    no_argument,       &opt::format, ASQG },
 	{ "dist",    no_argument,       &opt::format, DIST },
 	{ "dot",     no_argument,       &opt::format, DOT },
+	{ "gv",      no_argument,       &opt::format, DOT },
 	{ "dot-meancov", no_argument,   &opt::format, DOT_MEANCOV },
+	{ "gfa",     no_argument,       &opt::format, GFA },
 	{ "sam",     no_argument,       &opt::format, SAM },
 	{ "estimate", no_argument,      NULL, 'e' },
 	{ "kmer",    required_argument, NULL, 'k' },
@@ -102,6 +110,15 @@ void readGraphs(Graph& g, It first, It last, BetterEP betterEP)
 			readGraph(*it, g, betterEP);
 	} else
 		readGraph("-", g, betterEP);
+
+	if (opt::addComplementaryEdges) {
+		// Add any missing complementary edges. This feature is disabled.
+		size_t numAdded = addComplementaryEdges(g);
+		if (opt::verbose > 0) {
+			cerr << "Added " << numAdded << " complementary edges.\n";
+			printGraphStats(cerr, g);
+		}
+	}
 }
 
 int main(int argc, char** argv)
diff --git a/IntegrationTest/DIDA/alignment-test.mk b/IntegrationTest/DIDA/alignment-test.mk
new file mode 100755
index 0000000..4685bf0
--- /dev/null
+++ b/IntegrationTest/DIDA/alignment-test.mk
@@ -0,0 +1,84 @@
+#!/usr/bin/make -rRf
+
+SHELL=/bin/bash
+
+#------------------------------------------------------------
+# test input/output files
+#------------------------------------------------------------
+
+# target seq for alignments
+ref_url:=http://gage.cbcb.umd.edu/data/Staphylococcus_aureus/Data.original/genome.fasta
+ref:=ref.fa
+test_ref=test_ref.fa
+
+# query seqs for alignments
+reads_url:=http://gage.cbcb.umd.edu/data/Staphylococcus_aureus/Data.original/frag_1.fastq.gz
+reads=reads.fq.gz
+test_reads=test_reads.fq
+
+# output alignment files
+dida_wrapper_sam=dida_wrapper.sam
+abyss_map_sam=abyss_map.sam
+
+#------------------------------------------------------------
+# params
+#------------------------------------------------------------
+
+# number of MPI tasks
+np?=3
+# number of threads per task
+j?=1
+# min align length
+l?=20
+# num of reads to align
+n?=10000
+
+#------------------------------------------------------------
+# special targets
+#------------------------------------------------------------
+
+.PHONY: clean dida_wrapper_test
+
+default: dida_wrapper_test
+
+clean:
+	rm -f $(dida_wrapper_sam) $(abyss_map_sam) ref-* *.lines $(test_reads)
+
+#------------------------------------------------------------
+# downloading/building test input data
+#------------------------------------------------------------
+
+# download ref
+$(ref):
+	curl $(ref_url) > $@
+
+# split ref into chunks of 100,000bp or less
+$(test_ref): $(ref)
+	fold -w 100000 $^ | awk '{print ">"i++; print $$0}' > $@
+
+# download some reads
+$(reads):
+	curl $(reads_url) > $@
+
+# extract first $n reads
+$(test_reads): $(reads)
+	zcat $(reads) | paste - - - - | head -$n | \
+		tr '\t' '\n' > $@
+
+#------------------------------------------------------------
+# running DIDA/abyss-map
+#------------------------------------------------------------
+
+$(dida_wrapper_sam): $(test_reads) $(test_ref)
+	abyss-dida-wrapper -l$l -j$j $(ALIGNER_OPTIONS) -d'$(DIDA_OPTIONS)' $^ > $@
+
+$(abyss_map_sam): $(test_reads) $(test_ref)
+	abyss-map --order -l$l -j$j $^ > $@
+
+#------------------------------------------------------------
+# tests
+#------------------------------------------------------------
+
+dida_wrapper_test: $(abyss_map_sam) $(dida_wrapper_sam)
+	compare-sam $(abyss_map_sam) $(dida_wrapper_sam)
+	@echo $@": PASSED!"
diff --git a/IntegrationTest/DIDA/assembly-test.mk b/IntegrationTest/DIDA/assembly-test.mk
new file mode 100755
index 0000000..9446957
--- /dev/null
+++ b/IntegrationTest/DIDA/assembly-test.mk
@@ -0,0 +1,83 @@
+#!/usr/bin/make -Rrf
+
+SHELL=/bin/bash -o pipefail
+
+#------------------------------------------------------------
+# simulated test data
+#------------------------------------------------------------
+
+# yeast chromosome III, 50X coverage
+ref_url?='http://www.ebi.ac.uk/ena/data/view/X59720&display=fasta'
+ref:=ref.fa
+read_len:=100
+cov:=50
+num_read_pairs:=316600
+test_read1:=read1.fq
+test_read2:=read2.fq
+
+#------------------------------------------------------------
+# assembly outputs
+#------------------------------------------------------------
+
+standard_assembly_dir?=standard-assembly
+dida_assembly_dir?=dida-assembly
+assembly_name?=test
+
+#------------------------------------------------------------
+# assembly params
+#------------------------------------------------------------
+
+k?=30
+in?=../$(test_read1) ../$(test_read2)
+abyss_opt=v=-v k=$k name='$(assembly_name)' in='$(in)'
+
+#------------------------------------------------------------
+# meta rules
+#------------------------------------------------------------
+
+.PHONY: clean fasta_identity_test
+default: fasta_identity_test
+
+clean:
+	rm -rf $(standard_assembly_dir)/* $(dida_assembly_dir)/* \
+		$(test_read1) $(test_read2)
+
+#------------------------------------------------------------
+# rules for downloading data
+#------------------------------------------------------------
+
+$(ref):
+	curl $(ref_url) > $@
+
+$(test_read1) $(test_read2): $(ref)
+	wgsim -N $(num_read_pairs) -1 $(read_len) -2 $(read_len) \
+		$^ $(test_read1) $(test_read2)
+
+#------------------------------------------------------------
+# rules for running assemblies
+#------------------------------------------------------------
+
+$(standard_assembly_dir):
+	mkdir -p $@
+
+$(dida_assembly_dir):
+	mkdir -p $@
+
+$(standard_assembly_dir)/$(assembly_name)-8.fa: $(test_read1) $(test_read2) \
+		| $(standard_assembly_dir)
+	abyss-pe -C $(standard_assembly_dir) $(abyss_opt) $(ABYSS_OPT)
+
+$(dida_assembly_dir)/$(assembly_name)-8.fa: $(test_read1) $(test_read2) \
+		| $(dida_assembly_dir)
+	abyss-pe -C $(dida_assembly_dir) $(abyss_opt) $(ABYSS_OPT) \
+		aligner=dida
+
+#------------------------------------------------------------
+# test rules
+#------------------------------------------------------------
+
+fasta_identity_test: \
+		$(dida_assembly_dir)/$(assembly_name)-8.fa \
+		$(standard_assembly_dir)/$(assembly_name)-8.fa
+	compare-fastx $^
+	@echo '$@: PASSED!'
diff --git a/IntegrationTest/DIDA/compare-fastx b/IntegrationTest/DIDA/compare-fastx
new file mode 100755
index 0000000..9b85ed1
--- /dev/null
+++ b/IntegrationTest/DIDA/compare-fastx
@@ -0,0 +1,14 @@
+#!/bin/bash
+set -eu -o pipefail
+
+if [ $# -ne 2 ]; then
+	echo "Usage: $(basename $0) <file1> <file2>" >&2
+	echo "Compare FASTX files without regard for sequence orientation." >&2
+	exit 1
+fi
+
+function canonical_seqs {
+	bioawk -c fastx '{print $seq; print revcomp($seq)}' "$@" | sort
+}
+
+diff <(canonical_seqs $1) <(canonical_seqs $2)
diff --git a/IntegrationTest/DIDA/compare-sam b/IntegrationTest/DIDA/compare-sam
new file mode 100755
index 0000000..d9ef3a9
--- /dev/null
+++ b/IntegrationTest/DIDA/compare-sam
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+if [ $# -ne 2 ]; then
+	echo "Usage: $(basename $0) <abyss_map_sam_file> <dida_sam_file>" >&2
+	exit 1
+fi
+
+remove_cosmetic_diffs() {
+	# (1) take out @PG headers, they are expected to be different
+	# (2) in case of unmapped reads
+	#    (i) DIDA sets RNEXT = "*" instead of "="
+	#    (ii) DIDA sets SEQ and QUAL to "*" instead of actual SEQ/QUAL
+	egrep -v '^@PG' "$@" | \
+		awk 'BEGIN { OFS="\t" } !/^@/ && $2 == 4 { $7=$10=$11="*" } { print }'
+}
+
+set -eu -o pipefail
+
+abyss_map_output="$1"
+dida_output="$2"
+
+# Known types of differences:
+#
+# (i) Multiple aligns, abyss-map sets MAPQ=0 but DIDA has MAPQ>0.
+# (ii) MAPQ values are equal and > 0, but different CIGAR strings
+#      When different fragments of the same read have equal quality
+#      alignments, abyss-map will choose arbitrarily.
+# (iii) Different choice between forward and reverse complement,
+#       where both aligns have equal quality.
+# (iv) bloom filter miss
+#
+# I have not seen any other types of differences in my testing.
+#
+# - Ben V
+
+paste -d'\n' \
+	<(egrep -v '^@' $abyss_map_output | remove_cosmetic_diffs) \
+	<(egrep -v '^@' $dida_output | remove_cosmetic_diffs) \
+	| awk '\
+	BEGIN {
+		mapq_not_zero=diff_read_frags=bloom_filter_misses=diff_dir=unclassified=0;
+		aborted=0;
+		UNMAPPED_FLAG=4;
+		RC_FLAG=16;
+	}
+	{
+		line1=$0; qname1=$1; flags1=$2; mapq1=$5; cigar1=$6;
+		getline;
+		line2=$0; qname2=$1; flags2=$2; mapq2=$5; cigar2=$6;
+		if (qname1 != qname2) {
+			print "error: mismatch between read ids "qname1" and "qname2"!" > "/dev/stderr";
+			print "Ensure that read ids occur in the same order in both files." > "/dev/stderr";
+			aborted=1;
+			exit 1;
+		}
+		if (line1 != line2) {
+			if (mapq1 == 0 && mapq2 != 0) {
+				mapq_not_zero++;
+				print line1 > "mapq_not_zero.abyss-map.lines";
+				print line2 > "mapq_not_zero.dida.lines"
+			}
+			else if (mapq1 != 0 && mapq2 == 0) {
+				mapq_zero++;
+				print line1 > "mapq_zero.abyss-map.lines";
+				print line2 > "mapq_zero.dida.lines"
+			}
+			else if (mapq1 > 0 && mapq1 == mapq2) {
+				if (cigar1 != cigar2) {
+					diff_read_frags++;
+					print line1 > "diff_read_frags.abyss-map.lines";
+					print line2 > "diff_read_frags.dida.lines";
+				}
+				else if (and(flags1,RC_FLAG) != and(flags2,RC_FLAG)) {
+					diff_dir++;
+					print line1 > "diff_dir.abyss-map.lines";
+					print line2 > "diff_dir.dida.lines";
+				}
+				else {
+					unclassified++;
+					print line1 > "unclassified.abyss-map.lines";
+					print line2 > "unclassified.dida.lines";
+				}
+			}
+			else if (!and(flags1,UNMAPPED_FLAG) && and(flags2,UNMAPPED_FLAG)) {
+				bloom_filter_misses++;
+				print line1 > "bloom_filter_miss.abyss-map.lines";
+				print line2 > "bloom_filter_miss.dida.lines";
+			}
+			else if (mapq1 > 0 || mapq2 > 0) {
+				unclassified++;
+				print line1 > "unclassified.abyss-map.lines";
+				print line2 > "unclassified.dida.lines";
+			}
+		}
+	}
+	END {
+		if (aborted)
+			exit 1;
+
+		print "diff counts:";
+		print "\tdue to bloom filter misses: "bloom_filter_misses;
+		print "\tabyss-map MAPQ == 0, DIDA MAPQ != 0: "mapq_not_zero;
+		print "\tabyss-map MAPQ != 0, DIDA MAPQ == 0: "mapq_zero;
+		print "\tequal len aligns for diff frags of same read: "diff_read_frags;
+		print "\tequal len aligns for forward/reverse complement: "diff_dir;
+		print "\tunclassified diff: "unclassified;
+
+		if (bloom_filter_misses + mapq_not_zero + mapq_zero + diff_read_frags + diff_dir + unclassified > 0)
+			exit 1;
+	}'
diff --git a/Konnector/DBGBloom.h b/Konnector/DBGBloom.h
index c42737b..e3defdd 100644
--- a/Konnector/DBGBloom.h
+++ b/Konnector/DBGBloom.h
@@ -6,12 +6,12 @@
 #ifndef DBGBLOOM_H
 #define DBGBLOOM_H 1
 
+#include "Assembly/SeqExt.h" // for NUM_BASES
 #include "Common/IOUtil.h"
 #include "Common/Kmer.h"
-#include "Common/SeqExt.h" // for NUM_BASES
-#include "Graph/Properties.h"
 #include "Common/Uncompress.h"
 #include "DataLayer/FastaReader.h"
+#include "Graph/Properties.h"
 
 #include <algorithm>
 #include <cassert>
diff --git a/Konnector/DBGBloomAlgorithms.h b/Konnector/DBGBloomAlgorithms.h
index 863e3e1..c1e7aa6 100644
--- a/Konnector/DBGBloomAlgorithms.h
+++ b/Konnector/DBGBloomAlgorithms.h
@@ -7,13 +7,13 @@
 
 #include "Common/Kmer.h"
 #include "Common/KmerIterator.h"
-#include "Common/Warnings.h"
 #include "DBGBloom.h"
 #include "Common/StringUtil.h"
 #include "Common/Sequence.h"
 #include "DataLayer/FastaReader.h"
 #include "Graph/Path.h"
 #include <climits>
+#include <string>
 #include <algorithm> // for std::max
 #define NO_MATCH UINT_MAX
 
@@ -27,71 +27,83 @@ static inline Sequence pathToSeq(Path<Kmer> path)
 	return seq;
 }
 
+/**
+ * Choose a suitable starting kmer for a path search and
+ * return its position. More specifically, find the kmer
+ * closest to the end of the given sequence that is followed by
+ * at least (numMatchesThreshold - 1) consecutive kmers that
+ * are also present in the Bloom filter de Bruijn graph. If there
+ * is no sequence of matches of length numMatchesThreshold,
+ * use the longest sequence of matching kmers instead.
+ *
+ * The default behaviour of this method is to choose
+ * the last kmer in the sequence that is present in the
+ * Bloom filter de Bruijn graph.
+ *
+ * @param seq sequence in which to find start kmer
+ * @param k kmer size
+ * @param g de Bruijn graph
+ * @param numMatchesThreshold if we encounter a sequence
+ * of numMatchesThreshold consecutive kmers in the Bloom filter,
+ * choose the kmer at the beginning of that sequence
+ * @return position of chosen start kmer
+ */
 template<typename Graph>
-static inline unsigned getStartKmerPos(unsigned k, const FastaRecord& read,
-		const Graph& g, bool rc = false, bool longSearch = false)
+static inline unsigned getStartKmerPos(const Sequence& seq,
+	unsigned k, Direction dir, const Graph& g,
+	unsigned numMatchesThreshold=1)
 {
-	if (read.seq.size() < k)
-		return NO_MATCH;
+	assert(numMatchesThreshold > 0);
 
-	// build a vector indicating whether each kmer is a match
-	// Note: the vector intentionally has an extra false element at
-	// the end, for the second loop below.
-
-	const std::string& seq = read.seq;
-	std::vector<bool> match(seq.length() - k + 2, false);
-	bool foundMatch = false;
-	for (unsigned i = 0; i < seq.length() - k + 1; i++) {
-		std::string kmerStr = seq.substr(i, k);
-		size_t pos = kmerStr.find_first_not_of("AGCTagct");
-		if (pos != std::string::npos) {
-			i += pos;
-			continue;
-		}
-		Kmer kmer(kmerStr);
-		if (rc)
-			kmer.reverseComplement();
-		if (vertex_exists(kmer, g)) {
-			foundMatch = true;
-			match[i] = true;
-		}
-	}
-	if (!foundMatch)
+	if (seq.size() < k)
 		return NO_MATCH;
 
-	// find the longest string of matches
+	int inc, startPos, endPos;
+	if (dir == FORWARD) {
+		inc = -1;
+		startPos = seq.length() - k;
+		endPos = -1;
+	} else {
+		assert(dir == REVERSE);
+		inc = 1;
+		startPos = 0;
+		endPos = seq.length() - k + 1;
+	}
 
-	unsigned maxMatchLength = 0;
+	unsigned matchCount = 0;
+	unsigned maxMatchLen = 0;
 	unsigned maxMatchPos = 0;
-	unsigned matchLength = 0;
-	unsigned matchPos = 0;
-	bool matchPosSet = false;
-	for (unsigned i = 0; i < match.size(); i++) {
-		if (match[i]) {
-			if (!matchPosSet) {
-				matchPos = i;
-				matchPosSet = true;
+	int i;
+	for (i = startPos; i != endPos; i += inc) {
+		assert(i >= 0 && i <= (int)(seq.length() - k + 1));
+		std::string kmerStr = seq.substr(i, k);
+		if (kmerStr.find_first_not_of("AGCTagct")
+			!= std::string::npos ||
+			!vertex_exists(Kmer(kmerStr), g)) {
+			if (matchCount > maxMatchLen) {
+				assert(i - inc >= 0 &&
+					i - inc < (int)(seq.length() - k + 1));
+				maxMatchPos = i - inc;
+				maxMatchLen = matchCount;
 			}
-			matchLength++;
+			matchCount = 0;
 		} else {
-			// Note: match has an extra false element at the end,
-			// so this else block will get executed at least once.
-			if ((longSearch && matchLength > maxMatchLength)
-					|| (!longSearch && matchLength >= maxMatchLength))
-			{
-				maxMatchPos = matchPos;
-				maxMatchLength = matchLength;
-			}
-			matchLength = 0;
-			matchPosSet = false;
+			matchCount++;
+			if (matchCount >= numMatchesThreshold)
+				return i;
 		}
 	}
-	assert(maxMatchLength > 0);
-
-	if (longSearch)
-		return maxMatchPos;
+	/* handle case where first/last kmer in seq is a match */
+	if (matchCount > maxMatchLen) {
+		assert(i - inc >= 0 &&
+			i - inc < (int)(seq.length() - k + 1));
+		maxMatchPos = i - inc;
+		maxMatchLen = matchCount;
+	}
+	if (maxMatchLen == 0)
+		return NO_MATCH;
 	else
-		return maxMatchPos + maxMatchLength - 1;
+		return maxMatchPos;
 }
 
 struct BaseChangeScore {
@@ -117,8 +129,6 @@ static inline bool correctSingleBaseError(const Graph& g, unsigned k,
 	if (read.seq.length() < k)
 		return false;
 
-	SUPPRESS_UNUSED_WARNING(correctedPos);
-
 	const std::string bases = "AGCT";
 	const size_t minScore = 3;
 	std::vector<BaseChangeScore> scores;
diff --git a/Konnector/konnector.cc b/Konnector/konnector.cc
index e09eb14..1c8f80d 100644
--- a/Konnector/konnector.cc
+++ b/Konnector/konnector.cc
@@ -31,18 +31,7 @@
 # include "Bloom/ConcurrentBloomFilter.h"
 #endif
 
-#undef USESEQAN
-
-#if USESEQAN
-#include <seqan/align.h>
-#include <seqan/sequence.h>
-#include <seqan/align_split.h>
-#endif
-
 using namespace std;
-#if USESEQAN
-using namespace seqan;
-#endif
 
 #define PROGRAM "konnector"
 
@@ -63,11 +52,27 @@ static const char USAGE_MESSAGE[] =
 "  -j, --threads=N            use N parallel threads [1]\n"
 "  -k, --kmer=N               the size of a k-mer\n"
 "  -b, --bloom-size=N         size of bloom filter [500M]\n"
+"  -c, --min-coverage=N       kmer coverage threshold for error correction [2].\n"
+"                             This option specifies the number of levels in the\n"
+"                             cascading Bloom filter; it has no effect if the Bloom\n"
+"                             filter is loaded from an external file.\n"
 "  -B, --max-branches=N       max branches in de Bruijn graph traversal;\n"
 "                             use 'nolimit' for no limit [350]\n"
 "  -d, --dot-file=FILE        write graph traversals to a DOT file\n"
+"  -D, --dup-bloom-size=N     use an additional Bloom filter to avoid\n"
+"                             assembling the same region of the genome\n"
+"                             multiple times. This option is highly\n"
+"                             recommended when the -E (--extend) option\n"
+"                             and has no effect otherwise. As a rule of\n"
+"                             thumb, the Bloom filter size should be\n"
+"                             about twice the target genome size [disabled]\n"
 "  -e, --fix-errors           find and fix single-base errors when reads\n"
 "                             have no kmers in bloom filter [disabled]\n"
+"  -E, --extend               in addition to finding a connecting path,\n"
+"                             extend the reads outwards to the next\n"
+"                             dead end or branching point in the de Brujin\n"
+"                             graph. If the reads were not successfully\n"
+"                             connected, extend them inwards as well.\n"
 "  -f, --min-frag=N           min fragment size in base pairs [0]\n"
 "  -F, --max-frag=N           max fragment size in base pairs [1000]\n"
 "  -i, --input-bloom=FILE     load bloom filter from FILE\n"
@@ -79,10 +84,6 @@ static const char USAGE_MESSAGE[] =
 "      --trim-masked          trim masked bases from the ends of reads\n"
 "      --no-trim-masked       do not trim masked bases from the ends\n"
 "                             of reads [default]\n"
-"  -l, --long-search          start path search as close as possible\n"
-"                             to the beginnings of reads. Takes more time\n"
-"                             but improves results when bloom filter false\n"
-"                             positive rate is high [disabled]\n"
 "  -m, --read-mismatches=N    max mismatches between paths and reads; use\n"
 "                             'nolimit' for no limit [nolimit]\n"
 "  -M, --max-mismatches=N     max mismatches between all alternate paths;\n"
@@ -110,6 +111,19 @@ static const char USAGE_MESSAGE[] =
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 const unsigned g_progressStep = 1000;
+/*
+ * ignore branches less than this length
+ *(false positive branches)
+ */
+const unsigned g_trimLen = 3;
+
+/*
+ * Bloom filter use to keep track of portions
+ * of genome that have already been assembled.
+ * This Bloom filter is only used when the
+ * -E (--extend) option is in effect.
+ */
+BloomFilter g_dupBloom;
 
 namespace opt {
 
@@ -119,16 +133,12 @@ namespace opt {
 	/** The size of the bloom filter in bytes. */
 	size_t bloomSize = 500 * 1024 * 1024;
 
+	/** The maximum count value of the Bloom filter. */
+	unsigned minCoverage = 2;
+
 	/** Input read files are interleaved? */
 	bool interleaved = false;
 
-	/**
-	 * Choose start/goal kmers for path search as close as
-	 * possible to beginning (5' end) of reads. Improves
-	 * results when bloom filter FPR is high.
-	 */
-	bool longSearch = false;
-
 	/** Max active branches during de Bruijn graph traversal */
 	unsigned maxBranches = 350;
 
@@ -136,11 +146,25 @@ namespace opt {
 	static string dotPath;
 
 	/**
+	 * Dup Bloom filter size.
+	 * The dup filter is used to avoid assembling duplicate
+	 * sequences when the -E (--extend) option is in effect.
+	 */
+	size_t dupBloomSize = 0;
+
+	/**
 	 * Find and fix single base errors when a read has no
 	 * kmers in the bloom filter.
 	 */
 	bool fixErrors = false;
 
+	/**
+	 * Extend reads outwards until the next dead or branching
+	 * point in the de Bruijn graph.  If a read pair is not
+	 * successfully connected, extend them inwards as well.
+	 */
+	bool extend = false;
+
 	/** The size of a k-mer. */
 	unsigned k;
 
@@ -195,22 +219,28 @@ static struct {
 	size_t readPairsProcessed;
 	size_t readPairsMerged;
 	size_t skipped;
+	/* counts below are used only when -E is enabled */
+	size_t mergedAndExtended;
+	size_t mergedAndSkipped;
+	size_t singleEndCorrected;
 } g_count;
 
-static const char shortopts[] = "b:B:d:ef:F:i:Ij:k:lm:M:no:P:q:r:s:t:v";
+static const char shortopts[] = "b:B:c:d:D:eEf:F:i:Ij:k:lm:M:no:P:q:r:s:t:v";
 
 enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "bloom-size",       required_argument, NULL, 'b' },
+	{ "min-coverage",     required_argument, NULL, 'c' },
 	{ "max-branches",     required_argument, NULL, 'B' },
 	{ "dot-file",         required_argument, NULL, 'd' },
+	{ "dup-bloom-size",   required_argument, NULL, 'D' },
 	{ "fix-errors",       no_argument, NULL, 'e' },
+	{ "extend",           no_argument, NULL, 'E' },
 	{ "min-frag",         required_argument, NULL, 'f' },
 	{ "max-frag",         required_argument, NULL, 'F' },
 	{ "input-bloom",      required_argument, NULL, 'i' },
 	{ "interleaved",      no_argument, NULL, 'I' },
-	{ "long-search",      no_argument, NULL, 'l' },
 	{ "threads",          required_argument, NULL, 'j' },
 	{ "kmer",             required_argument, NULL, 'k' },
 	{ "chastity",         no_argument, &opt::chastityFilter, 1 },
@@ -236,178 +266,422 @@ static const struct option longopts[] = {
 	{ NULL, 0, NULL, 0 }
 };
 
-#if USESEQAN
-const string r1 =
-"AGAATCAACCAACCGTTCAATGATATAATCAAGAGCGATATTGTAATCTTTGTTTCT";
-const string r2 =
-"CGACGTCCACCAATTCGTCCCTGTGCACGAGCAGTTTCCAGTCCAGCTTTTGTTCGT";
-const string ins =
-"AGAATCAACCAACCGTTCAATGATATAATCAAGAGCGATATTGTAATCTTTGTTTCTGTCACCCGGCCCCCACGACTCAAGGATTAGACCATAAACACCATCCTCTTCACCTATCGAACACTCAGCTTTCAGTTCAATTCCATTATTATCAAAAACATGCATAATATTAATCTTTAATCAATTTTTCACGACAATACTACTTTTATTGATAAAATTGCAACAAGTTGCTGTTGTTTTACTTTCTTTTGTACACAAAGTGTCTTTAACTTTATTTATCCCCTGCAGGAAACCTCTTATACAAAGTTGACACACCAACATCATAGATAATCGCCACCTTCTGGCGAGGAGTTCCTGCTGCAATTAATCGTCCAGCTTGTGCCCATTGTTCTGGTGTAAGTTTGGGACGACGTCCACCAATTCGTCCCTGTGCACGAGCAGTTTCCAGTCCAGCTTTTGTTCGT";
-
-static void seqanTests()
+/**
+ * Return true if the Bloom filter contains all of the
+ * kmers in the given sequence.
+ */
+static bool bloomContainsSeq(const BloomFilter& bloom, const Sequence& seq)
 {
-	typedef String<Dna> DS;
-	typedef Align<DS> Alignment;
-
-    //DS seq1 = "TTGT";
-    //DS seq2 = "TTAGT";
-	DS ref = ins;
-	DS seq1 = r1;
-	DS seq2 = r2;
-
-    Alignment align1;
-	resize(rows(align1), 2);
-	assignSource(row(align1, 0), ref);
-	assignSource(row(align1, 1), seq1);
-    Alignment align2;
-	resize(rows(align2), 2);
-	assignSource(row(align2, 0), ref);
-	assignSource(row(align2, 1), seq2);
-
-	Score<int> scoring(2, -2, -50, -100);
-
-	cout << splitAlignment(align1, align2, scoring) << endl;
-	cout << align1 << endl;
-	cout << align2 << endl;
-
-	cout << localAlignment(align1, scoring) << endl;
-	cout << align1 << endl;
-
-	cout << localAlignment(align2, scoring) << endl;
-	cout << align2 << endl;
+	if (containsAmbiguityCodes(seq)) {
+		Sequence seqCopy = seq;
+		flattenAmbiguityCodes(seqCopy, false);
+		for (KmerIterator it(seqCopy, opt::k); it != KmerIterator::end();
+			++it) {
+			if (!bloom[*it])
+				return false;
+		}
+		return true;
+	}
+	for (KmerIterator it(seq, opt::k); it != KmerIterator::end(); ++it) {
+		if (!bloom[*it])
+			return false;
+	}
+	return true;
 }
-#endif
 
-/** Connect a read pair. */
+/**
+ * Load the kmers of a given sequence into a Bloom filter.
+ */
+static inline void loadSeq(BloomFilter& bloom, unsigned k, const Sequence& seq)
+{
+	if (containsAmbiguityCodes(seq)) {
+		Sequence seqCopy = seq;
+		Sequence rc = reverseComplement(seqCopy);
+		flattenAmbiguityCodes(seqCopy, false);
+		flattenAmbiguityCodes(rc, false);
+		Bloom::loadSeq(bloom, k, seqCopy);
+		Bloom::loadSeq(bloom, k, rc);
+	} else {
+		Bloom::loadSeq(bloom, k, seq);
+	}
+}
+
+/**
+ * Extend a read/pseudoread both left and right until
+ * we hit the next dead end or branching point in the
+ * de Bruijn graph.
+ *
+ * @param seq sequence to be extended
+ * @param k kmer size
+ * @param g de Bruijn graph
+ * return true if the read was extended in either
+ * (or both) directions, false otherwise
+ */
+template <typename Graph>
+static bool extendRead(Sequence& seq, unsigned k, const Graph& g)
+{
+	ExtendSeqResult result;
+	bool extended = false;
+
+	/*
+	 * offset start pos to reduce chance of hitting
+	 * a dead end on a false positive kmer
+	 */
+	const unsigned runLengthHint = 3;
+	unsigned startPos = getStartKmerPos(seq, k, FORWARD, g,
+		runLengthHint);
+	if (startPos != NO_MATCH) {
+		assert(startPos <= seq.length() - k);
+		result = extendSeq(seq, FORWARD, startPos, k, g,
+				NO_LIMIT, g_trimLen, opt::mask);
+		if (result == ES_EXTENDED_TO_DEAD_END ||
+				result == ES_EXTENDED_TO_BRANCHING_POINT ||
+				result == ES_EXTENDED_TO_CYCLE) {
+			extended = true;
+		}
+	}
+
+	startPos = getStartKmerPos(seq, k, REVERSE, g, runLengthHint);
+	if (startPos != NO_MATCH) {
+		assert(startPos <= seq.length() - k);
+		result = extendSeq(seq, REVERSE, startPos, k, g,
+				NO_LIMIT, g_trimLen, opt::mask);
+		if (result == ES_EXTENDED_TO_DEAD_END ||
+				result == ES_EXTENDED_TO_BRANCHING_POINT ||
+				result == ES_EXTENDED_TO_CYCLE) {
+			extended = true;
+		}
+	}
+
+	return extended;
+}
+
+enum ExtendResult { ER_NOT_EXTENDED, ER_REDUNDANT, ER_EXTENDED };
+
+/**
+ * Attempt to extend a merged read (a.k.a. pseudoread)
+ * outward to the next branching point or dead end in
+ * the de Bruijn graph.
+ *
+ * @param seq pseudoread to be extended
+ * @param k kmer size
+ * @param g de Bruijn graph in which to perform extension
+ * @return ExtendResult (ER_NOT_EXTENDED, ER_EXTENDED,
+ * ER_REDUNDANT)
+ */
 template <typename Graph>
+static inline ExtendResult
+extendReadIfNonRedundant(Sequence& seq, unsigned k, const Graph& g)
+{
+	bool redundant = false;
+	if (opt::dupBloomSize > 0) {
+		/*
+		 * Check to see if the current pseudoread
+		 * is contained in a region of the genome
+		 * that has already been assembled.
+		 */
+#pragma omp critical(dupBloom)
+		redundant = bloomContainsSeq(g_dupBloom, seq);
+		if (redundant)
+			return ER_REDUNDANT;
+	}
+	Sequence origSeq = seq;
+	bool extended = extendRead(seq, k, g);
+	if (opt::dupBloomSize > 0) {
+		/*
+		 * mark the extended read as an assembled
+		 * region of the genome.
+		 */
+#pragma omp critical(dupBloom)
+		{
+			/* must check again to avoid race conditions */
+			if (!bloomContainsSeq(g_dupBloom, origSeq))
+				loadSeq(g_dupBloom, opt::k, seq);
+			else
+				redundant = true;
+		}
+		if (redundant)
+			return ER_REDUNDANT;
+	}
+	assert(!redundant);
+	if (extended)
+		return ER_EXTENDED;
+	else
+		return ER_NOT_EXTENDED;
+}
+
+/**
+ * Print progress stats about reads merged/extended so far.
+ */
+static inline void printProgressMessage()
+{
+	cerr << "Merged " << g_count.uniquePath + g_count.multiplePaths << " of "
+		<< g_count.readPairsProcessed << " read pairs";
+
+	if (opt::extend) {
+		cerr << ", corrected/extended " << g_count.singleEndCorrected << " of "
+			<< (g_count.readPairsProcessed - g_count.uniquePath -
+				g_count.multiplePaths) * 2
+		<< " unmerged reads";
+	}
+
+	cerr << " (no start/goal kmer: " << g_count.noStartOrGoalKmer << ", "
+		<< "no path: " << g_count.noPath << ", "
+		<< "too many paths: " << g_count.tooManyPaths << ", "
+		<< "too many branches: " << g_count.tooManyBranches << ", "
+		<< "too many path/path mismatches: " << g_count.tooManyMismatches << ", "
+		<< "too many path/read mismatches: " << g_count.tooManyReadMismatches << ", "
+		<< "contains cycle: " << g_count.containsCycle << ", "
+		<< "skipped: " << g_count.skipped
+		<< ")\n";
+}
+
+
+/**
+ * For a successfully merged read pair, get the sequence
+ * representing the connecting path between the two reads.
+ */
+template <typename Bloom>
+static inline string getConnectingSeq(ConnectPairsResult& result,
+	unsigned k, const Bloom& bloom)
+{
+	assert(result.pathResult == FOUND_PATH);
+	(void)bloom;
+
+	vector<FastaRecord>& paths = result.mergedSeqs;
+	assert(paths.size() > 0);
+
+	Sequence& seq = (paths.size() == 1) ?
+		paths.front().seq : result.consensusSeq.seq;
+
+	/*
+	 * initialize sequence to the chars between the
+	 * start and goal kmers of the path search.
+	 */
+	int startPos = result.startKmerPos;
+	int endPos = seq.length() - result.goalKmerPos - k;
+	assert(startPos >= 0 && startPos <=
+		(int)(seq.length() - k + 1));
+
+	return seq.substr(startPos, endPos - startPos + k);
+}
+
+/** Connect a read pair. */
+template <typename Graph, typename Bloom>
 static void connectPair(const Graph& g,
-	const FastqRecord& read1,
-	const FastqRecord& read2,
+	const Bloom& bloom,
+	FastqRecord& read1,
+	FastqRecord& read2,
 	const ConnectPairsParams& params,
 	ofstream& mergedStream,
 	ofstream& read1Stream,
 	ofstream& read2Stream,
 	ofstream& traceStream)
 {
-	bool skip = false;
-
+	/*
+	 * Implements the -r option, which is used to only
+	 * process a subset of the input read pairs.
+	 */
 	if (!opt::readName.empty() &&
 		read1.id.find(opt::readName) == string::npos) {
 #pragma omp atomic
 		++g_count.skipped;
-		skip = true;
+		return;
 	}
 
-	if (!skip) {
+	ConnectPairsResult result =
+		connectPairs(opt::k, read1, read2, g, params);
 
-		ConnectPairsResult result =
-			connectPairs(opt::k, read1, read2, g, params);
+	vector<FastaRecord>& paths = result.mergedSeqs;
+	bool mergedSeqRedundant = false;
+	bool read1Corrected = false;
+	bool read1Redundant = false;
+	bool read2Corrected = false;
+	bool read2Redundant = false;
 
-		vector<FastaRecord>& paths = result.mergedSeqs;
+	/*
+	 * extend reads inwards or outwards up to the
+	 * next dead end or branching point in the de
+	 * Brujin graph
+	 */
+	if (opt::extend) {
+		ExtendResult extendResult;
+		if (result.pathResult == FOUND_PATH
+			&& result.pathMismatches <= params.maxPathMismatches
+			&& result.readMismatches <= params.maxReadMismatches) {
+			assert(paths.size() > 0);
+			Sequence& seq = (paths.size() == 1) ?
+				paths.front().seq : result.consensusSeq.seq;
+			seq = getConnectingSeq(result, opt::k, bloom);
+			extendResult = extendReadIfNonRedundant(
+				seq, opt::k, g);
+			if (extendResult == ER_REDUNDANT) {
+#pragma omp atomic
+				g_count.mergedAndSkipped++;
+				mergedSeqRedundant = true;
+			} else if (extendResult == ER_EXTENDED) {
+#pragma omp atomic
+				g_count.mergedAndExtended++;
+			}
+		} else {
 
-		if (!opt::tracefilePath.empty())
-#pragma omp critical(tracefile)
-		{
-			traceStream << result;
-			assert_good(traceStream, opt::tracefilePath);
+			/*
+			 * read pair could not be merged, so try
+			 * to extend each read individually (in
+			 * both directions).
+			 */
+
+//std::cerr << "correcting " << read1.id << " (read 1)" << std::endl;
+			read1Corrected = correctAndExtendSeq(read1.seq,
+				opt::k, g, read1.seq.length(), g_trimLen,
+				opt::mask);
+
+			if (read1Corrected) {
+#pragma omp atomic
+				g_count.singleEndCorrected++;
+				extendResult = extendReadIfNonRedundant(read1.seq,
+					opt::k, g);
+				if (extendResult == ER_REDUNDANT)
+					read1Redundant = true;
+			}
+
+//std::cerr << "correcting " << read2.id << " (read 2)" << std::endl;
+			read2Corrected = correctAndExtendSeq(read2.seq,
+				opt::k, g, read2.seq.length(), g_trimLen,
+				opt::mask);
+
+			if (read2Corrected) {
+#pragma omp atomic
+				g_count.singleEndCorrected++;
+				extendResult = extendReadIfNonRedundant(read2.seq,
+					opt::k, g);
+				if (extendResult == ER_REDUNDANT)
+					read2Redundant = true;
+			}
 		}
+	}
 
-		switch (result.pathResult) {
+	if (!opt::tracefilePath.empty())
+#pragma omp critical(tracefile)
+	{
+		traceStream << result;
+		assert_good(traceStream, opt::tracefilePath);
+	}
 
-			case NO_PATH:
-				assert(paths.empty());
-				if (result.foundStartKmer && result.foundGoalKmer)
+	switch (result.pathResult) {
+
+		case NO_PATH:
+			assert(paths.empty());
+			if (result.foundStartKmer && result.foundGoalKmer)
 #pragma omp atomic
-					++g_count.noPath;
-				else {
+				++g_count.noPath;
+			else {
 #pragma omp atomic
-					++g_count.noStartOrGoalKmer;
-				}
-				break;
+				++g_count.noStartOrGoalKmer;
+			}
+			break;
 
-			case FOUND_PATH:
-				assert(!paths.empty());
-				if (result.pathMismatches > params.maxPathMismatches ||
-						result.readMismatches > params.maxReadMismatches) {
-					if (result.pathMismatches > params.maxPathMismatches)
+		case FOUND_PATH:
+			assert(!paths.empty());
+			if (result.pathMismatches > params.maxPathMismatches ||
+					result.readMismatches > params.maxReadMismatches) {
+				if (result.pathMismatches > params.maxPathMismatches)
 #pragma omp atomic
-						++g_count.tooManyMismatches;
-					else
-						++g_count.tooManyReadMismatches;
-#pragma omp critical(read1Stream)
+					++g_count.tooManyMismatches;
+				else
+					++g_count.tooManyReadMismatches;
+				if (opt::extend) {
+					if (read1Corrected || read2Corrected)
+#pragma omp critical(mergedStream)
+					{
+						if (read1Corrected && !read1Redundant)
+							mergedStream << (FastaRecord)read1;
+						if (read2Corrected && !read2Redundant)
+							mergedStream << (FastaRecord)read2;
+					}
+					if (!read1Corrected || !read2Corrected)
+#pragma omp critical(readStream)
+					{
+						if (!read1Corrected)
+							read1Stream << (FastaRecord)read1;
+						if (!read2Corrected)
+							read1Stream << (FastaRecord)read2;
+					}
+				} else
+#pragma omp critical(readStream)
+				{
 					read1Stream << read1;
-#pragma omp critical(read2Stream)
 					read2Stream << read2;
 				}
-				else if (paths.size() > 1) {
+			}
+			else if (paths.size() > 1) {
 #pragma omp atomic
-					++g_count.multiplePaths;
+				++g_count.multiplePaths;
+				if (!mergedSeqRedundant)
 #pragma omp critical(mergedStream)
 					mergedStream << result.consensusSeq;
-				}
-				else {
+			}
+			else {
 #pragma omp atomic
-					++g_count.uniquePath;
+				++g_count.uniquePath;
+				if (!mergedSeqRedundant)
 #pragma omp critical(mergedStream)
 					mergedStream << paths.front();
-				}
-				break;
+			}
+			break;
 
-			case TOO_MANY_PATHS:
+		case TOO_MANY_PATHS:
 #pragma omp atomic
-				++g_count.tooManyPaths;
-				break;
+			++g_count.tooManyPaths;
+			break;
 
-			case TOO_MANY_BRANCHES:
+		case TOO_MANY_BRANCHES:
 #pragma omp atomic
-				++g_count.tooManyBranches;
-				break;
+			++g_count.tooManyBranches;
+			break;
 
-			case PATH_CONTAINS_CYCLE:
+		case PATH_CONTAINS_CYCLE:
 #pragma omp atomic
-				++g_count.containsCycle;
-				break;
+			++g_count.containsCycle;
+			break;
 
-			case EXCEEDED_MEM_LIMIT:
+		case EXCEEDED_MEM_LIMIT:
 #pragma omp atomic
-				++g_count.exceededMemLimit;
-				break;
-		}
-
-		if (result.pathResult != FOUND_PATH) {
-#pragma omp critical(read1Stream)
-			read1Stream << read1;
-#pragma omp critical(read2Stream)
-			read2Stream << read2;
-		}
+			++g_count.exceededMemLimit;
+			break;
 	}
 
-#pragma omp critical(cerr)
-	{
-		g_count.readPairsProcessed++;
-		if (opt::verbose >= 2)
-		{
-			if(g_count.readPairsProcessed % g_progressStep == 0) {
-				cerr << "Merged " << g_count.uniquePath + g_count.multiplePaths << " of "
-					<< g_count.readPairsProcessed << " read pairs "
-					<< "(no start/goal kmer: " << g_count.noStartOrGoalKmer << ", "
-					<< "no path: " << g_count.noPath << ", "
-					<< "too many paths: " << g_count.tooManyPaths << ", "
-					<< "too many branches: " << g_count.tooManyBranches << ", "
-					<< "too many path/path mismatches: " << g_count.tooManyMismatches << ", "
-					<< "too many path/read mismatches: " << g_count.tooManyReadMismatches << ", "
-					<< "contains cycle: " << g_count.containsCycle << ", "
-					<< "exceeded mem limit: " << g_count.exceededMemLimit << ", "
-					<< "skipped: " << g_count.skipped
-					<< ")\n";
+	if (result.pathResult != FOUND_PATH) {
+		if (opt::extend) {
+			if (read1Corrected || read2Corrected)
+#pragma omp critical(mergedStream)
+			{
+				if (read1Corrected && !read1Redundant)
+					mergedStream << (FastaRecord)read1;
+				if (read2Corrected && !read2Redundant)
+					mergedStream << (FastaRecord)read2;
+			}
+			if (!read1Corrected || !read2Corrected)
+#pragma omp critical(readStream)
+			{
+				if (!read1Corrected)
+					read1Stream << (FastaRecord)read1;
+				if (!read2Corrected)
+					read1Stream << (FastaRecord)read2;
 			}
+		} else
+#pragma omp critical(readStream)
+		{
+			read1Stream << read1;
+			read2Stream << read2;
 		}
 	}
 }
 
 /** Connect read pairs. */
-template <typename Graph, typename FastaStream>
+template <typename Graph, typename FastaStream, typename Bloom>
 static void connectPairs(const Graph& g,
+	const Bloom& bloom,
 	FastaStream& in,
 	const ConnectPairsParams& params,
 	ofstream& mergedStream,
@@ -420,11 +694,20 @@ static void connectPairs(const Graph& g,
 		bool good;
 #pragma omp critical(in)
 		good = in >> a >> b;
-		if (good)
-			connectPair(g, a, b, params, mergedStream, read1Stream,
+		if (good) {
+			connectPair(g, bloom, a, b, params, mergedStream, read1Stream,
 				read2Stream, traceStream);
-		else
+#pragma omp atomic
+			g_count.readPairsProcessed++;
+			if (opt::verbose >= 2)
+#pragma omp critical(cerr)
+			{
+				if(g_count.readPairsProcessed % g_progressStep == 0)
+					printProgressMessage();
+			}
+		} else {
 			break;
+		}
 	}
 }
 
@@ -436,7 +719,7 @@ static inline void setMaxOption(unsigned& arg, istream& in)
 {
 	string str;
 	getline(in, str);
-	if (in.good() && str == "nolimit") {
+	if (!in.fail() && str.compare("nolimit")==0) {
 		arg = NO_LIMIT;
 	} else {
 		istringstream ss(str);
@@ -453,6 +736,7 @@ static inline void setMaxOption(unsigned& arg, istream& in)
 int main(int argc, char** argv)
 {
 	bool die = false;
+	bool minCovOptUsed = false;
 
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -462,12 +746,20 @@ int main(int argc, char** argv)
 			die = true; break;
 		  case 'b':
 			opt::bloomSize = SIToBytes(arg); break;
+		  case 'c':
+			arg >> opt::minCoverage;
+			minCovOptUsed = true;
+			break;
 		  case 'B':
 			setMaxOption(opt::maxBranches, arg); break;
 		  case 'd':
 			arg >> opt::dotPath; break;
+		  case 'D':
+			opt::dupBloomSize = SIToBytes(arg); break;
 		  case 'e':
 			opt::fixErrors = true; break;
+		  case 'E':
+			opt::extend = true; break;
 		  case 'f':
 			arg >> opt::minFrag; break;
 		  case 'F':
@@ -480,8 +772,6 @@ int main(int argc, char** argv)
 			arg >> opt::threads; break;
 		  case 'k':
 			arg >> opt::k; break;
-		  case 'l':
-			opt::longSearch = true; break;
 		  case 'm':
 			setMaxOption(opt::maxReadMismatches, arg); break;
 		  case 'n':
@@ -541,6 +831,12 @@ int main(int argc, char** argv)
 		exit(EXIT_FAILURE);
 	}
 
+	if (!opt::inputBloomPath.empty() && minCovOptUsed) {
+		cerr << PROGRAM ": warning: -c option has no effect when "
+			" using a pre-built Bloom filter (-i option)\n";
+	}
+
+
 #if _OPENMP
 	if (opt::threads > 0)
 		omp_set_num_threads(opt::threads);
@@ -554,7 +850,11 @@ int main(int argc, char** argv)
 
 	assert(opt::bloomSize > 0);
 
-	BloomFilter bloom;
+	if (opt::dupBloomSize > 0)
+		g_dupBloom.resize(opt::dupBloomSize * 8);
+
+	BloomFilter* bloom;
+	CascadingBloomFilter* cascadingBloom = NULL;
 
 	if (!opt::inputBloomPath.empty()) {
 
@@ -562,34 +862,40 @@ int main(int argc, char** argv)
 			std::cerr << "Loading bloom filter from `"
 				<< opt::inputBloomPath << "'...\n";
 
+		bloom = new BloomFilter();
+
 		const char* inputPath = opt::inputBloomPath.c_str();
 		ifstream inputBloom(inputPath, ios_base::in | ios_base::binary);
 		assert_good(inputBloom, inputPath);
-		inputBloom >> bloom;
+		inputBloom >> *bloom;
 		assert_good(inputBloom, inputPath);
 		inputBloom.close();
 
 	} else {
 
-		// Specify bloom filter size in bits. Divide by two
-		// because counting bloom filter requires twice as
-		// much space.
-		size_t bits = opt::bloomSize * 8 / 2;
-		CascadingBloomFilter tempBloom(bits);
+		if (opt::verbose)
+			std::cerr << "Using a minimum kmer coverage threshold of "
+				<< opt::minCoverage << "\n";
+
+		// Specify bloom filter size in bits and divide by number
+		// of levels in cascading Bloom filter.
+
+		size_t bits = opt::bloomSize * 8 / opt::minCoverage;
+		cascadingBloom = new CascadingBloomFilter(bits, opt::minCoverage);
 #ifdef _OPENMP
-		ConcurrentBloomFilter<CascadingBloomFilter> cbf(tempBloom, 1000);
+		ConcurrentBloomFilter<CascadingBloomFilter> cbf(*cascadingBloom, 1000);
 		for (int i = optind; i < argc; i++)
 			Bloom::loadFile(cbf, opt::k, string(argv[i]), opt::verbose);
 #else
 		for (int i = optind; i < argc; i++)
-			Bloom::loadFile(tempBloom, opt::k, string(argv[i]), opt::verbose);
+			Bloom::loadFile(*cascadingBloom, opt::k, string(argv[i]), opt::verbose);
 #endif
-		bloom = tempBloom.getBloomFilter(tempBloom.MAX_COUNT-1);
+		bloom = &cascadingBloom->getBloomFilter(opt::minCoverage - 1);
 	}
 
 	if (opt::verbose)
 		cerr << "Bloom filter FPR: " << setprecision(3)
-			<< 100 * bloom.FPR() << "%\n";
+			<< 100 * bloom->FPR() << "%\n";
 
 	ofstream dotStream;
 	if (!opt::dotPath.empty()) {
@@ -611,20 +917,40 @@ int main(int argc, char** argv)
 		assert_good(traceStream, opt::tracefilePath);
 	}
 
-	DBGBloom<BloomFilter> g(bloom);
+	DBGBloom<BloomFilter> g(*bloom);
+
+	/*
+	 * read pairs that were successfully connected
+	 * (and possibly extended outwards)
+	 */
 
 	string mergedOutputPath(opt::outputPrefix);
-	mergedOutputPath.append("_merged.fa");
+	if (opt::extend)
+		mergedOutputPath.append("_pseudoreads.fa");
+	else
+		mergedOutputPath.append("_merged.fa");
 	ofstream mergedStream(mergedOutputPath.c_str());
 	assert_good(mergedStream, mergedOutputPath);
 
+	/*
+	 * read pairs that were not successfully connected,
+	 * but may have been extended inwards and/or outwards
+	 * (if -E option was used)
+	 */
+
 	string read1OutputPath(opt::outputPrefix);
-	read1OutputPath.append("_reads_1.fq");
+	if (opt::extend)
+		read1OutputPath.append("_reads_1.fa");
+	else
+		read1OutputPath.append("_reads_1.fq");
 	ofstream read1Stream(read1OutputPath.c_str());
 	assert_good(read1Stream, read1OutputPath);
 
 	string read2OutputPath(opt::outputPrefix);
-	read2OutputPath.append("_reads_2.fq");
+	if (opt::extend)
+		read2OutputPath.append("_reads_2.fa");
+	else
+		read2OutputPath.append("_reads_2.fq");
 	ofstream read2Stream(read2OutputPath.c_str());
 	assert_good(read2Stream, read2OutputPath);
 
@@ -639,8 +965,8 @@ int main(int argc, char** argv)
 	params.maxBranches = opt::maxBranches;
 	params.maxPathMismatches = opt::maxMismatches;
 	params.maxReadMismatches = opt::maxReadMismatches;
+	params.kmerMatchesThreshold = 3;
 	params.fixErrors = opt::fixErrors;
-	params.longSearch = opt::longSearch;
 	params.maskBases = opt::mask;
 	params.memLimit = opt::searchMem;
 	params.dotPath = opt::dotPath;
@@ -649,13 +975,13 @@ int main(int argc, char** argv)
 	if (opt::interleaved) {
 		FastaConcat in(argv + optind, argv + argc,
 				FastaReader::FOLD_CASE);
-		connectPairs(g, in, params, mergedStream, read1Stream,
+		connectPairs(g, *bloom, in, params, mergedStream, read1Stream,
 				read2Stream, traceStream);
 		assert(in.eof());
 	} else {
 		FastaInterleave in(argv + optind, argv + argc,
 				FastaReader::FOLD_CASE);
-		connectPairs(g, in, params, mergedStream, read1Stream,
+		connectPairs(g, *bloom, in, params, mergedStream, read1Stream,
 				read2Stream, traceStream);
 		assert(in.eof());
 	}
@@ -705,18 +1031,27 @@ int main(int argc, char** argv)
 				<< " (" << setprecision(3) << (float)100
 					* g_count.containsCycle / g_count.readPairsProcessed
 				<< "%)\n"
-			"Exceeded mem limit: " << g_count.exceededMemLimit
-				<< " (" << setprecision(3) << (float)100
-					* g_count.exceededMemLimit / g_count.readPairsProcessed
-				<< "%)\n"
 			"Skipped: " << g_count.skipped
 				<< " (" << setprecision(3) << (float)100
 					* g_count.skipped / g_count.readPairsProcessed
-				<< "%)\n"
-			"Bloom filter FPR: " << setprecision(3) << 100 * bloom.FPR()
-				<< "%\n";
+				<< "%)\n";
+			if (opt::extend) {
+				cerr << "Unmerged reads corrected/extended: "
+					<< g_count.singleEndCorrected
+					<< " (" << setprecision(3) <<  (float)100
+					* g_count.singleEndCorrected / ((g_count.readPairsProcessed -
+					g_count.uniquePath - g_count.multiplePaths) * 2)
+					<< "%)\n";
+			}
+			std::cerr << "Bloom filter FPR: " << setprecision(3)
+				<< 100 * bloom->FPR() << "%\n";
 	}
 
+	if (!opt::inputBloomPath.empty())
+		delete bloom;
+	else
+		delete cascadingBloom;
+
 	assert_good(mergedStream, mergedOutputPath.c_str());
 	mergedStream.close();
 	assert_good(read1Stream, read1OutputPath.c_str());
diff --git a/Konnector/konnector.h b/Konnector/konnector.h
index 7517a63..e78fac6 100644
--- a/Konnector/konnector.h
+++ b/Konnector/konnector.h
@@ -6,9 +6,12 @@
 #include "DataLayer/FastaInterleave.h"
 #include "Graph/BidirectionalBFS.h"
 #include "Graph/ConstrainedBidiBFSVisitor.h"
+#include "Graph/ExtendPath.h"
 #include "Align/alignGlobal.h"
 #include "Graph/DefaultColorMap.h"
 #include "Graph/DotIO.h"
+#include "Common/Sequence.h"
+#include "Common/KmerSet.h"
 #include <algorithm>
 #include <boost/tuple/tuple.hpp>
 #include <limits>
@@ -20,6 +23,7 @@
 
 struct ConnectPairsResult
 {
+	unsigned k;
 	std::string readNamePrefix;
 	PathSearchResult pathResult;
 	std::vector<FastaRecord> mergedSeqs;
@@ -37,6 +41,7 @@ struct ConnectPairsResult
 	size_t memUsage;
 
 	ConnectPairsResult() :
+		k(0),
 		pathResult(NO_PATH),
 		foundStartKmer(false),
 		foundGoalKmer(false),
@@ -53,7 +58,8 @@ struct ConnectPairsResult
 
 	static std::ostream& printHeaders(std::ostream& out)
 	{
-		out << "read_id" << "\t"
+		out << "k\t"
+			<< "read_id" << "\t"
 			<< "search_result" << "\t"
 			<< "num_paths" << "\t"
 			<< "path_lengths" << "\t"
@@ -72,7 +78,8 @@ struct ConnectPairsResult
 	friend std::ostream& operator <<(std::ostream& out,
 		const ConnectPairsResult& o)
 	{
-		out << o.readNamePrefix << "\t"
+		out << o.k << '\t'
+			<< o.readNamePrefix << "\t"
 			<< PathSearchResultLabel[o.pathResult] << "\t"
 			<< o.mergedSeqs.size() << "\t";
 		if (o.mergedSeqs.size() == 0) {
@@ -85,9 +92,15 @@ struct ConnectPairsResult
 			}
 			out << "\t";
 		}
-		out << o.startKmerPos << "\t"
-			<< o.goalKmerPos << "\t"
-			<< o.numNodesVisited << "\t"
+		if (o.startKmerPos == NO_MATCH)
+			out << "NA\t";
+		else
+			out << o.startKmerPos << "\t";
+		if (o.goalKmerPos == NO_MATCH)
+			out << "NA\t";
+		else
+			out << o.goalKmerPos << "\t";
+		out << o.numNodesVisited << "\t"
 			<< o.maxActiveBranches << "\t"
 			<< o.maxDepthVisitedForward << "\t"
 			<< o.maxDepthVisitedReverse << "\t"
@@ -107,8 +120,8 @@ struct ConnectPairsParams {
 	unsigned maxBranches;
 	unsigned maxPathMismatches;
 	unsigned maxReadMismatches;
+	unsigned kmerMatchesThreshold;
 	bool fixErrors;
-	bool longSearch;
 	bool maskBases;
 	size_t memLimit;
 	std::string dotPath;
@@ -121,8 +134,8 @@ struct ConnectPairsParams {
 		maxBranches(NO_LIMIT),
 		maxPathMismatches(NO_LIMIT),
 		maxReadMismatches(NO_LIMIT),
+		kmerMatchesThreshold(1),
 		fixErrors(false),
-		longSearch(false),
 		maskBases(false),
 		memLimit(std::numeric_limits<std::size_t>::max()),
 		dotStream(NULL)
@@ -198,6 +211,8 @@ static inline ConnectPairsResult connectPairs(
 	const ConnectPairsParams& params)
 {
 	ConnectPairsResult result;
+	result.k = k;
+	result.readNamePrefix = read1.id.substr(0, read1.id.find_last_of("/"));
 
 	if (!isReadNamePair(read1.id, read2.id)) {
 #pragma omp critical(cerr)
@@ -212,11 +227,13 @@ static inline ConnectPairsResult connectPairs(
 		return result;
 	}
 
-	unsigned startKmerPos = getStartKmerPos(k, read1, g,
-			false, params.longSearch);
+	const unsigned numMatchesThreshold = 3;
 
-	unsigned goalKmerPos = getStartKmerPos(k, read2, g,
-			true, params.longSearch);
+	unsigned startKmerPos = getStartKmerPos(read1, k, FORWARD, g,
+		numMatchesThreshold);
+
+	unsigned goalKmerPos = getStartKmerPos(read2, k, FORWARD, g,
+		numMatchesThreshold);
 
 	const FastaRecord* pRead1 = &read1;
 	const FastaRecord* pRead2 = &read2;
@@ -227,8 +244,8 @@ static inline ConnectPairsResult connectPairs(
 	if (startKmerPos == NO_MATCH && params.fixErrors) {
 		correctedRead1 = read1;
 		if (correctSingleBaseError(g, k, correctedRead1, unused)) {
-			startKmerPos = getStartKmerPos(k, correctedRead1, g,
-				false, params.longSearch);
+			startKmerPos = getStartKmerPos(correctedRead1, k, FORWARD, g,
+				params.kmerMatchesThreshold);
 			assert(startKmerPos != NO_MATCH);
 			pRead1 = &correctedRead1;
 		}
@@ -237,8 +254,8 @@ static inline ConnectPairsResult connectPairs(
 	if (goalKmerPos == NO_MATCH && params.fixErrors) {
 		correctedRead2 = read2;
 		if (correctSingleBaseError(g, k, correctedRead2, unused)) {
-			goalKmerPos = getStartKmerPos(k, correctedRead2, g,
-				true, params.longSearch);
+			goalKmerPos = getStartKmerPos(correctedRead2, k, FORWARD, g,
+				params.kmerMatchesThreshold);
 			assert(goalKmerPos != NO_MATCH);
 			pRead2 = &correctedRead2;
 		}
@@ -274,7 +291,6 @@ static inline ConnectPairsResult connectPairs(
 	bidirectionalBFS(g, startKmer, goalKmer, visitor);
 
 	std::vector< Path<Kmer> > paths;
-	result.readNamePrefix = pRead1->id.substr(0, pRead1->id.find_last_of("/"));
 	result.pathResult = visitor.pathsToGoal(paths);
 	result.numNodesVisited = visitor.getNumNodesVisited();
 	result.maxActiveBranches = visitor.getMaxActiveBranches();
@@ -338,4 +354,441 @@ static inline ConnectPairsResult connectPairs(
 	return result;
 }
 
+static inline unsigned getHeadKmerPos(const Sequence& seq, Direction dir,
+	unsigned k)
+{
+	return (dir == FORWARD) ?  seq.length() - k : 0;
+}
+
+static inline Kmer getHeadKmer(const Sequence& seq, Direction dir,
+	unsigned k)
+{
+	return Kmer(seq.substr(getHeadKmerPos(seq, dir, k), k));
+}
+
+template <typename Graph>
+static inline bool extendSeqThroughBubble(Sequence& seq,
+	Direction dir, unsigned startKmerPos, unsigned k,
+	const Graph& g, unsigned trimLen=0, bool maskNew=false)
+{
+	assert(seq.length() >= k);
+	assert(dir == FORWARD || dir == REVERSE);
+
+	/*
+	 * unhandled case: bubble is contained entirely
+	 * within input sequence.
+	 */
+	unsigned bubbleSeqLen = 2*k + 1;
+
+	if (dir == FORWARD &&
+		startKmerPos + bubbleSeqLen <= seq.length()) {
+		return false;
+	} else if (dir == REVERSE &&
+		bubbleSeqLen <= startKmerPos) {
+		return false;
+	}
+
+	Kmer head(seq.substr(startKmerPos, k));
+	std::vector<Kmer> buds = trueBranches(head, dir, g, trimLen);
+
+	/* more than two branches -- not a simple bubble */
+	if (buds.size() != 2)
+		return false;
+
+	Path<Kmer> path1, path2;
+	if (dir == FORWARD) {
+		path1.push_back(head);
+		path2.push_back(head);
+	}
+	path1.push_back(buds.front());
+	path2.push_back(buds.back());
+	if (dir == REVERSE) {
+		path1.push_back(head);
+		path2.push_back(head);
+	}
+	extendPath(path1, dir, g, trimLen, k+2);
+	extendPath(path2, dir, g, trimLen, k+2);
+
+	/* paths lengths not k+1 -- not a simple bubble */
+	if (path1.size() != k+2 || path2.size() != k+2)
+		return false;
+
+	Kmer head1, head2;
+	if (dir == FORWARD) {
+		head1 = path1.back();
+		head2 = path2.back();
+	} else {
+		assert(dir == REVERSE);
+		head1 = path1.front();
+		head2 = path2.front();
+	}
+
+	/* paths don't reconnect -- not a simple bubble */
+	if (head1 != head2)
+		return false;
+
+	NWAlignment alignment;
+	alignPair(pathToSeq(path1), pathToSeq(path2), alignment);
+	Sequence& consensus = alignment.match_align;
+
+	if (dir == FORWARD) {
+		overlaySeq(consensus, seq, startKmerPos, maskNew);
+	} else {
+		overlaySeq(consensus, seq,
+			-consensus.length() + startKmerPos + k, maskNew);
+	}
+
+	return true;
+}
+
+Path<Kmer> seqToPath(const Sequence& seq, unsigned k)
+{
+	assert(seq.length() >= k);
+	Path<Kmer> path;
+	Sequence seqCopy = seq;
+	flattenAmbiguityCodes(seqCopy);
+	for (unsigned i = 0; i < seq.length() - k + 1; ++i) {
+		std::string kmerStr = seq.substr(i, k);
+		path.push_back(Kmer(kmerStr));
+	}
+	return path;
+}
+
+/**
+ * Reason a sequence could not be extended uniquely within
+ * the de Bruijn graph; or if the sequence could be extended,
+ * the reason we stopped extending.
+ */
+enum ExtendSeqResult {
+	/*
+	 * could not find a start kmer in Bloom filter for
+	 * path traversal
+	 */
+	ES_NO_START_KMER=0,
+	/* start kmer had no neighbours */
+	ES_DEAD_END,
+	/* start kmer had two or more branches */
+	ES_BRANCHING_POINT,
+	/* start kmer was part of a cycle */
+	ES_CYCLE,
+	/* input seq was already max length or less */
+	ES_LENGTH_LIMIT,
+	/*
+	 * we did not make it from the start kmer to the
+	 * beginning/end of the input sequence, because
+	 * we hit a dead end.
+	 */
+	ES_INTERNAL_DEAD_END,
+	/*
+	 * we did not make it from the start kmer to the
+	 * beginning/end of the input sequence, because
+	 * we hit a branching point.
+	 */
+	ES_INTERNAL_BRANCHING_POINT,
+	/*
+	 * we did not make from the start kmer to the
+	 * beginning/end of the input sequence, because
+	 * we hit a cycle.
+	 */
+	ES_INTERNAL_CYCLE,
+	/*
+	 * we successfully extended the input sequence
+	 * and stopped extending at a dead end.
+	 */
+	ES_EXTENDED_TO_DEAD_END,
+	/*
+	 * we successfully extended the input sequence
+	 * and stopped extending at a branching point.
+	 */
+	ES_EXTENDED_TO_BRANCHING_POINT,
+	/*
+	 * we successfully extended the input sequence
+	 * and stopped when we hit a cycle.
+	 */
+	ES_EXTENDED_TO_CYCLE,
+	/*
+	 * we successfully extended the input sequence
+	 * the given length limit
+	 */
+	ES_EXTENDED_TO_LENGTH_LIMIT
+};
+
+/**
+ * Extend a sequence up to the next dead end or branching point in the
+ * de Bruijn graph.
+ *
+ * @param seq sequence to be extended (modified by this function)
+ * @param dir direction to extend (FORWARD or REVERSE)
+ * @param trimLen ignore branches less than or equal to this length
+ * @param k kmer size of de Bruijn graph
+ * @param g de Bruijn graph
+ * @return ExtendSeqResult (ES_NO_START_KMER, ES_DEAD_END,
+ * ES_BRANCHING_POINT, ES_EXTENDED_TO_BRANCHING_POINT,
+ * ES_EXTENDED_TO_DEAD_END)
+ */
+template <typename Graph>
+static inline ExtendSeqResult extendSeq(Sequence& seq, Direction dir,
+	unsigned startKmerPos, unsigned k, const Graph& g,
+	unsigned maxLen=NO_LIMIT, unsigned trimLen=0,
+	bool maskNew=false)
+{
+	if (seq.length() < k)
+		return ES_NO_START_KMER;
+
+	assert(startKmerPos < seq.length() - k + 1);
+
+	if (maxLen < seq.length())
+		maxLen = seq.length();
+
+	size_t origSeqLen = seq.length();
+
+	/*
+	 * temporarily switch orientation so that REVERSE and FORWARD cases
+	 * can be handled in the same way.
+	 */
+
+	if (dir == REVERSE) {
+		startKmerPos = seq.length() - startKmerPos - k;
+		assert(startKmerPos < seq.length() - k + 1);
+		seq = reverseComplement(seq);
+	}
+
+	/* initialize the path to be extended */
+
+	std::string kmerStr = seq.substr(startKmerPos, k);
+	if (kmerStr.find_first_not_of("AGCTagct") !=
+		std::string::npos)
+		return ES_NO_START_KMER;
+
+	Kmer startKmer(kmerStr);
+	Path<Kmer> path;
+	path.push_back(startKmer);
+	PathExtensionResult pathResult = LENGTH_LIMIT;
+
+	/* track visited kmers to avoid traversing cycles in an infinite loop */
+
+	KmerSet visited(k);
+	visited.loadSeq(seq);
+
+	/* extend through unambiguous paths and simple bubbles */
+
+	bool done = false;
+	while (!done && seq.length() < maxLen) {
+
+		/*
+		 * extend the path up to the next dead end or branching point
+		 * in the de Bruijn graph.
+		 */
+		unsigned maxPathLen;
+		if (maxLen == NO_LIMIT) {
+			maxPathLen = NO_LIMIT;
+		} else {
+			maxPathLen = (unsigned)std::max((int)1,
+				(int)(maxLen - startKmerPos - k + 1));
+		}
+
+		pathResult = extendPath(path, FORWARD, g, trimLen,
+			maxPathLen);
+
+		/*
+		 * give up if we don't at extend beyond end
+		 * of existing sequence
+		 */
+		unsigned overlappingKmers = seq.length() - startKmerPos - k + 1;
+		if (path.size() <= overlappingKmers) {
+			done = true;
+			break;
+		}
+
+		/* check for cycle */
+		path.erase(path.begin(), path.begin() + overlappingKmers);
+		for (Path<Kmer>::iterator it = path.begin();
+			it != path.end(); ++it) {
+			if (visited.containsKmer(*it)) {
+				pathResult = EXTENDED_TO_CYCLE;
+				path.erase(it, path.end());
+				break;
+			}
+			visited.addKmer(*it);
+		}
+
+		/*
+		 * graft path extension onto original input sequence
+		 */
+		if (path.size() > 0 &&
+			(pathResult == EXTENDED_TO_DEAD_END ||
+			pathResult == EXTENDED_TO_BRANCHING_POINT ||
+			pathResult == EXTENDED_TO_CYCLE ||
+			pathResult == EXTENDED_TO_LENGTH_LIMIT))
+		{
+			std::string pathSeq = pathToSeq(path);
+			overlaySeq(pathSeq, seq, seq.length() - k + 1, maskNew);
+		}
+
+		/*
+		 * extend through simple bubbles
+		 */
+		done = true;
+		if (seq.length() < maxLen &&
+			(pathResult == BRANCHING_POINT ||
+			pathResult == EXTENDED_TO_BRANCHING_POINT)) {
+			startKmerPos = startKmerPos + path.size() - 1;
+			assert(startKmerPos < seq.length() - k + 1);
+			if (extendSeqThroughBubble(seq, FORWARD, startKmerPos,
+				k, g, trimLen, maskNew)) {
+
+				/* make sure we don't exceed extension limit */
+				if (seq.length() > maxLen)
+					seq = seq.substr(0, maxLen);
+
+				/* check for cycle */
+				Path<Kmer> bubblePath = seqToPath(seq.substr(startKmerPos), k);
+				for (Path<Kmer>::iterator it = bubblePath.begin();
+					it != bubblePath.end(); ++it) {
+					if (visited.containsKmer(*it)) {
+						pathResult = EXTENDED_TO_CYCLE;
+						bubblePath.erase(it, bubblePath.end());
+						break;
+					}
+					visited.addKmer(*it);
+				}
+
+				/* set up for another round of extension */
+				if (pathResult != EXTENDED_TO_CYCLE && seq.length() < maxLen) {
+					done = false;
+					startKmerPos = seq.length() - k;
+					path.clear();
+					path.push_back(Kmer(seq.substr(startKmerPos)));
+				}
+			}
+		}
+
+	} /* while (!done && seq.length() < maxLen) */
+
+	/* translate and return result code */
+
+	ExtendSeqResult result;
+
+	switch (pathResult)
+	{
+	case EXTENDED_TO_DEAD_END:
+		if (seq.length() > origSeqLen)
+			result = ES_EXTENDED_TO_DEAD_END;
+		else
+			result = ES_INTERNAL_DEAD_END;
+		break;
+	case EXTENDED_TO_BRANCHING_POINT:
+		if (seq.length() > origSeqLen)
+			result = ES_EXTENDED_TO_BRANCHING_POINT;
+		else
+			result = ES_INTERNAL_BRANCHING_POINT;
+		break;
+	case EXTENDED_TO_CYCLE:
+		if (seq.length() > origSeqLen)
+			result = ES_EXTENDED_TO_CYCLE;
+		else
+			result = ES_INTERNAL_CYCLE;
+	case DEAD_END:
+		result = ES_DEAD_END;
+		break;
+	case BRANCHING_POINT:
+		result = ES_BRANCHING_POINT;
+		break;
+	case CYCLE:
+		result = ES_CYCLE;
+		break;
+	case LENGTH_LIMIT:
+		result = ES_LENGTH_LIMIT;
+		break;
+	case EXTENDED_TO_LENGTH_LIMIT:
+		result = ES_EXTENDED_TO_LENGTH_LIMIT;
+		break;
+	default:
+		/* all other cases should be handled above */
+		assert(false);
+	}
+
+	/* switch back to original orientation */
+	if (dir == REVERSE)
+		seq = reverseComplement(seq);
+
+	return result;
+}
+
+/**
+ * Correct the given sequence using the Bloom filter de Bruijn
+ * graph.  The correction is performed by finding the longest
+ * stretch of good kmers in the sequence and extending that
+ * region both left and right.
+ */
+template <typename Graph>
+static inline bool correctAndExtendSeq(Sequence& seq,
+	unsigned k, const Graph& g, unsigned maxLen=NO_LIMIT,
+	unsigned trimLen=0, bool maskNew=false)
+{
+	if (seq.size() < k)
+		return false;
+
+	if (maxLen < seq.length())
+		maxLen = seq.length();
+
+	/*
+	 * find longest stretch of contiguous kmers
+	 * in de Bruijn graph
+	 */
+
+	const unsigned UNSET = UINT_MAX;
+	unsigned matchStart = UNSET;
+	unsigned matchLen = 0;
+	unsigned maxMatchLen = 0;
+	unsigned maxMatchStart = UNSET;
+
+	for (unsigned i = 0; i < seq.length() - k + 1; ++i) {
+		std::string kmerStr = seq.substr(i, k);
+		size_t pos = kmerStr.find_first_not_of("AGCTagct");
+		if (pos != std::string::npos ||
+			!vertex_exists(Kmer(kmerStr), g)) {
+			if (matchStart != UNSET &&
+				matchLen > maxMatchLen) {
+				maxMatchLen = matchLen;
+				maxMatchStart = matchStart;
+			}
+			matchStart = UNSET;
+			matchLen = 0;
+			if (pos != std::string::npos)
+				i += pos;
+		} else {
+			if (matchStart == UNSET)
+				matchStart = i;
+			matchLen++;
+		}
+	}
+	if (matchStart != UNSET && matchLen > maxMatchLen) {
+		maxMatchStart = matchStart;
+		maxMatchLen = matchLen;
+	}
+	if (maxMatchLen == 0)
+		return false;
+	assert(maxMatchStart != UNSET);
+	assert(maxMatchLen > 0);
+
+	unsigned maxMatchSeqLen = maxMatchLen+k-1;
+	unsigned seedSeqLen = std::min(2*k-1, maxMatchSeqLen);
+
+	Sequence correctedSeq = seq.substr(
+		maxMatchStart + maxMatchSeqLen - seedSeqLen,
+		std::string::npos);
+
+	extendSeq(correctedSeq, REVERSE, correctedSeq.length()-k, k, g, 2*k,
+		trimLen, maskNew);
+	if (correctedSeq.length() < 2*k)
+		return false;
+
+	correctedSeq = correctedSeq.substr(0, k);
+	extendSeq(correctedSeq, FORWARD, 0, k, g, 2*k+1, trimLen, maskNew);
+
+	seq = correctedSeq;
+	return true;
+}
+
 #endif
diff --git a/LogKmerCount/logcounter.cc b/LogKmerCount/logcounter.cc
index 15331eb..93a4a84 100644
--- a/LogKmerCount/logcounter.cc
+++ b/LogKmerCount/logcounter.cc
@@ -119,10 +119,10 @@ int main(int argc, char** argv)
 		  case 'v':
 			opt::verbose++; break;
 		  case OPT_HELP:
-			cerr << USAGE_MESSAGE;
+			cout << USAGE_MESSAGE;
 			exit(EXIT_SUCCESS);
 		  case OPT_VERSION:
-			cerr << VERSION_MESSAGE;
+			cout << VERSION_MESSAGE;
 			exit(EXIT_SUCCESS);
 		}
 		if (optarg != NULL && (!arg.eof() || arg.fail())) {
diff --git a/Makefile.am b/Makefile.am
index 47800ee..6314e11 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,16 +2,16 @@ if HAVE_LIBMPI
 Parallel=Parallel
 endif
 
-if HAVE_GTEST
-Unittest=Unittest
-else
-check:
-	@echo "error: To use 'make check' command, please setup"; \
-	echo "       gtest header&library as shown on the Wiki"; \
-	false
+if HAVE_PTHREAD
+GTest=lib/gtest-1.7.0
+UnitTest=Unittest
 endif
 
-dist_doc_DATA = ChangeLog COPYRIGHT LICENSE \
+dist_doc_DATA = \
+	ChangeLog \
+	CITATION.bib CITATION.md \
+	COPYRIGHT \
+	LICENSE \
 	README.css README.html README.md
 
 EXTRA_DIST=doxygen.conf
@@ -19,15 +19,15 @@ EXTRA_DIST=doxygen.conf
 SUBDIRS = \
 	bin \
 	doc \
-	Assembly \
 	Common \
+	Graph \
 	DataLayer \
+	DataBase \
 	FMIndex \
-	Graph \
+	Assembly \
 	dialign \
 	Align \
 	ABYSS $(Parallel) \
-	AdjList \
 	Bloom \
 	Konnector \
 	Consensus \
@@ -40,6 +40,7 @@ SUBDIRS = \
 	MergePaths \
 	Misc \
 	Overlap \
+	PairedDBG \
 	ParseAligns \
 	PathOverlap \
 	PopBubbles \
@@ -48,7 +49,13 @@ SUBDIRS = \
 	kmerprint \
 	FilterGraph \
 	GapFiller \
-	$(Unittest)
+	Sealer \
+	AdjList \
+	$(GTest) \
+	$(UnitTest)
 
 %.html: %.md
 	-multimarkdown $< >$@
+
+clean-local:
+	rm -f README.html
diff --git a/Map/Makefile.am b/Map/Makefile.am
index 1fedfaf..903fd7c 100644
--- a/Map/Makefile.am
+++ b/Map/Makefile.am
@@ -22,7 +22,9 @@ abyss_map_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
 abyss_map_LDADD = \
 	$(top_builddir)/FMIndex/libfmindex.a \
 	$(top_builddir)/DataLayer/libdatalayer.a \
-	$(top_builddir)/Common/libcommon.a
+	$(top_builddir)/Common/libcommon.a \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS)
 
 abyss_map_SOURCES = map.cc
 
diff --git a/Map/index.cc b/Map/index.cc
index beac34a..cb5beb8 100644
--- a/Map/index.cc
+++ b/Map/index.cc
@@ -37,6 +37,9 @@ static const char USAGE_MESSAGE[] =
 "      --fa2bwt            build the BWT directly without the SA\n"
 "      --bwt2fm            build the FM index from the BWT\n"
 "  -a, --alphabet=STRING   use the alphabet STRING [-ACGT]\n"
+"      --alpha             equivalent to -a' ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n"
+"      --dna               equivalent to -a'-ACGT'\n"
+"      --protein           equivalent to -a'#*ACDEFGHIKLMNPQRSTVWY'\n"
 "  -s, --sample=N          sample the suffix array [16]\n"
 "  -d, --decompress        decompress the index FILE\n"
 "  -c, --stdout            write output to standard output\n"
@@ -75,7 +78,8 @@ namespace opt {
 
 static const char shortopts[] = "a:cds:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION,
+	OPT_ALPHA, OPT_DNA, OPT_PROTEIN };
 
 static const struct option longopts[] = {
 	{ "both", no_argument, &opt::indexes, opt::BOTH },
@@ -84,6 +88,9 @@ static const struct option longopts[] = {
 	{ "fa2bwt", no_argument, &opt::fa2bwt, true },
 	{ "bwt2fm", no_argument, &opt::bwt2fm, true },
 	{ "alphabet", optional_argument, NULL, 'a' },
+	{ "alpha", optional_argument, NULL, OPT_ALPHA },
+	{ "dna", optional_argument, NULL, OPT_DNA },
+	{ "protein", optional_argument, NULL, OPT_PROTEIN },
 	{ "decompress", no_argument, NULL, 'd' },
 	{ "sample", required_argument, NULL, 's' },
 	{ "stdout", no_argument, NULL, 'c' },
@@ -182,6 +189,15 @@ int main(int argc, char **argv)
 				opt::alphabet = arg.str();
 				arg.clear(ios::eofbit);
 				break;
+			case OPT_ALPHA:
+				opt::alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+				break;
+			case OPT_DNA:
+				opt::alphabet = "-ACGT";
+				break;
+			case OPT_PROTEIN:
+				opt::alphabet = "#*ACDEFGHIKLMNPQRSTVWY";
+				break;
 			case 'c': opt::toStdout = true; break;
 			case 'd': opt::decompress = true; break;
 			case 's': arg >> opt::sampleSA; break;
diff --git a/Map/map.cc b/Map/map.cc
index 5cc13d1..d642004 100644
--- a/Map/map.cc
+++ b/Map/map.cc
@@ -17,14 +17,14 @@
 #include <cstdlib>
 #include <getopt.h>
 #include <iostream>
-#include <sstream>
 #include <stdint.h>
-#include <string>
 #include <utility>
 #include <queue>
 #if _OPENMP
 # include <omp.h>
 #endif
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 using namespace boost;
@@ -32,6 +32,8 @@ using namespace boost::algorithm;
 
 #define PROGRAM "abyss-map"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Shaun Jackman.\n"
@@ -58,15 +60,27 @@ static const char USAGE_MESSAGE[] =
 "      --no-multi          don't Align unaligned segments [default]\n"
 "      --SS                expect contigs to be oriented correctly\n"
 "      --no-SS             no assumption about contig orientation\n"
+"      --rc                map the sequence and its reverse complement [default]\n"
+"      --no-rc             do not map the reverse complement sequence\n"
+"  -a, --alphabet=STRING   use the alphabet STRING [-ACGT]\n"
+"      --alpha             equivalent to --no-rc -a' ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n"
+"      --dna               equivalent to --rc    -a'-ACGT'\n"
+"      --protein           equivalent to --no-rc -a'#*ACDEFGHIKLMNPQRSTVWY'\n"
 "      --chastity          discard unchaste reads\n"
 "      --no-chastity       do not discard unchaste reads [default]\n"
 "  -v, --verbose           display verbose output\n"
 "      --help              display this help and exit\n"
 "      --version           output version information and exit\n"
+"      --db=FILE           specify path of database repository in FILE\n"
+"      --library=NAME      specify library NAME for database\n"
+"      --strain=NAME       specify strain NAME for database\n"
+"      --species=NAME      specify species NAME for database\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	/** Find matches at least k bp. */
 	static unsigned k;
 
@@ -79,6 +93,12 @@ namespace opt {
 	/** Run a strand-specific RNA-Seq alignments. */
 	static int ss;
 
+	/** Do not map the sequence's reverse complement. */
+	static int norc;
+
+	/** The alphabet. */
+	static string alphabet = "-ACGT";
+
 	/** Identify duplicate and subsumed sequences. */
 	static bool dup = false;
 
@@ -92,9 +112,15 @@ namespace opt {
 	static int verbose;
 }
 
+// for sqlite params
+static bool haveDbParam(false);
+
 static const char shortopts[] = "j:k:l:s:dv";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION,
+	OPT_ALPHA, OPT_DNA, OPT_PROTEIN,
+	OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES,
+};
 
 static const struct option longopts[] = {
 	{ "sample", required_argument, NULL, 's' },
@@ -107,11 +133,22 @@ static const struct option longopts[] = {
 	{ "no-multi", no_argument, &opt::multi, 0 },
 	{ "SS", no_argument, &opt::ss, 1 },
 	{ "no-SS", no_argument, &opt::ss, 0 },
+	{ "rc", no_argument, &opt::norc, 0 },
+	{ "no-rc", no_argument, &opt::norc, 1 },
+	{ "alphabet", optional_argument, NULL, 'a' },
+	{ "alpha", optional_argument, NULL, OPT_ALPHA },
+	{ "dna", optional_argument, NULL, OPT_DNA },
+	{ "protein", optional_argument, NULL, OPT_PROTEIN },
+	{ "decompress", no_argument, NULL, 'd' },
 	{ "verbose", no_argument, NULL, 'v' },
 	{ "chastity", no_argument, &opt::chastityFilter, 1 },
 	{ "no-chastity", no_argument, &opt::chastityFilter, 0 },
 	{ "help", no_argument, NULL, OPT_HELP },
 	{ "version", no_argument, NULL, OPT_VERSION },
+	{ "db", required_argument, NULL, OPT_DB },
+	{ "library", required_argument, NULL, OPT_LIBRARY },
+	{ "strain", required_argument, NULL, OPT_STRAIN },
+	{ "species", required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -244,7 +281,7 @@ static void printDuplicates(const Match& m, const Match& rcm,
 {
 	size_t myLen = m.qspan();
 	size_t maxLen;
-	if (opt::ss)
+	if (opt::ss || opt::norc)
 		maxLen = getMaxLen(m, faIndex, fmIndex);
 	else
 		maxLen = max(getMaxLen(m, faIndex, fmIndex),
@@ -261,7 +298,7 @@ static void printDuplicates(const Match& m, const Match& rcm,
 	}
 	size_t myPos = getMyPos(m, faIndex, fmIndex, rec.id);
 	size_t minPos;
-	if (opt::ss)
+	if (opt::ss || opt::norc)
 		minPos = getMinPos(m, maxLen, faIndex, fmIndex);
 	else
 		minPos = min(getMinPos(m, maxLen, faIndex, fmIndex),
@@ -284,6 +321,8 @@ pair<Match, Match> findMatch(const FMIndex& fmIndex, const string& seq)
 {
 	Match m = fmIndex.find(seq,
 			opt::dup ? seq.length() : opt::k);
+	if (opt::norc)
+		return make_pair(m, Match());
 
 	string rcqseq = reverseComplement(seq);
 	Match rcm;
@@ -460,7 +499,7 @@ static void buildFMIndex(FMIndex& fm, const char* path)
 	}
 
 	transform(s.begin(), s.end(), s.begin(), ::toupper);
-	fm.setAlphabet("-ACGT");
+	fm.setAlphabet(opt::alphabet);
 	fm.assign(s.begin(), s.end());
 }
 
@@ -511,6 +550,9 @@ int main(int argc, char** argv)
 	opt::chastityFilter = false;
 	opt::trimMasked = false;
 
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -523,6 +565,22 @@ int main(int argc, char** argv)
 				break;
 			case 's': arg >> opt::sampleSA; break;
 			case 'd': opt::dup = true; break;
+			case 'a':
+				opt::alphabet = arg.str();
+				arg.clear(ios::eofbit);
+				break;
+			case OPT_ALPHA:
+				opt::alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+				opt::norc = true;
+				break;
+			case OPT_DNA:
+				opt::alphabet = "-ACGT";
+				opt::norc = false;
+				break;
+			case OPT_PROTEIN:
+				opt::alphabet = "#*ACDEFGHIKLMNPQRSTVWY";
+				opt::norc = true;
+				break;
 			case 'v': opt::verbose++; break;
 			case OPT_HELP:
 				cout << USAGE_MESSAGE;
@@ -530,6 +588,20 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db;
+				haveDbParam = true;
+				break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0];
+				haveDbParam = true;
+				break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1];
+				haveDbParam = true;
+				break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -565,6 +637,16 @@ int main(int argc, char** argv)
 		omp_set_num_threads(opt::threads);
 #endif
 
+	if (!opt::db.empty()) {
+		init(db, opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars);
+		addToDb(db, "K", opt::k);
+		addToDb(db, "SS", opt::ss);
+	}
+
 	const char* targetFile(argv[--argc]);
 	ostringstream ss;
 	ss << targetFile << ".fm";
@@ -622,6 +704,9 @@ int main(int argc, char** argv)
 				<< setprecision(3) << (float)bytes / bp << " B/bp.\n";
 	}
 
+	if (!opt::db.empty())
+		addToDb(db, "readContigs", faIndex.size());
+
 	// Check that the indexes are up to date.
 	checkIndexes(targetFile, fmIndex, faIndex);
 
@@ -649,13 +734,23 @@ int main(int argc, char** argv)
 			<< "Mapped " << unique << " of " << total
 			<< " reads uniquely (" << (float)100 * unique / total
 			<< "%)\n";
-		if (opt::ss)
+
+		// TODO: This block shouldn't be in a verbose restricted section.
+		if (!opt::db.empty()) {
+			addToDb(db, "read_alignments_initial", total);
+			addToDb(db, "mapped", mapped);
+			addToDb(db, "mapped_uniq", unique);
+			addToDb(db, "reads_map_ss", g_count.suboptimal);
+		}
+
+		if (opt::ss) {
 			cerr << "Mapped " << g_count.suboptimal
 				<< " (" << (float)100 * g_count.suboptimal / total << "%)"
 				<< " reads to the opposite strand of the optimal mapping.\n"
 				<< "Made " << g_count.subunmapped << " ("
 				<< (float)100 * g_count.subunmapped / total << "%)"
 				<< " unmapped suboptimal decisions.\n";
+		}
 	}
 
 	cout.flush();
diff --git a/Map/overlap.cc b/Map/overlap.cc
index e6ee16e..1c0cd9f 100644
--- a/Map/overlap.cc
+++ b/Map/overlap.cc
@@ -142,7 +142,7 @@ static void addSuffixOverlaps(Graph &g,
 		const FAIRecord& tseq = seqPos.get<0>();
 		size_t tstart = seqPos.get<1>();
 		size_t tend = tstart + fmi.qspan();
-		assert(tend < tseq.size || tstart > 0);
+		assert(tend <= tseq.size);
 		(void)tend;
 		if (tstart > 0) {
 			// This match is due to an ambiguity code in the target sequence.
@@ -189,7 +189,7 @@ static void addPrefixOverlaps(Graph &g,
 		const FAIRecord& tseq = seqPos.get<0>();
 		size_t tstart = seqPos.get<1>();
 		size_t tend = tstart + fmi.qspan();
-		assert(tstart > 0 || tend < tseq.size);
+		assert(tend <= tseq.size);
 		if (tend < tseq.size) {
 			// This match is due to an ambiguity code in the target sequence.
 			continue;
diff --git a/MergePaths/Makefile.am b/MergePaths/Makefile.am
index bf07dd7..377bec7 100644
--- a/MergePaths/Makefile.am
+++ b/MergePaths/Makefile.am
@@ -7,6 +7,8 @@ MergePaths_CPPFLAGS = -I$(top_srcdir) \
 MergePaths_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
 
 MergePaths_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
@@ -19,6 +21,8 @@ MergeContigs_CPPFLAGS = -I$(top_srcdir) \
 	-I$(top_srcdir)/DataLayer
 
 MergeContigs_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Align/libalign.a \
 	$(top_builddir)/Common/libcommon.a
@@ -32,6 +36,8 @@ PathConsensus_CPPFLAGS = -I$(top_srcdir) \
 	-I$(top_srcdir)/SimpleGraph
 
 PathConsensus_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Align/libalign.a \
 	$(top_builddir)/Common/libcommon.a \
diff --git a/MergePaths/MergeContigs.cpp b/MergePaths/MergeContigs.cpp
index fe3612c..fdecdbb 100644
--- a/MergePaths/MergeContigs.cpp
+++ b/MergePaths/MergeContigs.cpp
@@ -24,16 +24,17 @@
 #include <fstream>
 #include <getopt.h>
 #include <iostream>
-#include <iterator>
 #include <limits>
-#include <sstream>
-#include <string>
 #include <vector>
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 
 #define PROGRAM "MergeContigs"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Shaun Jackman.\n"
@@ -63,11 +64,18 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for database\n"
+"      --strain=NAME     specify strain NAME for database\n"
+"      --species=NAME    specify species NAME for database\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k; // used by ContigProperties
+	unsigned pathCount; // num of initial paths
 
 	/** Output FASTA path. */
 	static string out = "-";
@@ -90,7 +98,8 @@ namespace opt {
 
 static const char shortopts[] = "g:k:o:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "adj", no_argument, &opt::format, ADJ },
@@ -105,6 +114,10 @@ static const struct option longopts[] = {
 	{ "verbose",     no_argument,       NULL, 'v' },
 	{ "help",        no_argument,       NULL, OPT_HELP },
 	{ "version",     no_argument,       NULL, OPT_VERSION },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -186,12 +199,12 @@ static void mergeContigs(const Graph& g, const Contigs& contigs,
 	assert(d < 0);
 	unsigned overlap = -d;
 	const Sequence& s = sequence(contigs, v);
-	assert(s.length() > overlap);
+	assert(s.length() >= overlap);
 	Sequence ao;
 	Sequence bo(s, 0, overlap);
 	Sequence o;
 	do {
-		assert(seq.length() > overlap);
+		assert(seq.length() >= overlap);
 		ao = seq.substr(seq.length() - overlap);
 		o = createConsensus(ao, bo);
 		if (!o.empty()) {
@@ -310,6 +323,9 @@ static ContigPaths readPaths(const string& inPath,
 	if (opt::verbose > 0)
 		cerr << "Read " << count << " paths. "
 			"Using " << toSI(getMemoryUsage()) << "B of memory.\n";
+	if (!opt::db.empty())
+		addToDb(db, "Init_paths", count);
+	opt::pathCount = count;
 	assert(in.eof());
 	return paths;
 }
@@ -402,6 +418,9 @@ int main(int argc, char** argv)
 		commandLine = ss.str();
 	}
 
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -418,6 +437,14 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db; break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0]; break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1]; break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -452,6 +479,17 @@ int main(int argc, char** argv)
 		exit(EXIT_FAILURE);
 	}
 
+	if (!opt::db.empty()) {
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars
+		);
+		addToDb(db, "K", opt::k);
+	}
+
 	const char* contigFile = argv[optind++];
 	string adjPath, mergedPathFile;
 	Graph g;
@@ -469,6 +507,10 @@ int main(int argc, char** argv)
 			cerr << "Read " << num_vertices(g) << " vertices. "
 				"Using " << toSI(getMemoryUsage())
 				<< "B of memory.\n";
+		if (!opt::db.empty()) {
+			addToDb(db, "Init_vertices", num_vertices(g));
+			addToDb(db, "Init_edges", num_edges(g));
+		}
 	}
 	mergedPathFile = string(argv[optind++]);
 
@@ -499,6 +541,8 @@ int main(int argc, char** argv)
 			cerr << "Read " << count << " sequences. "
 				"Using " << toSI(getMemoryUsage())
 				<< "B of memory.\n";
+		if (!opt::db.empty())
+			addToDb(db, "Init_seq", count);
 		assert(in.eof());
 		assert(!contigs.empty());
 		opt::colourSpace = isdigit(contigs[0].seq[0]);
@@ -558,6 +602,9 @@ int main(int argc, char** argv)
 						isACGT));
 	}
 
+	if (!opt::graphPath.empty())
+		outputGraph(g, pathIDs, paths, commandLine);
+
 	if (npaths == 0)
 		return 0;
 
@@ -573,9 +620,6 @@ int main(int argc, char** argv)
 			minCovUsed = min(minCovUsed, cov);
 	}
 
-	if (!opt::graphPath.empty())
-		outputGraph(g, pathIDs, paths, commandLine);
-
 	cerr << "The minimum coverage of single-end contigs is "
 		<< minCov << ".\n"
 		<< "The minimum coverage of merged contigs is "
@@ -589,5 +633,27 @@ int main(int argc, char** argv)
 		printContiguityStats(cerr, lengthHistogram, STATS_MIN_LENGTH)
 			<< '\t' << opt::out << '\n';
 	}
+#if 0
+	// assembly contiguity statistics
+	vector<int> vals = passContiguityStatsVal(lengthHistogram,200);
+	vector<string> keys = make_vector<string>()
+		<< "n"
+		<< "n200"
+		<< "nN50"
+		<< "min"
+		<< "N80"
+		<< "N50"
+		<< "N20"
+		<< "Esize"
+		<< "max"
+		<< "sum"
+		<< "nNG50"
+		<< "NG50";
+
+	if (!opt::db.empty()) {
+		for (unsigned a=0; a<vals.size(); a++)
+			addToDb(db, keys[a], vals[a]);
+	}
+#endif
 	return 0;
 }
diff --git a/MergePaths/MergePaths.cpp b/MergePaths/MergePaths.cpp
index 9e3e939..0ed8add 100644
--- a/MergePaths/MergePaths.cpp
+++ b/MergePaths/MergePaths.cpp
@@ -21,23 +21,24 @@
 #include <functional>
 #include <getopt.h>
 #include <iostream>
-#include <iterator>
 #include <limits>
 #include <map>
 #include <numeric>
 #include <set>
-#include <sstream>
-#include <string>
 #include <vector>
 #if _OPENMP
 # include <omp.h>
 #endif
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 using boost::tie;
 
 #define PROGRAM "MergePaths"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Jared Simpson and Shaun Jackman.\n"
@@ -65,10 +66,16 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for database\n"
+"      --strain=NAME     specify strain NAME for database\n"
+"      --species=NAME    specify species NAME for database\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k; // used by GraphIO
 	static string out;
 	static int threads = 1;
@@ -85,7 +92,8 @@ namespace opt {
 
 static const char shortopts[] = "g:j:k:o:s:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "graph",       no_argument,       NULL, 'g' },
@@ -94,10 +102,14 @@ static const struct option longopts[] = {
 	{ "kmer",        required_argument, NULL, 'k' },
 	{ "out",         required_argument, NULL, 'o' },
 	{ "seed-length", required_argument, NULL, 's' },
-	{ "threads",     required_argument,	NULL, 'j' },
+	{ "threads",     required_argument, NULL, 'j' },
 	{ "verbose",     no_argument,       NULL, 'v' },
 	{ "help",        no_argument,       NULL, OPT_HELP },
 	{ "version",     no_argument,       NULL, OPT_VERSION },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -614,6 +626,8 @@ static void addMissingEdges(const Lengths& lengths,
 	}
 	if (opt::verbose > 0)
 		cout << "Added " << numAdded << " missing edges.\n";
+	if (!opt::db.empty())
+		addToDb(db, "addedMissingEdges", numAdded);
 }
 
 /** Remove transitive edges. */
@@ -627,6 +641,10 @@ static void removeTransitiveEdges(PathGraph& pathGraph)
 			<< nbefore << " edges leaving "
 			<< nafter << " edges.\n";
 	assert(nbefore - nremoved == nafter);
+	if (!opt::db.empty()) {
+		addToDb(db, "Edges_init", nbefore);
+		addToDb(db, "Edges_removed_transitive", nremoved);
+	}
 }
 
 /** Remove ambiguous edges that overlap by only a small amount.
@@ -665,6 +683,8 @@ static void removeSmallOverlaps(PathGraph& g,
 	if (opt::verbose > 0)
 		cout << "Removed " << edges.size()
 			<< " small overlap edges.\n";
+	if (!opt::db.empty())
+		addToDb(db, "Edges_removed_small_overlap", edges.size());
 }
 
 /** Output the path overlap graph. */
@@ -812,6 +832,21 @@ static void buildPathGraph(const Lengths& lengths,
 	removeSmallOverlaps(g, paths);
 	if (opt::verbose > 0)
 		printGraphStats(cout, g);
+
+	// graph statistics
+	vector<int> vals = passGraphStatsVal(g);
+	vector<string> keys = make_vector<string>()
+		<< "V"
+		<< "E"
+		<< "degree0pctg"
+		<< "degree1pctg"
+		<< "degree234pctg"
+		<< "degree5pctg"
+		<< "degree_max";
+	if (!opt::db.empty()) {
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
 	outputPathGraph(g);
 }
 
@@ -838,13 +873,18 @@ static Lengths readContigLengths(istream& in)
 /** Read contig lengths. */
 static Lengths readContigLengths(const string& path)
 {
-	ifstream in(path.c_str());
-	assert_good(in, path);
+	ifstream fin(path.c_str());
+	if (path != "-")
+		assert_good(fin, path);
+	istream& in = path == "-" ? cin : fin;
 	return readContigLengths(in);
 }
 
 int main(int argc, char** argv)
 {
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -863,6 +903,14 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db; break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0]; break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1]; break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -903,12 +951,24 @@ int main(int argc, char** argv)
 	if (opt::verbose > 0)
 		cerr << "Reading `" << argv[optind] << "'..." << endl;
 
+	if (!opt::db.empty()) {
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars
+		);
+	}
+
 	Lengths lengths = readContigLengths(argv[optind++]);
 	ContigPathMap originalPathMap = readPaths(
 			lengths, argv[optind++]);
 
 	removeRepeats(originalPathMap);
 
+	if (!opt::db.empty())
+		addToDb(db, "K", opt::k);
 	if (!opt::greedy) {
 		// Assemble the path overlap graph.
 		PathGraph pathGraph;
diff --git a/MergePaths/PathConsensus.cpp b/MergePaths/PathConsensus.cpp
index 09a90b1..5da8845 100644
--- a/MergePaths/PathConsensus.cpp
+++ b/MergePaths/PathConsensus.cpp
@@ -21,17 +21,20 @@
 #include <fstream>
 #include <getopt.h>
 #include <iostream>
-#include <iterator>
 #include <map>
 #include <set>
-#include <string>
 #include <vector>
+#include "VectorUtil.h"
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 using boost::tie;
 
 #define PROGRAM "PathConsensus"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Shaun Jackman and Rong She.\n"
@@ -57,12 +60,22 @@ static const char USAGE_MESSAGE[] =
 "  -o, --out=FILE        output contig paths to FILE\n"
 "  -s, --consensus=FILE  output consensus sequences to FILE\n"
 "  -g, --graph=FILE      output the contig adjacency graph to FILE\n"
+"      --adj             output the graph in ADJ format [default]\n"
+"      --asqg            output the graph in ASQG format\n"
+"      --dot             output the graph in GraphViz format\n"
+"      --gv              output the graph in GraphViz format\n"
+"      --gfa             output the graph in GFA format\n"
+"      --sam             output the graph in SAM format\n"
 "  -a, --branches=N      maximum number of sequences to align\n"
 "                        default: 4\n"
 "  -p, --identity=REAL   minimum identity, default: 0.9\n"
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for database\n"
+"      --strain=NAME     specify strain NAME for database\n"
+"      --species=NAME    specify species NAME for database\n"
 "\n"
 " DIALIGN-TX options:\n"
 "  -D, --dialign-d=N     dialign debug level, default: 0\n"
@@ -73,6 +86,8 @@ static const char USAGE_MESSAGE[] =
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k; // used by ContigProperties
 	static string out;
 	static string consensusPath;
@@ -94,7 +109,8 @@ namespace opt {
 
 static const char shortopts[] = "d:k:o:s:g:a:p:vD:M:P:";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "kmer",        required_argument, NULL, 'k' },
@@ -102,6 +118,12 @@ static const struct option longopts[] = {
 	{ "out",         required_argument, NULL, 'o' },
 	{ "consensus",   required_argument, NULL, 's' },
 	{ "graph",       required_argument, NULL, 'g' },
+	{ "adj",         no_argument,       &opt::format, ADJ },
+	{ "asqg",        no_argument,       &opt::format, ASQG },
+	{ "dot",         no_argument,       &opt::format, DOT },
+	{ "gv",          no_argument,       &opt::format, DOT },
+	{ "gfa",         no_argument,       &opt::format, GFA },
+	{ "sam",         no_argument,       &opt::format, SAM },
 	{ "branches",    required_argument, NULL, 'a' },
 	{ "identity",    required_argument, NULL, 'p' },
 	{ "verbose",     no_argument,       NULL, 'v' },
@@ -110,6 +132,10 @@ static const struct option longopts[] = {
 	{ "dialign-d",   required_argument, NULL, 'D' },
 	{ "dialign-m",   required_argument, NULL, 'M' },
 	{ "dialign-p",   required_argument, NULL, 'P' },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -705,6 +731,7 @@ static ContigPath fillGap(const Graph& g,
 	} else if (solutions.size() == 1) {
 		if (opt::verbose > 1)
 			cerr << "1 path\n" << solutions.front() << '\n';
+		consensus = solutions.front();
 		stats.numMerged++;
 	} else {
 		assert(solutions.size() > 1);
@@ -737,6 +764,10 @@ int main(int argc, char** argv)
 		commandLine = ss.str();
 	}
 
+	if (!opt::db.empty()) {
+		opt::metaVars.resize(3);
+	}
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 			shortopts, longopts, NULL)) != -1;) {
@@ -760,6 +791,14 @@ int main(int argc, char** argv)
 		case OPT_VERSION:
 			cout << VERSION_MESSAGE;
 			exit(EXIT_SUCCESS);
+		case OPT_DB:
+			arg >> opt::db; break;
+		case OPT_LIBRARY:
+			arg >> opt::metaVars[0]; break;
+		case OPT_STRAIN:
+			arg >> opt::metaVars[1]; break;
+		case OPT_SPECIES:
+			arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -830,6 +869,18 @@ int main(int argc, char** argv)
 	if (opt::verbose > 0)
 		cerr << "Read " << paths.size() << " paths\n";
 
+	if (!opt::db.empty()) {
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars
+		);
+		addToDb(db, "K", opt::k);
+		addToDb(db, "pathRead", paths.size());
+	}
+
 	// Start numbering new contigs from the last
 	if (!pathIDs.empty())
 		setNextContigName(pathIDs.back());
@@ -936,6 +987,24 @@ int main(int argc, char** argv)
 		write_graph(fout, g, PROGRAM, commandLine);
 		assert_good(fout, opt::graphPath);
 	}
-
+	vector<int> vals = make_vector<int>()
+		<< stats.numAmbPaths
+		<< stats.numMerged
+		<< stats.numNoSolutions
+		<< stats.numTooManySolutions
+		<< stats.tooComplex
+		<< stats.notMerged;
+
+	vector<string> keys = make_vector<string>()
+		<< "ambg_paths"
+		<< "merged"
+		<< "no_paths"
+		<< "too_many_paths"
+		<< "too_complex"
+		<< "dissimilar";
+	if (!opt::db.empty()) {
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
 	return 0;
 }
diff --git a/Overlap/Overlap.cpp b/Overlap/Overlap.cpp
index 75f75b5..4fa86d7 100644
--- a/Overlap/Overlap.cpp
+++ b/Overlap/Overlap.cpp
@@ -59,6 +59,12 @@ static const char USAGE_MESSAGE[] =
 "      --SS              expect contigs to be oriented correctly\n"
 "      --no-SS           no assumption about contig orientation [default]\n"
 "  -g, --graph=FILE      write the contig adjacency graph to FILE\n"
+"      --adj             output the graph in ADJ format [default]\n"
+"      --asqg            output the graph in ASQG format\n"
+"      --dot             output the graph in GraphViz format\n"
+"      --gv              output the graph in GraphViz format\n"
+"      --gfa             output the graph in GFA format\n"
+"      --sam             output the graph in SAM format\n"
 "  -o, --out=FILE        write result to FILE\n"
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
@@ -101,6 +107,13 @@ static const struct option longopts[] = {
 	{ "no-merge-repeat", no_argument, &opt::mask, 0 },
 	{ "SS",            no_argument,       &opt::ss, 1 },
 	{ "no-SS",         no_argument,       &opt::ss, 0 },
+	{ "graph",         required_argument, NULL, 'g' },
+	{ "adj",           no_argument,       &opt::format, ADJ },
+	{ "asqg",          no_argument,       &opt::format, ASQG },
+	{ "dot",           no_argument,       &opt::format, DOT },
+	{ "gv",            no_argument,       &opt::format, DOT },
+	{ "gfa",           no_argument,       &opt::format, GFA },
+	{ "sam",           no_argument,       &opt::format, SAM },
 	{ "out",     required_argument, NULL, 'o' },
 	{ "verbose", no_argument,       NULL, 'v' },
 	{ "help",    no_argument,       NULL, OPT_HELP },
@@ -438,7 +451,7 @@ int main(int argc, char** argv)
 		if (opt::verbose > 0)
 			printGraphStats(cout, scaffoldGraph);
 		remove_edge_if(
-				!bind(checkEdgeForOverlap,
+				!boost::lambda::bind(checkEdgeForOverlap,
 					boost::cref(graph), boost::ref(scaffoldGraph),
 					_1),
 				static_cast<OverlapGraph::base_type&>(scaffoldGraph));
diff --git a/PairedDBG/BranchRecord.h b/PairedDBG/BranchRecord.h
new file mode 100644
index 0000000..757b091
--- /dev/null
+++ b/PairedDBG/BranchRecord.h
@@ -0,0 +1,43 @@
+#ifndef PAIREDDBG_BRANCHRECORD_H
+#define PAIREDDBG_BRANCHRECORD_H 1
+
+#include "Common/Options.h" // for opt::verbose
+
+/** Generate the sequence of this contig. */
+template <typename It, typename OutIt>
+void branchRecordToStr(It it, It last, OutIt out)
+{
+	assert(it < last);
+	std::string k0 = it->first.str();
+	std::copy(k0.begin(), k0.end(), out);
+	++it;
+	Sequence::iterator outa = out + Kmer::length();
+	Sequence::iterator outb = out + KmerPair::length();
+	for (; it != last; ++it) {
+		std::pair<char, char> x = it->first.getLastBaseChar();
+		if (*outa == 'N' || *outa == x.first) {
+			*outa = x.first;
+		} else {
+			char amb = ambiguityOr(*outa, x.first);
+			if (opt::verbose > 1) {
+				std::cerr << "Warning: Expected '" << *outa
+					<< "' and saw '" << x.first
+					<< "' at " << outa - out << '\n';
+				std::copy(out, outb, std::ostream_iterator<char>(std::cerr));
+				std::cerr << '\n'
+					<< std::string(outa - out - Kmer::length() + 1, ' ')
+					<< it->first.str() << '\n'
+					<< std::string(outa - out, ' ') << amb << '\n';
+			}
+			*outa = amb;
+		}
+		++outa;
+		assert(*outb == 'N');
+		*outb = x.second;
+		++outb;
+	}
+}
+
+#include "Assembly/BranchRecordBase.h"
+
+#endif
diff --git a/PairedDBG/Dinuc.h b/PairedDBG/Dinuc.h
new file mode 100644
index 0000000..9218aec
--- /dev/null
+++ b/PairedDBG/Dinuc.h
@@ -0,0 +1,167 @@
+#ifndef PAIREDDBG_DINUC_H
+#define PAIREDDBG_DINUC_H 1
+
+#include "Common/BitUtil.h"
+#include <cassert>
+#include <stdint.h>
+
+/** A pair of nucleotides. */
+class Dinuc
+{
+public:
+	/** The number of symbols. */
+	static const unsigned NUM = 16;
+
+	/** A nucleotide. A bit vector of two bits. */
+	typedef uint8_t Nuc;
+
+	/** A dinucleotide. A bit vector of four bits. */
+	typedef uint8_t Bits;
+
+	/** Default constructor. */
+	Dinuc() { }
+
+	/** Construct a Dinuc from two nucleotides. */
+	Dinuc(Nuc a, Nuc b) : m_data(a | (b << 2)) { }
+
+	/** Construct a Dinuc from an integer. */
+	explicit Dinuc(Bits x) : m_data(x) { }
+
+	/** Cast to an integer. */
+	Bits toInt() const { return m_data; }
+
+	/** Return the first nucleotide. */
+	Nuc a() const { return m_data & 0x3; }
+
+	/** Return the first nucleotide. */
+	Nuc b() const { return (m_data >> 2) & 0x3; }
+
+	/** Compare two dinucleotides. */
+	bool operator<(const Dinuc& x) const
+	{
+		return m_data < x.m_data;
+	}
+
+	/** Complement a single base. */
+	static Nuc complementNuc(Nuc x) { return 3 - x; }
+
+	/** Return the reverse complement of this dinucleotide. */
+	Dinuc reverseComplement() const
+	{
+		return Dinuc(complementNuc(b()), complementNuc(a()));
+	}
+
+	/** Increment this dinucleotide. */
+	Dinuc& operator++()
+	{
+		++m_data;
+		return *this;
+	}
+
+	/** Return the first dinucleotide. */
+	static Dinuc begin() { return Dinuc(0); }
+
+	/** Return the last dinucleotide. */
+	static Dinuc end() { return Dinuc(NUM); }
+
+private:
+	/** Two nucleotides packed into a single scalar. */
+	Bits m_data;
+};
+
+/** Return the reverse complement of this dinucleotide. */
+static inline Dinuc reverseComplement(const Dinuc& x)
+{
+	return x.reverseComplement();
+}
+
+/** A set of dinucleotides. */
+class DinucSet
+{
+public:
+	typedef Dinuc Symbol;
+
+	/** The number of symbols. */
+	static const unsigned NUM = Dinuc::NUM;
+
+	/** A bit vector. */
+	typedef uint16_t Bits;
+
+	/** Default constructor. */
+	DinucSet() : m_data(0) { }
+
+	/** Construct a set containing a single element. */
+	DinucSet(const Dinuc& x) : m_data(1 << x.toInt()) { }
+
+/** Return a set with the specified bits set. */
+static DinucSet mask(Bits x)
+{
+	DinucSet s;
+	s.m_data = x;
+	return s;
+}
+
+/** Return whether the specified element is present in this set. */
+bool checkBase(const Dinuc& x) const
+{
+	return m_data & (1 << x.toInt());
+}
+
+/** Return the number of elements in this set. */
+unsigned outDegree() const
+{
+	return popcount(m_data);
+}
+
+/** Return whether this set is non-empty. */
+bool hasExtension() const
+{
+	return m_data != 0;
+}
+
+/** Return whether this set has two or more elements. */
+bool isAmbiguous() const
+{
+	return outDegree() > 1;
+}
+
+/** Add the specified element to this set. */
+void setBase(const Dinuc& x)
+{
+	m_data |= 1 << x.toInt();
+}
+
+/** Remove all elements from this set. */
+void clear()
+{
+	m_data = 0;
+}
+
+/** Remove the specified elements from this set. */
+void clear(const DinucSet& x)
+{
+	m_data &= ~x.m_data;
+}
+
+/** Return the complementary nucleotides of this set. */
+DinucSet complement() const
+{
+	DinucSet x;
+	for (Dinuc i = Dinuc::begin(); i < Dinuc::end(); ++i) {
+		if (checkBase(i))
+			x.setBase(i.reverseComplement());
+	}
+	return x;
+}
+
+bool operator==(const DinucSet& x) const
+{
+	return m_data == x.m_data;
+}
+
+private:
+	/** A bit vector representing a set. */
+	Bits m_data;
+};
+
+#endif
diff --git a/PairedDBG/KmerPair.cc b/PairedDBG/KmerPair.cc
new file mode 100644
index 0000000..54f9802
--- /dev/null
+++ b/PairedDBG/KmerPair.cc
@@ -0,0 +1,4 @@
+#include "KmerPair.h"
+
+/** The length of a k-mer pair, including the gap. */
+unsigned KmerPair::s_length;
diff --git a/PairedDBG/KmerPair.h b/PairedDBG/KmerPair.h
new file mode 100644
index 0000000..1086257
--- /dev/null
+++ b/PairedDBG/KmerPair.h
@@ -0,0 +1,229 @@
+#ifndef PAIREDDBG_KMERPAIR_H
+#define PAIREDDBG_KMERPAIR_H 1
+
+#include "Dinuc.h"
+
+#include "Common/Kmer.h"
+
+#include <stdint.h>
+#include <utility>
+
+/** A pair of k-mer. */
+class KmerPair
+{
+public:
+	typedef Dinuc::Nuc Nuc;
+
+/** Default constructor. */
+KmerPair() { }
+
+/** Construct a k-mer pair from two k-mer. */
+KmerPair(const Kmer& a, const Kmer& b) : m_a(a), m_b(b) { }
+
+/** Construct a k-mer pair from two strings. */
+KmerPair(const std::string& a, const std::string& b) : m_a(a), m_b(b) { }
+
+/** Construct a k-mer pair from one string.
+ * The first and last word of the specified string are used to construct the
+ * two k-mers. The two words may overlap.
+ */
+KmerPair(const std::string& s) :
+	m_a(s.substr(0, Kmer::length())),
+	m_b(s.substr(s.size() - Kmer::length(), Kmer::length()))
+{
+}
+
+/** Return whether the two objects are equal. */
+bool operator==(const KmerPair& x) const
+{
+	return m_a == x.m_a && m_b == x.m_b;
+}
+
+/** Return whether the two objects are inequal. */
+bool operator!=(const KmerPair& x) const
+{
+	return !(*this == x);
+}
+
+/** Return whether this object is less than the other. */
+bool operator<(const KmerPair& x) const
+{
+	return m_a != x.m_a
+		? m_a < x.m_a
+		: m_b < x.m_b;
+}
+
+/** Return the length of a the k-mer pair, including the gap. */
+static unsigned length()
+{
+	return s_length;
+}
+
+/** Set the length of a k-mer pair, including the gap.
+ * This value is shared by all instances.
+ */
+static void setLength(unsigned length)
+{
+	assert(length >= 2 * Kmer::length());
+	s_length = length;
+}
+
+/** Return the first nucleotides. */
+Dinuc front() const
+{
+	return Dinuc(m_a.front(), m_b.front());
+}
+
+/** Return the terminal nucleotides. */
+Dinuc back() const
+{
+	return Dinuc(m_a.back(), m_b.back());
+}
+
+/** Return the terminal nucleotides as characters. */
+std::pair<char, char> getLastBaseChar() const
+{
+	return std::make_pair(m_a.getLastBaseChar(), m_b.getLastBaseChar());
+}
+
+/** Return the hash value. */
+uint64_t getHashCode() const
+{
+	return m_a.getHashCode() ^ m_b.getHashCode();
+}
+
+/** Return whether this k-mer pair is palindromic. */
+bool isPalindrome() const
+{
+	return m_a == ::reverseComplement(m_b);
+}
+
+/** Return whether the specified k-mer pair edge is palindromic. */
+bool isPalindrome(extDirection dir) const
+{
+	Kmer a(m_a);
+	if (dir == SENSE)
+		a.shift(SENSE, 0);
+	else
+		a.setLastBase(SENSE, 0);
+
+	Kmer b(m_b);
+	b.reverseComplement();
+	if (dir == ANTISENSE)
+		b.shift(SENSE, 0);
+	else
+		b.setLastBase(SENSE, 0);
+
+	return a == b;
+}
+
+/** Return a string representation of the k-mer pair, using an accurate number
+ * of Ns to separate the two k-mer.
+ */
+std::string str() const
+{
+	assert(length() >= m_a.length());
+	std::string s(length(), 'N');
+	s.replace(0, m_a.length(), m_a.str());
+	s.replace(length() - m_b.length(), m_b.length(), m_b.str());
+	return s;
+}
+
+/** Return a string representation of the k-mer pair, using the specified
+ * separator string to separate the two k-mer.
+ */
+std::string str(const char* sep) const
+{
+	std::string s;
+	s.reserve(2 * Kmer::length() + 1);
+	s += m_a.str();
+	s += sep;
+	s += m_b.str();
+	return s;
+}
+
+/** Set the last base of each k-mer. */
+void setLastBase(extDirection sense, const Dinuc& x)
+{
+	m_a.setLastBase(sense, x.a());
+	m_b.setLastBase(sense, x.b());
+}
+
+/** Shift both k-mer. */
+Dinuc shift(extDirection sense, Dinuc x = Dinuc(0))
+{
+	return Dinuc(
+			m_a.shift(sense, x.a()),
+			m_b.shift(sense, x.b()));
+}
+
+/** Reverse complement this k-mer pair. */
+void reverseComplement()
+{
+	m_a.reverseComplement();
+	m_b.reverseComplement();
+	std::swap(m_a, m_b);
+}
+
+/** Print this k-mer pair. */
+friend std::ostream& operator<<(std::ostream& out, const KmerPair& x)
+{
+	return out << x.m_a.str() << '-' << x.m_b.str();
+}
+
+/** Return the number of bytes needed. */
+static unsigned serialSize()
+{
+	return sizeof(KmerPair);
+}
+
+/** Serialize this k-mer pair. */
+size_t serialize(void* dest) const
+{
+	memcpy(dest, this, sizeof *this);
+	return sizeof *this;
+}
+
+/** Unserialize this k-mer pair. */
+size_t unserialize(const void* src)
+{
+	memcpy(this, src, sizeof *this);
+	return sizeof *this;
+}
+
+/** Return a hash value that does not change with reverse complementation. */
+unsigned getCode() const
+{
+	return m_a.getCode() ^ m_b.getCode();
+}
+
+private:
+
+	/** The length of a k-mer pair, including the gap. */
+	static unsigned s_length;
+
+	/** The first k-mer. */
+	Kmer m_a;
+
+	/** The second k-mer. */
+	Kmer m_b;
+};
+
+/** Return the reverse complement. */
+static inline KmerPair reverseComplement(const KmerPair& u)
+{
+	KmerPair urc(u);
+	urc.reverseComplement();
+	return urc;
+}
+
+NAMESPACE_STD_HASH_BEGIN
+	template <> struct hash<KmerPair> {
+		size_t operator()(const KmerPair& u) const
+		{
+			return u.getHashCode();
+		}
+	};
+NAMESPACE_STD_HASH_END
+
+#endif
diff --git a/PairedDBG/Makefile.am b/PairedDBG/Makefile.am
new file mode 100644
index 0000000..859aee7
--- /dev/null
+++ b/PairedDBG/Makefile.am
@@ -0,0 +1,26 @@
+if PAIRED_DBG
+bin_PROGRAMS = abyss-paired-dbg
+noinst_LIBRARIES = libpaireddbg.a
+endif
+
+# abyss-paired-dbg
+
+abyss_paired_dbg_CPPFLAGS = -DPAIRED_DBG -I$(top_srcdir)
+
+libdb = $(top_builddir)/DataBase/libdb.a $(SQLITE_LIBS)
+
+abyss_paired_dbg_LDADD = \
+	$(top_builddir)/Assembly/libassembly.a \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Common/libcommon.a \
+	$(libdb)
+
+abyss_paired_dbg_SOURCES = \
+	abyss-paired-dbg.cc \
+	BranchRecord.h \
+	KmerPair.cc KmerPair.h \
+	Dinuc.h \
+	PairedDBGAlgorithms.h \
+	SequenceCollection.h
+
+libpaireddbg_a_SOURCES = KmerPair.cc KmerPair.h
diff --git a/PairedDBG/PairedDBGAlgorithms.h b/PairedDBG/PairedDBGAlgorithms.h
new file mode 100644
index 0000000..c5d3353
--- /dev/null
+++ b/PairedDBG/PairedDBGAlgorithms.h
@@ -0,0 +1,42 @@
+#ifndef PairedDBG_PairedDBGAlgorithms_h
+#define PairedDBG_PairedDBGAlgorithms_h 1
+
+#include "Graph/GraphAlgorithms.h" // for removeEdgeIf
+#include <iostream>
+
+/** Return true if a paired dBG edge is inconsistent.
+ * This predicate is only valid when the size of the gap is exactly zero.
+ */
+template <typename Graph>
+struct InconsistentPairedDBGEdge
+{
+	InconsistentPairedDBGEdge(Graph& g) : m_g(g) { }
+	bool operator()(typename graph_traits<Graph>::edge_descriptor e) const
+	{
+		assert(opt::kmerSize == 2 * opt::singleKmerSize);
+		// u aaaaabbbbb
+		// v  aaaaabbbbb
+		return source(e, m_g).front().b()
+			!= target(e, m_g).back().a();
+	}
+	const Graph& m_g;
+};
+
+/** Remove inconsistent edges from a paired dBG.
+ * Currently this algorithm is only used for the special case when
+ * assembling a paired dBG whose gap is exactly zero.
+ */
+template <typename Graph>
+void
+removePairedDBGInconsistentEdges(Graph& g)
+{
+	assert(opt::kmerSize >= 2 * opt::singleKmerSize);
+	if (opt::kmerSize == 2 * opt::singleKmerSize) {
+		// The gap is exactly zero.
+		std::cerr << "Removed "
+			<< removeEdgeIf(InconsistentPairedDBGEdge<Graph>(g), g)
+			<< " inconsistent edges.\n";
+	}
+}
+
+#endif
diff --git a/PairedDBG/SequenceCollection.h b/PairedDBG/SequenceCollection.h
new file mode 100644
index 0000000..9f6016f
--- /dev/null
+++ b/PairedDBG/SequenceCollection.h
@@ -0,0 +1,24 @@
+#ifndef PAIREDDBG_SEQUENCECOLLECTION_H
+#define PAIREDDBG_SEQUENCECOLLECTION_H 1
+
+#include "config.h"
+#include "Dinuc.h"
+#include "KmerPair.h"
+#include "Assembly/VertexData.h"
+
+typedef VertexData<Dinuc, DinucSet> KmerPairData;
+
+#if HAVE_GOOGLE_SPARSE_HASH_MAP
+# include <google/sparse_hash_map>
+typedef google::sparse_hash_map<KmerPair, KmerPairData, hash<KmerPair> >
+	SequenceDataHash;
+#else
+# include "Common/UnorderedMap.h"
+typedef unordered_map<KmerPair, KmerPairData, hash<KmerPair> >
+	SequenceDataHash;
+#endif
+
+#include "Assembly/DBG.h"
+#include "PairedDBG/BranchRecord.h"
+
+#endif
diff --git a/PairedDBG/abyss-paired-dbg.cc b/PairedDBG/abyss-paired-dbg.cc
new file mode 100644
index 0000000..043044a
--- /dev/null
+++ b/PairedDBG/abyss-paired-dbg.cc
@@ -0,0 +1 @@
+#include "ABYSS/abyss.cc"
diff --git a/Parallel/CommLayer.cpp b/Parallel/CommLayer.cpp
index 7e07008..9299ab1 100644
--- a/Parallel/CommLayer.cpp
+++ b/Parallel/CommLayer.cpp
@@ -1,8 +1,8 @@
 #include "config.h"
 #include "CommLayer.h"
-#include "Common/Options.h"
-#include "Log.h"
 #include "MessageBuffer.h"
+#include "Common/Log.h"
+#include "Common/Options.h"
 #include <mpi.h>
 #include <cstring>
 #include <vector>
diff --git a/Parallel/Makefile.am b/Parallel/Makefile.am
index 6181bac..da4893f 100644
--- a/Parallel/Makefile.am
+++ b/Parallel/Makefile.am
@@ -1,19 +1,29 @@
 bin_PROGRAMS = ABYSS-P
+if PAIRED_DBG
+bin_PROGRAMS += abyss-paired-dbg-mpi
+endif
 
-ABYSS_P_CPPFLAGS = -I$(top_srcdir) \
-	-I$(top_srcdir)/Assembly \
-	-I$(top_srcdir)/Common \
-	-I$(top_srcdir)/DataLayer
+libdb = $(top_builddir)/DataBase/libdb.a $(SQLITE_LIBS)
+
+ABYSS_P_CPPFLAGS = -I$(top_srcdir)
 
 ABYSS_P_LDADD = \
 	$(top_builddir)/Assembly/libassembly.a \
 	$(top_builddir)/Common/libcommon.a \
 	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(libdb) \
 	$(MPI_LIBS)
 
 ABYSS_P_SOURCES = \
 	parallelAbyss.cpp \
 	CommLayer.cpp CommLayer.h \
 	NetworkSequenceCollection.cpp NetworkSequenceCollection.h \
+	SequenceCollection.h \
 	MessageBuffer.cpp MessageBuffer.h \
-	Messages.cpp Messages.h 
+	Messages.cpp Messages.h
+
+abyss_paired_dbg_mpi_CPPFLAGS = $(ABYSS_P_CPPFLAGS) -DPAIRED_DBG
+
+abyss_paired_dbg_mpi_LDADD = $(ABYSS_P_LDADD)
+
+abyss_paired_dbg_mpi_SOURCES = $(ABYSS_P_SOURCES)
diff --git a/Parallel/MessageBuffer.cpp b/Parallel/MessageBuffer.cpp
index 630e68b..cc5ba9e 100644
--- a/Parallel/MessageBuffer.cpp
+++ b/Parallel/MessageBuffer.cpp
@@ -11,26 +11,26 @@ MessageBuffer::MessageBuffer()
 		m_msgQueues[i].reserve(MAX_MESSAGES);
 }
 
-void MessageBuffer::sendSeqAddMessage(int nodeID, const Kmer& seq)
+void MessageBuffer::sendSeqAddMessage(int nodeID, const V& seq)
 {
 	queueMessage(nodeID, new SeqAddMessage(seq), SM_BUFFERED);
 }
 
-void MessageBuffer::sendSeqRemoveMessage(int nodeID, const Kmer& seq)
+void MessageBuffer::sendSeqRemoveMessage(int nodeID, const V& seq)
 {
 	queueMessage(nodeID, new SeqRemoveMessage(seq), SM_BUFFERED);
 }
 
 // Send a set flag message
 void MessageBuffer::sendSetFlagMessage(int nodeID,
-		const Kmer& seq, SeqFlag flag)
+		const V& seq, SeqFlag flag)
 {
 	queueMessage(nodeID, new SetFlagMessage(seq, flag), SM_BUFFERED);
 }
 
 // Send a remove extension message
 void MessageBuffer::sendRemoveExtension(int nodeID,
-		const Kmer& seq, extDirection dir, SeqExt ext)
+		const V& seq, extDirection dir, SymbolSet ext)
 {
 	queueMessage(nodeID, new RemoveExtensionMessage(seq, dir, ext),
 			SM_BUFFERED);
@@ -38,7 +38,7 @@ void MessageBuffer::sendRemoveExtension(int nodeID,
 
 // Send a sequence data request
 void MessageBuffer::sendSeqDataRequest(int nodeID,
-		IDType group, IDType id, const Kmer& seq)
+		IDType group, IDType id, const V& seq)
 {
 	queueMessage(nodeID,
 			new SeqDataRequest(seq, group, id), SM_IMMEDIATE);
@@ -46,8 +46,8 @@ void MessageBuffer::sendSeqDataRequest(int nodeID,
 
 // Send a sequence data response
 void MessageBuffer::sendSeqDataResponse(int nodeID,
-		IDType group, IDType id, const Kmer& seq,
-		ExtensionRecord extRec, int multiplicity)
+		IDType group, IDType id, const V& seq,
+		SymbolSetPair extRec, int multiplicity)
 {
 	queueMessage(nodeID,
 			new SeqDataResponse(seq, group, id, extRec, multiplicity),
@@ -56,7 +56,7 @@ void MessageBuffer::sendSeqDataResponse(int nodeID,
 
 // Send a set base message
 void MessageBuffer::sendSetBaseExtension(int nodeID,
-		const Kmer& seq, extDirection dir, uint8_t base)
+		const V& seq, extDirection dir, Symbol base)
 {
 	queueMessage(nodeID,
 			new SetBaseMessage(seq, dir, base), SM_BUFFERED);
diff --git a/Parallel/MessageBuffer.h b/Parallel/MessageBuffer.h
index 69c501b..ec75dcd 100644
--- a/Parallel/MessageBuffer.h
+++ b/Parallel/MessageBuffer.h
@@ -20,6 +20,12 @@ enum SendMode
 class MessageBuffer : public CommLayer
 {
 	public:
+		typedef SequenceCollectionHash Graph;
+		typedef graph_traits<Graph>::vertex_descriptor V;
+		typedef Graph::Symbol Symbol;
+		typedef Graph::SymbolSet SymbolSet;
+		typedef Graph::SymbolSetPair SymbolSetPair;
+
 		MessageBuffer();
 
 		void sendCheckPointMessage(int argument = 0)
@@ -42,19 +48,19 @@ class MessageBuffer : public CommLayer
 					command, argument);
 		}
 
-		void sendSeqAddMessage(int nodeID, const Kmer& seq);
-		void sendSeqRemoveMessage(int nodeID, const Kmer& seq);
+		void sendSeqAddMessage(int nodeID, const V& seq);
+		void sendSeqRemoveMessage(int nodeID, const V& seq);
 		void sendSetFlagMessage(int nodeID,
-				const Kmer& seq, SeqFlag flag);
+				const V& seq, SeqFlag flag);
 		void sendRemoveExtension(int nodeID,
-				const Kmer& seq, extDirection dir, SeqExt ext);
+				const V& seq, extDirection dir, SymbolSet ext);
 		void sendSeqDataRequest(int nodeID,
-				IDType group, IDType id, const Kmer& seq);
+				IDType group, IDType id, const V& seq);
 		void sendSeqDataResponse(int nodeID,
-				IDType group, IDType id, const Kmer& seq,
-				ExtensionRecord extRec, int multiplicity);
+				IDType group, IDType id, const V& seq,
+				SymbolSetPair extRec, int multiplicity);
 		void sendSetBaseExtension(int nodeID,
-				const Kmer& seq, extDirection dir, uint8_t base);
+				const V& seq, extDirection dir, Symbol base);
 
 		void flush();
 		void queueMessage
diff --git a/Parallel/Messages.h b/Parallel/Messages.h
index 833c952..1a42f92 100644
--- a/Parallel/Messages.h
+++ b/Parallel/Messages.h
@@ -1,8 +1,7 @@
 #ifndef MESSAGES_H
 #define MESSAGES_H 1
 
-#include "Kmer.h"
-#include "KmerData.h"
+#include "SequenceCollection.h"
 #include <ostream>
 
 class NetworkSequenceCollection;
@@ -32,8 +31,14 @@ typedef uint32_t IDType;
 class Message
 {
 	public:
+		typedef SequenceCollectionHash Graph;
+		typedef graph_traits<Graph>::vertex_descriptor V;
+		typedef Graph::Symbol Symbol;
+		typedef Graph::SymbolSet SymbolSet;
+		typedef Graph::SymbolSetPair SymbolSetPair;
+
 		Message() { }
-		Message(const Kmer& seq) : m_seq(seq) { }
+		Message(const V& seq) : m_seq(seq) { }
 		virtual ~Message() { }
 
 		virtual void handle(
@@ -42,7 +47,7 @@ class Message
 		virtual size_t getNetworkSize() const
 		{
 			return sizeof (uint8_t) // MessageType
-				+ Kmer::serialSize();
+				+ V::serialSize();
 		}
 
 		static MessageType readMessageType(char* buffer);
@@ -55,15 +60,15 @@ class Message
 			return out << message.m_seq.str() << '\n';
 		}
 
-		Kmer m_seq;
+		V m_seq;
 };
 
-/** Add a Kmer. */
+/** Add a vertex. */
 class SeqAddMessage : public Message
 {
 	public:
 		SeqAddMessage() { }
-		SeqAddMessage(const Kmer& seq) : Message(seq) { }
+		SeqAddMessage(const V& seq) : Message(seq) { }
 
 		void handle(int senderID, NetworkSequenceCollection& handler);
 		size_t serialize(char* buffer);
@@ -71,12 +76,12 @@ class SeqAddMessage : public Message
 		static const MessageType TYPE = MT_ADD;
 };
 
-/** Remove a Kmer. */
+/** Remove a vertex. */
 class SeqRemoveMessage : public Message
 {
 	public:
 		SeqRemoveMessage() { }
-		SeqRemoveMessage(const Kmer& seq) : Message(seq) { }
+		SeqRemoveMessage(const V& seq) : Message(seq) { }
 
 		void handle(int senderID, NetworkSequenceCollection& handler);
 		size_t serialize(char* buffer);
@@ -89,7 +94,7 @@ class SetFlagMessage : public Message
 {
 	public:
 		SetFlagMessage() { }
-		SetFlagMessage(const Kmer& seq, SeqFlag flag)
+		SetFlagMessage(const V& seq, SeqFlag flag)
 			: Message(seq), m_flag(flag) { }
 
 		size_t getNetworkSize() const
@@ -110,8 +115,8 @@ class RemoveExtensionMessage : public Message
 {
 	public:
 		RemoveExtensionMessage() { }
-		RemoveExtensionMessage(const Kmer& seq,
-				extDirection dir, SeqExt ext)
+		RemoveExtensionMessage(const V& seq,
+				extDirection dir, SymbolSet ext)
 			: Message(seq), m_dir(dir), m_ext(ext) { }
 
 		size_t getNetworkSize() const
@@ -126,7 +131,7 @@ class RemoveExtensionMessage : public Message
 
 		static const MessageType TYPE = MT_REMOVE_EXT;
 		uint8_t m_dir; // extDirection
-		SeqExt m_ext;
+		SymbolSet m_ext;
 };
 
 /** Request vertex properties. */
@@ -134,7 +139,7 @@ class SeqDataRequest : public Message
 {
 	public:
 		SeqDataRequest() { }
-		SeqDataRequest(const Kmer& seq, IDType group, IDType id)
+		SeqDataRequest(const V& seq, IDType group, IDType id)
 			: Message(seq), m_group(group), m_id(id) { }
 
 		size_t getNetworkSize() const
@@ -157,8 +162,8 @@ class SeqDataResponse : public Message
 {
 	public:
 		SeqDataResponse() { }
-		SeqDataResponse(const Kmer& seq, IDType group, IDType id,
-				ExtensionRecord& extRecord, int multiplicity) :
+		SeqDataResponse(const V& seq, IDType group, IDType id,
+				SymbolSetPair& extRecord, int multiplicity) :
 			Message(seq), m_group(group), m_id(id),
 			m_extRecord(extRecord), m_multiplicity(multiplicity) { }
 
@@ -176,7 +181,7 @@ class SeqDataResponse : public Message
 		static const MessageType TYPE = MT_SEQ_DATA_RESPONSE;
 		IDType m_group;
 		IDType m_id;
-		ExtensionRecord m_extRecord;
+		SymbolSetPair m_extRecord;
 		uint16_t m_multiplicity;
 };
 
@@ -185,8 +190,8 @@ class SetBaseMessage : public Message
 {
 	public:
 		SetBaseMessage() { }
-		SetBaseMessage(const Kmer& seq,
-				extDirection dir, uint8_t base)
+		SetBaseMessage(const V& seq,
+				extDirection dir, Symbol base)
 			: Message(seq), m_dir(dir), m_base(base) { }
 
 		size_t getNetworkSize() const
@@ -201,7 +206,7 @@ class SetBaseMessage : public Message
 
 		static const MessageType TYPE = MT_SET_BASE;
 		uint8_t m_dir; // extDirection
-		uint8_t m_base;
+		Symbol m_base;
 };
 
 #endif
diff --git a/Parallel/NetworkSequenceCollection.cpp b/Parallel/NetworkSequenceCollection.cpp
index c673958..b708a69 100644
--- a/Parallel/NetworkSequenceCollection.cpp
+++ b/Parallel/NetworkSequenceCollection.cpp
@@ -1,11 +1,11 @@
 #include "NetworkSequenceCollection.h"
+#include "Assembly/AssemblyAlgorithms.h"
 #include "Assembly/Options.h"
-#include "AssemblyAlgorithms.h"
+#include "Common/Histogram.h"
+#include "Common/Log.h"
 #include "Common/Options.h"
-#include "FastaWriter.h"
-#include "Histogram.h"
-#include "Log.h"
-#include "StringUtil.h"
+#include "Common/StringUtil.h"
+#include "DataLayer/FastaWriter.h"
 #include <climits> // for UINT_MAX
 #include <cstdlib>
 #include <fstream>
@@ -14,6 +14,17 @@
 
 using namespace std;
 
+namespace NSC
+{
+	dbMap moveFromAaStatMap()
+	{
+		dbMap temp;
+		temp.insert(AssemblyAlgorithms::tempStatMap.getAC());
+		AssemblyAlgorithms::tempStatMap.clear();
+		return temp;
+	}
+}
+
 // Don't load data into the control process when we have at least
 // DEDICATE_CONTROL_AT total processes. This is needed because the
 // control node uses a lot of memory at large NP.
@@ -134,7 +145,7 @@ void NetworkSequenceCollection::run()
 			{
 				assert(m_trimStep != 0);
 				m_comm.barrier();
-				size_t numRemoved = performNetworkTrim(this);
+				size_t numRemoved = performNetworkTrim();
 				EndState();
 				SetState(NAS_WAITING);
 				m_comm.sendCheckPointMessage(numRemoved);
@@ -155,7 +166,7 @@ void NetworkSequenceCollection::run()
 				m_comm.reduce(m_data.cleanup());
 				m_lowCoverageContigs = 0;
 				m_lowCoverageKmer = 0;
-				numAssembled = performNetworkAssembly(this);
+				numAssembled = performNetworkAssembly();
 				EndState();
 				SetState(NAS_WAITING);
 				m_comm.sendCheckPointMessage();
@@ -176,7 +187,7 @@ void NetworkSequenceCollection::run()
 			case NAS_DISCOVER_BUBBLES:
 			{
 				size_t numDiscovered
-					= performNetworkDiscoverBubbles(this);
+					= performNetworkDiscoverBubbles();
 				EndState();
 				SetState(NAS_WAITING);
 				m_comm.sendCheckPointMessage(numDiscovered);
@@ -230,7 +241,7 @@ void NetworkSequenceCollection::run()
 				m_comm.barrier();
 				pumpNetwork();
 				FastaWriter writer(opt::contigsTempPath.c_str());
-				numAssembled = performNetworkAssembly(this, &writer);
+				numAssembled = performNetworkAssembly(&writer);
 				EndState();
 				SetState(NAS_WAITING);
 				m_comm.sendCheckPointMessage();
@@ -283,7 +294,6 @@ size_t NetworkSequenceCollection::controlErode()
 	numEroded += m_comm.reduce(
 			AssemblyAlgorithms::getNumEroded());
 	cout << "Eroded " << numEroded << " tips.\n";
-
 	size_t removed = m_comm.reduce(m_data.cleanup());
 	m_comm.barrier();
 	assert(removed == numEroded);
@@ -322,7 +332,7 @@ size_t NetworkSequenceCollection::controlTrimRound(unsigned trimLen)
 	SetState(NAS_TRIM);
 	m_comm.sendControlMessage(APC_TRIM, trimLen);
 	m_comm.barrier();
-	size_t numRemoved = performNetworkTrim(this);
+	size_t numRemoved = performNetworkTrim();
 	EndState();
 
 	m_numReachedCheckpoint++;
@@ -339,7 +349,7 @@ size_t NetworkSequenceCollection::controlTrimRound(unsigned trimLen)
 }
 
 /** Perform multiple rounds of trimming until complete. */
-void NetworkSequenceCollection::controlTrim(unsigned start)
+void NetworkSequenceCollection::controlTrim(unsigned& sum, unsigned start)
 {
 	if (opt::trimLen == 0)
 		return;
@@ -355,6 +365,7 @@ void NetworkSequenceCollection::controlTrim(unsigned start)
 	}
 	cout << "Pruned " << total << " tips in "
 		<< rounds << " rounds.\n";
+	sum += total;
 }
 
 /** Remove low-coverage contigs. */
@@ -375,7 +386,7 @@ void NetworkSequenceCollection::controlCoverage()
 	m_lowCoverageContigs = 0;
 	m_lowCoverageKmer = 0;
 	pair<size_t, size_t> numAssembled
-		= performNetworkAssembly(this);
+		= performNetworkAssembly();
 	EndState();
 
 	m_numReachedCheckpoint++;
@@ -398,6 +409,12 @@ void NetworkSequenceCollection::controlCoverage()
 	size_t lowCoverageKmer = m_comm.reduce(m_lowCoverageKmer);
 	cout << "Removed " << lowCoverageKmer << " k-mer in "
 		<< lowCoverageContigs << " low-coverage contigs.\n";
+
+	if (!opt::db.empty()) {
+		AssemblyAlgorithms::addToDb ("totalLowCovCntg", lowCoverageContigs);
+		AssemblyAlgorithms::addToDb ("totalLowCovKmer", lowCoverageKmer);
+	}
+
 	EndState();
 
 	SetState(NAS_SPLIT_AMBIGUOUS);
@@ -418,7 +435,11 @@ void NetworkSequenceCollection::controlCoverage()
 /** Run the assembly state machine for the controller (rank = 0). */
 void NetworkSequenceCollection::runControl()
 {
+	unsigned prunedSum = 0;
+	unsigned erosionSum = 0;
+	unsigned finalAmbg = 0;
 	SetState(NAS_LOADING);
+	size_t temp;
 	while (m_state != NAS_DONE) {
 		switch (m_state) {
 			case NAS_LOADING:
@@ -446,6 +467,9 @@ void NetworkSequenceCollection::runControl()
 					<< toSI(numLoaded * sizeof (value_type))
 					<< "B of RAM is required.\n";
 
+				if (!opt::db.empty())
+					AssemblyAlgorithms::addToDb("loadedKmer", numLoaded);
+
 				Histogram myh
 					= AssemblyAlgorithms::coverageHistogram(m_data);
 				Histogram h(m_comm.reduce(myh.toVector()));
@@ -473,18 +497,24 @@ void NetworkSequenceCollection::runControl()
 						NAS_ADJ_COMPLETE);
 				m_comm.barrier();
 				pumpNetwork();
+				temp = m_comm.reduce(m_numBasesAdjSet);
 				logger(0) << "Added " << m_numBasesAdjSet
 					<< " edges.\n";
-				cout << "Added " << m_comm.reduce(m_numBasesAdjSet)
-					<< " edges.\n";
-				EndState();
+				cout << "Added " << temp << " edges.\n";
+
+				if (!opt::db.empty())
+					AssemblyAlgorithms::addToDb ("EdgesGenerated", temp);
 
+				EndState();
 				SetState(opt::erode > 0 ? NAS_ERODE : NAS_TRIM);
 				break;
 			case NAS_ERODE:
 				assert(opt::erode > 0);
 				cout << "Eroding tips...\n";
-				controlErode();
+
+				erosionSum += controlErode();
+				//controlErode();
+
 				SetState(NAS_TRIM);
 				break;
 
@@ -504,7 +534,7 @@ void NetworkSequenceCollection::runControl()
 				exit(EXIT_FAILURE);
 
 			case NAS_TRIM:
-				controlTrim();
+				controlTrim(prunedSum);
 				SetState(opt::coverage > 0 ? NAS_COVERAGE
 						: opt::bubbleLen > 0 ? NAS_POPBUBBLE
 						: NAS_MARK_AMBIGUOUS);
@@ -528,11 +558,18 @@ void NetworkSequenceCollection::runControl()
 				out.close();
 				cout << "Removed " << numPopped << " bubbles.\n";
 
+				if (!opt::db.empty())
+					AssemblyAlgorithms::addToDb ("poppedBubbles", numPopped);
+
 				SetState(NAS_MARK_AMBIGUOUS);
 				break;
 			}
 			case NAS_MARK_AMBIGUOUS:
-				controlMarkAmbiguous();
+
+				finalAmbg = controlMarkAmbiguous();
+
+				//controlMarkAmbiguous();
+
 				SetState(NAS_ASSEMBLE);
 				break;
 			case NAS_ASSEMBLE:
@@ -543,7 +580,7 @@ void NetworkSequenceCollection::runControl()
 				pumpNetwork();
 				FastaWriter writer(opt::contigsTempPath.c_str());
 				pair<size_t, size_t> numAssembled
-					= performNetworkAssembly(this, &writer);
+					= performNetworkAssembly(&writer);
 				EndState();
 
 				m_numReachedCheckpoint++;
@@ -562,6 +599,11 @@ void NetworkSequenceCollection::runControl()
 					<< " k-mer in " << numAssembled.first
 					<< " contigs.\n";
 
+				if (!opt::db.empty()) {
+					AssemblyAlgorithms::addToDb ("assembledKmerNum", numAssembled.second);
+					AssemblyAlgorithms::addToDb ("assembledCntg", numAssembled.first);
+				}
+
 				SetState(NAS_DONE);
 				break;
 			}
@@ -569,6 +611,13 @@ void NetworkSequenceCollection::runControl()
 				break;
 		}
 	}
+
+	if (!opt::db.empty()) {
+		AssemblyAlgorithms::addToDb ("finalAmbgVertices", finalAmbg);
+		AssemblyAlgorithms::addToDb ("totalErodedTips", erosionSum);
+		AssemblyAlgorithms::addToDb ("totalPrunedTips", prunedSum);
+	}
+
 }
 
 void NetworkSequenceCollection::EndState()
@@ -633,7 +682,7 @@ size_t NetworkSequenceCollection::pumpNetwork()
 }
 
 /** Call the observers of the specified sequence. */
-void NetworkSequenceCollection::notify(const Kmer& key)
+void NetworkSequenceCollection::notify(const V& key)
 {
 	switch (m_state) {
 		case NAS_ERODE:
@@ -731,9 +780,9 @@ void NetworkSequenceCollection::parseControlMessage(int source)
 void NetworkSequenceCollection::handle(
 		int senderID, const SeqDataRequest& message)
 {
-	const Kmer& kmer = message.m_seq;
+	const V& kmer = message.m_seq;
 	assert(isLocal(kmer));
-	ExtensionRecord extRec;
+	SymbolSetPair extRec;
 	int multiplicity = -1;
 	bool found = m_data.getSeqData(kmer, extRec, multiplicity);
 	assert(found);
@@ -752,16 +801,16 @@ void NetworkSequenceCollection::handle(
 }
 
 /** Distributed trimming function. */
-size_t NetworkSequenceCollection::performNetworkTrim(
-		ISequenceCollection* seqCollection)
+size_t NetworkSequenceCollection::performNetworkTrim()
 {
 	Timer timer("NetworkTrim");
+	NetworkSequenceCollection* seqCollection = this;
 	size_t numBranchesRemoved = 0;
 
 	// The branch ids
 	uint64_t branchGroupID = 0;
 
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
+	for (iterator iter = seqCollection->begin();
 			iter != seqCollection->end(); ++iter) {
 		if (iter->second.deleted())
 			continue;
@@ -848,8 +897,9 @@ size_t NetworkSequenceCollection::processBranchesTrim()
 
 /** Discover bubbles to pop. */
 size_t NetworkSequenceCollection::
-performNetworkDiscoverBubbles(ISequenceCollection* seqCollection)
+performNetworkDiscoverBubbles()
 {
+	NetworkSequenceCollection* seqCollection = this;
 	Timer timer("NetworkDiscoverBubbles");
 
 	// The branch ids
@@ -864,7 +914,7 @@ performNetworkDiscoverBubbles(ISequenceCollection* seqCollection)
 	// Set the cutoffs
 	const unsigned maxNumBranches = 3;
 
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
+	for (iterator iter = seqCollection->begin();
 			iter != seqCollection->end(); ++iter) {
 		if (iter->second.deleted())
 			continue;
@@ -872,7 +922,7 @@ performNetworkDiscoverBubbles(ISequenceCollection* seqCollection)
 		if (++count % 100000 == 0)
 			logger(1) << "Popping bubbles: " << count << '\n';
 
-		ExtensionRecord extRec = iter->second.extension();
+		SymbolSetPair extRec = iter->second.extension();
 		for (extDirection dir = SENSE; dir <= ANTISENSE; ++dir) {
 			if (extRec.dir[dir].isAmbiguous()) {
 				BranchGroupMap::iterator groupIter
@@ -991,7 +1041,7 @@ size_t NetworkSequenceCollection::controlDiscoverBubbles()
 	SetState(NAS_DISCOVER_BUBBLES);
 	m_comm.sendControlMessage(APC_SET_STATE, NAS_DISCOVER_BUBBLES);
 
-	size_t numDiscovered = performNetworkDiscoverBubbles(this);
+	size_t numDiscovered = performNetworkDiscoverBubbles();
 	EndState();
 
 	m_numReachedCheckpoint++;
@@ -1066,16 +1116,20 @@ size_t NetworkSequenceCollection::controlSplitAmbiguous()
 	while (!checkpointReached())
 		pumpNetwork();
 	cout << "Split " << m_checkpointSum << " ambiguous branches.\n";
+
+	if (!opt::db.empty())
+		AssemblyAlgorithms::addToDb ("totalSplitAmbg", m_checkpointSum);
+
 	return m_checkpointSum;
 }
 
 /** Assemble a contig. */
 void NetworkSequenceCollection::assembleContig(
-		ISequenceCollection* seqCollection, FastaWriter* writer,
+		FastaWriter* writer,
 		BranchRecord& branch, unsigned id)
 {
 	size_t removed = AssemblyAlgorithms::assembleContig(
-			seqCollection, writer, branch, id);
+			this, writer, branch, id);
 	if (removed > 0) {
 		m_lowCoverageContigs++;
 		m_lowCoverageKmer += removed;
@@ -1097,15 +1151,15 @@ namespace std {
  * @return the number of contigs and k-mer assembled
  */
 pair<size_t, size_t> NetworkSequenceCollection::
-performNetworkAssembly(ISequenceCollection* seqCollection,
-		FastaWriter* fileWriter)
+performNetworkAssembly(FastaWriter* fileWriter)
 {
 	Timer timer("NetworkAssembly");
+	NetworkSequenceCollection* seqCollection = this;
 	pair<size_t, size_t> numAssembled(0, 0);
 	uint64_t branchGroupID = 0;
 	assert(m_activeBranchGroups.empty());
 
-	for (ISequenceCollection::iterator iter = seqCollection->begin();
+	for (iterator iter = seqCollection->begin();
 			iter != seqCollection->end(); ++iter) {
 		if (iter->second.deleted())
 			continue;
@@ -1123,7 +1177,7 @@ performNetworkAssembly(ISequenceCollection* seqCollection,
 			BranchRecord currBranch(SENSE);
 			currBranch.push_back(*iter);
 			currBranch.terminate(BS_NOEXT);
-			assembleContig(seqCollection, fileWriter, currBranch,
+			assembleContig(fileWriter, currBranch,
 					m_numAssembled + numAssembled.first);
 			numAssembled.first++;
 			numAssembled.second += currBranch.size();
@@ -1140,13 +1194,13 @@ performNetworkAssembly(ISequenceCollection* seqCollection,
 		// Generate the first extension request
 		BranchRecord& branch = inserted.first->second[0];
 		branch.push_back(*iter);
-		Kmer kmer = iter->first;
+		V kmer = iter->first;
 		AssemblyAlgorithms::extendBranch(branch,
 				kmer, iter->second.getExtension(dir));
 		assert(branch.isActive());
 		generateExtensionRequest(branchGroupID++, 0, kmer);
 
-		numAssembled += processBranchesAssembly(seqCollection,
+		numAssembled += processBranchesAssembly(
 				fileWriter, numAssembled.first);
 		seqCollection->pumpNetwork();
 
@@ -1155,7 +1209,7 @@ performNetworkAssembly(ISequenceCollection* seqCollection,
 			while(m_activeBranchGroups.size() > LOW_ACTIVE)
 			{
 				seqCollection->pumpNetwork();
-				numAssembled += processBranchesAssembly(seqCollection,
+				numAssembled += processBranchesAssembly(
 						fileWriter, numAssembled.first);
 			}
 		}
@@ -1164,7 +1218,7 @@ performNetworkAssembly(ISequenceCollection* seqCollection,
 	// Clear out the remaining branches
 	while(!m_activeBranchGroups.empty())
 	{
-		numAssembled += processBranchesAssembly(seqCollection,
+		numAssembled += processBranchesAssembly(
 				fileWriter, numAssembled.first);
 		seqCollection->pumpNetwork();
 	}
@@ -1186,8 +1240,7 @@ performNetworkAssembly(ISequenceCollection* seqCollection,
  * @return the number of contigs and k-mer assembled
  */
 pair<size_t, size_t> NetworkSequenceCollection::
-processBranchesAssembly(ISequenceCollection* seqCollection,
-		FastaWriter* fileWriter, unsigned currContigID)
+processBranchesAssembly(FastaWriter* fileWriter, unsigned currContigID)
 {
 	size_t assembledContigs = 0, assembledKmer = 0;
 	for (BranchGroupMap::iterator it = m_activeBranchGroups.begin();
@@ -1202,7 +1255,7 @@ processBranchesAssembly(ISequenceCollection* seqCollection,
 					|| (!opt::ss && branch.isCanonical())) {
 				assembledContigs++;
 				assembledKmer += branch.size();
-				assembleContig(seqCollection, fileWriter, branch,
+				assembleContig(fileWriter, branch,
 						m_numAssembled + currContigID++);
 			}
 			m_activeBranchGroups.erase(it++);
@@ -1214,10 +1267,10 @@ processBranchesAssembly(ISequenceCollection* seqCollection,
 
 /** Send a request for the edges of vertex kmer. */
 void NetworkSequenceCollection::generateExtensionRequest(
-		uint64_t groupID, uint64_t branchID, const Kmer& kmer)
+		uint64_t groupID, uint64_t branchID, const V& kmer)
 {
 	if (isLocal(kmer)) {
-		ExtensionRecord extRec;
+		SymbolSetPair extRec;
 		int multiplicity = -1;
 		bool success = m_data.getSeqData(kmer, extRec, multiplicity);
 		assert(success);
@@ -1248,8 +1301,8 @@ void NetworkSequenceCollection::generateExtensionRequests(
 }
 
 void NetworkSequenceCollection::processSequenceExtension(
-		uint64_t groupID, uint64_t branchID, const Kmer& seq,
-		const ExtensionRecord& extRec, int multiplicity)
+		uint64_t groupID, uint64_t branchID, const V& seq,
+		const SymbolSetPair& extRec, int multiplicity)
 {
 	switch(m_state)
 	{
@@ -1285,14 +1338,14 @@ void NetworkSequenceCollection::processSequenceExtension(
 
 /** Process a sequence extension for trimming. */
 void NetworkSequenceCollection::processLinearSequenceExtension(
-		uint64_t groupID, uint64_t branchID, const Kmer& seq,
-		const ExtensionRecord& extRec, int multiplicity,
+		uint64_t groupID, uint64_t branchID, const V& seq,
+		const SymbolSetPair& extRec, int multiplicity,
 		unsigned maxLength)
 {
 	BranchGroupMap::iterator iter
 		= m_activeBranchGroups.find(groupID);
 	assert(iter != m_activeBranchGroups.end());
-	Kmer currSeq = seq;
+	V currSeq = seq;
 	bool active = AssemblyAlgorithms::processLinearExtensionForBranch(
 			iter->second[branchID], currSeq, extRec, multiplicity,
 			maxLength);
@@ -1302,8 +1355,8 @@ void NetworkSequenceCollection::processLinearSequenceExtension(
 
 /** Process a sequence extension for popping. */
 void NetworkSequenceCollection::processSequenceExtensionPop(
-		uint64_t groupID, uint64_t branchID, const Kmer& seq,
-		const ExtensionRecord& extRec, int multiplicity,
+		uint64_t groupID, uint64_t branchID, const V& seq,
+		const SymbolSetPair& extRec, int multiplicity,
 		unsigned maxLength)
 {
 	BranchGroupMap::iterator groupIt
@@ -1324,7 +1377,7 @@ void NetworkSequenceCollection::processSequenceExtensionPop(
 }
 
 /** Add a k-mer to this collection. */
-void NetworkSequenceCollection::add(const Kmer& seq,
+void NetworkSequenceCollection::add(const V& seq,
 		unsigned coverage)
 {
 	if (isLocal(seq)) {
@@ -1336,7 +1389,7 @@ void NetworkSequenceCollection::add(const Kmer& seq,
 }
 
 /** Remove a k-mer from this collection. */
-void NetworkSequenceCollection::remove(const Kmer& seq)
+void NetworkSequenceCollection::remove(const V& seq)
 {
 	if (isLocal(seq))
 		m_data.remove(seq);
@@ -1355,7 +1408,7 @@ checkpointReached(unsigned numRequired) const
 	return m_numReachedCheckpoint == numRequired;
 }
 
-void NetworkSequenceCollection::setFlag(const Kmer& seq, SeqFlag flag)
+void NetworkSequenceCollection::setFlag(const V& seq, SeqFlag flag)
 {
 	if (isLocal(seq))
 		m_data.setFlag(seq, flag);
@@ -1364,7 +1417,7 @@ void NetworkSequenceCollection::setFlag(const Kmer& seq, SeqFlag flag)
 }
 
 bool NetworkSequenceCollection::setBaseExtension(
-		const Kmer& seq, extDirection dir, uint8_t base)
+		const V& seq, extDirection dir, Symbol base)
 {
 	if (isLocal(seq)) {
 		if (m_data.setBaseExtension(seq, dir, base))
@@ -1380,7 +1433,7 @@ bool NetworkSequenceCollection::setBaseExtension(
 
 /** Remove the specified extensions from this k-mer. */
 void NetworkSequenceCollection::removeExtension(
-		const Kmer& seq, extDirection dir, SeqExt ext)
+		const V& seq, extDirection dir, SymbolSet ext)
 {
 	if (isLocal(seq)) {
 		m_data.removeExtension(seq, dir, ext);
@@ -1392,13 +1445,13 @@ void NetworkSequenceCollection::removeExtension(
 }
 
 /** Return whether this sequence belongs to this process. */
-bool NetworkSequenceCollection::isLocal(const Kmer& seq) const
+bool NetworkSequenceCollection::isLocal(const V& seq) const
 {
 	return computeNodeID(seq) == opt::rank;
 }
 
 /** Return the process ID to which the specified kmer belongs. */
-int NetworkSequenceCollection::computeNodeID(const Kmer& seq) const
+int NetworkSequenceCollection::computeNodeID(const V& seq) const
 {
 	if (opt::numProc < DEDICATE_CONTROL_AT) {
 		return seq.getCode() % (unsigned)opt::numProc;
diff --git a/Parallel/NetworkSequenceCollection.h b/Parallel/NetworkSequenceCollection.h
index e63838c..e0b8407 100644
--- a/Parallel/NetworkSequenceCollection.h
+++ b/Parallel/NetworkSequenceCollection.h
@@ -1,16 +1,22 @@
 #ifndef NETWORKSEQUENCECOLLECTION_H
 #define NETWORKSEQUENCECOLLECTION_H 1
 
-#include "SequenceCollection.h"
-#include "BranchGroup.h"
-#include "BranchRecord.h"
 #include "CommLayer.h"
-#include "FastaWriter.h"
 #include "MessageBuffer.h"
-#include "Timer.h"
+#include "SequenceCollection.h"
+#include "Assembly/BranchGroup.h"
+#include "Common/Timer.h"
+#include "DataLayer/FastaWriter.h"
 #include <ostream>
 #include <set>
 #include <utility>
+#include "Common/InsOrderedMap.h"
+
+namespace NSC
+{
+	typedef InsOrderedMap<std::string, int> dbMap;
+	dbMap moveFromAaStatMap();
+}
 
 enum NetworkAssemblyState
 {
@@ -38,22 +44,37 @@ enum NetworkAssemblyState
 
 typedef std::map<uint64_t, BranchGroup> BranchGroupMap;
 
-/** A distributed map of Kmer to KmerData. */
-class NetworkSequenceCollection : public ISequenceCollection
+/** A distributed map of vertices to vertex properties. */
+class NetworkSequenceCollection
 {
 	public:
+		typedef SequenceDataHash::key_type V;
+
+		typedef SequenceDataHash::key_type key_type;
+		typedef SequenceDataHash::mapped_type mapped_type;
+		typedef SequenceDataHash::value_type value_type;
+		typedef SequenceDataHash::iterator iterator;
+		typedef SequenceDataHash::const_iterator const_iterator;
+
+		typedef mapped_type::Symbol Symbol;
+		typedef mapped_type::SymbolSet SymbolSet;
+		typedef mapped_type::SymbolSetPair SymbolSetPair;
+
+		// Used by boost::vertex_bundle_type
+		typedef mapped_type vertex_bundled;
+
 		NetworkSequenceCollection()
 			: m_state(NAS_WAITING), m_trimStep(0),
 			m_numPopped(0), m_numAssembled(0) { }
 
-		size_t performNetworkTrim(ISequenceCollection* seqCollection);
+		size_t performNetworkTrim();
 
-		size_t performNetworkDiscoverBubbles(ISequenceCollection* c);
+		size_t performNetworkDiscoverBubbles();
 		size_t performNetworkPopBubbles(std::ostream& out);
 
 		size_t controlErode();
 		size_t controlTrimRound(unsigned trimLen);
-		void controlTrim(unsigned start = 1);
+		void controlTrim(unsigned&, unsigned start = 1);
 		size_t controlRemoveMarked();
 		void controlCoverage();
 		size_t controlDiscoverBubbles();
@@ -64,22 +85,40 @@ class NetworkSequenceCollection : public ISequenceCollection
 
 		// Perform a network assembly
 		std::pair<size_t, size_t> performNetworkAssembly(
-				ISequenceCollection* seqCollection,
 				FastaWriter* fileWriter = NULL);
 
-		void add(const Kmer& seq, unsigned coverage = 1);
-		void remove(const Kmer& seq);
-		void setFlag(const Kmer& seq, SeqFlag flag);
+		void add(const V& seq, unsigned coverage = 1);
+		void remove(const V& seq);
+		void setFlag(const V& seq, SeqFlag flag);
+
+		/** Mark the specified sequence in both directions. */
+		void mark(const V& seq)
+		{
+			setFlag(seq, SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE));
+		}
+
+		/** Mark the specified sequence. */
+		void mark(const V& seq, extDirection sense)
+		{
+			setFlag(seq, sense == SENSE
+					? SF_MARK_SENSE : SF_MARK_ANTISENSE);
+		}
 
 		/** Return true if this container is empty. */
 		bool empty() const { return m_data.empty(); }
 
 		void printLoad() const { m_data.printLoad(); }
 
-		void removeExtension(const Kmer& seq, extDirection dir,
-				SeqExt ext);
-		bool setBaseExtension(const Kmer& seq, extDirection dir,
-				uint8_t base);
+		void removeExtension(const V& seq, extDirection dir,
+				SymbolSet ext);
+
+		/** Remove the specified edge of this vertex. */
+		void removeExtension(const V& seq, extDirection dir, Symbol base)
+		{
+			removeExtension(seq, dir, SymbolSet(base));
+		}
+
+		bool setBaseExtension(const V& seq, extDirection dir, Symbol base);
 
 		// Receive and dispatch packets.
 		size_t pumpNetwork();
@@ -105,9 +144,13 @@ class NetworkSequenceCollection : public ISequenceCollection
 		void handle(int senderID, const SeqDataRequest& message);
 		void handle(int senderID, const SeqDataResponse& message);
 
+		/** The observer callback function. */
+		typedef void (*SeqObserver)(SequenceCollectionHash* c,
+				const value_type& seq);
+
 		// Observer pattern, not implemented.
-		void attach(SeqObserver f) { (void)f; }
-		void detach(SeqObserver f) { (void)f; }
+		void attach(SeqObserver) { }
+		void detach(SeqObserver) { }
 
 		/** Load this collection from disk. */
 		void load(const char *path)
@@ -129,34 +172,33 @@ class NetworkSequenceCollection : public ISequenceCollection
 
 	private:
 		// Observer pattern
-		void notify(const Kmer& seq);
+		void notify(const V& seq);
 
 		void loadSequences();
 
 		std::pair<size_t, size_t> processBranchesAssembly(
-				ISequenceCollection* seqCollection,
 				FastaWriter* fileWriter, unsigned currContigID);
 		size_t processBranchesTrim();
 		bool processBranchesDiscoverBubbles();
 
 		void generateExtensionRequest(
-				uint64_t groupID, uint64_t branchID, const Kmer& seq);
+				uint64_t groupID, uint64_t branchID, const V& seq);
 		void generateExtensionRequests(uint64_t groupID,
 				BranchGroup::const_iterator first,
 				BranchGroup::const_iterator last);
 		void processSequenceExtension(
-				uint64_t groupID, uint64_t branchID, const Kmer& seq,
-				const ExtensionRecord& extRec, int multiplicity);
+				uint64_t groupID, uint64_t branchID, const V& seq,
+				const SymbolSetPair& extRec, int multiplicity);
 		void processLinearSequenceExtension(
-				uint64_t groupID, uint64_t branchID, const Kmer& seq,
-				const ExtensionRecord& extRec, int multiplicity,
+				uint64_t groupID, uint64_t branchID, const V& seq,
+				const SymbolSetPair& extRec, int multiplicity,
 				unsigned maxLength);
 		void processSequenceExtensionPop(
-				uint64_t groupID, uint64_t branchID, const Kmer& seq,
-				const ExtensionRecord& extRec, int multiplicity,
+				uint64_t groupID, uint64_t branchID, const V& seq,
+				const SymbolSetPair& extRec, int multiplicity,
 				unsigned maxLength);
 
-		void assembleContig(ISequenceCollection* seqCollection,
+		void assembleContig(
 				FastaWriter* fileWriter,
 				BranchRecord& branch, unsigned id);
 
@@ -166,8 +208,8 @@ class NetworkSequenceCollection : public ISequenceCollection
 
 		void parseControlMessage(int source);
 
-		bool isLocal(const Kmer& seq) const;
-		int computeNodeID(const Kmer& seq) const;
+		bool isLocal(const V& seq) const;
+		int computeNodeID(const V& seq) const;
 
 		void EndState();
 
@@ -228,4 +270,16 @@ class NetworkSequenceCollection : public ISequenceCollection
 		static const size_t LOW_ACTIVE = 10;
 };
 
+// Graph
+
+namespace boost {
+
+template <>
+struct graph_traits<NetworkSequenceCollection>
+	: graph_traits<SequenceCollectionHash>
+{
+}; // graph_traits<NetworkSequenceCollection>
+
+} // namespace boost
+
 #endif
diff --git a/Parallel/SequenceCollection.h b/Parallel/SequenceCollection.h
new file mode 100644
index 0000000..a24d1a2
--- /dev/null
+++ b/Parallel/SequenceCollection.h
@@ -0,0 +1,10 @@
+#ifndef PARALLEL_SEQUENCECOLLECTION_H
+#define PARALLEL_SEQUENCECOLLECTION_H 1
+
+#if PAIRED_DBG
+# include "PairedDBG/SequenceCollection.h"
+#else
+# include "Assembly/SequenceCollection.h"
+#endif
+
+#endif
diff --git a/Parallel/parallelAbyss.cpp b/Parallel/parallelAbyss.cpp
index b000bc9..461f75a 100644
--- a/Parallel/parallelAbyss.cpp
+++ b/Parallel/parallelAbyss.cpp
@@ -1,11 +1,11 @@
 #include "config.h"
-#include "Log.h"
 #include "NetworkSequenceCollection.h"
 #include "Assembly/Options.h"
+#include "Common/Log.h"
 #include "Common/Options.h"
+#include "Common/Timer.h"
+#include "Common/Uncompress.h"
 #include "DataLayer/FastaReader.h"
-#include "Timer.h"
-#include "Uncompress.h"
 #include <cerrno>
 #include <climits> // for HOST_NAME_MAX
 #include <cstdio> // for setvbuf
@@ -13,14 +13,19 @@
 #include <cstring> // for strerror
 #include <iostream>
 #include <mpi.h>
-#include <sstream>
 #include <unistd.h> // for gethostname
 #include <vector>
+#include "DataBase/DB.h"
 
 using namespace std;
 
 static const char* FASTA_SUFFIX = ".fa";
 
+#if PAIRED_DBG
+// Define KmerPair::s_length
+# include "PairedDBG/KmerPair.cc"
+#endif
+
 static void mergeFastaFiles(const string& outputPath, const string& inputPathPrefix, bool generateNewIds = false)
 {
 	cout << "Concatenating fasta files to " << outputPath << endl;
@@ -77,6 +82,9 @@ int main(int argc, char** argv)
 	// reinitialize uncompress.
 	uncompress_init();
 
+#if PAIRED_DBG
+	opt::singleKmerSize = -1;
+#endif
 	opt::parse(argc, argv);
 	if (opt::rank == 0)
 		cout << "Running on " << opt::numProc << " processors\n";
@@ -87,6 +95,13 @@ int main(int argc, char** argv)
 	logger(0) << "Running on host " << hostname << endl;
 	MPI_Barrier(MPI_COMM_WORLD);
 
+#if PAIRED_DBG
+	Kmer::setLength(opt::singleKmerSize);
+	KmerPair::setLength(opt::kmerSize);
+#else
+	Kmer::setLength(opt::kmerSize);
+#endif
+
 	if (opt::rank == 0) {
 		NetworkSequenceCollection networkSeqs;
 		networkSeqs.runControl();
@@ -103,6 +118,20 @@ int main(int argc, char** argv)
 		if (!opt::snpPath.empty())
 			mergeFastaFiles(opt::snpPath, "snp-");
 		cout << "Done." << endl;
+		DB db;
+		if (!opt::db.empty()) {
+			init(db,
+					opt::getUvalue(),
+					opt::getVvalue(),
+					"ABYSS-P",
+					opt::getCommand(),
+					opt::getMetaValue()
+			);
+			addToDb(db, "SS", opt::ss);
+			addToDb(db, "K", opt::kmerSize);
+			addToDb(db, "numProc", opt::numProc);
+			addToDb(db, NSC::moveFromAaStatMap());
+		}
 	}
 
 	return 0;
diff --git a/ParseAligns/Makefile.am b/ParseAligns/Makefile.am
index c574c86..9e99927 100644
--- a/ParseAligns/Makefile.am
+++ b/ParseAligns/Makefile.am
@@ -4,6 +4,8 @@ abyss_fixmate_CPPFLAGS= -I$(top_srcdir) \
 	-I$(top_srcdir)/Common
 
 abyss_fixmate_LDADD= \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/Common/libcommon.a
 
 abyss_fixmate_SOURCES=abyss-fixmate.cc
diff --git a/ParseAligns/abyss-fixmate.cc b/ParseAligns/abyss-fixmate.cc
index 1183a28..0c97f92 100644
--- a/ParseAligns/abyss-fixmate.cc
+++ b/ParseAligns/abyss-fixmate.cc
@@ -14,15 +14,17 @@
 #include <getopt.h>
 #include <iomanip>
 #include <iostream>
-#include <iterator>
-#include <sstream>
-#include <string>
 #include <boost/unordered_map.hpp>
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
+#include <math.h>
 
 using namespace std;
 
 #define PROGRAM "abyss-fixmate"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Shaun Jackman.\n"
@@ -49,10 +51,16 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for sqlite\n"
+"      --strain=NAME     specify strain NAME for sqlite\n"
+"      --species=NAME    specify species NAME for sqlite\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	static string fragPath;
 	static string histPath;
 	static string covPath;
@@ -61,9 +69,13 @@ namespace opt {
 	static int print_all;
 }
 
+// for sqlite params
+static vector<string> keys;
+static vector<int> vals;
+
 static const char shortopts[] = "h:c:l:s:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
 
 static const struct option longopts[] = {
 	{ "qname",     no_argument,       &opt::qname, 1 },
@@ -77,6 +89,10 @@ static const struct option longopts[] = {
 	{ "verbose",   no_argument,       NULL, 'v' },
 	{ "help",      no_argument,       NULL, OPT_HELP },
 	{ "version",   no_argument,       NULL, OPT_VERSION },
+	{ "db",        required_argument, NULL, OPT_DB },
+	{ "library",   required_argument, NULL, OPT_LIBRARY },
+	{ "strain",    required_argument, NULL, OPT_STRAIN },
+	{ "species",   required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -314,10 +330,34 @@ static void printHistogramStats(Histogram h)
 		"max: " << h.maximum() << " "
 		"ignored: " << n_orig - h.size() << '\n'
 		<< h.barplot() << endl;
+	if (!opt::db.empty()) {
+		vals = make_vector<int>()
+			<< (int)round(h.mean())
+			<< h.median()
+			<< (int)round(h.sd())
+			<< h.size()
+			<< h.minimum()
+			<< h.maximum()
+			<< n_orig-h.size();
+
+		keys = make_vector<string>()
+			<< "mean"
+			<< "median"
+			<< "sd"
+			<< "n"
+			<< "min"
+			<< "max"
+			<< "ignored";
+
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
 }
 
 int main(int argc, char* const* argv)
 {
+	opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -337,6 +377,18 @@ int main(int argc, char* const* argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db;
+				break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0];
+				break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1];
+				break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2];
+				break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -356,6 +408,15 @@ int main(int argc, char* const* argv)
 		assert(g_fragFile.is_open());
 	}
 
+	if (!opt::db.empty())
+		init(db,
+			opt::db,
+			opt::verbose,
+			PROGRAM,
+			opt::getCommand(argc, argv),
+			opt::metaVars
+		);
+
 	Alignments alignments(1);
 	if (optind < argc) {
 		for_each(argv + optind, argv + argc,
@@ -367,6 +428,8 @@ int main(int argc, char* const* argv)
 	}
 	if (opt::verbose > 0)
 		cerr << "Read " << stats.alignments << " alignments" << endl;
+	if (!opt::db.empty())
+		addToDb(db, "read_alignments_initial", stats.alignments);
 
 	// Print the unpaired alignments.
 	if (opt::print_all) {
@@ -398,7 +461,32 @@ int main(int argc, char* const* argv)
 		"FF         " << percent(stats.numFF, sum) << "\n"
 		"Different  " << percent(stats.numDifferent, sum) << "\n"
 		"Total      " << sum << endl;
-	
+
+	if (!opt::db.empty()) {
+		vals = make_vector<int>()
+			<< alignments.size()
+			<< stats.bothUnaligned
+			<< stats.oneUnaligned
+			<< numFR
+			<< numRF
+			<< stats.numFF
+			<< stats.numDifferent
+			<< sum;
+
+		keys = make_vector<string>()
+			<< "Mateless"
+			<< "Unaligned"
+			<< "Singleton"
+			<< "FR"
+			<< "RF"
+			<< "FF"
+			<< "Different"
+			<< "Total";
+
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
+
 	if (alignments.size() == sum) {
 		cerr << PROGRAM ": error: All reads are mateless. This "
 			"can happen when first and second read IDs do not match."
diff --git a/PathOverlap/Makefile.am b/PathOverlap/Makefile.am
index 4e517d8..edbc4d7 100644
--- a/PathOverlap/Makefile.am
+++ b/PathOverlap/Makefile.am
@@ -5,6 +5,8 @@ PathOverlap_CPPFLAGS = -I$(top_srcdir) \
 	-I$(top_srcdir)/DataLayer
 
 PathOverlap_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/DataLayer/libdatalayer.a \
 	$(top_builddir)/Common/libcommon.a
 
diff --git a/PathOverlap/PathOverlap.cpp b/PathOverlap/PathOverlap.cpp
index b312b02..66ad428 100644
--- a/PathOverlap/PathOverlap.cpp
+++ b/PathOverlap/PathOverlap.cpp
@@ -15,19 +15,20 @@
 #include <cstring> // for strerror
 #include <cstdlib>
 #include <functional>
-#include <string>
-#include <sstream>
 #include <iostream>
-#include <iterator>
 #include <fstream>
 #include <getopt.h>
 #include <map>
 #include <vector>
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 
 #define PROGRAM "PathOverlap"
 
+DB db;
+
 static const char *VERSION_MESSAGE =
 PROGRAM " (ABySS) " VERSION "\n"
 "Written by Shaun Jackman and Tony Raymond.\n"
@@ -53,18 +54,27 @@ static const char *USAGE_MESSAGE =
 "      --overlap         find overlapping paths [default]\n"
 "      --assemble        assemble overlapping paths\n"
 "      --trim            trim overlapping paths\n"
-"      --adj             output the graph in adj format [default]\n"
-"      --dot             output the graph in dot format\n"
+"      --adj             output the graph in ADJ format [default]\n"
+"      --asqg            output the graph in ASQG format\n"
+"      --dot             output the graph in GraphViz format\n"
+"      --gv              output the graph in GraphViz format\n"
+"      --gfa             output the graph in GFA format\n"
 "      --sam             output the graph in SAM format\n"
 "      --SS              expect contigs to be oriented correctly\n"
 "      --no-SS           no assumption about contig orientation [default]\n"
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for sqlite\n"
+"      --strain=NAME     specify strain NAME for sqlite\n"
+"      --species=NAME    specify species NAME for sqlite\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k;
 
 	/** Output format. */
@@ -95,7 +105,8 @@ namespace opt {
 
 static const char* shortopts = "g:k:r:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION };
 
 static const struct option longopts[] = {
 	{ "graph",        required_argument, NULL, 'g' },
@@ -103,15 +114,22 @@ static const struct option longopts[] = {
 	{ "assemble",     no_argument,       &opt::mode, opt::ASSEMBLE },
 	{ "overlap",      no_argument,       &opt::mode, opt::OVERLAP },
 	{ "trim",         no_argument,       &opt::mode, opt::TRIM },
-	{ "adj",          no_argument,       &opt::format, ADJ, },
-	{ "dot",          no_argument,       &opt::format, DOT, },
-	{ "sam",          no_argument,       &opt::format, SAM, },
+	{ "adj",          no_argument,       &opt::format, ADJ },
+	{ "asqg",         no_argument,       &opt::format, ASQG },
+	{ "dot",          no_argument,       &opt::format, DOT },
+	{ "gv",           no_argument,       &opt::format, DOT },
+	{ "gfa",          no_argument,       &opt::format, GFA },
+	{ "sam",          no_argument,       &opt::format, SAM },
 	{ "SS",           no_argument,       &opt::ss, 1 },
 	{ "no-SS",        no_argument,       &opt::ss, 0 },
 	{ "repeats",      required_argument, NULL, 'r' },
 	{ "verbose",      no_argument,       NULL, 'v' },
 	{ "help",         no_argument,       NULL, OPT_HELP },
 	{ "version",      no_argument,       NULL, OPT_VERSION },
+	{ "db",           required_argument, NULL, OPT_DB },
+	{ "library",      required_argument, NULL, OPT_LIBRARY },
+	{ "strain",       required_argument, NULL, OPT_STRAIN },
+	{ "species",      required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -557,6 +575,9 @@ int main(int argc, char** argv)
 		commandLine = ss.str();
 	}
 
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -573,6 +594,14 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db; break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0]; break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1]; break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -677,5 +706,16 @@ int main(int argc, char** argv)
 		assert_good(out, opt::repeatContigs);
 	}
 
+	if (!opt::db.empty()) {
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars);
+		addToDb(db, "SS", opt::ss);
+		addToDb(db, "K", opt::k);
+	}
+
 	return 0;
 }
diff --git a/PopBubbles/PopBubbles.cpp b/PopBubbles/PopBubbles.cpp
index 08f4765..8b90d2e 100644
--- a/PopBubbles/PopBubbles.cpp
+++ b/PopBubbles/PopBubbles.cpp
@@ -75,7 +75,13 @@ static const char USAGE_MESSAGE[] =
 "      --SS              expect contigs to be oriented correctly\n"
 "      --no-SS           no assumption about contig orientation [default]\n"
 "  -g, --graph=FILE      write the contig adjacency graph to FILE\n"
-"      --dot             output bubbles in dot format\n"
+"      --adj             output the graph in ADJ format [default]\n"
+"      --asqg            output the graph in ASQG format\n"
+"      --dot             output the graph in GraphViz format\n"
+"      --gv              output the graph in GraphViz format\n"
+"      --gfa             output the graph in GFA format\n"
+"      --sam             output the graph in SAM format\n"
+"      --bubble-graph    output a graph of the bubbles\n"
 "  -j, --threads=N       use N parallel threads [1]\n"
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
@@ -104,8 +110,8 @@ namespace opt {
 	/** Write the contig adjacency graph to this file. */
 	static string graphPath;
 
-	/** Output bubbles in dot format. */
-	static int dot;
+	/** Output a graph of the bubbles. */
+	static int bubbleGraph;
 
 	int format; // used by ContigProperties
 
@@ -124,8 +130,14 @@ static const struct option longopts[] = {
 	{ "branches",      required_argument, NULL, 'a' },
 	{ "bubble-length", required_argument, NULL, 'b' },
 	{ "coverage",      required_argument, NULL, 'c' },
-	{ "dot",           no_argument,       &opt::dot, 1, },
+	{ "bubble-graph",  no_argument,       &opt::bubbleGraph, 1, },
 	{ "graph",         required_argument, NULL, 'g' },
+	{ "adj",           no_argument,       &opt::format, ADJ },
+	{ "asqg",          no_argument,       &opt::format, ASQG },
+	{ "dot",           no_argument,       &opt::format, DOT },
+	{ "gv",            no_argument,       &opt::format, DOT },
+	{ "gfa",           no_argument,       &opt::format, GFA },
+	{ "sam",           no_argument,       &opt::format, SAM },
 	{ "kmer",          required_argument, NULL, 'k' },
 	{ "identity",      required_argument, NULL, 'p' },
 	{ "scaffold",      no_argument,       &opt::scaffold, 1},
@@ -178,7 +190,7 @@ static void popBubble(Graph& g,
 		adj = g.adjacent_vertices(v);
 	copy(adj.first, adj.second, sorted.begin());
 	sort(sorted.begin(), sorted.end(), CompareCoverage(g));
-	if (opt::dot)
+	if (opt::bubbleGraph)
 #pragma omp critical(cout)
 	{
 		cout << '"' << get(vertex_name, g, v) << "\" -> {";
@@ -235,15 +247,15 @@ static float getAlignmentIdentity(const Graph& g,
 	unsigned nbranches = distance(first, last);
 	vector<int> inDists(nbranches);
 	transform(first, last, inDists.begin(),
-			bind(getDistance, boost::cref(g), t, _1));
+			boost::lambda::bind(getDistance, boost::cref(g), t, _1));
 	vector<int> outDists(nbranches);
 	transform(first, last, outDists.begin(),
-			bind(getDistance, boost::cref(g), _1, v));
+			boost::lambda::bind(getDistance, boost::cref(g), _1, v));
 	vector<int> insertLens(nbranches);
 	transform(first, last, insertLens.begin(),
-			bind(getDistance, boost::cref(g), t, _1)
-				+ bind(getLength, &g, _1)
-				+ bind(getDistance, boost::cref(g), _1, v));
+			boost::lambda::bind(getDistance, boost::cref(g), t, _1)
+				+ boost::lambda::bind(getLength, &g, _1)
+				+ boost::lambda::bind(getDistance, boost::cref(g), _1, v));
 
 	int max_in_overlap = -(*min_element(inDists.begin(),
 			inDists.end()));
@@ -263,7 +275,7 @@ static float getAlignmentIdentity(const Graph& g,
 		return max_identity;
 
 	vector<string> seqs(nbranches);
-	transform(first, last, seqs.begin(), bind(getSequence, &g, _1));
+	transform(first, last, seqs.begin(), boost::lambda::bind(getSequence, &g, _1));
 	for (unsigned i = 0; i < seqs.size(); i++) {
 		// Remove the overlapping sequence.
 		int n = seqs[i].size();
@@ -606,7 +618,7 @@ int main(int argc, char** argv)
 	if (opt::minCoverage > 0)
 		filterGraph(g);
 
-	if (opt::dot)
+	if (opt::bubbleGraph)
 		cout << "digraph bubbles {\n";
 
 	Bubbles bubbles = discoverBubbles(g);
@@ -619,7 +631,7 @@ int main(int argc, char** argv)
 	g_popped.erase(unique(g_popped.begin(), g_popped.end()),
 			g_popped.end());
 
-	if (opt::dot) {
+	if (opt::bubbleGraph) {
 		cout << "}\n";
 	} else {
 		for (vector<ContigID>::const_iterator it = g_popped.begin();
diff --git a/README.md b/README.md
index 66ca8b2..ed06ef3 100644
--- a/README.md
+++ b/README.md
@@ -16,19 +16,23 @@ Contents
 	* [Install ABySS on Debian or Ubuntu](#install-abyss-on-debian-or-ubuntu)
 	* [Install ABySS on Mac OS X](#install-abyss-on-mac-os-x)
 * [Dependencies](#dependencies)
+* [Compiling ABySS from GiHub](#compiling-abyss-from-github)
 * [Compiling ABySS from source](#compiling-abyss-from-source)
 * [Assembling a paired-end library](#assembling-a-paired-end-library)
 * [Assembling multiple libraries](#assembling-multiple-libraries)
 * [Scaffolding](#scaffolding)
 * [Rescaffolding with long sequences](#rescaffolding-with-long-sequences)
+* [Assembling using a paired de Bruijn graph](#assembling-using-a-paired-de-bruijn-graph)
 * [Assembling a strand-specific RNA-Seq library](#assembling-a-strand-specific-rna-seq-library)
 * [Optimizing the parameter k](#optimizing-the-parameter-k)
 * [Parallel processing](#parallel-processing)
 * [Running ABySS on a cluster](#running-abyss-on-a-cluster)
+* [Using the DIDA alignment framework](#using-the-dida-alignment-framework)
 * [Assembly Parameters](#assembly-parameters)
 * [ABySS programs](#abyss-programs)
+* [Export to SQLite Database](#export-to-sqlite-database)
 * [Publications](#publications)
-* [Mailing List](#mailing-list)
+* [Support](#support)
 * [Authors](#authors)
 
 Quick Start
@@ -45,9 +49,9 @@ or download and install the
 
 ## Install ABySS on Mac OS X
 
-Install [Homebrew](http://brew.sh/), and run the command
+Install [Homebrew](http://brew.sh/), and run the commands
 
-	brew install abyss
+	brew install homebrew/science/abyss
 
 ## Assemble a small synthetic data set
 
@@ -236,6 +240,27 @@ the `long` parameter. These scaffolds will be stored in the file
 		mp1='mp1_1.fa mp1_2.fa' mp2='mp2_1.fa mp2_2.fa' \
 		long1=long1.fa
 
+Assembling using a paired de Bruijn graph
+=========================================
+
+Assemblies may be performed using a _paired de Bruijn graph_ instead
+of a standard de Bruijn graph.  In paired de Bruijn graph mode, ABySS
+uses _k-mer pairs_ in place of k-mers, where each k-mer pair consists of
+two equal-size k-mers separated by a fixed distance.  A k-mer pair
+is functionally similar to a large k-mer spanning the breadth of the k-mer
+pair, but uses less memory because the sequence in the gap is not stored.
+To assemble using paired de Bruijn graph mode, specify both individual
+k-mer size (`K`) and k-mer pair span (`k`). For example, to assemble E.
+coli with a individual k-mer size of 16 and a k-mer pair span of 64:
+
+	abyss-pe name=ecoli K=16 k=64 in='reads1.fa reads2.fa'
+
+In this example, the size of the intervening gap between k-mer pairs is
+32 bp (64 - 2\*16). Note that the `k` parameter takes on a new meaning
+in paired de Bruijn graph mode. `k` indicates kmer pair span in
+paired de Bruijn graph mode (when `K` is set), whereas `k` indicates
+k-mer size in standard de Bruijn graph mode (when `K` is not set).
+
 Assembling a strand-specific RNA-Seq library
 ============================================
 
@@ -303,6 +328,18 @@ For example, to submit an array of jobs to assemble every odd value of
 	qsub -N ecoli -pe openmpi 64 -t 51-63:2 \
 		<<<'abyss-pe -C k$SGE_TASK_ID in=/data/reads.fa'
 
+Using the DIDA alignment framework
+=================================
+
+ABySS supports the use of DIDA (Distributed Indexing Dispatched Alignment),
+an MPI-based framework for computing sequence alignments in parallel across
+multiple machines. The DIDA software must be separately downloaded and
+installed from http://www.bcgsc.ca/platform/bioinfo/software/dida. In
+comparison to the standard ABySS alignment stages which are constrained
+to a single machine, DIDA offers improved performance and the ability to
+scale to larger targets. Please see the DIDA section of the abyss-pe man
+page (in the `doc` subdirectory) for details on usage.
+
 Assembly Parameters
 ===================
 
@@ -315,7 +352,8 @@ Parameters of the driver script, `abyss-pe`
  * `e`: minimum erosion k-mer coverage [`sqrt(median)`]
  * `E`: minimum erosion k-mer coverage per strand [`1`]
  * `j`: number of threads [`2`]
- * `k`: size of k-mer (bp)
+ * `k`: size of k-mer (when `K` is not set) or the span of a k-mer pair (when `K` is set)
+ * `K`: the length of a single k-mer in a k-mer pair (bp)
  * `l`: minimum alignment length of a read (bp) [`k`]
  * `m`: minimum overlap of two unitigs (bp) [`30`]
  * `n`: minimum number of pairs required for building contigs [`10`]
@@ -331,10 +369,10 @@ Please see the
 [abyss-pe](http://manpages.ubuntu.com/abyss-pe.1.html)
 manual page for more information on assembly parameters.
 
-Possibly, `abyss-pe` parameters can have same names as existing environment variables'. The parameters then cannot be used until the environment variables are unset. To detect such occasions, run the command: 
+Possibly, `abyss-pe` parameters can have same names as existing environment variables'. The parameters then cannot be used until the environment variables are unset. To detect such occasions, run the command:
 
 	abyss-pe env [options]
- 
+
 Above command will report all `abyss-pe` parameters that are set from various origins. However it will not operate ABySS programs.
 
 ABySS programs
@@ -343,9 +381,9 @@ ABySS programs
 `abyss-pe` is a driver script implemented as a Makefile. Any option of
 `make` may be used with `abyss-pe`. Particularly useful options are:
 
- * `-C dir`, `--directory=dir`  
+ * `-C dir`, `--directory=dir`
    Change to the directory `dir` and store the results there.
- * `-n`, `--dry-run`  
+ * `-n`, `--dry-run`
    Print the commands that would be executed, but do not execute
    them.
 
@@ -373,6 +411,50 @@ ABySS programs
 For a flowchart showing the relationship between these programs,
 see doc/flowchart.pdf.
 
+Export to SQLite Database
+=========================
+
+ABySS has a built-in support for SQLite database. With this option activated, it exports log values into a SQLite file and/or `.csv` files at runtime.
+
+## Activating the functionality
+
+Download SQLite [here](http://www.sqlite.org/download.html) and install. (See [Quick Start](#quick-start) for details)
+
+To compile ABySS with SQLite, add configure flag `--with-sqlite` to the steps in [Compiling ABySS from GiHub](#compiling-abyss-from-github) / [Compiling ABySS from source](#compiling-abyss-from-source).
+
+	./configure [other options] --with-sqlite=/path/to/sqlite3/
+	make
+	sudo make install
+
+## Database parameters
+Of `abyss-pe`:
+ * `db`: path to SQLite repository file [`$(name).sqlite`]
+ * `species`: name of species to archive [ ]
+ * `strain`: name of strain to archive [ ]
+ * `library`: name of library to archive [ ]
+
+For example, to export data of species 'Ecoli', strain 'O121' and library 'pe200' into your SQLite database repository named '/abyss/test.sqlite':
+
+	abyss-pe db=/abyss/test.sqlite species=Ecoli strain=O121 library=pe200 [other options]
+
+## Helper programs
+Found in your `path`:
+ * `abyss-db-txt`: create a flat file showing entire repository at a glance
+ * `abyss-db-csv`: create `.csv` table(s) from the repository
+
+Usage:
+
+    abyss-db-txt /your/repository
+    abyss-db-csv /your/repository program(s)
+
+For example,
+
+	abyss-db-txt repo.sqlite
+
+	abyss-db-csv repo.sqlite DistanceEst
+	abyss-db-csv repo.sqlite DistanceEst abyss-scaffold
+	abyss-db-csv repo.sqlite --all
+
 Publications
 ============
 
@@ -382,6 +464,7 @@ Simpson, Jared T., Kim Wong, Shaun D. Jackman, Jacqueline E. Schein,
 Steven JM Jones, and İnanç Birol.
 **ABySS: a parallel assembler for short read sequence data**.
 *Genome research* 19, no. 6 (2009): 1117-1123.
+[doi:10.1101/gr.089532.108](http://dx.doi.org/10.1101/gr.089532.108)
 
 ## [Trans-ABySS](http://www.nature.com/nmeth/journal/v7/n11/abs/nmeth.1517.html)
 
@@ -389,6 +472,7 @@ Robertson, Gordon, Jacqueline Schein, Readman Chiu, Richard Corbett,
 Matthew Field, Shaun D. Jackman, Karen Mungall et al.
 **De novo assembly and analysis of RNA-seq data**.
 *Nature methods* 7, no. 11 (2010): 909-912.
+[doi:10.1038/10.1038/nmeth.1517](http://dx.doi.org/10.1038/nmeth.1517)
 
 ## [ABySS-Explorer](http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=5290690)
 
@@ -396,18 +480,19 @@ Nielsen, Cydney B., Shaun D. Jackman, Inanc Birol, and Steven JM Jones.
 **ABySS-Explorer: visualizing genome sequence assemblies**.
 *IEEE Transactions on Visualization and Computer Graphics*
 15, no. 6 (2009): 881-888.
+[doi:10.1109/TVCG.2009.116](http://dx.doi.org/10.1109/TVCG.2009.116)
 
-Mailing List
-============
+Support
+=======
+
+[Ask a question](https://www.biostars.org/p/new/post/?tag_val=abyss,assembly)
+on [Biostars](https://www.biostars.org/t/abyss/).
 
 Subscribe to the
 [ABySS mailing list]
 (http://groups.google.com/group/abyss-users),
 <abyss-users at googlegroups.com>.
 
-Post questions to the community on
-[![Biostar](http://www.biostars.org/static/biostar.antipixel.png)](http://www.biostars.org/show/tag/abyss/).
-
 For questions related to transcriptome assembly, contact the
 [Trans-ABySS mailing list]
 (http://groups.google.com/group/trans-abyss),
diff --git a/Scaffold/Makefile.am b/Scaffold/Makefile.am
index 04a908a..253b181 100644
--- a/Scaffold/Makefile.am
+++ b/Scaffold/Makefile.am
@@ -7,6 +7,8 @@ abyss_scaffold_CPPFLAGS = -I$(top_srcdir) \
 abyss_scaffold_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
 
 abyss_scaffold_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/Common/libcommon.a
 
 abyss_scaffold_SOURCES = scaffold.cc
diff --git a/Scaffold/drawgraph.cc b/Scaffold/drawgraph.cc
index d034e5f..6d39178 100644
--- a/Scaffold/drawgraph.cc
+++ b/Scaffold/drawgraph.cc
@@ -39,7 +39,7 @@ PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 
 static const char USAGE_MESSAGE[] =
 "Usage: " PROGRAM " [OPTION]... FASTA|OVERLAP DIST...\n"
-"Place each contig on a one-dimesional coordinate system using\n"
+"Place each contig on a one-dimensional coordinate system using\n"
 "distance estimates and output a DOT graph with coordinates.\n"
 "\n"
 " Arguments:\n"
@@ -50,7 +50,10 @@ static const char USAGE_MESSAGE[] =
 "\n"
 " Options:\n"
 "\n"
+"      --l2=REAL         set the L2 regularizer to REAL [1e-323]\n"
 "  -x, --xscale=N        set the x scale to N nt/inch [100e3]\n"
+"      --gv, --dot       output in GraphViz DOT format [default]\n"
+"      --tsv             output in TSV format\n"
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
@@ -60,6 +63,9 @@ static const char USAGE_MESSAGE[] =
 namespace opt {
 	unsigned k; // used by ContigProperties
 
+	/** The L2 regularizer. */
+	double l2 = 1e-323;
+
 	/** The x scale. */
 	double xscale = 100e3; // nt/inch
 
@@ -72,9 +78,13 @@ namespace opt {
 
 static const char shortopts[] = "x:v";
 
-enum { OPT_HELP = 1, OPT_VERSION };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_L2 };
 
 static const struct option longopts[] = {
+	{ "dot", no_argument, &opt::format, DOT },
+	{ "gv", no_argument, &opt::format, DOT },
+	{ "tsv", no_argument, &opt::format, TSV },
+	{ "l2", required_argument, NULL, OPT_L2 },
 	{ "xscale", required_argument, NULL, 'x' },
 	{ "verbose", no_argument, NULL, 'v' },
 	{ "help", no_argument, NULL, OPT_HELP },
@@ -116,8 +126,9 @@ static void solve(Matrix& a, Vector& b)
 {
 	int ret = cholesky_decompose(a);
 	if (ret > 0) {
-		cerr << PROGRAM ": error: "
-			"The graph has multiple connected components.\n";
+		cerr << PROGRAM ": error: The graph matrix is singular. "
+			"It may have multiple connected components. "
+			"Try increasing the L2 regularizer, for example --l2=1e-300\n";
 		exit(EXIT_FAILURE);
 	}
 	cholesky_solve(a, b, ublas::lower());
@@ -134,6 +145,9 @@ int main(int argc, char** argv)
 		  case '?':
 			die = true;
 			break;
+		  case OPT_L2:
+			arg >> opt::l2;
+			break;
 		  case 'x':
 			arg >> opt::xscale;
 			break;
@@ -184,8 +198,22 @@ int main(int argc, char** argv)
 	Matrix a(n, n);
 	Vector b = ublas::zero_vector<double>(n);
 
-	// Set the origin.
+	// Set the origin of the layout. Pin the first contig and its reverse
+	// complement to an extreme negative and positive position, so that the two
+	// components should not overlap. The two vertices should be in separate
+	// components. If the graph has multiple components, the matrix should be
+	// regularized by adding lambda to all values on the diagonal. The
+	// components will overlap be can be separated afterward.
+	const double MAX_SCAFFOLD_SIZE = 10e6;
 	a(0, 0) = 1;
+	b[0] = -MAX_SCAFFOLD_SIZE;
+	a(1, 1) = 1;
+	b[1] = MAX_SCAFFOLD_SIZE;
+
+	// Add the L2 regularizer to the matrix.
+	if (opt::l2 > 0)
+		for (unsigned i = 0; i < n; ++i)
+			a(i, i) += opt::l2;
 
 	// Build the information matrix.
 	Eit eit, elast;
@@ -209,18 +237,54 @@ int main(int argc, char** argv)
 	// Solve the equation Ax = b for x.
 	solve(a, b);
 
+	// Determine the origin and width of the layout.
+	double min_pos = std::numeric_limits<double>::max();
+	double max_pos = -std::numeric_limits<double>::max();
+	double min_rc = std::numeric_limits<double>::max();
+	for (unsigned i = 0; i < n; ++i) {
+		if (b[i] == 0) {
+			// A disconnected vertex.
+		} else if (b[i] < 0) {
+			min_pos = min(min_pos, b[i] - g[vertex(i, g)].length);
+			max_pos = max(max_pos, b[i]);
+		} else
+			min_rc = min(min_rc, b[i] - g[vertex(i, g)].length);
+	}
+	assert(min_pos != std::numeric_limits<double>::max());
+	assert(max_pos != -std::numeric_limits<double>::max());
+	assert(min_rc != std::numeric_limits<double>::max());
+
+	// Set the origin of the positive and negative components.
+	for (unsigned i = 0; i < n; ++i) {
+		if (b[i] == 0)
+			// A disconnected vertex.
+			b[i] = NAN;
+		else if (b[i] < 0)
+			b[i] = b[i] - min_pos;
+		else
+			b[i] = b[i] - min_rc + (max_pos - min_pos);
+	}
+
 	// Output the coordinates of each contig.
-	if (opt::verbose > 1) {
+	if (opt::format == TSV) {
+		std::cout << "Name\tSize\tLeftPos\tRightPos\n";
 		Vit uit, ulast;
 		for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) {
 			V u = *uit;
 			size_t ui = get(vertex_index, g, u);
-			ssize_t x1 = (ssize_t)b[ui];
-			ssize_t x0 = x1 - g[u].length;
-			cerr << get(vertex_name, g, u)
-				<< '\t' << x0 << '\t' << x1 << '\n';
+			std::cout << get(vertex_name, g, u) << '\t' << g[u].length;
+			if (std::isnan(b[ui])) {
+				// A disconnected vertex.
+				std::cout << "\tNA\tNA\n";
+			} else {
+				ssize_t x1 = (ssize_t)round(b[ui]);
+				ssize_t x0 = x1 - g[u].length;
+				std::cout << '\t' << x0 << '\t' << x1 << '\n';
+			}
 		}
+		exit(EXIT_SUCCESS);
 	}
+	assert(opt::format == DOT);
 
 	// Sort the contigs by their right coordinate.
 	std::vector< std::pair<double, V> > sorted;
@@ -229,7 +293,8 @@ int main(int argc, char** argv)
 	for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) {
 		V u = *uit;
 		size_t ui = get(vertex_index, g, u);
-		sorted.push_back(std::make_pair(b[ui], u));
+		double x1 = isnan(b[ui]) ? 0 : b[ui];
+		sorted.push_back(std::make_pair(x1, u));
 	}
 	sort(sorted.begin(), sorted.end());
 
@@ -243,7 +308,7 @@ int main(int argc, char** argv)
 	size_t yi = 0;
 	for (size_t i = 0; i < n; ++i) {
 		V u = sorted[i].second;
-		double pos = b[get(vertex_index, g, u)];
+		double pos = sorted[i].first;
 		size_t l = g[u].length;
 
 		if (pos - l < pos0)
diff --git a/Scaffold/junction.cc b/Scaffold/junction.cc
index 2ccaed0..f78e520 100644
--- a/Scaffold/junction.cc
+++ b/Scaffold/junction.cc
@@ -188,7 +188,7 @@ int main(int argc, char** argv)
 	ScaffoldGraph scaffoldG(overlapG.num_vertices() / 2);
 	if (optind < argc) {
 		for_each(argv + optind, argv + argc,
-				bind(readGraph, _1, boost::ref(scaffoldG)));
+				boost::lambda::bind(readGraph, _1, boost::ref(scaffoldG)));
 		// Add any missing complementary edges.
 		size_t numAdded = addComplementaryEdges(scaffoldG);
 		if (opt::verbose > 0)
diff --git a/Scaffold/scaffold.cc b/Scaffold/scaffold.cc
index 1ad0736..d1ef9f0 100644
--- a/Scaffold/scaffold.cc
+++ b/Scaffold/scaffold.cc
@@ -22,9 +22,9 @@
 #include <functional>
 #include <getopt.h>
 #include <iostream>
-#include <sstream>
-#include <string>
 #include <utility>
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 using namespace std::rel_ops;
@@ -33,6 +33,8 @@ using boost::tie;
 
 #define PROGRAM "abyss-scaffold"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Shaun Jackman.\n"
@@ -57,6 +59,7 @@ static const char USAGE_MESSAGE[] =
 "                        that maximizes the scaffold N50.\n"
 "  -k, --kmer=N          length of a k-mer\n"
 "      --min-gap=N       minimum scaffold gap length to output [50]\n"
+"      --max-gap=N       maximum scaffold gap length to output [inf]\n"
 "      --complex         remove complex transitive edges\n"
 "      --no-complex      don't remove complex transitive edges [default]\n"
 "      --SS              expect contigs to be oriented correctly\n"
@@ -66,10 +69,17 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for sqlite\n"
+"      --strain=NAME     specify strain NAME for sqlite\n"
+"      --species=NAME    specify species NAME for sqlite\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
+
 	unsigned k; // used by ContigProperties
 
 	/** Minimum number of pairs. */
@@ -82,6 +92,10 @@ namespace opt {
 	/** Minimum scaffold gap length to output. */
 	static int minGap = 50;
 
+	/** Maximum scaffold gap length to output.
+	 * -ve value means no maximum. */
+	static int maxGap = -1;
+
 	/** Write the paths to this file. */
 	static string out;
 
@@ -103,12 +117,15 @@ namespace opt {
 
 static const char shortopts[] = "g:k:n:o:s:v";
 
-enum { OPT_HELP = 1, OPT_VERSION, OPT_MIN_GAP, OPT_COMP };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_MIN_GAP, OPT_MAX_GAP, OPT_COMP,
+	OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION, OPT_MIN_GAP, OPT_MAX_GAP, OPT_COMP };
 
 static const struct option longopts[] = {
 	{ "graph",       no_argument,       NULL, 'g' },
 	{ "kmer",        required_argument, NULL, 'k' },
 	{ "min-gap",     required_argument, NULL, OPT_MIN_GAP },
+	{ "max-gap",     required_argument, NULL, OPT_MAX_GAP },
 	{ "npairs",      required_argument, NULL, 'n' },
 	{ "out",         required_argument, NULL, 'o' },
 	{ "seed-length", required_argument, NULL, 's' },
@@ -119,6 +136,10 @@ static const struct option longopts[] = {
 	{ "verbose",     no_argument,       NULL, 'v' },
 	{ "help",        no_argument,       NULL, OPT_HELP },
 	{ "version",     no_argument,       NULL, OPT_VERSION },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -180,6 +201,10 @@ static void filterGraph(Graph& g, unsigned minContigLength)
 	unsigned numRemovedE = numBefore - num_edges(g);
 	if (opt::verbose > 0)
 		cerr << "Removed " << numRemovedE << " edges.\n";
+	if (!opt::db.empty()) {
+		addToDb(db, "V_removed", numRemovedV);
+		addToDb(db, "E_removed", numRemovedE);
+	}
 }
 
 /** Return true if the specified edge is a cycle. */
@@ -209,6 +234,9 @@ static void removeCycles(Graph& g)
 		cerr << "Removed " << cycles.size() << " cyclic edges.\n";
 		printGraphStats(cerr, g);
 	}
+
+	if (!opt::db.empty())
+		addToDb(db, "E_removed_cyclic", cycles.size());
 }
 
 /** Find edges in g0 that resolve forks in g.
@@ -262,6 +290,8 @@ static void resolveForks(Graph& g, const Graph& g0)
 	if (opt::verbose > 0)
 		cerr << "Added " << numEdges
 			<< " edges to ambiguous vertices.\n";
+	if (!opt::db.empty())
+		addToDb(db, "E_added_ambig", numEdges);
 }
 
 /** Remove tips.
@@ -278,6 +308,9 @@ static void pruneTips(Graph& g)
 		cerr << "Removed " << n << " tips.\n";
 		printGraphStats(cerr, g);
 	}
+
+	if (!opt::db.empty())
+		addToDb(db, "Tips_removed", n);
 }
 
 /** Remove repetitive vertices from this graph.
@@ -354,6 +387,10 @@ static void removeRepeats(Graph& g)
 			<< numRemoved << " ambiguous vertices.\n";
 		printGraphStats(cerr, g);
 	}
+	if (!opt::db.empty()) {
+		addToDb(db, "V_cleared_ambg", repeats.size());
+		addToDb(db, "V_removed_ambg", numRemoved);
+	}
 }
 
 /** Remove weak edges from this graph.
@@ -433,6 +470,23 @@ static void removeWeakEdges(Graph& g)
 		cerr << "Removed " << weak.size() << " weak edges.\n";
 		printGraphStats(cerr, g);
 	}
+	if (!opt::db.empty())
+		addToDb(db, "E_removed_weak", weak.size());
+}
+
+static void removeLongEdges(Graph& g)
+{
+	typedef graph_traits<Graph>::edge_descriptor E;
+	typedef graph_traits<Graph>::edge_iterator Eit;
+
+	vector<E> long_e;
+	Eit eit, elast;
+	for (tie(eit, elast) = edges(g); eit != elast; ++eit) {
+		E e = *eit;
+		if (g[e].distance > opt::maxGap)
+			long_e.push_back(e);
+	}
+	remove_edges(g, long_e.begin(), long_e.end());
 }
 
 /** Return whether the specified distance estimate is an exact
@@ -494,6 +548,21 @@ static void readGraph(const string& path, Graph& g)
 	assert(in.eof());
 	if (opt::verbose > 0)
 		printGraphStats(cerr, g);
+
+	vector<int> vals = passGraphStatsVal(g);
+	vector<string> keys = make_vector<string>()
+		<< "V_readGraph"
+		<< "E_readGraph"
+		<< "degree0_readGraph"
+		<< "degree1_readGraph"
+		<< "degree234_readGraph"
+		<< "degree5_readGraph"
+		<< "max_readGraph";
+
+	if (!opt::db.empty()) {
+		for(unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
 	g_contigNames.lock();
 }
 
@@ -548,6 +617,30 @@ static Histogram buildScaffoldLengthHistogram(
 	return h;
 }
 
+/** Add contiguity stats to database */
+static void addCntgStatsToDb(
+		const Histogram h, const unsigned min)
+{
+	vector<int> vals = passContiguityStatsVal(h, min);
+	vector<string> keys = make_vector<string>()
+		<< "n"
+		<< "n200"
+		<< "nN50"
+		<< "min"
+		<< "N80"
+		<< "N50"
+		<< "N20"
+		<< "Esize"
+		<< "max"
+		<< "sum"
+		<< "nNG50"
+		<< "NG50";
+	if (!opt::db.empty()) {
+		for(unsigned i=0; i<vals.size(); i++)
+			addToDb(db, keys[i], vals[i]);
+	}
+}
+
 /** Build scaffold paths.
  * @param output write the results
  * @return the scaffold N50
@@ -586,6 +679,9 @@ unsigned scaffold(const Graph& g0, unsigned minContigLength,
 		printGraphStats(cerr, g);
 	}
 
+	if (!opt::db.empty())
+		addToDb(db, "Edges_transitive", numTransitive);
+
 	// Prune tips.
 	pruneTips(g);
 
@@ -597,6 +693,10 @@ unsigned scaffold(const Graph& g0, unsigned minContigLength,
 			<< " vertices in bubbles.\n";
 		printGraphStats(cerr, g);
 	}
+
+	if (!opt::db.empty())
+		addToDb(db, "Vertices_bubblePopped", popped.size());
+
 	if (opt::verbose > 1) {
 		cerr << "Popped:";
 		for (vector<V>::const_iterator it = popped.begin();
@@ -608,12 +708,16 @@ unsigned scaffold(const Graph& g0, unsigned minContigLength,
 	// Remove weak edges.
 	removeWeakEdges(g);
 
+	// Remove any edges longer than opt::maxGap.
+	if (opt::maxGap >= 0)
+		removeLongEdges(g);
+
 	// Assemble the paths.
 	ContigPaths paths;
 	assembleDFS(g, back_inserter(paths), opt::ss);
 	sort(paths.begin(), paths.end());
+	unsigned n = 0;
 	if (opt::verbose > 0) {
-		unsigned n = 0;
 		for (ContigPaths::const_iterator it = paths.begin();
 				it != paths.end(); ++it)
 			n += it->size();
@@ -622,6 +726,11 @@ unsigned scaffold(const Graph& g0, unsigned minContigLength,
 		printGraphStats(cerr, g);
 	}
 
+	if (!opt::db.empty()) {
+		addToDb(db, "contigs_assembled", n);
+		addToDb(db, "scaffolds_assembled", paths.size());
+	}
+
 	const unsigned STATS_MIN_LENGTH = opt::minContigLength;
 	if (!output) {
 		static bool printHeader = true;
@@ -631,6 +740,7 @@ unsigned scaffold(const Graph& g0, unsigned minContigLength,
 			<< "\ts=" << minContigLength << '\n';
 		if (opt::verbose == 0)
 			printHeader = false;
+		addCntgStatsToDb(h, STATS_MIN_LENGTH);
 		return h.trimLow(STATS_MIN_LENGTH).n50();
 	}
 
@@ -656,12 +766,16 @@ unsigned scaffold(const Graph& g0, unsigned minContigLength,
 	// Print assembly contiguity statistics.
 	Histogram h = buildScaffoldLengthHistogram(g, paths);
 	printContiguityStats(cerr, h, STATS_MIN_LENGTH) << '\n';
+	addCntgStatsToDb(h, STATS_MIN_LENGTH);
 	return h.trimLow(STATS_MIN_LENGTH).n50();
 }
 
 /** Run abyss-scaffold. */
 int main(int argc, char** argv)
 {
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -697,12 +811,27 @@ int main(int argc, char** argv)
 		  case OPT_MIN_GAP:
 			arg >> opt::minGap;
 			break;
+		  case OPT_MAX_GAP:
+			arg >> opt::maxGap;
+			break;
 		  case OPT_HELP:
 			cout << USAGE_MESSAGE;
 			exit(EXIT_SUCCESS);
 		  case OPT_VERSION:
 			cout << VERSION_MESSAGE;
 			exit(EXIT_SUCCESS);
+		  case OPT_DB:
+			arg >> opt::db;
+			break;
+		  case OPT_LIBRARY:
+			arg >> opt::metaVars[0];
+			break;
+		  case OPT_STRAIN:
+			arg >> opt::metaVars[1];
+			break;
+		  case OPT_SPECIES:
+			arg >> opt::metaVars[2];
+			break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -726,6 +855,15 @@ int main(int argc, char** argv)
 			<< " --help' for more information.\n";
 		exit(EXIT_FAILURE);
 	}
+	if (!opt::db.empty()) {
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars);
+		addToDb(db, "K", opt::k);
+	}
 
 	Graph g;
 	if (optind < argc) {
@@ -741,6 +879,9 @@ int main(int argc, char** argv)
 		printGraphStats(cerr, g);
 	}
 
+	if (!opt::db.empty())
+		addToDb(db, "add_complement_edges", numAdded);
+
 	// Remove invalid edges.
 	unsigned numBefore = num_edges(g);
 	remove_edge_if(InvalidEdge(g), static_cast<DG&>(g));
@@ -749,6 +890,9 @@ int main(int argc, char** argv)
 		cerr << "warning: Removed "
 			<< numRemoved << " invalid edges.\n";
 
+	if (!opt::db.empty())
+		addToDb(db, "Edges_invalid", numRemoved);
+
 	if (opt::minContigLengthEnd == 0) {
 		scaffold(g, opt::minContigLength, true);
 		return 0;
diff --git a/Sealer/Makefile.am b/Sealer/Makefile.am
new file mode 100644
index 0000000..30704e1
--- /dev/null
+++ b/Sealer/Makefile.am
@@ -0,0 +1,29 @@
+bin_PROGRAMS = abyss-sealer
+
+if HAVE_PANDOC
+dist_man1_MANS = abyss-sealer.1
+endif
+
+EXTRA_DIST = README.md
+
+abyss_sealer_CPPFLAGS = -I$(top_srcdir) \
+	-I$(top_srcdir)/Common \
+	-I$(top_srcdir)/DataLayer
+
+abyss_sealer_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
+
+abyss_sealer_LDADD = \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Align/libalign.a \
+	$(top_builddir)/Common/libcommon.a
+
+abyss_sealer_SOURCES = sealer.cc \
+	$(top_srcdir)/Bloom/BloomFilter.h \
+	$(top_srcdir)/Bloom/CascadingBloomFilter.h \
+	$(top_srcdir)/Konnector/DBGBloom.h \
+	$(top_srcdir)/Konnector/DBGBloomAlgorithms.h \
+	$(top_srcdir)/Konnector/konnector.h
+
+# Convert the README.md to a man page using Pandoc
+abyss-sealer.1: README.md
+	-pandoc -s -o $@ $<
diff --git a/Sealer/README.md b/Sealer/README.md
new file mode 100644
index 0000000..190aa86
--- /dev/null
+++ b/Sealer/README.md
@@ -0,0 +1,171 @@
+---
+title: abyss-sealer
+author: Daniel Paulino
+date: 2014-11-13
+header: ABySS
+footer: ABySS
+section: 1
+---
+
+Name
+================================================================================
+
+abyss-sealer - Close gaps within scaffolds
+
+Synopsis
+================================================================================
+
+`abyss-sealer -k <kmer size> -k <kmer size>... -o <output_prefix> -S <path to scaffold file> [options]... <reads1> [reads2]...`
+
+For example:
+
+`abyss-sealer -k90 -k80 -k70 -k60 -k50 -k40 -k30 -o test -S scaffold.fa read1.fa read2.fa`
+
+Description
+===========
+
+Sealer is an application of Konnector that closes intra-scaffold gaps. It performs three sequential functions. First, regions with Ns are identified from an input scaffold. Flanking nucleotues (2 x 100bp) are extracted from those regions while respecting the strand (5' to 3') direction on the sequence immediately downstream of each gap. In the second step, flanking sequence pairs are used as input to Konnector along with a set of reads with a high level of coverage redundancy. Ideally, t [...]
+
+Installation
+============
+
+See ABySS installation instructions.
+
+How to run as stand-alone application
+=====================================
+
+`abyss-sealer [-k values...] [-o outputprefix] [-S assembly file] [options...] [reads...]`
+
+Sealer requires the following information to run:
+- draft assembly
+- user-supplied k values (>0)
+- output prefix
+- WGS reads (for building Bloom Filters)
+
+Sample commands
+===============
+
+Without pre-built bloom filters:
+
+`abyss-sealer -k90 -k80 -o run1 -S test.fa read1.fa.gz read2.fa.gz`
+
+With pre-built bloom filters:
+
+`abyss-sealer -k90 -k80 -o run1 -S test.fa -i k90.bloom -i k80.bloom read1.fa.gz read2.fa.gz`
+
+Note: when using pre-built bloom filters, Sealer must be compiled with the same `maxk` value that the bloom filter was built with. For example, if a bloom filter was built with a `maxk`of 64, Sealer must be compiled with a `maxk` of 64 as well. If different values are used between the pre-built bloom filter and Sealer, any sequences generated will be nonsensical and incorrect.
+
+Suggested parameters for first run
+==================================
+
+When running Sealer for the first time on a dataset, we recommend using the following parameters. *P* is the threshold for number of paths allowed to be traversed. When set to 10, Konnector will attempt to close gaps even when there are 10 different paths found. It would attempt to create a consensus sequence between these paths. The default setting is 2. The required parameter *k* sets the k-mer length, and these suggested values will provide insight for optimizing Sealer. For instance, [...]
+
+- `-P 10`
+- `-k90 -k80 -k70 -k60 -k50 -k40 -k30`
+
+Output files
+============
+
+- prefix_log.txt
+- prefix_scaffold.fa
+- prefix_merged.fa
+- prefix_flanks_1.fq -> if `--print-flanks` option used
+- prefix_flanks_2.fq -> if `--print-flanks` option used
+
+The log file contains results of each Konnector run. The structure of one run is as follows:
+
+* \#\# unique gaps closed for k##
+* No start/goal kmer: ###
+* No path: ###
+* Unique path: ###
+* Multiple paths: ###
+* Too many paths: ###
+* Too many branches: ###
+* Too many path/path mismatches: ###
+* Too many path/read mismatches: ###
+* Contains cycle: ###
+* Exceeded mem limit: ###
+* Skipped: ###
+* \#\#\# flanks left
+* k## run complete
+* Total gaps closed so far = ###
+
+The scaffold.fa file is a gap-filled version of the draft assembly inserted into Sealer. The merged.fa file contains every newly generated sequence that were inserted into gaps, including the flanking sequences. Negative sizes of new sequences indicate Konnector collapsed the pair of flanking sequences. For example:
+
+\>[scaffold ID]\_[original start position of gap on scaffold]\_[size of new sequence]
+ACGCGACGAGCAGCGAGCACGAGCAGCGACGAGCGACGACGAGCAGCGACGAGCG
+
+If `--print-flanks` option is enabled, Sealer outputs the flanking sequences
+used to insert into Konnector. This may be useful should users which to double
+check if this tool is extracting the correct sequences surrounding gaps. The
+structure of these files are as follows:
+
+\>[scaffold ID]\_[original start position of gap on scaffold]\_[size of gap]/[1 or 2 indicating whether left or right flank]
+GCTAGCTAGCTAGCTGATCGATCGTAGCTAGCTAGCTGACTAGCTGATCAGTCGA
+
+How to optimize for gap closure
+===============================
+
+To optimize Sealer, users can observe the log files generated after a run and
+adjust parameters accordingly. If K runs are showing gaps having too many
+paths or branches, consider increasing -P or -B parameters, respectively.
+
+Also consider increasing the number of K values used. Generally, large K-mers
+are better able to address highly repetitive genomic regions, while smaller
+K-mers are better able to resolve areas of low coverage.
+
+Sometimes, datasets will only have gaps closed around a certain k value.
+After running Sealer with the suggested k parameters of -k90 to -k30 (interval
+of 10), observe which k value has the most gap closures. Supposing gaps are
+mostly being closed at k90, then consider running Sealer with k values around
+k90. i.e. -k95 to k85 (interval of 1)
+
+Runtime and memory usage
+========================
+
+More K values mean more bloom filters will be required, which will increase
+runtime as it takes time to build/load each bloom filter at the beginning of
+each k run. Memory usage is not affected by using more bloom filters.
+
+The larger value used for parameters such as `-P`, `-B` or `-F` will increase
+runtime.
+
+Options
+=======
+
+Parameters of `abyss-sealer`
+
+* `--print-flanks`: outputs flank files
+* `-S`,`--input-scaffold=FILE`: load scaffold from FILE
+* `-L`,`--flank-length=N`: length of flanks to be used as pseudoreads [`100`]
+* `-D`,`--flank-distance=N`: distance of flank from gap [0]
+* `-j`,`--threads=N`: use N parallel threads [1]
+* `-k`,`--kmer=N`: the size of a k-mer
+* `-b`,`--bloom-size=N`: size of bloom filter [500M]
+* `-B`,`--max-branches=N`: max branches in de Bruijn graph traversal; use 'nolimit' for no limit [1000]
+* `-d`,`--dot-file=FILE`: write graph traversals to a DOT file
+* `-e`,`--fix-errors`: find and fix single-base errors when reads have no kmers in bloom filter [disabled]
+* `-f`,`--min-frag=N`: min fragment size in base pairs [0]
+* `-F`,`--max-frag=N`: max fragment size in base pairs [1000]
+* `-i`,`--input-bloom=FILE`: load bloom filter from FILE
+* `--mask`: mask new and changed bases as lower case
+* `--no-mask`: do not mask bases [default]
+* `--chastity`: discard unchaste reads [default]
+* `--no-chastity`: do not discard unchaste reads
+* `--trim-masked`: trim masked bases from the ends of reads
+* `--no-trim-masked`: do not trim masked bases from the ends of reads [default]
+* `-l`,`--long-search`: start path search as close as possible to the beginnings of reads. Takes more time but improves results when bloom filter false positive rate is high [disabled]
+* `-m,`--flank-mismatches=N`: max mismatches between paths and flanks; use 'nolimit' for no limit [nolimit]
+* `-M,`--max-mismatches=N`: max mismatches between all alternate paths; use 'nolimit' for no limit [nolimit]
+* `-n `--no-limits`: disable all limits; equivalent to '-B nolimit -m nolimit -M nolimit -P nolimit'
+* `-o,`--output-prefix=FILE`: prefix of output FASTA files [required]
+* `-P,`--max-paths=N`: merge at most N alternate paths; use 'nolimit' for no limit [2]
+* `-q,`--trim-quality=N`: trim bases from the ends of reads whose quality is less than the threshold
+* `--standard-quality`: zero quality is `!' (33) default for FASTQ and SAM files
+* `--illumina-quality`: zero quality is `@' (64) default for qseq and export files
+* `-r,`--read-name=STR`: only process reads with names that contain STR
+* `-s,`--search-mem=N`: mem limit for graph searches; multiply by the number of threads (-j) to get the total mem used for graph traversal [500M]
+* `-t,`--trace-file=FILE`: write graph search stats to FILE
+* `-v,`--verbose`: display verbose output
+* `--help`: display this help and exit
+* `--version`: output version information and exit
diff --git a/Sealer/sealer.cc b/Sealer/sealer.cc
new file mode 100644
index 0000000..420deeb
--- /dev/null
+++ b/Sealer/sealer.cc
@@ -0,0 +1,1025 @@
+/**
+ * Close intra-scaffold gaps
+ * Copyright 2014 Canada's Michael Smith Genome Science Centre
+ */
+
+#include "config.h"
+
+#include "Konnector/konnector.h"
+#include "Konnector/DBGBloom.h"
+#include "Konnector/DBGBloomAlgorithms.h"
+#include "Bloom/CascadingBloomFilter.h"
+
+#include "Align/alignGlobal.h"
+#include "Common/IOUtil.h"
+#include "Common/Options.h"
+#include "Common/StringUtil.h"
+#include "DataLayer/FastaConcat.h"
+#include "DataLayer/Options.h"
+#include "Graph/DotIO.h"
+#include "Graph/Options.h"
+#include "Graph/GraphUtil.h"
+
+#include <cassert>
+#include <getopt.h>
+#include <iostream>
+#include <cstring>
+
+#include <string>
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+#include <map>
+
+
+#if _OPENMP
+# include <omp.h>
+# include "Bloom/ConcurrentBloomFilter.h"
+#endif
+
+#undef USESEQAN
+
+#if USESEQAN
+#include <seqan/align.h>
+#include <seqan/sequence.h>
+#include <seqan/align_split.h>
+#endif
+
+using namespace std;
+#if USESEQAN
+using namespace seqan;
+#endif
+
+#define PROGRAM "abyss-sealer"
+
+static const char VERSION_MESSAGE[] =
+PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
+"Written by Shaun Jackman, Hamid Mohamadi, Anthony Raymond,\n"
+"Ben Vandervalk and Daniel Paulino\n"
+"\n"
+"Copyright 2014 Canada's Michael Smith Genome Science Centre\n";
+
+static const char USAGE_MESSAGE[] =
+"Usage: " PROGRAM " -k <kmer size> -k <kmer size>... -o <output_prefix> -S <path to scaffold file> [options]... <reads1> [reads2]...\n"
+"i.e. abyss-sealer -k90 -k80 -k70 -k60 -k50 -k40 -k30 -o test -S scaffold.fa read1.fa read2.fa\n\n"
+"Close gaps by using left and right flanking sequences of gaps as 'reads' for Konnector\n"
+"and performing multiple runs with each of the supplied K values..\n"
+"\n"
+" Options:\n"
+"\n"
+"      --print-flanks           outputs flank files\n"
+"  -S, --input-scaffold=FILE    load scaffold from FILE\n"
+"  -L, --flank-length=N         length of flanks to be used as pseudoreads [100]\n"
+"  -D, --flank-distance=N       distance of flank from gap [0]\n"
+"  -j, --threads=N              use N parallel threads [1]\n"
+"  -k, --kmer=N                 the size of a k-mer\n"
+"  -b, --bloom-size=N           size of bloom filter [500M]\n"
+"  -B, --max-branches=N         max branches in de Bruijn graph traversal;\n"
+"                               use 'nolimit' for no limit [1000]\n"
+"  -d, --dot-file=FILE          write graph traversals to a DOT file\n"
+"  -e, --fix-errors             find and fix single-base errors when reads\n"
+"                               have no kmers in bloom filter [disabled]\n"
+"  -f, --min-frag=N             min fragment size in base pairs [0]\n"
+"  -F, --max-frag=N             max fragment size in base pairs [1000]\n"
+"  -i, --input-bloom=FILE       load bloom filter from FILE\n"
+"      --mask                   mask new and changed bases as lower case\n"
+"      --no-mask                do not mask bases [default]\n"
+"      --chastity               discard unchaste reads [default]\n"
+"      --no-chastity            do not discard unchaste reads\n"
+"      --trim-masked            trim masked bases from the ends of reads\n"
+"      --no-trim-masked         do not trim masked bases from the ends\n"
+"                               of reads [default]\n"
+"  -m, --flank-mismatches=N     max mismatches between paths and flanks; use\n"
+"                               'nolimit' for no limit [nolimit]\n"
+"  -M, --max-mismatches=N       max mismatches between all alternate paths;\n"
+"                               use 'nolimit' for no limit [nolimit]\n"
+"  -n  --no-limits              disable all limits; equivalent to\n"
+"                               '-B nolimit -m nolimit -M nolimit -P nolimit'\n"
+"  -o, --output-prefix=FILE     prefix of output FASTA files [required]\n"
+"  -P, --max-paths=N            merge at most N alternate paths; use 'nolimit'\n"
+"                               for no limit [2]\n"
+"  -q, --trim-quality=N         trim bases from the ends of reads whose\n"
+"                               quality is less than the threshold\n"
+"      --standard-quality       zero quality is `!' (33)\n"
+"                               default for FASTQ and SAM files\n"
+"      --illumina-quality       zero quality is `@' (64)\n"
+"                               default for qseq and export files\n"
+"  -r, --read-name=STR          only process reads with names that contain STR\n"
+"  -s, --search-mem=N           mem limit for graph searches; multiply by the\n"
+"                               number of threads (-j) to get the total mem used\n"
+"                               for graph traversal [500M]\n"
+"  -t, --trace-file=FILE        write graph search stats to FILE\n"
+"  -v, --verbose                display verbose output\n"
+"      --help                   display this help and exit\n"
+"      --version                output version information and exit\n"
+"\n"
+"Report bugs to <" PACKAGE_BUGREPORT ">.\n";
+
+namespace opt {
+
+	/** Length of flank. */
+	int flankLength = 100;
+
+	/** Distance of flank from gap. */
+	unsigned flankDistance = 0;
+
+	/** scaffold file input. */
+	static string inputScaffold;
+
+	/** The number of parallel threads. */
+	static unsigned threads = 1;
+
+	/** The size of the bloom filter in bytes. */
+	size_t bloomSize = 500 * 1024 * 1024;
+
+	/** The maximum count value of the BLoom filter. */
+	unsigned max_count = 2;
+
+	/** Input read files are interleaved? */
+	bool interleaved = false;
+
+	/** Max active branches during de Bruijn graph traversal */
+	unsigned maxBranches = 1000;
+
+	/** multi-graph DOT file containing graph traversals */
+	static string dotPath;
+
+	/**
+	 * Find and fix single base errors when a read has no
+	 * kmers in the bloom filter.
+	 */
+	bool fixErrors = false;
+
+	/** The size of a k-mer. */
+	unsigned k;
+
+	/** Vector of kmers. */
+	vector<unsigned> kvector;
+
+	/** Vector of Bloom filter paths corresponding to kmer values */
+	vector<string> bloomFilterPaths;
+
+	/** The minimum fragment size */
+	unsigned minFrag = 0;
+
+	/** The maximum fragment size */
+	unsigned maxFrag = 1000;
+
+	/** Bloom filter input file */
+	static string inputBloomPath;
+
+	/** Max paths between left and right flanking sequences */
+	unsigned maxPaths = 2;
+
+	/** Prefix for output files */
+	static string outputPrefix;
+
+	/** Max mismatches allowed when building consensus seqs */
+	unsigned maxMismatches = NO_LIMIT;
+
+	/** Only process flanks that contain this substring. */
+	static string readName;
+
+	/** Max mem used per thread during graph traversal */
+	static size_t searchMem = 500 * 1024 * 1024;
+
+	/** Output file for graph search stats */
+	static string tracefilePath;
+
+	/** Mask bases not in flanks */
+	static int mask = 0;
+
+	/** Max mismatches between consensus and flanks */
+	static unsigned maxFlankMismatches = NO_LIMIT;
+
+	/** Output flanks files */
+	static int printFlanks = 0;
+
+	/** Output detailed stats */
+	static int detailedStats = 0;
+}
+
+/** Counters */
+
+struct Counters {
+	size_t noStartOrGoalKmer;
+	size_t noPath;
+	size_t uniquePath;
+	size_t multiplePaths;
+	size_t tooManyPaths;
+	size_t tooManyBranches;
+	size_t tooManyMismatches;
+	size_t tooManyReadMismatches;
+	size_t containsCycle;
+	size_t exceededMemLimit;
+	size_t traversalMemExceeded;
+	size_t readPairsProcessed;
+	size_t readPairsMerged;
+	size_t skipped;
+};
+
+static const char shortopts[] = "S:L:D:b:B:d:ef:F:i:Ij:k:lm:M:no:P:q:r:s:t:v";
+
+enum { OPT_HELP = 1, OPT_VERSION };
+
+static const struct option longopts[] = {
+	{ "detailed-stats",   no_argument, &opt::detailedStats, 1},
+	{ "print-flanks",     no_argument, &opt::printFlanks, 1},
+	{ "input-scaffold",   required_argument, NULL, 'S' },
+	{ "flank-length",     required_argument, NULL, 'L' },
+	{ "flank-distance",   required_argument, NULL, 'D' },
+	{ "bloom-size",       required_argument, NULL, 'b' },
+	{ "max-branches",     required_argument, NULL, 'B' },
+	{ "dot-file",         required_argument, NULL, 'd' },
+	{ "fix-errors",       no_argument, NULL, 'e' },
+	{ "min-frag",         required_argument, NULL, 'f' },
+	{ "max-frag",         required_argument, NULL, 'F' },
+	{ "input-bloom",      required_argument, NULL, 'i' },
+	{ "interleaved",      no_argument, NULL, 'I' },
+	{ "threads",          required_argument, NULL, 'j' },
+	{ "kmer",             required_argument, NULL, 'k' },
+	{ "chastity",         no_argument, &opt::chastityFilter, 1 },
+	{ "no-chastity",      no_argument, &opt::chastityFilter, 0 },
+	{ "mask",             no_argument, &opt::mask, 1 },
+	{ "no-mask",          no_argument, &opt::mask, 0 },
+	{ "no-limits",        no_argument, NULL, 'n' },
+	{ "trim-masked",      no_argument, &opt::trimMasked, 1 },
+	{ "no-trim-masked",   no_argument, &opt::trimMasked, 0 },
+	{ "output-prefix",    required_argument, NULL, 'o' },
+	{ "flank-mismatches", required_argument, NULL, 'm' },
+	{ "max-mismatches",   required_argument, NULL, 'M' },
+	{ "max-paths",        required_argument, NULL, 'P' },
+	{ "trim-quality",     required_argument, NULL, 'q' },
+	{ "standard-quality", no_argument, &opt::qualityOffset, 33 },
+	{ "illumina-quality", no_argument, &opt::qualityOffset, 64 },
+	{ "read-name",        required_argument, NULL, 'r' },
+	{ "search-mem",       required_argument, NULL, 's' },
+	{ "trace-file",       required_argument, NULL, 't' },
+	{ "verbose",          no_argument, NULL, 'v' },
+	{ "help",             no_argument, NULL, OPT_HELP },
+	{ "version",          no_argument, NULL, OPT_VERSION },
+	{ NULL, 0, NULL, 0 }
+};
+
+/** The coordinates of a feature. */
+struct Coord
+{
+	int start;
+	int end;
+	
+	Coord() { }
+	Coord(int start, int end) : start(start), end(end) { }
+
+	/** Return the size of this feature. */
+	int size() const { return end - start; }
+};
+
+/** The coordinates of a gap and its flanking scaftigs. */
+struct Gap
+{
+	/** The left flanking scaftig. */
+	Coord left;
+
+	/** The right flanking scaftig. */
+	Coord right;
+
+	Gap() { }
+
+	Gap(int leftStart, int leftEnd, int rightStart, int rightEnd)
+		: left(leftStart, leftEnd), right(rightStart, rightEnd) { }
+
+	/** The start of the gap. */
+	int gapStart() const { return left.end; }
+
+	/** The end of the gap. */
+	int gapEnd() const { return right.start; }
+
+	/** The total size of the flanks plus the gap. */
+	int totalSize() const { return right.end - left.start; }
+
+	/** The size of the original gap. */
+	int gapSize() const { return gapEnd() - gapStart(); }
+
+	/** The size of the flanks. */
+	int flankSize() const { return left.size() + right.size(); }
+};
+
+/** The coordinates of a gap, its flanking scaftigs, and the sequence that
+ * fills it.
+ */
+struct ClosedGap : Gap
+{
+	/** The sequence that fills the gap. */
+	std::string seq;
+
+	ClosedGap() { }
+
+	ClosedGap(Gap gap, std::string seq) : Gap(gap), seq(seq) { }
+};
+
+#if USESEQAN
+const string r1 =
+"AGAATCAACCAACCGTTCAATGATATAATCAAGAGCGATATTGTAATCTTTGTTTCT";
+const string r2 =
+"CGACGTCCACCAATTCGTCCCTGTGCACGAGCAGTTTCCAGTCCAGCTTTTGTTCGT";
+const string ins =
+"AGAATCAACCAACCGTTCAATGATATAATCAAGAGCGATATTGTAATCTTTGTTTCTGTCACCCGGCCCCCACGACTCAAGGATTAGACCATAAACACCATCCTCTTCACCTATCGAACACTCAGCTTTCAGTTCAATTCCATTATTATCAAAAACATGCATAATATTAATCTTTAATCAATTTTTCACGACAATACTACTTTTATTGATAAAATTGCAACAAGTTGCTGTTGTTTTACTTTCTTTTGTACACAAAGTGTCTTTAACTTTATTTATCCCCTGCAGGAAACCTCTTATACAAAGTTGACACACCAACATCATAGATAATCGCCACCTTCTGGCGAGGAGTTCCTGCTGCAATTAATCGTCCAGCTTGTGCCCATTGTTCTGGTGTAAGTTTGGGACGACGTCCACCAATTCGTCCCTGTGCACGAGCAGTTTCCAGTCCAGCTTTTGTTCGT";
+
+static void seqanTests()
+{
+	typedef String<Dna> DS;
+	typedef Align<DS> Alignment;
+
+	//DS seq1 = "TTGT";
+	//DS seq2 = "TTAGT";
+	DS ref = ins;
+	DS seq1 = r1;
+	DS seq2 = r2;
+
+	Alignment align1;
+	resize(rows(align1), 2);
+	assignSource(row(align1, 0), ref);
+	assignSource(row(align1, 1), seq1);
+	Alignment align2;
+	resize(rows(align2), 2);
+	assignSource(row(align2, 0), ref);
+	assignSource(row(align2, 1), seq2);
+
+	Score<int> scoring(2, -2, -50, -100);
+
+	cout << splitAlignment(align1, align2, scoring) << endl;
+	cout << align1 << endl;
+	cout << align2 << endl;
+
+	cout << localAlignment(align1, scoring) << endl;
+	cout << align1 << endl;
+
+	cout << localAlignment(align2, scoring) << endl;
+	cout << align2 << endl;
+}
+#endif
+
+/**
+ * Set the value for a commandline option, using "nolimit"
+ * to represent NO_LIMIT.
+ */
+static inline void setMaxOption(unsigned& arg, istream& in)
+{
+	string str;
+	getline(in, str);
+	if (in && str == "nolimit") {
+		arg = NO_LIMIT;
+	} else {
+		istringstream ss(str);
+		ss >> arg;
+		// copy state bits (fail, bad, eof) to
+		// original stream
+		in.clear(ss.rdstate());
+	}
+}
+
+string sizetToString (size_t a)
+{
+	ostringstream temp;
+	temp << a;
+	return temp.str();
+}
+
+string IntToString (int a)
+{
+	ostringstream temp;
+	temp<<a;
+	return temp.str();
+}
+
+// returns merged sequence resulting from Konnector
+template <typename Graph>
+string merge(const Graph& g,
+	unsigned k,
+	const Gap& gap,
+	FastaRecord &read1,
+	FastaRecord &read2,
+	const ConnectPairsParams& params,
+	Counters& g_count,
+	ofstream& traceStream)
+{
+	ConnectPairsResult result = connectPairs(k, read1, read2, g, params);
+	ostringstream ss;
+	ss << result.readNamePrefix << '_' << gap.gapStart() << '_' << gap.gapSize();
+	result.readNamePrefix = ss.str();
+
+	if (!opt::tracefilePath.empty())
+#pragma omp critical(tracefile)
+	{
+			traceStream << result;
+			assert_good(traceStream, opt::tracefilePath);
+	}
+
+	vector<FastaRecord>& paths = result.mergedSeqs;
+	switch (result.pathResult) {
+
+		case NO_PATH:
+			assert(paths.empty());
+			if (result.foundStartKmer && result.foundGoalKmer)
+#pragma omp atomic
+				++g_count.noPath;
+			else {
+#pragma omp atomic
+				++g_count.noStartOrGoalKmer;
+			}
+			break;
+
+		case FOUND_PATH:
+			assert(!paths.empty());
+			if (result.pathMismatches > params.maxPathMismatches ||
+					result.readMismatches > params.maxReadMismatches) {
+				if (result.pathMismatches > params.maxPathMismatches)
+#pragma omp atomic
+					++g_count.tooManyMismatches;
+				else
+#pragma omp atomic
+					++g_count.tooManyReadMismatches;
+			}
+			else if (paths.size() > 1) {
+#pragma omp atomic
+				++g_count.multiplePaths;
+			}
+			else {
+#pragma omp atomic
+				++g_count.uniquePath;
+			}
+			break;
+
+		case TOO_MANY_PATHS:
+#pragma omp atomic
+			++g_count.tooManyPaths;
+			break;
+
+		case TOO_MANY_BRANCHES:
+#pragma omp atomic
+			++g_count.tooManyBranches;
+			break;
+
+		case PATH_CONTAINS_CYCLE:
+#pragma omp atomic
+			++g_count.containsCycle;
+			break;
+
+		case EXCEEDED_MEM_LIMIT:
+#pragma omp atomic
+			++g_count.exceededMemLimit;
+			break;
+	}
+
+	if (result.pathResult == FOUND_PATH) {
+		if  (result.pathMismatches > params.maxPathMismatches)
+			return "";
+		else if (result.mergedSeqs.size() > 1)
+			return result.consensusSeq;
+		else
+			return result.mergedSeqs.front();
+	}
+	else
+		return "";
+}
+
+void printLog(ofstream &logStream, const string &output) {
+#pragma omp critical(logStream)
+	logStream << output;
+	if (opt::verbose > 0)
+#pragma omp critical(cerr)
+		cerr << output;
+}
+
+void insertIntoScaffold(ofstream &scaffoldStream,
+	ofstream &mergedStream,
+	FastaRecord &record,
+	map<string, map<int, ClosedGap> > &allmerged,
+	unsigned &gapsclosedfinal)
+{
+	map<string, map<int, ClosedGap> >::iterator scaf_it;
+	map<int, ClosedGap>::reverse_iterator pos_it;
+
+	scaf_it = allmerged.find(record.id);
+	scaffoldStream << ">" << record.id << " " << record.comment << endl;
+	string modifiedSeq = record.seq;
+	if (scaf_it != allmerged.end()) {
+		for (pos_it = allmerged[record.id].rbegin();
+			pos_it != allmerged[record.id].rend();
+			pos_it++)
+		{
+			const ClosedGap& closedGap = pos_it->second;
+			int newseqsize = pos_it->second.seq.length() - closedGap.flankSize();
+			modifiedSeq.replace(
+				closedGap.left.start,
+				closedGap.totalSize(),
+				closedGap.seq
+			);
+			mergedStream << ">" << record.id << "_" << pos_it->first << "_" << newseqsize <<  endl;
+			mergedStream << pos_it->second.seq << endl;
+			gapsclosedfinal++;
+		}
+		scaffoldStream << modifiedSeq << endl;
+	}
+	else {
+		scaffoldStream << record.seq  << endl;
+	}
+
+}
+
+std::pair<FastaRecord, FastaRecord>
+makePseudoReads(std::string seq, FastaRecord record, const Gap& gap)
+{
+	std::pair<FastaRecord, FastaRecord> scaftigs;
+	// extract left flank
+	std::string leftflank = seq.substr(gap.left.start, gap.left.size());
+	std::transform(leftflank.begin(), leftflank.end(), leftflank.begin(), ::toupper);
+	scaftigs.first.seq = leftflank;
+	scaftigs.first.id = record.id + "/1";
+
+	// extract right flank
+	scaftigs.second.id = record.id + "/2";
+	std::string rightflank = seq.substr(gap.right.start, gap.right.size());
+	std::transform(rightflank.begin(), rightflank.end(), rightflank.begin(), ::toupper);
+	scaftigs.second.seq = reverseComplement(rightflank);
+
+	return scaftigs;
+}
+
+template <typename Graph>
+void kRun(const ConnectPairsParams& params,
+	unsigned k,
+	const Graph& g,
+	map<string, map<int, ClosedGap> > &allmerged,
+	map<FastaRecord, map<FastaRecord, Gap> > &flanks,
+	unsigned &gapsclosed,
+	ofstream &logStream,
+	ofstream &traceStream)
+{
+	map<FastaRecord, map<FastaRecord, Gap> >::iterator read1_it;
+	map<FastaRecord, Gap>::iterator read2_it;
+	unsigned uniqueGapsClosed = 0;
+	bool success;
+
+	Counters g_count;
+	g_count.noStartOrGoalKmer = 0;
+	g_count.noPath = 0;
+	g_count.uniquePath = 0;
+	g_count.multiplePaths = 0;
+	g_count.tooManyPaths = 0;
+	g_count.tooManyBranches = 0;
+	g_count.tooManyMismatches = 0;
+	g_count.tooManyReadMismatches = 0;
+	g_count.containsCycle = 0;
+	g_count.exceededMemLimit = 0;
+	g_count.traversalMemExceeded = 0;
+	g_count.readPairsProcessed = 0;
+	g_count.readPairsMerged = 0;
+	g_count.skipped = 0;
+
+	printLog(logStream, "Flanks inserted into k run = " + IntToString(flanks.size()) + "\n");
+
+	for (read1_it = flanks.begin(); read1_it != flanks.end();) {
+		success = false;
+		FastaRecord read1 = read1_it->first;
+		for (read2_it = flanks[read1].begin(); read2_it != flanks[read1].end(); read2_it++) {
+			FastaRecord read2 = read2_it->first;
+
+			int startposition = read2_it->second.gapStart();
+			string tempSeq = merge(g, k, read2_it->second, read1, read2, params, g_count, traceStream);
+			if (!tempSeq.empty()) {
+				success = true;
+				allmerged[read1.id.substr(0,read1.id.length()-2)][startposition]
+					= ClosedGap(read2_it->second, tempSeq);
+//#pragma omp atomic
+				gapsclosed++;
+//#pragma omp atomic
+				uniqueGapsClosed++;
+				if (gapsclosed % 100 == 0)
+					printLog(logStream, IntToString(gapsclosed) + " gaps closed so far\n");
+			}
+		}
+		if (success) {
+			flanks.erase(read1_it++);
+		}
+		else
+			read1_it++;
+	}
+
+	printLog(logStream, IntToString(uniqueGapsClosed) + " unique gaps closed for k" + IntToString(k) + "\n");
+
+	printLog(logStream, "No start/goal kmer: "
+		+ sizetToString(g_count.noStartOrGoalKmer) + "\n");
+	printLog(logStream, "No path: "
+		+ sizetToString(g_count.noPath) + "\n");
+	printLog(logStream, "Unique path: "
+		+ sizetToString(g_count.uniquePath) + "\n");
+	printLog(logStream, "Multiple paths: "
+		+ sizetToString(g_count.multiplePaths) + "\n");
+	printLog(logStream, "Too many paths: "
+		+ sizetToString(g_count.tooManyPaths) + "\n");
+	printLog(logStream, "Too many branches: "
+		+ sizetToString(g_count.tooManyBranches) + "\n");
+	printLog(logStream, "Too many path/path mismatches: "
+		+ sizetToString(g_count.tooManyMismatches) + "\n");
+	printLog(logStream, "Too many path/read mismatches: "
+		+ sizetToString(g_count.tooManyReadMismatches) + "\n");
+	printLog(logStream, "Contains cycle: "
+		+ sizetToString(g_count.containsCycle) + "\n");
+	printLog(logStream, "Exceeded mem limit: "
+		+ sizetToString(g_count.exceededMemLimit) + "\n");
+	printLog(logStream, "Skipped: "
+		+ sizetToString(g_count.skipped) + "\n");
+
+	printLog(logStream, IntToString(flanks.size()) + " flanks left\n");
+
+}
+
+bool operator<(const FastaRecord& a, const FastaRecord& b)
+{
+	if (a.id == b.id)
+		return a.seq < b.seq;
+	else
+		return a.id < b.id;
+}
+
+void findFlanks(FastaRecord &record,
+	int flanklength,
+	unsigned &gapnumber,
+	map<FastaRecord, map<FastaRecord, Gap> > &flanks)
+{
+	const string& seq = record.seq;
+
+	// Iterate over the gaps.
+	for (size_t offset = 0;
+			seq.string::find_first_of("Nn", offset) != string::npos;) {
+#pragma omp atomic
+		gapnumber++;
+		size_t startposition = seq.string::find_first_of("Nn", offset);
+
+		size_t endposition = seq.string::find_first_not_of("Nn", startposition);
+		if (endposition == string::npos) {
+			std::cerr << PROGRAM ": Warning: sequence ends with an N: " << record.id << "\n";
+			break;
+		}
+
+		size_t right_end = seq.string::find_first_of("Nn", endposition);
+		if (right_end == string::npos)
+			right_end = seq.length();
+
+		Gap gap(
+			max((ssize_t)offset, (ssize_t)startposition - (ssize_t)flanklength),
+			startposition,
+			endposition,
+			min(right_end, endposition + flanklength));
+
+		std::pair<FastaRecord, FastaRecord> scaftigs =
+			makePseudoReads(seq, record, gap);
+#pragma omp critical (flanks)
+		flanks[scaftigs.first][scaftigs.second] = gap;
+
+		offset = endposition;
+	}
+}
+
+/**
+ * Connect pairs using a Bloom filter de Bruijn graph
+ */
+int main(int argc, char** argv)
+{
+	bool die = false;
+
+	for (int c; (c = getopt_long(argc, argv,
+					shortopts, longopts, NULL)) != -1;) {
+		istringstream arg(optarg != NULL ? optarg : "");
+		switch (c) {
+		  case '?':
+			die = true; break;
+		  case 'S':
+			arg >> opt::inputScaffold; break;
+		  case 'L':
+			arg >> opt::flankLength; break;
+		  case 'D':
+			arg >> opt::flankDistance; break;
+		  case 'b':
+			opt::bloomSize = SIToBytes(arg); break;
+		  case 'B':
+			setMaxOption(opt::maxBranches, arg); break;
+		  case 'd':
+			arg >> opt::dotPath; break;
+		  case 'e':
+			opt::fixErrors = true; break;
+		  case 'f':
+			arg >> opt::minFrag; break;
+		  case 'F':
+			arg >> opt::maxFrag; break;
+		  case 'i': {
+			string tempPath;
+			arg >> tempPath;
+			opt::bloomFilterPaths.push_back(tempPath);
+			opt::inputBloomPath = tempPath;
+			break;
+			}
+		  case 'I':
+			opt::interleaved = true; break;
+		  case 'j':
+			arg >> opt::threads; break;
+		  case 'k': {
+			unsigned tempK;
+			arg >> tempK;
+			opt::kvector.push_back(tempK);
+			opt::k = tempK;
+			break;
+			}
+		  case 'm':
+			setMaxOption(opt::maxFlankMismatches, arg); break;
+		  case 'n':
+			opt::maxBranches = NO_LIMIT;
+			opt::maxFlankMismatches = NO_LIMIT;
+			opt::maxMismatches = NO_LIMIT;
+			opt::maxPaths = NO_LIMIT;
+			break;
+		  case 'M':
+			setMaxOption(opt::maxMismatches, arg); break;
+		  case 'o':
+			arg >> opt::outputPrefix; break;
+		  case 'P':
+			setMaxOption(opt::maxPaths, arg); break;
+		  case 'q':
+			arg >> opt::qualityThreshold; break;
+		  case 'r':
+			arg >> opt::readName; break;
+		  case 's':
+			opt::searchMem = SIToBytes(arg); break;
+		  case 't':
+			arg >> opt::tracefilePath; break;
+		  case 'v':
+			opt::verbose++; break;
+		  case OPT_HELP:
+			cout << USAGE_MESSAGE;
+			exit(EXIT_SUCCESS);
+		  case OPT_VERSION:
+			cout << VERSION_MESSAGE;
+			exit(EXIT_SUCCESS);
+		}
+		if (optarg != NULL && (!arg.eof() || arg.fail())) {
+			cerr << PROGRAM ": invalid option: `-"
+				<< (char)c << optarg << "'\n";
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (opt::inputScaffold.empty()) {
+		cerr << PROGRAM ": missing mandatory option `-S'\n";
+		die = true;
+	}
+
+	if (opt::k == 0) {
+		cerr << PROGRAM ": missing mandatory option `-k'\n";
+		die = true;
+	}
+
+	if (opt::outputPrefix.empty()) {
+		cerr << PROGRAM ": missing mandatory option `-o'\n";
+		die = true;
+	}
+
+	if (argc - optind < 1) {
+		cerr << PROGRAM ": missing input file arguments\n";
+		die = true;
+	}
+
+	if (die) {
+		cerr << "Try `" << PROGRAM
+			<< " --help' for more information.\n";
+		exit(EXIT_FAILURE);
+	}
+
+#if _OPENMP
+	if (opt::threads > 0)
+		omp_set_num_threads(opt::threads);
+#endif
+
+	Kmer::setLength(opt::k);
+
+#if USESEQAN
+	seqanTests();
+#endif
+
+	assert(opt::bloomSize > 0);
+
+	ofstream dotStream;
+	if (!opt::dotPath.empty()) {
+		if (opt::verbose)
+			cerr << "Writing graph traversals to "
+				"dot file `" << opt::dotPath << "'\n";
+		dotStream.open(opt::dotPath.c_str());
+		assert_good(dotStream, opt::dotPath);
+	}
+
+	ofstream traceStream;
+	if (!opt::tracefilePath.empty()) {
+		if (opt::verbose)
+			cerr << "Writing graph search stats to `"
+				<< opt::tracefilePath << "'\n";
+		traceStream.open(opt::tracefilePath.c_str());
+		assert(traceStream.is_open());
+		ConnectPairsResult::printHeaders(traceStream);
+		assert_good(traceStream, opt::tracefilePath);
+	}
+
+	string logOutputPath(opt::outputPrefix);
+	logOutputPath.append("_log.txt");
+	ofstream logStream(logOutputPath.c_str());
+	assert_good(logStream, logOutputPath);
+
+	string scaffoldOutputPath(opt::outputPrefix);
+	scaffoldOutputPath.append("_scaffold.fa");
+	ofstream scaffoldStream(scaffoldOutputPath.c_str());
+	assert_good(scaffoldStream, scaffoldOutputPath);
+
+	string mergedOutputPath(opt::outputPrefix);
+	mergedOutputPath.append("_merged.fa");
+	ofstream mergedStream(mergedOutputPath.c_str());
+	assert_good(mergedStream, mergedOutputPath);
+
+	printLog(logStream, "Finding flanks\n");
+
+	ConnectPairsParams params;
+
+	params.minMergedSeqLen = opt::minFrag;
+	params.maxMergedSeqLen = opt::maxFrag;
+	params.maxPaths = opt::maxPaths;
+	params.maxBranches = opt::maxBranches;
+	params.maxPathMismatches = opt::maxMismatches;
+	params.maxReadMismatches = opt::maxFlankMismatches;
+	/*
+	 * search from the end of the scaffold flank until
+	 * we find this many matches in a row.
+	 */
+	params.kmerMatchesThreshold = 1;
+	params.fixErrors = opt::fixErrors;
+	params.maskBases = opt::mask;
+	params.memLimit = opt::searchMem;
+	params.dotPath = opt::dotPath;
+	params.dotStream = opt::dotPath.empty() ? NULL : &dotStream;
+
+	map<FastaRecord, map<FastaRecord, Gap> > flanks;
+	const char* scaffoldInputPath = opt::inputScaffold.c_str();
+	FastaReader reader1(scaffoldInputPath, FastaReader::FOLD_CASE);
+	unsigned gapsfound = 0;
+	string temp;
+
+#pragma omp parallel
+	for (FastaRecord record;;) {
+		bool good;
+#pragma omp critical(reader1)
+		good = reader1 >> record;
+		if (good) {
+			findFlanks(record, opt::flankLength, gapsfound, flanks);
+		}
+		else {
+			break;
+		}
+	}
+
+	temp = IntToString(gapsfound) + " gaps found\n";
+	printLog(logStream, temp);
+	temp = IntToString((int)flanks.size()) + " flanks extracted\n\n";
+	printLog(logStream, temp);
+
+	if (opt::printFlanks > 0) {
+		map<FastaRecord, map<FastaRecord, Gap> >::iterator read1_it;
+		map<FastaRecord, Gap>::iterator read2_it;
+
+		string read1OutputPath(opt::outputPrefix);
+		read1OutputPath.append("_flanks_1.fq");
+		ofstream read1Stream(read1OutputPath.c_str());
+		assert_good(read1Stream, read1OutputPath);
+
+		string read2OutputPath(opt::outputPrefix);
+		read2OutputPath.append("_flanks_2.fq");
+		ofstream read2Stream(read2OutputPath.c_str());
+		assert_good(read2Stream, read2OutputPath);
+
+		for (read1_it = flanks.begin(); read1_it != flanks.end(); read1_it++) {
+			FastaRecord read1 = read1_it->first;
+			for (read2_it = flanks[read1].begin(); read2_it != flanks[read1].end(); read2_it++) {
+				FastaRecord read2 = read2_it->first;
+				const Gap& gap = read2_it->second;
+
+				read1Stream << ">" << read1.id.substr(0,read2.id.length()-2)
+					<< "_" << gap.gapStart() << "_" << gap.gapSize() << "/1\n";
+				read1Stream << read1.seq << endl;
+
+				read2Stream << ">" << read2.id.substr(0,read2.id.length()-2)
+					<< "_" << gap.gapStart() << "_" << gap.gapSize() << "/2\n";
+				read2Stream << read2.seq << endl;
+			}
+		}
+		assert_good(read1Stream, read1OutputPath.c_str());
+		read1Stream.close();
+		assert_good(read2Stream, read2OutputPath.c_str());
+		read2Stream.close();
+	}
+
+	/** map for merged sequence resutls */
+	map<string, map<int, ClosedGap> > allmerged;
+	unsigned gapsclosed=0;
+
+	for (unsigned i = 0; i<opt::kvector.size(); i++) {
+		opt::k = opt::kvector.at(i);
+		Kmer::setLength(opt::k);
+
+		BloomFilter* bloom;
+		CascadingBloomFilter* cascadingBloom = NULL;
+
+		if (!opt::bloomFilterPaths.empty() && i <= opt::bloomFilterPaths.size()) {
+
+			temp = "Loading bloom filter from `" + opt::bloomFilterPaths.at(i) + "'...\n";
+			printLog(logStream, temp);
+
+			bloom = new BloomFilter();
+
+			const char* inputPath = opt::bloomFilterPaths.at(i).c_str();
+			ifstream inputBloom(inputPath, ios_base::in | ios_base::binary);
+			assert_good(inputBloom, inputPath);
+			inputBloom >> *bloom;
+			assert_good(inputBloom, inputPath);
+			inputBloom.close();
+		} else {
+			printLog(logStream, "Building bloom filter\n");
+
+			size_t bits = opt::bloomSize * 8 / 2;
+			cascadingBloom = new CascadingBloomFilter(bits, opt::max_count);
+#ifdef _OPENMP
+			ConcurrentBloomFilter<CascadingBloomFilter> cbf(*cascadingBloom, 1000);
+			for (int i = optind; i < argc; i++)
+				Bloom::loadFile(cbf, opt::k, argv[i], 0 /*opt::verbose*/);
+#else
+			for (int i = optind; i < argc; i++)
+				Bloom::loadFile(*cascadingBloom, opt::k, argv[i], 0 /* opt::verbose*/);
+#endif
+			bloom = &cascadingBloom->getBloomFilter(opt::max_count - 1);
+		}
+
+		DBGBloom<BloomFilter> g(*bloom);
+
+		temp = "Starting K run with k = " + IntToString(opt::k) + "\n";
+		printLog(logStream, temp);
+
+		kRun(params, opt::k, g, allmerged, flanks, gapsclosed, logStream, traceStream);
+
+		temp = "k" + IntToString(opt::k) + " run complete\n"
+				+ "Total gaps closed so far = " + IntToString(gapsclosed) + "\n\n";
+		printLog(logStream, temp);
+
+		if (!opt::inputBloomPath.empty())
+			delete bloom;
+		else
+			delete cascadingBloom;
+	}
+
+	printLog(logStream, "K sweep complete\nCreating new scaffold with gaps closed...\n");
+
+	map<string, map<int, map<string, string> > >::iterator scaf_it;
+	map<int, map<string, string> >::reverse_iterator pos_it;
+	FastaReader reader2(scaffoldInputPath, FastaReader::FOLD_CASE);
+	unsigned gapsclosedfinal = 0;
+
+	/** creating new scaffold with gaps closed */
+	for (FastaRecord record;;) {
+		bool good;
+		good = reader2 >> record;
+		if (good) {
+			insertIntoScaffold(scaffoldStream, mergedStream, record, allmerged, gapsclosedfinal);
+		}
+		else
+			break;
+	}
+	printLog(logStream, "New scaffold complete\n");
+	printLog(logStream, "Gaps closed = " + IntToString(gapsclosed) + "\n");
+	logStream << (float)100 * gapsclosed / gapsfound << "%\n\n";
+	if (opt::verbose > 0) {
+		cerr << (float)100 * gapsclosed / gapsfound << "%\n\n";
+	}
+
+	assert_good(scaffoldStream, scaffoldOutputPath.c_str());
+	scaffoldStream.close();
+	assert_good(mergedStream, mergedOutputPath.c_str());
+	mergedStream.close();
+	assert_good(logStream, logOutputPath.c_str());
+	logStream.close();
+
+	if (!opt::dotPath.empty()) {
+		assert_good(dotStream, opt::dotPath);
+		dotStream.close();
+	}
+
+	if (!opt::tracefilePath.empty()) {
+		assert_good(traceStream, opt::tracefilePath);
+		traceStream.close();
+	}
+
+	return 0;
+}
diff --git a/SimpleGraph/Makefile.am b/SimpleGraph/Makefile.am
index e58574e..9609a6b 100644
--- a/SimpleGraph/Makefile.am
+++ b/SimpleGraph/Makefile.am
@@ -6,6 +6,8 @@ SimpleGraph_CPPFLAGS = -I$(top_srcdir) \
 SimpleGraph_CXXFLAGS = $(AM_CXXFLAGS) -Wno-strict-aliasing
 
 SimpleGraph_LDADD = \
+	$(top_builddir)/DataBase/libdb.a \
+	$(SQLITE_LIBS) \
 	$(top_builddir)/Common/libcommon.a \
 	-lpthread
 
diff --git a/SimpleGraph/SimpleGraph.cpp b/SimpleGraph/SimpleGraph.cpp
index 2554485..373ec70 100644
--- a/SimpleGraph/SimpleGraph.cpp
+++ b/SimpleGraph/SimpleGraph.cpp
@@ -14,18 +14,18 @@
 #include <fstream>
 #include <getopt.h>
 #include <iostream>
-#include <iterator>
-#include <map>
 #include <pthread.h>
 #include <set>
-#include <sstream>
-#include <string>
 #include <vector>
+#include "DataBase/Options.h"
+#include "DataBase/DB.h"
 
 using namespace std;
 
 #define PROGRAM "SimpleGraph"
 
+DB db;
+
 static const char VERSION_MESSAGE[] =
 PROGRAM " (" PACKAGE_NAME ") " VERSION "\n"
 "Written by Jared Simpson and Shaun Jackman.\n"
@@ -56,10 +56,16 @@ static const char USAGE_MESSAGE[] =
 "  -v, --verbose         display verbose output\n"
 "      --help            display this help and exit\n"
 "      --version         output version information and exit\n"
+"      --db=FILE         specify path of database repository in FILE\n"
+"      --library=NAME    specify library NAME for sqlite\n"
+"      --strain=NAME     specify strain NAME for sqlite\n"
+"      --species=NAME    specify species NAME for sqlite\n"
 "\n"
 "Report bugs to <" PACKAGE_BUGREPORT ">.\n";
 
 namespace opt {
+	string db;
+	dbVars metaVars;
 	unsigned k; // used by ContigProperties
 	static unsigned threads = 1;
 	static int extend;
@@ -76,7 +82,9 @@ namespace opt {
 
 static const char shortopts[] = "d:j:k:o:v";
 
-enum { OPT_HELP = 1, OPT_VERSION, OPT_MAX_COST };
+enum { OPT_HELP = 1, OPT_VERSION, OPT_MAX_COST,
+	OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES };
+//enum { OPT_HELP = 1, OPT_VERSION, OPT_MAX_COST };
 
 static const struct option longopts[] = {
 	{ "kmer",        required_argument, NULL, 'k' },
@@ -87,10 +95,14 @@ static const struct option longopts[] = {
 	{ "no-extend",   no_argument,       &opt::extend, 0 },
 	{ "scaffold",    no_argument,       &opt::scaffold, 1 },
 	{ "no-scaffold", no_argument,       &opt::scaffold, 0 },
-	{ "threads",     required_argument,	NULL, 'j' },
+	{ "threads",     required_argument, NULL, 'j' },
 	{ "verbose",     no_argument,       NULL, 'v' },
 	{ "help",        no_argument,       NULL, OPT_HELP },
 	{ "version",     no_argument,       NULL, OPT_VERSION },
+	{ "db",          required_argument, NULL, OPT_DB },
+	{ "library",     required_argument, NULL, OPT_LIBRARY },
+	{ "strain",      required_argument, NULL, OPT_STRAIN },
+	{ "species",     required_argument, NULL, OPT_SPECIES },
 	{ NULL, 0, NULL, 0 }
 };
 
@@ -100,6 +112,9 @@ static void generatePathsThroughEstimates(const Graph& g,
 
 int main(int argc, char** argv)
 {
+	if (!opt::db.empty())
+		opt::metaVars.resize(3);
+
 	bool die = false;
 	for (int c; (c = getopt_long(argc, argv,
 					shortopts, longopts, NULL)) != -1;) {
@@ -118,6 +133,17 @@ int main(int argc, char** argv)
 			case OPT_VERSION:
 				cout << VERSION_MESSAGE;
 				exit(EXIT_SUCCESS);
+			case OPT_DB:
+				arg >> opt::db;
+				break;
+			case OPT_LIBRARY:
+				arg >> opt::metaVars[0];
+				break;
+			case OPT_STRAIN:
+				arg >> opt::metaVars[1];
+				break;
+			case OPT_SPECIES:
+				arg >> opt::metaVars[2]; break;
 		}
 		if (optarg != NULL && !arg.eof()) {
 			cerr << PROGRAM ": invalid option: `-"
@@ -150,6 +176,14 @@ int main(int argc, char** argv)
 		exit(EXIT_FAILURE);
 	}
 
+	if (!opt::db.empty())
+		init(db,
+				opt::db,
+				opt::verbose,
+				PROGRAM,
+				opt::getCommand(argc, argv),
+				opt::metaVars);
+
 	string adjFile(argv[optind++]);
 	string estFile(argv[optind++]);
 
@@ -164,6 +198,11 @@ int main(int argc, char** argv)
 
 	if (opt::verbose > 0)
 		printGraphStats(cout, g);
+	if (!opt::db.empty()) {
+		addToDb(db, "K", opt::k);
+		addToDb(db, "V", (num_vertices(g) - num_vertices_removed(g)));
+		addToDb(db, "E", num_edges(g));
+	}
 
 	// try to find paths that match the distance estimates
 	generatePathsThroughEstimates(g, estFile);
@@ -677,6 +716,26 @@ static void generatePathsThroughEstimates(const Graph& g,
 		"Too many solutions: " << stats.tooManySolutions << "\n"
 		"Too complex: " << stats.tooComplex << "\n";
 
+	vector<int> vals = make_vector<int>()
+		<< stats.totalAttempted
+		<< stats.uniqueEnd
+		<< stats.noPossiblePaths
+		<< stats.noValidPaths
+		<< stats.repeat
+		<< stats.multiEnd
+		<< stats.tooManySolutions
+		<< stats.tooComplex;
+
+	vector<string> keys = make_vector<string>()
+		<< "stat_attempted_path_total"
+		<< "stat_unique_path"
+		<< "stat_impossible_path"
+		<< "stat_no_valid_path"
+		<< "stat_repetitive"
+		<< "stat_multi_valid_path"
+		<< "stat_too_many"
+		<< "stat_too_complex";
+
 	inStream.close();
 	outStream.close();
 
@@ -691,4 +750,17 @@ static void generatePathsThroughEstimates(const Graph& g,
 				"threshold paramter, n, to " << g_minNumPairsUsed
 				<< ".\n";
 	}
+
+	vals += make_vector<int>()
+		<< g_minNumPairs
+		<< g_minNumPairsUsed;
+
+	keys += make_vector<string>()
+		<< "minPairNum_DistanceEst"
+		<< "minPairNum_UsedInPath";
+
+	if (!opt::db.empty()) {
+		for (unsigned i=0; i<vals.size(); i++)
+			addToDb (db, keys[i], vals[i]);
+	}
 }
diff --git a/Unittest/Common/BitUtilTest.cpp b/Unittest/Common/BitUtilTest.cpp
index 311d16e..ed3a21f 100644
--- a/Unittest/Common/BitUtilTest.cpp
+++ b/Unittest/Common/BitUtilTest.cpp
@@ -1,5 +1,6 @@
 #include "Common/BitUtil.h"
 #include "gtest/gtest.h"
+#include <boost/utility/binary.hpp>
 
 /** Test limits */
 TEST(popcountTest, boundaries)
@@ -15,3 +16,232 @@ TEST(popcountTest, random_values)
 	EXPECT_EQ(45ULL, popcount(0x814BC5FFFFFFF7FULL));
 	EXPECT_EQ(46ULL, popcount(0x815BC5FFFFFFF7FULL));
 }
+
+TEST(readBitsTest, overwriteBits)
+{
+	// NOTE!: In the binary diagrams below, the rightmost bit of each byte
+	// is the LSB.
+
+	size_t bitSize, bitOffset;
+	char src[2];
+	char dest[4];
+
+	// SUBTEST: src size < 1 byte
+	//
+	// src             = 000
+	// bit offset      = 9
+	// dest            = 11111111 11111111 11111111 11111111
+	// expected result = 11111111 10001111 11111111 11111111
+
+	bitSize = 3;
+	bitOffset = 9;
+	memset(src, 0x00, 2);
+	memset(dest, 0xFF, 4);
+
+	std::istringstream in1(std::string(src, (bitSize + 7)/8));
+
+	readBits(in1, dest, bitSize, bitOffset);
+
+	EXPECT_EQ((char)0xFF, dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(10001111), dest[1]);
+	EXPECT_EQ((char)0xFF, dest[2]);
+	EXPECT_EQ((char)0xFF, dest[3]);
+
+	// SUBTEST: byte-aligned with partial last byte
+	//
+	// src             = 00000000 000
+	// bit offset      = 8
+	// dest            = 11111111 11111111 11111111 11111111
+	// expected result = 11111111 00000000 00011111 11111111
+
+	bitSize = 11;
+	bitOffset = 8;
+	memset(src, 0x00, 2);
+	memset(dest, 0xFF, 4);
+
+	std::istringstream in2(std::string(src, (bitSize + 7)/8));
+
+	readBits(in2, dest, bitSize, bitOffset);
+
+	EXPECT_EQ((char)0xFF, dest[0]);
+	EXPECT_EQ((char)0x00, dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(00011111), dest[2]);
+	EXPECT_EQ((char)0xFF, dest[3]);
+
+	// SUBTEST: not byte-aligned, src size > 1 byte
+	//
+	// src             = 00000000 00000000
+	// bit offset      = 4
+	// dest            = 11111111 11111111 11111111 11111111
+	// expected result = 11110000 00000000 00011111 11111111
+
+	bitSize = 15;
+	bitOffset = 4;
+	memset(src, 0x00, 2);
+	memset(dest, 0xFF, 4);
+
+	std::istringstream in3(std::string(src, (bitSize + 7)/8));
+
+	readBits(in3, dest, bitSize, bitOffset);
+
+	EXPECT_EQ((char)BOOST_BINARY(11110000), dest[0]);
+	EXPECT_EQ((char)0x00, dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(00011111), dest[2]);
+	EXPECT_EQ((char)0xFF, dest[3]);
+}
+
+TEST(readBitsTest, orBits)
+{
+	// NOTE!: In the binary diagrams below, the rightmost bit of each byte
+	// is the LSB.
+
+	size_t bitSize, bitOffset;
+	char src[2];
+	char dest[4];
+
+	// SUBTEST: src size < 1 byte
+	//
+	// src             = 101
+	// bit offset      = 9
+	// dest            = 10101010 10101010 10101010 10101010
+	// expected result = 10101010 11111010 10101010 10101010
+
+	bitSize = 3;
+	bitOffset = 9;
+	memset(src, 0x00, 2);
+	src[0] = BOOST_BINARY(10100000);
+	memset(dest, BOOST_BINARY(10101010), 4);
+
+	std::istringstream in1(std::string(src, (bitSize + 7)/8));
+
+	readBits(in1, dest, bitSize, bitOffset, BITWISE_OR);
+
+	EXPECT_EQ((char)BOOST_BINARY(10101010), dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(11111010), dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(10101010), dest[2]);
+	EXPECT_EQ((char)BOOST_BINARY(10101010), dest[3]);
+
+	// SUBTEST: byte-aligned with partial last byte
+	//
+	// src             = 01010101 010
+	// bit offset      = 8
+	// dest            = 10101010 10101010 10101010 10101010
+	// expected result = 10101010 11111111 11101010 10101010
+
+	bitSize = 11;
+	bitOffset = 8;
+	memset(src, 0x00, 2);
+	src[0] = BOOST_BINARY(01010101);
+	src[1] = BOOST_BINARY(01000000);
+	memset(dest, BOOST_BINARY(10101010), 4);
+
+	std::istringstream in2(std::string(src, (bitSize + 7)/8));
+
+	readBits(in2, dest, bitSize, bitOffset, BITWISE_OR);
+
+	EXPECT_EQ((char)BOOST_BINARY(10101010), dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(11101010), dest[2]);
+	EXPECT_EQ((char)BOOST_BINARY(10101010), dest[3]);
+
+	// SUBTEST: not byte-aligned, src size > 1 byte
+	//
+	// src             = 01010101 0101010
+	// bit offset      = 4
+	// dest            = 10101010 10101010 10101010 10101010
+	// expected result = 10101111 11111111 11101010 10101010
+
+	bitSize = 15;
+	bitOffset = 4;
+	memset(src, 0x00, 2);
+	src[0] = BOOST_BINARY(01010101);
+	src[1] = BOOST_BINARY(01010100);
+	memset(dest, BOOST_BINARY(10101010), 4);
+
+	std::istringstream in3(std::string(src, (bitSize + 7)/8));
+
+	readBits(in3, dest, bitSize, bitOffset, BITWISE_OR);
+
+	EXPECT_EQ((char)BOOST_BINARY(10101111), dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(11101010), dest[2]);
+	EXPECT_EQ((char)BOOST_BINARY(10101010), dest[3]);
+}
+
+TEST(readBitsTest, andBits)
+{
+	// NOTE!: In the binary diagrams below, the rightmost bit of each byte
+	// is the LSB.
+
+	size_t bitSize, bitOffset;
+	char src[2];
+	char dest[4];
+
+	// SUBTEST: src size < 1 byte
+	//
+	// src             = 101
+	// bit offset      = 9
+	// dest            = 11111111 11111111 11111111 11111111
+	// expected result = 11111111 11011111 11111111 11111111
+
+	bitSize = 3;
+	bitOffset = 9;
+	memset(src, 0x00, 2);
+	src[0] = BOOST_BINARY(10100000);
+	memset(dest, BOOST_BINARY(11111111), 4);
+
+	std::istringstream in1(std::string(src, (bitSize + 7)/8));
+
+	readBits(in1, dest, bitSize, bitOffset, BITWISE_AND);
+
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(11011111), dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[2]);
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[3]);
+
+	// SUBTEST: byte-aligned with partial last byte
+	//
+	// src             = 01010101 010
+	// bit offset      = 8
+	// dest            = 11111111 11111111 11111111 11111111
+	// expected result = 11111111 01010101 01011111 11111111
+
+	bitSize = 11;
+	bitOffset = 8;
+	memset(src, 0x00, 2);
+	src[0] = BOOST_BINARY(01010101);
+	src[1] = BOOST_BINARY(01000000);
+	memset(dest, BOOST_BINARY(11111111), 4);
+
+	std::istringstream in2(std::string(src, (bitSize + 7)/8));
+
+	readBits(in2, dest, bitSize, bitOffset, BITWISE_AND);
+
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(01010101), dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(01011111), dest[2]);
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[3]);
+
+	// SUBTEST: not byte-aligned, src size > 1 byte
+	//
+	// src             = 01010101 0101010
+	// bit offset      = 4
+	// dest            = 11111111 11111111 11111111 11111111
+	// expected result = 11110101 01010101 01011111 11111111
+
+	bitSize = 15;
+	bitOffset = 4;
+	memset(src, 0x00, 2);
+	src[0] = BOOST_BINARY(01010101);
+	src[1] = BOOST_BINARY(01010100);
+	memset(dest, BOOST_BINARY(11111111), 4);
+
+	std::istringstream in3(std::string(src, (bitSize + 7)/8));
+
+	readBits(in3, dest, bitSize, bitOffset, BITWISE_AND);
+
+	EXPECT_EQ((char)BOOST_BINARY(11110101), dest[0]);
+	EXPECT_EQ((char)BOOST_BINARY(01010101), dest[1]);
+	EXPECT_EQ((char)BOOST_BINARY(01011111), dest[2]);
+	EXPECT_EQ((char)BOOST_BINARY(11111111), dest[3]);
+}
diff --git a/Unittest/Common/StringUtilTest.cpp b/Unittest/Common/StringUtilTest.cpp
index 4ac4152..b321fd1 100644
--- a/Unittest/Common/StringUtilTest.cpp
+++ b/Unittest/Common/StringUtilTest.cpp
@@ -59,6 +59,35 @@ TEST(toSI_test, all_the_cases)
 	EXPECT_EQ("23.4 G", toSI(23440222111));
 }
 
+TEST(fromSI_test, all_the_cases)
+{
+	// zero values
+	EXPECT_EQ(0, fromSI("0"));
+	EXPECT_EQ(0, fromSI("0G"));
+
+	// negative values
+	EXPECT_EQ(-1.23e3, fromSI("-1.23k"));
+	EXPECT_EQ(-9.06e6, fromSI("-9.06M"));
+	EXPECT_EQ(-1.234e9, fromSI("-1.234G"));
+
+	// positive values
+	EXPECT_EQ(1.23e3, fromSI("1.23k"));
+	EXPECT_EQ(9.06e6, fromSI("9.06M"));
+	EXPECT_EQ(1.234e9, fromSI("1.234G"));
+}
+
+TEST(bytesToSI_test, all_the_cases)
+{
+	// zero values
+	EXPECT_EQ("0", bytesToSI(0));
+
+	// unit conversion
+	EXPECT_EQ("1", bytesToSI(1));
+	EXPECT_EQ("1k", bytesToSI(1024));
+	EXPECT_EQ("1M", bytesToSI(1048576UL));
+	EXPECT_EQ("1G", bytesToSI(1073741824UL));
+}
+
 template <typename T>
 class MultiTypes{
  public:
@@ -134,7 +163,6 @@ TEST(SIToBytes_test, unit_conversions)
 	EXPECT_EQ(1536u, SIToBytes("1.5k"));
 	EXPECT_EQ(1048576u, SIToBytes("1M"));
 	EXPECT_EQ(1073741824u, SIToBytes("1G"));
-	EXPECT_EQ(1099511627776u, SIToBytes("1T"));
 }
 
 TEST(SIToBytes_test, error_handling)
diff --git a/Unittest/DBG/LoadAlgorithmTest.cpp b/Unittest/DBG/LoadAlgorithmTest.cpp
new file mode 100644
index 0000000..8de2f39
--- /dev/null
+++ b/Unittest/DBG/LoadAlgorithmTest.cpp
@@ -0,0 +1,43 @@
+#include "Assembly/SequenceCollection.h"
+#include "Assembly/DBG.h"
+#include "Assembly/AssemblyAlgorithms.h"
+#include "Assembly/Options.h"
+#include "Common/UnorderedSet.h"
+
+#include <gtest/gtest.h>
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+TEST(LoadAlgorithmTest, base)
+{
+	typedef SequenceCollectionHash Graph;
+	Graph g;
+
+	opt::kmerSize = 5;
+	Kmer::setLength(5);
+
+	Sequence seq("TAATGCCA");
+
+	AssemblyAlgorithms::loadSequence(&g, seq);
+
+	unordered_set<Kmer> kmers, expectedKmers;
+
+	expectedKmers.insert(Kmer("TAATG"));
+	expectedKmers.insert(Kmer("AATGC"));
+	expectedKmers.insert(Kmer("ATGCC"));
+	expectedKmers.insert(Kmer("TGCCA"));
+
+	for (Graph::const_iterator it = g.begin();
+			it != g.end(); ++it) {
+		Kmer kmer(it->first);
+#if 0
+cerr << "visiting Kmer: " << kmer << "\n";
+#endif
+		ASSERT_TRUE(expectedKmers.find(kmer) != expectedKmers.end());
+		expectedKmers.erase(kmer);
+	}
+
+	ASSERT_TRUE(expectedKmers.empty());
+}
diff --git a/Unittest/Graph/AllPathsSearchTest.cpp b/Unittest/Graph/AllPathsSearchTest.cpp
index a7f337b..cccdc06 100644
--- a/Unittest/Graph/AllPathsSearchTest.cpp
+++ b/Unittest/Graph/AllPathsSearchTest.cpp
@@ -1,7 +1,6 @@
 #include "Graph/Path.h"
 #include "Graph/AllPathsSearch.h"
 #include "Common/UnorderedMap.h"
-#include "Common/Warnings.h"
 #include <boost/graph/adjacency_list.hpp>
 #include <gtest/gtest.h>
 #include <set>
diff --git a/Unittest/Graph/BidirectionalBFSTest.cpp b/Unittest/Graph/BidirectionalBFSTest.cpp
index 1717d9f..d2f54ab 100644
--- a/Unittest/Graph/BidirectionalBFSTest.cpp
+++ b/Unittest/Graph/BidirectionalBFSTest.cpp
@@ -2,7 +2,6 @@
 #include "Graph/BidirectionalBFS.h"
 #include "Graph/BidirectionalBFSVisitor.h"
 #include "Common/UnorderedMap.h"
-#include "Common/Warnings.h"
 #include <boost/graph/adjacency_list.hpp>
 #include <gtest/gtest.h>
 
@@ -33,78 +32,66 @@ public:
 
 	TestVisitor() : rank(0) { }
 
-	BFSVisitorResult discover_vertex(const Vertex& u, const Graph& g, Direction dir,
-		unsigned numFrontierNodes)
+	BFSVisitorResult discover_vertex(const Vertex& u, const Graph&, Direction dir,
+		unsigned)
 	{
 		if (DEBUG)
 			cerr << dir << ": discover_vertex " << u << "\n";
 
-		SUPPRESS_UNUSED_WARNING(g);
-		SUPPRESS_UNUSED_WARNING(numFrontierNodes);
 		return SUCCESS;
 	}
 
-	void examine_vertex(const Vertex& u, const Graph& g, Direction dir)
+	void examine_vertex(const Vertex& u, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": examine_vertex " << u << "\n";
 
-		SUPPRESS_UNUSED_WARNING(g);
 		dirMap[u] = dir;
 		rankMap[u] = rank++;
 	}
 
-	void examine_edge(const Edge& e, const Graph& g, Direction dir)
+	void examine_edge(const Edge& e, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": examine_edge " << e << "\n";
-
-		SUPPRESS_UNUSED_WARNING(g);
 	}
 
-	BFSVisitorResult tree_edge(const Edge& e, const Graph& g, Direction dir)
+	BFSVisitorResult tree_edge(const Edge& e, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": tree_edge " << e << "\n";
 
-		SUPPRESS_UNUSED_WARNING(g);
 		return SUCCESS;
 	}
 
-	BFSVisitorResult common_edge(const Edge& e, const Graph& g, Direction dir)
+	BFSVisitorResult common_edge(const Edge& e, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": common_edge " << e << "\n";
 
-		SUPPRESS_UNUSED_WARNING(g);
 		commonEdges.push_back(e);
 		return SUCCESS;
 	}
 
-	BFSVisitorResult non_tree_edge(const Edge& e, const Graph& g, Direction dir)
+	BFSVisitorResult non_tree_edge(const Edge& e, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": non_tree_edge " << e << "\n";
 
-		SUPPRESS_UNUSED_WARNING(g);
 		commonEdges.push_back(e);
 		return SUCCESS;
 	}
 
-	void gray_target(const Edge& e, const Graph& g, Direction dir)
+	void gray_target(const Edge& e, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": gray_target " << e << "\n";
-
-		SUPPRESS_UNUSED_WARNING(g);
 	}
 
-	void black_target(const Edge& e, const Graph& g, Direction dir)
+	void black_target(const Edge& e, const Graph&, Direction dir)
 	{
 		if (DEBUG)
 			cerr << dir << ": black_target " << e << "\n";
-
-		SUPPRESS_UNUSED_WARNING(g);
 	}
 
 };
diff --git a/Unittest/Graph/ConstrainedBidiBFSVisitorTest.cpp b/Unittest/Graph/ConstrainedBidiBFSVisitorTest.cpp
index bd00bd6..5d5690b 100644
--- a/Unittest/Graph/ConstrainedBidiBFSVisitorTest.cpp
+++ b/Unittest/Graph/ConstrainedBidiBFSVisitorTest.cpp
@@ -1,4 +1,3 @@
-#include "Common/Warnings.h"
 #include "Graph/Path.h"
 #include "Graph/ConstrainedBidiBFSVisitor.h"
 #include "Graph/BidirectionalBFS.h"
diff --git a/Unittest/Graph/ExtendPathTest.cpp b/Unittest/Graph/ExtendPathTest.cpp
new file mode 100644
index 0000000..63ad7d9
--- /dev/null
+++ b/Unittest/Graph/ExtendPathTest.cpp
@@ -0,0 +1,345 @@
+#include "Graph/Path.h"
+#include "Graph/ExtendPath.h"
+#include <boost/graph/adjacency_list.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+
+typedef boost::adjacency_list<boost::vecS, boost::vecS,
+	boost::bidirectionalS> Graph;
+
+// note: vertex_descriptor for adjacency_list<> is int
+typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
+// note: edge_descriptor for adjacency_list<> is int
+typedef boost::graph_traits<Graph>::edge_descriptor Edge;
+
+TEST(extendPath, lookAhead)
+{
+	unsigned depth;
+
+	/* case 1: simple path */
+
+	/*
+	 * 0--1--2
+	 */
+
+	Graph g1;
+	add_edge(0, 1, g1);
+	add_edge(1, 2, g1);
+
+	depth = 1;
+	ASSERT_TRUE(lookAhead(1, FORWARD, depth, g1));
+	ASSERT_TRUE(lookAhead(1, REVERSE, depth, g1));
+	ASSERT_FALSE(lookAhead(2, FORWARD, depth, g1));
+	ASSERT_FALSE(lookAhead(0, REVERSE, depth, g1));
+
+	depth = 2;
+	ASSERT_FALSE(lookAhead(1, FORWARD, depth, g1));
+	ASSERT_FALSE(lookAhead(1, REVERSE, depth, g1));
+	ASSERT_TRUE(lookAhead(0, FORWARD, depth, g1));
+	ASSERT_TRUE(lookAhead(2, REVERSE, depth, g1));
+
+	/* case 2: with branching */
+
+	/*
+	 *      2
+	 *     /
+	 * 0--1
+	 *     \
+	 *      3--4
+	 */
+
+	Graph g2;
+	add_edge(0, 1, g2);
+	add_edge(1, 2, g2);
+	add_edge(1, 3, g2);
+	add_edge(3, 4, g2);
+
+	depth = 3;
+	ASSERT_TRUE(lookAhead(0, FORWARD, depth, g2));
+
+	depth = 4;
+	ASSERT_FALSE(lookAhead(0, FORWARD, depth, g2));
+}
+
+TEST(extendPath, noExtension)
+{
+	// Graph containing a single edge.
+
+	Graph g;
+	add_edge(0, 1, g);
+	Path<Vertex> path;
+	path.push_back(0);
+	path.push_back(1);
+
+	extendPath(path, FORWARD, g);
+	ASSERT_EQ(2u, path.size());
+
+	extendPath(path, REVERSE, g);
+	ASSERT_EQ(2u, path.size());
+}
+
+TEST(extendPath, extendForward)
+{
+	/*
+	 *      2
+	 *     /
+	 * 0--1
+	 *     \
+	 *      3
+	 */
+
+	Graph g;
+	add_edge(0, 1, g);
+	add_edge(1, 2, g);
+	add_edge(1, 3, g);
+
+	Path<Vertex> expectedPath;
+	expectedPath.push_back(0);
+	expectedPath.push_back(1);
+
+	Path<Vertex> path;
+	path.push_back(0);
+	ASSERT_EQ(1u, path.size());
+
+	extendPath(path, FORWARD, g);
+	ASSERT_EQ(2u, path.size());
+	ASSERT_EQ(expectedPath, path);
+}
+
+TEST(extendPath, extendReverse)
+{
+	/*
+	 *  0
+	 *   \
+	 *    2--3
+	 *   /
+	 *  1
+	 */
+
+	Graph g;
+	add_edge(0, 2, g);
+	add_edge(1, 2, g);
+	add_edge(2, 3, g);
+
+	Path<Vertex> expectedPath;
+	expectedPath.push_back(2);
+	expectedPath.push_back(3);
+
+	Path<Vertex> path;
+	path.push_back(3);
+	ASSERT_EQ(1u, path.size());
+
+	extendPath(path, REVERSE, g);
+	ASSERT_EQ(2u, path.size());
+	ASSERT_EQ(expectedPath, path);
+}
+
+TEST(extendPath, bidirectional)
+{
+	/*
+	 *  0         5
+	 *   \       /
+	 *    2--3--4
+	 *   /       \
+	 *  1         6
+	 */
+
+	Graph g;
+	add_edge(0, 2, g);
+	add_edge(1, 2, g);
+	add_edge(2, 3, g);
+	add_edge(3, 4, g);
+	add_edge(4, 5, g);
+	add_edge(4, 6, g);
+
+	Path<Vertex> expectedPath;
+	expectedPath.push_back(2);
+	expectedPath.push_back(3);
+	expectedPath.push_back(4);
+
+	Path<Vertex> path;
+	path.push_back(3);
+	ASSERT_EQ(1u, path.size());
+
+	extendPath(path, FORWARD, g);
+	extendPath(path, REVERSE, g);
+	EXPECT_EQ(3u, path.size());
+	ASSERT_EQ(expectedPath, path);
+}
+
+TEST(extendPath, withTrimming)
+{
+	const unsigned trimLen = 1;
+
+	/*
+	 *       2
+	 *      /
+	 *  0--1--3--4
+	 */
+
+	Graph g;
+	add_edge(0, 1, g);
+	add_edge(1, 2, g);
+	add_edge(1, 3, g);
+	add_edge(3, 4, g);
+
+	Path<Vertex> expectedPath;
+	expectedPath.push_back(0);
+	expectedPath.push_back(1);
+	expectedPath.push_back(3);
+	expectedPath.push_back(4);
+
+	Path<Vertex> path;
+	path.push_back(0);
+
+	extendPath(path, FORWARD, g, trimLen);
+	ASSERT_EQ(4u, path.size());
+	ASSERT_EQ(expectedPath, path);
+
+	/*
+	 *       2  4
+	 *      /  /
+	 *  0--1--3
+	 *         \
+	 *          5
+	 */
+
+	Graph g2;
+	add_edge(0, 1, g2);
+	add_edge(1, 2, g2);
+	add_edge(1, 3, g2);
+	add_edge(3, 4, g2);
+	add_edge(3, 5, g2);
+
+	Path<Vertex> expectedPath2;
+	expectedPath2.push_back(0);
+	expectedPath2.push_back(1);
+	expectedPath2.push_back(3);
+
+	Path<Vertex> path2;
+	path2.push_back(0);
+
+	extendPath(path2, FORWARD, g2, trimLen);
+	EXPECT_EQ(3u, path2.size());
+	ASSERT_EQ(expectedPath2, path2);
+}
+
+TEST(extendPath, cycles)
+{
+	PathExtensionResult result;
+
+	/*
+	 * 2---1
+	 *  \ /
+	 *   0
+	 */
+
+	Graph g;
+	add_edge(0, 1, g);
+	add_edge(1, 2, g);
+	add_edge(2, 0, g);
+
+	Path<Vertex> pathForward;
+	pathForward.push_back(0);
+
+	Path<Vertex> expectedPathForward;
+	expectedPathForward.push_back(0);
+	expectedPathForward.push_back(1);
+	expectedPathForward.push_back(2);
+
+	result = extendPath(pathForward, FORWARD, g);
+	EXPECT_EQ(EXTENDED_TO_CYCLE, result);
+	EXPECT_EQ(expectedPathForward, pathForward);
+
+	Path<Vertex> pathReverse;
+	pathReverse.push_back(0);
+
+	Path<Vertex> expectedPathReverse;
+	expectedPathReverse.push_back(1);
+	expectedPathReverse.push_back(2);
+	expectedPathReverse.push_back(0);
+
+	result = extendPath(pathReverse, REVERSE, g);
+	EXPECT_EQ(EXTENDED_TO_CYCLE, result);
+	EXPECT_EQ(expectedPathReverse, pathReverse);
+
+	/*
+	 *   3---2
+	 *    \ /
+	 * 0---1
+	 */
+
+	Graph g2;
+	add_edge(0, 1, g2);
+	add_edge(1, 2, g2);
+	add_edge(2, 3, g2);
+	add_edge(3, 1, g2);
+
+	Path<Vertex> path2;
+	path2.push_back(0);
+
+	Path<Vertex> expectedPath2;
+	expectedPath2.push_back(0);
+	expectedPath2.push_back(1);
+	expectedPath2.push_back(2);
+	expectedPath2.push_back(3);
+
+	result = extendPath(path2, FORWARD, g2);
+	EXPECT_EQ(EXTENDED_TO_CYCLE, result);
+	EXPECT_EQ(expectedPath2, path2);
+
+	/*
+	 * 2---3
+	 *  \ /
+	 *   1---0
+	 */
+
+	Graph g3;
+	add_edge(1, 0, g3);
+	add_edge(2, 1, g3);
+	add_edge(3, 2, g3);
+	add_edge(1, 3, g3);
+
+	Path<Vertex> path3;
+	path3.push_back(0);
+
+	Path<Vertex> expectedPath3;
+	expectedPath3.push_back(3);
+	expectedPath3.push_back(2);
+	expectedPath3.push_back(1);
+	expectedPath3.push_back(0);
+
+	result = extendPath(path3, REVERSE, g3);
+	EXPECT_EQ(EXTENDED_TO_CYCLE, result);
+	EXPECT_EQ(expectedPath3, path3);
+}
+
+TEST(extendPath, cyclesAndBranches)
+{
+	PathExtensionResult result;
+
+	/*
+	 *     2
+	 *    //
+	 * 0--1--3--4
+	 */
+
+	Graph g;
+	add_edge(0, 1, g);
+	add_edge(1, 2, g);
+	add_edge(2, 1, g);
+	add_edge(1, 3, g);
+	add_edge(3, 4, g);
+
+	Path<Vertex> path;
+	path.push_back(0);
+
+	Path<Vertex> expectedPath;
+	expectedPath.push_back(0);
+	expectedPath.push_back(1);
+
+	result = extendPath(path, FORWARD, g);
+	EXPECT_EQ(EXTENDED_TO_BRANCHING_POINT, result);
+	EXPECT_EQ(expectedPath, path);
+}
diff --git a/Unittest/Konnector/BloomFilter.cc b/Unittest/Konnector/BloomFilter.cc
index d326946..43e4873 100644
--- a/Unittest/Konnector/BloomFilter.cc
+++ b/Unittest/Konnector/BloomFilter.cc
@@ -3,6 +3,7 @@
 #include "Bloom/CascadingBloomFilter.h"
 #include "Bloom/BloomFilterWindow.h"
 #include "Bloom/CascadingBloomFilterWindow.h"
+#include "Common/BitUtil.h"
 
 #include <gtest/gtest.h>
 #include <string>
@@ -99,7 +100,7 @@ TEST(BloomFilter, union_)
 
 	ss >> unionBloom;
 	ASSERT_TRUE(ss.good());
-	unionBloom.read(ss, Bloom::LOAD_UNION);
+	unionBloom.read(ss, BITWISE_OR);
 	ASSERT_TRUE(ss.good());
 
 	EXPECT_EQ(unionBloom.size(), bits);
@@ -140,7 +141,7 @@ TEST(BloomFilter, intersect)
 
 	ss >> intersectBloom;
 	ASSERT_TRUE(ss.good());
-	intersectBloom.read(ss, Bloom::LOAD_INTERSECT);
+	intersectBloom.read(ss, BITWISE_AND);
 	ASSERT_TRUE(ss.good());
 
 	EXPECT_EQ(intersectBloom.size(), bits);
@@ -151,7 +152,7 @@ TEST(BloomFilter, intersect)
 
 TEST(CascadingBloomFilter, base)
 {
-	CascadingBloomFilter x(100);
+	CascadingBloomFilter x(100, 2);
 	EXPECT_EQ(x.size(), 100U);
 
 	Kmer::setLength(16);
@@ -183,30 +184,6 @@ TEST(CascadingBloomFilter, base)
 	EXPECT_FALSE(x[d]);
 }
 
-TEST(BloomFilter, shrink)
-{
-	BloomFilter big(10);
-	BloomFilter small;
-
-	big.insert(1);
-	big.insert(8);
-
-	EXPECT_EQ(2U, big.popcount());
-	EXPECT_TRUE(big[1]);
-	EXPECT_TRUE(big[8]);
-
-	stringstream ss;
-	ss << big;
-	ASSERT_TRUE(ss.good());
-	small.read(ss, Bloom::LOAD_OVERWRITE, 2);
-	ASSERT_TRUE(ss.good());
-
-	EXPECT_EQ(5U, small.size());
-	EXPECT_EQ(2U, small.popcount());
-	EXPECT_TRUE(small[1]);
-	EXPECT_TRUE(small[3]);
-}
-
 TEST(BloomFilter, windowSerialization)
 {
 	size_t bits = 100;
@@ -264,7 +241,7 @@ TEST(BloomFilter, windowUnion)
 	BloomFilter unionBloom;
 	ss >> unionBloom;
 	ASSERT_TRUE(ss.good());
-	unionBloom.read(ss, Bloom::LOAD_UNION);
+	unionBloom.read(ss, BITWISE_OR);
 	ASSERT_TRUE(ss.good());
 
 	EXPECT_EQ(2U, unionBloom.popcount());
@@ -279,7 +256,7 @@ TEST(CascadingBloomFilter, window)
 	size_t pos2 = 80;
 	size_t pos3 = 50;
 
-	CascadingBloomFilter CascadingBloom(bits);
+	CascadingBloomFilter CascadingBloom(bits, 2);
 
 	// set a bit in both halves of the second level
 	// bloom filter
@@ -293,11 +270,11 @@ TEST(CascadingBloomFilter, window)
 	EXPECT_TRUE(CascadingBloom[pos2]);
 	EXPECT_EQ(2U, CascadingBloom.getBloomFilter(1).popcount());
 
-	CascadingBloomFilterWindow window1(bits, 0, bits/2 - 1);
+	CascadingBloomFilterWindow window1(bits, 0, bits/2 - 1, 2);
 	window1.insert(pos1);
 	window1.insert(pos1);
 
-	CascadingBloomFilterWindow window2(bits, bits/2, bits - 1);
+	CascadingBloomFilterWindow window2(bits, bits/2, bits - 1, 2);
 	window2.insert(pos2);
 	window2.insert(pos2);
 
@@ -313,7 +290,7 @@ TEST(CascadingBloomFilter, window)
 	BloomFilter unionBloom;
 	ss >> unionBloom;
 	ASSERT_TRUE(ss.good());
-	unionBloom.read(ss, Bloom::LOAD_UNION);
+	unionBloom.read(ss, BITWISE_OR);
 	ASSERT_TRUE(ss.good());
 
 	EXPECT_EQ(2U, unionBloom.popcount());
diff --git a/Unittest/Konnector/DBGBloomAlgorithmsTest.cpp b/Unittest/Konnector/DBGBloomAlgorithmsTest.cpp
index 7646977..93be30f 100644
--- a/Unittest/Konnector/DBGBloomAlgorithmsTest.cpp
+++ b/Unittest/Konnector/DBGBloomAlgorithmsTest.cpp
@@ -7,15 +7,25 @@
 
 using namespace std;
 
-/**
- * Test fixture for the getStartKmerPos function.
+/*
+ * Tests for getStartKmerPos() function, which does
+ * the following:
  *
- * getStartKmerPos chooses the kmer at the
- * beginning of the longest series kmer matches with
- * within the read.  In the case where there are
- * two equal-length series of matches,
- * getStartKmerPos choose the kmer position closest
- * to the beginning (5' end) of the read.
+ * Choose a suitable starting kmer for a path search and
+ * return its position. More specifically, find the kmer
+ * closest to the end of the given sequence that is followed by
+ * at least (numMatchesThreshold - 1) consecutive kmers that
+ * are also present in the Bloom filter de Bruijn graph. If there
+ * is no sequence of matches of length numMatchesThreshold,
+ * use the longest sequence of matching kmers instead.
+ *
+ * @param seq sequence in which to find start kmer
+ * @param k kmer size
+ * @param g de Bruijn graph
+ * @param numMatchesThreshold if we encounter a sequence
+ * of numMatchesThreshold consecutive kmers in the Bloom filter,
+ * choose the kmer at the beginning of that sequence
+ * @return position of chosen start kmer
  */
 class GetStartKmerPosTest : public testing::Test {
 
@@ -38,10 +48,10 @@ TEST_F(GetStartKmerPosTest, FullReadMatch)
 	BloomFilter bloom(bloomFilterSize);
 	Bloom::loadSeq(bloom, k, testRead.seq);
 	DBGBloom<BloomFilter> g(bloom);
+	const unsigned numMatchesThreshold = 1;
 
-	EXPECT_EQ(0U, getStartKmerPos(k, testRead, g, false, true));
-	// true indicates revese complement (second read)
-	EXPECT_EQ(0U, getStartKmerPos(k, testRead, g, true, true));
+	EXPECT_EQ(5U, getStartKmerPos(testRead, k, FORWARD, g,
+		numMatchesThreshold));
 }
 
 TEST_F(GetStartKmerPosTest, FullReadMismatch)
@@ -50,10 +60,10 @@ TEST_F(GetStartKmerPosTest, FullReadMismatch)
 	// Leave the bloom filter empty to generate a mismatch
 	// for every kmer in the read.
 	DBGBloom<BloomFilter> g(bloom);
-	EXPECT_EQ(NO_MATCH, getStartKmerPos(k, testRead, g, false, true));
+	EXPECT_EQ(NO_MATCH, getStartKmerPos(testRead, k, FORWARD, g));
 }
 
-TEST_F(GetStartKmerPosTest, SelectLongestMatchRegion)
+TEST_F(GetStartKmerPosTest, NumMatchesThreshold)
 {
 	const string& seq = testRead.seq;
 	BloomFilter bloom(bloomFilterSize);
@@ -67,10 +77,31 @@ TEST_F(GetStartKmerPosTest, SelectLongestMatchRegion)
 		Bloom::loadSeq(bloom, k, seq.substr(i,k));
 	}
 
-	EXPECT_EQ(2U, getStartKmerPos(k, testRead, g, false, true));
-	// true indicates revese complement (second read)
-	EXPECT_EQ(getStartKmerPos(k, testRead, g),
-		getStartKmerPos(k, testRead, g, true));
+	unsigned numMatchesThreshold;
+
+	numMatchesThreshold = 1;
+	EXPECT_EQ(5U, getStartKmerPos(testRead, k, FORWARD, g,
+		numMatchesThreshold));
+
+	numMatchesThreshold = 2;
+	EXPECT_EQ(2U, getStartKmerPos(testRead, k, FORWARD, g,
+		numMatchesThreshold));
+
+	numMatchesThreshold = 3;
+	EXPECT_EQ(2U, getStartKmerPos(testRead, k, FORWARD, g,
+		numMatchesThreshold));
+
+	numMatchesThreshold = 1;
+	EXPECT_EQ(0U, getStartKmerPos(testRead, k, REVERSE, g,
+		numMatchesThreshold));
+
+	numMatchesThreshold = 2;
+	EXPECT_EQ(3U, getStartKmerPos(testRead, k, REVERSE, g,
+		numMatchesThreshold));
+
+	numMatchesThreshold = 3;
+	EXPECT_EQ(3U, getStartKmerPos(testRead, k, REVERSE, g,
+		numMatchesThreshold));
 }
 
 TEST_F(GetStartKmerPosTest, EqualLengthMatchRegions)
@@ -87,9 +118,15 @@ TEST_F(GetStartKmerPosTest, EqualLengthMatchRegions)
 		Bloom::loadSeq(bloom, k, seq.substr(i,k));
 	}
 
-	EXPECT_EQ(1U, getStartKmerPos(k, testRead, g, false, true));
-	// true indicates revese complement (second read)
-	EXPECT_EQ(1U, getStartKmerPos(k, testRead, g, true, true));
+	unsigned numMatchesThreshold;
+
+	numMatchesThreshold = 2;
+	EXPECT_EQ(4U, getStartKmerPos(testRead, k, FORWARD, g,
+		numMatchesThreshold));
+
+	numMatchesThreshold = 2;
+	EXPECT_EQ(2U, getStartKmerPos(testRead, k, REVERSE, g,
+		numMatchesThreshold));
 }
 
 class CorrectSingleBaseErrorTest : public testing::Test {
diff --git a/Unittest/Konnector/DBGBloomTest.cpp b/Unittest/Konnector/DBGBloomTest.cpp
index e746902..8937209 100644
--- a/Unittest/Konnector/DBGBloomTest.cpp
+++ b/Unittest/Konnector/DBGBloomTest.cpp
@@ -15,7 +15,7 @@ TEST(DBGBloom, BloomFilterPolymorphism)
 	 Kmer kmer2("ACC");
 	  Kmer kmer3("CCA");
 
-	CascadingBloomFilter countingBloom(bits);
+	CascadingBloomFilter countingBloom(bits, 2);
 
 	countingBloom.insert(kmer1);
 	countingBloom.insert(kmer1);
diff --git a/Unittest/Konnector/integration-tests.mk b/Unittest/Konnector/integration-tests.mk
index 0b4dfb2..18e9c07 100755
--- a/Unittest/Konnector/integration-tests.mk
+++ b/Unittest/Konnector/integration-tests.mk
@@ -353,13 +353,13 @@ abyss_bloom_multithreaded_test: $(tmpdir) $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq
 #------------------------------------------------------------
 
 konnector_multithreaded_test: $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq
-	/usr/bin/time -v $(konnector) $(cp_opts) -o $(tmpdir)/e$e_singlethreaded \
-		$(CP_OPTS) -j1 $^
+	/usr/bin/time -v $(konnector) $(k_opts) -o $(tmpdir)/e$e_singlethreaded \
+		$(K_OPTS) -j1 $^
 	cat $(tmpdir)/e$e_singlethreaded_merged.fa | \
 		paste - - | sort | tr '\t' '\n' \
 		> $(tmpdir)/e$e_singlethreaded_merged.sorted.fa
-	/usr/bin/time -v $(konnector) $(cp_opts) -o $(tmpdir)/e$e_multithreaded \
-		$(CP_OPTS) -j10 $^
+	/usr/bin/time -v $(konnector) $(k_opts) -o $(tmpdir)/e$e_multithreaded \
+		$(K_OPTS) -j10 $^
 	cat $(tmpdir)/e$e_multithreaded_merged.fa | \
 		paste - - | sort | tr '\t' '\n' \
 		> $(tmpdir)/e$e_multithreaded_merged.sorted.fa
diff --git a/Unittest/Makefile.am b/Unittest/Makefile.am
index 6726b5e..d0e41d4 100644
--- a/Unittest/Makefile.am
+++ b/Unittest/Makefile.am
@@ -1,109 +1,210 @@
-UNIT_TESTS = common_stringutil
+GTEST_LIBS_ = $(top_builddir)/lib/gtest-1.7.0/libgtest_main.a
+# -Wno-error is used here because there is no portable way
+# to suppress warning: "argument unused during compilation: '-pthread'"
+# for clang on OSX.
+# See: http://stackoverflow.com/questions/17841140/os-x-clang-pthread
+GTEST_CXXFLAGS_ = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS) -Wno-error
+GTEST_INCLUDES_ = -I$(top_srcdir) -I$(top_srcdir)/lib/gtest-1.7.0/include
+GTEST_LDFLAGS_ = $(PTHREAD_LIBS)
+
 check_PROGRAMS = common_stringutil
 common_stringutil_SOURCES = Common/StringUtilTest.cpp
-common_stringutil_CPPFLAGS = -I$(top_srcdir)
-common_stringutil_LDADD = $(GTEST_LIBS)
+common_stringutil_CPPFLAGS = $(GTEST_INCLUDES_)
+common_stringutil_LDADD = $(GTEST_LIBS_)
+common_stringutil_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_stringutil_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += common_histogram
 check_PROGRAMS += common_histogram
 common_histogram_SOURCES = Common/HistogramTest.cpp
-common_histogram_CPPFLAGS = -I$(top_srcdir)
-common_histogram_LDADD = $(GTEST_LIBS)
+common_histogram_CPPFLAGS = $(GTEST_INCLUDES_)
+common_histogram_LDADD = $(GTEST_LIBS_)
+common_histogram_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_histogram_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += common_bitutil
 check_PROGRAMS += common_bitutil
 common_bitutil_SOURCES = Common/BitUtilTest.cpp
-common_bitutil_CPPFLAGS = -I$(top_srcdir)
-common_bitutil_LDADD = $(GTEST_LIBS)
+common_bitutil_CPPFLAGS = $(GTEST_INCLUDES_)
+common_bitutil_LDADD = $(GTEST_LIBS_)
+common_bitutil_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_bitutil_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += common_kmer
 check_PROGRAMS += common_kmer
 common_kmer_SOURCES = Common/KmerTest.cpp
-common_kmer_CPPFLAGS = -I$(top_srcdir)
-common_kmer_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+common_kmer_CPPFLAGS = $(GTEST_INCLUDES_)
+common_kmer_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+common_kmer_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_kmer_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += common_sequence
 check_PROGRAMS += common_sequence
 common_sequence_SOURCES = Common/Sequence.cc
-common_sequence_CPPFLAGS = -I$(top_srcdir)
-common_sequence_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+common_sequence_CPPFLAGS = $(GTEST_INCLUDES_)
+common_sequence_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+common_sequence_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_sequence_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += common_KmerIterator
 check_PROGRAMS += common_KmerIterator
 common_KmerIterator_SOURCES = Common/KmerIteratorTest.cpp
-common_KmerIterator_CPPFLAGS = -I$(top_srcdir)
-common_KmerIterator_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+common_KmerIterator_CPPFLAGS = $(GTEST_INCLUDES_)
+common_KmerIterator_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+common_KmerIterator_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_KmerIterator_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += common_sam
 check_PROGRAMS += common_sam
 common_sam_SOURCES = Common/SAM.cc
-common_sam_CPPFLAGS = -I$(top_srcdir)
-common_sam_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+common_sam_CPPFLAGS = $(GTEST_INCLUDES_)
+common_sam_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+common_sam_CXXFLAGS = $(GTEST_CXXFLAGS_)
+common_sam_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += BloomFilter
 check_PROGRAMS += BloomFilter
 BloomFilter_SOURCES = Konnector/BloomFilter.cc
-BloomFilter_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-BloomFilter_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
-BloomFilter_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+BloomFilter_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+BloomFilter_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+BloomFilter_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+BloomFilter_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += Konnector_DBGBloom
 check_PROGRAMS += Konnector_DBGBloom
 Konnector_DBGBloom_SOURCES = Konnector/DBGBloomTest.cpp
-Konnector_DBGBloom_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-Konnector_DBGBloom_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
-Konnector_DBGBloom_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+Konnector_DBGBloom_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+Konnector_DBGBloom_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+Konnector_DBGBloom_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+Konnector_DBGBloom_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += Konnector_DBGBloomAlgorithms
 check_PROGRAMS += Konnector_DBGBloomAlgorithms
 Konnector_DBGBloomAlgorithms_SOURCES = Konnector/DBGBloomAlgorithmsTest.cpp
-Konnector_DBGBloomAlgorithms_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-Konnector_DBGBloomAlgorithms_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
+Konnector_DBGBloomAlgorithms_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+Konnector_DBGBloomAlgorithms_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
 Konnector_DBGBloomAlgorithms_LDADD = \
 	$(top_builddir)/Common/libcommon.a \
-	$(GTEST_LIBS)
+	$(GTEST_LIBS_)
+Konnector_DBGBloomAlgorithms_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += graph_ConstrainedBFSVisitor
 check_PROGRAMS += graph_ConstrainedBFSVisitor
 graph_ConstrainedBFSVisitor_SOURCES = Graph/ConstrainedBFSVisitorTest.cpp
-graph_ConstrainedBFSVisitor_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-graph_ConstrainedBFSVisitor_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+graph_ConstrainedBFSVisitor_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+graph_ConstrainedBFSVisitor_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+graph_ConstrainedBFSVisitor_CXXFLAGS = $(GTEST_CXXFLAGS_)
+graph_ConstrainedBFSVisitor_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += graph_BidirectionalBFS
 check_PROGRAMS += graph_BidirectionalBFS
 graph_BidirectionalBFS_SOURCES = Graph/BidirectionalBFSTest.cpp
-graph_BidirectionalBFS_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-graph_BidirectionalBFS_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+graph_BidirectionalBFS_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+graph_BidirectionalBFS_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+graph_BidirectionalBFS_CXXFLAGS = $(GTEST_CXXFLAGS_)
+graph_BidirectionalBFS_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += graph_AllPathsSearch
 check_PROGRAMS += graph_AllPathsSearch
 graph_AllPathsSearch_SOURCES = Graph/AllPathsSearchTest.cpp
-graph_AllPathsSearch_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-graph_AllPathsSearch_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+graph_AllPathsSearch_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+graph_AllPathsSearch_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+graph_AllPathsSearch_CXXFLAGS = $(GTEST_CXXFLAGS_)
+graph_AllPathsSearch_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += graph_HashGraph
 check_PROGRAMS += graph_HashGraph
 graph_HashGraph_SOURCES = Graph/HashGraphTest.cpp
-graph_HashGraph_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-graph_HashGraph_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+graph_HashGraph_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+graph_HashGraph_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+graph_HashGraph_CXXFLAGS = $(GTEST_CXXFLAGS_)
+graph_HashGraph_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += graph_ConstrainedBidiBFSVisitor
 check_PROGRAMS += graph_ConstrainedBidiBFSVisitor
 graph_ConstrainedBidiBFSVisitor_SOURCES = \
 	Graph/ConstrainedBidiBFSVisitorTest.cpp
-graph_ConstrainedBidiBFSVisitor_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-graph_ConstrainedBidiBFSVisitor_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
+graph_ConstrainedBidiBFSVisitor_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+graph_ConstrainedBidiBFSVisitor_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+graph_ConstrainedBidiBFSVisitor_CXXFLAGS = $(GTEST_CXXFLAGS_)
+graph_ConstrainedBidiBFSVisitor_LDFLAGS = $(GTEST_LDFLAGS_)
+
+check_PROGRAMS += graph_ExtendPath
+graph_ExtendPath_SOURCES = Graph/ExtendPathTest.cpp
+graph_ExtendPath_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
+graph_ExtendPath_LDADD = $(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+graph_ExtendPath_CXXFLAGS = $(GTEST_CXXFLAGS_)
+graph_ExtendPath_LDFLAGS = $(GTEST_LDFLAGS_)
 
-UNIT_TESTS += Konnector_konnector
 check_PROGRAMS += Konnector_konnector
 Konnector_konnector_SOURCES = \
 	Konnector/konnectorTest.cpp
-Konnector_konnector_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common
-Konnector_konnector_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
+Konnector_konnector_CPPFLAGS = $(GTEST_INCLUDES_) -I$(top_srcdir)/Common
 Konnector_konnector_LDADD = \
 	$(top_builddir)/Align/libalign.a \
-	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS)
-
-##Tests for log kmer counting / Counting bloom filter
-
-TESTS = $(UNIT_TESTS)
+	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+Konnector_konnector_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+Konnector_konnector_LDFLAGS = $(GTEST_LDFLAGS_)
+
+check_PROGRAMS += DBG_LoadAlgorithm
+DBG_LoadAlgorithm_SOURCES = \
+	DBG/LoadAlgorithmTest.cpp
+DBG_LoadAlgorithm_CPPFLAGS = \
+	$(GTEST_INCLUDES_) \
+	-I$(top_srcdir)/DataLayer \
+	-I$(top_srcdir)/Common
+DBG_LoadAlgorithm_LDADD = \
+	$(top_builddir)/Assembly/libassembly.a \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+DBG_LoadAlgorithm_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+DBG_LoadAlgorithm_LDFLAGS = $(GTEST_LDFLAGS_)
+
+if PAIRED_DBG
+
+check_PROGRAMS += PairedDBG_LoadAlgorithm
+PairedDBG_LoadAlgorithm_SOURCES = \
+	PairedDBG/LoadAlgorithmTest.cpp
+PairedDBG_LoadAlgorithm_CPPFLAGS = \
+	$(GTEST_INCLUDES_) \
+	-I$(top_srcdir)/DataLayer \
+	-I$(top_srcdir)/Common
+PairedDBG_LoadAlgorithm_LDADD = \
+	$(top_builddir)/PairedDBG/libpaireddbg.a \
+	$(top_builddir)/Assembly/libassembly.a \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+PairedDBG_LoadAlgorithm_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+PairedDBG_LoadAlgorithm_LDFLAGS = $(GTEST_LDFLAGS_)
+
+check_PROGRAMS += PairedDBG_KmerPair
+PairedDBG_KmerPair_SOURCES = \
+	PairedDBG/KmerPairTest.cc
+PairedDBG_KmerPair_CPPFLAGS = \
+	$(GTEST_INCLUDES_) \
+	-I$(top_srcdir)/DataLayer \
+	-I$(top_srcdir)/Common
+PairedDBG_KmerPair_LDADD = \
+	$(top_builddir)/PairedDBG/libpaireddbg.a \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+PairedDBG_KmerPair_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+PairedDBG_KmerPair_LDFLAGS = $(GTEST_LDFLAGS_)
+
+check_PROGRAMS += PairedDBG_Dinuc
+PairedDBG_Dinuc_SOURCES = \
+	PairedDBG/DinucTest.cc
+PairedDBG_Dinuc_CPPFLAGS = \
+	$(GTEST_INCLUDES_) \
+	-I$(top_srcdir)/DataLayer \
+	-I$(top_srcdir)/Common
+PairedDBG_Dinuc_LDADD = \
+	$(top_builddir)/PairedDBG/libpaireddbg.a \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+PairedDBG_Dinuc_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS)
+PairedDBG_Dinuc_LDFLAGS = $(GTEST_LDFLAGS_)
+
+check_PROGRAMS += PairedDBG_BranchRecord
+PairedDBG_BranchRecord_SOURCES = \
+	PairedDBG/BranchRecordTest.cpp
+PairedDBG_BranchRecord_CPPFLAGS = \
+	$(GTEST_INCLUDES_) \
+	-I$(top_srcdir)/DataLayer \
+	-I$(top_srcdir)/Common
+PairedDBG_BranchRecord_LDADD = \
+	$(top_builddir)/PairedDBG/libpaireddbg.a \
+	$(top_builddir)/DataLayer/libdatalayer.a \
+	$(top_builddir)/Common/libcommon.a $(GTEST_LIBS_)
+PairedDBG_BranchRecord_CXXFLAGS = $(GTEST_CXXFLAGS_) $(OPENMP_CXXFLAGS)
+PairedDBG_BranchRecord_LDFLAGS = $(GTEST_LDFLAGS_)
+
+endif # PAIRED_DBG
+
+TESTS = $(check_PROGRAMS)
diff --git a/Unittest/PairedDBG/BranchRecordTest.cpp b/Unittest/PairedDBG/BranchRecordTest.cpp
new file mode 100644
index 0000000..c848271
--- /dev/null
+++ b/Unittest/PairedDBG/BranchRecordTest.cpp
@@ -0,0 +1,58 @@
+#include "Assembly/Options.h"
+#include "Common/Options.h"
+#include "PairedDBG/SequenceCollection.h"
+
+#include <gtest/gtest.h>
+#include <vector>
+
+using namespace std;
+
+TEST(BranchRecordTest, Sequence)
+{
+	// length of each kmer in kmer pair
+	Kmer::setLength(2);
+	// space between kmer pair
+	unsigned delta = 2;
+	// the length of both kmers plus the gap
+	KmerPair::setLength(Kmer::length() * 2 + delta);
+
+	// sequence for branch: TAGGGATT	
+	// kmer pairs:          TA  GA
+	//                       AG  AT
+	//                        GG  TT
+
+	std::pair<KmerPair,KmerPairData>
+		kmerPair1(KmerPair("TA", "GA"), KmerPairData()),
+		kmerPair2(KmerPair("AG", "AT"), KmerPairData()),
+		kmerPair3(KmerPair("GG", "TT"), KmerPairData());
+		
+	// test sequence reconstruction in forward dir
+
+	BranchRecord forwardBranch(SENSE);
+	forwardBranch.push_back(kmerPair1);
+	forwardBranch.push_back(kmerPair2);
+	forwardBranch.push_back(kmerPair3);
+	ASSERT_EQ("TAGGGATT", (Sequence)forwardBranch);
+
+	// test sequence reconstruction in reverse dir
+
+	BranchRecord reverseBranch(ANTISENSE);
+	reverseBranch.push_back(kmerPair3);
+	reverseBranch.push_back(kmerPair2);
+	reverseBranch.push_back(kmerPair1);
+	ASSERT_EQ("TAGGGATT", (Sequence)reverseBranch);
+	
+	// test sequence reconstruction with "N"s (forward dir)
+
+	BranchRecord shortBranchForward(SENSE);
+	shortBranchForward.push_back(kmerPair1);
+	shortBranchForward.push_back(kmerPair2);
+	ASSERT_EQ("TAGNGAT", (Sequence)shortBranchForward);
+	
+	// test sequence reconstruction with "N"s (reverse dir)
+
+	BranchRecord shortBranchReverse(ANTISENSE);
+	shortBranchReverse.push_back(kmerPair2);
+	shortBranchReverse.push_back(kmerPair1);
+	ASSERT_EQ("TAGNGAT", (Sequence)shortBranchReverse);
+}
diff --git a/Unittest/PairedDBG/DinucTest.cc b/Unittest/PairedDBG/DinucTest.cc
new file mode 100644
index 0000000..b62317e
--- /dev/null
+++ b/Unittest/PairedDBG/DinucTest.cc
@@ -0,0 +1,82 @@
+#include "PairedDBG/Dinuc.h"
+
+#include <gtest/gtest.h>
+
+using namespace std;
+
+const uint8_t A(0), C(1), G(2), T(3);
+
+bool operator==(const Dinuc& a, const Dinuc& b)
+{
+	return a.toInt() == b.toInt();
+}
+
+TEST(Dinuc, Dinuc)
+{
+	uint8_t CG = C | G << 2;
+	Dinuc cg1(C, G);
+	Dinuc cg2(CG);
+
+	EXPECT_EQ(cg1, cg2);
+	EXPECT_EQ(cg1.toInt(), CG);
+	EXPECT_EQ(cg1.a(), C);
+	EXPECT_EQ(cg1.b(), G);
+
+	uint8_t GG = G | G << 2;
+	++cg2;
+	Dinuc gg(GG);
+	EXPECT_EQ(cg2, gg);
+	EXPECT_TRUE(cg1 < gg);
+
+	Dinuc gc(G, C);
+	EXPECT_EQ(cg1, cg1.reverseComplement());
+}
+
+TEST(Dinuc, complementNuc)
+{
+	EXPECT_EQ(Dinuc::complementNuc(A), T);
+	EXPECT_EQ(Dinuc::complementNuc(T), A);
+	EXPECT_EQ(Dinuc::complementNuc(C), G);
+	EXPECT_EQ(Dinuc::complementNuc(G), C);
+}
+
+/* Tests mask() and operator==() as well complement(). Probably testing too much in one test... */
+TEST(DinucSet, general)
+{
+	Dinuc AT(A, T);
+	Dinuc CG(C, G);
+	Dinuc GT(G, T);
+	Dinuc CC(C, C);
+
+	DinucSet ds;
+	ASSERT_FALSE(ds.hasExtension());
+
+	ds.setBase(AT);
+	ASSERT_TRUE(ds.hasExtension());
+	ds.setBase(CG);
+	ds.setBase(GT);
+
+	ASSERT_EQ(ds.outDegree(), 3u);
+	ASSERT_TRUE(ds.checkBase(AT));
+	ASSERT_TRUE(ds.checkBase(CG));
+	ASSERT_TRUE(ds.checkBase(GT));
+	ASSERT_FALSE(ds.checkBase(CC));
+
+	uint16_t x = 1 << AT.toInt() | 1 << CG.toInt() | 1 << GT.toInt();
+
+	Dinuc AC(A, C);	
+	uint16_t y = 1 << AT.toInt() | 1 << CG.toInt() | 1 << AC.toInt();
+
+	DinucSet ds_new = DinucSet::mask(x);
+	ASSERT_EQ(ds_new.outDegree(), 3u);
+	DinucSet ds_new_rc = DinucSet::mask(y);
+	EXPECT_EQ(ds, ds_new);
+	EXPECT_EQ(ds.complement(), ds_new_rc);
+
+	ds.clear();
+	ASSERT_FALSE(ds.hasExtension());
+
+	ds.setBase(AT);
+	ds_new.clear(ds);
+	ASSERT_EQ(ds_new.outDegree(), 2u);
+}
diff --git a/Unittest/PairedDBG/KmerPairTest.cc b/Unittest/PairedDBG/KmerPairTest.cc
new file mode 100644
index 0000000..30cb331
--- /dev/null
+++ b/Unittest/PairedDBG/KmerPairTest.cc
@@ -0,0 +1,96 @@
+#include "PairedDBG/KmerPair.h"
+
+#include <gtest/gtest.h>
+
+using namespace std;
+
+string seq1 = "AACCTTGG";
+string seq2 = "ACGTACGT";
+string seq = "AACCTTGGNNNNNACGTACGT";
+
+TEST(KmerPair, constructors)
+{
+	Kmer::setLength(8);
+	KmerPair::setLength(21);
+
+	Kmer kmer1(seq1);
+	Kmer kmer2(seq2);
+	KmerPair k1(kmer1, kmer2);
+	KmerPair k2(seq1, seq2);
+	KmerPair k3(seq);
+	KmerPair k4(seq1, seq1);
+
+	EXPECT_EQ(k1, k2);
+	EXPECT_EQ(k1, k3);
+	EXPECT_NE(k1, k4);
+
+	EXPECT_EQ(KmerPair::length(), 21u);
+}
+
+TEST(KmerPair, str)
+{
+	Kmer::setLength(8);
+	KmerPair::setLength(21);
+
+	KmerPair k(seq);
+	string res1 = k.str();
+	EXPECT_EQ(res1, seq);
+
+	KmerPair::setLength(22); // Maybe this shouldn't be allowed?
+	string res2 = k.str();
+	EXPECT_EQ(res2, "AACCTTGGNNNNNNACGTACGT"); // Add one 'N' from seq
+}
+
+TEST(KmerPair, reverseComplement)
+{
+	string rcseq1 = "CCAAGGTT";
+	string rcseq2 = "ACGTACGT";
+	EXPECT_EQ(rcseq1, reverseComplement(seq1)); // just to make sure ;)
+
+	KmerPair k(seq1, seq2);
+	KmerPair rck(rcseq2, rcseq1);
+	EXPECT_EQ(rck, reverseComplement(k));
+	k.reverseComplement();
+	EXPECT_EQ(rck, k);
+}
+
+TEST(KmerPair, isPalindrome)
+{
+	Kmer::setLength(8);
+	KmerPair::setLength(21);
+
+	string rcseq1 = reverseComplement(seq1);
+	KmerPair kp(seq1, rcseq1);
+	EXPECT_EQ(kp, reverseComplement(kp));
+	EXPECT_TRUE(kp.isPalindrome());
+
+	string pal("AGAATTCT");
+	Kmer k(pal);
+	EXPECT_TRUE(k.isPalindrome());
+	KmerPair kp_pal(k, k);
+	EXPECT_TRUE(k.isPalindrome());
+
+	KmerPair kp_npal(pal, seq2);
+	EXPECT_FALSE(kp_npal.isPalindrome());
+}
+
+TEST(KmerPair, isPalindrome_edge)
+{
+	Kmer::setLength(4);
+	KmerPair::setLength(12);
+
+	string epal = "CCGCNNNNAGCG";
+	KmerPair kp(epal);
+	EXPECT_FALSE(kp.isPalindrome());
+	EXPECT_FALSE(kp.isPalindrome(ANTISENSE));
+	EXPECT_TRUE(kp.isPalindrome(SENSE));
+
+	EXPECT_EQ(KmerPair::length(), 12u);
+}
+
+/* TODO: Missing tests:
+*    setLastBase
+*    shift
+*    getHashCode - may not want to do
+*    getLastBaseChar
+*/
diff --git a/Unittest/PairedDBG/LoadAlgorithmTest.cpp b/Unittest/PairedDBG/LoadAlgorithmTest.cpp
new file mode 100644
index 0000000..88460b0
--- /dev/null
+++ b/Unittest/PairedDBG/LoadAlgorithmTest.cpp
@@ -0,0 +1,53 @@
+#include "PairedDBG/SequenceCollection.h"
+#include "Assembly/AssemblyAlgorithms.h"
+#include "Assembly/Options.h"
+#include "Common/UnorderedSet.h"
+
+#include <gtest/gtest.h>
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+TEST(LoadAlgorithmTest, base)
+{
+	typedef SequenceCollectionHash Graph;
+	Graph g;
+
+	// length of each kmer in kmer pair
+	Kmer::setLength(2);
+	// space between kmer pair
+	unsigned delta = 2;
+	// the length of both kmers plus the gap
+	KmerPair::setLength(Kmer::length() * 2 + delta);
+
+	// see test.png for an image of the paired
+	// de Bruijn graph for this sequence
+	Sequence seq("TAATGCCATGGGATGTT");
+
+	AssemblyAlgorithms::loadSequence(&g, seq);
+
+	unordered_set<KmerPair> kmerPairs, expectedKmerPairs;
+
+	expectedKmerPairs.insert(KmerPair("TAGC"));
+	expectedKmerPairs.insert(KmerPair("AACC"));
+	expectedKmerPairs.insert(KmerPair("ATCA"));
+	expectedKmerPairs.insert(KmerPair("GCTG"));
+	expectedKmerPairs.insert(KmerPair("CCGG"));
+	expectedKmerPairs.insert(KmerPair("CAGG"));
+	expectedKmerPairs.insert(KmerPair("ATGA"));
+	expectedKmerPairs.insert(KmerPair("GGTG"));
+	expectedKmerPairs.insert(KmerPair("GGGT"));
+	expectedKmerPairs.insert(KmerPair("GATT"));
+
+	for (Graph::const_iterator it = g.begin(); it != g.end(); ++it) {
+		KmerPair kmerPair(it->first);
+#if 0
+cerr << "visiting KmerPair: " << kmerPair << "\n";
+#endif
+		ASSERT_TRUE(expectedKmerPairs.find(kmerPair) != expectedKmerPairs.end());
+		expectedKmerPairs.erase(kmerPair);
+	}
+
+	ASSERT_TRUE(expectedKmerPairs.empty());
+}
diff --git a/Unittest/PairedDBG/test.fa b/Unittest/PairedDBG/test.fa
new file mode 100644
index 0000000..65f4587
--- /dev/null
+++ b/Unittest/PairedDBG/test.fa
@@ -0,0 +1,2 @@
+>test
+TAATGCCATGGGATGTT
diff --git a/Unittest/PairedDBG/test.png b/Unittest/PairedDBG/test.png
new file mode 100644
index 0000000..ab55f36
Binary files /dev/null and b/Unittest/PairedDBG/test.png differ
diff --git a/Unittest/PairedDBG/test.svg b/Unittest/PairedDBG/test.svg
new file mode 100644
index 0000000..bfb5ae7
--- /dev/null
+++ b/Unittest/PairedDBG/test.svg
@@ -0,0 +1,859 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1052.3622"
+   height="744.09448"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.47 r22583"
+   sodipodi:docname="test.svg"
+   inkscape:export-filename="/home/benv/work/git/abyss-dev/Unittest/PairedDBG/test.png"
+   inkscape:export-xdpi="191.94"
+   inkscape:export-ydpi="191.94">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS"
+       style="overflow:visible">
+      <path
+         id="path4054"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.2,0.2)" />
+    </marker>
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM"
+       style="overflow:visible">
+      <path
+         id="path4051"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.4,0.4)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3932"
+         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible">
+      <path
+         id="path3908"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3920"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <inkscape:perspective
+       id="perspective3618"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3649"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective5494"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS-7"
+       style="overflow:visible">
+      <path
+         id="path4054-4"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.2,0.2)" />
+    </marker>
+    <inkscape:perspective
+       id="perspective6599"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <marker
+       inkscape:stockid="TriangleOutM"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutM-0"
+       style="overflow:visible">
+      <path
+         id="path4051-2"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.4,0.4)" />
+    </marker>
+    <inkscape:perspective
+       id="perspective7297"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS-7-7"
+       style="overflow:visible">
+      <path
+         id="path4054-4-8"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.2,0.2)" />
+    </marker>
+    <inkscape:perspective
+       id="perspective7346"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <marker
+       inkscape:stockid="TriangleOutS"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="TriangleOutS-7-5"
+       style="overflow:visible">
+      <path
+         id="path4054-4-3"
+         d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+         transform="scale(0.2,0.2)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="538.34994"
+     inkscape:cy="382.72848"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     showborder="true"
+     inkscape:showpageshadow="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1918"
+     inkscape:window-height="1053"
+     inkscape:window-x="1920"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-308.2677)">
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2816"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion2818"><rect
+           id="rect2820"
+           width="657.14288"
+           height="348.57144"
+           x="-1257.1428"
+           y="412.36218" /></flowRegion><flowPara
+         id="flowPara2822"></flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path3598"
+       sodipodi:cx="-1645.7142"
+       sodipodi:cy="72.362183"
+       sodipodi:rx="194.28572"
+       sodipodi:ry="194.28572"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       transform="matrix(0.22056136,0,0,0.22056136,438.20442,715.68127)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3600"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,568.57995,694.25091)"><flowRegion
+         id="flowRegion3602"><rect
+           id="rect3604"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3606"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">GC..TA</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 44.711376,733.04983 60.085294,0"
+       id="path3608" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,567.63214,668.31414)"
+       xml:space="preserve"
+       id="flowRoot3600-4"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion3602-3"><rect
+           id="rect3604-4"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3606-2"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">TA..GC</flowPara></flowRoot>    <path
+       transform="matrix(0.22056136,0,0,0.22056136,570.57982,715.68127)"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       sodipodi:ry="194.28572"
+       sodipodi:rx="194.28572"
+       sodipodi:cy="72.362183"
+       sodipodi:cx="-1645.7142"
+       id="path3694"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,700.95535,694.25091)"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3696"
+       xml:space="preserve"><flowRegion
+         id="flowRegion3698"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3700" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3702">GG..TT</flowPara></flowRoot>    <path
+       id="path3704"
+       d="m 177.08675,733.04983 60.0853,0"
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <flowRoot
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3706"
+       xml:space="preserve"
+       transform="matrix(0.3285914,0,0,0.3285914,700.00753,668.31414)"><flowRegion
+         id="flowRegion3708"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3710" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3712">AA..CC</flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path3714"
+       sodipodi:cx="-1645.7142"
+       sodipodi:cy="72.362183"
+       sodipodi:rx="194.28572"
+       sodipodi:ry="194.28572"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       transform="matrix(0.22056136,0,0,0.22056136,706.71054,716.48507)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3716"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,837.08607,695.05471)"><flowRegion
+         id="flowRegion3718"><rect
+           id="rect3720"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3722"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">TG..AT</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 313.21751,733.85363 60.08525,0"
+       id="path3724" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,836.13825,669.11793)"
+       xml:space="preserve"
+       id="flowRoot3726"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion3728"><rect
+           id="rect3730"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3732"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">AT..CA</flowPara></flowRoot>    <path
+       transform="matrix(0.22056136,0,0,0.22056136,837.20826,716.48507)"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       sodipodi:ry="194.28572"
+       sodipodi:rx="194.28572"
+       sodipodi:cy="72.362183"
+       sodipodi:cx="-1645.7142"
+       id="path3734"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,967.58385,695.05471)"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3736"
+       xml:space="preserve"><flowRegion
+         id="flowRegion3738"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3740" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3742">AT..CA</flowPara></flowRoot>    <path
+       id="path3744"
+       d="m 443.71521,733.85363 60.08528,0"
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <flowRoot
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3746"
+       xml:space="preserve"
+       transform="matrix(0.3285914,0,0,0.3285914,966.63601,669.11793)"><flowRegion
+         id="flowRegion3748"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3750" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3752">TG..AT</flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path3756"
+       sodipodi:cx="-1645.7142"
+       sodipodi:cy="72.362183"
+       sodipodi:rx="194.28572"
+       sodipodi:ry="194.28572"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       transform="matrix(0.22056136,0,0,0.22056136,970.52246,716.48507)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3758"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,1100.898,695.05471)"><flowRegion
+         id="flowRegion3760"><rect
+           id="rect3762"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3764"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">CA..CC</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 577.02944,733.85363 60.08527,0"
+       id="path3766" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1099.9502,669.11793)"
+       xml:space="preserve"
+       id="flowRoot3768"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion3770"><rect
+           id="rect3772"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3774"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">GG..TG</flowPara></flowRoot>    <path
+       transform="matrix(0.22056136,0,0,0.22056136,1106.6531,716.48507)"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       sodipodi:ry="194.28572"
+       sodipodi:rx="194.28572"
+       sodipodi:cy="72.362183"
+       sodipodi:cx="-1645.7142"
+       id="path3776"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1237.0287,695.05471)"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3778"
+       xml:space="preserve"><flowRegion
+         id="flowRegion3780"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3782" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3784">AC..CC</flowPara></flowRoot>    <path
+       id="path3786"
+       d="m 713.16016,733.85363 60.08527,0"
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <flowRoot
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3788"
+       xml:space="preserve"
+       transform="matrix(0.3285914,0,0,0.3285914,1236.0808,669.11793)"><flowRegion
+         id="flowRegion3790"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3792" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3794">GG..GT</flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path3796"
+       sodipodi:cx="-1645.7142"
+       sodipodi:cy="72.362183"
+       sodipodi:rx="194.28572"
+       sodipodi:ry="194.28572"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       transform="matrix(0.22056136,0,0,0.22056136,1241.8451,716.48507)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3798"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,1372.2206,695.05471)"><flowRegion
+         id="flowRegion3800"><rect
+           id="rect3802"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3804"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">AA..TC</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 848.35205,733.85363 60.08527,0"
+       id="path3806" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1371.2728,669.11793)"
+       xml:space="preserve"
+       id="flowRoot3808"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion3810"><rect
+           id="rect3812"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3814"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">GA..TT</flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path3816"
+       sodipodi:cx="-1645.7142"
+       sodipodi:cy="72.362183"
+       sodipodi:rx="194.28572"
+       sodipodi:ry="194.28572"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       transform="matrix(0.22056136,0,0,0.22056136,900.11003,548.43404)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3818"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,1030.4856,527.00368)"><flowRegion
+         id="flowRegion3820"><rect
+           id="rect3822"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3824"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">CA..GC</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 506.61699,565.80259 60.08528,0"
+       id="path3826" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1029.5378,501.0669)"
+       xml:space="preserve"
+       id="flowRoot3828"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion3830"><rect
+           id="rect3832"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3834"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">GC..TG</flowPara></flowRoot>    <path
+       transform="matrix(0.22056136,0,0,0.22056136,1041.8737,548.43404)"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       sodipodi:ry="194.28572"
+       sodipodi:rx="194.28572"
+       sodipodi:cy="72.362183"
+       sodipodi:cx="-1645.7142"
+       id="path3836"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1172.2493,527.00369)"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3838"
+       xml:space="preserve"><flowRegion
+         id="flowRegion3840"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3842" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3844">CC..GG</flowPara></flowRoot>    <path
+       id="path3846"
+       d="m 648.38071,565.8026 60.08527,0"
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <flowRoot
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3848"
+       xml:space="preserve"
+       transform="matrix(0.3285914,0,0,0.3285914,1171.3014,501.06691)"><flowRegion
+         id="flowRegion3850"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3852" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3854">CC..GG</flowPara></flowRoot>    <path
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path3858"
+       sodipodi:cx="-1645.7142"
+       sodipodi:cy="72.362183"
+       sodipodi:rx="194.28572"
+       sodipodi:ry="194.28572"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       transform="matrix(0.22056136,0,0,0.22056136,1178.0045,548.43404)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3860"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,1308.38,527.00369)"><flowRegion
+         id="flowRegion3862"><rect
+           id="rect3864"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3866"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">CC..TG</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 784.51144,565.8026 60.08527,0"
+       id="path3868" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1307.4322,501.06691)"
+       xml:space="preserve"
+       id="flowRoot3870"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion3872"><rect
+           id="rect3874"
+           width="211.42857"
+           height="68.571426"
+           x="-1585.7142"
+           y="123.79076"
+           style="font-size:48px" /></flowRegion><flowPara
+         id="flowPara3876"
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">CA..GG</flowPara></flowRoot>    <path
+       transform="matrix(0.22056136,0,0,0.22056136,1311.3187,548.43404)"
+       d="m -1451.4285,72.362183 a 194.28572,194.28572 0 1 1 -388.5715,0 194.28572,194.28572 0 1 1 388.5715,0 z"
+       sodipodi:ry="194.28572"
+       sodipodi:rx="194.28572"
+       sodipodi:cy="72.362183"
+       sodipodi:cx="-1645.7142"
+       id="path3878"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:6.67130613;stroke-miterlimit:4;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1441.6942,527.00369)"
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3880"
+       xml:space="preserve"><flowRegion
+         id="flowRegion3882"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3884" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3886">TC..AT</flowPara></flowRoot>    <path
+       id="path3888"
+       d="m 917.82572,565.8026 60.08524,0"
+       style="fill:none;stroke:#000000;stroke-width:0.85433763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <flowRoot
+       style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot3890"
+       xml:space="preserve"
+       transform="matrix(0.3285914,0,0,0.3285914,1440.7465,501.06691)"><flowRegion
+         id="flowRegion3892"><rect
+           style="font-size:48px"
+           y="123.79076"
+           x="-1585.7142"
+           height="68.571426"
+           width="211.42857"
+           id="rect3894" /></flowRegion><flowPara
+         style="font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara3896">AT..GA</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:0.32859138px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 124.51212,732.11099"
+       id="path3898" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)"
+       d="m 122.63448,733.04983 31.92034,0"
+       id="path3900" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)"
+       d="m 255.85541,733.04983 33.79792,0"
+       id="path3900-1"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       id="path5514"
+       d="m 389.16962,733.04983 33.79793,0"
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)"
+       d="m 520.60617,733.04983 33.79796,0"
+       id="path5516"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       id="path5518"
+       d="m 655.79806,733.04983 33.79795,0"
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)"
+       d="m 791.92879,733.04983 33.79795,0"
+       id="path5520"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)"
+       d="m 486.8082,684.23053 22.53196,-66.65711"
+       id="path5522"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       id="path5524"
+       d="m 588.20212,564.99879 33.79796,0"
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)"
+       d="m 727.14934,565.93762 33.79795,0"
+       id="path5526"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       id="path5528"
+       d="m 863.28006,564.05996 33.79798,0"
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS)" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS-7)"
+       d="m 947.8683,616.63459 c 0,0 -1.87767,15.96015 -23.47081,24.40964 -28.46449,11.13831 -194.82397,-2.84955 -304.18175,7.51066 -89.18909,8.4495 -110.78224,44.12513 -110.78224,44.12513"
+       id="path5532"
+       sodipodi:nodetypes="cssc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS-7)"
+       d="m 649.31955,521.8125 c 0,0 -30.97255,-3.37963 -32.3694,-24.32836 -1.25688,-18.84961 1.53118,-24.59355 17.79717,-28.83862 12.71769,-3.31904 28.65472,9.04184 30.53238,23.12433 1.87768,14.08249 1.87768,20.65432 1.87768,20.65432"
+       id="path5728"
+       sodipodi:nodetypes="csssc" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot5924"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,988.23816,687.67909)"><flowRegion
+         id="flowRegion5926"><rect
+           id="rect5928"
+           width="1019.9999"
+           height="80.000023"
+           x="-1702.8572"
+           y="486.64789" /></flowRegion><flowPara
+         id="flowPara5932"
+         style="font-size:64px;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch">FORWARD:TAATGCCATGGGATGTT</flowPara></flowRoot>    <flowRoot
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot5939"
+       xml:space="preserve"
+       transform="matrix(0.3285914,0,0,0.3285914,849.09928,705.5169)"><flowRegion
+         id="flowRegion5941"><rect
+           y="486.64789"
+           x="-1702.8572"
+           height="91.428543"
+           width="1514.2856"
+           id="rect5943" /></flowRegion><flowPara
+         style="font-size:64px;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch"
+         id="flowPara5945">REVERSE COMPLEMENT:AACATCCCATGGCATTA</flowPara></flowRoot>    <text
+       xml:space="preserve"
+       style="font-size:13.14365578px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       x="470.94135"
+       y="836.32141"
+       id="text5949"><tspan
+         sodipodi:role="line"
+         id="tspan5951"
+         x="470.94135"
+         y="836.32141"
+         style="font-size:21.0298481px;font-style:italic;font-weight:bold;font-family:Courier 10 Pitch;-inkscape-font-specification:Courier 10 Pitch Bold">INPUT SEQUENCE</tspan></text>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot5995"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"><flowRegion
+         id="flowRegion5997"><rect
+           id="rect5999"
+           width="882.85712"
+           height="588.57141"
+           x="-1451.4286"
+           y="-701.92352" /></flowRegion><flowPara
+         id="flowPara6001" /></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:2.23442173;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.93768639, 2.23442159;stroke-dashoffset:0;marker-end:url(#TriangleOutM)"
+       d="m 442.77634,552.79397 57.26881,0"
+       id="path6201" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:2.23442173;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.93768639, 2.23442159;stroke-dashoffset:0;marker-end:url(#TriangleOutM)"
+       d="m 443.76307,575.32595 57.26881,0"
+       id="path6201-0" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6619"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="matrix(0.3285914,0,0,0.3285914,1003.2594,513.99505)"><flowRegion
+         id="flowRegion6621"><rect
+           id="rect6623"
+           width="357.14279"
+           height="97.14286"
+           x="-1977.1428"
+           y="86.647896" /></flowRegion><flowPara
+         id="flowPara6627">Forward pair</flowPara></flowRoot>    <flowRoot
+       transform="matrix(0.3285914,0,0,0.3285914,1016.4031,537.46587)"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       id="flowRoot6646"
+       xml:space="preserve"><flowRegion
+         id="flowRegion6648"><rect
+           y="86.647896"
+           x="-1977.1428"
+           height="97.14286"
+           width="357.14279"
+           id="rect6650" /></flowRegion><flowPara
+         id="flowPara6652">Reverse complement pair </flowPara><flowPara
+         id="flowPara6654">pair</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6679"
+       style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
+       transform="translate(-13.131983,371.90731)"><flowRegion
+         id="flowRegion6681"><rect
+           id="rect6683"
+           width="266.68027"
+           height="130.30968"
+           x="70.710678"
+           y="151.13493"
+           style="font-size:16px" /></flowRegion><flowPara
+         id="flowPara6685"
+         style="font-style:italic">Adaptation of Figure 4.35 from:</flowPara><flowPara
+         id="flowPara6689"
+         style="font-style:italic" /><flowPara
+         id="flowPara6693"
+         style="font-style:italic">Phillip Compeau, Pavel Pevzner.  Bioinformatics Algorithms: An Active Learning Approach. Illustrated edition, 2014.</flowPara><flowPara
+         id="flowPara6695" /></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:5.06;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#TriangleOutS-7)"
+       d="m 89.285714,375.52305 c 0,0 60.023926,-24.05127 117.857146,-23.57143 61.46381,0.50996 112.14285,25.71429 112.14285,25.71429"
+       id="path6697"
+       transform="translate(0,308.2677)"
+       sodipodi:nodetypes="csc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.05999999999999961;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#TriangleOutS-7)"
+       d="m 540,204.09448 c 0,0 38.29133,-56.8738 99.28571,-65.71428 46.22076,-6.6992 90,2.85714 124.28572,27.85714 27.04603,19.72106 34.28572,37.14286 34.28572,37.14286"
+       id="path7091"
+       transform="translate(0,308.2677)"
+       sodipodi:nodetypes="cssc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.05999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS-7)"
+       d="m 509.76315,770.88342 c 0,0 71.44958,23.35875 168.57143,24.28571 69.31828,0.66159 160,-25 160,-25"
+       id="path6697-4"
+       sodipodi:nodetypes="csc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:5.0603075;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#TriangleOutS-7)"
+       d="m 188.45096,777.98988 c 0,0 -20.10546,15.8838 -14.27346,36.05279 5.24763,18.14801 11.97048,22.59658 28.70898,21.03917 13.08713,-1.21768 23.85252,-18.27307 20.8144,-32.15155 -3.0381,-13.87847 -5.27959,-20.05623 -5.27959,-20.05623"
+       id="path5728-7"
+       sodipodi:nodetypes="csssc" />
+  </g>
+</svg>
diff --git a/bin/Makefile.am b/bin/Makefile.am
index 3909976..624de41 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -1,3 +1,10 @@
+if !HAVE_LIBMPI
+nompi=ABYSS-P
+endif
+
+ABYSS-P: $(top_builddir)/bin/abyss-nompi
+	cp $< $@
+
 dist_bin_SCRIPTS = \
 	abyss-bowtie \
 	abyss-bowtie2 \
@@ -9,9 +16,12 @@ dist_bin_SCRIPTS = \
 	abyss-pe \
 	abyss-samtoafg \
 	abyss-tabtomd \
-	abyss-bloom-dist.mk
+	abyss-bloom-dist.mk \
+	abyss-dida
+	$(nompi)
 dist_noinst_SCRIPTS = \
 	abyss-adjtodot.pl \
 	abyss-cstont \
 	abyss-fac.pl \
-	abyss-joindist
+	abyss-joindist \
+	abyss-nompi
diff --git a/bin/abyss-dida b/bin/abyss-dida
new file mode 100755
index 0000000..593cfec
--- /dev/null
+++ b/bin/abyss-dida
@@ -0,0 +1,107 @@
+#!/bin/bash
+set -eu -o pipefail
+
+#------------------------------------------------------------
+# parse command line options
+#------------------------------------------------------------
+
+case $1 in
+	--help)
+		cat <<EOF
+Usage: abyss-dida [OPTION]... QUERY... TARGET
+
+Options:
+
+    --help        this help message
+    -d STRING     additional command line opts for DIDA
+    -j            number of threads [1]
+    -m            path of 'mpirun' executable [mpirun]
+    -n            number of ranks in DIDA MPI job [3]
+    -x VAR=value  set environment variable for MPI job
+    --version     print version info and exit
+
+Align the sequences of the files QUERY to those of the file
+TARGET using DIDA.
+EOF
+		exit
+		;;
+	--version)
+		cat <<EOF
+abyss-dida (ABySS)
+Written by Ben Vandervalk.
+EOF
+		dida-wrapper --version
+		exit
+		;;
+esac
+
+n=3
+mpirun=''
+dida_cmd='dida-wrapper'
+dida_opt='--no-clean --se'
+while getopts :d:j:l:m:n:v:x: opt; do
+	case $opt in
+		d) dida_opt="$dida_opt $OPTARG";;
+		j) dida_cmd="$dida_cmd -j$OPTARG";;
+		l) dida_cmd="$dida_cmd -l$OPTARG";;
+		m) mpirun="$OPTARG";;
+		n) n=$OPTARG;;
+		v) ;;
+		x) export "$OPTARG";;
+		\?) echo >&2 "$(basename 0): invalid option: $OPTARG"; exit 1;;
+	esac
+done
+dida_cmd="$dida_cmd $dida_opt"
+shift $((OPTIND-1))
+
+# dida-wrapper requires n >= 3
+if [ $n -lt 3 ]; then
+	n = 3
+fi
+
+# default mpirun cmd, if none specified
+if [ -z "$mpirun" ]; then
+	mpirun="mpirun -np $n"
+fi
+
+#------------------------------------------------------------
+# parse command line arguments (query and target files)
+#------------------------------------------------------------
+
+# Add file arguments to dida command.  Convert all input file paths
+# to absolute, since we change to a temp dir below
+
+query=($(readlink -f "$@"))
+target=${query[${#query[@]}-1]}
+unset query[${#query[@]}-1]
+
+#------------------------------------------------------------
+# set up and switch to temp sandbox dir
+#------------------------------------------------------------
+
+tmpdir=$(mktemp -d --tmpdir=.)
+pushd $tmpdir > /dev/null
+
+ln -s "$target"
+target_link="$(basename $target)"
+
+#------------------------------------------------------------
+# run DIDA
+#------------------------------------------------------------
+
+dida_cmd="$mpirun /bin/bash -c '$dida_cmd <(abyss-tofastq --interleave ${query[@]}) $target_link'"
+echo >&2 "$dida_cmd"
+# tricky: must use eval here to preserve nested quotes
+# (e.g. quotes in $mpirun command)
+eval "$dida_cmd"
+
+du=$(du -hsc * | tail -1 | awk '{print $1}')
+echo >&2 "dida-wrapper job used $du temp disk space"
+
+#------------------------------------------------------------
+# clean up
+#------------------------------------------------------------
+
+rm -f *
+popd > /dev/null
+rmdir $tmpdir
diff --git a/bin/abyss-fac.pl b/bin/abyss-fac.pl
index 4d09942..828caa1 100755
--- a/bin/abyss-fac.pl
+++ b/bin/abyss-fac.pl
@@ -109,11 +109,11 @@ eng($ntotal), eng($n), $nn50, $min, $n80, $n50, $n20, $max, eng($sum), $path
 }
 
 format Spaces_TOP =
-n       n:@<<<< n:N50   min     N80     N50     N20     max     sum
+n       n:@<<<< L50   min     N80     N50     N20     max     sum
 $opt_threshold
 .
 format Pipes_TOP =
-||n    ||n:@<<<||n:N50 ||min   ||N80   ||N50   ||N20   ||max   ||sum   ||
+||n    ||n:@<<<||L50 ||min   ||N80   ||N50   ||N20   ||max   ||sum   ||
 $opt_threshold
 .
 
diff --git a/bin/abyss-fatoagp b/bin/abyss-fatoagp
index d1b517d..a5297b9 100755
--- a/bin/abyss-fatoagp
+++ b/bin/abyss-fatoagp
@@ -31,6 +31,8 @@ while (<>) {
 	my $x = 0;
 	for my $ctgseq (@ctgseqs) {
 		my $len = length $ctgseq;
+		$i++ if ($len == 0);
+		next if ($len == 0);
 		# object object_beg object_end part_number
 		print 'scaffold', $scafid, "\t",
 			$x + 1, "\t",
diff --git a/bin/abyss-nompi b/bin/abyss-nompi
new file mode 100755
index 0000000..d8d7909
--- /dev/null
+++ b/bin/abyss-nompi
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+echo >&2 "error: ABySS was not configured with support for MPI. For details"
+echo >&2 "       on compiling ABySS with MPI suppor see:"
+echo >&2 "       https://github.com/bcgsc/abyss#compiling-abyss-from-source"
+exit 1
diff --git a/bin/abyss-pe b/bin/abyss-pe
index 0fb384c..60436c6 100755
--- a/bin/abyss-pe
+++ b/bin/abyss-pe
@@ -90,12 +90,22 @@ ifdef path
 PATH:=$(path):$(PATH)
 endif
 
+ifdef db
+# Determine the location of sqlite database
+override dbopt:=--db=$(db)
+
+# Track data details for database
+library ?= ""
+strain ?= ""
+species ?= ""
+endif
+
 # Programs
 MARKDOWN=multimarkdown
 
-ifdef lib
 map=$(foreach a,$(2),$(call $(1),$(a)))
 deref=$($1)
+ifdef lib
 in?=$(call map, deref, $(lib))
 else
 ifdef in
@@ -114,9 +124,17 @@ ifdef se
 override se:=$(strip $(se))
 endif
 
+# Graph file format
+graph?=dot
+# g is private. Use graph instead.
+override g:=$(graph)
+
 # ABYSS parameters
 q ?= 3
 abyssopt += -k$k -q$q
+ifdef K
+abyssopt += -K$K
+endif
 ifdef e
 abyssopt += -e$e
 endif
@@ -139,7 +157,7 @@ endif
 ifdef ss
 SS=--SS
 endif
-abyssopt += $v $(SS) --coverage-hist=coverage.hist -s $*-bubbles.fa
+abyssopt += $v $(dbopt) $(SS) --coverage-hist=coverage.hist -s $*-bubbles.fa
 
 # Number of threads
 ifdef PE_HOSTFILE
@@ -155,10 +173,17 @@ endif
 
 # AdjList parameters
 m?=50
+alopt += $v $(dbopt) $(SS) -k$k -m$m
+ifdef K
+alopt += -K$K
+endif
 
 # filtergraph parameters
+ifdef K
+fgopt += --assemble --shim-max-degree=2
+endif
 ifdef xtip
-fgopt := -t$(shell echo $k*2 |bc)
+fgopt += -t$(shell echo $k*2 |bc)
 endif
 
 # PopBubbles parameters
@@ -181,8 +206,26 @@ ifeq ($(SS),--SS)
   override aligner=map$(ssq_t)
  endif
 endif
+
 align?=abyss-$(aligner)
-mapopt=$v -j$j -l$($*_l) $(SS) $(ALIGNER_OPTIONS) $(MAP_OPTIONS)
+mapopt=$v $(dbopt) -j$j -l$($*_l) $(SS) $(ALIGNER_OPTIONS) $(MAP_OPTIONS)
+
+# DIDA parameters
+escape_quotes=$(shell echo "$(1)" | sed 's|"|\\\"|g')
+ifeq ($(aligner),dida)
+   ifdef np
+       mapopt+=-n$(np)
+   endif
+   ifdef DIDA_RUN_OPTIONS
+       mapopt+=$(DIDA_RUN_OPTIONS)
+   endif
+   ifdef DIDA_MPIRUN
+       mapopt+=-m"$(call escape_quotes,$(DIDA_MPIRUN))"
+   endif
+   ifdef DIDA_OPTIONS
+       mapopt+=-d"$(call escape_quotes,$(DIDA_OPTIONS))"
+   endif
+endif
 
 # fixmate parameters
 ifeq ($(align),abyss-kaligner)
@@ -190,7 +233,7 @@ fixmate?=ParseAligns
 else
 fixmate?=abyss-fixmate$(ssq_t)
 endif
-fmopt=$v -l$($*_l) $(FIXMATE_OPTIONS)
+fmopt=$v $(dbopt) -l$($*_l) $(FIXMATE_OPTIONS)
 
 # DistanceEst parameters
 DistanceEst?=DistanceEst$(ssq_t)
@@ -201,23 +244,35 @@ libs=$(pe) $(mp)
 $(foreach i,$(libs),$(eval $i_l?=$l))
 $(foreach i,$(libs),$(eval $i_s?=$s))
 $(foreach i,$(libs),$(eval $i_n?=$n))
-deopt=$v -j$j -k$k -l$($*_l) -s$($*_s) -n$($*_n) $($*_de) \
+deopt=$v $(dbopt) -j$j -k$k -l$($*_l) -s$($*_s) -n$($*_n) $($*_de) \
 	$(DISTANCEEST_OPTIONS)
 
 # SimpleGraph parameters
+sgopt += $(dbopt)
 ifdef d
 sgopt += -d$d
 endif
 
+# MergePaths parameters
+mpopt += $v $(dbopt) -j$j -k$k
+
+# PathOverlap parameters
+poopt += $v $(dbopt) -k$k
+
 # PathConsensus parameters
+pcopt += $(dbopt)
 ifdef a
 pcopt += -a$a
 endif
 pcopt += -p$p
 
+# MergeContigs parameters
+mcopt += $v $(dbopt) -k$k
+
 # Scaffold parameters
 S?=$s
 N?=$n
+scopt += $v $(dbopt) $(SS) -k$k
 
 # BWA-SW parameters
 bwaswopt=-t$j
@@ -263,7 +318,7 @@ Report bugs to <abyss-users at bcgsc.ca>.\n'
 
 version:
 	@printf '\
-abyss-pe (ABySS) 1.5.2\n\
+abyss-pe (ABySS) 1.9.0\n\
 Written by Shaun Jackman and Anthony Raymond.\n\
 \n\
 Copyright 2012 Canada'\''s Michael Smith Genome Science Centre\n'
@@ -286,6 +341,7 @@ versions: version
 	@abyss-fixmate --version; echo
 	@abyss-map --version; echo
 	@abyss-scaffold --version; echo
+	@abyss-sealer --version; echo
 	@abyss-todot --version; echo
 	@$(align) --version; echo
 	@awk --version; echo
@@ -293,22 +349,28 @@ versions: version
 	@-mpirun --version
 
 # Determine the default target
+ifdef db
+default: startDb
+endif
 default: unitigs
 ifneq ($(in),)
-default: contigs contigs-dot
+default: contigs contigs-graph
 endif
 ifneq ($(mp),)
-default: scaffolds scaffolds-dot
+default: scaffolds scaffolds-graph
 ifneq ($(long),)
-default: long-scaffs long-scaffs-dot
+default: long-scaffs long-scaffs-graph
+endif
 endif
+ifdef db
+default: finishDb
 endif
 default: stats
 
 # Define the commands (phony targets)
 unitigs: $(name)-unitigs.fa
 
-unitigs-dot: $(name)-unitigs.dot
+unitigs-graph: $(name)-unitigs.$g
 
 pe-index: $(name)-3.fa.fm
 
@@ -318,7 +380,7 @@ pe-bam: $(addsuffix -3.bam.bai, $(pe))
 
 contigs: $(name)-contigs.fa
 
-contigs-dot: $(name)-contigs.dot
+contigs-graph: $(name)-contigs.$g
 
 mp-index: $(name)-6.fa.fm
 
@@ -328,30 +390,41 @@ mp-bam: $(addsuffix -6.bam.bai, $(mp))
 
 scaffolds: $(name)-scaffolds.fa
 
-scaffolds-dot: $(name)-scaffolds.dot
+scaffolds-graph: $(name)-scaffolds.$g
+
+seal-scaffolds: $(name)-scaffolds-sealed.fa
 
 scaftigs: $(name)-scaftigs.fa $(name)-scaftigs.agp
 
 long-scaffs: $(name)-long-scaffs.fa
 
-long-scaffs-dot: $(name)-long-scaffs.dot
+long-scaffs-graph: $(name)-long-scaffs.$g
 
 all: default bam stats
 
 clean:
-	rm -f *.adj *.dot *.sam.gz *.hist *.dist *.path *.path[123]
+	rm -f *.adj *.asqg *.dot *.gfa *.sam *.txt \
+		*.sam.gz *.hist *.dist *.path *.path[123]
+
+ifdef db
+.PHONY: startDb finishDb
+endif
 
 .PHONY: bam default stats \
-	unitigs unitigs-dot \
-	pe-index pe-sam pe-bam contigs contigs-dot \
-	mp-index mp-sam mp-bam scaffolds scaffolds-dot \
-	scaftigs long-scaffs long-scaffs-dot \
+	unitigs unitigs-graph \
+	pe-index pe-sam pe-bam contigs contigs-graph \
+	mp-index mp-sam mp-bam scaffolds scaffolds-graph \
+	scaftigs long-scaffs long-scaffs-graph seal-scaffolds \
 	all clean help version versions
+
 .DELETE_ON_ERROR:
 .SECONDARY:
 
 # Utilities
 
+%.fa.fai: %.fa
+	abyss-index $v --fai $<
+
 %.fa.fm: %.fa
 	abyss-index $v $<
 
@@ -363,40 +436,69 @@ clean:
 
 # Assemble unitigs
 
+ifdef db
+startDb:
+	@echo -e \
+	$(name)".sqlite\n"\
+	> name.txt
+	@echo -e \
+	$(shell echo `date +%s`"_"`whoami`_)\
+	$(shell echo $$RANDOM \% 1000 \+ 1 | bc)"\n"\
+	$(library)"\n"\
+	$(strain)"\n"\
+	$(species)"\n"\
+	$(name)"\n"\
+	$(k)"\n"\
+	$(lib)$(in)$(se)\
+	> db.txt
+endif
+
+ifdef K
+ifdef np
 %-1.fa:
+	$(mpirun) -np $(np) abyss-paired-dbg-mpi $(abyssopt) $(ABYSS_OPTIONS) -o $*-1.fa $(in) $(se)
+else
+%-1.fa %-1.$g:
+	abyss-paired-dbg $(abyssopt) $(ABYSS_OPTIONS) -o $*-1.fa -g $*-1.$g $(in) $(se)
+endif
+
+else
 ifdef np
+%-1.fa:
 	$(mpirun) -np $(np) ABYSS-P $(abyssopt) $(ABYSS_OPTIONS) -o $@ $(in) $(se)
 else
+%-1.fa:
 	ABYSS $(abyssopt) $(ABYSS_OPTIONS) -o $@ $(in) $(se)
 endif
+endif
 
 # Find overlapping contigs
 
-%-1.adj: %-1.fa
-	AdjList $(SS) $v -k$k -m$m $< >$@
+%-1.$g: %-1.fa
+	AdjList $(alopt) --$g $< >$@
 
 # Remove shim contigs
 
-%-2.adj: %-1.adj
-	abyss-filtergraph $v $(fgopt) $(FILTERGRAPH_OPTIONS) -k$k -g $@ $^ >$*-1.path
+%-2.$g1 %-1.path: %-1.$g %-1.fa
+	abyss-filtergraph $v --$g $(fgopt) $(FILTERGRAPH_OPTIONS) -k$k -g $*-2.$g1 $^ >$*-1.path
+
+%-2.fa %-2.$g: %-1.fa %-2.$g1 %-1.path
+	MergeContigs $(mcopt) -g $*-2.$g -o $*-2.fa $^
 
 # Pop bubbles
 
-%-2.path %-3.adj: %-1.fa %-2.adj
-	PopBubbles $v -j$j -k$k $(SS) $(pbopt) $(POPBUBBLES_OPTIONS) -g $*-3.adj $^ >$*-2.path
+%-2.path %-3.$g: %-2.fa %-2.$g
+	PopBubbles $v --$g -j$j -k$k $(SS) $(pbopt) $(POPBUBBLES_OPTIONS) -g $*-3.$g $^ >$*-2.path
 
-%-3.fa: %-1.fa %-2.adj %-2.path
-	MergeContigs $v -k$k -o $@ $^
+%-3.fa: %-2.fa %-2.$g %-2.path
+	MergeContigs $(mcopt) -o $@ $^
 	awk '!/^>/ {x[">" $$1]=1; next} {getline s} $$1 in x {print $$0 "\n" s}' \
 		$*-2.path $*-1.fa >$*-indel.fa
 
-%-3.dot: %-3.adj
-	abyss-todot $v -k$k $< >$@
-
 %-unitigs.fa: %-3.fa
 	ln -sf $< $@
 
-%-unitigs.dot: %-3.dot
+%-unitigs.$g: %-3.$g
 	ln -sf $< $@
 
 # Estimate distances between unitigs
@@ -439,37 +541,38 @@ endif
 
 # Find overlaps between contigs
 
-%-4.fa %-4.adj: %-3.fa %-3.adj %-3.dist
-	Overlap $v $(SS) $(OVERLAP_OPTIONS) -k$k -g $*-4.adj -o $*-4.fa $^
+%-4.fa %-4.$g: %-3.fa %-3.$g %-3.dist
+	Overlap $v --$g $(SS) $(OVERLAP_OPTIONS) -k$k -g $*-4.$g -o $*-4.fa $^
 
 # Assemble contigs
 
-%-4.path1: %-4.adj %-3.dist
+%-4.path1: %-4.$g %-3.dist
 	SimpleGraph $v $(sgopt) $(SIMPLEGRAPH_OPTIONS) -j$j -k$k -o $@ $^
 
-%-4.path2: %-4.adj %-4.path1
-	MergePaths $v $(MERGEPATHS_OPTIONS) -j$j -k$k -o $@ $^
+%-4.path2: %-4.path1 %-3.fa.fai %-4.fa.fai
+	cat $*-3.fa.fai $*-4.fa.fai \
+		|MergePaths $(mpopt) $(MERGEPATHS_OPTIONS) -o $@ - $<
 
-%-4.path3: %-4.adj %-4.path2
-	PathOverlap --assemble $(SS) $v -k$k $^ >$@
+%-4.path3: %-4.$g %-4.path2
+	PathOverlap --assemble $(poopt) $(SS) $^ >$@
 
 ifndef cs
 
-%-5.path %-5.fa %-5.adj: %-3.fa %-4.fa %-4.adj %-4.path3
+%-5.path %-5.fa %-5.$g: %-3.fa %-4.fa %-4.$g %-4.path3
 	cat $(wordlist 1, 2, $^) \
-		|PathConsensus $v -k$k $(pcopt) -o $*-5.path -s $*-5.fa -g $*-5.adj - $(wordlist 3, 4, $^)
+		|PathConsensus $v --$g -k$k $(pcopt) -o $*-5.path -s $*-5.fa -g $*-5.$g - $(wordlist 3, 4, $^)
 
-%-6.fa: %-3.fa %-4.fa %-5.fa %-5.adj %-5.path
-	cat $(wordlist 1, 3, $^) |MergeContigs $v -k$k -o $@ - $(wordlist 4, 5, $^)
+%-6.fa: %-3.fa %-4.fa %-5.fa %-5.$g %-5.path
+	cat $(wordlist 1, 3, $^) |MergeContigs $(mcopt) -o $@ - $(wordlist 4, 5, $^)
 
 else
 
-%-5.adj %-5.path: %-4.adj %-4.path3
-	ln -sf $*-4.adj $*-5.adj
+%-5.$g %-5.path: %-4.$g %-4.path3
+	ln -sf $*-4.$g $*-5.$g
 	ln -sf $*-4.path3 $*-5.path
 
-%-cs.fa: %-3.fa %-4.fa %-4.adj %-4.path3
-	cat $(wordlist 1, 2, $^) |MergeContigs $v -k$k -o $@ - $(wordlist 3, 4, $^)
+%-cs.fa: %-3.fa %-4.fa %-4.$g %-4.path3
+	cat $(wordlist 1, 2, $^) |MergeContigs $(mcopt) -o $@ - $(wordlist 3, 4, $^)
 
 # Convert colour-space sequence to nucleotides
 
@@ -479,13 +582,13 @@ else
 
 endif
 
-%-6.dot: %-5.adj %-5.path
-	PathOverlap --overlap $v --dot -k$k $^ >$@
+%-6.$g: %-5.$g %-5.path
+	PathOverlap --overlap $(poopt) --$g $^ >$@
 
 %-contigs.fa: %-6.fa
 	ln -sf $< $@
 
-%-contigs.dot: %-6.dot
+%-contigs.$g: %-6.$g
 	ln -sf $< $@
 
 # Estimate distances between contigs
@@ -518,25 +621,34 @@ endif
 
 # Scaffold
 
-%-6.path: $(name)-6.dot $(addsuffix -6.dist.dot, $(mp))
-	abyss-scaffold $v $(SS) -k$k -s$S -n$N -g $@.dot $(SCAFFOLD_OPTIONS) $^ >$@
+%-6.path: $(name)-6.$g $(addsuffix -6.dist.dot, $(mp))
+	abyss-scaffold $(scopt) -s$S -n$N -g $@.dot $(SCAFFOLD_OPTIONS) $^ >$@
 
-%-7.path %-7.adj %-7.fa: %-6.fa %-6.dot %-6.path
-	PathConsensus $v -k$k $(pcopt) -s $*-7.fa -g $*-7.adj -o $*-7.path $^
+%-7.path %-7.$g %-7.fa: %-6.fa %-6.$g %-6.path
+	PathConsensus $v --$g -k$k $(pcopt) -s $*-7.fa -g $*-7.$g -o $*-7.path $^
 
-%-8.fa: %-6.fa %-7.fa %-7.adj %-7.path
+%-8.fa: %-6.fa %-7.fa %-7.$g %-7.path
 	cat $(wordlist 1, 2, $^) \
-		|MergeContigs $v -k$k -o $@ - $(wordlist 3, 4, $^)
+		|MergeContigs $(mcopt) -o $@ - $(wordlist 3, 4, $^)
 
-%-8.dot: %-7.adj %-7.path
-	PathOverlap --overlap $v --dot -k$k $^ >$@
+%-8.$g: %-7.$g %-7.path
+	PathOverlap --overlap $(poopt) --$g $^ >$@
 
 %-scaffolds.fa: %-8.fa
 	ln -sf $< $@
 
-%-scaffolds.dot: %-8.dot
+%-scaffolds.$g: %-8.$g
 	ln -sf $< $@
 
+# Sealed Scaffold
+sealer_ks?=-k90 -k80 -k70 -k60 -k50 -k40 -k30
+
+%-8_scaffold.fa: %-8.fa
+	abyss-sealer -v -j$j --print-flanks -o$*-8 -S$< $(sealer_ks) $(SEALER_OPTIONS) $(in) $(se)
+
+%-scaffolds-sealed.fa: %-8_scaffold.fa
+	ln -s $< $@
+
 # Scaftig
 
 %-scaftigs.fa: %-scaffolds-agp.fa
@@ -558,25 +670,30 @@ endif
 	abyss-longseqdist -k$k $(LONGSEQDIST_OPTIONS) $< \
 		|grep -v "l=" >$@
 
-%-8.path: $(name)-8.dot $(addsuffix -8.dist.dot, $(long))
-	abyss-scaffold $v $(SS) -k$k -s$S -n1 -g $@.dot $(SCAFFOLD_OPTIONS) $^ >$@
+%-8.path: $(name)-8.$g $(addsuffix -8.dist.dot, $(long))
+	abyss-scaffold $(scopt) -s$S -n1 -g $@.$g $(SCAFFOLD_OPTIONS) $^ >$@
 
-%-9.path %-9.adj %-9.fa: %-8.fa %-8.dot %-8.path
-	PathConsensus $v -k$k $(pcopt) -s $*-9.fa -g $*-9.adj -o $*-9.path $^
+%-9.path %-9.$g %-9.fa: %-8.fa %-8.$g %-8.path
+	PathConsensus $v --$g -k$k $(pcopt) -s $*-9.fa -g $*-9.$g -o $*-9.path $^
 
-%-10.fa: %-8.fa %-9.fa %-9.adj %-9.path
+%-10.fa: %-8.fa %-9.fa %-9.$g %-9.path
 	cat $(wordlist 1, 2, $^) \
-		|MergeContigs $v -k$k -o $@ - $(wordlist 3, 4, $^)
+		|MergeContigs $(mcopt) -o $@ - $(wordlist 3, 4, $^)
 
-%-10.dot: %-9.adj %-9.path
-	PathOverlap --overlap $v --dot -k$k $^ >$@
+%-10.$g: %-9.$g %-9.path
+	PathOverlap --overlap $(poopt) --$g $^ >$@
 
 %-long-scaffs.fa: %-10.fa
 	ln -sf $< $@
 
-%-long-scaffs.dot: %-10.dot
+%-long-scaffs.$g: %-10.$g
 	ln -sf $< $@
 
+ifdef db
+finishDb:
+	@rm -f db.txt
+endif
+
 # Create the final BAM file
 
 ifneq ($(mp),)
@@ -596,7 +713,7 @@ $(name)-unitigs.bam: %.bam: %.fa
 $(name)-contigs.bam $(name)-scaffolds.bam: %.bam: %.fa
 	$(align) $v -j$j -l$l $(ALIGNER_OPTIONS) \
 		$(call map, deref, $(sort $(lib) $(pe) $(mp))) $< \
-		|$(fixmate) $(fmopt) \
+		|$(fixmate) $v $(FIXMATE_OPTIONS) \
 		|sort -snk3 -k4 \
 		|samtools view -Sb - >$@
 
@@ -674,7 +791,6 @@ override varList := a b c d e E j k l m n N p q s S t v cs pi \
 	FIXMATE_OPTIONS BWASW_OPTIONS FATOAGP_OPTIONS SAMTOBREAK_OPTIONS \
 	MARKDOWN
 
-.PHONY: env
 env:
 	@echo -e "\
 	List of ABySS configuration variables currently set:\n\n\
diff --git a/circle.yml b/circle.yml
new file mode 100644
index 0000000..d87c453
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,11 @@
+dependencies:
+  pre:
+    - sudo apt-get update -qq
+    - sudo apt-get install libgtest-dev
+    - sudo apt-get install libsparsehash-dev
+test:
+  override:
+    - ./autogen.sh
+    - ./configure --with-mpi=/usr/lib/openmpi
+    - make
+    - make check
diff --git a/configure.ac b/configure.ac
index 66b9954..a3af488 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,9 @@
 AC_PREREQ(2.62)
-AC_INIT(ABySS, 1.5.2, abyss-users at bcgsc.ca, abyss,
+AC_INIT(ABySS, 1.9.0, abyss-users at bcgsc.ca, abyss,
 		http://www.bcgsc.ca/platform/bioinfo/software/abyss)
+m4_include(m4/m4_ax_pthread.m4)
 AM_INIT_AUTOMAKE(1.9.6 foreign subdir-objects)
-AC_CONFIG_SRCDIR([ABYSS/Abyss.cpp])
+AC_CONFIG_SRCDIR([ABYSS/abyss.cc])
 AC_CONFIG_HEADER([config.h])
 
 # Checks for programs.
@@ -15,6 +16,8 @@ AC_PROG_RANLIB
 AC_CHECK_TOOL(GHC, ghc)
 AC_CHECK_TOOL(GHC_PKG, ghc-pkg)
 AM_CONDITIONAL([HAVE_GHC_MMAP], ["$GHC_PKG" list |grep -q mmap])
+AC_CHECK_PROG(PANDOC, pandoc, yes)
+AM_CONDITIONAL([HAVE_PANDOC], [test x"$PANDOC" = x"yes"])
 
 # Checks for header files.
 AC_CHECK_HEADERS([dlfcn.h fcntl.h float.h limits.h \
@@ -75,23 +78,20 @@ AC_CHECK_DECL(HOST_NAME_MAX, [],
 AC_ARG_WITH(boost, AS_HELP_STRING([--with-boost=PATH],
 			[specify directory for the boost header files]))
 if test "$with_boost" -a -d "$with_boost"; then
-	boost_cppflags="-isystem$with_boost"
+	boost_cppflags="-isystem$with_boost -isystem$with_boost/include"
 fi
+
 # MPI
 AC_ARG_WITH(mpi, AS_HELP_STRING([--with-mpi=PATH],
 	[specify prefix directory for the installed MPI parallel
 	computing library]))
 if test "$with_mpi" -a -d "$with_mpi"; then
 	mpi_cppflags="-isystem$with_mpi/include"
-	mpi_ldflags="-L$with_mpi/lib"
-fi
-
-# GTest
-AC_ARG_WITH(gtest, AS_HELP_STRING([--with-gtest=PATH],
-	[specify prefix directory for the installed gtest library]))
-if test "$with_gtest" -a -d "$with_gtest"; then
-	gtest_cppflags="-I$with_gtest/include"
-	gtest_ldflags="-L$with_gtest/lib"
+	if test -d "$with_mpi/lib64"; then
+		mpi_ldflags="-L$with_mpi/lib64"
+	else
+		mpi_ldflags="-L$with_mpi/lib"
+	fi
 fi
 
 AC_ARG_ENABLE(mpich, AS_HELP_STRING([--enable-mpich],
@@ -99,6 +99,22 @@ AC_ARG_ENABLE(mpich, AS_HELP_STRING([--enable-mpich],
 AC_ARG_ENABLE(lammpi, AS_HELP_STRING([--enable-lammpi],
 	[use LAM/MPI (default is to use Open MPI)]))
 
+# SQLite
+AC_ARG_WITH(sqlite, AS_HELP_STRING([--with-sqlite=PATH],
+	[specify prefix directory for the installed sqlite library]))
+if test "$with_sqlite" -a "$with_sqlite" != "no" -a -d "$with_sqlite"; then
+	sqlite_cppflags="-I$with_sqlite/include"
+	sqlite_ldflags="-L$with_sqlite/lib -lsqlite3"
+fi
+
+# SparseHash
+AC_ARG_WITH(sparsehash, AS_HELP_STRING([--with-sparsehash=PATH],
+	[specify prefix directory for the installed spasehash library]))
+if test "$with_sparsehash" -a "$with_sparsehash" != "no" -a -d "$with_sparsehash" ; then
+	sparsehash_cppflags="-isystem$with_sparsehash/include"
+	sparsehash_ldflags="-L$with_sparsehash/lib"
+fi
+
 AC_ARG_ENABLE(fm, AS_HELP_STRING([--enable-fm],
 	[specify the width of the FM-index in bits (default is 64-bit)]),
 	[], [enable_fm=64])
@@ -106,19 +122,24 @@ AC_DEFINE_UNQUOTED(FMBITS, $enable_fm,
 				   [Width of bits of the FM-index in bits])
 
 AC_ARG_ENABLE(maxk, AS_HELP_STRING([--enable-maxk=N],
-	[set the maximum k-mer length (default is 64)]),
-	[], [enable_maxk=64])
+	[set the maximum k-mer length (default is 96)]),
+	[], [enable_maxk=96])
 AC_DEFINE_UNQUOTED(MAX_KMER, [$enable_maxk], [maximum k-mer length])
 
 # Find the absolute path to the source.
 my_abs_srcdir=$(cd $srcdir; pwd)
 
 # Set compiler flags.
-boost_ver=1.55.0
-boost_ver_dir=boost_1_55_0
+boost_ver=1.56.0
+boost_ver_dir=boost_1_56_0
 AC_SUBST(CPPFLAGS,
-		 "-I$my_abs_srcdir $boost_cppflags $mpi_cppflags $gtest_cppflags $CPPFLAGS -isystem$my_abs_srcdir/$boost_ver_dir")
-AC_SUBST(LDFLAGS, "$mpi_ldflags $gtest_ldflags $LDFLAGS")
+		 "-I$my_abs_srcdir $boost_cppflags $mpi_cppflags $sqlite_cppflags $sparsehash_cppflags $CPPFLAGS -isystem$my_abs_srcdir/$boost_ver_dir")
+AC_SUBST(LDFLAGS, "$mpi_ldflags $sqlite_ldflags $sparsehash_ldflags $LDFLAGS")
+
+# Check for pthread.h / libpthread
+# (optional 'make check' dependency)
+AX_PTHREAD([have_pthread="yes"])
+AM_CONDITIONAL([HAVE_PTHREAD], [test x"$have_pthread" = x"yes"])
 
 # Check for the MPI parallel computing library.
 libs="$LIBS"
@@ -138,7 +159,7 @@ elif test "$enable_lammpi"; then
 	AC_CHECK_LIB([lam], [lam_mutex_lock])
 	AC_CHECK_LIB([mpi], [MPI_Init])
 	AC_LANG_PUSH([C++])
-	AC_CHECK_LIB([lammpi++], [main]) 
+	AC_CHECK_LIB([lammpi++], [main])
 	AC_LANG_POP([C++])
 else
 	AC_CHECK_LIB([mpi], [MPI_Init])
@@ -190,13 +211,16 @@ if test $ac_cv_header_boost_property_map_property_map_hpp != yes; then
 	cd -])
 fi
 
-# Check for gtest
+# Check for SQLite
 libs="$LIBS"
-AC_CHECK_HEADERS([gtest/gtest.h])
-AC_CHECK_LIB([pthread], [pthread_create])
-AC_CHECK_LIB([gtest_main],[main])
-AM_CONDITIONAL([HAVE_GTEST], [test $ac_cv_header_gtest_gtest_h = yes -a $ac_cv_lib_gtest_main_main = yes])
-AC_SUBST(GTEST_LIBS, "$LIBS")
+if test "$with_sqlite" != "no"; then
+	AC_CHECK_HEADERS([sqlite3.h])
+	AC_CHECK_LIB([sqlite3],[main])
+fi
+if (test "$ac_cv_header_sqlite3_h" = "yes" -a "$ac_cv_lib_sqlite3_main" = "yes"); then
+	AC_DEFINE(_SQL, 1, [Define to 1 if you have sqlite lib/header])
+fi
+AC_SUBST(SQLITE_LIBS, "$LIBS")
 LIBS=$libs
 
 # Check for OpenMP.
@@ -206,7 +230,21 @@ if test -z $OPENMP_CXXFLAGS; then
 fi
 
 # Set compiler flags.
-AC_SUBST(AM_CXXFLAGS, '-Wall -Wextra -Werror')
+
+AC_ARG_ENABLE([werror], AS_HELP_STRING([--disable-werror],
+	[do not treat compiler warnings as errors]))
+
+if test x"$enable_werror" = x"no"; then
+	AC_SUBST(AM_CXXFLAGS, '-Wall -Wextra')
+elif test x"$enable_werror" = x"yes"; then
+	AC_SUBST(AM_CXXFLAGS, '-Wall -Wextra -Werror')
+else
+	# default
+	AC_SUBST(AM_CXXFLAGS, '-Wall -Wextra')
+fi
+
+# Build abyss-paired-dbg and abyss-paired-dbg-mpi
+AM_CONDITIONAL([PAIRED_DBG], [true])
 
 AC_CONFIG_FILES([
 	Makefile
@@ -235,19 +273,31 @@ AC_CONFIG_FILES([
 	SimpleGraph/Makefile
 	MergePaths/Makefile
 	KAligner/Makefile
+	PairedDBG/Makefile
 	ParseAligns/Makefile
 	PathOverlap/Makefile
 	Consensus/Makefile
 	FilterGraph/Makefile
 	GapFiller/Makefile
+	Sealer/Makefile
+	lib/gtest-1.7.0/Makefile
 	Unittest/Makefile
 	LogKmerCount/Makefile
 	Bloom/Makefile
+	DataBase/Makefile
 ])
-AC_OUTPUT
 
-if test $ac_cv_header_google_sparse_hash_map != yes; then
-	AC_MSG_WARN([ABySS should be compiled with Google sparsehash to
+if test "$with_sparsehash" != "no" -a "$ac_cv_header_google_sparse_hash_map" != "yes"; then
+	AC_MSG_ERROR([ABySS should be compiled with Google sparsehash to
 	reduce memory usage. It may be downloaded here:
-	http://code.google.com/p/google-sparsehash])
+	http://code.google.com/p/google-sparsehash
+
+	If you do not wish to use sparsehash, specify --without-sparsehash.])
+fi
+
+if test $ac_cv_header_pthread_h != yes -o $ac_cv_lib_pthread_pthread_create != yes; then
+	AC_MSG_WARN([Warning: Running the unit tests with 'make check' has been disabled
+	because pthread.h and/or libpthread could not be found.])
 fi
+
+AC_OUTPUT
diff --git a/doc/ABYSS.1 b/doc/ABYSS.1
index ce3b3fb..6b90240 100644
--- a/doc/ABYSS.1
+++ b/doc/ABYSS.1
@@ -1,4 +1,4 @@
-.TH ABYSS "1" "2014-May" "ABYSS (ABySS) 1.5.2" "User Commands"
+.TH ABYSS "1" "2015-May" "ABYSS (ABySS) 1.9.0" "User Commands"
 .SH NAME
 ABYSS \- assemble short reads into contigs
 .SH SYNOPSIS
@@ -94,4 +94,4 @@ Written by Jared Simpson and Shaun Jackman.
 .SH "REPORTING BUGS"
 Report bugs to <abyss-users at bcgsc.ca>.
 .SH COPYRIGHT
-Copyright 2014 Canada's Michael Smith Genome Sciences Centre
+Copyright 2015 Canada's Michael Smith Genome Sciences Centre
diff --git a/doc/abyss-pe.1 b/doc/abyss-pe.1
index 42385af..349ee05 100644
--- a/doc/abyss-pe.1
+++ b/doc/abyss-pe.1
@@ -1,4 +1,4 @@
-.TH abyss-pe "1" "2014-May" "abyss-pe (ABySS) 1.5.2" "User Commands"
+.TH abyss-pe "1" "2015-May" "abyss-pe (ABySS) 1.9.0" "User Commands"
 .SH NAME
 abyss-pe - assemble reads into contigs
 .SH SYNOPSIS
@@ -67,7 +67,10 @@ minimum erosion k-mer coverage per strand [1]
 number of threads [2]
 .TP
 .B k
-size of k-mer (bp)
+size of a k-mer (when K is not set) or the span of a k-mer pair (when K is set)
+.TP
+.B K
+size of a single k-mer in a k-mer pair (bp)
 .TP
 .B l
 minimum alignment length of a read (bp) [k]
@@ -123,9 +126,10 @@ the number of processes of an MPI assembly
 the path to mpirun
 .TP
 .B aligner
-the program to use to align the reads to the contigs [map]
+The program to use to align the reads to the contigs [map].
 .br
-map, kaligner, bwa, bwasw, bowtie or bowtie2
+Permitted values are: map, kaligner, bwa, bwasw, bowtie, bowtie2, dida.
+See the \fBDIDA\fR section below for further info on the dida option.
 .TP
 .B cs
 convert colour-space contigs to nucleotide contigs following assembly
@@ -210,6 +214,47 @@ Display the versions of all programs used by abyss-pe.
 .B help
 Display a helpful message.
 
+.SH "DIDA"
+ABySS supports the use of DIDA (Distributed Indexing Dispatched
+Alignment), an MPI-based alignment framework for computing sequence
+alignments across multiple machines. To use DIDA with ABySS, first
+download and install DIDA from http://www.bcgsc.ca/platform/bioinfo/software/dida,
+then specify `dida` as the value of the \fBaligner\fR parameter to
+\fBabyss-pe\fR.
+
+.SS "DIDA-related abyss-pe parameters"
+.TP
+.B DIDA_MPIRUN
+The `mpirun` command used to run DIDA jobs.
+.TP
+.B DIDA_RUN_OPTIONS
+Runtime options such as number of threads per MPI rank
+and values for environment variables (e.g. PATH, LD_LIBRARY_PATH).
+Run `abyss-dida --help` for a list of available options.
+.TP
+.B DIDA_OPTIONS
+Options that are passed directly to the DIDA binary. For example,
+this can be used to control the minimum alignment length threshold.
+Run `dida-wrapper --help` for a list of available options.
+
+.SS "MPI COMPATIBILITY"
+Due to its use of multi-threading, DIDA has known deadlocking issues
+with OpenMPI.  Using the MPICH MPI library is strongly recommmended
+when running assemblies with DIDA. Testing was done with MPICH 3.1.3,
+compiled with --enable-threads=funneled.
+
+.SS "EXAMPLE"
+The recommended runtime configuration for DIDA is 1 MPI rank per
+machine and 1 thread per CPU core. For example, to run an
+assembly across 3 cluster nodes with 12 cores each, do:
+
+	abyss-pe k=64 name=ecoli in='reads1.fa reads2.fa' aligner=dida DIDA_RUN_OPTIONS='-j12' DIDA_MPIRUN='mpirun -np 3 -ppn 1 -bind-to board'
+
+This example uses the MPICH command line options for `mpirun`.
+Here, `-np 3` indicates the number of MPI ranks, `-ppn 1` indicates
+the number of MPI ranks per "node", and `-bind-to board` defines
+a "node" to be a motherboard (i.e. a full machine).
+
 .SH "ENVIRONMENT VARIABLES"
 Any parameter that may be specified on the command line may also be
 specified in an environment variable.
@@ -266,4 +311,4 @@ Written by Shaun Jackman.
 .SH "REPORTING BUGS"
 Report bugs to <abyss-users at googlegroups.com>.
 .SH COPYRIGHT
-Copyright 2014 Canada's Michael Smith Genome Sciences Centre
+Copyright 2015 Canada's Michael Smith Genome Sciences Centre
diff --git a/doc/abyss-tofastq.1 b/doc/abyss-tofastq.1
index 1d8e9ec..e997080 100644
--- a/doc/abyss-tofastq.1
+++ b/doc/abyss-tofastq.1
@@ -1,4 +1,4 @@
-.TH abyss-tofastq "1" "2014-May" "ABySS 1.5.2" "User Commands"
+.TH abyss-tofastq "1" "2015-May" "ABySS 1.9.0" "User Commands"
 .SH NAME
 abyss-tofastq \- convert various file formats to FASTQ format
 .br
@@ -18,4 +18,4 @@ Written by Shaun Jackman.
 .SH "REPORTING BUGS"
 Report bugs to <abyss-users at bcgsc.ca>.
 .SH COPYRIGHT
-Copyright 2014 Canada's Michael Smith Genome Sciences Centre
+Copyright 2015 Canada's Michael Smith Genome Sciences Centre
diff --git a/doc/flowchart.graffle b/doc/flowchart.graffle
index fa3d897..c00b837 100644
--- a/doc/flowchart.graffle
+++ b/doc/flowchart.graffle
@@ -5198,7 +5198,7 @@
 {\colortbl;\red255\green255\blue255;}
 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
 
-\f0\b\fs28 \cf0 ABySS paired-end pipeline version 1.5.2}</string>
+\f0\b\fs28 \cf0 ABySS paired-end pipeline version 1.9.0}</string>
 				<key>VerticalPad</key>
 				<integer>0</integer>
 			</dict>
diff --git a/lib/gtest-1.7.0/CHANGES b/lib/gtest-1.7.0/CHANGES
new file mode 100644
index 0000000..0552132
--- /dev/null
+++ b/lib/gtest-1.7.0/CHANGES
@@ -0,0 +1,157 @@
+Changes for 1.7.0:
+
+* New feature: death tests are supported on OpenBSD and in iOS
+  simulator now.
+* New feature: Google Test now implements a protocol to allow
+  a test runner to detect that a test program has exited
+  prematurely and report it as a failure (before it would be
+  falsely reported as a success if the exit code is 0).
+* New feature: Test::RecordProperty() can now be used outside of the
+  lifespan of a test method, in which case it will be attributed to
+  the current test case or the test program in the XML report.
+* New feature (potentially breaking): --gtest_list_tests now prints
+  the type parameters and value parameters for each test.
+* Improvement: char pointers and char arrays are now escaped properly
+  in failure messages.
+* Improvement: failure summary in XML reports now includes file and
+  line information.
+* Improvement: the <testsuites> XML element now has a timestamp attribute.
+* Improvement: When --gtest_filter is specified, XML report now doesn't
+  contain information about tests that are filtered out.
+* Fixed the bug where long --gtest_filter flag values are truncated in
+  death tests.
+* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a
+  function instead of a macro in order to work better with Clang.
+* Compatibility fixes with C++ 11 and various platforms.
+* Bug/warning fixes.
+
+Changes for 1.6.0:
+
+* New feature: ADD_FAILURE_AT() for reporting a test failure at the
+  given source location -- useful for writing testing utilities.
+* New feature: the universal value printer is moved from Google Mock
+  to Google Test.
+* New feature: type parameters and value parameters are reported in
+  the XML report now.
+* A gtest_disable_pthreads CMake option.
+* Colored output works in GNU Screen sessions now.
+* Parameters of value-parameterized tests are now printed in the
+  textual output.
+* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are
+  now correctly reported.
+* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to
+  ostream.
+* More complete handling of exceptions.
+* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter
+  name is already used by another library.
+* --gtest_catch_exceptions is now true by default, allowing a test
+  program to continue after an exception is thrown.
+* Value-parameterized test fixtures can now derive from Test and
+  WithParamInterface<T> separately, easing conversion of legacy tests.
+* Death test messages are clearly marked to make them more
+  distinguishable from other messages.
+* Compatibility fixes for Android, Google Native Client, MinGW, HP UX,
+  PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear),
+  IBM XL C++ (Visual Age C++), and C++0x.
+* Bug fixes and implementation clean-ups.
+* Potentially incompatible changes: disables the harmful 'make install'
+  command in autotools.
+
+Changes for 1.5.0:
+
+ * New feature: assertions can be safely called in multiple threads
+   where the pthreads library is available.
+ * New feature: predicates used inside EXPECT_TRUE() and friends
+   can now generate custom failure messages.
+ * New feature: Google Test can now be compiled as a DLL.
+ * New feature: fused source files are included.
+ * New feature: prints help when encountering unrecognized Google Test flags.
+ * Experimental feature: CMake build script (requires CMake 2.6.4+).
+ * Experimental feature: the Pump script for meta programming.
+ * double values streamed to an assertion are printed with enough precision
+   to differentiate any two different values.
+ * Google Test now works on Solaris and AIX.
+ * Build and test script improvements.
+ * Bug fixes and implementation clean-ups.
+
+ Potentially breaking changes:
+
+ * Stopped supporting VC++ 7.1 with exceptions disabled.
+ * Dropped support for 'make install'.
+
+Changes for 1.4.0:
+
+ * New feature: the event listener API
+ * New feature: test shuffling
+ * New feature: the XML report format is closer to junitreport and can
+   be parsed by Hudson now.
+ * New feature: when a test runs under Visual Studio, its failures are
+   integrated in the IDE.
+ * New feature: /MD(d) versions of VC++ projects.
+ * New feature: elapsed time for the tests is printed by default.
+ * New feature: comes with a TR1 tuple implementation such that Boost
+   is no longer needed for Combine().
+ * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
+ * New feature: the Xcode project can now produce static gtest
+   libraries in addition to a framework.
+ * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
+   Symbian, gcc, and C++Builder.
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.3.0:
+
+ * New feature: death tests on Windows, Cygwin, and Mac.
+ * New feature: ability to use Google Test assertions in other testing
+   frameworks.
+ * New feature: ability to run disabled test via
+   --gtest_also_run_disabled_tests.
+ * New feature: the --help flag for printing the usage.
+ * New feature: access to Google Test flag values in user code.
+ * New feature: a script that packs Google Test into one .h and one
+   .cc file for easy deployment.
+ * New feature: support for distributing test functions to multiple
+   machines (requires support from the test runner).
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.2.1:
+
+ * Compatibility fixes for Linux IA-64 and IBM z/OS.
+ * Added support for using Boost and other TR1 implementations.
+ * Changes to the build scripts to support upcoming release of Google C++
+   Mocking Framework.
+ * Added Makefile to the distribution package.
+ * Improved build instructions in README.
+
+Changes for 1.2.0:
+
+ * New feature: value-parameterized tests.
+ * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
+   macros.
+ * Changed the XML report format to match JUnit/Ant's.
+ * Added tests to the Xcode project.
+ * Added scons/SConscript for building with SCons.
+ * Added src/gtest-all.cc for building Google Test from a single file.
+ * Fixed compatibility with Solaris and z/OS.
+ * Enabled running Python tests on systems with python 2.3 installed,
+   e.g. Mac OS X 10.4.
+ * Bug fixes.
+
+Changes for 1.1.0:
+
+ * New feature: type-parameterized tests.
+ * New feature: exception assertions.
+ * New feature: printing elapsed time of tests.
+ * Improved the robustness of death tests.
+ * Added an Xcode project and samples.
+ * Adjusted the output format on Windows to be understandable by Visual Studio.
+ * Minor bug fixes.
+
+Changes for 1.0.1:
+
+ * Added project files for Visual Studio 7.1.
+ * Fixed issues with compiling on Mac OS X.
+ * Fixed issues with compiling on Cygwin.
+
+Changes for 1.0.0:
+
+ * Initial Open Source release of Google Test
diff --git a/lib/gtest-1.7.0/CONTRIBUTORS b/lib/gtest-1.7.0/CONTRIBUTORS
new file mode 100644
index 0000000..feae2fc
--- /dev/null
+++ b/lib/gtest-1.7.0/CONTRIBUTORS
@@ -0,0 +1,37 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Testing Framework project.  People
+# who commit code to the project are encouraged to add their names
+# here.  Please keep the list sorted by first names.
+
+Ajay Joshi <jaj at google.com>
+Balázs Dán <balazs.dan at gmail.com>
+Bharat Mediratta <bharat at menalto.com>
+Chandler Carruth <chandlerc at google.com>
+Chris Prince <cprince at google.com>
+Chris Taylor <taylorc at google.com>
+Dan Egnor <egnor at google.com>
+Eric Roman <eroman at chromium.org>
+Hady Zalek <hady.zalek at gmail.com>
+Jeffrey Yasskin <jyasskin at google.com>
+Jói Sigurðsson <joi at google.com>
+Keir Mierle <mierle at gmail.com>
+Keith Ray <keith.ray at gmail.com>
+Kenton Varda <kenton at google.com>
+Manuel Klimek <klimek at google.com>
+Markus Heule <markus.heule at gmail.com>
+Mika Raento <mikie at iki.fi>
+Miklós Fazekas <mfazekas at szemafor.com>
+Pasi Valminen <pasi.valminen at gmail.com>
+Patrick Hanna <phanna at google.com>
+Patrick Riley <pfr at google.com>
+Peter Kaminski <piotrk at google.com>
+Preston Jackson <preston.a.jackson at gmail.com>
+Rainer Klaffenboeck <rainer.klaffenboeck at dynatrace.com>
+Russ Cox <rsc at google.com>
+Russ Rufer <russ at pentad.com>
+Sean Mcafee <eefacm at gmail.com>
+Sigurður Ásgeirsson <siggi at google.com>
+Tracy Bialik <tracy at pentad.com>
+Vadim Berman <vadimb at google.com>
+Vlad Losev <vladl at google.com>
+Zhanyong Wan <wan at google.com>
diff --git a/lib/gtest-1.7.0/LICENSE b/lib/gtest-1.7.0/LICENSE
new file mode 100644
index 0000000..1941a11
--- /dev/null
+++ b/lib/gtest-1.7.0/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted 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 Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+OWNER OR 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.
diff --git a/lib/gtest-1.7.0/Makefile.am b/lib/gtest-1.7.0/Makefile.am
new file mode 100644
index 0000000..b819468
--- /dev/null
+++ b/lib/gtest-1.7.0/Makefile.am
@@ -0,0 +1,42 @@
+check_LIBRARIES = libgtest.a libgtest_main.a
+
+# gtest source files that we don't compile directly.  They are
+# #included by gtest-all.cc.
+EXTRA_DIST = \
+  src/gtest-death-test.cc \
+  src/gtest-filepath.cc \
+  src/gtest-internal-inl.h \
+  src/gtest-port.cc \
+  src/gtest-printers.cc \
+  src/gtest-test-part.cc \
+  src/gtest-typed-test.cc \
+  src/gtest.cc \
+  include/gtest/gtest.h \
+  include/gtest/gtest-death-test.h \
+  include/gtest/gtest-message.h \
+  include/gtest/gtest-param-test.h \
+  include/gtest/gtest-printers.h \
+  include/gtest/gtest-spi.h \
+  include/gtest/gtest-test-part.h \
+  include/gtest/gtest-typed-test.h \
+  include/gtest/gtest.h \
+  include/gtest/gtest_pred_impl.h \
+  include/gtest/gtest_prod.h \
+  include/gtest/internal/gtest-death-test-internal.h \
+  include/gtest/internal/gtest-filepath.h \
+  include/gtest/internal/gtest-internal.h \
+  include/gtest/internal/gtest-linked_ptr.h \
+  include/gtest/internal/gtest-param-util-generated.h \
+  include/gtest/internal/gtest-param-util.h \
+  include/gtest/internal/gtest-port.h \
+  include/gtest/internal/gtest-string.h \
+  include/gtest/internal/gtest-tuple.h \
+  include/gtest/internal/gtest-type-util.h
+
+libgtest_a_CPPFLAGS = -I$(top_srcdir) -isystem $(top_srcdir)/lib/gtest-1.7.0/include
+libgtest_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-missing-field-initializers
+libgtest_a_SOURCES = src/gtest-all.cc
+
+libgtest_main_a_CPPFLAGS = -I$(top_srcdir) -isystem $(top_srcdir)/lib/gtest-1.7.0/include
+libgtest_main_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-missing-field-initializers
+libgtest_main_a_SOURCES = src/gtest_main.cc src/gtest-all.cc
diff --git a/lib/gtest-1.7.0/README b/lib/gtest-1.7.0/README
new file mode 100644
index 0000000..26f35a8
--- /dev/null
+++ b/lib/gtest-1.7.0/README
@@ -0,0 +1,435 @@
+Google C++ Testing Framework
+============================
+
+http://code.google.com/p/googletest/
+
+Overview
+--------
+
+Google's framework for writing C++ tests on a variety of platforms
+(Linux, Mac OS X, Windows, Windows CE, Symbian, etc).  Based on the
+xUnit architecture.  Supports automatic test discovery, a rich set of
+assertions, user-defined assertions, death tests, fatal and non-fatal
+failures, various options for running the tests, and XML test report
+generation.
+
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development.  There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available.  Please
+join us!
+
+Requirements for End Users
+--------------------------
+
+Google Test is designed to have fairly minimal requirements to build
+and use with your projects, but there are some.  Currently, we support
+Linux, Windows, Mac OS X, and Cygwin.  We will also make our best
+effort to support other platforms (e.g. Solaris, AIX, and z/OS).
+However, since core members of the Google Test project have no access
+to these platforms, Google Test may have outstanding issues there.  If
+you notice any problems on your platform, please notify
+googletestframework at googlegroups.com.  Patches for fixing them are
+even more welcome!
+
+### Linux Requirements ###
+
+These are the base requirements to build and use Google Test from a source
+package (as described below):
+  * GNU-compatible Make or gmake
+  * POSIX-standard shell
+  * POSIX(-2) Regular Expressions (regex.h)
+  * A C++98-standard-compliant compiler
+
+### Windows Requirements ###
+
+  * Microsoft Visual C++ 7.1 or newer
+
+### Cygwin Requirements ###
+
+  * Cygwin 1.5.25-14 or newer
+
+### Mac OS X Requirements ###
+
+  * Mac OS X 10.4 Tiger or newer
+  * Developer Tools Installed
+
+Also, you'll need CMake 2.6.4 or higher if you want to build the
+samples using the provided CMake script, regardless of the platform.
+
+Requirements for Contributors
+-----------------------------
+
+We welcome patches.  If you plan to contribute a patch, you need to
+build Google Test and its own tests from an SVN checkout (described
+below), which has further requirements:
+
+  * Python version 2.3 or newer (for running some of the tests and
+    re-generating certain source files from templates)
+  * CMake 2.6.4 or newer
+
+Getting the Source
+------------------
+
+There are two primary ways of getting Google Test's source code: you
+can download a stable source release in your preferred archive format,
+or directly check out the source from our Subversion (SVN) repositary.
+The SVN checkout requires a few extra steps and some extra software
+packages on your system, but lets you track the latest development and
+make patches much more easily, so we highly encourage it.
+
+### Source Package ###
+
+Google Test is released in versioned source packages which can be
+downloaded from the download page [1].  Several different archive
+formats are provided, but the only difference is the tools used to
+manipulate them, and the size of the resulting file.  Download
+whichever you are most comfortable with.
+
+  [1] http://code.google.com/p/googletest/downloads/list
+
+Once the package is downloaded, expand it using whichever tools you
+prefer for that type.  This will result in a new directory with the
+name "gtest-X.Y.Z" which contains all of the source code.  Here are
+some examples on Linux:
+
+  tar -xvzf gtest-X.Y.Z.tar.gz
+  tar -xvjf gtest-X.Y.Z.tar.bz2
+  unzip gtest-X.Y.Z.zip
+
+### SVN Checkout ###
+
+To check out the main branch (also known as the "trunk") of Google
+Test, run the following Subversion command:
+
+  svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
+
+Setting up the Build
+--------------------
+
+To build Google Test and your tests that use it, you need to tell your
+build system where to find its headers and source files.  The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
+
+### Generic Build Instructions ###
+
+Suppose you put Google Test in directory ${GTEST_DIR}.  To build it,
+create a library build target (or a project as called by Visual Studio
+and Xcode) to compile
+
+  ${GTEST_DIR}/src/gtest-all.cc
+
+with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR}
+in the normal header search path.  Assuming a Linux-like system and gcc,
+something like the following will do:
+
+  g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
+      -pthread -c ${GTEST_DIR}/src/gtest-all.cc
+  ar -rv libgtest.a gtest-all.o
+
+(We need -pthread as Google Test uses threads.)
+
+Next, you should compile your test source file with
+${GTEST_DIR}/include in the system header search path, and link it
+with gtest and any other necessary libraries:
+
+  g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
+      -o your_test
+
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Test on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin).  It doesn't try to build Google
+Test's own tests.  Instead, it just builds the Google Test library and
+a sample test.  You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+  cd ${GTEST_DIR}/make
+  make
+  ./sample1_unittest
+
+If you see errors, try to tweak the contents of make/Makefile to make
+them go away.  There are instructions in make/Makefile on how to do
+it.
+
+### Using CMake ###
+
+Google Test comes with a CMake build script (CMakeLists.txt) that can
+be used on a wide range of platforms ("C" stands for cross-platofrm.).
+If you don't have CMake installed already, you can download it for
+free from http://www.cmake.org/.
+
+CMake works by generating native makefiles or build projects that can
+be used in the compiler environment of your choice.  The typical
+workflow starts with:
+
+  mkdir mybuild       # Create a directory to hold the build output.
+  cd mybuild
+  cmake ${GTEST_DIR}  # Generate native build scripts.
+
+If you want to build Google Test's samples, you should replace the
+last command with
+
+  cmake -Dgtest_build_samples=ON ${GTEST_DIR}
+
+If you are on a *nix system, you should now see a Makefile in the
+current directory.  Just type 'make' to build gtest.
+
+If you use Windows and have Vistual Studio installed, a gtest.sln file
+and several .vcproj files will be created.  You can then build them
+using Visual Studio.
+
+On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
+
+### Legacy Build Scripts ###
+
+Before settling on CMake, we have been providing hand-maintained build
+projects/scripts for Visual Studio, Xcode, and Autotools.  While we
+continue to provide them for convenience, they are not actively
+maintained any more.  We highly recommend that you follow the
+instructions in the previous two sections to integrate Google Test
+with your existing build system.
+
+If you still need to use the legacy build scripts, here's how:
+
+The msvc\ folder contains two solutions with Visual C++ projects.
+Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
+are ready to build Google Test the same way you build any Visual
+Studio project.  Files that have names ending with -md use DLL
+versions of Microsoft runtime libraries (the /MD or the /MDd compiler
+option).  Files without that suffix use static versions of the runtime
+libraries (the /MT or the /MTd option).  Please note that one must use
+the same option to compile both gtest and the test code.  If you use
+Visual Studio 2005 or above, we recommend the -md version as /MD is
+the default for new projects in these versions of Visual Studio.
+
+On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
+Xcode.  Build the "gtest" target.  The universal binary framework will
+end up in your selected build directory (selected in the Xcode
+"Preferences..." -> "Building" pane and defaults to xcode/build).
+Alternatively, at the command line, enter:
+
+  xcodebuild
+
+This will build the "Release" configuration of gtest.framework in your
+default build location.  See the "xcodebuild" man page for more
+information about building different configurations and building in
+different locations.
+
+If you wish to use the Google Test Xcode project with Xcode 4.x and
+above, you need to either:
+ * update the SDK configuration options in xcode/Config/General.xconfig.
+   Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If
+   you choose this route you lose the ability to target earlier versions
+   of MacOS X.
+ * Install an SDK for an earlier version. This doesn't appear to be
+   supported by Apple, but has been reported to work
+   (http://stackoverflow.com/questions/5378518).
+
+Tweaking Google Test
+--------------------
+
+Google Test can be used in diverse environments.  The default
+configuration may not work (or may not work well) out of the box in
+some environments.  However, you can easily tweak Google Test by
+defining control macros on the compiler command line.  Generally,
+these macros are named like GTEST_XYZ and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below.  For a complete list,
+see file include/gtest/internal/gtest-port.h.
+
+### Choosing a TR1 Tuple Library ###
+
+Some Google Test features require the C++ Technical Report 1 (TR1)
+tuple library, which is not yet available with all compilers.  The
+good news is that Google Test implements a subset of TR1 tuple that's
+enough for its own need, and will automatically use this when the
+compiler doesn't provide TR1 tuple.
+
+Usually you don't need to care about which tuple library Google Test
+uses.  However, if your project already uses TR1 tuple, you need to
+tell Google Test to use the same TR1 tuple library the rest of your
+project uses, or the two tuple implementations will clash.  To do
+that, add
+
+  -DGTEST_USE_OWN_TR1_TUPLE=0
+
+to the compiler flags while compiling Google Test and your tests.  If
+you want to force Google Test to use its own tuple library, just add
+
+  -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
+
+If you don't want Google Test to use tuple at all, add
+
+  -DGTEST_HAS_TR1_TUPLE=0
+
+and all features using tuple will be disabled.
+
+### Multi-threaded Tests ###
+
+Google Test is thread-safe where the pthread library is available.
+After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE
+macro to see whether this is the case (yes if the macro is #defined to
+1, no if it's undefined.).
+
+If Google Test doesn't correctly detect whether pthread is available
+in your environment, you can force it with
+
+  -DGTEST_HAS_PTHREAD=1
+
+or
+
+  -DGTEST_HAS_PTHREAD=0
+
+When Google Test uses pthread, you may need to add flags to your
+compiler and/or linker to select the pthread library, or you'll get
+link errors.  If you use the CMake script or the deprecated Autotools
+script, this is taken care of for you.  If you use your own build
+script, you'll need to read your compiler and linker's manual to
+figure out what flags to add.
+
+### As a Shared Library (DLL) ###
+
+Google Test is compact, so most users can build and link it as a
+static library for the simplicity.  You can choose to use Google Test
+as a shared library (known as a DLL on Windows) if you prefer.
+
+To compile *gtest* as a shared library, add
+
+  -DGTEST_CREATE_SHARED_LIBRARY=1
+
+to the compiler flags.  You'll also need to tell the linker to produce
+a shared library instead - consult your linker's manual for how to do
+it.
+
+To compile your *tests* that use the gtest shared library, add
+
+  -DGTEST_LINKED_AS_SHARED_LIBRARY=1
+
+to the compiler flags.
+
+Note: while the above steps aren't technically necessary today when
+using some compilers (e.g. GCC), they may become necessary in the
+future, if we decide to improve the speed of loading the library (see
+http://gcc.gnu.org/wiki/Visibility for details).  Therefore you are
+recommended to always add the above flags when using Google Test as a
+shared library.  Otherwise a future release of Google Test may break
+your build script.
+
+### Avoiding Macro Name Clashes ###
+
+In C++, macros don't obey namespaces.  Therefore two libraries that
+both define a macro of the same name will clash if you #include both
+definitions.  In case a Google Test macro clashes with another
+library, you can force Google Test to rename its macro to avoid the
+conflict.
+
+Specifically, if both Google Test and some other code define macro
+FOO, you can add
+
+  -DGTEST_DONT_DEFINE_FOO=1
+
+to the compiler flags to tell Google Test to change the macro's name
+from FOO to GTEST_FOO.  Currently FOO can be FAIL, SUCCEED, or TEST.
+For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
+
+  GTEST_TEST(SomeTest, DoesThis) { ... }
+
+instead of
+
+  TEST(SomeTest, DoesThis) { ... }
+
+in order to define a test.
+
+Upgrating from an Earlier Version
+---------------------------------
+
+We strive to keep Google Test releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits.  This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Test.
+
+### Upgrading from 1.3.0 or Earlier ###
+
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library.  See the instructions in section "Choosing a TR1 Tuple
+Library".
+
+### Upgrading from 1.4.0 or Earlier ###
+
+The Autotools build script (configure + make) is no longer officially
+supportted.  You are encouraged to migrate to your own build system or
+use CMake.  If you still need to use Autotools, you can find
+instructions in the README file from Google Test 1.4.0.
+
+On platforms where the pthread library is available, Google Test uses
+it in order to be thread-safe.  See the "Multi-threaded Tests" section
+for what this means to your build script.
+
+If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
+Test will no longer compile.  This should affect very few people, as a
+large portion of STL (including <string>) doesn't compile in this mode
+anyway.  We decided to stop supporting it in order to greatly simplify
+Google Test's implementation.
+
+Developing Google Test
+----------------------
+
+This section discusses how to make your own changes to Google Test.
+
+### Testing Google Test Itself ###
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you can use CMake:
+
+  mkdir mybuild
+  cd mybuild
+  cmake -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Make sure you have Python installed, as some of Google Test's tests
+are written in Python.  If the cmake command complains about not being
+able to find Python ("Could NOT find PythonInterp (missing:
+PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
+executable can be found:
+
+  cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
+
+Next, you can build Google Test and all of its own tests.  On *nix,
+this is usually done by 'make'.  To run the tests, do
+
+  make test
+
+All tests should pass.
+
+### Regenerating Source Files ###
+
+Some of Google Test's source files are generated from templates (not
+in the C++ sense) using a script.  A template file is named FOO.pump,
+where FOO is the name of the file it will generate.  For example, the
+file include/gtest/internal/gtest-type-util.h.pump is used to generate
+gtest-type-util.h in the same directory.
+
+Normally you don't need to worry about regenerating the source files,
+unless you need to modify them.  In that case, you should modify the
+corresponding .pump files instead and run the pump.py Python script to
+regenerate them.  You can find pump.py in the scripts/ directory.
+Read the Pump manual [2] for how to use it.
+
+  [2] http://code.google.com/p/googletest/wiki/PumpManual
+
+### Contributing a Patch ###
+
+We welcome patches.  Please read the Google Test developer's guide [3]
+for how you can contribute.  In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+  [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
+
+Happy testing!
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-death-test.h b/lib/gtest-1.7.0/include/gtest/gtest-death-test.h
new file mode 100644
index 0000000..957a69c
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-death-test.h
@@ -0,0 +1,294 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests.  It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include "gtest/internal/gtest-death-test-internal.h"
+
+namespace testing {
+
+// This flag controls the style of death tests.  Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process.  Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests.  IMPORTANT: This is an internal utility.  Using it may break the
+// implementation of death tests.  User code MUST NOT use it.
+GTEST_API_ bool InDeathTestChild();
+
+}  // namespace internal
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+//   1. It generates a warning if there is more than one active
+//   thread.  This is because it's safe to fork() or clone() only
+//   when there is a single thread.
+//
+//   2. The parent process clone()s a sub-process and runs the death
+//   test in it; the sub-process exits with code 0 at the end of the
+//   death test, if it hasn't exited already.
+//
+//   3. The parent process waits for the sub-process to terminate.
+//
+//   4. The parent process checks the exit code and error message of
+//   the sub-process.
+//
+// Examples:
+//
+//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+//   for (int i = 0; i < 5; i++) {
+//     EXPECT_DEATH(server.ProcessRequest(i),
+//                  "Invalid request .* in ProcessRequest()")
+//                  << "Failed to die on request " << i;
+//   }
+//
+//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+//   bool KilledBySIGHUP(int exit_code) {
+//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+//   }
+//
+//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// On the regular expressions used in death tests:
+//
+//   On POSIX-compliant systems (*nix), we use the <regex.h> library,
+//   which uses the POSIX extended regex syntax.
+//
+//   On other platforms (e.g. Windows), we only support a simple regex
+//   syntax implemented as part of Google Test.  This limited
+//   implementation should be enough most of the time when writing
+//   death tests; though it lacks many features you can find in PCRE
+//   or POSIX extended regex syntax.  For example, we don't support
+//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+//   repetition count ("x{5,7}"), among others.
+//
+//   Below is the syntax that we do support.  We chose it to be a
+//   subset of both PCRE and POSIX extended regex, so it's easy to
+//   learn wherever you come from.  In the following: 'A' denotes a
+//   literal character, period (.), or a single \\ escape sequence;
+//   'x' and 'y' denote regular expressions; 'm' and 'n' are for
+//   natural numbers.
+//
+//     c     matches any literal character c
+//     \\d   matches any decimal digit
+//     \\D   matches any character that's not a decimal digit
+//     \\f   matches \f
+//     \\n   matches \n
+//     \\r   matches \r
+//     \\s   matches any ASCII whitespace, including \n
+//     \\S   matches any character that's not a whitespace
+//     \\t   matches \t
+//     \\v   matches \v
+//     \\w   matches any letter, _, or decimal digit
+//     \\W   matches any character that \\w doesn't match
+//     \\c   matches any literal character c, which must be a punctuation
+//     .     matches any single character except \n
+//     A?    matches 0 or 1 occurrences of A
+//     A*    matches 0 or many occurrences of A
+//     A+    matches 1 or many occurrences of A
+//     ^     matches the beginning of a string (not that of each line)
+//     $     matches the end of a string (not that of each line)
+//     xy    matches x followed by y
+//
+//   If you accidentally use PCRE or POSIX extended regex features
+//   not implemented by us, you will get a run-time failure.  In that
+//   case, please try to rewrite your regular expression within the
+//   above syntax.
+//
+//   This implementation is *not* meant to be as highly tuned or robust
+//   as a compiled regex library, but should perform well enough for a
+//   death test, which already incurs significant overhead by launching
+//   a child process.
+//
+// Known caveats:
+//
+//   A "threadsafe" style death test obtains the path to the test
+//   program from argv[0] and re-executes it in the sub-process.  For
+//   simplicity, the current implementation doesn't search the PATH
+//   when launching the sub-process.  This means that the user must
+//   invoke the test program via a path that contains at least one
+//   path separator (e.g. path/to/foo_test and
+//   /absolute/path/to/bar_test are fine, but foo_test is not).  This
+//   is rarely a problem as people usually don't put the test binary
+//   directory in PATH.
+//
+// TODO(wan at google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+# define ASSERT_EXIT(statement, predicate, regex) \
+    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_EXIT(statement, predicate, regex) \
+    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+# define ASSERT_DEATH(statement, regex) \
+    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+# define EXPECT_DEATH(statement, regex) \
+    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class GTEST_API_ ExitedWithCode {
+ public:
+  explicit ExitedWithCode(int exit_code);
+  bool operator()(int exit_status) const;
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ExitedWithCode& other);
+
+  const int exit_code_;
+};
+
+# if !GTEST_OS_WINDOWS
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class GTEST_API_ KilledBySignal {
+ public:
+  explicit KilledBySignal(int signum);
+  bool operator()(int exit_status) const;
+ private:
+  const int signum_;
+};
+# endif  // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+//   if (sideeffect) {
+//     *sideeffect = 12;
+//   }
+//   LOG(DFATAL) << "death";
+//   return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+//   int sideeffect = 0;
+//   // Only asserts in dbg.
+//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+//   // opt-mode has sideeffect visible.
+//   EXPECT_EQ(12, sideeffect);
+// #else
+//   // dbg-mode no visible sideeffect.
+//   EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects.  A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+//   // Side-effects here will have an effect after this statement in
+//   // opt mode, but none in debug mode.
+//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+# ifdef NDEBUG
+
+#  define EXPECT_DEBUG_DEATH(statement, regex) \
+  GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+#  define ASSERT_DEBUG_DEATH(statement, regex) \
+  GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+# else
+
+#  define EXPECT_DEBUG_DEATH(statement, regex) \
+  EXPECT_DEATH(statement, regex)
+
+#  define ASSERT_DEBUG_DEATH(statement, regex) \
+  ASSERT_DEATH(statement, regex)
+
+# endif  // NDEBUG for EXPECT_DEBUG_DEATH
+#endif  // GTEST_HAS_DEATH_TEST
+
+// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
+// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
+// death tests are supported; otherwise they just issue a warning.  This is
+// useful when you are combining death test assertions with normal test
+// assertions in one test.
+#if GTEST_HAS_DEATH_TEST
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+    EXPECT_DEATH(statement, regex)
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+    ASSERT_DEATH(statement, regex)
+#else
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+    GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+    GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
+#endif
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-message.h b/lib/gtest-1.7.0/include/gtest/gtest-message.h
new file mode 100644
index 0000000..fe879bc
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-message.h
@@ -0,0 +1,250 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+
+#include "gtest/internal/gtest-port.h"
+
+// Ensures that there is at least one operator<< in the global namespace.
+// See Message& operator<<(...) below for why.
+void operator<<(const testing::internal::Secret&, int);
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+//   1. You stream a bunch of values to a Message object.
+//      It will remember the text in a stringstream.
+//   2. Then you stream the Message object to an ostream.
+//      This causes the text in the Message to be streamed
+//      to the ostream.
+//
+// For example;
+//
+//   testing::Message foo;
+//   foo << 1 << " != " << 2;
+//   std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from.  In particular, its
+// destructor is not virtual.
+//
+// Note that stringstream behaves differently in gcc and in MSVC.  You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do).  The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class GTEST_API_ Message {
+ private:
+  // The type of basic IO manipulators (endl, ends, and flush) for
+  // narrow streams.
+  typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+  // Constructs an empty Message.
+  Message();
+
+  // Copy constructor.
+  Message(const Message& msg) : ss_(new ::std::stringstream) {  // NOLINT
+    *ss_ << msg.GetString();
+  }
+
+  // Constructs a Message from a C-string.
+  explicit Message(const char* str) : ss_(new ::std::stringstream) {
+    *ss_ << str;
+  }
+
+#if GTEST_OS_SYMBIAN
+  // Streams a value (either a pointer or not) to this object.
+  template <typename T>
+  inline Message& operator <<(const T& value) {
+    StreamHelper(typename internal::is_pointer<T>::type(), value);
+    return *this;
+  }
+#else
+  // Streams a non-pointer value to this object.
+  template <typename T>
+  inline Message& operator <<(const T& val) {
+    // Some libraries overload << for STL containers.  These
+    // overloads are defined in the global namespace instead of ::std.
+    //
+    // C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+    // overloads are visible in either the std namespace or the global
+    // namespace, but not other namespaces, including the testing
+    // namespace which Google Test's Message class is in.
+    //
+    // To allow STL containers (and other types that has a << operator
+    // defined in the global namespace) to be used in Google Test
+    // assertions, testing::Message must access the custom << operator
+    // from the global namespace.  With this using declaration,
+    // overloads of << defined in the global namespace and those
+    // visible via Koenig lookup are both exposed in this function.
+    using ::operator <<;
+    *ss_ << val;
+    return *this;
+  }
+
+  // Streams a pointer value to this object.
+  //
+  // This function is an overload of the previous one.  When you
+  // stream a pointer to a Message, this definition will be used as it
+  // is more specialized.  (The C++ Standard, section
+  // [temp.func.order].)  If you stream a non-pointer, then the
+  // previous definition will be used.
+  //
+  // The reason for this overload is that streaming a NULL pointer to
+  // ostream is undefined behavior.  Depending on the compiler, you
+  // may get "0", "(nil)", "(null)", or an access violation.  To
+  // ensure consistent result across compilers, we always treat NULL
+  // as "(null)".
+  template <typename T>
+  inline Message& operator <<(T* const& pointer) {  // NOLINT
+    if (pointer == NULL) {
+      *ss_ << "(null)";
+    } else {
+      *ss_ << pointer;
+    }
+    return *this;
+  }
+#endif  // GTEST_OS_SYMBIAN
+
+  // Since the basic IO manipulators are overloaded for both narrow
+  // and wide streams, we have to provide this specialized definition
+  // of operator <<, even though its body is the same as the
+  // templatized version above.  Without this definition, streaming
+  // endl or other basic IO manipulators to Message will confuse the
+  // compiler.
+  Message& operator <<(BasicNarrowIoManip val) {
+    *ss_ << val;
+    return *this;
+  }
+
+  // Instead of 1/0, we want to see true/false for bool values.
+  Message& operator <<(bool b) {
+    return *this << (b ? "true" : "false");
+  }
+
+  // These two overloads allow streaming a wide C string to a Message
+  // using the UTF-8 encoding.
+  Message& operator <<(const wchar_t* wide_c_str);
+  Message& operator <<(wchar_t* wide_c_str);
+
+#if GTEST_HAS_STD_WSTRING
+  // Converts the given wide string to a narrow string using the UTF-8
+  // encoding, and streams the result to this Message object.
+  Message& operator <<(const ::std::wstring& wstr);
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+  // Converts the given wide string to a narrow string using the UTF-8
+  // encoding, and streams the result to this Message object.
+  Message& operator <<(const ::wstring& wstr);
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+  // Gets the text streamed to this object so far as an std::string.
+  // Each '\0' character in the buffer is replaced with "\\0".
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  std::string GetString() const;
+
+ private:
+
+#if GTEST_OS_SYMBIAN
+  // These are needed as the Nokia Symbian Compiler cannot decide between
+  // const T& and const T* in a function template. The Nokia compiler _can_
+  // decide between class template specializations for T and T*, so a
+  // tr1::type_traits-like is_pointer works, and we can overload on that.
+  template <typename T>
+  inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
+    if (pointer == NULL) {
+      *ss_ << "(null)";
+    } else {
+      *ss_ << pointer;
+    }
+  }
+  template <typename T>
+  inline void StreamHelper(internal::false_type /*is_pointer*/,
+                           const T& value) {
+    // See the comments in Message& operator <<(const T&) above for why
+    // we need this using statement.
+    using ::operator <<;
+    *ss_ << value;
+  }
+#endif  // GTEST_OS_SYMBIAN
+
+  // We'll hold the text streamed to this object here.
+  const internal::scoped_ptr< ::std::stringstream> ss_;
+
+  // We declare (but don't implement) this to prevent the compiler
+  // from implementing the assignment operator.
+  void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+  return os << sb.GetString();
+}
+
+namespace internal {
+
+// Converts a streamable value to an std::string.  A NULL pointer is
+// converted to "(null)".  When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+template <typename T>
+std::string StreamableToString(const T& streamable) {
+  return (Message() << streamable).GetString();
+}
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-param-test.h b/lib/gtest-1.7.0/include/gtest/gtest-param-test.h
new file mode 100644
index 0000000..d6702c8
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-param-test.h
@@ -0,0 +1,1421 @@
+// This file was GENERATED by command:
+//     pump.py gtest-param-test.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: vladl at google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+  // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+  // Inside a test, access the test parameter with the GetParam() method
+  // of the TestWithParam<T> class:
+  EXPECT_TRUE(foo.Blah(GetParam()));
+  ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+  ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a  summary of them, which
+// are all in the testing namespace:
+//
+//
+//  Range(begin, end [, step]) - Yields values {begin, begin+step,
+//                               begin+step+step, ...}. The values do not
+//                               include end. step defaults to 1.
+//  Values(v1, v2, ..., vN)    - Yields values {v1, v2, ..., vN}.
+//  ValuesIn(container)        - Yields values from a C-style array, an STL
+//  ValuesIn(begin,end)          container, or an iterator range [begin, end).
+//  Bool()                     - Yields sequence {false, true}.
+//  Combine(g1, g2, ..., gN)   - Yields all combinations (the Cartesian product
+//                               for the math savvy) of the values generated
+//                               by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+                        FooTest,
+                        Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+//    * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+//    * InstantiationName/FooTest.DoesBlah/1 for "miny"
+//    * InstantiationName/FooTest.DoesBlah/2 for "moe"
+//    * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+//    * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+//    * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+//    * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test {
+  // You can inherit all the usual members for a non-parameterized test
+  // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
+  // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo) {
+  // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah) {
+  // GetParam works just the same here as if you inherit from TestWithParam.
+  EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif  // 0
+
+#include "gtest/internal/gtest-port.h"
+
+#if !GTEST_OS_SYMBIAN
+# include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-param-util-generated.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+//   - returns a generator producing a sequence of values {start, start+1,
+//     start+2, ..., }.
+// Range(start, end, step)
+//   - returns a generator producing a sequence of values {start, start+step,
+//     start+step+step, ..., }.
+// Notes:
+//   * The generated sequences never include end. For example, Range(1, 5)
+//     returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+//     returns a generator producing {1, 3, 5, 7}.
+//   * start and end must have the same type. That type may be any integral or
+//     floating-point type or a user defined type satisfying these conditions:
+//     * It must be assignable (have operator=() defined).
+//     * It must have operator+() (operator+(int-compatible type) for
+//       two-operand version).
+//     * It must have operator<() defined.
+//     Elements in the resulting sequences will also have that type.
+//   * Condition start < end must be satisfied in order for resulting sequences
+//     to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+  return internal::ParamGenerator<T>(
+      new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+  return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+//   - returns a generator producing sequences with elements from
+//     a C-style array.
+// ValuesIn(const Container& container)
+//   - returns a generator producing sequences with elements from
+//     an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+//   - returns a generator producing sequences with elements from
+//     a range [begin, end) defined by a pair of STL-style iterators. These
+//     iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+//   ::std::vector< ::std::string> v;
+//   v.push_back("a");
+//   v.push_back("b");
+//   return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+//                         StlStringTest,
+//                         ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+//   ::std::list<char> list;
+//   list.push_back('a');
+//   list.push_back('b');
+//   return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+//                         CharTest,
+//                         ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+  typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
+      ::value_type ParamType;
+  return internal::ParamGenerator<ParamType>(
+      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+  return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container) {
+  return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+//   - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1) {
+  return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
+  return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
+  return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
+  return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5) {
+  return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6) {
+  return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7) {
+  return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+      v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
+  return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+      v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
+  return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
+  return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+    T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11) {
+  return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+      T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+    T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12) {
+  return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13) {
+  return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
+  return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
+  return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16) {
+  return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17) {
+  return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18) {
+  return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
+  return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
+  return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
+  return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22) {
+  return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23) {
+  return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24) {
+  return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+      v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
+  return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+      v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+    T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26) {
+  return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+    T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27) {
+  return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+    T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28) {
+  return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+      v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29) {
+  return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+      v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
+  return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+      v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
+  return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+      v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32) {
+  return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33) {
+  return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+    T31 v31, T32 v32, T33 v33, T34 v34) {
+  return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
+  return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
+  return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37) {
+  return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37, T38 v38) {
+  return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+      v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+      v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37, T38 v38, T39 v39) {
+  return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+      v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+      v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+    T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+    T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
+  return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+      v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+    T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
+  return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+      v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+    T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42) {
+  return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+      v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+      v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+    T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42, T43 v43) {
+  return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+      v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+      v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42, T43 v43, T44 v44) {
+  return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+      v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+      v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+    T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+    T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
+  return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+      v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+      v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
+  return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+      v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
+  return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+      v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+    T48 v48) {
+  return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+      v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+    T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+    T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+    T47 v47, T48 v48, T49 v49) {
+  return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+      v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+    T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+    T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
+  return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+      v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+//   - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+//   virtual void SetUp() {
+//     external_flag = GetParam();
+//   }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+  return Values(false, true);
+}
+
+# if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+//   - returns a generator producing sequences with elements coming from
+//     the Cartesian product of elements from the sequences generated by
+//     gen1, gen2, ..., genN. The sequence elements will have a type of
+//     tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+//     of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+//     : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+//                         Combine(Values("cat", "dog"),
+//                                 Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+//     : public testing::TestWithParam<tuple<bool, bool> > {
+//   virtual void SetUp() {
+//     // Assigns external_flag_1 and external_flag_2 values from the tuple.
+//     tie(external_flag_1, external_flag_2) = GetParam();
+//   }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+//   // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+//                         Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+    const Generator1& g1, const Generator2& g2) {
+  return internal::CartesianProductHolder2<Generator1, Generator2>(
+      g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3) {
+  return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+      g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+    Generator4> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4) {
+  return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+      Generator4>(
+      g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+    Generator4, Generator5> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5) {
+  return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+      Generator4, Generator5>(
+      g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6) {
+  return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6>(
+      g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7) {
+  return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7>(
+      g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8) {
+  return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8>(
+      g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8,
+    Generator9> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8, const Generator9& g9) {
+  return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+      g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8, typename Generator9,
+    typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+    Generator10> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8, const Generator9& g9,
+        const Generator10& g10) {
+  return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+      Generator10>(
+      g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+# endif  // GTEST_HAS_COMBINE
+
+
+
+# define TEST_P(test_case_name, test_name) \
+  class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+      : public test_case_name { \
+   public: \
+    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+    virtual void TestBody(); \
+   private: \
+    static int AddToRegistry() { \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+                  #test_case_name, \
+                  #test_name, \
+                  new ::testing::internal::TestMetaFactory< \
+                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+      return 0; \
+    } \
+    static int gtest_registering_dummy_; \
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+  }; \
+  int GTEST_TEST_CLASS_NAME_(test_case_name, \
+                             test_name)::gtest_registering_dummy_ = \
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+  void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+  ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+  int gtest_##prefix##test_case_name##_dummy_ = \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+                  #prefix, \
+                  &gtest_##prefix##test_case_name##_EvalGenerator_, \
+                  __FILE__, __LINE__)
+
+}  // namespace testing
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-param-test.h.pump b/lib/gtest-1.7.0/include/gtest/gtest-param-test.h.pump
new file mode 100644
index 0000000..2dc9303
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-param-test.h.pump
@@ -0,0 +1,487 @@
+$$ -*- mode: c++; -*-
+$var n = 50  $$ Maximum length of Values arguments we want to support.
+$var maxtuple = 10  $$ Maximum number of Combine arguments we want to support.
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: vladl at google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+  // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+  // Inside a test, access the test parameter with the GetParam() method
+  // of the TestWithParam<T> class:
+  EXPECT_TRUE(foo.Blah(GetParam()));
+  ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+  ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a  summary of them, which
+// are all in the testing namespace:
+//
+//
+//  Range(begin, end [, step]) - Yields values {begin, begin+step,
+//                               begin+step+step, ...}. The values do not
+//                               include end. step defaults to 1.
+//  Values(v1, v2, ..., vN)    - Yields values {v1, v2, ..., vN}.
+//  ValuesIn(container)        - Yields values from a C-style array, an STL
+//  ValuesIn(begin,end)          container, or an iterator range [begin, end).
+//  Bool()                     - Yields sequence {false, true}.
+//  Combine(g1, g2, ..., gN)   - Yields all combinations (the Cartesian product
+//                               for the math savvy) of the values generated
+//                               by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+                        FooTest,
+                        Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+//    * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+//    * InstantiationName/FooTest.DoesBlah/1 for "miny"
+//    * InstantiationName/FooTest.DoesBlah/2 for "moe"
+//    * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+//    * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+//    * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+//    * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test {
+  // You can inherit all the usual members for a non-parameterized test
+  // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
+  // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo) {
+  // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah) {
+  // GetParam works just the same here as if you inherit from TestWithParam.
+  EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif  // 0
+
+#include "gtest/internal/gtest-port.h"
+
+#if !GTEST_OS_SYMBIAN
+# include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-param-util-generated.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+//   - returns a generator producing a sequence of values {start, start+1,
+//     start+2, ..., }.
+// Range(start, end, step)
+//   - returns a generator producing a sequence of values {start, start+step,
+//     start+step+step, ..., }.
+// Notes:
+//   * The generated sequences never include end. For example, Range(1, 5)
+//     returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+//     returns a generator producing {1, 3, 5, 7}.
+//   * start and end must have the same type. That type may be any integral or
+//     floating-point type or a user defined type satisfying these conditions:
+//     * It must be assignable (have operator=() defined).
+//     * It must have operator+() (operator+(int-compatible type) for
+//       two-operand version).
+//     * It must have operator<() defined.
+//     Elements in the resulting sequences will also have that type.
+//   * Condition start < end must be satisfied in order for resulting sequences
+//     to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+  return internal::ParamGenerator<T>(
+      new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+  return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+//   - returns a generator producing sequences with elements from
+//     a C-style array.
+// ValuesIn(const Container& container)
+//   - returns a generator producing sequences with elements from
+//     an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+//   - returns a generator producing sequences with elements from
+//     a range [begin, end) defined by a pair of STL-style iterators. These
+//     iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+//   ::std::vector< ::std::string> v;
+//   v.push_back("a");
+//   v.push_back("b");
+//   return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+//                         StlStringTest,
+//                         ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+//   ::std::list<char> list;
+//   list.push_back('a');
+//   list.push_back('b');
+//   return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+//                         CharTest,
+//                         ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+  typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
+      ::value_type ParamType;
+  return internal::ParamGenerator<ParamType>(
+      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+  return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container) {
+  return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+//   - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to $n parameters.
+//
+$range i 1..n
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename T$j]]>
+internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) {
+  return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]);
+}
+
+]]
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+//   - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+//   virtual void SetUp() {
+//     external_flag = GetParam();
+//   }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+  return Values(false, true);
+}
+
+# if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+//   - returns a generator producing sequences with elements coming from
+//     the Cartesian product of elements from the sequences generated by
+//     gen1, gen2, ..., genN. The sequence elements will have a type of
+//     tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+//     of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to $maxtuple arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+//     : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+//                         Combine(Values("cat", "dog"),
+//                                 Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+//     : public testing::TestWithParam<tuple<bool, bool> > {
+//   virtual void SetUp() {
+//     // Assigns external_flag_1 and external_flag_2 values from the tuple.
+//     tie(external_flag_1, external_flag_2) = GetParam();
+//   }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+//   // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+//                         Combine(Bool(), Bool()));
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename Generator$j]]>
+internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine(
+    $for j, [[const Generator$j& g$j]]) {
+  return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>(
+      $for j, [[g$j]]);
+}
+
+]]
+# endif  // GTEST_HAS_COMBINE
+
+
+
+# define TEST_P(test_case_name, test_name) \
+  class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+      : public test_case_name { \
+   public: \
+    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+    virtual void TestBody(); \
+   private: \
+    static int AddToRegistry() { \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+                  #test_case_name, \
+                  #test_name, \
+                  new ::testing::internal::TestMetaFactory< \
+                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+      return 0; \
+    } \
+    static int gtest_registering_dummy_; \
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+  }; \
+  int GTEST_TEST_CLASS_NAME_(test_case_name, \
+                             test_name)::gtest_registering_dummy_ = \
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+  void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+  ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+  int gtest_##prefix##test_case_name##_dummy_ = \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+                  #prefix, \
+                  &gtest_##prefix##test_case_name##_EvalGenerator_, \
+                  __FILE__, __LINE__)
+
+}  // namespace testing
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-printers.h b/lib/gtest-1.7.0/include/gtest/gtest-printers.h
new file mode 100644
index 0000000..0639d9f
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-printers.h
@@ -0,0 +1,855 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// A user can teach this function how to print a class type T by
+// defining either operator<<() or PrintTo() in the namespace that
+// defines T.  More specifically, the FIRST defined function in the
+// following list will be used (assuming T is defined in namespace
+// foo):
+//
+//   1. foo::PrintTo(const T&, ostream*)
+//   2. operator<<(ostream&, const T&) defined in either foo or the
+//      global namespace.
+//
+// If none of the above is defined, it will print the debug string of
+// the value if it is a protocol buffer, or print the raw bytes in the
+// value otherwise.
+//
+// To aid debugging: when T is a reference type, the address of the
+// value is also printed; when T is a (const) char pointer, both the
+// pointer value and the NUL-terminated string it points to are
+// printed.
+//
+// We also provide some convenient wrappers:
+//
+//   // Prints a value to a string.  For a (const or not) char
+//   // pointer, the NUL-terminated string (but not the pointer) is
+//   // printed.
+//   std::string ::testing::PrintToString(const T& value);
+//
+//   // Prints a value tersely: for a reference type, the referenced
+//   // value (but not the address) is printed; for a (const or not) char
+//   // pointer, the NUL-terminated string (but not the pointer) is
+//   // printed.
+//   void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
+//
+//   // Prints value using the type inferred by the compiler.  The difference
+//   // from UniversalTersePrint() is that this function prints both the
+//   // pointer and the NUL-terminated string for a (const or not) char pointer.
+//   void ::testing::internal::UniversalPrint(const T& value, ostream*);
+//
+//   // Prints the fields of a tuple tersely to a string vector, one
+//   // element for each field. Tuple support must be enabled in
+//   // gtest-port.h.
+//   std::vector<string> UniversalTersePrintTupleFieldsToStrings(
+//       const Tuple& value);
+//
+// Known limitation:
+//
+// The print primitives print the elements of an STL-style container
+// using the compiler-inferred type of *iter where iter is a
+// const_iterator of the container.  When const_iterator is an input
+// iterator but not a forward iterator, this inferred type may not
+// match value_type, and the print output may be incorrect.  In
+// practice, this is rarely a problem as for most containers
+// const_iterator is a forward iterator.  We'll fix this if there's an
+// actual need for it.  Note that this fix cannot rely on value_type
+// being defined as many user-defined container types don't have
+// value_type.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#include <ostream>  // NOLINT
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+#include "gtest/internal/gtest-port.h"
+#include "gtest/internal/gtest-internal.h"
+
+namespace testing {
+
+// Definitions in the 'internal' and 'internal2' name spaces are
+// subject to change without notice.  DO NOT USE THEM IN USER CODE!
+namespace internal2 {
+
+// Prints the given number of bytes in the given object to the given
+// ostream.
+GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
+                                     size_t count,
+                                     ::std::ostream* os);
+
+// For selecting which printer to use when a given type has neither <<
+// nor PrintTo().
+enum TypeKind {
+  kProtobuf,              // a protobuf type
+  kConvertibleToInteger,  // a type implicitly convertible to BiggestInt
+                          // (e.g. a named or unnamed enum type)
+  kOtherType              // anything else
+};
+
+// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
+// by the universal printer to print a value of type T when neither
+// operator<< nor PrintTo() is defined for T, where kTypeKind is the
+// "kind" of T as defined by enum TypeKind.
+template <typename T, TypeKind kTypeKind>
+class TypeWithoutFormatter {
+ public:
+  // This default version is called when kTypeKind is kOtherType.
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
+                         sizeof(value), os);
+  }
+};
+
+// We print a protobuf using its ShortDebugString() when the string
+// doesn't exceed this many characters; otherwise we print it using
+// DebugString() for better readability.
+const size_t kProtobufOneLinerMaxLength = 50;
+
+template <typename T>
+class TypeWithoutFormatter<T, kProtobuf> {
+ public:
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    const ::testing::internal::string short_str = value.ShortDebugString();
+    const ::testing::internal::string pretty_str =
+        short_str.length() <= kProtobufOneLinerMaxLength ?
+        short_str : ("\n" + value.DebugString());
+    *os << ("<" + pretty_str + ">");
+  }
+};
+
+template <typename T>
+class TypeWithoutFormatter<T, kConvertibleToInteger> {
+ public:
+  // Since T has no << operator or PrintTo() but can be implicitly
+  // converted to BiggestInt, we print it as a BiggestInt.
+  //
+  // Most likely T is an enum type (either named or unnamed), in which
+  // case printing it as an integer is the desired behavior.  In case
+  // T is not an enum, printing it as an integer is the best we can do
+  // given that it has no user-defined printer.
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    const internal::BiggestInt kBigInt = value;
+    *os << kBigInt;
+  }
+};
+
+// Prints the given value to the given ostream.  If the value is a
+// protocol message, its debug string is printed; if it's an enum or
+// of a type implicitly convertible to BiggestInt, it's printed as an
+// integer; otherwise the bytes in the value are printed.  This is
+// what UniversalPrinter<T>::Print() does when it knows nothing about
+// type T and T has neither << operator nor PrintTo().
+//
+// A user can override this behavior for a class type Foo by defining
+// a << operator in the namespace where Foo is defined.
+//
+// We put this operator in namespace 'internal2' instead of 'internal'
+// to simplify the implementation, as much code in 'internal' needs to
+// use << in STL, which would conflict with our own << were it defined
+// in 'internal'.
+//
+// Note that this operator<< takes a generic std::basic_ostream<Char,
+// CharTraits> type instead of the more restricted std::ostream.  If
+// we define it to take an std::ostream instead, we'll get an
+// "ambiguous overloads" compiler error when trying to print a type
+// Foo that supports streaming to std::basic_ostream<Char,
+// CharTraits>, as the compiler cannot tell whether
+// operator<<(std::ostream&, const T&) or
+// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
+// specific.
+template <typename Char, typename CharTraits, typename T>
+::std::basic_ostream<Char, CharTraits>& operator<<(
+    ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
+  TypeWithoutFormatter<T,
+      (internal::IsAProtocolMessage<T>::value ? kProtobuf :
+       internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
+       kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
+  return os;
+}
+
+}  // namespace internal2
+}  // namespace testing
+
+// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
+// magic needed for implementing UniversalPrinter won't work.
+namespace testing_internal {
+
+// Used to print a value that is not an STL-style container when the
+// user doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
+  // With the following statement, during unqualified name lookup,
+  // testing::internal2::operator<< appears as if it was declared in
+  // the nearest enclosing namespace that contains both
+  // ::testing_internal and ::testing::internal2, i.e. the global
+  // namespace.  For more details, refer to the C++ Standard section
+  // 7.3.4-1 [namespace.udir].  This allows us to fall back onto
+  // testing::internal2::operator<< in case T doesn't come with a <<
+  // operator.
+  //
+  // We cannot write 'using ::testing::internal2::operator<<;', which
+  // gcc 3.3 fails to compile due to a compiler bug.
+  using namespace ::testing::internal2;  // NOLINT
+
+  // Assuming T is defined in namespace foo, in the next statement,
+  // the compiler will consider all of:
+  //
+  //   1. foo::operator<< (thanks to Koenig look-up),
+  //   2. ::operator<< (as the current namespace is enclosed in ::),
+  //   3. testing::internal2::operator<< (thanks to the using statement above).
+  //
+  // The operator<< whose type matches T best will be picked.
+  //
+  // We deliberately allow #2 to be a candidate, as sometimes it's
+  // impossible to define #1 (e.g. when foo is ::std, defining
+  // anything in it is undefined behavior unless you are a compiler
+  // vendor.).
+  *os << value;
+}
+
+}  // namespace testing_internal
+
+namespace testing {
+namespace internal {
+
+// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
+// value to the given ostream.  The caller must ensure that
+// 'ostream_ptr' is not NULL, or the behavior is undefined.
+//
+// We define UniversalPrinter as a class template (as opposed to a
+// function template), as we need to partially specialize it for
+// reference types, which cannot be done with function templates.
+template <typename T>
+class UniversalPrinter;
+
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os);
+
+// Used to print an STL-style container when the user doesn't define
+// a PrintTo() for it.
+template <typename C>
+void DefaultPrintTo(IsContainer /* dummy */,
+                    false_type /* is not a pointer */,
+                    const C& container, ::std::ostream* os) {
+  const size_t kMaxCount = 32;  // The maximum number of elements to print.
+  *os << '{';
+  size_t count = 0;
+  for (typename C::const_iterator it = container.begin();
+       it != container.end(); ++it, ++count) {
+    if (count > 0) {
+      *os << ',';
+      if (count == kMaxCount) {  // Enough has been printed.
+        *os << " ...";
+        break;
+      }
+    }
+    *os << ' ';
+    // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
+    // handle *it being a native array.
+    internal::UniversalPrint(*it, os);
+  }
+
+  if (count > 0) {
+    *os << ' ';
+  }
+  *os << '}';
+}
+
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it.  (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space.  Their representation is
+// implementation-defined.  Therefore they will be printed as raw
+// bytes.)
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+                    true_type /* is a pointer */,
+                    T* p, ::std::ostream* os) {
+  if (p == NULL) {
+    *os << "NULL";
+  } else {
+    // C++ doesn't allow casting from a function pointer to any object
+    // pointer.
+    //
+    // IsTrue() silences warnings: "Condition is always true",
+    // "unreachable code".
+    if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
+      // T is not a function type.  We just call << to print p,
+      // relying on ADL to pick up user-defined << for their pointer
+      // types, if any.
+      *os << p;
+    } else {
+      // T is a function type, so '*os << p' doesn't do what we want
+      // (it just prints p as bool).  We want to print p as a const
+      // void*.  However, we cannot cast it to const void* directly,
+      // even using reinterpret_cast, as earlier versions of gcc
+      // (e.g. 3.4.5) cannot compile the cast when p is a function
+      // pointer.  Casting to UInt64 first solves the problem.
+      *os << reinterpret_cast<const void*>(
+          reinterpret_cast<internal::UInt64>(p));
+    }
+  }
+}
+
+// Used to print a non-container, non-pointer value when the user
+// doesn't define PrintTo() for it.
+template <typename T>
+void DefaultPrintTo(IsNotContainer /* dummy */,
+                    false_type /* is not a pointer */,
+                    const T& value, ::std::ostream* os) {
+  ::testing_internal::DefaultPrintNonContainerTo(value, os);
+}
+
+// Prints the given value using the << operator if it has one;
+// otherwise prints the bytes in it.  This is what
+// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
+// or overloaded for type T.
+//
+// A user can override this behavior for a class type Foo by defining
+// an overload of PrintTo() in the namespace where Foo is defined.  We
+// give the user this option as sometimes defining a << operator for
+// Foo is not desirable (e.g. the coding style may prevent doing it,
+// or there is already a << operator but it doesn't do what the user
+// wants).
+template <typename T>
+void PrintTo(const T& value, ::std::ostream* os) {
+  // DefaultPrintTo() is overloaded.  The type of its first two
+  // arguments determine which version will be picked.  If T is an
+  // STL-style container, the version for container will be called; if
+  // T is a pointer, the pointer version will be called; otherwise the
+  // generic version will be called.
+  //
+  // Note that we check for container types here, prior to we check
+  // for protocol message types in our operator<<.  The rationale is:
+  //
+  // For protocol messages, we want to give people a chance to
+  // override Google Mock's format by defining a PrintTo() or
+  // operator<<.  For STL containers, other formats can be
+  // incompatible with Google Mock's format for the container
+  // elements; therefore we check for container types here to ensure
+  // that our format is used.
+  //
+  // The second argument of DefaultPrintTo() is needed to bypass a bug
+  // in Symbian's C++ compiler that prevents it from picking the right
+  // overload between:
+  //
+  //   PrintTo(const T& x, ...);
+  //   PrintTo(T* x, ...);
+  DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
+}
+
+// The following list of PrintTo() overloads tells
+// UniversalPrinter<T>::Print() how to print standard types (built-in
+// types, strings, plain arrays, and pointers).
+
+// Overloads for various char types.
+GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
+GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
+inline void PrintTo(char c, ::std::ostream* os) {
+  // When printing a plain char, we always treat it as unsigned.  This
+  // way, the output won't be affected by whether the compiler thinks
+  // char is signed or not.
+  PrintTo(static_cast<unsigned char>(c), os);
+}
+
+// Overloads for other simple built-in types.
+inline void PrintTo(bool x, ::std::ostream* os) {
+  *os << (x ? "true" : "false");
+}
+
+// Overload for wchar_t type.
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its decimal code (except for L'\0').
+// The L'\0' char is printed as "L'\\0'". The decimal code is printed
+// as signed integer when wchar_t is implemented by the compiler
+// as a signed type and is printed as an unsigned integer when wchar_t
+// is implemented as an unsigned type.
+GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
+
+// Overloads for C strings.
+GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
+inline void PrintTo(char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const char*>(s), os);
+}
+
+// signed/unsigned char is often used for representing binary data, so
+// we print pointers to it as void* to be safe.
+inline void PrintTo(const signed char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(signed char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(unsigned char* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const void*>(s), os);
+}
+
+// MSVC can be configured to define wchar_t as a typedef of unsigned
+// short.  It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
+// type.  When wchar_t is a typedef, defining an overload for const
+// wchar_t* would cause unsigned short* be printed as a wide string,
+// possibly causing invalid memory accesses.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Overloads for wide C strings
+GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
+inline void PrintTo(wchar_t* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const wchar_t*>(s), os);
+}
+#endif
+
+// Overload for C arrays.  Multi-dimensional arrays are printed
+// properly.
+
+// Prints the given number of elements in an array, without printing
+// the curly braces.
+template <typename T>
+void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
+  UniversalPrint(a[0], os);
+  for (size_t i = 1; i != count; i++) {
+    *os << ", ";
+    UniversalPrint(a[i], os);
+  }
+}
+
+// Overloads for ::string and ::std::string.
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
+inline void PrintTo(const ::string& s, ::std::ostream* os) {
+  PrintStringTo(s, os);
+}
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
+inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
+  PrintStringTo(s, os);
+}
+
+// Overloads for ::wstring and ::std::wstring.
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
+  PrintWideStringTo(s, os);
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
+  PrintWideStringTo(s, os);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_TR1_TUPLE
+// Overload for ::std::tr1::tuple.  Needed for printing function arguments,
+// which are packed as tuples.
+
+// Helper function for printing a tuple.  T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os);
+
+// Overloaded PrintTo() for tuples of various arities.  We support
+// tuples of up-to 10 fields.  The following implementation works
+// regardless of whether tr1::tuple is implemented using the
+// non-standard variadic template feature or not.
+
+inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1>
+void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2>
+void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9>
+void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
+             ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10>
+void PrintTo(
+    const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
+    ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Overload for std::pair.
+template <typename T1, typename T2>
+void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
+  *os << '(';
+  // We cannot use UniversalPrint(value.first, os) here, as T1 may be
+  // a reference type.  The same for printing value.second.
+  UniversalPrinter<T1>::Print(value.first, os);
+  *os << ", ";
+  UniversalPrinter<T2>::Print(value.second, os);
+  *os << ')';
+}
+
+// Implements printing a non-reference type T by letting the compiler
+// pick the right overload of PrintTo() for T.
+template <typename T>
+class UniversalPrinter {
+ public:
+  // MSVC warns about adding const to a function type, so we want to
+  // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4180)  // Temporarily disables warning 4180.
+#endif  // _MSC_VER
+
+  // Note: we deliberately don't call this PrintTo(), as that name
+  // conflicts with ::testing::internal::PrintTo in the body of the
+  // function.
+  static void Print(const T& value, ::std::ostream* os) {
+    // By default, ::testing::internal::PrintTo() is used for printing
+    // the value.
+    //
+    // Thanks to Koenig look-up, if T is a class and has its own
+    // PrintTo() function defined in its namespace, that function will
+    // be visible here.  Since it is more specific than the generic ones
+    // in ::testing::internal, it will be picked by the compiler in the
+    // following statement - exactly what we want.
+    PrintTo(value, os);
+  }
+
+#ifdef _MSC_VER
+# pragma warning(pop)           // Restores the warning state.
+#endif  // _MSC_VER
+};
+
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
+  if (len == 0) {
+    *os << "{}";
+  } else {
+    *os << "{ ";
+    const size_t kThreshold = 18;
+    const size_t kChunkSize = 8;
+    // If the array has more than kThreshold elements, we'll have to
+    // omit some details by printing only the first and the last
+    // kChunkSize elements.
+    // TODO(wan at google.com): let the user control the threshold using a flag.
+    if (len <= kThreshold) {
+      PrintRawArrayTo(begin, len, os);
+    } else {
+      PrintRawArrayTo(begin, kChunkSize, os);
+      *os << ", ..., ";
+      PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+    }
+    *os << " }";
+  }
+}
+// This overload prints a (const) char array compactly.
+GTEST_API_ void UniversalPrintArray(
+    const char* begin, size_t len, ::std::ostream* os);
+
+// This overload prints a (const) wchar_t array compactly.
+GTEST_API_ void UniversalPrintArray(
+    const wchar_t* begin, size_t len, ::std::ostream* os);
+
+// Implements printing an array type T[N].
+template <typename T, size_t N>
+class UniversalPrinter<T[N]> {
+ public:
+  // Prints the given array, omitting some elements when there are too
+  // many.
+  static void Print(const T (&a)[N], ::std::ostream* os) {
+    UniversalPrintArray(a, N, os);
+  }
+};
+
+// Implements printing a reference type T&.
+template <typename T>
+class UniversalPrinter<T&> {
+ public:
+  // MSVC warns about adding const to a function type, so we want to
+  // disable the warning.
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4180)  // Temporarily disables warning 4180.
+#endif  // _MSC_VER
+
+  static void Print(const T& value, ::std::ostream* os) {
+    // Prints the address of the value.  We use reinterpret_cast here
+    // as static_cast doesn't compile when T is a function type.
+    *os << "@" << reinterpret_cast<const void*>(&value) << " ";
+
+    // Then prints the value itself.
+    UniversalPrint(value, os);
+  }
+
+#ifdef _MSC_VER
+# pragma warning(pop)           // Restores the warning state.
+#endif  // _MSC_VER
+};
+
+// Prints a value tersely: for a reference type, the referenced value
+// (but not the address) is printed; for a (const) char pointer, the
+// NUL-terminated string (but not the pointer) is printed.
+
+template <typename T>
+class UniversalTersePrinter {
+ public:
+  static void Print(const T& value, ::std::ostream* os) {
+    UniversalPrint(value, os);
+  }
+};
+template <typename T>
+class UniversalTersePrinter<T&> {
+ public:
+  static void Print(const T& value, ::std::ostream* os) {
+    UniversalPrint(value, os);
+  }
+};
+template <typename T, size_t N>
+class UniversalTersePrinter<T[N]> {
+ public:
+  static void Print(const T (&value)[N], ::std::ostream* os) {
+    UniversalPrinter<T[N]>::Print(value, os);
+  }
+};
+template <>
+class UniversalTersePrinter<const char*> {
+ public:
+  static void Print(const char* str, ::std::ostream* os) {
+    if (str == NULL) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(string(str), os);
+    }
+  }
+};
+template <>
+class UniversalTersePrinter<char*> {
+ public:
+  static void Print(char* str, ::std::ostream* os) {
+    UniversalTersePrinter<const char*>::Print(str, os);
+  }
+};
+
+#if GTEST_HAS_STD_WSTRING
+template <>
+class UniversalTersePrinter<const wchar_t*> {
+ public:
+  static void Print(const wchar_t* str, ::std::ostream* os) {
+    if (str == NULL) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(::std::wstring(str), os);
+    }
+  }
+};
+#endif
+
+template <>
+class UniversalTersePrinter<wchar_t*> {
+ public:
+  static void Print(wchar_t* str, ::std::ostream* os) {
+    UniversalTersePrinter<const wchar_t*>::Print(str, os);
+  }
+};
+
+template <typename T>
+void UniversalTersePrint(const T& value, ::std::ostream* os) {
+  UniversalTersePrinter<T>::Print(value, os);
+}
+
+// Prints a value using the type inferred by the compiler.  The
+// difference between this and UniversalTersePrint() is that for a
+// (const) char pointer, this prints both the pointer and the
+// NUL-terminated string.
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os) {
+  // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
+  // UniversalPrinter with T directly.
+  typedef T T1;
+  UniversalPrinter<T1>::Print(value, os);
+}
+
+#if GTEST_HAS_TR1_TUPLE
+typedef ::std::vector<string> Strings;
+
+// This helper template allows PrintTo() for tuples and
+// UniversalTersePrintTupleFieldsToStrings() to be defined by
+// induction on the number of tuple fields.  The idea is that
+// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
+// fields in tuple t, and can be defined in terms of
+// TuplePrefixPrinter<N - 1>.
+
+// The inductive case.
+template <size_t N>
+struct TuplePrefixPrinter {
+  // Prints the first N fields of a tuple.
+  template <typename Tuple>
+  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+    TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
+    *os << ", ";
+    UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
+        ::Print(::std::tr1::get<N - 1>(t), os);
+  }
+
+  // Tersely prints the first N fields of a tuple to a string vector,
+  // one element for each field.
+  template <typename Tuple>
+  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+    TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
+    ::std::stringstream ss;
+    UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
+    strings->push_back(ss.str());
+  }
+};
+
+// Base cases.
+template <>
+struct TuplePrefixPrinter<0> {
+  template <typename Tuple>
+  static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
+
+  template <typename Tuple>
+  static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
+};
+// We have to specialize the entire TuplePrefixPrinter<> class
+// template here, even though the definition of
+// TersePrintPrefixToStrings() is the same as the generic version, as
+// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
+// support specializing a method template of a class template.
+template <>
+struct TuplePrefixPrinter<1> {
+  template <typename Tuple>
+  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
+    UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
+        Print(::std::tr1::get<0>(t), os);
+  }
+
+  template <typename Tuple>
+  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
+    ::std::stringstream ss;
+    UniversalTersePrint(::std::tr1::get<0>(t), &ss);
+    strings->push_back(ss.str());
+  }
+};
+
+// Helper function for printing a tuple.  T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T& t, ::std::ostream* os) {
+  *os << "(";
+  TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
+      PrintPrefixTo(t, os);
+  *os << ")";
+}
+
+// Prints the fields of a tuple tersely to a string vector, one
+// element for each field.  See the comment before
+// UniversalTersePrint() for how we define "tersely".
+template <typename Tuple>
+Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
+  Strings result;
+  TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
+      TersePrintPrefixToStrings(value, &result);
+  return result;
+}
+#endif  // GTEST_HAS_TR1_TUPLE
+
+}  // namespace internal
+
+template <typename T>
+::std::string PrintToString(const T& value) {
+  ::std::stringstream ss;
+  internal::UniversalTersePrinter<T>::Print(value, &ss);
+  return ss.str();
+}
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-spi.h b/lib/gtest-1.7.0/include/gtest/gtest-spi.h
new file mode 100644
index 0000000..f63fa9a
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-spi.h
@@ -0,0 +1,232 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include "gtest/gtest.h"
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class GTEST_API_ ScopedFakeTestPartResultReporter
+    : public TestPartResultReporterInterface {
+ public:
+  // The two possible mocking modes of this object.
+  enum InterceptMode {
+    INTERCEPT_ONLY_CURRENT_THREAD,  // Intercepts only thread local failures.
+    INTERCEPT_ALL_THREADS           // Intercepts all failures.
+  };
+
+  // The c'tor sets this object as the test part result reporter used
+  // by Google Test.  The 'result' parameter specifies where to report the
+  // results. This reporter will only catch failures generated in the current
+  // thread. DEPRECATED
+  explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+  // Same as above, but you can choose the interception scope of this object.
+  ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+                                   TestPartResultArray* result);
+
+  // The d'tor restores the previous test part result reporter.
+  virtual ~ScopedFakeTestPartResultReporter();
+
+  // Appends the TestPartResult object to the TestPartResultArray
+  // received in the constructor.
+  //
+  // This method is from the TestPartResultReporterInterface
+  // interface.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+  void Init();
+
+  const InterceptMode intercept_mode_;
+  TestPartResultReporterInterface* old_reporter_;
+  TestPartResultArray* const result_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE().  Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring.  If that's not the case, a
+// non-fatal failure will be generated.
+class GTEST_API_ SingleFailureChecker {
+ public:
+  // The constructor remembers the arguments.
+  SingleFailureChecker(const TestPartResultArray* results,
+                       TestPartResult::Type type,
+                       const string& substr);
+  ~SingleFailureChecker();
+ private:
+  const TestPartResultArray* const results_;
+  const TestPartResult::Type type_;
+  const string substr_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures.  It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+//   - 'statement' cannot reference local non-static variables or
+//     non-static members of the current object.
+//   - 'statement' cannot return a value.
+//   - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+  do { \
+    class GTestExpectFatalFailureHelper {\
+     public:\
+      static void Execute() { statement; }\
+    };\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+      GTestExpectFatalFailureHelper::Execute();\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+  do { \
+    class GTestExpectFatalFailureHelper {\
+     public:\
+      static void Execute() { statement; }\
+    };\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ALL_THREADS, &gtest_failures);\
+      GTestExpectFatalFailureHelper::Execute();\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures.  It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+//   - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works.  If we do that, the code won't compile when the user gives
+// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
+// expands to code containing an unprotected comma.  The
+// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
+// catches that.
+//
+// For the same reason, we have to write
+//   if (::testing::internal::AlwaysTrue()) { statement; }
+// instead of
+//   GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+// to avoid an MSVC warning on unreachable code.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+  do {\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+        (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+      if (::testing::internal::AlwaysTrue()) { statement; }\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+  do {\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+        (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
+          &gtest_failures);\
+      if (::testing::internal::AlwaysTrue()) { statement; }\
+    }\
+  } while (::testing::internal::AlwaysFalse())
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-test-part.h b/lib/gtest-1.7.0/include/gtest/gtest-test-part.h
new file mode 100644
index 0000000..77eb844
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-test-part.h
@@ -0,0 +1,179 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: mheule at google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult {
+ public:
+  // The possible outcomes of a test part (i.e. an assertion or an
+  // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+  enum Type {
+    kSuccess,          // Succeeded.
+    kNonFatalFailure,  // Failed but the test can continue.
+    kFatalFailure      // Failed and the test should be terminated.
+  };
+
+  // C'tor.  TestPartResult does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestPartResult object.
+  TestPartResult(Type a_type,
+                 const char* a_file_name,
+                 int a_line_number,
+                 const char* a_message)
+      : type_(a_type),
+        file_name_(a_file_name == NULL ? "" : a_file_name),
+        line_number_(a_line_number),
+        summary_(ExtractSummary(a_message)),
+        message_(a_message) {
+  }
+
+  // Gets the outcome of the test part.
+  Type type() const { return type_; }
+
+  // Gets the name of the source file where the test part took place, or
+  // NULL if it's unknown.
+  const char* file_name() const {
+    return file_name_.empty() ? NULL : file_name_.c_str();
+  }
+
+  // Gets the line in the source file where the test part took place,
+  // or -1 if it's unknown.
+  int line_number() const { return line_number_; }
+
+  // Gets the summary of the failure message.
+  const char* summary() const { return summary_.c_str(); }
+
+  // Gets the message associated with the test part.
+  const char* message() const { return message_.c_str(); }
+
+  // Returns true iff the test part passed.
+  bool passed() const { return type_ == kSuccess; }
+
+  // Returns true iff the test part failed.
+  bool failed() const { return type_ != kSuccess; }
+
+  // Returns true iff the test part non-fatally failed.
+  bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+  // Returns true iff the test part fatally failed.
+  bool fatally_failed() const { return type_ == kFatalFailure; }
+
+ private:
+  Type type_;
+
+  // Gets the summary of the failure message by omitting the stack
+  // trace in it.
+  static std::string ExtractSummary(const char* message);
+
+  // The name of the source file where the test part took place, or
+  // "" if the source file is unknown.
+  std::string file_name_;
+  // The line in the source file where the test part took place, or -1
+  // if the line number is unknown.
+  int line_number_;
+  std::string summary_;  // The test failure summary.
+  std::string message_;  // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray {
+ public:
+  TestPartResultArray() {}
+
+  // Appends the given TestPartResult to the array.
+  void Append(const TestPartResult& result);
+
+  // Returns the TestPartResult at the given index (0-based).
+  const TestPartResult& GetTestPartResult(int index) const;
+
+  // Returns the number of TestPartResult objects in the array.
+  int size() const;
+
+ private:
+  std::vector<TestPartResult> array_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+  virtual ~TestPartResultReporterInterface() {}
+
+  virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+    : public TestPartResultReporterInterface {
+ public:
+  HasNewFatalFailureHelper();
+  virtual ~HasNewFatalFailureHelper();
+  virtual void ReportTestPartResult(const TestPartResult& result);
+  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+  bool has_new_fatal_failure_;
+  TestPartResultReporterInterface* original_reporter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest-typed-test.h b/lib/gtest-1.7.0/include/gtest/gtest-typed-test.h
new file mode 100644
index 0000000..fe1e83b
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest-typed-test.h
@@ -0,0 +1,259 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list.  You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template.  It should be parameterized
+// by a type.  Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+  ...
+  typedef std::list<T> List;
+  static T shared_;
+  T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list.  The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+//   TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+  // Inside a test, refer to TypeParam to get the type parameter.
+  // Since we are inside a derived class template, C++ requires use to
+  // visit the members of FooTest via 'this'.
+  TypeParam n = this->value_;
+
+  // To visit static members of the fixture, add the TestFixture::
+  // prefix.
+  n += TestFixture::shared_;
+
+  // To refer to typedefs in the fixture, add the "typename
+  // TestFixture::" prefix.
+  typename TestFixture::List values;
+  values.push_back(n);
+  ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif  // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type.  Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are.  The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have.  Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly.  Here's an example:
+
+#if 0
+
+// First, define a fixture class template.  It should be parameterized
+// by a type.  Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+  ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+  // Inside a test, refer to TypeParam to get the type parameter.
+  TypeParam n = 0;
+  ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them.  The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+                           DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want.  If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name.  Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+//   INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif  // 0
+
+#include "gtest/internal/gtest-port.h"
+#include "gtest/internal/gtest-type-util.h"
+
+// Implements typed tests.
+
+#if GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define TYPED_TEST_CASE(CaseName, Types) \
+  typedef ::testing::internal::TypeList< Types >::type \
+      GTEST_TYPE_PARAMS_(CaseName)
+
+# define TYPED_TEST(CaseName, TestName) \
+  template <typename gtest_TypeParam_> \
+  class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+      : public CaseName<gtest_TypeParam_> { \
+   private: \
+    typedef CaseName<gtest_TypeParam_> TestFixture; \
+    typedef gtest_TypeParam_ TypeParam; \
+    virtual void TestBody(); \
+  }; \
+  bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
+      ::testing::internal::TypeParameterizedTest< \
+          CaseName, \
+          ::testing::internal::TemplateSel< \
+              GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+          GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+              "", #CaseName, #TestName, 0); \
+  template <typename gtest_TypeParam_> \
+  void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif  // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in.  The exact
+// name of the namespace is subject to change without notice.
+# define GTEST_CASE_NAMESPACE_(TestCaseName) \
+  gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+  gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+  gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+# define TYPED_TEST_CASE_P(CaseName) \
+  static ::testing::internal::TypedTestCasePState \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+# define TYPED_TEST_P(CaseName, TestName) \
+  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+  template <typename gtest_TypeParam_> \
+  class TestName : public CaseName<gtest_TypeParam_> { \
+   private: \
+    typedef CaseName<gtest_TypeParam_> TestFixture; \
+    typedef gtest_TypeParam_ TypeParam; \
+    virtual void TestBody(); \
+  }; \
+  static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+          __FILE__, __LINE__, #CaseName, #TestName); \
+  } \
+  template <typename gtest_TypeParam_> \
+  void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+  typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+  } \
+  static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+          __FILE__, __LINE__, #__VA_ARGS__)
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+  bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
+      ::testing::internal::TypeParameterizedTestCase<CaseName, \
+          GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+          ::testing::internal::TypeList< Types >::type>::Register(\
+              #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif  // GTEST_HAS_TYPED_TEST_P
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest.h b/lib/gtest-1.7.0/include/gtest/gtest.h
new file mode 100644
index 0000000..6fa0a39
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest.h
@@ -0,0 +1,2291 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test.  It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy at prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+#include <limits>
+#include <ostream>
+#include <vector>
+
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+#include "gtest/gtest-death-test.h"
+#include "gtest/gtest-message.h"
+#include "gtest/gtest-param-test.h"
+#include "gtest/gtest-printers.h"
+#include "gtest/gtest_prod.h"
+#include "gtest/gtest-test-part.h"
+#include "gtest/gtest-typed-test.h"
+
+// Depending on the platform, different string classes are available.
+// On Linux, in addition to ::std::string, Google also makes use of
+// class ::string, which has the same interface as ::std::string, but
+// has a different implementation.
+//
+// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// ::string is available AND is a distinct type to ::std::string, or
+// define it to 0 to indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// heuristically.
+
+namespace testing {
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flag specifies the random number seed.
+GTEST_DECLARE_int32_(random_seed);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// When this flag is specified, tests' order is randomized on every iteration.
+GTEST_DECLARE_bool_(shuffle);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// When this flag is set with a "host:port" string, on supported
+// platforms test results are streamed to the specified port on
+// the specified host machine.
+GTEST_DECLARE_string_(stream_result_to);
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal {
+
+class AssertHelper;
+class DefaultGlobalTestPartResultReporter;
+class ExecDeathTest;
+class NoExecDeathTest;
+class FinalSuccessChecker;
+class GTestFlagSaver;
+class StreamingListenerTest;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class UnitTestRecordPropertyTestHelper;
+class WindowsDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+                                    const std::string& message);
+
+}  // namespace internal
+
+// The friend relationship of some of these classes is cyclic.
+// If we don't forward declare them the compiler might confuse the classes
+// in friendship clauses with same named classes on the scope.
+class Test;
+class TestCase;
+class TestInfo;
+class UnitTest;
+
+// A class for indicating whether an assertion was successful.  When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that describes how it failed.
+//
+// To create an instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// This class is useful for two purposes:
+//   1. Defining predicate functions to be used with Boolean test assertions
+//      EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
+//   2. Defining predicate-format functions to be
+//      used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// For example, if you define IsEven predicate:
+//
+//   testing::AssertionResult IsEven(int n) {
+//     if ((n % 2) == 0)
+//       return testing::AssertionSuccess();
+//     else
+//       return testing::AssertionFailure() << n << " is odd";
+//   }
+//
+// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
+// will print the message
+//
+//   Value of: IsEven(Fib(5))
+//     Actual: false (5 is odd)
+//   Expected: true
+//
+// instead of a more opaque
+//
+//   Value of: IsEven(Fib(5))
+//     Actual: false
+//   Expected: true
+//
+// in case IsEven is a simple Boolean predicate.
+//
+// If you expect your predicate to be reused and want to support informative
+// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
+// about half as often as positive ones in our tests), supply messages for
+// both success and failure cases:
+//
+//   testing::AssertionResult IsEven(int n) {
+//     if ((n % 2) == 0)
+//       return testing::AssertionSuccess() << n << " is even";
+//     else
+//       return testing::AssertionFailure() << n << " is odd";
+//   }
+//
+// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
+//
+//   Value of: IsEven(Fib(6))
+//     Actual: true (8 is even)
+//   Expected: false
+//
+// NB: Predicates that support negative Boolean assertions have reduced
+// performance in positive ones so be careful not to use them in tests
+// that have lots (tens of thousands) of positive Boolean assertions.
+//
+// To use this class with EXPECT_PRED_FORMAT assertions such as:
+//
+//   // Verifies that Foo() returns an even number.
+//   EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you need to define:
+//
+//   testing::AssertionResult IsEven(const char* expr, int n) {
+//     if ((n % 2) == 0)
+//       return testing::AssertionSuccess();
+//     else
+//       return testing::AssertionFailure()
+//         << "Expected: " << expr << " is even\n  Actual: it's " << n;
+//   }
+//
+// If Foo() returns 5, you will see the following message:
+//
+//   Expected: Foo() is even
+//     Actual: it's 5
+//
+class GTEST_API_ AssertionResult {
+ public:
+  // Copy constructor.
+  // Used in EXPECT_TRUE/FALSE(assertion_result).
+  AssertionResult(const AssertionResult& other);
+  // Used in the EXPECT_TRUE/FALSE(bool_expression).
+  explicit AssertionResult(bool success) : success_(success) {}
+
+  // Returns true iff the assertion succeeded.
+  operator bool() const { return success_; }  // NOLINT
+
+  // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+  AssertionResult operator!() const;
+
+  // Returns the text streamed into this AssertionResult. Test assertions
+  // use it when they fail (i.e., the predicate's outcome doesn't match the
+  // assertion's expectation). When nothing has been streamed into the
+  // object, returns an empty string.
+  const char* message() const {
+    return message_.get() != NULL ?  message_->c_str() : "";
+  }
+  // TODO(vladl at google.com): Remove this after making sure no clients use it.
+  // Deprecated; please use message() instead.
+  const char* failure_message() const { return message(); }
+
+  // Streams a custom failure message into this object.
+  template <typename T> AssertionResult& operator<<(const T& value) {
+    AppendMessage(Message() << value);
+    return *this;
+  }
+
+  // Allows streaming basic output manipulators such as endl or flush into
+  // this object.
+  AssertionResult& operator<<(
+      ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) {
+    AppendMessage(Message() << basic_manipulator);
+    return *this;
+  }
+
+ private:
+  // Appends the contents of message to message_.
+  void AppendMessage(const Message& a_message) {
+    if (message_.get() == NULL)
+      message_.reset(new ::std::string);
+    message_->append(a_message.GetString().c_str());
+  }
+
+  // Stores result of the assertion predicate.
+  bool success_;
+  // Stores the message describing the condition in case the expectation
+  // construct is not satisfied with the predicate's outcome.
+  // Referenced via a pointer to avoid taking too much stack frame space
+  // with test assertions.
+  internal::scoped_ptr< ::std::string> message_;
+
+  GTEST_DISALLOW_ASSIGN_(AssertionResult);
+};
+
+// Makes a successful assertion result.
+GTEST_API_ AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result.
+GTEST_API_ AssertionResult AssertionFailure();
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << msg.
+GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F.  For example:
+//
+//   class FooTest : public testing::Test {
+//    protected:
+//     virtual void SetUp() { ... }
+//     virtual void TearDown() { ... }
+//     ...
+//   };
+//
+//   TEST_F(FooTest, Bar) { ... }
+//   TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test {
+ public:
+  friend class TestInfo;
+
+  // Defines types for pointers to functions that set up and tear down
+  // a test case.
+  typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+  typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+  // The d'tor is virtual as we intend to inherit from Test.
+  virtual ~Test();
+
+  // Sets up the stuff shared by all tests in this test case.
+  //
+  // Google Test will call Foo::SetUpTestCase() before running the first
+  // test in test case Foo.  Hence a sub-class can define its own
+  // SetUpTestCase() method to shadow the one defined in the super
+  // class.
+  static void SetUpTestCase() {}
+
+  // Tears down the stuff shared by all tests in this test case.
+  //
+  // Google Test will call Foo::TearDownTestCase() after running the last
+  // test in test case Foo.  Hence a sub-class can define its own
+  // TearDownTestCase() method to shadow the one defined in the super
+  // class.
+  static void TearDownTestCase() {}
+
+  // Returns true iff the current test has a fatal failure.
+  static bool HasFatalFailure();
+
+  // Returns true iff the current test has a non-fatal failure.
+  static bool HasNonfatalFailure();
+
+  // Returns true iff the current test has a (either fatal or
+  // non-fatal) failure.
+  static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+  // Logs a property for the current test, test case, or for the entire
+  // invocation of the test program when used outside of the context of a
+  // test case.  Only the last value for a given key is remembered.  These
+  // are public static so they can be called from utility functions that are
+  // not members of the test fixture.  Calls to RecordProperty made during
+  // lifespan of the test (from the moment its constructor starts to the
+  // moment its destructor finishes) will be output in XML as attributes of
+  // the <testcase> element.  Properties recorded from fixture's
+  // SetUpTestCase or TearDownTestCase are logged as attributes of the
+  // corresponding <testsuite> element.  Calls to RecordProperty made in the
+  // global context (before or after invocation of RUN_ALL_TESTS and from
+  // SetUp/TearDown method of Environment objects registered with Google
+  // Test) will be output as attributes of the <testsuites> element.
+  static void RecordProperty(const std::string& key, const std::string& value);
+  static void RecordProperty(const std::string& key, int value);
+
+ protected:
+  // Creates a Test object.
+  Test();
+
+  // Sets up the test fixture.
+  virtual void SetUp();
+
+  // Tears down the test fixture.
+  virtual void TearDown();
+
+ private:
+  // Returns true iff the current test has the same fixture class as
+  // the first test in the current test case.
+  static bool HasSameFixtureClass();
+
+  // Runs the test after the test fixture has been set up.
+  //
+  // A sub-class must implement this to define the test logic.
+  //
+  // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+  // Instead, use the TEST or TEST_F macro.
+  virtual void TestBody() = 0;
+
+  // Sets up, executes, and tears down the test.
+  void Run();
+
+  // Deletes self.  We deliberately pick an unusual name for this
+  // internal method to avoid clashing with names used in user TESTs.
+  void DeleteSelf_() { delete this; }
+
+  // Uses a GTestFlagSaver to save and restore all Google Test flags.
+  const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+  // Often a user mis-spells SetUp() as Setup() and spends a long time
+  // wondering why it is never called by Google Test.  The declaration of
+  // the following method is solely for catching such an error at
+  // compile time:
+  //
+  //   - The return type is deliberately chosen to be not void, so it
+  //   will be a conflict if a user declares void Setup() in his test
+  //   fixture.
+  //
+  //   - This method is private, so it will be another compiler error
+  //   if a user calls it from his test fixture.
+  //
+  // DO NOT OVERRIDE THIS FUNCTION.
+  //
+  // If you see an error about overriding the following function or
+  // about it being private, you have mis-spelled SetUp() as Setup().
+  struct Setup_should_be_spelled_SetUp {};
+  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+  // We disallow copying Tests.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+typedef internal::TimeInMillis TimeInMillis;
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+  // C'tor.  TestProperty does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestProperty object.
+  TestProperty(const std::string& a_key, const std::string& a_value) :
+    key_(a_key), value_(a_value) {
+  }
+
+  // Gets the user supplied key.
+  const char* key() const {
+    return key_.c_str();
+  }
+
+  // Gets the user supplied value.
+  const char* value() const {
+    return value_.c_str();
+  }
+
+  // Sets a new value, overriding the one supplied in the constructor.
+  void SetValue(const std::string& new_value) {
+    value_ = new_value;
+  }
+
+ private:
+  // The key supplied by the user.
+  std::string key_;
+  // The value supplied by the user.
+  std::string value_;
+};
+
+// The result of a single Test.  This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class GTEST_API_ TestResult {
+ public:
+  // Creates an empty TestResult.
+  TestResult();
+
+  // D'tor.  Do not inherit from TestResult.
+  ~TestResult();
+
+  // Gets the number of all test parts.  This is the sum of the number
+  // of successful test parts and the number of failed test parts.
+  int total_part_count() const;
+
+  // Returns the number of the test properties.
+  int test_property_count() const;
+
+  // Returns true iff the test passed (i.e. no test part failed).
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the test failed.
+  bool Failed() const;
+
+  // Returns true iff the test fatally failed.
+  bool HasFatalFailure() const;
+
+  // Returns true iff the test has a non-fatal failure.
+  bool HasNonfatalFailure() const;
+
+  // Returns the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns the i-th test part result among all the results. i can range
+  // from 0 to test_property_count() - 1. If i is not in that range, aborts
+  // the program.
+  const TestPartResult& GetTestPartResult(int i) const;
+
+  // Returns the i-th test property. i can range from 0 to
+  // test_property_count() - 1. If i is not in that range, aborts the
+  // program.
+  const TestProperty& GetTestProperty(int i) const;
+
+ private:
+  friend class TestInfo;
+  friend class TestCase;
+  friend class UnitTest;
+  friend class internal::DefaultGlobalTestPartResultReporter;
+  friend class internal::ExecDeathTest;
+  friend class internal::TestResultAccessor;
+  friend class internal::UnitTestImpl;
+  friend class internal::WindowsDeathTest;
+
+  // Gets the vector of TestPartResults.
+  const std::vector<TestPartResult>& test_part_results() const {
+    return test_part_results_;
+  }
+
+  // Gets the vector of TestProperties.
+  const std::vector<TestProperty>& test_properties() const {
+    return test_properties_;
+  }
+
+  // Sets the elapsed time.
+  void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+  // Adds a test property to the list. The property is validated and may add
+  // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+  // key names). If a property is already recorded for the same key, the
+  // value will be updated, rather than storing multiple values for the same
+  // key.  xml_element specifies the element for which the property is being
+  // recorded and is used for validation.
+  void RecordProperty(const std::string& xml_element,
+                      const TestProperty& test_property);
+
+  // Adds a failure if the key is a reserved attribute of Google Test
+  // testcase tags.  Returns true if the property is valid.
+  // TODO(russr): Validate attribute names are legal and human readable.
+  static bool ValidateTestProperty(const std::string& xml_element,
+                                   const TestProperty& test_property);
+
+  // Adds a test part result to the list.
+  void AddTestPartResult(const TestPartResult& test_part_result);
+
+  // Returns the death test count.
+  int death_test_count() const { return death_test_count_; }
+
+  // Increments the death test count, returning the new count.
+  int increment_death_test_count() { return ++death_test_count_; }
+
+  // Clears the test part results.
+  void ClearTestPartResults();
+
+  // Clears the object.
+  void Clear();
+
+  // Protects mutable state of the property vector and of owned
+  // properties, whose values may be updated.
+  internal::Mutex test_properites_mutex_;
+
+  // The vector of TestPartResults
+  std::vector<TestPartResult> test_part_results_;
+  // The vector of TestProperties
+  std::vector<TestProperty> test_properties_;
+  // Running count of death tests.
+  int death_test_count_;
+  // The elapsed time, in milliseconds.
+  TimeInMillis elapsed_time_;
+
+  // We disallow copying TestResult.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+};  // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+//   Test case name
+//   Test name
+//   Whether the test should be run
+//   A function pointer that creates the test object when invoked
+//   Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class GTEST_API_ TestInfo {
+ public:
+  // Destructs a TestInfo object.  This function is not virtual, so
+  // don't inherit from TestInfo.
+  ~TestInfo();
+
+  // Returns the test case name.
+  const char* test_case_name() const { return test_case_name_.c_str(); }
+
+  // Returns the test name.
+  const char* name() const { return name_.c_str(); }
+
+  // Returns the name of the parameter type, or NULL if this is not a typed
+  // or a type-parameterized test.
+  const char* type_param() const {
+    if (type_param_.get() != NULL)
+      return type_param_->c_str();
+    return NULL;
+  }
+
+  // Returns the text representation of the value parameter, or NULL if this
+  // is not a value-parameterized test.
+  const char* value_param() const {
+    if (value_param_.get() != NULL)
+      return value_param_->c_str();
+    return NULL;
+  }
+
+  // Returns true if this test should run, that is if the test is not
+  // disabled (or it is disabled but the also_run_disabled_tests flag has
+  // been specified) and its full name matches the user-specified filter.
+  //
+  // Google Test allows the user to filter the tests by their full names.
+  // The full name of a test Bar in test case Foo is defined as
+  // "Foo.Bar".  Only the tests that match the filter will run.
+  //
+  // A filter is a colon-separated list of glob (not regex) patterns,
+  // optionally followed by a '-' and a colon-separated list of
+  // negative patterns (tests to exclude).  A test is run if it
+  // matches one of the positive patterns and does not match any of
+  // the negative patterns.
+  //
+  // For example, *A*:Foo.* is a filter that matches any string that
+  // contains the character 'A' or starts with "Foo.".
+  bool should_run() const { return should_run_; }
+
+  // Returns true iff this test will appear in the XML report.
+  bool is_reportable() const {
+    // For now, the XML report includes all tests matching the filter.
+    // In the future, we may trim tests that are excluded because of
+    // sharding.
+    return matches_filter_;
+  }
+
+  // Returns the result of the test.
+  const TestResult* result() const { return &result_; }
+
+ private:
+#if GTEST_HAS_DEATH_TEST
+  friend class internal::DefaultDeathTestFactory;
+#endif  // GTEST_HAS_DEATH_TEST
+  friend class Test;
+  friend class TestCase;
+  friend class internal::UnitTestImpl;
+  friend class internal::StreamingListenerTest;
+  friend TestInfo* internal::MakeAndRegisterTestInfo(
+      const char* test_case_name,
+      const char* name,
+      const char* type_param,
+      const char* value_param,
+      internal::TypeId fixture_class_id,
+      Test::SetUpTestCaseFunc set_up_tc,
+      Test::TearDownTestCaseFunc tear_down_tc,
+      internal::TestFactoryBase* factory);
+
+  // Constructs a TestInfo object. The newly constructed instance assumes
+  // ownership of the factory object.
+  TestInfo(const std::string& test_case_name,
+           const std::string& name,
+           const char* a_type_param,   // NULL if not a type-parameterized test
+           const char* a_value_param,  // NULL if not a value-parameterized test
+           internal::TypeId fixture_class_id,
+           internal::TestFactoryBase* factory);
+
+  // Increments the number of death tests encountered in this test so
+  // far.
+  int increment_death_test_count() {
+    return result_.increment_death_test_count();
+  }
+
+  // Creates the test object, runs it, records its result, and then
+  // deletes it.
+  void Run();
+
+  static void ClearTestResult(TestInfo* test_info) {
+    test_info->result_.Clear();
+  }
+
+  // These fields are immutable properties of the test.
+  const std::string test_case_name_;     // Test case name
+  const std::string name_;               // Test name
+  // Name of the parameter type, or NULL if this is not a typed or a
+  // type-parameterized test.
+  const internal::scoped_ptr<const ::std::string> type_param_;
+  // Text representation of the value parameter, or NULL if this is not a
+  // value-parameterized test.
+  const internal::scoped_ptr<const ::std::string> value_param_;
+  const internal::TypeId fixture_class_id_;   // ID of the test fixture class
+  bool should_run_;                 // True iff this test should run
+  bool is_disabled_;                // True iff this test is disabled
+  bool matches_filter_;             // True if this test matches the
+                                    // user-specified filter.
+  internal::TestFactoryBase* const factory_;  // The factory that creates
+                                              // the test object
+
+  // This field is mutable and needs to be reset before running the
+  // test for the second time.
+  TestResult result_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// A test case, which consists of a vector of TestInfos.
+//
+// TestCase is not copyable.
+class GTEST_API_ TestCase {
+ public:
+  // Creates a TestCase with the given name.
+  //
+  // TestCase does NOT have a default constructor.  Always use this
+  // constructor to create a TestCase object.
+  //
+  // Arguments:
+  //
+  //   name:         name of the test case
+  //   a_type_param: the name of the test's type parameter, or NULL if
+  //                 this is not a type-parameterized test.
+  //   set_up_tc:    pointer to the function that sets up the test case
+  //   tear_down_tc: pointer to the function that tears down the test case
+  TestCase(const char* name, const char* a_type_param,
+           Test::SetUpTestCaseFunc set_up_tc,
+           Test::TearDownTestCaseFunc tear_down_tc);
+
+  // Destructor of TestCase.
+  virtual ~TestCase();
+
+  // Gets the name of the TestCase.
+  const char* name() const { return name_.c_str(); }
+
+  // Returns the name of the parameter type, or NULL if this is not a
+  // type-parameterized test case.
+  const char* type_param() const {
+    if (type_param_.get() != NULL)
+      return type_param_->c_str();
+    return NULL;
+  }
+
+  // Returns true if any test in this test case should run.
+  bool should_run() const { return should_run_; }
+
+  // Gets the number of successful tests in this test case.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests in this test case.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests that will be reported in the XML report.
+  int reportable_disabled_test_count() const;
+
+  // Gets the number of disabled tests in this test case.
+  int disabled_test_count() const;
+
+  // Gets the number of tests to be printed in the XML report.
+  int reportable_test_count() const;
+
+  // Get the number of tests in this test case that should run.
+  int test_to_run_count() const;
+
+  // Gets the number of all tests in this test case.
+  int total_test_count() const;
+
+  // Returns true iff the test case passed.
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the test case failed.
+  bool Failed() const { return failed_test_count() > 0; }
+
+  // Returns the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns the i-th test among all the tests. i can range from 0 to
+  // total_test_count() - 1. If i is not in that range, returns NULL.
+  const TestInfo* GetTestInfo(int i) const;
+
+  // Returns the TestResult that holds test properties recorded during
+  // execution of SetUpTestCase and TearDownTestCase.
+  const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
+
+ private:
+  friend class Test;
+  friend class internal::UnitTestImpl;
+
+  // Gets the (mutable) vector of TestInfos in this TestCase.
+  std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+  // Gets the (immutable) vector of TestInfos in this TestCase.
+  const std::vector<TestInfo*>& test_info_list() const {
+    return test_info_list_;
+  }
+
+  // Returns the i-th test among all the tests. i can range from 0 to
+  // total_test_count() - 1. If i is not in that range, returns NULL.
+  TestInfo* GetMutableTestInfo(int i);
+
+  // Sets the should_run member.
+  void set_should_run(bool should) { should_run_ = should; }
+
+  // Adds a TestInfo to this test case.  Will delete the TestInfo upon
+  // destruction of the TestCase object.
+  void AddTestInfo(TestInfo * test_info);
+
+  // Clears the results of all tests in this test case.
+  void ClearResult();
+
+  // Clears the results of all tests in the given test case.
+  static void ClearTestCaseResult(TestCase* test_case) {
+    test_case->ClearResult();
+  }
+
+  // Runs every test in this TestCase.
+  void Run();
+
+  // Runs SetUpTestCase() for this TestCase.  This wrapper is needed
+  // for catching exceptions thrown from SetUpTestCase().
+  void RunSetUpTestCase() { (*set_up_tc_)(); }
+
+  // Runs TearDownTestCase() for this TestCase.  This wrapper is
+  // needed for catching exceptions thrown from TearDownTestCase().
+  void RunTearDownTestCase() { (*tear_down_tc_)(); }
+
+  // Returns true iff test passed.
+  static bool TestPassed(const TestInfo* test_info) {
+    return test_info->should_run() && test_info->result()->Passed();
+  }
+
+  // Returns true iff test failed.
+  static bool TestFailed(const TestInfo* test_info) {
+    return test_info->should_run() && test_info->result()->Failed();
+  }
+
+  // Returns true iff the test is disabled and will be reported in the XML
+  // report.
+  static bool TestReportableDisabled(const TestInfo* test_info) {
+    return test_info->is_reportable() && test_info->is_disabled_;
+  }
+
+  // Returns true iff test is disabled.
+  static bool TestDisabled(const TestInfo* test_info) {
+    return test_info->is_disabled_;
+  }
+
+  // Returns true iff this test will appear in the XML report.
+  static bool TestReportable(const TestInfo* test_info) {
+    return test_info->is_reportable();
+  }
+
+  // Returns true if the given test should run.
+  static bool ShouldRunTest(const TestInfo* test_info) {
+    return test_info->should_run();
+  }
+
+  // Shuffles the tests in this test case.
+  void ShuffleTests(internal::Random* random);
+
+  // Restores the test order to before the first shuffle.
+  void UnshuffleTests();
+
+  // Name of the test case.
+  std::string name_;
+  // Name of the parameter type, or NULL if this is not a typed or a
+  // type-parameterized test.
+  const internal::scoped_ptr<const ::std::string> type_param_;
+  // The vector of TestInfos in their original order.  It owns the
+  // elements in the vector.
+  std::vector<TestInfo*> test_info_list_;
+  // Provides a level of indirection for the test list to allow easy
+  // shuffling and restoring the test order.  The i-th element in this
+  // vector is the index of the i-th test in the shuffled test list.
+  std::vector<int> test_indices_;
+  // Pointer to the function that sets up the test case.
+  Test::SetUpTestCaseFunc set_up_tc_;
+  // Pointer to the function that tears down the test case.
+  Test::TearDownTestCaseFunc tear_down_tc_;
+  // True iff any test in this test case should run.
+  bool should_run_;
+  // Elapsed time, in milliseconds.
+  TimeInMillis elapsed_time_;
+  // Holds test properties recorded during execution of SetUpTestCase and
+  // TearDownTestCase.
+  TestResult ad_hoc_test_result_;
+
+  // We disallow copying TestCases.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment.  The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+//   1. You cannot safely throw from a destructor.  This is a problem
+//      as in some cases Google Test is used where exceptions are enabled, and
+//      we may want to implement ASSERT_* using exceptions where they are
+//      available.
+//   2. You cannot use ASSERT_* directly in a constructor or
+//      destructor.
+class Environment {
+ public:
+  // The d'tor is virtual as we need to subclass Environment.
+  virtual ~Environment() {}
+
+  // Override this to define how to set up the environment.
+  virtual void SetUp() {}
+
+  // Override this to define how to tear down the environment.
+  virtual void TearDown() {}
+ private:
+  // If you see an error about overriding the following function or
+  // about it being private, you have mis-spelled SetUp() as Setup().
+  struct Setup_should_be_spelled_SetUp {};
+  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// The interface for tracing execution of tests. The methods are organized in
+// the order the corresponding events are fired.
+class TestEventListener {
+ public:
+  virtual ~TestEventListener() {}
+
+  // Fired before any test activity starts.
+  virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
+
+  // Fired before each iteration of tests starts.  There may be more than
+  // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
+  // index, starting from 0.
+  virtual void OnTestIterationStart(const UnitTest& unit_test,
+                                    int iteration) = 0;
+
+  // Fired before environment set-up for each iteration of tests starts.
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
+
+  // Fired after environment set-up for each iteration of tests ends.
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
+
+  // Fired before the test case starts.
+  virtual void OnTestCaseStart(const TestCase& test_case) = 0;
+
+  // Fired before the test starts.
+  virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+  // Fired after a failed assertion or a SUCCEED() invocation.
+  virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
+
+  // Fired after the test ends.
+  virtual void OnTestEnd(const TestInfo& test_info) = 0;
+
+  // Fired after the test case ends.
+  virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
+
+  // Fired before environment tear-down for each iteration of tests starts.
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
+
+  // Fired after environment tear-down for each iteration of tests ends.
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
+
+  // Fired after each iteration of tests finishes.
+  virtual void OnTestIterationEnd(const UnitTest& unit_test,
+                                  int iteration) = 0;
+
+  // Fired after all test activities have ended.
+  virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
+};
+
+// The convenience class for users who need to override just one or two
+// methods and are not concerned that a possible change to a signature of
+// the methods they override will not be caught during the build.  For
+// comments about each method please see the definition of TestEventListener
+// above.
+class EmptyTestEventListener : public TestEventListener {
+ public:
+  virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+                                    int /*iteration*/) {}
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+  virtual void OnTestStart(const TestInfo& /*test_info*/) {}
+  virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
+  virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
+  virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+                                  int /*iteration*/) {}
+  virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+};
+
+// TestEventListeners lets users add listeners to track events in Google Test.
+class GTEST_API_ TestEventListeners {
+ public:
+  TestEventListeners();
+  ~TestEventListeners();
+
+  // Appends an event listener to the end of the list. Google Test assumes
+  // the ownership of the listener (i.e. it will delete the listener when
+  // the test program finishes).
+  void Append(TestEventListener* listener);
+
+  // Removes the given event listener from the list and returns it.  It then
+  // becomes the caller's responsibility to delete the listener. Returns
+  // NULL if the listener is not found in the list.
+  TestEventListener* Release(TestEventListener* listener);
+
+  // Returns the standard listener responsible for the default console
+  // output.  Can be removed from the listeners list to shut down default
+  // console output.  Note that removing this object from the listener list
+  // with Release transfers its ownership to the caller and makes this
+  // function return NULL the next time.
+  TestEventListener* default_result_printer() const {
+    return default_result_printer_;
+  }
+
+  // Returns the standard listener responsible for the default XML output
+  // controlled by the --gtest_output=xml flag.  Can be removed from the
+  // listeners list by users who want to shut down the default XML output
+  // controlled by this flag and substitute it with custom one.  Note that
+  // removing this object from the listener list with Release transfers its
+  // ownership to the caller and makes this function return NULL the next
+  // time.
+  TestEventListener* default_xml_generator() const {
+    return default_xml_generator_;
+  }
+
+ private:
+  friend class TestCase;
+  friend class TestInfo;
+  friend class internal::DefaultGlobalTestPartResultReporter;
+  friend class internal::NoExecDeathTest;
+  friend class internal::TestEventListenersAccessor;
+  friend class internal::UnitTestImpl;
+
+  // Returns repeater that broadcasts the TestEventListener events to all
+  // subscribers.
+  TestEventListener* repeater();
+
+  // Sets the default_result_printer attribute to the provided listener.
+  // The listener is also added to the listener list and previous
+  // default_result_printer is removed from it and deleted. The listener can
+  // also be NULL in which case it will not be added to the list. Does
+  // nothing if the previous and the current listener objects are the same.
+  void SetDefaultResultPrinter(TestEventListener* listener);
+
+  // Sets the default_xml_generator attribute to the provided listener.  The
+  // listener is also added to the listener list and previous
+  // default_xml_generator is removed from it and deleted. The listener can
+  // also be NULL in which case it will not be added to the list. Does
+  // nothing if the previous and the current listener objects are the same.
+  void SetDefaultXmlGenerator(TestEventListener* listener);
+
+  // Controls whether events will be forwarded by the repeater to the
+  // listeners in the list.
+  bool EventForwardingEnabled() const;
+  void SuppressEventForwarding();
+
+  // The actual list of listeners.
+  internal::TestEventRepeater* repeater_;
+  // Listener responsible for the standard result output.
+  TestEventListener* default_result_printer_;
+  // Listener responsible for the creation of the XML output file.
+  TestEventListener* default_xml_generator_;
+
+  // We disallow copying TestEventListeners.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
+};
+
+// A UnitTest consists of a vector of TestCases.
+//
+// This is a singleton class.  The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called.  This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class GTEST_API_ UnitTest {
+ public:
+  // Gets the singleton UnitTest object.  The first time this method
+  // is called, a UnitTest object is constructed and returned.
+  // Consecutive calls will return the same object.
+  static UnitTest* GetInstance();
+
+  // Runs all tests in this UnitTest object and prints the result.
+  // Returns 0 if successful, or 1 otherwise.
+  //
+  // This method can only be called from the main thread.
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  int Run() GTEST_MUST_USE_RESULT_;
+
+  // Returns the working directory when the first TEST() or TEST_F()
+  // was executed.  The UnitTest object owns the string.
+  const char* original_working_dir() const;
+
+  // Returns the TestCase object for the test that's currently running,
+  // or NULL if no test is running.
+  const TestCase* current_test_case() const
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Returns the TestInfo object for the test that's currently running,
+  // or NULL if no test is running.
+  const TestInfo* current_test_info() const
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Returns the random seed used at the start of the current test run.
+  int random_seed() const;
+
+#if GTEST_HAS_PARAM_TEST
+  // Returns the ParameterizedTestCaseRegistry object used to keep track of
+  // value-parameterized tests and instantiate and register them.
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  internal::ParameterizedTestCaseRegistry& parameterized_test_registry()
+      GTEST_LOCK_EXCLUDED_(mutex_);
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Gets the number of successful test cases.
+  int successful_test_case_count() const;
+
+  // Gets the number of failed test cases.
+  int failed_test_case_count() const;
+
+  // Gets the number of all test cases.
+  int total_test_case_count() const;
+
+  // Gets the number of all test cases that contain at least one test
+  // that should run.
+  int test_case_to_run_count() const;
+
+  // Gets the number of successful tests.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests that will be reported in the XML report.
+  int reportable_disabled_test_count() const;
+
+  // Gets the number of disabled tests.
+  int disabled_test_count() const;
+
+  // Gets the number of tests to be printed in the XML report.
+  int reportable_test_count() const;
+
+  // Gets the number of all tests.
+  int total_test_count() const;
+
+  // Gets the number of tests that should run.
+  int test_to_run_count() const;
+
+  // Gets the time of the test program start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp() const;
+
+  // Gets the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const;
+
+  // Returns true iff the unit test passed (i.e. all test cases passed).
+  bool Passed() const;
+
+  // Returns true iff the unit test failed (i.e. some test case failed
+  // or something outside of all tests failed).
+  bool Failed() const;
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  const TestCase* GetTestCase(int i) const;
+
+  // Returns the TestResult containing information on test failures and
+  // properties logged outside of individual test cases.
+  const TestResult& ad_hoc_test_result() const;
+
+  // Returns the list of event listeners that can be used to track events
+  // inside Google Test.
+  TestEventListeners& listeners();
+
+ private:
+  // Registers and returns a global test environment.  When a test
+  // program is run, all global test environments will be set-up in
+  // the order they were registered.  After all tests in the program
+  // have finished, all global test environments will be torn-down in
+  // the *reverse* order they were registered.
+  //
+  // The UnitTest object takes ownership of the given environment.
+  //
+  // This method can only be called from the main thread.
+  Environment* AddEnvironment(Environment* env);
+
+  // Adds a TestPartResult to the current TestResult object.  All
+  // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+  // eventually call this to report their results.  The user code
+  // should use the assertion macros instead of calling this directly.
+  void AddTestPartResult(TestPartResult::Type result_type,
+                         const char* file_name,
+                         int line_number,
+                         const std::string& message,
+                         const std::string& os_stack_trace)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Adds a TestProperty to the current TestResult object when invoked from
+  // inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+  // from SetUpTestCase or TearDownTestCase, or to the global property set
+  // when invoked elsewhere.  If the result already contains a property with
+  // the same key, the value will be updated.
+  void RecordProperty(const std::string& key, const std::string& value);
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  TestCase* GetMutableTestCase(int i);
+
+  // Accessors for the implementation object.
+  internal::UnitTestImpl* impl() { return impl_; }
+  const internal::UnitTestImpl* impl() const { return impl_; }
+
+  // These classes and funcions are friends as they need to access private
+  // members of UnitTest.
+  friend class Test;
+  friend class internal::AssertHelper;
+  friend class internal::ScopedTrace;
+  friend class internal::StreamingListenerTest;
+  friend class internal::UnitTestRecordPropertyTestHelper;
+  friend Environment* AddGlobalTestEnvironment(Environment* env);
+  friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+  friend void internal::ReportFailureInUnknownLocation(
+      TestPartResult::Type result_type,
+      const std::string& message);
+
+  // Creates an empty UnitTest.
+  UnitTest();
+
+  // D'tor
+  virtual ~UnitTest();
+
+  // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+  // Google Test trace stack.
+  void PushGTestTrace(const internal::TraceInfo& trace)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Pops a trace from the per-thread Google Test trace stack.
+  void PopGTestTrace()
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // Protects mutable state in *impl_.  This is mutable as some const
+  // methods need to lock it too.
+  mutable internal::Mutex mutex_;
+
+  // Opaque implementation object.  This field is never changed once
+  // the object is constructed.  We don't mark it as const here, as
+  // doing so will cause a warning in the constructor of UnitTest.
+  // Mutable state in *impl_ is protected by mutex_.
+  internal::UnitTestImpl* impl_;
+
+  // We disallow copying UnitTest.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main().  If you use gtest_main, you need to call this before main()
+// starts for it to take effect.  For example, you can define a global
+// variable like this:
+//
+//   testing::Environment* const foo_env =
+//       testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+  return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test.  This must be called before calling
+// RUN_ALL_TESTS().  In particular, it parses a command line for the
+// flags that Google Test recognizes.  Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned.  Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+GTEST_API_ void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal {
+
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ).  OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value.  In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object.  If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison {
+ public:
+  static ::std::string Format(const ToPrint& value) {
+    return ::testing::PrintToString(value);
+  }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand> {
+ public:
+  static ::std::string Format(const ToPrint* value) {
+    return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+  }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType)                \
+  template <typename OtherOperand>                                      \
+  class FormatForComparison<CharType*, OtherOperand> {                  \
+   public:                                                              \
+    static ::std::string Format(CharType* value) {                      \
+      return ::testing::PrintToString(static_cast<const void*>(value)); \
+    }                                                                   \
+  }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+  template <>                                                           \
+  class FormatForComparison<CharType*, OtherStringType> {               \
+   public:                                                              \
+    static ::std::string Format(CharType* value) {                      \
+      return ::testing::PrintToString(value);                           \
+    }                                                                   \
+  }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
+#endif
+
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message.  The type (but not value)
+// of the other operand may affect the format.  This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(
+    const T1& value, const T2& /* other_operand */) {
+  return FormatForComparison<T1, T2>::Format(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            const T1& expected,
+                            const T2& actual) {
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4389)  // Temporarily disables warning on
+                                // signed/unsigned mismatch.
+#endif
+
+  if (expected == actual) {
+    return AssertionSuccess();
+  }
+
+#ifdef _MSC_VER
+# pragma warning(pop)          // Restores the warning state.
+#endif
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   FormatForComparisonFailureMessage(expected, actual),
+                   FormatForComparisonFailureMessage(actual, expected),
+                   false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
+                                       const char* actual_expression,
+                                       BiggestInt expected,
+                                       BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ.  The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal.  The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+  // This templatized version is for the general case.
+  template <typename T1, typename T2>
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 const T1& expected,
+                                 const T2& actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+
+  // With this overloaded version, we allow anonymous enums to be used
+  // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+  // enums can be implicitly cast to BiggestInt.
+  //
+  // Even though its body looks the same as the above version, we
+  // cannot merge the two, as it will make anonymous enums unhappy.
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 BiggestInt expected,
+                                 BiggestInt actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal, like NULL, false, or 0.
+template <>
+class EqHelper<true> {
+ public:
+  // We define two overloaded versions of Compare().  The first
+  // version will be picked when the second argument to ASSERT_EQ() is
+  // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+  // EXPECT_EQ(false, a_bool).
+  template <typename T1, typename T2>
+  static AssertionResult Compare(
+      const char* expected_expression,
+      const char* actual_expression,
+      const T1& expected,
+      const T2& actual,
+      // The following line prevents this overload from being considered if T2
+      // is not a pointer type.  We need this because ASSERT_EQ(NULL, my_ptr)
+      // expands to Compare("", "", NULL, my_ptr), which requires a conversion
+      // to match the Secret* in the other overload, which would otherwise make
+      // this template match better.
+      typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+
+  // This version will be picked when the second argument to ASSERT_EQ() is a
+  // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+  template <typename T>
+  static AssertionResult Compare(
+      const char* expected_expression,
+      const char* actual_expression,
+      // We used to have a second template parameter instead of Secret*.  That
+      // template parameter would deduce to 'long', making this a better match
+      // than the first overload even without the first overload's EnableIf.
+      // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
+      // non-pointer argument" (even a deduced integral argument), so the old
+      // implementation caused warnings in user code.
+      Secret* /* expected (NULL) */,
+      T* actual) {
+    // We already know that 'expected' is a null pointer.
+    return CmpHelperEQ(expected_expression, actual_expression,
+                       static_cast<T*>(NULL), actual);
+  }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   const T1& val1, const T2& val2) {\
+  if (val1 op val2) {\
+    return AssertionSuccess();\
+  } else {\
+    return AssertionFailure() \
+        << "Expected: (" << expr1 << ") " #op " (" << expr2\
+        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+  }\
+}\
+GTEST_API_ AssertionResult CmpHelper##op_name(\
+    const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=);
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=);
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, <);
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=);
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, >);
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                                          const char* actual_expression,
+                                          const char* expected,
+                                          const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+                                              const char* actual_expression,
+                                              const char* expected,
+                                              const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                                          const char* s2_expression,
+                                          const char* s1,
+                                          const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+                                              const char* s2_expression,
+                                              const char* s1,
+                                              const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                                          const char* actual_expression,
+                                          const wchar_t* expected,
+                                          const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                                          const char* s2_expression,
+                                          const wchar_t* s1,
+                                          const wchar_t* s2);
+
+}  // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves.  They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif  // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+//   RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+                                         const char* actual_expression,
+                                         RawType expected,
+                                         RawType actual) {
+  const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+  if (lhs.AlmostEquals(rhs)) {
+    return AssertionSuccess();
+  }
+
+  ::std::stringstream expected_ss;
+  expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+              << expected;
+
+  ::std::stringstream actual_ss;
+  actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+            << actual;
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   StringStreamToString(&expected_ss),
+                   StringStreamToString(&actual_ss),
+                   false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
+                                                const char* expr2,
+                                                const char* abs_error_expr,
+                                                double val1,
+                                                double val2,
+                                                double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class GTEST_API_ AssertHelper {
+ public:
+  // Constructor.
+  AssertHelper(TestPartResult::Type type,
+               const char* file,
+               int line,
+               const char* message);
+  ~AssertHelper();
+
+  // Message assignment is a semantic trick to enable assertion
+  // streaming; see the GTEST_MESSAGE_ macro below.
+  void operator=(const Message& message) const;
+
+ private:
+  // We put our data in a struct so that the size of the AssertHelper class can
+  // be as small as possible.  This is important because gcc is incapable of
+  // re-using stack space even for temporary variables, so every EXPECT_EQ
+  // reserves stack space for another AssertHelper.
+  struct AssertHelperData {
+    AssertHelperData(TestPartResult::Type t,
+                     const char* srcfile,
+                     int line_num,
+                     const char* msg)
+        : type(t), file(srcfile), line(line_num), message(msg) { }
+
+    TestPartResult::Type const type;
+    const char* const file;
+    int const line;
+    std::string const message;
+
+   private:
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
+  };
+
+  AssertHelperData* const data_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+}  // namespace internal
+
+#if GTEST_HAS_PARAM_TEST
+// The pure interface class that all value-parameterized tests inherit from.
+// A value-parameterized class must inherit from both ::testing::Test and
+// ::testing::WithParamInterface. In most cases that just means inheriting
+// from ::testing::TestWithParam, but more complicated test hierarchies
+// may need to inherit from Test and WithParamInterface at different levels.
+//
+// This interface has support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+//  protected:
+//   FooTest() {
+//     // Can use GetParam() here.
+//   }
+//   virtual ~FooTest() {
+//     // Can use GetParam() here.
+//   }
+//   virtual void SetUp() {
+//     // Can use GetParam() here.
+//   }
+//   virtual void TearDown {
+//     // Can use GetParam() here.
+//   }
+// };
+// TEST_P(FooTest, DoesBar) {
+//   // Can use GetParam() method here.
+//   Foo foo;
+//   ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class WithParamInterface {
+ public:
+  typedef T ParamType;
+  virtual ~WithParamInterface() {}
+
+  // The current parameter value. Is also available in the test fixture's
+  // constructor. This member function is non-static, even though it only
+  // references static data, to reduce the opportunity for incorrect uses
+  // like writing 'WithParamInterface<bool>::GetParam()' for a test that
+  // uses a fixture whose parameter type is int.
+  const ParamType& GetParam() const {
+    GTEST_CHECK_(parameter_ != NULL)
+        << "GetParam() can only be called inside a value-parameterized test "
+        << "-- did you intend to write TEST_P instead of TEST_F?";
+    return *parameter_;
+  }
+
+ private:
+  // Sets parameter value. The caller is responsible for making sure the value
+  // remains alive and unchanged throughout the current test.
+  static void SetParam(const ParamType* parameter) {
+    parameter_ = parameter;
+  }
+
+  // Static value used for accessing parameter during a test lifetime.
+  static const ParamType* parameter_;
+
+  // TestClass must be a subclass of WithParamInterface<T> and Test.
+  template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* WithParamInterface<T>::parameter_ = NULL;
+
+// Most value-parameterized classes can ignore the existence of
+// WithParamInterface, and can just inherit from ::testing::TestWithParam.
+
+template <typename T>
+class TestWithParam : public Test, public WithParamInterface<T> {
+};
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied.  If not,
+// it behaves like ADD_FAILURE.  In particular:
+//
+//   EXPECT_TRUE  verifies that a Boolean condition is true.
+//   EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure.  People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a nonfatal failure at the given source file location with
+// a generic message.
+#define ADD_FAILURE_AT(file, line) \
+  GTEST_MESSAGE_AT_(file, line, "Failed", \
+                    ::testing::TestPartResult::kNonFatalFailure)
+
+// Generates a fatal failure with a generic message.
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+# define FAIL() GTEST_FAIL()
+#endif
+
+// Generates a success with a generic message.
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+# define SUCCEED() GTEST_SUCCEED()
+#endif
+
+// Macros for testing exceptions.
+//
+//    * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+//         Tests that the statement throws the expected exception.
+//    * {ASSERT|EXPECT}_NO_THROW(statement):
+//         Tests that the statement doesn't throw any exception.
+//    * {ASSERT|EXPECT}_ANY_THROW(statement):
+//         Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+  GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+  GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+  GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+  GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+  GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+  GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions. Condition can be either a Boolean expression or an
+// AssertionResult. For more information on how to use AssertionResult with
+// these macros see comments on that class.
+#define EXPECT_TRUE(condition) \
+  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+                      GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+                      GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+                      GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+                      GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+#include "gtest/gtest_pred_impl.h"
+
+// Macros for testing equalities and inequalities.
+//
+//    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+//    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2
+//    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2
+//    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2
+//    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2
+//    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values.  The values must be compatible built-in types,
+// or you will get a compiler error.  By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+//   1. It is possible to make a user-defined type work with
+//   {ASSERT|EXPECT}_??(), but that requires overloading the
+//   comparison operators and is thus discouraged by the Google C++
+//   Usage Guide.  Therefore, you are advised to use the
+//   {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+//   equal.
+//
+//   2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+//   pointers (in particular, C strings).  Therefore, if you use it
+//   with two C strings, you are testing how their locations in memory
+//   are related, not how their content is related.  To compare two C
+//   strings by content, use {ASSERT|EXPECT}_STR*().
+//
+//   3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+//   {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+//   what the actual value is when it fails, and similarly for the
+//   other comparisons.
+//
+//   4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+//   evaluate their arguments, which is undefined.
+//
+//   5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+//   EXPECT_NE(5, Foo());
+//   EXPECT_EQ(NULL, a_pointer);
+//   ASSERT_LT(i, array_size);
+//   ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal:: \
+                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+                      expected, actual)
+#define EXPECT_NE(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define GTEST_ASSERT_EQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal:: \
+                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+                      expected, actual)
+#define GTEST_ASSERT_NE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define GTEST_ASSERT_LE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define GTEST_ASSERT_LT(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define GTEST_ASSERT_GE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define GTEST_ASSERT_GT(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
+// ASSERT_XY(), which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_ASSERT_EQ
+# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_NE
+# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LE
+# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LT
+# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GE
+# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GT
+# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
+#endif
+
+// C-string Comparisons.  All tests treat NULL and any non-NULL string
+// as different.  Two NULLs are equal.
+//
+//    * {ASSERT|EXPECT}_STREQ(s1, s2):     Tests that s1 == s2
+//    * {ASSERT|EXPECT}_STRNE(s1, s2):     Tests that s1 != s2
+//    * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+//    * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+//    * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+//         Tests that two float values are almost equal.
+//    * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+//         Tests that two double values are almost equal.
+//    * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+//         Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands.  See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+                      expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+                      expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+                      expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+                      expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+  EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+                      val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+  ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+                      val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+//   EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
+                                   float val1, float val2);
+GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
+                                    double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+//    * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+# define EXPECT_HRESULT_SUCCEEDED(expr) \
+    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define ASSERT_HRESULT_SUCCEEDED(expr) \
+    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define EXPECT_HRESULT_FAILED(expr) \
+    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+# define ASSERT_HRESULT_FAILED(expr) \
+    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif  // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+//   * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+//   EXPECT_NO_FATAL_FAILURE(Process());
+//   ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope.  The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+  ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+    __FILE__, __LINE__, ::testing::Message() << (message))
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
+// the same type.  The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template.  This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated.  For example, given:
+//
+//   template <typename T> class Foo {
+//    public:
+//     void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+//   };
+//
+// the code:
+//
+//   void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated.  Instead, you need:
+//
+//   void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+bool StaticAssertTypeEq() {
+  (void)internal::StaticAssertTypeEqHelper<T1, T2>();
+  return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test".  For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro.  Example:
+//
+//   TEST(FooTest, InitializesCorrectly) {
+//     Foo foo;
+//     EXPECT_TRUE(foo.StatusIsOK());
+//   }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test.  This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X.  The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code.  GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define GTEST_TEST(test_case_name, test_name)\
+  GTEST_TEST_(test_case_name, test_name, \
+              ::testing::Test, ::testing::internal::GetTestTypeId())
+
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#endif
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name.  The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier.  The user should put
+// his test code between braces after using this macro.  Example:
+//
+//   class FooTest : public testing::Test {
+//    protected:
+//     virtual void SetUp() { b_.AddElement(3); }
+//
+//     Foo a_;
+//     Foo b_;
+//   };
+//
+//   TEST_F(FooTest, InitializesCorrectly) {
+//     EXPECT_TRUE(a_.StatusIsOK());
+//   }
+//
+//   TEST_F(FooTest, ReturnsElementCountCorrectly) {
+//     EXPECT_EQ(0, a_.size());
+//     EXPECT_EQ(1, b_.size());
+//   }
+
+#define TEST_F(test_fixture, test_name)\
+  GTEST_TEST_(test_fixture, test_name, test_fixture, \
+              ::testing::internal::GetTypeId<test_fixture>())
+
+}  // namespace testing
+
+// Use this function in main() to run all tests.  It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+//
+// This function was formerly a macro; thus, it is in the global
+// namespace and has an all-caps name.
+int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
+
+inline int RUN_ALL_TESTS() {
+  return ::testing::UnitTest::GetInstance()->Run();
+}
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h b/lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h
new file mode 100644
index 0000000..30ae712
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest_pred_impl.h
@@ -0,0 +1,358 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+
+// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
+// 'gen_gtest_pred_impl.py 5'.  DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+# error Do not include gtest_pred_impl.h directly.  Include gtest.h instead.
+#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+//   ASSERT_PRED_FORMAT1(pred_format, v1)
+//   ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+//   ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult.  See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+//   ASSERT_PRED1(pred, v1)
+//   ASSERT_PRED2(pred, v1, v2)
+//   ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework at googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce.  Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const ::testing::AssertionResult gtest_ar = (expression)) \
+    ; \
+  else \
+    on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+                                  const char* e1,
+                                  Pred pred,
+                                  const T1& v1) {
+  if (pred(v1)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, v1), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1.  Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+                                             #v1, \
+                                             pred, \
+                                             v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+  GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+  GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2) {
+  if (pred(v1, v2)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2.  Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             pred, \
+                                             v1, \
+                                             v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+  GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+  GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3) {
+  if (pred(v1, v2, v3)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ", "
+                            << e3 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2
+                            << "\n" << e3 << " evaluates to " << v3;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3.  Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+  GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+  GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  const char* e4,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3,
+                                  const T4& v4) {
+  if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ", "
+                            << e3 << ", "
+                            << e4 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2
+                            << "\n" << e3 << " evaluates to " << v3
+                            << "\n" << e4 << " evaluates to " << v4;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4.  Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             #v4, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3, \
+                                             v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4,
+          typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  const char* e4,
+                                  const char* e5,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3,
+                                  const T4& v4,
+                                  const T5& v5) {
+  if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+  return AssertionFailure() << pred_text << "("
+                            << e1 << ", "
+                            << e2 << ", "
+                            << e3 << ", "
+                            << e4 << ", "
+                            << e5 << ") evaluates to false, where"
+                            << "\n" << e1 << " evaluates to " << v1
+                            << "\n" << e2 << " evaluates to " << v2
+                            << "\n" << e3 << " evaluates to " << v3
+                            << "\n" << e4 << " evaluates to " << v4
+                            << "\n" << e5 << " evaluates to " << v5;
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5.  Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             #v4, \
+                                             #v5, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3, \
+                                             v4, \
+                                             v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/lib/gtest-1.7.0/include/gtest/gtest_prod.h b/lib/gtest-1.7.0/include/gtest/gtest_prod.h
new file mode 100644
index 0000000..da80ddc
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/gtest_prod.h
@@ -0,0 +1,58 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class.  For example:
+//
+// class MyClass {
+//  private:
+//   void MyMethod();
+//   FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+//   // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+//   // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h
new file mode 100644
index 0000000..2b3a78f
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h
@@ -0,0 +1,319 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: wan at google.com (Zhanyong Wan), eefacm at gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests.  They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include "gtest/internal/gtest-internal.h"
+
+#include <stdio.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro.  It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status:  The integer exit information in the format specified
+//               by wait(2)
+// exit code:    The integer code passed to exit(3), _exit(2), or
+//               returned from main()
+class GTEST_API_ DeathTest {
+ public:
+  // Create returns false if there was an error determining the
+  // appropriate action to take for the current death test; for example,
+  // if the gtest_death_test_style flag is set to an invalid value.
+  // The LastMessage method will return a more detailed message in that
+  // case.  Otherwise, the DeathTest pointer pointed to by the "test"
+  // argument is set.  If the death test should be skipped, the pointer
+  // is set to NULL; otherwise, it is set to the address of a new concrete
+  // DeathTest object that controls the execution of the current test.
+  static bool Create(const char* statement, const RE* regex,
+                     const char* file, int line, DeathTest** test);
+  DeathTest();
+  virtual ~DeathTest() { }
+
+  // A helper class that aborts a death test when it's deleted.
+  class ReturnSentinel {
+   public:
+    explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+    ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+   private:
+    DeathTest* const test_;
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+  } GTEST_ATTRIBUTE_UNUSED_;
+
+  // An enumeration of possible roles that may be taken when a death
+  // test is encountered.  EXECUTE means that the death test logic should
+  // be executed immediately.  OVERSEE means that the program should prepare
+  // the appropriate environment for a child process to execute the death
+  // test, then wait for it to complete.
+  enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+  // An enumeration of the three reasons that a test might be aborted.
+  enum AbortReason {
+    TEST_ENCOUNTERED_RETURN_STATEMENT,
+    TEST_THREW_EXCEPTION,
+    TEST_DID_NOT_DIE
+  };
+
+  // Assumes one of the above roles.
+  virtual TestRole AssumeRole() = 0;
+
+  // Waits for the death test to finish and returns its status.
+  virtual int Wait() = 0;
+
+  // Returns true if the death test passed; that is, the test process
+  // exited during the test, its exit status matches a user-supplied
+  // predicate, and its stderr output matches a user-supplied regular
+  // expression.
+  // The user-supplied predicate may be a macro expression rather
+  // than a function pointer or functor, or else Wait and Passed could
+  // be combined.
+  virtual bool Passed(bool exit_status_ok) = 0;
+
+  // Signals that the death test did not die as expected.
+  virtual void Abort(AbortReason reason) = 0;
+
+  // Returns a human-readable outcome message regarding the outcome of
+  // the last death test.
+  static const char* LastMessage();
+
+  static void set_last_death_test_message(const std::string& message);
+
+ private:
+  // A string containing a description of the outcome of the last death test.
+  static std::string last_death_test_message_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests.  May be mocked out for testing.
+class DeathTestFactory {
+ public:
+  virtual ~DeathTestFactory() { }
+  virtual bool Create(const char* statement, const RE* regex,
+                      const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+  virtual bool Create(const char* statement, const RE* regex,
+                      const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+
+// Traps C++ exceptions escaping statement and reports them as test
+// failures. Note that trapping SEH exceptions is not implemented here.
+# if GTEST_HAS_EXCEPTIONS
+#  define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+  try { \
+    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+  } catch (const ::std::exception& gtest_exception) { \
+    fprintf(\
+        stderr, \
+        "\n%s: Caught std::exception-derived exception escaping the " \
+        "death test statement. Exception message: %s\n", \
+        ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
+        gtest_exception.what()); \
+    fflush(stderr); \
+    death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+  } catch (...) { \
+    death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+  }
+
+# else
+#  define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+  GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+
+# endif
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    const ::testing::internal::RE& gtest_regex = (regex); \
+    ::testing::internal::DeathTest* gtest_dt; \
+    if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
+        __FILE__, __LINE__, &gtest_dt)) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+    } \
+    if (gtest_dt != NULL) { \
+      ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+          gtest_dt_ptr(gtest_dt); \
+      switch (gtest_dt->AssumeRole()) { \
+        case ::testing::internal::DeathTest::OVERSEE_TEST: \
+          if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+            goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+          } \
+          break; \
+        case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+          ::testing::internal::DeathTest::ReturnSentinel \
+              gtest_sentinel(gtest_dt); \
+          GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
+          gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+          break; \
+        } \
+        default: \
+          break; \
+      } \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+      fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
+// NDEBUG mode. In this case we need the statements to be executed, the regex is
+// ignored, and the macro must accept a streamed message even though the message
+// is never printed.
+# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+     GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+  } else \
+    ::testing::Message()
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag {
+ public:
+  InternalRunDeathTestFlag(const std::string& a_file,
+                           int a_line,
+                           int an_index,
+                           int a_write_fd)
+      : file_(a_file), line_(a_line), index_(an_index),
+        write_fd_(a_write_fd) {}
+
+  ~InternalRunDeathTestFlag() {
+    if (write_fd_ >= 0)
+      posix::Close(write_fd_);
+  }
+
+  const std::string& file() const { return file_; }
+  int line() const { return line_; }
+  int index() const { return index_; }
+  int write_fd() const { return write_fd_; }
+
+ private:
+  std::string file_;
+  int line_;
+  int index_;
+  int write_fd_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#else  // GTEST_HAS_DEATH_TEST
+
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
+// systems that support death tests. This allows one to write such a macro
+// on a system that does not support death tests and be sure that it will
+// compile on a death-test supporting system.
+//
+// Parameters:
+//   statement -  A statement that a macro such as EXPECT_DEATH would test
+//                for program termination. This macro has to make sure this
+//                statement is compiled but not executed, to ensure that
+//                EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+//                parameter iff EXPECT_DEATH compiles with it.
+//   regex     -  A regex that a macro such as EXPECT_DEATH would use to test
+//                the output of statement.  This parameter has to be
+//                compiled but not evaluated by this macro, to ensure that
+//                this macro only accepts expressions that a macro such as
+//                EXPECT_DEATH would accept.
+//   terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+//                and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+//                This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+//                compile inside functions where ASSERT_DEATH doesn't
+//                compile.
+//
+//  The branch that has an always false condition is used to ensure that
+//  statement and regex are compiled (and thus syntactically correct) but
+//  never executed. The unreachable code macro protects the terminator
+//  statement from generating an 'unreachable code' warning in case
+//  statement unconditionally returns or throws. The Message constructor at
+//  the end allows the syntax of streaming additional messages into the
+//  macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+    if (::testing::internal::AlwaysTrue()) { \
+      GTEST_LOG_(WARNING) \
+          << "Death tests are not supported on this platform.\n" \
+          << "Statement '" #statement "' cannot be verified."; \
+    } else if (::testing::internal::AlwaysFalse()) { \
+      ::testing::internal::RE::PartialMatch(".*", (regex)); \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+      terminator; \
+    } else \
+      ::testing::Message()
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-filepath.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-filepath.h
new file mode 100644
index 0000000..7a13b4b
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-filepath.h
@@ -0,0 +1,206 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: keith.ray at gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test.  They are subject to change without notice.
+//
+// This file is #included in <gtest/internal/gtest-internal.h>.
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#include "gtest/internal/gtest-string.h"
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class GTEST_API_ FilePath {
+ public:
+  FilePath() : pathname_("") { }
+  FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+  explicit FilePath(const std::string& pathname) : pathname_(pathname) {
+    Normalize();
+  }
+
+  FilePath& operator=(const FilePath& rhs) {
+    Set(rhs);
+    return *this;
+  }
+
+  void Set(const FilePath& rhs) {
+    pathname_ = rhs.pathname_;
+  }
+
+  const std::string& string() const { return pathname_; }
+  const char* c_str() const { return pathname_.c_str(); }
+
+  // Returns the current working directory, or "" if unsuccessful.
+  static FilePath GetCurrentDir();
+
+  // Given directory = "dir", base_name = "test", number = 0,
+  // extension = "xml", returns "dir/test.xml". If number is greater
+  // than zero (e.g., 12), returns "dir/test_12.xml".
+  // On Windows platform, uses \ as the separator rather than /.
+  static FilePath MakeFileName(const FilePath& directory,
+                               const FilePath& base_name,
+                               int number,
+                               const char* extension);
+
+  // Given directory = "dir", relative_path = "test.xml",
+  // returns "dir/test.xml".
+  // On Windows, uses \ as the separator rather than /.
+  static FilePath ConcatPaths(const FilePath& directory,
+                              const FilePath& relative_path);
+
+  // Returns a pathname for a file that does not currently exist. The pathname
+  // will be directory/base_name.extension or
+  // directory/base_name_<number>.extension if directory/base_name.extension
+  // already exists. The number will be incremented until a pathname is found
+  // that does not already exist.
+  // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+  // There could be a race condition if two or more processes are calling this
+  // function at the same time -- they could both pick the same filename.
+  static FilePath GenerateUniqueFileName(const FilePath& directory,
+                                         const FilePath& base_name,
+                                         const char* extension);
+
+  // Returns true iff the path is "".
+  bool IsEmpty() const { return pathname_.empty(); }
+
+  // If input name has a trailing separator character, removes it and returns
+  // the name, otherwise return the name string unmodified.
+  // On Windows platform, uses \ as the separator, other platforms use /.
+  FilePath RemoveTrailingPathSeparator() const;
+
+  // Returns a copy of the FilePath with the directory part removed.
+  // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+  // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+  // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+  // returns an empty FilePath ("").
+  // On Windows platform, '\' is the path separator, otherwise it is '/'.
+  FilePath RemoveDirectoryName() const;
+
+  // RemoveFileName returns the directory path with the filename removed.
+  // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+  // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+  // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+  // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+  // On Windows platform, '\' is the path separator, otherwise it is '/'.
+  FilePath RemoveFileName() const;
+
+  // Returns a copy of the FilePath with the case-insensitive extension removed.
+  // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+  // FilePath("dir/file"). If a case-insensitive extension is not
+  // found, returns a copy of the original FilePath.
+  FilePath RemoveExtension(const char* extension) const;
+
+  // Creates directories so that path exists. Returns true if successful or if
+  // the directories already exist; returns false if unable to create
+  // directories for any reason. Will also return false if the FilePath does
+  // not represent a directory (that is, it doesn't end with a path separator).
+  bool CreateDirectoriesRecursively() const;
+
+  // Create the directory so that path exists. Returns true if successful or
+  // if the directory already exists; returns false if unable to create the
+  // directory for any reason, including if the parent directory does not
+  // exist. Not named "CreateDirectory" because that's a macro on Windows.
+  bool CreateFolder() const;
+
+  // Returns true if FilePath describes something in the file-system,
+  // either a file, directory, or whatever, and that something exists.
+  bool FileOrDirectoryExists() const;
+
+  // Returns true if pathname describes a directory in the file-system
+  // that exists.
+  bool DirectoryExists() const;
+
+  // Returns true if FilePath ends with a path separator, which indicates that
+  // it is intended to represent a directory. Returns false otherwise.
+  // This does NOT check that a directory (or file) actually exists.
+  bool IsDirectory() const;
+
+  // Returns true if pathname describes a root directory. (Windows has one
+  // root directory per disk drive.)
+  bool IsRootDirectory() const;
+
+  // Returns true if pathname describes an absolute path.
+  bool IsAbsolutePath() const;
+
+ private:
+  // Replaces multiple consecutive separators with a single separator.
+  // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+  // redundancies that might be in a pathname involving "." or "..".
+  //
+  // A pathname with multiple consecutive separators may occur either through
+  // user error or as a result of some scripts or APIs that generate a pathname
+  // with a trailing separator. On other platforms the same API or script
+  // may NOT generate a pathname with a trailing "/". Then elsewhere that
+  // pathname may have another "/" and pathname components added to it,
+  // without checking for the separator already being there.
+  // The script language and operating system may allow paths like "foo//bar"
+  // but some of the functions in FilePath will not handle that correctly. In
+  // particular, RemoveTrailingPathSeparator() only removes one separator, and
+  // it is called in CreateDirectoriesRecursively() assuming that it will change
+  // a pathname from directory syntax (trailing separator) to filename syntax.
+  //
+  // On Windows this method also replaces the alternate path separator '/' with
+  // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
+  // "bar\\foo".
+
+  void Normalize();
+
+  // Returns a pointer to the last occurence of a valid path separator in
+  // the FilePath. On Windows, for example, both '/' and '\' are valid path
+  // separators. Returns NULL if no path separator was found.
+  const char* FindLastPathSeparator() const;
+
+  std::string pathname_;
+};  // class FilePath
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-internal.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-internal.h
new file mode 100644
index 0000000..0dcc3a3
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-internal.h
@@ -0,0 +1,1158 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: wan at google.com (Zhanyong Wan), eefacm at gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test.  They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_OS_LINUX
+# include <stdlib.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <unistd.h>
+#endif  // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#include <ctype.h>
+#include <float.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-string.h"
+#include "gtest/internal/gtest-filepath.h"
+#include "gtest/internal/gtest-type-util.h"
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__.  Writing
+//
+//   foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number.  For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+class ProtocolMessage;
+namespace proto2 { class Message; }
+
+namespace testing {
+
+// Forward declarations.
+
+class AssertionResult;                 // Result of an assertion.
+class Message;                         // Represents a failure message.
+class Test;                            // Represents a test.
+class TestInfo;                        // Information about a test.
+class TestPartResult;                  // Result of a test part.
+class UnitTest;                        // A collection of test cases.
+
+template <typename T>
+::std::string PrintToString(const T& value);
+
+namespace internal {
+
+struct TraceInfo;                      // Information about a trace point.
+class ScopedTrace;                     // Implements scoped trace.
+class TestInfoImpl;                    // Opaque implementation of TestInfo
+class UnitTestImpl;                    // Opaque implementation of UnitTest
+
+// How many times InitGoogleTest() has been called.
+GTEST_API_ extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant).  Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler.  These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise.  Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal.  Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2];  // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_POD_
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_IS_NULL_LITERAL_(x) false
+#else
+# define GTEST_IS_NULL_LITERAL_(x) \
+    (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif  // GTEST_ELLIPSIS_NEEDS_POD_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ std::string AppendUserMessage(
+    const std::string& gtest_msg, const Message& user_msg);
+
+#if GTEST_HAS_EXCEPTIONS
+
+// This exception is thrown by (and only by) a failed Google Test
+// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
+// are enabled).  We derive it from std::runtime_error, which is for
+// errors presumably detectable only at run time.  Since
+// std::runtime_error inherits from std::exception, many testing
+// frameworks know how to extract and print the message inside it.
+class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
+ public:
+  explicit GoogleTestFailureException(const TestPartResult& failure);
+};
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
+// A helper class for creating scoped traces in user programs.
+class GTEST_API_ ScopedTrace {
+ public:
+  // The c'tor pushes the given source file location and message onto
+  // a trace stack maintained by Google Test.
+  ScopedTrace(const char* file, int line, const Message& message);
+
+  // The d'tor pops the info pushed by the c'tor.
+  //
+  // Note that the d'tor is not virtual in order to be efficient.
+  // Don't inherit from ScopedTrace!
+  ~ScopedTrace();
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_;  // A ScopedTrace object does its job in its
+                            // c'tor and d'tor.  Therefore it doesn't
+                            // need to be used otherwise.
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+//   expected_expression: "foo"
+//   actual_expression:   "bar"
+//   expected_value:      "5"
+//   actual_value:        "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
+                                     const char* actual_expression,
+                                     const std::string& expected_value,
+                                     const std::string& actual_value,
+                                     bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ std::string GetBoolAssertionFailureMessage(
+    const AssertionResult& assertion_result,
+    const char* expression_text,
+    const char* actual_predicate_value,
+    const char* expected_predicate_value);
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison.  (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly.  Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+//   The most-significant bit being the leftmost, an IEEE
+//   floating-point looks like
+//
+//     sign_bit exponent_bits fraction_bits
+//
+//   Here, sign_bit is a single bit that designates the sign of the
+//   number.
+//
+//   For float, there are 8 exponent bits and 23 fraction bits.
+//
+//   For double, there are 11 exponent bits and 52 fraction bits.
+//
+//   More details can be found at
+//   http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+//   RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+  // Defines the unsigned integer type that has the same size as the
+  // floating point number.
+  typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+  // Constants.
+
+  // # of bits in a number.
+  static const size_t kBitCount = 8*sizeof(RawType);
+
+  // # of fraction bits in a number.
+  static const size_t kFractionBitCount =
+    std::numeric_limits<RawType>::digits - 1;
+
+  // # of exponent bits in a number.
+  static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+  // The mask for the sign bit.
+  static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+  // The mask for the fraction bits.
+  static const Bits kFractionBitMask =
+    ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+  // The mask for the exponent bits.
+  static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+  // How many ULP's (Units in the Last Place) we want to tolerate when
+  // comparing two numbers.  The larger the value, the more error we
+  // allow.  A 0 value means that two numbers must be exactly the same
+  // to be considered equal.
+  //
+  // The maximum error of a single floating-point operation is 0.5
+  // units in the last place.  On Intel CPU's, all floating-point
+  // calculations are done with 80-bit precision, while double has 64
+  // bits.  Therefore, 4 should be enough for ordinary use.
+  //
+  // See the following article for more details on ULP:
+  // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+  static const size_t kMaxUlps = 4;
+
+  // Constructs a FloatingPoint from a raw floating-point number.
+  //
+  // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+  // around may change its bits, although the new value is guaranteed
+  // to be also a NAN.  Therefore, don't expect this constructor to
+  // preserve the bits in x when x is a NAN.
+  explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+  // Static methods
+
+  // Reinterprets a bit pattern as a floating-point number.
+  //
+  // This function is needed to test the AlmostEquals() method.
+  static RawType ReinterpretBits(const Bits bits) {
+    FloatingPoint fp(0);
+    fp.u_.bits_ = bits;
+    return fp.u_.value_;
+  }
+
+  // Returns the floating-point number that represent positive infinity.
+  static RawType Infinity() {
+    return ReinterpretBits(kExponentBitMask);
+  }
+
+  // Returns the maximum representable finite floating-point number.
+  static RawType Max();
+
+  // Non-static methods
+
+  // Returns the bits that represents this number.
+  const Bits &bits() const { return u_.bits_; }
+
+  // Returns the exponent bits of this number.
+  Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+  // Returns the fraction bits of this number.
+  Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+  // Returns the sign bit of this number.
+  Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+  // Returns true iff this is NAN (not a number).
+  bool is_nan() const {
+    // It's a NAN if the exponent bits are all ones and the fraction
+    // bits are not entirely zeros.
+    return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+  }
+
+  // Returns true iff this number is at most kMaxUlps ULP's away from
+  // rhs.  In particular, this function:
+  //
+  //   - returns false if either number is (or both are) NAN.
+  //   - treats really large numbers as almost equal to infinity.
+  //   - thinks +0.0 and -0.0 are 0 DLP's apart.
+  bool AlmostEquals(const FloatingPoint& rhs) const {
+    // The IEEE standard says that any comparison operation involving
+    // a NAN must return false.
+    if (is_nan() || rhs.is_nan()) return false;
+
+    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+        <= kMaxUlps;
+  }
+
+ private:
+  // The data type used to store the actual floating-point number.
+  union FloatingPointUnion {
+    RawType value_;  // The raw floating-point number.
+    Bits bits_;      // The bits that represent the number.
+  };
+
+  // Converts an integer from the sign-and-magnitude representation to
+  // the biased representation.  More precisely, let N be 2 to the
+  // power of (kBitCount - 1), an integer x is represented by the
+  // unsigned number x + N.
+  //
+  // For instance,
+  //
+  //   -N + 1 (the most negative number representable using
+  //          sign-and-magnitude) is represented by 1;
+  //   0      is represented by N; and
+  //   N - 1  (the biggest number representable using
+  //          sign-and-magnitude) is represented by 2N - 1.
+  //
+  // Read http://en.wikipedia.org/wiki/Signed_number_representations
+  // for more details on signed number representations.
+  static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+    if (kSignBitMask & sam) {
+      // sam represents a negative number.
+      return ~sam + 1;
+    } else {
+      // sam represents a positive number.
+      return kSignBitMask | sam;
+    }
+  }
+
+  // Given two numbers in the sign-and-magnitude representation,
+  // returns the distance between them as an unsigned number.
+  static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+                                                     const Bits &sam2) {
+    const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+    const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+    return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+  }
+
+  FloatingPointUnion u_;
+};
+
+// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
+// macro defined by <windows.h>.
+template <>
+inline float FloatingPoint<float>::Max() { return FLT_MAX; }
+template <>
+inline double FloatingPoint<double>::Max() { return DBL_MAX; }
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them.  The TypeId type is
+// used to hold such IDs.  The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+  // dummy_ must not have a const type.  Otherwise an overly eager
+  // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+  // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+  static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T.  Different values will be
+// returned for different types.  Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+  // The compiler is required to allocate a different
+  // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+  // the template.  Therefore, the address of dummy_ is guaranteed to
+  // be unique.
+  return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test.  Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+GTEST_API_ TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+  virtual ~TestFactoryBase() {}
+
+  // Creates a test instance to run. The instance is both created and destroyed
+  // within TestInfoImpl::Run()
+  virtual Test* CreateTest() = 0;
+
+ protected:
+  TestFactoryBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+  virtual Test* CreateTest() { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
+                                            long hr);  // NOLINT
+GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
+                                            long hr);  // NOLINT
+
+#endif  // GTEST_OS_WINDOWS
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+//   test_case_name:   name of the test case
+//   name:             name of the test
+//   type_param        the name of the test's type parameter, or NULL if
+//                     this is not a typed or a type-parameterized test.
+//   value_param       text representation of the test's value parameter,
+//                     or NULL if this is not a type-parameterized test.
+//   fixture_class_id: ID of the test fixture class
+//   set_up_tc:        pointer to the function that sets up the test case
+//   tear_down_tc:     pointer to the function that tears down the test case
+//   factory:          pointer to the factory that creates a test object.
+//                     The newly created TestInfo instance will assume
+//                     ownership of the factory object.
+GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
+    const char* test_case_name,
+    const char* name,
+    const char* type_param,
+    const char* value_param,
+    TypeId fixture_class_id,
+    SetUpTestCaseFunc set_up_tc,
+    TearDownTestCaseFunc tear_down_tc,
+    TestFactoryBase* factory);
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false.  None of pstr, *pstr, and prefix can be NULL.
+GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// State of the definition of a type-parameterized test case.
+class GTEST_API_ TypedTestCasePState {
+ public:
+  TypedTestCasePState() : registered_(false) {}
+
+  // Adds the given test name to defined_test_names_ and return true
+  // if the test case hasn't been registered; otherwise aborts the
+  // program.
+  bool AddTestName(const char* file, int line, const char* case_name,
+                   const char* test_name) {
+    if (registered_) {
+      fprintf(stderr, "%s Test %s must be defined before "
+              "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+              FormatFileLocation(file, line).c_str(), test_name, case_name);
+      fflush(stderr);
+      posix::Abort();
+    }
+    defined_test_names_.insert(test_name);
+    return true;
+  }
+
+  // Verifies that registered_tests match the test names in
+  // defined_test_names_; returns registered_tests if successful, or
+  // aborts the program otherwise.
+  const char* VerifyRegisteredTestNames(
+      const char* file, int line, const char* registered_tests);
+
+ private:
+  bool registered_;
+  ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+  const char* comma = strchr(str, ',');
+  if (comma == NULL) {
+    return NULL;
+  }
+  while (IsSpace(*(++comma))) {}
+  return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline std::string GetPrefixUntilComma(const char* str) {
+  const char* comma = strchr(str, ',');
+  return comma == NULL ? str : std::string(str, comma);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test.  The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter.  It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+  // 'index' is the index of the test in the type list 'Types'
+  // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+  // Types).  Valid values for 'index' are [0, N - 1] where N is the
+  // length of Types.
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names, int index) {
+    typedef typename Types::Head Type;
+    typedef Fixture<Type> FixtureClass;
+    typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+    // First, registers the first type-parameterized test in the type
+    // list.
+    MakeAndRegisterTestInfo(
+        (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
+         + StreamableToString(index)).c_str(),
+        GetPrefixUntilComma(test_names).c_str(),
+        GetTypeName<Type>().c_str(),
+        NULL,  // No value parameter.
+        GetTypeId<FixtureClass>(),
+        TestClass::SetUpTestCase,
+        TestClass::TearDownTestCase,
+        new TestFactoryImpl<TestClass>);
+
+    // Next, recurses (at compile time) with the tail of the type list.
+    return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+        ::Register(prefix, case_name, test_names, index + 1);
+  }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+                       const char* /*test_names*/, int /*index*/) {
+    return true;
+  }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test.  The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names) {
+    typedef typename Tests::Head Head;
+
+    // First, register the first test in 'Test' for each type in 'Types'.
+    TypeParameterizedTest<Fixture, Head, Types>::Register(
+        prefix, case_name, test_names, 0);
+
+    // Next, recurses (at compile time) with the tail of the test list.
+    return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+        ::Register(prefix, case_name, SkipComma(test_names));
+  }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+                       const char* /*test_names*/) {
+    return true;
+  }
+};
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
+    UnitTest* unit_test, int skip_count);
+
+// Helpers for suppressing warnings on unreachable code or constant
+// condition.
+
+// Always returns true.
+GTEST_API_ bool AlwaysTrue();
+
+// Always returns false.
+inline bool AlwaysFalse() { return !AlwaysTrue(); }
+
+// Helper for suppressing false warning from Clang on a const char*
+// variable declared in a conditional expression always being NULL in
+// the else branch.
+struct GTEST_API_ ConstCharPtr {
+  ConstCharPtr(const char* str) : value(str) {}
+  operator bool() const { return true; }
+  const char* value;
+};
+
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution.  Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code).  Unlike rand_r(), it's portable.  An LCG isn't very random,
+// but it's good enough for our purposes.
+class GTEST_API_ Random {
+ public:
+  static const UInt32 kMaxRange = 1u << 31;
+
+  explicit Random(UInt32 seed) : state_(seed) {}
+
+  void Reseed(UInt32 seed) { state_ = seed; }
+
+  // Generates a random number from [0, range).  Crashes if 'range' is
+  // 0 or greater than kMaxRange.
+  UInt32 Generate(UInt32 range);
+
+ private:
+  UInt32 state_;
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
+// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
+// compiler error iff T1 and T2 are different types.
+template <typename T1, typename T2>
+struct CompileAssertTypesEqual;
+
+template <typename T>
+struct CompileAssertTypesEqual<T, T> {
+};
+
+// Removes the reference from a type if it is a reference type,
+// otherwise leaves it unchanged.  This is the same as
+// tr1::remove_reference, which is not widely available yet.
+template <typename T>
+struct RemoveReference { typedef T type; };  // NOLINT
+template <typename T>
+struct RemoveReference<T&> { typedef T type; };  // NOLINT
+
+// A handy wrapper around RemoveReference that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_REFERENCE_(T) \
+    typename ::testing::internal::RemoveReference<T>::type
+
+// Removes const from a type if it is a const type, otherwise leaves
+// it unchanged.  This is the same as tr1::remove_const, which is not
+// widely available yet.
+template <typename T>
+struct RemoveConst { typedef T type; };  // NOLINT
+template <typename T>
+struct RemoveConst<const T> { typedef T type; };  // NOLINT
+
+// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
+// definition to fail to remove the const in 'const int[3]' and 'const
+// char[3][4]'.  The following specialization works around the bug.
+template <typename T, size_t N>
+struct RemoveConst<const T[N]> {
+  typedef typename RemoveConst<T>::type type[N];
+};
+
+#if defined(_MSC_VER) && _MSC_VER < 1400
+// This is the only specialization that allows VC++ 7.1 to remove const in
+// 'const int[3] and 'const int[3][4]'.  However, it causes trouble with GCC
+// and thus needs to be conditionally compiled.
+template <typename T, size_t N>
+struct RemoveConst<T[N]> {
+  typedef typename RemoveConst<T>::type type[N];
+};
+#endif
+
+// A handy wrapper around RemoveConst that works when the argument
+// T depends on template parameters.
+#define GTEST_REMOVE_CONST_(T) \
+    typename ::testing::internal::RemoveConst<T>::type
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+    GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
+
+// Adds reference to a type if it is not a reference type,
+// otherwise leaves it unchanged.  This is the same as
+// tr1::add_reference, which is not widely available yet.
+template <typename T>
+struct AddReference { typedef T& type; };  // NOLINT
+template <typename T>
+struct AddReference<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper around AddReference that works when the argument T
+// depends on template parameters.
+#define GTEST_ADD_REFERENCE_(T) \
+    typename ::testing::internal::AddReference<T>::type
+
+// Adds a reference to const on top of T as necessary.  For example,
+// it transforms
+//
+//   char         ==> const char&
+//   const char   ==> const char&
+//   char&        ==> const char&
+//   const char&  ==> const char&
+//
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+    GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T))
+
+// ImplicitlyConvertible<From, To>::value is a compile-time bool
+// constant that's true iff type From can be implicitly converted to
+// type To.
+template <typename From, typename To>
+class ImplicitlyConvertible {
+ private:
+  // We need the following helper functions only for their types.
+  // They have no implementations.
+
+  // MakeFrom() is an expression whose type is From.  We cannot simply
+  // use From(), as the type From may not have a public default
+  // constructor.
+  static From MakeFrom();
+
+  // These two functions are overloaded.  Given an expression
+  // Helper(x), the compiler will pick the first version if x can be
+  // implicitly converted to type To; otherwise it will pick the
+  // second version.
+  //
+  // The first version returns a value of size 1, and the second
+  // version returns a value of size 2.  Therefore, by checking the
+  // size of Helper(x), which can be done at compile time, we can tell
+  // which version of Helper() is used, and hence whether x can be
+  // implicitly converted to type To.
+  static char Helper(To);
+  static char (&Helper(...))[2];  // NOLINT
+
+  // We have to put the 'public' section after the 'private' section,
+  // or MSVC refuses to compile the code.
+ public:
+  // MSVC warns about implicitly converting from double to int for
+  // possible loss of data, so we need to temporarily disable the
+  // warning.
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4244)  // Temporarily disables warning 4244.
+
+  static const bool value =
+      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+# pragma warning(pop)           // Restores the warning state.
+#elif defined(__BORLANDC__)
+  // C++Builder cannot use member overload resolution during template
+  // instantiation.  The simplest workaround is to use its C++0x type traits
+  // functions (C++Builder 2009 and above only).
+  static const bool value = __is_convertible(From, To);
+#else
+  static const bool value =
+      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
+#endif  // _MSV_VER
+};
+template <typename From, typename To>
+const bool ImplicitlyConvertible<From, To>::value;
+
+// IsAProtocolMessage<T>::value is a compile-time bool constant that's
+// true iff T is type ProtocolMessage, proto2::Message, or a subclass
+// of those.
+template <typename T>
+struct IsAProtocolMessage
+    : public bool_constant<
+  ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
+  ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
+};
+
+// When the compiler sees expression IsContainerTest<C>(0), if C is an
+// STL-style container class, the first overload of IsContainerTest
+// will be viable (since both C::iterator* and C::const_iterator* are
+// valid types and NULL can be implicitly converted to them).  It will
+// be picked over the second overload as 'int' is a perfect match for
+// the type of argument 0.  If C::iterator or C::const_iterator is not
+// a valid type, the first overload is not viable, and the second
+// overload will be picked.  Therefore, we can determine whether C is
+// a container class by checking the type of IsContainerTest<C>(0).
+// The value of the expression is insignificant.
+//
+// Note that we look for both C::iterator and C::const_iterator.  The
+// reason is that C++ injects the name of a class as a member of the
+// class itself (e.g. you can refer to class iterator as either
+// 'iterator' or 'iterator::iterator').  If we look for C::iterator
+// only, for example, we would mistakenly think that a class named
+// iterator is an STL container.
+//
+// Also note that the simpler approach of overloading
+// IsContainerTest(typename C::const_iterator*) and
+// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
+typedef int IsContainer;
+template <class C>
+IsContainer IsContainerTest(int /* dummy */,
+                            typename C::iterator* /* it */ = NULL,
+                            typename C::const_iterator* /* const_it */ = NULL) {
+  return 0;
+}
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
+
+// EnableIf<condition>::type is void when 'Cond' is true, and
+// undefined when 'Cond' is false.  To use SFINAE to make a function
+// overload only apply when a particular expression is true, add
+// "typename EnableIf<expression>::type* = 0" as the last parameter.
+template<bool> struct EnableIf;
+template<> struct EnableIf<true> { typedef void type; };  // NOLINT
+
+// Utilities for native arrays.
+
+// ArrayEq() compares two k-dimensional native arrays using the
+// elements' operator==, where k can be any integer >= 0.  When k is
+// 0, ArrayEq() degenerates into comparing a single pair of values.
+
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
+  return internal::ArrayEq(lhs, N, rhs);
+}
+
+// This helper reduces code bloat.  If we instead put its logic inside
+// the previous ArrayEq() function, arrays with different sizes would
+// lead to different copies of the template code.
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
+  for (size_t i = 0; i != size; i++) {
+    if (!internal::ArrayEq(lhs[i], rhs[i]))
+      return false;
+  }
+  return true;
+}
+
+// Finds the first element in the iterator range [begin, end) that
+// equals elem.  Element may be a native array type itself.
+template <typename Iter, typename Element>
+Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
+  for (Iter it = begin; it != end; ++it) {
+    if (internal::ArrayEq(*it, elem))
+      return it;
+  }
+  return end;
+}
+
+// CopyArray() copies a k-dimensional native array using the elements'
+// operator=, where k can be any integer >= 0.  When k is 0,
+// CopyArray() degenerates into copying a single value.
+
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) { *to = from; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline void CopyArray(const T(&from)[N], U(*to)[N]) {
+  internal::CopyArray(from, N, *to);
+}
+
+// This helper reduces code bloat.  If we instead put its logic inside
+// the previous CopyArray() function, arrays with different sizes
+// would lead to different copies of the template code.
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to) {
+  for (size_t i = 0; i != size; i++) {
+    internal::CopyArray(from[i], to + i);
+  }
+}
+
+// The relation between an NativeArray object (see below) and the
+// native array it represents.
+enum RelationToSource {
+  kReference,  // The NativeArray references the native array.
+  kCopy        // The NativeArray makes a copy of the native array and
+               // owns the copy.
+};
+
+// Adapts a native array to a read-only STL-style container.  Instead
+// of the complete STL container concept, this adaptor only implements
+// members useful for Google Mock's container matchers.  New members
+// should be added as needed.  To simplify the implementation, we only
+// support Element being a raw type (i.e. having no top-level const or
+// reference modifier).  It's the client's responsibility to satisfy
+// this requirement.  Element can be an array type itself (hence
+// multi-dimensional arrays are supported).
+template <typename Element>
+class NativeArray {
+ public:
+  // STL-style container typedefs.
+  typedef Element value_type;
+  typedef Element* iterator;
+  typedef const Element* const_iterator;
+
+  // Constructs from a native array.
+  NativeArray(const Element* array, size_t count, RelationToSource relation) {
+    Init(array, count, relation);
+  }
+
+  // Copy constructor.
+  NativeArray(const NativeArray& rhs) {
+    Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+  }
+
+  ~NativeArray() {
+    // Ensures that the user doesn't instantiate NativeArray with a
+    // const or reference type.
+    static_cast<void>(StaticAssertTypeEqHelper<Element,
+        GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
+    if (relation_to_source_ == kCopy)
+      delete[] array_;
+  }
+
+  // STL-style container methods.
+  size_t size() const { return size_; }
+  const_iterator begin() const { return array_; }
+  const_iterator end() const { return array_ + size_; }
+  bool operator==(const NativeArray& rhs) const {
+    return size() == rhs.size() &&
+        ArrayEq(begin(), size(), rhs.begin());
+  }
+
+ private:
+  // Initializes this object; makes a copy of the input array if
+  // 'relation' is kCopy.
+  void Init(const Element* array, size_t a_size, RelationToSource relation) {
+    if (relation == kReference) {
+      array_ = array;
+    } else {
+      Element* const copy = new Element[a_size];
+      CopyArray(array, a_size, copy);
+      array_ = copy;
+    }
+    size_ = a_size;
+    relation_to_source_ = relation;
+  }
+
+  const Element* array_;
+  size_t size_;
+  RelationToSource relation_to_source_;
+
+  GTEST_DISALLOW_ASSIGN_(NativeArray);
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
+  ::testing::internal::AssertHelper(result_type, file, line, message) \
+    = ::testing::Message()
+
+#define GTEST_MESSAGE_(message, result_type) \
+  GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)
+
+#define GTEST_FATAL_FAILURE_(message) \
+  return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+  GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
+
+#define GTEST_SUCCESS_(message) \
+  GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
+
+// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+  if (::testing::internal::AlwaysTrue()) { statement; }
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::ConstCharPtr gtest_msg = "") { \
+    bool gtest_caught_expected = false; \
+    try { \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    } \
+    catch (expected_exception const&) { \
+      gtest_caught_expected = true; \
+    } \
+    catch (...) { \
+      gtest_msg.value = \
+          "Expected: " #statement " throws an exception of type " \
+          #expected_exception ".\n  Actual: it throws a different type."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+    } \
+    if (!gtest_caught_expected) { \
+      gtest_msg.value = \
+          "Expected: " #statement " throws an exception of type " \
+          #expected_exception ".\n  Actual: it throws nothing."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+      fail(gtest_msg.value)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    try { \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    } \
+    catch (...) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+      fail("Expected: " #statement " doesn't throw an exception.\n" \
+           "  Actual: it throws.")
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    bool gtest_caught_any = false; \
+    try { \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    } \
+    catch (...) { \
+      gtest_caught_any = true; \
+    } \
+    if (!gtest_caught_any) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+      fail("Expected: " #statement " throws an exception.\n" \
+           "  Actual: it doesn't.")
+
+
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
+// either a boolean expression or an AssertionResult. text is a textual
+// represenation of expression as it was passed into the EXPECT_TRUE.
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const ::testing::AssertionResult gtest_ar_ = \
+      ::testing::AssertionResult(expression)) \
+    ; \
+  else \
+    fail(::testing::internal::GetBoolAssertionFailureMessage(\
+        gtest_ar_, text, #actual, #expected).c_str())
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (::testing::internal::AlwaysTrue()) { \
+    ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+    if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+      fail("Expected: " #statement " doesn't generate new fatal " \
+           "failures in the current thread.\n" \
+           "  Actual: it does.")
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+  test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+  virtual void TestBody();\
+  static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+  ::test_info_ =\
+    ::testing::internal::MakeAndRegisterTestInfo(\
+        #test_case_name, #test_name, NULL, NULL, \
+        (parent_id), \
+        parent_class::SetUpTestCase, \
+        parent_class::TearDownTestCase, \
+        new ::testing::internal::TestFactoryImpl<\
+            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h
new file mode 100644
index 0000000..b1362cd
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h
@@ -0,0 +1,233 @@
+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: Dan Egnor (egnor at google.com)
+//
+// A "smart" pointer type with reference tracking.  Every pointer to a
+// particular object is kept on a circular linked list.  When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+//   object is traversed.  This class is therefore NOT SUITABLE when there
+//   will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+//   will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+//   Unlike other linked_ptr implementations, in this implementation
+//   a linked_ptr object is thread-safe in the sense that:
+//     - it's safe to copy linked_ptr objects concurrently,
+//     - it's safe to copy *from* a linked_ptr and read its underlying
+//       raw pointer (e.g. via get()) concurrently, and
+//     - it's safe to write to two linked_ptrs that point to the same
+//       shared object concurrently.
+// TODO(wan at google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+namespace internal {
+
+// Protects copying of all linked_ptr objects.
+GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// This is used internally by all instances of linked_ptr<>.  It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+  // Create a new circle that includes only this instance.
+  void join_new() {
+    next_ = this;
+  }
+
+  // Many linked_ptr operations may change p.link_ for some linked_ptr
+  // variable p in the same circle as this object.  Therefore we need
+  // to prevent two such operations from occurring concurrently.
+  //
+  // Note that different types of linked_ptr objects can coexist in a
+  // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+  // linked_ptr<Derived2>).  Therefore we must use a single mutex to
+  // protect all linked_ptr objects.  This can create serious
+  // contention in production code, but is acceptable in a testing
+  // framework.
+
+  // Join an existing circle.
+  void join(linked_ptr_internal const* ptr)
+      GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
+    MutexLock lock(&g_linked_ptr_mutex);
+
+    linked_ptr_internal const* p = ptr;
+    while (p->next_ != ptr) p = p->next_;
+    p->next_ = this;
+    next_ = ptr;
+  }
+
+  // Leave whatever circle we're part of.  Returns true if we were the
+  // last member of the circle.  Once this is done, you can join() another.
+  bool depart()
+      GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
+    MutexLock lock(&g_linked_ptr_mutex);
+
+    if (next_ == this) return true;
+    linked_ptr_internal const* p = next_;
+    while (p->next_ != this) p = p->next_;
+    p->next_ = next_;
+    return false;
+  }
+
+ private:
+  mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+  typedef T element_type;
+
+  // Take over ownership of a raw pointer.  This should happen as soon as
+  // possible after the object is created.
+  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+  ~linked_ptr() { depart(); }
+
+  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+  linked_ptr(linked_ptr const& ptr) {  // NOLINT
+    assert(&ptr != this);
+    copy(&ptr);
+  }
+
+  // Assignment releases the old value and acquires the new.
+  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+    depart();
+    copy(&ptr);
+    return *this;
+  }
+
+  linked_ptr& operator=(linked_ptr const& ptr) {
+    if (&ptr != this) {
+      depart();
+      copy(&ptr);
+    }
+    return *this;
+  }
+
+  // Smart pointer members.
+  void reset(T* ptr = NULL) {
+    depart();
+    capture(ptr);
+  }
+  T* get() const { return value_; }
+  T* operator->() const { return value_; }
+  T& operator*() const { return *value_; }
+
+  bool operator==(T* p) const { return value_ == p; }
+  bool operator!=(T* p) const { return value_ != p; }
+  template <typename U>
+  bool operator==(linked_ptr<U> const& ptr) const {
+    return value_ == ptr.get();
+  }
+  template <typename U>
+  bool operator!=(linked_ptr<U> const& ptr) const {
+    return value_ != ptr.get();
+  }
+
+ private:
+  template <typename U>
+  friend class linked_ptr;
+
+  T* value_;
+  linked_ptr_internal link_;
+
+  void depart() {
+    if (link_.depart()) delete value_;
+  }
+
+  void capture(T* ptr) {
+    value_ = ptr;
+    link_.join_new();
+  }
+
+  template <typename U> void copy(linked_ptr<U> const* ptr) {
+    value_ = ptr->get();
+    if (value_)
+      link_.join(&ptr->link_);
+    else
+      link_.join_new();
+  }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+  return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+  return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+  return linked_ptr<T>(ptr);
+}
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h
new file mode 100644
index 0000000..e805485
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h
@@ -0,0 +1,5143 @@
+// This file was GENERATED by command:
+//     pump.py gtest-param-util-generated.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: vladl at google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework at googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+  explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray1& other);
+
+  const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2 {
+ public:
+  ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray2& other);
+
+  const T1 v1_;
+  const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3 {
+ public:
+  ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray3& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4 {
+ public:
+  ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray4& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5 {
+ public:
+  ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray5& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+class ValueArray6 {
+ public:
+  ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray6& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+class ValueArray7 {
+ public:
+  ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray7& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+class ValueArray8 {
+ public:
+  ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+      T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray8& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+class ValueArray9 {
+ public:
+  ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+      T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray9& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10 {
+ public:
+  ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray10& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+class ValueArray11 {
+ public:
+  ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray11& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+class ValueArray12 {
+ public:
+  ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray12& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+class ValueArray13 {
+ public:
+  ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray13& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+class ValueArray14 {
+ public:
+  ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray14& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15 {
+ public:
+  ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray15& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+class ValueArray16 {
+ public:
+  ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray16& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+class ValueArray17 {
+ public:
+  ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+      T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray17& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+class ValueArray18 {
+ public:
+  ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray18& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+class ValueArray19 {
+ public:
+  ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray19& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20 {
+ public:
+  ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray20& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+class ValueArray21 {
+ public:
+  ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray21& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+class ValueArray22 {
+ public:
+  ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray22& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+class ValueArray23 {
+ public:
+  ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray23& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+class ValueArray24 {
+ public:
+  ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray24& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25 {
+ public:
+  ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+      T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray25& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+class ValueArray26 {
+ public:
+  ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray26& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+class ValueArray27 {
+ public:
+  ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray27& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+class ValueArray28 {
+ public:
+  ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray28& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+class ValueArray29 {
+ public:
+  ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray29& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30 {
+ public:
+  ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray30& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+class ValueArray31 {
+ public:
+  ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray31& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+class ValueArray32 {
+ public:
+  ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray32& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+class ValueArray33 {
+ public:
+  ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+      T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray33& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+class ValueArray34 {
+ public:
+  ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray34& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35 {
+ public:
+  ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+      v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray35& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+class ValueArray36 {
+ public:
+  ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray36& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+class ValueArray37 {
+ public:
+  ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+      v36_(v36), v37_(v37) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray37& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+class ValueArray38 {
+ public:
+  ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray38& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+class ValueArray39 {
+ public:
+  ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray39& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40 {
+ public:
+  ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+      v40_(v40) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray40& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+class ValueArray41 {
+ public:
+  ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+      T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray41& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+class ValueArray42 {
+ public:
+  ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray42& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+class ValueArray43 {
+ public:
+  ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+      v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+      v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray43& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+class ValueArray44 {
+ public:
+  ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+      v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+      v43_(v43), v44_(v44) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray44& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45 {
+ public:
+  ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+      v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+      v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray45& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+class ValueArray46 {
+ public:
+  ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray46& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+class ValueArray47 {
+ public:
+  ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+      v47_(v47) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray47& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+class ValueArray48 {
+ public:
+  ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+      v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+      v46_(v46), v47_(v47), v48_(v48) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+        static_cast<T>(v48_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray48& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+class ValueArray49 {
+ public:
+  ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+      T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+        static_cast<T>(v48_), static_cast<T>(v49_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray49& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+  const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50 {
+ public:
+  ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+      T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_), static_cast<T>(v2_),
+        static_cast<T>(v3_), static_cast<T>(v4_), static_cast<T>(v5_),
+        static_cast<T>(v6_), static_cast<T>(v7_), static_cast<T>(v8_),
+        static_cast<T>(v9_), static_cast<T>(v10_), static_cast<T>(v11_),
+        static_cast<T>(v12_), static_cast<T>(v13_), static_cast<T>(v14_),
+        static_cast<T>(v15_), static_cast<T>(v16_), static_cast<T>(v17_),
+        static_cast<T>(v18_), static_cast<T>(v19_), static_cast<T>(v20_),
+        static_cast<T>(v21_), static_cast<T>(v22_), static_cast<T>(v23_),
+        static_cast<T>(v24_), static_cast<T>(v25_), static_cast<T>(v26_),
+        static_cast<T>(v27_), static_cast<T>(v28_), static_cast<T>(v29_),
+        static_cast<T>(v30_), static_cast<T>(v31_), static_cast<T>(v32_),
+        static_cast<T>(v33_), static_cast<T>(v34_), static_cast<T>(v35_),
+        static_cast<T>(v36_), static_cast<T>(v37_), static_cast<T>(v38_),
+        static_cast<T>(v39_), static_cast<T>(v40_), static_cast<T>(v41_),
+        static_cast<T>(v42_), static_cast<T>(v43_), static_cast<T>(v44_),
+        static_cast<T>(v45_), static_cast<T>(v46_), static_cast<T>(v47_),
+        static_cast<T>(v48_), static_cast<T>(v49_), static_cast<T>(v50_)};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray50& other);
+
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+  const T49 v49_;
+  const T50 v50_;
+};
+
+# if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+  CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2)
+      : g1_(g1), g2_(g2) {}
+  virtual ~CartesianProductGenerator2() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current2_;
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator2::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator2& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+};  // class CartesianProductGenerator2
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+  CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+      : g1_(g1), g2_(g2), g3_(g3) {}
+  virtual ~CartesianProductGenerator3() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current3_;
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator3::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator3& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+};  // class CartesianProductGenerator3
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+  CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+  virtual ~CartesianProductGenerator4() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current4_;
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator4::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator4& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+};  // class CartesianProductGenerator4
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+  CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+  virtual ~CartesianProductGenerator5() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current5_;
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator5::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator5& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+};  // class CartesianProductGenerator5
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+class CartesianProductGenerator6
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+        T6> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+  CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+  virtual ~CartesianProductGenerator6() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current6_;
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator6::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator6& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+};  // class CartesianProductGenerator6
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+class CartesianProductGenerator7
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+  CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+  virtual ~CartesianProductGenerator7() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current7_;
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator7::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator7& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+};  // class CartesianProductGenerator7
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+  CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+          g8_(g8) {}
+  virtual ~CartesianProductGenerator8() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current8_;
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator8::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator8& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+};  // class CartesianProductGenerator8
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8, T9> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+  CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9) {}
+  virtual ~CartesianProductGenerator9() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end(), g9_, g9_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8,
+      const ParamGenerator<T9>& g9,
+      const typename ParamGenerator<T9>::iterator& current9)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+          begin9_(g9.begin()), end9_(g9.end()), current9_(current9)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current9_;
+      if (current9_ == end9_) {
+        current9_ = begin9_;
+        ++current8_;
+      }
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_ &&
+          current9_ == typed_other->current9_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_),
+        begin9_(other.begin9_),
+        end9_(other.end9_),
+        current9_(other.current9_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_,
+            *current9_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_ ||
+          current9_ == end9_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    const typename ParamGenerator<T9>::iterator begin9_;
+    const typename ParamGenerator<T9>::iterator end9_;
+    typename ParamGenerator<T9>::iterator current9_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator9::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator9& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+  const ParamGenerator<T9> g9_;
+};  // class CartesianProductGenerator9
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8, T9, T10> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+  CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+      const ParamGenerator<T10>& g10)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9), g10_(g10) {}
+  virtual ~CartesianProductGenerator10() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8,
+      const ParamGenerator<T9>& g9,
+      const typename ParamGenerator<T9>::iterator& current9,
+      const ParamGenerator<T10>& g10,
+      const typename ParamGenerator<T10>::iterator& current10)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+          begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+          begin10_(g10.begin()), end10_(g10.end()), current10_(current10)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current10_;
+      if (current10_ == end10_) {
+        current10_ = begin10_;
+        ++current9_;
+      }
+      if (current9_ == end9_) {
+        current9_ = begin9_;
+        ++current8_;
+      }
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_ &&
+          current9_ == typed_other->current9_ &&
+          current10_ == typed_other->current10_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_),
+        begin9_(other.begin9_),
+        end9_(other.end9_),
+        current9_(other.current9_),
+        begin10_(other.begin10_),
+        end10_(other.end10_),
+        current10_(other.current10_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_,
+            *current9_, *current10_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_ ||
+          current9_ == end9_ ||
+          current10_ == end10_;
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    const typename ParamGenerator<T9>::iterator begin9_;
+    const typename ParamGenerator<T9>::iterator end9_;
+    typename ParamGenerator<T9>::iterator current9_;
+    const typename ParamGenerator<T10>::iterator begin10_;
+    const typename ParamGenerator<T10>::iterator end10_;
+    typename ParamGenerator<T10>::iterator current10_;
+    ParamType current_value_;
+  };  // class CartesianProductGenerator10::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator10& other);
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+  const ParamGenerator<T9> g9_;
+  const ParamGenerator<T10> g10_;
+};  // class CartesianProductGenerator10
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2 {
+ public:
+CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+      : g1_(g1), g2_(g2) {}
+  template <typename T1, typename T2>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+        new CartesianProductGenerator2<T1, T2>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder2& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+};  // class CartesianProductHolder2
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3 {
+ public:
+CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3)
+      : g1_(g1), g2_(g2), g3_(g3) {}
+  template <typename T1, typename T2, typename T3>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+        new CartesianProductGenerator3<T1, T2, T3>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder3& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+};  // class CartesianProductHolder3
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4>
+class CartesianProductHolder4 {
+ public:
+CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+  template <typename T1, typename T2, typename T3, typename T4>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+        new CartesianProductGenerator4<T1, T2, T3, T4>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder4& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+};  // class CartesianProductHolder4
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5>
+class CartesianProductHolder5 {
+ public:
+CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+        new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder5& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+};  // class CartesianProductHolder5
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6 {
+ public:
+CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+        new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder6& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+};  // class CartesianProductHolder6
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7 {
+ public:
+CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+      T7> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+        new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder7& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+};  // class CartesianProductHolder7
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8>
+class CartesianProductHolder8 {
+ public:
+CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+          g8_(g8) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+      T8> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+        new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder8& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+};  // class CartesianProductHolder8
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8, class Generator9>
+class CartesianProductHolder9 {
+ public:
+CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8,
+    const Generator9& g9)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8, typename T9>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+      T9> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+        T9> >(
+        new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_),
+        static_cast<ParamGenerator<T9> >(g9_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder9& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+  const Generator9 g9_;
+};  // class CartesianProductHolder9
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10 {
+ public:
+CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8,
+    const Generator9& g9, const Generator10& g10)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9), g10_(g10) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8, typename T9, typename T10>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+      T9, T10> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+        T9, T10> >(
+        new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+            T10>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_),
+        static_cast<ParamGenerator<T9> >(g9_),
+        static_cast<ParamGenerator<T10> >(g10_)));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder10& other);
+
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+  const Generator9 g9_;
+  const Generator10 g10_;
+};  // class CartesianProductHolder10
+
+# endif  // GTEST_HAS_COMBINE
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h.pump b/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h.pump
new file mode 100644
index 0000000..009206f
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h.pump
@@ -0,0 +1,301 @@
+$$ -*- mode: c++; -*-
+$var n = 50  $$ Maximum length of Values arguments we want to support.
+$var maxtuple = 10  $$ Maximum number of Combine arguments we want to support.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: vladl at google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most $n arguments in Values,
+// and at most $maxtuple arguments in Combine. Please contact
+// googletestframework at googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at $maxtuple.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-param-util.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+  explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray1& other);
+
+  const T1 v1_;
+};
+
+$range i 2..n
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename T$j]]>
+class ValueArray$i {
+ public:
+  ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {$for j, [[static_cast<T>(v$(j)_)]]};
+    return ValuesIn(array);
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const ValueArray$i& other);
+
+$for j [[
+
+  const T$j v$(j)_;
+]]
+
+};
+
+]]
+
+# if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+$range k 2..i
+
+template <$for j, [[typename T$j]]>
+class CartesianProductGenerator$i
+    : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > {
+ public:
+  typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType;
+
+  CartesianProductGenerator$i($for j, [[const ParamGenerator<T$j>& g$j]])
+      : $for j, [[g$(j)_(g$j)]] {}
+  virtual ~CartesianProductGenerator$i() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]);
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]);
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base, $for j, [[
+
+      const ParamGenerator<T$j>& g$j,
+      const typename ParamGenerator<T$j>::iterator& current$(j)]])
+        : base_(base),
+$for j, [[
+
+          begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j)
+]]    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current$(i)_;
+
+$for k [[
+      if (current$(i+2-k)_ == end$(i+2-k)_) {
+        current$(i+2-k)_ = begin$(i+2-k)_;
+        ++current$(i+2-k-1)_;
+      }
+
+]]
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         ($for j  && [[
+
+          current$(j)_ == typed_other->current$(j)_
+]]);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_), $for j, [[
+
+        begin$(j)_(other.begin$(j)_),
+        end$(j)_(other.end$(j)_),
+        current$(j)_(other.current$(j)_)
+]] {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType($for j, [[*current$(j)_]]);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+$for j  || [[
+
+          current$(j)_ == end$(j)_
+]];
+    }
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+$for j [[
+
+    const typename ParamGenerator<T$j>::iterator begin$(j)_;
+    const typename ParamGenerator<T$j>::iterator end$(j)_;
+    typename ParamGenerator<T$j>::iterator current$(j)_;
+]]
+
+    ParamType current_value_;
+  };  // class CartesianProductGenerator$i::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductGenerator$i& other);
+
+
+$for j [[
+  const ParamGenerator<T$j> g$(j)_;
+
+]]
+};  // class CartesianProductGenerator$i
+
+
+]]
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+
+template <$for j, [[class Generator$j]]>
+class CartesianProductHolder$i {
+ public:
+CartesianProductHolder$i($for j, [[const Generator$j& g$j]])
+      : $for j, [[g$(j)_(g$j)]] {}
+  template <$for j, [[typename T$j]]>
+  operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const {
+    return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >(
+        new CartesianProductGenerator$i<$for j, [[T$j]]>(
+$for j,[[
+
+        static_cast<ParamGenerator<T$j> >(g$(j)_)
+]]));
+  }
+
+ private:
+  // No implementation - assignment is unsupported.
+  void operator=(const CartesianProductHolder$i& other);
+
+
+$for j [[
+  const Generator$j g$(j)_;
+
+]]
+};  // class CartesianProductHolder$i
+
+]]
+
+# endif  // GTEST_HAS_COMBINE
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util.h
new file mode 100644
index 0000000..d5e1028
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-param-util.h
@@ -0,0 +1,619 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: vladl at google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*.  Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-linked_ptr.h"
+#include "gtest/internal/gtest-port.h"
+#include "gtest/gtest-printers.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
+                                          const char* file, int line);
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+  virtual ~ParamIteratorInterface() {}
+  // A pointer to the base generator instance.
+  // Used only for the purposes of iterator comparison
+  // to make sure that two iterators belong to the same generator.
+  virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+  // Advances iterator to point to the next element
+  // provided by the generator. The caller is responsible
+  // for not calling Advance() on an iterator equal to
+  // BaseGenerator()->End().
+  virtual void Advance() = 0;
+  // Clones the iterator object. Used for implementing copy semantics
+  // of ParamIterator<T>.
+  virtual ParamIteratorInterface* Clone() const = 0;
+  // Dereferences the current iterator and provides (read-only) access
+  // to the pointed value. It is the caller's responsibility not to call
+  // Current() on an iterator equal to BaseGenerator()->End().
+  // Used for implementing ParamGenerator<T>::operator*().
+  virtual const T* Current() const = 0;
+  // Determines whether the given iterator and other point to the same
+  // element in the sequence generated by the generator.
+  // Used for implementing ParamGenerator<T>::operator==().
+  virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+  typedef T value_type;
+  typedef const T& reference;
+  typedef ptrdiff_t difference_type;
+
+  // ParamIterator assumes ownership of the impl_ pointer.
+  ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+  ParamIterator& operator=(const ParamIterator& other) {
+    if (this != &other)
+      impl_.reset(other.impl_->Clone());
+    return *this;
+  }
+
+  const T& operator*() const { return *impl_->Current(); }
+  const T* operator->() const { return impl_->Current(); }
+  // Prefix version of operator++.
+  ParamIterator& operator++() {
+    impl_->Advance();
+    return *this;
+  }
+  // Postfix version of operator++.
+  ParamIterator operator++(int /*unused*/) {
+    ParamIteratorInterface<T>* clone = impl_->Clone();
+    impl_->Advance();
+    return ParamIterator(clone);
+  }
+  bool operator==(const ParamIterator& other) const {
+    return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+  }
+  bool operator!=(const ParamIterator& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  friend class ParamGenerator<T>;
+  explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+  scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+  typedef T ParamType;
+
+  virtual ~ParamGeneratorInterface() {}
+
+  // Generator interface definition
+  virtual ParamIteratorInterface<T>* Begin() const = 0;
+  virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+  typedef ParamIterator<T> iterator;
+
+  explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+  ParamGenerator& operator=(const ParamGenerator& other) {
+    impl_ = other.impl_;
+    return *this;
+  }
+
+  iterator begin() const { return iterator(impl_->Begin()); }
+  iterator end() const { return iterator(impl_->End()); }
+
+ private:
+  linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+  RangeGenerator(T begin, T end, IncrementT step)
+      : begin_(begin), end_(end),
+        step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+  virtual ~RangeGenerator() {}
+
+  virtual ParamIteratorInterface<T>* Begin() const {
+    return new Iterator(this, begin_, 0, step_);
+  }
+  virtual ParamIteratorInterface<T>* End() const {
+    return new Iterator(this, end_, end_index_, step_);
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<T> {
+   public:
+    Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+             IncrementT step)
+        : base_(base), value_(value), index_(index), step_(step) {}
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+      return base_;
+    }
+    virtual void Advance() {
+      value_ = value_ + step_;
+      index_++;
+    }
+    virtual ParamIteratorInterface<T>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const T* Current() const { return &value_; }
+    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const int other_index =
+          CheckedDowncastToActualType<const Iterator>(&other)->index_;
+      return index_ == other_index;
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : ParamIteratorInterface<T>(),
+          base_(other.base_), value_(other.value_), index_(other.index_),
+          step_(other.step_) {}
+
+    // No implementation - assignment is unsupported.
+    void operator=(const Iterator& other);
+
+    const ParamGeneratorInterface<T>* const base_;
+    T value_;
+    int index_;
+    const IncrementT step_;
+  };  // class RangeGenerator::Iterator
+
+  static int CalculateEndIndex(const T& begin,
+                               const T& end,
+                               const IncrementT& step) {
+    int end_index = 0;
+    for (T i = begin; i < end; i = i + step)
+      end_index++;
+    return end_index;
+  }
+
+  // No implementation - assignment is unsupported.
+  void operator=(const RangeGenerator& other);
+
+  const T begin_;
+  const T end_;
+  const IncrementT step_;
+  // The index for the end() iterator. All the elements in the generated
+  // sequence are indexed (0-based) to aid iterator comparison.
+  const int end_index_;
+};  // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+  template <typename ForwardIterator>
+  ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+      : container_(begin, end) {}
+  virtual ~ValuesInIteratorRangeGenerator() {}
+
+  virtual ParamIteratorInterface<T>* Begin() const {
+    return new Iterator(this, container_.begin());
+  }
+  virtual ParamIteratorInterface<T>* End() const {
+    return new Iterator(this, container_.end());
+  }
+
+ private:
+  typedef typename ::std::vector<T> ContainerType;
+
+  class Iterator : public ParamIteratorInterface<T> {
+   public:
+    Iterator(const ParamGeneratorInterface<T>* base,
+             typename ContainerType::const_iterator iterator)
+        : base_(base), iterator_(iterator) {}
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+      return base_;
+    }
+    virtual void Advance() {
+      ++iterator_;
+      value_.reset();
+    }
+    virtual ParamIteratorInterface<T>* Clone() const {
+      return new Iterator(*this);
+    }
+    // We need to use cached value referenced by iterator_ because *iterator_
+    // can return a temporary object (and of type other then T), so just
+    // having "return &*iterator_;" doesn't work.
+    // value_ is updated here and not in Advance() because Advance()
+    // can advance iterator_ beyond the end of the range, and we cannot
+    // detect that fact. The client code, on the other hand, is
+    // responsible for not calling Current() on an out-of-range iterator.
+    virtual const T* Current() const {
+      if (value_.get() == NULL)
+        value_.reset(new T(*iterator_));
+      return value_.get();
+    }
+    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      return iterator_ ==
+          CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+    }
+
+   private:
+    Iterator(const Iterator& other)
+          // The explicit constructor call suppresses a false warning
+          // emitted by gcc when supplied with the -Wextra option.
+        : ParamIteratorInterface<T>(),
+          base_(other.base_),
+          iterator_(other.iterator_) {}
+
+    const ParamGeneratorInterface<T>* const base_;
+    typename ContainerType::const_iterator iterator_;
+    // A cached value of *iterator_. We keep it here to allow access by
+    // pointer in the wrapping iterator's operator->().
+    // value_ needs to be mutable to be accessed in Current().
+    // Use of scoped_ptr helps manage cached value's lifetime,
+    // which is bound by the lifespan of the iterator itself.
+    mutable scoped_ptr<const T> value_;
+  };  // class ValuesInIteratorRangeGenerator::Iterator
+
+  // No implementation - assignment is unsupported.
+  void operator=(const ValuesInIteratorRangeGenerator& other);
+
+  const ContainerType container_;
+};  // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+  typedef typename TestClass::ParamType ParamType;
+  explicit ParameterizedTestFactory(ParamType parameter) :
+      parameter_(parameter) {}
+  virtual Test* CreateTest() {
+    TestClass::SetParam(&parameter_);
+    return new TestClass();
+  }
+
+ private:
+  const ParamType parameter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+  virtual ~TestMetaFactoryBase() {}
+
+  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+    : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ public:
+  typedef typename TestCase::ParamType ParamType;
+
+  TestMetaFactory() {}
+
+  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+    return new ParameterizedTestFactory<TestCase>(parameter);
+  }
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase {
+ public:
+  virtual ~ParameterizedTestCaseInfoBase() {}
+
+  // Base part of test case name for display purposes.
+  virtual const string& GetTestCaseName() const = 0;
+  // Test case id to verify identity.
+  virtual TypeId GetTestCaseTypeId() const = 0;
+  // UnitTest class invokes this method to register tests in this
+  // test case right before running them in RUN_ALL_TESTS macro.
+  // This method should not be called more then once on any single
+  // instance of a ParameterizedTestCaseInfoBase derived class.
+  virtual void RegisterTests() = 0;
+
+ protected:
+  ParameterizedTestCaseInfoBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+ public:
+  // ParamType and GeneratorCreationFunc are private types but are required
+  // for declarations of public methods AddTestPattern() and
+  // AddTestCaseInstantiation().
+  typedef typename TestCase::ParamType ParamType;
+  // A function that returns an instance of appropriate generator type.
+  typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+  explicit ParameterizedTestCaseInfo(const char* name)
+      : test_case_name_(name) {}
+
+  // Test case base name for display purposes.
+  virtual const string& GetTestCaseName() const { return test_case_name_; }
+  // Test case id to verify identity.
+  virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+  // TEST_P macro uses AddTestPattern() to record information
+  // about a single test in a LocalTestInfo structure.
+  // test_case_name is the base name of the test case (without invocation
+  // prefix). test_base_name is the name of an individual test without
+  // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+  // test case base name and DoBar is test base name.
+  void AddTestPattern(const char* test_case_name,
+                      const char* test_base_name,
+                      TestMetaFactoryBase<ParamType>* meta_factory) {
+    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+                                                       test_base_name,
+                                                       meta_factory)));
+  }
+  // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+  // about a generator.
+  int AddTestCaseInstantiation(const string& instantiation_name,
+                               GeneratorCreationFunc* func,
+                               const char* /* file */,
+                               int /* line */) {
+    instantiations_.push_back(::std::make_pair(instantiation_name, func));
+    return 0;  // Return value used only to run this method in namespace scope.
+  }
+  // UnitTest class invokes this method to register tests in this test case
+  // test cases right before running tests in RUN_ALL_TESTS macro.
+  // This method should not be called more then once on any single
+  // instance of a ParameterizedTestCaseInfoBase derived class.
+  // UnitTest has a guard to prevent from calling this method more then once.
+  virtual void RegisterTests() {
+    for (typename TestInfoContainer::iterator test_it = tests_.begin();
+         test_it != tests_.end(); ++test_it) {
+      linked_ptr<TestInfo> test_info = *test_it;
+      for (typename InstantiationContainer::iterator gen_it =
+               instantiations_.begin(); gen_it != instantiations_.end();
+               ++gen_it) {
+        const string& instantiation_name = gen_it->first;
+        ParamGenerator<ParamType> generator((*gen_it->second)());
+
+        string test_case_name;
+        if ( !instantiation_name.empty() )
+          test_case_name = instantiation_name + "/";
+        test_case_name += test_info->test_case_base_name;
+
+        int i = 0;
+        for (typename ParamGenerator<ParamType>::iterator param_it =
+                 generator.begin();
+             param_it != generator.end(); ++param_it, ++i) {
+          Message test_name_stream;
+          test_name_stream << test_info->test_base_name << "/" << i;
+          MakeAndRegisterTestInfo(
+              test_case_name.c_str(),
+              test_name_stream.GetString().c_str(),
+              NULL,  // No type parameter.
+              PrintToString(*param_it).c_str(),
+              GetTestCaseTypeId(),
+              TestCase::SetUpTestCase,
+              TestCase::TearDownTestCase,
+              test_info->test_meta_factory->CreateTestFactory(*param_it));
+        }  // for param_it
+      }  // for gen_it
+    }  // for test_it
+  }  // RegisterTests
+
+ private:
+  // LocalTestInfo structure keeps information about a single test registered
+  // with TEST_P macro.
+  struct TestInfo {
+    TestInfo(const char* a_test_case_base_name,
+             const char* a_test_base_name,
+             TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
+        test_case_base_name(a_test_case_base_name),
+        test_base_name(a_test_base_name),
+        test_meta_factory(a_test_meta_factory) {}
+
+    const string test_case_base_name;
+    const string test_base_name;
+    const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+  };
+  typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+  // Keeps pairs of <Instantiation name, Sequence generator creation function>
+  // received from INSTANTIATE_TEST_CASE_P macros.
+  typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
+      InstantiationContainer;
+
+  const string test_case_name_;
+  TestInfoContainer tests_;
+  InstantiationContainer instantiations_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+};  // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry {
+ public:
+  ParameterizedTestCaseRegistry() {}
+  ~ParameterizedTestCaseRegistry() {
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      delete *it;
+    }
+  }
+
+  // Looks up or creates and returns a structure containing information about
+  // tests and instantiations of a particular test case.
+  template <class TestCase>
+  ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+      const char* test_case_name,
+      const char* file,
+      int line) {
+    ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      if ((*it)->GetTestCaseName() == test_case_name) {
+        if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+          // Complain about incorrect usage of Google Test facilities
+          // and terminate the program since we cannot guaranty correct
+          // test case setup and tear-down in this case.
+          ReportInvalidTestCaseType(test_case_name,  file, line);
+          posix::Abort();
+        } else {
+          // At this point we are sure that the object we found is of the same
+          // type we are looking for, so we downcast it to that type
+          // without further checks.
+          typed_test_info = CheckedDowncastToActualType<
+              ParameterizedTestCaseInfo<TestCase> >(*it);
+        }
+        break;
+      }
+    }
+    if (typed_test_info == NULL) {
+      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+      test_case_infos_.push_back(typed_test_info);
+    }
+    return typed_test_info;
+  }
+  void RegisterTests() {
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      (*it)->RegisterTests();
+    }
+  }
+
+ private:
+  typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+  TestCaseInfoContainer test_case_infos_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-port.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-port.h
new file mode 100644
index 0000000..dc4fe0c
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-port.h
@@ -0,0 +1,1947 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: wan at google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms.  They are subject to change without notice.  DO NOT USE
+// THEM IN USER CODE.
+//
+// This file is fundamental to Google Test.  All other Google Test source
+// files are expected to #include this.  Therefore, it cannot #include
+// any other Google Test header.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior.  If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+//   GTEST_HAS_CLONE          - Define it to 1/0 to indicate that clone(2)
+//                              is/isn't available.
+//   GTEST_HAS_EXCEPTIONS     - Define it to 1/0 to indicate that exceptions
+//                              are enabled.
+//   GTEST_HAS_GLOBAL_STRING  - Define it to 1/0 to indicate that ::string
+//                              is/isn't available (some systems define
+//                              ::string, which is different to std::string).
+//   GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+//                              is/isn't available (some systems define
+//                              ::wstring, which is different to std::wstring).
+//   GTEST_HAS_POSIX_RE       - Define it to 1/0 to indicate that POSIX regular
+//                              expressions are/aren't available.
+//   GTEST_HAS_PTHREAD        - Define it to 1/0 to indicate that <pthread.h>
+//                              is/isn't available.
+//   GTEST_HAS_RTTI           - Define it to 1/0 to indicate that RTTI is/isn't
+//                              enabled.
+//   GTEST_HAS_STD_WSTRING    - Define it to 1/0 to indicate that
+//                              std::wstring does/doesn't work (Google Test can
+//                              be used where std::wstring is unavailable).
+//   GTEST_HAS_TR1_TUPLE      - Define it to 1/0 to indicate tr1::tuple
+//                              is/isn't available.
+//   GTEST_HAS_SEH            - Define it to 1/0 to indicate whether the
+//                              compiler supports Microsoft's "Structured
+//                              Exception Handling".
+//   GTEST_HAS_STREAM_REDIRECTION
+//                            - Define it to 1/0 to indicate whether the
+//                              platform supports I/O stream redirection using
+//                              dup() and dup2().
+//   GTEST_USE_OWN_TR1_TUPLE  - Define it to 1/0 to indicate whether Google
+//                              Test's own tr1 tuple implementation should be
+//                              used.  Unused when the user sets
+//                              GTEST_HAS_TR1_TUPLE to 0.
+//   GTEST_LANG_CXX11         - Define it to 1/0 to indicate that Google Test
+//                              is building in C++11/C++98 mode.
+//   GTEST_LINKED_AS_SHARED_LIBRARY
+//                            - Define to 1 when compiling tests that use
+//                              Google Test as a shared library (known as
+//                              DLL on Windows).
+//   GTEST_CREATE_SHARED_LIBRARY
+//                            - Define to 1 when compiling Google Test itself
+//                              as a shared library.
+
+// This header defines the following utilities:
+//
+// Macros indicating the current platform (defined to 1 if compiled on
+// the given platform; otherwise undefined):
+//   GTEST_OS_AIX      - IBM AIX
+//   GTEST_OS_CYGWIN   - Cygwin
+//   GTEST_OS_HPUX     - HP-UX
+//   GTEST_OS_LINUX    - Linux
+//     GTEST_OS_LINUX_ANDROID - Google Android
+//   GTEST_OS_MAC      - Mac OS X
+//     GTEST_OS_IOS    - iOS
+//       GTEST_OS_IOS_SIMULATOR - iOS simulator
+//   GTEST_OS_NACL     - Google Native Client (NaCl)
+//   GTEST_OS_OPENBSD  - OpenBSD
+//   GTEST_OS_QNX      - QNX
+//   GTEST_OS_SOLARIS  - Sun Solaris
+//   GTEST_OS_SYMBIAN  - Symbian
+//   GTEST_OS_WINDOWS  - Windows (Desktop, MinGW, or Mobile)
+//     GTEST_OS_WINDOWS_DESKTOP  - Windows Desktop
+//     GTEST_OS_WINDOWS_MINGW    - MinGW
+//     GTEST_OS_WINDOWS_MOBILE   - Windows Mobile
+//   GTEST_OS_ZOS      - z/OS
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support.  Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable.  If you notice any problems on your platform, please notify
+// googletestframework at googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_* macros are defined.
+//
+// Macros indicating available Google Test features (defined to 1 if
+// the corresponding feature is supported; otherwise undefined):
+//   GTEST_HAS_COMBINE      - the Combine() function (for value-parameterized
+//                            tests)
+//   GTEST_HAS_DEATH_TEST   - death tests
+//   GTEST_HAS_PARAM_TEST   - value-parameterized tests
+//   GTEST_HAS_TYPED_TEST   - typed tests
+//   GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+//   GTEST_USES_POSIX_RE    - enhanced POSIX regex is used. Do not confuse with
+//                            GTEST_HAS_POSIX_RE (see above) which users can
+//                            define themselves.
+//   GTEST_USES_SIMPLE_RE   - our own simple regex is used;
+//                            the above two are mutually exclusive.
+//   GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+//
+// Macros for basic C++ coding:
+//   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+//   GTEST_ATTRIBUTE_UNUSED_  - declares that a class' instances or a
+//                              variable don't have to be used.
+//   GTEST_DISALLOW_ASSIGN_   - disables operator=.
+//   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+//   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.
+//
+// Synchronization:
+//   Mutex, MutexLock, ThreadLocal, GetThreadCount()
+//                  - synchronization primitives.
+//   GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+//                         synchronization primitives have real implementations
+//                         and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+//   is_pointer     - as in TR1; needed on Symbian and IBM XL C/C++ only.
+//   IteratorTraits - partial implementation of std::iterator_traits, which
+//                    is not available in libCstd when compiled with Sun C++.
+//
+// Smart pointers:
+//   scoped_ptr     - as in TR2.
+//
+// Regular expressions:
+//   RE             - a simple regular expression class using the POSIX
+//                    Extended Regular Expression syntax on UNIX-like
+//                    platforms, or a reduced regular exception syntax on
+//                    other platforms, including Windows.
+//
+// Logging:
+//   GTEST_LOG_()   - logs messages at the specified severity level.
+//   LogToStderr()  - directs all log messages to stderr.
+//   FlushInfoLog() - flushes informational log messages.
+//
+// Stdout and stderr capturing:
+//   CaptureStdout()     - starts capturing stdout.
+//   GetCapturedStdout() - stops capturing stdout and returns the captured
+//                         string.
+//   CaptureStderr()     - starts capturing stderr.
+//   GetCapturedStderr() - stops capturing stderr and returns the captured
+//                         string.
+//
+// Integer types:
+//   TypeWithSize   - maps an integer to a int type.
+//   Int32, UInt32, Int64, UInt64, TimeInMillis
+//                  - integers of known sizes.
+//   BiggestInt     - the biggest signed integer type.
+//
+// Command-line utilities:
+//   GTEST_FLAG()       - references a flag.
+//   GTEST_DECLARE_*()  - declares a flag.
+//   GTEST_DEFINE_*()   - defines a flag.
+//   GetInjectableArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+//   GetEnv()             - gets the value of an environment variable.
+//   BoolFromGTestEnv()   - parses a bool environment variable.
+//   Int32FromGTestEnv()  - parses an Int32 environment variable.
+//   StringFromGTestEnv() - parses a string environment variable.
+
+#include <ctype.h>   // for isspace, etc
+#include <stddef.h>  // for ptrdiff_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif  // !_WIN32_WCE
+
+#if defined __APPLE__
+# include <AvailabilityMacros.h>
+# include <TargetConditionals.h>
+#endif
+
+#include <iostream>  // NOLINT
+#include <sstream>  // NOLINT
+#include <string>  // NOLINT
+
+#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+#define GTEST_FLAG_PREFIX_ "gtest_"
+#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+#define GTEST_NAME_ "Google Test"
+#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+# define GTEST_GCC_VER_ \
+    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif  // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+# define GTEST_OS_CYGWIN 1
+#elif defined __SYMBIAN32__
+# define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+# define GTEST_OS_WINDOWS 1
+# ifdef _WIN32_WCE
+#  define GTEST_OS_WINDOWS_MOBILE 1
+# elif defined(__MINGW__) || defined(__MINGW32__)
+#  define GTEST_OS_WINDOWS_MINGW 1
+# else
+#  define GTEST_OS_WINDOWS_DESKTOP 1
+# endif  // _WIN32_WCE
+#elif defined __APPLE__
+# define GTEST_OS_MAC 1
+# if TARGET_OS_IPHONE
+#  define GTEST_OS_IOS 1
+#  if TARGET_IPHONE_SIMULATOR
+#   define GTEST_OS_IOS_SIMULATOR 1
+#  endif
+# endif
+#elif defined __linux__
+# define GTEST_OS_LINUX 1
+# if defined __ANDROID__
+#  define GTEST_OS_LINUX_ANDROID 1
+# endif
+#elif defined __MVS__
+# define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+# define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+# define GTEST_OS_AIX 1
+#elif defined(__hpux)
+# define GTEST_OS_HPUX 1
+#elif defined __native_client__
+# define GTEST_OS_NACL 1
+#elif defined __OpenBSD__
+# define GTEST_OS_OPENBSD 1
+#elif defined __QNX__
+# define GTEST_OS_QNX 1
+#endif  // __CYGWIN__
+
+#ifndef GTEST_LANG_CXX11
+// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
+// -std={c,gnu}++{0x,11} is passed.  The C++11 standard specifies a
+// value for __cplusplus, and recent versions of clang, gcc, and
+// probably other compilers set that too in C++11 mode.
+# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
+// Compiling in at least C++11 mode.
+#  define GTEST_LANG_CXX11 1
+# else
+#  define GTEST_LANG_CXX11 0
+# endif
+#endif
+
+// Brings in definitions for functions used in the testing::internal::posix
+// namespace (read, write, close, chdir, isatty, stat). We do not currently
+// use them on Windows Mobile.
+#if !GTEST_OS_WINDOWS
+// This assumes that non-Windows OSes provide unistd.h. For OSes where this
+// is not the case, we need to include headers that provide the functions
+// mentioned above.
+# include <unistd.h>
+# include <strings.h>
+#elif !GTEST_OS_WINDOWS_MOBILE
+# include <direct.h>
+# include <io.h>
+#endif
+
+#if GTEST_OS_LINUX_ANDROID
+// Used to define __ANDROID_API__ matching the target NDK API level.
+#  include <android/api-level.h>  // NOLINT
+#endif
+
+// Defines this to true iff Google Test can use POSIX regular expressions.
+#ifndef GTEST_HAS_POSIX_RE
+# if GTEST_OS_LINUX_ANDROID
+// On Android, <regex.h> is only available starting with Gingerbread.
+#  define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
+# else
+#  define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
+# endif
+#endif
+
+#if GTEST_HAS_POSIX_RE
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise.  We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+# include <regex.h>  // NOLINT
+
+# define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+// <regex.h> is not available on Windows.  Use our own simple regex
+// implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform.  Use our own
+// simple regex implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#endif  // GTEST_HAS_POSIX_RE
+
+#ifndef GTEST_HAS_EXCEPTIONS
+// The user didn't tell us whether exceptions are enabled, so we need
+// to figure it out.
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+#  ifndef _HAS_EXCEPTIONS
+#   define _HAS_EXCEPTIONS 1
+#  endif  // _HAS_EXCEPTIONS
+#  define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+#  define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__SUNPRO_CC)
+// Sun Pro CC supports exceptions.  However, there is no compile-time way of
+// detecting whether they are enabled or not.  Therefore, we assume that
+// they are enabled unless the user tells us otherwise.
+#  define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__IBMCPP__) && __EXCEPTIONS
+// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+#  define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__HP_aCC)
+// Exception handling is in effect by default in HP aCC compiler. It has to
+// be turned of by +noeh compiler option if desired.
+#  define GTEST_HAS_EXCEPTIONS 1
+# else
+// For other compilers, we assume exceptions are disabled to be
+// conservative.
+#  define GTEST_HAS_EXCEPTIONS 0
+# endif  // defined(_MSC_VER) || defined(__BORLANDC__)
+#endif  // GTEST_HAS_EXCEPTIONS
+
+#if !defined(GTEST_HAS_STD_STRING)
+// Even though we don't use this macro any longer, we keep it in case
+// some clients still depend on it.
+# define GTEST_HAS_STD_STRING 1
+#elif !GTEST_HAS_STD_STRING
+// The user told us that ::std::string isn't available.
+# error "Google Test cannot be used where ::std::string isn't available."
+#endif  // !defined(GTEST_HAS_STD_STRING)
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+# define GTEST_HAS_GLOBAL_STRING 0
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan at google.com): uses autoconf to detect whether ::std::wstring
+//   is available.
+
+// Cygwin 1.7 and below doesn't support ::std::wstring.
+// Solaris' libc++ doesn't support it either.  Android has
+// no support for it at least as recent as Froyo (2.2).
+# define GTEST_HAS_STD_WSTRING \
+    (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+
+#endif  // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+# define GTEST_HAS_GLOBAL_WSTRING \
+    (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+# ifdef _MSC_VER
+
+#  ifdef _CPPRTTI  // MSVC defines this macro iff RTTI is enabled.
+#   define GTEST_HAS_RTTI 1
+#  else
+#   define GTEST_HAS_RTTI 0
+#  endif
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
+
+#  ifdef __GXX_RTTI
+// When building against STLport with the Android NDK and with
+// -frtti -fno-exceptions, the build fails at link time with undefined
+// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
+// so disable RTTI when detected.
+#   if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
+       !defined(__EXCEPTIONS)
+#    define GTEST_HAS_RTTI 0
+#   else
+#    define GTEST_HAS_RTTI 1
+#   endif  // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
+#  else
+#   define GTEST_HAS_RTTI 0
+#  endif  // __GXX_RTTI
+
+// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
+// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
+// first version with C++ support.
+# elif defined(__clang__)
+
+#  define GTEST_HAS_RTTI __has_feature(cxx_rtti)
+
+// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
+// both the typeid and dynamic_cast features are present.
+# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
+
+#  ifdef __RTTI_ALL__
+#   define GTEST_HAS_RTTI 1
+#  else
+#   define GTEST_HAS_RTTI 0
+#  endif
+
+# else
+
+// For all other compilers, we assume RTTI is enabled.
+#  define GTEST_HAS_RTTI 1
+
+# endif  // _MSC_VER
+
+#endif  // GTEST_HAS_RTTI
+
+// It's this header's responsibility to #include <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+# include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we assume pthreads support is
+// available on Linux and Mac.
+//
+// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
+// to your compiler flags.
+# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
+    || GTEST_OS_QNX)
+#endif  // GTEST_HAS_PTHREAD
+
+#if GTEST_HAS_PTHREAD
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+# include <pthread.h>  // NOLINT
+
+// For timespec and nanosleep, used below.
+# include <time.h>  // NOLINT
+#endif
+
+// Determines whether Google Test can use tr1/tuple.  You can define
+// this macro to 0 to prevent Google Test from using tuple (any
+// feature depending on tuple with be disabled in this mode).
+#ifndef GTEST_HAS_TR1_TUPLE
+# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR)
+// STLport, provided with the Android NDK, has neither <tr1/tuple> or <tuple>.
+#  define GTEST_HAS_TR1_TUPLE 0
+# else
+// The user didn't tell us not to do it, so we assume it's OK.
+#  define GTEST_HAS_TR1_TUPLE 1
+# endif
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Determines whether Google Test's own tr1 tuple implementation
+// should be used.
+#ifndef GTEST_USE_OWN_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// We use our own TR1 tuple if we aren't sure the user has an
+// implementation of it already.  At this time, libstdc++ 4.0.0+ and
+// MSVC 2010 are the only mainstream standard libraries that come
+// with a TR1 tuple implementation.  NVIDIA's CUDA NVCC compiler
+// pretends to be GCC by defining __GNUC__ and friends, but cannot
+// compile GCC's tuple implementation.  MSVC 2008 (9.0) provides TR1
+// tuple in a 323 MB Feature Pack download, which we cannot assume the
+// user has.  QNX's QCC compiler is a modified GCC but it doesn't
+// support TR1 tuple.  libc++ only provides std::tuple, in C++11 mode,
+// and it can be used with some compilers that define __GNUC__.
+# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \
+      && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600
+#  define GTEST_ENV_HAS_TR1_TUPLE_ 1
+# endif
+
+// C++11 specifies that <tuple> provides std::tuple. Use that if gtest is used
+// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6
+// can build with clang but need to use gcc4.2's libstdc++).
+# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
+#  define GTEST_ENV_HAS_STD_TUPLE_ 1
+# endif
+
+# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
+#  define GTEST_USE_OWN_TR1_TUPLE 0
+# else
+#  define GTEST_USE_OWN_TR1_TUPLE 1
+# endif
+
+#endif  // GTEST_USE_OWN_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+
+# if GTEST_USE_OWN_TR1_TUPLE
+#  include "gtest/internal/gtest-tuple.h"
+# elif GTEST_ENV_HAS_STD_TUPLE_
+#  include <tuple>
+// C++11 puts its tuple into the ::std namespace rather than
+// ::std::tr1.  gtest expects tuple to live in ::std::tr1, so put it there.
+// This causes undefined behavior, but supported compilers react in
+// the way we intend.
+namespace std {
+namespace tr1 {
+using ::std::get;
+using ::std::make_tuple;
+using ::std::tuple;
+using ::std::tuple_element;
+using ::std::tuple_size;
+}
+}
+
+# elif GTEST_OS_SYMBIAN
+
+// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
+// use STLport's tuple implementation, which unfortunately doesn't
+// work as the copy of STLport distributed with Symbian is incomplete.
+// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
+// use its own tuple implementation.
+#  ifdef BOOST_HAS_TR1_TUPLE
+#   undef BOOST_HAS_TR1_TUPLE
+#  endif  // BOOST_HAS_TR1_TUPLE
+
+// This prevents <boost/tr1/detail/config.hpp>, which defines
+// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
+#  define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
+#  include <tuple>
+
+# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header.  This does
+// not conform to the TR1 spec, which requires the header to be <tuple>.
+
+#  if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
+// which is #included by <tr1/tuple>, to not compile when RTTI is
+// disabled.  _TR1_FUNCTIONAL is the header guard for
+// <tr1/functional>.  Hence the following #define is a hack to prevent
+// <tr1/functional> from being included.
+#   define _TR1_FUNCTIONAL 1
+#   include <tr1/tuple>
+#   undef _TR1_FUNCTIONAL  // Allows the user to #include
+                        // <tr1/functional> if he chooses to.
+#  else
+#   include <tr1/tuple>  // NOLINT
+#  endif  // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+
+# else
+// If the compiler is not GCC 4.0+, we assume the user is using a
+// spec-conforming TR1 implementation.
+#  include <tuple>  // NOLINT
+# endif  // GTEST_USE_OWN_TR1_TUPLE
+
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+# if GTEST_OS_LINUX && !defined(__ia64__)
+#  if GTEST_OS_LINUX_ANDROID
+// On Android, clone() is only available on ARM starting with Gingerbread.
+#    if defined(__arm__) && __ANDROID_API__ >= 9
+#     define GTEST_HAS_CLONE 1
+#    else
+#     define GTEST_HAS_CLONE 0
+#    endif
+#  else
+#   define GTEST_HAS_CLONE 1
+#  endif
+# else
+#  define GTEST_HAS_CLONE 0
+# endif  // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif  // GTEST_HAS_CLONE
+
+// Determines whether to support stream redirection. This is used to test
+// output correctness and to implement death tests.
+#ifndef GTEST_HAS_STREAM_REDIRECTION
+// By default, we assume that stream redirection is supported on all
+// platforms except known mobile ones.
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
+#  define GTEST_HAS_STREAM_REDIRECTION 0
+# else
+#  define GTEST_HAS_STREAM_REDIRECTION 1
+# endif  // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+#endif  // GTEST_HAS_STREAM_REDIRECTION
+
+// Determines whether to support death tests.
+// Google Test does not support death tests for VC 7.1 and earlier as
+// abort() in a VC 7.1 application compiled as GUI in debug config
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+     (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
+     (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
+     GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
+     GTEST_OS_OPENBSD || GTEST_OS_QNX)
+# define GTEST_HAS_DEATH_TEST 1
+# include <vector>  // NOLINT
+#endif
+
+// We don't support MSVC 7.1 with exceptions disabled now.  Therefore
+// all the compilers we care about are adequate for supporting
+// value-parameterized tests.
+#define GTEST_HAS_PARAM_TEST 1
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, IBM Visual Age, and HP aCC support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
+    defined(__IBMCPP__) || defined(__HP_aCC)
+# define GTEST_HAS_TYPED_TEST 1
+# define GTEST_HAS_TYPED_TEST_P 1
+#endif
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled.  The implementation doesn't
+// work on Sun Studio since it doesn't understand templated conversion
+// operators.
+#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
+# define GTEST_HAS_COMBINE 1
+#endif
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+    (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
+
+// Determines whether test results can be streamed to a socket.
+#if GTEST_OS_LINUX
+# define GTEST_CAN_STREAM_RESULTS_ 1
+#endif
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding.  This leads to problems with code like:
+//
+//   if (gate)
+//     ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default:  // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used.  This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor.  Example:
+//
+//   struct Foo {
+//     Foo() { ... }
+//   } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+# define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_ASSIGN_(type)\
+  void operator=(type const &)
+
+// A macro to disallow copy constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+  type(type const &);\
+  GTEST_DISALLOW_ASSIGN_(type)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro.  The macro should be used on function declarations
+// following the argument list:
+//
+//   Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+# define GTEST_MUST_USE_RESULT_
+#endif  // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling.  This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+#  define GTEST_HAS_SEH 1
+# else
+// Assume no SEH.
+#  define GTEST_HAS_SEH 0
+# endif
+
+#endif  // GTEST_HAS_SEH
+
+#ifdef _MSC_VER
+
+# if GTEST_LINKED_AS_SHARED_LIBRARY
+#  define GTEST_API_ __declspec(dllimport)
+# elif GTEST_CREATE_SHARED_LIBRARY
+#  define GTEST_API_ __declspec(dllexport)
+# endif
+
+#endif  // _MSC_VER
+
+#ifndef GTEST_API_
+# define GTEST_API_
+#endif
+
+#ifdef __GNUC__
+// Ask the compiler to never inline a given function.
+# define GTEST_NO_INLINE_ __attribute__((noinline))
+#else
+# define GTEST_NO_INLINE_
+#endif
+
+// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
+#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
+# define GTEST_HAS_CXXABI_H_ 1
+#else
+# define GTEST_HAS_CXXABI_H_ 0
+#endif
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+// A secret type that Google Test users don't know about.  It has no
+// definition on purpose.  Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+//                         content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define GTEST_COMPILE_ASSERT_(expr, msg) \
+  typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
+      msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
+
+// Implementation details of GTEST_COMPILE_ASSERT_:
+//
+// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//    #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is
+//                                      // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     GTEST_COMPILE_ASSERT_(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
+//
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+#if GTEST_HAS_GLOBAL_STRING
+typedef ::string string;
+#else
+typedef ::std::string string;
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+typedef ::wstring wstring;
+#elif GTEST_HAS_STD_WSTRING
+typedef ::std::wstring wstring;
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// A helper for suppressing warnings on constant condition.  It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+  typedef T element_type;
+
+  explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+  ~scoped_ptr() { reset(); }
+
+  T& operator*() const { return *ptr_; }
+  T* operator->() const { return ptr_; }
+  T* get() const { return ptr_; }
+
+  T* release() {
+    T* const ptr = ptr_;
+    ptr_ = NULL;
+    return ptr;
+  }
+
+  void reset(T* p = NULL) {
+    if (p != ptr_) {
+      if (IsTrue(sizeof(T) > 0)) {  // Makes sure T is a complete type.
+        delete ptr_;
+      }
+      ptr_ = p;
+    }
+  }
+
+ private:
+  T* ptr_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>.  It uses the POSIX Extended
+// Regular Expression syntax.
+class GTEST_API_ RE {
+ public:
+  // A copy constructor is required by the Standard to initialize object
+  // references from r-values.
+  RE(const RE& other) { Init(other.pattern()); }
+
+  // Constructs an RE from a string.
+  RE(const ::std::string& regex) { Init(regex.c_str()); }  // NOLINT
+
+#if GTEST_HAS_GLOBAL_STRING
+
+  RE(const ::string& regex) { Init(regex.c_str()); }  // NOLINT
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  RE(const char* regex) { Init(regex); }  // NOLINT
+  ~RE();
+
+  // Returns the string representation of the regex.
+  const char* pattern() const { return pattern_; }
+
+  // FullMatch(str, re) returns true iff regular expression re matches
+  // the entire str.
+  // PartialMatch(str, re) returns true iff regular expression re
+  // matches a substring of str (including str itself).
+  //
+  // TODO(wan at google.com): make FullMatch() and PartialMatch() work
+  // when str contains NUL characters.
+  static bool FullMatch(const ::std::string& str, const RE& re) {
+    return FullMatch(str.c_str(), re);
+  }
+  static bool PartialMatch(const ::std::string& str, const RE& re) {
+    return PartialMatch(str.c_str(), re);
+  }
+
+#if GTEST_HAS_GLOBAL_STRING
+
+  static bool FullMatch(const ::string& str, const RE& re) {
+    return FullMatch(str.c_str(), re);
+  }
+  static bool PartialMatch(const ::string& str, const RE& re) {
+    return PartialMatch(str.c_str(), re);
+  }
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  static bool FullMatch(const char* str, const RE& re);
+  static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+  void Init(const char* regex);
+
+  // We use a const char* instead of an std::string, as Google Test used to be
+  // used where std::string is not available.  TODO(wan at google.com): change to
+  // std::string.
+  const char* pattern_;
+  bool is_valid_;
+
+#if GTEST_USES_POSIX_RE
+
+  regex_t full_regex_;     // For FullMatch().
+  regex_t partial_regex_;  // For PartialMatch().
+
+#else  // GTEST_USES_SIMPLE_RE
+
+  const char* full_pattern_;  // For FullMatch();
+
+#endif
+
+  GTEST_DISALLOW_ASSIGN_(RE);
+};
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line);
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file,
+                                                               int line);
+
+// Defines logging utilities:
+//   GTEST_LOG_(severity) - logs messages at the specified severity level. The
+//                          message itself is streamed into the macro.
+//   LogToStderr()  - directs all log messages to stderr.
+//   FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+  GTEST_INFO,
+  GTEST_WARNING,
+  GTEST_ERROR,
+  GTEST_FATAL
+};
+
+// Formats log entry severity, provides a stream object for streaming the
+// log message, and terminates the message with a newline when going out of
+// scope.
+class GTEST_API_ GTestLog {
+ public:
+  GTestLog(GTestLogSeverity severity, const char* file, int line);
+
+  // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+  ~GTestLog();
+
+  ::std::ostream& GetStream() { return ::std::cerr; }
+
+ private:
+  const GTestLogSeverity severity_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
+};
+
+#define GTEST_LOG_(severity) \
+    ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+                                  __FILE__, __LINE__).GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+//  Synopsys:
+//    GTEST_CHECK_(boolean_condition);
+//     or
+//    GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+//    This checks the condition and if the condition is not satisfied
+//    it prints message about the condition violation, including the
+//    condition itself, plus additional message streamed into it, if any,
+//    and then it aborts the program. It aborts the program irrespective of
+//    whether it is built in the debug mode or not.
+#define GTEST_CHECK_(condition) \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+    if (::testing::internal::IsTrue(condition)) \
+      ; \
+    else \
+      GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+
+// An all-mode assert to verify that the given POSIX-style function
+// call returns 0 (indicating success).  Known limitation: this
+// doesn't expand to a balanced 'if' statement, so enclose the macro
+// in {} if you need to use it as the only statement in an 'if'
+// branch.
+#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
+  if (const int gtest_error = (posix_call)) \
+    GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
+                      << gtest_error
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Use ImplicitCast_ as a safe version of static_cast for upcasting in
+// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
+// const Foo*).  When you use ImplicitCast_, the compiler checks that
+// the cast is safe.  Such explicit ImplicitCast_s are necessary in
+// surprisingly many situations where C++ demands an exact type match
+// instead of an argument type convertable to a target type.
+//
+// The syntax for using ImplicitCast_ is the same as for static_cast:
+//
+//   ImplicitCast_<ToType>(expr)
+//
+// ImplicitCast_ would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., implicit_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To>
+inline To ImplicitCast_(To x) { return x; }
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
+// always succeed.  When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo?  It
+// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
+// when you downcast, you should use this macro.  In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not).  In normal mode, we do the efficient static_cast<>
+// instead.  Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+//    This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., down_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To, typename From>  // use like this: DownCast_<T*>(foo);
+inline To DownCast_(From* f) {  // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    const To to = NULL;
+    ::testing::internal::ImplicitCast_<From*>(to);
+  }
+
+#if GTEST_HAS_RTTI
+  // RTTI: debug mode only!
+  GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+  return static_cast<To>(f);
+}
+
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+  GTEST_CHECK_(typeid(*base) == typeid(Derived));
+  return dynamic_cast<Derived*>(base);  // NOLINT
+#else
+  return static_cast<Derived*>(base);  // Poor man's downcast.
+#endif
+}
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Defines the stderr capturer:
+//   CaptureStdout     - starts capturing stdout.
+//   GetCapturedStdout - stops capturing stdout and returns the captured string.
+//   CaptureStderr     - starts capturing stderr.
+//   GetCapturedStderr - stops capturing stderr and returns the captured string.
+//
+GTEST_API_ void CaptureStdout();
+GTEST_API_ std::string GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ std::string GetCapturedStderr();
+
+#endif  // GTEST_HAS_STREAM_REDIRECTION
+
+
+#if GTEST_HAS_DEATH_TEST
+
+const ::std::vector<testing::internal::string>& GetInjectableArgvs();
+void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
+                             new_argvs);
+
+// A copy of all command line arguments.  Set by InitGoogleTest().
+extern ::std::vector<testing::internal::string> g_argvs;
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+#if GTEST_HAS_PTHREAD
+
+// Sleeps for (roughly) n milli-seconds.  This function is only for
+// testing Google Test's own constructs.  Don't use it in user tests,
+// either directly or indirectly.
+inline void SleepMilliseconds(int n) {
+  const timespec time = {
+    0,                  // 0 seconds.
+    n * 1000L * 1000L,  // And n ms.
+  };
+  nanosleep(&time, NULL);
+}
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified.  Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class Notification {
+ public:
+  Notification() : notified_(false) {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+  }
+  ~Notification() {
+    pthread_mutex_destroy(&mutex_);
+  }
+
+  // Notifies all threads created with this notification to start. Must
+  // be called from the controller thread.
+  void Notify() {
+    pthread_mutex_lock(&mutex_);
+    notified_ = true;
+    pthread_mutex_unlock(&mutex_);
+  }
+
+  // Blocks until the controller thread notifies. Must be called from a test
+  // thread.
+  void WaitForNotification() {
+    for (;;) {
+      pthread_mutex_lock(&mutex_);
+      const bool notified = notified_;
+      pthread_mutex_unlock(&mutex_);
+      if (notified)
+        break;
+      SleepMilliseconds(10);
+    }
+  }
+
+ private:
+  pthread_mutex_t mutex_;
+  bool notified_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+
+// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
+// Consequently, it cannot select a correct instantiation of ThreadWithParam
+// in order to call its Run(). Introducing ThreadWithParamBase as a
+// non-templated base class for ThreadWithParam allows us to bypass this
+// problem.
+class ThreadWithParamBase {
+ public:
+  virtual ~ThreadWithParamBase() {}
+  virtual void Run() = 0;
+};
+
+// pthread_create() accepts a pointer to a function type with the C linkage.
+// According to the Standard (7.5/1), function types with different linkages
+// are different even if they are otherwise identical.  Some compilers (for
+// example, SunStudio) treat them as different types.  Since class methods
+// cannot be defined with C-linkage we need to define a free C-function to
+// pass into pthread_create().
+extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
+  static_cast<ThreadWithParamBase*>(thread)->Run();
+  return NULL;
+}
+
+// Helper class for testing Google Test's multi-threading constructs.
+// To use it, write:
+//
+//   void ThreadFunc(int param) { /* Do things with param */ }
+//   Notification thread_can_start;
+//   ...
+//   // The thread_can_start parameter is optional; you can supply NULL.
+//   ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
+//   thread_can_start.Notify();
+//
+// These classes are only for testing Google Test's own constructs. Do
+// not use them in user tests, either directly or indirectly.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+  typedef void (*UserThreadFunc)(T);
+
+  ThreadWithParam(
+      UserThreadFunc func, T param, Notification* thread_can_start)
+      : func_(func),
+        param_(param),
+        thread_can_start_(thread_can_start),
+        finished_(false) {
+    ThreadWithParamBase* const base = this;
+    // The thread can be created only after all fields except thread_
+    // have been initialized.
+    GTEST_CHECK_POSIX_SUCCESS_(
+        pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+  }
+  ~ThreadWithParam() { Join(); }
+
+  void Join() {
+    if (!finished_) {
+      GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+      finished_ = true;
+    }
+  }
+
+  virtual void Run() {
+    if (thread_can_start_ != NULL)
+      thread_can_start_->WaitForNotification();
+    func_(param_);
+  }
+
+ private:
+  const UserThreadFunc func_;  // User-supplied thread function.
+  const T param_;  // User-supplied parameter to the thread function.
+  // When non-NULL, used to block execution until the controller thread
+  // notifies.
+  Notification* const thread_can_start_;
+  bool finished_;  // true iff we know that the thread function has finished.
+  pthread_t thread_;  // The native thread object.
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms. They
+// are used in conjunction with class MutexLock:
+//
+//   Mutex mutex;
+//   ...
+//   MutexLock lock(&mutex);  // Acquires the mutex and releases it at the end
+//                            // of the current scope.
+//
+// MutexBase implements behavior for both statically and dynamically
+// allocated mutexes.  Do not use MutexBase directly.  Instead, write
+// the following to define a static mutex:
+//
+//   GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+//
+// You can forward declare a static mutex like this:
+//
+//   GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// To create a dynamic mutex, just define an object of type Mutex.
+class MutexBase {
+ public:
+  // Acquires this mutex.
+  void Lock() {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+    owner_ = pthread_self();
+    has_owner_ = true;
+  }
+
+  // Releases this mutex.
+  void Unlock() {
+    // Since the lock is being released the owner_ field should no longer be
+    // considered valid. We don't protect writing to has_owner_ here, as it's
+    // the caller's responsibility to ensure that the current thread holds the
+    // mutex when this is called.
+    has_owner_ = false;
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
+  }
+
+  // Does nothing if the current thread holds the mutex. Otherwise, crashes
+  // with high probability.
+  void AssertHeld() const {
+    GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
+        << "The current thread is not holding the mutex @" << this;
+  }
+
+  // A static mutex may be used before main() is entered.  It may even
+  // be used before the dynamic initialization stage.  Therefore we
+  // must be able to initialize a static mutex object at link time.
+  // This means MutexBase has to be a POD and its member variables
+  // have to be public.
+ public:
+  pthread_mutex_t mutex_;  // The underlying pthread mutex.
+  // has_owner_ indicates whether the owner_ field below contains a valid thread
+  // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
+  // accesses to the owner_ field should be protected by a check of this field.
+  // An alternative might be to memset() owner_ to all zeros, but there's no
+  // guarantee that a zero'd pthread_t is necessarily invalid or even different
+  // from pthread_self().
+  bool has_owner_;
+  pthread_t owner_;  // The thread holding the mutex.
+};
+
+// Forward-declares a static mutex.
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+    extern ::testing::internal::MutexBase mutex
+
+// Defines and statically (i.e. at link time) initializes a static mutex.
+// The initialization list here does not explicitly initialize each field,
+// instead relying on default initialization for the unspecified fields. In
+// particular, the owner_ field (a pthread_t) is not explicitly initialized.
+// This allows initialization to work whether pthread_t is a scalar or struct.
+// The flag -Wmissing-field-initializers must not be specified for this to work.
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+    ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
+
+// The Mutex class can only be used for mutexes created at runtime. It
+// shares its API with MutexBase otherwise.
+class Mutex : public MutexBase {
+ public:
+  Mutex() {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+    has_owner_ = false;
+  }
+  ~Mutex() {
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
+  }
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+// We cannot name this class MutexLock as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms.  Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+  explicit GTestMutexLock(MutexBase* mutex)
+      : mutex_(mutex) { mutex_->Lock(); }
+
+  ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+  MutexBase* const mutex_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage.  Therefore it cannot be templatized to access
+// ThreadLocal<T>.  Hence the need for class
+// ThreadLocalValueHolderBase.
+class ThreadLocalValueHolderBase {
+ public:
+  virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Called by pthread to delete thread-local data stored by
+// pthread_setspecific().
+extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
+  delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+//
+//   // Thread 1
+//   ThreadLocal<int> tl(100);  // 100 is the default value for each thread.
+//
+//   // Thread 2
+//   tl.set(150);  // Changes the value for thread 2 only.
+//   EXPECT_EQ(150, tl.get());
+//
+//   // Thread 1
+//   EXPECT_EQ(100, tl.get());  // In thread 1, tl has the original value.
+//   tl.set(200);
+//   EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// An object managed for a thread by a ThreadLocal instance is deleted
+// when the thread exits.  Or, if the ThreadLocal instance dies in
+// that thread, when the ThreadLocal dies.  It's the user's
+// responsibility to ensure that all other threads using a ThreadLocal
+// have exited when it dies, or the per-thread objects for those
+// threads will not be deleted.
+//
+// Google Test only uses global ThreadLocal objects.  That means they
+// will die after main() has returned.  Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal {
+ public:
+  ThreadLocal() : key_(CreateKey()),
+                  default_() {}
+  explicit ThreadLocal(const T& value) : key_(CreateKey()),
+                                         default_(value) {}
+
+  ~ThreadLocal() {
+    // Destroys the managed object for the current thread, if any.
+    DeleteThreadLocalValue(pthread_getspecific(key_));
+
+    // Releases resources associated with the key.  This will *not*
+    // delete managed objects for other threads.
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
+  }
+
+  T* pointer() { return GetOrCreateValue(); }
+  const T* pointer() const { return GetOrCreateValue(); }
+  const T& get() const { return *pointer(); }
+  void set(const T& value) { *pointer() = value; }
+
+ private:
+  // Holds a value of type T.
+  class ValueHolder : public ThreadLocalValueHolderBase {
+   public:
+    explicit ValueHolder(const T& value) : value_(value) {}
+
+    T* pointer() { return &value_; }
+
+   private:
+    T value_;
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+  };
+
+  static pthread_key_t CreateKey() {
+    pthread_key_t key;
+    // When a thread exits, DeleteThreadLocalValue() will be called on
+    // the object managed for that thread.
+    GTEST_CHECK_POSIX_SUCCESS_(
+        pthread_key_create(&key, &DeleteThreadLocalValue));
+    return key;
+  }
+
+  T* GetOrCreateValue() const {
+    ThreadLocalValueHolderBase* const holder =
+        static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+    if (holder != NULL) {
+      return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+    }
+
+    ValueHolder* const new_holder = new ValueHolder(default_);
+    ThreadLocalValueHolderBase* const holder_base = new_holder;
+    GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+    return new_holder->pointer();
+  }
+
+  // A key pthreads uses for looking up per-thread values.
+  const pthread_key_t key_;
+  const T default_;  // The default value for each thread.
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# define GTEST_IS_THREADSAFE 1
+
+#else  // GTEST_HAS_PTHREAD
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable).  Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+  Mutex() {}
+  void Lock() {}
+  void Unlock() {}
+  void AssertHeld() const {}
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+  extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+class GTestMutexLock {
+ public:
+  explicit GTestMutexLock(Mutex*) {}  // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+  ThreadLocal() : value_() {}
+  explicit ThreadLocal(const T& value) : value_(value) {}
+  T* pointer() { return &value_; }
+  const T* pointer() const { return &value_; }
+  const T& get() const { return value_; }
+  void set(const T& value) { value_ = value; }
+ private:
+  T value_;
+};
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+# define GTEST_IS_THREADSAFE 0
+
+#endif  // GTEST_HAS_PTHREAD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler and generates a warning in Sun Studio.  The Nokia Symbian
+// and the IBM XL C/C++ compiler try to instantiate a copy constructor
+// for objects passed through ellipsis (...), failing for uncopyable
+// objects.  We define this to ensure that only POD is passed through
+// ellipsis on these systems.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+# define GTEST_ELLIPSIS_NEEDS_POD_ 1
+#else
+# define GTEST_CAN_COMPARE_NULL 1
+#endif
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template.  These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+# define GTEST_NEEDS_IS_POINTER_ 1
+#endif
+
+template <bool bool_value>
+struct bool_constant {
+  typedef bool_constant<bool_value> type;
+  static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+template <typename Iterator>
+struct IteratorTraits {
+  typedef typename Iterator::value_type value_type;
+};
+
+template <typename T>
+struct IteratorTraits<T*> {
+  typedef T value_type;
+};
+
+template <typename T>
+struct IteratorTraits<const T*> {
+  typedef T value_type;
+};
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_SEP_ "\\"
+# define GTEST_HAS_ALT_PATH_SEP_ 1
+// The biggest signed integer type the compiler supports.
+typedef __int64 BiggestInt;
+#else
+# define GTEST_PATH_SEP_ "/"
+# define GTEST_HAS_ALT_PATH_SEP_ 0
+typedef long long BiggestInt;  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+
+// Utilities for char.
+
+// isspace(int ch) and friends accept an unsigned char or EOF.  char
+// may be signed, depending on the compiler (or compiler flags).
+// Therefore we need to cast a char to unsigned char before calling
+// isspace(), etc.
+
+inline bool IsAlpha(char ch) {
+  return isalpha(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsAlNum(char ch) {
+  return isalnum(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsDigit(char ch) {
+  return isdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsLower(char ch) {
+  return islower(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsSpace(char ch) {
+  return isspace(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsUpper(char ch) {
+  return isupper(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(char ch) {
+  return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(wchar_t ch) {
+  const unsigned char low_byte = static_cast<unsigned char>(ch);
+  return ch == low_byte && isxdigit(low_byte) != 0;
+}
+
+inline char ToLower(char ch) {
+  return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
+}
+inline char ToUpper(char ch) {
+  return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
+}
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions.  These wrappers hide the differences between
+// Windows/MSVC and POSIX systems.  Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix {
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+# ifdef __BORLANDC__
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+# else  // !__BORLANDC__
+#  if GTEST_OS_WINDOWS_MOBILE
+inline int IsATTY(int /* fd */) { return 0; }
+#  else
+inline int IsATTY(int fd) { return _isatty(fd); }
+#  endif  // GTEST_OS_WINDOWS_MOBILE
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+# endif  // __BORLANDC__
+
+# if GTEST_OS_WINDOWS_MOBILE
+inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
+// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
+// time and thus not defined there.
+# else
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st) {
+  return (_S_IFDIR & st.st_mode) != 0;
+}
+# endif  // GTEST_OS_WINDOWS_MOBILE
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif  // GTEST_OS_WINDOWS
+
+// Functions deprecated by MSVC 8.0.
+
+#ifdef _MSC_VER
+// Temporarily disable warning 4996 (deprecated function).
+# pragma warning(push)
+# pragma warning(disable:4996)
+#endif
+
+inline const char* StrNCpy(char* dest, const char* src, size_t n) {
+  return strncpy(dest, src, n);
+}
+
+// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
+// StrError() aren't needed on Windows CE at this time and thus not
+// defined there.
+
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode) {
+  return fopen(path, mode);
+}
+#if !GTEST_OS_WINDOWS_MOBILE
+inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
+  return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+#endif
+inline int FClose(FILE* fp) { return fclose(fp); }
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int Read(int fd, void* buf, unsigned int count) {
+  return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+  return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+#endif
+inline const char* GetEnv(const char* name) {
+#if GTEST_OS_WINDOWS_MOBILE
+  // We are on Windows CE, which has no environment variables.
+  return NULL;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+  // Environment variables which we programmatically clear will be set to the
+  // empty string rather than unset (NULL).  Handle that case.
+  const char* const env = getenv(name);
+  return (env != NULL && env[0] != '\0') ? env : NULL;
+#else
+  return getenv(name);
+#endif
+}
+
+#ifdef _MSC_VER
+# pragma warning(pop)  // Restores the warning state.
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void Abort();
+#else
+inline void Abort() { abort(); }
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+}  // namespace posix
+
+// MSVC "deprecates" snprintf and issues warnings wherever it is used.  In
+// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
+// MSVC-based platforms.  We map the GTEST_SNPRINTF_ macro to the appropriate
+// function in order to achieve that.  We use macro definition here because
+// snprintf is a variadic function.
+#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+// MSVC 2005 and above support variadic macros.
+# define GTEST_SNPRINTF_(buffer, size, format, ...) \
+     _snprintf_s(buffer, size, size, format, __VA_ARGS__)
+#elif defined(_MSC_VER)
+// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't
+// complain about _snprintf.
+# define GTEST_SNPRINTF_ _snprintf
+#else
+# define GTEST_SNPRINTF_ snprintf
+#endif
+
+// The maximum number a BiggestInt can represent.  This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+    ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type.  It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+//   TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs.  Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+  // This prevents the user from using TypeWithSize<N> with incorrect
+  // values of N.
+  typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+  // unsigned int has size 4 in both gcc and MSVC.
+  //
+  // As base/basictypes.h doesn't compile on Windows, we cannot use
+  // uint32, uint64, and etc here.
+  typedef int Int;
+  typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+#if GTEST_OS_WINDOWS
+  typedef __int64 Int;
+  typedef unsigned __int64 UInt;
+#else
+  typedef long long Int;  // NOLINT
+  typedef unsigned long long UInt;  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+    GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+    GTEST_API_ extern ::std::string GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+    GTEST_API_ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+    GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+    GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
+
+// Thread annotations
+#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+#define GTEST_LOCK_EXCLUDED_(locks)
+
+// Parses 'str' for a 32-bit signed integer.  If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-string.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-string.h
new file mode 100644
index 0000000..97f1a7f
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-string.h
@@ -0,0 +1,167 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: wan at google.com (Zhanyong Wan), eefacm at gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test.  They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by <gtest/internal/gtest-internal.h>.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+# include <mem.h>
+#endif
+
+#include <string.h>
+#include <string>
+
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+namespace internal {
+
+// String - an abstract class holding static string utilities.
+class GTEST_API_ String {
+ public:
+  // Static utility methods
+
+  // Clones a 0-terminated C string, allocating memory using new.  The
+  // caller is responsible for deleting the return value using
+  // delete[].  Returns the cloned string, or NULL if the input is
+  // NULL.
+  //
+  // This is different from strdup() in string.h, which allocates
+  // memory using malloc().
+  static const char* CloneCString(const char* c_str);
+
+#if GTEST_OS_WINDOWS_MOBILE
+  // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+  // able to pass strings to Win32 APIs on CE we need to convert them
+  // to 'Unicode', UTF-16.
+
+  // Creates a UTF-16 wide string from the given ANSI string, allocating
+  // memory using new. The caller is responsible for deleting the return
+  // value using delete[]. Returns the wide string, or NULL if the
+  // input is NULL.
+  //
+  // The wide string is created using the ANSI codepage (CP_ACP) to
+  // match the behaviour of the ANSI versions of Win32 calls and the
+  // C runtime.
+  static LPCWSTR AnsiToUtf16(const char* c_str);
+
+  // Creates an ANSI string from the given wide string, allocating
+  // memory using new. The caller is responsible for deleting the return
+  // value using delete[]. Returns the ANSI string, or NULL if the
+  // input is NULL.
+  //
+  // The returned string is created using the ANSI codepage (CP_ACP) to
+  // match the behaviour of the ANSI versions of Win32 calls and the
+  // C runtime.
+  static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+  // Compares two C strings.  Returns true iff they have the same content.
+  //
+  // Unlike strcmp(), this function can handle NULL argument(s).  A
+  // NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool CStringEquals(const char* lhs, const char* rhs);
+
+  // Converts a wide C string to a String using the UTF-8 encoding.
+  // NULL will be converted to "(null)".  If an error occurred during
+  // the conversion, "(failed to convert from wide string)" is
+  // returned.
+  static std::string ShowWideCString(const wchar_t* wide_c_str);
+
+  // Compares two wide C strings.  Returns true iff they have the same
+  // content.
+  //
+  // Unlike wcscmp(), this function can handle NULL argument(s).  A
+  // NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+  // Compares two C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike strcasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool CaseInsensitiveCStringEquals(const char* lhs,
+                                           const char* rhs);
+
+  // Compares two wide C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike wcscasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL wide C string,
+  // including the empty string.
+  // NB: The implementations on different platforms slightly differ.
+  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+  // environment variable. On GNU platform this method uses wcscasecmp
+  // which compares according to LC_CTYPE category of the current locale.
+  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+  // current locale.
+  static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+                                               const wchar_t* rhs);
+
+  // Returns true iff the given string ends with the given suffix, ignoring
+  // case. Any string is considered to end with an empty suffix.
+  static bool EndsWithCaseInsensitive(
+      const std::string& str, const std::string& suffix);
+
+  // Formats an int value as "%02d".
+  static std::string FormatIntWidth2(int value);  // "%02d" for width == 2
+
+  // Formats an int value as "%X".
+  static std::string FormatHexInt(int value);
+
+  // Formats a byte as "%02X".
+  static std::string FormatByte(unsigned char value);
+
+ private:
+  String();  // Not meant to be instantiated.
+};  // class String
+
+// Gets the content of the stringstream's buffer as an std::string.  Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h
new file mode 100644
index 0000000..7b3dfc3
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h
@@ -0,0 +1,1012 @@
+// This file was GENERATED by command:
+//     pump.py gtest-tuple.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility>  // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined).  This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+    template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
+   private:
+#endif
+
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
+    void, void, void>
+#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
+    void, void, void>
+#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
+    void, void, void>
+#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
+    void, void, void>
+#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
+    void, void, void>
+#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
+    void, void, void>
+#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    void, void, void>
+#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    T##7, void, void>
+#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    T##7, T##8, void>
+#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+    T##7, T##8, T##9>
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+#define GTEST_0_TYPENAMES_(T)
+#define GTEST_1_TYPENAMES_(T) typename T##0
+#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
+#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
+#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3
+#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4
+#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5
+#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6
+#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
+#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6, \
+    typename T##7, typename T##8
+#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+    typename T##3, typename T##4, typename T##5, typename T##6, \
+    typename T##7, typename T##8, typename T##9
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior.  We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <typename T0 = void, typename T1 = void, typename T2 = void,
+    typename T3 = void, typename T4 = void, typename T5 = void,
+    typename T6 = void, typename T7 = void, typename T8 = void,
+    typename T9 = void>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; };  // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&.  This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; };  // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>.  kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 0, GTEST_10_TUPLE_(T) > {
+  typedef T0 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 1, GTEST_10_TUPLE_(T) > {
+  typedef T1 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 2, GTEST_10_TUPLE_(T) > {
+  typedef T2 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 3, GTEST_10_TUPLE_(T) > {
+  typedef T3 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 4, GTEST_10_TUPLE_(T) > {
+  typedef T4 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 5, GTEST_10_TUPLE_(T) > {
+  typedef T5 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 6, GTEST_10_TUPLE_(T) > {
+  typedef T6 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 7, GTEST_10_TUPLE_(T) > {
+  typedef T7 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 8, GTEST_10_TUPLE_(T) > {
+  typedef T8 type;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 9, GTEST_10_TUPLE_(T) > {
+  typedef T9 type;
+};
+
+}  // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+  tuple() {}
+  tuple(const tuple& /* t */)  {}
+  tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+class GTEST_1_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
+
+  tuple(const tuple& t) : f0_(t.f0_) {}
+
+  template <GTEST_1_TYPENAMES_(U)>
+  tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_1_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_1_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    return *this;
+  }
+
+  T0 f0_;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+class GTEST_2_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
+      f1_(f1) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
+
+  template <GTEST_2_TYPENAMES_(U)>
+  tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
+  template <typename U0, typename U1>
+  tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_2_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+  template <typename U0, typename U1>
+  tuple& operator=(const ::std::pair<U0, U1>& p) {
+    f0_ = p.first;
+    f1_ = p.second;
+    return *this;
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_2_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+class GTEST_3_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+  template <GTEST_3_TYPENAMES_(U)>
+  tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_3_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_3_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+class GTEST_4_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
+      f3_(f3) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
+
+  template <GTEST_4_TYPENAMES_(U)>
+  tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_4_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_4_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+class GTEST_5_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
+      GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_) {}
+
+  template <GTEST_5_TYPENAMES_(U)>
+  tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_5_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_5_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+class GTEST_6_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+      f5_(f5) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_) {}
+
+  template <GTEST_6_TYPENAMES_(U)>
+  tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_6_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_6_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+class GTEST_7_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
+      f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+  template <GTEST_7_TYPENAMES_(U)>
+  tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_7_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_7_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+class GTEST_8_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
+      GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+      f5_(f5), f6_(f6), f7_(f7) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+  template <GTEST_8_TYPENAMES_(U)>
+  tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_8_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_8_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    f7_ = t.f7_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+  T7 f7_;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+class GTEST_9_TUPLE_(T) {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+      GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+      f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+  template <GTEST_9_TYPENAMES_(U)>
+  tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_9_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_9_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    f7_ = t.f7_;
+    f8_ = t.f8_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+  T7 f7_;
+  T8 f8_;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+class tuple {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
+      f9_() {}
+
+  explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+      GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+      GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+      GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
+      f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
+
+  tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+      f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
+
+  template <GTEST_10_TYPENAMES_(U)>
+  tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+      f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
+      f9_(t.f9_) {}
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_10_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_10_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
+    f0_ = t.f0_;
+    f1_ = t.f1_;
+    f2_ = t.f2_;
+    f3_ = t.f3_;
+    f4_ = t.f4_;
+    f5_ = t.f5_;
+    f6_ = t.f6_;
+    f7_ = t.f7_;
+    f8_ = t.f8_;
+    f9_ = t.f9_;
+    return *this;
+  }
+
+  T0 f0_;
+  T1 f1_;
+  T2 f2_;
+  T3 f3_;
+  T4 f4_;
+  T5 f5_;
+  T6 f6_;
+  T7 f7_;
+  T8 f8_;
+  T9 f9_;
+};
+
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple().  And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+template <GTEST_1_TYPENAMES_(T)>
+inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
+  return GTEST_1_TUPLE_(T)(f0);
+}
+
+template <GTEST_2_TYPENAMES_(T)>
+inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
+  return GTEST_2_TUPLE_(T)(f0, f1);
+}
+
+template <GTEST_3_TYPENAMES_(T)>
+inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
+  return GTEST_3_TUPLE_(T)(f0, f1, f2);
+}
+
+template <GTEST_4_TYPENAMES_(T)>
+inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3) {
+  return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
+}
+
+template <GTEST_5_TYPENAMES_(T)>
+inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4) {
+  return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
+}
+
+template <GTEST_6_TYPENAMES_(T)>
+inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5) {
+  return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
+}
+
+template <GTEST_7_TYPENAMES_(T)>
+inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
+  return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
+}
+
+template <GTEST_8_TYPENAMES_(T)>
+inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
+  return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
+}
+
+template <GTEST_9_TYPENAMES_(T)>
+inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+    const T8& f8) {
+  return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
+}
+
+template <GTEST_10_TYPENAMES_(T)>
+inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+    const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+    const T8& f8, const T9& f9) {
+  return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
+}
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+template <GTEST_0_TYPENAMES_(T)>
+struct tuple_size<GTEST_0_TUPLE_(T) > {
+  static const int value = 0;
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+struct tuple_size<GTEST_1_TUPLE_(T) > {
+  static const int value = 1;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+struct tuple_size<GTEST_2_TUPLE_(T) > {
+  static const int value = 2;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+struct tuple_size<GTEST_3_TUPLE_(T) > {
+  static const int value = 3;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+struct tuple_size<GTEST_4_TUPLE_(T) > {
+  static const int value = 4;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+struct tuple_size<GTEST_5_TUPLE_(T) > {
+  static const int value = 5;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+struct tuple_size<GTEST_6_TUPLE_(T) > {
+  static const int value = 6;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+struct tuple_size<GTEST_7_TUPLE_(T) > {
+  static const int value = 7;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+struct tuple_size<GTEST_8_TUPLE_(T) > {
+  static const int value = 8;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+struct tuple_size<GTEST_9_TUPLE_(T) > {
+  static const int value = 9;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+struct tuple_size<GTEST_10_TUPLE_(T) > {
+  static const int value = 10;
+};
+
+template <int k, class Tuple>
+struct tuple_element {
+  typedef typename gtest_internal::TupleElement<
+      k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+template <>
+class Get<0> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+  Field(Tuple& t) { return t.f0_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+  ConstField(const Tuple& t) { return t.f0_; }
+};
+
+template <>
+class Get<1> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+  Field(Tuple& t) { return t.f1_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+  ConstField(const Tuple& t) { return t.f1_; }
+};
+
+template <>
+class Get<2> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+  Field(Tuple& t) { return t.f2_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+  ConstField(const Tuple& t) { return t.f2_; }
+};
+
+template <>
+class Get<3> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+  Field(Tuple& t) { return t.f3_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+  ConstField(const Tuple& t) { return t.f3_; }
+};
+
+template <>
+class Get<4> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+  Field(Tuple& t) { return t.f4_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+  ConstField(const Tuple& t) { return t.f4_; }
+};
+
+template <>
+class Get<5> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+  Field(Tuple& t) { return t.f5_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+  ConstField(const Tuple& t) { return t.f5_; }
+};
+
+template <>
+class Get<6> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+  Field(Tuple& t) { return t.f6_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+  ConstField(const Tuple& t) { return t.f6_; }
+};
+
+template <>
+class Get<7> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+  Field(Tuple& t) { return t.f7_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+  ConstField(const Tuple& t) { return t.f7_; }
+};
+
+template <>
+class Get<8> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+  Field(Tuple& t) { return t.f8_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+  ConstField(const Tuple& t) { return t.f8_; }
+};
+
+template <>
+class Get<9> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+  Field(Tuple& t) { return t.f9_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+  ConstField(const Tuple& t) { return t.f9_; }
+};
+
+}  // namespace gtest_internal
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(GTEST_10_TUPLE_(T)& t) {
+  return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k,  GTEST_10_TUPLE_(T)))
+get(const GTEST_10_TUPLE_(T)& t) {
+  return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+  template <class Tuple1, class Tuple2>
+  static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+    return true;
+  }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+  template <class Tuple1, class Tuple2>
+  static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+    return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+        ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+  }
+};
+
+}  // namespace gtest_internal
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator==(const GTEST_10_TUPLE_(T)& t,
+                       const GTEST_10_TUPLE_(U)& u) {
+  return gtest_internal::SameSizeTuplePrefixComparator<
+      tuple_size<GTEST_10_TUPLE_(T) >::value,
+      tuple_size<GTEST_10_TUPLE_(U) >::value>::Eq(t, u);
+}
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
+                       const GTEST_10_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+}  // namespace tr1
+}  // namespace std
+
+#undef GTEST_0_TUPLE_
+#undef GTEST_1_TUPLE_
+#undef GTEST_2_TUPLE_
+#undef GTEST_3_TUPLE_
+#undef GTEST_4_TUPLE_
+#undef GTEST_5_TUPLE_
+#undef GTEST_6_TUPLE_
+#undef GTEST_7_TUPLE_
+#undef GTEST_8_TUPLE_
+#undef GTEST_9_TUPLE_
+#undef GTEST_10_TUPLE_
+
+#undef GTEST_0_TYPENAMES_
+#undef GTEST_1_TYPENAMES_
+#undef GTEST_2_TYPENAMES_
+#undef GTEST_3_TYPENAMES_
+#undef GTEST_4_TYPENAMES_
+#undef GTEST_5_TYPENAMES_
+#undef GTEST_6_TYPENAMES_
+#undef GTEST_7_TYPENAMES_
+#undef GTEST_8_TYPENAMES_
+#undef GTEST_9_TYPENAMES_
+#undef GTEST_10_TYPENAMES_
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump b/lib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump
new file mode 100644
index 0000000..c7d9e03
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump
@@ -0,0 +1,339 @@
+$$ -*- mode: c++; -*-
+$var n = 10  $$ Maximum number of tuple fields we want to support.
+$$ This meta comment fixes auto-indentation in Emacs. }}
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility>  // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined).  This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+    template <GTEST_$(n)_TYPENAMES_(U)> friend class tuple; \
+   private:
+#endif
+
+
+$range i 0..n-1
+$range j 0..n
+$range k 1..n
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+
+$for k [[
+$range m 0..k-1
+$range m2 k..n-1
+#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]>
+
+]]
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+
+$for j [[
+$range m 0..j-1
+#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]]
+
+
+]]
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior.  We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <$for i, [[typename T$i = void]]>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; };  // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&.  This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; };  // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; };  // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>.  kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+
+$for i [[
+template <GTEST_$(n)_TYPENAMES_(T)>
+struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T) > {
+  typedef T$i type;
+};
+
+
+]]
+}  // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+  tuple() {}
+  tuple(const tuple& /* t */)  {}
+  tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+
+$for k [[
+$range m 0..k-1
+template <GTEST_$(k)_TYPENAMES_(T)>
+class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] {
+ public:
+  template <int k> friend class gtest_internal::Get;
+
+  tuple() : $for m, [[f$(m)_()]] {}
+
+  explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]]
+$for m, [[f$(m)_(f$m)]] {}
+
+  tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
+
+  template <GTEST_$(k)_TYPENAMES_(U)>
+  tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
+
+$if k == 2 [[
+  template <typename U0, typename U1>
+  tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+]]
+
+  tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+  template <GTEST_$(k)_TYPENAMES_(U)>
+  tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) {
+    return CopyFrom(t);
+  }
+
+$if k == 2 [[
+  template <typename U0, typename U1>
+  tuple& operator=(const ::std::pair<U0, U1>& p) {
+    f0_ = p.first;
+    f1_ = p.second;
+    return *this;
+  }
+
+]]
+
+  GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+  template <GTEST_$(k)_TYPENAMES_(U)>
+  tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) {
+
+$for m [[
+    f$(m)_ = t.f$(m)_;
+
+]]
+    return *this;
+  }
+
+
+$for m [[
+  T$m f$(m)_;
+
+]]
+};
+
+
+]]
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple().  And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+$for k [[
+$range m 0..k-1
+
+template <GTEST_$(k)_TYPENAMES_(T)>
+inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) {
+  return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]);
+}
+
+]]
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+
+$for j [[
+template <GTEST_$(j)_TYPENAMES_(T)>
+struct tuple_size<GTEST_$(j)_TUPLE_(T) > {
+  static const int value = $j;
+};
+
+
+]]
+template <int k, class Tuple>
+struct tuple_element {
+  typedef typename gtest_internal::TupleElement<
+      k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+
+$for i [[
+template <>
+class Get<$i> {
+ public:
+  template <class Tuple>
+  static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
+  Field(Tuple& t) { return t.f$(i)_; }  // NOLINT
+
+  template <class Tuple>
+  static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
+  ConstField(const Tuple& t) { return t.f$(i)_; }
+};
+
+
+]]
+}  // namespace gtest_internal
+
+template <int k, GTEST_$(n)_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
+get(GTEST_$(n)_TUPLE_(T)& t) {
+  return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_$(n)_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k,  GTEST_$(n)_TUPLE_(T)))
+get(const GTEST_$(n)_TUPLE_(T)& t) {
+  return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+  template <class Tuple1, class Tuple2>
+  static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+    return true;
+  }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+  template <class Tuple1, class Tuple2>
+  static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+    return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+        ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+  }
+};
+
+}  // namespace gtest_internal
+
+template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
+inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
+                       const GTEST_$(n)_TUPLE_(U)& u) {
+  return gtest_internal::SameSizeTuplePrefixComparator<
+      tuple_size<GTEST_$(n)_TUPLE_(T) >::value,
+      tuple_size<GTEST_$(n)_TUPLE_(U) >::value>::Eq(t, u);
+}
+
+template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t,
+                       const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+}  // namespace tr1
+}  // namespace std
+
+
+$for j [[
+#undef GTEST_$(j)_TUPLE_
+
+]]
+
+
+$for j [[
+#undef GTEST_$(j)_TYPENAMES_
+
+]]
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h b/lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h
new file mode 100644
index 0000000..e46f7cf
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h
@@ -0,0 +1,3331 @@
+// This file was GENERATED by command:
+//     pump.py gtest-type-util.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework at googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+// #ifdef __GNUC__ is too general here.  It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# if GTEST_HAS_CXXABI_H_
+#  include <cxxabi.h>
+# elif defined(__HP_aCC)
+#  include <acxx_demangle.h>
+# endif  // GTEST_HASH_CXXABI_H_
+
+namespace testing {
+namespace internal {
+
+// GetTypeName<T>() returns a human-readable name of type T.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+# if GTEST_HAS_RTTI
+
+  const char* const name = typeid(T).name();
+#  if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+  int status = 0;
+  // gcc's implementation of typeid(T).name() mangles the type name,
+  // so we have to demangle it.
+#   if GTEST_HAS_CXXABI_H_
+  using abi::__cxa_demangle;
+#   endif  // GTEST_HAS_CXXABI_H_
+  char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+  const std::string name_str(status == 0 ? readable_name : name);
+  free(readable_name);
+  return name_str;
+#  else
+  return name;
+#  endif  // GTEST_HAS_CXXABI_H_ || __HP_aCC
+
+# else
+
+  return "<type>";
+
+# endif  // GTEST_HAS_RTTI
+}
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type.  This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+  typedef bool type;
+};
+
+// A unique type used as the default value for the arguments of class
+// template Types.  This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists.  In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+  typedef T1 Head;
+  typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+  typedef T1 Head;
+  typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+  typedef T1 Head;
+  typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+  typedef T1 Head;
+  typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+  typedef T1 Head;
+  typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+struct Types6 {
+  typedef T1 Head;
+  typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+struct Types7 {
+  typedef T1 Head;
+  typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+struct Types8 {
+  typedef T1 Head;
+  typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+  typedef T1 Head;
+  typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+  typedef T1 Head;
+  typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+struct Types11 {
+  typedef T1 Head;
+  typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+struct Types12 {
+  typedef T1 Head;
+  typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+struct Types13 {
+  typedef T1 Head;
+  typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+  typedef T1 Head;
+  typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+  typedef T1 Head;
+  typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+struct Types16 {
+  typedef T1 Head;
+  typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+struct Types17 {
+  typedef T1 Head;
+  typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+struct Types18 {
+  typedef T1 Head;
+  typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+  typedef T1 Head;
+  typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+  typedef T1 Head;
+  typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+struct Types21 {
+  typedef T1 Head;
+  typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+struct Types22 {
+  typedef T1 Head;
+  typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+struct Types23 {
+  typedef T1 Head;
+  typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+  typedef T1 Head;
+  typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+  typedef T1 Head;
+  typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+struct Types26 {
+  typedef T1 Head;
+  typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+struct Types27 {
+  typedef T1 Head;
+  typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+struct Types28 {
+  typedef T1 Head;
+  typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+  typedef T1 Head;
+  typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+  typedef T1 Head;
+  typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+struct Types31 {
+  typedef T1 Head;
+  typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+struct Types32 {
+  typedef T1 Head;
+  typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+struct Types33 {
+  typedef T1 Head;
+  typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+  typedef T1 Head;
+  typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+  typedef T1 Head;
+  typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+struct Types36 {
+  typedef T1 Head;
+  typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+struct Types37 {
+  typedef T1 Head;
+  typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+struct Types38 {
+  typedef T1 Head;
+  typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+  typedef T1 Head;
+  typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+  typedef T1 Head;
+  typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+struct Types41 {
+  typedef T1 Head;
+  typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+struct Types42 {
+  typedef T1 Head;
+  typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+struct Types43 {
+  typedef T1 Head;
+  typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+  typedef T1 Head;
+  typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+  typedef T1 Head;
+  typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+struct Types46 {
+  typedef T1 Head;
+  typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+struct Types47 {
+  typedef T1 Head;
+  typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+struct Types48 {
+  typedef T1 Head;
+  typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+  typedef T1 Head;
+  typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+  typedef T1 Head;
+  typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+}  // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length.  Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+    typename T3 = internal::None, typename T4 = internal::None,
+    typename T5 = internal::None, typename T6 = internal::None,
+    typename T7 = internal::None, typename T8 = internal::None,
+    typename T9 = internal::None, typename T10 = internal::None,
+    typename T11 = internal::None, typename T12 = internal::None,
+    typename T13 = internal::None, typename T14 = internal::None,
+    typename T15 = internal::None, typename T16 = internal::None,
+    typename T17 = internal::None, typename T18 = internal::None,
+    typename T19 = internal::None, typename T20 = internal::None,
+    typename T21 = internal::None, typename T22 = internal::None,
+    typename T23 = internal::None, typename T24 = internal::None,
+    typename T25 = internal::None, typename T26 = internal::None,
+    typename T27 = internal::None, typename T28 = internal::None,
+    typename T29 = internal::None, typename T30 = internal::None,
+    typename T31 = internal::None, typename T32 = internal::None,
+    typename T33 = internal::None, typename T34 = internal::None,
+    typename T35 = internal::None, typename T36 = internal::None,
+    typename T37 = internal::None, typename T38 = internal::None,
+    typename T39 = internal::None, typename T40 = internal::None,
+    typename T41 = internal::None, typename T42 = internal::None,
+    typename T43 = internal::None, typename T44 = internal::None,
+    typename T45 = internal::None, typename T46 = internal::None,
+    typename T47 = internal::None, typename T48 = internal::None,
+    typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+  typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, internal::None, internal::None, internal::None> {
+  typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, T48, internal::None, internal::None> {
+  typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, T48, T49, internal::None> {
+  typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal {
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type.  TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>.  This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+  template <typename T>
+  struct Bind {
+    typedef Tmpl<T> type;
+  };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+  TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates.  This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists.  In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN).  Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4>
+struct Templates4 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7>
+struct Templates7 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10>
+struct Templates10 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13>
+struct Templates13 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16>
+struct Templates16 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19>
+struct Templates19 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22>
+struct Templates22 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25>
+struct Templates25 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28>
+struct Templates28 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31>
+struct Templates31 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34>
+struct Templates34 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37>
+struct Templates37 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40>
+struct Templates40 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43>
+struct Templates43 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46>
+struct Templates46 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49>
+struct Templates49 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length.  Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+    GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+    GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+    GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+    GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+    GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+    GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+    GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+    GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+    GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+    GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+    GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+    GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+    GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+    GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+    GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+    GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+    GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+    GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+    GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+    GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+    GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+    GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+    GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+    GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+  typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, NoneT, NoneT, NoneT> {
+  typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, T48, NoneT, NoneT> {
+  typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, T48, T49, NoneT> {
+  typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList {
+  typedef Types1<T> type;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49, T50> > {
+  typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h.pump b/lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h.pump
new file mode 100644
index 0000000..251fdf0
--- /dev/null
+++ b/lib/gtest-1.7.0/include/gtest/internal/gtest-type-util.h.pump
@@ -0,0 +1,297 @@
+$$ -*- mode: c++; -*-
+$var n = 50  $$ Maximum length of type lists we want to support.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently we support at most $n types in a list, and at most $n
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework at googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include "gtest/internal/gtest-port.h"
+
+// #ifdef __GNUC__ is too general here.  It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# if GTEST_HAS_CXXABI_H_
+#  include <cxxabi.h>
+# elif defined(__HP_aCC)
+#  include <acxx_demangle.h>
+# endif  // GTEST_HASH_CXXABI_H_
+
+namespace testing {
+namespace internal {
+
+// GetTypeName<T>() returns a human-readable name of type T.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+# if GTEST_HAS_RTTI
+
+  const char* const name = typeid(T).name();
+#  if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+  int status = 0;
+  // gcc's implementation of typeid(T).name() mangles the type name,
+  // so we have to demangle it.
+#   if GTEST_HAS_CXXABI_H_
+  using abi::__cxa_demangle;
+#   endif  // GTEST_HAS_CXXABI_H_
+  char* const readable_name = __cxa_demangle(name, 0, 0, &status);
+  const std::string name_str(status == 0 ? readable_name : name);
+  free(readable_name);
+  return name_str;
+#  else
+  return name;
+#  endif  // GTEST_HAS_CXXABI_H_ || __HP_aCC
+
+# else
+
+  return "<type>";
+
+# endif  // GTEST_HAS_RTTI
+}
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type.  This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+  typedef bool type;
+};
+
+// A unique type used as the default value for the arguments of class
+// template Types.  This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists.  In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+  typedef T1 Head;
+  typedef Types0 Tail;
+};
+
+$range i 2..n
+
+$for i [[
+$range j 1..i
+$range k 2..i
+template <$for j, [[typename T$j]]>
+struct Types$i {
+  typedef T1 Head;
+  typedef Types$(i-1)<$for k, [[T$k]]> Tail;
+};
+
+
+]]
+
+}  // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length.  Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Types template.
+
+$range i 1..n
+template <$for i, [[typename T$i = internal::None]]>
+struct Types {
+  typedef internal::Types$n<$for i, [[T$i]]> type;
+};
+
+template <>
+struct Types<$for i, [[internal::None]]> {
+  typedef internal::Types0 type;
+};
+
+$range i 1..n-1
+$for i [[
+$range j 1..i
+$range k i+1..n
+template <$for j, [[typename T$j]]>
+struct Types<$for j, [[T$j]]$for k[[, internal::None]]> {
+  typedef internal::Types$i<$for j, [[T$j]]> type;
+};
+
+]]
+
+namespace internal {
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type.  TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>.  This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+  template <typename T>
+  struct Bind {
+    typedef Tmpl<T> type;
+  };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+  TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates.  This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists.  In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN).  Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates0 Tail;
+};
+
+$range i 2..n
+
+$for i [[
+$range j 1..i
+$range k 2..i
+template <$for j, [[GTEST_TEMPLATE_ T$j]]>
+struct Templates$i {
+  typedef TemplateSel<T1> Head;
+  typedef Templates$(i-1)<$for k, [[T$k]]> Tail;
+};
+
+
+]]
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length.  Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Templates template.
+
+$range i 1..n
+template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]>
+struct Templates {
+  typedef Templates$n<$for i, [[T$i]]> type;
+};
+
+template <>
+struct Templates<$for i, [[NoneT]]> {
+  typedef Templates0 type;
+};
+
+$range i 1..n-1
+$for i [[
+$range j 1..i
+$range k i+1..n
+template <$for j, [[GTEST_TEMPLATE_ T$j]]>
+struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
+  typedef Templates$i<$for j, [[T$j]]> type;
+};
+
+]]
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList {
+  typedef Types1<T> type;
+};
+
+
+$range i 1..n
+template <$for i, [[typename T$i]]>
+struct TypeList<Types<$for i, [[T$i]]> > {
+  typedef typename Types<$for i, [[T$i]]>::type type;
+};
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/lib/gtest-1.7.0/src/gtest-all.cc b/lib/gtest-1.7.0/src/gtest-all.cc
new file mode 100644
index 0000000..0a9cee5
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-all.cc
@@ -0,0 +1,48 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: mheule at google.com (Markus Heule)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#include "gtest/gtest.h"
+
+// The following lines pull in the real gtest *.cc files.
+#include "src/gtest.cc"
+#include "src/gtest-death-test.cc"
+#include "src/gtest-filepath.cc"
+#include "src/gtest-port.cc"
+#include "src/gtest-printers.cc"
+#include "src/gtest-test-part.cc"
+#include "src/gtest-typed-test.cc"
diff --git a/lib/gtest-1.7.0/src/gtest-death-test.cc b/lib/gtest-1.7.0/src/gtest-death-test.cc
new file mode 100644
index 0000000..a6023fc
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-death-test.cc
@@ -0,0 +1,1344 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan), vladl at google.com (Vlad Losev)
+//
+// This file implements death tests.
+
+#include "gtest/gtest-death-test.h"
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_OS_MAC
+#  include <crt_externs.h>
+# endif  // GTEST_OS_MAC
+
+# include <errno.h>
+# include <fcntl.h>
+# include <limits.h>
+
+# if GTEST_OS_LINUX
+#  include <signal.h>
+# endif  // GTEST_OS_LINUX
+
+# include <stdarg.h>
+
+# if GTEST_OS_WINDOWS
+#  include <windows.h>
+# else
+#  include <sys/mman.h>
+#  include <sys/wait.h>
+# endif  // GTEST_OS_WINDOWS
+
+# if GTEST_OS_QNX
+#  include <spawn.h>
+# endif  // GTEST_OS_QNX
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-string.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+    death_test_style,
+    internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+    "Indicates how to run a death test in a forked child process: "
+    "\"threadsafe\" (child process re-executes the test binary "
+    "from the beginning, running only the specific death test) or "
+    "\"fast\" (child process runs the death test immediately "
+    "after forking).");
+
+GTEST_DEFINE_bool_(
+    death_test_use_fork,
+    internal::BoolFromGTestEnv("death_test_use_fork", false),
+    "Instructs to use fork()/_exit() instead of clone() in death tests. "
+    "Ignored and always uses fork() on POSIX systems where clone() is not "
+    "implemented. Useful when running under valgrind or similar tools if "
+    "those do not support clone(). Valgrind 3.3.1 will just fail if "
+    "it sees an unsupported combination of clone() flags. "
+    "It is not recommended to use this flag w/o valgrind though it will "
+    "work in 99% of the cases. Once valgrind is fixed, this flag will "
+    "most likely be removed.");
+
+namespace internal {
+GTEST_DEFINE_string_(
+    internal_run_death_test, "",
+    "Indicates the file, line number, temporal index of "
+    "the single death test to run, and a file descriptor to "
+    "which a success code may be sent, all separated by "
+    "the '|' characters.  This flag is specified if and only if the current "
+    "process is a sub-process launched for running a thread-safe "
+    "death test.  FOR INTERNAL USE ONLY.");
+}  // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Valid only for fast death tests. Indicates the code is running in the
+// child process of a fast style death test.
+static bool g_in_fast_death_test_child = false;
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process.  Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests.  IMPORTANT: This is an internal utility.  Using it may break the
+// implementation of death tests.  User code MUST NOT use it.
+bool InDeathTestChild() {
+# if GTEST_OS_WINDOWS
+
+  // On Windows, death tests are thread-safe regardless of the value of the
+  // death_test_style flag.
+  return !GTEST_FLAG(internal_run_death_test).empty();
+
+# else
+
+  if (GTEST_FLAG(death_test_style) == "threadsafe")
+    return !GTEST_FLAG(internal_run_death_test).empty();
+  else
+    return g_in_fast_death_test_child;
+#endif
+}
+
+}  // namespace internal
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+# if GTEST_OS_WINDOWS
+
+  return exit_status == exit_code_;
+
+# else
+
+  return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+
+# endif  // GTEST_OS_WINDOWS
+}
+
+# if !GTEST_OS_WINDOWS
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+  return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+# endif  // !GTEST_OS_WINDOWS
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static std::string ExitSummary(int exit_code) {
+  Message m;
+
+# if GTEST_OS_WINDOWS
+
+  m << "Exited with exit status " << exit_code;
+
+# else
+
+  if (WIFEXITED(exit_code)) {
+    m << "Exited with exit status " << WEXITSTATUS(exit_code);
+  } else if (WIFSIGNALED(exit_code)) {
+    m << "Terminated by signal " << WTERMSIG(exit_code);
+  }
+#  ifdef WCOREDUMP
+  if (WCOREDUMP(exit_code)) {
+    m << " (core dumped)";
+  }
+#  endif
+# endif  // GTEST_OS_WINDOWS
+
+  return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+  return !ExitedWithCode(0)(exit_status);
+}
+
+# if !GTEST_OS_WINDOWS
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement.  It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static std::string DeathTestThreadWarning(size_t thread_count) {
+  Message msg;
+  msg << "Death tests use fork(), which is unsafe particularly"
+      << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+  if (thread_count == 0)
+    msg << "couldn't detect the number of threads.";
+  else
+    msg << "detected " << thread_count << " threads.";
+  return msg.GetString();
+}
+# endif  // !GTEST_OS_WINDOWS
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestThrew = 'T';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test can
+// conclude.  DIED means that the process died while executing the test
+// code; LIVED means that process lived beyond the end of the test code;
+// RETURNED means that the test statement attempted to execute a return
+// statement, which is not allowed; THREW means that the test statement
+// returned control by throwing an exception.  IN_PROGRESS means the test
+// has not yet concluded.
+// TODO(vladl at google.com): Unify names and possibly values for
+// AbortReason, DeathTestOutcome, and flag characters above.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process.  Otherwise, the
+// message is simply printed to stderr.  In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const std::string& message) {
+  // On a POSIX system, this function may be called from a threadsafe-style
+  // death test child process, which operates on a very small stack.  Use
+  // the heap for any additional non-minuscule memory requirements.
+  const InternalRunDeathTestFlag* const flag =
+      GetUnitTestImpl()->internal_run_death_test_flag();
+  if (flag != NULL) {
+    FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+    fputc(kDeathTestInternalError, parent);
+    fprintf(parent, "%s", message.c_str());
+    fflush(parent);
+    _exit(1);
+  } else {
+    fprintf(stderr, "%s", message.c_str());
+    fflush(stderr);
+    posix::Abort();
+  }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+# define GTEST_DEATH_TEST_CHECK_(expression) \
+  do { \
+    if (!::testing::internal::IsTrue(expression)) { \
+      DeathTestAbort( \
+          ::std::string("CHECK failed: File ") + __FILE__ +  ", line " \
+          + ::testing::internal::StreamableToString(__LINE__) + ": " \
+          + #expression); \
+    } \
+  } while (::testing::internal::AlwaysFalse())
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again.  The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR.  If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+  do { \
+    int gtest_retval; \
+    do { \
+      gtest_retval = (expression); \
+    } while (gtest_retval == -1 && errno == EINTR); \
+    if (gtest_retval == -1) { \
+      DeathTestAbort( \
+          ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
+          + ::testing::internal::StreamableToString(__LINE__) + ": " \
+          + #expression + " != -1"); \
+    } \
+  } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+std::string GetLastErrnoDescription() {
+    return errno == 0 ? "" : posix::StrError(errno);
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+  Message error;
+  char buffer[256];
+  int num_read;
+
+  do {
+    while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+      buffer[num_read] = '\0';
+      error << buffer;
+    }
+  } while (num_read == -1 && errno == EINTR);
+
+  if (num_read == 0) {
+    GTEST_LOG_(FATAL) << error.GetString();
+  } else {
+    const int last_error = errno;
+    GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+                      << GetLastErrnoDescription() << " [" << last_error << "]";
+  }
+}
+
+// Death test constructor.  Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+  TestInfo* const info = GetUnitTestImpl()->current_test_info();
+  if (info == NULL) {
+    DeathTestAbort("Cannot run a death test outside of a TEST or "
+                   "TEST_F construct");
+  }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+                       const char* file, int line, DeathTest** test) {
+  return GetUnitTestImpl()->death_test_factory()->Create(
+      statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+  return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const std::string& message) {
+  last_death_test_message_ = message;
+}
+
+std::string DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+  DeathTestImpl(const char* a_statement, const RE* a_regex)
+      : statement_(a_statement),
+        regex_(a_regex),
+        spawned_(false),
+        status_(-1),
+        outcome_(IN_PROGRESS),
+        read_fd_(-1),
+        write_fd_(-1) {}
+
+  // read_fd_ is expected to be closed and cleared by a derived class.
+  ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+  void Abort(AbortReason reason);
+  virtual bool Passed(bool status_ok);
+
+  const char* statement() const { return statement_; }
+  const RE* regex() const { return regex_; }
+  bool spawned() const { return spawned_; }
+  void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
+  int status() const { return status_; }
+  void set_status(int a_status) { status_ = a_status; }
+  DeathTestOutcome outcome() const { return outcome_; }
+  void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+  int read_fd() const { return read_fd_; }
+  void set_read_fd(int fd) { read_fd_ = fd; }
+  int write_fd() const { return write_fd_; }
+  void set_write_fd(int fd) { write_fd_ = fd; }
+
+  // Called in the parent process only. Reads the result code of the death
+  // test child process via a pipe, interprets it to set the outcome_
+  // member, and closes read_fd_.  Outputs diagnostics and terminates in
+  // case of unexpected codes.
+  void ReadAndInterpretStatusByte();
+
+ private:
+  // The textual content of the code this object is testing.  This class
+  // doesn't own this string and should not attempt to delete it.
+  const char* const statement_;
+  // The regular expression which test output must match.  DeathTestImpl
+  // doesn't own this object and should not attempt to delete it.
+  const RE* const regex_;
+  // True if the death test child process has been successfully spawned.
+  bool spawned_;
+  // The exit status of the child process.
+  int status_;
+  // How the death test concluded.
+  DeathTestOutcome outcome_;
+  // Descriptor to the read end of the pipe to the child process.  It is
+  // always -1 in the child process.  The child keeps its write end of the
+  // pipe in write_fd_.
+  int read_fd_;
+  // Descriptor to the child's write end of the pipe to the parent process.
+  // It is always -1 in the parent process.  The parent keeps its end of the
+  // pipe in read_fd_.
+  int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_.  Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+  char flag;
+  int bytes_read;
+
+  // The read() here blocks until data is available (signifying the
+  // failure of the death test) or until the pipe is closed (signifying
+  // its success), so it's okay to call this in the parent before
+  // the child process has exited.
+  do {
+    bytes_read = posix::Read(read_fd(), &flag, 1);
+  } while (bytes_read == -1 && errno == EINTR);
+
+  if (bytes_read == 0) {
+    set_outcome(DIED);
+  } else if (bytes_read == 1) {
+    switch (flag) {
+      case kDeathTestReturned:
+        set_outcome(RETURNED);
+        break;
+      case kDeathTestThrew:
+        set_outcome(THREW);
+        break;
+      case kDeathTestLived:
+        set_outcome(LIVED);
+        break;
+      case kDeathTestInternalError:
+        FailFromInternalError(read_fd());  // Does not return.
+        break;
+      default:
+        GTEST_LOG_(FATAL) << "Death test child process reported "
+                          << "unexpected status byte ("
+                          << static_cast<unsigned int>(flag) << ")";
+    }
+  } else {
+    GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+                      << GetLastErrnoDescription();
+  }
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+  set_read_fd(-1);
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+  // The parent process considers the death test to be a failure if
+  // it finds any data in our pipe.  So, here we write a single flag byte
+  // to the pipe, then exit.
+  const char status_ch =
+      reason == TEST_DID_NOT_DIE ? kDeathTestLived :
+      reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;
+
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+  // We are leaking the descriptor here because on some platforms (i.e.,
+  // when built as Windows DLL), destructors of global objects will still
+  // run after calling _exit(). On such systems, write_fd_ will be
+  // indirectly closed from the destructor of UnitTestImpl, causing double
+  // close if it is also closed here. On debug configurations, double close
+  // may assert. As there are no in-process buffers to flush here, we are
+  // relying on the OS to close the descriptor after the process terminates
+  // when the destructors are not run.
+  _exit(1);  // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Returns an indented copy of stderr output for a death test.
+// This makes distinguishing death test output lines from regular log lines
+// much easier.
+static ::std::string FormatDeathTestOutput(const ::std::string& output) {
+  ::std::string ret;
+  for (size_t at = 0; ; ) {
+    const size_t line_end = output.find('\n', at);
+    ret += "[  DEATH   ] ";
+    if (line_end == ::std::string::npos) {
+      ret += output.substr(at);
+      break;
+    }
+    ret += output.substr(at, line_end + 1 - at);
+    at = line_end + 1;
+  }
+  return ret;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+//   outcome:  An enumeration describing how the death test
+//             concluded: DIED, LIVED, THREW, or RETURNED.  The death test
+//             fails in the latter three cases.
+//   status:   The exit status of the child process. On *nix, it is in the
+//             in the format specified by wait(2). On Windows, this is the
+//             value supplied to the ExitProcess() API or a numeric code
+//             of the exception that terminated the program.
+//   regex:    A regular expression object to be applied to
+//             the test's captured standard error output; the death test
+//             fails if it does not match.
+//
+// Argument:
+//   status_ok: true if exit_status is acceptable in the context of
+//              this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met.  Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+  if (!spawned())
+    return false;
+
+  const std::string error_message = GetCapturedStderr();
+
+  bool success = false;
+  Message buffer;
+
+  buffer << "Death test: " << statement() << "\n";
+  switch (outcome()) {
+    case LIVED:
+      buffer << "    Result: failed to die.\n"
+             << " Error msg:\n" << FormatDeathTestOutput(error_message);
+      break;
+    case THREW:
+      buffer << "    Result: threw an exception.\n"
+             << " Error msg:\n" << FormatDeathTestOutput(error_message);
+      break;
+    case RETURNED:
+      buffer << "    Result: illegal return in test statement.\n"
+             << " Error msg:\n" << FormatDeathTestOutput(error_message);
+      break;
+    case DIED:
+      if (status_ok) {
+        const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
+        if (matched) {
+          success = true;
+        } else {
+          buffer << "    Result: died but not with expected error.\n"
+                 << "  Expected: " << regex()->pattern() << "\n"
+                 << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+        }
+      } else {
+        buffer << "    Result: died but not with expected exit code:\n"
+               << "            " << ExitSummary(status()) << "\n"
+               << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+      }
+      break;
+    case IN_PROGRESS:
+    default:
+      GTEST_LOG_(FATAL)
+          << "DeathTest::Passed somehow called before conclusion of test";
+  }
+
+  DeathTest::set_last_death_test_message(buffer.GetString());
+  return success;
+}
+
+# if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes:  Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+//    ends of it.
+// 2. The parent starts the child and provides it with the information
+//    necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+//    using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+//    this is done before step 3, the object's reference count goes down to
+//    0 and it is destroyed, preventing the child from acquiring it. The
+//    parent now has to release it, or read operations on the read end of
+//    the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+//    any possible error messages) from the pipe, and its stderr and then
+//    determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+  WindowsDeathTest(const char* a_statement,
+                   const RE* a_regex,
+                   const char* file,
+                   int line)
+      : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+
+  // All of these virtual functions are inherited from DeathTest.
+  virtual int Wait();
+  virtual TestRole AssumeRole();
+
+ private:
+  // The name of the file in which the death test is located.
+  const char* const file_;
+  // The line number on which the death test is located.
+  const int line_;
+  // Handle to the write end of the pipe to the child process.
+  AutoHandle write_handle_;
+  // Child process handle.
+  AutoHandle child_handle_;
+  // Event the child process uses to signal the parent that it has
+  // acquired the handle to the write end of the pipe. After seeing this
+  // event the parent can release its own handles to make sure its
+  // ReadFile() calls return when the child terminates.
+  AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists.  As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait() {
+  if (!spawned())
+    return 0;
+
+  // Wait until the child either signals that it has acquired the write end
+  // of the pipe or it dies.
+  const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+  switch (::WaitForMultipleObjects(2,
+                                   wait_handles,
+                                   FALSE,  // Waits for any of the handles.
+                                   INFINITE)) {
+    case WAIT_OBJECT_0:
+    case WAIT_OBJECT_0 + 1:
+      break;
+    default:
+      GTEST_DEATH_TEST_CHECK_(false);  // Should not get here.
+  }
+
+  // The child has acquired the write end of the pipe or exited.
+  // We release the handle on our side and continue.
+  write_handle_.Reset();
+  event_handle_.Reset();
+
+  ReadAndInterpretStatusByte();
+
+  // Waits for the child process to exit if it haven't already. This
+  // returns immediately if the child has already exited, regardless of
+  // whether previous calls to WaitForMultipleObjects synchronized on this
+  // handle or not.
+  GTEST_DEATH_TEST_CHECK_(
+      WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+                                             INFINITE));
+  DWORD status_code;
+  GTEST_DEATH_TEST_CHECK_(
+      ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE);
+  child_handle_.Reset();
+  set_status(static_cast<int>(status_code));
+  return status();
+}
+
+// The AssumeRole process for a Windows death test.  It creates a child
+// process with the same executable as the current process to run the
+// death test.  The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole() {
+  const UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const TestInfo* const info = impl->current_test_info();
+  const int death_test_index = info->result()->death_test_count();
+
+  if (flag != NULL) {
+    // ParseInternalRunDeathTestFlag() has performed all the necessary
+    // processing.
+    set_write_fd(flag->write_fd());
+    return EXECUTE_TEST;
+  }
+
+  // WindowsDeathTest uses an anonymous pipe to communicate results of
+  // a death test.
+  SECURITY_ATTRIBUTES handles_are_inheritable = {
+    sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+  HANDLE read_handle, write_handle;
+  GTEST_DEATH_TEST_CHECK_(
+      ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+                   0)  // Default buffer size.
+      != FALSE);
+  set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+                                O_RDONLY));
+  write_handle_.Reset(write_handle);
+  event_handle_.Reset(::CreateEvent(
+      &handles_are_inheritable,
+      TRUE,    // The event will automatically reset to non-signaled state.
+      FALSE,   // The initial state is non-signalled.
+      NULL));  // The even is unnamed.
+  GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
+  const std::string filter_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
+      info->test_case_name() + "." + info->name();
+  const std::string internal_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
+      "=" + file_ + "|" + StreamableToString(line_) + "|" +
+      StreamableToString(death_test_index) + "|" +
+      StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
+      // size_t has the same width as pointers on both 32-bit and 64-bit
+      // Windows platforms.
+      // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+      "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
+      "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
+
+  char executable_path[_MAX_PATH + 1];  // NOLINT
+  GTEST_DEATH_TEST_CHECK_(
+      _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
+                                            executable_path,
+                                            _MAX_PATH));
+
+  std::string command_line =
+      std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
+      internal_flag + "\"";
+
+  DeathTest::set_last_death_test_message("");
+
+  CaptureStderr();
+  // Flush the log buffers since the log streams are shared with the child.
+  FlushInfoLog();
+
+  // The child process will share the standard handles with the parent.
+  STARTUPINFOA startup_info;
+  memset(&startup_info, 0, sizeof(STARTUPINFO));
+  startup_info.dwFlags = STARTF_USESTDHANDLES;
+  startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+  startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+  startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+  PROCESS_INFORMATION process_info;
+  GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
+      executable_path,
+      const_cast<char*>(command_line.c_str()),
+      NULL,   // Retuned process handle is not inheritable.
+      NULL,   // Retuned thread handle is not inheritable.
+      TRUE,   // Child inherits all inheritable handles (for write_handle_).
+      0x0,    // Default creation flags.
+      NULL,   // Inherit the parent's environment.
+      UnitTest::GetInstance()->original_working_dir(),
+      &startup_info,
+      &process_info) != FALSE);
+  child_handle_.Reset(process_info.hProcess);
+  ::CloseHandle(process_info.hThread);
+  set_spawned(true);
+  return OVERSEE_TEST;
+}
+# else  // We are not on Windows.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface.  Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl {
+ public:
+  ForkingDeathTest(const char* statement, const RE* regex);
+
+  // All of these virtual functions are inherited from DeathTest.
+  virtual int Wait();
+
+ protected:
+  void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+  // PID of child process during death test; 0 in the child process itself.
+  pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
+    : DeathTestImpl(a_statement, a_regex),
+      child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists.  As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+  if (!spawned())
+    return 0;
+
+  ReadAndInterpretStatusByte();
+
+  int status_value;
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+  set_status(status_value);
+  return status_value;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+  NoExecDeathTest(const char* a_statement, const RE* a_regex) :
+      ForkingDeathTest(a_statement, a_regex) { }
+  virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test.  It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+  const size_t thread_count = GetThreadCount();
+  if (thread_count != 1) {
+    GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
+  }
+
+  int pipe_fd[2];
+  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+  DeathTest::set_last_death_test_message("");
+  CaptureStderr();
+  // When we fork the process below, the log file buffers are copied, but the
+  // file descriptors are shared.  We flush all log files here so that closing
+  // the file descriptors in the child process doesn't throw off the
+  // synchronization between descriptors and buffers in the parent process.
+  // This is as close to the fork as possible to avoid a race condition in case
+  // there are multiple threads running before the death test, and another
+  // thread writes to the log file.
+  FlushInfoLog();
+
+  const pid_t child_pid = fork();
+  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+  set_child_pid(child_pid);
+  if (child_pid == 0) {
+    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+    set_write_fd(pipe_fd[1]);
+    // Redirects all logging to stderr in the child process to prevent
+    // concurrent writes to the log files.  We capture stderr in the parent
+    // process and append the child process' output to a log.
+    LogToStderr();
+    // Event forwarding to the listeners of event listener API mush be shut
+    // down in death test subprocesses.
+    GetUnitTestImpl()->listeners()->SuppressEventForwarding();
+    g_in_fast_death_test_child = true;
+    return EXECUTE_TEST;
+  } else {
+    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+    set_read_fd(pipe_fd[0]);
+    set_spawned(true);
+    return OVERSEE_TEST;
+  }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+  ExecDeathTest(const char* a_statement, const RE* a_regex,
+                const char* file, int line) :
+      ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
+  virtual TestRole AssumeRole();
+ private:
+  static ::std::vector<testing::internal::string>
+  GetArgvsForDeathTestChildProcess() {
+    ::std::vector<testing::internal::string> args = GetInjectableArgvs();
+    return args;
+  }
+  // The name of the file in which the death test is located.
+  const char* const file_;
+  // The line number on which the death test is located.
+  const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+  Arguments() {
+    args_.push_back(NULL);
+  }
+
+  ~Arguments() {
+    for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+         ++i) {
+      free(*i);
+    }
+  }
+  void AddArgument(const char* argument) {
+    args_.insert(args_.end() - 1, posix::StrDup(argument));
+  }
+
+  template <typename Str>
+  void AddArguments(const ::std::vector<Str>& arguments) {
+    for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+         i != arguments.end();
+         ++i) {
+      args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+    }
+  }
+  char* const* Argv() {
+    return &args_[0];
+  }
+
+ private:
+  std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+  char* const* argv;  // Command-line arguments for the child's call to exec
+  int close_fd;       // File descriptor to close; the read end of a pipe
+};
+
+#  if GTEST_OS_MAC
+inline char** GetEnviron() {
+  // When Google Test is built as a framework on MacOS X, the environ variable
+  // is unavailable. Apple's documentation (man environ) recommends using
+  // _NSGetEnviron() instead.
+  return *_NSGetEnviron();
+}
+#  else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#  endif  // GTEST_OS_MAC
+
+#  if !GTEST_OS_QNX
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+  ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+  // We need to execute the test program in the same environment where
+  // it was originally invoked.  Therefore we change to the original
+  // working directory first.
+  const char* const original_dir =
+      UnitTest::GetInstance()->original_working_dir();
+  // We can safely call chdir() as it's a direct system call.
+  if (chdir(original_dir) != 0) {
+    DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+                   GetLastErrnoDescription());
+    return EXIT_FAILURE;
+  }
+
+  // We can safely call execve() as it's a direct system call.  We
+  // cannot use execvp() as it's a libc function and thus potentially
+  // unsafe.  Since execve() doesn't search the PATH, the user must
+  // invoke the test program via a valid path that contains at least
+  // one path separator.
+  execve(args->argv[0], args->argv, GetEnviron());
+  DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
+                 original_dir + " failed: " +
+                 GetLastErrnoDescription());
+  return EXIT_FAILURE;
+}
+#  endif  // !GTEST_OS_QNX
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+//
+// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
+// StackLowerThanAddress into StackGrowsDown, which then doesn't give
+// correct answer.
+void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
+void StackLowerThanAddress(const void* ptr, bool* result) {
+  int dummy;
+  *result = (&dummy < ptr);
+}
+
+bool StackGrowsDown() {
+  int dummy;
+  bool result;
+  StackLowerThanAddress(&dummy, &result);
+  return result;
+}
+
+// Spawns a child process with the same executable as the current process in
+// a thread-safe manner and instructs it to run the death test.  The
+// implementation uses fork(2) + exec.  On systems where clone(2) is
+// available, it is used instead, being slightly more thread-safe.  On QNX,
+// fork supports only single-threaded environments, so this function uses
+// spawn(2) there instead.  The function dies with an error message if
+// anything goes wrong.
+static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
+  ExecDeathTestArgs args = { argv, close_fd };
+  pid_t child_pid = -1;
+
+#  if GTEST_OS_QNX
+  // Obtains the current directory and sets it to be closed in the child
+  // process.
+  const int cwd_fd = open(".", O_RDONLY);
+  GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
+  // We need to execute the test program in the same environment where
+  // it was originally invoked.  Therefore we change to the original
+  // working directory first.
+  const char* const original_dir =
+      UnitTest::GetInstance()->original_working_dir();
+  // We can safely call chdir() as it's a direct system call.
+  if (chdir(original_dir) != 0) {
+    DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+                   GetLastErrnoDescription());
+    return EXIT_FAILURE;
+  }
+
+  int fd_flags;
+  // Set close_fd to be closed after spawn.
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
+                                        fd_flags | FD_CLOEXEC));
+  struct inheritance inherit = {0};
+  // spawn is a system call.
+  child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
+  // Restores the current working directory.
+  GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
+
+#  else   // GTEST_OS_QNX
+#   if GTEST_OS_LINUX
+  // When a SIGPROF signal is received while fork() or clone() are executing,
+  // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
+  // it after the call to fork()/clone() is complete.
+  struct sigaction saved_sigprof_action;
+  struct sigaction ignore_sigprof_action;
+  memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
+  sigemptyset(&ignore_sigprof_action.sa_mask);
+  ignore_sigprof_action.sa_handler = SIG_IGN;
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
+      SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
+#   endif  // GTEST_OS_LINUX
+
+#   if GTEST_HAS_CLONE
+  const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+  if (!use_fork) {
+    static const bool stack_grows_down = StackGrowsDown();
+    const size_t stack_size = getpagesize();
+    // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+    void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+                             MAP_ANON | MAP_PRIVATE, -1, 0);
+    GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+
+    // Maximum stack alignment in bytes:  For a downward-growing stack, this
+    // amount is subtracted from size of the stack space to get an address
+    // that is within the stack space and is aligned on all systems we care
+    // about.  As far as I know there is no ABI with stack alignment greater
+    // than 64.  We assume stack and stack_size already have alignment of
+    // kMaxStackAlignment.
+    const size_t kMaxStackAlignment = 64;
+    void* const stack_top =
+        static_cast<char*>(stack) +
+            (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
+    GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
+        reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
+
+    child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+    GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+  }
+#   else
+  const bool use_fork = true;
+#   endif  // GTEST_HAS_CLONE
+
+  if (use_fork && (child_pid = fork()) == 0) {
+      ExecDeathTestChildMain(&args);
+      _exit(0);
+  }
+#  endif  // GTEST_OS_QNX
+#  if GTEST_OS_LINUX
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(
+      sigaction(SIGPROF, &saved_sigprof_action, NULL));
+#  endif  // GTEST_OS_LINUX
+
+  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+  return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test.  It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+  const UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const TestInfo* const info = impl->current_test_info();
+  const int death_test_index = info->result()->death_test_count();
+
+  if (flag != NULL) {
+    set_write_fd(flag->write_fd());
+    return EXECUTE_TEST;
+  }
+
+  int pipe_fd[2];
+  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+  // Clear the close-on-exec flag on the write end of the pipe, lest
+  // it be closed when the child process does an exec:
+  GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+  const std::string filter_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
+      + info->test_case_name() + "." + info->name();
+  const std::string internal_flag =
+      std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+      + file_ + "|" + StreamableToString(line_) + "|"
+      + StreamableToString(death_test_index) + "|"
+      + StreamableToString(pipe_fd[1]);
+  Arguments args;
+  args.AddArguments(GetArgvsForDeathTestChildProcess());
+  args.AddArgument(filter_flag.c_str());
+  args.AddArgument(internal_flag.c_str());
+
+  DeathTest::set_last_death_test_message("");
+
+  CaptureStderr();
+  // See the comment in NoExecDeathTest::AssumeRole for why the next line
+  // is necessary.
+  FlushInfoLog();
+
+  const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+  set_child_pid(child_pid);
+  set_read_fd(pipe_fd[0]);
+  set_spawned(true);
+  return OVERSEE_TEST;
+}
+
+# endif  // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address.  If the test should be
+// skipped, sets that pointer to NULL.  Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+                                     const char* file, int line,
+                                     DeathTest** test) {
+  UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const int death_test_index = impl->current_test_info()
+      ->increment_death_test_count();
+
+  if (flag != NULL) {
+    if (death_test_index > flag->index()) {
+      DeathTest::set_last_death_test_message(
+          "Death test count (" + StreamableToString(death_test_index)
+          + ") somehow exceeded expected maximum ("
+          + StreamableToString(flag->index()) + ")");
+      return false;
+    }
+
+    if (!(flag->file() == file && flag->line() == line &&
+          flag->index() == death_test_index)) {
+      *test = NULL;
+      return true;
+    }
+  }
+
+# if GTEST_OS_WINDOWS
+
+  if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+      GTEST_FLAG(death_test_style) == "fast") {
+    *test = new WindowsDeathTest(statement, regex, file, line);
+  }
+
+# else
+
+  if (GTEST_FLAG(death_test_style) == "threadsafe") {
+    *test = new ExecDeathTest(statement, regex, file, line);
+  } else if (GTEST_FLAG(death_test_style) == "fast") {
+    *test = new NoExecDeathTest(statement, regex);
+  }
+
+# endif  // GTEST_OS_WINDOWS
+
+  else {  // NOLINT - this is more readable than unbalanced brackets inside #if.
+    DeathTest::set_last_death_test_message(
+        "Unknown death test style \"" + GTEST_FLAG(death_test_style)
+        + "\" encountered");
+    return false;
+  }
+
+  return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.  GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+                        ::std::vector< ::std::string>* dest) {
+  ::std::vector< ::std::string> parsed;
+  ::std::string::size_type pos = 0;
+  while (::testing::internal::AlwaysTrue()) {
+    const ::std::string::size_type colon = str.find(delimiter, pos);
+    if (colon == ::std::string::npos) {
+      parsed.push_back(str.substr(pos));
+      break;
+    } else {
+      parsed.push_back(str.substr(pos, colon - pos));
+      pos = colon + 1;
+    }
+  }
+  dest->swap(parsed);
+}
+
+# if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+int GetStatusFileDescriptor(unsigned int parent_process_id,
+                            size_t write_handle_as_size_t,
+                            size_t event_handle_as_size_t) {
+  AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+                                                   FALSE,  // Non-inheritable.
+                                                   parent_process_id));
+  if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+    DeathTestAbort("Unable to open parent process " +
+                   StreamableToString(parent_process_id));
+  }
+
+  // TODO(vladl at google.com): Replace the following check with a
+  // compile-time assertion when available.
+  GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+  const HANDLE write_handle =
+      reinterpret_cast<HANDLE>(write_handle_as_size_t);
+  HANDLE dup_write_handle;
+
+  // The newly initialized handle is accessible only in in the parent
+  // process. To obtain one accessible within the child, we need to use
+  // DuplicateHandle.
+  if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+                         ::GetCurrentProcess(), &dup_write_handle,
+                         0x0,    // Requested privileges ignored since
+                                 // DUPLICATE_SAME_ACCESS is used.
+                         FALSE,  // Request non-inheritable handler.
+                         DUPLICATE_SAME_ACCESS)) {
+    DeathTestAbort("Unable to duplicate the pipe handle " +
+                   StreamableToString(write_handle_as_size_t) +
+                   " from the parent process " +
+                   StreamableToString(parent_process_id));
+  }
+
+  const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+  HANDLE dup_event_handle;
+
+  if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+                         ::GetCurrentProcess(), &dup_event_handle,
+                         0x0,
+                         FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+    DeathTestAbort("Unable to duplicate the event handle " +
+                   StreamableToString(event_handle_as_size_t) +
+                   " from the parent process " +
+                   StreamableToString(parent_process_id));
+  }
+
+  const int write_fd =
+      ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+  if (write_fd == -1) {
+    DeathTestAbort("Unable to convert pipe handle " +
+                   StreamableToString(write_handle_as_size_t) +
+                   " to a file descriptor");
+  }
+
+  // Signals the parent that the write end of the pipe has been acquired
+  // so the parent can release its own write end.
+  ::SetEvent(dup_event_handle);
+
+  return write_fd;
+}
+# endif  // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+  if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+  // can use it here.
+  int line = -1;
+  int index = -1;
+  ::std::vector< ::std::string> fields;
+  SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+  int write_fd = -1;
+
+# if GTEST_OS_WINDOWS
+
+  unsigned int parent_process_id = 0;
+  size_t write_handle_as_size_t = 0;
+  size_t event_handle_as_size_t = 0;
+
+  if (fields.size() != 6
+      || !ParseNaturalNumber(fields[1], &line)
+      || !ParseNaturalNumber(fields[2], &index)
+      || !ParseNaturalNumber(fields[3], &parent_process_id)
+      || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+      || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+    DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
+                   GTEST_FLAG(internal_run_death_test));
+  }
+  write_fd = GetStatusFileDescriptor(parent_process_id,
+                                     write_handle_as_size_t,
+                                     event_handle_as_size_t);
+# else
+
+  if (fields.size() != 4
+      || !ParseNaturalNumber(fields[1], &line)
+      || !ParseNaturalNumber(fields[2], &index)
+      || !ParseNaturalNumber(fields[3], &write_fd)) {
+    DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+        + GTEST_FLAG(internal_run_death_test));
+  }
+
+# endif  // GTEST_OS_WINDOWS
+
+  return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+}  // namespace internal
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest-filepath.cc b/lib/gtest-1.7.0/src/gtest-filepath.cc
new file mode 100644
index 0000000..6be58b6
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-filepath.cc
@@ -0,0 +1,382 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+//
+// Authors: keith.ray at gmail.com (Keith Ray)
+
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-filepath.h"
+#include "gtest/internal/gtest-port.h"
+
+#include <stdlib.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>
+#elif GTEST_OS_WINDOWS
+# include <direct.h>
+# include <io.h>
+#elif GTEST_OS_SYMBIAN
+// Symbian OpenC has PATH_MAX in sys/syslimits.h
+# include <sys/syslimits.h>
+#else
+# include <limits.h>
+# include <climits>  // Some Linux distributions define PATH_MAX here.
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+# define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif  // GTEST_OS_WINDOWS
+
+#include "gtest/internal/gtest-string.h"
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+// On Windows, '\\' is the standard path separator, but many tools and the
+// Windows API also accept '/' as an alternate path separator. Unless otherwise
+// noted, a file path can contain either kind of path separators, or a mixture
+// of them.
+const char kPathSeparator = '\\';
+const char kAlternatePathSeparator = '/';
+const char kPathSeparatorString[] = "\\";
+const char kAlternatePathSeparatorString[] = "/";
+# if GTEST_OS_WINDOWS_MOBILE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+# else
+const char kCurrentDirectoryString[] = ".\\";
+# endif  // GTEST_OS_WINDOWS_MOBILE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif  // GTEST_OS_WINDOWS
+
+// Returns whether the given character is a valid path separator.
+static bool IsPathSeparator(char c) {
+#if GTEST_HAS_ALT_PATH_SEP_
+  return (c == kPathSeparator) || (c == kAlternatePathSeparator);
+#else
+  return c == kPathSeparator;
+#endif
+}
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#if GTEST_OS_WINDOWS_MOBILE
+  // Windows CE doesn't have a current directory, so we just return
+  // something reasonable.
+  return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+  return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+  return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif  // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+  const std::string dot_extension = std::string(".") + extension;
+  if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
+    return FilePath(pathname_.substr(
+        0, pathname_.length() - dot_extension.length()));
+  }
+  return *this;
+}
+
+// Returns a pointer to the last occurence of a valid path separator in
+// the FilePath. On Windows, for example, both '/' and '\' are valid path
+// separators. Returns NULL if no path separator was found.
+const char* FilePath::FindLastPathSeparator() const {
+  const char* const last_sep = strrchr(c_str(), kPathSeparator);
+#if GTEST_HAS_ALT_PATH_SEP_
+  const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
+  // Comparing two pointers of which only one is NULL is undefined.
+  if (last_alt_sep != NULL &&
+      (last_sep == NULL || last_alt_sep > last_sep)) {
+    return last_alt_sep;
+  }
+#endif
+  return last_sep;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+  const char* const last_sep = FindLastPathSeparator();
+  return last_sep ? FilePath(last_sep + 1) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+  const char* const last_sep = FindLastPathSeparator();
+  std::string dir;
+  if (last_sep) {
+    dir = std::string(c_str(), last_sep + 1 - c_str());
+  } else {
+    dir = kCurrentDirectoryString;
+  }
+  return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+                                const FilePath& base_name,
+                                int number,
+                                const char* extension) {
+  std::string file;
+  if (number == 0) {
+    file = base_name.string() + "." + extension;
+  } else {
+    file = base_name.string() + "_" + StreamableToString(number)
+        + "." + extension;
+  }
+  return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+                               const FilePath& relative_path) {
+  if (directory.IsEmpty())
+    return relative_path;
+  const FilePath dir(directory.RemoveTrailingPathSeparator());
+  return FilePath(dir.string() + kPathSeparator + relative_path.string());
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#if GTEST_OS_WINDOWS_MOBILE
+  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+  const DWORD attributes = GetFileAttributes(unicode);
+  delete [] unicode;
+  return attributes != kInvalidFileAttributes;
+#else
+  posix::StatStruct file_stat;
+  return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif  // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+  bool result = false;
+#if GTEST_OS_WINDOWS
+  // Don't strip off trailing separator if path is a root directory on
+  // Windows (like "C:\\").
+  const FilePath& path(IsRootDirectory() ? *this :
+                                           RemoveTrailingPathSeparator());
+#else
+  const FilePath& path(*this);
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+  const DWORD attributes = GetFileAttributes(unicode);
+  delete [] unicode;
+  if ((attributes != kInvalidFileAttributes) &&
+      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+    result = true;
+  }
+#else
+  posix::StatStruct file_stat;
+  result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+      posix::IsDir(file_stat);
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+  return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#if GTEST_OS_WINDOWS
+  // TODO(wan at google.com): on Windows a network share like
+  // \\server\share can be a root directory, although it cannot be the
+  // current directory.  Handle this properly.
+  return pathname_.length() == 3 && IsAbsolutePath();
+#else
+  return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const {
+  const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+  return pathname_.length() >= 3 &&
+     ((name[0] >= 'a' && name[0] <= 'z') ||
+      (name[0] >= 'A' && name[0] <= 'Z')) &&
+     name[1] == ':' &&
+     IsPathSeparator(name[2]);
+#else
+  return IsPathSeparator(name[0]);
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+                                          const FilePath& base_name,
+                                          const char* extension) {
+  FilePath full_pathname;
+  int number = 0;
+  do {
+    full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+  } while (full_pathname.FileOrDirectoryExists());
+  return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+  return !pathname_.empty() &&
+         IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+  if (!this->IsDirectory()) {
+    return false;
+  }
+
+  if (pathname_.length() == 0 || this->DirectoryExists()) {
+    return true;
+  }
+
+  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+  return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#if GTEST_OS_WINDOWS_MOBILE
+  FilePath removed_sep(this->RemoveTrailingPathSeparator());
+  LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+  int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+  delete [] unicode;
+#elif GTEST_OS_WINDOWS
+  int result = _mkdir(pathname_.c_str());
+#else
+  int result = mkdir(pathname_.c_str(), 0777);
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+  if (result == -1) {
+    return this->DirectoryExists();  // An error is OK if the directory exists.
+  }
+  return true;  // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+  return IsDirectory()
+      ? FilePath(pathname_.substr(0, pathname_.length() - 1))
+      : *this;
+}
+
+// Removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+// TODO(wan at google.com): handle Windows network shares (e.g. \\server\share).
+void FilePath::Normalize() {
+  if (pathname_.c_str() == NULL) {
+    pathname_ = "";
+    return;
+  }
+  const char* src = pathname_.c_str();
+  char* const dest = new char[pathname_.length() + 1];
+  char* dest_ptr = dest;
+  memset(dest_ptr, 0, pathname_.length() + 1);
+
+  while (*src != '\0') {
+    *dest_ptr = *src;
+    if (!IsPathSeparator(*src)) {
+      src++;
+    } else {
+#if GTEST_HAS_ALT_PATH_SEP_
+      if (*dest_ptr == kAlternatePathSeparator) {
+        *dest_ptr = kPathSeparator;
+      }
+#endif
+      while (IsPathSeparator(*src))
+        src++;
+    }
+    dest_ptr++;
+  }
+  *dest_ptr = '\0';
+  pathname_ = dest;
+  delete[] dest;
+}
+
+}  // namespace internal
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest-internal-inl.h b/lib/gtest-1.7.0/src/gtest-internal-inl.h
new file mode 100644
index 0000000..35df303
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-internal-inl.h
@@ -0,0 +1,1218 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan at google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation.  Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
+// part of Google Test's implementation; otherwise it's undefined.
+#if !GTEST_IMPLEMENTATION_
+// A user is trying to include this from his code - just say no.
+# error "gtest-internal-inl.h is part of Google Test's internal implementation."
+# error "It must not be included except by Google Test itself."
+#endif  // GTEST_IMPLEMENTATION_
+
+#ifndef _WIN32_WCE
+# include <errno.h>
+#endif  // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h>  // For strtoll/_strtoul64/malloc/free.
+#include <string.h>  // For memmove.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "gtest/internal/gtest-port.h"
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h>  // NOLINT
+# include <netdb.h>  // NOLINT
+#endif
+
+#if GTEST_OS_WINDOWS
+# include <windows.h>  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+
+#include "gtest/gtest.h"  // NOLINT
+#include "gtest/gtest-spi.h"
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library.  This is solely for testing GetTestTypeId().
+GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRandomSeedFlag[] = "random_seed";
+const char kRepeatFlag[] = "repeat";
+const char kShuffleFlag[] = "shuffle";
+const char kStackTraceDepthFlag[] = "stack_trace_depth";
+const char kStreamResultToFlag[] = "stream_result_to";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+GTEST_API_ extern bool g_help_flag;
+
+// Returns the current time in milliseconds.
+GTEST_API_ TimeInMillis GetTimeInMillis();
+
+// Returns true iff Google Test should use colors in the output.
+GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
+
+// Formats the given time in milliseconds as seconds.
+GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
+
+// Converts the given time in milliseconds to a date string in the ISO 8601
+// format, without the timezone information.  N.B.: due to the use the
+// non-reentrant localtime() function, this function is not thread safe.  Do
+// not use it in any code that can be called from multiple threads.
+GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
+
+// Parses a string for an Int32 flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+GTEST_API_ bool ParseInt32Flag(
+    const char* str, const char* flag, Int32* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
+  const unsigned int raw_seed = (random_seed_flag == 0) ?
+      static_cast<unsigned int>(GetTimeInMillis()) :
+      static_cast<unsigned int>(random_seed_flag);
+
+  // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+  // it's easy to type.
+  const int normalized_seed =
+      static_cast<int>((raw_seed - 1U) %
+                       static_cast<unsigned int>(kMaxRandomSeed)) + 1;
+  return normalized_seed;
+}
+
+// Returns the first valid random seed after 'seed'.  The behavior is
+// undefined if 'seed' is invalid.  The seed after kMaxRandomSeed is
+// considered to be 1.
+inline int GetNextRandomSeed(int seed) {
+  GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
+      << "Invalid random seed " << seed << " - must be in [1, "
+      << kMaxRandomSeed << "].";
+  const int next_seed = seed + 1;
+  return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
+}
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+  // The c'tor.
+  GTestFlagSaver() {
+    also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+    break_on_failure_ = GTEST_FLAG(break_on_failure);
+    catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+    color_ = GTEST_FLAG(color);
+    death_test_style_ = GTEST_FLAG(death_test_style);
+    death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+    filter_ = GTEST_FLAG(filter);
+    internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+    list_tests_ = GTEST_FLAG(list_tests);
+    output_ = GTEST_FLAG(output);
+    print_time_ = GTEST_FLAG(print_time);
+    random_seed_ = GTEST_FLAG(random_seed);
+    repeat_ = GTEST_FLAG(repeat);
+    shuffle_ = GTEST_FLAG(shuffle);
+    stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
+    stream_result_to_ = GTEST_FLAG(stream_result_to);
+    throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+  }
+
+  // The d'tor is not virtual.  DO NOT INHERIT FROM THIS CLASS.
+  ~GTestFlagSaver() {
+    GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+    GTEST_FLAG(break_on_failure) = break_on_failure_;
+    GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+    GTEST_FLAG(color) = color_;
+    GTEST_FLAG(death_test_style) = death_test_style_;
+    GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+    GTEST_FLAG(filter) = filter_;
+    GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+    GTEST_FLAG(list_tests) = list_tests_;
+    GTEST_FLAG(output) = output_;
+    GTEST_FLAG(print_time) = print_time_;
+    GTEST_FLAG(random_seed) = random_seed_;
+    GTEST_FLAG(repeat) = repeat_;
+    GTEST_FLAG(shuffle) = shuffle_;
+    GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
+    GTEST_FLAG(stream_result_to) = stream_result_to_;
+    GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+  }
+
+ private:
+  // Fields for saving the original values of flags.
+  bool also_run_disabled_tests_;
+  bool break_on_failure_;
+  bool catch_exceptions_;
+  std::string color_;
+  std::string death_test_style_;
+  bool death_test_use_fork_;
+  std::string filter_;
+  std::string internal_run_death_test_;
+  bool list_tests_;
+  std::string output_;
+  bool print_time_;
+  internal::Int32 random_seed_;
+  internal::Int32 repeat_;
+  bool shuffle_;
+  internal::Int32 stack_trace_depth_;
+  std::string stream_result_to_;
+  bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+GTEST_API_ bool ShouldShard(const char* total_shards_str,
+                            const char* shard_index_str,
+                            bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error and
+// and aborts.
+GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+GTEST_API_ bool ShouldRunTestOnShard(
+    int total_shards, int shard_index, int test_id);
+
+// STL container utilities.
+
+// Returns the number of elements in the given container that satisfy
+// the given predicate.
+template <class Container, typename Predicate>
+inline int CountIf(const Container& c, Predicate predicate) {
+  // Implemented as an explicit loop since std::count_if() in libCstd on
+  // Solaris has a non-standard signature.
+  int count = 0;
+  for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) {
+    if (predicate(*it))
+      ++count;
+  }
+  return count;
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+void ForEach(const Container& c, Functor functor) {
+  std::for_each(c.begin(), c.end(), functor);
+}
+
+// Returns the i-th element of the vector, or default_value if i is not
+// in range [0, v.size()).
+template <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
+  return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+}
+
+// Performs an in-place shuffle of a range of the vector's elements.
+// 'begin' and 'end' are element indices as an STL-style range;
+// i.e. [begin, end) are shuffled, where 'end' == size() means to
+// shuffle to the end of the vector.
+template <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+                  std::vector<E>* v) {
+  const int size = static_cast<int>(v->size());
+  GTEST_CHECK_(0 <= begin && begin <= size)
+      << "Invalid shuffle range start " << begin << ": must be in range [0, "
+      << size << "].";
+  GTEST_CHECK_(begin <= end && end <= size)
+      << "Invalid shuffle range finish " << end << ": must be in range ["
+      << begin << ", " << size << "].";
+
+  // Fisher-Yates shuffle, from
+  // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+  for (int range_width = end - begin; range_width >= 2; range_width--) {
+    const int last_in_range = begin + range_width - 1;
+    const int selected = begin + random->Generate(range_width);
+    std::swap((*v)[selected], (*v)[last_in_range]);
+  }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v) {
+  ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object.  Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T* x) {
+  delete x;
+}
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+  // Constructor.
+  //
+  // TestPropertyKeyIs has NO default constructor.
+  explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
+
+  // Returns true iff the test name of test property matches on key_.
+  bool operator()(const TestProperty& test_property) const {
+    return test_property.key() == key_;
+  }
+
+ private:
+  std::string key_;
+};
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests.  It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag.  E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter.  If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class GTEST_API_ UnitTestOptions {
+ public:
+  // Functions for processing the gtest_output flag.
+
+  // Returns the output format, or "" for normal printed output.
+  static std::string GetOutputFormat();
+
+  // Returns the absolute path of the requested output file, or the
+  // default (test_detail.xml in the original working directory) if
+  // none was explicitly specified.
+  static std::string GetAbsolutePathToOutputFile();
+
+  // Functions for processing the gtest_filter flag.
+
+  // Returns true iff the wildcard pattern matches the string.  The
+  // first ':' or '\0' character in pattern marks the end of it.
+  //
+  // This recursive algorithm isn't very efficient, but is clear and
+  // works well enough for matching test names, which are short.
+  static bool PatternMatchesString(const char *pattern, const char *str);
+
+  // Returns true iff the user-specified filter matches the test case
+  // name and the test name.
+  static bool FilterMatchesTest(const std::string &test_case_name,
+                                const std::string &test_name);
+
+#if GTEST_OS_WINDOWS
+  // Function for supporting the gtest_catch_exception flag.
+
+  // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+  // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+  // This function is useful as an __except condition.
+  static int GTestShouldProcessSEH(DWORD exception_code);
+#endif  // GTEST_OS_WINDOWS
+
+  // Returns true if "name" matches the ':' separated list of glob-style
+  // filters in "filter".
+  static bool MatchesFilter(const std::string& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present.  Used by UnitTestOptions::GetOutputFile.
+GTEST_API_ FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+  OsStackTraceGetterInterface() {}
+  virtual ~OsStackTraceGetterInterface() {}
+
+  // Returns the current OS stack trace as an std::string.  Parameters:
+  //
+  //   max_depth  - the maximum number of stack frames to be included
+  //                in the trace.
+  //   skip_count - the number of top frames to be skipped; doesn't count
+  //                against max_depth.
+  virtual string CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+  // UponLeavingGTest() should be called immediately before Google Test calls
+  // user code. It saves some information about the current stack that
+  // CurrentStackTrace() will use to find and hide Google Test stack frames.
+  virtual void UponLeavingGTest() = 0;
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+  OsStackTraceGetter() : caller_frame_(NULL) {}
+
+  virtual string CurrentStackTrace(int max_depth, int skip_count)
+      GTEST_LOCK_EXCLUDED_(mutex_);
+
+  virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
+
+  // This string is inserted in place of stack frames that are part of
+  // Google Test's implementation.
+  static const char* const kElidedFramesMarker;
+
+ private:
+  Mutex mutex_;  // protects all internal state
+
+  // We save the stack frame below the frame that calls user code.
+  // We do this because the address of the frame immediately below
+  // the user code changes between the call to UponLeavingGTest()
+  // and any calls to CurrentStackTrace() from within the user code.
+  void* caller_frame_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+  const char* file;
+  int line;
+  std::string message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+  : public TestPartResultReporterInterface {
+ public:
+  explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+  // Implements the TestPartResultReporterInterface. Reports the test part
+  // result in the current test.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+  UnitTestImpl* const unit_test_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+    : public TestPartResultReporterInterface {
+ public:
+  explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+  // Implements the TestPartResultReporterInterface. The implementation just
+  // delegates to the current global test part result reporter of *unit_test_.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+  UnitTestImpl* const unit_test_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class.  We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class GTEST_API_ UnitTestImpl {
+ public:
+  explicit UnitTestImpl(UnitTest* parent);
+  virtual ~UnitTestImpl();
+
+  // There are two different ways to register your own TestPartResultReporter.
+  // You can register your own repoter to listen either only for test results
+  // from the current thread or for results from all threads.
+  // By default, each per-thread test result repoter just passes a new
+  // TestPartResult to the global test result reporter, which registers the
+  // test part result for the currently running test.
+
+  // Returns the global test part result reporter.
+  TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+  // Sets the global test part result reporter.
+  void SetGlobalTestPartResultReporter(
+      TestPartResultReporterInterface* reporter);
+
+  // Returns the test part result reporter for the current thread.
+  TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+  // Sets the test part result reporter for the current thread.
+  void SetTestPartResultReporterForCurrentThread(
+      TestPartResultReporterInterface* reporter);
+
+  // Gets the number of successful test cases.
+  int successful_test_case_count() const;
+
+  // Gets the number of failed test cases.
+  int failed_test_case_count() const;
+
+  // Gets the number of all test cases.
+  int total_test_case_count() const;
+
+  // Gets the number of all test cases that contain at least one test
+  // that should run.
+  int test_case_to_run_count() const;
+
+  // Gets the number of successful tests.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests that will be reported in the XML report.
+  int reportable_disabled_test_count() const;
+
+  // Gets the number of disabled tests.
+  int disabled_test_count() const;
+
+  // Gets the number of tests to be printed in the XML report.
+  int reportable_test_count() const;
+
+  // Gets the number of all tests.
+  int total_test_count() const;
+
+  // Gets the number of tests that should run.
+  int test_to_run_count() const;
+
+  // Gets the time of the test program start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+  // Gets the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns true iff the unit test passed (i.e. all test cases passed).
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the unit test failed (i.e. some test case failed
+  // or something outside of all tests failed).
+  bool Failed() const {
+    return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+  }
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  const TestCase* GetTestCase(int i) const {
+    const int index = GetElementOr(test_case_indices_, i, -1);
+    return index < 0 ? NULL : test_cases_[i];
+  }
+
+  // Gets the i-th test case among all the test cases. i can range from 0 to
+  // total_test_case_count() - 1. If i is not in that range, returns NULL.
+  TestCase* GetMutableTestCase(int i) {
+    const int index = GetElementOr(test_case_indices_, i, -1);
+    return index < 0 ? NULL : test_cases_[index];
+  }
+
+  // Provides access to the event listener list.
+  TestEventListeners* listeners() { return &listeners_; }
+
+  // Returns the TestResult for the test that's currently running, or
+  // the TestResult for the ad hoc test if no test is running.
+  TestResult* current_test_result();
+
+  // Returns the TestResult for the ad hoc test.
+  const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
+
+  // Sets the OS stack trace getter.
+  //
+  // Does nothing if the input and the current OS stack trace getter
+  // are the same; otherwise, deletes the old getter and makes the
+  // input the current getter.
+  void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+  // Returns the current OS stack trace getter if it is not NULL;
+  // otherwise, creates an OsStackTraceGetter, makes it the current
+  // getter, and returns it.
+  OsStackTraceGetterInterface* os_stack_trace_getter();
+
+  // Returns the current OS stack trace as an std::string.
+  //
+  // The maximum number of stack frames to be included is specified by
+  // the gtest_stack_trace_depth flag.  The skip_count parameter
+  // specifies the number of top frames to be skipped, which doesn't
+  // count against the number of frames to be included.
+  //
+  // For example, if Foo() calls Bar(), which in turn calls
+  // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+  // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+  std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
+
+  // Finds and returns a TestCase with the given name.  If one doesn't
+  // exist, creates one and returns it.
+  //
+  // Arguments:
+  //
+  //   test_case_name: name of the test case
+  //   type_param:     the name of the test's type parameter, or NULL if
+  //                   this is not a typed or a type-parameterized test.
+  //   set_up_tc:      pointer to the function that sets up the test case
+  //   tear_down_tc:   pointer to the function that tears down the test case
+  TestCase* GetTestCase(const char* test_case_name,
+                        const char* type_param,
+                        Test::SetUpTestCaseFunc set_up_tc,
+                        Test::TearDownTestCaseFunc tear_down_tc);
+
+  // Adds a TestInfo to the unit test.
+  //
+  // Arguments:
+  //
+  //   set_up_tc:    pointer to the function that sets up the test case
+  //   tear_down_tc: pointer to the function that tears down the test case
+  //   test_info:    the TestInfo object
+  void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+                   Test::TearDownTestCaseFunc tear_down_tc,
+                   TestInfo* test_info) {
+    // In order to support thread-safe death tests, we need to
+    // remember the original working directory when the test program
+    // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
+    // the user may have changed the current directory before calling
+    // RUN_ALL_TESTS().  Therefore we capture the current directory in
+    // AddTestInfo(), which is called to register a TEST or TEST_F
+    // before main() is reached.
+    if (original_working_dir_.IsEmpty()) {
+      original_working_dir_.Set(FilePath::GetCurrentDir());
+      GTEST_CHECK_(!original_working_dir_.IsEmpty())
+          << "Failed to get the current working directory.";
+    }
+
+    GetTestCase(test_info->test_case_name(),
+                test_info->type_param(),
+                set_up_tc,
+                tear_down_tc)->AddTestInfo(test_info);
+  }
+
+#if GTEST_HAS_PARAM_TEST
+  // Returns ParameterizedTestCaseRegistry object used to keep track of
+  // value-parameterized tests and instantiate and register them.
+  internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+    return parameterized_test_registry_;
+  }
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Sets the TestCase object for the test that's currently running.
+  void set_current_test_case(TestCase* a_current_test_case) {
+    current_test_case_ = a_current_test_case;
+  }
+
+  // Sets the TestInfo object for the test that's currently running.  If
+  // current_test_info is NULL, the assertion results will be stored in
+  // ad_hoc_test_result_.
+  void set_current_test_info(TestInfo* a_current_test_info) {
+    current_test_info_ = a_current_test_info;
+  }
+
+  // Registers all parameterized tests defined using TEST_P and
+  // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter
+  // combination. This method can be called more then once; it has guards
+  // protecting from registering the tests more then once.  If
+  // value-parameterized tests are disabled, RegisterParameterizedTests is
+  // present but does nothing.
+  void RegisterParameterizedTests();
+
+  // Runs all tests in this UnitTest object, prints the result, and
+  // returns true if all tests are successful.  If any exception is
+  // thrown during a test, this test is considered to be failed, but
+  // the rest of the tests will still be run.
+  bool RunAllTests();
+
+  // Clears the results of all tests, except the ad hoc tests.
+  void ClearNonAdHocTestResult() {
+    ForEach(test_cases_, TestCase::ClearTestCaseResult);
+  }
+
+  // Clears the results of ad-hoc test assertions.
+  void ClearAdHocTestResult() {
+    ad_hoc_test_result_.Clear();
+  }
+
+  // Adds a TestProperty to the current TestResult object when invoked in a
+  // context of a test or a test case, or to the global property set. If the
+  // result already contains a property with the same key, the value will be
+  // updated.
+  void RecordProperty(const TestProperty& test_property);
+
+  enum ReactionToSharding {
+    HONOR_SHARDING_PROTOCOL,
+    IGNORE_SHARDING_PROTOCOL
+  };
+
+  // Matches the full name of each test against the user-specified
+  // filter to decide whether the test should run, then records the
+  // result in each TestCase and TestInfo object.
+  // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+  // based on sharding variables in the environment.
+  // Returns the number of tests that should run.
+  int FilterTests(ReactionToSharding shard_tests);
+
+  // Prints the names of the tests matching the user-specified filter flag.
+  void ListTestsMatchingFilter();
+
+  const TestCase* current_test_case() const { return current_test_case_; }
+  TestInfo* current_test_info() { return current_test_info_; }
+  const TestInfo* current_test_info() const { return current_test_info_; }
+
+  // Returns the vector of environments that need to be set-up/torn-down
+  // before/after the tests are run.
+  std::vector<Environment*>& environments() { return environments_; }
+
+  // Getters for the per-thread Google Test trace stack.
+  std::vector<TraceInfo>& gtest_trace_stack() {
+    return *(gtest_trace_stack_.pointer());
+  }
+  const std::vector<TraceInfo>& gtest_trace_stack() const {
+    return gtest_trace_stack_.get();
+  }
+
+#if GTEST_HAS_DEATH_TEST
+  void InitDeathTestSubprocessControlInfo() {
+    internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+  }
+  // Returns a pointer to the parsed --gtest_internal_run_death_test
+  // flag, or NULL if that flag was not specified.
+  // This information is useful only in a death test child process.
+  // Must not be called before a call to InitGoogleTest.
+  const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+    return internal_run_death_test_flag_.get();
+  }
+
+  // Returns a pointer to the current death test factory.
+  internal::DeathTestFactory* death_test_factory() {
+    return death_test_factory_.get();
+  }
+
+  void SuppressTestEventsIfInSubprocess();
+
+  friend class ReplaceDeathTestFactory;
+#endif  // GTEST_HAS_DEATH_TEST
+
+  // Initializes the event listener performing XML output as specified by
+  // UnitTestOptions. Must not be called before InitGoogleTest.
+  void ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+  // Initializes the event listener for streaming test results to a socket.
+  // Must not be called before InitGoogleTest.
+  void ConfigureStreamingOutput();
+#endif
+
+  // Performs initialization dependent upon flag values obtained in
+  // ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to
+  // ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest
+  // this function is also called from RunAllTests.  Since this function can be
+  // called more than once, it has to be idempotent.
+  void PostFlagParsingInit();
+
+  // Gets the random seed used at the start of the current test iteration.
+  int random_seed() const { return random_seed_; }
+
+  // Gets the random number generator.
+  internal::Random* random() { return &random_; }
+
+  // Shuffles all test cases, and the tests within each test case,
+  // making sure that death tests are still run first.
+  void ShuffleTests();
+
+  // Restores the test cases and tests to their order before the first shuffle.
+  void UnshuffleTests();
+
+  // Returns the value of GTEST_FLAG(catch_exceptions) at the moment
+  // UnitTest::Run() starts.
+  bool catch_exceptions() const { return catch_exceptions_; }
+
+ private:
+  friend class ::testing::UnitTest;
+
+  // Used by UnitTest::Run() to capture the state of
+  // GTEST_FLAG(catch_exceptions) at the moment it starts.
+  void set_catch_exceptions(bool value) { catch_exceptions_ = value; }
+
+  // The UnitTest object that owns this implementation object.
+  UnitTest* const parent_;
+
+  // The working directory when the first TEST() or TEST_F() was
+  // executed.
+  internal::FilePath original_working_dir_;
+
+  // The default test part result reporters.
+  DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+  DefaultPerThreadTestPartResultReporter
+      default_per_thread_test_part_result_reporter_;
+
+  // Points to (but doesn't own) the global test part result reporter.
+  TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+  // Protects read and write access to global_test_part_result_reporter_.
+  internal::Mutex global_test_part_result_reporter_mutex_;
+
+  // Points to (but doesn't own) the per-thread test part result reporter.
+  internal::ThreadLocal<TestPartResultReporterInterface*>
+      per_thread_test_part_result_reporter_;
+
+  // The vector of environments that need to be set-up/torn-down
+  // before/after the tests are run.
+  std::vector<Environment*> environments_;
+
+  // The vector of TestCases in their original order.  It owns the
+  // elements in the vector.
+  std::vector<TestCase*> test_cases_;
+
+  // Provides a level of indirection for the test case list to allow
+  // easy shuffling and restoring the test case order.  The i-th
+  // element of this vector is the index of the i-th test case in the
+  // shuffled order.
+  std::vector<int> test_case_indices_;
+
+#if GTEST_HAS_PARAM_TEST
+  // ParameterizedTestRegistry object used to register value-parameterized
+  // tests.
+  internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+  // Indicates whether RegisterParameterizedTests() has been called already.
+  bool parameterized_tests_registered_;
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Index of the last death test case registered.  Initially -1.
+  int last_death_test_case_;
+
+  // This points to the TestCase for the currently running test.  It
+  // changes as Google Test goes through one test case after another.
+  // When no test is running, this is set to NULL and Google Test
+  // stores assertion results in ad_hoc_test_result_.  Initially NULL.
+  TestCase* current_test_case_;
+
+  // This points to the TestInfo for the currently running test.  It
+  // changes as Google Test goes through one test after another.  When
+  // no test is running, this is set to NULL and Google Test stores
+  // assertion results in ad_hoc_test_result_.  Initially NULL.
+  TestInfo* current_test_info_;
+
+  // Normally, a user only writes assertions inside a TEST or TEST_F,
+  // or inside a function called by a TEST or TEST_F.  Since Google
+  // Test keeps track of which test is current running, it can
+  // associate such an assertion with the test it belongs to.
+  //
+  // If an assertion is encountered when no TEST or TEST_F is running,
+  // Google Test attributes the assertion result to an imaginary "ad hoc"
+  // test, and records the result in ad_hoc_test_result_.
+  TestResult ad_hoc_test_result_;
+
+  // The list of event listeners that can be used to track events inside
+  // Google Test.
+  TestEventListeners listeners_;
+
+  // The OS stack trace getter.  Will be deleted when the UnitTest
+  // object is destructed.  By default, an OsStackTraceGetter is used,
+  // but the user can set this field to use a custom getter if that is
+  // desired.
+  OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+  // True iff PostFlagParsingInit() has been called.
+  bool post_flag_parse_init_performed_;
+
+  // The random number seed used at the beginning of the test run.
+  int random_seed_;
+
+  // Our random number generator.
+  internal::Random random_;
+
+  // The time of the test program start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp_;
+
+  // How long the test took to run, in milliseconds.
+  TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+  // The decomposed components of the gtest_internal_run_death_test flag,
+  // parsed when RUN_ALL_TESTS is called.
+  internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+  internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif  // GTEST_HAS_DEATH_TEST
+
+  // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+  internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+  // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
+  // starts.
+  bool catch_exceptions_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+};  // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+  return UnitTest::GetInstance()->impl();
+}
+
+#if GTEST_USES_SIMPLE_RE
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+GTEST_API_ bool IsInSet(char ch, const char* str);
+GTEST_API_ bool IsAsciiDigit(char ch);
+GTEST_API_ bool IsAsciiPunct(char ch);
+GTEST_API_ bool IsRepeat(char ch);
+GTEST_API_ bool IsAsciiWhiteSpace(char ch);
+GTEST_API_ bool IsAsciiWordChar(char ch);
+GTEST_API_ bool IsValidEscape(char ch);
+GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
+GTEST_API_ bool ValidateRegex(const char* regex);
+GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
+GTEST_API_ bool MatchRepetitionAndRegexAtHead(
+    bool escaped, char ch, char repeat, const char* regex, const char* str);
+GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
+
+#endif  // GTEST_USES_SIMPLE_RE
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+GTEST_API_ std::string GetLastErrnoDescription();
+
+# if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+class AutoHandle {
+ public:
+  AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+  explicit AutoHandle(HANDLE handle) : handle_(handle) {}
+
+  ~AutoHandle() { Reset(); }
+
+  HANDLE Get() const { return handle_; }
+  void Reset() { Reset(INVALID_HANDLE_VALUE); }
+  void Reset(HANDLE handle) {
+    if (handle != handle_) {
+      if (handle_ != INVALID_HANDLE_VALUE)
+        ::CloseHandle(handle_);
+      handle_ = handle;
+    }
+  }
+
+ private:
+  HANDLE handle_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+# endif  // GTEST_OS_WINDOWS
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter.  Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
+  // Fail fast if the given string does not begin with a digit;
+  // this bypasses strtoXXX's "optional leading whitespace and plus
+  // or minus sign" semantics, which are undesirable here.
+  if (str.empty() || !IsDigit(str[0])) {
+    return false;
+  }
+  errno = 0;
+
+  char* end;
+  // BiggestConvertible is the largest integer type that system-provided
+  // string-to-number conversion routines can return.
+
+# if GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+  // MSVC and C++ Builder define __int64 instead of the standard long long.
+  typedef unsigned __int64 BiggestConvertible;
+  const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
+
+# else
+
+  typedef unsigned long long BiggestConvertible;  // NOLINT
+  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
+
+# endif  // GTEST_OS_WINDOWS && !defined(__GNUC__)
+
+  const bool parse_success = *end == '\0' && errno == 0;
+
+  // TODO(vladl at google.com): Convert this to compile time assertion when it is
+  // available.
+  GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+  const Integer result = static_cast<Integer>(parsed);
+  if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+    *number = result;
+    return true;
+  }
+  return false;
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+// TestResult contains some private methods that should be hidden from
+// Google Test user but are required for testing. This class allow our tests
+// to access them.
+//
+// This class is supplied only for the purpose of testing Google Test's own
+// constructs. Do not use it in user tests, either directly or indirectly.
+class TestResultAccessor {
+ public:
+  static void RecordProperty(TestResult* test_result,
+                             const std::string& xml_element,
+                             const TestProperty& property) {
+    test_result->RecordProperty(xml_element, property);
+  }
+
+  static void ClearTestPartResults(TestResult* test_result) {
+    test_result->ClearTestPartResults();
+  }
+
+  static const std::vector<testing::TestPartResult>& test_part_results(
+      const TestResult& test_result) {
+    return test_result.test_part_results();
+  }
+};
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Streams test results to the given port on the given host machine.
+class StreamingListener : public EmptyTestEventListener {
+ public:
+  // Abstract base class for writing strings to a socket.
+  class AbstractSocketWriter {
+   public:
+    virtual ~AbstractSocketWriter() {}
+
+    // Sends a string to the socket.
+    virtual void Send(const string& message) = 0;
+
+    // Closes the socket.
+    virtual void CloseConnection() {}
+
+    // Sends a string and a newline to the socket.
+    void SendLn(const string& message) {
+      Send(message + "\n");
+    }
+  };
+
+  // Concrete class for actually writing strings to a socket.
+  class SocketWriter : public AbstractSocketWriter {
+   public:
+    SocketWriter(const string& host, const string& port)
+        : sockfd_(-1), host_name_(host), port_num_(port) {
+      MakeConnection();
+    }
+
+    virtual ~SocketWriter() {
+      if (sockfd_ != -1)
+        CloseConnection();
+    }
+
+    // Sends a string to the socket.
+    virtual void Send(const string& message) {
+      GTEST_CHECK_(sockfd_ != -1)
+          << "Send() can be called only when there is a connection.";
+
+      const int len = static_cast<int>(message.length());
+      if (write(sockfd_, message.c_str(), len) != len) {
+        GTEST_LOG_(WARNING)
+            << "stream_result_to: failed to stream to "
+            << host_name_ << ":" << port_num_;
+      }
+    }
+
+   private:
+    // Creates a client socket and connects to the server.
+    void MakeConnection();
+
+    // Closes the socket.
+    void CloseConnection() {
+      GTEST_CHECK_(sockfd_ != -1)
+          << "CloseConnection() can be called only when there is a connection.";
+
+      close(sockfd_);
+      sockfd_ = -1;
+    }
+
+    int sockfd_;  // socket file descriptor
+    const string host_name_;
+    const string port_num_;
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
+  };  // class SocketWriter
+
+  // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
+  static string UrlEncode(const char* str);
+
+  StreamingListener(const string& host, const string& port)
+      : socket_writer_(new SocketWriter(host, port)) { Start(); }
+
+  explicit StreamingListener(AbstractSocketWriter* socket_writer)
+      : socket_writer_(socket_writer) { Start(); }
+
+  void OnTestProgramStart(const UnitTest& /* unit_test */) {
+    SendLn("event=TestProgramStart");
+  }
+
+  void OnTestProgramEnd(const UnitTest& unit_test) {
+    // Note that Google Test current only report elapsed time for each
+    // test iteration, not for the entire test program.
+    SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
+
+    // Notify the streaming server to stop.
+    socket_writer_->CloseConnection();
+  }
+
+  void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) {
+    SendLn("event=TestIterationStart&iteration=" +
+           StreamableToString(iteration));
+  }
+
+  void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) {
+    SendLn("event=TestIterationEnd&passed=" +
+           FormatBool(unit_test.Passed()) + "&elapsed_time=" +
+           StreamableToString(unit_test.elapsed_time()) + "ms");
+  }
+
+  void OnTestCaseStart(const TestCase& test_case) {
+    SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
+  }
+
+  void OnTestCaseEnd(const TestCase& test_case) {
+    SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed())
+           + "&elapsed_time=" + StreamableToString(test_case.elapsed_time())
+           + "ms");
+  }
+
+  void OnTestStart(const TestInfo& test_info) {
+    SendLn(std::string("event=TestStart&name=") + test_info.name());
+  }
+
+  void OnTestEnd(const TestInfo& test_info) {
+    SendLn("event=TestEnd&passed=" +
+           FormatBool((test_info.result())->Passed()) +
+           "&elapsed_time=" +
+           StreamableToString((test_info.result())->elapsed_time()) + "ms");
+  }
+
+  void OnTestPartResult(const TestPartResult& test_part_result) {
+    const char* file_name = test_part_result.file_name();
+    if (file_name == NULL)
+      file_name = "";
+    SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
+           "&line=" + StreamableToString(test_part_result.line_number()) +
+           "&message=" + UrlEncode(test_part_result.message()));
+  }
+
+ private:
+  // Sends the given message and a newline to the socket.
+  void SendLn(const string& message) { socket_writer_->SendLn(message); }
+
+  // Called at the start of streaming to notify the receiver what
+  // protocol we are using.
+  void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
+
+  string FormatBool(bool value) { return value ? "1" : "0"; }
+
+  const scoped_ptr<AbstractSocketWriter> socket_writer_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
+};  // class StreamingListener
+
+#endif  // GTEST_CAN_STREAM_RESULTS_
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/lib/gtest-1.7.0/src/gtest-port.cc b/lib/gtest-1.7.0/src/gtest-port.cc
new file mode 100644
index 0000000..0c4df5f
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-port.cc
@@ -0,0 +1,805 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+#include "gtest/internal/gtest-port.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>  // For TerminateProcess()
+#elif GTEST_OS_WINDOWS
+# include <io.h>
+# include <sys/stat.h>
+#else
+# include <unistd.h>
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_MAC
+# include <mach/mach_init.h>
+# include <mach/task.h>
+# include <mach/vm_map.h>
+#endif  // GTEST_OS_MAC
+
+#if GTEST_OS_QNX
+# include <devctl.h>
+# include <sys/procfs.h>
+#endif  // GTEST_OS_QNX
+
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest-message.h"
+#include "gtest/internal/gtest-internal.h"
+#include "gtest/internal/gtest-string.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+namespace internal {
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdOutFileno = 1;
+const int kStdErrFileno = 2;
+#else
+const int kStdOutFileno = STDOUT_FILENO;
+const int kStdErrFileno = STDERR_FILENO;
+#endif  // _MSC_VER
+
+#if GTEST_OS_MAC
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+  const task_t task = mach_task_self();
+  mach_msg_type_number_t thread_count;
+  thread_act_array_t thread_list;
+  const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+  if (status == KERN_SUCCESS) {
+    // task_threads allocates resources in thread_list and we need to free them
+    // to avoid leaks.
+    vm_deallocate(task,
+                  reinterpret_cast<vm_address_t>(thread_list),
+                  sizeof(thread_t) * thread_count);
+    return static_cast<size_t>(thread_count);
+  } else {
+    return 0;
+  }
+}
+
+#elif GTEST_OS_QNX
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+  const int fd = open("/proc/self/as", O_RDONLY);
+  if (fd < 0) {
+    return 0;
+  }
+  procfs_info process_info;
+  const int status =
+      devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
+  close(fd);
+  if (status == EOK) {
+    return static_cast<size_t>(process_info.num_threads);
+  } else {
+    return 0;
+  }
+}
+
+#else
+
+size_t GetThreadCount() {
+  // There's no portable way to detect the number of threads, so we just
+  // return 0 to indicate that we cannot detect it.
+  return 0;
+}
+
+#endif  // GTEST_OS_MAC
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE.  Currently only needed for death tests.
+
+RE::~RE() {
+  if (is_valid_) {
+    // regfree'ing an invalid regex might crash because the content
+    // of the regex is undefined. Since the regex's are essentially
+    // the same, one cannot be valid (or invalid) without the other
+    // being so too.
+    regfree(&partial_regex_);
+    regfree(&full_regex_);
+  }
+  free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+  if (!re.is_valid_) return false;
+
+  regmatch_t match;
+  return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+  if (!re.is_valid_) return false;
+
+  regmatch_t match;
+  return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+  pattern_ = posix::StrDup(regex);
+
+  // Reserves enough bytes to hold the regular expression used for a
+  // full match.
+  const size_t full_regex_len = strlen(regex) + 10;
+  char* const full_pattern = new char[full_regex_len];
+
+  snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+  is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+  // We want to call regcomp(&partial_regex_, ...) even if the
+  // previous expression returns false.  Otherwise partial_regex_ may
+  // not be properly initialized can may cause trouble when it's
+  // freed.
+  //
+  // Some implementation of POSIX regex (e.g. on at least some
+  // versions of Cygwin) doesn't accept the empty string as a valid
+  // regex.  We change it to an equivalent form "()" to be safe.
+  if (is_valid_) {
+    const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+    is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
+  }
+  EXPECT_TRUE(is_valid_)
+      << "Regular expression \"" << regex
+      << "\" is not a valid POSIX Extended regular expression.";
+
+  delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true iff ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+  return ch != '\0' && strchr(str, ch) != NULL;
+}
+
+// Returns true iff ch belongs to the given classification.  Unlike
+// similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsAsciiPunct(char ch) {
+  return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsAsciiWordChar(char ch) {
+  return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+      ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true iff "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+  return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true iff the given atom (specified by escaped and pattern)
+// matches ch.  The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
+  if (escaped) {  // "\\p" where p is pattern_char.
+    switch (pattern_char) {
+      case 'd': return IsAsciiDigit(ch);
+      case 'D': return !IsAsciiDigit(ch);
+      case 'f': return ch == '\f';
+      case 'n': return ch == '\n';
+      case 'r': return ch == '\r';
+      case 's': return IsAsciiWhiteSpace(ch);
+      case 'S': return !IsAsciiWhiteSpace(ch);
+      case 't': return ch == '\t';
+      case 'v': return ch == '\v';
+      case 'w': return IsAsciiWordChar(ch);
+      case 'W': return !IsAsciiWordChar(ch);
+    }
+    return IsAsciiPunct(pattern_char) && pattern_char == ch;
+  }
+
+  return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+std::string FormatRegexSyntaxError(const char* regex, int index) {
+  return (Message() << "Syntax error at index " << index
+          << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex) {
+  if (regex == NULL) {
+    // TODO(wan at google.com): fix the source file location in the
+    // assertion failures to match where the regex is used in user
+    // code.
+    ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+    return false;
+  }
+
+  bool is_valid = true;
+
+  // True iff ?, *, or + can follow the previous atom.
+  bool prev_repeatable = false;
+  for (int i = 0; regex[i]; i++) {
+    if (regex[i] == '\\') {  // An escape sequence
+      i++;
+      if (regex[i] == '\0') {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+                      << "'\\' cannot appear at the end.";
+        return false;
+      }
+
+      if (!IsValidEscape(regex[i])) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+                      << "invalid escape sequence \"\\" << regex[i] << "\".";
+        is_valid = false;
+      }
+      prev_repeatable = true;
+    } else {  // Not an escape sequence.
+      const char ch = regex[i];
+
+      if (ch == '^' && i > 0) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'^' can only appear at the beginning.";
+        is_valid = false;
+      } else if (ch == '$' && regex[i + 1] != '\0') {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'$' can only appear at the end.";
+        is_valid = false;
+      } else if (IsInSet(ch, "()[]{}|")) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'" << ch << "' is unsupported.";
+        is_valid = false;
+      } else if (IsRepeat(ch) && !prev_repeatable) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'" << ch << "' can only follow a repeatable token.";
+        is_valid = false;
+      }
+
+      prev_repeatable = !IsInSet(ch, "^$?*+");
+    }
+  }
+
+  return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression.  The regex atom is defined as c if escaped is false,
+// or \c otherwise.  repeat is the repetition meta character (?, *,
+// or +).  The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway.  We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+    bool escaped, char c, char repeat, const char* regex,
+    const char* str) {
+  const size_t min_count = (repeat == '+') ? 1 : 0;
+  const size_t max_count = (repeat == '?') ? 1 :
+      static_cast<size_t>(-1) - 1;
+  // We cannot call numeric_limits::max() as it conflicts with the
+  // max() macro on Windows.
+
+  for (size_t i = 0; i <= max_count; ++i) {
+    // We know that the atom matches each of the first i characters in str.
+    if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+      // We have enough matches at the head, and the tail matches too.
+      // Since we only care about *whether* the pattern matches str
+      // (as opposed to *how* it matches), there is no need to find a
+      // greedy match.
+      return true;
+    }
+    if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+      return false;
+  }
+  return false;
+}
+
+// Returns true iff regex matches a prefix of str.  regex must be a
+// valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str) {
+  if (*regex == '\0')  // An empty regex matches a prefix of anything.
+    return true;
+
+  // "$" only matches the end of a string.  Note that regex being
+  // valid guarantees that there's nothing after "$" in it.
+  if (*regex == '$')
+    return *str == '\0';
+
+  // Is the first thing in regex an escape sequence?
+  const bool escaped = *regex == '\\';
+  if (escaped)
+    ++regex;
+  if (IsRepeat(regex[1])) {
+    // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+    // here's an indirect recursion.  It terminates as the regex gets
+    // shorter in each recursion.
+    return MatchRepetitionAndRegexAtHead(
+        escaped, regex[0], regex[1], regex + 2, str);
+  } else {
+    // regex isn't empty, isn't "$", and doesn't start with a
+    // repetition.  We match the first atom of regex with the first
+    // character of str and recurse.
+    return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+        MatchRegexAtHead(regex + 1, str + 1);
+  }
+}
+
+// Returns true iff regex matches any substring of str.  regex must be
+// a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally.  In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str) {
+  if (regex == NULL || str == NULL)
+    return false;
+
+  if (*regex == '^')
+    return MatchRegexAtHead(regex + 1, str);
+
+  // A successful match can be anywhere in str.
+  do {
+    if (MatchRegexAtHead(regex, str))
+      return true;
+  } while (*str++ != '\0');
+  return false;
+}
+
+// Implements the RE class.
+
+RE::~RE() {
+  free(const_cast<char*>(pattern_));
+  free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+  return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+  return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+  pattern_ = full_pattern_ = NULL;
+  if (regex != NULL) {
+    pattern_ = posix::StrDup(regex);
+  }
+
+  is_valid_ = ValidateRegex(regex);
+  if (!is_valid_) {
+    // No need to calculate the full pattern when the regex is invalid.
+    return;
+  }
+
+  const size_t len = strlen(regex);
+  // Reserves enough bytes to hold the regular expression used for a
+  // full match: we need space to prepend a '^', append a '$', and
+  // terminate the string with '\0'.
+  char* buffer = static_cast<char*>(malloc(len + 3));
+  full_pattern_ = buffer;
+
+  if (*regex != '^')
+    *buffer++ = '^';  // Makes sure full_pattern_ starts with '^'.
+
+  // We don't use snprintf or strncpy, as they trigger a warning when
+  // compiled with VC++ 8.0.
+  memcpy(buffer, regex, len);
+  buffer += len;
+
+  if (len == 0 || regex[len - 1] != '$')
+    *buffer++ = '$';  // Makes sure full_pattern_ ends with '$'.
+
+  *buffer = '\0';
+}
+
+#endif  // GTEST_USES_POSIX_RE
+
+const char kUnknownFile[] = "unknown file";
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
+  const std::string file_name(file == NULL ? kUnknownFile : file);
+
+  if (line < 0) {
+    return file_name + ":";
+  }
+#ifdef _MSC_VER
+  return file_name + "(" + StreamableToString(line) + "):";
+#else
+  return file_name + ":" + StreamableToString(line) + ":";
+#endif  // _MSC_VER
+}
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+// Note that FormatCompilerIndependentFileLocation() does NOT append colon
+// to the file location it produces, unlike FormatFileLocation().
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
+    const char* file, int line) {
+  const std::string file_name(file == NULL ? kUnknownFile : file);
+
+  if (line < 0)
+    return file_name;
+  else
+    return file_name + ":" + StreamableToString(line);
+}
+
+
+GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
+    : severity_(severity) {
+  const char* const marker =
+      severity == GTEST_INFO ?    "[  INFO ]" :
+      severity == GTEST_WARNING ? "[WARNING]" :
+      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";
+  GetStream() << ::std::endl << marker << " "
+              << FormatFileLocation(file, line).c_str() << ": ";
+}
+
+// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+GTestLog::~GTestLog() {
+  GetStream() << ::std::endl;
+  if (severity_ == GTEST_FATAL) {
+    fflush(stderr);
+    posix::Abort();
+  }
+}
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996)
+#endif  // _MSC_VER
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Object that captures an output stream (stdout/stderr).
+class CapturedStream {
+ public:
+  // The ctor redirects the stream to a temporary file.
+  explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
+# if GTEST_OS_WINDOWS
+    char temp_dir_path[MAX_PATH + 1] = { '\0' };  // NOLINT
+    char temp_file_path[MAX_PATH + 1] = { '\0' };  // NOLINT
+
+    ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+    const UINT success = ::GetTempFileNameA(temp_dir_path,
+                                            "gtest_redir",
+                                            0,  // Generate unique file name.
+                                            temp_file_path);
+    GTEST_CHECK_(success != 0)
+        << "Unable to create a temporary file in " << temp_dir_path;
+    const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+    GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
+                                    << temp_file_path;
+    filename_ = temp_file_path;
+# else
+    // There's no guarantee that a test has write access to the current
+    // directory, so we create the temporary file in the /tmp directory
+    // instead. We use /tmp on most systems, and /sdcard on Android.
+    // That's because Android doesn't have /tmp.
+#  if GTEST_OS_LINUX_ANDROID
+    // Note: Android applications are expected to call the framework's
+    // Context.getExternalStorageDirectory() method through JNI to get
+    // the location of the world-writable SD Card directory. However,
+    // this requires a Context handle, which cannot be retrieved
+    // globally from native code. Doing so also precludes running the
+    // code as part of a regular standalone executable, which doesn't
+    // run in a Dalvik process (e.g. when running it through 'adb shell').
+    //
+    // The location /sdcard is directly accessible from native code
+    // and is the only location (unofficially) supported by the Android
+    // team. It's generally a symlink to the real SD Card mount point
+    // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
+    // other OEM-customized locations. Never rely on these, and always
+    // use /sdcard.
+    char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
+#  else
+    char name_template[] = "/tmp/captured_stream.XXXXXX";
+#  endif  // GTEST_OS_LINUX_ANDROID
+    const int captured_fd = mkstemp(name_template);
+    filename_ = name_template;
+# endif  // GTEST_OS_WINDOWS
+    fflush(NULL);
+    dup2(captured_fd, fd_);
+    close(captured_fd);
+  }
+
+  ~CapturedStream() {
+    remove(filename_.c_str());
+  }
+
+  std::string GetCapturedString() {
+    if (uncaptured_fd_ != -1) {
+      // Restores the original stream.
+      fflush(NULL);
+      dup2(uncaptured_fd_, fd_);
+      close(uncaptured_fd_);
+      uncaptured_fd_ = -1;
+    }
+
+    FILE* const file = posix::FOpen(filename_.c_str(), "r");
+    const std::string content = ReadEntireFile(file);
+    posix::FClose(file);
+    return content;
+  }
+
+ private:
+  // Reads the entire content of a file as an std::string.
+  static std::string ReadEntireFile(FILE* file);
+
+  // Returns the size (in bytes) of a file.
+  static size_t GetFileSize(FILE* file);
+
+  const int fd_;  // A stream to capture.
+  int uncaptured_fd_;
+  // Name of the temporary file holding the stderr output.
+  ::std::string filename_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
+};
+
+// Returns the size (in bytes) of a file.
+size_t CapturedStream::GetFileSize(FILE* file) {
+  fseek(file, 0, SEEK_END);
+  return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+std::string CapturedStream::ReadEntireFile(FILE* file) {
+  const size_t file_size = GetFileSize(file);
+  char* const buffer = new char[file_size];
+
+  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
+  size_t bytes_read = 0;       // # of bytes read so far
+
+  fseek(file, 0, SEEK_SET);
+
+  // Keeps reading the file until we cannot read further or the
+  // pre-determined file size is reached.
+  do {
+    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+    bytes_read += bytes_last_read;
+  } while (bytes_last_read > 0 && bytes_read < file_size);
+
+  const std::string content(buffer, bytes_read);
+  delete[] buffer;
+
+  return content;
+}
+
+# ifdef _MSC_VER
+#  pragma warning(pop)
+# endif  // _MSC_VER
+
+static CapturedStream* g_captured_stderr = NULL;
+static CapturedStream* g_captured_stdout = NULL;
+
+// Starts capturing an output stream (stdout/stderr).
+void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
+  if (*stream != NULL) {
+    GTEST_LOG_(FATAL) << "Only one " << stream_name
+                      << " capturer can exist at a time.";
+  }
+  *stream = new CapturedStream(fd);
+}
+
+// Stops capturing the output stream and returns the captured string.
+std::string GetCapturedStream(CapturedStream** captured_stream) {
+  const std::string content = (*captured_stream)->GetCapturedString();
+
+  delete *captured_stream;
+  *captured_stream = NULL;
+
+  return content;
+}
+
+// Starts capturing stdout.
+void CaptureStdout() {
+  CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+  CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
+}
+
+// Stops capturing stdout and returns the captured string.
+std::string GetCapturedStdout() {
+  return GetCapturedStream(&g_captured_stdout);
+}
+
+// Stops capturing stderr and returns the captured string.
+std::string GetCapturedStderr() {
+  return GetCapturedStream(&g_captured_stderr);
+}
+
+#endif  // GTEST_HAS_STREAM_REDIRECTION
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments.  Set by InitGoogleTest().
+::std::vector<testing::internal::string> g_argvs;
+
+static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
+                                        NULL;  // Owned.
+
+void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
+  if (g_injected_test_argvs != argvs)
+    delete g_injected_test_argvs;
+  g_injected_test_argvs = argvs;
+}
+
+const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
+  if (g_injected_test_argvs != NULL) {
+    return *g_injected_test_argvs;
+  }
+  return g_argvs;
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS_MOBILE
+namespace posix {
+void Abort() {
+  DebugBreak();
+  TerminateProcess(GetCurrentProcess(), 1);
+}
+}  // namespace posix
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+// Returns the name of the environment variable corresponding to the
+// given flag.  For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static std::string FlagToEnvVar(const char* flag) {
+  const std::string full_flag =
+      (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+  Message env_var;
+  for (size_t i = 0; i != full_flag.length(); i++) {
+    env_var << ToUpper(full_flag.c_str()[i]);
+  }
+
+  return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer.  If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+  // Parses the environment variable as a decimal integer.
+  char* end = NULL;
+  const long long_value = strtol(str, &end, 10);  // NOLINT
+
+  // Has strtol() consumed all characters in the string?
+  if (*end != '\0') {
+    // No - an invalid character was encountered.
+    Message msg;
+    msg << "WARNING: " << src_text
+        << " is expected to be a 32-bit integer, but actually"
+        << " has value \"" << str << "\".\n";
+    printf("%s", msg.GetString().c_str());
+    fflush(stdout);
+    return false;
+  }
+
+  // Is the parsed value in the range of an Int32?
+  const Int32 result = static_cast<Int32>(long_value);
+  if (long_value == LONG_MAX || long_value == LONG_MIN ||
+      // The parsed value overflows as a long.  (strtol() returns
+      // LONG_MAX or LONG_MIN when the input overflows.)
+      result != long_value
+      // The parsed value overflows as an Int32.
+      ) {
+    Message msg;
+    msg << "WARNING: " << src_text
+        << " is expected to be a 32-bit integer, but actually"
+        << " has value " << str << ", which overflows.\n";
+    printf("%s", msg.GetString().c_str());
+    fflush(stdout);
+    return false;
+  }
+
+  *value = result;
+  return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+  const std::string env_var = FlagToEnvVar(flag);
+  const char* const string_value = posix::GetEnv(env_var.c_str());
+  return string_value == NULL ?
+      default_value : strcmp(string_value, "0") != 0;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+  const std::string env_var = FlagToEnvVar(flag);
+  const char* const string_value = posix::GetEnv(env_var.c_str());
+  if (string_value == NULL) {
+    // The environment variable is not set.
+    return default_value;
+  }
+
+  Int32 result = default_value;
+  if (!ParseInt32(Message() << "Environment variable " << env_var,
+                  string_value, &result)) {
+    printf("The default value %s is used.\n",
+           (Message() << default_value).GetString().c_str());
+    fflush(stdout);
+    return default_value;
+  }
+
+  return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+  const std::string env_var = FlagToEnvVar(flag);
+  const char* const value = posix::GetEnv(env_var.c_str());
+  return value == NULL ? default_value : value;
+}
+
+}  // namespace internal
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest-printers.cc b/lib/gtest-1.7.0/src/gtest-printers.cc
new file mode 100644
index 0000000..75fa408
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-printers.cc
@@ -0,0 +1,363 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+// Google Test - The Google C++ Testing Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// It uses the << operator when possible, and prints the bytes in the
+// object otherwise.  A user can override its behavior for a class
+// type Foo by defining either operator<<(::std::ostream&, const Foo&)
+// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
+// defines Foo.
+
+#include "gtest/gtest-printers.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <ostream>  // NOLINT
+#include <string>
+#include "gtest/internal/gtest-port.h"
+
+namespace testing {
+
+namespace {
+
+using ::std::ostream;
+
+// Prints a segment of bytes in the given object.
+void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
+                                size_t count, ostream* os) {
+  char text[5] = "";
+  for (size_t i = 0; i != count; i++) {
+    const size_t j = start + i;
+    if (i != 0) {
+      // Organizes the bytes into groups of 2 for easy parsing by
+      // human.
+      if ((j % 2) == 0)
+        *os << ' ';
+      else
+        *os << '-';
+    }
+    GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
+    *os << text;
+  }
+}
+
+// Prints the bytes in the given value to the given ostream.
+void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
+                              ostream* os) {
+  // Tells the user how big the object is.
+  *os << count << "-byte object <";
+
+  const size_t kThreshold = 132;
+  const size_t kChunkSize = 64;
+  // If the object size is bigger than kThreshold, we'll have to omit
+  // some details by printing only the first and the last kChunkSize
+  // bytes.
+  // TODO(wan): let the user control the threshold using a flag.
+  if (count < kThreshold) {
+    PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
+  } else {
+    PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
+    *os << " ... ";
+    // Rounds up to 2-byte boundary.
+    const size_t resume_pos = (count - kChunkSize + 1)/2*2;
+    PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
+  }
+  *os << ">";
+}
+
+}  // namespace
+
+namespace internal2 {
+
+// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
+// given object.  The delegation simplifies the implementation, which
+// uses the << operator and thus is easier done outside of the
+// ::testing::internal namespace, which contains a << operator that
+// sometimes conflicts with the one in STL.
+void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
+                          ostream* os) {
+  PrintBytesInObjectToImpl(obj_bytes, count, os);
+}
+
+}  // namespace internal2
+
+namespace internal {
+
+// Depending on the value of a char (or wchar_t), we print it in one
+// of three formats:
+//   - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
+//   - as a hexidecimal escape sequence (e.g. '\x7F'), or
+//   - as a special escape sequence (e.g. '\r', '\n').
+enum CharFormat {
+  kAsIs,
+  kHexEscape,
+  kSpecialEscape
+};
+
+// Returns true if c is a printable ASCII character.  We test the
+// value of c directly instead of calling isprint(), which is buggy on
+// Windows Mobile.
+inline bool IsPrintableAscii(wchar_t c) {
+  return 0x20 <= c && c <= 0x7E;
+}
+
+// Prints a wide or narrow char c as a character literal without the
+// quotes, escaping it when necessary; returns how c was formatted.
+// The template argument UnsignedChar is the unsigned version of Char,
+// which is the type of c.
+template <typename UnsignedChar, typename Char>
+static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
+  switch (static_cast<wchar_t>(c)) {
+    case L'\0':
+      *os << "\\0";
+      break;
+    case L'\'':
+      *os << "\\'";
+      break;
+    case L'\\':
+      *os << "\\\\";
+      break;
+    case L'\a':
+      *os << "\\a";
+      break;
+    case L'\b':
+      *os << "\\b";
+      break;
+    case L'\f':
+      *os << "\\f";
+      break;
+    case L'\n':
+      *os << "\\n";
+      break;
+    case L'\r':
+      *os << "\\r";
+      break;
+    case L'\t':
+      *os << "\\t";
+      break;
+    case L'\v':
+      *os << "\\v";
+      break;
+    default:
+      if (IsPrintableAscii(c)) {
+        *os << static_cast<char>(c);
+        return kAsIs;
+      } else {
+        *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
+        return kHexEscape;
+      }
+  }
+  return kSpecialEscape;
+}
+
+// Prints a wchar_t c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
+  switch (c) {
+    case L'\'':
+      *os << "'";
+      return kAsIs;
+    case L'"':
+      *os << "\\\"";
+      return kSpecialEscape;
+    default:
+      return PrintAsCharLiteralTo<wchar_t>(c, os);
+  }
+}
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
+  return PrintAsStringLiteralTo(
+      static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
+}
+
+// Prints a wide or narrow character c and its code.  '\0' is printed
+// as "'\\0'", other unprintable characters are also properly escaped
+// using the standard C++ escape sequence.  The template argument
+// UnsignedChar is the unsigned version of Char, which is the type of c.
+template <typename UnsignedChar, typename Char>
+void PrintCharAndCodeTo(Char c, ostream* os) {
+  // First, print c as a literal in the most readable form we can find.
+  *os << ((sizeof(c) > 1) ? "L'" : "'");
+  const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
+  *os << "'";
+
+  // To aid user debugging, we also print c's code in decimal, unless
+  // it's 0 (in which case c was printed as '\\0', making the code
+  // obvious).
+  if (c == 0)
+    return;
+  *os << " (" << static_cast<int>(c);
+
+  // For more convenience, we print c's code again in hexidecimal,
+  // unless c was already printed in the form '\x##' or the code is in
+  // [1, 9].
+  if (format == kHexEscape || (1 <= c && c <= 9)) {
+    // Do nothing.
+  } else {
+    *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
+  }
+  *os << ")";
+}
+
+void PrintTo(unsigned char c, ::std::ostream* os) {
+  PrintCharAndCodeTo<unsigned char>(c, os);
+}
+void PrintTo(signed char c, ::std::ostream* os) {
+  PrintCharAndCodeTo<unsigned char>(c, os);
+}
+
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its code.  L'\0' is printed as "L'\\0'".
+void PrintTo(wchar_t wc, ostream* os) {
+  PrintCharAndCodeTo<wchar_t>(wc, os);
+}
+
+// Prints the given array of characters to the ostream.  CharType must be either
+// char or wchar_t.
+// The array starts at begin, the length is len, it may include '\0' characters
+// and may not be NUL-terminated.
+template <typename CharType>
+static void PrintCharsAsStringTo(
+    const CharType* begin, size_t len, ostream* os) {
+  const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
+  *os << kQuoteBegin;
+  bool is_previous_hex = false;
+  for (size_t index = 0; index < len; ++index) {
+    const CharType cur = begin[index];
+    if (is_previous_hex && IsXDigit(cur)) {
+      // Previous character is of '\x..' form and this character can be
+      // interpreted as another hexadecimal digit in its number. Break string to
+      // disambiguate.
+      *os << "\" " << kQuoteBegin;
+    }
+    is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
+  }
+  *os << "\"";
+}
+
+// Prints a (const) char/wchar_t array of 'len' elements, starting at address
+// 'begin'.  CharType must be either char or wchar_t.
+template <typename CharType>
+static void UniversalPrintCharArray(
+    const CharType* begin, size_t len, ostream* os) {
+  // The code
+  //   const char kFoo[] = "foo";
+  // generates an array of 4, not 3, elements, with the last one being '\0'.
+  //
+  // Therefore when printing a char array, we don't print the last element if
+  // it's '\0', such that the output matches the string literal as it's
+  // written in the source code.
+  if (len > 0 && begin[len - 1] == '\0') {
+    PrintCharsAsStringTo(begin, len - 1, os);
+    return;
+  }
+
+  // If, however, the last element in the array is not '\0', e.g.
+  //    const char kFoo[] = { 'f', 'o', 'o' };
+  // we must print the entire array.  We also print a message to indicate
+  // that the array is not NUL-terminated.
+  PrintCharsAsStringTo(begin, len, os);
+  *os << " (no terminating NUL)";
+}
+
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) wchar_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints the given C string to the ostream.
+void PrintTo(const char* s, ostream* os) {
+  if (s == NULL) {
+    *os << "NULL";
+  } else {
+    *os << ImplicitCast_<const void*>(s) << " pointing to ";
+    PrintCharsAsStringTo(s, strlen(s), os);
+  }
+}
+
+// MSVC compiler can be configured to define whar_t as a typedef
+// of unsigned short. Defining an overload for const wchar_t* in that case
+// would cause pointers to unsigned shorts be printed as wide strings,
+// possibly accessing more memory than intended and causing invalid
+// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
+// wchar_t is implemented as a native type.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Prints the given wide C string to the ostream.
+void PrintTo(const wchar_t* s, ostream* os) {
+  if (s == NULL) {
+    *os << "NULL";
+  } else {
+    *os << ImplicitCast_<const void*>(s) << " pointing to ";
+    PrintCharsAsStringTo(s, wcslen(s), os);
+  }
+}
+#endif  // wchar_t is native
+
+// Prints a ::string object.
+#if GTEST_HAS_GLOBAL_STRING
+void PrintStringTo(const ::string& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+void PrintStringTo(const ::std::string& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+// Prints a ::wstring object.
+#if GTEST_HAS_GLOBAL_WSTRING
+void PrintWideStringTo(const ::wstring& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_WSTRING
+void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+}  // namespace internal
+
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest-test-part.cc b/lib/gtest-1.7.0/src/gtest-test-part.cc
new file mode 100644
index 0000000..c60eef3
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-test-part.cc
@@ -0,0 +1,110 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: mheule at google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include "gtest/gtest-test-part.h"
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+std::string TestPartResult::ExtractSummary(const char* message) {
+  const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+  return stack_trace == NULL ? message :
+      std::string(message, stack_trace);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+  return os
+      << result.file_name() << ":" << result.line_number() << ": "
+      << (result.type() == TestPartResult::kSuccess ? "Success" :
+          result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
+          "Non-fatal failure") << ":\n"
+      << result.message() << std::endl;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+  array_.push_back(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+  if (index < 0 || index >= size()) {
+    printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+    internal::posix::Abort();
+  }
+
+  return array_[index];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+  return static_cast<int>(array_.size());
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+    : has_new_fatal_failure_(false),
+      original_reporter_(GetUnitTestImpl()->
+                         GetTestPartResultReporterForCurrentThread()) {
+  GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+  GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
+      original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+    const TestPartResult& result) {
+  if (result.fatally_failed())
+    has_new_fatal_failure_ = true;
+  original_reporter_->ReportTestPartResult(result);
+}
+
+}  // namespace internal
+
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest-typed-test.cc b/lib/gtest-1.7.0/src/gtest-typed-test.cc
new file mode 100644
index 0000000..f0079f4
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest-typed-test.cc
@@ -0,0 +1,110 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+
+#include "gtest/gtest-typed-test.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+namespace internal {
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Skips to the first non-space char in str. Returns an empty string if str
+// contains only whitespace characters.
+static const char* SkipSpaces(const char* str) {
+  while (IsSpace(*str))
+    str++;
+  return str;
+}
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+    const char* file, int line, const char* registered_tests) {
+  typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+  registered_ = true;
+
+  // Skip initial whitespace in registered_tests since some
+  // preprocessors prefix stringizied literals with whitespace.
+  registered_tests = SkipSpaces(registered_tests);
+
+  Message errors;
+  ::std::set<std::string> tests;
+  for (const char* names = registered_tests; names != NULL;
+       names = SkipComma(names)) {
+    const std::string name = GetPrefixUntilComma(names);
+    if (tests.count(name) != 0) {
+      errors << "Test " << name << " is listed more than once.\n";
+      continue;
+    }
+
+    bool found = false;
+    for (DefinedTestIter it = defined_test_names_.begin();
+         it != defined_test_names_.end();
+         ++it) {
+      if (name == *it) {
+        found = true;
+        break;
+      }
+    }
+
+    if (found) {
+      tests.insert(name);
+    } else {
+      errors << "No test named " << name
+             << " can be found in this test case.\n";
+    }
+  }
+
+  for (DefinedTestIter it = defined_test_names_.begin();
+       it != defined_test_names_.end();
+       ++it) {
+    if (tests.count(*it) == 0) {
+      errors << "You forgot to list test " << *it << ".\n";
+    }
+  }
+
+  const std::string& errors_str = errors.GetString();
+  if (errors_str != "") {
+    fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+            errors_str.c_str());
+    fflush(stderr);
+    posix::Abort();
+  }
+
+  return registered_tests;
+}
+
+#endif  // GTEST_HAS_TYPED_TEST_P
+
+}  // namespace internal
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest.cc b/lib/gtest-1.7.0/src/gtest.cc
new file mode 100644
index 0000000..6de53dd
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest.cc
@@ -0,0 +1,5015 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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: wan at google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include "gtest/gtest.h"
+#include "gtest/gtest-spi.h"
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <limits>
+#include <ostream>  // NOLINT
+#include <sstream>
+#include <vector>
+
+#if GTEST_OS_LINUX
+
+// TODO(kenton at google.com): Use autoconf to detect availability of
+// gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+# include <fcntl.h>  // NOLINT
+# include <limits.h>  // NOLINT
+# include <sched.h>  // NOLINT
+// Declares vsnprintf().  This header is not available on Windows.
+# include <strings.h>  // NOLINT
+# include <sys/mman.h>  // NOLINT
+# include <sys/time.h>  // NOLINT
+# include <unistd.h>  // NOLINT
+# include <string>
+
+#elif GTEST_OS_SYMBIAN
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h>  // NOLINT
+
+#elif GTEST_OS_ZOS
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+# include <sys/time.h>  // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+# include <strings.h>  // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE  // We are on Windows CE.
+
+# include <windows.h>  // NOLINT
+
+#elif GTEST_OS_WINDOWS  // We are on Windows proper.
+
+# include <io.h>  // NOLINT
+# include <sys/timeb.h>  // NOLINT
+# include <sys/types.h>  // NOLINT
+# include <sys/stat.h>  // NOLINT
+
+# if GTEST_OS_WINDOWS_MINGW
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton at google.com): Use autoconf to detect availability of
+//   gettimeofday().
+// TODO(kenton at google.com): There are other ways to get the time on
+//   Windows, like GetTickCount() or GetSystemTimeAsFileTime().  MinGW
+//   supports these.  consider using them instead.
+#  define GTEST_HAS_GETTIMEOFDAY_ 1
+#  include <sys/time.h>  // NOLINT
+# endif  // GTEST_OS_WINDOWS_MINGW
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <windows.h>  // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton at google.com): Use autoconf to detect availability of
+//   gettimeofday().
+# define GTEST_HAS_GETTIMEOFDAY_ 1
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <sys/time.h>  // NOLINT
+# include <unistd.h>  // NOLINT
+
+#endif  // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h>  // NOLINT
+# include <netdb.h>  // NOLINT
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS
+# define vsnprintf _vsnprintf
+#endif  // GTEST_OS_WINDOWS
+
+namespace testing {
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+bool g_help_flag = false;
+
+}  // namespace internal
+
+static const char* GetDefaultFilter() {
+  return kUniversalFilter;
+}
+
+GTEST_DEFINE_bool_(
+    also_run_disabled_tests,
+    internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+    "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+    break_on_failure,
+    internal::BoolFromGTestEnv("break_on_failure", false),
+    "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+    catch_exceptions,
+    internal::BoolFromGTestEnv("catch_exceptions", true),
+    "True iff " GTEST_NAME_
+    " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+    color,
+    internal::StringFromGTestEnv("color", "auto"),
+    "Whether to use colors in the output.  Valid values: yes, no, "
+    "and auto.  'auto' means to use colors if the output is "
+    "being sent to a terminal and the TERM environment variable "
+    "is set to a terminal type that supports colors.");
+
+GTEST_DEFINE_string_(
+    filter,
+    internal::StringFromGTestEnv("filter", GetDefaultFilter()),
+    "A colon-separated list of glob (not regex) patterns "
+    "for filtering the tests to run, optionally followed by a "
+    "'-' and a : separated list of negative patterns (tests to "
+    "exclude).  A test is run if it matches one of the positive "
+    "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+                   "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+    output,
+    internal::StringFromGTestEnv("output", ""),
+    "A format (currently must be \"xml\"), optionally followed "
+    "by a colon and an output file name or directory. A directory "
+    "is indicated by a trailing pathname separator. "
+    "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+    "If a directory is specified, output files will be created "
+    "within that directory, with file-names based on the test "
+    "executable's name and, if necessary, made unique by adding "
+    "digits.");
+
+GTEST_DEFINE_bool_(
+    print_time,
+    internal::BoolFromGTestEnv("print_time", true),
+    "True iff " GTEST_NAME_
+    " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+    random_seed,
+    internal::Int32FromGTestEnv("random_seed", 0),
+    "Random number seed to use when shuffling test orders.  Must be in range "
+    "[1, 99999], or 0 to use a seed based on the current time.");
+
+GTEST_DEFINE_int32_(
+    repeat,
+    internal::Int32FromGTestEnv("repeat", 1),
+    "How many times to repeat each test.  Specify a negative number "
+    "for repeating forever.  Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_bool_(
+    show_internal_stack_frames, false,
+    "True iff " GTEST_NAME_ " should include internal stack frames when "
+    "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(
+    shuffle,
+    internal::BoolFromGTestEnv("shuffle", false),
+    "True iff " GTEST_NAME_
+    " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+    stack_trace_depth,
+    internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+    "The maximum number of stack frames to print when an "
+    "assertion fails.  The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_string_(
+    stream_result_to,
+    internal::StringFromGTestEnv("stream_result_to", ""),
+    "This flag specifies the host name and the port number on which to stream "
+    "test results. Example: \"localhost:555\". The flag is effective only on "
+    "Linux.");
+
+GTEST_DEFINE_bool_(
+    throw_on_failure,
+    internal::BoolFromGTestEnv("throw_on_failure", false),
+    "When this flag is specified, a failed assertion will throw an exception "
+    "if exceptions are enabled or exit the program with a non-zero code "
+    "otherwise.");
+
+namespace internal {
+
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG).  Crashes if 'range' is 0 or greater
+// than kMaxRange.
+UInt32 Random::Generate(UInt32 range) {
+  // These constants are the same as are used in glibc's rand(3).
+  state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+
+  GTEST_CHECK_(range > 0)
+      << "Cannot generate a number in the range [0, 0).";
+  GTEST_CHECK_(range <= kMaxRange)
+      << "Generation of a number in [0, " << range << ") was requested, "
+      << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+  // Converting via modulus introduces a bit of downward bias, but
+  // it's simple, and a linear congruential generator isn't too good
+  // to begin with.
+  return state_ % range;
+}
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test.  Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test.  g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called.  We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+GTEST_API_ int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a vector of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
+                               int (TestCase::*method)() const) {
+  int sum = 0;
+  for (size_t i = 0; i < case_list.size(); i++) {
+    sum += (case_list[i]->*method)();
+  }
+  return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+  return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+  return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+  return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResult::Type type,
+                           const char* file,
+                           int line,
+                           const char* message)
+    : data_(new AssertHelperData(type, file, line, message)) {
+}
+
+AssertHelper::~AssertHelper() {
+  delete data_;
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+  UnitTest::GetInstance()->
+    AddTestPartResult(data_->type, data_->file, data_->line,
+                      AppendUserMessage(data_->message, message),
+                      UnitTest::GetInstance()->impl()
+                      ->CurrentOsStackTraceExceptTop(1)
+                      // Skips the stack frame for this function itself.
+                      );  // NOLINT
+}
+
+// Mutex for linked pointers.
+GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// Application pathname gotten in InitGoogleTest.
+std::string g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+  FilePath result;
+
+#if GTEST_OS_WINDOWS
+  result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+  result.Set(FilePath(g_executable_path));
+#endif  // GTEST_OS_WINDOWS
+
+  return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+std::string UnitTestOptions::GetOutputFormat() {
+  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+  if (gtest_output_flag == NULL) return std::string("");
+
+  const char* const colon = strchr(gtest_output_flag, ':');
+  return (colon == NULL) ?
+      std::string(gtest_output_flag) :
+      std::string(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
+  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+  if (gtest_output_flag == NULL)
+    return "";
+
+  const char* const colon = strchr(gtest_output_flag, ':');
+  if (colon == NULL)
+    return internal::FilePath::ConcatPaths(
+        internal::FilePath(
+            UnitTest::GetInstance()->original_working_dir()),
+        internal::FilePath(kDefaultOutputFile)).string();
+
+  internal::FilePath output_name(colon + 1);
+  if (!output_name.IsAbsolutePath())
+    // TODO(wan at google.com): on Windows \some\path is not an absolute
+    // path (as its meaning depends on the current drive), yet the
+    // following logic for turning it into an absolute path is wrong.
+    // Fix it.
+    output_name = internal::FilePath::ConcatPaths(
+        internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+        internal::FilePath(colon + 1));
+
+  if (!output_name.IsDirectory())
+    return output_name.string();
+
+  internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+      output_name, internal::GetCurrentExecutableName(),
+      GetOutputFormat().c_str()));
+  return result.string();
+}
+
+// Returns true iff the wildcard pattern matches the string.  The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+                                           const char *str) {
+  switch (*pattern) {
+    case '\0':
+    case ':':  // Either ':' or '\0' marks the end of the pattern.
+      return *str == '\0';
+    case '?':  // Matches any single character.
+      return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+    case '*':  // Matches any string (possibly empty) of characters.
+      return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+          PatternMatchesString(pattern + 1, str);
+    default:  // Non-special character.  Matches itself.
+      return *pattern == *str &&
+          PatternMatchesString(pattern + 1, str + 1);
+  }
+}
+
+bool UnitTestOptions::MatchesFilter(
+    const std::string& name, const char* filter) {
+  const char *cur_pattern = filter;
+  for (;;) {
+    if (PatternMatchesString(cur_pattern, name.c_str())) {
+      return true;
+    }
+
+    // Finds the next pattern in the filter.
+    cur_pattern = strchr(cur_pattern, ':');
+
+    // Returns if no more pattern can be found.
+    if (cur_pattern == NULL) {
+      return false;
+    }
+
+    // Skips the pattern separater (the ':' character).
+    cur_pattern++;
+  }
+}
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name,
+                                        const std::string &test_name) {
+  const std::string& full_name = test_case_name + "." + test_name.c_str();
+
+  // Split --gtest_filter at '-', if there is one, to separate into
+  // positive filter and negative filter portions
+  const char* const p = GTEST_FLAG(filter).c_str();
+  const char* const dash = strchr(p, '-');
+  std::string positive;
+  std::string negative;
+  if (dash == NULL) {
+    positive = GTEST_FLAG(filter).c_str();  // Whole string is a positive filter
+    negative = "";
+  } else {
+    positive = std::string(p, dash);   // Everything up to the dash
+    negative = std::string(dash + 1);  // Everything after the dash
+    if (positive.empty()) {
+      // Treat '-test1' as the same as '*-test1'
+      positive = kUniversalFilter;
+    }
+  }
+
+  // A filter is a colon-separated list of patterns.  It matches a
+  // test if any pattern in it matches the test.
+  return (MatchesFilter(full_name, positive.c_str()) &&
+          !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_HAS_SEH
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+  // Google Test should handle a SEH exception if:
+  //   1. the user wants it to, AND
+  //   2. this is not a breakpoint exception, AND
+  //   3. this is not a C++ exception (VC++ implements them via SEH,
+  //      apparently).
+  //
+  // SEH exception code for C++ exceptions.
+  // (see http://support.microsoft.com/kb/185294 for more information).
+  const DWORD kCxxExceptionCode = 0xe06d7363;
+
+  bool should_handle = true;
+
+  if (!GTEST_FLAG(catch_exceptions))
+    should_handle = false;
+  else if (exception_code == EXCEPTION_BREAKPOINT)
+    should_handle = false;
+  else if (exception_code == kCxxExceptionCode)
+    should_handle = false;
+
+  return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+#endif  // GTEST_HAS_SEH
+
+}  // namespace internal
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test.  The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+    TestPartResultArray* result)
+    : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+      result_(result) {
+  Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test.  The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+    InterceptMode intercept_mode, TestPartResultArray* result)
+    : intercept_mode_(intercept_mode),
+      result_(result) {
+  Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+    old_reporter_ = impl->GetGlobalTestPartResultReporter();
+    impl->SetGlobalTestPartResultReporter(this);
+  } else {
+    old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+    impl->SetTestPartResultReporterForCurrentThread(this);
+  }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+    impl->SetGlobalTestPartResultReporter(old_reporter_);
+  } else {
+    impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+  }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test.  We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test.  This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X.  The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code.  GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+  return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library.  This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+                              const char* /* type_expr */,
+                              const char* /* substr_expr */,
+                              const TestPartResultArray& results,
+                              TestPartResult::Type type,
+                              const string& substr) {
+  const std::string expected(type == TestPartResult::kFatalFailure ?
+                        "1 fatal failure" :
+                        "1 non-fatal failure");
+  Message msg;
+  if (results.size() != 1) {
+    msg << "Expected: " << expected << "\n"
+        << "  Actual: " << results.size() << " failures";
+    for (int i = 0; i < results.size(); i++) {
+      msg << "\n" << results.GetTestPartResult(i);
+    }
+    return AssertionFailure() << msg;
+  }
+
+  const TestPartResult& r = results.GetTestPartResult(0);
+  if (r.type() != type) {
+    return AssertionFailure() << "Expected: " << expected << "\n"
+                              << "  Actual:\n"
+                              << r;
+  }
+
+  if (strstr(r.message(), substr.c_str()) == NULL) {
+    return AssertionFailure() << "Expected: " << expected << " containing \""
+                              << substr << "\"\n"
+                              << "  Actual:\n"
+                              << r;
+  }
+
+  return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+    const TestPartResultArray* results,
+    TestPartResult::Type type,
+    const string& substr)
+    : results_(results),
+      type_(type),
+      substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring.  If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+  EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_);
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+    UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  unit_test_->current_test_result()->AddTestPartResult(result);
+  unit_test_->listeners()->repeater()->OnTestPartResult(result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+    UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+  return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+    TestPartResultReporterInterface* reporter) {
+  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+  global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+  return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+    TestPartResultReporterInterface* reporter) {
+  per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+  return CountIf(test_cases_, TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+  return CountIf(test_cases_, TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+  return static_cast<int>(test_cases_.size());
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+  return CountIf(test_cases_, ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTestImpl::reportable_disabled_test_count() const {
+  return SumOverTestCaseList(test_cases_,
+                             &TestCase::reportable_disabled_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTestImpl::reportable_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+  (void)skip_count;
+  return "";
+}
+
+// Returns the current time in milliseconds.
+TimeInMillis GetTimeInMillis() {
+#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
+  // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
+  // http://analogous.blogspot.com/2005/04/epoch.html
+  const TimeInMillis kJavaEpochToWinFileTimeDelta =
+    static_cast<TimeInMillis>(116444736UL) * 100000UL;
+  const DWORD kTenthMicrosInMilliSecond = 10000;
+
+  SYSTEMTIME now_systime;
+  FILETIME now_filetime;
+  ULARGE_INTEGER now_int64;
+  // TODO(kenton at google.com): Shouldn't this just use
+  //   GetSystemTimeAsFileTime()?
+  GetSystemTime(&now_systime);
+  if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+    now_int64.LowPart = now_filetime.dwLowDateTime;
+    now_int64.HighPart = now_filetime.dwHighDateTime;
+    now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+      kJavaEpochToWinFileTimeDelta;
+    return now_int64.QuadPart;
+  }
+  return 0;
+#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
+  __timeb64 now;
+
+# ifdef _MSC_VER
+
+  // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+  // (deprecated function) there.
+  // TODO(kenton at google.com): Use GetTickCount()?  Or use
+  //   SystemTimeToFileTime()
+#  pragma warning(push)          // Saves the current warning state.
+#  pragma warning(disable:4996)  // Temporarily disables warning 4996.
+  _ftime64(&now);
+#  pragma warning(pop)           // Restores the warning state.
+# else
+
+  _ftime64(&now);
+
+# endif  // _MSC_VER
+
+  return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif GTEST_HAS_GETTIMEOFDAY_
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+# error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String.
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+  if (!ansi) return NULL;
+  const int length = strlen(ansi);
+  const int unicode_length =
+      MultiByteToWideChar(CP_ACP, 0, ansi, length,
+                          NULL, 0);
+  WCHAR* unicode = new WCHAR[unicode_length + 1];
+  MultiByteToWideChar(CP_ACP, 0, ansi, length,
+                      unicode, unicode_length);
+  unicode[unicode_length] = 0;
+  return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str)  {
+  if (!utf16_str) return NULL;
+  const int ansi_length =
+      WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+                          NULL, 0, NULL, NULL);
+  char* ansi = new char[ansi_length + 1];
+  WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+                      ansi, ansi_length, NULL, NULL);
+  ansi[ansi_length] = 0;
+  return ansi;
+}
+
+#endif  // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings.  Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s).  A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+  if ( lhs == NULL ) return rhs == NULL;
+
+  if ( rhs == NULL ) return false;
+
+  return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
+                                     Message* msg) {
+  for (size_t i = 0; i != length; ) {  // NOLINT
+    if (wstr[i] != L'\0') {
+      *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+      while (i != length && wstr[i] != L'\0')
+        i++;
+    } else {
+      *msg << '\0';
+      i++;
+    }
+  }
+}
+
+#endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+}  // namespace internal
+
+// Constructs an empty Message.
+// We allocate the stringstream separately because otherwise each use of
+// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+// stack frame leading to huge stack frames in some cases; gcc does not reuse
+// the stack space.
+Message::Message() : ss_(new ::std::stringstream) {
+  // By default, we want there to be enough precision when printing
+  // a double to a Message.
+  *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
+}
+
+// These two overloads allow streaming a wide C string to a Message
+// using the UTF-8 encoding.
+Message& Message::operator <<(const wchar_t* wide_c_str) {
+  return *this << internal::String::ShowWideCString(wide_c_str);
+}
+Message& Message::operator <<(wchar_t* wide_c_str) {
+  return *this << internal::String::ShowWideCString(wide_c_str);
+}
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+  return *this;
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+  return *this;
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// Gets the text streamed to this object so far as an std::string.
+// Each '\0' character in the buffer is replaced with "\\0".
+std::string Message::GetString() const {
+  return internal::StringStreamToString(ss_.get());
+}
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+    : success_(other.success_),
+      message_(other.message_.get() != NULL ?
+               new ::std::string(*other.message_) :
+               static_cast< ::std::string*>(NULL)) {
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const {
+  AssertionResult negation(!success_);
+  if (message_.get() != NULL)
+    negation << *message_;
+  return negation;
+}
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+  return AssertionResult(true);
+}
+
+// Makes a failed assertion result.
+AssertionResult AssertionFailure() {
+  return AssertionResult(false);
+}
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << message.
+AssertionResult AssertionFailure(const Message& message) {
+  return AssertionFailure() << message;
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+//   expected_expression: "foo"
+//   actual_expression:   "bar"
+//   expected_value:      "5"
+//   actual_value:        "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+                          const char* actual_expression,
+                          const std::string& expected_value,
+                          const std::string& actual_value,
+                          bool ignoring_case) {
+  Message msg;
+  msg << "Value of: " << actual_expression;
+  if (actual_value != actual_expression) {
+    msg << "\n  Actual: " << actual_value;
+  }
+
+  msg << "\nExpected: " << expected_expression;
+  if (ignoring_case) {
+    msg << " (ignoring case)";
+  }
+  if (expected_value != expected_expression) {
+    msg << "\nWhich is: " << expected_value;
+  }
+
+  return AssertionFailure() << msg;
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+std::string GetBoolAssertionFailureMessage(
+    const AssertionResult& assertion_result,
+    const char* expression_text,
+    const char* actual_predicate_value,
+    const char* expected_predicate_value) {
+  const char* actual_message = assertion_result.message();
+  Message msg;
+  msg << "Value of: " << expression_text
+      << "\n  Actual: " << actual_predicate_value;
+  if (actual_message[0] != '\0')
+    msg << " (" << actual_message << ")";
+  msg << "\nExpected: " << expected_predicate_value;
+  return msg.GetString();
+}
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+                                     const char* expr2,
+                                     const char* abs_error_expr,
+                                     double val1,
+                                     double val2,
+                                     double abs_error) {
+  const double diff = fabs(val1 - val2);
+  if (diff <= abs_error) return AssertionSuccess();
+
+  // TODO(wan): do not print the value of an expression if it's
+  // already a literal.
+  return AssertionFailure()
+      << "The difference between " << expr1 << " and " << expr2
+      << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+      << expr1 << " evaluates to " << val1 << ",\n"
+      << expr2 << " evaluates to " << val2 << ", and\n"
+      << abs_error_expr << " evaluates to " << abs_error << ".";
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+                                const char* expr2,
+                                RawType val1,
+                                RawType val2) {
+  // Returns success if val1 is less than val2,
+  if (val1 < val2) {
+    return AssertionSuccess();
+  }
+
+  // or if val1 is almost equal to val2.
+  const FloatingPoint<RawType> lhs(val1), rhs(val2);
+  if (lhs.AlmostEquals(rhs)) {
+    return AssertionSuccess();
+  }
+
+  // Note that the above two checks will both fail if either val1 or
+  // val2 is NaN, as the IEEE floating-point standard requires that
+  // any predicate involving a NaN must return false.
+
+  ::std::stringstream val1_ss;
+  val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+          << val1;
+
+  ::std::stringstream val2_ss;
+  val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+          << val2;
+
+  return AssertionFailure()
+      << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+      << "  Actual: " << StringStreamToString(&val1_ss) << " vs "
+      << StringStreamToString(&val2_ss);
+}
+
+}  // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+                        float val1, float val2) {
+  return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+                         double val1, double val2) {
+  return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            BiggestInt expected,
+                            BiggestInt actual) {
+  if (expected == actual) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   FormatForComparisonFailureMessage(expected, actual),
+                   FormatForComparisonFailureMessage(actual, expected),
+                   false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments.  It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   BiggestInt val1, BiggestInt val2) {\
+  if (val1 op val2) {\
+    return AssertionSuccess();\
+  } else {\
+    return AssertionFailure() \
+        << "Expected: (" << expr1 << ") " #op " (" << expr2\
+        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+  }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const char* expected,
+                               const char* actual) {
+  if (String::CStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   PrintToString(expected),
+                   PrintToString(actual),
+                   false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+                                   const char* actual_expression,
+                                   const char* expected,
+                                   const char* actual) {
+  if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   PrintToString(expected),
+                   PrintToString(actual),
+                   true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const char* s1,
+                               const char* s2) {
+  if (!String::CStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  } else {
+    return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+                              << s2_expression << "), actual: \""
+                              << s1 << "\" vs \"" << s2 << "\"";
+  }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+                                   const char* s2_expression,
+                                   const char* s1,
+                                   const char* s2) {
+  if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  } else {
+    return AssertionFailure()
+        << "Expected: (" << s1_expression << ") != ("
+        << s2_expression << ") (ignoring case), actual: \""
+        << s1 << "\" vs \"" << s2 << "\"";
+  }
+}
+
+}  // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack.  NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+  if (needle == NULL || haystack == NULL)
+    return needle == haystack;
+
+  return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+  if (needle == NULL || haystack == NULL)
+    return needle == haystack;
+
+  return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+                     const StringType& haystack) {
+  return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+    bool expected_to_be_substring,
+    const char* needle_expr, const char* haystack_expr,
+    const StringType& needle, const StringType& haystack) {
+  if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+    return AssertionSuccess();
+
+  const bool is_wide_string = sizeof(needle[0]) > 1;
+  const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+  return AssertionFailure()
+      << "Value of: " << needle_expr << "\n"
+      << "  Actual: " << begin_string_quote << needle << "\"\n"
+      << "Expected: " << (expected_to_be_substring ? "" : "not ")
+      << "a substring of " << haystack_expr << "\n"
+      << "Which is: " << begin_string_quote << haystack << "\"";
+}
+
+}  // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+                                     const char* expected,
+                                     long hr) {  // NOLINT
+# if GTEST_OS_WINDOWS_MOBILE
+
+  // Windows CE doesn't support FormatMessage.
+  const char error_text[] = "";
+
+# else
+
+  // Looks up the human-readable system message for the HRESULT code
+  // and since we're not passing any params to FormatMessage, we don't
+  // want inserts expanded.
+  const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS;
+  const DWORD kBufSize = 4096;
+  // Gets the system's human readable message string for this HRESULT.
+  char error_text[kBufSize] = { '\0' };
+  DWORD message_length = ::FormatMessageA(kFlags,
+                                          0,  // no source, we're asking system
+                                          hr,  // the error
+                                          0,  // no line width restrictions
+                                          error_text,  // output buffer
+                                          kBufSize,  // buf size
+                                          NULL);  // no arguments for inserts
+  // Trims tailing white space (FormatMessage leaves a trailing CR-LF)
+  for (; message_length && IsSpace(error_text[message_length - 1]);
+          --message_length) {
+    error_text[message_length - 1] = '\0';
+  }
+
+# endif  // GTEST_OS_WINDOWS_MOBILE
+
+  const std::string error_hex("0x" + String::FormatHexInt(hr));
+  return ::testing::AssertionFailure()
+      << "Expected: " << expr << " " << expected << ".\n"
+      << "  Actual: " << error_hex << " " << error_text << "\n";
+}
+
+}  // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) {  // NOLINT
+  if (SUCCEEDED(hr)) {
+    return AssertionSuccess();
+  }
+  return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) {  // NOLINT
+  if (FAILED(hr)) {
+    return AssertionSuccess();
+  }
+  return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif  // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length   Encoding
+//   0 -  7 bits       0xxxxxxx
+//   8 - 11 bits       110xxxxx 10xxxxxx
+//  12 - 16 bits       1110xxxx 10xxxxxx 10xxxxxx
+//  17 - 21 bits       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) <<  7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern.  Returns the n
+// lowest bits.  As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+  const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+  *bits >>= n;
+  return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+std::string CodePointToUtf8(UInt32 code_point) {
+  if (code_point > kMaxCodePoint4) {
+    return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")";
+  }
+
+  char str[5];  // Big enough for the largest valid code point.
+  if (code_point <= kMaxCodePoint1) {
+    str[1] = '\0';
+    str[0] = static_cast<char>(code_point);                          // 0xxxxxxx
+  } else if (code_point <= kMaxCodePoint2) {
+    str[2] = '\0';
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xC0 | code_point);                   // 110xxxxx
+  } else if (code_point <= kMaxCodePoint3) {
+    str[3] = '\0';
+    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xE0 | code_point);                   // 1110xxxx
+  } else {  // code_point <= kMaxCodePoint4
+    str[4] = '\0';
+    str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xF0 | code_point);                   // 11110xxx
+  }
+  return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+  return sizeof(wchar_t) == 2 &&
+      (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+                                                    wchar_t second) {
+  const UInt32 mask = (1 << 10) - 1;
+  return (sizeof(wchar_t) == 2) ?
+      (((first & mask) << 10) | (second & mask)) + 0x10000 :
+      // This function should not be called when the condition is
+      // false, but we provide a sensible default in case it is.
+      static_cast<UInt32>(first);
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+std::string WideStringToUtf8(const wchar_t* str, int num_chars) {
+  if (num_chars == -1)
+    num_chars = static_cast<int>(wcslen(str));
+
+  ::std::stringstream stream;
+  for (int i = 0; i < num_chars; ++i) {
+    UInt32 unicode_code_point;
+
+    if (str[i] == L'\0') {
+      break;
+    } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+      unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+                                                                 str[i + 1]);
+      i++;
+    } else {
+      unicode_code_point = static_cast<UInt32>(str[i]);
+    }
+
+    stream << CodePointToUtf8(unicode_code_point);
+  }
+  return StringStreamToString(&stream);
+}
+
+// Converts a wide C string to an std::string using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+std::string String::ShowWideCString(const wchar_t * wide_c_str) {
+  if (wide_c_str == NULL)  return "(null)";
+
+  return internal::WideStringToUtf8(wide_c_str, -1);
+}
+
+// Compares two wide C strings.  Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s).  A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+  if (lhs == NULL) return rhs == NULL;
+
+  if (rhs == NULL) return false;
+
+  return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const wchar_t* expected,
+                               const wchar_t* actual) {
+  if (String::WideCStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   PrintToString(expected),
+                   PrintToString(actual),
+                   false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const wchar_t* s1,
+                               const wchar_t* s2) {
+  if (!String::WideCStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  }
+
+  return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+                            << s2_expression << "), actual: "
+                            << PrintToString(s1)
+                            << " vs " << PrintToString(s2);
+}
+
+// Compares two C strings, ignoring case.  Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s).  A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+  if (lhs == NULL)
+    return rhs == NULL;
+  if (rhs == NULL)
+    return false;
+  return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+  // Compares two wide C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike wcscasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL wide C string,
+  // including the empty string.
+  // NB: The implementations on different platforms slightly differ.
+  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+  // environment variable. On GNU platform this method uses wcscasecmp
+  // which compares according to LC_CTYPE category of the current locale.
+  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+  // current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+                                              const wchar_t* rhs) {
+  if (lhs == NULL) return rhs == NULL;
+
+  if (rhs == NULL) return false;
+
+#if GTEST_OS_WINDOWS
+  return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID
+  return wcscasecmp(lhs, rhs) == 0;
+#else
+  // Android, Mac OS X and Cygwin don't define wcscasecmp.
+  // Other unknown OSes may not define it either.
+  wint_t left, right;
+  do {
+    left = towlower(*lhs++);
+    right = towlower(*rhs++);
+  } while (left && left == right);
+  return left == right;
+#endif  // OS selector
+}
+
+// Returns true iff str ends with the given suffix, ignoring case.
+// Any string is considered to end with an empty suffix.
+bool String::EndsWithCaseInsensitive(
+    const std::string& str, const std::string& suffix) {
+  const size_t str_len = str.length();
+  const size_t suffix_len = suffix.length();
+  return (str_len >= suffix_len) &&
+         CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len,
+                                      suffix.c_str());
+}
+
+// Formats an int value as "%02d".
+std::string String::FormatIntWidth2(int value) {
+  std::stringstream ss;
+  ss << std::setfill('0') << std::setw(2) << value;
+  return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexInt(int value) {
+  std::stringstream ss;
+  ss << std::hex << std::uppercase << value;
+  return ss.str();
+}
+
+// Formats a byte as "%02X".
+std::string String::FormatByte(unsigned char value) {
+  std::stringstream ss;
+  ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
+     << static_cast<unsigned int>(value);
+  return ss.str();
+}
+
+// Converts the buffer in a stringstream to an std::string, converting NUL
+// bytes to "\\0" along the way.
+std::string StringStreamToString(::std::stringstream* ss) {
+  const ::std::string& str = ss->str();
+  const char* const start = str.c_str();
+  const char* const end = start + str.length();
+
+  std::string result;
+  result.reserve(2 * (end - start));
+  for (const char* ch = start; ch != end; ++ch) {
+    if (*ch == '\0') {
+      result += "\\0";  // Replaces NUL with "\\0";
+    } else {
+      result += *ch;
+    }
+  }
+
+  return result;
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+std::string AppendUserMessage(const std::string& gtest_msg,
+                              const Message& user_msg) {
+  // Appends the user message if it's non-empty.
+  const std::string user_msg_string = user_msg.GetString();
+  if (user_msg_string.empty()) {
+    return gtest_msg;
+  }
+
+  return gtest_msg + "\n" + user_msg_string;
+}
+
+}  // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+    : death_test_count_(0),
+      elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Returns the i-th test part result among all the results. i can
+// range from 0 to total_part_count() - 1. If i is not in that range,
+// aborts the program.
+const TestPartResult& TestResult::GetTestPartResult(int i) const {
+  if (i < 0 || i >= total_part_count())
+    internal::posix::Abort();
+  return test_part_results_.at(i);
+}
+
+// Returns the i-th test property. i can range from 0 to
+// test_property_count() - 1. If i is not in that range, aborts the
+// program.
+const TestProperty& TestResult::GetTestProperty(int i) const {
+  if (i < 0 || i >= test_property_count())
+    internal::posix::Abort();
+  return test_properties_.at(i);
+}
+
+// Clears the test part results.
+void TestResult::ClearTestPartResults() {
+  test_part_results_.clear();
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+  test_part_results_.push_back(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const std::string& xml_element,
+                                const TestProperty& test_property) {
+  if (!ValidateTestProperty(xml_element, test_property)) {
+    return;
+  }
+  internal::MutexLock lock(&test_properites_mutex_);
+  const std::vector<TestProperty>::iterator property_with_matching_key =
+      std::find_if(test_properties_.begin(), test_properties_.end(),
+                   internal::TestPropertyKeyIs(test_property.key()));
+  if (property_with_matching_key == test_properties_.end()) {
+    test_properties_.push_back(test_property);
+    return;
+  }
+  property_with_matching_key->SetValue(test_property.value());
+}
+
+// The list of reserved attributes used in the <testsuites> element of XML
+// output.
+static const char* const kReservedTestSuitesAttributes[] = {
+  "disabled",
+  "errors",
+  "failures",
+  "name",
+  "random_seed",
+  "tests",
+  "time",
+  "timestamp"
+};
+
+// The list of reserved attributes used in the <testsuite> element of XML
+// output.
+static const char* const kReservedTestSuiteAttributes[] = {
+  "disabled",
+  "errors",
+  "failures",
+  "name",
+  "tests",
+  "time"
+};
+
+// The list of reserved attributes used in the <testcase> element of XML output.
+static const char* const kReservedTestCaseAttributes[] = {
+  "classname",
+  "name",
+  "status",
+  "time",
+  "type_param",
+  "value_param"
+};
+
+template <int kSize>
+std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
+  return std::vector<std::string>(array, array + kSize);
+}
+
+static std::vector<std::string> GetReservedAttributesForElement(
+    const std::string& xml_element) {
+  if (xml_element == "testsuites") {
+    return ArrayAsVector(kReservedTestSuitesAttributes);
+  } else if (xml_element == "testsuite") {
+    return ArrayAsVector(kReservedTestSuiteAttributes);
+  } else if (xml_element == "testcase") {
+    return ArrayAsVector(kReservedTestCaseAttributes);
+  } else {
+    GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+  }
+  // This code is unreachable but some compilers may not realizes that.
+  return std::vector<std::string>();
+}
+
+static std::string FormatWordList(const std::vector<std::string>& words) {
+  Message word_list;
+  for (size_t i = 0; i < words.size(); ++i) {
+    if (i > 0 && words.size() > 2) {
+      word_list << ", ";
+    }
+    if (i == words.size() - 1) {
+      word_list << "and ";
+    }
+    word_list << "'" << words[i] << "'";
+  }
+  return word_list.GetString();
+}
+
+bool ValidateTestPropertyName(const std::string& property_name,
+                              const std::vector<std::string>& reserved_names) {
+  if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
+          reserved_names.end()) {
+    ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
+                  << " (" << FormatWordList(reserved_names)
+                  << " are reserved by " << GTEST_NAME_ << ")";
+    return false;
+  }
+  return true;
+}
+
+// Adds a failure if the key is a reserved attribute of the element named
+// xml_element.  Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const std::string& xml_element,
+                                      const TestProperty& test_property) {
+  return ValidateTestPropertyName(test_property.key(),
+                                  GetReservedAttributesForElement(xml_element));
+}
+
+// Clears the object.
+void TestResult::Clear() {
+  test_part_results_.clear();
+  test_properties_.clear();
+  death_test_count_ = 0;
+  elapsed_time_ = 0;
+}
+
+// Returns true iff the test failed.
+bool TestResult::Failed() const {
+  for (int i = 0; i < total_part_count(); ++i) {
+    if (GetTestPartResult(i).failed())
+      return true;
+  }
+  return false;
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+  return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+  return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true iff the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+  return result.nonfatally_failed();
+}
+
+// Returns true iff the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const {
+  return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts.  This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+  return static_cast<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const {
+  return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+    : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+  delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, const std::string& value) {
+  UnitTest::GetInstance()->RecordProperty(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, int value) {
+  Message value_message;
+  value_message << value;
+  RecordProperty(key, value_message.GetString().c_str());
+}
+
+namespace internal {
+
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+                                    const std::string& message) {
+  // This function is a friend of UnitTest and as such has access to
+  // AddTestPartResult.
+  UnitTest::GetInstance()->AddTestPartResult(
+      result_type,
+      NULL,  // No info about the source file where the exception occurred.
+      -1,    // We have no info on which line caused the exception.
+      message,
+      "");   // No stack trace, either.
+}
+
+}  // namespace internal
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class.  This function checks if the current test has the
+// same fixture class as the first test in the current test case.  If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  const TestCase* const test_case = impl->current_test_case();
+
+  // Info about the first test in the current test case.
+  const TestInfo* const first_test_info = test_case->test_info_list()[0];
+  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
+  const char* const first_test_name = first_test_info->name();
+
+  // Info about the current test.
+  const TestInfo* const this_test_info = impl->current_test_info();
+  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
+  const char* const this_test_name = this_test_info->name();
+
+  if (this_fixture_id != first_fixture_id) {
+    // Is the first test defined using TEST?
+    const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+    // Is this test defined using TEST?
+    const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+    if (first_is_TEST || this_is_TEST) {
+      // The user mixed TEST and TEST_F in this test case - we'll tell
+      // him/her how to fix it.
+
+      // Gets the name of the TEST and the name of the TEST_F.  Note
+      // that first_is_TEST and this_is_TEST cannot both be true, as
+      // the fixture IDs are different for the two tests.
+      const char* const TEST_name =
+          first_is_TEST ? first_test_name : this_test_name;
+      const char* const TEST_F_name =
+          first_is_TEST ? this_test_name : first_test_name;
+
+      ADD_FAILURE()
+          << "All tests in the same test case must use the same test fixture\n"
+          << "class, so mixing TEST_F and TEST in the same test case is\n"
+          << "illegal.  In test case " << this_test_info->test_case_name()
+          << ",\n"
+          << "test " << TEST_F_name << " is defined using TEST_F but\n"
+          << "test " << TEST_name << " is defined using TEST.  You probably\n"
+          << "want to change the TEST to TEST_F or move it to another test\n"
+          << "case.";
+    } else {
+      // The user defined two fixture classes with the same name in
+      // two namespaces - we'll tell him/her how to fix it.
+      ADD_FAILURE()
+          << "All tests in the same test case must use the same test fixture\n"
+          << "class.  However, in test case "
+          << this_test_info->test_case_name() << ",\n"
+          << "you defined test " << first_test_name
+          << " and test " << this_test_name << "\n"
+          << "using two different test fixture classes.  This can happen if\n"
+          << "the two classes are from different namespaces or translation\n"
+          << "units and have the same name.  You should probably rename one\n"
+          << "of the classes to put the tests into different test cases.";
+    }
+    return false;
+  }
+
+  return true;
+}
+
+#if GTEST_HAS_SEH
+
+// Adds an "exception thrown" fatal failure to the current test.  This
+// function returns its result via an output parameter pointer because VC++
+// prohibits creation of objects with destructors on stack in functions
+// using __try (see error C2712).
+static std::string* FormatSehExceptionMessage(DWORD exception_code,
+                                              const char* location) {
+  Message message;
+  message << "SEH exception with code 0x" << std::setbase(16) <<
+    exception_code << std::setbase(10) << " thrown in " << location << ".";
+
+  return new std::string(message.GetString());
+}
+
+#endif  // GTEST_HAS_SEH
+
+namespace internal {
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static std::string FormatCxxExceptionMessage(const char* description,
+                                             const char* location) {
+  Message message;
+  if (description != NULL) {
+    message << "C++ exception with description \"" << description << "\"";
+  } else {
+    message << "Unknown C++ exception";
+  }
+  message << " thrown in " << location << ".";
+
+  return message.GetString();
+}
+
+static std::string PrintTestPartResultToString(
+    const TestPartResult& test_part_result);
+
+GoogleTestFailureException::GoogleTestFailureException(
+    const TestPartResult& failure)
+    : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
+// We put these helper functions in the internal namespace as IBM's xlC
+// compiler rejects the code if they were declared static.
+
+// Runs the given method and handles SEH exceptions it throws, when
+// SEH is supported; returns the 0-value for type Result in case of an
+// SEH exception.  (Microsoft compilers cannot handle SEH and C++
+// exceptions in the same function.  Therefore, we provide a separate
+// wrapper function for handling SEH exceptions.)
+template <class T, typename Result>
+Result HandleSehExceptionsInMethodIfSupported(
+    T* object, Result (T::*method)(), const char* location) {
+#if GTEST_HAS_SEH
+  __try {
+    return (object->*method)();
+  } __except (internal::UnitTestOptions::GTestShouldProcessSEH(  // NOLINT
+      GetExceptionCode())) {
+    // We create the exception message on the heap because VC++ prohibits
+    // creation of objects with destructors on stack in functions using __try
+    // (see error C2712).
+    std::string* exception_message = FormatSehExceptionMessage(
+        GetExceptionCode(), location);
+    internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+                                             *exception_message);
+    delete exception_message;
+    return static_cast<Result>(0);
+  }
+#else
+  (void)location;
+  return (object->*method)();
+#endif  // GTEST_HAS_SEH
+}
+
+// Runs the given method and catches and reports C++ and/or SEH-style
+// exceptions, if they are supported; returns the 0-value for type
+// Result in case of an SEH exception.
+template <class T, typename Result>
+Result HandleExceptionsInMethodIfSupported(
+    T* object, Result (T::*method)(), const char* location) {
+  // NOTE: The user code can affect the way in which Google Test handles
+  // exceptions by setting GTEST_FLAG(catch_exceptions), but only before
+  // RUN_ALL_TESTS() starts. It is technically possible to check the flag
+  // after the exception is caught and either report or re-throw the
+  // exception based on the flag's value:
+  //
+  // try {
+  //   // Perform the test method.
+  // } catch (...) {
+  //   if (GTEST_FLAG(catch_exceptions))
+  //     // Report the exception as failure.
+  //   else
+  //     throw;  // Re-throws the original exception.
+  // }
+  //
+  // However, the purpose of this flag is to allow the program to drop into
+  // the debugger when the exception is thrown. On most platforms, once the
+  // control enters the catch block, the exception origin information is
+  // lost and the debugger will stop the program at the point of the
+  // re-throw in this function -- instead of at the point of the original
+  // throw statement in the code under test.  For this reason, we perform
+  // the check early, sacrificing the ability to affect Google Test's
+  // exception handling in the method where the exception is thrown.
+  if (internal::GetUnitTestImpl()->catch_exceptions()) {
+#if GTEST_HAS_EXCEPTIONS
+    try {
+      return HandleSehExceptionsInMethodIfSupported(object, method, location);
+    } catch (const internal::GoogleTestFailureException&) {  // NOLINT
+      // This exception type can only be thrown by a failed Google
+      // Test assertion with the intention of letting another testing
+      // framework catch it.  Therefore we just re-throw it.
+      throw;
+    } catch (const std::exception& e) {  // NOLINT
+      internal::ReportFailureInUnknownLocation(
+          TestPartResult::kFatalFailure,
+          FormatCxxExceptionMessage(e.what(), location));
+    } catch (...) {  // NOLINT
+      internal::ReportFailureInUnknownLocation(
+          TestPartResult::kFatalFailure,
+          FormatCxxExceptionMessage(NULL, location));
+    }
+    return static_cast<Result>(0);
+#else
+    return HandleSehExceptionsInMethodIfSupported(object, method, location);
+#endif  // GTEST_HAS_EXCEPTIONS
+  } else {
+    return (object->*method)();
+  }
+}
+
+}  // namespace internal
+
+// Runs the test and updates the test result.
+void Test::Run() {
+  if (!HasSameFixtureClass()) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
+  // We will run the test only if SetUp() was successful.
+  if (!HasFatalFailure()) {
+    impl->os_stack_trace_getter()->UponLeavingGTest();
+    internal::HandleExceptionsInMethodIfSupported(
+        this, &Test::TestBody, "the test body");
+  }
+
+  // However, we want to clean up as much as possible.  Hence we will
+  // always call TearDown(), even if SetUp() or the test body has
+  // failed.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      this, &Test::TearDown, "TearDown()");
+}
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+  return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true iff the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+  return internal::GetUnitTestImpl()->current_test_result()->
+      HasNonfatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object.
+TestInfo::TestInfo(const std::string& a_test_case_name,
+                   const std::string& a_name,
+                   const char* a_type_param,
+                   const char* a_value_param,
+                   internal::TypeId fixture_class_id,
+                   internal::TestFactoryBase* factory)
+    : test_case_name_(a_test_case_name),
+      name_(a_name),
+      type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+      value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+      fixture_class_id_(fixture_class_id),
+      should_run_(false),
+      is_disabled_(false),
+      matches_filter_(false),
+      factory_(factory),
+      result_() {}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() { delete factory_; }
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+//   test_case_name:   name of the test case
+//   name:             name of the test
+//   type_param:       the name of the test's type parameter, or NULL if
+//                     this is not a typed or a type-parameterized test.
+//   value_param:      text representation of the test's value parameter,
+//                     or NULL if this is not a value-parameterized test.
+//   fixture_class_id: ID of the test fixture class
+//   set_up_tc:        pointer to the function that sets up the test case
+//   tear_down_tc:     pointer to the function that tears down the test case
+//   factory:          pointer to the factory that creates a test object.
+//                     The newly created TestInfo instance will assume
+//                     ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+    const char* test_case_name,
+    const char* name,
+    const char* type_param,
+    const char* value_param,
+    TypeId fixture_class_id,
+    SetUpTestCaseFunc set_up_tc,
+    TearDownTestCaseFunc tear_down_tc,
+    TestFactoryBase* factory) {
+  TestInfo* const test_info =
+      new TestInfo(test_case_name, name, type_param, value_param,
+                   fixture_class_id, factory);
+  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+  return test_info;
+}
+
+#if GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+                               const char* file, int line) {
+  Message errors;
+  errors
+      << "Attempted redefinition of test case " << test_case_name << ".\n"
+      << "All tests in the same test case must use the same test fixture\n"
+      << "class.  However, in test case " << test_case_name << ", you tried\n"
+      << "to define a test using a fixture class different from the one\n"
+      << "used earlier. This can happen if the two fixture classes are\n"
+      << "from different namespaces and have the same name. You should\n"
+      << "probably rename one of the classes to put the tests into different\n"
+      << "test cases.";
+
+  fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+          errors.GetString().c_str());
+}
+#endif  // GTEST_HAS_PARAM_TEST
+
+}  // namespace internal
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only.  We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+  // Constructor.
+  //
+  // TestNameIs has NO default constructor.
+  explicit TestNameIs(const char* name)
+      : name_(name) {}
+
+  // Returns true iff the test name of test_info matches name_.
+  bool operator()(const TestInfo * test_info) const {
+    return test_info && test_info->name() == name_;
+  }
+
+ private:
+  std::string name_;
+};
+
+}  // namespace
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+#if GTEST_HAS_PARAM_TEST
+  if (!parameterized_tests_registered_) {
+    parameterized_test_registry_.RegisterTests();
+    parameterized_tests_registered_ = true;
+  }
+#endif
+}
+
+}  // namespace internal
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfo::Run() {
+  if (!should_run_) return;
+
+  // Tells UnitTest where to store test result.
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_info(this);
+
+  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+  // Notifies the unit test event listeners that a test is about to start.
+  repeater->OnTestStart(*this);
+
+  const TimeInMillis start = internal::GetTimeInMillis();
+
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+
+  // Creates the test object.
+  Test* const test = internal::HandleExceptionsInMethodIfSupported(
+      factory_, &internal::TestFactoryBase::CreateTest,
+      "the test fixture's constructor");
+
+  // Runs the test only if the test object was created and its
+  // constructor didn't generate a fatal failure.
+  if ((test != NULL) && !Test::HasFatalFailure()) {
+    // This doesn't throw as all user code that can throw are wrapped into
+    // exception handling code.
+    test->Run();
+  }
+
+  // Deletes the test object.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      test, &Test::DeleteSelf_, "the test fixture's destructor");
+
+  result_.set_elapsed_time(internal::GetTimeInMillis() - start);
+
+  // Notifies the unit test event listener that a test has just finished.
+  repeater->OnTestEnd(*this);
+
+  // Tells UnitTest to stop associating assertion results to this
+  // test.
+  impl->set_current_test_info(NULL);
+}
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+  return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+  return CountIf(test_info_list_, TestFailed);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int TestCase::reportable_disabled_test_count() const {
+  return CountIf(test_info_list_, TestReportableDisabled);
+}
+
+// Gets the number of disabled tests in this test case.
+int TestCase::disabled_test_count() const {
+  return CountIf(test_info_list_, TestDisabled);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int TestCase::reportable_test_count() const {
+  return CountIf(test_info_list_, TestReportable);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+  return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+  return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+//   name:         name of the test case
+//   a_type_param: the name of the test case's type parameter, or NULL if
+//                 this is not a typed or a type-parameterized test case.
+//   set_up_tc:    pointer to the function that sets up the test case
+//   tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* a_name, const char* a_type_param,
+                   Test::SetUpTestCaseFunc set_up_tc,
+                   Test::TearDownTestCaseFunc tear_down_tc)
+    : name_(a_name),
+      type_param_(a_type_param ? new std::string(a_type_param) : NULL),
+      set_up_tc_(set_up_tc),
+      tear_down_tc_(tear_down_tc),
+      should_run_(false),
+      elapsed_time_(0) {
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+  // Deletes every Test in the collection.
+  ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+const TestInfo* TestCase::GetTestInfo(int i) const {
+  const int index = GetElementOr(test_indices_, i, -1);
+  return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+TestInfo* TestCase::GetMutableTestInfo(int i) {
+  const int index = GetElementOr(test_indices_, i, -1);
+  return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Adds a test to this test case.  Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+  test_info_list_.push_back(test_info);
+  test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+  if (!should_run_) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_case(this);
+
+  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+  repeater->OnTestCaseStart(*this);
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
+
+  const internal::TimeInMillis start = internal::GetTimeInMillis();
+  for (int i = 0; i < total_test_count(); i++) {
+    GetMutableTestInfo(i)->Run();
+  }
+  elapsed_time_ = internal::GetTimeInMillis() - start;
+
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  internal::HandleExceptionsInMethodIfSupported(
+      this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
+
+  repeater->OnTestCaseEnd(*this);
+  impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+  ad_hoc_test_result_.Clear();
+  ForEach(test_info_list_, TestInfo::ClearTestResult);
+}
+
+// Shuffles the tests in this test case.
+void TestCase::ShuffleTests(internal::Random* random) {
+  Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestCase::UnshuffleTests() {
+  for (size_t i = 0; i < test_indices_.size(); i++) {
+    test_indices_[i] = static_cast<int>(i);
+  }
+}
+
+// Formats a countable noun.  Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static std::string FormatCountableNoun(int count,
+                                       const char * singular_form,
+                                       const char * plural_form) {
+  return internal::StreamableToString(count) + " " +
+      (count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static std::string FormatTestCount(int test_count) {
+  return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static std::string FormatTestCaseCount(int test_case_count) {
+  return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResult::Type enum to human-friendly string
+// representation.  Both kNonFatalFailure and kFatalFailure are translated
+// to "Failure", as the user usually doesn't care about the difference
+// between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResult::Type type) {
+  switch (type) {
+    case TestPartResult::kSuccess:
+      return "Success";
+
+    case TestPartResult::kNonFatalFailure:
+    case TestPartResult::kFatalFailure:
+#ifdef _MSC_VER
+      return "error: ";
+#else
+      return "Failure\n";
+#endif
+    default:
+      return "Unknown result type";
+  }
+}
+
+namespace internal {
+
+// Prints a TestPartResult to an std::string.
+static std::string PrintTestPartResultToString(
+    const TestPartResult& test_part_result) {
+  return (Message()
+          << internal::FormatFileLocation(test_part_result.file_name(),
+                                          test_part_result.line_number())
+          << " " << TestPartResultTypeToString(test_part_result.type())
+          << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(const TestPartResult& test_part_result) {
+  const std::string& result =
+      PrintTestPartResultToString(test_part_result);
+  printf("%s\n", result.c_str());
+  fflush(stdout);
+  // If the test program runs in Visual Studio or a debugger, the
+  // following statements add the test part result message to the Output
+  // window such that the user can double-click on it to jump to the
+  // corresponding source code location; otherwise they do nothing.
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+  // We don't call OutputDebugString*() on Windows Mobile, as printing
+  // to stdout is done by OutputDebugString() there already - we don't
+  // want the same message printed twice.
+  ::OutputDebugStringA(result.c_str());
+  ::OutputDebugStringA("\n");
+#endif
+}
+
+// class PrettyUnitTestResultPrinter
+
+enum GTestColor {
+  COLOR_DEFAULT,
+  COLOR_RED,
+  COLOR_GREEN,
+  COLOR_YELLOW
+};
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+  switch (color) {
+    case COLOR_RED:    return FOREGROUND_RED;
+    case COLOR_GREEN:  return FOREGROUND_GREEN;
+    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+    default:           return 0;
+  }
+}
+
+#else
+
+// Returns the ANSI color code for the given color.  COLOR_DEFAULT is
+// an invalid input.
+const char* GetAnsiColorCode(GTestColor color) {
+  switch (color) {
+    case COLOR_RED:     return "1";
+    case COLOR_GREEN:   return "2";
+    case COLOR_YELLOW:  return "3";
+    default:            return NULL;
+  };
+}
+
+#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+  const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+  if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS
+    // On Windows the TERM variable is usually not set, but the
+    // console there does support colors.
+    return stdout_is_tty;
+#else
+    // On non-Windows platforms, we rely on the TERM variable.
+    const char* const term = posix::GetEnv("TERM");
+    const bool term_supports_color =
+        String::CStringEquals(term, "xterm") ||
+        String::CStringEquals(term, "xterm-color") ||
+        String::CStringEquals(term, "xterm-256color") ||
+        String::CStringEquals(term, "screen") ||
+        String::CStringEquals(term, "screen-256color") ||
+        String::CStringEquals(term, "linux") ||
+        String::CStringEquals(term, "cygwin");
+    return stdout_is_tty && term_supports_color;
+#endif  // GTEST_OS_WINDOWS
+  }
+
+  return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+      String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+      String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+      String::CStringEquals(gtest_color, "1");
+  // We take "yes", "true", "t", and "1" as meaning "yes".  If the
+  // value is neither one of these nor "auto", we treat it as "no" to
+  // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS
+  const bool use_color = false;
+#else
+  static const bool in_color_mode =
+      ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+  const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+#endif  // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+  // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+  if (!use_color) {
+    vprintf(fmt, args);
+    va_end(args);
+    return;
+  }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+  const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+  // Gets the current text color.
+  CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+  GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+  const WORD old_color_attrs = buffer_info.wAttributes;
+
+  // We need to flush the stream buffers into the console before each
+  // SetConsoleTextAttribute call lest it affect the text that is already
+  // printed but has not yet reached the console.
+  fflush(stdout);
+  SetConsoleTextAttribute(stdout_handle,
+                          GetColorAttribute(color) | FOREGROUND_INTENSITY);
+  vprintf(fmt, args);
+
+  fflush(stdout);
+  // Restores the text color.
+  SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+  printf("\033[0;3%sm", GetAnsiColorCode(color));
+  vprintf(fmt, args);
+  printf("\033[m");  // Resets the terminal to default.
+#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+  va_end(args);
+}
+
+// Text printed in Google Test's text output and --gunit_list_tests
+// output to label the type parameter and value parameter for a test.
+static const char kTypeParamLabel[] = "TypeParam";
+static const char kValueParamLabel[] = "GetParam()";
+
+void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
+  const char* const type_param = test_info.type_param();
+  const char* const value_param = test_info.value_param();
+
+  if (type_param != NULL || value_param != NULL) {
+    printf(", where ");
+    if (type_param != NULL) {
+      printf("%s = %s", kTypeParamLabel, type_param);
+      if (value_param != NULL)
+        printf(" and ");
+    }
+    if (value_param != NULL) {
+      printf("%s = %s", kValueParamLabel, value_param);
+    }
+  }
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener {
+ public:
+  PrettyUnitTestResultPrinter() {}
+  static void PrintTestName(const char * test_case, const char * test) {
+    printf("%s.%s", test_case, test);
+  }
+
+  // The following methods override what's in the TestEventListener class.
+  virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestCaseStart(const TestCase& test_case);
+  virtual void OnTestStart(const TestInfo& test_info);
+  virtual void OnTestPartResult(const TestPartResult& result);
+  virtual void OnTestEnd(const TestInfo& test_info);
+  virtual void OnTestCaseEnd(const TestCase& test_case);
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+  virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+
+ private:
+  static void PrintFailedTests(const UnitTest& unit_test);
+};
+
+  // Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+    const UnitTest& unit_test, int iteration) {
+  if (GTEST_FLAG(repeat) != 1)
+    printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+  const char* const filter = GTEST_FLAG(filter).c_str();
+
+  // Prints the filter if it's not *.  This reminds the user that some
+  // tests may be skipped.
+  if (!String::CStringEquals(filter, kUniversalFilter)) {
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: %s filter = %s\n", GTEST_NAME_, filter);
+  }
+
+  if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+    const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: This is test shard %d of %s.\n",
+                  static_cast<int>(shard_index) + 1,
+                  internal::posix::GetEnv(kTestTotalShards));
+  }
+
+  if (GTEST_FLAG(shuffle)) {
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: Randomizing tests' orders with a seed of %d .\n",
+                  unit_test.random_seed());
+  }
+
+  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  printf("Running %s from %s.\n",
+         FormatTestCount(unit_test.test_to_run_count()).c_str(),
+         FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+    const UnitTest& /*unit_test*/) {
+  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  printf("Global test environment set-up.\n");
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+  const std::string counts =
+      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  printf("%s from %s", counts.c_str(), test_case.name());
+  if (test_case.type_param() == NULL) {
+    printf("\n");
+  } else {
+    printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
+  }
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
+  ColoredPrintf(COLOR_GREEN,  "[ RUN      ] ");
+  PrintTestName(test_info.test_case_name(), test_info.name());
+  printf("\n");
+  fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+    const TestPartResult& result) {
+  // If the test part succeeded, we don't need to do anything.
+  if (result.type() == TestPartResult::kSuccess)
+    return;
+
+  // Print failure message from the assertion (e.g. expected this and got that).
+  PrintTestPartResult(result);
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+  if (test_info.result()->Passed()) {
+    ColoredPrintf(COLOR_GREEN, "[       OK ] ");
+  } else {
+    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+  }
+  PrintTestName(test_info.test_case_name(), test_info.name());
+  if (test_info.result()->Failed())
+    PrintFullTestCommentIfPresent(test_info);
+
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms)\n", internal::StreamableToString(
+           test_info.result()->elapsed_time()).c_str());
+  } else {
+    printf("\n");
+  }
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+  if (!GTEST_FLAG(print_time)) return;
+
+  const std::string counts =
+      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  printf("%s from %s (%s ms total)\n\n",
+         counts.c_str(), test_case.name(),
+         internal::StreamableToString(test_case.elapsed_time()).c_str());
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+    const UnitTest& /*unit_test*/) {
+  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  printf("Global test environment tear-down\n");
+  fflush(stdout);
+}
+
+// Internal helper for printing the list of failed tests.
+void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
+  const int failed_test_count = unit_test.failed_test_count();
+  if (failed_test_count == 0) {
+    return;
+  }
+
+  for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+    const TestCase& test_case = *unit_test.GetTestCase(i);
+    if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
+      continue;
+    }
+    for (int j = 0; j < test_case.total_test_count(); ++j) {
+      const TestInfo& test_info = *test_case.GetTestInfo(j);
+      if (!test_info.should_run() || test_info.result()->Passed()) {
+        continue;
+      }
+      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+      printf("%s.%s", test_case.name(), test_info.name());
+      PrintFullTestCommentIfPresent(test_info);
+      printf("\n");
+    }
+  }
+}
+
+void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+                                                     int /*iteration*/) {
+  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  printf("%s from %s ran.",
+         FormatTestCount(unit_test.test_to_run_count()).c_str(),
+         FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms total)",
+           internal::StreamableToString(unit_test.elapsed_time()).c_str());
+  }
+  printf("\n");
+  ColoredPrintf(COLOR_GREEN,  "[  PASSED  ] ");
+  printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+  int num_failures = unit_test.failed_test_count();
+  if (!unit_test.Passed()) {
+    const int failed_test_count = unit_test.failed_test_count();
+    ColoredPrintf(COLOR_RED,  "[  FAILED  ] ");
+    printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+    PrintFailedTests(unit_test);
+    printf("\n%2d FAILED %s\n", num_failures,
+                        num_failures == 1 ? "TEST" : "TESTS");
+  }
+
+  int num_disabled = unit_test.reportable_disabled_test_count();
+  if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+    if (!num_failures) {
+      printf("\n");  // Add a spacer if no FAILURE banner is displayed.
+    }
+    ColoredPrintf(COLOR_YELLOW,
+                  "  YOU HAVE %d DISABLED %s\n\n",
+                  num_disabled,
+                  num_disabled == 1 ? "TEST" : "TESTS");
+  }
+  // Ensure that Google Test output is printed before, e.g., heapchecker output.
+  fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener {
+ public:
+  TestEventRepeater() : forwarding_enabled_(true) {}
+  virtual ~TestEventRepeater();
+  void Append(TestEventListener *listener);
+  TestEventListener* Release(TestEventListener* listener);
+
+  // Controls whether events will be forwarded to listeners_. Set to false
+  // in death test child processes.
+  bool forwarding_enabled() const { return forwarding_enabled_; }
+  void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
+
+  virtual void OnTestProgramStart(const UnitTest& unit_test);
+  virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+  virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
+  virtual void OnTestCaseStart(const TestCase& test_case);
+  virtual void OnTestStart(const TestInfo& test_info);
+  virtual void OnTestPartResult(const TestPartResult& result);
+  virtual void OnTestEnd(const TestInfo& test_info);
+  virtual void OnTestCaseEnd(const TestCase& test_case);
+  virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+  virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
+  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+  virtual void OnTestProgramEnd(const UnitTest& unit_test);
+
+ private:
+  // Controls whether events will be forwarded to listeners_. Set to false
+  // in death test child processes.
+  bool forwarding_enabled_;
+  // The list of listeners that receive events.
+  std::vector<TestEventListener*> listeners_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
+};
+
+TestEventRepeater::~TestEventRepeater() {
+  ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener *listener) {
+  listeners_.push_back(listener);
+}
+
+// TODO(vladl at google.com): Factor the search functionality into Vector::Find.
+TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
+  for (size_t i = 0; i < listeners_.size(); ++i) {
+    if (listeners_[i] == listener) {
+      listeners_.erase(listeners_.begin() + i);
+      return listener;
+    }
+  }
+
+  return NULL;
+}
+
+// Since most methods are very similar, use macros to reduce boilerplate.
+// This defines a member that forwards the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+  if (forwarding_enabled_) { \
+    for (size_t i = 0; i < listeners_.size(); i++) { \
+      listeners_[i]->Name(parameter); \
+    } \
+  } \
+}
+// This defines a member that forwards the call to all listeners in reverse
+// order.
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+  if (forwarding_enabled_) { \
+    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
+      listeners_[i]->Name(parameter); \
+    } \
+  } \
+}
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
+GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
+
+#undef GTEST_REPEATER_METHOD_
+#undef GTEST_REVERSE_REPEATER_METHOD_
+
+void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
+                                             int iteration) {
+  if (forwarding_enabled_) {
+    for (size_t i = 0; i < listeners_.size(); i++) {
+      listeners_[i]->OnTestIterationStart(unit_test, iteration);
+    }
+  }
+}
+
+void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
+                                           int iteration) {
+  if (forwarding_enabled_) {
+    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
+      listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+    }
+  }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+  explicit XmlUnitTestResultPrinter(const char* output_file);
+
+  virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+
+ private:
+  // Is c a whitespace character that is normalized to a space character
+  // when it appears in an XML attribute value?
+  static bool IsNormalizableWhitespace(char c) {
+    return c == 0x9 || c == 0xA || c == 0xD;
+  }
+
+  // May c appear in a well-formed XML document?
+  static bool IsValidXmlCharacter(char c) {
+    return IsNormalizableWhitespace(c) || c >= 0x20;
+  }
+
+  // Returns an XML-escaped copy of the input string str.  If
+  // is_attribute is true, the text is meant to appear as an attribute
+  // value, and normalizable whitespace is preserved by replacing it
+  // with character references.
+  static std::string EscapeXml(const std::string& str, bool is_attribute);
+
+  // Returns the given string with all characters invalid in XML removed.
+  static std::string RemoveInvalidXmlCharacters(const std::string& str);
+
+  // Convenience wrapper around EscapeXml when str is an attribute value.
+  static std::string EscapeXmlAttribute(const std::string& str) {
+    return EscapeXml(str, true);
+  }
+
+  // Convenience wrapper around EscapeXml when str is not an attribute value.
+  static std::string EscapeXmlText(const char* str) {
+    return EscapeXml(str, false);
+  }
+
+  // Verifies that the given attribute belongs to the given element and
+  // streams the attribute as XML.
+  static void OutputXmlAttribute(std::ostream* stream,
+                                 const std::string& element_name,
+                                 const std::string& name,
+                                 const std::string& value);
+
+  // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+  static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+  // Streams an XML representation of a TestInfo object.
+  static void OutputXmlTestInfo(::std::ostream* stream,
+                                const char* test_case_name,
+                                const TestInfo& test_info);
+
+  // Prints an XML representation of a TestCase object
+  static void PrintXmlTestCase(::std::ostream* stream,
+                               const TestCase& test_case);
+
+  // Prints an XML summary of unit_test to output stream out.
+  static void PrintXmlUnitTest(::std::ostream* stream,
+                               const UnitTest& unit_test);
+
+  // Produces a string representing the test properties in a result as space
+  // delimited XML attributes based on the property key="value" pairs.
+  // When the std::string is not empty, it includes a space at the beginning,
+  // to delimit this attribute from prior attributes.
+  static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
+
+  // The output file.
+  const std::string output_file_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+    : output_file_(output_file) {
+  if (output_file_.c_str() == NULL || output_file_.empty()) {
+    fprintf(stderr, "XML output file may not be null\n");
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+                                                  int /*iteration*/) {
+  FILE* xmlout = NULL;
+  FilePath output_file(output_file_);
+  FilePath output_dir(output_file.RemoveFileName());
+
+  if (output_dir.CreateDirectoriesRecursively()) {
+    xmlout = posix::FOpen(output_file_.c_str(), "w");
+  }
+  if (xmlout == NULL) {
+    // TODO(wan): report the reason of the failure.
+    //
+    // We don't do it for now as:
+    //
+    //   1. There is no urgent need for it.
+    //   2. It's a bit involved to make the errno variable thread-safe on
+    //      all three operating systems (Linux, Windows, and Mac OS).
+    //   3. To interpret the meaning of errno in a thread-safe way,
+    //      we need the strerror_r() function, which is not available on
+    //      Windows.
+    fprintf(stderr,
+            "Unable to open file \"%s\"\n",
+            output_file_.c_str());
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+  std::stringstream stream;
+  PrintXmlUnitTest(&stream, unit_test);
+  fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+  fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str.  If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+std::string XmlUnitTestResultPrinter::EscapeXml(
+    const std::string& str, bool is_attribute) {
+  Message m;
+
+  for (size_t i = 0; i < str.size(); ++i) {
+    const char ch = str[i];
+    switch (ch) {
+      case '<':
+        m << "<";
+        break;
+      case '>':
+        m << ">";
+        break;
+      case '&':
+        m << "&";
+        break;
+      case '\'':
+        if (is_attribute)
+          m << "'";
+        else
+          m << '\'';
+        break;
+      case '"':
+        if (is_attribute)
+          m << """;
+        else
+          m << '"';
+        break;
+      default:
+        if (IsValidXmlCharacter(ch)) {
+          if (is_attribute && IsNormalizableWhitespace(ch))
+            m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
+              << ";";
+          else
+            m << ch;
+        }
+        break;
+    }
+  }
+
+  return m.GetString();
+}
+
+// Returns the given string with all characters invalid in XML removed.
+// Currently invalid characters are dropped from the string. An
+// alternative is to replace them with certain characters such as . or ?.
+std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
+    const std::string& str) {
+  std::string output;
+  output.reserve(str.size());
+  for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
+    if (IsValidXmlCharacter(*it))
+      output.push_back(*it);
+
+  return output;
+}
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests">        <-- corresponds to a UnitTest object
+//   <testsuite name="testcase-name">  <-- corresponds to a TestCase object
+//     <testcase name="test-name">     <-- corresponds to a TestInfo object
+//       <failure message="...">...</failure>
+//       <failure message="...">...</failure>
+//       <failure message="...">...</failure>
+//                                     <-- individual assertion failures
+//     </testcase>
+//   </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+  ::std::stringstream ss;
+  ss << ms/1000.0;
+  return ss.str();
+}
+
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
+  // Using non-reentrant version as localtime_r is not portable.
+  time_t seconds = static_cast<time_t>(ms / 1000);
+#ifdef _MSC_VER
+# pragma warning(push)          // Saves the current warning state.
+# pragma warning(disable:4996)  // Temporarily disables warning 4996
+                                // (function or variable may be unsafe).
+  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
+# pragma warning(pop)           // Restores the warning state again.
+#else
+  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
+#endif
+  if (time_struct == NULL)
+    return "";  // Invalid ms value
+
+  // YYYY-MM-DDThh:mm:ss
+  return StreamableToString(time_struct->tm_year + 1900) + "-" +
+      String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
+      String::FormatIntWidth2(time_struct->tm_mday) + "T" +
+      String::FormatIntWidth2(time_struct->tm_hour) + ":" +
+      String::FormatIntWidth2(time_struct->tm_min) + ":" +
+      String::FormatIntWidth2(time_struct->tm_sec);
+}
+
+// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
+                                                     const char* data) {
+  const char* segment = data;
+  *stream << "<![CDATA[";
+  for (;;) {
+    const char* const next_segment = strstr(segment, "]]>");
+    if (next_segment != NULL) {
+      stream->write(
+          segment, static_cast<std::streamsize>(next_segment - segment));
+      *stream << "]]>]]><![CDATA[";
+      segment = next_segment + strlen("]]>");
+    } else {
+      *stream << segment;
+      break;
+    }
+  }
+  *stream << "]]>";
+}
+
+void XmlUnitTestResultPrinter::OutputXmlAttribute(
+    std::ostream* stream,
+    const std::string& element_name,
+    const std::string& name,
+    const std::string& value) {
+  const std::vector<std::string>& allowed_names =
+      GetReservedAttributesForElement(element_name);
+
+  GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+                   allowed_names.end())
+      << "Attribute " << name << " is not allowed for element <" << element_name
+      << ">.";
+
+  *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
+}
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+                                                 const char* test_case_name,
+                                                 const TestInfo& test_info) {
+  const TestResult& result = *test_info.result();
+  const std::string kTestcase = "testcase";
+
+  *stream << "    <testcase";
+  OutputXmlAttribute(stream, kTestcase, "name", test_info.name());
+
+  if (test_info.value_param() != NULL) {
+    OutputXmlAttribute(stream, kTestcase, "value_param",
+                       test_info.value_param());
+  }
+  if (test_info.type_param() != NULL) {
+    OutputXmlAttribute(stream, kTestcase, "type_param", test_info.type_param());
+  }
+
+  OutputXmlAttribute(stream, kTestcase, "status",
+                     test_info.should_run() ? "run" : "notrun");
+  OutputXmlAttribute(stream, kTestcase, "time",
+                     FormatTimeInMillisAsSeconds(result.elapsed_time()));
+  OutputXmlAttribute(stream, kTestcase, "classname", test_case_name);
+  *stream << TestPropertiesAsXmlAttributes(result);
+
+  int failures = 0;
+  for (int i = 0; i < result.total_part_count(); ++i) {
+    const TestPartResult& part = result.GetTestPartResult(i);
+    if (part.failed()) {
+      if (++failures == 1) {
+        *stream << ">\n";
+      }
+      const string location = internal::FormatCompilerIndependentFileLocation(
+          part.file_name(), part.line_number());
+      const string summary = location + "\n" + part.summary();
+      *stream << "      <failure message=\""
+              << EscapeXmlAttribute(summary.c_str())
+              << "\" type=\"\">";
+      const string detail = location + "\n" + part.message();
+      OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+      *stream << "</failure>\n";
+    }
+  }
+
+  if (failures == 0)
+    *stream << " />\n";
+  else
+    *stream << "    </testcase>\n";
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream,
+                                                const TestCase& test_case) {
+  const std::string kTestsuite = "testsuite";
+  *stream << "  <" << kTestsuite;
+  OutputXmlAttribute(stream, kTestsuite, "name", test_case.name());
+  OutputXmlAttribute(stream, kTestsuite, "tests",
+                     StreamableToString(test_case.reportable_test_count()));
+  OutputXmlAttribute(stream, kTestsuite, "failures",
+                     StreamableToString(test_case.failed_test_count()));
+  OutputXmlAttribute(
+      stream, kTestsuite, "disabled",
+      StreamableToString(test_case.reportable_disabled_test_count()));
+  OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+  OutputXmlAttribute(stream, kTestsuite, "time",
+                     FormatTimeInMillisAsSeconds(test_case.elapsed_time()));
+  *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result())
+          << ">\n";
+
+  for (int i = 0; i < test_case.total_test_count(); ++i) {
+    if (test_case.GetTestInfo(i)->is_reportable())
+      OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i));
+  }
+  *stream << "  </" << kTestsuite << ">\n";
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
+                                                const UnitTest& unit_test) {
+  const std::string kTestsuites = "testsuites";
+
+  *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+  *stream << "<" << kTestsuites;
+
+  OutputXmlAttribute(stream, kTestsuites, "tests",
+                     StreamableToString(unit_test.reportable_test_count()));
+  OutputXmlAttribute(stream, kTestsuites, "failures",
+                     StreamableToString(unit_test.failed_test_count()));
+  OutputXmlAttribute(
+      stream, kTestsuites, "disabled",
+      StreamableToString(unit_test.reportable_disabled_test_count()));
+  OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+  OutputXmlAttribute(
+      stream, kTestsuites, "timestamp",
+      FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
+  OutputXmlAttribute(stream, kTestsuites, "time",
+                     FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
+
+  if (GTEST_FLAG(shuffle)) {
+    OutputXmlAttribute(stream, kTestsuites, "random_seed",
+                       StreamableToString(unit_test.random_seed()));
+  }
+
+  *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
+
+  OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+  *stream << ">\n";
+
+  for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+    if (unit_test.GetTestCase(i)->reportable_test_count() > 0)
+      PrintXmlTestCase(stream, *unit_test.GetTestCase(i));
+  }
+  *stream << "</" << kTestsuites << ">\n";
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+    const TestResult& result) {
+  Message attributes;
+  for (int i = 0; i < result.test_property_count(); ++i) {
+    const TestProperty& property = result.GetTestProperty(i);
+    attributes << " " << property.key() << "="
+        << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+  }
+  return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
+// replaces them by "%xx" where xx is their hexadecimal value. For
+// example, replaces "=" with "%3D".  This algorithm is O(strlen(str))
+// in both time and space -- important as the input str may contain an
+// arbitrarily long test failure message and stack trace.
+string StreamingListener::UrlEncode(const char* str) {
+  string result;
+  result.reserve(strlen(str) + 1);
+  for (char ch = *str; ch != '\0'; ch = *++str) {
+    switch (ch) {
+      case '%':
+      case '=':
+      case '&':
+      case '\n':
+        result.append("%" + String::FormatByte(static_cast<unsigned char>(ch)));
+        break;
+      default:
+        result.push_back(ch);
+        break;
+    }
+  }
+  return result;
+}
+
+void StreamingListener::SocketWriter::MakeConnection() {
+  GTEST_CHECK_(sockfd_ == -1)
+      << "MakeConnection() can't be called when there is already a connection.";
+
+  addrinfo hints;
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;    // To allow both IPv4 and IPv6 addresses.
+  hints.ai_socktype = SOCK_STREAM;
+  addrinfo* servinfo = NULL;
+
+  // Use the getaddrinfo() to get a linked list of IP addresses for
+  // the given host name.
+  const int error_num = getaddrinfo(
+      host_name_.c_str(), port_num_.c_str(), &hints, &servinfo);
+  if (error_num != 0) {
+    GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
+                        << gai_strerror(error_num);
+  }
+
+  // Loop through all the results and connect to the first we can.
+  for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL;
+       cur_addr = cur_addr->ai_next) {
+    sockfd_ = socket(
+        cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
+    if (sockfd_ != -1) {
+      // Connect the client socket to the server socket.
+      if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) {
+        close(sockfd_);
+        sockfd_ = -1;
+      }
+    }
+  }
+
+  freeaddrinfo(servinfo);  // all done with this structure
+
+  if (sockfd_ == -1) {
+    GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "
+                        << host_name_ << ":" << port_num_;
+  }
+}
+
+// End of class Streaming Listener
+#endif  // GTEST_CAN_STREAM_RESULTS__
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message)
+    GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+  TraceInfo trace;
+  trace.file = file;
+  trace.line = line;
+  trace.message = message.GetString();
+
+  UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+ScopedTrace::~ScopedTrace()
+    GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+  UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as an std::string.  Parameters:
+//
+//   max_depth  - the maximum number of stack frames to be included
+//                in the trace.
+//   skip_count - the number of top frames to be skipped; doesn't count
+//                against max_depth.
+//
+string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
+                                             int /* skip_count */)
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  return "";
+}
+
+void OsStackTraceGetter::UponLeavingGTest()
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+    "... " GTEST_NAME_ " internal frames ...";
+
+// A helper class that creates the premature-exit file in its
+// constructor and deletes the file in its destructor.
+class ScopedPrematureExitFile {
+ public:
+  explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
+      : premature_exit_filepath_(premature_exit_filepath) {
+    // If a path to the premature-exit file is specified...
+    if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') {
+      // create the file with a single "0" character in it.  I/O
+      // errors are ignored as there's nothing better we can do and we
+      // don't want to fail the test because of this.
+      FILE* pfile = posix::FOpen(premature_exit_filepath, "w");
+      fwrite("0", 1, 1, pfile);
+      fclose(pfile);
+    }
+  }
+
+  ~ScopedPrematureExitFile() {
+    if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') {
+      remove(premature_exit_filepath_);
+    }
+  }
+
+ private:
+  const char* const premature_exit_filepath_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile);
+};
+
+}  // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+    : repeater_(new internal::TestEventRepeater()),
+      default_result_printer_(NULL),
+      default_xml_generator_(NULL) {
+}
+
+TestEventListeners::~TestEventListeners() { delete repeater_; }
+
+// Returns the standard listener responsible for the default console
+// output.  Can be removed from the listeners list to shut down default
+// console output.  Note that removing this object from the listener list
+// with Release transfers its ownership to the user.
+void TestEventListeners::Append(TestEventListener* listener) {
+  repeater_->Append(listener);
+}
+
+// Removes the given event listener from the list and returns it.  It then
+// becomes the caller's responsibility to delete the listener. Returns
+// NULL if the listener is not found in the list.
+TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
+  if (listener == default_result_printer_)
+    default_result_printer_ = NULL;
+  else if (listener == default_xml_generator_)
+    default_xml_generator_ = NULL;
+  return repeater_->Release(listener);
+}
+
+// Returns repeater that broadcasts the TestEventListener events to all
+// subscribers.
+TestEventListener* TestEventListeners::repeater() { return repeater_; }
+
+// Sets the default_result_printer attribute to the provided listener.
+// The listener is also added to the listener list and previous
+// default_result_printer is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
+  if (default_result_printer_ != listener) {
+    // It is an error to pass this method a listener that is already in the
+    // list.
+    delete Release(default_result_printer_);
+    default_result_printer_ = listener;
+    if (listener != NULL)
+      Append(listener);
+  }
+}
+
+// Sets the default_xml_generator attribute to the provided listener.  The
+// listener is also added to the listener list and previous
+// default_xml_generator is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
+  if (default_xml_generator_ != listener) {
+    // It is an error to pass this method a listener that is already in the
+    // list.
+    delete Release(default_xml_generator_);
+    default_xml_generator_ = listener;
+    if (listener != NULL)
+      Append(listener);
+  }
+}
+
+// Controls whether events will be forwarded by the repeater to the
+// listeners in the list.
+bool TestEventListeners::EventForwardingEnabled() const {
+  return repeater_->forwarding_enabled();
+}
+
+void TestEventListeners::SuppressEventForwarding() {
+  repeater_->set_forwarding_enabled(false);
+}
+
+// class UnitTest
+
+// Gets the singleton UnitTest object.  The first time this method is
+// called, a UnitTest object is constructed and returned.  Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest* UnitTest::GetInstance() {
+  // When compiled with MSVC 7.1 in optimized mode, destroying the
+  // UnitTest object upon exiting the program messes up the exit code,
+  // causing successful tests to appear failed.  We have to use a
+  // different implementation in this case to bypass the compiler bug.
+  // This implementation makes the compiler happy, at the cost of
+  // leaking the UnitTest object.
+
+  // CodeGear C++Builder insists on a public destructor for the
+  // default implementation.  Use this implementation to keep good OO
+  // design with private destructor.
+
+#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+  static UnitTest* const instance = new UnitTest;
+  return instance;
+#else
+  static UnitTest instance;
+  return &instance;
+#endif  // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+}
+
+// Gets the number of successful test cases.
+int UnitTest::successful_test_case_count() const {
+  return impl()->successful_test_case_count();
+}
+
+// Gets the number of failed test cases.
+int UnitTest::failed_test_case_count() const {
+  return impl()->failed_test_case_count();
+}
+
+// Gets the number of all test cases.
+int UnitTest::total_test_case_count() const {
+  return impl()->total_test_case_count();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTest::test_case_to_run_count() const {
+  return impl()->test_case_to_run_count();
+}
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const {
+  return impl()->successful_test_count();
+}
+
+// Gets the number of failed tests.
+int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTest::reportable_disabled_test_count() const {
+  return impl()->reportable_disabled_test_count();
+}
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const {
+  return impl()->disabled_test_count();
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTest::reportable_test_count() const {
+  return impl()->reportable_test_count();
+}
+
+// Gets the number of all tests.
+int UnitTest::total_test_count() const { return impl()->total_test_count(); }
+
+// Gets the number of tests that should run.
+int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
+
+// Gets the time of the test program start, in ms from the start of the
+// UNIX epoch.
+internal::TimeInMillis UnitTest::start_timestamp() const {
+    return impl()->start_timestamp();
+}
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const {
+  return impl()->elapsed_time();
+}
+
+// Returns true iff the unit test passed (i.e. all test cases passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true iff the unit test failed (i.e. some test case failed
+// or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+const TestCase* UnitTest::GetTestCase(int i) const {
+  return impl()->GetTestCase(i);
+}
+
+// Returns the TestResult containing information on test failures and
+// properties logged outside of individual test cases.
+const TestResult& UnitTest::ad_hoc_test_result() const {
+  return *impl()->ad_hoc_test_result();
+}
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+TestCase* UnitTest::GetMutableTestCase(int i) {
+  return impl()->GetMutableTestCase(i);
+}
+
+// Returns the list of event listeners that can be used to track events
+// inside Google Test.
+TestEventListeners& UnitTest::listeners() {
+  return *impl()->listeners();
+}
+
+// Registers and returns a global test environment.  When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered.  After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+  if (env == NULL) {
+    return NULL;
+  }
+
+  impl_->environments().push_back(env);
+  return env;
+}
+
+// Adds a TestPartResult to the current TestResult object.  All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results.  The user code should use the
+// assertion macros instead of calling this directly.
+void UnitTest::AddTestPartResult(
+    TestPartResult::Type result_type,
+    const char* file_name,
+    int line_number,
+    const std::string& message,
+    const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) {
+  Message msg;
+  msg << message;
+
+  internal::MutexLock lock(&mutex_);
+  if (impl_->gtest_trace_stack().size() > 0) {
+    msg << "\n" << GTEST_NAME_ << " trace:";
+
+    for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
+         i > 0; --i) {
+      const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
+      msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
+          << " " << trace.message;
+    }
+  }
+
+  if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+    msg << internal::kStackTraceMarker << os_stack_trace;
+  }
+
+  const TestPartResult result =
+    TestPartResult(result_type, file_name, line_number,
+                   msg.GetString().c_str());
+  impl_->GetTestPartResultReporterForCurrentThread()->
+      ReportTestPartResult(result);
+
+  if (result_type != TestPartResult::kSuccess) {
+    // gtest_break_on_failure takes precedence over
+    // gtest_throw_on_failure.  This allows a user to set the latter
+    // in the code (perhaps in order to use Google Test assertions
+    // with another testing framework) and specify the former on the
+    // command line for debugging.
+    if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS
+      // Using DebugBreak on Windows allows gtest to still break into a debugger
+      // when a failure happens and both the --gtest_break_on_failure and
+      // the --gtest_catch_exceptions flags are specified.
+      DebugBreak();
+#else
+      // Dereference NULL through a volatile pointer to prevent the compiler
+      // from removing. We use this rather than abort() or __builtin_trap() for
+      // portability: Symbian doesn't implement abort() well, and some debuggers
+      // don't correctly trap abort().
+      *static_cast<volatile int*>(NULL) = 1;
+#endif  // GTEST_OS_WINDOWS
+    } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+      throw internal::GoogleTestFailureException(result);
+#else
+      // We cannot call abort() as it generates a pop-up in debug mode
+      // that cannot be suppressed in VC 7.1 or below.
+      exit(1);
+#endif
+    }
+  }
+}
+
+// Adds a TestProperty to the current TestResult object when invoked from
+// inside a test, to current TestCase's ad_hoc_test_result_ when invoked
+// from SetUpTestCase or TearDownTestCase, or to the global property set
+// when invoked elsewhere.  If the result already contains a property with
+// the same key, the value will be updated.
+void UnitTest::RecordProperty(const std::string& key,
+                              const std::string& value) {
+  impl_->RecordProperty(TestProperty(key, value));
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+  const bool in_death_test_child_process =
+      internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+  // Google Test implements this protocol for catching that a test
+  // program exits before returning control to Google Test:
+  //
+  //   1. Upon start, Google Test creates a file whose absolute path
+  //      is specified by the environment variable
+  //      TEST_PREMATURE_EXIT_FILE.
+  //   2. When Google Test has finished its work, it deletes the file.
+  //
+  // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
+  // running a Google-Test-based test program and check the existence
+  // of the file at the end of the test execution to see if it has
+  // exited prematurely.
+
+  // If we are in the child process of a death test, don't
+  // create/delete the premature exit file, as doing so is unnecessary
+  // and will confuse the parent process.  Otherwise, create/delete
+  // the file upon entering/leaving this function.  If the program
+  // somehow exits before this function has a chance to return, the
+  // premature-exit file will be left undeleted, causing a test runner
+  // that understands the premature-exit-file protocol to report the
+  // test as having failed.
+  const internal::ScopedPrematureExitFile premature_exit_file(
+      in_death_test_child_process ?
+      NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
+
+  // Captures the value of GTEST_FLAG(catch_exceptions).  This value will be
+  // used for the duration of the program.
+  impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
+
+#if GTEST_HAS_SEH
+  // Either the user wants Google Test to catch exceptions thrown by the
+  // tests or this is executing in the context of death test child
+  // process. In either case the user does not want to see pop-up dialogs
+  // about crashes - they are expected.
+  if (impl()->catch_exceptions() || in_death_test_child_process) {
+# if !GTEST_OS_WINDOWS_MOBILE
+    // SetErrorMode doesn't exist on CE.
+    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+                 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+# endif  // !GTEST_OS_WINDOWS_MOBILE
+
+# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
+    // Death test children can be terminated with _abort().  On Windows,
+    // _abort() can show a dialog with a warning message.  This forces the
+    // abort message to go to stderr instead.
+    _set_error_mode(_OUT_TO_STDERR);
+# endif
+
+# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+    // In the debug version, Visual Studio pops up a separate dialog
+    // offering a choice to debug the aborted program. We need to suppress
+    // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+    // executed. Google Test will notify the user of any unexpected
+    // failure via stderr.
+    //
+    // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
+    // Users of prior VC versions shall suffer the agony and pain of
+    // clicking through the countless debug dialogs.
+    // TODO(vladl at google.com): find a way to suppress the abort dialog() in the
+    // debug mode when compiled with VC 7.1 or lower.
+    if (!GTEST_FLAG(break_on_failure))
+      _set_abort_behavior(
+          0x0,                                    // Clear the following flags:
+          _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
+# endif
+  }
+#endif  // GTEST_HAS_SEH
+
+  return internal::HandleExceptionsInMethodIfSupported(
+      impl(),
+      &internal::UnitTestImpl::RunAllTests,
+      "auxiliary test code (environments or event listeners)") ? 0 : 1;
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+  return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+const TestCase* UnitTest::current_test_case() const
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+const TestInfo* UnitTest::current_test_info() const
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  return impl_->current_test_info();
+}
+
+// Returns the random seed used at the start of the current test run.
+int UnitTest::random_seed() const { return impl_->random_seed(); }
+
+#if GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+internal::ParameterizedTestCaseRegistry&
+    UnitTest::parameterized_test_registry()
+        GTEST_LOCK_EXCLUDED_(mutex_) {
+  return impl_->parameterized_test_registry();
+}
+#endif  // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+  impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+  delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+void UnitTest::PopGTestTrace()
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  internal::MutexLock lock(&mutex_);
+  impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+    : parent_(parent),
+#ifdef _MSC_VER
+# pragma warning(push)                    // Saves the current warning state.
+# pragma warning(disable:4355)            // Temporarily disables warning 4355
+                                         // (using this in initializer).
+      default_global_test_part_result_reporter_(this),
+      default_per_thread_test_part_result_reporter_(this),
+# pragma warning(pop)                     // Restores the warning state again.
+#else
+      default_global_test_part_result_reporter_(this),
+      default_per_thread_test_part_result_reporter_(this),
+#endif  // _MSC_VER
+      global_test_part_result_repoter_(
+          &default_global_test_part_result_reporter_),
+      per_thread_test_part_result_reporter_(
+          &default_per_thread_test_part_result_reporter_),
+#if GTEST_HAS_PARAM_TEST
+      parameterized_test_registry_(),
+      parameterized_tests_registered_(false),
+#endif  // GTEST_HAS_PARAM_TEST
+      last_death_test_case_(-1),
+      current_test_case_(NULL),
+      current_test_info_(NULL),
+      ad_hoc_test_result_(),
+      os_stack_trace_getter_(NULL),
+      post_flag_parse_init_performed_(false),
+      random_seed_(0),  // Will be overridden by the flag before first use.
+      random_(0),  // Will be reseeded before first use.
+      start_timestamp_(0),
+      elapsed_time_(0),
+#if GTEST_HAS_DEATH_TEST
+      death_test_factory_(new DefaultDeathTestFactory),
+#endif
+      // Will be overridden by the flag before first use.
+      catch_exceptions_(false) {
+  listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
+}
+
+UnitTestImpl::~UnitTestImpl() {
+  // Deletes every TestCase.
+  ForEach(test_cases_, internal::Delete<TestCase>);
+
+  // Deletes every Environment.
+  ForEach(environments_, internal::Delete<Environment>);
+
+  delete os_stack_trace_getter_;
+}
+
+// Adds a TestProperty to the current TestResult object when invoked in a
+// context of a test, to current test case's ad_hoc_test_result when invoke
+// from SetUpTestCase/TearDownTestCase, or to the global property set
+// otherwise.  If the result already contains a property with the same key,
+// the value will be updated.
+void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
+  std::string xml_element;
+  TestResult* test_result;  // TestResult appropriate for property recording.
+
+  if (current_test_info_ != NULL) {
+    xml_element = "testcase";
+    test_result = &(current_test_info_->result_);
+  } else if (current_test_case_ != NULL) {
+    xml_element = "testsuite";
+    test_result = &(current_test_case_->ad_hoc_test_result_);
+  } else {
+    xml_element = "testsuites";
+    test_result = &ad_hoc_test_result_;
+  }
+  test_result->RecordProperty(xml_element, test_property);
+}
+
+#if GTEST_HAS_DEATH_TEST
+// Disables event forwarding if the control is currently in a death test
+// subprocess. Must not be called before InitGoogleTest.
+void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
+  if (internal_run_death_test_flag_.get() != NULL)
+    listeners()->SuppressEventForwarding();
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+// Initializes event listeners performing XML output as specified by
+// UnitTestOptions. Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureXmlOutput() {
+  const std::string& output_format = UnitTestOptions::GetOutputFormat();
+  if (output_format == "xml") {
+    listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+        UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+  } else if (output_format != "") {
+    printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+           output_format.c_str());
+    fflush(stdout);
+  }
+}
+
+#if GTEST_CAN_STREAM_RESULTS_
+// Initializes event listeners for streaming test results in string form.
+// Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureStreamingOutput() {
+  const std::string& target = GTEST_FLAG(stream_result_to);
+  if (!target.empty()) {
+    const size_t pos = target.find(':');
+    if (pos != std::string::npos) {
+      listeners()->Append(new StreamingListener(target.substr(0, pos),
+                                                target.substr(pos+1)));
+    } else {
+      printf("WARNING: unrecognized streaming target \"%s\" ignored.\n",
+             target.c_str());
+      fflush(stdout);
+    }
+  }
+}
+#endif  // GTEST_CAN_STREAM_RESULTS_
+
+// Performs initialization dependent upon flag values obtained in
+// ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to
+// ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest
+// this function is also called from RunAllTests.  Since this function can be
+// called more than once, it has to be idempotent.
+void UnitTestImpl::PostFlagParsingInit() {
+  // Ensures that this function does not execute more than once.
+  if (!post_flag_parse_init_performed_) {
+    post_flag_parse_init_performed_ = true;
+
+#if GTEST_HAS_DEATH_TEST
+    InitDeathTestSubprocessControlInfo();
+    SuppressTestEventsIfInSubprocess();
+#endif  // GTEST_HAS_DEATH_TEST
+
+    // Registers parameterized tests. This makes parameterized tests
+    // available to the UnitTest reflection API without running
+    // RUN_ALL_TESTS.
+    RegisterParameterizedTests();
+
+    // Configures listeners for XML output. This makes it possible for users
+    // to shut down the default XML output before invoking RUN_ALL_TESTS.
+    ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+    // Configures listeners for streaming test results to the specified server.
+    ConfigureStreamingOutput();
+#endif  // GTEST_CAN_STREAM_RESULTS_
+  }
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only.  We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+  // Constructor.
+  explicit TestCaseNameIs(const std::string& name)
+      : name_(name) {}
+
+  // Returns true iff the name of test_case matches name_.
+  bool operator()(const TestCase* test_case) const {
+    return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+  }
+
+ private:
+  std::string name_;
+};
+
+// Finds and returns a TestCase with the given name.  If one doesn't
+// exist, creates one and returns it.  It's the CALLER'S
+// RESPONSIBILITY to ensure that this function is only called WHEN THE
+// TESTS ARE NOT SHUFFLED.
+//
+// Arguments:
+//
+//   test_case_name: name of the test case
+//   type_param:     the name of the test case's type parameter, or NULL if
+//                   this is not a typed or a type-parameterized test case.
+//   set_up_tc:      pointer to the function that sets up the test case
+//   tear_down_tc:   pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+                                    const char* type_param,
+                                    Test::SetUpTestCaseFunc set_up_tc,
+                                    Test::TearDownTestCaseFunc tear_down_tc) {
+  // Can we find a TestCase with the given name?
+  const std::vector<TestCase*>::const_iterator test_case =
+      std::find_if(test_cases_.begin(), test_cases_.end(),
+                   TestCaseNameIs(test_case_name));
+
+  if (test_case != test_cases_.end())
+    return *test_case;
+
+  // No.  Let's create one.
+  TestCase* const new_test_case =
+      new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc);
+
+  // Is this a death test case?
+  if (internal::UnitTestOptions::MatchesFilter(test_case_name,
+                                               kDeathTestCaseFilter)) {
+    // Yes.  Inserts the test case after the last death test case
+    // defined so far.  This only works when the test cases haven't
+    // been shuffled.  Otherwise we may end up running a death test
+    // after a non-death test.
+    ++last_death_test_case_;
+    test_cases_.insert(test_cases_.begin() + last_death_test_case_,
+                       new_test_case);
+  } else {
+    // No.  Appends to the end of the list.
+    test_cases_.push_back(new_test_case);
+  }
+
+  test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
+  return new_test_case;
+}
+
+// Helpers for setting up / tearing down the given environment.  They
+// are for use in the ForEach() function.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns true if all tests are successful.  If any exception is
+// thrown during a test, the test is considered to be failed, but the
+// rest of the tests will still be run.
+//
+// When parameterized tests are enabled, it expands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+bool UnitTestImpl::RunAllTests() {
+  // Makes sure InitGoogleTest() was called.
+  if (!GTestIsInitialized()) {
+    printf("%s",
+           "\nThis test program did NOT call ::testing::InitGoogleTest "
+           "before calling RUN_ALL_TESTS().  Please fix it.\n");
+    return false;
+  }
+
+  // Do not run any test if the --help flag was specified.
+  if (g_help_flag)
+    return true;
+
+  // Repeats the call to the post-flag parsing initialization in case the
+  // user didn't call InitGoogleTest.
+  PostFlagParsingInit();
+
+  // Even if sharding is not on, test runners may want to use the
+  // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+  // protocol.
+  internal::WriteToShardStatusFileIfNeeded();
+
+  // True iff we are in a subprocess for running a thread-safe-style
+  // death test.
+  bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+  in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif  // GTEST_HAS_DEATH_TEST
+
+  const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+                                        in_subprocess_for_death_test);
+
+  // Compares the full test names with the filter to decide which
+  // tests to run.
+  const bool has_tests_to_run = FilterTests(should_shard
+                                              ? HONOR_SHARDING_PROTOCOL
+                                              : IGNORE_SHARDING_PROTOCOL) > 0;
+
+  // Lists the tests and exits if the --gtest_list_tests flag was specified.
+  if (GTEST_FLAG(list_tests)) {
+    // This must be called *after* FilterTests() has been called.
+    ListTestsMatchingFilter();
+    return true;
+  }
+
+  random_seed_ = GTEST_FLAG(shuffle) ?
+      GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
+
+  // True iff at least one test has failed.
+  bool failed = false;
+
+  TestEventListener* repeater = listeners()->repeater();
+
+  start_timestamp_ = GetTimeInMillis();
+  repeater->OnTestProgramStart(*parent_);
+
+  // How many times to repeat the tests?  We don't want to repeat them
+  // when we are inside the subprocess of a death test.
+  const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+  // Repeats forever if the repeat count is negative.
+  const bool forever = repeat < 0;
+  for (int i = 0; forever || i != repeat; i++) {
+    // We want to preserve failures generated by ad-hoc test
+    // assertions executed before RUN_ALL_TESTS().
+    ClearNonAdHocTestResult();
+
+    const TimeInMillis start = GetTimeInMillis();
+
+    // Shuffles test cases and tests if requested.
+    if (has_tests_to_run && GTEST_FLAG(shuffle)) {
+      random()->Reseed(random_seed_);
+      // This should be done before calling OnTestIterationStart(),
+      // such that a test event listener can see the actual test order
+      // in the event.
+      ShuffleTests();
+    }
+
+    // Tells the unit test event listeners that the tests are about to start.
+    repeater->OnTestIterationStart(*parent_, i);
+
+    // Runs each test case if there is at least one test to run.
+    if (has_tests_to_run) {
+      // Sets up all environments beforehand.
+      repeater->OnEnvironmentsSetUpStart(*parent_);
+      ForEach(environments_, SetUpEnvironment);
+      repeater->OnEnvironmentsSetUpEnd(*parent_);
+
+      // Runs the tests only if there was no fatal failure during global
+      // set-up.
+      if (!Test::HasFatalFailure()) {
+        for (int test_index = 0; test_index < total_test_case_count();
+             test_index++) {
+          GetMutableTestCase(test_index)->Run();
+        }
+      }
+
+      // Tears down all environments in reverse order afterwards.
+      repeater->OnEnvironmentsTearDownStart(*parent_);
+      std::for_each(environments_.rbegin(), environments_.rend(),
+                    TearDownEnvironment);
+      repeater->OnEnvironmentsTearDownEnd(*parent_);
+    }
+
+    elapsed_time_ = GetTimeInMillis() - start;
+
+    // Tells the unit test event listener that the tests have just finished.
+    repeater->OnTestIterationEnd(*parent_, i);
+
+    // Gets the result and clears it.
+    if (!Passed()) {
+      failed = true;
+    }
+
+    // Restores the original test order after the iteration.  This
+    // allows the user to quickly repro a failure that happens in the
+    // N-th iteration without repeating the first (N - 1) iterations.
+    // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
+    // case the user somehow changes the value of the flag somewhere
+    // (it's always safe to unshuffle the tests).
+    UnshuffleTests();
+
+    if (GTEST_FLAG(shuffle)) {
+      // Picks a new random seed for each iteration.
+      random_seed_ = GetNextRandomSeed(random_seed_);
+    }
+  }
+
+  repeater->OnTestProgramEnd(*parent_);
+
+  return !failed;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded() {
+  const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+  if (test_shard_file != NULL) {
+    FILE* const file = posix::FOpen(test_shard_file, "w");
+    if (file == NULL) {
+      ColoredPrintf(COLOR_RED,
+                    "Could not write to the test shard status file \"%s\" "
+                    "specified by the %s environment variable.\n",
+                    test_shard_file, kTestShardStatusFile);
+      fflush(stdout);
+      exit(EXIT_FAILURE);
+    }
+    fclose(file);
+  }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+                 const char* shard_index_env,
+                 bool in_subprocess_for_death_test) {
+  if (in_subprocess_for_death_test) {
+    return false;
+  }
+
+  const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+  const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+  if (total_shards == -1 && shard_index == -1) {
+    return false;
+  } else if (total_shards == -1 && shard_index != -1) {
+    const Message msg = Message()
+      << "Invalid environment variables: you have "
+      << kTestShardIndex << " = " << shard_index
+      << ", but have left " << kTestTotalShards << " unset.\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  } else if (total_shards != -1 && shard_index == -1) {
+    const Message msg = Message()
+      << "Invalid environment variables: you have "
+      << kTestTotalShards << " = " << total_shards
+      << ", but have left " << kTestShardIndex << " unset.\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  } else if (shard_index < 0 || shard_index >= total_shards) {
+    const Message msg = Message()
+      << "Invalid environment variables: we require 0 <= "
+      << kTestShardIndex << " < " << kTestTotalShards
+      << ", but you have " << kTestShardIndex << "=" << shard_index
+      << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  }
+
+  return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
+  const char* str_val = posix::GetEnv(var);
+  if (str_val == NULL) {
+    return default_val;
+  }
+
+  Int32 result;
+  if (!ParseInt32(Message() << "The value of environment variable " << var,
+                  str_val, &result)) {
+    exit(EXIT_FAILURE);
+  }
+  return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
+  return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+  const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+      Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+  const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+      Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+  // num_runnable_tests are the number of tests that will
+  // run across all shards (i.e., match filter and are not disabled).
+  // num_selected_tests are the number of tests to be run on
+  // this shard.
+  int num_runnable_tests = 0;
+  int num_selected_tests = 0;
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    TestCase* const test_case = test_cases_[i];
+    const std::string &test_case_name = test_case->name();
+    test_case->set_should_run(false);
+
+    for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+      TestInfo* const test_info = test_case->test_info_list()[j];
+      const std::string test_name(test_info->name());
+      // A test is disabled if test case name or test name matches
+      // kDisableTestFilter.
+      const bool is_disabled =
+          internal::UnitTestOptions::MatchesFilter(test_case_name,
+                                                   kDisableTestFilter) ||
+          internal::UnitTestOptions::MatchesFilter(test_name,
+                                                   kDisableTestFilter);
+      test_info->is_disabled_ = is_disabled;
+
+      const bool matches_filter =
+          internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+                                                       test_name);
+      test_info->matches_filter_ = matches_filter;
+
+      const bool is_runnable =
+          (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+          matches_filter;
+
+      const bool is_selected = is_runnable &&
+          (shard_tests == IGNORE_SHARDING_PROTOCOL ||
+           ShouldRunTestOnShard(total_shards, shard_index,
+                                num_runnable_tests));
+
+      num_runnable_tests += is_runnable;
+      num_selected_tests += is_selected;
+
+      test_info->should_run_ = is_selected;
+      test_case->set_should_run(test_case->should_run() || is_selected);
+    }
+  }
+  return num_selected_tests;
+}
+
+// Prints the given C-string on a single line by replacing all '\n'
+// characters with string "\\n".  If the output takes more than
+// max_length characters, only prints the first max_length characters
+// and "...".
+static void PrintOnOneLine(const char* str, int max_length) {
+  if (str != NULL) {
+    for (int i = 0; *str != '\0'; ++str) {
+      if (i >= max_length) {
+        printf("...");
+        break;
+      }
+      if (*str == '\n') {
+        printf("\\n");
+        i += 2;
+      } else {
+        printf("%c", *str);
+        ++i;
+      }
+    }
+  }
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+  // Print at most this many characters for each type/value parameter.
+  const int kMaxParamLength = 250;
+
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    const TestCase* const test_case = test_cases_[i];
+    bool printed_test_case_name = false;
+
+    for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+      const TestInfo* const test_info =
+          test_case->test_info_list()[j];
+      if (test_info->matches_filter_) {
+        if (!printed_test_case_name) {
+          printed_test_case_name = true;
+          printf("%s.", test_case->name());
+          if (test_case->type_param() != NULL) {
+            printf("  # %s = ", kTypeParamLabel);
+            // We print the type parameter on a single line to make
+            // the output easy to parse by a program.
+            PrintOnOneLine(test_case->type_param(), kMaxParamLength);
+          }
+          printf("\n");
+        }
+        printf("  %s", test_info->name());
+        if (test_info->value_param() != NULL) {
+          printf("  # %s = ", kValueParamLabel);
+          // We print the value parameter on a single line to make the
+          // output easy to parse by a program.
+          PrintOnOneLine(test_info->value_param(), kMaxParamLength);
+        }
+        printf("\n");
+      }
+    }
+  }
+  fflush(stdout);
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+    OsStackTraceGetterInterface* getter) {
+  if (os_stack_trace_getter_ != getter) {
+    delete os_stack_trace_getter_;
+    os_stack_trace_getter_ = getter;
+  }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+  if (os_stack_trace_getter_ == NULL) {
+    os_stack_trace_getter_ = new OsStackTraceGetter;
+  }
+
+  return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+TestResult* UnitTestImpl::current_test_result() {
+  return current_test_info_ ?
+      &(current_test_info_->result_) : &ad_hoc_test_result_;
+}
+
+// Shuffles all test cases, and the tests within each test case,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests() {
+  // Shuffles the death test cases.
+  ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
+
+  // Shuffles the non-death test cases.
+  ShuffleRange(random(), last_death_test_case_ + 1,
+               static_cast<int>(test_cases_.size()), &test_case_indices_);
+
+  // Shuffles the tests inside each test case.
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    test_cases_[i]->ShuffleTests(random());
+  }
+}
+
+// Restores the test cases and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests() {
+  for (size_t i = 0; i < test_cases_.size(); i++) {
+    // Unshuffles the tests in each test case.
+    test_cases_[i]->UnshuffleTests();
+    // Resets the index of each test case.
+    test_case_indices_[i] = static_cast<int>(i);
+  }
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
+                                            int skip_count) {
+  // We pass skip_count + 1 to skip this wrapper function in addition
+  // to what the user really wants to skip.
+  return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
+// suppress unreachable code warnings.
+namespace {
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool IsTrue(bool condition) { return condition; }
+
+bool AlwaysTrue() {
+#if GTEST_HAS_EXCEPTIONS
+  // This condition is always false so AlwaysTrue() never actually throws,
+  // but it makes the compiler think that it may throw.
+  if (IsTrue(false))
+    throw ClassUniqueToAlwaysTrue();
+#endif  // GTEST_HAS_EXCEPTIONS
+  return true;
+}
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false.  None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr) {
+  const size_t prefix_len = strlen(prefix);
+  if (strncmp(*pstr, prefix, prefix_len) == 0) {
+    *pstr += prefix_len;
+    return true;
+  }
+  return false;
+}
+
+// Parses a string as a command line flag.  The string should have
+// the format "--flag=value".  When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+                           const char* flag,
+                           bool def_optional) {
+  // str and flag must not be NULL.
+  if (str == NULL || flag == NULL) return NULL;
+
+  // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+  const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag;
+  const size_t flag_len = flag_str.length();
+  if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+  // Skips the flag name.
+  const char* flag_end = str + flag_len;
+
+  // When def_optional is true, it's OK to not have a "=value" part.
+  if (def_optional && (flag_end[0] == '\0')) {
+    return flag_end;
+  }
+
+  // If def_optional is true and there are more characters after the
+  // flag name, or if def_optional is false, there must be a '=' after
+  // the flag name.
+  if (flag_end[0] != '=') return NULL;
+
+  // Returns the string after "=".
+  return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, true);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Converts the string value to a bool.
+  *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+  return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, false);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Sets *value to the value of the flag.
+  return ParseInt32(Message() << "The value of flag --" << flag,
+                    value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, std::string* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, false);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Sets *value to the value of the flag.
+  *value = value_str;
+  return true;
+}
+
+// Determines whether a string has a prefix that Google Test uses for its
+// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
+// If Google Test detects that a command line flag has its prefix but is not
+// recognized, it will print its help message. Flags starting with
+// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
+// internal flags and do not trigger the help message.
+static bool HasGoogleTestFlagPrefix(const char* str) {
+  return (SkipPrefix("--", &str) ||
+          SkipPrefix("-", &str) ||
+          SkipPrefix("/", &str)) &&
+         !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
+         (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
+          SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
+}
+
+// Prints a string containing code-encoded text.  The following escape
+// sequences can be used in the string to control the text color:
+//
+//   @@    prints a single '@' character.
+//   @R    changes the color to red.
+//   @G    changes the color to green.
+//   @Y    changes the color to yellow.
+//   @D    changes to the default terminal text color.
+//
+// TODO(wan at google.com): Write tests for this once we add stdout
+// capturing to Google Test.
+static void PrintColorEncoded(const char* str) {
+  GTestColor color = COLOR_DEFAULT;  // The current color.
+
+  // Conceptually, we split the string into segments divided by escape
+  // sequences.  Then we print one segment at a time.  At the end of
+  // each iteration, the str pointer advances to the beginning of the
+  // next segment.
+  for (;;) {
+    const char* p = strchr(str, '@');
+    if (p == NULL) {
+      ColoredPrintf(color, "%s", str);
+      return;
+    }
+
+    ColoredPrintf(color, "%s", std::string(str, p).c_str());
+
+    const char ch = p[1];
+    str = p + 2;
+    if (ch == '@') {
+      ColoredPrintf(color, "@");
+    } else if (ch == 'D') {
+      color = COLOR_DEFAULT;
+    } else if (ch == 'R') {
+      color = COLOR_RED;
+    } else if (ch == 'G') {
+      color = COLOR_GREEN;
+    } else if (ch == 'Y') {
+      color = COLOR_YELLOW;
+    } else {
+      --str;
+    }
+  }
+}
+
+static const char kColorEncodedHelpMessage[] =
+"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
+"following command line flags to control its behavior:\n"
+"\n"
+"Test Selection:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "list_tests at D\n"
+"      List the names of all tests instead of running them. The name of\n"
+"      TEST(Foo, Bar) is \"Foo.Bar\".\n"
+"  @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+    "[@G- at YNEGATIVE_PATTERNS]@D\n"
+"      Run only the tests whose name matches one of the positive patterns but\n"
+"      none of the negative patterns. '?' matches any single character; '*'\n"
+"      matches any substring; ':' separates two patterns.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests at D\n"
+"      Run all disabled tests too.\n"
+"\n"
+"Test Execution:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
+"      Run the tests repeatedly; use a negative count to repeat forever.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "shuffle at D\n"
+"      Randomize tests' orders on every iteration.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
+"      Random number seed to use for shuffling test orders (between 1 and\n"
+"      99999, or 0 to use a seed based on the current time).\n"
+"\n"
+"Test Output:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes at Y|@Gno at Y|@Gauto at Y)@D\n"
+"      Enable/disable colored output. The default is @Gauto at D.\n"
+"  - at G-" GTEST_FLAG_PREFIX_ "print_time=0 at D\n"
+"      Don't print the elapsed time of each test.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "output=xml at Y[@G:@YDIRECTORY_PATH at G"
+    GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
+"      Generate an XML report in the given directory or with the given file\n"
+"      name. @YFILE_PATH at D defaults to @Gtest_details.xml at D.\n"
+#if GTEST_CAN_STREAM_RESULTS_
+"  @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST at G:@YPORT at D\n"
+"      Stream test results to the given server.\n"
+#endif  // GTEST_CAN_STREAM_RESULTS_
+"\n"
+"Assertion Behavior:\n"
+#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast at Y|@Gthreadsafe at Y)@D\n"
+"      Set the default death test style.\n"
+#endif  // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "break_on_failure at D\n"
+"      Turn assertion failures into debugger break-points.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "throw_on_failure at D\n"
+"      Turn assertion failures into C++ exceptions.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0 at D\n"
+"      Do not report exceptions as test failures. Instead, allow them\n"
+"      to crash the program or throw a pop-up (on Windows).\n"
+"\n"
+"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests at D, you can alternatively set "
+    "the corresponding\n"
+"environment variable of a flag (all letters in upper-case). For example, to\n"
+"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+    "color=no at D or set\n"
+"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR at D environment variable to @Gno at D.\n"
+"\n"
+"For more information, please read the " GTEST_NAME_ " documentation at\n"
+"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
+"(not one in your own code or tests), please report it to\n"
+"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.  The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+  for (int i = 1; i < *argc; i++) {
+    const std::string arg_string = StreamableToString(argv[i]);
+    const char* const arg = arg_string.c_str();
+
+    using internal::ParseBoolFlag;
+    using internal::ParseInt32Flag;
+    using internal::ParseStringFlag;
+
+    // Do we see a Google Test flag?
+    if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+                      &GTEST_FLAG(also_run_disabled_tests)) ||
+        ParseBoolFlag(arg, kBreakOnFailureFlag,
+                      &GTEST_FLAG(break_on_failure)) ||
+        ParseBoolFlag(arg, kCatchExceptionsFlag,
+                      &GTEST_FLAG(catch_exceptions)) ||
+        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+        ParseStringFlag(arg, kDeathTestStyleFlag,
+                        &GTEST_FLAG(death_test_style)) ||
+        ParseBoolFlag(arg, kDeathTestUseFork,
+                      &GTEST_FLAG(death_test_use_fork)) ||
+        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+        ParseStringFlag(arg, kInternalRunDeathTestFlag,
+                        &GTEST_FLAG(internal_run_death_test)) ||
+        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+        ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+        ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+        ParseInt32Flag(arg, kStackTraceDepthFlag,
+                       &GTEST_FLAG(stack_trace_depth)) ||
+        ParseStringFlag(arg, kStreamResultToFlag,
+                        &GTEST_FLAG(stream_result_to)) ||
+        ParseBoolFlag(arg, kThrowOnFailureFlag,
+                      &GTEST_FLAG(throw_on_failure))
+        ) {
+      // Yes.  Shift the remainder of the argv list left by one.  Note
+      // that argv has (*argc + 1) elements, the last one always being
+      // NULL.  The following loop moves the trailing NULL element as
+      // well.
+      for (int j = i; j != *argc; j++) {
+        argv[j] = argv[j + 1];
+      }
+
+      // Decrements the argument count.
+      (*argc)--;
+
+      // We also need to decrement the iterator as we just removed
+      // an element.
+      i--;
+    } else if (arg_string == "--help" || arg_string == "-h" ||
+               arg_string == "-?" || arg_string == "/?" ||
+               HasGoogleTestFlagPrefix(arg)) {
+      // Both help flag and unrecognized Google Test flags (excluding
+      // internal ones) trigger help display.
+      g_help_flag = true;
+    }
+  }
+
+  if (g_help_flag) {
+    // We print the help here instead of in RUN_ALL_TESTS(), as the
+    // latter may not be called at all if the user is using Google
+    // Test with another testing framework.
+    PrintColorEncoded(kColorEncodedHelpMessage);
+  }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+  ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+  ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+  g_init_gtest_count++;
+
+  // We don't want to run the initialization code twice.
+  if (g_init_gtest_count != 1) return;
+
+  if (*argc <= 0) return;
+
+  internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#if GTEST_HAS_DEATH_TEST
+
+  g_argvs.clear();
+  for (int i = 0; i != *argc; i++) {
+    g_argvs.push_back(StreamableToString(argv[i]));
+  }
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+  ParseGoogleTestFlagsOnly(argc, argv);
+  GetUnitTestImpl()->PostFlagParsingInit();
+}
+
+}  // namespace internal
+
+// Initializes Google Test.  This must be called before calling
+// RUN_ALL_TESTS().  In particular, it parses a command line for the
+// flags that Google Test recognizes.  Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned.  Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+  internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+  internal::InitGoogleTestImpl(argc, argv);
+}
+
+}  // namespace testing
diff --git a/lib/gtest-1.7.0/src/gtest_main.cc b/lib/gtest-1.7.0/src/gtest_main.cc
new file mode 100644
index 0000000..f302822
--- /dev/null
+++ b/lib/gtest-1.7.0/src/gtest_main.cc
@@ -0,0 +1,38 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted 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 Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR 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.
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+
+GTEST_API_ int main(int argc, char **argv) {
+  printf("Running main() from gtest_main.cc\n");
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/m4/m4_ax_pthread.m4 b/m4/m4_ax_pthread.m4
new file mode 100644
index 0000000..d383ad5
--- /dev/null
+++ b/m4/m4_ax_pthread.m4
@@ -0,0 +1,332 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj at alum.mit.edu>
+#   Copyright (c) 2011 Daniel Richard G. <skunk at iSKUNK.ORG>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 21
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Clang doesn't consider unrecognized options an error unless we specify
+# -Werror. We throw in some extra Clang-specific options to ensure that
+# this doesn't happen for GCC, which also accepts -Werror.
+
+AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
+save_CFLAGS="$CFLAGS"
+ax_pthread_extra_flags="-Werror"
+CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
+                  [AC_MSG_RESULT([yes])],
+                  [ax_pthread_extra_flags=
+                   AC_MSG_RESULT([no])])
+CFLAGS="$save_CFLAGS"
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test "x$ax_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT([$attr_name])
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                # TODO: What about Clang on Solaris?
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT([$flag])
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            [ax_cv_PTHREAD_PRIO_INHERIT], [
+                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                                [[int i = PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != xyes; then
+            case $host_os in
+                aix*)
+                AS_CASE(["x/$CC"],
+                  [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+                  [#handle absolute path differently from PATH based program lookup
+                   AS_CASE(["x$CC"],
+                     [x/*],
+                     [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+                     [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD

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



More information about the debian-med-commit mailing list