pax_global_header00006660000000000000000000000064136146224140014515gustar00rootroot0000000000000052 comment=ffd5e372b94b26d1e302271c5fb8f92b85381f0a abyss-2.2.4/000077500000000000000000000000001361462241400126435ustar00rootroot00000000000000abyss-2.2.4/.circleci/000077500000000000000000000000001361462241400144765ustar00rootroot00000000000000abyss-2.2.4/.circleci/config.yml000066400000000000000000000060141361462241400164670ustar00rootroot00000000000000version: 2 aliases: - &docker_image ubuntu:bionic - &install_common | apt-get update -qq apt-get install -qq software-properties-common add-apt-repository -y ppa:ubuntu-toolchain-r/test apt-get update -qq apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc jobs: linux_clang6: docker: - image: *docker_image steps: - run: *install_common - run: | apt-get install -qq clang-6.0 - checkout - run: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=clang-6.0 CXX=clang++-6.0" ./configure CC=clang-6.0 CXX=clang++-6.0 --with-mpi=/usr/lib/openmpi - run: make -j12 distcheck linux_gcc5: docker: - image: *docker_image steps: - run: *install_common - run: | apt-get install -qq gcc-5 g++-5 - checkout - run: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-5 CXX=g++-5" ./configure CC=gcc-5 CXX=g++-5 --with-mpi=/usr/lib/openmpi - run: make -j12 distcheck linux_gcc6: docker: - image: *docker_image steps: - run: *install_common - run: | apt-get install -qq gcc-6 g++-6 - checkout - run: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-6 CXX=g++-6" ./configure CC=gcc-6 CXX=g++-6 --with-mpi=/usr/lib/openmpi - run: make -j12 distcheck linux_gcc7: docker: - image: *docker_image steps: - run: *install_common - run: | apt-get install -qq gcc-7 g++-7 - checkout - run: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-7 CXX=g++-7" ./configure CC=gcc-7 CXX=g++-7 --with-mpi=/usr/lib/openmpi - run: make -j12 distcheck linux_gcc8: docker: - image: *docker_image steps: - run: *install_common - run: | apt-get install -qq gcc-8 g++-8 - checkout - run: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-8 CXX=g++-8" ./configure CC=gcc-8 CXX=g++-8 --with-mpi=/usr/lib/openmpi - run: make -j12 distcheck clang-format: docker: - image: *docker_image steps: - run: *install_common - run: | apt-get install --yes --force-yes sudo sudo apt-get install --yes --force-yes curl curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" sudo apt-get update sudo apt-get install -y --no-install-recommends clang-format-8 sudo ln -s clang-format-8 /usr/bin/clang-format - checkout - run: | ./autogen.sh ./configure - run: make clang-format workflows: version: 2 abyss_builds: jobs: - linux_gcc8 - linux_gcc7 - linux_gcc6 - linux_gcc5 - linux_clang6 - clang-format abyss-2.2.4/.clang-format000066400000000000000000000003031361462241400152120ustar00rootroot00000000000000BasedOnStyle: Mozilla AlignAfterOpenBracket: AlwaysBreak AlignOperands: true ColumnLimit: 100 ContinuationIndentWidth: 4 IndentCaseLabels: false IndentWidth: 4 TabWidth: 4 UseTab: ForIndentation abyss-2.2.4/.github/000077500000000000000000000000001361462241400142035ustar00rootroot00000000000000abyss-2.2.4/.github/ISSUE_TEMPLATE.rb000066400000000000000000000014701361462241400167150ustar00rootroot00000000000000# Please report - [ ] version of ABySS with `abyss-pe version` - [ ] distribution of Linux with `lsb_release -d` # Assembly error - [ ] complete `abyss-pe` command line - [ ] last 20 lines of the output of `abyss-pe` - [ ] number of sequenced bases - [ ] estimated genome size and ploidy - [ ] estimated sequencing depth of coverage # Build error Consider installing ABySS using [Linuxbrew](https://linuxbrew.sh) on Linux or [Homebrew](https://brew.sh) on macOS with `brew install abyss`, or using [Bioconda](https://bioconda.github.io) with `conda install abyss`. - [ ] Have you tried installing ABySS using Brew or Bioconda? - [ ] version of GCC or compiler with `gcc --version` - [ ] complete `./configure` command line - [ ] last 20 lines of the output of `./configure` - [ ] last 20 lines of the output of `make` abyss-2.2.4/.github/stale.yml000066400000000000000000000012501361462241400160340ustar00rootroot00000000000000# Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale daysUntilStale: 21 # Number of days of inactivity before a stale Issue or Pull Request is closed daysUntilClose: 7 # Issues or Pull Requests with these labels will never be considered stale exemptLabels: - gsoc-outreachy - help wanted - in progress # Label to use when marking as stale staleLabel: stale # Comment to post when marking as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. abyss-2.2.4/.gitignore000066400000000000000000000003701361462241400146330ustar00rootroot00000000000000Makefile Makefile.in README.html aclocal.m4 autom4te.cache config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh lib*.a missing stamp-h1 test-driver _* *.o *.swp *.swo *.swn *~ tags compile *.orig .deps abyss-2.2.4/.travis.yml000066400000000000000000000004011361462241400147470ustar00rootroot00000000000000language: cpp compiler: - gcc before_install: - 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 abyss-2.2.4/ABYSS/000077500000000000000000000000001361462241400135245ustar00rootroot00000000000000abyss-2.2.4/ABYSS/Makefile.am000066400000000000000000000004221361462241400155560ustar00rootroot00000000000000bin_PROGRAMS = ABYSS 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.cc abyss-2.2.4/ABYSS/abyss.cc000066400000000000000000000112721361462241400151570ustar00rootroot00000000000000#include "Assembly/Options.h" #if PAIRED_DBG #include "PairedDBG/PairedDBGAlgorithms.h" #include "PairedDBG/SequenceCollection.h" #else #include "Assembly/SequenceCollection.h" #endif #include "Assembly/AssemblyAlgorithms.h" #include "Assembly/DotWriter.h" #include "DataBase/DB.h" #include #include // for setvbuf #include #include #include using namespace std; DB db; static void removeLowCoverageContigs(SequenceCollectionHash& g) { AssemblyAlgorithms::markAmbiguous(&g); cout << "Removing low-coverage contigs " "(mean k-mer coverage < " << opt::coverage << ")\n"; AssemblyAlgorithms::assemble(&g); AssemblyAlgorithms::splitAmbiguous(&g); opt::coverage = 0; } static void popBubbles(SequenceCollectionHash& g) { cout << "Popping bubbles" << endl; ofstream out; AssemblyAlgorithms::openBubbleFile(out); unsigned numPopped = AssemblyAlgorithms::popBubbles(&g, out); assert(out.good()); cout << "Removed " << numPopped << " bubbles\n"; } static void write_graph(const string& path, const SequenceCollectionHash& c) { if (path.empty()) return; cout << "Writing graph to `" << path << "'\n"; ofstream out(path.c_str()); DotWriter::write(out, c); } static void assemble(const string& pathIn, const string& pathOut) { Timer timer(__func__); SequenceCollectionHash g; if (!pathIn.empty()) AssemblyAlgorithms::loadSequences(&g, pathIn.c_str()); for_each(opt::inFiles.begin(), opt::inFiles.end(), [&g](std::string s) { AssemblyAlgorithms::loadSequences(&g, s); }); size_t numLoaded = g.size(); if (!opt::db.empty()) addToDb(db, "loadedKmer", numLoaded); cout << "Loaded " << numLoaded << " k-mer\n"; g.setDeletedKey(); g.shrink(); if (g.empty()) { cerr << "error: no usable sequence\n"; exit(EXIT_FAILURE); } AssemblyAlgorithms::setCoverageParameters(AssemblyAlgorithms::coverageHistogram(g)); if (opt::kc > 0) { cout << "Minimum k-mer multiplicity kc is " << opt::kc << endl; cout << "Removing low-multiplicity k-mers" << endl; size_t removed = AssemblyAlgorithms::applyKmerCoverageThreshold(g, opt::kc); cout << "Removed " << removed << " low-multiplicity k-mers, " << g.size() << " k-mers remaining" << std::endl; } cout << "Generating adjacency" << endl; AssemblyAlgorithms::generateAdjacency(&g); #if PAIRED_DBG removePairedDBGInconsistentEdges(g); #endif erode: if (opt::erode > 0) { cout << "Eroding tips" << endl; AssemblyAlgorithms::erodeEnds(&g); assert(AssemblyAlgorithms::erodeEnds(&g) == 0); g.cleanup(); } AssemblyAlgorithms::performTrim(&g); g.cleanup(); if (opt::coverage > 0) { removeLowCoverageContigs(g); g.wipeFlag(SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE)); g.cleanup(); goto erode; } if (opt::bubbleLen > 0) popBubbles(g); write_graph(opt::graphPath, g); AssemblyAlgorithms::markAmbiguous(&g); FastaWriter writer(pathOut.c_str()); unsigned nContigs = AssemblyAlgorithms::assemble(&g, &writer); if (nContigs == 0) { cerr << "error: no contigs assembled\n"; exit(EXIT_FAILURE); } size_t numAssembled = g.size(); size_t numRemoved = numLoaded - numAssembled; cout << "Removed " << numRemoved << " k-mer.\n" "The signal-to-noise ratio (SNR) is " << 10 * log10((double)numAssembled / numRemoved) << " dB.\n"; } int main(int argc, char* const* argv) { Timer timer("Total"); // 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; if (krange) 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; #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. opt::erode = (unsigned)-1; opt::erodeStrand = (unsigned)-1; opt::coverage = -1; opt::trimLen = k; opt::bubbleLen = 3 * k; } ostringstream k0, k1; if (k > opt::kMin) k0 << "contigs-k" << k - opt::kStep << ".fa"; if (k < opt::kMax) k1 << "contigs-k" << k << ".fa"; else k1 << opt::contigsPath.c_str(); assemble(k0.str(), k1.str()); } if (!opt::db.empty()) addToDb(db, AssemblyAlgorithms::tempStatMap); return 0; } abyss-2.2.4/AdjList/000077500000000000000000000000001361462241400141755ustar00rootroot00000000000000abyss-2.2.4/AdjList/AdjList.cpp000066400000000000000000000305651361462241400162440ustar00rootroot00000000000000#include "Common/Options.h" #include "Common/Sequence.h" #include "DataLayer/Options.h" #include "ContigNode.h" #include "ContigProperties.h" #include "FastaReader.h" #include "Iterator.h" #include "Kmer.h" #include "StringUtil.h" #include "SuffixArray.h" #include "Uncompress.h" #include "UnorderedMap.h" #include "Graph/ContigGraph.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include #include #include #include #include #include #include #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" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... [FILE]...\n" "Find overlaps of [m,k) bases. Contigs may be read from FILE(s)\n" "or standard input. Output is written to standard output.\n" "Overlaps of exactly k-1 bases are found using a hash table.\n" "Overlaps of fewer than k-1 bases are found using a suffix array.\n" "\n" " Options:\n" "\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 graph in ADJ format [default]\n" " --asqg output the graph in ASQG format\n" " --dot output the graph in GraphViz format\n" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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. */ static int ss; /** The minimum required amount of overlap. */ static unsigned minOverlap = 50; } static const char shortopts[] = "k:K:m:v"; 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 }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "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 } }; /** A contig adjacency graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; /** Parse and return the coverage from the specified FASTA comment. */ static unsigned getCoverage(const string& comment) { istringstream ss(comment); unsigned length, coverage = 0; ss >> length >> coverage; return coverage; } /** Add the overlaps of vseq to the graph. */ static void addOverlapsSA(Graph& g, const SuffixArray& sa, ContigNode v, const string& vseq) { assert(!vseq.empty()); set seen; typedef SuffixArray::const_iterator It; for (string q(vseq, 0, vseq.size() - 1); q.size() >= opt::minOverlap; chop(q)) { pair range = sa.equal_range(q); for (It it = range.first; it != range.second; ++it) { ContigNode u(it->second); if (opt::ss && u.sense() != v.sense()) continue; if (seen.insert(u).second) { // Add the longest overlap between two vertices. unsigned overlap = it->first.size(); add_edge(u, v, -overlap, static_cast(g)); } } } } /** Add overlaps of fewer than k-1 bp to the graph. */ static void addOverlapsSA(Graph& g, const vector& prefixes) { // Construct a suffix array of the blunt contigs. typedef pair Suffix; typedef vector Suffixes; Suffixes suffixes; typedef graph_traits::vertex_descriptor V; typedef graph_traits::vertex_iterator Vit; pair vertices = g.vertices(); for (Vit it = vertices.first; it != vertices.second; ++it) { ContigNode u(*it); if (out_degree(u, g) > 0) continue; size_t uci = get(vertex_index, g, get(vertex_complement, g, u)); assert(uci < prefixes.size()); string suffix(reverseComplement(prefixes[uci]).str()); suffixes.push_back(Suffix(suffix, u)); } SuffixArray sa(opt::minOverlap); for (Suffixes::const_iterator it = suffixes.begin(); it != suffixes.end(); ++it) sa.insert(*it); sa.construct(); for (Suffixes::const_iterator it = suffixes.begin(); it != suffixes.end(); ++it) { V uc = get(vertex_complement, g, it->second); addOverlapsSA(g, sa, uc, reverseComplement(it->first)); } } /** Read contigs. Add contig properties to the graph. Add prefixes to * the collection and add suffixes to their index. */ template static void readContigs(const string& path, Graph& g, vector& prefixes, unordered_map >& suffixMap) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; unsigned count = 0; FastaReader in(path.c_str(), FastaReader::FOLD_CASE); for (FastaRecord rec; in >> rec;) { Sequence& seq = rec.seq; if (count++ == 0) { // Detect colour-space contigs. opt::colourSpace = isdigit(seq[0]); } else { if (opt::colourSpace) assert(isdigit(seq[0])); else assert(isalpha(seq[0])); } flattenAmbiguityCodes(seq); // Add the prefix to the collection. unsigned overlap = opt::k - 1; assert(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)); // Add the suffix to the index. ContigProperties vp(seq.length(), getCoverage(rec.comment)); ContigNode u = add_vertex(vp, g); put(vertex_name, g, u, rec.id); suffixMap[suffix].push_back(u); suffixMap[reverseComplement(prefix)].push_back( get(vertex_complement, g, u)); } assert(in.eof()); } /** Build contig overlap graph. */ template static void buildOverlapGraph(Graph& g, vector& prefixes, unordered_map >& suffixMap) { // Add the overlap edges of exactly k-1 bp. typedef graph_traits::vertex_descriptor V; typedef unordered_map > SuffixMap; typedef typename vector::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(g)); } } SuffixMap().swap(suffixMap); if (opt::verbose > 0) printGraphStats(cerr, g); } template void loadDataStructures(Graph& g, vector& prefixes, unordered_map >& 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 prefixes; unordered_map > 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 prefixes; unordered_map > suffixMap(prefixes.size()); loadDataStructures(g, prefixes, suffixMap, argc, argv); buildOverlapGraph(g, prefixes, suffixMap); } #endif int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; 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;) { istringstream arg(optarg != NULL ? optarg : ""); 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: 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (opt::minOverlap == 0) 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; // contig overlap graph Graph 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 vals = make_vector() << opt::ss << opt::k; vector new_vals = passGraphStatsVal(g); vals.insert(vals.end(), new_vals.begin(), new_vals.end()); vector keys = make_vector() << "SS" << "K" << "V" << "E" << "degree0pctg" << "degree1pctg" << "degree234pctg" << "degree5pctg" << "degree_max"; if (!opt::db.empty()) { for (unsigned i=0; i #include #include #include #include #include #include #include using namespace std; #define PROGRAM "abyss-align" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [FASTA]...\n" "Align multiple sequences globally using either Needleman-Wunsch\n" "or DIALIGN-TX. Groups of sequences may be separated using `#.'\n" "\n" " Arguments:\n" "\n" " FASTA sequences in FASTA format\n" "\n" " Options:\n" "\n" " -v, --verbose display verbose output\n" " --help display this help and exit\n" " --version output version information and exit\n" "\n" " DIALIGN-TX options:\n" "\n" " -D, --dialign-d=N dialign debug level, default: 0\n" " -M, --dialign-m=FILE score matrix, default: dna_matrix.scr\n" " -P, --dialign-p=FILE diagonal length probability distribution\n" " default: dna_diag_prob_100_exp_550000\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { static int dialign_debug; static string dialign_score; static string dialign_prob; } static const char shortopts[] = "v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { "dialign-d", required_argument, NULL, 'D' }, { "dialign-m", required_argument, NULL, 'M' }, { "dialign-p", required_argument, NULL, 'P' }, { NULL, 0, NULL, 0 } }; /** Align two sequences using the Needlman-Wunsch algorithm. */ static void alignPair(const string& seq0, const string& seq1, ostream& out) { NWAlignment align; unsigned match = alignGlobal(seq0, seq1, align); float identity = (float)match / align.size(); out << align << identity << "\n\n"; } /** Align multiple sequences using DIALIGN-TX. */ static void alignMulti(const vector& seq, ostream& out) { unsigned match; string alignment; string consensus = dialign(seq, alignment, match); float identity = (float)match / consensus.size(); out << alignment << consensus << '\n' << identity << "\n\n"; } /** Align the specified sequences. */ static void align(const vector& seq, ostream& out) { switch (seq.size()) { case 0: return; case 1: out << seq.front() << '\n' << 1 << "\n\n"; return; case 2: return alignPair(seq[0], seq[1], out); default: return alignMulti(seq, out); } } /** Align multiple sequences. */ static void alignFile(const char* path) { if (opt::verbose > 0) cerr << "Aligning `" << path << "'\n"; FastaReader in(path, FastaReader::NO_FOLD_CASE); for (vector seq; in;) { seq.clear(); FastaRecord fa; if (in >> fa) seq.push_back(fa.seq); while (in.peek() == '>' && in >> fa) seq.push_back(fa.seq); align(seq, cout); } assert(in.eof()); } 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 'D': arg >> opt::dialign_debug; break; case 'M': arg >> opt::dialign_score; break; case 'P': arg >> opt::dialign_prob; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } // Initialize dialign. init_parameters(); set_parameters_dna(); para->DEBUG = opt::dialign_debug; para->SCR_MATRIX_FILE_NAME = (char*)opt::dialign_score.c_str(); para->DIAG_PROB_FILE_NAME = (char*)opt::dialign_prob.c_str(); initDialign(); if (optind < argc) for_each(&argv[optind], &argv[argc], alignFile); else alignFile("-"); return 0; } abyss-2.2.4/Align/alignGlobal.cc000066400000000000000000000110311361462241400164130ustar00rootroot00000000000000/** Global sequence alignment with an affine gap penalty using the * Needleman-Wunsch algorithm and the improvement by Gotoh. * @author Shaun Jackman */ #include "alignGlobal.h" #include "Sequence.h" #include #include #include #include #include // for abort using namespace std; /** A character representing a gap. */ static const char GAP = '*'; /** The score of a match. */ static const int MATCH = 5; /** The penalty of a mismatch. */ static const int MISMATCH = -4; /** The penalty of opening a gap. */ static const int GAP_OPEN = -12; /** The penalty of extending a gap. */ static const int GAP_EXTEND = -4; /** Return the score of the alignment of a and b. * @param [out] consensus the consensus of a and b * @return the score */ static int score(char a, char b, char& c) { if (a == b) { c = a; return MATCH; } else { c = ambiguityOr(a, b); return c == a || c == b ? MATCH : MISMATCH; } } /** Return the score of the alignment of a and b. */ static int score(char a, char b) { char c; return score(a, b, c); } /** Find the optimal alignment from the score matrices. * @param[out] align the alignment * @return the number of matches */ static unsigned backtrack(int** f, int** g, int** h, const string& seqA, const string& seqB, NWAlignment& align) { string alignmentA, alignmentB, consensus; unsigned matches = 0; unsigned i = seqA.size(), j = seqB.size(); while (i > 0 && j > 0) { int fij = f[i][j]; char a = seqA[i-1], b = seqB[j-1], c; int s = score(a, b, c); if (fij == f[i-1][j-1] + s) { alignmentA += a; alignmentB += b; consensus += c; if (s == MATCH) matches++; i--; j--; } else if (fij == f[i-1][j] + GAP_OPEN || fij == g[i-1][j] + GAP_EXTEND) { while (g[i][j] == g[i-1][j] + GAP_EXTEND) { char a = seqA[i-1]; alignmentA += a; alignmentB += GAP; consensus += tolower(a); i--; assert(i > 0); } assert(g[i][j] == f[i-1][j] + GAP_OPEN); char a = seqA[i-1]; alignmentA += a; alignmentB += GAP; consensus += tolower(a); i--; } else if (fij == f[i][j-1] + GAP_OPEN || fij == h[i][j-1] + GAP_EXTEND) { while (h[i][j] == h[i][j-1] + GAP_EXTEND) { char b = seqB[j-1]; alignmentA += GAP; alignmentB += b; consensus += tolower(b); j--; assert(j > 0); } assert(h[i][j] == f[i][j-1] + GAP_OPEN); char b = seqB[j-1]; alignmentA += GAP; alignmentB += b; consensus += tolower(b); j--; } else { assert(false); abort(); } } while (i > 0) { char a = seqA[i-1]; alignmentA += a; alignmentB += GAP; consensus += tolower(a); i--; } while (j > 0) { char b = seqB[j-1]; alignmentA += GAP; alignmentB += b; consensus += tolower(b); j--; } reverse(alignmentA.begin(), alignmentA.end()); reverse(alignmentB.begin(), alignmentB.end()); reverse(consensus.begin(), consensus.end()); align.query_align = alignmentA; align.target_align = alignmentB; align.match_align = consensus; return matches; } /** Find the optimal global alignment of the two sequences using the * Needleman-Wunsch algorithm and the improvement by Gotoh to use an * affine gap penalty rather than a linear gap penalty. * @param[out] align the alignment * @return the number of matches */ unsigned alignGlobal(const string& seqA, const string& seqB, NWAlignment& align) { unsigned lenA = seqA.size(); unsigned lenB = seqB.size(); int** f = new int*[lenA + 1]; int** g = new int*[lenA + 1]; int** h = new int*[lenA + 1]; for (unsigned i = 0; i <= lenA; i++) { f[i] = new int[lenB + 1]; g[i] = new int[lenB + 1]; h[i] = new int[lenB + 1]; } // Initialize the score matrix. for (unsigned i = 0; i <= lenA; i++) { f[i][0] = g[i][0] = i == 0 ? 0 : GAP_OPEN + GAP_EXTEND * ((int)i - 1); h[i][0] = INT_MIN/2; } for (unsigned j = 0; j <= lenB; j++) { f[0][j] = h[0][j] = j == 0 ? 0 : GAP_OPEN + GAP_EXTEND * ((int)j - 1); g[0][j] = INT_MIN/2; } // Calculate the score matrix. for (unsigned i = 1; i <= lenA; i++) { for (unsigned j = 1; j <= lenB; j++) { g[i][j] = max( f[i-1][j] + GAP_OPEN, g[i-1][j] + GAP_EXTEND); h[i][j] = max( f[i][j-1] + GAP_OPEN, h[i][j-1] + GAP_EXTEND); f[i][j] = max( f[i-1][j-1] + score(seqA[i-1], seqB[j-1]), max(g[i][j], h[i][j])); } } // Find the best alignment. unsigned matches = backtrack(f, g, h, seqA, seqB, align); for (unsigned i = 0; i <= lenA; i++) { delete[] f[i]; delete[] g[i]; delete[] h[i]; } delete[] f; delete[] g; delete[] h; return matches; } abyss-2.2.4/Align/alignGlobal.h000066400000000000000000000045421361462241400162660ustar00rootroot00000000000000#ifndef ALIGNGLOBAL_H #define ALIGNGLOBAL_H #include #include #include #include #include #include /** The result of a Needleman-Wunsch alignment. */ struct NWAlignment { std::string query_align; std::string target_align; std::string match_align; //consensus sequence NWAlignment() {} unsigned size() { return match_align.length(); } std::string consensus() { return match_align; } friend std::ostream& operator<<(std::ostream& out, const NWAlignment& o) { const std::string& a = o.query_align; const std::string& b = o.target_align; const std::string& c = o.match_align; assert(a.size() == c.size()); assert(b.size() == c.size()); for (unsigned i = 0; i < c.size(); ++i) out << (toupper(a[i]) == toupper(c[i]) ? '.' : a[i]); out << '\n'; for (unsigned i = 0; i < c.size(); ++i) out << (toupper(b[i]) == toupper(c[i]) ? '.' : b[i]); out << '\n'; return out << c << '\n'; } }; unsigned alignGlobal( const std::string& a, const std::string& b, NWAlignment& align); /** Align the specified pair of sequences. * @return the number of matches and size of the consensus */ static inline std::pair alignPair( const std::string& seqa, const std::string& seqb, NWAlignment& align) { unsigned matches = alignGlobal(seqa, seqb, align); return std::make_pair(matches, align.size()); } /** Align the specified sequences. * @return the number of matches and size of the consensus */ template static std::pair alignMulti( const std::vector& seqs, NWAlignment& align) { Seq alignment = seqs[0]; unsigned matches = 0; for (unsigned j = 0; j < seqs.size() - 1; j++) { matches = std::min(matches, alignGlobal(alignment, seqs[j+1], align)); alignment = align.match_align; } return std::make_pair(matches, alignment.size()); } /** Align the specified sequences. * @return the number of matches and size of the consensus */ template static std::pair align( const std::vector& seqs, NWAlignment& aln) { assert(seqs.size() > 1); if (seqs.size() == 2) return alignPair(seqs[0], seqs[1], aln); else return alignMulti(seqs, aln); } template static std::pair align(const std::vector& seqs) { NWAlignment aln; return align(seqs, aln); } #endif abyss-2.2.4/Align/dialign.cpp000066400000000000000000000260041361462241400160120ustar00rootroot00000000000000#include "dialign.h" #include "Common/Options.h" #include "Sequence.h" #include "Uncompress.h" #include // for min #include #include // for log #include #include #include #include // for clock #include #include #include using namespace std; /** Score matrix. */ scr_matrix* smatrix; /** Diagonal length probability distribution. */ prob_dist* pdist; /** Return a DNA score matrix. */ static scr_matrix* newDefaultScoreMatrix() { string s("ACGT?#$"); struct scr_matrix* p = (scr_matrix*)calloc(1, sizeof *smatrix); p->length = s.size(); p->num2char = (int*)calloc(256, sizeof(int)); p->char2num = (int*)calloc(256, sizeof(int)); for (unsigned i = 0; i < s.size(); ++i) { unsigned c = s[i]; p->num2char[i] = c; p->char2num[c] = i; } p->data = (int*)calloc(s.size() * s.size(), sizeof(int)); unsigned n = s.size() - 3; // ignore ?#$ // Set the diagonal to 1. for (unsigned i = 0; i < n; i++) p->data[s.size() * i + i] = 1; p->max_score = 1; p->avg_sim_score = para->PROT_SIM_SCORE_THRESHOLD; p->dist = (int*)calloc(2, sizeof(int)); p->dist[0] = n * n - n; p->dist[1] = n; return p; } /** Return a probability distribution for diagonal lengths * for a DNA score matrix. */ static prob_dist* newDefaultDiagProbDist() { prob_dist *o = (prob_dist*)calloc(1, sizeof *o); o->smatrix = smatrix; unsigned length = 100; o->max_dlen = length; o->data = (long double**)calloc( length + 1, sizeof(long double *)); o->log_data = (double**)calloc(length + 1, sizeof(double *)); long double **dist = o->data; double **log_dist = o->log_data; const double* p = dna_diag_prob_100_exp_550000; for (unsigned i = 1; i <= length; i++) { unsigned mxscr = i * smatrix->max_score; dist[i] = (long double*)calloc( mxscr + 1, sizeof(long double)); log_dist[i] = (double*)calloc(mxscr + 1, sizeof(double)); for (unsigned scr = 0; scr <= mxscr; scr++) { double weight = *p++; assert(weight > 0); dist[i][scr] = weight; log_dist[i][scr] = -log(weight); } } return o; } /** Initialize dialign. */ void initDialign() { // Score matrix smatrix = strlen(para->SCR_MATRIX_FILE_NAME) > 0 ? read_scr_matrix(para->SCR_MATRIX_FILE_NAME) : newDefaultScoreMatrix(); if (para->DEBUG > 5) print_scr_matrix(smatrix); // Probability distribution for diagonal lengths pdist = strlen(para->DIAG_PROB_FILE_NAME) > 0 ? read_diag_prob_dist(smatrix, para->DIAG_PROB_FILE_NAME) : newDefaultDiagProbDist(); } static void free_scr_matrix(struct scr_matrix* smatrix) { free(smatrix->dist); free(smatrix->data); free(smatrix->char2num); free(smatrix->num2char); free(smatrix); } void free_prob_dist(struct prob_dist* pdist) { unsigned int length = pdist->max_dlen; unsigned int i; for (i=1; i<=length; i++) { free(pdist->data[i]); free(pdist->log_data[i]); } free(pdist->data); free(pdist->log_data); free_scr_matrix(pdist->smatrix); free(pdist); } static void free_seq_col(struct seq_col* scol) { unsigned int length = scol->length; unsigned int i; for (i=0; iseqs[i]).data); free(scol->seqs); free(scol); } /** Print a dialign alignment. */ static ostream& print(ostream& out, const alignment& o, const string& consensus) { const seq_col& scol = *o.scol; vector proc(scol.length, 0); algn_pos **ap = o.algn; for (int s = 0; s < scol.length; s++) { const seq& sq = scol.seqs[s]; for (int j = 0; j < o.max_pos; j++) { if (proc[s] < sq.length) { const algn_pos& ap1 = *find_eqc(ap, s, proc[s]); assert(j <= *ap1.eqcAlgnPos); if (*ap1.eqcAlgnPos == j) { char c = sq.data[proc[s]]; if (toupper(c) == toupper(consensus[j])) out << '.'; else if (ap1.state & para->STATE_ORPHANE) out << (char)tolower(c); else out << c; proc[s]++; } else out << '*'; } else out << '*'; } out << '\n'; } return out; } /** Return the minimum number of matches. */ static unsigned countMatches(const alignment& o, const string& consensus) { unsigned minMatches = consensus.size(); const seq_col& scol = *o.scol; vector proc(scol.length, 0); algn_pos **ap = o.algn; for (int s = 0; s < scol.length; s++) { unsigned matches = 0; const seq& sq = scol.seqs[s]; for (int j = 0; j < o.max_pos; j++) { if (proc[s] < sq.length) { const algn_pos& ap1 = *find_eqc(ap, s, proc[s]); assert(j <= *ap1.eqcAlgnPos); if (*ap1.eqcAlgnPos == j) { char c = sq.data[proc[s]]; if (toupper(c) == toupper(consensus[j])) matches++; proc[s]++; } } } minMatches = min(minMatches, matches); } return minMatches; } static struct seq_col* read_seqs(const vector& amb_seqs) { struct seq_col* scol = (struct seq_col*)calloc(1, sizeof(struct seq_col)); struct seq* seqs = (scol->seqs = (struct seq*)calloc(amb_seqs.size(), sizeof(struct seq))); if(scol==NULL || seqs==NULL) { cerr << "read_seqs(): Out of memory !\n"; exit(EXIT_FAILURE); } scol->length = amb_seqs.size(); scol->avg_length = 0; seq* seq; for (size_t i=0; iseqs[i]); seq->max_seen = 0; //seq->name = calloc(rlen, sizeof(char)); //do I need this? seq->num = i; seq->orf_frame=0; seq->crick_strand=0; //strncpy(seq->name, &(rline[1]), rlen-2); seq->data = (char*)calloc(amb_seqs[i].length()+1, sizeof(char)); if (seq->data == NULL) { cerr << "seq->data out of memory !\n"; exit(EXIT_FAILURE); } strcpy(seq->data, amb_seqs[i].c_str()); seq->length = amb_seqs[i].length(); scol->avg_length += amb_seqs[i].length(); if(para->DEBUG >1) printf("DEBUG: seq:%s\n", seq->data); } scol->avg_length /= scol->length; if(para->DEBUG >1) printf("DEBUG: total # of amb_seqs: %i, avg_length: %i\n", scol->length, scol->avg_length); return scol; } // assume initial sequences contain only a/c/g/t/n static string get_alignment_consensus(struct alignment *algn) { struct seq_col *scol = algn->scol; unsigned int slen = scol->length; int j; unsigned int s,max; struct seq* sq; struct algn_pos **ap = algn->algn; prepare_alignment(algn); max = algn->max_pos; if (para->DEBUG > 5) printf("slen is %u, max pos is %u\n", slen, max); struct algn_pos *ap1; max = algn->max_pos; int* proc = new int[slen]; for (j=0; j<(int)slen; j++) proc[j] = 0; string consensus; for (j=0; j<(int)max; j++) { char c = 'X'; bool gap = false; for(s=0;sseqs[s]); if(proc[s] < sq->length) { ap1 = find_eqc(ap,s,proc[s]); if(*ap1->eqcAlgnPos==j) { char cur_char = toupper(sq->data[proc[s]]); c = c == 'X' ? cur_char : ambiguityOr(c, cur_char); proc[s]++; } else gap = true; } else gap = true; } consensus += gap ? tolower(c) : c; } delete[] proc; return consensus; } /** Align multiple sequences using DIALIGN-TX. * @param [out] alignment the alignment * @param [out] matches the minimum number of matches * @return the consensus sequence */ string dialign(const vector& amb_seqs, string& alignment, unsigned& matches) { int i; struct seq_col *in_seq_col = NULL; double tim = clock(); in_seq_col = read_seqs(amb_seqs); // fast mode has higher threshold weights struct parameters *dialign_para = para; if(dialign_para->FAST_MODE) dialign_para->PROT_SIM_SCORE_THRESHOLD += 0.25; // Consider Anchors -> default for DNA: DO_ANCHOR = 0; struct alignment *algn = NULL; if (!dialign_para->FAST_MODE) algn = create_empty_alignment(in_seq_col); struct alignment *salgn = create_empty_alignment(in_seq_col); if (dialign_para->DEBUG > 1) printf("empty alignments created\n"); // Compute pairwise diagonals struct diag_col *all_diags = find_all_diags(smatrix, pdist, in_seq_col, salgn, 1); double duration = (clock()-tim)/CLOCKS_PER_SEC; if (dialign_para->DEBUG > 1) printf("Found %i diags in %f secs\n", all_diags->diag_amount, duration); int diag_amount = all_diags->diag_amount; // Compute alignment double tim2 = clock(); if (!dialign_para->FAST_MODE) { vector cp_diags(all_diags->diag_amount); for(i = 0; i < diag_amount; i++) { cp_diags[i] = (diag*)malloc(sizeof(struct diag)); *(cp_diags[i]) = *(all_diags->diags[i]); } guided_aligner(algn, in_seq_col, all_diags, smatrix, pdist, all_diags->gt_root, 1); for(i = 0; i < diag_amount; i++) all_diags->diags[i] = cp_diags[i]; all_diags->diag_amount = diag_amount; } simple_aligner(in_seq_col, all_diags, smatrix, pdist, salgn, 1); duration = (clock()-tim2)/CLOCKS_PER_SEC; if (!dialign_para->FAST_MODE) { if (dialign_para->DEBUG > 1) printf("First alignment after %f secs. " "simple: %f guided: %f\n", duration, salgn->total_weight, algn->total_weight); else if (dialign_para->DEBUG > 1) printf("First alignment after %f secs. simple: %f \n", duration, salgn->total_weight); } free_diag_col(all_diags); dialign_para->DO_ANCHOR = 0; // anchors done // round 2+ int round; char newFound = 0; int type; // consider sensitivity level if (!dialign_para->FAST_MODE) { if (dialign_para->SENS_MODE == 0) { dialign_para->DIAG_THRESHOLD_WEIGHT = 0.0; } else if (dialign_para->SENS_MODE == 1) { dialign_para->DIAG_THRESHOLD_WEIGHT = -log(0.75);//-log(.875+0.125/2.0); } else if (dialign_para->SENS_MODE == 2) { dialign_para->DIAG_THRESHOLD_WEIGHT = -log(0.5);//-log(0.875); } } int stype = (dialign_para->FAST_MODE ? 1 : 0); for (type = stype; type < 2; type++) { for (round = 2; round <= 20; round++) { tim2 = clock(); all_diags = find_all_diags(smatrix, pdist, in_seq_col, (type ? salgn : algn), round); duration = (clock()-tim2)/CLOCKS_PER_SEC; if (dialign_para->DEBUG > 1) printf("Found %i diags after %f secs\n", all_diags->diag_amount, duration); if (all_diags->diag_amount == 0) { free_diag_col(all_diags); break; } else { // round 2 and further we use the simple aligner newFound = simple_aligner(in_seq_col, all_diags, smatrix, pdist, (type ? salgn : algn), round); free_diag_col(all_diags); if (!newFound) break; } } } if (dialign_para->DEBUG > 1) printf("Alignment ready!\n"); if (!dialign_para->FAST_MODE) { if (dialign_para->DEBUG > 1) printf("Final alignment simple: %f guided: %f\n", salgn->total_weight, algn->total_weight); } else { if (dialign_para->DEBUG > 1) printf("Final alignment simple: %f \n", salgn->total_weight); } if (dialign_para->FAST_MODE || salgn->total_weight > algn->total_weight) { if (!dialign_para->FAST_MODE) free_alignment(algn); algn = salgn; } else { free_alignment(salgn); } if (opt::verbose > 3) simple_print_alignment_default(algn); string consensus = get_alignment_consensus(algn); matches = countMatches(*algn, consensus); ostringstream ss; print(ss, *algn, consensus); alignment = ss.str(); if (dialign_para->DEBUG > 0) { duration = (clock()-tim)/CLOCKS_PER_SEC; cerr << "Total time: " << duration << " s\n" "Total weight: " << algn->total_weight << '\n'; } free_alignment(algn); free_seq_col(in_seq_col); return consensus; } abyss-2.2.4/Align/dialign.h000066400000000000000000000023471361462241400154630ustar00rootroot00000000000000#ifndef DIALIGN_H #define DIALIGN_H 1 extern "C" { #include "dialign/io.h" #include "dialign/parameters.h" #include "dialign/struct.h" extern struct scr_matrix *smatrix; extern struct prob_dist *pdist; extern const double dna_diag_prob_100_exp_550000[5151]; struct alignment* create_empty_alignment(struct seq_col *scol); struct diag_col *find_all_diags(struct scr_matrix *smatrix, struct prob_dist *pdist, struct seq_col *in_seq_col, struct alignment *algn, int round); struct alignment* guided_aligner(struct alignment *palgn, struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct gt_node *gtn, int round); char simple_aligner(struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct alignment *algn, int round); void prepare_alignment(struct alignment *algn); struct algn_pos *find_eqc(struct algn_pos **ap, int seqnum, int pos); void free_alignment(struct alignment* algn); void free_diag_col(struct diag_col* dcol); } #include #include void initDialign(); void free_prob_dist(struct prob_dist* pdist); std::string dialign(const std::vector& amb_seqs, std::string& alignment, unsigned& matches); #endif abyss-2.2.4/Align/dna_diag_prob.cc000066400000000000000000004037711361462241400167700ustar00rootroot00000000000000#include "dialign.h" /* Probability distribution for diagonal lengths. */ const double dna_diag_prob_100_exp_550000[5151] = { /* 1 0 */ 1.000000e+00, /* 1 1 */ 6.730455e-01, /* 2 0 */ 1.000000e+00, /* 2 1 */ 9.670818e-01, /* 2 2 */ 4.120255e-01, /* 3 0 */ 1.000000e+00, /* 3 1 */ 9.979000e-01, /* 3 2 */ 8.519509e-01, /* 3 3 */ 1.974073e-01, /* 4 0 */ 1.000000e+00, /* 4 1 */ 9.998618e-01, /* 4 2 */ 9.809545e-01, /* 4 3 */ 5.966600e-01, /* 4 4 */ 7.885273e-02, /* 5 0 */ 1.000000e+00, /* 5 1 */ 9.999909e-01, /* 5 2 */ 9.982182e-01, /* 5 3 */ 8.905636e-01, /* 5 4 */ 3.229873e-01, /* 5 5 */ 2.844545e-02, /* 6 0 */ 1.000000e+00, /* 6 1 */ 1.000000e+00, /* 6 2 */ 9.998564e-01, /* 6 3 */ 9.827782e-01, /* 6 4 */ 6.597564e-01, /* 6 5 */ 1.446764e-01, /* 6 6 */ 9.710909e-03, /* 7 0 */ 1.000000e+00, /* 7 1 */ 1.000000e+00, /* 7 2 */ 9.999964e-01, /* 7 3 */ 9.980182e-01, /* 7 4 */ 8.957327e-01, /* 7 5 */ 3.821818e-01, /* 7 6 */ 5.771455e-02, /* 7 7 */ 3.210909e-03, /* 8 0 */ 1.000000e+00, /* 8 1 */ 1.000000e+00, /* 8 2 */ 1.000000e+00, /* 8 3 */ 9.998164e-01, /* 8 4 */ 9.798309e-01, /* 8 5 */ 6.726545e-01, /* 8 6 */ 1.831455e-01, /* 8 7 */ 2.081818e-02, /* 8 8 */ 1.034545e-03, /* 9 0 */ 1.000000e+00, /* 9 1 */ 1.000000e+00, /* 9 2 */ 1.000000e+00, /* 9 3 */ 9.999891e-01, /* 9 4 */ 9.971818e-01, /* 9 5 */ 8.838709e-01, /* 9 6 */ 4.005764e-01, /* 9 7 */ 7.684182e-02, /* 9 8 */ 7.283636e-03, /* 9 9 */ 3.327273e-04, /* 10 0 */ 1.000000e+00, /* 10 1 */ 1.000000e+00, /* 10 2 */ 1.000000e+00, /* 10 3 */ 9.999982e-01, /* 10 4 */ 9.996382e-01, /* 10 5 */ 9.730073e-01, /* 10 6 */ 6.584691e-01, /* 10 7 */ 1.977636e-01, /* 10 8 */ 2.972182e-02, /* 10 9 */ 2.398182e-03, /* 10 10 */ 1.127273e-04, /* 11 0 */ 1.000000e+00, /* 11 1 */ 1.000000e+00, /* 11 2 */ 1.000000e+00, /* 11 3 */ 1.000000e+00, /* 11 4 */ 9.999655e-01, /* 11 5 */ 9.953236e-01, /* 11 6 */ 8.598509e-01, /* 11 7 */ 3.929982e-01, /* 11 8 */ 8.693273e-02, /* 11 9 */ 1.099091e-02, /* 11 10 */ 7.872727e-04, /* 11 11 */ 3.272727e-05, /* 12 0 */ 1.000000e+00, /* 12 1 */ 1.000000e+00, /* 12 2 */ 1.000000e+00, /* 12 3 */ 1.000000e+00, /* 12 4 */ 9.999945e-01, /* 12 5 */ 9.993891e-01, /* 12 6 */ 9.605727e-01, /* 12 7 */ 6.266636e-01, /* 12 8 */ 1.981436e-01, /* 12 9 */ 3.510364e-02, /* 12 10 */ 3.932727e-03, /* 12 11 */ 2.781818e-04, /* 12 12 */ 1.007318e-05, /* 13 0 */ 1.000000e+00, /* 13 1 */ 1.000000e+00, /* 13 2 */ 1.000000e+00, /* 13 3 */ 1.000000e+00, /* 13 4 */ 1.000000e+00, /* 13 5 */ 9.999000e-01, /* 13 6 */ 9.921364e-01, /* 13 7 */ 8.258491e-01, /* 13 8 */ 3.724073e-01, /* 13 9 */ 8.930182e-02, /* 13 10 */ 1.366727e-02, /* 13 11 */ 1.394545e-03, /* 13 12 */ 7.818182e-05, /* 13 13 */ 2.920628e-06, /* 14 0 */ 1.000000e+00, /* 14 1 */ 1.000000e+00, /* 14 2 */ 1.000000e+00, /* 14 3 */ 1.000000e+00, /* 14 4 */ 1.000000e+00, /* 14 5 */ 9.999964e-01, /* 14 6 */ 9.987527e-01, /* 14 7 */ 9.410745e-01, /* 14 8 */ 5.849291e-01, /* 14 9 */ 1.902582e-01, /* 14 10 */ 3.750727e-02, /* 14 11 */ 5.054545e-03, /* 14 12 */ 4.563636e-04, /* 14 13 */ 3.454545e-05, /* 14 14 */ 8.381903e-07, /* 15 0 */ 1.000000e+00, /* 15 1 */ 1.000000e+00, /* 15 2 */ 1.000000e+00, /* 15 3 */ 1.000000e+00, /* 15 4 */ 1.000000e+00, /* 15 5 */ 1.000000e+00, /* 15 6 */ 9.998218e-01, /* 15 7 */ 9.857345e-01, /* 15 8 */ 7.810727e-01, /* 15 9 */ 3.435873e-01, /* 15 10 */ 8.694000e-02, /* 15 11 */ 1.504909e-02, /* 15 12 */ 1.870909e-03, /* 15 13 */ 1.400000e-04, /* 15 14 */ 1.096725e-05, /* 15 15 */ 2.384186e-07, /* 16 0 */ 1.000000e+00, /* 16 1 */ 1.000000e+00, /* 16 2 */ 1.000000e+00, /* 16 3 */ 1.000000e+00, /* 16 4 */ 1.000000e+00, /* 16 5 */ 1.000000e+00, /* 16 6 */ 9.999818e-01, /* 16 7 */ 9.972691e-01, /* 16 8 */ 9.120782e-01, /* 16 9 */ 5.356636e-01, /* 16 10 */ 1.751473e-01, /* 16 11 */ 3.724182e-02, /* 16 12 */ 5.770909e-03, /* 16 13 */ 6.545455e-04, /* 16 14 */ 4.363636e-05, /* 16 15 */ 3.297115e-06, /* 16 16 */ 6.728806e-08, /* 17 0 */ 1.000000e+00, /* 17 1 */ 1.000000e+00, /* 17 2 */ 1.000000e+00, /* 17 3 */ 1.000000e+00, /* 17 4 */ 1.000000e+00, /* 17 5 */ 1.000000e+00, /* 17 6 */ 9.999982e-01, /* 17 7 */ 9.996127e-01, /* 17 8 */ 9.740327e-01, /* 17 9 */ 7.278618e-01, /* 17 10 */ 3.094855e-01, /* 17 11 */ 8.132909e-02, /* 17 12 */ 1.516182e-02, /* 17 13 */ 2.134545e-03, /* 17 14 */ 2.309091e-04, /* 17 15 */ 2.406444e-05, /* 17 16 */ 9.806827e-07, /* 17 17 */ 1.885928e-08, /* 18 0 */ 1.000000e+00, /* 18 1 */ 1.000000e+00, /* 18 2 */ 1.000000e+00, /* 18 3 */ 1.000000e+00, /* 18 4 */ 1.000000e+00, /* 18 5 */ 1.000000e+00, /* 18 6 */ 1.000000e+00, /* 18 7 */ 9.999382e-01, /* 18 8 */ 9.941927e-01, /* 18 9 */ 8.733745e-01, /* 18 10 */ 4.831091e-01, /* 18 11 */ 1.582600e-01, /* 18 12 */ 3.553818e-02, /* 18 13 */ 6.020000e-03, /* 18 14 */ 8.090909e-04, /* 18 15 */ 8.000000e-05, /* 18 16 */ 7.522642e-06, /* 18 17 */ 2.889283e-07, /* 18 18 */ 5.253241e-09, /* 19 0 */ 1.000000e+00, /* 19 1 */ 1.000000e+00, /* 19 2 */ 1.000000e+00, /* 19 3 */ 1.000000e+00, /* 19 4 */ 1.000000e+00, /* 19 5 */ 1.000000e+00, /* 19 6 */ 1.000000e+00, /* 19 7 */ 9.999927e-01, /* 19 8 */ 9.989600e-01, /* 19 9 */ 9.548018e-01, /* 19 10 */ 6.672091e-01, /* 19 11 */ 2.747782e-01, /* 19 12 */ 7.364909e-02, /* 19 13 */ 1.470364e-02, /* 19 14 */ 2.361818e-03, /* 19 15 */ 3.127273e-04, /* 19 16 */ 3.454545e-05, /* 19 17 */ 2.323941e-06, /* 19 18 */ 8.440111e-08, /* 19 19 */ 1.455192e-09, /* 20 0 */ 1.000000e+00, /* 20 1 */ 1.000000e+00, /* 20 2 */ 1.000000e+00, /* 20 3 */ 1.000000e+00, /* 20 4 */ 1.000000e+00, /* 20 5 */ 1.000000e+00, /* 20 6 */ 1.000000e+00, /* 20 7 */ 9.999945e-01, /* 20 8 */ 9.998364e-01, /* 20 9 */ 9.880182e-01, /* 20 10 */ 8.238018e-01, /* 20 11 */ 4.288382e-01, /* 20 12 */ 1.396818e-01, /* 20 13 */ 3.265455e-02, /* 20 14 */ 5.916364e-03, /* 20 15 */ 9.327273e-04, /* 20 16 */ 1.145455e-04, /* 20 17 */ 1.305579e-05, /* 20 18 */ 7.103254e-07, /* 20 19 */ 2.446632e-08, /* 20 20 */ 4.010872e-10, /* 21 0 */ 1.000000e+00, /* 21 1 */ 1.000000e+00, /* 21 2 */ 1.000000e+00, /* 21 3 */ 1.000000e+00, /* 21 4 */ 1.000000e+00, /* 21 5 */ 1.000000e+00, /* 21 6 */ 1.000000e+00, /* 21 7 */ 1.000000e+00, /* 21 8 */ 9.999709e-01, /* 21 9 */ 9.974091e-01, /* 21 10 */ 9.260218e-01, /* 21 11 */ 6.026582e-01, /* 21 12 */ 2.398145e-01, /* 21 13 */ 6.590545e-02, /* 21 14 */ 1.380364e-02, /* 21 15 */ 2.380000e-03, /* 21 16 */ 3.672727e-04, /* 21 17 */ 4.363636e-05, /* 21 18 */ 4.166890e-06, /* 21 19 */ 2.150355e-07, /* 21 20 */ 7.043127e-09, /* 21 21 */ 1.100489e-10, /* 22 0 */ 1.000000e+00, /* 22 1 */ 1.000000e+00, /* 22 2 */ 1.000000e+00, /* 22 3 */ 1.000000e+00, /* 22 4 */ 1.000000e+00, /* 22 5 */ 1.000000e+00, /* 22 6 */ 1.000000e+00, /* 22 7 */ 1.000000e+00, /* 22 8 */ 9.999964e-01, /* 22 9 */ 9.995200e-01, /* 22 10 */ 9.760564e-01, /* 22 11 */ 7.642291e-01, /* 22 12 */ 3.756655e-01, /* 22 13 */ 1.211818e-01, /* 22 14 */ 2.931455e-02, /* 22 15 */ 5.654545e-03, /* 22 16 */ 9.218182e-04, /* 22 17 */ 1.345455e-04, /* 22 18 */ 1.913187e-05, /* 22 19 */ 1.314848e-06, /* 22 20 */ 6.453058e-08, /* 22 21 */ 2.014701e-09, /* 22 22 */ 3.007017e-11, /* 23 0 */ 1.000000e+00, /* 23 1 */ 1.000000e+00, /* 23 2 */ 1.000000e+00, /* 23 3 */ 1.000000e+00, /* 23 4 */ 1.000000e+00, /* 23 5 */ 1.000000e+00, /* 23 6 */ 1.000000e+00, /* 23 7 */ 1.000000e+00, /* 23 8 */ 1.000000e+00, /* 23 9 */ 9.999091e-01, /* 23 10 */ 9.939800e-01, /* 23 11 */ 8.861836e-01, /* 23 12 */ 5.363855e-01, /* 23 13 */ 2.062655e-01, /* 23 14 */ 5.769273e-02, /* 23 15 */ 1.282000e-02, /* 23 16 */ 2.223636e-03, /* 23 17 */ 3.818182e-04, /* 23 18 */ 4.909091e-05, /* 23 19 */ 6.281672e-06, /* 23 20 */ 4.106150e-07, /* 23 21 */ 1.921126e-08, /* 23 22 */ 5.729817e-10, /* 23 23 */ 8.185452e-12, /* 24 0 */ 1.000000e+00, /* 24 1 */ 1.000000e+00, /* 24 2 */ 1.000000e+00, /* 24 3 */ 1.000000e+00, /* 24 4 */ 1.000000e+00, /* 24 5 */ 1.000000e+00, /* 24 6 */ 1.000000e+00, /* 24 7 */ 1.000000e+00, /* 24 8 */ 1.000000e+00, /* 24 9 */ 9.999873e-01, /* 24 10 */ 9.987582e-01, /* 24 11 */ 9.557455e-01, /* 24 12 */ 6.970909e-01, /* 24 13 */ 3.241800e-01, /* 24 14 */ 1.044855e-01, /* 24 15 */ 2.595818e-02, /* 24 16 */ 5.249091e-03, /* 24 17 */ 9.036364e-04, /* 24 18 */ 1.381818e-04, /* 24 19 */ 2.497199e-05, /* 24 20 */ 2.038172e-06, /* 24 21 */ 1.270206e-07, /* 24 22 */ 5.677681e-09, /* 24 23 */ 1.620926e-10, /* 24 24 */ 2.220446e-12, /* 25 0 */ 1.000000e+00, /* 25 1 */ 1.000000e+00, /* 25 2 */ 1.000000e+00, /* 25 3 */ 1.000000e+00, /* 25 4 */ 1.000000e+00, /* 25 5 */ 1.000000e+00, /* 25 6 */ 1.000000e+00, /* 25 7 */ 1.000000e+00, /* 25 8 */ 1.000000e+00, /* 25 9 */ 9.999982e-01, /* 25 10 */ 9.997836e-01, /* 25 11 */ 9.863527e-01, /* 25 12 */ 8.327455e-01, /* 25 13 */ 4.696527e-01, /* 25 14 */ 1.758091e-01, /* 25 15 */ 4.943091e-02, /* 25 16 */ 1.134000e-02, /* 25 17 */ 2.156364e-03, /* 25 18 */ 3.509091e-04, /* 25 19 */ 6.727273e-05, /* 25 20 */ 8.405790e-06, /* 25 21 */ 6.541608e-07, /* 25 22 */ 3.895211e-08, /* 25 23 */ 1.666734e-09, /* 25 24 */ 4.563105e-11, /* 25 25 */ 6.004086e-13, /* 26 0 */ 1.000000e+00, /* 26 1 */ 1.000000e+00, /* 26 2 */ 1.000000e+00, /* 26 3 */ 1.000000e+00, /* 26 4 */ 1.000000e+00, /* 26 5 */ 1.000000e+00, /* 26 6 */ 1.000000e+00, /* 26 7 */ 1.000000e+00, /* 26 8 */ 1.000000e+00, /* 26 9 */ 1.000000e+00, /* 26 10 */ 9.999618e-01, /* 26 11 */ 9.967691e-01, /* 26 12 */ 9.239927e-01, /* 26 13 */ 6.252236e-01, /* 26 14 */ 2.766891e-01, /* 26 15 */ 8.827091e-02, /* 26 16 */ 2.257636e-02, /* 26 17 */ 4.838182e-03, /* 26 18 */ 8.618182e-04, /* 26 19 */ 1.400000e-04, /* 26 20 */ 2.909091e-05, /* 26 21 */ 2.795292e-06, /* 26 22 */ 2.078667e-07, /* 26 23 */ 1.184957e-08, /* 26 24 */ 4.862590e-10, /* 26 25 */ 1.278777e-11, /* 26 26 */ 1.618705e-13, /* 27 0 */ 1.000000e+00, /* 27 1 */ 1.000000e+00, /* 27 2 */ 1.000000e+00, /* 27 3 */ 1.000000e+00, /* 27 4 */ 1.000000e+00, /* 27 5 */ 1.000000e+00, /* 27 6 */ 1.000000e+00, /* 27 7 */ 1.000000e+00, /* 27 8 */ 1.000000e+00, /* 27 9 */ 1.000000e+00, /* 27 10 */ 9.999945e-01, /* 27 11 */ 9.993291e-01, /* 27 12 */ 9.726164e-01, /* 27 13 */ 7.696218e-01, /* 27 14 */ 4.050855e-01, /* 27 15 */ 1.481582e-01, /* 27 16 */ 4.218000e-02, /* 27 17 */ 1.004000e-02, /* 27 18 */ 1.972727e-03, /* 27 19 */ 3.290909e-04, /* 27 20 */ 6.727273e-05, /* 27 21 */ 1.031061e-05, /* 27 22 */ 9.192084e-07, /* 27 23 */ 6.544501e-08, /* 27 24 */ 3.578101e-09, /* 27 25 */ 1.410507e-10, /* 27 26 */ 3.568701e-12, /* 27 27 */ 4.352074e-14, /* 28 0 */ 1.000000e+00, /* 28 1 */ 1.000000e+00, /* 28 2 */ 1.000000e+00, /* 28 3 */ 1.000000e+00, /* 28 4 */ 1.000000e+00, /* 28 5 */ 1.000000e+00, /* 28 6 */ 1.000000e+00, /* 28 7 */ 1.000000e+00, /* 28 8 */ 1.000000e+00, /* 28 9 */ 1.000000e+00, /* 28 10 */ 1.000000e+00, /* 28 11 */ 9.999000e-01, /* 28 12 */ 9.922545e-01, /* 28 13 */ 8.798709e-01, /* 28 14 */ 5.509618e-01, /* 28 15 */ 2.333200e-01, /* 28 16 */ 7.442364e-02, /* 28 17 */ 1.933455e-02, /* 28 18 */ 4.320000e-03, /* 28 19 */ 7.781818e-04, /* 28 20 */ 1.381818e-04, /* 28 21 */ 2.727273e-05, /* 28 22 */ 3.504586e-06, /* 28 23 */ 2.991620e-07, /* 28 24 */ 2.042947e-08, /* 28 25 */ 1.073040e-09, /* 28 26 */ 4.069754e-11, /* 28 27 */ 9.920537e-13, /* 28 28 */ 1.167122e-14, /* 29 0 */ 1.000000e+00, /* 29 1 */ 1.000000e+00, /* 29 2 */ 1.000000e+00, /* 29 3 */ 1.000000e+00, /* 29 4 */ 1.000000e+00, /* 29 5 */ 1.000000e+00, /* 29 6 */ 1.000000e+00, /* 29 7 */ 1.000000e+00, /* 29 8 */ 1.000000e+00, /* 29 9 */ 1.000000e+00, /* 29 10 */ 1.000000e+00, /* 29 11 */ 9.999873e-01, /* 29 12 */ 9.982291e-01, /* 29 13 */ 9.487145e-01, /* 29 14 */ 6.981673e-01, /* 29 15 */ 3.453327e-01, /* 29 16 */ 1.235055e-01, /* 29 17 */ 3.544727e-02, /* 29 18 */ 8.707273e-03, /* 29 19 */ 1.783636e-03, /* 29 20 */ 3.090909e-04, /* 29 21 */ 5.090909e-05, /* 29 22 */ 1.183615e-05, /* 29 23 */ 1.177724e-06, /* 29 24 */ 9.643441e-08, /* 29 25 */ 6.326911e-09, /* 29 26 */ 3.197442e-10, /* 29 27 */ 1.168440e-11, /* 29 28 */ 2.747802e-13, /* 29 29 */ 3.122502e-15, /* 30 0 */ 1.000000e+00, /* 30 1 */ 1.000000e+00, /* 30 2 */ 1.000000e+00, /* 30 3 */ 1.000000e+00, /* 30 4 */ 1.000000e+00, /* 30 5 */ 1.000000e+00, /* 30 6 */ 1.000000e+00, /* 30 7 */ 1.000000e+00, /* 30 8 */ 1.000000e+00, /* 30 9 */ 1.000000e+00, /* 30 10 */ 1.000000e+00, /* 30 11 */ 9.999982e-01, /* 30 12 */ 9.996145e-01, /* 30 13 */ 9.822418e-01, /* 30 14 */ 8.227145e-01, /* 30 15 */ 4.789527e-01, /* 30 16 */ 1.952782e-01, /* 30 17 */ 6.181273e-02, /* 30 18 */ 1.640727e-02, /* 30 19 */ 3.714545e-03, /* 30 20 */ 7.036364e-04, /* 30 21 */ 1.200000e-04, /* 30 22 */ 3.611135e-05, /* 30 23 */ 4.102757e-06, /* 30 24 */ 3.916149e-07, /* 30 25 */ 3.080943e-08, /* 30 26 */ 1.944996e-09, /* 30 27 */ 9.471121e-11, /* 30 28 */ 3.339140e-12, /* 30 29 */ 7.585165e-14, /* 30 30 */ 8.335346e-16, /* 31 0 */ 1.000000e+00, /* 31 1 */ 1.000000e+00, /* 31 2 */ 1.000000e+00, /* 31 3 */ 1.000000e+00, /* 31 4 */ 1.000000e+00, /* 31 5 */ 1.000000e+00, /* 31 6 */ 1.000000e+00, /* 31 7 */ 1.000000e+00, /* 31 8 */ 1.000000e+00, /* 31 9 */ 1.000000e+00, /* 31 10 */ 1.000000e+00, /* 31 11 */ 1.000000e+00, /* 31 12 */ 9.999218e-01, /* 31 13 */ 9.951964e-01, /* 31 14 */ 9.121473e-01, /* 31 15 */ 6.207782e-01, /* 31 16 */ 2.910200e-01, /* 31 17 */ 1.022600e-01, /* 31 18 */ 2.944727e-02, /* 31 19 */ 7.225455e-03, /* 31 20 */ 1.632727e-03, /* 31 21 */ 2.781818e-04, /* 31 22 */ 5.454545e-05, /* 31 23 */ 1.289846e-05, /* 31 24 */ 1.405896e-06, /* 31 25 */ 1.289439e-07, /* 31 26 */ 9.761676e-09, /* 31 27 */ 5.938159e-10, /* 31 28 */ 2.789857e-11, /* 31 29 */ 9.501289e-13, /* 31 30 */ 2.087219e-14, /* 31 31 */ 2.220446e-16, /* 32 0 */ 1.000000e+00, /* 32 1 */ 1.000000e+00, /* 32 2 */ 1.000000e+00, /* 32 3 */ 1.000000e+00, /* 32 4 */ 1.000000e+00, /* 32 5 */ 1.000000e+00, /* 32 6 */ 1.000000e+00, /* 32 7 */ 1.000000e+00, /* 32 8 */ 1.000000e+00, /* 32 9 */ 1.000000e+00, /* 32 10 */ 1.000000e+00, /* 32 11 */ 1.000000e+00, /* 32 12 */ 9.999800e-01, /* 32 13 */ 9.989327e-01, /* 32 14 */ 9.638855e-01, /* 32 15 */ 7.548182e-01, /* 32 16 */ 4.098745e-01, /* 32 17 */ 1.615600e-01, /* 32 18 */ 5.084727e-02, /* 32 19 */ 1.364182e-02, /* 32 20 */ 3.136364e-03, /* 32 21 */ 6.763636e-04, /* 32 22 */ 1.345455e-04, /* 32 23 */ 2.363636e-05, /* 32 24 */ 4.550656e-06, /* 32 25 */ 4.766309e-07, /* 32 26 */ 4.206818e-08, /* 32 27 */ 3.068960e-09, /* 32 28 */ 1.801294e-10, /* 32 29 */ 8.175199e-12, /* 32 30 */ 2.692578e-13, /* 32 31 */ 5.726376e-15, /* 32 32 */ 5.903481e-17, /* 33 0 */ 1.000000e+00, /* 33 1 */ 1.000000e+00, /* 33 2 */ 1.000000e+00, /* 33 3 */ 1.000000e+00, /* 33 4 */ 1.000000e+00, /* 33 5 */ 1.000000e+00, /* 33 6 */ 1.000000e+00, /* 33 7 */ 1.000000e+00, /* 33 8 */ 1.000000e+00, /* 33 9 */ 1.000000e+00, /* 33 10 */ 1.000000e+00, /* 33 11 */ 1.000000e+00, /* 33 12 */ 9.999982e-01, /* 33 13 */ 9.997782e-01, /* 33 14 */ 9.881109e-01, /* 33 15 */ 8.623436e-01, /* 33 16 */ 5.440909e-01, /* 33 17 */ 2.428600e-01, /* 33 18 */ 8.408545e-02, /* 33 19 */ 2.426545e-02, /* 33 20 */ 6.121818e-03, /* 33 21 */ 1.385455e-03, /* 33 22 */ 2.618182e-04, /* 33 23 */ 5.818182e-05, /* 33 24 */ 1.347999e-05, /* 33 25 */ 1.587125e-06, /* 33 26 */ 1.599811e-07, /* 33 27 */ 1.360743e-08, /* 33 28 */ 9.578529e-10, /* 33 29 */ 5.431157e-11, /* 33 30 */ 2.383911e-12, /* 33 31 */ 7.601493e-14, /* 33 32 */ 1.566672e-15, /* 33 33 */ 1.566672e-17, /* 34 0 */ 1.000000e+00, /* 34 1 */ 1.000000e+00, /* 34 2 */ 1.000000e+00, /* 34 3 */ 1.000000e+00, /* 34 4 */ 1.000000e+00, /* 34 5 */ 1.000000e+00, /* 34 6 */ 1.000000e+00, /* 34 7 */ 1.000000e+00, /* 34 8 */ 1.000000e+00, /* 34 9 */ 1.000000e+00, /* 34 10 */ 1.000000e+00, /* 34 11 */ 1.000000e+00, /* 34 12 */ 1.000000e+00, /* 34 13 */ 9.999491e-01, /* 34 14 */ 9.967473e-01, /* 34 15 */ 9.345491e-01, /* 34 16 */ 6.803855e-01, /* 34 17 */ 3.466745e-01, /* 34 18 */ 1.326655e-01, /* 34 19 */ 4.164000e-02, /* 34 20 */ 1.138000e-02, /* 34 21 */ 2.674545e-03, /* 34 22 */ 6.127273e-04, /* 34 23 */ 1.236364e-04, /* 34 24 */ 3.272727e-05, /* 34 25 */ 4.832540e-06, /* 34 26 */ 5.476121e-07, /* 34 27 */ 5.319727e-08, /* 34 28 */ 4.366179e-09, /* 34 29 */ 2.969215e-10, /* 34 30 */ 1.628299e-11, /* 34 31 */ 6.919649e-13, /* 34 32 */ 2.138318e-14, /* 34 33 */ 4.274975e-16, /* 34 34 */ 4.150461e-18, /* 35 0 */ 1.000000e+00, /* 35 1 */ 1.000000e+00, /* 35 2 */ 1.000000e+00, /* 35 3 */ 1.000000e+00, /* 35 4 */ 1.000000e+00, /* 35 5 */ 1.000000e+00, /* 35 6 */ 1.000000e+00, /* 35 7 */ 1.000000e+00, /* 35 8 */ 1.000000e+00, /* 35 9 */ 1.000000e+00, /* 35 10 */ 1.000000e+00, /* 35 11 */ 1.000000e+00, /* 35 12 */ 1.000000e+00, /* 35 13 */ 9.999891e-01, /* 35 14 */ 9.993000e-01, /* 35 15 */ 9.741855e-01, /* 35 16 */ 8.002673e-01, /* 35 17 */ 4.693836e-01, /* 35 18 */ 2.005109e-01, /* 35 19 */ 6.863273e-02, /* 35 20 */ 2.008182e-02, /* 35 21 */ 4.994545e-03, /* 35 22 */ 1.203636e-03, /* 35 23 */ 2.509091e-04, /* 35 24 */ 6.909091e-05, /* 35 25 */ 1.361253e-05, /* 35 26 */ 1.712671e-06, /* 35 27 */ 1.870482e-07, /* 35 28 */ 1.753457e-08, /* 35 29 */ 1.390408e-09, /* 35 30 */ 9.145275e-11, /* 35 31 */ 4.855738e-12, /* 35 32 */ 1.999846e-13, /* 35 33 */ 5.994838e-15, /* 35 34 */ 1.163620e-16, /* 35 35 */ 1.097755e-18, /* 36 0 */ 1.000000e+00, /* 36 1 */ 1.000000e+00, /* 36 2 */ 1.000000e+00, /* 36 3 */ 1.000000e+00, /* 36 4 */ 1.000000e+00, /* 36 5 */ 1.000000e+00, /* 36 6 */ 1.000000e+00, /* 36 7 */ 1.000000e+00, /* 36 8 */ 1.000000e+00, /* 36 9 */ 1.000000e+00, /* 36 10 */ 1.000000e+00, /* 36 11 */ 1.000000e+00, /* 36 12 */ 1.000000e+00, /* 36 13 */ 1.000000e+00, /* 36 14 */ 9.998473e-01, /* 36 15 */ 9.916673e-01, /* 36 16 */ 8.920873e-01, /* 36 17 */ 6.013491e-01, /* 36 18 */ 2.898691e-01, /* 36 19 */ 1.085455e-01, /* 36 20 */ 3.413636e-02, /* 36 21 */ 9.327273e-03, /* 36 22 */ 2.260000e-03, /* 36 23 */ 5.000000e-04, /* 36 24 */ 1.254545e-04, /* 36 25 */ 2.727273e-05, /* 36 26 */ 4.951677e-06, /* 36 27 */ 6.004733e-07, /* 36 28 */ 6.328771e-08, /* 36 29 */ 5.732104e-09, /* 36 30 */ 4.396344e-10, /* 36 31 */ 2.799794e-11, /* 36 32 */ 1.440749e-12, /* 36 33 */ 5.756166e-14, /* 36 34 */ 1.675315e-15, /* 36 35 */ 3.159878e-17, /* 36 36 */ 2.898970e-19, /* 37 0 */ 1.000000e+00, /* 37 1 */ 1.000000e+00, /* 37 2 */ 1.000000e+00, /* 37 3 */ 1.000000e+00, /* 37 4 */ 1.000000e+00, /* 37 5 */ 1.000000e+00, /* 37 6 */ 1.000000e+00, /* 37 7 */ 1.000000e+00, /* 37 8 */ 1.000000e+00, /* 37 9 */ 1.000000e+00, /* 37 10 */ 1.000000e+00, /* 37 11 */ 1.000000e+00, /* 37 12 */ 1.000000e+00, /* 37 13 */ 1.000000e+00, /* 37 14 */ 9.999709e-01, /* 37 15 */ 9.978782e-01, /* 37 16 */ 9.506036e-01, /* 37 17 */ 7.282236e-01, /* 37 18 */ 3.987636e-01, /* 37 19 */ 1.646855e-01, /* 37 20 */ 5.604727e-02, /* 37 21 */ 1.618545e-02, /* 37 22 */ 4.296364e-03, /* 37 23 */ 1.007273e-03, /* 37 24 */ 2.272727e-04, /* 37 25 */ 5.272727e-05, /* 37 26 */ 1.335903e-05, /* 37 27 */ 1.780765e-06, /* 37 28 */ 2.084087e-07, /* 37 29 */ 2.122332e-08, /* 37 30 */ 1.859323e-09, /* 37 31 */ 1.380787e-10, /* 37 32 */ 8.522708e-12, /* 37 33 */ 4.254562e-13, /* 37 34 */ 1.650411e-14, /* 37 35 */ 4.667715e-16, /* 37 36 */ 8.561809e-18, /* 37 37 */ 7.644472e-20, /* 38 0 */ 1.000000e+00, /* 38 1 */ 1.000000e+00, /* 38 2 */ 1.000000e+00, /* 38 3 */ 1.000000e+00, /* 38 4 */ 1.000000e+00, /* 38 5 */ 1.000000e+00, /* 38 6 */ 1.000000e+00, /* 38 7 */ 1.000000e+00, /* 38 8 */ 1.000000e+00, /* 38 9 */ 1.000000e+00, /* 38 10 */ 1.000000e+00, /* 38 11 */ 1.000000e+00, /* 38 12 */ 1.000000e+00, /* 38 13 */ 1.000000e+00, /* 38 14 */ 1.000000e+00, /* 38 15 */ 9.995291e-01, /* 38 16 */ 9.810600e-01, /* 38 17 */ 8.353509e-01, /* 38 18 */ 5.225836e-01, /* 38 19 */ 2.401600e-01, /* 38 20 */ 8.822364e-02, /* 38 21 */ 2.739455e-02, /* 38 22 */ 7.583636e-03, /* 38 23 */ 1.885455e-03, /* 38 24 */ 4.309091e-04, /* 38 25 */ 1.000000e-04, /* 38 26 */ 2.909091e-05, /* 38 27 */ 4.924639e-06, /* 38 28 */ 6.335722e-07, /* 38 29 */ 7.164674e-08, /* 38 30 */ 7.057612e-09, /* 38 31 */ 5.986987e-10, /* 38 32 */ 4.309330e-11, /* 38 33 */ 2.580401e-12, /* 38 34 */ 1.250740e-13, /* 38 35 */ 4.714790e-15, /* 38 36 */ 1.296792e-16, /* 38 37 */ 2.314981e-18, /* 38 38 */ 2.013027e-20, /* 39 0 */ 1.000000e+00, /* 39 1 */ 1.000000e+00, /* 39 2 */ 1.000000e+00, /* 39 3 */ 1.000000e+00, /* 39 4 */ 1.000000e+00, /* 39 5 */ 1.000000e+00, /* 39 6 */ 1.000000e+00, /* 39 7 */ 1.000000e+00, /* 39 8 */ 1.000000e+00, /* 39 9 */ 1.000000e+00, /* 39 10 */ 1.000000e+00, /* 39 11 */ 1.000000e+00, /* 39 12 */ 1.000000e+00, /* 39 13 */ 1.000000e+00, /* 39 14 */ 1.000000e+00, /* 39 15 */ 9.998836e-01, /* 39 16 */ 9.940309e-01, /* 39 17 */ 9.138745e-01, /* 39 18 */ 6.495091e-01, /* 39 19 */ 3.354945e-01, /* 39 20 */ 1.346200e-01, /* 39 21 */ 4.504364e-02, /* 39 22 */ 1.313636e-02, /* 39 23 */ 3.481818e-03, /* 39 24 */ 8.290909e-04, /* 39 25 */ 1.836364e-04, /* 39 26 */ 5.636364e-05, /* 39 27 */ 1.279770e-05, /* 39 28 */ 1.794965e-06, /* 39 29 */ 2.231459e-07, /* 39 30 */ 2.441015e-08, /* 39 31 */ 2.328391e-09, /* 39 32 */ 1.914474e-10, /* 39 33 */ 1.336871e-11, /* 39 34 */ 7.772841e-13, /* 39 35 */ 3.661232e-14, /* 39 36 */ 1.342230e-15, /* 39 37 */ 3.593008e-17, /* 39 38 */ 6.246868e-19, /* 39 39 */ 5.293956e-21, /* 40 0 */ 1.000000e+00, /* 40 1 */ 1.000000e+00, /* 40 2 */ 1.000000e+00, /* 40 3 */ 1.000000e+00, /* 40 4 */ 1.000000e+00, /* 40 5 */ 1.000000e+00, /* 40 6 */ 1.000000e+00, /* 40 7 */ 1.000000e+00, /* 40 8 */ 1.000000e+00, /* 40 9 */ 1.000000e+00, /* 40 10 */ 1.000000e+00, /* 40 11 */ 1.000000e+00, /* 40 12 */ 1.000000e+00, /* 40 13 */ 1.000000e+00, /* 40 14 */ 1.000000e+00, /* 40 15 */ 9.999855e-01, /* 40 16 */ 9.985218e-01, /* 40 17 */ 9.615964e-01, /* 40 18 */ 7.668636e-01, /* 40 19 */ 4.470873e-01, /* 40 20 */ 1.971200e-01, /* 40 21 */ 7.127636e-02, /* 40 22 */ 2.214545e-02, /* 40 23 */ 6.107273e-03, /* 40 24 */ 1.563636e-03, /* 40 25 */ 4.000000e-04, /* 40 26 */ 9.818182e-05, /* 40 27 */ 2.727273e-05, /* 40 28 */ 4.775773e-06, /* 40 29 */ 6.472909e-07, /* 40 30 */ 7.784511e-08, /* 40 31 */ 8.246177e-09, /* 40 32 */ 7.624211e-10, /* 40 33 */ 6.081897e-11, /* 40 34 */ 4.123850e-12, /* 40 35 */ 2.330079e-13, /* 40 36 */ 1.067409e-14, /* 40 37 */ 3.808568e-16, /* 40 38 */ 9.929493e-18, /* 40 39 */ 1.682494e-19, /* 40 40 */ 1.390491e-21, /* 41 0 */ 1.000000e+00, /* 41 1 */ 1.000000e+00, /* 41 2 */ 1.000000e+00, /* 41 3 */ 1.000000e+00, /* 41 4 */ 1.000000e+00, /* 41 5 */ 1.000000e+00, /* 41 6 */ 1.000000e+00, /* 41 7 */ 1.000000e+00, /* 41 8 */ 1.000000e+00, /* 41 9 */ 1.000000e+00, /* 41 10 */ 1.000000e+00, /* 41 11 */ 1.000000e+00, /* 41 12 */ 1.000000e+00, /* 41 13 */ 1.000000e+00, /* 41 14 */ 1.000000e+00, /* 41 15 */ 9.999982e-01, /* 41 16 */ 9.996836e-01, /* 41 17 */ 9.854945e-01, /* 41 18 */ 8.630436e-01, /* 41 19 */ 5.692127e-01, /* 41 20 */ 2.783564e-01, /* 41 21 */ 1.091036e-01, /* 41 22 */ 3.642364e-02, /* 41 23 */ 1.052545e-02, /* 41 24 */ 2.803636e-03, /* 41 25 */ 7.127273e-04, /* 41 26 */ 1.727273e-04, /* 41 27 */ 4.363636e-05, /* 41 28 */ 1.200995e-05, /* 41 29 */ 1.762333e-06, /* 41 30 */ 2.310793e-07, /* 41 31 */ 2.691219e-08, /* 41 32 */ 2.763383e-09, /* 41 33 */ 2.478829e-10, /* 41 34 */ 1.920108e-11, /* 41 35 */ 1.265251e-12, /* 41 36 */ 6.952903e-14, /* 41 37 */ 3.100028e-15, /* 41 38 */ 1.077303e-16, /* 41 39 */ 2.737359e-18, /* 41 40 */ 4.523354e-20, /* 41 41 */ 3.647867e-22, /* 42 0 */ 1.000000e+00, /* 42 1 */ 1.000000e+00, /* 42 2 */ 1.000000e+00, /* 42 3 */ 1.000000e+00, /* 42 4 */ 1.000000e+00, /* 42 5 */ 1.000000e+00, /* 42 6 */ 1.000000e+00, /* 42 7 */ 1.000000e+00, /* 42 8 */ 1.000000e+00, /* 42 9 */ 1.000000e+00, /* 42 10 */ 1.000000e+00, /* 42 11 */ 1.000000e+00, /* 42 12 */ 1.000000e+00, /* 42 13 */ 1.000000e+00, /* 42 14 */ 1.000000e+00, /* 42 15 */ 1.000000e+00, /* 42 16 */ 9.999400e-01, /* 42 17 */ 9.956200e-01, /* 42 18 */ 9.298000e-01, /* 42 19 */ 6.904818e-01, /* 42 20 */ 3.770509e-01, /* 42 21 */ 1.607691e-01, /* 42 22 */ 5.732000e-02, /* 42 23 */ 1.790182e-02, /* 42 24 */ 4.956364e-03, /* 42 25 */ 1.287273e-03, /* 42 26 */ 3.236364e-04, /* 42 27 */ 8.909091e-05, /* 42 28 */ 2.870078e-05, /* 42 29 */ 4.532606e-06, /* 42 30 */ 6.434737e-07, /* 42 31 */ 8.171026e-08, /* 42 32 */ 9.224648e-09, /* 42 33 */ 9.190054e-10, /* 42 34 */ 8.005158e-11, /* 42 35 */ 6.026240e-12, /* 42 36 */ 3.862141e-13, /* 42 37 */ 2.065689e-14, /* 42 38 */ 8.970424e-16, /* 42 39 */ 3.038228e-17, /* 42 40 */ 7.528752e-19, /* 42 41 */ 1.214006e-20, /* 42 42 */ 9.559106e-23, /* 43 0 */ 1.000000e+00, /* 43 1 */ 1.000000e+00, /* 43 2 */ 1.000000e+00, /* 43 3 */ 1.000000e+00, /* 43 4 */ 1.000000e+00, /* 43 5 */ 1.000000e+00, /* 43 6 */ 1.000000e+00, /* 43 7 */ 1.000000e+00, /* 43 8 */ 1.000000e+00, /* 43 9 */ 1.000000e+00, /* 43 10 */ 1.000000e+00, /* 43 11 */ 1.000000e+00, /* 43 12 */ 1.000000e+00, /* 43 13 */ 1.000000e+00, /* 43 14 */ 1.000000e+00, /* 43 15 */ 1.000000e+00, /* 43 16 */ 9.999873e-01, /* 43 17 */ 9.989127e-01, /* 43 18 */ 9.693127e-01, /* 43 19 */ 7.987545e-01, /* 43 20 */ 4.900527e-01, /* 43 21 */ 2.294218e-01, /* 43 22 */ 8.803091e-02, /* 43 23 */ 2.904545e-02, /* 43 24 */ 8.496364e-03, /* 43 25 */ 2.352727e-03, /* 43 26 */ 5.927273e-04, /* 43 27 */ 1.581818e-04, /* 43 28 */ 3.454545e-05, /* 43 29 */ 1.107221e-05, /* 43 30 */ 1.691782e-06, /* 43 31 */ 2.326039e-07, /* 43 32 */ 2.863275e-08, /* 43 33 */ 3.136358e-09, /* 43 34 */ 3.034254e-10, /* 43 35 */ 2.568689e-11, /* 43 36 */ 1.880737e-12, /* 43 37 */ 1.173182e-13, /* 43 38 */ 6.111650e-15, /* 43 39 */ 2.586715e-16, /* 43 40 */ 8.544185e-18, /* 43 41 */ 2.066084e-19, /* 43 42 */ 3.252888e-21, /* 43 43 */ 2.502221e-23, /* 44 0 */ 1.000000e+00, /* 44 1 */ 1.000000e+00, /* 44 2 */ 1.000000e+00, /* 44 3 */ 1.000000e+00, /* 44 4 */ 1.000000e+00, /* 44 5 */ 1.000000e+00, /* 44 6 */ 1.000000e+00, /* 44 7 */ 1.000000e+00, /* 44 8 */ 1.000000e+00, /* 44 9 */ 1.000000e+00, /* 44 10 */ 1.000000e+00, /* 44 11 */ 1.000000e+00, /* 44 12 */ 1.000000e+00, /* 44 13 */ 1.000000e+00, /* 44 14 */ 1.000000e+00, /* 44 15 */ 1.000000e+00, /* 44 16 */ 9.999945e-01, /* 44 17 */ 9.997709e-01, /* 44 18 */ 9.887491e-01, /* 44 19 */ 8.835436e-01, /* 44 20 */ 6.091655e-01, /* 44 21 */ 3.144418e-01, /* 44 22 */ 1.304509e-01, /* 44 23 */ 4.616182e-02, /* 44 24 */ 1.412727e-02, /* 44 25 */ 4.100000e-03, /* 44 26 */ 1.101818e-03, /* 44 27 */ 2.872727e-04, /* 44 28 */ 6.545455e-05, /* 44 29 */ 2.580812e-05, /* 44 30 */ 4.222470e-06, /* 44 31 */ 6.248615e-07, /* 44 32 */ 8.328601e-08, /* 44 33 */ 9.947662e-09, /* 44 34 */ 1.058166e-09, /* 44 35 */ 9.949435e-11, /* 44 36 */ 8.192334e-12, /* 44 37 */ 5.838328e-13, /* 44 38 */ 3.547233e-14, /* 44 39 */ 1.801075e-15, /* 44 40 */ 7.434345e-17, /* 44 41 */ 2.396322e-18, /* 44 42 */ 5.657843e-20, /* 44 43 */ 8.702360e-22, /* 44 44 */ 6.543128e-24, /* 45 0 */ 1.000000e+00, /* 45 1 */ 1.000000e+00, /* 45 2 */ 1.000000e+00, /* 45 3 */ 1.000000e+00, /* 45 4 */ 1.000000e+00, /* 45 5 */ 1.000000e+00, /* 45 6 */ 1.000000e+00, /* 45 7 */ 1.000000e+00, /* 45 8 */ 1.000000e+00, /* 45 9 */ 1.000000e+00, /* 45 10 */ 1.000000e+00, /* 45 11 */ 1.000000e+00, /* 45 12 */ 1.000000e+00, /* 45 13 */ 1.000000e+00, /* 45 14 */ 1.000000e+00, /* 45 15 */ 1.000000e+00, /* 45 16 */ 1.000000e+00, /* 45 17 */ 9.999564e-01, /* 45 18 */ 9.966509e-01, /* 45 19 */ 9.415818e-01, /* 45 20 */ 7.239727e-01, /* 45 21 */ 4.167873e-01, /* 45 22 */ 1.870564e-01, /* 45 23 */ 7.046545e-02, /* 45 24 */ 2.312182e-02, /* 45 25 */ 6.969091e-03, /* 45 26 */ 1.892727e-03, /* 45 27 */ 5.000000e-04, /* 45 28 */ 1.309091e-04, /* 45 29 */ 2.363636e-05, /* 45 30 */ 1.005114e-05, /* 45 31 */ 1.592761e-06, /* 45 32 */ 2.285070e-07, /* 45 33 */ 2.955320e-08, /* 45 34 */ 3.427961e-09, /* 45 35 */ 3.544035e-10, /* 45 36 */ 3.241173e-11, /* 45 37 */ 2.597673e-12, /* 45 38 */ 1.803171e-13, /* 45 39 */ 1.067811e-14, /* 45 40 */ 5.287662e-16, /* 45 41 */ 2.129909e-17, /* 45 42 */ 6.703430e-19, /* 45 43 */ 1.546225e-20, /* 45 44 */ 2.324636e-22, /* 45 45 */ 1.709291e-24, /* 46 0 */ 1.000000e+00, /* 46 1 */ 1.000000e+00, /* 46 2 */ 1.000000e+00, /* 46 3 */ 1.000000e+00, /* 46 4 */ 1.000000e+00, /* 46 5 */ 1.000000e+00, /* 46 6 */ 1.000000e+00, /* 46 7 */ 1.000000e+00, /* 46 8 */ 1.000000e+00, /* 46 9 */ 1.000000e+00, /* 46 10 */ 1.000000e+00, /* 46 11 */ 1.000000e+00, /* 46 12 */ 1.000000e+00, /* 46 13 */ 1.000000e+00, /* 46 14 */ 1.000000e+00, /* 46 15 */ 1.000000e+00, /* 46 16 */ 1.000000e+00, /* 46 17 */ 9.999873e-01, /* 46 18 */ 9.991945e-01, /* 46 19 */ 9.749400e-01, /* 46 20 */ 8.239800e-01, /* 46 21 */ 5.291509e-01, /* 46 22 */ 2.600491e-01, /* 46 23 */ 1.046618e-01, /* 46 24 */ 3.656909e-02, /* 46 25 */ 1.147636e-02, /* 46 26 */ 3.390909e-03, /* 46 27 */ 8.654545e-04, /* 46 28 */ 2.163636e-04, /* 46 29 */ 6.363636e-05, /* 46 30 */ 2.291027e-05, /* 46 31 */ 3.870297e-06, /* 46 32 */ 5.946037e-07, /* 46 33 */ 8.277658e-08, /* 46 34 */ 1.039699e-08, /* 46 35 */ 1.172141e-09, /* 46 36 */ 1.178721e-10, /* 46 37 */ 1.049294e-11, /* 46 38 */ 8.191423e-13, /* 46 39 */ 5.542111e-14, /* 46 40 */ 3.200859e-15, /* 46 41 */ 1.546779e-16, /* 46 42 */ 6.083654e-18, /* 46 43 */ 1.870577e-19, /* 46 44 */ 4.217467e-21, /* 46 45 */ 6.200846e-23, /* 46 46 */ 4.461040e-25, /* 47 0 */ 1.000000e+00, /* 47 1 */ 1.000000e+00, /* 47 2 */ 1.000000e+00, /* 47 3 */ 1.000000e+00, /* 47 4 */ 1.000000e+00, /* 47 5 */ 1.000000e+00, /* 47 6 */ 1.000000e+00, /* 47 7 */ 1.000000e+00, /* 47 8 */ 1.000000e+00, /* 47 9 */ 1.000000e+00, /* 47 10 */ 1.000000e+00, /* 47 11 */ 1.000000e+00, /* 47 12 */ 1.000000e+00, /* 47 13 */ 1.000000e+00, /* 47 14 */ 1.000000e+00, /* 47 15 */ 1.000000e+00, /* 47 16 */ 1.000000e+00, /* 47 17 */ 1.000000e+00, /* 47 18 */ 9.998400e-01, /* 47 19 */ 9.908709e-01, /* 47 20 */ 9.002327e-01, /* 47 21 */ 6.445527e-01, /* 47 22 */ 3.496745e-01, /* 47 23 */ 1.514055e-01, /* 47 24 */ 5.606727e-02, /* 47 25 */ 1.855091e-02, /* 47 26 */ 5.649091e-03, /* 47 27 */ 1.465455e-03, /* 47 28 */ 4.400000e-04, /* 47 29 */ 1.018182e-04, /* 47 30 */ 2.181818e-05, /* 47 31 */ 9.001442e-06, /* 47 32 */ 1.474317e-06, /* 47 33 */ 2.197961e-07, /* 47 34 */ 2.971721e-08, /* 47 35 */ 3.627943e-09, /* 47 36 */ 3.978434e-10, /* 47 37 */ 3.894349e-11, /* 47 38 */ 3.376828e-12, /* 47 39 */ 2.569460e-13, /* 47 40 */ 1.695502e-14, /* 47 41 */ 9.556262e-16, /* 47 42 */ 4.509145e-17, /* 47 43 */ 1.732648e-18, /* 47 44 */ 5.207469e-20, /* 47 45 */ 1.148217e-21, /* 47 46 */ 1.651776e-23, /* 47 47 */ 1.163223e-25, /* 48 0 */ 1.000000e+00, /* 48 1 */ 1.000000e+00, /* 48 2 */ 1.000000e+00, /* 48 3 */ 1.000000e+00, /* 48 4 */ 1.000000e+00, /* 48 5 */ 1.000000e+00, /* 48 6 */ 1.000000e+00, /* 48 7 */ 1.000000e+00, /* 48 8 */ 1.000000e+00, /* 48 9 */ 1.000000e+00, /* 48 10 */ 1.000000e+00, /* 48 11 */ 1.000000e+00, /* 48 12 */ 1.000000e+00, /* 48 13 */ 1.000000e+00, /* 48 14 */ 1.000000e+00, /* 48 15 */ 1.000000e+00, /* 48 16 */ 1.000000e+00, /* 48 17 */ 1.000000e+00, /* 48 18 */ 9.999691e-01, /* 48 19 */ 9.972855e-01, /* 48 20 */ 9.503600e-01, /* 48 21 */ 7.527745e-01, /* 48 22 */ 4.519164e-01, /* 48 23 */ 2.128200e-01, /* 48 24 */ 8.375636e-02, /* 48 25 */ 2.908182e-02, /* 48 26 */ 9.198182e-03, /* 48 27 */ 2.627273e-03, /* 48 28 */ 7.218182e-04, /* 48 29 */ 1.927273e-04, /* 48 30 */ 4.545455e-05, /* 48 31 */ 2.010826e-05, /* 48 32 */ 3.497392e-06, /* 48 33 */ 5.558840e-07, /* 48 34 */ 8.048867e-08, /* 48 35 */ 1.057759e-08, /* 48 36 */ 1.256115e-09, /* 48 37 */ 1.340855e-10, /* 48 38 */ 1.278501e-11, /* 48 39 */ 1.080571e-12, /* 48 40 */ 8.019253e-14, /* 48 41 */ 5.164104e-15, /* 48 42 */ 2.842071e-16, /* 48 43 */ 1.310165e-17, /* 48 44 */ 4.920988e-19, /* 48 45 */ 1.446419e-20, /* 48 46 */ 3.120494e-22, /* 48 47 */ 4.394208e-24, /* 48 48 */ 3.030488e-26, /* 49 0 */ 1.000000e+00, /* 49 1 */ 1.000000e+00, /* 49 2 */ 1.000000e+00, /* 49 3 */ 1.000000e+00, /* 49 4 */ 1.000000e+00, /* 49 5 */ 1.000000e+00, /* 49 6 */ 1.000000e+00, /* 49 7 */ 1.000000e+00, /* 49 8 */ 1.000000e+00, /* 49 9 */ 1.000000e+00, /* 49 10 */ 1.000000e+00, /* 49 11 */ 1.000000e+00, /* 49 12 */ 1.000000e+00, /* 49 13 */ 1.000000e+00, /* 49 14 */ 1.000000e+00, /* 49 15 */ 1.000000e+00, /* 49 16 */ 1.000000e+00, /* 49 17 */ 1.000000e+00, /* 49 18 */ 9.999964e-01, /* 49 19 */ 9.993364e-01, /* 49 20 */ 9.790891e-01, /* 49 21 */ 8.448345e-01, /* 49 22 */ 5.628055e-01, /* 49 23 */ 2.895964e-01, /* 49 24 */ 1.218327e-01, /* 49 25 */ 4.456364e-02, /* 49 26 */ 1.467455e-02, /* 49 27 */ 4.443636e-03, /* 49 28 */ 1.227273e-03, /* 49 29 */ 3.490909e-04, /* 49 30 */ 9.090909e-05, /* 49 31 */ 4.327777e-05, /* 49 32 */ 7.965546e-06, /* 49 33 */ 1.344503e-06, /* 49 34 */ 2.075567e-07, /* 49 35 */ 2.921216e-08, /* 49 36 */ 3.734365e-09, /* 49 37 */ 4.316877e-10, /* 49 38 */ 4.488768e-11, /* 49 39 */ 4.171887e-12, /* 49 40 */ 3.439059e-13, /* 49 41 */ 2.490755e-14, /* 49 42 */ 1.566203e-15, /* 49 43 */ 8.421283e-17, /* 49 44 */ 3.794760e-18, /* 49 45 */ 1.393928e-19, /* 49 46 */ 4.008833e-21, /* 49 47 */ 8.466055e-23, /* 49 48 */ 1.167514e-24, /* 49 49 */ 7.888609e-27, /* 50 0 */ 1.000000e+00, /* 50 1 */ 1.000000e+00, /* 50 2 */ 1.000000e+00, /* 50 3 */ 1.000000e+00, /* 50 4 */ 1.000000e+00, /* 50 5 */ 1.000000e+00, /* 50 6 */ 1.000000e+00, /* 50 7 */ 1.000000e+00, /* 50 8 */ 1.000000e+00, /* 50 9 */ 1.000000e+00, /* 50 10 */ 1.000000e+00, /* 50 11 */ 1.000000e+00, /* 50 12 */ 1.000000e+00, /* 50 13 */ 1.000000e+00, /* 50 14 */ 1.000000e+00, /* 50 15 */ 1.000000e+00, /* 50 16 */ 1.000000e+00, /* 50 17 */ 1.000000e+00, /* 50 18 */ 1.000000e+00, /* 50 19 */ 9.998582e-01, /* 50 20 */ 9.925655e-01, /* 50 21 */ 9.130836e-01, /* 50 22 */ 6.745400e-01, /* 50 23 */ 3.807000e-01, /* 50 24 */ 1.719945e-01, /* 50 25 */ 6.671273e-02, /* 50 26 */ 2.311818e-02, /* 50 27 */ 7.265455e-03, /* 50 28 */ 2.103636e-03, /* 50 29 */ 5.945455e-04, /* 50 30 */ 1.854545e-04, /* 50 31 */ 4.363636e-05, /* 50 32 */ 1.747206e-05, /* 50 33 */ 3.120954e-06, /* 50 34 */ 5.116619e-07, /* 50 35 */ 7.677976e-08, /* 50 36 */ 1.051201e-08, /* 50 37 */ 1.308154e-09, /* 50 38 */ 1.473078e-10, /* 50 39 */ 1.493061e-11, /* 50 40 */ 1.353458e-12, /* 50 41 */ 1.088853e-13, /* 50 42 */ 7.700562e-15, /* 50 43 */ 4.730807e-16, /* 50 44 */ 2.486481e-17, /* 50 45 */ 1.095785e-18, /* 50 46 */ 3.938416e-20, /* 50 47 */ 1.108758e-21, /* 50 48 */ 2.293122e-23, /* 50 49 */ 3.098259e-25, /* 50 50 */ 2.051827e-27, /* 51 0 */ 1.000000e+00, /* 51 1 */ 1.000000e+00, /* 51 2 */ 1.000000e+00, /* 51 3 */ 1.000000e+00, /* 51 4 */ 1.000000e+00, /* 51 5 */ 1.000000e+00, /* 51 6 */ 1.000000e+00, /* 51 7 */ 1.000000e+00, /* 51 8 */ 1.000000e+00, /* 51 9 */ 1.000000e+00, /* 51 10 */ 1.000000e+00, /* 51 11 */ 1.000000e+00, /* 51 12 */ 1.000000e+00, /* 51 13 */ 1.000000e+00, /* 51 14 */ 1.000000e+00, /* 51 15 */ 1.000000e+00, /* 51 16 */ 1.000000e+00, /* 51 17 */ 1.000000e+00, /* 51 18 */ 1.000000e+00, /* 51 19 */ 9.999818e-01, /* 51 20 */ 9.977582e-01, /* 51 21 */ 9.574091e-01, /* 51 22 */ 7.771127e-01, /* 51 23 */ 4.843073e-01, /* 51 24 */ 2.370891e-01, /* 51 25 */ 9.729818e-02, /* 51 26 */ 3.544000e-02, /* 51 27 */ 1.151636e-02, /* 51 28 */ 3.529091e-03, /* 51 29 */ 9.763636e-04, /* 51 30 */ 2.963636e-04, /* 51 31 */ 8.727273e-05, /* 51 32 */ 3.700954e-05, /* 51 33 */ 6.974399e-06, /* 51 34 */ 1.210079e-06, /* 51 35 */ 1.928461e-07, /* 51 36 */ 2.815128e-08, /* 51 37 */ 3.752039e-09, /* 51 38 */ 4.548453e-10, /* 51 39 */ 4.992671e-11, /* 51 40 */ 4.935757e-12, /* 51 41 */ 4.366615e-13, /* 51 42 */ 3.430342e-14, /* 51 43 */ 2.370237e-15, /* 51 44 */ 1.423408e-16, /* 51 45 */ 7.316749e-18, /* 51 46 */ 3.155025e-19, /* 51 47 */ 1.110044e-20, /* 51 48 */ 3.060458e-22, /* 51 49 */ 6.201397e-24, /* 51 50 */ 8.212358e-26, /* 51 51 */ 5.332700e-28, /* 52 0 */ 1.000000e+00, /* 52 1 */ 1.000000e+00, /* 52 2 */ 1.000000e+00, /* 52 3 */ 1.000000e+00, /* 52 4 */ 1.000000e+00, /* 52 5 */ 1.000000e+00, /* 52 6 */ 1.000000e+00, /* 52 7 */ 1.000000e+00, /* 52 8 */ 1.000000e+00, /* 52 9 */ 1.000000e+00, /* 52 10 */ 1.000000e+00, /* 52 11 */ 1.000000e+00, /* 52 12 */ 1.000000e+00, /* 52 13 */ 1.000000e+00, /* 52 14 */ 1.000000e+00, /* 52 15 */ 1.000000e+00, /* 52 16 */ 1.000000e+00, /* 52 17 */ 1.000000e+00, /* 52 18 */ 1.000000e+00, /* 52 19 */ 9.999927e-01, /* 52 20 */ 9.994291e-01, /* 52 21 */ 9.819764e-01, /* 52 22 */ 8.613145e-01, /* 52 23 */ 5.942745e-01, /* 52 24 */ 3.165400e-01, /* 52 25 */ 1.389745e-01, /* 52 26 */ 5.301636e-02, /* 52 27 */ 1.834909e-02, /* 52 28 */ 5.754545e-03, /* 52 29 */ 1.683636e-03, /* 52 30 */ 5.000000e-04, /* 52 31 */ 1.636364e-04, /* 52 32 */ 2.909091e-05, /* 52 33 */ 1.504559e-05, /* 52 34 */ 2.754107e-06, /* 52 35 */ 4.645180e-07, /* 52 36 */ 7.201697e-08, /* 52 37 */ 1.023441e-08, /* 52 38 */ 1.328815e-09, /* 52 39 */ 1.570260e-10, /* 52 40 */ 1.681192e-11, /* 52 41 */ 1.622068e-12, /* 52 42 */ 1.401310e-13, /* 52 43 */ 1.075558e-14, /* 52 44 */ 7.264703e-16, /* 52 45 */ 4.266767e-17, /* 52 46 */ 2.146032e-18, /* 52 47 */ 9.058708e-20, /* 52 48 */ 3.121320e-21, /* 52 49 */ 8.431414e-23, /* 52 50 */ 1.674536e-24, /* 52 51 */ 2.174362e-26, /* 52 52 */ 1.384944e-28, /* 53 0 */ 1.000000e+00, /* 53 1 */ 1.000000e+00, /* 53 2 */ 1.000000e+00, /* 53 3 */ 1.000000e+00, /* 53 4 */ 1.000000e+00, /* 53 5 */ 1.000000e+00, /* 53 6 */ 1.000000e+00, /* 53 7 */ 1.000000e+00, /* 53 8 */ 1.000000e+00, /* 53 9 */ 1.000000e+00, /* 53 10 */ 1.000000e+00, /* 53 11 */ 1.000000e+00, /* 53 12 */ 1.000000e+00, /* 53 13 */ 1.000000e+00, /* 53 14 */ 1.000000e+00, /* 53 15 */ 1.000000e+00, /* 53 16 */ 1.000000e+00, /* 53 17 */ 1.000000e+00, /* 53 18 */ 1.000000e+00, /* 53 19 */ 9.999982e-01, /* 53 20 */ 9.998927e-01, /* 53 21 */ 9.935582e-01, /* 53 22 */ 9.235200e-01, /* 53 23 */ 7.005618e-01, /* 53 24 */ 4.099745e-01, /* 53 25 */ 1.929582e-01, /* 53 26 */ 7.798000e-02, /* 53 27 */ 2.814909e-02, /* 53 28 */ 9.010909e-03, /* 53 29 */ 2.787273e-03, /* 53 30 */ 8.090909e-04, /* 53 31 */ 2.509091e-04, /* 53 32 */ 6.363636e-05, /* 53 33 */ 3.140881e-05, /* 53 34 */ 6.048937e-06, /* 53 35 */ 1.076413e-06, /* 53 36 */ 1.766232e-07, /* 53 37 */ 2.665825e-08, /* 53 38 */ 3.690638e-09, /* 53 39 */ 4.671135e-10, /* 53 40 */ 5.384108e-11, /* 53 41 */ 5.625972e-12, /* 53 42 */ 5.300656e-13, /* 53 43 */ 4.474118e-14, /* 53 44 */ 3.356926e-15, /* 53 45 */ 2.217554e-16, /* 53 46 */ 1.274407e-17, /* 53 47 */ 6.274730e-19, /* 53 48 */ 2.593959e-20, /* 53 49 */ 8.756985e-22, /* 53 50 */ 2.318520e-23, /* 53 51 */ 4.515094e-25, /* 53 52 */ 5.750796e-27, /* 53 53 */ 3.594247e-29, /* 54 0 */ 1.000000e+00, /* 54 1 */ 1.000000e+00, /* 54 2 */ 1.000000e+00, /* 54 3 */ 1.000000e+00, /* 54 4 */ 1.000000e+00, /* 54 5 */ 1.000000e+00, /* 54 6 */ 1.000000e+00, /* 54 7 */ 1.000000e+00, /* 54 8 */ 1.000000e+00, /* 54 9 */ 1.000000e+00, /* 54 10 */ 1.000000e+00, /* 54 11 */ 1.000000e+00, /* 54 12 */ 1.000000e+00, /* 54 13 */ 1.000000e+00, /* 54 14 */ 1.000000e+00, /* 54 15 */ 1.000000e+00, /* 54 16 */ 1.000000e+00, /* 54 17 */ 1.000000e+00, /* 54 18 */ 1.000000e+00, /* 54 19 */ 1.000000e+00, /* 54 20 */ 9.999673e-01, /* 54 21 */ 9.980673e-01, /* 54 22 */ 9.630091e-01, /* 54 23 */ 7.965091e-01, /* 54 24 */ 5.125364e-01, /* 54 25 */ 2.606636e-01, /* 54 26 */ 1.116873e-01, /* 54 27 */ 4.187091e-02, /* 54 28 */ 1.438727e-02, /* 54 29 */ 4.538182e-03, /* 54 30 */ 1.352727e-03, /* 54 31 */ 4.254545e-04, /* 54 32 */ 1.200000e-04, /* 54 33 */ 3.090909e-05, /* 54 34 */ 1.285200e-05, /* 54 35 */ 2.406249e-06, /* 54 36 */ 4.165814e-07, /* 54 37 */ 6.654741e-08, /* 54 38 */ 9.785129e-09, /* 54 39 */ 1.320579e-09, /* 54 40 */ 1.630338e-10, /* 54 41 */ 1.834062e-11, /* 54 42 */ 1.871477e-12, /* 54 43 */ 1.722800e-13, /* 54 44 */ 1.421521e-14, /* 54 45 */ 1.043135e-15, /* 54 46 */ 6.742650e-17, /* 54 47 */ 3.793308e-18, /* 54 48 */ 1.829139e-19, /* 54 49 */ 7.408627e-21, /* 54 50 */ 2.451469e-22, /* 54 51 */ 6.364255e-24, /* 54 52 */ 1.215710e-25, /* 54 53 */ 1.519405e-27, /* 54 54 */ 9.321501e-30, /* 55 0 */ 1.000000e+00, /* 55 1 */ 1.000000e+00, /* 55 2 */ 1.000000e+00, /* 55 3 */ 1.000000e+00, /* 55 4 */ 1.000000e+00, /* 55 5 */ 1.000000e+00, /* 55 6 */ 1.000000e+00, /* 55 7 */ 1.000000e+00, /* 55 8 */ 1.000000e+00, /* 55 9 */ 1.000000e+00, /* 55 10 */ 1.000000e+00, /* 55 11 */ 1.000000e+00, /* 55 12 */ 1.000000e+00, /* 55 13 */ 1.000000e+00, /* 55 14 */ 1.000000e+00, /* 55 15 */ 1.000000e+00, /* 55 16 */ 1.000000e+00, /* 55 17 */ 1.000000e+00, /* 55 18 */ 1.000000e+00, /* 55 19 */ 1.000000e+00, /* 55 20 */ 9.999909e-01, /* 55 21 */ 9.995073e-01, /* 55 22 */ 9.845073e-01, /* 55 23 */ 8.751073e-01, /* 55 24 */ 6.197382e-01, /* 55 25 */ 3.424109e-01, /* 55 26 */ 1.563109e-01, /* 55 27 */ 6.148000e-02, /* 55 28 */ 2.202182e-02, /* 55 29 */ 7.229091e-03, /* 55 30 */ 2.185455e-03, /* 55 31 */ 6.818182e-04, /* 55 32 */ 2.054545e-04, /* 55 33 */ 5.818182e-05, /* 55 34 */ 2.647316e-05, /* 55 35 */ 5.201807e-06, /* 55 36 */ 9.475367e-07, /* 55 37 */ 1.597089e-07, /* 55 38 */ 2.485547e-08, /* 55 39 */ 3.562824e-09, /* 55 40 */ 4.690213e-10, /* 55 41 */ 5.651425e-11, /* 55 42 */ 6.208515e-12, /* 55 43 */ 6.189887e-13, /* 55 44 */ 5.570305e-14, /* 55 45 */ 4.495265e-15, /* 55 46 */ 3.227786e-16, /* 55 47 */ 2.042454e-17, /* 55 48 */ 1.125344e-18, /* 55 49 */ 5.316680e-20, /* 55 50 */ 2.110727e-21, /* 55 51 */ 6.848393e-23, /* 55 52 */ 1.743970e-24, /* 55 53 */ 3.268936e-26, /* 55 54 */ 4.010372e-28, /* 55 55 */ 2.415887e-30, /* 56 0 */ 1.000000e+00, /* 56 1 */ 1.000000e+00, /* 56 2 */ 1.000000e+00, /* 56 3 */ 1.000000e+00, /* 56 4 */ 1.000000e+00, /* 56 5 */ 1.000000e+00, /* 56 6 */ 1.000000e+00, /* 56 7 */ 1.000000e+00, /* 56 8 */ 1.000000e+00, /* 56 9 */ 1.000000e+00, /* 56 10 */ 1.000000e+00, /* 56 11 */ 1.000000e+00, /* 56 12 */ 1.000000e+00, /* 56 13 */ 1.000000e+00, /* 56 14 */ 1.000000e+00, /* 56 15 */ 1.000000e+00, /* 56 16 */ 1.000000e+00, /* 56 17 */ 1.000000e+00, /* 56 18 */ 1.000000e+00, /* 56 19 */ 1.000000e+00, /* 56 20 */ 9.999982e-01, /* 56 21 */ 9.998964e-01, /* 56 22 */ 9.944836e-01, /* 56 23 */ 9.311891e-01, /* 56 24 */ 7.227964e-01, /* 56 25 */ 4.365145e-01, /* 56 26 */ 2.129782e-01, /* 56 27 */ 8.882182e-02, /* 56 28 */ 3.311455e-02, /* 56 29 */ 1.130182e-02, /* 56 30 */ 3.514545e-03, /* 56 31 */ 1.089091e-03, /* 56 32 */ 3.145455e-04, /* 56 33 */ 9.636364e-05, /* 56 34 */ 2.545455e-05, /* 56 35 */ 1.089870e-05, /* 56 36 */ 2.083571e-06, /* 56 37 */ 3.695176e-07, /* 56 38 */ 6.067924e-08, /* 56 39 */ 9.206175e-09, /* 56 40 */ 1.287242e-09, /* 56 41 */ 1.653934e-10, /* 56 42 */ 1.946183e-11, /* 56 43 */ 2.089027e-12, /* 56 44 */ 2.036059e-13, /* 56 45 */ 1.792048e-14, /* 56 46 */ 1.415118e-15, /* 56 47 */ 9.947271e-17, /* 56 48 */ 6.164546e-18, /* 56 49 */ 3.327854e-19, /* 56 50 */ 1.541073e-20, /* 56 51 */ 5.999095e-22, /* 56 52 */ 1.909302e-23, /* 56 53 */ 4.771033e-25, /* 56 54 */ 8.778431e-27, /* 56 55 */ 1.057492e-28, /* 56 56 */ 6.257346e-31, /* 57 0 */ 1.000000e+00, /* 57 1 */ 1.000000e+00, /* 57 2 */ 1.000000e+00, /* 57 3 */ 1.000000e+00, /* 57 4 */ 1.000000e+00, /* 57 5 */ 1.000000e+00, /* 57 6 */ 1.000000e+00, /* 57 7 */ 1.000000e+00, /* 57 8 */ 1.000000e+00, /* 57 9 */ 1.000000e+00, /* 57 10 */ 1.000000e+00, /* 57 11 */ 1.000000e+00, /* 57 12 */ 1.000000e+00, /* 57 13 */ 1.000000e+00, /* 57 14 */ 1.000000e+00, /* 57 15 */ 1.000000e+00, /* 57 16 */ 1.000000e+00, /* 57 17 */ 1.000000e+00, /* 57 18 */ 1.000000e+00, /* 57 19 */ 1.000000e+00, /* 57 20 */ 1.000000e+00, /* 57 21 */ 9.999691e-01, /* 57 22 */ 9.982818e-01, /* 57 23 */ 9.670418e-01, /* 57 24 */ 8.133236e-01, /* 57 25 */ 5.386000e-01, /* 57 26 */ 2.829636e-01, /* 57 27 */ 1.253164e-01, /* 57 28 */ 4.860545e-02, /* 57 29 */ 1.748545e-02, /* 57 30 */ 5.656364e-03, /* 57 31 */ 1.780000e-03, /* 57 32 */ 5.363636e-04, /* 57 33 */ 1.690909e-04, /* 57 34 */ 4.727273e-05, /* 57 35 */ 2.217481e-05, /* 57 36 */ 4.439106e-06, /* 57 37 */ 8.262776e-07, /* 57 38 */ 1.427695e-07, /* 57 39 */ 2.285578e-08, /* 57 40 */ 3.382612e-09, /* 57 41 */ 4.616369e-10, /* 57 42 */ 5.792491e-11, /* 57 43 */ 6.659900e-12, /* 57 44 */ 6.988516e-13, /* 57 45 */ 6.661924e-14, /* 57 46 */ 5.737602e-15, /* 57 47 */ 4.435469e-16, /* 57 48 */ 3.053546e-17, /* 57 49 */ 1.854109e-18, /* 57 50 */ 9.810829e-20, /* 57 51 */ 4.454908e-21, /* 57 52 */ 1.701125e-22, /* 57 53 */ 5.312699e-24, /* 57 54 */ 1.303145e-25, /* 57 55 */ 2.354406e-27, /* 57 56 */ 2.785896e-29, /* 57 57 */ 1.619707e-31, /* 58 0 */ 1.000000e+00, /* 58 1 */ 1.000000e+00, /* 58 2 */ 1.000000e+00, /* 58 3 */ 1.000000e+00, /* 58 4 */ 1.000000e+00, /* 58 5 */ 1.000000e+00, /* 58 6 */ 1.000000e+00, /* 58 7 */ 1.000000e+00, /* 58 8 */ 1.000000e+00, /* 58 9 */ 1.000000e+00, /* 58 10 */ 1.000000e+00, /* 58 11 */ 1.000000e+00, /* 58 12 */ 1.000000e+00, /* 58 13 */ 1.000000e+00, /* 58 14 */ 1.000000e+00, /* 58 15 */ 1.000000e+00, /* 58 16 */ 1.000000e+00, /* 58 17 */ 1.000000e+00, /* 58 18 */ 1.000000e+00, /* 58 19 */ 1.000000e+00, /* 58 20 */ 1.000000e+00, /* 58 21 */ 9.999891e-01, /* 58 22 */ 9.996018e-01, /* 58 23 */ 9.863200e-01, /* 58 24 */ 8.862327e-01, /* 58 25 */ 6.426800e-01, /* 58 26 */ 3.667018e-01, /* 58 27 */ 1.722927e-01, /* 58 28 */ 7.062909e-02, /* 58 29 */ 2.618909e-02, /* 58 30 */ 8.863636e-03, /* 58 31 */ 2.780000e-03, /* 58 32 */ 8.654545e-04, /* 58 33 */ 2.836364e-04, /* 58 34 */ 8.363636e-05, /* 58 35 */ 4.389190e-05, /* 58 36 */ 9.181637e-06, /* 58 37 */ 1.789636e-06, /* 58 38 */ 3.245551e-07, /* 58 39 */ 5.467178e-08, /* 58 40 */ 8.537870e-09, /* 58 41 */ 1.233334e-09, /* 58 42 */ 1.643778e-10, /* 58 43 */ 2.015353e-11, /* 58 44 */ 2.265251e-12, /* 58 45 */ 2.324916e-13, /* 58 46 */ 2.168693e-14, /* 58 47 */ 1.828519e-15, /* 58 48 */ 1.384415e-16, /* 58 49 */ 9.338316e-18, /* 58 50 */ 5.557891e-19, /* 58 51 */ 2.883751e-20, /* 58 52 */ 1.284484e-21, /* 58 53 */ 4.813036e-23, /* 58 54 */ 1.475504e-24, /* 58 55 */ 3.553893e-26, /* 58 56 */ 6.306941e-28, /* 58 57 */ 7.332677e-30, /* 58 58 */ 4.190101e-32, /* 59 0 */ 1.000000e+00, /* 59 1 */ 1.000000e+00, /* 59 2 */ 1.000000e+00, /* 59 3 */ 1.000000e+00, /* 59 4 */ 1.000000e+00, /* 59 5 */ 1.000000e+00, /* 59 6 */ 1.000000e+00, /* 59 7 */ 1.000000e+00, /* 59 8 */ 1.000000e+00, /* 59 9 */ 1.000000e+00, /* 59 10 */ 1.000000e+00, /* 59 11 */ 1.000000e+00, /* 59 12 */ 1.000000e+00, /* 59 13 */ 1.000000e+00, /* 59 14 */ 1.000000e+00, /* 59 15 */ 1.000000e+00, /* 59 16 */ 1.000000e+00, /* 59 17 */ 1.000000e+00, /* 59 18 */ 1.000000e+00, /* 59 19 */ 1.000000e+00, /* 59 20 */ 1.000000e+00, /* 59 21 */ 9.999964e-01, /* 59 22 */ 9.999127e-01, /* 59 23 */ 9.950327e-01, /* 59 24 */ 9.379564e-01, /* 59 25 */ 7.414873e-01, /* 59 26 */ 4.604600e-01, /* 59 27 */ 2.318527e-01, /* 59 28 */ 9.998182e-02, /* 59 29 */ 3.844182e-02, /* 59 30 */ 1.356727e-02, /* 59 31 */ 4.440000e-03, /* 59 32 */ 1.414545e-03, /* 59 33 */ 4.527273e-04, /* 59 34 */ 1.290909e-04, /* 59 35 */ 3.636364e-05, /* 59 36 */ 1.846973e-05, /* 59 37 */ 3.761991e-06, /* 59 38 */ 7.144417e-07, /* 59 39 */ 1.263181e-07, /* 59 40 */ 2.075750e-08, /* 59 41 */ 3.164058e-09, /* 59 42 */ 4.463720e-10, /* 59 43 */ 5.813116e-11, /* 59 44 */ 6.967641e-12, /* 59 45 */ 7.660021e-13, /* 59 46 */ 7.693110e-14, /* 59 47 */ 7.025349e-15, /* 59 48 */ 5.801376e-16, /* 59 49 */ 4.303671e-17, /* 59 50 */ 2.845480e-18, /* 59 51 */ 1.660648e-19, /* 59 52 */ 8.452131e-21, /* 59 53 */ 3.694305e-22, /* 59 54 */ 1.358839e-23, /* 59 55 */ 4.090516e-25, /* 59 56 */ 9.677654e-27, /* 59 57 */ 1.687512e-28, /* 59 58 */ 1.928337e-30, /* 59 59 */ 1.083336e-32, /* 60 0 */ 1.000000e+00, /* 60 1 */ 1.000000e+00, /* 60 2 */ 1.000000e+00, /* 60 3 */ 1.000000e+00, /* 60 4 */ 1.000000e+00, /* 60 5 */ 1.000000e+00, /* 60 6 */ 1.000000e+00, /* 60 7 */ 1.000000e+00, /* 60 8 */ 1.000000e+00, /* 60 9 */ 1.000000e+00, /* 60 10 */ 1.000000e+00, /* 60 11 */ 1.000000e+00, /* 60 12 */ 1.000000e+00, /* 60 13 */ 1.000000e+00, /* 60 14 */ 1.000000e+00, /* 60 15 */ 1.000000e+00, /* 60 16 */ 1.000000e+00, /* 60 17 */ 1.000000e+00, /* 60 18 */ 1.000000e+00, /* 60 19 */ 1.000000e+00, /* 60 20 */ 1.000000e+00, /* 60 21 */ 1.000000e+00, /* 60 22 */ 9.999764e-01, /* 60 23 */ 9.984418e-01, /* 60 24 */ 9.702473e-01, /* 60 25 */ 8.273545e-01, /* 60 26 */ 5.613109e-01, /* 60 27 */ 3.040182e-01, /* 60 28 */ 1.385364e-01, /* 60 29 */ 5.582545e-02, /* 60 30 */ 2.043636e-02, /* 60 31 */ 6.976364e-03, /* 60 32 */ 2.280000e-03, /* 60 33 */ 7.400000e-04, /* 60 34 */ 2.327273e-04, /* 60 35 */ 7.272727e-05, /* 60 36 */ 2.363636e-05, /* 60 37 */ 7.688956e-06, /* 60 38 */ 1.525950e-06, /* 60 39 */ 2.825366e-07, /* 60 40 */ 4.873234e-08, /* 60 41 */ 7.816599e-09, /* 60 42 */ 1.163633e-09, /* 60 43 */ 1.604075e-10, /* 60 44 */ 2.042263e-11, /* 60 45 */ 2.394269e-12, /* 60 46 */ 2.575747e-13, /* 60 47 */ 2.532532e-14, /* 60 48 */ 2.265097e-15, /* 60 49 */ 1.832716e-16, /* 60 50 */ 1.332664e-17, /* 60 51 */ 8.640147e-19, /* 60 52 */ 4.946376e-20, /* 60 53 */ 2.470440e-21, /* 60 54 */ 1.059957e-22, /* 60 55 */ 3.828378e-24, /* 60 56 */ 1.132023e-25, /* 60 57 */ 2.631550e-27, /* 60 58 */ 4.510064e-29, /* 60 59 */ 5.066858e-31, /* 60 60 */ 2.799369e-33, /* 61 0 */ 1.000000e+00, /* 61 1 */ 1.000000e+00, /* 61 2 */ 1.000000e+00, /* 61 3 */ 1.000000e+00, /* 61 4 */ 1.000000e+00, /* 61 5 */ 1.000000e+00, /* 61 6 */ 1.000000e+00, /* 61 7 */ 1.000000e+00, /* 61 8 */ 1.000000e+00, /* 61 9 */ 1.000000e+00, /* 61 10 */ 1.000000e+00, /* 61 11 */ 1.000000e+00, /* 61 12 */ 1.000000e+00, /* 61 13 */ 1.000000e+00, /* 61 14 */ 1.000000e+00, /* 61 15 */ 1.000000e+00, /* 61 16 */ 1.000000e+00, /* 61 17 */ 1.000000e+00, /* 61 18 */ 1.000000e+00, /* 61 19 */ 1.000000e+00, /* 61 20 */ 1.000000e+00, /* 61 21 */ 1.000000e+00, /* 61 22 */ 9.999945e-01, /* 61 23 */ 9.995945e-01, /* 61 24 */ 9.874273e-01, /* 61 25 */ 8.950982e-01, /* 61 26 */ 6.628473e-01, /* 61 27 */ 3.880236e-01, /* 61 28 */ 1.881018e-01, /* 61 29 */ 7.946909e-02, /* 61 30 */ 3.018182e-02, /* 61 31 */ 1.063455e-02, /* 61 32 */ 3.509091e-03, /* 61 33 */ 1.150909e-03, /* 61 34 */ 3.527273e-04, /* 61 35 */ 1.309091e-04, /* 61 36 */ 4.545455e-05, /* 61 37 */ 1.530465e-05, /* 61 38 */ 3.168073e-06, /* 61 39 */ 6.130048e-07, /* 61 40 */ 1.107264e-07, /* 61 41 */ 1.864204e-08, /* 61 42 */ 2.920318e-09, /* 61 43 */ 4.248067e-10, /* 61 44 */ 5.725076e-11, /* 61 45 */ 7.129487e-12, /* 61 46 */ 8.179200e-13, /* 61 47 */ 8.614410e-14, /* 61 48 */ 8.295594e-15, /* 61 49 */ 7.269902e-16, /* 61 50 */ 5.765781e-17, /* 61 51 */ 4.111223e-18, /* 61 52 */ 2.614679e-19, /* 61 53 */ 1.468878e-20, /* 61 54 */ 7.201500e-22, /* 61 55 */ 3.034106e-23, /* 61 56 */ 1.076440e-24, /* 61 57 */ 3.127496e-26, /* 61 58 */ 7.145780e-28, /* 61 59 */ 1.204044e-29, /* 61 60 */ 1.330276e-31, /* 61 61 */ 7.229760e-34, /* 62 0 */ 1.000000e+00, /* 62 1 */ 1.000000e+00, /* 62 2 */ 1.000000e+00, /* 62 3 */ 1.000000e+00, /* 62 4 */ 1.000000e+00, /* 62 5 */ 1.000000e+00, /* 62 6 */ 1.000000e+00, /* 62 7 */ 1.000000e+00, /* 62 8 */ 1.000000e+00, /* 62 9 */ 1.000000e+00, /* 62 10 */ 1.000000e+00, /* 62 11 */ 1.000000e+00, /* 62 12 */ 1.000000e+00, /* 62 13 */ 1.000000e+00, /* 62 14 */ 1.000000e+00, /* 62 15 */ 1.000000e+00, /* 62 16 */ 1.000000e+00, /* 62 17 */ 1.000000e+00, /* 62 18 */ 1.000000e+00, /* 62 19 */ 1.000000e+00, /* 62 20 */ 1.000000e+00, /* 62 21 */ 1.000000e+00, /* 62 22 */ 1.000000e+00, /* 62 23 */ 9.999055e-01, /* 62 24 */ 9.954673e-01, /* 62 25 */ 9.430218e-01, /* 62 26 */ 7.576345e-01, /* 62 27 */ 4.823636e-01, /* 62 28 */ 2.498327e-01, /* 62 29 */ 1.111527e-01, /* 62 30 */ 4.388727e-02, /* 62 31 */ 1.600727e-02, /* 62 32 */ 5.414545e-03, /* 62 33 */ 1.745455e-03, /* 62 34 */ 5.872727e-04, /* 62 35 */ 1.963636e-04, /* 62 36 */ 6.000000e-05, /* 62 37 */ 2.971200e-05, /* 62 38 */ 6.403902e-06, /* 62 39 */ 1.292477e-06, /* 62 40 */ 2.439800e-07, /* 62 41 */ 4.301795e-08, /* 62 42 */ 7.073523e-09, /* 62 43 */ 1.082786e-09, /* 62 44 */ 1.539895e-10, /* 62 45 */ 2.029911e-11, /* 62 46 */ 2.473719e-12, /* 62 47 */ 2.778383e-13, /* 62 48 */ 2.866035e-14, /* 62 49 */ 2.704311e-15, /* 62 50 */ 2.323072e-16, /* 62 51 */ 1.806687e-17, /* 62 52 */ 1.263706e-18, /* 62 53 */ 7.886742e-20, /* 62 54 */ 4.349284e-21, /* 62 55 */ 2.093878e-22, /* 62 56 */ 8.665508e-24, /* 62 57 */ 3.020800e-25, /* 62 58 */ 8.626352e-27, /* 62 59 */ 1.937777e-28, /* 62 60 */ 3.211009e-30, /* 62 61 */ 3.489822e-32, /* 62 62 */ 1.866215e-34, /* 63 0 */ 1.000000e+00, /* 63 1 */ 1.000000e+00, /* 63 2 */ 1.000000e+00, /* 63 3 */ 1.000000e+00, /* 63 4 */ 1.000000e+00, /* 63 5 */ 1.000000e+00, /* 63 6 */ 1.000000e+00, /* 63 7 */ 1.000000e+00, /* 63 8 */ 1.000000e+00, /* 63 9 */ 1.000000e+00, /* 63 10 */ 1.000000e+00, /* 63 11 */ 1.000000e+00, /* 63 12 */ 1.000000e+00, /* 63 13 */ 1.000000e+00, /* 63 14 */ 1.000000e+00, /* 63 15 */ 1.000000e+00, /* 63 16 */ 1.000000e+00, /* 63 17 */ 1.000000e+00, /* 63 18 */ 1.000000e+00, /* 63 19 */ 1.000000e+00, /* 63 20 */ 1.000000e+00, /* 63 21 */ 1.000000e+00, /* 63 22 */ 1.000000e+00, /* 63 23 */ 9.999782e-01, /* 63 24 */ 9.985273e-01, /* 63 25 */ 9.728036e-01, /* 63 26 */ 8.386218e-01, /* 63 27 */ 5.818691e-01, /* 63 28 */ 3.231600e-01, /* 63 29 */ 1.519018e-01, /* 63 30 */ 6.306909e-02, /* 63 31 */ 2.366000e-02, /* 63 32 */ 8.256364e-03, /* 63 33 */ 2.745455e-03, /* 63 34 */ 9.290909e-04, /* 63 35 */ 2.745455e-04, /* 63 36 */ 1.036364e-04, /* 63 37 */ 3.090909e-05, /* 63 38 */ 1.262229e-05, /* 63 39 */ 2.652579e-06, /* 63 40 */ 5.222986e-07, /* 63 41 */ 9.624253e-08, /* 63 42 */ 1.657350e-08, /* 63 43 */ 2.663040e-09, /* 63 44 */ 3.985459e-10, /* 63 45 */ 5.544069e-11, /* 63 46 */ 7.151814e-12, /* 63 47 */ 8.532648e-13, /* 63 48 */ 9.386522e-14, /* 63 49 */ 9.487489e-15, /* 63 50 */ 8.775163e-16, /* 63 51 */ 7.391887e-17, /* 63 52 */ 5.639350e-18, /* 63 53 */ 3.870787e-19, /* 63 54 */ 2.371410e-20, /* 63 55 */ 1.284179e-21, /* 63 56 */ 6.072903e-23, /* 63 57 */ 2.469506e-24, /* 63 58 */ 8.461326e-26, /* 63 59 */ 2.375578e-27, /* 63 60 */ 5.247986e-29, /* 63 61 */ 8.554499e-31, /* 63 62 */ 9.148167e-33, /* 63 63 */ 4.814825e-35, /* 64 0 */ 1.000000e+00, /* 64 1 */ 1.000000e+00, /* 64 2 */ 1.000000e+00, /* 64 3 */ 1.000000e+00, /* 64 4 */ 1.000000e+00, /* 64 5 */ 1.000000e+00, /* 64 6 */ 1.000000e+00, /* 64 7 */ 1.000000e+00, /* 64 8 */ 1.000000e+00, /* 64 9 */ 1.000000e+00, /* 64 10 */ 1.000000e+00, /* 64 11 */ 1.000000e+00, /* 64 12 */ 1.000000e+00, /* 64 13 */ 1.000000e+00, /* 64 14 */ 1.000000e+00, /* 64 15 */ 1.000000e+00, /* 64 16 */ 1.000000e+00, /* 64 17 */ 1.000000e+00, /* 64 18 */ 1.000000e+00, /* 64 19 */ 1.000000e+00, /* 64 20 */ 1.000000e+00, /* 64 21 */ 1.000000e+00, /* 64 22 */ 1.000000e+00, /* 64 23 */ 1.000000e+00, /* 64 24 */ 9.995673e-01, /* 64 25 */ 9.884709e-01, /* 64 26 */ 9.025364e-01, /* 64 27 */ 6.803455e-01, /* 64 28 */ 4.089236e-01, /* 64 29 */ 2.032127e-01, /* 64 30 */ 8.823091e-02, /* 64 31 */ 3.457636e-02, /* 64 32 */ 1.244364e-02, /* 64 33 */ 4.245455e-03, /* 64 34 */ 1.403636e-03, /* 64 35 */ 4.454545e-04, /* 64 36 */ 1.563636e-04, /* 64 37 */ 4.363636e-05, /* 64 38 */ 2.429234e-05, /* 64 39 */ 5.307045e-06, /* 64 40 */ 1.088091e-06, /* 64 41 */ 2.091422e-07, /* 64 42 */ 3.764001e-08, /* 64 43 */ 6.334051e-09, /* 64 44 */ 9.950509e-10, /* 64 45 */ 1.456645e-10, /* 64 46 */ 1.982948e-11, /* 64 47 */ 2.504367e-12, /* 64 48 */ 2.926505e-13, /* 64 49 */ 3.154507e-14, /* 64 50 */ 3.125437e-15, /* 64 51 */ 2.834734e-16, /* 64 52 */ 2.342444e-17, /* 64 53 */ 1.753691e-18, /* 64 54 */ 1.181631e-19, /* 64 55 */ 7.108705e-21, /* 64 56 */ 3.781370e-22, /* 64 57 */ 1.757087e-23, /* 64 58 */ 7.022788e-25, /* 64 59 */ 2.365732e-26, /* 64 60 */ 6.531982e-28, /* 64 61 */ 1.419496e-29, /* 64 62 */ 2.276751e-31, /* 64 63 */ 2.396319e-33, /* 64 64 */ 1.241616e-35, /* 65 0 */ 1.000000e+00, /* 65 1 */ 1.000000e+00, /* 65 2 */ 1.000000e+00, /* 65 3 */ 1.000000e+00, /* 65 4 */ 1.000000e+00, /* 65 5 */ 1.000000e+00, /* 65 6 */ 1.000000e+00, /* 65 7 */ 1.000000e+00, /* 65 8 */ 1.000000e+00, /* 65 9 */ 1.000000e+00, /* 65 10 */ 1.000000e+00, /* 65 11 */ 1.000000e+00, /* 65 12 */ 1.000000e+00, /* 65 13 */ 1.000000e+00, /* 65 14 */ 1.000000e+00, /* 65 15 */ 1.000000e+00, /* 65 16 */ 1.000000e+00, /* 65 17 */ 1.000000e+00, /* 65 18 */ 1.000000e+00, /* 65 19 */ 1.000000e+00, /* 65 20 */ 1.000000e+00, /* 65 21 */ 1.000000e+00, /* 65 22 */ 1.000000e+00, /* 65 23 */ 1.000000e+00, /* 65 24 */ 9.999073e-01, /* 65 25 */ 9.958218e-01, /* 65 26 */ 9.467673e-01, /* 65 27 */ 7.717836e-01, /* 65 28 */ 5.023564e-01, /* 65 29 */ 2.667618e-01, /* 65 30 */ 1.216418e-01, /* 65 31 */ 4.977636e-02, /* 65 32 */ 1.856727e-02, /* 65 33 */ 6.527273e-03, /* 65 34 */ 2.114545e-03, /* 65 35 */ 7.218182e-04, /* 65 36 */ 2.127273e-04, /* 65 37 */ 6.909091e-05, /* 65 38 */ 4.570693e-05, /* 65 39 */ 1.036508e-05, /* 65 40 */ 2.209270e-06, /* 65 41 */ 4.421772e-07, /* 65 42 */ 8.301201e-08, /* 65 43 */ 1.459960e-08, /* 65 44 */ 2.402039e-09, /* 65 45 */ 3.691116e-10, /* 65 46 */ 5.287847e-11, /* 65 47 */ 7.047590e-12, /* 65 48 */ 8.717975e-13, /* 65 49 */ 9.982346e-14, /* 65 50 */ 1.054755e-14, /* 65 51 */ 1.024783e-15, /* 65 52 */ 9.117874e-17, /* 65 53 */ 7.393733e-18, /* 65 54 */ 5.433866e-19, /* 65 55 */ 3.595355e-20, /* 65 56 */ 2.124675e-21, /* 65 57 */ 1.110521e-22, /* 65 58 */ 5.071958e-24, /* 65 59 */ 1.993065e-25, /* 65 60 */ 6.602797e-27, /* 65 61 */ 1.793391e-28, /* 65 62 */ 3.834823e-30, /* 65 63 */ 6.053656e-32, /* 65 64 */ 6.272555e-34, /* 65 65 */ 3.200283e-36, /* 66 0 */ 1.000000e+00, /* 66 1 */ 1.000000e+00, /* 66 2 */ 1.000000e+00, /* 66 3 */ 1.000000e+00, /* 66 4 */ 1.000000e+00, /* 66 5 */ 1.000000e+00, /* 66 6 */ 1.000000e+00, /* 66 7 */ 1.000000e+00, /* 66 8 */ 1.000000e+00, /* 66 9 */ 1.000000e+00, /* 66 10 */ 1.000000e+00, /* 66 11 */ 1.000000e+00, /* 66 12 */ 1.000000e+00, /* 66 13 */ 1.000000e+00, /* 66 14 */ 1.000000e+00, /* 66 15 */ 1.000000e+00, /* 66 16 */ 1.000000e+00, /* 66 17 */ 1.000000e+00, /* 66 18 */ 1.000000e+00, /* 66 19 */ 1.000000e+00, /* 66 20 */ 1.000000e+00, /* 66 21 */ 1.000000e+00, /* 66 22 */ 1.000000e+00, /* 66 23 */ 1.000000e+00, /* 66 24 */ 9.999727e-01, /* 66 25 */ 9.986800e-01, /* 66 26 */ 9.743327e-01, /* 66 27 */ 8.483073e-01, /* 66 28 */ 5.999273e-01, /* 66 29 */ 3.415018e-01, /* 66 30 */ 1.643382e-01, /* 66 31 */ 6.988000e-02, /* 66 32 */ 2.721636e-02, /* 66 33 */ 9.720000e-03, /* 66 34 */ 3.261818e-03, /* 66 35 */ 1.074545e-03, /* 66 36 */ 3.327273e-04, /* 66 37 */ 1.018182e-04, /* 66 38 */ 2.909091e-05, /* 66 39 */ 1.978679e-05, /* 66 40 */ 4.377932e-06, /* 66 41 */ 9.109396e-07, /* 66 42 */ 1.780794e-07, /* 66 43 */ 3.267067e-08, /* 66 44 */ 5.617875e-09, /* 66 45 */ 9.041309e-10, /* 66 46 */ 1.359651e-10, /* 66 47 */ 1.907033e-11, /* 66 48 */ 2.489505e-12, /* 66 49 */ 3.017574e-13, /* 66 50 */ 3.387003e-14, /* 66 51 */ 3.509452e-15, /* 66 52 */ 3.344901e-16, /* 66 53 */ 2.920528e-17, /* 66 54 */ 2.324854e-18, /* 66 55 */ 1.677829e-19, /* 66 56 */ 1.090499e-20, /* 66 57 */ 6.332189e-22, /* 66 58 */ 3.253082e-23, /* 66 59 */ 1.460748e-24, /* 66 60 */ 5.645127e-26, /* 66 61 */ 1.839710e-27, /* 66 62 */ 4.916764e-29, /* 66 63 */ 1.034766e-30, /* 66 64 */ 1.608103e-32, /* 66 65 */ 1.640753e-34, /* 66 66 */ 8.244991e-37, /* 67 0 */ 1.000000e+00, /* 67 1 */ 1.000000e+00, /* 67 2 */ 1.000000e+00, /* 67 3 */ 1.000000e+00, /* 67 4 */ 1.000000e+00, /* 67 5 */ 1.000000e+00, /* 67 6 */ 1.000000e+00, /* 67 7 */ 1.000000e+00, /* 67 8 */ 1.000000e+00, /* 67 9 */ 1.000000e+00, /* 67 10 */ 1.000000e+00, /* 67 11 */ 1.000000e+00, /* 67 12 */ 1.000000e+00, /* 67 13 */ 1.000000e+00, /* 67 14 */ 1.000000e+00, /* 67 15 */ 1.000000e+00, /* 67 16 */ 1.000000e+00, /* 67 17 */ 1.000000e+00, /* 67 18 */ 1.000000e+00, /* 67 19 */ 1.000000e+00, /* 67 20 */ 1.000000e+00, /* 67 21 */ 1.000000e+00, /* 67 22 */ 1.000000e+00, /* 67 23 */ 1.000000e+00, /* 67 24 */ 9.999964e-01, /* 67 25 */ 9.996564e-01, /* 67 26 */ 9.892164e-01, /* 67 27 */ 9.085345e-01, /* 67 28 */ 6.953600e-01, /* 67 29 */ 4.264436e-01, /* 67 30 */ 2.178000e-01, /* 67 31 */ 9.685636e-02, /* 67 32 */ 3.918909e-02, /* 67 33 */ 1.462000e-02, /* 67 34 */ 5.047273e-03, /* 67 35 */ 1.730909e-03, /* 67 36 */ 5.400000e-04, /* 67 37 */ 1.727273e-04, /* 67 38 */ 5.454545e-05, /* 67 39 */ 3.696268e-05, /* 67 40 */ 8.477655e-06, /* 67 41 */ 1.831149e-06, /* 67 42 */ 3.721599e-07, /* 67 43 */ 7.109862e-08, /* 67 44 */ 1.275342e-08, /* 67 45 */ 2.145197e-09, /* 67 46 */ 3.378709e-10, /* 67 47 */ 4.974639e-11, /* 67 48 */ 6.834239e-12, /* 67 49 */ 8.742175e-13, /* 67 50 */ 1.038745e-13, /* 67 51 */ 1.143340e-14, /* 67 52 */ 1.162160e-15, /* 67 53 */ 1.087000e-16, /* 67 54 */ 9.316973e-18, /* 67 55 */ 7.283141e-19, /* 67 56 */ 5.163188e-20, /* 67 57 */ 3.297431e-21, /* 67 58 */ 1.881974e-22, /* 67 59 */ 9.505793e-24, /* 67 60 */ 4.197813e-25, /* 67 61 */ 1.595852e-26, /* 67 62 */ 5.117440e-28, /* 67 63 */ 1.346098e-29, /* 67 64 */ 2.788948e-31, /* 67 65 */ 4.267918e-33, /* 67 66 */ 4.288938e-35, /* 67 67 */ 2.123237e-37, /* 68 0 */ 1.000000e+00, /* 68 1 */ 1.000000e+00, /* 68 2 */ 1.000000e+00, /* 68 3 */ 1.000000e+00, /* 68 4 */ 1.000000e+00, /* 68 5 */ 1.000000e+00, /* 68 6 */ 1.000000e+00, /* 68 7 */ 1.000000e+00, /* 68 8 */ 1.000000e+00, /* 68 9 */ 1.000000e+00, /* 68 10 */ 1.000000e+00, /* 68 11 */ 1.000000e+00, /* 68 12 */ 1.000000e+00, /* 68 13 */ 1.000000e+00, /* 68 14 */ 1.000000e+00, /* 68 15 */ 1.000000e+00, /* 68 16 */ 1.000000e+00, /* 68 17 */ 1.000000e+00, /* 68 18 */ 1.000000e+00, /* 68 19 */ 1.000000e+00, /* 68 20 */ 1.000000e+00, /* 68 21 */ 1.000000e+00, /* 68 22 */ 1.000000e+00, /* 68 23 */ 1.000000e+00, /* 68 24 */ 1.000000e+00, /* 68 25 */ 9.999091e-01, /* 68 26 */ 9.960218e-01, /* 68 27 */ 9.500491e-01, /* 68 28 */ 7.830400e-01, /* 68 29 */ 5.190255e-01, /* 68 30 */ 2.823655e-01, /* 68 31 */ 1.322473e-01, /* 68 32 */ 5.526364e-02, /* 68 33 */ 2.137091e-02, /* 68 34 */ 7.643636e-03, /* 68 35 */ 2.589091e-03, /* 68 36 */ 8.781818e-04, /* 68 37 */ 2.727273e-04, /* 68 38 */ 9.818182e-05, /* 68 39 */ 2.181818e-05, /* 68 40 */ 1.606108e-05, /* 68 41 */ 3.596260e-06, /* 68 42 */ 7.587403e-07, /* 68 43 */ 1.507004e-07, /* 68 44 */ 2.814974e-08, /* 68 45 */ 4.939385e-09, /* 68 46 */ 8.130997e-10, /* 68 47 */ 1.253855e-10, /* 68 48 */ 1.808261e-11, /* 68 49 */ 2.434270e-12, /* 68 50 */ 3.052438e-13, /* 68 51 */ 3.556715e-14, /* 68 52 */ 3.840482e-15, /* 68 53 */ 3.830887e-16, /* 68 54 */ 3.517491e-17, /* 68 55 */ 2.960674e-18, /* 68 56 */ 2.273444e-19, /* 68 57 */ 1.583675e-20, /* 68 58 */ 9.941117e-22, /* 68 59 */ 5.578389e-23, /* 68 60 */ 2.771022e-24, /* 68 61 */ 1.203781e-25, /* 68 62 */ 4.503013e-27, /* 68 63 */ 1.421213e-28, /* 68 64 */ 3.680320e-30, /* 68 65 */ 7.508525e-32, /* 68 66 */ 1.131712e-33, /* 68 67 */ 1.120399e-35, /* 68 68 */ 5.465360e-38, /* 69 0 */ 1.000000e+00, /* 69 1 */ 1.000000e+00, /* 69 2 */ 1.000000e+00, /* 69 3 */ 1.000000e+00, /* 69 4 */ 1.000000e+00, /* 69 5 */ 1.000000e+00, /* 69 6 */ 1.000000e+00, /* 69 7 */ 1.000000e+00, /* 69 8 */ 1.000000e+00, /* 69 9 */ 1.000000e+00, /* 69 10 */ 1.000000e+00, /* 69 11 */ 1.000000e+00, /* 69 12 */ 1.000000e+00, /* 69 13 */ 1.000000e+00, /* 69 14 */ 1.000000e+00, /* 69 15 */ 1.000000e+00, /* 69 16 */ 1.000000e+00, /* 69 17 */ 1.000000e+00, /* 69 18 */ 1.000000e+00, /* 69 19 */ 1.000000e+00, /* 69 20 */ 1.000000e+00, /* 69 21 */ 1.000000e+00, /* 69 22 */ 1.000000e+00, /* 69 23 */ 1.000000e+00, /* 69 24 */ 1.000000e+00, /* 69 25 */ 9.999673e-01, /* 69 26 */ 9.987545e-01, /* 69 27 */ 9.754800e-01, /* 69 28 */ 8.571036e-01, /* 69 29 */ 6.147436e-01, /* 69 30 */ 3.579145e-01, /* 69 31 */ 1.770345e-01, /* 69 32 */ 7.712364e-02, /* 69 33 */ 3.093455e-02, /* 69 34 */ 1.142182e-02, /* 69 35 */ 4.003636e-03, /* 69 36 */ 1.376364e-03, /* 69 37 */ 3.981818e-04, /* 69 38 */ 1.436364e-04, /* 69 39 */ 3.818182e-05, /* 69 40 */ 2.980109e-05, /* 69 41 */ 6.908438e-06, /* 69 42 */ 1.510983e-06, /* 69 43 */ 3.115482e-07, /* 69 44 */ 6.050374e-08, /* 69 45 */ 1.105559e-08, /* 69 46 */ 1.898527e-09, /* 69 47 */ 3.059943e-10, /* 69 48 */ 4.621947e-11, /* 69 49 */ 6.531641e-12, /* 69 50 */ 8.619517e-13, /* 69 51 */ 1.059931e-13, /* 69 52 */ 1.211584e-14, /* 69 53 */ 1.283857e-15, /* 69 54 */ 1.257197e-16, /* 69 55 */ 1.133580e-17, /* 69 56 */ 9.372644e-19, /* 69 57 */ 7.071979e-20, /* 69 58 */ 4.842130e-21, /* 69 59 */ 2.988432e-22, /* 69 60 */ 1.649208e-23, /* 69 61 */ 8.059003e-25, /* 69 62 */ 3.444902e-26, /* 69 63 */ 1.268323e-27, /* 69 64 */ 3.940849e-29, /* 69 65 */ 1.004900e-30, /* 69 66 */ 2.019292e-32, /* 69 67 */ 2.998366e-34, /* 69 68 */ 2.924961e-36, /* 69 69 */ 1.406231e-38, /* 70 0 */ 1.000000e+00, /* 70 1 */ 1.000000e+00, /* 70 2 */ 1.000000e+00, /* 70 3 */ 1.000000e+00, /* 70 4 */ 1.000000e+00, /* 70 5 */ 1.000000e+00, /* 70 6 */ 1.000000e+00, /* 70 7 */ 1.000000e+00, /* 70 8 */ 1.000000e+00, /* 70 9 */ 1.000000e+00, /* 70 10 */ 1.000000e+00, /* 70 11 */ 1.000000e+00, /* 70 12 */ 1.000000e+00, /* 70 13 */ 1.000000e+00, /* 70 14 */ 1.000000e+00, /* 70 15 */ 1.000000e+00, /* 70 16 */ 1.000000e+00, /* 70 17 */ 1.000000e+00, /* 70 18 */ 1.000000e+00, /* 70 19 */ 1.000000e+00, /* 70 20 */ 1.000000e+00, /* 70 21 */ 1.000000e+00, /* 70 22 */ 1.000000e+00, /* 70 23 */ 1.000000e+00, /* 70 24 */ 1.000000e+00, /* 70 25 */ 9.999945e-01, /* 70 26 */ 9.996545e-01, /* 70 27 */ 9.895091e-01, /* 70 28 */ 9.136618e-01, /* 70 29 */ 7.081473e-01, /* 70 30 */ 4.425527e-01, /* 70 31 */ 2.320400e-01, /* 70 32 */ 1.058727e-01, /* 70 33 */ 4.385091e-02, /* 70 34 */ 1.680182e-02, /* 70 35 */ 5.967273e-03, /* 70 36 */ 2.050909e-03, /* 70 37 */ 6.600000e-04, /* 70 38 */ 2.145455e-04, /* 70 39 */ 6.727273e-05, /* 70 40 */ 2.000000e-05, /* 70 41 */ 1.299508e-05, /* 70 42 */ 2.942654e-06, /* 70 43 */ 6.290003e-07, /* 70 44 */ 1.268119e-07, /* 70 45 */ 2.409148e-08, /* 70 46 */ 4.308299e-09, /* 70 47 */ 7.243892e-10, /* 70 48 */ 1.143620e-10, /* 70 49 */ 1.692706e-11, /* 70 50 */ 2.344964e-12, /* 70 51 */ 3.034710e-13, /* 70 52 */ 3.660913e-14, /* 70 53 */ 4.106721e-15, /* 70 54 */ 4.272031e-16, /* 70 55 */ 4.108083e-17, /* 70 56 */ 3.638674e-18, /* 70 57 */ 2.956248e-19, /* 70 58 */ 2.192480e-20, /* 70 59 */ 1.475948e-21, /* 70 60 */ 8.958564e-23, /* 70 61 */ 4.863479e-24, /* 70 62 */ 2.338529e-25, /* 70 63 */ 9.838693e-27, /* 70 64 */ 3.566119e-28, /* 70 65 */ 1.091098e-29, /* 70 66 */ 2.740347e-31, /* 70 67 */ 5.424843e-33, /* 70 68 */ 7.937298e-35, /* 70 69 */ 7.631322e-37, /* 70 70 */ 3.616740e-39, /* 71 0 */ 1.000000e+00, /* 71 1 */ 1.000000e+00, /* 71 2 */ 1.000000e+00, /* 71 3 */ 1.000000e+00, /* 71 4 */ 1.000000e+00, /* 71 5 */ 1.000000e+00, /* 71 6 */ 1.000000e+00, /* 71 7 */ 1.000000e+00, /* 71 8 */ 1.000000e+00, /* 71 9 */ 1.000000e+00, /* 71 10 */ 1.000000e+00, /* 71 11 */ 1.000000e+00, /* 71 12 */ 1.000000e+00, /* 71 13 */ 1.000000e+00, /* 71 14 */ 1.000000e+00, /* 71 15 */ 1.000000e+00, /* 71 16 */ 1.000000e+00, /* 71 17 */ 1.000000e+00, /* 71 18 */ 1.000000e+00, /* 71 19 */ 1.000000e+00, /* 71 20 */ 1.000000e+00, /* 71 21 */ 1.000000e+00, /* 71 22 */ 1.000000e+00, /* 71 23 */ 1.000000e+00, /* 71 24 */ 1.000000e+00, /* 71 25 */ 9.999982e-01, /* 71 26 */ 9.999164e-01, /* 71 27 */ 9.961473e-01, /* 71 28 */ 9.527655e-01, /* 71 29 */ 7.929055e-01, /* 71 30 */ 5.340600e-01, /* 71 31 */ 2.971418e-01, /* 71 32 */ 1.422764e-01, /* 71 33 */ 6.150909e-02, /* 71 34 */ 2.423273e-02, /* 71 35 */ 8.849091e-03, /* 71 36 */ 3.105455e-03, /* 71 37 */ 1.063636e-03, /* 71 38 */ 3.072727e-04, /* 71 39 */ 1.236364e-04, /* 71 40 */ 3.090909e-05, /* 71 41 */ 2.395975e-05, /* 71 42 */ 5.610527e-06, /* 71 43 */ 1.241665e-06, /* 71 44 */ 2.595177e-07, /* 71 45 */ 5.118347e-08, /* 71 46 */ 9.516609e-09, /* 71 47 */ 1.666332e-09, /* 71 48 */ 2.744391e-10, /* 71 49 */ 4.245695e-11, /* 71 50 */ 6.160422e-12, /* 71 51 */ 8.369309e-13, /* 71 52 */ 1.062556e-13, /* 71 53 */ 1.257932e-14, /* 71 54 */ 1.385296e-15, /* 71 55 */ 1.415151e-16, /* 71 56 */ 1.336797e-17, /* 71 57 */ 1.163482e-18, /* 71 58 */ 9.291277e-20, /* 71 59 */ 6.775049e-21, /* 71 60 */ 4.485495e-22, /* 71 61 */ 2.678282e-23, /* 71 62 */ 1.430726e-24, /* 71 63 */ 6.771001e-26, /* 71 64 */ 2.804494e-27, /* 71 65 */ 1.000974e-28, /* 71 66 */ 3.016481e-30, /* 71 67 */ 7.463613e-32, /* 71 68 */ 1.455901e-33, /* 71 69 */ 2.099473e-35, /* 71 70 */ 1.989846e-37, /* 71 71 */ 9.298344e-40, /* 72 0 */ 1.000000e+00, /* 72 1 */ 1.000000e+00, /* 72 2 */ 1.000000e+00, /* 72 3 */ 1.000000e+00, /* 72 4 */ 1.000000e+00, /* 72 5 */ 1.000000e+00, /* 72 6 */ 1.000000e+00, /* 72 7 */ 1.000000e+00, /* 72 8 */ 1.000000e+00, /* 72 9 */ 1.000000e+00, /* 72 10 */ 1.000000e+00, /* 72 11 */ 1.000000e+00, /* 72 12 */ 1.000000e+00, /* 72 13 */ 1.000000e+00, /* 72 14 */ 1.000000e+00, /* 72 15 */ 1.000000e+00, /* 72 16 */ 1.000000e+00, /* 72 17 */ 1.000000e+00, /* 72 18 */ 1.000000e+00, /* 72 19 */ 1.000000e+00, /* 72 20 */ 1.000000e+00, /* 72 21 */ 1.000000e+00, /* 72 22 */ 1.000000e+00, /* 72 23 */ 1.000000e+00, /* 72 24 */ 1.000000e+00, /* 72 25 */ 1.000000e+00, /* 72 26 */ 9.999836e-01, /* 72 27 */ 9.987836e-01, /* 72 28 */ 9.770964e-01, /* 72 29 */ 8.636182e-01, /* 72 30 */ 6.278745e-01, /* 72 31 */ 3.720873e-01, /* 72 32 */ 1.881782e-01, /* 72 33 */ 8.431455e-02, /* 72 34 */ 3.458727e-02, /* 72 35 */ 1.306182e-02, /* 72 36 */ 4.589091e-03, /* 72 37 */ 1.563636e-03, /* 72 38 */ 4.781818e-04, /* 72 39 */ 1.800000e-04, /* 72 40 */ 4.727273e-05, /* 72 41 */ 4.334026e-05, /* 72 42 */ 1.048307e-05, /* 72 43 */ 2.399161e-06, /* 72 44 */ 5.191813e-07, /* 72 45 */ 1.061555e-07, /* 72 46 */ 2.049087e-08, /* 72 47 */ 3.730404e-09, /* 72 48 */ 6.398217e-10, /* 72 49 */ 1.032622e-10, /* 72 50 */ 1.566068e-11, /* 72 51 */ 2.228439e-12, /* 72 52 */ 2.970059e-13, /* 72 53 */ 3.700530e-14, /* 72 54 */ 4.300826e-15, /* 72 55 */ 4.651158e-16, /* 72 56 */ 4.667474e-17, /* 72 57 */ 4.332488e-18, /* 72 58 */ 3.706400e-19, /* 72 59 */ 2.910132e-20, /* 72 60 */ 2.086960e-21, /* 72 61 */ 1.359229e-22, /* 72 62 */ 7.986046e-24, /* 72 63 */ 4.198890e-25, /* 72 64 */ 1.956318e-26, /* 72 65 */ 7.979072e-28, /* 72 66 */ 2.804993e-29, /* 72 67 */ 8.327564e-31, /* 72 68 */ 2.030341e-32, /* 72 69 */ 3.903424e-34, /* 72 70 */ 5.548905e-36, /* 72 71 */ 5.185446e-38, /* 72 72 */ 2.389606e-40, /* 73 0 */ 1.000000e+00, /* 73 1 */ 1.000000e+00, /* 73 2 */ 1.000000e+00, /* 73 3 */ 1.000000e+00, /* 73 4 */ 1.000000e+00, /* 73 5 */ 1.000000e+00, /* 73 6 */ 1.000000e+00, /* 73 7 */ 1.000000e+00, /* 73 8 */ 1.000000e+00, /* 73 9 */ 1.000000e+00, /* 73 10 */ 1.000000e+00, /* 73 11 */ 1.000000e+00, /* 73 12 */ 1.000000e+00, /* 73 13 */ 1.000000e+00, /* 73 14 */ 1.000000e+00, /* 73 15 */ 1.000000e+00, /* 73 16 */ 1.000000e+00, /* 73 17 */ 1.000000e+00, /* 73 18 */ 1.000000e+00, /* 73 19 */ 1.000000e+00, /* 73 20 */ 1.000000e+00, /* 73 21 */ 1.000000e+00, /* 73 22 */ 1.000000e+00, /* 73 23 */ 1.000000e+00, /* 73 24 */ 1.000000e+00, /* 73 25 */ 1.000000e+00, /* 73 26 */ 9.999982e-01, /* 73 27 */ 9.996455e-01, /* 73 28 */ 9.902618e-01, /* 73 29 */ 9.175218e-01, /* 73 30 */ 7.185400e-01, /* 73 31 */ 4.565764e-01, /* 73 32 */ 2.443255e-01, /* 73 33 */ 1.140218e-01, /* 73 34 */ 4.873636e-02, /* 73 35 */ 1.892909e-02, /* 73 36 */ 6.830909e-03, /* 73 37 */ 2.400000e-03, /* 73 38 */ 7.636364e-04, /* 73 39 */ 2.490909e-04, /* 73 40 */ 8.727273e-05, /* 73 41 */ 2.545455e-05, /* 73 42 */ 1.921314e-05, /* 73 43 */ 4.542068e-06, /* 73 44 */ 1.016463e-06, /* 73 45 */ 2.151885e-07, /* 73 46 */ 4.306303e-08, /* 73 47 */ 8.139008e-09, /* 73 48 */ 1.451430e-09, /* 73 49 */ 2.439508e-10, /* 73 50 */ 3.859718e-11, /* 73 51 */ 5.740601e-12, /* 73 52 */ 8.013766e-13, /* 73 53 */ 1.048193e-13, /* 73 54 */ 1.282112e-14, /* 73 55 */ 1.463325e-15, /* 73 56 */ 1.554582e-16, /* 73 57 */ 1.532956e-17, /* 73 58 */ 1.398648e-18, /* 73 59 */ 1.176441e-19, /* 73 60 */ 9.084415e-21, /* 73 61 */ 6.408863e-22, /* 73 62 */ 4.107283e-23, /* 73 63 */ 2.375189e-24, /* 73 64 */ 1.229450e-25, /* 73 65 */ 5.640645e-27, /* 73 66 */ 2.265971e-28, /* 73 67 */ 7.847718e-30, /* 73 68 */ 2.295796e-31, /* 73 69 */ 5.516701e-33, /* 73 70 */ 1.045540e-34, /* 73 71 */ 1.465456e-36, /* 73 72 */ 1.350538e-38, /* 73 73 */ 6.138808e-41, /* 74 0 */ 1.000000e+00, /* 74 1 */ 1.000000e+00, /* 74 2 */ 1.000000e+00, /* 74 3 */ 1.000000e+00, /* 74 4 */ 1.000000e+00, /* 74 5 */ 1.000000e+00, /* 74 6 */ 1.000000e+00, /* 74 7 */ 1.000000e+00, /* 74 8 */ 1.000000e+00, /* 74 9 */ 1.000000e+00, /* 74 10 */ 1.000000e+00, /* 74 11 */ 1.000000e+00, /* 74 12 */ 1.000000e+00, /* 74 13 */ 1.000000e+00, /* 74 14 */ 1.000000e+00, /* 74 15 */ 1.000000e+00, /* 74 16 */ 1.000000e+00, /* 74 17 */ 1.000000e+00, /* 74 18 */ 1.000000e+00, /* 74 19 */ 1.000000e+00, /* 74 20 */ 1.000000e+00, /* 74 21 */ 1.000000e+00, /* 74 22 */ 1.000000e+00, /* 74 23 */ 1.000000e+00, /* 74 24 */ 1.000000e+00, /* 74 25 */ 1.000000e+00, /* 74 26 */ 1.000000e+00, /* 74 27 */ 9.999073e-01, /* 74 28 */ 9.963455e-01, /* 74 29 */ 9.545073e-01, /* 74 30 */ 8.003109e-01, /* 74 31 */ 5.471964e-01, /* 74 32 */ 3.100909e-01, /* 74 33 */ 1.521491e-01, /* 74 34 */ 6.699455e-02, /* 74 35 */ 2.708909e-02, /* 74 36 */ 1.015273e-02, /* 74 37 */ 3.541818e-03, /* 74 38 */ 1.196364e-03, /* 74 39 */ 3.690909e-04, /* 74 40 */ 1.345455e-04, /* 74 41 */ 4.181818e-05, /* 74 42 */ 3.457071e-05, /* 74 43 */ 8.433222e-06, /* 74 44 */ 1.949504e-06, /* 74 45 */ 4.268128e-07, /* 74 46 */ 8.843700e-08, /* 74 47 */ 1.732904e-08, /* 74 48 */ 3.208309e-09, /* 74 49 */ 5.606722e-10, /* 74 50 */ 9.238271e-11, /* 74 51 */ 1.433445e-11, /* 74 52 */ 2.091587e-12, /* 74 53 */ 2.865489e-13, /* 74 54 */ 3.679532e-14, /* 74 55 */ 4.419851e-15, /* 74 56 */ 4.955516e-16, /* 74 57 */ 5.173205e-17, /* 74 58 */ 5.014198e-18, /* 74 59 */ 4.498100e-19, /* 74 60 */ 3.720998e-20, /* 74 61 */ 2.826643e-21, /* 74 62 */ 1.962240e-22, /* 74 63 */ 1.237747e-23, /* 74 64 */ 7.046719e-25, /* 74 65 */ 3.591817e-26, /* 74 66 */ 1.623103e-27, /* 74 67 */ 6.423662e-29, /* 74 68 */ 2.192183e-30, /* 74 69 */ 6.320670e-32, /* 74 70 */ 1.497251e-33, /* 74 71 */ 2.797871e-35, /* 74 72 */ 3.867374e-37, /* 74 73 */ 3.515508e-39, /* 74 74 */ 1.576461e-41, /* 75 0 */ 1.000000e+00, /* 75 1 */ 1.000000e+00, /* 75 2 */ 1.000000e+00, /* 75 3 */ 1.000000e+00, /* 75 4 */ 1.000000e+00, /* 75 5 */ 1.000000e+00, /* 75 6 */ 1.000000e+00, /* 75 7 */ 1.000000e+00, /* 75 8 */ 1.000000e+00, /* 75 9 */ 1.000000e+00, /* 75 10 */ 1.000000e+00, /* 75 11 */ 1.000000e+00, /* 75 12 */ 1.000000e+00, /* 75 13 */ 1.000000e+00, /* 75 14 */ 1.000000e+00, /* 75 15 */ 1.000000e+00, /* 75 16 */ 1.000000e+00, /* 75 17 */ 1.000000e+00, /* 75 18 */ 1.000000e+00, /* 75 19 */ 1.000000e+00, /* 75 20 */ 1.000000e+00, /* 75 21 */ 1.000000e+00, /* 75 22 */ 1.000000e+00, /* 75 23 */ 1.000000e+00, /* 75 24 */ 1.000000e+00, /* 75 25 */ 1.000000e+00, /* 75 26 */ 1.000000e+00, /* 75 27 */ 9.999764e-01, /* 75 28 */ 9.987818e-01, /* 75 29 */ 9.776255e-01, /* 75 30 */ 8.685945e-01, /* 75 31 */ 6.387436e-01, /* 75 32 */ 3.855745e-01, /* 75 33 */ 1.986418e-01, /* 75 34 */ 9.116727e-02, /* 75 35 */ 3.802909e-02, /* 75 36 */ 1.482545e-02, /* 75 37 */ 5.290909e-03, /* 75 38 */ 1.870909e-03, /* 75 39 */ 5.854545e-04, /* 75 40 */ 1.963636e-04, /* 75 41 */ 5.454545e-05, /* 75 42 */ 1.818182e-05, /* 75 43 */ 1.536939e-05, /* 75 44 */ 3.666280e-06, /* 75 45 */ 8.291621e-07, /* 75 46 */ 1.776759e-07, /* 75 47 */ 3.604843e-08, /* 75 48 */ 6.919383e-09, /* 75 49 */ 1.255401e-09, /* 75 50 */ 2.150778e-10, /* 75 51 */ 3.475510e-11, /* 75 52 */ 5.290613e-12, /* 75 53 */ 7.576144e-13, /* 75 54 */ 1.018976e-13, /* 75 55 */ 1.284964e-14, /* 75 56 */ 1.516266e-15, /* 75 57 */ 1.670542e-16, /* 75 58 */ 1.714179e-17, /* 75 59 */ 1.633614e-18, /* 75 60 */ 1.441279e-19, /* 75 61 */ 1.172911e-20, /* 75 62 */ 8.767493e-22, /* 75 63 */ 5.990517e-23, /* 75 64 */ 3.720124e-24, /* 75 65 */ 2.085589e-25, /* 75 66 */ 1.047060e-26, /* 75 67 */ 4.661394e-28, /* 75 68 */ 1.817853e-29, /* 75 69 */ 6.114352e-31, /* 75 70 */ 1.737895e-32, /* 75 71 */ 4.059084e-34, /* 75 72 */ 7.480285e-36, /* 75 73 */ 1.019872e-37, /* 75 74 */ 9.146107e-40, /* 75 75 */ 4.046950e-42, /* 76 0 */ 1.000000e+00, /* 76 1 */ 1.000000e+00, /* 76 2 */ 1.000000e+00, /* 76 3 */ 1.000000e+00, /* 76 4 */ 1.000000e+00, /* 76 5 */ 1.000000e+00, /* 76 6 */ 1.000000e+00, /* 76 7 */ 1.000000e+00, /* 76 8 */ 1.000000e+00, /* 76 9 */ 1.000000e+00, /* 76 10 */ 1.000000e+00, /* 76 11 */ 1.000000e+00, /* 76 12 */ 1.000000e+00, /* 76 13 */ 1.000000e+00, /* 76 14 */ 1.000000e+00, /* 76 15 */ 1.000000e+00, /* 76 16 */ 1.000000e+00, /* 76 17 */ 1.000000e+00, /* 76 18 */ 1.000000e+00, /* 76 19 */ 1.000000e+00, /* 76 20 */ 1.000000e+00, /* 76 21 */ 1.000000e+00, /* 76 22 */ 1.000000e+00, /* 76 23 */ 1.000000e+00, /* 76 24 */ 1.000000e+00, /* 76 25 */ 1.000000e+00, /* 76 26 */ 1.000000e+00, /* 76 27 */ 9.999945e-01, /* 76 28 */ 9.996673e-01, /* 76 29 */ 9.903782e-01, /* 76 30 */ 9.195927e-01, /* 76 31 */ 7.270855e-01, /* 76 32 */ 4.693382e-01, /* 76 33 */ 2.551018e-01, /* 76 34 */ 1.216400e-01, /* 76 35 */ 5.298545e-02, /* 76 36 */ 2.116545e-02, /* 76 37 */ 7.898182e-03, /* 76 38 */ 2.785455e-03, /* 76 39 */ 9.236364e-04, /* 76 40 */ 3.054545e-04, /* 76 41 */ 1.000000e-04, /* 76 42 */ 3.454545e-05, /* 76 43 */ 2.751660e-05, /* 76 44 */ 6.766674e-06, /* 76 45 */ 1.579193e-06, /* 76 46 */ 3.495682e-07, /* 76 47 */ 7.334807e-08, /* 76 48 */ 1.457783e-08, /* 76 49 */ 2.742159e-09, /* 76 50 */ 4.877450e-10, /* 76 51 */ 8.195054e-11, /* 76 52 */ 1.299200e-11, /* 76 53 */ 1.940951e-12, /* 76 54 */ 2.728683e-13, /* 76 55 */ 3.604170e-14, /* 76 56 */ 4.464826e-15, /* 76 57 */ 5.177169e-16, /* 76 58 */ 5.606671e-17, /* 76 59 */ 5.656630e-18, /* 76 60 */ 5.301809e-19, /* 76 61 */ 4.601626e-20, /* 76 62 */ 3.684930e-21, /* 76 63 */ 2.711123e-22, /* 76 64 */ 1.823700e-23, /* 76 65 */ 1.115229e-24, /* 76 66 */ 6.158181e-26, /* 76 67 */ 3.045854e-27, /* 76 68 */ 1.336168e-28, /* 76 69 */ 5.135738e-30, /* 76 70 */ 1.702873e-31, /* 76 71 */ 4.772319e-33, /* 76 72 */ 1.099239e-34, /* 76 73 */ 1.998124e-36, /* 76 74 */ 2.687631e-38, /* 76 75 */ 2.378250e-40, /* 76 76 */ 1.038537e-42, /* 77 0 */ 1.000000e+00, /* 77 1 */ 1.000000e+00, /* 77 2 */ 1.000000e+00, /* 77 3 */ 1.000000e+00, /* 77 4 */ 1.000000e+00, /* 77 5 */ 1.000000e+00, /* 77 6 */ 1.000000e+00, /* 77 7 */ 1.000000e+00, /* 77 8 */ 1.000000e+00, /* 77 9 */ 1.000000e+00, /* 77 10 */ 1.000000e+00, /* 77 11 */ 1.000000e+00, /* 77 12 */ 1.000000e+00, /* 77 13 */ 1.000000e+00, /* 77 14 */ 1.000000e+00, /* 77 15 */ 1.000000e+00, /* 77 16 */ 1.000000e+00, /* 77 17 */ 1.000000e+00, /* 77 18 */ 1.000000e+00, /* 77 19 */ 1.000000e+00, /* 77 20 */ 1.000000e+00, /* 77 21 */ 1.000000e+00, /* 77 22 */ 1.000000e+00, /* 77 23 */ 1.000000e+00, /* 77 24 */ 1.000000e+00, /* 77 25 */ 1.000000e+00, /* 77 26 */ 1.000000e+00, /* 77 27 */ 1.000000e+00, /* 77 28 */ 9.999236e-01, /* 77 29 */ 9.962600e-01, /* 77 30 */ 9.555727e-01, /* 77 31 */ 8.066455e-01, /* 77 32 */ 5.586891e-01, /* 77 33 */ 3.216600e-01, /* 77 34 */ 1.601673e-01, /* 77 35 */ 7.201636e-02, /* 77 36 */ 2.981091e-02, /* 77 37 */ 1.142364e-02, /* 77 38 */ 4.109091e-03, /* 77 39 */ 1.452727e-03, /* 77 40 */ 4.763636e-04, /* 77 41 */ 1.436364e-04, /* 77 42 */ 6.545455e-05, /* 77 43 */ 4.843240e-05, /* 77 44 */ 1.226667e-05, /* 77 45 */ 2.951251e-06, /* 77 46 */ 6.741495e-07, /* 77 47 */ 1.461259e-07, /* 77 48 */ 3.003560e-08, /* 77 49 */ 5.850119e-09, /* 77 50 */ 1.078834e-09, /* 77 51 */ 1.881937e-10, /* 77 52 */ 3.102197e-11, /* 77 53 */ 4.826681e-12, /* 77 54 */ 7.079245e-13, /* 77 55 */ 9.773839e-14, /* 77 56 */ 1.268214e-14, /* 77 57 */ 1.543826e-15, /* 77 58 */ 1.759622e-16, /* 77 59 */ 1.873649e-17, /* 77 60 */ 1.859158e-18, /* 77 61 */ 1.714248e-19, /* 77 62 */ 1.464076e-20, /* 77 63 */ 1.153966e-21, /* 77 64 */ 8.358531e-23, /* 77 65 */ 5.536729e-24, /* 77 66 */ 3.334898e-25, /* 77 67 */ 1.814204e-26, /* 77 68 */ 8.842025e-28, /* 77 69 */ 3.822997e-29, /* 77 70 */ 1.448554e-30, /* 77 71 */ 4.735759e-32, /* 77 72 */ 1.308868e-33, /* 77 73 */ 2.973718e-35, /* 77 74 */ 5.332743e-37, /* 77 75 */ 7.077763e-39, /* 77 76 */ 6.180987e-41, /* 77 77 */ 2.664219e-43, /* 78 0 */ 1.000000e+00, /* 78 1 */ 1.000000e+00, /* 78 2 */ 1.000000e+00, /* 78 3 */ 1.000000e+00, /* 78 4 */ 1.000000e+00, /* 78 5 */ 1.000000e+00, /* 78 6 */ 1.000000e+00, /* 78 7 */ 1.000000e+00, /* 78 8 */ 1.000000e+00, /* 78 9 */ 1.000000e+00, /* 78 10 */ 1.000000e+00, /* 78 11 */ 1.000000e+00, /* 78 12 */ 1.000000e+00, /* 78 13 */ 1.000000e+00, /* 78 14 */ 1.000000e+00, /* 78 15 */ 1.000000e+00, /* 78 16 */ 1.000000e+00, /* 78 17 */ 1.000000e+00, /* 78 18 */ 1.000000e+00, /* 78 19 */ 1.000000e+00, /* 78 20 */ 1.000000e+00, /* 78 21 */ 1.000000e+00, /* 78 22 */ 1.000000e+00, /* 78 23 */ 1.000000e+00, /* 78 24 */ 1.000000e+00, /* 78 25 */ 1.000000e+00, /* 78 26 */ 1.000000e+00, /* 78 27 */ 1.000000e+00, /* 78 28 */ 9.999800e-01, /* 78 29 */ 9.987127e-01, /* 78 30 */ 9.779600e-01, /* 78 31 */ 8.725400e-01, /* 78 32 */ 6.480145e-01, /* 78 33 */ 3.979891e-01, /* 78 34 */ 2.073600e-01, /* 78 35 */ 9.732182e-02, /* 78 36 */ 4.155818e-02, /* 78 37 */ 1.637636e-02, /* 78 38 */ 5.943636e-03, /* 78 39 */ 2.210909e-03, /* 78 40 */ 7.527273e-04, /* 78 41 */ 2.290909e-04, /* 78 42 */ 8.727273e-05, /* 78 43 */ 2.727273e-05, /* 78 44 */ 2.185797e-05, /* 78 45 */ 5.416361e-06, /* 78 46 */ 1.275512e-06, /* 78 47 */ 2.853091e-07, /* 78 48 */ 6.058219e-08, /* 78 49 */ 1.220348e-08, /* 78 50 */ 2.330276e-09, /* 78 51 */ 4.214559e-10, /* 78 52 */ 7.212941e-11, /* 78 53 */ 1.166905e-11, /* 78 54 */ 1.782453e-12, /* 78 55 */ 2.567436e-13, /* 78 56 */ 3.482220e-14, /* 78 57 */ 4.440102e-15, /* 78 58 */ 5.312934e-16, /* 78 59 */ 5.954074e-17, /* 78 60 */ 6.235350e-18, /* 78 61 */ 6.086700e-19, /* 78 62 */ 5.522604e-20, /* 78 63 */ 4.642451e-21, /* 78 64 */ 3.602428e-22, /* 78 65 */ 2.569527e-23, /* 78 66 */ 1.676473e-24, /* 78 67 */ 9.948157e-26, /* 78 68 */ 5.332816e-27, /* 78 69 */ 2.561673e-28, /* 78 70 */ 1.091858e-29, /* 78 71 */ 4.079185e-31, /* 78 72 */ 1.315190e-32, /* 78 73 */ 3.585395e-34, /* 78 74 */ 8.036417e-36, /* 78 75 */ 1.422042e-37, /* 78 76 */ 1.862656e-39, /* 78 77 */ 1.605620e-41, /* 78 78 */ 6.832425e-44, /* 79 0 */ 1.000000e+00, /* 79 1 */ 1.000000e+00, /* 79 2 */ 1.000000e+00, /* 79 3 */ 1.000000e+00, /* 79 4 */ 1.000000e+00, /* 79 5 */ 1.000000e+00, /* 79 6 */ 1.000000e+00, /* 79 7 */ 1.000000e+00, /* 79 8 */ 1.000000e+00, /* 79 9 */ 1.000000e+00, /* 79 10 */ 1.000000e+00, /* 79 11 */ 1.000000e+00, /* 79 12 */ 1.000000e+00, /* 79 13 */ 1.000000e+00, /* 79 14 */ 1.000000e+00, /* 79 15 */ 1.000000e+00, /* 79 16 */ 1.000000e+00, /* 79 17 */ 1.000000e+00, /* 79 18 */ 1.000000e+00, /* 79 19 */ 1.000000e+00, /* 79 20 */ 1.000000e+00, /* 79 21 */ 1.000000e+00, /* 79 22 */ 1.000000e+00, /* 79 23 */ 1.000000e+00, /* 79 24 */ 1.000000e+00, /* 79 25 */ 1.000000e+00, /* 79 26 */ 1.000000e+00, /* 79 27 */ 1.000000e+00, /* 79 28 */ 9.999945e-01, /* 79 29 */ 9.996473e-01, /* 79 30 */ 9.902782e-01, /* 79 31 */ 9.217127e-01, /* 79 32 */ 7.343291e-01, /* 79 33 */ 4.810400e-01, /* 79 34 */ 2.647127e-01, /* 79 35 */ 1.285164e-01, /* 79 36 */ 5.689636e-02, /* 79 37 */ 2.329636e-02, /* 79 38 */ 8.629091e-03, /* 79 39 */ 3.203636e-03, /* 79 40 */ 1.160000e-03, /* 79 41 */ 3.763636e-04, /* 79 42 */ 1.272727e-04, /* 79 43 */ 4.909091e-05, /* 79 44 */ 3.831186e-05, /* 79 45 */ 9.769472e-06, /* 79 46 */ 2.369594e-06, /* 79 47 */ 5.464353e-07, /* 79 48 */ 1.197387e-07, /* 79 49 */ 2.491720e-08, /* 79 50 */ 4.920829e-09, /* 79 51 */ 9.215558e-10, /* 79 52 */ 1.635236e-10, /* 79 53 */ 2.746651e-11, /* 79 54 */ 4.362484e-12, /* 79 55 */ 6.544295e-13, /* 79 56 */ 9.260317e-14, /* 79 57 */ 1.234225e-14, /* 79 58 */ 1.546927e-15, /* 79 59 */ 1.820005e-16, /* 79 60 */ 2.006006e-17, /* 79 61 */ 2.066684e-18, /* 79 62 */ 1.985190e-19, /* 79 63 */ 1.772880e-20, /* 79 64 */ 1.467247e-21, /* 79 65 */ 1.121176e-22, /* 79 66 */ 7.876863e-24, /* 79 67 */ 5.063081e-25, /* 79 68 */ 2.960552e-26, /* 79 69 */ 1.564190e-27, /* 79 70 */ 7.407096e-29, /* 79 71 */ 3.112920e-30, /* 79 72 */ 1.146929e-31, /* 79 73 */ 3.647497e-33, /* 79 74 */ 9.809933e-35, /* 79 75 */ 2.169660e-36, /* 79 76 */ 3.788936e-38, /* 79 77 */ 4.898764e-40, /* 79 78 */ 4.168863e-42, /* 79 79 */ 1.751623e-44, /* 80 0 */ 1.000000e+00, /* 80 1 */ 1.000000e+00, /* 80 2 */ 1.000000e+00, /* 80 3 */ 1.000000e+00, /* 80 4 */ 1.000000e+00, /* 80 5 */ 1.000000e+00, /* 80 6 */ 1.000000e+00, /* 80 7 */ 1.000000e+00, /* 80 8 */ 1.000000e+00, /* 80 9 */ 1.000000e+00, /* 80 10 */ 1.000000e+00, /* 80 11 */ 1.000000e+00, /* 80 12 */ 1.000000e+00, /* 80 13 */ 1.000000e+00, /* 80 14 */ 1.000000e+00, /* 80 15 */ 1.000000e+00, /* 80 16 */ 1.000000e+00, /* 80 17 */ 1.000000e+00, /* 80 18 */ 1.000000e+00, /* 80 19 */ 1.000000e+00, /* 80 20 */ 1.000000e+00, /* 80 21 */ 1.000000e+00, /* 80 22 */ 1.000000e+00, /* 80 23 */ 1.000000e+00, /* 80 24 */ 1.000000e+00, /* 80 25 */ 1.000000e+00, /* 80 26 */ 1.000000e+00, /* 80 27 */ 1.000000e+00, /* 80 28 */ 1.000000e+00, /* 80 29 */ 9.999109e-01, /* 80 30 */ 9.962982e-01, /* 80 31 */ 9.565618e-01, /* 80 32 */ 8.112491e-01, /* 80 33 */ 5.686655e-01, /* 80 34 */ 3.323945e-01, /* 80 35 */ 1.681582e-01, /* 80 36 */ 7.708909e-02, /* 80 37 */ 3.264364e-02, /* 80 38 */ 1.276000e-02, /* 80 39 */ 4.596364e-03, /* 80 40 */ 1.734545e-03, /* 80 41 */ 5.927273e-04, /* 80 42 */ 1.800000e-04, /* 80 43 */ 7.818182e-05, /* 80 44 */ 2.000000e-05, /* 80 45 */ 1.733034e-05, /* 80 46 */ 4.325712e-06, /* 80 47 */ 1.027437e-06, /* 80 48 */ 2.321085e-07, /* 80 49 */ 4.984573e-08, /* 80 50 */ 1.016947e-08, /* 80 51 */ 1.969709e-09, /* 80 52 */ 3.619126e-10, /* 80 53 */ 6.302740e-11, /* 80 54 */ 1.039354e-11, /* 80 55 */ 1.621226e-12, /* 80 56 */ 2.389227e-13, /* 80 57 */ 3.322273e-14, /* 80 58 */ 4.352566e-15, /* 80 59 */ 5.363947e-16, /* 80 60 */ 6.206826e-17, /* 80 61 */ 6.730181e-18, /* 80 62 */ 6.823033e-19, /* 80 63 */ 6.450933e-20, /* 80 64 */ 5.671815e-21, /* 80 65 */ 4.622428e-22, /* 80 66 */ 3.479077e-23, /* 80 67 */ 2.408038e-24, /* 80 68 */ 1.525239e-25, /* 80 69 */ 8.790225e-27, /* 80 70 */ 4.578355e-28, /* 80 71 */ 2.137700e-29, /* 80 72 */ 8.859910e-31, /* 80 73 */ 3.219899e-32, /* 80 74 */ 1.010239e-33, /* 80 75 */ 2.680997e-35, /* 80 76 */ 5.851920e-37, /* 80 77 */ 1.008728e-38, /* 80 78 */ 1.287553e-40, /* 80 79 */ 1.081902e-42, /* 80 80 */ 4.489218e-45, /* 81 0 */ 1.000000e+00, /* 81 1 */ 1.000000e+00, /* 81 2 */ 1.000000e+00, /* 81 3 */ 1.000000e+00, /* 81 4 */ 1.000000e+00, /* 81 5 */ 1.000000e+00, /* 81 6 */ 1.000000e+00, /* 81 7 */ 1.000000e+00, /* 81 8 */ 1.000000e+00, /* 81 9 */ 1.000000e+00, /* 81 10 */ 1.000000e+00, /* 81 11 */ 1.000000e+00, /* 81 12 */ 1.000000e+00, /* 81 13 */ 1.000000e+00, /* 81 14 */ 1.000000e+00, /* 81 15 */ 1.000000e+00, /* 81 16 */ 1.000000e+00, /* 81 17 */ 1.000000e+00, /* 81 18 */ 1.000000e+00, /* 81 19 */ 1.000000e+00, /* 81 20 */ 1.000000e+00, /* 81 21 */ 1.000000e+00, /* 81 22 */ 1.000000e+00, /* 81 23 */ 1.000000e+00, /* 81 24 */ 1.000000e+00, /* 81 25 */ 1.000000e+00, /* 81 26 */ 1.000000e+00, /* 81 27 */ 1.000000e+00, /* 81 28 */ 1.000000e+00, /* 81 29 */ 9.999709e-01, /* 81 30 */ 9.987473e-01, /* 81 31 */ 9.785800e-01, /* 81 32 */ 8.746836e-01, /* 81 33 */ 6.568109e-01, /* 81 34 */ 4.079582e-01, /* 81 35 */ 2.168473e-01, /* 81 36 */ 1.029455e-01, /* 81 37 */ 4.495818e-02, /* 81 38 */ 1.837091e-02, /* 81 39 */ 6.714545e-03, /* 81 40 */ 2.478182e-03, /* 81 41 */ 9.290909e-04, /* 81 42 */ 2.872727e-04, /* 81 43 */ 1.018182e-04, /* 81 44 */ 2.909091e-05, /* 81 45 */ 1.272727e-05, /* 81 46 */ 7.765106e-06, /* 81 47 */ 1.898017e-06, /* 81 48 */ 4.416469e-07, /* 81 49 */ 9.778181e-08, /* 81 50 */ 2.058761e-08, /* 81 51 */ 4.119512e-09, /* 81 52 */ 7.828388e-10, /* 81 53 */ 1.411709e-10, /* 81 54 */ 2.413712e-11, /* 81 55 */ 3.909066e-12, /* 81 56 */ 5.990197e-13, /* 81 57 */ 8.675069e-14, /* 81 58 */ 1.185755e-14, /* 81 59 */ 1.527466e-15, /* 81 60 */ 1.851379e-16, /* 81 61 */ 2.107561e-17, /* 81 62 */ 2.248787e-18, /* 81 63 */ 2.243976e-19, /* 81 64 */ 2.088754e-20, /* 81 65 */ 1.808476e-21, /* 81 66 */ 1.451730e-22, /* 81 67 */ 1.076467e-23, /* 81 68 */ 7.342005e-25, /* 81 69 */ 4.583476e-26, /* 81 70 */ 2.604059e-27, /* 81 71 */ 1.337335e-28, /* 81 72 */ 6.158023e-30, /* 81 73 */ 2.517498e-31, /* 81 74 */ 9.026236e-33, /* 81 75 */ 2.794413e-34, /* 81 76 */ 7.318804e-36, /* 81 77 */ 1.576860e-37, /* 81 78 */ 2.683437e-39, /* 81 79 */ 3.382009e-41, /* 81 80 */ 2.806456e-43, /* 81 81 */ 1.150187e-45, /* 82 0 */ 1.000000e+00, /* 82 1 */ 1.000000e+00, /* 82 2 */ 1.000000e+00, /* 82 3 */ 1.000000e+00, /* 82 4 */ 1.000000e+00, /* 82 5 */ 1.000000e+00, /* 82 6 */ 1.000000e+00, /* 82 7 */ 1.000000e+00, /* 82 8 */ 1.000000e+00, /* 82 9 */ 1.000000e+00, /* 82 10 */ 1.000000e+00, /* 82 11 */ 1.000000e+00, /* 82 12 */ 1.000000e+00, /* 82 13 */ 1.000000e+00, /* 82 14 */ 1.000000e+00, /* 82 15 */ 1.000000e+00, /* 82 16 */ 1.000000e+00, /* 82 17 */ 1.000000e+00, /* 82 18 */ 1.000000e+00, /* 82 19 */ 1.000000e+00, /* 82 20 */ 1.000000e+00, /* 82 21 */ 1.000000e+00, /* 82 22 */ 1.000000e+00, /* 82 23 */ 1.000000e+00, /* 82 24 */ 1.000000e+00, /* 82 25 */ 1.000000e+00, /* 82 26 */ 1.000000e+00, /* 82 27 */ 1.000000e+00, /* 82 28 */ 1.000000e+00, /* 82 29 */ 1.000000e+00, /* 82 30 */ 9.996455e-01, /* 82 31 */ 9.905182e-01, /* 82 32 */ 9.231127e-01, /* 82 33 */ 7.410545e-01, /* 82 34 */ 4.910727e-01, /* 82 35 */ 2.746691e-01, /* 82 36 */ 1.353927e-01, /* 82 37 */ 6.124000e-02, /* 82 38 */ 2.562727e-02, /* 82 39 */ 9.823636e-03, /* 82 40 */ 3.667273e-03, /* 82 41 */ 1.350909e-03, /* 82 42 */ 4.418182e-04, /* 82 43 */ 1.581818e-04, /* 82 44 */ 6.000000e-05, /* 82 45 */ 5.201647e-05, /* 82 46 */ 1.371625e-05, /* 82 47 */ 3.447358e-06, /* 82 48 */ 8.255113e-07, /* 82 49 */ 1.882571e-07, /* 82 50 */ 4.086492e-08, /* 82 51 */ 8.438652e-09, /* 82 52 */ 1.656687e-09, /* 82 53 */ 3.089885e-10, /* 82 54 */ 5.470584e-11, /* 82 55 */ 9.186099e-12, /* 82 56 */ 1.461537e-12, /* 82 57 */ 2.200894e-13, /* 82 58 */ 3.133126e-14, /* 82 59 */ 4.210842e-15, /* 82 60 */ 5.334977e-16, /* 82 61 */ 6.361483e-17, /* 82 62 */ 7.126172e-18, /* 82 63 */ 7.484204e-19, /* 82 64 */ 7.352608e-20, /* 82 65 */ 6.739665e-21, /* 82 66 */ 5.747651e-22, /* 82 67 */ 4.545547e-23, /* 82 68 */ 3.321369e-24, /* 82 69 */ 2.232739e-25, /* 82 70 */ 1.374084e-26, /* 82 71 */ 7.697514e-28, /* 82 72 */ 3.898565e-29, /* 82 73 */ 1.770729e-30, /* 82 74 */ 7.141767e-32, /* 82 75 */ 2.526657e-33, /* 82 76 */ 7.719843e-35, /* 82 77 */ 1.995767e-36, /* 82 78 */ 4.245083e-38, /* 82 79 */ 7.133088e-40, /* 82 80 */ 8.878151e-42, /* 82 81 */ 7.276690e-44, /* 82 82 */ 2.946028e-46, /* 83 0 */ 1.000000e+00, /* 83 1 */ 1.000000e+00, /* 83 2 */ 1.000000e+00, /* 83 3 */ 1.000000e+00, /* 83 4 */ 1.000000e+00, /* 83 5 */ 1.000000e+00, /* 83 6 */ 1.000000e+00, /* 83 7 */ 1.000000e+00, /* 83 8 */ 1.000000e+00, /* 83 9 */ 1.000000e+00, /* 83 10 */ 1.000000e+00, /* 83 11 */ 1.000000e+00, /* 83 12 */ 1.000000e+00, /* 83 13 */ 1.000000e+00, /* 83 14 */ 1.000000e+00, /* 83 15 */ 1.000000e+00, /* 83 16 */ 1.000000e+00, /* 83 17 */ 1.000000e+00, /* 83 18 */ 1.000000e+00, /* 83 19 */ 1.000000e+00, /* 83 20 */ 1.000000e+00, /* 83 21 */ 1.000000e+00, /* 83 22 */ 1.000000e+00, /* 83 23 */ 1.000000e+00, /* 83 24 */ 1.000000e+00, /* 83 25 */ 1.000000e+00, /* 83 26 */ 1.000000e+00, /* 83 27 */ 1.000000e+00, /* 83 28 */ 1.000000e+00, /* 83 29 */ 1.000000e+00, /* 83 30 */ 9.999145e-01, /* 83 31 */ 9.963582e-01, /* 83 32 */ 9.573200e-01, /* 83 33 */ 8.156473e-01, /* 83 34 */ 5.770345e-01, /* 83 35 */ 3.419727e-01, /* 83 36 */ 1.758200e-01, /* 83 37 */ 8.197091e-02, /* 83 38 */ 3.548182e-02, /* 83 39 */ 1.419818e-02, /* 83 40 */ 5.261818e-03, /* 83 41 */ 1.983636e-03, /* 83 42 */ 6.890909e-04, /* 83 43 */ 2.363636e-04, /* 83 44 */ 9.454545e-05, /* 83 45 */ 2.909091e-05, /* 83 46 */ 2.385593e-05, /* 83 47 */ 6.160385e-06, /* 83 48 */ 1.516874e-06, /* 83 49 */ 3.559963e-07, /* 83 50 */ 7.959684e-08, /* 83 51 */ 1.694630e-08, /* 83 52 */ 3.433440e-09, /* 83 53 */ 6.615710e-10, /* 83 54 */ 1.211437e-10, /* 83 55 */ 2.106459e-11, /* 83 56 */ 3.474921e-12, /* 83 57 */ 5.433102e-13, /* 83 58 */ 8.042425e-14, /* 83 59 */ 1.125738e-14, /* 83 60 */ 1.488053e-15, /* 83 61 */ 1.854753e-16, /* 83 62 */ 2.176343e-17, /* 83 63 */ 2.399653e-18, /* 83 64 */ 2.481222e-19, /* 83 65 */ 2.400440e-20, /* 83 66 */ 2.167285e-21, /* 83 67 */ 1.820926e-22, /* 83 68 */ 1.419076e-23, /* 83 69 */ 1.021986e-24, /* 83 70 */ 6.772705e-26, /* 83 71 */ 4.109794e-27, /* 83 72 */ 2.270509e-28, /* 83 73 */ 1.134292e-29, /* 83 74 */ 5.082753e-31, /* 83 75 */ 2.022816e-32, /* 83 76 */ 7.062790e-34, /* 83 77 */ 2.130057e-35, /* 83 78 */ 5.436467e-37, /* 83 79 */ 1.141793e-38, /* 83 80 */ 1.894702e-40, /* 83 81 */ 2.329241e-42, /* 83 82 */ 1.885903e-44, /* 83 83 */ 7.543611e-47, /* 84 0 */ 1.000000e+00, /* 84 1 */ 1.000000e+00, /* 84 2 */ 1.000000e+00, /* 84 3 */ 1.000000e+00, /* 84 4 */ 1.000000e+00, /* 84 5 */ 1.000000e+00, /* 84 6 */ 1.000000e+00, /* 84 7 */ 1.000000e+00, /* 84 8 */ 1.000000e+00, /* 84 9 */ 1.000000e+00, /* 84 10 */ 1.000000e+00, /* 84 11 */ 1.000000e+00, /* 84 12 */ 1.000000e+00, /* 84 13 */ 1.000000e+00, /* 84 14 */ 1.000000e+00, /* 84 15 */ 1.000000e+00, /* 84 16 */ 1.000000e+00, /* 84 17 */ 1.000000e+00, /* 84 18 */ 1.000000e+00, /* 84 19 */ 1.000000e+00, /* 84 20 */ 1.000000e+00, /* 84 21 */ 1.000000e+00, /* 84 22 */ 1.000000e+00, /* 84 23 */ 1.000000e+00, /* 84 24 */ 1.000000e+00, /* 84 25 */ 1.000000e+00, /* 84 26 */ 1.000000e+00, /* 84 27 */ 1.000000e+00, /* 84 28 */ 1.000000e+00, /* 84 29 */ 1.000000e+00, /* 84 30 */ 9.999727e-01, /* 84 31 */ 9.987236e-01, /* 84 32 */ 9.785109e-01, /* 84 33 */ 8.772145e-01, /* 84 34 */ 6.635636e-01, /* 84 35 */ 4.174327e-01, /* 84 36 */ 2.249873e-01, /* 84 37 */ 1.084073e-01, /* 84 38 */ 4.819091e-02, /* 84 39 */ 1.998182e-02, /* 84 40 */ 7.518182e-03, /* 84 41 */ 2.838182e-03, /* 84 42 */ 1.054545e-03, /* 84 43 */ 3.472727e-04, /* 84 44 */ 1.327273e-04, /* 84 45 */ 5.090909e-05, /* 84 46 */ 4.087779e-05, /* 84 47 */ 1.083778e-05, /* 84 48 */ 2.741887e-06, /* 84 49 */ 6.616934e-07, /* 84 50 */ 1.522582e-07, /* 84 51 */ 3.338996e-08, /* 84 52 */ 6.974803e-09, /* 84 53 */ 1.386981e-09, /* 84 54 */ 2.623881e-10, /* 84 55 */ 4.718815e-11, /* 84 56 */ 8.060890e-12, /* 84 57 */ 1.306780e-12, /* 84 58 */ 2.008437e-13, /* 84 59 */ 2.923289e-14, /* 84 60 */ 4.024523e-15, /* 84 61 */ 5.233617e-16, /* 84 62 */ 6.419295e-17, /* 84 63 */ 7.414018e-18, /* 84 64 */ 8.048306e-19, /* 84 65 */ 8.195076e-20, /* 84 66 */ 7.809230e-21, /* 84 67 */ 6.946390e-22, /* 84 68 */ 5.751147e-23, /* 84 69 */ 4.417509e-24, /* 84 70 */ 3.136278e-25, /* 84 71 */ 2.049347e-26, /* 84 72 */ 1.226424e-27, /* 84 73 */ 6.683321e-29, /* 84 74 */ 3.293987e-30, /* 84 75 */ 1.456468e-31, /* 84 76 */ 5.720560e-33, /* 84 77 */ 1.971569e-34, /* 84 78 */ 5.870187e-36, /* 84 79 */ 1.479355e-37, /* 84 80 */ 3.068356e-39, /* 84 81 */ 5.029082e-41, /* 84 82 */ 6.107403e-43, /* 84 83 */ 4.885613e-45, /* 84 84 */ 1.931073e-47, /* 85 0 */ 1.000000e+00, /* 85 1 */ 1.000000e+00, /* 85 2 */ 1.000000e+00, /* 85 3 */ 1.000000e+00, /* 85 4 */ 1.000000e+00, /* 85 5 */ 1.000000e+00, /* 85 6 */ 1.000000e+00, /* 85 7 */ 1.000000e+00, /* 85 8 */ 1.000000e+00, /* 85 9 */ 1.000000e+00, /* 85 10 */ 1.000000e+00, /* 85 11 */ 1.000000e+00, /* 85 12 */ 1.000000e+00, /* 85 13 */ 1.000000e+00, /* 85 14 */ 1.000000e+00, /* 85 15 */ 1.000000e+00, /* 85 16 */ 1.000000e+00, /* 85 17 */ 1.000000e+00, /* 85 18 */ 1.000000e+00, /* 85 19 */ 1.000000e+00, /* 85 20 */ 1.000000e+00, /* 85 21 */ 1.000000e+00, /* 85 22 */ 1.000000e+00, /* 85 23 */ 1.000000e+00, /* 85 24 */ 1.000000e+00, /* 85 25 */ 1.000000e+00, /* 85 26 */ 1.000000e+00, /* 85 27 */ 1.000000e+00, /* 85 28 */ 1.000000e+00, /* 85 29 */ 1.000000e+00, /* 85 30 */ 9.999982e-01, /* 85 31 */ 9.996273e-01, /* 85 32 */ 9.903636e-01, /* 85 33 */ 9.249673e-01, /* 85 34 */ 7.449036e-01, /* 85 35 */ 4.995436e-01, /* 85 36 */ 2.830582e-01, /* 85 37 */ 1.419964e-01, /* 85 38 */ 6.502545e-02, /* 85 39 */ 2.749273e-02, /* 85 40 */ 1.094182e-02, /* 85 41 */ 4.189091e-03, /* 85 42 */ 1.532727e-03, /* 85 43 */ 5.381818e-04, /* 85 44 */ 2.000000e-04, /* 85 45 */ 7.454545e-05, /* 85 46 */ 2.363636e-05, /* 85 47 */ 1.878203e-05, /* 85 48 */ 4.878657e-06, /* 85 49 */ 1.209711e-06, /* 85 50 */ 2.862349e-07, /* 85 51 */ 6.460062e-08, /* 85 52 */ 1.389997e-08, /* 85 53 */ 2.849826e-09, /* 85 54 */ 5.564007e-10, /* 85 55 */ 1.033783e-10, /* 85 56 */ 1.826500e-11, /* 85 57 */ 3.066200e-12, /* 85 58 */ 4.886250e-13, /* 85 59 */ 7.384287e-14, /* 85 60 */ 1.057102e-14, /* 85 61 */ 1.431755e-15, /* 85 62 */ 1.832213e-16, /* 85 63 */ 2.212018e-17, /* 85 64 */ 2.515282e-18, /* 85 65 */ 2.688876e-19, /* 85 66 */ 2.696813e-20, /* 85 67 */ 2.531824e-21, /* 85 68 */ 2.219244e-22, /* 85 69 */ 1.810971e-23, /* 85 70 */ 1.371303e-24, /* 85 71 */ 9.599656e-26, /* 85 72 */ 6.186215e-27, /* 85 73 */ 3.651740e-28, /* 85 74 */ 1.963271e-29, /* 85 75 */ 9.548075e-31, /* 85 76 */ 4.166544e-32, /* 85 77 */ 1.615356e-33, /* 85 78 */ 5.496263e-35, /* 85 79 */ 1.615858e-36, /* 85 80 */ 4.021493e-38, /* 85 81 */ 8.238551e-40, /* 85 82 */ 1.333917e-41, /* 85 83 */ 1.600497e-43, /* 85 84 */ 1.265137e-45, /* 85 85 */ 4.941942e-48, /* 86 0 */ 1.000000e+00, /* 86 1 */ 1.000000e+00, /* 86 2 */ 1.000000e+00, /* 86 3 */ 1.000000e+00, /* 86 4 */ 1.000000e+00, /* 86 5 */ 1.000000e+00, /* 86 6 */ 1.000000e+00, /* 86 7 */ 1.000000e+00, /* 86 8 */ 1.000000e+00, /* 86 9 */ 1.000000e+00, /* 86 10 */ 1.000000e+00, /* 86 11 */ 1.000000e+00, /* 86 12 */ 1.000000e+00, /* 86 13 */ 1.000000e+00, /* 86 14 */ 1.000000e+00, /* 86 15 */ 1.000000e+00, /* 86 16 */ 1.000000e+00, /* 86 17 */ 1.000000e+00, /* 86 18 */ 1.000000e+00, /* 86 19 */ 1.000000e+00, /* 86 20 */ 1.000000e+00, /* 86 21 */ 1.000000e+00, /* 86 22 */ 1.000000e+00, /* 86 23 */ 1.000000e+00, /* 86 24 */ 1.000000e+00, /* 86 25 */ 1.000000e+00, /* 86 26 */ 1.000000e+00, /* 86 27 */ 1.000000e+00, /* 86 28 */ 1.000000e+00, /* 86 29 */ 1.000000e+00, /* 86 30 */ 1.000000e+00, /* 86 31 */ 9.999145e-01, /* 86 32 */ 9.961091e-01, /* 86 33 */ 9.578036e-01, /* 86 34 */ 8.183455e-01, /* 86 35 */ 5.846345e-01, /* 86 36 */ 3.503655e-01, /* 86 37 */ 1.828855e-01, /* 86 38 */ 8.655091e-02, /* 86 39 */ 3.789273e-02, /* 86 40 */ 1.547455e-02, /* 86 41 */ 5.954545e-03, /* 86 42 */ 2.240000e-03, /* 86 43 */ 7.836364e-04, /* 86 44 */ 2.745455e-04, /* 86 45 */ 1.054545e-04, /* 86 46 */ 3.454545e-05, /* 86 47 */ 3.208182e-05, /* 86 48 */ 8.549921e-06, /* 86 49 */ 2.176699e-06, /* 86 50 */ 5.291995e-07, /* 86 51 */ 1.228163e-07, /* 86 52 */ 2.719675e-08, /* 86 53 */ 5.743641e-09, /* 86 54 */ 1.156183e-09, /* 86 55 */ 2.217012e-10, /* 86 56 */ 4.046828e-11, /* 86 57 */ 7.026501e-12, /* 86 58 */ 1.159521e-12, /* 86 59 */ 1.816912e-13, /* 86 60 */ 2.700625e-14, /* 86 61 */ 3.803506e-15, /* 86 62 */ 5.069416e-16, /* 86 63 */ 6.385496e-17, /* 86 64 */ 7.589987e-18, /* 86 65 */ 8.499122e-19, /* 86 66 */ 8.949349e-20, /* 86 67 */ 8.843020e-21, /* 86 68 */ 8.180981e-22, /* 86 69 */ 7.067884e-23, /* 86 70 */ 5.685863e-24, /* 86 71 */ 4.245264e-25, /* 86 72 */ 2.930869e-26, /* 86 73 */ 1.863016e-27, /* 86 74 */ 1.084979e-28, /* 86 75 */ 5.755841e-30, /* 86 76 */ 2.762654e-31, /* 86 77 */ 1.189987e-32, /* 86 78 */ 4.554713e-34, /* 86 79 */ 1.530231e-35, /* 86 80 */ 4.442803e-37, /* 86 81 */ 1.092124e-38, /* 86 82 */ 2.210199e-40, /* 86 83 */ 3.535642e-42, /* 86 84 */ 4.191941e-44, /* 86 85 */ 3.274757e-46, /* 86 86 */ 1.264385e-48, /* 87 0 */ 1.000000e+00, /* 87 1 */ 1.000000e+00, /* 87 2 */ 1.000000e+00, /* 87 3 */ 1.000000e+00, /* 87 4 */ 1.000000e+00, /* 87 5 */ 1.000000e+00, /* 87 6 */ 1.000000e+00, /* 87 7 */ 1.000000e+00, /* 87 8 */ 1.000000e+00, /* 87 9 */ 1.000000e+00, /* 87 10 */ 1.000000e+00, /* 87 11 */ 1.000000e+00, /* 87 12 */ 1.000000e+00, /* 87 13 */ 1.000000e+00, /* 87 14 */ 1.000000e+00, /* 87 15 */ 1.000000e+00, /* 87 16 */ 1.000000e+00, /* 87 17 */ 1.000000e+00, /* 87 18 */ 1.000000e+00, /* 87 19 */ 1.000000e+00, /* 87 20 */ 1.000000e+00, /* 87 21 */ 1.000000e+00, /* 87 22 */ 1.000000e+00, /* 87 23 */ 1.000000e+00, /* 87 24 */ 1.000000e+00, /* 87 25 */ 1.000000e+00, /* 87 26 */ 1.000000e+00, /* 87 27 */ 1.000000e+00, /* 87 28 */ 1.000000e+00, /* 87 29 */ 1.000000e+00, /* 87 30 */ 1.000000e+00, /* 87 31 */ 9.999745e-01, /* 87 32 */ 9.987091e-01, /* 87 33 */ 9.785836e-01, /* 87 34 */ 8.782709e-01, /* 87 35 */ 6.693455e-01, /* 87 36 */ 4.258327e-01, /* 87 37 */ 2.328127e-01, /* 87 38 */ 1.138782e-01, /* 87 39 */ 5.116545e-02, /* 87 40 */ 2.156000e-02, /* 87 41 */ 8.500000e-03, /* 87 42 */ 3.220000e-03, /* 87 43 */ 1.178182e-03, /* 87 44 */ 4.272727e-04, /* 87 45 */ 1.490909e-04, /* 87 46 */ 5.454545e-05, /* 87 47 */ 2.000000e-05, /* 87 48 */ 1.476659e-05, /* 87 49 */ 3.857169e-06, /* 87 50 */ 9.628326e-07, /* 87 51 */ 2.296007e-07, /* 87 52 */ 5.228315e-08, /* 87 53 */ 1.136372e-08, /* 87 54 */ 2.356296e-09, /* 87 55 */ 4.658490e-10, /* 87 56 */ 8.775971e-11, /* 87 57 */ 1.574270e-11, /* 87 58 */ 2.686987e-12, /* 87 59 */ 4.360015e-13, /* 87 60 */ 6.719599e-14, /* 87 61 */ 9.826247e-15, /* 87 62 */ 1.361858e-15, /* 87 63 */ 1.786641e-16, /* 87 64 */ 2.215694e-17, /* 87 65 */ 2.593540e-18, /* 87 66 */ 2.860626e-19, /* 87 67 */ 2.967627e-20, /* 87 68 */ 2.889629e-21, /* 87 69 */ 2.634880e-22, /* 87 70 */ 2.244124e-23, /* 87 71 */ 1.780087e-24, /* 87 72 */ 1.310752e-25, /* 87 73 */ 8.926149e-27, /* 87 74 */ 5.597773e-28, /* 87 75 */ 3.216830e-29, /* 87 76 */ 1.684220e-30, /* 87 77 */ 7.979445e-32, /* 87 78 */ 3.393251e-33, /* 87 79 */ 1.282426e-34, /* 87 80 */ 4.254941e-36, /* 87 81 */ 1.220184e-37, /* 87 82 */ 2.963035e-39, /* 87 83 */ 5.924554e-41, /* 87 84 */ 9.365135e-43, /* 87 85 */ 1.097344e-44, /* 87 86 */ 8.473199e-47, /* 87 87 */ 3.234045e-49, /* 88 0 */ 1.000000e+00, /* 88 1 */ 1.000000e+00, /* 88 2 */ 1.000000e+00, /* 88 3 */ 1.000000e+00, /* 88 4 */ 1.000000e+00, /* 88 5 */ 1.000000e+00, /* 88 6 */ 1.000000e+00, /* 88 7 */ 1.000000e+00, /* 88 8 */ 1.000000e+00, /* 88 9 */ 1.000000e+00, /* 88 10 */ 1.000000e+00, /* 88 11 */ 1.000000e+00, /* 88 12 */ 1.000000e+00, /* 88 13 */ 1.000000e+00, /* 88 14 */ 1.000000e+00, /* 88 15 */ 1.000000e+00, /* 88 16 */ 1.000000e+00, /* 88 17 */ 1.000000e+00, /* 88 18 */ 1.000000e+00, /* 88 19 */ 1.000000e+00, /* 88 20 */ 1.000000e+00, /* 88 21 */ 1.000000e+00, /* 88 22 */ 1.000000e+00, /* 88 23 */ 1.000000e+00, /* 88 24 */ 1.000000e+00, /* 88 25 */ 1.000000e+00, /* 88 26 */ 1.000000e+00, /* 88 27 */ 1.000000e+00, /* 88 28 */ 1.000000e+00, /* 88 29 */ 1.000000e+00, /* 88 30 */ 1.000000e+00, /* 88 31 */ 9.999945e-01, /* 88 32 */ 9.996291e-01, /* 88 33 */ 9.903109e-01, /* 88 34 */ 9.251400e-01, /* 88 35 */ 7.494745e-01, /* 88 36 */ 5.065945e-01, /* 88 37 */ 2.911964e-01, /* 88 38 */ 1.479655e-01, /* 88 39 */ 6.874727e-02, /* 88 40 */ 2.957091e-02, /* 88 41 */ 1.206727e-02, /* 88 42 */ 4.640000e-03, /* 88 43 */ 1.761818e-03, /* 88 44 */ 6.236364e-04, /* 88 45 */ 2.127273e-04, /* 88 46 */ 8.363636e-05, /* 88 47 */ 3.272727e-05, /* 88 48 */ 2.514700e-05, /* 88 49 */ 6.735024e-06, /* 88 50 */ 1.724962e-06, /* 88 51 */ 4.223463e-07, /* 88 52 */ 9.882074e-08, /* 88 53 */ 2.208713e-08, /* 88 54 */ 4.713477e-09, /* 88 55 */ 9.599105e-10, /* 88 56 */ 1.864484e-10, /* 88 57 */ 3.451829e-11, /* 88 58 */ 6.086932e-12, /* 88 59 */ 1.021576e-12, /* 88 60 */ 1.630406e-13, /* 88 61 */ 2.472109e-14, /* 88 62 */ 3.557449e-15, /* 88 63 */ 4.853071e-16, /* 88 64 */ 6.268445e-17, /* 88 65 */ 7.655455e-18, /* 88 66 */ 8.826555e-19, /* 88 67 */ 9.591617e-20, /* 88 68 */ 9.805396e-21, /* 88 69 */ 9.410516e-22, /* 88 70 */ 8.459321e-23, /* 88 71 */ 7.104121e-24, /* 88 72 */ 5.557467e-25, /* 88 73 */ 4.036540e-26, /* 88 74 */ 2.711971e-27, /* 88 75 */ 1.678206e-28, /* 88 76 */ 9.517924e-30, /* 88 77 */ 4.918924e-31, /* 88 78 */ 2.300767e-32, /* 88 79 */ 9.660825e-34, /* 88 80 */ 3.605759e-35, /* 88 81 */ 1.181654e-36, /* 88 82 */ 3.347490e-38, /* 88 83 */ 8.031396e-40, /* 88 84 */ 1.586836e-41, /* 88 85 */ 2.478979e-43, /* 88 86 */ 2.871065e-45, /* 88 87 */ 2.191526e-47, /* 88 88 */ 8.269910e-50, /* 89 0 */ 1.000000e+00, /* 89 1 */ 1.000000e+00, /* 89 2 */ 1.000000e+00, /* 89 3 */ 1.000000e+00, /* 89 4 */ 1.000000e+00, /* 89 5 */ 1.000000e+00, /* 89 6 */ 1.000000e+00, /* 89 7 */ 1.000000e+00, /* 89 8 */ 1.000000e+00, /* 89 9 */ 1.000000e+00, /* 89 10 */ 1.000000e+00, /* 89 11 */ 1.000000e+00, /* 89 12 */ 1.000000e+00, /* 89 13 */ 1.000000e+00, /* 89 14 */ 1.000000e+00, /* 89 15 */ 1.000000e+00, /* 89 16 */ 1.000000e+00, /* 89 17 */ 1.000000e+00, /* 89 18 */ 1.000000e+00, /* 89 19 */ 1.000000e+00, /* 89 20 */ 1.000000e+00, /* 89 21 */ 1.000000e+00, /* 89 22 */ 1.000000e+00, /* 89 23 */ 1.000000e+00, /* 89 24 */ 1.000000e+00, /* 89 25 */ 1.000000e+00, /* 89 26 */ 1.000000e+00, /* 89 27 */ 1.000000e+00, /* 89 28 */ 1.000000e+00, /* 89 29 */ 1.000000e+00, /* 89 30 */ 1.000000e+00, /* 89 31 */ 1.000000e+00, /* 89 32 */ 9.999018e-01, /* 89 33 */ 9.961400e-01, /* 89 34 */ 9.579236e-01, /* 89 35 */ 8.207636e-01, /* 89 36 */ 5.906891e-01, /* 89 37 */ 3.584673e-01, /* 89 38 */ 1.897818e-01, /* 89 39 */ 9.075818e-02, /* 89 40 */ 4.045636e-02, /* 89 41 */ 1.669636e-02, /* 89 42 */ 6.596364e-03, /* 89 43 */ 2.523636e-03, /* 89 44 */ 9.290909e-04, /* 89 45 */ 3.272727e-04, /* 89 46 */ 1.145455e-04, /* 89 47 */ 4.727273e-05, /* 89 48 */ 4.224722e-05, /* 89 49 */ 1.159424e-05, /* 89 50 */ 3.044763e-06, /* 89 51 */ 7.649037e-07, /* 89 52 */ 1.837631e-07, /* 89 53 */ 4.220317e-08, /* 89 54 */ 9.261558e-09, /* 89 55 */ 1.941200e-09, /* 89 56 */ 3.883970e-10, /* 89 57 */ 7.413919e-11, /* 89 58 */ 1.349295e-11, /* 89 59 */ 2.339617e-12, /* 89 60 */ 3.862091e-13, /* 89 61 */ 6.064107e-14, /* 89 62 */ 9.048317e-15, /* 89 63 */ 1.281666e-15, /* 89 64 */ 1.721443e-16, /* 89 65 */ 2.189659e-17, /* 89 66 */ 2.634065e-18, /* 89 67 */ 2.992133e-19, /* 89 68 */ 3.204116e-20, /* 89 69 */ 3.228483e-21, /* 89 70 */ 3.054581e-22, /* 89 71 */ 2.707471e-23, /* 89 72 */ 2.242394e-24, /* 89 73 */ 1.730346e-25, /* 89 74 */ 1.239934e-26, /* 89 75 */ 8.220240e-28, /* 89 76 */ 5.020302e-29, /* 89 77 */ 2.810509e-30, /* 89 78 */ 1.433978e-31, /* 89 79 */ 6.622837e-33, /* 89 80 */ 2.746329e-34, /* 89 81 */ 1.012437e-35, /* 89 82 */ 3.277628e-37, /* 89 83 */ 9.173809e-39, /* 89 84 */ 2.174925e-40, /* 89 85 */ 4.246864e-42, /* 89 86 */ 6.557695e-44, /* 89 87 */ 7.507942e-46, /* 89 88 */ 5.666052e-48, /* 89 89 */ 2.114199e-50, /* 90 0 */ 1.000000e+00, /* 90 1 */ 1.000000e+00, /* 90 2 */ 1.000000e+00, /* 90 3 */ 1.000000e+00, /* 90 4 */ 1.000000e+00, /* 90 5 */ 1.000000e+00, /* 90 6 */ 1.000000e+00, /* 90 7 */ 1.000000e+00, /* 90 8 */ 1.000000e+00, /* 90 9 */ 1.000000e+00, /* 90 10 */ 1.000000e+00, /* 90 11 */ 1.000000e+00, /* 90 12 */ 1.000000e+00, /* 90 13 */ 1.000000e+00, /* 90 14 */ 1.000000e+00, /* 90 15 */ 1.000000e+00, /* 90 16 */ 1.000000e+00, /* 90 17 */ 1.000000e+00, /* 90 18 */ 1.000000e+00, /* 90 19 */ 1.000000e+00, /* 90 20 */ 1.000000e+00, /* 90 21 */ 1.000000e+00, /* 90 22 */ 1.000000e+00, /* 90 23 */ 1.000000e+00, /* 90 24 */ 1.000000e+00, /* 90 25 */ 1.000000e+00, /* 90 26 */ 1.000000e+00, /* 90 27 */ 1.000000e+00, /* 90 28 */ 1.000000e+00, /* 90 29 */ 1.000000e+00, /* 90 30 */ 1.000000e+00, /* 90 31 */ 1.000000e+00, /* 90 32 */ 9.999727e-01, /* 90 33 */ 9.985945e-01, /* 90 34 */ 9.783782e-01, /* 90 35 */ 8.799582e-01, /* 90 36 */ 6.740891e-01, /* 90 37 */ 4.329364e-01, /* 90 38 */ 2.400436e-01, /* 90 39 */ 1.191818e-01, /* 90 40 */ 5.422545e-02, /* 90 41 */ 2.318727e-02, /* 90 42 */ 9.343636e-03, /* 90 43 */ 3.709091e-03, /* 90 44 */ 1.358182e-03, /* 90 45 */ 4.909091e-04, /* 90 46 */ 1.563636e-04, /* 90 47 */ 6.000000e-05, /* 90 48 */ 2.545455e-05, /* 90 49 */ 1.968780e-05, /* 90 50 */ 5.297929e-06, /* 90 51 */ 1.364697e-06, /* 90 52 */ 3.364010e-07, /* 90 53 */ 7.932701e-08, /* 90 54 */ 1.788794e-08, /* 90 55 */ 3.855562e-09, /* 90 56 */ 7.939514e-10, /* 90 57 */ 1.561159e-10, /* 90 58 */ 2.929481e-11, /* 90 59 */ 5.242538e-12, /* 90 60 */ 8.941039e-13, /* 90 61 */ 1.452069e-13, /* 90 62 */ 2.243691e-14, /* 90 63 */ 3.295356e-15, /* 90 64 */ 4.595696e-16, /* 90 65 */ 6.078716e-17, /* 90 66 */ 7.616165e-18, /* 90 67 */ 9.026558e-19, /* 90 68 */ 1.010427e-19, /* 90 69 */ 1.066475e-20, /* 90 70 */ 1.059369e-21, /* 90 71 */ 9.883072e-23, /* 90 72 */ 8.639305e-24, /* 90 73 */ 7.058014e-25, /* 90 74 */ 5.373259e-26, /* 90 75 */ 3.799397e-27, /* 90 76 */ 2.485918e-28, /* 90 77 */ 1.498619e-29, /* 90 78 */ 8.282795e-31, /* 90 79 */ 4.172864e-32, /* 90 80 */ 1.903284e-33, /* 90 81 */ 7.795539e-35, /* 90 82 */ 2.838967e-36, /* 90 83 */ 9.080582e-38, /* 90 84 */ 2.511465e-39, /* 90 85 */ 5.884445e-41, /* 90 86 */ 1.135722e-42, /* 90 87 */ 1.733626e-44, /* 90 88 */ 1.962373e-46, /* 90 89 */ 1.464377e-48, /* 90 90 */ 5.403605e-51, /* 91 0 */ 1.000000e+00, /* 91 1 */ 1.000000e+00, /* 91 2 */ 1.000000e+00, /* 91 3 */ 1.000000e+00, /* 91 4 */ 1.000000e+00, /* 91 5 */ 1.000000e+00, /* 91 6 */ 1.000000e+00, /* 91 7 */ 1.000000e+00, /* 91 8 */ 1.000000e+00, /* 91 9 */ 1.000000e+00, /* 91 10 */ 1.000000e+00, /* 91 11 */ 1.000000e+00, /* 91 12 */ 1.000000e+00, /* 91 13 */ 1.000000e+00, /* 91 14 */ 1.000000e+00, /* 91 15 */ 1.000000e+00, /* 91 16 */ 1.000000e+00, /* 91 17 */ 1.000000e+00, /* 91 18 */ 1.000000e+00, /* 91 19 */ 1.000000e+00, /* 91 20 */ 1.000000e+00, /* 91 21 */ 1.000000e+00, /* 91 22 */ 1.000000e+00, /* 91 23 */ 1.000000e+00, /* 91 24 */ 1.000000e+00, /* 91 25 */ 1.000000e+00, /* 91 26 */ 1.000000e+00, /* 91 27 */ 1.000000e+00, /* 91 28 */ 1.000000e+00, /* 91 29 */ 1.000000e+00, /* 91 30 */ 1.000000e+00, /* 91 31 */ 1.000000e+00, /* 91 32 */ 9.999964e-01, /* 91 33 */ 9.995255e-01, /* 91 34 */ 9.901091e-01, /* 91 35 */ 9.248764e-01, /* 91 36 */ 7.525418e-01, /* 91 37 */ 5.127691e-01, /* 91 38 */ 2.985800e-01, /* 91 39 */ 1.536127e-01, /* 91 40 */ 7.255091e-02, /* 91 41 */ 3.156545e-02, /* 91 42 */ 1.297273e-02, /* 91 43 */ 5.234545e-03, /* 91 44 */ 1.960000e-03, /* 91 45 */ 7.527273e-04, /* 91 46 */ 2.472727e-04, /* 91 47 */ 8.727273e-05, /* 91 48 */ 4.000000e-05, /* 91 49 */ 3.299227e-05, /* 91 50 */ 9.091975e-06, /* 91 51 */ 2.399893e-06, /* 91 52 */ 6.065901e-07, /* 91 53 */ 1.467688e-07, /* 91 54 */ 3.398244e-08, /* 91 55 */ 7.526385e-09, /* 91 56 */ 1.593814e-09, /* 91 57 */ 3.225486e-10, /* 91 58 */ 6.234811e-11, /* 91 59 */ 1.150434e-11, /* 91 60 */ 2.024995e-12, /* 91 61 */ 3.397775e-13, /* 91 62 */ 5.430351e-14, /* 91 63 */ 8.259320e-15, /* 91 64 */ 1.194339e-15, /* 91 65 */ 1.640293e-16, /* 91 66 */ 2.137098e-17, /* 91 67 */ 2.638071e-18, /* 91 68 */ 3.081076e-19, /* 91 69 */ 3.399423e-20, /* 91 70 */ 3.537193e-21, /* 91 71 */ 3.464561e-22, /* 91 72 */ 3.187636e-23, /* 91 73 */ 2.748605e-24, /* 91 74 */ 2.215397e-25, /* 91 75 */ 1.664252e-26, /* 91 76 */ 1.161404e-27, /* 91 77 */ 7.500937e-29, /* 91 78 */ 4.464280e-30, /* 91 79 */ 2.436340e-31, /* 91 80 */ 1.212171e-32, /* 91 81 */ 5.460947e-34, /* 91 82 */ 2.209581e-35, /* 91 83 */ 7.950357e-37, /* 91 84 */ 2.512835e-38, /* 91 85 */ 6.868500e-40, /* 91 86 */ 1.590683e-41, /* 91 87 */ 3.034946e-43, /* 91 88 */ 4.580272e-45, /* 91 89 */ 5.126603e-47, /* 91 90 */ 3.783267e-49, /* 91 91 */ 1.380754e-51, /* 92 0 */ 1.000000e+00, /* 92 1 */ 1.000000e+00, /* 92 2 */ 1.000000e+00, /* 92 3 */ 1.000000e+00, /* 92 4 */ 1.000000e+00, /* 92 5 */ 1.000000e+00, /* 92 6 */ 1.000000e+00, /* 92 7 */ 1.000000e+00, /* 92 8 */ 1.000000e+00, /* 92 9 */ 1.000000e+00, /* 92 10 */ 1.000000e+00, /* 92 11 */ 1.000000e+00, /* 92 12 */ 1.000000e+00, /* 92 13 */ 1.000000e+00, /* 92 14 */ 1.000000e+00, /* 92 15 */ 1.000000e+00, /* 92 16 */ 1.000000e+00, /* 92 17 */ 1.000000e+00, /* 92 18 */ 1.000000e+00, /* 92 19 */ 1.000000e+00, /* 92 20 */ 1.000000e+00, /* 92 21 */ 1.000000e+00, /* 92 22 */ 1.000000e+00, /* 92 23 */ 1.000000e+00, /* 92 24 */ 1.000000e+00, /* 92 25 */ 1.000000e+00, /* 92 26 */ 1.000000e+00, /* 92 27 */ 1.000000e+00, /* 92 28 */ 1.000000e+00, /* 92 29 */ 1.000000e+00, /* 92 30 */ 1.000000e+00, /* 92 31 */ 1.000000e+00, /* 92 32 */ 9.999982e-01, /* 92 33 */ 9.998873e-01, /* 92 34 */ 9.959782e-01, /* 92 35 */ 9.570600e-01, /* 92 36 */ 8.220836e-01, /* 92 37 */ 5.950418e-01, /* 92 38 */ 3.650345e-01, /* 92 39 */ 1.957327e-01, /* 92 40 */ 9.528000e-02, /* 92 41 */ 4.273818e-02, /* 92 42 */ 1.803818e-02, /* 92 43 */ 7.307273e-03, /* 92 44 */ 2.823636e-03, /* 92 45 */ 1.096364e-03, /* 92 46 */ 3.727273e-04, /* 92 47 */ 1.236364e-04, /* 92 48 */ 5.272727e-05, /* 92 49 */ 1.454545e-05, /* 92 50 */ 1.090909e-05, /* 92 51 */ 4.161937e-06, /* 92 52 */ 1.077973e-06, /* 92 53 */ 2.674447e-07, /* 92 54 */ 6.353810e-08, /* 92 55 */ 1.444947e-08, /* 92 56 */ 3.144210e-09, /* 92 57 */ 6.543615e-10, /* 92 58 */ 1.301828e-10, /* 92 59 */ 2.474457e-11, /* 92 60 */ 4.490891e-12, /* 92 61 */ 7.777170e-13, /* 92 62 */ 1.284188e-13, /* 92 63 */ 2.020249e-14, /* 92 64 */ 3.025295e-15, /* 92 65 */ 4.308219e-16, /* 92 66 */ 5.828219e-17, /* 92 67 */ 7.481321e-18, /* 92 68 */ 9.100644e-19, /* 92 69 */ 1.047634e-19, /* 92 70 */ 1.139519e-20, /* 92 71 */ 1.169148e-21, /* 92 72 */ 1.129370e-22, /* 92 73 */ 1.024978e-23, /* 92 74 */ 8.719570e-25, /* 92 75 */ 6.935020e-26, /* 92 76 */ 5.141663e-27, /* 92 77 */ 3.541839e-28, /* 92 78 */ 2.258361e-29, /* 92 79 */ 1.327184e-30, /* 92 80 */ 7.152978e-32, /* 92 81 */ 3.515187e-33, /* 92 82 */ 1.564418e-34, /* 92 83 */ 6.254000e-36, /* 92 84 */ 2.223614e-37, /* 92 85 */ 6.945795e-39, /* 92 86 */ 1.876566e-40, /* 92 87 */ 4.296222e-42, /* 92 88 */ 8.104234e-44, /* 92 89 */ 1.209386e-45, /* 92 90 */ 1.338659e-47, /* 92 91 */ 9.770718e-50, /* 92 92 */ 3.527335e-52, /* 93 0 */ 1.000000e+00, /* 93 1 */ 1.000000e+00, /* 93 2 */ 1.000000e+00, /* 93 3 */ 1.000000e+00, /* 93 4 */ 1.000000e+00, /* 93 5 */ 1.000000e+00, /* 93 6 */ 1.000000e+00, /* 93 7 */ 1.000000e+00, /* 93 8 */ 1.000000e+00, /* 93 9 */ 1.000000e+00, /* 93 10 */ 1.000000e+00, /* 93 11 */ 1.000000e+00, /* 93 12 */ 1.000000e+00, /* 93 13 */ 1.000000e+00, /* 93 14 */ 1.000000e+00, /* 93 15 */ 1.000000e+00, /* 93 16 */ 1.000000e+00, /* 93 17 */ 1.000000e+00, /* 93 18 */ 1.000000e+00, /* 93 19 */ 1.000000e+00, /* 93 20 */ 1.000000e+00, /* 93 21 */ 1.000000e+00, /* 93 22 */ 1.000000e+00, /* 93 23 */ 1.000000e+00, /* 93 24 */ 1.000000e+00, /* 93 25 */ 1.000000e+00, /* 93 26 */ 1.000000e+00, /* 93 27 */ 1.000000e+00, /* 93 28 */ 1.000000e+00, /* 93 29 */ 1.000000e+00, /* 93 30 */ 1.000000e+00, /* 93 31 */ 1.000000e+00, /* 93 32 */ 1.000000e+00, /* 93 33 */ 9.999709e-01, /* 93 34 */ 9.984582e-01, /* 93 35 */ 9.776200e-01, /* 93 36 */ 8.802127e-01, /* 93 37 */ 6.768945e-01, /* 93 38 */ 4.390200e-01, /* 93 39 */ 2.459364e-01, /* 93 40 */ 1.235055e-01, /* 93 41 */ 5.715273e-02, /* 93 42 */ 2.466727e-02, /* 93 43 */ 1.020364e-02, /* 93 44 */ 4.041818e-03, /* 93 45 */ 1.576364e-03, /* 93 46 */ 5.490909e-04, /* 93 47 */ 1.854545e-04, /* 93 48 */ 6.909091e-05, /* 93 49 */ 2.181818e-05, /* 93 50 */ 1.090909e-05, /* 93 51 */ 7.121256e-06, /* 93 52 */ 1.888941e-06, /* 93 53 */ 4.802404e-07, /* 93 54 */ 1.169907e-07, /* 93 55 */ 2.729938e-08, /* 93 56 */ 6.099614e-09, /* 93 57 */ 1.304430e-09, /* 93 58 */ 2.668755e-10, /* 93 59 */ 5.220905e-11, /* 93 60 */ 9.760883e-12, /* 93 61 */ 1.742896e-12, /* 93 62 */ 2.970295e-13, /* 93 63 */ 4.827832e-14, /* 93 64 */ 7.477851e-15, /* 93 65 */ 1.102779e-15, /* 93 66 */ 1.546909e-16, /* 93 67 */ 2.061788e-17, /* 93 68 */ 2.608074e-18, /* 93 69 */ 3.127066e-19, /* 93 70 */ 3.548830e-20, /* 93 71 */ 3.806212e-21, /* 93 72 */ 3.851407e-22, /* 93 73 */ 3.669824e-23, /* 93 74 */ 3.285956e-24, /* 93 75 */ 2.758396e-25, /* 93 76 */ 2.165203e-26, /* 93 77 */ 1.584589e-27, /* 93 78 */ 1.077643e-28, /* 93 79 */ 6.784882e-30, /* 93 80 */ 3.937769e-31, /* 93 81 */ 2.096247e-32, /* 93 82 */ 1.017665e-33, /* 93 83 */ 4.474797e-35, /* 93 84 */ 1.767681e-36, /* 93 85 */ 6.211426e-38, /* 93 86 */ 1.917778e-39, /* 93 87 */ 5.122030e-41, /* 93 88 */ 1.159374e-42, /* 93 89 */ 2.162529e-44, /* 93 90 */ 3.191405e-46, /* 93 91 */ 3.493870e-48, /* 93 92 */ 2.522520e-50, /* 93 93 */ 9.008998e-53, /* 94 0 */ 1.000000e+00, /* 94 1 */ 1.000000e+00, /* 94 2 */ 1.000000e+00, /* 94 3 */ 1.000000e+00, /* 94 4 */ 1.000000e+00, /* 94 5 */ 1.000000e+00, /* 94 6 */ 1.000000e+00, /* 94 7 */ 1.000000e+00, /* 94 8 */ 1.000000e+00, /* 94 9 */ 1.000000e+00, /* 94 10 */ 1.000000e+00, /* 94 11 */ 1.000000e+00, /* 94 12 */ 1.000000e+00, /* 94 13 */ 1.000000e+00, /* 94 14 */ 1.000000e+00, /* 94 15 */ 1.000000e+00, /* 94 16 */ 1.000000e+00, /* 94 17 */ 1.000000e+00, /* 94 18 */ 1.000000e+00, /* 94 19 */ 1.000000e+00, /* 94 20 */ 1.000000e+00, /* 94 21 */ 1.000000e+00, /* 94 22 */ 1.000000e+00, /* 94 23 */ 1.000000e+00, /* 94 24 */ 1.000000e+00, /* 94 25 */ 1.000000e+00, /* 94 26 */ 1.000000e+00, /* 94 27 */ 1.000000e+00, /* 94 28 */ 1.000000e+00, /* 94 29 */ 1.000000e+00, /* 94 30 */ 1.000000e+00, /* 94 31 */ 1.000000e+00, /* 94 32 */ 1.000000e+00, /* 94 33 */ 9.999873e-01, /* 94 34 */ 9.994909e-01, /* 94 35 */ 9.895655e-01, /* 94 36 */ 9.249655e-01, /* 94 37 */ 7.539382e-01, /* 94 38 */ 5.178655e-01, /* 94 39 */ 3.043455e-01, /* 94 40 */ 1.588255e-01, /* 94 41 */ 7.545818e-02, /* 94 42 */ 3.347455e-02, /* 94 43 */ 1.406909e-02, /* 94 44 */ 5.674545e-03, /* 94 45 */ 2.172727e-03, /* 94 46 */ 7.963636e-04, /* 94 47 */ 2.690909e-04, /* 94 48 */ 1.036364e-04, /* 94 49 */ 4.181818e-05, /* 94 50 */ 1.272727e-05, /* 94 51 */ 1.202746e-05, /* 94 52 */ 3.265403e-06, /* 94 53 */ 8.502207e-07, /* 94 54 */ 2.122480e-07, /* 94 55 */ 5.078575e-08, /* 94 56 */ 1.164339e-08, /* 94 57 */ 2.556769e-09, /* 94 58 */ 5.375208e-10, /* 94 59 */ 1.081403e-10, /* 94 60 */ 2.080870e-11, /* 94 61 */ 3.827549e-12, /* 94 62 */ 6.725812e-13, /* 94 63 */ 1.128290e-13, /* 94 64 */ 1.805610e-14, /* 94 65 */ 2.754225e-15, /* 94 66 */ 4.000915e-16, /* 94 67 */ 5.529409e-17, /* 94 68 */ 7.262619e-18, /* 94 69 */ 9.055116e-19, /* 94 70 */ 1.070344e-19, /* 94 71 */ 1.197757e-20, /* 94 72 */ 1.266940e-21, /* 94 73 */ 1.264571e-22, /* 94 74 */ 1.188798e-23, /* 94 75 */ 1.050365e-24, /* 94 76 */ 8.702131e-26, /* 94 77 */ 6.742652e-27, /* 94 78 */ 4.871728e-28, /* 94 79 */ 3.271486e-29, /* 94 80 */ 2.034152e-30, /* 94 81 */ 1.166081e-31, /* 94 82 */ 6.132288e-33, /* 94 83 */ 2.941371e-34, /* 94 84 */ 1.278040e-35, /* 94 85 */ 4.989550e-37, /* 94 86 */ 1.732982e-38, /* 94 87 */ 5.289366e-40, /* 94 88 */ 1.396710e-41, /* 94 89 */ 3.126090e-43, /* 94 90 */ 5.766438e-45, /* 94 91 */ 8.416817e-47, /* 94 92 */ 9.114743e-49, /* 94 93 */ 6.510202e-51, /* 94 94 */ 2.300425e-53, /* 95 0 */ 1.000000e+00, /* 95 1 */ 1.000000e+00, /* 95 2 */ 1.000000e+00, /* 95 3 */ 1.000000e+00, /* 95 4 */ 1.000000e+00, /* 95 5 */ 1.000000e+00, /* 95 6 */ 1.000000e+00, /* 95 7 */ 1.000000e+00, /* 95 8 */ 1.000000e+00, /* 95 9 */ 1.000000e+00, /* 95 10 */ 1.000000e+00, /* 95 11 */ 1.000000e+00, /* 95 12 */ 1.000000e+00, /* 95 13 */ 1.000000e+00, /* 95 14 */ 1.000000e+00, /* 95 15 */ 1.000000e+00, /* 95 16 */ 1.000000e+00, /* 95 17 */ 1.000000e+00, /* 95 18 */ 1.000000e+00, /* 95 19 */ 1.000000e+00, /* 95 20 */ 1.000000e+00, /* 95 21 */ 1.000000e+00, /* 95 22 */ 1.000000e+00, /* 95 23 */ 1.000000e+00, /* 95 24 */ 1.000000e+00, /* 95 25 */ 1.000000e+00, /* 95 26 */ 1.000000e+00, /* 95 27 */ 1.000000e+00, /* 95 28 */ 1.000000e+00, /* 95 29 */ 1.000000e+00, /* 95 30 */ 1.000000e+00, /* 95 31 */ 1.000000e+00, /* 95 32 */ 1.000000e+00, /* 95 33 */ 9.999945e-01, /* 95 34 */ 9.998709e-01, /* 95 35 */ 9.957073e-01, /* 95 36 */ 9.568036e-01, /* 95 37 */ 8.226800e-01, /* 95 38 */ 5.988291e-01, /* 95 39 */ 3.702836e-01, /* 95 40 */ 2.010164e-01, /* 95 41 */ 9.868545e-02, /* 95 42 */ 4.486545e-02, /* 95 43 */ 1.930364e-02, /* 95 44 */ 7.840000e-03, /* 95 45 */ 3.081818e-03, /* 95 46 */ 1.209091e-03, /* 95 47 */ 4.290909e-04, /* 95 48 */ 1.490909e-04, /* 95 49 */ 6.363636e-05, /* 95 50 */ 1.818182e-05, /* 95 51 */ 7.272727e-06, /* 95 52 */ 5.571383e-06, /* 95 53 */ 1.484788e-06, /* 95 54 */ 3.796085e-07, /* 95 55 */ 9.308038e-08, /* 95 56 */ 2.188249e-08, /* 95 57 */ 4.930610e-09, /* 95 58 */ 1.064392e-09, /* 95 59 */ 2.200458e-10, /* 95 60 */ 4.354404e-11, /* 95 61 */ 8.243685e-12, /* 95 62 */ 1.492250e-12, /* 95 63 */ 2.581165e-13, /* 95 64 */ 4.263287e-14, /* 95 65 */ 6.718942e-15, /* 95 66 */ 1.009548e-15, /* 95 67 */ 1.444879e-16, /* 95 68 */ 1.967832e-17, /* 95 69 */ 2.547587e-18, /* 95 70 */ 3.131435e-19, /* 95 71 */ 3.649819e-20, /* 95 72 */ 4.028078e-21, /* 95 73 */ 4.202883e-22, /* 95 74 */ 4.138802e-23, /* 95 75 */ 3.839339e-24, /* 95 76 */ 3.347959e-25, /* 95 77 */ 2.737976e-26, /* 95 78 */ 2.094450e-27, /* 95 79 */ 1.494262e-28, /* 95 80 */ 9.909705e-30, /* 95 81 */ 6.086073e-31, /* 95 82 */ 3.446553e-32, /* 95 83 */ 1.790789e-33, /* 95 84 */ 8.487866e-35, /* 95 85 */ 3.644855e-36, /* 95 86 */ 1.406511e-37, /* 95 87 */ 4.829242e-39, /* 95 88 */ 1.457297e-40, /* 95 89 */ 3.805092e-42, /* 95 90 */ 8.422257e-44, /* 95 91 */ 1.536581e-45, /* 95 92 */ 2.218544e-47, /* 95 93 */ 2.376770e-49, /* 95 94 */ 1.679613e-51, /* 95 95 */ 5.872774e-54, /* 96 0 */ 1.000000e+00, /* 96 1 */ 1.000000e+00, /* 96 2 */ 1.000000e+00, /* 96 3 */ 1.000000e+00, /* 96 4 */ 1.000000e+00, /* 96 5 */ 1.000000e+00, /* 96 6 */ 1.000000e+00, /* 96 7 */ 1.000000e+00, /* 96 8 */ 1.000000e+00, /* 96 9 */ 1.000000e+00, /* 96 10 */ 1.000000e+00, /* 96 11 */ 1.000000e+00, /* 96 12 */ 1.000000e+00, /* 96 13 */ 1.000000e+00, /* 96 14 */ 1.000000e+00, /* 96 15 */ 1.000000e+00, /* 96 16 */ 1.000000e+00, /* 96 17 */ 1.000000e+00, /* 96 18 */ 1.000000e+00, /* 96 19 */ 1.000000e+00, /* 96 20 */ 1.000000e+00, /* 96 21 */ 1.000000e+00, /* 96 22 */ 1.000000e+00, /* 96 23 */ 1.000000e+00, /* 96 24 */ 1.000000e+00, /* 96 25 */ 1.000000e+00, /* 96 26 */ 1.000000e+00, /* 96 27 */ 1.000000e+00, /* 96 28 */ 1.000000e+00, /* 96 29 */ 1.000000e+00, /* 96 30 */ 1.000000e+00, /* 96 31 */ 1.000000e+00, /* 96 32 */ 1.000000e+00, /* 96 33 */ 9.999982e-01, /* 96 34 */ 9.999764e-01, /* 96 35 */ 9.984782e-01, /* 96 36 */ 9.773127e-01, /* 96 37 */ 8.798055e-01, /* 96 38 */ 6.793218e-01, /* 96 39 */ 4.432273e-01, /* 96 40 */ 2.516127e-01, /* 96 41 */ 1.279745e-01, /* 96 42 */ 5.969636e-02, /* 96 43 */ 2.622909e-02, /* 96 44 */ 1.099818e-02, /* 96 45 */ 4.398182e-03, /* 96 46 */ 1.745455e-03, /* 96 47 */ 6.236364e-04, /* 96 48 */ 2.218182e-04, /* 96 49 */ 8.363636e-05, /* 96 50 */ 2.545455e-05, /* 96 51 */ 7.272727e-06, /* 96 52 */ 1.818182e-06, /* 96 53 */ 1.818182e-06, /* 96 54 */ 6.696392e-07, /* 96 55 */ 1.681618e-07, /* 96 56 */ 4.051297e-08, /* 96 57 */ 9.360587e-09, /* 96 58 */ 2.073478e-09, /* 96 59 */ 4.401612e-10, /* 96 60 */ 8.950545e-11, /* 96 61 */ 1.742623e-11, /* 96 62 */ 3.246706e-12, /* 96 63 */ 5.785165e-13, /* 96 64 */ 9.852473e-14, /* 96 65 */ 1.602616e-14, /* 96 66 */ 2.487929e-15, /* 96 67 */ 3.683077e-16, /* 96 68 */ 5.194626e-17, /* 96 69 */ 6.973308e-18, /* 96 70 */ 8.900105e-19, /* 96 71 */ 1.078722e-19, /* 96 72 */ 1.239996e-20, /* 96 73 */ 1.349926e-21, /* 96 74 */ 1.389636e-22, /* 96 75 */ 1.350350e-23, /* 96 76 */ 1.236291e-24, /* 96 77 */ 1.064166e-25, /* 96 78 */ 8.592018e-27, /* 96 79 */ 6.489944e-28, /* 96 80 */ 4.572678e-29, /* 96 81 */ 2.995323e-30, /* 96 82 */ 1.817286e-31, /* 96 83 */ 1.016804e-32, /* 96 84 */ 5.220649e-34, /* 96 85 */ 2.445493e-35, /* 96 86 */ 1.037994e-36, /* 96 87 */ 3.959693e-38, /* 96 88 */ 1.344180e-39, /* 96 89 */ 4.010897e-41, /* 96 90 */ 1.035684e-42, /* 96 91 */ 2.267316e-44, /* 96 92 */ 4.091775e-46, /* 96 93 */ 5.844501e-48, /* 96 94 */ 6.194970e-50, /* 96 95 */ 4.331937e-52, /* 96 96 */ 1.498940e-54, /* 97 0 */ 1.000000e+00, /* 97 1 */ 1.000000e+00, /* 97 2 */ 1.000000e+00, /* 97 3 */ 1.000000e+00, /* 97 4 */ 1.000000e+00, /* 97 5 */ 1.000000e+00, /* 97 6 */ 1.000000e+00, /* 97 7 */ 1.000000e+00, /* 97 8 */ 1.000000e+00, /* 97 9 */ 1.000000e+00, /* 97 10 */ 1.000000e+00, /* 97 11 */ 1.000000e+00, /* 97 12 */ 1.000000e+00, /* 97 13 */ 1.000000e+00, /* 97 14 */ 1.000000e+00, /* 97 15 */ 1.000000e+00, /* 97 16 */ 1.000000e+00, /* 97 17 */ 1.000000e+00, /* 97 18 */ 1.000000e+00, /* 97 19 */ 1.000000e+00, /* 97 20 */ 1.000000e+00, /* 97 21 */ 1.000000e+00, /* 97 22 */ 1.000000e+00, /* 97 23 */ 1.000000e+00, /* 97 24 */ 1.000000e+00, /* 97 25 */ 1.000000e+00, /* 97 26 */ 1.000000e+00, /* 97 27 */ 1.000000e+00, /* 97 28 */ 1.000000e+00, /* 97 29 */ 1.000000e+00, /* 97 30 */ 1.000000e+00, /* 97 31 */ 1.000000e+00, /* 97 32 */ 1.000000e+00, /* 97 33 */ 9.999982e-01, /* 97 34 */ 9.999873e-01, /* 97 35 */ 9.994655e-01, /* 97 36 */ 9.893491e-01, /* 97 37 */ 9.243073e-01, /* 97 38 */ 7.551709e-01, /* 97 39 */ 5.215800e-01, /* 97 40 */ 3.095800e-01, /* 97 41 */ 1.632655e-01, /* 97 42 */ 7.875273e-02, /* 97 43 */ 3.541091e-02, /* 97 44 */ 1.515455e-02, /* 97 45 */ 6.174545e-03, /* 97 46 */ 2.432727e-03, /* 97 47 */ 9.418182e-04, /* 97 48 */ 3.345455e-04, /* 97 49 */ 1.290909e-04, /* 97 50 */ 4.545455e-05, /* 97 51 */ 1.272727e-05, /* 97 52 */ 3.636364e-06, /* 97 53 */ 3.636364e-06, /* 97 54 */ 1.165628e-06, /* 97 55 */ 2.996145e-07, /* 97 56 */ 7.392618e-08, /* 97 57 */ 1.750409e-08, /* 97 58 */ 3.975984e-09, /* 97 59 */ 8.660753e-10, /* 97 60 */ 1.808412e-10, /* 97 61 */ 3.618065e-11, /* 97 62 */ 6.932340e-12, /* 97 63 */ 1.271378e-12, /* 97 64 */ 2.230515e-13, /* 97 65 */ 3.741038e-14, /* 97 66 */ 5.994193e-15, /* 97 67 */ 9.168284e-16, /* 97 68 */ 1.337523e-16, /* 97 69 */ 1.859408e-17, /* 97 70 */ 2.460799e-18, /* 97 71 */ 3.096948e-19, /* 97 72 */ 3.701967e-20, /* 97 73 */ 4.197663e-21, /* 97 74 */ 4.508584e-22, /* 97 75 */ 4.579841e-23, /* 97 76 */ 4.392273e-24, /* 97 77 */ 3.969448e-25, /* 97 78 */ 3.373309e-26, /* 97 79 */ 2.689355e-27, /* 97 80 */ 2.006170e-28, /* 97 81 */ 1.396167e-29, /* 97 82 */ 9.034712e-31, /* 97 83 */ 5.415782e-32, /* 97 84 */ 2.994357e-33, /* 97 85 */ 1.519425e-34, /* 97 86 */ 7.035069e-36, /* 97 87 */ 2.951896e-37, /* 97 88 */ 1.113342e-38, /* 97 89 */ 3.737146e-40, /* 97 90 */ 1.102792e-41, /* 97 91 */ 2.816444e-43, /* 97 92 */ 6.099007e-45, /* 97 93 */ 1.088886e-46, /* 97 94 */ 1.538832e-48, /* 97 95 */ 1.614003e-50, /* 97 96 */ 1.116904e-52, /* 97 97 */ 3.825014e-55, /* 98 0 */ 1.000000e+00, /* 98 1 */ 1.000000e+00, /* 98 2 */ 1.000000e+00, /* 98 3 */ 1.000000e+00, /* 98 4 */ 1.000000e+00, /* 98 5 */ 1.000000e+00, /* 98 6 */ 1.000000e+00, /* 98 7 */ 1.000000e+00, /* 98 8 */ 1.000000e+00, /* 98 9 */ 1.000000e+00, /* 98 10 */ 1.000000e+00, /* 98 11 */ 1.000000e+00, /* 98 12 */ 1.000000e+00, /* 98 13 */ 1.000000e+00, /* 98 14 */ 1.000000e+00, /* 98 15 */ 1.000000e+00, /* 98 16 */ 1.000000e+00, /* 98 17 */ 1.000000e+00, /* 98 18 */ 1.000000e+00, /* 98 19 */ 1.000000e+00, /* 98 20 */ 1.000000e+00, /* 98 21 */ 1.000000e+00, /* 98 22 */ 1.000000e+00, /* 98 23 */ 1.000000e+00, /* 98 24 */ 1.000000e+00, /* 98 25 */ 1.000000e+00, /* 98 26 */ 1.000000e+00, /* 98 27 */ 1.000000e+00, /* 98 28 */ 1.000000e+00, /* 98 29 */ 1.000000e+00, /* 98 30 */ 1.000000e+00, /* 98 31 */ 1.000000e+00, /* 98 32 */ 1.000000e+00, /* 98 33 */ 9.999982e-01, /* 98 34 */ 9.999982e-01, /* 98 35 */ 9.998291e-01, /* 98 36 */ 9.954018e-01, /* 98 37 */ 9.559018e-01, /* 98 38 */ 8.228018e-01, /* 98 39 */ 6.024091e-01, /* 98 40 */ 3.748891e-01, /* 98 41 */ 2.062673e-01, /* 98 42 */ 1.021473e-01, /* 98 43 */ 4.720727e-02, /* 98 44 */ 2.056909e-02, /* 98 45 */ 8.587273e-03, /* 98 46 */ 3.423636e-03, /* 98 47 */ 1.374545e-03, /* 98 48 */ 4.818182e-04, /* 98 49 */ 1.836364e-04, /* 98 50 */ 7.090909e-05, /* 98 51 */ 2.363636e-05, /* 98 52 */ 7.272727e-06, /* 98 53 */ 1.818182e-06, /* 98 54 */ 1.818182e-06, /* 98 55 */ 5.267047e-07, /* 98 56 */ 1.330220e-07, /* 98 57 */ 3.225799e-08, /* 98 58 */ 7.508939e-09, /* 98 59 */ 1.677266e-09, /* 98 60 */ 3.593731e-10, /* 98 61 */ 7.382976e-11, /* 98 62 */ 1.453660e-11, /* 98 63 */ 2.741727e-12, /* 98 64 */ 4.950843e-13, /* 98 65 */ 8.554002e-14, /* 98 66 */ 1.413230e-14, /* 98 67 */ 2.231013e-15, /* 98 68 */ 3.362806e-16, /* 98 69 */ 4.835559e-17, /* 98 70 */ 6.627328e-18, /* 98 71 */ 8.648544e-19, /* 98 72 */ 1.073461e-19, /* 98 73 */ 1.265758e-20, /* 98 74 */ 1.416022e-21, /* 98 75 */ 1.500800e-22, /* 98 76 */ 1.504624e-23, /* 98 77 */ 1.424407e-24, /* 98 78 */ 1.270905e-25, /* 98 79 */ 1.066465e-26, /* 98 80 */ 8.396791e-28, /* 98 81 */ 6.186907e-29, /* 98 82 */ 4.253515e-30, /* 98 83 */ 2.719524e-31, /* 98 84 */ 1.610901e-32, /* 98 85 */ 8.802389e-34, /* 98 86 */ 4.414932e-35, /* 98 87 */ 2.020777e-36, /* 98 88 */ 8.383250e-38, /* 98 89 */ 3.126483e-39, /* 98 90 */ 1.037857e-40, /* 98 91 */ 3.029097e-42, /* 98 92 */ 7.652349e-44, /* 98 93 */ 1.639369e-45, /* 98 94 */ 2.895834e-47, /* 98 95 */ 4.049526e-49, /* 98 96 */ 4.203260e-51, /* 98 97 */ 2.878812e-53, /* 98 98 */ 9.758684e-56, /* 99 0 */ 1.000000e+00, /* 99 1 */ 1.000000e+00, /* 99 2 */ 1.000000e+00, /* 99 3 */ 1.000000e+00, /* 99 4 */ 1.000000e+00, /* 99 5 */ 1.000000e+00, /* 99 6 */ 1.000000e+00, /* 99 7 */ 1.000000e+00, /* 99 8 */ 1.000000e+00, /* 99 9 */ 1.000000e+00, /* 99 10 */ 1.000000e+00, /* 99 11 */ 1.000000e+00, /* 99 12 */ 1.000000e+00, /* 99 13 */ 1.000000e+00, /* 99 14 */ 1.000000e+00, /* 99 15 */ 1.000000e+00, /* 99 16 */ 1.000000e+00, /* 99 17 */ 1.000000e+00, /* 99 18 */ 1.000000e+00, /* 99 19 */ 1.000000e+00, /* 99 20 */ 1.000000e+00, /* 99 21 */ 1.000000e+00, /* 99 22 */ 1.000000e+00, /* 99 23 */ 1.000000e+00, /* 99 24 */ 1.000000e+00, /* 99 25 */ 1.000000e+00, /* 99 26 */ 1.000000e+00, /* 99 27 */ 1.000000e+00, /* 99 28 */ 1.000000e+00, /* 99 29 */ 1.000000e+00, /* 99 30 */ 1.000000e+00, /* 99 31 */ 1.000000e+00, /* 99 32 */ 1.000000e+00, /* 99 33 */ 9.999982e-01, /* 99 34 */ 9.999982e-01, /* 99 35 */ 9.999509e-01, /* 99 36 */ 9.982255e-01, /* 99 37 */ 9.766164e-01, /* 99 38 */ 8.793091e-01, /* 99 39 */ 6.818582e-01, /* 99 40 */ 4.474327e-01, /* 99 41 */ 2.563855e-01, /* 99 42 */ 1.315418e-01, /* 99 43 */ 6.242545e-02, /* 99 44 */ 2.772000e-02, /* 99 45 */ 1.168909e-02, /* 99 46 */ 4.869091e-03, /* 99 47 */ 1.847273e-03, /* 99 48 */ 7.490909e-04, /* 99 49 */ 2.781818e-04, /* 99 50 */ 1.109091e-04, /* 99 51 */ 3.454545e-05, /* 99 52 */ 9.090909e-06, /* 99 53 */ 3.636364e-06, /* 99 54 */ 3.399340e-06, /* 99 55 */ 9.139701e-07, /* 99 56 */ 2.361419e-07, /* 99 57 */ 5.861544e-08, /* 99 58 */ 1.397429e-08, /* 99 59 */ 3.198841e-09, /* 99 60 */ 7.028326e-10, /* 99 61 */ 1.481641e-10, /* 99 62 */ 2.995602e-11, /* 99 63 */ 5.805985e-12, /* 99 64 */ 1.078201e-12, /* 99 65 */ 1.917417e-13, /* 99 66 */ 3.263364e-14, /* 99 67 */ 5.312044e-15, /* 99 68 */ 8.264092e-16, /* 99 69 */ 1.227802e-16, /* 99 70 */ 1.740577e-17, /* 99 71 */ 2.352283e-18, /* 99 72 */ 3.027479e-19, /* 99 73 */ 3.706736e-20, /* 99 74 */ 4.312225e-21, /* 99 75 */ 4.760386e-22, /* 99 76 */ 4.979561e-23, /* 99 77 */ 4.927930e-24, /* 99 78 */ 4.605854e-25, /* 99 79 */ 4.057863e-26, /* 99 80 */ 3.362842e-27, /* 99 81 */ 2.615259e-28, /* 99 82 */ 1.903623e-29, /* 99 83 */ 1.293075e-30, /* 99 84 */ 8.169561e-32, /* 99 85 */ 4.782606e-33, /* 99 86 */ 2.583121e-34, /* 99 87 */ 1.280779e-35, /* 99 88 */ 5.796027e-37, /* 99 89 */ 2.377613e-38, /* 99 90 */ 8.769106e-40, /* 99 91 */ 2.879119e-41, /* 99 92 */ 8.312080e-43, /* 99 93 */ 2.077380e-44, /* 99 94 */ 4.403236e-46, /* 99 95 */ 7.696459e-48, /* 99 96 */ 1.065101e-49, /* 99 97 */ 1.094180e-51, /* 99 98 */ 7.417834e-54, /* 99 99 */ 2.489206e-56, /* 100 0 */ 1.000000e+00, /* 100 1 */ 1.000000e+00, /* 100 2 */ 1.000000e+00, /* 100 3 */ 1.000000e+00, /* 100 4 */ 1.000000e+00, /* 100 5 */ 1.000000e+00, /* 100 6 */ 1.000000e+00, /* 100 7 */ 1.000000e+00, /* 100 8 */ 1.000000e+00, /* 100 9 */ 1.000000e+00, /* 100 10 */ 1.000000e+00, /* 100 11 */ 1.000000e+00, /* 100 12 */ 1.000000e+00, /* 100 13 */ 1.000000e+00, /* 100 14 */ 1.000000e+00, /* 100 15 */ 1.000000e+00, /* 100 16 */ 1.000000e+00, /* 100 17 */ 1.000000e+00, /* 100 18 */ 1.000000e+00, /* 100 19 */ 1.000000e+00, /* 100 20 */ 1.000000e+00, /* 100 21 */ 1.000000e+00, /* 100 22 */ 1.000000e+00, /* 100 23 */ 1.000000e+00, /* 100 24 */ 1.000000e+00, /* 100 25 */ 1.000000e+00, /* 100 26 */ 1.000000e+00, /* 100 27 */ 1.000000e+00, /* 100 28 */ 1.000000e+00, /* 100 29 */ 1.000000e+00, /* 100 30 */ 1.000000e+00, /* 100 31 */ 1.000000e+00, /* 100 32 */ 1.000000e+00, /* 100 33 */ 1.000000e+00, /* 100 34 */ 9.999982e-01, /* 100 35 */ 9.999873e-01, /* 100 36 */ 9.993691e-01, /* 100 37 */ 9.888091e-01, /* 100 38 */ 9.235400e-01, /* 100 39 */ 7.562327e-01, /* 100 40 */ 5.248073e-01, /* 100 41 */ 3.143236e-01, /* 100 42 */ 1.679527e-01, /* 100 43 */ 8.159091e-02, /* 100 44 */ 3.699455e-02, /* 100 45 */ 1.610727e-02, /* 100 46 */ 6.689091e-03, /* 100 47 */ 2.636364e-03, /* 100 48 */ 1.078182e-03, /* 100 49 */ 4.018182e-04, /* 100 50 */ 1.472727e-04, /* 100 51 */ 6.000000e-05, /* 100 52 */ 9.090909e-06, /* 100 53 */ 3.636364e-06, /* 100 54 */ 1.818182e-06, /* 100 55 */ 1.566172e-06, /* 100 56 */ 4.137515e-07, /* 100 57 */ 1.050673e-07, /* 100 58 */ 2.563978e-08, /* 100 59 */ 6.011147e-09, /* 100 60 */ 1.353504e-09, /* 100 61 */ 2.925965e-10, /* 100 62 */ 6.070414e-11, /* 100 63 */ 1.208155e-11, /* 100 64 */ 2.305576e-12, /* 100 65 */ 4.216651e-13, /* 100 66 */ 7.386612e-14, /* 100 67 */ 1.238651e-14, /* 100 68 */ 1.986969e-15, /* 100 69 */ 3.046910e-16, /* 100 70 */ 4.462873e-17, /* 100 71 */ 6.238579e-18, /* 100 72 */ 8.315159e-19, /* 100 73 */ 1.055676e-19, /* 100 74 */ 1.275228e-20, /* 100 75 */ 1.463930e-21, /* 100 76 */ 1.594991e-22, /* 100 77 */ 1.646936e-23, /* 100 78 */ 1.609128e-24, /* 100 79 */ 1.485065e-25, /* 100 80 */ 1.292139e-26, /* 100 81 */ 1.057696e-27, /* 100 82 */ 8.125980e-29, /* 100 83 */ 5.844013e-30, /* 100 84 */ 3.922698e-31, /* 100 85 */ 2.449347e-32, /* 100 86 */ 1.417312e-33, /* 100 87 */ 7.567497e-35, /* 100 88 */ 3.709746e-36, /* 100 89 */ 1.660037e-37, /* 100 90 */ 6.734411e-39, /* 100 91 */ 2.456615e-40, /* 100 92 */ 7.978409e-42, /* 100 93 */ 2.278723e-43, /* 100 94 */ 5.634718e-45, /* 100 95 */ 1.181819e-46, /* 100 96 */ 2.044278e-48, /* 100 97 */ 2.799988e-50, /* 100 98 */ 2.847185e-52, /* 100 99 */ 1.910777e-54, /* 100 100 */ 6.348098e-57 }; abyss-2.2.4/Align/mergepairs.cc000066400000000000000000000235461361462241400163540ustar00rootroot00000000000000#include "smith_waterman.h" #include "config.h" #include "DataLayer/Options.h" #include "Align/Options.h" #include "Common/Options.h" #include "FastaReader.h" #include "IOUtil.h" #include "Uncompress.h" #include "alignGlobal.h" #include #include #include #include #include #include #include #include using namespace std; #define PROGRAM "abyss-mergepairs" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Anthony Raymond.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... READS1 READS2\n" "Attempt to merge reads in READS1 with reads in READS2\n" "\n" " Options:\n" "\n" " -o, --prefix=PREFIX the prefix of all output files [out]\n" " -p, --identity=N minimum overlap identity [0.9]\n" " -m, --matches=N minimum number of matches in overlap [10]\n" " -1, --length1=N trim bases from 3' end of first read\n" " down to a maximum of N bp long [inf]\n" " -2, --length2=N trim bases from 3' end of second read\n" " down to a maximum of N bp long [inf]\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" " -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" " -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 { static string prefix = "out"; static float identity = 0.9; static unsigned min_matches = 10; /** Max length of read 1. */ static int max_len_1 = 0; /** Max length of read 2. */ static int max_len_2 = 0; } static struct { unsigned total_reads; unsigned merged_reads; unsigned unmerged_reads; unsigned unchaste_reads; unsigned no_alignment; unsigned too_many_aligns; unsigned low_matches; unsigned has_indel; unsigned pid_low; } stats; static const char shortopts[] = "o:p:m:q:1:2:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "prefix", required_argument, NULL, 'o' }, { "identity", required_argument, NULL, 'p' }, { "matches", required_argument, NULL, 'm' }, { "verbose", no_argument, NULL, 'v' }, { "length1", no_argument, NULL, '1' }, { "length2", no_argument, NULL, '2' }, { "chastity", no_argument, &opt::chastityFilter, 1 }, { "no-chastity", no_argument, &opt::chastityFilter, 0 }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "trim-quality", required_argument, NULL, 'q' }, { "standard-quality", no_argument, &opt::qualityOffset, 33 }, { "illumina-quality", no_argument, &opt::qualityOffset, 64 }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; char bestBase(char a, char b, char qa, char qb) { return qa > qb ? a : b; } /** Merge the read sequences taking the highest quality base when * there is a dissagreement while reporting the lowest quality * possible. */ static void mergeReads(overlap_align& overlap, FastqRecord& rec1, FastqRecord& rec2, FastqRecord& out) { size_t ol = overlap.length(); Sequence seq1 = rec1.seq; string qual1 = rec1.qual; Sequence rc_seq2 = reverseComplement(rec2.seq); string rc_qual2(rec2.qual); reverse(rc_qual2.begin(), rc_qual2.end()); // Form overhanging portions of the reads. size_t out_len = overlap.overlap_t_pos + ol + rc_seq2.length() - overlap.overlap_h_pos - 1; Sequence out_seq(out_len, 'N'); string out_qual(out_len, '#'); assert(out_seq.length() >= seq1.length() || out_seq.length() >= rc_seq2.length()); copy(seq1.begin(), seq1.begin() + overlap.overlap_t_pos, out_seq.begin()); copy(rc_seq2.begin() + overlap.overlap_h_pos + 1, rc_seq2.end(), out_seq.begin() + overlap.overlap_t_pos + ol); copy(qual1.begin(), qual1.begin() + overlap.overlap_t_pos, out_qual.begin()); copy(rc_qual2.begin() + ol, rc_qual2.end(), out_qual.begin() + seq1.length()); // Fix the sequence and quality inside the overlap. for (unsigned i = 0; i < ol; i++) { assert(int(seq1.length() - ol + i) >= 0); unsigned pos = seq1.length() - ol + i; assert(pos < seq1.length() && i < rc_seq2.length() && pos < out_seq.length()); if (seq1[pos] == rc_seq2[i]) { out_seq[pos] = seq1[pos]; out_qual[pos] = max(qual1[pos], rc_qual2[i]); } else { out_seq[pos] = bestBase(seq1[pos], rc_seq2[i], qual1[pos], rc_qual2[i]); out_qual[pos] = min(qual1[pos], rc_qual2[i]); } } //cout << seq1 << '\n' << rc_seq2 << '\n' << out_seq << '\n'; //cout << qual1 << '\n' << rc_qual2 << '\n' << out_qual << '\n'; out = FastqRecord(rec1.id, rec1.comment, out_seq, out_qual); } bool isGapless(overlap_align& o, Sequence& s) { return o.length() == s.length() - o.overlap_t_pos && o.length() == o.overlap_h_pos + 1; } static void filterAlignments(vector& overlaps, FastaRecord& rec) { if (overlaps.empty()) { stats.no_alignment++; return; } vector::iterator it; for (it = overlaps.begin(); it != overlaps.end(); it++ ) { overlap_align o = *it; if (o.overlap_match < opt::min_matches) overlaps.erase(it--); } if (overlaps.empty()) { stats.low_matches++; return; } for (it = overlaps.begin(); it != overlaps.end(); it++ ) { overlap_align o = *it; if (o.pid() < opt::identity) overlaps.erase(it--); } if (overlaps.empty()) { stats.pid_low++; return; } for (it = overlaps.begin(); it != overlaps.end(); it++ ) { overlap_align o = *it; if (!isGapless(o, rec.seq)) overlaps.erase(it--); } if (overlaps.empty()) { stats.has_indel++; return; } } /** Align read pairs. */ static void alignFiles(const char* reads1, const char* reads2) { if (opt::verbose > 0) cerr << "Merging `" << reads1 << "' with `" << reads2 << "'\n"; FastaReader r1(reads1, FastaReader::NO_FOLD_CASE, opt::max_len_1); FastaReader r2(reads2, FastaReader::NO_FOLD_CASE, opt::max_len_2); // Openning the output files string name(opt::prefix); name.append("_reads_1.fastq"); ofstream unmerged1(name.c_str()); name = string(opt::prefix); name.append("_reads_2.fastq"); ofstream unmerged2(name.c_str()); name = string(opt::prefix); name.append("_merged.fastq"); ofstream merged(name.c_str()); FastqRecord rec1, rec2; int x = 0; while (r1 >> rec1 && r2 >> rec2) { stats.total_reads++; string rc_qual2(rec2.qual); reverse(rc_qual2.begin(), rc_qual2.end()); vector overlaps; alignOverlap(rec1.seq, reverseComplement(rec2.seq), 0, overlaps, true, opt::verbose > 2); filterAlignments(overlaps, rec1); if (overlaps.size() == 1) { // If there is only one good alignment, merge reads and // print to merged file stats.merged_reads++; FastqRecord out; mergeReads(overlaps[0], rec1, rec2, out); merged << out; cout << overlaps[0].length() << ' ' << overlaps[0].overlap_match << '\n'; } else { // print reads to separate files if (overlaps.size() > 1) stats.too_many_aligns++; stats.unmerged_reads++; unmerged1 << rec1; unmerged2 << rec2; } if (opt::verbose > 0 && ++x % 10000 == 0) { cerr << "Aligned " << x << " reads.\n"; } } r2 >> rec2; stats.unchaste_reads = r1.unchaste(); stats.total_reads += r1.unchaste(); assert(r1.eof()); assert(r2.eof()); unmerged1.close(); unmerged2.close(); merged.close(); } int main(int argc, char** argv) { bool die = false; //defaults for alignment parameters opt::match = 1; opt::mismatch = -2; opt::gap_open = -10000; opt::gap_extend = -10000; for (int c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'o': arg >> opt::prefix; break; case 'p': arg >> opt::identity; break; case 'm': arg >> opt::min_matches; break; case 'q': arg >> opt::qualityThreshold; break; case '1': arg >> opt::max_len_1; break; case '2': arg >> opt::max_len_2; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } const char* reads1 = argv[optind++]; const char* reads2 = argv[optind++]; alignFiles(reads1, reads2); cerr << "Pair merging stats: total=" << stats.total_reads << " merged=" << stats.merged_reads << " unmerged=" << stats.unmerged_reads << " unchaste=" << stats.unchaste_reads << '\n' << "no_alignment=" << stats.no_alignment << " too_many_aligns=" << stats.too_many_aligns << " too_few_matches=" << stats.low_matches << " has_indel=" << stats.has_indel << " low_pid=" << stats.pid_low << '\n'; return 0; } abyss-2.2.4/Align/smith_waterman.cpp000066400000000000000000000175451361462241400174370ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////////// // Smith_waterman implementation, with modification, to find sequence overlap // // Written by Rong She (rshe@bcgsc.ca) // Last modified: Jul 7, 2010 ////////////////////////////////////////////////////////////////////////////// #include "smith_waterman.h" #include "Sequence.h" #include "Align/Options.h" #include #include #include #include // for DBL_MAX #include using namespace std; namespace opt { /** The score of a match. */ int match = 5; /** The score of a mismatch. */ int mismatch = -4; /** gap open penalty */ int gap_open = -12; /** gap extend penalty */ int gap_extend = -4; } /** Print the specified alignment. */ static ostream& printAlignment(ostream& out, const string& aseq, const string& bseq, unsigned alignPos[], SMAlignment align) { unsigned astart = alignPos[0], aend = alignPos[1] + 1; unsigned bstart = alignPos[2], bend = alignPos[3] + 1; assert(aend == aseq.size()); assert(bstart == 0); (void)aend; (void)bstart; out << aseq.substr(0, astart) << align.query_align << '\n' << string(astart, ' '); for (unsigned i = 0; i < align.match_align.size(); i++) { char a = align.query_align[i], b = align.target_align[i], c = align.match_align[i]; out << (c == a || c == b ? '.' : c); } return out << '\n' << string(astart, ' ') << align.target_align << bseq.substr(bend) << '\n'; } /** Index comparison functor. */ template struct index_cmp { const T arr; index_cmp(const T arr) : arr(arr) {} bool operator()(const int a, const int b) const { return arr[a] > arr[b]; } }; /** Return whether the characters a and b match. * @param c [out] the consensus character */ static bool isMatch(char a, char b, char& c) { if (a == b) { c = a; } else if (toupper(a) == toupper(b)) { c = islower(a) || islower(b) ? tolower(a) : a; } else if (a == 'N' || a == 'n') { c = b; } else if (b == 'N' || b == 'n') { c = a; } else { c = ambiguityOr(a, b); return ambiguityIsSubset(a, b); } return true; } /** Return the score of the alignment of a and b. */ static int matchScore(const char a, const char b) { char consensus; return isMatch(a, b, consensus) ? opt::match : opt::mismatch; } /** Return the score of a gap, either newly opened or extended. */ static int gapScore(bool prev_is_gap) { return prev_is_gap ? opt::gap_extend : opt::gap_open; } //the backtrack step in smith_waterman unsigned Backtrack(const int i_max, const int j_max, int** I_i, int** I_j, const string& seq_a, const string& seq_b, SMAlignment& align, unsigned* align_pos) { // Backtracking from H_max int current_i=i_max,current_j=j_max; int next_i=I_i[current_i][current_j]; int next_j=I_j[current_i][current_j]; string consensus_a(""), consensus_b(""), match(""); unsigned num_of_match = 0; while(((current_i!=next_i) || (current_j!=next_j)) && (next_j!=0) && (next_i!=0)){ if(next_i==current_i) { consensus_a += '-'; //deletion in A match += tolower(seq_b[current_j-1]); consensus_b += seq_b[current_j-1]; //b must be some actual char, cannot be '-' aligns with '-'! } else { consensus_a += seq_a[current_i-1]; // match/mismatch in A if(next_j==current_j) { consensus_b += '-'; // deletion in B match += tolower(seq_a[current_i-1]); } else { consensus_b += seq_b[current_j-1]; // match/mismatch in B char consensus_char; if (isMatch(seq_a[current_i-1], seq_b[current_j-1], consensus_char)) { match += consensus_char; num_of_match++; } else { match += ambiguityOr( seq_a[current_i-1], seq_b[current_j-1]); } } } current_i = next_i; current_j = next_j; next_i=I_i[current_i][current_j]; next_j=I_j[current_i][current_j]; } //check whether the alignment is what we want (pinned at the ends), modified version of SW (i_max is already fixed) if (current_j > 1) return 0; //record the last one consensus_a += seq_a[current_i-1]; consensus_b += seq_b[current_j-1]; char consensus_char; if (isMatch(seq_a[current_i-1], seq_b[current_j-1], consensus_char)) { match += consensus_char; num_of_match++; } else { match += ambiguityOr(seq_a[current_i-1], seq_b[current_j-1]); } align_pos[0] = current_i-1; align_pos[2] = current_j-1; align_pos[1] = i_max-1; align_pos[3] = j_max-1; reverse(consensus_a.begin(), consensus_a.end()); reverse(consensus_b.begin(), consensus_b.end()); reverse(match.begin(), match.end()); align.query_align = consensus_a; align.match_align = match; align.target_align = consensus_b; return num_of_match; } /* This is the Smith-Waterman algorithm (a variation of * Needleman-Wunsch algorithm), finds one optimal local alignment * Modified to find overlap of seq_a and seq_b (alignment that is * pinned at the end of seq_a and beginning of seq_b). * Actually, this should be a variation of needleman algorithm, that * looks for a global alignment, but without penalizing overhangs... * and make sure the alignment is end-to-end (end of seqA to beginning * of seqB). */ void alignOverlap(const string& seq_a, const string& seq_b, unsigned seq_a_start_pos, vector& overlaps, bool multi_align, bool verbose) { // get the actual lengths of the sequences int N_a = seq_a.length(); int N_b = seq_b.length(); // initialize H int i, j; double** H; int **I_i, **I_j; H = new double*[N_a+1]; I_i = new int*[N_a+1]; I_j = new int*[N_a+1]; bool** V = new bool*[N_a+1]; for(i=0;i<=N_a;i++){ H[i] = new double[N_b+1]; I_i[i] = new int[N_b+1]; I_j[i] = new int[N_b+1]; H[i][0]=0; //only need to initialize first row and first column I_i[i][0] = i-1; V[i] = new bool[N_b+1]; V[i][0] = true; //valid start } for (j = 0; j <= N_b; j++) { H[0][j] = 0; //initialize first column I_j[0][j] = j-1; V[0][j] = false; //wrong start, not overlap } V[0][0] = true; for(i=1;i<=N_a;i++){ for(j=1;j<=N_b;j++){ char a = seq_a[i-1], b = seq_b[j-1]; double scores[3] = { V[i-1][j-1] ? H[i-1][j-1] + matchScore(a, b) : -DBL_MAX, // match or mismatch V[i-1][j] ? H[i-1][j] + gapScore(I_j[i-1][j] == j) : -DBL_MAX, // deletion in sequence A V[i][j-1] ? H[i][j-1] + gapScore(I_i[i][j-1] == i) : -DBL_MAX // deletion in sequence B }; double* pMax = max_element(scores, scores + 3); H[i][j] = *pMax; switch (pMax - scores) { case 0: // match or mismatch I_i[i][j] = i-1; I_j[i][j] = j-1; break; case 1: // deletion in sequence A I_i[i][j] = i-1; I_j[i][j] = j; break; case 2: // deletion in sequence B I_i[i][j] = i; I_j[i][j] = j-1; break; } V[i][j] = H[i][j] == -DBL_MAX ? false : true; } } // search H for the maximal score unsigned num_of_match = 0; double H_max = 0.; int i_max=N_a, j_max; int* j_max_indexes=new int[N_b]; //this array holds the index of j_max in H[N_a] for (j=0; j(H[N_a])); //find ALL overlap alignments, starting from the highest score j_max j = 0; bool found = false; while (j < N_b) { j_max = j_max_indexes[j]; H_max = H[N_a][j_max]; if (H_max == 0) break; SMAlignment align; unsigned align_pos[4]; num_of_match = Backtrack(i_max, j_max, I_i, I_j, seq_a, seq_b, align, align_pos); if (num_of_match) { overlaps.push_back(overlap_align(seq_a_start_pos+align_pos[0], align_pos[3], align.match_align, num_of_match)); if (!found) { if (verbose) printAlignment(cerr, seq_a, seq_b, align_pos, align); found = true; if (!multi_align || (j+1 < N_b && H[N_a][j_max_indexes[j+1]] < H_max)) break; } } j++; } delete [] j_max_indexes; for(i=0;i<=N_a;i++){ delete [] H[i]; delete [] I_i[i]; delete [] I_j[i]; delete [] V[i]; } delete [] H; delete [] I_i; delete [] I_j; delete [] V; } abyss-2.2.4/Align/smith_waterman.h000066400000000000000000000037131361462241400170740ustar00rootroot00000000000000////////////////////////////////////////////////////////////////////////////// // Smith_waterman header // // Written by Rong She (rshe@bcgsc.ca) // Last modified: Jul 6, 2010 ////////////////////////////////////////////////////////////////////////////// #ifndef SMITH_WATERMAN_H #define SMITH_WATERMAN_H #include #include #include using namespace std; /* a simple data structure to store alignment sequences */ struct SMAlignment { string query_align; string target_align; string match_align; SMAlignment() {} friend ostream& operator<<(ostream& os, const SMAlignment& align) { os << "query:" << align.query_align << endl; os << "match:" << align.match_align << endl; os << "targt:" << align.target_align << endl; return os; } }; /* overlap alignment between two sequences t and h */ struct overlap_align { unsigned overlap_t_pos; //overlap on t is from this pos to end of sequence t unsigned overlap_h_pos; //overlap on h is from beginning of sequence h to this pos string overlap_str; unsigned overlap_match; overlap_align() : overlap_t_pos(0), overlap_h_pos(0), overlap_str(""), overlap_match(0) {} overlap_align(unsigned t_pos, unsigned h_pos, string& overlap, unsigned num_of_match) : overlap_t_pos(t_pos), overlap_h_pos(h_pos), overlap_str(overlap), overlap_match(num_of_match) {} unsigned length() const { return overlap_str.length(); } double pid() const { return (double)overlap_match / overlap_str.length(); } friend ostream& operator<<(ostream& os, const overlap_align& align) { os << "overlap region:" << align.overlap_str << endl << "t:" << align.overlap_t_pos << ", h:" << align.overlap_h_pos << ";num_of_match:" << align.overlap_match << ";len:" << align.length() << ";pid:" << align.pid() << endl; return os; } }; void alignOverlap(const string& seq_a, const string& seq_b, unsigned seq_a_start_pos, vector& overlaps, bool multi_align, bool verbose); #endif /* SMITH_WATERMAN_H */ abyss-2.2.4/Assembly/000077500000000000000000000000001361462241400144225ustar00rootroot00000000000000abyss-2.2.4/Assembly/AdjacencyAlgorithm.h000066400000000000000000000024341361462241400203260ustar00rootroot00000000000000#ifndef ASSEMBLY_ADJACENCYALGORITHM_H #define ASSEMBLY_ADJACENCYALGORITHM_H 1 namespace AssemblyAlgorithms { /** Generate the adjacency information for each sequence in the * collection. */ template size_t generateAdjacency(Graph* seqCollection) { typedef typename graph_traits::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 abyss-2.2.4/Assembly/AssembleAlgorithm.h000066400000000000000000000076431361462241400202070ustar00rootroot00000000000000#ifndef ASSEMBLY_ASSEMBLEALGORITHM_H #define ASSEMBLY_ASSEMBLEALGORITHM_H 1 #include "DataLayer/FastaWriter.h" #include #include namespace AssemblyAlgorithms { /** Assemble a contig. * @return the number of k-mer below the coverage threshold */ template 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::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 abyss-2.2.4/Assembly/AssemblyAlgorithms.cc000066400000000000000000000005711361462241400205450ustar00rootroot00000000000000#include "config.h" #include "Common/InsOrderedMap.h" #include #include namespace AssemblyAlgorithms { /** The number of k-mer that have been eroded. */ size_t g_numEroded; std::vector tempCounter(16,0); InsOrderedMap tempStatMap; void addToDb(const std::string& key, const int& value) { tempStatMap.push_back(key, value); } }; abyss-2.2.4/Assembly/AssemblyAlgorithms.h000066400000000000000000000071261361462241400204120ustar00rootroot00000000000000#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 #include #include "Common/InsOrderedMap.h" class Histogram; /** A summary of the in- and out-degree of a vertex. */ enum SeqContiguity { SC_ISLAND, // sequence is completely isolated SC_ENDPOINT, // one end of the sequence is open SC_CONTIGUOUS // the sequence is closed on both ends }; /** De Bruijn graph assembly algorithms. */ namespace AssemblyAlgorithms { extern std::vector tempCounter; extern InsOrderedMap tempStatMap; extern void addToDb(const std::string&, const int&); static inline bool extendBranch(BranchRecord& branch, graph_traits::vertex_descriptor& kmer, SequenceCollectionHash::SymbolSet ext); static inline bool processLinearExtensionForBranch(BranchRecord& branch, graph_traits::vertex_descriptor& currSeq, SequenceCollectionHash::SymbolSetPair extensions, int multiplicity, unsigned maxLength, bool addKmer = true); static inline void initiateBranchGroup(BranchGroup& group, const graph_traits::vertex_descriptor& seq, const SequenceCollectionHash::SymbolSet& extension); template void removeSequenceAndExtensions(Graph* seqCollection, const typename Graph::value_type& seq); /** Return the kmer which are adjacent to this kmer. */ template void generateSequencesFromExtension( const V& currSeq, extDirection dir, SymbolSet extension, std::vector& outseqs) { typedef typename SymbolSet::Symbol Symbol; std::vector 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 */ static inline SeqContiguity checkSeqContiguity( 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 */ template 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 abyss-2.2.4/Assembly/BranchGroup.h000066400000000000000000000131011361462241400170010ustar00rootroot00000000000000#ifndef BRANCHGROUP_H #define BRANCHGROUP_H 1 #include "Common/Algorithms.h" #include "Common/Exception.h" #include // for swap #include #include enum BranchGroupStatus { BGS_ACTIVE, BGS_NOEXT, BGS_JOINED, BGS_TOOLONG, BGS_TOOMANYBRANCHES }; /** A container of BranchRecord. */ class BranchGroup { public: typedef std::vector BranchGroupData; typedef BranchGroupData::iterator iterator; typedef BranchGroupData::const_iterator const_iterator; BranchGroup() : m_dir(SENSE) , m_maxNumBranches(0) , m_noExt(false) , m_status(BGS_ACTIVE) {} BranchGroup(extDirection dir, size_t maxNumBranches, const BranchRecord::V& origin) : m_dir(dir) , m_origin(origin) , m_maxNumBranches(maxNumBranches) , m_noExt(false) , m_status(BGS_ACTIVE) { m_branches.reserve(m_maxNumBranches); } BranchGroup( extDirection dir, size_t maxNumBranches, const BranchRecord::V& origin, const BranchRecord& branch) : m_dir(dir) , m_origin(origin) , m_maxNumBranches(maxNumBranches) , m_noExt(false) , m_status(BGS_ACTIVE) { m_branches.reserve(m_maxNumBranches); m_branches.push_back(branch); } BranchGroup(const BranchGroup& o) : m_branches(o.m_branches) , m_dir(o.m_dir) , m_origin(o.m_origin) , m_maxNumBranches(o.m_maxNumBranches) , m_noExt(o.m_noExt) , m_status(o.m_status) { m_branches.reserve(m_maxNumBranches); } /** Add a branch to this group. */ BranchRecord& addBranch(const BranchRecord& branch) { assert(m_branches.size() < m_maxNumBranches); m_branches.push_back(branch); return m_branches.back(); } /** Add a branch to this group and extend the new branch with * the given k-mer. */ void addBranch(const BranchRecord& branch, const BranchRecord::V& kmer) { if (m_branches.size() < m_maxNumBranches) addBranch(branch).push_back(std::make_pair(kmer, BranchRecord::VP())); else m_status = BGS_TOOMANYBRANCHES; } /** Return the specified branch. */ BranchRecord& operator[](unsigned id) { return m_branches[id]; } /** Return the number of branches in this group. */ size_t size() const { return m_branches.size(); } /** Return whether a branch contains the specified k-mer at * the index i. */ bool exists(unsigned i, const BranchRecord::V& kmer) const { for (BranchGroupData::const_iterator it = m_branches.begin(); it != m_branches.end(); ++it) if (it->exists(i, kmer)) return true; return false; } // return the current status of the branch BranchGroupStatus getStatus() const { return m_status; } // set the no extension flag void setNoExtension() { m_noExt = true; } // is the no extension flag set? bool isNoExt() const { return m_noExt; } // return the direction of growth extDirection getDirection() const { return m_dir; } iterator begin() { return m_branches.begin(); } iterator end() { return m_branches.end(); } const_iterator begin() const { return m_branches.begin(); } const_iterator end() const { return m_branches.end(); } // 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(), [](BranchRecord& b) { return b.pop_back(); }); // Sort the branches by coverage. std::function lambda = [](const BranchRecord& b) { return b.calculateBranchMultiplicity(); }; sort_by_transform(m_branches.begin(), m_branches.end(), lambda); 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; BranchRecord::V m_origin; size_t m_maxNumBranches; bool m_noExt; BranchGroupStatus m_status; }; #endif abyss-2.2.4/Assembly/BranchRecord.h000066400000000000000000000007051361462241400171310ustar00rootroot00000000000000#ifndef ASSEMBLY_BRANCHRECORD_H #define ASSEMBLY_BRANCHRECORD_H 1 /** Generate the sequence of this contig. */ template void branchRecordToStr(It it, It last, OutIt out) { 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 abyss-2.2.4/Assembly/BranchRecordBase.h000066400000000000000000000104431361462241400177240ustar00rootroot00000000000000#ifndef ASSEMBLY_BRANCHRECORDBASE_H #define ASSEMBLY_BRANCHRECORDBASE_H 1 #include "Common/Exception.h" #include #include #include #include #include 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 vertices. */ class BranchRecord { public: typedef SequenceCollectionHash Graph; typedef graph_traits::vertex_descriptor V; typedef vertex_bundle_type::type VP; typedef std::pair value_type; typedef std::vector 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); } /** 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 V& 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; } /** 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; } /** 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; extDirection m_dir; BranchState m_state; }; namespace std { template <> inline void swap(BranchRecord& a, BranchRecord& b) NOEXCEPT { a.swap(b); } } #endif abyss-2.2.4/Assembly/BubbleAlgorithm.h000066400000000000000000000173341361462241400176450ustar00rootroot00000000000000#ifndef ASSEMBLY_BUBBLEALGORITHM_H #define ASSEMBLY_BUBBLEALGORITHM_H 1 #include "Common/IOUtil.h" #include "Common/Options.h" // for opt::rank #include #include namespace AssemblyAlgorithms { static inline bool processBranchGroupExtension(BranchGroup& group, size_t branchIndex, const graph_traits::vertex_descriptor& seq, SequenceCollectionHash::SymbolSetPair ext, int multiplicity, unsigned maxLength); template 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::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::vertex_descriptor& seq, const SequenceCollectionHash::SymbolSet& extension) { typedef SequenceCollectionHash Graph; typedef graph_traits::vertex_descriptor V; std::vector extSeqs; generateSequencesFromExtension(seq, group.getDirection(), extension, extSeqs); assert(extSeqs.size() > 1); for (std::vector::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::vertex_descriptor& seq, SequenceCollectionHash::SymbolSetPair ext, int multiplicity, unsigned maxLength) { typedef SequenceCollectionHash Graph; typedef graph_traits::vertex_descriptor V; typedef vertex_bundle_type::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 extKmer; generateSequencesFromExtension(seq, !dir, ext.dir[!dir], extKmer); assert(extKmer.size() > 1); for (std::vector::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 extKmer; generateSequencesFromExtension(seq, dir, ext.dir[dir], extKmer); assert(extKmer.size() > 1); BranchRecord original = branch; std::vector::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_good(out, opt::snpPath); } /** Collapse a bubble to a single path. */ template void collapseJoinedBranches(Graph* collection, BranchGroup& group) { typedef typename graph_traits::vertex_descriptor V; typedef typename vertex_bundle_type::type VP; typedef typename std::map 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 abyss-2.2.4/Assembly/CoverageAlgorithm.h000066400000000000000000000066551361462241400202110ustar00rootroot00000000000000#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 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; } } /** Remove all k-mers with multiplicity lower than the given threshold */ static inline size_t applyKmerCoverageThreshold(SequenceCollectionHash& c, unsigned kc) { if (kc == 0) return 0; for (SequenceCollectionHash::iterator it = c.begin(); it != c.end(); ++it) { if (it->second.getMultiplicity() < kc) it->second.setFlag(SF_DELETE); } return c.cleanup(); } } // namespace AssemblyAlgorithms #endif abyss-2.2.4/Assembly/DBG.h000066400000000000000000000524371361462241400152020ustar00rootroot00000000000000#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 #include #include #include #include #include #include #include #include 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 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) { // Initialize sparsehash size to 2^30 (~1 billion) empty buckets. // Setting the initial sparsehash size to a large // number avoids the prohibitively slow step of resizing // the hash table and rehashing *every* element when the // maximum load factor is exceeded. // // The initial memory footprint per CPU core is // 2^30 * 2.67 / 8 ~= 0.358 GB. The value of 2^30 buckets // was chosen to accomodate a k=144 32-thread assembly of human // (NA24143) uncorrected Illumina reads with ~70X coverage and // 20,317,980,431 distinct 144-mers, without requiring sparsehash // resizing. For further details on the test dataset, see: // "ABySS 2.0: Resource-efficient assembly of large genomes // using a Bloom filter". m_data.rehash((size_t)pow(2, 30)); 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 { // 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 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 { /** 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 { /** 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 { /** 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 { 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 } // namespace boost // IncidenceGraph static inline std::pair< graph_traits::out_edge_iterator, graph_traits::out_edge_iterator> out_edges( graph_traits::vertex_descriptor u, const SequenceCollectionHash& g) { typedef graph_traits 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::degree_size_type out_degree( graph_traits::vertex_descriptor u, const SequenceCollectionHash& g) { return g[u].getExtension(SENSE).outDegree(); } // BidirectionalGraph static inline std::pair< graph_traits::in_edge_iterator, graph_traits::in_edge_iterator> in_edges( graph_traits::vertex_descriptor u, const SequenceCollectionHash& g) { typedef graph_traits 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::degree_size_type in_degree(graph_traits::vertex_descriptor u, const SequenceCollectionHash& g) { return g[u].getExtension(ANTISENSE).outDegree(); } // AdjacencyGraph static inline std::pair::adjacency_iterator, graph_traits::adjacency_iterator> adjacent_vertices( graph_traits::vertex_descriptor u, const SequenceCollectionHash& g) { typedef graph_traits::adjacency_iterator adjacency_iterator; typedef graph_traits::SymbolSet SymbolSet; SymbolSet adj = g[u].getExtension(SENSE); return std::make_pair(adjacency_iterator(u, adj), adjacency_iterator()); } // VertexListGraph static inline std::pair::vertex_iterator, graph_traits::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::edge_descriptor> { typedef graph_traits 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 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::edge_iterator, graph_traits::edge_iterator> edges(const SequenceCollectionHash& g) { typedef graph_traits GTraits; typedef GTraits::vertex_iterator vertex_iterator; typedef GTraits::edge_iterator edge_iterator; std::pair 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::vertex_descriptor u, graph_traits::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::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::vertex_descriptor get(vertex_complement_t, const SequenceCollectionHash&, graph_traits::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::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::vertex_descriptor u) { return u.str(); } /** Return the properties of this vertex. */ static inline vertex_bundle_type::type get(vertex_bundle_t, const SequenceCollectionHash& g, graph_traits::vertex_descriptor u) { return g[u]; } /** Return the coverage of this vertex. */ static inline unsigned get(vertex_coverage_t, const SequenceCollectionHash& g, graph_traits::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::edge_descriptor) { return no_property(); } #endif abyss-2.2.4/Assembly/DotWriter.h000066400000000000000000000117431361462241400165240ustar00rootroot00000000000000#ifndef ASSEMBLY_DOTWRITER_H #define ASSEMBLY_DOTWRITER_H 1 /** Written by Shaun Jackman . */ #include "Common/UnorderedMap.h" #include "Graph/ContigGraphAlgorithms.h" #include #include #include class DotWriter { private: typedef SequenceCollectionHash Graph; typedef graph_traits::vertex_descriptor V; typedef graph_traits::vertex_iterator Vit; typedef graph_traits::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 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 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 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 Names; /** A map of terminal k-mers to contig names. */ Names m_names; /** The current contig name. */ unsigned m_id; }; #endif abyss-2.2.4/Assembly/ErodeAlgorithm.h000066400000000000000000000057261361462241400175120ustar00rootroot00000000000000#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 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 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 void removeExtensionsToSequence(Graph* seqCollection, const typename Graph::value_type& seq, extDirection dir) { typedef typename graph_traits::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 size_t erode(Graph* c, const typename Graph::value_type& seq) { typedef typename vertex_bundle_type::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 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 abyss-2.2.4/Assembly/LoadAlgorithm.h000066400000000000000000000114541361462241400173260ustar00rootroot00000000000000#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 size_t loadKmer(Graph& g, FastaReader& in) { typedef typename graph_traits::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 bool loadSequence(Graph* seqCollection, Sequence& seq) { typedef typename graph_traits::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 void loadSequences(Graph* seqCollection, std::string inFile) { typedef typename graph_traits::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 abyss-2.2.4/Assembly/Makefile.am000066400000000000000000000010231361462241400164520ustar00rootroot00000000000000noinst_LIBRARIES = libassembly.a libassembly_a_CPPFLAGS = -I$(top_srcdir) libassembly_a_SOURCES = \ 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 abyss-2.2.4/Assembly/Options.cc000066400000000000000000000246451361462241400163770ustar00rootroot00000000000000/** Written by Shaun Jackman . */ #include "config.h" #include "Common/Options.h" #include "DataLayer/Options.h" #include #include #include // for INT_MAX #include #include #include #include "DataBase/Options.h" #include #include using namespace std; #define PROGRAM "ABYSS" #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) namespace opt { static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Jared Simpson, Shaun Jackman and Anthony Raymond.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -o [OPTION]... FILE...\n" "Assemble the input files, FILE, which may be in FASTA, FASTQ,\n" "qseq, export, SAM or BAM format and compressed with gz, bz2 or xz.\n" "\n" " Options:\n" "\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" " [default]\n" " --no-trim-masked do not trim masked bases from the ends of\n" " reads\n" " -q, --trim-quality=N trim bases from the ends of reads whose\n" " quality is less than the threshold\n" " -Q, --mask-quality=N mask all low quality bases as `N'\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" " --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 the length of a k-mer (when -K is not set) [<=" STR(MAX_KMER) "]\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 blunt contigs to trim [k]\n" " -c, --coverage=FLOAT remove contigs with mean k-mer coverage\n" " less than this threshold\n" " --kc=N remove all k-mers with multiplicity < N [0]\n" " -b, --bubbles=N pop bubbles shorter than N bp [3*k]\n" " -b0, --no-bubbles do not pop bubbles\n" " -e, --erode=N erode bases at the ends of blunt contigs with coverage\n" " less than this threshold [round(sqrt(median))]\n" " -E, --erode-strand=N erode bases at the ends of blunt contigs\n" " with coverage less than this threshold on\n" " either strand [1 if sqrt(median) > 2 else 0]\n" " --coverage-hist=FILE write the k-mer coverage histogram to FILE\n" " -m, --mask-cov do not include kmers containing masked bases in\n" " coverage calculations [experimental]\n" " -s, --snp=FILE record popped bubbles in FILE\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" " ABYSS Options: (won't work with ABYSS-P)\n" "\n" " -g, --graph=FILE generate a graph in dot format\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; /** 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 /** k-mer range */ int kMin = -1; int kMax = -1; int kStep = 1; /** erosion coverage */ unsigned erode = (unsigned)-1; /** erosion strand coverage */ unsigned erodeStrand = (unsigned)-1; /** trim length */ int trimLen = -1; /** Coverage cutoff. */ float coverage = -1; /** Minimum k-mer multiplicity cutoff. */ unsigned kc = 0; /** Pop bubbles shorter than N bp. */ int bubbleLen = -1; /** Whether to run a strand-specific assembly. */ int ss = 0; /** * do not include kmers containing masked bases in * coverage calculations (experimental) */ bool maskCov = false; /** coverage histogram path */ string coverageHistPath; /** output contigs path */ string contigsPath; /** temporary output contigs path * Each node stores its contigs in its own file temporarily. */ string contigsTempPath; /** graph output */ string graphPath; /** output bubble path */ string snpPath; /** input FASTA files */ vector inFiles; string db; vector metaVars; /** commandline specific to assembly */ string assemblyCmd; 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, OPT_KC }; 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 }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "trim-quality", required_argument, NULL, 'q' }, { "standard-quality", no_argument, &opt::qualityOffset, 33 }, { "illumina-quality", no_argument, &opt::qualityOffset, 64 }, { "SS", no_argument, &opt::ss, 1 }, { "no-SS", no_argument, &opt::ss, 0 }, { "coverage", required_argument, NULL, 'c' }, { "kc", required_argument, NULL, OPT_KC }, { "coverage-hist", required_argument, NULL, COVERAGE_HIST }, { "bubble-length", required_argument, NULL, 'b' }, { "no-bubbles", no_argument, &opt::bubbleLen, 0 }, { "erode", required_argument, NULL, 'e' }, { "erode-strand", required_argument, NULL, 'E' }, { "no-erode", no_argument, (int*)&erode, 0 }, { "mask-cov", no_argument, NULL, 'm' }, { "graph", required_argument, NULL, 'g' }, { "snp", required_argument, NULL, 's' }, { "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 getMetaValue() { return opt::metaVars; } /** Parse the specified command line. */ void parse(int argc, char* const* argv) { ostringstream sargv; if (opt::rank <= 0) { char* const* last = argv + argc - 1; copy(argv, last, ostream_iterator(sargv, " ")); 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'b': arg >> bubbleLen; break; case 'c': arg >> coverage; break; case 'k': arg >> kmerSize; k = kmerSize; kMin = kmerSize; switch (arg.get()) { case ',': arg >> kMax; kStep = kMax - kMin; break; case '-': arg >> kMax; if (arg.get() == ':') arg >> kStep; break; default: kMax = kmerSize; } assert(kMin <= kMax); break; case 'K': arg >> singleKmerSize; break; case COVERAGE_HIST: getline(arg, coverageHistPath); break; case 'm': maskCov = true; break; case 'o': getline(arg, contigsPath); break; case 'e': arg >> erode; break; case 'E': arg >> erodeStrand; break; case 't': arg >> trimLen; break; case 'g': getline(arg, graphPath); break; case 'q': arg >> opt::qualityThreshold; break; case 'Q': arg >> opt::internalQThreshold; break; case 's': getline(arg, snpPath); break; case 'v': verbose++; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); 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; case OPT_KC: arg >> opt::kc; break; } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } 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; } if (contigsPath.empty()) { cerr << PROGRAM ": missing -o,--out option\n"; die = true; } if (argv[optind] == NULL) { cerr << PROGRAM ": missing input sequence file argument\n"; die = true; } if (die) { cerr << "Try `" PROGRAM " --help' for more information.\n"; exit(EXIT_FAILURE); } assert(opt::qualityThreshold <= 40); assert(opt::internalQThreshold <= 40); if (opt::rank <= 0 && opt::coverage >= 0 && opt::erode == (unsigned)-1) cerr << "warning: -c,--coverage was specified, " "but -e,--erode was not specified\n" "Previously, the default was -e2 (or --erode=2)." << endl; if (trimLen < 0) trimLen = kmerSize; if (bubbleLen < 0) bubbleLen = 3*kmerSize; assert(bubbleLen == 0 || bubbleLen > kmerSize); if (bubbleLen == 0) snpPath.clear(); inFiles.resize(argc - optind); copy(&argv[optind], &argv[argc], inFiles.begin()); if (rank >= 0) { ostringstream s; s << "contigs-" << opt::rank << ".fa"; contigsTempPath = s.str(); } if (opt::rank <= 0) cout << PACKAGE_STRING "\n" << sargv.str() << endl; } } // namespace opt abyss-2.2.4/Assembly/Options.h000066400000000000000000000015461361462241400162340ustar00rootroot00000000000000#ifndef ASSEMBLY_OPTIONS_H #define ASSEMBLY_OPTIONS_H 1 #include #include namespace opt { extern unsigned kmerSize; extern unsigned singleKmerSize; extern unsigned kMin; extern unsigned kMax; extern unsigned kStep; extern unsigned erode; extern unsigned erodeStrand; extern unsigned trimLen; extern float coverage; extern unsigned kc; extern unsigned bubbleLen; extern unsigned ss; extern bool maskCov; extern std::string coverageHistPath; extern std::string contigsPath; extern std::string contigsTempPath; extern std::string graphPath; extern std::string snpPath; extern std::vector inFiles; extern std::string db; void parse(int argc, char* const* argv); extern std::string assemblyCmd; std::vector getMetaValue(); int getVvalue(); std::string getUvalue(); std::string getCommand(); } #endif abyss-2.2.4/Assembly/SeqExt.h000066400000000000000000000050401361462241400160030ustar00rootroot00000000000000#ifndef SEQEXT_H #define SEQEXT_H 1 #include "Common/Options.h" // for opt::colourSpace #include "Common/Sequence.h" // for codeToBase #include #include #include 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< 0; } /** Return whether this kmer has more than one adjacent kmer. */ bool isAmbiguous() const { bool powerOfTwo = (m_record & (m_record - 1)) > 0; return m_record > 0 && powerOfTwo; } /** 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); for (unsigned i = 0; i << NUM; ++i) if (o.checkBase(i)) out << codeToBase(i); return out; } private: uint8_t m_record; }; #endif abyss-2.2.4/Assembly/SequenceCollection.h000066400000000000000000000011271361462241400203600ustar00rootroot00000000000000#ifndef ASSEMBLY_SEQUENCECOLLECTION_H #define ASSEMBLY_SEQUENCECOLLECTION_H 1 #include "config.h" #include "SeqExt.h" #include "VertexData.h" #include "Common/Kmer.h" typedef VertexData KmerData; typedef KmerData::SymbolSetPair ExtensionRecord; #if HAVE_GOOGLE_SPARSE_HASH_MAP # include typedef google::sparse_hash_map > SequenceDataHash; #else # include "Common/UnorderedMap.h" typedef unordered_map > SequenceDataHash; #endif #include "Assembly/DBG.h" #include "Assembly/BranchRecord.h" #endif abyss-2.2.4/Assembly/SplitAlgorithm.h000066400000000000000000000045611361462241400175430ustar00rootroot00000000000000#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 size_t markNeighbours(Graph* g, const typename Graph::value_type& u, extDirection sense) { typedef typename graph_traits::vertex_descriptor V; typedef typename std::vector 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 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 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 abyss-2.2.4/Assembly/TrimAlgorithm.h000066400000000000000000000126711361462241400173640ustar00rootroot00000000000000#ifndef ASSEMBLY_TRIMALGORITHM_H #define ASSEMBLY_TRIMALGORITHM_H 1 namespace AssemblyAlgorithms { template 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::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::vertex_descriptor& kmer, SequenceCollectionHash::SymbolSet ext) { typedef SequenceCollectionHash Graph; typedef graph_traits::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 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::vertex_descriptor& currSeq, SequenceCollectionHash::SymbolSetPair extensions, int multiplicity, unsigned maxLength, bool addKmer) { typedef SequenceCollectionHash Graph; typedef vertex_bundle_type::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 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 abyss-2.2.4/Assembly/VertexData.h000066400000000000000000000073111361462241400166440ustar00rootroot00000000000000#ifndef ASSEMBLY_VERTEXDATA_H #define ASSEMBLY_VERTEXDATA_H 1 #include "Common/Sense.h" #include #include #include enum SeqFlag { SF_MARK_SENSE = 0x1, SF_MARK_ANTISENSE = 0x2, SF_DELETE = 0x4, }; static inline SeqFlag complement(SeqFlag flag) { unsigned out = 0; if (flag & SF_MARK_SENSE) out |= SF_MARK_ANTISENSE; if (flag & SF_MARK_ANTISENSE) out |= SF_MARK_SENSE; if (flag & SF_DELETE) out |= SF_DELETE; return SeqFlag(out); } /** Vertex properties of a de Bruijn Graph vertex. */ template class VertexData { /** Maximum value of k-mer coverage. */ #define COVERAGE_MAX 32767U public: /** 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; } VertexData(extDirection dir, unsigned multiplicity) : m_flags(0) { assert(multiplicity <= COVERAGE_MAX); m_multiplicity[dir] = multiplicity; m_multiplicity[!dir] = 0; } VertexData(unsigned multiplicity, SymbolSetPair ext) : m_flags(0), m_ext(ext) { setMultiplicity(multiplicity); } unsigned getMultiplicity(extDirection dir) const { return m_multiplicity[dir]; } unsigned getMultiplicity() const { return m_multiplicity[SENSE] + m_multiplicity[ANTISENSE]; } void addMultiplicity(extDirection dir, unsigned n = 1) { m_multiplicity[dir] = std::min(m_multiplicity[dir] + n, COVERAGE_MAX); assert(m_multiplicity[dir] > 0); } /** Set the multiplicity (not strand specific). */ void setMultiplicity(unsigned multiplicity) { assert(multiplicity <= 2*COVERAGE_MAX); // Split the multiplicity over both senses. m_multiplicity[SENSE] = (multiplicity + 1) / 2; m_multiplicity[ANTISENSE] = multiplicity / 2; assert(getMultiplicity() == multiplicity); } void setFlag(SeqFlag flag) { m_flags |= flag; } bool isFlagSet(SeqFlag flag) const { return m_flags & flag; } void clearFlag(SeqFlag flag) { m_flags &= ~flag; } /** Return true if the specified sequence is deleted. */ bool deleted() const { return isFlagSet(SF_DELETE); } /** Return true if the specified sequence is marked. */ bool marked(extDirection sense) const { return isFlagSet(sense == SENSE ? SF_MARK_SENSE : SF_MARK_ANTISENSE); } /** Return true if the specified sequence is marked. */ bool marked() const { return isFlagSet(SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE)); } SymbolSetPair extension() const { return m_ext; } SymbolSet getExtension(extDirection dir) const { return m_ext.dir[dir]; } void setBaseExtension(extDirection dir, Symbol x) { m_ext.dir[dir].setBase(x); } void removeExtension(extDirection dir, SymbolSet ext) { m_ext.dir[dir].clear(ext); } bool hasExtension(extDirection dir) const { return m_ext.dir[dir].hasExtension(); } bool isAmbiguous(extDirection dir) const { return m_ext.dir[dir].isAmbiguous(); } /** Return the complement of this data. */ VertexData operator~() const { 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.complement(); return o; } friend std::ostream& operator<<( std::ostream& out, const VertexData& o) { return out << "C=" << o.m_multiplicity[0] + o.m_multiplicity[1]; } private: uint8_t m_flags; uint16_t m_multiplicity[2]; SymbolSetPair m_ext; }; #endif abyss-2.2.4/Bloom/000077500000000000000000000000001361462241400137135ustar00rootroot00000000000000abyss-2.2.4/Bloom/Bloom.h000066400000000000000000000113321361462241400151340ustar00rootroot00000000000000/* * Bloom.h * * This class was created when we removed the virtual class * BloomFilterBase. * * It contains a mix of components from BloomFilterBase as well as * additional functions and properties shared between Bloom Filter * classes. * * Contains useful algorithms for bloom filter calculations * * Created on: May 28, 2014 * Author: cjustin */ #ifndef BLOOM_H_ #define BLOOM_H_ #include "Common/Kmer.h" #include "Common/HashFunction.h" #include "Common/Uncompress.h" #include "Common/IOUtil.h" #include "DataLayer/FastaReader.h" #include #include #if _OPENMP # include #endif namespace Bloom { typedef Kmer key_type; /** Header section of serialized bloom filters. */ struct FileHeader { unsigned bloomVersion; unsigned k; size_t fullBloomSize; size_t startBitPos; size_t endBitPos; size_t hashSeed; }; /** 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 = 5; /** Return the hash value of this object. */ inline static size_t hash(const key_type& key) { if (key.isCanonical()) return hashmem(&key, key.bytes()); key_type copy(key); copy.reverseComplement(); return hashmem(©, copy.bytes(), 0); } /** Return the hash value of this object given seed. */ inline static size_t hash(const key_type& key, size_t seed) { if (key.isCanonical()) return hashmem(&key, key.bytes(), seed); key_type copy(key); copy.reverseComplement(); return hashmem(©, copy.bytes(), seed); } template inline static void loadSeq(BF& bloomFilter, unsigned k, const std::string& seq); /** Load a sequence file into a bloom filter */ template inline static void loadFile(BF& bloomFilter, unsigned k, const std::string& path, 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; #pragma omp parallel for (std::vector buffer(taskIOBufferSize);;) { buffer.clear(); size_t bufferSize = 0; bool good = true; #pragma omp critical(in) 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 < buffer.size(); j++) { loadSeq(bloomFilter, k, buffer.at(j)); if (verbose) #pragma omp critical(cerr) { count++; if (count % LOAD_PROGRESS_STEP == 0) std::cerr << "Loaded " << count << " reads into bloom filter\n"; } } } assert(in.eof()); if (verbose) { std::cerr << "Loaded " << count << " reads from `" << path << "` into bloom filter\n"; } } /** Load a sequence (string) into a bloom filter */ template inline static void loadSeq(BF& bloomFilter, unsigned k, const std::string& seq) { if (seq.size() < k) return; for (size_t i = 0; i < seq.size() - k + 1; ++i) { std::string kmer = seq.substr(i, k); size_t pos = kmer.find_last_not_of("ACGTacgt"); if (pos == std::string::npos) { bloomFilter.insert(Kmer(kmer)); } else i += pos; } } inline static void writeHeader(std::ostream& out, const FileHeader& header) { (void)writeHeader; out << BLOOM_VERSION << '\n'; out << Kmer::length() << '\n'; out << header.fullBloomSize << '\t' << header.startBitPos << '\t' << header.endBitPos << '\n'; out << header.hashSeed << '\n'; assert(out); } FileHeader readHeader(std::istream& in) { FileHeader header; // read bloom filter file format version in >> header.bloomVersion >> expect("\n"); assert(in); if (header.bloomVersion != BLOOM_VERSION) { std::cerr << "error: bloom filter version (`" << header.bloomVersion << "'), does not match version required " "by this program (`" << BLOOM_VERSION << "').\n"; exit(EXIT_FAILURE); } // read bloom filter k value in >> header.k >> expect("\n"); assert(in); if (header.k != Kmer::length()) { std::cerr << "error: this program must be run with the same kmer " "size as the bloom filter being loaded (k=" << header.k << ").\n"; exit(EXIT_FAILURE); } // read bloom filter dimensions in >> header.fullBloomSize >> expect("\t") >> header.startBitPos >> expect("\t") >> header.endBitPos >> expect("\n"); in >> header.hashSeed >> expect("\n"); assert(in); assert(header.startBitPos < header.fullBloomSize); assert(header.endBitPos < header.fullBloomSize); assert(header.startBitPos <= header.endBitPos); return header; } }; #endif /* BLOOM_H_ */ abyss-2.2.4/Bloom/BloomFilter.h000066400000000000000000000075241361462241400163120ustar00rootroot00000000000000/** * A Bloom filter * Copyright 2013 Shaun Jackman */ #ifndef BLOOMFILTER_H #define BLOOMFILTER_H 1 #include "Bloom/Bloom.h" #include "Common/Kmer.h" #include "Common/IOUtil.h" #include "Common/BitUtil.h" #include #include #include #include /* * Put `BloomFilter` class in `Konnector` namespace to avoid collision with BTL * `BloomFilter` class of the same name. */ namespace Konnector { /** A Bloom filter. */ class BloomFilter { public: /** Constructor. */ BloomFilter() : m_size(0), m_hashSeed(0), m_array(NULL) { } /** Constructor. */ BloomFilter(size_t n, size_t hashSeed=0) : m_size(n), m_hashSeed(hashSeed) { m_array = new char[(n + 7)/8](); } ~BloomFilter() { delete[] m_array; } /** Return the size of the bit array. */ size_t size() const { return m_size; } /** Return the population count, i.e. the number of set bits. */ size_t popcount() const { 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(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 */ double FPR() const { return (double)popcount() / size(); } /** Return whether the specified bit is set. */ bool operator[](size_t i) const { 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 (*this)[Bloom::hash(key, m_hashSeed) % m_size]; } /** Add the object with the specified index to this set. */ void insert(size_t i) { 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) { insert(Bloom::hash(key, m_hashSeed) % m_size); } /** Operator for reading a bloom filter from a stream. */ friend std::istream& operator>>(std::istream& in, BloomFilter& o) { o.read(in, BITWISE_OVERWRITE); return in; } /** Operator for writing the bloom filter to a stream. */ friend std::ostream& operator<<(std::ostream& out, const BloomFilter& o) { o.write(out); return out; } /** Read a bloom filter from a stream. */ void read(std::istream& in, BitwiseOp readOp = BITWISE_OVERWRITE) { Bloom::FileHeader header = Bloom::readHeader(in); assert(in); if (m_hashSeed != header.hashSeed) { if (readOp == BITWISE_OVERWRITE) { m_hashSeed = header.hashSeed; } else { std::cerr << "error: can't union/intersect bloom filters with " << "different hash seeds\n"; exit(EXIT_FAILURE); } } 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::FileHeader header; header.fullBloomSize = m_size; header.startBitPos = 0; header.endBitPos = m_size - 1; header.hashSeed = m_hashSeed; 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: size_t m_size; size_t m_hashSeed; char* m_array; }; } // end Konnector namespace #endif abyss-2.2.4/Bloom/BloomFilterWindow.h000066400000000000000000000103361361462241400174750ustar00rootroot00000000000000#ifndef BLOOMFILTERWINDOW_H #define BLOOMFILTERWINDOW_H 1 #include "Bloom.h" #include "BloomFilter.h" #include "Common/HashFunction.h" #include "Common/Kmer.h" #include "Common/IOUtil.h" #include #include #include /** * A bloom filter that represents a window * within a larger bloom filter. */ class BloomFilterWindow : public Konnector::BloomFilter { public: /** Constructor. */ BloomFilterWindow() : Konnector::BloomFilter() { }; /** Constructor. * * @param fullBloomSize size in bits of the containing bloom filter * @param startBitPos index of first bit in the window * @param endBitPos index of last bit in the window */ BloomFilterWindow(size_t fullBloomSize, size_t startBitPos, size_t endBitPos, size_t hashSeed=0) : Konnector::BloomFilter(endBitPos - startBitPos + 1, hashSeed), m_fullBloomSize(fullBloomSize), m_startBitPos(startBitPos), m_endBitPos(endBitPos) { assert(startBitPos < fullBloomSize); assert(endBitPos < fullBloomSize); assert(startBitPos <= endBitPos); } /** * Get the full size (in bits) of the bloom filter that * this window is a part of. */ size_t fullBloomSize() { return m_fullBloomSize; } /** Get the start bit position for the window. */ size_t startBitPos() { return m_startBitPos; } /** Get the end bit position for the window. */ size_t endBitPos() { return m_endBitPos; } /** Return the size of the bit array. */ size_t size() const { return Konnector::BloomFilter::size(); } /** Return the number of elements with count >= max_count. */ size_t popcount() const { return Konnector::BloomFilter::popcount(); } /** Return the estimated false positive rate */ double FPR() const { return Konnector::BloomFilter::FPR(); } /** Return whether the specified bit is set. */ bool operator[](size_t i) const { if (i >= m_startBitPos && i <= m_endBitPos) return Konnector::BloomFilter::operator[](i - m_startBitPos); return false; } /** Return whether the object is present in this set. */ bool operator[](const Bloom::key_type& key) const { return (*this)[Bloom::hash(key, m_hashSeed) % m_fullBloomSize]; } /** Add the object with the specified index to this set. */ void insert(size_t i) { if (i >= m_startBitPos && i <= m_endBitPos) Konnector::BloomFilter::insert(i - m_startBitPos); } /** Add the object to this set. */ void insert(const Bloom::key_type& key) { insert(Bloom::hash(key, m_hashSeed) % m_fullBloomSize); } /** Operator for reading a bloom filter from a stream. */ friend std::istream& operator>>(std::istream& in, BloomFilterWindow& o) { o.read(in, BITWISE_OVERWRITE); return in; } /** Operator for writing the bloom filter to a stream. */ friend std::ostream& operator<<(std::ostream& out, const BloomFilterWindow& o) { o.write(out); return out; } /** Read a bloom filter window from a stream. */ 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; if (m_hashSeed != header.hashSeed) { if (readOp == BITWISE_OVERWRITE) { m_hashSeed = header.hashSeed; } else { std::cerr << "error: can't union/intersect bloom filters with " << "different hash seed values\n"; exit(EXIT_FAILURE); } } size_t bits = header.endBitPos - header.startBitPos + 1; if (m_size != bits) { if (readOp == BITWISE_OVERWRITE) { Konnector::BloomFilter::resize(bits); } else { std::cerr << "error: can't union/intersect bloom filters with " << "different sizes\n"; exit(EXIT_FAILURE); } } readBits(in, m_array, bits, 0, readOp); assert(in); } /** Write a bloom filter window to a stream. */ void write(std::ostream& out) const { Bloom::FileHeader header; header.fullBloomSize = m_fullBloomSize; header.startBitPos = m_startBitPos; header.endBitPos = m_endBitPos; header.hashSeed = m_hashSeed; Bloom::writeHeader(out, header); assert(out); size_t windowSize = m_endBitPos - m_startBitPos + 1; out.write(m_array, (windowSize + 7)/8); assert(out); } private: size_t m_fullBloomSize; size_t m_startBitPos, m_endBitPos; }; #endif abyss-2.2.4/Bloom/CascadingBloomFilter.h000066400000000000000000000051041361462241400200770ustar00rootroot00000000000000/** * A cascading Bloom filter * Copyright 2013 Shaun Jackman */ #ifndef CascadingBLOOMFILTER_H #define CascadingBLOOMFILTER_H 1 #include "Bloom/Bloom.h" #include "BloomFilter.h" #include /** A Cascading Bloom filter. */ class CascadingBloomFilter { public: /** Constructor */ CascadingBloomFilter() {} /** Constructor */ CascadingBloomFilter(size_t n, size_t max_count, size_t hashSeed=0) : m_hashSeed(hashSeed) { m_data.reserve(max_count); for (unsigned i = 0; i < max_count; i++) m_data.push_back(new Konnector::BloomFilter(n, hashSeed)); } /** Destructor */ ~CascadingBloomFilter() { typedef std::vector::iterator Iterator; for (Iterator i = m_data.begin(); i != m_data.end(); i++) { assert(*i != NULL); delete *i; } } /** Return the size of the bit array. */ size_t size() const { assert(m_data.back() != NULL); return m_data.back()->size(); } /** Return the number of elements with count >= max_count. */ size_t popcount() const { assert(m_data.back() != NULL); return m_data.back()->popcount(); } /** Return the estimated false positive rate */ double FPR() const { return (double)popcount() / size(); } /** Return whether the element with this index has count >= * max_count. */ bool operator[](size_t i) const { assert(m_data.back() != NULL); return (*m_data.back())[i]; } /** Return whether this element has count >= max_count. */ bool operator[](const Bloom::key_type& key) const { assert(m_data.back() != NULL); return (*m_data.back())[Bloom::hash(key, m_hashSeed) % m_data.back()->size()]; } /** Add the object with the specified index to this multiset. */ void insert(size_t index) { 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); break; } } } /** Add the object to this Cascading multiset. */ void insert(const Bloom::key_type& key) { assert(m_data.back() != NULL); insert(Bloom::hash(key, m_hashSeed) % m_data.back()->size()); } /** Get the Bloom filter for a given level */ Konnector::BloomFilter& getBloomFilter(unsigned level) { assert(m_data.at(level) != NULL); return *m_data.at(level); } void write(std::ostream& out) const { assert(m_data.back() != NULL); out << *m_data.back(); } /** Operator for writing the bloom filter to a stream */ friend std::ostream& operator<<(std::ostream& out, const CascadingBloomFilter& o) { o.write(out); return out; } private: size_t m_hashSeed; std::vector m_data; }; #endif abyss-2.2.4/Bloom/CascadingBloomFilterWindow.h000066400000000000000000000044211361462241400212700ustar00rootroot00000000000000#ifndef COUNTINGBLOOMFILTERWINDOW_H #define COUNTINGBLOOMFILTERWINDOW_H 1 #include "Bloom.h" #include "BloomFilter.h" #include "CascadingBloomFilter.h" #include class CascadingBloomFilterWindow : private CascadingBloomFilter { public: /** Constructor. * * @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, unsigned max_count, size_t hashSeed=0) : m_fullBloomSize(fullBloomSize), m_hashSeed(hashSeed) { m_data.reserve(max_count); for (unsigned i = 0; i < max_count; i++) m_data.push_back(new BloomFilterWindow(fullBloomSize, startBitPos, endBitPos, hashSeed)); } /** Return the size of the bit array. */ size_t size() const { assert(m_data.back() != NULL); return m_data.back()->size(); } /** Return the number of elements with count >= max_count. */ size_t popcount() const { assert(m_data.back() != NULL); return m_data.back()->popcount(); } /** Return the estimated false positive rate */ double FPR() const { return (double)popcount() / size(); } /** Add the object with the specified index to this multiset. */ void insert(size_t index) { 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); break; } } } /** Add the object to this counting multiset. */ void insert(const Bloom::key_type& key) { assert(m_data.back() != NULL); insert(Bloom::hash(key, m_hashSeed) % m_fullBloomSize); } void write(std::ostream& out) const { assert(m_data.back() != NULL); out << *m_data.back(); } /** Operator for writing the bloom filter to a stream */ friend std::ostream& operator<<(std::ostream& out, const CascadingBloomFilterWindow& o) { o.write(out); return out; } /** Get the Bloom filter for a given level */ BloomFilterWindow& getBloomFilter(unsigned level) { assert(m_data.at(level) != NULL); return *m_data.at(level); } private: size_t m_fullBloomSize; size_t m_hashSeed; std::vector m_data; }; #endif abyss-2.2.4/Bloom/ConcurrentBloomFilter.h000066400000000000000000000042451361462241400203520ustar00rootroot00000000000000#ifndef CONCURRENTBLOOMFILTER_H #define CONCURRENTBLOOMFILTER_H #ifndef _OPENMP # error ConcurrentBloomFilter class requires a compiler that supports OpenMP #endif #include "config.h" #include #include /** * A wrapper class that makes a Bloom filter * thread-safe. */ template class ConcurrentBloomFilter { public: /** Constructor */ ConcurrentBloomFilter(BloomFilterType& bloom, size_t numLocks, size_t hashSeed=0) : m_bloom(bloom), m_locks(numLocks), m_hashSeed(hashSeed) { m_windowSize = bloom.size() / numLocks; // round down to the nearest byte boundary, // because bytes that span locks will // cause concurrency issues m_windowSize -= m_windowSize % 8; assert(numLocks < bloom.size()); for (size_t i = 0; i < m_locks.size(); i++) omp_init_lock(&(m_locks.at(i))); } /** Destructor */ ~ConcurrentBloomFilter() { for (size_t i = 0; i < m_locks.size(); i++) omp_destroy_lock(&(m_locks.at(i))); } /** Return whether the specified bit is set. */ bool operator[](size_t i) const { assert(i < m_bloom.size()); bool bit; getLock(i); bit = m_bloom[i]; releaseLock(i); return bit; } /** Return whether the object is present in this set. */ bool operator[](const Bloom::key_type& key) const { return *this[Bloom::hash(key, m_hashSeed) % m_bloom.size()]; } /** Add the object with the specified index to this set. */ void insert(size_t index) { assert(index < m_bloom.size()); getLock(index); m_bloom.insert(index); releaseLock(index); } /** Add the object to this set. */ void insert(const Bloom::key_type& key) { insert(Bloom::hash(key, m_hashSeed) % m_bloom.size()); } private: void getLock(size_t bitIndex) { assert(bitIndex < m_bloom.size()); size_t lockIndex = std::min(bitIndex / m_windowSize, m_locks.size() - 1); omp_set_lock(&(m_locks.at(lockIndex))); } void releaseLock(size_t bitIndex) { assert(bitIndex < m_bloom.size()); size_t lockIndex = std::min(bitIndex / m_windowSize, m_locks.size() - 1); omp_unset_lock(&(m_locks.at(lockIndex))); } BloomFilterType& m_bloom; std::vector m_locks; size_t m_hashSeed; size_t m_windowSize; }; #endif abyss-2.2.4/Bloom/HashAgnosticCascadingBloom.h000066400000000000000000000112571361462241400212330ustar00rootroot00000000000000/** * A cascading Bloom filter * Copyright 2015 Shaun Jackman, Ben Vandervalk. */ #ifndef HASH_AGNOSTIC_CASCADING_BLOOM_H #define HASH_AGNOSTIC_CASCADING_BLOOM_H 1 #include "vendor/btl_bloomfilter/BloomFilter.hpp" #include /** * An implementation of a Cascading Bloom filter. * A Cascading Bloom filter implements a crude * counting mechanism using an array of _l_ Bloom * filters; we say that such a Bloom filter has * l _levels_. Each time an element is inserted, we * check for its presence in each level, and then * insert the element into the first Bloom filter * where the element is not already present. * * We use the Cascading Bloom filter to filter * out error k-mers from the de Bruijn graph, since * these k-mers typically only occur once in the * the data. */ class HashAgnosticCascadingBloom { public: typedef uint64_t hash_t; /** Default constructor */ HashAgnosticCascadingBloom() : m_k(0) , m_hashes(0) {} /** * Constructor. * @param size size of the Bloom filters (in bits) * @param hashes number of hash functions * @param levels number of levels in Cascading Bloom filter * @param k k-mer size */ HashAgnosticCascadingBloom(size_t size, unsigned hashes, size_t levels, unsigned k) : m_k(k) , m_hashes(hashes) { m_data.reserve(levels); for (unsigned i = 0; i < levels; i++) m_data.push_back(new BloomFilter(size, hashes, k)); } /** * Constructor to load a single-level BloomFilter from * files. This is used to make BloomFilter support the * same interface as HashAgnosticCascadingBloom. */ HashAgnosticCascadingBloom(const string& bloomPath) { loadFilter(bloomPath); } /** Destructor */ ~HashAgnosticCascadingBloom() { clear(); } /** Return k-mer size used by Bloom filter. */ unsigned getKmerSize() const { return m_k; } /** Return number of hash functions used by Bloom filter */ unsigned getHashNum() const { return m_hashes; } /** Return the size of the bit array. */ size_t size() const { assert(m_data.back() != NULL); return m_data.back()->getFilterSize(); } /** Return the size of the bit array. */ size_t getFilterSize() const { return size(); } /** Return the number of elements with count >= levels. */ size_t popcount() const { assert(m_data.back() != NULL); return m_data.back()->getPop(); } /** Return number of levels in cascading Bloom filter */ unsigned levels() const { return m_data.size(); } /** Return the estimated false positive rate */ double FPR() const { return pow((double)popcount() / size(), m_hashes); } /** * Return true if the element with the given hash values * has count >= levels. */ bool contains(const std::vector& hashes) const { assert(m_data.back() != NULL); return m_data.back()->contains(hashes); } /** * Return true if the element with the given hash values * has count >= levels. */ bool contains(const hash_t hashes[]) const { assert(m_data.back() != NULL); return m_data.back()->contains(hashes); } /** Add the object with the specified index to this multiset. */ void insert(const std::vector& hashes) { for (unsigned i = 0; i < m_data.size(); ++i) { assert(m_data.at(i) != NULL); if (!(*m_data[i]).contains(hashes)) { m_data[i]->insert(hashes); break; } } } /** Add the object with the specified index to this multiset. */ void insert(const hash_t hashes[]) { for (unsigned i = 0; i < m_data.size(); ++i) { assert(m_data.at(i) != NULL); if (!(*m_data[i]).contains(hashes)) { m_data[i]->insert(hashes); break; } } } /** Get the Bloom filter for a given level */ BloomFilter& getBloomFilter(unsigned level) { assert(m_data.at(level) != NULL); return *m_data.at(level); } /** Operator for writing the Bloom filter to a stream */ friend std::ostream& operator<<(std::ostream& out, const HashAgnosticCascadingBloom& o) { assert(o.m_data.size() > 0); assert(o.m_data.back() != NULL); /* o.m_data.back()->storeFilter(out); */ out << *o.m_data.back(); return out; } /** Load a Bloom filter from a file */ void loadFilter(const string& bloomPath) { clear(); BloomFilter* bloom = new BloomFilter(bloomPath); m_k = bloom->getKmerSize(); m_hashes = bloom->getHashNum(); m_data.push_back(bloom); } private: /** Free all allocated memory and reset parameters to defaults */ void clear() { m_k = 0; m_hashes = 0; typedef std::vector::iterator Iterator; for (Iterator i = m_data.begin(); i != m_data.end(); i++) { assert(*i != NULL); delete *i; } m_data.clear(); } /** k-mer length */ unsigned m_k; /** number of hash functions */ unsigned m_hashes; /** the array of Bloom filters */ std::vector m_data; }; #endif abyss-2.2.4/Bloom/Makefile.am000066400000000000000000000010751361462241400157520ustar00rootroot00000000000000bin_PROGRAMS = abyss-bloom abyss_bloom_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -I$(top_srcdir)/vendor abyss_bloom_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_bloom_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Align/libalign.a \ $(top_builddir)/Common/libcommon.a abyss_bloom_SOURCES = bloom.cc \ Bloom.h \ BloomFilter.h \ BloomFilterWindow.h \ ConcurrentBloomFilter.h \ CascadingBloomFilter.h \ CascadingBloomFilterWindow.h \ RollingBloomDBGVisitor.h \ HashAgnosticCascadingBloom.h abyss-2.2.4/Bloom/RollingBloomDBGVisitor.h000066400000000000000000000112521361462241400203610ustar00rootroot00000000000000#ifndef _ROLLING_BLOOM_DBG_VISITOR_H_ #define _ROLLING_BLOOM_DBG_VISITOR_H_ 1 #include "Common/UnorderedMap.h" #include "Common/UnorderedSet.h" #include "Graph/BreadthFirstSearch.h" #include "vendor/btl_bloomfilter/BloomFilter.hpp" #include /** * Visitor class that outputs visited nodes/edges in GraphViz format during * a bounded breadth first traversal. An instance of this class may be passed * as an argument to the `breadthFirstSearch` function. */ template class RollingBloomDBGVisitor : public DefaultBFSVisitor { public: typedef typename boost::graph_traits::vertex_descriptor VertexT; typedef typename boost::graph_traits::edge_descriptor EdgeT; typedef unordered_map DepthMap; typedef typename DepthMap::const_iterator DepthMapConstIt; typedef typename DepthMap::iterator DepthMapIt; typedef std::vector>> KmerProperties; typedef typename KmerProperties::const_iterator KmerPropertiesIt; typedef std::vector> BloomProperties; typedef typename BloomProperties::const_iterator BloomPropertiesIt; typedef uint64_t hash_t; /** Constructor */ template RollingBloomDBGVisitor( const VertexSetT& roots, unsigned maxDepth, const KmerProperties& kmerProperties, const BloomProperties& bloomProperties, std::ostream& out) : m_maxDepth(maxDepth) , m_kmerProperties(kmerProperties) , m_bloomProperties(bloomProperties) , m_out(out) { typedef typename VertexSetT::const_iterator RootIt; for (RootIt it = roots.begin(); it != roots.end(); ++it) m_depthMap[*it] = 0; /* start directed graph (GraphViz) */ m_out << "digraph " << " {\n"; } /** Called when graph search completes */ void post_processing() { /* end directed graph (GraphViz) */ m_out << "}\n"; } /** Invoked on edges that lead to an undiscovered vertex */ BFSVisitorResult tree_edge(const EdgeT& e, const GraphT& g) { VertexT parent = source(e, g); VertexT child = target(e, g); if (!isForwardEdge(e, g)) std::swap(parent, child); DepthMapConstIt parentIt = m_depthMap.find(parent); assert(parentIt != m_depthMap.end()); unsigned parentDepth = parentIt->second; if (parentDepth >= m_maxDepth) return BFS_SKIP_ELEMENT; DepthMapIt childIt; bool inserted; boost::tie(childIt, inserted) = m_depthMap.insert(std::make_pair(child, parentDepth + 1)); assert(inserted); /* * since we use this visitor class with an undirected BFS, * each edge is traversed twice (once forward, once reverse) */ if (isForwardEdge(e, g)) outputEdge(e, g); return BFS_SUCCESS; } /** Invoked when a vertex is visited for the first time */ BFSVisitorResult discover_vertex(const VertexT& v, const GraphT&) { /* declare vertex (GraphViz) */ m_out << '\t' << v.kmer().c_str(); m_out << " ["; DepthMapConstIt depthIt = m_depthMap.find(v); assert(depthIt != m_depthMap.end()); unsigned depth = depthIt->second; m_out << "depth=" << depth; for (KmerPropertiesIt it = m_kmerProperties.begin(); it != m_kmerProperties.end(); ++it) { if (it->second.find(v) != it->second.end()) m_out << "," << it->first; } hash_t hashes[MAX_HASHES]; v.rollingHash().getHashes(hashes); for (BloomPropertiesIt it = m_bloomProperties.begin(); it != m_bloomProperties.end(); ++it) { if (it->second->contains(hashes)) m_out << "," << it->first; } m_out << "];\n"; return BFS_SUCCESS; } /** * Invoked when an edge is traversed. (Each edge * in the graph is traversed exactly once.) */ BFSVisitorResult non_tree_edge(const EdgeT& e, const GraphT& g) { /* * since we use this visitor class with an undirected BFS, * each edge is traversed twice (once forward, once reverse) */ if (isForwardEdge(e, g)) outputEdge(e, g); return BFS_SUCCESS; } BFSVisitorResult examine_vertex(const VertexT& v, const GraphT&) { m_currentVertex = v; return BFS_SUCCESS; } /** Return if the current edge is a forward edge */ bool isForwardEdge(const EdgeT& e, const GraphT& g) { assert(source(e, g) == m_currentVertex || target(e, g) == m_currentVertex); return source(e, g) == m_currentVertex; } /** Output and edge */ void outputEdge(const EdgeT& e, const GraphT& g) { const VertexT& u = source(e, g); const VertexT& v = target(e, g); /* declare edge (GraphViz) */ m_out << '\t' << u.kmer().c_str() << " -> " << v.kmer().c_str() << ";\n"; } protected: VertexT m_currentVertex; DepthMap m_depthMap; const unsigned m_maxDepth; const KmerProperties& m_kmerProperties; const BloomProperties& m_bloomProperties; std::ostream& m_out; }; #endif abyss-2.2.4/Bloom/bloom.cc000066400000000000000000001175051361462241400153430ustar00rootroot00000000000000/** * Build and manipulate bloom filter files. */ #include "Bloom/Bloom.h" #include "Bloom/BloomFilter.h" #include "Bloom/BloomFilterWindow.h" #include "Bloom/CascadingBloomFilter.h" #include "Bloom/CascadingBloomFilterWindow.h" #include "Bloom/HashAgnosticCascadingBloom.h" #include "Bloom/RollingBloomDBGVisitor.h" #include "BloomDBG/BloomIO.h" #include "BloomDBG/RollingBloomDBG.h" #include "BloomDBG/RollingHashIterator.h" #include "Common/BitUtil.h" #include "Common/Kmer.h" #include "Common/KmerIterator.h" #include "Common/Options.h" #include "Common/StringUtil.h" #include "Common/UnorderedSet.h" #include "DataLayer/FastaConcat.h" #include "DataLayer/FastaReader.h" #include "DataLayer/Options.h" #include "Graph/ExtendPath.h" #include "Graph/Path.h" #include "Konnector/DBGBloom.h" #include "config.h" #include "vendor/btl_bloomfilter/BloomFilter.hpp" #include "vendor/btl_bloomfilter/CountingBloomFilter.hpp" #include #include #include #include #include #include #if _OPENMP #include "Bloom/ConcurrentBloomFilter.h" #include #endif using namespace std; #define PROGRAM "abyss-bloom" #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman, Hamid Mohamadi, Anthony Raymond and\n" "Ben Vandervalk.\n" "\n" "Copyright 2013 Canada's Michael Smith Genome Science Centre\n"; static const char USAGE_MESSAGE[] = "Usage 1: " PROGRAM " build [GLOBAL_OPTS] [COMMAND_OPTS] [READS_FILE_2]...\n" "Usage 2: " PROGRAM " union [GLOBAL_OPTS] [COMMAND_OPTS] " " [BLOOM_FILE_3]...\n" "Usage 3: " PROGRAM " intersect [GLOBAL_OPTS] [COMMAND_OPTS] " " [BLOOM_FILE_3]...\n" "Usage 4: " PROGRAM " info [GLOBAL_OPTS] [COMMAND_OPTS] \n" "Usage 5: " PROGRAM " compare [GLOBAL_OPTS] [COMMAND_OPTS] \n" "Usage 6: " PROGRAM " graph [GLOBAL_OPTS] [COMMAND_OPTS] \n" "Usage 8: " PROGRAM " kmers [GLOBAL_OPTS] [COMMAND_OPTS] \n" "Usage 9: " PROGRAM " trim [GLOBAL_OPTS] [COMMAND_OPTS] [READS_FILE_2]... > trimmed.fq\n" "\n" "Build and manipulate Bloom filter files.\n" "\n" " Global options:\n" "\n" " -k, --kmer=N the size of a k-mer [<=" STR( MAX_KMER) "]\n" " -v, --verbose display verbose output\n" " --help display this help and exit\n" " --version output version information and exit\n" "\n" " 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" " -h, --hash-seed=N seed for hash function (only works with\n" " `-t konnector') [0]\n" " -H, --num-hashes=N number of hash functions (only works with\n" " `-t rolling-hash') [1]\n" " -l, --levels=N build a cascading bloom filter with N levels\n" " and output the last level\n" " -L, --init-level='N=FILE' initialize level N of cascading bloom filter\n" " from FILE\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" " -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" " -t, --bloom-type=STR 'konnector', 'rolling-hash', or 'counting' [konnector]\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" " -w, --window M/N build a bloom filter for subwindow M of N\n" "\n" " Options for `" PROGRAM " union': (none)\n" " Options for `" PROGRAM " intersect': (none)\n" " Options for `" PROGRAM " info': (none)\n" " Options for `" PROGRAM " compare':\n" "\n" " -m, --method=`String' choose distance calculation method \n" " [`jaccard'(default), `forbes', `czekanowski']\n" "\n" " Options for `" PROGRAM " graph':\n" "\n" " -d, --depth=N depth of neighbouring from --root [k]\n" " -R, --root=KMER root k-mer from graph traversal [required]\n" " -f, --root-fasta=FILE get root k-mers from FASTA file\n" " -a, --fasta-attr=STR:FILE, assign a node attribute (e.g. 'color=blue')\n" " --node-attr=STR:FILE to k-mers in the given FASTA\n" " -A, --bloom-attr=STR:FILE assign a node attribute (e.g. 'color=blue')\n" " to k-mers in the given Bloom filter\n" "\n" " Options for `" PROGRAM " kmers':\n" "\n" " -r, --inverse get k-mers that are *NOT* in the bloom filter\n" " --bed output k-mers in BED format\n" " --fasta output k-mers in FASTA format [default]\n" " --raw output k-mers in raw format (one per line)\n" "\n" " Options for `" PROGRAM " trim': (none)\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; ; enum BloomFilterType { BT_KONNECTOR, BT_ROLLING_HASH, BT_COUNTING, BT_UNKNOWN }; enum OutputFormat { BED, FASTA, RAW }; /* types related to --fasta-attr/--bloom-attr options */ typedef string KmerProperty; typedef string FilePath; typedef vector> KmerProperties; typedef KmerProperties::iterator KmerPropertiesIt; 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; /** Depth of graph traversal */ size_t depth = 0; /** The number of parallel threads. */ unsigned threads = 1; /** Seed for Bloom filter hash function. */ size_t hashSeed = 0; /** Number of hash functions (only works with `-t rolling-hash') */ unsigned numHashes = 1; /** The size of a k-mer. */ unsigned k; /** Number of levels for cascading bloom filter. */ unsigned levels = 1; /** * Files used to initialize levels of cascading * bloom filter (-L option). */ vector> levelInitPaths; /** * Num of locked windows to use, when invoking with * the -j option. */ size_t numLocks = 1000; /** The type of Bloom filter to build */ BloomFilterType bloomType = BT_KONNECTOR; /** * For the "graph" command: assign node attribute * (e.g. "color=blue") to k-mers contained in the * associated FASTA file */ KmerProperties fastaProperties; /** * For the "graph" command: assign node attribute * (e.g. "color=blue") to k-mers contained in the * associated Bloom filter */ KmerProperties bloomProperties; /** Index of bloom filter window. ("M" for -w option) */ unsigned windowIndex = 0; /** Number of windows in complete bloom filter. ("N" for -w option) */ unsigned windows = 0; /* Method for similarity or distance calculation. -m option */ string method("jaccard"); /* Inverse option to retrieve kmers which are not in the filter */ bool inverse = false; /** Root nodes (k-mer) for `graph` subcommand */ vector roots; /** FASTA files containing root k-mers for `graph` subcommand */ vector rootFastas; OutputFormat format = FASTA; } static const char shortopts[] = "a:A:b:B:d:f:h:H:j:k:l:L:m:n:q:rR:vt:w:"; enum { OPT_HELP = 1, OPT_VERSION, OPT_BED, OPT_FASTA, OPT_RAW }; static const struct option longopts[] = { { "bloom-size", required_argument, NULL, 'b' }, { "bloom-type", required_argument, NULL, 't' }, { "buffer-size", required_argument, NULL, 'B' }, { "depth", required_argument, NULL, 'd' }, { "hash-seed", required_argument, NULL, 'h' }, { "num-hashes", required_argument, NULL, 'H' }, { "threads", required_argument, NULL, 'j' }, { "kmer", required_argument, NULL, 'k' }, { "levels", required_argument, NULL, 'l' }, { "init-level", required_argument, NULL, 'L' }, { "chastity", no_argument, &opt::chastityFilter, 1 }, { "no-chastity", no_argument, &opt::chastityFilter, 0 }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "num-locks", required_argument, NULL, 'n' }, { "trim-quality", required_argument, NULL, 'q' }, { "standard-quality", no_argument, &opt::qualityOffset, 33 }, { "illumina-quality", no_argument, &opt::qualityOffset, 64 }, { "fasta-attr", required_argument, NULL, 'a' }, { "node-attr", required_argument, NULL, 'a' }, { "bloom-attr", required_argument, NULL, 'A' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { "window", required_argument, NULL, 'w' }, { "method", required_argument, NULL, 'm' }, { "inverse", required_argument, NULL, 'r' }, { "root", required_argument, NULL, 'R' }, { "root-fasta", required_argument, NULL, 'f' }, { "bed", no_argument, NULL, OPT_BED }, { "fasta", no_argument, NULL, OPT_FASTA }, { "raw", no_argument, NULL, OPT_RAW }, { NULL, 0, NULL, 0 } }; __attribute__((noreturn)) static void dieWithUsageError() { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } void parseGlobalOpts(int argc, char** argv) { bool done = false; int optindPrev = optind; for (int c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': dieWithUsageError(); case 'k': arg >> opt::k; break; case 'v': opt::verbose++; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); default: // end of global opts optind = optindPrev; done = true; break; } if (done) break; if (optarg != NULL && (!arg.eof() || arg.fail())) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } optindPrev = optind; } if (opt::k == 0) { cerr << PROGRAM ": missing mandatory option `-k'\n"; dieWithUsageError(); } Kmer::setLength(opt::k); } static inline istream* openInputStream(const string& path) { if (path == "-") return &cin; return new ifstream(path.c_str()); } static inline ostream* openOutputStream(const string& path) { if (path == "-") return &cout; return new ofstream(path.c_str()); } static inline void closeInputStream(istream* in, const string& path) { if (path == "-") return; ifstream* ifs = static_cast(in); ifs->close(); delete ifs; } static inline void closeOutputStream(ostream* out, const string& path) { if (path == "-") return; ofstream* ofs = static_cast(out); ofs->close(); delete ofs; } template void initBloomFilterLevels(CBF& bf) { assert(opt::levels >= 2); assert(opt::levelInitPaths.size() <= opt::levels); for (unsigned i = 0; i < opt::levelInitPaths.size(); i++) { vector& paths = opt::levelInitPaths.at(i); for (unsigned j = 0; j < paths.size(); j++) { string path = paths.at(j); cerr << "Loading `" << path << "' into level " << i + 1 << " of cascading bloom filter...\n"; istream* in = openInputStream(path); assert(*in); BitwiseOp readOp = (j > 0) ? BITWISE_OR : BITWISE_OVERWRITE; bf.getBloomFilter(i).read(*in, readOp); assert(*in); closeInputStream(in, path); } } } template void loadFilters(BF& bf, int argc, char** argv) { for (int i = optind; i < argc; i++) Bloom::loadFile(bf, opt::k, argv[i], opt::verbose, opt::bufferSize); if (opt::verbose) cerr << "Successfully loaded bloom filter.\n"; } template void writeBloom(BF& bf, string& outputPath) { if (opt::verbose) { cerr << "Writing bloom filter to `" << outputPath << "'...\n"; } ostream* out = openOutputStream(outputPath); assert_good(*out, outputPath); *out << bf; out->flush(); assert_good(*out, outputPath); closeOutputStream(out, outputPath); } template void printBloomStats(ostream& os, const BF& bloom) { os << "Bloom size (bits): " << bloom.size() << "\n" << "Bloom popcount (bits): " << bloom.popcount() << "\n" << "Bloom filter FPR: " << setprecision(3) << 100 * bloom.FPR() << "%\n"; } template void printCascadingBloomStats(ostream& os, BF& bloom) { for (unsigned i = 0; i < opt::levels; i++) { os << "Stats for Bloom filter level " << i + 1 << ":\n" << "\tBloom size (bits): " << bloom.getBloomFilter(i).size() << "\n" << "\tBloom popcount (bits): " << bloom.getBloomFilter(i).popcount() << "\n" << "\tBloom filter FPR: " << setprecision(3) << 100 * bloom.getBloomFilter(i).FPR() << "%\n"; } } template void printHashAgnosticCascadingBloomStats(ostream& os, BF& bloom) { for (unsigned i = 0; i < opt::levels; i++) { os << "Stats for Bloom filter level " << i + 1 << ":\n" << "\tBloom size (bits): " << bloom.getBloomFilter(i).getFilterSize() << "\n" << "\tBloom popcount (bits): " << bloom.getBloomFilter(i).getPop() << "\n" << "\tBloom filter FPR: " << setprecision(3) << 100 * bloom.getBloomFilter(i).getFPR() << "%\n"; } } template void printRollingBloomStats(ostream& os, BF& bloom) { os << "Bloom size (bits): " << bloom.getFilterSize() << "\n" << "Bloom popcount (bits): " << bloom.getPop() << "\n" << "Bloom filter FPR: " << setprecision(3) << 100 * bloom.getFPR() << "%\n"; } template void printCountingBloomStats(ostream& os, BF& bloom) { os << "Stats for Bloom filter level " << ":\n" << "\tBloom size (bytes): " << bloom.sizeInBytes() << "\n" << "\tBloom pre-threshold popcount: " << bloom.popCount() << "\n" << "\tBloom filter pre-threshold FPR: " << setprecision(3) << 100 * bloom.FPR() << "%\n"; } /** * Convert string argument from `-t' option to an equivalent * BloomFilterType value. */ static inline BloomFilterType strToBloomType(const std::string& str) { if (str == "konnector") return BT_KONNECTOR; else if (str == "rolling-hash") return BT_ROLLING_HASH; else if (str == "counting") return BT_COUNTING; else return BT_UNKNOWN; } static inline string bloomTypeToStr(const BloomFilterType type) { assert(type != BT_UNKNOWN); if (type == BT_KONNECTOR) { return string("konnector"); } else if (type == BT_ROLLING_HASH) { return string("rolling-hash"); } else { assert(type == BT_COUNTING); return string("counting"); } } /** Build a konnector-style Bloom filter. */ static inline void buildKonnectorBloom(size_t bits, string outputPath, int argc, char** argv) { // if we are building a cascading bloom filter, reduce // the size of each level so that the overall bloom filter // fits within the memory limit (specified by -b) bits /= opt::levels; if (opt::windows == 0) { if (opt::levels == 1) { Konnector::BloomFilter bloom(bits, opt::hashSeed); #ifdef _OPENMP ConcurrentBloomFilter cbf(bloom, opt::numLocks, opt::hashSeed); loadFilters(cbf, argc, argv); #else loadFilters(bloom, argc, argv); #endif printBloomStats(cerr, bloom); writeBloom(bloom, outputPath); } else { CascadingBloomFilter cascadingBloom(bits, opt::levels, opt::hashSeed); initBloomFilterLevels(cascadingBloom); #ifdef _OPENMP ConcurrentBloomFilter cbf( cascadingBloom, opt::numLocks, opt::hashSeed); loadFilters(cbf, argc, argv); #else loadFilters(cascadingBloom, argc, argv); #endif printCascadingBloomStats(cerr, cascadingBloom); writeBloom(cascadingBloom, outputPath); } } else { size_t bitsPerWindow = bits / opt::windows; size_t startBitPos = (opt::windowIndex - 1) * bitsPerWindow; size_t endBitPos; if (opt::windowIndex < opt::windows) endBitPos = opt::windowIndex * bitsPerWindow - 1; else endBitPos = bits - 1; if (opt::levels == 1) { BloomFilterWindow bloom(bits, startBitPos, endBitPos, opt::hashSeed); loadFilters(bloom, argc, argv); printBloomStats(cerr, bloom); writeBloom(bloom, outputPath); } else { CascadingBloomFilterWindow cascadingBloom( bits, startBitPos, endBitPos, opt::levels, opt::hashSeed); initBloomFilterLevels(cascadingBloom); loadFilters(cascadingBloom, argc, argv); printCascadingBloomStats(cerr, cascadingBloom); writeBloom(cascadingBloom, outputPath); } } } /** Build a rolling-hash based Bloom filter (used by pre 2.2.0 `abyss-bloom-dbg`) */ static inline void buildRollingHashBloom(size_t bits, string outputPath, int argc, char** argv) { /* BloomFilter class requires size to be a multiple of 64 */ size_t bloomLevelSize = BloomDBG::roundUpToMultiple(bits / opt::levels, (size_t)64); /* use cascading Bloom filter to remove error k-mers */ HashAgnosticCascadingBloom cascadingBloom(bloomLevelSize, opt::numHashes, opt::levels, opt::k); /* load reads into Bloom filter */ for (int i = optind; i < argc; ++i) BloomDBG::loadFile(cascadingBloom, argv[i], opt::verbose); if (opt::verbose) printHashAgnosticCascadingBloomStats(cerr, cascadingBloom); writeBloom(cascadingBloom, outputPath); } /** Build a Counting Bloom filter (used by `abyss-bloom-dbg`) */ static inline void buildCountingBloom(size_t bytes, string outputPath, int argc, char** argv) { /* use cascading Bloom filter to remove error k-mers */ CountingBloomFilter countingBloom(bytes, opt::numHashes, opt::k, 0); /* load reads into Bloom filter */ for (int i = optind; i < argc; ++i) BloomDBG::loadFile(countingBloom, argv[i], opt::verbose); if (opt::verbose) printCountingBloomStats(cerr, countingBloom); writeBloom(countingBloom, outputPath); } /** * Build Bloom filter file of type 'konnector', 'rolling-hash' or 'counting', as * per `-t` option. */ int build(int argc, char** argv) { parseGlobalOpts(argc, argv); for (int c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': dieWithUsageError(); case 'b': opt::bloomSize = SIToBytes(arg); break; case 'B': arg >> opt::bufferSize; break; case 'h': arg >> opt::hashSeed; break; case 'H': arg >> opt::numHashes; break; case 'j': arg >> opt::threads; break; case 'l': arg >> opt::levels; break; case 'L': { unsigned level; arg >> level >> expect("="); if (arg.fail() || arg.eof()) break; string path; arg >> path; if (arg.fail()) break; if (level > opt::levelInitPaths.size()) opt::levelInitPaths.resize(level); opt::levelInitPaths[level - 1].push_back(path); break; } case 'n': arg >> opt::numLocks; break; case 'q': arg >> opt::qualityThreshold; break; case 't': { std::string str; arg >> str; opt::bloomType = strToBloomType(str); } break; case 'w': arg >> opt::windowIndex; arg >> expect("/"); arg >> opt::windows; break; } if (optarg != NULL && (!arg.eof() || arg.fail())) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (!opt::levelInitPaths.empty() && opt::levels < 2) { cerr << PROGRAM ": -L can only be used with cascading bloom " "filters (-l >= 2)\n"; dieWithUsageError(); } if (opt::levelInitPaths.size() > opt::levels) { cerr << PROGRAM ": level arg to -L is greater than number" " of bloom filter levels (-l)\n"; dieWithUsageError(); } if (opt::bloomType == BT_UNKNOWN) { cerr << PROGRAM ": unrecognized argument to `-t' " << "(should be 'konnector', 'rolling-hash' or 'counting')\n"; dieWithUsageError(); } if (opt::bloomType == BT_KONNECTOR && opt::numHashes != 1) { cerr << PROGRAM ": warning: -H option has no effect" " when using `-t konnector'\n"; opt::numHashes = 1; } if (opt::bloomType == BT_COUNTING && (opt::levels != 1)) { cerr << PROGRAM ": warning: -l option has no effect" " when using `-t counting'\n"; } #if _OPENMP if (opt::threads > 0) omp_set_num_threads(opt::threads); #endif // bloom filter size in bits and bytes size_t bits = opt::bloomSize * 8; size_t bytes = opt::bloomSize; if (opt::windows != 0 && bits / opt::levels % opt::windows != 0) { cerr << PROGRAM ": (b / l) % w == 0 must be true, where " << "b is bloom filter size (-b), " << "l is number of levels (-l), and " << "w is number of windows (-w)\n"; dieWithUsageError(); } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; dieWithUsageError(); } string outputPath(argv[optind]); optind++; if (opt::verbose) { cerr << "Building a Bloom filter of type '" << bloomTypeToStr(opt::bloomType) << "' with "; if (opt::bloomType != BT_COUNTING) { cerr << opt::levels << " level(s), "; } cerr << opt::numHashes << " hash function(s), and a total size of " << opt::bloomSize << " bytes" << endl; } assert(opt::bloomType != BT_UNKNOWN); if (opt::bloomType == BT_KONNECTOR) { buildKonnectorBloom(bits, outputPath, argc, argv); } else if (opt::bloomType == BT_ROLLING_HASH) { buildRollingHashBloom(bits, outputPath, argc, argv); } else { assert(opt::bloomType == BT_COUNTING); buildCountingBloom(bytes, outputPath, argc, argv); } return 0; } int combine(int argc, char** argv, BitwiseOp readOp) { parseGlobalOpts(argc, argv); if (argc - optind < 3) { cerr << PROGRAM ": missing arguments\n"; dieWithUsageError(); } string outputPath(argv[optind]); optind++; Konnector::BloomFilter bloom; for (int i = optind; i < argc; i++) { string path(argv[i]); if (opt::verbose) std::cerr << "Loading bloom filter from `" << path << "'...\n"; istream* in = openInputStream(path); assert_good(*in, path); BitwiseOp op = (i > optind) ? readOp : BITWISE_OVERWRITE; bloom.read(*in, op); assert_good(*in, path); closeInputStream(in, path); } if (opt::verbose) { cerr << "Successfully loaded bloom filter.\n"; printBloomStats(cerr, bloom); switch (readOp) { case BITWISE_OR: std::cerr << "Writing union of bloom filters to `" << outputPath << "'...\n"; break; case BITWISE_AND: std::cerr << "Writing intersection of bloom filters to `" << outputPath << "'...\n"; break; default: std::cerr << "error: expected BITWISE_OR or BITWISE_AND\n"; assert(false); break; } } ostream* out = openOutputStream(outputPath); assert_good(*out, outputPath); *out << bloom; out->flush(); assert_good(*out, outputPath); closeOutputStream(out, outputPath); return 0; } int info(int argc, char** argv) { parseGlobalOpts(argc, argv); if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; dieWithUsageError(); } Konnector::BloomFilter bloom; string path = argv[optind]; if (opt::verbose) std::cerr << "Loading bloom filter from `" << path << "'...\n"; istream* in = openInputStream(path); assert_good(*in, path); *in >> bloom; printBloomStats(cerr, bloom); closeInputStream(in, path); return 0; } int compare(int argc, char** argv) { parseGlobalOpts(argc, argv); // Arg parser to get `m' option in case set for (int c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': cerr << PROGRAM ": unrecognized option: `-" << optopt << "'" << endl; dieWithUsageError(); case 'm': arg >> opt::method; break; break; } if (optarg != NULL && (!arg.eof() || arg.fail())) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } if (opt::method != "jaccard" && opt::method != "czekanowski" && opt::method != "forbes") std::cerr << "Invalid method: " << opt::method << std::endl; } // Set method strin string method(opt::method); if (opt::verbose) std::cerr << "Computing distance for 2" << " samples...\n"; // Get both paths and open istreams Konnector::BloomFilter bloomA; string pathA(argv[optind]); Konnector::BloomFilter bloomB; string pathB(argv[optind + 1]); if (opt::verbose) std::cerr << "Loading bloom filters from " << pathA << " and " << pathB << "...\n"; istream* inA = openInputStream(pathA); istream* inB = openInputStream(pathB); // Assert state of streams assert_good(*inA, pathA); assert_good(*inB, pathB); // Not sure this conversion is needed, check docs std::istream& tA = *inA; std::istream& tB = *inB; // Need to read header for bit start and end info Bloom::FileHeader headerA = Bloom::readHeader(tA); Bloom::FileHeader headerB = Bloom::readHeader(tB); // Need to assert after every read operation assert(tA); assert(tB); const size_t IO_BUFFER_SIZE = 32 * 1024; unsigned char mask = 1; // The number of total bits in the vector size_t bitsA = headerA.endBitPos - headerA.startBitPos + 1; size_t bitsB = headerB.endBitPos - headerB.startBitPos + 1; // They need to be the same size to be comparable if (bitsA != bitsB) { std::cerr << "Bit sizes of arrays not equal" << std::endl; exit(EXIT_FAILURE); } if (opt::verbose) std::cerr << "Bits: " << bitsA << std::endl; /* As in Choi et al. (2010), a - cases where both bits are set (1/1) b - cases where bits are set in the first but nor the second (1/0) c - cases where bits are set in the second but not the first (0/1) d - cases where bits are not set in either (0/0) */ unsigned long a = 0; unsigned long b = 0; unsigned long c = 0; unsigned long d = 0; // Iteratively compare bits for (size_t i = 0; i < bitsA;) { char bufferA[IO_BUFFER_SIZE]; char bufferB[IO_BUFFER_SIZE]; // The number of bits in the buffer is its size * 8 except for the last iteration size_t bitsRead = std::min(IO_BUFFER_SIZE * 8, bitsA - i); size_t bytesRead = (bitsRead + 7) / 8; // Read bytes from the the istream and immediately assert tA.read(bufferA, bytesRead); tB.read(bufferB, bytesRead); assert(tA); assert(tB); // For each byte in the buffer, compare bits for (size_t j = 0; j < IO_BUFFER_SIZE; j++) { // Compare bit-wise for (int bit = 0; bit < 8; bit++) { bool f = (bufferA[j] & (mask << bit)) != 0; bool s = (bufferB[j] & (mask << bit)) != 0; if (f == 1 && s == 1) { a++; } else if (f == 1 && s == 0) { b++; } else if (f == 0 && s == 1) { c++; } else d++; } } i += bitsRead; } assert(tA); assert(tB); // Result output: std::cout << "1/1: " << a << "\n1/0: " << b << "\n0/1: " << c << "\n0/0: " << d << std::endl; if (method == "jaccard") { float Dist = (float)a / (float)(a + b + c); std::cout << "Jaccard similarity: " << Dist << std::endl; } if (method == "czekanowski") { float Dist = (2 * (float)a) / (float)((2 * a) + b + c); std::cout << "Czekanowski similarity: " << Dist << std::endl; } if (method == "forbes") { float n = (float)(a + b + c + d); float Dist = (n * a - ((a + b) * (a + c))) / (n * std::min(a + b, a + c) - ((a + b) * (a + c))); std::cout << "Forbes similarity: " << Dist << std::endl; } // Check and clean up assert_good(tA, pathA); assert_good(tA, pathB); closeInputStream(inA, pathA); closeInputStream(inB, pathB); return 1; } /** * Given a Bloom filter, generate a Bloom filter de Bruijn graph in * GraphViz format. */ int graph(int argc, char** argv) { parseGlobalOpts(argc, argv); // default graph neighbourhood depth opt::depth = opt::k; for (int c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': dieWithUsageError(); case 'a': { string s; arg >> s; size_t pos = s.find(":"); if (pos < s.length()) opt::fastaProperties.push_back(make_pair(s.substr(0, pos), s.substr(pos + 1))); else arg.setstate(ios::failbit); } break; case 'A': { string s; arg >> s; size_t pos = s.find(":"); if (pos < s.length()) opt::bloomProperties.push_back(make_pair(s.substr(0, pos), s.substr(pos + 1))); else arg.setstate(ios::failbit); } break; case 'd': arg >> opt::depth; break; case 'f': { string path; arg >> path; opt::rootFastas.push_back(path); break; } case 'R': { string kmer; arg >> kmer; opt::roots.push_back(kmer); break; } } if (optarg != NULL && (!arg.eof() || arg.fail())) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::roots.empty() && opt::rootFastas.empty()) { cerr << PROGRAM ": must specify either --root or --root-fasta\n"; dieWithUsageError(); } if (argc - optind != 1) { cerr << PROGRAM ": missing arguments\n"; dieWithUsageError(); } typedef RollingBloomDBG Graph; typedef boost::graph_traits::vertex_descriptor V; string bloomPath(argv[optind]); optind++; if (opt::verbose) cerr << "Loading main Bloom filter from `" << bloomPath << "'..." << endl; HashAgnosticCascadingBloom bloom(bloomPath); assert(opt::k == bloom.getKmerSize()); Graph g(bloom); /* implement --fasta-attr option */ vector>> fastaProperties; for (KmerPropertiesIt it = opt::fastaProperties.begin(); it != opt::fastaProperties.end(); ++it) { if (opt::verbose) cerr << "Loading k-mers from `" << it->second << "', to be " << "annotated with '" << it->first << "'\n"; fastaProperties.push_back(make_pair(it->first, unordered_set())); size_t count = 0; size_t checkpoint = 0; const size_t step = 10000; FastaReader in(it->second.c_str(), FastaReader::FOLD_CASE); for (FastaRecord rec; in >> rec;) { for (RollingHashIterator it(rec.seq, bloom.getHashNum(), bloom.getKmerSize()); it != RollingHashIterator::end(); ++it, ++count) { V v(it.kmer().c_str(), it.rollingHash()); if (vertex_exists(v, g)) fastaProperties.back().second.insert(v); } while (opt::verbose && count >= checkpoint) { cerr << "Loaded " << checkpoint << " k-mers\n"; checkpoint += step; } } if (opt::verbose) cerr << "Loaded " << count << " k-mers in total\n"; } /* implement --bloom-attr option */ typedef vector> BloomProperties; BloomProperties bloomProperties; for (KmerPropertiesIt it = opt::bloomProperties.begin(); it != opt::bloomProperties.end(); ++it) { if (opt::verbose) cerr << "Loading Bloom filter from `" << it->second << "', to be " << "annotated with '" << it->first << "'\n"; bloomProperties.push_back(make_pair(it->first, new BloomFilter(it->second))); if (opt::verbose) printRollingBloomStats(cerr, *bloomProperties.back().second); } /* implement -R/--root option */ unordered_set roots; typedef typename std::vector::const_iterator KmerIt; for (KmerIt it = opt::roots.begin(); it != opt::roots.end(); ++it) { assert(it->size() == opt::k); V v(it->c_str(), RollingHash(it->c_str(), bloom.getHashNum(), bloom.getKmerSize())); if (vertex_exists(v, g)) roots.insert(v); } /* implement -f/--root-fasta option */ typedef typename std::vector::const_iterator PathIt; for (PathIt pathIt = opt::rootFastas.begin(); pathIt != opt::rootFastas.end(); ++pathIt) { FastaReader in(pathIt->c_str(), FastaReader::FOLD_CASE); for (FastaRecord rec; in >> rec;) { for (RollingHashIterator it(rec.seq, bloom.getHashNum(), bloom.getKmerSize()); it != RollingHashIterator::end(); ++it) { V v(it.kmer().c_str(), it.rollingHash()); if (vertex_exists(v, g)) roots.insert(v); } } } /* run breadth-first search and output GraphViz */ RollingBloomDBGVisitor visitor( roots, opt::depth, fastaProperties, bloomProperties, cout); breadthFirstSearchMulti(roots, g, true, visitor); /* clean-up */ typedef typename BloomProperties::iterator BloomPropertiesIt; for (BloomPropertiesIt it = bloomProperties.begin(); it != bloomProperties.end(); ++it) { delete it->second; } return 0; } int memberOf(int argc, char** argv) { // Initalise bloom and get globals Konnector::BloomFilter bloom; parseGlobalOpts(argc, argv); // Arg parser to get `m' option in case set for (int c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': cerr << PROGRAM ": unrecognized option: `-" << optopt << "'" << endl; dieWithUsageError(); case 'r': opt::inverse = true; break; break; case OPT_BED: opt::format = BED; break; case OPT_FASTA: opt::format = FASTA; break; case OPT_RAW: opt::format = RAW; break; } if (optarg != NULL && (!arg.eof() || arg.fail())) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } string path = argv[optind]; string fasta = argv[++optind]; unsigned k = opt::k; if (opt::verbose) std::cerr << "Loading bloom filter from `" << path << "'...\n"; istream* in = openInputStream(path); assert_good(*in, path); *in >> bloom; assert(!fasta.empty()); if (opt::verbose) std::cerr << "Reading `" << fasta << "'...\n"; FastaReader _in(fasta.c_str(), FastaReader::FOLD_CASE); size_t seqCount = 0; for (FastaRecord rec; _in >> rec; ++seqCount) { string& seq = rec.seq; if (seq.size() < k) continue; for (size_t i = 0; i < seq.size() - k + 1; ++i) { string kmer = seq.substr(i, k); size_t pos = kmer.find_last_not_of("ACGTacgt"); if (pos != string::npos) { i += pos; continue; } if (bloom[Kmer(kmer)] != opt::inverse) { if (opt::format == FASTA) { cout << ">" << rec.id << ":seq:" << seqCount << ":kmer:" << i << "\n"; } else if (opt::format == BED) { cout << rec.id << "\t" << i << "\t" << i + k - 1 << "\t"; } cout << kmer << "\n"; } } if (opt::verbose && seqCount % 1000 == 0) cerr << "processed " << seqCount << " sequences" << endl; } assert(_in.eof()); if (opt::verbose) cerr << "processed " << seqCount << " sequences" << endl; return 0; } /** * Calculate number of bases to trim from left end of sequence. */ int calcLeftTrim( const Sequence& seq, unsigned k, const Konnector::BloomFilter& bloom, size_t minBranchLen) { // Boost graph interface for Bloom filter DBGBloom g(bloom); // if this is the first k-mer we have found in // Bloom filter, starting from the left end // of the sequence bool firstKmerMatch = true; // longest branch of Bloom filter false positives const unsigned fpTrim = 5; KmerIterator it(seq, k); for (; it != KmerIterator::end(); ++it) { const Kmer& kmer = *it; // assume k-mers not present in Bloom filter are // due to sequencing errors and should be trimmed if (!bloom[kmer]) continue; PathExtensionResultCode leftResult, rightResult; boost::tie(boost::tuples::ignore, leftResult) = successor(kmer, REVERSE, g, minBranchLen, fpTrim); boost::tie(boost::tuples::ignore, rightResult) = successor(kmer, FORWARD, g, minBranchLen, fpTrim); if (firstKmerMatch) { bool leftTip = leftResult == ER_DEAD_END && rightResult == ER_LENGTH_LIMIT; bool rightTip = leftResult == ER_LENGTH_LIMIT && rightResult == ER_DEAD_END; if (!leftTip && !rightTip) break; } else { bool leftFork = leftResult == ER_AMBI_IN || leftResult == ER_AMBI_OUT; bool rightFork = rightResult == ER_AMBI_IN || rightResult == ER_AMBI_OUT; if (leftFork || rightFork) break; } firstKmerMatch = false; } // for each k-mer (left to right) if (it.pos() == 0) return 0; return k + it.pos() - 1; } /** * Trim reads that corresponds to tips in the Bloom filter * de Bruijn graph. */ int trim(int argc, char** argv) { // parse command line opts parseGlobalOpts(argc, argv); unsigned k = opt::k; // arg 1: Bloom filter // args 2-n: FASTA/FASTQ files if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; dieWithUsageError(); } // load Bloom filter de Bruijn graph string bloomPath(argv[optind++]); if (opt::verbose) cerr << "Loading bloom filter from `" << bloomPath << "'...\n"; Konnector::BloomFilter bloom; istream* in = openInputStream(bloomPath); assert_good(*in, bloomPath); bloom.read(*in); assert_good(*in, bloomPath); if (opt::verbose) printBloomStats(cerr, bloom); // Calculate min length threshold for a "true branch" // (not due to Bloom filter false positives) const double falseBranchProbability = 0.0001; const size_t minBranchLen = (size_t)ceil(log(falseBranchProbability) / log(bloom.FPR())); if (opt::verbose >= 2) cerr << "min length threshold for true branches (k-mers): " << minBranchLen << endl; size_t readCount = 0; // trim reads and print to STDOUT for (int i = optind; i < argc; ++i) { if (opt::verbose) cerr << "Reading `" << argv[i] << "'..." << endl; FastaReader in(argv[i], FastaReader::FOLD_CASE); for (FastqRecord rec; in >> rec; ++readCount) { Sequence& seq = rec.seq; string& qual = rec.qual; // can't trim if read length < k; just echo // back to STDOUT if (seq.size() < k) { cout << rec; continue; } // start pos for trimmed read unsigned startPos = calcLeftTrim(seq, k, bloom, minBranchLen); // end pos for trimmed read unsigned endPos = seq.length() - 1 - calcLeftTrim(reverseComplement(seq), k, bloom, minBranchLen); // if whole read was trimmed away if (endPos < startPos) continue; // output trimmed read unsigned trimmedLen = endPos - startPos + 1; seq = seq.substr(startPos, trimmedLen); qual = qual.substr(startPos, trimmedLen); cout << rec; if (opt::verbose && (readCount + 1) % 100000 == 0) cerr << "Processed " << (readCount + 1) << " reads" << endl; } // for each read assert(in.eof()); } // for each input FASTA/FASTQ file if (opt::verbose) cerr << "Processed " << readCount << " reads" << endl; // success return 0; } int main(int argc, char** argv) { if (argc < 2) dieWithUsageError(); string command(argv[1]); optind++; if (command == "--help" || command == "-h") { cout << USAGE_MESSAGE; 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, BITWISE_OR); } else if (command == "intersect") { return combine(argc, argv, BITWISE_AND); } else if (command == "info") { return info(argc, argv); } else if (command == "compare") { return compare(argc, argv); } else if (command == "graph") { return graph(argc, argv); } else if (command == "kmers" || command == "getKmers") { return memberOf(argc, argv); } else if (command == "trim") { return trim(argc, argv); } cerr << PROGRAM ": unrecognized command: `" << command << "'" << endl; dieWithUsageError(); } abyss-2.2.4/BloomDBG/000077500000000000000000000000001361462241400142305ustar00rootroot00000000000000abyss-2.2.4/BloomDBG/AssemblyCounters.h000066400000000000000000000030371361462241400177060ustar00rootroot00000000000000#ifndef _ASSEMBLY_COUNTERS_H_ #define _ASSEMBLY_COUNTERS_H_ #include "Common/IOUtil.h" #include #include #include namespace BloomDBG { /** * Counters for tracking assembly statistics and producing * progress messages. */ struct AssemblyCounters { /** reads consisting entirely of solid k-mers */ size_t solidReads; /** * reads consisting entirely of k-mers already * included in output contigs */ size_t visitedReads; size_t readsProcessed; size_t basesAssembled; size_t contigID; AssemblyCounters() : solidReads(0), visitedReads(0), readsProcessed(0), basesAssembled(0), contigID(0) {} /** serialize counters as a TSV table */ friend std::ostream& operator<<(std::ostream& out, const AssemblyCounters& o) { /* write headers */ out << "solid_reads" << '\t' << "processed_reads" << '\t' << "bases_assembled" << '\t' << "next_contig_id" << '\n'; /* write data */ out << o.solidReads << '\t' << o.readsProcessed << '\t' << o.basesAssembled << '\t' << o.contigID << '\n'; return out; } /** deserialize counters from a TSV table */ friend std::istream& operator>>(std::istream& in, AssemblyCounters& o) { /* ignore header line */ std::string headers; getline(in, headers); /* read data */ in >> o.solidReads >> expect("\t") >> o.readsProcessed >> expect("\t") >> o.basesAssembled >> expect("\t") >> o.contigID >> expect("\n"); return in; } }; } /* end of BloomDBG namespace */ #endif abyss-2.2.4/BloomDBG/AssemblyParams.h000066400000000000000000000064001361462241400173240ustar00rootroot00000000000000#ifndef _ASSEMBLY_PARAMS_H_ #define _ASSEMBLY_PARAMS_H_ #include #include #include namespace BloomDBG { /** * Parameters controlling assembly. */ struct AssemblyParams { /** Bloom filter size (in bytes) */ size_t bloomSize; /** Checkpoint frequency (reads processed per checkpoint) */ size_t readsPerCheckpoint; /** Do not delete checkpoint files after a successful assembly */ bool keepCheckpoint; /** Filename prefix for checkpoint files */ std::string checkpointPathPrefix; /** minimum k-mer coverage threshold */ unsigned minCov; /** path to output debugging info about processing of each read */ std::string readLogPath; /** WIG track containing 0/1 for sufficient k-mer cov */ std::string covTrackPath; /** path for output GraphViz file */ std::string graphPath; /** num Bloom filter hash functions */ unsigned numHashes; /** input Bloom filter file (if empty, build Bloom filter from reads)*/ std::string bloomPath; /** the number of parallel threads. */ unsigned threads; /** the size of a k-mer. */ unsigned k; /** the size of a single k-mer in a k-mer pair */ unsigned K; /** reference genome */ std::string refPath; /** Quadratic Residue (QR) seed length */ unsigned qrSeedLen; /** spaced seed */ std::string spacedSeed; /** maximum length of branches to trim */ unsigned trim; /** verbose level for progress messages */ int verbose; /** output contigs path (empty string indicates STDOUT) */ std::string outputPath; /** output path for trace file (-T) option */ std::string tracePath; /** Default constructor */ AssemblyParams() : bloomSize(0), readsPerCheckpoint(std::numeric_limits::max()), keepCheckpoint(false), checkpointPathPrefix("bloom-dbg-checkpoint"), minCov(2), graphPath(), numHashes(1), threads(1), k(0), K(0), qrSeedLen(0), spacedSeed(), trim(std::numeric_limits::max()), verbose(0), outputPath(), tracePath() {} /** Return true if all required members are initialized */ bool initialized() const { return bloomSize > 0 && k > 0 && trim != std::numeric_limits::max(); } /** Return true if checkpoint creation is enabled */ bool checkpointsEnabled() const { return readsPerCheckpoint != std::numeric_limits::max(); } /** Reset all spaced seed params to their default values */ void resetSpacedSeedParams() { spacedSeed.clear(); K = 0; qrSeedLen = 0; } /** Report current parameter values (for logging) */ friend std::ostream& operator<<(std::ostream& out, const AssemblyParams& o) { out << "Assembly parameters:" << std::endl << '\t' << "K-mer size (-k): " << o.k << std::endl << '\t' << "K-mer coverage threshold (--kc): " << o.minCov << std::endl << '\t' << "Max branch trim length (-t): " << o.trim << std::endl << '\t' << "Bloom size in bytes (-b): " << o.bloomSize << std::endl << '\t' << "Bloom hash functions (-H): " << o.numHashes << std::endl; if (o.K > 0) out << '\t' << "Spaced k-mer size (-K): " << o.K << std::endl; if (o.qrSeedLen > 0) out << '\t' << "Quadratic residue (QR) seed length (--qr-seed): " << o.qrSeedLen << std::endl; return out; } }; } /* end of BloomDBG namespace */ #endif abyss-2.2.4/BloomDBG/AssemblyStreams.h000066400000000000000000000014231361462241400175170ustar00rootroot00000000000000#ifndef _ASSEMBLY_STREAMS_H_ #define _ASSEMBLY_STREAMS_H_ namespace BloomDBG { /** Bundles together input and output streams used during assembly */ template struct AssemblyStreams { /** input reads stream */ InputStreamT& in; /** main FASTA output */ std::ostream& out; /** duplicated FASTA output for checkpointing */ std::ostream& checkpointOut; /** trace file output for debugging */ std::ostream& traceOut; /** outcomes of processing each read */ std::ostream& readLogOut; AssemblyStreams(InputStreamT& in, std::ostream& out, std::ostream& checkpointOut, std::ostream& traceOut, std::ostream& readLogOut) : in(in), out(out), checkpointOut(checkpointOut), traceOut(traceOut), readLogOut(readLogOut) {} }; } #endif abyss-2.2.4/BloomDBG/BloomIO.h000066400000000000000000000057771361462241400157210ustar00rootroot00000000000000#ifndef BLOOM_IO_H #define BLOOM_IO_H 1 #include "BloomDBG/RollingHash.h" #include "BloomDBG/RollingHashIterator.h" #include "DataLayer/FastaReader.h" #include "vendor/btl_bloomfilter/BloomFilter.hpp" namespace BloomDBG { /** * Round up `num` to the nearest multiple of `base`. */ template inline static T roundUpToMultiple(T num, T base) { if (base == 0) return num; T remainder = num % base; if (remainder == 0) return num; return num + base - remainder; } /** * Load DNA sequence into Bloom filter using rolling hash. * * @param bloom target Bloom filter * @param seq DNA sequence */ template inline static void loadSeq(BF& bloom, const std::string& seq) { const unsigned k = bloom.getKmerSize(); const unsigned numHashes = bloom.getHashNum(); for (RollingHashIterator it(seq, numHashes, k); it != RollingHashIterator::end(); ++it) { bloom.insert(*it); } } /** * Load sequences contents of FASTA file into Bloom filter using * rolling hash. * @param bloom target Bloom filter * @param path path to FASTA file * @param verbose if true, print progress messages to STDERR */ template inline static void loadFile(BF& bloom, const std::string& path, bool verbose = false) { const size_t BUFFER_SIZE = 1000000; const size_t LOAD_PROGRESS_STEP = 10000; assert(!path.empty()); if (verbose) std::cerr << "Reading `" << path << "'..." << std::endl; FastaReader in(path.c_str(), FastaReader::FOLD_CASE); uint64_t readCount = 0; #pragma omp parallel for (std::vector buffer(BUFFER_SIZE);;) { buffer.clear(); size_t bufferSize = 0; bool good = true; #pragma omp critical(in) for (; good && bufferSize < BUFFER_SIZE;) { 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 < buffer.size(); j++) { loadSeq(bloom, buffer.at(j)); if (verbose) #pragma omp critical(cerr) { readCount++; if (readCount % LOAD_PROGRESS_STEP == 0) std::cerr << "Loaded " << readCount << " reads into Bloom filter\n"; } } } assert(in.eof()); if (verbose) { std::cerr << "Loaded " << readCount << " reads from `" << path << "` into Bloom filter\n"; } } /** Load FASTQ/FASTA/SAM/BAM files from command line into a Bloom filter */ template static inline void loadBloomFilter(int argc, char** argv, BloomFilterT& bloom, bool verbose = false) { /* load reads into Bloom filter */ for (int i = optind; i < argc; ++i) { /* * Debugging feature: If there is a ':' * separating the list of input read files into * two parts, use the first set of files * to load the Bloom filter and the second * set of files for the assembly (read extension). */ if (strcmp(argv[i], ":") == 0) { optind = i + 1; break; } BloomDBG::loadFile(bloom, argv[i], verbose); } if (verbose) cerr << "Bloom filter FPR: " << setprecision(3) << bloom.FPR() * 100 << "%" << endl; } } // end namespace 'BloomDBG' #endif abyss-2.2.4/BloomDBG/Checkpoint.h000066400000000000000000000215471361462241400165010ustar00rootroot00000000000000#ifndef _CHECKPOINT_H_ #define _CHECKPOINT_H_ #include "BloomDBG/AssemblyCounters.h" #include "BloomDBG/AssemblyParams.h" #include "BloomDBG/AssemblyStreams.h" #include "Common/IOUtil.h" #include "DataLayer/FastaReader.h" #include #include #include namespace BloomDBG { const std::string CHECKPOINT_FASTA_EXT = ".contigs.fa"; const std::string CHECKPOINT_COUNTERS_EXT = ".counters.tsv"; const std::string CHECKPOINT_BLOOM_DBG_EXT = ".dbg.bloom"; const std::string CHECKPOINT_BLOOM_VISITED_EXT = ".visited.bloom"; const std::string CHECKPOINT_TMP_EXT = ".tmp"; /** * Save the current assembly state to a set of checkpoint files, * so that the assembly can be resumed from that point. * * @param dbg Bloom filter de Bruijn graph * @param visitedKmerSet k-mers included in output contigs so far * @param counters counters capturing assembly state * (e.g. next input read index, next output contig index) * @param params various assembly parameters (corresponding to * command line opts) */ template static inline void createCheckpoint( const BloomDBGT& dbg, const VisitedKmerSetT& visitedKmerSet, const AssemblyCounters& counters, const AssemblyParams& params) { assert(params.checkpointsEnabled()); assert(!params.checkpointPathPrefix.empty()); std::string prefix = params.checkpointPathPrefix; if (params.verbose) std::cerr << "Writing checkpoint data..." << std::endl; /* write out Bloom filter de Bruijn graph */ std::string dbgPath = prefix + CHECKPOINT_BLOOM_DBG_EXT; std::string dbgPathTmp = dbgPath + CHECKPOINT_TMP_EXT; if (params.verbose) std::cerr << '\t' << "Writing Bloom filter de Bruijn graph to `" << dbgPathTmp << "'" << std::endl; std::ofstream dbgOut; dbgOut.open(dbgPathTmp.c_str()); assert_good(dbgOut, dbgPathTmp); dbgOut << dbg; assert_good(dbgOut, dbgPathTmp); /* write out visited k-mers Bloom filter */ std::string visitedPath = prefix + CHECKPOINT_BLOOM_VISITED_EXT; std::string visitedPathTmp = visitedPath + CHECKPOINT_TMP_EXT; if (params.verbose) std::cerr << '\t' << "Writing visited k-mers Bloom to `" << visitedPathTmp << "'" << std::endl; std::ofstream visitedOut; visitedOut.open(visitedPathTmp.c_str()); assert_good(visitedOut, visitedPathTmp); visitedOut << visitedKmerSet; assert_good(visitedOut, visitedPathTmp); /* write out index of next input read */ std::string countersPath = prefix + CHECKPOINT_COUNTERS_EXT; std::string countersPathTmp = countersPath + CHECKPOINT_TMP_EXT; if (params.verbose) std::cerr << '\t' << "Writing assembly counters to `" << countersPathTmp << "'" << std::endl; std::ofstream countersOut; countersOut.open(countersPathTmp.c_str()); assert_good(countersOut, countersPathTmp); countersOut << counters; assert_good(countersOut, countersPathTmp); /* copy/move new checkpoint files on top of old ones */ std::string fastaPath = prefix + CHECKPOINT_FASTA_EXT; std::string fastaPathTmp = fastaPath + CHECKPOINT_TMP_EXT; if (params.verbose) std::cerr << '\t' << "Copying `" << fastaPathTmp << " to `" << fastaPath << "'" << std::endl; copyFile(fastaPathTmp, fastaPath); if (params.verbose) std::cerr << '\t' << "Moving `" << dbgPathTmp << "' to `" << dbgPath << "'" << std::endl; if (rename(dbgPathTmp.c_str(), dbgPath.c_str()) != 0) { perror("Error renaming file"); abort(); } if (params.verbose) std::cerr << '\t' << "Moving `" << visitedPathTmp << "' to `" << visitedPath << "'" << std::endl; if (rename(visitedPathTmp.c_str(), visitedPath.c_str()) != 0) { perror("Error renaming file"); abort(); } if (params.verbose) std::cerr << '\t' << "Moving `" << countersPathTmp << "' to `" << countersPath << "'" << std::endl; if (rename(countersPathTmp.c_str(), countersPath.c_str()) != 0) { perror("Error renaming file"); abort(); } } /** Return true if checkpoint files exist and are readable */ static inline bool checkpointExists(const AssemblyParams& params) { assert(params.checkpointsEnabled()); assert(!params.checkpointPathPrefix.empty()); std::string prefix = params.checkpointPathPrefix; std::string fastaPath = prefix + CHECKPOINT_FASTA_EXT; std::string dbgPath = prefix + CHECKPOINT_BLOOM_DBG_EXT; std::string visitedPath = prefix + CHECKPOINT_BLOOM_VISITED_EXT; std::string countersPath = prefix + CHECKPOINT_COUNTERS_EXT; return std::ifstream(fastaPath.c_str()).good() && std::ifstream(dbgPath.c_str()).good() && std::ifstream(visitedPath.c_str()).good() && std::ifstream(countersPath.c_str()).good(); } /** * Restore assembly state from checkpoint files. * * @param dbg Bloom filter de Bruijn graph * @param visitedKmerSet k-mers included in output contigs so far * @param counters counters capturing assembly state * (e.g. next input read index, next output contig index) * @param params various assembly parameters (corresponding to * @param out main output stream for assembled contigs * command line opts) */ template static inline void resumeFromCheckpoint( BloomDBGT& dbg, VisitedKmerSetT& visitedKmerSet, AssemblyCounters& counters, const AssemblyParams& params, AssemblyStreams& streams) { assert(checkpointExists(params)); assert(params.checkpointsEnabled()); assert(!params.checkpointPathPrefix.empty()); std::string prefix = params.checkpointPathPrefix; if (params.verbose) std::cerr << "Resuming from last checkpoint..." << std::endl; /* load Bloom filter de Bruijn graph */ std::string dbgPath = prefix + CHECKPOINT_BLOOM_DBG_EXT; if (params.verbose) std::cerr << '\t' << "Reading Bloom filter de Bruijn graph from `" << dbgPath << "'" << std::endl; dbg.loadFilter(dbgPath); /* load visited k-mers Bloom filter */ std::string visitedPath = prefix + CHECKPOINT_BLOOM_VISITED_EXT; if (params.verbose) std::cerr << '\t' << "Reading reading visited k-mers Bloom from `" << visitedPath << "'" << std::endl; visitedKmerSet.loadFilter(visitedPath); /* load index for next input read */ std::string countersPath = prefix + CHECKPOINT_COUNTERS_EXT; if (params.verbose) std::cerr << '\t' << "Reading index of next input read from `" << countersPath << "'" << std::endl; std::ifstream countersIn(countersPath.c_str()); assert_good(countersIn, countersPath); countersIn >> counters; assert_good(countersIn, countersPath); /* advance to previous position in input reads */ if (params.verbose) std::cerr << '\t' << "Advancing to read index " << counters.readsProcessed << " in input reads..." << std::endl; FastaRecord rec; for (size_t i = 0; i < counters.readsProcessed && streams.in; ++i) streams.in >> rec; assert(!streams.in.eof()); /* restore previously assembled contigs */ std::string fastaPath = prefix + CHECKPOINT_FASTA_EXT; std::string fastaPathTmp = fastaPath + CHECKPOINT_TMP_EXT; if (params.verbose) std::cerr << '\t' << "Copying `" << fastaPath << "' to `" << fastaPathTmp << "'" << std::endl; copyFile(fastaPath, fastaPathTmp); if (params.verbose) std::cerr << '\t' << "Outputting previously assembled contigs " << "from `" << fastaPath << "'" << std::endl; std::ifstream prevContigs(fastaPath.c_str()); assert_good(prevContigs, fastaPath); streams.out << prevContigs.rdbuf(); assert(streams.out); } /** Delete a file if it exists */ static inline void removeFileIfExists(const std::string& path) { if (std::ifstream(path.c_str()).good()) { if (remove(path.c_str()) != 0) { perror("Error removing file"); abort(); } } } /** Remove all checkpoint-related files */ static inline void removeCheckpointData(const AssemblyParams& params) { assert(params.checkpointsEnabled()); assert(!params.checkpointPathPrefix.empty()); std::string prefix = params.checkpointPathPrefix; if (params.verbose) std::cerr << "Removing checkpoint files..." << std::endl; /* remove Bloom filter de Bruijn graph file(s) */ std::string dbgPath = prefix + CHECKPOINT_BLOOM_DBG_EXT; std::string dbgPathTmp = dbgPath + CHECKPOINT_TMP_EXT; removeFileIfExists(dbgPath); removeFileIfExists(dbgPathTmp); /* remove visited k-mers Bloom filter file(s) */ std::string visitedPath = prefix + CHECKPOINT_BLOOM_VISITED_EXT; std::string visitedPathTmp = visitedPath + CHECKPOINT_TMP_EXT; removeFileIfExists(visitedPath); removeFileIfExists(visitedPathTmp); /* remove assembly counters file(s) */ std::string countersPath = prefix + CHECKPOINT_COUNTERS_EXT; std::string countersPathTmp = countersPath + CHECKPOINT_TMP_EXT; removeFileIfExists(countersPath); removeFileIfExists(countersPathTmp); /* remove contigs FASTA file(s) */ std::string fastaPath = prefix + CHECKPOINT_FASTA_EXT; std::string fastaPathTmp = fastaPath + CHECKPOINT_TMP_EXT; removeFileIfExists(fastaPath); removeFileIfExists(fastaPathTmp); } } #endif abyss-2.2.4/BloomDBG/LightweightKmer.h000066400000000000000000000071711361462241400175050ustar00rootroot00000000000000#ifndef LIGHTWEIGHT_KMER_H #define LIGHTWEIGHT_KMER_H 1 #include "BloomDBG/MaskedKmer.h" #include "Common/Kmer.h" #include "Common/Sequence.h" #include "Common/Sense.h" #include #include #include #include /** * Class that stores a shared pointer to a k-mer (char array). * * I implemented this class because I observed that storing and * copying the full char array between data structures was hurting * performance and using a lot of memory. * * Having a lightweight k-mer representation is particularly * important when using it as the `vertex_descriptor` in a Boost graph. */ class LightweightKmer { private: /** Shared pointer to k-mer data */ boost::shared_array m_kmer; public: /** Default constructor */ LightweightKmer() {} /** Constructor */ LightweightKmer(const char* kmer) : m_kmer(new char[Kmer::length() + 1]) { const unsigned k = Kmer::length(); std::copy(kmer, kmer + k, m_kmer.get()); /* null-terminate k-mer string */ *(m_kmer.get() + k) = '\0'; } /** Get pointer to raw char array for k-mer */ char* c_str() { return (char*)m_kmer.get(); } /** Get pointer to raw char array for k-mer (read-only) */ const char* c_str() const { return (const char*)m_kmer.get(); } /** Shift the k-mer and set the value of the new incoming base. */ void shift(extDirection dir, char charIn = 'A') { const unsigned k = Kmer::length(); assert(k >= 2); if (dir == SENSE) { memmove(m_kmer.get(), m_kmer.get() + 1, k - 1); } else { memmove(m_kmer.get() + 1, m_kmer.get(), k - 1); } setLastBase(dir, charIn); } /** Change the first/last base of the k-mer */ void setLastBase(extDirection dir, char base) { const unsigned k = Kmer::length(); unsigned pos = (dir == SENSE) ? k - 1 : 0; setBase(pos, base); } /** Change a base within the k-mer */ void setBase(unsigned pos, char base) { assert(pos < Kmer::length()); *(m_kmer.get() + pos) = base; } /** Get the base (ACGT) at a given position */ char getBase(unsigned pos) const { return *(m_kmer.get() + pos); } /** * Return true if k-mer is in its lexicographically smallest orientation */ bool isCanonical() const { const unsigned k = Kmer::length(); for (unsigned i = 0; i < k/2; ++i) { const char c1 = toupper(m_kmer.get()[i]); const char c2 = complementBaseChar( toupper(m_kmer.get()[k-i-1])); if (c1 > c2) return false; else if (c1 < c2) return true; } return true; } /** * Reverse complement the k-mer, if it is not already in its * canonical (i.e. lexicographically smallest) orientation. */ void canonicalize() { if (!isCanonical()) reverseComplement(); } void reverseComplement() { const unsigned k = Kmer::length(); for (unsigned i = 0; i < k/2; ++i) { const char tmp = complementBaseChar(m_kmer.get()[i]); m_kmer.get()[i] = complementBaseChar( m_kmer.get()[k-i-1]); m_kmer.get()[k-i-1] = tmp; } /* if k is odd, we need to reverse complement the middle char */ if (k % 2 == 1 && k > 1) m_kmer.get()[k/2] = complementBaseChar(m_kmer.get()[k/2]); } /** Equality operator */ bool operator==(const LightweightKmer& o) const { unsigned k = Kmer::length(); const std::string& spacedSeed = MaskedKmer::mask(); if (spacedSeed.empty()) { return !memcmp(m_kmer.get(), o.m_kmer.get(), k); } else { assert(spacedSeed.length() == k); for (unsigned i = 0; i < k; ++i) { if (spacedSeed.at(i) != '0' && getBase(i) != o.getBase(i)) return false; } return true; } } /** Inequality operator */ bool operator!=(const LightweightKmer& o) const { return !operator==(o); } }; #endif abyss-2.2.4/BloomDBG/Makefile.am000066400000000000000000000011171361462241400162640ustar00rootroot00000000000000bin_PROGRAMS = abyss-bloom-dbg abyss_bloom_dbg_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -I$(top_srcdir)/vendor abyss_bloom_dbg_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_bloom_dbg_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a abyss_bloom_dbg_SOURCES = \ AssemblyCounters.h \ AssemblyParams.h \ AssemblyStreams.h \ bloom-dbg.cc \ bloom-dbg.h \ BloomIO.h \ Checkpoint.h \ LightweightKmer.h \ MaskedKmer.h \ RollingBloomDBG.h \ RollingHash.h \ RollingHashIterator.h \ SpacedSeed.h abyss-2.2.4/BloomDBG/MaskedKmer.h000066400000000000000000000052301361462241400164240ustar00rootroot00000000000000#ifndef MASKED_KMER_H #define MASKED_KMER_H 1 #include "Common/Kmer.h" #include "Common/Hash.h" #include "Common/Sequence.h" #include #include #include class MaskedKmer : public Kmer { public: /** Default constructor */ MaskedKmer() : Kmer() {} /** * Constructor. * @param seq k-mer sequence */ explicit MaskedKmer(const Sequence& seq) : Kmer(seq) {} /** Set global k-mer mask (a.k.a. spaced seed) */ static void setMask(const std::string& kmerMask) { /* setLength() must be called before setMask() */ assert(length() > 0); /* set global bitmask */ mask() = kmerMask; /* empty mask is equivalent to string of '1's */ if (kmerMask.empty()) return; /* check for valid spaced seed pattern */ if (mask().length() != length()) { std::cerr << "error: spaced seed must be exactly k bits long\n"; exit(EXIT_FAILURE); } else if (mask().find_first_not_of("01") != std::string::npos) { std::cerr << "error: spaced seed must contain only '0's or '1's\n"; exit(EXIT_FAILURE); } else if (*mask().begin() != '1' || *mask().rbegin() != '1') { std::cerr << "error: spaced seed must begin and end with '1's\n"; exit(EXIT_FAILURE); } } /** Get global k-mer mask */ static std::string& mask() { static std::string s_kmerMask; return s_kmerMask; } /** Compare this k-mer to another */ int compare(const Kmer& other) const { if (!mask().empty()) { Kmer kmer1(*this), kmer2(other); maskKmer(kmer1); maskKmer(kmer2); return kmer1.compare(kmer2); } return Kmer::compare(other); } /** Equality operator */ bool operator==(const MaskedKmer& other) const { return compare(other) == 0; } /** Inequality operator */ bool operator!=(const MaskedKmer& other) const { return compare(other) != 0; } /** Less-than operator */ bool operator<(const MaskedKmer& other) const { return compare(other) < 0; } /** Mask out don't care positions by changing them to 'A' */ static void maskKmer(Kmer& kmer) { if (mask().empty()) return; assert(mask().length() == length()); for(size_t i = 0; i < mask().length(); ++i) { if (mask().at(i) == '0') kmer.set(i, baseToCode('A')); } } }; /** Return the reverse complement of the specified k-mer. */ static inline MaskedKmer reverseComplement(const MaskedKmer& seq) { MaskedKmer rc(seq); rc.reverseComplement(); return rc; } /** Define default hash function for use with STL containers */ NAMESPACE_STD_HASH_BEGIN template <> struct hash { size_t operator()(const MaskedKmer& kmer) const { MaskedKmer kmerCopy(kmer); MaskedKmer::maskKmer(kmerCopy); return kmerCopy.getHashCode(); } }; NAMESPACE_STD_HASH_END #endif abyss-2.2.4/BloomDBG/RollingBloomDBG.h000066400000000000000000000320621361462241400173200ustar00rootroot00000000000000/** * de Bruijn Graph data structure using a Bloom filter * Copyright 2015 Shaun Jackman, Ben Vandervalk */ #ifndef ROLLING_BLOOM_DBG_H #define ROLLING_BLOOM_DBG_H 1 #include "Assembly/SeqExt.h" // for NUM_BASES #include "Common/Hash.h" #include "BloomDBG/MaskedKmer.h" #include "Graph/Properties.h" #include "BloomDBG/RollingHash.h" #include "BloomDBG/LightweightKmer.h" #include "vendor/btl_bloomfilter/BloomFilter.hpp" #include #include #include // for abort #include #include #include // for std::pair #include #include #define BASE_CHARS "ACGT" using boost::graph_traits; /** * Represents a vertex in the de Bruijn graph. */ struct RollingBloomDBGVertex { private: LightweightKmer m_kmer; RollingHash m_rollingHash; public: RollingBloomDBGVertex() {} RollingBloomDBGVertex(const char* kmer, const RollingHash rollingHash) : m_kmer(kmer), m_rollingHash(rollingHash) {} const LightweightKmer& kmer() const { return m_kmer; }; LightweightKmer& kmer() { return m_kmer; }; const RollingHash& rollingHash() const { return m_rollingHash; } RollingBloomDBGVertex clone() const { return RollingBloomDBGVertex(m_kmer.c_str(), m_rollingHash); } void shift(extDirection dir, char charIn = 'A') { if (dir == SENSE) { m_rollingHash.rollRight(m_kmer.c_str(), charIn); } else { m_rollingHash.rollLeft(charIn, m_kmer.c_str()); } m_kmer.shift(dir, charIn); } void setLastBase(extDirection dir, char base) { m_rollingHash.setLastBase(kmer().c_str(), dir, base); kmer().setLastBase(dir, base); } void reverseComplement() { m_kmer.reverseComplement(); m_rollingHash.reverseComplement(); } bool isCanonical() const { return m_kmer.isCanonical(); } void canonicalize() { if (!m_kmer.isCanonical()) reverseComplement(); } /** * Comparison operator that takes spaced seed bitmask into account. */ bool operator==(const RollingBloomDBGVertex& o) const { /* do fast comparison first */ if (m_rollingHash != o.m_rollingHash) return false; return compare(o) == 0; } /** * Inequality operator that takes spaced seed bitmask into account. */ bool operator!=(const RollingBloomDBGVertex& o) const { return !(*this == o); } /** * Comparison operator that is invariant under reverse-complement. */ bool operator<(const RollingBloomDBGVertex& o) const { return compare(o) < 0; } /** Comparison operator that is invariant under reverse complement */ int compare(const RollingBloomDBGVertex& o) const { unsigned k = Kmer::length(); const std::string& spacedSeed = MaskedKmer::mask(); const LightweightKmer& kmer1 = kmer(); const LightweightKmer& kmer2 = o.kmer(); bool rc1 = !kmer1.isCanonical(); bool rc2 = !kmer2.isCanonical(); int end1 = rc1 ? -1 : k; int end2 = rc2 ? -1 : k; int inc1 = rc1 ? -1 : 1; int inc2 = rc2 ? -1 : 1; int pos1 = rc1 ? k-1 : 0; int pos2 = rc2 ? k-1 : 0; for (; pos1 != end1 && pos2 != end2; pos1+=inc1, pos2+=inc2) { char c1 = toupper(kmer1.c_str()[pos1]); char c2 = toupper(kmer2.c_str()[pos2]); /* ignore positions masked by spaced seed */ if (!spacedSeed.empty() && spacedSeed.at(pos1) != '1') { /* spaced seed must be symmetric */ assert(spacedSeed.at(pos2) != '1'); continue; } if (rc1) c1 = complementBaseChar(c1); if (rc2) c2 = complementBaseChar(c2); if (c1 > c2) return 1; if (c1 < c2) return -1; } return 0; } }; NAMESPACE_STD_HASH_BEGIN template <> struct hash { /** * Hash function for graph vertex type (vertex_descriptor) */ size_t operator()(const RollingBloomDBGVertex& vertex) const { return vertex.rollingHash().getHashSeed(); } }; NAMESPACE_STD_HASH_END template class RollingBloomDBG: public BF { public: /** The bundled vertex properties. */ typedef no_property vertex_bundled; typedef no_property vertex_property_type; /** The bundled edge properties. */ typedef no_property edge_bundled; typedef no_property edge_property_type; /** The bloom filter */ const BF& m_bloom; RollingBloomDBG(const BF& bloom) : m_bloom(bloom) {} private: /** Copy constructor. */ RollingBloomDBG(const RollingBloomDBG&); }; // class RollingBloomDBG // Graph namespace boost { /** Graph traits */ template struct graph_traits< RollingBloomDBG > { // Graph /** * Identifier for accessing a vertex in the graph. * The second member of the pair (std::vector) is * a set of hash values associated with the k-mer. */ typedef uint64_t hash_t; typedef RollingBloomDBGVertex vertex_descriptor; typedef boost::directed_tag directed_category; struct traversal_category : boost::adjacency_graph_tag, boost::bidirectional_graph_tag, boost::vertex_list_graph_tag { }; typedef boost::disallow_parallel_edge_tag edge_parallel_category; // IncidenceGraph typedef std::pair edge_descriptor; typedef unsigned degree_size_type; // VertexListGraph typedef uint64_t vertices_size_type; typedef void vertex_iterator; // EdgeListGraph typedef uint64_t edges_size_type; typedef void edge_iterator; // AdjacencyGraph /** Iterate through the adjacent vertices of a vertex. */ struct adjacency_iterator : public std::iterator { /** Skip to the next edge that is present. */ void next() { for (; m_i < NUM_BASES; ++m_i) { m_v.setLastBase(SENSE, BASE_CHARS[m_i]); if (vertex_exists(m_v, *m_g)) break; } } public: adjacency_iterator() { } adjacency_iterator(const RollingBloomDBG& g) : m_g(&g), m_i(NUM_BASES) { } adjacency_iterator(const RollingBloomDBG& g, const vertex_descriptor& u) : m_g(&g), m_u(u), m_v(u.clone()), 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; } adjacency_iterator operator++(int) { adjacency_iterator it = *this; ++*this; return it; } private: const RollingBloomDBG* m_g; vertex_descriptor m_u; vertex_descriptor m_v; short unsigned m_i; }; // adjacency_iterator /** IncidenceGraph */ struct out_edge_iterator : public std::iterator { /** Skip to the next edge that is present. */ void next() { for (; m_i < NUM_BASES; ++m_i) { m_v.setLastBase(SENSE, BASE_CHARS[m_i]); if (vertex_exists(m_v, *m_g)) break; } } public: out_edge_iterator() { } out_edge_iterator(const RollingBloomDBG& g) : m_g(&g), m_i(NUM_BASES) { } out_edge_iterator(const RollingBloomDBG& g, const vertex_descriptor& u) : m_g(&g), m_u(u), m_v(u.clone()), m_i(0) { m_v.shift(SENSE); next(); } edge_descriptor operator*() const { assert(m_i < NUM_BASES); return edge_descriptor(m_u, m_v.clone()); } 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_BASES); ++m_i; next(); return *this; } out_edge_iterator operator++(int) { out_edge_iterator it = *this; ++*this; return it; } private: const RollingBloomDBG* m_g; vertex_descriptor m_u; vertex_descriptor m_v; unsigned m_i; }; // out_edge_iterator /** BidirectionalGraph */ struct in_edge_iterator : public std::iterator { /** Skip to the next edge that is present. */ void next() { for (; m_i < NUM_BASES; ++m_i) { m_v.setLastBase(ANTISENSE, BASE_CHARS[m_i]); if (vertex_exists(m_v, *m_g)) break; } } public: in_edge_iterator() { } in_edge_iterator(const RollingBloomDBG& g) : m_g(&g), m_i(NUM_BASES) { } in_edge_iterator(const RollingBloomDBG& g, const vertex_descriptor& u) : m_g(&g), m_u(u), m_v(u.clone()), m_i(0) { m_v.shift(ANTISENSE); next(); } edge_descriptor operator*() const { assert(m_i < NUM_BASES); return edge_descriptor(m_v.clone(), m_u); } 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_BASES); ++m_i; next(); return *this; } in_edge_iterator operator++(int) { in_edge_iterator it = *this; ++*this; return it; } private: const RollingBloomDBG* m_g; vertex_descriptor m_u; vertex_descriptor m_v; unsigned m_i; }; // in_edge_iterator }; // graph_traits } // namespace boost // Subgraph /** Return whether this vertex exists in the subgraph. */ template static inline bool vertex_exists( const typename graph_traits >::vertex_descriptor& u, const RollingBloomDBG& g) { typedef uint64_t hash_t; hash_t hashes[MAX_HASHES]; u.rollingHash().getHashes(hashes); return g.m_bloom.contains(hashes); } template static inline std::pair::adjacency_iterator, typename graph_traits::adjacency_iterator> adjacent_vertices( const typename graph_traits::vertex_descriptor& u, const Graph& g) { typedef typename graph_traits::adjacency_iterator adjacency_iterator; return std::make_pair(adjacency_iterator(g, u), adjacency_iterator(g)); } // IncidenceGraph template static inline typename graph_traits::degree_size_type out_degree( const typename graph_traits::vertex_descriptor& u, const Graph& g) { typedef typename graph_traits::adjacency_iterator Ait; std::pair adj = adjacent_vertices(u, g); return std::distance(adj.first, adj.second); } template static inline typename std::pair >::out_edge_iterator, typename graph_traits >::out_edge_iterator> out_edges( const typename graph_traits >::vertex_descriptor& u, const RollingBloomDBG& g) { typedef RollingBloomDBG Graph; typedef typename graph_traits::out_edge_iterator Oit; return std::make_pair(Oit(g, u), Oit(g)); } // BidirectionalGraph template static inline std::pair >::in_edge_iterator, typename graph_traits >::in_edge_iterator> in_edges( const typename graph_traits >::vertex_descriptor& u, const RollingBloomDBG& g) { typedef RollingBloomDBG Graph; typedef typename graph_traits::in_edge_iterator Iit; return std::make_pair(Iit(g, u), Iit(g)); } template static inline typename graph_traits >::degree_size_type in_degree(const typename graph_traits >::vertex_descriptor& u, const RollingBloomDBG& g) { typedef RollingBloomDBG Graph; typedef typename graph_traits::in_edge_iterator Iit; std::pair it = in_edges(u, g); return std::distance(it.first, it.second); } // PropertyGraph /** Return the reverse complement of the specified k-mer. */ template static inline typename graph_traits< RollingBloomDBG >::vertex_descriptor get(vertex_complement_t, const RollingBloomDBG&, typename graph_traits >::vertex_descriptor u) { typedef RollingBloomDBG Graph; typedef typename graph_traits::vertex_descriptor V; return V(reverseComplement(u.first), u.second); } /** Return the name of the specified vertex. */ template static inline MaskedKmer get(vertex_name_t, const RollingBloomDBG&, typename graph_traits >::vertex_descriptor u) { return u.first; } template static inline bool get(vertex_removed_t, const RollingBloomDBG&, typename graph_traits >::vertex_descriptor) { return false; } template static inline no_property get(vertex_bundle_t, const RollingBloomDBG&, typename graph_traits >::edge_descriptor) { return no_property(); } template static inline no_property get(edge_bundle_t, const RollingBloomDBG&, typename graph_traits >::edge_descriptor) { return no_property(); } template static inline std::pair::edge_descriptor, bool> edge(const typename boost::graph_traits::vertex_descriptor& u, const typename boost::graph_traits::vertex_descriptor&v, const Graph& g) { typedef typename boost::graph_traits::edge_descriptor E; typedef typename boost::graph_traits::adjacency_iterator AdjIt; AdjIt it, end; E e(u, v); for (boost::tie(it, end) = adjacent_vertices(u, g); it != end; ++it) { if (*it == v) return std::make_pair(e, true); } return std::make_pair(e, false); } #endif abyss-2.2.4/BloomDBG/RollingHash.h000066400000000000000000000135001361462241400166120ustar00rootroot00000000000000#ifndef ABYSS_ROLLING_HASH_H #define ABYSS_ROLLING_HASH_H 1 #include "config.h" #include "BloomDBG/LightweightKmer.h" #include "BloomDBG/MaskedKmer.h" #include "Common/Sense.h" #include "vendor/nthash/nthash.hpp" #include #include #include #include #include #include class RollingHash { private: typedef uint64_t hash_t; /** * Determine the canonical hash value, given hash values for * forward and reverse-complement of the same k-mer. */ hash_t canonicalHash(hash_t hash, hash_t rcHash) const { return (rcHash < hash) ? rcHash : hash; } public: /** * Default constructor. */ RollingHash() : m_numHashes(0), m_k(0), m_hash1(0), m_rcHash1(0) {} /** * Constructor. Construct RollingHash object when initial k-mer * is unknown. * @param numHashes number of pseudo-independent hash values to compute * for each k-mer * @param k k-mer length */ RollingHash(unsigned numHashes, unsigned k) : m_numHashes(numHashes), m_k(k), m_hash1(0), m_rcHash1(0) {} /** * Constructor. Construct RollingHash object while specifying * initial k-mer to be hashed. * @param kmer initial k-mer for initializing hash value(s) * @param numHashes number of pseudo-independent hash values to compute * for each k-mer * @param k k-mer length */ RollingHash(const std::string& kmer, unsigned numHashes, unsigned k) : m_numHashes(numHashes), m_k(k), m_hash1(0), m_rcHash1(0) { /* init rolling hash state */ reset(kmer); } /** * Initialize hash state from sequence. * @param kmer k-mer used to initialize hash state */ void reset(const std::string& kmer) { /* compute initial hash values for forward and reverse-complement k-mer */ NTC64(kmer.c_str(), m_k, m_hash1, m_rcHash1); /* get canonical hash value from forward/reverse hash values */ m_hash = canonicalHash(m_hash1, m_rcHash1); if (!MaskedKmer::mask().empty()) m_hash = maskHash(m_hash1, m_rcHash1, MaskedKmer::mask().c_str(), kmer.c_str(), m_k); } /** * Compute hash values for next k-mer to the right and * update internal state. * @param kmer current k-mer * @param nextKmer k-mer we are rolling into */ void rollRight(const char* kmer, char charIn) { NTC64(kmer[0], charIn, m_k, m_hash1, m_rcHash1); m_hash = canonicalHash(m_hash1, m_rcHash1); if (!MaskedKmer::mask().empty()) { // TODO: copying the k-mer and shifting is very inefficient; // we need a specialized nthash function that rolls and masks // simultaneously LightweightKmer next(kmer); next.shift(SENSE, charIn); m_hash = maskHash(m_hash1, m_rcHash1, MaskedKmer::mask().c_str(), next.c_str(), m_k); } } /** * Compute hash values for next k-mer to the left and * update internal state. * @param prevKmer k-mer we are rolling into * @param kmer current k-mer */ void rollLeft(char charIn, const char* kmer) { NTC64L(kmer[m_k-1], charIn, m_k, m_hash1, m_rcHash1); m_hash = canonicalHash(m_hash1, m_rcHash1); if (!MaskedKmer::mask().empty()) { // TODO: copying the k-mer and shifting is very inefficient; // we need a specialized nthash function that rolls and masks // simultaneously LightweightKmer next(kmer); next.shift(ANTISENSE, charIn); m_hash = maskHash(m_hash1, m_rcHash1, MaskedKmer::mask().c_str(), next.c_str(), m_k); } } /** * Get the seed hash value for the current k-mer. The seed hash * value is used to calculate multiple pseudo-independant * hash functions. */ size_t getHashSeed() const { return (size_t)m_hash; } /** * Get hash values for current k-mer. * * @param hashes array for returned hash values */ void getHashes(hash_t hashes[]) const { for (unsigned i = 0; i < m_numHashes; ++i) hashes[i] = NTE64(m_hash, m_k, i); } /** Equality operator */ bool operator==(const RollingHash& o) const { /** * Note: If hash seeds are equal, then the values * for all hash functions will also be equal, since * the hash values are calculated from the * seed in a deterministic manner. In practice seed * collision is very unlikely, though! */ return m_k == o.m_k && getHashSeed() == o.getHashSeed(); } /** Inequality operator */ bool operator!=(const RollingHash& o) const { return !(*this == o); } /** * Change the hash value to reflect a change in the first/last base of * the k-mer. * @param kmer point to the k-mer char array * @param dir if SENSE, change last base; if ANTISENSE, * change first base * @param base new value for the base */ void setLastBase(char* kmer, extDirection dir, char base) { if (dir == SENSE) { /* roll left to remove old last char */ NTC64L(kmer[m_k-1], 'A', m_k, m_hash1, m_rcHash1); /* roll right to add new last char */ NTC64('A', base, m_k, m_hash1, m_rcHash1); } else { /* roll right to remove old first char */ NTC64(kmer[0], 'A', m_k, m_hash1, m_rcHash1); /* roll left to add new first char */ NTC64L('A', base, m_k, m_hash1, m_rcHash1); } m_hash = canonicalHash(m_hash1, m_rcHash1); if (!MaskedKmer::mask().empty()) m_hash = maskHash(m_hash1, m_rcHash1, MaskedKmer::mask().c_str(), kmer, m_k); } /** * Reverse complement the hash state, so that rolling right becomes * rolling left, and vice versa. This operation is needed * whenever we reverse-complement a k-mer that has an associated * `RollingHash` state, so that subsequent rolling operations will * produce the correct hash value. */ void reverseComplement() { std::swap(m_hash1, m_rcHash1); } private: /** number of hash functions */ unsigned m_numHashes; /** k-mer length */ unsigned m_k; /** value of first hash function for current k-mer */ hash_t m_hash1; /** value of first hash function for current k-mer, after * reverse-complementing */ hash_t m_rcHash1; /** current canonical hash value */ hash_t m_hash; }; #endif abyss-2.2.4/BloomDBG/RollingHashIterator.h000066400000000000000000000125371361462241400203350ustar00rootroot00000000000000#ifndef ROLLING_HASH_ITERATOR_H #define ROLLING_HASH_ITERATOR_H 1 #include #include #include #include #include #include #include #include #include "BloomDBG/RollingHash.h" /** * Permitted characters in k-mers. All k-mers containing * other characters will be skipped. */ #define ACGT_CHARS "ACGT" /** * Iterate over hash values for k-mers in a * given DNA sequence. * * This implementation uses a rolling hash * function to efficiently calculate * hash values for successive k-mers. */ class RollingHashIterator { private: /** * Advance iterator right to the next valid k-mer. */ void next() { if (m_seq.length() < m_k) { m_pos = std::numeric_limits::max(); return; } const std::string& spacedSeed = MaskedKmer::mask(); while(m_pos < m_seq.length() - m_k + 1) { /* skip k-mers with non-ACGT chars in unmasked positions */ while (!m_badCharPos.empty() && m_badCharPos.front() < m_pos) m_badCharPos.pop_front(); if (!m_badCharPos.empty() && m_badCharPos.front() < m_pos + m_k) { /* empty spaced seed is equivalent to a string of '1's */ if (spacedSeed.empty()) { m_rollNextHash = false; m_pos = m_badCharPos.front() + 1; continue; } bool goodKmer = true; assert(spacedSeed.length() == m_k); for (size_t i = 0; i < m_badCharPos.size() && m_badCharPos.at(i) < m_pos + m_k; ++i) { size_t kmerPos = m_badCharPos.at(i) - m_pos; if (spacedSeed.at(kmerPos) == '1') { goodKmer = false; break; } } if (!goodKmer) { m_rollNextHash = false; ++m_pos; continue; } } /* we are positioned at the next valid k-mer */ if (!m_rollNextHash) { /* we don't have hash values for the * preceding k-mer, so we must compute * the hash values from scratch */ m_rollingHash.reset(m_seq.substr(m_pos, m_k)); m_rollNextHash = true; } else { /* compute new hash values based on * hash values of preceding k-mer */ assert(m_pos > 0); m_rollingHash.rollRight(m_seq.c_str() + m_pos - 1, m_seq[m_pos + m_k - 1]); } m_rollingHash.getHashes(m_hashes); return; } /* there are no more valid k-mers */ m_pos = std::numeric_limits::max(); } public: typedef uint64_t hash_t; /** * Default constructor. Creates an iterator pointing to * the end of the iterator range. */ RollingHashIterator() : m_numHashes(0), m_k(0), m_rollingHash(m_numHashes, m_k), m_pos(std::numeric_limits::max()) {} /** * Constructor. * @param seq DNA sequence to be hashed * @param k k-mer size * for each k-mer */ RollingHashIterator(const std::string& seq, unsigned numHashes, unsigned k) : m_seq(seq), m_numHashes(numHashes), m_k(k), m_rollingHash(m_numHashes, m_k), m_rollNextHash(false), m_pos(0) { init(); } /** * Initialize internal state of iterator. */ void init() { /* note: empty spaced seed indicates no masking (string of '1's) */ assert(MaskedKmer::mask().empty() || MaskedKmer::mask().length() == m_k); /* convert sequence to upper case */ std::transform(m_seq.begin(), m_seq.end(), m_seq.begin(), ::toupper); /* record positions of non-ACGT chars */ size_t i = m_seq.find_first_not_of(ACGT_CHARS); while (i != std::string::npos) { m_badCharPos.push_back(i); i = m_seq.find_first_not_of(ACGT_CHARS, i + 1); } /* find first "good" k-mer in sequence */ next(); } /** get reference to hash values for current k-mer */ const hash_t* operator*() const { assert(m_pos + m_k <= m_seq.length()); return m_hashes; } /** test equality with another iterator */ bool operator==(const RollingHashIterator& it) const { return m_pos == it.m_pos; } /** test inequality with another iterator */ bool operator!=(const RollingHashIterator& it) const { return !(*this == it); } /** pre-increment operator */ RollingHashIterator& operator++() { ++m_pos; next(); return *this; } /** post-increment operator */ RollingHashIterator operator++(int) { RollingHashIterator it = *this; ++*this; return it; } /** iterator pointing to one past last element */ static const RollingHashIterator end() { return RollingHashIterator(); } /** return position of current k-mer */ unsigned pos() const { return m_pos; } /** return k-mer at current position */ std::string kmer(bool mask=false) const { std::string kmer(m_seq, m_pos, m_k); const std::string& spacedSeed = MaskedKmer::mask(); if (mask && !spacedSeed.empty()) { assert(spacedSeed.length() == m_k); for(size_t i = 0; i < spacedSeed.length(); ++i) { if (spacedSeed.at(i) == '0') kmer.at(i) = 'N'; } } return kmer; } /** return RollingHash object for current state */ RollingHash rollingHash() { return m_rollingHash; } private: /** DNA sequence being hashed */ std::string m_seq; /** number of hash functions */ unsigned m_numHashes; /** hash values */ hash_t m_hashes[MAX_HASHES]; /** k-mer size */ unsigned m_k; /** internal state for rolling hash */ RollingHash m_rollingHash; /** true whenever we can "roll" the hash values for * the current k-mer to compute the hash values for the * next k-mer */ bool m_rollNextHash; /** position of current k-mer */ size_t m_pos; /** positions of non-ACGT chars in sequence */ std::deque m_badCharPos; }; #endif abyss-2.2.4/BloomDBG/SpacedSeed.h000066400000000000000000000042471361462241400164100ustar00rootroot00000000000000#ifndef SPACED_SEED_H #define SPACED_SEED_H #include #include #include namespace SpacedSeed { /** * Generate a spaced seed pattern (bitmask) for two equal-size * k-mers separated by a gap. * * @param k width of spaced seed pattern * @param K size of the individual k-mers. K must be <= k/2. * @return spaced seed pattern for gapped k-mer pair */ static inline std::string kmerPair(unsigned k, unsigned K) { assert(K <= k/2); std::string seed(k, '0'); std::fill(seed.begin(), seed.begin() + K, '1'); std::fill(seed.rbegin(), seed.rbegin() + K, '1'); return seed; } /** * Generate a Quadratic Residue (QR) seed. The background theory * for QR seeds is described in: * * Egidi, Lavinia, and Giovanni Manzini. "Multiple seeds * sensitivity using a single seed with threshold." Journal of * bioinformatics and computational biology 13.04 (2015): 1550011. * * @param len desired length of QR seed. `len` must * be prime and >= 11. * @return a QR seed represented as a std::string * of 0's and 1's */ static inline std::string qrSeed(unsigned len) { assert(len >= 11); std::string seed(len, '1'); for (size_t i = 0; i < len; ++i) { for (size_t j = 1; j < len; ++j) { if (j*j % len == i) { seed.at(i) = '0'; break; } } } return seed; } /** * Generate a spaced seed pattern (bitmask) for two equal-length * Quadratic Residue (QR) seeds separated by a gap. The first * QR seed is in the usual orientation and the second QR is reversed, * so that the overall pattern is symmetric. * * @param k width of the spaced seed pattern * @param qrSeedLen width of the individual QR seeds. * qrSeedLen must be a prime number >= 11 and must also be <= k/2. * @return spaced seed pattern for gapped QR seed pair */ static inline std::string qrSeedPair(unsigned k, unsigned qrSeedLen) { assert(qrSeedLen <= k/2); std::string seed(k, '0'); std::string qrSeed = SpacedSeed::qrSeed(qrSeedLen); std::copy(qrSeed.begin(), qrSeed.end(), seed.begin()); std::reverse(qrSeed.begin(), qrSeed.end()); std::copy(qrSeed.rbegin(), qrSeed.rend(), seed.rbegin()); return seed; } } #endif abyss-2.2.4/BloomDBG/bloom-dbg.cc000066400000000000000000000453531361462241400164130ustar00rootroot00000000000000#include "config.h" #include "BloomDBG/AssemblyCounters.h" #include "BloomDBG/AssemblyParams.h" #include "BloomDBG/Checkpoint.h" #include "BloomDBG/MaskedKmer.h" #include "BloomDBG/SpacedSeed.h" #include "BloomDBG/bloom-dbg.h" #include "Common/Options.h" #include "Common/StringUtil.h" #include "DataLayer/Options.h" #include "vendor/btl_bloomfilter/CountingBloomFilter.hpp" #include #include #include #include #include #include #include #include #if _OPENMP #include #endif typedef uint8_t BloomCounterType; typedef CountingBloomFilter CountingBloomFilterType; using namespace std; #define PROGRAM "abyss-bloom-dbg" #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Ben Vandervalk, Shaun Jackman, Hamid Mohamadi,\n" "Justin Chu, and Anthony Raymond.\n" "\n" "Copyright 2015 Canada's Michael Smith Genome Science Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -b -H -k \\\n" " [options] [FASTQ]... > assembly.fasta\n" "\n" "Perform a de Bruijn graph assembly of the given FASTQ files.\n" "\n" "Basic Options:\n" "\n" " -b --bloom-size=N overall memory budget for the assembly in bytes.\n" " Unit suffixes 'k' (kilobytes), 'M' (megabytes),\n" " or 'G' (gigabytes) may be used. [required]\n" " --chastity discard unchaste reads [default]\n" " --no-chastity do not discard unchaste reads\n" " -g --graph=FILE write de Bruijn graph to FILE (GraphViz)\n" " --help display this help and exit\n" " -H --num-hashes=N number of Bloom filter hash functions [1]\n" " -i --input-bloom=FILE load Bloom filter from FILE\n" " -j, --threads=N use N parallel threads [1]\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" " -k, --kmer=N the size of a k-mer [<=" STR( MAX_KMER) "]\n" " --kc=N ignore k-mers having a count < N,\n" " using a counting Bloom filter [2]\n" " -o, --out=FILE write the contigs to FILE [STDOUT]\n" " -q, --trim-quality=N trim bases from the ends of reads whose\n" " quality is less than the threshold\n" " -Q, --mask-quality=N mask all low quality bases as `N'\n" " --standard-quality zero quality is `!' (33), typically\n" " for FASTQ and SAM files [default]\n" " --illumina-quality zero quality is `@' (64), typically\n" " for qseq and export files\n" " -t, --trim-length=N max branch length to trim, in k-mers [k]\n" " -v, --verbose display verbose output\n" " --version output version information and exit\n" "\n" "Spaced Seed Options:\n" "\n" " -K, --single-kmer=N use a spaced seed that consists of two k-mers\n" " separated by a gap. K must be chosen such that\n" " K <= k/2\n" " --qr-seed=N use a spaced seed than consists of two mirrored\n" " QR seeds separated by a gap. The following must\n" " hold: (a) N must be prime, (b) N >= 11,\n" " (c) N <= k/2\n" " -s, --spaced-seed=STR bitmask indicating k-mer positions to be\n" " ignored during hashing. The pattern must be\n" " symmetric\n" "\n" "Debugging Options:\n" "\n" " -C, --cov-track=FILE WIG track with 0/1 indicating k-mers with\n" " coverage above the -c threshold. A reference\n" " must also be specified with -R.\n" " --read-log=FILE write outcome of processing each read to FILE\n" " -R, --ref=FILE specify a reference genome. FILE may be\n" " FASTA, FASTQ, SAM, or BAM and may be gzipped.\n" " -T, --trace-file=FILE write debugging info about generation of\n" " each read to FILE\n" "\n" "Experimental Options:\n" "\n" " Note!: These options may not be supported in future versions.\n" "\n" " --checkpoint=N create a checkpoint every N reads [disabled=0]\n" " --keep-checkpoint do not delete checkpoint files after assembly\n" " completes successfully [disabled]\n" " --checkpoint-prefix=STR filename prefix for checkpoint files\n" " ['bloom-dbg-checkpoint']\n" "\n" "Example:\n" "\n" " Assemble a genome using a k-mer size of 50bp. Allocate a 1GB\n" " Bloom filter with 2 hash functions and require that a k-mer\n" " occurs 3 times or more to be included in the assembly. (The k-mer\n" " count threshold filters out k-mers containing sequencing errors.)\n" "\n" " $ " PROGRAM " -k50 -b1G -H2 --kc=3 reads1.fq.gz reads2.fq.gz > assembly.fa\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; /** Assembly params (stores command-line options) */ BloomDBG::AssemblyParams params; static const char shortopts[] = "b:C:g:H:i:j:k:K:o:q:Q:R:s:t:T:v"; enum { OPT_HELP = 1, OPT_VERSION, QR_SEED, MIN_KMER_COV, CHECKPOINT, KEEP_CHECKPOINT, CHECKPOINT_PREFIX, READ_LOG, }; static const struct option longopts[] = { { "bloom-size", required_argument, NULL, 'b' }, { "min-coverage", required_argument, NULL, 'c' }, { "cov-track", required_argument, NULL, 'C' }, { "chastity", no_argument, &opt::chastityFilter, 1 }, { "no-chastity", no_argument, &opt::chastityFilter, 0 }, { "checkpoint", required_argument, NULL, CHECKPOINT }, { "keep-checkpoint", no_argument, NULL, KEEP_CHECKPOINT }, { "checkpoint-prefix", required_argument, NULL, CHECKPOINT_PREFIX }, { "graph", required_argument, NULL, 'g' }, { "num-hashes", required_argument, NULL, 'H' }, { "input-bloom", required_argument, NULL, 'i' }, { "help", no_argument, NULL, OPT_HELP }, { "threads", required_argument, NULL, 'j' }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "kmer", required_argument, NULL, 'k' }, { "kc", required_argument, NULL, MIN_KMER_COV }, { "single-kmer", required_argument, NULL, 'K' }, { "out", required_argument, NULL, 'o' }, { "trim-quality", required_argument, NULL, 'q' }, { "mask-quality", required_argument, NULL, 'Q' }, { "standard-quality", no_argument, &opt::qualityOffset, 33 }, { "illumina-quality", no_argument, &opt::qualityOffset, 64 }, { "qr-seed", required_argument, NULL, QR_SEED }, { "read-log", required_argument, NULL, READ_LOG }, { "ref", required_argument, NULL, 'R' }, { "spaced-seed", required_argument, NULL, 's' }, { "trim-length", required_argument, NULL, 't' }, { "trace-file", required_argument, NULL, 'T' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; template void printCountingBloomStats(T& bloom, ostream& os) { os << "Counting Bloom filter stats:" << "\n\t#counters = " << bloom.size() << "\n\t#size (B) = " << bloom.sizeInBytes() << "\n\tthreshold = " << bloom.threshold() << "\n\tpopcount = " << bloom.filtered_popcount() << "\n\tFPR = " << setprecision(3) << 100.f * bloom.filtered_FPR() << "%" << "\n"; } /** Create optional auxiliary output files */ template void writeAuxiliaryFiles( int argc, char** argv, const BloomFilterT& bloom, const BloomDBG::AssemblyParams& params) { /* generate wiggle coverage track */ if (!params.covTrackPath.empty() && !params.refPath.empty()) BloomDBG::writeCovTrack(bloom, params); /* generate de Bruijn graph in GraphViz format */ if (!params.graphPath.empty()) { ofstream graphOut(params.graphPath.c_str()); assert_good(graphOut, params.graphPath); BloomDBG::outputGraph(argc, argv, bloom, params, graphOut); assert_good(graphOut, params.graphPath); graphOut.close(); assert_good(graphOut, params.graphPath); } } /** Initialize global variables for k-mer size and spaced seed pattern */ void initGlobals(const BloomDBG::AssemblyParams& params) { /* set global variable for k-mer length */ MaskedKmer::setLength(params.k); if (params.verbose) cerr << "Assembling with k-mer size " << params.k << endl; /* set global variable for spaced seed */ if (params.K > 0) MaskedKmer::setMask(SpacedSeed::kmerPair(params.k, params.K)); else if (params.qrSeedLen > 0) MaskedKmer::setMask(SpacedSeed::qrSeedPair(params.k, params.qrSeedLen)); else MaskedKmer::setMask(params.spacedSeed); if (params.verbose && !MaskedKmer::mask().empty()) cerr << "Using spaced seed " << MaskedKmer::mask() << endl; } /** * Resume assembly from previously saved checkpoint. */ void resumeAssemblyFromCheckpoint(int argc, char** argv, BloomDBG::AssemblyParams& params, ostream& out) { assert(params.checkpointsEnabled() && checkpointExists(params)); assert(params.initialized()); initGlobals(params); /* empty Bloom filter de Bruijn graph */ CountingBloomFilterType solidKmerSet; /* empty visited k-mers Bloom filter */ BloomFilter visitedKmerSet; /* counters for progress messages */ BloomDBG::AssemblyCounters counters; /* setup input/output streams for the assembly */ /* input reads */ FastaConcat in(argv + optind, argv + argc, FastaReader::FOLD_CASE); /* output stream for duplicate contigs FASTA output (for checkpoints) */ ofstream checkpointOut; assert(!params.checkpointPathPrefix.empty()); string prefix = params.checkpointPathPrefix; string checkpointPath = prefix + BloomDBG::CHECKPOINT_FASTA_EXT; checkpointOut.open(checkpointPath.c_str(), std::ofstream::app); assert_good(checkpointOut, checkpointPath); /* stream for trace file output ('-T' option) */ ofstream traceOut; if (!params.tracePath.empty()) { traceOut.open(params.tracePath.c_str()); assert_good(traceOut, params.tracePath); BloomDBG::ContigRecord::printHeaders(traceOut); assert_good(traceOut, params.tracePath); } /* logs outcome of processing of each read (`--read-log`) */ std::ofstream readLogOut; if (!params.readLogPath.empty()) { readLogOut.open(params.readLogPath.c_str()); assert_good(readLogOut, params.readLogPath); BloomDBG::ReadRecord::printHeaders(readLogOut); assert_good(readLogOut, params.readLogPath); } /* bundle input/output streams for assembly */ BloomDBG::AssemblyStreams streams(in, out, checkpointOut, traceOut, readLogOut); /* restore state of Bloom filters, counters, and input/output streams */ BloomDBG::resumeFromCheckpoint(solidKmerSet, visitedKmerSet, counters, params, streams); /* resume the assembly */ BloomDBG::assemble(solidKmerSet, visitedKmerSet, counters, params, streams); } /** * Do the assembly after loading a pre-built Bloom filter * from file (`-i` option). (The input Bloom filter file * is constructed using `abyss-bloom build -t rolling-hash`.) */ void prebuiltBloomAssembly(int argc, char** argv, BloomDBG::AssemblyParams& params, ostream& out) { /* load prebuilt Bloom filter from file */ assert(!params.bloomPath.empty()); if (params.verbose) cerr << "Loading prebuilt Bloom filter from `" << params.bloomPath << "'" << endl; /* load the Bloom filter from file */ CountingBloomFilterType bloom(params.bloomPath, params.minCov); if (params.verbose) cerr << "Bloom filter FPR: " << setprecision(3) << bloom.FPR() * 100 << "%" << endl; printCountingBloomStats(bloom, cerr); /* override command line options with values from Bloom file */ params.k = bloom.getKmerSize(); params.numHashes = bloom.getHashNum(); params.bloomSize = bloom.sizeInBytes(); if (params.trim == std::numeric_limits::max()) params.trim = params.k; assert(params.numHashes <= MAX_HASHES); assert(params.initialized()); /* init global vars for k-mer size and spaced seed pattern */ initGlobals(params); if (params.verbose) cerr << params; /* do assembly */ BloomDBG::assemble(argc - optind, argv + optind, bloom, params, out); /* write supplementary files (e.g. GraphViz) */ writeAuxiliaryFiles(argc - optind, argv + optind, bloom, params); } /** * Load the reads into a counting Bloom filter and do the assembly. */ void countingBloomAssembly(int argc, char** argv, const BloomDBG::AssemblyParams& params, ostream& out) { /* init global vars for k-mer size and spaced seed pattern */ assert(params.initialized()); initGlobals(params); if (params.verbose) cerr << params; /* Initialize a counting Bloom filter: Divide the requested memory in bytes by 1.125 to account for the memory used in building the visitedKmer BloomFilter. Then further divide the byte-size of each counter to determine the number of counters, and then round up that count to the next multiple of 64.*/ double countingBloomFilterSize = params.bloomSize / 1.125 / sizeof(BloomCounterType); size_t counters = BloomDBG::roundUpToMultiple((size_t) round(countingBloomFilterSize), (size_t)64); CountingBloomFilterType bloom(counters, params.numHashes, params.k, params.minCov); BloomDBG::loadBloomFilter(argc, argv, bloom, params.verbose); if (params.verbose) printCountingBloomStats(bloom, cerr); /* second pass through FASTA files for assembling */ BloomDBG::assemble(argc - optind, argv + optind, bloom, params, out); /* write supplementary files (e.g. GraphViz) */ writeAuxiliaryFiles(argc - optind, argv + optind, bloom, params); } /** * Create a de novo genome assembly 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 'b': params.bloomSize = SIToBytes(arg); break; case 'C': arg >> params.covTrackPath; break; case 'g': arg >> params.graphPath; break; case 'H': arg >> params.numHashes; break; case 'i': arg >> params.bloomPath; break; case 'j': arg >> params.threads; break; case 'k': arg >> params.k; break; case 'K': params.resetSpacedSeedParams(); arg >> params.K; break; case 'o': arg >> params.outputPath; break; case 'q': arg >> opt::qualityThreshold; break; case 'R': arg >> params.refPath; break; case 's': params.resetSpacedSeedParams(); arg >> params.spacedSeed; break; case 't': arg >> params.trim; break; case 'T': arg >> params.tracePath; break; case 'Q': arg >> opt::internalQThreshold; break; case 'v': ++params.verbose; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case MIN_KMER_COV: arg >> params.minCov; break; case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); case QR_SEED: params.resetSpacedSeedParams(); arg >> params.qrSeedLen; break; case CHECKPOINT: arg >> params.readsPerCheckpoint; break; case KEEP_CHECKPOINT: params.keepCheckpoint = true; break; case CHECKPOINT_PREFIX: arg >> params.checkpointPathPrefix; break; case READ_LOG: arg >> params.readLogPath; break; } if (optarg != NULL && (!arg.eof() || arg.fail())) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (params.bloomPath.empty() && params.bloomSize == 0) { cerr << PROGRAM ": missing mandatory option `-b'\n"; die = true; } if (params.bloomPath.empty() && params.k == 0) { cerr << PROGRAM ": missing mandatory option `-k'\n"; die = true; } if (params.k > 0 && params.K > 0 && params.K > params.k / 2) { cerr << PROGRAM ": value of `-K' must be <= k/2\n"; die = true; } if (params.numHashes > MAX_HASHES) { cerr << PROGRAM ": number of hash functions (`-H`) must " "be <= " << MAX_HASHES << " (set by `configure` option " "--enable-max-hashes=N)\n"; die = true; } if (params.k > 0 && params.qrSeedLen > 0 && (params.qrSeedLen < 11 || params.qrSeedLen > params.k / 2)) { cerr << PROGRAM ": value of `--qr-seed' must be >= 11 and <= k/2\n"; die = true; } if (!params.covTrackPath.empty() && params.refPath.empty()) { cerr << PROGRAM ": you must specify a reference with `-R' " "when using `-C'\n"; die = true; } if (params.k > 0 && params.trim == std::numeric_limits::max()) { params.trim = params.k; } 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 (params.threads > 0) omp_set_num_threads(params.threads); #endif /* print contigs to STDOUT unless -o option was set */ ofstream outputFile; if (!params.outputPath.empty()) { outputFile.open(params.outputPath.c_str()); assert_good(outputFile, params.outputPath); } ostream& out = params.outputPath.empty() ? cout : outputFile; /* load the Bloom filter and do the assembly */ if (params.checkpointsEnabled() && checkpointExists(params)) resumeAssemblyFromCheckpoint(argc, argv, params, out); else if (!params.bloomPath.empty()) prebuiltBloomAssembly(argc, argv, params, out); else countingBloomAssembly(argc, argv, params, out); /* cleanup */ if (!params.outputPath.empty()) outputFile.close(); return EXIT_SUCCESS; } abyss-2.2.4/BloomDBG/bloom-dbg.h000066400000000000000000001105371361462241400162520ustar00rootroot00000000000000#ifndef BLOOM_DBG_H #define BLOOM_DBG_H 1 #include "config.h" #include "BloomDBG/AssemblyCounters.h" #include "BloomDBG/AssemblyParams.h" #include "BloomDBG/BloomIO.h" #include "BloomDBG/Checkpoint.h" #include "BloomDBG/MaskedKmer.h" #include "BloomDBG/RollingBloomDBG.h" #include "BloomDBG/RollingHash.h" #include "BloomDBG/RollingHashIterator.h" #include "Common/Hash.h" #include "Common/IOUtil.h" #include "Common/Sequence.h" #include "Common/Uncompress.h" #include "Common/UnorderedSet.h" #include "DataLayer/FastaConcat.h" #include "DataLayer/FastaReader.h" #include "Graph/BreadthFirstSearch.h" #include "Graph/ExtendPath.h" #include "Graph/Path.h" #include "vendor/btl_bloomfilter/BloomFilter.hpp" #include #include #include #include #include #include #if _OPENMP #include #endif #if HAVE_GOOGLE_SPARSE_HASH_MAP #include typedef google::sparse_hash_set> KmerHash; #else #include "Common/UnorderedSet.h" typedef unordered_set> KmerHash; #endif namespace BloomDBG { /** * Type for a vertex in the de Bruijn graph. */ typedef RollingBloomDBGVertex Vertex; /** * Return true if all of the k-mers in `seq` are contained in `bloom` * and false otherwise. */ template inline static bool allKmersInBloom(const Sequence& seq, const BloomT& bloom) { const unsigned k = bloom.getKmerSize(); const unsigned numHashes = bloom.getHashNum(); assert(seq.length() >= k); unsigned validKmers = 0; for (RollingHashIterator it(seq, numHashes, k); it != RollingHashIterator::end(); ++it, ++validKmers) { if (!bloom.contains(*it)) return false; } /* if we skipped over k-mers containing non-ACGT chars */ if (validKmers < seq.length() - k + 1) return false; return true; } /** * Add all k-mers of a DNA sequence to a Bloom filter. */ template inline static void addKmersToBloom(const Sequence& seq, BloomT& bloom) { const unsigned k = bloom.getKmerSize(); const unsigned numHashes = bloom.getHashNum(); for (RollingHashIterator it(seq, numHashes, k); it != RollingHashIterator::end(); ++it) { bloom.insert(*it); } } /** * Returns the sum of all kmer multiplicities in `seq` by querying `bloom` */ template inline static unsigned getSeqAbsoluteKmerCoverage(const Sequence& seq, const CountingBloomT& bloom) { const unsigned k = bloom.getKmerSize(); const unsigned numHashes = bloom.getHashNum(); assert(seq.length() >= k); unsigned coverage = 0; for (RollingHashIterator it(seq, numHashes, k); it != RollingHashIterator::end(); ++it) { coverage += bloom.minCount(*it); } return coverage; } /** * Translate a DNA sequence to an equivalent path in the * de Bruijn graph. */ inline static Path seqToPath(const Sequence& seq, unsigned k, unsigned numHashes) { Path path; assert(seq.length() >= k); for (RollingHashIterator it(seq, numHashes, k); it != RollingHashIterator::end(); ++it) { path.push_back(Vertex(it.kmer().c_str(), it.rollingHash())); } return path; } /** * Translate a path in the de Bruijn graph to an equivalent * DNA sequence. */ inline static Sequence pathToSeq(const Path& path, unsigned k) { assert(path.size() > 0); assert(k > 0); const std::string& spacedSeed = MaskedKmer::mask(); assert(spacedSeed.empty() || spacedSeed.length() == k); Sequence seq; seq.resize(path.size() + k - 1, 'N'); for (size_t i = 0; i < path.size(); ++i) { std::string kmer(path.at(i).kmer().c_str()); for (size_t j = 0; j < k; ++j) { if (spacedSeed.empty() || spacedSeed.at(j) == '1') { if (seq.at(i + j) != 'N' && seq.at(i + j) != kmer.at(j)) { std::cerr << "warning: inconsistent DBG path detected " "at position " << i + j << ": " << seq.substr(0, i + j) << " (orig base: '" << seq.at(i + j) << "'" << ", new base: '" << kmer.at(j) << "')" << std::endl; } seq.at(i + j) = kmer.at(j); } } } return seq; } enum SeedType { ST_BRANCH_KMER = 0, ST_READ }; static inline std::string seedTypeStr(const SeedType& type) { switch (type) { case ST_BRANCH_KMER: return "BRANCH_KMER"; case ST_READ: return "READ"; default: break; } assert(false); } /** * Results for the extension of a read segment. * Each instance represents a row in the trace file generated * by the '-T' option for abyss-bloom-dbg. */ struct ContigRecord { /** output FASTA ID for this contig */ size_t contigID; /** length of contig (bp) */ unsigned length; /** coverage of contig */ unsigned coverage; /** FASTA ID of seeding read */ std::string readID; /** Type of sequence used to seed contig (branch k-mer or full read) */ SeedType seedType; /** Starting sequence prior to extensions */ Sequence seed; /** Result code for attempted left sequence extension (e.g. DEAD END) */ PathExtensionResult leftExtensionResult; /** Result code for attempted left sequence extension (e.g. DEAD END) */ PathExtensionResult rightExtensionResult; /** * True if the extended sequence was excluded from the output contigs * because it was redundant. (An identical sequence was generated * when extending a previous read.) */ bool redundant; ContigRecord() : contigID(std::numeric_limits::max()) , readID() , leftExtensionResult(std::make_pair(0, ER_DEAD_END)) , rightExtensionResult(std::make_pair(0, ER_DEAD_END)) , redundant(false) {} static std::ostream& printHeaders(std::ostream& out) { out << "contig_id" << '\t' << "length" << '\t' << "redundant" << '\t' << "read_id" << '\t' << "left_result" << '\t' << "left_extension" << '\t' << "right_result" << '\t' << "right_extension" << '\t' << "seed_type" << '\t' << "seed_length" << '\t' << "seed" << '\n'; return out; } friend std::ostream& operator<<(std::ostream& out, const ContigRecord& o) { if (o.redundant) out << "NA" << '\t'; else out << o.contigID << '\t'; out << o.length << '\t' << o.redundant << '\t' << o.readID << '\t'; if (o.leftExtensionResult.first > 0) out << pathExtensionResultStr(o.leftExtensionResult.second) << '\t' << o.leftExtensionResult.first << '\t'; else out << "NA" << '\t' << "NA" << '\t'; if (o.rightExtensionResult.first > 0) out << pathExtensionResultStr(o.rightExtensionResult.second) << '\t' << o.rightExtensionResult.first << '\t'; else out << "NA" << '\t' << "NA" << '\t'; out << seedTypeStr(o.seedType) << '\t' << o.seed.length() << '\t' << o.seed << '\n'; return out; } }; enum ReadResult { RR_UNINITIALIZED = 0, RR_SHORTER_THAN_K, RR_NON_ACGT, RR_BLUNT_END, RR_NOT_SOLID, RR_ALL_KMERS_VISITED, RR_ALL_BRANCH_KMERS_VISITED, RR_GENERATED_CONTIGS }; static inline std::string readResultStr(const ReadResult& result) { switch (result) { case RR_UNINITIALIZED: return "NA"; case RR_SHORTER_THAN_K: return "SHORTER_THAN_K"; case RR_NON_ACGT: return "NON_ACGT"; case RR_BLUNT_END: return "BLUNT_END"; case RR_NOT_SOLID: return "NOT_SOLID"; case RR_ALL_KMERS_VISITED: return "ALL_KMERS_VISITED"; case RR_ALL_BRANCH_KMERS_VISITED: return "ALL_BRANCH_KMERS_VISITED"; case RR_GENERATED_CONTIGS: return "GENERATED_CONTIGS"; default: break; } assert(false); } /** * Records results of processing a sequencing read. * Each instance represents a row in the read log file generated * by the `--read-log` option of `abyss-bloom-dbg`. */ struct ReadRecord { /** FASTA ID for this read */ std::string readID; /** outcome of processing the read */ ReadResult result; ReadRecord() : readID() , result(RR_UNINITIALIZED) {} ReadRecord(const std::string& readID) : readID(readID) , result(RR_UNINITIALIZED) {} ReadRecord(const std::string& readID, ReadResult result) : readID(readID) , result(result) {} static std::ostream& printHeaders(std::ostream& out) { out << "read_id" << '\t' << "result" << '\n'; return out; } friend std::ostream& operator<<(std::ostream& out, const ReadRecord& o) { out << o.readID << '\t' << readResultStr(o.result) << '\n'; return out; } }; /** Print an intermediate progress message during assembly */ void readsProgressMessage(AssemblyCounters counters) { std::cerr << "Processed " << counters.readsProcessed << " reads" << ", solid reads: " << counters.solidReads << " (" << std::setprecision(3) << (float)100 * counters.solidReads / counters.readsProcessed << "%)" << ", visited reads: " << counters.visitedReads << " (" << std::setprecision(3) << (float)100 * counters.visitedReads / counters.readsProcessed << "%)" << std::endl; } /** Print an intermediate progress message during assembly */ void basesProgressMessage(AssemblyCounters counters) { std::cerr << "Assembled " << counters.basesAssembled << " bp in " << counters.contigID + 1 << " contigs" << std::endl; } /** * Split a path at branching k-mers (degree > 2). */ template inline static std::vector::vertex_descriptor>> splitPath( const Path::vertex_descriptor>& path, const GraphT& dbg, unsigned minBranchLen) { assert(path.size() > 0); typedef typename boost::graph_traits::vertex_descriptor V; typedef typename Path::const_iterator PathIt; std::vector> splitPaths; Path currentPath; for (PathIt it = path.begin(); it != path.end(); ++it) { currentPath.push_back(*it); unsigned inDegree = trueBranches(*it, REVERSE, dbg, minBranchLen).size(); unsigned outDegree = trueBranches(*it, FORWARD, dbg, minBranchLen).size(); if (inDegree > 1 || outDegree > 1) { /* we've hit a branching point -- end the current * path and start a new one */ splitPaths.push_back(currentPath); currentPath.clear(); currentPath.push_back(*it); } } if (currentPath.size() > 1 || splitPaths.empty()) splitPaths.push_back(currentPath); assert(splitPaths.size() >= 1); return splitPaths; } /** * Trim a sequence down to the longest contiguous subsequence * of "good" k-mers. If the sequence has length < k or contains * no good k-mers, the trimmed sequence will be the empty string. * * @param seq the DNA sequence to be trimmed * @param goodKmerSet Bloom filter containing "good" k-mers */ template static inline void trimSeq(Sequence& seq, const BloomT& goodKmerSet) { const unsigned k = goodKmerSet.getKmerSize(); const unsigned numHashes = goodKmerSet.getHashNum(); if (seq.length() < k) { seq.clear(); return; } const unsigned UNSET = UINT_MAX; unsigned prevPos = UNSET; unsigned matchStart = UNSET; unsigned matchLen = 0; unsigned maxMatchStart = UNSET; unsigned maxMatchLen = 0; /* note: RollingHashIterator skips over k-mer * positions with non-ACGT chars */ for (RollingHashIterator it(seq, numHashes, k); it != RollingHashIterator::end(); prevPos = it.pos(), ++it) { if (!goodKmerSet.contains(*it) || (prevPos != UNSET && it.pos() - prevPos > 1)) { /* end any previous match */ if (matchStart != UNSET && matchLen > maxMatchLen) { maxMatchLen = matchLen; maxMatchStart = matchStart; } matchStart = UNSET; matchLen = 0; } if (goodKmerSet.contains(*it)) { /* initiate or extend match */ if (matchStart == UNSET) matchStart = it.pos(); matchLen++; } } /* handles case last match extends to end of seq */ if (matchStart != UNSET && matchLen > maxMatchLen) { maxMatchLen = matchLen; maxMatchStart = matchStart; } /* if there were no matching k-mers */ if (maxMatchLen == 0) { seq.clear(); return; } /* trim read down to longest matching subseq */ seq = seq.substr(maxMatchStart, maxMatchLen + k - 1); } /** * Append a contig to the output FASTA stream. */ inline static void printContig( const Sequence& seq, unsigned length, unsigned coverage, size_t contigID, const std::string& readID, unsigned k, std::ostream& out) { assert(seq.length() >= k); FastaRecord contig; /* set FASTA id */ std::ostringstream id; id << contigID; /* add FASTA comment indicating extended read id */ std::ostringstream comment; comment << length << ' ' << coverage << ' '; comment << "read:" << readID; assert(id.good()); contig.id = id.str(); contig.comment = comment.str(); /* set seq */ contig.seq = seq; /* output FASTQ record */ out << contig; assert(out); } /** * Return true if the left end of the given sequence is a blunt end * in the Bloom filterde Bruijn graph. PRECONDITION: `seq` does not contain * any non-ACGT chars. */ template inline static unsigned leftIsBluntEnd(const Sequence& seq, const GraphT& graph, const AssemblyParams& params) { unsigned k = params.k; unsigned numHashes = params.numHashes; unsigned fpLookAhead = 5; if (seq.length() < k) return false; Sequence firstKmerStr(seq, 0, k); Path path = seqToPath(firstKmerStr, k, numHashes); Vertex& firstKmer = path.front(); return !lookAhead(firstKmer, REVERSE, fpLookAhead, graph); } /** * Return true if the left and/or right end of the sequence is a blunt * end in the de Bruijn graph. Such reads likely have read errors * and thus we should not try to extend these into contings. * When testing for a blunt end, we account for the possibility of * false positive extensions by using a small amount of look-ahead * (as dictated by params.fpLookAhead). */ template inline static bool hasBluntEnd(const Sequence& seq, const GraphT& graph, const AssemblyParams& params) { if (leftIsBluntEnd(seq, graph, params)) return true; Sequence rc = reverseComplement(seq); if (leftIsBluntEnd(rc, graph, params)) return true; return false; } /** * Output a contig sequence if it is not redundant, i.e. it has not already * been generated from a different read / thread of execution. */ template inline static void outputContig( const Path& contigPath, ContigRecord& rec, SolidKmerSetT& solidKmerSet, AssembledKmerSetT& assembledKmerSet, KmerHash& contigEndKmers, const AssemblyParams& params, AssemblyCounters& counters, AssemblyStreamsT& streams) { const unsigned fpLookAhead = 5; Sequence seq = pathToSeq(contigPath, params.k); /* vertices representing start/end k-mers of contig */ Sequence kmer1 = seq.substr(0, params.k); canonicalize(kmer1); RollingHash hash1(kmer1.c_str(), params.numHashes, params.k); Vertex v1(kmer1.c_str(), hash1); Sequence kmer2 = seq.substr(seq.length() - params.k); canonicalize(kmer2); RollingHash hash2(kmer2.c_str(), params.numHashes, params.k); Vertex v2(kmer2.c_str(), hash2); bool redundant = false; #pragma omp critical(redundancyCheck) { /* * If we use `assembledKmerSet` to check very short contigs, * we may get full-length matches purely due to Bloom filter * positives. For such contigs, we additionally track * the start and end in a separate hash table called * `contigEndKmers`. */ if (seq.length() < params.k + fpLookAhead - 1) { if (contigEndKmers.find(v1) != contigEndKmers.end() && contigEndKmers.find(v2) != contigEndKmers.end()) { redundant = true; } else { contigEndKmers.insert(v1); contigEndKmers.insert(v2); } } else if (allKmersInBloom(seq, assembledKmerSet)) { redundant = true; } if (!redundant) { /* mark remaining k-mers as assembled */ addKmersToBloom(seq, assembledKmerSet); } } rec.redundant = redundant; if (!redundant) { #pragma omp critical(fasta) { rec.length = seq.length(); rec.coverage = getSeqAbsoluteKmerCoverage(seq, solidKmerSet); /* add contig to output FASTA */ printContig(seq, rec.length, rec.coverage, counters.contigID, rec.readID, params.k, streams.out); /* add contig to checkpoint FASTA file */ if (params.checkpointsEnabled()) printContig(seq, rec.length, rec.coverage, counters.contigID, rec.readID, params.k, streams.checkpointOut); rec.contigID = counters.contigID; counters.contigID++; counters.basesAssembled += seq.length(); } } #pragma omp critical(trace) streams.traceOut << rec; } enum ContigType { CT_LINEAR, CT_CIRCULAR, CT_HAIRPIN }; template static inline ContigType getContigType(const Path& contigPath, const GraphT& dbg) { if (edge(contigPath.back(), contigPath.front(), dbg).second) { Vertex v = contigPath.front().clone(); v.shift(ANTISENSE, contigPath.back().kmer().getBase(0)); if (v.kmer() == contigPath.back().kmer()) return CT_CIRCULAR; else return CT_HAIRPIN; } return CT_LINEAR; } /** Special case behaviour for circular/hairpin contigs */ template static inline void preprocessCircularContig(Path& contigPath, const GraphT& dbg, unsigned trim) { assert(!contigPath.empty()); ContigType contigType = getContigType(contigPath, dbg); assert(contigType != CT_LINEAR); if (contigPath.size() <= 2) return; /* longest branch of Bloom filter positives */ const unsigned fpTrim = 5; /* * Note: A circular/hairpin contig contains at most two branch k-mers. * And if it does contain branch k-mers, they will be the first/last * k-mers. * * If only one end of the circular/hairpin contig is a branch k-mer, * add that k-mer to the other end of the contig as well. This * enables the usual branch k-mer trimming logic for linear contigs to * produce the correct results downstream. */ bool branchStart = ambiguous(contigPath.front(), FORWARD, dbg, trim, fpTrim) || ambiguous(contigPath.front(), REVERSE, dbg, trim, fpTrim); bool branchEnd = ambiguous(contigPath.back(), FORWARD, dbg, trim, fpTrim) || ambiguous(contigPath.back(), REVERSE, dbg, trim, fpTrim); if (branchStart && !branchEnd) { if (contigType == CT_CIRCULAR) { contigPath.push_back(contigPath.front()); } else { assert(contigType == CT_HAIRPIN); Vertex rc = contigPath.front().clone(); rc.reverseComplement(); contigPath.push_back(rc); } } else if (!branchStart && branchEnd) { if (contigType == CT_CIRCULAR) { contigPath.push_front(contigPath.back()); } else { assert(contigType == CT_HAIRPIN); Vertex rc = contigPath.back().clone(); rc.reverseComplement(); contigPath.push_front(rc); } } } /** * Ensure that branching k-mers are not repeated in the output * contigs by selectively trimming contig ends. * * The idea is to keep a branch k-mer at the end of contig only * if the edge leading up to it is unambigous. For example, in the * diagram below the contig generated from the right side would * include the branching k-mer k5, whereas the two contigs entering * on the left would discard it: * * ...-k1-k2 * \ * k5-k6-... * / * ...-k3-k4 * * If a branch k-mer has both indegree > 1 and outdegree > 1, it is * output separately as its own contig of length k. */ template inline static void trimBranchKmers(Path& contigPath, const GraphT& dbg, unsigned trim) { assert(!contigPath.empty()); if (contigPath.size() == 1) return; /* special case: circular/hairpin contigs */ ContigType contigType = getContigType(contigPath, dbg); if (contigType == CT_CIRCULAR || contigType == CT_HAIRPIN) preprocessCircularContig(contigPath, dbg, trim); unsigned l = contigPath.size(); /* longest branch of Bloom filter false positives */ const unsigned fpTrim = 5; bool ambiguous1 = ambiguous(contigPath.at(0), contigPath.at(1), FORWARD, dbg, trim, fpTrim); bool ambiguous2 = ambiguous(contigPath.at(l - 1), contigPath.at(l - 2), REVERSE, dbg, trim, fpTrim); if (ambiguous1) contigPath.pop_front(); assert(!contigPath.empty()); if (ambiguous2) contigPath.pop_back(); assert(!contigPath.empty()); } bool isTip( unsigned length, PathExtensionResultCode leftResult, PathExtensionResultCode rightResult, unsigned trim) { if (length > trim) return false; if (leftResult == ER_DEAD_END && (rightResult == ER_DEAD_END || rightResult == ER_AMBI_IN)) return true; if (rightResult == ER_DEAD_END && (leftResult == ER_DEAD_END || leftResult == ER_AMBI_IN)) return true; return false; } /** * Decide if a read should be extended and if so extend it into a contig. */ template static inline ReadRecord processRead( const FastaRecord& rec, const SolidKmerSetT& solidKmerSet, AssembledKmerSetT& assembledKmerSet, KmerHash& contigEndKmers, KmerHash& visitedBranchKmers, const AssemblyParams& params, AssemblyCounters& counters, AssemblyStreamsT& streams) { (void)visitedBranchKmers; typedef typename Path::iterator PathIt; /* Boost graph API for Bloom filter */ RollingBloomDBG dbg(solidKmerSet); unsigned k = params.k; const Sequence& seq = rec.seq; /* we can't extend reads shorter than k */ if (seq.length() < k) return ReadRecord(rec.id, RR_SHORTER_THAN_K); /* skip reads with non-ACGT chars */ if (!allACGT(seq)) return ReadRecord(rec.id, RR_NON_ACGT); /* don't extend reads that are tips */ if (hasBluntEnd(seq, dbg, params)) return ReadRecord(rec.id, RR_BLUNT_END); /* only extend "solid" reads */ if (!allKmersInBloom(seq, solidKmerSet)) return ReadRecord(rec.id, RR_NOT_SOLID); #pragma omp atomic counters.solidReads++; /* skip reads in previously assembled regions */ if (allKmersInBloom(seq, assembledKmerSet)) { #pragma omp atomic counters.visitedReads++; return ReadRecord(rec.id, RR_ALL_KMERS_VISITED); } /* * We use `assembledKmers` to track read k-mers * that have already been included in the output contigs, and * therefore do not need to be processed (extended) again. * Note that we do not use `assembledKmerSet` (a Bloom filter) * for this purpose because Bloom filter false positives * may cause us to omit short contigs (e.g. contigs with length k). */ unordered_set assembledKmers; Path path = seqToPath(rec.seq, params.k, params.numHashes); for (PathIt it = path.begin(); it != path.end(); ++it) { if (assembledKmers.find(*it) != assembledKmers.end()) continue; ExtendPathParams extendParams; extendParams.trimLen = params.trim; extendParams.fpTrim = 5; extendParams.maxLen = NO_LIMIT; extendParams.lookBehind = true; extendParams.lookBehindStartVertex = false; ContigRecord contigRec; contigRec.readID = rec.id; contigRec.seedType = ST_READ; contigRec.seed = it->kmer().c_str(); Path contigPath; contigPath.push_back(*it); contigRec.leftExtensionResult = extendPath(contigPath, REVERSE, dbg, extendParams); contigRec.rightExtensionResult = extendPath(contigPath, FORWARD, dbg, extendParams); PathExtensionResultCode leftResult = contigRec.leftExtensionResult.second; PathExtensionResultCode rightResult = contigRec.rightExtensionResult.second; if (!isTip(contigPath.size(), leftResult, rightResult, params.trim)) { /* selectively trim branch k-mers from contig ends */ trimBranchKmers(contigPath, dbg, params.trim); /* output contig to FASTA file */ outputContig( contigPath, contigRec, solidKmerSet, assembledKmerSet, contigEndKmers, params, counters, streams); } /* mark contig k-mers as visited */ for (PathIt it2 = contigPath.begin(); it2 != contigPath.end(); ++it2) assembledKmers.insert(*it2); } return ReadRecord(rec.id, RR_GENERATED_CONTIGS); } /** * Perform a Bloom-filter-based de Bruijn graph assembly. * Contigs are generated by extending reads left/right within * the de Bruijn graph, up to the next branching point or dead end. * Short branches due to Bloom filter false positives are * ignored. * * @param argc number of input FASTA files * @param argv array of input FASTA filenames * @param genomeSize approx genome size * @param goodKmerSet Bloom filter containing k-mers that * occur more than once in the input data * @param out output stream for contigs (FASTA) * @param verbose set to true to print progress messages to * STDERR */ template inline static void assemble( int argc, char** argv, SolidKmerSetT& solidKmerSet, const AssemblyParams& params, std::ostream& out) { /* k-mers in previously assembled contigs */ BloomFilter assembledKmerSet( solidKmerSet.size(), solidKmerSet.getHashNum(), solidKmerSet.getKmerSize()); /* counters for progress messages */ AssemblyCounters counters; /* input reads */ FastaConcat in(argv, argv + argc, FastaReader::FOLD_CASE); /* duplicate FASTA output for checkpoints */ std::ofstream checkpointOut; if (params.checkpointsEnabled()) { assert(!params.checkpointPathPrefix.empty()); std::string path = params.checkpointPathPrefix + CHECKPOINT_FASTA_EXT + CHECKPOINT_TMP_EXT; checkpointOut.open(path.c_str()); assert_good(checkpointOut, path); } /* trace file output ('-T' option) */ std::ofstream traceOut; if (!params.tracePath.empty()) { traceOut.open(params.tracePath.c_str()); assert_good(traceOut, params.tracePath); ContigRecord::printHeaders(traceOut); assert_good(traceOut, params.tracePath); } /* logs outcome of processing of each read (`--read-log`) */ std::ofstream readLogOut; if (!params.readLogPath.empty()) { readLogOut.open(params.readLogPath.c_str()); assert_good(readLogOut, params.readLogPath); ReadRecord::printHeaders(readLogOut); assert_good(readLogOut, params.readLogPath); } /* bundle output streams */ AssemblyStreams streams(in, out, checkpointOut, traceOut, readLogOut); /* run the assembly */ assemble(solidKmerSet, assembledKmerSet, counters, params, streams); } /** * Perform a Bloom-filter-based de Bruijn graph assembly. * Contigs are generated by extending reads left/right within * the de Bruijn graph, up to the next branching point or dead end. * Short branches due to Bloom filter false positives are * ignored. * * @param argc number of input FASTA files * @param argv array of input FASTA filenames * @param genomeSize approx genome size * @param goodKmerSet Bloom filter containing k-mers that * occur more than once in the input data * @param assembledKmerSet Bloom filter containing k-mers that have * already been included in contigs * @param in input stream for sequencing reads (FASTA) * @param out output stream for contigs (FASTA) * @param verbose set to true to print progress messages to * STDERR */ template inline static void assemble( const SolidKmerSetT& goodKmerSet, AssembledKmerSetT& assembledKmerSet, AssemblyCounters& counters, const AssemblyParams& params, AssemblyStreams& streams) { assert(params.initialized()); /* per-thread I/O buffer (size is in bases) */ const size_t SEQ_BUFFER_SIZE = 1000000; if (params.verbose) std::cerr << "Trimming branches " << params.trim << " k-mers or shorter" << std::endl; InputReadStreamT& in = streams.in; std::ostream& checkpointOut = streams.checkpointOut; KmerHash contigEndKmers; contigEndKmers.rehash((size_t)pow(2, 28)); KmerHash visitedBranchKmers; /* * Print a progress message whenever `READS_PROGRESS_STEP` * reads have been processed or `BASES_PROGRESS_STEP` * bases have been assembled. The purpose of using * two measures of progess is to show steady updates * throughout the assembly process. */ const size_t READS_PROGRESS_STEP = 100000; const size_t BASES_PROGRESS_STEP = 1000000; size_t basesProgressLine = BASES_PROGRESS_STEP; while (true) { size_t readsUntilCheckpoint = params.readsPerCheckpoint; #pragma omp parallel for (std::vector buffer;;) { /* read sequences in batches to reduce I/O contention */ buffer.clear(); size_t bufferSize; bool good = true; #pragma omp critical(in) for (bufferSize = 0; bufferSize < SEQ_BUFFER_SIZE && readsUntilCheckpoint > 0;) { FastaRecord rec; good = in >> rec; if (!good) break; #pragma omp atomic readsUntilCheckpoint--; buffer.push_back(rec); bufferSize += rec.seq.length(); } if (buffer.size() == 0) break; for (std::vector::iterator it = buffer.begin(); it != buffer.end(); ++it) { ReadRecord result = processRead( *it, goodKmerSet, assembledKmerSet, contigEndKmers, visitedBranchKmers, params, counters, streams); #pragma omp critical(readsProgress) { ++counters.readsProcessed; if (params.verbose && counters.readsProcessed % READS_PROGRESS_STEP == 0) readsProgressMessage(counters); } if (params.verbose) #pragma omp critical(basesProgress) { if (counters.basesAssembled >= basesProgressLine) { basesProgressMessage(counters); while (counters.basesAssembled >= basesProgressLine) basesProgressLine += BASES_PROGRESS_STEP; } } if (!params.readLogPath.empty()) { #pragma omp critical(readLog) streams.readLogOut << result; } } } /* for batch of reads between I/O operations */ if (readsUntilCheckpoint > 0) { assert(in.eof()); break; } /* save assembly state to checkpoint files */ checkpointOut.flush(); createCheckpoint(goodKmerSet, assembledKmerSet, counters, params); } /* for each batch of reads between checkpoints */ assert(in.eof()); if (params.verbose) { readsProgressMessage(counters); basesProgressMessage(counters); std::cerr << "Assembly complete" << std::endl; } if (params.checkpointsEnabled() && !params.keepCheckpoint) removeCheckpointData(params); } /** * Visitor class that outputs visited nodes/edges in GraphViz format during * a breadth first traversal. An instance of this class may be passed * as an argument to the `breadthFirstSearch` function. */ template class GraphvizBFSVisitor : public DefaultBFSVisitor { typedef typename boost::graph_traits::vertex_descriptor VertexT; typedef typename boost::graph_traits::edge_descriptor EdgeT; public: /** Constructor */ GraphvizBFSVisitor(std::ostream& out) : m_out(out) , m_nodesVisited(0) , m_edgesVisited(0) { /* start directed graph (GraphViz) */ m_out << "digraph g {\n"; } /** Destructor */ ~GraphvizBFSVisitor() { /* end directed graph (GraphViz) */ m_out << "}\n"; } /** Invoked when a vertex is visited for the first time */ BFSVisitorResult discover_vertex(const VertexT& v, const GraphT&) { ++m_nodesVisited; /* declare vertex (GraphViz) */ m_out << '\t' << v.kmer().c_str() << ";\n"; return BFS_SUCCESS; } /** * Invoked when an edge is traversed. (Each edge * in the graph is traversed exactly once.) */ BFSVisitorResult examine_edge(const EdgeT& e, const GraphT& g) { ++m_edgesVisited; const VertexT& u = source(e, g); const VertexT& v = target(e, g); /* declare edge (GraphViz) */ m_out << '\t' << u.kmer().c_str() << " -> " << v.kmer().c_str() << ";\n"; return BFS_SUCCESS; } /** Return number of distinct nodes visited */ size_t getNumNodesVisited() const { return m_nodesVisited; } /** Get number of distinct edges visited */ size_t getNumEdgesVisited() const { return m_edgesVisited; } protected: /** output stream for GraphViz serialization */ std::ostream& m_out; /** number of nodes visited so far */ size_t m_nodesVisited; /** number of edges visited so far */ size_t m_edgesVisited; }; /** * Output a GraphViz serialization of the de Bruijn graph * using FASTA files and a Bloom filter as input. * * @param argc number of input FASTA files * @param argv array of input FASTA filenames * @param kmerSet Bloom filter containing valid k-mers * @param out output stream for GraphViz serialization * @param verbose prints progress messages to STDERR if true */ template static inline void outputGraph( int argc, char** argv, const BloomT& kmerSet, const AssemblyParams& params, std::ostream& out) { assert(params.initialized()); typedef RollingBloomDBG GraphT; /* interval for progress messages */ const unsigned progressStep = 1000; const unsigned k = kmerSet.getKmerSize(); const unsigned numHashes = kmerSet.getHashNum(); /* counter for progress messages */ size_t readsProcessed = 0; /* Boost graph API over rolling hash Bloom filter */ GraphT dbg(kmerSet); /* Marks visited nodes in breadth-first traversal */ DefaultColorMap colorMap; /* BFS Visitor -- generates GraphViz output as nodes * and edges are traversed. */ GraphvizBFSVisitor visitor(out); if (params.verbose) std::cerr << "Generating GraphViz output..." << std::endl; FastaConcat in(argv, argv + argc, FastaReader::FOLD_CASE); for (FastaRecord rec;;) { bool good; good = in >> rec; if (!good) break; Sequence& seq = rec.seq; /* Trim down to longest subsequence of "good" k-mers */ trimSeq(seq, kmerSet); if (seq.length() > 0) { /* BFS traversal in forward dir */ std::string startKmer = seq.substr(0, k); Vertex start(startKmer.c_str(), RollingHash(startKmer, numHashes, k)); breadthFirstSearch(start, dbg, colorMap, visitor); /* BFS traversal in reverse dir */ Sequence rcSeq = reverseComplement(seq); std::string rcStartKmer = rcSeq.substr(0, k); Vertex rcStart(rcStartKmer.c_str(), RollingHash(rcStartKmer, numHashes, k)); breadthFirstSearch(rcStart, dbg, colorMap, visitor); } if (++readsProcessed % progressStep == 0 && params.verbose) { std::cerr << "processed " << readsProcessed << " (k-mers visited: " << visitor.getNumNodesVisited() << ", edges visited: " << visitor.getNumEdgesVisited() << ")" << std::endl; } } assert(in.eof()); if (params.verbose) { std::cerr << "processed " << readsProcessed << " reads (k-mers visited: " << visitor.getNumNodesVisited() << ", edges visited: " << visitor.getNumEdgesVisited() << ")" << std::endl; std::cerr << "GraphViz generation complete" << std::endl; } } /** * Write a single block of a 'variableStep' WIG file. * * @param chr chromosome name * @param start start coordinate of block * @param length length of block * @param val value of block * @param out output stream for WIG file * @param outPath path for output WIG file */ static inline void outputWigBlock( const std::string& chr, size_t start, size_t length, unsigned val, ostream& out, const std::string& outPath) { assert(length > 0); out << "variableStep chrom=" << chr << " span=" << length << "\n"; out << start << ' ' << val << '\n'; assert_good(out, outPath); } /** * Write a WIG file for a reference genome, using the values 0 and 1 * to indicate whether or not a given k-mer had sufficient coverage * in the reads to exceed the minimum coverage threshold. * * @param goodKmerSet Bloom filter of k-mers that exceed the * minimum coverage threshold * @param params encapsulates all command line options for the * assembly, including the reference genome and the output path * for the WIG file. */ template static inline void writeCovTrack(const BloomT& goodKmerSet, const AssemblyParams& params) { assert(!params.covTrackPath.empty()); assert(!params.refPath.empty()); const unsigned k = goodKmerSet.getKmerSize(); const unsigned numHashes = goodKmerSet.getHashNum(); std::ofstream covTrack(params.covTrackPath.c_str()); assert_good(covTrack, params.covTrackPath); if (params.verbose) std::cerr << "Writing 0/1 k-mer coverage track for `" << params.refPath << "` to `" << params.covTrackPath << "`" << std::endl; FastaReader ref(params.refPath.c_str(), FastaReader::FOLD_CASE); for (FastaRecord rec; ref >> rec;) { std::string chr = rec.id; bool firstVal = true; size_t blockStart = 1; size_t blockLength = 0; uint8_t blockVal = 0; for (RollingHashIterator it(rec.seq, numHashes, k); it != RollingHashIterator::end(); ++it) { uint8_t val = goodKmerSet.contains(*it) ? 1 : 0; if (firstVal) { firstVal = false; /* WIG standard uses 1-based coords */ blockStart = it.pos() + 1; blockLength = 1; blockVal = val; } else if (val != blockVal) { assert(firstVal == false); outputWigBlock( chr, blockStart, blockLength, blockVal, covTrack, params.covTrackPath); /* WIG standard uses 1-based coords */ blockStart = it.pos() + 1; blockLength = 1; blockVal = val; } else { blockLength++; } } /* output last block */ if (blockLength > 0) { outputWigBlock(chr, blockStart, blockLength, blockVal, covTrack, params.covTrackPath); } } assert(ref.eof()); assert_good(covTrack, params.covTrackPath); covTrack.close(); } } /* BloomDBG namespace */ #endif abyss-2.2.4/CITATION.bib000066400000000000000000000010541361462241400145330ustar00rootroot00000000000000@article{Jackman_2017, title={ABySS 2.0: resource-efficient assembly of large genomes using a Bloom filter}, volume={27}, ISSN={1549-5469}, url={http://doi.org/10.1101/gr.214346.116}, DOI={10.1101/gr.214346.116}, number={5}, journal={Genome Research}, publisher={Cold Spring Harbor Laboratory}, author={Jackman, Shaun D. and Vandervalk, Benjamin P. and Mohamadi, Hamid and Chu, Justin and Yeo, Sarah and Hammond, S. Austin and Jahesh, Golnaz and Khan, Hamza and Coombe, Lauren and Warren, Rene L. and et al.}, year={2017}, month={Feb}, pages={768–777} } abyss-2.2.4/CITATION.md000066400000000000000000000035051361462241400144020ustar00rootroot00000000000000# Citation Shaun D Jackman, Benjamin P Vandervalk, Hamid Mohamadi, Justin Chu, Sarah Yeo, S Austin Hammond, Golnaz Jahesh, Hamza Khan, Lauren Coombe, René L Warren, and Inanc Birol (2017). **ABySS 2.0: Resource-efficient assembly of large genomes using a Bloom filter**. *Genome research*, 27(5), 768-777. [doi:10.1101/gr.214346.116](http://doi.org/10.1101/gr.214346.116) - [PDF](http://genome.cshlp.org/content/27/5/768.full.pdf) - [Genome Research](http://genome.cshlp.org/content/27/5/768) - [PubMed PMID: 28232478](https://www.ncbi.nlm.nih.gov/pubmed/28232478) - [Google Scholar](http://scholar.google.ca/scholar?q=10.1101/gr.214346.116) # BibTeX ```bibtex @article{Jackman_2017, title={ABySS 2.0: resource-efficient assembly of large genomes using a Bloom filter}, volume={27}, ISSN={1549-5469}, url={http://doi.org/10.1101/gr.214346.116}, DOI={10.1101/gr.214346.116}, number={5}, journal={Genome Research}, publisher={Cold Spring Harbor Laboratory}, author={Jackman, Shaun D. and Vandervalk, Benjamin P. and Mohamadi, Hamid and Chu, Justin and Yeo, Sarah and Hammond, S. Austin and Jahesh, Golnaz and Khan, Hamza and Coombe, Lauren and Warren, Rene L. and et al.}, year={2017}, month={Feb}, pages={768–777} } ``` # MLA Jackman, Shaun D., et al. "ABySS 2.0: resource-efficient assembly of large genomes using a Bloom filter." Genome research 27.5 (2017): 768-777. # APA Jackman, S. D., Vandervalk, B. P., Mohamadi, H., Chu, J., Yeo, S., Hammond, S. A., ... & Birol, I. (2017). ABySS 2.0: resource-efficient assembly of large genomes using a Bloom filter. Genome research, 27(5), 768-777. # Chicago Jackman, Shaun D., Benjamin P. Vandervalk, Hamid Mohamadi, Justin Chu, Sarah Yeo, S. Austin Hammond, Golnaz Jahesh et al. "ABySS 2.0: resource-efficient assembly of large genomes using a Bloom filter." Genome research 27, no. 5 (2017): 768-777. abyss-2.2.4/COPYRIGHT000066400000000000000000000145471361462241400141510ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: ABySS Upstream-Contact: Shaun Jackman Source: https://github.com/bcgsc/abyss License: GPL-3 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, version 3. . 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 . . For commercial licensing options, please contact Patrick Rebstein Files: * Copyright: Copyright 2016 British Columbia Cancer Agency Branch License: GPL-3 Files: Layout/* Copyright: Copyright 2012 Shaun Jackman License: GPL-3 Files: vendor/btl_bloomfilter/* Copyright: Copyright 2016 Justin Chu License: GPL-3 Files: vendor/nthash/* Copyright: Copyright 2016 Hamid Mohamadi License: GPL-3 Files: Common/cholesky.hpp Copyright: Copyright 2005 Gunter Winkler, Konstantin Kutzkow License: LGPL-2.1+ Files: Common/city.cc Common/city.h Copyright: Copyright 2011 Google, Inc. License: Expat Files: dialign/* Copyright: Copyright 2008 Amarendran R. Subramanian License: LGPL-2.1+ License: LGPL-2.1+ On Debian systems, see `/usr/share/common-licenses/LGPL-2.1'. . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. . This library 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 Lesser General Public License for more details. . You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . Amarendran R. Subramanian, hereby disclaims all copyright interest in the DIALIGN-TX (a multiple sequence alignment algorithm) written by Amarendran R. Subramanian. . Amarendran R. Subramanian, 2004-2008 . DIALIGN-TX has been co-authored by Volker Menrad and Dorothea Emig. . Research work using DIALIGN-TX should cite: . DIALIGN-TX: improvement of the segment-based approach for multiple sequence alignment by combining greedy and progressive alignment strategies Amarendran R. Subramanian, Michael Kaufmann, Burkhard Morgenstern, Algorithms for Molecular Biology 3:6, 2008 . DIALIGN-T: An improved algorithm for segment-based multiple sequence alignment Amarendran R. Subramanian, Jan Weyer-Menkhoff, Michael Kaufmann, Burkhard Morgenstern, BMC Bioinformatics 6:66, 2005 Files: FMIndex/bit_array.h Copyright: Copyright 2010 Daisuke Okanohara License: BSD-3-clause 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 the authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. Files: FMIndex/sais.hxx Copyright: Copyright 2010 Yuta Mori License: Expat License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Files: vendor/gtest-*/* Copyright: Copyright 2008 Google Inc. License: BSD-3-clause 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. abyss-2.2.4/ChangeLog000066400000000000000000001415421361462241400144240ustar00rootroot000000000000002020-01-30 Johnathan Wong * Release version 2.2.4 General: * Refactor deprecated functions in clang-8 Sealer: * Remove unsupported -D option from help page abyss-bloom: * Add counting Bloom Filter instruction to help page abyss-bloom-dbg: * Report coverage information of unitigs 2019-09-20 Johnathan Wong * Release version 2.2.3 * Revert memory consumption of Bloom filters to pre 2.2.0 behaviour ABySS will now share the specified memory among all Bloom filters instead of just the counting Bloom filter. * Fix gcc-9 compilation warnings 2019-08-16 Johnathan Wong * Release version 2.2.2 * Fix abyss-overlap for 32-bit systems 2019-08-12 Johnathan Wong * Release version 2.2.1 * Fix abyss-bloom for macOS 2019-08-01 Johnathan Wong * Release version 2.2.0 * Construct a counting Bloom filter instead of a cascading Bloom filter. abyss-bloom: * Add 'counting' as valid argument to '-t' option to build a counting bloom filter 2018-12-04 Sauparna Palchowdhury * Release version 2.1.5 * Compiler fixes and increse stack size limits to avoid stack overflows. abyss-pe: * Add 'ulimit' statements to the Makefile to increse a thread's stack size to 64MB. 2018-11-09 Ben Vandervalk * Release version 2.1.4 * Major improvements to Bloom filter assembly contiguity and correctness. Bloom filter assemblies now have equivalent scaffold contiguity and better correctness than MPI assemblies of the same data, while still requiring less than 1/10th of the memory. On human, Bloom filter assembly times are still a few hours longer than MPI assemblies (e.g. 17 hours vs. 13 hours, using 48 threads). abyss-pe: * Change default value of `m` from 50 => 0, which has the effect of disallowing sequence overlaps < k-1 bp. QUAST tests on E. coli / C. elegans / H. sapiens showed that both contiguity and correctness were improved by allowing only overlaps of k-1 bp between sequence ends. 2018-11-05 Ben Vandervalk * Release version 2.1.3 * Bug fix release abyss-bloom: * Added `graph` command for visualizing neighbourhoods of the Bloom filter de Bruijn graph (produces GraphViz) abyss-fixmate-ssq: * Fixed missing tab in SAM output which broke ABySS linked reads pipeline (Tigmint/ARCS) 2018-10-24 Ben Vandervalk * Release version 2.1.2 * Improved scaffold N50 on human by ~10% by implementing a new `DistanceEst --median` option (thanks to @lcoombe!) * Added a `--max-cost` option to `konnector` and `abyss-sealer`. This address a long-standing issue with indeterminately long running times, particularly for low values of `k`. abyss-pe: * Use the new `DistanceEst --median` option as the default for the scaffolding stage Dockerfile: * Fix OpenMPI setup DistanceEst: * Added `--median` option konnector: * Added `--max-cost` option to bound running time sealer: * Added `--max-cost` option to bound running time 2018-09-11 Ben Vandervalk * Release version 2.1.1 abyss-bloom-dbg: * upgrade to most recent version of ntHash to reduce some assembly/hashing artifacts. On a human assembly, this reduced QUAST major misassemblies by 5% and increased scaffold contiguity by 10% * `kc` parameter now also applies to MPI assemblies (see below) abyss-fac: * change N20 and N80 to N25 and N75, respectively ABYSS-P: * add `--kc` option, with implements a hard minimum k-mer multiplicity cutoff abyss-pe: * fix `zsh: no such option: pipefail` error with old versions of `zsh` (fallback to `bash` instead) * adding `time=1` now times *all* assembly commands abyss-sealer: * parallelize gap sealing with OpenMP (thanks to @schutzekatze!) * add `--gap-file` option (thanks to @schutzekatze!) DistanceEst: * add support for GFA output 2018-04-13 Ben Vandervalk * Release version 2.1.0 * Adds support for misassembly correction and scaffolding using linked reads, using Tigmint and ARCS. (Tigmint and ARCS must be installed separately.) * Support simultaneous optimization of `s` (min sequence length) and `n` (min supporting read pairs / Chromium barcodes) during scaffolding abyss-longseqdist: * Fix hang on input SAM containing no alignments with MAPQ > 0 abyss-pe: * New `lr` parameter. Provide linked reads (i.e. 10x Genomics Chromium reads) via this parameter to perform misassembly correction and scaffolding using Chromium barcode information. Requires Tigmint and ARCS tools to be installed in addition to ABySS. * Fix bug where `j` (threads) was not being correctly passed to to `bgzip`/`pigz` * Fix bug where `zsh` time/memory profiling was not being used, even when `zsh` was available abyss-scaffold: * Simultaneous optimization of `n` and `s` using line search or grid search [default] SimpleGraph: * add options `-s` and `-n` to filter paired-end paths by seed length and edge weight, respectively 2018-03-14 Ben Vandervalk * Release version 2.0.3 * Many compiler fixes for GCC >= 6, Boost >= 1.64 * Read and write GFA 2 assembly graphs with abyss-pe graph=gfa2 * Support reading CRAM via samtools abyss-bloom: * New `abyss-bloom build -t rolling-hash` option, to pre-build input Bloom filters for `abyss-bloom-dbg` * Fix incorrect output of `abyss-bloom kmers -r` (thanks to @notestaff!) abyss-bloom-dbg: * New `-i` option to read Bloom filter files built by `abyss-bloom build -t rolling-hash` * Improved error branch trimming (reduces number of small output sequences) * Fix intermittent segfaults caused by non-null-terminated strings abyss-map: * Append BX tag to SAM output (Chromium 10x Genomics data) ABYSS-P: * Increase default number of sparsehash buckets from 200,000,000 => 1,000,000,000 * Benefit: Allows larger datasets to be assembled without time-consuming sparsehash resize operations (e.g. H. sapiens) * Caveat: Increases minimum memory requirement per CPU core from 89 MB to 358 MB abyss-pe: * Parallelize `gzip` with `pigz`, if available * Report time/memory for each program with `zsh`, if available * Fix: use `N` instead of `n` for scaffold stage, when set by user abyss-samtobreak: * New `--alignment-length` (`-a`) option to exclude alignments shorter than a given length * New `--contig-length` (`-l`) option to exclude contigs shorter than a given length * New `--genome-size` (`-G`) option, for contiguity metrics that depend on the reference genome size * New `--mapq` (`-q`) option for minimum MAPQ score * New `--patch-gaps` (`-g`) option to join alignments separated by small gaps * New TSV output format with additional contiguity stats (e.g. L50, NG50) * Fix handling of hard-clipped alignments abyss-todot: * New `--add-complements` option abyss-tofastq: * New `--bx` option to copy BX tag from from SAM/BAM to FASTQ header comment (Chromium 10x Genomics data) 2016-10-21 Ben Vandervalk * Release version 2.0.2 * Fix compile errors with gcc 6 and boost 1.62 2016-09-14 Ben Vandervalk * Release version 2.0.1 * Resolve licensing issues by switching to standard GPL-3 license 2016-08-30 Ben Vandervalk * Release version 2.0.0 * New Bloom filter mode for assembly => assemble large genomes with minimal memory (e.g. 34G for H. sapiens) * Update param defaults for modern Illumina data * Make sqlite3 an optional dependency abyss-bloom: * New 'compare' command for bitwise comparison of Bloom filters (thanks to @bschiffthaler!) * New 'kmers' command for printing k-mers that match a Bloom filter (thanks to @bschiffthaler!) abyss-bloom-dbg: * New preunitig assembler that uses Bloom filter * Add 'B' param (Bloom filter size) to 'abyss-pe' command to enable Bloom filter mode * See README.md and '--help' for further instructions abyss-fatoagp: * Mask scaftigs shorter than 50bp with 'N's (short scaftigs were causing problems with NCBI submission) abyss-pe: * Update default parameter values for modern Illumina data * Change 'l=k' => 'l=40' * Change 's=200' => 's=1000' * Change 'S=s' => 'S=1000-10000' (do a param sweep of 'S') * Use 'DistanceEst --mean' for scaffolding stage, instead of the default '--mle' abyss-sealer: * New '--max-gap-length' ('-G') option to replace unintuitive '--max-frag'; use of '--max-frag' is now deprecated * Require user to explicitly specify Bloom filter size (e.g. '-b40G') * Report false positive rate (FPR) when building/loading Bloom filters * Don't require input FASTQ files when using pre-built Bloom filter files konnector: * Fix bug causing output read 2 file to be empty * New percent sequence identity options ('-x' and '-X') * New '--alt-paths-mode' option to output alternate connecting paths between read pairs README.md: * Fixes to documentation of ABYSS and abyss-pe parameters (thanks to @nsoranzo!) 2015-05-28 Ben Vandervalk * 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 * Release version 1.5.2 * First official release of Konnector and abyss-bloom. * More GCC 4.8+ fixes! Modified Boost install instructions. * Fixed rare bug when parsing output of BWA. ABYSS: * New option, --mask-cov, use kmers with lowercased bases, but don't count them towards multiplicity. abyss-bloom: * Construct reusable Bloom filter files for use with Konnector. * Perform boolean operations on two or more bloom filters. Currently supports union and intersection operations. abyss-fixmate: * Check for boost 1.43+ when using `unordered_map::quick_erase`. * New option, --all, to report all alignments. * Set mate unmapped flag for mateless reads. abyss-longseqdist: * Fixed `error: invalid CIGAR` when reading BWA output. configure: * Include mpi and boost libraries as system libraries. Silences warnings (treated as errors) when compiling with GCC 4.8+. konnector: * Merge read pairs into a single sequence (pseudoread) by building a Bloom filter de Bruijn graph and searching for paths between the paired end reads. Input reads may be FASTA/FASTQ/SAM/BAM. The input files must be sorted by read name and may not contain orphan reads. 2014-05-07 Anthony Raymond * Release version 1.5.1 * Fix an issue with strand-specific RNA-Seq assembly when running `abyss-filtergraph --assemble --SS`. * Portability fixes for Fujitsu C Compiler (FCC). abyss-filtergraph: * Assemble contigs in forward orientation with `--assemble --SS` abyss-pe: * Fix some cases where abyss-pe uses incorrect executables ABYSS-P: * Portability fix with FCC 2014-05-01 Anthony Raymond * Release version 1.5.0 * Assemble strand-specific RNA-Seq libraries into strand-specific contigs. * New parameters, Q and xtip. Improves assembly in high-coverage regions by removing recurrent read errors. * Portability fixes for Fujitsu C Compiler. abyss-pe: * New parameter, `Q`, to mask low quality bases to N. * New parameter, `xtip=1`, to remove 2-in 0-out tips. * New parameter, `ss=1`, to perform strand-specific assembly using ssRNA-Seq libraries. * New command, `scaftigs`. Breaks scaffold sequences at 'N's and produce a scaftigs.fa file. * Include long-scaffs.fa in FAC statistics if `long` parameter used. abyss-fixmate: * Performance improvement for GCC-4.6 and older. DistanceEst: * Report an estimation of duplicate fragments from read pairs mapping to different contigs. abyss-fixmate: * Report number of fragments removed as noise and outliers. ABYSS/ABYSS-P: * New option, --SS, to support strand-specific assembly. abyss-layout: * New option, --SS, to support strand-specific assembly. abyss-map: * New option, --SS, to support strand-specific assembly. abyss-overlap: * New option, --SS, to support strand-specific assembly. abyss-PathOverlap: * New option, --SS, to support strand-specific assembly. abyss-scaffold: * New option, --SS, to support strand-specific assembly. * Don't prune xtips when scaffolding. AdjList: * New option, --SS, to support strand-specific assembly. Overlap: * New option, --SS, to support strand-specific assembly. PopBubbles: * New option, --SS, to support strand-specific assembly. 2013-11-20 Anthony Raymond * Release version 1.3.7 * Use long sequences to rescaffold scaffolds. May be run by adding libraries to the `long’ parameter. When Scaffolding with RNA-Seq contigs from a Trans-ABySS assembly, the genic contiguity is greatly improved. * Added support gcc 4.8+, and Mac OS X 10.9 Mavericks with clang. * Licensed as GPL for non-commercial purposes. abyss-fac: * Added e-size to contiguity statistics as described in the GAGE paper. abyss-filtergraph: * Bug fix. `--assemble’ will not fail an assertion. * New option, --max-length, used to remove contigs over the specified threshold. * Trim 2-in 0-out tips when removing tips. abyss-map: * Bug fix. Correctly set mapq=0 for reads that multi map. abyss-longseqdist: * New program. Generate distance estimates between all contigs a single read maps to. abyss-mergepairs: * Report number of reads chastity filtered. abyss-overlap: * Bug fix. Handle ambiguity codes. abyss-pe: * Support BWA-MEM with assembly. Run using parameter `aligner=bwamem’. * Added another scaffolding stage using long sequences. May be run by adding libraries to the `long’ parameter. ABYSS-P: * Bug fix. Do not use awk to merge fasta files. abyss-samtobreak: * Building bug fix. Check that ghc modules are installed. UnitTest: * The Google C++ testing framework has been added to ABySS. 2013-07-15 Anthony Raymond * Release version 1.3.6 * Improved documentation for GitHub devs. * ABYSS-P performance improvement. * Various portability and bug fixes. abyss-mergepairs: * Fix program name. abyss-fac: * New option --exp-size to give the expected genome size needed for NG50 calculation. * New option --count-ambig include ambiguities in calculations. ABYSS/ABYSS-P: * Performance improvement. Runtime reduced by ~20%. * Fix support for MPICH. abyss-map: * No longer require POPCNT instruction. * New option --order to force output order the same as input. abyss-filtergraph: * New option --remove to remove specified contigs from graph. PopBubbles: * Bug fix. Setting branches > 2 will now work. abyss-fixmate: * Improved error when first and second read IDs do not match. * New option --cov to compute and store the physical coverage in a Wiggle file. AdjIO: * Bug fix for non-GCC compilers. 2013-03-04 Anthony Raymond * Release version 1.3.5 * Standardized --help message format. * Improve documentation. * Merge overlapping read pairs. * Layout and merge contigs using sequence overlap graph. * Attempt to fill scaffold gap with consensus of all paths between contigs. abyss-pe: * Attempt to fill scaffold gap with consensus of all paths between contigs. AdjList: * Increase the default value of m from 30 to 50. abyss-overlap: * Increase the default value of m from 30 to 50. * New options, --tred and --no-tred. Remove transitive edges. Default --tred. abyss-mergepairs: * New program. Merges overlapping read pairs. ABYSS-P: * Bug fix. Exit when there is a problem reading a file. * Don't store sequences in the rank 0 process when using at least 1000 cores. Improves memory distribution with large number of cores. abyss-fac: * Increase the default value of t from 200 to 500. DistanceEst: * Bug fix. Exit with success if there is only one contig. Fixes this error: DistanceEst: DistanceEst.cpp:534: int main(int, char**): Assertion `in' failed. * Bug fix. Fix the bug causing this error: DistanceEst: error: The observed fragment of size 128 bp is shorter than 2*l (l=71). Decrease l to 64. * Bug fix. Correctly estimate distance using MLE when l=0. abyss-layout: * New program. Layout contigs using the sequence overlap graph. abyss-map: * Return helpful error when query ID starts with '@` * New options, --chastity and --no-chastity. Ignore chastity failed reads. Default --no-chastity. abyss-samtobreak: * New script. Calculate contig and scaffold contiguity and correctness metrics. abyss-fixmate: * New option, l. Minimum alignment length. Set unmapped flag if the CIGAR match length is too small. * Print all alignments when the histogram output file not given. * Print SAM header to the same file when given. 2012-05-30 Shaun Jackman * Release version 1.3.4. * Do not extend paths, which can cause misassemblies. * Increase the default value of m from 30 to 50. * Various portability fixes. abyss-pe: * Increase the default value of m from 30 to 50 to reduce the likelihood of misassemblies. * Integrate with SLURM. Thanks to Timothy Carlson. ABYSS: * Use CityHash64 rather than Bob Jenkins' hashlittle. SimpleGraph: * Do not extend paths. Closes #8. Extending paths can cause misassemblies when the de Bruijn graph is incomplete. MergePaths: * Bug fix. Closes #6. Fix the bug causing the error: Assertion `!m_ambig' failed. abyss-fatoagp: * New script. Create a FASTA file of scaftigs and an AGP file. 2012-03-13 Shaun Jackman * Release version 1.3.3. * New parameter, l. Specify the minimum alignment length when aligning the reads to the contigs. * Improve the scaffolding algorithm that identifies repeats. * Improve the documentation. abyss-pe: * New parameter, l. Specify the minimum alignment length when aligning the reads to the contigs. This option may be specified per library. The default value is k. * New parameter, S. Specify the minimum contig size required for building scaffolds. * New parameter, N. Specify the minimum number of pairs required for building scaffolds. * Integrate with Load Sharing Facility (LSF). * Calculate the assembly contiguity statistics. KAligner, abyss-map: * Rename the minimum alignment length option -k to -l. DistanceEst: * Dual licensed under the GPL and BCCA-Academic licenses. * New options, --fr and --rf. Specify the orientation of the library. The default behaviour is to detect the orientation. * New options, --mind and --maxd. Specify the minimum and maximum distances for the maximum likelihood estimator. * New option, -l, --min-align. Specify the minimum alignment length of the aligner, which can improve distance estimates. * Increase the default minimum mapping quality, -q, to 10, was 1. MergePaths: * Bug fix. Fix the bug causing the error: Assertion `count(it2+1, path2.end(), pivot) == 0' failed. PathConsensus: * Bug fix. Fix the bug causing the error: Assertion `fstSol.size() == sndSol.size()' failed. MergeContigs: * Calculate the assembly contiguity statistics. abyss-scaffold: * Improve the algorithm that identifies repeats. * Remove simple cycles from the scaffold graph. * Calculate the assembly contiguity statistics. * The option -s may specify a range, such as -s200-10000, to find the value of s that maximizes the scaffold N50. abyss-fac: * New option, -m, --mmd. Output MultiMarkdown format. abyss-index: * New option, -a, --alphabet. Specify the alphabet. * New option, --bwt. Output the Burrows-Wheeler transform. abyss-samtoafg: * New script. Convert a SAM file to an AMOS AFG file. README, README.html, abyss-pe.1: * Improve the documentation. 2011-12-13 Shaun Jackman * Release version 1.3.2. * Enable scaffolding by default. * Remove small shim contigs. * Improved distance estimates. * Reduce sequence duplication. * Read compressed files on Mac OS X. abyss-pe: * Enable scaffolding by default. If the mp parameter is not specified, use a default value of ${pe} or ${lib}. * Support using bowtie2 to align reads to contigs by specifying aligner=bowtie2. * The default aligner is abyss-map. * Output the scaffold overlap graph, ${name}-scaffolds.dot. * Set DYLD_FORCE_FLAT_NAMESPACE to read compressed files on OS X. ABYSS: * Can read k-mer count data from a Jellyfish file with extension .jf for k-mer counts or .jfq for q-mer counts. Jellyfish must be installed. * Bug fix. Fix the bug causing the error bool chomp(std::string&, char): Assertion `s.length() > 1' failed. abyss-filtergraph: * New program. Remove small shim contigs that add no useful sequence to the assembly. Thanks to Tony Raymond (tgr). PopBubbles: * New option, -a, --branches. Specify the maximum number of branches of a bubble that may be popped. Default is 2. * Use DIALIGN-TX for multiple sequence alignment. Thanks to tgr. DistanceEst: * Improved distance estimates. abyss-joindist: * Remove this program. Use abyss-todot instead. MergePaths: * Use a non-greedy algorithm that reduces sequence duplication but may reduce contiguity. The greedy algorithm may be used by specifying the option --greedy. abyss-fixmate: * Do not output query names by default. configure: * New option, --enable-samseqqual. Enable SAM sequence and quality fields. 2011-10-24 Shaun Jackman * Release version 1.3.1. * Read sequence files in SRA format. The tool fastq-dump from the sratoolkit must be installed. * Read a contig overlap graph in the ASQG format of SGA. * Fix compile errors for Mac OS X. * Fix the bug that caused the line number of an error in a FASTQ file to be reported incorrectly. abyss-pe: * Support using BWA-SW to align reads to contigs by specifying aligner=bwasw. * The parameter ALIGNER_OPTIONS may be used to specify a different value for k when aligning using abyss-map. * New target, bam, may be used to produce a final BAM file of the reads aligned to the scaffolds. KAligner: * Fix the bug causing the error: Assertion `qstep >= 0 && qstep <= m_hashSize' failed. abyss-scaffold: * The result is independent of the order in which the mate-pair libraries are specified. * Permit scaffolding contigs that have non-numeric identifiers. * The overlap graph is optional. abyss-todot: * Convert adj, dist or ASQG formatted graph files to dot format. * Merge multiple graph files into one. 2011-09-09 Shaun Jackman * Release version 1.3.0. * Use mate-pair libraries to scaffold contigs. * Support CASAVA-formatted FASTQ files. * Bug fix. Do not trim quality 41 bases from the ends of reads. * Boost C++ Libraries are required to compile ABySS. abyss-pe: * New parameter, mp, to specify the mate-pair libraries to be used for scaffolding. * Increase the default value for s from 100 to 200. * Set the default value for n to 10. * Integrate with PBS. abyss-scaffold: * New program. Scaffold using mate-pair libraries. DistanceEst: * Ignore multimapped alignments with a mapping quality of zero. * New option, -q, --min-mapq. Ignore alignments with mapping quality less than this threshold. Default is 1. * Do not use OpenMP 3.0. PopBubbles: * Scaffold over complex bubbles with the option --scaffold. Disabled by default. MergePaths: * Fix a bug that causes PathOverlap to die with the error: Distance get(edge_bundle_t, const Graph&, ContigNode, ContigNode): Assertion `e.second' failed. * New option, --no-greedy. Use a non-greedy algorithm that reduces sequence duplication but reduces contiguity. Disabled by default. KAligner: * Performance improvements. Thanks to Tony Raymond (tgr). * The output is printed in the same order as the input when multithreaded. (tgr) abyss-map: * New program. Use the BWT and FM-index to find the longest common substring. To use it, specify the option aligner=map to abyss-pe. abyss-index: * New program. Build a FM-index of a FASTA file. abyss-bowtie: * Use abyss-tofastq --interleave to speed up abyss-fixmate. abyss-bwa: * Use bwa index -a bwtsw by default. * Use abyss-tofastq --interleave to speed up abyss-fixmate. abyss-fac: * Report N80, N50 and N20. Do not report median and mean. * Increase the default minimum contig size threshold, option -t, from 100 to 200. abyss-fixmate: * Set the mapping quality of both alignments to the minimum mapping quality of the pair of alignments. abyss-tofastq: * New option, -i, --interleave. Interleave the files. configure: * New option, --with-boost. Specify the path for Boost. * New option, --disable-popcnt. Do not use the popcnt instruction. 2011-04-15 Shaun Jackman * Release version 1.2.7. abyss-pe: * Support using bwa or bowtie to align reads to contigs. Specify aligner=bwa or aligner=bowtie. * Integrate with IBM LoadLeveler. PopBubbles: * Use an affine gap penalty. * The default maximum bubble length is 10 kbp. * New option, --scaffold. Scaffold over bubbles with insufficient sequence identity to be popped. SimpleGraph: * New parameter d to specify the acceptable error of a distance estimate. The default is 6 bp. PathConsensus: * Use an affine gap penalty. MergePaths: * Fix a bug that causes PathOverlap to die with the error: Distance get(edge_bundle_t, const Graph&, ContigNode, ContigNode): Assertion `e.second' failed. 2011-02-07 Shaun Jackman * Release version 1.2.6. * Find contigs that overlap by fewer than k-1 bp. * Pop bubbles with sufficient sequence identity. * Merge paths that overlap unambiguously. abyss-pe: * New parameter, m, the minimum number of overlapping bases. The default is 30. * The minimum sequence identity parameter, p, applies to both PopBubbles and PathConsensus. ABYSS: * Support values of k larger than 96. The maximum value of k is set when compiling using `configure --enable-maxk´. AdjList: * Find sequences that overlap by fewer than k-1 bp. The parameter m specifies the minimum number of overlapping bases. PopBubbles: * Align both branches of the bubble and pop bubbles whose sequence identity is sufficient, at least 90% by default. * New parameter, p, the minimum identity required. * The maximum bubble size is unlimited by default. This limit can be changed using the parameter b. SimpleGraph: * Extend each path as long as is unambiguously possible. PathOverlap: * Merge paths that overlap unambiguously. MergeContigs: * Perform an alignment of the two sequences when no simple overlap is found. abyss-fac: * New option, -g. Specify the expected genome size. 2010-11-15 Shaun Jackman * Release version 1.2.5. AdjList: * Fix the colour-space-specific bug causing the error Assertion `seq.length() > (unsigned)opt::overlap' failed. PathConsensus: * Fix the bug causing the error Assertion `fstSol.size() == 1' failed. abyss-fixmate: * Do not output the @RG header record at the end of the output that gives the median fragment size. It breaks `samtools view -S`. * --no-qname: New option. Set the qname to *. 2010-10-13 Shaun Jackman * Release version 1.2.4. ABYSS-P: * Fix the bug causing the error Unexpected sequence extension message. KAligner: * Reduce the amount of memory used by KAligner. PathConsensus: * New program. Replace gaps of Ns that span a region of ambiguous sequence with a consensus sequence of the possible sequences that fill the gap. By default a minimum 90% identity is required. This default can be changed with the parameter, p. The consensus sequence uses IUPAC-IUB ambiguity codes. DIALIGN-TX is used for the multiple sequence alignment. PathOverlap: * Fix the bug causing the error Assertion `back(paths, u) == front(paths, v)' failed. 2010-09-08 Shaun Jackman * Release version 1.2.3. ABYSS-P: * Bug fix. Fix the bug causing the error Assertion `m_comm.receiveEmpty()' failed. PopBubbles: * Bug fix. Fix the bug causing the error error: unexpected ID PathOverlap: * Include the single-end contigs in the overlap graph. abyss-pe: * Output an overlap graph of the paired-end assembly in the file ${name}-contigs.dot. * Do not create the intermediate file ${name}-4.fa. abyss-adjtodot: * Convert an overlap graph in adj format to Graphviz dot format or SAM alignment format. 2010-08-25 Shaun Jackman * Release version 1.2.2. * Merge contigs after popping bubbles. * Handle multi-line FASTA sequences. * Report the amount of memory used. * Most tools can output their results in SAM format, including AdjList, KAligner, ParseAligns and PathOverlap. abyss-pe: * New command, se-dot. Output a Graphviz dot file of the single-end assembly. ABYSS: * Handle multi-line FASTA sequences. * Report the amount of memory used. * Improve error messages for incorrectly-formatted FASTA files. * Bug fix. Improved handling of palindromes. PopBubbles: * Merge contigs after popping bubbles. * Bug fix. Do not pop bubbles resulting from palindromes. KAligner: * Report the amount of memory used. * New option, --sam. Output the alignments in SAM format. ParseAligns, DistanceEst: * Bug fix. The CIGAR string was oriented with respect to the query rather than with respect to the target, which is standard. AdjList, PathOverlap: * New option, --sam. Output the adjacency graph in SAM format. abyss-fixmate: * New program. Similar to samtools fixmate, but does not require that the input be sorted by query ID, although it is faster if it is sorted. 2010-07-12 Shaun Jackman * Release version 1.2.1. * Handle reverse-forward oriented mate pair libraries. * Improved distance estimates, particularly with large fragment libraries. abyss-pe: * New commands: se-contigs: Assemble single-end contigs. pe-contigs: Assemble paired-end contigs (default). se-sam: Output a gzipped SAM file of the single-end assembly. se-bam: Ouptut a BAM file of the single-end assembly. pe-dot: Output a Graphviz dot file of the paired-end assembly. all: Sam as se-bam pe-contigs pe-dot. * Options for one particular library may be specified: lib='lib1 lib2' lib2_s=1000 lib2_n=25 * Input sequence may come from an arbitrary command, which is useful to assemble a region of an aligned BAM file: in='<(samtools view genome.bam chr10)' ABYSS: * Bug fix. When reading SAM/BAM files, the quality format incorrectly defaulted to ASCII-64, when it should be ASCII-33. ABYSS-P: * May use the Intel MPI library. ParseAligns: * Count the number of forward-reverse, reverse-forward and forward-forward oriented alignments. DistanceEst: * Handle reverse-forward oriented mate pair libraries. * Improved distance estimates, particularly with large fragment libraries. * Remove duplicate mate pairs. * Print a pretty UTF-8 bar plot of the fragment-size distribution. * Multithreaded using OpenMP. The -j, --threads option specifies the number of threads to use. * Performance improvment. Overlap: * Handle cases when more than one gap occurs within the mate pair fragment size. SimpleGraph: * Performance improvment. MergePaths: * Handle the case when a circular sequence is assmembled into a single contig. abyss-tofastq: * New program. Convert qseq, export, SAM and BAM files to FASTA or FASTQ format. The files may be compressed with gz, bz2 or xz and may be tarred. 2010-05-25 Shaun Jackman * Release version 1.2.0. * Scaffold over gaps in coverage and unresolved repetitive sequence using Ns. * Read sequence from SAM and BAM files. abyss-pe: * Set q=3 by default. Trim bases from the ends of reads whose quality is less than 3. * Do not store the .pair.gz file. * Generate a BAM file of the mate pairs that align to different contigs of the single-end assembly. Disabled by default. * Output a Graphviz dot file of the paired-end assembly. Disabled by default. * Store the bubbles in ${name}-bubbles.fa rather than bubbles.fa. * Store the indel bubbles in ${name}-indel.fa. * Bug fix for mawk. ABYSS: * Set -E0 when coverage is low (<2). ABYSS-P: * Remove the temporary files contigs-*.fa and snp-*.fa. PopBubbles: * Output in Graphviz dot format using --dot. KAligner: * Do not ignore sequences (reads or contigs) containing N. * Output SAM headers (but not SAM alignments). ParseAligns: * Output in SAM format. DistanceEst: * Input in SAM format. * Output in Graphviz dot format using --dot. Overlap: * Scaffold over gaps in coverage. Scaffolding can be disabled using the option --no-scaffold. * Merge contigs that overlap at simple repeats. These merges can be prevented using the option --no-merge-repeat. SimpleGraph: * Scaffold over repeats. Scaffolding can be disabled using the option --no-scaffold. MergePaths: * Merge paths containing ambiguous sequence. * Multithreaded using OpenMP. The -j, --threads option specifies the number of threads to use. MergeContigs: * Merge paths and contigs containing ambiguous sequence. PathOverlap: * Output in Graphviz dot format using --dot. Consensus: * Output the pileup in samtools format. 2010-02-15 Shaun Jackman * Release version 1.1.2. ABYSS: * Read tar files including compressed tar files. * New parameter -b, --bubble-length=N. Pop bubbles shorter than N bp. The default is b=3*k. AdjList: * Include the contig coverage in the output. * The script abyss-adjtodot converts an ABySS adjacency file to GraphViz dot format. PopBubbles: * Pop bubbles resulting from indels. KAligner: * Synchronize the threads periodically (every ten thousand alignments by default) to ease the computational burden on ParseAligns. This synchronization can be disabled using --sync=0. * Use two threads by default. abyss-pe: * New parameter, b. * Use two threads by default. * The read length argument, l, is deprecated. To emulate the behaviour of ABySS 1.0.14 and older, set t=6*(l-k+1). The default is t=k. 2010-01-19 Shaun Jackman * Release version 1.1.1. ABYSS: * Pop complex bubbles either completely or not at all. Bubble popping now completes in a single round. * Choose better (typically lower) default values for the parameters -e,--erode and -c,--coverage. The default threshold is the square root of the median k-mer coverage. 2009-12-18 Shaun Jackman * Release version 1.1.0. * The output format of AdjList, DistanceEst and SimpleGraph has changed to be more humanly readable. ABYSS: * New options, -q, --trim-quality. Trim bases from the ends of reads whose quality is less than the specified threshold. --standard-quality: zero quality is `!' (33) default for FASTQ files --illumina-quality: zero quality is `@' (64) default for qseq and export files Thanks to Tony Raymond. SimpleGraph: * Multithreaded. The -j, --threads option specifies the number of threads to use. * Expand tandem repeats when it is possible to determine the exact number of the repeat. MergePaths: * Bug fix. A repeat that is larger than the fragment size could be misassembled. Thanks to Tony Raymond. abyss-pe: * Determine the parameter j (number of threads) by finding the number of slots allocated on the head node in the PE_HOSTFILE. * Store the k-mer coverage histogram in coverage.hist. 2009-11-13 Shaun Jackman * Release version 1.0.16. * Improve the performance and memory usage of KAligner and AdjList, particularly for very large data sets. KAligner: * Improve memory usage when maxk is 32 or 96. No change when maxk is the default 64. * New option, -i, --ignore-multimap. Ignore any duplicate k-mer in the target sequence. Thanks to Tony Raymond. AdjList: * Improve performance for very large data sets. ParseAligns: * For reads whose ID begins with `SRR', expect that the forward and reverse read have identical ID and no suffix, such as /1 and /2. 2009-10-19 Shaun Jackman * Release version 1.0.15. ABYSS: * New options, -e, --erode and -E, --erode-strand. The parameter e erodes bases at the ends of blunt contigs with coverage less than the specified threshold. The parameter E erodes bases at the ends of blunt contigs with coverage less than the specified threshold on either strand. * New feature. If the parameters e and c are not specified, attempt to choose appropriate values based on the observed k-mer coverage. This feature will work best for higher coverage data. For lower coverage data, setting e=c=2 is reasonable. * New option, --trim-masked. Removed masked (lower case) sequence at the beginning and end of the read. Disable with --no-trim-masked. * The read length, l, is an optional parameter. If the read length is specified, the trim parameter, t, will default to 6*(l-k+1), as before. If the read length is not specified, t will be set to the same value as k. For longer reads or when k is less than 85% of l, it should not be necessary to specify l. The parameter t may be specified directly if desired. DistanceEst: * Bug fix. The standard deviation could be calculated incorrectly for larger numbers, particularly for libraries with large fragment sizes. Thanks to Tony Raymond. Overlap: * Bug fix. If Overlap found mate pairs on the same contig with incorrect orientation, it would generate a misassembled contig. These misassembled contigs are easily identified in the xxx-3-overlap.fa file. The two contigs IDs, in the fourth and fifth column, will be identical. * New option, --mask-repeat. If two contigs are joined by mate pairs and are found to overlap by a simple repeat so that the exact number of the repeat is unknown, join the contigs estimating the number of the repeat, and mask (lower case) the repeat sequence. This feature is disabled by default. abyss-pe: * Use gunzip -c rather than zcat for portability. configure: * New option, --enable-mpich. Use the MPICH2 MPI library. 2009-09-08 Shaun Jackman * Release version 1.0.14. * Read files compressed with xzip (.xz) and compress (.Z). abyss-pe: * Assemble multiple libraries with different fragment sizes. * New manual page. ABYSS: * Don't necessarily discard reads that contain an N. Keep those k-mer that do not contain an N. ABYSS-P: * Serially renumber the contigs output by ABYSS-P using awk. 2009-08-26 Shaun Jackman * Release version 1.0.13. * Read files compressed with gzip (.gz) or bzip2 (.bz2). ABYSS-P: * Bug fix. Fix a race condition in the erosion algorithm. 2009-08-18 Shaun Jackman * Release version 1.0.12. abyss-pe: * Both ABYSS and KAligner are run only once per assembly, which speeds up the paired-end assembly by nearly a factor of two. * The k-mer coverage information is correct in every contig file. * A new parameter, cs, converts colour-space contigs to nucleotide contigs using Consensus. * A new parameter, ABYSS_OPTIONS, may be used to disable chastity filtering by specifying ABYSS_OPTIONS=--no-chastity. ABYSS: * Read files in export format, which is similar to qseq format. * Discard reads that failed the chastity filter. Use the --no-chastity option to retain these unchaste reads. Chastity filtering affects only qseq- and export formatted-files. * Remove low-coverage contigs within ABYSS rather than filtering using awk and reassembling. * Support big-endian architecture machines. KAligner: * A new option, -m or --multimap, specifies that a duplicate k-mer may be seen in the target sequence. By default, every k-mer in the target sequence must be unique. * A new option, --seq, prints the read sequence of each alignment. Overlap: * A new option, --scaffold, fills the gap between two blunt contigs with Ns. This feature is disabled by default. Consensus: * Call the consensus sequence for each contig based on the alignment of reads to contigs. * Convert colour-space contigs to nucleotide contigs. * Written by Tony Raymond. 2009-07-21 Shaun Jackman * Release version 1.0.11. * Assemble colour-space reads. Read identifiers must be named with the suffixes F3 and R3. * Read files in qseq format. Thanks to Tony Raymond (tgr). * Prevent misassemblies mediated by tandem segmental duplications. A sequence XRRY, where R is a repeat sequence, could have been misassembled as XRY. (tgr) abyss-pe: * Integrate with Sun Grid Engine (SGE). A parallel, paired-end assembly can be run with a single qsub command. The parameters lib, np and k default to the qsub environment variables JOB_NAME (qsub -N), NSLOTS (qsub -pe) and SGE_TASK_ID (qsub -t) respectively. * The .pair file, the largest intermediate file, is now gzipped. ABYSS-P: * Bug fix. At k=19, k-mer would be distributed to even-numbered processes only. KAligner: * Multithreaded. The -j, --threads option specifies the number of threads to use. The order in which the alignments are output will vary from run to run, but the alignments are deterministic and will not vary. Each thread reads and aligns one file, so the reads must be in more than one file to use this feature. (tgr) 2009-06-18 Shaun Jackman * Release version 1.0.10. abyss-pe: * Start an MPI ABySS assembly if the np option is specified. ABYSS: * For a non-parallel assembly, allocate more hash buckets to allow for large single-machine jobs. * Print the hash load during the loading process. KAligner: * Output the IDs of reads that do not align. * Print a progress report of the number of reads aligned. ParseAligns: * To reduce memory usage, do not track reads that did not align. KAligner and ParseAligns should now be able to handle any number of reads in a single run. MergePaths: * Number paired-end contigs so that their IDs do not overlap with the single-end contigs. If a single-end contig is not used in a paired-end contig, its ID will not change. * Merge overlapping paired-end contigs that were previously being missed in some situations. configure: * Print a warning if Google sparsehash was not found. 2009-05-15 Shaun Jackman * Release version 1.0.9. abyss-pe: * Allow multiple input files specified by the parameter `in'. * Support reading FASTA or FASTQ file formats. KAligner: * Support using Google sparsehash to reduce memory usage. Google sparsehash does not provide a multimap, so KAligner built using Google sparsehash cannot handle a duplicate k-mer in the reference sequence. It will print an error message and die if a duplicate k-mer is encountered. If Google sparsehash is not used, the standard STL multimap will be used which does permit duplicate k-mer. * Support reading the query sequence from standard input. ParseAligns: * Significantly reduce memory usage if the mate reads are encountered one after the next in the same file. 2009-04-02 Shaun Jackman * Release version 1.0.8. * Bug fix. Fix the undefined behaviour causing the error Assertion `marked == split' failed. 2009-03-31 Shaun Jackman * Release version 1.0.7. * Use a mark-and-sweep trimming algorithm to remove errors at the ends of blunt contigs. * The parallel (ABYSS-P) trimming algorithm is now deterministic; it will produce the same result every time. In addition, the result of the parallel trimming algorithm is identical to the result of the non-parallel trimming algorithm. * Start trimming branches at length 1, previously 2. * Bug fix in ABYSS-P. Repeat sequences of k-1 bases could potentially be misassembled. Use a mark-and-sweep algorithm to split ambiguous edges before contig generation. The previous algorithm was not deterministic. * Reduce memory usage by 200 MB by removing the MPI transmit buffer. * Bug fix in ABYSS-P. Fix an additional race condition in the erosion algorithm. 2009-03-24 Shaun Jackman * Release version 1.0.6. * Bug fix. Fix a race condition in the erosion algorithm. * For the parallel program (ABYSS-P), after bubble popping perform as many trimming rounds as necessary to remove all the tips, as the non-parallel program does. * New script, abyss2afg, to create an AMOS AFG assembly. 2009-03-11 Shaun Jackman * Release version 1.0.5. * Portability fixes. Tested with g++ 4.3.3. 2009-03-04 Shaun Jackman * Release version 1.0.4. ABYSS: * Remove the need to specify a -e,--erode parameter by improving the erosion algorithm to complete in a single pass. * Remove the default limit on the maximum number of bubble popping rounds. A limit may be specified using -b,--bubbles. * Generate a warning if an input file is empty, but do not die. * When using a Google sparsehash, allocate room for 100 million k-mers. * Increase the maximum FASTA line length from 64 kB to 256 kB. * Require only one of either -l,--read-length or -t,--trim-length to be specified. * Allow read pairs to be named `_forward' and `_reverse'. * Ensure that exactly k-1 bases of context is given on each side of the bubble sequence. Previously, one side would have k bases of context, and the other side would have k-1 bases. * Add command line options to each of the paired-end programs. ABYSS-P: * Use Open MPI as the default MPI library. * Do not link against the Open MPI C++ library. abyss-pe: * Use pipes where possible to avoid intermediate files. * The semantics of the n argument have changed. See DistanceEst -n,--npairs below. SimpleGraph: * If more than one path is found but only one meets all of the constraints, use it. * Allow for some constant error in distance estimates that does not decrease with the number of samples. The expected fragment size seems to vary with genomic coordinate to a certain degree. So, the distribution of fragment size spanning two given contigs may differ from the empirical distribution by a roughly constant offset. DistanceEst: * The semantics of the -n,--npairs option has changed. Require at least NPAIRS pairs between contigs (>= NPAIRS). Previously, required strictly more than NPAIRS pairs between contigs (> NPAIRS). * Give the estimated error to a single decimal place. * When counting the number of pairs that join two contigs, only count pairs that fit the empirical distribution. * When deciding whether the pairs joining two contigs are inconsistent in sense, require NPAIRS read pairs joining two contigs in each sense before considering the pair data to be inconsistent. ParseAligns: * Measure fragments in total size, not alignment distance. * Allow a read that spans two contigs to be used in distance estimates. * Add the -h,--hist option to produce a histogram. * Bug fix. When measuring the empirical fragment size, ensure that the sense of the alignments is correct. Output a negative fragment size if the reverse read aligns ahead of the forward read. * Bug fix. Miscalculated the fragment size estimate between two contigs if they did not have the same sense and one contig required flipping. It was possible to see one distance estimate from contig A to contig B and a differing estimate from contig B to contig A. Typically, the distance estimate would be off by one. 2009-01-23 Shaun Jackman * Release version 1.0.3. * Merge contigs that ended due to a lack of coverage, but which are connected by paired-end reads and overlap unambiguously. * Track the multiplicity the sense and antisense strand separately. Erode the end of a blunt contig until it is represented by both strands. * Ignore the case of the nucleotide sequence of a FASTA file. * Increase the maximum FASTA line length from 1 kB to 64 kB to allow loading contigs. * Output the path through the single-end contigs in the comment field of the paired-end contig. * In the paired-end driver script, abyss-pe, Implement a coverage cutoff, c. Pass the erosion parameter, e, to the single-end assembler. 2008-11-21 Shaun Jackman * Release version 1.0.2. * Terminate contig extension at palindromic k-mers. * If erosion (-e,--erode) is enabled, remove the tips of blunt contigs that are represented only once. 2008-11-07 Shaun Jackman * Release version 1.0.1. * Portability improvements to compile for Mac OS X. 2008-08-07 Shaun Jackman * Release version 1.0. abyss-2.2.4/Common/000077500000000000000000000000001361462241400140735ustar00rootroot00000000000000abyss-2.2.4/Common/Algorithms.h000066400000000000000000000031571361462241400163630ustar00rootroot00000000000000#ifndef ALGORITHMS_H #define ALGORITHMS_H 1 #include #include #include #include /** Apply function f to each element in the range [first, last) for * which the predicate p is true. */ template Function for_each_if(It first, It last, Function f, Pred p) { for (; first != last; ++first) if (p(*first)) f(*first); return f; } /** Copies each element in the range [first, last) into the range * starting at result for which the predicate p is true. */ template OutputIt copy_if(InputIt first, InputIt last, OutputIt result, Pred pred) { for (; first != last; ++first) { if (pred(*first)) { *result = *first; ++result; } } return result; } /** Sorts the elements in the range [first,last) ordered by the value * returned by the unary function op, which is called once for each * element in the range [first,last). The copy constructor of the * value_type of It is not used. */ template void sort_by_transform(It first, It last, Op op) { typedef typename std::iterator_traits::difference_type size_type; typedef typename Op::result_type key_type; size_type n = last - first; std::vector< std::pair > keys; keys.reserve(n); for (It it = first; it != last; ++it) keys.push_back(std::make_pair(op(*it), it - first)); sort(keys.begin(), keys.end()); for (size_type i = 0; i < n; i++) { size_type j = keys[i].second; while (j < i) j = keys[j].second; if (i != j) std::swap(first[i], first[j]); keys[i].second = j; } } #endif abyss-2.2.4/Common/Alignment.h000066400000000000000000000042541361462241400161670ustar00rootroot00000000000000#ifndef ALIGNMENT_H #define ALIGNMENT_H 1 #include #include #include #include /** An ungapped alignment of a query to a target. */ struct Alignment { std::string contig; int contig_start_pos; int read_start_pos; int align_length; int read_length; bool isRC; Alignment() { } Alignment(const Alignment& o, std::string /*qid*/, std::string /*seq*/) { *this = o; } Alignment(std::string contig, int contig_start, int read_start, int align_length, int read_length, bool isRC) : contig(contig), contig_start_pos(contig_start), read_start_pos(read_start), align_length(align_length), read_length(read_length), isRC(isRC) { } /** * Return the taret position at the query start. * Note: not alignment start, and may be negative */ int targetAtQueryStart() const { unsigned tend = contig_start_pos + align_length; return !isRC ? contig_start_pos - read_start_pos : int(tend + read_start_pos); } /** Return the distance between the specified alignments. * May be used to calculate fragment size when the alignments are * mate pairs. */ int operator-(const Alignment& o) const { return targetAtQueryStart() - o.targetAtQueryStart(); } /** Return an alignment of the reverse complement of the query to * the same target. */ Alignment flipQuery() const { Alignment rc(*this); unsigned qend = read_start_pos + align_length; assert(qend <= (unsigned)read_length); rc.read_start_pos = read_length - qend; rc.isRC = !isRC; return rc; } static int calculateReverseReadStart(int read_start_pos, int read_length, int align_length) { unsigned qend = read_start_pos + align_length; return read_length - qend; } bool operator<(const Alignment& a1) const { return read_start_pos < a1.read_start_pos; } friend std::istream& operator >>(std::istream& in, Alignment& a) { return in >> a.contig >> a.contig_start_pos >> a.read_start_pos >> a.align_length >> a.read_length >> a.isRC; } friend std::ostream& operator <<(std::ostream& out, const Alignment& a) { return out << a.contig << ' ' << a.contig_start_pos << ' ' << a.read_start_pos << ' ' << a.align_length << ' ' << a.read_length << ' ' << a.isRC; } }; // struct Alignment #endif abyss-2.2.4/Common/BitUtil.h000066400000000000000000000111211361462241400156140ustar00rootroot00000000000000#ifndef BITUTILS_H #define BITUTILS_H 1 #include "config.h" #include // for exit #include #include #include enum BitwiseOp { BITWISE_OVERWRITE, BITWISE_OR, BITWISE_AND }; /** The return value of the CPUID instruction. */ struct CPUID { unsigned a, b, c, d; }; /** Return the result of the CPUID instruction * or -1 if it is not supported. */ static inline CPUID cpuid(unsigned op) { CPUID x; #if __GNUC__ && __x86_64__ __asm__("cpuid" : "=a" (x.a), "=b" (x.b), "=c" (x.c), "=d" (x.d) : "a" (op)); return x; #else (void)op; x.a = x.b = x.c = x.d = static_cast(-1); return x; #endif } /** Return whether this processor has the POPCNT instruction. */ static inline bool havePopcnt() { return cpuid(1).c & (1 << 23); } static const bool hasPopcnt = havePopcnt(); /** Return the Hamming weight of x. */ static inline uint64_t popcount(uint64_t x) { #if HAVE_POPCNT && __GNUC__ && __x86_64__ if (hasPopcnt) { __asm__("popcnt %1,%0" : "=r" (x) : "r" (x)); return x; } #endif x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL); x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL; x = x + (x >> 8); x = x + (x >> 16); x = x + (x >> 32); 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 abyss-2.2.4/Common/ConstString.h000066400000000000000000000051731361462241400165270ustar00rootroot00000000000000#ifndef CONSTSTRING_H #define CONSTSTRING_H 1 #include "Common/Hash.h" #include "Common/HashFunction.h" #include #include #include #include /** An immutable string that does not allocate resources. */ class cstring { public: cstring(const char* p) : m_p(p) { } cstring(const std::string& s) : m_p(s.c_str()) { } /** Return the size of this string. */ size_t size() const { return strlen(m_p); } /** Return a null-terminated sequence of characters. */ const char* c_str() const { return m_p; } operator const char*() const { return m_p; } bool operator==(const cstring& o) const { return m_p == o.m_p || strcmp(m_p, o.m_p) == 0; } bool operator<(const cstring& o) const { return m_p != o.m_p && strcmp(m_p, o.m_p) < 0; } friend std::ostream& operator<<(std::ostream& out, const cstring& o) { return out << o.m_p; } protected: const char* m_p; }; /** An immutable string. */ class const_string : public cstring { public: const_string(const std::string& s) : cstring(strcpy(new char[s.size() + 1], s.c_str())) { } #if __GXX_EXPERIMENTAL_CXX0X__ const_string(const_string&& s) : cstring(s.m_p) { s.m_p = NULL; } #endif #if 0 /* Should be like this, but... */ const_string(const const_string& s) : cstring(strcpy(new char[s.size() + 1], s.c_str())) { } #else /** Copy constructor. * When a vector grows, libstdc++ calls the copy constructor for * each element of the vector, which would invalidate any cstring * that point to this const_string. To work around this issue, the * new const_string gets the original data, and the old * const_string gets the copy, which will probably be destructed * soon. Making the copy is wasteful, but the C++ standard does * not help us out here. */ const_string(const const_string& s) : cstring(s.c_str()) { const_cast(s).m_p = strcpy(new char[s.size() + 1], s.c_str()); } #endif ~const_string() { delete[] m_p; } const_string& operator=(const const_string& s) { assert(false); if (this == &s) return *this; assert(m_p != s.m_p); delete[] m_p; m_p = strcpy(new char[s.size() + 1], s.c_str()); return *this; } void swap(const_string& s) { std::swap(m_p, s.m_p); } private: const_string(); const_string(const char* s); const_string(const cstring&); bool operator==(const const_string& s); }; namespace std { template <> inline void swap(const_string& a, const_string& b) { a.swap(b); } } NAMESPACE_STD_HASH_BEGIN template <> struct hash { size_t operator()(const cstring& s) const { return hashmem(s.c_str(), strlen(s.c_str())); } }; NAMESPACE_STD_HASH_END #endif abyss-2.2.4/Common/ContigID.cpp000066400000000000000000000001151361462241400162340ustar00rootroot00000000000000#include "ContigID.h" Dictionary g_contigNames; unsigned g_nextContigName; abyss-2.2.4/Common/ContigID.h000066400000000000000000000033631361462241400157110ustar00rootroot00000000000000#ifndef CONTIGID_H #define CONTIGID_H 1 #include "ConstString.h" #include "Dictionary.h" #include #include #include #include /** The dictionary of contig names. */ extern Dictionary g_contigNames; /** The next unique contig name. */ extern unsigned g_nextContigName; /** Set the next contig name returned by createContigName. */ static inline void setNextContigName(cstring s) { std::istringstream iss((std::string)s); if (iss >> g_nextContigName && iss.eof()) ++g_nextContigName; else g_nextContigName = 0; } /** * Set the next contig name returned by createContigName * to one plus the current largest numeric contig name. */ static inline void setNextContigName() { if (g_contigNames.empty()) { g_nextContigName = 0; return; } unsigned maxContigName = 0; for (unsigned i = 0; i < g_contigNames.size(); ++i) { cstring s = g_contigNames.getName(i); std::istringstream iss((std::string)s); unsigned contigName; if (iss >> contigName && iss.eof() && contigName > maxContigName) maxContigName = contigName; } g_nextContigName = 1 + maxContigName; } /** Return the next unique contig name. */ static inline std::string createContigName() { if (g_nextContigName == 0) setNextContigName(); std::ostringstream ss; ss << g_nextContigName++; return ss.str(); } /** A contig index. */ class ContigID { public: ContigID() { } explicit ContigID(unsigned index) : m_index(index) { }; /** Return the index. */ operator unsigned() const { return m_index; } /** The insertion operator is not implemented to prevent * unintentional use of the cast operator (unsigned). */ friend std::ostream& operator<<(std::ostream&, const ContigID&); private: /** The index. */ unsigned m_index; }; #endif abyss-2.2.4/Common/ContigNode.h000066400000000000000000000151361361462241400163030ustar00rootroot00000000000000#ifndef CONTIGNODE_H #define CONTIGNODE_H 1 #include "config.h" // for WORDS_BIGENDIAN #include "ContigID.h" #include "Graph/Properties.h" #include "StringUtil.h" #include #include #include // for strtoul #include #include // for intptr_t #include #include /** A vertex of a contig graph, which is a pair of a contig index and * an orientation. */ class ContigNode { public: ContigNode() : m_index(0) { } ContigNode(const ContigNode& o) : m_index(o.m_index) { } /** Construct from a vertex index. */ explicit ContigNode(unsigned index) : m_index(index) { } /** Construct from a contig index and an orientation. */ ContigNode(unsigned index, bool sense) : m_index(2 * index + sense) { } /** Construct from a contig index and an orientation. */ ContigNode(unsigned index, int sense) : m_index(2 * index + sense) { assert(sense == 0 || sense == 1); } /** Construct an ambiguous ContigNode. */ ContigNode(unsigned n, char c) : m_index(-(int)n) { assert(n > 0); assert(c == 'N'); (void)c; } bool operator==(const ContigNode& o) const { return m_index == o.m_index; } bool operator!=(const ContigNode& o) const { return m_index != o.m_index; } bool operator<(const ContigNode& o) const { return m_index < o.m_index; } /** Return the complement of this vertex if sense is true. */ ContigNode operator^(bool sense) const { assert(!ambiguous()); return ContigNode(m_index ^ sense); } /** Copy constructors */ ContigNode(ContigNode&&) = default; ContigNode& operator=(const ContigNode&) = default; ContigNode& operator=(ContigNode&&) = default; /** Return whether this ContigNode is ambiguous. */ bool ambiguous() const { return m_index < 0; } /** Return the vertex index. */ unsigned index() const { assert(!ambiguous()); return m_index; } /** Return the contig index. */ unsigned id() const { return ambiguous() ? m_index : m_index / 2; } /** Return the contig index as a ContigID. */ ContigID contigIndex() const { assert(!ambiguous()); return ContigID(id()); } /** Return the orientation of this vertex. */ bool sense() const { assert(!ambiguous()); return m_index & 1; } /** Return the length in k-mer of this ambiguous contig. */ unsigned length() const { assert(ambiguous()); return -m_index; } /** Return the string of Ns. */ std::string ambiguousSequence() const { assert(ambiguous()); unsigned n = length(); if (n > 100000) { std::cerr << "warning: scaffold gap is longer than 100 kbp: " << n << '\n'; } else if (n > 1000000) { std::cerr << "error: scaffold gap is longer than 1 Mbp: " << n << '\n'; exit(EXIT_FAILURE); } return std::string(n, 'N'); } /** Toggle the orientation of this vertex if sense is true. */ ContigNode& operator^=(bool sense) { assert(!ambiguous()); m_index ^= sense; return *this; } /** Increment this vertex index. */ ContigNode& operator++() { assert(!ambiguous()); ++m_index; return *this; } private: int m_index; }; /** Return the hash value of this ContigNode. */ static inline unsigned hash_value(const ContigNode& o) { return o.index(); } /** Vertex index property map of a ContigNode. */ struct ContigNodeIndexMap : boost::put_get_helper { typedef ContigNode key_type; typedef unsigned value_type; typedef value_type reference; typedef boost::readable_property_map_tag category; reference operator[](const key_type& u) const { return u.index(); } }; /** Contig index property map of a ContigNode. */ struct ContigIndexMap : boost::put_get_helper { typedef ContigNode key_type; typedef ContigID value_type; typedef value_type reference; typedef boost::readable_property_map_tag category; reference operator[](const key_type& u) const { return u.contigIndex(); } }; /** Return the contig name of the specified vertex. */ template Dictionary::name_reference get(vertex_contig_name_t, const Graph&, ContigNode u) { assert(!u.ambiguous()); return get(g_contigNames, u.id()); } /** The string representation of a vertex name. */ struct VertexName : std::pair { typedef std::pair Base; VertexName(const char* s, char c) : Base(reinterpret_cast(s), c) { assert(c == '+' || c == '-'); } VertexName(unsigned n, char c) : Base(n, c) { assert(c == 'N'); } friend std::ostream& operator<<( std::ostream& out, const VertexName& o) { if (o.second == 'N') out << o.first; else out << reinterpret_cast(o.first); return out << o.second; } }; /** Return the name of the specified vertex. */ static inline VertexName get(const Dictionary& pmap, ContigNode u) { return u.ambiguous() ? VertexName(u.length(), 'N') : VertexName(get(pmap, u.id()), u.sense() ? '-' : '+'); } /** Return the name of the specified vertex. */ template VertexName get(vertex_name_t, const Graph&, ContigNode u) { return get(g_contigNames, u); } /** Set the name of the specified vertex. */ template void put(vertex_name_t, const Graph&, ContigNode u, const std::string& name) { assert(!name.empty()); char c = name[name.size() - 1]; if (c == '+' || c == '-') put(g_contigNames, u.id(), name.substr(0, name.size() - 1)); else put(g_contigNames, u.id(), name); } /** The string representation of an edge name. */ struct EdgeName : std::pair { typedef std::pair Base; EdgeName(Base::first_type a, Base::second_type b) : Base(a, b) { } friend std::ostream& operator<<( std::ostream& out, const EdgeName& o) { return out << '"' << o.first << "\" -> \"" << o.second << '"'; } }; /** Return the name of the specified edge. */ static inline EdgeName get(const Dictionary& pmap, std::pair e) { return EdgeName(get(pmap, e.first), get(pmap, e.second)); } /** Return the name of the specified edge. */ template EdgeName get(edge_name_t, const Graph& g, std::pair e) { return EdgeName( get(vertex_name, g, source(e, g)), get(vertex_name, g, target(e, g))); } /** Find the vertex with the specified name. */ static inline ContigNode find_vertex( std::string name, bool sense, const Dictionary& pmap) { assert(!name.empty()); return ContigNode(get(pmap, name), sense); } /** Find the vertex with the specified name. */ static inline ContigNode find_vertex( std::string name, const Dictionary& pmap) { assert(!name.empty()); char c = chop(name); assert(c == '+' || c == '-' || c == 'N'); return c == 'N' ? ContigNode(strtoul(name.c_str(), NULL, 0), 'N') : find_vertex(name, c == '-', pmap); } #endif abyss-2.2.4/Common/ContigPath.h000066400000000000000000000035271361462241400163130ustar00rootroot00000000000000#ifndef CONTIGPATH_H #define CONTIGPATH_H 1 #include "ContigNode.h" #include #include #include #include #include #include #include #include /** A sequence of ContigNode. */ typedef std::vector ContigPath; /** Reverse and complement the specified path. */ template void reverseComplement(T first, T last) { std::reverse(first, last); for (T it = first; it < last; ++it) if (!it->ambiguous()) *it ^= 1; } /** Return the reverse complement of the specified path. */ static inline ContigPath reverseComplement(const ContigPath& path) { ContigPath rc(path.rbegin(), path.rend()); for (ContigPath::iterator it = rc.begin(); it < rc.end(); ++it) if (!it->ambiguous()) *it ^= 1; return rc; } static inline std::ostream& operator<<(std::ostream& out, const ContigPath& o) { assert(!o.empty()); ContigPath::const_iterator it = o.begin(); out << get(g_contigNames, *it); for (++it; it != o.end(); ++it) out << ' ' << get(g_contigNames, *it); return out; } static inline std::istream& operator>>(std::istream& in, ContigPath& o) { o.clear(); std::string s; if (getline(in, s)) { std::istringstream ss(s); for (std::string name; ss >> name;) o.push_back(find_vertex(name, g_contigNames)); assert(ss.eof()); } return in; } static inline void markSeenInPath(std::istream& in, std::vector& marked) { assert(in.good()); std::string s; ContigPath path; while (in >> s >> path) { if (path.empty()) { size_t i = get(g_contigNames, s); assert(i < marked.size()); marked[i] = true; } for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) { if (!it->ambiguous()) { size_t i = it->contigIndex(); assert(i < marked.size()); marked[i] = true; } } } assert(in.eof()); } #endif abyss-2.2.4/Common/ContigProperties.h000066400000000000000000000126201361462241400175450ustar00rootroot00000000000000#ifndef CONTIGPROPERTIES_H #define CONTIGPROPERTIES_H 1 #include "ContigNode.h" #include "Graph/Options.h" #include "Graph/Properties.h" #include "IOUtil.h" #include #include #include #include using boost::graph_traits; /** Contig length property. */ struct Length { unsigned length; bool operator==(const Length& o) const { return length == o.length; } Length& operator+=(const Length& o) { length += o.length; return *this; } template Length& operator+=(const T& o) { assert((int)length + (int)o.distance >= 0); length += o.distance; return *this; } friend std::ostream& operator<<(std::ostream& out, const Length& o) { return out << "l=" << o.length; } friend std::istream& operator>>(std::istream& in, Length& o) { if (in >> std::ws && in.peek() == 'l') return in >> expect("l =") >> o.length; else return in >> o.length; } }; static inline void put(vertex_length_t, Length& vp, unsigned length) { vp.length = length; } static inline void put(vertex_coverage_t, Length&, unsigned) { } /** The length and coverage of a contig. */ struct ContigProperties { unsigned length; unsigned coverage; ContigProperties() : length(0), coverage(0) { } ContigProperties(unsigned length, unsigned coverage) : length(length), coverage(coverage) { } bool operator==(const ContigProperties& o) const { return length == o.length && coverage == o.coverage; } ContigProperties& operator +=(const ContigProperties& o) { length += o.length; coverage += o.coverage; return *this; } friend std::ostream& operator <<(std::ostream& out, const ContigProperties& o) { float coverage = opt::k <= 0 ? 0 : (float)o.coverage / (o.length - opt::k + 1); switch (opt::format) { case ADJ: return out << ' ' << o.length << ' ' << o.coverage; case DOT: return out << "l=" << o.length << " C=" << o.coverage; case DOT_MEANCOV: assert(opt::k > 0); return out << "l=" << o.length << " c=" << coverage; case SAM: out << "\tLN:" << o.length; return opt::k > 0 ? (out << "\tXc:" << coverage) : (out << "\tXC:" << o.coverage); } return out; } friend std::istream& operator >>(std::istream& in, ContigProperties& o) { if (in >> std::ws && in.peek() == 'l') { in >> expect("l =") >> o.length; if (in >> std::ws && in.peek() == 'C') in >> expect("C =") >> o.coverage; return in; } else if (in.peek() == 'C') { return in >> expect("C=") >> o.coverage >> expect(", l=") >> o.length; } else return in >> o.length >> o.coverage; } }; static inline void put(vertex_length_t, ContigProperties& vp, unsigned length) { vp.length = length; } static inline void put(vertex_coverage_t, ContigProperties& vp, unsigned coverage) { vp.coverage = coverage; } /** The distance between two contigs. */ struct Distance { int distance; Distance() : distance(-opt::k + 1) { } Distance(int d) : distance(d) { } bool operator==(const Distance& o) const { return distance == o.distance; } bool operator!=(const Distance& o) const { return distance != o.distance; } friend std::ostream& operator<<(std::ostream& out, const Distance& o) { return out << "d=" << o.distance; } friend std::istream& operator>>(std::istream& in, Distance& o) { in >> expect(" d = "); if (in.peek() == '"') return in >> expect("\"") >> o.distance >> expect("\""); else return in >> o.distance; } }; /** Add the specified distance (overlap) to the specified contig * length. */ template ContigProperties& operator+=(ContigProperties& a, const T& b) { assert((int)a.length + (int)b.distance > 0); a.length += b.distance; return a; } /** Return the distance between two vertices. */ template int get(edge_distance_t, const Graph& g, typename graph_traits::edge_descriptor e) { return g[e].distance; } /** Return the edge properties of (u,v) unless either u or v is * ambiguous, in which case return a default-constructed instance of * the edge properties. */ template typename edge_bundle_type::type get(edge_bundle_t, const Graph& g, ContigNode u, ContigNode v) { typedef typename graph_traits::edge_descriptor edge_descriptor; if (u.ambiguous() || v.ambiguous()) { return typename edge_bundle_type::type(); } else { std::pair e = edge(u, v, g); if (!e.second) std::cerr << "error: no edge " << get(vertex_name, g, u) << " -> " << get(vertex_name, g, v) << '\n'; assert(e.second); return g[e.first]; } } /** Edge weight property map. */ template struct EdgeWeightMap { typedef typename Graph::edge_descriptor key_type; typedef int value_type; typedef value_type reference; typedef boost::readable_property_map_tag category; EdgeWeightMap(const Graph& g) : m_g(g) { } reference operator[](const key_type& e) const { int weight = m_g[e].distance + m_g[target(e, m_g)].length; if (weight < 0) std::cerr << "error: invalid edge: " << get(edge_name, m_g, e) << " [" << get(edge_bundle, m_g, e) << "]\n"; assert(weight >= 0); return weight; } private: const Graph& m_g; }; /** Return the edge weight. */ template typename EdgeWeightMap::value_type get(edge_weight_t, const Graph& g, typename graph_traits::edge_descriptor e) { return EdgeWeightMap(g)[e]; } #endif abyss-2.2.4/Common/Dictionary.h000066400000000000000000000056411361462241400163570ustar00rootroot00000000000000#ifndef DICTIONARY_H #define DICTIONARY_H 1 #include "ConstString.h" #include "UnorderedMap.h" #include #include #include #include #include /** A bidirectional map of indices and names. */ class Dictionary { public: typedef unsigned index_type; typedef unsigned index_reference; typedef std::string name_type; typedef cstring name_reference; typedef std::vector Vector; typedef unordered_map > Map; Dictionary() : m_locked(false) { } /** Insert the specified name. */ index_reference insert(const name_type& name) { m_vec.push_back(name); std::pair inserted = m_map.insert(Map::value_type( m_vec.back(), m_map.size())); if (!inserted.second) { std::cerr << "error: duplicate ID: `" << name << "'\n"; abort(); } return inserted.first->second; } /** If the specified index is within this dictionary, ensure * that the name is identical, otherwise append the name to * this dictionary. */ void put(index_type index, const name_type& name) { if (index < m_vec.size()) { assert(getName(index) == name); } else { assert(!m_locked); assert(index == m_vec.size()); index_type i = insert(name); assert(i == index); (void)i; } } /** Return the index of the specified name. */ index_reference getIndex(const name_type& name) const { Map::const_iterator it = m_map.find(name); if (it == m_map.end()) { std::cerr << "error: unexpected ID: `" << name << "'\n"; abort(); } return it->second; } /** Return the name of the specified index. */ name_reference getName(index_type index) const { assert(index < m_vec.size()); return m_vec[index]; } /** Lock this dictionary. No further elements may be added. */ void lock() { m_locked = true; } /** Unlock this dictionary. */ void unlock() { m_locked = false; } /** Return true if this dictionary is empty. */ bool empty() const { return m_vec.empty(); } /** Return the number of elements in this dictionary. */ size_t size() const { return m_vec.size(); } /** Return the number of elements with the specified name. */ size_t count(const name_type& name) const { return m_map.count(name); } /** Return the last name in this dictionary. */ name_reference back() const { assert(!m_vec.empty()); return m_vec.back(); } private: Map m_map; Vector m_vec; bool m_locked; }; static inline Dictionary::name_reference get( const Dictionary& pmap, Dictionary::index_type index) { return pmap.getName(index); } static inline void put(Dictionary& pmap, Dictionary::index_type index, const Dictionary::name_type& name) { pmap.put(index, name); } static inline Dictionary::index_reference get( const Dictionary& pmap, Dictionary::name_type name) { return pmap.getIndex(name); } #endif abyss-2.2.4/Common/Estimate.h000066400000000000000000000114651361462241400160260ustar00rootroot00000000000000#ifndef ESTIMATE_H #define ESTIMATE_H 1 #include "Common/ContigProperties.h" // for Distance #include "Common/Exception.h" #include "ContigID.h" #include "ContigNode.h" #include "Graph/Options.h" // for opt::k #include "IOUtil.h" #include #include // for ceilf #include #include #include #include #include #include #include namespace opt { /** The acceptable error of a distance estimate. */ extern unsigned distanceError; } /** An estimate of the distance between two contigs. */ struct DistanceEst { int distance; unsigned numPairs; float stdDev; DistanceEst() : distance(-opt::k + 1), numPairs(0), stdDev(0) { } DistanceEst(int distance) : distance(distance), numPairs(0), stdDev(distance) { } DistanceEst(int distance, unsigned numPairs, float stdDev) : distance(distance), numPairs(numPairs), stdDev(stdDev) { } bool operator==(const DistanceEst& o) const { return distance == o.distance && numPairs == o.numPairs && stdDev == o.stdDev; } friend std::ostream& operator<<(std::ostream& out, const DistanceEst& o) { if (opt::format == DIST) { return out << o.distance << ',' << o.numPairs << ',' << std::fixed << std::setprecision(1) << o.stdDev; } else if (opt::format == GFA1 || opt::format == GFA2) { out << o.distance; if (o.stdDev > 0 || o.numPairs > 0) out << '\t' << ceilf(o.stdDev) << '\t' << "FC:i:" << o.numPairs; else out << "\t*"; return out; } else { out << "d=" << o.distance; if (o.stdDev > 0 || o.numPairs > 0) out << " e=" << std::fixed << std::setprecision(1) << o.stdDev << " n=" << o.numPairs; return out; } } friend std::istream& operator>>(std::istream& in, DistanceEst& o) { if (in >> std::ws && in.peek() == 'd') { // Graphviz if (!(in >> expect("d =") >> o.distance >> std::ws)) return in; if (in.peek() == ']') { o.stdDev = o.numPairs = 0; return in; } else if (in.peek() == ',') return in >> expect(", e =") >> o.stdDev >> expect(", n =") >> o.numPairs; else return in >> expect(" e =") >> o.stdDev >> expect(" n =") >> o.numPairs; } else { in >> o.distance; if (in.peek() == ',') { // ABySS dist return in >> expect(",") >> o.numPairs >> expect(",") >> o.stdDev; } else { // GFA 2 in >> o.stdDev; if (in.peek() == '\n') return in; in >> expect("\t"); if (in.peek() == 'F') in >> expect("FC:i:") >> o.numPairs; return in; } } } }; /** Return the better of two distance estimates. * Return the estimate whose error is least, or when the errors are * equal, return the larger distance estimate. * Add the number of pairs. */ struct BetterDistanceEst { NoProperty operator()( const NoProperty& a, const NoProperty&) const { 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 { bool which = a.stdDev != b.stdDev ? a.stdDev < b.stdDev : a.distance > b.distance; DistanceEst x = which ? a : b; x.numPairs = a.numPairs + b.numPairs; return x; } }; /** Merge two distance estimates. */ struct MergeDistanceEst { DistanceEst operator()( const DistanceEst& a, const DistanceEst& b) const { int x1 = a.distance, x2 = b.distance; double v1 = a.stdDev * a.stdDev, v2 = b.stdDev * b.stdDev; DistanceEst x; x.distance = (int)round((x1 * v2 + x2 * v1) / (v1 + v2)); x.stdDev = sqrt(v1 * v2 / (v1 + v2)); x.numPairs = a.numPairs + b.numPairs; return x; } }; /** Return the allowed error for the given estimate. */ static inline unsigned allowedError(float stddev) { /** The number of standard deviations. */ const int NUM_SIGMA = 3; return (unsigned)ceilf(NUM_SIGMA * stddev + opt::distanceError); } /** Distance estimates to and from a particular contig. */ struct EstimateRecord { typedef std::pair Estimate; typedef std::vector Estimates; ContigID refID; Estimates estimates[2]; /** Read the distance estimates for one contig. */ friend std::istream& operator >>(std::istream& in, EstimateRecord& o) { o.estimates[false].clear(); o.estimates[true].clear(); std::string name; in >> name; if (!in) return in; o.refID = ContigID(get(g_contigNames, name)); for (int rc = false; rc <= true; ++rc) { std::string s; std::getline(in, s, !rc ? ';' : '\n'); std::istringstream ss(s); for (Estimate ep; getline(ss >> std::ws, s, ',');) { ep.first = find_vertex(s, g_contigNames); if (ss >> ep.second) o.estimates[rc].push_back(ep); } assert(ss.eof()); } return in; } }; namespace std { template<> inline void swap(EstimateRecord&, EstimateRecord&) NOEXCEPT { assert(false); } } #endif abyss-2.2.4/Common/Exception.h000066400000000000000000000004451361462241400162050ustar00rootroot00000000000000#ifndef _EXCEPTION_H_ #define _EXCEPTION_H_ 1 /* `noexcept` is only recognized in C++11 or later. See https://stackoverflow.com/questions/24567173/backwards-compatible-noexceptfalse-for-destructors */ #if __cplusplus >= 201103L #define NOEXCEPT noexcept #else #define NOEXCEPT #endif #endif abyss-2.2.4/Common/Fcontrol.cpp000066400000000000000000000004011361462241400163600ustar00rootroot00000000000000#include "Fcontrol.h" #include /* Set the FD_CLOEXEC flag of the specified file descriptor. */ int setCloexec(int fd) { int flags = fcntl(fd, F_GETFD, 0); if (flags == -1) return -1; flags |= FD_CLOEXEC; return fcntl(fd, F_SETFD, flags); } abyss-2.2.4/Common/Fcontrol.h000066400000000000000000000001111361462241400160230ustar00rootroot00000000000000#ifndef FCONTROL_H #define FCONTROL_H 1 int setCloexec(int fd); #endif abyss-2.2.4/Common/Functional.h000066400000000000000000000035651361462241400163570ustar00rootroot00000000000000#ifndef FUNCTIONAL_H #define FUNCTIONAL_H 1 #include /** A functor that always returns true. */ template struct True : std::unary_function { bool operator()(const Arg&) const { return true; } }; /** A functor to adapt a pointer to a member variable. */ template struct MemVar : std::unary_function { MemVar(Result Arg::* p) : m_p(p) { } Result operator()(const Arg& arg) const { return arg.*m_p; } private: Result Arg::* m_p; }; /** Return a functor to adapt a pointer to a member variable. */ template MemVar mem_var(Result Arg::* p) { return MemVar(p); } /** A functor, f1(f2(x)). */ template struct unary_compose : std::unary_function < typename F2::argument_type, typename F1::result_type> { unary_compose(const F1& f1, const F2& f2) : f1(f1), f2(f2) { } typename F1::result_type operator()( const typename F2::argument_type& x) const { return f1(f2(x)); } private: F1 f1; F2 f2; }; /** Return a functor, f1(f2(x)). */ template unary_compose compose1(const F1& f1, const F2& f2) { return unary_compose(f1, f2); } /** A functor, f(g1(x), g2(x)). */ template struct binary_compose : std::unary_function < typename G1::argument_type, typename F::result_type> { binary_compose(const F& f, const G1& g1, const G2& g2) : f(f), g1(g1), g2(g2) { } typename G1::result_type operator()( const typename G1::argument_type& x) const { return f(g1(x), g2(x)); } private: F f; G1 g1; G2 g2; }; /** Return a functor, f(g1(x), g2(x)). */ template binary_compose compose2( const F& f, const G1& g1, const G2& g2) { return binary_compose(f, g1, g2); } #endif abyss-2.2.4/Common/Hash.h000066400000000000000000000011121361462241400151220ustar00rootroot00000000000000#ifndef HASH_H_ #define HASH_H_ 1 #include "config.h" #if HAVE_STD_HASH #ifdef __FUJITSU # include #else # include #endif using std::hash; # define NAMESPACE_STD_HASH_BEGIN namespace std { # define NAMESPACE_STD_HASH_END } #elif HAVE_STD_TR1_HASH # include using std::tr1::hash; # define NAMESPACE_STD_HASH_BEGIN namespace std { namespace tr1 { # define NAMESPACE_STD_HASH_END } } #else # include using boost::hash; # define NAMESPACE_STD_HASH_BEGIN namespace boost { # define NAMESPACE_STD_HASH_END } #endif #endif abyss-2.2.4/Common/HashFunction.h000066400000000000000000000005601361462241400166360ustar00rootroot00000000000000#ifndef HASHFUNCTION_H #define HASHFUNCTION_H 1 #include "city.h" #include #include static inline uint64_t hashmem(const void *p, size_t n) { return CityHash64(static_cast(p), n); } static inline uint64_t hashmem(const void *p, size_t n, size_t seed) { return CityHash64WithSeed(static_cast(p), n, seed); } #endif abyss-2.2.4/Common/Histogram.cpp000066400000000000000000000050021361462241400165310ustar00rootroot00000000000000#include "Histogram.h" #include #include #include #include using namespace std; /** Remove samples less than the specified threshold. */ Histogram Histogram::trimLow(T threshold) const { Histogram h; for (Histogram::Map::const_iterator it = m_map.begin(); it != m_map.end(); it++) if (it->first >= threshold) h.insert(it->first, it->second); return h; } /** Trim off the bottom fraction/2 and top fraction/2 data points. * At least (1 - fraction) of the data will remain. */ Histogram Histogram::trimFraction(double fraction) const { double low_cutoff = fraction/2; double high_cutoff = 1.0f - fraction/2; size_type n = size(); double cumulative = 0; Histogram newHist; for (Histogram::Map::const_iterator it = m_map.begin(); it != m_map.end(); it++) { double temp_total = cumulative + (double)it->second / n; if (temp_total > low_cutoff && cumulative < high_cutoff) newHist.insert(it->first, it->second); cumulative = temp_total; } return newHist; } /** Bin these elements into n buckets. The number of buckets returned * may be smaller than n. */ Histogram::Bins Histogram::bin(unsigned n) const { Histogram::Bins bins; bins.reserve(n); T nperbucket = (T)ceilf((float)(maximum() - minimum()) / n); T next = minimum() + nperbucket; Histogram::Bins::value_type count = 0; for (Histogram::Map::const_iterator it = m_map.begin(); it != m_map.end(); it++) { if (it->first >= next) { bins.push_back(count); count = 0; next += nperbucket; } count += it->second; } if (count > 0) bins.push_back(count); return bins; } /** Return a unicode bar plot. * @param n number of buckets */ string Histogram::barplot(unsigned nbins) const { /** Unicode bar characters. */ static const char* bars[10] = { " ", "_", "\342\226\201", // 9601 "\342\226\202", // 9602 "\342\226\203", // 9603 "\342\226\204", // 9604 "\342\226\205", // 9605 "\342\226\206", // 9606 "\342\226\207", // 9607 "\342\226\210", // 9608 }; Histogram::Bins bins = bin(nbins); ostringstream ss; Histogram::Bins::value_type max = 1 + *max_element(bins.begin(), bins.end()); for (Histogram::Bins::const_iterator it = bins.begin(); it != bins.end(); ++it) ss << bars[10 * *it / max]; string s(ss.str()); while (!s.empty() && *s.rbegin() == ' ') s.erase(s.size() - 1); return s; } /** Return a unicode bar plot. */ string Histogram::barplot() const { const char *columns = getenv("COLUMNS"); return barplot(columns == NULL ? 80 : strtoul(columns, NULL, 0)); } abyss-2.2.4/Common/Histogram.h000066400000000000000000000226461361462241400162130ustar00rootroot00000000000000#ifndef HISTOGRAM_H #define HISTOGRAM_H 1 #include "Common/Exception.h" #include "StringUtil.h" // for toEng #include "VectorUtil.h" // for make_vector #include #include // for INT_MAX #include #include #include #include #include #include /** A histogram of type T, which is int be default. * A histogram may be implemented as a multiset. This class aims * to provide a similar interface to a multiset. */ class Histogram { typedef int T; typedef size_t size_type; typedef std::map Map; typedef long long unsigned accumulator; public: typedef Map::const_iterator const_iterator; Histogram() { } /** Construct a histogram of the specified elements. */ template Histogram(InputIterator first, InputIterator last) { for (InputIterator it = first; it != last; ++it) insert(*it); } /** Construct a histogram from a vector, where the index into the * vector is the sample, and the value at that index is the number * of times that sample was observed. */ explicit Histogram(std::vector v) { for (T i = 0; i < (T)v.size(); i++) if (v[i] > 0) m_map.insert(std::make_pair(i, v[i])); } void insert(T value) { m_map[value]++; } void insert(T value, size_type count) { m_map[value] += count; } size_type count(T value) const { Map::const_iterator iter = m_map.find(value); return iter == m_map.end() ? 0 : iter->second; } /** Return the number of elements in the range [lo,hi]. */ size_type count(T lo, T hi) const { assert(lo <= hi); size_type n = 0; Map::const_iterator last = m_map.upper_bound(hi); for (Map::const_iterator it = m_map.lower_bound(lo); it != last; ++it) n += it->second; return n; } T minimum() const { return empty() ? 0 : m_map.begin()->first; } T maximum() const { return empty() ? 0 : m_map.rbegin()->first; } bool empty() const { return m_map.empty(); } size_type size() const { size_type n = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) n += it->second; return n; } /** Return the sum. */ accumulator sum() const { accumulator total = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) total += (accumulator)it->first * it->second; return total; } /** Return the mean. */ double mean() const { accumulator n = 0, total = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { n += it->second; total += (accumulator)it->first * it->second; } return (double)total / n; } double variance() const { accumulator n = 0, total = 0, squares = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { n += it->second; total += (accumulator)it->first * it->second; squares += (accumulator)it->first * it->first * it->second; } return (squares - (double)total * total / n) / n; } double sd() const { return sqrt(variance()); } /** Return the specified percentile. */ T percentile(float p) const { size_type x = (size_type)ceil(p * size()); size_type n = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { n += it->second; if (n >= x) return it->first; } return maximum(); } /** Return the median. */ T median() const { return percentile(0.5); } /** Return the largest weight in the arg min of partial sum of * weights. */ T argMin(accumulator x) const { accumulator total = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { total += (accumulator)it->first * it->second; if (total >= x) return it->first; } return maximum(); } /** Return the specified weighted percentile. */ T weightedPercentile(float p) const { return argMin((accumulator)ceil(p * sum())); } /** Return the expected value */ double expectedValue() const { double value = 0; accumulator acc = sum(); for (Map::const_iterator it = m_map.begin(); it != m_map.end(); it++) { value += (double)it->first * it->first * it->second / acc; } return value; } /** Return the N50. */ T n50() const { return weightedPercentile(0.5); } /** Return the first local minimum or zero if a minimum is not * found. */ T firstLocalMinimum() const { const unsigned SMOOTHING = 4; assert(!empty()); Map::const_iterator minimum = m_map.begin(); size_type count = 0; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { if (it->second <= minimum->second) { minimum = it; count = 0; } else if (++count >= SMOOTHING) break; } if (minimum->first == maximum()) return 0; return minimum->first; } void eraseNegative() { for (Map::iterator it = m_map.begin(); it != m_map.end();) if (it->first < 0) m_map.erase(it++); else ++it; } /** Remove noise from the histogram. Noise is defined as a * sample x where h[x-1] == 0 && h[x+1] == 0. */ void removeNoise() { for (Map::iterator it = m_map.begin(); it != m_map.end();) { if (m_map.count(it->first - 1) == 0 && m_map.count(it->first + 1) == 0 && m_map.size() > 1) m_map.erase(it++); else ++it; } } /** Remove outliers from the histogram. A sample is an outlier * if it is outside the range [Q1 - k*(Q3-Q1), Q3 + k*(Q3-Q1)] * where k = 20. */ void removeOutliers() { T q1 = percentile(0.25); T q3 = percentile(0.75); T l = q1 - 20 * (q3 - q1); T u = q3 + 20 * (q3 - q1); for (Map::iterator it = m_map.begin(); it != m_map.end();) { if (it->first < l || it->first > u) m_map.erase(it++); else ++it; } } /** Negate each element of this histogram. */ Histogram negate() const { Histogram h; for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) h.m_map.insert(std::make_pair(-it->first, it->second)); return h; } Histogram trimFraction(double fraction) const; Histogram trimLow(T threshold) const; typedef std::vector Bins; Bins bin(unsigned n) const; std::string barplot() const; std::string barplot(unsigned nbins) const; const_iterator begin() const { return m_map.begin(); } const_iterator end() const { return m_map.end(); } /** Return a vector representing this histogram. */ std::vector toVector() const { assert(minimum() >= 0); #if 0 std::vector v(maximum()+1); #else // CommLayer::reduce requires the arrays have the same size. std::vector v(65536); assert(maximum() < (T)v.size()); #endif for (Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) v[it->first] = it->second; return v; } friend std::ostream& operator<<(std::ostream& o, const Histogram& h) { for (Map::const_iterator it = h.m_map.begin(); it != h.m_map.end(); ++it) o << it->first << '\t' << it->second << '\n'; return o; } friend std::istream& operator>>(std::istream& in, Histogram& h) { Histogram::T value; size_type count; while (in >> value >> count) h.insert(value, count); assert(in.eof()); return in; } private: Map m_map; }; namespace std { template<> inline void swap(Histogram&, Histogram&) NOEXCEPT { assert(false); } } /** Print assembly contiguity statistics header. */ static inline std::ostream& printContiguityStatsHeader( std::ostream& out, unsigned minSize, const std::string& sep = "\t", const long long unsigned expSize = 0) { out << "n" << sep << "n:" << minSize << sep << "L50" << sep; if (expSize > 0) out << "LG50" << sep << "NG50" << sep; return out << "min" << sep << "N75" << sep << "N50" << sep << "N25" << sep << "E-size" << sep << "max" << sep << "sum" << sep << "name" << '\n'; } /** Print assembly contiguity statistics. */ static inline std::ostream& printContiguityStats( std::ostream& out, const Histogram& h0, unsigned minSize, bool printHeader = true, const std::string& sep = "\t", const long long unsigned expSize = 0) { Histogram h = h0.trimLow(minSize); if (printHeader) printContiguityStatsHeader(out, minSize, sep, expSize); unsigned n50 = h.n50(); out << toEng(h0.size()) << sep << toEng(h.size()) << sep << toEng(h.count(n50, INT_MAX)) << sep; long long unsigned sum = h.sum(); if (expSize > 0) { unsigned ng50; if (sum < expSize/2) ng50 = h.minimum(); else ng50 = h.argMin(sum - expSize/2); out << toEng(h.count(ng50, INT_MAX)) << sep << toEng(ng50) << sep; } return out << toEng(h.minimum()) << sep << toEng(h.weightedPercentile(1 - 0.75)) << sep << toEng(n50) << sep << toEng(h.weightedPercentile(1 - 0.25)) << sep << toEng((unsigned)h.expectedValue()) << sep << toEng(h.maximum()) << sep << toEng(sum); } /** Pass assembly contiguity statistics -- values only. */ static inline std::vector 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 vec = make_vector() << h0.size() << h.size() << h.count(n50, INT_MAX) << h.minimum() << h.weightedPercentile(1 - 0.75) << n50 << h.weightedPercentile(1 - 0.25) << (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(); #endif } #endif abyss-2.2.4/Common/IOUtil.h000066400000000000000000000060451361462241400154160ustar00rootroot00000000000000#ifndef IOUTIL_H #define IOUTIL_H 1 #include #include #include #include // for strerror #include #include #include // for numeric_limits #include /** Print an error message and exit if stream is not good. */ static inline void assert_good(const std::ios& stream, const std::string& path) { if (!stream.good()) { std::cerr << "error: `" << path << "': " << strerror(errno) << std::endl; exit(EXIT_FAILURE); } } /** Print an error message and exit if stream is not eof. */ static inline void assert_eof(std::istream& in, const std::string& path) { if (!in.eof()) { in.clear(); std::string s; std::getline(in, s); std::cerr << "error: `" << path << "': " "Expected end-of-file and saw `" << s << "'\n"; exit(EXIT_FAILURE); } } /** This input stream manipulator skips the specified string. */ struct expect { const char* s; expect(const char* s) : s(s) { } }; static inline std::istream& operator>>(std::istream& in, expect o) { for (const char* p = o.s; *p != '\0'; ++p) { if (*p == ' ') { in >> std::ws; } else { char c = in.get(); if (!in || c != *p) { std::cerr << "error: Expected `" << p << "' and saw "; if (in) { std::cerr << '`' << c << "'\n"; std::string s; if (getline(in, s) && !s.empty()) std::cerr << "near: " << c << s << '\n'; } else if (in.eof()) std::cerr << "end-of-file\n"; else std::cerr << "I/O error\n"; exit(EXIT_FAILURE); } } } return in; } /** This input stream manipulator discards characters until reaching * the delimeter. */ struct Ignore { const char delim; size_t n; Ignore(const char delim, size_t n = std::numeric_limits::max()) : delim(delim), n(n) { } }; static inline std::istream& operator>>(std::istream& in, Ignore o) { return in.ignore(o.n, o.delim); } /** Skip the specified character if it's next in the input stream. */ struct Skip { char c; Skip(const char c) : c(c) { } }; static inline std::istream& operator>>(std::istream& in, Skip o) { if (in.peek() == o.c) in.ignore(1); return in; } /** Read a file and store it in the specified vector. */ template static inline void readFile(const char* path, Vector& s) { std::ifstream in(path); assert_good(in, path); in.seekg(0, std::ios::end); ssize_t n = in.tellg(); assert(n > 0); s.resize(n); in.seekg(0, std::ios::beg); assert_good(in, path); char *p = reinterpret_cast(&s[0]); #if __MACH__ // Read 1 GB at a time. Reads of 2 GB or more fail. const ssize_t N = 1024 * 1024 * 1024; for (; n > N; n -= N, p += N) { in.read(p, N); assert_good(in, path); assert(in.gcount() == N); } #endif in.read(p, n); assert_good(in, path); assert(in.gcount() == n); } /** Copy a file */ inline static void copyFile(const std::string& srcPath, const std::string& dstPath) { assert(srcPath != dstPath); std::ifstream src(srcPath.c_str(), std::ios::binary); std::ofstream dst(dstPath.c_str(), std::ios::binary); dst << src.rdbuf(); assert(dst); } #endif abyss-2.2.4/Common/InsOrderedMap.h000066400000000000000000000032221361462241400167370ustar00rootroot00000000000000/** * 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 #include #include #include using namespace boost::multi_index; template 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 > // 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 abyss-2.2.4/Common/Iterator.h000066400000000000000000000044621361462241400160430ustar00rootroot00000000000000#ifndef ITERATOR_H #define ITERATOR_H 1 #include /** A counting output iterator. */ class CountingOutputIterator { public: explicit CountingOutputIterator(size_t& count) : m_count(count) { m_count = 0; } CountingOutputIterator& operator++() { ++m_count; return *this; } CountingOutputIterator& operator*() { return *this; } template CountingOutputIterator& operator=(const T&) { return *this; } private: size_t& m_count; }; /** An output stream iterator, like ostream_iterator, that outputs the * a delimiter before and after the item. */ template > class affix_ostream_iterator : public std::iterator { public: typedef charT char_type; typedef traits traits_type; typedef std::basic_ostream ostream_type; typedef void value_type; affix_ostream_iterator(ostream_type& s, charT const *prefix, charT const *suffix = NULL) : os(&s), prefix(prefix), suffix(suffix) {} affix_ostream_iterator& operator =(T const &item) { if (prefix != NULL) *os << prefix; *os << item; if (suffix != NULL) *os << suffix; return *this; } affix_ostream_iterator &operator*() { return *this; } affix_ostream_iterator &operator++() { return *this; } affix_ostream_iterator &operator++(int) { return *this; } private: std::basic_ostream *os; charT const* prefix; charT const* suffix; }; /** Traits of an output iterator. */ template struct output_iterator_traits { typedef typename OutputIterator::value_type value_type; }; /** Traits of a back_insert_iterator. */ template struct output_iterator_traits< std::back_insert_iterator > { typedef typename Container::value_type value_type; }; /** Traits of an ostream_iterator. */ template struct output_iterator_traits< std::ostream_iterator > { typedef T value_type; }; /** Traits of an affix_ostream_iterator. */ template struct output_iterator_traits< affix_ostream_iterator > { typedef T value_type; }; #endif abyss-2.2.4/Common/Kmer.cpp000066400000000000000000000300461361462241400155000ustar00rootroot00000000000000#include "config.h" #include "Kmer.h" #include "Common/Options.h" #include "HashFunction.h" #include #include using namespace std; /** The size of a k-mer. This variable is static and is shared by all * instances. */ unsigned Kmer::s_length; /** The size of a k-mer in bytes. */ unsigned Kmer::s_bytes; static unsigned seqIndexToByteNumber(unsigned seqIndex); static unsigned seqIndexToBaseIndex(unsigned seqIndex); static uint8_t getBaseCode(const char* pSeq, unsigned byteNum, unsigned index); static void setBaseCode(char* pSeq, unsigned byteNum, unsigned index, uint8_t base); /** Construct a k-mer from a string. */ Kmer::Kmer(const Sequence& seq) { assert(seq.length() == s_length); memset(m_seq, 0, NUM_BYTES); const char* p = seq.data(); for (unsigned i = 0; i < s_length; i++) set(i, baseToCode(*p++)); } /** Compare two k-mer. */ int Kmer::compare(const Kmer& other) const { return memcmp(m_seq, other.m_seq, bytes()); } /** Compute a hash-like value of the packed sequence over the first 16 * bases and the reverse complement of the last 16 bases * The reverse complement of the last 16 bases is used so that a * sequence and its reverse complement will hash to the same value. * @todo make this faster */ 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 < 8 ? 1 : s_length < 20 ? s_length/8 : 4; Kmer rc = *this; rc.reverseComplement(); const unsigned prime = 101; unsigned sum = 0; for (unsigned i = 0; i < NUM_BYTES; i++) sum = prime * sum + (m_seq[i] ^ rc.m_seq[i]); return sum; } size_t Kmer::getHashCode() const { // Hash numbytes - 1 to avoid getting different hash values for // the same sequence for n % 4 != 0 sequences. return hashmem(m_seq, bytes() - 1); } /** Return the string representation of this sequence. */ Sequence Kmer::str() const { Sequence s; s.reserve(s_length); for (unsigned i = 0; i < s_length; i++) s.push_back(codeToBase(at(i))); return s; } /** Swap the positions of four bases. */ static const uint8_t swapBases[256] = { 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0, 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0, 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4, 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4, 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8, 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8, 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc, 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc, 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1, 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1, 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5, 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5, 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9, 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9, 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd, 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd, 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2, 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2, 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6, 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6, 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda, 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa, 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde, 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe, 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3, 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3, 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7, 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7, 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb, 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb, 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf, 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff }; #if MAX_KMER > 96 # include typedef bitset<2 * MAX_KMER> Seq; #else # define SEQ_WORDS ((Kmer::NUM_BYTES + 7)/8) # define SEQ_BITS (64 * SEQ_WORDS) # define SEQ_FULL_WORDS ((int)Kmer::NUM_BYTES/8) # define SEQ_ODD_BYTES (Kmer::NUM_BYTES - 8*SEQ_FULL_WORDS) /** A sequence of bits of length SEQ_BITS. */ struct Seq { uint64_t x[SEQ_WORDS]; /** Return the number of bits in this sequence. */ static unsigned size() { return SEQ_BITS; } /** Flip all the bits. */ void flip() { for (unsigned i = 0; i < SEQ_WORDS; i++) x[i] = ~x[i]; } /** Shift right by the specified number of bits. */ void operator>>=(uint8_t n) { if (n == 0) return; #if MAX_KMER <= 32 x[0] >>= n; #elif MAX_KMER <= 64 uint64_t x0 = x[0], x1 = x[1]; if (n < 64) { x[0] = x0 >> n; x[1] = x1 >> n | x0 << (64 - n); } else { x[0] = 0; x[1] = x0 >> (n - 64); } #elif MAX_KMER <= 96 uint64_t x0 = x[0], x1 = x[1], x2 = x[2]; if (n < 64) { x[0] = x0 >> n; x[1] = x1 >> n | x0 << (64 - n); x[2] = x2 >> n | x1 << (64 - n); } else if (n == 64) { x[0] = 0; x[1] = x0; x[2] = x1; } else if (n < 128) { n -= 64; x[0] = 0; x[1] = x0 >> n; x[2] = x1 >> n | x0 << (64 - n); } else { n -= 128; x[0] = 0; x[1] = 0; x[2] = x0 >> n; } #else # error #endif } }; #endif /** Load with appropriate endianness for shifting. */ static Seq load(const uint8_t *src) { Seq seq; #if MAX_KMER > 96 # if WORDS_BIGENDIAN const size_t *s = reinterpret_cast(src); size_t *d = reinterpret_cast(&seq + 1); copy(s, s + Kmer::NUM_BYTES/sizeof(size_t), reverse_iterator(d)); # else uint8_t *d = reinterpret_cast(&seq); memcpy(d, src, sizeof seq); reverse(d, d + sizeof seq); # endif #else uint64_t *px = seq.x; const uint8_t *p = src; for (int i = 0; i < SEQ_FULL_WORDS; i++) { *px++ = (uint64_t)p[0] << 56 | (uint64_t)p[1] << 48 | (uint64_t)p[2] << 40 | (uint64_t)p[3] << 32 | (uint64_t)p[4] << 24 | (uint64_t)p[5] << 16 | (uint64_t)p[6] << 8 | (uint64_t)p[7] << 0; p += 8; } if (SEQ_ODD_BYTES > 0) { uint64_t x = 0; if (SEQ_ODD_BYTES > 0) x |= (uint64_t)p[0] << 56; if (SEQ_ODD_BYTES > 1) x |= (uint64_t)p[1] << 48; if (SEQ_ODD_BYTES > 2) x |= (uint64_t)p[2] << 40; if (SEQ_ODD_BYTES > 3) x |= (uint64_t)p[3] << 32; if (SEQ_ODD_BYTES > 4) x |= (uint64_t)p[4] << 24; if (SEQ_ODD_BYTES > 5) x |= (uint64_t)p[5] << 16; if (SEQ_ODD_BYTES > 6) x |= (uint64_t)p[6] << 8; if (SEQ_ODD_BYTES > 7) x |= (uint64_t)p[7] << 0; *px = x; } #endif return seq; } /** * Reverse the bytes by storing them in the reverse order of * loading, and reverse the words in the same fashion. */ static void storeReverse(uint8_t *dest, const Seq seq) { #if MAX_KMER > 96 # if WORDS_BIGENDIAN const size_t *s = reinterpret_cast(&seq); size_t *d = reinterpret_cast(dest); copy(s, s + Kmer::NUM_BYTES/sizeof(size_t), reverse_iterator(d + Kmer::NUM_BYTES/sizeof(size_t))); reverse(dest, dest + Kmer::NUM_BYTES); # else memcpy(dest, &seq, Kmer::NUM_BYTES); # endif #else const uint64_t *px = &seq.x[SEQ_WORDS-1]; # if WORDS_BIGENDIAN for (int i = 0; i < SEQ_FULL_WORDS; i++) { dest[0] = *px >> 0; dest[1] = *px >> 8; dest[2] = *px >> 16; dest[3] = *px >> 24; dest[4] = *px >> 32; dest[5] = *px >> 40; dest[6] = *px >> 48; dest[7] = *px >> 56; dest += 8; px--; } # else uint64_t *d = (uint64_t*)dest; for (int i = 0; i < SEQ_FULL_WORDS; i++) *d++ = *px--; dest = (uint8_t*)d; # endif if (SEQ_ODD_BYTES > 0) dest[0] = *px >> 0; if (SEQ_ODD_BYTES > 1) dest[1] = *px >> 8; if (SEQ_ODD_BYTES > 2) dest[2] = *px >> 16; if (SEQ_ODD_BYTES > 3) dest[3] = *px >> 24; if (SEQ_ODD_BYTES > 4) dest[4] = *px >> 32; if (SEQ_ODD_BYTES > 5) dest[5] = *px >> 40; if (SEQ_ODD_BYTES > 6) dest[6] = *px >> 48; if (SEQ_ODD_BYTES > 7) dest[7] = *px >> 56; #endif } /** Reverse-complement this sequence. */ void Kmer::reverseComplement() { Seq seq = load((uint8_t*)m_seq); // Complement the bits. if (!opt::colourSpace) seq.flip(); // Shift the bits flush to the right of the double word. seq >>= seq.size() - 2*s_length; storeReverse((uint8_t*)m_seq, seq); // Reverse the pairs of bits withing a byte. unsigned numBytes = bytes(); for (unsigned i = 0; i < numBytes; i++) m_seq[i] = swapBases[(uint8_t)m_seq[i]]; } bool Kmer::isCanonical() const { for (unsigned i = 0, j = s_length - 1; i < s_length / 2 + s_length % 2; i++, j--) { uint8_t base = getBaseCode(m_seq, seqIndexToByteNumber(i), seqIndexToBaseIndex(i)); uint8_t rcBase = 0x3 & ~getBaseCode(m_seq, seqIndexToByteNumber(j), seqIndexToBaseIndex(j)); if (base == rcBase) continue; return rcBase > base; } return true; } void Kmer::canonicalize() { if (!isCanonical()) reverseComplement(); } void Kmer::setLastBase(extDirection dir, uint8_t base) { set(dir == SENSE ? s_length - 1 : 0, base); } /** Shift the sequence left and append a new base to the end. * @return the base shifted out */ uint8_t Kmer::shiftAppend(uint8_t base) { unsigned numBytes = bytes(); uint8_t shiftIn = base; for(int i = numBytes - 1; i >= 0; i--) { unsigned index = (unsigned)i == numBytes - 1 ? seqIndexToBaseIndex(s_length - 1) : 3; shiftIn = leftShiftByte(m_seq, i, index, shiftIn); } return shiftIn; } /** Shift the sequence right and prepend a new base at the front. * @return the base shifted out */ uint8_t Kmer::shiftPrepend(uint8_t base) { unsigned numBytes = bytes(); unsigned lastBaseByte = seqIndexToByteNumber(s_length - 1); unsigned lastBaseIndex = seqIndexToBaseIndex(s_length - 1); // save the last base (which gets shifted out) uint8_t lastBase = getBaseCode(m_seq, lastBaseByte, lastBaseIndex); // Zero the last base, which is required by compare. setBaseCode(m_seq, lastBaseByte, lastBaseIndex, 0); uint8_t shiftIn = base; for(unsigned i = 0; i <= numBytes - 1; i++) { // index is always zero unsigned index = 0; shiftIn = rightShiftByte(m_seq, i, index, shiftIn); } return lastBase; } uint8_t Kmer::leftShiftByte(char* pSeq, unsigned byteNum, unsigned index, uint8_t base) { // save the first base uint8_t outBase = (pSeq[byteNum] >> 6) & 0x3; // shift left one position pSeq[byteNum] <<= 2; // Set the new base setBaseCode(pSeq, byteNum, index, base); return outBase; } uint8_t Kmer::rightShiftByte(char* pSeq, unsigned byteNum, unsigned index, uint8_t base) { // save the last base uint8_t outBase = pSeq[byteNum] & 0x3; // shift right one position pSeq[byteNum] >>= 2; // add the new base setBaseCode(pSeq, byteNum, index, base); return outBase; } //Set a base by byte number/ sub index // beware, this does not check for out of bounds access static void setBaseCode(char* pSeq, unsigned byteNum, unsigned index, uint8_t base) { // shift the value into position unsigned shiftValue = 2*(3 - index); base <<= shiftValue; // clear the value uint8_t mask = 0x3; mask <<= shiftValue; mask = ~mask; pSeq[byteNum] &= mask; // set the appropriate value with an OR pSeq[byteNum] |= base; } /** Return the base at the specified index. */ uint8_t Kmer::at(unsigned i) const { assert(i < s_length); return getBaseCode(m_seq, seqIndexToByteNumber(i), seqIndexToBaseIndex(i)); } /** Set the base at the specified index. */ void Kmer::set(unsigned i, uint8_t base) { assert(i < s_length); setBaseCode(m_seq, seqIndexToByteNumber(i), seqIndexToBaseIndex(i), base); } // get a base code by the byte number and sub index static uint8_t getBaseCode(const char* pSeq, unsigned byteNum, unsigned index) { unsigned shiftLen = 2 * (3 - index); return (pSeq[byteNum] >> shiftLen) & 0x3; } static unsigned seqIndexToByteNumber(unsigned seqIndex) { return seqIndex / 4; } static unsigned seqIndexToBaseIndex(unsigned seqIndex) { return seqIndex % 4; } /** Return true if this sequence is a palindrome. */ bool Kmer::isPalindrome() const { return s_length % 2 == 1 && !opt::colourSpace ? false : *this == ::reverseComplement(*this); } /** Return true if the length k-1 subsequence is a palindrome. */ bool Kmer::isPalindrome(extDirection dir) const { if (s_length % 2 == 0 && !opt::colourSpace) return false; Kmer seq(*this); if (dir == SENSE) seq.shiftAppend(0); else seq.setLastBase(SENSE, 0); Kmer rc(*this); rc.reverseComplement(); if (dir == SENSE) rc.setLastBase(SENSE, 0); else rc.shiftAppend(0); return seq == rc; } abyss-2.2.4/Common/Kmer.h000066400000000000000000000063371361462241400151530ustar00rootroot00000000000000#ifndef Kmer_H #define Kmer_H 1 #include "config.h" #include "Sense.h" #include "Sequence.h" #include "Common/Hash.h" #include // for memcpy #include #include /** A k-mer. */ class Kmer { public: Kmer() { } explicit Kmer(const Sequence& seq); int compare(const Kmer& other) const; bool operator==(const Kmer& other) const { return compare(other) == 0; } bool operator!=(const Kmer& other) const { return compare(other) != 0; } bool operator<(const Kmer& other) const { return compare(other) < 0; } Sequence str() const; unsigned getCode() const; size_t getHashCode() const; static unsigned length() { return s_length; } /** Set the length of a k-mer. * This value is shared by all instances. */ static void setLength(unsigned length) { if (length > MAX_KMER) { std::cerr << "Error: k is " << length << " and must be no more than " << MAX_KMER << ". You can recompile ABySS to increase this limit.\n"; exit(EXIT_FAILURE); } s_length = length; s_bytes = (length + 3) / 4; } void reverseComplement(); bool isCanonical() const; void canonicalize(); bool isPalindrome() const; bool isPalindrome(extDirection dir) const; void setLastBase(extDirection dir, uint8_t base); /** 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) { return dir == SENSE ? shiftAppend(base) : shiftPrepend(base); } /** Return the number of bytes needed. */ static unsigned bytes() { return s_bytes; } static unsigned serialSize() { return NUM_BYTES; } size_t serialize(void* dest) const { memcpy(dest, m_seq, sizeof m_seq); return sizeof m_seq; } size_t unserialize(const void* src) { memcpy(m_seq, src, sizeof m_seq); return sizeof m_seq; } friend std::ostream& operator<<(std::ostream& out, const Kmer& o) { return out << o.str(); } uint8_t at(unsigned i) const; void set(unsigned i, uint8_t base); protected: uint8_t shiftAppend(uint8_t base); uint8_t shiftPrepend(uint8_t base); static uint8_t leftShiftByte(char* pSeq, unsigned byteNum, unsigned index, uint8_t base); static uint8_t rightShiftByte(char* pSeq, unsigned byteNum, unsigned index, uint8_t base); public: #if MAX_KMER > 96 # if MAX_KMER % 32 != 0 # error MAX_KMER must be a multiple of 32. # endif #else # if MAX_KMER % 4 != 0 # error MAX_KMER must be a multiple of 4. # endif #endif static const unsigned NUM_BYTES = MAX_KMER / 4; protected: static unsigned s_length; static unsigned s_bytes; char m_seq[NUM_BYTES]; }; /** Return the reverse complement of the specified k-mer. */ static inline Kmer reverseComplement(const Kmer& seq) { Kmer rc(seq); rc.reverseComplement(); return rc; } NAMESPACE_STD_HASH_BEGIN template <> struct hash { size_t operator()(const Kmer& kmer) const { return kmer.getHashCode(); } }; NAMESPACE_STD_HASH_END #endif abyss-2.2.4/Common/KmerIterator.h000066400000000000000000000041021361462241400166510ustar00rootroot00000000000000#ifndef KMER_ITERATOR_H_ #define KMER_ITERATOR_H_ #include "Common/Sequence.h" #include "Common/Kmer.h" #include #include #include struct KmerIterator : public std::iterator { void next() { for(; m_pos + m_k < m_seq.size() + 1; m_pos++) { //TODO(daattali) substr() and find_first_not_of() might be // slow and could be improved for better performance std::string kmerStr = m_seq.substr(m_pos, m_k); if (m_pos_invalid >= m_pos + m_k) { // no invalid characters in current kmer, move along } else { size_t pos = m_seq.find_first_not_of("AGCTagct", m_pos); if (pos == std::string::npos) { m_pos_invalid = std::numeric_limits::max(); } else if (pos >= m_pos + m_k) { m_pos_invalid = pos; } else { pos = kmerStr.find_last_not_of("AGCTagct"); m_pos += pos; continue; } } m_kmer = Kmer(kmerStr); if (m_rc) m_kmer.reverseComplement(); return; } m_pos = std::numeric_limits::max(); } public: KmerIterator() : m_seq(), m_pos(std::numeric_limits::max()), m_pos_invalid(0), m_kmer() { } KmerIterator(const Sequence& seq, unsigned k, bool rc = false) : m_seq(seq), m_k(k), m_rc(rc), m_pos(0), m_pos_invalid(0), m_kmer() { next(); } const Kmer& operator*() const { assert(m_pos + m_k < m_seq.size() + 1); return m_kmer; } bool operator==(const KmerIterator& it) const { return m_pos == it.m_pos; } bool operator!=(const KmerIterator& it) const { return !(*this == it); } KmerIterator& operator++() { assert(m_pos + m_k < m_seq.size() + 1); m_pos++; next(); return *this; } KmerIterator operator++(int) { KmerIterator it = *this; ++*this; return it; } size_t pos() { return m_pos; } static const KmerIterator& end() { return KmerIterator::m_end; } private: const Sequence m_seq; unsigned m_k; bool m_rc; size_t m_pos; size_t m_pos_invalid; Kmer m_kmer; static const KmerIterator m_end; }; const KmerIterator KmerIterator::m_end = KmerIterator(); #endif abyss-2.2.4/Common/KmerSet.h000066400000000000000000000013701361462241400156170ustar00rootroot00000000000000#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 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 abyss-2.2.4/Common/Log.cpp000066400000000000000000000005441361462241400153230ustar00rootroot00000000000000#include "Log.h" #include "Common/Options.h" #include using namespace std; /** Print a log message if the verbosity level is at least the * specified level. */ ostream& logger(int level) { if (opt::verbose < level) { static ostream bitBucket(NULL); return bitBucket; } if (opt::rank >= 0) cout << opt::rank << ": "; return cout; } abyss-2.2.4/Common/Log.h000066400000000000000000000001341361462241400147630ustar00rootroot00000000000000#ifndef LOG_H #define LOG_H 1 #include std::ostream& logger(int level); #endif abyss-2.2.4/Common/Makefile.am000066400000000000000000000014541361462241400161330ustar00rootroot00000000000000noinst_LIBRARIES = libcommon.a libcommon_a_CPPFLAGS = -I$(top_srcdir) libcommon_a_SOURCES = \ Algorithms.h \ Alignment.h \ BitUtil.h \ ConstString.h \ ContigID.h ContigID.cpp \ ContigNode.h \ ContigPath.h \ ContigProperties.h \ Dictionary.h \ Estimate.h \ Exception.h \ Fcontrol.cpp Fcontrol.h \ Functional.h \ 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 \ 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 \ cholesky.hpp \ KmerIterator.h \ MemUtils.h \ city.cc city.h abyss-2.2.4/Common/MemUtils.h000066400000000000000000000007201361462241400160020ustar00rootroot00000000000000#ifndef MEMUTILS_H #define MEMUTILS_H #include "Common/UnorderedMap.h" template static inline size_t 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 = size_t((1.0 - map.load_factor()) * map.bucket_count() * sizeof(Entry *)); return filled_bucket_bytes + empty_bucket_bytes; } #endif abyss-2.2.4/Common/MemoryUtil.h000066400000000000000000000022471361462241400163570ustar00rootroot00000000000000#ifndef MEMORYUTIL_H #define MEMORYUTIL_H 1 #include "config.h" #include #include #include // for sbrk #if __MACH__ # ifdef __APPLE__ # include // for mach_task_self # include // for task_info # else extern "C" { # include // for mach_task_self and task_info } # endif #endif /** Return the number of bytes used by the data and stack segments. * @return -1 on error */ static inline ssize_t getMemoryUsage() { #if __MACH__ struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; int status = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); assert(status == KERN_SUCCESS); return status == KERN_SUCCESS ? (ssize_t)t_info.virtual_size : -1; #elif HAVE_GETPAGESIZE std::ifstream in("/proc/self/statm"); size_t size, resident, share, text, lib, data; return in >> size >> resident >> share >> text >> lib >> data ? ssize_t(data * getpagesize()) : -1; #else /** Start of the data segment. */ static intptr_t sbrk0 = reinterpret_cast(sbrk(0)); return reinterpret_cast(sbrk(0)) - sbrk0; #endif } #endif abyss-2.2.4/Common/Options.cpp000066400000000000000000000003341361462241400162320ustar00rootroot00000000000000#include "Common/Options.h" namespace opt { /** Colour space sequences */ bool colourSpace; /** MPI rank */ int rank = -1; /** Number of MPI processes */ int numProc = 1; /** Verbose output */ int verbose; } abyss-2.2.4/Common/Options.h000066400000000000000000000004171361462241400157010ustar00rootroot00000000000000#ifndef COMMON_OPTIONS_H #define COMMON_OPTIONS_H 1 /** * Global variables that are mostly constant for the duration of the * execution of the program. */ namespace opt { extern bool colourSpace; extern int numProc; extern int rank; extern int verbose; } #endif abyss-2.2.4/Common/PMF.h000066400000000000000000000027561361462241400147000ustar00rootroot00000000000000#ifndef PMF_H #define PMF_H 1 #include "Common/Exception.h" #include "Histogram.h" #include #include #include class Histogram; /** Probability mass function */ class PMF { public: /** Construct a PMF from a histogram. */ PMF(const Histogram& h) : m_dist(h.maximum() + 1), m_mean(h.mean()), m_stdDev(h.sd()), m_median(h.median()) { unsigned count = h.size(); m_minp = (double)1 / count; for (size_t i = 0; i < m_dist.size(); i++) { unsigned n = h.count(i); m_dist[i] = n > 0 ? (double)n / count : m_minp; } } /** Return the probability of x. */ double operator[](size_t x) const { return x < m_dist.size() ? m_dist[x] : m_minp; } /** Return the minimum probability. */ double minProbability() const { return m_minp; } /** Return the minimum value. */ size_t minValue() const { return 0; } /** Return the maximum value. */ size_t maxValue() const { assert(!m_dist.empty()); return m_dist.size() - 1; } /** Return the median of this distribution. */ int median() const { return m_median; } /** Return the mean of this distribution. */ double mean() const { return m_mean; } /** Return the standard deviation of the sampled mean * of n observations. */ double getSampleStdDev(unsigned n) const { return m_stdDev / sqrt(n); } private: std::vector m_dist; double m_mean; double m_stdDev; double m_minp; int m_median; }; namespace std { template<> inline void swap(PMF&, PMF&) NOEXCEPT { assert(false); } } #endif abyss-2.2.4/Common/SAM.h000066400000000000000000000223541361462241400146720ustar00rootroot00000000000000#ifndef SAM_H #define SAM_H 1 #include "config.h" // for SAM_SEQ_QUAL #include "IOUtil.h" #include "Alignment.h" #include "ContigID.h" // for g_contigNames #include // for swap #include // for exit #include #include // for numeric_limits #include #include namespace opt { /** The minimal alignment size. */ static unsigned minAlign = 1; } /** A SAM alignment of a single query. */ struct SAMAlignment { std::string rname; int pos; unsigned short flag; unsigned short mapq; std::string cigar; /** Flag */ enum { /** the read is paired in sequencing, no matter whether it is * mapped in a pair */ FPAIRED = 1, /** the read is mapped in a proper pair */ FPROPER_PAIR = 2, /** the read itself is unmapped; conflictive with FPROPER_PAIR */ FUNMAP = 4, /** the mate is unmapped */ FMUNMAP = 8, /** the read is mapped to the reverse strand */ FREVERSE = 16, /** the mate is mapped to the reverse strand */ FMREVERSE = 32, /** this is read1 */ FREAD1 = 64, /** this is read2 */ FREAD2 = 128, /** not primary alignment */ FSECONDARY = 256, /** QC failure */ FQCFAIL = 512, /** optical or PCR duplicate */ FDUP = 1024, }; SAMAlignment() : rname("*"), pos(-1), flag(FUNMAP), mapq(0) { } /** Consturct a single-end alignment. */ SAMAlignment(const Alignment& a) : rname(a.contig), pos(a.contig_start_pos), flag(a.isRC ? FREVERSE : 0), mapq(255) { unsigned qend = a.read_start_pos + a.align_length; int clip0 = a.read_start_pos; int clip1 = a.read_length - qend; assert(clip1 >= 0); if (a.isRC) std::swap(clip0, clip1); std::ostringstream s; if (clip0 > 0) s << clip0 << 'S'; s << a.align_length << 'M'; if (clip1 > 0) s << clip1 << 'S'; cigar = s.str(); } bool isPaired() const { return flag & FPAIRED; } bool isUnmapped() const { return flag & FUNMAP; } bool isMateUnmapped() const { return flag & FMUNMAP; } bool isReverse() const { return flag & FREVERSE; } bool isMateReverse() const { return flag & FMREVERSE; } bool isRead1() const { return flag & FREAD1; } bool isRead2() const { return flag & FREAD2; } /** The alignment coordinates of a gapped alignment. */ struct CigarCoord { /** The length of the query sequence. */ unsigned qlen; /** The start of the alignment on the query. */ unsigned qstart; /** The length of the alignment on the query. */ unsigned qspan; /** The length of the alignment on the target. */ unsigned tspan; /** Parse the specified CIGAR string. */ CigarCoord(const std::string& cigar) : qlen(0), qstart(0), qspan(0), tspan(0) { if (cigar == "*") return; std::istringstream in(cigar); bool first = true; unsigned len; char type; while (in >> len >> type) { switch (type) { case 'H': case 'S': if (first) qstart = len; qlen += len; break; case 'M': case 'X': case '=': qlen += len; qspan += len; tspan += len; break; case 'I': qlen += len; qspan += len; break; case 'D': case 'N': case 'P': tspan += len; break; default: std::cerr << "error: invalid CIGAR: `" << cigar << "'\n"; exit(EXIT_FAILURE); } first = false; } assert(in.eof()); } }; /** * Return the position of the first base of the query on the * target extrapolated from the start of the alignment. */ int targetAtQueryStart() const { CigarCoord a(cigar); assert(a.qstart + a.qspan <= a.qlen); return isReverse() ? pos + a.tspan + (a.qlen - a.qspan - a.qstart) : pos - a.qstart; } /** Parse the specified CIGAR string. * @return an alignment setting the fields read_start_pos, * align_length, and read_length. The other fields will be * uninitialized. */ static Alignment parseCigar(const std::string& cigar, bool isRC) { Alignment a; std::istringstream in(cigar); unsigned len; char type; unsigned clip0 = 0; a.align_length = 0; unsigned qlen = 0; unsigned clip1 = 0; while (in >> len >> type) { switch (type) { case 'I': case 'X': case '=': qlen += len; clip1 += len; // fallthrough case 'D': case 'N': case 'P': if (a.align_length == 0) { // Ignore a malformatted CIGAR string whose first // non-clipping operation is not M. std::cerr << "warning: malformatted CIGAR: " << cigar << std::endl; } break; case 'M': if ((unsigned)a.align_length < len) { clip0 += a.align_length + clip1; a.align_length = len; qlen += len; clip1 = 0; break; } // fallthrough case 'H': case 'S': qlen += len; clip1 += len; break; default: std::cerr << "error: invalid CIGAR: `" << cigar << "'\n"; exit(EXIT_FAILURE); } } a.read_start_pos = isRC ? clip1 : clip0; a.read_length = qlen; if (!in.eof()){ std::cerr << "error: invalid CIGAR: `" << cigar << "'\n"; exit(EXIT_FAILURE); } return a; } operator Alignment() const { assert(~flag & FUNMAP); bool isRC = flag & FREVERSE; // strand of the query Alignment a = parseCigar(cigar, isRC); a.contig = rname; a.contig_start_pos = pos; a.isRC = isRC; return a; } }; /** A SAM alignment of a query and its mate. */ struct SAMRecord : SAMAlignment { std::string qname; std::string mrnm; int mpos; int isize; #if SAM_SEQ_QUAL std::string seq; std::string qual; std::string tags; #endif /** Consturct a single-end alignment. */ explicit SAMRecord(const SAMAlignment& a = SAMAlignment(), const std::string& qname = "*", #if SAM_SEQ_QUAL const std::string& seq = "*", const std::string& qual = "*", const std::string& tags = "" #else const std::string& /*seq*/ = "*", const std::string& /*qual*/ = "*", const std::string& /*tags*/ = "" #endif ) : SAMAlignment(a), qname(qname), mrnm("*"), mpos(-1), isize(0) #if SAM_SEQ_QUAL , seq(seq), qual(qual), tags(tags) #endif { } /** Construct a paired-end alignment. */ SAMRecord(const Alignment& a0, const Alignment& a1) { *this = SAMRecord(a0); flag |= FPAIRED; if (a1.isRC) flag |= FMREVERSE; mrnm = a1.contig; mpos = a1.contig_start_pos; isize = a1.targetAtQueryStart() - a0.targetAtQueryStart(); } /** Set the mate mapping fields. */ void fixMate(const SAMAlignment& o) { flag &= ~(FPROPER_PAIR | FMUNMAP | FMREVERSE); flag |= FPAIRED; if (rname == o.rname && isReverse() != o.isReverse()) flag |= FPROPER_PAIR; if (o.isUnmapped()) flag |= FMUNMAP; if (o.isReverse()) flag |= FMREVERSE; mrnm = o.rname; mpos = o.pos; isize = isMateUnmapped() ? 0 : o.targetAtQueryStart() - targetAtQueryStart(); // Fix unaligned mates if (!o.isUnmapped() && isUnmapped()) { rname = o.rname; pos = o.pos; } else if (o.isUnmapped() && !isUnmapped()) { mrnm = "="; mpos = pos; } } void noMate() { flag &= ~FPAIRED; } /** * Return the position of the first base of the mate query on the * target extrapolated from the start of the alignment. */ int mateTargetAtQueryStart() const { return targetAtQueryStart() + isize; } friend std::ostream& operator <<(std::ostream& out, const SAMRecord& o) { out << o.qname << '\t' << o.flag << '\t' << o.rname << '\t' << (1 + o.pos) << '\t' << o.mapq << '\t' << o.cigar << '\t' << (o.mrnm == o.rname ? "=" : o.mrnm) << '\t' << (1 + o.mpos) << '\t' << o.isize; #if SAM_SEQ_QUAL out << '\t' << o.seq << '\t' << o.qual; if (!o.tags.empty()) out << '\t' << o.tags; #else out << "\t*\t*"; #endif return out; } friend std::istream& operator >>(std::istream& in, SAMRecord& o) { in >> o.qname >> o.flag >> o.rname >> o.pos >> o.mapq >> o.cigar >> o.mrnm >> o.mpos >> o.isize; #if SAM_SEQ_QUAL in >> o.seq >> o.qual; if (in.peek() != '\n') in >> o.tags; #endif in.ignore(std::numeric_limits::max(), '\n'); if (!in) return in; o.pos--; o.mpos--; if (o.mrnm == "=") o.mrnm = o.rname; // Set the paired flags if qname ends in /1 or /2. unsigned l = o.qname.length(); if (l >= 2 && o.qname[l-2] == '/') { switch (o.qname[l-1]) { case '1': o.flag |= FPAIRED | FREAD1; break; case '2': case '3': o.flag |= FPAIRED | FREAD2; break; default: return in; } o.qname.resize(l - 2); assert(!o.qname.empty()); } // Set the unmapped flag if the alignment is not long enough. CigarCoord a(o.cigar); if (a.qspan < opt::minAlign || a.tspan < opt::minAlign) o.flag |= FUNMAP; return in; } }; /** Set the mate mapping fields of a0 and a1. */ static inline void fixMate(SAMRecord& a0, SAMRecord& a1) { a0.fixMate(a1); a1.fixMate(a0); } /** Read contig lengths from SAM headers. */ static inline unsigned readContigLengths(std::istream& in, std::vector& lengths) { assert(in); assert(lengths.empty()); assert(g_contigNames.empty()); for (std::string line; in.peek() == '@' && getline(in, line);) { std::istringstream ss(line); std::string type; ss >> type; if (type != "@SQ") continue; std::string s; unsigned len; ss >> expect(" SN:") >> s >> expect(" LN:") >> len; assert(ss); put(g_contigNames, lengths.size(), s); lengths.push_back(len); } if (lengths.empty()) { std::cerr << "error: no @SQ records in the SAM header\n"; exit(EXIT_FAILURE); } return lengths.size(); } #endif abyss-2.2.4/Common/Sense.h000066400000000000000000000005711361462241400153240ustar00rootroot00000000000000#ifndef SENSE_H #define SENSE_H 1 #include enum extDirection { SENSE = 0, ANTISENSE = 1, NUM_DIRECTIONS }; static inline extDirection operator !(extDirection dir) { return dir == SENSE ? ANTISENSE : SENSE; } static inline extDirection& operator ++(extDirection& dir) { assert(dir == SENSE || dir == ANTISENSE); return dir = extDirection(dir + 1); } #endif abyss-2.2.4/Common/Sequence.cpp000066400000000000000000000123671361462241400163600ustar00rootroot00000000000000#include "Sequence.h" #include "Common/Options.h" #include #include #include #include // for abort #include #include using namespace std; enum { A, C, G, T }; static const int cstont[4][4] = { { A, C, G, T }, { C, A, T, G }, { G, T, A, C }, { T, G, C, A } }; /** Return the complement of the specified nucleotide. */ char complementBaseChar(char c) { char rc; switch (toupper(c)) { case 'A': rc = 'T'; break; case 'C': rc = 'G'; break; case 'G': rc = 'C'; break; case 'T': rc = 'A'; break; case 'N': rc = 'N'; break; case '.': rc = '.'; break; case 'M': rc = 'K'; break; // A or C case 'R': rc = 'Y'; break; // A or G case 'W': rc = 'W'; break; // A or T case 'S': rc = 'S'; break; // C or G case 'Y': rc = 'R'; break; // C or T case 'K': rc = 'M'; break; // G or T case 'V': rc = 'B'; break; // A or C or G case 'H': rc = 'D'; break; // A or C or T case 'D': rc = 'H'; break; // A or G or T case 'B': rc = 'V'; break; // C or G or T default: cerr << "error: unexpected character: `" << c << "'\n"; assert(false); abort(); } return islower(c) ? tolower(rc) : rc; } /** Return the reverse complement of the specified sequence. */ Sequence reverseComplement(const Sequence& s) { Sequence rc(s); reverse(rc.begin(), rc.end()); if (!opt::colourSpace) transform(rc.begin(), rc.end(), rc.begin(), complementBaseChar); return rc; } static const uint8_t b2C[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //0 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //1 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //2 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, //3 0 1 2 3 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x02, //4 A C G 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, 0x00, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x02, //6 a c g 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //9 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //A 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //B 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //C 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //D 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //E 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //F 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /** Return the base enumeration for the specified character. */ uint8_t baseToCode(char base) { uint8_t r = b2C[unsigned(base)]; if (r != 0xFF) return r; cerr << "error: unexpected character: '" << base << "'\n"; assert(false); abort(); } char codeToBase(uint8_t code) { assert(code < 4); return (opt::colourSpace ? "0123" : "ACGT")[code]; } char colourToNucleotideSpace(char anchor, char cs) { return cs == '.' ? 'N' : "ACGT"[cstont[baseToCode(anchor)][baseToCode(cs)]]; } Sequence colourToNucleotideSpace(char anchor, const Sequence& seq) { int seed = baseToCode(anchor); ostringstream s; s << anchor; for (string::const_iterator it = seq.begin(); it != seq.end(); ++it) { seed = cstont[seed][baseToCode(*it)]; s << codeToBase(seed); } return s.str(); } char nucleotideToColourSpace(char a, char b) { if (toupper(a) == 'N' || toupper(b) == 'N') return islower(a) || islower(b) ? 'n' : 'N'; return "0123"[cstont[baseToCode(a)][baseToCode(b)]]; } /** Convert the specified ambiguity code to a bitmask. */ unsigned ambiguityToBitmask(char c) { if (isdigit(c)) // colour space return 1 << baseToCode(c); static const unsigned ambiguityToBitmaskTable[26] = { 0x1, // 'A' ---A 0xe, // 'B' TGC- 0x2, // 'C' --C- 0xd, // 'D' TG-A 0x0, // 'E' 0x0, // 'F' 0x4, // 'G' -G-- 0xb, // 'H' T-CA 0x0, // 'I' 0x0, // 'J' 0xc, // 'K' TG-- 0x0, // 'L' 0x3, // 'M' --CA 0xf, // 'N' ACGT 0x0, // 'O' 0x0, // 'P' 0x0, // 'Q' 0x5, // 'R' -G-A 0x6, // 'S' -GC- 0x8, // 'T' T--- 0x0, // 'U' 0x7, // 'V' -GCA 0x9, // 'W' T--A 0x0, // 'X' 0xa, // 'Y' T-C- 0x0, // 'Z' }; unsigned i = toupper(c) - 'A'; assert(i < 26); unsigned x = ambiguityToBitmaskTable[i]; assert(x > 0); return x; } /** Convert the specified bitmask to an ambiguity code. */ unsigned bitmaskToAmbiguity(unsigned x) { static const char bitmaskToAmbiguityTable[16] = { 'N', //---- 'A', //---A 'C', //--C- 'M', //--CA 'G', //-G-- 'R', //-G-A 'S', //-GC- 'V', //-GCA 'T', //T--- 'W', //T--A 'Y', //T-C- 'H', //T-CA 'K', //TG-- 'D', //TG-A 'B', //TGC- 'N', //TGCA }; assert(x < 16); return bitmaskToAmbiguityTable[x]; } abyss-2.2.4/Common/Sequence.h000066400000000000000000000075501361462241400160230ustar00rootroot00000000000000#ifndef SEQUENCE_H #define SEQUENCE_H 1 #include #include #include #include typedef std::string Sequence; char complementBaseChar(char c); Sequence reverseComplement(const Sequence& s); Sequence colourToNucleotideSpace(char anchor, const Sequence& seq); char colourToNucleotideSpace(char anchor, char cs); char nucleotideToColourSpace(char a, char b); uint8_t baseToCode(char base); char codeToBase(uint8_t code); /** Return true if c is one of [ACGTacgt]. */ static inline bool isACGT(char c) { return c == 'A' || c == 'C' || c == 'G' || c == 'T' || c == 'a' || c == 'c' || c == 'g' || c == 't'; } /** * Return true if a sequence consists entirely of ACGT chars * (case insensitive). */ static inline bool allACGT(const Sequence& seq) { return strspn(seq.c_str(), "acgtACGT") == seq.length(); } /** * Transform a sequence in its canonical orientation. */ static inline void canonicalize(Sequence& seq) { Sequence rc = reverseComplement(seq); if (rc < seq) seq = rc; } /** * 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); /** Return the bitwise-and of the specified ambiguity codes. */ static inline char ambiguityAnd(char ca, char cb) { char c = bitmaskToAmbiguity( ambiguityToBitmask(ca) & ambiguityToBitmask(cb)); return islower(ca) && islower(cb) ? tolower(c) : c; } /** Return the bitwise-or of the specified ambiguity codes. */ static inline char ambiguityOr(char ca, char cb) { char c = bitmaskToAmbiguity( ambiguityToBitmask(ca) | ambiguityToBitmask(cb)); return islower(ca) || islower(cb) ? tolower(c) : c; } /** Return whether one ambiguity code is a subset of the other. */ static inline bool ambiguityIsSubset(char a, char b) { char intersection = ambiguityAnd(a, 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(const Sequence& overlay, Sequence& target, int shift, bool maskNew = false) { Sequence::const_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) *dest = tolower(*src); else *dest = *src; } } #endif abyss-2.2.4/Common/SignalHandler.cpp000066400000000000000000000025731361462241400173210ustar00rootroot00000000000000/** * Signal handling code, particularly SIGCHLD. */ #include "SignalHandler.h" #include #include #include // for perror #include #include #include #include using namespace std; /** Print the specified exit status. */ static void printStatus(pid_t pid, int status) { if (WIFEXITED(status)) cerr << "PID " << pid << " exited with status " << WEXITSTATUS(status) << endl; else if (WIFSIGNALED(status)) cerr << "PID " << pid << " killed by signal " << WTERMSIG(status) << endl; else cerr << "PID " << pid << " exited with code " << status << endl; } /** SIGCHLD handler. Reap child processes and report an error if any * fail. */ static void sigchldHandler(int sig) { assert(sig == SIGCHLD); (void)sig; pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { // Writing to cerr in a signal handler is not allowed, but // we're about to exit and an error message would be really // helpful. if (status != 0) { printStatus(pid, status); exit(EXIT_FAILURE); } } if (pid == -1 && errno != ECHILD) { perror("waitpid"); exit(EXIT_FAILURE); } } /** Install a handler for SIGCHLD. */ void signalInit() { struct sigaction action; action.sa_handler = sigchldHandler; sigemptyset(&action.sa_mask); action.sa_flags = SA_RESTART; sigaction(SIGCHLD, &action, NULL); } abyss-2.2.4/Common/SignalHandler.h000066400000000000000000000001161361462241400167550ustar00rootroot00000000000000#ifndef SIGNALHANDLER_H #define SIGNALHANDLER_H 1 void signalInit(); #endif abyss-2.2.4/Common/StringUtil.h000066400000000000000000000110011361462241400163410ustar00rootroot00000000000000#ifndef STRINGUTIL_H #define STRINGUTIL_H 1 #include #include #include #include #include /** Return the last character of s and remove it. */ static inline char chop(std::string& s) { assert(s.length() > 1); unsigned back = s.length() - 1; char c = s[back]; s.erase(back); return c; } /** If the last character of s is c, remove it and return true. */ static inline bool chomp(std::string& s, char c = '\n') { unsigned back = s.length() - 1; if (!s.empty() && s[back] == c) { s.erase(back); return true; } else return false; } /** Return the SI representation of n. */ static inline std::string toSI(double n) { std::ostringstream s; s << std::setprecision(3); if (n < 1e3) s << n << ' '; else if (n < 1e6) s << n/1e3 << " k"; else if (n < 1e9) s << n/1e6 << " M"; else if (n < 1e12) s << n/1e9 << " G"; else s << n/1e12 << " T"; 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 static inline std::string toEng(T n) { std::ostringstream s; s << std::setprecision(4); if (n < 10000000) s << n; else if (n < 1e9) s << n/1e6 << "e6"; else if (n < 1e12) s << n/1e9 << "e9"; else s << n/1e12 << "e12"; return s.str(); } /** Return true if the second string is a prefix of the string s. */ template bool startsWith(const std::string& s, const char (&prefix)[N]) { size_t n = N - 1; return s.size() > n && equal(s.begin(), s.begin() + n, prefix); } /** Return true if the second string is a suffix of the string s. */ template bool endsWith(const std::string& s, const char (&suffix)[N]) { size_t n = N - 1; return s.size() > n && equal(s.end() - n, s.end(), suffix); } /** Return true if the second string is a suffix of the string s. */ static inline bool endsWith(const std::string& s, const std::string& suffix) { size_t n = suffix.size(); return s.size() > n && equal(s.end() - n, s.end(), suffix.begin()); } static inline bool isReadNamePair(const std::string& name1, const std::string& name2) { assert(!name1.empty() && !name2.empty()); if (name1 == name2) return true; if (endsWith(name1,"/1") && endsWith(name2,"/2")) { int len1 = name1.length(); int len2 = name2.length(); assert(len1 > 2 && len2 > 2); return name1.compare(0, len1-2, name2, 0, len2-2) == 0; } return false; } static inline size_t SIToBytes(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 assume bytes iss.clear(std::ios::eofbit); return (size_t)ceil(size); } if (units.size() > 1) { // unrecognized multichar suffix iss.setstate(std::ios::failbit); return 0; } switch(tolower(units[0])) { case 'k': size *= (size_t)1<<10; break; case 'm': size *= (size_t)1<<20; break; case 'g': size *= (size_t)1<<30; break; default: iss.setstate(std::ios::failbit); return 0; } return (size_t)ceil(size); } static inline size_t SIToBytes(const std::string& str) { std::istringstream iss(str); return SIToBytes(iss); } #endif abyss-2.2.4/Common/SuffixArray.h000066400000000000000000000040351361462241400165110ustar00rootroot00000000000000#ifndef SUFFIXARRAY_H #define SUFFIXARRAY_H 1 #include "ConstString.h" #include "ContigNode.h" #include #include #include #include /** A suffix array augmented with a mapped value type. */ class SuffixArray { public: typedef cstring key_type; typedef ContigNode mapped_type; typedef std::pair value_type; typedef std::vector::const_iterator const_iterator; /** Construct an empty suffix array. */ SuffixArray(unsigned minOverlap) : m_minOverlap(minOverlap), m_dirty(false) { } /** Insert the specified sequence into this suffix array. */ template void insert(const T& seq, const mapped_type& data) { m_dirty = true; typedef typename T::const_pointer It; It last = &seq[seq.size() - m_minOverlap + 1]; for (It it = &seq[1]; it < last; ++it) m_data.push_back(value_type(it, data)); } /** Insert the specified sequence into this suffix array. */ template void insert(const std::pair& x) { insert(x.first, x.second); } /** Construct the suffix array. */ void construct() { if (m_dirty) sort(m_data.begin(), m_data.end()); m_dirty = false; } /** Find all the elements whose suffix matches the prefix of the * specified query sequence. * @return the range of matches as a pair of iterators */ template std::pair equal_range( const T& seq) const { assert(!m_dirty); return std::equal_range(m_data.begin(), m_data.end(), key_type(&seq[0]), Compare()); } size_t size() const { return m_data.size(); } const_iterator begin() const { return m_data.begin(); } const_iterator end() const { return m_data.end(); } private: /** Comparison functor. */ struct Compare { bool operator()(const value_type& a, const key_type& b) const { return a.first < b; } bool operator()(const key_type& a, const value_type& b) const { return a < b.first; } }; unsigned m_minOverlap; bool m_dirty; std::vector m_data; }; #endif abyss-2.2.4/Common/Timer.cpp000066400000000000000000000005441361462241400156620ustar00rootroot00000000000000#include "Timer.h" #include "Log.h" #include using namespace std; // Constructor starts the timer Timer::Timer(string funcString) : m_funcStr(funcString), m_start(clock()) { } // Destructor stops it and prints Timer::~Timer() { logger(2) << m_funcStr << ": " << setprecision(3) << (double)(clock() - m_start) / CLOCKS_PER_SEC << " s\n"; } abyss-2.2.4/Common/Timer.h000066400000000000000000000004601361462241400153240ustar00rootroot00000000000000#ifndef TIMER_H #define TIMER_H 1 #include /** * Time the duration between the construction and destruction of this * timer object and log that duration. */ class Timer { public: Timer(std::string funcString); ~Timer(); private: std::string m_funcStr; clock_t m_start; }; #endif abyss-2.2.4/Common/Uncompress.cpp000066400000000000000000000126431361462241400167430ustar00rootroot00000000000000/** Uncompress input files using pipes. * Hook the standard file opening functions, open, fopen and fopen64. * If the extension of the file being opened indicates the file is * compressed (.gz, .bz2, .xz), open a pipe to a program that * decompresses that file (gunzip, bunzip2 or xzdec) and return a * handle to the open pipe. * @author Shaun Jackman */ #include "config.h" #if HAVE_LIBDL #include "Fcontrol.h" #include "SignalHandler.h" #include "StringUtil.h" #include #include // for perror #include #include #include #include using namespace std; static const char* wgetExec(const string& path) { return startsWith(path, "http://") ? "wget -O-" : startsWith(path, "https://") ? "wget -O-" : startsWith(path, "ftp://") ? "wget -O-" : NULL; } static const char* zcatExec(const string& path) { return endsWith(path, ".ar") ? "ar -p" : endsWith(path, ".tar") ? "tar -xOf" : endsWith(path, ".tar.Z") ? "tar -zxOf" : endsWith(path, ".tar.gz") ? "tar -zxOf" : endsWith(path, ".tar.bz2") ? "tar -jxOf" : endsWith(path, ".tar.xz") ? "tar --use-compress-program=xzdec -xOf" : endsWith(path, ".Z") ? "gunzip -c" : endsWith(path, ".gz") ? "gunzip -c" : endsWith(path, ".bz2") ? "bunzip2 -c" : endsWith(path, ".xz") ? "xzdec -c" : endsWith(path, ".zip") ? "unzip -p" : endsWith(path, ".bam") ? "samtools view -h" : endsWith(path, ".cram") ? "samtools view -h" : endsWith(path, ".jf") ? "jellyfish dump" : endsWith(path, ".jfq") ? "jellyfish qdump" : endsWith(path, ".sra") ? "fastq-dump -Z --split-spot" : endsWith(path, ".url") ? "wget -O- -i" : endsWith(path, ".fqz") ? "fqz_comp -d" : NULL; } extern "C" { /** Open a pipe to uncompress the specified file. * Not thread safe. * @return a file descriptor */ static int uncompress(const char *path) { const char *wget = wgetExec(path); const char *zcat = wget != NULL ? wget : zcatExec(path); assert(zcat != NULL); int fd[2]; if (pipe(fd) == -1) return -1; int err = setCloexec(fd[0]); assert(err == 0); (void)err; char arg0[16], arg1[16], arg2[16]; int n = sscanf(zcat, "%s %s %s", arg0, arg1, arg2); assert(n == 2 || n == 3); /* It would be more portable to use fork than vfork, but fork can * fail with ENOMEM when the process calling fork is using a lot * of memory. A workaround for this problem is to set * sysctl vm.overcommit_memory=1 */ #if HAVE_WORKING_VFORK pid_t pid = vfork(); #else pid_t pid = fork(); #endif if (pid == -1) return -1; if (pid == 0) { dup2(fd[1], STDOUT_FILENO); close(fd[1]); if (n == 2) execlp(arg0, arg0, arg1, path, NULL); else execlp(arg0, arg0, arg1, arg2, path, NULL); // Calling perror after vfork is not allowed, but we're about // to exit and an error message would be really helpful. perror(arg0); _exit(EXIT_FAILURE); } else { close(fd[1]); return fd[0]; } } /** Open a pipe to uncompress the specified file. * @return a FILE pointer */ static FILE* funcompress(const char* path) { int fd = uncompress(path); if (fd == -1) { perror(path); exit(EXIT_FAILURE); } return fdopen(fd, "r"); } typedef FILE* (*fopen_t)(const char *path, const char *mode); /** If the specified file is compressed, return a pipe that * uncompresses it. */ FILE *fopen(const char *path, const char *mode) { static fopen_t real_fopen; if (real_fopen == NULL) real_fopen = (fopen_t)dlsym(RTLD_NEXT, "fopen"); if (real_fopen == NULL) { fprintf(stderr, "error: dlsym fopen: %s\n", dlerror()); exit(EXIT_FAILURE); } // open a web address if (wgetExec(path) != NULL) return funcompress(path); // to check if the file exists, we need to attempt to open it FILE* stream = real_fopen(path, mode); if (string(mode) != "r" || !stream || zcatExec(path) == NULL) return stream; else { fclose(stream); return funcompress(path); } } /** If the specified file is compressed, return a pipe that * uncompresses it. */ FILE *fopen64(const char *path, const char *mode) { static fopen_t real_fopen64; if (real_fopen64 == NULL) real_fopen64 = (fopen_t)dlsym(RTLD_NEXT, "fopen64"); if (real_fopen64 == NULL) { fprintf(stderr, "error: dlsym fopen64: %s\n", dlerror()); exit(EXIT_FAILURE); } // open a web address if (wgetExec(path) != NULL) return funcompress(path); // to check if the file exists, we need to attempt to open it FILE* stream = real_fopen64(path, mode); if (string(mode) != "r" || !stream || zcatExec(path) == NULL) return stream; else { fclose(stream); return funcompress(path); } } typedef int (*open_t)(const char *path, int flags, mode_t mode); /** If the specified file is compressed, return a pipe that * uncompresses it. */ int open(const char *path, int flags, mode_t mode) { static open_t real_open; if (real_open == NULL) real_open = (open_t)dlsym(RTLD_NEXT, "open"); if (real_open == NULL) { fprintf(stderr, "error: dlsym open: %s\n", dlerror()); exit(EXIT_FAILURE); } // open a web address if (wgetExec(path) != NULL) return uncompress(path); // to check if the file exists, we need to attempt to open it int filedesc = real_open(path, flags, mode); if (mode != ios_base::in || filedesc < 0 || zcatExec(path) == NULL) return filedesc; else { close(filedesc); return uncompress(path); } } } // extern "C" #endif // HAVE_LIBDL /** Initialize the uncompress module. */ bool uncompress_init() { #if HAVE_LIBDL signalInit(); #endif return HAVE_LIBDL; } abyss-2.2.4/Common/Uncompress.h000066400000000000000000000004151361462241400164020ustar00rootroot00000000000000#ifndef UNCOMPRESS_H #define UNCOMPRESS_H 1 bool uncompress_init(); namespace { const bool uncompressInitialized = uncompress_init(); bool getUncompressInitialized() __attribute__((unused)); bool getUncompressInitialized() { return uncompressInitialized; } } #endif abyss-2.2.4/Common/UnorderedMap.h000066400000000000000000000006751361462241400166410ustar00rootroot00000000000000#ifndef UNORDEREDMAP_H #define UNORDEREDMAP_H 1 #include "config.h" #include "Common/Hash.h" #if HAVE_UNORDERED_MAP # include using std::unordered_map; using std::unordered_multimap; #elif HAVE_TR1_UNORDERED_MAP # include using std::tr1::unordered_map; using std::tr1::unordered_multimap; #else # include using boost::unordered_map; using boost::unordered_multimap; #endif #endif abyss-2.2.4/Common/UnorderedSet.h000066400000000000000000000006751361462241400166570ustar00rootroot00000000000000#ifndef UNORDEREDSET_H #define UNORDEREDSET_H 1 #include "config.h" #include "Common/Hash.h" #if HAVE_UNORDERED_SET # include using std::unordered_set; using std::unordered_multiset; #elif HAVE_TR1_UNORDERED_SET # include using std::tr1::unordered_set; using std::tr1::unordered_multiset; #else # include using boost::unordered_set; using boost::unordered_multiset; #endif #endif abyss-2.2.4/Common/VectorUtil.h000066400000000000000000000007601361462241400163470ustar00rootroot00000000000000#ifndef VECTOR_UTIL_H #define VECTOR_UTIL_H 1 #include template class make_vector { private: std::vector vec; public: typedef make_vector mv; typedef std::vector 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 abyss-2.2.4/Common/cholesky.hpp000066400000000000000000000163551361462241400164370ustar00rootroot00000000000000/** -*- c++ -*- \file cholesky.hpp \brief cholesky decomposition */ /* - begin : 2005-08-24 - copyright : (C) 2005 by Gunter Winkler, Konstantin Kutzkow - email : guwi17@gmx.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _H_CHOLESKY_HPP_ #define _H_CHOLESKY_HPP_ #include /* * Workaround: UBLAS has not been updated to reflect changes to Boost serialization * in Boost 1.64. Including array_wrapper.hpp fixes the problem. However, * including array_wrapper.hpp with Boost < 1.64 also causes compilation * errors, so the #include must be conditional on BOOST_VERSION. * * See: https://stackoverflow.com/questions/44534516/error-make-array-is-not-a-member-of-boostserialization * And also: https://github.com/uBLAS/ublas/pull/55#issuecomment-316985022 */ #if BOOST_VERSION >= 106400 #include #endif #include #include #include #include #include #include #include namespace ublas = boost::numeric::ublas; /** \brief decompose the symmetric positive definit matrix A into product L L^T. * * \param MATRIX type of input matrix * \param TRIA type of lower triangular output matrix * \param A square symmetric positive definite input matrix (only the lower triangle is accessed) * \param L lower triangular output matrix * \return nonzero if decompositon fails (the value ist 1 + the numer of the failing row) */ template < class MATRIX, class TRIA > size_t cholesky_decompose(const MATRIX& A, TRIA& L) { using namespace ublas; assert( A.size1() == A.size2() ); assert( A.size1() == L.size1() ); assert( A.size2() == L.size2() ); const size_t n = A.size1(); for (size_t k=0 ; k < n; k++) { double qL_kk = A(k,k) - inner_prod( project( row(L, k), range(0, k) ), project( row(L, k), range(0, k) ) ); if (qL_kk <= 0) { return 1 + k; } else { double L_kk = sqrt( qL_kk ); L(k,k) = L_kk; matrix_column cLk(L, k); project( cLk, range(k+1, n) ) = ( project( column(A, k), range(k+1, n) ) - prod( project(L, range(k+1, n), range(0, k)), project(row(L, k), range(0, k) ) ) ) / L_kk; } } return 0; } /** \brief decompose the symmetric positive definit matrix A into product L L^T. * * \param MATRIX type of matrix A * \param A input: square symmetric positive definite matrix (only the lower triangle is accessed) * \param A output: the lower triangle of A is replaced by the cholesky factor * \return nonzero if decompositon fails (the value ist 1 + the numer of the failing row) */ template < class MATRIX > size_t cholesky_decompose(MATRIX& A) { using namespace ublas; const MATRIX& A_c(A); const size_t n = A.size1(); for (size_t k=0 ; k < n; k++) { double qL_kk = A_c(k,k) - inner_prod( project( row(A_c, k), range(0, k) ), project( row(A_c, k), range(0, k) ) ); if (qL_kk <= 0) { return 1 + k; } else { double L_kk = sqrt( qL_kk ); matrix_column cLk(A, k); project( cLk, range(k+1, n) ) = ( project( column(A_c, k), range(k+1, n) ) - prod( project(A_c, range(k+1, n), range(0, k)), project(row(A_c, k), range(0, k) ) ) ) / L_kk; A(k,k) = L_kk; } } return 0; } #if 0 using namespace ublas; // Operations: // n * (n - 1) / 2 + n = n * (n + 1) / 2 multiplications, // n * (n - 1) / 2 additions // Dense (proxy) case template void inplace_solve (const matrix_expression &e1, vector_expression &e2, lower_tag, column_major_tag) { std::cout << " is_lc "; typedef typename E2::size_type size_type; typedef typename E2::difference_type difference_type; typedef typename E2::value_type value_type; BOOST_UBLAS_CHECK (e1 ().size1 () == e1 ().size2 (), bad_size ()); BOOST_UBLAS_CHECK (e1 ().size2 () == e2 ().size (), bad_size ()); size_type size = e2 ().size (); for (size_type n = 0; n < size; ++ n) { #ifndef BOOST_UBLAS_SINGULAR_CHECK BOOST_UBLAS_CHECK (e1 () (n, n) != value_type/*zero*/(), singular ()); #else if (e1 () (n, n) == value_type/*zero*/()) singular ().raise (); #endif value_type t = e2 () (n) / e1 () (n, n); e2 () (n) = t; if (t != value_type/*zero*/()) { project( e2 (), range(n+1, size) ) .minus_assign( t * project( column( e1 (), n), range(n+1, size) ) ); } } } #endif /** \brief decompose the symmetric positive definit matrix A into product L L^T. * * \param MATRIX type of matrix A * \param A input: square symmetric positive definite matrix (only the lower triangle is accessed) * \param A output: the lower triangle of A is replaced by the cholesky factor * \return nonzero if decompositon fails (the value ist 1 + the numer of the failing row) */ template < class MATRIX > size_t incomplete_cholesky_decompose(MATRIX& A) { using namespace ublas; typedef typename MATRIX::value_type T; // read access to a const matrix is faster const MATRIX& A_c(A); const size_t n = A.size1(); for (size_t k=0 ; k < n; k++) { double qL_kk = A_c(k,k) - inner_prod( project( row( A_c, k ), range(0, k) ), project( row( A_c, k ), range(0, k) ) ); if (qL_kk <= 0) { return 1 + k; } else { double L_kk = sqrt( qL_kk ); // aktualisieren for (size_t i = k+1; i < A.size1(); ++i) { T* Aik = A.find_element(i, k); if (Aik != 0) { *Aik = ( *Aik - inner_prod( project( row( A_c, k ), range(0, k) ), project( row( A_c, i ), range(0, k) ) ) ) / L_kk; } } A(k,k) = L_kk; } } return 0; } /** \brief solve system L L^T x = b inplace * * \param L a triangular matrix * \param x input: right hand side b; output: solution x */ template < class TRIA, class VEC > void cholesky_solve(const TRIA& L, VEC& x, ublas::lower) { using namespace ublas; // ::inplace_solve(L, x, lower_tag(), typename TRIA::orientation_category () ); inplace_solve(L, x, lower_tag() ); inplace_solve(trans(L), x, upper_tag()); } #endif abyss-2.2.4/Common/city.cc000066400000000000000000000357241361462241400153650ustar00rootroot00000000000000// Copyright (c) 2011 Google, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // CityHash, by Geoff Pike and Jyrki Alakuijala // // This file provides CityHash64() and related functions. // // It's probably possible to create even faster hash functions by // writing a program that systematically explores some of the space of // possible hash functions, by using SIMD instructions, or by // compromising on hash quality. #include "config.h" #include #include #include // for memcpy and memset using namespace std; static uint64 UNALIGNED_LOAD64(const char *p) { uint64 result; memcpy(&result, p, sizeof(result)); return result; } static uint32 UNALIGNED_LOAD32(const char *p) { uint32 result; memcpy(&result, p, sizeof(result)); return result; } #if !defined(WORDS_BIGENDIAN) #define uint32_in_expected_order(x) (x) #define uint64_in_expected_order(x) (x) #else #ifdef _MSC_VER #include #define bswap_32(x) _byteswap_ulong(x) #define bswap_64(x) _byteswap_uint64(x) #elif defined(__APPLE__) // Mac OS X / Darwin features #include #define bswap_32(x) OSSwapInt32(x) #define bswap_64(x) OSSwapInt64(x) #elif defined(__FreeBSD__) #include #define bswap_32(x) bswap32(x) #define bswap_64(x) bswap64(x) #else #include #endif #define uint32_in_expected_order(x) (bswap_32(x)) #define uint64_in_expected_order(x) (bswap_64(x)) #endif // WORDS_BIGENDIAN #if !defined(LIKELY) #if HAVE_BUILTIN_EXPECT #define LIKELY(x) (__builtin_expect(!!(x), 1)) #else #define LIKELY(x) (x) #endif #endif static uint64 Fetch64(const char *p) { return uint64_in_expected_order(UNALIGNED_LOAD64(p)); } static uint32 Fetch32(const char *p) { return uint32_in_expected_order(UNALIGNED_LOAD32(p)); } // Some primes between 2^63 and 2^64 for various uses. static const uint64 k0 = 0xc3a5c85c97cb3127ULL; static const uint64 k1 = 0xb492b66fbe98f273ULL; static const uint64 k2 = 0x9ae16a3b2f90404fULL; static const uint64 k3 = 0xc949d7c7509e6557ULL; // Bitwise right rotate. Normally this will compile to a single // instruction, especially if the shift is a manifest constant. static uint64 Rotate(uint64 val, int shift) { // Avoid shifting by 64: doing so yields an undefined result. return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); } // Equivalent to Rotate(), but requires the second arg to be non-zero. // On x86-64, and probably others, it's possible for this to compile // to a single instruction if both args are already in registers. static uint64 RotateByAtLeast1(uint64 val, int shift) { return (val >> shift) | (val << (64 - shift)); } static uint64 ShiftMix(uint64 val) { return val ^ (val >> 47); } static uint64 HashLen16(uint64 u, uint64 v) { return Hash128to64(uint128(u, v)); } static uint64 HashLen0to16(const char *s, size_t len) { if (len > 8) { uint64 a = Fetch64(s); uint64 b = Fetch64(s + len - 8); return HashLen16(a, RotateByAtLeast1(b + len, len)) ^ b; } if (len >= 4) { uint64 a = Fetch32(s); return HashLen16(len + (a << 3), Fetch32(s + len - 4)); } if (len > 0) { uint8 a = s[0]; uint8 b = s[len >> 1]; uint8 c = s[len - 1]; uint32 y = static_cast(a) + (static_cast(b) << 8); uint32 z = len + (static_cast(c) << 2); return ShiftMix(y * k2 ^ z * k3) * k2; } return k2; } // This probably works well for 16-byte strings as well, but it may be overkill // in that case. static uint64 HashLen17to32(const char *s, size_t len) { uint64 a = Fetch64(s) * k1; uint64 b = Fetch64(s + 8); uint64 c = Fetch64(s + len - 8) * k2; uint64 d = Fetch64(s + len - 16) * k0; return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d, a + Rotate(b ^ k3, 20) - c + len); } // Return a 16-byte hash for 48 bytes. Quick and dirty. // Callers do best to use "random-looking" values for a and b. static pair WeakHashLen32WithSeeds( uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) { a += w; b = Rotate(b + a + z, 21); uint64 c = a; a += x; a += y; b += Rotate(a, 44); return make_pair(a + z, b + c); } // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. static pair WeakHashLen32WithSeeds( const char* s, uint64 a, uint64 b) { return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a, b); } // Return an 8-byte hash for 33 to 64 bytes. static uint64 HashLen33to64(const char *s, size_t len) { uint64 z = Fetch64(s + 24); uint64 a = Fetch64(s) + (len + Fetch64(s + len - 16)) * k0; uint64 b = Rotate(a + z, 52); uint64 c = Rotate(a, 37); a += Fetch64(s + 8); c += Rotate(a, 7); a += Fetch64(s + 16); uint64 vf = a + z; uint64 vs = b + Rotate(a, 31) + c; a = Fetch64(s + 16) + Fetch64(s + len - 32); z = Fetch64(s + len - 8); b = Rotate(a + z, 52); c = Rotate(a, 37); a += Fetch64(s + len - 24); c += Rotate(a, 7); a += Fetch64(s + len - 16); uint64 wf = a + z; uint64 ws = b + Rotate(a, 31) + c; uint64 r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0); return ShiftMix(r * k0 + vs) * k2; } uint64 CityHash64(const char *s, size_t len) { if (len <= 32) { if (len <= 16) { return HashLen0to16(s, len); } else { return HashLen17to32(s, len); } } else if (len <= 64) { return HashLen33to64(s, len); } // For strings over 64 bytes we hash the end first, and then as we // loop we keep 56 bytes of state: v, w, x, y, and z. uint64 x = Fetch64(s + len - 40); uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56); uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); pair v = WeakHashLen32WithSeeds(s + len - 64, len, z); pair w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); x = x * k1 + Fetch64(s); // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. len = (len - 1) & ~static_cast(63); do { x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; x ^= w.second; y += v.first + Fetch64(s + 40); z = Rotate(z + w.first, 33) * k1; v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); std::swap(z, x); s += 64; len -= 64; } while (len != 0); return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z, HashLen16(v.second, w.second) + x); } uint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) { return CityHash64WithSeeds(s, len, k2, seed); } uint64 CityHash64WithSeeds(const char *s, size_t len, uint64 seed0, uint64 seed1) { return HashLen16(CityHash64(s, len) - seed0, seed1); } // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings // of any length representable in signed long. Based on City and Murmur. static uint128 CityMurmur(const char *s, size_t len, uint128 seed) { uint64 a = Uint128Low64(seed); uint64 b = Uint128High64(seed); uint64 c = 0; uint64 d = 0; signed long l = len - 16; if (l <= 0) { // len <= 16 a = ShiftMix(a * k1) * k1; c = b * k1 + HashLen0to16(s, len); d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c)); } else { // len > 16 c = HashLen16(Fetch64(s + len - 8) + k1, a); d = HashLen16(b + len, c + Fetch64(s + len - 16)); a += d; do { a ^= ShiftMix(Fetch64(s) * k1) * k1; a *= k1; b ^= a; c ^= ShiftMix(Fetch64(s + 8) * k1) * k1; c *= k1; d ^= c; s += 16; l -= 16; } while (l > 0); } a = HashLen16(a, c); b = HashLen16(d, b); return uint128(a ^ b, HashLen16(b, a)); } uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) { if (len < 128) { return CityMurmur(s, len, seed); } // We expect len >= 128 to be the common case. Keep 56 bytes of state: // v, w, x, y, and z. pair v, w; uint64 x = Uint128Low64(seed); uint64 y = Uint128High64(seed); uint64 z = len * k1; v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s); v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8); w.first = Rotate(y + z, 35) * k1 + x; w.second = Rotate(x + Fetch64(s + 88), 53) * k1; // This is the same inner loop as CityHash64(), manually unrolled. do { x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; x ^= w.second; y += v.first + Fetch64(s + 40); z = Rotate(z + w.first, 33) * k1; v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); std::swap(z, x); s += 64; x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; x ^= w.second; y += v.first + Fetch64(s + 40); z = Rotate(z + w.first, 33) * k1; v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); std::swap(z, x); s += 64; len -= 128; } while (LIKELY(len >= 128)); x += Rotate(v.first + z, 49) * k0; z += Rotate(w.first, 37) * k0; // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. for (size_t tail_done = 0; tail_done < len; ) { tail_done += 32; y = Rotate(x + y, 42) * k0 + v.second; w.first += Fetch64(s + len - tail_done + 16); x = x * k0 + w.first; z += w.second + Fetch64(s + len - tail_done); w.second += v.first; v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second); } // At this point our 56 bytes of state should contain more than // enough information for a strong 128-bit hash. We use two // different 56-byte-to-8-byte hashes to get a 16-byte final result. x = HashLen16(x, v.first); y = HashLen16(y + z, w.first); return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second)); } uint128 CityHash128(const char *s, size_t len) { if (len >= 16) { return CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s) ^ k3, Fetch64(s + 8))); } else if (len >= 8) { return CityHash128WithSeed(NULL, 0, uint128(Fetch64(s) ^ (len * k0), Fetch64(s + len - 8) ^ k1)); } else { return CityHash128WithSeed(s, len, uint128(k0, k1)); } } #if 0 // #ifdef __SSE4_2__ #include #include // Requires len >= 240. static void CityHashCrc256Long(const char *s, size_t len, uint32 seed, uint64 *result) { uint64 a = Fetch64(s + 56) + k0; uint64 b = Fetch64(s + 96) + k0; uint64 c = result[0] = HashLen16(b, len); uint64 d = result[1] = Fetch64(s + 120) * k0 + len; uint64 e = Fetch64(s + 184) + seed; uint64 f = seed; uint64 g = 0; uint64 h = 0; uint64 i = 0; uint64 j = 0; uint64 t = c + d; // 240 bytes of input per iter. size_t iters = len / 240; len -= iters * 240; do { #define CHUNK(multiplier, z) \ { \ uint64 old_a = a; \ a = Rotate(b, 41 ^ z) * multiplier + Fetch64(s); \ b = Rotate(c, 27 ^ z) * multiplier + Fetch64(s + 8); \ c = Rotate(d, 41 ^ z) * multiplier + Fetch64(s + 16); \ d = Rotate(e, 33 ^ z) * multiplier + Fetch64(s + 24); \ e = Rotate(t, 25 ^ z) * multiplier + Fetch64(s + 32); \ t = old_a; \ } \ f = _mm_crc32_u64(f, a); \ g = _mm_crc32_u64(g, b); \ h = _mm_crc32_u64(h, c); \ i = _mm_crc32_u64(i, d); \ j = _mm_crc32_u64(j, e); \ s += 40 CHUNK(1, 1); CHUNK(k0, 0); CHUNK(1, 1); CHUNK(k0, 0); CHUNK(1, 1); CHUNK(k0, 0); } while (--iters > 0); while (len >= 40) { CHUNK(k0, 0); len -= 40; } if (len > 0) { s = s + len - 40; CHUNK(k0, 0); } j += i << 32; a = HashLen16(a, j); h += g << 32; b += h; c = HashLen16(c, f) + i; d = HashLen16(d, e + result[0]); j += e; i += HashLen16(h, t); e = HashLen16(a, d) + j; f = HashLen16(b, c) + a; g = HashLen16(j, i) + c; result[0] = e + f + g + h; a = ShiftMix((a + g) * k0) * k0 + b; result[1] += a + result[0]; a = ShiftMix(a * k0) * k0 + c; result[2] = a + result[1]; a = ShiftMix((a + e) * k0) * k0; result[3] = a + result[2]; } // Requires len < 240. static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) { char buf[240]; memcpy(buf, s, len); memset(buf + len, 0, 240 - len); CityHashCrc256Long(buf, 240, ~static_cast(len), result); } void CityHashCrc256(const char *s, size_t len, uint64 *result) { if (LIKELY(len >= 240)) { CityHashCrc256Long(s, len, 0, result); } else { CityHashCrc256Short(s, len, result); } } uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) { if (len <= 900) { return CityHash128WithSeed(s, len, seed); } else { uint64 result[4]; CityHashCrc256(s, len, result); uint64 u = Uint128High64(seed) + result[0]; uint64 v = Uint128Low64(seed) + result[1]; return uint128(HashLen16(u, v + result[2]), HashLen16(Rotate(v, 32), u * k0 + result[3])); } } uint128 CityHashCrc128(const char *s, size_t len) { if (len <= 900) { return CityHash128(s, len); } else { uint64 result[4]; CityHashCrc256(s, len, result); return uint128(result[2], result[3]); } } #endif abyss-2.2.4/Common/city.h000066400000000000000000000071251361462241400152210ustar00rootroot00000000000000// Copyright (c) 2011 Google, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // CityHash, by Geoff Pike and Jyrki Alakuijala // // This file provides a few functions for hashing strings. On x86-64 // hardware in 2011, CityHash64() is faster than other high-quality // hash functions, such as Murmur. This is largely due to higher // instruction-level parallelism. CityHash64() and CityHash128() also perform // well on hash-quality tests. // // CityHash128() is optimized for relatively long strings and returns // a 128-bit hash. For strings more than about 2000 bytes it can be // faster than CityHash64(). // // Functions in the CityHash family are not suitable for cryptography. // // WARNING: This code has not been tested on big-endian platforms! // It is known to work well on little-endian platforms that have a small penalty // for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. // // By the way, for some hash functions, given strings a and b, the hash // of a+b is easily derived from the hashes of a and b. This property // doesn't hold for any hash functions in this file. #ifndef CITY_HASH_H_ #define CITY_HASH_H_ #include // for size_t. #include #include typedef uint8_t uint8; typedef uint32_t uint32; typedef uint64_t uint64; typedef std::pair uint128; inline uint64 Uint128Low64(const uint128& x) { return x.first; } inline uint64 Uint128High64(const uint128& x) { return x.second; } // Hash function for a byte array. uint64 CityHash64(const char *buf, size_t len); // Hash function for a byte array. For convenience, a 64-bit seed is also // hashed into the result. uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed); // Hash function for a byte array. For convenience, two seeds are also // hashed into the result. uint64 CityHash64WithSeeds(const char *buf, size_t len, uint64 seed0, uint64 seed1); // Hash function for a byte array. uint128 CityHash128(const char *s, size_t len); // Hash function for a byte array. For convenience, a 128-bit seed is also // hashed into the result. uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed); // Hash 128 input bits down to 64 bits of output. // This is intended to be a reasonably good hash function. inline uint64 Hash128to64(const uint128& x) { // Murmur-inspired hashing. const uint64 kMul = 0x9ddfea08eb382d69ULL; uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; a ^= (a >> 47); uint64 b = (Uint128High64(x) ^ a) * kMul; b ^= (b >> 47); b *= kMul; return b; } #endif // CITY_HASH_H_ abyss-2.2.4/Consensus/000077500000000000000000000000001361462241400146235ustar00rootroot00000000000000abyss-2.2.4/Consensus/Consensus.cpp000066400000000000000000000331221361462241400173100ustar00rootroot00000000000000#include "Alignment.h" #include "Common/Options.h" #include "ContigID.h" #include "FastaReader.h" #include "IOUtil.h" #include "Uncompress.h" #include "UnorderedMap.h" #include #include #include #include #include #include #include #include using namespace std; #define PROGRAM "Consensus" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Tony Raymond and Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... CONTIG\n" "\n" "Read alignments from KAligner from standard input.\n" "Ensure that the --seq option was used when running KAligner.\n" "Call a consensus at each position of each contig and write the\n" "consensus in FASTA format to OUTPUT.\n" "\n" " Arguments:\n" "\n" " CONTIG contigs in FASTA format\n" "\n" " Options:\n" "\n" " -o, --out=OUTPUT write the output FASTA file to OUTPUT\n" " -p, --pileup=PILEUP write the pileup to PILEUP\n" " --nt output nucleotide contigs [default]\n" " --cs output colour-space contigs\n" " -V, --variants print only variants in the pileup\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 { static string outPath; static string pileupPath; static bool csToNt; static int outputCS; static int onlyVariants; } static const char shortopts[] = "o:p:vV"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "verbose", no_argument, NULL, 'v' }, { "out", required_argument, NULL, 'o' }, { "pileup", required_argument, NULL, 'p' }, { "variants", no_argument, &opt::onlyVariants, 1 }, { "nt", no_argument, &opt::outputCS, 0 }, { "cs", no_argument, &opt::outputCS, 1 }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; struct BaseCount { unsigned count[4]; BaseCount() { fill(count, count + 4, 0); } /** Return the number of reads at this position. */ unsigned sum() const { return accumulate(count, count+4, 0); } friend ostream& operator <<(ostream& out, const BaseCount& base) { out << base.count[0]; for (int x = 1; x < 4; x++) out << '\t' << base.count[x]; return out; } }; typedef vector BaseCounts; struct ContigCount { Sequence seq; unsigned coverage; string comment; BaseCounts counts; }; /** A map of contigs. The alignments reference the contig by name. */ typedef unordered_map ContigMap; static ContigMap g_contigs; /** Read all contigs in and store the contigs in g_contigs and make a * g_baseCounts, to store pile-up for each base. */ static void readContigs(const string& contigsPath) { FastaReader contigsFile(contigsPath.c_str(), FastaReader::NO_FOLD_CASE); int count = 0; for (FastaRecord rec; contigsFile >> rec;) { const Sequence& seq = rec.seq; ContigCount& contig = g_contigs[rec.id]; contig.seq = seq; istringstream ss(rec.comment); unsigned length; contig.coverage = 0; ss >> length >> contig.coverage >> ws; getline(ss, contig.comment); if (count == 0) { // Detect colour-space contigs. opt::colourSpace = isdigit(seq[0]); if (!opt::outputCS) opt::csToNt = opt::colourSpace; else if (!opt::colourSpace) { cerr << "error: Cannot convert nucleotide data to " "colour space.\n"; exit(EXIT_FAILURE); } } else { if (opt::colourSpace) assert(isdigit(seq[0])); else assert(isalpha(seq[0])); } contig.counts = BaseCounts(contig.seq.length() + (opt::csToNt ? 1 : 0)); count++; } cerr << "Read " << count << " contigs\n"; assert(contigsFile.eof()); assert(count > 0); } typedef vector AlignmentVector; static void readAlignment(string& line, string& readID, Sequence& seq, AlignmentVector& alignments) { char anchor; istringstream s(line); if (opt::colourSpace || opt::csToNt) s >> readID >> anchor >> seq; else s >> readID >> seq; Alignment alignment; while (s >> alignment) alignments.push_back(alignment); if (!alignments.empty() && opt::csToNt && seq.find_first_not_of("0123") == string::npos) seq = colourToNucleotideSpace(anchor, seq); } /** Builds the pile up of all reads based on the alignments and * read sequence */ static void buildBaseQuality() { if (opt::csToNt) opt::colourSpace = false; // for each read and/or set of alignments. for (string line; getline(cin, line);) { string readID; Sequence seq; AlignmentVector alignments; readAlignment(line, readID, seq, alignments); // If converting to NT space, check that at least one of the // alignments starts at read location 0. Otherwise, it is // likely to introduce a frameshift or erroneous sequence in // the final consensus. if (opt::csToNt) { bool good = false; for (AlignmentVector::const_iterator alignIter = alignments.begin(); alignIter != alignments.end(); ++alignIter) { if (alignIter->read_start_pos == 0) { good = true; break; } } if (!good) continue; } // For each alignment for the read. for (AlignmentVector::const_iterator alignIter = alignments.begin(); alignIter != alignments.end(); ++alignIter) { string seqrc; Alignment a; if (alignIter->isRC) { seqrc = reverseComplement(seq); a = alignIter->flipQuery(); } else { seqrc = seq; a = *alignIter; } const char* s = seqrc.c_str(); ContigMap::iterator contigIt = g_contigs.find(a.contig); if (contigIt == g_contigs.end()) { cerr << "error: unexpected contig ID: `" << a.contig << "'\n"; exit(EXIT_FAILURE); } BaseCounts& countsVec = contigIt->second.counts; int read_min; int read_max; if (!opt::csToNt) { read_min = a.read_start_pos - a.contig_start_pos; read_min = read_min > 0 ? read_min : 0; read_max = a.read_start_pos + countsVec.size() - a.contig_start_pos; read_max = read_max < a.read_length ? read_max : a.read_length; } else { read_min = a.read_start_pos; read_max = read_min + a.align_length + 1; } if ((int)countsVec.size() < a.contig_start_pos - a.read_start_pos + read_max - 1) cerr << countsVec.size() << '\n'; // Assertions to make sure alignment math was done right. assert((int)countsVec.size() >= a.contig_start_pos - a.read_start_pos + read_max - 1); assert(read_max <= (int)seq.length()); assert(read_min >= 0); // Pile-up every base in the read to the contig. for (int x = read_min; x < read_max; x++) { char c = toupper(s[x]); switch (c) { case 'A': case 'C': case 'G': case 'T': case '0': case '1': case '2': case '3': unsigned pos = a.contig_start_pos - a.read_start_pos + x; assert(pos < countsVec.size()); countsVec[pos].count[baseToCode(c)]++; } } } } } /** Returns the most likely base found by the pile up count. */ static char selectBase(const BaseCount& count, unsigned& sumBest, unsigned& sumSecond) { int bestBase = -1; unsigned bestCount = 0; unsigned secondCount = 0; for (int x = 0; x < 4; x++) { if (count.count[x] > bestCount) { bestBase = x; secondCount = bestCount; bestCount = count.count[x]; } } sumBest += bestCount; sumSecond += secondCount; if (bestBase == -1) return 'N'; return codeToBase(bestBase); } /** Convert all 'N' bases to nt's based on local information. */ static void fixUnknown(Sequence& ntSeq, const Sequence& csSeq ) { size_t index = ntSeq.find_first_of('N'); size_t rindex = ntSeq.find_last_of('N'); char base; #if 0 if (index == 0) { #if 0 for (index = ntSeq.find_first_of("ACGT"); index > 0; index--) #endif index = ntSeq.find_first_of("ACGT"); while (index != 0) { base = colourToNucleotideSpace(ntSeq.at(index), csSeq.at(index - 1)); ntSeq.replace(index - 1, 1, 1, base); //ntSeq[index-1] = base; index = ntSeq.find_first_of("ACGT"); } index = ntSeq.find_first_of('N'); } #endif if (index == 0 || rindex == ntSeq.length() - 1) { ntSeq = ntSeq.substr(ntSeq.find_first_of("ACGT"), ntSeq.find_last_of("ACGT") - ntSeq.find_first_of("ACGT") + 1); index = ntSeq.find_first_of('N'); } while (index != string::npos) { // If the base isn't the first or last base in the seq... base = colourToNucleotideSpace(ntSeq.at(index - 1), csSeq.at(index - 1)); ntSeq.replace(index, 1, 1, base); index = ntSeq.find_first_of('N'); } } static void writePileup(ostream& out, const string &id, unsigned pos, char refc, char genotype, const BaseCount& counts) { char foldrefc = toupper(refc); if (opt::onlyVariants && foldrefc == genotype) return; out << id << '\t' // reference sequence name << 1 + pos << '\t' // reference coordinate << refc << '\t' // reference base << genotype << '\t' // genotype << "25\t" // P(genotype is wrong) << "25\t" // P(genotype is the same as the reference) << "25\t" // RMS mapping quality << counts.sum() << '\t'; // number of reads switch (foldrefc) { case 'A': case 'C': case 'G': case 'T': case '0': case '1': case '2': case '3': { uint8_t ref = baseToCode(foldrefc); for (int i = 0; i < 4; i++) if (i != ref) out << string(counts.count[i], codeToBase(i)); out << string(counts.count[ref], '.'); break; } default: for (int i = 0; i < 4; i++) out << string(counts.count[i], codeToBase(i)); } out << '\n'; assert(out.good()); } /** Forms contigs based on the consensus of each base and outputs them * to the file specified by the -o option. */ static void consensus(const string& outPath, const string& pileupPath) { ofstream outFile(outPath.c_str()); assert_good(outFile, outPath); ofstream pileupFile; ostream& pileupOut = pileupPath.empty() || pileupPath == "-" ? cout : (pileupFile.open(pileupPath.c_str()), pileupFile); assert_good(pileupOut, pileupPath); unsigned numIgnored = 0; for (ContigMap::const_iterator it = g_contigs.begin(); it != g_contigs.end(); ++it) { const ContigCount& contig = it->second; unsigned seqLength = it->second.counts.size(); Sequence outSeq(seqLength, 'N'); unsigned sumBest = 0; unsigned sumSecond = 0; for (unsigned x = 0; x < seqLength; x++) { char c = selectBase( it->second.counts[x], sumBest, sumSecond); outSeq[x] = islower(contig.seq[x]) ? tolower(c) : c; } if (outSeq.find_first_of("ACGT") != string::npos) { // Check that the average percent agreement was enough to // write the contig to file. float percentAgreement = sumBest / (float)(sumBest + sumSecond); if (isnan(percentAgreement) || percentAgreement < .9) { numIgnored++; if (opt::csToNt) { if (opt::verbose > 0) cerr << "warning: Contig " << it->first << " has less than 90% agreement " "and will not be converted.\n"; } else continue; } else { if (opt::csToNt) fixUnknown(outSeq, contig.seq); ostringstream comment; comment << outSeq.length() << ' ' << contig.coverage; if (!contig.comment.empty()) comment << ' ' << contig.comment; outFile << FastaRecord( it->first, comment.str(), outSeq); assert(outFile.good()); } if (opt::verbose > 1) { // ID pos reference genotype A C G T if (opt::csToNt) for (unsigned i = 0; i < seqLength - 1; i++) cout << it->first << '\t' << 1+i << '\t' << contig.seq[i] << '\t' << nucleotideToColourSpace( outSeq[i], outSeq[i + 1]) << '\t' << contig.counts[i].sum() << '\t' << contig.counts[i] << '\n'; else for (unsigned i = 0; i < seqLength; i++) cout << it->first << '\t' << 1+i << '\t' << contig.seq[i] << '\t' << outSeq[i] << '\t' << contig.counts[i].sum() << '\t' << contig.counts[i] << '\n'; } if (!pileupPath.empty()) { if (opt::csToNt) for (unsigned i = 0; i < seqLength-1; i++) writePileup(pileupOut, it->first, i, contig.seq[i], nucleotideToColourSpace( outSeq[i], outSeq[i+1]), contig.counts[i]); else for (unsigned i = 0; i < seqLength; i++) writePileup(pileupOut, it->first, i, contig.seq[i], outSeq[i], contig.counts[i]); } } else if (opt::verbose > 0) { cerr << "warning: Contig " << it->first << " was not supported by a complete read " "and was omitted.\n"; } } } 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 'v': opt::verbose++; break; case 'o': arg >> opt::outPath; break; case 'p': arg >> opt::pileupPath; break; case 'V': opt::onlyVariants = true; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::outPath.empty() && opt::pileupPath.empty()) { cerr << PROGRAM ": " << "missing -o,--out option\n"; die = true; } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 1) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } readContigs(argv[optind++]); buildBaseQuality(); consensus(opt::outPath, opt::pileupPath); } abyss-2.2.4/Consensus/Makefile.am000066400000000000000000000004011361462241400166520ustar00rootroot00000000000000bin_PROGRAMS = Consensus Consensus_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer Consensus_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a Consensus_SOURCES = \ Consensus.cpp abyss-2.2.4/DAssembler/000077500000000000000000000000001361462241400146645ustar00rootroot00000000000000abyss-2.2.4/DAssembler/DAssembler.cpp000066400000000000000000000450651361462241400174230ustar00rootroot00000000000000#include "config.h" #include "Uncompress.h" #include "UnorderedMap.h" #include #include #include #include #include #include #include #include #include "FastaReader.h" #include "Rotation.h" #include "RotatedRead.h" using namespace std; #define PROGRAM "DAssembler" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Rod Docking.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; namespace opt { static unsigned max_overlap = 10; static unsigned max_mismatch = 2; static unsigned min_coverage = 2; static unsigned read_length = 50; static int verbose = 0; } static const char shortopts[] = "o:m:c:r:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "max_overlap", required_argument, NULL, 'o' }, { "max_mismatch", required_argument, NULL, 'm' }, { "min_coverage", required_argument, NULL, 'c' }, { "read_length", required_argument, NULL, 'r' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [READS]\n" "Assemble a single contig from reads in a single orientation.\n" "\n" " Arguments:\n" "\n" " READS fasta-formatted reads file: the first read is used as the seed.\n" "\n" " Options:\n" "\n" " -o, --max_overlap=INT maximum tier overlap for consensus calling" " [10]\n" " -m, --max_mismatch=INT maximum mismatches allowed for consensus" " calling [2]\n" " -c, --min_coverage=INT minimum coverage to call a consensus base" " [2]\n" " -r, --read_length=INT read length\n" " -v, --verbose display verbose output\n" " --help display this help and exit\n" "\n"; /* A small struct for holding overlap information: just a sequence and offset from the focal read */ struct Overlap{ string seq; unsigned offset; Overlap(const string& seq, unsigned offset) : seq(seq), offset(offset) { } }; /* Additional sort of Overlap objects used for pretty-printing alignments*/ static bool offset_sort(const Overlap& x, const Overlap& y) { return x.offset < y.offset; } /* Calculate the tier overlap between two rotated reads */ static int tier_overlap(const string& seq1, const string& seq2, bool allow_mismatch = false); /* From a rotated read, return the original sequence */ static string original_read_from_rotated_read( const string& rotated_read) { size_t dollar_pos = rotated_read.find('$'); string orig_seq = rotated_read.substr( dollar_pos+1,rotated_read.size()-dollar_pos) + rotated_read.substr(0,dollar_pos); return orig_seq; } /* Struct for holding base counts at a given position */ struct BaseCount { unsigned x[4]; BaseCount() { fill(x, x + 4, 0); } /** Return the number of reads at this position. */ unsigned sum() const { return accumulate(x, x+4, 0); } friend ostream& operator <<(ostream& out, const BaseCount& base) { out << base.x[0]; for (int x = 1; x < 4; x++) out << '\t' << base.x[x]; return out; } }; /* Call a consensus base */ static char call_consensus_base(BaseCount counts, char orig_base) { unsigned coverage = accumulate(counts.x, counts.x+4, 0); /*If we're below minimum coverage but have an already-called base (i.e., for the first few bases)*/ if (coverage < opt::min_coverage) return orig_base; // Call a consensus base unsigned *maxIt = max_element(counts.x, counts.x+4); // Very verbose debugging output // char base_to_return = float(*maxIt) <= float(coverage)*0.60 ? orig_base : codeToBase(maxIt - counts.x); // char new_base_to_return = *maxIt < opt::min_coverage ? orig_base : codeToBase(maxIt - counts.x); // float call_threshold = float(coverage)*0.60; // float max_base_percent = float(*maxIt) / float(coverage); // cerr << "Coverage: " << coverage << "\tOriginal: " << orig_base << // "\tReturning: " << base_to_return << "\tBases: " << counts << // "\tCall threshold: " << call_threshold << // "\tMax base percent: " << max_base_percent << // "\tNew base to return: " << new_base_to_return << endl; // Original version with hard-coded coverage frequency of 60% // return float(*maxIt) <= float(coverage)*0.60 ? orig_base // : codeToBase(maxIt - counts.x); // Return the most-frequent base, so long as that base has // coverage >= min_coverage return *maxIt < opt::min_coverage ? orig_base : codeToBase(maxIt - counts.x); } /* Return the frequency of the most-common base*/ static float most_common_base_frequency(BaseCount counts) { // Calculate coverage as before unsigned coverage = accumulate(counts.x, counts.x+4, 0); // Call a consensus base unsigned *maxIt = max_element(counts.x, counts.x+4); // Return the frequency of the most-common base return float(*maxIt) / float(coverage); } typedef vector Rotations; // Find all overlaps with the given focal read and call a consensus sequence static string find_complex_overlap(const RotatedRead& f, const Rotations& r, vector& rl) { // A vector for tracking all the overlaps, seeded with the initial read vector o; o.push_back(Overlap(f.seq, 0)); // The pre-pended string to use to seed the search const string& seq1 = '$' + f.seq; //Find it in the sorted list - NOTE: if the flank read doesn't correspond // to a real read, this iterator will not be used Rotations::const_iterator rt = lower_bound(r.begin(), r.end(), seq1); /* Continue down the sorted list, checking for other matches - for real reads (seq1 == rt->seq), continue from the position of seq1 in the list - otherwise, just start at the beginning */ for(Rotations::const_iterator st = (seq1 == rt->seq) ? rt+1 : r.begin(); st != r.end(); ++st) { // Check for an overlap between the two sequences, // allowing for mismatches const string& seq2 = st->seq; unsigned new_overlap = tier_overlap(seq1, seq2, true); // Continue if there's no match if (new_overlap == 0 || new_overlap > opt::max_overlap) continue; // Add a new overlap object for each appropriate overlap found o.push_back(Overlap( original_read_from_rotated_read(seq2), new_overlap)); } // Counters for calculating coverage // Vector size should be something like "read_length + maximum tier" // THIS WILL BREAK WITH LONGER READS vector counts(300); // Pretty-print the alignment for verbose only if(opt::verbose){ cerr << endl; sort(o.begin(), o.end(), offset_sort); } // Go through each overlap to count bases offset by the appropriate amount for(vector::const_iterator ot = o.begin(); ot != o.end(); ++ot){ // Pretty-print each found read aligned with the focal read if (opt::verbose) cerr << string(ot->offset, ' ') << ot->seq << " t:" << ot->offset; // Retrieve the original RotatedRead object to get the // count for each read vector::const_iterator rt = lower_bound( rl.begin(), rl.end(), ot->seq); if(opt::verbose){cerr << " x" << rt->count << " used: " << rt->used << endl;} // Continue if we've marked this read as used already if(rt->used == true){ continue; } // Increment the coverage lists appropriately for (size_t i = 0; i < opt::read_length; ++i){ if ((ot->seq[i] == 'X') || (ot->seq[i] == 'N')){ continue; } counts[i+ot->offset].x[baseToCode(ot->seq[i])] += rt->count; } } // Call consensus bases until we run out of coverage ostringstream new_contig; char new_base = '*'; float current_consensus_freq = 1.0; float next_consensus_freq = 1.0; for (unsigned i = 0; new_base != 'X'; i++) { // Retrieve the original base, or 'X' if we're past the end // of the original flank char orig_base = i < opt::read_length ? f.seq[i] : 'X'; // Call a new consensus base if possible new_base = call_consensus_base(counts[i], orig_base); // Check the frequency of the most-common base current_consensus_freq = most_common_base_frequency(counts[i]); next_consensus_freq = most_common_base_frequency(counts[i+1]); //cerr << "Current: " << current_consensus_freq << " Next: " << next_consensus_freq << endl; // Bail out if we encounter two SNPs in a row // Set the current base to 'X' and trim the last one if ((current_consensus_freq <= 0.8) && (next_consensus_freq <= 0.8)) new_base = 'X'; // If we've found a new base, add it to the growing consensus if (new_base != 'X') new_contig << new_base; } if (opt::verbose) cerr << new_contig.str() << " (consensus) " << endl; // Mark reads that shouldn't be used again unsigned growth = new_contig.str().size() - opt::read_length; for(vector::const_iterator ot = o.begin(); ot != o.end(); ++ot){ // Reads are used if they don't extend to the end of the consensus if (ot->offset <= (growth-1)){ //Find the correct RotatedRead object and mark it as used vector::iterator rt = lower_bound( rl.begin(), rl.end(), ot->seq); if(rt->seq == ot->seq) rt->used = true; } } /*The sequence returned here contains the original focal read plus any extension The main routine is responsible for trimming back the growing contig */ return new_contig.str(); } // Calculate the tier overlap between two reads static int tier_overlap(const string& seq1, const string& seq2, bool allow_mismatch) { assert(seq1 != seq2); //Find the position of the '$' character in both reads unsigned first_dollar_pos = seq1.find('$'); unsigned second_dollar_pos = seq2.find('$'); unsigned earliest_dollar_pos = first_dollar_pos <= second_dollar_pos ? first_dollar_pos : second_dollar_pos; unsigned latest_dollar_pos = first_dollar_pos > second_dollar_pos ? first_dollar_pos : second_dollar_pos; //If the two strings are equal outside the dollar signs, // return the tier - this is a no-mismatch overlap if( (seq1.substr(0, earliest_dollar_pos) == seq2.substr(0, earliest_dollar_pos)) && (seq1.substr(latest_dollar_pos+1, (opt::read_length+1)-latest_dollar_pos+1) == seq2.substr(latest_dollar_pos+1, (opt::read_length+1)-latest_dollar_pos+1)) ){ return latest_dollar_pos - earliest_dollar_pos; } //Otherwise, if mismatches are allowed, calculate that overlap if (allow_mismatch){ unsigned num_mismatch = 0; for(unsigned i = 0; i < (opt::read_length+1); ++i) { if ((i >= earliest_dollar_pos) && (i <= latest_dollar_pos)){ continue; }else if (seq1[i] != seq2[i]){ num_mismatch++; } } //NOTE: this is also checking that the second read is // DOWNSTREAM from the first if ((num_mismatch <= opt::max_mismatch) && (second_dollar_pos > first_dollar_pos)){ return latest_dollar_pos - earliest_dollar_pos; } } //Otherwise... // NOTE: we're currently defining both "no overlap" // and "no offset but mismatches" as "0" // ==> This could probably be changed return 0; } // From a sorted list of RotatedRead objects, generate a sorted // vector of Rotation objects // This function generates the main vector we traverse when looking // for simple extensions static Rotations generate_rotations_list( const vector& read_list) { // Each rotation has a sequence (string) and overlap (int) // The overlap refers to the overlap between the current sequence // and the next sequence in the list Rotations s; // For each distinct read, add all the rotations to the overlap list for (vector::const_iterator it = read_list.begin(); it != read_list.end(); ++it) for(vector::size_type i = 0; i != (*it).rotations.size(); ++i) // Initialize object with sequence s.push_back(Rotation((*it).rotations[i])); // Sort the list of rotated reads sort(s.begin(), s.end()); // Find the 0-mismatch tier overlap between each pair of reads // in the sorted list for (Rotations::iterator rt = s.begin(); rt != s.end()-1; ++rt) rt->overlap = tier_overlap(rt->seq, rt[1].seq); // Define last entry in the list as 0 s[s.size()-1].overlap = 0; return s; } // Main control flow function int main(int argc, char** argv) { // Parse command-line options 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 'o': arg >> opt::max_overlap; break; case 'm': arg >> opt::max_mismatch; break; case 'c': arg >> opt::min_coverage; break; case 'r': arg >> opt::read_length; 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 (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 1) { cerr << PROGRAM ": too many arguments\n"; die = true; } else if (opt::max_overlap > (opt::read_length-1)){ cerr << PROGRAM ": max_overlap cannot be larger than (read_length-1)\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(1); } const char* fasta_file = argv[optind++]; if(opt::verbose){ cerr << PROGRAM << "\n max_overlap: " << opt::max_overlap << "\n max_mismatch: " << opt::max_mismatch << "\n min_coverage: " << opt::min_coverage << "\n read_length: " << opt::read_length << endl; } // Use the ABySS FastaReader class to read in a fasta file of reads // Assume the first read in the file is the seed for the assembly if(opt::verbose){cerr << "Reading `" << fasta_file << "'... ";} typedef unordered_map ReadMap; ReadMap read_map; bool first_read = true; string contig; FastaReader in(fasta_file, FastaReader::FOLD_CASE); for (FastaRecord rec; in >> rec;) { string read_seq = rec.seq; if (first_read){ contig = read_seq; first_read = false; } // Count the reads as we collect them here... read_map[read_seq]++; } vector read_list; // ... Then put them into the vector of RotatedRead objects for (ReadMap::iterator i = read_map.begin(); i != read_map.end(); ++i) read_list.push_back(RotatedRead(i->first, i->second)); read_map.clear(); sort(read_list.begin(), read_list.end()); if(opt::verbose){cerr << "finished reading fasta file with " << read_list.size() << " distinct reads.\n\n" << endl;} // Generate the sorted lists Rotations rotation_list = generate_rotations_list(read_list); // Main assembly loop if(opt::verbose){cerr << contig << " (seed)" << endl;} bool time_to_die = false; int hard_cap = 0; while(! time_to_die){ // Temporary hard-cap to prevent runaway execution hard_cap++; if (hard_cap >= 500){ time_to_die = true; //cerr << "Hard cap hit - I give up!" << endl; //cerr << contig.size(); // cout << ">contig (" << contig.size() << "bp)" << endl // << contig << endl; //cout << contig.size(); cout << contig << endl; exit(1); } // Another break if the contig grows too long if (contig.size() >= 1500){ //cerr << contig.size(); cout << contig << endl; exit(1); } // Extract the flanking sequence and fetch rotations of that read string flank = contig.substr(contig.size()-opt::read_length); // Retrieve the flanking read vector::iterator low = lower_bound( read_list.begin(), read_list.end(), flank); //TODO - This search sometimes causes a segfault at higher -o values // Figure out why! RotatedRead flank_read = (*low); // If the flank sequence doesn't correspond to a real read: // - generate a temporary RotatedRead object for the complex search if (flank != flank_read.seq){ if (opt::verbose) cerr << "Flank doesn't correspond to a real read" << endl; flank_read = RotatedRead(flank, 1); } bool found_complex_overlap = false; string read_to_add; string extension_seq = find_complex_overlap( flank_read, rotation_list, read_list); if (! (extension_seq == flank_read.seq)){ found_complex_overlap = true; // The new contig = old contig - flank read + extension sequence // (the extension sequence contains the flank read) contig = contig.substr(0, contig.size()-opt::read_length) + extension_seq; // This is very verbose - prints out a fasta sequence for each // step of the assembly process if(opt::verbose){ cout << ">p" << opt::max_overlap << "_" << contig.size() << "bp_complex\n" << contig << endl; } } // If the search fails, stop extension if (! found_complex_overlap){ time_to_die = true; } } // Output the final contig cout << contig << endl; return 0; } abyss-2.2.4/DAssembler/Makefile.am000066400000000000000000000004621361462241400167220ustar00rootroot00000000000000bin_PROGRAMS = DAssembler DAssembler_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer DAssembler_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a DAssembler_SOURCES = DAssembler.cpp \ RotatedRead.cpp RotatedRead.h \ Rotation.h abyss-2.2.4/DAssembler/RotatedRead.cpp000066400000000000000000000010431361462241400175640ustar00rootroot00000000000000#include #include "RotatedRead.h" #include "Sequence.h" using namespace std; //Constructor RotatedRead::RotatedRead(const string& orig_seq, unsigned count) : seq(orig_seq), count(count) { // Add all rotations of the read to the object string appended_seq = orig_seq + '$'; used = false; for(unsigned int i = 0; i < appended_seq.size(); ++i) { string rotated_read = appended_seq.substr(i,(appended_seq.size()-i)) + appended_seq.substr(0,i); rotations.push_back(rotated_read); } } abyss-2.2.4/DAssembler/RotatedRead.h000066400000000000000000000010051361462241400172270ustar00rootroot00000000000000#ifndef ROTATEDREAD_H #define ROTATEDREAD_H 1 #include #include class RotatedRead{ public: RotatedRead(const std::string& orig_seq, unsigned count = 1); bool operator <(const RotatedRead& x) const { return seq < x.seq; } bool operator ==(const RotatedRead& x) const { return seq == x.seq; } std::string seq; std::vector rotations; unsigned count; bool used; }; #endif //ROTATEDREAD_H abyss-2.2.4/DAssembler/Rotation.h000066400000000000000000000007411361462241400166360ustar00rootroot00000000000000#ifndef ROTATION_H #define ROTATION_H 1 #include #include using namespace std; class Rotation { public: Rotation(const string& orig_seq) : seq(orig_seq), overlap(0) { } bool operator <(const Rotation& x) const { return seq < x.seq; } bool operator ==(const Rotation& x) const { return seq == x.seq; } string seq; unsigned overlap; }; #endif //ROTATION_H abyss-2.2.4/DataBase/000077500000000000000000000000001361462241400143075ustar00rootroot00000000000000abyss-2.2.4/DataBase/DB.cc000066400000000000000000000127751361462241400151170ustar00rootroot00000000000000#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 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 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; } abyss-2.2.4/DataBase/DB.h000066400000000000000000000104011361462241400147410ustar00rootroot00000000000000/** * A SQLite3 interface */ #ifndef DB_H #define DB_H 1 #include "Common/InsOrderedMap.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #if _SQL # include #endif typedef std::vector > dbVec; // for output typedef InsOrderedMap dbMap; // for input typedef std::vector 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= 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() { // suppress unused variable warnings under clang++ (void)db; (void)stmt; 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 abyss-2.2.4/DataBase/Makefile.am000066400000000000000000000005411361462241400163430ustar00rootroot00000000000000noinst_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 if HAVE_SQLITE3 bin_PROGRAMS = abyss-db-csv endif 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 abyss-2.2.4/DataBase/Options.h000066400000000000000000000006111361462241400161110ustar00rootroot00000000000000#ifndef OPTIONS_H #define OPTIONS_H 1 #include #include #include 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(command, " ")); command << *last; return command.str(); } } #endif abyss-2.2.4/DataBase/abyss-db-txt000077500000000000000000000012771361462241400165650ustar00rootroot00000000000000#! /bin/bash 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 abyss-2.2.4/DataBase/db-csv.cc000066400000000000000000000047721361462241400160060ustar00rootroot00000000000000/** * Populate SQLite database table(s) and export to CSV */ #include "DB.h" #include 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 vs; static bool existFile(const char* f) { return (bool)ifstream(f); } template static bool existTable( D& db, const string& t) { dbVec v = db.readSqlToVec(TABLE_LIST); unsigned i = 0; while (i 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 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 static void populateAll( D& db, const string& repo) { dbVec v = db.readSqlToVec(TABLE_LIST); for (unsigned i=0; i #include #include class FastaConcat { public: FastaConcat(char** first, char** last, int flags) : m_fail(false), m_flags(flags), m_fileIndex(0), m_reader(NULL) { assert(first != last); for (char** p = first; p != last; p++) m_filenames.push_back(*p); m_reader = new FastaReader( m_filenames.at(m_fileIndex).c_str(), flags); } ~FastaConcat() { if(m_reader != NULL) delete m_reader; } bool eof() const { return m_fileIndex == m_filenames.size(); } /** Return true if all of the streams are still good. */ operator void*() const { return m_fail ? NULL : const_cast(this); } template friend FastaConcat& operator>>( FastaConcat& in, Record& o) { in.m_fail = false; for (; in.m_fileIndex < in.m_filenames.size(); in.m_fileIndex++) { assert(in.m_reader != NULL); *in.m_reader >> o; if (!in.m_reader->fail()) { return in; } else if (in.m_reader->fail() && !in.m_reader->eof()) { in.m_fail = true; return in; } else { delete in.m_reader; in.m_reader = NULL; if (in.m_fileIndex < in.m_filenames.size() - 1) { in.m_reader = new FastaReader( in.m_filenames.at(in.m_fileIndex + 1).c_str(), in.m_flags); } } } // set fail when attempting to read at eof // (like normal iostreams) in.m_fail = true; return in; } private: /** Emulates failbit of iostream */ bool m_fail; /** FastaReader flags */ int m_flags; /** Index of current file */ unsigned m_fileIndex; /** FastaReader for current file */ FastaReader* m_reader; /** List of filenames to read */ std::vector m_filenames; }; #endif abyss-2.2.4/DataLayer/FastaIndex.h000066400000000000000000000101041361462241400167040ustar00rootroot00000000000000#ifndef FASTA_INDEX_H #define FASTA_INDEX_H 1 #include "IOUtil.h" #include #include #include #include #include // for ostream_iterator #include #include /** A record of an indexed FASTA file. */ struct FAIRecord { size_t offset; size_t size; std::string id; FAIRecord() : offset(0), size(0) { } FAIRecord(size_t offset, size_t size, const std::string& id) : offset(offset), size(size), id(id) { } friend std::ostream& operator<<(std::ostream& out, const FAIRecord& o) { return out << o.id << '\t' << o.size << '\t' << o.offset << '\t' << o.size << '\t' << o.size + 1; } friend std::istream& operator>>(std::istream& in, FAIRecord& o) { size_t lineLen, lineBinLen; in >> o.id >> o.size >> o.offset >> lineLen >> lineBinLen; if (!in) return in; assert(o.size == lineLen || lineLen == lineBinLen); return in >> Ignore('\n'); } }; /** An indexed FASTA (fai) file. */ class FastaIndex { typedef std::vector Data; struct CompareOffset { /** Used with upper_bound. */ bool operator()(size_t a, const FAIRecord& b) const { return a < b.offset; } }; public: typedef boost::tuple SeqPos; /** Return the number of contigs. */ size_t size() { return m_data.size(); } /** Return the size of the FASTA file. */ size_t fileSize() const { assert(!m_data.empty()); return m_data.back().offset + m_data.back().size + 1; } typedef Data::const_iterator const_iterator; const_iterator begin() const { return m_data.begin(); } const_iterator end() const { return m_data.end(); } /** Index the specified FASTA file. */ void index(const std::string& path) { m_data.clear(); std::ifstream in(path.c_str()); assert_good(in, path); char c; for (std::string id; in >> c && in >> id && in >> Ignore('\n');) { assert(c == '>'); assert(!id.empty()); std::streampos offset = in.tellg(); assert(offset > 0); in >> Ignore('\n'); size_t n = in.gcount(); assert(n > 0); m_data.push_back(FAIRecord(offset, n - 1, id)); } assert(in.eof()); } /** Translate a file offset to a sequence:position coordinate. */ SeqPos operator[](size_t offset) const { Data::const_iterator it = std::upper_bound( m_data.begin(), m_data.end(), offset, CompareOffset()); assert(it != m_data.begin()); --it; assert(it != m_data.end()); assert(it->offset <= offset); assert(offset < it->offset + it->size); return SeqPos(*it, offset - it->offset); } /** Write FASTA headers to the specified seekable stream. */ void writeFASTAHeaders(std::ostream& out) const { assert(out); if (!out.seekp(0)) return; for (Data::const_iterator it = m_data.begin(); it != m_data.end(); ++it) { out << '>' << it->id << ' '; assert(it->offset > 0); if (!out.seekp(it->offset - 1)) break; out << '\n'; if (!out.seekp(it->offset + it->size)) break; out << '\n'; } } /** Write this index to a stream in SAM format. */ void writeSAMHeader(std::ostream& out) const { for (Data::const_iterator it = m_data.begin(); it != m_data.end(); ++it) out << "@SQ\tSN:" << it->id << "\tLN:" << it->size << '\n'; } /** Write this index to a stream. */ friend std::ostream& operator<<(std::ostream& out, const FastaIndex& o) { std::copy(o.m_data.begin(), o.m_data.end(), std::ostream_iterator(out, "\n")); return out; } /** Read a FASTA index from a stream. */ friend std::istream& operator>>(std::istream& in, FastaIndex& o) { assert(in.good()); o.m_data.clear(); // Count the number of records. if (in.seekg(0, std::ios::beg)) { size_t n = 0; while (in) if (in.get() == '\n') n++; o.m_data.reserve(n); in.clear(); in.seekg(0, std::ios::beg); assert(in.good()); } else in.clear(); // Read the records. for (FAIRecord rec; in >> rec;) { if (!o.m_data.empty()) assert(rec.offset > o.m_data.back().offset); o.m_data.push_back(rec); } assert(in.eof()); assert(!o.m_data.empty()); return in; } private: Data m_data; }; #endif abyss-2.2.4/DataLayer/FastaInterleave.h000066400000000000000000000031371361462241400177430ustar00rootroot00000000000000#ifndef FASTAINTERLEAVE_H #define FASTAINTERLEAVE_H 1 #include "FastaReader.h" #include #include class FastaInterleave { typedef FastaReader Stream; typedef std::vector Streams; public: FastaInterleave(char** first, char** last, int flags) : m_it(m_streams.begin()), m_fail(false) { assert(first != last); m_streams.reserve(last - first); for (char** p = first; p < last; ++p) m_streams.push_back(new Stream(*p, flags)); m_it = m_streams.begin(); } ~FastaInterleave() { for (Streams::iterator it = m_streams.begin(); it != m_streams.end(); ++it) delete *it; } /** Return true if all the streams are eof. */ bool eof() const { for (Streams::const_iterator it = m_streams.begin(); it != m_streams.end(); ++it) if (!(*it)->eof()) return false; return true; } /** Return true if any of the streams are good. */ operator void*() const { return m_fail ? NULL : const_cast(this); } /** Extract one record from the next stream. */ template friend FastaInterleave& operator>>( FastaInterleave& in, Record& o) { for (unsigned i = 0; i < in.m_streams.size(); ++i) { assert(in.m_it != in.m_streams.end()); bool good = **in.m_it >> o; if (++in.m_it == in.m_streams.end()) in.m_it = in.m_streams.begin(); if (good) { in.m_fail = false; return in; } } in.m_fail = true; return in; } private: /** The streams. */ Streams m_streams; /** The next stream from which to read. */ Streams::iterator m_it; /** True when all streams have failed. */ bool m_fail; }; #endif abyss-2.2.4/DataLayer/FastaReader.cpp000066400000000000000000000246501361462241400174050ustar00rootroot00000000000000#include "Common/IOUtil.h" #include "Common/StringUtil.h" #include "DataLayer/FastaReader.h" #include "DataLayer/Options.h" #include #include #include #include #include #include #include using namespace std; namespace opt { /** * Copy the BX tag from the input SAM line to the FASTA/FASTQ comment. * The BX tag contains the linked-reads barcode for the read. * If BX tag is absent, the FASTA/FASTQ comment will be empty. */ int bxTag; /** Discard reads that failed the chastity filter. */ int chastityFilter = 1; /** Trim masked (lower case) characters from the ends of * sequences. */ int trimMasked = 1; /** minimum quality threshold */ int qualityThreshold; /** quality offset, usually 33 or 64 */ int qualityOffset; /** minimum quality for internal bases */ int internalQThreshold; } /** Output an error message. */ ostream& FastaReader::die() { return cerr << m_path << ':' << m_line << ": error: "; } FastaReader::FastaReader(const char* path, int flags, int len) : m_path(path), m_fin(path), m_in(strcmp(path, "-") == 0 ? cin : m_fin), m_flags(flags), m_line(0), m_unchaste(0), m_end(numeric_limits::max()), m_maxLength(len) { if (strcmp(path, "-") != 0) assert_good(m_fin, path); if (m_in.peek() == EOF) cerr << m_path << ':' << m_line << ": warning: " "file is empty\n"; } /** Split the fasta file into nsections and seek to the start * of section. */ void FastaReader::split(unsigned section, unsigned nsections) { assert(nsections >= section); assert(section > 0); assert(strcmp(m_path, "-") != 0); if (nsections == 1) return; // Move the get pointer to the first entry in this section and // update the m_end if there is more than one section. m_in.seekg(0, ios::end); streampos length = m_in.tellg(); assert(length > 0); streampos start = length * (section - 1) / nsections; streampos end = length * section / nsections; assert(end > 0); if (end < length) { m_in.seekg(end); if (m_in.peek() == '>') end += 1; } m_end = end; m_in.seekg(start); if (start > 0) { m_in.ignore(numeric_limits::max(), '\n'); m_in.ignore(numeric_limits::max(), '>'); if (m_in.peek() == EOF) cerr << m_path << ':' << section << ": warning: " "there are no contigs in this section\n"; m_in.putback('>'); } assert(m_end > 0); assert(m_in.good()); } /** Return whether this read passed the chastity filter. */ bool FastaReader::isChaste(const string& s, const string& line) { if (s == "1" || s == "Y") { return true; } else if (s == "0" || s == "N") { return false; } else { die() << "chastity filter should be one of 0, 1, N or Y\n" "and saw `" << s << "' near\n" << line << endl; exit(EXIT_FAILURE); } } /** Check that the seqeuence and quality agree in length. */ void FastaReader::checkSeqQual(const string& s, const string& q) { if (s.length() != q.length()) { die() << "sequence and quality must be the same length near\n" << s << '\n' << q << endl; exit(EXIT_FAILURE); } } /** Return whether the read seq is in colour space. */ static bool isColourSpace(const string& seq) { assert(!seq.empty()); size_t i = seq.find_first_of("ACGTacgt0123", 1); return i != string::npos && isdigit(seq[i]); } /** Read a single record. */ Sequence FastaReader::read(string& id, string& comment, char& anchor, string& q) { next_record: id.clear(); comment.clear(); anchor = 0; q.clear(); // Discard comments. while (m_in.peek() == '#') ignoreLines(1); signed char recordType = m_in.peek(); Sequence s; unsigned qualityOffset = 0; if (recordType == EOF || m_in.tellg() >= m_end) { m_in.seekg(0, ios::end); m_in.clear(std::ios::eofbit | std::ios::failbit); return s; } else if (recordType == '>' || recordType == '@') { // Read the header. string header; getline(header); istringstream headerStream(header); // Ignore SAM headers. if (header[0] == '@' && isalpha(header[1]) && isalpha(header[2]) && header[3] == '\t') goto next_record; headerStream >> recordType >> id >> ws; std::getline(headerStream, comment); // Casava FASTQ format if (comment.size() > 3 && comment[1] == ':' && comment[3] == ':') { // read, chastity, flags, index: 1:Y:0:AAAAAA if (opt::chastityFilter && comment[2] == 'Y') { m_unchaste++; if (recordType == '@') { ignoreLines(3); } else { while (m_in.peek() != '>' && m_in.peek() != '#' && ignoreLines(1)) ; } goto next_record; } if (id.size() > 2 && id.rbegin()[1] != '/') { // Add the read number to the ID. id += '/'; id += comment[0]; } } getline(s); if (recordType == '>') { // Read a multi-line FASTA record. string line; while (m_in.peek() != '>' && m_in.peek() != '#' && getline(line)) s += line; if (m_in.eof()) m_in.clear(); } if (recordType == '@') { char c = m_in.get(); if (c != '+') { string line; getline(line); die() << "expected `+' and saw "; if (m_in.eof()) cerr << "end-of-file\n"; else cerr << "`" << c << "' near\n" << c << line << "\n"; exit(EXIT_FAILURE); } ignoreLines(1); getline(q); } else q.clear(); if (s.empty()) { die() << "sequence with ID `" << id << "' is empty\n"; exit(EXIT_FAILURE); } bool colourSpace = isColourSpace(s); if (colourSpace && !isdigit(s[0])) { // The first character is the primer base. The second // character is the dibase read of the primer and the // first base of the sample, which is not part of the // assembly. assert(s.length() > 2); anchor = colourToNucleotideSpace(s[0], s[1]); s.erase(0, 2); q.erase(0, 1); } if (!q.empty()) checkSeqQual(s, q); if (opt::trimMasked && !colourSpace) { // Removed masked (lower case) sequence at the beginning // and end of the read. size_t trimFront = 0; while (trimFront <= s.length() && islower(s[trimFront])) trimFront++; size_t trimBack = s.length(); while (trimBack > 0 && islower(s[trimBack - 1])) trimBack--; s.erase(trimBack); s.erase(0, trimFront); if (!q.empty()) { q.erase(trimBack); q.erase(0, trimFront); } } if (flagFoldCase()) transform(s.begin(), s.end(), s.begin(), ::toupper); qualityOffset = 33; } else { string line; vector fields; fields.reserve(22); getline(line); istringstream in(line); string field; while (std::getline(in, field, '\t')) fields.push_back(field); if (fields.size() >= 11 && (fields[9].length() == fields[10].length() || fields[10] == "*")) { // SAM unsigned flags = strtoul(fields[1].c_str(), NULL, 0); if (flags & 0x100) // FSECONDARY goto next_record; if (opt::chastityFilter && (flags & 0x200)) { // FQCFAIL m_unchaste++; goto next_record; } id = fields[0]; char which_read = '0'; switch (flags & 0xc1) { // FPAIRED|FREAD1|FREAD2 case 0: case 1: // FPAIRED which_read = '0'; break; case 0x41: // FPAIRED|FREAD1 id += "/1"; which_read = '1'; break; case 0x81: // FPAIRED|FREAD2 id += "/2"; which_read = '2'; break; default: die() << "invalid flags: `" << id << "' near" << line << endl; exit(EXIT_FAILURE); } if (opt::bxTag) { // Copy the linked-reads barcode BX tag to the FASTA comment. for (unsigned i = 11; i < fields.size(); ++i) { if (startsWith(fields[i], "BX:Z:")) { comment = fields[i]; break; } } } else { comment = flags & 0x200 ? "0:Y:0:" : "0:N:0:"; // FQCFAIL comment[0] = which_read; } s = fields[9]; q = fields[10]; if (s == "*") s.clear(); if (q == "*") q.clear(); if (flags & 0x10) { // FREVERSE s = reverseComplement(s); reverse(q.begin(), q.end()); } qualityOffset = 33; if (!q.empty()) checkSeqQual(s, q); } else if (fields.size() == 11 || fields.size() == 22) { // qseq or export if (opt::chastityFilter && !isChaste(fields.back(), line)) { m_unchaste++; goto next_record; } ostringstream o; o << fields[0]; for (int i = 1; i < 6; i++) if (!fields[i].empty()) o << ':' << fields[i]; if (!fields[6].empty() && fields[6] != "0") o << '#' << fields[6]; // The reverse read is typically the second read, but is // the third read of an indexed run. o << '/' << (fields[7] == "3" ? "2" : fields[7]); id = o.str(); comment = fields[7]; comment += isChaste(fields.back(), line) ? ":N:0:" : ":Y:0:"; s = fields[8]; q = fields[9]; qualityOffset = 64; checkSeqQual(s, q); } else { die() << "Expected either `>' or `@' or 11 fields\n" "and saw `" << recordType << "' and " << fields.size() << " fields near\n" << line << endl; exit(EXIT_FAILURE); } } if (opt::qualityOffset > 0) qualityOffset = opt::qualityOffset; // Trim from the 3' end to the maximum length. Then, trim based on // quality. if (m_maxLength > 0) { s.erase(m_maxLength); q.erase(m_maxLength); } static const char ASCII[] = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; if (opt::qualityThreshold > 0 && !q.empty()) { assert(s.length() == q.length()); assert(qualityOffset > (unsigned)ASCII[0]); const char* goodQual = ASCII + (qualityOffset - ASCII[0]) + opt::qualityThreshold; size_t trimFront = q.find_first_of(goodQual); size_t trimBack = q.find_last_of(goodQual) + 1; if (trimFront >= trimBack) { // The entire read is poor quality. s.erase(1); q.erase(1); } else if (trimFront > 0 || trimBack < q.length()) { s.erase(trimBack); s.erase(0, trimFront); q.erase(trimBack); q.erase(0, trimFront); } } if (opt::internalQThreshold > 0 && !q.empty()) { assert(s.length() == q.length()); assert(qualityOffset > (unsigned)ASCII[0]); const char* internalGoodQual = ASCII + (qualityOffset - ASCII[0]) + opt::internalQThreshold; size_t i = 0; while ((i = q.find_first_not_of(internalGoodQual, i)) != string::npos) s[i++] = 'N'; } assert(qualityOffset >= 33); if (flagConvertQual() && qualityOffset != 33) { // Convert to standard quality (ASCII 33). for (string::iterator it = q.begin(); it != q.end(); ++it) { int x = *it - qualityOffset; if (x < -5 || x > 41) { die() << "quality " << x << " is out of range -5 <= q <= 41 near\n" << q << '\n' << string(it - q.begin(), ' ') << "^\n"; exit(EXIT_FAILURE); } *it = 33 + max(0, x); } } return s; } abyss-2.2.4/DataLayer/FastaReader.h000066400000000000000000000110741361462241400170460ustar00rootroot00000000000000#ifndef FASTAREADER_H #define FASTAREADER_H 1 #include "Common/Sequence.h" #include "Common/StringUtil.h" // for chomp #include #include // for exit #include #include #include // for numeric_limits #include /** Read a FASTA, FASTQ, export, qseq or SAM file. */ class FastaReader { public: enum { /** Fold lower-case characters to upper-case. */ FOLD_CASE = 0, NO_FOLD_CASE = 1, /** Convert to standard quality. */ NO_CONVERT_QUALITY = 0, CONVERT_QUALITY = 2, }; bool flagFoldCase() { return ~m_flags & NO_FOLD_CASE; } bool flagConvertQual() { return m_flags & CONVERT_QUALITY; } FastaReader(const char* path, int flags, int len = 0); ~FastaReader() { if (!m_in.eof()) { std::string line; getline(line); die() << "expected end-of-file near\n" << line << '\n'; exit(EXIT_FAILURE); } } Sequence read(std::string& id, std::string& comment, char& anchor, std::string& qual); /** Split the fasta file into nsections and seek to the start * of section. */ void split(unsigned section, unsigned nsections); /** Return whether this stream is at end-of-file. */ bool eof() const { return m_in.eof(); }; /** Return true if failbit or badbit of stream is set. */ bool fail() const { return m_in.fail(); }; /** Return whether this stream is good. */ operator const void*() const { return m_in ? this : NULL; } /** Return the next character of this stream. */ int peek() { return m_in.peek(); } /** Interface for manipulators. */ FastaReader& operator>>(std::istream& (*f)(std::istream&)) { f(m_in); return *this; } /** Returns the number of unchaste reads. */ unsigned unchaste() const { return m_unchaste; } FastaReader& operator >>(Sequence& seq) { std::string id, comment, qual; char anchor; seq = this->read(id, comment, anchor, qual); return *this; } private: /** Read a single line. */ std::istream& getline(std::string& s) { if (std::getline(m_in, s)) { chomp(s, '\r'); m_line++; } return m_in; } /** Ignore the specified number of lines. */ std::istream& ignoreLines(unsigned n) { for (unsigned i = 0; i < n; ++i) { if (m_in.ignore( std::numeric_limits::max(), '\n')) m_line++; } return m_in; } std::ostream& die(); bool isChaste(const std::string& s, const std::string& line); void checkSeqQual(const std::string& s, const std::string& q); const char* m_path; std::ifstream m_fin; std::istream& m_in; /** Flags indicating parsing options. */ int m_flags; /** Number of lines read. */ unsigned m_line; /** Count of unchaste reads. */ unsigned m_unchaste; /** Position of the end of the current section. */ std::streampos m_end; /** Trim sequences to this length. 0 is unlimited. */ const int m_maxLength; }; /** A FASTA record. */ struct FastaRecord { /** Identifier */ std::string id; /** Comment following the first white-space of the header */ std::string comment; /** Anchor base for a colour-space sequence */ char anchor; /** The sequence */ Sequence seq; FastaRecord() : anchor(0) { } FastaRecord(const std::string& id, const std::string& comment, const Sequence& seq) : id(id), comment(comment), anchor(0), seq(seq) { } operator Sequence() const { return seq; } FastaRecord& operator=(const std::string& s) { seq = s; return *this; } size_t size() const { return seq.size(); } friend FastaReader& operator >>(FastaReader& in, FastaRecord& o) { std::string q; o.seq = in.read(o.id, o.comment, o.anchor, q); return in; } friend std::ostream& operator <<(std::ostream& out, const FastaRecord& o) { out << '>' << o.id; if (!o.comment.empty()) out << ' ' << o.comment; return out << '\n' << o.seq << '\n'; } }; /** A FASTQ record. */ struct FastqRecord : FastaRecord { /** Quality */ std::string qual; FastqRecord() { } FastqRecord(const std::string& id, const std::string& comment, const Sequence& seq, const std::string& qual) : FastaRecord(id, comment, seq), qual(qual) { assert(seq.length() == qual.length()); } friend FastaReader& operator >>(FastaReader& in, FastqRecord& o) { o.seq = in.read(o.id, o.comment, o.anchor, o.qual); return in; } friend std::ostream& operator <<(std::ostream& out, const FastqRecord& o) { if (o.qual.empty()) return out << static_cast(o); out << '@' << o.id; if (!o.comment.empty()) out << ' ' << o.comment; return out << '\n' << o.seq << "\n" "+\n" << o.qual << '\n'; } }; #endif //FASTAREADER_H abyss-2.2.4/DataLayer/FastaWriter.cpp000066400000000000000000000034121361462241400174500ustar00rootroot00000000000000#include "FastaWriter.h" #include "Common/Options.h" #include #include #include #include #include // for strerror #include #include // for fsync using namespace std; static inline void die(const string& s) { cerr << "error: writing to `" << s << "': " << strerror(errno) << endl; exit(EXIT_FAILURE); } FastaWriter::FastaWriter(const char* path, bool append) : m_path(path), m_fileHandle(fopen(path, append ? "a" : "w")) { if (m_fileHandle == NULL) die(m_path); } FastaWriter::~FastaWriter() { int n = fsync(fileno(m_fileHandle)); if (n < 0) die(m_path); n = fclose(m_fileHandle); if (n < 0) die(m_path); m_fileHandle = NULL; } void FastaWriter::WriteSequence(const Sequence& seq, unsigned id, unsigned multiplicity, const string& comment) { assert(m_fileHandle != NULL); const char *sep = comment.empty() ? "" : " "; int n = opt::rank < 0 ? fprintf(m_fileHandle, ">%llu %zu %u%s%s\n%s\n", (long long unsigned)id, seq.length(), multiplicity, sep, comment.c_str(), seq.c_str()) : fprintf(m_fileHandle, ">%u:%llu %zu %u%s%s\n%s\n", opt::rank, (long long unsigned)id, seq.length(), multiplicity, sep, comment.c_str(), seq.c_str()); if (n < 0) die(m_path); } void FastaWriter::WriteSequence(const Sequence& seq, unsigned long long id, const std::string& comment) { assert(m_fileHandle != NULL); int n = fprintf(m_fileHandle, ">%llu %s\n%s\n", id, comment.c_str(), seq.c_str()); if (n < 0) die(m_path); } void FastaWriter::WriteSequence(const Sequence& seq, const std::string& id, const std::string& comment) { assert(m_fileHandle != NULL); int n = fprintf(m_fileHandle, ">%s %s\n%s\n", id.c_str(), comment.c_str(), seq.c_str()); if (n < 0) die(m_path); } abyss-2.2.4/DataLayer/FastaWriter.h000066400000000000000000000015341361462241400171200ustar00rootroot00000000000000#ifndef FASTAWRITER_H #define FASTAWRITER_H 1 #include "Common/Sequence.h" #include /** Output a FASTA file. */ class FastaWriter { public: // Constructor opens file FastaWriter(const char* path, bool append = false); // Destructor closes it ~FastaWriter(); /** Write a sequence with a comment. */ void WriteSequence(const Sequence& seq, unsigned id, unsigned multiplicity, const std::string& comment); /** Write a sequence. */ void WriteSequence(const Sequence& seq, unsigned id, unsigned multiplicity) { WriteSequence(seq, id, multiplicity, ""); } void WriteSequence(const Sequence& seq, unsigned long long id, const std::string& comment); void WriteSequence(const Sequence& seq, const std::string& id, const std::string& comment); private: const char *m_path; FILE* m_fileHandle; }; #endif abyss-2.2.4/DataLayer/Makefile.am000066400000000000000000000010751361462241400165500ustar00rootroot00000000000000bin_PROGRAMS = abyss-fac abyss-tofastq noinst_LIBRARIES = libdatalayer.a 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) abyss_tofastq_LDADD = libdatalayer.a \ $(top_builddir)/Common/libcommon.a abyss_tofastq_SOURCES = abyss-tofastq.cc libdatalayer_a_CPPFLAGS = -I$(top_srcdir) libdatalayer_a_SOURCES = \ FastaIndex.h \ FastaInterleave.h \ FastaReader.cpp FastaReader.h \ FastaWriter.cpp FastaWriter.h \ FastaConcat.h \ Options.h abyss-2.2.4/DataLayer/Options.h000066400000000000000000000003611361462241400163150ustar00rootroot00000000000000#ifndef DATALAYER_OPTIONS #define DATALAYER_OPTIONS 1 namespace opt { extern int bxTag; extern int chastityFilter; extern int trimMasked; extern int qualityOffset; extern int qualityThreshold; extern int internalQThreshold; } #endif abyss-2.2.4/DataLayer/abyss-tofastq.cc000066400000000000000000000134671361462241400176330ustar00rootroot00000000000000/** Convert various file formats to FASTQ format. * Written by Shaun Jackman . */ #include "config.h" #include "Common/IOUtil.h" #include "Common/Uncompress.h" #include "DataLayer/FastaInterleave.h" #include "DataLayer/FastaReader.h" #include "DataLayer/Options.h" #include #include #include #include #include #include using namespace std; #define PROGRAM "abyss-tofastq" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [FILE]...\n" "Convert to FASTQ format. The input format may be FASTA, FASTQ,\n" "qseq, export, SAM or BAM format and compressed with gz, bz2 or xz\n" "and may be tarred.\n" "\n" " Options:\n" "\n" " --cat concatenate the records [default]\n" " -i, --interleave interleave the records\n" " --fastq output FASTQ format [default]\n" " --fasta output FASTA format\n" " --bx copy SAM BX tag to output FASTA comment\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" " -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" " -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 { /** Interleave the lines of each file. */ static int interleave; static int toFASTQ = 1; static int verbose; } static const char shortopts[] = "iq:v"; enum { OPT_HELP = 1, OPT_VERSION, OPT_BX }; static const struct option longopts[] = { { "cat", no_argument, &opt::interleave, 0 }, { "interleave", no_argument, &opt::interleave, 1 }, { "fasta", no_argument, &opt::toFASTQ, 0 }, { "fastq", no_argument, &opt::toFASTQ, 1 }, { "bx", no_argument, &opt::bxTag, 1 }, { "chastity", no_argument, &opt::chastityFilter, 1 }, { "no-chastity", no_argument, &opt::chastityFilter, 0 }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "trim-quality", required_argument, NULL, 'q' }, { "standard-quality", no_argument, &opt::qualityOffset, 33 }, { "illumina-quality", no_argument, &opt::qualityOffset, 64 }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** FastaReader flags. */ static const int FASTAREADER_FLAGS = FastaReader::NO_FOLD_CASE | FastaReader::CONVERT_QUALITY; /** Total count. */ static struct { unsigned records; unsigned characters; } g_total; template static void convert(const char* path) { FastaReader in(path, FASTAREADER_FLAGS); unsigned records = 0, characters = 0; for (Record record; in >> record;) { cout << record; assert_good(cout, "stdout"); records++; characters += record.seq.size(); } assert(in.eof()); g_total.records += records; g_total.characters += characters; if (opt::verbose) cerr << records << '\t' << characters << '\t' << path << '\n'; } /** Interleave the records. */ template static void interleave(char** first, char** last) { FastaInterleave in(first, last, FASTAREADER_FLAGS); unsigned records = 0, characters = 0; for (Record record; in >> record;) { cout << record; assert_good(cout, "stdout"); records++; characters += record.seq.size(); } assert(in.eof()); g_total.records += records; g_total.characters += characters; } int main(int argc, char** argv) { opt::trimMasked = false; if (string(argv[0]).find("tofasta") != string::npos) opt::toFASTQ = false; 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 'i': opt::interleave = true; break; case 'q': arg >> opt::qualityThreshold; break; case 'v': opt::verbose++; break; case OPT_BX: opt::bxTag = true; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } typedef void (*F)(const char*); F convertFasta = convert; F convertFastq = convert; F f = opt::toFASTQ ? convertFastq : convertFasta; if (optind == argc) { f("-"); } else if (!opt::interleave || argc - optind == 1) { // Concatenate. for_each(argv + optind, argv + argc, f); } else { // Interleave. if (opt::toFASTQ) interleave(argv + optind, argv + argc); else interleave(argv + optind, argv + argc); } if (opt::verbose && argc - optind > 1) cerr << g_total.records << '\t' << g_total.characters << '\t' << "total\n"; cout.flush(); assert_good(cout, "stdout"); return 0; } abyss-2.2.4/DataLayer/fac.cc000066400000000000000000000140631361462241400155550ustar00rootroot00000000000000/** Calculate assembly contiguity statistics. * Written by Shaun Jackman . */ #include "config.h" #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 #include #include #include using namespace std; #define PROGRAM "abyss-fac" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [FILE]...\n" "Calculate assembly contiguity statistics.\n" "\n" " Options:\n" "\n" " -G, -e, --genome-size=N expected genome size. Used to calculate NG50\n" " and associated stats [disabled]\n" " -s, -t, --min-length=N ignore sequences shorter than N bp [500]\n" " -d, --delimiter=S use S for the field delimiter [\\t]\n" " -j, --jira output JIRA format\n" " -m, --mmd output MultiMarkdown format\n" " --chastity discard unchaste sequences [default]\n" " --no-chastity do not discard unchaste sequences\n" " --trim-masked trim masked bases from the end\n" " --no-trim-masked do not trim masked bases from the ends\n" " of sequences [default]\n" " --count-ambig count ambiguity codes in sequences\n" " --no-count-ambig do not count ambiguity codes in sequences [default]\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 { static unsigned minLength = 500; static long long unsigned genomeSize; static string delimiter = "\t"; static int format; static int verbose; static int countAmbig; } enum { TAB, JIRA, MMD }; static const char shortopts[] = "d:e:G:jms:t:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "genome-size", required_argument, NULL, 'G' }, { "min-length", no_argument, NULL, 's' }, { "delimiter", required_argument, NULL, 'd' }, { "jira", no_argument, NULL, 'j' }, { "mmd", no_argument, NULL, 'm' }, { "chastity", no_argument, &opt::chastityFilter, 1 }, { "no-chastity", no_argument, &opt::chastityFilter, 0 }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "count-ambig", no_argument, &opt::countAmbig, 1 }, { "no-count-ambig", no_argument, &opt::countAmbig, 0 }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** FastaReader flags. */ static const int FASTAREADER_FLAGS = FastaReader::NO_FOLD_CASE; /** Print contiguity statistics. */ static void printContiguityStatistics(const char* path) { static bool printHeader = true; if (string(path) == "---") { if (printHeader == false) cout << '\n'; printHeader = true; return; } // Read the sequences and count the lengths. Histogram h; FastaReader in(path, FASTAREADER_FLAGS); for (string s; in >> s;) h.insert(opt::countAmbig ? s.length() : count_if(s.begin(), s.end(), isACGT)); assert(in.eof()); // Print the table header. if (opt::format == JIRA && printHeader) { printHeader = false; const char* sep = "\t||"; cout << "||" << "n" << sep << "n:" << opt::minLength << sep << "L50" << sep; if (opt::genomeSize > 0) cout << "n:NG50" << sep << "NG50" << sep; cout << "min" << sep << "N75" << sep << "N50" << sep << "N25" << sep << "E-size" << sep << "max" << sep << "sum" << sep << "name" << sep << '\n'; } else if (opt::format == MMD && printHeader) { printHeader = false; const char* sep = "\t|"; cout << "n" << sep << "n:" << opt::minLength << sep << "L50" << sep; if (opt::genomeSize > 0) cout << "n:NG50" << sep << "NG50" << sep; cout << "min" << sep << "N75" << sep << "N50" << sep << "N25" << sep << "E-size" << sep << "max" << sep << "sum" << sep << "name" << '\n'; if (opt::genomeSize > 0) cout << "------" << sep << "------" << sep; cout << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << sep << "------" << '\n'; } // Print the table. if (opt::format == JIRA) cout << '|'; printContiguityStats(cout, h, opt::minLength, printHeader, opt::delimiter, opt::genomeSize) << opt::delimiter << path; if (opt::format == JIRA) cout << opt::delimiter; cout << endl; printHeader = false; } int main(int argc, char** argv) { opt::trimMasked = false; 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 'd': opt::delimiter = arg.str(); arg.clear(ios::eofbit); break; case 'j': opt::delimiter = "\t|"; opt::format = JIRA; break; case 'm': opt::delimiter = "\t|"; opt::format = MMD; break; case 'G': case 'e': { double x; arg >> x; opt::genomeSize = x; break; } case 's': case 't': arg >> opt::minLength; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (optind == argc) printContiguityStatistics("-"); else for_each(argv + optind, argv + argc, printContiguityStatistics); cout.flush(); assert_good(cout, "stdout"); return 0; } abyss-2.2.4/DistanceEst/000077500000000000000000000000001361462241400150515ustar00rootroot00000000000000abyss-2.2.4/DistanceEst/DistanceEst.cpp000066400000000000000000000477161361462241400200020ustar00rootroot00000000000000#include "Estimate.h" #include "Histogram.h" #include "IOUtil.h" #include "MLE.h" #include "PMF.h" #include "SAM.h" #include "Uncompress.h" #include "Graph/Options.h" // for opt::k #include #include #include #include #include #include #include #include #include #include // for numeric_limits #include #if _OPENMP # include #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" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -s -n [OPTION]... HIST [PAIR]\n" "Estimate distances between contigs using paired-end alignments.\n" "\n" " Arguments:\n" "\n" " HIST distribution of fragments size\n" " PAIR alignments between contigs\n" "\n" " Options:\n" "\n" " --mind=N minimum distance between contigs [-(k-1)]\n" " --maxd=N maximum distance between contigs\n" " --fr force the orientation to forward-reverse\n" " --rf force the orientation to reverse-forward\n" " -k, --kmer=N set --mind to -(k-1) bp\n" " -l, --min-align=N the minimal alignment size [1]\n" " -n, --npairs=NPAIRS minimum number of pairs\n" " -s, --seed-length=L minimum length of the seed contigs\n" " -q, --min-mapq=N ignore alignments with mapping quality\n" " less than this threshold [10]\n" " -o, --out=FILE write result to FILE\n" " --mle use the MLE [default]\n" " (maximum likelihood estimator)\n" " --median use the difference of the population median\n" " and the sample median\n" " --mean use the difference of the population mean\n" " and the sample mean\n" " --dist output the graph in dist format [default]\n" " --dot output the graph in GraphViz format\n" " --gv output the graph in GraphViz format\n" " --gfa output the graph in GFA2 format\n" " --gfa2 output the graph in GFA2 format\n" " -j, --threads=N use N parallel threads [1]\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"; /** Which estimator to use. See opt::method. */ enum { MLE, MEAN, MEDIAN }; namespace opt { string db; dbVars metaVars; unsigned k; // used by Estimate.h /** Output graph format. */ int format = DIST; /** Minimum distance between contigs. */ static int minDist = numeric_limits::min(); /** Maximum distance between contigs. */ static int maxDist = numeric_limits::max(); static unsigned seedLen; static unsigned npairs; static unsigned minMapQ = 10; /** Reverse-forward mate pair orientation. */ static int rf = -1; /** Which estimator to use. */ static int method = MLE; static int verbose; static string out; static int threads = 1; } 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_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, }, { "dot", no_argument, &opt::format, DOT, }, { "gv", no_argument, &opt::format, DOT, }, { "gfa", no_argument, &opt::format, GFA2, }, { "gfa2", no_argument, &opt::format, GFA2, }, { "fr", no_argument, &opt::rf, false }, { "rf", no_argument, &opt::rf, true }, { "min-align", required_argument, NULL, 'l' }, { "mind", required_argument, NULL, OPT_MIND }, { "maxd", required_argument, NULL, OPT_MAXD }, { "mle", no_argument, &opt::method, MLE }, { "median", no_argument, &opt::method, MEDIAN }, { "mean", no_argument, &opt::method, MEAN }, { "kmer", required_argument, NULL, 'k' }, { "npairs", required_argument, NULL, 'n' }, { "out", required_argument, NULL, 'o' }, { "min-mapq", required_argument, NULL, 'q' }, { "seed-length", required_argument, NULL, 's' }, { "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 } }; /** A collection of aligned read pairs. */ typedef vector Pairs; /** Estimate the distance between two contigs using the difference of * the population mean and the sample mean. * @param numPairs [out] the number of pairs that agree with the * expected distribution * @return the estimated distance */ static int estimateDistanceUsingMean( const std::vector& samples, const PMF& pmf, unsigned& numPairs) { Histogram h(samples.begin(), samples.end()); int d = (int)round(pmf.mean() - h.mean()); // Count the number of samples that agree with the distribution. unsigned n = 0; for (Histogram::const_iterator it = h.begin(); it != h.end(); ++it) if (pmf[it->first + d] > pmf.minProbability()) n += it->second; numPairs = n; return d; } /** Estimate the distance between two contigs using the difference of * the population median and the sample median. * @param numPairs [out] the number of pairs that agree with the * expected distribution * @return the estimated distance */ static int estimateDistanceUsingMedian( const std::vector& samples, const PMF& pmf, unsigned& numPairs) { Histogram h(samples.begin(), samples.end()); int d = (int)round(pmf.median() - h.median()); // Count the number of samples that agree with the distribution. unsigned n = 0; for (Histogram::const_iterator it = h.begin(); it != h.end(); ++it) if (pmf[it->first + d] > pmf.minProbability()) n += it->second; numPairs = n; return d; } /** Global variable to track a recommended minAlign parameter */ unsigned g_recMA; static struct { /* Fragment stats are considered only for fragments aligning * to different contigs, and where the contig is >=opt::seedLen. */ unsigned total_frags; unsigned dup_frags; } stats; /** Estimate the distance between two contigs. * @param numPairs [out] the number of pairs that agree with the * expected distribution * @return the estimated distance */ static int estimateDistance(unsigned len0, unsigned len1, const Pairs& pairs, const PMF& pmf, unsigned& numPairs) { // The provisional fragment sizes are calculated as if the contigs // were perfectly adjacent with no overlap or gap. typedef vector > Fragments; Fragments fragments; fragments.reserve(pairs.size()); for (Pairs::const_iterator it = pairs.begin(); it != pairs.end(); ++it) { int a0 = it->targetAtQueryStart(); int a1 = it->mateTargetAtQueryStart(); if (it->isReverse()) a0 = len0 - a0; if (!it->isMateReverse()) a1 = len1 - a1; fragments.push_back(opt::rf ? make_pair(a1, len1 + a0) : make_pair(a0, len0 + a1)); } // Remove duplicate fragments. unsigned orig = fragments.size(); sort(fragments.begin(), fragments.end()); fragments.erase(unique(fragments.begin(), fragments.end()), fragments.end()); numPairs = fragments.size(); assert((int)orig - (int)numPairs >= 0); stats.total_frags += orig; stats.dup_frags += orig - numPairs; if (numPairs < opt::npairs) return INT_MIN; vector fragmentSizes; fragmentSizes.reserve(fragments.size()); unsigned ma = opt::minAlign; for (Fragments::const_iterator it = fragments.begin(); it != fragments.end(); ++it) { int x = it->second - it->first; if (!opt::rf && opt::method == MLE && x <= 2 * int(ma - 1)) { unsigned align = x / 2; if (opt::verbose > 0) #pragma omp critical(cerr) cerr << PROGRAM ": warning: The observed fragment of " "size " << x << " bp is shorter than 2*l " "(l=" << opt::minAlign << ").\n"; ma = min(ma, align); } fragmentSizes.push_back(x); } #pragma omp critical(g_recMA) g_recMA = min(g_recMA, ma); switch (opt::method) { case MLE: // Use the maximum likelihood estimator. return maximumLikelihoodEstimate(ma, opt::minDist, opt::maxDist, fragmentSizes, pmf, len0, len1, opt::rf, numPairs); case MEAN: // Use the difference of the population mean // and the sample mean. return estimateDistanceUsingMean( fragmentSizes, pmf, numPairs); case MEDIAN: // Use the difference of the population median // and the sample median. return estimateDistanceUsingMedian( fragmentSizes, pmf, numPairs); default: assert(false); abort(); } } static void writeEstimate(ostream& out, const ContigNode& id0, const ContigNode& id1, unsigned len0, unsigned len1, const Pairs& pairs, const PMF& pmf) { if (pairs.size() < opt::npairs) return; DistanceEst est; est.distance = estimateDistance(len0, len1, pairs, pmf, est.numPairs); est.stdDev = pmf.getSampleStdDev(est.numPairs); std::pair e(id0, id1 ^ id0.sense()); if (est.numPairs >= opt::npairs) { if (opt::format == DOT) { #pragma omp critical(out) out << get(g_contigNames, e) << " [" << est << "]\n"; } else if (opt::format == GFA2) { // Output only one of the two complementary edges. if (len1 < opt::seedLen || e.first < e.second || e.first == e.second) #pragma omp critical(out) out << "G\t*" << '\t' << get(g_contigNames, e.first) << '\t' << get(g_contigNames, e.second) << '\t' << est.distance << '\t' << (int)ceilf(est.stdDev) << "\tFC:i:" << est.numPairs << '\n'; } else out << ' ' << get(g_contigNames, id1) << ',' << est; } else if (opt::verbose > 1) { #pragma omp critical(cerr) cerr << "warning: " << get(g_contigNames, e) << " [d=" << est.distance << "] " << est.numPairs << " of " << pairs.size() << " pairs fit the expected distribution\n"; } } /** Generate distance estimates for the specified alignments. */ static void writeEstimates(ostream& out, const vector& pairs, const vector& lengthVec, const PMF& pmf) { assert(!pairs.empty()); ContigID id0(get(g_contigNames, pairs.front().rname)); assert(id0 < lengthVec.size()); unsigned len0 = lengthVec[id0]; if (len0 < opt::seedLen) return; // Skip contigs shorter than the seed length. ostringstream ss; if (opt::format == DIST) ss << pairs.front().rname; typedef map PairsMap; PairsMap dataMap[2]; for (Pairs::const_iterator it = pairs.begin(); it != pairs.end(); ++it) dataMap[it->isReverse()][find_vertex( it->mrnm, it->isReverse() == it->isMateReverse(), g_contigNames)] .push_back(*it); for (int sense0 = false; sense0 <= true; sense0++) { if (opt::format == DIST && sense0) ss << " ;"; const PairsMap& x = dataMap[sense0 ^ opt::rf]; for (PairsMap::const_iterator it = x.begin(); it != x.end(); ++it) writeEstimate(opt::format == DIST ? ss : out, ContigNode(id0, sense0), it->first, len0, lengthVec[it->first.id()], it->second, pmf); } if (opt::format == DIST) #pragma omp critical(out) out << ss.str() << '\n'; assert(out.good()); } /** Load a histogram from the specified file. */ static Histogram loadHist(const string& path) { ifstream in(path.c_str()); assert_good(in, path); Histogram hist; in >> hist; assert(in.eof()); if (hist.empty()) { cerr << "error: the histogram `" << path << "' is empty\n"; exit(EXIT_FAILURE); } return hist; } /** Copy records from [it, last) to out and stop before alignments to * the next target sequence. * @param[in,out] it an input iterator */ template static void readPairs(It& it, const It& last, vector& out) { assert(out.empty()); for (; it != last; ++it) { if (it->isUnmapped() || it->isMateUnmapped() || !it->isPaired() || it->rname == it->mrnm || it->mapq < opt::minMapQ) continue; if (!out.empty() && out.back().rname != it->rname) break; out.push_back(*it); SAMRecord& sam = out.back(); // Clear unused fields. sam.qname.clear(); #if SAM_SEQ_QUAL sam.seq.clear(); sam.qual.clear(); #endif } // Check that the input is sorted. if (it != last && !out.empty() && get(g_contigNames, it->rname) < get(g_contigNames, out.front().rname)) { cerr << "error: input must be sorted: saw `" << out.front().rname << "' before `" << it->rname << "'\n"; exit(EXIT_FAILURE); } } 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case OPT_MIND: arg >> opt::minDist; break; case OPT_MAXD: arg >> opt::maxDist; break; case 'l': arg >> opt::minAlign; break; case 'j': arg >> opt::threads; break; case 'k': arg >> opt::k; break; case 'n': arg >> opt::npairs; break; case 'o': arg >> opt::out; break; case 'q': arg >> opt::minMapQ; break; case 's': arg >> opt::seedLen; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (opt::seedLen <= 0) { cerr << PROGRAM ": missing -s,--seed-length option\n"; die = true; } if (opt::npairs <= 0) { cerr << PROGRAM ": missing -n,--npairs option\n"; die = true; } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (opt::seedLen < 2*opt::k) cerr << "warning: the seed-length should be at least twice k:" " k=" << opt::k << ", s=" << opt::seedLen << '\n'; assert(opt::minAlign > 0); #if _OPENMP if (opt::threads > 0) 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++]); ifstream inFile(alignFile.c_str()); istream& in(strcmp(alignFile.c_str(), "-") == 0 ? cin : inFile); if (strcmp(alignFile.c_str(), "-") != 0) assert_good(inFile, alignFile); ofstream outFile; if (!opt::out.empty()) { outFile.open(opt::out.c_str()); assert(outFile.is_open()); } ostream& out = opt::out.empty() ? cout : outFile; if (opt::format == DOT) out << "digraph dist {\ngraph [" "k=" << opt::k << " " "s=" << opt::seedLen << " " "n=" << opt::npairs << "]\n"; else if (opt::format == GFA2) out << "H\tVN:Z:2.0\n"; vector vals = make_vector() << opt::k << opt::seedLen << opt::npairs; vector keys = make_vector() << "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(); // Read the fragment size distribution. Histogram distanceHist = loadHist(distanceCountFile); unsigned numRF = distanceHist.count(INT_MIN, 0); unsigned numFR = distanceHist.count(1, INT_MAX); unsigned numTotal = distanceHist.size(); bool libRF = numFR < numRF; if (opt::verbose > 0) { cerr << "Mate orientation FR: " << numFR << setprecision(3) << " (" << (float)100*numFR/numTotal << "%)" << " RF: " << numRF << setprecision(3) << " (" << (float)100*numRF/numTotal << "%)\n" << "The library " << distanceCountFile << " is oriented " << (libRF ? "reverse-forward (RF)" : "forward-reverse (FR)") << ".\n"; } vals += make_vector() << numFR << numRF; keys += make_vector() << "FR_orientation" << "RF_orientation"; // Determine the orientation of the library. if (opt::rf == -1) opt::rf = libRF; if (opt::rf) distanceHist = distanceHist.negate(); if (opt::rf != libRF) cerr << "warning: The orientation is forced to " << (opt::rf ? "reverse-forward (RF)" : "forward-reverse (FR)") << " which differs from the detected orientation.\n"; distanceHist.eraseNegative(); distanceHist.removeNoise(); distanceHist.removeOutliers(); Histogram h = distanceHist.trimFraction(0.0001); if (opt::verbose > 0) cerr << "Stats mean: " << setprecision(4) << h.mean() << " " "median: " << setprecision(4) << h.median() << " " "sd: " << setprecision(4) << h.sd() << " " "n: " << h.size() << " " "min: " << h.minimum() << " max: " << h.maximum() << '\n' << h.barplot() << endl; PMF pmf(h); if (opt::minDist == numeric_limits::min()) opt::minDist = -opt::k + 1; if (opt::maxDist == numeric_limits::max()) opt::maxDist = pmf.maxValue(); if (opt::verbose > 0) cerr << "Minimum and maximum distance are set to " << opt::minDist << " and " << opt::maxDist << " bp.\n"; assert(opt::minDist < opt::maxDist); vals += make_vector() << opt::minDist << opt::maxDist << (int)round(h.mean()) << h.median() << (int)round(h.sd()) << h.size() << h.minimum() << h.maximum(); keys += make_vector() << "minDist" << "maxDist" << "mean" << "median" << "sd" << "n" << "min" << "max"; // Read the contig lengths. vector contigLens; vals += make_vector() << readContigLengths(in, contigLens); keys += make_vector() << "CntgCounted"; // readContigLengths(in, contigLens); g_contigNames.lock(); // Estimate the distances between contigs. istream_iterator it(in), last; if (contigLens.size() == 1) { // When mapping to a single contig, no alignments spanning // contigs are expected. assert(in.eof()); exit(EXIT_SUCCESS); } assert(in); g_recMA = opt::minAlign; #pragma omp parallel for (vector records;;) { records.clear(); #pragma omp critical(in) readPairs(it, last, records); if (records.empty()) break; writeEstimates(out, records, contigLens, pmf); } if (opt::verbose > 0) { float prop_dups = (float)100 * stats.dup_frags / stats.total_frags; cerr << "Duplicate rate of spanning fragments: " << stats.dup_frags << "/" << stats.total_frags << " (" << setprecision(3) << prop_dups << "%)\n"; if (prop_dups > 50) cerr << PROGRAM << ": warning: duplicate rate of fragments " "spanning more than one contig is high.\n"; } vals += make_vector() << stats.total_frags << stats.dup_frags; keys += make_vector() << "total_frags" << "dupl_frags"; if (!opt::db.empty()) { for (unsigned i=0; i 0 && g_recMA != opt::minAlign) cerr << PROGRAM << ": warning: MLE will be more accurate if " "l is decreased to " << g_recMA << ".\n"; assert(in.eof()); if (opt::format == DOT) out << "}\n"; return 0; } abyss-2.2.4/DistanceEst/MLE.cpp000066400000000000000000000130651361462241400161770ustar00rootroot00000000000000#include "MLE.h" #include "PMF.h" #include #include // for swap #include #include // for numeric_limits #include using namespace std; using boost::tie; /** This window function is a triangle with a flat top, or a rectangle * with sloped sides. */ class WindowFunction { public: WindowFunction(int len0, int len1) : x1(len0), x2(len1), x3(len0 + len1) { assert(len0 > 0); assert(len1 > 0); assert(len0 <= len1); } /** Return this window function evaluated at x. */ double operator()(int x) const { return (x <= 0 ? 1 : x < x1 ? x : x < x2 ? x1 : x < x3 ? x3 - x : 1) / (double)x1; } private: /** Parameters of this window function. */ 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) * @param samples the samples * @param pmf the probability mass function * @return the log likelihood */ static pair computeLikelihood(int theta, const Histogram& samples, const PMF& pmf) { double likelihood = 0; unsigned nsamples = 0; for (Histogram::const_iterator it = samples.begin(); it != samples.end(); ++it) { double p = pmf[it->first + theta]; unsigned n = it->second; likelihood += n * log(p); if (p > pmf.minProbability()) nsamples += n; } return make_pair(likelihood, nsamples); } /** Return the most likely distance between two contigs and the number * of pairs that support that estimate. */ static pair maximumLikelihoodEstimate(int first, int last, const Histogram& samples, const PMF& pmf, unsigned len0, unsigned len1) { 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 * shorter fragments. */ WindowFunction window(len0, len1); unsigned nsamples = samples.size(); double bestLikelihood = -numeric_limits::max(); int bestTheta = first; unsigned bestn = 0; vector le; vector le_n; vector le_theta; for (int theta = first; theta <= last; theta++) { // Calculate the normalizing constant of the PMF, f_theta(x). double c = 0; for (int i = pmf.minValue(); i <= (int)pmf.maxValue(); ++i) c += pmf[i] * window(i - theta); double likelihood; unsigned n; tie(likelihood, n) = computeLikelihood(theta, samples, pmf); likelihood -= nsamples * log(c); 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 = le_theta[i]; bestn = le_n[i]; } } return make_pair(bestTheta, bestn); } /** Return the most likely distance between two contigs and the number * of pairs that support that distance estimate. * @param len0 the length of the first contig in bp * @param len1 the length of the second contig in bp * @param rf whether the fragment library is oriented reverse-forward * @param[out] n the number of samples with a non-zero probability */ int maximumLikelihoodEstimate(unsigned l, int first, int last, const vector& samples, const PMF& pmf, unsigned len0, unsigned len1, bool rf, unsigned& n) { assert(first < last); assert(!samples.empty()); // The aligner is unable to map reads to the ends of the sequence. // Correct for this lack of sensitivity by subtracting l-1 bp from // the length of each sequence, where the aligner requires a match // of at least l bp. When the fragment library is oriented // forward-reverse, subtract 2*(l-1) from each sample. assert(l > 0); assert(len0 >= l); assert(len1 >= l); len0 -= l - 1; len1 -= l - 1; if (len0 > len1) swap(len0, len1); if (rf) { // This library is oriented reverse-forward. Histogram h(samples.begin(), samples.end()); int d; tie(d, n) = maximumLikelihoodEstimate( first, last, h, pmf, len0, len1); return d; } else { // This library is oriented forward-reverse. // Subtract 2*(l-1) from each sample. Histogram h; typedef vector Samples; for (Samples::const_iterator it = samples.begin(); it != samples.end(); ++it) { assert(*it > 2 * (int)(l - 1)); h.insert(*it - 2 * (l - 1)); } int d; tie(d, n) = maximumLikelihoodEstimate( first, last, h, pmf, len0, len1); return max(first, d - 2 * (int)(l - 1)); } } abyss-2.2.4/DistanceEst/MLE.h000066400000000000000000000003611361462241400156370ustar00rootroot00000000000000#ifndef MLE_H #define MLE_H 1 #include class PMF; int maximumLikelihoodEstimate(unsigned k, int first, int last, const std::vector& samples, const PMF& pmf, unsigned len0, unsigned len1, bool rf, unsigned& n); #endif abyss-2.2.4/DistanceEst/Makefile.am000066400000000000000000000010521361462241400171030ustar00rootroot00000000000000bin_PROGRAMS = DistanceEst DistanceEst-ssq DistanceEst_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common 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 DistanceEst_ssq_CPPFLAGS = $(DistanceEst_CPPFLAGS) \ -D SAM_SEQ_QUAL=1 DistanceEst_ssq_CXXFLAGS = $(DistanceEst_CXXFLAGS) DistanceEst_ssq_LDADD = $(DistanceEst_LDADD) DistanceEst_ssq_SOURCES = $(DistanceEst_SOURCES) abyss-2.2.4/Dockerfile000066400000000000000000000014221361462241400146340ustar00rootroot00000000000000FROM ubuntu:18.04 MAINTAINER Shaun Jackman RUN apt-get update \ && apt-get install -y --no-install-recommends \ bsdmainutils libgomp1 make openmpi-bin ssh sudo \ && useradd -m -s /bin/bash abyss \ && echo 'abyss ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers ADD . /tmp/abyss RUN apt-get install -y --no-install-recommends \ automake g++ libboost-dev libopenmpi-dev libsparsehash-dev \ && cd /tmp/abyss \ && ./autogen.sh \ && mkdir build && cd build \ && ../configure --with-mpi=/usr/lib/x86_64-linux-gnu/openmpi \ && make install-strip \ && rm -rf /tmp/abyss \ && apt-get autoremove -y binutils \ automake g++ libboost-dev libopenmpi-dev libsparsehash-dev USER abyss WORKDIR /home/abyss ENV SHELL=/bin/bash USER=abyss ENTRYPOINT ["abyss-pe"] CMD ["help"] abyss-2.2.4/FMIndex/000077500000000000000000000000001361462241400141355ustar00rootroot00000000000000abyss-2.2.4/FMIndex/BitArrays.h000066400000000000000000000052071361462241400162120ustar00rootroot00000000000000#ifndef BITARRAYS_H #define BITARRAYS_H 1 #include "bit_array.h" #include #include #include #include #include // for numeric_limits #include #include #include /** Store a string of symbols from a small alphabet using a vector of * BitArray. */ class BitArrays { /** A symbol. */ typedef uint8_t T; /** The sentinel symbol. */ static T SENTINEL() { return std::numeric_limits::max(); } public: /** Count the occurrences of the symbols of [first, last). */ template void assign(It first, It last) { assert(first < last); m_data.clear(); // Determine the size of the alphabet ignoring the sentinel. T n = 0; for (It it = first; it != last; ++it) if (*it != SENTINEL()) n = std::max(n, *it); n++; assert(n < std::numeric_limits::max()); m_data.resize(n, wat_array::BitArray(last - first)); size_t i = 0; for (It it = first; it != last; ++it, ++i) { T c = *it; if (c == SENTINEL()) continue; assert(c < m_data.size()); m_data[c].SetBit(1, i); } std::for_each( m_data.begin(), m_data.end(), [](wat_array::BitArray& b) { return b.Build(); }); } /** Return the size of the string. */ size_t size() const { assert(!m_data.empty()); return m_data.front().length(); } /** Return the number of occurrences of the specified symbol. */ size_t count(T c) const { return m_data[c].one_num(); } /** Return the count of symbol c in s[0, i). */ size_t rank(T c, size_t i) const { return m_data[c].Rank(1, i); } /** Return the symbol at the specified position. */ T at(size_t i) const { assert(!m_data.empty()); assert(i < m_data.front().length()); for (Data::const_iterator it = m_data.begin(); it != m_data.end(); ++it) if (it->Lookup(i)) return it - m_data.begin(); return std::numeric_limits::max(); } /** Store this data structure. */ friend std::ostream& operator<<(std::ostream& out, const BitArrays& o) { uint32_t n = o.m_data.size(); out.write(reinterpret_cast(&n), sizeof n); for (Data::const_iterator it = o.m_data.begin(); it != o.m_data.end(); ++it) it->Save(out); return out; } /** Load this data structure. */ friend std::istream& operator>>(std::istream& in, BitArrays& o) { o.m_data.clear(); uint32_t n = 0; if (!in.read(reinterpret_cast(&n), sizeof n)) return in; assert(n > 0); assert(n < std::numeric_limits::max()); o.m_data.resize(n); for (Data::iterator it = o.m_data.begin(); it != o.m_data.end(); ++it) it->Load(in); return in; } private: typedef std::vector Data; Data m_data; }; #endif abyss-2.2.4/FMIndex/DAWG.h000066400000000000000000000071351361462241400150360ustar00rootroot00000000000000/* Directed acyclic word graph. */ #ifndef DAWG_H #define DAWG_H 1 #include "FMIndex.h" #include #include #include // for distance #include #include using boost::graph_traits; /** An FM-index is a representation of a DAWG. */ typedef FMIndex DAWG; // Graph namespace boost { template <> struct graph_traits { typedef DAWG::size_type size_type; // Graph typedef std::pair vertex_descriptor; typedef boost::directed_tag directed_category; struct traversal_category : boost::incidence_graph_tag { }; typedef boost::disallow_parallel_edge_tag edge_parallel_category; // IncidenceGraph typedef std::pair edge_descriptor; typedef unsigned degree_size_type; // VertexListGraph /** Vertex iterator. */ struct vertex_iterator : public vertex_descriptor { vertex_iterator() : vertex_descriptor(0, 0) { } vertex_iterator(size_type l, size_type u) : vertex_descriptor(l, u) { } vertex_descriptor operator*() const { return *this; }; }; // IncidenceGraph /** Out edge iterator. */ class out_edge_iterator : public std::iterator { public: out_edge_iterator() : m_g(NULL), m_u(), m_v(), m_i(0) { } out_edge_iterator(const DAWG& g, vertex_descriptor u, degree_size_type i) : m_g(&g), m_u(u), m_v(), m_i(i) { next(); } edge_descriptor operator*() const { return edge_descriptor(m_u, m_v); } bool operator==(const out_edge_iterator& it) const { return m_g == it.m_g && m_u == it.m_u && m_i == it.m_i; } bool operator!=(const out_edge_iterator& it) const { return !(*this == it); } out_edge_iterator& operator++() { assert(m_i < m_g->alphabetSize()); ++m_i; next(); return *this; } out_edge_iterator operator++(int) { out_edge_iterator it = *this; ++*this; return it; } private: /** Skip to the next edge that is present. */ void next() { for (; m_i < m_g->alphabetSize(); m_i++) { m_v = vertex_descriptor( m_g->update(m_u.first, m_i), m_g->update(m_u.second, m_i)); if (m_v.first < m_v.second) break; } } const DAWG* m_g; vertex_descriptor m_u; vertex_descriptor m_v; degree_size_type m_i; }; // out_edge_iterator }; // graph_traits } // namespace boost // IncidenceGraph static inline std::pair< graph_traits::out_edge_iterator, graph_traits::out_edge_iterator> out_edges( graph_traits::vertex_descriptor u, const DAWG& g) { typedef graph_traits::out_edge_iterator Eit; return std::pair( Eit(g, u, 0), Eit(g, u, g.alphabetSize())); } static inline graph_traits::degree_size_type out_degree( graph_traits::vertex_descriptor u, const DAWG& g) { typedef graph_traits::out_edge_iterator Eit; std::pair it = out_edges(u, g); return std::distance(it.first, it.second); } // VertexListGraph static inline std::pair::vertex_iterator, graph_traits::vertex_iterator> vertices(const DAWG& g) { typedef graph_traits::vertex_iterator Vit; return std::pair(Vit(0, g.size() + 1), Vit()); } // PropertyGraph static inline DAWG::value_type get(boost::vertex_name_t, const DAWG& g, graph_traits::vertex_descriptor u) { assert(u.first < u.second); return u.first == 0 ? '$' : g.symbolAt(u.first); } static inline DAWG::value_type get(boost::edge_name_t, const DAWG& g, graph_traits::edge_descriptor e) { graph_traits::vertex_descriptor v = target(e, g); assert(v.first < v.second); return g.symbolAt(v.first); } #endif abyss-2.2.4/FMIndex/FMIndex.h000066400000000000000000000337621361462241400156130ustar00rootroot00000000000000#ifndef FMINDEX_H #define FMINDEX_H 1 #include "config.h" #include "BitArrays.h" #include "IOUtil.h" #include "sais.hxx" #include #include #include #include // for exit #include #include #include // for numeric_limits #include #include #include /** An FM index. */ class FMIndex { /** A symbol. */ typedef uint8_t T; /** The sentinel symbol. */ static T SENTINEL() { return std::numeric_limits::max(); } public: /** An index. */ typedef boost::uint_t::least size_type; /** An index for SAIS, which must be signed. */ typedef boost::int_t::least sais_size_type; /** The type of a symbol. */ typedef T value_type; /** A suffix array interval. */ struct SAInterval { size_type l, u; SAInterval(size_type l, size_type u) : l(l), u(u) { } SAInterval(const FMIndex& fm) : l(1), u(fm.m_occ.size()) { } bool empty() const { return l >= u; } bool operator==(const SAInterval& x) const { return x.l == l && x.u == u; } size_type size() const { assert(l <= u); return u - l; } }; /** A match of a substring of a query sequence to an FM index. */ struct Match : public SAInterval { unsigned qstart, qend, num; Match() : SAInterval(0, 0), qstart(0), qend(0), num(0) { } Match(size_type l, size_type u, unsigned qstart, unsigned qend, unsigned num = 1) : SAInterval(l, u), qstart(qstart), qend(qend), num(num) { } unsigned qspan() const { assert(qstart <= qend); return qend - qstart; } }; FMIndex() : m_sampleSA(1) { } /** Return the size of the string not counting the sentinel. */ size_t size() const { return m_occ.size() - 1; } /** The size of the alphabet. */ unsigned alphabetSize() const { return m_alphabet.size(); } /** Encode the alphabet of [first, last). */ template void encode(It first, It last) const { assert(first < last); assert(!m_alphabet.empty()); std::transform(first, last, first, Translate(*this)); } /** Decode the alphabet of [first, last). */ template void decode(It first, It last) const { assert(first < last); assert(!m_alphabet.empty()); for (It it = first; it < last; ++it) *it = m_alphabet[*it]; } /** Build the BWT of [first, last). * The BWT including the sentinel is stored in [first, last]. * @return the position of the sentinel */ template size_type buildBWT(It first, It last) const { assert(first < last); assert(size_t(last - first) < std::numeric_limits::max()); encode(first, last); std::replace(first, last, SENTINEL(), T(0)); std::cerr << "Building the Burrows-Wheeler transform...\n"; size_t n = last - first; std::vector sa(n); assert(sizeof (size_type) == sizeof (sais_size_type)); sais_size_type sentinel = saisxx_bwt(first, first, &sa[0], (sais_size_type)n, (sais_size_type)m_alphabet.size()); assert(sentinel >= 0); if (sentinel < 0) abort(); // Insert the sentinel. std::copy_backward(first + sentinel, last, last + 1); first[sentinel] = SENTINEL(); return sentinel; } /** Set the specified element of the sampled suffix array. */ void setSA(size_t sai, size_t pos) { if (sai % m_sampleSA == 0) { size_t i = sai / m_sampleSA; assert(i < m_sa.size()); m_sa[i] = pos; } } /** Construct the suffix array from the FM index. */ void constructSuffixArray() { // The length of the original string. size_t n = m_occ.size() - 1; assert(n > 0); assert(m_sampleSA > 0); m_sa.resize(n / m_sampleSA + 1); size_t sai = 0; for (size_t i = n; i > 0; i--) { setSA(sai, i); T c = m_occ.at(sai); assert(c != SENTINEL()); sai = m_cf[c] + m_occ.rank(c, sai); assert(sai > 0); } setSA(sai, 0); } /** Build an FM-index of the specified BWT. */ template void assignBWT(It first, It last) { assert(last - first > 1); assert(size_t(last - first) < std::numeric_limits::max()); std::cerr << "Building the character occurrence table...\n"; m_occ.assign(first, last); countOccurrences(); // Construct the suffix array from the FM index. std::cerr << "Building the suffix array...\n"; constructSuffixArray(); } /** Build an FM-index of the specified data. */ template void assign(It first, It last) { assert(first < last); assert(size_t(last - first) < std::numeric_limits::max()); encode(first, last); std::replace(first, last, SENTINEL(), T(0)); // Construct the suffix array. std::cerr << "Building the suffix array...\n"; size_t n = last - first; m_sampleSA = 1; m_sa.resize(n + 1); m_sa[0] = n; assert(sizeof (size_type) == sizeof (sais_size_type)); int status = saisxx(first, reinterpret_cast(&m_sa[1]), (sais_size_type)n, (sais_size_type)m_alphabet.size()); assert(status == 0); if (status != 0) abort(); // Construct the Burrows-Wheeler transform. std::vector bwt; std::cerr << "Building the Burrows-Wheeler transform...\n"; bwt.resize(m_sa.size()); for (size_t i = 0; i < m_sa.size(); i++) bwt[i] = m_sa[i] == 0 ? SENTINEL() : first[m_sa[i] - 1]; std::cerr << "Building the character occurrence table...\n"; m_occ.assign(bwt.begin(), bwt.end()); countOccurrences(); } /** Sample the suffix array. */ void sampleSA(unsigned period) { assert(period > 0); if (period == m_sampleSA) return; assert(m_sampleSA == 1); m_sampleSA = period; if (m_sampleSA == 1 || m_sa.empty()) return; std::vector::iterator out = m_sa.begin(); for (size_t i = 0; i < m_sa.size(); i += m_sampleSA) *out++ = m_sa[i]; m_sa.erase(out, m_sa.end()); assert(!m_sa.empty()); } /** Return the specified element of the suffix array. */ size_t at(size_t i) const { assert(i < m_occ.size()); size_t n = 0; while (i % m_sampleSA != 0) { T c = m_occ.at(i); i = c == SENTINEL() ? 0 : m_cf[c] + m_occ.rank(c, i); n++; } assert(i / m_sampleSA < m_sa.size()); size_t pos = m_sa[i / m_sampleSA] + n; return pos < m_occ.size() ? pos : pos - m_occ.size(); } /** Return the specified element of the suffix array. */ size_t operator[](size_t i) const { return at(i); } /** Return the symbol at the specifed position of the BWT. */ T bwtAt(size_t i) const { assert(i < m_occ.size()); T c = m_occ.at(i); assert(c != SENTINEL()); assert(c < m_alphabet.size()); return m_alphabet[c]; } /** Return the first symbol of the specified suffix. */ T symbolAt(size_t i) const { assert(i < m_occ.size()); std::vector::const_iterator it = std::upper_bound(m_cf.begin(), m_cf.end(), i); assert(it != m_cf.begin()); T c = it - m_cf.begin() - 1; assert(c < m_alphabet.size()); return m_alphabet[c]; } /** Decompress the index. */ template void decompress(It out) { // Construct the original string. std::vector s; for (size_t i = 0;;) { assert(i < m_occ.size()); T c = m_occ.at(i); if (c == SENTINEL()) break; s.push_back(c); i = m_cf[c] + m_occ.rank(c, i); assert(i > 0); } // Translate the character set and output the result. for (std::vector::reverse_iterator it = s.rbegin(); it != s.rend(); ++it) { T c = *it; assert(c < m_alphabet.size()); *out++ = m_alphabet[c]; } } /** Extend a suffix array coordinate by one character to the left. */ size_type update(size_type i, T c) const { assert(c < m_cf.size()); return m_cf[c] + m_occ.rank(c, i); } /** Extend a suffix array interval by one character to the left. */ SAInterval update(SAInterval sai, T c) const { return SAInterval(update(sai.l, c), update(sai.u, c)); } /** Search for an exact match. */ template SAInterval findExact(It first, It last, SAInterval sai) const { assert(first < last); for (It it = last - 1; it >= first && !sai.empty(); --it) { T c = *it; if (c == SENTINEL()) return SAInterval(0, 0); sai = update(sai, c); } return sai; } /** Search for an exact match. */ template SAInterval findExact(const String& q) const { String s(q.size()); std::transform(q.begin(), q.end(), s.begin(), Translate(*this)); return findExact(s.begin(), s.end()); } /** Search for a suffix of the query that matches a prefix of the * target. */ template OutIt findOverlapSuffix(It first, It last, OutIt out, unsigned minOverlap) const { assert(first < last); SAInterval sai(*this); for (It it = last - 1; it >= first && !sai.empty(); --it) { T c = *it; if (c == SENTINEL()) break; sai = update(sai, c); if (sai.empty()) break; if (unsigned(last - it) < minOverlap) continue; SAInterval sai1 = update(sai, 0); if (!sai1.empty()) *out++ = Match(sai1.l, sai1.u, it - first, last - first); } return out; } /** Search for a suffix of the query that matches a prefix of the * target. */ template OutIt findOverlapSuffix(const std::string& q, OutIt out, unsigned minOverlap) const { std::string s = q; std::transform(s.begin(), s.end(), s.begin(), Translate(*this)); return findOverlapSuffix(s.begin(), s.end(), out, minOverlap); } /** Search for a prefix of the query that matches a suffix of the * target. */ template OutIt findOverlapPrefix(const std::string& q, OutIt out, unsigned minOverlap) const { std::string s = q; std::transform(s.begin(), s.end(), s.begin(), Translate(*this)); typedef std::string::const_iterator It; It first = s.begin(); for (It it = first + minOverlap; it <= s.end(); ++it) { SAInterval sai = findExact(first, it, update(SAInterval(*this), 0)); if (!sai.empty()) *out++ = Match(sai.l, sai.u, 0, it - first); } return out; } /** Search for a matching suffix of the query. */ template Match findSuffix(It first, It last, MemoIt memoIt) const { assert(first < last); SAInterval sai(*this); It it; for (it = last - 1; it >= first && !sai.empty(); --it) { T c = *it; if (c == SENTINEL()) break; SAInterval sai1 = update(sai, c); if (sai1.empty()) break; sai = sai1; if (*memoIt == sai) { // This vertex of the prefix DAWG has been visited. break; } *memoIt++ = sai; } return Match(sai.l, sai.u, it - first + 1, last - first); } /** Search for a matching substring of the query at least k long. * @return the longest match */ template Match findSubstring(It first, It last, unsigned k) const { assert(first < last); Match best(0, 0, 0, k > 0 ? k - 1 : 0); // Record which vertices of the prefix DAWG have been visited. std::vector memo(last - first, SAInterval(0, 0)); SAInterval* memoIt = &memo[0]; for (It it = last; it > first; --it) { if (unsigned(it - first) < best.qspan()) return best; Match interval = findSuffix(first, it, memoIt++); if (interval.qspan() > best.qspan()) best = interval; else if (interval.qspan() == best.qspan()) best.num++; } return best; } /** Translate from ASCII to the indexed alphabet. */ struct Translate { Translate(const FMIndex& fmIndex) : m_fmIndex(fmIndex) { } T operator()(unsigned char c) const { return c < m_fmIndex.m_mapping.size() ? m_fmIndex.m_mapping[c] : SENTINEL(); } private: const FMIndex& m_fmIndex; }; /** Search for a matching substring of the query at least k long. * @return the longest match and the number of matches */ Match find(const std::string& q, unsigned k) const { std::string s = q; std::transform(s.begin(), s.end(), s.begin(), Translate(*this)); return findSubstring(s.begin(), s.end(), k); } /** Set the alphabet to [first, last). * The character '\0' is treated specially and not included in the * alphabet. */ template void setAlphabet(It first, It last) { assert(first < last); std::vector mask(std::numeric_limits::max()); for (It it = first; it < last; ++it) { assert((size_t)*it < mask.size()); mask[*it] = true; } // Remove the character '\0' from the alphabet. mask[0] = false; m_alphabet.clear(); m_mapping.clear(); for (unsigned c = 0; c < mask.size(); ++c) { if (!mask[c]) continue; m_mapping.resize(c + 1, std::numeric_limits::max()); m_mapping[c] = m_alphabet.size(); m_alphabet.push_back(c); } assert(!m_alphabet.empty()); } /** Set the alphabet to the characters of s. */ void setAlphabet(const std::string& s) { assert(!s.empty()); setAlphabet(s.begin(), s.end()); } #define STRINGIFY(X) #X #define FM_VERSION_BITS(BITS) "FM " STRINGIFY(BITS) " 1" #define FM_VERSION FM_VERSION_BITS(FMBITS) /** Store an index. */ friend std::ostream& operator<<(std::ostream& out, const FMIndex& o) { out << FM_VERSION << '\n' << o.m_sampleSA << '\n'; out << o.m_alphabet.size() << '\n'; out.write(reinterpret_cast(&o.m_alphabet[0]), o.m_alphabet.size() * sizeof o.m_alphabet[0]); out << o.m_sa.size() << '\n'; out.write(reinterpret_cast(&o.m_sa[0]), o.m_sa.size() * sizeof o.m_sa[0]); return out << o.m_occ; } /** Load an index. */ friend std::istream& operator>>(std::istream& in, FMIndex& o) { std::string version; std::getline(in, version); assert(in); if (version != FM_VERSION) { std::cerr << "error: the version of this FM-index, `" << version << "', does not match the version required " "by this program, `" FM_VERSION "'.\n"; exit(EXIT_FAILURE); } in >> o.m_sampleSA; assert(in); size_t n; in >> n >> expect("\n"); assert(in); assert(n < std::numeric_limits::max()); o.m_alphabet.resize(n); in.read(reinterpret_cast(&o.m_alphabet[0]), n * sizeof o.m_alphabet[0]); o.setAlphabet(o.m_alphabet.begin(), o.m_alphabet.end()); in >> n >> expect("\n"); assert(in); assert(n < std::numeric_limits::max()); o.m_sa.resize(n); in.read(reinterpret_cast(&o.m_sa[0]), n * sizeof o.m_sa[0]); in >> o.m_occ; assert(in); o.countOccurrences(); return in; } private: /** Build the cumulative frequency table m_cf from m_occ. */ void countOccurrences() { assert(!m_alphabet.empty()); m_cf.resize(m_alphabet.size()); // The sentinel character occurs once. m_cf[0] = 1; for (unsigned i = 0; i < m_cf.size() - 1; ++i) m_cf[i + 1] = m_cf[i] + m_occ.count(i); } unsigned m_sampleSA; std::vector m_alphabet; std::vector m_mapping; std::vector m_cf; std::vector m_sa; BitArrays m_occ; }; #endif abyss-2.2.4/FMIndex/Makefile.am000066400000000000000000000010611361462241400161670ustar00rootroot00000000000000noinst_LIBRARIES = libfmindex.a noinst_PROGRAMS = abyss-count abyss-dawg libfmindex_a_CPPFLAGS = -I$(top_srcdir)/Common libfmindex_a_SOURCES = \ BitArrays.h \ bit_array.cc bit_array.h \ DAWG.h \ FMIndex.h \ sais.hxx abyss_dawg_SOURCES = abyss-dawg.cc abyss_dawg_LDADD = libfmindex.a \ $(top_builddir)/Common/libcommon.a abyss_dawg_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common abyss_count_SOURCES = count.cc abyss_count_LDADD = libfmindex.a \ $(top_builddir)/Common/libcommon.a abyss_count_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common abyss-2.2.4/FMIndex/abyss-dawg.cc000066400000000000000000000076471361462241400165230ustar00rootroot00000000000000#include "BitUtil.h" #include "DAWG.h" #include "Uncompress.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using boost::default_dfs_visitor; #define PROGRAM "abyss-dawg" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [FASTA]\n" "Output a directed acyclic word graph (DAWG) of the specified file.\n" "The index file TARGET.fm will be used if present.\n" "\n" " Options:\n" "\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 { /** Verbose output. */ static int verbose; }; static const char shortopts[] = "v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** A directed acyclic word graph. */ typedef DAWG Graph; /** DAWG visitor. */ struct DAWGVisitor : public default_dfs_visitor { typedef graph_traits::edge_descriptor E; typedef graph_traits::vertex_descriptor V; void examine_edge(E e, const Graph& g) { using boost::edge_name; V u = source(e, g); V v = target(e, g); char c = get(edge_name, g, e); cout << '"' << u.first << ',' << u.second << "\" -> \"" << v.first << ',' << v.second << "\"" " [label=\""; if (isprint(c)) cout << c; else cout << "0x" << hex << (unsigned)c << dec; cout << "\"]\n"; } }; /** Read an FM index. */ static void readFMIndex(FMIndex& g, const string& faPath) { string fmPath = faPath + ".fm"; ifstream in(fmPath.c_str()); if (in) { if (opt::verbose > 0) cerr << "Reading `" << fmPath << "'...\n"; assert_good(in, fmPath); in >> g; assert_good(in, fmPath); in.close(); return; } // Build the FM index. std::vector s; if (string(faPath) == "-") { if (opt::verbose > 0) std::cerr << "Reading stdin...\n"; copy(istreambuf_iterator(cin), istreambuf_iterator(), back_inserter(s)); assert_good(cin, "stdin"); } else { if (opt::verbose > 0) std::cerr << "Reading `" << faPath << "'...\n"; readFile(faPath.c_str(), s); } g.assign(s.begin(), s.end()); } 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 '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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind > 1) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } string faPath(optind < argc ? argv[optind] : "-"); using boost::default_color_type; using boost::depth_first_visit; using boost::make_assoc_property_map; typedef graph_traits::vertex_descriptor V; // Read the FM index. Graph g; readFMIndex(g, faPath); cout << "digraph dawg {\n"; map colorMap; depth_first_visit(g, *vertices(g).first, DAWGVisitor(), make_assoc_property_map(colorMap)); cout << "}\n" << flush; assert_good(cout, "stdout"); return 0; } abyss-2.2.4/FMIndex/bit_array.cc000066400000000000000000000130721361462241400164230ustar00rootroot00000000000000/* * Copyright (c) 2010 Daisuke Okanohara * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above Copyright * notice, this list of conditions and the following disclaimer. * * 2. 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. * * 3. Neither the name of the authors nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. */ #include "bit_array.h" #include "BitUtil.h" // for popcount #include namespace wat_array { BitArray::BitArray() : length_(0), one_num_(0){ } BitArray::BitArray(uint64_t length){ Init(length); } BitArray::~BitArray(){ } uint64_t BitArray::length() const { return length_; } uint64_t BitArray::one_num() const{ return one_num_; } void BitArray::Init(uint64_t length){ length_ = length; one_num_ = 0; uint64_t block_num = (length + BLOCK_BITNUM - 1) / BLOCK_BITNUM; bit_blocks_.resize(block_num); } void BitArray::Clear(){ std::vector().swap(bit_blocks_); std::vector().swap(rank_tables_); length_ = 0; one_num_ = 0; } void BitArray::Build() { one_num_ = 0; uint64_t table_num = ((bit_blocks_.size() + TABLE_INTERVAL - 1) / TABLE_INTERVAL) + 1; rank_tables_.resize(table_num); for (size_t i = 0; i < bit_blocks_.size(); ++i){ if ((i % TABLE_INTERVAL) == 0){ rank_tables_[i/TABLE_INTERVAL] = one_num_; } one_num_ += PopCount(bit_blocks_[i]); } rank_tables_.back() = one_num_; } void BitArray::SetBit(uint64_t bit, uint64_t pos) { if (!bit) return; bit_blocks_[pos / BLOCK_BITNUM] |= (1LLU << (pos % BLOCK_BITNUM)); } uint64_t BitArray::Rank(uint64_t bit, uint64_t pos) const { if (pos > length_) return NOTFOUND; if (bit) return RankOne(pos); else return pos - RankOne(pos); } uint64_t BitArray::Select(uint64_t bit, uint64_t rank) const { if (bit){ if (rank > one_num_) return NOTFOUND; } else { if (rank > length_ - one_num_) return NOTFOUND; } uint64_t block_pos = SelectOutBlock(bit, rank); uint64_t block = (bit) ? bit_blocks_[block_pos] : ~bit_blocks_[block_pos]; return block_pos * BLOCK_BITNUM + SelectInBlock(block, rank); } uint64_t BitArray::SelectOutBlock(uint64_t bit, uint64_t& rank) const { // binary search over tables uint64_t left = 0; uint64_t right = rank_tables_.size(); while (left < right){ uint64_t mid = (left + right) / 2; uint64_t length = BLOCK_BITNUM * TABLE_INTERVAL * mid; if (GetBitNum(rank_tables_[mid], length, bit) < rank) { left = mid+1; } else { right = mid; } } uint64_t table_ind = (left != 0) ? left - 1: 0; uint64_t block_pos = table_ind * TABLE_INTERVAL; rank -= GetBitNum(rank_tables_[table_ind], block_pos * BLOCK_BITNUM, bit); // sequential search over blocks for ( ; block_pos < bit_blocks_.size(); ++block_pos){ uint64_t rank_next= GetBitNum(PopCount(bit_blocks_[block_pos]), BLOCK_BITNUM, bit); if (rank <= rank_next){ break; } rank -= rank_next; } return block_pos; } uint64_t BitArray::SelectInBlock(uint64_t x, uint64_t rank) { uint64_t x1 = x - ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1); uint64_t x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> 2) & 0x3333333333333333LLU); uint64_t x3 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FLLU; uint64_t pos = 0; for (;; pos += 8){ uint64_t rank_next = (x3 >> pos) & 0xFFLLU; if (rank <= rank_next) break; rank -= rank_next; } uint64_t v2 = (x2 >> pos) & 0xFLLU; if (rank > v2) { rank -= v2; pos += 4; } uint64_t v1 = (x1 >> pos) & 0x3LLU; if (rank > v1){ rank -= v1; pos += 2; } uint64_t v0 = (x >> pos) & 0x1LLU; if (v0 < rank){ rank -= v0; pos += 1; } return pos; } uint64_t BitArray::Lookup(uint64_t pos) const { return (bit_blocks_[pos / BLOCK_BITNUM] >> (pos % BLOCK_BITNUM)) & 1LLU; } uint64_t BitArray::RankOne(uint64_t pos) const { uint64_t block_ind = pos / BLOCK_BITNUM; uint64_t table_ind = block_ind / TABLE_INTERVAL; assert(table_ind < rank_tables_.size()); uint64_t rank = rank_tables_[table_ind]; for (uint64_t i = table_ind * TABLE_INTERVAL; i < block_ind; ++i){ rank += PopCount(bit_blocks_[i]); } rank += PopCountMask(bit_blocks_[block_ind], pos % BLOCK_BITNUM); return rank; } /** Return the Hamming weight of x. */ uint64_t BitArray::PopCount(uint64_t x) { return popcount(x); } uint64_t BitArray::PopCountMask(uint64_t x, uint64_t offset) { if (offset == 0) return 0; return PopCount(x & ((1LLU << offset) - 1)); } uint64_t BitArray::GetBitNum(uint64_t one_num, uint64_t num, uint64_t bit) { if (bit) return one_num; else return num - one_num; } void BitArray::PrintForDebug(std::ostream& os) const { for (uint64_t i = 0; i < length_; ++i){ if (Lookup(i)) os << "1"; else os << "0"; if (((i+1) % 8) == 0) { os << " "; } } } void BitArray::Save(std::ostream& os) const{ os.write((const char*)(&length_), sizeof(length_)); os.write((const char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size()); } void BitArray::Load(std::istream& is){ Clear(); is.read((char*)(&length_), sizeof(length_)); Init(length_); is.read((char*)(&bit_blocks_[0]), sizeof(bit_blocks_[0]) * bit_blocks_.size()); Build(); } } abyss-2.2.4/FMIndex/bit_array.h000066400000000000000000000040211361462241400162570ustar00rootroot00000000000000/* * Copyright (c) 2010 Daisuke Okanohara * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above Copyright * notice, this list of conditions and the following disclaimer. * * 2. 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. * * 3. Neither the name of the authors nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. */ #ifndef WAT_ARRAY_BIT_ARRAY_HPP_ #define WAT_ARRAY_BIT_ARRAY_HPP_ #include #include #include namespace wat_array { enum { NOTFOUND = 0xFFFFFFFFFFFFFFFFLLU }; class BitArray { private: enum { BLOCK_BITNUM = 64, TABLE_INTERVAL = 4 }; public: BitArray(); ~BitArray(); BitArray(uint64_t size); uint64_t length() const; uint64_t one_num() const; void Init(uint64_t size); void Clear(); void SetBit(uint64_t bit, uint64_t pos); void Build(); uint64_t Rank(uint64_t bit, uint64_t pos) const; uint64_t Select(uint64_t bit, uint64_t rank) const; uint64_t Lookup(uint64_t pos) const; static uint64_t PopCount(uint64_t x); static uint64_t PopCountMask(uint64_t x, uint64_t offset); static uint64_t SelectInBlock(uint64_t x, uint64_t rank); static uint64_t GetBitNum(uint64_t one_num, uint64_t num, uint64_t bit); void PrintForDebug(std::ostream& os) const; void Save(std::ostream& os) const; void Load(std::istream& is); private: uint64_t RankOne(uint64_t pos) const; uint64_t SelectOutBlock(uint64_t bit, uint64_t& rank) const; private: std::vector bit_blocks_; std::vector rank_tables_; uint64_t length_; uint64_t one_num_; }; } #endif // WAT_ARRAY_BIT_ARRAY_HPP_ abyss-2.2.4/FMIndex/count.cc000066400000000000000000000113501361462241400155740ustar00rootroot00000000000000#include "BitUtil.h" #include "DAWG.h" #include "Uncompress.h" #include #include #include #include #include #include #include #include #include #include using namespace std; using boost::default_color_type; #define PROGRAM "abyss-count" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... [FASTA]\n" "Count k-mer of the specified file.\n" "The index file TARGET.fm will be used if present.\n" "\n" " Options:\n" "\n" " -k, --kmer the size of a k-mer\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 { /** The size of a k-mer. */ static unsigned k; /** Verbose output. */ static int verbose; }; static const char shortopts[] = "k:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "kmer", no_argument, NULL, 'k' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** A directed acyclic word graph. */ typedef DAWG Graph; /** A color map that always returns white. */ struct WhiteMap { typedef graph_traits::vertex_descriptor key_type; typedef default_color_type value_type; typedef value_type& reference; typedef boost::lvalue_property_map_tag category; }; default_color_type get(const WhiteMap&, graph_traits::vertex_descriptor) { return boost::white_color; } void put(WhiteMap&, graph_traits::vertex_descriptor, default_color_type) { } /** Count k-mer. */ class CountKmerVisitor : public boost::default_dfs_visitor { typedef graph_traits::edge_descriptor E; typedef graph_traits::vertex_descriptor V; public: CountKmerVisitor(vector& s) : m_s(s) { assert(m_s.empty()); m_s.reserve(opt::k); } bool operator()(V u, const Graph& g) const { assert(m_s.size() < opt::k); if (u.first == 0) return false; char c = get(boost::vertex_name, g, u); m_s.push_back(c); if (c == '-') return true; if (m_s.size() < opt::k) return false; assert(m_s.size() == opt::k); unsigned count = u.second - u.first; copy(m_s.rbegin(), m_s.rend(), ostream_iterator(cout)); cout << '\t' << count << '\n'; return true; } void finish_vertex(V u, const Graph&) { if (m_s.empty()) { assert(u.first == 0); (void)u; } else m_s.pop_back(); } private: vector& m_s; }; // CountKmerVisitor /** Read an FM index. */ static void readFMIndex(FMIndex& g, const string& faPath) { string fmPath = faPath + ".fm"; ifstream in(fmPath.c_str()); if (in) { if (opt::verbose > 0) cerr << "Reading `" << fmPath << "'...\n"; assert_good(in, fmPath); in >> g; assert_good(in, fmPath); in.close(); return; } // Build the FM index. std::vector s; if (string(faPath) == "-") { if (opt::verbose > 0) std::cerr << "Reading stdin...\n"; copy(istreambuf_iterator(cin), istreambuf_iterator(), back_inserter(s)); assert_good(cin, "stdin"); } else { if (opt::verbose > 0) std::cerr << "Reading `" << faPath << "'...\n"; readFile(faPath.c_str(), s); } g.assign(s.begin(), s.end()); } 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 'k': arg >> opt::k; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (argc - optind > 1) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } string faPath(optind < argc ? argv[optind] : "-"); // Read the FM index. Graph g; readFMIndex(g, faPath); // Count k-mer. vector s; boost::depth_first_visit(g, *vertices(g).first, CountKmerVisitor(s), WhiteMap(), CountKmerVisitor(s)); assert_good(cout, "stdout"); return 0; } abyss-2.2.4/FMIndex/sais.hxx000066400000000000000000000463151361462241400156360ustar00rootroot00000000000000/* * sais.hxx for sais * Copyright (c) 2008-2010 Yuta Mori All Rights Reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _SAIS_HXX #define _SAIS_HXX 1 #ifdef __cplusplus #include #include #include #ifdef __INTEL_COMPILER #pragma warning(disable : 383 981 1418) #endif #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4365) #endif namespace saisxx_private { /* find the start or end of each bucket */ template void getCounts(const string_type T, bucket_type C, index_type n, index_type k) { index_type i; for(i = 0; i < k; ++i) { C[i] = 0; } for(i = 0; i < n; ++i) { ++C[T[i]]; } } template void getBuckets(const bucketC_type C, bucketB_type B, index_type k, bool end) { index_type i, sum = 0; if(end != false) { for(i = 0; i < k; ++i) { sum += C[i]; B[i] = sum; } } else { for(i = 0; i < k; ++i) { sum += C[i]; B[i] = sum - C[i]; } } } template void LMSsort1(string_type T, sarray_type SA, bucketC_type C, bucketB_type B, index_type n, index_type k, bool recount) { typedef typename std::iterator_traits::value_type char_type; sarray_type b; index_type i, j; char_type c0, c1; /* compute SAl */ if(recount != false) { getCounts(T, C, n, k); } getBuckets(C, B, k, false); /* find starts of buckets */ j = n - 1; b = SA + B[c1 = T[j]]; --j; *b++ = (T[j] < c1) ? ~j : j; for(i = 0; i < n; ++i) { if(0 < (j = SA[i])) { assert(T[j] >= T[j + 1]); if((c0 = T[j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } assert(i < (b - SA)); --j; *b++ = (T[j] < c1) ? ~j : j; SA[i] = 0; } else if(j < 0) { SA[i] = ~j; } } /* compute SAs */ if(recount != false) { getCounts(T, C, n, k); } getBuckets(C, B, k, true); /* find ends of buckets */ for(i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) { if(0 < (j = SA[i])) { assert(T[j] <= T[j + 1]); if((c0 = T[j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } assert((b - SA) <= i); --j; *--b = (T[j] > c1) ? ~(j + 1) : j; SA[i] = 0; } } } template index_type LMSpostproc1(string_type T, sarray_type SA, index_type n, index_type m) { typedef typename std::iterator_traits::value_type char_type; index_type i, j, p, q, plen, qlen, name; char_type c0, c1; bool diff; /* compact all the sorted substrings into the first m items of SA 2*m must be not larger than n (proveable) */ assert(0 < n); for(i = 0; (p = SA[i]) < 0; ++i) { SA[i] = ~p; assert((i + 1) < n); } if(i < m) { for(j = i, ++i;; ++i) { assert(i < n); if((p = SA[i]) < 0) { SA[j++] = ~p; SA[i] = 0; if(j == m) { break; } } } } /* store the length of all substrings */ i = n - 1; j = n - 1; c0 = T[n - 1]; do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) >= c1)); for(; 0 <= i;) { do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) <= c1)); if(0 <= i) { SA[m + ((i + 1) >> 1)] = j - i; j = i + 1; do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) >= c1)); } } /* find the lexicographic names of all substrings */ for(i = 0, name = 0, q = n, qlen = 0; i < m; ++i) { p = SA[i], plen = SA[m + (p >> 1)], diff = true; if((plen == qlen) && ((q + plen) < n)) { for(j = 0; (j < plen) && (T[p + j] == T[q + j]); ++j) { } if(j == plen) { diff = false; } } if(diff != false) { ++name, q = p, qlen = plen; } SA[m + (p >> 1)] = name; } return name; } template void LMSsort2(string_type T, sarray_type SA, bucketC_type C, bucketB_type B, bucketD_type D, index_type n, index_type k) { typedef typename std::iterator_traits::value_type char_type; sarray_type b; index_type i, j, t, d; char_type c0, c1; /* compute SAl */ getBuckets(C, B, k, false); /* find starts of buckets */ j = n - 1; b = SA + B[c1 = T[j]]; --j; t = (T[j] < c1); j += n; *b++ = (t & 1) ? ~j : j; for(i = 0, d = 0; i < n; ++i) { if(0 < (j = SA[i])) { if(n <= j) { d += 1; j -= n; } assert(T[j] >= T[j + 1]); if((c0 = T[j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } assert(i < (b - SA)); --j; t = c0; t = (t << 1) | (T[j] < c1); if(D[t] != d) { j += n; D[t] = d; } *b++ = (t & 1) ? ~j : j; SA[i] = 0; } else if(j < 0) { SA[i] = ~j; } } for(i = n - 1; 0 <= i; --i) { if(0 < SA[i]) { if(SA[i] < n) { SA[i] += n; for(j = i - 1; SA[j] < n; --j) { } SA[j] -= n; i = j; } } } /* compute SAs */ getBuckets(C, B, k, true); /* find ends of buckets */ for(i = n - 1, d += 1, b = SA + B[c1 = 0]; 0 <= i; --i) { if(0 < (j = SA[i])) { if(n <= j) { d += 1; j -= n; } assert(T[j] <= T[j + 1]); if((c0 = T[j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } assert((b - SA) <= i); --j; t = c0; t = (t << 1) | (T[j] > c1); if(D[t] != d) { j += n; D[t] = d; } *--b = (t & 1) ? ~(j + 1) : j; SA[i] = 0; } } } template index_type LMSpostproc2(sarray_type SA, index_type n, index_type m) { index_type i, j, d, name; /* compact all the sorted LMS substrings into the first m items of SA */ assert(0 < n); for(i = 0, name = 0; (j = SA[i]) < 0; ++i) { j = ~j; if(n <= j) { name += 1; } SA[i] = j; assert((i + 1) < n); } if(i < m) { for(d = i, ++i;; ++i) { assert(i < n); if((j = SA[i]) < 0) { j = ~j; if(n <= j) { name += 1; } SA[d++] = j; SA[i] = 0; if(d == m) { break; } } } } if(name < m) { /* store the lexicographic names */ for(i = m - 1, d = name + 1; 0 <= i; --i) { if(n <= (j = SA[i])) { j -= n; --d; } SA[m + (j >> 1)] = d; } } else { /* unset flags */ for(i = 0; i < m; ++i) { if(n <= (j = SA[i])) { j -= n; SA[i] = j; } } } return name; } /* compute SA and BWT */ template void induceSA(string_type T, sarray_type SA, bucketC_type C, bucketB_type B, index_type n, index_type k, bool recount) { typedef typename std::iterator_traits::value_type char_type; sarray_type b; index_type i, j; char_type c0, c1; /* compute SAl */ if(recount != false) { getCounts(T, C, n, k); } getBuckets(C, B, k, false); /* find starts of buckets */ b = SA + B[c1 = T[j = n - 1]]; *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j; for(i = 0; i < n; ++i) { j = SA[i], SA[i] = ~j; if(0 < j) { if((c0 = T[--j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j; } } /* compute SAs */ if(recount != false) { getCounts(T, C, n, k); } getBuckets(C, B, k, true); /* find ends of buckets */ for(i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) { if(0 < (j = SA[i])) { if((c0 = T[--j]) != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } *--b = ((j == 0) || (T[j - 1] > c1)) ? ~j : j; } else { SA[i] = ~j; } } } template int computeBWT(string_type T, sarray_type SA, bucketC_type C, bucketB_type B, index_type n, index_type k, bool recount) { typedef typename std::iterator_traits::value_type char_type; sarray_type b; index_type i, j, pidx = -1; char_type c0, c1; /* compute SAl */ if(recount != false) { getCounts(T, C, n, k); } getBuckets(C, B, k, false); /* find starts of buckets */ b = SA + B[c1 = T[j = n - 1]]; *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j; for(i = 0; i < n; ++i) { if(0 < (j = SA[i])) { SA[i] = ~((index_type)(c0 = T[--j])); if(c0 != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } *b++ = ((0 < j) && (T[j - 1] < c1)) ? ~j : j; } else if(j != 0) { SA[i] = ~j; } } /* compute SAs */ if(recount != false) { getCounts(T, C, n, k); } getBuckets(C, B, k, true); /* find ends of buckets */ for(i = n - 1, b = SA + B[c1 = 0]; 0 <= i; --i) { if(0 < (j = SA[i])) { SA[i] = (c0 = T[--j]); if(c0 != c1) { B[c1] = b - SA; b = SA + B[c1 = c0]; } *--b = ((0 < j) && (T[j - 1] > c1)) ? ~((index_type)T[j - 1]) : j; } else if(j != 0) { SA[i] = ~j; } else { pidx = i; } } return pidx; } template std::pair stage1sort(string_type T, sarray_type SA, bucketC_type C, bucketB_type B, index_type n, index_type k, unsigned flags) { typedef typename std::iterator_traits::value_type char_type; sarray_type b; index_type i, j, name, m; char_type c0, c1; getCounts(T, C, n, k); getBuckets(C, B, k, true); /* find ends of buckets */ for(i = 0; i < n; ++i) { SA[i] = 0; } b = SA + n - 1; i = n - 1; j = n; m = 0; c0 = T[n - 1]; do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) >= c1)); for(; 0 <= i;) { do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) <= c1)); if(0 <= i) { *b = j; b = SA + --B[c1]; j = i; ++m; assert(B[c1] != (n - 1)); do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) >= c1)); } } SA[n - 1] = 0; if(1 < m) { if(flags & (16 | 32)) { assert((j + 1) < n); ++B[T[j + 1]]; if(flags & 16) { index_type *D; try { D = new index_type[k * 2]; } catch(...) { D = 0; } if(D == 0) { return std::make_pair(-2, -2); } for(i = 0, j = 0; i < k; ++i) { j += C[i]; if(B[i] != j) { assert(SA[B[i]] != 0); SA[B[i]] += n; } D[i] = D[i + k] = 0; } LMSsort2(T, SA, C, B, D, n, k); delete[] D; } else { bucketB_type D = B - k * 2; for(i = 0, j = 0; i < k; ++i) { j += C[i]; if(B[i] != j) { assert(SA[B[i]] != 0); SA[B[i]] += n; } D[i] = D[i + k] = 0; } LMSsort2(T, SA, C, B, D, n, k); } name = LMSpostproc2(SA, n, m); } else { LMSsort1(T, SA, C, B, n, k, (flags & (4 | 64)) != 0); name = LMSpostproc1(T, SA, n, m); } } else if(m == 1) { *b = j + 1; name = 1; } else { name = 0; } return std::make_pair(m, name); } template index_type stage3sort(string_type T, sarray_type SA, bucketC_type C, bucketB_type B, index_type n, index_type m, index_type k, unsigned flags, bool isbwt) { typedef typename std::iterator_traits::value_type char_type; index_type i, j, p, q, pidx = 0; char_type c0, c1; if((flags & 8) != 0) { getCounts(T, C, n, k); } /* put all left-most S characters into their buckets */ if(1 < m) { getBuckets(C, B, k, 1); /* find ends of buckets */ i = m - 1, j = n, p = SA[m - 1], c1 = T[p]; do { q = B[c0 = c1]; while(q < j) { SA[--j] = 0; } do { SA[--j] = p; if(--i < 0) { break; } p = SA[i]; } while((c1 = T[p]) == c0); } while(0 <= i); while(0 < j) { SA[--j] = 0; } } if(isbwt == false) { induceSA(T, SA, C, B, n, k, (flags & (4 | 64)) != 0); } else { pidx = computeBWT(T, SA, C, B, n, k, (flags & (4 | 64)) != 0); } return pidx; } /* find the suffix array SA of T[0..n-1] in {0..k}^n use a working space (excluding s and SA) of at most 2n+O(1) for a constant alphabet */ template int suffixsort(string_type T, sarray_type SA, index_type fs, index_type n, index_type k, bool isbwt) { typedef typename std::iterator_traits::value_type char_type; sarray_type RA, C, B; index_type *Cp, *Bp; index_type i, j, m, name, pidx, newfs; unsigned flags = 0; char_type c0, c1; /* stage 1: reduce the problem by at least 1/2 sort all the S-substrings */ C = B = SA; /* for warnings */ Cp = 0, Bp = 0; if(k <= 256) { try { Cp = new index_type[k]; } catch(...) { Cp = 0; } if(Cp == 0) { return -2; } if(k <= fs) { B = SA + (n + fs - k); flags = 1; } else { try { Bp = new index_type[k]; } catch(...) { Bp = 0; } if(Bp == 0) { return -2; } flags = 3; } } else if(k <= fs) { C = SA + (n + fs - k); if(k <= (fs - k)) { B = C - k; flags = 0; } else if(k <= 1024) { try { Bp = new index_type[k]; } catch(...) { Bp = 0; } if(Bp == 0) { return -2; } flags = 2; } else { B = C; flags = 64 | 8; } } else { try { Cp = new index_type[k]; } catch(...) { Cp = 0; } if(Cp == 0) { return -2; } Bp = Cp; flags = 4 | 8; } if((n <= ((std::numeric_limits::max)() / 2)) && (2 <= (n / k))) { if(flags & 1) { flags |= ((k * 2) <= (fs - k)) ? 32 : 16; } else if((flags == 0) && ((k * 2) <= (fs - k * 2))) { flags |= 32; } } { std::pair r; if(Cp != 0) { if(Bp != 0) { r = stage1sort(T, SA, Cp, Bp, n, k, flags); } else { r = stage1sort(T, SA, Cp, B, n, k, flags); } } else { if(Bp != 0) { r = stage1sort(T, SA, C, Bp, n, k, flags); } else { r = stage1sort(T, SA, C, B, n, k, flags); } } m = r.first, name = r.second; } if(m < 0) { if(flags & (1 | 4)) { delete[] Cp; } if(flags & 2) { delete[] Bp; } return -2; } /* stage 2: solve the reduced problem recurse if names are not yet unique */ if(name < m) { if(flags & 4) { delete[] Cp; } if(flags & 2) { delete[] Bp; } newfs = (n + fs) - (m * 2); if((flags & (1 | 4 | 64)) == 0) { if((k + name) <= newfs) { newfs -= k; } else { flags |= 8; } } assert((n >> 1) <= (newfs + m)); RA = SA + m + newfs; for(i = m + (n >> 1) - 1, j = m - 1; m <= i; --i) { if(SA[i] != 0) { RA[j--] = SA[i] - 1; } } if(suffixsort(RA, SA, newfs, m, name, false) != 0) { if(flags & 1) { delete[] Cp; } return -2; } i = n - 1; j = m - 1; c0 = T[n - 1]; do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) >= c1)); for(; 0 <= i;) { do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) <= c1)); if(0 <= i) { RA[j--] = i + 1; do { c1 = c0; } while((0 <= --i) && ((c0 = T[i]) >= c1)); } } for(i = 0; i < m; ++i) { SA[i] = RA[SA[i]]; } if(flags & 4) { try { Cp = new index_type[k]; } catch(...) { Cp = 0; } if(Cp == 0) { return -2; } Bp = Cp; } if(flags & 2) { try { Bp = new index_type[k]; } catch(...) { Bp = 0; } if(Bp == 0) { if(flags & 1) { delete[] Cp; } return -2; } } } /* stage 3: induce the result for the original problem */ if(Cp != 0) { if(Bp != 0) { pidx = stage3sort(T, SA, Cp, Bp, n, m, k, flags, isbwt); } else { pidx = stage3sort(T, SA, Cp, B, n, m, k, flags, isbwt); } } else { if(Bp != 0) { pidx = stage3sort(T, SA, C, Bp, n, m, k, flags, isbwt); } else { pidx = stage3sort(T, SA, C, B, n, m, k, flags, isbwt); } } if(flags & (1 | 4)) { delete[] Cp; } if(flags & 2) { delete[] Bp; } return pidx; } } /* namespace saisxx_private */ /** * @brief Constructs the suffix array of a given string in linear time. * @param T[0..n-1] The input string. (random access iterator) * @param SA[0..n-1] The output array of suffixes. (random access iterator) * @param n The length of the given string. * @param k The alphabet size. * @return 0 if no error occurred, -1 or -2 otherwise. */ template int saisxx(string_type T, sarray_type SA, index_type n, index_type k = 256) { typedef typename std::iterator_traits::value_type savalue_type; savalue_type unused; (void)unused; assert((std::numeric_limits::min)() < 0); assert((std::numeric_limits::min)() < 0); assert((std::numeric_limits::max)() == (std::numeric_limits::max)()); assert((std::numeric_limits::min)() == (std::numeric_limits::min)()); if((n < 0) || (k <= 0)) { return -1; } if(n <= 1) { if(n == 1) { SA[0] = 0; } return 0; } return saisxx_private::suffixsort(T, SA, (index_type)0, n, k, false); } /** * @brief Constructs the burrows-wheeler transformed string of a given string in linear time. * @param T[0..n-1] The input string. (random access iterator) * @param U[0..n-1] The output string. (random access iterator) * @param A[0..n-1] The temporary array. (random access iterator) * @param n The length of the given string. * @param k The alphabet size. * @return The primary index if no error occurred, -1 or -2 otherwise. */ template index_type saisxx_bwt(string_type T, string_type U, sarray_type A, index_type n, index_type k = 256) { typedef typename std::iterator_traits::value_type savalue_type; typedef typename std::iterator_traits::value_type char_type; savalue_type unused; (void)unused; index_type i, pidx; assert((std::numeric_limits::min)() < 0); assert((std::numeric_limits::min)() < 0); assert((std::numeric_limits::max)() == (std::numeric_limits::max)()); assert((std::numeric_limits::min)() == (std::numeric_limits::min)()); if((n < 0) || (k <= 0)) { return -1; } if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; } pidx = saisxx_private::suffixsort(T, A, (index_type)0, n, k, true); if(0 <= pidx) { U[0] = T[n - 1]; for(i = 0; i < pidx; ++i) { U[i + 1] = (char_type)A[i]; } for(i += 1; i < n; ++i) { U[i] = (char_type)A[i]; } pidx += 1; } return pidx; } #ifdef _MSC_VER #pragma warning(pop) #endif #endif /* __cplusplus */ #endif /* _SAIS_HXX */ abyss-2.2.4/FilterGraph/000077500000000000000000000000001361462241400150525ustar00rootroot00000000000000abyss-2.2.4/FilterGraph/FilterGraph.cc000066400000000000000000000536761361462241400176110ustar00rootroot00000000000000/** * Remove short contigs that do not contribute any relevant * information to the assembly. * Written by Tony Raymond */ #include "Common/Options.h" #include "ContigID.h" #include "ContigPath.h" #include "ContigProperties.h" #include "FastaReader.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "IOUtil.h" #include "Uncompress.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace rel_ops; using namespace boost::lambda; using boost::tie; #define PROGRAM "abyss-filtergraph" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Tony Raymond.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [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" " -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" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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"; namespace opt { unsigned k; // used by ContigProperties /** Run a strand-specific RNA-Seq assembly. */ static int ss; /** Remove island contigs less than this length. */ static unsigned minIslandLen = 0; /** Remove tips less than this length. */ static unsigned minTipLen = 0; /** Remove all contigs less than this length. */ static unsigned minLen = 0; /** 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; /** Write the contig adjacency graph to this file. */ static string graphPath; /** Contigs to ignore. */ static string ignorePath; /** Contigs to remove. */ static string removePath; /** The minimum overlap allowed between two contigs. */ static int minOverlap = 10; /** Output graph format. */ int format = ADJ; // used by ContigProperties } static const char shortopts[] = "c:C:g:i:r:k:l:L:m:t:T:v"; 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 }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "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 } }; static vector g_removed; /** Contig adjacency graph. */ typedef ContigGraph> Graph; typedef Graph::vertex_descriptor vertex_descriptor; typedef Graph::edge_descriptor edge_descriptor; /** Data for verbose output. */ static struct { unsigned removed; unsigned tails; unsigned too_long; unsigned too_complex; unsigned self_adj; unsigned checked; unsigned parallel_edge; } g_count; /** Returns if the contig can be removed from the graph. */ static bool removable(const Graph* pg, vertex_descriptor v) { typedef graph_traits GTraits; typedef GTraits::out_edge_iterator OEit; typedef GTraits::in_edge_iterator IEit; typedef GTraits::vertex_descriptor V; const Graph& g = *pg; // Check if previously removed if (get(vertex_removed, g, v)) { g_count.removed++; return false; } unsigned min_degree = min(out_degree(v, g), in_degree(v, g)); // Check for tails if (min_degree == 0) { g_count.tails++; return false; } // Check that the result will be less complex that the original if (min_degree > opt::shimMaxDegree) { g_count.too_complex++; return false; } // Check if self adjacent OEit oei0, oei1; tie(oei0, oei1) = out_edges(v, g); for (OEit vw = oei0; vw != oei1; ++vw) { V w = target(*vw, g); V vc = get(vertex_complement, g, v); if (v == w || vc == w) { g_count.self_adj++; return false; } } // Check that removing the contig will result in adjacent contigs // overlapping by at least opt::minOverlap. IEit iei0, iei1; tie(iei0, iei1) = in_edges(v, g); IEit maxuv = iei0; for (IEit uv = iei0; uv != iei1; ++uv) if (g[*maxuv].distance < g[*uv].distance) maxuv = uv; OEit maxvw = oei0; for (OEit vw = oei0; vw != oei1; ++vw) if (g[*maxvw].distance < g[*vw].distance) maxvw = vw; if (g[*maxuv].distance + (int)g[v].length + g[*maxvw].distance > -opt::minOverlap) { g_count.too_long++; return false; } return true; } /** Data to store information of an edge. */ struct EdgeInfo { vertex_descriptor u; vertex_descriptor w; edge_bundle_type::type ep; EdgeInfo(vertex_descriptor u, vertex_descriptor w, int ep) : u(u) , w(w) , ep(ep) {} EdgeInfo() : u() , w() , ep() {} }; /** Returns a list of edges that may be added when the vertex v is * removed. */ static bool findNewEdges( const Graph& g, vertex_descriptor v, vector& eds, vector& markedContigs) { typedef graph_traits GTraits; typedef GTraits::vertex_descriptor V; typedef GTraits::out_edge_iterator OEit; typedef GTraits::in_edge_iterator IEit; IEit iei0, iei1; tie(iei0, iei1) = in_edges(v, g); OEit oei0, oei1; tie(oei0, oei1) = out_edges(v, g); vector marked; // if not marked and longest link LE contig length. // for every edge from u->v and v->w we must add an edge u->w for (IEit uv = iei0; uv != iei1; ++uv) { for (OEit vw = oei0; vw != oei1; ++vw) { int x = g[*uv].distance + (int)g[v].length + g[*vw].distance; assert(x <= 0); EdgeInfo ed(source(*uv, g), target(*vw, g), x); eds.push_back(ed); if (out_degree(v, g) > 1) marked.push_back(ed.u); if (in_degree(v, g) > 1) marked.push_back(ed.w); } } for (vector::const_iterator it = marked.begin(); it != marked.end(); it++) markedContigs[get(vertex_index, g, *it)] = true; return true; } /** Adds all edges described in the vector eds. */ static void addNewEdges(Graph& g, const vector& eds) { for (vector::const_iterator edsit = eds.begin(); edsit != eds.end(); ++edsit) { // 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); } } static void removeContig(vertex_descriptor v, Graph& g) { clear_vertex(v, g); remove_vertex(v, g); g_removed.push_back(get(vertex_contig_index, g, v)); g_count.removed++; } /** Remove the specified contig from the adjacency graph. */ static void removeContigs(Graph& g, vector& sc) { typedef graph_traits GTraits; typedef GTraits::vertex_descriptor V; vector out; out.reserve(sc.size()); vector markedContigs(g.num_vertices()); for (vector::iterator it = sc.begin(); it != sc.end(); ++it) { V v = *it; if (opt::verbose > 0 && ++g_count.checked % 10000000 == 0) cerr << "Removed " << g_count.removed << "/" << g_count.checked << " vertices that have been checked.\n"; if (markedContigs[get(vertex_index, g, v)]) { out.push_back(v); continue; } if (!removable(&g, v)) continue; vector eds; if (findNewEdges(g, v, eds, markedContigs)) addNewEdges(g, eds); else continue; removeContig(v, g); } sc.swap(out); } /** Return the value of the bit at the specified index. */ struct Marked : unary_function { typedef vector Data; Marked(const Graph& g, const Data& data) : m_g(g) , m_data(data) {} bool operator()(vertex_descriptor u) const { return m_data[get(vertex_contig_index, m_g, u)]; } private: const Graph& m_g; const Data& m_data; }; /** Finds all potentially removable contigs in the graph. */ static void findShortContigs(const Graph& g, const vector& seen, vector& sc) { typedef graph_traits GTraits; typedef GTraits::vertex_iterator Vit; Vit first, second; tie(first, second) = vertices(g); ::copy_if( first, second, back_inserter(sc), !boost::lambda::bind(Marked(g, seen), _1) && boost::lambda::bind(removable, &g, _1)); } /** Functor used for sorting contigs based on degree, then size, * and then ID. */ struct sortContigs { const Graph& g; sortContigs(const Graph& g) : g(g) {} template bool operator()(V a, V b) { const ContigProperties& ap = g[a]; const ContigProperties& bp = g[b]; unsigned dega = out_degree(a, g) * in_degree(a, g); unsigned degb = out_degree(b, g) * in_degree(b, g); return dega != degb ? dega < degb : ap.length != bp.length ? ap.length < bp.length : a < b; } }; struct ShorterThanX : unary_function { const Graph& g; const vector& seen; size_t x; ShorterThanX(const Graph& g, const vector& seen, size_t x) : g(g) , seen(seen) , x(x) {} bool operator()(vertex_descriptor y) const { return g[y].length < x && !get(vertex_removed, g, y) && !seen[get(vertex_contig_index, g, y)]; } }; struct LongerThanX : unary_function { const Graph& g; const vector& seen; size_t x; LongerThanX(const Graph& g, const vector& seen, size_t x) : g(g) , seen(seen) , x(x) {} bool operator()(vertex_descriptor y) const { return g[y].length > x && !get(vertex_removed, g, y) && !seen[get(vertex_contig_index, g, y)]; } }; struct CoverageLessThan : unary_function { const Graph& g; const vector& seen; float minCov; CoverageLessThan(const Graph& g, const vector& 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& seen) { if (opt::verbose > 0) cerr << "Removing shim contigs from the graph...\n"; vector shortContigs; findShortContigs(g, seen, shortContigs); for (unsigned i = 0; !shortContigs.empty(); ++i) { if (opt::verbose > 0) cerr << "Pass " << i + 1 << ": Checking " << shortContigs.size() << " contigs.\n"; sort(shortContigs.begin(), shortContigs.end(), sortContigs(g)); removeContigs(g, shortContigs); } if (opt::verbose > 0) { cerr << "Shim removal stats:\n"; cerr << "Removed: " << g_count.removed / 2 << " Too Complex: " << g_count.too_complex / 2 << " Tails: " << g_count.tails / 2 << " Too Long: " << g_count.too_long / 2 << " Self Adjacent: " << g_count.self_adj / 2 << " Parallel Edges: " << g_count.parallel_edge / 2 << '\n'; } } template static void removeContigs_if(Graph& g, pred p) { typedef graph_traits GTraits; typedef GTraits::vertex_iterator Vit; typedef GTraits::vertex_descriptor V; Vit first, second; tie(first, second) = vertices(g); vector sc; ::copy_if(first, second, back_inserter(sc), p); remove_vertex_if(g, sc.begin(), sc.end(), True()); transform(sc.begin(), sc.end(), back_inserter(g_removed), [](const ContigNode& c) { return c.contigIndex(); }); if (opt::verbose > 0) cerr << "Removed " << sc.size() / 2 << " contigs.\n"; } /** Contig sequences. */ typedef vector 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 { 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 static void remove_edge(Graph& g, It first, It last) { for (; first != last; first++) remove_edge(*first, g); } template static void removeEdges_if(Graph& g, pred p) { typedef graph_traits GTraits; typedef GTraits::edge_iterator Eit; typedef GTraits::edge_descriptor E; Eit first, second; tie(first, second) = edges(g); vector 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) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } 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 'c': arg >> opt::minCoverage; break; case 'C': arg >> opt::maxCoverage; break; case 'l': arg >> opt::minLen; break; case 'L': arg >> opt::maxLen; break; case 'm': arg >> opt::minOverlap; break; case 'g': arg >> opt::graphPath; break; case 'i': arg >> opt::ignorePath; break; case 'r': arg >> opt::removePath; break; case 'k': arg >> opt::k; break; case 'T': arg >> opt::minIslandLen; break; case 't': arg >> opt::minTipLen; break; case 'v': opt::verbose++; break; case OPT_SHIM_MAX_DEG: arg >> opt::shimMaxDegree; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::minOverlap < 0) { cerr << PROGRAM ": " << "--min-overlap must be a positive integer.\n"; die = true; } if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } Graph g; // Read the contig adjacency graph. { string adjPath(argv[optind++]); if (opt::verbose > 0) cerr << "Loading graph from file: " << adjPath << '\n'; ifstream fin(adjPath.c_str()); assert_good(fin, adjPath); fin >> g; assert(fin.eof()); } // Read the set of contigs to ignore. vector seen(num_vertices(g) / 2); if (!opt::ignorePath.empty()) { ifstream in(opt::ignorePath.c_str()); assert_good(in, opt::ignorePath); markSeenInPath(in, seen); } if (opt::verbose > 0) { cerr << "Graph stats before:\n"; printGraphStats(cerr, g); } // Remove list of contigs if (!opt::removePath.empty()) { ifstream in(opt::removePath.c_str()); assert(in.good()); string s; size_t b = g_removed.size(); while (in >> s) { size_t i = get(g_contigNames, s); removeContig(ContigNode(i, 0), g); } assert(in.eof()); if (opt::verbose) cerr << "Removed " << g_removed.size() - b << " contigs.\n"; } // Remove shims. if (opt::shim) removeShims(g, seen); // Remove islands. if (opt::minIslandLen > 0) { size_t s = g_removed.size(); removeIslands_if(g, back_inserter(g_removed), ShorterThanX(g, seen, opt::minIslandLen)); if (opt::verbose) cerr << "Removed " << g_removed.size() - s << " islands.\n"; } // Remove tips. if (opt::minTipLen > 0) { size_t s, prev; s = g_removed.size(); do { prev = g_removed.size(); pruneTips_if(g, back_inserter(g_removed), ShorterThanX(g, seen, opt::minTipLen)); } while (prev < g_removed.size()); if (opt::verbose) cerr << "Removed " << g_removed.size() - s << " tips.\n"; } // Remove short contigs. if (opt::minLen > 0) removeContigs_if(g, ShorterThanX(g, seen, opt::minLen)); // Remove long contigs. 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); } // 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. 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 ContigPaths; ContigPaths paths; if (opt::ss) assemble_stranded(g, back_inserter(paths)); else assemble(g, back_inserter(paths)); g_contigNames.unlock(); for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { ContigNode u(numContigs + it - paths.begin(), false); string name = createContigName(); put(vertex_name, g, u, name); cout << name << '\t' << *it << '\n'; } g_contigNames.lock(); } return 0; } abyss-2.2.4/FilterGraph/Makefile.am000066400000000000000000000005371361462241400171130ustar00rootroot00000000000000bin_PROGRAMS = abyss-filtergraph abyss_filtergraph_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer abyss_filtergraph_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_filtergraph_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a abyss_filtergraph_SOURCES = FilterGraph.cc abyss-2.2.4/GapFiller/000077500000000000000000000000001361462241400145105ustar00rootroot00000000000000abyss-2.2.4/GapFiller/Makefile.am000066400000000000000000000007251361462241400165500ustar00rootroot00000000000000bin_PROGRAMS = abyss-gapfill abyss_gapfill_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -I$(top_srcdir)/Align \ -D SAM_SEQ_QUAL=1 abyss_gapfill_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_gapfill_LDADD = \ $(top_builddir)/Align/libalign.a \ $(top_builddir)/dialign/libdialign.a \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a abyss_gapfill_SOURCES = gapfill.cpp gapfill.h abyss-2.2.4/GapFiller/gapfill.cpp000066400000000000000000000221651361462241400166400ustar00rootroot00000000000000#include "alignGlobal.h" #include "SAM.h" #include "DataLayer/Options.h" #include "smith_waterman.h" #include "Align/Options.h" #include "Uncompress.h" #include "FastaReader.h" #include "gapfill.h" #include "config.h" #include #include #include #include #include #include #include #include #include using namespace std; using namespace boost; #define PROGRAM "abyss-gapfill" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Anthony Raymond.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Science Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... CONTIGS ALIGNS\n" "Attempts to fill gaps in CONTIGS with spanning sequences\n" "from ALIGNS.\n" "\n" " -l, --min-align=N the minimal alignment size [1]\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 { static float identity = 0.9; static unsigned min_size = 500; static int verbose; } static const char shortopts[] = "l:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "min-align", required_argument, NULL, 'l' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; typedef map Scaffolds; typedef multimap Alignments; static struct { unsigned long long seqs; unsigned long long scaffolds; unsigned long long aligns; unsigned long long split_same; unsigned long long gaps; unsigned long long gaps_filled; unsigned long long n_removed; unsigned long long bases_added; } stats; static void readScaffolds(const char* path, Scaffolds& scaffs) { FastaReader in(path, FastaReader::NO_FOLD_CASE); FastaRecord rec; if (opt::verbose) cerr << "Loading scaffolds from `" << path << "'...\n"; while (in >> rec) { if (++stats.seqs % 10000000 == 0 && opt::verbose) cerr << "Loaded " << stats.scaffolds << " scaffolds " << "out of " << stats.seqs << " sequences.\n"; // Store only long scaffolded sequences if (rec.seq.size() >= opt::min_size) { assert(scaffs.find(rec.id) == scaffs.end()); Scaffold scaff(rec); if (scaff.hasGaps()) { stats.scaffolds++; stats.gaps += scaff.numGaps(); scaffs.insert(make_pair(rec.id, scaff)); } } } } static void readAlignments(const char* path, Alignments& aligns, Scaffolds& scaffs) { ifstream in(path); SAMRecord rec; if (opt::verbose) cerr << "Loading alignments from `" << path << "'...\n"; // Parse out the headers. while (in.peek() == '@') { string tmp; getline(in, tmp); assert(in); } while (in >> rec) { if (++stats.aligns % 10000000 == 0 && opt::verbose) cerr << "Loaded " << stats.split_same << " alignments " << "out of " << stats.aligns << ".\n"; // If aligns to either side of gap store in aligns. if (rec.tags.size() >= 2 && rec.tags[0] == 'X' && rec.tags[1] == 'A' && rec.tags.find(rec.rname, 5) != string::npos && scaffs.count(rec.rname) > 0 && scaffs.find(rec.rname)->second.isNearGaps(rec)) { stats.split_same++; aligns.insert(make_pair(rec.rname, rec)); } assert(in); } assert(in.eof()); } static void filterGapAlignments(vector& overlaps) { if (overlaps.empty()) { //stats.no_alignment++; return; } vector::iterator it; for (it = overlaps.begin(); it != overlaps.end(); it++ ) { overlap_align o = *it; if (o.overlap_match < opt::min_matches) overlaps.erase(it--); } if (overlaps.empty()) { //stats.low_matches++; return; } for (it = overlaps.begin(); it != overlaps.end(); it++ ) { overlap_align o = *it; if (o.pid() < opt::identity) overlaps.erase(it--); } } static void alignReadToGapFlanks(string seg1, string seg2, string read, vector& seqs) { //overlap align end of first segment to start of read vector overlaps1; { string a(seg1), b(read); if (seg1.size() > opt::max_overlap) a = seg1.substr(seg1.size() - opt::max_overlap); if (read.size() > opt::max_overlap) b = read.substr(0, opt::max_overlap); alignOverlap(a, b, 0, overlaps1, true, opt::verbose > 2); } filterGapAlignments(overlaps1); //overlap align start of second segment to end of read vector overlaps2; { string a(read), b(seg2); if (read.size() > opt::max_overlap) a = read.substr(read.size() - opt::max_overlap); if (seg2.size() > opt::max_overlap) b = seg2.substr(0, opt::max_overlap); alignOverlap(a, b, 0, overlaps2, true, opt::verbose > 2); } filterGapAlignments(overlaps2); //if both alignments have sufficient identity, return overlaps if (overlaps1.size() == 1 && overlaps2.size() == 1) { unsigned start = overlaps1[0].overlap_str.size(); int length = read.size() - overlaps2[0].overlap_str.size() - start; if (length <= 0) //TODO: Handle overlapping scaffolds properly!!! return; seqs.push_back(read.substr(start, length)); } } static void alignReadsToGapFlanks(Scaffold& scaff, const Alignments& aligns) { string cid = scaff.rec.id; Alignments::const_iterator start, end; tie(start, end) = aligns.equal_range(cid); if (opt::verbose > 1) cerr << "examining contig " << cid << ", which has " << distance(start, end) << " alignments and " << scaff.numSegs() << " segments...\n"; vector< vector > gap_seqs(scaff.gaps.size()); //identify the set of gaps that this alignment could span for (unsigned i = 0; i < scaff.gaps.size(); i++) { vector& seqs = gap_seqs[i]; for ( ; start != end; start++) { Scaffold::Gap& gap = scaff.gaps[i]; if (!Scaffold::isNearGap(gap, start->second)) continue; string read_seq = start->second.seq; int seg1_start = max(0, (int)(gap.first - opt::max_overlap)); assert(seg1_start >= 0); string seg1 = scaff.rec.seq.substr(seg1_start, gap.first - seg1_start); int seg2_end = min(scaff.rec.seq.size(), gap.second + opt::max_overlap); assert((unsigned)seg2_end <= scaff.rec.seq.size()); string seg2 = scaff.rec.seq.substr(gap.second, seg2_end - gap.second); alignReadToGapFlanks(seg1, seg2, read_seq, seqs); } } for (int i = gap_seqs.size() - 1; i >= 0; i--) { vector& seqs = gap_seqs[i]; if (seqs.size() == 0) continue; string alignment; unsigned matches; switch (seqs.size()) { case 1: alignment = seqs[0]; break; default: NWAlignment align; alignment = seqs[0]; for (unsigned j = 0; j < seqs.size() - 1; j++) { matches = max(matches, alignGlobal(alignment, seqs[j+1], align)); alignment = align.match_align; } break; //if using dialign: // Sequence consensus = dialign(*it, alignment, matches); } if (alignment != "") { pair result = scaff.fillGap(i,alignment); stats.n_removed += result.first; stats.bases_added += result.second; stats.gaps_filled++; } } } static void fillGaps(Scaffolds& scaffs, const Alignments& aligns) { //foreach scaffold for (Scaffolds::iterator sit = scaffs.begin(); sit != scaffs.end(); sit++) { alignReadsToGapFlanks(sit->second, aligns); } } static void printFixedContigs(const Scaffolds& scaffs, const char* path, ostream& out) { FastaReader in(path, FastaReader::NO_FOLD_CASE); FastaRecord rec; cerr << "Fixing scaffolds from `" << path << "'...\n"; while (in >> rec) { Scaffolds::const_iterator it = scaffs.find(rec.id); if (it == scaffs.end()) out << rec; else out << it->second; } } int main(int argc, char* const* 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 '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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind != 2) { cerr << PROGRAM ": incorrect number of arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } Scaffolds scaffs; readScaffolds(argv[argc-2], scaffs); if (opt::verbose) cerr << "Loaded " << stats.scaffolds << " scaffolds " << "out of " << stats.seqs << " sequences.\n"; Alignments aligns; readAlignments(argv[argc-1], aligns, scaffs); if (opt::verbose) cerr << "aligns: " << stats.aligns << "\tsplit: " << stats.split_same << '\n'; fillGaps(scaffs, aligns); if (opt::verbose) cerr << "Contigs: " << stats.seqs << "\nScaffolds: " << stats.scaffolds << "\nGaps: " << stats.gaps << "\nGaps filled: " << stats.gaps_filled << "\nN's removed: " << stats.n_removed << "\nBases added: " << stats.bases_added << '\n'; printFixedContigs(scaffs, argv[argc-2], cout); return 0; } abyss-2.2.4/GapFiller/gapfill.h000066400000000000000000000027141361462241400163030ustar00rootroot00000000000000#ifndef GAPFILL_H #define GAPFILL_H 1 #include "FastaReader.h" namespace opt { static unsigned min_matches = 50; static unsigned max_overlap = 500; } struct Scaffold { typedef pair Gap; typedef vector Gaps; FastaRecord rec; Gaps gaps; Scaffold(FastaRecord rec) : rec(rec) { splitScaffold(); } void splitScaffold() { size_t j = 0; for (size_t i = rec.seq.find_first_of('N'); i != string::npos; i = rec.seq.find_first_of('N', j)) { j = rec.seq.find_first_not_of('N', i); gaps.push_back(Gap(i, j)); } } bool hasGaps() const { return gaps.size() > 0; } unsigned numGaps() const { return gaps.size(); } unsigned numSegs() const { return numGaps() + 1; } static bool isNearGap(const Scaffold::Gap& gap, const SAMRecord& align) { int align_start = align.pos; int gap_start = gap.first; return align_start <= gap_start && align_start >= (int)(gap_start - opt::max_overlap + opt::min_matches); } bool isNearGaps(const SAMRecord& align) const { for (Gaps::const_iterator it = gaps.begin(); it != gaps.end(); it++) if (isNearGap(*it, align)) return true; return false; } pair fillGap(unsigned i, string& seq) { assert(i < gaps.size()); Gap& g = gaps[i]; rec.seq.replace(g.first, g.second - g.first, seq); return make_pair(g.second - g.first, seq.size()); } friend ostream& operator<<(ostream& out, const Scaffold& scaff) { return out << scaff.rec; } }; #endif abyss-2.2.4/Graph/000077500000000000000000000000001361462241400137045ustar00rootroot00000000000000abyss-2.2.4/Graph/AdjIO.h000066400000000000000000000120751361462241400150100ustar00rootroot00000000000000#ifndef ADJIO_H #define ADJIO_H 1 #include "ContigID.h" #include "ContigGraph.h" #include "IOUtil.h" #include #include // for count #include #include #include #include #include using namespace std::rel_ops; using boost::graph_traits; template void write_edge_prop(std::ostream& out, const EdgeProp& ep) { if (ep != EdgeProp()) out << " [" << ep << ']'; } static inline void write_edge_prop(std::ostream&, const no_property&) { } /** Output a contig adjacency graph. */ template std::ostream& write_adj(std::ostream& out, const Graph& g) { typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename graph_traits::out_edge_iterator out_edge_iterator; std::pair vit = vertices(g); bool sense = false; for (vertex_iterator u = vit.first; u != vit.second; ++u, sense = !sense) { if (get(vertex_removed, g, *u)) continue; if (!sense) out << get(vertex_contig_name, g, *u) << get(vertex_bundle, g, *u); out << "\t;"; std::pair adj = out_edges(*u, g); for (out_edge_iterator e = adj.first; e != adj.second; ++e) { vertex_descriptor v = target(*e, g); assert(!get(vertex_removed, g, v)); out << ' ' << get(vertex_name, g, v ^ sense); write_edge_prop(out, get(edge_bundle, g, e)); } if (sense) out << '\n'; } return out; } /** Read the edges of a graph in dist format. */ template std::istream& readDistEdges(std::istream& in, ContigGraph& g, typename graph_traits::vertex_descriptor u, BetterEP betterEP) { typedef typename graph_traits::vertex_descriptor V; typedef typename graph_traits::edge_descriptor E; typedef typename Graph::edge_property_type EP; for (std::string vname; getline(in >> std::ws, vname, ',');) { assert(!vname.empty()); V v = find_vertex(vname, g); v = v ^ get(vertex_sense, g, u); EP ep; in >> ep; assert(in); if (in.peek() != ' ') in >> Ignore(' '); E e; bool found; boost::tie(e, found) = edge(u, v, g); if (found) { // Parallel edge EP& ref = g[e]; ref = betterEP(ref, ep); } else g.Graph::add_edge(u, v, ep); } assert(in.eof()); return in; } /** Read a contig adjacency graph. * @param betterEP handle parallel edges */ template std::istream& read_adj(std::istream& in, ContigGraph& g, BetterEP betterEP) { if (in.eof()) { // Allow reading an empty file if the graph is not empty. assert(num_vertices(g) > 0); return in; } assert(in); typedef typename Graph::vertex_descriptor vertex_descriptor; typedef typename Graph::vertex_property_type vertex_property_type; typedef typename Graph::edge_property_type edge_property_type; // Check for ADJ or DIST format. std::string line; getline(in, line); assert(in); unsigned numSemicolons = std::count(line.begin(), line.end(), ';'); if (numSemicolons > 2) { std::cerr << "error: expected 0, 1 or 2 semicolons and saw " << numSemicolons << '\n'; exit(EXIT_FAILURE); } bool faiFormat = numSemicolons == 0; bool adjFormat = numSemicolons == 2; // Read the vertex properties. if (adjFormat || faiFormat) { assert(num_vertices(g) == 0); in.clear(); in.seekg(0, std::ios::beg); assert(in); for (std::string uname; in >> uname;) { vertex_property_type vp; if (faiFormat) { unsigned length; in >> length; put(vertex_length, vp, length); } else in >> vp; in >> Ignore('\n'); assert(in); vertex_descriptor u = add_vertex(vp, g); put(vertex_name, g, u, uname); } assert(in.eof()); } assert(num_vertices(g) > 0); g_contigNames.lock(); if (faiFormat) return in; // Read the edges. in.clear(); in.seekg(0, std::ios::beg); assert(in); for (std::string name; in >> name;) { if (adjFormat) in >> Ignore(';'); vertex_descriptor u = find_vertex(name, false, g); for (int sense = false; sense <= true; ++sense) { std::string s; getline(in, s, !sense ? ';' : '\n'); assert(in.good()); std::istringstream ss(s); if (!adjFormat) { readDistEdges(ss, g, u ^ sense, betterEP); } else for (std::string vname; ss >> vname;) { ss >> std::ws; vertex_descriptor v = find_vertex(vname, g); assert(!edge(u ^ sense, v ^ sense, g).second); if (ss.peek() == '[') { ss.get(); edge_property_type ep; ss >> ep >> Ignore(']'); g.Graph::add_edge(u ^ sense, v ^ sense, ep); } else g.Graph::add_edge(u ^ sense, v ^ sense); } assert(ss.eof()); } } assert(in.eof()); return in; } template class AdjWriter { const Graph& m_g; public: AdjWriter(const Graph& g) : m_g(g) { } friend std::ostream& operator<<(std::ostream& out, const AdjWriter& o) { return write_adj(out, o.m_g); } }; template AdjWriter adj_writer(const Graph& g) { return AdjWriter(g); } #endif abyss-2.2.4/Graph/AllPathsSearch.h000066400000000000000000000064531361462241400167230ustar00rootroot00000000000000#ifndef ALLPATHS_SEARCH_H_ #define ALLPATHS_SEARCH_H_ #include "Common/UnorderedSet.h" #include "Graph/Path.h" #include // for boost::tie #include #include #include /** result of exhaustive path search from vertex A to vertex B */ template struct AllPathsSearchResult { public: /** code indicating type of success/failure for search */ PathSearchResult resultCode; /** number of edges traversed during search */ unsigned cost; /** all paths from vertex A to vertex B (if successful) */ std::vector< Path > paths; /** constructor */ AllPathsSearchResult() : resultCode(NO_PATH), cost(0) {} }; template AllPathsSearchResult::vertex_descriptor> allPathsSearch( const IncidenceGraph& g, typename boost::graph_traits::vertex_descriptor start, typename boost::graph_traits::vertex_descriptor goal, unsigned maxPaths, unsigned minDepth, unsigned maxDepth, unsigned maxCost) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::out_edge_iterator EdgeIter; typedef typename std::pair EdgeIterPair; unordered_set > visited; Path path; std::vector eiStack; unordered_set cycleVertices; path.push_back(start); visited.insert(start); eiStack.push_back(out_edges(start, g)); AllPathsSearchResult result; while(!path.empty() && result.cost <= maxCost) { if (path.back() == goal && (minDepth == NO_LIMIT || (path.size() - 1) >= minDepth)) { if (maxPaths != NO_LIMIT && result.paths.size() >= maxPaths) { result.resultCode = TOO_MANY_PATHS; return result; } if (!cycleVertices.empty()) { result.resultCode = PATH_CONTAINS_CYCLE; return result; } result.paths.push_back(path); } // find next unvisited node and append to path while(!path.empty()) { if ((maxDepth != NO_LIMIT && (path.size() - 1) >= maxDepth) || eiStack.back().first == eiStack.back().second) { visited.erase(path.back()); cycleVertices.erase(path.back()); path.pop_back(); eiStack.pop_back(); assert(path.empty() == eiStack.empty()); if (!path.empty()) eiStack.back().first++; } else { V v = target(*(eiStack.back().first), g); if (visited.find(v) != visited.end()) { cycleVertices.insert(v); eiStack.back().first++; } else { path.push_back(v); eiStack.push_back(out_edges(v, g)); visited.insert(v); result.cost++; break; } } // if ei != ei_end } // while !path.empty() } // while !path.empty() if (result.cost > maxCost) result.resultCode = MAX_COST_EXCEEDED; else if (result.paths.empty()) result.resultCode = NO_PATH; else result.resultCode = FOUND_PATH; return result; } template AllPathsSearchResult::vertex_descriptor> allPathsSearch( const IncidenceGraph& g, typename boost::graph_traits::vertex_descriptor start, typename boost::graph_traits::vertex_descriptor goal) { return allPathsSearch(g, start, goal, NO_LIMIT, NO_LIMIT, NO_LIMIT, NO_LIMIT); } #endif abyss-2.2.4/Graph/AsqgIO.h000066400000000000000000000103121361462241400151750ustar00rootroot00000000000000#ifndef ASQGIO_H #define ASQGIO_H 1 #include "Common/IOUtil.h" #include "Graph/Properties.h" #include #include #include #include #include using boost::graph_traits; /** Write a graph in ASQG format. */ template std::ostream& write_asqg(std::ostream& out, Graph& g) { typedef typename graph_traits::edge_descriptor E; typedef typename graph_traits::edge_iterator Eit; typedef typename graph_traits::vertex_descriptor V; typedef typename graph_traits::vertex_iterator Vit; typedef typename vertex_bundle_type::type VP; out << "HT\tVN:i:1\n"; assert(out); std::pair vrange = vertices(g); for (Vit uit = vrange.first; uit != vrange.second; ++uit, ++uit) { V u = *uit; if (get(vertex_removed, g, u)) continue; const VP& vp = g[u]; out << "VT\t" << get(vertex_contig_name, g, u) << "\t*\tLN:i:" << vp.length; if (vp.coverage > 0) out << "\tKC:i:" << vp.coverage; out << '\n'; } std::pair erange = edges(g); for (Eit eit = erange.first; eit != erange.second; ++eit) { E e = *eit; V u = source(e, g); V v = target(e, g); 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) << ' ' << int((usense ? overlap : ulen) - 1) << ' ' << ulen << ' ' << (!vsense ? 0 : vlen - overlap) << ' ' << int((!vsense ? overlap : vlen) - 1) << ' ' << vlen << ' ' << (usense != vsense) << " -1\n"; // number of mismatches } return out; } /** Read a graph in ASQG format. */ template std::istream& read_asqg(std::istream& in, Graph& g) { assert(in); typedef typename graph_traits::vertex_descriptor V; typedef typename graph_traits::edge_descriptor E; typedef typename vertex_property::type VP; typedef typename edge_property::type EP; // Add vertices if this graph is empty. bool addVertices = num_vertices(g) == 0; while (in && in.peek() != EOF) { switch (in.peek()) { case 'H': in >> expect("HT") >> Ignore('\n'); assert(in); break; case 'V': { std::string uname, seq; in >> expect("VT") >> uname >> seq; assert(in); assert(!seq.empty()); unsigned length = 0; if (seq == "*") { in >> expect(" LN:i:") >> length; 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 { V u = find_vertex(uname, false, g); assert(get(vertex_index, g, u) < num_vertices(g)); (void)u; } break; } case 'E': { 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'); 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 = edge(u, v, g); if (e.second) { // Ignore duplicate edges that are self loops. assert(g[e.first] == ep); assert(u == v); } else add_edge(u, v, ep, g); break; } default: { std::string s; in >> s; std::cerr << "error: unknown record type: `" << s << "'\n"; exit(EXIT_FAILURE); } } } assert(in.eof()); return in; } #endif abyss-2.2.4/Graph/Assemble.h000066400000000000000000000030531361462241400156110ustar00rootroot00000000000000#ifndef ASSEMBLE_H #define ASSEMBLE_H 1 #include "Common/ContigNode.h" // for ContigIndexMap #include "Common/Iterator.h" // for output_iterator_traits #include "Graph/DepthFirstSearch.h" using boost::graph_traits; /** Return true if this edge is contiguous. */ template bool isContiguous(const Graph &g, typename graph_traits::edge_descriptor e) { return out_degree(source(e, g), g) == 1 && in_degree(target(e, g), g) == 1; } /** Assemble contigous paths. Write the paths to out. */ template class AssembleVisitor : public boost::default_dfs_visitor { public: AssembleVisitor(OutIt it) : m_it(it) { } template void discover_vertex(const Vertex& u, Graph&) { m_path.push_back(u); } template void finish_vertex(const Vertex&, Graph&) { finishContig(); } template void examine_edge(const Edge& e, const Graph& g) { if (!isContiguous(g, e)) finishContig(); } private: void finishContig() { if (m_path.size() > 1) *m_it++ = m_path; m_path.clear(); } OutIt m_it; typename output_iterator_traits::value_type m_path; }; /** Assemble unambiguous paths. Write the paths to out. */ template void assembleDFS(const Graph& g, OutIt out, bool ss = false) { (void)ss; typedef boost::vector_property_map< boost::default_color_type, ContigIndexMap> ColorMap; depthFirstSearch(g, AssembleVisitor(out), ColorMap(num_vertices(g) / 2), ss); } #endif abyss-2.2.4/Graph/BidirectionalBFS.h000066400000000000000000000115201361462241400171570ustar00rootroot00000000000000#ifndef BIDIRECTIONALBFS_H #define BIDIRECTIONALBFS_H 1 #include "Graph/DefaultColorMap.h" #include "Graph/BidirectionalBFSVisitor.h" #include "Graph/Path.h" #include #include using boost::function_requires; using boost::graph_traits; using boost::property_traits; using boost::color_traits; template inline BFSVisitorResult bidirectionalBFS_visit_edge( const BidirectionalGraph& g, typename boost::graph_traits::edge_descriptor e, Buffer& Q, BidirectionalBFSVisitor& vis, ColorMap& color1, ColorMap& color2, Direction dir) { function_requires< boost::BidirectionalGraphConcept >(); typedef graph_traits GTraits; typedef typename GTraits::vertex_descriptor Vertex; function_requires< boost::ReadWritePropertyMapConcept >(); typedef typename property_traits::value_type ColorValue; typedef color_traits Color; ColorMap& color = (dir == FORWARD) ? color1 : color2; ColorMap& other_color = (dir == FORWARD) ? color2 : color1; Vertex v = (dir == FORWARD) ? target(e, g) : source(e, g); vis.examine_edge(e, g, dir); ColorValue v_color = get(color, v); ColorValue other_v_color = get(other_color, v); BFSVisitorResult result; if (other_v_color != Color::white()) { // We have encountered a common edge, i.e. an // edge where one vertex has been visited by // the forward traversal and the other has // been visited by the reverse traversal. // Each common edge is once by the forward // traversal and once by the reverse traversal. BFSVisitorResult result; result = vis.common_edge(e, g, dir); if (result == SKIP_ELEMENT || result == ABORT_SEARCH) return result; } else if (v_color == Color::white()) { result = vis.discover_vertex(v, g, dir, Q.size()); if (result == SKIP_ELEMENT || result == ABORT_SEARCH) return result; result = vis.tree_edge(e, g, dir); if (result == SKIP_ELEMENT || result == ABORT_SEARCH) return result; put(color, v, Color::gray()); Q.push(v); } else { result = vis.non_tree_edge(e, g, dir); if (result == SKIP_ELEMENT || result == ABORT_SEARCH) return result; if (v_color == Color::gray()) vis.gray_target(e, g, dir); else vis.black_target(e, g, dir); } return SUCCESS; } template void bidirectionalBFS( const BidirectionalGraph& g, typename boost::graph_traits::vertex_descriptor s1, typename boost::graph_traits::vertex_descriptor s2, Buffer& Q1, Buffer& Q2, BidirectionalBFSVisitor& vis, ColorMap& color1, ColorMap& color2) { function_requires< boost::BidirectionalGraphConcept >(); typedef graph_traits GTraits; typedef typename GTraits::vertex_descriptor Vertex; function_requires< boost::ReadWritePropertyMapConcept >(); typedef typename property_traits::value_type ColorValue; typedef color_traits Color; typename GTraits::out_edge_iterator oei, oei_end; typename GTraits::in_edge_iterator iei, iei_end; put(color1, s1, Color::gray()); put(color2, s2, Color::gray()); vis.discover_vertex(s1, g, FORWARD, Q1.size()); vis.discover_vertex(s2, g, REVERSE, Q2.size()); Q1.push(s1); Q2.push(s2); Direction dir = FORWARD; while (!Q1.empty() || !Q2.empty()) { Buffer& Q = (dir == FORWARD) ? Q1 : Q2; ColorMap& color = (dir == FORWARD) ? color1 : color2; Vertex u = Q.top(); Q.pop(); vis.examine_vertex(u, g, dir); if (dir == FORWARD) { for (boost::tie(oei, oei_end) = out_edges(u, g); oei != oei_end; ++oei) { if (bidirectionalBFS_visit_edge(g, *oei, Q, vis, color1, color2, dir) == ABORT_SEARCH) { return; } } } else { for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; ++iei) { if (bidirectionalBFS_visit_edge(g, *iei, Q, vis, color1, color2, dir) == ABORT_SEARCH) { return; } } } put(color, u, Color::black()); vis.finish_vertex(u, g, dir); if (dir == REVERSE && !Q1.empty()) dir = FORWARD; else if (dir == FORWARD && !Q2.empty()) dir = REVERSE; } // while(!Q1.empty() || !Q2.empty()) } // bidirectionalBFS template void bidirectionalBFS(const BidirectionalGraph& g, typename graph_traits::vertex_descriptor start, typename graph_traits::vertex_descriptor goal, BidirectionalBFSVisitor& visitor) { typedef typename graph_traits::vertex_descriptor V; DefaultColorMap colorMap1; DefaultColorMap colorMap2; boost::queue q1; boost::queue q2; bidirectionalBFS(g, start, goal, q1, q2, visitor, colorMap1, colorMap2); } #endif abyss-2.2.4/Graph/BidirectionalBFSVisitor.h000066400000000000000000000024001361462241400205340ustar00rootroot00000000000000#ifndef BIDIRECTION_BFS_VISITOR_H #define BIDIRECTION_BFS_VISITOR_H 1 #include "Graph/Path.h" enum BFSVisitorResult { SUCCESS, ABORT_SEARCH, SKIP_ELEMENT }; template class BidirectionalBFSVisitor { public: typedef typename boost::graph_traits::vertex_descriptor Vertex; typedef typename boost::graph_traits::edge_descriptor Edge; typedef unsigned NumFrontierNodes; BidirectionalBFSVisitor() { } virtual ~BidirectionalBFSVisitor() { } virtual BFSVisitorResult discover_vertex(const Vertex&, const Graph&, Direction, NumFrontierNodes) { return SUCCESS; } virtual void examine_vertex(const Vertex&, const Graph&, Direction) { } virtual void finish_vertex(const Vertex&, const Graph&, Direction) { } virtual void examine_edge(const Edge&, const Graph&, Direction) { } virtual BFSVisitorResult common_edge(const Edge&, const Graph&, Direction) { return SUCCESS; } virtual BFSVisitorResult tree_edge(const Edge&, const Graph&, Direction) { return SUCCESS; } virtual BFSVisitorResult non_tree_edge(const Edge&, const Graph&, Direction) { return SUCCESS; } virtual void gray_target(const Edge&, const Graph&, Direction) { } virtual void black_target(const Edge&, const Graph&, Direction) { } }; #endif abyss-2.2.4/Graph/BreadthFirstSearch.h000066400000000000000000000165001361462241400175660ustar00rootroot00000000000000#ifndef DEPTHFIRSTSEARCH_H #define DEPTHFIRSTSEARCH_H 1 #include "Graph/DefaultColorMap.h" #include #include using boost::function_requires; using boost::graph_traits; using boost::property_traits; using boost::color_traits; /** return code from BFS visitor callbacks */ enum BFSVisitorResult { BFS_SUCCESS = 0, BFS_SKIP_ELEMENT, BFS_ABORT_SEARCH }; /** * Default BFS visitor that does nothing. Used as a placeholder when * no special visitor behaviour is needed. */ template class DefaultBFSVisitor { public: typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::edge_descriptor E; BFSVisitorResult discover_vertex(const V&, const G&) { return BFS_SUCCESS; } BFSVisitorResult examine_vertex(const V&, const G&) { return BFS_SUCCESS; } BFSVisitorResult finish_vertex(const V&, const G&) { return BFS_SUCCESS; } BFSVisitorResult examine_edge(const E&, const G&) { return BFS_SUCCESS; } BFSVisitorResult tree_edge(const E&, const G&) { return BFS_SUCCESS; } BFSVisitorResult non_tree_edge(const E&, const G&) { return BFS_SUCCESS; } BFSVisitorResult gray_target(const E&, const G&) { return BFS_SUCCESS; } BFSVisitorResult black_target(const E&, const G&) { return BFS_SUCCESS; } void post_processing() {} }; template static inline BFSVisitorResult bfsVisitEdge( const typename boost::graph_traits::edge_descriptor& e, bool isOutEdge, const Graph& g, Queue& queue, ColorMap& colorMap, Visitor& visitor) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename property_traits::value_type ColorValue; typedef color_traits Color; BFSVisitorResult result = BFS_SUCCESS; /* note: boost edges always go from source to target */ const V& v = isOutEdge ? target(e, g) : source(e, g); result = visitor.examine_edge(e, g); if (result != BFS_SUCCESS) return result; ColorValue color = get(colorMap, v); if (color == Color::white()) { result = visitor.tree_edge(e, g); if (result != BFS_SUCCESS) return result; result = visitor.discover_vertex(v, g); if (result != BFS_SUCCESS) return result; put(colorMap, v, Color::gray()); queue.push(v); } else { result = visitor.non_tree_edge(e, g); if (result != BFS_SUCCESS) return result; if (color == Color::gray()) { result = visitor.gray_target(e, g); } else { result = visitor.black_target(e, g); } } return result; } /** * An implementation of BFS that allows multiple start nodes and permits * terminating the search early. Visitors can terminate the search by * returning the BFS_ABORT_SEARCH result code from their callback routines. */ template static inline void breadthFirstSearchImpl( const VertexSet& startVertices, const Graph& g, bool undirected, ColorMap& colorMap, Visitor& visitor) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::edge_descriptor E; typedef typename boost::graph_traits::in_edge_iterator IEIt; typedef typename boost::graph_traits::out_edge_iterator OEIt; typedef typename VertexSet::const_iterator VertexListConstIt; typedef typename property_traits::value_type ColorValue; typedef color_traits Color; /* breadth-first search queue */ boost::queue queue; BFSVisitorResult result; IEIt iei, iei_end; OEIt oei, oei_end; /* push start vertices onto search queue */ for (VertexListConstIt it = startVertices.begin(); it != startVertices.end(); ++it) { ColorValue color = get(colorMap, *it); if (color == Color::white()) { result = visitor.discover_vertex(*it, g); if (result == BFS_SKIP_ELEMENT) continue; else if (result == BFS_ABORT_SEARCH) return; put(colorMap, *it, Color::gray()); } /* * note: vertex may already be black if user is reusing colorMap across * multiple searches */ if (color != Color::black()) { queue.push(*it); } } /* do breadth first search */ while (!queue.empty()) { V u = queue.top(); queue.pop(); result = visitor.examine_vertex(u, g); if (result == BFS_SKIP_ELEMENT) continue; else if (result == BFS_ABORT_SEARCH) return; for (boost::tie(oei, oei_end) = out_edges(u, g); oei != oei_end; ++oei) { const E& e = *oei; result = bfsVisitEdge(e, true, g, queue, colorMap, visitor); if (result == BFS_ABORT_SEARCH) return; } if (undirected) { for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; ++iei) { const E& e = *iei; result = bfsVisitEdge(e, false, g, queue, colorMap, visitor); if (result == BFS_ABORT_SEARCH) return; } } put(colorMap, u, Color::black()); result = visitor.finish_vertex(u, g); if (result == BFS_ABORT_SEARCH) return; } visitor.post_processing(); } template void breadthFirstSearch(const Graph& g, bool undirected, const typename graph_traits::vertex_descriptor& root) { typedef typename graph_traits::vertex_descriptor V; std::vector startVertices(1, root); DefaultColorMap colorMap; DefaultBFSVisitor visitor; breadthFirstSearchImpl(startVertices, g, undirected, colorMap, visitor); } template void breadthFirstSearch(const Graph& g, const typename graph_traits::vertex_descriptor& root) { breadthFirstSearch(g, false, root); } template void breadthFirstSearch( const typename boost::graph_traits::vertex_descriptor& root, const Graph& g, bool undirected, Visitor& visitor) { typedef typename graph_traits::vertex_descriptor V; std::vector startVertices(1, root); DefaultColorMap colorMap; breadthFirstSearchImpl(startVertices, g, undirected, colorMap, visitor); } template void breadthFirstSearch( const typename boost::graph_traits::vertex_descriptor& root, const Graph& g, Visitor& visitor) { breadthFirstSearch(root, g, false, visitor); } template void breadthFirstSearch( const typename boost::graph_traits::vertex_descriptor& root, const Graph& g, ColorMap& colorMap, Visitor& visitor) { typedef typename graph_traits::vertex_descriptor V; std::vector startVertices(1, root); breadthFirstSearchImpl(startVertices, g, false, colorMap, visitor); } template void breadthFirstSearchMulti( const VertexSet& startVertices, const Graph& g, Visitor& visitor) { DefaultColorMap colorMap; breadthFirstSearchImpl(startVertices, g, false, colorMap, visitor); } template void breadthFirstSearchMulti( const VertexSet& startVertices, const Graph& g, bool undirected, Visitor& visitor) { DefaultColorMap colorMap; breadthFirstSearchImpl(startVertices, g, undirected, colorMap, visitor); } template void breadthFirstSearch(const IncidenceGraph& g, typename graph_traits::vertex_descriptor root, BFSVisitor& visitor) { typedef typename graph_traits::vertex_descriptor V; DefaultColorMap colorMap; boost::queue q; breadthFirstSearch(g, root, q, visitor, colorMap); } #endif abyss-2.2.4/Graph/ConstrainedBFSVisitor.h000066400000000000000000000070221361462241400202420ustar00rootroot00000000000000#ifndef CONSTRAINED_BFS_VISITOR_H #define CONSTRAINED_BFS_VISITOR_H #include "Common/UnorderedMap.h" #include "Common/IOUtil.h" #include "Graph/BreadthFirstSearch.h" #include "Graph/DefaultColorMap.h" #include "Graph/Path.h" #include "Graph/HashGraph.h" #include "Graph/AllPathsSearch.h" #include #include #include #include #include template class ConstrainedBFSVisitor : public DefaultBFSVisitor { public: typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::edge_descriptor E; typedef unsigned short depth_t; private: typedef std::vector Predecessors; typedef unordered_map > OutDegreeMap; typedef unordered_map > DepthMap; HashGraph m_traversalGraph; OutDegreeMap m_outDegree; DepthMap m_depthMap; V m_start; V m_goal; depth_t m_minDepth; depth_t m_maxDepth; unsigned m_maxBranches; DefaultColorMap& m_colorMap; bool m_bFoundGoal; depth_t m_maxDepthVisited; unsigned m_branches; bool m_tooManyBranches; public: ConstrainedBFSVisitor( const V& start, const V& goal, depth_t minDepth, depth_t maxDepth, unsigned maxBranches, DefaultColorMap& colorMap) : m_start(start), m_goal(goal), m_minDepth(minDepth), m_maxDepth(maxDepth), m_maxBranches(maxBranches), m_colorMap(colorMap), m_bFoundGoal(false), m_maxDepthVisited(0), m_branches(1), m_tooManyBranches(false) {} #if 0 // for debugging BFSVisitorResult examine_vertex(const V& v, const G& g) { std::cout << "visiting vertex: " << v << "\n"; return BFS_SUCCESS; } #endif BFSVisitorResult examine_edge(const E& e, const G& g) { V u = source(e, g); V v = target(e, g); #if 0 // for debugging std::cout << "visiting edge: (" << u << ", " << v << ")\n"; #endif if (m_tooManyBranches) { put(m_colorMap, v, boost::black_color); return BFS_ABORT_SEARCH; } if (v == m_goal) m_bFoundGoal = true; // record history of traversal, so that we can trace // backwards from goal to start in pathsToGoal() add_edge(v, u, m_traversalGraph); // track depth of nodes and go no deeper than m_maxDepth if (get(m_colorMap, v) == boost::white_color) // tree edge m_depthMap[v] = m_depthMap[u] + 1; if (m_depthMap[v] >= m_maxDepth) put(m_colorMap, v, boost::black_color); if (m_depthMap[v] > m_maxDepthVisited) m_maxDepthVisited = m_depthMap[v]; // track number of branches and abort if we exceed m_maxBranches if (m_maxBranches != NO_LIMIT && ++m_outDegree[u] > 1) m_branches++; if (m_maxBranches != NO_LIMIT && m_branches > m_maxBranches) { m_tooManyBranches = true; put(m_colorMap, v, boost::black_color); } return BFS_SUCCESS; } AllPathsSearchResult uniquePathToGoal() { AllPathsSearchResult result = pathsToGoal(1); return result; } AllPathsSearchResult pathsToGoal(unsigned maxPaths) { AllPathsSearchResult result; if (m_tooManyBranches) { result.resultCode = TOO_MANY_BRANCHES; return result; } else if (!m_bFoundGoal) { result.resultCode = NO_PATH; return result; } result = allPathsSearch(m_traversalGraph, m_goal, m_start, maxPaths, m_minDepth, m_maxDepth, NO_LIMIT); if (result.resultCode == FOUND_PATH) { for (unsigned i = 0; i < result.paths.size(); i++) reverse(result.paths[i].begin(), result.paths[i].end()); } return result; } depth_t getMaxDepthVisited() { return m_maxDepthVisited; } }; #endif /* CONSTRAINED_BFS_VISITOR_H */ abyss-2.2.4/Graph/ConstrainedBidiBFSVisitor.h000066400000000000000000000301331361462241400210310ustar00rootroot00000000000000#ifndef CONSTRAINED_BIDI_BFS_VISITOR_H #define CONSTRAINED_BIDI_BFS_VISITOR_H #include "Common/UnorderedMap.h" #include "Common/UnorderedSet.h" #include "Common/IOUtil.h" #include "Graph/Path.h" #include "Graph/HashGraph.h" #include "Graph/BidirectionalBFSVisitor.h" #include "Graph/AllPathsSearch.h" #include "Common/MemUtils.h" #include #include #include #include #include template class ConstrainedBidiBFSVisitor : public BidirectionalBFSVisitor { protected: typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::edge_descriptor E; typedef unsigned short depth_t; typedef std::vector< Path > PathList; typedef unordered_map > DepthMap; struct EdgeHash { const G& m_g; EdgeHash(const G& g) : m_g(g) { } std::size_t operator()(const E& e) const { V u = source(e, m_g); V v = target(e, m_g); return hash()(u) ^ hash()(v); } }; typedef unordered_set EdgeSet; const G& m_graph; V m_start; V m_goal; /** maximum number of paths to discover before aborting search */ unsigned m_maxPaths; /** records history of forward/reverse traversals */ HashGraph m_traversalGraph[2]; /** records depth of vertices during forward/reverse traversal */ DepthMap m_depthMap[2]; /** depth limits for forward/reverse traversal */ depth_t m_maxDepth[2]; /** max depth for forward/reverse traversal */ depth_t m_maxDepthVisited[2]; depth_t m_minPathLength; depth_t m_maxPathLength; /** maximum number of frontier nodes allowed at any given * time during forward/reverse traversal */ unsigned m_maxBranches; /** max number of edges to traverse during search */ unsigned m_maxCost; /** number of edges traversed so far */ unsigned m_cost; /** memory limit for graph search */ size_t m_memLimit; /** controls frequency of memory limit checks */ size_t m_memCheckCounter; /** true if we have exceeded the memory limit */ bool m_exceededMemLimit; /** the max number of frontier nodes we had at any time * during forward/reverse traversal (up to a limit * of m_maxBranches) */ unsigned m_peakActiveBranches; bool m_tooManyBranches; bool m_maxCostExceeded; bool m_tooManyPaths; unsigned long long m_numNodesVisited; /** edges that connect the forward and reverse traversals */ EdgeSet m_commonEdges; PathList m_pathsFound; public: ConstrainedBidiBFSVisitor( const G& graph, const V& start, const V& goal, unsigned maxPaths, depth_t minPathLength, depth_t maxPathLength, unsigned maxBranches, unsigned maxCost, size_t memLimit ) : m_graph(graph), m_start(start), m_goal(goal), m_maxPaths(maxPaths), m_minPathLength(minPathLength), m_maxPathLength(maxPathLength), m_maxBranches(maxBranches), m_maxCost(maxCost), m_cost(0), m_memLimit(memLimit), m_memCheckCounter(0), m_exceededMemLimit(false), m_peakActiveBranches(0), m_tooManyBranches(false), m_maxCostExceeded(false), m_tooManyPaths(false), m_numNodesVisited(0), m_commonEdges(m_maxPaths, EdgeHash(m_graph)) { depth_t maxDepth = maxPathLength - 1; m_maxDepth[FORWARD] = maxDepth / 2 + maxDepth % 2; m_maxDepth[REVERSE] = maxDepth / 2; m_maxDepthVisited[FORWARD] = 0; m_maxDepthVisited[REVERSE] = 0; // special case if (start == goal && 1 >= m_minPathLength) { Path path; path.push_back(start); m_pathsFound.push_back(path); } } #if 0 // for debugging void examine_vertex(const V& v, const G&, Direction dir) { std::cout << "visiting vertex: " << v << " from dir: " << dir << "\n"; } void examine_edge(const E& e, const G& g, Direction dir) { V u = source(e, g); V v = target(e, g); std::cout << "visiting edge: (" << u << "," << v << ") from dir: " << dir << "\n"; } #endif BFSVisitorResult discover_vertex(const V&, const G&, Direction, unsigned numActiveBranches) { if (m_maxBranches != NO_LIMIT && numActiveBranches >= m_maxBranches) { m_tooManyBranches = true; return ABORT_SEARCH; } m_numNodesVisited++; // include new branch started by vertex v numActiveBranches++; if (numActiveBranches > m_peakActiveBranches) m_peakActiveBranches = numActiveBranches; return SUCCESS; } BFSVisitorResult tree_edge(const E& e, const G& g, Direction dir) { if (m_cost >= m_maxCost) { m_maxCostExceeded = true; return ABORT_SEARCH; } m_cost++; if (!updateTargetDepth(e, g, dir)) return SKIP_ELEMENT; return recordEdgeTraversal(e, g, dir); } BFSVisitorResult non_tree_edge(const E& e, const G& g, Direction dir) { if (m_cost >= m_maxCost) { m_maxCostExceeded = true; return ABORT_SEARCH; } m_cost++; return recordEdgeTraversal(e, g, dir); } BFSVisitorResult common_edge(const E& e, const G& g, Direction dir) { if (m_cost >= m_maxCost) { m_maxCostExceeded = true; return ABORT_SEARCH; } m_cost++; V u = source(e, g); V v = target(e, g); const V& parent = (dir == FORWARD) ? u : v; if (m_depthMap[dir][parent] >= m_maxDepth[dir]) return SKIP_ELEMENT; return recordCommonEdge(e); } PathSearchResult uniquePathToGoal(Path& path) { std::vector< Path > paths; PathSearchResult result = pathsToGoal(paths); if (paths.size() > 1) { return TOO_MANY_PATHS; } else if (result == FOUND_PATH && paths.size() == 1) { path = paths[0]; return FOUND_PATH; } return result; } PathSearchResult pathsToGoal(PathList& pathsFound) { if (m_tooManyPaths) return TOO_MANY_PATHS; else if (m_tooManyBranches) return TOO_MANY_BRANCHES; else if (m_maxCostExceeded) return MAX_COST_EXCEEDED; else if (m_exceededMemLimit) return EXCEEDED_MEM_LIMIT; PathSearchResult result = buildPaths(); if (result == FOUND_PATH) pathsFound = m_pathsFound; return result; } depth_t getMaxDepthVisited(Direction dir) { return m_maxDepthVisited[dir]; } unsigned getMaxActiveBranches() { return m_peakActiveBranches; } unsigned long long getNumNodesVisited() { return m_numNodesVisited; } unsigned getSearchCost() { return m_cost; } size_t approxMemUsage() { return m_traversalGraph[FORWARD].approxMemSize() + m_traversalGraph[REVERSE].approxMemSize() + approxMemSize(m_depthMap[FORWARD]) + approxMemSize(m_depthMap[REVERSE]); } void getTraversalGraph(HashGraph& traversalGraph) { typedef typename HashGraph::vertex_iterator vertex_iterator; typedef typename HashGraph::adjacency_iterator adjacency_iterator; Direction dir[] = { FORWARD, REVERSE }; for (unsigned i = 0; i < 2; i++) { HashGraph& g = m_traversalGraph[dir[i]]; vertex_iterator vi, vi_end; boost::tie(vi, vi_end) = vertices(g); for(; vi != vi_end; vi++) { adjacency_iterator ai, ai_end; boost::tie(ai, ai_end) = adjacent_vertices(*vi, g); for(; ai != ai_end; ai++) { add_edge(*ai, *vi, traversalGraph); } } } } protected: BFSVisitorResult recordCommonEdge(const E& e) { m_commonEdges.insert(e); if (m_maxPaths != NO_LIMIT && m_commonEdges.size() > m_maxPaths) { m_tooManyPaths = true; return ABORT_SEARCH; } /** * Tricky point: * * Recording the common edges in the both the * forward and reverse traversal histories * is necessary for edge cases where forward * or reverse traversals are limited to * a depth of zero. (In other words, * the traversal graph has zero edges * and exactly one vertex which is either * the start or the goal vertex.) * * I cannot find a way to add a vertex * with a specific vertex_descriptor * to a graph using the Boost graph API. * The only way seems to be creating an edge * that has the given vertex_descriptor * as the source or target. */ BFSVisitorResult result = recordEdgeTraversal(e, m_graph, FORWARD); if (result != SUCCESS) return result; return recordEdgeTraversal(e, m_graph, REVERSE); } BFSVisitorResult checkMemLimit() { const size_t MEM_COUNTER_ROLLOVER = 1000; m_memCheckCounter++; if (m_memCheckCounter >= MEM_COUNTER_ROLLOVER) { m_memCheckCounter = 0; if (approxMemUsage() > m_memLimit) { m_exceededMemLimit = true; return ABORT_SEARCH; } } return SUCCESS; } /** * Record history of edge traversal, so that we can retrace * paths from a common edge to start/goal. */ BFSVisitorResult recordEdgeTraversal(const E& e, const G& g, Direction dir) { BFSVisitorResult result = checkMemLimit(); if (result != SUCCESS) return result; V u = source(e, g); V v = target(e, g); if (dir == FORWARD) add_edge(v, u, m_traversalGraph[FORWARD]); else add_edge(u, v, m_traversalGraph[REVERSE]); return result; } /** * Record the depth of a newly visited vertex. * @return true if the vertex is visitable is less than the max * depth limit false otherwise. */ bool updateTargetDepth(const E& e, const G& g, Direction dir) { const V& parent = (dir == FORWARD) ? source(e, g) : target(e, g); const V& child = (dir == FORWARD) ? target(e, g) : source(e, g); depth_t parentDepth = m_depthMap[dir][parent]; if (parentDepth == m_maxDepth[dir]) return false; depth_t childDepth = parentDepth + 1; m_depthMap[dir][child] = childDepth; if (childDepth > m_maxDepthVisited[dir]) m_maxDepthVisited[dir] = childDepth; return true; } PathSearchResult buildPaths() { PathSearchResult overallResult = NO_PATH; // m_pathsFound will already contain one sol'n // in the special case where start_kmer == goal_kmer if (!m_pathsFound.empty()) overallResult = FOUND_PATH; typename EdgeSet::const_iterator i = m_commonEdges.begin(); for (; i != m_commonEdges.end(); i++) { PathSearchResult result = buildPaths(*i); if (result == FOUND_PATH) { overallResult = FOUND_PATH; } else if (result != FOUND_PATH && result != NO_PATH) { // we have encountered a failure case // (e.g. TOO_MANY_PATHS) overallResult = result; break; } } return overallResult; } PathSearchResult buildPaths(const E& common_edge) { if (m_cost > m_maxCost) { m_maxCostExceeded = true; return MAX_COST_EXCEEDED; } V u = source(common_edge, m_graph); V v = target(common_edge, m_graph); // find paths from common edge to start vertex (forward traversal) unsigned maxPathsToStart = m_maxPaths - m_pathsFound.size(); PathSearchResult resultCode; AllPathsSearchResult leftResult = allPathsSearch( m_traversalGraph[FORWARD], u, m_start, maxPathsToStart, 0, m_maxDepth[FORWARD], m_maxCost - m_cost); m_cost += leftResult.cost; resultCode = leftResult.resultCode; if (resultCode == FOUND_PATH) { // find paths from common edge to goal vertex (reverse traversal) unsigned maxPathsToGoal = (m_maxPaths - m_pathsFound.size()) / leftResult.paths.size(); AllPathsSearchResult rightResult = allPathsSearch(m_traversalGraph[REVERSE], v, m_goal, maxPathsToGoal, 0, m_maxDepth[REVERSE], m_maxCost - m_cost); m_cost += rightResult.cost; resultCode = rightResult.resultCode; if (resultCode == FOUND_PATH) resultCode = buildPaths(leftResult.paths, rightResult.paths); } // result == FOUND_PATH (common edge => start) if (resultCode == MAX_COST_EXCEEDED) m_maxCostExceeded = true; else if (resultCode == TOO_MANY_PATHS) m_tooManyPaths = true; return resultCode; } PathSearchResult buildPaths(const PathList& pathsToStart, const PathList& pathsToGoal) { bool addedPath = false; typename PathList::const_iterator pathToStart = pathsToStart.begin(); for (; pathToStart != pathsToStart.end(); pathToStart++) { typename PathList::const_iterator pathToGoal = pathsToGoal.begin(); for(; pathToGoal != pathsToGoal.end(); pathToGoal++) { if (pathToStart->size() + pathToGoal->size() < m_minPathLength || pathToStart->size() + pathToGoal->size() > m_maxPathLength) continue; m_pathsFound.push_back(*pathToStart); Path& mergedPath = m_pathsFound.back(); reverse(mergedPath.begin(), mergedPath.end()); m_pathsFound.back().insert(mergedPath.end(), pathToGoal->begin(), pathToGoal->end()); addedPath = true; } } return (addedPath ? FOUND_PATH : NO_PATH); } }; #endif /* CONSTRAINED_BFS_VISITOR_H */ abyss-2.2.4/Graph/ConstrainedSearch.h000066400000000000000000000101071361462241400174530ustar00rootroot00000000000000#ifndef CONSTRAINEDSEARCH_H #define CONSTRAINEDSEARCH_H 1 #include "Common/ContigPath.h" #include "Common/ContigProperties.h" #include "Graph/ContigGraph.h" #include "Graph/DirectedGraph.h" #include "Graph/Properties.h" #include #include // for INT_MIN #include #include #include #include namespace opt { unsigned maxCost = 100000; /** Abort the search after visiting maxPaths solutions. */ const unsigned maxPaths = 200; } typedef std::pair Constraint; typedef std::vector Constraints; typedef std::vector ContigPaths; /** Compare the distance of two constraints. */ static inline bool compareDistance( const Constraint& a, const Constraint& b) { return a.second < b.second; } /** Compare the ID of a constraint. */ static inline bool compareID(const Constraint& constraint, const ContigNode& key) { return constraint.first < key; } /** Find a constraint by ID. */ static inline Constraints::iterator findConstraint( Constraints& constraints, const ContigNode& key) { Constraints::iterator it = lower_bound( constraints.begin(), constraints.end(), key, compareID); return it != constraints.end() && it->first == key ? it : constraints.end(); } /** Find paths through the graph that satisfy the constraints. * @return false if the search exited early */ template bool constrainedSearch(const Graph& g, vertex_descriptor u, Constraints& constraints, Constraints::const_iterator nextConstraint, unsigned satisfied, ContigPath& path, ContigPaths& solutions, int distance, unsigned& visitedCount) { typedef typename graph_traits::out_edge_iterator out_edge_iterator; assert(satisfied < constraints.size()); static const int SATISFIED = INT_MAX; if (!path.empty()) { vertex_descriptor v = path.back(); Constraints::iterator it = findConstraint(constraints, v); if (it != constraints.end() && it->second != SATISFIED) { if (distance > it->second) return true; // This constraint cannot be met. if (++satisfied == constraints.size()) { // All the constraints have been satisfied. solutions.push_back(path); return solutions.size() <= opt::maxPaths; } // This constraint has been satisfied. int constraint = it->second; it->second = SATISFIED; if (!constrainedSearch(g, u, constraints, nextConstraint, satisfied, path, solutions, distance, visitedCount)) return false; it->second = constraint; return true; } if (++visitedCount >= opt::maxCost) return false; // Too complex. // Check that the next constraint has not been violated. while (distance > nextConstraint->second && findConstraint(constraints, nextConstraint->first)->second == SATISFIED) ++nextConstraint; // This constraint is satisfied. if (distance > nextConstraint->second) return true; // This constraint cannot be met. distance += g[v].length; u = v; } path.push_back(vertex_descriptor()); std::pair adj = g.out_edges(u); for (out_edge_iterator it = adj.first; it != adj.second; ++it) { path.back() = target(*it, g); if (!constrainedSearch(g, u, constraints, nextConstraint, satisfied, path, solutions, distance + g[*it].distance, visitedCount)) return false; } assert(!path.empty()); path.pop_back(); return true; } /** Find paths through the graph that satisfy the constraints. * @return false if the search exited early */ template bool constrainedSearch(const Graph& g, vertex_descriptor v, Constraints& constraints, ContigPaths& paths, unsigned& cost) { if (constraints.empty()) return false; // Sort the constraints by ID. sort(constraints.begin(), constraints.end()); // Sort the constraints by distance. Constraints queue(constraints); sort(queue.begin(), queue.end(), compareDistance); ContigPath path; constrainedSearch(g, v, constraints, queue.begin(), 0, path, paths, 0, cost); return cost >= opt::maxCost ? false : !paths.empty(); } #endif abyss-2.2.4/Graph/ContigGraph.h000066400000000000000000000273331361462241400162720ustar00rootroot00000000000000#ifndef CONTIGGRAPH_H #define CONTIGGRAPH_H 1 #include "Common/ContigID.h" #include "Graph/Properties.h" #include #include #include using boost::graph_traits; /** A contig graph is a directed graph with the property that * the edge (u,v) implies the existence of the edge (~v,~u). */ template class ContigGraph : public G { public: /** Copy constructors */ ContigGraph(const ContigGraph&) = default; ContigGraph(ContigGraph&&) = default; ContigGraph& operator=(const ContigGraph&) = default; ContigGraph& operator=(ContigGraph&&) = default; typedef G base_type; // Graph typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::directed_category directed_category; typedef typename graph_traits::traversal_category traversal_category; typedef typename graph_traits::edge_parallel_category edge_parallel_category; // IncidenceGraph typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename graph_traits::out_edge_iterator out_edge_iterator; typedef typename graph_traits::degree_size_type degree_size_type; // AdjacencyGraph typedef typename graph_traits::adjacency_iterator adjacency_iterator; // VertexListGraph typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename graph_traits::vertices_size_type vertices_size_type; // EdgeListGraph typedef typename graph_traits::edge_iterator edge_iterator; typedef typename graph_traits::edges_size_type edges_size_type; // VertexMutablePropertyGraph typedef typename vertex_property::type vertex_property_type; // EdgeMutablePropertyGraph typedef typename edge_property::type edge_property_type; // BidirectionalGraph /** Iterate through the in-edges. */ class in_edge_iterator : public std::iterator { /** Return the complement (~v, ~u) of the edge (u, v). */ static edge_descriptor complement(const edge_descriptor& e) { return std::pair( e.second ^ 1, e.first ^ 1); } public: in_edge_iterator() { } in_edge_iterator(typename graph_traits::out_edge_iterator it) : m_it(it) { } edge_descriptor operator*() const { return complement(*m_it); } bool operator==(const in_edge_iterator& it) const { return m_it == it.m_it; } bool operator!=(const in_edge_iterator& it) const { return m_it != it.m_it; } in_edge_iterator& operator++() { ++m_it; return *this; } in_edge_iterator operator++(int) { in_edge_iterator it = *this; ++*this; return it; } private: out_edge_iterator m_it; }; public: /** Construct an empty contig graph. */ ContigGraph() { } /** Construct a contig graph with n vertices. The underlying * directed graph has two vertices for each contig. */ ContigGraph(vertices_size_type n) : G(2 * n) { } /** Return the in degree of vertex v. */ degree_size_type in_degree(vertex_descriptor v) const { return G::out_degree(get(vertex_complement, *this, v)); } /** Remove all out edges from vertex u. */ void clear_out_edges(vertex_descriptor u) { std::pair adj = G::adjacent_vertices(u); for (adjacency_iterator v = adj.first; v != adj.second; ++v) { vertex_descriptor uc = get(vertex_complement, *this, u); vertex_descriptor vc = get(vertex_complement, *this, *v); if (vc == u) { // When ~v == u, removing (~v,~u), which is (u,~u), // would invalidate our iterator. This edge will be // removed by clear_out_edges. } else G::remove_edge(vc, uc); } G::clear_out_edges(u); } /** Remove all in edges from vertex v. */ void clear_in_edges(vertex_descriptor v) { clear_out_edges(get(vertex_complement, *this, v)); } /** Remove all edges to and from vertex v. */ void clear_vertex(vertex_descriptor v) { clear_out_edges(v); clear_in_edges(v); } /** Add a vertex to this graph. */ vertex_descriptor add_vertex( const vertex_property_type& data = vertex_property_type()) { vertex_descriptor v = G::add_vertex(data); G::add_vertex(data); return v; } /** Remove vertex v from this graph. It is assumed that there * are no edges to or from vertex v. It is best to call * clear_vertex before remove_vertex. */ void remove_vertex(vertex_descriptor v) { G::remove_vertex(v); G::remove_vertex(get(vertex_complement, *this, v)); } /** Add edge (u,v) to this graph. */ std::pair add_edge(vertex_descriptor u, vertex_descriptor v) { vertex_descriptor uc = get(vertex_complement, *this, u); vertex_descriptor vc = get(vertex_complement, *this, v); std::pair e = G::add_edge(u, v); if (u != vc) G::add_edge(vc, uc); return e; } /** Add edge (u,v) to this graph. */ std::pair add_edge(vertex_descriptor u, vertex_descriptor v, const edge_property_type& ep) { vertex_descriptor uc = get(vertex_complement, *this, u); vertex_descriptor vc = get(vertex_complement, *this, v); std::pair e = G::add_edge(u, v, ep); if (u != vc) G::add_edge(vc, uc, ep); return e; } /** Remove the edge (u,v) from this graph. */ void remove_edge(vertex_descriptor u, vertex_descriptor v) { vertex_descriptor uc = get(vertex_complement, *this, u); vertex_descriptor vc = get(vertex_complement, *this, v); G::remove_edge(u, v); if (u != vc) G::remove_edge(vc, uc); } /** Remove the edge e from this graph. */ void remove_edge(edge_descriptor e) { remove_edge(source(e, *this), target(e, *this)); } }; namespace std { template inline void swap(ContigGraph& a, ContigGraph& b) { a.swap(b); } } // IncidenceGraph template std::pair< typename ContigGraph::out_edge_iterator, typename ContigGraph::out_edge_iterator> out_edges( typename ContigGraph::vertex_descriptor u, const ContigGraph& g) { return g.out_edges(u); } template typename ContigGraph::degree_size_type out_degree( typename ContigGraph::vertex_descriptor u, const ContigGraph& g) { return g.out_degree(u); } // BidirectionalGraph template std::pair< typename ContigGraph::in_edge_iterator, typename ContigGraph::in_edge_iterator> in_edges( typename ContigGraph::vertex_descriptor u, const ContigGraph& g) { typedef typename ContigGraph::in_edge_iterator in_edge_iterator; typedef typename ContigGraph::out_edge_iterator out_edge_iterator; std::pair it = out_edges(get(vertex_complement, g, u), g); return std::pair( it.first, it.second); } template typename ContigGraph::degree_size_type in_degree( typename ContigGraph::vertex_descriptor u, const ContigGraph& g) { return g.in_degree(u); } // AdjacencyGraph template std::pair< typename ContigGraph::adjacency_iterator, typename ContigGraph::adjacency_iterator> adjacent_vertices( typename ContigGraph::vertex_descriptor u, const ContigGraph& g) { return g.adjacent_vertices(u); } // VertexListGraph template typename ContigGraph::vertices_size_type num_vertices(const ContigGraph& g) { return g.num_vertices(); } template std::pair::vertex_iterator, typename ContigGraph::vertex_iterator> vertices(const ContigGraph& g) { return g.vertices(); } // EdgeListGraph template typename ContigGraph::edges_size_type num_edges(const ContigGraph& g) { return g.num_edges(); } template std::pair::edge_iterator, typename ContigGraph::edge_iterator> edges(const ContigGraph& g) { return g.edges(); } // AdjacencyMatrix template std::pair::edge_descriptor, bool> edge( typename ContigGraph::vertex_descriptor u, typename ContigGraph::vertex_descriptor v, const ContigGraph& g) { return g.edge(u, v); } // VertexMutableGraph template typename ContigGraph::vertex_descriptor add_vertex(ContigGraph& g) { return g.add_vertex(); } template void remove_vertex( typename ContigGraph::vertex_descriptor u, ContigGraph& g) { g.remove_vertex(u); } // EdgeMutableGraph template void clear_vertex( typename ContigGraph::vertex_descriptor u, ContigGraph& g) { g.clear_vertex(u); } template std::pair::edge_descriptor, bool> add_edge( typename ContigGraph::vertex_descriptor u, typename ContigGraph::vertex_descriptor v, ContigGraph& g) { return g.add_edge(u, v); } template void remove_edge( typename ContigGraph::vertex_descriptor u, typename ContigGraph::vertex_descriptor v, ContigGraph& g) { return g.remove_edge(u, v); } template void remove_edge( typename ContigGraph::edge_descriptor e, ContigGraph& g) { g.remove_edge(e); } // MutableIncidenceGraph template void clear_out_edges( typename ContigGraph::vertex_descriptor u, ContigGraph& g) { g.clear_out_edges(u); } // MutableBidirectionalGraph template void clear_in_edges( typename ContigGraph::vertex_descriptor u, ContigGraph& g) { g.clear_in_edges(u); } // PropertyGraph /** Return true if this vertex has been removed. */ template bool get(vertex_removed_t tag, const ContigGraph& g, typename ContigGraph::vertex_descriptor u) { return get(tag, static_cast(g), u); } template void put(vertex_removed_t tag, ContigGraph& g, typename ContigGraph::vertex_descriptor u, bool flag) { put(tag, static_cast(g), u, flag); put(tag, static_cast(g), get(vertex_complement, g, u), flag); } /** Return the properties of the edge of iterator eit. */ template const typename ContigGraph::edge_property_type& get(edge_bundle_t, const ContigGraph&, typename ContigGraph::out_edge_iterator eit) { return eit.get_property(); } // PropertyGraph template typename vertex_bundle_type::type get(vertex_bundle_t, const ContigGraph& g, typename ContigGraph::vertex_descriptor u) { return g[u]; } template typename edge_bundle_type::type get(edge_bundle_t, const ContigGraph& g, typename ContigGraph::edge_descriptor e) { return g[e]; } // PropertyGraph namespace boost { template struct property_map, vertex_index_t> { typedef typename property_map::type type; typedef type const_type; }; } /** Return the complement of the specified vertex. */ template typename graph_traits::vertex_descriptor get(vertex_complement_t, const ContigGraph&, typename graph_traits::vertex_descriptor u) { return u ^ 1; } /** Return the contig index of the specified vertex. */ template ContigID get(vertex_contig_index_t, const ContigGraph&, typename graph_traits::vertex_descriptor u) { return u.contigIndex(); } /** Return the sense of the specified vertex. */ template bool get(vertex_sense_t, const ContigGraph&, typename graph_traits::vertex_descriptor u) { return u.sense(); } // VertexMutablePropertyGraph template typename ContigGraph::vertex_descriptor add_vertex( const typename vertex_property::type& vp, ContigGraph& g) { return g.add_vertex(vp); } // EdgeMutablePropertyGraph template std::pair::edge_descriptor, bool> add_edge( typename ContigGraph::vertex_descriptor u, typename ContigGraph::vertex_descriptor v, const typename ContigGraph::edge_property_type& ep, ContigGraph& g) { return g.add_edge(u, v, ep); } #endif abyss-2.2.4/Graph/ContigGraphAlgorithms.h000066400000000000000000000255161361462241400203250ustar00rootroot00000000000000#ifndef CONTIGGRAPHALGORITHMS_H #define CONTIGGRAPHALGORITHMS_H 1 #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 #include #include #include #include #include using boost::graph_traits; /** Return true if the edge e is a palindrome. */ template struct IsPalindrome : std::unary_function::edge_descriptor, bool> { IsPalindrome(const Graph& g) : m_g(g) {} bool operator()(typename graph_traits::edge_descriptor e) const { return source(e, m_g) == get(vertex_complement, m_g, target(e, m_g)); } private: const Graph& m_g; }; /** Return whether the outgoing edge of vertex u is contiguous. */ template bool contiguous_out(const Graph& g, typename graph_traits::vertex_descriptor u) { return out_degree(u, g) == 1 && in_degree(*adjacent_vertices(u, g).first, g) == 1; } /** Return whether the incoming edge of vertex u is contiguous. */ template bool contiguous_in(const Graph& g, typename graph_traits::vertex_descriptor u) { return contiguous_out(g, get(vertex_complement, g, u)); } /** Add the outgoing edges of vertex u to vertex uout. */ template void copy_out_edges( Graph& g, typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor uout) { typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename graph_traits::out_edge_iterator out_edge_iterator; typedef typename edge_property::type edge_property_type; assert(u != uout); std::pair edges = g.out_edges(u); bool palindrome = false; edge_property_type palindrome_ep; for (out_edge_iterator e = edges.first; e != edges.second; ++e) { vertex_descriptor v = target(*e, g); vertex_descriptor vc = get(vertex_complement, g, v); if (vc == u) { // When ~v == u, adding the edge (~v,~u), which is (u,~u), // would invalidate our iterator. Add the edge after this // loop completes. palindrome = true; palindrome_ep = g[*e]; } else g.add_edge(uout, v, g[*e]); } if (palindrome) { vertex_descriptor uc = get(vertex_complement, g, u); vertex_descriptor uoutc = get(vertex_complement, g, uout); g.add_edge(uout, uc, palindrome_ep); g.add_edge(uout, uoutc, palindrome_ep); } } /** Add the incoming edges of vertex u to vertex v. */ template void copy_in_edges(Graph& g, typename Graph::vertex_descriptor u, typename Graph::vertex_descriptor v) { copy_out_edges(g, get(vertex_complement, g, u), get(vertex_complement, g, v)); } /** Assemble a path of unambigous out edges starting at vertex u. * u itself is not copied to out. */ template OutIt extend(const Graph& g, typename Graph::vertex_descriptor u, OutIt out) { typedef typename graph_traits::vertex_descriptor vertex_descriptor; std::set seen; while (out_degree(u, g) == 1 && seen.insert(u).second) { u = *adjacent_vertices(u, g).first; *out++ = u; } return out; } /** Assemble an unambiguous path starting at vertex u. * Every edge must satisfy the predicate. */ template OutIt assemble_if(const Graph& g, typename Graph::vertex_descriptor u, OutIt out, Predicate pred) { typedef typename graph_traits::edge_descriptor edge_descriptor; while (contiguous_out(g, u)) { edge_descriptor e = *out_edges(u, g).first; if (!pred(e)) break; *out++ = u; u = target(e, g); } *out++ = u; return out; } /** Remove vertices in the sequence [first, last) from the graph * for which the predicate p is true. Edges incident to those vertices * are removed as well. */ template void remove_vertex_if(Graph& g, It first, It last, Predicate p) { for_each_if( first, last, [&g](const ContigNode& c) { return g.clear_vertex(c); }, p); for_each_if( first, last, [&g](const ContigNode& c) { return g.remove_vertex(c); }, p); } /** Add the vertex and edge propeties of the path [first, last). */ template VP addProp(const Graph& g, It first, It last, const VP*) { typedef typename graph_traits::vertex_descriptor vertex_descriptor; assert(first != last); VP vp = get(vertex_bundle, g, *first); for (It it = first + 1; it != last; ++it) { vertex_descriptor u = *(it - 1); vertex_descriptor v = *it; vp += get(edge_bundle, g, u, v); vp += get(vertex_bundle, g, v); } return vp; } template no_property addProp(const Graph&, It, It, const no_property*) { return no_property(); } template typename vertex_property::type addProp(const Graph& g, It first, It last) { return addProp(g, first, last, (typename vertex_property::type*)NULL); } /** Merge the vertices in the sequence [first, last). * Create a new vertex whose property is the sum of [first, last). * Remove the vertices [first, last). */ template typename graph_traits::vertex_descriptor merge(Graph& g, It first, It last) { typedef typename graph_traits::vertex_descriptor vertex_descriptor; assert(first != last); vertex_descriptor u = add_vertex(addProp(g, first, last), g); copy_in_edges(g, *first, u); copy_out_edges(g, *(last - 1), u); return u; } /** Assemble unambiguous paths. Write the paths to out. * Every edge must satisfy the predicate. */ template OutIt assemble_if(Graph& g, OutIt out, Predicate pred0) { typedef typename Graph::vertex_iterator vertex_iterator; // pred(e) = !isPalindrome(e) && pred0(e) binary_compose, std::unary_negate>, Predicate> pred( compose2(std::logical_and(), std::not1(IsPalindrome(g)), pred0)); std::pair uit = g.vertices(); for (vertex_iterator u = uit.first; u != uit.second; ++u) { if (!contiguous_out(g, *u) || contiguous_in(g, *u) || !pred(*out_edges(*u, g).first)) continue; typename output_iterator_traits::value_type path; assemble_if(g, *u, back_inserter(path), pred); assert(path.size() >= 2); assert(path.front() != path.back()); merge(g, path.begin(), path.end()); remove_vertex_if( g, path.begin(), path.end(), [](const ContigNode& c) { return !c.ambiguous(); }); *out++ = path; } return out; } /** Assemble unambiguous paths. Write the paths to out. */ template OutIt assemble(Graph& g, OutIt out) { typedef typename graph_traits::edge_descriptor edge_descriptor; return assemble_if(g, out, True()); } /** Return true if the edge e is +ve sense. */ template struct IsPositive : std::unary_function::edge_descriptor, bool> { IsPositive(const Graph& g) : m_g(g) {} bool operator()(typename graph_traits::edge_descriptor e) const { return !get(vertex_sense, m_g, source(e, m_g)) && !get(vertex_sense, m_g, target(e, m_g)); } private: const Graph& m_g; }; /** Assemble unambiguous paths in forward orientation only. * Write the paths to out. */ template OutIt assemble_stranded(Graph& g, OutIt out) { return assemble_if(g, out, IsPositive(g)); } /** Remove tips. * For an edge (u,v), remove the vertex v if deg+(u) > 1, * deg+(v) = 0, and p(v) is true. * Stores all removed vertices in result. */ template OutputIt pruneTips_if(Graph& g, OutputIt result, Pred p) { typedef typename graph_traits::adjacency_iterator Vit; typedef typename graph_traits::vertex_iterator Uit; typedef typename graph_traits::vertex_descriptor V; /** Identify the tips. */ std::vector tips; std::pair urange = vertices(g); for (Uit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (out_degree(u, g) < 2) continue; std::pair vrange = adjacent_vertices(u, g); for (Vit vit = vrange.first; vit != vrange.second; ++vit) { V v = *vit; // assert(v != u); if (out_degree(v, g) == 0 && p(v)) tips.push_back(v); } } /** Remove the tips. */ remove_vertex_if(g, tips.begin(), tips.end(), True()); std::transform( tips.begin(), tips.end(), result, [](const ContigNode& c) { return c.contigIndex(); }); return result; } /** Return true if the vertex is a normal 1-in 0-out tip. */ template struct IsTip : std::unary_function::vertex_descriptor, bool> { IsTip(const Graph& g) : m_g(g) {} bool operator()(typename graph_traits::vertex_descriptor v) const { return in_degree(v, m_g) == 1; } private: const Graph& m_g; }; /** Remove tips. * For an edge (u,v), remove the vertex v if deg+(u) > 1 * and deg-(v) = 1 and deg+(v) = 0. * Stores all removed vertices in result. */ template OutputIt pruneTips(Graph& g, OutputIt result) { return pruneTips_if(g, result, IsTip(g)); } /** Remove islands. * For a vertex v, remove v if deg+(v) = 0, deg-(v) = 0 and p(v) is * true. * Stores all removed vertices in result. */ template OutputIt removeIslands_if(Graph& g, OutputIt result, Pred p) { typedef typename graph_traits::vertex_iterator Uit; typedef typename graph_traits::vertex_descriptor V; /** Identify and remove Islands. */ std::pair urange = vertices(g); for (Uit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (get(vertex_removed, g, u)) continue; if (p(u) && in_degree(u, g) == 0 && out_degree(u, g) == 0) { *result++ = get(vertex_contig_index, g, u); clear_vertex(u, g); remove_vertex(u, g); } } return result; } /** Add missing complementary edges. */ template size_t addComplementaryEdges(ContigGraph& g) { typedef ContigGraph Graph; typedef graph_traits GTraits; typedef typename GTraits::edge_descriptor E; typedef typename GTraits::edge_iterator Eit; typedef typename GTraits::vertex_descriptor V; std::pair erange = edges(g); size_t numAdded = 0; for (Eit eit = erange.first; eit != erange.second; ++eit) { E e = *eit; V u = source(e, g), v = target(e, g); V uc = get(vertex_complement, g, u); V vc = get(vertex_complement, g, v); E f; bool found; boost::tie(f, found) = edge(vc, uc, g); if (!found) { add_edge(vc, uc, g[e], static_cast(g)); numAdded++; } else if (!(g[e] == g[f])) { // The edge properties do not agree. Select the better. g[e] = g[f] = BetterDistanceEst()(g[e], g[f]); } } return numAdded; } #endif abyss-2.2.4/Graph/DefaultColorMap.h000066400000000000000000000025701361462241400171020ustar00rootroot00000000000000#ifndef DEFAULTCOLORMAP_H #define DEFAULTCOLORMAP_H #include "UnorderedMap.h" #include #include template class DefaultColorMap { public: typedef typename boost::graph_traits::vertex_descriptor key_type; typedef typename boost::graph_traits::vertex_descriptor& reference; typedef boost::default_color_type value_type; typedef boost::read_write_property_map_tag category; typedef unordered_map > map_type; map_type map; }; namespace boost { template struct property_traits< DefaultColorMap > { typedef typename DefaultColorMap::key_type key_type; typedef typename DefaultColorMap::reference reference; typedef typename DefaultColorMap::value_type value_type; typedef typename DefaultColorMap::category category; }; } template typename DefaultColorMap::value_type get(const DefaultColorMap& colorMap, typename DefaultColorMap::key_type key) { typedef typename DefaultColorMap::map_type::const_iterator It; It i = colorMap.map.find(key); if (i != colorMap.map.end()) return i->second; return boost::white_color; } template void put(DefaultColorMap& colorMap, typename DefaultColorMap::key_type key, typename DefaultColorMap::value_type value) { colorMap.map[key] = value; } #endif abyss-2.2.4/Graph/DepthFirstSearch.h000066400000000000000000000036531361462241400172660ustar00rootroot00000000000000#ifndef DEPTHFIRSTSEARCH_H #define DEPTHFIRSTSEARCH_H 1 #include "Graph/ContigGraphAlgorithms.h" // for contiguous_in #include using boost::graph_traits; /** * Perform a depth-first search starting first with vertices with * deg-(u) = 0 and then visiting any remaining vertices. */ template void depthFirstSearch(const Graph& g, Visitor vis, ColorMap color, bool ss = false) { using boost::color_traits; using boost::property_traits; using boost::tie; typedef graph_traits GTraits; typedef typename GTraits::vertex_descriptor V; typedef typename GTraits::vertex_iterator Vit; typedef typename property_traits::value_type ColorValue; const ColorValue white = color_traits::white(); // Initialize the vertices. Vit uit, ulast; for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) { V u = *uit; put(color, u, white); vis.initialize_vertex(u, g); } // Visit vertices with deg-(u) = 0. for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) { V u = *uit; if (get(color, u) == white && in_degree(u, g) == 0) { vis.start_vertex(u, g); boost::detail::depth_first_visit_impl(g, u, vis, color, boost::detail::nontruth2()); } if (ss) { ++uit; assert(uit != ulast); } } // Visit vertices where discontiguous-(u). for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) { V u = *uit; if (get(color, u) == white && !contiguous_in(g, u)) { vis.start_vertex(u, g); boost::detail::depth_first_visit_impl(g, u, vis, color, boost::detail::nontruth2()); } if (ss) { ++uit; assert(uit != ulast); } } // Visit the remaining vertices. for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) { V u = *uit; if (get(color, u) == white) { vis.start_vertex(u, g); boost::detail::depth_first_visit_impl(g, u, vis, color, boost::detail::nontruth2()); } } } #endif abyss-2.2.4/Graph/DirectedGraph.h000066400000000000000000000500561361462241400165700ustar00rootroot00000000000000#ifndef DIRECTEDGRAPH_H #define DIRECTEDGRAPH_H 1 #include "Common/ContigNode.h" #include "Graph/Properties.h" #include #include #include #include /** A directed graph. */ template class DirectedGraph { class Vertex; typedef typename std::vector Vertices; class Edge; typedef typename std::vector Edges; public: // Graph typedef ContigNode vertex_descriptor; // IncidenceGraph typedef std::pair edge_descriptor; typedef unsigned degree_size_type; // BidirectionalGraph typedef void in_edge_iterator; // VertexListGraph typedef unsigned vertices_size_type; // EdgeListGraph typedef unsigned edges_size_type; // PropertyGraph typedef VertexProp vertex_bundled; typedef VertexProp vertex_property_type; typedef EdgeProp edge_bundled; typedef EdgeProp edge_property_type; typedef boost::directed_tag directed_category; typedef boost::allow_parallel_edge_tag edge_parallel_category; struct traversal_category : boost::incidence_graph_tag, boost::adjacency_graph_tag, boost::vertex_list_graph_tag, boost::edge_list_graph_tag { }; /** Iterate through the vertices of this graph. */ class vertex_iterator : public std::iterator { public: vertex_iterator() { } explicit vertex_iterator(vertices_size_type v) : m_v(v) { } const vertex_descriptor& operator *() const { return m_v; } bool operator ==(const vertex_iterator& it) const { return m_v == it.m_v; } bool operator !=(const vertex_iterator& it) const { return m_v != it.m_v; } vertex_iterator& operator ++() { ++m_v; return *this; } vertex_iterator operator ++(int) { vertex_iterator it = *this; ++*this; return it; } private: vertex_descriptor m_v; }; /** Iterate through the out-edges. */ class out_edge_iterator : public std::iterator { typedef typename Edges::const_iterator const_iterator; public: out_edge_iterator() { } out_edge_iterator(const const_iterator& it, vertex_descriptor src) : m_it(it), m_src(src) { } edge_descriptor operator *() const { return edge_descriptor(m_src, m_it->target()); } bool operator ==(const out_edge_iterator& it) const { return m_it == it.m_it; } bool operator !=(const out_edge_iterator& it) const { return m_it != it.m_it; } out_edge_iterator& operator ++() { ++m_it; return *this; } out_edge_iterator operator ++(int) { out_edge_iterator it = *this; ++*this; return it; } const edge_property_type& get_property() const { return m_it->get_property(); } private: const_iterator m_it; vertex_descriptor m_src; }; /** Iterate through adjacent vertices. */ class adjacency_iterator : public Edges::const_iterator { typedef typename Edges::const_iterator It; public: adjacency_iterator() { } adjacency_iterator(const It& it) : It(it) { } vertex_descriptor operator*() const { return It::operator*().target(); } const edge_property_type& get_property() const { return It::operator*().get_property(); } }; /** Iterate through edges. */ class edge_iterator : public std::iterator { void nextVertex() { vertex_iterator vlast = m_g->vertices().second; for (; m_vit != vlast; ++m_vit) { std::pair adj = m_g->adjacent_vertices(*m_vit); 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: edge_iterator() { } edge_iterator(const DirectedGraph* g, const vertex_iterator& vit) : m_g(g), m_vit(vit) { nextVertex(); } edge_descriptor operator*() const { return edge_descriptor(*m_vit, *m_eit); } const edge_property_type& get_property() const { return m_eit->get_property(); } 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 == m_g->adjacent_vertices(*m_vit).second) { ++m_vit; nextVertex(); } return *this; } edge_iterator operator++(int) { edge_iterator it = *this; ++*this; return it; } private: const DirectedGraph* m_g; vertex_iterator m_vit; adjacency_iterator m_eit; }; private: /** A vertex and its properties. */ class Vertex { public: Vertex() { } Vertex(const vertex_property_type& p) : m_prop(p) { } /** Return the properties of this vertex. */ const vertex_property_type& get_property() const { return m_prop; } /** Returns an iterator-range to the out edges of vertex u. */ std::pair out_edges(vertex_descriptor u) const { return make_pair(out_edge_iterator(m_edges.begin(), u), out_edge_iterator(m_edges.end(), u)); } /** Returns an iterator-range to the adjacent vertices. */ std::pair adjacent_vertices() const { return make_pair(m_edges.begin(), m_edges.end()); } /** Return the number of outgoing edges. */ degree_size_type out_degree() const { return m_edges.size(); } /** Add an edge to this vertex. */ bool add_edge(vertex_descriptor v, const edge_property_type& ep) { m_edges.push_back(Edge(v, ep)); return true; } /** Remove the edge to v from this vertex. */ void remove_edge(vertex_descriptor v) { m_edges.erase(remove(m_edges.begin(), m_edges.end(), v), m_edges.end()); } /** Remove all out edges from this vertex. */ void clear_out_edges() { m_edges.clear(); } /** Return the properties of the edge with target v. */ edge_property_type& operator[](vertex_descriptor v) { typename Edges::iterator it = find(m_edges.begin(), m_edges.end(), v); assert(it != m_edges.end()); return it->get_property(); } /** Return the properties of the edge with target v. */ const edge_property_type& operator[](vertex_descriptor v) const { typename Edges::const_iterator it = find(m_edges.begin(), m_edges.end(), v); assert(it != m_edges.end()); return it->get_property(); } /** Return true if edge (u,v) exists. */ bool edge(vertex_descriptor v) const { return count(m_edges.begin(), m_edges.end(), v) > 0; } /** Remove edges that satisfy the predicate. */ template void remove_edge_if(vertex_descriptor u, Predicate predicate) { typename Edges::iterator out = m_edges.begin(); for (typename Edges::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { if (!predicate(edge_descriptor(u, it->target()))) { if (out != it) *out = *it; ++out; } } m_edges.erase(out, m_edges.end()); } private: Edges m_edges; vertex_property_type m_prop; }; /** A directed edge. */ class Edge { public: explicit Edge(vertex_descriptor v, const edge_property_type& ep) : m_target(v), m_ep(ep) { } /** Returns the target vertex of this edge. */ vertex_descriptor target() const { return m_target; } /** Return true if the target of this edge is v. */ bool operator ==(const vertex_descriptor& v) const { return m_target == v; } edge_property_type& get_property() { return m_ep; } const edge_property_type& get_property() const { return m_ep; } private: /** The target vertex of this edge. */ vertex_descriptor m_target; edge_property_type m_ep; }; public: /** Create an empty graph. */ DirectedGraph() { } /** Create a graph with n vertices and zero edges. */ DirectedGraph(vertices_size_type n) : m_vertices(n) { } /** Swap this graph with graph x. */ void swap(DirectedGraph& x) { m_vertices.swap(x.m_vertices); m_removed.swap(x.m_removed); } /** Return properties of vertex u. */ const vertex_property_type& operator[](vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].get_property(); } /** Returns an iterator-range to the vertices. */ std::pair vertices() const { return make_pair(vertex_iterator(0), vertex_iterator(num_vertices())); } /** Remove all the edges and vertices from this graph. */ void clear() { m_vertices.clear(); m_removed.clear(); } /** Add a vertex to this graph. */ vertex_descriptor add_vertex( const vertex_property_type& vp = vertex_property_type()) { m_vertices.push_back(Vertex(vp)); return vertex_descriptor(num_vertices() - 1); } /** Returns an iterator-range to the out edges of vertex u. */ std::pair out_edges(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].out_edges(u); } /** Returns an iterator-range to the adjacent vertices of * vertex u. */ std::pair adjacent_vertices(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].adjacent_vertices(); } /** Adds edge (u,v) to this graph. */ std::pair add_edge(vertex_descriptor u, vertex_descriptor v, const edge_property_type& ep = edge_property_type()) { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); assert(get(vertex_index, *this, v) < num_vertices()); return make_pair(edge_descriptor(u, v), m_vertices[ui].add_edge(v, ep)); } /** Remove the edge (u,v) from this graph. */ void remove_edge(vertex_descriptor u, vertex_descriptor v) { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); m_vertices[ui].remove_edge(v); } /** Remove the edge e from this graph. */ void remove_edge(edge_descriptor e) { remove_edge(e.first, e.second); } /** Remove all out edges from vertex u. */ void clear_out_edges(vertex_descriptor u) { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); m_vertices[ui].clear_out_edges(); } /** Remove all edges to and from vertex u from this graph. * O(V+E) */ void clear_vertex(vertex_descriptor u) { clear_out_edges(u); std::pair adj = adjacent_vertices(u); for (adjacency_iterator v = adj.first; v != adj.second; ++v) remove_edge(*v, u); } /** Set the vertex_removed property. */ void put(vertex_removed_t, vertex_descriptor u, bool flag) { vertices_size_type ui = get(vertex_index, *this, u); if (ui >= m_removed.size()) m_removed.resize(ui + 1); m_removed[ui] = flag; } /** Remove vertex u from this graph. It is assumed that there * are no edges to or from vertex u. It is best to call * clear_vertex before remove_vertex. */ void remove_vertex(vertex_descriptor u) { put(vertex_removed, u, true); } /** Return the number of vertices. */ vertices_size_type num_vertices() const { return m_vertices.size(); } /** Return the number of edges. */ edges_size_type num_edges() const { edges_size_type n = 0; std::pair vit = vertices(); for (vertex_iterator v = vit.first; v != vit.second; ++v) n += out_degree(*v); return n; } /** Return the out degree of vertex u. */ degree_size_type out_degree(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].out_degree(); } /** Return the nth vertex. */ static vertex_descriptor vertex(vertices_size_type n) { return vertex_descriptor(n); } /** Iterate through the edges of this graph. */ std::pair edges() const { std::pair vit = vertices(); return make_pair(edge_iterator(this, vit.first), edge_iterator(this, vit.second)); } /** Return the edge (u,v) if it exists and a flag indicating * whether the edge exists. */ std::pair edge( vertex_descriptor u, vertex_descriptor v) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return make_pair(edge_descriptor(u, v), m_vertices[ui].edge(v)); } /** Return properties of edge e. */ edge_property_type& operator[](edge_descriptor e) { vertices_size_type ui = get(vertex_index, *this, e.first); assert(ui < num_vertices()); return m_vertices[ui][e.second]; } /** Return properties of edge e. */ const edge_property_type& operator[](edge_descriptor e) const { vertices_size_type ui = get(vertex_index, *this, e.first); assert(ui < num_vertices()); return m_vertices[ui][e.second]; } /** Remove edges that satisfy the predicate. */ template void remove_edge_if(Predicate predicate) { unsigned i = 0; for (typename Vertices::iterator it = m_vertices.begin(); it != m_vertices.end(); ++it) it->remove_edge_if(vertex(i++), predicate); } /** Return true if this vertex has been removed. */ bool is_removed(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); return ui < m_removed.size() ? m_removed[ui] : false; } protected: /** Copy constructors */ DirectedGraph(const DirectedGraph& d) = default; DirectedGraph(DirectedGraph&&) = default; DirectedGraph& operator=(const DirectedGraph&) = default; DirectedGraph& operator=(DirectedGraph&&) = default; private: /** The set of vertices. */ Vertices m_vertices; /** Flags indicating vertices that have been removed. */ std::vector m_removed; }; namespace std { template inline void swap(DirectedGraph& a, DirectedGraph& b) { a.swap(b); } } // IncidenceGraph template std::pair< typename DirectedGraph::out_edge_iterator, typename DirectedGraph::out_edge_iterator> out_edges( typename DirectedGraph::vertex_descriptor u, const DirectedGraph& g) { return g.out_edges(u); } template typename DirectedGraph::degree_size_type out_degree( typename DirectedGraph::vertex_descriptor u, const DirectedGraph& g) { return g.out_degree(u); } // AdjacencyGraph template std::pair< typename DirectedGraph::adjacency_iterator, typename DirectedGraph::adjacency_iterator> adjacent_vertices( typename DirectedGraph::vertex_descriptor u, const DirectedGraph& g) { return g.adjacent_vertices(u); } // VertexListGraph template typename DirectedGraph::vertices_size_type num_vertices(const DirectedGraph& g) { return g.num_vertices(); } template typename DirectedGraph::vertex_descriptor vertex(typename DirectedGraph::vertices_size_type ui, const DirectedGraph& g) { return g.vertex(ui); } template std::pair::vertex_iterator, typename DirectedGraph::vertex_iterator> vertices(const DirectedGraph& g) { return g.vertices(); } // EdgeListGraph template typename DirectedGraph::edges_size_type num_edges(const DirectedGraph& g) { return g.num_edges(); } template std::pair::edge_iterator, typename DirectedGraph::edge_iterator> edges(const DirectedGraph& g) { return g.edges(); } // AdjacencyMatrix template std::pair::edge_descriptor, bool> edge( typename DirectedGraph::vertex_descriptor u, typename DirectedGraph::vertex_descriptor v, const DirectedGraph& g) { return g.edge(u, v); } // VertexMutableGraph template typename DirectedGraph::vertex_descriptor add_vertex(DirectedGraph& g) { return g.add_vertex(); } template void remove_vertex( typename DirectedGraph::vertex_descriptor u, DirectedGraph& g) { g.remove_vertex(u); } // EdgeMutableGraph template void clear_vertex( typename DirectedGraph::vertex_descriptor u, DirectedGraph& g) { g.clear_vertex(u); } template std::pair::edge_descriptor, bool> add_edge( typename DirectedGraph::vertex_descriptor u, typename DirectedGraph::vertex_descriptor v, DirectedGraph& g) { return g.add_edge(u, v); } template void remove_edge( typename DirectedGraph::vertex_descriptor u, typename DirectedGraph::vertex_descriptor v, DirectedGraph& g) { g.remove_edge(u, v); } template void remove_edge( typename DirectedGraph::edge_descriptor e, DirectedGraph& g) { g.remove_edge(e); } // MutableIncidenceGraph template void clear_out_edges( typename DirectedGraph::vertex_descriptor u, DirectedGraph& g) { g.clear_out_edges(u); } // MutableEdgeListGraph template void remove_edge_if(Predicate predicate, DirectedGraph& g) { g.remove_edge_if(predicate); } // PropertyGraph /** Return true if this vertex has been removed. */ template bool get(vertex_removed_t, const DirectedGraph& g, typename DirectedGraph::vertex_descriptor u) { return g.is_removed(u); } template void put(vertex_removed_t tag, DirectedGraph& g, typename DirectedGraph::vertex_descriptor u, bool flag) { g.put(tag, u, flag); } /** Return the edge properties of the edge iterator eit. */ template const typename DirectedGraph::edge_property_type& get(edge_bundle_t, const DirectedGraph&, typename DirectedGraph::edge_iterator eit) { return eit.get_property(); } /** Return the edge properties of the out-edge iterator eit. */ template const typename DirectedGraph::edge_property_type& get(edge_bundle_t, const DirectedGraph&, typename DirectedGraph::out_edge_iterator eit) { return eit.get_property(); } // PropertyGraph template const VP& get(vertex_bundle_t, const DirectedGraph& g, typename DirectedGraph::vertex_descriptor u) { return g[u]; } template const EP& get(edge_bundle_t, const DirectedGraph& g, typename DirectedGraph::edge_descriptor e) { return g[e]; } // PropertyGraph vertex_index namespace boost { template struct property_map, vertex_index_t> { typedef ContigNodeIndexMap type; typedef type const_type; }; } template ContigNodeIndexMap get(vertex_index_t, const DirectedGraph&) { return ContigNodeIndexMap(); } template ContigNodeIndexMap::reference get(vertex_index_t tag, const DirectedGraph& g, typename DirectedGraph::vertex_descriptor u) { return get(get(tag, g), u); } // VertexMutablePropertyGraph template typename DirectedGraph::vertex_descriptor add_vertex(const VP& vp, DirectedGraph& g) { return g.add_vertex(vp); } // EdgeMutablePropertyGraph template std::pair::edge_descriptor, bool> add_edge( typename DirectedGraph::vertex_descriptor u, typename DirectedGraph::vertex_descriptor v, const typename DirectedGraph::edge_property_type& ep, DirectedGraph& g) { return g.add_edge(u, v, ep); } // NamedGraph template typename DirectedGraph::vertex_descriptor find_vertex(const std::string& name, const DirectedGraph&) { return find_vertex(name, g_contigNames); } template typename DirectedGraph::vertex_descriptor find_vertex(const std::string& name, bool sense, const DirectedGraph&) { return find_vertex(name, sense, g_contigNames); } #endif abyss-2.2.4/Graph/DistIO.h000066400000000000000000000021241361462241400152070ustar00rootroot00000000000000#ifndef DISTIO_H #define DISTIO_H 1 #include #include #include using boost::graph_traits; /** Output a distance estimate graph. */ template std::ostream& write_dist(std::ostream& out, const Graph& g) { typedef typename graph_traits::vertex_descriptor V; typedef typename graph_traits::vertex_iterator Vit; typedef typename graph_traits::out_edge_iterator Eit; std::pair urange = vertices(g); for (Vit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (get(vertex_removed, g, u) || out_degree(u, g) + in_degree(u, g) == 0) continue; bool sense = get(vertex_sense, g, u); if (!sense) out << get(vertex_contig_name, g, u); else out << " ;"; std::pair erange = out_edges(u, g); for (Eit eit = erange.first; eit != erange.second; ++eit) { V v = target(*eit, g) ^ sense; assert(!get(vertex_removed, g, v)); out << ' ' << get(vertex_name, g, v) << ',' << get(edge_bundle, g, eit); } if (sense) out << '\n'; } return out; } #endif abyss-2.2.4/Graph/DotIO.h000066400000000000000000000172321361462241400150400ustar00rootroot00000000000000#ifndef DOTIO_H #define DOTIO_H 1 #include "ContigID.h" // for g_contigNames.lock #include "Graph/Options.h" #include "IOUtil.h" #include #include #include // for exit #include #include using boost::graph_traits; template void write_vertex(std::ostream& out, const Graph& g, typename graph_traits::vertex_descriptor u, const VertexProp*) { out << '"' << get(vertex_name, g, u) << "\"" " [" << get(vertex_bundle, g, u) << "]\n"; } template void write_vertex(std::ostream&, const Graph&, typename graph_traits::vertex_descriptor, const no_property*) { } template void write_edges(std::ostream& out, const Graph& g, typename graph_traits::vertex_descriptor u, const EdgeProp*) { typedef typename graph_traits::out_edge_iterator out_edge_iterator; typedef typename edge_property::type edge_property_type; std::pair adj = out_edges(u, g); for (out_edge_iterator e = adj.first; e != adj.second; ++e) { assert(!get(vertex_removed, g, target(*e, g))); out << get(edge_name, g, *e); const edge_property_type& ep = get(edge_bundle, g, e); if (!(ep == edge_property_type())) out << " [" << ep << ']'; out << '\n'; } } template void write_edges(std::ostream& out, const Graph& g, typename graph_traits::vertex_descriptor u, const no_property*) { typedef typename graph_traits::adjacency_iterator adjacency_iterator; unsigned outdeg = out_degree(u, g); if (outdeg == 0) return; out << '"' << get(vertex_name, g, u) << "\" ->"; if (outdeg > 1) out << " {"; std::pair adj = adjacent_vertices(u, g); for (adjacency_iterator v = adj.first; v != adj.second; ++v) out << " \"" << get(vertex_name, g, *v) << '"'; if (outdeg > 1) out << " }"; out << '\n'; } /** Output a GraphViz dot graph. */ template std::ostream& write_dot(std::ostream& out, const Graph& g) { return write_dot(out, g, "adj"); } /** Output a GraphViz dot graph. */ template std::ostream& write_dot(std::ostream& out, const Graph& g, const std::string& graphName) { typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename vertex_property::type vertex_property_type; typedef typename edge_property::type edge_property_type; out << "digraph " << graphName << " {\n"; // Graph properties if (opt::k > 0) out << "graph [k=" << opt::k << "]\n" "edge [d=" << -int(opt::k - 1) << "]\n"; // Vertices std::pair 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, (vertex_property_type*)NULL); } // Edges for (vertex_iterator u = vit.first; u != vit.second; ++u) { if (get(vertex_removed, g, *u)) continue; write_edges(out, g, *u, (edge_property_type*)NULL); } return out << "}\n"; } /** Output a GraphViz dot graph. */ template struct DotWriter { const Graph& g; DotWriter(const Graph& g) : g(g) { } friend std::ostream& operator<<(std::ostream& out, const DotWriter& o) { return write_dot(out, o.g); } }; /** Output a GraphViz dot graph. */ template DotWriter dot_writer(const Graph& g) { return DotWriter(g); } /** Read a string delimited by double quotes. */ static inline std::istream& read_dot_name(std::istream& in, std::string& s) { if (in >> std::ws && in.peek() == '"') { in.get(); getline(in, s, '"'); } else in.clear(std::ios::failbit); return in; } /** Read a vertex descriptor delimited by double quotes. */ template std::istream& read_dot_id(std::istream& in, const Graph& g, typename graph_traits::vertex_descriptor& u) { std::string s; if (read_dot_name(in, s)) u = find_vertex(s, g); return in; } /** Read a GraphViz dot graph. * @param betterEP handle parallel edges */ template std::istream& read_dot(std::istream& in, Graph& g, BetterEP betterEP) { assert(in); typedef typename graph_traits::vertex_descriptor vertex_descriptor; typedef typename vertex_property::type vertex_property_type; typedef typename graph_traits::edge_descriptor edge_descriptor; typedef typename edge_property::type edge_property_type; typedef typename graph_traits::directed_category directed_category; bool isDirectedGraph = boost::detail::is_directed(directed_category()); // Add vertices if this graph is empty. bool addVertices = num_vertices(g) == 0; // Graph properties in >> expect(isDirectedGraph ? "digraph" : "graph"); in >> Ignore('{'); assert(in); edge_property_type defaultEdgeProp; for (bool done = false; !done && in >> std::ws;) { switch (in.peek()) { case 'g': { // Graph Properties in >> expect("graph [ "); if (in.peek() == 'k') { unsigned k; in >> expect("k =") >> k; assert(in); if (opt::k > 0) assert(k == opt::k); opt::k = k; } in >> Ignore(']'); break; } case 'e': // edge // Default edge properties in >> expect("edge [") >> defaultEdgeProp >> Ignore(']'); assert(in); break; default: done = true; break; } if (in >> std::ws && in.peek() == ';') in.get(); } for (std::string uname; read_dot_name(in, uname);) { char c; in >> c; assert(in); if (c == ';') { // Vertex if (addVertices) { vertex_descriptor u = add_vertex(g); put(vertex_name, g, u, uname); } else { vertex_descriptor u = find_vertex(uname, g); assert(get(vertex_index, g, u) < num_vertices(g)); (void)u; } } else if (c == '[') { // Vertex properties vertex_property_type vp; in >> vp >> Ignore(']'); assert(in); if (addVertices) { vertex_descriptor u = add_vertex(vp, g); put(vertex_name, g, u, uname); } else { vertex_descriptor u = find_vertex(uname, g); assert(get(vertex_index, g, u) < num_vertices(g)); if (g[u] != vp) { std::cerr << "error: " "vertex properties do not agree: " "\"" << uname << "\" " "[" << g[u] << "] [" << vp << "]\n"; exit(EXIT_FAILURE); } } } else if (c == '-') { // Edge in >> expect(isDirectedGraph ? ">" : "-"); assert(in); g_contigNames.lock(); vertex_descriptor u = find_vertex(uname, g); if (in >> std::ws && in.peek() == '{') { // Subgraph in >> expect("{"); for (vertex_descriptor v; read_dot_id(in, g, v);) add_edge(u, v, defaultEdgeProp, g); if (in.fail()) in.clear(); in >> expect(" }"); assert(in); } else { vertex_descriptor v; if (!read_dot_id(in, g, v)) { in.clear(); std::cerr << "error: Expected `\"' and saw `" << (char)in.peek() << "'.\n"; exit(EXIT_FAILURE); } assert(in); edge_property_type ep = defaultEdgeProp; if (in >> std::ws && in.peek() == '[') { // Edge properties in >> expect("[") >> ep >> Ignore(']'); assert(in); } edge_descriptor e; bool found; boost::tie(e, found) = edge(u, v, g); if (found) { // Parallel edge edge_property_type& ref = g[e]; ref = betterEP(ref, ep); } else add_edge(u, v, ep, g); } } else { std::cerr << "error: Expected `[' or `->' and saw `" << c << "'.\n"; exit(EXIT_FAILURE); } if (in >> std::ws && in.peek() == ';') in.get(); } if (in.fail()) in.clear(); // Check for the closing brace. in >> expect("}") >> std::ws; assert(in.eof()); assert(num_vertices(g) > 0); return in; } #endif abyss-2.2.4/Graph/ExtendPath.h000066400000000000000000000532701361462241400161300ustar00rootroot00000000000000 #ifndef _EXTENDPATH_H_ #define _EXTENDPATH_H_ #include "Graph/Path.h" #include "Common/UnorderedSet.h" #include "Common/UnorderedMap.h" #include "Common/Hash.h" #include #include #include #include #include #include /** * Parameters for path extension. */ struct ExtendPathParams { /* ignore branches shorter than or equal to this length */ unsigned trimLen; /* longest branch of Bloom filter false positives */ unsigned fpTrim; /* maximum length after extension */ unsigned maxLen; /* * if true, multiple incoming branches > trimLen * will cause a path extension to halt */ bool lookBehind; /* * If false, ignore incoming branches for the starting vertex. * This is useful when when we are intentionally starting our * path extension from a branching point. */ bool lookBehindStartVertex; /* constructor */ ExtendPathParams() : trimLen(0), fpTrim(0), maxLen(NO_LIMIT), lookBehind(true), lookBehindStartVertex(true) {} }; /** * The result of attempting to extend a path. */ enum PathExtensionResultCode { /** stopped path extension at a vertex with multiple incoming branches */ ER_AMBI_IN, /** stopped path extension at a vertex with multiple outgoing branches */ ER_AMBI_OUT, /** stopped path extension at a vertex with no outgoing branches */ ER_DEAD_END, /** stopped path extension after completing a cycle */ ER_CYCLE, /** stopped path extension at caller-specified length limit */ ER_LENGTH_LIMIT, }; /** * Translate path extension result code to a string. */ static inline const char* pathExtensionResultStr(PathExtensionResultCode result) { switch(result) { case ER_AMBI_IN: return "AMBI_IN"; case ER_AMBI_OUT: return "AMBI_OUT"; case ER_DEAD_END: return "DEAD_END"; case ER_CYCLE: return "CYCLE"; case ER_LENGTH_LIMIT: return "LENGTH_LIMIT"; default: assert(false); } } /** length of path extension (in vertices) and reason for stopping */ typedef std::pair PathExtensionResult; /** * Return true if there is a path of at least depthLimit vertices * that extends from given vertex u, otherwise return false. * Implemented using a bounded depth first search. * * @param start starting vertex for traversal * @param dir direction for traversal (FORWARD or REVERSE) * @param depth depth of current vertex u * @param depthLimit maximum depth to probe * @param g graph to use for traversal * @param visited vertices that have already been visited by the DFS * @return true if at least one path with length >= len * extends from v in direction dir, false otherwise */ template static inline bool lookAhead( const typename boost::graph_traits::vertex_descriptor& u, Direction dir, unsigned depth, unsigned depthLimit, unordered_set< typename boost::graph_traits::vertex_descriptor, hash::vertex_descriptor> >& visited, const Graph& g) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::out_edge_iterator OutEdgeIter; typedef typename boost::graph_traits::in_edge_iterator InEdgeIter; OutEdgeIter oei, oei_end; InEdgeIter iei, iei_end; visited.insert(u); if (depth >= depthLimit) return true; if (dir == FORWARD) { for (boost::tie(oei, oei_end) = out_edges(u, g); oei != oei_end; ++oei) { const V& v = target(*oei, g); if (visited.find(v) == visited.end()) { if(lookAhead(v, dir, depth+1, depthLimit, visited, g)) return true; } } } 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 (visited.find(v) == visited.end()) { if(lookAhead(v, dir, depth+1, depthLimit, visited, g)) return true; } } } return false; } /** * 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 depth 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 static inline bool lookAhead( const typename boost::graph_traits::vertex_descriptor& start, Direction dir, unsigned depth, const Graph& g) { typedef typename boost::graph_traits::vertex_descriptor V; unordered_set< V, hash > visited; return lookAhead(start, dir, 0, depth, visited, g); } /** * Return true if the given edge represents the beginning of a "true branch". * * A path is a true branch if it has length >= `trim` or terminates in a * branching node, where a branching node is (recursively) defined to be * a node with either >= 2 incoming true branches or >= 2 outgoing true branches. * * This method is similar to `lookAhead`, but it additionally changes traversal * direction when a dead-end is encountered. */ template static inline bool trueBranch( const typename boost::graph_traits::edge_descriptor& e, unsigned depth, Direction dir, const Graph& g, unsigned trim, unsigned fpTrim, unordered_set::vertex_descriptor>& visited) { typedef typename boost::graph_traits::vertex_descriptor V; typename boost::graph_traits::out_edge_iterator oei, oei_end; typename boost::graph_traits::in_edge_iterator iei, iei_end; const V& u = (dir == FORWARD) ? source(e, g) : target(e, g); const V& v = (dir == FORWARD) ? target(e, g) : source(e, g); /* branches with bubbles/cycles are considered true branches */ if (visited.find(v) != visited.end()) return true; if (depth >= trim) return true; visited.insert(v); if (dir == FORWARD) { for (boost::tie(oei, oei_end) = out_edges(v, g); oei != oei_end; ++oei) { if (trueBranch(*oei, depth+1, FORWARD, g, trim, fpTrim, visited)) return true; } /* * Note: The test for depth/lookAhead >= fpTrim before changing * traversal direction is needed to deal with an X-shaped * graph pattern that is frequently created by Bloom false positives. * See the test for `trueBranch` in `ExtendPathTest.h` for an example. */ if (depth >= fpTrim || lookAhead(v, FORWARD, fpTrim, g)) { for (boost::tie(iei, iei_end) = in_edges(v, g); iei != iei_end; ++iei) { if (source(*iei, g) == u) continue; if (trueBranch(*iei, 0, REVERSE, g, trim, fpTrim, visited)) return true; } } } else { assert(dir == REVERSE); for (boost::tie(iei, iei_end) = in_edges(v, g); iei != iei_end; ++iei) { if (trueBranch(*iei, depth+1, REVERSE, g, trim, fpTrim, visited)) return true; } /* * Note: The test for depth/lookAhead >= fpTrim before changing * traversal direction is needed to deal with an X-shaped * graph pattern that is frequently created by Bloom false positives. * See the test for `trueBranch` in `ExtendPathTest.h` for an example. */ if (depth >= fpTrim || lookAhead(v, REVERSE, fpTrim, g)) { for (boost::tie(oei, oei_end) = out_edges(v, g); oei != oei_end; ++oei) { if (target(*oei, g) == u) continue; if (trueBranch(*oei, 0, FORWARD, g, trim, fpTrim, visited)) return true; } } } visited.erase(v); return false; } /** * Return true if the given edge represents the start of a "true branch". * Roughly speaking, a path is a true branch if it has length >= trim * or terminates in a branching node, where a branching node is (recursively) * defined to be a node with either >= 2 incoming true branches or >= outgoing * true branches. */ template static inline bool trueBranch( const typename boost::graph_traits::edge_descriptor& e, Direction dir, const Graph& g, unsigned trim, unsigned fpTrim) { typedef typename boost::graph_traits::vertex_descriptor V; unordered_set visited; return trueBranch(e, 0, dir, g, trim, fpTrim, visited); } /** * Return neighbour vertices that begin branches that are longer than trimLen. * * @param u root vertex * @param dir direction for neighbours (FORWARD or REVERSE) * @param g graph * @param trimLen ignore all branches less than or equal to this length * @return std::vector of neighbour vertices that start branches that are * greater than trimLen vertices in length */ template static inline std::vector::vertex_descriptor> trueBranches(const typename boost::graph_traits::vertex_descriptor& u, Direction dir, const BidirectionalGraph& g, unsigned trim, unsigned fpTrim) { typedef BidirectionalGraph G; typedef boost::graph_traits 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 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 (trueBranch(*oei, dir, g, trim, fpTrim)) 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 (trueBranch(*iei, dir, g, trim, fpTrim)) { branchRoots.push_back(v); } } } return branchRoots; } /** * Return the unique predecessor/successor of a given vertex. In * cases where a predecessor/successor does not exist (i.e. a dead end) * or is not unique (i.e. a branching point), return an result code indicating * why a unique successor could not be returned. */ template static inline std::pair::vertex_descriptor, PathExtensionResultCode> successor(const typename boost::graph_traits::vertex_descriptor& u, Direction dir, const Graph& g, unsigned trim, unsigned fpTrim) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::in_edge_iterator InEdgeIt; typedef typename boost::graph_traits::out_edge_iterator OutEdgeIt; InEdgeIt iei, iei_end; OutEdgeIt oei, oei_end; /* assign u to suppress uninitialized warning */ V v = u; for (unsigned i = 0; true; i = (i == 0) ? 1 : std::min(trim, 2*i)) { unsigned trueBranches = 0; if (dir == FORWARD) { for (boost::tie(oei, oei_end) = out_edges(u, g); oei != oei_end; ++oei) { if (trueBranch(*oei, FORWARD, g, i, fpTrim)) { v = target(*oei, g); ++trueBranches; if (trueBranches >= 2) break; } } } else { assert(dir == REVERSE); for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; ++iei) { if (trueBranch(*iei, REVERSE, g, i, fpTrim)) { v = source(*iei, g); ++trueBranches; if (trueBranches >= 2) break; } } } if (trueBranches == 0) return std::make_pair(v, ER_DEAD_END); else if (trueBranches == 1) return std::make_pair(v, ER_LENGTH_LIMIT); else if (i == trim) return std::make_pair(v, ER_AMBI_OUT); } } /** * Return true if the given vertex has more than one possible * predecessor/successor in the graph. */ template static inline bool ambiguous(const typename boost::graph_traits::vertex_descriptor& u, Direction dir, const Graph& g, unsigned trim, unsigned fpTrim) { return successor(u, dir, g, trim, fpTrim).second == ER_AMBI_OUT; } /** * Return true if the given vertex has more than one possible * predecessor/successor in the graph. * * @param expected always include this vertex in the set of possible * predecssors/successors, even if it is not a true branch. */ template static inline bool ambiguous(const typename boost::graph_traits::vertex_descriptor& u, const typename boost::graph_traits::vertex_descriptor& expected, Direction dir, const Graph& g, unsigned trim, unsigned fpTrim) { typedef typename boost::graph_traits::vertex_descriptor V; V v; PathExtensionResultCode result; boost::tie(v, result) = successor(u, dir, g, trim, fpTrim); return result == ER_AMBI_OUT || (result == ER_LENGTH_LIMIT && v != expected); } /** * Extend path by a single vertex, if there is a unique predecessor/successor * in the direction of extension. */ template static inline PathExtensionResultCode extendPathBySingleVertex( Path::vertex_descriptor>& path, Direction dir, const Graph& g, unsigned trim, unsigned fpTrim, bool lookBehind) { assert(!path.empty()); typedef typename boost::graph_traits::vertex_descriptor V; V t, v; PathExtensionResultCode result; const V& head = (dir == FORWARD) ? path.back() : path.front(); if (lookBehind) { Direction otherDir = (dir == FORWARD) ? REVERSE : FORWARD; boost::tie(t, result) = successor(head, otherDir, g, trim, fpTrim); if (result == ER_AMBI_OUT) return ER_AMBI_IN; /* * Tricky: If our path was seeded on a tip, we want to stop the * extension when we reconnect to the graph. We can detect that * we are on tip if we reach a branching point where the predecessor * vertex in the path does not match the expected predecessor `t`. */ if (path.size() > 1) { if (result == ER_DEAD_END) { /* no predecessors or all predecessors were tips */ return ER_AMBI_IN; } else { /* check if we are on a tip */ assert(result == ER_LENGTH_LIMIT); const V& prev = (dir == FORWARD) ? *(path.rbegin() + 1) : *(path.begin() + 1); if (prev != t) return ER_AMBI_IN; } } } boost::tie(v, result) = successor(head, dir, g, trim, fpTrim); if (result != ER_LENGTH_LIMIT) return result; if (dir == FORWARD) path.push_back(v); else path.push_front(v); return ER_LENGTH_LIMIT; } /** * Return the depth of the graph from the given source vertex, * i.e. the distance of the furthest node. The depth is measured * by means of an exhaustive breadth first search. * * @param root starting vertex for traversal * @param dir direction for traversal (FORWARD or REVERSE) * @param g graph to use for traversal * @return the distance of the furthest vertex from root */ template static inline size_t depth( typename boost::graph_traits::vertex_descriptor root, Direction dir, const Graph& g) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::out_edge_iterator OutEdgeIter; typedef typename boost::graph_traits::in_edge_iterator InEdgeIter; OutEdgeIter oei, oei_end; InEdgeIter iei, iei_end; unordered_set > visited; typedef unordered_map DepthMap; DepthMap depthMap; std::deque q; q.push_back(root); visited.insert(root); std::pair inserted = depthMap.insert(std::make_pair(root, 0)); assert(inserted.second); size_t maxDepth = 0; while (!q.empty()) { V& u = q.front(); visited.insert(u); typename DepthMap::const_iterator it = depthMap.find(u); assert(it != depthMap.end()); size_t depth = it->second; if (depth > maxDepth) maxDepth = depth; 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 inserted = depthMap.insert(std::make_pair(v, depth+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 inserted = depthMap.insert(std::make_pair(v, depth+1)); assert(inserted.second); q.push_back(v); } } } q.pop_front(); } return maxDepth; } /** * Return the neighbor vertex corresponding to the longest branch. If there * are no neighbour vertices, an assertion will be thrown. If there * is a tie between branch lengths, the "winning" branch is chosen arbitrarily. * * @param u root vertex * @param dir direction of branches to consider (FORWARD or REVERSE) * @param g the graph * @return the vertex at the head of the longest branch */ template inline static std::pair::vertex_descriptor, bool> longestBranch(const typename boost::graph_traits::vertex_descriptor& u, Direction dir, const Graph& g) { typedef typename boost::graph_traits::vertex_descriptor V; typedef typename boost::graph_traits::out_edge_iterator OutEdgeIter; typedef typename boost::graph_traits::in_edge_iterator InEdgeIter; OutEdgeIter oei, oei_end; InEdgeIter iei, iei_end; size_t maxDepth = 0; unsigned degree = 0; bool tie = false; /* note: had to initialize to prevent compiler warnings */ V longestBranch = u; if (dir == FORWARD) { for (boost::tie(oei, oei_end) = out_edges(u, g); oei != oei_end; ++oei) { degree++; const V& v = target(*oei, g); size_t d = depth(v, dir, g) + 1; if (d > maxDepth) { maxDepth = d; longestBranch = v; tie = false; } else if (d == maxDepth && v < longestBranch) { /* * make an arbitrary choice among branches * of equal length using the vertex comparison * operator (operator<). */ longestBranch = v; tie = true; } } } else { assert(dir == REVERSE); for (boost::tie(iei, iei_end) = in_edges(u, g); iei != iei_end; ++iei) { degree++; const V& v = source(*iei, g); size_t d = depth(v, dir, g) + 1; if (d > maxDepth) { maxDepth = d; longestBranch = v; tie = false; } else if (d == maxDepth && v < longestBranch) { /* * make an arbitrary choice among branches * of equal length using the vertex comparison * operator (operator<). */ longestBranch = v; tie = true; } } } assert(degree > 0); return std::make_pair(longestBranch, tie); } /** * 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 visited set of previously visited vertices (used * to detect cycles in the de Bruijn graph) * @param params parameters controlling extension (e.g. trimLen) * @return PathExtensionResult: NO_EXTENSION, HIT_BRANCHING_POINT, * or EXTENDED. */ template static inline PathExtensionResult extendPath( Path::vertex_descriptor>& path, Direction dir, const BidirectionalGraph& g, unordered_set::vertex_descriptor>& visited, const ExtendPathParams& params) { typedef BidirectionalGraph G; typedef boost::graph_traits 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); size_t origPathLen = path.size(); PathExtensionResultCode result = ER_DEAD_END; bool lookBehind = params.lookBehindStartVertex; assert(!path.empty()); while (path.size() < params.maxLen) { result = extendPathBySingleVertex(path, dir, g, params.trimLen, params.fpTrim, lookBehind); if (result != ER_LENGTH_LIMIT) break; const V& head = (dir == FORWARD) ? path.back() : path.front(); bool inserted; boost::tie(boost::tuples::ignore, inserted) = visited.insert(head); if (!inserted) { result = ER_CYCLE; if (dir == FORWARD) path.pop_back(); else path.pop_front(); break; } /* override `lookBehindStartVertex` after first extension */ lookBehind = params.lookBehind; } if (params.maxLen != NO_LIMIT && path.size() == params.maxLen) result = ER_LENGTH_LIMIT; assert(path.size() >= origPathLen); unsigned extension = path.size() - origPathLen; /* * Sanity check: If no length limit was imposed, we must have stopped * the extension for some other reason (e.g. dead end) */ assert(params.maxLen != NO_LIMIT || result != ER_LENGTH_LIMIT); return std::make_pair(extension, result); } /** * 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 params parameters controlling extension (e.g. trimLen) * @return PathExtensionResult: NO_EXTENSION, HIT_BRANCHING_POINT, * or EXTENDED. */ template PathExtensionResult extendPath( Path::vertex_descriptor>& path, Direction dir, const BidirectionalGraph& g, const ExtendPathParams& params) { typedef typename boost::graph_traits::vertex_descriptor V; /* track visited nodes to avoid infinite traversal of cycles */ unordered_set visited; visited.insert(path.begin(), path.end()); return extendPath(path, dir, g, visited, params); } /** * 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 * @return PathExtensionResult: NO_EXTENSION, HIT_BRANCHING_POINT, * or EXTENDED. */ template PathExtensionResult extendPath( Path::vertex_descriptor>& path, Direction dir, const BidirectionalGraph& g) { /* default extension params */ ExtendPathParams params; return extendPath(path, dir, g, params); } #endif abyss-2.2.4/Graph/FastaIO.h000066400000000000000000000016731361462241400153520ustar00rootroot00000000000000#ifndef FASTAIO_H #define FASTAIO_H 1 #include "Graph/Properties.h" #include #include #include #include #include using boost::graph_traits; /** Read the vertices from a FASTA file. */ template std::istream& read_fasta(std::istream& in, Graph& g) { assert(in); typedef typename graph_traits::vertex_descriptor V; typedef typename vertex_property::type VP; for (std::string uname; in.peek() != EOF && in >> expect(">") >> uname;) { std::string comment; getline(in, comment); assert(in); std::istringstream ss(comment); VP vp; ss >> vp; size_t n = 0; while (in >> std::ws && in.peek() != '>' && in) { in >> Ignore('\n'); assert(in); assert(in.gcount() > 1); n += in.gcount() - 1; } put(vertex_length, vp, n); V u = add_vertex(vp, g); put(vertex_name, g, u, uname); } assert(in.eof()); return in; } #endif abyss-2.2.4/Graph/GfaIO.h000066400000000000000000000225711361462241400150110ustar00rootroot00000000000000#ifndef GFAIO_H #define GFAIO_H 1 #include "Common/IOUtil.h" #include "Graph/Properties.h" #include #include #include #include #include using boost::graph_traits; struct Distance; struct DistanceEst; /** Write a graph in GFA format. */ template std::ostream& write_gfa1(std::ostream& out, Graph& g) { typedef typename graph_traits::edge_descriptor E; typedef typename graph_traits::edge_iterator Eit; typedef typename graph_traits::vertex_descriptor V; typedef typename graph_traits::vertex_iterator Vit; typedef typename vertex_bundle_type::type VP; out << "H\tVN:Z:1.0\n"; assert(out); std::pair vrange = vertices(g); for (Vit uit = vrange.first; uit != vrange.second; ++uit, ++uit) { V u = *uit; if (get(vertex_removed, g, u)) continue; const VP& vp = g[u]; out << "S\t" << get(vertex_contig_name, g, u) << "\t*\tLN:i:" << vp.length; if (vp.coverage > 0) out << "\tKC:i:" << vp.coverage; out << '\n'; } std::pair erange = edges(g); for (Eit eit = erange.first; eit != erange.second; ++eit) { E e = *eit; V u = source(e, g); V v = target(e, g); if (get(vertex_removed, g, u)) continue; // Output only the canonical edge. if (u > get(vertex_complement, g, v)) continue; int distance = g[e].distance; 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; } /** Write a GFA 2 overlap edge. */ template std::ostream& write_gfa2_edge(std::ostream& out, const Graph& g, typename graph_traits::edge_iterator eit) { typedef typename graph_traits::edge_descriptor E; typedef typename graph_traits::vertex_descriptor V; E e = *eit; V u = source(e, g); V v = target(e, g); int distance = get(edge_bundle, g, eit).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); unsigned ustart = usense ? 0 : ulen - overlap; unsigned uend = usense ? overlap : ulen; unsigned vstart = !vsense ? 0 : vlen - overlap; unsigned vend = !vsense ? overlap : vlen; out << "E\t*" << '\t' << get(vertex_name, g, u) << '\t' << get(vertex_name, g, v); out << '\t' << ustart; if (ustart == ulen) out << '$'; out << '\t' << uend; if (uend == ulen) out << '$'; out << '\t' << vstart; if (vstart == vlen) out << '$'; out << '\t' << vend; if (vend == vlen) out << '$'; out << '\t' << overlap << 'M' << "\n"; assert(out); return out; } /** Write GFA 2 gap edge. */ template std::ostream& write_gfa2_gap(std::ostream& out, const Graph& g, typename graph_traits::edge_iterator eit) { typedef typename graph_traits::edge_descriptor E; typedef typename graph_traits::vertex_descriptor V; E e = *eit; V u = source(e, g); V v = target(e, g); return out << "G\t*" << '\t' << get(vertex_name, g, u) << '\t' << get(vertex_name, g, v) << '\t' << get(edge_bundle, g, eit) << '\n'; } /** Write GFA 2 overlap edges. */ template std::ostream& write_gfa2_edges(std::ostream& out, const Graph& g, const Distance*) { typedef typename graph_traits::edge_iterator Eit; typedef typename graph_traits::edge_descriptor E; typedef typename graph_traits::vertex_descriptor V; std::pair erange = edges(g); for (Eit eit = erange.first; eit != erange.second; ++eit) { E e = *eit; V u = source(e, g); V v = target(e, g); 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)); write_gfa2_edge(out, g, eit); } return out; } /** Write GFA 2 overlap and gap edges. */ template std::ostream& write_gfa2_edges(std::ostream& out, const Graph& g, const DistanceEst*) { typedef typename graph_traits::edge_descriptor E; typedef typename graph_traits::edge_iterator Eit; typedef typename graph_traits::vertex_descriptor V; typedef typename edge_bundle_type::type EP; std::pair erange = edges(g); for (Eit eit = erange.first; eit != erange.second; ++eit) { E e = *eit; V u = source(e, g); V v = target(e, g); 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)); const EP& ep = get(edge_bundle, g, eit); if (ep.stdDev > 0) write_gfa2_gap(out, g, eit); else write_gfa2_edge(out, g, eit); } return out; } /** Write a graph in GFA 2 format. */ template std::ostream& write_gfa2(std::ostream& out, Graph& g) { typedef typename graph_traits::vertex_descriptor V; typedef typename graph_traits::vertex_iterator Vit; typedef typename vertex_bundle_type::type VP; typedef typename edge_bundle_type::type EP; out << "H\tVN:Z:2.0\n"; assert(out); std::pair vrange = vertices(g); for (Vit uit = vrange.first; uit != vrange.second; ++uit, ++uit) { V u = *uit; if (get(vertex_removed, g, u)) continue; const VP& vp = g[u]; out << "S\t" << get(vertex_contig_name, g, u) << '\t' << vp.length << "\t*"; if (vp.coverage > 0) out << "\tKC:i:" << vp.coverage; out << '\n'; } return write_gfa2_edges(out, g, (EP*)NULL); } /** Read a graph in GFA format. */ template std::istream& read_gfa(std::istream& in, Graph& g, BetterEP betterEP) { assert(in); typedef typename graph_traits::vertex_descriptor V; typedef typename vertex_property::type VP; typedef typename graph_traits::edge_descriptor E; typedef typename edge_property::type EP; // Add vertices if this graph is empty. bool addVertices = num_vertices(g) == 0; while (in && in.peek() != EOF) { switch (in.peek()) { case 'H': in >> expect("H\tVN:Z:"); if (in.peek() == '1') in >> expect("1.0\n"); else in >> expect("2.0\n"); assert(in); break; case 'S': { std::string uname; in >> expect("S\t") >> uname >> expect("\t"); assert(in); std::string seq; unsigned length = 0; if (isdigit(in.peek())) { // GFA 2 in >> length >> seq; assert(in); } else { // GFA 1 in >> seq; assert(in); assert(!seq.empty()); if (seq == "*") { in >> expect(" LN:i:") >> length; 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 { V u = find_vertex(uname, false, g); assert(get(vertex_index, g, u) < num_vertices(g)); (void)u; } break; } case 'L': { std::string uname, vname; 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(!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; } case 'E': { std::string ename, uname, vname; in >> expect("E\t") >> ename >> uname >> vname; assert(in); unsigned ustart, uend, vstart, vend; in >> ustart >> Skip('$') >> uend >> Skip('$') >> vstart >> Skip('$') >> vend >> Skip('$') >> Ignore('\n'); assert(in); unsigned ulength = uend - ustart; unsigned vlength = vend - vstart; if (ulength != vlength) { std::cerr << "error: alignment contains gaps: " << ename << '\t' << uname << '\t' << vname << '\n'; exit(EXIT_FAILURE); } V u = find_vertex(uname, g); V v = find_vertex(vname, g); int d = -ulength; EP ep(d); add_edge(u, v, ep, g); break; } case 'G': { std::string ename, uname, vname; in >> expect("G\t") >> ename >> uname >> vname; assert(in); EP ep; in >> ep >> Ignore('\n'); assert(in); V u = find_vertex(uname, g); V v = find_vertex(vname, g); E e; bool found; boost::tie(e, found) = edge(u, v, g); if (found) { // Parallel edge EP& ref = g[e]; ref = betterEP(ref, ep); } else add_edge(u, v, ep, g); break; } case '#': // comment case 'C': // GFA1 containment case 'F': // GFA2 fragment case 'O': // GFA2 ordered path case 'P': // GFA1 path case 'U': // GFA2 unordered set in >> Ignore('\n'); break; default: { std::string s; in >> s >> Ignore('\n'); std::cerr << "warning: unknown record type: `" << s << "'\n"; } } } assert(in.eof()); return in; } #endif abyss-2.2.4/Graph/GraphAlgorithms.h000066400000000000000000000125621361462241400171560ustar00rootroot00000000000000#ifndef GRAPHALGORITHMS_H #define GRAPHALGORITHMS_H 1 #include "Graph/Properties.h" #include "ConstrainedSearch.h" // for constrainedSearch #include #include #include #include using boost::graph_traits; /** * Return the transitive edges. * Find the subset of edges (u,w) in E for which there exists a vertex * v such that the edges (u,v) and (v,w) exist in E. * This algorithm is not a general-purpose transitive reduction * algorithm. It is able to find transitive edges with exactly one * intermediate vertex. */ template void find_transitive_edges(const Graph& g, OutIt out) { typedef graph_traits GTraits; typedef typename GTraits::adjacency_iterator adjacency_iterator; typedef typename GTraits::edge_descriptor edge_descriptor; typedef typename GTraits::out_edge_iterator out_edge_iterator; typedef typename GTraits::vertex_descriptor vertex_descriptor; typedef typename GTraits::vertex_iterator vertex_iterator; std::vector seen(num_vertices(g)); std::pair urange = vertices(g); for (vertex_iterator uit = urange.first; uit != urange.second; ++uit) { vertex_descriptor u = *uit; if (get(vertex_removed, g, u)) continue; // Clear the colour of the adjacent vertices. std::pair vrange = adjacent_vertices(u, g); for (adjacency_iterator vit = vrange.first; vit != vrange.second; ++vit) seen[get(vertex_index, g, *vit)] = false; // Set the colour of all vertices reachable in two hops. for (adjacency_iterator vit = vrange.first; vit != vrange.second; ++vit) { vertex_descriptor v = *vit; if (u == v) // ignore self loops continue; std::pair wrange = adjacent_vertices(v, g); for (adjacency_iterator wit = wrange.first; wit != wrange.second; ++wit) { vertex_descriptor w = *wit; if (v == w) // ignore self loops continue; seen[get(vertex_index, g, w)] = true; } } // Find the transitive edges. std::pair uvrange = out_edges(u, g); for (out_edge_iterator uvit = uvrange.first; uvit != uvrange.second; ++uvit) { edge_descriptor uv = *uvit; vertex_descriptor v = target(uv, g); if (seen[get(vertex_index, g, v)]) { // The edge (u,v) is transitive. Mark it for removal. *out++ = uv; } } } } /** Remove edges from the graph that satisfy the predicate. * @return the number of edges removed */ template size_t removeEdgeIf(Predicate predicate, Graph& g) { typedef graph_traits GTraits; typedef typename GTraits::edge_descriptor edge_descriptor; typedef typename GTraits::edge_iterator edge_iterator; size_t n = 0; std::pair 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 */ template void remove_edges(Graph& g, It first, It last) { for (It it = first; it != last; ++it) remove_edge(*it, g); } /** * Remove transitive edges from the specified graph. * Find and remove the subset of edges (u,w) in E for which there * exists a vertex v such that the edges (u,v) and (v,w) exist in E. * This algorithm is not a general-purpose transitive reduction * algorithm. It is able to find transitive edges with exactly one * intermediate vertex. * @return the number of transitive edges removed from g */ template unsigned remove_transitive_edges(Graph& g) { typedef typename graph_traits::edge_descriptor edge_descriptor; std::vector transitive; find_transitive_edges(g, back_inserter(transitive)); remove_edges(g, transitive.begin(), transitive.end()); return transitive.size(); } /** * Find transitive edges when more than one intermediate vertex exists * between u and w. */ template void find_complex_transitive_edges(Graph& g, OutIt out) { typedef graph_traits GTraits; typedef typename GTraits::vertex_descriptor vertex_descriptor; typedef typename GTraits::edge_iterator edge_iterator; //ConstrainedSearch anyPath(100000, 2, false); edge_iterator efirst, elast; for (boost::tie(efirst, elast) = edges(g); efirst != elast; efirst++) { vertex_descriptor u = source(*efirst, g); Constraint c = std::make_pair(target(*efirst, g), 100000); Constraints cs; cs.push_back(c); ContigPaths cp; unsigned numVisited = 0; constrainedSearch(g, u, cs, cp, numVisited); if (cp.size() > 1) *out++ = *efirst; } } /** * Remove transitive edges from the specified graph. * Find and remove the subset of edges (u,w) in E for which there * exists a vertex path v such that the edges (u,v) and (v,w) exist in E. * @return the number of transitive edges removed from g */ template unsigned remove_complex_transitive_edges(Graph& g) { typedef typename graph_traits::edge_descriptor edge_descriptor; std::vector transitive; find_complex_transitive_edges(g, back_inserter(transitive)); remove_edges(g, transitive.begin(), transitive.end()); return transitive.size(); } #endif abyss-2.2.4/Graph/GraphIO.h000066400000000000000000000044421361462241400153520ustar00rootroot00000000000000#ifndef GRAPHIO_H #define GRAPHIO_H 1 #include "Graph/Options.h" #include "AdjIO.h" #include "AsqgIO.h" #include "DistIO.h" #include "DotIO.h" #include "FastaIO.h" #include "GfaIO.h" #include "SAMIO.h" #include #include // for abort #include #include #include /** Write the graph g to the specified output stream in the format * specified by opt::format. */ template std::ostream& write_graph(std::ostream& out, const Graph& g, const std::string& program, const std::string& commandLine) { switch (opt::format) { case ADJ: return out << adj_writer(g); case ASQG: return write_asqg(out, g); case DIST: return write_dist(out, g); case DOT: case DOT_MEANCOV: return out << dot_writer(g); case GFA1: return write_gfa1(out, g); case GFA2: return write_gfa2(out, g); case SAM: return write_sam(out, g, program, commandLine); default: assert(false); abort(); } } #include "ContigGraph.h" /** Read a graph. */ template std::istream& read_graph(std::istream& in, ContigGraph& g, BetterEP betterEP) { in >> std::ws; assert(in); switch (in.peek()) { case '@': // @SQ: SAM format return read_sam_header(in, g); case 'd': // digraph: GraphViz dot format (directed graph) case 'g': // graph: GraphViz dot format (undirected graph) return read_dot(in, g, betterEP); 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, betterEP); 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 return read_adj(in, g, betterEP); } } /** Disallow parallel edges. */ struct DisallowParallelEdges { template EP operator()(const EP& a, const EP& b) const { std::cerr << "error: parallel edges:" " [" << a << "], [" << b << "]\n"; exit(EXIT_FAILURE); } }; /** Read a graph. */ template std::istream& operator>>(std::istream& in, ContigGraph& g) { return read_graph(in, g, DisallowParallelEdges()); } #endif abyss-2.2.4/Graph/GraphUtil.h000066400000000000000000000050761361462241400157640ustar00rootroot00000000000000#ifndef GRAPHUTIL_H #define GRAPHUTIL_H 1 #include "Histogram.h" #include #include #include using boost::graph_traits; /** Return the number of vertices that have been marked as removed. */ template typename graph_traits::vertices_size_type num_vertices_removed(const Graph& g) { typedef graph_traits GTraits; typedef typename GTraits::vertices_size_type vertices_size_type; typedef typename GTraits::vertex_iterator vertex_iterator; vertices_size_type n = 0; std::pair vit = vertices(g); for (vertex_iterator u = vit.first; u != vit.second; ++u) if (get(vertex_removed, g, *u)) n++; return n; } /** Print a histogram of the degree. */ template Histogram printHistogram(const Graph& g) { typedef typename graph_traits::vertex_iterator vertex_iterator; Histogram h; std::pair 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 std::ostream& printGraphStats(std::ostream& out, const Graph& g) { using std::setprecision; 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; 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); return out << "Degree: " << h.barplot(h.maximum() + 1) << "\n" " 01234\n" "0: " << setprecision(2) << (float)100 * n0 / n << "% " "1: " << setprecision(2) << (float)100 * n1 / n << "% " "2-4: " << setprecision(2) << (float)100 * n234 / n << "% " "5+: " << setprecision(2) << (float)100 * n5 / n << "% " "max: " << h.maximum() << std::endl; } /** Pass graph statistics -- values only . */ template std::vector 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() << 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(); #endif } #endif abyss-2.2.4/Graph/HashGraph.h000066400000000000000000000260201361462241400157220ustar00rootroot00000000000000#ifndef HASH_GRAPH_H #define HASH_GRAPH_H #include "Common/UnorderedMap.h" #include "Common/UnorderedSet.h" #include "Graph/Properties.h" #include #include #include #include #define DEFAULT_VERTEX_COLOR "gray" template class HashGraph { public: typedef HashGraph Graph; typedef boost::graph_traits GraphTraits; typedef typename GraphTraits::vertex_descriptor vertex_descriptor; typedef typename GraphTraits::vertex_property_type vertex_property_type; typedef typename GraphTraits::edge_descriptor edge_descriptor; typedef typename GraphTraits::edge_property_type edge_property_type; typedef typename GraphTraits::out_edge_iterator out_edge_iterator; typedef typename GraphTraits::adjacency_iterator adjacency_iterator; typedef typename GraphTraits::degree_size_type degree_size_type; typedef typename GraphTraits::vertex_iterator vertex_iterator; typedef typename GraphTraits::vertices_size_type vertices_size_type; typedef typename GraphTraits::VertexList VertexList; typedef typename GraphTraits::VertexListIterator VertexListIterator; typedef typename GraphTraits::EdgeList EdgeList; protected: typedef unordered_map > VertexMap; typedef std::pair VertexMapEntry; typedef unordered_map VertexColorMap; VertexMap m_vertices; VertexColorMap m_vertexColor; size_t m_numEdges; public: typedef typename VertexMap::const_iterator VertexMapIterator; HashGraph() : m_numEdges(0) {} size_t approxMemSize() { size_t pointer_size = sizeof(void *); size_t entry_bytes = m_numEdges * sizeof(vertex_descriptor); size_t filled_bucket_bytes = m_vertices.size() * (sizeof(typename VertexMap::value_type) + 3 * 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; } void set_vertex_color(const vertex_descriptor& v, const std::string& color) { m_vertexColor[v] = color; } std::string get_vertex_color(const vertex_descriptor& v) const { typename VertexColorMap::const_iterator i = m_vertexColor.find(v); if (i == m_vertexColor.end()) return DEFAULT_VERTEX_COLOR; return i->second; } std::pair get_vertex_map_entries() const { return std::pair (m_vertices.begin(), m_vertices.end()); } vertices_size_type num_vertices() const { return m_vertices.size(); } std::pair get_successors(const vertex_descriptor& v) const { typename VertexMap::const_iterator i = m_vertices.find(v); assert(i != m_vertices.end()); VertexListIterator begin = i->second.begin(); VertexListIterator end = i->second.end(); return std::pair (begin, end); } degree_size_type out_degree(const vertex_descriptor& v) const { typename VertexMap::const_iterator i = m_vertices.find(v); if (i == m_vertices.end()) return 0; return i->second.size(); } typename VertexMap::iterator init_vertex(const vertex_descriptor &v) { bool inserted; VertexList successors; successors.reserve(1); VertexMapEntry entry(v, successors); typename VertexMap::iterator i; boost::tie(i, inserted) = m_vertices.insert(entry); assert(inserted); return i; } std::pair add_edge(const vertex_descriptor& u, const vertex_descriptor& v) { bool edgeInserted = false; typename VertexMap::iterator i = m_vertices.find(u); if (i == m_vertices.end()) i = init_vertex(u); VertexList& successors = i->second; if (std::find(successors.begin(), successors.end(), v) == successors.end()) { successors.push_back(v); m_numEdges++; edgeInserted = true; } i = m_vertices.find(v); if (i == m_vertices.end()) init_vertex(v); return std::pair (edge_descriptor(u, v), edgeInserted); } }; namespace boost { template struct graph_traits< HashGraph > { // Graph typedef VertexType vertex_descriptor; typedef std::pair edge_descriptor; typedef boost::directed_tag directed_category; typedef boost::allow_parallel_edge_tag edge_parallel_category; struct traversal_category : boost::incidence_graph_tag, boost::adjacency_graph_tag, boost::vertex_list_graph_tag, boost::edge_list_graph_tag { }; // BidirectionalGraph typedef void in_edge_iterator; // VertexListGraph typedef std::vector VertexList; typedef typename std::vector::const_iterator VertexListIterator; typedef unsigned vertices_size_type; // EdgeListGraph typedef void edges_size_type; // PropertyGraph typedef std::string vertex_bundled; typedef std::string vertex_property_type; typedef no_property edge_bundled; typedef no_property edge_property_type; // IncidenceGraph typedef std::vector EdgeList; typedef unsigned degree_size_type; class vertex_iterator : public std::iterator { protected: void init(bool end) { boost::tie(m_it, m_end) = m_g->get_vertex_map_entries(); if (end) m_it = m_end; } public: vertex_iterator() {} vertex_iterator(const HashGraph& g, bool end) : m_g(&g) { init(end); } vertex_descriptor operator *() const { return m_it->first; } bool operator ==(const vertex_iterator& it) const { return m_it == it.m_it; } bool operator !=(const vertex_iterator& it) const { return m_it != it.m_it; } vertex_iterator& operator ++() { ++m_it; return *this; } vertex_iterator operator++(int) { vertex_iterator it = *this; ++*this; return it; } private: const HashGraph* m_g; typename HashGraph::VertexMapIterator m_it, m_end; }; struct adjacency_iterator : public std::iterator { protected: void init(bool end) { boost::tie(m_successor, m_successor_end) = m_g->get_successors(m_v); if (end) m_successor = m_successor_end; } public: adjacency_iterator() { } adjacency_iterator(const HashGraph& g, vertex_descriptor v, bool end) : m_g(&g), m_v(v) { init(end); } vertex_descriptor operator*() const { return *m_successor; } bool operator==(const adjacency_iterator& it) const { return m_successor == it.m_successor; } bool operator!=(const adjacency_iterator& it) const { return !(*this == it); } adjacency_iterator& operator++() { m_successor++; return *this; } adjacency_iterator operator++(int) { adjacency_iterator it = *this; ++*this; return it; } private: const HashGraph* m_g; vertex_descriptor m_v; VertexListIterator m_successor; VertexListIterator m_successor_end; }; struct out_edge_iterator : public std::iterator { protected: void init(bool end) { boost::tie(m_successor, m_successor_end) = m_g->get_successors(m_v); if (end) m_successor = m_successor_end; } public: out_edge_iterator() { } out_edge_iterator(const HashGraph& g, vertex_descriptor v) : m_g(&g), m_v(v) { init(false); } out_edge_iterator(const HashGraph& g, vertex_descriptor v, bool end) : m_g(&g), m_v(v) { init(end); } edge_descriptor operator*() const { return edge_descriptor(m_v, *m_successor); } bool operator==(const out_edge_iterator& it) const { return m_successor == it.m_successor; } bool operator!=(const out_edge_iterator& it) const { return !(*this == it); } out_edge_iterator& operator++() { m_successor++; return *this; } out_edge_iterator operator++(int) { out_edge_iterator it = *this; ++*this; return it; } private: const HashGraph* m_g; vertex_descriptor m_v; VertexListIterator m_successor; VertexListIterator m_successor_end; }; // out_edge_iterator }; // graph_traits } // IncidenceGraph template std::pair< typename HashGraph::out_edge_iterator, typename HashGraph::out_edge_iterator> out_edges( typename HashGraph::vertex_descriptor v, const HashGraph& g) { typedef typename HashGraph::out_edge_iterator out_edge_iterator; return std::pair (out_edge_iterator(g, v), out_edge_iterator(g, v, true)); } template typename HashGraph::degree_size_type out_degree( typename HashGraph::vertex_descriptor v, const HashGraph& g) { return g.out_degree(v); } // AdjacencyGraph template std::pair< typename HashGraph::adjacency_iterator, typename HashGraph::adjacency_iterator> adjacent_vertices( typename HashGraph::vertex_descriptor v, const HashGraph& g) { typedef typename HashGraph::adjacency_iterator adjacency_iterator; return std::pair (adjacency_iterator(g, v, false), adjacency_iterator(g, v, true)); } // VertexListGraph template std::pair< typename HashGraph::vertex_iterator, typename HashGraph::vertex_iterator> vertices(const HashGraph& g) { typedef typename HashGraph::vertex_iterator vertex_iterator; return std::pair (vertex_iterator(g, false), vertex_iterator(g, true)); } template typename HashGraph::vertices_size_type num_vertices(const HashGraph& g) { return g.num_vertices(); } // MutableGraph template std::pair::edge_descriptor, bool> add_edge( typename HashGraph::vertex_descriptor u, typename HashGraph::vertex_descriptor v, HashGraph& g) { return g.add_edge(u, v); } // PropertyGraph // (dummy functions so that HashGraph // works with DotIO.h routines) template bool get(vertex_removed_t, const HashGraph&, typename HashGraph::vertex_descriptor) { return false; } template void put(vertex_removed_t, HashGraph&, typename HashGraph::vertex_descriptor, bool) { return; } template typename HashGraph::vertex_descriptor get(vertex_name_t, const HashGraph&, typename HashGraph::vertex_descriptor v) { return v; } template std::string get(vertex_bundle_t, const HashGraph& g, typename HashGraph::vertex_descriptor v) { const std::string& color = g.get_vertex_color(v); std::ostringstream ss; ss << "color=" << color; assert(ss); return ss.str(); } #endif abyss-2.2.4/Graph/Makefile.am000066400000000000000000000016021361462241400157370ustar00rootroot00000000000000bin_PROGRAMS = abyss-gc abyss-todot abyss_todot_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common abyss_todot_LDFLAGS = -L. abyss_todot_LDADD = \ $(top_builddir)/Common/libcommon.a abyss_todot_SOURCES = todot.cc EXTRA_DIST = \ AdjIO.h \ AllPathsSearch.h \ AsqgIO.h \ Assemble.h \ BidirectionalBFS.h \ BidirectionalBFSVisitor.h \ BreadthFirstSearch.h \ ConstrainedBFSVisitor.h \ ConstrainedBidiBFSVisitor.h \ ConstrainedSearch.h \ ContigGraph.h \ ContigGraphAlgorithms.h \ DefaultColorMap.h \ DepthFirstSearch.h \ DirectedGraph.h \ DistIO.h \ DotIO.h \ ExtendPath.h \ FastaIO.h \ GfaIO.h \ GraphAlgorithms.h \ GraphIO.h \ GraphUtil.h \ HashGraph.h \ Options.h \ Path.h \ PopBubbles.h \ Properties.h \ SAMIO.h \ UndirectedGraph.h abyss_gc_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common abyss_gc_LDADD = $(top_builddir)/Common/libcommon.a abyss_gc_SOURCES = gc.cc abyss-2.2.4/Graph/Options.h000066400000000000000000000004561361462241400155150ustar00rootroot00000000000000#ifndef GRAPH_OPTIONS_H #define GRAPH_OPTIONS_H 1 namespace opt { /** The size of a k-mer. */ extern unsigned k; /** The file format of the graph when writing. */ extern int format; } /** Enumeration of output formats */ enum { ADJ, ASQG, DIST, DOT, DOT_MEANCOV, GFA1, GFA2, SAM, TSV }; #endif abyss-2.2.4/Graph/Path.h000066400000000000000000000017651361462241400147620ustar00rootroot00000000000000#ifndef PATH_H_ #define PATH_H_ #include #include #include #include #include enum PathSearchResult { FOUND_PATH = 0, TOO_MANY_PATHS, TOO_MANY_BRANCHES, PATH_CONTAINS_CYCLE, MAX_COST_EXCEEDED, EXCEEDED_MEM_LIMIT, NO_PATH }; const char* PathSearchResultLabel[] = { "FOUND_PATH", "TOO_MANY_PATHS", "TOO_MANY_BRANCHES", "PATH_CONTAINS_CYCLE", "MAX_COST_EXCEEDED", "EXCEEDED_MEM_LIMIT", "NO_PATH" }; enum Direction { FORWARD = 0, REVERSE }; inline static const char* directionStr(Direction dir) { switch(dir) { case FORWARD: return "FORWARD"; case REVERSE: return "REVERSE"; default: assert(false); } } const unsigned NO_LIMIT = UINT_MAX; template class Path : public std::deque { public: std::string str() { std::stringstream s; typename std::deque::iterator i = this->begin(); for (; i != this->end(); i++) { if (i != this->begin()) s << ","; s << *i; } return s.str(); } }; #endif abyss-2.2.4/Graph/PopBubbles.h000066400000000000000000000130611361462241400161130ustar00rootroot00000000000000#ifndef POPBUBBLES_H #define POPBUBBLES_H 1 #include "Common/Options.h" #include "DepthFirstSearch.h" #include #include #include #include #include #include #include #include using boost::graph_traits; /** Record a topological order of the vertices. */ template struct TopoVisitor : public boost::default_dfs_visitor { TopoVisitor(OutIt it) : m_it(it) { } template void finish_vertex(const Vertex& u, Graph&) { *m_it++ = u; } private: OutIt m_it; }; /** Record a topological order of the vertices. */ template void topologicalSort(const Graph& g, It it) { using boost::default_color_type; using boost::property_map; using boost::vector_property_map; typedef typename property_map::type VertexIndexMap; typedef vector_property_map ColorMap; depthFirstSearch(g, TopoVisitor(it), ColorMap(num_vertices(g))); } /** Return true if the specified sequence of vertices is a bubble. */ template bool isBubble(const Graph& g, It first, It last) { typedef typename graph_traits::adjacency_iterator Ait; typedef typename graph_traits::in_edge_iterator Iit; typedef typename graph_traits::vertex_descriptor V; assert(last - first > 1); if (last - first == 2) return false; // unambiguous edge if (*first == get(vertex_complement, g, last[-1])) return false; // palindrome std::set targets(first, first + 1); for (It it = first; it != last - 1; ++it) { std::pair adj = adjacent_vertices(*it, g); targets.insert(adj.first, adj.second); } std::set sources(last - 1, last); for (It it = first + 1; it != last; ++it) { std::pair adj = in_edges(*it, g); for (Iit eit = adj.first; eit != adj.second; ++eit) sources.insert(source(*eit, g)); } std::set bubble(first, last); return sources == bubble && targets == bubble; } typedef std::vector Bubble; typedef std::vector Bubbles; /** Discover bubbles. */ template Bubbles discoverBubbles(const Graph& g) { typedef typename graph_traits::vertex_descriptor V; std::vector topo(num_vertices(g)); topologicalSort(g, topo.rbegin()); Bubbles bubbles; typedef typename std::vector::const_iterator It; for (It first = topo.begin(); first != topo.end(); ++first) { int sum = out_degree(*first, g); if (sum < 2) continue; if (opt::verbose > 3) std::cerr << "* " << get(vertex_name, g, *first) << '\n'; for (It it = first + 1; it != topo.end(); ++it) { unsigned indeg = in_degree(*it, g); unsigned outdeg = out_degree(*it, g); sum -= indeg; if (opt::verbose > 3) std::cerr << get(vertex_name, g, *it) << '\t' << indeg << '\t' << outdeg << '\t' << sum << '\t' << sum + (int)outdeg << '\n'; if (indeg == 0 || sum < 0) break; if (sum == 0) { It last = it + 1; if (isBubble(g, first, last)) { if (opt::verbose > 3) std::cerr << "good\n"; bubbles.push_back(Bubble(first, last)); first = it - 1; } break; } if (outdeg == 0) break; sum += outdeg; } } return bubbles; } /** Return the length of the longest path through the bubble. */ template int longestPath(const Graph& g, const Bubble& topo) { using boost::tie; typedef graph_traits GTraits; typedef typename GTraits::edge_descriptor E; typedef typename GTraits::out_edge_iterator Eit; typedef typename GTraits::vertex_descriptor V; EdgeWeightMap weight(g); /* GCC 4.4.6 has a bug that prevents ContigNode being used as the * key of a std::map. Possibly related to * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390 */ boost::unordered_map distance; distance[topo.front()] = 0; for (Bubble::const_iterator it = topo.begin(); it != topo.end(); ++it) { V u = *it; Eit eit, elast; for (tie(eit, elast) = out_edges(u, g); eit != elast; ++eit) { E e = *eit; V v = target(e, g); distance[v] = std::max( distance[v], distance[u] + weight[e]); } } V v = topo.back(); return distance[v] - g[v].length; } /** Scaffold over the bubble between vertices u and w. * Add an edge (u,w) with the distance property set to the length of * the largest branch of the bubble. */ template void scaffoldBubble(Graph& g, const Bubble& bubble) { typedef graph_traits GTraits; typedef typename GTraits::vertex_descriptor V; assert(bubble.size() > 2); V u = bubble.front(), w = bubble.back(); if (edge(u, w, g).second) { // Already scaffolded. return; } assert(isBubble(g, bubble.begin(), bubble.end())); add_edge(u, w, std::max(longestPath(g, bubble), 1), g); } /** Replace each bubble in the graph with a single edge. * Remove the vertices in the bubbles from the graph. * @return the vertices that were removed from the graph */ template std::vector::vertex_descriptor> popBubbles(Graph& g) { typedef typename graph_traits::vertex_descriptor V; typedef std::vector Vertices; Vertices popped; Bubbles bubbles = discoverBubbles(g); for (Bubbles::const_iterator it = bubbles.begin(); it != bubbles.end(); ++it) { scaffoldBubble(g, *it); popped.insert(popped.end(), it->begin() + 1, it->end() - 1); } for (typename Vertices::const_iterator it = popped.begin(); it != popped.end(); ++it) { V u = *it; clear_vertex(u, g); remove_vertex(u, g); } return popped; } #endif abyss-2.2.4/Graph/Properties.h000066400000000000000000000041071361462241400162130ustar00rootroot00000000000000#ifndef GRAPH_PROPERTIES_H #define GRAPH_PROPERTIES_H 1 #include #include #include /** The distance between two vertices. */ enum edge_distance_t { edge_distance }; /** The complementary vertex of a skew-symmetric graph. */ enum vertex_complement_t { vertex_complement }; /** The index of a contig. */ enum vertex_contig_index_t { vertex_contig_index }; /** The name of a contig without an orientation. */ enum vertex_contig_name_t { vertex_contig_name }; /** The coverage of a vertex. */ enum vertex_coverage_t { vertex_coverage }; /** The length of a vertex. */ enum vertex_length_t { vertex_length }; /** A property indicating that this vertex has been removed. */ enum vertex_removed_t { vertex_removed }; /** The orientation of a vertex. */ enum vertex_sense_t { vertex_sense }; using boost::edge_bundle; using boost::edge_bundle_t; using boost::edge_name; using boost::edge_name_t; using boost::edge_weight; using boost::edge_weight_t; using boost::no_property; using boost::vertex_bundle; using boost::vertex_bundle_t; using boost::vertex_index; using boost::vertex_index_t; using boost::vertex_name; using boost::vertex_name_t; using boost::edge_bundle_type; using boost::edge_property; using boost::vertex_bundle_type; using boost::vertex_property; namespace boost { BOOST_INSTALL_PROPERTY(edge, distance); BOOST_INSTALL_PROPERTY(vertex, complement); BOOST_INSTALL_PROPERTY(vertex, contig_index); BOOST_INSTALL_PROPERTY(vertex, contig_name); BOOST_INSTALL_PROPERTY(vertex, coverage); BOOST_INSTALL_PROPERTY(vertex, length); BOOST_INSTALL_PROPERTY(vertex, removed); BOOST_INSTALL_PROPERTY(vertex, sense); } /** No property. */ struct NoProperty { NoProperty(...) { } bool operator==(const NoProperty&) const { return true; } bool operator!=(const NoProperty&) const { return false; } friend std::ostream& operator<<(std::ostream& out, const NoProperty&) { return out; } friend std::istream& operator>>(std::istream& in, NoProperty&) { return in; } }; template void put(Tag, NoProperty&, unsigned) { } #endif abyss-2.2.4/Graph/SAMIO.h000066400000000000000000000054101361462241400147250ustar00rootroot00000000000000#ifndef SAMIO_H #define SAMIO_H 1 #include "Common/ContigNode.h" #include "Graph/Properties.h" #include #include #include #include using boost::graph_traits; /** Output a graph in SAM alignment format. * vertex_descriptor must be convertible to a ContigNode * vertex_property_type must have members length and coverage * edge_property_type must have a member distance */ template std::ostream& write_sam(std::ostream& out, const Graph& g, const std::string& program, const std::string& commandLine) { typedef typename graph_traits::vertex_iterator vertex_iterator; typedef typename vertex_property::type vertex_property_type; typedef typename graph_traits::edge_iterator edge_iterator; out << "@HD\tVN:1.0\n" "@PG\tID:" << program << "\tVN:" VERSION "\t" "CL:" << commandLine << '\n'; std::pair vit = vertices(g); for (vertex_iterator u = vit.first; u != vit.second; ++u, ++u) { if (get(vertex_removed, g, *u)) continue; const vertex_property_type& vp = g[*u]; out << "@SQ\tSN:" << get(vertex_contig_name, g, *u) << "\tLN:" << vp.length; if (vp.coverage > 0) out << "\tXC:" << vp.coverage; out << '\n'; } std::pair eit = edges(g); for (edge_iterator e = eit.first; e != eit.second; ++e) { 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) continue; unsigned flag = u.sense() == v.sense() ? 0 : 0x10; //FREVERSE unsigned alen = -distance; unsigned pos = 1 + (u.sense() ? 0 : g[u].length - alen); out << get(vertex_contig_name, g, v) // QNAME << '\t' << flag // FLAG << '\t' << get(vertex_contig_name, g, u) // RNAME << '\t' << pos // POS << "\t255\t"; // MAPQ // CIGAR unsigned clip = g[v].length - alen; if (u.sense()) out << clip << 'H' << alen << "M\t"; else out << alen << 'M' << clip << "H\t"; // MRNM MPOS ISIZE SEQ QUAL out << "*\t0\t0\t*\t*\n"; } return out; } template std::istream& read_sam_header(std::istream& in, Graph& g) { typedef typename graph_traits::vertex_descriptor V; typedef typename vertex_property::type VP; assert(in); for (std::string line; in.peek() == '@' && getline(in, line);) { std::istringstream ss(line); std::string type; ss >> type; if (type != "@SQ") continue; std::string s; VP vp; ss >> expect(" SN:") >> s >> expect(" LN:") >> vp; assert(ss); V u = add_vertex(vp, g); put(vertex_name, g, u, s); } if (g.num_vertices() == 0) { std::cerr << "error: no @SQ records in the SAM header\n"; exit(EXIT_FAILURE); } return in; } #endif abyss-2.2.4/Graph/UndirectedGraph.h000066400000000000000000000552501361462241400171340ustar00rootroot00000000000000#ifndef UNDIRECTEDGRAPH_H #define UNDIRECTEDGRAPH_H 1 #include "Common/ContigNode.h" #include "Common/Hash.h" #include "Graph/Properties.h" #include #include #include #include #include /** * An edge for an undirected graph, having the key property that * (u, v) == (v, u). The unsigned values here are the vertex_descriptor's. */ class UndirectedEdge : public std::pair { public: UndirectedEdge() : std::pair() {} UndirectedEdge(unsigned u, unsigned v) : std::pair(u, v) {} bool operator ==(const UndirectedEdge& e) const { return (first == e.first && second == e.second) || (first == e.second && second == e.first); } bool operator !=(const UndirectedEdge& e) const { return !(*this == e); } size_t hashCode() const { return first ^ second; } }; /** * The hash function for an undirected edge, having the key property that * hash(u, v) == hash(v, u). */ NAMESPACE_STD_HASH_BEGIN template <> struct hash { /** * Hash function for graph vertex type (vertex_descriptor) */ size_t operator()(const UndirectedEdge& e) const { return e.hashCode(); } }; NAMESPACE_STD_HASH_END /** A undirected graph. */ template class UndirectedGraph { class Vertex; typedef typename std::vector Vertices; class Edge; typedef typename std::vector Edges; public: // Graph /* typedef ContigNode vertex_descriptor; */ typedef unsigned vertex_descriptor; // IncidenceGraph typedef UndirectedEdge edge_descriptor; typedef unsigned degree_size_type; // BidirectionalGraph typedef void in_edge_iterator; // VertexListGraph typedef unsigned vertices_size_type; // EdgeListGraph typedef unsigned edges_size_type; // PropertyGraph typedef VertexProp vertex_bundled; typedef VertexProp vertex_property_type; typedef EdgeProp edge_bundled; typedef EdgeProp edge_property_type; typedef boost::undirected_tag directed_category; typedef boost::allow_parallel_edge_tag edge_parallel_category; struct traversal_category : boost::incidence_graph_tag, boost::adjacency_graph_tag, boost::vertex_list_graph_tag, boost::edge_list_graph_tag { }; /** Iterate through the vertices of this graph. */ class vertex_iterator : public std::iterator { public: vertex_iterator() { } explicit vertex_iterator(vertices_size_type v) : m_v(v) { } const vertex_descriptor& operator *() const { return m_v; } bool operator ==(const vertex_iterator& it) const { return m_v == it.m_v; } bool operator !=(const vertex_iterator& it) const { return m_v != it.m_v; } vertex_iterator& operator ++() { ++m_v; return *this; } vertex_iterator operator ++(int) { vertex_iterator it = *this; ++*this; return it; } private: vertex_descriptor m_v; }; /** Iterate through the out-edges. */ class out_edge_iterator : public std::iterator { typedef typename Edges::const_iterator const_iterator; public: out_edge_iterator() { } out_edge_iterator(const const_iterator& it, vertex_descriptor src) : m_it(it), m_src(src) { } edge_descriptor operator *() const { return edge_descriptor(m_src, m_it->target()); } bool operator ==(const out_edge_iterator& it) const { return m_it == it.m_it; } bool operator !=(const out_edge_iterator& it) const { return m_it != it.m_it; } out_edge_iterator& operator ++() { ++m_it; return *this; } out_edge_iterator operator ++(int) { out_edge_iterator it = *this; ++*this; return it; } const edge_property_type& get_property() const { return m_it->get_property(); } private: const_iterator m_it; vertex_descriptor m_src; }; /** Iterate through adjacent vertices. */ class adjacency_iterator : public Edges::const_iterator { typedef typename Edges::const_iterator It; public: adjacency_iterator() { } adjacency_iterator(const It& it) : It(it) { } vertex_descriptor operator*() const { return It::operator*().target(); } }; /** Iterate through edges. */ class edge_iterator : public std::iterator { void nextVertex() { vertex_iterator vlast = m_g->vertices().second; for (; m_vit != vlast; ++m_vit) { std::pair adj = m_g->adjacent_vertices(*m_vit); /* * Since each edge exists as both (u, v) and * (v, u), require `adj.first >= *m_vit` to visit only * one of the two possible forms. */ if (adj.first != adj.second && *adj.first >= *m_vit) { m_eit = adj.first; return; } } // Set m_eit to a known value. static const adjacency_iterator s_eitNULL; m_eit = s_eitNULL; } public: edge_iterator() { } edge_iterator(const UndirectedGraph* 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 == m_g->adjacent_vertices(*m_vit).second) { ++m_vit; nextVertex(); } return *this; } edge_iterator operator++(int) { edge_iterator it = *this; ++*this; return it; } private: const UndirectedGraph* m_g; vertex_iterator m_vit; adjacency_iterator m_eit; }; private: /** A vertex and its properties. */ class Vertex { public: Vertex() { } Vertex(const vertex_property_type& p) : m_prop(p) { } /** Return the properties of this vertex. */ const vertex_property_type& get_property() const { return m_prop; } /** Returns an iterator-range to the out edges of vertex u. */ std::pair out_edges(vertex_descriptor u) const { return make_pair(out_edge_iterator(m_edges.begin(), u), out_edge_iterator(m_edges.end(), u)); } /** Returns an iterator-range to the adjacent vertices. */ std::pair adjacent_vertices() const { return make_pair(m_edges.begin(), m_edges.end()); } /** Return the number of outgoing edges. */ degree_size_type out_degree() const { return m_edges.size(); } /** Add an edge to this vertex. */ bool add_edge(vertex_descriptor v, const edge_property_type& ep) { m_edges.push_back(Edge(v, ep)); return true; } /** Remove the edge to v from this vertex. */ void remove_edge(vertex_descriptor v) { m_edges.erase(remove(m_edges.begin(), m_edges.end(), v), m_edges.end()); } /** Remove all out edges from this vertex. */ void clear_out_edges() { m_edges.clear(); } /** Return the properties of the edge with target v. */ edge_property_type& operator[](vertex_descriptor v) { typename Edges::iterator it = find(m_edges.begin(), m_edges.end(), v); assert(it != m_edges.end()); return it->get_property(); } /** Return the properties of the edge with target v. */ const edge_property_type& operator[](vertex_descriptor v) const { typename Edges::const_iterator it = find(m_edges.begin(), m_edges.end(), v); assert(it != m_edges.end()); return it->get_property(); } /** Return true if edge (u,v) exists. */ bool edge(vertex_descriptor v) const { return count(m_edges.begin(), m_edges.end(), v) > 0; } /** Remove edges that satisfy the predicate. */ template void remove_edge_if(vertex_descriptor u, Predicate predicate) { typename Edges::iterator out = m_edges.begin(); for (typename Edges::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { if (!predicate(edge_descriptor(u, it->target()))) { if (out != it) *out = *it; ++out; } } m_edges.erase(out, m_edges.end()); } private: Edges m_edges; vertex_property_type m_prop; }; /** A directed edge. */ class Edge { public: explicit Edge(vertex_descriptor v, const edge_property_type& ep) : m_target(v), m_ep(ep) { } /** Returns the target vertex of this edge. */ vertex_descriptor target() const { return m_target; } /** Return true if the target of this edge is v. */ bool operator ==(const vertex_descriptor& v) const { return m_target == v; } edge_property_type& get_property() { return m_ep; } const edge_property_type& get_property() const { return m_ep; } private: /** The target vertex of this edge. */ vertex_descriptor m_target; edge_property_type m_ep; }; public: /** Create an empty graph. */ UndirectedGraph() { } /** Create a graph with n vertices and zero edges. */ UndirectedGraph(vertices_size_type n) : m_vertices(n) { } /** Swap this graph with graph x. */ void swap(UndirectedGraph& x) { m_vertices.swap(x.m_vertices); m_removed.swap(x.m_removed); } /** Return properties of vertex u. */ const vertex_property_type& operator[](vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].get_property(); } /** Returns an iterator-range to the vertices. */ std::pair vertices() const { return make_pair(vertex_iterator(0), vertex_iterator(num_vertices())); } /** Remove all the edges and vertices from this graph. */ void clear() { m_vertices.clear(); m_removed.clear(); } /** Add a vertex to this graph. */ vertex_descriptor add_vertex( const vertex_property_type& vp = vertex_property_type()) { m_vertices.push_back(Vertex(vp)); return vertex_descriptor(num_vertices() - 1); } /** Returns an iterator-range to the out edges of vertex u. */ std::pair out_edges(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].out_edges(u); } /** Returns an iterator-range to the adjacent vertices of * vertex u. */ std::pair adjacent_vertices(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].adjacent_vertices(); } /** Adds edge (u,v) to this graph. */ std::pair add_edge(vertex_descriptor u, vertex_descriptor v, const edge_property_type& ep = edge_property_type()) { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); vertices_size_type vi = get(vertex_index, *this, v); assert(vi < num_vertices()); m_vertices[vi].add_edge(u, ep); return make_pair(edge_descriptor(u, v), m_vertices[ui].add_edge(v, ep)); } /** Remove the edge (u,v) from this graph. */ void remove_edge(vertex_descriptor u, vertex_descriptor v) { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); vertices_size_type vi = get(vertex_index, *this, v); assert(vi < num_vertices()); m_vertices[ui].remove_edge(v); m_vertices[ui].remove_edge(u); } /** Remove the edge e from this graph. */ void remove_edge(edge_descriptor e) { remove_edge(e.first, e.second); } #if 0 /** Remove all out edges from vertex u. */ void clear_out_edges(vertex_descriptor u) { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); m_vertices[ui].clear_out_edges(); } #endif /** Remove all edges to and from vertex u from this graph. * O(V+E) */ void clear_vertex(vertex_descriptor u) { std::pair adj = adjacent_vertices(u); for (adjacency_iterator v = adj.first; v != adj.second; ++v) remove_edge(*v, u); } /** Set the vertex_removed property. */ void put(vertex_removed_t, vertex_descriptor u, bool flag) { vertices_size_type ui = get(vertex_index, *this, u); if (ui >= m_removed.size()) m_removed.resize(ui + 1); m_removed[ui] = flag; } /** Remove vertex u from this graph. It is assumed that there * are no edges to or from vertex u. It is best to call * clear_vertex before remove_vertex. */ void remove_vertex(vertex_descriptor u) { put(vertex_removed, u, true); } /** Return the number of vertices. */ vertices_size_type num_vertices() const { return m_vertices.size(); } /** Return the number of edges. */ edges_size_type num_edges() const { edges_size_type n = 0; std::pair vit = vertices(); for (vertex_iterator v = vit.first; v != vit.second; ++v) n += out_degree(*v); /* should have (u, v) and (v, u) versions for each edge */ assert(n % 2 == 0); return n / 2; } /** Return the out degree of vertex u. */ degree_size_type out_degree(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return m_vertices[ui].out_degree(); } /** Return the nth vertex. */ static vertex_descriptor vertex(vertices_size_type n) { return vertex_descriptor(n); } /** Iterate through the edges of this graph. */ std::pair edges() const { std::pair vit = vertices(); return make_pair(edge_iterator(this, vit.first), edge_iterator(this, vit.second)); } /** Return the edge (u,v) if it exists and a flag indicating * whether the edge exists. */ std::pair edge( vertex_descriptor u, vertex_descriptor v) const { vertices_size_type ui = get(vertex_index, *this, u); assert(ui < num_vertices()); return make_pair(edge_descriptor(u, v), m_vertices[ui].edge(v)); } /** Return properties of edge e. */ edge_property_type& operator[](edge_descriptor e) { vertices_size_type ui = get(vertex_index, *this, e.first); assert(ui < num_vertices()); return m_vertices[ui][e.second]; } /** Return properties of edge e. */ const edge_property_type& operator[](edge_descriptor e) const { vertices_size_type ui = get(vertex_index, *this, e.first); assert(ui < num_vertices()); return m_vertices[ui][e.second]; } /** Remove edges that satisfy the predicate. */ template void remove_edge_if(Predicate predicate) { unsigned i = 0; for (typename Vertices::iterator it = m_vertices.begin(); it != m_vertices.end(); ++it) it->remove_edge_if(vertex(i++), predicate); } /** Return true if this vertex has been removed. */ bool is_removed(vertex_descriptor u) const { vertices_size_type ui = get(vertex_index, *this, u); return ui < m_removed.size() ? m_removed[ui] : false; } /** Set the name (usually contig ID) for a given vertex_descriptor */ void put(vertex_name_t, vertex_descriptor u, const Dictionary::name_type& name) { m_vertexNames.put(u, name); } /** Find a vertex_descriptor by name (usually contig ID) */ vertex_descriptor find_vertex(const Dictionary::name_type& name) const { return m_vertexNames.getIndex(name); } private: UndirectedGraph& operator =(const UndirectedGraph& x); /** The set of vertices. */ Vertices m_vertices; /** Bidirectional map of names to vertex_descriptors */ Dictionary m_vertexNames; /** Flags indicating vertices that have been removed. */ std::vector m_removed; }; namespace std { template inline void swap(UndirectedGraph& a, UndirectedGraph& b) { a.swap(b); } } // IncidenceGraph template std::pair< typename UndirectedGraph::out_edge_iterator, typename UndirectedGraph::out_edge_iterator> out_edges( typename UndirectedGraph::vertex_descriptor u, const UndirectedGraph& g) { return g.out_edges(u); } template typename UndirectedGraph::degree_size_type out_degree( typename UndirectedGraph::vertex_descriptor u, const UndirectedGraph& g) { return g.out_degree(u); } // AdjacencyGraph template std::pair< typename UndirectedGraph::adjacency_iterator, typename UndirectedGraph::adjacency_iterator> adjacent_vertices( typename UndirectedGraph::vertex_descriptor u, const UndirectedGraph& g) { return g.adjacent_vertices(u); } // VertexListGraph template typename UndirectedGraph::vertices_size_type num_vertices(const UndirectedGraph& g) { return g.num_vertices(); } template typename UndirectedGraph::vertex_descriptor vertex(typename UndirectedGraph::vertices_size_type ui, const UndirectedGraph& g) { return g.vertex(ui); } template std::pair::vertex_iterator, typename UndirectedGraph::vertex_iterator> vertices(const UndirectedGraph& g) { return g.vertices(); } // EdgeListGraph template typename UndirectedGraph::edges_size_type num_edges(const UndirectedGraph& g) { return g.num_edges(); } template std::pair::edge_iterator, typename UndirectedGraph::edge_iterator> edges(const UndirectedGraph& g) { return g.edges(); } // AdjacencyMatrix template std::pair::edge_descriptor, bool> edge( typename UndirectedGraph::vertex_descriptor u, typename UndirectedGraph::vertex_descriptor v, const UndirectedGraph& g) { return g.edge(u, v); } // VertexMutableGraph template typename UndirectedGraph::vertex_descriptor add_vertex(UndirectedGraph& g) { return g.add_vertex(); } template void remove_vertex( typename UndirectedGraph::vertex_descriptor u, UndirectedGraph& g) { g.remove_vertex(u); } // EdgeMutableGraph template void clear_vertex( typename UndirectedGraph::vertex_descriptor u, UndirectedGraph& g) { g.clear_vertex(u); } template std::pair::edge_descriptor, bool> add_edge( typename UndirectedGraph::vertex_descriptor u, typename UndirectedGraph::vertex_descriptor v, UndirectedGraph& g) { return g.add_edge(u, v); } template void remove_edge( typename UndirectedGraph::vertex_descriptor u, typename UndirectedGraph::vertex_descriptor v, UndirectedGraph& g) { g.remove_edge(u, v); } template void remove_edge( typename UndirectedGraph::edge_descriptor e, UndirectedGraph& g) { g.remove_edge(e); } // MutableIncidenceGraph template void clear_out_edges( typename UndirectedGraph::vertex_descriptor u, UndirectedGraph& g) { g.clear_out_edges(u); } // MutableEdgeListGraph template void remove_edge_if(Predicate predicate, UndirectedGraph& g) { g.remove_edge_if(predicate); } // PropertyGraph /** Return true if this vertex has been removed. */ template bool get(vertex_removed_t, const UndirectedGraph& g, typename UndirectedGraph::vertex_descriptor u) { return g.is_removed(u); } template void put(vertex_removed_t tag, UndirectedGraph& g, typename UndirectedGraph::vertex_descriptor u, bool flag) { g.put(tag, u, flag); } /** Return the properties of the edge of iterator eit. */ template const typename UndirectedGraph::edge_property_type& get(edge_bundle_t, const UndirectedGraph&, typename UndirectedGraph::out_edge_iterator eit) { return eit.get_property(); } // PropertyGraph template const VP& get(vertex_bundle_t, const UndirectedGraph& g, typename UndirectedGraph::vertex_descriptor u) { return g[u]; } template const EP& get(edge_bundle_t, const UndirectedGraph& g, typename UndirectedGraph::edge_descriptor e) { return g[e]; } // PropertyGraph vertex_index #if 0 namespace boost { template struct property_map, vertex_index_t> { typedef ContigNodeIndexMap type; typedef type const_type; }; } template ContigNodeIndexMap get(vertex_index_t, const UndirectedGraph&) { return ContigNodeIndexMap(); } template ContigNodeIndexMap::reference get(vertex_index_t tag, const UndirectedGraph& g, typename UndirectedGraph::vertex_descriptor u) { return get(get(tag, g), u); } #endif // VertexMutablePropertyGraph template typename UndirectedGraph::vertex_descriptor add_vertex(const VP& vp, UndirectedGraph& g) { return g.add_vertex(vp); } // EdgeMutablePropertyGraph template std::pair::edge_descriptor, bool> add_edge( typename UndirectedGraph::vertex_descriptor u, typename UndirectedGraph::vertex_descriptor v, const typename UndirectedGraph::edge_property_type& ep, UndirectedGraph& g) { return g.add_edge(u, v, ep); } // NamedGraph template typename UndirectedGraph::vertex_descriptor find_vertex(const std::string& name, const UndirectedGraph& g) { /* return find_vertex(name, g_contigNames); */ return g.find_vertex(name); } #if 0 template typename UndirectedGraph::vertex_descriptor find_vertex(const std::string& name, bool sense, const UndirectedGraph&) { return find_vertex(name, sense, g_contigNames); } #endif /** * Get the index of a vertex in UndirectedGraph's * internal data structures (vertex list and * vertex_descriptor => vertex_name map). */ template typename UndirectedGraph::vertices_size_type get(vertex_index_t, const UndirectedGraph&, typename UndirectedGraph::vertex_descriptor u) { /* * For UndirectedGraph, vertex_index and vertex_descriptor * are always the same, where `vertex_index` indicates the position of * the vertex in UndirectedGraph's vertex list (`m_vertices` above) * and also the position of the vertex in the * vertex_name <=> vertex_descriptor map (`m_vertexNames` above). * * For DirectedGraph, vertex_index and vertex_descriptor are * different types (unsigned and ContigNode, respectively), because * vertex names end with "+" or "-". */ return u; } /** * Set the name for a vertex. This is a std::string and usually * stores the contig ID. */ template void put(vertex_name_t tag, UndirectedGraph& g, typename UndirectedGraph::vertex_descriptor& u, const Dictionary::name_type& name) { g.put(tag, u, name); } #endif abyss-2.2.4/Graph/gc.cc000066400000000000000000000053371361462241400146140ustar00rootroot00000000000000/** Convert a graph to dot format. * Written by Shaun Jackman . */ #include "ContigGraph.h" #include "DirectedGraph.h" #include "GraphIO.h" #include "GraphUtil.h" #include "IOUtil.h" #include "Uncompress.h" #include #include #include using namespace std; #define PROGRAM "abyss-gc" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [FILE]...\n" "Count the number of vertices and edges in a graph.\n" "\n" " Options:\n" "\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 { unsigned k; // used by DotIO static int verbose; } static const char shortopts[] = "v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Read a graph from the specified file. */ template static void readGraph(const string& path, Graph& g, BetterEP betterEP) { if (opt::verbose > 0) cout << "Reading `" << path << "'...\n"; ifstream fin(path.c_str()); istream& in = path == "-" ? cin : fin; assert_good(in, path); read_graph(in, g, betterEP); assert(in.eof()); printGraphStats(cout, g); g_contigNames.lock(); } /** Read a graph from the specified files. */ template void readGraphs(Graph& g, It first, It last, BetterEP betterEP) { if (first != last) { for (It it = first; it < last; ++it) readGraph(*it, g, betterEP); } else readGraph("-", g, betterEP); } 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 '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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } ContigGraph > g; readGraphs(g, argv + optind, argv + argc, DisallowParallelEdges()); assert_good(cout, "-"); return 0; } abyss-2.2.4/Graph/todot.cc000066400000000000000000000134741361462241400153550ustar00rootroot00000000000000/** Convert a graph to dot format. * Written by Shaun Jackman . */ #include "ContigGraph.h" #include "ContigProperties.h" #include "DirectedGraph.h" #include "Estimate.h" #include "Graph/ContigGraphAlgorithms.h" // for addComplementaryEdges #include "GraphIO.h" #include "GraphUtil.h" #include "IOUtil.h" #include "Uncompress.h" #include #include #include #include // for ostream_iterator #include using namespace std; using namespace std::rel_ops; #define PROGRAM "abyss-todot" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [FILE]...\n" "Convert the specified graph to dot format.\n" "\n" " Options:\n" "\n" " -k, --kmer=N report the mean k-mer coverage, otherwise\n" " the sum k-mer coverage is reported\n" " --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 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 GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --sam output the graph in SAM format\n" " -e, --estimate output distance estimates\n" " --add-complements add missing complementary edges\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 { unsigned k; // used by Distance static int verbose; /** Output distance estimates. */ bool estimate; /** Add missing complementary edges. * Type would be bool, but is int for compatibility with getopt_long. */ int addComplementaryEdges; /** Output format */ int format = DOT; // used by ContigProperties } static const char shortopts[] = "ek:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "adj", no_argument, &opt::format, ADJ }, { "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, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "sam", no_argument, &opt::format, SAM }, { "estimate", no_argument, NULL, 'e' }, { "add-complements", no_argument, &opt::addComplementaryEdges, true }, { "kmer", required_argument, NULL, 'k' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Read a graph from the specified file. */ template static void readGraph(const string& path, Graph& g, BetterEP betterEP) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; ifstream fin(path.c_str()); istream& in = path == "-" ? cin : fin; assert_good(in, path); read_graph(in, g, betterEP); assert(in.eof()); if (opt::verbose > 0) printGraphStats(cerr, g); g_contigNames.lock(); } /** Read a graph from the specified files. */ template void readGraphs(Graph& g, It first, It last, BetterEP betterEP) { if (first != last) { for (It it = first; it < last; ++it) 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) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } 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 'e': opt::estimate = true; break; case 'k': arg >> opt::k; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 0) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (opt::estimate) { // GFA outputs only the canonical edges, so // both complementary edges must be present. if (opt::format == GFA1 || opt::format == GFA2) opt::addComplementaryEdges = true; ContigGraph > g; readGraphs(g, argv + optind, argv + argc, BetterDistanceEst()); write_graph(cout, g, PROGRAM, commandLine); } else { ContigGraph > g; readGraphs(g, argv + optind, argv + argc, DisallowParallelEdges()); write_graph(cout, g, PROGRAM, commandLine); } assert(cout.good()); return 0; } abyss-2.2.4/IntegrationTest/000077500000000000000000000000001361462241400157665ustar00rootroot00000000000000abyss-2.2.4/IntegrationTest/DIDA/000077500000000000000000000000001361462241400164675ustar00rootroot00000000000000abyss-2.2.4/IntegrationTest/DIDA/alignment-test.mk000077500000000000000000000043201361462241400217550ustar00rootroot00000000000000#!/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!" abyss-2.2.4/IntegrationTest/DIDA/assembly-test.mk000077500000000000000000000045101361462241400216170ustar00rootroot00000000000000#!/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!' abyss-2.2.4/IntegrationTest/DIDA/compare-fastx000077500000000000000000000005131361462241400211650ustar00rootroot00000000000000#!/bin/bash set -eu -o pipefail if [ $# -ne 2 ]; then echo "Usage: $(basename $0) " >&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) abyss-2.2.4/IntegrationTest/DIDA/compare-sam000077500000000000000000000065351361462241400206320ustar00rootroot00000000000000#!/bin/bash if [ $# -ne 2 ]; then echo "Usage: $(basename $0) " >&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; }' abyss-2.2.4/IntegrationTest/Konnector/000077500000000000000000000000001361462241400177305ustar00rootroot00000000000000abyss-2.2.4/IntegrationTest/Konnector/integration-tests.mk000077500000000000000000000323201361462241400237470ustar00rootroot00000000000000#!/usr/bin/make -Rrf # Test konnector SHELL=/bin/bash -o pipefail #------------------------------------------------------------ # testing params #------------------------------------------------------------ # threads (leave as 1 for consistent results) j?=1 # counting bloom filter size # For the parallel_load_* tests, this number # must be in bytes (no "M" or "G" suffix) and divisible by 2. b?=100000000 # kmer size k?=20 # number of synthetic read pairs # For the parallel_load_* tests, this number must be # divisible by 3. N?=6000 # error rate of synthetic reads e?=0.005 # path to konnector binary konnector?=konnector # path to abyss-bloom binary bloom?=abyss-bloom # path to abyss-bloom-dist.mk makefile bloom_dist=abyss-bloom-dist.mk # temp dir for test outputs tmpdir=tmp # shared options to konnector k_opts=-j$j -v -v -k$k # user options to konnector K_OPTS?= #------------------------------------------------------------ # global vars #------------------------------------------------------------ b_div_2:=$(shell echo $b / 2 | bc) #------------------------------------------------------------ # phony targets #------------------------------------------------------------ tests=run_test \ save_and_load_test \ union_test \ interleaved_files_test \ window_single_test \ window_test \ parallel_load_2_files_test \ parallel_load_3_files_test \ abyss_bloom_dist_1_file_test \ abyss_bloom_dist_2_files_test \ abyss_bloom_dist_3_files_test \ abyss_bloom_illegal_chars_test .PHONY: all $(tests) .DELETE_ON_ERROR: .SECONDARY: #------------------------------------------------------------ # top level rules #------------------------------------------------------------ .PHONY: all clean tmpdir all: $(tests) clean: rm -f $(tmpdir)/* rmdir $(tmpdir) || true #------------------------------------------------------------ # common rules #------------------------------------------------------------ $(tmpdir): mkdir -p $(tmpdir) $(tmpdir)/test_reference.fa: | $(tmpdir) curl -L https://raw.githubusercontent.com/dzerbino/velvet/master/data/test_reference.fa \ |abyss-tofastq --fasta >$@ $(tmpdir)/e%_1.fq $(tmpdir)/e%_2.fq: $(tmpdir)/test_reference.fa wgsim -S 0 -e $* -N $N -r 0 -R 0 $< $(tmpdir)/e$*_1.fq $(tmpdir)/e$*_2.fq $(tmpdir)/e%_pseudoreads.fa $(tmpdir)/e%_reads_1.fq $(tmpdir)/e%_reads_2.fq: $(tmpdir)/e%_1.fq $(tmpdir)/e%_2.fq /usr/bin/time -v $(konnector) $(k_opts) -b$b -o $(tmpdir)/e$* $(K_OPTS) $^ $(tmpdir)/e%_l2.bloom: $(tmpdir) $(tmpdir)/e%_1.fq $(tmpdir)/e%_2.fq $(bloom) build -v -k$k -l2 -b$b $@ $(filter-out $<, $^) $(tmpdir)/e%_interleaved.fq: $(tmpdir)/e%_1.fq $(tmpdir)/e%_2.fq paste -d'\n' <(cat $(tmpdir)/e$e_1.fq | paste - - - -) \ <(cat $(tmpdir)/e$e_2.fq | paste - - - -) | \ tr '\t' '\n' > $(tmpdir)/e$e_interleaved.fq FASTQ_CHUNKS:=3 FASTQ_CHUNK_SIZE:=$(shell echo '$N * 2 * 4 / $(FASTQ_CHUNKS)' | bc) $(tmpdir)/e%_reads_1of3.fq \ $(tmpdir)/e%_reads_2of3.fq \ $(tmpdir)/e%_reads_3of3.fq: $(tmpdir)/e%_interleaved.fq awk '{ print > "$(tmpdir)/e$e_reads_" \ int((NR-1)/$(FASTQ_CHUNK_SIZE))+1 \ "of"$(FASTQ_CHUNKS)".fq"}' $< #------------------------------------------------------------ # run_test #------------------------------------------------------------ run_test: $(tmpdir) $(tmpdir)/e$e_pseudoreads.fa @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # save_and_load_test #------------------------------------------------------------ save_and_load_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_pseudoreads.fa \ $(tmpdir)/e$e_reads_1.fq \ $(tmpdir)/e$e_reads_2.fq /usr/bin/time -v $(konnector) $(k_opts) -o $(tmpdir)/e$e_loaded \ -i $(tmpdir)/e$e_l2.bloom $(K_OPTS) $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq diff $(tmpdir)/e$e_pseudoreads.fa $(tmpdir)/e$e_loaded_pseudoreads.fa diff $(tmpdir)/e$e_reads_1.fq $(tmpdir)/e$e_loaded_reads_1.fq diff $(tmpdir)/e$e_reads_2.fq $(tmpdir)/e$e_loaded_reads_2.fq @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # interleaved_files_test #------------------------------------------------------------ HALF_FASTQ_LINES:=$(shell echo '$N * 2 * 4 / 2' | bc) interleaved_files_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_pseudoreads.fa \ $(tmpdir)/e$e_interleaved_a.fq \ $(tmpdir)/e$e_interleaved_b.fq /usr/bin/time -v $(konnector) $(k_opts) -I -b$b \ -i $(tmpdir)/e$e_l2.bloom -o $(tmpdir)/e$e_interleaved \ $(K_OPTS) \ $(tmpdir)/e$e_interleaved_a.fq \ $(tmpdir)/e$e_interleaved_b.fq diff $(tmpdir)/e$e_pseudoreads.fa $(tmpdir)/e$e_interleaved_pseudoreads.fa diff $(tmpdir)/e$e_reads_1.fq $(tmpdir)/e$e_interleaved_reads_1.fq diff $(tmpdir)/e$e_reads_2.fq $(tmpdir)/e$e_interleaved_reads_2.fq @echo '------------------' @echo '$@: PASSED' @echo '------------------' $(tmpdir)/e%_interleaved_a.fq $(tmpdir)/e%_interleaved_b.fq: \ $(tmpdir)/e%_interleaved.fq head -n $(HALF_FASTQ_LINES) $< > $(tmpdir)/e$*_interleaved_a.fq tail -n $(HALF_FASTQ_LINES) $< > $(tmpdir)/e$*_interleaved_b.fq #------------------------------------------------------------ # union_test #------------------------------------------------------------ union_test: $(tmpdir) $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -b$b $(tmpdir)/e$e.bloom $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -b$b $(tmpdir)/e$e_1.bloom $(tmpdir)/e$e_1.fq $(bloom) build -v -k$k -b$b $(tmpdir)/e$e_2.bloom $(tmpdir)/e$e_2.fq $(bloom) union -v -k$k $(tmpdir)/e$e_union.bloom $(tmpdir)/e$e_1.bloom $(tmpdir)/e$e_2.bloom cmp $(tmpdir)/e$e.bloom $(tmpdir)/e$e_union.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # intersect_test #------------------------------------------------------------ intersect_test: $(tmpdir) $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -b$b $(tmpdir)/e$e.bloom $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -b$b $(tmpdir)/e$e_1.bloom $(tmpdir)/e$e_1.fq $(bloom) intersect -v -k$k $(tmpdir)/e$e_intersect.bloom \ $(tmpdir)/e$e.bloom $(tmpdir)/e$e_1.bloom cmp $(tmpdir)/e$e_intersect.bloom $(tmpdir)/e$e_1.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # window_single_test #------------------------------------------------------------ window_single_test: $(tmpdir)/e$e.bloom $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -w1/2 -b$b $(tmpdir)/e$e_window1.bloom \ $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -w2/2 -b$b $(tmpdir)/e$e_window2.bloom \ $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) union -v -k$k $(tmpdir)/e$e_l2_concat.bloom \ $(tmpdir)/e$e_window1.bloom $(tmpdir)/e$e_window2.bloom cmp $(tmpdir)/e$e.bloom $(tmpdir)/e$e_l2_concat.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # window_test #------------------------------------------------------------ window_test: $(tmpdir)/e$e_l2.bloom $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -l2 -w1/2 -b$b $(tmpdir)/e$e_l2_window1.bloom \ $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -l2 -w2/2 -b$b $(tmpdir)/e$e_l2_window2.bloom \ $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq $(bloom) union -v -k$k $(tmpdir)/e$e_l2_concat.bloom \ $(tmpdir)/e$e_l2_window1.bloom $(tmpdir)/e$e_l2_window2.bloom cmp $(tmpdir)/e$e_l2.bloom $(tmpdir)/e$e_l2_concat.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # parallel_load_2_files_test #------------------------------------------------------------ parallel_load_2_files_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_1.fq \ $(tmpdir)/e$e_2.fq echo 'b_div_2: $(b_div_2)' $(bloom) build -v -k$k -b$(b_div_2) $(tmpdir)/e$e_l1_read1.bloom \ $(tmpdir)/e$e_1.fq $(bloom) build -v -k$k -b$(b_div_2) $(tmpdir)/e$e_l1_read2.bloom \ $(tmpdir)/e$e_2.fq $(bloom) build -v -k$k -b$b -l2 -L 1=$(tmpdir)/e$e_l1_read2.bloom \ $(tmpdir)/e$e_l2_read1.bloom $(tmpdir)/e$e_1.fq $(bloom) build -v -k$k -b$b -l2 -L 1=$(tmpdir)/e$e_l1_read1.bloom \ $(tmpdir)/e$e_l2_read2.bloom $(tmpdir)/e$e_2.fq $(bloom) union -v -k$k $(tmpdir)/e$e_l2_union.bloom \ $(tmpdir)/e$e_l2_read1.bloom \ $(tmpdir)/e$e_l2_read2.bloom cmp $(tmpdir)/e$e_l2.bloom $(tmpdir)/e$e_l2_union.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # parallel_load_3_files_test #------------------------------------------------------------ parallel_load_3_files_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_reads_1of3.fq \ $(tmpdir)/e$e_reads_2of3.fq \ $(tmpdir)/e$e_reads_3of3.fq $(bloom) build -v -k$k -b$(b_div_2) $(tmpdir)/e$e_l1_1of3.bloom \ $(tmpdir)/e$e_reads_1of3.fq $(bloom) build -v -k$k -b$(b_div_2) $(tmpdir)/e$e_l1_2of3.bloom \ $(tmpdir)/e$e_reads_2of3.fq $(bloom) build -v -k$k -b$(b_div_2) $(tmpdir)/e$e_l1_3of3.bloom \ $(tmpdir)/e$e_reads_3of3.fq $(bloom) build -v -k$k -b$b -l2 \ -L 1=$(tmpdir)/e$e_l1_2of3.bloom \ -L 1=$(tmpdir)/e$e_l1_3of3.bloom \ $(tmpdir)/e$e_l2_1of3.bloom $(tmpdir)/e$e_reads_1of3.fq $(bloom) build -v -k$k -b$b -l2 \ -L 1=$(tmpdir)/e$e_l1_1of3.bloom \ -L 1=$(tmpdir)/e$e_l1_3of3.bloom \ $(tmpdir)/e$e_l2_2of3.bloom $(tmpdir)/e$e_reads_2of3.fq $(bloom) build -v -k$k -b$b -l2 \ -L 1=$(tmpdir)/e$e_l1_1of3.bloom \ -L 1=$(tmpdir)/e$e_l1_2of3.bloom \ $(tmpdir)/e$e_l2_3of3.bloom $(tmpdir)/e$e_reads_3of3.fq $(bloom) union -v -k$k $(tmpdir)/e$e_l2_union.bloom \ $(tmpdir)/e$e_l2_1of3.bloom \ $(tmpdir)/e$e_l2_2of3.bloom \ $(tmpdir)/e$e_l2_3of3.bloom cmp $(tmpdir)/e$e_l2.bloom $(tmpdir)/e$e_l2_union.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # abyss_bloom_dist_1_file_test #------------------------------------------------------------ abyss_bloom_dist_1_file_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_1.fq \ $(tmpdir)/e$e_2.fq cat $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq > $(tmpdir)/e$e_1cat2.fq $(bloom_dist) -C $(tmpdir) name=dist-1-file k=$k b=$(b_div_2) w=2 \ files='e$e_1cat2.fq' cmp $(tmpdir)/e$e_l2.bloom <(gunzip -c $(tmpdir)/dist-1-file.bloom.gz) @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # abyss_bloom_dist_2_files_test #------------------------------------------------------------ abyss_bloom_dist_2_files_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_1.fq \ $(tmpdir)/e$e_2.fq $(bloom_dist) -C $(tmpdir) name=dist-2-files k=$k b=$(b_div_2) w=2 \ files='e$e_1.fq e$e_2.fq' cmp $(tmpdir)/e$e_l2.bloom <(gunzip -c $(tmpdir)/dist-2-files.bloom.gz) @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # abyss_bloom_dist_3_files_test #------------------------------------------------------------ abyss_bloom_dist_3_files_test: $(tmpdir)/e$e_l2.bloom \ $(tmpdir)/e$e_reads_1of3.fq \ $(tmpdir)/e$e_reads_2of3.fq \ $(tmpdir)/e$e_reads_3of3.fq $(bloom_dist) -C $(tmpdir) name=dist-3-files k=$k b=$(b_div_2) w=2 \ files='e$e_reads_1of3.fq e$e_reads_2of3.fq e$e_reads_3of3.fq' cmp $(tmpdir)/e$e_l2.bloom <(gunzip -c $(tmpdir)/dist-3-files.bloom.gz) @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # abyss_bloom_illegal_chars_test #------------------------------------------------------------ abyss_bloom_illegal_chars_test: $(bloom) build -v -k3 -b1M $(tmpdir)/illegal_char_test.bloom <(echo -e ">test\nAGCTagctAGCTnqrsAGCTNQRS") @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # abyss_bloom_multithreaded_test #------------------------------------------------------------ abyss_bloom_multithreaded_test: $(tmpdir) $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq \ $(tmpdir)/e$e_l2.bloom $(bloom) build -v -k$k -j10 -l2 -b$b $(tmpdir)/e$e_l2_multithreaded.bloom \ $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq cmp $(tmpdir)/e$e_l2.bloom $(tmpdir)/e$e_l2_multithreaded.bloom @echo '------------------' @echo '$@: PASSED' @echo '------------------' #------------------------------------------------------------ # konnector_multithreaded_test #------------------------------------------------------------ konnector_multithreaded_test: $(tmpdir)/e$e_1.fq $(tmpdir)/e$e_2.fq /usr/bin/time -v $(konnector) $(k_opts) -o $(tmpdir)/e$e_singlethreaded \ $(K_OPTS) -j1 $^ cat $(tmpdir)/e$e_singlethreaded_pseudoreads.fa | \ paste - - | sort | tr '\t' '\n' \ > $(tmpdir)/e$e_singlethreaded_pseudoreads.sorted.fa /usr/bin/time -v $(konnector) $(k_opts) -o $(tmpdir)/e$e_multithreaded \ $(K_OPTS) -j10 $^ cat $(tmpdir)/e$e_multithreaded_pseudoreads.fa | \ paste - - | sort | tr '\t' '\n' \ > $(tmpdir)/e$e_multithreaded_pseudoreads.sorted.fa diff $(tmpdir)/e$e_singlethreaded_pseudoreads.sorted.fa \ $(tmpdir)/e$e_multithreaded_pseudoreads.sorted.fa @echo '------------------' @echo '$@: PASSED' @echo '------------------' abyss-2.2.4/KAligner/000077500000000000000000000000001361462241400143375ustar00rootroot00000000000000abyss-2.2.4/KAligner/Aligner.cpp000066400000000000000000000160101361462241400164220ustar00rootroot00000000000000#include "Aligner.h" #include "Iterator.h" #include "SAM.h" #include "Sequence.h" #include #include #include #include #include using namespace std; namespace opt { /** For a duplicate k-mer in the target * ERROR: report an error and exit * MULTIMAP: report all alignments * IGNORE: do not report any alignments */ int multimap; } template <> void Aligner::addReferenceSequence( const Kmer& kmer, Position pos) { assert(opt::multimap == opt::MULTIMAP); m_target.insert(make_pair(kmer, pos)); } template void Aligner::addReferenceSequence( const Kmer& kmer, Position pos) { assert(opt::multimap != opt::MULTIMAP); Kmer rc_kmer = reverseComplement(kmer); map_iterator findIt = m_target.find(rc_kmer); if (findIt != m_target.end()) { if (!findIt->second.isDuplicate()) findIt->second.setDuplicate( contigIndexToID(findIt->second.contig), contigIndexToID(pos.contig), kmer.str()); return; } pair inserted = m_target.insert(make_pair(kmer, pos)); if (!inserted.second) if (!inserted.first->second.isDuplicate()) inserted.first->second.setDuplicate( contigIndexToID(inserted.first->second.contig), contigIndexToID(pos.contig), kmer.str()); } /** Create an index of the target sequence. */ template void Aligner::addReferenceSequence( const StringID& idString, const Sequence& seq) { unsigned id = contigIDToIndex(idString); int size = seq.length(); for(int i = 0; i < (size - m_hashSize + 1); ++i) { Sequence subseq(seq, i, m_hashSize); if (subseq.find_first_not_of("ACGT0123") != string::npos) continue; addReferenceSequence(Kmer(subseq), Position(id, i)); } } template template void Aligner::alignRead( const string& qid, const Sequence& seq, oiterator dest) { coalesceAlignments(qid, seq, getAlignmentsInternal(seq, false), dest); Sequence seqrc = reverseComplement(seq); coalesceAlignments(qid, seqrc, getAlignmentsInternal(seqrc, true), dest); } /** Store all alignments for a given Kmer in the parameter aligns. * @param[out] aligns Map of contig IDs to alignment vectors. */ template void Aligner::alignKmer( AlignmentSet& aligns, const Sequence& seq, bool isRC, bool good, int read_ind, int seqLen) { assert(read_ind >= 0); Sequence kmer(seq, read_ind, m_hashSize); if (!good && kmer.find_first_not_of("ACGT0123") != string::npos) return; pair range = m_target.equal_range(Kmer(kmer)); if (range.first != range.second && opt::multimap == opt::IGNORE && range.first->second.isDuplicate()) return; for (map_const_iterator resultIter = range.first; resultIter != range.second; ++resultIter) { assert(opt::multimap != opt::IGNORE || !resultIter->second.isDuplicate()); int read_pos = !isRC ? read_ind : Alignment::calculateReverseReadStart( read_ind, seqLen, m_hashSize); unsigned ctgIndex = resultIter->second.contig; Alignment align(string(), resultIter->second.pos, read_pos, m_hashSize, seqLen, isRC); aligns[ctgIndex].push_back(align); } } template typename Aligner::AlignmentSet Aligner::getAlignmentsInternal( const Sequence& seq, bool isRC) { // The results AlignmentSet aligns; bool good = seq.find_first_not_of("ACGT0123") == string::npos; int seqLen = seq.length(); int last_kmer = seqLen - m_hashSize; if (last_kmer < 0) return aligns; // Align the first kmer alignKmer(aligns, seq, isRC, good, 0, seqLen); if (last_kmer == 0) return aligns; // Align the last kmer alignKmer(aligns, seq, isRC, good, last_kmer, seqLen); // Short-cut logic ignoring the middle alignments if the first // and last kmers overlap, and align to the same contig if (good && seqLen <= 2 * m_hashSize && aligns.size() == 1) { AlignmentSet::const_iterator ctgIter = aligns.begin(); const AlignmentVector& a = ctgIter->second; if (ctgIter->second.size() == 2) { int qstep = isRC ? a[0].read_start_pos - a[1].read_start_pos : a[1].read_start_pos - a[0].read_start_pos; assert(qstep >= 0); // Verify this isn't a kmer aligning to two parts of a // contig, and that the alignments are coalescable. if (qstep == last_kmer && a[1].contig_start_pos == a[0].contig_start_pos + qstep) return aligns; } } // Align middle kmers for(int i = 1; i < last_kmer; ++i) alignKmer(aligns, seq, isRC, good, i, seqLen); return aligns; } static int compareQueryPos(const Alignment& a1, const Alignment& a2) { return a1.read_start_pos < a2.read_start_pos; } /** Coalesce the k-mer alignments into a read alignment. */ template template void Aligner::coalesceAlignments( const string& qid, const string& seq, const AlignmentSet& alignSet, oiterator& dest) { typedef typename output_iterator_traits::value_type value_type; for (AlignmentSet::const_iterator ctgIter = alignSet.begin(); ctgIter != alignSet.end(); ++ctgIter) { AlignmentVector alignVec = ctgIter->second; assert(!alignVec.empty()); sort(alignVec.begin(), alignVec.end(), compareQueryPos); AlignmentVector::iterator prevIter = alignVec.begin(); AlignmentVector::iterator currIter = alignVec.begin() + 1; Alignment currAlign = *prevIter; while (currIter != alignVec.end()) { int qstep = currIter->read_start_pos - prevIter->read_start_pos; assert(qstep >= 0); int tstep = currIter->isRC ? -qstep : qstep; if (currIter->contig_start_pos == prevIter->contig_start_pos + tstep && qstep <= m_hashSize) { currAlign.align_length += qstep; if (currAlign.isRC) currAlign.contig_start_pos -= qstep; } else { currAlign.contig = contigIndexToID(ctgIter->first); *dest++ = value_type(currAlign, qid, seq); currAlign = *currIter; } prevIter = currIter; currIter++; } currAlign.contig = contigIndexToID(ctgIter->first); *dest++ = value_type(currAlign, qid, seq); } } // Explicit instantiation. template void Aligner::addReferenceSequence( const StringID& id, const Sequence& seq); template void Aligner::addReferenceSequence( const StringID& id, const Sequence& seq); template void Aligner:: alignRead >( const string& qid, const Sequence& seq, affix_ostream_iterator dest); template void Aligner:: alignRead >( const string& qid, const Sequence& seq, affix_ostream_iterator dest); template void Aligner:: alignRead >( const string& qid, const Sequence& seq, ostream_iterator dest); template void Aligner:: alignRead >( const string& qid, const Sequence& seq, ostream_iterator dest); abyss-2.2.4/KAligner/Aligner.h000066400000000000000000000071361361462241400161000ustar00rootroot00000000000000#ifndef ALIGNER_H #define ALIGNER_H 1 #include "Alignment.h" #include "ConstString.h" #include "Functional.h" #include "KAligner/Options.h" #include "Kmer.h" #include "UnorderedMap.h" #include "config.h" #include #include #include // for strcpy #include #include #include #include #include #include #include #include typedef std::string StringID; /** A tuple of a target ID and position. */ struct Position { uint32_t contig; uint32_t pos; // 0 indexed Position( uint32_t contig = std::numeric_limits::max(), uint32_t pos = std::numeric_limits::max()) : contig(contig) , pos(pos) {} /** Mark this seed as a duplicate. */ void setDuplicate(const char* thisContig, const char* otherContig, const Sequence& kmer) { if (opt::multimap == opt::IGNORE) contig = std::numeric_limits::max(); else { std::cerr << "error: duplicate k-mer in " << thisContig << " also in " << otherContig << ": " << kmer << '\n'; exit(EXIT_FAILURE); } } /** Return whether this seed is a duplciate. */ bool isDuplicate() const { return contig == std::numeric_limits::max(); } }; typedef unordered_multimap> SeqPosHashMultiMap; #if HAVE_GOOGLE_SPARSE_HASH_MAP #include typedef google::sparse_hash_map> SeqPosHashUniqueMap; #else typedef unordered_map> SeqPosHashUniqueMap; #endif typedef std::vector AlignmentVector; /** * Index a target sequence and align query sequences to that indexed * target. */ template class Aligner { public: typedef typename SeqPosHashMap::iterator map_iterator; typedef typename SeqPosHashMap::const_iterator map_const_iterator; Aligner(int hashSize, size_t buckets) : m_hashSize(hashSize) , m_target(buckets) {} Aligner(int hashSize, size_t buckets, float factor) : m_hashSize(hashSize) { m_target.max_load_factor(factor); m_target.rehash(buckets); } void addReferenceSequence(const StringID& id, const Sequence& seq); void addReferenceSequence(const Kmer& kmer, Position pos); template void alignRead(const std::string& qid, const Sequence& seq, oiterator dest); size_t size() const { return m_target.size(); } size_t bucket_count() const { return m_target.bucket_count(); } /** Return the number of duplicate k-mer in the target. */ size_t countDuplicates() const { assert(opt::multimap == opt::IGNORE); return count_if( m_target.begin(), m_target.end(), [](const std::pair& s) { return s.second.isDuplicate(); }); } private: explicit Aligner(const Aligner&); typedef std::map AlignmentSet; void alignKmer( AlignmentSet& aligns, const Sequence& kmer, bool isRC, bool good, int read_ind, int seqLen); AlignmentSet getAlignmentsInternal(const Sequence& seq, bool isRC); template void coalesceAlignments( const std::string& qid, const std::string& seq, const AlignmentSet& alignSet, oiterator& dest); // The number of bases to hash on int m_hashSize; /** A map of k-mer to contig coordinates. */ SeqPosHashMap m_target; /** A dictionary of contig IDs. */ std::vector m_dict; unsigned contigIDToIndex(const std::string& id) { m_dict.push_back(id); return m_dict.size() - 1; } cstring contigIndexToID(unsigned index) { assert(index < m_dict.size()); return m_dict[index]; } }; #endif abyss-2.2.4/KAligner/KAligner.cpp000066400000000000000000000364061361462241400165500ustar00rootroot00000000000000#include "Aligner.h" #include "Common/Options.h" #include "DataLayer/Options.h" #include "KAligner/Options.h" #include "FastaReader.h" #include "Iterator.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "SAM.h" #include "StringUtil.h" // for toSI #include "Uncompress.h" #include "Pipe.h" #include "PipeMux.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define PROGRAM "KAligner" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Jared Simpson and Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... QUERY... TARGET\n" "Align the sequences of the files QUERY to those of TARGET.\n" "All perfect matches of at least k bases will be found.\n" "\n" " Options:\n" "\n" " -k, -l, --kmer=N k-mer size and minimum alignment length\n" " -s, --section=S/N split the target into N sections and align\n" " reads to section S [1/1]\n" " -i, --ignore-multimap ignore duplicate k-mer in the target\n" " [default]\n" " -m, --multimap allow duplicate k-mer in the target\n" " --no-multimap disallow duplicate k-mer in the target\n" " -j, --threads=N use N threads [2] up to one per query file\n" " or if N is 0 use one thread per query file\n" " -v, --verbose display verbose output\n" " --no-sam output the results in KAligner format\n" " --sam output the results in SAM format\n" " --seq print the sequence with the alignments\n" " --help display this help and exit\n" " --version output version information and exit\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; /** Enumeration of output formats */ enum format { KALIGNER, SAM }; namespace opt { static unsigned k; static int threads = 2; static int printSeq; static unsigned section = 1; static unsigned nsections = 1; /** Output formats */ static int format; } static const char shortopts[] = "ij:k:l:mo:s:v"; enum { OPT_HELP = 1, OPT_VERSION, OPT_SYNC }; static const struct option longopts[] = { { "kmer", required_argument, NULL, 'k' }, { "section", required_argument, NULL, 's' }, { "no-multi", no_argument, &opt::multimap, opt::ERROR }, { "multimap", no_argument, &opt::multimap, opt::MULTIMAP }, { "ignore-multimap", no_argument, &opt::multimap, opt::IGNORE }, { "threads", required_argument, NULL, 'j' }, { "verbose", no_argument, NULL, 'v' }, { "no-sam", no_argument, &opt::format, KALIGNER }, { "sam", no_argument, &opt::format, SAM }, { "no-seq", no_argument, &opt::printSeq, 0 }, { "seq", no_argument, &opt::printSeq, 1 }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Return the number of k-mer in the specified file. */ static size_t countKmer(const string& path) { struct stat st; if (stat(path.c_str(), &st) == -1) { perror(path.c_str()); exit(EXIT_FAILURE); } if (!S_ISREG(st.st_mode)) { cerr << "Not calculating k-mer in `" << path << "', because it is not a regular file.\n"; return 500000000; } if (opt::verbose > 0) cerr << "Reading target `" << path << "'..." << endl; ifstream in(path.c_str()); assert(in.is_open()); size_t scaffolds = 0, contigs = 0, bases = 0; enum { ID, SEQUENCE, GAP } state = SEQUENCE; for (char c; in.get(c);) { c = toupper(c); switch (state) { case ID: if (c == '\n') state = SEQUENCE; break; case SEQUENCE: case GAP: switch (c) { case '>': scaffolds++; contigs++; state = ID; break; case 'N': case 'B': case 'D': case 'H': case 'K': case 'M': case 'R': case 'S': case 'V': case 'W': case 'Y': if (state != GAP) contigs++; state = GAP; break; case 'A': case 'C': case 'G': case 'T': case '0': case '1': case '2': case '3': bases++; state = SEQUENCE; break; case '\n': break; default: cerr << "error: unexpected character: " "`" << c << "'\n"; exit(EXIT_FAILURE); } break; } } size_t overlaps = contigs * (opt::k-1); size_t kmer = bases - overlaps; if (opt::verbose > 0) { cerr << "Read " << bases << " bases, " << contigs << " contigs, " << scaffolds << " scaffolds" " from `" << path << "'. " "Expecting " << kmer << " k-mer.\n"; cerr << "Index will use at least " << toSI(kmer * sizeof(pair)) << "B.\n"; } assert(bases > overlaps); return kmer; } template static void readContigsIntoDB(string refFastaFile, Aligner& aligner); static void *alignReadsToDB(void *arg); static void *readFile(void *arg); /** Unique aligner using map */ static Aligner *g_aligner_u; /** Multimap aligner using multimap */ static Aligner *g_aligner_m; /** Number of reads. */ static unsigned g_readCount; /** Number of reads that aligned. */ static unsigned g_alignedCount; /** Guard cerr. */ static pthread_mutex_t g_mutexCerr = PTHREAD_MUTEX_INITIALIZER; /** Stores the output string and the read index number for an * alignment. */ struct OutData { string s; size_t index; OutData(string s = string(), size_t index = 0) : s(s), index(index) { } /** Operator needed for sorting priority queue. */ bool operator<(const OutData& a) const { // Smaller index number has higher priority. return index > a.index; } }; /** Shares data between workers and the output thread. */ static Pipe g_pipeOut(1<<7); /** Shares data between producer and worker threads. */ static PipeMux g_pipeMux(1); /** Notification of the current size of the g_pqueue. */ static size_t g_pqSize; static const size_t MAX_PQ_SIZE = 1000; /** Conditional variable used to block workers until the g_pqueue has * become small enough. */ static pthread_cond_t g_pqSize_cv = PTHREAD_COND_INITIALIZER; static pthread_mutex_t g_mutexPqSize = PTHREAD_MUTEX_INITIALIZER; static void* printAlignments(void*) { priority_queue pqueue; size_t index = 1; for (pair p = g_pipeOut.pop(); p.second > 0; p = g_pipeOut.pop()) { pqueue.push(p.first); while (!pqueue.empty()) { const OutData& rec = pqueue.top(); if (index == rec.index) { // Print the record at the current index. index++; assert(rec.index > 0); cout << rec.s; assert_good(cout, "stdout"); pqueue.pop(); } else if (g_pipeMux.invalidEntry(index)) { // Skip this index since it is invalid. index++; } else { // The record for this index has not been added, get // another record from the pipe. break; } } // Let waiting workers continue if the pqueue is small enough. pthread_mutex_lock(&g_mutexPqSize); g_pqSize = pqueue.size(); if (g_pqSize < MAX_PQ_SIZE) pthread_cond_broadcast(&g_pqSize_cv); pthread_mutex_unlock(&g_mutexPqSize); } return NULL; } /** Store a FastaReader and Pipe. */ struct WorkerArg { FastaReader& in; Pipe& out; WorkerArg(FastaReader& in, Pipe& out) : in(in), out(out) { } ~WorkerArg() { delete ∈ } }; static pthread_t getReadFiles(const char *readsFile) { if (opt::verbose > 0) { pthread_mutex_lock(&g_mutexCerr); cerr << "Reading `" << readsFile << "'...\n"; pthread_mutex_unlock(&g_mutexCerr); } FastaReader* in = new FastaReader( readsFile, FastaReader::FOLD_CASE); WorkerArg* arg = new WorkerArg(*in, *g_pipeMux.addPipe()); pthread_t thread; pthread_create(&thread, NULL, readFile, static_cast(arg)); return thread; } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } char delim = '/'; 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 'k': case 'l': arg >> opt::k; break; case 'm': opt::multimap = opt::MULTIMAP; break; case 'i': opt::multimap = opt::IGNORE; break; case 'j': arg >> opt::threads; break; case 'v': opt::verbose++; break; case 's': arg >> opt::section >> delim >> opt::nsections; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::section == 0 || opt::section > opt::nsections || delim != '/') { cerr << PROGRAM ": -s, --section option is incorrectly set\n"; die = true; } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } Kmer::setLength(opt::k); if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } string refFastaFile(argv[--argc]); int numQuery = argc - optind; if (opt::threads <= 0) opt::threads = numQuery; // SAM headers. cout << "@HD\tVN:1.0\n" "@PG\tID:" PROGRAM "\tVN:" VERSION "\t" "CL:" << commandLine << '\n'; size_t numKmer = countKmer(refFastaFile); if (opt::multimap == opt::MULTIMAP) { g_aligner_m = new Aligner(opt::k, numKmer); readContigsIntoDB(refFastaFile, *g_aligner_m); } else { #if HAVE_GOOGLE_SPARSE_HASH_MAP g_aligner_u = new Aligner(opt::k, numKmer, 0.3); #else g_aligner_u = new Aligner(opt::k, numKmer); #endif readContigsIntoDB(refFastaFile, *g_aligner_u); } g_readCount = 0; vector producer_threads; transform(argv + optind, argv + argc, back_inserter(producer_threads), getReadFiles); vector threads; for (int i = 0; i < opt::threads; i++) { pthread_t thread; pthread_create(&thread, NULL, alignReadsToDB, NULL); threads.push_back(thread); } pthread_t out_thread; pthread_create(&out_thread, NULL, printAlignments, NULL); void *status; // Wait for all threads to finish. for (size_t i = 0; i < producer_threads.size(); i++) pthread_join(producer_threads[i], &status); for (size_t i = 0; i < threads.size(); i++) pthread_join(threads[i], &status); g_pipeOut.close(); pthread_join(out_thread, &status); if (opt::verbose > 0) cerr << "Aligned " << g_alignedCount << " of " << g_readCount << " reads (" << (float)100 * g_alignedCount / g_readCount << "%)\n"; if (opt::multimap == opt::MULTIMAP) delete g_aligner_m; else delete g_aligner_u; return 0; } template static void printProgress(const Aligner& align, unsigned count) { size_t size = align.size(); size_t buckets = align.bucket_count(); cerr << "Read " << count << " contigs. " "Hash load: " << size << " / " << buckets << " = " << (float)size / buckets << " using " << toSI(getMemoryUsage()) << "B." << endl; } template static void readContigsIntoDB(string refFastaFile, Aligner& aligner) { if (opt::verbose > 0) cerr << "Reading target `" << refFastaFile << "'..." << endl; unsigned count = 0; FastaReader in(refFastaFile.c_str(), FastaReader::FOLD_CASE); if (opt::nsections > 1) in.split(opt::section, opt::nsections); for (FastaRecord rec; in >> rec;) { if (count == 0) { // Detect colour-space contigs. opt::colourSpace = isdigit(rec.seq[0]); } else { if (opt::colourSpace) assert(isdigit(rec.seq[0])); else assert(isalpha(rec.seq[0])); } cout << "@SQ\tSN:" << rec.id << "\tLN:" << rec.seq.length() << '\n'; aligner.addReferenceSequence(rec.id, rec.seq); count++; if (opt::verbose > 0 && count % 100000 == 0) printProgress(aligner, count); } assert(in.eof()); if (opt::verbose > 0) printProgress(aligner, count); if (opt::multimap == opt::IGNORE) { // Count the number of duplicate k-mer in the target. size_t duplicates = aligner.countDuplicates(); if (duplicates > 0) cerr << "Found " << duplicates << " (" << (float)100 * duplicates / aligner.size() << "%) duplicate k-mer.\n"; } } /** Read each fasta record from 'in', and add it to 'pipe'. */ static void readFile(FastaReader& in, Pipe& pipe) { for (FastaRecord rec; in >> rec;) pipe.push(rec); assert(in.eof()); pipe.close(); } /** Producer thread. */ static void* readFile(void* arg) { WorkerArg* p = static_cast(arg); readFile(p->in, p->out); delete p; return NULL; } /** @Returns the time in seconds between [start, end]. */ static double timeDiff(const timeval& start, const timeval& end) { double result = (double)end.tv_sec + (double)end.tv_usec/1000000.0; result -= (double)start.tv_sec + (double)start.tv_usec/1000000.0; return result; } static void* alignReadsToDB(void*) { opt::chastityFilter = false; opt::trimMasked = false; static timeval start, end; pthread_mutex_lock(&g_mutexCerr); gettimeofday(&start, NULL); pthread_mutex_unlock(&g_mutexCerr); for (pair recPair = g_pipeMux.nextValue(); recPair.second > 0; recPair = g_pipeMux.nextValue()) { const FastaRecord& rec = recPair.first; const Sequence& seq = rec.seq; ostringstream output; if (seq.find_first_not_of("ACGT0123") == string::npos) { if (opt::colourSpace) assert(isdigit(seq[0])); else assert(isalpha(seq[0])); } switch (opt::format) { case KALIGNER: if (opt::multimap == opt::MULTIMAP) g_aligner_m->alignRead(rec.id, seq, affix_ostream_iterator( output, "\t")); else g_aligner_u->alignRead(rec.id, seq, affix_ostream_iterator( output, "\t")); break; case SAM: if (opt::multimap == opt::MULTIMAP) g_aligner_m->alignRead(rec.id, seq, ostream_iterator(output, "\n")); else g_aligner_u->alignRead(rec.id, seq, ostream_iterator(output, "\n")); break; } ostringstream out; string s = output.str(); switch (opt::format) { case KALIGNER: out << rec.id; if (opt::printSeq) { out << ' '; if (opt::colourSpace) out << rec.anchor; out << seq; } out << s << '\n'; break; case SAM: out << s; break; } g_pipeOut.push(OutData(out.str(), recPair.second)); // Prevent the priority_queue from growing too large by // waiting for threads going far too slow. pthread_mutex_lock(&g_mutexPqSize); if (g_pqSize >= MAX_PQ_SIZE) pthread_cond_wait(&g_pqSize_cv, &g_mutexPqSize); pthread_mutex_unlock(&g_mutexPqSize); if (opt::verbose > 0) { pthread_mutex_lock(&g_mutexCerr); if (!s.empty()) g_alignedCount++; if (++g_readCount % 1000000 == 0) { gettimeofday(&end, NULL); double result = timeDiff(start, end); cerr << "Aligned " << g_readCount << " reads at " << (int)(1000000 / result) << " reads/sec.\n"; start = end; } pthread_mutex_unlock(&g_mutexCerr); } } return NULL; } abyss-2.2.4/KAligner/Makefile.am000066400000000000000000000005061361462241400163740ustar00rootroot00000000000000bin_PROGRAMS = KAligner KAligner_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer KAligner_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a \ -lpthread KAligner_SOURCES = KAligner.cpp Aligner.cpp Aligner.h Options.h \ Pipe.h PipeMux.h Semaphore.h abyss-2.2.4/KAligner/Options.h000066400000000000000000000002061361462241400161410ustar00rootroot00000000000000#ifndef ALIGN_OPTIONS_H #define ALIGN_OPTIONS_H 1 namespace opt { enum { IGNORE, MULTIMAP, ERROR }; extern int multimap; } #endif abyss-2.2.4/KAligner/Pipe.h000066400000000000000000000041411361462241400154050ustar00rootroot00000000000000#ifndef PIPE_H #define PIPE_H 1 #include "Semaphore.h" #include #include /** An asynchronous queue for transmitting data from one thread to * another. */ template class Pipe { public: /** Ready to use after constructed. Not thread safe. */ Pipe(unsigned size = 1024) : m_sem_in(size), m_sem_out(0), m_open(true) { assert(size > 0); pthread_mutex_init(&m_mutex_queue, NULL); } /** Destoyr semaphores/mutexs. Not thread safe. */ ~Pipe() { pthread_mutex_destroy(&m_mutex_queue); } /** Add data to the buffer/queue. */ void push(T x) { // Block if pipe is full, or in use. m_sem_in.wait(); pthread_mutex_lock(&m_mutex_queue); assert(m_open); add(x); pthread_mutex_unlock(&m_mutex_queue); m_sem_out.post(); } /** Get data and remove it from the buffer. */ std::pair pop() { // block when pipe is empty and m_open, or in use. m_sem_out.wait(); pthread_mutex_lock(&m_mutex_queue); std::pair temp = remove(); pthread_mutex_unlock(&m_mutex_queue); // If pipe is m_open ensure poping will allow one more push. // Otherwise, let next accessor know pipe is closed. if (temp.second) m_sem_in.post(); else { assert(!m_open); m_sem_out.post(); } return temp; } /** Allows a pop when the pipe is empty to signal the pipe is * closed. */ void close() { pthread_mutex_lock(&m_mutex_queue); m_open = false; pthread_mutex_unlock(&m_mutex_queue); m_sem_out.post(); } private: /** Add an element to the buffer. */ void add(const T& t) { m_queue.push(t); } /** Remove an element from the buffer. */ std::pair remove() { std::pair temp; if (!m_queue.empty()) { temp.first = m_queue.front(); temp.second = 1; m_queue.pop(); } else { temp.second = 0; } return temp; } /** Semaphores to block read on empty, or write on full. */ Semaphore m_sem_in, m_sem_out; /** Mutual exclusion for reading and writing */ pthread_mutex_t m_mutex_queue; /** True if close() has not been called. */ bool m_open; /** Pipe's buffer */ std::queue m_queue; }; #endif abyss-2.2.4/KAligner/PipeMux.h000066400000000000000000000071041361462241400161010ustar00rootroot00000000000000#ifndef PIPEMUX_H #define PIPEMUX_H 1 #include "Pipe.h" #include "Semaphore.h" #include #include template class PipeMux { public: /** Default constructor. */ PipeMux(size_t pipe_size = 1) : m_index(0) , m_entry_num(0) , m_pipe_size(pipe_size) { pthread_rwlock_init(&m_rwlock_vecs, NULL); pthread_mutex_init(&m_mutex_index, NULL); } /** Destroy remaining pipes, and mutexes. */ ~PipeMux() { pthread_rwlock_destroy(&m_rwlock_vecs); pthread_mutex_destroy(&m_mutex_index); assert(m_pipes.empty()); assert(m_mutex_pipes.empty()); } /** Instantiates a new pipe and adds it to this PipeMux. */ Pipe* addPipe() { Pipe* p = new Pipe(m_pipe_size); pthread_mutex_t* m = new pthread_mutex_t; pthread_mutex_init(m, NULL); pthread_rwlock_wrlock(&m_rwlock_vecs); m_pipes.push_back(p); m_mutex_pipes.push_back(m); pthread_rwlock_unlock(&m_rwlock_vecs); return p; } /** Returns the next value from the appropriate pipe, deletes * closed pipes and returns */ std::pair nextValue() { size_t entry; std::pair t(T(), 0); do { pthread_rwlock_rdlock(&m_rwlock_vecs); pthread_mutex_lock(&m_mutex_index); if (m_pipes.empty() && m_mutex_pipes.empty()) { pthread_rwlock_unlock(&m_rwlock_vecs); pthread_mutex_unlock(&m_mutex_index); return t; } unsigned i = m_index; m_index = m_index + 1 < m_pipes.size() ? m_index + 1 : 0; entry = ++m_entry_num; assert(i < m_mutex_pipes.size()); pthread_mutex_lock(m_mutex_pipes[i]); pthread_mutex_unlock(&m_mutex_index); assert(i < m_pipes.size()); Pipe* p_pipe = m_pipes[i]; t = p_pipe->pop(); // you know you're fed up with race conditions when... assert(i < m_mutex_pipes.size()); pthread_mutex_unlock(m_mutex_pipes[i]); pthread_rwlock_unlock(&m_rwlock_vecs); if (!t.second) removePipe(p_pipe, entry); } while (!t.second); t.second = entry; return t; } bool invalidEntry(size_t e) { pthread_rwlock_rdlock(&m_rwlock_vecs); for (unsigned i = 0; i < m_invalid_entries.size(); i++) { assert(i < m_invalid_entries.size()); if (m_invalid_entries[i] == e) { pthread_rwlock_unlock(&m_rwlock_vecs); return true; } } pthread_rwlock_unlock(&m_rwlock_vecs); return false; } /** Checks that the PipeMux is empty. */ bool empty() { pthread_rwlock_rdlock(&m_rwlock_vecs); bool isEmpty = m_pipes.empty(); pthread_rwlock_unlock(&m_rwlock_vecs); return isEmpty; } private: std::vector*> m_pipes; std::vector m_mutex_pipes; std::vector m_invalid_entries; pthread_rwlock_t m_rwlock_vecs; pthread_mutex_t m_mutex_index; unsigned m_index; size_t m_entry_num; size_t m_pipe_size; /** Removes Pipe p if it is still present in m_pipes. */ void removePipe(Pipe* p, size_t entry) { pthread_rwlock_wrlock(&m_rwlock_vecs); m_invalid_entries.push_back(entry); unsigned i; for (i = 0; i < m_pipes.size(); i++) { assert(i < m_pipes.size()); if (m_pipes[i] == p) break; } if (i >= m_pipes.size()) { pthread_rwlock_unlock(&m_rwlock_vecs); return; } assert(i < m_pipes.size()); delete m_pipes[i]; m_pipes.erase(m_pipes.begin() + i); assert(i < m_mutex_pipes.size()); pthread_mutex_destroy(m_mutex_pipes[i]); delete m_mutex_pipes[i]; m_mutex_pipes.erase(m_mutex_pipes.begin() + i); // Make sure the index points to the next element. pthread_mutex_lock(&m_mutex_index); m_index = m_index == m_pipes.size() ? 0 : m_index; pthread_mutex_unlock(&m_mutex_index); pthread_rwlock_unlock(&m_rwlock_vecs); } }; #endif abyss-2.2.4/KAligner/Semaphore.h000066400000000000000000000034431361462241400164370ustar00rootroot00000000000000#ifndef SEMAPHORE_H #define SEMAPHORE_H 1 /** Semaphore class needed since some OS' do not support unnamed * semaphores. */ #if __APPLE__ # include class Semaphore { public: Semaphore(unsigned value) : m_value(value) { pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_cv, NULL); } ~Semaphore() { pthread_mutex_destroy(&m_mutex); pthread_cond_destroy(&m_cv); } void wait() { pthread_mutex_lock(&m_mutex); // Not a spinlock! For some reason signaling a condvar can // cause more than one thread waiting to continue... while (m_value == 0) pthread_cond_wait(&m_cv, &m_mutex); assert(m_value > 0); m_value--; pthread_mutex_unlock(&m_mutex); } void post() { pthread_mutex_lock(&m_mutex); m_value++; pthread_cond_signal(&m_cv); pthread_mutex_unlock(&m_mutex); } private: unsigned m_value; pthread_mutex_t m_mutex; pthread_cond_t m_cv; }; #else # include # include # include // for strerror class Semaphore { public: Semaphore(unsigned value) { #if SEM_VALUE_MAX assert(value <= SEM_VALUE_MAX); #endif if (sem_init(&m_sem, 0, value) == -1) { std::cerr << "error: sem_init:" << strerror(errno) << std::endl; assert(false); exit(EXIT_FAILURE); } } ~Semaphore() { if (sem_destroy(&m_sem) == -1) { std::cerr << "error: sem_destroy:" << strerror(errno) << std::endl; assert(false); exit(EXIT_FAILURE); } } void wait() { if (sem_wait(&m_sem) == -1) { std::cerr << "error: sem_wait:" << strerror(errno) << std::endl; assert(false); exit(EXIT_FAILURE); } } void post() { if (sem_post(&m_sem) == -1) { std::cerr << "error: sem_post:" << strerror(errno) << std::endl; assert(false); exit(EXIT_FAILURE); } } private: sem_t m_sem; }; #endif #endif abyss-2.2.4/Konnector/000077500000000000000000000000001361462241400146055ustar00rootroot00000000000000abyss-2.2.4/Konnector/DBGBloom.h000066400000000000000000000221651361462241400163510ustar00rootroot00000000000000/** * de Bruijn Graph data structure using a Bloom filter * Copyright 2013 Shaun Jackman */ #ifndef DBGBLOOM_H #define DBGBLOOM_H 1 #include "Assembly/SeqExt.h" // for NUM_BASES #include "Common/IOUtil.h" #include "Common/Kmer.h" #include "Common/Uncompress.h" #include "DataLayer/FastaReader.h" #include "Graph/Properties.h" #include #include #include // for abort #include #include using boost::graph_traits; template class DBGBloom: public BF { public: /** The bundled vertex properties. */ typedef no_property vertex_bundled; typedef no_property vertex_property_type; /** The bundled edge properties. */ typedef no_property edge_bundled; typedef no_property edge_property_type; /** The bloom filter */ const BF& m_bloom; DBGBloom(const BF& bloom) : m_bloom(bloom), m_depthThresh(0) { } DBGBloom(const BF& bloom, unsigned depthThresh) : m_bloom(bloom), m_depthThresh(depthThresh) { } const unsigned m_depthThresh; private: /** Copy constructor. */ DBGBloom(const DBGBloom&); }; // class DBGBloom /** PropertyGraph vertex_index */ template struct DBGBloomIndexMap : boost::put_get_helper { typedef Kmer key_type; typedef size_t value_type; typedef value_type reference; typedef boost::readable_property_map_tag category; const Graph& m_g; DBGBloomIndexMap(const Graph& g) : m_g(g) { } reference operator[](const key_type& u) const { return m_g.m_bloom.hash(u) % m_g.m_bloom.size(); } }; // Graph namespace boost { /** Graph traits */ template struct graph_traits< DBGBloom > { // Graph typedef Kmer vertex_descriptor; typedef boost::directed_tag directed_category; struct traversal_category : boost::adjacency_graph_tag, boost::bidirectional_graph_tag, boost::vertex_list_graph_tag { }; typedef boost::disallow_parallel_edge_tag edge_parallel_category; static vertex_descriptor null_vertex() { return Kmer(); } // IncidenceGraph typedef std::pair edge_descriptor; typedef unsigned degree_size_type; // VertexListGraph typedef size_t vertices_size_type; typedef void vertex_iterator; // EdgeListGraph typedef size_t edges_size_type; typedef void edge_iterator; // AdjacencyGraph /** Iterate through the adjacent vertices of a vertex. */ struct adjacency_iterator : public std::iterator { /** Skip to the next edge that is present. */ void next() { for (; m_i < NUM_BASES; ++m_i) { m_v.setLastBase(SENSE, m_i); if (vertex_exists(m_v, m_g)) break; } } public: adjacency_iterator(const DBGBloom& g) : m_g(g), m_i(NUM_BASES) { } adjacency_iterator(const DBGBloom& g, vertex_descriptor u) : m_g(g), m_v(u), 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: const DBGBloom& m_g; vertex_descriptor m_v; short unsigned m_i; }; // adjacency_iterator /** IncidenceGraph */ struct out_edge_iterator : public std::iterator { /** Skip to the next edge that is present. */ void next() { for (; m_i < NUM_BASES; ++m_i) { m_v.setLastBase(SENSE, m_i); if (vertex_exists(m_v, *m_g)) break; } } public: out_edge_iterator() { } out_edge_iterator(const DBGBloom& g) : m_g(&g), m_i(NUM_BASES) { } out_edge_iterator(const DBGBloom& g, vertex_descriptor u) : m_g(&g), m_u(u), m_v(u), m_i(0) { m_v.shift(SENSE); next(); } edge_descriptor operator*() const { assert(m_i < NUM_BASES); return edge_descriptor(m_u, m_v); } 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_BASES); ++m_i; next(); return *this; } out_edge_iterator operator++(int) { out_edge_iterator it = *this; ++*this; return it; } private: const DBGBloom* m_g; vertex_descriptor m_u; vertex_descriptor m_v; unsigned m_i; }; // out_edge_iterator /** BidirectionalGraph */ struct in_edge_iterator : public std::iterator { /** Skip to the next edge that is present. */ void next() { for (; m_i < NUM_BASES; ++m_i) { m_v.setLastBase(ANTISENSE, m_i); if (vertex_exists(m_v, *m_g)) break; } } public: in_edge_iterator() { } in_edge_iterator(const DBGBloom& g) : m_g(&g), m_i(NUM_BASES) { } in_edge_iterator(const DBGBloom& g, vertex_descriptor u) : m_g(&g), m_u(u), m_v(u), m_i(0) { m_v.shift(ANTISENSE); next(); } edge_descriptor operator*() const { assert(m_i < NUM_BASES); return edge_descriptor(m_v, m_u); } 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_BASES); ++m_i; next(); return *this; } in_edge_iterator operator++(int) { in_edge_iterator it = *this; ++*this; return it; } private: const DBGBloom* m_g; vertex_descriptor m_u; vertex_descriptor m_v; unsigned m_i; }; // in_edge_iterator }; // graph_traits } // namespace boost // Subgraph /** Return whether this vertex exists in the subgraph. */ template static inline bool vertex_exists(typename graph_traits::vertex_descriptor u, const Graph& g) { return g.m_bloom[u] > g.m_depthThresh; } template static inline std::pair::adjacency_iterator, typename graph_traits::adjacency_iterator> adjacent_vertices( typename graph_traits::vertex_descriptor u, const Graph& g) { typedef typename graph_traits::adjacency_iterator adjacency_iterator; return std::make_pair(adjacency_iterator(g, u), adjacency_iterator(g)); } // IncidenceGraph template static inline typename graph_traits::degree_size_type out_degree( typename graph_traits::vertex_descriptor u, const Graph& g) { typedef typename graph_traits::adjacency_iterator Ait; std::pair adj = adjacent_vertices(u, g); return std::distance(adj.first, adj.second); } template static inline typename std::pair::out_edge_iterator, typename graph_traits::out_edge_iterator> out_edges( typename graph_traits::vertex_descriptor u, const Graph& g) { typedef typename graph_traits::out_edge_iterator Oit; return std::make_pair(Oit(g, u), Oit(g)); } // BidirectionalGraph template static inline typename graph_traits::degree_size_type in_degree(typename graph_traits::vertex_descriptor u, const Graph& g) { return out_degree(reverseComplement(u), g); } template static inline typename graph_traits::degree_size_type degree(typename graph_traits::vertex_descriptor u, const Graph& g) { return in_degree(u, g) + out_degree(u, g); } template static inline std::pair::in_edge_iterator, typename graph_traits::in_edge_iterator> in_edges( typename graph_traits::vertex_descriptor u, const Graph& g) { typedef typename graph_traits::in_edge_iterator Iit; return std::make_pair(Iit(g, u), Iit(g)); } // VertexListGraph template static inline typename graph_traits::vertices_size_type num_vertices(const Graph& g) { return g.m_bloom.popcount(); } // PropertyGraph vertex_index template static inline DBGBloomIndexMap get(vertex_index_t, const Graph& g) { return DBGBloomIndexMap(g); } template static inline typename graph_traits::vertices_size_type get(vertex_index_t tag, const Graph& g, typename graph_traits::vertex_descriptor u) { return get(get(tag, g), u); } // PropertyGraph /** Return the reverse complement of the specified k-mer. */ template static inline typename graph_traits::vertex_descriptor get(vertex_complement_t, const Graph&, typename graph_traits::vertex_descriptor u) { return reverseComplement(u); } /** Return the name of the specified vertex. */ template static inline Kmer get(vertex_name_t, const Graph&, typename graph_traits::vertex_descriptor u) { return u; } template static inline bool get(vertex_removed_t, const Graph&, typename graph_traits::vertex_descriptor) { return false; } template static inline no_property get(vertex_bundle_t, const Graph&, typename graph_traits::edge_descriptor) { return no_property(); } template static inline no_property get(edge_bundle_t, const Graph&, typename graph_traits::edge_descriptor) { return no_property(); } #endif abyss-2.2.4/Konnector/DBGBloomAlgorithms.h000066400000000000000000000130741361462241400204020ustar00rootroot00000000000000/** * Algorithms for a de Bruijn Graph using a Bloom filter * Copyright 2014 Canada's Michael Smith Genome Science Centre */ #ifndef DBGBLOOMALGORITHMS_H #define DBGBLOOMALGORITHMS_H 1 #include "Common/Kmer.h" #include "Common/KmerIterator.h" #include "DBGBloom.h" #include "Common/StringUtil.h" #include "Common/Sequence.h" #include "DataLayer/FastaReader.h" #include "Graph/Path.h" #include #include #include // for std::max #define NO_MATCH UINT_MAX static inline Sequence pathToSeq(Path path) { Sequence seq; assert(path.size() > 0); seq.append(path[0].str()); for (unsigned i = 1; i < path.size(); i++) seq.append(1, path[i].getLastBaseChar()); 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. * * @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 * @param anchorToEnd if true, all k-mers from end of sequence * up to the chosen k-mer must be matches. (This option is used when * we wish to preserve the original sequences of the reads.) * @return position of chosen start kmer */ template static inline unsigned getStartKmerPos(const Sequence& seq, unsigned k, Direction dir, const Graph& g, unsigned numMatchesThreshold=1, bool anchorToEnd=false) { assert(numMatchesThreshold > 0); if (seq.size() < k) return NO_MATCH; 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 matchCount = 0; unsigned maxMatchLen = 0; unsigned maxMatchPos = 0; 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; } if (anchorToEnd) break; matchCount = 0; } else { matchCount++; if (matchCount >= numMatchesThreshold) return i; } } /* 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; } struct BaseChangeScore { size_t m_pos; char m_base; unsigned m_score; public: BaseChangeScore() : m_pos(0), m_base('N'), m_score(0){} BaseChangeScore(size_t pos, char base, unsigned score) : m_pos(pos), m_base(base), m_score(score){} }; template static inline bool correctSingleBaseError(const Graph& g, unsigned k, FastaRecord& read, size_t& correctedPos, bool rc = false) { if (read.seq.length() < k) return false; const std::string bases = "AGCT"; const size_t minScore = 3; std::vector scores; for (size_t i = 0; i < read.seq.length(); i++) { size_t overlapStart = std::max((int) (i - k + 1), 0); size_t overlapEnd = std::min(i + k - 1, read.seq.length() - 1); assert(overlapStart < overlapEnd); Sequence overlapStr = read.seq.substr(overlapStart, overlapEnd - overlapStart + 1); size_t changePos = i - overlapStart; for (size_t j = 0; j < bases.size(); j++) { if (read.seq[i] == bases[j]) continue; overlapStr[changePos] = bases[j]; size_t score = 0; for (KmerIterator it(overlapStr, k, rc); it != KmerIterator::end(); it++) { if (vertex_exists(*it, g)) score++; } if (score > minScore) scores.push_back(BaseChangeScore(i, bases[j], score)); } } if (scores.size() == 0) return false; BaseChangeScore bestScore; bool bestScoreSet = false; for (size_t i = 0; i < scores.size(); i++) { if (!bestScoreSet || scores[i].m_score > bestScore.m_score) { bestScore = scores[i]; bestScoreSet = true; } } correctedPos = bestScore.m_pos; read.seq[correctedPos] = bestScore.m_base; return true; } /** Uppercase only bases that are present in original reads. * @return number of mis-matching bases. */ static inline unsigned maskNew(const FastaRecord& read1, const FastaRecord& read2, FastaRecord& merged, int mask = 0) { Sequence r1 = read1.seq, r2 = reverseComplement(read2.seq); if (mask) { transform(r1.begin(), r1.end(), r1.begin(), ::tolower); transform(r2.begin(), r2.end(), r2.begin(), ::tolower); transform(merged.seq.begin(), merged.seq.end(), merged.seq.begin(), ::tolower); } unsigned mismatches = 0; for (unsigned i = 0; i < r1.size(); i++) { assert(i < merged.seq.size()); if (r1[i] == merged.seq[i]) merged.seq[i] = toupper(r1[i]); else mismatches++; } for (unsigned i = 0; i < r2.size(); i++) { assert(r2.size() <= merged.seq.size()); unsigned merged_loc = i + merged.seq.size() - r2.size(); if (r2[i] == merged.seq[merged_loc]) merged.seq[merged_loc] = toupper(r2[i]); else mismatches++; } return mismatches; } #endif abyss-2.2.4/Konnector/Makefile.am000066400000000000000000000006161361462241400166440ustar00rootroot00000000000000bin_PROGRAMS = konnector konnector_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer konnector_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) konnector_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Align/libalign.a \ $(top_builddir)/Common/libcommon.a konnector_SOURCES = konnector.cc \ DBGBloom.h \ DBGBloomAlgorithms.h \ konnector.h abyss-2.2.4/Konnector/README.md000066400000000000000000000164521361462241400160740ustar00rootroot00000000000000--- title: konnector author: Ben Vandervalk, Shaun Jackman, Tony Raymond, Hamid Mohamadi, Justin Chu date: 2015-06-30 header: ABySS footer: ABySS section: 1 --- NAME ==== konnector - merged paired-end sequences by finding connecting paths in the de Bruijn graph SYNOPSIS ======== `konnector -k -o [options]... [FASTQ]...` DESCRIPTION =========== Konnector generates long pseudo-reads by finding connecting paths between paired-end reads within the de Bruijn graph. This can be thought of as a targeted de novo assembly in the neighbourhood of the paired-end reads. An additional feature of Konnector is the ability to extend the pseudo-reads and unmerged reads outwards, until it encounters a branching point or dead end in the de Bruijn graph. Konnector uses a Bloom filter representation of the de Bruijn graph to minimize memory requirements, as described in: Chikhi, Rayan, and Guillaume Rizk. "Space-efficient and exact de Bruijn graph representation based on a Bloom filter." Algorithms for Molecular Biology 8.22 (2013):1. OPTIONS ======= Required Options ---------------- ``` -k, --kmer=N the size of a k-mer [required] -o, --output-prefix=FILE prefix of output FASTA files [required] ``` Bloom Filter Options -------------------- ``` -b, --bloom-size=N size of bloom filter [500M] -c, --min-coverage=N kmer coverage threshold for error correction [2]. This option specifies the number of levels in the cascading Bloom filter; it has no effect if the Bloom filter is loaded from an external file. -i, --input-bloom=FILE load bloom filter from FILE; Bloom filter files can be created separately with the 'abyss-bloom' program ``` Graph Search Limits ------------------- ``` -B, --max-branches=N max branches in de Bruijn graph traversal; use 'nolimit' for no limit [350] -f, --min-frag=N min fragment size in base pairs [0] -F, --max-frag=N max fragment size in base pairs [1000] -P, --max-paths=N merge at most N alternate paths; use 'nolimit' for no limit [2] ``` Sequence Identity Limits ------------------------ ``` -m, --read-mismatches=N max mismatches between paths and reads; use 'nolimit' for no limit [nolimit] -M, --max-mismatches=N max mismatches between all alternate paths; use 'nolimit' for no limit [2] -x, --read-identity=N min percent seq identity between consensus seq and reads [0] -X, --path-identity=N min percent seq identity across alternate connecting paths [0] ``` Input Options ------------- ``` -q, --trim-quality=N trim bases from the ends of reads whose quality is less than the threshold --standard-quality zero quality is `!' (33), typically for FASTQ and SAM files [default] --illumina-quality zero quality is `@' (64), typically for qseq and export files --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] -I, --interleaved input reads files are interleaved ``` Output Options -------------- ``` --fastq output merged reads in FASTQ format (default is FASTA); bases that are corrected or inserted by konnector are assigned a fixed quality score determined by -Q -Q, --corrected-qual quality score for bases corrected or inserted by konnector; only relevant when --fastq is in effect [40] --mask mask new and changed bases as lower case --no-mask do not mask bases [default] -p, --alt-paths-mode output a separate pseudoread for each alternate path connecting a read pair (default is to create a consensus sequence of all connecting paths). The limit on the number of alternate paths is specified by the '--max-paths' option. The sequence IDs for alternate paths are named: ${orig_read_id}_1, ${orig_read_id}_2, ... --preserve-reads don't correct any bases within the reads [disabled] -v, --verbose display verbose output ``` Debugging Options ----------------- ``` -d, --dot-file=FILE write graph traversals to a DOT file -r, --read-name=STR only process reads with names that contain STR -t, --trace-file=FILE write graph search stats to FILE ``` Sequence Extension Options -------------------------- ``` -D, --dup-bloom-size=N use an additional Bloom filter to avoid assembling the same region of the genome multiple times. This option is highly recommended whenever -E (--extend) is used and has no effect otherwise. As a rule of thumb, the Bloom filter size should be about twice the target genome size [disabled] -E, --extend in addition to connecting read pairs, extend the merged reads outwards to the next dead end or branching point in the de Brujin graph. For read pairs that were not successfully connected, trim the single-end reads at both ends and extend them independently. ``` Other Options ------------- ``` -e, --fix-errors find and fix single-base errors when reads have no kmers in bloom filter [disabled] -j, --threads=N use N parallel threads [1] -n --no-limits disable all limits; equivalent to '-B nolimit -m nolimit -M nolimit -P nolimit' --help display this help and exit --version output version information and exit ``` OUTPUT FILES ============ `$PREFIX` in the filenames below is determined by the `-o` option. Without `--extend`: * `$PREFIX_pseudoreads.fa`: Pseudo-reads created by connecting paired-end reads. * `$PREFIX_reads_1.fq`: Read 1 from read pairs that could not be connected. * `$PREFIX_reads_2.fq`: Read 2 from read pairs that could not be connected. With `--extend`: * `$prefix_pseudoreads.fa`: Pseudo-reads created by connecting paired-end reads, which may or may not be extended. Also contains single-end reads from read pairs that could not be connected, but which could be trimmed and/or extended. * `$PREFIX_reads_1.fq`: Read 1 from read pairs that could not be connected and which could not be trimmed (because they contain no "good" k-mers). * `$PREFIX_reads_2.fq`: Read 2 from read pairs that could not be connected and which could not be trimmed (because they contain no "good" k-mers). AUTHORS ======= Ben Vandervalk, Shaun Jackman, Tony Raymond, Hamid Mohamadi, Justin Chu. REPORTING BUGS ============== Report bugs to . abyss-2.2.4/Konnector/konnector.cc000066400000000000000000001163061361462241400171250ustar00rootroot00000000000000/** * Connect pairs using a Bloom filter de Bruijn graph * Copyright 2013 Shaun Jackman */ #include "config.h" #include "konnector.h" #include "Bloom/CascadingBloomFilter.h" #include "DBGBloom.h" #include "DBGBloomAlgorithms.h" #include "Align/alignGlobal.h" #include "Common/IOUtil.h" #include "Common/Options.h" #include "Common/StringUtil.h" #include "DataLayer/FastaConcat.h" #include "DataLayer/FastaInterleave.h" #include "DataLayer/Options.h" #include "Graph/DotIO.h" #include "Graph/Options.h" #include "Graph/GraphUtil.h" #include #include #include #include #include #if _OPENMP # include # include "Bloom/ConcurrentBloomFilter.h" #endif using namespace std; using Konnector::BloomFilter; #define PROGRAM "konnector" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman, Hamid Mohamadi, Anthony Raymond, \n" "Ben Vandervalk and Justin Chu.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Science Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -o [options]... [reads2]...\n" "Connect the pairs READS1 and READS2 and close the gap using\n" "a Bloom filter de Bruijn graph.\n" "\n" " Options:\n" "\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" " -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" " -C, --max-cost=N max edges to traverse during each graph search [25000]\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" " --fastq output merged reads in FASTQ format\n" " (default is FASTA)\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" " -I, --interleaved input reads files are interleaved\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, --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" " use 'nolimit' for no limit [2]\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" " --preserve-reads don't correct any bases within the reads [disabled]\n" " -p, --alt-paths-mode output a separate pseudoread for each alternate\n" " path connecting a read pair (default is to create\n" " a consensus sequence of all connecting paths)\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), typically\n" " for FASTQ and SAM files [default]\n" " --illumina-quality zero quality is `@' (64), typically\n" " for qseq and export files\n" " -Q, --corrected-qual quality score for bases corrected or inserted\n" " by konnector; only relevant when --fastq is\n" " in effect [40]\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" " -x, --read-identity=N min percent seq identity between consensus seq\n" " and reads [0]\n" " -X, --path-identity=N min percent seq identity across alternate\n" " connecting paths [0]\n" " --help display this help and exit\n" " --version output version information and exit\n" "\n" " Deprecated Options:\n" "\n" " -B, --max-branches=N max branches in de Bruijn graph traversal;\n" " use 'nolimit' for no limit [nolimit]\n" "\n" " Note: --max-branches was not effective for truncating expensive searches,\n" " and has been superseded by the --max-cost option.\n" "\n" "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 to keep track of portions * of genome that have already been assembled. * This Bloom filter is only used when both * the --extend and --dup-bloom-size options * are in effect. */ BloomFilter g_dupBloom; namespace opt { /** 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 minCoverage = 2; /** Input read files are interleaved? */ bool interleaved = false; /** Max active branches during de Bruijn graph traversal */ unsigned maxBranches = NO_LIMIT; /** * Max cost for a connecting path search. Searches that * exceed this cost limit will be aborted and the read * pair will remain unmerged. */ unsigned maxCost = 25000; /** multi-graph DOT file containing graph traversals */ 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; /** * Output pseudo-reads in FASTQ format. */ bool fastq = false; /** The size of a k-mer. */ unsigned k; /** The minimum fragment size */ unsigned minFrag = 0; /** The maximum fragment size */ unsigned maxFrag = 1000; /** Bloom filter input file */ static string inputBloomPath; /** * Do not correct bases in input read sequences. */ static bool preserveReads = false; /** * Output separate sequence for each alternate path * between read pairs */ static bool altPathsMode = false; /** Max paths between read 1 and read 2 */ unsigned maxPaths = 2; /** * Quality score for bases that are corrected * or inserted by konnector. */ uint8_t correctedQual = 40; /** Prefix for output files */ static string outputPrefix; /** Max mismatches allowed when building consensus seqs */ unsigned maxMismatches = 2; /** Only process reads 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 reads */ static int mask = 0; /** Max mismatches between consensus and original reads */ static unsigned maxReadMismatches = NO_LIMIT; /** * Min percent seq identity between consensus seq * and input reads */ static float minReadIdentity = 0.0f; /** * Min percent seq identity between all alternate * paths */ static float minPathIdentity = 0.0f; } /** Counters */ static struct { 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 maxCostExceeded; size_t exceededMemLimit; size_t traversalMemExceeded; size_t readPairsProcessed; size_t readPairsMerged; size_t skipped; /* counts below are used only when -E is enabled */ size_t mergedAndSkipped; size_t singleEndExtended; } g_count; static const char shortopts[] = "b:B:c:C:d:D:eEf:F:i:Ij:k:lm:M:no:p:P:q:Q:r:s:t:vx:X:"; enum { OPT_FASTQ = 1, OPT_HELP, OPT_PRESERVE_READS, 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' }, { "max-cost", required_argument, NULL, 'C' }, { "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' }, { "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' }, { "read-mismatches", required_argument, NULL, 'm' }, { "max-mismatches", required_argument, NULL, 'M' }, { "alt-paths-mode", no_argument, NULL, 'p' }, { "max-paths", required_argument, NULL, 'P' }, { "trim-quality", required_argument, NULL, 'q' }, { "corrected-qual", 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' }, { "read-identity", required_argument, NULL, 'x' }, { "path-identity", required_argument, NULL, 'X' }, { "fastq", no_argument, NULL, OPT_FASTQ }, { "help", no_argument, NULL, OPT_HELP }, { "preserve-reads", no_argument, NULL, OPT_PRESERVE_READS }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** * Return true if the Bloom filter contains all of the * "good" kmers in the given sequence. */ static inline bool isSeqRedundant(const BloomFilter& assembledKmers, const BloomFilter& goodKmers, Sequence seq) { flattenAmbiguityCodes(seq, false); for (KmerIterator it(seq, opt::k); it != KmerIterator::end(); ++it) { if (goodKmers[*it] && !assembledKmers[*it]) return false; } return true; } /** * Load the kmers of a given sequence into a Bloom filter. */ static inline void addKmers(BloomFilter& bloom, const BloomFilter& goodKmers, unsigned k, const Sequence& seq) { if (containsAmbiguityCodes(seq)) { Sequence flattened = seq; Sequence rcFlattened = reverseComplement(seq); flattenAmbiguityCodes(flattened, false); flattenAmbiguityCodes(rcFlattened, false); for (KmerIterator it(flattened, k); it != KmerIterator::end();++it) { if (goodKmers[*it]) bloom.insert(*it); } for (KmerIterator it(rcFlattened, k); it != KmerIterator::end(); ++it) { if (goodKmers[*it]) bloom.insert(*it); } return; } else { for (KmerIterator it(seq, k); it != KmerIterator::end(); ++it) { if (goodKmers[*it]) bloom.insert(*it); } } } enum ExtendResult { ER_NOT_EXTENDED, ER_REDUNDANT, ER_EXTENDED }; /** * Calculate quality string for a pseudo-read. A base will * have a score of CORRECTED_BASE_QUAL if it was corrected * by konnector or added by konnector (in the gap between * paired-end reads). For bases that are unchanged from the * input reads, the original quality score is used. In the * case that the two input read(s) overlap and both provide * a correct base call, the maximum of the two quality scores * is used. */ static inline std::string calcQual(const FastqRecord& read1, const FastqRecord& read2, Sequence& merged) { unsigned char correctedQual = opt::qualityOffset + opt::correctedQual; std::string qual(merged.length(), correctedQual); /* * In the case that the input files are FASTA, * the quality strings for read1 / read2 will be * empty, so just return a uniform quality string. */ if (read1.qual.empty() || read2.qual.empty()) return qual; Sequence r1 = read1.seq, r2 = reverseComplement(read2.seq); std::string r1qual = read1.qual, r2qual = read2.qual; std::reverse(r2qual.begin(), r2qual.end()); assert(r1.length() <= merged.length()); assert(r2.length() <= merged.length()); /* region covered only by read 1 */ unsigned r2offset = merged.length() - r2.length(); for (unsigned r1pos = 0; r1pos < r1.length() && r1pos < r2offset; ++r1pos) { if (r1.at(r1pos) == merged.at(r1pos)) { qual.at(r1pos) = r1qual.at(r1pos); } else { //r1Corrected.at(i) = true; qual.at(r1pos) = correctedQual; } } /* region where read 1 and read 2 overlap */ for (unsigned r1pos = r2offset; r1pos < r1.length(); ++r1pos) { unsigned r2pos = r1pos - r2offset; if (r1.at(r1pos) != merged.at(r1pos) || r2.at(r2pos) != merged.at(r1pos)) { qual.at(r1pos) = correctedQual; } else { assert(r1.at(r1pos) == r2.at(r2pos)); qual.at(r1pos) = max(r1qual.at(r1pos), r2qual.at(r2pos)); } } /* region covered only by read 2 */ for (unsigned r1pos = max(r2offset, (unsigned)r1.length()); r1pos < merged.length(); ++r1pos) { unsigned r2pos = r1pos - r2offset; if (r2.at(r2pos) == merged.at(r1pos)) { qual.at(r1pos) = r2qual.at(r2pos); } else { qual.at(r1pos) = correctedQual; } } return qual; } static inline string calcQual(const FastqRecord& orig, const Sequence& extended, unsigned extendedLeft, unsigned extendedRight) { assert(extended.length() == orig.seq.length() + extendedLeft + extendedRight); unsigned char correctedQual = opt::qualityOffset + opt::correctedQual; string qual(extended.length(), correctedQual); /* * In the case that the input files are FASTA, * the quality strings for read1 / read2 will be * empty, so just return a uniform quality string. */ if (orig.qual.empty()) return qual; unsigned offset = extendedLeft; for (unsigned i = 0; i < orig.seq.length(); ++i) { assert(offset + i < extended.length()); assert(i < orig.seq.length()); assert(i < orig.qual.length()); if (orig.seq.at(i) == extended.at(offset + i)) qual.at(offset + i) = orig.qual.at(i); } return qual; } /** * 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 static bool extendRead(FastqRecord& rec, unsigned k, const Graph& g) { unsigned extendedLeft = 0, extendedRight = 0; Sequence extendedSeq = rec.seq; /* * offset start pos to reduce chance of hitting * a dead end on a false positive kmer */ const unsigned runLengthHint = 3; unsigned startPos = getStartKmerPos(extendedSeq, k, FORWARD, g, runLengthHint); if (startPos != NO_MATCH) { assert(startPos <= extendedSeq.length() - k); unsigned lengthBefore = extendedSeq.length(); extendSeq(extendedSeq, FORWARD, startPos, k, g, NO_LIMIT, g_trimLen, opt::mask, !opt::altPathsMode, opt::preserveReads); extendedRight = extendedSeq.length() - lengthBefore; } startPos = getStartKmerPos(extendedSeq, k, REVERSE, g, runLengthHint); if (startPos != NO_MATCH) { assert(startPos <= extendedSeq.length() - k); unsigned lengthBefore = extendedSeq.length(); extendSeq(extendedSeq, REVERSE, startPos, k, g, NO_LIMIT, g_trimLen, opt::mask, !opt::altPathsMode, opt::preserveReads); extendedLeft = extendedSeq.length() - lengthBefore; } if (extendedLeft > 0 || extendedRight > 0) { rec.qual = calcQual(rec, extendedSeq, extendedLeft, extendedRight); rec.seq = extendedSeq; return true; } return false; } /** * 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 static inline ExtendResult extendReadIfNonRedundant(FastqRecord& seq, BloomT1& assembledKmers, const BloomT2& goodKmers, unsigned k, const Graph& g) { bool extended = false; 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 = isSeqRedundant(assembledKmers, goodKmers, seq); if (redundant) return ER_REDUNDANT; } Sequence origSeq = seq.seq; 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 (!isSeqRedundant(assembledKmers, goodKmers, origSeq)) addKmers(assembledKmers, goodKmers, k, seq.seq); else redundant = true; } if (redundant) return ER_REDUNDANT; } assert(!redundant); if (extended) return ER_EXTENDED; else return ER_NOT_EXTENDED; } static inline FastqRecord connectingSeq(const FastqRecord& mergedSeq, unsigned startKmerPos, unsigned goalKmerPos) { FastqRecord rec; unsigned start = startKmerPos; unsigned end = mergedSeq.seq.length() - 1 - goalKmerPos; assert(start <= end); rec.id = mergedSeq.id; rec.seq = mergedSeq.seq.substr(start, end - start + 1); rec.qual = mergedSeq.qual.substr(start, end - start + 1); return rec; } /** * 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.singleEndExtended << " 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 << ", " << "max cost exceeded: " << g_count.maxCostExceeded << ", " << "skipped: " << g_count.skipped << ")\n"; } static inline void updateCounters(const ConnectPairsParams& params, const ConnectPairsResult& result) { switch (result.pathResult) { case NO_PATH: assert(result.mergedSeqs.empty()); if (result.foundStartKmer && result.foundGoalKmer) #pragma omp atomic ++g_count.noPath; else #pragma omp atomic ++g_count.noStartOrGoalKmer; break; case FOUND_PATH: assert(!result.mergedSeqs.empty()); if (result.pathMismatches > params.maxPathMismatches || result.pathIdentity < params.minPathIdentity) { #pragma omp atomic ++g_count.tooManyMismatches; } else if (result.readMismatches > params.maxReadMismatches || result.readIdentity < params.minReadIdentity) { #pragma omp atomic ++g_count.tooManyReadMismatches; } else { if (result.mergedSeqs.size() == 1) #pragma omp atomic ++g_count.uniquePath; else #pragma omp atomic ++g_count.multiplePaths; } 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 MAX_COST_EXCEEDED: #pragma omp atomic ++g_count.maxCostExceeded; break; case EXCEEDED_MEM_LIMIT: #pragma omp atomic ++g_count.exceededMemLimit; break; } } static inline void outputRead(const FastqRecord& read, ostream& out, bool fastq = true) { if (fastq) out << read; else out << (FastaRecord)read; } static inline bool exceedsMismatchThresholds(const ConnectPairsParams& params, const ConnectPairsResult& result) { return (result.pathMismatches > params.maxPathMismatches || result.pathIdentity < params.minPathIdentity || result.readMismatches > params.maxReadMismatches || result.readIdentity < params.minReadIdentity); } /** * Correct and extend an unmerged single-end read. * @return true if the read was modified, false otherwise */ template static inline bool correctAndExtend(FastqRecord& read, BloomT1& assembledKmers, const BloomT2& goodKmers, unsigned k, const Graph& g, bool preserveRead=false) { bool corrected = false; if (!preserveRead) corrected = trimRead(read, k, g); if (preserveRead || corrected) { ExtendResult extendResult = extendReadIfNonRedundant(read, assembledKmers, goodKmers, k, g); if (extendResult == ER_EXTENDED) return true; } return corrected; } /** Connect a read pair. */ template static void connectPair(const Graph& g, const Bloom& bloom, FastqRecord& read1, FastqRecord& read2, const ConnectPairsParams& params, ofstream& mergedStream, ofstream& read1Stream, ofstream& read2Stream, ofstream& traceStream) { /* * 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; return; } /* Search for connecting paths between read pair */ ConnectPairsResult result = connectPairs(opt::k, read1, read2, g, params); /* Calculate quality strings for merged reads */ vector paths; FastqRecord consensus; if (result.pathResult == FOUND_PATH) { for (unsigned i = 0; i < result.mergedSeqs.size(); ++i) { FastqRecord fastq; fastq.id = result.mergedSeqs.at(i).id; fastq.seq = result.mergedSeqs.at(i).seq; fastq.qual = calcQual(read1, read2, result.mergedSeqs.at(i).seq); paths.push_back(fastq); } consensus.id = result.consensusSeq.id; consensus.seq = result.consensusSeq.seq; consensus.qual = calcQual(read1, read2, result.consensusSeq.seq); } bool outputRead1 = false; bool outputRead2 = false; std::vector pathRedundant; /* * 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 && !exceedsMismatchThresholds(params, result)) { /* we found at least one connecting path */ assert(paths.size() > 0); if (opt::altPathsMode) { /* extend each alternate path independently */ for (unsigned i = 0; i < paths.size(); ++i) { if (!opt::preserveReads) paths.at(i) = connectingSeq(paths.at(i), result.startKmerPos, result.goalKmerPos); extendResult = extendReadIfNonRedundant( paths.at(i), g_dupBloom, bloom, opt::k, g); pathRedundant.push_back(extendResult == ER_REDUNDANT); } } else { /* extend consensus sequence for all paths */ if (!opt::preserveReads) consensus = connectingSeq(consensus, result.startKmerPos, result.goalKmerPos); extendResult = extendReadIfNonRedundant( consensus, g_dupBloom, bloom, opt::k, g); pathRedundant.push_back(extendResult == ER_REDUNDANT); } if (std::find(pathRedundant.begin(), pathRedundant.end(), false) == pathRedundant.end()) { #pragma omp atomic g_count.mergedAndSkipped++; } } else { /* * read pair could not be merged, so try * to correct and extend each read individually (in * both directions). */ if (correctAndExtend(read1, g_dupBloom, bloom, opt::k, g, opt::preserveReads)) { /* avoid duplicate read IDs */ if (!endsWith(read1.id, "/1")) { read1.id.append("/1"); read1.comment.clear(); } outputRead1 = true; #pragma omp atomic g_count.singleEndExtended++; } if (correctAndExtend(read2, g_dupBloom, bloom, opt::k, g, opt::preserveReads)) { /* avoid duplicate read IDs */ if (!endsWith(read2.id, "/2")) { read2.id.append("/2"); read2.comment.clear(); } outputRead2 = true; #pragma omp atomic g_count.singleEndExtended++; } } } if (!opt::tracefilePath.empty()) #pragma omp critical(tracefile) { traceStream << result; assert_good(traceStream, opt::tracefilePath); } /* update stats regarding merge successes / failures */ updateCounters(params, result); /* output merged / unmerged reads */ if (result.pathResult == FOUND_PATH && !exceedsMismatchThresholds(params, result)) { assert(!paths.empty()); if (opt::altPathsMode) { #pragma omp critical(mergedStream) for (unsigned i = 0; i < paths.size(); ++i) { if (opt::dupBloomSize == 0 || !pathRedundant.at(i)) outputRead(paths.at(i), mergedStream, opt::fastq); } } else if (opt::dupBloomSize == 0 || !pathRedundant.front()) { #pragma omp critical(mergedStream) outputRead(consensus, mergedStream, opt::fastq); } } else { if (opt::extend) { if (outputRead1 || outputRead2) #pragma omp critical(mergedStream) { if (outputRead1) outputRead(read1, mergedStream, opt::fastq); if (outputRead2) outputRead(read2, mergedStream, opt::fastq); } if (!outputRead1 || !outputRead2) #pragma omp critical(readStream) { if (!outputRead1) read1Stream << read1; if (!outputRead2) read2Stream << read2; } } else #pragma omp critical(readStream) { read1Stream << read1; read2Stream << read2; } } } /** Connect read pairs. */ template static void connectPairs(const Graph& g, const Bloom& bloom, FastaStream& in, const ConnectPairsParams& params, ofstream& mergedStream, ofstream& read1Stream, ofstream& read2Stream, ofstream& traceStream) { #pragma omp parallel for (FastqRecord a, b;;) { bool good; #pragma omp critical(in) good = in >> a >> b; if (good) { connectPair(g, bloom, a, b, params, mergedStream, read1Stream, read2Stream, traceStream); #pragma omp atomic g_count.readPairsProcessed++; if (opt::verbose >= 2) #pragma omp critical(cerr) { if(g_count.readPairsProcessed % g_progressStep == 0) printProgressMessage(); } } else { break; } } } /** * 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.fail() && str.compare("nolimit")==0) { arg = NO_LIMIT; } else { istringstream ss(str); ss >> arg; // copy state bits (fail, bad, eof) to // original stream in.clear(ss.rdstate()); } } /** * Connect pairs using a Bloom filter de Bruijn graph */ int main(int argc, char** argv) { bool die = false; bool minCovOptUsed = 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 'b': opt::bloomSize = SIToBytes(arg); break; case 'B': setMaxOption(opt::maxBranches, arg); break; case 'c': arg >> opt::minCoverage; minCovOptUsed = true; break; case 'C': arg >> opt::maxCost; 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': arg >> opt::maxFrag; break; case 'i': arg >> opt::inputBloomPath; break; case 'I': opt::interleaved = true; break; case 'j': arg >> opt::threads; break; case 'k': arg >> opt::k; break; case 'm': setMaxOption(opt::maxReadMismatches, arg); break; case 'n': opt::maxBranches = NO_LIMIT; opt::maxReadMismatches = 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': opt::altPathsMode = true; break; case 'P': setMaxOption(opt::maxPaths, arg); break; case 'q': arg >> opt::qualityThreshold; break; case 'Q': arg >> opt::correctedQual; break; case 'r': arg >> opt::readName; break; case 's': opt::searchMem = SIToBytes(arg); break; case 't': arg >> opt::tracefilePath; break; case 'x': arg >> opt::minReadIdentity; break; case 'X': arg >> opt::minPathIdentity; break; case 'v': opt::verbose++; break; case OPT_FASTQ: opt::fastq = true; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_PRESERVE_READS: opt::preserveReads = true; break; 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::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 (!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); #endif Kmer::setLength(opt::k); #if USESEQAN seqanTests(); #endif /* * We need to set a default quality score offset * in order to generate quality scores * for bases that are corrected/inserted by * konnector (--fastq option). */ if (opt::qualityOffset == 0) opt::qualityOffset = 33; assert(opt::bloomSize > 0); if (opt::dupBloomSize > 0) g_dupBloom.resize(opt::dupBloomSize * 8); BloomFilter* bloom; CascadingBloomFilter* cascadingBloom = NULL; if (!opt::inputBloomPath.empty()) { if (opt::verbose) 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; assert_good(inputBloom, inputPath); inputBloom.close(); } else { 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 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(*cascadingBloom, opt::k, string(argv[i]), opt::verbose); #endif bloom = &cascadingBloom->getBloomFilter(opt::minCoverage - 1); } if (opt::verbose) cerr << "Bloom filter FPR: " << setprecision(3) << 100 * bloom->FPR() << "%\n"; 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); } DBGBloom g(*bloom); /* * read pairs that were successfully connected * (and possibly extended outwards) */ string mergedOutputPath(opt::outputPrefix); mergedOutputPath.append("_pseudoreads"); if (opt::fastq) mergedOutputPath.append(".fq"); else mergedOutputPath.append(".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"); ofstream read1Stream(read1OutputPath.c_str()); assert_good(read1Stream, read1OutputPath); string read2OutputPath(opt::outputPrefix); read2OutputPath.append("_reads_2.fq"); ofstream read2Stream(read2OutputPath.c_str()); assert_good(read2Stream, read2OutputPath); if (opt::verbose > 0) cerr << "Connecting read pairs\n"; ConnectPairsParams params; params.minMergedSeqLen = opt::minFrag; params.maxMergedSeqLen = opt::maxFrag; params.maxCost = opt::maxCost; params.maxPaths = opt::maxPaths; params.maxBranches = opt::maxBranches; params.maxPathMismatches = opt::maxMismatches; params.minPathIdentity = opt::minPathIdentity; params.maxReadMismatches = opt::maxReadMismatches; params.minReadIdentity = opt::minReadIdentity; params.kmerMatchesThreshold = 3; params.fixErrors = opt::fixErrors; params.maskBases = opt::mask; params.preserveReads = opt::preserveReads; params.memLimit = opt::searchMem; params.dotPath = opt::dotPath; params.dotStream = opt::dotPath.empty() ? NULL : &dotStream; if (opt::interleaved) { FastaConcat in(argv + optind, argv + argc, FastaReader::FOLD_CASE); connectPairs(g, *bloom, in, params, mergedStream, read1Stream, read2Stream, traceStream); assert(in.eof()); } else { FastaInterleave in(argv + optind, argv + argc, FastaReader::FOLD_CASE); connectPairs(g, *bloom, in, params, mergedStream, read1Stream, read2Stream, traceStream); assert(in.eof()); } if (opt::verbose > 0) { cerr << "Processed " << g_count.readPairsProcessed << " read pairs\n" "Merged (Unique path + Multiple paths): " << g_count.uniquePath + g_count.multiplePaths << " (" << setprecision(3) << (float)100 * (g_count.uniquePath + g_count.multiplePaths) / g_count.readPairsProcessed << "%)\n" "No start/goal kmer: " << g_count.noStartOrGoalKmer << " (" << setprecision(3) << (float)100 * g_count.noStartOrGoalKmer / g_count.readPairsProcessed << "%)\n" "No path: " << g_count.noPath << " (" << setprecision(3) << (float)100 * g_count.noPath / g_count.readPairsProcessed << "%)\n" "Unique path: " << g_count.uniquePath << " (" << setprecision(3) << (float)100 * g_count.uniquePath / g_count.readPairsProcessed << "%)\n" "Multiple paths: " << g_count.multiplePaths << " (" << setprecision(3) << (float)100 * g_count.multiplePaths / g_count.readPairsProcessed << "%)\n" "Too many paths: " << g_count.tooManyPaths << " (" << setprecision(3) << (float)100 * g_count.tooManyPaths / g_count.readPairsProcessed << "%)\n" "Too many branches: " << g_count.tooManyBranches << " (" << setprecision(3) << (float)100 * g_count.tooManyBranches / g_count.readPairsProcessed << "%)\n" "Too many path/path mismatches: " << g_count.tooManyMismatches << " (" << setprecision(3) << (float)100 * g_count.tooManyMismatches / g_count.readPairsProcessed << "%)\n" "Too many path/read mismatches: " << g_count.tooManyReadMismatches << " (" << setprecision(3) << (float)100 * g_count.tooManyReadMismatches / g_count.readPairsProcessed << "%)\n" "Contains cycle: " << g_count.containsCycle << " (" << setprecision(3) << (float)100 * g_count.containsCycle / g_count.readPairsProcessed << "%)\n" "Max cost exceeded: " << g_count.maxCostExceeded << " (" << setprecision(3) << (float)100 * g_count.maxCostExceeded / g_count.readPairsProcessed << "%)\n" "Skipped: " << g_count.skipped << " (" << setprecision(3) << (float)100 * g_count.skipped / g_count.readPairsProcessed << "%)\n"; if (opt::extend) { cerr << "Unmerged reads corrected/extended: " << g_count.singleEndExtended << " (" << setprecision(3) << (float)100 * g_count.singleEndExtended / ((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()); read1Stream.close(); assert_good(read2Stream, read2OutputPath.c_str()); read2Stream.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; } abyss-2.2.4/Konnector/konnector.h000066400000000000000000000571411361462241400167700ustar00rootroot00000000000000#ifndef CONNECTPAIRS_H #define CONNECTPAIRS_H #include "DBGBloomAlgorithms.h" #include "Bloom/CascadingBloomFilter.h" #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 #include #include #include #if _OPENMP # include #endif struct ConnectPairsResult { unsigned k; std::string readNamePrefix; PathSearchResult pathResult; unsigned searchCost; /** alternate connecting sequence(s) for read pair */ std::vector connectingSeqs; /** read pairs joined with alternate connecting sequence(s) */ std::vector mergedSeqs; /** consensus sequence for alternate connecting sequences */ Sequence consensusConnectingSeq; /** * consensus sequence for read pairs joined by * alternate connecting sequences */ FastaRecord consensusSeq; bool foundStartKmer; bool foundGoalKmer; unsigned startKmerPos; unsigned goalKmerPos; unsigned long long numNodesVisited; unsigned maxActiveBranches; unsigned maxDepthVisitedForward; unsigned maxDepthVisitedReverse; unsigned pathMismatches; float pathIdentity; unsigned readMismatches; float readIdentity; size_t memUsage; ConnectPairsResult() : k(0), pathResult(NO_PATH), searchCost(0), foundStartKmer(false), foundGoalKmer(false), startKmerPos(NO_MATCH), goalKmerPos(NO_MATCH), numNodesVisited(0), maxActiveBranches(0), maxDepthVisitedForward(0), maxDepthVisitedReverse(0), pathMismatches(0), pathIdentity(0.0f), readMismatches(0), readIdentity(0.0f), memUsage(0) {} static std::ostream& printHeaders(std::ostream& out) { out << "k\t" << "read_id" << "\t" << "search_result" << "\t" << "search_cost" << "\t" << "num_paths" << "\t" << "path_lengths" << "\t" << "start_kmer_pos" << "\t" << "end_kmer_pos" << "\t" << "nodes_visited" << "\t" << "max_breadth" << "\t" << "max_depth_forward" << "\t" << "max_depth_reverse" << "\t" << "path_mismatches" << "\t" << "path_identity" << "\t" << "read_mismatches" << "\t" << "read_identity" << "\t" << "mem_usage" << "\n"; return out; } friend std::ostream& operator <<(std::ostream& out, const ConnectPairsResult& o) { out << o.k << '\t' << o.readNamePrefix << "\t" << PathSearchResultLabel[o.pathResult] << "\t" << o.searchCost << "\t" << o.mergedSeqs.size() << "\t"; if (o.mergedSeqs.size() == 0) { out << "NA" << "\t"; } else { for (unsigned i = 0; i < o.mergedSeqs.size(); i++) { out << o.mergedSeqs[i].seq.size(); if (i < o.mergedSeqs.size() - 1) out << ","; } out << "\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" << o.pathMismatches << "\t" << std::setprecision(3) << o.pathIdentity << "\t" << o.readMismatches << "\t" << std::setprecision(3) << o.readIdentity << "\t" << o.memUsage << "\n"; return out; } }; struct ConnectPairsParams { unsigned minMergedSeqLen; unsigned maxMergedSeqLen; unsigned maxPaths; unsigned maxBranches; unsigned maxCost; unsigned maxPathMismatches; float minPathIdentity; unsigned maxReadMismatches; float minReadIdentity; unsigned kmerMatchesThreshold; bool fixErrors; bool maskBases; bool preserveReads; size_t memLimit; std::string dotPath; std::ofstream* dotStream; ConnectPairsParams() : minMergedSeqLen(0), maxMergedSeqLen(1000), maxPaths(NO_LIMIT), maxBranches(NO_LIMIT), maxCost(NO_LIMIT), maxPathMismatches(NO_LIMIT), minPathIdentity(0.0f), maxReadMismatches(NO_LIMIT), minReadIdentity(0.0f), kmerMatchesThreshold(1), fixErrors(false), maskBases(false), preserveReads(false), memLimit(std::numeric_limits::max()), dotStream(NULL) {} }; static inline void colorPath(HashGraph& graph, unsigned k, const Sequence& seq, const std::string& color, bool addEdges = true) { KmerIterator it(seq, k); if (it != it.end()) { graph.set_vertex_color(*it, color); Kmer prev = *it; ++it; for(; it != it.end(); prev=*it, ++it) { if (addEdges) add_edge(prev, *it, graph); graph.set_vertex_color(*it, color); } } } /** Write a color-coded traversal graph to a DOT file. */ static inline void writeDot( HashGraph& traversalGraph, unsigned k, const FastaRecord& read1, const FastaRecord& read2, const ConnectPairsParams& params, const ConnectPairsResult& result) { const std::string pathColor("darkgreen"); const std::string solutionColor("green"); const std::string read1Color("blue"); const std::string read2Color("red"); // color kmers for the paths / consensus const std::vector& paths = result.mergedSeqs; if (paths.size() == 1) { colorPath(traversalGraph, k, paths.front(), solutionColor); } else if (paths.size() > 1) { for (unsigned i = 0; i < paths.size(); i++) colorPath(traversalGraph, k, paths.at(i), pathColor); colorPath(traversalGraph, k, result.consensusSeq, solutionColor); } // color the reads colorPath(traversalGraph, k, read1.seq, read1Color); colorPath(traversalGraph, k, reverseComplement(read2.seq), read2Color); // write out the dot file // GraphViz utils don't like colons in graph names std::string graphName = result.readNamePrefix; std::replace(graphName.begin(), graphName.end(), ':', '_'); write_dot(*params.dotStream, traversalGraph, graphName); assert_good(*params.dotStream, params.dotPath); }; template static inline ConnectPairsResult connectPairs( unsigned k, const FastaRecord& read1, const FastaRecord& read2, const Graph& g, 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) std::cerr << "error: name mismatch between paired end reads.\n" << "Read 1: " << read1.id << "\n" << "Read 2: " << read2.id << "\n"; exit(EXIT_FAILURE); } if (read1.seq.length() < k || read2.seq.length() < k) { result.pathResult = NO_PATH; return result; } const unsigned numMatchesThreshold = 3; unsigned startKmerPos = getStartKmerPos(read1, k, FORWARD, g, numMatchesThreshold, params.preserveReads); unsigned goalKmerPos = getStartKmerPos(read2, k, FORWARD, g, numMatchesThreshold, params.preserveReads); const FastaRecord* pRead1 = &read1; const FastaRecord* pRead2 = &read2; FastaRecord correctedRead1; FastaRecord correctedRead2; size_t unused; if (startKmerPos == NO_MATCH && params.fixErrors) { correctedRead1 = read1; if (correctSingleBaseError(g, k, correctedRead1, unused)) { startKmerPos = getStartKmerPos(correctedRead1, k, FORWARD, g, params.kmerMatchesThreshold); assert(startKmerPos != NO_MATCH); pRead1 = &correctedRead1; } } if (goalKmerPos == NO_MATCH && params.fixErrors) { correctedRead2 = read2; if (correctSingleBaseError(g, k, correctedRead2, unused)) { goalKmerPos = getStartKmerPos(correctedRead2, k, FORWARD, g, params.kmerMatchesThreshold); assert(goalKmerPos != NO_MATCH); pRead2 = &correctedRead2; } } if (startKmerPos == NO_MATCH || goalKmerPos == NO_MATCH) { result.pathResult = NO_PATH; return result; } else { result.startKmerPos = startKmerPos; result.foundStartKmer = true; result.goalKmerPos = goalKmerPos; result.foundGoalKmer = true; } Kmer startKmer(pRead1->seq.substr(startKmerPos, k)); Kmer goalKmer(pRead2->seq.substr(goalKmerPos, k)); goalKmer.reverseComplement(); unsigned maxPathLen = params.maxMergedSeqLen - k + 1 - startKmerPos - goalKmerPos; assert(maxPathLen <= params.maxMergedSeqLen - k + 1); unsigned minPathLen = (unsigned)std::max((int)0, (int)(params.minMergedSeqLen - k + 1 - startKmerPos - goalKmerPos)); // do not allow merged seqs that are shorter than the reads minPathLen = std::max(minPathLen, (unsigned)std::max( pRead1->seq.length() - k + 1 - startKmerPos, pRead2->seq.length() - k + 1 - goalKmerPos)); ConstrainedBidiBFSVisitor visitor(g, startKmer, goalKmer, params.maxPaths, minPathLen, maxPathLen, params.maxBranches, params.maxCost, params.memLimit); bidirectionalBFS(g, startKmer, goalKmer, visitor); std::vector< Path > paths; result.pathResult = visitor.pathsToGoal(paths); result.searchCost = visitor.getSearchCost(); result.numNodesVisited = visitor.getNumNodesVisited(); result.maxActiveBranches = visitor.getMaxActiveBranches(); result.maxDepthVisitedForward = visitor.getMaxDepthVisited(FORWARD); result.maxDepthVisitedReverse = visitor.getMaxDepthVisited(REVERSE); result.memUsage = visitor.approxMemUsage(); if (result.pathResult == FOUND_PATH) { /* build sequences for connecting paths */ std::string seqPrefix, seqSuffix; if (params.preserveReads) { seqPrefix = pRead1->seq; seqSuffix = reverseComplement(pRead2->seq); unsigned trimLeft = pRead1->seq.length() - startKmerPos; unsigned trimRight = pRead2->seq.length() - goalKmerPos; for (unsigned i = 0; i < paths.size(); i++) { Sequence connectingSeq = pathToSeq(paths[i]); /* * If the input reads overlap, we must fail because * there's no way to preserve the original read * sequences in the merged read (the reads may disagree * in the region of overlap) */ if (trimLeft + trimRight > connectingSeq.length()) { result.pathResult = NO_PATH; return result; } connectingSeq = connectingSeq.substr(trimLeft, connectingSeq.length() - trimLeft - trimRight); result.connectingSeqs.push_back(connectingSeq); } } else { seqPrefix = pRead1->seq.substr(0, startKmerPos); seqSuffix = reverseComplement(pRead2->seq.substr(0, goalKmerPos)); for (unsigned i = 0; i < paths.size(); i++) result.connectingSeqs.push_back(pathToSeq(paths[i])); } unsigned readPairLength = read1.seq.length() + read2.seq.length(); if (paths.size() == 1) { /* found a unique path between the reads */ FastaRecord mergedSeq; mergedSeq.id = result.readNamePrefix; mergedSeq.seq = seqPrefix + result.connectingSeqs.front() + seqSuffix; result.readMismatches = maskNew(read1, read2, mergedSeq, params.maskBases); result.pathIdentity = 100.0f; result.readIdentity = 100.0f * (float)(readPairLength - result.readMismatches) / readPairLength; result.mergedSeqs.push_back(mergedSeq); result.consensusSeq = mergedSeq; result.consensusConnectingSeq = result.connectingSeqs.front(); } else { /* * multiple paths were found, so build a consensus * sequence using multiple sequence alignment. */ NWAlignment aln; unsigned matches, size; boost::tie(matches, size) = align(result.connectingSeqs, aln); assert(size >= matches); result.pathMismatches = size - matches; result.consensusConnectingSeq = aln.match_align; result.pathIdentity = 100.0f * (float)(result.consensusConnectingSeq.length() - result.pathMismatches) / result.consensusConnectingSeq.length(); result.consensusSeq.id = result.readNamePrefix; result.consensusSeq.seq = seqPrefix + result.consensusConnectingSeq + seqSuffix; result.readMismatches = maskNew(read1, read2, result.consensusSeq, params.maskBases); result.readIdentity = 100.0f * (float)(readPairLength - result.readMismatches) / readPairLength; unsigned i = 1; for (std::vector::iterator it = result.connectingSeqs.begin(); it != result.connectingSeqs.end(); ++it) { FastaRecord mergedSeq; std::ostringstream id; id << result.readNamePrefix << '_' << i++; mergedSeq.id = id.str(); mergedSeq.seq = seqPrefix + *it + seqSuffix; result.mergedSeqs.push_back(mergedSeq); } } assert(result.connectingSeqs.size() == result.mergedSeqs.size()); } /* write traversal graph to dot file (-d option) */ if (!params.dotPath.empty()) { HashGraph traversalGraph; visitor.getTraversalGraph(traversalGraph); writeDot(traversalGraph, k, read1, read2, params, result); } #if 0 # pragma omp critical(cerr) std::cerr << result; #endif 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 static inline bool extendSeqThroughBubble(Sequence& seq, Direction dir, unsigned startKmerPos, unsigned k, const Graph& g, unsigned trimLen=0, bool maskNew=false, bool preserveSeq=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; } std::string headKmer = seq.substr(startKmerPos, k); if (headKmer.find_first_not_of("AGCTagct") != std::string::npos) return false; /* longest branch of Bloom filter false positives */ const unsigned fpTrim = 5; Kmer head(seq.substr(startKmerPos, k)); std::vector buds = trueBranches(head, dir, g, trimLen, fpTrim); /* more than two branches -- not a simple bubble */ if (buds.size() != 2) return false; Path 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); } ExtendPathParams params; params.trimLen = trimLen; params.fpTrim = 5; params.maxLen = k + 2; params.lookBehind = true; extendPath(path1, dir, g, params); extendPath(path2, dir, g, params); /* 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) { if (preserveSeq) { /* * make sure bubble extends beyond end of * original sequence */ assert(startKmerPos + consensus.length() > seq.length()); overlaySeq(consensus.substr(seq.length() - startKmerPos), seq, seq.length(), maskNew); } else { overlaySeq(consensus, seq, startKmerPos, maskNew); } } else { if (preserveSeq) { /* * make sure bubble extends beyond end of * original sequence */ assert(consensus.length() > startKmerPos + k); consensus = consensus.substr(0, consensus.length() - startKmerPos - k); overlaySeq(consensus, seq, -consensus.length(), maskNew); } else { overlaySeq(consensus, seq, -consensus.length() + startKmerPos + k, maskNew); } } return true; } Path seqToPath(const Sequence& seq, unsigned k) { assert(seq.length() >= k); Path 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 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, bool popBubbles=true, bool preserveSeq=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 path; path.push_back(startKmer); PathExtensionResult pathResult = std::make_pair(0, ER_DEAD_END); /* 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)); } ExtendPathParams params; params.trimLen = trimLen; params.fpTrim = 5; params.maxLen = maxPathLen; params.lookBehind = false; pathResult = extendPath(path, FORWARD, g, params); /* * 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::iterator it = path.begin(); it != path.end(); ++it) { if (visited.containsKmer(*it)) { pathResult.second = ER_CYCLE; path.erase(it, path.end()); break; } visited.addKmer(*it); } /* * graft path extension onto original input sequence */ if (path.size() > 0 && pathResult.first > 0) { std::string pathSeq = pathToSeq(path); if (preserveSeq) overlaySeq(pathSeq.substr(k), seq, seq.length(), maskNew); else overlaySeq(pathSeq, seq, seq.length() - k + 1, maskNew); } /* * extend through simple bubbles */ done = true; if (popBubbles && seq.length() < maxLen && pathResult.second == ER_AMBI_OUT) { startKmerPos = startKmerPos + path.size() - 1; assert(startKmerPos < seq.length() - k + 1); if (extendSeqThroughBubble(seq, FORWARD, startKmerPos, k, g, trimLen, maskNew, preserveSeq)) { /* make sure we don't exceed extension limit */ if (seq.length() > maxLen) seq = seq.substr(0, maxLen); /* check for cycle */ for (unsigned i = startKmerPos + 1; 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 (visited.containsKmer(kmer)) { pathResult.second = ER_CYCLE; seq.erase(i); break; } visited.addKmer(kmer); } /* set up for another round of extension */ if (pathResult.second != ER_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.second) { case ER_DEAD_END: if (seq.length() == k) result = ES_DEAD_END; else if (seq.length() > origSeqLen) result = ES_EXTENDED_TO_DEAD_END; else result = ES_INTERNAL_DEAD_END; break; case ER_AMBI_IN: case ER_AMBI_OUT: if (seq.length() == k) result = ES_BRANCHING_POINT; else if (seq.length() > origSeqLen) result = ES_EXTENDED_TO_BRANCHING_POINT; else result = ES_INTERNAL_BRANCHING_POINT; break; case ER_CYCLE: if (seq.length() == k) result = ES_CYCLE; else if (seq.length() > origSeqLen) result = ES_EXTENDED_TO_CYCLE; else result = ES_INTERNAL_CYCLE; break; case ER_LENGTH_LIMIT: if (seq.length() == origSeqLen) { result = ES_LENGTH_LIMIT; } else { assert(seq.length() > origSeqLen); 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; } template static inline bool trimRead(FastqRecord& read, unsigned k, const Graph& g) { Sequence& seq = read.seq; if (seq.size() < k) return false; /* * 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); read.seq = read.seq.substr(maxMatchStart, maxMatchLen + k - 1); if (!read.qual.empty()) read.qual = read.qual.substr(maxMatchStart, maxMatchLen + k - 1); return true; } #endif abyss-2.2.4/LICENSE000066400000000000000000001010161361462241400136470ustar00rootroot00000000000000ABySS Copyright 2016 British Columbia Cancer Agency Branch 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, version 3. 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 . For commercial licensing options, please contact Patrick Rebstein See the file COPYRIGHT for details of the copyright and license of each individual file included with this software. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS abyss-2.2.4/Layout/000077500000000000000000000000001361462241400141205ustar00rootroot00000000000000abyss-2.2.4/Layout/Makefile.am000066400000000000000000000002651361462241400161570ustar00rootroot00000000000000bin_PROGRAMS = abyss-layout abyss_layout_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common abyss_layout_LDADD = $(top_builddir)/Common/libcommon.a abyss_layout_SOURCES = layout.cc abyss-2.2.4/Layout/layout.cc000066400000000000000000000212411361462241400157440ustar00rootroot00000000000000#include "ContigPath.h" #include "ContigProperties.h" #include "Graph/Assemble.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphAlgorithms.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "Uncompress.h" #include "config.h" #include #include #include #include #include #include #include #include using namespace std; using boost::tie; #define PROGRAM "abyss-layout" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2012 Shaun Jackman\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... OVERLAP\n" "Layout contigs using the sequence overlap graph.\n" "Output sequence paths.\n" "\n" " Arguments:\n" "\n" " OVERLAP the sequence overlap graph\n" "\n" " Options:\n" "\n" " -s, --min-length=N minimum sequence length [0]\n" " -m, --min-overlap=N minimum overlap [0]\n" " -k, --kmer=N length of a k-mer\n" " -o, --out=FILE write the paths to FILE\n" " -g, --graph=FILE write the graph to FILE\n" " --tred remove transitive edges\n" " --no-tred do not remove transitive edges [default]\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" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { unsigned k; // used by ContigProperties /** Minimum sequence length. */ static unsigned minLength; /** Minimum overlap. */ static unsigned minOverlap; /** Write the paths to this file. */ static string out; /** Write the graph to this file. */ static string graphPath; /** Remove transitive edges. */ static int tred; /** Run a strand-specific RNA-Seq assembly. */ static int ss; /** Verbose output. */ int verbose; // used by PopBubbles /** Output format */ int format = DOT; } static const char shortopts[] = "g:k:m:o:s:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "graph", required_argument, NULL, 'g' }, { "kmer", required_argument, NULL, 'k' }, { "min-overlap", required_argument, NULL, 'm' }, { "out", required_argument, NULL, 'o' }, { "min-length", required_argument, NULL, 's' }, { "tred", no_argument, &opt::tred, true }, { "no-tred", no_argument, &opt::tred, false }, { "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 }, { NULL, 0, NULL, 0 } }; /** An overlap graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; /** Remove short vertices. */ static void filterVertices(Graph& g, unsigned minLength) { typedef graph_traits GTraits; typedef GTraits::vertex_descriptor V; typedef GTraits::vertex_iterator Vit; if (minLength == 0) return; // Remove short sequences. unsigned numRemoved = 0; std::pair urange = vertices(g); for (Vit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (g[u].length < minLength) clear_vertex(u, g); if (out_degree(u, g) == 0 && in_degree(u, g) == 0) { remove_vertex(u, g); numRemoved++; } } if (opt::verbose > 0) { cerr << "Ignored " << numRemoved << " sequences shorter than " << minLength << " bp.\n"; printGraphStats(cerr, g); } } /** Return true if the edge is a small overlap. */ struct IsSmallOverlap { IsSmallOverlap(Graph& g) : m_g(g) {} bool operator()(graph_traits::edge_descriptor e) const { int maxDistance = -opt::minOverlap; return m_g[e].distance > maxDistance; } const Graph& m_g; }; /** Remove small overlaps. */ static void filterEdges(Graph& g, unsigned minOverlap) { if (minOverlap == 0) return; unsigned numBefore = num_edges(g); remove_edge_if(IsSmallOverlap(g), static_cast(g)); unsigned numRemoved = numBefore - num_edges(g); if (opt::verbose > 0) { cerr << "Removed " << numRemoved << " small overlaps.\n"; printGraphStats(cerr, g); } } /** Read a graph from the specified file. */ static void readGraph(const string& path, Graph& g) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; ifstream fin(path.c_str()); istream& in = path == "-" ? cin : fin; assert_good(in, path); in >> g; assert(in.eof()); if (opt::verbose > 0) printGraphStats(cerr, g); g_contigNames.lock(); } /** Return the length histogram. */ static Histogram buildLengthHistogram(const Graph& g) { typedef graph_traits::vertex_descriptor V; typedef graph_traits::vertex_iterator Vit; Histogram h; Vit uit, ulast; for (tie(uit, ulast) = vertices(g); uit != ulast; ++++uit) { V u = *uit; if (!get(vertex_removed, g, u)) h.insert(g[u].length); } return h; } /** Run abyss-layout. */ 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 'k': arg >> opt::k; break; case 'g': arg >> opt::graphPath; break; case 'm': arg >> opt::minOverlap; break; case 'o': arg >> opt::out; break; case 's': arg >> opt::minLength; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } Graph g; if (optind < argc) { for (; optind < argc; optind++) readGraph(argv[optind], g); } else readGraph("-", g); // Remove short sequences. filterVertices(g, opt::minLength); // Remove small overlaps. filterEdges(g, opt::minOverlap); // Remove transitive edges. if (opt::tred) { unsigned numTransitive = remove_transitive_edges(g); if (opt::verbose > 0) { cerr << "Removed " << numTransitive << " transitive edges.\n"; printGraphStats(cerr, g); } } /** A container of contig paths. */ typedef vector ContigPaths; // Assemble the paths. ContigPaths paths; assembleDFS(g, back_inserter(paths), opt::ss); sort(paths.begin(), paths.end()); if (opt::verbose > 0) { unsigned n = 0; for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) n += it->size(); cerr << "Assembled " << n << " sequences in " << paths.size() << " contigs.\n"; printGraphStats(cerr, g); } // Output the paths. ofstream fout(opt::out.c_str()); ostream& out = opt::out.empty() || opt::out == "-" ? cout : fout; assert_good(out, opt::out); g_contigNames.unlock(); for (vector::const_iterator it = paths.begin(); it != paths.end(); ++it) out << createContigName() << '\t' << *it << '\n'; assert_good(out, opt::out); // Create the new vertices. for (vector::const_iterator it = paths.begin(); it != paths.end(); ++it) { const ContigPath& path = *it; merge(g, path.begin(), path.end()); remove_vertex_if( g, path.begin(), path.end(), [](const ContigNode& c) { return !c.ambiguous(); }); } if (opt::verbose > 0) printGraphStats(cerr, g); // Output the graph. if (!opt::graphPath.empty()) { ofstream out(opt::graphPath.c_str()); assert_good(out, opt::graphPath); write_dot(out, g); assert_good(out, opt::graphPath); } // Print assembly contiguity statistics. if (opt::verbose > 0) { Histogram h = buildLengthHistogram(g); const unsigned STATS_MIN_LENGTH = 200; // bp printContiguityStats(cerr, h, STATS_MIN_LENGTH) << '\n'; } return 0; } abyss-2.2.4/LogKmerCount/000077500000000000000000000000001361462241400152145ustar00rootroot00000000000000abyss-2.2.4/LogKmerCount/CountingBloomFilter.h000066400000000000000000000056221361462241400213170ustar00rootroot00000000000000/** * A counting Bloom filter * Copyright 2014 bcgsc */ #ifndef COUNTINGBLOOMFILTER_H #define COUNTINGBLOOMFILTER_H 1 #include "Bloom/Bloom.h" #include #include #include /** A counting Bloom filter. */ template class CountingBloomFilter { public: /** Constructor */ CountingBloomFilter(unsigned hashnum = 1) : m_data(0), hashNum(hashnum), uniqueEntries(0), replicateEntries(0) { } /** Constructor */ CountingBloomFilter(size_t n, unsigned hashnum = 1) : m_data(n), hashNum(hashnum), uniqueEntries(0), replicateEntries(0) { } /** Destructor */ virtual ~CountingBloomFilter() {} /** Return the size (in discrete elements) of the bit array. */ size_t size() const { return m_data.size(); } /** Return the number of elements with count >= MAX_COUNT. */ size_t popcount() const { return uniqueEntries; } /** Return the estimated false positive rate */ double FPR() const { return pow(1.0 - pow(1.0 - 1.0 / double(m_data.size()), double(uniqueEntries) * hashNum), double(hashNum)); } /** Return the count of the single element (debugging purposes) */ NumericType operator[](size_t i) const { return m_data[i]; } /** Return the count of this element. */ NumericType operator[](const Bloom::key_type& key) const { NumericType currentMin = m_data[Bloom::hash(key, 0) % m_data.size()]; for (unsigned int i = 1; i < hashNum; ++i) { NumericType min = m_data[Bloom::hash(key, i) % m_data.size()]; if (min < currentMin) { currentMin = min; } if (0 == currentMin) { break; } } return currentMin; } /** Add the object with the specified index (debugging purposes). */ void insert(size_t index) { ++m_data[index]; } /** Add the object to this counting multiset. * If all values are the same update all * If some values are larger only update smallest counts*/ void insert(const Bloom::key_type& key) { //check for which elements to update NumericType minEle = (*this)[key]; //update only those elements for (unsigned int i = 1; i < hashNum; ++i) { size_t hashVal = Bloom::hash(key, i) % m_data.size(); NumericType val = m_data[hashVal]; if (minEle == val) { insert(hashVal); } } if (minEle) ++uniqueEntries; else ++replicateEntries; } void write(std::ostream& out) const { assert(!m_data.empty()); out.write(reinterpret_cast(&m_data), sizeof(NumericType)); } //TODO: need to implement tracking of directionality void loadSeq(unsigned k, const std::string& seq) { if (seq.size() < k) return; for (size_t i = 0; i < seq.size() - k + 1; ++i) { std::string kmer = seq.substr(i, k); size_t pos = kmer.find_last_not_of("ACGTacgt"); if (pos == std::string::npos) { insert(Kmer(kmer)); } else i += pos; } } protected: std::vector m_data; unsigned hashNum; size_t uniqueEntries; size_t replicateEntries; }; #endif abyss-2.2.4/LogKmerCount/Makefile.am000066400000000000000000000006011361462241400172450ustar00rootroot00000000000000bin_PROGRAMS = logcounter logcounter_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer logcounter_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) logcounter_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Align/libalign.a \ $(top_builddir)/Common/libcommon.a logcounter_SOURCES = logcounter.cc \ CountingBloomFilter.h \ plc.h abyss-2.2.4/LogKmerCount/logcounter.cc000066400000000000000000000110041361462241400177000ustar00rootroot00000000000000/** * logarithmic k-mer count based on a Bloom filter * Copyright 2014 BCGSC */ #include "config.h" #include "plc.h" #include "CountingBloomFilter.h" #include "Common/IOUtil.h" #include "Common/Options.h" #include "Common/StringUtil.h" #include "DataLayer/Options.h" #include #include #include #include #if _OPENMP # include #endif using namespace std; #define PROGRAM "logcounter" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by ?.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Science Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [READS]...\n" " -j, --threads=N use N parallel threads [1]\n" " -k, --kmer=N the size of a k-mer\n" " -s, --seed=N the seed value used\n" " -b, --bloom-size=N size of bloom filter [500M]\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" " -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" " -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 { /** The number of parallel threads. */ static unsigned threads = 1; /** The size of the bloom filter in bytes. */ size_t bloomSize = 500 * 1024 * 1024; /** The size of a k-mer. */ unsigned k; /** The seed value to use for random number gen **/ unsigned s; // /** Prefix for output files */ // static string outputPrefix; } ///** Counters */ //static struct { //} g_count; static const char shortopts[] = "j:k:s:q:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "bloom-size", required_argument, NULL, 'b' }, { "threads", required_argument, NULL, 'j' }, { "kmer", required_argument, NULL, 'k' }, { "seed", required_argument, NULL, 's' }, { "chastity", no_argument, &opt::chastityFilter, 1 }, { "no-chastity", no_argument, &opt::chastityFilter, 0 }, { "trim-masked", no_argument, &opt::trimMasked, 1 }, { "no-trim-masked", no_argument, &opt::trimMasked, 0 }, { "trim-quality", required_argument, NULL, 'q' }, { "standard-quality", no_argument, &opt::qualityOffset, 33 }, { "illumina-quality", no_argument, &opt::qualityOffset, 64 }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; 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 'b': opt::bloomSize = SIToBytes(arg); break; case 'j': arg >> opt::threads; break; case 'k': arg >> opt::k; break; case 's': arg >> opt::s; break; case 'q': arg >> opt::qualityThreshold; 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::k == 0) { cerr << PROGRAM ": missing mandatory option `-k'\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 //set seed srand (opt::s); Kmer::setLength(opt::k); assert(opt::bloomSize > 0); //size determined by CountingBloomFilter bloom(opt::bloomSize, 1); for (int i = optind; i < argc; i++) Bloom::loadFile(bloom, opt::k, string(argv[i]), opt::verbose); return 0; } abyss-2.2.4/LogKmerCount/plc.h000066400000000000000000000022171361462241400161450ustar00rootroot00000000000000/** * A minifloat like datatype for probablistic log counts (PLC) of elements * Unsigned generic implementation * Mantissa = 3 bits * Exponent = 5 bits * Copyright 2014 bcgsc */ #include #include #include #include using namespace std; static const unsigned mantissa = 3; static const uint8_t mantiMask = 0xFF >> (8 - mantissa); static const uint8_t addMask = 0x80 >> (7 - mantissa); class plc { public: plc() { m_val = 0; } void operator++() { //from 0-1 if (m_val <= mantiMask) { ++m_val; } else { //this shifts the first bit off and creates the value //need to get the correct transition probability size_t shiftVal = 1 << ((m_val >> mantissa) - 1); if (rand() % shiftVal == 0) { ++m_val; } } } bool operator==(plc val) { return val.rawValue() == m_val; } operator bool() { return m_val; } float toFloat() { if (m_val <= mantiMask) return float(m_val); return ldexp((m_val & mantiMask) | addMask, (m_val >> mantissa) - 1); } /* * return raw value of byte use to store value */ uint8_t rawValue() { return m_val; } private: uint8_t m_val; }; abyss-2.2.4/LogKmerCount/plc_strand.h000066400000000000000000000027571361462241400175310ustar00rootroot00000000000000/** * A minifloat like datatype for probablistic log counts (PLC) of elements * Contains unique functionalities for minimizing collision * Mantissa = 3 bits * Exponent = 4 bits * ControlBit = 1 bits * Copyright 2014 bcgsc */ static const uint8_t numericBitMask = 0x7F; static const unsigned mantissa = 3; static const uint8_t mantiMask = 0xFF >> (8 - mantissa); static const uint8_t addMask = 0x80 >> (7 - mantissa); class plc { public: plc() { m_val = 0; } void operator++() { //extract numeric section of plc uint8_t maskedVal = m_val & numericBitMask; //check if at max value if (maskedVal == numericBitMask) { return; } if (maskedVal <= mantissa) { ++m_val; } else { //this shifts the first bit off and creates the value //need to get the correct transition probability unsigned shiftVal = 1 << ((maskedVal >> mantissa) - 1); if (rand() % shiftVal == 0) { ++maskedVal; } } } bool operator==(plc val) { return val.rawValue() & numericBitMask == m_val & numericBitMask; } operator bool() { return m_val & numericBitMask; } float toFloat() { //extract numeric section of plc uint8_t maskedVal = m_val & numericBitMask; if (maskedVal <= mantissa) return float(maskedVal); return ldexp((maskedVal & mantiMask) | addMask, (maskedVal >> mantissa) - 1); } /* * return raw value of byte use to store value */ uint8_t rawValue() { return m_val; } void setStrandBit() { m_val &= 0x80; } private: uint8_t m_val; }; abyss-2.2.4/Makefile.am000066400000000000000000000042031361462241400146760ustar00rootroot00000000000000if HAVE_LIBMPI Parallel=Parallel endif if HAVE_PTHREAD GTest=vendor/gtest-1.7.0 UnitTest=Unittest endif dist_doc_DATA = \ ChangeLog \ CITATION.bib CITATION.md \ COPYRIGHT \ LICENSE \ README.md if HAVE_PANDOC dist_doc_DATA += README.html endif EXTRA_DIST=autogen.sh doxygen.conf SUBDIRS = \ bin \ doc \ Common \ Graph \ DataLayer \ DataBase \ FMIndex \ Assembly \ dialign \ Align \ ABYSS $(Parallel) \ Bloom \ BloomDBG \ Konnector \ Consensus \ DAssembler \ DistanceEst \ KAligner \ Layout \ LogKmerCount \ Map \ MergePaths \ Overlap \ PairedDBG \ ParseAligns \ PathOverlap \ PopBubbles \ Scaffold \ SimpleGraph \ kmerprint \ FilterGraph \ GapFiller \ Sealer \ AdjList \ vendor \ vendor/nthash \ $(GTest) \ $(UnitTest) %.html: $(srcdir)/%.md -pandoc -s -o $@ $< clean-local: rm -f README.html clang-format: for i in Bloom/RollingBloomDBGVisitor.h Bloom/bloom.cc BloomDBG/BloomIO.h \ BloomDBG/Checkpoint.h BloomDBG/HashAgnosticCascadingBloom.h BloomDBG/bloom-dbg.* \ ABYSS/abyss.cc Assembly/BranchGroup.h FMIndex/BitArrays.h FilterGraph/FilterGraph.cc \ Graph/ContigGraphAlgorithms.h KAligner/Aligner.h KAligner/PipeMux.h Layout/layout.cc \ MergePaths/MergeContigs.cpp MergePaths/MergePaths.cpp ParseAligns/ParseAligns.cpp \ ParseAligns/abyss-fixmate.cc PathOverlap/PathOverlap.cpp PopBubbles/PopBubbles.cpp Scaffold/scaffold.cc \ Unittest/BloomDBG/HashAgnosticCascadingBloomTest.cpp; do clang-format -style=file $$i >$$i.fixed; done for i in Bloom/RollingBloomDBGVisitor.h Bloom/bloom.cc BloomDBG/BloomIO.h \ BloomDBG/Checkpoint.h BloomDBG/HashAgnosticCascadingBloom.h BloomDBG/bloom-dbg.* \ ABYSS/abyss.cc Assembly/BranchGroup.h FMIndex/BitArrays.h FilterGraph/FilterGraph.cc \ Graph/ContigGraphAlgorithms.h KAligner/Aligner.h KAligner/PipeMux.h Layout/layout.cc \ MergePaths/MergeContigs.cpp MergePaths/MergePaths.cpp ParseAligns/ParseAligns.cpp \ ParseAligns/abyss-fixmate.cc PathOverlap/PathOverlap.cpp PopBubbles/PopBubbles.cpp Scaffold/scaffold.cc \ Unittest/BloomDBG/HashAgnosticCascadingBloomTest.cpp; do diff -su $$i $$i.fixed && rm -f $$i.fixed; done if ls *.fixed; then exit 1; fi abyss-2.2.4/Map/000077500000000000000000000000001361462241400133605ustar00rootroot00000000000000abyss-2.2.4/Map/Makefile.am000066400000000000000000000024631361462241400154210ustar00rootroot00000000000000bin_PROGRAMS = abyss-index abyss-map abyss-map-ssq abyss-overlap abyss_index_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -I$(top_srcdir)/FMIndex abyss_index_LDADD = \ $(top_builddir)/FMIndex/libfmindex.a \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a abyss_index_SOURCES = index.cc abyss_map_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -I$(top_srcdir)/FMIndex 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)/DataBase/libdb.a \ $(SQLITE_LIBS) abyss_map_SOURCES = map.cc abyss_map_ssq_CPPFLAGS = $(abyss_map_CPPFLAGS) \ -D SAM_SEQ_QUAL=1 abyss_map_ssq_CXXFLAGS = $(abyss_map_CXXFLAGS) abyss_map_ssq_LDADD = $(abyss_map_LDADD) abyss_map_ssq_SOURCES = $(abyss_map_SOURCES) abyss_overlap_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -I$(top_srcdir)/FMIndex abyss_overlap_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_overlap_LDADD = \ $(top_builddir)/FMIndex/libfmindex.a \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a abyss_overlap_SOURCES = overlap.cc abyss-2.2.4/Map/index.cc000066400000000000000000000174361361462241400150110ustar00rootroot00000000000000#include "config.h" #include "BitUtil.h" #include "FastaIndex.h" #include "FMIndex.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "StringUtil.h" #include "Uncompress.h" #include #include // for toupper #include #include #include #include #include #include using namespace std; #define PROGRAM "abyss-index" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... FILE\n" "Build an FM-index of FILE and store it in FILE.fm.\n" "\n" " Options:\n" "\n" " --both build both FAI and FM indexes [default]\n" " --fai build a FAI index\n" " --fm build a FM index\n" " --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" " -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 { /** Sample the suffix array. */ static unsigned sampleSA = 16; /** Which indexes to create. */ enum { NONE, FAI, FM, BOTH }; static int indexes = BOTH; /** Build the BWT directly without the SA. */ static int fa2bwt; /** Build the FM index from the BWT. */ static int bwt2fm; /** The alphabet. */ static string alphabet = "-ACGT"; /** Decompress the index. */ static bool decompress; /** Write output to standard output. */ static bool toStdout; /** Verbose output. */ static int verbose; } static const char shortopts[] = "a:cds:v"; enum { OPT_HELP = 1, OPT_VERSION, OPT_ALPHA, OPT_DNA, OPT_PROTEIN }; static const struct option longopts[] = { { "both", no_argument, &opt::indexes, opt::BOTH }, { "fai", no_argument, &opt::indexes, opt::FAI }, { "fm", no_argument, &opt::indexes, opt::FM }, { "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' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Index the specified FASTA file. */ static void indexFasta(const string& faPath, const string& faiPath) { cerr << "Reading `" << faPath << "'...\n"; FastaIndex fai; fai.index(faPath); if (opt::verbose > 0) cerr << "Read " << fai.size() << " contigs.\n"; cerr << "Writing `" << faiPath << "'...\n"; ofstream out(faiPath.c_str()); assert_good(out, faiPath); out << fai; out.flush(); assert_good(out, faiPath); } /** Build the FM index from the BWT. */ static void buildFMIndexFromBWT(FMIndex& fm, const string& path) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; std::vector bwt; readFile(path.c_str(), bwt); assert(bwt.size() > 1); if (opt::alphabet.empty()) { fm.setAlphabet(bwt.begin(), bwt.end()); std::cerr << "The alphabet has " << fm.alphabetSize() << " symbols.\n"; } else fm.setAlphabet(opt::alphabet); fm.encode(bwt.begin(), bwt.end()); fm.sampleSA(opt::sampleSA); fm.assignBWT(bwt.begin(), bwt.end()); } /** Build an FM index of the specified file. */ static void buildFMIndex(FMIndex& fm, const string& path) { if (opt::verbose > 0) std::cerr << "Reading `" << path << "'...\n"; std::vector s; readFile(path.c_str(), s); uint64_t MAX_SIZE = numeric_limits::max(); if (s.size() > MAX_SIZE) { std::cerr << PROGRAM << ": `" << path << "', " << toSI(s.size()) << "B, must be smaller than " << toSI(MAX_SIZE) << "B\n"; exit(EXIT_FAILURE); } // Set the alphabet. transform(s.begin(), s.end(), s.begin(), ::toupper); if (opt::alphabet.empty()) { fm.setAlphabet(s.begin(), s.end()); std::cerr << "The alphabet has " << fm.alphabetSize() << " symbols.\n"; } else fm.setAlphabet(opt::alphabet); if (opt::fa2bwt) { // Build the BWT first. s.push_back(0); fm.buildBWT(s.begin(), s.end() - 1); fm.sampleSA(opt::sampleSA); fm.assignBWT(s.begin(), s.end()); } else { // Construct the suffix array first. fm.assign(s.begin(), s.end()); fm.sampleSA(opt::sampleSA); } } 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 'a': 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; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (argc - optind > 1) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (opt::decompress) { // Decompress the index. string fmPath(argv[optind]); if (fmPath.size() < 4 || !equal(fmPath.end() - 3, fmPath.end(), ".fm")) fmPath.append(".fm"); string faPath(fmPath, 0, fmPath.size() - 3); ifstream in(fmPath.c_str()); assert_good(in, fmPath); FMIndex fmIndex; in >> fmIndex; assert_good(in, fmPath); in.close(); ofstream fout; if (!opt::toStdout) fout.open(faPath.c_str()); ostream& out = opt::toStdout ? cout : fout; assert_good(out, faPath); fmIndex.decompress( ostream_iterator(out, "")); out.flush(); assert_good(out, faPath); in.open((faPath + ".fai").c_str()); FastaIndex faIndex; if (in) { in >> faIndex; faIndex.writeFASTAHeaders(out); } return 0; } string path = argv[optind]; FMIndex fm; if (opt::bwt2fm) { buildFMIndexFromBWT(fm, path); } else { if (opt::indexes & opt::FAI) indexFasta(path, path + ".fai"); if ((opt::indexes & opt::FM) == 0) return 0; buildFMIndex(fm, path); } if (opt::verbose > 0) { size_t n = fm.size(); ssize_t bytes = getMemoryUsage(); cerr << "Read " << toSI(n) << "B. " "Used " << toSI(bytes) << "B of memory and " << setprecision(3) << (float)bytes / n << " B/bp.\n"; } string fmPath = opt::toStdout ? "-" : path + ".fm"; cerr << "Writing `" << fmPath << "'...\n"; ofstream fout; if (!opt::toStdout) fout.open(fmPath.c_str()); ostream& out = opt::toStdout ? cout : fout; assert_good(out, fmPath); out << fm; out.flush(); assert_good(out, fmPath); return 0; } abyss-2.2.4/Map/map.cc000066400000000000000000000502141361462241400144460ustar00rootroot00000000000000#include "BitUtil.h" #include "DataLayer/Options.h" #include "FMIndex.h" #include "FastaIndex.h" #include "FastaInterleave.h" #include "FastaReader.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "SAM.h" #include "StringUtil.h" #include "Uncompress.h" #include #include #include #include #include // for toupper #include #include #include #include #include #include #if _OPENMP # include #endif #include "DataBase/Options.h" #include "DataBase/DB.h" using namespace std; using namespace boost; 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" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... QUERY... TARGET\n" "Map the sequences of the files QUERY to those of the file TARGET.\n" "The index files TARGET.fai and TARGET.fm will be used if present.\n" "\n" " Options:\n" "\n" " -l, --min-align=N find matches at least N bp [1]\n" " -j, --threads=N use N parallel threads [1]\n" " -C, --append-comment append the FASTA/FASTQ comment to the SAM tags\n" " -s, --sample=N sample the suffix array [1]\n" " -d, --dup identify and print duplicate sequence\n" " IDs between QUERY and TARGET\n" " --order print alignments in the same order as\n" " read from QUERY\n" " --no-order print alignments ASAP [default]\n" " --multi Align unaligned segments of primary\n" " alignment\n" " --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; /** Append the FASTA/FASTQ comment to the SAM tags. */ static int appendComment; /** Sample the suffix array. */ static unsigned sampleSA; /** The number of parallel threads. */ static unsigned threads = 1; /** 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; /** Align unaligned segments of primary alignment. */ static int multi; /** Ensure output order matches input order. */ static int order; /** Verbose output. */ static int verbose; } // for sqlite params static bool haveDbParam(false); static const char shortopts[] = "Cj:k:l:s:dv"; 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[] = { { "append-comment", no_argument, NULL, 'C' }, { "sample", required_argument, NULL, 's' }, { "min-align", required_argument, NULL, 'l' }, { "dup", no_argument, NULL, 'd' }, { "threads", required_argument, NULL, 'j' }, { "order", no_argument, &opt::order, 1 }, { "no-order", no_argument, &opt::order, 0 }, { "multi", no_argument, &opt::multi, 1 }, { "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 } }; /** Counts. */ static struct { unsigned unique; unsigned multimapped; unsigned unmapped; unsigned suboptimal; unsigned subunmapped; } g_count; typedef FMIndex::Match Match; #if SAM_SEQ_QUAL static string toXA(const FastaIndex& faIndex, const FMIndex& fmIndex, const Match& m, bool rc, unsigned qlength, unsigned seq_start) { if (m.size() == 0) return ""; FastaIndex::SeqPos seqPos = faIndex[fmIndex[m.l]]; string rname = seqPos.get<0>().id; int pos = seqPos.get<1>() + 1; // Set the mapq to the alignment score. assert(m.qstart < m.qend); unsigned matches = m.qend - m.qstart; unsigned qstart = seq_start + m.qstart; unsigned qend = m.qend + seq_start; unsigned short flag = rc ? SAMAlignment::FREVERSE : 0; ostringstream ss; if (qstart > 0) ss << qstart << 'S'; ss << matches << 'M'; if (qend < qlength) ss << qlength - qend << 'S'; string cigar = ss.str(); stringstream xa_tag; xa_tag << rname << ',' << pos << ',' << cigar << ",0," << flag; return xa_tag.str(); } #endif /** Return a SAM record of the specified match. */ static SAMRecord toSAM(const FastaIndex& faIndex, const FMIndex& fmIndex, const Match& m, bool rc, unsigned qlength) { SAMRecord a; if (m.size() == 0) { // No hit. a.rname = "*"; a.pos = -1; a.flag = SAMAlignment::FUNMAP; a.mapq = 0; a.cigar = "*"; } else { FastaIndex::SeqPos seqPos = faIndex[fmIndex[m.l]]; a.rname = seqPos.get<0>().id; a.pos = seqPos.get<1>(); a.flag = rc ? SAMAlignment::FREVERSE : 0; // Set the mapq to the alignment score. assert(m.qstart < m.qend); unsigned matches = m.qend - m.qstart; assert (m.num != 0); a.mapq = m.size() > 1 || m.num > 1 ? 0 : min(matches, 254U); ostringstream ss; if (m.qstart > 0) ss << m.qstart << 'S'; ss << matches << 'M'; if (m.qend < qlength) ss << qlength - m.qend << 'S'; a.cigar = ss.str(); } a.mrnm = "*"; a.mpos = -1; a.isize = 0; return a; } /** Return the position of the current contig. */ static size_t getMyPos(const Match& m, const FastaIndex& faIndex, const FMIndex& fmIndex, const string& id) { for (size_t i = m.l; i < m.u; i++) { if (faIndex[fmIndex[i]].get<0>().id == id) return fmIndex[i]; } return fmIndex[m.l]; } /** Return the earlies position of all contigs in m. */ static size_t getMinPos(const Match& m, size_t maxLen, const FastaIndex& faIndex, const FMIndex& fmIndex) { size_t minPos = numeric_limits::max(); for (size_t i = m.l; i < m.u; i++) { size_t pos = fmIndex[i]; if (faIndex[pos].get<0>().size == maxLen && pos < minPos) minPos = fmIndex[i]; } return minPos; } /** Return the largest length of all contig in m. */ static size_t getMaxLen(const Match& m, const FastaIndex& faIndex, const FMIndex& fmIndex) { size_t maxLen = 0; for (size_t i = m.l; i < m.u; i++) { size_t len = faIndex[fmIndex[i]].get<0>().size; if (len > maxLen) maxLen = len; } return maxLen; } /** Print the current contig id if it is not the lartest and earliest * contig in m. */ static void printDuplicates(const Match& m, const Match& rcm, const FastaIndex& faIndex, const FMIndex& fmIndex, const FastqRecord& rec) { size_t myLen = m.qspan(); size_t maxLen; if (opt::ss || opt::norc) maxLen = getMaxLen(m, faIndex, fmIndex); else maxLen = max(getMaxLen(m, faIndex, fmIndex), getMaxLen(rcm, faIndex, fmIndex)); if (myLen < maxLen) { #pragma omp atomic g_count.multimapped++; #pragma omp critical(cout) { cout << rec.id << '\n'; assert_good(cout, "stdout"); } return; } size_t myPos = getMyPos(m, faIndex, fmIndex, rec.id); size_t minPos; if (opt::ss || opt::norc) minPos = getMinPos(m, maxLen, faIndex, fmIndex); else minPos = min(getMinPos(m, maxLen, faIndex, fmIndex), getMinPos(rcm, maxLen, faIndex, fmIndex)); if (myPos > minPos) { #pragma omp atomic g_count.multimapped++; #pragma omp critical(cout) { cout << rec.id << '\n'; assert_good(cout, "stdout"); } } #pragma omp atomic g_count.unique++; return; } pair 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; if (opt::ss) rcm = fmIndex.find(rcqseq, opt::dup ? rcqseq.length() : opt::k); else rcm = fmIndex.find(rcqseq, opt::dup ? rcqseq.length() : m.qspan()); return make_pair(m, rcm); } static queue g_pq; /** Return the mapping of the specified sequence. */ static void find(const FastaIndex& faIndex, const FMIndex& fmIndex, const FastqRecord& rec) { if (rec.seq.empty()) { cerr << PROGRAM ": error: " "the sequence `" << rec.id << "' is empty\n"; exit(EXIT_FAILURE); } Match m, rcm; tie(m, rcm) = findMatch(fmIndex, rec.seq); if (opt::dup) { printDuplicates(m, rcm, faIndex, fmIndex, rec); return; } bool rc; if (opt::ss) { rc = rec.id.size() > 2 && rec.id.substr(rec.id.size()-2) == "/1"; bool prc = rcm.qspan() > m.qspan(); if (prc != rc && ((rc && rcm.size() > 0) || (!rc && m.size() > 0))) #pragma omp atomic g_count.suboptimal++; if (prc != rc && ((rc && rcm.size() == 0 && m.size() > 0) || (!rc && m.size() == 0 && rcm.size() > 0))) #pragma omp atomic g_count.subunmapped++; } else { rc = rcm.qspan() > m.qspan(); // if both matches are the same length, sum up the number of times // each were seen. if (rcm.qspan() == m.qspan()) rc ? rcm.num += m.num : m.num += rcm.num; } vector alts; Match mm = rc ? rcm : m; string mseq = rc ? reverseComplement(rec.seq) : rec.seq; #if SAM_SEQ_QUAL if (opt::multi) { if (mm.qstart > 0) { string seq = mseq.substr(0, mm.qstart); Match m1, rcm1; tie(m1, rcm1) = findMatch(fmIndex, seq); bool rc1 = rcm1.qspan() > m1.qspan(); string xa = toXA(faIndex, fmIndex, rc1 ? rcm1 : m1, rc ^ rc1, mseq.size(), 0); if (xa != "") alts.push_back(xa); } if (mm.qend < mseq.size()) { string seq = mseq.substr(mm.qend, mseq.length() - mm.qend); Match m2, rcm2; tie(m2, rcm2) = findMatch(fmIndex, seq); bool rc2 = rcm2.qspan() > m2.qspan(); string xa = toXA(faIndex, fmIndex, rc2 ? rcm2 : m2, rc ^ rc2, mseq.size(), mm.qend); if (xa != "") alts.push_back(xa); } } #endif SAMRecord sam = toSAM(faIndex, fmIndex, mm, rc, rec.seq.size()); if (rec.id[0] == '@') { cerr << PROGRAM ": error: " "the query ID `" << rec.id << "' is invalid since it " "begins with `@'\n"; exit(EXIT_FAILURE); } sam.qname = rec.id; #if SAM_SEQ_QUAL sam.seq = mseq; sam.qual = rec.qual.empty() ? "*" : rec.qual; if (rc) reverse(sam.qual.begin(), sam.qual.end()); #endif bool print = opt::order == 0; do { #pragma omp critical(cout) { #pragma omp critical(g_pq) if (!print) { print = g_pq.front() == rec.id; if (print) g_pq.pop(); } if (print) { cout << sam; if (opt::appendComment && !rec.comment.empty()) { // Output the FASTQ comment, which should be formatted as SAM tags. cout << '\t' << rec.comment; } else if (startsWith(rec.comment, "BX:Z:")) { // Output the BX tag if it's the first tag. size_t i = rec.comment.find_first_of("\t "); if (i == string::npos) i = rec.comment.size(); cout << '\t'; cout.write(rec.comment.data(), i); } #if SAM_SEQ_QUAL if (alts.size() > 0) cout << "\tXA:Z:" << join(alts, ";"); #endif cout << '\n'; assert_good(cout, "stdout"); } } } while (!print); // spinlock :( if (sam.isUnmapped()) #pragma omp atomic g_count.unmapped++; else if (sam.mapq == 0) #pragma omp atomic g_count.multimapped++; else #pragma omp atomic g_count.unique++; } /** Map the sequences of the specified file. */ static void find(const FastaIndex& faIndex, const FMIndex& fmIndex, FastaInterleave& in) { #pragma omp parallel for (FastqRecord rec;;) { bool good; #pragma omp critical(in) { good = in >> rec; if (opt::order) { #pragma omp critical(g_pq) g_pq.push(rec.id); } } if (good) find(faIndex, fmIndex, rec); else break; } assert(in.eof()); } /** Build an FM index of the specified file. */ static void buildFMIndex(FMIndex& fm, const char* path) { if (opt::verbose > 0) std::cerr << "Reading `" << path << "'...\n"; std::vector s; readFile(path, s); uint64_t MAX_SIZE = numeric_limits::max(); if (s.size() > MAX_SIZE) { std::cerr << PROGRAM << ": `" << path << "', " << toSI(s.size()) << "B, must be smaller than " << toSI(MAX_SIZE) << "B\n"; exit(EXIT_FAILURE); } transform(s.begin(), s.end(), s.begin(), ::toupper); fm.setAlphabet(opt::alphabet); fm.assign(s.begin(), s.end()); } /** Return the size of the specified file. */ static streampos fileSize(const string& path) { std::ifstream in(path.c_str()); assert_good(in, path); in.seekg(0, std::ios::end); assert_good(in, path); return in.tellg(); } /** Check that the indexes are up to date. */ static void checkIndexes(const string& path, const FMIndex& fmIndex, const FastaIndex& faIndex) { size_t fastaFileSize = fileSize(path); if (fmIndex.size() != fastaFileSize) { cerr << PROGRAM ": `" << path << "': " "The size of the FM-index, " << fmIndex.size() << " B, does not match the size of the FASTA file, " << fastaFileSize << " B. The index is likely stale.\n"; exit(EXIT_FAILURE); } if (faIndex.fileSize() != fastaFileSize) { cerr << PROGRAM ": `" << path << "': " "The size of the FASTA index, " << faIndex.fileSize() << " B, does not match the size of the FASTA file, " << fastaFileSize << " B. The index is likely stale.\n"; exit(EXIT_FAILURE); } } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'C': opt::appendComment = 1; break; case 'j': arg >> opt::threads; break; case 'k': case 'l': arg >> opt::k; 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; exit(EXIT_SUCCESS); 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } #ifndef SAM_SEQ_QUAL # define SAM_SEQ_QUAL 0 #endif if (opt::multi && !SAM_SEQ_QUAL) { cerr << PROGRAM ": multiple alignments not supported with " "this install. Recompile ABySS with `./configure " "--enable-samseqqual'.\n"; die = true; } if (argc - optind < 2) { cerr << PROGRAM ": missing 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 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"; string fmPath(ss.str()); ss.str(""); ss << targetFile << ".fai"; string faiPath(ss.str()); ifstream in; // Read the FASTA index. FastaIndex faIndex; in.open(faiPath.c_str()); if (in) { if (opt::verbose > 0) cerr << "Reading `" << faiPath << "'...\n"; in >> faIndex; assert(in.eof()); in.close(); } else { if (opt::verbose > 0) cerr << "Reading `" << targetFile << "'...\n"; faIndex.index(targetFile); } if (opt::verbose > 0) { ssize_t bytes = getMemoryUsage(); if (bytes > 0) cerr << "Using " << toSI(bytes) << "B of memory and " << setprecision(3) << (float)bytes / faIndex.size() << " B/sequence.\n"; } // Read the FM index. FMIndex fmIndex; in.open(fmPath.c_str()); if (in) { if (opt::verbose > 0) cerr << "Reading `" << fmPath << "'...\n"; assert_good(in, fmPath); in >> fmIndex; assert_good(in, fmPath); in.close(); } else buildFMIndex(fmIndex, targetFile); if (opt::sampleSA > 1) fmIndex.sampleSA(opt::sampleSA); if (opt::verbose > 0) { size_t bp = fmIndex.size(); cerr << "Read " << toSI(bp) << "B in " << faIndex.size() << " contigs.\n"; ssize_t bytes = getMemoryUsage(); if (bytes > 0) cerr << "Using " << toSI(bytes) << "B of memory and " << 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); if (!opt::dup) { // Write the SAM header. cout << "@HD\tVN:1.4\n" "@PG\tID:" PROGRAM "\tPN:" PROGRAM "\tVN:" VERSION "\t" "CL:" << commandLine << '\n'; faIndex.writeSAMHeader(cout); cout.flush(); assert_good(cout, "stdout"); } else if (opt::verbose > 0) cerr << "Identifying duplicates.\n"; FastaInterleave fa(argv + optind, argv + argc, FastaReader::FOLD_CASE); find(faIndex, fmIndex, fa); if (opt::verbose > 0) { size_t unique = g_count.unique; size_t mapped = unique + g_count.multimapped; size_t total = mapped + g_count.unmapped; cerr << "Mapped " << mapped << " of " << total << " reads (" << (float)100 * mapped / total << "%)\n" << "Mapped " << unique << " of " << total << " reads uniquely (" << (float)100 * unique / total << "%)\n"; // 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(); assert_good(cout, "stdout"); return 0; } abyss-2.2.4/Map/overlap.cc000066400000000000000000000321761361462241400153500ustar00rootroot00000000000000#if __APPLE_CC__ /* Work around a bug in i686-apple-darwin11-llvm-gcc 4.2.1 * Undefined symbols for architecture x86_64: * "___builtin_expect", referenced from: */ #define NDEBUG 1 #endif #include "BitUtil.h" #include "ContigProperties.h" #include "DataLayer/Options.h" #include "FMIndex.h" #include "FastaIndex.h" #include "FastaReader.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "SAM.h" #include "StringUtil.h" #include "Uncompress.h" #include "Graph/ContigGraph.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphAlgorithms.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include #include #include // for toupper #include #include #include #include #include #include #include #if _OPENMP # include #endif using namespace std; #define PROGRAM "abyss-overlap" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... FILE\n" "Find overlaps of [m,k) bases. Sequences are read from FILE.\n" "Output is written to standard output. The index files FILE.fai\n" "and FILE.fm will be used if present.\n" "\n" " Options:\n" "\n" " -m, --min=N find matches at least N bp [50]\n" " -k, --max=N find matches less than N bp [inf]\n" " -j, --threads=N use N parallel threads [1]\n" " -s, --sample=N sample the suffix array [1]\n" " --tred remove transitive edges [default]\n" " --no-tred do not remove transitive edges\n" " --adj output the results in adj format\n" " --dot output the results in dot format [default]\n" " --sam output the results 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" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { /** Find matches at least k bp. */ static unsigned minOverlap = 50; /** Find matches less than k bp. */ static unsigned maxOverlap = UINT_MAX; /** Sample the suffix array. */ static unsigned sampleSA; /** Run a strand-specific overlaping algorithm. */ static int ss; /** Remove transitive edges. */ static int tred = true; /** The number of parallel threads. */ static unsigned threads = 1; /** Verbose output. */ static int verbose; unsigned k; // used by GraphIO int format = DOT; // used by GraphIO } static const char shortopts[] = "j:k:m:s:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "adj", no_argument, &opt::format, ADJ }, { "dot", no_argument, &opt::format, DOT }, { "sam", no_argument, &opt::format, SAM }, { "help", no_argument, NULL, OPT_HELP }, { "max", required_argument, NULL, 'k' }, { "min", required_argument, NULL, 'm' }, { "sample", required_argument, NULL, 's' }, { "threads", required_argument, NULL, 'j' }, { "SS", no_argument, &opt::ss, 1 }, { "no-SS", no_argument, &opt::ss, 0 }, { "tred", no_argument, &opt::tred, true }, { "no-tred", no_argument, &opt::tred, false }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** The overlap graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; typedef FMIndex::Match Match; /** Add suffix overlaps to the graph. */ static void addSuffixOverlaps(Graph &g, const FastaIndex& faIndex, const FMIndex& fmIndex, const ContigNode& u, const Match& fmi) { typedef edge_property::type EP; typedef graph_traits::edge_descriptor E; typedef graph_traits::vertex_descriptor V; Distance ep(-fmi.qspan()); assert(ep.distance < 0); for (unsigned i = fmi.l; i < fmi.u; ++i) { size_t toffset = fmIndex[i] + 1; FastaIndex::SeqPos seqPos = faIndex[toffset]; const FAIRecord& tseq = seqPos.get<0>(); size_t tstart = seqPos.get<1>(); size_t tend = tstart + fmi.qspan(); assert(tend <= tseq.size); (void)tend; if (tstart > 0) { // This match is due to an ambiguity code in the target sequence. continue; } V v = find_vertex(tseq.id, false, g); #pragma omp critical(g) { pair e = edge(u, v, g); if (e.second) { const EP& ep0 = g[e.first]; if (opt::verbose > 1) cerr << "duplicate edge: " << get(edge_name, g, e.first) << ' ' << ep0 << ' ' << ep << '\n'; assert(ep0.distance < ep.distance); } else if(u.sense()) { // Add u- -> v+ add_edge(u, v, ep, static_cast(g)); } else { // Add u+ -> v+ and v- -> u- add_edge(u, v, ep, g); } } } } /** Add prefix overlaps to the graph. */ static void addPrefixOverlaps(Graph &g, const FastaIndex& faIndex, const FMIndex& fmIndex, const ContigNode& v, const Match& fmi) { typedef edge_property::type EP; typedef graph_traits::edge_descriptor E; typedef graph_traits::vertex_descriptor V; assert(v.sense()); assert(fmi.qstart == 0); Distance ep(-fmi.qspan()); assert(ep.distance < 0); for (unsigned i = fmi.l; i < fmi.u; ++i) { size_t toffset = fmIndex[i]; FastaIndex::SeqPos seqPos = faIndex[toffset]; const FAIRecord& tseq = seqPos.get<0>(); size_t tstart = seqPos.get<1>(); size_t tend = tstart + fmi.qspan(); assert(tend <= tseq.size); if (tend < tseq.size) { // This match is due to an ambiguity code in the target sequence. continue; } V u = find_vertex(tseq.id, false, g); #pragma omp critical(g) { pair e = edge(u, v, g); if (e.second) { const EP& ep0 = g[e.first]; if (opt::verbose > 1) cerr << "duplicate edge: " << get(edge_name, g, e.first) << ' ' << ep0 << ' ' << ep << '\n'; assert(ep0.distance < ep.distance); } else { // Add u+ -> v- add_edge(u, v, ep, static_cast(g)); } } } } /** Find suffix overlaps. */ static void findOverlapsSuffix(Graph &g, const FastaIndex& faIndex, const FMIndex& fmIndex, const ContigNode& u, const string& seq) { size_t pos = seq.size() > opt::maxOverlap ? seq.size() - opt::maxOverlap + 1 : 1; string suffix(seq, pos); typedef vector Matches; Matches matches; fmIndex.findOverlapSuffix(suffix, back_inserter(matches), opt::minOverlap); for (Matches::reverse_iterator it = matches.rbegin(); !(it == matches.rend()); ++it) addSuffixOverlaps(g, faIndex, fmIndex, u, *it); } /** Find prefix overlaps. */ static void findOverlapsPrefix(Graph &g, const FastaIndex& faIndex, const FMIndex& fmIndex, const ContigNode& v, const string& seq) { assert(v.sense()); string prefix(seq, 0, min((size_t)opt::maxOverlap, seq.size()) - 1); typedef vector Matches; Matches matches; fmIndex.findOverlapPrefix(prefix, back_inserter(matches), opt::minOverlap); for (Matches::reverse_iterator it = matches.rbegin(); !(it == matches.rend()); ++it) addPrefixOverlaps(g, faIndex, fmIndex, v, *it); } static void findOverlaps(Graph& g, const FastaIndex& faIndex, const FMIndex& fmIndex, const FastqRecord& rec) { typedef graph_traits::vertex_descriptor V; V u = find_vertex(rec.id, false, g); V uc = get(vertex_complement, g, u); // Add edges u+ -> v+ and v- -> u- findOverlapsSuffix(g, faIndex, fmIndex, u, rec.seq); if (!opt::ss) { string rcseq = reverseComplement(rec.seq); // Add edges u- -> v+ findOverlapsSuffix(g, faIndex, fmIndex, uc, rcseq); // Add edges v+ -> u- findOverlapsPrefix(g, faIndex, fmIndex, uc, rcseq); } } /** Map the sequences of the specified file. */ static void findOverlaps(Graph& g, const FastaIndex& faIndex, const FMIndex& fmIndex, FastaReader& in) { #pragma omp parallel for (FastqRecord rec;;) { bool good; #pragma omp critical(in) good = in >> rec; if (good) findOverlaps(g, faIndex, fmIndex, rec); else break; } assert(in.eof()); } /** Build an FM index of the specified file. */ static void buildFMIndex(FMIndex& fm, const char* path) { if (opt::verbose > 0) std::cerr << "Reading `" << path << "'...\n"; std::vector s; readFile(path, s); uint64_t MAX_SIZE = numeric_limits::max(); if (s.size() > MAX_SIZE) { std::cerr << PROGRAM << ": `" << path << "', " << toSI(s.size()) << "B, must be smaller than " << toSI(MAX_SIZE) << "B\n"; exit(EXIT_FAILURE); } transform(s.begin(), s.end(), s.begin(), ::toupper); fm.setAlphabet("-ACGT"); fm.assign(s.begin(), s.end()); } /** Read contigs and add vertices to the graph. */ static void addVertices(const string& path, Graph& g) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; ifstream in(path.c_str()); assert_good(in, path); in >> g; g_contigNames.lock(); assert(in.eof()); } /** Return the size of the specified file. */ static streampos fileSize(const string& path) { std::ifstream in(path.c_str()); assert_good(in, path); in.seekg(0, std::ios::end); assert_good(in, path); return in.tellg(); } /** Check that the indexes are up to date. */ static void checkIndexes(const string& path, const FMIndex& fmIndex, const FastaIndex& faIndex) { size_t fastaFileSize = fileSize(path); if (fmIndex.size() != fastaFileSize) { cerr << PROGRAM ": `" << path << "': " "The size of the FM-index, " << fmIndex.size() << " B, does not match the size of the FASTA file, " << fastaFileSize << " B. The index is likely stale.\n"; exit(EXIT_FAILURE); } if (faIndex.fileSize() != fastaFileSize) { cerr << PROGRAM ": `" << path << "': " "The size of the FASTA index, " << faIndex.fileSize() << " B, does not match the size of the FASTA file, " << fastaFileSize << " B. The index is likely stale.\n"; exit(EXIT_FAILURE); } } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } 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 'j': arg >> opt::threads; break; case 'm': arg >> opt::minOverlap; break; case 'k': arg >> opt::maxOverlap; break; case 's': arg >> opt::sampleSA; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 1) { cerr << PROGRAM ": too many 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 if (opt::minOverlap == 0) opt::minOverlap = opt::maxOverlap - 1; opt::minOverlap = min(opt::minOverlap, opt::maxOverlap - 1); if (opt::maxOverlap != UINT_MAX) opt::k = opt::maxOverlap; const char* fastaFile(argv[--argc]); ostringstream ss; ss << fastaFile << ".fm"; string fmPath(ss.str()); ss.str(""); ss << fastaFile << ".fai"; string faiPath(ss.str()); ifstream in; // Read the FASTA index. FastaIndex faIndex; in.open(faiPath.c_str()); if (in) { if (opt::verbose > 0) cerr << "Reading `" << faiPath << "'...\n"; in >> faIndex; assert(in.eof()); in.close(); } else { if (opt::verbose > 0) cerr << "Reading `" << fastaFile << "'...\n"; faIndex.index(fastaFile); } // Read the FM index. FMIndex fmIndex; in.open(fmPath.c_str()); if (in) { if (opt::verbose > 0) cerr << "Reading `" << fmPath << "'...\n"; assert_good(in, fmPath); in >> fmIndex; assert_good(in, fmPath); in.close(); } else buildFMIndex(fmIndex, fastaFile); if (opt::sampleSA > 1) fmIndex.sampleSA(opt::sampleSA); if (opt::verbose > 0) { size_t bp = fmIndex.size(); cerr << "Read " << toSI(bp) << "B in " << faIndex.size() << " contigs.\n"; ssize_t bytes = getMemoryUsage(); if (bytes > 0) cerr << "Using " << toSI(bytes) << "B of memory and " << setprecision(3) << (float)bytes / bp << " B/bp.\n"; } // Check that the indexes are up to date. checkIndexes(fastaFile, fmIndex, faIndex); opt::chastityFilter = false; opt::trimMasked = false; Graph g; addVertices(fastaFile, g); FastaReader fa(fastaFile, FastaReader::FOLD_CASE); findOverlaps(g, faIndex, fmIndex, fa); if (opt::verbose > 0) printGraphStats(cerr, g); // Remove transitive edges. if (opt::tred) { unsigned numTransitive = remove_transitive_edges(g); if (opt::verbose > 0) { cerr << "Removed " << numTransitive << " transitive edges.\n"; printGraphStats(cerr, g); } } write_graph(cout, g, PROGRAM, commandLine); cout.flush(); assert_good(cout, "stdout"); return 0; } abyss-2.2.4/MergePaths/000077500000000000000000000000001361462241400147025ustar00rootroot00000000000000abyss-2.2.4/MergePaths/Makefile.am000066400000000000000000000022461361462241400167420ustar00rootroot00000000000000bin_PROGRAMS = MergePaths MergeContigs PathConsensus MergePaths_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer 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 MergePaths_SOURCES = \ MergePaths.cpp MergeContigs_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Align \ -I$(top_srcdir)/Common \ -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 MergeContigs_SOURCES = MergeContigs.cpp PathConsensus_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Align \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer \ -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 \ $(top_builddir)/dialign/libdialign.a PathConsensus_SOURCES = \ PathConsensus.cpp abyss-2.2.4/MergePaths/MergeContigs.cpp000066400000000000000000000453531361462241400200060ustar00rootroot00000000000000#include "Common/Options.h" #include "ContigNode.h" #include "ContigPath.h" #include "ContigProperties.h" #include "DataBase/DB.h" #include "DataBase/Options.h" #include "DataLayer/Options.h" #include "Dictionary.h" #include "FastaReader.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "Graph/Options.h" #include "Histogram.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "Sequence.h" #include "StringUtil.h" #include "Uncompress.h" #include "config.h" #include "smith_waterman.h" #include #include #include #include #include #include #include using namespace std; #define PROGRAM "MergeContigs" DB db; static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -o [OPTION]... FASTA [OVERLAP] PATH\n" "Merge paths of contigs to create larger contigs.\n" "\n" " Arguments:\n" "\n" " FASTA contigs in FASTA format\n" " OVERLAP contig overlap graph\n" " PATH sequences of contig IDs\n" "\n" " Options:\n" "\n" " -k, --kmer=KMER_SIZE k-mer size\n" " -o, --out=FILE output the merged contigs to FILE [stdout]\n" " -g, --graph=FILE write the contig overlap graph to FILE\n" " --merged output only merged contigs\n" " --adj output the graph in adj format\n" " --dot output the graph in dot format [default]\n" " --dot-meancov same as above but give the mean coverage\n" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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" " --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 = "-"; /** Output graph path. */ static string graphPath; /** Output graph format. */ int format = DOT; /** Output only merged contigs. */ int onlyMerged; /** Minimum overlap. */ static unsigned minOverlap = 20; /** Minimum alignment identity. */ static float minIdentity = 0.9; } static const char shortopts[] = "g:k:o:v"; 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 }, { "dot", no_argument, &opt::format, DOT }, { "dot-meancov", no_argument, &opt::format, DOT_MEANCOV }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "sam", no_argument, &opt::format, SAM }, { "graph", required_argument, NULL, 'g' }, { "kmer", required_argument, NULL, 'k' }, { "merged", no_argument, &opt::onlyMerged, 1 }, { "out", required_argument, NULL, 'o' }, { "path", required_argument, NULL, 'p' }, { "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 } }; /* A contig sequence. */ struct Contig { Contig(const string& comment, const string& seq) : comment(comment) , seq(seq) {} Contig(const FastaRecord& o) : comment(o.comment) , seq(o.seq) {} string comment; string seq; }; /** The contig sequences. */ typedef vector Contigs; /** Return the sequence of the specified contig node. The sequence * may be ambiguous or reverse complemented. */ static Sequence sequence(const Contigs& contigs, const ContigNode& id) { if (id.ambiguous()) { string s(id.ambiguousSequence()); if (s.length() < opt::k) transform(s.begin(), s.end(), s.begin(), ::tolower); return string(opt::k - 1, 'N') + s; } else { const Sequence& seq = contigs[id.id()].seq; return id.sense() ? reverseComplement(seq) : seq; } } /** Return a consensus sequence of a and b. * @return an empty string if a consensus could not be found */ static string createConsensus(const Sequence& a, const Sequence& b) { assert(a.length() == b.length()); if (a == b) return a; string s; s.reserve(a.length()); for (string::const_iterator ita = a.begin(), itb = b.begin(); ita != a.end(); ++ita, ++itb) { bool mask = islower(*ita) || islower(*itb); char ca = toupper(*ita), cb = toupper(*itb); char c = ca == cb ? ca : ca == 'N' ? cb : cb == 'N' ? ca : ambiguityIsSubset(ca, cb) ? ambiguityOr(ca, cb) : 'x'; if (c == 'x') return string(""); s += mask ? tolower(c) : c; } return s; } typedef ContigGraph> Graph; typedef graph_traits::vertex_descriptor vertex_descriptor; /** Return the properties of the specified vertex, unless u is * ambiguous, in which case return the length of the ambiguous * sequence. */ static inline ContigProperties get(vertex_bundle_t, const Graph& g, ContigNode u) { return u.ambiguous() ? ContigProperties(u.length() + opt::k - 1, 0) : g[u]; } /** Append the sequence of contig v to seq. */ static void mergeContigs( const Graph& g, const Contigs& contigs, vertex_descriptor u, vertex_descriptor v, Sequence& seq, const ContigPath& path) { int d = get(edge_bundle, g, u, v).distance; assert(d < 0); unsigned overlap = -d; const Sequence& s = sequence(contigs, v); assert(s.length() >= overlap); Sequence ao; Sequence bo(s, 0, overlap); Sequence o; do { assert(seq.length() >= overlap); ao = seq.substr(seq.length() - overlap); o = createConsensus(ao, bo); if (!o.empty()) { seq.resize(seq.length() - overlap); seq += o; seq += Sequence(s, overlap); return; } } while (chomp(seq, 'n')); // Try an overlap alignment. if (opt::verbose > 2) cerr << '\n'; vector overlaps; alignOverlap(ao, bo, 0, overlaps, false, opt::verbose > 2); bool good = false; if (!overlaps.empty()) { assert(overlaps.size() == 1); const overlap_align& o = overlaps.front(); unsigned matches = o.overlap_match; const string& consensus = o.overlap_str; float identity = (float)matches / consensus.size(); good = matches >= opt::minOverlap && identity >= opt::minIdentity; if (opt::verbose > 2) cerr << matches << " / " << consensus.size() << " = " << identity << (matches < opt::minOverlap ? " (too few)" : identity < opt::minIdentity ? " (too low)" : " (good)") << '\n'; } if (good) { assert(overlaps.size() == 1); const overlap_align& o = overlaps.front(); seq.erase(seq.length() - overlap + o.overlap_t_pos); seq += o.overlap_str; seq += Sequence(s, o.overlap_h_pos + 1); } else { cerr << "warning: the head of " << get(vertex_name, g, v) << " does not match the tail of the previous contig\n" << ao << '\n' << bo << '\n' << path << endl; seq += 'n'; seq += s; } } /** Return a FASTA comment for the specified path. */ static void pathToComment(ostream& out, const Graph& g, const ContigPath& path) { out << get(vertex_name, g, path.front()); if (path.size() == 1) return; else if (path.size() == 3) out << ',' << get(vertex_name, g, path[1]); else if (path.size() > 3) out << ",..."; out << ',' << get(vertex_name, g, path.back()); } /** Merge the specified path. */ static Contig mergePath(const Graph& g, const Contigs& contigs, const ContigPath& path) { Sequence seq; unsigned coverage = 0; for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) { if (!it->ambiguous()) coverage += g[*it].coverage; if (seq.empty()) { seq = sequence(contigs, *it); } else { assert(it != path.begin()); mergeContigs(g, contigs, *(it - 1), *it, seq, path); } } ostringstream ss; ss << seq.size() << ' ' << coverage << ' '; pathToComment(ss, g, path); return Contig(ss.str(), seq); } /** A container of ContigPath. */ typedef vector ContigPaths; /** Read contig paths from the specified file. * @param ids [out] the string ID of the paths */ static ContigPaths readPaths(const string& inPath, vector* ids = NULL) { if (ids != NULL) assert(ids->empty()); ifstream fin(inPath.c_str()); if (opt::verbose > 0) cerr << "Reading `" << inPath << "'..." << endl; if (inPath != "-") assert_good(fin, inPath); istream& in = inPath == "-" ? cin : fin; unsigned count = 0; ContigPaths paths; string id; ContigPath path; while (in >> id >> path) { paths.push_back(path); if (ids != NULL) ids->push_back(id); ++count; if (opt::verbose > 1 && count % 1000000 == 0) cerr << "Read " << count << " paths. " "Using " << toSI(getMemoryUsage()) << "B of memory.\n"; } 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; } /** Finds all contigs used in each path in paths, and * marks them as seen in the vector seen. */ static void seenContigs(vector& seen, const ContigPaths& paths) { for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) for (ContigPath::const_iterator itc = it->begin(); itc != it->end(); ++itc) if (itc->id() < seen.size()) seen[itc->id()] = true; } /** Mark contigs for removal. An empty path indicates that a contig * should be removed. */ static void markRemovedContigs(vector& marked, const vector& pathIDs, const ContigPaths& paths) { for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { if (it->empty()) { size_t i = get(g_contigNames, pathIDs[it - paths.begin()]); assert(i < marked.size()); marked[i] = true; } } } /** Output the updated overlap graph. */ static void outputGraph( Graph& g, const vector& pathIDs, const ContigPaths& paths, const string& commandLine) { typedef graph_traits::vertex_descriptor V; // Add the path vertices. g_contigNames.unlock(); for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { const ContigPath& path = *it; const string& id = pathIDs[it - paths.begin()]; if (!path.empty()) { V u = merge(g, path.begin(), path.end()); put(vertex_name, g, u, id); } } g_contigNames.lock(); // Remove the vertices that are used in paths. for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { const ContigPath& path = *it; const string& id = pathIDs[it - paths.begin()]; if (path.empty()) { remove_vertex(find_vertex(id, false, g), g); } else { remove_vertex_if( g, path.begin(), path.end(), [](const ContigNode& c) { return !c.ambiguous(); }); } } // Output the graph. const string& graphPath = opt::graphPath; assert(!graphPath.empty()); if (opt::verbose > 0) cerr << "Writing `" << graphPath << "'..." << endl; ofstream fout(graphPath.c_str()); assert_good(fout, graphPath); write_graph(fout, g, PROGRAM, commandLine); assert_good(fout, graphPath); if (opt::verbose > 0) printGraphStats(cerr, g); } int main(int argc, char** argv) { opt::trimMasked = false; string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'g': arg >> opt::graphPath; break; case 'k': arg >> opt::k; break; case 'o': arg >> opt::out; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (opt::out.empty()) { cerr << PROGRAM ": " << "missing -o,--out option\n"; die = true; } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (argc - optind > 3) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --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); } const char* contigFile = argv[optind++]; string adjPath, mergedPathFile; Graph g; if (argc - optind > 1) { adjPath = string(argv[optind++]); // Read the contig adjacency graph. if (opt::verbose > 0) cerr << "Reading `" << adjPath << "'..." << endl; ifstream fin(adjPath.c_str()); assert_good(fin, adjPath); fin >> g; assert(fin.eof()); if (opt::verbose > 0) 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++]); // Read the contig sequence. Contigs contigs; { if (opt::verbose > 0) cerr << "Reading `" << contigFile << "'..." << endl; unsigned count = 0; FastaReader in(contigFile, FastaReader::NO_FOLD_CASE); for (FastaRecord rec; in >> rec;) { if (!adjPath.empty() && g_contigNames.count(rec.id) == 0) continue; if (adjPath.empty()) { graph_traits::vertex_descriptor u = add_vertex(ContigProperties(rec.seq.length(), 0), g); put(vertex_name, g, u, rec.id); } assert(get(g_contigNames, rec.id) == contigs.size()); contigs.push_back(rec); ++count; if (opt::verbose > 1 && count % 1000000 == 0) cerr << "Read " << count << " sequences. " "Using " << toSI(getMemoryUsage()) << "B of memory.\n"; } if (opt::verbose > 0) 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]); g_contigNames.lock(); } vector pathIDs; ContigPaths paths = readPaths(mergedPathFile, &pathIDs); // Record all the contigs that are in a path. vector seen(contigs.size()); seenContigs(seen, paths); markRemovedContigs(seen, pathIDs, paths); // Output those contigs that were not seen in a path. Histogram lengthHistogram; ofstream fout; ostream& out = opt::out == "-" ? cout : (fout.open(opt::out.c_str()), fout); assert_good(out, opt::out); if (!opt::onlyMerged) { for (Contigs::const_iterator it = contigs.begin(); it != contigs.end(); ++it) { ContigID id(it - contigs.begin()); if (!seen[id]) { const Contig& contig = *it; out << '>' << get(g_contigNames, id); if (!contig.comment.empty()) out << ' ' << contig.comment; out << '\n' << contig.seq << '\n'; if (opt::verbose > 0) lengthHistogram.insert(count_if(contig.seq.begin(), contig.seq.end(), isACGT)); } } } unsigned npaths = 0; for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { const ContigPath& path = *it; if (path.empty()) continue; Contig contig = mergePath(g, contigs, path); out << '>' << pathIDs[it - paths.begin()] << ' ' << contig.comment << '\n' << contig.seq << '\n'; assert_good(out, opt::out); npaths++; if (opt::verbose > 0) lengthHistogram.insert(count_if(contig.seq.begin(), contig.seq.end(), isACGT)); } if (!opt::graphPath.empty()) outputGraph(g, pathIDs, paths, commandLine); if (npaths == 0) return 0; float minCov = numeric_limits::infinity(), minCovUsed = numeric_limits::infinity(); for (unsigned i = 0; i < contigs.size(); i++) { ContigProperties vp = g[ContigNode(i, false)]; if (vp.coverage == 0 || vp.length < opt::k) continue; float cov = (float)vp.coverage / (vp.length - opt::k + 1); minCov = min(minCov, cov); if (seen[i]) minCovUsed = min(minCovUsed, cov); } cerr << "The minimum coverage of single-end contigs is " << minCov << ".\n" << "The minimum coverage of merged contigs is " << minCovUsed << ".\n"; if (minCov < minCovUsed) cerr << "Consider increasing the coverage threshold " "parameter, c, to " << minCovUsed << ".\n"; if (opt::verbose > 0) { const unsigned STATS_MIN_LENGTH = 200; // bp printContiguityStats(cerr, lengthHistogram, STATS_MIN_LENGTH) << '\t' << opt::out << '\n'; } return 0; } abyss-2.2.4/MergePaths/MergePaths.cpp000066400000000000000000001301111361462241400174420ustar00rootroot00000000000000#include "Common/Options.h" #include "ContigID.h" #include "ContigPath.h" #include "Functional.h" // for mem_var #include "Graph/Assemble.h" #include "Graph/ContigGraph.h" #include "Graph/DirectedGraph.h" #include "Graph/DotIO.h" #include "Graph/GraphAlgorithms.h" #include "Graph/GraphUtil.h" #include "IOUtil.h" #include "Uncompress.h" #include "config.h" #include #include #include #include // for UINT_MAX #include #include #include #include #include #include #include #include #include #include #include #if _OPENMP #include #endif #include "DataBase/DB.h" #include "DataBase/Options.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" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... LEN PATH\n" "Merge sequences of contigs IDs.\n" "\n" " Arguments:\n" "\n" " LEN lengths of the contigs\n" " PATH sequences of contig IDs\n" "\n" " Options:\n" "\n" " -k, --kmer=KMER_SIZE k-mer size\n" " -s, --seed-length=L minimum length of a seed contig [0]\n" " -G, --genome-size=N expected genome size. Used to calculate NG50\n" " and associated stats [disabled]\n" " -o, --out=FILE write result to FILE\n" " --no-greedy use the non-greedy algorithm [default]\n" " --greedy use the greedy algorithm\n" " -g, --graph=FILE write the path overlap graph to FILE\n" " -j, --threads=N use N parallel threads [1]\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 static string out; static int threads = 1; /** Minimum length of a seed contig. */ static unsigned seedLen; /** Use a greedy algorithm. */ static int greedy; /** Genome size. Used to calculate NG50. */ static long long unsigned genomeSize; /** Write the path overlap graph to this file. */ static string graphPath; } static const char shortopts[] = "G:g:j:k:o:s:v"; 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[] = { { "genome-size", required_argument, NULL, 'G' }, { "graph", no_argument, NULL, 'g' }, { "greedy", no_argument, &opt::greedy, true }, { "no-greedy", no_argument, &opt::greedy, false }, { "kmer", required_argument, NULL, 'k' }, { "out", required_argument, NULL, 'o' }, { "seed-length", required_argument, NULL, 's' }, { "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 } }; typedef map ContigPathMap; /** Orientation of an edge. */ enum dir_type { DIR_X, // u--v none DIR_F, // u->v forward DIR_R, // u<-v reverse DIR_B, // u<>v both }; /** Lengths of contigs measured in k-mer. */ typedef vector Lengths; static ContigPath align(const Lengths& lengths, const ContigPath& p1, const ContigPath& p2, ContigNode pivot); static ContigPath align( const Lengths& lengths, const ContigPath& p1, const ContigPath& p2, ContigNode pivot, dir_type& orientation); static bool gDebugPrint; /** * Build a histogram of the lengths of the assembled paths and unused contigs. * Note: This function does not account for the ammount of overlap between contigs. */ static Histogram buildAssembledLengthHistogram(const Lengths& lengths, const ContigPaths& paths) { Histogram h; // Compute the lengths of the paths // Mark the vertices that are used in paths vector used(lengths.size()); for (ContigPaths::const_iterator pathIt = paths.begin(); pathIt != paths.end(); ++pathIt) { const ContigPath& path = *pathIt; size_t totalLength = 0; for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) { if (it->ambiguous()) continue; unsigned id = it->id(); assert(id < lengths.size()); totalLength += lengths[id]; used[id] = true; } h.insert(totalLength); } // Add the contigs that were not used in paths. for (unsigned i = 0; i < lengths.size(); ++i) { if (!used[i]) h.insert(lengths[i]); } return h; } /** Report assembly metrics. */ static void reportAssemblyMetrics(const Lengths& lengths, const ContigPaths& paths) { Histogram h = buildAssembledLengthHistogram(lengths, paths); const unsigned STATS_MIN_LENGTH = opt::seedLen; printContiguityStats(cerr, h, STATS_MIN_LENGTH, true, "\t", opt::genomeSize) << '\t' << opt::out << '\n'; } /** Return all contigs that are tandem repeats, identified as those * contigs that appear more than once in a single path. */ static set findRepeats(const ContigPathMap& paths) { set repeats; for (ContigPathMap::const_iterator pathIt = paths.begin(); pathIt != paths.end(); ++pathIt) { const ContigPath& path = pathIt->second; map count; for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) if (!it->ambiguous()) count[it->contigIndex()]++; for (map::const_iterator it = count.begin(); it != count.end(); ++it) if (it->second > 1) repeats.insert(it->first); } return repeats; } /** Remove tandem repeats from the set of paths. * @return the removed paths */ static set removeRepeats(ContigPathMap& paths) { set repeats = findRepeats(paths); if (gDebugPrint) { cout << "Repeats:"; if (!repeats.empty()) { for (set::const_iterator it = repeats.begin(); it != repeats.end(); ++it) cout << ' ' << get(g_contigNames, *it); } else cout << " none"; cout << '\n'; } unsigned removed = 0; for (set::const_iterator it = repeats.begin(); it != repeats.end(); ++it) if (paths.count(*it) > 0) removed++; if (removed == paths.size()) { // Every path was identified as a repeat. It's most likely a // cyclic sequence. Don't remove anything. repeats.clear(); return repeats; } ostringstream ss; for (set::const_iterator it = repeats.begin(); it != repeats.end(); ++it) if (paths.erase(*it) > 0) ss << ' ' << get(g_contigNames, *it); if (opt::verbose > 0 && removed > 0) cout << "Removing paths in repeats:" << ss.str() << '\n'; return repeats; } static void appendToMergeQ(deque& mergeQ, set& seen, const ContigPath& path) { for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) if (!it->ambiguous() && seen.insert(*it).second) mergeQ.push_back(*it); } /** A path overlap graph. */ typedef ContigGraph> PathGraph; /** Add an edge if the two paths overlap. * @param pivot the pivot at which to seed the alignment * @return whether an overlap was found */ static bool addOverlapEdge( const Lengths& lengths, PathGraph& gout, ContigNode pivot, ContigNode seed1, const ContigPath& path1, ContigNode seed2, const ContigPath& path2) { assert(seed1 != seed2); // Determine the orientation of the overlap edge. dir_type orientation = DIR_X; ContigPath consensus = align(lengths, path1, path2, pivot, orientation); if (consensus.empty()) return false; assert(orientation != DIR_X); if (orientation == DIR_B) { // One of the paths subsumes the other. Use the order of the // seeds to determine the orientation of the edge. orientation = find(consensus.begin(), consensus.end(), seed1) < find(consensus.begin(), consensus.end(), seed2) ? DIR_F : DIR_R; } assert(orientation == DIR_F || orientation == DIR_R); // Add the edge. ContigNode u = orientation == DIR_F ? seed1 : seed2; ContigNode v = orientation == DIR_F ? seed2 : seed1; bool added = false; #pragma omp critical(gout) if (!edge(u, v, gout).second) { add_edge(u, v, gout); added = true; } return added; } /** Return the specified path. */ static ContigPath getPath(const ContigPathMap& paths, ContigNode u) { ContigPathMap::const_iterator it = paths.find(u.contigIndex()); assert(it != paths.end()); ContigPath path = it->second; if (u.sense()) reverseComplement(path.begin(), path.end()); return path; } /** Find the overlaps between paths and add edges to the graph. */ static void findPathOverlaps( const Lengths& lengths, const ContigPathMap& paths, const ContigNode& seed1, const ContigPath& path1, PathGraph& gout) { for (ContigPath::const_iterator it = path1.begin(); it != path1.end(); ++it) { ContigNode seed2 = *it; if (seed1 == seed2) continue; if (seed2.ambiguous()) continue; ContigPathMap::const_iterator path2It = paths.find(seed2.contigIndex()); if (path2It == paths.end()) continue; ContigPath path2 = path2It->second; if (seed2.sense()) reverseComplement(path2.begin(), path2.end()); addOverlapEdge(lengths, gout, seed2, seed1, path1, seed2, path2); } } /** Attempt to merge the paths specified in mergeQ with path. * @return the number of paths merged */ static unsigned mergePaths( const Lengths& lengths, ContigPath& path, deque& mergeQ, set& seen, const ContigPathMap& paths) { unsigned merged = 0; deque invalid; for (ContigNode pivot; !mergeQ.empty(); mergeQ.pop_front()) { pivot = mergeQ.front(); ContigPathMap::const_iterator path2It = paths.find(pivot.contigIndex()); if (path2It == paths.end()) continue; ContigPath path2 = path2It->second; if (pivot.sense()) reverseComplement(path2.begin(), path2.end()); ContigPath consensus = align(lengths, path, path2, pivot); if (consensus.empty()) { invalid.push_back(pivot); continue; } appendToMergeQ(mergeQ, seen, path2); path.swap(consensus); if (gDebugPrint) #pragma omp critical(cout) cout << get(g_contigNames, pivot) << '\t' << path2 << '\n' << '\t' << path << '\n'; merged++; } mergeQ.swap(invalid); return merged; } /** Merge the paths of the specified seed path. * @return the merged contig path */ static ContigPath mergePath(const Lengths& lengths, const ContigPathMap& paths, const ContigPath& seedPath) { assert(!seedPath.empty()); ContigNode seed1 = seedPath.front(); ContigPathMap::const_iterator path1It = paths.find(seed1.contigIndex()); assert(path1It != paths.end()); ContigPath path(path1It->second); if (seedPath.front().sense()) reverseComplement(path.begin(), path.end()); if (opt::verbose > 1) #pragma omp critical(cout) cout << "\n* " << seedPath << '\n' << get(g_contigNames, seedPath.front()) << '\t' << path << '\n'; for (ContigPath::const_iterator it = seedPath.begin() + 1; it != seedPath.end(); ++it) { ContigNode seed2 = *it; ContigPathMap::const_iterator path2It = paths.find(seed2.contigIndex()); assert(path2It != paths.end()); ContigPath path2 = path2It->second; if (seed2.sense()) reverseComplement(path2.begin(), path2.end()); ContigNode pivot = find(path.begin(), path.end(), seed2) != path.end() ? seed2 : seed1; ContigPath consensus = align(lengths, path, path2, pivot); if (consensus.empty()) { // This seed could be removed from the seed path. if (opt::verbose > 1) #pragma omp critical(cout) cout << get(g_contigNames, seed2) << '\t' << path2 << '\n' << "\tinvalid\n"; } else { path.swap(consensus); if (opt::verbose > 1) #pragma omp critical(cout) cout << get(g_contigNames, seed2) << '\t' << path2 << '\n' << '\t' << path << '\n'; } seed1 = seed2; } return path; } /** A collection of contig paths. */ typedef vector ContigPaths; /** Merge the specified seed paths. * @return the merged contig paths */ static ContigPaths mergeSeedPaths(const Lengths& lengths, const ContigPathMap& paths, const ContigPaths& seedPaths) { if (opt::verbose > 0) cout << "\nMerging paths\n"; ContigPaths out; out.reserve(seedPaths.size()); for (ContigPaths::const_iterator it = seedPaths.begin(); it != seedPaths.end(); ++it) out.push_back(mergePath(lengths, paths, *it)); return out; } /** Extend the specified path as long as is unambiguously possible and * add the result to the specified container. */ static void extendPaths(const Lengths& lengths, ContigID id, const ContigPathMap& paths, ContigPathMap& out) { ContigPathMap::const_iterator pathIt = paths.find(id); assert(pathIt != paths.end()); pair inserted; #pragma omp critical(out) inserted = out.insert(*pathIt); assert(inserted.second); ContigPath& path = inserted.first->second; if (gDebugPrint) #pragma omp critical(cout) cout << "\n* " << get(g_contigNames, id) << "+\n" << '\t' << path << '\n'; set seen; seen.insert(ContigNode(id, false)); deque mergeQ; appendToMergeQ(mergeQ, seen, path); while (mergePaths(lengths, path, mergeQ, seen, paths) > 0) ; if (!mergeQ.empty() && gDebugPrint) { #pragma omp critical(cout) { cout << "invalid\n"; for (deque::const_iterator it = mergeQ.begin(); it != mergeQ.end(); ++it) cout << get(g_contigNames, *it) << '\t' << paths.find(it->contigIndex())->second << '\n'; } } } /** Return true if the contigs are equal or both are ambiguous. */ static bool equalOrBothAmbiguos(const ContigNode& a, const ContigNode& b) { return a == b || (a.ambiguous() && b.ambiguous()); } /** Return true if both paths are equal, ignoring ambiguous nodes. */ static bool equalIgnoreAmbiguos(const ContigPath& a, const ContigPath& b) { return a.size() == b.size() && equal(a.begin(), a.end(), b.begin(), equalOrBothAmbiguos); } /** Return whether this path is a cycle. */ static bool isCycle(const Lengths& lengths, const ContigPath& path) { return !align(lengths, path, path, path.front()).empty(); } /** Identify paths subsumed by the specified path. * @param overlaps [out] paths that are found to overlap * @return the ID of the subsuming path */ static ContigID identifySubsumedPaths( const Lengths& lengths, ContigPathMap::const_iterator path1It, ContigPathMap& paths, set& out, set& overlaps) { ostringstream vout; out.clear(); ContigID id(path1It->first); const ContigPath& path = path1It->second; if (gDebugPrint) vout << get(g_contigNames, ContigNode(id, false)) << '\t' << path << '\n'; for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) { ContigNode pivot = *it; if (pivot.ambiguous() || pivot.id() == id) continue; ContigPathMap::iterator path2It = paths.find(pivot.contigIndex()); if (path2It == paths.end()) continue; ContigPath path2 = path2It->second; if (pivot.sense()) reverseComplement(path2.begin(), path2.end()); ContigPath consensus = align(lengths, path, path2, pivot); if (consensus.empty()) continue; if (equalIgnoreAmbiguos(consensus, path)) { if (gDebugPrint) vout << get(g_contigNames, pivot) << '\t' << path2 << '\n'; out.insert(path2It->first); } else if (equalIgnoreAmbiguos(consensus, path2)) { // This path is larger. Use it as the seed. return identifySubsumedPaths(lengths, path2It, paths, out, overlaps); } else if (isCycle(lengths, consensus)) { // The consensus path is a cycle. bool isCyclePath1 = isCycle(lengths, path); bool isCyclePath2 = isCycle(lengths, path2); if (!isCyclePath1 && !isCyclePath2) { // Neither path is a cycle. if (gDebugPrint) vout << get(g_contigNames, pivot) << '\t' << path2 << '\n' << "ignored\t" << consensus << '\n'; overlaps.insert(id); overlaps.insert(path2It->first); } else { // At least one path is a cycle. if (gDebugPrint) vout << get(g_contigNames, pivot) << '\t' << path2 << '\n' << "cycle\t" << consensus << '\n'; if (isCyclePath1 && isCyclePath2) out.insert(path2It->first); else if (!isCyclePath1) overlaps.insert(id); else if (!isCyclePath2) overlaps.insert(path2It->first); } } else { if (gDebugPrint) vout << get(g_contigNames, pivot) << '\t' << path2 << '\n' << "ignored\t" << consensus << '\n'; overlaps.insert(id); overlaps.insert(path2It->first); } } cout << vout.str(); return id; } /** Remove paths subsumed by the specified path. * @param seed [out] the ID of the subsuming path * @param overlaps [out] paths that are found to overlap * @return the next iterator after path1it */ static ContigPathMap::const_iterator removeSubsumedPaths( const Lengths& lengths, ContigPathMap::const_iterator path1It, ContigPathMap& paths, ContigID& seed, set& overlaps) { if (gDebugPrint) cout << '\n'; set eq; seed = identifySubsumedPaths(lengths, path1It, paths, eq, overlaps); ++path1It; for (set::const_iterator it = eq.begin(); it != eq.end(); ++it) { if (*it == path1It->first) ++path1It; paths.erase(*it); } return path1It; } /** Remove paths subsumed by another path. * @return paths that are found to overlap */ static set removeSubsumedPaths(const Lengths& lengths, ContigPathMap& paths) { set overlaps, seen; for (ContigPathMap::const_iterator iter = paths.begin(); iter != paths.end();) { if (seen.count(iter->first) == 0) { ContigID seed; iter = removeSubsumedPaths(lengths, iter, paths, seed, overlaps); seen.insert(seed); } else ++iter; } return overlaps; } /** Add missing overlap edges. For each vertex u with at least two * outgoing edges, (u,v1) and (u,v2), add the edge (v1,v2) if v1 < v2, * and add the edge (v2,v1) if v2 < v1. */ static void addMissingEdges(const Lengths& lengths, PathGraph& g, const ContigPathMap& paths) { typedef graph_traits::adjacency_iterator Vit; typedef graph_traits::vertex_iterator Uit; typedef graph_traits::vertex_descriptor V; unsigned numAdded = 0; pair urange = vertices(g); for (Uit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (out_degree(u, g) < 2) continue; pair vrange = adjacent_vertices(u, g); for (Vit vit1 = vrange.first; vit1 != vrange.second;) { V v1 = *vit1; ++vit1; assert(v1 != u); ContigPath path1 = getPath(paths, v1); if (find(path1.begin(), path1.end(), ContigPath::value_type(u)) == path1.end()) continue; for (Vit vit2 = vit1; vit2 != vrange.second; ++vit2) { V v2 = *vit2; assert(v2 != u); assert(v1 != v2); if (edge(v1, v2, g).second || edge(v2, v1, g).second) continue; ContigPath path2 = getPath(paths, v2); if (find(path2.begin(), path2.end(), ContigPath::value_type(u)) == path2.end()) continue; numAdded += addOverlapEdge(lengths, g, u, v1, path1, v2, path2); } } } if (opt::verbose > 0) cout << "Added " << numAdded << " missing edges.\n"; if (!opt::db.empty()) addToDb(db, "addedMissingEdges", numAdded); } /** Remove transitive edges. */ static void removeTransitiveEdges(PathGraph& pathGraph) { unsigned nbefore = num_edges(pathGraph); unsigned nremoved = remove_transitive_edges(pathGraph); unsigned nafter = num_edges(pathGraph); if (opt::verbose > 0) cout << "Removed " << nremoved << " transitive edges of " << 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. * Remove the edge (u,v) if deg+(u) > 1 and deg-(v) > 1 and the * overlap of (u,v) is small. */ static void removeSmallOverlaps(PathGraph& g, const ContigPathMap& paths) { typedef graph_traits::edge_descriptor E; typedef graph_traits::out_edge_iterator Eit; typedef graph_traits::vertex_descriptor V; typedef graph_traits::vertex_iterator Vit; vector edges; pair urange = vertices(g); for (Vit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (out_degree(u, g) < 2) continue; ContigPath pathu = getPath(paths, u); pair uvits = out_edges(u, g); for (Eit uvit = uvits.first; uvit != uvits.second; ++uvit) { E uv = *uvit; V v = target(uv, g); assert(v != u); if (in_degree(v, g) < 2) continue; ContigPath pathv = getPath(paths, v); if (pathu.back() == pathv.front() && paths.count(pathu.back().contigIndex()) > 0) edges.push_back(uv); } } remove_edges(g, edges.begin(), edges.end()); 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. */ static void outputPathGraph(PathGraph& pathGraph) { if (opt::graphPath.empty()) return; ofstream out(opt::graphPath.c_str()); assert_good(out, opt::graphPath); write_dot(out, pathGraph); assert_good(out, opt::graphPath); } /** Sort and output the specified paths. */ static void outputSortedPaths(const Lengths& lengths, const ContigPathMap& paths) { // Sort the paths. vector sortedPaths(paths.size()); transform( paths.begin(), paths.end(), sortedPaths.begin(), mem_var(&ContigPathMap::value_type::second)); sort(sortedPaths.begin(), sortedPaths.end()); // Output the paths. ofstream fout(opt::out.c_str()); ostream& out = opt::out.empty() ? cout : fout; assert_good(out, opt::out); for (vector::const_iterator it = sortedPaths.begin(); it != sortedPaths.end(); ++it) out << createContigName() << '\t' << *it << '\n'; assert_good(out, opt::out); // Report assembly metrics. reportAssemblyMetrics(lengths, sortedPaths); } /** Assemble the path overlap graph. */ static void assemblePathGraph(const Lengths& lengths, PathGraph& pathGraph, ContigPathMap& paths) { ContigPaths seedPaths; assembleDFS(pathGraph, back_inserter(seedPaths)); ContigPaths mergedPaths = mergeSeedPaths(lengths, paths, seedPaths); if (opt::verbose > 1) cout << '\n'; // Replace each path with the merged path. for (ContigPaths::const_iterator it1 = seedPaths.begin(); it1 != seedPaths.end(); ++it1) { const ContigPath& path(mergedPaths[it1 - seedPaths.begin()]); ContigPath pathrc(path); reverseComplement(pathrc.begin(), pathrc.end()); for (ContigPath::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) { ContigNode seed(*it2); if (find(path.begin(), path.end(), seed) != path.end()) { paths[seed.contigIndex()] = seed.sense() ? pathrc : path; } else { // This seed was not included in the merged path. } } } removeRepeats(paths); // Remove the subsumed paths. if (opt::verbose > 0) cout << "Removing redundant contigs\n"; removeSubsumedPaths(lengths, paths); outputSortedPaths(lengths, paths); } /** Read a set of paths from the specified file. */ static ContigPathMap readPaths(const Lengths& lengths, const string& filePath) { if (opt::verbose > 0) cerr << "Reading `" << filePath << "'..." << endl; ifstream in(filePath.c_str()); assert_good(in, filePath); unsigned tooSmall = 0; ContigPathMap paths; std::string name; ContigPath path; while (in >> name >> path) { // Ignore seed contigs shorter than the threshold length. ContigID id(get(g_contigNames, name)); unsigned len = lengths[id] + opt::k - 1; if (len < opt::seedLen) { tooSmall++; continue; } bool inserted = paths.insert(make_pair(id, path)).second; assert(inserted); (void)inserted; } assert(in.eof()); if (opt::seedLen > 0) cout << "Ignored " << tooSmall << " paths whose seeds are shorter than " << opt::seedLen << " bp.\n"; return paths; } /** Store it in out and increment it. * @return true if out != last */ template bool atomicInc(T1& it, T2 last, T3& out) { #pragma omp critical(atomicInc) out = it == last ? it : it++; return out != last; } /** Build the path overlap graph. */ static void buildPathGraph(const Lengths& lengths, PathGraph& g, const ContigPathMap& paths) { // Create the vertices of the path overlap graph. PathGraph(lengths.size()).swap(g); // Remove the non-seed contigs. typedef graph_traits::vertex_iterator vertex_iterator; pair vit = g.vertices(); for (vertex_iterator u = vit.first; u != vit.second; ++u) if (paths.count(get(vertex_contig_index, g, *u)) == 0) remove_vertex(*u, g); // Find the overlapping paths. ContigPathMap::const_iterator sharedIt = paths.begin(); #pragma omp parallel for (ContigPathMap::const_iterator it; atomicInc(sharedIt, paths.end(), it);) findPathOverlaps(lengths, paths, ContigNode(it->first, false), it->second, g); if (gDebugPrint) cout << '\n'; addMissingEdges(lengths, g, paths); removeTransitiveEdges(g); removeSmallOverlaps(g, paths); if (opt::verbose > 0) printGraphStats(cout, g); // graph statistics vector vals = passGraphStatsVal(g); vector keys = make_vector() << "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); } /** Read contig lengths. */ static Lengths readContigLengths(istream& in) { assert(in); assert(g_contigNames.empty()); Lengths lengths; string s; unsigned len; while (in >> s >> len) { in.ignore(numeric_limits::max(), '\n'); put(g_contigNames, lengths.size(), s); assert(len >= opt::k); lengths.push_back(len - opt::k + 1); } assert(in.eof()); assert(!lengths.empty()); g_contigNames.lock(); return lengths; } /** Read contig lengths. */ static Lengths readContigLengths(const string& 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'G': { double x; arg >> x; opt::genomeSize = x; break; } case 'g': arg >> opt::graphPath; break; case 'j': arg >> opt::threads; break; case 'k': arg >> opt::k; break; case 'o': arg >> opt::out; break; case 's': arg >> opt::seedLen; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (!opt::graphPath.empty()) opt::greedy = false; gDebugPrint = opt::verbose > 1; #if _OPENMP if (opt::threads > 0) omp_set_num_threads(opt::threads); #endif 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; buildPathGraph(lengths, pathGraph, originalPathMap); if (!opt::out.empty()) assemblePathGraph(lengths, pathGraph, originalPathMap); exit(EXIT_SUCCESS); } ContigPathMap resultsPathMap; #if _OPENMP ContigPathMap::iterator sharedIt = originalPathMap.begin(); #pragma omp parallel for (ContigPathMap::iterator it; atomicInc(sharedIt, originalPathMap.end(), it);) extendPaths(lengths, it->first, originalPathMap, resultsPathMap); #else for (ContigPathMap::const_iterator it = originalPathMap.begin(); it != originalPathMap.end(); ++it) extendPaths(lengths, it->first, originalPathMap, resultsPathMap); #endif if (gDebugPrint) cout << '\n'; set repeats = removeRepeats(resultsPathMap); if (gDebugPrint) cout << "\nRemoving redundant contigs\n"; set overlaps = removeSubsumedPaths(lengths, resultsPathMap); if (!overlaps.empty() && !repeats.empty()) { // Remove the newly-discovered repeat contigs from the // original paths. for (set::const_iterator it = repeats.begin(); it != repeats.end(); ++it) originalPathMap.erase(*it); // Reassemble the paths that were found to overlap. if (gDebugPrint) { cout << "\nReassembling overlapping contigs:"; for (set::const_iterator it = overlaps.begin(); it != overlaps.end(); ++it) cout << ' ' << get(g_contigNames, *it); cout << '\n'; } for (set::const_iterator it = overlaps.begin(); it != overlaps.end(); ++it) { if (originalPathMap.count(*it) == 0) continue; // repeat ContigPathMap::iterator oldIt = resultsPathMap.find(*it); if (oldIt == resultsPathMap.end()) continue; // subsumed ContigPath old = oldIt->second; resultsPathMap.erase(oldIt); extendPaths(lengths, *it, originalPathMap, resultsPathMap); if (gDebugPrint) { if (resultsPathMap[*it] == old) cout << "no change\n"; else cout << "was\t" << old << '\n'; } } if (gDebugPrint) cout << '\n'; removeRepeats(resultsPathMap); overlaps = removeSubsumedPaths(lengths, resultsPathMap); if (!overlaps.empty() && gDebugPrint) { cout << "\nOverlapping contigs:"; for (set::const_iterator it = overlaps.begin(); it != overlaps.end(); ++it) cout << ' ' << get(g_contigNames, *it); cout << '\n'; } } originalPathMap.clear(); outputSortedPaths(lengths, resultsPathMap); return 0; } /** Return the length of the specified contig in k-mer. */ static unsigned getLength(const Lengths& lengths, const ContigNode& u) { return u.ambiguous() ? u.length() : lengths.at(u.id()); } /** Functor to add the number of k-mer in two contigs. */ struct AddLength { AddLength(const Lengths& lengths) : m_lengths(lengths) {} unsigned operator()(unsigned addend, const ContigNode& u) const { return addend + getLength(m_lengths, u); } private: const Lengths& m_lengths; }; /** Attempt to fill in gaps in one path with the sequence from the * other path and store the consensus at result if an alignment is * found. * @return true if an alignment is found */ template static bool alignCoordinates( const Lengths& lengths, iterator& first1, iterator last1, iterator& first2, iterator last2, oiterator& result) { oiterator out = result; int ambiguous1 = 0, ambiguous2 = 0; iterator it1 = first1, it2 = first2; while (it1 != last1 && it2 != last2) { if (it1->ambiguous()) { ambiguous1 += it1->length(); ++it1; assert(it1 != last1); assert(!it1->ambiguous()); } if (it2->ambiguous()) { ambiguous2 += it2->length(); ++it2; assert(it2 != last2); assert(!it2->ambiguous()); } if (ambiguous1 > 0 && ambiguous2 > 0) { if (ambiguous1 > ambiguous2) { *out++ = ContigNode(ambiguous2, 'N'); ambiguous1 -= ambiguous2; ambiguous2 = 0; } else { *out++ = ContigNode(ambiguous1, 'N'); ambiguous2 -= ambiguous1; ambiguous1 = 0; } } else if (ambiguous1 > 0) { ambiguous1 -= getLength(lengths, *it2); *out++ = *it2++; } else if (ambiguous2 > 0) { ambiguous2 -= getLength(lengths, *it1); *out++ = *it1++; } else assert(false); if (ambiguous1 == 0 && ambiguous2 == 0) break; if (ambiguous1 < 0 || ambiguous2 < 0) return false; } assert(ambiguous1 == 0 || ambiguous2 == 0); int ambiguous = ambiguous1 + ambiguous2; assert(out > result); if (out[-1].ambiguous()) assert(ambiguous == 0); else *out++ = ContigNode(max(1, ambiguous), 'N'); first1 = it1; first2 = it2; result = out; return true; } /** Align the ambiguous region [it1, it1e) to [it2, it2e) and store * the consensus at out if an alignment is found. * @return true if an alignment is found */ template static bool buildConsensus( const Lengths& lengths, iterator it1, iterator it1e, iterator it2, iterator it2e, oiterator& out) { iterator it1b = it1 + 1; assert(!it1b->ambiguous()); if (it1b == it1e) { // path2 completely fills the gap in path1. out = copy(it2, it2e, out); return true; } // The gaps of path1 and path2 overlap. iterator it2a = it2e - 1; if (it2e == it2 || !it2a->ambiguous()) { // The two paths do not agree. No alignment. return false; } unsigned ambiguous1 = it1->length(); unsigned ambiguous2 = it2a->length(); unsigned unambiguous1 = accumulate(it1b, it1e, 0, AddLength(lengths)); unsigned unambiguous2 = accumulate(it2, it2a, 0, AddLength(lengths)); if (ambiguous1 < unambiguous2 || ambiguous2 < unambiguous1) { // Two gaps overlap and either of the gaps is smaller // than the unambiguous sequence that overlaps the // gap. No alignment. return false; } unsigned n = max(1U, max(ambiguous2 - unambiguous1, ambiguous1 - unambiguous2)); out = copy(it2, it2a, out); *out++ = ContigNode(n, 'N'); out = copy(it1b, it1e, out); return true; } /** Align the ambiguous region [it1, last1) to [it2, last2) using it1e * as the seed of the alignment. The end of the alignment is returned * in it1 and it2. * @return true if an alignment is found */ template static bool alignAtSeed( const Lengths& lengths, iterator& it1, iterator it1e, iterator last1, iterator& it2, iterator last2, oiterator& out) { assert(it1 != last1); assert(it1->ambiguous()); assert(it1 + 1 != last1); assert(!it1e->ambiguous()); assert(it2 != last2); // Find the best seeded alignment. The best alignment has the // fewest number of contigs in the consensus sequence. unsigned bestLen = UINT_MAX; iterator bestIt2e; for (iterator it2e = it2; (it2e = find(it2e, last2, *it1e)) != last2; ++it2e) { oiterator myOut = out; if (buildConsensus(lengths, it1, it1e, it2, it2e, myOut) && align(lengths, it1e, last1, it2e, last2, myOut)) { unsigned len = myOut - out; if (len <= bestLen) { bestLen = len; bestIt2e = it2e; } } } if (bestLen != UINT_MAX) { bool good = buildConsensus(lengths, it1, it1e, it2, bestIt2e, out); assert(good); it1 = it1e; it2 = bestIt2e; return good; } else return false; } /** Align the ambiguous region [it1, last1) to [it2, last2). * The end of the alignment is returned in it1 and it2. * @return true if an alignment is found */ template static bool alignAmbiguous( const Lengths& lengths, iterator& it1, iterator last1, iterator& it2, iterator last2, oiterator& out) { assert(it1 != last1); assert(it1->ambiguous()); assert(it1 + 1 != last1); assert(it2 != last2); // Find a seed for the alignment. for (iterator it1e = it1; it1e != last1; ++it1e) { if (it1e->ambiguous()) continue; if (alignAtSeed(lengths, it1, it1e, last1, it2, last2, out)) return true; } // No valid seeded alignment. Check whether path2 fits entirely // within the gap of path1. return alignCoordinates(lengths, it1, last1, it2, last2, out); } /** Align the next pair of contigs. * The end of the alignment is returned in it1 and it2. * @return true if an alignment is found */ template static bool alignOne( const Lengths& lengths, iterator& it1, iterator last1, iterator& it2, iterator last2, oiterator& out) { // Check for a trivial alignment. unsigned n1 = last1 - it1, n2 = last2 - it2; if (n1 <= n2 && equal(it1, last1, it2)) { // [it1,last1) is a prefix of [it2,last2). out = copy(it1, last1, out); it1 += n1; it2 += n1; assert(it1 == last1); return true; } else if (n2 < n1 && equal(it2, last2, it1)) { // [it2,last2) is a prefix of [it1,last1). out = copy(it2, last2, out); it1 += n2; it2 += n2; assert(it2 == last2); return true; } return it1->ambiguous() && it2->ambiguous() ? (it1->length() > it2->length() ? alignAmbiguous(lengths, it1, last1, it2, last2, out) : alignAmbiguous(lengths, it2, last2, it1, last1, out)) : it1->ambiguous() ? alignAmbiguous(lengths, it1, last1, it2, last2, out) : it2->ambiguous() ? alignAmbiguous(lengths, it2, last2, it1, last1, out) : (*out++ = *it1, *it1++ == *it2++); } /** Align the ambiguous region [it1, last1) to [it2, last2) * and store the consensus at out if an alignment is found. * @return the orientation of the alignment if an alignments is found * or zero otherwise */ template static dir_type align( const Lengths& lengths, iterator it1, iterator last1, iterator it2, iterator last2, oiterator& out) { assert(it1 != last1); assert(it2 != last2); while (it1 != last1 && it2 != last2) if (!alignOne(lengths, it1, last1, it2, last2, out)) return DIR_X; assert(it1 == last1 || it2 == last2); out = copy(it1, last1, out); out = copy(it2, last2, out); return it1 == last1 && it2 == last2 ? DIR_B : it1 == last1 ? DIR_F : it2 == last2 ? DIR_R : DIR_X; } /** Find an equivalent region of the two specified paths, starting the * alignment at pivot1 of path1 and pivot2 of path2. * @param[out] orientation the orientation of the alignment * @return the consensus sequence */ static ContigPath align( const Lengths& lengths, const ContigPath& p1, const ContigPath& p2, ContigPath::const_iterator pivot1, ContigPath::const_iterator pivot2, dir_type& orientation) { assert(*pivot1 == *pivot2); ContigPath::const_reverse_iterator rit1 = ContigPath::const_reverse_iterator(pivot1 + 1), rit2 = ContigPath::const_reverse_iterator(pivot2 + 1); ContigPath alignmentr(p1.rend() - rit1 + p2.rend() - rit2); ContigPath::iterator rout = alignmentr.begin(); dir_type alignedr = align(lengths, rit1, p1.rend(), rit2, p2.rend(), rout); alignmentr.erase(rout, alignmentr.end()); ContigPath::const_iterator it1 = pivot1, it2 = pivot2; ContigPath alignmentf(p1.end() - it1 + p2.end() - it2); ContigPath::iterator fout = alignmentf.begin(); dir_type alignedf = align(lengths, it1, p1.end(), it2, p2.end(), fout); alignmentf.erase(fout, alignmentf.end()); ContigPath consensus; if (alignedr != DIR_X && alignedf != DIR_X) { // Found an alignment. assert(!alignmentf.empty()); assert(!alignmentr.empty()); consensus.reserve(alignmentr.size() - 1 + alignmentf.size()); consensus.assign(alignmentr.rbegin(), alignmentr.rend() - 1); consensus.insert(consensus.end(), alignmentf.begin(), alignmentf.end()); // Determine the orientation of the alignment. unsigned dirs = alignedr << 2 | alignedf; static const dir_type DIRS[16] = { DIR_X, // 0000 XX impossible DIR_X, // 0001 XF impossible DIR_X, // 0010 XR impossible DIR_X, // 0011 XB impossible DIR_X, // 0100 FX impossible DIR_B, // 0101 FF u is subsumed in v DIR_R, // 0110 FR v->u DIR_R, // 0111 FB v->u DIR_X, // 1000 RX impossible DIR_F, // 1001 RF u->v DIR_B, // 1010 RR v is subsumed in u DIR_F, // 1011 RB u->v DIR_X, // 1100 BX impossible DIR_F, // 1101 BF u->v DIR_R, // 1110 BR v->u DIR_B, // 1111 BB u and v are equal }; assert(dirs < 16); orientation = DIRS[dirs]; assert(orientation != DIR_X); } return consensus; } /** Return a pivot suitable for aligning the two paths if one exists, * otherwise return false. */ static pair findPivot(const ContigPath& path1, const ContigPath& path2) { for (ContigPath::const_iterator it = path2.begin(); it != path2.end(); ++it) { if (it->ambiguous()) continue; if (count(path2.begin(), path2.end(), *it) == 1 && count(path1.begin(), path1.end(), *it) == 1) return make_pair(*it, true); } return make_pair(ContigNode(0), false); } /** Find an equivalent region of the two specified paths. * @param[out] orientation the orientation of the alignment * @return the consensus sequence */ static ContigPath align( const Lengths& lengths, const ContigPath& path1, const ContigPath& path2, ContigNode pivot, dir_type& orientation) { if (&path1 == &path2) { // Ignore the trivial alignment when aligning a path to // itself. } else if (path1 == path2) { // These two paths are identical. orientation = DIR_B; return path1; } else { ContigPath::const_iterator it = search(path1.begin(), path1.end(), path2.begin(), path2.end()); if (it != path1.end()) { // path2 is subsumed in path1. // Determine the orientation of the edge. orientation = it == path1.begin() ? DIR_R : it + path2.size() == path1.end() ? DIR_F : DIR_B; return path1; } } // Find a suitable pivot. if (find(path1.begin(), path1.end(), pivot) == path1.end() || find(path2.begin(), path2.end(), pivot) == path2.end()) { bool good; tie(pivot, good) = findPivot(path1, path2); if (!good) return ContigPath(); } assert(find(path1.begin(), path1.end(), pivot) != path1.end()); ContigPath::const_iterator it2 = find(path2.begin(), path2.end(), pivot); assert(it2 != path2.end()); if (&path1 != &path2) { // The seed must be unique in path2, unless we're aligning a // path to itself. assert(count(it2 + 1, path2.end(), pivot) == 0); } ContigPath consensus; for (ContigPath::const_iterator it1 = find_if( path1.begin(), path1.end(), [&pivot](const ContigNode& c) { return c == pivot; }); it1 != path1.end(); it1 = find_if(it1 + 1, path1.end(), [&pivot](const ContigNode& c) { return c == pivot; })) { if (&*it1 == &*it2) { // We are aligning a path to itself, and this is the // trivial alignment, which we'll ignore. continue; } consensus = align(lengths, path1, path2, it1, it2, orientation); if (!consensus.empty()) return consensus; } return consensus; } /** Find an equivalent region of the two specified paths. * @return the consensus sequence */ static ContigPath align(const Lengths& lengths, const ContigPath& path1, const ContigPath& path2, ContigNode pivot) { dir_type orientation; return align(lengths, path1, path2, pivot, orientation); } abyss-2.2.4/MergePaths/PathConsensus.cpp000066400000000000000000000734231361462241400202140ustar00rootroot00000000000000#include "dialign.h" #include "config.h" #include "Common/Options.h" #include "ConstString.h" #include "ContigNode.h" #include "ContigPath.h" #include "Dictionary.h" #include "FastaReader.h" #include "IOUtil.h" #include "StringUtil.h" #include "Uncompress.h" #include "alignGlobal.h" #include "Graph/ConstrainedSearch.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/GraphIO.h" #include #include #include #include #include #include #include #include #include #include #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" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -s -o [OPTION]... FASTA ADJ PATH\n" "Align sequences of ambiguous paths and output a consensus\n" "sequence.\n" "\n" " Arguments:\n" "\n" " FASTA contigs in FASTA format\n" " ADJ contig adjacency graph\n" " PATH paths of these contigs\n" "\n" " Options:\n" "\n" " -k, --kmer=N k-mer size\n" " -d, --dist-error=N acceptable error of a distance estimate\n" " default: 6 bp\n" " -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" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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" " -M, --dialign-m=FILE score matrix, default: dna_matrix.scr\n" " -P, --dialign-p=FILE diagonal length probability distribution\n" " default: dna_diag_prob_100_exp_550000\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { string db; dbVars metaVars; unsigned k; // used by ContigProperties static string out; static string consensusPath; static string graphPath; static float identity = 0.9; static unsigned numBranches = 4; static int dialign_debug; static string dialign_score; static string dialign_prob; /** Output format. */ int format; // used by ContigProperties /** The the number of bases to continue the constrained search of * the graph beyond the size of the ambiguous gap in the path. */ unsigned distanceError = 6; } static const char shortopts[] = "d:k:o:s:g:a:p:vD:M:P:"; 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' }, { "dist-error", required_argument, NULL, 'd' }, { "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 }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "sam", no_argument, &opt::format, SAM }, { "branches", required_argument, NULL, 'a' }, { "identity", required_argument, NULL, 'p' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { "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 } }; static struct { unsigned numAmbPaths; unsigned numMerged; unsigned numNoSolutions; unsigned numTooManySolutions; unsigned tooComplex; unsigned notMerged; } stats; struct AmbPathConstraint { ContigNode source; ContigNode dest; int dist; AmbPathConstraint(const ContigNode& src, const ContigNode& dst, int d) : source(src), dest(dst), dist(d) {} bool operator ==(const AmbPathConstraint& a) const { return source == a.source && dest == a.dest && dist == a.dist; } bool operator <(const AmbPathConstraint& a) const { return source < a.source || (source == a.source && dest < a.dest) || (source == a.source && dest == a.dest && dist < a.dist); } }; typedef ContigGraph > Graph; typedef ContigPath Path; typedef vector ContigPaths; typedef map AmbPath2Contig; typedef vector Contigs; static Contigs g_contigs; AmbPath2Contig g_ambpath_contig; /** Return the sequence of the specified contig node. The sequence * may be ambiguous or reverse complemented. */ static const Sequence getSequence(ContigNode id) { if (id.ambiguous()) { string s(id.ambiguousSequence()); if (s.length() < opt::k) transform(s.begin(), s.end(), s.begin(), ::tolower); return string(opt::k - 1, 'N') + s; } else { string seq(g_contigs[id.id()]); return id.sense() ? reverseComplement(seq) : seq; } } /** Return the distance from vertex u to v. */ static int getDistance(const Graph& g, graph_traits::vertex_descriptor u, graph_traits::vertex_descriptor v) { typedef graph_traits::edge_descriptor E; pair e = edge(u, v, g); assert(e.second); return g[e.first].distance; } /** Read contig paths from the specified file. * @param[in] inPath the filename of the contig paths * @param[out] ids the string ID of the paths * @param[out] isAmb whether the path contains a gap */ static ContigPaths readPaths(const string& inPath, vector& ids, vector& isAmb) { assert(ids.empty()); assert(isAmb.empty()); assert(g_ambpath_contig.empty()); ifstream fin(inPath.c_str()); if (opt::verbose > 0) cerr << "Reading `" << inPath << "'..." << endl; if (inPath != "-") assert_good(fin, inPath); istream& in = inPath == "-" ? cin : fin; ContigPaths paths; string id; Path path; while (in >> id >> path) { paths.push_back(path); ids.push_back(id); isAmb.push_back(false); if (path.size() <= 2) continue; for (Path::iterator it = path.begin() + 2; it != path.end(); ++it) { ContigPath::value_type t = it[-2], u = it[-1], v = it[0]; if (u.ambiguous()) { assert(!t.ambiguous()); assert(!v.ambiguous()); g_ambpath_contig.insert(AmbPath2Contig::value_type( AmbPathConstraint(t, v, u.length()), ContigPath())); isAmb.back() = true; } } } assert(in.eof()); return paths; } /** Mark every contig in path as seen. */ static void markSeen(vector& seen, const ContigPath& path, bool flag) { for (Path::const_iterator it = path.begin(); it != path.end(); ++it) if (!it->ambiguous() && it->id() < seen.size()) seen[it->id()] = flag; } /** Mark every contig in paths as seen. */ static void markSeen(vector& seen, const vector& paths, bool flag) { for (vector::const_iterator it = paths.begin(); it != paths.end(); ++it) markSeen(seen, *it, flag); } /** A new vertex and two edges that will be added to the graph. */ struct NewVertex { typedef graph_traits::vertex_descriptor V; typedef vertex_property::type VP; typedef edge_property::type EP; V t, u, v; VP vpu; EP eptu, epuv; NewVertex(V t, V u, V v, const VP& vpu, const EP& eptu, const EP& epuv) : t(t), u(u), v(v), vpu(vpu), eptu(eptu), epuv(epuv) { } }; typedef vector NewVertices; /** The new vertices that will be added to the graph. */ static NewVertices g_newVertices; /** Output a new contig. */ static ContigNode outputNewContig(const Graph& g, const vector& solutions, size_t longestPrefix, size_t longestSuffix, const Sequence& seq, const unsigned coverage, ofstream& out) { assert(!solutions.empty()); assert(longestPrefix > 0); assert(longestSuffix > 0); size_t numContigs = num_vertices(g) / 2; ContigNode u(numContigs + g_newVertices.size(), false); string name = createContigName(); put(vertex_name, g, u, name); out << '>' << name << ' ' << seq.length() << ' ' << coverage << ' '; int dtu = INT_MAX, duv = INT_MAX; for (vector::const_iterator it = solutions.begin(); it != solutions.end(); it++) { if (it != solutions.begin()) out << ';'; const ContigPath& path = *it; ContigPath::const_iterator first = path.begin() + longestPrefix, last = path.end() - longestSuffix; assert(first <= last); if (first < last) { ContigPath::const_iterator it = first; out << get(vertex_name, g, *it); for (++it; it != last; ++it) out << ',' << get(vertex_name, g, *it); dtu = min(dtu, getDistance(g, first[-1], first[0])); duv = min(duv, getDistance(g, last[-1], last[0])); } else out << '*'; } out << '\n' << seq << '\n'; assert(dtu < INT_MAX); assert(duv < INT_MAX); // Record the newly-created contig to be added to the graph later. g_newVertices.push_back(NewVertex( *(solutions[0].begin() + longestPrefix - 1), u, *(solutions[0].rbegin() + longestSuffix - 1), ContigProperties(seq.length(), coverage), dtu, duv)); return u; } /** Return a consensus sequence of a and b. * @return an empty string if a consensus could not be found */ static string createConsensus(const Sequence& a, const Sequence& b) { assert(a.length() == b.length()); if (a == b) return a; string s; s.reserve(a.length()); for (string::const_iterator ita = a.begin(), itb = b.begin(); ita != a.end(); ++ita, ++itb) { bool mask = islower(*ita) || islower(*itb); char ca = toupper(*ita), cb = toupper(*itb); char c = ca == cb ? ca : ca == 'N' ? cb : cb == 'N' ? ca : 'x'; if (c == 'x') return string(""); s += mask ? tolower(c) : c; } return s; } /** Merge the specified two contigs, default overlap is k-1, * generate a consensus sequence of the overlapping region. The result * is stored in the first argument. */ static void mergeContigs(const Graph& g, unsigned overlap, Sequence& seq, const Sequence& s, const ContigNode& node, const Path& path) { assert(s.length() > overlap); Sequence ao; Sequence bo(s, 0, overlap); Sequence o; do { assert(seq.length() > overlap); ao = seq.substr(seq.length() - overlap); o = createConsensus(ao, bo); } while (o.empty() && chomp(seq, 'n')); if (o.empty()) { cerr << "warning: the head of " << get(vertex_name, g, node) << " does not match the tail of the previous contig\n" << ao << '\n' << bo << '\n' << path << endl; seq += 'n'; seq += s; } else { seq.resize(seq.length() - overlap); seq += o; seq += Sequence(s, overlap); } } static Sequence mergePath(const Graph&g, const Path& path) { Sequence seq; Path::const_iterator prev_it; for (Path::const_iterator it = path.begin(); it != path.end(); ++it) { if (seq.empty()) { seq = getSequence(*it); } else { int d = get(edge_bundle, g, *(it-1), *it).distance; assert(d < 0); unsigned overlap = -d; mergeContigs(g, overlap, seq, getSequence(*it), *it, path); } prev_it = it; } return seq; } /** Calculate the ContigProperties of a path. */ static ContigProperties calculatePathProperties(const Graph& g, const ContigPath& path) { return addProp(g, path.begin(), path.end()); } /* Resolve ambiguous region using pairwise alignment * (Needleman-Wunsch) ('solutions' contain exactly two paths, from a * source contig to a dest contig) */ static ContigPath alignPair(const Graph& g, const ContigPaths& solutions, ofstream& out) { assert(solutions.size() == 2); assert(solutions[0].size() > 1); assert(solutions[1].size() > 1); assert(solutions[0].front() == solutions[1].front()); assert(solutions[0].back() == solutions[1].back()); ContigPath fstSol(solutions[0].begin()+1, solutions[0].end()-1); ContigPath sndSol(solutions[1].begin()+1, solutions[1].end()-1); if (fstSol.empty() || sndSol.empty()) { // This entire sequence may be deleted. const ContigPath& sol(fstSol.empty() ? sndSol : fstSol); assert(!sol.empty()); Sequence consensus(mergePath(g, sol)); assert(consensus.size() > opt::k - 1); string::iterator first = consensus.begin() + opt::k - 1; transform(first, consensus.end(), first, ::tolower); unsigned match = opt::k - 1; float identity = (float)match / consensus.size(); if (opt::verbose > 2) cerr << consensus << '\n'; if (opt::verbose > 1) cerr << identity << (identity < opt::identity ? " (too low)\n" : "\n"); if (identity < opt::identity) return ContigPath(); unsigned coverage = calculatePathProperties(g, sol).coverage; ContigNode u = outputNewContig(g, solutions, 1, 1, consensus, coverage, out); ContigPath path; path.push_back(solutions.front().front()); path.push_back(u); path.push_back(solutions.front().back()); return path; } Sequence fstPathContig(mergePath(g, fstSol)); Sequence sndPathContig(mergePath(g, sndSol)); if (fstPathContig == sndPathContig) { // These two paths have identical sequence. if (fstSol.size() == sndSol.size()) { // A perfect match must be caused by palindrome. typedef ContigPath::const_iterator It; pair it = mismatch( fstSol.begin(), fstSol.end(), sndSol.begin()); assert(it.first != fstSol.end()); assert(it.second != sndSol.end()); assert(*it.first == get(vertex_complement, g, *it.second)); assert(equal(it.first+1, It(fstSol.end()), it.second+1)); if (opt::verbose > 1) cerr << "Palindrome: " << get(vertex_contig_name, g, *it.first) << '\n'; return solutions[0]; } else { // The paths are different lengths. cerr << PROGRAM ": warning: " "Two paths have identical sequence, which may be " "caused by a transitive edge in the overlap graph.\n" << '\t' << fstSol << '\n' << '\t' << sndSol << '\n'; return solutions[fstSol.size() > sndSol.size() ? 0 : 1]; } } unsigned minLength = min( fstPathContig.length(), sndPathContig.length()); unsigned maxLength = max( fstPathContig.length(), sndPathContig.length()); float lengthRatio = (float)minLength / maxLength; if (lengthRatio < opt::identity) { if (opt::verbose > 1) cerr << minLength << '\t' << maxLength << '\t' << lengthRatio << "\t(different length)\n"; return ContigPath(); } NWAlignment align; unsigned match = alignGlobal(fstPathContig, sndPathContig, align); float identity = (float)match / align.size(); if (opt::verbose > 2) cerr << align; if (opt::verbose > 1) cerr << identity << (identity < opt::identity ? " (too low)\n" : "\n"); if (identity < opt::identity) return ContigPath(); unsigned coverage = calculatePathProperties(g, fstSol).coverage + calculatePathProperties(g, sndSol).coverage; ContigNode u = outputNewContig(g, solutions, 1, 1, align.consensus(), coverage, out); ContigPath path; path.push_back(solutions.front().front()); path.push_back(u); path.push_back(solutions.front().back()); return path; } template struct GetLength { size_t operator()(const Seq& sequence) { return sequence.length(); } }; /* Resolve ambiguous region using multiple alignment of all paths in * `solutions'. */ static ContigPath alignMulti(const Graph& g, const vector& solutions, ofstream& out) { // Find the size of the smallest path. const Path& firstSol = solutions.front(); size_t min_len = firstSol.size(); for (vector::const_iterator it = solutions.begin() + 1; it != solutions.end(); ++it) min_len = min(min_len, it->size()); // Find the longest prefix. Path vppath; size_t longestPrefix; bool commonPrefix = true; for (longestPrefix = 0; longestPrefix < min_len; longestPrefix++) { const ContigNode& common_path_node = firstSol[longestPrefix]; for (vector::const_iterator solIter = solutions.begin(); solIter != solutions.end(); ++solIter) { const ContigNode& pathnode = (*solIter)[longestPrefix]; if (pathnode != common_path_node) { // Found the longest prefix. commonPrefix = false; break; } } if (!commonPrefix) break; vppath.push_back(common_path_node); } // Find the longest suffix. Path vspath; size_t longestSuffix; bool commonSuffix = true; for (longestSuffix = 0; longestSuffix < min_len-longestPrefix; longestSuffix++) { const ContigNode& common_path_node = firstSol[firstSol.size()-longestSuffix-1]; for (vector::const_iterator solIter = solutions.begin(); solIter != solutions.end(); ++solIter) { const ContigNode& pathnode = (*solIter)[solIter->size()-longestSuffix-1]; if (pathnode != common_path_node) { // Found the longest suffix. commonSuffix = false; break; } } if (!commonSuffix) break; vspath.push_back(common_path_node); } reverse(vspath.begin(), vspath.end()); if (opt::verbose > 1 && vppath.size() + vspath.size() > 2) cerr << vppath << " * " << vspath << '\n'; // Get sequence of ambiguous region in paths assert(longestPrefix > 0 && longestSuffix > 0); vector amb_seqs; unsigned coverage = 0; for (vector::const_iterator solIter = solutions.begin(); solIter != solutions.end(); solIter++) { assert(longestPrefix + longestSuffix <= solIter->size()); Path path(solIter->begin() + longestPrefix, solIter->end() - longestSuffix); if (!path.empty()) { amb_seqs.push_back(mergePath(g, path)); coverage += calculatePathProperties(g, path).coverage; } else { // The prefix and suffix paths overlap by k-1 bp. Sequence s = getSequence(solutions[0][longestPrefix-1]); amb_seqs.push_back(s.substr(s.length() - opt::k + 1)); } } vector lengths(amb_seqs.size()); transform(amb_seqs.begin(), amb_seqs.end(), lengths.begin(), GetLength()); unsigned minLength = *min_element(lengths.begin(), lengths.end()); unsigned maxLength = *max_element(lengths.begin(), lengths.end()); float lengthRatio = (float)minLength / maxLength; if (lengthRatio < opt::identity) { if (opt::verbose > 1) cerr << minLength << '\t' << maxLength << '\t' << lengthRatio << "\t(different length)\n"; return ContigPath(); } unsigned matches, consensusSize; NWAlignment alignment; tie(matches, consensusSize) = align(amb_seqs, alignment); string consensus = alignment.consensus(); if (opt::verbose > 2) cerr << alignment << consensus << '\n'; float identity = (float)matches / consensus.size(); if (opt::verbose > 1) cerr << identity << (identity < opt::identity ? " (too low)\n" : "\n"); if (identity < opt::identity) return ContigPath(); if (identity == 1) { // A perfect match must be caused by two palindromes. ContigID palindrome0 = solutions[0][longestPrefix].contigIndex(); ContigID palindrome1 = solutions[0].rbegin()[longestSuffix].contigIndex(); if (opt::verbose > 1) cerr << "Palindrome: " << get(g_contigNames, palindrome0) << '\n' << "Palindrome: " << get(g_contigNames, palindrome1) << '\n'; #ifndef NDEBUG string s0 = getSequence(ContigNode(palindrome0, false)); string s1 = getSequence(ContigNode(palindrome1, false)); assert(s0 == reverseComplement(s0)); assert(s1 == reverseComplement(s1)); for (vector::const_iterator it = solutions.begin(); it != solutions.end(); ++it) { const ContigPath& path = *it; assert(path[longestPrefix].contigIndex() == palindrome0); assert(path.rbegin()[longestSuffix].contigIndex() == palindrome1); assert(path.size() == solutions[0].size()); } #endif return solutions[0]; } ContigNode u = outputNewContig(g, solutions, longestPrefix, longestSuffix, consensus, coverage, out); ContigPath path(vppath); path.push_back(u); path.insert(path.end(), vspath.begin(), vspath.end()); return path; } /** Align the sequences of the specified paths. * @return the consensus sequence */ static ContigPath align(const Graph& g, const vector& sequences, ofstream& out) { assert(sequences.size() > 1); return sequences.size() == 2 ? alignPair(g, sequences, out) : alignMulti(g, sequences, out); } /** Return the consensus sequence of the specified gap. */ static ContigPath fillGap(const Graph& g, const AmbPathConstraint& apConstraint, vector& seen, ofstream& outFasta) { if (opt::verbose > 1) cerr << "\n* " << get(vertex_name, g, apConstraint.source) << ' ' << apConstraint.dist << "N " << get(vertex_name, g, apConstraint.dest) << '\n'; Constraints constraints; constraints.push_back(Constraint(apConstraint.dest, apConstraint.dist + opt::distanceError)); ContigPaths solutions; unsigned numVisited = 0; constrainedSearch(g, apConstraint.source, constraints, solutions, numVisited); bool tooComplex = numVisited >= opt::maxCost; for (ContigPaths::iterator solIt = solutions.begin(); solIt != solutions.end(); solIt++) solIt->insert(solIt->begin(), apConstraint.source); ContigPath consensus; bool tooManySolutions = solutions.size() > opt::numBranches; if (tooComplex) { stats.tooComplex++; if (opt::verbose > 1) cerr << solutions.size() << " paths (too complex)\n"; } else if (tooManySolutions) { stats.numTooManySolutions++; if (opt::verbose > 1) cerr << solutions.size() << " paths (too many)\n"; } else if (solutions.empty()) { stats.numNoSolutions++; if (opt::verbose > 1) cerr << "no paths\n"; } 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); if (opt::verbose > 2) copy(solutions.begin(), solutions.end(), ostream_iterator(cerr, "\n")); else if (opt::verbose > 1) cerr << solutions.size() << " paths\n"; consensus = align(g, solutions, outFasta); if (!consensus.empty()) { stats.numMerged++; // Mark contigs that are used in a consensus. markSeen(seen, solutions, true); if (opt::verbose > 1) cerr << consensus << '\n'; } else stats.notMerged++; } return consensus; } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'd': arg >> opt::distanceError; break; case 'k': arg >> opt::k; break; case 'o': arg >> opt::out; break; case 'p': arg >> opt::identity; break; case 'a': arg >> opt::numBranches; break; case 's': arg >> opt::consensusPath; break; case 'g': arg >> opt::graphPath; break; case 'D': arg >> opt::dialign_debug; break; case 'M': arg >> opt::dialign_score; break; case 'P': arg >> opt::dialign_prob; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (opt::out.empty()) { cerr << PROGRAM ": " << "missing -o,--out option\n"; die = true; } if (opt::consensusPath.empty()) { cerr << PROGRAM ": " << "missing -s,--consensus option\n"; die = true; } if (argc - optind < 3) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } const char *contigFile = argv[optind++]; string adjFile(argv[optind++]); string allPaths(argv[optind++]); // Read the contig overlap graph. if (opt::verbose > 0) cerr << "Reading `" << adjFile << "'..." << endl; ifstream fin(adjFile.c_str()); assert_good(fin, adjFile); Graph g; fin >> g; assert(fin.eof()); g_contigNames.lock(); // Read contigs Contigs& contigs = g_contigs; { if (opt::verbose > 0) cerr << "Reading `" << contigFile << "'..." << endl; FastaReader in(contigFile, FastaReader::NO_FOLD_CASE); for (FastaRecord rec; in >> rec;) { assert(contigs.size() == get(g_contigNames, rec.id)); contigs.push_back(rec.seq); } assert(in.eof()); assert(!contigs.empty()); opt::colourSpace = isdigit(contigs[0][0]); } vector pathIDs; vector isAmbPath; ContigPaths paths = readPaths(allPaths, pathIDs, isAmbPath); stats.numAmbPaths = g_ambpath_contig.size(); 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()); // Prepare output fasta file ofstream fa(opt::consensusPath.c_str()); assert_good(fa, opt::consensusPath); init_parameters(); set_parameters_dna(); para->DEBUG = opt::dialign_debug; para->SCR_MATRIX_FILE_NAME = (char*)opt::dialign_score.c_str(); para->DIAG_PROB_FILE_NAME = (char*)opt::dialign_prob.c_str(); initDialign(); // Contigs that were seen in a consensus. vector seen(contigs.size()); // resolve ambiguous paths recorded in g_ambpath_contig g_contigNames.unlock(); for (AmbPath2Contig::iterator ambIt = g_ambpath_contig.begin(); ambIt != g_ambpath_contig.end(); ambIt++) ambIt->second = fillGap(g, ambIt->first, seen, fa); g_contigNames.lock(); assert_good(fa, opt::consensusPath); fa.close(); if (opt::verbose > 1) cerr << '\n'; // Unmark contigs that are used in a path. for (AmbPath2Contig::iterator it = g_ambpath_contig.begin(); it != g_ambpath_contig.end(); it++) markSeen(seen, it->second, false); markSeen(seen, paths, false); ofstream out(opt::out.c_str()); assert_good(out, opt::out); // Output those contigs that were not seen in ambiguous path. for (unsigned id = 0; id < contigs.size(); ++id) if (seen[id]) out << get(g_contigNames, id) << '\n'; for (ContigPaths::const_iterator path = paths.begin(); path != paths.end(); ++path) { unsigned i = path - paths.begin(); if (!isAmbPath[i]) { out << pathIDs[i] << '\t' << *path << '\n'; continue; } assert(path->size() > 2); Path cur_path; cur_path.push_back(path->front()); for (Path::const_iterator prev = path->begin(), it = path->begin() + 1, next = path->begin() + 2; it != path->end(); ++prev, ++it, ++next) { if (!it->ambiguous()) { cur_path.push_back(*it); continue; } //replace Ns by resolved new contig assert(next != path->end()); AmbPath2Contig::iterator ambIt = g_ambpath_contig.find( AmbPathConstraint(*prev, *next, -it->id())); assert(ambIt != g_ambpath_contig.end()); const ContigPath& solution = ambIt->second; if (!solution.empty()) { assert(solution.size() > 1); cur_path.insert(cur_path.end(), solution.begin() + 1, solution.end() - 1); } else cur_path.push_back(*it); } out << pathIDs[i] << '\t' << cur_path << '\n'; } assert_good(out, opt::out); out.close(); free_prob_dist(pdist); free(para); cerr << "Ambiguous paths: " << stats.numAmbPaths << "\n" "Merged: " << stats.numMerged << "\n" "No paths: " << stats.numNoSolutions << "\n" "Too many paths: " << stats.numTooManySolutions << "\n" "Too complex: " << stats.tooComplex << "\n" "Dissimilar: " << stats.notMerged << "\n"; if (!opt::graphPath.empty()) { ofstream fout(opt::graphPath.c_str()); assert_good(fout, opt::graphPath); // Add the newly-created consensus contigs to the graph. for (NewVertices::const_iterator it = g_newVertices.begin(); it != g_newVertices.end(); ++it) { Graph::vertex_descriptor u = add_vertex(it->vpu, g); assert(u == it->u); add_edge(it->t, it->u, it->eptu, g); add_edge(it->u, it->v, it->epuv, g); } write_graph(fout, g, PROGRAM, commandLine); assert_good(fout, opt::graphPath); } vector vals = make_vector() << stats.numAmbPaths << stats.numMerged << stats.numNoSolutions << stats.numTooManySolutions << stats.tooComplex << stats.notMerged; vector keys = make_vector() << "ambg_paths" << "merged" << "no_paths" << "too_many_paths" << "too_complex" << "dissimilar"; if (!opt::db.empty()) { for (unsigned i=0; i [(a, a)] pairs [] = [] pairs (x:y:ys) = (x, y) : pairs ys -- Parse an integer from a ByteString. readS :: ByteString -> Int readS s = x where Just (x, _) = S.readInt s -- Return the rank of the smallest element x for which the sum of the elements x or larger is at least c. rankSumAtLeast :: Int -> [Int] -> Int rankSumAtLeast c xs = i where i = fromMaybe 0 $ findIndex ((>= c) . snd) $ zip ws $ scanl1 (+) ws ws = sortBy (flip compare) xs -- Return the smallest element x for which the sum of the elements x or larger is at least c. sumAtLeast :: Int -> [Int] -> Int sumAtLeast c xs = x where (x, _) = fromMaybe (0, 0) $ find ((>= c) . snd) $ zip ws $ scanl1 (+) ws ws = sortBy (flip compare) xs -- Calculate NGx. ngx :: Double -> Int -> [Int] -> Int ngx x g = sumAtLeast $ ceiling $ x * fromIntegral g -- Calculate N50. n50 :: [Int] -> Int n50 xs = ngx 0.5 (sum xs) xs -- Calculate LGx. lgx :: Double -> Int -> [Int] -> Int lgx x g = rankSumAtLeast $ ceiling $ x * fromIntegral g -- Calculate L50. l50 :: [Int] -> Int l50 xs = lgx 0.5 (sum xs) xs -- A SAM record. -- qname flag rname pos mapq cigar rnext pnext tlen seq qual data SAM = SAM { qname :: ByteString, flag :: Int, rname :: ByteString, pos :: Int, mapq :: Int, cigar :: ByteString, --rnext :: ByteString, --pnext :: Int, --tlen :: Int, --qseq :: ByteString, --qual :: ByteString seqLength :: Int } -- Return whether the unmapped flag is set. isUnmapped :: SAM -> Bool isUnmapped x = flag x .&. 4 /= 0 -- Return whether the reverse complement flag is set. isRC :: SAM -> Bool isRC x = flag x .&. 16 /= 0 -- Parse the CIGAR string. readCigar :: ByteString -> [(Int, Char)] readCigar s = map (readS *** S.head) . pairs . S.groupBy ((==) `on` isDigit) $ s -- Return the left and right soft-clipping. getSoftClip :: SAM -> (Int, Int) getSoftClip sam = ( if elem (snd x) "HS" then fst x else 0, if elem (snd y) "HS" then fst y else 0) where (x, y) = (head xs, last xs) xs = readCigar $ cigar sam -- Return the sum of the specified CIGAR elements. cigarLength :: [Char] -> ByteString -> Int cigarLength ops s = sum [n | (n, op) <- readCigar s, op `elem` ops] -- Return the length of the query alignment. qLength :: SAM -> Int qLength = cigarLength "IM" . cigar -- Return the start position of the query alignment oriented to agree -- with the target. qStart' = fst . getSoftClip -- Return the end position of the query alignment oriented to agree -- with the target. qEnd' x = qStart' x + qLength x -- Return the start position of the query alignment. qStart :: SAM -> Int qStart x = (if isRC x then snd else fst) $ getSoftClip x -- Return the end position of the query alignment. qEnd :: SAM -> Int qEnd x = qStart x + qLength x -- Return the length of the target alignment. tLength :: SAM -> Int tLength = cigarLength "DMN" . cigar -- Return the start of the target alignment. tStart :: SAM -> Int tStart = pos -- Return the end position of the target alignment. tEnd :: SAM -> Int tEnd x = tStart x + tLength x -- Return the start position of the target alignment oriented to agree -- with the query. The coordinate system is [-length, 0). tStart' x = if isRC x then 0 - tEnd x else tStart x -- Return the end position of the target alignment oriented to agree -- with the query. The coordinate system is [-length, 0). tEnd' x = tStart' x + tLength x -- Parse a SAM record. readSAM :: ByteString -> SAM readSAM s = SAM qname (readS flag) rname (readS pos) (readS mapq) cigar lengthQseq where lengthQseq = if S.head cigar == '*' then fromIntegral $ S.length qseq else cigarLength "HIMS" cigar (qname:flag:rname:pos:mapq:cigar:_:_:_:qseq:_) = S.words s -- Print a SAM record. showSAM :: SAM -> String showSAM (SAM qname flag rname pos mapq cigar _) = intercalate "\t" [S.unpack qname, show flag, S.unpack rname, show pos, show mapq, S.unpack cigar, "*", "0", "0", "*", "*"] -- Exclude alignments that overlap a long alignment by 50%. excludeOverlaps :: [SAM] -> [SAM] excludeOverlaps xs = reverse . foldl accum [] $ xs where accum ys x = if any overlapx ys then ys else x:ys where overlapx y = end - start > (qLength x) `div` 2 where start = max (qStart x) (qStart y) end = min (qEnd x) (qEnd y) -- Compare the target position. compareTStart :: SAM -> SAM -> Ordering compareTStart a b = compare (rname a, pos a) (rname b, pos b) -- Patch gaps in the alignments that are shorter than 500 bp. patchGaps :: Int -> [SAM] -> [SAM] patchGaps optPatchGaps ws = reverse . foldl accum [] $ xs where xs = sortBy compareTStart ws accum [] x = [x] accum (y:ys) x = if isSmallGap y x then x:ys else x:y:ys isSmallGap q p = (rname p, isRC p) == (rname q, isRC q) && max gapt gapq < optPatchGaps where gapt = abs (tStart p - tEnd q) gapq = abs (qStart' p - qEnd' q) -- Return whether the pair of aligned contigs are colinear. isColinear :: SAM -> SAM -> Bool isColinear a b = (rname a, isRC a) == (rname b, isRC b) && tStart' a < tStart' b && tEnd' a < tEnd' b -- Return pairs of non-colinear alignments. filterNonColinear :: [SAM] -> [(SAM, SAM)] filterNonColinear xs = filter (not . uncurry isColinear) $ zip xs (tail xs) -- The command line options. data Opt = OptAlignmentLength Int | OptContigLength Int | OptGenomeSize Int | OptMapq Int | OptPatchGaps Int | OptSAM | OptSAMContigs | OptSAMScaffolds | OptText | OptTSV | OptHelp | OptVersion deriving Eq options :: [OptDescr Opt] options = [ Option ['a'] ["alignment-length"] (ReqArg (OptAlignmentLength . read) "N") "exclude alignments with aligned query length shorter than N bp [500]", Option ['l'] ["contig-length"] (ReqArg (OptContigLength . read) "N") "exclude contigs shorter than N bp [200]", Option ['G'] ["genome-size"] (ReqArg (OptGenomeSize . read) "N") "expected genome size used to calculate NG50 [0]", Option ['q'] ["mapq"] (ReqArg (OptMapq . read) "N") "exclude alignments with mapq less than N [10]", Option ['g'] ["patch-gaps"] (ReqArg (OptPatchGaps . read) "N") "join alignments separated by a gap shorter than INT bp (with --text only) [500]", Option ['p'] ["sam"] (NoArg OptSAM) "output contig and scaffold breakpoints in SAM format", Option [] ["sam-contigs"] (NoArg OptSAMContigs) "output contig breakpoints in SAM format", Option [] ["sam-scaffolds"] (NoArg OptSAMScaffolds) "output scaffold breakpoints in SAM format", Option [] ["text"] (NoArg OptText) "output report in plain text format", Option [] ["tsv"] (NoArg OptTSV) "output report in TSV format [default]", Option [] ["help"] (NoArg OptHelp) "display this help and exit", Option [] ["version"] (NoArg OptVersion) "display version information and exit" ] data Format = FormatSAM | FormatSAMContigs | FormatSAMScaffolds | FormatText | FormatTSV deriving Eq data Options = Options { optAlignmentLength :: Int, optContigLength :: Int, optGenomeSize :: Int, optMapq :: Int, optPatchGaps :: Int, optFormat :: Format } defaultOptions = Options { optAlignmentLength = 500, optContigLength = 200, optGenomeSize = 0, optMapq = 10, optPatchGaps = 500, optFormat = FormatTSV } -- Parse the command line options. parseOptions :: [Opt] -> Options parseOptions = foldl parseOption defaultOptions where parseOption opt x = case x of OptAlignmentLength n -> opt { optAlignmentLength = n } OptContigLength n -> opt { optContigLength = n } OptGenomeSize n -> opt { optGenomeSize = n } OptMapq n -> opt { optMapq = n } OptPatchGaps n -> opt { optPatchGaps = n } OptSAM -> opt { optFormat = FormatSAM } OptSAMContigs -> opt { optFormat = FormatSAMContigs } OptSAMScaffolds -> opt { optFormat = FormatSAMScaffolds } OptText -> opt { optFormat = FormatText } OptTSV -> opt { optFormat = FormatTSV } -- Parse the command line arguments. parseArgs :: IO (Options, [String]) parseArgs = do args <- getArgs case getOpt Permute options args of (opts, files, []) -> if OptHelp `elem` opts then help else if OptVersion `elem` opts then putStr version >> exitSuccess else return (parseOptions opts, files) (_, _, errs) -> error (concat errs ++ tryHelp) where help = putStr (usageInfo usage options) >> exitSuccess tryHelp = "Try 'abyss-samtobreak --help' for more information." version = "abyss-samtobreak (ABySS) 2.2.4\n" usage = "Usage: samtobreak [OPTION]... [FILE]...\n\ \Calculate contig and scaffold contiguity and correctness metrics.\n" -- Calculate contig and scaffold contiguity and correctness metrics. printStats :: Integer -> FilePath -> Options -> IO () printStats recordIndex path (Options optAlignmentLength optContigLength optGenomeSize optMapq optPatchGaps optFormat) = do s <- S.readFile path when (S.null s) $ error $ "`" ++ path ++ "' is empty" let -- Parse the SAM file and discard short contigs. isHeader x = S.head x == '@' (headers, alignments) = span isHeader . S.lines $ s allContigs = map readSAM $ alignments -- Calculate the size of the reference genome. sq = filter ((S.pack "@SQ" ==) . head) . map S.words $ headers referenceLengths = map (readS . S.drop 3 . fromJust . find (S.isPrefixOf $ S.pack "LN:")) sq reference_bases = sum referenceLengths -- Keep the first (primary) alignment of each contig. primaryContigs = map head . groupBy ((==) `on` qname) $ allContigs -- Group the contigs into scaffolds by their name. isScaffoldDelimiter c = c == '_' || c == ':' scaffoldName = S.takeWhile (not . isScaffoldDelimiter) . qname primaryScaffolds = groupBy ((==) `on` scaffoldName) $ primaryContigs -- Separate the mapped and unmapped contigs, and discard short contigs. isLong x = seqLength x >= optContigLength (unmapped, mapped) = partition isUnmapped $ filter isLong allContigs -- Exclude overlapping alignments. excluded = map excludeOverlaps . groupBy ((==) `on` qname) $ mapped concatExcluded = concat excluded alignedContigLengths = map qLength concatExcluded -- Keep long alignments with high mapping quality. isGood x = mapq x >= optMapq && qLength x >= optAlignmentLength good = filter (not . null) . map (filter isGood) $ excluded -- Discard contigs that have more than one alignment. -- Group contigs into scaffolds by their name. oneHit = concat . filter ((== 1) . length) $ good scaffs = groupBy ((==) `on` scaffoldName) $ oneHit -- Print SAM headers. when (optFormat == FormatSAM || optFormat == FormatSAMContigs || optFormat == FormatSAMScaffolds) (do S.putStr $ S.unlines headers) -- Print contig breakpoints. when (optFormat == FormatSAMContigs || optFormat == FormatSAM) (do mapM_ (putStrLn . showSAM) $ concat $ filter ((> 1) . length) $ good ) -- Print scaffold breakpoints. when (optFormat == FormatSAMScaffolds || optFormat == FormatSAM) (do putStr $ concat $ map (\(a, b) -> unlines [showSAM a, showSAM b]) $ concatMap filterNonColinear scaffs ) -- Exit after printing the breakpoints. when (optFormat == FormatSAM || optFormat == FormatSAMContigs || optFormat == FormatSAMScaffolds) (do exitSuccess) let genomeSize = if optGenomeSize > 0 then optGenomeSize else reference_bases ng50 = ngx 0.5 genomeSize lg50 = lgx 0.5 genomeSize -- Contig metrics mapped_contigs = length good unmapped_contigs = length unmapped mapped_bases = sum alignedContigLengths unmapped_contig_bases = sum . map seqLength $ unmapped contigLengths = map seqLength $ filter isLong primaryContigs contig_n50 = n50 contigLengths contig_na50 = n50 alignedContigLengths contig_ng50 = ng50 contigLengths contig_nga50 = ng50 alignedContigLengths contig_max = maximum contigLengths contig_aligned_max = maximum alignedContigLengths contig_l50 = l50 contigLengths contig_la50 = l50 alignedContigLengths contig_lg50 = lg50 contigLengths contig_lga50 = lg50 alignedContigLengths contigs = length contigLengths contig_breakpoints = length (concat good) - length good -- Scaffold metrics scaffoldLengths = filter (>= optContigLength) . map (sum . map seqLength) $ primaryScaffolds colinearScaffs = concatMap (groupBy' isColinear) scaffs alignedScaffoldLengths = map (sum . map qLength) $ colinearScaffs scaffold_n50 = n50 scaffoldLengths scaffold_na50 = n50 alignedScaffoldLengths scaffold_ng50 = ng50 scaffoldLengths scaffold_nga50 = ng50 alignedScaffoldLengths scaffold_max = maximum scaffoldLengths scaffold_aligned_max = maximum alignedScaffoldLengths scaffold_l50 = l50 scaffoldLengths scaffold_la50 = l50 alignedScaffoldLengths scaffold_lg50 = lg50 scaffoldLengths scaffold_lga50 = lg50 alignedScaffoldLengths scaffolds = length scaffoldLengths total_bases = sum scaffoldLengths scaffold_breakpoints = length colinearScaffs - length scaffs total_breakpoints = contig_breakpoints + scaffold_breakpoints when (optFormat == FormatText) (do when (recordIndex > 0) (putChar '\n') putStrLn $ "File: " ++ path putStr "Number of unmapped contigs: " print unmapped_contigs putStr "Total length of unmapped contigs: " print unmapped_contig_bases putStr "Number of alignments dropped due to excessive overlaps: " print $ length mapped - length concatExcluded putStr "Mapped contig bases: " print mapped_bases putStr $ "Contig N50: " print contig_n50 putStr $ "Contig NA50: " print contig_na50 putStr $ "Contig NG50: " print contig_ng50 putStr $ "Contig NGA50: " print contig_nga50 putStr $ "Contig max: " print contig_max putStr $ "Contig aligned max: " print contig_aligned_max putStr "Number of break points: " print $ length concatExcluded - length excluded putStr $ "Number of Q10 break points longer than " ++ show optAlignmentLength ++ " bp: " print contig_breakpoints -- Patch small gaps. when (optPatchGaps > 0) (do let patched = map (patchGaps optPatchGaps) excluded concatPatched = concat patched patchedGood = filter (not . null) . map (filter isGood) $ patched concatPatchedGood = concat patchedGood putStr "Number of break points after patching gaps shorter than 500 bp: " print $ length concatPatched - length patched putStr "Number of Q10 break points longer than 500 bp after gap patching: " print $ length concatPatchedGood - length patchedGood ) putStr $ "Scaffold N50: " print scaffold_n50 putStr $ "Scaffold NA50: " print scaffold_na50 putStr $ "Scaffold NG50: " print scaffold_ng50 putStr $ "Scaffold NGA50: " print scaffold_nga50 putStr $ "Scaffold max: " print scaffold_max putStr $ "Scaffold aligned max: " print scaffold_aligned_max putStr $ "Number of Q10 scaffold breakpoints longer than " ++ show optAlignmentLength ++ " bp: " print scaffold_breakpoints putStr "Number of contig and scaffold breakpoints: " print total_breakpoints ) when (optFormat == FormatTSV) (do when (recordIndex == 0) ( putStrLn ("File" ++ "\tContig_N50" ++ "\tContig_NA50" ++ "\tContig_NG50" ++ "\tContig_NGA50" ++ "\tContig_max" ++ "\tContig_aligned_max" ++ "\tScaffold_N50" ++ "\tScaffold_NA50" ++ "\tScaffold_NG50" ++ "\tScaffold_NGA50" ++ "\tScaffold_max" ++ "\tScaffold_aligned_max" ++ "\tContig_breakpoints" ++ "\tScaffold_breakpoints" ++ "\tTotal_breakpoints" ++ "\tContig_L50" ++ "\tContig_LA50" ++ "\tContig_LG50" ++ "\tContig_LGA50" ++ "\tScaffold_L50" ++ "\tScaffold_LA50" ++ "\tScaffold_LG50" ++ "\tScaffold_LGA50" ++ "\tReference_bases" ++ "\tTotal_bases" ++ "\tMapped_bases" ++ "\tUnmapped_contig_bases" ++ "\tContigs" ++ "\tMapped_contigs" ++ "\tUnmapped_contigs" ++ "\tScaffolds" ++ "\talignment-length" ++ "\tcontig-length" ++ "\tmapq" ++ "\tgenome-size") ) putStr path putStr $ '\t' : show contig_n50 putStr $ '\t' : show contig_na50 putStr $ '\t' : show contig_ng50 putStr $ '\t' : show contig_nga50 putStr $ '\t' : show contig_max putStr $ '\t' : show contig_aligned_max putStr $ '\t' : show scaffold_n50 putStr $ '\t' : show scaffold_na50 putStr $ '\t' : show scaffold_ng50 putStr $ '\t' : show scaffold_nga50 putStr $ '\t' : show scaffold_max putStr $ '\t' : show scaffold_aligned_max putStr $ '\t' : show contig_breakpoints putStr $ '\t' : show scaffold_breakpoints putStr $ '\t' : show total_breakpoints putStr $ '\t' : show contig_l50 putStr $ '\t' : show contig_la50 putStr $ '\t' : show contig_lg50 putStr $ '\t' : show contig_lga50 putStr $ '\t' : show scaffold_l50 putStr $ '\t' : show scaffold_la50 putStr $ '\t' : show scaffold_lg50 putStr $ '\t' : show scaffold_lga50 putStr $ '\t' : show reference_bases putStr $ '\t' : show total_bases putStr $ '\t' : show mapped_bases putStr $ '\t' : show unmapped_contig_bases putStr $ '\t' : show contigs putStr $ '\t' : show mapped_contigs putStr $ '\t' : show unmapped_contigs putStr $ '\t' : show scaffolds putStr $ '\t' : show optAlignmentLength putStr $ '\t' : show optContigLength putStr $ '\t' : show optMapq putStr $ '\t' : show genomeSize putChar '\n' ) -- Calculate contig and scaffold contiguity and correctness metrics. main :: IO () main = do (opt, files) <- parseArgs case files of [] -> printStats 0 "/dev/stdin" opt otherwise -> mapM_ (\(recordIndex, path) -> do printStats recordIndex path opt) (zip [0..] files) abyss-2.2.4/Overlap/000077500000000000000000000000001361462241400142535ustar00rootroot00000000000000abyss-2.2.4/Overlap/Makefile.am000066400000000000000000000003671361462241400163150ustar00rootroot00000000000000bin_PROGRAMS = Overlap Overlap_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer Overlap_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a Overlap_SOURCES = \ Overlap.cpp abyss-2.2.4/Overlap/Overlap.cpp000066400000000000000000000413531361462241400163750ustar00rootroot00000000000000/** * Find contigs that overlap and end due to a lack of coverage. * Written by Shaun Jackman . */ #include "config.h" #include "Common/Options.h" #include "ContigProperties.h" #include "Estimate.h" #include "FastaReader.h" #include "IOUtil.h" #include "Uncompress.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include #include #include #include #include #include #include // for UINT_MAX #include #include #include #include #include #include #include using namespace std; using namespace boost::lambda; #define PROGRAM "Overlap" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -o [OPTION]... CONTIGS ADJ DIST\n" "Find overlaps between blunt contigs that have negative distance\n" "estimates. Add edges to the overlap graph.\n" "\n" " Options:\n" "\n" " -k, --kmer=KMER_SIZE k-mer size\n" " -m, --min=OVERLAP require a minimum of OVERLAP bases\n" " default is 5 bases\n" " --scaffold join contigs with Ns [default]\n" " --no-scaffold do not scaffold\n" " --mask-repeat join contigs at a simple repeat and mask\n" " the repeat sequence [default]\n" " --no-merge-repeat don't join contigs at a repeat\n" " --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" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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" " --version output version information and exit\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { unsigned k; // used by ContigGraph static unsigned minimum_overlap = 5; static int mask = 1; static int scaffold = 1; /** Run a strand-specific RNA-Seq assembly. */ static int ss; /** The acceptable error of a distance estimate. */ unsigned distanceError = 6; /** Write the contig adjacency graph to this file. */ static string graphPath; /** Write the new contigs to this file. */ static string out; /** Output format */ int format = ADJ; // used by ContigProperties } static const char shortopts[] = "g:k:m:o:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "kmer", required_argument, NULL, 'k' }, { "min", required_argument, NULL, 'm' }, { "scaffold", no_argument, &opt::scaffold, 1 }, { "no-scaffold", no_argument, &opt::scaffold, 0 }, { "mask-repeat", no_argument, &opt::mask, 1 }, { "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 }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "sam", no_argument, &opt::format, SAM }, { "out", required_argument, NULL, 'o' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Contig sequences. */ static vector g_contigs; /** Contig adjacency graph. */ typedef ContigGraph > Graph; static struct { unsigned overlap; unsigned scaffold; unsigned none; unsigned tooshort; unsigned homopolymer; unsigned motif; unsigned ambiguous; } stats; /** Return the sequence of the specified contig. */ static string sequence(const ContigNode& id) { const string& seq = g_contigs[id.id()]; return id.sense() ? reverseComplement(seq) : seq; } static unsigned findOverlap(const Graph& g, const ContigNode& t_id, const ContigNode& h_id, bool& mask) { mask = false; string t = sequence(t_id); string h = sequence(h_id); unsigned len = min(t.length(), h.length()); vector overlaps; overlaps.reserve(len); for (unsigned overlap = len; overlap >= 1; overlap--) { if (t.substr(t.length()-overlap, overlap) == h.substr(0, overlap)) overlaps.push_back(overlap); } if (opt::verbose > 0) { cout << get(vertex_name, g, t_id) << '\t' << get(vertex_name, g, h_id); for (vector::const_iterator i = overlaps.begin(); i != overlaps.end(); ++i) cout << '\t' << *i; cout << '\n'; } if (overlaps.empty()) { stats.none++; return 0; } if (overlaps[0] < opt::minimum_overlap) { stats.tooshort++; return 0; } if (overlaps.size() >= 3 && overlaps[0]-overlaps[1] == overlaps[1]-overlaps[2]) { // Homopolymer run or motif. if (overlaps[0]-overlaps[1] == 1) stats.homopolymer++; else stats.motif++; mask = true; } return overlaps[0]; } static FastaRecord newContig(const Graph& g, const ContigNode& t, const ContigNode& v, int dist, const string& seq) { ostringstream comment; comment << seq.length() << " 0 " << get(vertex_name, g, t) << ' ' << get(vertex_name, g, v) << ' ' << dist; return FastaRecord(createContigName(), comment.str(), seq); } /** An overlap of two sequences. */ struct Overlap : public DistanceEst { unsigned overlap; bool mask; Overlap() : overlap(UINT_MAX), mask(false) { } Overlap(int) { assert(false); } Overlap(const DistanceEst& est, unsigned overlap, bool mask) : DistanceEst(est), overlap(overlap), mask(mask) { } bool operator==(const Overlap& o) const { return overlap == o.overlap; } operator Distance() const { assert(overlap > 0); return -overlap; } friend ostream& operator<<(ostream& out, const Overlap& o) { return out << "d=" << (o.overlap > 0 ? -(int)o.overlap : o.distance); } }; /** Create a contig representing the gap between contigs u and v. */ static FastaRecord createGapContig(const Graph& g, const ContigNode& u, const ContigNode& v, const Overlap& o) { assert(opt::scaffold); assert(o.overlap == 0); stats.scaffold++; int distance = o.distance; if (opt::verbose > 0) cout << get(vertex_name, g, u) << '\t' << get(vertex_name, g, v) << "\t(" << distance << ")\n"; assert(distance < 100000); string gap = distance <= 0 ? string("n") : string(distance, 'N'); const string& useq = sequence(u); const string& vseq = sequence(v); unsigned overlap = opt::k - 1; // by convention return newContig(g, u, v, distance, useq.substr(useq.length() - overlap) + gap + vseq.substr(0, overlap)); } /** The scaffold graph. Edges join two blunt contigs that are joined * by a distance estimate. */ typedef ContigGraph > OverlapGraph; /** * Check for an overlap between the specified pair of contigs. * Add the size of the overlap to the edge properties. Add the * complementary edge if it does not exist in the graph. * @param goverlap the contig overlap graph * @param g the scaffold graph * @return true if the contigs overlap */ static bool checkEdgeForOverlap(const Graph& goverlap, OverlapGraph& g, graph_traits::edge_descriptor e) { typedef graph_traits::vertex_descriptor V; typedef graph_traits::edge_descriptor E; typedef edge_bundle_type::type EP; V u = source(e, g), v = target(e, g); V uc = get(vertex_complement, g, u); V vc = get(vertex_complement, g, v); assert(u != v); assert(u != vc); EP& ep = g[e]; if (ep.overlap != UINT_MAX) { // Found the complementary overlap. return ep.overlap > 0 || opt::scaffold; } if (ep.distance >= 0 && !opt::scaffold) { // Positive distance estimate and not scaffolding. return false; } if (out_degree(u, goverlap) > 0 || in_degree(v, goverlap) > 0) { // Not blunt. return false; } bool mask = false; unsigned overlap = ep.distance - (int)allowedError(ep.stdDev) <= 0 ? findOverlap(goverlap, u, v, mask) : 0; if (mask && !opt::mask) { // Ambiguous overlap. return false; } if (overlap == 0 && !opt::scaffold) { // No overlap and not scaffolding. return false; } ep.overlap = overlap; ep.mask = mask; pair ecomplement = edge(vc, uc, g); if (ecomplement.second) { // Modify the complementary edge. g[ecomplement.first] = ep; } else { // Add the complementary edge. assert(vc != u); add_edge(vc, uc, ep, static_cast(g)); } return true; } static void findOverlap(const Graph& g, ContigID refID, bool rc, const ContigNode& pair, const DistanceEst& est, OverlapGraph& out) { if (refID == pair.id() || (est.distance >= 0 && !opt::scaffold)) return; ContigNode ref(refID, false); const ContigNode& t = rc ? pair : ref; const ContigNode& h = rc ? ref : pair; if (out_degree(t, g) > 0 || in_degree(h, g) > 0 || edge(t, h, out).second) return; bool mask = false; unsigned overlap = est.distance - (int)allowedError(est.stdDev) <= 0 ? findOverlap(g, t, h, mask) : 0; if (mask && !opt::mask) return; if (overlap > 0 || opt::scaffold) add_edge(t, h, Overlap(est, overlap, mask), out); } static void readContigs(const char *contigPath) { FastaReader in(contigPath, FastaReader::FOLD_CASE); for (FastaRecord rec; in >> rec;) g_contigs.push_back(rec.seq); assert(in.eof()); assert(!g_contigs.empty()); opt::colourSpace = isdigit(g_contigs[0][0]); } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } 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 'g': arg >> opt::graphPath; break; case 'k': arg >> opt::k; break; case 'm': arg >> opt::minimum_overlap; break; case 'o': arg >> opt::out; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (opt::out.empty()) { cerr << PROGRAM ": " << "missing -o,--out option\n"; die = true; } if (argc - optind < 3) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (argc - optind > 3) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } const char* contigPath(argv[optind++]); string adjPath(argv[optind++]); string estPath(argv[optind++]); readContigs(contigPath); // Read the contig adjacency graph. ifstream fin(adjPath.c_str()); assert_good(fin, adjPath); Graph graph; fin >> graph; assert(fin.eof()); g_contigNames.lock(); // Open the output file. ofstream out(opt::out.c_str()); assert_good(out, opt::out); // Read the scaffold graph. ifstream in(estPath.c_str()); assert_good(in, estPath); // Find overlapping contigs. OverlapGraph scaffoldGraph(graph.num_vertices() / 2); if (in.peek() == 'd') { // dot graph format in >> scaffoldGraph; assert(in.eof()); if (opt::verbose > 0) printGraphStats(cout, scaffoldGraph); remove_edge_if( !boost::lambda::bind(checkEdgeForOverlap, boost::cref(graph), boost::ref(scaffoldGraph), _1), static_cast(scaffoldGraph)); } else { // dist graph format for (EstimateRecord er; in >> er;) { for (int sense = false; sense <= true; ++sense) { typedef vector< pair > Estimates; const Estimates& ests = er.estimates[sense]; for (Estimates::const_iterator it = ests.begin(); it != ests.end(); ++it) findOverlap(graph, er.refID, sense, it->first, it->second, scaffoldGraph); } } assert(in.eof()); } in.close(); if (opt::verbose > 1) cout << dot_writer(scaffoldGraph); typedef graph_traits::vertex_descriptor vertex_descriptor; typedef graph_traits::vertex_iterator vertex_iterator; typedef graph_traits::edge_descriptor edge_descriptor; typedef graph_traits::out_edge_iterator out_edge_iterator; /** The overlapping edges (d<0) of scaffoldGraph. */ OverlapGraph overlapGraph(num_vertices(graph) / 2); /** The canonical edges of scaffoldGraph. */ unsigned numOverlaps = num_edges(scaffoldGraph) / 2; typedef vector Edges; Edges edges; edges.reserve(numOverlaps); // Create the set of canonical edges and the overlap subgraph. std::pair uit = vertices(scaffoldGraph); for (vertex_iterator u = uit.first; u != uit.second; ++u) { std::pair vit = out_edges(*u, scaffoldGraph); for (out_edge_iterator e = vit.first; e != vit.second; ++e) { vertex_descriptor v = target(*e, scaffoldGraph); assert(*u != v); if (v < *u) continue; edges.push_back(*e); const Overlap& ep = get(edge_bundle, scaffoldGraph, e); if (ep.overlap > 0) add_edge(*u, v, ep, overlapGraph); } } assert(edges.size() == numOverlaps); // First, give priority to overlapping edges (not scaffolded). for (Edges::const_iterator it = edges.begin(); it != edges.end(); ++it) { const ContigNode& t = source(*it, overlapGraph), h = target(*it, overlapGraph); if (!edge(t, h, overlapGraph).second) { // This edge is scaffolded. continue; } const Overlap& overlap = get(edge_bundle, overlapGraph, *it); assert(overlap.overlap > 0); if (contiguous_out(overlapGraph, t)) { stats.overlap++; assert(*adjacent_vertices(t, overlapGraph).first == h); add_edge(t, h, overlap, graph); // Clear the out-edges of t and the in-edges of h. clear_out_edges(t, scaffoldGraph); clear_in_edges(h, scaffoldGraph); } else stats.ambiguous++; } overlapGraph.clear(); // Second, handle scaffolded edges. g_contigNames.unlock(); for (Edges::const_iterator it = edges.begin(); it != edges.end(); ++it) { const ContigNode& t = source(*it, scaffoldGraph), h = target(*it, scaffoldGraph); if (!edge(t, h, scaffoldGraph).second) { // This edge involved a vertex that has already been used // and removed. continue; } const Overlap& overlap = get(edge_bundle, scaffoldGraph, *it); if (overlap.overlap > 0) { // This edge is not scaffolded. } else if (contiguous_out(scaffoldGraph, t)) { assert(*adjacent_vertices(t, scaffoldGraph).first == h); ContigNode t1 = t, h1 = h; if (opt::ss && t.sense() && h.sense()) { t1 = h ^ true; h1 = t ^ true; } FastaRecord contig = createGapContig(graph, t1, h1, overlap); out << contig; assert(out.good()); // Add the new contig to the adjacency graph. vertex_descriptor v = add_vertex( ContigProperties(contig.seq.length(), 0), graph); put(vertex_name, graph, v, contig.id); add_edge(t1, v, graph); add_edge(v, h1, graph); } else stats.ambiguous++; } g_contigNames.lock(); out.close(); if (!opt::graphPath.empty()) { // Output the updated adjacency graph. ofstream fout(opt::graphPath.c_str()); assert_good(fout, opt::graphPath); write_graph(fout, graph, PROGRAM, commandLine); assert_good(fout, opt::graphPath); } cout << "Overlap: " << stats.overlap << "\n" "Scaffold: " << stats.scaffold << "\n" "No overlap: " << stats.none << "\n" "Insignificant (<" << opt::minimum_overlap << "bp): " << stats.tooshort << "\n" "Homopolymer: " << stats.homopolymer << "\n" "Motif: " << stats.motif << "\n" "Ambiguous: " << stats.ambiguous << "\n"; return 0; } abyss-2.2.4/PairedDBG/000077500000000000000000000000001361462241400143645ustar00rootroot00000000000000abyss-2.2.4/PairedDBG/BranchRecord.h000066400000000000000000000022321361462241400170700ustar00rootroot00000000000000#ifndef PAIREDDBG_BRANCHRECORD_H #define PAIREDDBG_BRANCHRECORD_H 1 #include "Common/Options.h" // for opt::verbose /** Generate the sequence of this contig. */ template 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 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(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 abyss-2.2.4/PairedDBG/Dinuc.h000066400000000000000000000063421361462241400156040ustar00rootroot00000000000000#ifndef PAIREDDBG_DINUC_H #define PAIREDDBG_DINUC_H 1 #include "Common/BitUtil.h" #include #include /** 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 abyss-2.2.4/PairedDBG/KmerPair.cc000066400000000000000000000001521361462241400164030ustar00rootroot00000000000000#include "KmerPair.h" /** The length of a k-mer pair, including the gap. */ unsigned KmerPair::s_length; abyss-2.2.4/PairedDBG/KmerPair.h000066400000000000000000000111551361462241400162520ustar00rootroot00000000000000#ifndef PAIREDDBG_KMERPAIR_H #define PAIREDDBG_KMERPAIR_H 1 #include "Dinuc.h" #include "Common/Kmer.h" #include #include /** 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 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 { size_t operator()(const KmerPair& u) const { return u.getHashCode(); } }; NAMESPACE_STD_HASH_END #endif abyss-2.2.4/PairedDBG/Makefile.am000066400000000000000000000011131361462241400164140ustar00rootroot00000000000000if 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 abyss-2.2.4/PairedDBG/PairedDBGAlgorithms.h000066400000000000000000000022231361462241400203070ustar00rootroot00000000000000#ifndef PairedDBG_PairedDBGAlgorithms_h #define PairedDBG_PairedDBGAlgorithms_h 1 #include "Graph/GraphAlgorithms.h" // for removeEdgeIf #include /** Return true if a paired dBG edge is inconsistent. * This predicate is only valid when the size of the gap is exactly zero. */ template struct InconsistentPairedDBGEdge { InconsistentPairedDBGEdge(Graph& g) : m_g(g) { } bool operator()(typename graph_traits::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 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(g), g) << " inconsistent edges.\n"; } } #endif abyss-2.2.4/PairedDBG/SequenceCollection.h000066400000000000000000000011121361462241400203140ustar00rootroot00000000000000#ifndef PAIREDDBG_SEQUENCECOLLECTION_H #define PAIREDDBG_SEQUENCECOLLECTION_H 1 #include "config.h" #include "Dinuc.h" #include "KmerPair.h" #include "Assembly/VertexData.h" typedef VertexData KmerPairData; #if HAVE_GOOGLE_SPARSE_HASH_MAP # include typedef google::sparse_hash_map > SequenceDataHash; #else # include "Common/UnorderedMap.h" typedef unordered_map > SequenceDataHash; #endif #include "Assembly/DBG.h" #include "PairedDBG/BranchRecord.h" #endif abyss-2.2.4/PairedDBG/abyss-paired-dbg.cc000066400000000000000000000000321361462241400200030ustar00rootroot00000000000000#include "ABYSS/abyss.cc" abyss-2.2.4/Parallel/000077500000000000000000000000001361462241400143775ustar00rootroot00000000000000abyss-2.2.4/Parallel/CommLayer.cpp000066400000000000000000000153641361462241400170040ustar00rootroot00000000000000#include "config.h" #include "CommLayer.h" #include "MessageBuffer.h" #include "Common/Log.h" #include "Common/Options.h" #include #include #include using namespace std; static const unsigned RX_BUFSIZE = 16*1024; CommLayer::CommLayer() : m_msgID(0), m_rxBuffer(new uint8_t[RX_BUFSIZE]), m_request(MPI_REQUEST_NULL), m_rxPackets(0), m_rxMessages(0), m_rxBytes(0), m_txPackets(0), m_txMessages(0), m_txBytes(0) { assert(m_request == MPI_REQUEST_NULL); MPI_Irecv(m_rxBuffer, RX_BUFSIZE, MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &m_request); } CommLayer::~CommLayer() { MPI_Cancel(&m_request); delete[] m_rxBuffer; logger(1) << "Sent " << m_msgID << " control, " << m_txPackets << " packets, " << m_txMessages << " messages, " << m_txBytes << " bytes. " << "Received " << m_rxPackets << " packets, " << m_rxMessages << " messages, " << m_rxBytes << " bytes.\n"; } /** Return the status of an MPI request. * Wraps MPI_Request_get_status. */ static bool request_get_status(const MPI_Request& req, MPI_Status& status) { int flag; MPI_Request_get_status(req, &flag, &status); // Work around a bug present in Open MPI 1.3.3 and earlier. // MPI_Request_get_status may return false on the first call even // though a message is waiting. The second call should work. if (!flag) MPI_Request_get_status(req, &flag, &status); return flag; } /** Return the tag of the received message or APM_NONE if no message * has been received. If a message has been received, this call should * be followed by a call to either ReceiveControlMessage or * ReceiveBufferedMessage. */ APMessage CommLayer::checkMessage(int& sendID) { MPI_Status status; bool flag = request_get_status(m_request, status); if (flag) sendID = status.MPI_SOURCE; return flag ? (APMessage)status.MPI_TAG : APM_NONE; } /** Return true if no message has been received. */ bool CommLayer::receiveEmpty() { MPI_Status status; return !request_get_status(m_request, status); } /** Block until all processes have reached this routine. */ void CommLayer::barrier() { logger(4) << "entering barrier\n"; MPI_Barrier(MPI_COMM_WORLD); logger(4) << "left barrier\n"; } /** Broadcast a message. */ void CommLayer::broadcast(int message) { assert(opt::rank == 0); MPI_Bcast(&message, 1, MPI_INT, 0, MPI_COMM_WORLD); barrier(); } /** Receive a broadcast message. */ int CommLayer::receiveBroadcast() { assert(opt::rank != 0); int message; MPI_Bcast(&message, 1, MPI_INT, 0, MPI_COMM_WORLD); barrier(); return message; } /** Block until all processes have reached this routine. * @return the sum of count from all processors */ long long unsigned CommLayer::reduce(long long unsigned count) { logger(4) << "entering reduce: " << count << '\n'; long long unsigned sum; MPI_Allreduce(&count, &sum, 1, MPI_UNSIGNED_LONG_LONG, MPI_SUM, MPI_COMM_WORLD); logger(4) << "left reduce: " << sum << '\n'; return sum; } /** Reduce the specified vector. */ vector CommLayer::reduce(const vector& v) { logger(4) << "entering reduce\n"; vector sum(v.size()); MPI_Allreduce(const_cast(&v[0]), &sum[0], v.size(), MPI_UNSIGNED, MPI_SUM, MPI_COMM_WORLD); logger(4) << "left reduce\n"; return sum; } /** Reduce the specified vector. */ vector CommLayer::reduce( const vector& v) { logger(4) << "entering reduce\n"; vector sum(v.size()); MPI_Allreduce(const_cast(&v[0]), &sum[0], v.size(), MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); logger(4) << "left reduce\n"; return sum; } uint64_t CommLayer::sendCheckPointMessage(int argument) { logger(4) << "checkpoint: " << argument << '\n'; assert(opt::rank != 0); ControlMessage msg; msg.id = m_msgID++; msg.msgType = APC_CHECKPOINT; msg.argument = argument; MPI_Send(&msg, sizeof msg, MPI_BYTE, 0, APM_CONTROL, MPI_COMM_WORLD); return msg.id; } /** Send a control message to every other process. */ void CommLayer::sendControlMessage(APControl m, int argument) { for (int i = 0; i < opt::numProc; i++) if (i != opt::rank) // Don't send the message to myself. sendControlMessageToNode(i, m, argument); } /** Send a control message to a specific node. */ uint64_t CommLayer::sendControlMessageToNode(int nodeID, APControl m, int argument) { assert(opt::rank == 0); ControlMessage msg; msg.id = m_msgID++; msg.msgType = m; msg.argument = argument; MPI_Send(&msg, sizeof msg, MPI_BYTE, nodeID, APM_CONTROL, MPI_COMM_WORLD); return msg.id; } /** Receive a control message. */ ControlMessage CommLayer::receiveControlMessage() { int flag; MPI_Status status; MPI_Test(&m_request, &flag, &status); assert(flag); assert((APMessage)status.MPI_TAG == APM_CONTROL); int count; MPI_Get_count(&status, MPI_BYTE, &count); ControlMessage msg; assert(count == sizeof msg); memcpy(&msg, m_rxBuffer, sizeof msg); assert(m_request == MPI_REQUEST_NULL); MPI_Irecv(m_rxBuffer, RX_BUFSIZE, MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &m_request); return msg; } /** Send a buffered collection of messages. */ void CommLayer::sendBufferedMessage(int destID, char* msg, size_t size) { MPI_Send(msg, size, MPI_BYTE, destID, APM_BUFFERED, MPI_COMM_WORLD); } /** Receive a buffered message. */ void CommLayer::receiveBufferedMessage(MessagePtrVector& outmessages) { assert(outmessages.empty()); int flag; MPI_Status status; MPI_Test(&m_request, &flag, &status); assert(flag); assert((APMessage)status.MPI_TAG == APM_BUFFERED); int size; MPI_Get_count(&status, MPI_BYTE, &size); int offset = 0; while (offset < size) { MessageType type = Message::readMessageType( (char*)m_rxBuffer + offset); Message* pNewMessage; switch(type) { case MT_ADD: pNewMessage = new SeqAddMessage(); break; case MT_REMOVE: pNewMessage = new SeqRemoveMessage(); break; case MT_SET_FLAG: pNewMessage = new SetFlagMessage(); break; case MT_REMOVE_EXT: pNewMessage = new RemoveExtensionMessage(); break; case MT_SEQ_DATA_REQUEST: pNewMessage = new SeqDataRequest(); break; case MT_SEQ_DATA_RESPONSE: pNewMessage = new SeqDataResponse(); break; case MT_SET_BASE: pNewMessage = new SetBaseMessage(); break; default: assert(false); break; } // Unserialize the new message from the buffer offset += pNewMessage->unserialize( (char*)m_rxBuffer + offset); // Constructed message will be deleted in the // NetworkSequenceCollection calling function. outmessages.push_back(pNewMessage); } assert(offset == size); assert(m_request == MPI_REQUEST_NULL); MPI_Irecv(m_rxBuffer, RX_BUFSIZE, MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &m_request); m_rxPackets++; m_rxMessages += outmessages.size(); m_rxBytes += size; } abyss-2.2.4/Parallel/CommLayer.h000066400000000000000000000040241361462241400164400ustar00rootroot00000000000000#ifndef COMMLAYER_H #define COMMLAYER_H 1 #include "Messages.h" #include #include enum APMessage { APM_NONE, APM_CONTROL, APM_BUFFERED }; enum APControl { APC_SET_STATE, APC_ERODE_COMPLETE, APC_TRIM, APC_POPBUBBLE, APC_ASSEMBLE, APC_CHECKPOINT, APC_WAIT, APC_BARRIER, }; typedef std::vector MessagePtrVector; struct ControlMessage { int64_t id; APControl msgType; int argument; }; /** Interprocess communication and synchronization primitives. */ class CommLayer { public: CommLayer(); ~CommLayer(); // Check if a message exists, if it does return the type APMessage checkMessage(int &sendID); // Return whether a message has been received. bool receiveEmpty(); // Block until all processes have reached this routine. void barrier(); void broadcast(int message); int receiveBroadcast(); // Block until all processes have reached this routine. long long unsigned reduce(long long unsigned count); std::vector reduce(const std::vector& v); std::vector reduce( const std::vector& v); // Send a control message void sendControlMessage(APControl m, int argument = 0); // Send a control message to a specific node uint64_t sendControlMessageToNode(int nodeID, APControl command, int argument = 0); // Receive a control message ControlMessage receiveControlMessage(); // Send a message that the checkpoint has been reached uint64_t sendCheckPointMessage(int argument = 0); // Send a buffered message void sendBufferedMessage(int destID, char* msg, size_t size); // Receive a buffered sequence of messages void receiveBufferedMessage(MessagePtrVector& outmessages); uint64_t reduceInflight() { return reduce(m_txPackets - m_rxPackets); } private: uint64_t m_msgID; uint8_t* m_rxBuffer; MPI_Request m_request; protected: // Counters uint64_t m_rxPackets; uint64_t m_rxMessages; uint64_t m_rxBytes; uint64_t m_txPackets; uint64_t m_txMessages; uint64_t m_txBytes; }; #endif abyss-2.2.4/Parallel/Makefile.am000066400000000000000000000013231361462241400164320ustar00rootroot00000000000000bin_PROGRAMS = ABYSS-P if PAIRED_DBG bin_PROGRAMS += abyss-paired-dbg-mpi endif 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 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) abyss-2.2.4/Parallel/MessageBuffer.cpp000066400000000000000000000073661361462241400176350ustar00rootroot00000000000000#include "MessageBuffer.h" #include "Common/Options.h" #include using namespace std; MessageBuffer::MessageBuffer() : m_msgQueues(opt::numProc) { for (unsigned i = 0; i < m_msgQueues.size(); i++) m_msgQueues[i].reserve(MAX_MESSAGES); } void MessageBuffer::sendSeqAddMessage(int nodeID, const V& seq) { queueMessage(nodeID, new SeqAddMessage(seq), SM_BUFFERED); } 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 V& seq, SeqFlag flag) { queueMessage(nodeID, new SetFlagMessage(seq, flag), SM_BUFFERED); } // Send a remove extension message void MessageBuffer::sendRemoveExtension(int nodeID, const V& seq, extDirection dir, SymbolSet ext) { queueMessage(nodeID, new RemoveExtensionMessage(seq, dir, ext), SM_BUFFERED); } // Send a sequence data request void MessageBuffer::sendSeqDataRequest(int nodeID, IDType group, IDType id, const V& seq) { queueMessage(nodeID, new SeqDataRequest(seq, group, id), SM_IMMEDIATE); } // Send a sequence data response void MessageBuffer::sendSeqDataResponse(int nodeID, IDType group, IDType id, const V& seq, SymbolSetPair extRec, int multiplicity) { queueMessage(nodeID, new SeqDataResponse(seq, group, id, extRec, multiplicity), SM_IMMEDIATE); } // Send a set base message void MessageBuffer::sendSetBaseExtension(int nodeID, const V& seq, extDirection dir, Symbol base) { queueMessage(nodeID, new SetBaseMessage(seq, dir, base), SM_BUFFERED); } void MessageBuffer::queueMessage( int nodeID, Message* message, SendMode mode) { if (opt::verbose >= 9) cout << opt::rank << " to " << nodeID << ": " << *message; m_msgQueues[nodeID].push_back(message); checkQueueForSend(nodeID, mode); } void MessageBuffer::checkQueueForSend(int nodeID, SendMode mode) { size_t numMsgs = m_msgQueues[nodeID].size(); // check if the messages should be sent if ((numMsgs == MAX_MESSAGES || mode == SM_IMMEDIATE) && numMsgs > 0) { // Calculate the total size of the message size_t totalSize = 0; for(size_t i = 0; i < numMsgs; i++) { totalSize += m_msgQueues[nodeID][i]->getNetworkSize(); } // Generate a buffer for all the messages char* buffer = new char[totalSize]; // Copy the messages into the buffer size_t offset = 0; for(size_t i = 0; i < numMsgs; i++) offset += m_msgQueues[nodeID][i]->serialize( buffer + offset); assert(offset == totalSize); sendBufferedMessage(nodeID, buffer, totalSize); delete [] buffer; clearQueue(nodeID); m_txPackets++; m_txMessages += numMsgs; m_txBytes += totalSize; } } // Clear a queue of messages void MessageBuffer::clearQueue(int nodeID) { size_t numMsgs = m_msgQueues[nodeID].size(); for(size_t i = 0; i < numMsgs; i++) { // Delete the messages delete m_msgQueues[nodeID][i]; m_msgQueues[nodeID][i] = 0; } m_msgQueues[nodeID].clear(); } // Flush the message buffer by sending all messages that are queued void MessageBuffer::flush() { // Send all messages in all queues for(size_t id = 0; id < m_msgQueues.size(); ++id) { // force the queue to send any pending messages checkQueueForSend(id, SM_IMMEDIATE); } } // Check if all the queues are empty bool MessageBuffer::transmitBufferEmpty() const { bool isEmpty = true; for (MessageQueues::const_iterator it = m_msgQueues.begin(); it != m_msgQueues.end(); ++it) { if (!it->empty()) { cerr << opt::rank << ": error: tx buffer should be empty: " << it->size() << " messages from " << opt::rank << " to " << it - m_msgQueues.begin() << '\n'; for (MsgBuffer::const_iterator j = it->begin(); j != it->end(); ++j) cerr << **j << '\n'; isEmpty = false; } } return isEmpty; } abyss-2.2.4/Parallel/MessageBuffer.h000066400000000000000000000040701361462241400172670ustar00rootroot00000000000000#ifndef MESSAGE_BUFFER_H #define MESSAGE_BUFFER_H 1 class MessageBuffer; #include "CommLayer.h" #include "Messages.h" #include typedef std::vector MsgBuffer; typedef std::vector MessageQueues; enum SendMode { SM_BUFFERED, SM_IMMEDIATE }; /** A buffer of Message. */ class MessageBuffer : public CommLayer { public: typedef SequenceCollectionHash Graph; typedef graph_traits::vertex_descriptor V; typedef Graph::Symbol Symbol; typedef Graph::SymbolSet SymbolSet; typedef Graph::SymbolSetPair SymbolSetPair; MessageBuffer(); void sendCheckPointMessage(int argument = 0) { assert(transmitBufferEmpty()); CommLayer::sendCheckPointMessage(argument); } void sendControlMessage(APControl command, int argument = 0) { assert(transmitBufferEmpty()); CommLayer::sendControlMessage(command, argument); } void sendControlMessageToNode(int dest, APControl command, int argument = 0) { assert(transmitBufferEmpty()); CommLayer::sendControlMessageToNode(dest, command, argument); } void sendSeqAddMessage(int nodeID, const V& seq); void sendSeqRemoveMessage(int nodeID, const V& seq); void sendSetFlagMessage(int nodeID, const V& seq, SeqFlag flag); void sendRemoveExtension(int nodeID, const V& seq, extDirection dir, SymbolSet ext); void sendSeqDataRequest(int nodeID, IDType group, IDType id, const V& seq); void sendSeqDataResponse(int nodeID, IDType group, IDType id, const V& seq, SymbolSetPair extRec, int multiplicity); void sendSetBaseExtension(int nodeID, const V& seq, extDirection dir, Symbol base); void flush(); void queueMessage (int nodeID, Message* message, SendMode mode); // clear out a queue void clearQueue(int nodeID); bool transmitBufferEmpty() const; // check if a queue is full, if so, send the messages if the // immediate mode flag is set, send even if the queue is not // full. void checkQueueForSend(int nodeID, SendMode mode); private: static const size_t MAX_MESSAGES = 100; MessageQueues m_msgQueues; }; #endif abyss-2.2.4/Parallel/Messages.cpp000066400000000000000000000113511361462241400166530ustar00rootroot00000000000000#include "Messages.h" #include "NetworkSequenceCollection.h" #include static size_t serializeData(const void* ptr, char* buffer, size_t size) { memcpy(buffer, ptr, size); return size; } static size_t unserializeData(void* ptr, const char* buffer, size_t size) { memcpy(ptr, buffer, size); return size; } MessageType Message::readMessageType(char* buffer) { return (MessageType)*(uint8_t*)buffer; } size_t Message::unserialize(const char* buffer) { size_t offset = 0; offset++; // MessageType offset += m_seq.unserialize(buffer + offset); return offset; } size_t SeqAddMessage::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); return offset; } void SeqAddMessage::handle(int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } size_t SeqRemoveMessage::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); return offset; } void SeqRemoveMessage::handle(int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } size_t SetFlagMessage::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); offset += serializeData(&m_flag, buffer + offset, sizeof(m_flag)); return offset; } size_t SetFlagMessage::unserialize(const char* buffer) { size_t offset = 0; offset += Message::unserialize(buffer); offset += unserializeData( &m_flag, buffer + offset, sizeof(m_flag)); return offset; } void SetFlagMessage::handle( int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } size_t RemoveExtensionMessage::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); offset += serializeData(&m_dir, buffer + offset, sizeof m_dir); offset += serializeData(&m_ext, buffer + offset, sizeof m_ext); return offset; } size_t RemoveExtensionMessage::unserialize(const char* buffer) { size_t offset = 0; offset += Message::unserialize(buffer); offset += unserializeData(&m_dir, buffer + offset, sizeof m_dir); offset += unserializeData(&m_ext, buffer + offset, sizeof m_ext); return offset; } void RemoveExtensionMessage::handle( int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } size_t SetBaseMessage::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); offset += serializeData(&m_dir, buffer + offset, sizeof(m_dir)); offset += serializeData(&m_base, buffer + offset, sizeof(m_base)); return offset; } size_t SetBaseMessage::unserialize(const char* buffer) { size_t offset = 0; offset += Message::unserialize(buffer); offset += unserializeData(&m_dir, buffer + offset, sizeof(m_dir)); offset += unserializeData( &m_base, buffer + offset, sizeof(m_base)); return offset; } void SetBaseMessage::handle( int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } size_t SeqDataRequest::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); offset += serializeData( &m_group, buffer + offset, sizeof(m_group)); offset += serializeData(&m_id, buffer + offset, sizeof(m_id)); return offset; } size_t SeqDataRequest::unserialize(const char* buffer) { size_t offset = 0; offset += Message::unserialize(buffer); offset += unserializeData( &m_group, buffer + offset, sizeof(m_group)); offset += unserializeData(&m_id, buffer + offset, sizeof(m_id)); return offset; } void SeqDataRequest::handle( int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } size_t SeqDataResponse::serialize(char* buffer) { size_t offset = 0; buffer[offset++] = TYPE; offset += m_seq.serialize(buffer + offset); offset += serializeData( &m_group, buffer + offset, sizeof(m_group)); offset += serializeData( &m_id, buffer + offset, sizeof(m_id)); offset += serializeData( &m_extRecord, buffer + offset, sizeof(m_extRecord)); offset += serializeData( &m_multiplicity, buffer + offset, sizeof(m_multiplicity)); return offset; } size_t SeqDataResponse::unserialize(const char* buffer) { size_t offset = 0; offset += Message::unserialize(buffer); offset += unserializeData( &m_group, buffer + offset, sizeof(m_group)); offset += unserializeData( &m_id, buffer + offset, sizeof(m_id)); offset += unserializeData( &m_extRecord, buffer + offset, sizeof(m_extRecord)); offset += unserializeData( &m_multiplicity, buffer + offset, sizeof(m_multiplicity)); return offset; } void SeqDataResponse::handle( int senderID, NetworkSequenceCollection& handler) { handler.handle(senderID, *this); } abyss-2.2.4/Parallel/Messages.h000066400000000000000000000113071361462241400163210ustar00rootroot00000000000000#ifndef MESSAGES_H #define MESSAGES_H 1 #include "SequenceCollection.h" #include class NetworkSequenceCollection; enum MessageType { MT_VOID, MT_ADD, MT_REMOVE, MT_SET_FLAG, MT_REMOVE_EXT, MT_SEQ_DATA_REQUEST, MT_SEQ_DATA_RESPONSE, MT_SET_BASE }; enum MessageOp { MO_VOID, MO_ADD, MO_REMOVE, }; typedef uint32_t IDType; /** The base class of all interprocess messages. */ class Message { public: typedef SequenceCollectionHash Graph; typedef graph_traits::vertex_descriptor V; typedef Graph::Symbol Symbol; typedef Graph::SymbolSet SymbolSet; typedef Graph::SymbolSetPair SymbolSetPair; Message() { } Message(const V& seq) : m_seq(seq) { } virtual ~Message() { } virtual void handle( int senderID, NetworkSequenceCollection& handler) = 0; virtual size_t getNetworkSize() const { return sizeof (uint8_t) // MessageType + V::serialSize(); } static MessageType readMessageType(char* buffer); virtual size_t serialize(char* buffer) = 0; virtual size_t unserialize(const char* buffer); friend std::ostream& operator <<(std::ostream& out, const Message& message) { return out << message.m_seq.str() << '\n'; } V m_seq; }; /** Add a vertex. */ class SeqAddMessage : public Message { public: SeqAddMessage() { } SeqAddMessage(const V& seq) : Message(seq) { } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); static const MessageType TYPE = MT_ADD; }; /** Remove a vertex. */ class SeqRemoveMessage : public Message { public: SeqRemoveMessage() { } SeqRemoveMessage(const V& seq) : Message(seq) { } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); static const MessageType TYPE = MT_REMOVE; }; /** Set a flag. */ class SetFlagMessage : public Message { public: SetFlagMessage() { } SetFlagMessage(const V& seq, SeqFlag flag) : Message(seq), m_flag(flag) { } size_t getNetworkSize() const { return Message::getNetworkSize() + sizeof m_flag; } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); size_t unserialize(const char* buffer); static const MessageType TYPE = MT_SET_FLAG; uint8_t m_flag; // SeqFlag }; /** Remove an edge. */ class RemoveExtensionMessage : public Message { public: RemoveExtensionMessage() { } RemoveExtensionMessage(const V& seq, extDirection dir, SymbolSet ext) : Message(seq), m_dir(dir), m_ext(ext) { } size_t getNetworkSize() const { return Message::getNetworkSize() + sizeof m_dir + sizeof m_ext; } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); size_t unserialize(const char* buffer); static const MessageType TYPE = MT_REMOVE_EXT; uint8_t m_dir; // extDirection SymbolSet m_ext; }; /** Request vertex properties. */ class SeqDataRequest : public Message { public: SeqDataRequest() { } SeqDataRequest(const V& seq, IDType group, IDType id) : Message(seq), m_group(group), m_id(id) { } size_t getNetworkSize() const { return Message::getNetworkSize() + sizeof m_group + sizeof m_id; } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); size_t unserialize(const char* buffer); static const MessageType TYPE = MT_SEQ_DATA_REQUEST; IDType m_group; IDType m_id; }; /** The response to a request for vertex properties. */ class SeqDataResponse : public Message { public: SeqDataResponse() { } 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) { } size_t getNetworkSize() const { return Message::getNetworkSize() + sizeof m_group + sizeof m_id + sizeof m_extRecord + sizeof m_multiplicity; } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); size_t unserialize(const char* buffer); static const MessageType TYPE = MT_SEQ_DATA_RESPONSE; IDType m_group; IDType m_id; SymbolSetPair m_extRecord; uint16_t m_multiplicity; }; /** Add an edge. */ class SetBaseMessage : public Message { public: SetBaseMessage() { } SetBaseMessage(const V& seq, extDirection dir, Symbol base) : Message(seq), m_dir(dir), m_base(base) { } size_t getNetworkSize() const { return Message::getNetworkSize() + sizeof m_dir + sizeof m_base; } void handle(int senderID, NetworkSequenceCollection& handler); size_t serialize(char* buffer); size_t unserialize(const char* buffer); static const MessageType TYPE = MT_SET_BASE; uint8_t m_dir; // extDirection Symbol m_base; }; #endif abyss-2.2.4/Parallel/NetworkSequenceCollection.cpp000066400000000000000000001163731361462241400222540ustar00rootroot00000000000000#include "NetworkSequenceCollection.h" #include "Assembly/AssemblyAlgorithms.h" #include "Assembly/Options.h" #include "Common/Histogram.h" #include "Common/Log.h" #include "Common/Options.h" #include "Common/StringUtil.h" #include "DataLayer/FastaWriter.h" #include // for UINT_MAX #include #include #include #include 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. const int DEDICATE_CONTROL_AT = 1000; void NetworkSequenceCollection::loadSequences() { Timer timer("LoadSequences"); for (unsigned i = opt::rank; i < opt::inFiles.size(); i += opt::numProc) AssemblyAlgorithms::loadSequences(this, opt::inFiles[i]); } /** Receive, process, send, and synchronize. * @return the number of inflight messages */ size_t NetworkSequenceCollection::pumpFlushReduce() { pumpNetwork(); m_comm.flush(); return m_comm.reduceInflight(); } /** Receive packets and process them until no more work exists for any * slave processor. */ void NetworkSequenceCollection::completeOperation() { Timer timer("completeOperation"); while (pumpFlushReduce() > 0) ; assert(m_comm.transmitBufferEmpty()); // Nothing to send. m_comm.barrier(); // Synchronize. assert(m_comm.receiveEmpty()); // Nothing to receive. assert(m_comm.reduceInflight() == 0); } /** Run the assembly state machine. */ void NetworkSequenceCollection::run() { /** The number of contigs and k-mer assembled. */ pair numAssembled; ofstream bubbleFile; SetState(NAS_LOADING); while (m_state != NAS_DONE) { switch (m_state) { case NAS_LOADING: m_data.setColourSpace( m_comm.receiveBroadcast()); loadSequences(); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(); break; case NAS_LOAD_COMPLETE: { m_comm.barrier(); pumpNetwork(); logger(0) << "Loaded " << m_data.size() << " k-mer.\n"; assert(!m_data.empty()); m_data.setDeletedKey(); m_data.shrink(); m_comm.reduce(m_data.size()); Histogram myh = AssemblyAlgorithms::coverageHistogram(m_data); Histogram h(m_comm.reduce(myh.toVector())); AssemblyAlgorithms::setCoverageParameters(h); /* * If we have loaded the k-mer hash table from disk, then * the adjacency data for each k-mer has already been computed * in the hash table. * * `applyKmerCoverageThreshold` would not work correctly * in this case because it removes k-mer records from * the hash table without attempting to update the adjacency * info of neighbouring k-mers. */ if (!m_data.isAdjacencyLoaded() && opt::kc > 0) { m_comm.barrier(); size_t removed = AssemblyAlgorithms::applyKmerCoverageThreshold(m_data, opt::kc); logger(1) << "Removed " << removed << " low multiplicity k-mers" << std::endl; m_comm.reduce(removed); m_comm.reduce(m_data.size()); } EndState(); SetState(NAS_WAITING); break; } case NAS_GEN_ADJ: m_comm.barrier(); m_numBasesAdjSet = 0; AssemblyAlgorithms::generateAdjacency(this); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(); break; case NAS_ADJ_COMPLETE: m_comm.barrier(); pumpNetwork(); logger(0) << "Added " << m_numBasesAdjSet << " edges.\n"; m_comm.reduce(m_numBasesAdjSet); EndState(); SetState(NAS_WAITING); break; case NAS_ERODE: { m_comm.barrier(); size_t numEroded = AssemblyAlgorithms::erodeEnds(this); EndState(); SetState(NAS_ERODE_WAITING); m_comm.sendCheckPointMessage(numEroded); break; } case NAS_ERODE_WAITING: pumpNetwork(); break; case NAS_ERODE_COMPLETE: completeOperation(); m_comm.reduce(AssemblyAlgorithms::getNumEroded()); m_comm.reduce(m_data.cleanup()); m_comm.barrier(); SetState(NAS_WAITING); break; case NAS_TRIM: { assert(m_trimStep != 0); m_comm.barrier(); size_t numRemoved = performNetworkTrim(); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(numRemoved); break; } case NAS_REMOVE_MARKED: { m_comm.barrier(); size_t count = AssemblyAlgorithms::removeMarked(this); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(count); break; } case NAS_COVERAGE: { m_comm.reduce(m_data.cleanup()); m_lowCoverageContigs = 0; m_lowCoverageKmer = 0; numAssembled = performNetworkAssembly(); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(); break; } case NAS_COVERAGE_COMPLETE: m_comm.barrier(); pumpNetwork(); m_comm.reduce(numAssembled.first); m_comm.reduce(numAssembled.second); m_comm.reduce(m_lowCoverageContigs); m_comm.reduce(m_lowCoverageKmer); opt::coverage = 0; EndState(); SetState(NAS_WAITING); break; case NAS_DISCOVER_BUBBLES: { size_t numDiscovered = performNetworkDiscoverBubbles(); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(numDiscovered); break; } case NAS_POPBUBBLE: { if (!bubbleFile.is_open()) AssemblyAlgorithms::openBubbleFile(bubbleFile); size_t numPopped = performNetworkPopBubbles(bubbleFile); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(numPopped); break; } case NAS_MARK_AMBIGUOUS: { m_comm.barrier(); pumpNetwork(); size_t count = AssemblyAlgorithms::markAmbiguous(this); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(count); break; } case NAS_SPLIT_AMBIGUOUS: { m_comm.barrier(); assert(m_comm.receiveEmpty()); m_comm.barrier(); size_t count = AssemblyAlgorithms::splitAmbiguous(this); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(count); break; } case NAS_CLEAR_FLAGS: m_comm.barrier(); pumpNetwork(); m_data.wipeFlag( SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE)); m_comm.reduce(m_data.cleanup()); EndState(); SetState(NAS_WAITING); break; case NAS_ASSEMBLE: { m_comm.barrier(); pumpNetwork(); FastaWriter writer(opt::contigsTempPath.c_str()); numAssembled = performNetworkAssembly(&writer); EndState(); SetState(NAS_WAITING); m_comm.sendCheckPointMessage(); break; } case NAS_ASSEMBLE_COMPLETE: m_comm.reduce(numAssembled.first); m_comm.reduce(numAssembled.second); EndState(); SetState(NAS_DONE); break; case NAS_WAITING: pumpNetwork(); break; case NAS_DONE: break; } } } size_t NetworkSequenceCollection::controlErode() { SetState(NAS_ERODE); m_comm.sendControlMessage(APC_SET_STATE, NAS_ERODE); m_comm.barrier(); size_t numEroded = AssemblyAlgorithms::erodeEnds(this); EndState(); // Do not call SetState, because it clears the // checkpoint information. //SetState(NAS_ERODE_WAITING); m_state = NAS_ERODE_WAITING; m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); numEroded += m_checkpointSum; EndState(); if (numEroded == 0) { SetState(NAS_WAITING); m_comm.sendControlMessage(APC_WAIT); m_comm.barrier(); return 0; } SetState(NAS_ERODE_COMPLETE); m_comm.sendControlMessage(APC_ERODE_COMPLETE); completeOperation(); 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); (void)removed; SetState(NAS_WAITING); return numEroded; } /** Remove marked k-mer. * @return the number of k-mer removed */ size_t NetworkSequenceCollection::controlRemoveMarked() { if (opt::verbose > 0) cout << "Sweeping...\n"; SetState(NAS_REMOVE_MARKED); m_comm.sendControlMessage(APC_SET_STATE, NAS_REMOVE_MARKED); m_comm.barrier(); size_t count = AssemblyAlgorithms::removeMarked(this); m_checkpointSum += count; EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); return m_checkpointSum; } /** Perform a single round of trimming at the specified length. */ size_t NetworkSequenceCollection::controlTrimRound(unsigned trimLen) { assert(trimLen > 0); m_trimStep = trimLen; cout << "Pruning tips shorter than " << trimLen << " bp...\n"; SetState(NAS_TRIM); m_comm.sendControlMessage(APC_TRIM, trimLen); m_comm.barrier(); size_t numRemoved = performNetworkTrim(); EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); numRemoved += m_checkpointSum; size_t numSweeped = controlRemoveMarked(); if (numRemoved > 0) cout << "Pruned " << numSweeped << " k-mer in " << numRemoved << " tips.\n"; return numRemoved; } /** Perform multiple rounds of trimming until complete. */ void NetworkSequenceCollection::controlTrim(unsigned& sum, unsigned start) { if (opt::trimLen == 0) return; unsigned rounds = 0, total = 0; for (unsigned trim = start; trim < opt::trimLen; trim *= 2) { rounds++; total += controlTrimRound(trim); } size_t count; while ((count = controlTrimRound(opt::trimLen)) > 0) { rounds++; total += count; } cout << "Pruned " << total << " tips in " << rounds << " rounds.\n"; sum += total; } /** Remove low-coverage contigs. */ void NetworkSequenceCollection::controlCoverage() { assert(opt::coverage > 0); // Split ambiguous branches. SetState(NAS_MARK_AMBIGUOUS); controlMarkAmbiguous(); // Remove low-coverage contigs. cout << "Removing low-coverage contigs " "(mean k-mer coverage < " << opt::coverage << ")...\n"; SetState(NAS_COVERAGE); m_comm.sendControlMessage(APC_SET_STATE, NAS_COVERAGE); m_comm.reduce(m_data.cleanup()); m_lowCoverageContigs = 0; m_lowCoverageKmer = 0; pair numAssembled = performNetworkAssembly(); EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); // Count the number of low-coverage contigs. SetState(NAS_COVERAGE_COMPLETE); m_comm.sendControlMessage(APC_SET_STATE, NAS_COVERAGE_COMPLETE); m_comm.barrier(); pumpNetwork(); numAssembled.first = m_comm.reduce(numAssembled.first); numAssembled.second = m_comm.reduce(numAssembled.second); cout << "Found " << numAssembled.second << " k-mer in " << numAssembled.first << " contigs " "before removing low-coverage contigs.\n"; size_t lowCoverageContigs = m_comm.reduce(m_lowCoverageContigs); 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); controlSplitAmbiguous(); SetState(NAS_CLEAR_FLAGS); m_comm.sendControlMessage(APC_SET_STATE, NAS_CLEAR_FLAGS); m_comm.barrier(); pumpNetwork(); m_data.wipeFlag(SeqFlag(SF_MARK_SENSE | SF_MARK_ANTISENSE)); size_t removed = m_comm.reduce(m_data.cleanup()); cout << "Removed " << removed << " marked k-mer.\n"; EndState(); opt::coverage = 0; } /** 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: { loadSequences(); EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); SetState(NAS_LOAD_COMPLETE); m_comm.sendControlMessage(APC_SET_STATE, NAS_LOAD_COMPLETE); m_comm.barrier(); pumpNetwork(); logger(0) << "Loaded " << m_data.size() << " k-mer.\n"; assert(!m_data.empty() || opt::numProc >= DEDICATE_CONTROL_AT); m_data.setDeletedKey(); m_data.shrink(); size_t numLoaded = m_comm.reduce(m_data.size()); cout << "Loaded " << numLoaded << " k-mer. " "At least " << 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())); AssemblyAlgorithms::setCoverageParameters(h); /* * If we have loaded the k-mer hash table from disk, then * the adjacency data for each k-mer has already been computed * in the hash table. * * `applyKmerCoverageThreshold` would not work correctly * in this case because it removes k-mer records from * the hash table without attempting to update the adjacency * info of neighbouring k-mers. */ if (!m_data.isAdjacencyLoaded() && opt::kc > 0) { cout << "Minimum k-mer multiplicity kc is " << opt::kc << '\n'; cout << "Removing low multiplicity k-mers..." << std::endl; m_comm.barrier(); size_t removed = AssemblyAlgorithms::applyKmerCoverageThreshold(m_data, opt::kc); logger(1) << "Removed " << removed << " low multiplicity k-mers" << std::endl; size_t sumRemoved = m_comm.reduce(removed); size_t remaining = m_comm.reduce(m_data.size()); cout << "Removed " << sumRemoved << " low-multiplicity k-mers, " << remaining << " k-mers remaining" << std::endl; } EndState(); SetState(m_data.isAdjacencyLoaded() ? NAS_ERODE : NAS_GEN_ADJ); break; } case NAS_GEN_ADJ: cout << "Finding adjacent k-mer...\n"; m_comm.sendControlMessage(APC_SET_STATE, NAS_GEN_ADJ); m_comm.barrier(); m_numBasesAdjSet = 0; AssemblyAlgorithms::generateAdjacency(this); EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); SetState(NAS_ADJ_COMPLETE); m_comm.sendControlMessage(APC_SET_STATE, NAS_ADJ_COMPLETE); m_comm.barrier(); pumpNetwork(); temp = m_comm.reduce(m_numBasesAdjSet); logger(0) << "Added " << m_numBasesAdjSet << " edges.\n"; 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"; erosionSum += controlErode(); //controlErode(); SetState(NAS_TRIM); break; case NAS_LOAD_COMPLETE: case NAS_ADJ_COMPLETE: case NAS_REMOVE_MARKED: case NAS_ERODE_WAITING: case NAS_ERODE_COMPLETE: case NAS_COVERAGE_COMPLETE: case NAS_SPLIT_AMBIGUOUS: case NAS_CLEAR_FLAGS: case NAS_DISCOVER_BUBBLES: case NAS_ASSEMBLE_COMPLETE: case NAS_WAITING: // These states are used only by the slaves. assert(false); exit(EXIT_FAILURE); case NAS_TRIM: controlTrim(prunedSum); SetState(opt::coverage > 0 ? NAS_COVERAGE : opt::bubbleLen > 0 ? NAS_POPBUBBLE : NAS_MARK_AMBIGUOUS); break; case NAS_COVERAGE: controlCoverage(); SetState(opt::erode > 0 ? NAS_ERODE : NAS_TRIM); break; case NAS_POPBUBBLE: { assert(opt::bubbleLen > 0); ofstream out; AssemblyAlgorithms::openBubbleFile(out); cout << "Popping bubbles...\n"; size_t numPopped = controlPopBubbles(out); assert(numPopped == m_numPopped); assert(out.good()); out.close(); cout << "Removed " << numPopped << " bubbles.\n"; if (!opt::db.empty()) AssemblyAlgorithms::addToDb ("poppedBubbles", numPopped); SetState(NAS_MARK_AMBIGUOUS); break; } case NAS_MARK_AMBIGUOUS: finalAmbg = controlMarkAmbiguous(); //controlMarkAmbiguous(); SetState(NAS_ASSEMBLE); break; case NAS_ASSEMBLE: { cout << "Assembling...\n"; m_comm.sendControlMessage(APC_ASSEMBLE); m_comm.barrier(); pumpNetwork(); FastaWriter writer(opt::contigsTempPath.c_str()); pair numAssembled = performNetworkAssembly(&writer); EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); SetState(NAS_ASSEMBLE_COMPLETE); m_comm.sendControlMessage(APC_SET_STATE, NAS_ASSEMBLE_COMPLETE); numAssembled.first = m_comm.reduce( numAssembled.first); numAssembled.second = m_comm.reduce( numAssembled.second); cout << "Assembled " << numAssembled.second << " 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; } case NAS_DONE: break; } } if (!opt::db.empty()) { AssemblyAlgorithms::addToDb ("finalAmbgVertices", finalAmbg); AssemblyAlgorithms::addToDb ("totalErodedTips", erosionSum); AssemblyAlgorithms::addToDb ("totalPrunedTips", prunedSum); } } void NetworkSequenceCollection::EndState() { // Flush the message buffer m_comm.flush(); } // // Set the state // void NetworkSequenceCollection::SetState( NetworkAssemblyState newState) { logger(2) << "SetState " << newState << " (was " << m_state << ")\n"; // Ensure there are no pending messages assert(m_comm.transmitBufferEmpty()); m_state = newState; // Reset the checkpoint counter m_numReachedCheckpoint = 0; m_checkpointSum = 0; } /** Receive and dispatch packets. * @return the number of packets received */ size_t NetworkSequenceCollection::pumpNetwork() { for (size_t count = 0; ; count++) { int senderID; APMessage msg = m_comm.checkMessage(senderID); switch(msg) { case APM_CONTROL: parseControlMessage(senderID); // Deal with the control packet before we continue // processing further packets. return ++count; case APM_BUFFERED: { MessagePtrVector msgs; m_comm.receiveBufferedMessage(msgs); for (MessagePtrVector::iterator iter = msgs.begin(); iter != msgs.end(); iter++) { // Handle each message based on its type (*iter)->handle(senderID, *this); // Delete the message delete (*iter); *iter = 0; } break; } case APM_NONE: return count; } } } /** Call the observers of the specified sequence. */ void NetworkSequenceCollection::notify(const V& key) { switch (m_state) { case NAS_ERODE: case NAS_ERODE_WAITING: case NAS_ERODE_COMPLETE: AssemblyAlgorithms::erode(this, m_data.getSeqAndData(key)); break; default: // Nothing to do. break; } } void NetworkSequenceCollection::handle( int /*senderID*/, const SeqAddMessage& message) { assert(isLocal(message.m_seq)); m_data.add(message.m_seq); } void NetworkSequenceCollection::handle( int /*senderID*/, const SeqRemoveMessage& message) { assert(isLocal(message.m_seq)); m_data.remove(message.m_seq); } void NetworkSequenceCollection::handle( int /*senderID*/, const SetFlagMessage& message) { assert(isLocal(message.m_seq)); m_data.setFlag(message.m_seq, (SeqFlag)message.m_flag); } void NetworkSequenceCollection::handle( int /*senderID*/, const SetBaseMessage& message) { assert(isLocal(message.m_seq)); setBaseExtension(message.m_seq, (extDirection)message.m_dir, message.m_base); } void NetworkSequenceCollection::handle( int /*senderID*/, const RemoveExtensionMessage& message) { assert(isLocal(message.m_seq)); m_data.removeExtension(message.m_seq, (extDirection)message.m_dir, message.m_ext); notify(message.m_seq); } void NetworkSequenceCollection::parseControlMessage(int source) { ControlMessage controlMsg = m_comm.receiveControlMessage(); switch(controlMsg.msgType) { case APC_SET_STATE: SetState(NetworkAssemblyState(controlMsg.argument)); break; case APC_CHECKPOINT: logger(4) << "checkpoint from " << source << ": " << controlMsg.argument << '\n'; m_numReachedCheckpoint++; m_checkpointSum += controlMsg.argument; break; case APC_WAIT: SetState(NAS_WAITING); m_comm.barrier(); break; case APC_BARRIER: assert(m_state == NAS_WAITING); m_comm.barrier(); break; case APC_TRIM: m_trimStep = controlMsg.argument; SetState(NAS_TRIM); break; case APC_ERODE_COMPLETE: assert(m_state == NAS_ERODE_WAITING); m_comm.flush(); SetState(NAS_ERODE_COMPLETE); break; case APC_POPBUBBLE: m_numPopped = controlMsg.argument; SetState(NAS_POPBUBBLE); break; case APC_ASSEMBLE: m_numAssembled = controlMsg.argument; SetState(NAS_ASSEMBLE); break; } } void NetworkSequenceCollection::handle( int senderID, const SeqDataRequest& message) { const V& kmer = message.m_seq; assert(isLocal(kmer)); SymbolSetPair extRec; int multiplicity = -1; bool found = m_data.getSeqData(kmer, extRec, multiplicity); assert(found); (void)found; m_comm.sendSeqDataResponse( senderID, message.m_group, message.m_id, kmer, extRec, multiplicity); } void NetworkSequenceCollection::handle( int /*senderID*/, const SeqDataResponse& message) { processSequenceExtension( message.m_group, message.m_id, message.m_seq, message.m_extRecord, message.m_multiplicity); } /** Distributed trimming function. */ size_t NetworkSequenceCollection::performNetworkTrim() { Timer timer("NetworkTrim"); NetworkSequenceCollection* seqCollection = this; size_t numBranchesRemoved = 0; // The branch ids uint64_t branchGroupID = 0; for (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 = AssemblyAlgorithms::checkSeqContiguity( *iter, dir); if (status == SC_CONTIGUOUS) continue; else if(status == SC_ISLAND) { seqCollection->mark(iter->first); numBranchesRemoved++; continue; } bool inserted = m_activeBranchGroups.insert( BranchGroupMap::value_type(branchGroupID, BranchGroup(dir, 1, iter->first, BranchRecord(dir)))) .second; assert(inserted); (void)inserted; generateExtensionRequest(branchGroupID, 0, iter->first); branchGroupID++; numBranchesRemoved += processBranchesTrim(); seqCollection->pumpNetwork(); // Primitive load balancing if(m_activeBranchGroups.size() > MAX_ACTIVE) { while(m_activeBranchGroups.size() > LOW_ACTIVE) { seqCollection->pumpNetwork(); numBranchesRemoved += processBranchesTrim(); } } } // Clear out the remaining branches while(!m_activeBranchGroups.empty()) { numBranchesRemoved += processBranchesTrim(); seqCollection->pumpNetwork(); } logger(0) << "Pruned " << numBranchesRemoved << " tips.\n"; return numBranchesRemoved; } // // Process current branches, removing those that are finished // returns true if the branch list has branches remaining // size_t NetworkSequenceCollection::processBranchesTrim() { size_t numBranchesRemoved = 0; vector removeBranches; // Check if any of the current branches have gone inactive for (BranchGroupMap::iterator iter = m_activeBranchGroups.begin(); iter != m_activeBranchGroups.end(); iter++) { if(!iter->second.isActive()) { assert(iter->second.size() == 1); if (AssemblyAlgorithms::processTerminatedBranchTrim( this, iter->second[0])) numBranchesRemoved++; // Mark the group for removal removeBranches.push_back(iter); } } // Remove all the finished branches for (vector::iterator rmIter = removeBranches.begin(); rmIter != removeBranches.end(); rmIter++) m_activeBranchGroups.erase(*rmIter); return numBranchesRemoved; } /** Discover bubbles to pop. */ size_t NetworkSequenceCollection:: performNetworkDiscoverBubbles() { NetworkSequenceCollection* seqCollection = this; Timer timer("NetworkDiscoverBubbles"); // The branch ids uint64_t branchGroupID = 0; m_finishedGroups.clear(); // make sure the branch group structure is initially empty assert(m_activeBranchGroups.empty()); size_t count = 0; // Set the cutoffs const unsigned maxNumBranches = 3; for (iterator iter = seqCollection->begin(); iter != seqCollection->end(); ++iter) { if (iter->second.deleted()) continue; if (++count % 100000 == 0) logger(1) << "Popping bubbles: " << count << '\n'; SymbolSetPair extRec = iter->second.extension(); for (extDirection dir = SENSE; dir <= ANTISENSE; ++dir) { if (extRec.dir[dir].isAmbiguous()) { BranchGroupMap::iterator groupIter = m_activeBranchGroups.insert( BranchGroupMap::value_type(branchGroupID, BranchGroup(dir, maxNumBranches, iter->first))).first; BranchGroup& group = groupIter->second; AssemblyAlgorithms::initiateBranchGroup( group, iter->first, extRec.dir[dir]); generateExtensionRequests(branchGroupID++, group.begin(), group.end()); } } // Primitive load balancing if (m_activeBranchGroups.size() > MAX_ACTIVE) { while (m_activeBranchGroups.size() > LOW_ACTIVE) { seqCollection->pumpNetwork(); processBranchesDiscoverBubbles(); } } processBranchesDiscoverBubbles(); seqCollection->pumpNetwork(); } // Wait until the groups finish extending. while (processBranchesDiscoverBubbles()) seqCollection->pumpNetwork(); assert(m_activeBranchGroups.empty()); size_t numDiscovered = m_bubbles.size(); logger(1) << "Discovered " << numDiscovered << " bubbles.\n"; return numDiscovered; } /** Pop bubbles discovered previously. */ size_t NetworkSequenceCollection:: performNetworkPopBubbles(ostream& out) { Timer timer("NetworkPopBubbles"); // Deal with any packets still in the queue. The barrier // synchronization guarantees that the packets have been // delivered, but we may not have dealt with them yet. pumpNetwork(); assert(m_comm.receiveEmpty()); size_t numPopped = 0; for (BranchGroupMap::iterator iter = m_bubbles.begin(); iter != m_bubbles.end(); iter++) { assert(iter->second.getStatus() == BGS_JOINED); // Check whether this bubble has already been popped. if (!iter->second.isAmbiguous(m_data)) continue; numPopped++; AssemblyAlgorithms::writeBubble(out, iter->second, m_numPopped + numPopped); AssemblyAlgorithms::collapseJoinedBranches( this, iter->second); assert(!iter->second.isAmbiguous(m_data)); assert(m_comm.receiveEmpty()); } m_bubbles.clear(); out.flush(); assert(out.good()); logger(0) << "Removed " << numPopped << " bubbles.\n"; return numPopped; } // // Process groups that are finished searching for bubbles // bool NetworkSequenceCollection::processBranchesDiscoverBubbles() { bool active = false; // Check if any of the current branches have gone inactive BranchGroupMap::iterator iter = m_activeBranchGroups.begin(); while (iter != m_activeBranchGroups.end()) { // All branches have been extended one sequence. Check the // stop conditions. updateStatus() is called in // processSequenceExtensionPop(). BranchGroupStatus status = iter->second.isNoExt() ? BGS_NOEXT : iter->second.getStatus(); bool finished = false; switch (status) { case BGS_TOOLONG: case BGS_TOOMANYBRANCHES: case BGS_NOEXT: finished = true; break; case BGS_JOINED: m_bubbles.insert(*iter); finished = true; break; case BGS_ACTIVE: active = true; break; default: assert(false); } if (finished) { m_finishedGroups.insert(iter->first); m_activeBranchGroups.erase(iter++); } else iter++; } return active; } /** Discover bubbles to pop. */ size_t NetworkSequenceCollection::controlDiscoverBubbles() { SetState(NAS_DISCOVER_BUBBLES); m_comm.sendControlMessage(APC_SET_STATE, NAS_DISCOVER_BUBBLES); size_t numDiscovered = performNetworkDiscoverBubbles(); EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); numDiscovered += m_checkpointSum; if (numDiscovered > 0 && opt::verbose > 0) cout << "Discovered " << numDiscovered << " bubbles.\n"; return numDiscovered; } /** Pop the bubbles discovered previously. */ size_t NetworkSequenceCollection::controlPopBubbles(ostream& out) { controlDiscoverBubbles(); m_comm.sendControlMessage(APC_BARRIER); m_comm.barrier(); pumpNetwork(); // Perform a round-robin bubble pop to avoid concurrency issues SetState(NAS_POPBUBBLE); m_checkpointSum = performNetworkPopBubbles(out); EndState(); // Now tell all the slave nodes to perform the pop one by one for(int i = 1; i < opt::numProc; i++) { m_comm.sendControlMessage(APC_BARRIER); m_comm.barrier(); m_numReachedCheckpoint = 0; m_comm.sendControlMessageToNode(i, APC_POPBUBBLE, m_numPopped + m_checkpointSum); while (!checkpointReached(1)) pumpNetwork(); } size_t numPopped = m_checkpointSum; m_numPopped += numPopped; if (numPopped > 0) cout << "Removed " << numPopped << " bubbles.\n"; return numPopped; } /** Mark ambiguous branches. */ size_t NetworkSequenceCollection::controlMarkAmbiguous() { cout << "Marking ambiguous branches...\n"; m_comm.sendControlMessage(APC_SET_STATE, NAS_MARK_AMBIGUOUS); m_comm.barrier(); pumpNetwork(); size_t count = AssemblyAlgorithms::markAmbiguous(this); m_checkpointSum += count; EndState(); m_numReachedCheckpoint++; while (!checkpointReached()) pumpNetwork(); cout << "Marked " << m_checkpointSum << " ambiguous branches.\n"; return m_checkpointSum; } /** Remove ambiguous branches. */ size_t NetworkSequenceCollection::controlSplitAmbiguous() { cout << "Splitting ambiguous branches...\n"; m_comm.sendControlMessage(APC_SET_STATE, NAS_SPLIT_AMBIGUOUS); m_comm.barrier(); assert(m_comm.receiveEmpty()); m_comm.barrier(); size_t count = AssemblyAlgorithms::splitAmbiguous(this); m_checkpointSum += count; EndState(); m_numReachedCheckpoint++; 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( FastaWriter* writer, BranchRecord& branch, unsigned id) { size_t removed = AssemblyAlgorithms::assembleContig( this, writer, branch, id); if (removed > 0) { m_lowCoverageContigs++; m_lowCoverageKmer += removed; } } namespace std { /** Add a pair of numbers. */ pair& operator+=( pair& a, pair b) { a.first += b.first; a.second += b.second; return a; } } /** Assemble contigs. * @return the number of contigs and k-mer assembled */ pair NetworkSequenceCollection:: performNetworkAssembly(FastaWriter* fileWriter) { Timer timer("NetworkAssembly"); NetworkSequenceCollection* seqCollection = this; pair numAssembled(0, 0); uint64_t branchGroupID = 0; assert(m_activeBranchGroups.empty()); for (iterator iter = seqCollection->begin(); iter != seqCollection->end(); ++iter) { if (iter->second.deleted()) continue; extDirection dir; // dir will be set to the assembly direction if the sequence // can be assembled. SeqContiguity status = AssemblyAlgorithms::checkSeqContiguity( *iter, dir, true); if (status == SC_CONTIGUOUS) continue; else if(status == SC_ISLAND) { // Output the singleton contig. BranchRecord currBranch(SENSE); currBranch.push_back(*iter); currBranch.terminate(BS_NOEXT); assembleContig(fileWriter, currBranch, m_numAssembled + numAssembled.first); numAssembled.first++; numAssembled.second += currBranch.size(); continue; } BranchGroup group(dir, 1, iter->first); group.addBranch(BranchRecord(dir)); pair inserted = m_activeBranchGroups.insert( BranchGroupMap::value_type(branchGroupID, group)); assert(inserted.second); // Generate the first extension request BranchRecord& branch = inserted.first->second[0]; branch.push_back(*iter); V kmer = iter->first; AssemblyAlgorithms::extendBranch(branch, kmer, iter->second.getExtension(dir)); assert(branch.isActive()); generateExtensionRequest(branchGroupID++, 0, kmer); numAssembled += processBranchesAssembly( fileWriter, numAssembled.first); seqCollection->pumpNetwork(); if(m_activeBranchGroups.size() > MAX_ACTIVE) { while(m_activeBranchGroups.size() > LOW_ACTIVE) { seqCollection->pumpNetwork(); numAssembled += processBranchesAssembly( fileWriter, numAssembled.first); } } } // Clear out the remaining branches while(!m_activeBranchGroups.empty()) { numAssembled += processBranchesAssembly( fileWriter, numAssembled.first); seqCollection->pumpNetwork(); } if (opt::coverage > 0) { logger(0) << "Found " << numAssembled.second << " k-mer in " << numAssembled.first << " contigs before removing low-coverage contigs.\n" "Removed " << m_lowCoverageKmer << " k-mer in " << m_lowCoverageContigs << " low-coverage contigs.\n"; } else logger(0) << "Assembled " << numAssembled.second << " k-mer in " << numAssembled.first << " contigs.\n"; return numAssembled; } /** Processes branches that are in progress, removing those that have * completed. * @return the number of contigs and k-mer assembled */ pair NetworkSequenceCollection:: processBranchesAssembly(FastaWriter* fileWriter, unsigned currContigID) { size_t assembledContigs = 0, assembledKmer = 0; for (BranchGroupMap::iterator it = m_activeBranchGroups.begin(); it != m_activeBranchGroups.end();) { if (!it->second.isActive()) { assert(it->second.size() == 1); BranchRecord& branch = it->second[0]; assert(branch.getState() == BS_NOEXT || branch.getState() == BS_AMBI_SAME || branch.getState() == BS_AMBI_OPP); if ((opt::ss && branch.getDirection() == SENSE) || (!opt::ss && branch.isCanonical())) { assembledContigs++; assembledKmer += branch.size(); assembleContig(fileWriter, branch, m_numAssembled + currContigID++); } m_activeBranchGroups.erase(it++); } else ++it; } return make_pair(assembledContigs, assembledKmer); } /** Send a request for the edges of vertex kmer. */ void NetworkSequenceCollection::generateExtensionRequest( uint64_t groupID, uint64_t branchID, const V& kmer) { if (isLocal(kmer)) { SymbolSetPair extRec; int multiplicity = -1; bool success = m_data.getSeqData(kmer, extRec, multiplicity); assert(success); (void)success; processSequenceExtension(groupID, branchID, kmer, extRec, multiplicity); } else m_comm.sendSeqDataRequest(computeNodeID(kmer), groupID, branchID, kmer); } /** Generate an extension request for each branch of this group. */ void NetworkSequenceCollection::generateExtensionRequests( uint64_t groupID, BranchGroup::const_iterator first, BranchGroup::const_iterator last) { assert(first != last); #if !NDEBUG size_t length = first->size(); #endif unsigned branchID = 0; for (BranchGroup::const_iterator it = first; it != last; ++it) { assert(it->size() == length); generateExtensionRequest(groupID, branchID++, it->back().first); } } void NetworkSequenceCollection::processSequenceExtension( uint64_t groupID, uint64_t branchID, const V& seq, const SymbolSetPair& extRec, int multiplicity) { switch(m_state) { case NAS_TRIM: return processLinearSequenceExtension(groupID, branchID, seq, extRec, multiplicity, m_trimStep); case NAS_ASSEMBLE: case NAS_COVERAGE: return processLinearSequenceExtension(groupID, branchID, seq, extRec, multiplicity, UINT_MAX); case NAS_DISCOVER_BUBBLES: return processSequenceExtensionPop(groupID, branchID, seq, extRec, multiplicity, opt::bubbleLen - opt::kmerSize + 1); case NAS_WAITING: if (m_finishedGroups.count(groupID) == 0) { logger(0) << "error: unexpected seqext message: " "state: " << m_state << " " "gid: " << groupID << " bid: " << branchID << " " "seq: " << seq.str() << '\n'; assert(false); } break; default: logger(0) << "error: unexpected seqext message: " "state: " << m_state << " " "gid: " << groupID << " bid: " << branchID << " " "seq: " << seq.str() << '\n'; assert(false); break; } } /** Process a sequence extension for trimming. */ void NetworkSequenceCollection::processLinearSequenceExtension( 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()); V currSeq = seq; bool active = AssemblyAlgorithms::processLinearExtensionForBranch( iter->second[branchID], currSeq, extRec, multiplicity, maxLength); if (active) generateExtensionRequest(groupID, branchID, currSeq); } /** Process a sequence extension for popping. */ void NetworkSequenceCollection::processSequenceExtensionPop( uint64_t groupID, uint64_t branchID, const V& seq, const SymbolSetPair& extRec, int multiplicity, unsigned maxLength) { BranchGroupMap::iterator groupIt = m_activeBranchGroups.find(groupID); if (groupIt == m_activeBranchGroups.end()) { // This branch is already complete. Double check that that is // the case. assert(m_finishedGroups.count(groupID) > 0); return; } BranchGroup& group = groupIt->second; bool extendable = AssemblyAlgorithms::processBranchGroupExtension( group, branchID, seq, extRec, multiplicity, maxLength); if (extendable && group.updateStatus(maxLength) == BGS_ACTIVE) generateExtensionRequests(groupID, group.begin(), group.end()); } /** Add a k-mer to this collection. */ void NetworkSequenceCollection::add(const V& seq, unsigned coverage) { if (isLocal(seq)) { m_data.add(seq, coverage); } else { assert(coverage == 1); m_comm.sendSeqAddMessage(computeNodeID(seq), seq); } } /** Remove a k-mer from this collection. */ void NetworkSequenceCollection::remove(const V& seq) { if (isLocal(seq)) m_data.remove(seq); else m_comm.sendSeqRemoveMessage(computeNodeID(seq), seq); } bool NetworkSequenceCollection::checkpointReached() const { return m_numReachedCheckpoint == (unsigned)opt::numProc; } bool NetworkSequenceCollection:: checkpointReached(unsigned numRequired) const { return m_numReachedCheckpoint == numRequired; } void NetworkSequenceCollection::setFlag(const V& seq, SeqFlag flag) { if (isLocal(seq)) m_data.setFlag(seq, flag); else m_comm.sendSetFlagMessage(computeNodeID(seq), seq, flag); } bool NetworkSequenceCollection::setBaseExtension( const V& seq, extDirection dir, Symbol base) { if (isLocal(seq)) { if (m_data.setBaseExtension(seq, dir, base)) m_numBasesAdjSet++; } else { int nodeID = computeNodeID(seq); m_comm.sendSetBaseExtension(nodeID, seq, dir, base); } // As this call delegates, the return value is meaningless. return false; } /** Remove the specified extensions from this k-mer. */ void NetworkSequenceCollection::removeExtension( const V& seq, extDirection dir, SymbolSet ext) { if (isLocal(seq)) { m_data.removeExtension(seq, dir, ext); notify(seq); } else { int nodeID = computeNodeID(seq); m_comm.sendRemoveExtension(nodeID, seq, dir, ext); } } /** Return whether this sequence belongs to this process. */ 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 V& seq) const { if (opt::numProc < DEDICATE_CONTROL_AT) { return seq.getCode() % (unsigned)opt::numProc; } else { return seq.getCode() % (unsigned)(opt::numProc - 1) + 1; } } abyss-2.2.4/Parallel/NetworkSequenceCollection.h000066400000000000000000000177131361462241400217170ustar00rootroot00000000000000#ifndef NETWORKSEQUENCECOLLECTION_H #define NETWORKSEQUENCECOLLECTION_H 1 #include "CommLayer.h" #include "MessageBuffer.h" #include "SequenceCollection.h" #include "Assembly/BranchGroup.h" #include "Common/Timer.h" #include "DataLayer/FastaWriter.h" #include #include #include #include "Common/InsOrderedMap.h" namespace NSC { typedef InsOrderedMap dbMap; dbMap moveFromAaStatMap(); } enum NetworkAssemblyState { NAS_LOADING, // loading sequences NAS_LOAD_COMPLETE, // loading is complete NAS_GEN_ADJ, // generating the sequence data NAS_ADJ_COMPLETE, // adjacency generation is complete NAS_ERODE, // erode the branch ends one sequence at a time NAS_ERODE_WAITING, NAS_ERODE_COMPLETE, NAS_TRIM, // trimming the data NAS_REMOVE_MARKED, // remove marked sequences NAS_COVERAGE, // remove low-coverage contigs NAS_COVERAGE_COMPLETE, NAS_DISCOVER_BUBBLES, // discover read errors/SNPs NAS_POPBUBBLE, // remove read errors/SNPs NAS_MARK_AMBIGUOUS, // mark ambiguous branches NAS_SPLIT_AMBIGUOUS, // split ambiguous branches NAS_CLEAR_FLAGS, // clear the flags NAS_ASSEMBLE, // assembling the data NAS_ASSEMBLE_COMPLETE, // assembling is complete NAS_WAITING, // non-control process is waiting NAS_DONE // finished, clean up and exit }; typedef std::map BranchGroupMap; /** 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(); size_t performNetworkDiscoverBubbles(); size_t performNetworkPopBubbles(std::ostream& out); size_t controlErode(); size_t controlTrimRound(unsigned trimLen); void controlTrim(unsigned&, unsigned start = 1); size_t controlRemoveMarked(); void controlCoverage(); size_t controlDiscoverBubbles(); size_t controlPopBubbles(std::ostream& out); size_t controlMarkAmbiguous(); size_t controlSplitAmbiguous(); size_t controlSplit(); // Perform a network assembly std::pair performNetworkAssembly( FastaWriter* fileWriter = NULL); 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 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(); size_t pumpFlushReduce(); void completeOperation(); // run the assembly void run(); // run the assembly from the controller's point of view void runControl(); // test if the checkpoint has been reached bool checkpointReached() const; bool checkpointReached(unsigned numRequired) const; void handle(int senderID, const SeqAddMessage& message); void handle(int senderID, const SeqRemoveMessage& message); void handle(int senderID, const SetBaseMessage& message); void handle(int senderID, const SetFlagMessage& message); void handle(int senderID, const RemoveExtensionMessage& m); 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) { } void detach(SeqObserver) { } /** Load this collection from disk. */ void load(const char *path) { m_data.load(path); } /** Indicate that this is a colour-space collection. */ void setColourSpace(bool flag) { m_data.setColourSpace(flag); m_comm.broadcast(flag); } 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(); } private: // Observer pattern void notify(const V& seq); void loadSequences(); std::pair processBranchesAssembly( FastaWriter* fileWriter, unsigned currContigID); size_t processBranchesTrim(); bool processBranchesDiscoverBubbles(); void generateExtensionRequest( 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 V& seq, const SymbolSetPair& extRec, int multiplicity); void processLinearSequenceExtension( 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 V& seq, const SymbolSetPair& extRec, int multiplicity, unsigned maxLength); void assembleContig( FastaWriter* fileWriter, BranchRecord& branch, unsigned id); // Check if a branch is redundant with a previously output // branch. bool isBranchRedundant(const BranchRecord& branch); void parseControlMessage(int source); bool isLocal(const V& seq) const; int computeNodeID(const V& seq) const; void EndState(); // Set the state of the network assembly void SetState(NetworkAssemblyState newState); SequenceCollectionHash m_data; // The communications layer implements the functions over the // network. MessageBuffer m_comm; // The number of nodes in the network unsigned m_numDataNodes; // the state of the assembly NetworkAssemblyState m_state; // The number of processes that have sent a checkpoint reached // message, this is used by the control process to determine // the state flow. unsigned m_numReachedCheckpoint; /** The sum of the values returned by the slave nodes in their * checkpoint messages. */ size_t m_checkpointSum; // the number of bases of adjacency set size_t m_numBasesAdjSet; // the current length to trim on (comes from the control node) unsigned m_trimStep; /** The number of low-coverage contigs removed. */ size_t m_lowCoverageContigs; /** The number of low-coverage k-mer removed. */ size_t m_lowCoverageKmer; /** The number of bubbles popped so far. */ size_t m_numPopped; // the number of sequences assembled so far size_t m_numAssembled; // The current branches that are active BranchGroupMap m_activeBranchGroups; /** Bubbles, which are branch groups that have joined. */ BranchGroupMap m_bubbles; // List of IDs of finished groups, used for sanity checking // during bubble popping. std::set m_finishedGroups; static const size_t MAX_ACTIVE = 50; static const size_t LOW_ACTIVE = 10; }; // Graph namespace boost { template <> struct graph_traits : graph_traits { }; // graph_traits } // namespace boost #endif abyss-2.2.4/Parallel/SequenceCollection.h000066400000000000000000000003101361462241400203260ustar00rootroot00000000000000#ifndef PARALLEL_SEQUENCECOLLECTION_H #define PARALLEL_SEQUENCECOLLECTION_H 1 #if PAIRED_DBG # include "PairedDBG/SequenceCollection.h" #else # include "Assembly/SequenceCollection.h" #endif #endif abyss-2.2.4/Parallel/parallelAbyss.cpp000066400000000000000000000063711361462241400177100ustar00rootroot00000000000000#include "config.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 #include // for HOST_NAME_MAX #include // for setvbuf #include #include // for strerror #include #include #include // for gethostname #include #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; // write merged FASTA file FastaWriter writer(outputPath.c_str()); uint64_t seqid = 0; for(int i = 0; i < opt::numProc; i++) { ostringstream filename; filename << inputPathPrefix << i << FASTA_SUFFIX; assert(filename.good()); string str(filename.str()); FastaReader reader(str.c_str(), FastaReader::NO_FOLD_CASE); for (FastaRecord rec; reader >> rec;) { if (generateNewIds) writer.WriteSequence(rec.seq, seqid++, rec.comment); else writer.WriteSequence(rec.seq, rec.id, rec.comment); } assert(reader.eof()); } // remove temp FASTA files bool die = false; for (int i = 0; i < opt::numProc; i++) { ostringstream s; s << inputPathPrefix << i << FASTA_SUFFIX; string str(s.str()); const char* path = str.c_str(); if (unlink(path) == -1) { cerr << "error: removing `" << path << "': " << strerror(errno) << endl; die = true; } } if (die) exit(EXIT_FAILURE); } int main(int argc, char** argv) { Timer timer("Total"); // Set stdout to be line buffered. setvbuf(stdout, NULL, _IOLBF, 0); MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &opt::rank); MPI_Comm_size(MPI_COMM_WORLD, &opt::numProc); // OMPI-1.6.1 and later reset the SIGCHLD handler so we need to // 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"; MPI_Barrier(MPI_COMM_WORLD); char hostname[HOST_NAME_MAX]; gethostname(hostname, sizeof hostname); 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(); } else { NetworkSequenceCollection networkSeqs; networkSeqs.run(); } MPI_Barrier(MPI_COMM_WORLD); MPI_Finalize(); if (opt::rank == 0) { mergeFastaFiles(opt::contigsPath, "contigs-", true); 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; } abyss-2.2.4/ParseAligns/000077500000000000000000000000001361462241400150535ustar00rootroot00000000000000abyss-2.2.4/ParseAligns/Makefile.am000066400000000000000000000011641361462241400171110ustar00rootroot00000000000000bin_PROGRAMS = abyss-fixmate abyss-fixmate-ssq ParseAligns 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 abyss_fixmate_ssq_CPPFLAGS = $(abyss_fixmate_CPPFLAGS) \ -D SAM_SEQ_QUAL=1 abyss_fixmate_ssq_LDADD = $(abyss_fixmate_LDADD) abyss_fixmate_ssq_SOURCES = $(abyss_fixmate_SOURCES) ParseAligns_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common ParseAligns_LDADD = \ $(top_builddir)/Common/libcommon.a ParseAligns_SOURCES = \ ParseAligns.cpp abyss-2.2.4/ParseAligns/ParseAligns.cpp000066400000000000000000000465521361462241400200030ustar00rootroot00000000000000#include "Alignment.h" #include "Estimate.h" #include "Histogram.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "SAM.h" #include "StringUtil.h" #include "Uncompress.h" #include "UnorderedMap.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define PROGRAM "ParseAligns" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Jared Simpson and Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... [FILE]...\n" "Write pairs that map to the same contig to the file SAME.\n" "Write pairs that map to different contigs to standard output.\n" "Alignments may be read from FILE(s) or standard input.\n" "\n" " Options:\n" "\n" " -l, --min-align=N minimum alignment length\n" " -d, --dist=DISTANCE write distance estimates to this file\n" " -f, --frag=SAME write fragment sizes to this file\n" " -h, --hist=FILE write the fragment size histogram to FILE\n" " --sam alignments are in SAM format\n" " --kaligner alignments are in KAligner format\n" " -c, --cover=COVERAGE coverage cut-off for distance estimates\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 { unsigned k; // used by DistanceEst static unsigned c; static int verbose; static string distPath; static string fragPath; static string histPath; /** Input alignment format. */ static int inputFormat; enum { KALIGNER, SAM }; /** Output format */ int format = ADJ; // used by Estimate } static const char shortopts[] = "d:l:f:h:c:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "dist", required_argument, NULL, 'd' }, { "min-align", required_argument, NULL, 'l' }, { "frag", required_argument, NULL, 'f' }, { "hist", required_argument, NULL, 'h' }, { "kaligner", no_argument, &opt::inputFormat, opt::KALIGNER }, { "sam", no_argument, &opt::inputFormat, opt::SAM }, { "cover", required_argument, NULL, 'c' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; static struct { size_t alignments; size_t bothUnaligned; size_t oneUnaligned; size_t numDifferent; size_t numFF; size_t numMulti; size_t numSplit; } stats; static ofstream fragFile; static Histogram histogram; typedef vector AlignmentVector; /** A map of read IDs to alignments. */ typedef unordered_map ReadAlignMap; /** A map of contig IDs to distance estimates. */ typedef unordered_map EstimateMap; static EstimateMap estMap; static bool checkUniqueAlignments(const AlignmentVector& alignVec); static string makePairID(string id); /** * Return the size of the fragment demarcated by the specified * alignments. */ static int fragmentSize(const Alignment& a0, const Alignment& a1) { assert(a0.contig == a1.contig); assert(a0.isRC != a1.isRC); const Alignment& f = a0.isRC ? a1 : a0; const Alignment& r = a0.isRC ? a0 : a1; return r - f; } typedef pair Estimate; typedef vector Estimates; static void addEstimate(EstimateMap& map, const Alignment& a, Estimate& est, bool reverse) { // count up the number of estimates that agree bool placed = false; bool a_isRC = a.isRC != reverse; EstimateMap::iterator estimatesIt = map.find(a.contig); if (estimatesIt != map.end()) { Estimates& estimates = estimatesIt->second.estimates[a_isRC]; for (Estimates::iterator estIt = estimates.begin(); estIt != estimates.end(); ++estIt) { if (estIt->first.id() == est.first.id()) { estIt->second.numPairs++; estIt->second.distance += est.second.distance; placed = true; break; } } } if (!placed) map[a.contig].estimates[a_isRC].push_back(est); } static void doReadIntegrity(const ReadAlignMap::value_type& a) { AlignmentVector::const_iterator refAlignIter = a.second.begin(); unsigned firstStart, lastEnd, largestSize; Alignment first, last, largest; firstStart = refAlignIter->read_start_pos; lastEnd = firstStart + refAlignIter->align_length; largestSize = refAlignIter->align_length; first = last = largest = *refAlignIter; ++refAlignIter; // for each alignment in the vector a.second for (; refAlignIter != a.second.end(); ++refAlignIter) { if ((unsigned)refAlignIter->read_start_pos < firstStart) { firstStart = refAlignIter->read_start_pos; first = *refAlignIter; } if ((unsigned)(refAlignIter->read_start_pos + refAlignIter->align_length) > lastEnd) { lastEnd = refAlignIter->read_start_pos + refAlignIter->align_length; last = *refAlignIter; } if ((unsigned)refAlignIter->align_length > largestSize) { largestSize = refAlignIter->align_length; largest = *refAlignIter; } } if (largest.contig != last.contig) { Estimate est; unsigned largest_end = largest.read_start_pos + largest.align_length - opt::k; int distance = last.read_start_pos - largest_end; est.first = find_vertex(last.contig, largest.isRC != last.isRC, g_contigNames); est.second.distance = distance - opt::k; est.second.numPairs = 1; est.second.stdDev = 0; addEstimate(estMap, largest, est, false); } if (largest.contig != first.contig && largest.contig != last.contig) { Estimate est; unsigned first_end = first.read_start_pos + first.align_length - opt::k; int distance = last.read_start_pos - first_end; est.first = find_vertex(last.contig, first.isRC != last.isRC, g_contigNames); est.second.distance = distance - opt::k; est.second.numPairs = 1; est.second.stdDev = 0; addEstimate(estMap, first, est, false); } if (largest.contig != first.contig) { largest.flipQuery(); first.flipQuery(); Estimate est; unsigned largest_end = largest.read_start_pos + largest.align_length - opt::k; int distance = first.read_start_pos - largest_end; est.first = find_vertex(first.contig, largest.isRC != first.isRC, g_contigNames); est.second.distance = distance - opt::k; est.second.numPairs = 1; est.second.stdDev = 0; addEstimate(estMap, largest, est, false); } #if 0 //for each alignment in the vector a.second for (AlignmentVector::const_iterator refAlignIter = a.second.begin(); refAlignIter != a.second.end(); ++refAlignIter) { //for each alignment after the current one for (AlignmentVector::const_iterator alignIter = a.second.begin(); alignIter != a.second.end(); ++alignIter) { //make sure both alignments aren't for the same contig if (alignIter->contig != refAlignIter->contig) { Estimate est; //Make sure the distance is read as 0 if the two contigs are //directly adjacent to each other. A -ve number suggests an //overlap. assert(refAlignIter->read_start_pos != alignIter->read_start_pos); const Alignment& a = refAlignIter->read_start_pos < alignIter->read_start_pos ? *refAlignIter : *alignIter; const Alignment& b = refAlignIter->read_start_pos > alignIter->read_start_pos ? *refAlignIter : *alignIter; unsigned a_end = a.read_start_pos + a.align_length - opt::k; int distance = b.read_start_pos - a_end; est.nID = ContigID(b.contig); est.distance = distance - opt::k; est.numPairs = 1; est.stdDev = 0; //weird file format... est.isRC = a.isRC != b.isRC; addEstimate(estMap, a, est, false); } } } #endif } static void generateDistFile() { ofstream distFile(opt::distPath.c_str()); assert(distFile.is_open()); for (EstimateMap::iterator mapIt = estMap.begin(); mapIt != estMap.end(); ++mapIt) { // Skip empty iterators assert(!mapIt->second.estimates[0].empty() || !mapIt->second.estimates[1].empty()); distFile << mapIt->first; for (int refIsRC = 0; refIsRC <= 1; refIsRC++) { if (refIsRC) distFile << " ;"; for (Estimates::iterator vecIt = mapIt->second.estimates[refIsRC].begin(); vecIt != mapIt->second.estimates[refIsRC].end(); ++vecIt) { vecIt->second.distance = (int)round((double)vecIt->second.distance / (double)vecIt->second.numPairs); if (vecIt->second.numPairs >= opt::c && vecIt->second.numPairs != 0 /*&& vecIt->distance > 1 - opt::k*/) distFile << ' ' << get(g_contigNames, vecIt->first) << ',' << vecIt->second; } } distFile << '\n'; assert_good(distFile, opt::distPath); } distFile.close(); } static bool isSingleEnd(const string& id); static bool needsFlipping(const string& id); /** * Return an alignment flipped as necessary to produce an alignment * pair whose expected orientation is forward-reverse. If the * expected orientation is forward-forward, then reverse the first * alignment, so that the alignment is forward-reverse, which is * required by DistanceEst. */ static const Alignment flipAlignment(const Alignment& a, const string& id) { return needsFlipping(id) ? a.flipQuery() : a; } static void handleAlignmentPair(const ReadAlignMap::value_type& curr, const ReadAlignMap::value_type& pair) { const string& currID = curr.first; const string& pairID = pair.first; // Both reads must align to a unique location. // The reads are allowed to span more than one contig, but // at least one of the two reads must span no more than // two contigs. const unsigned MAX_SPAN = 2; if (curr.second.empty() && pair.second.empty()) { stats.bothUnaligned++; } else if (curr.second.empty() || pair.second.empty()) { stats.oneUnaligned++; } else if (!checkUniqueAlignments(curr.second) || !checkUniqueAlignments(pair.second)) { stats.numMulti++; } else if (curr.second.size() > MAX_SPAN && pair.second.size() > MAX_SPAN) { stats.numSplit++; } else { // Iterate over the vectors, outputting the aligments bool counted = false; for (AlignmentVector::const_iterator refAlignIter = curr.second.begin(); refAlignIter != curr.second.end(); ++refAlignIter) { for (AlignmentVector::const_iterator pairAlignIter = pair.second.begin(); pairAlignIter != pair.second.end(); ++pairAlignIter) { const Alignment& a0 = flipAlignment(*refAlignIter, currID); const Alignment& a1 = flipAlignment(*pairAlignIter, pairID); bool sameTarget = a0.contig == a1.contig; if (sameTarget && curr.second.size() == 1 && pair.second.size() == 1) { // Same target and the only alignment. if (a0.isRC != a1.isRC) { // Correctly oriented. Add this alignment to // the distribution of fragment sizes. int size = fragmentSize(a0, a1); histogram.insert(size); if (!opt::fragPath.empty()) { fragFile << size << '\n'; assert(fragFile.good()); } } else stats.numFF++; counted = true; } bool outputSameTarget = opt::fragPath.empty() && opt::histPath.empty(); if (!sameTarget || outputSameTarget) { cout << SAMRecord(a0, a1) << '\n' << SAMRecord(a1, a0) << '\n'; assert(cout.good()); } } } if (!counted) stats.numDifferent++; } } static void printProgress(const ReadAlignMap& map) { if (opt::verbose == 0) return; static size_t prevBuckets; if (prevBuckets == 0) prevBuckets = map.bucket_count(); size_t buckets = map.bucket_count(); if (stats.alignments % 1000000 == 0 || buckets != prevBuckets) { prevBuckets = buckets; size_t size = map.size(); cerr << "Read " << stats.alignments << " alignments. " "Hash load: " << size << " / " << buckets << " = " << (float)size / buckets << " using " << toSI(getMemoryUsage()) << "B." << endl; } } static void handleAlignment(const ReadAlignMap::value_type& alignments, ReadAlignMap& out) { if (!isSingleEnd(alignments.first)) { string pairID = makePairID(alignments.first); ReadAlignMap::iterator pairIter = out.find(pairID); if (pairIter != out.end()) { handleAlignmentPair(*pairIter, alignments); out.erase(pairIter); } else if (!out.insert(alignments).second) { cerr << "error: duplicate read ID `" << alignments.first << "'\n"; exit(EXIT_FAILURE); } } if (!opt::distPath.empty() && alignments.second.size() >= 2) doReadIntegrity(alignments); stats.alignments++; printProgress(out); } static void readAlignment(const string& line, ReadAlignMap& out) { istringstream s(line); pair v; switch (opt::inputFormat) { case opt::SAM: { SAMRecord sam; s >> sam; assert(s); v.first = sam.qname; if (sam.isRead1()) v.first += "/1"; else if (sam.isRead2()) v.first += "/2"; if (!sam.isUnmapped()) v.second.push_back(sam); break; } case opt::KALIGNER: { s >> v.first; assert(s); v.second.reserve(count(line.begin(), line.end(), '\t')); v.second.assign(istream_iterator(s), istream_iterator()); assert(s.eof()); break; } } handleAlignment(v, out); } static void readAlignments(istream& in, ReadAlignMap* pout) { for (string line; getline(in, line);) if (line.empty() || line[0] == '@') cout << line << '\n'; else readAlignment(line, *pout); assert(in.eof()); } static void readAlignmentsFile(string path, ReadAlignMap* pout) { if (opt::verbose > 0) cerr << "Reading `" << path << "'..." << endl; ifstream fin(path.c_str()); assert_good(fin, path); readAlignments(fin, pout); fin.close(); } /** Return the specified number formatted as a percent. */ static string percent(size_t x, size_t n) { ostringstream ss; ss << setw((int)log10(n) + 1) << x; if (x > 0) ss << " " << setprecision(3) << (float)100 * x / n << '%'; return ss.str(); } int main(int argc, char* const* 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 'l': arg >> opt::k; break; case 'c': arg >> opt::c; break; case 'd': arg >> opt::distPath; break; case 'f': arg >> opt::fragPath; break; case 'h': arg >> opt::histPath; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0 && opt::inputFormat == opt::KALIGNER) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (!opt::fragPath.empty()) { fragFile.open(opt::fragPath.c_str()); assert(fragFile.is_open()); } ReadAlignMap alignTable(1); if (optind < argc) { for_each(argv + optind, argv + argc, [&alignTable](const std::string& s) { readAlignmentsFile(s, &alignTable); }); } else { if (opt::verbose > 0) cerr << "Reading from standard input..." << endl; readAlignments(cin, &alignTable); } if (opt::verbose > 0) cerr << "Read " << stats.alignments << " alignments" << endl; unsigned numRF = histogram.count(INT_MIN, 0); unsigned numFR = histogram.count(1, INT_MAX); size_t sum = alignTable.size() + stats.bothUnaligned + stats.oneUnaligned + numFR + numRF + stats.numFF + stats.numDifferent + stats.numMulti + stats.numSplit; cerr << "Mateless " << percent(alignTable.size(), sum) << "\n" "Unaligned " << percent(stats.bothUnaligned, sum) << "\n" "Singleton " << percent(stats.oneUnaligned, sum) << "\n" "FR " << percent(numFR, sum) << "\n" "RF " << percent(numRF, sum) << "\n" "FF " << percent(stats.numFF, sum) << "\n" "Different " << percent(stats.numDifferent, sum) << "\n" "Multimap " << percent(stats.numMulti, sum) << "\n" "Split " << percent(stats.numSplit, sum) << "\n" "Total " << sum << endl; if (!opt::distPath.empty()) generateDistFile(); if (!opt::fragPath.empty()) fragFile.close(); if (!opt::histPath.empty()) { ofstream histFile(opt::histPath.c_str()); assert(histFile.is_open()); histFile << histogram; assert(histFile.good()); histFile.close(); } if (numFR < numRF) histogram = histogram.negate(); histogram.eraseNegative(); histogram.removeNoise(); histogram.removeOutliers(); Histogram h = histogram.trimFraction(0.0001); if (opt::verbose > 0) cerr << "Stats mean: " << setprecision(4) << h.mean() << " " "median: " << setprecision(4) << h.median() << " " "sd: " << setprecision(4) << h.sd() << " " "n: " << h.size() << " " "min: " << h.minimum() << " max: " << h.maximum() << '\n' << h.barplot() << endl; if (stats.numFF > numFR && stats.numFF > numRF) { cerr << "error: The mate pairs of this library are oriented " "forward-forward (FF), which is not supported by ABySS." << endl; exit(EXIT_FAILURE); } return 0; } /** Return whether any k-mer in the query is aligned more than once. */ static bool checkUniqueAlignments(const AlignmentVector& alignVec) { assert(!alignVec.empty()); if (alignVec.size() == 1) return true; unsigned nKmer = alignVec.front().read_length - opt::k + 1; vector coverage(nKmer); for (AlignmentVector::const_iterator iter = alignVec.begin(); iter != alignVec.end(); ++iter) { assert((unsigned)iter->align_length >= opt::k); unsigned end = iter->read_start_pos + iter->align_length - opt::k + 1; assert(end <= nKmer); for (unsigned i = iter->read_start_pos; i < end; i++) coverage[i]++; } for (unsigned i = 0; i < nKmer; ++i) if (coverage[i] > 1) return false; return true; } static bool replaceSuffix(string& s, const string& suffix0, const string& suffix1) { if (endsWith(s, suffix0)) { s.replace(s.length() - suffix0.length(), string::npos, suffix1); return true; } else if (endsWith(s, suffix1)) { s.replace(s.length() - suffix1.length(), string::npos, suffix0); return true; } else return false; } /** Return true if the specified read ID is of a single-end read. */ static bool isSingleEnd(const string& id) { unsigned l = id.length(); return endsWith(id, ".fn") || (l > 6 && id.substr(l - 6, 5) == ".part"); } /** Return the mate ID of the specified read ID. */ static string makePairID(string id) { if (equal(id.begin(), id.begin() + 3, "SRR")) return id; assert(!id.empty()); char& c = id[id.length() - 1]; switch (c) { case '1': c = '2'; return id; case '2': c = '1'; return id; case 'A': c = 'B'; return id; case 'B': c = 'A'; return id; case 'F': c = 'R'; return id; case 'R': c = 'F'; return id; case 'f': c = 'r'; return id; case 'r': c = 'f'; return id; } if (replaceSuffix(id, "forward", "reverse") || replaceSuffix(id, "F3", "R3")) return id; cerr << "error: read ID `" << id << "' must end in one of\n" "\t1 and 2 or A and B or F and R or" " F3 and R3 or forward and reverse\n"; exit(EXIT_FAILURE); } static bool needsFlipping(const string& id) { return endsWith(id, "F3"); } abyss-2.2.4/ParseAligns/abyss-fixmate.cc000066400000000000000000000354401361462241400201440ustar00rootroot00000000000000#include "ContigID.h" #include "DataBase/DB.h" #include "DataBase/Options.h" #include "Histogram.h" #include "IOUtil.h" #include "MemoryUtil.h" #include "SAM.h" #include "StringUtil.h" #include "Uncompress.h" #include "UnorderedMap.h" #include #include #include #include #include #include #include #include #include using namespace std; #define PROGRAM "abyss-fixmate" DB db; static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... [FILE]...\n" "Write read pairs that map to the same contig to the file SAME.\n" "Write read pairs that map to different contigs to stdout.\n" "Alignments may be in FILE(s) or standard input.\n" "\n" " Options:\n" "\n" " --no-qname set the qname to * [default]\n" " --qname do not alter the qname\n" " --all print all alignments\n" " --diff print alignments that align to different\n" " contigs [default]\n" " -l, --min-align=N the minimal alignment size [1]\n" " -s, --same=SAME write properly-paired reads to this file\n" " -h, --hist=FILE write the fragment size histogram to FILE\n" " -c, --cov=FILE write the physical coverage to FILE\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; static string fragPath; static string histPath; static string covPath; static int qname; static int verbose; static int print_all; } // for sqlite params static vector keys; static vector vals; static const char shortopts[] = "h:c:l:s:v"; 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 }, { "no-qname", no_argument, &opt::qname, 0 }, { "all", no_argument, &opt::print_all, 1 }, { "diff", no_argument, &opt::print_all, 0 }, { "min-align", required_argument, NULL, 'l' }, { "hist", required_argument, NULL, 'h' }, { "cov", required_argument, NULL, 'c' }, { "same", required_argument, NULL, 's' }, { "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 } }; static struct { size_t alignments; size_t bothUnaligned; size_t oneUnaligned; size_t numDifferent; size_t numFF; } stats; static ofstream g_fragFile; static Histogram g_histogram; static ofstream g_covFile; static vector> g_contigCov; static void incrementRange(SAMRecord& a) { unsigned inx = get(g_contigNames, a.rname); g_contigCov[inx][a.pos]++; assert(a.isize >= 0); unsigned end = a.pos + a.isize; if (end >= g_contigCov[inx].size()) end = g_contigCov[inx].size() - 1; g_contigCov[inx][end]--; } static void handlePair(SAMRecord& a0, SAMRecord& a1) { if ((a0.isRead1() && a1.isRead1()) || (a0.isRead2() && a1.isRead2())) { cerr << "error: duplicate read ID `" << a0.qname << (a0.isRead1() ? "/1" : "") << (a0.isRead2() ? "/2" : "") << "'\n"; exit(EXIT_FAILURE); } if (!opt::qname) a0.qname = a1.qname = "*"; fixMate(a0, a1); if (a0.isUnmapped() && a1.isUnmapped()) { // Both reads are unaligned. stats.bothUnaligned++; } else if (a0.isUnmapped() || a1.isUnmapped()) { // One read is unaligned. stats.oneUnaligned++; } else if (a0.rname != a1.rname) { // Different targets. stats.numDifferent++; // Set the mapping quality of both reads to their minimum. a0.mapq = a1.mapq = min(a0.mapq, a1.mapq); if (!opt::print_all) cout << a0 << '\n' << a1 << '\n'; } else if (a0.isReverse() == a1.isReverse()) { // Same target, FF orientation. stats.numFF++; } else { // Same target, FR or RF orientation. if (!opt::covPath.empty()) { SAMRecord a = a0.isize >= 0 ? a0 : a1; incrementRange(a); } g_histogram.insert(a0.isReverse() ? a1.isize : a0.isize); if (!opt::fragPath.empty()) { g_fragFile << a0 << '\n' << a1 << '\n'; assert(g_fragFile.good()); } } if (opt::print_all) { cout << a0 << '\n' << a1 << '\n'; assert(cout.good()); } } #if SAM_SEQ_QUAL typedef boost::unordered_map Alignments; #else typedef boost::unordered_map Alignments; #endif static void printProgress(const Alignments& map) { if (opt::verbose == 0) return; static size_t prevBuckets; if (prevBuckets == 0) prevBuckets = map.bucket_count(); size_t buckets = map.bucket_count(); if (stats.alignments % 1000000 == 0 || buckets != prevBuckets) { prevBuckets = buckets; size_t size = map.size(); cerr << "Read " << stats.alignments << " alignments. " << "Hash load: " << size << " / " << buckets << " = " << (float)size / buckets << " using " << toSI(getMemoryUsage()) << "B." << endl; } } static void handleAlignment(SAMRecord& sam, Alignments& map) { pair it = map.insert(make_pair(sam.qname, sam)); if (!it.second) { #if SAM_SEQ_QUAL SAMRecord& a0 = it.first->second; #else SAMRecord a0(it.first->second, it.first->first); #endif handlePair(a0, sam); #include #if BOOST_VERSION >= 104300 && BOOST_VERSION < 104800 // erase() is slow on older compilers so we use quick_erase() // quick_erase() is no longer necessary with BOOST 1.48.0. // quick_erase() is deprecated with BOOST 1.65.0. // See http://www.boost.org/doc/libs/1_65_0/doc/html/unordered/changes.html map.quick_erase(it.first); #else map.erase(it.first); #endif } stats.alignments++; printProgress(map); } static void assert_eof(istream& in) { if (in.eof()) return; in.clear(); string line; getline(in, line); cerr << "error: `" << line << "'\n"; exit(EXIT_FAILURE); } /** Print physical coverage in wiggle format. */ static void printCov(string file) { ofstream out(file.c_str()); for (unsigned i = 0; i < g_contigCov.size(); i++) { out << "variableStep\tchrom=" << get(g_contigNames, i) << '\n'; int prev = g_contigCov[i][0]; if (prev != 0) out << "0\t" << prev << '\n'; for (unsigned j = 1; j < g_contigCov[i].size(); j++) { prev += g_contigCov[i][j]; if (prev != 0) out << j << "\t" << prev << '\n'; } } } void parseTag(string line) { stringstream ss(line); string tag; char type[2]; string id; char delim; unsigned length; ss >> tag; if (tag != "@SQ") return; while (ss >> type[0] >> type[1] >> delim) { assert(delim == ':'); if (type[0] == 'S' && type[1] == 'N') ss >> id; else if (type[0] == 'L' && type[1] == 'N') ss >> length; } assert(length > 0); assert(id.size() > 0); put(g_contigNames, g_contigCov.size(), id); g_contigCov.push_back(vector(length)); } static void readAlignments(istream& in, Alignments* pMap) { for (SAMRecord sam; in >> ws;) { if (in.peek() == '@') { string line; getline(in, line); assert(in); if (!opt::covPath.empty()) parseTag(line); cout << line << '\n'; if (!opt::fragPath.empty()) g_fragFile << line << '\n'; } else if (in >> sam) handleAlignment(sam, *pMap); } if (!opt::covPath.empty()) printCov(opt::covPath); assert_eof(in); } static void readAlignmentsFile(string path, Alignments* pMap) { if (opt::verbose > 0) cerr << "Reading `" << path << "'..." << endl; ifstream fin(path.c_str()); assert_good(fin, path); readAlignments(fin, pMap); fin.close(); } /** Return the specified number formatted as a percent. */ static string percent(size_t x, size_t n) { ostringstream ss; ss << setw((int)log10(n) + 1) << x; if (x > 0) ss << " " << setprecision(3) << (float)100 * x / n << '%'; return ss.str(); } /** Print statistics of the specified histogram. h not passed by * reference because we want to make a copy **/ static void printHistogramStats(Histogram h) { unsigned n_orig = h.size(); h.eraseNegative(); h.removeNoise(); h.removeOutliers(); h = h.trimFraction(0.0001); cerr << "Stats mean: " << setprecision(4) << h.mean() << " " "median: " << setprecision(4) << h.median() << " " "sd: " << setprecision(4) << h.sd() << " " "n: " << h.size() << " " "min: " << h.minimum() << " " "max: " << h.maximum() << " " "ignored: " << n_orig - h.size() << '\n' << h.barplot() << endl; if (!opt::db.empty()) { vals = make_vector() << (int)round(h.mean()) << h.median() << (int)round(h.sd()) << h.size() << h.minimum() << h.maximum() << n_orig - h.size(); keys = make_vector() << "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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'l': arg >> opt::minAlign; break; case 's': arg >> opt::fragPath; break; case 'h': arg >> opt::histPath; break; case 'c': arg >> opt::covPath; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (!opt::fragPath.empty()) { g_fragFile.open(opt::fragPath.c_str()); 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, [&alignments](const std::string& s) { readAlignmentsFile(s, &alignments); }); } else { if (opt::verbose > 0) cerr << "Reading from standard input..." << endl; readAlignments(cin, &alignments); } 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) { for (Alignments::iterator it = alignments.begin(); it != alignments.end(); it++) { #if SAM_SEQ_QUAL SAMRecord& a0 = it->second; #else SAMRecord a0(it->second, it->first); #endif a0.noMate(); cout << a0 << '\n'; assert(cout.good()); } } unsigned numRF = g_histogram.count(INT_MIN, 0); unsigned numFR = g_histogram.count(1, INT_MAX); size_t sum = alignments.size() + stats.bothUnaligned + stats.oneUnaligned + numFR + numRF + stats.numFF + stats.numDifferent; cerr << "Mateless " << percent(alignments.size(), sum) << "\n" "Unaligned " << percent(stats.bothUnaligned, sum) << "\n" "Singleton " << percent(stats.oneUnaligned, sum) << "\n" "FR " << percent(numFR, sum) << "\n" "RF " << percent(numRF, sum) << "\n" "FF " << percent(stats.numFF, sum) << "\n" "Different " << percent(stats.numDifferent, sum) << "\n" "Total " << sum << endl; if (!opt::db.empty()) { vals = make_vector() << alignments.size() << stats.bothUnaligned << stats.oneUnaligned << numFR << numRF << stats.numFF << stats.numDifferent << sum; keys = make_vector() << "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." << endl; exit(EXIT_FAILURE); } if (!opt::fragPath.empty()) g_fragFile.close(); if (!opt::histPath.empty()) { ofstream histFile(opt::histPath.c_str()); assert(histFile.is_open()); histFile << g_histogram; assert(histFile.good()); histFile.close(); } if (opt::verbose > 0) { size_t numTotal = numFR + numRF; // Print the statistics of the forward-reverse distribution. if ((float)numFR / numTotal > 0.001) { cerr << "FR "; printHistogramStats(g_histogram); } // Print the statistics of the reverse-forward distribution. if ((float)numRF / numTotal > 0.001) { cerr << "RF "; printHistogramStats(g_histogram.negate()); } } if (stats.numFF > numFR && stats.numFF > numRF) { cerr << PROGRAM ": error: The mate pairs of this library are " "oriented forward-forward (FF), which is not supported " "by ABySS." << endl; exit(EXIT_FAILURE); } return 0; } abyss-2.2.4/PathOverlap/000077500000000000000000000000001361462241400150705ustar00rootroot00000000000000abyss-2.2.4/PathOverlap/Makefile.am000066400000000000000000000005011361462241400171200ustar00rootroot00000000000000bin_PROGRAMS = PathOverlap PathOverlap_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer PathOverlap_LDADD = \ $(top_builddir)/DataBase/libdb.a \ $(SQLITE_LIBS) \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a PathOverlap_SOURCES = \ PathOverlap.cpp abyss-2.2.4/PathOverlap/PathOverlap.cpp000066400000000000000000000515131361462241400200260ustar00rootroot00000000000000#include "ContigID.h" #include "ContigPath.h" #include "ContigProperties.h" #include "DataBase/DB.h" #include "DataBase/Options.h" #include "Functional.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "IOUtil.h" #include "Uncompress.h" #include "config.h" #include #include #include #include #include // for strerror #include #include #include #include #include #include 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" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char* USAGE_MESSAGE = "Usage: " PROGRAM " -k [OPTION]... ADJ PATH\n" "Find paths that overlap. Either output the graph of overlapping\n" "paths, assemble overlapping paths into larger paths, or trim the\n" "overlapping paths.\n" "\n" " Arguments:\n" "\n" " ADJ contig adjacency graph\n" " PATH sequences of contig IDs\n" "\n" " Options:\n" "\n" " -k, --kmer=N k-mer size\n" " -g, --graph=FILE write the contig adjacency graph to FILE\n" " -r, --repeats=FILE write repeat contigs to FILE\n" " --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" " --asqg output the graph in ASQG format\n" " --dot output the graph in GraphViz format\n" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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. */ int format; // used by ContigProperties /** Write the contig adjacency graph to this file. */ static string graphPath; /** Output the IDs of contigs in overlaps to this file. */ static string repeatContigs; /** Run a strand-specific RNA-Seq assembly. */ static int ss; /** Mode of operation. */ enum { /** Find overlapping paths, do not assemble. */ OVERLAP, /** Assemble overlapping paths. */ ASSEMBLE, /** Trim overlapping paths. */ TRIM, }; static int mode; static int verbose; } static const char* shortopts = "g:k:r:v"; 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' }, { "kmer", required_argument, NULL, 'k' }, { "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 }, { "asqg", no_argument, &opt::format, ASQG }, { "dot", no_argument, &opt::format, DOT }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "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 } }; /** A vertex of the overlap graph. */ struct Vertex { unsigned id; bool sense; /** The number of single-end contigs. */ static unsigned s_offset; Vertex(unsigned id, bool sense) : id(id) , sense(sense) {} bool operator==(const Vertex& v) const { return id == v.id && sense == v.sense; } ContigNode descriptor() const { return ContigNode(s_offset + id, sense); } }; unsigned Vertex::s_offset; /** An alignment of two overlapping contigs. */ struct Overlap { Vertex source; Vertex target; /** Overlap measured in number of contigs. */ unsigned overlap; /** Overlap measured in bp. */ int distance; Overlap(const Vertex& source, const Vertex& target, unsigned overlap, int distance) : source(source) , target(target) , overlap(overlap) , distance(distance) {} }; /** The contig IDs that have been removed from paths. */ static vector s_trimmedContigs; /** The contig graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; typedef vector Paths; /** Return whether this vertex is a path or a contig. */ static bool isPath(const ContigNode& u) { return u.id() >= Vertex::s_offset; } /** Return a path, complemented if necessary. */ static ContigPath getPath(const Paths& paths, const ContigNode& u) { if (isPath(u)) { unsigned i = u.id() - Vertex::s_offset; return u.sense() ? reverseComplement(paths[i]) : paths[i]; } else return ContigPath(1, u); } /** Read contig paths from the specified file. * @param g the contig adjacency graph * @param inPath the file of contig paths * @param[out] pathIDs the path IDs * @return the paths */ static Paths readPaths(Graph& g, const string& inPath, vector& pathIDs) { typedef graph_traits::vertex_descriptor V; assert(pathIDs.empty()); ifstream fin(inPath.c_str()); if (opt::verbose > 0) cerr << "Reading `" << inPath << "'..." << endl; if (inPath != "-") assert_good(fin, inPath); istream& in = inPath == "-" ? cin : fin; assert_good(in, inPath); Paths paths; string id; ContigPath path; while (in >> id >> path) { if (path.empty()) { // Remove this contig from the graph. V u = find_vertex(id, false, g); clear_vertex(u, g); remove_vertex(u, g); } else { pathIDs.push_back(id); paths.push_back(path); } } assert(in.eof()); return paths; } typedef multimap SeedMap; /** Index the first and last contig of each path to facilitate finding * overlaps between paths. */ static SeedMap makeSeedMap(const Paths& paths) { SeedMap seedMap; for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) { if (it->empty()) continue; assert(!it->front().ambiguous()); seedMap.insert(make_pair(it->front(), Vertex(it - paths.begin(), false))); assert(!it->back().ambiguous()); seedMap.insert(make_pair(it->back() ^ 1, Vertex(it - paths.begin(), true))); } return seedMap; } /** Check whether path starts with the sequence [first, last). */ static bool startsWith( ContigPath path, bool rc, ContigPath::const_iterator first, ContigPath::const_iterator last) { if (rc) reverseComplement(path.begin(), path.end()); assert(*first == path.front()); assert(first < last); return unsigned(last - first) > path.size() ? false : equal(first, last, path.begin()); } /** Check whether path starts with the sequence [first, last). */ static unsigned findOverlap( const Graph& g, const Paths& paths, ContigPath::const_iterator first, ContigPath::const_iterator last, const Vertex& v, int& distance) { if (!startsWith(paths[v.id], v.sense, first, last)) return 0; distance = -addProp(g, first, last).length; return last - first; } typedef vector Overlaps; /** Find every path that overlaps with the specified path. */ static void findOverlaps( const Graph& g, const Paths& paths, const SeedMap& seedMap, const Vertex& v, Overlaps& overlaps) { ContigPath rc; if (v.sense) { rc = paths[v.id]; reverseComplement(rc.begin(), rc.end()); } const ContigPath& path = v.sense ? rc : paths[v.id]; for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) { if (it->ambiguous()) continue; pair range = seedMap.equal_range(*it); for (SeedMap::const_iterator seed = range.first; seed != range.second; ++seed) { if (v == seed->second) continue; int distance = 0; unsigned overlap = findOverlap(g, paths, it, path.end(), seed->second, distance); if (overlap > 0) overlaps.push_back(Overlap(v, seed->second, overlap, distance)); } } } /** Find every pair of overlapping paths. */ static Overlaps findOverlaps(const Graph& g, const Paths& paths) { SeedMap seedMap = makeSeedMap(paths); Overlaps overlaps; for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) { unsigned i = it - paths.begin(); findOverlaps(g, paths, seedMap, Vertex(i, false), overlaps); findOverlaps(g, paths, seedMap, Vertex(i, true), overlaps); } return overlaps; } /** Record the trimmed contigs. */ static void recordTrimmedContigs(ContigPath::const_iterator first, ContigPath::const_iterator last) { for (ContigPath::const_iterator it = first; it != last; ++it) if (!it->ambiguous()) s_trimmedContigs.push_back(it->contigIndex()); } /** Remove ambiguous contigs from the ends of the path. */ static void removeAmbiguousContigs(ContigPath& path) { if (!path.empty() && path.back().ambiguous()) path.erase(path.end() - 1); if (!path.empty() && path.front().ambiguous()) path.erase(path.begin()); } /** Remove the overlapping portion of the specified contig. */ static void removeContigs(ContigPath& path, unsigned first, unsigned last) { assert(first <= path.size()); assert(last <= path.size()); if (first < last) { recordTrimmedContigs(path.begin(), path.begin() + first); recordTrimmedContigs(path.begin() + last, path.end()); path.erase(path.begin() + last, path.end()); path.erase(path.begin(), path.begin() + first); } else { recordTrimmedContigs(path.begin(), path.end()); path.clear(); } removeAmbiguousContigs(path); } /** Find the largest overlap for each contig and remove it. */ static void trimOverlaps(Paths& paths, const Overlaps& overlaps) { vector removed[2]; removed[0].resize(paths.size()); removed[1].resize(paths.size()); for (Overlaps::const_iterator it = overlaps.begin(); it != overlaps.end(); ++it) { unsigned& a = removed[!it->source.sense][it->source.id]; unsigned& b = removed[it->target.sense][it->target.id]; a = max(a, it->overlap); b = max(b, it->overlap); } for (Paths::iterator it = paths.begin(); it != paths.end(); ++it) removeContigs( *it, removed[0][it - paths.begin()], it->size() - removed[1][it - paths.begin()]); } /** Trim the ends of paths that overlap another path. */ static void trimOverlaps(const Graph& g, Paths& paths) { for (Overlaps overlaps = findOverlaps(g, paths); !overlaps.empty(); overlaps = findOverlaps(g, paths)) { cerr << "Found " << overlaps.size() / 2 << " overlaps.\n"; trimOverlaps(paths, overlaps); } } static inline ContigProperties get(vertex_bundle_t, const Graph& g, ContigNode u) { return u.ambiguous() ? ContigProperties(u.length() + opt::k - 1, 0) : g[u]; } /** Add the path overlap edges to the specified graph. */ static void addPathOverlapEdges( Graph& g, const Paths& paths, const vector& pathIDs, const Overlaps& overlaps) { typedef graph_traits::vertex_descriptor V; const bool allowParallelEdge = opt::mode == opt::ASSEMBLE; // Add the path vertices. g_contigNames.unlock(); for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) { const ContigPath& path = *it; const string& id = pathIDs[it - paths.begin()]; if (!path.empty()) { V u = merge(g, path.begin(), path.end()); put(vertex_name, g, u, id); } } g_contigNames.lock(); // Remove the single-end contigs that are in paths. for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) remove_vertex_if( g, it->begin(), it->end(), [](const ContigNode& c) { return !c.ambiguous(); }); // Add the path edges. for (Overlaps::const_iterator it = overlaps.begin(); it != overlaps.end(); ++it) { V u = it->source.descriptor(); V v = it->target.descriptor(); if (allowParallelEdge || !edge(u, v, g).second) add_edge(u, v, it->distance, static_cast(g)); else if (opt::verbose > 0) cerr << "ambiguous overlap: " << get(vertex_name, g, u) << " -> " << get(vertex_name, g, v) << '\n'; } } typedef graph_traits::edge_descriptor edge_descriptor; /** A property map giving the number of contigs by which two paths * overlap. */ typedef map OverlapMap; /** Return the number of contigs by which the two paths overlap. */ static unsigned getOverlap( const OverlapMap& pmap, graph_traits::vertex_descriptor u, graph_traits::vertex_descriptor v) { if (isPath(u) && isPath(v)) { // Both vertices are paths. OverlapMap::const_iterator it = pmap.find(edge_descriptor(u, v)); return it == pmap.end() ? 0 : it->second; } else { // One of the two vertices is a contig. return 0; } } /** Merge a sequence of overlapping paths. */ static ContigPath mergePaths(const Paths& paths, const OverlapMap& overlaps, const ContigPath& merge) { assert(!merge.empty()); ContigNode u = merge.front(); ContigPath path(getPath(paths, u)); for (ContigPath::const_iterator it = merge.begin() + 1; it != merge.end(); ++it) { ContigNode v = *it; ContigPath vpath(getPath(paths, v)); unsigned overlap = getOverlap(overlaps, u, v); assert(path.size() > overlap); assert(vpath.size() > overlap); assert(equal(path.end() - overlap, path.end(), vpath.begin())); path.insert(path.end(), vpath.begin() + overlap, vpath.end()); u = v; } return path; } /** Return true if the edge e is a path overlap. */ struct IsPathOverlap : unary_function { IsPathOverlap(const Graph& g, const OverlapMap& pmap, const IsPositive& pred) : m_g(g) , m_pmap(pmap) , m_isPositive(pred) {} bool operator()(edge_descriptor e) const { bool stranded = true; if (opt::ss) stranded = m_isPositive(e); return stranded && getOverlap(m_pmap, source(e, m_g), target(e, m_g)); } private: const Graph& m_g; const OverlapMap& m_pmap; const IsPositive& m_isPositive; }; /** Assemble overlapping paths. */ static void assembleOverlappingPaths(Graph& g, Paths& paths, vector& pathIDs) { if (paths.empty()) return; // Find overlapping paths. Overlaps overlaps = findOverlaps(g, paths); addPathOverlapEdges(g, paths, pathIDs, overlaps); // Create a property map of path overlaps. OverlapMap overlapMap; for (Overlaps::const_iterator it = overlaps.begin(); it != overlaps.end(); ++it) overlapMap.insert(OverlapMap::value_type( OverlapMap::key_type(it->source.descriptor(), it->target.descriptor()), it->overlap)); // Assemble unambiguously overlapping paths. Paths merges; assemble_if(g, back_inserter(merges), IsPathOverlap(g, overlapMap, IsPositive(g))); // Merge overlapping paths. g_contigNames.unlock(); assert(!pathIDs.empty()); setNextContigName(pathIDs.back()); for (Paths::const_iterator it = merges.begin(); it != merges.end(); ++it) { string name = createContigName(); if (opt::verbose > 0) cerr << name << '\t' << *it << '\n'; Vertex u(paths.size(), false); put(vertex_name, g, u.descriptor(), name); pathIDs.push_back(name); paths.push_back(mergePaths(paths, overlapMap, *it)); // Remove the merged paths. for (ContigPath::const_iterator it2 = it->begin(); it2 != it->end(); ++it2) { if (isPath(*it2)) paths[it2->id() - Vertex::s_offset].clear(); } } g_contigNames.lock(); } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'g': arg >> opt::graphPath; break; case 'k': arg >> opt::k; break; case 'r': arg >> opt::repeatContigs; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } const char* adjPath = argv[optind++]; if (opt::verbose > 0) cerr << "Reading `" << adjPath << "'..." << endl; ifstream fin(adjPath); assert_good(fin, adjPath); Graph g; fin >> g; Vertex::s_offset = g.num_vertices() / 2; string pathsFile(argv[optind++]); vector pathIDs; Paths paths = readPaths(g, pathsFile, pathIDs); switch (opt::mode) { case opt::OVERLAP: // Find overlapping paths, do not assemble. addPathOverlapEdges(g, paths, pathIDs, findOverlaps(g, paths)); paths.clear(); if (opt::graphPath.empty()) opt::graphPath = "-"; break; case opt::ASSEMBLE: // Assemble overlapping paths. assembleOverlappingPaths(g, paths, pathIDs); break; case opt::TRIM: // Trim overlapping paths. trimOverlaps(g, paths); // Remove paths consisting of a single contig. for_each_if( paths.begin(), paths.end(), [](ContigPath& c) { return c.clear(); }, [](const ContigPath& c) { return c.size() == 1; }); // Add the paths to the graph. addPathOverlapEdges(g, paths, pathIDs, Overlaps()); break; } // Output the paths. for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) { if (it->empty()) continue; assert(it->size() != 1); cout << pathIDs[it - paths.begin()] << '\t' << *it << '\n'; } assert(cout.good()); // Output the graph. if (!opt::graphPath.empty()) { ofstream fout; ostream& out = opt::graphPath == "-" ? cout : (fout.open(opt::graphPath.c_str()), fout); assert_good(out, opt::graphPath); write_graph(out, g, PROGRAM, commandLine); assert_good(out, opt::graphPath); } // Output the repeat contigs. if (!opt::repeatContigs.empty()) { sort(s_trimmedContigs.begin(), s_trimmedContigs.end()); s_trimmedContigs.erase( unique(s_trimmedContigs.begin(), s_trimmedContigs.end()), s_trimmedContigs.end()); ofstream out(opt::repeatContigs.c_str()); assert_good(out, opt::repeatContigs); for (vector::const_iterator it = s_trimmedContigs.begin(); it != s_trimmedContigs.end(); ++it) out << get(g_contigNames, *it) << '\n'; 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; } abyss-2.2.4/PopBubbles/000077500000000000000000000000001361462241400147005ustar00rootroot00000000000000abyss-2.2.4/PopBubbles/Makefile.am000066400000000000000000000006411361462241400167350ustar00rootroot00000000000000bin_PROGRAMS = PopBubbles PopBubbles_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Align \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer PopBubbles_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) PopBubbles_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Align/libalign.a \ $(top_builddir)/Common/libcommon.a \ $(top_builddir)/dialign/libdialign.a PopBubbles_SOURCES = PopBubbles.cpp abyss-2.2.4/PopBubbles/PopBubbles.cpp000066400000000000000000000527501361462241400174520ustar00rootroot00000000000000/** * Identify and pop simple bubbles. * Written by Shaun Jackman . */ #include "Graph/PopBubbles.h" #include "Common/Options.h" #include "ConstString.h" #include "ContigPath.h" #include "ContigProperties.h" #include "FastaReader.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DepthFirstSearch.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "IOUtil.h" #include "Sequence.h" #include "Uncompress.h" #include "alignGlobal.h" #include "config.h" #include #include #include #include // for UINT_MAX #include #include #include #include #include #include #include #include #include #include #include #if _OPENMP #include #endif using namespace std; using namespace boost::lambda; using boost::tie; #define PROGRAM "PopBubbles" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... FASTA ADJ\n" "Identify and pop simple bubbles.\n" "\n" " Arguments:\n" "\n" " FASTA contigs in FASTA format\n" " ADJ contig adjacency graph\n" "\n" " Options:\n" "\n" " -k, --kmer=N k-mer size\n" " -a, --branches=N maximum number of branches, default: 2\n" " -b, --bubble-length=N pop bubbles shorter than N bp\n" " default is 10000\n" " -p, --identity=REAL minimum identity, default: 0.9\n" " -c, --coverage=REAL remove contigs with mean k-mer coverage\n" " less than this threshold [0]\n" " --scaffold scaffold over bubbles that have\n" " insufficient identity\n" " --no-scaffold disable scaffolding [default]\n" " --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" " --gfa output the graph in GFA1 format\n" " --gfa1 output the graph in GFA1 format\n" " --gfa2 output the graph in GFA2 format\n" " --gv output the graph in GraphViz 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" " --version output version information and exit\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { unsigned k; // used by ContigProperties /** Maximum number of branches. */ static unsigned maxBranches = 2; /** Pop bubbles shorter than this threshold. */ static unsigned maxLength = 10000; /** Minimum identity. */ static float identity = 0.9; /** Minimum mean k-mer coverage. */ static float minCoverage; /** Scaffold over bubbles that have insufficient identity. */ static int scaffold; /** Write the contig adjacency graph to this file. */ static string graphPath; /** Output a graph of the bubbles. */ static int bubbleGraph; int format; // used by ContigProperties /** Run a strand-specific RNA-Seq assembly. */ static int ss; /** Number of threads. */ static int threads = 1; } static const char shortopts[] = "a:b:c:g:j:k:p:v"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "branches", required_argument, NULL, 'a' }, { "bubble-length", required_argument, NULL, 'b' }, { "coverage", required_argument, NULL, 'c' }, { "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 }, { "gfa", no_argument, &opt::format, GFA1 }, { "gfa1", no_argument, &opt::format, GFA1 }, { "gfa2", no_argument, &opt::format, GFA2 }, { "gv", no_argument, &opt::format, DOT }, { "sam", no_argument, &opt::format, SAM }, { "kmer", required_argument, NULL, 'k' }, { "identity", required_argument, NULL, 'p' }, { "scaffold", no_argument, &opt::scaffold, 1 }, { "no-scaffold", no_argument, &opt::scaffold, 0 }, { "SS", no_argument, &opt::ss, 1 }, { "no-SS", no_argument, &opt::ss, 0 }, { "threads", required_argument, NULL, 'j' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Popped branches. */ static vector g_popped; /** Contig adjacency graph. */ typedef ContigGraph> Graph; typedef Graph::vertex_descriptor vertex_descriptor; typedef Graph::adjacency_iterator adjacency_iterator; /** Return the distance from vertex u to v. */ static int getDistance(const Graph& g, vertex_descriptor u, vertex_descriptor v) { typedef graph_traits::edge_descriptor edge_descriptor; pair e = edge(u, v, g); assert(e.second); return g[e.first].distance; } struct CompareCoverage { const Graph& g; CompareCoverage(const Graph& g) : g(g) {} bool operator()(vertex_descriptor u, vertex_descriptor v) { return g[u].coverage > g[v].coverage; } }; /** Pop the bubble between vertices v and tail. */ static void popBubble(Graph& g, vertex_descriptor v, vertex_descriptor tail) { unsigned nbranches = g.out_degree(v); assert(nbranches > 1); assert(nbranches == g.in_degree(tail)); vector sorted(nbranches); pair adj = g.adjacent_vertices(v); copy(adj.first, adj.second, sorted.begin()); sort(sorted.begin(), sorted.end(), CompareCoverage(g)); if (opt::bubbleGraph) #pragma omp critical(cout) { cout << '"' << get(vertex_name, g, v) << "\" -> {"; for (vector::const_iterator it = sorted.begin(); it != sorted.end(); ++it) cout << " \"" << get(vertex_name, g, *it) << '"'; cout << " } -> \"" << get(vertex_name, g, tail) << "\"\n"; } #pragma omp critical(g_popped) transform(sorted.begin() + 1, sorted.end(), back_inserter(g_popped), [](const ContigNode& c) { return c.contigIndex(); }); } static struct { unsigned bubbles; unsigned popped; unsigned scaffold; unsigned notSimple; unsigned tooLong; unsigned tooMany; unsigned dissimilar; } g_count; /** Contig sequences. */ typedef vector 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 the length of vertex v. */ static unsigned getLength(const Graph* g, vertex_descriptor v) { return (*g)[v].length; } /** Align the sequences of [first,last). * @param t the vertex to the left of the bubble * @param v the vertex to the right of the bubble * @return the identity of the global alignment */ template static float getAlignmentIdentity(const Graph& g, vertex_descriptor t, vertex_descriptor v, It first, It last) { unsigned nbranches = distance(first, last); vector inDists(nbranches); transform( first, last, inDists.begin(), boost::lambda::bind(getDistance, boost::cref(g), t, _1)); vector outDists(nbranches); transform( first, last, outDists.begin(), boost::lambda::bind(getDistance, boost::cref(g), _1, v)); vector insertLens(nbranches); transform( first, last, insertLens.begin(), 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())); assert(max_in_overlap >= 0); int max_out_overlap = -(*min_element(outDists.begin(), outDists.end())); assert(max_out_overlap >= 0); int min_insert_len = *min_element(insertLens.begin(), insertLens.end()); int max_insert_len = *max_element(insertLens.begin(), insertLens.end()); float max_identity = (float)(min_insert_len + max_in_overlap + max_out_overlap) / (max_insert_len + max_in_overlap + max_out_overlap); if (min_insert_len <= 0 || max_identity < opt::identity) return max_identity; vector seqs(nbranches); 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(); int l = -inDists[i], r = -outDists[i]; assert(n > l + r); seqs[i] = seqs[i].substr(l, n - l - r); } unsigned matches, consensusSize; tie(matches, consensusSize) = align(seqs); return (float)(matches + max_in_overlap + max_out_overlap) / (consensusSize + max_in_overlap + max_out_overlap); } /** Pop the specified bubble if it is a simple bubble. * @return whether the bubble is popped */ static bool popSimpleBubble(Graph* pg, vertex_descriptor v) { Graph& g = *pg; unsigned nbranches = g.out_degree(v); assert(nbranches >= 2); vertex_descriptor v1 = *g.adjacent_vertices(v).first; if (g.out_degree(v1) != 1) { #pragma omp atomic g_count.notSimple++; return false; } vertex_descriptor tail = *g.adjacent_vertices(v1).first; if (v == get(vertex_complement, g, tail) // Palindrome || g.in_degree(tail) != nbranches) { #pragma omp atomic g_count.notSimple++; return false; } // Check that every branch is simple and ends at the same node. pair adj = g.adjacent_vertices(v); for (adjacency_iterator it = adj.first; it != adj.second; ++it) { if (g.out_degree(*it) != 1 || g.in_degree(*it) != 1) { #pragma omp atomic g_count.notSimple++; return false; } if (*g.adjacent_vertices(*it).first != tail) { // The branches do not merge back to the same node. #pragma omp atomic g_count.notSimple++; return false; } } if (opt::verbose > 2) #pragma omp critical(cerr) { cerr << "\n* " << get(vertex_name, g, v) << " ->"; for (adjacency_iterator it = adj.first; it != adj.second; ++it) cerr << ' ' << get(vertex_name, g, *it); cerr << " -> " << get(vertex_name, g, tail) << '\n'; } if (nbranches > opt::maxBranches) { // Too many branches. #pragma omp atomic g_count.tooMany++; if (opt::verbose > 1) #pragma omp critical(cerr) cerr << nbranches << " paths (too many)\n"; return false; } vector lengths(nbranches); transform(adj.first, adj.second, lengths.begin(), [&g](const ContigNode& c) { return getLength(&g, c); }); unsigned minLength = *min_element(lengths.begin(), lengths.end()); unsigned maxLength = *max_element(lengths.begin(), lengths.end()); if (maxLength >= opt::maxLength) { // This branch is too long. #pragma omp atomic g_count.tooLong++; if (opt::verbose > 1) #pragma omp critical(cerr) cerr << minLength << '\t' << maxLength << "\t0\t(too long)\n"; return false; } float identity = opt::identity == 0 ? 0 : getAlignmentIdentity(g, v, tail, adj.first, adj.second); bool dissimilar = identity < opt::identity; if (opt::verbose > 1) #pragma omp critical(cerr) cerr << minLength << '\t' << maxLength << '\t' << identity << (dissimilar ? "\t(dissimilar)" : "") << '\n'; if (dissimilar) { // Insufficient identity. #pragma omp atomic g_count.dissimilar++; return false; } #pragma omp atomic g_count.popped++; popBubble(g, v, tail); return true; } /** Add distances to a path. */ static ContigPath addDistance(const Graph& g, const ContigPath& path) { ContigPath out; out.reserve(path.size()); ContigNode u = path.front(); out.push_back(u); for (ContigPath::const_iterator it = path.begin() + 1; it != path.end(); ++it) { ContigNode v = *it; int distance = getDistance(g, u, v); if (distance >= 0) { int numN = distance + opt::k - 1; // by convention assert(numN >= 0); numN = max(numN, 1); out.push_back(ContigNode(numN, 'N')); } out.push_back(v); u = v; } return out; } /** Return the length of the longest path through the bubble. */ static int longestPath(const Graph& g, const Bubble& topo) { typedef graph_traits::edge_descriptor E; typedef graph_traits::out_edge_iterator Eit; typedef graph_traits::vertex_descriptor V; EdgeWeightMap weight(g); map distance; distance[topo.front()] = 0; for (Bubble::const_iterator it = topo.begin(); it != topo.end(); ++it) { V u = *it; Eit eit, elast; for (tie(eit, elast) = out_edges(u, g); eit != elast; ++eit) { E e = *eit; V v = target(e, g); distance[v] = max(distance[v], distance[u] + weight[e]); } } V v = topo.back(); return distance[v] - g[v].length; } /** Scaffold over the bubble between vertices u and w. * Add an edge (u,w) with the distance property set to the length of * the largest branch of the bubble. */ static void scaffoldBubble(Graph& g, const Bubble& bubble) { typedef graph_traits::vertex_descriptor V; assert(opt::scaffold); assert(bubble.size() > 2); V u = bubble.front(), w = bubble.back(); if (edge(u, w, g).second) { // Already scaffolded. return; } assert(isBubble(g, bubble.begin(), bubble.end())); assert(bubble.size() > 2); size_t n = bubble.size() - 2; g_popped.reserve(g_popped.size() + n); for (Bubble::const_iterator it = bubble.begin() + 1; it != bubble.end() - 1; ++it) g_popped.push_back(it->contigIndex()); add_edge(u, w, max(longestPath(g, bubble), 1), g); } /** Pop the specified bubble if it is simple, otherwise scaffold. */ static void popOrScaffoldBubble(Graph& g, const Bubble& bubble) { #pragma omp atomic g_count.bubbles++; if (!popSimpleBubble(&g, bubble.front()) && opt::scaffold) { #pragma omp atomic g_count.scaffold++; scaffoldBubble(g, bubble); } } /** Return the length of the specified vertex in k-mer. */ static unsigned getKmerLength(const ContigProperties& vp) { assert(vp.length >= opt::k); return vp.length - opt::k + 1; } /** Return the mean k-mer coverage of the specified vertex. */ static float getMeanCoverage(const ContigProperties& vp) { return (float)vp.coverage / getKmerLength(vp); } /** Remove contigs with insufficient coverage. */ static void filterGraph(Graph& g) { typedef graph_traits GTraits; typedef GTraits::vertex_descriptor V; typedef GTraits::vertex_iterator Vit; unsigned removedContigs = 0, removedKmer = 0; std::pair urange = vertices(g); for (Vit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (get(vertex_removed, g, u)) continue; const ContigProperties& vp = g[u]; if (getMeanCoverage(vp) < opt::minCoverage) { removedContigs++; removedKmer += getKmerLength(vp); clear_vertex(u, g); remove_vertex(u, g); g_popped.push_back(get(vertex_contig_index, g, u)); } } if (opt::verbose > 0) { cerr << "Removed " << removedKmer << " k-mer in " << removedContigs << " contigs with mean k-mer coverage " "less than " << opt::minCoverage << ".\n"; printGraphStats(cerr, g); } } /** Remove the specified contig from the adjacency graph. */ static void removeContig(Graph* g, ContigID id) { ContigNode v(id, false); g->clear_vertex(v); g->remove_vertex(v); } int main(int argc, char** argv) { string commandLine; { ostringstream ss; char** last = argv + argc - 1; copy(argv, last, ostream_iterator(ss, " ")); ss << *last; commandLine = ss.str(); } 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 'a': arg >> opt::maxBranches; break; case 'b': arg >> opt::maxLength; break; case 'c': arg >> opt::minCoverage; break; case 'g': arg >> opt::graphPath; break; case 'j': arg >> opt::threads; break; case 'k': arg >> opt::k; break; case 'p': arg >> opt::identity; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } const char* contigsPath(argv[optind++]); string adjPath(argv[optind++]); // Read the contig adjacency graph. if (opt::verbose > 0) cerr << "Reading `" << adjPath << "'...\n"; ifstream fin(adjPath.c_str()); assert_good(fin, adjPath); Graph g; fin >> g; assert(fin.eof()); g_contigNames.lock(); if (opt::verbose > 0) printGraphStats(cerr, g); // Read the contigs. Contigs& contigs = g_contigs; if (opt::identity > 0) { 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()); assert(!contigs.empty()); opt::colourSpace = isdigit(contigs.front()[0]); } // Remove contigs with insufficient coverage. if (opt::minCoverage > 0) filterGraph(g); if (opt::bubbleGraph) cout << "digraph bubbles {\n"; Bubbles bubbles = discoverBubbles(g); for (Bubbles::const_iterator it = bubbles.begin(); it != bubbles.end(); ++it) popOrScaffoldBubble(g, *it); // Each bubble should be identified twice. Remove the duplicate. sort(g_popped.begin(), g_popped.end()); g_popped.erase(unique(g_popped.begin(), g_popped.end()), g_popped.end()); if (opt::bubbleGraph) { cout << "}\n"; } else { for (vector::const_iterator it = g_popped.begin(); it != g_popped.end(); ++it) cout << get(g_contigNames, *it) << '\n'; } if (opt::verbose > 0) cerr << "Bubbles: " << (g_count.bubbles + 1) / 2 << " Popped: " << (g_count.popped + 1) / 2 << " Scaffolds: " << (g_count.scaffold + 1) / 2 << " Complex: " << (g_count.notSimple + 1) / 2 << " Too long: " << (g_count.tooLong + 1) / 2 << " Too many: " << (g_count.tooMany + 1) / 2 << " Dissimilar: " << (g_count.dissimilar + 1) / 2 << '\n'; if (!opt::graphPath.empty()) { // Remove the popped contigs from the adjacency graph. for_each(g_popped.begin(), g_popped.end(), [&g](const ContigID& c) { return removeContig(&g, c); }); // Assemble unambiguous paths. g_contigNames.unlock(); typedef vector ContigPaths; ContigPaths paths; size_t numContigs = num_vertices(g) / 2; if (opt::scaffold) { Graph gorig = g; if (opt::ss) assemble_stranded(g, back_inserter(paths)); else assemble(g, back_inserter(paths)); for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { ContigNode u(numContigs + it - paths.begin(), false); string name = createContigName(); put(vertex_name, g, u, name); cout << name << '\t' << addDistance(gorig, *it) << '\n'; } } else { if (opt::ss) assemble_stranded(g, back_inserter(paths)); else assemble(g, back_inserter(paths)); for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { ContigNode u(numContigs + it - paths.begin(), false); string name = createContigName(); put(vertex_name, g, u, name); cout << name << '\t' << *it << '\n'; } } g_contigNames.lock(); paths.clear(); // Output the updated adjacency graph. ofstream fout(opt::graphPath.c_str()); assert_good(fout, opt::graphPath); write_graph(fout, g, PROGRAM, commandLine); assert_good(fout, opt::graphPath); if (opt::verbose > 0) printGraphStats(cerr, g); } return 0; } abyss-2.2.4/README.md000066400000000000000000000622621361462241400141320ustar00rootroot00000000000000[![Release](https://img.shields.io/github/release/bcgsc/abyss.svg)](https://github.com/bcgsc/abyss/releases) [![Downloads](https://img.shields.io/github/downloads/bcgsc/abyss/total?logo=github)](https://github.com/bcgsc/abyss/releases/download/2.2.3/abyss-2.2.3.tar.gz) [![Conda](https://img.shields.io/conda/dn/bioconda/abyss?label=Conda)](https://anaconda.org/bioconda/abyss) [![Issues](https://img.shields.io/github/issues/bcgsc/abyss.svg)](https://github.com/bcgsc/abyss/issues) ABySS ===== ABySS is a *de novo* sequence assembler intended for short paired-end reads and large genomes. Please [cite our papers](#citation). News ==== 3 May 2019 Looking for a fun & worthy challenge? Think you can contribute code to this project? Join our team of developers! We are currently looking for C++ bioinformatics programmers. Inquire for staff, graduate student, and postdoctoral positions. [Contact the project lead (Inanc Birol)](mailto:ibirol@bcgsc.ca?Subject=ABySS%20developer%20position) Contents ======== * [Quick Start](#quick-start) * [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 GitHub](#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) * [Scaffolding with linked reads](#scaffolding-with-linked-reads) * [Rescaffolding with long sequences](#rescaffolding-with-long-sequences) * [Assembling using a Bloom filter de Bruijn graph](#assembling-using-a-bloom-filter-de-bruijn-graph) * [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) * [Citation](#citation) * [Related Publications](#related-publications) * [Support](#support) * [Authors](#authors) Quick Start =========== ## Install ABySS on Linux Install [Linuxbrew](http://linuxbrew.sh/), and run the command brew install abyss ## Install ABySS on macOS Install [Homebrew](https://brew.sh/), and run the command brew install abyss ## Install ABySS on Windows Install [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/) and [Linuxbrew](http://linuxbrew.sh/), and run the command brew install abyss ## Install ABySS on Debian or Ubuntu Run the command sudo apt-get install abyss ## Assemble a small synthetic data set wget http://www.bcgsc.ca/platform/bioinfo/software/abyss/releases/1.3.4/test-data.tar.gz tar xzvf test-data.tar.gz abyss-pe k=25 name=test \ in='test-data/reads1.fastq test-data/reads2.fastq' ## Calculate assembly contiguity statistics abyss-fac test-unitigs.fa Dependencies ============ Dependencies may be installed using the package manager [Homebrew](https://homebrew.sh) on macOS and [Linxubrew](http://linuxbrew.sh) on Linux and Windows, using Windows Subsystem for Linux. ABySS requires a C++ compiler that supports [OpenMP](http://www.openmp.org) such as [GCC](http://gcc.gnu.org). ABySS requires the following libraries: * [Boost](http://www.boost.org/) * [Open MPI](http://www.open-mpi.org) * [sparsehash](https://code.google.com/p/sparsehash/) brew install boost open-mpi google-sparsehash ABySS will receive an error when compiling with Boost 1.51.0 or 1.52.0 since they contain a bug. Later versions of Boost compile without error. ## Dependencies for linked reads - [ARCS](https://github.com/bcgsc/arcs) to scaffold - [Tigmint](https://github.com/bcgsc/tigmint) to correct assembly errors brew install brewsci/bio/arcs brewsci/bio/links-scaffolder ## Optional dependencies - [pigz](https://zlib.net/pigz/) for parallel gzip - [samtools](https://samtools.github.io) for reading BAM files - [zsh](https://sourceforge.net/projects/zsh/) for reporting time and memory usage brew install pigz samtools zsh Compiling ABySS from GitHub =========================== When installing ABySS from GitHub source the following tools are required: * [Autoconf](http://www.gnu.org/software/autoconf) * [Automake](http://www.gnu.org/software/automake) To generate the configure script and make files: ./autogen.sh See "Compiling ABySS from source" for further steps. Compiling ABySS from source =========================== To compile and install ABySS in `/usr/local`: ./configure make sudo make install To install ABySS in a specified directory: ./configure --prefix=/opt/abyss make sudo make install ABySS uses OpenMP for parallelization, which requires a modern compiler such as GCC 4.2 or greater. If you have an older compiler, it is best to upgrade your compiler if possible. If you have multiple versions of GCC installed, you can specify a different compiler: ./configure CC=gcc-4.6 CXX=g++-4.6 ABySS requires the Boost C++ libraries. Many systems come with Boost installed. If yours does not, you can download [Boost](http://www.boost.org/users/download). It is not necessary to compile Boost before installing it. The Boost header file directory should be found at `/usr/include/boost`, in the ABySS source directory, or its location specified to `configure`: ./configure --with-boost=/usr/local/include If you wish to build the parallel assembler with MPI support, MPI should be found in `/usr/include` and `/usr/lib` or its location specified to `configure`: ./configure --with-mpi=/usr/lib/openmpi While OpenMPI is assumed by default you can switch to LAM/MPI or MPICH using: ./configure --enable-mpich use MPICH (default is to use Open MPI) ./configure --enable-lammpi use LAM/MPI (default is to use Open MPI) ABySS should be built using the sparsehash library to reduce memory usage, although it will build without. sparsehash should be found in `/usr/include` or its location specified to `configure`: ./configure CPPFLAGS=-I/usr/local/include If the optional dependency SQLite is installed in non-default directories, its location can be specified to `configure`: ./configure --with-sqlite=/opt/sqlite3 The default maximum k-mer size is 128 and may be decreased to reduce memory usage or increased at compile time. This value must be a multiple of 32 (i.e. 32, 64, 96, 128, etc): ./configure --enable-maxk=160 If you encounter compiler warnings, you may ignore them like so: make AM_CXXFLAGS=-Wall To run ABySS, its executables should be found in your `PATH`. If you installed ABySS in `/opt/abyss`, add `/opt/abyss/bin` to your `PATH`: PATH=/opt/abyss/bin:$PATH Before starting an assembly =========================== ABySS stores temporary files in `TMPDIR`, which is `/tmp` by default on most systems. If your default temporary disk volume is too small, set `TMPDIR` to a larger volume, such as `/var/tmp` or your home directory. export TMPDIR=/var/tmp Assembling a paired-end library =============================== To assemble paired reads in two files named `reads1.fa` and `reads2.fa` into contigs in a file named `ecoli-contigs.fa`, run the command: abyss-pe name=ecoli k=96 in='reads1.fa reads2.fa' The parameter `in` specifies the input files to read, which may be in FASTA, FASTQ, qseq, export, SRA, SAM or BAM format and compressed with gz, bz2 or xz and may be tarred. The assembled contigs will be stored in `${name}-contigs.fa`. A pair of reads must be named with the suffixes `/1` and `/2` to identify the first and second read, or the reads may be named identically. The paired reads may be in separate files or interleaved in a single file. Reads without mates should be placed in a file specified by the parameter `se` (single-end). Reads without mates in the paired-end files will slow down the paired-end assembler considerably during the `abyss-fixmate` stage. Assembling multiple libraries ============================= The distribution of fragment sizes of each library is calculated empirically by aligning paired reads to the contigs produced by the single-end assembler, and the distribution is stored in a file with the extension `.hist`, such as `ecoli-3.hist`. The N50 of the single-end assembly must be well over the fragment-size to obtain an accurate empirical distribution. Here's an example scenario of assembling a data set with two different fragment libraries and single-end reads. Note that the names of the libraries (`pea` and `peb`) are arbitrary. * Library `pea` has reads in two files, `pea_1.fa` and `pea_2.fa`. * Library `peb` has reads in two files, `peb_1.fa` and `peb_2.fa`. * Single-end reads are stored in two files, `se1.fa` and `se2.fa`. The command line to assemble this example data set is: abyss-pe k=96 name=ecoli lib='pea peb' \ pea='pea_1.fa pea_2.fa' peb='peb_1.fa peb_2.fa' \ se='se1.fa se2.fa' The empirical distribution of fragment sizes will be stored in two files named `pea-3.hist` and `peb-3.hist`. These files may be plotted to check that the empirical distribution agrees with the expected distribution. The assembled contigs will be stored in `${name}-contigs.fa`. Scaffolding =========== Long-distance mate-pair libraries may be used to scaffold an assembly. Specify the names of the mate-pair libraries using the parameter `mp`. The scaffolds will be stored in the file `${name}-scaffolds.fa`. Here's an example of assembling a data set with two paired-end libraries and two mate-pair libraries. Note that the names of the libraries (`pea`, `peb`, `mpa`, `mpb`) are arbitrary. abyss-pe k=96 name=ecoli lib='pea peb' mp='mpc mpd' \ pea='pea_1.fa pea_2.fa' peb='peb_1.fa peb_2.fa' \ mpc='mpc_1.fa mpc_2.fa' mpd='mpd_1.fa mpd_2.fa' The mate-pair libraries are used only for scaffolding and do not contribute towards the consensus sequence. Scaffolding with linked reads ================================================================================ ABySS can scaffold using linked reads from 10x Genomics Chromium. The barcodes must first be extracted from the read sequences and added to the `BX:Z` tag of the FASTQ header, typically using the `longranger basic` command of [Long Ranger](https://support.10xgenomics.com/genome-exome/software/overview/welcome) or [EMA preproc](https://github.com/arshajii/ema#readme). The linked reads are used to correct assembly errors, which requires that [Tigmint](https://github.com/bcgsc/tigmint). The linked reads are also used for scaffolding, which requires [ARCS](https://github.com/bcgsc/arcs). See [Dependencies](#dependencies) for installation instructions. ABySS can combine paired-end, mate-pair, and linked-read libraries. The `pe` and `lr` libraries will be used to build the de Bruijn graph. The `mp` libraries will be used for paired-end/mate-pair scaffolding. The `lr` libraries will be used for misassembly correction using Tigmint and scaffolding using ARCS. abyss-pe k=96 name=hsapiens \ pe='pea' pea='lra.fastq.gz' \ mp='mpa' mpa='lra.fastq.gz' \ lr='lra' lra='lra.fastq.gz' ABySS performs better with a mixture of paired-end, mate-pair, and linked reads, but it is possible to assemble only linked reads using ABySS, though this mode of operation is experimental. abyss-pe k=96 name=hsapiens lr='lra' lra='lra.fastq.gz' Rescaffolding with long sequences ================================= Long sequences such as RNA-Seq contigs can be used to rescaffold an assembly. Sequences are aligned using BWA-MEM to the assembled scaffolds. Additional scaffolds are then formed between scaffolds that can be linked unambiguously when considering all BWA-MEM alignments. Similar to scaffolding, the names of the datasets can be specified with the `long` parameter. These scaffolds will be stored in the file `${name}-long-scaffs.fa`. The following is an example of an assembly with PET, MPET and an RNA-Seq assembly. Note that the names of the libraries are arbitrary. abyss-pe k=96 name=ecoli lib='pe1 pe2' mp='mp1 mp2' long='longa' \ pe1='pe1_1.fa pe1_2.fa' pe2='pe2_1.fa pe2_2.fa' \ mp1='mp1_1.fa mp1_2.fa' mp2='mp2_1.fa mp2_2.fa' \ longa='longa.fa' Assembling using a Bloom filter de Bruijn graph ========================================= Assemblies may be performed using a _Bloom filter de Bruijn graph_, which typically reduces memory requirements by an order of magnitude. To assemble in Bloom filter mode, the user must specify 3 additional parameters: `B` (Bloom filter size in bytes), `H` (number of Bloom filter hash functions), and `kc` (minimum k-mer count threshold). `B` is the overall memory budget for the Bloom filter assembler, and may be specified with unit suffixes 'k' (kilobytes), 'M' (megabytes), 'G' (gigabytes). If no units are specified bytes are assumed. For example, the following will run a E. coli assembly with an overall memory budget of 100 megabytes, 3 hash functions, a minimum k-mer count threshold of 3, with verbose logging enabled: abyss-pe name=ecoli k=96 in='reads1.fa reads2.fa' B=100M H=3 kc=3 v=-v At the current time, the user must calculate suitable values for `B` and `H` on their own, and finding the best value for `kc` may require experimentation (optimal values are typically in the range of 2-4). Internally, the Bloom filter assembler allocates the entire memory budget (`B * 8/9`) to a Counting Bloom filter, and an additional (`B/9`) memory to another Bloom filter that is used to track k-mers that have previously been included in contigs. Users are recommended to target a Bloom filter false positive rate (FPR) that is less than 5%, as reported by the assembly log when using the `v=-v` option (verbose level 1). 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 96: abyss-pe name=ecoli K=16 k=96 in='reads1.fa reads2.fa' In this example, the size of the intervening gap between k-mer pairs is 64 bp (96 - 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 ============================================ Strand-specific RNA-Seq libraries can be assembled such that the resulting unitigs, contigs and scaffolds are oriented correctly with respect to the original transcripts that were sequenced. In order to run ABySS in strand-specific mode, the `SS` parameter must be used as in the following example: abyss-pe name=SS-RNA k=96 in='reads1.fa reads2.fa' SS=--SS The expected orientation for the read sequences with respect to the original RNA is RF. i.e. the first read in a read pair is always in reverse orientation. Optimizing the parameter k ========================== To find the optimal value of `k`, run multiple assemblies and inspect the assembly contiguity statistics. The following shell snippet will assemble for every eighth value of `k` from 50 to 90. for k in `seq 50 8 90`; do mkdir k$k abyss-pe -C k$k name=ecoli k=$k in=../reads.fa done abyss-fac k*/ecoli-contigs.fa The default maximum value for `k` is 96. This limit may be changed at compile time using the `--enable-maxk` option of configure. It may be decreased to 32 to decrease memory usage or increased to larger values. Parallel processing =================== The `np` option of `abyss-pe` specifies the number of processes to use for the parallel MPI job. Without any MPI configuration, this will allow you to use multiple cores on a single machine. To use multiple machines for assembly, you must create a `hostfile` for `mpirun`, which is described in the `mpirun` man page. *Do not* run `mpirun -np 8 abyss-pe`. To run ABySS with 8 threads, use `abyss-pe np=8`. The `abyss-pe` driver script will start the MPI process, like so: `mpirun -np 8 ABYSS-P`. The paired-end assembly stage is multithreaded, but must run on a single machine. The number of threads to use may be specified with the parameter `j`. The default value for `j` is the value of `np`. Running ABySS on a cluster ========================== ABySS integrates well with cluster job schedulers, such as: * SGE (Sun Grid Engine) * Portable Batch System (PBS) * Load Sharing Facility (LSF) * IBM LoadLeveler For example, to submit an array of jobs to assemble every eighth value of `k` between 50 and 90 using 64 processes for each job: qsub -N ecoli -pe openmpi 64 -t 50-90:8 \ <<<'mkdir k$SGE_TASK_ID && 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 =================== Parameters of the driver script, `abyss-pe` * `a`: maximum number of branches of a bubble [`2`] * `b`: maximum length of a bubble (bp) [`""`] * `B`: Bloom filter size (e.g. "100M") * `c`: minimum mean k-mer coverage of a unitig [`sqrt(median)`] * `d`: allowable error of a distance estimate (bp) [`6`] * `e`: minimum erosion k-mer coverage [`round(sqrt(median))`] * `E`: minimum erosion k-mer coverage per strand [1 if `sqrt(median) > 2` else 0] * `G`: genome size, used to calculate NG50 * `H`: number of Bloom filter hash functions [`1`] * `j`: number of threads [`2`] * `k`: size of k-mer (when `K` is not set) or the span of a k-mer pair (when `K` is set) * `kc`: minimum k-mer count threshold for Bloom filter assembly [`2`] * `K`: the length of a single k-mer in a k-mer pair (bp) * `l`: minimum alignment length of a read (bp) [`40`] * `m`: minimum overlap of two unitigs (bp) [`k-1`] * `n`: minimum number of pairs required for building contigs [`10`] * `N`: minimum number of pairs required for building scaffolds [`n`] * `np`: number of MPI processes [`1`] * `p`: minimum sequence identity of a bubble [`0.9`] * `q`: minimum base quality [`3`] * `s`: minimum unitig size required for building contigs (bp) [`1000`] * `S`: minimum contig size required for building scaffolds (bp) [`1000-10000`] * `t`: maximum length of blunt contigs to trim [`k`] * `v`: use `v=-v` for verbose logging, `v=-vv` for extra verbose * `x`: spaced seed (Bloom filter assembly only) * `lr_s`: minimum contig size required for building scaffolds with linked reads (bp) [`S`] * `lr_n`: minimum number of barcodes required for building scaffolds with linked reads [`10`] Please see the [abyss-pe](http://manpages.ubuntu.com/abyss-pe.1.html) manual page for more information on assembly parameters. Environment variables ===================== `abyss-pe` configuration variables may be set on the command line or from the environment, for example with `export k=96`. It can happen that `abyss-pe` picks up such variables from your environment that you had not intended, and that can cause trouble. To troubleshoot that situation, use the `abyss-pe env` command to print the values of all the `abyss-pe` configuration variables: abyss-pe env [options] 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` Change to the directory `dir` and store the results there. * `-n`, `--dry-run` Print the commands that would be executed, but do not execute them. `abyss-pe` uses the following programs, which must be found in your `PATH`: * `ABYSS`: de Bruijn graph assembler * `ABYSS-P`: parallel (MPI) de Bruijn graph assembler * `AdjList`: find overlapping sequences * `DistanceEst`: estimate the distance between sequences * `MergeContigs`: merge sequences * `MergePaths`: merge overlapping paths * `Overlap`: find overlapping sequences using paired-end reads * `PathConsensus`: find a consensus sequence of ambiguous paths * `PathOverlap`: find overlapping paths * `PopBubbles`: remove bubbles from the sequence overlap graph * `SimpleGraph`: find paths through the overlap graph * `abyss-fac`: calculate assembly contiguity statistics * `abyss-filtergraph`: remove shim contigs from the overlap graph * `abyss-fixmate`: fill the paired-end fields of SAM alignments * `abyss-map`: map reads to a reference sequence * `abyss-scaffold`: scaffold contigs using distance estimates * `abyss-todot`: convert graph formats and merge graphs This [flowchart](https://github.com/bcgsc/abyss/blob/master/doc/flowchart.pdf) shows the ABySS assembly pipeline its intermediate files. Export to SQLite Database ========================= ABySS has a built-in support for SQLite database to export log values into a SQLite file and/or `.csv` files at runtime. ## 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 'pea' into your SQLite database repository named '/abyss/test.sqlite': abyss-pe db=/abyss/test.sqlite species=Ecoli strain=O121 library=pea [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 Citation ================================================================================ ## [ABySS 2.0](http://doi.org/10.1101/gr.214346.116) Shaun D Jackman, Benjamin P Vandervalk, Hamid Mohamadi, Justin Chu, Sarah Yeo, S Austin Hammond, Golnaz Jahesh, Hamza Khan, Lauren Coombe, René L Warren, and Inanc Birol (2017). **ABySS 2.0: Resource-efficient assembly of large genomes using a Bloom filter**. *Genome research*, 27(5), 768-777. [doi:10.1101/gr.214346.116](http://doi.org/10.1101/gr.214346.116) ## [ABySS](http://genome.cshlp.org/content/19/6/1117) Simpson, Jared T., Kim Wong, Shaun D. Jackman, Jacqueline E. Schein, Steven JM Jones, and Inanc Birol (2009). **ABySS: a parallel assembler for short read sequence data**. *Genome research*, 19(6), 1117-1123. [doi:10.1101/gr.089532.108](http://dx.doi.org/10.1101/gr.089532.108) Related Publications ================================================================================ ## [Trans-ABySS](http://www.nature.com/nmeth/journal/v7/n11/abs/nmeth.1517.html) Robertson, Gordon, Jacqueline Schein, Readman Chiu, Richard Corbett, Matthew Field, Shaun D. Jackman, Karen Mungall, et al (2010). **De novo assembly and analysis of RNA-seq data**. *Nature methods*, 7(11), 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) Nielsen, Cydney B., Shaun D. Jackman, Inanc Birol, and Steven JM Jones (2009). **ABySS-Explorer: visualizing genome sequence assemblies**. *IEEE Transactions on Visualization and Computer Graphics*, 15(6), 881-888. [doi:10.1109/TVCG.2009.116](http://dx.doi.org/10.1109/TVCG.2009.116) Support ======= [Ask a question](https://www.biostars.org/p/new/post/?tag_val=abyss,assembly) on [Biostars](https://www.biostars.org/t/abyss/). [Create a new issue](https://github.com/bcgsc/abyss/issues) on GitHub. Subscribe to the [ABySS mailing list](http://groups.google.com/group/abyss-users), . For questions related to transcriptome assembly, contact the [Trans-ABySS mailing list](http://groups.google.com/group/trans-abyss), . Authors ======= + **[Shaun Jackman](http://sjackman.ca)** - [GitHub/sjackman](https://github.com/sjackman) - [@sjackman](https://twitter.com/sjackman) + **Tony Raymond** - [GitHub/traymond](https://github.com/traymond) + **Ben Vandervalk** - [GitHub/benvvalk ](https://github.com/benvvalk) + **Jared Simpson** - [GitHub/jts](https://github.com/jts) Supervised by [**Dr. Inanc Birol**](http://www.bcgsc.ca/faculty/inanc-birol). Copyright 2016 Canada's Michael Smith Genome Sciences Centre abyss-2.2.4/Scaffold/000077500000000000000000000000001361462241400143645ustar00rootroot00000000000000abyss-2.2.4/Scaffold/Makefile.am000066400000000000000000000017761361462241400164330ustar00rootroot00000000000000bin_PROGRAMS = abyss-scaffold abyss-junction abyss-longseqdist noinst_PROGRAMS = abyss-drawgraph abyss_scaffold_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common 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 abyss_longseqdist_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common abyss_longseqdist_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_longseqdist_LDADD = \ $(top_builddir)/Common/libcommon.a abyss_longseqdist_SOURCES = longseqdist.cpp abyss_junction_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common abyss_junction_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) abyss_junction_LDADD = \ $(top_builddir)/Common/libcommon.a abyss_junction_SOURCES = junction.cc abyss_drawgraph_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/Common abyss_drawgraph_LDADD = $(top_builddir)/Common/libcommon.a abyss_drawgraph_SOURCES = drawgraph.cc abyss-2.2.4/Scaffold/drawgraph.cc000066400000000000000000000216761361462241400166660ustar00rootroot00000000000000/** * Place each contig on a one-dimesional coordinate system using * distance estimates. * Written by Shaun Jackman. */ /** Disable Boost uBLAS runtime sanity checks. */ #define BOOST_UBLAS_NDEBUG 1 #include "ContigProperties.h" #include "Estimate.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "cholesky.hpp" #include #include #include #include #include #include #include #include #include using namespace std; using boost::tie; namespace ublas = boost::numeric::ublas; #define PROGRAM "abyss-drawgraph" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... FASTA|OVERLAP DIST...\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" "\n" " FASTA contigs in FASTA format\n" " OVERLAP the contig overlap graph\n" " DIST estimates of the distance between contigs\n" "\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" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { unsigned k; // used by ContigProperties /** The L2 regularizer. */ double l2 = 1e-323; /** The x scale. */ double xscale = 100e3; // nt/inch /** Verbose output. */ int verbose; // used by PopBubbles /** Output format */ int format = DOT; // used by DistanceEst } static const char shortopts[] = "x:v"; 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 }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** A distance estimate graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; /** A matrix. */ typedef ublas::matrix Matrix; /** A vector. */ typedef ublas::vector Vector; /** Read a graph from the specified file. */ static void readGraph(const string& path, Graph& g) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; ifstream fin(path.c_str()); istream& in = path == "-" ? cin : fin; assert_good(in, path); read_graph(in, g, BetterDistanceEst()); assert(in.eof()); if (opt::verbose > 0) printGraphStats(cerr, g); g_contigNames.lock(); } /** Solve Ax = b for x using Cholesky decomposition. * The matrix A is symmetric and positive-definite. * @param[in,out] a input matrix A, which is clobbered * @param[in,out] b input vector b and output vector x */ static void solve(Matrix& a, Vector& b) { int ret = cholesky_decompose(a); if (ret > 0) { 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()); } /** Run abyss-drawgraph. */ 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 OPT_L2: arg >> opt::l2; break; case 'x': arg >> opt::xscale; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 0) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } typedef graph_traits::edge_descriptor E; typedef graph_traits::edge_iterator Eit; typedef graph_traits::vertex_descriptor V; typedef graph_traits::vertex_iterator Vit; Graph g; if (optind < argc) { for (; optind < argc; optind++) readGraph(argv[optind], g); } else readGraph("-", g); // Add any missing complementary edges. addComplementaryEdges(g); size_t n = num_vertices(g); Matrix a(n, n); Vector b = ublas::zero_vector(n); // 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; for (tie(eit, elast) = edges(g); eit != elast; ++eit) { E e = *eit; V u = source(e, g); V v = target(e, g); size_t ui = get(vertex_index, g, u); size_t vi = get(vertex_index, g, v); int d = get(edge_weight, g, e); double err = max(0.1, (double)g[e].stdDev); double weight = 1 / err; a(ui, ui) += weight; a(ui, vi) -= weight; a(vi, ui) -= weight; a(vi, vi) += weight; b[ui] -= d * weight; b[vi] += d * weight; } // Solve the equation Ax = b for x. solve(a, b); // Determine the origin and width of the layout. double min_pos = std::numeric_limits::max(); double max_pos = -std::numeric_limits::max(); double min_rc = std::numeric_limits::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::max()); assert(max_pos != -std::numeric_limits::max()); assert(min_rc != std::numeric_limits::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::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); 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 > sorted; sorted.reserve(n); Vit uit, ulast; for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) { V u = *uit; size_t ui = get(vertex_index, g, u); double x1 = std::isnan(b[ui]) ? 0 : b[ui]; sorted.push_back(std::make_pair(x1, u)); } sort(sorted.begin(), sorted.end()); // Write the graph. cout << "digraph g {\n" "node [shape=\"box\" height=0.3 fixedsize=1]\n"; assert_good(cout, "stdout"); // Write the vertices. double pos0 = -numeric_limits::max(); size_t yi = 0; for (size_t i = 0; i < n; ++i) { V u = sorted[i].second; double pos = sorted[i].first; size_t l = g[u].length; if (pos - l < pos0) yi++; pos0 = pos; double dpi = 72; const double W = dpi / opt::xscale; // pt/nt const double H = 32; // pt double w = l * W; double x = pos * W - w / 2; double y = yi * H; cout << '"' << get(vertex_name, g, u) << "\"" " [pos=\"" << x << ",-" << y << "\"" " width=" << w / dpi << "]\n"; } // Write the edges. for (tie(eit, elast) = edges(g); eit != elast; ++eit) cout << get(edge_name, g, *eit) << '\n'; cout << "}\n"; assert_good(cout, "stdout"); return 0; } abyss-2.2.4/Scaffold/junction.cc000066400000000000000000000133651361462241400165340ustar00rootroot00000000000000#include "config.h" #include "Common/ContigPath.h" #include "Common/IOUtil.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "Uncompress.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace boost::lambda; using boost::tie; #define PROGRAM "abyss-junction" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " [OPTION]... OVERLAP [SCAFFOLD]...\n" "Extend junction contigs that are supported by the scaffold graph.\n" "\n" " Arguments:\n" "\n" " OVERLAP the overlap graph\n" " SCAFFOLD a scaffold graph\n" "\n" " Options:\n" "\n" " -i, --ignore=FILE ignore junctions seen in 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 { unsigned k; // used by DotIO /** Do not check for evidence in the scaffold graph. */ bool noScaffoldGraph; /** Junction contigs to ignore. */ string ignorePath; /** Verbose output. */ int verbose; // used by PopBubbles /** Output format */ int format = DOT; // used by DistanceEst } static const char shortopts[] = "i:v"; enum { OPT_HELP = 1, OPT_VERSION, }; static const struct option longopts[] = { { "ignore", no_argument, NULL, 'i' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** Counts. */ static struct { unsigned junctions; unsigned supported; } g_count; /** An overlap graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; typedef Graph OverlapGraph; /** A scaffold graph. */ typedef Graph ScaffoldGraph; /** Extend junction contigs. */ void extendJunction( const OverlapGraph& overlapG, const ScaffoldGraph& scaffoldG, graph_traits::vertex_descriptor v) { if (get(vertex_sense, overlapG, v) || in_degree(v, overlapG) != 1 || out_degree(v, overlapG) != 1) return; typedef graph_traits::vertex_descriptor V; V u = source(*in_edges(v, overlapG).first, overlapG); V w = *adjacent_vertices(v, overlapG).first; if (opt::noScaffoldGraph || edge(u, w, scaffoldG).second) { // This junction contig is supported by the scaffold graph. ContigPath path; path.reserve(3); extend(overlapG, get(vertex_complement, overlapG, v), back_inserter(path)); reverseComplement(path.begin(), path.end()); path.push_back(v); extend(overlapG, v, back_inserter(path)); assert(path.size() >= 3); cout << createContigName() << '\t' << path << '\n'; g_count.supported++; } g_count.junctions++; } /** Allow parallel edges. */ struct AllowParallelEdges { template EP operator()(const EP& a, const EP&) const { return a; } }; /** Read a graph from the specified file. */ static void readGraph(const string& path, Graph& g) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; ifstream fin(path.c_str()); istream& in = path == "-" ? cin : fin; assert_good(in, path); read_graph(in, g, AllowParallelEdges()); assert(in.eof()); if (opt::verbose > 1) printGraphStats(cerr, g); g_contigNames.lock(); } 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 'i': arg >> opt::ignorePath; 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()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } OverlapGraph overlapG; readGraph(argv[optind++], overlapG); ScaffoldGraph scaffoldG(overlapG.num_vertices() / 2); if (optind < argc) { for_each(argv + optind, argv + argc, boost::lambda::bind(readGraph, _1, boost::ref(scaffoldG))); // Add any missing complementary edges. size_t numAdded = addComplementaryEdges(scaffoldG); if (opt::verbose > 0) cerr << "Added " << numAdded << " complementary edges.\n"; if (opt::verbose > 1) printGraphStats(cerr, scaffoldG); } else opt::noScaffoldGraph = true; // Read the set of contigs to ignore. vector seen(num_vertices(overlapG) / 2); if (!opt::ignorePath.empty()) { ifstream in(opt::ignorePath.c_str()); assert_good(in, opt::ignorePath); markSeenInPath(in, seen); } // Extend the junction contigs. graph_traits::vertex_iterator uit, ulast; for (tie(uit, ulast) = vertices(overlapG); uit != ulast; ++uit) if (!seen[get(vertex_contig_index, overlapG, *uit)]) extendJunction(overlapG, scaffoldG, *uit); assert_good(cout, "stdout"); if (opt::verbose > 0) { cerr << "Junctions: " << g_count.junctions << '\n'; if (!opt::noScaffoldGraph) cerr << "Supported: " << g_count.supported << '\n'; } return 0; } abyss-2.2.4/Scaffold/longseqdist.cpp000066400000000000000000000123041361462241400174240ustar00rootroot00000000000000#include "config.h" #include "IOUtil.h" #include "ContigNode.h" #include "Uncompress.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphAlgorithms.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "ContigProperties.h" #include "SAM.h" #include #include #include #include #include using namespace std; using namespace boost; #define PROGRAM "abyss-longseqdist" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Anthony Raymond.\n" "\n" "Copyright 2014 Canada's Michael Smith Genome Science Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... SAM >DIST\n" "Generate distance estimates between all contigs a single\n" "read maps to.\n" "\n" " Arguments:\n" "\n" " SAM BWA-MEM alignments of long sequences to the assembly\n" " DIST estimates of the distance between contigs\n" "\n" " Options:\n" "\n" " -k, --kmer=N length of a k-mer\n" " --min-gap=N minimum scaffold gap length to output [200]\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 { unsigned k; // used by ContigProperties /** Minimum scaffold gap length to output. */ static int minGap = 200; /** Verbose output. */ int verbose; // used by PopBubbles /** Output format */ int format = DOT; // used by DistanceEst } static const char shortopts[] = "k:n:o:v"; enum { OPT_HELP = 1, OPT_VERSION, OPT_MIN_GAP }; static const struct option longopts[] = { { "kmer", required_argument, NULL, 'k' }, { "min-gap", required_argument, NULL, OPT_MIN_GAP }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; /** A distance estimate graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; static void processQuery(vector& recs, Graph& g) { typedef graph_traits::vertex_descriptor V; typedef graph_traits::edge_descriptor E; typedef edge_property::type EP; if (recs.size() <= 1) return; sort(recs.begin(), recs.end()); for (vector::const_iterator itx = recs.begin(); itx != recs.end(); itx++) { for (vector::const_iterator ity = itx + 1; ity != recs.end(); ity++) { // if aligned to the same contig, don't draw self edge if (itx->contig == ity->contig) continue; // if y is subsumed in x don't draw edge unsigned xqend = itx->read_start_pos + itx->align_length; unsigned yqend = ity->read_start_pos + ity->align_length; if (xqend >= yqend) continue; V u = find_vertex(itx->contig, itx->isRC, g); V v = find_vertex(ity->contig, ity->isRC, g); E e; EP ep(opt::minGap, 1, opt::minGap); bool found; tie(e, found) = edge(u, v, g); if (found) { EP& ep = g[e]; ep.numPairs++; } else add_edge(u, v, ep, g); } } } static void readAlignments(istream& in, Graph& g) { SAMRecord rec, prev; vector recs; int i = 0; while (in >> prev && (prev.isUnmapped() || prev.mapq == 0)); recs.push_back(prev); while (in >> rec) { if (rec.isUnmapped() || rec.mapq == 0) continue; if (opt::verbose > 0 && ++i % 100000 == 0) cerr << "Processed " << i << " good alignments...\n"; if (rec.qname != prev.qname) { processQuery(recs, g); recs.clear(); prev = rec; recs.push_back(prev); } else recs.push_back(rec); } if (opt::verbose > 0) cerr << "Processed " << i << " good alignments.\n"; processQuery(recs, g); } 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 'k': arg >> opt::k; break; case 'v': opt::verbose++; break; case OPT_MIN_GAP: arg >> opt::minGap; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (argc - optind != 1) { cerr << PROGRAM ": incorrect number of arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } if (opt::verbose > 0) cerr << "Reading graph file '" << argv[optind] << "`...\n"; Graph g; ifstream in(argv[optind]); in >> g; g_contigNames.lock(); if (opt::verbose > 0) cerr << "Finished reading graph.\n"; if (in.eof()) { cerr << PROGRAM ": there are no alignments\n"; exit(EXIT_FAILURE); } if (opt::verbose > 0) cerr << "Processing alignments from '" << argv[optind] << "`...\n"; readAlignments(in, g); write_dot(cout, g); return 0; } abyss-2.2.4/Scaffold/scaffold.cc000066400000000000000000001014621361462241400164600ustar00rootroot00000000000000#include "Common/UnorderedMap.h" #include "ContigNode.h" #include "ContigPath.h" #include "ContigProperties.h" #include "DataBase/DB.h" #include "DataBase/Options.h" #include "Estimate.h" #include "Graph/Assemble.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/DirectedGraph.h" #include "Graph/GraphAlgorithms.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include "Graph/PopBubbles.h" #include "IOUtil.h" #include "Iterator.h" #include "Uncompress.h" #include "config.h" #include #include #include #include #include #include #include #include #include using namespace std; using namespace std::rel_ops; using boost::edge_bundle_type; using boost::tie; #define PROGRAM "abyss-scaffold" DB db; static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2018 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... FASTA|OVERLAP DIST...\n" "Scaffold contigs using the distance estimate graph.\n" "\n" " Arguments:\n" "\n" " FASTA contigs in FASTA format\n" " OVERLAP the contig overlap graph\n" " DIST estimates of the distance between contigs\n" "\n" " Options:\n" "\n" " -n, --npairs=N minimum number of pairs [0]\n" " or -n A-B:S Find the value of n in [A,B] with step size S\n" " that maximizes the scaffold N50.\n" " Default value for the step size is 1, if unspecified.\n" " -s, --seed-length=N minimum contig length [1000]\n" " or -s A-B Find the value of s in [A,B]\n" " that maximizes the scaffold N50.\n" " --grid optimize using a grid search [default]\n" " --line optimize using a line search\n" " -k, --kmer=N length of a k-mer\n" " -G, --genome-size=N expected genome size. Used to calculate NG50\n" " and associated stats [disabled]\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" " --no-SS no assumption about contig orientation [default]\n" " -o, --out=FILE write the paths to FILE\n" " -g, --graph=FILE write the graph to FILE\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; // used by ContigProperties /** Optimization search strategy. */ static int searchStrategy; /** Minimum number of pairs. */ static unsigned minEdgeWeight; static unsigned minEdgeWeightEnd; static unsigned minEdgeWeightStep; /** Minimum contig length. */ static unsigned minContigLength = 1000; static unsigned minContigLengthEnd = 1000; /** Genome size. Used to calculate NG50. */ static long long unsigned genomeSize; /** 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; /** Write the graph to this file. */ static string graphPath; /** Run a strand-specific RNA-Seq assembly. */ static int ss; /** Verbose output. */ int verbose; // used by PopBubbles /** Output format */ int format = DOT; // used by DistanceEst /** Remove complex transitive edges */ static int comp_trans; } static const char shortopts[] = "G:g:k:n:o:s:v"; enum { OPT_HELP = 1, OPT_VERSION, OPT_MIN_GAP, OPT_MAX_GAP, OPT_COMP, OPT_DB, OPT_LIBRARY, OPT_STRAIN, OPT_SPECIES }; /** Optimization search strategy. */ enum { GRID_SEARCH, LINE_SEARCH }; static const struct option longopts[] = { { "graph", no_argument, NULL, 'g' }, { "kmer", required_argument, NULL, 'k' }, { "genome-size", required_argument, NULL, 'G' }, { "min-gap", required_argument, NULL, OPT_MIN_GAP }, { "max-gap", required_argument, NULL, OPT_MAX_GAP }, { "npairs", required_argument, NULL, 'n' }, { "grid", no_argument, &opt::searchStrategy, GRID_SEARCH }, { "line", no_argument, &opt::searchStrategy, LINE_SEARCH }, { "out", required_argument, NULL, 'o' }, { "seed-length", required_argument, NULL, 's' }, { "complex", no_argument, &opt::comp_trans, 1 }, { "no-complex", no_argument, &opt::comp_trans, 0 }, { "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 } }; /** A distance estimate graph. */ typedef DirectedGraph DG; typedef ContigGraph Graph; /** Return whether this edge is invalid. * An edge is invalid when the overlap is larger than the length of * either of its incident sequences. */ struct InvalidEdge { InvalidEdge(Graph& g) : m_g(g) {} bool operator()(graph_traits::edge_descriptor e) const { int d = m_g[e].distance; int ulength = m_g[source(e, m_g)].length; int vlength = m_g[target(e, m_g)].length; return d + ulength <= 0 || d + vlength <= 0; } const Graph& m_g; }; /** Return whether the specified edges has sufficient support. */ struct PoorSupport { PoorSupport(Graph& g, unsigned minEdgeWeight) : m_g(g) , m_minEdgeWeight(minEdgeWeight) {} bool operator()(graph_traits::edge_descriptor e) const { return m_g[e].numPairs < m_minEdgeWeight; } const Graph& m_g; unsigned m_minEdgeWeight; }; /** Remove short vertices and unsupported edges from the graph. */ static void filterGraph(Graph& g, unsigned minEdgeWeight, unsigned minContigLength) { typedef graph_traits GTraits; typedef GTraits::vertex_descriptor V; typedef GTraits::vertex_iterator Vit; // Remove short contigs. unsigned numRemovedV = 0; std::pair urange = vertices(g); for (Vit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (g[u].length < minContigLength) clear_vertex(u, g); if (out_degree(u, g) == 0 && in_degree(u, g) == 0) { remove_vertex(u, g); numRemovedV++; } } if (opt::verbose > 0) cerr << "Removed " << numRemovedV << " vertices.\n"; // Remove poorly-supported edges. unsigned numBefore = num_edges(g); remove_edge_if(PoorSupport(g, minEdgeWeight), static_cast(g)); 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. */ static bool isCycle(Graph& g, graph_traits::edge_descriptor e) { return edge(target(e, g), source(e, g), g).second; } /** Remove simple cycles of length two from the graph. */ static void removeCycles(Graph& g) { typedef graph_traits::edge_descriptor E; typedef graph_traits::edge_iterator Eit; // Identify the cycles. vector cycles; Eit eit, elast; for (tie(eit, elast) = edges(g); eit != elast; ++eit) { E e = *eit; if (isCycle(g, e)) cycles.push_back(e); } /** Remove the cycles. */ remove_edges(g, cycles.begin(), cycles.end()); if (opt::verbose > 0) { 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. * For a pair of edges (u,v1) and (u,v2) in g, if exactly one of the * edges (v1,v2) or (v2,v1) exists in g0, add that edge to g. */ static void resolveForks(Graph& g, const Graph& g0) { typedef graph_traits::adjacency_iterator Vit; typedef graph_traits::edge_descriptor E; typedef graph_traits::vertex_iterator Uit; typedef graph_traits::vertex_descriptor V; unsigned numEdges = 0; pair urange = vertices(g); for (Uit uit = urange.first; uit != urange.second; ++uit) { V u = *uit; if (out_degree(u, g) < 2) continue; pair vrange = adjacent_vertices(u, g); for (Vit vit1 = vrange.first; vit1 != vrange.second;) { V v1 = *vit1; ++vit1; assert(v1 != u); for (Vit vit2 = vit1; vit2 != vrange.second; ++vit2) { V v2 = *vit2; assert(v2 != u); assert(v1 != v2); if (edge(v1, v2, g).second || edge(v2, v1, g).second) continue; pair e12 = edge(v1, v2, g0); pair e21 = edge(v2, v1, g0); if (e12.second && e21.second) { if (opt::verbose > 1) cerr << "cycle: " << get(vertex_name, g, v1) << ' ' << get(vertex_name, g, v2) << '\n'; } else if (e12.second || e21.second) { E e = e12.second ? e12.first : e21.first; V v = source(e, g0), w = target(e, g0); add_edge(v, w, g0[e], g); numEdges++; if (opt::verbose > 1) cerr << get(vertex_name, g, u) << " -> " << get(vertex_name, g, v) << " -> " << get(vertex_name, g, w) << " [" << g0[e] << "]\n"; } } } } if (opt::verbose > 0) cerr << "Added " << numEdges << " edges to ambiguous vertices.\n"; if (!opt::db.empty()) addToDb(db, "E_added_ambig", numEdges); } /** Remove tips. * For an edge (u,v), remove the vertex v if deg+(u) > 1 * and deg-(v) = 1 and deg+(v) = 0. */ static void pruneTips(Graph& g) { /** Identify the tips. */ size_t n = 0; pruneTips(g, CountingOutputIterator(n)); if (opt::verbose > 0) { cerr << "Removed " << n << " tips.\n"; printGraphStats(cerr, g); } if (!opt::db.empty()) addToDb(db, "Tips_removed", n); } /** Remove repetitive vertices from this graph. * input: digraph g { t1->v1 t2->v2 t1->u t2->u u->v1 u->v2 } * operation: remove vertex u * output: digraph g { t1->v1 t2->v2 } */ static void removeRepeats(Graph& g) { typedef graph_traits::adjacency_iterator Ait; typedef graph_traits::edge_descriptor E; typedef graph_traits::vertex_descriptor V; vector repeats; vector transitive; find_transitive_edges(g, back_inserter(transitive)); for (vector::const_iterator it = transitive.begin(); it != transitive.end(); ++it) { // Iterate through the transitive edges, u->w1. V u = source(*it, g), w1 = target(*it, g); Ait vit, vlast; for (tie(vit, vlast) = adjacent_vertices(u, g); vit != vlast; ++vit) { V v = *vit; assert(u != v); // no self loops if (!edge(v, w1, g).second) continue; // u->w1 is a transitive edge spanning u->v->w1. Ait wit, wlast; for (tie(wit, wlast) = adjacent_vertices(v, g); wit != wlast; ++wit) { // For each edge v->w2, check that an edge // w1->w2 or w2->w1 exists. If not, v is a repeat. V w2 = *wit; assert(v != w2); // no self loops if (w1 != w2 && !edge(w1, w2, g).second && !edge(w2, w1, g).second) { repeats.push_back(v); break; } } } } sort(repeats.begin(), repeats.end()); repeats.erase(unique(repeats.begin(), repeats.end()), repeats.end()); if (opt::verbose > 1) { cerr << "Ambiguous:"; for (vector::const_iterator it = repeats.begin(); it != repeats.end(); ++it) cerr << ' ' << get(vertex_name, g, *it); cerr << '\n'; } // Remove the repetitive vertices. unsigned numRemoved = 0; for (vector::const_iterator it = repeats.begin(); it != repeats.end(); ++it) { V u = *it; V uc = get(vertex_complement, g, u); clear_out_edges(u, g); if (it != repeats.begin() && it[-1] == uc) { remove_vertex(u, g); numRemoved++; } } if (opt::verbose > 0) { cerr << "Cleared " << repeats.size() << " ambiguous vertices.\n" << "Removed " << 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. * input: digraph g { u1->v2 u1->v1 u2->v2 } * (u1,v2).n < (u1,v1).n and (u1,v2).n < (u2,v2).n * operation: remove edge u1->v2 * output: digraph g {u1->v1 u2->v2 } */ static void removeWeakEdges(Graph& g) { typedef graph_traits::edge_descriptor E; typedef graph_traits::edge_iterator Eit; typedef graph_traits::in_edge_iterator Iit; typedef graph_traits::out_edge_iterator Oit; typedef graph_traits::vertex_descriptor V; vector weak; Eit eit, elast; for (tie(eit, elast) = edges(g); eit != elast; ++eit) { E u1v2 = *eit; V u1 = source(u1v2, g), v2 = target(u1v2, g); if (out_degree(u1, g) != 2 || in_degree(v2, g) != 2) continue; Oit oit, olast; tie(oit, olast) = out_edges(u1, g); E u1v1; if (target(*oit, g) == v2) { ++oit; u1v1 = *oit; } else { u1v1 = *oit; ++oit; } assert(++oit == olast); V v1 = target(u1v1, g); assert(v1 != v2); if (in_degree(v1, g) != 1) continue; Iit iit, ilast; tie(iit, ilast) = in_edges(v2, g); E u2v2; if (source(*iit, g) == u1) { ++iit; assert(iit != ilast); u2v2 = *iit; } else { assert(iit != ilast); u2v2 = *iit; ++iit; } assert(++iit == ilast); V u2 = source(u2v2, g); assert(u1 != u2); if (out_degree(u2, g) != 1) continue; unsigned n = g[u1v2].numPairs; if (n < g[u1v1].numPairs && n < g[u2v2].numPairs) weak.push_back(u1v2); } if (opt::verbose > 1) { cerr << "Weak edges:\n"; for (vector::const_iterator it = weak.begin(); it != weak.end(); ++it) { E e = *it; cerr << '\t' << get(edge_name, g, e) << " [" << g[e] << "]\n"; } } /** Remove the weak edges. */ remove_edges(g, weak.begin(), weak.end()); if (opt::verbose > 0) { 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::edge_descriptor E; typedef graph_traits::edge_iterator Eit; vector 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 * overlap. */ static bool isOverlap(const DistanceEst& d) { if (d.stdDev == 0) { assert(d.distance < 0); return true; } else return false; } /** Add distance estimates to a path. * @param g0 the original graph * @param g1 the transformed graph */ static ContigPath addDistEst(const Graph& g0, const Graph& g1, const ContigPath& path) { typedef graph_traits::edge_descriptor E; typedef edge_bundle_type::type EP; ContigPath out; out.reserve(2 * path.size()); ContigNode u = path.front(); out.push_back(u); for (ContigPath::const_iterator it = path.begin() + 1; it != path.end(); ++it) { ContigNode v = *it; assert(!v.ambiguous()); pair e0 = edge(u, v, g0); pair e1 = edge(u, v, g1); if (!e0.second && !e1.second) std::cerr << "error: missing edge: " << get(vertex_name, g0, u) << " -> " << get(vertex_name, g0, v) << '\n'; assert(e0.second || e1.second); const EP& ep = e0.second ? g0[e0.first] : g1[e1.first]; if (!isOverlap(ep)) { int distance = max(ep.distance, (int)opt::minGap); int numN = distance + opt::k - 1; // by convention assert(numN >= 0); numN = max(numN, 1); out.push_back(ContigNode(numN, 'N')); } out.push_back(v); u = v; } return out; } /** Read a graph from the specified file. */ static void readGraph(const string& path, Graph& g) { if (opt::verbose > 0) cerr << "Reading `" << path << "'...\n"; ifstream fin(path.c_str()); istream& in = path == "-" ? cin : fin; assert_good(in, path); read_graph(in, g, BetterDistanceEst()); assert(in.eof()); if (opt::verbose > 0) printGraphStats(cerr, g); vector vals = passGraphStatsVal(g); vector keys = make_vector() << "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(); } /** Return the scaffold length of [first, last), not counting gaps. */ template unsigned addLength(const Graph& g, It first, It last) { typedef typename graph_traits::vertex_descriptor V; assert(first != last); unsigned length = g[*first].length; for (It it = first + 1; it != last; ++it) { V u = *(it - 1); V v = *it; length += min(0, get(edge_bundle, g, u, v).distance); length += g[v].length; } return length; } /** A container of contig paths. */ typedef vector ContigPaths; /** * Build the scaffold length histogram. * @param g The graph g is destroyed. */ static Histogram buildScaffoldLengthHistogram(Graph& g, const ContigPaths& paths) { Histogram h; // Clear the removed flag. typedef graph_traits::vertex_iterator Vit; Vit uit, ulast; for (tie(uit, ulast) = vertices(g); uit != ulast; ++uit) put(vertex_removed, g, *uit, false); // Remove the vertices that are used in paths // and add the lengths of the scaffolds. for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) { h.insert(addLength(g, it->begin(), it->end())); remove_vertex_if( g, it->begin(), it->end(), [](const ContigNode& c) { return !c.ambiguous(); }); } // Add the contigs that were not used in paths. for (tie(uit, ulast) = vertices(g); uit != ulast; ++++uit) { typedef graph_traits::vertex_descriptor V; V u = *uit; if (!get(vertex_removed, g, u)) h.insert(g[u].length); } return h; } /** Add contiguity stats to database */ static void addCntgStatsToDb(const Histogram h, const unsigned min) { vector vals = passContiguityStatsVal(h, min); vector keys = make_vector() << "n" << "n200" << "nN50" << "min" << "N75" << "N50" << "N25" << "Esize" << "max" << "sum" << "nNG50" << "NG50"; if (!opt::db.empty()) { for (unsigned i = 0; i < vals.size(); i++) addToDb(db, keys[i], vals[i]); } } /** Parameters of scaffolding. */ struct ScaffoldParam { ScaffoldParam(unsigned n, unsigned s) : n(n) , s(s) {} bool operator==(const ScaffoldParam& o) const { return n == o.n && s == o.s; } unsigned n; unsigned s; }; NAMESPACE_STD_HASH_BEGIN template<> struct hash { size_t operator()(const ScaffoldParam& param) const { return hash()(param.n) ^ hash()(param.s); } }; NAMESPACE_STD_HASH_END /** Result of scaffolding. */ struct ScaffoldResult : ScaffoldParam { ScaffoldResult() : ScaffoldParam(0, 0) , n50(0) {} ScaffoldResult(unsigned n, unsigned s, unsigned n50, std::string metrics) : ScaffoldParam(n, s) , n50(n50) , metrics(metrics) {} unsigned n50; std::string metrics; }; /** Build scaffold paths. * @param output write the results * @return the scaffold N50 */ ScaffoldResult scaffold(const Graph& g0, unsigned minEdgeWeight, unsigned minContigLength, bool output) { Graph g(g0); // Filter the graph. filterGraph(g, minEdgeWeight, minContigLength); if (opt::verbose > 0) printGraphStats(cerr, g); // Remove cycles. removeCycles(g); // Resolve forks. resolveForks(g, g0); // Prune tips. pruneTips(g); // Remove repeats. removeRepeats(g); // Remove transitive edges. unsigned numTransitive; if (opt::comp_trans) numTransitive = remove_complex_transitive_edges(g); else numTransitive = remove_transitive_edges(g); if (opt::verbose > 0) { cerr << "Removed " << numTransitive << " transitive edges.\n"; printGraphStats(cerr, g); } if (!opt::db.empty()) addToDb(db, "Edges_transitive", numTransitive); // Prune tips. pruneTips(g); // Pop bubbles. typedef graph_traits::vertex_descriptor V; vector popped = popBubbles(g); if (opt::verbose > 0) { cerr << "Removed " << popped.size() << " 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::const_iterator it = popped.begin(); it != popped.end(); ++it) cerr << ' ' << get(vertex_name, g, *it); cerr << '\n'; } // 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) { for (ContigPaths::const_iterator it = paths.begin(); it != paths.end(); ++it) n += it->size(); cerr << "Assembled " << n << " contigs in " << paths.size() << " scaffolds.\n"; printGraphStats(cerr, g); } if (!opt::db.empty()) { addToDb(db, "contigs_assembled", n); addToDb(db, "scaffolds_assembled", paths.size()); } if (output) { // Output the paths. ofstream fout(opt::out.c_str()); ostream& out = opt::out.empty() || opt::out == "-" ? cout : fout; assert_good(out, opt::out); g_contigNames.unlock(); for (vector::const_iterator it = paths.begin(); it != paths.end(); ++it) out << createContigName() << '\t' << addDistEst(g0, g, *it) << '\n'; assert_good(out, opt::out); // Output the graph. if (!opt::graphPath.empty()) { ofstream out(opt::graphPath.c_str()); assert_good(out, opt::graphPath); write_dot(out, g); assert_good(out, opt::graphPath); } } // Compute contiguity metrics. const unsigned STATS_MIN_LENGTH = opt::minContigLength; std::ostringstream ss; Histogram scaffold_histogram = buildScaffoldLengthHistogram(g, paths); printContiguityStats(ss, scaffold_histogram, STATS_MIN_LENGTH, false, "\t", opt::genomeSize) << "\tn=" << minEdgeWeight << " s=" << minContigLength << '\n'; std::string metrics = ss.str(); addCntgStatsToDb(scaffold_histogram, STATS_MIN_LENGTH); return ScaffoldResult( minEdgeWeight, minContigLength, scaffold_histogram.trimLow(STATS_MIN_LENGTH).n50(), metrics); } /** Memoize the optimization results so far. */ typedef unordered_map ScaffoldMemo; /** Build scaffold paths, memoized. */ ScaffoldResult scaffold_memoized(const Graph& g, unsigned n, unsigned s, ScaffoldMemo& memo) { ScaffoldParam param(n, s); ScaffoldMemo::const_iterator it = memo.find(param); if (it != memo.end()) { // Clear the metrics string, so that this result is not listed // multiple times in the final table of metrics. ScaffoldResult result(it->second); result.metrics.clear(); return result; } if (opt::verbose > 0) std::cerr << "\nScaffolding with n=" << n << " s=" << s << "\n\n"; ScaffoldResult result = scaffold(g, n, s, false); memo[param] = result; // Print assembly metrics. if (opt::verbose > 0) { std::cerr << '\n'; const unsigned STATS_MIN_LENGTH = opt::minContigLength; printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); } std::cerr << result.metrics; if (opt::verbose > 0) cerr << '\n'; return result; } /** Find the value of n that maximizes the scaffold N50. */ static ScaffoldResult optimize_n( const Graph& g, std::pair minEdgeWeight, unsigned minContigLength, ScaffoldMemo& memo) { std::string metrics_table; unsigned bestn = 0, bestN50 = 0; for (unsigned n = minEdgeWeight.first; n <= minEdgeWeight.second; n += opt::minEdgeWeightStep) { ScaffoldResult result = scaffold_memoized(g, n, minContigLength, memo); metrics_table += result.metrics; if (result.n50 > bestN50) { bestN50 = result.n50; bestn = n; } } return ScaffoldResult(bestn, minContigLength, bestN50, metrics_table); } /** Find the value of s that maximizes the scaffold N50. */ static ScaffoldResult optimize_s( const Graph& g, unsigned minEdgeWeight, std::pair minContigLength, ScaffoldMemo& memo) { std::string metrics_table; unsigned bests = 0, bestN50 = 0; const double STEP = cbrt(10); // Three steps per decade. unsigned ilast = (unsigned)round(log(minContigLength.second) / log(STEP)); for (unsigned i = (unsigned)round(log(minContigLength.first) / log(STEP)); i <= ilast; ++i) { unsigned s = (unsigned)pow(STEP, (int)i); // Round to 1 figure. double nearestDecade = pow(10, floor(log10(s))); s = unsigned(round(s / nearestDecade) * nearestDecade); ScaffoldResult result = scaffold_memoized(g, minEdgeWeight, s, memo); metrics_table += result.metrics; if (result.n50 > bestN50) { bestN50 = result.n50; bests = s; } } return ScaffoldResult(minEdgeWeight, bests, bestN50, metrics_table); } /** Find the values of n and s that maximizes the scaffold N50. */ static ScaffoldResult optimize_grid_search( const Graph& g, std::pair minEdgeWeight, std::pair minContigLength) { const unsigned STATS_MIN_LENGTH = opt::minContigLength; if (opt::verbose == 0) printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); ScaffoldMemo memo; std::string metrics_table; ScaffoldResult best(0, 0, 0, ""); for (unsigned n = minEdgeWeight.first; n <= minEdgeWeight.second; n += opt::minEdgeWeightStep) { ScaffoldResult result = optimize_s(g, n, minContigLength, memo); metrics_table += result.metrics; if (result.n50 > best.n50) best = result; } best.metrics = metrics_table; return best; } /** Find the values of n and s that maximizes the scaffold N50. */ static ScaffoldResult optimize_line_search( const Graph& g, std::pair minEdgeWeight, std::pair minContigLength) { const unsigned STATS_MIN_LENGTH = opt::minContigLength; if (opt::verbose == 0) printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); ScaffoldMemo memo; std::string metrics_table; ScaffoldResult best( (minEdgeWeight.first + minEdgeWeight.second) / 2, minContigLength.second, 0, ""); // An upper limit on the number of iterations. const unsigned MAX_ITERATIONS = 1 + (minEdgeWeight.second - minEdgeWeight.first) / opt::minEdgeWeightStep; for (unsigned i = 0; i < MAX_ITERATIONS; ++i) { // Optimize s. if (opt::verbose > 0) { std::cerr << "\nOptimizing s for n=" << best.n << "\n\n"; printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); } unsigned previous_s = best.s; best = optimize_s(g, best.n, minContigLength, memo); metrics_table += best.metrics; if (best.s == previous_s) break; // Optimize n. if (opt::verbose > 0) { std::cerr << "\nOptimizing n for s=" << best.s << "\n\n"; printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); } unsigned previous_n = best.n; best = optimize_n(g, minEdgeWeight, best.s, memo); metrics_table += best.metrics; if (best.n == previous_n) break; } std::cerr << "\nLine search converged in " << memo.size() << " iterations.\n"; best.metrics = metrics_table; return best; } /** 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'k': arg >> opt::k; break; case 'G': { double x; arg >> x; opt::genomeSize = x; break; } case 'g': arg >> opt::graphPath; break; case 'n': arg >> opt::minEdgeWeight; if (arg.peek() == '-') { arg >> expect("-") >> opt::minEdgeWeightEnd; assert(opt::minEdgeWeight <= opt::minEdgeWeightEnd); } else opt::minEdgeWeightEnd = opt::minEdgeWeight; if (arg.peek() == ':') arg >> expect(":") >> opt::minEdgeWeightStep; else opt::minEdgeWeightStep = 1; break; case 'o': arg >> opt::out; break; case 's': arg >> opt::minContigLength; if (arg.peek() == '-') { opt::minContigLengthEnd = 100 * opt::minContigLength; arg >> expect("-") >> opt::minContigLengthEnd; assert(opt::minContigLength <= opt::minContigLengthEnd); } else opt::minContigLengthEnd = opt::minContigLength; break; case 'v': opt::verbose++; break; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (argc - optind < 0) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --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) { for (; optind < argc; optind++) readGraph(argv[optind], g); } else readGraph("-", g); // Add any missing complementary edges. size_t numAdded = addComplementaryEdges(g); if (opt::verbose > 0) { cerr << "Added " << numAdded << " complementary edges.\n"; 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(g)); unsigned numRemoved = numBefore - num_edges(g); if (numRemoved > 0) cerr << "warning: Removed " << numRemoved << " invalid edges.\n"; if (!opt::db.empty()) addToDb(db, "Edges_invalid", numRemoved); const unsigned STATS_MIN_LENGTH = opt::minContigLength; if (opt::minEdgeWeight == opt::minEdgeWeightEnd && opt::minContigLength == opt::minContigLengthEnd) { ScaffoldResult result = scaffold(g, opt::minEdgeWeight, opt::minContigLength, true); // Print assembly contiguity statistics. if (opt::verbose > 0) std::cerr << '\n'; printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); std::cerr << result.metrics; } else { ScaffoldResult best(0, 0, 0, ""); switch (opt::searchStrategy) { case GRID_SEARCH: best = optimize_grid_search( g, std::make_pair(opt::minEdgeWeight, opt::minEdgeWeightEnd), std::make_pair(opt::minContigLength, opt::minContigLengthEnd)); break; case LINE_SEARCH: best = optimize_line_search( g, std::make_pair(opt::minEdgeWeight, opt::minEdgeWeightEnd), std::make_pair(opt::minContigLength, opt::minContigLengthEnd)); break; default: abort(); break; } if (opt::verbose > 0) std::cerr << "\nScaffolding with n=" << best.n << " s=" << best.s << "\n\n"; ScaffoldResult result = scaffold(g, best.n, best.s, true); // Print the table of all the parameter values attempted and their metrics. if (opt::verbose > 0) { std::cerr << '\n'; printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); std::cerr << best.metrics; } std::cerr << '\n' << "Best scaffold N50 is " << best.n50 << " at n=" << best.n << " s=" << best.s << ".\n"; // Print assembly contiguity statistics. std::cerr << '\n'; printContiguityStatsHeader(std::cerr, STATS_MIN_LENGTH, "\t", opt::genomeSize); std::cerr << result.metrics; } return 0; } abyss-2.2.4/Sealer/000077500000000000000000000000001361462241400140565ustar00rootroot00000000000000abyss-2.2.4/Sealer/Makefile.am000066400000000000000000000013451361462241400161150ustar00rootroot00000000000000bin_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 $@ $< abyss-2.2.4/Sealer/README.md000066400000000000000000000210671361462241400153430ustar00rootroot00000000000000--- 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 -b -k -k ... -o -S [options]... [reads2]...` For example: `abyss-sealer -b20G -k64 -k80 -k96 -k112 -k128 -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, the reads should represent the original dataset from which the draft assembly is generated, or further whole genome shotgun (WGS) sequencing data generated from the same sample. Within Konnector, the input WGS reads are used to populate a Bloom filter, tiling the reads with a sliding window of length *k*, thus generating a probabilistic representation of all the *k*-mers in the reads. Konnector also uses crude error removal and correctional algorithms, eliminating singletons (*k*-mers that are observed only once) and fixing base mismatches in the flanking sequence pairs. Sealer launches Konnector processes using a user-input range of *k*-mer lengths. In the third and final operation, successfully merged sequences are inserted into the gaps of the original scaffolds, and Sealer outputs a new gap-filled scaffold file. Installation ============ See ABySS installation instructions. How to run as stand-alone application ===================================== `abyss-sealer [-b bloom filter size][-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 -b20G -k64 -k96 -o run1 -S test.fa read1.fq.gz read2.fq.gz` With pre-built bloom filters: `abyss-sealer -k64 -k96 -o run1 -S test.fa -i k64.bloom -i k96.bloom read1.fq.gz read2.fq.gz` Reusable Bloom filters can be pre-built with `abyss-bloom build`, e.g.: `abyss-bloom build -vv -k64 -j12 -b20G -l2 k64.bloom read1.fq.gz read2.fq.gz` Note: when using pre-built bloom filters generated by `abyss-bloom build`, Sealer must be compiled with the same `maxk` value that `abyss-bloom` was compiled 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. 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. 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`] * `-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. Required when not using pre-built Bloom filter(s). * `-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 *k* is the size of *k*-mer for the de Bruijn graph. You may specify multiple values of *k*, which will increase the number of gaps closed at the cost of increased run time. Multiple values of *k* ought to be specified in increasing order, as lower values of *k* have fewer coverage gaps and are less likely to misassemble. *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. abyss-2.2.4/Sealer/sealer.cc000066400000000000000000001032021361462241400156360ustar00rootroot00000000000000/** * 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 #include #include #include #include #include #include #include #include #if _OPENMP # include # include "Bloom/ConcurrentBloomFilter.h" #endif #undef USESEQAN #if USESEQAN #include #include #include #endif using namespace std; using Konnector::BloomFilter; #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 "-b -k -k ... -o -S [options]... [reads2]...\n" "i.e. abyss-sealer -b20G -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" " -G, --max-gap-length=N max gap size to fill in bp [800]; runtime increases\n" " exponentially with respect to this parameter\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 (e.g. '40G'). Required\n" " when not using pre-built Bloom filter(s)\n" " (-i option)\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" " -C, --max-cost=N max edges to traverse during each graph search [100000]\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" " -g, --gap-file=FILE write sealed gaps to FILE\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" " Deprecated Options:\n" "\n" " -B, --max-branches=N max branches in de Bruijn graph traversal;\n" " use 'nolimit' for no limit [nolimit]\n" " -f, --min-frag=N min fragment size in base pairs\n" " -F, --max-frag=N max fragment size in base pairs\n" "\n" " Note 1: --max-branches was not effective for truncating expensive searches,\n" " and has been superseded by the --max-cost option.\n" "\n" " Note 2: --max-frag was formerly used to determine the maximum gap\n" " size that abyss-sealer would attempt to close, according to the formula\n" " max_gap_size = max_frag - 2 * flank_length, where flank_length is\n" " determined by the -L option. --max-frag is superseded by the more\n" " intuitive -G (--max-gap-length) option. The related option --min-frag\n" " does not seem to have any practical use.\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { /** Length of flank. */ int flankLength = 100; /** Max gap size to fill */ unsigned maxGapLength = 800; /** 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 = 0; /** 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 = NO_LIMIT; /** * Max cost for a connecting path search. Searches that * exceed this cost limit will be aborted and the gap * will remain unfilled. */ unsigned maxCost = 100000; /** 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 kvector; /** Vector of Bloom filter paths corresponding to kmer values */ vector bloomFilterPaths; /** The minimum fragment size */ unsigned minFrag = 0; /** The maximum fragment size */ unsigned maxFrag = 0; /** 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; /** Output file for sealed gaps */ static string gapfilePath; /** 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 maxCostExceeded; size_t exceededMemLimit; size_t traversalMemExceeded; size_t readPairsProcessed; size_t readPairsMerged; size_t skipped; }; static const char shortopts[] = "S:L:b:B:C:d:ef:F:G:g: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' }, { "max-gap-length", required_argument, NULL, 'G' }, { "bloom-size", required_argument, NULL, 'b' }, { "max-branches", required_argument, NULL, 'B' }, { "max-cost", required_argument, NULL, 'C' }, { "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' }, { "gap-file", required_argument, NULL, 'g' }, { "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 DS; typedef Align 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 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< string merge(const Graph& g, unsigned k, const Gap& gap, const FastaRecord &read1, const 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& 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 MAX_COST_EXCEEDED: #pragma omp atomic ++g_count.maxCostExceeded; 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 > &allmerged, unsigned &gapsclosedfinal) { map >::iterator scaf_it; map::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 makePseudoReads(std::string seq, FastaRecord record, const Gap& gap) { std::pair 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 void kRun(const ConnectPairsParams& params, unsigned k, const Graph& g, map > &allmerged, map > &flanks, unsigned &gapsclosed, ofstream &logStream, ofstream &traceStream, ofstream &gapStream) { map >::iterator read1_it; map::iterator read2_it; unsigned uniqueGapsClosed = 0; 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.maxCostExceeded = 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"); int counter = 0; vector >::iterator> flanks_closed; #pragma omp parallel private(read1_it, read2_it) firstprivate(counter) for (read1_it = flanks.begin(); read1_it != flanks.end(); ++read1_it) { FastaRecord read1 = read1_it->first; bool success = false; for (read2_it = flanks[read1].begin(); read2_it != flanks[read1].end(); ++read2_it, ++counter) { #if _OPENMP if (counter % omp_get_num_threads() != omp_get_thread_num()) continue; #endif 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; #pragma omp critical (allmerged) allmerged[read1.id.substr(0,read1.id.length()-2)][startposition] = ClosedGap(read2_it->second, tempSeq); #pragma omp atomic ++uniqueGapsClosed; #pragma omp critical (gapsclosed) if (++gapsclosed % 100 == 0) printLog(logStream, IntToString(gapsclosed) + " gaps closed so far\n"); if (!opt::gapfilePath.empty()) #pragma omp critical (gapStream) gapStream << ">" << read1.id.substr(0,read1.id.length()-2) << "_" << read2_it->second.gapStart() << "-" << read2_it->second.gapEnd() << " LN:i:" << tempSeq.length() << '\n' << tempSeq << '\n'; } } if (success) { #pragma omp critical (flanks_closed) flanks_closed.push_back(read1_it); } } for (vector >::iterator>::iterator it = flanks_closed.begin(); it != flanks_closed.end(); ++it) { if (flanks.count((*it)->first) > 0) flanks.erase(*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, "Max cost exceeded: " + sizetToString(g_count.maxCostExceeded) + "\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 > &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 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 'G': arg >> opt::maxGapLength; break; case 'b': opt::bloomSize = SIToBytes(arg); break; case 'B': setMaxOption(opt::maxBranches, arg); break; case 'C': setMaxOption(opt::maxCost, 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 'g': arg >> opt::gapfilePath; 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); } } /* translate --max-frag to --max-gap-length for backwards compatibility */ if (opt::maxFrag > 0) { if ((int)opt::maxFrag < 2 * opt::flankLength) opt::maxGapLength = 0; else opt::maxGapLength = opt::maxFrag - 2 * opt::flankLength; } 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::bloomFilterPaths.size() < opt::kvector.size() && opt::bloomSize == 0) { cerr << PROGRAM ": missing mandatory option `-b' (Bloom filter size)\n" << "Here are some guidelines for sizing the Bloom filter:\n" << " * E. coli (~5 Mbp genome), 615X coverage: -b500M\n" << " * S. cerevisiae (~12 Mbp genome), 25X coverage: -b500M\n" << " * C. elegans (~100 Mbp genome), 89X coverage: -b1200M\n" << " * H. sapiens (~3 Gbp genome), 71X coverage: -b40G\n"; die = true; } if (opt::outputPrefix.empty()) { cerr << PROGRAM ": missing mandatory option `-o'\n"; die = true; } if (opt::bloomFilterPaths.size() > opt::kvector.size()) { cerr << PROGRAM ": you must specify a k-mer size (-k) for each Bloom " " filter file (-i)\n"; die = true; } else if (opt::bloomFilterPaths.size() < opt::kvector.size() && argc - optind < 1) { cerr << PROGRAM ": missing input file arguments\n"; die = true; } else if (opt::bloomFilterPaths.size() == opt::kvector.size() && argc - optind > 0) { cerr << PROGRAM ": input FASTA/FASTQ args should be omitted when using " "pre-built Bloom filters (-i) for all k-mer sizes\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 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); } ofstream gapStream; if (!opt::gapfilePath.empty()) { gapStream.open(opt::gapfilePath.c_str()); assert(gapStream.is_open()); assert_good(gapStream, opt::gapfilePath); } 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::maxGapLength + 2 * opt::flankLength; params.maxPaths = opt::maxPaths; params.maxBranches = opt::maxBranches; params.maxCost = opt::maxCost; 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 > 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 >::iterator read1_it; map::iterator read2_it; string read1OutputPath(opt::outputPrefix); read1OutputPath.append("_flanks_1.fa"); ofstream read1Stream(read1OutputPath.c_str()); assert_good(read1Stream, read1OutputPath); string read2OutputPath(opt::outputPrefix); read2OutputPath.append("_flanks_2.fa"); 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 > allmerged; unsigned gapsclosed=0; for (unsigned i = 0; i> *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 cbf(*cascadingBloom, 1000); for (int i = optind; i < argc; i++) Bloom::loadFile(cbf, opt::k, argv[i], opt::verbose >= 2); #else for (int i = optind; i < argc; i++) Bloom::loadFile(*cascadingBloom, opt::k, argv[i], opt::verbose >= 2); #endif bloom = &cascadingBloom->getBloomFilter(opt::max_count - 1); } assert(bloom != NULL); if (opt::verbose) cerr << "Bloom filter FPR: " << setprecision(3) << 100 * bloom->FPR() << "%\n"; DBGBloom 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, gapStream); 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 > >::iterator scaf_it; map >::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(); } if (!opt::gapfilePath.empty()) { assert_good(gapStream, opt::gapfilePath); gapStream.close(); } return 0; } abyss-2.2.4/SimpleGraph/000077500000000000000000000000001361462241400150565ustar00rootroot00000000000000abyss-2.2.4/SimpleGraph/Makefile.am000066400000000000000000000004761361462241400171210ustar00rootroot00000000000000bin_PROGRAMS = SimpleGraph SimpleGraph_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Common SimpleGraph_CXXFLAGS = $(AM_CXXFLAGS) -Wno-strict-aliasing SimpleGraph_LDADD = \ $(top_builddir)/DataBase/libdb.a \ $(SQLITE_LIBS) \ $(top_builddir)/Common/libcommon.a \ -lpthread SimpleGraph_SOURCES = SimpleGraph.cpp abyss-2.2.4/SimpleGraph/SimpleGraph.cpp000066400000000000000000000566751361462241400200200ustar00rootroot00000000000000#include "config.h" #include "ContigPath.h" #include "Estimate.h" #include "IOUtil.h" #include "Uncompress.h" #include "Graph/ConstrainedSearch.h" #include "Graph/ContigGraph.h" #include "Graph/ContigGraphAlgorithms.h" #include "Graph/GraphIO.h" #include "Graph/GraphUtil.h" #include // for min #include // for UINT_MAX #include #include #include #include #include #include #include #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" "\n" "Copyright 2018 Canada's Michael Smith Genome Sciences Centre\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k -o [OPTION]... ADJ DIST\n" "Find paths through contigs using distance estimates.\n" "\n" " Arguments:\n" "\n" " ADJ adjacency of the contigs\n" " DIST distance estimates between the contigs\n" "\n" " Options:\n" "\n" " -k, --kmer=KMER_SIZE k-mer size\n" " -n, --npairs=N minimum number of pairs [0]\n" " -s, --seed-length=N minimum seed contig length [0]\n" " -d, --dist-error=N acceptable error of a distance estimate\n" " default is 6 bp\n" " --max-cost=COST maximum computational cost\n" " -o, --out=FILE write result to FILE\n" " -j, --threads=THREADS use THREADS parallel threads [1]\n" " --extend extend unambiguous paths\n" " --no-extend do not extend unambiguous paths [default]\n" " --scaffold join contigs with Ns [default]\n" " --no-scaffold do not scaffold\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; // used by ContigProperties static unsigned threads = 1; static int extend; static int scaffold = 1; static int verbose; static string out; /** Minimum number of pairs. */ static unsigned minEdgeWeight; /** Minimum seed length. */ static unsigned minSeedLength; /** The acceptable error of a distance estimate. */ unsigned distanceError = 6; /** Output format */ int format = DIST; // used by Estimate } static const char shortopts[] = "d:j:k:n:o:s:v"; 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' }, { "npairs", required_argument, NULL, 'n' }, { "seed-length", required_argument, NULL, 's' }, { "dist-error", required_argument, NULL, 'd' }, { "max-cost", required_argument, NULL, OPT_MAX_COST }, { "out", required_argument, NULL, 'o' }, { "extend", no_argument, &opt::extend, 1 }, { "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' }, { "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 } }; typedef ContigGraph > Graph; static void generatePathsThroughEstimates(const Graph& g, const string& estPath); 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;) { istringstream arg(optarg != NULL ? optarg : ""); switch (c) { case '?': die = true; break; case 'd': arg >> opt::distanceError; break; case 'j': arg >> opt::threads; break; case 'k': arg >> opt::k; break; case OPT_MAX_COST: arg >> opt::maxCost; break; case 'n': arg >> opt::minEdgeWeight; break; case 'o': arg >> opt::out; break; case 's': arg >> opt::minSeedLength; break; case 'v': opt::verbose++; 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: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } if (opt::k <= 0) { cerr << PROGRAM ": missing -k,--kmer option\n"; die = true; } if (opt::out.empty()) { cerr << PROGRAM ": " << "missing -o,--out option\n"; die = true; } if (argc - optind < 2) { cerr << PROGRAM ": missing arguments\n"; die = true; } else if (argc - optind > 2) { cerr << PROGRAM ": too many arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --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); string adjFile(argv[optind++]); string estFile(argv[optind++]); // Read the contig adjacency graph. if (opt::verbose > 0) cerr << "Reading `" << adjFile << "'..." << endl; ifstream fin(adjFile.c_str()); assert_good(fin, adjFile); Graph g; fin >> g; assert(fin.eof()); 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); } /** Print a set of constraints. */ static ostream& printConstraints(ostream& out, const Graph& g, const Constraints& s) { for (Constraints::const_iterator it = s.begin(); it != s.end(); ++it) out << ' ' << get(vertex_name, g, it->first) << ',' << it->second; return out; } /** Return the set of contigs that appear more than once in a single * solution. */ static set findRepeats(ContigID seed, const ContigPaths& solutions) { set repeats; for (ContigPaths::const_iterator solIt = solutions.begin(); solIt != solutions.end(); ++solIt) { map count; count[seed]++; for (ContigPath::const_iterator it = solIt->begin(); it != solIt->end(); ++it) count[it->contigIndex()]++; for (map::const_iterator it = count.begin(); it != count.end(); ++it) if (it->second > 1) repeats.insert(it->first); } return repeats; } /** The fewest number of pairs in a distance estimate. */ static unsigned g_minNumPairs = UINT_MAX; /** The fewest number of pairs used in a path. */ static unsigned g_minNumPairsUsed = UINT_MAX; static struct { unsigned seedTooShort; unsigned noEdges; unsigned edgesRemoved; unsigned totalAttempted; unsigned uniqueEnd; unsigned noPossiblePaths; unsigned noValidPaths; unsigned repeat; unsigned multiEnd; unsigned tooManySolutions; unsigned tooComplex; } stats; typedef graph_traits::vertex_descriptor vertex_descriptor; /** Return the distance from vertex u to v. */ static int getDistance(const Graph& g, vertex_descriptor u, vertex_descriptor v) { typedef graph_traits::edge_descriptor edge_descriptor; pair e = edge(u, v, g); assert(e.second); return g[e.first].distance; } /** Return the length of the specified path in k-mer. */ static unsigned calculatePathLength(const Graph& g, const ContigNode& origin, const ContigPath& path, size_t prefix = 0, size_t suffix = 0) { if (prefix + suffix == path.size()) return 0; assert(prefix + suffix < path.size()); int length = addProp(g, path.begin() + prefix, path.end() - suffix).length; // Account for the overlap on the left. vertex_descriptor u = prefix == 0 ? origin : path[prefix - 1]; length += getDistance(g, u, path[prefix]); assert(length > 0); return length; } /** Compare the lengths of two paths. */ struct ComparePathLength : binary_function { ComparePathLength(const Graph& g, const ContigNode& origin) : m_g(g), m_origin(origin) { } bool operator()(const ContigPath& a, const ContigPath& b) const { unsigned lenA = calculatePathLength(m_g, m_origin, a); unsigned lenB = calculatePathLength(m_g, m_origin, b); return lenA < lenB || (lenA == lenB && a.size() < b.size()); } private: const Graph& m_g; const ContigNode& m_origin; }; /** Return an ambiguous path that agrees with all the given paths. */ static ContigPath constructAmbiguousPath(const Graph &g, const ContigNode& origin, const ContigPaths& paths) { assert(!paths.empty()); // Find the size of the smallest path. const ContigPath& firstSol = paths.front(); size_t min_len = firstSol.size(); for (ContigPaths::const_iterator it = paths.begin() + 1; it != paths.end(); ++it) min_len = min(min_len, it->size()); // Find the longest prefix. ContigPath vppath; size_t longestPrefix; bool commonPrefix = true; for (longestPrefix = 0; longestPrefix < min_len; longestPrefix++) { const ContigNode& common_path_node = firstSol[longestPrefix]; for (ContigPaths::const_iterator solIter = paths.begin(); solIter != paths.end(); ++solIter) { const ContigNode& pathnode = (*solIter)[longestPrefix]; if (pathnode != common_path_node) { // Found the longest prefix. commonPrefix = false; break; } } if (!commonPrefix) break; vppath.push_back(common_path_node); } // Find the longest suffix. ContigPath vspath; size_t longestSuffix; bool commonSuffix = true; for (longestSuffix = 0; longestSuffix < min_len-longestPrefix; longestSuffix++) { const ContigNode& common_path_node = firstSol[firstSol.size()-longestSuffix-1]; for (ContigPaths::const_iterator solIter = paths.begin(); solIter != paths.end(); ++solIter) { const ContigNode& pathnode = (*solIter)[solIter->size()-longestSuffix-1]; if (pathnode != common_path_node) { // Found the longest suffix. commonSuffix = false; break; } } if (!commonSuffix) break; vspath.push_back(common_path_node); } ContigPath out; out.reserve(vppath.size() + 1 + vspath.size()); out.insert(out.end(), vppath.begin(), vppath.end()); if (longestSuffix > 0) { const ContigPath& longestPath( *max_element(paths.begin(), paths.end(), ComparePathLength(g, origin))); unsigned length = calculatePathLength(g, origin, longestPath, longestPrefix, longestSuffix); // Account for the overlap on the right. int dist = length + getDistance(g, longestSuffix == longestPath.size() ? origin : *(longestPath.rbegin() + longestSuffix), *(longestPath.rbegin() + longestSuffix - 1)); // Add k-1 because it is the convention. int numN = dist + opt::k - 1; assert(numN > 0); out.push_back(ContigNode(numN, 'N')); out.insert(out.end(), vspath.rbegin(), vspath.rend()); } return out; } /** Return a map of contig IDs to their distance along this path. * Repeat contigs, which would have more than one position, are not * represented in this map. */ map makeDistanceMap(const Graph& g, const ContigNode& origin, const ContigPath& path) { map distances; int distance = 0; for (ContigPath::const_iterator it = path.begin(); it != path.end(); ++it) { vertex_descriptor u = it == path.begin() ? origin : *(it - 1); vertex_descriptor v = *it; distance += getDistance(g, u, v); bool inserted = distances.insert( make_pair(v, distance)).second; if (!inserted) { // Mark this contig as a repeat. distances[v] = INT_MIN; } distance += g[v].length; } // Remove the repeats. for (map::iterator it = distances.begin(); it != distances.end();) if (it->second == INT_MIN) distances.erase(it++); else ++it; return distances; } /** Print a distance map. */ static void printDistanceMap(ostream& out, const Graph& g, const ContigNode& u, const ContigPath& path) { typedef map DistanceMap; DistanceMap distanceMap = makeDistanceMap(g, u, path); for (DistanceMap::const_iterator it = distanceMap.begin(); it != distanceMap.end(); ++it) out << get(edge_name, g, make_pair(u, it->first)) << " [d=" << it->second << "]\n"; } typedef std::vector > Estimates; /** Find a path for the specified distance estimates. * @param out [out] the solution path */ static void handleEstimate(const Graph& g, const EstimateRecord& er, bool dirIdx, ContigPath& out) { if (er.estimates[dirIdx].empty()) return; ContigNode origin(er.refID, dirIdx); ostringstream vout_ss; ostream bitBucket(NULL); ostream& vout = opt::verbose > 0 ? vout_ss : bitBucket; vout << "\n* " << get(vertex_name, g, origin) << '\n'; unsigned minNumPairs = UINT_MAX; // generate the reachable set Constraints constraints; for (Estimates::const_iterator iter = er.estimates[dirIdx].begin(); iter != er.estimates[dirIdx].end(); ++iter) { ContigNode v = iter->first; const DistanceEst& ep = iter->second; minNumPairs = min(minNumPairs, ep.numPairs); constraints.push_back(Constraint(v, ep.distance + allowedError(ep.stdDev))); } vout << "Constraints:"; printConstraints(vout, g, constraints) << '\n'; ContigPaths solutions; unsigned numVisited = 0; constrainedSearch(g, origin, constraints, solutions, numVisited); bool tooComplex = numVisited >= opt::maxCost; bool tooManySolutions = solutions.size() > opt::maxPaths; set repeats = findRepeats(er.refID, solutions); if (!repeats.empty()) { vout << "Repeats:"; for (set::const_iterator it = repeats.begin(); it != repeats.end(); ++it) vout << ' ' << get(g_contigNames, *it); vout << '\n'; } unsigned numPossiblePaths = solutions.size(); if (numPossiblePaths > 0) vout << "Paths: " << numPossiblePaths << '\n'; for (ContigPaths::iterator solIter = solutions.begin(); solIter != solutions.end();) { vout << *solIter << '\n'; // Calculate the path distance to each node and see if // it is within the estimated distance. map distanceMap = makeDistanceMap(g, origin, *solIter); // Remove solutions whose distance estimates are not correct. unsigned validCount = 0, invalidCount = 0, ignoredCount = 0; for (Estimates::const_iterator iter = er.estimates[dirIdx].begin(); iter != er.estimates[dirIdx].end(); ++iter) { ContigNode v = iter->first; const DistanceEst& ep = iter->second; vout << get(vertex_name, g, v) << ',' << ep << '\t'; map::iterator dmIter = distanceMap.find(v); if (dmIter == distanceMap.end()) { // This contig is a repeat. ignoredCount++; vout << "ignored\n"; continue; } // translate distance by -overlap to match // coordinate space used by the estimate int actualDistance = dmIter->second; int diff = actualDistance - ep.distance; unsigned buffer = allowedError(ep.stdDev); bool invalid = (unsigned)abs(diff) > buffer; bool repeat = repeats.count(v.contigIndex()) > 0; bool ignored = invalid && repeat; if (ignored) ignoredCount++; else if (invalid) invalidCount++; else validCount++; vout << "dist: " << actualDistance << " diff: " << diff << " buffer: " << buffer << " n: " << ep.numPairs << (ignored ? " ignored" : invalid ? " invalid" : "") << '\n'; } if (invalidCount == 0 && validCount > 0) ++solIter; else solIter = solutions.erase(solIter); } vout << "Solutions: " << solutions.size(); if (tooComplex) vout << " (too complex)"; if (tooManySolutions) vout << " (too many solutions)"; vout << '\n'; ContigPaths::iterator bestSol = solutions.end(); int minDiff = 999999; for (ContigPaths::iterator solIter = solutions.begin(); solIter != solutions.end(); ++solIter) { map distanceMap = makeDistanceMap(g, origin, *solIter); int sumDiff = 0; for (Estimates::const_iterator iter = er.estimates[dirIdx].begin(); iter != er.estimates[dirIdx].end(); ++iter) { ContigNode v = iter->first; const DistanceEst& ep = iter->second; if (repeats.count(v.contigIndex()) > 0) continue; map::iterator dmIter = distanceMap.find(v); assert(dmIter != distanceMap.end()); int actualDistance = dmIter->second; int diff = actualDistance - ep.distance; sumDiff += abs(diff); } if (sumDiff < minDiff) { minDiff = sumDiff; bestSol = solIter; } vout << *solIter << " length: " << calculatePathLength(g, origin, *solIter) << " sumdiff: " << sumDiff << '\n'; } /** Lock the debugging stream. */ static pthread_mutex_t coutMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&coutMutex); stats.totalAttempted++; g_minNumPairs = min(g_minNumPairs, minNumPairs); if (tooComplex) { stats.tooComplex++; } else if (tooManySolutions) { stats.tooManySolutions++; } else if (numPossiblePaths == 0) { stats.noPossiblePaths++; } else if (solutions.empty()) { stats.noValidPaths++; } else if (repeats.count(er.refID) > 0) { vout << "Repeat: " << get(vertex_name, g, origin) << '\n'; stats.repeat++; } else if (solutions.size() > 1) { ContigPath path = constructAmbiguousPath(g, origin, solutions); if (!path.empty()) { if (opt::extend) extend(g, path.back(), back_inserter(path)); vout << path << '\n'; if (opt::scaffold) { out.insert(out.end(), path.begin(), path.end()); g_minNumPairsUsed = min(g_minNumPairsUsed, minNumPairs); } } stats.multiEnd++; } else { assert(solutions.size() == 1); assert(bestSol != solutions.end()); ContigPath& path = *bestSol; if (opt::verbose > 1) printDistanceMap(vout, g, origin, path); if (opt::extend) extend(g, path.back(), back_inserter(path)); out.insert(out.end(), path.begin(), path.end()); stats.uniqueEnd++; g_minNumPairsUsed = min(g_minNumPairsUsed, minNumPairs); } cout << vout_ss.str(); if (!out.empty()) assert(!out.back().ambiguous()); pthread_mutex_unlock(&coutMutex); } /** Return whether the specified edge has sufficient support. */ struct PoorSupport { PoorSupport(unsigned minEdgeWeight) : m_minEdgeWeight(minEdgeWeight) { } bool operator()(const Estimates::value_type& estimate) const { return estimate.second.numPairs < m_minEdgeWeight; } const unsigned m_minEdgeWeight; }; struct WorkerArg { istream* in; ostream* out; const Graph* graph; WorkerArg(istream* in, ostream* out, const Graph* g) : in(in), out(out), graph(g) { } }; static void* worker(void* pArg) { WorkerArg& arg = *static_cast(pArg); unsigned countSeedTooShort = 0; unsigned countNoEdges = 0; unsigned countEdgesRemoved = 0; for (;;) { /** Lock the input stream. */ static pthread_mutex_t inMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&inMutex); EstimateRecord er; bool good = bool((*arg.in) >> er); pthread_mutex_unlock(&inMutex); if (!good) break; if ((*arg.graph)[ContigNode(er.refID, false)].length < opt::minSeedLength) { ++countSeedTooShort; continue; } // Remove edges with insufficient support. for (unsigned i = 0; i < 2; ++i) { Estimates& estimates = er.estimates[i]; if (estimates.empty()) continue; unsigned sizeBefore = estimates.size(); estimates.erase( remove_if(estimates.begin(), estimates.end(), PoorSupport(opt::minEdgeWeight)), estimates.end()); unsigned sizeAfter = estimates.size(); unsigned edgesRemoved = sizeBefore - sizeAfter; countEdgesRemoved += edgesRemoved; if (sizeAfter == 0) ++countNoEdges; } // Flip the anterior distance estimates. for (Estimates::iterator it = er.estimates[1].begin(); it != er.estimates[1].end(); ++it) it->first ^= 1; ContigPath path; handleEstimate(*arg.graph, er, true, path); reverseComplement(path.begin(), path.end()); path.push_back(ContigNode(er.refID, false)); handleEstimate(*arg.graph, er, false, path); if (path.size() > 1) { /** Lock the output stream. */ static pthread_mutex_t outMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&outMutex); *arg.out << get(g_contigNames, er.refID) << '\t' << path << '\n'; assert(arg.out->good()); pthread_mutex_unlock(&outMutex); } } static pthread_mutex_t statsMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&statsMutex); stats.seedTooShort += countSeedTooShort; stats.noEdges += countNoEdges; stats.edgesRemoved += countEdgesRemoved; pthread_mutex_unlock(&statsMutex); return NULL; } static void generatePathsThroughEstimates(const Graph& g, const string& estPath) { if (opt::verbose > 0) cerr << "Reading `" << estPath << "'..." << endl; ifstream inStream(estPath.c_str()); assert_good(inStream, estPath); ofstream outStream(opt::out.c_str()); assert(outStream.is_open()); // Create the worker threads. vector threads; threads.reserve(opt::threads); WorkerArg arg(&inStream, &outStream, &g); for (unsigned i = 0; i < opt::threads; i++) { pthread_t thread; pthread_create(&thread, NULL, worker, &arg); threads.push_back(thread); } // Wait for the worker threads to finish. for (vector::const_iterator it = threads.begin(); it != threads.end(); ++it) { void* status; pthread_join(*it, &status); } if (opt::verbose > 0) cout << '\n'; cout << "Seed too short: " << stats.seedTooShort << "\n" "Seeds with no edges: " << stats.noEdges << "\n" "Edges removed: " << stats.edgesRemoved << "\n" "Total paths attempted: " << stats.totalAttempted << "\n" "Unique path: " << stats.uniqueEnd << "\n" "No possible paths: " << stats.noPossiblePaths << "\n" "No valid paths: " << stats.noValidPaths << "\n" "Repetitive: " << stats.repeat << "\n" "Multiple valid paths: " << stats.multiEnd << "\n" "Too many solutions: " << stats.tooManySolutions << "\n" "Too complex: " << stats.tooComplex << "\n"; vector vals = make_vector() << stats.totalAttempted << stats.uniqueEnd << stats.noPossiblePaths << stats.noValidPaths << stats.repeat << stats.multiEnd << stats.tooManySolutions << stats.tooComplex; vector keys = make_vector() << "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(); cout << "\n" "The minimum number of pairs in a distance estimate is " << g_minNumPairs << ".\n"; if (g_minNumPairsUsed != UINT_MAX) { cout << "The minimum number of pairs used in a path is " << g_minNumPairsUsed << ".\n"; if (g_minNumPairs < g_minNumPairsUsed) cout << "Consider increasing the number of pairs " "threshold parameter, n, to " << g_minNumPairsUsed << ".\n"; } vals += make_vector() << g_minNumPairs << g_minNumPairsUsed; keys += make_vector() << "minPairNum_DistanceEst" << "minPairNum_UsedInPath"; if (!opt::db.empty()) { for (unsigned i=0; i #include using namespace std; typedef RollingBloomDBG Graph; typedef graph_traits GraphTraits; /* each vertex is represented by * std::pair>, where 'string' is the * k-mer and 'vector' is the associated set of * hash values */ typedef graph_traits::vertex_descriptor V; /** Convert a path in the de Bruijn graph to a sequence */ TEST(BloomDBG, pathToSeq) { const string inputSeq = "ACGTAC"; const string spacedSeed = "10001"; const unsigned k = 5; const unsigned numHashes = 2; MaskedKmer::setLength(k); MaskedKmer::setMask(spacedSeed); Path path = BloomDBG::seqToPath(inputSeq, k, numHashes); ASSERT_EQ(2U, path.size()); string outputSeq = BloomDBG::pathToSeq(path, k); ASSERT_EQ("ACNNAC", outputSeq); } abyss-2.2.4/Unittest/BloomDBG/CountingBloomFilterTest.cpp000066400000000000000000000025071361462241400233440ustar00rootroot00000000000000#include "vendor/btl_bloomfilter/CountingBloomFilter.hpp" #include "BloomDBG/RollingHashIterator.h" #include using namespace std; typedef uint64_t hash_t; TEST(CountingBloomFilter, base) { const unsigned bloomSize = 1000; const unsigned numHashes = 1; const unsigned numLevels = 2; const unsigned k = 16; CountingBloomFilter x(bloomSize, numHashes, k, numLevels); EXPECT_EQ(x.sizeInBytes(), bloomSize); const char *a = "AGATGTGCTGCCGCCT"; const char *b = "TGGACAGCGTTACCTC"; const char *c = "TAATAACAGTCCCTAT"; const char *d = "GATCGTGGCGGGCGAT"; const char *e = "TTTTTTTTTTTTTTTT"; RollingHashIterator itA(a, numHashes, k); RollingHashIterator itB(b, numHashes, k); RollingHashIterator itC(c, numHashes, k); RollingHashIterator itD(d, numHashes, k); RollingHashIterator itE(e, numHashes, k); x.insert(*itA); EXPECT_EQ(x.filtered_popcount(), 0U); EXPECT_FALSE(x.contains(*itE)); x.insert(*itA); EXPECT_EQ(x.filtered_popcount(), 1U); EXPECT_TRUE(x.contains(*itA)); x.insert(*itB); EXPECT_EQ(x.filtered_popcount(), 1U); EXPECT_FALSE(x.contains(*itB)); x.insert(*itC); EXPECT_EQ(x.filtered_popcount(), 1U); EXPECT_FALSE(x.contains(*itC)); x.insert(*itB); EXPECT_EQ(x.filtered_popcount(), 2U); EXPECT_TRUE(x.contains(*itB)); EXPECT_FALSE(x.contains(*itD)); } abyss-2.2.4/Unittest/BloomDBG/HashAgnosticCascadingBloomTest.cpp000066400000000000000000000022531361462241400245560ustar00rootroot00000000000000#include "Bloom/HashAgnosticCascadingBloom.h" #include "BloomDBG/RollingHashIterator.h" #include using namespace std; typedef uint64_t hash_t; TEST(HashAgnosticCascadingBloom, base) { const unsigned bloomSize = 1000; const unsigned numHashes = 1; const unsigned numLevels = 2; const unsigned k = 16; HashAgnosticCascadingBloom x(bloomSize, numHashes, numLevels, k); EXPECT_EQ(x.size(), bloomSize); const char* a = "AGATGTGCTGCCGCCT"; const char* b = "TGGACAGCGTTACCTC"; const char* c = "TAATAACAGTCCCTAT"; const char* d = "GATCGTGGCGGGCGAT"; RollingHashIterator itA(a, numHashes, k); RollingHashIterator itB(b, numHashes, k); RollingHashIterator itC(c, numHashes, k); RollingHashIterator itD(d, numHashes, k); hash_t hash; x.insert(*itA); EXPECT_EQ(x.popcount(), 0U); EXPECT_FALSE(x.contains(&hash)); x.insert(*itA); EXPECT_EQ(x.popcount(), 1U); EXPECT_TRUE(x.contains(*itA)); x.insert(*itB); EXPECT_EQ(x.popcount(), 1U); EXPECT_FALSE(x.contains(*itB)); x.insert(*itC); EXPECT_EQ(x.popcount(), 1U); EXPECT_FALSE(x.contains(*itC)); x.insert(*itB); EXPECT_EQ(x.popcount(), 2U); EXPECT_TRUE(x.contains(*itB)); EXPECT_FALSE(x.contains(*itD)); } abyss-2.2.4/Unittest/BloomDBG/LightweightKmerTest.cpp000066400000000000000000000012521361462241400225110ustar00rootroot00000000000000#include "BloomDBG/LightweightKmer.h" #include "Common/Kmer.h" #include TEST(LightweightKmerTest, isCanonical) { Kmer::setLength(5); const LightweightKmer kmer1("ACGTA"); const LightweightKmer kmer2("TACGT"); EXPECT_TRUE(kmer1.isCanonical()); EXPECT_FALSE(kmer2.isCanonical()); } TEST(LightweightKmerTest, canonicalize) { Kmer::setLength(5); const LightweightKmer kmer1("ACGTA"); const LightweightKmer kmer2("TACGT"); LightweightKmer kmer1Copy(kmer1.c_str()); kmer1Copy.canonicalize(); EXPECT_EQ(kmer1, kmer1Copy); LightweightKmer kmer2Copy(kmer2.c_str()); kmer2Copy.canonicalize(); EXPECT_NE(kmer2, kmer2Copy); EXPECT_EQ(kmer1, kmer2Copy); } abyss-2.2.4/Unittest/BloomDBG/MaskedKmerTest.cpp000066400000000000000000000006321361462241400214370ustar00rootroot00000000000000#include "BloomDBG/MaskedKmer.h" #include using namespace std; TEST(MaskedKmerTest, trivialMask) { MaskedKmer::setLength(4); MaskedKmer kmer1("ACGT"); MaskedKmer kmer2("ACGT"); ASSERT_EQ(kmer1, kmer2); } TEST(MaskedKmerTest, nonTrivialMask) { MaskedKmer::setLength(4); MaskedKmer::setMask("1001"); MaskedKmer kmer1("ACGT"); MaskedKmer kmer2("ATTT"); ASSERT_EQ(kmer1, kmer2); } abyss-2.2.4/Unittest/BloomDBG/RollingBloomDBGTest.cpp000066400000000000000000000212351361462241400223320ustar00rootroot00000000000000#include "BloomDBG/RollingBloomDBG.h" #include "vendor/btl_bloomfilter/BloomFilter.hpp" #include "Common/UnorderedSet.h" #include #include using namespace std; using namespace boost; typedef RollingBloomDBG Graph; typedef graph_traits GraphTraits; typedef graph_traits::vertex_descriptor V; typedef uint64_t hash_t; /** Test fixture for RollingBloomDBG tests. */ class RollingBloomDBGTest : public ::testing::Test { protected: const unsigned m_k; const unsigned m_bloomSize; const unsigned m_numHashes; BloomFilter m_bloom; Graph m_graph; RollingBloomDBGTest() : m_k(5), m_bloomSize(100000), m_numHashes(2), m_bloom(m_bloomSize, m_numHashes, m_k), m_graph(m_bloom) { MaskedKmer::setLength(m_k); /* * Test de Bruijn graph: * * CGACT ACTCT * \ / * GACTC * / \ * TGACT ACTCG * * Note: No unexpected edges * are created by the reverse * complements of these k-mers. */ hash_t hashes[MAX_HASHES]; RollingHash("CGACT", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("TGACT", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("GACTC", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("ACTCT", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("ACTCG", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); } }; TEST_F(RollingBloomDBGTest, out_edge_iterator) { /* TEST: check that "GACTC" has the expected outgoing edges */ const V GACTC("GACTC", RollingHash("GACTC", m_numHashes, m_k)); const V ACTCT("ACTCT", RollingHash("ACTCT", m_numHashes, m_k)); const V ACTCG("ACTCG", RollingHash("ACTCG", m_numHashes, m_k)); unordered_set expectedNeighbours; expectedNeighbours.insert(ACTCT); expectedNeighbours.insert(ACTCG); ASSERT_EQ(2u, out_degree(GACTC, m_graph)); GraphTraits::out_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = out_edges(GACTC, m_graph); ASSERT_NE(ei_end, ei); unordered_set::iterator neighbour = expectedNeighbours.find(target(*ei, m_graph)); EXPECT_NE(expectedNeighbours.end(), neighbour); expectedNeighbours.erase(neighbour); ei++; ASSERT_NE(ei_end, ei); neighbour = expectedNeighbours.find(target(*ei, m_graph)); ASSERT_NE(expectedNeighbours.end(), neighbour); ei++; ASSERT_EQ(ei_end, ei); } TEST_F(RollingBloomDBGTest, adjacency_iterator) { /* TEST: check that "GACTC" has the expected outgoing edges */ const V GACTC("GACTC", RollingHash("GACTC", m_numHashes, m_k)); const V ACTCT("ACTCT", RollingHash("ACTCT", m_numHashes, m_k)); const V ACTCG("ACTCG", RollingHash("ACTCG", m_numHashes, m_k)); unordered_set expectedNeighbours; expectedNeighbours.insert(ACTCT); expectedNeighbours.insert(ACTCG); ASSERT_EQ(2u, out_degree(GACTC, m_graph)); GraphTraits::adjacency_iterator ai, ai_end; boost::tie(ai, ai_end) = adjacent_vertices(GACTC, m_graph); ASSERT_NE(ai_end, ai); unordered_set::iterator neighbour = expectedNeighbours.find(*ai); EXPECT_NE(expectedNeighbours.end(), neighbour); expectedNeighbours.erase(neighbour); ai++; ASSERT_NE(ai_end, ai); neighbour = expectedNeighbours.find(*ai); ASSERT_NE(expectedNeighbours.end(), neighbour); ai++; ASSERT_EQ(ai_end, ai); } TEST_F(RollingBloomDBGTest, in_edges) { /* TEST: check that "GACTC" has the expected ingoing edges */ const V GACTC("GACTC", RollingHash("GACTC", m_numHashes, m_k)); const V CGACT("CGACT", RollingHash("CGACT", m_numHashes, m_k)); const V TGACT("TGACT", RollingHash("TGACT", m_numHashes, m_k)); unordered_set expectedNeighbours; expectedNeighbours.insert(CGACT); expectedNeighbours.insert(TGACT); ASSERT_EQ(2u, in_degree(GACTC, m_graph)); GraphTraits::in_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = in_edges(GACTC, m_graph); ASSERT_NE(ei_end, ei); unordered_set::iterator neighbour = expectedNeighbours.find(source(*ei, m_graph)); EXPECT_NE(expectedNeighbours.end(), neighbour); expectedNeighbours.erase(neighbour); ei++; ASSERT_NE(ei_end, ei); neighbour = expectedNeighbours.find(source(*ei, m_graph)); ASSERT_NE(expectedNeighbours.end(), neighbour); ei++; ASSERT_EQ(ei_end, ei); } TEST_F(RollingBloomDBGTest, pathTraversal) { /* * Walk a simple path: * * CGACT-GACTC-ACTCG */ BloomFilter bloom(m_bloomSize, m_numHashes, m_k); Graph graph(bloom); const V CGACT("CGACT", RollingHash("CGACT", m_numHashes, m_k)); const V GACTC("GACTC", RollingHash("GACTC", m_numHashes, m_k)); const V ACTCG("ACTCG", RollingHash("ACTCG", m_numHashes, m_k)); hash_t hashes[MAX_HASHES]; CGACT.rollingHash().getHashes(hashes); bloom.insert(hashes); GACTC.rollingHash().getHashes(hashes); bloom.insert(hashes); ACTCG.rollingHash().getHashes(hashes); bloom.insert(hashes); /* step one */ V v = CGACT; ASSERT_EQ(1u, out_degree(v, graph)); GraphTraits::out_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = out_edges(v, graph); ASSERT_NE(ei_end, ei); ASSERT_EQ(CGACT, source(*ei, graph)); ASSERT_EQ(GACTC, target(*ei, graph)); v = target(*ei, graph); ++ei; ASSERT_EQ(ei_end, ei); /* step two */ ASSERT_EQ(1u, out_degree(v, graph)); boost::tie(ei, ei_end) = out_edges(v, graph); ASSERT_NE(ei_end, ei); ASSERT_EQ(GACTC, source(*ei, graph)); ASSERT_EQ(ACTCG, target(*ei, graph)); v = target(*ei, graph); ++ei; ASSERT_EQ(ei_end, ei); } TEST_F(RollingBloomDBGTest, vertexComparison) { /* * Note: vertex comparision should be * invariant with respect to k-mer orientation. * In other words, a k-mer and its reverse * complement are considered to be the same * vertex. Different vertices are compared * by converting them to their canonical * orientations. */ const V kmer1("ACGTA", RollingHash("ACGTA", m_numHashes, m_k)); const V rcKmer1("TACGT", RollingHash("TACGT", m_numHashes, m_k)); const V kmer2("TGCAT", RollingHash("TGCAT", m_numHashes, m_k)); const V rcKmer2("ATGCA", RollingHash("ATGCA", m_numHashes, m_k)); ASSERT_TRUE(kmer1.isCanonical()); ASSERT_FALSE(kmer2.isCanonical()); /* we expect a vertex to be equal to its reverse complement */ ASSERT_EQ(kmer1, rcKmer1); ASSERT_EQ(kmer2, rcKmer2); /* * we expect kmer1 < kmer2, regardless of the orientation * of the two k-mers */ ASSERT_TRUE(kmer1 < kmer2); ASSERT_TRUE(kmer1 < rcKmer2); ASSERT_TRUE(rcKmer1 < kmer2); ASSERT_TRUE(rcKmer1 < rcKmer2); } /** Test fixture for RollingBloomDBG with spaced seed k-mers. */ class RollingBloomDBGSpacedSeedTest : public ::testing::Test { protected: const unsigned m_k; const unsigned m_bloomSize; const unsigned m_numHashes; BloomFilter m_bloom; Graph m_graph; const std::string m_spacedSeed; RollingBloomDBGSpacedSeedTest() : m_k(5), m_bloomSize(100000), m_numHashes(1), m_bloom(m_bloomSize, m_numHashes, m_k), m_graph(m_bloom), m_spacedSeed("11011") { MaskedKmer::setLength(m_k); MaskedKmer::setMask(m_spacedSeed); /* * Test de Bruijn graph: * * CGACT ACTCT * \ / * GACTC * / \ * TGACT ACTCG * * Masked version: * * CG_CT AC_CT * \ / * GA_TC * / \ * TG_CT AC_CG * * Note: With respect to the spaced seed "11011", * GACTC is equivalent to its own reverse complement * GAGTC. However, this does not result in * any additional edges in the graph. */ hash_t hashes[MAX_HASHES]; RollingHash("CGACT", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("TGACT", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("GACTC", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("ACTCT", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); RollingHash("ACTCG", m_numHashes, m_k).getHashes(hashes); m_bloom.insert(hashes); } }; TEST_F(RollingBloomDBGSpacedSeedTest, out_edge_iterator) { /* TEST: check that "GACTC" has the expected outgoing edges */ const V GACTC("GACTC", RollingHash("GACTC", m_numHashes, m_k)); const V ACTCT("ACTCT", RollingHash("ACTCT", m_numHashes, m_k)); const V ACTCG("ACTCG", RollingHash("ACTCG", m_numHashes, m_k)); unordered_set expectedNeighbours; expectedNeighbours.insert(ACTCT); expectedNeighbours.insert(ACTCG); ASSERT_EQ(2u, out_degree(GACTC, m_graph)); GraphTraits::out_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = out_edges(GACTC, m_graph); ASSERT_NE(ei_end, ei); unordered_set::iterator neighbour = expectedNeighbours.find(target(*ei, m_graph)); EXPECT_NE(expectedNeighbours.end(), neighbour); expectedNeighbours.erase(neighbour); ei++; ASSERT_NE(ei_end, ei); neighbour = expectedNeighbours.find(target(*ei, m_graph)); ASSERT_NE(expectedNeighbours.end(), neighbour); ei++; ASSERT_EQ(ei_end, ei); } abyss-2.2.4/Unittest/BloomDBG/RollingHashIteratorTest.cpp000066400000000000000000000050341361462241400233410ustar00rootroot00000000000000#include "BloomDBG/RollingHashIterator.h" #include #include using namespace std; TEST(RollingHashIterator, reverseComplement) { const unsigned k = 6; const unsigned numHashes = 1; const char* seq = "GCAATGT"; const char* rcSeq = "ACATTGC"; /** hash forward sequence */ RollingHashIterator it(seq, numHashes, k); size_t kmer1Hash, kmer2Hash; kmer1Hash = (*it)[0]; ++it; kmer2Hash = (*it)[0]; ++it; ASSERT_EQ(RollingHashIterator::end(), it); /** hash reverse complement sequence */ RollingHashIterator rcIt(rcSeq, numHashes, k); size_t rcKmer1Hash, rcKmer2Hash; rcKmer2Hash = (*rcIt)[0]; ++rcIt; rcKmer1Hash = (*rcIt)[0]; ++rcIt; ASSERT_EQ(RollingHashIterator::end(), rcIt); /** check hash values are the same for forward and reverse complement */ ASSERT_EQ(kmer1Hash, rcKmer1Hash); ASSERT_EQ(kmer2Hash, rcKmer2Hash); } TEST(RollingHashIterator, badKmers) { const unsigned k = 3; const unsigned numHashes = 1; /* skip bad k-mers in middle of sequence */ const char* seq = "AAANAAA"; RollingHashIterator it(seq, numHashes, k); ASSERT_EQ(0u, it.pos()); ++it; ASSERT_EQ(4u, it.pos()); ++it; ASSERT_EQ(RollingHashIterator::end(), it); /* all bad k-mers */ const char* seq2 = "NNNNNNN"; RollingHashIterator it2(seq2, numHashes, k); ASSERT_EQ(RollingHashIterator::end(), it2); } TEST(RollingHashIterator, seqShorterThanK) { const unsigned k = 5; const unsigned numHashes = 1; const char* seq = "ACGT"; RollingHashIterator it(seq, numHashes, k); ASSERT_EQ(RollingHashIterator::end(), it); } TEST(RollingHashIterator, emptySeq) { const unsigned k = 3; const unsigned numHashes = 1; const char* seq = ""; RollingHashIterator it(seq, numHashes, k); ASSERT_EQ(RollingHashIterator::end(), it); } TEST(RollingHashIterator, spacedSeed) { const unsigned k = 5; const unsigned numHashes = 1; const char* seq = "AGNNGC"; const char* rcSeq = "GCNNCT"; Kmer::setLength(k); MaskedKmer::setMask("10001"); /** hash forward sequence */ RollingHashIterator it(seq, numHashes, k); size_t kmer1Hash, kmer2Hash; kmer1Hash = (*it)[0]; ++it; kmer2Hash = (*it)[0]; ++it; ASSERT_EQ(RollingHashIterator::end(), it); /** hash reverse complement sequence */ RollingHashIterator rcIt(rcSeq, numHashes, k); size_t rcKmer1Hash, rcKmer2Hash; rcKmer2Hash = (*rcIt)[0]; ++rcIt; rcKmer1Hash = (*rcIt)[0]; ++rcIt; ASSERT_EQ(RollingHashIterator::end(), rcIt); /** check hash values are the same for forward and reverse complement */ ASSERT_EQ(kmer1Hash, rcKmer1Hash); ASSERT_EQ(kmer2Hash, rcKmer2Hash); } abyss-2.2.4/Unittest/BloomDBG/RollingHashTest.cpp000066400000000000000000000117741361462241400216370ustar00rootroot00000000000000#include "BloomDBG/RollingHash.h" #include #include #include #include "boost/dynamic_bitset.hpp" using namespace std; using namespace boost; /** test fixture for RollingHash tests */ class RollingHashTest : public ::testing::Test { protected: const unsigned m_numHashes; const unsigned m_k; const string m_kmerMask; RollingHashTest() : m_numHashes(2), m_k(4) { Kmer::setLength(m_k); } }; TEST_F(RollingHashTest, kmerMask) { MaskedKmer::setMask("1001"); RollingHash kmer1Hash("GCCG", m_numHashes, m_k); RollingHash kmer2Hash("GTTG", m_numHashes, m_k); ASSERT_EQ(kmer1Hash, kmer2Hash); } TEST_F(RollingHashTest, rollRight) { MaskedKmer::mask().clear(); RollingHash leftKmerHash("GACG", m_numHashes, m_k); RollingHash middleKmerHash("ACGT", m_numHashes, m_k); RollingHash rightKmerHash("CGTC", m_numHashes, m_k); leftKmerHash.rollRight("GACG", 'T'); ASSERT_EQ(middleKmerHash, leftKmerHash); leftKmerHash.rollRight("ACGT", 'C'); ASSERT_EQ(rightKmerHash, leftKmerHash); } TEST_F(RollingHashTest, rollRightMasked) { MaskedKmer::setMask("1001"); RollingHash leftKmerHash("GACG", m_numHashes, m_k); RollingHash middleKmerHash("ACGT", m_numHashes, m_k); RollingHash rightKmerHash("CGTC", m_numHashes, m_k); leftKmerHash.rollRight("GACG", 'T'); ASSERT_EQ(middleKmerHash, leftKmerHash); leftKmerHash.rollRight("ACGT", 'C'); ASSERT_EQ(rightKmerHash, leftKmerHash); } TEST_F(RollingHashTest, rollRightMaskedMismatch) { MaskedKmer::setMask("1001"); const char* origSeq = "GACGTC"; const char* mutatedSeq = "GACTTC"; RollingHash left(origSeq, m_numHashes, m_k); RollingHash middle(origSeq + 1, m_numHashes, m_k); RollingHash right(origSeq + 2, m_numHashes, m_k); RollingHash mutated(mutatedSeq, m_numHashes, m_k); ASSERT_NE(left, mutated); mutated.rollRight(mutatedSeq, 'T'); ASSERT_EQ(middle, mutated); mutated.rollRight(mutatedSeq + 1, 'C'); ASSERT_EQ(right, mutated); } TEST_F(RollingHashTest, rollLeft) { MaskedKmer::mask().clear(); RollingHash leftKmerHash("GACG", m_numHashes, m_k); RollingHash middleKmerHash("ACGT", m_numHashes, m_k); RollingHash rightKmerHash("CGTC", m_numHashes, m_k); rightKmerHash.rollLeft('A', "CGTC"); ASSERT_EQ(middleKmerHash, rightKmerHash); rightKmerHash.rollLeft('G', "ACGT"); ASSERT_EQ(leftKmerHash, rightKmerHash); } TEST_F(RollingHashTest, rollLeftMasked) { MaskedKmer::setMask("1001"); RollingHash leftKmerHash("GACG", m_numHashes, m_k); RollingHash middleKmerHash("ACGT", m_numHashes, m_k); RollingHash rightKmerHash("CGTC", m_numHashes, m_k); rightKmerHash.rollLeft('A', "CGTC"); ASSERT_EQ(middleKmerHash, rightKmerHash); rightKmerHash.rollLeft('G', "ACGT"); ASSERT_EQ(leftKmerHash, rightKmerHash); } TEST_F(RollingHashTest, rollLeftMaskedMismatch) { MaskedKmer::setMask("1001"); const char* origSeq = "GACGTC"; const char* mutatedSeq = "GAGGTC"; RollingHash left(origSeq, m_numHashes, m_k); RollingHash middle(origSeq + 1, m_numHashes, m_k); RollingHash right(origSeq + 2, m_numHashes, m_k); RollingHash mutated(mutatedSeq + 2, m_numHashes, m_k); ASSERT_NE(right, mutated); mutated.rollLeft('A', mutatedSeq + 2); ASSERT_EQ(middle, mutated); mutated.rollLeft('G', mutatedSeq + 1); ASSERT_EQ(left, mutated); } TEST_F(RollingHashTest, reset) { MaskedKmer::mask().clear(); RollingHash middleKmerHash("ACGT", m_numHashes, m_k); RollingHash rightKmerHash("CGTC", m_numHashes, m_k); middleKmerHash.reset("CGTC"); ASSERT_EQ(rightKmerHash, middleKmerHash); } TEST_F(RollingHashTest, resetMasked) { MaskedKmer::setMask("1001"); RollingHash middleKmerHash("ACGT", m_numHashes, m_k); RollingHash rightKmerHash("CGTC", m_numHashes, m_k); /* * Note: third base of middleKmerHash is intentionally set to 'G' * instead of 'T'. However, the hash values should * still match the rightKmerHash due to the effect of * the k-mer mask. */ middleKmerHash.reset("CGGC"); ASSERT_EQ(rightKmerHash, middleKmerHash); } TEST_F(RollingHashTest, setLastBase) { MaskedKmer::mask().clear(); char kmer1[] = "ACGT"; char kmer2[] = "ACGA"; char kmer3[] = "GCGT"; RollingHash hash1(kmer1, m_numHashes, m_k); RollingHash hash2(kmer2, m_numHashes, m_k); RollingHash hash3(kmer3, m_numHashes, m_k); ASSERT_NE(hash2, hash1); hash1.setLastBase(kmer1, SENSE, 'A'); ASSERT_EQ(hash2, hash1); hash1.reset(kmer1); ASSERT_NE(hash3, hash1); hash1.setLastBase(kmer1, ANTISENSE, 'G'); ASSERT_EQ(hash3, hash1); } TEST_F(RollingHashTest, reverseComplement) { MaskedKmer::mask().clear(); const RollingHash leftKmerHash("GACG", m_numHashes, m_k); const RollingHash middleKmerHash("ACGT", m_numHashes, m_k); const RollingHash rightKmerHash("CGTC", m_numHashes, m_k); RollingHash hash(rightKmerHash); /* * NOTE: after we call `reverseComplement`, the `rollRight` * and `rollLeft` operations are swapped. */ ASSERT_EQ(rightKmerHash, hash); hash.reverseComplement(); /* CGTC => GACG */ ASSERT_EQ(rightKmerHash, hash); hash.rollRight("GACG", 'T'); ASSERT_EQ(middleKmerHash, hash); hash.rollRight("ACGT", 'C'); ASSERT_EQ(leftKmerHash, hash); } abyss-2.2.4/Unittest/BloomDBG/SpacedSeedTest.cpp000066400000000000000000000012431361462241400214130ustar00rootroot00000000000000#include "BloomDBG/SpacedSeed.h" #include using namespace std; TEST(SpacedSeedTest, qrSeed) { /* * Generate a Quadratic Residue (QR) seed. The background theory * for QR seeds is described in: * * Egidi, Lavinia, and Giovanni Manzini. "Multiple seeds * sensitivity using a single seed with threshold." Journal of * bioinformatics and computational biology 13.04 (2015): 1550011. */ ASSERT_EQ("10100011101", SpacedSeed::qrSeed(11)); } TEST(SpacedSeedTest, qrSeedPair) { /* * Generate spaced seed pattern for two mirrored QR seeds with * a gap in between. */ ASSERT_EQ("101000111010000000000010111000101", SpacedSeed::qrSeedPair(33,11)); } abyss-2.2.4/Unittest/Common/000077500000000000000000000000001361462241400157125ustar00rootroot00000000000000abyss-2.2.4/Unittest/Common/BitUtilTest.cpp000066400000000000000000000153111361462241400206330ustar00rootroot00000000000000#include "Common/BitUtil.h" #include "gtest/gtest.h" #include /** Test limits */ TEST(popcountTest, boundaries) { EXPECT_EQ(64ULL, popcount(0xffffffffffffffffULL)); EXPECT_EQ(0ULL, popcount(0ULL)); } /** Test some random values */ TEST(popcountTest, random_values) { EXPECT_EQ(45ULL, popcount(0x992E54FFFFFFFBA1ULL)); 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]); } abyss-2.2.4/Unittest/Common/HistogramTest.cpp000066400000000000000000000020411361462241400212100ustar00rootroot00000000000000#include "Common/Histogram.h" #include "gtest/gtest.h" // test Histogram.empty() TEST(emptyTest, base_cases) { Histogram hi; EXPECT_TRUE(hi.empty()); hi.insert(2); EXPECT_FALSE(hi.empty()); hi.insert(4); EXPECT_FALSE(hi.empty()); } // test Histogram.count() TEST(countTest, non_negative_cases) { Histogram hi; hi.insert(2); hi.insert(4); EXPECT_EQ(hi.size(), (unsigned)2); hi.insert(6); hi.insert(8); hi.insert(10, 5); EXPECT_EQ(hi.size(), (unsigned)9); EXPECT_EQ(hi.count(INT_MIN, INT_MAX), (unsigned)9); EXPECT_EQ(hi.count(8, 10), (unsigned)6); hi.insert(12); EXPECT_EQ(hi.size(), (unsigned)10); EXPECT_EQ(hi.count(INT_MIN, INT_MAX), (unsigned)10); } // test Histogram.sum() TEST(sumTest, trivial_cases) { Histogram hello; EXPECT_EQ(hello.sum(), (unsigned)0); } // test Histogram.removeNoise() TEST(removeNoise, one_entry) { Histogram hi; hi.insert(10, 5); EXPECT_EQ(hi.size(), 5u); hi.removeNoise(); EXPECT_EQ(hi.size(), 5u); hi.insert(20, 10); EXPECT_EQ(hi.size(), 15u); hi.removeNoise(); EXPECT_EQ(hi.size(), 10u); } abyss-2.2.4/Unittest/Common/KmerIteratorTest.cpp000066400000000000000000000015451361462241400216730ustar00rootroot00000000000000#include "Common/KmerIterator.h" #include TEST(KmerIteratorTest, NoIllegalChars) { unsigned k = 3; Kmer::setLength(k); KmerIterator i("AGCTA", k); ASSERT_EQ(Kmer("AGC"), *i); i++; ASSERT_EQ(Kmer("GCT"), *i); i++; ASSERT_EQ(Kmer("CTA"), *i); i++; ASSERT_EQ(KmerIterator::end(), i); } TEST(KmerIteratorTest, IllegalChars) { unsigned k = 3; Kmer::setLength(k); KmerIterator i("AGCTNTAG", k); ASSERT_EQ(Kmer("AGC"), *i); i++; ASSERT_EQ(Kmer("GCT"), *i); i++; ASSERT_EQ(Kmer("TAG"), *i); i++; ASSERT_EQ(KmerIterator::end(), i); } TEST(KmerIteratorTest, SeqLengthOneLessThanK) { unsigned k = 3; Kmer::setLength(k); KmerIterator i("AG", k); ASSERT_EQ(KmerIterator::end(), i); } TEST(KmerIteratorTest, SeqLengthMuchLessThanK) { unsigned k = 10; Kmer::setLength(k); KmerIterator i("AG", k); ASSERT_EQ(KmerIterator::end(), i); } abyss-2.2.4/Unittest/Common/KmerTest.cpp000066400000000000000000000011131361462241400201500ustar00rootroot00000000000000#include "Common/Kmer.h" #include #include TEST(Kmer, canonicalize) { Kmer::setLength(4); Kmer canonical("ATGC"); Kmer nonCanonical("GCAT"); Kmer palindrome("ACGT"); Kmer kmer = canonical; kmer.canonicalize(); EXPECT_EQ(canonical, kmer); kmer = nonCanonical; kmer.canonicalize(); EXPECT_EQ(canonical, kmer); kmer = palindrome; kmer.canonicalize(); EXPECT_EQ(palindrome, kmer); Kmer::setLength(5); Kmer oddLength("GCTCG"); Kmer oddLengthCanonical("CGAGC"); kmer = oddLength; kmer.canonicalize(); EXPECT_EQ(oddLengthCanonical, kmer); } abyss-2.2.4/Unittest/Common/SAM.cc000066400000000000000000000032741361462241400166470ustar00rootroot00000000000000#include "Common/SAM.h" #include /** Verify SAM records are stored and used correctly */ using namespace std; /** @Return whether two Alignments are equivalent. */ bool operator==(const Alignment& a, const Alignment& b) { return a.read_start_pos == b.read_start_pos && a.align_length == b.align_length && a.read_length == b.read_length; } // Test SAM::parseCigar() TEST(parseCigar, check_alignment) { Alignment a; a.align_length = 40; a.read_start_pos = 0; a.read_length = 40; EXPECT_EQ(a, SAMAlignment::parseCigar("40M", false)); a.align_length = 40; a.read_start_pos = 20; a.read_length = 60; EXPECT_EQ(a, SAMAlignment::parseCigar("20S40M", false)); a.align_length = 40; a.read_start_pos = 0; a.read_length = 60; EXPECT_EQ(a, SAMAlignment::parseCigar("40M20S", false)); EXPECT_EQ(a, SAMAlignment::parseCigar("20S40M", true)); a.align_length = 40; a.read_start_pos = 20; a.read_length = 70; EXPECT_EQ(a, SAMAlignment::parseCigar("20S40M10S", false)); EXPECT_EQ(a, SAMAlignment::parseCigar("10S40M20S", true)); a.align_length = 40; a.read_start_pos = 20; a.read_length = 70; EXPECT_EQ(a, SAMAlignment::parseCigar("20I40M10S", false)); a.align_length = 40; a.read_start_pos = 30; a.read_length = 80; EXPECT_EQ(a, SAMAlignment::parseCigar("20M10I40M10S", false)); a.align_length = 40; a.read_start_pos = 0; a.read_length = 80; EXPECT_EQ(a, SAMAlignment::parseCigar("40M10I20M10S", false)); } // Check that we error when an invalid CIGAR is given. TEST(parseCigarDeath, invalid_cigar) { EXPECT_DEATH(SAMAlignment::parseCigar("20SS", false), "error: invalid CIGAR: `20SS'"); EXPECT_DEATH(SAMAlignment::parseCigar("20m", false), "error: invalid CIGAR: `20m'"); } abyss-2.2.4/Unittest/Common/Sequence.cc000066400000000000000000000005231361462241400177710ustar00rootroot00000000000000#include "Common/Sequence.h" #include using namespace std; TEST(reverseComplement, base) { string s = "AGATGTGCTGCCGCCTTGGACAGCGTTACCTCTAATAACAGTCCCTATGA"; string rc = "TCATAGGGACTGTTATTAGAGGTAACGCTGTCCAAGGCGGCAGCACATCT"; EXPECT_EQ(reverseComplement(s), rc); EXPECT_EQ(reverseComplement(reverseComplement(s)), s); } abyss-2.2.4/Unittest/Common/StringUtilTest.cpp000066400000000000000000000110401361462241400213560ustar00rootroot00000000000000#include "Common/StringUtil.h" #include "gtest/gtest.h" using namespace std; TEST(chop_test, base_case_2) { string myString = "me"; EXPECT_EQ((unsigned)2, myString.length()); EXPECT_EQ('e', chop(myString)); EXPECT_EQ((unsigned)1, myString.length()); } TEST(chop_test, trivial_gt_length2) { string myString = "something"; EXPECT_EQ((unsigned)9, myString.length()); EXPECT_EQ('g', chop(myString)); EXPECT_EQ((unsigned)8, myString.length()); EXPECT_EQ('n', chop(myString)); EXPECT_EQ((unsigned)7, myString.length()); } TEST(chomp_test, base_cases) { // test .length=1 string myString = "a"; EXPECT_TRUE(1 == myString.length()); EXPECT_FALSE(chomp(myString)); string anotherString = "\n"; EXPECT_TRUE(1 == anotherString.length()); EXPECT_TRUE(chomp(anotherString)); // test .length=2 string greatString = "ab"; EXPECT_FALSE(chomp(greatString)); EXPECT_EQ((unsigned)2, greatString.length()); string badString = "a\n"; EXPECT_TRUE(chomp(badString)); EXPECT_EQ((unsigned)1, badString.length()); } TEST(toSI_test, all_the_cases) { // negative and zero values EXPECT_EQ ("-0.000123 ", toSI(-0.0001234)); EXPECT_EQ("1e-13 ", toSI(0.0000000000001)); EXPECT_EQ("-1.2e-13 ", toSI(-0.00000000000012)); EXPECT_EQ("-1.23e-13 ", toSI(-0.000000000000123456)); EXPECT_EQ("0 ", toSI(0)); EXPECT_EQ("-0 ", toSI(-0.000)); //trivially all posible values EXPECT_EQ("1.23 k", toSI(1234)); EXPECT_EQ("123 M", toSI(123440111)); EXPECT_EQ("23.4 M", toSI(23440111)); EXPECT_EQ("1.23 G", toSI(1234123123)); EXPECT_EQ("123 G", toSI(123440111222)); 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 class MultiTypes{ public: T myVar; void type_int() { ::testing::StaticAssertTypeEq(); } void type_double() { ::testing::StaticAssertTypeEq(); } void type_string() { ::testing::StaticAssertTypeEq(); } }; TEST(toEng_test, integer_cases) { EXPECT_EQ("1234", toEng(1234)); MultiTypes temp; temp.type_int(); temp.myVar = 1234; EXPECT_EQ(temp.myVar, 1234); EXPECT_EQ("1234", toEng(temp.myVar)); temp.myVar = 12345678; EXPECT_EQ("12.35e6", toEng(temp.myVar)); temp.myVar = 123456789; EXPECT_EQ ("123.5e6" , toEng(temp.myVar)); } TEST(toEng_test, double_cases) { MultiTypes temp; temp.type_double(); temp.myVar = 123.456; EXPECT_EQ (temp.myVar, 123.456); EXPECT_EQ ("123.5", toEng(temp.myVar)); temp.myVar = 123456789.9; EXPECT_EQ ("123.5e6", toEng(temp.myVar)); } TEST(toEng_test, string_cases) { MultiTypes temp; temp.type_string(); temp.myVar = "123.456"; } TEST (startsWith_test, trivial_cases) { EXPECT_TRUE (startsWith("hello", "hell")); EXPECT_TRUE (startsWith("hello", "h")); EXPECT_FALSE (startsWith("hello", "hello")); EXPECT_TRUE (startsWith("hello", "")); EXPECT_FALSE (startsWith ("whatever", "who")); } TEST(endsWith_test, any_cases) { // suffix should not be the string itself EXPECT_FALSE(endsWith("hello", "hello")); EXPECT_FALSE(endsWith("", "")); EXPECT_TRUE(endsWith("hello", "")); // EXPECT_FALSE(endsWith("hello", NULL)); // NULL is not valid EXPECT_TRUE(endsWith("hello", "ello")); EXPECT_TRUE(endsWith("hello", "o")); EXPECT_FALSE(endsWith("hell", "hello")); EXPECT_FALSE(endsWith("hell", "heaven")); } TEST(SIToBytes_test, unit_conversions) { EXPECT_EQ(1024u, SIToBytes("1024")); EXPECT_EQ(1024u, SIToBytes("1k")); EXPECT_EQ(1536u, SIToBytes("1.5k")); EXPECT_EQ(1048576u, SIToBytes("1M")); EXPECT_EQ(1073741824u, SIToBytes("1G")); } TEST(SIToBytes_test, error_handling) { unsigned long long bytes; // non-number istringstream nonNumber("not-a-number"); bytes = SIToBytes(nonNumber); EXPECT_EQ(0u, bytes); EXPECT_TRUE(nonNumber.fail()); // unrecognized suffix istringstream illegalUnits("1024y"); bytes = SIToBytes(nonNumber); EXPECT_EQ(0u, bytes); EXPECT_TRUE(nonNumber.fail()); // valid string should set eof istringstream valid("500M"); bytes = SIToBytes(valid); EXPECT_EQ(524288000u, bytes); EXPECT_TRUE(valid.eof()); } abyss-2.2.4/Unittest/DBG/000077500000000000000000000000001361462241400150565ustar00rootroot00000000000000abyss-2.2.4/Unittest/DBG/LoadAlgorithmTest.cpp000066400000000000000000000016761361462241400211620ustar00rootroot00000000000000#include "config.h" #include "Assembly/SequenceCollection.h" #include "Assembly/DBG.h" #include "Assembly/AssemblyAlgorithms.h" #include "Assembly/Options.h" #include "Common/UnorderedSet.h" #include #include #include 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 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()); } abyss-2.2.4/Unittest/Graph/000077500000000000000000000000001361462241400155235ustar00rootroot00000000000000abyss-2.2.4/Unittest/Graph/AllPathsSearchTest.cpp000066400000000000000000000122341361462241400217270ustar00rootroot00000000000000#include "Graph/Path.h" #include "Graph/AllPathsSearch.h" #include "Common/UnorderedMap.h" #include #include #include using namespace std; typedef boost::adjacency_list Graph; // note: vertex_descriptor for adjacency_list<> is int typedef boost::graph_traits::vertex_descriptor Vertex; // note: edge_descriptor for adjacency_list<> is int typedef boost::graph_traits::edge_descriptor Edge; namespace { class AllPathsSearchTest : public ::testing::Test { protected: Graph disconnectedGraph; Graph simpleAcyclicGraph; Graph simpleCyclicGraph; Graph multiPathGraph; AllPathsSearchTest() { add_edge(0, 1, disconnectedGraph); add_vertex(disconnectedGraph); add_edge(0, 1, simpleAcyclicGraph); add_edge(0, 2, simpleAcyclicGraph); add_edge(2, 3, simpleAcyclicGraph); add_edge(0, 1, simpleCyclicGraph); add_edge(0, 4, simpleCyclicGraph); add_edge(1, 2, simpleCyclicGraph); add_edge(2, 1, simpleCyclicGraph); add_edge(1, 3, simpleCyclicGraph); add_edge(0, 1, multiPathGraph); add_edge(1, 2, multiPathGraph); add_edge(1, 3, multiPathGraph); add_edge(2, 3, multiPathGraph); add_edge(3, 4, multiPathGraph); add_edge(3, 5, multiPathGraph); add_edge(4, 5, multiPathGraph); add_edge(5, 6, multiPathGraph); } }; TEST_F(AllPathsSearchTest, UnreachableGoal) { AllPathsSearchResult result = allPathsSearch(disconnectedGraph, 0, 2); EXPECT_EQ(NO_PATH, result.resultCode); EXPECT_TRUE(result.paths.empty()); } TEST_F(AllPathsSearchTest, StartNodeEqualsGoal) { AllPathsSearchResult result = allPathsSearch(simpleAcyclicGraph, 0, 0); EXPECT_EQ(FOUND_PATH, result.resultCode); ASSERT_EQ(1u, result.paths.size()); ASSERT_EQ("0", result.paths[0].str()); } TEST_F(AllPathsSearchTest, SinglePath) { AllPathsSearchResult result = allPathsSearch(simpleAcyclicGraph, 0, 3, 1, 2, 2, NO_LIMIT); EXPECT_EQ(FOUND_PATH, result.resultCode); ASSERT_EQ(1u, result.paths.size()); ASSERT_EQ("0,2,3", result.paths[0].str()); } TEST_F(AllPathsSearchTest, MultiPathGraph) { AllPathsSearchResult result = allPathsSearch(multiPathGraph, 0, 6, 4, 4, 6, NO_LIMIT); set expectedPaths; expectedPaths.insert("0,1,3,5,6"); expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); expectedPaths.insert("0,1,2,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result.resultCode); ASSERT_EQ(4u, result.paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 4; i++) ASSERT_TRUE(expectedPaths.find(result.paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(result.paths[i].str() != result.paths[i+1].str()); } TEST_F(AllPathsSearchTest, RespectsMaxPathsLimit) { AllPathsSearchResult result = allPathsSearch(multiPathGraph, 0, 6, 3, NO_LIMIT, NO_LIMIT, NO_LIMIT); EXPECT_EQ(TOO_MANY_PATHS, result.resultCode); } TEST_F(AllPathsSearchTest, RespectsMaxDepthLimit) { AllPathsSearchResult result = allPathsSearch(multiPathGraph, 0, 6, 4, 4, 5, NO_LIMIT); // We expect the fourth path ("0,1,2,3,4,5,6") // to be excluded by the max depth limit. Note that // the depth of the start node is 0, and so a // path of length 7 reaches depth 6. set expectedPaths; expectedPaths.insert("0,1,3,5,6"); expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result.resultCode); ASSERT_EQ(3u, result.paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(expectedPaths.find(result.paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 2; i++) ASSERT_TRUE(result.paths[i].str() != result.paths[i+1].str()); } TEST_F(AllPathsSearchTest, RespectsMinDepthLimit) { AllPathsSearchResult result = allPathsSearch(multiPathGraph, 0, 6, 4, 5, 6, NO_LIMIT); // We expect the shortest path ("0,1,3,4,6") // to be excluded by the min depth limit. Note that // the depth of the start node is 0, and so a // path of length 5 reaches depth 4. set expectedPaths; expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); expectedPaths.insert("0,1,2,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result.resultCode); ASSERT_EQ(3u, result.paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(expectedPaths.find(result.paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 2; i++) ASSERT_TRUE(result.paths[i].str() != result.paths[i+1].str()); } TEST_F(AllPathsSearchTest, PathContainsCycle) { AllPathsSearchResult result = allPathsSearch(simpleCyclicGraph, 0, 3, NO_LIMIT, 0, NO_LIMIT, NO_LIMIT); EXPECT_EQ(PATH_CONTAINS_CYCLE, result.resultCode); } TEST_F(AllPathsSearchTest, IgnoreCycleNotOnPath) { AllPathsSearchResult result = allPathsSearch(simpleCyclicGraph, 0, 4, NO_LIMIT, 0, NO_LIMIT, NO_LIMIT); EXPECT_EQ(FOUND_PATH, result.resultCode); ASSERT_EQ(1u, result.paths.size()); ASSERT_EQ("0,4", result.paths.front().str()); } } abyss-2.2.4/Unittest/Graph/BidirectionalBFSTest.cpp000066400000000000000000000074661361462241400222070ustar00rootroot00000000000000#include "Graph/Path.h" #include "Graph/BidirectionalBFS.h" #include "Graph/BidirectionalBFSVisitor.h" #include "Common/UnorderedMap.h" #include #include using namespace std; static const bool DEBUG = false; typedef boost::adjacency_list Graph; // note: vertex_descriptor for adjacency_list<> is int typedef boost::graph_traits::vertex_descriptor Vertex; // note: edge_descriptor for adjacency_list<> is int typedef boost::graph_traits::edge_descriptor Edge; class TestVisitor : public BidirectionalBFSVisitor { public: typedef unordered_map DirMap; typedef unordered_map RankMap; typedef vector EdgeList; DirMap dirMap; RankMap rankMap; EdgeList commonEdges; int rank; TestVisitor() : rank(0) { } BFSVisitorResult discover_vertex(const Vertex& u, const Graph&, Direction dir, unsigned) { if (DEBUG) cerr << dir << ": discover_vertex " << u << "\n"; return SUCCESS; } void examine_vertex(const Vertex& u, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": examine_vertex " << u << "\n"; dirMap[u] = dir; rankMap[u] = rank++; } void examine_edge(const Edge& e, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": examine_edge " << e << "\n"; } BFSVisitorResult tree_edge(const Edge& e, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": tree_edge " << e << "\n"; return SUCCESS; } BFSVisitorResult common_edge(const Edge& e, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": common_edge " << e << "\n"; commonEdges.push_back(e); return SUCCESS; } BFSVisitorResult non_tree_edge(const Edge& e, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": non_tree_edge " << e << "\n"; commonEdges.push_back(e); return SUCCESS; } void gray_target(const Edge& e, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": gray_target " << e << "\n"; } void black_target(const Edge& e, const Graph&, Direction dir) { if (DEBUG) cerr << dir << ": black_target " << e << "\n"; } }; namespace { class BidirectionalBFSTest : public ::testing::Test { protected: Graph linearGraph; Graph branchingGraph; BidirectionalBFSTest() { add_edge(0, 1, linearGraph); add_edge(1, 2, linearGraph); add_edge(2, 3, linearGraph); add_edge(0, 1, branchingGraph); add_edge(0, 2, branchingGraph); add_edge(1, 3, branchingGraph); add_edge(3, 4, branchingGraph); add_edge(4, 6, branchingGraph); add_edge(5, 6, branchingGraph); } }; TEST_F(BidirectionalBFSTest, AlternatesDirection) { TestVisitor visitor; bidirectionalBFS(linearGraph, 0, 3, visitor); TestVisitor::DirMap& dir = visitor.dirMap; ASSERT_EQ(dir[0], FORWARD); ASSERT_EQ(dir[3], REVERSE); ASSERT_EQ(dir[1], FORWARD); ASSERT_EQ(dir[2], REVERSE); } TEST_F(BidirectionalBFSTest, FollowsBreadthFirstOrder) { TestVisitor visitor; bidirectionalBFS(branchingGraph, 0, 6, visitor); TestVisitor::RankMap& rank = visitor.rankMap; ASSERT_TRUE(rank[1] > rank[0]); ASSERT_TRUE(rank[2] > rank[0]); ASSERT_TRUE(rank[3] > rank[1]); ASSERT_TRUE(rank[3] > rank[2]); ASSERT_TRUE(rank[3] > rank[4]); ASSERT_TRUE(rank[3] > rank[5]); ASSERT_TRUE(rank[4] > rank[6]); ASSERT_TRUE(rank[5] > rank[6]); } TEST_F(BidirectionalBFSTest, IdentifiesCommonEdge) { TestVisitor visitor; bidirectionalBFS(linearGraph, 0, 3, visitor); TestVisitor::EdgeList& commonEdges = visitor.commonEdges; // Note: Each common edge is visited twice. It is // visited once by the forward traversal and once // by the reverse traversal. ASSERT_TRUE(commonEdges.size() == 2); ASSERT_TRUE(commonEdges[0] == commonEdges[1]); ASSERT_TRUE(source(commonEdges[0], linearGraph) == 1u); ASSERT_TRUE(target(commonEdges[0], linearGraph) == 2u); } } abyss-2.2.4/Unittest/Graph/ConstrainedBFSVisitorTest.cpp000066400000000000000000000073701361462241400232620ustar00rootroot00000000000000#include "Graph/Path.h" #include "Graph/BreadthFirstSearch.h" #include "Graph/ConstrainedBFSVisitor.h" #include "Graph/DefaultColorMap.h" #include #include #include using namespace std; using namespace boost; typedef adjacency_list Graph; typedef graph_traits::vertex_descriptor V; typedef std::vector< Path > PathList; namespace { class ConstrainedBFSVisitorTest : public ::testing::Test { protected: Graph simpleAcyclicGraph; Graph simpleCyclicGraph; ConstrainedBFSVisitorTest() { add_edge(0, 1, simpleAcyclicGraph); add_edge(0, 2, simpleAcyclicGraph); add_edge(2, 3, simpleAcyclicGraph); add_edge(0, 1, simpleCyclicGraph); add_edge(1, 3, simpleCyclicGraph); add_edge(0, 2, simpleCyclicGraph); add_edge(2, 3, simpleCyclicGraph); } }; TEST_F(ConstrainedBFSVisitorTest, IdentifyUniquePath) { int start = 0; int goal = 3; int minDepth = 0; int maxDepth = 2; int maxBranches = 3; DefaultColorMap colorMap; ConstrainedBFSVisitor visitor(start, goal, minDepth, maxDepth, maxBranches, colorMap); breadthFirstSearch(start, simpleAcyclicGraph, colorMap, visitor); AllPathsSearchResult result = visitor.uniquePathToGoal(); ASSERT_EQ(result.resultCode, FOUND_PATH); ASSERT_EQ(result.paths.size(), 1u); ASSERT_EQ(result.paths.at(0).str(), "0,2,3"); } TEST_F(ConstrainedBFSVisitorTest, RespectMaxDepthLimit) { int start = 0; int goal = 3; int minDepth = 0; int maxDepth = 1; int maxBranches = 3; DefaultColorMap colorMap; ConstrainedBFSVisitor visitor(start, goal, minDepth, maxDepth, maxBranches, colorMap); breadthFirstSearch(start, simpleAcyclicGraph, colorMap, visitor); EXPECT_EQ(visitor.getMaxDepthVisited(), 1); EXPECT_EQ(visitor.uniquePathToGoal().resultCode, NO_PATH); } TEST_F(ConstrainedBFSVisitorTest, RespectMinDepthLimit) { int start = 0; int goal = 3; int minDepth = 3; int maxDepth = 10; int maxBranches = 3; DefaultColorMap colorMap; ConstrainedBFSVisitor visitor(start, goal, minDepth, maxDepth, maxBranches, colorMap); breadthFirstSearch(start, simpleAcyclicGraph, colorMap, visitor); EXPECT_EQ(visitor.uniquePathToGoal().resultCode, NO_PATH); } TEST_F(ConstrainedBFSVisitorTest, IdentifyMultiplePaths) { int start = 0; int goal = 3; int minDepth = 0; int maxDepth = 3; int maxBranches = 3; DefaultColorMap colorMap; ConstrainedBFSVisitor visitor(start, goal, minDepth, maxDepth, maxBranches, colorMap); breadthFirstSearch(start, simpleCyclicGraph, colorMap, visitor); EXPECT_EQ(visitor.uniquePathToGoal().resultCode, TOO_MANY_PATHS); } TEST_F(ConstrainedBFSVisitorTest, ReturnMultiplePaths) { int start = 0; int goal = 3; int minDepth = 0; int maxDepth = 3; int maxBranches = 3; DefaultColorMap colorMap; ConstrainedBFSVisitor visitor(start, goal, minDepth, maxDepth, maxBranches, colorMap); breadthFirstSearch(start, simpleCyclicGraph, colorMap, visitor); AllPathsSearchResult result = visitor.pathsToGoal(2); EXPECT_EQ(result.resultCode, FOUND_PATH); ASSERT_EQ(result.paths.size(), 2u); string path1 = result.paths[0].str(); string path2 = result.paths[1].str(); EXPECT_TRUE(path1 != path2); ASSERT_TRUE(path1 == "0,1,3" || path1 == "0,2,3"); ASSERT_TRUE(path2 == "0,1,3" || path2 == "0,2,3"); } TEST_F(ConstrainedBFSVisitorTest, RespectBranchLimit) { int start = 0; int goal = 3; int minDepth = 0; int maxDepth = 3; int maxBranches = 1; DefaultColorMap colorMap; ConstrainedBFSVisitor visitor(start, goal, minDepth, maxDepth, maxBranches, colorMap); breadthFirstSearch(start, simpleAcyclicGraph, colorMap, visitor); EXPECT_EQ(visitor.uniquePathToGoal().resultCode, TOO_MANY_BRANCHES); } } abyss-2.2.4/Unittest/Graph/ConstrainedBidiBFSVisitorTest.cpp000066400000000000000000000137071361462241400240530ustar00rootroot00000000000000#include "Graph/Path.h" #include "Graph/ConstrainedBidiBFSVisitor.h" #include "Graph/BidirectionalBFS.h" #include #include #include #include using namespace std; using namespace boost; typedef adjacency_list Graph; typedef graph_traits::vertex_descriptor V; typedef graph_traits::edge_descriptor e; typedef std::vector< Path > PathList; static const size_t NO_MEM_LIMIT = std::numeric_limits::max(); namespace { class ConstrainedBidiBFSVisitorTest : public ::testing::Test { protected: Graph simpleAcyclicGraph; Graph simpleCyclicGraph; Graph cyclicGraph; ConstrainedBidiBFSVisitorTest() { add_edge(0, 1, simpleAcyclicGraph); add_edge(0, 2, simpleAcyclicGraph); add_edge(2, 3, simpleAcyclicGraph); add_edge(0, 1, simpleCyclicGraph); add_edge(1, 3, simpleCyclicGraph); add_edge(0, 2, simpleCyclicGraph); add_edge(2, 3, simpleCyclicGraph); add_edge(0, 1, cyclicGraph); add_edge(1, 2, cyclicGraph); add_edge(1, 3, cyclicGraph); add_edge(2, 3, cyclicGraph); add_edge(3, 4, cyclicGraph); add_edge(3, 5, cyclicGraph); add_edge(4, 5, cyclicGraph); add_edge(5, 6, cyclicGraph); } }; TEST_F(ConstrainedBidiBFSVisitorTest, IdentifyUniquePath) { ConstrainedBidiBFSVisitor visitor(simpleAcyclicGraph, 0, 3, 1, 1, 3, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleAcyclicGraph, 0, 3, visitor); Path uniquePath; PathSearchResult result = visitor.uniquePathToGoal(uniquePath); ASSERT_EQ(FOUND_PATH, result); ASSERT_EQ("0,2,3", uniquePath.str()); } TEST_F(ConstrainedBidiBFSVisitorTest, StartEqualsGoal) { ConstrainedBidiBFSVisitor visitor(simpleAcyclicGraph, 0, 0, 1, 1, 1, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleAcyclicGraph, 0, 0, visitor); Path uniquePath; PathSearchResult result = visitor.uniquePathToGoal(uniquePath); ASSERT_EQ(FOUND_PATH, result); ASSERT_EQ("0", uniquePath.str()); } TEST_F(ConstrainedBidiBFSVisitorTest, SingleEdgeToGoal) { ConstrainedBidiBFSVisitor visitor(simpleAcyclicGraph, 0, 1, 1, 1, 2, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleAcyclicGraph, 0, 1, visitor); Path uniquePath; PathSearchResult result = visitor.uniquePathToGoal(uniquePath); ASSERT_EQ(FOUND_PATH, result); ASSERT_EQ("0,1", uniquePath.str()); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMaxPathLength) { ConstrainedBidiBFSVisitor visitor(cyclicGraph, 0, 6, 4, 5, 6, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(cyclicGraph, 0, 6, visitor); vector< Path > paths; PathSearchResult result = visitor.pathsToGoal(paths); // We expect the fourth path ("0,1,2,3,4,5,6") // to be excluded by the max path length limit (6). set expectedPaths; expectedPaths.insert("0,1,3,5,6"); expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(3u, paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(expectedPaths.find(paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 2; i++) ASSERT_TRUE(paths[i].str() != paths[i+1].str()); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMinPathLength) { ConstrainedBidiBFSVisitor visitor(cyclicGraph, 0, 6, 4, 6, 7, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(cyclicGraph, 0, 6, visitor); vector< Path > paths; PathSearchResult result = visitor.pathsToGoal(paths); // We expect the first path ("0,1,3,5,6") // to be excluded by the min path length limit (6). set expectedPaths; expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); expectedPaths.insert("0,1,2,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(3u, paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(expectedPaths.find(paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 2; i++) ASSERT_TRUE(paths[i].str() != paths[i+1].str()); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMaxPathsLimit) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 1, 1, 3, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); Path uniquePath; EXPECT_EQ(visitor.uniquePathToGoal(uniquePath), TOO_MANY_PATHS); } TEST_F(ConstrainedBidiBFSVisitorTest, ReturnMultiplePaths) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 2, 1, 3, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); PathList paths; PathSearchResult result = visitor.pathsToGoal(paths); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(2u, paths.size()); string path1 = paths[0].str(); string path2 = paths[1].str(); EXPECT_TRUE(path1 != path2); ASSERT_TRUE(path1 == "0,1,3" || path1 == "0,2,3"); ASSERT_TRUE(path2 == "0,1,3" || path2 == "0,2,3"); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMaxBranches) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 2, 1, 3, 1, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); PathList paths; PathSearchResult result = visitor.pathsToGoal(paths); EXPECT_EQ(TOO_MANY_BRANCHES, result); EXPECT_EQ(0u, paths.size()); // expect early exit from traversal EXPECT_EQ(3u, visitor.getNumNodesVisited()); } TEST_F(ConstrainedBidiBFSVisitorTest, NoLimitForBranches) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 2, 1, 3, NO_LIMIT, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); PathList paths; PathSearchResult result = visitor.pathsToGoal(paths); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(2u, paths.size()); string path1 = paths[0].str(); string path2 = paths[1].str(); EXPECT_TRUE(path1 != path2); ASSERT_TRUE(path1 == "0,1,3" || path1 == "0,2,3"); ASSERT_TRUE(path2 == "0,1,3" || path2 == "0,2,3"); } } abyss-2.2.4/Unittest/Graph/DotIOTest.cpp000066400000000000000000000010161361462241400200430ustar00rootroot00000000000000#include "Graph/GraphIO.h" #include "Graph/DotIO.h" #include "Graph/UndirectedGraph.h" #include "Graph/Properties.h" #include #include #include using namespace std; TEST(DotIOTest, read_dot) { string undirectedGraph = "graph {\n" " \"a\";\n" " \"b\";\n" " \"a\" -- \"b\";\n" "}\n"; stringstream ss; ss << undirectedGraph; ASSERT_TRUE(ss.good()); UndirectedGraph g; read_dot(ss, g, DisallowParallelEdges()); ASSERT_TRUE(!ss.fail()); } abyss-2.2.4/Unittest/Graph/ExtendPathTest.cpp000066400000000000000000000204041361462241400211330ustar00rootroot00000000000000#include "Graph/Path.h" #include "Graph/ExtendPath.h" #include #include using namespace std; typedef boost::adjacency_list Graph; // note: vertex_descriptor for adjacency_list<> is int typedef boost::graph_traits::vertex_descriptor Vertex; // note: edge_descriptor for adjacency_list<> is int typedef boost::graph_traits::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, depth) { /* * 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); /* note: depth of starting node is 0 */ ASSERT_EQ(3u, depth(0, FORWARD, g)); ASSERT_EQ(2u, depth(1, FORWARD, g)); ASSERT_EQ(3u, depth(4, REVERSE, g)); ASSERT_EQ(1u, depth(1, REVERSE, g)); } TEST(extendPath, longestBranch) { /* * 2 * / * 0--1 * \ * 3--4 * / * 5 */ Graph g; add_edge(0, 1, g); add_edge(1, 2, g); add_edge(1, 3, g); add_edge(3, 4, g); add_edge(5, 3, g); ASSERT_EQ(1u, longestBranch(0, FORWARD, g).first); ASSERT_EQ(3u, longestBranch(1, FORWARD, g).first); ASSERT_EQ(1u, longestBranch(3, REVERSE, g).first); ASSERT_EQ(3u, longestBranch(4, REVERSE, g).first); } TEST(extendPath, noExtension) { // Graph containing a single edge. Graph g; add_edge(0, 1, g); Path 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 expectedPath; expectedPath.push_back(0); expectedPath.push_back(1); Path 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 expectedPath; expectedPath.push_back(2); expectedPath.push_back(3); Path 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 expectedPath; expectedPath.push_back(2); expectedPath.push_back(3); expectedPath.push_back(4); Path 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) { ExtendPathParams params; params.trimLen = 1; params.fpTrim = 0; /* * 3 * / * 0--1--2--4--5 */ Graph g; add_edge(0, 1, g); add_edge(1, 2, g); add_edge(2, 3, g); add_edge(2, 4, g); add_edge(4, 5, g); Path expectedPath; expectedPath.push_back(0); expectedPath.push_back(1); expectedPath.push_back(2); expectedPath.push_back(4); expectedPath.push_back(5); Path pathFwd; pathFwd.push_back(0); extendPath(pathFwd, FORWARD, g, params); ASSERT_EQ(expectedPath, pathFwd); Path pathRev; pathRev.push_back(5); extendPath(pathRev, REVERSE, g, params); ASSERT_EQ(expectedPath, pathRev); /* * 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 path2; path2.push_back(0); extendPath(path2, FORWARD, g2, params); /** * Note: In situations where there are * multiple branches shorter than the trim * length, we first check for a unique * branch that is longer than the false positive * trim length (`fpTrim`). If there are multiple branches * longer than the false positive trim length, * they are all considered sequencing error branches * and are all trimmed. If all branches are shorter * than the false positive trim length, we choose the * longest branch, provided that the choice is * unambiguous (i.e. no ties). */ ASSERT_EQ(3u, path2.size()); ASSERT_EQ(0u, path2.at(0)); ASSERT_EQ(1u, path2.at(1)); ASSERT_EQ(3u, path2.at(2)); } TEST(extendPath, trueBranch) { const unsigned trim = 1; const unsigned fpTrim = 1; /* * This "X" structure is created frequently * by Bloom filter false positives. (The "*"'s * denote the positions of the false * positives.) * * 5 * | * 3* 4 * |\/| * |/\| * 1 2* * | * 0 */ Graph g; add_edge(0, 1, g); add_edge(1, 3, g); add_edge(2, 3, g); add_edge(2, 4, g); add_edge(4, 5, g); ASSERT_FALSE(trueBranch(edge(1, 3, g).first, FORWARD, g, trim, fpTrim)); ASSERT_TRUE(trueBranch(edge(1, 4, g).first, FORWARD, g, trim, fpTrim)); } 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 pathForward; pathForward.push_back(0); Path expectedPathForward; expectedPathForward.push_back(0); expectedPathForward.push_back(1); expectedPathForward.push_back(2); result = extendPath(pathForward, FORWARD, g); EXPECT_EQ(2u, result.first); EXPECT_EQ(ER_CYCLE, result.second); EXPECT_EQ(expectedPathForward, pathForward); Path pathReverse; pathReverse.push_back(0); Path expectedPathReverse; expectedPathReverse.push_back(1); expectedPathReverse.push_back(2); expectedPathReverse.push_back(0); result = extendPath(pathReverse, REVERSE, g); EXPECT_EQ(2u, result.first); EXPECT_EQ(ER_CYCLE, result.second); 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 path2; path2.push_back(0); Path expectedPath2; expectedPath2.push_back(0); expectedPath2.push_back(1); result = extendPath(path2, FORWARD, g2); /* * note: expected result is EXTENDED_TO_BRANCHING_POINT * because vertex 1 has 2 incoming edges */ EXPECT_EQ(1u, result.first); EXPECT_EQ(ER_AMBI_IN, result.second); 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 path3; path3.push_back(0); Path expectedPath3; expectedPath3.push_back(1); expectedPath3.push_back(0); result = extendPath(path3, REVERSE, g3); /* * note: expected result is EXTENDED_TO_BRANCHING_POINT * because vertex 1 has 2 incoming edges */ EXPECT_EQ(1u, result.first); EXPECT_EQ(ER_AMBI_IN, result.second); 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 path; path.push_back(0); Path expectedPath; expectedPath.push_back(0); expectedPath.push_back(1); result = extendPath(path, FORWARD, g); EXPECT_EQ(1u, result.first); EXPECT_EQ(ER_AMBI_IN, result.second); EXPECT_EQ(expectedPath, path); } abyss-2.2.4/Unittest/Graph/HashGraphTest.cpp000066400000000000000000000037421361462241400207420ustar00rootroot00000000000000#include "Graph/HashGraph.h" #include #include using namespace std; namespace { class HashGraphTest : public ::testing::Test { protected: typedef HashGraph Graph; typedef boost::graph_traits::edge_descriptor edge_descriptor; typedef boost::graph_traits::out_edge_iterator out_edge_iterator; typedef boost::graph_traits::in_edge_iterator in_edge_iterator; typedef boost::graph_traits::vertex_descriptor vertex_descriptor; typedef boost::graph_traits::vertex_iterator vertex_iterator; Graph simpleCyclicGraph; string a; string b; string c; string d; unordered_set vertexSet; HashGraphTest() : a("a"), b("b"), c("c"), d("d") { add_edge(a, b, simpleCyclicGraph); add_edge(a, c, simpleCyclicGraph); add_edge(b, d, simpleCyclicGraph); add_edge(c, d, simpleCyclicGraph); vertexSet.insert(a); vertexSet.insert(b); vertexSet.insert(c); vertexSet.insert(d); } }; TEST_F(HashGraphTest, out_edge_iterator) { edge_descriptor expectedEdge1(a, b); edge_descriptor expectedEdge2(a, c); out_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = out_edges(a, simpleCyclicGraph); ASSERT_TRUE(ei != ei_end); edge_descriptor edge1 = *ei; EXPECT_TRUE(edge1 == expectedEdge1 || edge1 == expectedEdge2); ei++; ASSERT_TRUE(ei != ei_end); edge_descriptor edge2 = *ei; EXPECT_TRUE(edge2 != edge1); EXPECT_TRUE(edge2 == expectedEdge1 || edge2 == expectedEdge2); ei++; EXPECT_TRUE(ei == ei_end); } TEST_F(HashGraphTest, vertex_iterator) { vertex_iterator vi, vi_begin, vi_end; boost::tie(vi_begin, vi_end) = vertices(simpleCyclicGraph); ASSERT_TRUE(vi_begin != vi_end); unsigned count = 0; vertex_descriptor v; vi = vi_begin; for(; vi != vi_end; vi++, count++) { // check that current vertex is different from // previous vertex if (vi != vi_begin) { EXPECT_TRUE(*vi != v); } vertex_descriptor v = *vi; EXPECT_TRUE(vertexSet.find(v) != vertexSet.end()); } EXPECT_EQ(4U, count); } } abyss-2.2.4/Unittest/Graph/UndirectedGraphTest.cpp000066400000000000000000000024551361462241400221450ustar00rootroot00000000000000#include "Common/Hash.h" #include "Graph/UndirectedGraph.h" #include "Graph/Properties.h" #include #include #include #include using namespace std; typedef UndirectedGraph Graph; typedef boost::graph_traits::vertex_descriptor V; typedef boost::graph_traits::edge_descriptor E; typedef boost::graph_traits::edge_iterator EdgeIterator; TEST(UndirectedGraphTest, edgeComparison) { Graph g; V u = add_vertex(NoProperty(), g); V v = add_vertex(NoProperty(), g); E uv = E(u, v); E vu = E(v, u); ASSERT_EQ(uv, vu); ASSERT_EQ(uv.hashCode(), vu.hashCode()); } TEST(UndirectedGraphTest, edges) { Graph g; V u = add_vertex(NoProperty(), g); V v = add_vertex(NoProperty(), g); /* * Internally, both edge orientations (u, v) and (v, u) are * added to the graph data structures. Make sure that * this isn't exposed externally and that we only see one edge. */ E e; bool inserted; boost::tie(e, inserted) = add_edge(u, v, NoProperty(), g); ASSERT_TRUE(inserted); ASSERT_EQ(1u, num_edges(g)); /* make sure iterator only visits one version of the edge */ EdgeIterator eit, eit_end; boost::tie(eit, eit_end) = edges(g); ASSERT_NE(eit, eit_end); ASSERT_EQ(e, *eit); ++eit; ASSERT_EQ(eit, eit_end); } abyss-2.2.4/Unittest/Konnector/000077500000000000000000000000001361462241400164245ustar00rootroot00000000000000abyss-2.2.4/Unittest/Konnector/BloomFilter.cc000066400000000000000000000142311361462241400211520ustar00rootroot00000000000000#include "Bloom/Bloom.h" #include "Bloom/BloomFilter.h" #include "Bloom/CascadingBloomFilter.h" #include "Bloom/BloomFilterWindow.h" #include "Bloom/CascadingBloomFilterWindow.h" #include "Common/BitUtil.h" #include #include using namespace std; using Konnector::BloomFilter; TEST(BloomFilter, base) { BloomFilter x(10000); EXPECT_EQ(x.size(), 10000U); Kmer::setLength(16); Kmer a("AGATGTGCTGCCGCCT"); Kmer b("TGGACAGCGTTACCTC"); Kmer c("TAATAACAGTCCCTAT"); Kmer d("GATCGTGGCGGGCGAT"); x.insert(a); EXPECT_EQ(x.popcount(), 1U); EXPECT_TRUE(x[a]); x.insert(b); EXPECT_EQ(x.popcount(), 2U); EXPECT_TRUE(x[b]); EXPECT_TRUE(x[Bloom::hash(b) % x.size()]); x.insert(Bloom::hash(c) % x.size()); EXPECT_EQ(x.popcount(), 3U); EXPECT_TRUE(x[c]); EXPECT_TRUE(x[Bloom::hash(c) % x.size()]); EXPECT_FALSE(x[d]); } TEST(BloomFilter, serialization) { BloomFilter origBloom(20); EXPECT_EQ(origBloom.size(), 20U); Kmer::setLength(16); Kmer a("AGATGTGCTGCCGCCT"); Kmer b("TGGACAGCGTTACCTC"); Kmer c("TAATAACAGTCCCTAT"); origBloom.insert(a); origBloom.insert(b); origBloom.insert(c); EXPECT_TRUE(origBloom[a]); EXPECT_TRUE(origBloom[b]); EXPECT_TRUE(origBloom[c]); size_t origSize = origBloom.size(); size_t origPopcount = origBloom.popcount(); stringstream ss; ss << origBloom; ASSERT_TRUE(ss.good()); BloomFilter copyBloom; ss >> copyBloom; ASSERT_TRUE(ss.good()); EXPECT_EQ(origSize, copyBloom.size()); EXPECT_EQ(origPopcount, copyBloom.popcount()); EXPECT_TRUE(copyBloom[a]); EXPECT_TRUE(copyBloom[b]); EXPECT_TRUE(copyBloom[c]); } TEST(BloomFilter, union_) { size_t bits = 10000; BloomFilter bloom1(bits); BloomFilter bloom2(bits); Kmer a("AGATGTGCTGCCGCCT"); Kmer b("TGGACAGCGTTACCTC"); bloom1.insert(a); bloom2.insert(b); EXPECT_TRUE(bloom1[a]); EXPECT_FALSE(bloom1[b]); EXPECT_FALSE(bloom2[a]); EXPECT_TRUE(bloom2[b]); BloomFilter unionBloom; stringstream ss; ss << bloom1; ASSERT_TRUE(ss.good()); ss << bloom2; ASSERT_TRUE(ss.good()); ss >> unionBloom; ASSERT_TRUE(ss.good()); unionBloom.read(ss, BITWISE_OR); ASSERT_TRUE(ss.good()); EXPECT_EQ(unionBloom.size(), bits); EXPECT_TRUE(unionBloom[a]); EXPECT_TRUE(unionBloom[b]); } TEST(BloomFilter, intersect) { size_t bits = 10000; BloomFilter bloom1(bits); BloomFilter bloom2(bits); Kmer a("AGATGTGCTGCCGCCT"); Kmer b("TGGACAGCGTTACCTC"); Kmer c("AGCTAGCTAGCTAGCT"); bloom1.insert(a); bloom2.insert(b); bloom1.insert(c); bloom2.insert(c); EXPECT_TRUE(bloom1[a]); EXPECT_TRUE(bloom1[c]); EXPECT_FALSE(bloom1[b]); EXPECT_FALSE(bloom2[a]); EXPECT_TRUE(bloom2[b]); EXPECT_TRUE(bloom2[c]); BloomFilter intersectBloom; stringstream ss; ss << bloom1; ASSERT_TRUE(ss.good()); ss << bloom2; ASSERT_TRUE(ss.good()); ss >> intersectBloom; ASSERT_TRUE(ss.good()); intersectBloom.read(ss, BITWISE_AND); ASSERT_TRUE(ss.good()); EXPECT_EQ(intersectBloom.size(), bits); EXPECT_FALSE(intersectBloom[a]); EXPECT_FALSE(intersectBloom[b]); EXPECT_TRUE(intersectBloom[c]); } TEST(CascadingBloomFilter, base) { CascadingBloomFilter x(10000, 2); EXPECT_EQ(x.size(), 10000U); Kmer::setLength(16); Kmer a("AGATGTGCTGCCGCCT"); Kmer b("TGGACAGCGTTACCTC"); Kmer c("TAATAACAGTCCCTAT"); Kmer d("GATCGTGGCGGGCGAT"); x.insert(a); EXPECT_EQ(x.popcount(), 0U); EXPECT_FALSE(x[a]); x.insert(a); EXPECT_EQ(x.popcount(), 1U); EXPECT_TRUE(x[a]); x.insert(b); EXPECT_EQ(x.popcount(), 1U); EXPECT_FALSE(x[b]); x.insert(c); EXPECT_EQ(x.popcount(), 1U); EXPECT_FALSE(x[c]); x.insert(b); EXPECT_EQ(x.popcount(), 2U); EXPECT_TRUE(x[b]); EXPECT_TRUE(x[Bloom::hash(b) % x.size()]); x.insert(Bloom::hash(c) % x.size()); EXPECT_EQ(x.popcount(), 3U); EXPECT_TRUE(x[c]); EXPECT_FALSE(x[d]); } TEST(BloomFilter, windowSerialization) { size_t bits = 100; size_t pos = 80; BloomFilterWindow window(bits, bits/2, bits-1); window.insert(pos); EXPECT_TRUE(window[pos]); stringstream ss; ss << window; ASSERT_TRUE(ss.good()); BloomFilterWindow windowCopy; ss >> windowCopy; ASSERT_TRUE(ss.good()); EXPECT_TRUE(windowCopy[pos]); EXPECT_EQ(window.fullBloomSize(), windowCopy.fullBloomSize()); EXPECT_EQ(window.startBitPos(), windowCopy.startBitPos()); EXPECT_EQ(window.endBitPos(), windowCopy.endBitPos()); } TEST(BloomFilter, windowUnion) { size_t bits = 100; size_t pos1 = 25; size_t pos2 = 80; BloomFilter bloom(bits); // set a bit in both halves of bloom filter // bit array bloom.insert(pos1); bloom.insert(pos2); EXPECT_TRUE(bloom[pos1]); EXPECT_TRUE(bloom[pos2]); EXPECT_EQ(2U, bloom.popcount()); BloomFilterWindow window1(bits, 0, bits/2 - 1); window1.insert(pos1); EXPECT_TRUE(window1[pos1]); BloomFilterWindow window2(bits, bits/2, bits - 1); window2.insert(pos2); EXPECT_TRUE(window2[pos2]); stringstream ss; ss << window1; ASSERT_TRUE(ss.good()); ss << window2; ASSERT_TRUE(ss.good()); BloomFilter unionBloom; ss >> unionBloom; ASSERT_TRUE(ss.good()); unionBloom.read(ss, BITWISE_OR); ASSERT_TRUE(ss.good()); EXPECT_EQ(2U, unionBloom.popcount()); EXPECT_TRUE(unionBloom[pos1]); EXPECT_TRUE(unionBloom[pos2]); } TEST(CascadingBloomFilter, window) { size_t bits = 100; size_t pos1 = 25; size_t pos2 = 80; size_t pos3 = 50; CascadingBloomFilter CascadingBloom(bits, 2); // set a bit in both halves of the second level // bloom filter CascadingBloom.insert(pos1); CascadingBloom.insert(pos1); CascadingBloom.insert(pos2); CascadingBloom.insert(pos2); CascadingBloom.insert(pos3); EXPECT_TRUE(CascadingBloom[pos1]); EXPECT_TRUE(CascadingBloom[pos2]); EXPECT_EQ(2U, CascadingBloom.getBloomFilter(1).popcount()); CascadingBloomFilterWindow window1(bits, 0, bits/2 - 1, 2); window1.insert(pos1); window1.insert(pos1); CascadingBloomFilterWindow window2(bits, bits/2, bits - 1, 2); window2.insert(pos2); window2.insert(pos2); window2.insert(pos3); window1.insert(pos3); stringstream ss; ss << window1; ASSERT_TRUE(ss.good()); ss << window2; ASSERT_TRUE(ss.good()); BloomFilter unionBloom; ss >> unionBloom; ASSERT_TRUE(ss.good()); unionBloom.read(ss, BITWISE_OR); ASSERT_TRUE(ss.good()); EXPECT_EQ(2U, unionBloom.popcount()); EXPECT_TRUE(unionBloom[pos1]); EXPECT_TRUE(unionBloom[pos2]); EXPECT_FALSE(unionBloom[pos3]); } abyss-2.2.4/Unittest/Konnector/DBGBloomAlgorithmsTest.cpp000066400000000000000000000132141361462241400234100ustar00rootroot00000000000000#include "Konnector/DBGBloomAlgorithms.h" #include "Bloom/Bloom.h" #include "Bloom/CascadingBloomFilter.h" #include "Common/Sequence.h" #include #include using namespace std; using Konnector::BloomFilter; /* * Tests for getStartKmerPos() function, which does * the following: * * 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 { protected: FastaRecord testRead; static const int k = 2; // set this large to avoid false positives static const int bloomFilterSize = 1000000; GetStartKmerPosTest() { Kmer::setLength(k); testRead.seq = "TACAGTG"; } }; TEST_F(GetStartKmerPosTest, FullReadMatch) { BloomFilter bloom(bloomFilterSize); Bloom::loadSeq(bloom, k, testRead.seq); DBGBloom g(bloom); const unsigned numMatchesThreshold = 1; EXPECT_EQ(5U, getStartKmerPos(testRead, k, FORWARD, g, numMatchesThreshold)); } TEST_F(GetStartKmerPosTest, FullReadMismatch) { BloomFilter bloom(bloomFilterSize); // Leave the bloom filter empty to generate a mismatch // for every kmer in the read. DBGBloom g(bloom); EXPECT_EQ(NO_MATCH, getStartKmerPos(testRead, k, FORWARD, g)); } TEST_F(GetStartKmerPosTest, NumMatchesThreshold) { const string& seq = testRead.seq; BloomFilter bloom(bloomFilterSize); DBGBloom g(bloom); // This loop creates kmer match vector 101101 for (unsigned i = 0; i < seq.length() - k + 1; i++) { // non-matching kmers if (i == 1 || i == 4) continue; Bloom::loadSeq(bloom, k, seq.substr(i,k)); } 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) { const string& seq = testRead.seq; BloomFilter bloom(bloomFilterSize); DBGBloom g(bloom); // This loop creates kmer match vector 011011 for (unsigned i = 0; i < seq.length() - k + 1; i++) { // non-matching kmers if (i == 0 || i == 3) continue; Bloom::loadSeq(bloom, k, seq.substr(i,k)); } 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 { protected: FastaRecord correctRead; FastaRecord singleErrorRead; string simulatedFalsePositive; static const int k = 6; static const size_t errorPos1 = 4; // set this large to avoid false positives static const int bloomFilterSize = 1000000; CorrectSingleBaseErrorTest() { Kmer::setLength(k); correctRead.seq = "TACAGTGCC"; singleErrorRead.seq = correctRead.seq; singleErrorRead.seq[errorPos1] = 'C'; simulatedFalsePositive = "TGCAGT"; } }; TEST_F(CorrectSingleBaseErrorTest, SingleError) { BloomFilter bloom(bloomFilterSize); Bloom::loadSeq(bloom, k, correctRead.seq); DBGBloom g(bloom); size_t correctedPos = numeric_limits::max(); FastaRecord read = singleErrorRead; bool success = correctSingleBaseError(g, k, read, correctedPos); ASSERT_TRUE(success); EXPECT_EQ(read.seq, read.seq); EXPECT_TRUE(correctedPos == errorPos1); } TEST_F(CorrectSingleBaseErrorTest, ReverseComplement) { BloomFilter bloom(bloomFilterSize); Bloom::loadSeq(bloom, k, correctRead.seq); DBGBloom g(bloom); size_t correctedPos = numeric_limits::max(); FastaRecord read = singleErrorRead; bool success = correctSingleBaseError(g, k, read, correctedPos, true); ASSERT_TRUE(success); EXPECT_EQ(read.seq, read.seq); EXPECT_TRUE(correctedPos == errorPos1); } TEST_F(CorrectSingleBaseErrorTest, NoError) { BloomFilter bloom(bloomFilterSize); Bloom::loadSeq(bloom, k, singleErrorRead.seq); DBGBloom g(bloom); size_t correctedPos = numeric_limits::max(); FastaRecord read = singleErrorRead; bool success = correctSingleBaseError(g, k, read, correctedPos); ASSERT_FALSE(success); } TEST_F(CorrectSingleBaseErrorTest, SkipFalsePositive) { BloomFilter bloom(bloomFilterSize); Bloom::loadSeq(bloom, k, correctRead.seq); Bloom::loadSeq(bloom, k, simulatedFalsePositive); DBGBloom g(bloom); size_t correctedPos = numeric_limits::max(); FastaRecord read = singleErrorRead; bool success = correctSingleBaseError(g, k, read, correctedPos); ASSERT_TRUE(success); EXPECT_EQ(read.seq, read.seq); EXPECT_TRUE(correctedPos == errorPos1); } abyss-2.2.4/Unittest/Konnector/DBGBloomTest.cpp000066400000000000000000000031061361462241400213550ustar00rootroot00000000000000#include "Konnector/DBGBloom.h" #include "Bloom/CascadingBloomFilter.h" #include "Bloom/BloomFilter.h" #include #include using Konnector::BloomFilter; TEST(DBGBloom, BloomFilterPolymorphism) { unsigned bits = 100000; Kmer::setLength(3); Kmer kmer1("GAC"); Kmer kmer2("ACC"); Kmer kmer3("CCA"); CascadingBloomFilter countingBloom(bits, 2); countingBloom.insert(kmer1); countingBloom.insert(kmer1); countingBloom.insert(kmer2); countingBloom.insert(kmer2); countingBloom.insert(kmer3); countingBloom.insert(kmer3); DBGBloom graph(countingBloom); // test that expected edges exist boost::graph_traits< DBGBloom >::out_edge_iterator ei, ei_end; boost::tie(ei, ei_end) = out_edges(kmer1, graph); ASSERT_TRUE(ei != ei_end); EXPECT_TRUE(target(*ei, graph) == kmer2); ei++; EXPECT_TRUE(ei == ei_end); boost::tie(ei, ei_end) = out_edges(kmer2, graph); ASSERT_TRUE(ei != ei_end); EXPECT_TRUE(target(*ei, graph) == kmer3); ei++; EXPECT_TRUE(ei == ei_end); boost::graph_traits< DBGBloom >::out_edge_iterator ei2, ei_end2; DBGBloom graph2(countingBloom.getBloomFilter(1)); // test that the same edges exist in non-counting // bloom filter boost::tie(ei2, ei_end2) = out_edges(kmer1, graph2); ASSERT_TRUE(ei2 != ei_end2); EXPECT_TRUE(target(*ei2, graph2) == kmer2); ei2++; EXPECT_TRUE(ei2 == ei_end2); boost::tie(ei2, ei_end2) = out_edges(kmer2, graph2); ASSERT_TRUE(ei2 != ei_end2); EXPECT_TRUE(target(*ei2, graph2) == kmer3); ei2++; EXPECT_TRUE(ei2 == ei_end2); } abyss-2.2.4/Unittest/Konnector/konnectorTest.cpp000066400000000000000000000033231361462241400217730ustar00rootroot00000000000000#include "Konnector/konnector.h" #include #include using namespace std; using Konnector::BloomFilter; // workaround: opt::k must be defined because // it is used by write_dot(..) namespace opt { unsigned k = 0; } TEST(maskNew, read1) { FastqRecord r1("1", "", "ACGTACGT", "BBBBBBBB"); FastqRecord r2; FastaRecord read("2", "", "ACGTACGT"); int mask = 1; EXPECT_TRUE(maskNew(r1, r2, read, mask) == 0u); EXPECT_TRUE(read.seq == "ACGTACGT"); read = FastaRecord("2", "", "ACGTACGTA"); EXPECT_TRUE(maskNew(r1, r2, read, mask) == 0u); cout << read.seq << endl; EXPECT_TRUE(read.seq == "ACGTACGTa"); } TEST(maskNew, mask) { FastqRecord r1("1", "", "ACGTA", "BBBBB"); FastqRecord r2; FastaRecord read("2", "", "ACGTACGT"); int mask = 0; EXPECT_TRUE(maskNew(r1, r2, read, mask) == 0u); EXPECT_TRUE(read.seq == "ACGTACGT"); } TEST(ConnectPairsTest, MergeOverlappingPair) { // Merged seq: GATG // Read 1: GAT => // Read 2: TAC <= const int k = 2; Kmer::setLength(k); const int readLength = 3; string mergedSeq = "GATG"; FastaRecord read1, read2; read1.id = "read/1"; read1.seq = mergedSeq.substr(0,readLength); read2.id = "read/2"; read2.seq = reverseComplement(mergedSeq.substr(1,readLength)); BloomFilter bloom(1000); DBGBloom g(bloom); Bloom::loadSeq(bloom, k, read1.seq); Bloom::loadSeq(bloom, k, read2.seq); vector mergedSeqs; ConnectPairsParams params; params.maxPaths = 1; params.minMergedSeqLen = 0; params.maxMergedSeqLen = 4; ConnectPairsResult result = connectPairs(k, read1, read2, g, params); EXPECT_EQ(FOUND_PATH, result.pathResult); ASSERT_EQ(1u, result.mergedSeqs.size()); EXPECT_EQ("GATG", result.mergedSeqs[0].seq); } abyss-2.2.4/Unittest/Makefile.am000066400000000000000000000217471361462241400165310ustar00rootroot00000000000000# -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 AM_CXXFLAGS += $(PTHREAD_CFLAGS) -Wno-error AM_LDFLAGS = $(PTHREAD_LIBS) AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_srcdir)/vendor/gtest-1.7.0/include if HAVE_TR1_TUPLE AM_CPPFLAGS += -DGTEST_USE_OWN_TR1_TUPLE=0 endif LDADD = $(top_builddir)/vendor/gtest-1.7.0/libgtest_main.a check_PROGRAMS = common_stringutil common_stringutil_SOURCES = Common/StringUtilTest.cpp check_PROGRAMS += common_histogram common_histogram_SOURCES = Common/HistogramTest.cpp check_PROGRAMS += common_bitutil common_bitutil_SOURCES = Common/BitUtilTest.cpp check_PROGRAMS += common_kmer common_kmer_SOURCES = Common/KmerTest.cpp common_kmer_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += common_sequence common_sequence_SOURCES = Common/Sequence.cc common_sequence_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += common_KmerIterator common_KmerIterator_SOURCES = Common/KmerIteratorTest.cpp common_KmerIterator_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += common_sam common_sam_SOURCES = Common/SAM.cc common_sam_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += BloomFilter BloomFilter_SOURCES = Konnector/BloomFilter.cc BloomFilter_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common BloomFilter_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) BloomFilter_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) check_PROGRAMS += Konnector_DBGBloom Konnector_DBGBloom_SOURCES = Konnector/DBGBloomTest.cpp Konnector_DBGBloom_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common Konnector_DBGBloom_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) Konnector_DBGBloom_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) check_PROGRAMS += Konnector_DBGBloomAlgorithms Konnector_DBGBloomAlgorithms_SOURCES = Konnector/DBGBloomAlgorithmsTest.cpp Konnector_DBGBloomAlgorithms_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common Konnector_DBGBloomAlgorithms_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) Konnector_DBGBloomAlgorithms_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_ConstrainedBFSVisitor graph_ConstrainedBFSVisitor_SOURCES = Graph/ConstrainedBFSVisitorTest.cpp graph_ConstrainedBFSVisitor_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_ConstrainedBFSVisitor_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_BidirectionalBFS graph_BidirectionalBFS_SOURCES = Graph/BidirectionalBFSTest.cpp graph_BidirectionalBFS_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_BidirectionalBFS_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_AllPathsSearch graph_AllPathsSearch_SOURCES = Graph/AllPathsSearchTest.cpp graph_AllPathsSearch_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_AllPathsSearch_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_HashGraph graph_HashGraph_SOURCES = Graph/HashGraphTest.cpp graph_HashGraph_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_HashGraph_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_ConstrainedBidiBFSVisitor graph_ConstrainedBidiBFSVisitor_SOURCES = \ Graph/ConstrainedBidiBFSVisitorTest.cpp graph_ConstrainedBidiBFSVisitor_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_ConstrainedBidiBFSVisitor_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_ExtendPath graph_ExtendPath_SOURCES = Graph/ExtendPathTest.cpp graph_ExtendPath_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_ExtendPath_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += graph_DotIO graph_DotIO_SOURCES = Graph/DotIOTest.cpp graph_DotIO_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common graph_DotIO_LDADD = \ $(top_builddir)/Assembly/libassembly.a \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += graph_UndirectedGraph graph_UndirectedGraph_SOURCES = Graph/UndirectedGraphTest.cpp # graph_UndirectedGraph_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common # graph_UndirectedGraph_LDADD = $(top_builddir)/Common/libcommon.a $(LDADD) check_PROGRAMS += Konnector_konnector Konnector_konnector_SOURCES = \ Konnector/konnectorTest.cpp Konnector_konnector_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common Konnector_konnector_LDADD = \ $(top_builddir)/Align/libalign.a \ $(top_builddir)/Common/libcommon.a \ $(LDADD) Konnector_konnector_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) check_PROGRAMS += DBG_LoadAlgorithm DBG_LoadAlgorithm_SOURCES = \ DBG/LoadAlgorithmTest.cpp DBG_LoadAlgorithm_CPPFLAGS = \ $(AM_CPPFLAGS) \ -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 \ $(LDADD) DBG_LoadAlgorithm_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) if PAIRED_DBG check_PROGRAMS += PairedDBG_LoadAlgorithm PairedDBG_LoadAlgorithm_SOURCES = \ PairedDBG/LoadAlgorithmTest.cpp PairedDBG_LoadAlgorithm_CPPFLAGS = \ $(AM_CPPFLAGS) \ -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 \ $(LDADD) PairedDBG_LoadAlgorithm_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) check_PROGRAMS += PairedDBG_KmerPair PairedDBG_KmerPair_SOURCES = \ PairedDBG/KmerPairTest.cc PairedDBG_KmerPair_CPPFLAGS = \ $(AM_CPPFLAGS) \ -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 \ $(LDADD) PairedDBG_KmerPair_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) check_PROGRAMS += PairedDBG_Dinuc PairedDBG_Dinuc_SOURCES = \ PairedDBG/DinucTest.cc PairedDBG_Dinuc_CPPFLAGS = \ $(AM_CPPFLAGS) \ -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 \ $(LDADD) PairedDBG_Dinuc_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) check_PROGRAMS += PairedDBG_BranchRecord PairedDBG_BranchRecord_SOURCES = \ PairedDBG/BranchRecordTest.cpp PairedDBG_BranchRecord_CPPFLAGS = \ $(AM_CPPFLAGS) \ -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 \ $(LDADD) PairedDBG_BranchRecord_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) endif # PAIRED_DBG check_PROGRAMS += BloomDBG_BloomDBG BloomDBG_BloomDBG_SOURCES = BloomDBG/BloomDBGTest.cpp BloomDBG_BloomDBG_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/Common BloomDBG_BloomDBG_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) BloomDBG_BloomDBG_LDADD = \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_RollingHash BloomDBG_RollingHash_SOURCES = BloomDBG/RollingHashTest.cpp BloomDBG_RollingHash_LDADD = \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_RollingHashIterator BloomDBG_RollingHashIterator_SOURCES = BloomDBG/RollingHashIteratorTest.cpp BloomDBG_RollingHashIterator_LDADD = \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_HashAgnosticCascadingBloom BloomDBG_HashAgnosticCascadingBloom_SOURCES = \ BloomDBG/HashAgnosticCascadingBloomTest.cpp BloomDBG_HashAgnosticCascadingBloom_CXXFLAGS = $(AM_CXXFLAGS) \ $(OPENMP_CXXFLAGS) BloomDBG_HashAgnosticCascadingBloom_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_CountingBloomFilter BloomDBG_CountingBloomFilter_SOURCES = \ BloomDBG/CountingBloomFilterTest.cpp BloomDBG_CountingBloomFilter_CPPFLAGS = $(AM_CPPFLAGS) \ -I$(top_srcdir)/Common BloomDBG_CountingBloomFilter_CXXFLAGS = $(AM_CXXFLAGS) \ $(OPENMP_CXXFLAGS) BloomDBG_CountingBloomFilter_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_RollingBloomDBG BloomDBG_RollingBloomDBG_SOURCES = BloomDBG/RollingBloomDBGTest.cpp BloomDBG_RollingBloomDBG_CXXFLAGS = $(AM_CXXFLAGS) \ $(OPENMP_CXXFLAGS) BloomDBG_RollingBloomDBG_LDADD = \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_MaskedKmer BloomDBG_MaskedKmer_SOURCES = BloomDBG/MaskedKmerTest.cpp BloomDBG_MaskedKmer_LDADD = \ $(top_builddir)/Common/libcommon.a \ $(LDADD) check_PROGRAMS += BloomDBG_SpacedSeed BloomDBG_SpacedSeed_SOURCES = BloomDBG/SpacedSeedTest.cpp check_PROGRAMS += BloomDBG_LightweightKmer BloomDBG_LightweightKmer_SOURCES = BloomDBG/LightweightKmerTest.cpp BloomDBG_LightweightKmer_LDADD = \ $(top_builddir)/Common/libcommon.a \ $(LDADD) TESTS = $(check_PROGRAMS) abyss-2.2.4/Unittest/PairedDBG/000077500000000000000000000000001361462241400162035ustar00rootroot00000000000000abyss-2.2.4/Unittest/PairedDBG/BranchRecordTest.cpp000066400000000000000000000032501361462241400221030ustar00rootroot00000000000000#include "Assembly/Options.h" #include "Common/Options.h" #include "PairedDBG/SequenceCollection.h" #include #include 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 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); } abyss-2.2.4/Unittest/PairedDBG/DinucTest.cc000066400000000000000000000032171361462241400204170ustar00rootroot00000000000000#include "PairedDBG/Dinuc.h" #include 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); } abyss-2.2.4/Unittest/PairedDBG/KmerPairTest.cc000066400000000000000000000035741361462241400210750ustar00rootroot00000000000000#include "PairedDBG/KmerPair.h" #include 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 */ abyss-2.2.4/Unittest/PairedDBG/LoadAlgorithmTest.cpp000066400000000000000000000027451361462241400223050ustar00rootroot00000000000000#include "PairedDBG/SequenceCollection.h" #include "Assembly/AssemblyAlgorithms.h" #include "Assembly/Options.h" #include "Common/UnorderedSet.h" #include #include #include 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 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()); } abyss-2.2.4/Unittest/PairedDBG/test.fa000066400000000000000000000000301361462241400174630ustar00rootroot00000000000000>test TAATGCCATGGGATGTT abyss-2.2.4/Unittest/PairedDBG/test.png000066400000000000000000004623021361462241400176770ustar00rootroot00000000000000‰PNG  IHDRwÒBuësBITÛáOàtEXtSoftwaregnome-screenshotï¿> IDATxœìÝw\S×ÿ?ð“„½EÁ-bq×=˜uNT¬P‹R«­Vë@´ÕÖUÅ:?V«UA+¸­²·´¢âb(ÊP $ùýq¾Í/MB@7 ¼žôaÏ=¹y!ä¾ï,‘HDŒ­êÐD ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ*(ª  ¨2€r ÊÊ¡¥êÐ,TUUñx<W^^.õ_ñ?„B!‡Ãa³ÙGò’ÿÖÓÓ3ù—±±±‰‰ ‡ÃQõÿUh¡PXXXX P~~~iii#000Wè?Zµjemmm#ÁÊÊ Å°D"‘ª3€ …999™ÿÊÊÊ¢ÿxùò%ŸÏWuºZ°ÙìV­Z‰‹mÛ¶íÒ¥KçÎ;wîl`` êtMª Ç«W¯’““ÿùçqYáÕ«WUUUªÎ¥d,ËÆÆ†VÄÿíСƒŽŽŽª£h$T€BÒÓÓ“%äçç«:‘Êp8œ¶mÛöêÕ«OŸ>}ûöíÓ§O«V­T @3 ÊÐ …ÂgÏžI–Þ¿¯êPêËÖÖ––hÝÁÆÆFÕ‰Ôª ÍEQQÑŸþyûöíäää””.—«êDšÊÊʪoß¾ýû÷wvv8p žžžª¨ Tš¸ÇŸ={öܹsׯ_ªŽCtttôõõ þ%þ·¾¾¾–––P(‚²²²’•——«ú«!ººº pqqqqq8p ¾¾¾ª¨ª MPUUÕåË—Ï;wöìÙôôtžÑÐÐÐÒÒÒÂÂÂÒÒRüÉÿš™™Ñ‚‚w”¬®®.---...‘PPP“““››+þoQQ3zutt àìììââ2xð`T B• é(((¸páÂÙ³g/^¼XRR¢ôós8º ¤{{{uÞ’Ïççå剋ÙÙÙÏž={öìÙóçÏo4„ŽŽŽ³³³—————W»víéYÔ ª /55•Ή¸yó¦P(TÖiíììúöíÛ«W¯öíÛÓjB›6m´´´”u~•‰D¯_¿¦‡§OŸÒ¼xñ‚Ïç+÷‰œœœ¼¼¼<==Èf³•{rµ‚*€¦ÊÊÊÚ¿XXXff¦RNhooßW‚¥¥¥RN«Y„BaFFFJJÊßÿ***RÖÉ---ÇŒãåå5bÄccce@} Ê aª««Ïž=»wïÞ‹/6päBÛ¶m%Ë Ê Ù”dffÒrÃÝ»w“““ ~N—©S§Nš4ÉÔÔ´á'P¨2hŒôôôß~ûí÷ßÏËË«ßèb®®®}ûöíÓ§Ê õ™™y÷îݤ¤¤Ë—/ÿóÏ? ü8­§§çééùé§ŸŽ3FGGGY!TUuÇçó£¢¢öíÛW¿o¨ßHŠŠŠ’’’/_¾|ÿþý† -iÑ¢…ϧŸ~:lØ0‹¥ÄLB•@}=}útß¾}‡ÊÏϯÇÃ{ôèáéééååÕ¿,:ØØÞ¿O8$&&Þ»wO Ôï<öööÓ§OÿôÓOœœ”›€¨2¨ªªªãÇïÝ»÷òåËúX===WWWOOOOOO{{ûƈµzÿþ=ÝR4&&¦¸¸¸~'éÙ³g`` ¿¿?†Ÿ€A•@ðùüƒþôÓOºm„••Ý+ñ“O>100hœtðÁªªª®\¹]¿­@Œýüü¾úê«nݺ);€ò¡Ê *++ûí·M›6½zõªîb³Ù#GŽ ôòòÒÒÒj¼xÐp< å†;wîÔãC¸‹‹ËW_}5~üxü @¡Ê b<oïÞ½›7oÎÉÉ©û£lmmfÍšÕ¶mÛÆË!77722òÈ‘#wîÜùÐÇÚØØÌ™3'00ÐÚÚº1²4ª *SVV¶gÏž-[¶¼yó¦Žáp8£G ;v,‡ÃiÔxÐØž>}zäÈ‘#G޼xñ⃨­­=qâÄo¾ùfРA”  ~PeP.—»k×®Ÿþ¹î›GØÙÙÍš5kÖ¬YmÚ´iÔlÀ¼›7o†‡‡GFF~èf"...+W®ôððh¤` UF•””lß¾}ëÖ­EEEuéÏápÆŽûÅ_Œ=»Q6mÕÕÕ/^ ?{ö,—Ë­ûûõë·bÅŠqãÆ±X¬Æ‹P¨20¤¢¢âçŸ yÿþ}]ú›˜˜ÌŸ?Þ¼y666 Ô —Ë Ûµk×Çëþ¨>ú(88xÚ´i˜J*„*Μ9³hÑ¢ŒŒŒºt633ûæ›o.\hffÖØÁ@%&&îÚµ+**ªºººŽéСCPPÐÌ™3utt5€\¨24®´´´o¾ùæâÅ‹uélnn¾pá ˜šš6v0Я_¿þõ×_÷îÝ[÷UBmllV¬X1gÎl{ C• ±”””¬Y³fûöíUUUµvnÙ²å·ß~;þ|ccc²Æ©ªª:qâÄ®]»®]»VLJtîÜyýúõ>>> @ª Ê'‰:´|ùòºÜ|¶´´\²dɼy󌌌ÈšîÎ;6l8sæL?É÷ïßóæÍÎÎÎ € Ê twîÜ™?þ­[·jíieeµtéÒ¹sç0 š’‡nܸñرcu\²aìØ±7ntrrjì`Ð̡ʠ4oß¾ þý÷ßkýˆeeeµ|ùò9sæèëë3“ š¤ŒŒŒÍ›7ÿþûï•••µvf³ÙþþþkÖ¬±³³c 4O¨2(AUUÕ®]»~øá‡ââbÅ=µµµ,X°jÕ*f²A“—››ºgÏ.—[kg==½ùóç¯X±;˜@c@• ¡_qÏŽ;†††z{{3 š­âââ7nÛ¶ÇãÕÚÙÝÝ}÷îÝ]ºta 4¨2ÔÓ“'O>ûì³ZWy444\¹rå·ß~«««ËL°† …/^¼HMM-((àñxååå|>ßÚÚÚÑѱk×®ªu’½jÕªC‡ …BÅ=uuuƒ‚‚‚ƒƒõôô˜ÉMª L$mÛ¶mÅŠµÞ.ž>}úæÍ›mmm™ V?ÕÕÕIIIÑÑÑ7oÞ|ðàAYYYM=[¶lÙõ_}úôqqqa³ÙLF…’šštáÂ…Z{vêÔi×®]#FŒ` 4m¨2|˜ŒŒŒ™3g^¹rEq·Þ½{oß¾}èС̤ª‡²²²¿þú+**êüùóEEEõ8ƒ]@@@@@€½½½Òã²$$$,[¶ìîÝ»µöœ:uêÖ­[­­­HMª `Ïž=K—.U¼’¿¹¹ù† Õó>~~þ™3g¢¢¢âââ***~B6›=bĈÀÀ@///mm톟”N$EDD¬\¹2==]qO“uëÖ}õÕWêùêõ‡*@dgg\ºtIq7ooï_ýµuëÖ̤ú ? «¬¬lŒó[YYÍœ9séÒ¥-[¶lŒóCñùü-[¶¬_¿¾Ö™>Ç?tèP»víÉM ª µ;xðàÂ… ‹‹‹ô133Û¶m›¿¿?c©êîòåË!!!çÏŸg೟¥¥ehhèŒ3û‰ ~ÒÓÓ¿þú똘ÅÝŒ·nÝ:kÖ,fR@“*€"ååå_~ùeXX˜ân£GÞ·oŸº­ò(‰"##CBBê2'_¹<<<öìÙÓ±cG†Ÿêèĉ .|ýúµân^^^ûöí³²²b&4¨2ÔèÉ“'“&Mzøð¡‚>&&&¡¡¡jxË7''Çßß?..îCÈb±Úµk×¥Kccc6›ýüùó´´´‚‚‚:¾¾þ÷ß¿dÉ,Ö žJKKW­ZµcÇ@  ›……ÅÞ½{'L˜ÀX0Ðh¨2È1{ölÅ =zxxìß¿_ wX8{öl@@ÀÕ:vìèåååååÕ¿###Ù………iiiiii©©©‘‘‘999u9­““Ó¾}ûX÷$À¤”””/¿üòöíÛŠ»ùûûoß¾ÝÔÔ”™T ¹PeÆçó/^¼sçN}ŒŒŒ¶lÙòå—_2–ªŽ***–,Y²k×®ºtf³Ùƒ ¢Å…nݺÕýYª««Ï;·wïÞ¿þúK(Öú,;wîœ;wnÝÏL …¿þúëòåËKJJt³··?xð ««+cÁ@¡Êð/_¾ôññQ|k×ÅÅåÀíÛ·g,Ueffzyy¥¦¦ÖÚ³_¿~óæÍóôô´°°hÈ3feeýöÛo¨uhÃ?ü°zõê†<4ª—/_Μ93!!AA‹µlÙ²õë×s8Æ‚€fA•àÿ‹‰‰™1cFQQQMØlöš5kV¬XÁb±˜ V\.wРAŠK ,ËËËkñâÅÇWâSóùüM›6­_¿^ñ™óæÍÛ±c›ÍVâSƒ‰D¢mÛ¶WTT(èæîî~ìØ±Ö§ ©B•€BÁêÕ«7lØ àÓQ«V­Ž9âááÁd°:‰D“'O>uêTMôôôüýý¿ýö[‡FÊðôéÓ9sæ$&&*èãã㮣£ÓH á?~ìïï¯x_;;»“'Oöë×±T )Pe oß¾õõõWÐgèС666Œ¥ú k×®]µjUMG{õêõÇtíÚ•$\²dIaaaMÜÝÝOŸ>mllÌ@¨ŸêêêuëÖ­_¿¾ººº¦>ººº;vì d2¨?T ¹KMMõôôÌÊʪ©‹ÅZ²dɆ ´´´˜ VwÑÑÑãÇ—û¹ŽÅb-Z´è§Ÿ~brø@~~þ×_YS‡¾}ûÆÆÆš™™1 êáÎ;þþþiii úÌš5k×®]ºººŒ¥5‡*4k111S§N---­©ƒ™™Ù¡C‡¼½½™LõArrråî`ii6räHæSB‚‚‚6oÞ\ÓQoo﨨(5\Þ$ñx¼àààíÛ·+¸jøøãOž<©†û¹€J`éh¾vîÜéå奠Äзoßäädu.1BvíÚ%·Ä ««­ª!dÓ¦M!!!5Õ¢££Ô @MèëëÿòË/QQQ¦¦¦5õ¹{÷.œÂd0P[ËÍ‘@ X´hÑŽ;ô™;wîÖ­[Õ|(xEE…]AAì¡|þùçÌG’ wz?‡Ã‰uqqa<|°gÏžMœ8QÁ&gݺuË—/g2¨!Œe€f§´´ÔËËKA‰ÁÈÈèÈ‘#»wïVó!ä?þ[bX°`:”!~~~gΜ100=$¦M›–››Ë|*øP;w¾yóæ´iÓjê ‚ƒƒ'Nœ(wd 4ËÍËË—/===»téRË–-™LÕááᲺººÌ‡©U``àÌ™3å IHH`6ÔŸ³³óßÿ=pàÀš:p¹Ü‰'îß¿ŸÉT &Pe€fa÷îÝS§Nåñxr²X¬ 6Iý8::N:U¶ýêÕ«ùùùÌçeY¼xñÁƒµ´´äÍÎÎ6lØ7NŒA•šŽ×¯_;;;?|øPîQ6›½oß>#º5‹Üµô ™ORor‡3ˆD¢ÄÄDUÄ¥ñ÷÷ŠŠÒ××—{”Ž6B¡ ©B•šˆœœWW×çÏŸË=ª££1{öl†S5‘HÄãñdÛ5k¥ wwwÙöøøxæÃ€r;666¶E‹r–——3&%%…áTÀT )ÈÍÍuuu}öì™Ü£†††çΛ (ÝàÁƒ¯\¹bcc#÷èû÷ïGŒñøñc†S@cC•4^^^ž««ëÓ§OåmÑ¢Ellì'Ÿ|ÂpªFÕdª nnn²Ož<ÉÉÉa> (““Óõë×»té"÷hAA‡‡Gzz:é Q¡ÊšíÍ›7®®®Ož<‘{ÔÚÚúÊ•+d8Uc“»(ƒ®®nMKî©­>}ú˜™™É¶c8C“ѶmÛ«W¯~üñÇræä主»ggg3œ ª  ÁÞ¾}ëææ–––&÷¨­­í•+WœœœNÅ€&°ô#ÅápœeÛQehJ,--ãããk*öeffzxx¼}û–áTÐHPeM•ŸŸïææöèÑ#¹G­­­ããã;uêÄp*f…BÙFÙý4‚ÜIW®\a> 4cc㘘˜^½zÉ=úäÉ“#F¼{÷ŽáTÐ4òO@QQ‘››[M›V¶nÝ:!!¡¦ÙàM€Üa 5-Ö æ\]]e³²²D"óa ñ˜™™]¼x±k×®rÞ¿ôèÑ\.—áT t¨2€æ©¨¨ðööNMM•{´U«Vñññ §b’l#ÇÓÄ+s‹%ÕÈçó T’¥¥elllûöíå½uë–——WEEé@¹Pe # §OŸ~íÚ5¹Gé pGGG†S1LîX‘H¤‰Ãttt,,,dÛ_¿~Í|hl¶¶¶±±±5mo™˜˜èë뫉Å2C•4Ì‚ NŸ>-÷……E\\ÜG}Äp$æÉË@jXRýɽæD•¡©êСCll¬ÜÒ!$**jÕªU G%B•4ÉO?ý´k×.¹‡ÌÍÍccc»wïÎp$•àp8ººº²íZe°µµ•mÄî†M˜££ãÅ‹MMMå]·n]dd$Ñ@YPeqøðá+VÈ=dffÛ³gO†#©ÜIM©Ê€± M[ïÞ½/\¸PÓö«3gÎLNNf8(ª  .^¼8{öl¹‡tuu£¢¢z÷îÍp$Õ’;iBC« ˜1Ñ< <øÌ™3zzz²‡x<Þ¸qãÞ¼yÃ|*h T@$''Oš4©ªªJö‹Å:|ø°³³3ó©T c  pwwß»w¯ÜCÙÙÙ&L¨¬¬d84ª  î222ÆŒÃåråýù矧L™Âp$u`ll,Û˜››Ë|’†C•¡9óóó[ºt©ÜC7nܘ3gÃy PeµVPP0jÔ¨šNûí·‹-b8’šèÔ©“lã£G˜OÒp˜1ÑÌmܸq̘1r:t(44”á<Ш2€ú*//÷òòzúô©Ü£S§N a8’úptt”mÔÐ*ƒÜ± ïÞ½ãñẋæ±Ùì?þø£k×®r.]º4))‰áHPo¨2€šÓ¦M»yó¦Ü£...‡f±X §Rݺu“m|üø1óIÎÂÂBGGG¶Ãš“èèè-ZÈ …~~~ÅÅÅ̧€z@•ÔÔ¼yóΞ=+÷““STT”ÜëÒæCîX†çÏŸ—””0¦X,–µµµl;ª ÍJçÎ###9Žì¡¬¬¬yóæ1 êUPGk×®­iåù6mÚÄÄĘšš2IÝtîÜYKKKªQ œ:uJ%y @!ÄÃã¦UŽ=zäȆó@= Êj'**jÕªUr™™™ÅÄÄ´iÓ†áHjHGG§gÏž²íGe>LÃÉ­2dgg3ŸTkÁ‚Ÿþ¹ÜCóæÍËÌÌd6|0T@½“{HWW7**ÊÉɉáHjË××W¶1>>>//ù0 „m&@lçÎ]ºt‘m/))ñóóÌG€ºC•Ô—Ë0a‚Ü•X,ÖáÇ™O¥¶|}}ÙlésàСC*ÉÓ˜1bGÕÖÖ–=tõêÕŸ~ú‰ùHPw¨2€™9sfM»$üüóÏS¦La8š³±±qww—m߸qcAAóyUÔ·oßüQî¡5kÖhè^*ͪ  .6mÚtòäI¹‡¾ùæ›E‹1œG#øùùÉ6¾ÿþ»ï¾c>LC`ÆH >|¸l{UUö›Pg,‘H¤ê $66vÔ¨Qrg\»ºº^ºtIîþvÀåríííß½{'ÕÎf³“““å.©žž={&;_KK«²²RvV4/_¾ìÑ£Gqq±ì¡Ã‡Ë-±€Êá-T/++kÚâàï‡ IDAT´irK vvv(1ÔÄÈÈhíÚµ²íB¡ð‹/¾¨¬¬d>RýÈ1Q]]ýöí[æÃ€š°··ß½{·ÜCK–,‘,®ÅÇÇ×ô C•T¬¢¢bÒ¤I………²‡tuuOž7n b,Ôc@5*++}}}å–ZµjuâÄ ”>HÛ¶mOœ8¡¥¥%{ˆ®¹eËæS)æééiaa‘õ/Ù!¤  @ÜÁØØx„ Ìç‰DqqqÓ¦MËÌÌTÜcÔª  ÁÁÁ÷ïß—m×ÒÒŠŒŒlÓ¦ ó‘4³³ó¶mÛj:ºlÙ²¯¿þZ­v`±X Ëúå—_°¼_³rôèQGGGÓ§O …BÅÛ·oÏL*P UP ¹W›7ovvvf>OÓ0oÞ<3#víÚ5`ÀºTžš2dÈ´iÓêÒsüøñîîîÔŠ««k«V­!,«ÖÎË &°.¨LIIɼyóŽ9"n3fÌùóçU© ¨ªªš2eJTTTM ¶oß>kÖ,&S)ðêÕ+‡ŠŠŠš>—²X,mmíÇã2²ª®®^±bEHH!DÁ•‹‰‰Iqq1ƒ¹ FË*cbbnbbB±²²úý÷ßUJãikkŸ8q"  ¦ååå³gÏîß¿\\“Ájbgg¤àR$}ûí·(14OZZZ›7oŽŠŠ¢ïr±X,¼<ÔÆ2€êedd̘1ãûï¿5j”ª³4AAA›7oVÜÇÝÝ}Æ ýû÷g&RMx<žƒƒCvv¶ìGS‹eeeõìÙ3###•d5‘‘‘1yòääädKÎ%ÌĉOž<©’` c@õÚ·oõêU””kÓ¦M[¶lQ<¡=..nÀ€'N|ôècÁdéëëoÙ²EîÝ/‘H´qãF” }ûöׯ_Ÿ3gŽH$’}Uc,€ú@•ÔB]VwƒµdÉ’ .Ðõó8}út÷îÝgΜ™••ÅL0YS§N:t¨l{¿~ýüýý™ÏjHWWwÏž=áááúúúR‡°Á€ú@• )5jÔýû÷=<<w …‡êÔ©“§§gdd¤J6¼Ü¶m›Í–¬7±X¬íÛ·£’>ýôÓ;wîtíÚU²cÔª M\ëÖ­/^¼¸qãF]]]Å=«««ÏŸ??uêÔÖ­[ùå—7nÜ`&!Õ§OŸ€€ÉyŸ~úéÀ™Ì¡[·nwîÜñõõ· Ê >°ú#@s‘™™¹zõêððp¡PXLJtéÒÅßßßÇǧK—.šzûöm§N¸\.!D__ÿéÓ§¶¶¶ ŸŸ––¦§§§Ä3CSÅçóuttTþª Í×¥K—V¬Xq÷îÝzŸAWW×Ñѱ{÷î=zôpssëÓ§OÃSýù知¥¥>>> ?0 U€fM$}Z¿3=zTrÙ”——ÓWÇ344¤/*̳€Z .—K_<"‘Èø_x;¹*++é«¥¬¬LWW—¾Z °Ï®\¨2€’•––>‘–––——G¯åö700066nݺu×®]$1œ¨[·n>|8""¢°°ðƒøàÁ'''¥ç …™™™’/ª/^s¹\@ Û_KKËØØØÔÔ´sçÎ’¯(;;;\47\.÷éÓ§’oG¹¹¹¥¥¥ååårûëëëK¾uéÒ…¾xLLLN*‘››+ùVóôéÓ¢¢¢ÒÒÒªª*ÙÎl6ÛÈÈÈØØ¸}ûöâ÷™®]»vèÐA¹«ÕhT@ ²²²ââââãã_¿~]S7‹ehhhbb"‰èM!Eìíí]]]ÝÝÝÝÜܰ!óø|þùóçÿøã¸¸¸¢¢¢Zûkkk—••ikk+åÙ+**®_¿wïÞ½ÊÊÊšzêèèЛŠeee5] Púúúýúõswwwwwïß¿¿²¢‚ºyýúu|||\\\BBÂË—/kêFߎŒY,VII‰â·#[[[777ww÷¶mÛ6NpP¡P˜œœL_07nÜ(--­©'‡Ã¡ãï*++KJJ¼)iii}ôÑGô×ðáÃ'»úB•ꩪªêÏ?ÿ>>¨a5àÒ¥KgÏž‹‹{ò䉸Íf·k×®‹[[[úâ‘ûvD_<999O%dddH¾uìØÑÝÝÝÓÓsÔ¨Q¨Ui¨ÂÂÂãÇ_¼x111ñÝ»wâvñ‡N:µhÑ‚¾ÕHž¡ªªŠ¾ZJJJ²²²$ßjÞ¾}+¥Õ¿wwwŸîÝ»3÷ªª ðÁnß¾vìØ±‚‚Ú¢££3hÐ zë¦_¿~ ßU®²²òæÍ›ññññññ·nÝß nÕª•¯¯¯ŸŸ_ß¾}øP|>ÿƉ‰‰÷îÝKMMMOO …ô¯¯ïÑ£GëwÚwïÞEDD„……]¿~]ÜØ®];zëØÅÅÅÆÆ¦áá333ãÿ•››KÙl¶«««ŸŸß¤I“0IG%''Ó·£¼¼<Ú¢­­Ý¿úâ8p Tªø|þ;wè+çÆâ›ØS§N1cÆÀøÀŒÊÊÊsçÎ………]¸pAügÅÜÜÜÕÕÕÍÍÍÍÍÍÁÁ¡áóª ._¾LÇ÷IÖ¼zöìéçç7}útkkë>…šC•ê*??ïÞ½’«ÚÙÙM:uĈC‡Õ××o¤ç-++»zõêÅ‹#""ÄÓ1ýýý[¶lÙHÏ µ*//ôèуùä“aÆ5^ÁˆÇã]¿~ýÒ¥KÇŽËÊÊ¢:uòóó›3gŽ••U#=/4PJJÊž={"##ß¿O[8yòd77·^½z5ÞŠ-999ñññçÏŸ?sæ ]œˆÃḻ»þùç>>>MvµQ@m²³³.\(/jbb  ™ŒAEûùùÒ$FFFK–,ÉÍÍe24œ@ ˆŒŒìÙ³§øCiÿþýwìØ‘ŸŸÏp’ìììM›6I.Z9xðàóçÏ3ê.//oéÒ¥â:‚¡¡¡ŸŸß¥K—“1„Babbâ¬Y³Ä CêëëÏŸ?ÿÕ«WLÆ€Z]»vmôèÑâ_ðöíÛÿý÷OŸ>e8Fqqñþýû]\\ÄŽ;îÝ»·²²’á$ @•IOOŸ3gŽxİaÃŽ;V^^®ÚT\.7,,¬ÿþ4•žžÞ¼yó²²²T› ꢪªêСCôg×¢E‹+VKJJRù/uVVÖºuëZ·nMƒµiÓfÛ¶m*ÿ«ª\¨2€|ïß¿Ÿ?¾x©Eww÷ÄÄDU‡’véÒ%É‘ß~ûmII‰ªCA.\¸Ð©S'ú󲰰ذaCqq±ªCýÇÛ·oƒƒƒÅw§{ôè‘””¤êP âr¹AAAâr§‹‹Ë¥K—TJÚ•+WFŽIjii}ýõ×ïß¿Wu¨fêÁƒâº-Cgffª:Ôðx¼;wÚÛÛÓ­[·>|ø°ªC)M3­2„††½~ýZÕAêïÏ?ÿ R÷WYååå'Nœ Y¾|ùòåË8(èèÑ£AAAÿý·²âi.—““SUUÕØO”››{èСõë×mß¾½±ŸÔDxx¸øNËèÑ£¯_¿®êDŠ\½zU< ÖÆÆ&""BÕ‰@ÚË—/'L˜ þ<¢ò[Ð ¼{÷níÚµtÉ‹5sæÌ·oߪ:TóuêÔ);;;ñÛÑÕ«WUH‘»wïN˜0ŽŠ·²²jJ—Ž¡´´tñâÅ´>nhh¸xñ✜U‡ªŸÏ?pà@çÎéËÛÙÙ955UÕ¡”@ƒ« §OŸ¦û‹8pàƒXUU¥§§G÷Åm¤lÔ?ÿüsãÆ†ü}÷îÝ7=z${hÒ¤I„ðððdÂÕ«W[µj%žekk[SÏ!C†8Ôà·ß~wëÕ«!äÆŒÄgÂÒ¥Ké—yôèÑZ; ‚¥K—>ÜÔÔ”~K9N·nÝöìÙS]]-Õ977·¦oé‚ êoçÎ’+3ûúú~ðWšæÑ£GâÑÝ»w¿r努ÕU\\œ££#MþÉ'Ÿ¨Ã |‰D|>Ó¦Mt) +V”••©:T¼{÷î믿¦Ë³µhÑâÿûÃ3ÿáùóçâb×®]ãââT¨®®]»&^vdذa>þñãÇ5͘ï<$ןþI»UTThkks8œ&3siÇŽâ/³.…yº½žž^=F5lØ0ñÐÁ¯¾úJªóùóçkú–®\¹².ñRSSµµµõôô6oÞ|ûöíÇãN@Ó&Ö®]K·711Ùºu+¦”‹ÏçoÞ¼™. §££³uëVU'jî}ºFïÚíããC¿ooïÂÂBU'j¦öïßOêkÓ¦ÍÉ“'U§þ„Bá,,,!ææægΜQu¢&®°°ÐÛÛ›þ 7NÝfÔœœœiӦѯÅÃã!7 ¡&IIItƒ¡¡á–-[ø|¾ªÕ_BBB·nÝ!gýúõ*_«²~4²ÊðúõkCCÃ-Zܺu‹¢««[ëÉÏ×_MÙ´iS­=뢦þQQQô“â‡+®h8R©°T(mÈkWñ-\¸ZëyhÙè“O>©w’ÆVÓWZïï^jjª‰‰‰››[XX!ÄÑѱÞÙ222èÜ?©UÙ&OžL «÷™{÷îM¹{÷®ân²“5(ì4È¥K—è6ïÆÆÆGŽQuå8pàÝ/ÀÞÞþÚµkªŽÓ¼p¹Ü3fÐ++//¯¦QèÉÎÎ6lý¢.\¨q·Ö5ŵk×è`XCCÃ&³¨ÁÉ“'ÍÌÌ!VVV±°š¦ …6l Óš>ú裇ª:‘”——Ïž=›¾ÕŒ1B‡kd•þÑ ôÓÃ?ÿü#·gNNÎìÙ³õõõ]]]ÿýw‘H4xð`Bˆä¯÷Û·o·oß>vìØ¶mÛÒñá;w^³fMii©Ô GŽéââRZZzòäÉ &ØØØôïß_rñáG9;;Óõ“mmmÿEŸ]$=|øð‡~:thëÖ­Ùl¶©©iß¾}>,y½úÝwß9;;ÓÁðƒ ¢gpuu¥·ñ#""œwïÞ-ïêÕ«>>>–––,ËÖÖvâĉ²›èlÛ¶ÍÙÙ9"""??ñâÅÔÕÕµ±±YºtiÝGܺuË××·U«Vl6ÛÚÚÚÛÛ;--M²Ã²eËœiÉÿ£>¢ùýõךNH—™ Rü¼¡¡¡ÎÎβ7<èîîÞ¢E [[[??¿´´´‡:;;Ï›7OÜçÌ™3ÎÎÎ7n”zlVV–³³³¿¿¿dãØ±c]\\¸\îÙ³g}||¬­­Ùl¶äbÞÞÞíÛ·×ÒÒêܹóüùó?h á7oÞ´k×®sçÎEEEK—.%„|úé§u¸”ììlú6$µ?sÇŽ !õ[BfÔ¨QÎÎÎtáœ!C†ÐŸàÍ›7E"Ñ´iÓœsssccc}}}Û´iÃb±bbbèù|þ¶mÛúöíkhh¨££ãää´nÝ:Ù:à˜1c\\\ÊÊÊ¢££}||Z·nmoo?þ|ñ0Ôððð)S¦XZZš˜˜Lœ8QvÙž‚‚‚ÜÜ\MŸ´ „Bá÷ßÏf³éð@MЮÀÇ?úè#:\YöO4’ЧMoÒJuuõŠ+hq¿_¿~éééªNÔÔlÞ¼™~üprrzüø±ªã(Szzz¿~ýèÖï¿ÿ^CïQ«•üü|ñ¦MfJ5uôèQºRƒÍåË—UçÃh^•áÆ,«S§Nt$ Ý([îÝÚ˜˜z•kmm=~üxºþJXX-Lˆ{®]»–Vîîîtj´‹‹‹ä¸†¬¬,BˆÝºuë8Žƒƒ½ „LžêÒ¥ mwww— IWï ~ø|þ§Ÿ~JÑæÏŸßd¦¤I*++  _ãçŸ^Óð+P–„„:½cÇŽwîÜQuœFqñâEúgÈÊÊ*99YÕqš@0gÎú«:kÖ¬&vÅHUVV~óÍ7ôkœ>}ºFìW¹ŒŒ úAÑÈÈHýWįŸgÏžõéÓ‡Vl;¦ê8@ê B¡–N:E[fÍšEY¼x±TχhiiI^Н]»–^ÛÛÛKvŽˆˆœ•  ÿúë/zÅ.y‰~âÄ B‹Å277÷çr¹ÎÎ΄‘#GJžÓÆÆ†"·Â½}ûöçÏŸ‹ÿ·²²ò‡~ „˜˜˜H5>L™2eŠìºwïN¹w…ÎÀoÑ¢…xT…@ X´h!¤W¯^’¥ƒµtuu×­[GßÚª««¿ûî;z]-û\R~ùåBˆ±±qll,M+ W®\IéÚµ«äG·´´4BH»víj=gQQ}·=þüãÿ’ $ŒŒŒ¤6¡K :TW®\!ÿÅb±¦NZ÷5«èâ£R£<èi9Ž¡¡áþýûé7‡U())¡ë{IŽŒ}õê­CíÚµK|’Ó§OÓ“tíÚU<ãâÅ‹4çÈ‘#{÷î-¾}AË@„üü|ñ^¾|I% àCq¹ÜQ£FÑ? M~ëǃÒU-½½½Õa#ÍuòäIº3ÑÈ‘#‹‹‹U§åääÐ¥&&&ôGäâñxt£S---ÉÍÅš¤ˆˆúk2bĈ:Þ£)ÿüó½ÚêÔ©SÓÞN¨²²ò³Ï>£÷ðä®Ö§ž4¬ÊpèÐ!BÈðáÃÅ-ô¢×ÃÃCªç€!{÷î•l¬ªª¢“NÇ_ësMœ8‘üw”] OKKKêÂæêÕ«„333q Ý1¡E‹uüº***¬­­ÉG¼ÓE d×àñxZZZºººâòçË—/uttŒ¥æÏ———Ó;É´…Ç „¬[·N²' Ìb±Ýzûö­¾¾¾Ôn|>ŸˆœôèQBÈĉkýòãââH $Ë´lѹsgqKLL !¤eË–R³=i†BGø‹D"@`hhÈb±dç5|òÉ'„ñH‘H´jÕ*z ,;‰—–cÆ/µâ@jj*!dÀ€µ~±«W¯&„ìܹ“þozz:ýÎ×}Ÿϧ”);;»“'OÊNIضm›ŽŽÎ!Cf̘@#!íÛ·¯ã®tñÑ_~ùE²‘þÆB.\¸ ÕÍš5ôï¥Ô<Õß~û¶‹[¾ÿþ{Bˆ¹¹¹Ôž#tü޵µµdÅD Ð_[É—wrrò¸qã&L˜€›õVPP@ßLLL4q-îzˆ‰‰¡# ‡J‡§rýúë¯têM3¹IËårGŒAët½¶¥Ê½ÿ~øðá„}}ý³gϪ:âããéŸ?þXgÝ«VRR½oÚ·o_©ÛlM’P(¤3¬ !ß}÷ªãÔ‰&UJKK­­­Y,–äŽ@µ°°ìI·6h׮쥽ç¼fÍÙó ‚ׯ_ß¹sçÆ7nÜ3f !äĉâô†Ô­]ŒþÔÅ#ÒéÕ¯ìoI|>?==ýæÍ›ôéZ·nMþ;ƒ‘]†®yÙ·o_qË‚ !Ë—/—}:|]|AH‡cX[[K]$çääBZ·n­ °H$ &„|ýõײ‡† B9~ü¸¸…þ2H•3äÚ²e !ÄÆÆfœ É\hÙBrsúiÏž=R'¼yó&-ˆÇÚ=~ü˜Ò±cGÙgoÙ²%ùtœùóçKõ,(( k Ȩ®®¦ƒ\¥ôK\-âøñã´ «ø’rrrÆçééI+¸ô~ѳgϤº¥¥¥IÝD:}ú4ýðWÇ·'zù!µ‰Ž¿¿?‘·Š—ËmÙ²%›Í–§CÑW¬¸…þrɾ6úöí+UZ¢è„š&6W@µ^¿~íèèHšßxï7nÐinÝ»wÇJïÊE‡UB.\Ø|&œóùü©S§BØlö¾}ûTG#åååÑi¶-Z´¨Ë®ÞMFrr2½Ò¹sçšözYçÏŸ§óÍÝÝÝëxç¬iøùçŸéXû9sæ¨ÿ{¬&Uè%®ŸŸŸdc~~>ý“öú؜͋ IDATõkqãçŸNjØEâã?&„œ;wNÜ"Nž<9tèPÉûÃb’ëJÒ7‚””©sÒ l6[|é¾aÃRÃ2¥¥¥¿üòK—.]è«D’ä5ªP(455%„È®Éü¿ÿý(n¡Å<©•ÿ(BˆxV$Ž![&HHH uØâ.B!µÐ#E§ IŽ¤Û¡ÉÞñ–åëëKY²d‰ân‹/&„ˆ×îÊËËc±XÚÚÚ²wKh™ÉÉÉIÜräÈBˆTÏŒŒ Zàl¤Wï’k=Rôž¼©©éHt@„Ôy¤\¿~]WW×ÃÃC²øE_ÕrçÅÔÅãÇé6RvjB÷à5jT­=«««õõõY,–Ô@>º€‚ì5""‚2fÌÙS%&&’ÿî8KkjRK:Ññ&l6[²Ö&‰ÊÊÊ8Žžž^­[É@ÑùM;v”­ 6y>¤Îz÷îÝ´‡ô3iûöíôÃÌO?ý¤ê,L_}õý(¨Y§ÕAqq1ý$ckk[¿õª5ÚóçÏé@NÉ™¡P“+W®èééÑÏÍp“—°°0º6ê·ß~«ê,µÐ’½®VO¡¡¡ôßt"½˜¶¶vUUÕ½{÷Ä·vããã !ôºW u/yÈÏÏïèÑ£æææ~~~ݺu377×××çñxºººôV!$''çÍ›7:::tMIt´¼½QLINN– ¸¸xРA?îØ±ã¢E‹ìííÍÍ͵µµÿþûïú&K¥§§·k׎Þr‘ô÷ßKž<77÷ýû÷-[¶lÓ¦TO¡PH¯¢ÅKèÑ`C‡•êIÛ%È*..~ýúµ¾¾>­\Hyþü9!DòPJJŠÜo‚¬º<;‘ù®Òjw—.]dËCt‚äSÓÇÒ[功:///''ÇÜÜ\<Å@ŒÖbŒŒŒ233eã988(øJJJÆohh¸råJú‚„KKË{÷˜Ðë®k×®kÖ¬ñòòJLL,++344TÜ¿gÏžG-++«õÌiii<ÏÁÁNº¡x<^ZZšŽŽ]±RÒ£GèùeOEçéˆ_„¹¹¹yyyææætùq±'Ož”••9::ÒÑ%b÷ïß}úô¡ïªÐ@ÞÞÞ©©©íÛ·OJJ¢óõš•nݺ%%% <8%%e„ 111tG'¨·ÈÈH:Íó—_~¯l×|°Ùì;wjiimÛ¶ÍßßßÂÂBö¯$ÈÅçó'L˜’’bmm””D‡.6+;vLJJ2dÈ“'OÆŽ_ëg¹æìÁƒÞÞÞ¾¾¾áááâ+¯æcÆŒ>>>¡¡¡ÖÖÖK–,Qu¢š©ºÌQWt•6lØ îL?.ÈÞÛ¿}û6!ÄÊÊJܲcÇBȰaäÆÛœ:uŠÒ¯_?qËÙ³g !ݺu“ÍF§ñÏ™3GÜB«’²ƒØé~ .”j§S–.]*n¡é%7>£Ïâ蜩%©»wï’ÿ®¿H‡cÈ£·¸àé4ÉeÄè|KKKq ÝD@ñ½}ŠîY@yôè‘âžtȆ¸ÐKvr×} ¯ÉÜÜÜ!âÅæÎKùþûïÅ-çÏŸ'òVúý»D\\\­_”¬ØØØZ%wĨ;º#ùïpžšÐÕRƒƒƒkíI×¶ðõõ•l¼qã!¤OŸ>²ýéxQÙÉ"‘(00Pò7ôܹsDÞ|¢ððp"o.ÆÎ; !_|ñE­™ VÕÕÕtÉØV­ZÉþ-hVîÝ»GÇ úøøHÍ"„K?wÕåK& é§)ccc©í½@.@@· 355½ÿ¾ªã¨Ò³gÏè–%£Fj šÔOff&½£ìááÑÌ¿Ktv‹uøðaUg©‘fÜLHH8uꔕ•Õž={d:t(**êÞ½{ôé4BHee¥TO:cPò7ÝM`ÅŠt3R±ýû÷y7Ãe§9p¹\zD§iBJKKÓÓÓi­A¬ªªêÂ… ‡nœ)VVVFG›K>Ýýû÷ !tUI|>?55•Ãáˆ÷‰¤“x<žìw†~½t›Còïp SSS©`¤æÁ’j}":\Pò„²cdÝ»wO(È"!–žžþþý{;;;ñ¾›´Ö+^C,55•na ùåÐ:ˆø›Fñx¼“'Oy?h¹ß ºo…xGŒ"ž·)©¤¤„.ááããÃf³k-¥ÉEç#tîÜY<–§&¥¥¥t. ]ÏB1¹CQ|sèè5Ù—GvvöáÇõõõiƒü;Göµ¡¸½.ƒb V_~ùå™3gŒ/\¸@÷i¶zöì=räÈãÇ·jÕŠþ)‡Eǃðùü€€:]´Ùb±X,,,ü믿ƌsíÚ5Ù[ iÁ‚Ç×ÓÓ‹ŽŽ–ú„ÖÜtêÔéÂ… ®®®þùç¬Y³:${ÅÑÌŽ92''§OŸ>§N’;Ͻùøâ‹/Þ¼y³jÕª€€ ‹Ñ£G«:‘<ª.sÔ®ººšNR]ä¢åq }[ÿý÷ß%»={–þÆ®\¹RÜHgH.ñ(‰­ê,êB<,¨.K§7+ÕÕÕôSbÇŽ›ÃŽuDïïI­t¦&4 Ê°{÷nBˆ££cMÀ’’’!l6»¬¬Œ¶Ð«A›ëׯ‹D¢ÂÂÂ={öн !’[ ÑEû @7§ÌËË[¶l™¾¾>½o/¹™…½½=!ÄÔÔÔÛÛ›nõüùs:ÜÆÆFrêòòrú‘eõêÕ×®]KII¡[TUUÑÓΚ5+;;[(>zôÈËË‹ŽØ”ºÈÿñÇi5!222%%åÞ½{"‘hß¾}Df Ì)S¦BFŒA¯·_¾|¹nÝ:6›ÍápΟ?/îF7\¼x±Üoà°aÃjýYЋLggg:%;;{Ë–-ZZZl6[rw ‘HäååE9sæL­ç¤—úsçÎUÜ.ÆñÃ?ˆ[-(tëÖ-"""11qÆ öööíÚµ#„téÒEòát³qãÆ=zô¨ªª*99y̘1t B©!èZî¾»wïÞ¥¥ÓeË–‰÷zóæÍŸþ9iÒ¤ÈÈÈZ¿X)ô'âåå%Õ. ékõèÑ£´%99ÙÁÁaÇŽ?ær¹•••Ïž=ûùçŸé#GŽ”9¶uëÖÀÀÀ„„„¼¼<ºsJtt4]3¢mÛ¶uY[H¼ø¨ÔNotpx¶Ž¤ììlºWèÿþ÷¿ªªªªªª›7oÒAÝ»w—\_ÍÎÎŽÈl! MLLX,–ÔJlÚÚÚZZZ’›ÛÓ–3gάõ ±ëׯÓw°ððpUgQ/ôjGWWWj7hPL ÐMûõë'ÞÑ D"Q~~>ý(2cÆ UgQSÉÉɺºº¨îÉ¢³G9ŽÔ_ÍÜÊ•+ !fffÍp¹b½™×½{w5|V÷*CQQ½ŽR°w.½™/yñSXX(¥fffÆb±ôõõ#""Ú¶mKÉÈÈ?öÖ­[â!7ô²ÊÚÚ:11QOOO[[[¼riAAí””¤­­Íf³Å‹2~üñÇÿ½3«i{ÿ:CušgEš4‰TÆšPD\Jfe&”©+c(]Dƒ™¸2f ¯(7¤B¥ 4Oš‡Ó9¿?žßÝŸý=§N§£:¥ýþÃËY={íg¯½öÞk=ëYÏÃÞã=<>>äëÖ­ƒöd1[@”‚ZXXÀv |¸ÑÜ:Nœ8ßE„¬¬,¸HíÆ•`ü&öìÙÃRž™™ ubÆHoùÑQ(”¹sçb)Txã°H"„ÌÍÍñ™A9ñÕÕÕñ…0áÇçeáÂ… ð4 b1#---ñÎ&ÅÅÅ! –†Kfúñþý{„аaÃð…* €›k! `2™eeeðMÁç'"À€m•••üÖ¥×Û?%%%¿~ýÊo]zØð’ÈmÉNUU•––ú¿¹É 0V¯^8p ‹÷tŸåÙ³gÁíîÝ»üÖ¥ÇQ^^÷åË—ó[Vzz\†¬¬¬õë×KJJNŸ>½-ooïÆÆFlÊ'##óñãÇC‡½ÿ^DDÄØØxÆŒZZZŸ?&“Éøyé˜1câãã}||²²²455Gmgg'$$´mÛ6YYY,è4¶G}üøñ¡¡¡ïß¿WUU511Y¶lûÖ ½{÷ÚÛÛGGG0 {{{(߸q£††FPPPII‰‘‘‘ƒƒÃ§OŸ<<œ‚K|}}·lÙ¢¨¨˜––9 ø aehŸ¦¦¦¯_¿ C´Hmmmii©„„„´´4¿u! èAÔÕÕ 2$''ÇÓÓ6MpÃöíÛ<¨­­””„%"`«  žžÞF±½‚ïß¿ëêêÖÔÔÏ›7ßêð‡ææfCCÃÔÔÔ-[¶9r„ßêô<¸}ûvUUÕÔÔT|^³ßž¨¨¨ &H¤÷ïߡ\B§Ó‡ž’’ÒC¬À„•€€€€€à7d×®]ÐÖÖNNN&v´rOmm­®®n^^ž——$i'0ÜË—//^¼˜ßêô&|||þüóÏþýûgdd`™žûÐJJJiii}³x£©©I__?==}ÇŽà·:݃Á>|xRR’³³óÉ“'ù­NoâÕ«Wfff ¥'ìh#üÿ ~7ÊËË!iå‰'C‡… †GŽ©ªªâ·:=ˆ#GŽTWW?ž01t”7êêêœ>}šßºðªª*ooo„ŸŸabè‚‚‚ÇGùùùó[n"$$$))INNÎËˋߺô2LMM.\ØÒÒ²ÿ~~ëBX~;jjjÌÍÍ'OžÌo]zöööǯ¬¬$–Ñ0JKKÏž=‹ê; ªˆ€€€‡‡BèèÑ£õõõüV§»9yòdeeåðáÃçÌ™Ão]z“'O677¯¯¯‡œÄ}xÉlݺ•Ø Íûöí£P(÷îÝûôé5!¬ C^^ÞÁƒºô,.##£KÏÒ«©ªª‚=™„Ã?ÏìØ±!äççWWWÇo]z~~~µµµ¦¦¦¦¦¦üÖ¥W2gÎmmí¢¢¢óçÏó[—n¥®®rÄÂ3EÀð&?uêK÷ß’‡&&&JKK;;;ó[—^‰††Æ¼yó˜L&8ñÂÊ@@@@À7ÒÓÓ[ãСCüV¾~ýº}ûö˜˜˜.=KrròöíÛSRRºô,½X9422š4io5TUUÑéôvÅètzuu5o§èZZZ~þüÉÛ±³gÏÖÕÕ-))ü>Neeå‰'B»wïæ­&“YYYÉ幺?d“ÉärþVQQÁ`0x8™LÞ¾};BèðáÃMMM<ÔÐK9{ölII‰®®îìÙ³y«¡®®®±±±sµêDêëë¹ñOa0\>ìLš4ÉÈȨ¦¦öÁýÞÀ. qqq~ëÒ%TTTtõ+nÇŽ$éæÍ›™™™]z"ÎPùxn‚>N/**4hЄ ðåDZu¨©©9::ªªªò[‘J]]„àÁ‘!??ßÝÝýíÛ·_¾|5jÔ¨Q£ž>}zöìY–.zúôéààุ¸úúú!C†˜˜˜ÔÖÖŠ‰‰uÑœÜÃÃãÙ³gmýUVVööíÛXv&“yüøñàààÄÄƆmmmccãššIIÉ .pyF˜.Y²ÄÇÇÇÙÙ¹'›8vìXUU•±±1v«G8qâÝ»wêêê&&&ÒÒÒñññoÞ¼Á‹eeeíÙ³çíÛ·999ÒÒÒcÇŽ500 ÕÔÔì¼KaåþýûÇÿøñceeåÀ¥¥¥cccñbééé;wî|÷î]^^ž„„Ę1côõõ=zôàÁ.ϵpá½{÷æää­Zµª ®¦ÇÑØØèããƒÚ¾}{G“Á×××ïÛ·ïÙ³gÉÉÉ eäÈ‘&&&ïß¿_²dÉòåËA&,,ìàÁƒàpD"‘”••/_¾L£Ñ:ýBØ©­­Ý½{÷óçÏ?þL&“õõõãââ–-[¶råJ¼ä¹sç._¾œP[[«©©illÜÒÒB§ÓoݺÅýévîÜ9cÆŒcÇŽmÙ²EBB¢³¯¦§öîÝ;111­7o^ii)üú믿ƎË"æää”––ÖV%ƒ ê¸ÊÜ’””´{÷î>äççKKKéêê>zô(""bàÀ VH‰daaÁ›?Â!CfÍšu÷îÝ¿þúëï¿ÿîÌËèL> ò .ä·"ÿÿþ‹:}ú4¿éÓlܸ!4tèPƒÑ¡ÃÂÂäååÅÄÄÖ­[wáÂ…Ý»w2† 'OžÄÄÊË˧OŸŽ255õôôôõõµ¶¶†ùèQ£:ûjþ?ÚÚÚ²²²ffffffÕLUU~‚I.11$+**¦M›†š4iÒáÇϞ=kggG¡PBC† éÐI›››!ƒõÕ«W»àšz t:]QQ!ôèÑ£ØÜܼaÃè;vì8uêÔœ9sÀ$ €—¼v횸¸¸ŒŒÌºuëΜ9ãì쬤¤}ïÅ‹z5ÿƒN§ƒz†††ûöí»xñ¢““¶|ÚÔÔ„I^¿~]LLL^^~óæÍAAAnnnXjótè¤éCOO¯³¯¦‡ríÚ5„ººzsss‡üôéÓ!CH$’ƒƒƒŸŸßÞ½{GŽ mîêꊉ…‡‡O™2ÅÌÌŒF£A˜Ûîù¥¦¦êêê’ÉäÅ‹Ÿ:uÊÇÇgüøñ ÞÊ•+1±êêj{{{x[þõ×_sçÎ@)++wèŒ C__Ÿåmüû77·U]]íàà`ffË‚‚‚ãÇg‘iiif‡ÇàÁƒBºººðsÀ€¡ÆÆÆÎ»”ÿùsçh4Ú€ÜÜÜ‚‚‚6mÚ„Y"##1±S§NMœ8ÑÄÄ®ÿië(qqqPIYYY']D‡!¬ |ƒ+ÃÍ›7œœÆ·`Á‚³gÏâ§ŽEEE®®®>üñãÇþýû§L™²aÃ†ØØXWW×ÏŸ?cb'Nœpuuýøñ#VráÂ…­[·BUÕÕÕÁÁÁK—.577733[±bÅ›7oð äå幺º>{ö,''gïÞ½VVVØ %%eݺu¦¦¦kÖ¬‰ˆˆh×Êðöí[WW×ÔÔÔׯ_Ãk×®ÇËž>}zþüùãÆ³¶¶vqqùòå ^ >>ÞÕÕûô~úôÉÕÕ5::úóçÏ;vì°´´//L&8p@RRrøðá 7G𛛇***úüùs¼z .D9::b…° ¿wï^ü³sùòe„‚‚BGÏ ï1ccã_S¿çR\\L¥RB,}î±°°5j”““BèÓ§Oø?ÕÔÔ „vîÜ ?á.\»v ~nÙ²!T]]ý+ú·ELL ‰D;vlQQV˜——¶T|/îܹƒ‚MjëÖ­ãù¼cÆŒA:uŠç~ÂÊ@@@@À7Úµ2À”IGGgÁ‚†††¡‰'Ö××Ã_?þŒZ´h‘†††¶¶¶­­­““Srr2BÈÓÓdètº””BhË–-XµÊÊÊ&&&ðÿÛ·o“Éä1cÆÀÄžB¡H¤'N`Â`_ºt©ŠŠÊàÁƒmmmW¯^Íd2ÃÃÃÅÅÅÅÅÅííímmm%$$`ƒ•áܹs! ‰iÓ¦988HII± %ÝÝÝ………ÍÌÌ-Z¤§§‡þ÷ß1ð2 Ÿ=B­_¿^NNN__ßÖÖvûöí\ßßoß¾‘H$„ü;|øð¨¨(nÛÁÍ›7Yʳ²²ÄÄÄnܸ?#""B–––,b--- uà99¹E‹ÁÿY¬ ׯ_Gi,**ŠD"™šƒQ‹g IDATš²×`gg7aÂ„Žž777—L&“Éä?~ü‚ú½›yóæ!„:úXåææŠŠŠ*))ÕÕÕ±ü òž€³ƒÁ066FÅÆÆ²ˆADýÐÐÐ_Q¾-À¬¦¨¨È®ž§§§´´tKK ü433C½}û–EìÍ›74Å&Ë ð¬mܸ‘7Í{………ðAÁÛ¸ÁÓÓÿŒc@Ð_¼³àííM¥R‹ŠŠ`VÙ»lKy}}½ššVž@¡PFŒÁ^ÃÒ¥K ;zÞ²²20effò vÏ ìn\Ÿ¿cÇŽÁv'¼Ï “É,))Á¼X¬ {öìA•––þŠþ­ÒÒÒ2bÄ2™œœœÌò§§OŸ %%%±”OŸ>]GG‡ÉdŽ5JRR³xv°SðÑ,EXøXFŽé‡ó‡¼{÷.Ø 0_ÓÍ›7#„|||à'XB,«÷ æææðøÜjiiacšôôtü.;;;77;¶´´TCCCBBó²+B( £Óé:::òòòiiiP»aÛµ2P©TÌEðË—/JJJªªª˜rrr2ÄFRSS °’V­ è¨í–î+°¤È† ,À/òÓÔÔ$  ¨¨Øêb5ÞuÌ^­./ߺu«ë|•ÅÄÄV­Zÿg±2<~üýçW1É[]^f0õÙ&Nœˆ:|ø0¯º÷n~þü),,Œ»Gq„©cñyÞ¾}»k×.ø?¼ŽZ5 nÙ²%??ŸµÛˆ`j°€õùÜÜ\ÔöV ü£Á=ÏŸ?Gõë×·Ù‹€Ôfff=P[[›D"AP8À¾‰F[[{Ú´iL&355!´bÅ žôå„PAAûŸð]bÛ¶m¡‹/¶Z oÇÎÎ!äááÁñ=Ø ÈÛáûöí(..†ª¤¥¥±%&“™——‡÷Ëc±2€ãÕ÷ïßí Z!)) Ö‡Zý+{7((( R©`2™Hèï¿ÿæíÔ˜Y*##ƒ·~ÂÊ@@@@À7ZM” ** 7nFûØÕ××+**8~‚•AOOer8þ|!!!X£óöö $‘H%%%L&óÔ©S¡—/_¶¥,!b#9°2°Œ³Ÿ>}Ê>…€xfíZ°Ei–/0«; ,@ÿ…ef¶ae°µµmëð>E«qCI$FóôôĹðÀ0ˆ›É,;ûö­sÕnGGÇ»wïÂÿY¬ ?~ü˜2eÊׯ_™L&„¨dq”ýE`0Úw6Ò³iyˆ¸±zõj„н{÷8‹Á pêN "6Çh °a-^¼¸OÝÒÒ[²;ç¢×‘Ο?ß¡£)Ê€¸”ŠŠBaþVæææ¢¢¢?þ옮\ÓÜÜ,(((%%Õ®¤ B(::ºÏŠÒÐÐèÄ:{0æíÞ1ŒAƒa#ØIwùòeL ±±ÑÆÆósa±2|øðaÊ”)ìžM¿xÛ­_¿žKy‰”““Ãd2kkk¥¤¤ŒŒŒx>;$viËœÚÕ™, øŒ]ޝ_¿BùçÏŸ‡Ú¯_?L’F£™˜˜|ÿþvcÆŒ÷x KKËÆÆÆ×¯_#„ÂÃÃÍÌ̬­­™ÿ¹»‡‡‡ ãÃ/'$$8;;Oš4ièСƒ†EÈœœ|0½ÄøôéBˆ%ïË϶hõ(¨ [²d‰©©©®®îàÁƒ_¼xÁ® ,êõMbbb233ÅÄÄXÊ™LfccãîÝ»µµµaÃ' à‡¬¢¢Òî)²²²H$¶ªÛ š5kV«0`ÀÓ§O!\ˆ²²r'žzöìÙbbb))) XmoáÊ•+¡Å‹wôÀ/_¾ .:UVVêì[Æ àCÑ®z]Ñ£Èd2lš€¶ý]IKK‹‹‹£ÑhsæÌéÐÙÙÙ---ܼހ   IIÉ™3gÂÏ5kÖÔÖÖBÔÉ® ''§©©‰õ¸¯r¼¼ü—/_º:ct÷ÃÌ™3yË ñêÕ«¯_¿.Y²~Ο?_RRŸóHPPðñãÇiˆ‘#G>}úü¶:._5AAAfff /""²dÉ’ØØØÄÄDÞÎ rõêUÞÿE+Ÿ¡ÑhŠ8À¬ÐØØX^^Ž71-??+a—ïððð†††¨¨¨I“&)++kii…‡‡3Œ—/_Ž?ËÌ2|øð{÷î ÚØØ¬Y³†k, Àá¼?~ü`/dùÙ­"„vìØamm-''goo¿f͈·Ì9!9—§ÎÉÉ¡q¬ß"„Ž9Â<–ËÝÀÀ ]aNJJâ¦ò‡‚¼››gIrŸX`2™ÐÈsæÌ177ç ¯]PP€•¼{÷NOOoðèêêFFF"„”””˜L&¾ûõ(Ø/ä?þŒcÍš5­STTžƒÿNŸ¢ººбNË=Ø {®Q¬Óóâ{²»»;¾«XYY555±÷¨G 2ÓÓÓÃv®q„º c0p1=:eÊ”ŽN @"‘¸ìõõõ7oÞ”““Û»w¯»»»»»û»wïH$øÍuŠŠŠ$ ßsÊÊÊFŒï<0¹eï< .Ä‹±©CP©TØ4Íû;/Xx4x’PFEEA7ðôôTPPˆŠŠÂ/`ðöWÍ7`000ÀQÞ¿ÿéÓ'ƒáþÅÅÅ!žû³„„Dvv6¯©_‡Úý§$ h!!!99¹¢¢"–r(ÁÒ¼µŠºººººzxx¸••UCC&Nœøüùóøøøòòr(¶nÝ*,,ÉêBwïÞ=~ü8K,î°¸WTT„ÏÏ®m«°ˆÁO¨°¬¬ì¯¿þÒÖÖNMM…샡ââb,.}[°¨×°ªß®NÇþÃ<ÌáBíÊC*l„ƒÁà¦rÈ¿…jnnæF^__œVØ)MddäðáÃO:>í!HK[š===++«ººº¦¦¦‹/@†¿aÆ%&&&%%uî]g¡§§Ÿššª­­ %sçÎûHDDDVVÖÚµky¨vâĉ7nÜxùòåöíÛ;SÝÏëׯétúСC±—÷@èÖ¤¤$[[[bÆ 1ž•ä ö>?mÚ´ÊÊJ„PbbbLLŒ™™…B«À‹YXX´´´”——ß¾}ÛÔÔv>w}}}99¹ÒÒÒ„„Ø‹þûo¡I“&uô@111UUÕìì슊 iiiÎÂwïÞ­ªª¢Ñh0ÉÄÅÅÞ½{תÉõUWWÿúõkII X·eeeíìì`Ûÿõë×ÅÅÅá­§§÷êÕ«OŸ>a98íííáEúúõëÔÔT\„B–––gΜ‰ˆˆ`‰ÂÓ«)++KNN&“Éæææ<^SSsûömqqñàà`–?;wÜ3ùû«füøñ9«°°044tòäÉØh'((ˆB¡¤§§ƒ ,,|õêUHOÓ!&L˜ðøñã—/_êêêþòÕt —€€€ ‡2dÈOŸ>áWBêëëß¾}«¢¢"**Êù؉'ÆÇÇߺuKQQÊ'Nüòå ¬ ÙÙÙVVVøYlµà ÔùòåK|!d²l–£à'|‰ÓÒÒB‹-Â>º¡7oÞpS-·†òòòç΃ €„„ĨQ£òóó±!šˆˆˆ¯¯ï™3g ~›¹¹9Ì…`ÎpøðaîõÉËË;pà€››[«QH0êëë/\¸°fÍØ Ï!,ÌŸ?ÿÌ™3gΜ3f …Bquuå¹Ú¨¨(ÌBÔG€g.¿£Lœ8‘D"si²¬¬Œy,úæ×¯_ÛÆ¢X744pS9–Á»¨¨ˆƒØTUU[#„Èd²€€€››[«±µ¢££I$Rÿþýñå°º‹¥ÃòîÚµ ß‹êëë===§M›†/`€0`‡°êxÓ@\\‡›ÈýOKK l»Ý¿?KHÔ… R©TÕr|m^½zÅs ½0-qˆÌÊ™•+W"„ðYè[ZZ‚‚‚LLL°¤qLgðàÁéééøÃcbbÆÏ§6<<ë*.\hëì8 ÄæÌ™Ã.°|ùr„Ђ XB¾Áä‹!zûöm„®®.DÅ€œÁGŽi·ZåäÉ“!ÞïáÀ<¿ÿþ¼^TT$---$$ÄÒ÷ œœvîÜ ?srrÈdr«9VMLLZ &$„ŒŒ ‡Px {,,,”””xüø1ËŸÔÔÔðata‚÷çŸÒét¼lÝj+o»€)™ýì½HäææÆÛáfffªªªì9’ Öõ¥K—Øa‰þØ*eee4 ºçÄ%`6‚O0˽fþCwĈ,‘a½Ü¼y!ôðáC–ë««ÅÅÅÇŒÃAÀNNN®ÕR] ae àœ­ L&sãÆ0=³±±4hBhöìÙØTísÛV†ÂÂBøæáÓh >ÌxÉcÇŽ!„„„„¦L™bll,&&¶wïÞv­ L&óÕ«WRRR"""ÖÖÖâââþù'7V†-[¶HHH˜™™M:ULLLLL 3:0™LGGG„””ÔŒ3†ª¢¢²~ýúβ2üÆ€3ÿªU«Ø­ à2cÆ ÎYÖ÷ïßO&“7oÞ|ÿþý7oÞx{{ÃrÜÆ1±””Ø.1bÄwwwŸ©S§‚'g«i ±P‘ …CVÂ+V` ·:(d2™¾¾¾Û¶mƒbbb²mÛ¶={ö°$éLJJ‹€©©i```LLÌ¥K—œœœdddÛiĶZûöí㹆^Gyy9™L&‘H<ç/++£ººº‹‹‹¿¿¿ƒƒƒ¬¬,BhÞ¼yø!ïºuëB¢¢¢NNN~~~ÎÎΚšš!MMM|’’À›6mjëìWÐÕÕe(--3ŠŽŽN@@À›7oBBBÖ¯_¯ªªŠJMMÅ$ao‘¸¸øîÝ»Ÿ„¤ÑÀñãÇÙnÞ¼ ê-^¼8888&&æØ±cüñ‡€€€……&–‘‘n##£3gÎDGG_»vmùòå°ÕÖx¾‰›7oæíðÜ—Vs$s¦  `×®]$iذa;wîÄ’dÓét___X˜Ðh´ 6°×Y^^a‡ Â9¼³³3F“——Çæ,477ïÝ»—e󿂂–-[XÖýBCCYvFÐh´9sæäææv°IþìS‹å¹† x0qð4á†ôôt333*õ!䬭­cbbà¯k×®%“ÿÿ¾oQQQì;xòäI,¶1…B À׬   ((¸fÍΧ†)ߘ1c0×6233---ñê!„ÆŽûìÙ3¼XMM³³3Kê55µÃ‡óÜ2!!!¡Ñ£Gó\CE¨Tj«S}Î@Î,ìvc·õÇøïÅØ±c¡üóçÏì‰$DDDðVE<‹/èß¿ÿƒ8¨›e„……[õ¬‚ƒƒY≊Š.X° ¸¸˜ùß" //Ùvœœ° ¤ÂÂÂQQQm"&“ !½Yž…n€Äü/fA—¸jÕªÇC"q‚NDBB¢ºº:333%%Kú())éååµfÍ–¡0gª«««ªªÔÔÔÔÔÔÚŠ8ÕÒÒ’ššZRR¢©©©¬¬Ì!'Ä­dO±É7ñÞ¸„Á`dddddd(((¨ªªò¿OJJʰaÃäääJJJ:E½žÏvíÚµ|ùr,åʯðåË—oß¾©ªªª««s襥¥‰‰‰rrrZZZœCqÙUª««………Ûíÿ999)))ªªªĦ¯,”——'$$ÐétUUU555l6ËÓ§OüøñùóçaïÆï„²²ò÷ïß“““Û Ó.õõõ L&SKK‹Ë\Bœiii©­­å&ó7}¬±±1%%%??_YYYMM ۤÃÁÈÊÊJOO—““SSSëß¿?/ªÿÇ÷ïß•••ÅÅÅ«ªª~¥žBxx8$Òæ»‡_üüùS\\¼­wFsssSSS»1³JJJ -¥ªªªªª*±cyÀËËk÷îÝ+V¬ ì†Óa9&z7ùùùÕÕÕ‚‚‚êêê0P£P(k׮ݷoŸŒŒLGk‡¤˜œ¡P(  ]¸‘ì,BˆL&Cž°N©MSS“L&—–––——óФ½rÞY ¨¡¡ÁM”D999|pÙU ¤»Àˆ¿]1ÞÂ¶ŠŽŽÎãÇñÁäjkküøA"‘`ÛË/",, ŽZ…Bá2¹&7}LHHhäÈ‘X‰¶ “ÉÚÚÚXî›_DIIIDD¤ºº:??òeöjàÀç«êQp’ËÏœ¼¼<‰W~hÛîÕ9&z7!MMMp­œ8qbbbâñãÇûÈ|¸ Ñh0 …¦î À•öØ¡ÿo´íï×£ ÞŠŠ 9 s!‘HZZZ¨Gvž–––ºººB¼jº~½j+A7aeeuïÞ½v—}: ~ÙÙÊÊêÅ‹” á×r¿è\_v~×WÔYëö­ÍÛ;OuuõàÁƒ!]—ôp_†ß---‰TTTI£º ÂÊ@@@@@ÐM¨ªªþñÇX4f‚Î?Jã¼›€gzÅœðË—/[·n­®®þÅzŠ‹‹+++ÔÕÕ;E1v G}ùò…N§ó[—΄°2t=ÖÊ€ÊËË›7ož©©i||<7ò„•¡«†À“ÝìÎ@Xz7´¥u)0¬ÇçGì477=zTKK+((èWÂ{Ãejhht(n(A‡PTT„L–¹¹¹üÖ…•°°0žmUiiiˆ°2t1=Ùʼ~ýzÔ¨Q«V­â1·¹¹9''¦‹áË÷‹°2ôn***B„“H—"''‡þkêNQQÑÒ¥KŒŒ¢££y«èQÝCíTׯ_×ÖÖ¾té¶*˜U§Kæ-..æ·"œ`0ššš¾¾¾ÍÍÍ­ÊTUU1 2™LDêRøòª!LÔ½Xuä&U$Ï@\ú_ߌÐm¼ÿ~ܸq ,8tè’’R‡Ž%zT÷Г;Uaa¡““Ó©S§Œ¹?.‡Ë<¼Á¡çTVVv»Fÿv•ª««·lÙröìYÿ©S§¶*Ïe.žáË«†°2ônˆ9a7ãàž9!l &“yíÚµ{÷îíØ±cË–-ÜÇü'zT÷Ðó;Õ»wïLLL-ZtðàA.“&óÆn€CϹqãÆÚµk»]£6w˜ŒŒ ???ü梷t|yÕV‚Þ 1P븥ùúúž;w®[4j…¦¦&öÂúúú]»v=zÔÎÎŽ›zˆÕ=ô|+BˆÉd^¹r%$$dçÎ[¶lâ,Oø2t=Ù †Ož< sqqÙ³g¤¤$"^5Ýae è0ÄÊs7Àå°¾¸¸¸§…dƒµÄÜÜ\{{{ ‹€€€aÆq>„èQ݇NåîîÞíêü¸¸8–’úúú;wúúúΚ5‹Ã±Ä¼±€æ­­­e2™$‰ßêt€––__ß+W®x{{/[¶Œè-ݱc‚€€€€€€ cÐéô††DÌ »hÞšš~+Â#`kxùò¥¡¡áêÕ«===eeeÛ†Ë$zTWáS:t¨ÛÕáôŸœœœÙ³g[ZZèééµ* —CÌ»h^ƒQWW'**Êou:t¤’’’5kÖ´´´@TB¢·t5|ù~9&z1 Ö²èt:¿uùiiiAQ(~+ò«0ŒÓ§Okjj>xð -¸L¢Gu5½®SÁ1""ÂÀÀ`ݺuåååì2Dçé°æíE¹¹y\\ÜêÕ«Axº¾¼j_‚^ ‰D­©©©©©®\âììüñãÇ®S¬'³{÷îiÓ¦u說*Ôû×ÜH$“É”‘‘ñòòâÐp™]øŠ‰‰Ù¸q㯪Ø;QSS»qãFG꽊Á`œ:u*88ØÃÃÃÙÙY@@û“¸¸xcccuuµ¢¢"÷nÛ¶-22² 4ílÚ´iîܹ:\ß©T*÷!]ù¼|TUUñb óÃÀ=MMM¦¦¦¯b/áÅ‹u4ãË«†°2ônÄÅÅÁÊС£¦L™¢¯¯ßE*õp455;zÈﱘL&¯[·nïÞ½ÒÒÒÄx³2())999ýŠz½ÎíÙ½½SÑéôææf–BqqñÒÒÒŽÎ---ÕÕÕ;OµÞÄ!C:z‡I£ˆˆˆ‚‚B'¨ÅL&³¸¸¸Õ? ïܹsóæÍxËoQ )JŸ}Õ „;z_^5¿­•!    `ݺuÊÊÊœ%ïÝ»;cÆ (ùðáÃ;w†ŽY‹ŠŠüüüäää¶nÝŠ¸gÏž¦¦&aaá.ºŠŠŠ ‰$%%ÕEõôd.]ºôùóç… ¶¦‹€€ #..^PPÐÑ9áŒ3ºHŸß’Þ>!DY[[ûùùéêê¶+É›•AYYyÍš5<*×'齊L&/]ºÔÛÛ»_¿~,âmÞhmmÝiÊõ8ôœ%K–,Y²¤Û5úÿTVV²[ÜH$R[ÉPy¶2¯šAXÚÇÅÅ%,, û)  ¦¦6räHWWW|Ÿf0;w­Ý¶m[»u;vìßÿ577ÇJnß¾}øðá}ûöa%QQQ‡²±±Á¬ ß¿÷ôô”““;xðà¯_žššš³gÏÞ¹s'..,ÄòòòC† Y±bÅüùó{éþ«žÆ?ÿüƒ÷ê$‘H :::kÖ¬>|8Ããíí‘‘±`ÁÎbÎÎÎØOx(FíââBاú½"^o‡Ëü|ëÖ­ûã?ºE£VÈÉÉ™7o¾¼”µ´´|}}§OŸÎe=Dêz]ÒGèN&Lð÷÷1bD«2¼ùÀthÞÞs ·úîw IDATµ*C¼jº¾¼jz™•áéÓ§YYYø’”””G?~üÝ»wP˜žž^[[«®®Þ®“ÉŒGáß•P‚ŸmÂÎU¼ {I§ðäÉ“U«Výøñ!¤¡¡¡¥¥UQQ‘¹oß¾ÄÄD‘Î=i$**Š%ÓXZZZddd``à‰'œù¥FMMMff¦P»~tOž<ÉÉÉÁ—`Åû÷ïÕÔÔºPK‚ž zoúƒ^—ûZ•••Ûu¢ì:ØËâââ{öìqqqÁïœo¢Gu:•««k·«ó?ÂÂÂ>þŒ/ãÀ9âààÀáXè<„•¡Ké=>¼páB¹6¡·ÔÖÖ2 2™HJÐUqÚáçÏŸ_¾|A%&&ÂVÒÜÜÜ={ö”——oذáÉ“' ɽ €D"’H$!!!¬›Â´iÓêëë©ÔÎlÀÛ·o/X°€N§Ï˜1cÿþýPÞÜܱfÍšÊÊJÂÄÐ)À ݾ}»··7B¨®®îÉ“'‡úðáÃÖ­[gϞݡE]ABB“É6lç>VVV&†ÔÔTp‚ÍÉÉ Ù½{wii©‹‹ ‡â¿ òòò!ƒ#Aç ÐÔ½2™¼|ùr///vŸöv!zT7ÐÒÒRXXˆÚèTþþþÝ®Ñÿprrb±2Ðh4www77·v· 8!”››Û…úõy y¡©{ BBB[·nݾ}{»Y6ÅÅÅi4ZCCÃ?øhŸýíáË÷«7`Þ…_ÝUQQÙ´iÓüùóB¯_¿†ü:è?g¼Qû;4 obÈÍÍ-++ëׯŸ’’VÈne P(4ó ÃIÙùøñ#˜¶nÝzÿþ}ÌÄ€°¶¶NJJòòòê”suQ <×É`0:ýÔœa¹¡"""ööö›º¾¾þÇ­Õézrh.-eÐÕEDDttt DUUuóæÍ°ÎðúõkNÝ¥pyÞ©×ýý§'0cÆ ÅÿPUU;v¬‹‹ |Eú ðÀ»h%&&òOßh^ìeÛÃ155‹‹;wî&„¶¶6‰DúñãGmmm§ëF|ûö­¹¹Y\\¼ÿþüÖ¥,X‘‘±gÏn"‘ <!”‘‘Ñõzõ] y¡©{$ÉÎÎ.--ÍËË«]Èkii¡ÿûý"ètøòýêMV˜w±¯îÚØØ „jkkëëëñ’#FŒÈÈÈØ°aÃðáÃ…„„455OŸ>ÍRg`` ¹¹ùõë×Y΂ŸÝÉÈȨªªb…æææ%%%XÉÌÍÍŸ>}š‘‘±bÅ ===!!!mmmŸv§Lt:}éÒ¥t:ÝÒÒòðáíz‰‹‹¯^½_ÒÔÔäçç7bÄQQQ¦¯¯ðàA–”³L&ÓÚÚÚÒÒ²©©éþýûöööŠŠŠjjj7nÌÏϙ˗/Ï™3§_¿~RRREEEøJKKÍÍÍa—éÙ³gmlldee¥¤¤&Nœ˜––Æ®gss³¯¯ïäÉ“û÷ï/,,l``àããÞ69::úÏ?ÿ5j”¼¼<•J•““377ö싘§§§¹¹ù?ÿüÃRþðáCsss__ß¶š”°zÀ‚ÁÂÂ>Ÿ¥¥¥PÂd2oß¾½|ùr]]] Ο?ÿ*,..677·°°hlld?—¿¿¿¹¹ùÙ³gñ…)))ŽŽŽ†††4­ÿþ¶¶¶))),rie173ÈOVUUÕÔÔ„2™ÌË—/OŸ>]MMMPPPWW×ÍÍ ïbnnÞj4ƒ}>55!ôúõkó¶é ƒÁ˜}:‹þJJJ EGGÇÚÚzìØ±˜å(44/×øþý{–Ãׯ_:vì—Í…n¨¤¤$¾¡˜L&f3ÂNCvCCÃéÓ§c6c™ÜÜ\a0°Í |mðäææ ‹‹‹bÂ[·n¥R©$I__ßÖÖš]@@œqX.üÝ»wœ¯Ò ¬[·Ž¥ì/:::XÉ·o߯‡755µ²²‚ÇdèС VžAƒ±Ÿèܹsлàç™3gtØÀ2'3™Lp¶ÔÒÒ:xð …BQWW3f „/JOOgi+333èT&L°²²‚ *ÚÚÚuuu˜Ø×¯_Bjjjû÷ï'‘H’’’†††222UUUœê÷râÔÖÖÂO°T"„–,YÂ_ÅøÂû÷ïB***X ¼—DEE<ˆ=ã¿øš&''ó[NÔÖÖb¯…_dâĉ¡ëׯwJmì=z!´páB~+Ò ŽŽŽŠŠŠ/^d)qŒØ\ÝÝݱB˜ï]½z•¥Â… "„¼½½±’;vÀÄû00 „аaÃX.œJ¥bÍØàfváÂ|aSS)° gUU•žžBhùòåX‡)))¿„Xö$‘H555ø «ªª(JJJJ[šdddÀÆž”k×®!„¨Tª¶¶vTT–•• 4ˆ¥YjkkápttÄž”²²²ñãÇ#„öïßIÞ¹sú³ŒŒ ö655qn¥ß+“ÉÇCCC¼X]]ƒƒÃ„ Ö®]ûöí[ìOAAA7n¬®®f©ÙÛÛ{÷îÝØÏ–––óçÏ;::‚©ñÞ½{xáþùÇÕÕõû÷ï‘‘‘...ãÆ£mIIÉž={¦N:f̛͛7³˜Ì>}úäææ6yòd›Ý»w—••ýr“ôi~þü /Ö%ÀÊžqêêê,7Ž £”——Ã'¾Ý×òoBÞ³g¿ùmYµjË7®çðìÙ3žÍ÷t:†ÄÄ‹½‹hll„5üp½÷rùòeü:A§ó÷ß³¯"w½&úc]]øÒ`L&355ÕÍÍ-!!AZZ6Õ£ÿvª“H¤k×®YYYA!F[¹rehhh^^VgQQQ~~¾¼¼<Þ Œ›Ðì%)))urß¾}x‡ómÛ¶:u*???99Ÿ,O~~~BBBˆûÔ¯GMKK›6mÚ7°¨Ñ***nnnÎÎÎ÷ïß_¾|9‚'¹´´ô³gϰHÓ¦MSQQÉÍÍýüùs||¼¬¬,”Ï;×ÕÕ Â4»X™7oÞ`[vìØáää‹iµjÕª’’///°JàF±|ùòððp0ô „„……Y‚'‹‰‰:t(88òääd:n``€œjiiILL$“ɼ¹ƒÂá·K”——Ÿ8qâÀ¡€€lÛ¡>@B¨ÿþ{÷î?>^Oƒ·oß²ìzx÷îÝõë×ÕÔÔ6oÞ %±±±ÞÞÞJJJaaaXÆ`‰äááqåÊ•äää’’l­ŒN§6 3f v(púoL]]ú¿¡}ÒÓÓgΜùõëW ™ .œ;wÎÇÇgÓ¦M àïïo``àää„òåË—;v,[¶ ~–——Ïž=;22rܸqJJJ!!!AAA+V¬ ˜˜˜€€111???))©ÊÊÊŠŠ ##£ÜÜ\CCCCCÃòòòÛ·o744`êüùó6l––?~ü—/_<==/\¸ðìÙ3°…ð€„„„¢¢baaazz:þåÆd2B¹¹¹³fͲ´´ ঑SSSoݺ[\\ldddbbB§Ó+**°žÓØØèçç¦ „Fsqqi7©Sg‘˜˜xëÖ­¸¸¸¢¢¢Q£FÓéôššš-[¶àŃ‚‚¢££ dbb¢¯¯ÿþý}ûöñ \ÛTTT8¿–'`-¡Õ­‘¥¹¹ùÊ•+QQQ?~TQQ1111bDhh¨»»;‹þóçÏÿù矘˜ …bbbbbb’`llŒ 纂¦¦¦¿ÿþ;&&&11qÀ€ÆÆÆ†††?Þ¹s'K8ºÇ‡……ÅÅÅ1™LcccccãÄÄÄ &X[[óp^h[hçžÆ¯48…BÑÐÐHKKKKKƒø¯™™yãÆØØØ?~Œ3ÆÄÄ„J¥æääÀ² FMMÍÅ‹ccc“““uttLLLzäÈn¢t”œœœóçϳo(Ê’%Kðw¶ªª*00ðÇŸ>}ÒÔÔ466ÖÑÑyòäÉ‘#GxûŸ••ÕÒÒ¢¨¨ØÃ3YrI§¼j®\¹òéÓ§¶þª¦¦Æ2ÉJNN¾sçNlllii)|æêëëÁWº+ˆŠŠzöìld&‘H£Gž={6‹Lzzú•+WX6¿c¬X±–ô:ß^5ÝlÕà™·oß‚ÂTUUUUUŦ‚ªªªÏŸ?Ç$á½3kÖ,–>|ˆš6mV9)¬­­±XË•’’ÂáÒÒÒ°ˆ7‰9J0ÿó'ïׯ~ݘuêÔùóçÙCâã-m`È€Ï?öÇ=eeeþ‡Á`TVV’H¤~ýú=zÈ!...,Mšœœìççžö¯'ø;à}nݺ5~üxøÐ"„ a£Mpp0¸ýã¬Xu(ô#•Jõ†:hÐ 33³•+WÂ+!tçΦ¦& ˆl‚Lªø[c``†¿ww÷†††àûÆÛ·omllªªªNž< îµpûÚz±Õ††üŠ:«xõà’,XÀ©]úŽŽŽ ¥¢¢âÕ«W «W¯ÆbÄ>þ<**ÊÇÇ{é)((lذ!,,,88x×®]¢¢¢vvv—/_ÎÉÉ[*“ɼté¼WBùùù‹-Âj11±mÛ¶9s&((LcÀ¦M›ðÝR0(Áüw¼½½étz`` 6F722²µµ½yófvvv‡BFñÌ“'OÚͲ¦  0kÖ,„P}}ý¥K—Ú­sܸqÐÔÉÉɰ’3Ë–-ƒ‡ôÎ;XÄÙ¶PQQ8Ç•••7nÜhU¾ƒÿý7•Jë6 åÔ©S×®]Û¿?åa‘ñ÷÷ß´iÓ¤I“®_¿ þòãêÕ«ðδ´´ÀF9yòä²²2„Е+W:ÔÕ¹–Oœ8áââ2uêÔ«W¯Â“Éd:;;Ÿ9sŸ ¡¸¸U<ÀzïË—/­¬¬ètz«‘zÛååË—! ‹N¸Œ^˜1cDEEüø‘™™‰uˆÊÊÊñãÇ×ÖÖÞ¼yûÄÆÆš™™566â;ÕÂ… ïß¿¿yóæC‡AϬ¨¨7nÜçÏŸy»eÜPUU5a„ººº{÷îA”k„Pbb¢©©iUU¾S9::Þ¹sÇÝÝÝËË œÕkjj,,,>|øÀ[ŽØØØúúzeeeü”ø·ÁÒÒòöíÛíΚ8ð÷ß/_¾|üøñ7oÞ„/HKKËúõëÏœ9ƒï9_¾|155•””Œˆˆ€O¡9sæ0™L¼d'7½²²ì°zzz?þ'ͦ¦&!!!, }vv¶©©©ŒŒLdd$æÙñìÙ³éÓ§ÓétÞ:¼Ž`-ç7@DDÄÈÈèõë×/_¾„ÝÓì^ÔÔÔä͸ö›MY€Ð¡oÞ¼ijjÂÖ<:DiiéŸþ)//ÿäÉÌ3‹B¡øûû?zô?9_·n]}}ýãÇ1BÈÎÎnÑ¢EW®\é¢ÎC÷V÷O R©Tl¾êêê ¦jüækkk///wwwÞ:8ÿB#ÿXZZþŠ•¡©©‰Á`´•fF pGrrröíÛ§®®ŠõLóçÏcÛº”   ‰cÇŽ½~ýúâÅ‹ûöíÃoû­¯¯okSŒîx°ƒDEE577ëèè`‹=ÝG7ûNð LªO:ÅYìû÷ïèÿzÝcÀÜ;33+å;| ¬íã]J ܃‹‹ VòêÕ+„±±1VB§Ó¡gãwU0]TPPà¤7$$!$ @§Ó9_ßBöÍL&fz˜Ë4ÔÌíãÂ… ¡eË–±”Ã×åRü?öÎ;.Šëûûw+½I°P¥"*Ò¥Ø{G£äk4FÑDlÁ¬-jÄ(öklÑÄ‚ AÅAEz¥(e—¶ËîóÇy¼¿Éì "K™÷¾döÎÌ™ÙÙ™¹§|I2€²œ$W?I5P"PÛó"«K ÈËË3 q¹lرLFz¶mÛ†rvvn|XVV–‚‚‚ºº:I²®ªª Ž”XT"ú¬Âøï¿ÿâ]êÀã°|ùò&-äóùrrr4­Iá%8K0ˆ€ó+66¶É]‹D"páY˜á•;17oÞ”——g±X.\ÿ®=OOOÒrÈéÖ­^A\-ÒW¯^E ”ÞtAˆ|>ÿöíÛ ZZZ8C=zô0cöìÙ0F(öéÓþœ3gFÃ¥X“©­­-¾¬Ò àŽ$’ššŠs»ÔÕÕ—/_Ž+&ÔÕÕÙl¶ø6 .]ºô5ÏÙÿ!MõàÁƒa0¤›5É®]»`<ѽØŸ>}‚ñ$ñ‰àÊ>hÝÒ$çÏŸo²Ö—Édµu׬Yƒx΂ iáæÍ›™LfQQ—ËUUUÅgì+½¿ÿþ»øGEEEXÞ‰ýû÷ìÆÇÇÛÙÙ½y󦹻~úô)BHOO¯fwhàqF¬lŸ>}¢ÓéFFFâ¯7©©©öööXnhâ_P(ôõõ i™SUUÅd2õõõÅ+=E"Ñ£Gp ,Lç$>FIͶ¤¦Ä'OžlÁºÈŠmY’H$‚¯Äüðàà`\£ ¯ÙâzÞ"‘(::ÚÖÖöÝ»w-3 q–.]J§ÓñŸ–––={öÄ%«¡ä IDATª««ûùù‰>·*“xoäóù<òÍŸ<ÔÕÕ[°n»ü&¤Bé)++C„]x=räü¹gÏô¹4 ä{ˆ2ù˜µk×~í.]uuuZZZ0ÿ‚±,K$Íœ9S[[ÿ©««kmm ÿ‡ô^iæ$ ŸháÂ…_f{Kè¹ uuu\m2|ÝP˜Ë妧§«ªªâp1”B— –J?&''ƒS§`ÀI1wîÜFÂæÐ;ƒÏç¿xñü^ÜÅsfrrrÎ;§¤¤ í$š*ÍrñTqã³³³/^¼(''‡s×!¿±´´´q•ÌÌÌ7oÞTXrrr  [•]SScnnNrôÆÅÅIy1HDÊb„;wîTWWϘ1ƒ(‚ˆºxñ"—ËÕÔÔÆÚÚ:===11ÑÐÐpË–-JJJ¤$(|~š´2MÌÌÌŸ$TWWÃÓ«Éc‘~ס¾}ûÊÉɽÿ¾¬¬,,,ìÙ³gP´FvéÒ¥3fÐéôË—/‹×È †«] ‘xAê)1ÙR~w]&“éíí½k×®… ®Zµ 4>á=uêT#áæçç·iÓ¦'OžXYY]ºtÉÝÝ× AZÁÚµk—-[Ö\“ÌÌÌ:´sçÎ;wîüõ×_»ví*))iƒ¢¢"‰©+m†Ä¼38 GNNN¯ÎÂ044”f<_ 6LWW·ñÁØ`eeåF6_TTÔ·o_¬Ô+N …ÞÞÞ!!!¸;/™w¤›­pHœ|8¼6| tuuÑÒ³²² ‰FîZL&³egnG®®®â?«Ž‹£££‚‚Bnnnvv6)ÿZ@>¬¡”+ EEE˜M4rÁ€üWåÆ%%%sæÌAÍ;wíÚµGŽ!V¯ëêê3å‰0 ñÔò&‘åó«í-^  †¸¶"‰ 6 „V­ZEZ Du±ˆˆÒ˜ç())á>”"‘n" x $óÝ`¸d—¨)‰"## †ššÚ‡±¹¾¾"ÆÃ‡—è˜LJJ"&SÀ1’,WWWC™4Q–\¾|™´AhIìiÀ[5މ>GË ˆž~>ŸÓN¢G žÇD½7"8¦M4uuu‰´/''‡»Âû‡¦¦fmm-Éår¡žŸäï,,, »}û¶Ä½155EŠq0­"pÞ¾} •ÀâŠ;d¾|ùr¨ŠË„²…^½zIL÷ ÆÜ@9oúôé[/(l6›x~$‚U 5"÷Á4>""¢wïÞt:xñþù'ƒÁPTTl$²»‰â—ÀŽ;ÐûÂBú÷‚ š4Ü$¿o]]]XXXXXŽ wÄ;YÂB:bWà¶kÒí eV ,€ x+(( ÓéëK5”Ë@ÂÝÝ]AA¬7hË$¯(gïÞ½ès¾¸›fÝ&&&DÉ="p{”R‡*þúë/ø^ݾÿþûÖ:qàÝ«Iy0È%Ù´iS+îÂÎM&Žu>è¢_ ¤<žÄ¾D ØÎ¹m8yò$’BZtÁ[·Õ|XXX«o³½nebæo³€WRÞ¨8 ø.žÛ' ¤\üÈ]KÌÀj1ð¾gÏžVÜf{""-þ*‰_)—ø)ÄQ¤É¼þŒ;ÖÀÀ¿ÙB:33“8†x Ä\ÒGRRRRިƧ¢_ rì½}ÎÈ~ýú5TrC)M”¾¡¸=Q• ²²2==]^^žè_ohE55µµkׂDGYYÙñãÇGŽ) O:ÕxÓ,:þǰX¬‡ÚÙÙ]¿~=??ŸÏç¿yóæÂ… þþþ ÆýæÎ«  ð×_;vL ‚§OŸzxx„…… 8|èâÉÐ’Á`¼ò</55UNN,DËY,Ö‡–-[³ÙÄÄÄñãLJ††ÚØØÃõ Ý·jÕªƒBG=¡P˜——wîÜ9gg第,¡³ÂÂÂ-[¶|üø±¾¾þÙ³gC‡…DýàøHÇ•––nÚ´©°°Çã…‡‡4dÒHé*§OŸöõõm²hEEEff&’"—+W®\¿~½®®®ªªêâÅ‹Ð]F|u8™7nÜ8zôh¯^½°—]‹òòòÆšÿ!.—ûòåËŸ~ú‰¨zÐ,éGKKË&+çÌ™C§Ó÷íÛ·~ýzPâ‰D………7nÜ;v¬xu:ËÒ¥Kß¾}ëïïOCF;wnîܹL&óÔ©S (ú/Xf Ì“˜Ë@::???ƒñÇá„‹¢¢¢[·nM˜0ZÃ4rf^½zåëëëëëÛEœÎÇúõë…B!ÜÜÝÝÝÝÝ÷íÛ[Ìãljêž&&&NNN/^<|ø°ªª*±¯’®®î?üpçÎß~ûØW))) ü¶ Î €Ç㥤¤ÈËËà üçŸVPP˜?>üªª*x%¥øÆG£ÑîÞ½[TT$þ©’’RpppRRÒ¨Q£$®Ž ߤÙ×É“' †œœÜíÛ·oß¾——gddtæÌ™–‰™ID¢ˆÛß½{÷B0§…|:ŠnÞ¾}Í`0ÆŒÓZÛì(à£>sæL V—òŠjõ¯LJàŽD¼¢’““/^Œ¯¨ï¿ÿ¾¸¸†¢¶¶ö§Ÿ~"^{¸å“”Àùå—ÎʨQ£Ølö³gψ·zé‘òª€aRÞµZñüeñÄïZ=Z´h¾r–/_Þ,}ÊÒÒÒ°°0&ždÚÑŸCËn5¨Ñ¯ƒø©¬î6¡>ܺuËÆÆ&<<ž›fff"‘·'™*NãÇ(‘óçÏ×××6¬ý›[¶wl´ˆvJS-e`iii¤åBŒ`ƒq DY‰^mx“ÆÈ"‘ˆÇã1 ‹E CÊÓ•+W`jª¡¡׆††ôeÆÄTbª§¢¢âáljƒ< ~rrr¸BÁËË«¨¨‰ MMMÒŽ`‚aiiIZ=«ìííñˆ–ÛÙÙ={!Äd2±ZäÈ‘#Žb å Æëèè`šš1"5ðY,Ü'MšåI¤€6áaƒpJ—-[öHÉn4sæÌÆO2¼(**6YÌV]]› (++3 :¾mÛ¶iÓ¦!„Ä•rssñ÷uöìY‰Û|ñâ4 ˆ-Eˆ­F!­£IÕ‰o¿ýIÝ@kÛ¶møëÐÒÒ" §‰—,†„„À§ªªªÄ+ ðññiä~ò PÇNê @4’¤`-…°yDg"nóÛÔÐÐ mîÎ]°^Zb.ƒès:Cbb¢H$ÊÉÉ"¬>}úŒ=ÚÕÕZÓ“.Q˜›!„¾ýö[ÒÖ*++A¦G>>>#FŒ€ÛÔêÕ«a€Ä\†%K–Ðh4++«ñãÇ»»»+++Óh4bùñ… @ÁÁÁaܸqƒ ‚1­urº2 &·k×.œË@§Ói4Úüùó _ÚЄ……5¹×PI—DÍ V ‰21ææææææD ª¡wòèÑ£[k¿›7oF’Žºø©¯¯ß‚0¼oHÓ¤¶gÏž4­Œ“O¬™óæMÿþýÍÍÍ!Ρ«« Ïbˆ⌹êêjooo¸öØl¶‚‚† ¤ßoEE¼üà6Ø s8œ¬ oþ…Ÿˆ\»v IjyÞÆr0)!¾FFFöíÛ×ÜÜ&,FFFð¼–’}ûöIù›êp”””À›*Q/¯eˆç2` õ[ddäm‰tïÞçq“ å2´¨Ö‘x*Ú€Ž¡Ëàè訣£Ó¤˜ª@ ð÷÷§ÑhöIÄÙÙÙÈȈX”âîîÞ¯_?âsss‡ClϦ¬¬Ìápˆ±\.—¤©©‰'E"‘ò\\\"""Ξ=Íd2ííí¿ùæÜ²IFŒñúõëÓ§O¿~ý:==½¬¬L__¿gÏž...>>>¤$Ž… :88;v,99¹¾¾ÞÐÐpÚ´i¾¾¾DߟÏçp8â0 ‡#®ü¯¤¤Äápˆ>qèxæÌ™ªªªááá¯^½êÛ·¯««ëôéÓÅK^9òí·ßž;w.##£¤¤dðàÁ=zôpssóòò">xð ½½}hh(dz··:tèøñãïܹÃápHõƇ²²²ÑWGGGwww77·K—.q8b   àúõëšššM¶/†/´{÷îM³ÉËË?yòä·ß~{úô©’’’ƒƒƒ··÷ Aƒ>Ü·o_ñRºÞ½{oܸ±¾¾^II t1Å8p`zzú‘#G^¼x‘••Åb±tuu---GŽILÍ7nœ‡‡‡Äš1"Æ ëÑ£‡Ä~uâ¬ZµjâĉGMOOÏÏÏïÖ­›žžÞ°aÃFŽ)^îëë )vvv¸Ô3räHRC" ÒZ[[Ëáp°K#‰ Ò‡T;·|ùòqãÆ9r$==ýýû÷`ž¯¯/VÄ­««ãp80I&bhhÈápZPÅ×Ññ÷÷1bQšØ»wïµk×òóó--- ž>}zöìÙ˜˜˜ŒŒ ¸’Ið”)S@0œhD”••¯\¹róæÍû÷罹¦*((øøølß¾´ZB®®®‡t­\¹rÀ€ÏŸ?ÏÏÏWQQñ÷÷‡œ,<`êÔ©ÎÎÎ'OžLII)**²°°˜:uêØ±c[ëäteæÌ™sïÞ½Ó§Oã%ŽŽŽ{ö쑦3Ë AƒÎœ9sâĉƉ¡K—.UVV^¸pø|äóùÆ ;|ø°ÄN999OŸ>õôôl<¢RQQqûöíˆ?¤ìííOŸ>}îÜ9ÄÛ¾}ûöíÛBß}÷Ý‘#G._¾Œêß¿¿‚‚Bddd^^žôàF€,ˆUtA<<<ôõõóóó###¥|â`ÌÌÌÔÔÔž}úñãG//¯ÆÓ‡³³³Ÿ={æåå 2Iœ¸¹¹‰Ô4IDD›Í¦Ñh‹-ºuëVllìŽ;FŒA£Ñ¼¼¼ø|>Ç ¥Ñh£GŽŒŒÄR‘B¡ðßÿ…¶JS§N%½cáB9Ô¨t«$¾u………±X,:˜’’" ß½{÷矄{jkkAÀÅÊÊêäÉ“qqq r¤­­­¤¤„»'JÈýˆu) ðAII©²²²¹ëbugssócÇŽ½|ùòÒ¥Kß}÷žžž¼¼<±Í!Ê(++oÙ²åáÇ÷ïßÿùçŸA'H¼!;;_*:::@l¤òâÅ qó@~ÛÒÒ2<<¼¢¢¢¶¶öÁƒÐ_ñSSS;|ø0´®LLLܳgººz³¼ YYY4Á`4YÁÔ9€ZÚ–½¤=zô2yçÏŸýúõ—/_†„„øúúÒét'''쪨¨€æ!C†œ9s&>>þôéÓsæÌQWW×ÔÔï1ˆ/ ÜûPPPúŠ  ÆÞÀÀ@KK dÈI µåååàuvv~ôèQuu5—˽}û6¤G5ËË“Æ)S¦H¿JÇ¢¶¶2>î߿߂ՅBá“'O‚‚‚BK—.½}ûvtt4ɽxóæMxŽüðÃaaa111Û·o÷ðð Ñh£F÷E^ ¦Dpƒ?„о}ûˆ¥¥¥MŸ>!tòäIbCÜâââ»wï4ˆF£…††âKúíÛ· Ü ¡¡all ×UsïrŠÒ{n(/׿yb§sPWWÇf³Y,ÉÁßÞ¨««+((Øìš‚‚‚¢ rç΄¦¦f æ„"‘(..ŽT­Àb±üýýakÇŽ#~´hÑ"X‹Ô!rèСÄmÞ½{k egg7´ëÊÊJ\OѾC\\bãZBðz‡UWWÿðÃè¿X[[GGGK*Š‹‹AùèáÇүÕ)¨CËÂïµµµ$ݲ~ýúEDDF‚b q˜††FCadè–s‰FöŽ%±ûöí+1@Z[[»fͨ£¤Óérrr0^[[;**Š8òâÅ‹8¸¯=99¹Í›7K6Ðg ‘®h~)))·`õ¤¤$¨ÄÄ0ŒÙ³g“ºJ•——‹8::Šû•D"ѳgÏ ØÅb5¢‰P[[‹K®BBB$Ž‘X!ëééIV^^ŽëȘL&.u400w‚4Dee%äáËpÒØ,^¼!4nܸ¬ ÙåâˆßöcccIHÙlö‚ $ºæüñGCÔé',, n# $É3R½V#•©â,B\”J„Ôö®IΟ?êÞ½» §H4‘H$ñ+¡ooˆððp‰×DÇ%>>ÞÖÖÖÚÚT'(((((: Œ‹‹ ïw# |>?...66¶  ÀÔÔÔÕÕÕÀÀ>ª®®NHH¨­­E±X,ܾ[$%$$”••!„h4ZŸ>}°¨ ðáÇÇ»»»ca‰ÔÔÔܽ{×ÂÂä÷1/>>>55UKKËÐÐpÈ!†††â#sssŸ?þêÕ+---+++WWׯ øIýúë¯ŽŽŽP7Ñ•¹páÂôéÓõôô²²²HêRòîÝ»çÏŸÇÇÇkhhôïßßÃÃC¢^zEEELLLll¬@ èÓ§¯¯oC:£B¡ðþýûêêêM¶dJNNÎÍÍõðð²!š÷âÅ‹¸¸¸ššCCC333gggp‘Ì‹ÿþ}Ïž=ŒŒ\]]¥ï`ÿáÃCCÃêêêû÷ïCÝDW`È!Ïž=ûùçŸAHµ¹‚„„„˜˜˜wïÞ™˜˜8;;Ca—8111oÞ¼ÑÕÕµµµ…ë)--ŽŽvqqi\Ê¡®®îîÝ»¦¦¦¤)¦¸¸ªˆ˜™™ééé‰ÎÌÌ|ñâEBBN700°´´ttt”þŽ´cÇŽÀÀ@ ‹ÄÄÄfÝÇ:™™™æææB¡0!!¡Â%±±±¤>Gòòòƒ ¿ÛÔÕÕÅÅÅÅÄÄ|øðÁÔÔÔÍÍ­ŸW¯^}øðÁÍÍ­qY·ÂÂÂgÏž¹»»C`Lnn.îØ­[7|\¥¥¥)))|>!¤  0pà@¸Gåçç§¥¥·@£Ñ,--±—³ID"‘µµõëׯ·mÛáp™@y¾”ìììÚÚZccã& v,¸\î»wïTTTÄ5ü(((((Ú3—.]šZöb‘ÎM¿~ý&Mš$ ·nÝ*k[:$111ªªªK—.•­%”—‚‚‚‚‚¢³1mÚ4SSÓÜÜÜYÛÒñغukII‰¥¥å„ dmK{ÉdB}/‡Ã©¬¬”µ9Œ‚‚‚;v ®ê·š0a‚¥¥eII „X)šÅîÝ»sss Ä.;+à%ÿóÏ?dmK£¾¾Ú÷~ÿý÷ÒKÆ|%(/E«rñâEY[Ñî¸}ûö¶mÛÚ2ÕœÁ`lÙ²!´aƼ¼¼6Ûo' ===88!´uëÖN¬²ÖæÍ›×·oß‚‚‚õë×ËÚ–ÆŠ+*++œœÆŒ#k[dFÛ¹s'BhÇŽ©©©²6§#ñþý{è“܈|i'ÃÚÚzæÌ™õõõ‹/¦›Å´´´ˆ[eåe     h5Ö¯_âÄ Y[!áááGm›}]¾|yÍš5К¡Í˜2eЧ§'Ç[¶lY[î·£³dÉ’ÚÚÚqãÆuÍ a#°Ùì}ûö!„öìÙ“˜˜(ks: ÷ïß?wî“É|¸zõêÐÐPi?zôhõêÕW¯^ýÚVQPP9tèÐ?üÐ6û:tèܹsÛ>µoß>6›}ùòåÛ·o·ñ®;(—/_WTTܽ{·¬mixxxL›6M PsE)áóùp®ZЙ¯3±k×.%%¥ÈÈÈ¿þúKÖ¶t "##/\¸€½{] ===HâXµjôH¦h’ÀÀÀòòrGGÇùóçËÚ„B¢Å’%KÌÿ‹½½ýøñã÷îÝËãñHƒ³²²Bzzz-ØÑ“'OB¶¶¶-65,,LCCŸç´xS²¢¢¢âéÓ§¯_¿ÿhΜ9¡Ã‡·½U™™™ýúõ3778@(‚¤jqqqÛ†Y°`Bh÷îÝx —Ë}úôiBB‚øà… "„víÚÕ†¶>¥¥¥666æææÓ§O—µ-²DMMÍÇÇGÖVHÅøñãåäädmÅWgÍš5!“ªª*YÛÒÞ©¬¬ìÝ»7BhëÖ­²¶¥ýòîÝ;eee„ЩS§dmKà·ß~CõìÙ³²²RÖ¶È8zzzååå²¶¥½SSSÓ·o_„К5kdm‹làóùà˜[´h‘¬méÜ¿!Ä`0^¾|)k[þ?ÌË`jjÚ»dÀ€\.—8øŸþA5ª;¯¡¿¿Ëì,//×ÖÖFFGG'''çååµlS2äÌ™3¡)S¦ˆÔ¿„PLLLÛ[5~üxøÆûõë'q”üõîÝ» #boozøð!^réÒ¥†®F„ЃÚÐÀÖǵTUU…B¡¬ÍéÔÖÖîÝ»wöìÙŽŽŽ£FÚ¼ysAAþôãÇëÖ­3fŒ››Û’%KâââˆëþóÏ?eeeW¯^7ož§§çöíÛÁ1WTT´}ûv__ß &\»v¸ÖñãÇ„Bá‰'fΜéîî¾víÚ?Lj{jkkwïÞ=cÆ ''§ Ü»wøéùóçx<ã5(> IDATÞ?ÿü3wîÜ#FìØ±¶™ŸŸ¿mÛ6ooïI“&………‰Ÿ3gÎÌŸ?ßÉÉÉÏÏïܹsÄ¢££ÒÒÒbcc—-[æììŸß‚}ñùü¯+‰ÎŸ?rvvnÙêí8±Û¶mÿ¨¦¦¦ºººíMº{÷.Bœ» Cbh2ñÆ×öæaàü'ÛP(õË/¿F yyyVQQѶ6¶&¯_¿f0ÆÆÆð:•••%k‹:?©©©ð®æàààçççã㣢¢rìØ1ø4))©wïÞ,kĈ“&MÒÔÔd³Ù'NœÀ«ƒW(((HCCcôèÑ=zô@y{{úôÉÊÊÊÖÖÖËË‹N§Óh4âË1èíêèèÌœ9sĈt:½OŸ>D/*ÉË““cmmM§Ó=<<&NœWûúõëñ°¤[·ncÆŒÑÕÕ…ßoIII¿~ýììì<==i4N¿~ý:^‹ËåŽ9úôé86yòdü£Û³g„€ÔÕÕÝÝÝ „b³Ù=‚3fÌÐÑÑ¡ÓéÞŸ‰ˆˆxª¡600P[[{æÌ™^^^ ÃÄÄ$77±³³ëÞ½»ÏŒ3ôôôàÕèùßÿþ‡Â?sJX·n‚‚‚“““——×Õ«W¥ûæ[ÂÇ™L&BèìÙ³_o/#GŽ „X,VCþ& L}}½»»;BÈÞÞ¾¶¶VÖæ´SÊÊÊŒBTŠ‘¸¸8999„Б#GdmKûD” 1^Õ5Ö6999²¶¥ý2vìX„……E»òIu$/¤‚ˆGJù|¾¾¾~ ü7_qmdu((8yòdkí½¾¾¾–I½ýÆ7ëáájèÍû ÷Þ‚#CñäÉMMM„ÐóçÏŇA— 6´Ì°)ùTÄÄ}±¯_¿FõéÓ§eJDš-…ÂVÌ8ðôô„X••BèòåËÒ¬E¥<| Çg2™W®\ÁK***Þ¾} ÿ÷ðð`2™‘‘‘ðg^^ž±±±ŠŠÊ‡` xúôéóþý{‘HTWW÷í·ßBZopp0ŒIMMe³Ùxàe033+,,„%W®\AÍŸ?!yFŽ©¨¨øìÙ3ø³¤¤d„ t:=>>–€—ÁÒÒ¶Y[[ ͺzöì¹wï^“˜˜H§Óíììðf¡ àôéÓðgUU¼ˆœ9s–€—A]]—)ŽŒ¯¯/Þˆ”àe055ÍÏχ%×®]£ÑhsæÌÁcž>}нÒB¡ððáá+VའzzzoÞ¼iÒ€V«¨¨`7=‘W¯^)((t‚âµ6£   {÷ª)&Mš·ÙEøìß¿!¤  ðêÕ+YÛÒÉÈÈPUUEýú믲¶Eöðù|'''„££#•e&‘]»v!„ÛìBJ:’—ºà¸¸¸ˆq*RÔ}„ ...¤lÞêêêàà`kkk999++«;v&“ÀÃÃÃÃÃ8oœ?¾‹‹KJJÊË—/¿ýö[ ‹Õ§O<-Zäâ⢦¦†²±±qqqqqqÁ©¼ÍÝûÅ‹'L˜ ­­Í`0’’’D"ÑâÅ‹]\\Ÿ?>wî\cccMM͹sçâ"œ;wîÌ›7ÏÐÐPAAÁÙÙY\U!55uóæÍÎÎÎzzzt:]EEÅÆÆæØ±cD36oÞìââ¯\.Ÿ:ºÐÐP—;w’¶Ìårׯ_ïî«K§Óõõõ'Ož|÷î]<€Çã…„„888@9‰ªªjÿþý—.]JÊ=n(c™:uªH$ruumÈ3^bØS$Õ××;99)))™šš~÷ÝwEEEááá...â7ñ»wïŽ7NSS“F£õêÕkúôéâ/ÁÁÁ...7nÜÈÊÊZ´hQÿþýi4Z`` H$ sqqÁWãŽ;\\\””” ìƒOfQQ‘H$íÜiÓ¦ÕÕÕmß¾ÝËËKEEESSÓÏϤ+ñöí[???¡P¸ÿ~UUU++«_~ùr:jkkwìØáã㣬¬¬££³téRñ\„„„Y³f™™™ÉËË3™ÌîÝ»ûúúž?¨©©)((Û¤t+œœD"ѬY³BG|؆ \\\ÂÃÃß¾}»dÉ;;;‹Õ«W¯76î ¡çÞ½{¡ï¿ÿ^â§ñññ!???âB(€ÂÕæàe V„‡‡C¢Ñû3dȆ—ÀË€gò€“ÉÄE¶D/ÃóçÏB?ÿü3qüÇB?ýôü ^¢»dS­­­‰kÙÚÚ2™L¸T***ØlöèÑ£‰JKKY,–§§'ü ^bÒ„H$ÒÓÓÓ××Ç6ËË@ò5ŠÁ`ž/ð}ÛÛÛã%½ {öìirï­…P(ôõõEÙÚÚâ  ²²ÒÜÜ!4~üxYÛÒ‘ˆŒŒ¤ÓéT2³DöîÝ‹’——'U«Q“'OF™››Sr$jjjˆ1bŒòòò´´´ˆo\–EÌWm't$/ÃìÙ³BË—/'-e±XrrrÄúÀââb„––qdzz:ä3 WWW˜H3†8 ÂË–––x ŸÏ—““c2™§NRTTÔ××2d¬‹ºyó&éââbaa»°þ Ì´›»÷Õ«WCŽ­­­––Vmm­P(TSS£ÑhGŽQPP000°³³ƒ* @pøðaHåµ±±Û H¥ Tchhèæææáá³_R2ÿÌ™3ûôéH|®®®ð)ÌOp˜¸uëˆf©ªª>|Ĉ6¼jÕ*ðéÓ'333|f¦L™âä䤪ªJ§Ó¥yÆ|üøQSSSNN.;;[$-]º!}tI@šDh¢¢"ggg„’’’‡‡‡···¢¢â°aÃàEÿ·ß~Ã#…B!ÂA(uäÈ‘P椦¦–ššJÜ‹££#BhçÎÚÚÚL&ÓÂÂÂÈȼPi‚ÂóæÍƒ÷W6›Oæ!Càá1OgggEEE;;;¨ F9’¸G¬ì0}út6›mcc¶Á!p¹Ü#F(((ØÛÛC| !´zõjâŽ?W‹†††¯¯ïèÑ£áZ%&…„„r+§¦¦ÆÄÄ„F£A^ ;I,W<”ƒvïÞ]SSsÈ!êêê`'>WRê÷$W*¶Ž?N\˜ŸŸš;w.ü ¿âääd< ´´^ĵ–,Y‚‚è³—X) ‰~ýõWDH,"z Oä¢E‹8°oß¾½{÷îÙ³g×®]l6k”€—˜ ùîÝ;„Ð7ß|CÜ ¤Z€ðDLL BhìØ±Ø¿?lv÷îÝ={ö„ñàe M~&NœH£Ñð{[³¼ ™™™Ä…Û¶mC=yòþ¬®®>räÈĉ ÊÄJJJÚÚÚx¼D/Cgæ÷ìÙ!4oÞ¼¶Üo;§¾¾bΆ††Ÿ>}’µ9 ‡ÏâÍ„"::Š<(k[Ú)eeeFFF¡I“&µ ¹µÝtuu›ïéôܺu‹F£Ñh´¿þúKÖ¶´# áw„ßîÚÉË3¢={ö¼ÿ>&&&88XKK‹Åb‘^©!.7b襤¤Ä#§OŸ^VV ³²²à­‹ƒð21˜ÓcmmíþùòxŸ?|øpx’áÀcFF†––œŸ;wîàÁpsÇ*q|>fAÄ$@"ƒ±dÉ\'ÐÍÍ !„“ÕEŸSµÝÝÝÅ lc2™þþþøÂ8wîL¿‰¯¼k×®…=Ž1âÝ»w"‘H(B´††ÆàÁƒ'L˜PRRæA>¹^=''GNNŽÁ`DFF½ãIII8w]ôÙ— #Òs­Y³fÔÐÐ4¬ªª ζ²²òîݻᕢ®®|:_ÒÌ¥k²bÅ „QËÈï¿ÿŽºqãq¡@ @áP?xàB*++Bß~û-q-p™a.xH92PÍŽ“ˆ^#ÑÓÓ3cìØ±0~_péà#&UÀ þûï¿Bšššâ›Å2ð2†¢ÏÚ~ø¶Y^’3ôøñãè³¢[]]ݰaà ÆÀýüü¶lÙ²k×®~ýú)++ãñ½ Ø}ÓfÀY¢Z¡¢¢"NÇ=pC bãFqzôèA£Ñˆ³éyóæ “ÉÔÖÖÆóðgÏž!„TTTHédP%N, ‡É†……IËæ?ÄéMRRN×ÔÔ$Õ5}úô ®=<ç‡|$)w òMBÄTjö‹´ñ`hº9{ölâòúúzÈG ^Ø>>>!brJII $¬:990''!D§ÓñH˜'íHœåË—7NJWqAAŠŠŠ¼¼<nçååÁ™ÁßßBèСCÄåp&I9GMÕC¤¸/‘Š¹Þ¿Aì/ñ2æÆ›6m"º<Äs°gV"-ð2@.úuëÙl«{HZúàའPœ]¸p!qÀ AƒÚ¡—A$]¼xnß±»ëׯ‡§êWUßìÜTTTØÚÚ"„,--ª!ê:dggC"§»»;¥‹Ù$W¯^…÷«†´´º¥H£Ñ°ä¡P²MªªªT!RMM Ó·Ût‰óövHBBB}}½œœÜ¸Ïx{{CÆõ7®^½Êçó‰ã_¾|‰‚'BèãLJb³Ùûöí#y+ krrrCëâ%'N„o#‰B ŠNlgg‡—´`ï+W®!="/^¼@Mž<à˜ÖΟ?Ÿh3B:Zƒ„ >ŸŸ““óüùógÏžÅÆÆÂB\‚Š‹‹CAm‘”””ªª*333\jñûï¿;99AºDDŸ¥þß{W¯^MŒ¦§§ã(ir ÅŒ(<)Èe044Ä-< dwÖ€»"VÚ¯ªªa³ö™Ë@¶‹Å"UÖtΟ?ÏAÒœ¢edddÀƒräÈ‘2it-s>~üá%Ü…‡B !ŽN§µ¨»7nÜ`±X ½XRár¹ˆÐ$««Q__JUJJJÄÉf;¤Ãä2bÔƒÁðôô@XX^^VV–••¥¢¢R!+aMD" v!)„Pzz:—Ë566Æ)B¡4ÛaG[ÅçóA˜‰ÐܽõíÛ·¡“²@ðúõk&“ ¿:LEEEFF†’’Þ8Ç6lØâÅ‹«ªª–.]ò矞?^7­¬¬°ë¡¨¨¨  @[[d#ÄmÀIÙÙÙàMÔ“X¿~}hh¨££cAAAHHˆ­­­»»;)(*N]]Ìsôõõƒ‚‚V€à<|5$ó°1ÑÑÑ!KKKñ-C™‘‘Áçó{÷îMÌA¸\nQQ‹Å244„%T‚í$ÄaÊË˳³³UTTÀé#>xذaMn– 4ˆ”‘–H³EEÅäää5kÖ¨©©EFF.Z´¨W¯^+W®¬¨¨? i€9•Á¯¿þJü^>~üˆÄ¾ÈeæD!%GŽéß¿ÿìÙ³ÍÍÍÇŽ;dÈž={Bï „Ð¾}ûÌÌÌ&Nœèàààééimm]ZZúÇ`OÓ—0kÖ¬Œ3fذa3f̰°°€9¿D8àììüÍ7ß=ÚÃÃÃÐÐÐÁÁáßÿýÖ¬Y3{öìmÛ¶õîÝÛËËË××·_¿~}úôù¿”,X°@EEe„ ššš†††ÿüóO#ƒýüü¬¬¬ÆŒãää4mÚ´¾}ûnܸ>šŸ?~üx(§êR:thÖ¬YB¡pñâÅAAA²6§3`bbrëÖ-•[·nùøø”——ËÚ¢6%??ßÙÙùŋݻwÇÌÒ´xñbÏ8p@Öæ´5gΜ?~<ŸÏŸ={vpp°¬Íiï())ݼyÓÜÜ<==}èС©©©²¶¨M©««›1cÆÑ£G™Læßÿ=xð`Y[Ô̦‡´ÄgM;;»Gìq° $“£Ï¹îX“Ÿ¼ìb§LÛˆÓ˜ùëéé‰çu‹[õæÍ›ºººþýû«š»wbµ&77·´´´{÷î=zô .OJJª©©±¶¶Ac HúY[[cßÁ÷ß¿`Á‚ƒs@l†¸Sñ¢ éü¡‰OÎIÐh´±cÇŽ;6''çüù󇊊ŠJIIyûö-iæLd÷îÝàˆ‰ŒŒŒŒŒ@ÌÌ爺º:¤W`ó°Ÿ#‰ H“ß‘¥¥%؉½NçÆâ×|¶¶¶øjÄ44Ç_.ýÈF–ëèèlÙ²eýúõÑÑÑG޹råJpp°ŽŽDt›Å¹sç@åôùóçЭñ{áóù ¿ n§øé¢cc㘘˜'N¼xñâíÛ·¦¦¦sæÌ‰ø466öðáÃñññ\.wùòå~~~D?×È‘#µ´´ˆåTl6›Ãá~õ^^^ÊÊÊ$ßĆ ,--¡PbÓ¦MK–,!ngõêÕÄß‘®®nTTÔÅ‹Ÿ={–––Ö­[7///IE;¶gÏžŠŠŠxEEE‡Czv’ f³Ù§OŸž7o^DD,xxxlܸÑÛÛ <˜Ãáà[0iÒ¤>}úà_bŸ>}²³³ÃÂÂòòòjkk±WZ"ëÖ­0`À½{÷˜Læ† –,Y‚ ¸bbbvïÞýòåËnݺùûû_ºt ºêcÆŒÑ××Çwi555ÜfE&9r„Á`9rdΜ9>|øñÇehL[²iÓ&È­[²d P´ ¼sçΨQ£É&“Il<>cÆ „±û‘ú>ðx<ˆ5{zÁ”’x½Â]€Ãáv 5#GŽ$.„7˜âÂæîTÍHÀ»àÏ?ÿLZ{Ü»w/i9ˆÇ`ù‚‚„F#UCµ3BˆØŸ¶¹mÛ6Ò6!1‰Ø§ðÓ§O°ÙæöÊNKKc±Xt:¨AšóÍ7?ÅÑr>ŒÔÕÕI#!«ÂÜÜœ´Llllð’Áƒ%''C~Ajjêž={ †¼¼|LL Œ" ôßD qrrrñ˜ëš IDATèt:T‚HDGG!„… ¡ùˆ¸Ó Nér¢hÏP^†ÎÊùóç!aÐÂÂû;/_¾„×4iiÚßPl¹Y{ïÑ£‡Ä“bBà îQQQ‘Á`žp\.—N§“|ଠZaàÀ0×µ³³#®þñãGR‰2Ø ü¤DÓüü|¬U©  €K¸q4ä ¬Â0f̘F”¨Á_#ž»Aê̱|¤¬ŠÛ·o«Ê ÆÖ­[ûí7„ÐÎ;‰#ÓÒÒ `^EWW«ÖorëÖ-q{ ß„X¼#‰***H­1¡sd3YðswwÇKÄ+Apúˆ7h¿ÀÇÉpøøÐ444ˆmSàò %bˆ3uêTÔp‚ _áOø*#""HÃàtQyˈÿý·ÉŽ çÏŸ_¹r¥óM“H<}ún€ŠŠŠÇ—µ9­É@ÃÌ̬÷(EëRSSƒëS¼¼¼ˆÁ›ŽNvv6ÔÓét‡ÓésûÛžøøxˆ²ÙlR˪ŽÎñãÇa```ðôéSY›ÓIÀ7ù>}út¦›<—ËÅmM'OžÜHöwû¤c¨?:::Bt Ñhjjj†††FFFÐ7žÇûå—_´µµIš‚K—.utt}:– D"I0¬ººzÉ’%l6›¤¹ˆòððèß¿?Q6ŸÇãýôÓOªªªÐòË÷Ž©««[¸p!“ÉÄÓ`€Ë媩©µÓÀ’uëÖiiiAx øßÿþ×»wï£GZYY988L:533“Ãá@?FCC#))éöíÛéé銊ŠP?oggÇáp°Â §§÷úõë'N<~ü8##CNN®gÏžnnn %€Ú°aƒ»»û“'OrrrJJJ´µµMLL¦N Y)((ðôô1bDã‚dëÖ­ËÌÌ„G‘P(üæ›oBð'ÆÛÛ;99ùÁƒyyy °··×ÐЀDÈ}ÀôéÓçõë×;w‹+**ÒÑÑñôôôóó#)´=ÚÙÙ¢4$¬­­9Ä{1*** áááiiiååål6ê5`0éd"„TUU9޽½=^Ò­[7Ò@__ŸÃáÀ”žˆ±±1‡ÃÁ™>êêêOžÝÎ{¯HÕ+Wüýý?}ú¤§§wöìY,dKÑŠX[[¿xñbáÂ…gÏž]ºtéýû÷;&[¹Ü/‡Ëå.^¼:?þøñãMê¦SHÉ¢E‹§Nšžžîèè¸k×®… ÊÚ¨/%>>~ÆŒ)))rrr¿ÿþ;®pïHÈÖÉAAÑö\¿~!äèè(kC((((Ú»wïf³Ù!˜DÉÚœ" Ož< ñ EEE,QDÑödffb/¹ŸŸ_aa¡¬-j!ÙÙÙPŽòòò’XÜJѺ;v ¢h:::'Ožì¸9e/^„›ÍÞ½{·¬ÍéœTTTL›6 ~¡NNN ²¶¨…”——/[¶ ‚妦¦K¹·g(/Eg&..Ë^¡¡¡jjjrrr÷îCAAAñUyñâÎtqqépJ ñññP¨…²³³ëpöw>jkkW®\ /Íjjj!!!@ÖF5ƒššš7Bi´‚‚¶mÛ:ît·ÃñæÍÜØxذa.>99ç–öïß¿S*M´+þøãHa0®ÊàÌ™3ИF£Í›7¯ÃÙO„ò2Ptf¼½½µ´´¦M›èïïoccƒ’““ëdUÇ­‹@  Š &“ùã?v ýÒÒÒ¥K—‚ ’ººú¾}û¨šùöCbb¢³³3L·¬¬¬"##em‘T\¿~+U=:++KÖu9„BááÇAUŠÁ`,]º´CÜŽÊËËW­Z•Ë***;vì ÆQ|%>|ø0wî\†ÒÕÕ=uêT‡xÄÇÇï=’µE_ åe èÌ,_¾œ¨è¡§§R²¶‹‚‚‚¢ŸŸ¡BÊÊÊ+W®l·Yâ+V¬À² ~~~íÖÔ.ΩS§ðsÙÉÉ)<<\ÖIF(^¾|Ô#„ ®^½*k£º4ÅÅÅóçχ©£²²òŠ+o‰%CJJJ‚‚‚°Ä´iÓÞ¿/k£ºÑÑÑýû÷‡¯ÀÌÌìĉí¶WÔ¿ÿþ;vìX¸¶UTTvîÜÙ9R”—¢óS^^ž••%Þøƒ‚‚‚‚¢I"##ñ\KQQqÙ²eíê977wñâÅòòò`¡ƒƒ±÷0E;äÓ§OįìÚµk²6êÿgÏžµ´´óTTT‚‚‚¨^•í„Ç2¾yyùÅ‹çææÊÚ¨ÿ#??ÿÇTRR x÷î]YÕuáóù;wîÄnMƒýû÷7Òޮ퉊ŠÂ5 cΜ9íêñú…P^ Š& Ãbrrr3fÌ “au=ŸÏ¿víÚ¤I“p+%RãaŠöLaaa`` N?±´´ ÎÏÏ—¡I™™™ëׯ‡®Ø¡nݺmذáãÇ24‰B"‘‘‘¸»‹Åš4iÒµk×dþ·oßž1côSD 2äæÍ›²²‡‚Ç Á½»wï¾bŊׯ_ËФÒÒÒ}ûöaY\6›½`Á‚ΗjMy(((((((¤âþýû8ðeh+V¬xõêU[Ú·lÙ2b5œO'(aíš”––þòË/¸¥ƒÁðöö>wîI¹ù«R^^~ôèÑáÇCÆ2ÌC¶oßN¥@¶s?~ìëë‹ï:::Ë–-‹‹‹kKW®\©¯¯Ípssë(š#]ŠÚÚÚÇãoÊÖÖ6$$äÇmfC]]]hhèĉ¡‘BHAA! àÝ»wmfC[B‰Dˆ‚‚‚‚‚‚‚B:OŸ>}öìÙ÷ïßÃ’þýû1ÂÍÍÍÙÙYMM­Õ÷øéÓ§DEEݽ{7)) öîÝ{Ö¬Y~~~ýúõkõ=R´%<ïòå˧OŸŽŒŒ …!UUUOOO777777\¼ÐŠ…Âøøøû÷ïGEEEFFVWW#„X,–ŸŸßرcqPš¢“œœ|æÌ™³gÏæææÂ’~ýúÁÅãââš‘­KyyùÇávôêÕ+X¨¯¯?sæL???++«Vß#EkQ__qúôé«W¯â_½³³3Üj „“ãZ‘ŒŒ ¸ÕDDD”””ÀÂ!C†øùùM›6ík\¢íÊË@AAAAAAÑl„BaTTÔéÓ§/]ºÄåra!ƒÁ°µµussstt477755mÙl­¦¦&###%%åÉ“'QQQ¯^½‚É'BHUUuòäÉ~~~...8øLÑ9ÈÏÏ?{öìéÓ§_¿~êè踺ººººöïßßÜÜœ˜ÆÒܧ¦¦&$$Ü¿ÿÁƒeeeø#??¿éÓ§kii}é1PÈ‘H}æÌ™¿ÿþ»¼¼Òh4kkk77·¡C‡ÂíÚ‘6—ÚÚÚŒŒŒÔÔÔgÏžEEEÅÅÅÕ××ÃGÊÊÊ'Nôóósww§Óé­v<_™ÊÊÊK—.>}úþýûøá¢¤¤ääääêê:pà@ssóÞ½{·ìóñãÇÔÔÔ7oÞDGGGEE½{÷dbb2{öìÙ³gãÎ5ÊË@AAAAAAÑrªªªНEMMÍÇávôòåKâm„F£õêÕËÌÌÌÌ̬G¤‹‡F£ïEùùùiiiiiioß¾%mÇÚÚnG...ŠŠŠ²8PŠÖ!??n5÷îÝ#ºB }úôÿ”††ñjQVV®­­%^-¹¹¹©©©©©©8aPTT>|8\0lÛã“%”—¡1¶nÝZ^^¾råÊNœÍÒêTUUmܸ‘ÍfoܸQÖ¶PüÂÂÂ~üH¼Zx<žœœé‚122‚[±±1ƒÁµù²§£zjjjúõë—““ƒš7oÞñãÇ[¼©aÆ=yòäÞ½{¸)ðèÑ£áÇÛÛÛÇÄÄ|¡µÍ¢¬¬ Ä–“““ûöíÛ–»nöïßÿÃ?øûû=zT†f‚¤¤¤ „¦L™rñâE#sz÷î———žžÞÊÀ(((((((((((dHGÕ)ùý÷ßsrr`ßâí…ÂW¯^Ñh4ñ:™¡C‡VWW?yòä‹ m>qqqès^_ïºUøî»ïª««:$[3öíÛ—’’WHBB‚l‘-%%%yyyªªª&&&²¶…‚‚‚‚‚‚‚‚‚‚¢“Ó!½ ùùù[·nÕÐÐ8uêB())I 4¹–ĬŒŒ .—kbb"Þy‹N§ËËËyG“æf‹@¡••U³´j¥Ü Q½¦uc˜L¦¼¼|ã5&ÒXû%Y6%%%6lPVV>wîB(##ƒÇãI³¢ô;•~dC§QúÓû…VÁekk‹3E;hEû§CzV­ZÅãñÖ­[goo¯¨¨X[[›œœ,q¤H$:qâĘ1cLLL˜L¦–––»»ûüªªªrss›2e B¨´´Ôõ36l€uýýý]]]³²²úìÝw\S×û8ð“Aز÷p0ÃFe8AAEDE  V¬»ÖYk[±ËjÕmqÔ¶¶JµÖ(**nÁ)Š2dï‘ÜßççýÞO"*$Œçý‡/89÷Þ'79OÎyjiiÁÕ§êêꄯrèÐ!ww÷°°0jc~~þÒ¥KGŽ©   ££3}úô´´´î<;<—ÁÑÑñ=ÛÛÛúé'mmmGGÇ_ýUx욘˜øÙgŸ9RCCƒÉdjkk{zzÞºuK [TT”»»ûüQWW÷Å_¸¸¸ÈÊÊΚ5 !”žžîîî¾fÍ‚ ~ûí7 Ÿ¢¢"êIx<ž§§§§§'¹Çz}'óòò=z´|ùrkkkYYYsss‘ë\:;;wìØ1vìX%%%KKË5kÖÔ××ÇÄĸ»»ïÝ»·;7!ôí·ßÖ××oÚ´ÉÑÑQSS“ÏçS÷Ä"Í;×ÝÝýÅ‹W®\ :t(¾±±±=·mÛæîîž››»téRYYY ‹°°0ûÉ“'ÝÝÝ:T[[ûùçŸ;;;ËÊÊúûû“îÞ½¨­­Íd2 ýýýñ{Œª­­íŸþ™7ož™™™‚‚‹Å6lتU«ÊÊÊD>ßK—.ùûû³Ùl‹¥ªªêêêúÓO?‘/Î2Œ9²¥¥eëÖ­“&MRTTÔÕÕ]½z5¹ù`ï–_ø?Dsÿþ}fjjÊáp‚pvvFýûï¿Â=sssÇŽ‹b±XŽŽŽ3fÌ033C3† ˆ¬¬,{{{¼y„¡¡¡ýk¿ÿþ;AGVV–Éd¶··ã³ééé!„®RUU¥¢¢"++[\\L6nÙ²Wµ¶¶ž9s&ž·Ï`0._¾üÆ'hee…:|ø°ønIIIx¼¶¶ö´iÓ&L˜€¯8wî\j7>Ÿ¯¢¢Âd2Ùl¶———³³3®GB§Ó¯]»Fí¹hÑ"„Ð7ß|caaA§ÓÍÌÌ,--7nÜHÄBÁÁÁ~~~2226668H„›ÍÆ/†óÖÖÖd —ËÅwòŸþQPPÐ××3f ¹_qll,5†—/_âTYYyÊ”)žžžrrrS¦LY±bBè·ß~{ãÝ#"##ƒÁ`¶¶¶ËmüñÇÝi4š¼¼|XXƒÁ1bÄœ9s† †¢ÑhÙØØ „víÚ¥ªªª©©9{ölü¾ûî;jÏ?ü7š™™Ñét¼ÛVHH~4$$O(ÐÕÕõööÆ[g)((¤¥¥QOrñâE„ŠŠÊèÑ£gΜillŒ¯ennŽ ‘***fÏžß]VVV>>>ÖÖÖ CSS“ìƒSi?üðƒ²²²³³3~3#„–.]Ú[ $víÚuôèQiG€þ­Ÿeø|>…ž={·,]º!„ÃT¥¥¥†††¡yóæÕÔÔíiiiÔ”„‡‡‡ðX— <¡ÀÎÎŽlÁÛ=àÕ'Ÿ|‚"‡‘AüôÓO!SSÓ;wî¿üò Bhøðá<OÌliiÁYa§€¼¼·ãi/ŠŠŠÔ7›ÍÆÏ7  ººšzwìØRSSKJJÂí<oÆ !jl7n܈år¹dKnn.ÞÅ-<<œllnnÆõD&MšôìÙ3²½°°ðÀ䷸⣌ŒÌ—_~‰3/|>O½QTTÿ† <oÍš5¡O>ùDÚ± ëgY<ˆ8q"Ù‚gÑ{zz ôăX???ñ'ÄsÊËËÚÃÃÃB‹-"[6mÚ„Zµjµ[vv6ƒÁÐÑÑillÄ-YYYø“ä§OŸ œÓÞÞ!TPP &žû÷ïã!9‡B$zôhqï§Ÿ~ŠÏ€GÈâ9sŸ„Ìà2x ¹þâÆÔö‚‚œ} _‚äädÜsçÎÔž\.WWW—:Ã¥¹¹WÓ˜3gŽÀåJJJX,–²²rjj*µ½µµoD #Ò¶mÛjx{Α#GRóp2èË/¿¤¶777ãÉ/d*0hµ´´àYQøW½´Ã@ÿ&®D__ÓÜÜŒ'œS+ àOà¶™¸~ýú•+W444~ÿýw1',))©­­Õ××ÇcE*\CºñÎdeeQ»mܸ‘Çãmß¾]YY·|÷Ýw<oóæÍx2<›ÍÎÈÈ(,,³› ^Boee%++ÛUŸØØØ{÷îÙÚÚ®]»Vø!}ú×_ÉÈÈ9rDL­ÍG¡¦¦öÃ?Ïåråääð¶©€A«ªªjæÌ™)))øÛôôt.—ûþ•0hõ§,ÃÎ;ËË˃ƒƒ©ã4<†¬®®.++Ó××Çÿþû/BhÕªUxAWȪx]=D- gâããð‚„Pccã¥K—B111W®\8'N…ÈÉɉ ©;¥Oœ8jii™>}ºÀCUUU—(++;pàÀ‘#G***:SwÊÄÏwÊ”)ÚÚÚݲ²²¸\®¾¾>ž¹@•››K£Ñ¬­­ñ·|>?==F£QãÇÏ—8½N!„nݺU]]íèèèââ"ÐçDD¾LŠ‹‹ýüü&L˜@6Z[[Óh´–––¢¢"\˜ƒú”¡ÎÎN.—‹ÂS Èž+W®~íÚÛÛ…{N:UCCC ç±cÇB«W¯»­­ !¤¥¥E¶$%%………%$$à‡¨ÈWíÔ©SóæÍÃ?]Á!ùúúâ™ ¤üü|‚ Ølö[me` ¼¼¼¨5hqf™,=ð¶úM–¡¸¸˜œÂB}HFF†Ë妧§“Y†ëׯ#„>4†ÀÂÝx<^FFN§þ™eaa!''W[[[QQ¡««Ëãñ6n܈ #ÇiwïÞåp8JJJ¯^½¾œªªªªªª˜‰ HTvCØ7B ãÙ³gÂZXXàꡜœœ±cÇ644Œ=zùòå:::jjjt:=**êܹsÔg‡çn§-Ðë»4nÜ8rvöüùóÚÚZê& x[Ð!C†àœw@?^ä3%sIII!2aA…ÿü}c–¡¬¬lçÎ!‹%ðQPPhiiIOO'³ íííx_ò^‘òóóñ‹¨©©I U¸'zu"ç àžÞÞÞÝÊËËëëë544p­*>Ÿ_\\Œ(éƒ]»vmÚ´I^^~úôéÎÎÎ8‹±nݺªª*ò½ßäo¼-äË'Ð.&Å$îÝ»7sæL>>ÇŽ ¦>´ÿ~ô¿é<æ™—éê!áE%Â-8ï §§G]UA=-ùLËËËÑëÅÏâæÍ›¨ãá––„PDD„È䔊Çwvvjjj O:À—óôôÄ·—|QðF!TiiizzzäŒ |„ïÎh GõèÑ#‡3lØ0œšILL 6lØ7¨‹nž>}ZUU%//Å ×o¶7¾É»Ê[ ¿X€A%::úÃ?Äÿ± HKKÕ•ÞAÿÈ2ܼyóìÙ³:::~ôŸþ9þ(**"„š››zž:uª°°P`†°”””ãÇ«©©>|X8ùA-ÞC˜êììÄ»,^¼·äääà¿Â…;‡††"„-Z„Âó#ðNŸ=q1áå!\ó—vG]¼x‘ ˆ?þX ®Çßÿ²³³Ãï1„~š]Ý|ÅÜÜ\‘!ugÖ ` Ú»w/.%+òÑÔÔT Çôe¿þúë£G&L˜0qâDi‡Óôƒ,Ç[¿~=BhëÖ­x—A•••çÏŸÇ;&"„h4š¹¹#t® IDATyffæ­[·¨ëð…•••!„È ÿ¤®ÆÕdi†;vTUU}þùçËðXîÞ½{uuuÂ)‚ „GªÂ×511!kI c0–––™™™/^\¸p¡pò*¸ðÞ—¼.‡ÃÁI\Ú?#‡cmm­   p6—™™‰De „ïRWy‡î‹\/\¸°cÇr ––†—¥˜ššŠ¹'A¬_¿ž ˆo¾ùoÒ) ¥¥%""‚|‡TUUSÇó»ví*..vvvž5kµ'B(%%…¼c¡«W¯FGG«©©áÑë šööö•;ñââb¼Ü†lŽŽ>þ¼ººúÇŒ[ð«†'el6»³³Sd¼¤ŸN§·´´àü!³††Æ™3gðæ‹­­­W¯^7ou/F<²]¶lÙ7=z„ëák^»vMàB·oßF >\VVVKK ï×@Åårñ{ܸq©©©x3ÅæææôôôÅ‹‹¦xψ‘#Gž%==wÃõ)TUUÃÃÃÛÚÚ‚èìì|þüùÑ£G]]]+**p7ò£ûÝ»w×××s¹ÜÄÄD{{{œU™4iy]¼!Bpp°pHxw‰aÆ ?„ëDVVVâoù|>>3ÙB„‡‡B(&&FàXüþ×_M¶TUUá%S¦L¹téR||üæÍ›•””pɃ   1÷ ïo:|øðŽŽ‘ÈL¹k£““BHEEÅÍÍ ß±’’’/¿ü7’ÇâEEEeèСø%¨­­=t謬,FÃS0üFíêU DM:o›ZRR²}ûv:Î`0bccÉnx ==½[·nñx¼úúú(++ã{{øða²çÙ³gB,ë?þÀoƒŽŽŽäää¥K—>{ö ÷ùí·ßBK–,&''!deeEm @-\¸PÌ­ôkmmm8+>å^oO‡#r«;ê@èëY†ÚÚZ¼r^Ì«H®PHNNÆ-ä¬&“©­­ÿ¢²±±¡xâÄ ê€Aðù|\Ž¡¦¦FàBuuudç?þøCd0999d-@yyy²‚ À Z$á}T¿ýöîÆçóçÏŸi4šŽŽù,ôõõ©'$»±X,ü³±`Á<ÂÇse±O>ù!&®‚áçç'ÐþòåK„¡¡!ÙRXX(ÐB„ºº:BèåË—‡ûûû#„¢££©çÎ#ËF"„dddöíÛ÷í·ß"„:ÔÕMkjjÂU?#""ºêÓÚÚŠ×\¿~ .—+++Ë`0RRR”””h4Yï6J=¿(111x>‚ºº:>•ººú¹sç¨=—-[†úõ×_EÆðâÅ ²¾#¾-ø‹óçÏS»UTTÛ| 2„F£ÉËËŸ8qÏbxøð!µó§Ÿ~ŠßØt:][[¦  Àãñ¨!8p@ ˜ãÇã7µ'ÝöíÛ×Õmôk555cÇŽó¿ •˜ßºÀ ‚?i@§Óëêê¤ZßÕ×WL®Y³FEEÅÇǧ«>êêê;wîìèè 'ü3ŒsçÎ]¾|ùÂ… nnn...³gϦ8þüñãÇ߸q£´´”Ë庹¹!„š››7nܨ  @Iªªª¡¡¡­­­,kùòå"ƒa³Ù¹¹¹ÿýwJJÊÓ§Oétº®®.›Íž>}:þü\ ___OOÏ®6mþ‚F£8qbåÊ•§OŸ.,,¬««sqq144ôðð˜2e õcÇŽ;6..®££côèÑ&L˜1cÆ¥K—¶lÙ2sæL²›«««¶¶¶È;lhh¸eËêÆ—Ëݲe u­A-mmmk×®e±X‡{xxØØØl<áëë››››˜˜XVVfoo?jÔ(KKKƒ!ðÂQ._¾\QQOI^^>44´¹¹ÏÀ¥¬¬¬œoݺuöìÙû÷ïëé鹸¸,[¶Œºl„Ü›ÓÝÝýÊ•+'OžLJJb2™NNN‹-˜"5nÜ8ƒ®Ö/¦§§ïÝ»755µ´´TKKËÝÝý£>¢æ¡B:::;wîÌÈÈÐÑÑqrrš9s¦¥¥åóçÏgΜ)P^aÏž=óæÍ;qâD~~~CCÃøñãfΜIV¦À!yyy c``°eËjáR‚ .\Èçóg̘ÑÕmôk………¦¦¦ÙÙÙ o윖–†Ó”À ‡çM °··WUU•|0ýE—Ë2ºS§NÍŸ?ßÓÓóêÕ«=xÚ£G.^¼888øØ±câ{æææ²Ùl33³üüü ¤…Ãá$$$àš¸<¯«nNNNÿý÷Ÿ$ú ––]]]áõëׯ߻w¯TBêÄm…€Ä<|øP`Cµ¨¨¨eË–)))áz=¨«Lß§'ô ,kæÌ™?ÿü³øÏpH‰EôMQQQÂ)„Ðܹs%L?Ò×WL€AbíÚµOŸ>uww722ª®®~ðàAVV–¼¼üáÇÅoòºÚùâ}z@?ræÌ>Ÿ/¦Þá6»0˜qàÀáv6›íêê*ùxúÈ2€>ÁÖÖ6///""«¯¯¿`Á‚;wõì…‚À¥Þع«=M _‹ŒŒnœƒÁèΉ§OŸr8Ø70`”–– ÿïøðá¥K—"„êêêΟ?Ïd2ƒƒƒ¥ }<ÏÚÚ://O Éd¾|ùRGGG*Qõ0—ô!***xˆÞC§Ó---»ÙyĈ½ HÞéÓ§…S 222~~~øk55µÅ‹K<. 9räˆpŠ!4þ|H1¼Ìe‘±cÇÞ¿_ ÑÛÛ;66V*ñ}MSS“••ÕË—/Úeeeóòò†*•¨úØc,JJJ’““…Û% Ð7­\¹R8Å€Z½z5¤º² À`!r¹‹Åòõõ•J<@_ó÷ߟMNN~õêUŸ¹µµõ«¯¾ 2dHŸ\À–-[BCC™ÌÿÛÇä‡~ ¥ÑhdKYYYrròóçÏ…ß¾}{hhhoÙM|>ÿîÝ»Ÿþ¹‚‚ÞkÓÒÒòï¿ÿæóù"¹}û¶———‚‚‚–––¦¦æ¢E‹…»EEEmÚ´ÉÓÓ“Íf³Ùìn¾¯®_¿Îf³----Zô>O 0xDEE 7ÊÉÉÍš5KòÁ}ÍÚµk³²²„Û Ɖ'äåå%REô+¦¦¦¡ÿý—lÁ+))ñù|²ÑÄÄ!”••ÕKalÛ¶ !ôå—_öÒù§L™‚ºxñbŸùîÝ»!GGÇ?³€òòr„ªª*ÙRWW‡RPPàñxdã'Ÿ|‚Ú»w¯Àáõõõ4M^^¾³³³·CíŽÛ·oãŸ&“iaaáææÆb±pËúõë…ûïÛ·§½ÌÍÍ}}}ñn7l6»££ƒÚ­¨¨HàçQVV–Ëå¾1žÜÜ\UUU1€°‘#G ÿ0gÎiÇHßçŸÞÕyÇŽÒŽ®ŸéOsð¨ŒúwÒ£GBä'ä OŸ>•——·´´ì¥HÒÓÓB£Fêwçøð!úߨKð…É•¶¶¶ºº:ê¬üò ?Ó!C†´¶¶Ö××3ŒÞµ;222<==OŸ>ÝÜÜœ››{ëÖ­ÊÊÊeË–!„öíÛ—™™Ií³~ýz&“——wîܹ¬¬,ssó'Ož„‡‡S{>{ölÖ¬Y[·n½téÒ·ß~‹²µµ¥Îþ©¦¦fÆŒZZZÆÆÆH"¯&`(,,Ä¿™Àr `ýúõóåIS¦LÙ¼y³„ãéïúS–!== >>ø™.\¸?ºsçNwwwáúÑÑÑžžžjjj222¦¦¦+W®Ä 1¨Ö­[çîîþðáÜœœ•+WÚÙÙÉÊÊš˜˜8p ;ÏZ$2¹@¥¥¥¥  €’““#þùçÚÚÚqãÆ-X°€ÚÙÆÆ!$²ÖÍ—fÅŠ÷ïߊŠâp8I7èŠÈÝ%f̘¡¨¨(ù`€¾€Ïç/_¾\xœˆÑéô'NhkkK8ª@jk5Þ¶­^½šÚhff†ÊÌÌèvèÐ!²eîܹ¡#GŽœ¿ŸV¬XA¶àíIX,–««k@@€‹‹‹¬¬¬‘‘î0qâÄ¡C‡"„† bÿÚ‡~ˆ>}:BèÇ444d0–––¦¦¦¡¡¡Ä몲²²¶¶¶3f̰³³Ã)1yyùÇãÃ‹ŠŠìíí555BúúúäùùåÜáéÓ§cÇŽE)++»¹¹M™2ï=fkk+°àÿüùóxݾ¡¡áœ9slllètzDD“Éd0---âouMM NvÈÉÉ3fúôéø§KWW·ººšÚóîÝ»†††!--­Y³f9;;#„öîÝ‹'óçää=íììÐë )íí펎Žúúú! ò™~ú駸3žÝððáCòðööö9sæà7­©©)’¡¡aUU5$555„ÐÑ£G‡ ¢££3vìXòoè“'OŠâo%>>Ÿ¶¤¤·p¹\üò?^ 3^C§Ó©D¨ÏNFF!ôàÁ1Wܹs'BèÀACíܹS <äf±XÔÎ|ðBÈÒÒ²  ·477{{{#„>úè#²žfB£ÑÔÕÕÉ*¡mmmxñ‚øçÞ}õõõ8âééI6^¹r!¤®®.ô!âÎ;8k#òl©©©!êOÀéÓ§i4yÿñ¤ˆ´uëVá?ž”””Z[[¥ åååøâ®lß¾]Ú1öcý&ËÐÒÒ‚ɸì–˜˜ˆrrrè&##Cóšššètº@&óÓÿûï?ümCCFÓÒÒ"RÍŸ?‰šQZZŠß‘K–,éæ“ºyó&BÈÙÙ™Úhdd„*,,è¼zõjá”ñú&xyyáoù|¾­­-BèĉÔnmmmxâ9ó¢+¸ð‰‡‡uO.`aaA¶à„È?ü pœè;v,Ùòßÿ!„FEíæîfp0¼ûÈ‘#É–„„„‰‰IYYµçãÇÑÿîd³ .\ öÄóìííÅ?÷njmm0a¾µµµdû¦M›B‡ÄÄÄ „ôôôDžðСC!‡®®øßÿÉËË{zz’oc\Žšt€®X[[ ÿý4oÞ3¾ÐâÅ‹…Ÿocc#úß4ðëR\\\__oll,œGèüüùóÄÄD]]]ž‡ÇãÑét\MƒÉÈÈøùçŸ[ZZðì„Ð¥K—BC‡ÅŸOÚÙÙQ7^*‘»KÌž=[äî9ÀÀÃår·mÛöã?òx¼®úÐh´ƒ®X±B’ Tý8ËÐÞÞþäÉ&“‰ççwÕ­«q;ÞRQ`Ø)##³xñâÅ‹ggg;v,<<üìÙ³•••IIIâÏF^ZxÒDmm­ŸŸNŸ2e ÙNžŠÓ™¡ .àŠƒ]áp8xòðÇéIII\.×ÄÄWgè ¾Ðo¿ý†Ë%ŠëP_¨¸¸øÙ³gÔÙ¹\îãÇ õ•êê™ w~òä B—«’’‚²··'ƒ¯¨¨PVV¦NÁD.Ùx+/^œ7o^KKËêÕ«÷íÛ‡«„Àx{Kª .´··>\ä\†¼¼¼¶¶6ƒA>ªØØX„ÐçŸ.üP~~¾£££ªªªðvž€effâÉ\`¹€Á€ ˆ˜˜˜ï¿ÿª×…ƒK,°­d8þÌV Cgg§ùi îF§ÓÉÑAyyyt:]`ª|}}=þ4¸«a§µµuhhh`` ““Ó;wššš”••ÑëR‰WVV¾|ùR¸žBèÎ;µµµÞÞÞÔBèÊ•+/^¼È’tu~<|­©©éêa|>ŸF£—QPáMßøa>¾ð²a¸:ƒð…~úé'>ŸO]Û’••Åáp¬­­©(ðϹpÒ$''§££ÃÊÊŠ«ã£ÚÚÚzòx¼ÐÐP„К5kp Nô888¬Áë\”””ð¾§ï`ÿþýx Éž={„ëPŒëêꪪª¨?üðBè‹/¾yÛÒÒR8=QWW7uêTáC._¾ÜØØèêê:tèP\nD9‘AUUUäï`ÀàñxQQQ;wîÌÊÊßsôèÑLJ?ª{PÿÈ2<~ü˜Ëå¾qÚ^¬Îf³ÉÑZ{{{{{;F+//766ÆA|ôÑG­­­4MüÔ€êêj‚ pÕCÜRVV†ž fB>þ(¾¥¥…ÚXWW‡gã°ÙlêØ»«óÛØØ¤¦¦^ºtÉÃÃCøAàqµœœœŽŽNEEERRÞú‹ŠŠÂs7Þøa>ž€pñâE¼ÍgWB 6¬¬¬,11q̘1d‡»wï=zucÑ ž A O:À?ð<àñxÔÛ¶m+((prr"ïIWÓIpéP{{{겂ŒŒŒòòr===‘3H<oÆ ¿þú«¢¢âÉ“'ñ¶]±°°ÈÈȸvíš——Ùøõ×_çææš››/]ºTäQb¨©©áúT|>¿C¨7!TTTTPP0dȼI*ˆ,ÊàëëKÖH.—ûï¿ÿþøãdü®0ŒM›6}ÿý÷eïÁ{êk¹ñ0ŒÍf“•Q÷J0ÈËË㽿þú뢢"‡“’’2iÒ$¼€©©)™>øâ‹/.\˜˜˜ØÜÜŒª©©9sæÌºuëB«V­"O8lØ0„О={Ο?ŸžžŽ‡¯"/MÂu"oß¾}üøñ¶¶¶ŽŽŽØØØQ£F544‚Ï¿iÓ¦ëׯ§§§“Ó\.\H£Ñöïß¿mÛ6<=ž ˆŠŠŠ‹/Μ9g0¼·Â_|‡ëÕÕÕû÷ï_°`."ðÆ,CPP¼¼ü… Ö¬YCnÜP]]}ãÆ?üðï¿ÿ¸Phhè•+WB'Ožœ6m~ÞX‚?ÓíÛ·ÇÅÅ¥§§gffR;SŸ8q¢µµõÓ§O×­[‡“5Ož}Z\\Œ¿xôè‘@Yýî——_¶lÙ—_~ihhØ¡eƒŽ»»{ee%¤A§OŸn÷÷÷§nÖôõõõd6ü÷ùóçïyfeeåO>ùä³Ï>ë~Éðþ Ëeeero’““KJJ„Û% }ÇëÂårß¹‘Ï狼PW+”Ŭ\~ÛCzð4!„Éd 7ö¬®âýT[[[mmmÝkÔ¯…¿år¹=€ššÚºuëÖ­[§®®Þã'âA–hDÖ}ÔÕÕ¥–= kooooookk#ÿøVü¿ÂG )åÉú:ÞÛ‰Œ>ˆN§S+ó£ÝðÏÆçóÛ_# ¨Ä7¶´´ÔÕÕ½ÿ4„w¦­­ýÙgŸ­Zµ >Y”È2 ÑÅr‰€€:.ùxÀ ÕÒÒÒØØØÔÔÔÔÔ„¿ÿm[[™èèè 0Èðù|>ŸßŸiƒABNNnìØ±sæÌYºt©¼¼¼´ÃÔ Ë (wïÞ---n‡åàq8œêêꪪªšššîä °®–@Oa0£Fòððððð7nœœœœ´#A–`Dî.a``0~üxÉú8W[[[ݵªªªêêꦦ&iG ÿÇÚÚgÜÜÜTTT¤Y`ààóùgΜn Ñh’H AõõõbÒX]],Lôeººº#FŒ1bÄðáÃñ–––ÚÚÚÒŽ ˆY`àHLL¬¨¨n ’|0 ·ñêÕ«!/^¼¨©©áñxÒºKQQ‘šJÀ_ >*,ôGe‘»K»ººJ>ÐSÚÚÚ„S 8› Å*îƒÁ`¾&##Ã"ÜHméªÀjW3‰ÄÌ0zÛCzð|>Ÿ×›ºŠ <4MYYY]]]MM ÿ+æ Xø0@– x<^tt´pû|Ë%ú…ÖÖÖ'Ož dªªª¤šÔ0™Lyyy¹×Þøµ˜,ëÉi?ÝA¡·³}\¬Q¢uC7»‰D§ÓeeeåD¡þXuE^^^UUU]]]UU•Á`¼ÿóýü2ˆ[·nUVV ·Ãr‰¾©½½ýÉ“'ÙÅÅŬJþ$SYYyÈk"¿Æ_(** d`ˆ2ðÐét:.###í@¤ƒ jÒÏç¿mv@ÚÏ€7ƒ,0@ˆÜ]bøðáNNN’èèèÈËË# YYYOŸ>íG{=Òétüɤ˜dpâ@II EPÑh4<}FÚЋàý gÏžn ”|0€Ëåæçç“ …ìììÂÂB^_]‘>dÈÍ×´´´4ÿnQSSëªè@Y` ¸~ýzMMp;,— —••uÿþýû÷罹¦p¹\i…äääD¦ ¨ßjhh°X,iG `à€,0ˆÜ]ÂÔÔÔÑÑQòÁ µµµÉÉÉ8³’’ÒÜÜ,•0´µµ‡Jþkdd„“JJJR À`Y ßãr¹çÎn‡‰ =‹Ïççääà´Â½{÷òóó%V¬QFFÆÈÈH ›0tèP###ØL@ŸY ß»zõj]]p;exõõõ)))÷îÝÃ{õr222æææÃ‡È&èêêBYýd€~Oäî–––vvv’f¨¯¯¿víZBB½{÷žÏðáçM›æåå5yòdeeåŒ$h}pÀæææÂ‚‚‚ÂÂÂgÏžáy "×lÊÊÊÆÆÆÂÙ===&íè}T@@@tt´@ã¨Q£RSS¥äµ¶¶âäB|||GGÇ»DAAÁÝÝÝËËkÚ´i°ÒxO0—Hˆ@BÿûÆÿ¦¦¦ìììììlv‹ennneeeeeÅf³­¬¬ÌÍÍY,–T‚ô)ÍÍÍqqqÂíƒd¹D^^ÞÁƒÿù矺ººw;ƒ ž¶0aÂYYÙž ´`.èMMM™™™=JOOÏÏχ„Bb0&&&Ô¼ƒ¥¥¥‚‚‚´ãHÚ©S§æÏŸ/ÜþìÙ³¡C‡J>Éàr¹çÎ;xðàÍ›7ßápyyyoooooïiÓ¦ôxx€,èeeeéééééé8³PTTo-‰¡ÑhC‡ÅygggcccièusæÌ9þ¼@£‹‹Krr²TâémÏž=;tèPxxø«W¯ÞöX‹5mÚ´¹sçΚ5 vzdÀ»àóùyyyé¯=zô¨ªªJÚA‰@£ÑTTTÔÔÔTTTètº “Éó-ŸÏokkkkkkooo{Mä×ï¹;Z/ÑÓÓsqqquuuqqqrrRTT”vD€ÖØØ¨­­-\‰ ,,lÆ R ©—ðùüØØØƒÆÇÇ¿í¯\ƒ1yòä¹sçúùù©ªªöR„ ‚,è–ÖÖÖÇ“S?~ÜÚÚ*­` †®®®¾¾¾ºººššššššªªªÚkäתªª8¹Ð«Áp¹Ü¶¶¶úúúêêꪪª®þ­­­•V>‚Á`X[[»ººâ¤›Í†r’ Çh¤Ñh%%%†††R ©Ç•——‡‡‡:t¨¤¤ä­¤ÑhãÇŸ;wn@@€¶¶v/…‘ ËD«¬¬¤NUÈÏÏ—ð YEEÅÀÀÀÀÀ@__ßà5üµŽŽƒÁd0ïÏç×ÖÖâŒCeeåóçÏŸ?þìÙ3üoCCƒÄ"QQQqrrÂ---‰]ЃfΜyéÒ%ÆqãÆÝ¹sG*ñô¬ÜÜÜüñäÉ“ou ““ÓܹsLªèw Ëþ¿ššš¤¤¤àÌBYY™d®+''7bÄÓ×,,,ŒŒŒôõõÕ$ÿ†††gÏž‘IòßšššÞ¾ôˆ#pÆÁÕÕÕÁÁv¯ _¨¯¯×ÑÑáp8íûöí[·nTBê);v숎Ž~«Ô¶©©éâÅ‹çÎ;bĈދ ÝY†A­¢¢"11ñöíÛ‰‰‰ÙÙÙ½ýfPRR2111¥011144„ ü]innÎÏÏòäIÎkEEE<¯—.'++ëèèHt>|x/]ðžŽ=ºxñbF:þòåK===©„ôþRRRvìØqñâÅîÂd2gÍšµråJOOOø¯è# Ë0è<þœÌ,ôÞ…”””ìíí,--MLLtuu{ïrƒ‡ÃÉÏÏÇœ}ÈÏÏþ<³Ghkk3fÊ”)^^^&&&½q À»ñöö¾|ù²@ãĉoß¾-•xÞÓíÛ··oß~íÚµîbhh¸|ùòeË–éëë÷^`xeòóóÉÌÂÛÖÐê>]]]GGGœY055…O–$€Çãåäääææ>xð 99¹7V»˜ššNŸ>ÝËËËÝÝ]AA¡ÇÏè¾ÚÚZ]]].—+ÐþÛo¿­ZµJ*!½³øøøíÛ·ß½{·›ýi4Ú´iÓV®\éããÓï ôƒd&‚ ²²²pf!))©¢¢¢Ç/A£ÑLMM©i˜ªÐG¼xñ"%%%99999ùáÇmmm=xrYYÙ‰'zyyyyyYYYõà™Ý¾lÙ2FƒQZZª££#•ÞÁÅ‹·nÝš––ÖÍþZZZK–,Y±bT^ú8È2 <ïÑ£G8³pçÎÚÚÚž=¿¬¬¬µµ5N(8::ÚÛÛ+))õì%@ãr¹™™™ÉÉÉ8ïгkdŒqºÁÃÃcÈ!=xf€S§N½zõª@ãäÉ“¯_¿.•xÞÖ£G6nÜxóæÍnöwuu]·n¿¿?”§úÈ2ôo\.7%%%))éöíÛ÷îÝkjjêÁ“«¨¨à„þ—ÍfËÈÈôàùäÕÔÔ¤¤¤àŒÃÿýW__ß#§e2™cÇŽõòòš>}º½½=¬” ÷TWWëéé ïïøçŸ®X±B*!u_iié×_ýï¿ÿvsÿˆI“&}ýõ×½zdú¥ÒÒÒË—/_¾|ùêÕ«=˜YPVV7nœ““N+ÀAyyyɯeeeõÈºÓ¦Móòòš:uªººúûŸ@õ矮\¹R ‘Éd–——kjjJ%¤îhiiÙµk×Ï?ÿÜÚÚÚþÓ§Oÿæ›oÆŽÛÛ ÇA–¡ßèìì¼ÿ~\\ÜåË—322zê´êêê&L˜8qâĉ¡˜Ö ÕÒÒ’ššJ®­(//ÏÒét'''\3ÒÙÙ&8Ð#<<ÿÈ‘#ß~ûmw~«Ðh4__ßo¾ùfäÈ‘ˆ ½² }]EEE|||\\ÜÕ«W{j~»ŽŽN+¸¹¹ÙØØÀð{öìÙÕ«Wããã¯]»ÖØØøžg322úàƒ‚‚‚œ{$<§W¯^O; _²d‰TBïÚµk7nÌÌÌ|cOƒôÕW_Y[[K 0ôÈ2ôE|>?%%%.....îÑ£G=ò¹¹¹áä‚……ÅûŸ xÍåË—ãããÓÓÓßóÝ8lذÀÀÀ   ø €wðû￯^½Z QFFæÕ«WjjjR ©+UUUŸ~úéÉ“'ߨ“Éd.\¸0$$ÄÌÌL ·A–¡©ªªJHHˆ‹‹KHHè‘"LMMÉ9 Æ {ÿ‚AîÕ«W ñññW¯^­®®~ŸS™ššÙÚÚöTx xnnn‰‰‰ÞÞÞ±±±R‰§+Çß°aCw~KÌš5k÷îÝæææˆ ’Y)#âÁƒ—/_Ž‹‹KMMífÙí®Ðh46›Ó 'NÔ××ï©8 âóù©©©ññññññÿý÷ßû”d³ÙAAAl6»#`à)//744þoâèÑ£}ô‘TBöüùó•+WÆÇÇ¿±çÈ‘#ùåww÷Þ Yéàñx·nÝ:sæÌ¹sç^½zõžg³µµ233ñ‡;wîp¹Üw;ÉÈ‘#ñìXæÕøñãïÞ½+Ð8kÖ¬˜˜©ÄC•½lÙ²äädñÝ”””6mÚ´qãFyyyÉɃ,ƒ$ttt\¹råÌ™3.\xÏ}",--§OŸîíí=qâD‹ÕSгš››oܸwþüùwž­ãìì¼`Á‚ ôµ²vHÞË—/…ÿË>~üø‡~(•0‚ vïÞýí·ßr81Ý Æ’%K~øá‰Å©€,C/jkk»|ùrttôÅ‹›ššÞù<òòò“&Mòööööö>|xF@oãñx·oߎŒŒ<{öì»Íß‘““ó÷÷_¶l™››̯ƒÖž={>ûì3F99¹ÊÊJeee©„„ªªª NHHßÍÎÎîðáÃNNN’‰ ÒY†ž×ÜÜ×ÒÒòÎç1bÎ,¸»»ÃäRÐßuvvÞ¸q#22òܹsuuuïpSSÓ¥K—.Z´HWW·§£ ¯suuMIIhœ3gÎÙ³g¥BèæÍ›~øayy¹˜>²²²ß|óͦM›ddd$¤ ² =¦½½=&&&""">>¾½½ýÝNÂb±&Nœˆ“ =!}—˽zõjdddLLLCCÃÛÎd2}||–-[æååÅ`0z#BúšçÏŸ‹,S$ñpÇÛ¶mÛöíÛÅï‹4vìØÃ‡Ãö1À`Y†÷EÄ;wŽ;vúôéw2a†††3fÌðöööððPTTìÙè›:::âã㣢¢.\¸ðÆ¢ô /^¼téR( ¼Ý»wùå— •••’ÿ/£´´tþüù‰‰‰bú())ýøã«V­¢Óé }dÞ]aaá±cÇŽ?^\\üng6l˜¿¿@@€‹‹ ,8ƒV[[[\\\dddlllkkë[K£Ñ<==—-[æëë+¦*AßÿýÖ­[ß;X¤ÀÉÉ)55U ñƒ>ˆŠŠ’p$ÉÉÉ3gÎ_cÅËËëÏ?ÿ466–XTèS ËðÖêêê"##;vÿþýw;ƒ™™N.Œ5ªgc _kii¹téRddäåË—ßvÙ‘¦¦æ²eËÖ¬Yc`` ühLLŒ¯¯ï‰'æÏŸßCÁ !OŸ>511n?s挿¿¿$#¹xñâܹsŤåääöîÝûñÇK2*ô5eè..—÷ï¿ÿ^¼xQü~]]a³Ùvvv=IcccDDÄáÇ;;;œ\€ X¼­ÌÌÌÇ?~üm·¥˜0a† fÏžM§Ó/\¸0{ölÜîççÝ ‘Ð[ÓÓÓçÍ›wòäI‰Å°eË–mÛ¶‰é°hÑ¢@]! È2tÇ344¬¨¨x«£FàïïoffÖK0H´··Ÿ={öðá÷nÝz«_Y#FŒX¿~ýßÿ‘‘A6FFFöB˜ô¼‚‚sssáösçÎùúúJ €ÎÎΕ+W†‡‡wÕAIIé÷ß–@0è ËÐ-7n ëNO›… Î;×ÈȨ·£`°)**úûï¿=ZVVöng Ñh999ZZZ=½aûöíß~û­@ã!C*++eee{ûê---qqq]u°··ŠŠ™À [LuËÂ… ÅwÐÕÕݰaãG?~üÅ_@Š€Þ`bb²cÇŽ’’’ .Ìš5‹Éd¾í‚¨®®^³fMo„@“““ÓÕÕhœ={¶R UUU“&M“b˜6mÚ;w Å0—¡»¨“®1yyy__ßààà©S§2 ©À U^^~ôèÑC‡½Ãn²ÑÑÑ~~~½=‹Ïçß¾};"""::º¦¦!tñâEŸ^½hQQ‘——WaaaW.\þ™> xeè®°°°7â¯i4š››ÛÂ… ”••¥ƒŸÏ?þ|XXØÝ»w»yFÓÒÒÊÉÉÑÐÐèÕØèAׯ_?wîÜþýûY,Vï](55uÆŒ•••]uؼyóÎ;{/ôkeè®ŠŠ CCC33³ààà K;"Àÿøï¿ÿÂÂÂΜ9#f³=ª?üðøñã½ýKVVÖøñãD>J§Ó÷ïß¿zõj G€~² o!?? ÐÇ•””ìß¿ÿСCoì3kÖ, D@_S__¯ªª*ÐXZZ:f̘/^ˆ}zWÒh‚¿÷bcc½½½{?.úùóçŸ:u ÿ8¸ººjhhÄÆÆŠìikk{ùòe G€~ªßïA•ŸŸóæÍ7n¤¤¤”””¼1iÂápjjjðf`Âäää,--ÝÜÜ&Mšäææ&¼fô_555·nݺyófRRR^^^GG‡øþ<¯¡¡AL ´¡C‡º¸¸LžþwöF™Š²APq1ŠŠ­Ö:êF[÷Þm]µuàG« Õ:ªVÅî *«*²A”¥€²÷HI~<¿Þ÷š@LB’˸×_p¹ñ\òÜûÞïgÖÖ uþšš0Qåææ–••5þ&“ ö)===Ìšikk ö)+++²ë­ÂÃáp>}úFÌüüüšš.%¡R©x ÑÕÕíÞ½»ã¿˜ššJAHˆØ‚—f|||g»ÙÛÛGEEIA$¥…Á`äççèRXXÈ¥-ÍÍÍšššºÿ¥W¯^ -öööÚÚÚDß aTVVbÞµªª*¼w­±±‘ÅbqiŽ(éZSZš››sssA¨ c IDATm>}úÄ5æ´¶¶jkkãÕFOOÏÊÊ s³I´É‰Â —± ÕÕÕ÷ïßŠŠŠŽŽ.))Ádjj Ï€ƒƒƒ••~§§§§¦¦ÖÜÜŒkjj°ð‡¼¼¼––ìTT*uÀ€¾¾¾cÇŽ9r$¹0GÚÛÛŸ>}úìÙ³èè茌 ¼¶kiiA ÌÒ 1=ÑÕÕÕÑÑ¡ÓéxU©¯¯/,,Ä¿Ëñ²°°9räÈ‘#'OžL&ùKuuõ… ôõõy­ ªªª¢³¾¾þŸþ‰ŽŽNLLäýõ…BMMÍÎήoß¾#FŒðõõurrùT$2EAAAtttLLLfffnn.þm",úúúŽŽŽîîî¾¾¾¾¾¾ÆÆÆb”cÊ”)÷îÝã¿©©é«W¯lll$!€2ÓÞÞžœœõòåËwïÞ±ÙlÑNE¡PzöìÙ§O//¯‘#Gzxx¨««‹WZ™¢ªª \&)))999ÂZÉñhhhØÛÛ»¸¸€wÍÞÞ^Œr’Èt:=...***...;;›kõ$4ÍÊÊÊÉÉÉÇÇÇ×××ÝÝ\"‘tˆ;èèèÄÄÄ 8P\W$IOOˆˆˆŽŽ~þüycc#þ####Ð[[[¼Âhkk·¶¶â}Ôuuu 0eeeøóhhh€¹aÔ¨QC‡íÊkŽDvhii‰ˆˆ€¡?;EÑh4kkkPžž={âÇ===Æ5ÔTVVbï#lêXXX`ï£=zHý.IÄ ‡Ã‰‹‹‹ŒŒãW o=@m¬­­õôô𚣩©ÙÜÜŒsjkkß¿cW<¸¾¾þ°aÃ|}}njӯ_?éÞ"‰L#V†¤¤¤óçχ††bšíåå5aÂ__ßÁƒ‹ìŸä`çÎÒÒRØèæææïï?þ|2|T6©¨¨¸xñbppð›7o`K¯^½¦L™)0X)uñÂ`0¢££>|˜””MLLæÌ™óý÷ß»ººJâ¢$’ãÕ«WÁÁÁׯ_Ç|DØJÏÇÇÇÉÉÉÞÞ^doaIIINNNRRRLLÌ‹/0£…Bññññ÷÷Ÿ1c†žžžxî„D2Ðéôû÷ï?yò³¨««{zzúúú2ÄÑÑÑÒÒR´Pd&“ùáÇìììØØØèèh¼…KSSsÊ”) ,=zt×}GcÇŽ}ö쟦M›váÂ.^ˆäÓ§OW®\ ~ûö-¶ÑÔÔtĈ#FŒèß¿¿£££È¯§†††ÜÜÜÌÌL˜±à»ZYYÍŸ?ßßߟÌé“S8NLLÌÅ‹oݺ…½,¨Tª«««¯¯ïW_}åäädkk+Zø:¸Örrr`ƒ÷—P©ÔQ£FùûûO:UKKKl÷C"-rrr‚ƒƒ/]º„,--ÁÓÖ¯_?‘mÖÕÕÕ999iii111111˜3!äâââïï?wî\ssó®Þ‰À‘mbbbFIkeeµsçμ¼¢=zlÙ²åÍ›7]9óˆ#øÌ ÀÞ£Gëׯ‹ë^”¦¦¦àààÑ£Gcö&]]ÝéÓ§ÿùçŸYYYºh~~þ™3gæÌ™ƒ÷…xyy>}º¶¶VB%;999Û·oǸ9::®]»öÎ;ÕÕÕ’¸"NÿçŸ~ýõ×aÆá5váÂ…ÑÑÑl6[%/555'Nœ:t(¦6&&&óæÍ;wî܇$qE6›™™yìØ±©S§b&i6nܸ+W®´´´Hâ¢$ò‚ìZÂÃñ¦Yjjj , |˜«¯¯?{ö,öôjhh¬Zµª¨¨ˆ@‘H8N~~þâÅ‹1[þ°aÃ.^¼ØÔÔD H,ëÉ“'³gÏÆ–Ž#GŽŒŒŒ$P$>deeÍ;sëëë/]º466Vš2”—— 0›ØÛÛÿý÷ßmmmÒƒ¤CØlöÝ»wŒý:vvv»wï.((¦ééé7nÄ׆?~ü‹/D;›··7+žiÓ¦‘6/¡¨­­Ý½{w÷îÝá ¤R©cÆŒ¹|ùrss³Ôdhkk»{÷î·ß~‹½uuuüñDz²2©É@"‰‰‰S¦LÁR]ºwï¾zõêÄÄDiÊP\\¼ÿþ>}ú`ƒ€««kHHˆ”Ý6$‚SZZºqãF¬¬ººúôéÓ|øpÆŒX¶àðáß>}*ìy† òŤ}•Õ«W“/8Á©¨¨Øºu+–ôäèèø¿ÿýØ9LUUÕ±cÇÜÝÝA$MMÍ5kÖ@O.™âùóçãÆƒŸ‰F£}óÍ7·oßf0Š”°råJ,zËÁÁáüùóÒ\¸’|‘ÂÂÂ+V`óÌ!C†œ8q¢¦¦†@‘ŠŠŠöíÛ‡E†îÚµ‹X‘HA¶¬ •••ßÿ=Ì{ôôô¶mÛVQQA´P7qâDÌØ|öìY2¢Lj´··ÿñÇ0“£P(Ó¦MKII!Z¨NÁÛ˜)ÊÒ¥K%ñH"8ééé~~~Ø|nÞ¼y’‹a–––?þøÃÂÂ$ìѣDZcÇH²”¹rå Vt½{÷î»wï–©˜ó¢¢¢U«Vihh`“ˈˆÁ0`+ÃÔ©Ssss%'¿‚Q__¿iÓ&,‰ÝÝÝýÖ­[25+ˆˆˆðõõñÔÔÔ/^üùóg¢…"áp8œØØXøiTUU-Z$åÔ`þÔ××àmßäŒW())Y¸p!3;f̘˜˜¢…ú?X,Vhh(V›LWWwëÖ­DËE"=dÅÊÀf³Ïœ9Õh4ÚêÕ«ej2LJ„„„AƒÁ#äååíI$Êëׯ1·Œ¼|ç?üðLë/\¸@´DJJccãÆáŬ¦¦¶dÉ’÷ïß-TÇ0Œ3gÎØÚÚ‚¶»¹¹‘±0Ò!;;[™››:tˆØ$,>|þüyË–-XBììÙ³\:öíÛ·3+ƒ———¬Å…É8W¯^Ūy{{?~ü˜h‰:%66v„ ª¾¾þñãÇÉ0x©ªªZ´h<‰2fÒÜÜ„•òôôLKK#Z(%¥½½=((Ê7R(”É“''$$-TǰÙìû÷ïcÉæ={ö¼qãÑB‘H ™°2äääxzzbÖ,;¥;„Åb:u L$***›7o&6ÂMiiiY¹r%Ô%211‘Ç…ú«W¯°Ü{™]ß**7oÞÄæÌ™S\\L´D_¦½½ýܹsàG¢P(‹/&ca$GKKËöíÛ!•]GGç÷ß'6ƒF@ª««×®] éc.ðVøÛÞÞþÖ­[Ò‘Y1ÈÎÎ5j|‡ÎÎÎB…“HRR6ï4hPRRÑ)l6ûï¿ÿ†"0°ËEÉ ƒ‘¤4mÆ ¤wZÊÄÇÇ»¹¹ÁÃ;lØ0y±õ„……9::‚ØãÆ“©h A¼•áÊ•+à„122:wîœü†`UVVbéAƒI¨š«2“ ÙÑT*uÅŠòíÂK{{û±cÇ ÑQ__ŸœÓK‡¢¢",E¢oß¾ÑÑÑDK$555+V¬›‘‘Qpp0Ñ) ááá666 $3f̵’@_$--ÍËË [:òó²¶¶ÆÛŒŒŒŽ?NV&“¹sçN¼AJ¾¾=6›}öìYXåR©ÔU«VÉlÀŽâñöí[¬À¹»»{||<Ñ ÇçÏŸç΋y§ïܹC´DJACCÃÒ¥KaÄ633»téÑ ƒÁ€´2uuõÝ»w“y Š ‘V†ÖÖÖ%K–À 5vìXY.Á 8OŸ>511!Wb³FYXXˆ\S]¦(--Å:É­[·N¾¦§rÇýû÷!ÚHGGçСCò[¼*)) ‹<\°`4KÖ+6L&óçŸÆüùOž'L˜PUUE´Db£½½}ÇŽà2dHaa!Ñ) mmm›7o†9´———̦¼ ›Í>xð Ô•pvv–©¢•rJqq1æWܰaƒtô¨©©™6mÜѼyó: i655¥R©ßÿ½ü®‰âáÇХ²[·n÷ïß'Z1ðòåËÞ½{#„´´´þþûo¢ÅQXðÞ5??¿òòr¢%ê*ÑÓ˜ÁƒK¹¹¯òpêÔ)(ôkcc#嶦âÖ­[úúú!ù5ë“ð‡+ëW¯À¯Ø£Gþù‡$J{{;6ìŽ3†LZ™ššhꮢ¢ràÀE²Fa¬ªª ÅÀÓ.;DEEÁ„PQ½k%%%Æ ƒ÷ÑÞ½{‰GA(--…¸o55µcÇŽ-Žøa0ëÖ­µ™4iRKK Ñ‘ˆi[Ο?¾S¦L‘‹ÂÝ]$--ÍÌÌ !dggGÖƒŠœœKKK„¥¥evv6ÑâHœææfè.¦¦¦J´8rODD4y2dˆ\4’ 6›}àÀX'ûûû+ä²GrìØ±C £ÔÖÖNž<"Âä±/ŒPYY9dÈðÖ>|øhq$H||§öööŸþË& ß]$''ÇÊÊ !Ô«W/Åt½sçLؼ½½kjjˆ‡DlHÕÊð¿ÿýFŸÅ‹+O`Ìû÷ï¡Ý½™™™¼ô›!œÄÄDˆaîׯŸò†a2™þþþx÷î´“pss+++#Z©ÒØØ8zôh„††ÆóçωGþسg¼ˆ–EÚÄÄÄ@‘#G*@×iÁ˜&LP¶àD¬›©©i~~>ÑâtiX?~ µ~úé')\Nf©®®vvv†,esÑ Hee¥££#BhРA D‹C$kÖ¬!çvÂríÚ5XAíÞ½›hYˆ!''œ®¾¾¾äÄ®C~øá„ŽŽNll,Ѳö˜(­Ñ_pŠ‹‹¡¿£§§§rZî Æ”)S Ezz:ÑâȧOŸÃéÓ§‰–…RSS¡ÜôéÓY,ÑâÈIIIP¡à»ï¾SÎBK555DÙØØ|þü™hqHº„Ä­ qqqÐQâ‡~ôµdlÊâíí­´ŽúÎhjj‚–6 \I@X,ÖÌ™3ɹà<}úÌÿ6l Z"IOO700@M›6œØq•ÉÔÔÔž={F´,DròäIXÿ=Pù€9úöí«ÌŽ:îëë 5)”'a¤‹Üºu lyû÷ï'Z"Á–Ë—/'Z9 77úš7Nyò=y©¨¨€:8ýû÷W¤ÎJˆd­ %%%ðÀ|óÍ7ÊSî‘?ïÞ½ƒ¨æ9sæ-‹l™Ò={ö,,,$Z™€Á`@´j¯^½ÈL{þ¼~ýªÌŸ?_Ù%xyñâ…¦¦&BhÙ²eDË"CAiU²‡ ‡Ãùõ×_¡2Åýû÷‰–Einnöôô„$ÇOŸ>-Á444¸»»#„ìííÉö–_$::ª¬_¿žhYˆ',, ŠïÚµ‹hYdšÒÒR¨J0tèP²˜Eaa!dO>\:**´2´··>REðÄÇǃÓõìÙ³DË"+=z!¤­­™™I´,2Dcc#¤¨Mœ8‘\}:4ÂU¶²\ÔÕÕY[[#„.\H´,2Ê¥K—`¹¨´õêø€Y3ÉD^ Ò¡¥¥¥2g•·µµAŸQ£F‘…*¸¨««³±±!3øð¤¤¤@¸û_ýE´,2GXX…B¡P(>$ZYâƒÌÍÍɼ^¾ýö[(®ä“^^nݺÙ|QQQDË"sNY¹F"V†²²2333„ÐÚµk%q~Å ¾¾ÞÖÖ!ôý÷ß- ‘@9ÒÚŸŋCåéœ,¤5“?---...¡)S¦- alذ!dff¦lm$)) ÕJ[ OCCƒ£Ë‡Ÿ~ú !Ô½{wÒéÊEhh(´ Ž‰‰!ZY¤¶¶ê(ù¤—‹‚‚(ØLÖ­è Ò)+¿HÄÊ 1pà@ƒ!‰ó+ ˜ÏDiÝ—/_†Æõ¤‘’?­­­®®®¡E‹-‹¬@Z3!;;êb=z”hYàÞ½{à#Šˆˆ ZÙåøñã @h˜={6B¨OŸ>dõµÎ`2™^^^¡¯¾úŠ¬ê‘——§§§‡Ú»w/ѲÈ. P ’LÚÚÚ† ͧÉP»Î ²ò‹ø­ OžþL´,°qãFÒ†+&L@M:•hA¦ººÚÈÈH™-tÂ’••yOŸ>%Z"!Ÿ ¡hkkëÓ§BhÛ¶mDËB"(â´2hjj"„îÝ»'ÆÓ*Pz×ÏÏhA¤›Íööö& ›‹¬tuuKJJˆ–…0 ÈÐÖÖ–N§-‹Üðûï¿#„,,,”¡g!‹Å‚ÞãË–-#ZyÂÇÇG9‡åÌÌL …òâÅ ¢e‘òóó!†9,,ŒhYˆdÙ²e!777Ò>%8›7o†ºJ›ðxçΈ***"Z¹áÙ³gÊ™þ)¿ˆÓÊ0g΄ÐĉÅxN%¡°°PKKKy,»÷ï߇¥2™Š&°X¹r%Ñ‚Ãû÷ïÉ C`2™ÎÎΡ-[¶-‹ÄùóÏ?BÆÆÆÊÜÂS222TTTB‘‘‘DË"U† †ò÷÷'Z9 ÛÙÙ)­Á÷õë×T*•¬—$,={öDíÛ·hY ¹¹ÙÒÒRio¿+@ !eKÿ”_ÄfeÈË˃ÒtdÙ$ÑØ²e BhøðáD "  }=Y’M4bcc!ÅF9m4Ðúô›o¾!Zù#::!¤¢¢òþý{¢e‘ ÍÍÍÀ|þüy¢e‘? ñ§»»;Ñ‚Hëׯ#„ ÊËˉ–EÎhii±¶¶F-‹D ÓéÐ) 44”hYä•­[·"„¼½½‰DY'Nœ Zi3qâD„Њ+ˆD^¹wïBÈÐа¡¡hY¤ØÁI;¸hTWWC8ógψ–…ä P8ê2kÖ¬9~üø¸qãÂÃÃ<$99Ìx~ª¡¡±zõj°öµµµÖ××c­]»ÖÐаëb BFFÆõëד’’ÊËË äááÑÞÞÞØØ¥k0 ÆÅ‹_½z•––fmmíååÕ¿ÿ»wïþöÛoÆÆÆ^ëãÇvvvL&3))iàÀ¸â‰ýꫯ´´´ ÿfX,V```MM ü«®®¾råJÞ=oܸ‘––Æb±B4mòäÉ!˜Lfppð«W¯RRRz÷îíåa¨/ IDATååîî~ïÞ½­[·Bþ!ÆÓ§OÃÃÃh4š···——Wjjª§§ç˜1c¿œ‡‡GBBÂŽ;öìÙ#î[‘QÞ¿ïèèÈf³322úõëG´8òʘ1c"""Ö­[wäÈ¢e?§NZ±b…££ãÛ·o©T*ÑâÈ%•••Ð(*::ŒÂ Œ¤bçܹs‹/¶¶¶ÎÍÍ…ºÊ@jjª»»»ŠŠJ^^ž••ÑâÈ%§ÿþ™™™û÷ïÿù矉G´µµÙØØ”””\¾|¼&$"°eË–C‡ ><&&†hYHø!+Ccc£™™YKKËóçÏ¡. øûû_ºt‰ÏÁÁÁóçÏGåçç2¤¶¶ûhÕªUÇïŠÌrüøñÍ›7kjjzxxtïÞ=22²¬¬ !dccóþý{l·ìììY³fedd8;;»¸¸¤§§¿{÷>Љ‰>|¸àW\´hÑßÿ=oÞ<þ_Žü2}úô[·nmذ¬¹òéÓ'77·êêjlËÂ… ÏŸ?Ï»çˆ#ž?ŽiuÏž= ¥0ïyÿþýìÙ³œœ\]]³²²Þ¼y=zôú!„ZZZÖ­[wöìY33³!C†466¾|ù’Éd"„Ö¬YóÇ~ÅLž<¹[·nŸ?VSSûÉ K–,9{öì7ß|s÷î]ÁJMM½wïNGQ('''®}Š‹‹Ïœ9?/4mÞ¼yÐBIBäææ†††&$$”––<ØËËKEEåãÇàUF±X¬Ã‡cà CÛ‰‰‰ñõõÖÒ'´··ÛÛÛž?~áÂ…uêÔ©ÂÂÂÎ>íÛ·/¼‰0?~üäÉ“ääd‡3tèPÌÌLooïñãÇwAv~<{öìùóç ŸT*uøðáãÆãÚ'55õƽÐÕÕÕW­Z%øÏ½~ýú£GŽ=¦•ÈÈÈÑ£GkkkWCp>|øpéÒ¥ää䢢"777]]ݬ¬,hêŽÑÒÒröìÙÄÄÄŒŒ +++~ýú=x𠪇ˆ—æææ   ¦¦¦?¥P(~~~Pê`±X.\ˆ‹‹KII166öðð4hPXX؆ ìíí¼(“É´µµ-..¾téÒ¼yóÄpòÀŒ3nÞ¼¹`Á‚ .{ì;w"##“““UUU=<<<<<âãã¿þúküOƒJKK»qãFRRRee%x¹ ƒÁX¿~½Øn£#¢££>|˜œœÜÚÚ C\AA££ãôéÓBeee'OžlkkëðX*•:sæLWWW¯2{öl“ÂÂBèR§Øœ={vÉ’%¶¶¶999ÐÍ]pRRRnÞ¼™œœ\YY9xð`––‹µvíZØÃá9r¤¢¢þUSS[²d‰………˜ïá¿|þüùÔ©S|ôaöìÙà:tèPUUUgçñðð˜2eŠ€-++³¶¶¦Óé/_¾„Žu$2J×Ã!`±çââ"ÔQS§NíÝ»7ü žç &À¿‰‰‰¡Ó§Os2vìX777www==½¦¦¦®KÎ0dŒ? Jg³Ù+W®D™™™a»•——à+‘DGGÃÊ6<<\¨‹¦¤¤ „´µµ¥pƒÒ§¦¦_‰\|nÊ”)>>>šššµµµívúôi„Ð?ü€ºs玨ò Jmm­©©©®®îõë×±qqqp³·o߯6Nž<!´iÓ&&“ [jjj`ùºdÉ¡.Êf³Á¢$©}`LyýúµPîß¿ŸË Ã{†/Ú¼6lØ ¾[áæìÙ³ZZZÚÚÚÇŸ:u*¨eee…íS\\̵ Z¸p¡ÈWôòòBýúë¯â_† AYZZbÏ×immåÿÓ«««c;·´´,^¼!Ô«W¯éÓ§Oš4I[[v“hù7|\†¦¦&oQîøpöìYÁ¯øéÓ'xjÒÒÒÄz+²†6nÜ(ì!!!zzz:::#GŽô÷÷‡rñ!555ünoÞ¼qvv¦R©\¸páÀ) ì)¡.‘‘‘üÕÀ××Û¹¸¸b½•ÿÐÖÖ¶qãF …bnn>eÊ”©S§B•„ÐäÉ“aŸ3gÎð×±E‹ ~E‹ö¬S§NIæžd6› éEýõ—°:tHUUµ[·n~~~`—o»_¿~ØnÕÕÕ¦¦¦øßbêÔ©â¾ nNž<É_ Ÿ4S>`ii)Ôua9FV”qÄ`e9r$Bè÷ßê(???GGGø›ËÊðöí[„Ðüß¿¸¸˜J¥Â'Ô„IÊËË zôèÁUШ½½}È!ÖÖÖØps…„„paÓ¦MH¤"¨...¡àà`Ñ$—e`09Ý·²²RUUuÏž=W¯^E=z´³====½¼¼ÊËËUUUýüüD•WP ]ößÿ͵ý—_~A]»v þüŒ3¸v‹‹‹C-X°@ØëÂù•¤ÛÌb½¼¼D;(RË;‚`ilåæêêjnn···#„–/_.²äüÍÇÇ«ÖÞÞ…·fbhhãÕ·µµ]n™ÄÏÏ Yî"¤öìÙÿž:u áL“K—.EaÙ³ß}÷Bè§Ÿ~joo‡-MMMPÀì»ï¾ß}tÌÓ§OA{B\ŸÎœ9¯04môèÑðwzz:BèØ±cB]¢y%j_#–ÒÒRhŒUXX(ÔL>tèÐ?b÷íÛse̳ccc|òpll,¬*%T ÊL`& ˆÛÂzgôë×ÏÃÃþ¦Óé¶¶¶ZZZ—.]ÂÏÍÍ…€—#GŽuÝææfÈ”Ö ,§üöÛoH¤ÆícÇŽ¥R©{öìÁF•ššš¾}û¢ÿå B}ýõ×X/^6›™8År ²|ùrxßa­I ƨQ£BØx©vðïW_}¥­­AKKkΜ9B]ôرc!OOO1Ü€lóüùs„¡¡¡°_ÿýw˜ìÕÕÕÁ6›ýý÷ß#„ðë ÿ=zŒ?^EEEÒ¥I>Œ*..†=<<ôõõ±OÕÔÔ CpVV™/á zõêü;yòd¡®›››‹RUU­¬¬ÃmH†®Z`îN¥RKJJ„:pĈýû÷‡¿¹¬ ?~ä5[ìÛ·F£•••577ëëëKº¸(¬::ÄûQyy9æÞùôéB¨oß¾¼E\ÒÓÓøæÍa/}èÐ!„ÐØ±cE[ÆñôôD]°X9r„B¡0 ccãÎÜ&ÙÙÙØUfΜI¥R…D EMM …B±±±ÁxI ”””ÿzxx „Þ¾}˵›Í?~<—YMòòò”g…µÜÉ“'E;|ß¾}***åååÞÞÞÚÚÚ\•Þ¶mÛ†jnn†ñV‡£®®.!OuEEE·nÝŒ¹j_Ñéôž={vëÖw mü¡Óé1½ã€ÏŸ?Óh4*•*TaKñ¡žËÊmÁÖ ¹¼ž“²²2®„–Èœ9s,,,Z[[MLLxý™“'OÆO7ñV†üü|„ÐáÇ…º5LMM ‘/`âŽ÷í BKK‹•••¶¶6oÛË)S¦¨««³X,øwÁ‚¡›7orí:!²ä|"ö\sY†:`Àøfù¼&9øÝ…õµrþ½ßµk×vA|¹ÁÖÖ!„^„7ntèQ(((PSSÃbJKKuuu{õêÅÕæÉdº»»cþ9±“˜˜H¥R}||¸¶×××›˜˜Lš4 þ…œ ²²2ø—ËÊ`ll<}út¡®[UUõã¾u˜­Á·/8Ÿ>}ÒÑѱ²²jkkÃog2™ýû÷ç 766jkkoÙ²åáÇxº„Ø»w/B úæ²2Μ9“Ãá$%%!„0›&—•aΜ9ø£ÖÂÐI¤IW­ @3FØgÍššÇá±20™L###®h{{{Ì)½fÍ„Pjjj×dçÇŒ3BÑÑÑüw{òä‰h^h>À\™F£)Xo$°;ª««c¶yaqss6lü …‚^¾|É»ÛÏ?ÿŒ] ÃìØ±Cd±¿ÈË—/B‚¼VuuuuttÄ{uHHSøA6''!¤¦¦&²ò888€ßéòåË¡?ÿüÿ),&1[!—•¡{÷îÂ:güŸúÞ<ˆE¨bhhðY)Rutð¨`KkS¦\Vè˜î#(ÎÚ¡«6++KÒ=;êêê455¡5TëøçŸð;Œ;ÖÙÙûoe€rBB]‘ÅbAÙÚGuY|YÂ/\¸ ÔQ„¿nÝ:Þêëëãããáï²²2 …Ò§O^‹Åzþü9ׂA\\¼x?;â²2Œ5  6›­«««¯¯™Vñ¼zõª±±QØKGDD „LLLÕ,…‹200Ö#=xðàÎÖÒéééØº¢;4"þü9##C™aæÌ™¨“<ß¼¼¼>Àß»víBa–z.+ƒµµ5fHÈß¹s§H‚Ët:ÝÀÀ ³‰+À Â5iJKK333¹6þý÷ß¡ÌÌL‹eiiiii‰™>%ÁöíÛñN.+C¯^½¾ýö[‡óâÅ ¼Õ•ËʰtéR a/ ïëÁƒwõH$FWKpC‘B®âX‚põêÕk×®uø¸!.ˆÍËËÃj¶Áürï%”îs5 Ê£/mff6nÜ8‹îJ…Tå믿­?HZZZZZ¦K—.¥R©ýõ×nl6ûÒ¥K“&M‚« >ÜÙÙùܹs÷. @¾¨*%%%âU„¸‚ƒƒÅ{ZYL"+Ï«W¯rssAy¦OŸnddÄ¥9fffXÊ4®®®jjã L=¹Ø²e fã9þü°a쬬ÔÔÔ-Z”••ó]͹~ýzg5/åx xK{òÇÀÀ@KK«³ç·_¿~zzzàgKOO§Ñhnnn¼»9;;sõ‘;¡¡¡­­­pw0úq½MMM;<ÖØØØÔÔ&¸‚C¥R¡’ŸB/iii™™™ÚÚÚÓ¦Mê@H?4hïGzzzXK#X º»»óŽ*à.¥;&&&ºººi£««+¨Á‡œœ´´´xwóôô„ô¡ðõõµ°°¨¨¨€hžˆ™3gBé%a³ÙoÞ¼ÑÓÓë°¬¦««+–QÏGÇÌÌÌÀ:& 222B68³³³³¶¶†¿MMMÍÍͱz \¸¸¸;Ô ßGàèöXyáÑ£Guuu¶¶¶ÂV+ä£æææ¼ý¶ÎŸ?ïææÖ¯_?*•ºlÙ²¢¢"pˆJSSS ‹G„sŒŒŒ´´´0-âÂÅÅE„Y<ƒ‰‰‰XÅ}™£+& (æ¡££ÓÅR…\± ¼,^¼˜F£Ý¾};ì_lll$ZÆY|pûÑ£G—á€xBȩ޲e‹x¯kª#Fˆ÷´Ä2`ÀÔQø¨€¬[·ŽB¡„††b:àì쬡¡ÁåÜ CýøãØn0/—\ H0­\¹’ÿnІ³Ã º®P[[ õº07ˆâÁf³áÍ$ò¸xñb}}}¬ÆÊ?þˆ¼ŽÞØÏË 9?,Y‹ŠŠÙ955áJÒ@ù1Èx „ÐÝ»wE>ƒì––†D­›‹ÿ}¹b°O¡j7¾§”ñôôtwwÇþ0a‚ºº:¤ÊápØl6ÞmŽeàˆªÃP#ICCKV |I„ÇBZbccùïe ñÍâk®XìS(4wî\ñ^ú§Ÿ~BÍš5K¼§•)0´°éf6åææöÅ=ÁèùùógQeƒ¡¢¢¢§§'ÈÎxãŠeàˆ¤­­ Z®p…h)¯±k×.a„:ß&ÆB~V¸§¼¼\MMMÒ%ñúÀË€×ün\± Q_RP,iëÖ­"K"ºÔáªÃÓ•óð§µµõúõë,kêÔ©\]»v Êሾ}û&''ggg;99Á–’’¿///¯««óóó[²d •a*&FFŠ‹‹kmmUŒÖ>555éééT*j… “ɼrå ç߈><ÁÁÁëÖ­Ãþ…pÖƒóŠWPPpøða,èB¡lݺµwïÞB]zîܹxôèQ{{»HÂ?ÿüiÈ ^Íillüå—_ðmn¾ÿþû¡C‡òîiƒÀ!C¾ØSFXTTTTUUét:‹ÅÂ:,nݺßE~Ò¤I'ND|uŒÿ@Ôªªªß}÷݉'îÞ½ËÕÎS1`00zCU]¡€U@ss3ÖûöðáÃ`´<<<°ÎÍ3Õ­[7ìeáêêúðáÃÒÒÒ=zté:G@}dh–yóæ]¿~=,,, @„ÃI$NWLsæÌA8p ‹¦þ± iòGFF†®®ngÙ8………W¯^­¨¨àÝúúúÐÐЬ¬,Þ  =o;ο  ¯±±QKKKCCC@o¤à€uãéÓ§â=-Qܾ}!„÷ʼnpøùóçñ:••Õ½{w|*rmm­††Æ?üðî¿Lž<™J¥b%‘ñ466Þ¸q#==¿,+:::<<œ7ã´­­ bªsrrøŸÌ'Nœèžröðå© È·‡Ô>€È ^´´´:óÐrÅ2HHþºqãÆ÷Ä\=¼ˆ\2>>I¸b¹Ô>|8>ÇžÞX p(aHèt:tJrttTSSÓÐÐÁI% P††>uà¸bºxiaË•É8! aóê9ÿ&!ã‹õ‚À:hÐ ƒõzðŽœœœA‘,,,¸Â©$o,PZZÊ¥?nnnŽŽŽÏodd„ïÁ,8°’ùb¬‡üñ¢u200 ÑhXMÇÆÆF___Pmmm(C ­.>|ˆ¸aÃØM__I¬±”»»;•`±XÓ¦MƒëjjjªªªrõÚ¸bD XUxœ²¢E³B8|½Œµk×ÂïfJ¬]%›ÍîÌ2(é\± ÁË *** ÙG";tÉÊ`ff†ÄѸˆ¿•aÔ¨Q½zõâ Á‚ zJJ ×öÇÃC¥¢¢Â§bm}}=æFà]øµ´´@ ý½{÷¸>Â[8ØÏ¾þúk®ž—õõõ;vìèpe+Ð j})P°sÓ¦M¢>yòdcccÞ>´ }ñâü 2y§nP•jûöí\Û[ZZ°•ÿV¬XͨQ£x?=zô(BhôèÑ\•´šššvíÚ…)á›7oTUUŒŒòóó¹Îpùòea«Uc@é{;;;Ñ—}ÀyrüøqÑ=z´µµ5—á ú„uXN‰#°•!'''$$ä‹í$«ªª®]»öþý{ÞÎ;ÇgèÃ# ¡M(˜L¦®®.B(//O´3È­­­ Ýuk/+$ðwXiÕÉɩöG,+**êÉ“'¼ h¸x÷î]HHH‡f/¨Â8vìX.†wDLLL‡'—•zº~*Ùª£ Û]¸sçBÈÓÓ“wNµÖáiª««SWW×ÖÖæ- šœœŒxzuµµµ!!!ÙÙÙüe`2™áááÑÑÑ_Œ1îÌÊÀápÌÍÍ©Tjbb"¯ ¡ד‚á!R[ÒHèv*±¦ŠoŠannŽuƒFc–††÷ŒŒŒ7n|±lgYYÙÕ«W±¾ƒx Âo¿ýÆû‘··wgs qYjkk©Tª¢.Á:¹xñbŽ…*û¦wùûûS(ì_˜ë;vŒëeÑ«W¯Þ½{w¨6Ÿ?¾zõê«·´´Ü¾};99ù‹ÒJÙÊÀù·Ó„ Þé#º•zŸêéé}qþć¼¼¼ððp° <8,,ìÉ“'X¦}ssóýû÷)Êĉ###1'›ÍNHH€ø3fp­äW¬XYï:lE à+«u8 WUU¥R©[¶lÉÎÎf³ÙŸ>}ºtéRÿþýñV†¶¶60»¸¸\¸p!55544tñâÅÆÆÆÚÚÚ"›` •”N…vÐxÛ¼€´¶¶†‡‡«¨¨Œ5*""Ÿ™–˜˜!'“&MÊÏÏOLL0`€Axx8Þºôáǰ°0sss.ŒÈŸ^ÍL&Ë[¡P(¼«Êööv(çÓ§OŸsçÎ¥¤¤Ü¼ysÙ²efffÏŸ?Çöüõ×_Bººº/^¼ˆ‰‰Ù¶m›««+Bh÷îÝÂ~9@ss³ššÂõ+V$°•0oPA(**¢R©¼¦ÖÖVCCCWW×ÄÊpþüyP mmm> “?~„_!tëÖ-®OÛÚÚàѸ|ù2×G)))¿ýö6-ÐÐ&,„"rsYÜD¶¶¶]?+CVV–ªªª¯í¸3+fä¿àÇj‘êêêòvQÀ׫W¯rmÏËË£P(u?—•¡¹¹êJº‰†4zÕ¢ ¹l62­xm”x+çßNß~û-×cÛ™•¡²²K¦ã•ƒ…”cº:ƒ•² ÌUʤ‹V°à(XU)ŒúúzF¡P¾*Û!ñññT*ÕÌÌŒ·æÞÊÐÔÔéÇsíÖ™•Ú²"„Œ[ZZ: -- âÒ) ¯²¨¨H[[[SS“·»¬ œ ¢ñ¾(hdÎ;Œ Bcc£………Bánæ²2Ì›7OGG‡·q ,éy»%''cúÀ§ó“É´°°ûb­é[ žW´ð"I#º•áÏ?ÿDAs8‘67n„Oáu…éPJJ ~»‡‡þœ‘‘‘¨®®ŽµÞᥩ©ÉÄÄÎÀÕ5#-- V€èßÌ(x¹îºµµ|õx\]]»RƦ¢¢‚B¡P©Ô††‘O"#”——#„h4ÖúHpBCCñßêüùóa;>G!äììŒÏþ266ÆÎÀUÒ¶¤¤ûˆÁ``Cg‡ž% ¬p=>ƒÁؼy3WF¢³³ó³gϸö áªÀÜ­[·{ ŽB(88¸+'‘M áÙÌÌL„c !âéÈ‘#ñññØÌ¬¶¶6** ª¸]¸p›d—••=yò$<<ÜÚÚº[·naaaááá?~ìðäß~û-ö vè›ðÍ,:¬µöâÅ [-ZôàÁƒäää   ???(DO§Ó7´‰ða¶ZŽ•ºâ&ÚÛÛŸ?#ùÎ;ÃÃÃ_½zÅ密núúú§N‚‘äÍ›7ÇŽ344äµ20™L ì­Á§€â×_) —4++küøñT*õÖ­[øÄ®ÒÒÒ§OŸ:88¨««GFFbëØ÷ï߇‡‡‡‡‡S©Ô€á3ЋÆW_}Å_ÉåhÁ€·ÿ Ejj*”ÿøá‡222ÚÛÛ+**®_¿‹ÌÊÐÚÚ U{ ÝÔÔÔÚÚ ƒïßu‹O/ÀÚÚZìE£©©ÙaÛȆ††ˆˆˆ°°0pž_»v-<<œ79tìØ±!;;»û÷ï×ÖÖ2™ÌØØXèÞ*²•Š‚«««óYëÊ/<@õë×Oä3¬_¿!Ô½{÷ .”••±Ùì´´´   ---ÌÊRQQ¡Ñh?ÿüsNN›Í...¾xñ"h¯•æ@‡­(è tøC`¦––V`` „†åääœ:uªG\V†ÊÊJx]öíÛWCC^—|¦Ü‚°yóf„ЪU«ºrŒS¨ =ïÞ½ ú°mÛ¶ÜÜ\6›ýñãÇ .ÀÔ—Ãá0Œ¨¨(---OOÏgÏžá˧¦¦ž={!4jÔ(®Ä^Xê|b_¿~íÖYÿ슊 Ї>}úhkkƒ>ðZäétztttXX=†‡‡óFT 4µ±··ïÊIH$„èV×Ü»woW.ÿáǰµhkkk\\l|ùò%æCf³Ù©©©ÑÑÑÑÑÑ111¼>–òòòÛ·o1’™N§?xð ÃHfŒ¶¶¶„„„Ó§Ooܸ1 àêÕ«%AݸqcÇŽGŽ‰ŠŠ¡Ê.vvvH )êZAß IDAT„C€‹‹‹ÇÒéôøøxLðÓå´´´˜˜Ð?fffb*ÕýóÏ?ðQZZ×ù Æ£G¾XRÃá$$$ÄÄÄðP-..¾uëÖÎ;Ÿ>}ÚÙÎõõõû÷ïß»wïõë×»nHÚ²e ™ç pvæ°åW),’eíÚµøí˜'¿ÃRp…U‡„„€@OO×ÿŒQZZ %)Êýû÷;Ü'++ "¤0h4Ú¼yó`ÐÐÖY\BFFF"+;xyy!„ @¬h¼zõŠ÷§G½{÷ŽkÏ7n`iV˜éY]]½Ãq¬Ç3ÿ¤˜Ë—/úÑÐÐËÛ½{wL*•Š™*¸Êèbn(håÃÅêÕ«Eþf8,;øá‡®œDv€ªišššXz¼¼ÿ^444°eÿСCñ¹“ÍÍÍkÖ¬Oi4ÖÔ£G¤¤$®sÖÖÖBW …Â_™ýüüà<õÈ€{.ºuëÆµ[{{ûÞ½{A* …‚Å ;¬²M#""D>ƒÌÅV׬YÓ•“\¼xó4`cˆ¦¦æ‘#Gð»%''cM ñ^®û€Û!dnnΧÚÈÛ·o!¹ŒF£uV;#,, 넊]WEE…k‚K.(ÒWòÿyôèBHä@™åáÇ]¿¯ÄÄDggg^}˜6mçßöjXå¨À‚aii‰?gff&¦|ÊİX,èH…:_ôAº C‡åÚ r?yá3‰ú"ŠÏ+ïP8¢6§=ztddäÍ›7…m7M" “&Mzøðá¥K—D¨ƒ-S?~|Íš5ß}÷×z‰D\œ;wnñâÅ'N„—™"1kÖ¬ÐÐГ'O‚P(JKKÁÃÒÓÓsssƒé~}}}VVV[[BH]]ÝÍÍ ÞÙUUU†ÇÞÞ¾³ÊÌŸ>}JNN=z4ÿ¾ÍÍÍÄgxiooOKKKJJ*))±±±>|8ÌÔB #--N§#„TTTœœœºu륧§Ã²“B¡ØØØôêÕK°/æÿ`±Xzzz---¥¥¥æææÂ. p8mmíÖÖÖ‚‚¨«'l6;11¾d mmí[”766&%%¥¦¦–””XXXXYYùúúvÖ"þõë×t:ÝÇLJéõ?¦¥¥=š«M~~~II ümjjÚ§Oø»¼¼<77Jéèè 0|eEEEàLÆÓ¿:Øc„‡‡ûùùõïßÚ…Ê;wîÜ™:uêðáñ¦3¢ÁápÒÓÓÓÒÒÞ¼yc```ii9hÐ ¬)žÂÂÂäää´´46›miiéäääííÝaAõÖÖÖgÏž¹ººò×d‡óòåKUUUÃæ¥¥¥¬øæææØROYYèsSS“¥¥¥½½ýðáÃ1ƒˆ,\¸ðâÅ‹AAAà·W$FŒñÏ?ÿ\»v­‹êêêà;/++ëÝ»·µµµ¯¯/äâa2™)))iii¹¹¹ÆÆÆ–––^^^Ð#‰—>¼}ûvôèјµ¨Cêë룢¢¼½½±`^^@ÒÒÒ {öìiee5|øp®òõµµ\Šö¨««344„n>ŠÑ^ øßÿþ·uëÖeË–AFžÈ´µµ¥¦¦¦¦¦æææš˜˜XYYyyyAr “ÉLKKkiiAÑh4GGGccc8*++ J]P(P6ü9ëêꢣ£¿úê+lÿiooŒŒ´°°è0!TSS“™™ÉµÑÖÖ–kÚÃd2™L&~#¤¯ ôt‚‡‡GBBÂãÇ1 ,‰¬ ²}T'33S ¶’Ž€Œë;v-HWY½z5Bè—_~!Z…åÅ‹HA @º¹¹!„¢££‰Da0Ѝ¨(¢XTkiiu=|Œ¤C #ƒÂ|ÃP°YÁºfÈû÷ïG š& %ÏSSS‰Da155Eñ†Ê5Ðf2((ˆhA–  „‰„„ûÀ777—””P©Tˆê'‘ŽŽŽ!®¸hynó‘ˆP•‚‚ðÏ+ '77ý{ƒ$’¾ÛwïÞ-ˆˆÀðâèè(ZŸv’/Ò»wo –––ââb¢e êä"9fêÂECCCYY…Bé0$„D,(¤ò`/)¢QXä}£Àˆhe€þ–––üC³Hº‚ÂŒ¶p †’’ˆcccCCC‹õþý{¢e'Ÿ>}jiiÑÕÕ•Ó`~¹Æ™ììl¢Òˆ)i¨Tª½½=Rˆ—úWÕÉ¿äP˜© pG\iM$bD!•‡´2HyŸÆ(0"ZÈ÷´€¯7//Íf- B………UVV {N/..&Íÿ’Ó¢áæÕ«Wq-ä»Y ÈÚë944”Á`¾?iÄ”28õVO0ÈÙ‹¤±³³£Ñh¥¥¥DËÂMDDW=<Á!ßGR@‡Œ«W¯Š0¯ªªª©©QWW¹lÉ‘µi †ˆVèMȧx I×166¦P(­­­ DË‚B÷îÝspp â*ܨN§««Kšÿ% d3ÖÔÔ-7¯_¿vvvÞ¹sgss³°Ç’ë) k¯çýû÷;;;ß¹sGÀýÉX) ƒSaõ€¥¯šš9ã—Ø×+S DDD8::p•zÒÊ dp¨ÁX¹råСC;kHÔðnµ³³ë°à+‰X€¯·²²RçÀJŽˆJë^===± Cò¨T*Ô®—+B¨®®nãÆ...?ðšù‘HxeGUðÐéô½{÷:88\¾|™#LS¨®ßY‹±_¯aJ’ãÇS§N5joÍj^ªªª©$:ÛÁW-;¥'蹩©)´ä ‘ð>ÞÃÃcÁ‚‚$Ç’¯g) ££ÝdPyØlöÉ“'íììŽ=Ú™„a¤€l/XW‡óE=È!E:ÈòÔOLLŒ»»ûòåËq’Ê#ds¨á…N§ÿúë¯ŽŽŽ¡¡¡ü÷$—KÒA^4GÙPí0r´•>6ééé'Ož”¾0/^¼àÚÂb±Ž9réÒ¥½{÷.Y²¤ÃTr øŒ°ûöí#°o03‡Ã ¾uëÖ¶mÛ6nÜȧO ùz– EGG§±±±±±ÑÐа¼¼|×®]ÊóéÓ'ìo°LÕ×ׯ_¿þôéÓAAAãÆãÚŸa¤ï¢QôK¿DOrH‘|ÞGÛ·o$êDB$$$pmáp8§OŸ Ùµk×êÕ«UUU;;–T)_o[[[[[›ššþ#¢¦¾øZ0æ|úôiÖ¬YÇ?zô¨»»{‡G‘Ë%é /–Me£KVr´•4>6§OŸ&H¢ÿãlMMÍŠ+NžüñÇ·mÛ¦©©‰þ¾©©I¨óÔ×ׯ[·N""ÊgΜá·Ù!r§*Ìí 9vÉ’%ûöíû/X,Bˆ¬/ià†o[öa±XÁÁÁ˜-–DXän„µ0`ÀÑ£G}||:ÜG´qfÖ¬Y³f̓ˆJƒ¼(…BY¸páþýûñ¶tuu«««›ššŒŒŒ?UPPTXäEC€õmHéÙ³çÝ»wÅ&Ÿ S<ð>òôôË€åË—ÿäÉüP›îÝ»,Z´ˆJí´-9ÎH––He„oÛÈȈØ…§N*//Ço…ñòò:zôè Aƒ¸öǬ R”Qéà^äNOrH‘|ÞGëׯ¯««“ºDÿŸˆˆˆØØXüPssóÌ;—Oº"©}~ýõWéËSVVÆeeÐÔÔܶmÛ¦M›øÄ*P(”¦¦¦––²¼ä€‡±Ã€y2ÜÄÈ‘#G¸¬ 4mÍš5»víÒ××ç,3%àݬªª E1ŒŒŒ^0îÞ½‹­±ÀÁƒçÎÛáþ¤S the \O***°Þ:_Ô€R¤+ƒÔÅù?èt:—•AMMmóæÍ[·nÕÖÖæ,¹\”ü­ ÄŽ9AAA˜•Æggç£Gò¯=Aªt cd;YBí¨ÜÜ\± Còàëµ··çãì% …2wîÜÜÜÜíÛ·óO‡ÖÐÐèÝ»7‡Ã!µE¢äåå!„xûÃË~~~oÞ¼ ü¢‰!dbb‚ªªª’¼\ÊKee%BÈÐÐhA:@MMmÇŽ¹¹¹|–Ž 9©$¥¢¢Éž’`½´Ñ€Ôé£ à²ÌÔ©Sß½{·wïÞ/šпÊω„Í¡†ƒcÇŽedd|±¼%<ðDH‹U[[‹äAs” —¯ åãÇt:]¼‘`äää „‰„›ÁƒÇÆÆ^¾|¹gÏž‚ì·@Z$GuuuMMŠŠŠÅ–¤†½½ý£G?~,¸JÞð Høzíí퉄›iÓ¦eggïÙ³‡ÿÀÎΑJ"aÀˆ _µ¬! ž½{÷VWWonn.))‘‚lÊ ›ÍÎÏÏG29{Ápqq‰ŠŠºuë–à¥æ@ÿáY ‘²<ÔT*uÕªUùùù«W¯¤?%9–………mmm:::æææDËBòD´2hiiYXX°ÙlrÀ•2he033;þ|BB‚§§§àG‘kEI/0kkk¬¨L¡§§wèС¬¬¬ &u ©9R¾^'''¢ù?\]]£££oÞ¼ieeõÅI%‘𢗩—RO5Ra$Gaa!ƒÁ044466&Z–èÞ½ûŸþ™ššêëë+Ô ÿä¤W¢ÈæPP(”‘#G¦§§?~\ðvNZZZ¥¥¥O™ñ\ØÍ$R@ôP|ˆÍ&_Õ’¾[Ù‰Ÿ5kVnnîÂ… ù”GêRU$,§KøøøäæænÚ´I ˆŠŠJee%Ä‘HY{=¤¤¤Œ1BÀýI+ƒ;¦LMý…Õ PuRa$‡ :H0&Mš”——·råJA¼Ð\À½ÿÊå’Hj0®\¹Ù¯_?¡Ž¢P(äXÒÈÚ4†CÄê!GGÇÈÈÈììì® Áb±’’’òóóûõëçááajjúâÅ‹éÓ§síYZZûúõkCCC//¯!C†DGG4ˆ·a•Xˆ¯¯¯ïìSggç^½zÁß%%%ÙÙÙL&!D¥R-,,ºxuøneg´a>À-¼{÷N,bäååÅÇǧ¦¦š˜˜xxx¸»»‡‡‡7Ž+Ï¿ªªêÕ«WIIImmm999&&&òÙòyŒŒŒ æyCCCBB›Íîp7555///(Â'²¦*x(ò±’“““““ãáá!F©H0díõ,ZÀ *9jjjª««UTT:+¢NÂê YUJÒȲ•ÁÛÛ[äcMMMõõõëë닊ŠdêYP$d9–aâĉ¢èè蘖––““#lø ‰€ü?öÞ;®©óýÿ¿Â#L‘! ˆ¨  PªLG]m­Åâ¶Îºj«u¶uÖÖÖmmmŽG€ÊR™"ˆ‚ "Cö&Œ$$ùþqý<¿¼ˆu’p?ÿàANîœsä>çÜ÷ë¾ÜÏ•gƒ!\epvvF%&&JiÁ»wïfÍš¯©©imm}äÈâ­ÖÖV"³ ŸÏÿù矿ýö[‡cffÖÐÐÀáp¨T*Ç;räȪU«¤4C”ׯ_‹ ðòòJJJ‚ÿ—-[vçÎâ-›×¯_kiiI|ôªªª7oÞP©T5¸l\]]B ]Éù×íííß}÷Ý |fEE‘ï÷ôéÓsçÎ%Z^»vmÑ¢Eõõõ&&& eÿþý°}Μ9gΜ‘âT:å³Ï>ËÈÈÓ ¨¨ÈÆÆfÏž=„1ò×_-Y²¤»Gøð!BÈÍÍ­»T~¥TX,VBB›Íîð]*•êåå%Ô-322RRRž?nkk;bÄggçÛ·oO›6M¨‹¤¥¥é:›^¾|YTTÔÙlllàžÜ]TýñÜ¿ òòr)o/uuuiˆB¡ôíÛWT‘d±X?5Y*•êíí-TH¶°Ùìää䤤¤’’OOOöâÅ‹ñãÇmRSSkjjàmmmižDH鲺 tu™, „Š‹‹RRRÌÌÌ|||<==ïß¿ïããcff ªªª²²²àQE¡P™=§ªªêñãÇIII:::>>>ÞÞÞ)))ýû÷Š1ikkKLLLJJª¬¬ôöööññikk{÷ŸU67Lâè蘒’’››+ÊÀáp’““‰²8 CüP3///!!!==ÝÖÖÖÇÇÇÅÅåÖ­[“&M’wÑ®ŒŒŒÄÄÄ—/_:99ùøøØÙÙݹsgúôéBÞ¬¼º‡Ãyóæ R»Î§#½²™‘‘QQQYo555GŒÑa(**ÊËËkooGQ(”!C†XYYIyè’žž.&1jÿþý…rm466&$$$%%µµµùøøŒ9²  @[[ÛÅÅE‚£Ãý\u‡1ê _R^¼xb0ííí擄°ÐÌÌLOOïäÉ“mmm|>¿¤¤dÞ¼y`[ii)Ñ2$$!ôÉ'ŸðùüÆÆÆS§NÑh4„о}û$6@ ÉÉÉ¡mÛ¶ÅÆÆÆÆÆNŸ>!tâÄ xéêê:`À¢qUUÕÇ=ŠòööF;wNš£_ºt !äéé)õy(0ÿ¹yó¦4;™0aBhÉ’%ÕÕÕ|>¿¹¹ùŸþ¿Ç#GŽÍ~ýõWøê^¼xÁçó¹\îãÇ!Qå¤I“¤<‘ΰ±±ñóóƒ¾Ý 44^®Y³!”™™Éçó—.]ª££û==='''øäýû÷w÷ÐL&FÿÅÅÅr83’ùúë¯B+V¬x§N\»v-јÉdÂý‡B¡ØÚÚ zÕ&$$Èâ„:@ôÙ¼iÓ&ÑfúúúbÎBGGG‚[1,Ñét.—+‹S!'''„Э[·¤ÙÉÖ­[…¾Ïüü|¡6ÿüóø¾Ôá'+^¾| #0MMMbO¥R¡ˆ šÔpëÖ­R÷àÁƒ¡iÓ¦I¹%áéÓ§!333'Í~¸\î?üƒ^½zÁ?PêŸþ!š-[¶Lðç`0P€SüóÏ?ÓØØlÀ¼-[¶6KMM…\ÚÚÚD´9•J6l˜dÇ6lBèÚµk²8 åbáÂ…Ò_S·oߺH¯\¹ÒaËÖÖVb ͦ÷ð#ÆÆÆJcƒxjjj>ûì3„…BºõÄqß½{G4ëâ%ÐuâããBÖÖÖ²;¥àܹs!ivÂd2á&X¶lY‡-…<&ú÷ï/Í4­+466Н…gcc#ØþÎ;´E__Ÿ¨=I¥RgΜ)ÁÑÛÛÛAÜùò¥ŒN#3$Wø|>Ü}’’’$ÞÃ矎ºÿ¾àF‡ :ˆv|>?<<!4uêT¡aÁ?ü€Ú½{·ÄˆáÁƒ¡ëׯÃË 6 „²²²àå„ ÇvD}}ý¢¢":îïï/ÍÑ¿üòK„ÐæÍ›¥Ù‰ò°zõj„кuë$ÞÃÙ³gBË—/ÚþóÏ?#„~ÿýwxYTT¤§§çèèÈb±›eddhjjN™2EbÄcff6gÎø?!!!´k×.x 3“””>ŸbjjJ|ÊÐÐpĈð?L$èÌwïÞE988H{J È $ñ>Œºpá¨9ÎÎκºº„ÐC£ÑæÍ›-ÛÚÚ\\\¨TêŽ;ù|~]]ÜdBwîÜ‘Í)uÄË—/ccc?ùä'''##£––Á°~>sæL0¦Ä[¶l—\Æd2»{Ü¿þú !4fÌÙ ¬\¹!´~ýzivÂd2ÂÃÃi4(Å_ýµP˜o_¹r¾ö2 ¢/Q(”Å‹KcƒuuuMLL®]»Š|zzº¯¯/BÈÌÌL°å‹/bcc'Nœhdd4pà@SSSh/1› ¨äª4Ä”_‰‹.88¸¨¨ˆÏç×××?~†Ú¿ýöѬ¾¾þÑ£G—/_FïW ÀOÞ€>ëëë›Íçó[ZZ®_¿¢ÃW_}E4‹ŒŒÔÒÒ²²²ŠŒŒd³Ù</99ÙÝÝ!4pà@ Ž[[[K¥R)JUU•ÌNFi8}ú´ôÓE‡“––;`À:>zôè›yyy!„Ö®] ÊTEEÅ÷ßÏ£Û·oKcƒjjjúöíK£Ñ8P__Ïçóß¾}»téR8n^^ÑRôøûï¿E/®³{÷n„1”RJJJB4­©©IšýäææÆÅÅÍœ9SKKËÍÍN§×ÕÕ‰6«¨¨xøðá/¿üBÜsnܸ!Íq?Hqq1BhåÊ•ð(„ùËO?ý/õõõ‰Æüñ…BqvvNNNær¹l6;&&¼-$¢Ã’°¹¹¹”Â1FH¥2Ìž=IáJáÎÆóòò~øá⥓““††Fnn®P³ÂÂB:þË/¿Hf€x"##BðRHe¶°°lÏápz÷î 3–ÐÐP„PNNŽÄGÏŸ{÷îI¼¥âÚµk!777‰÷ЧOmmmA`³Ù{öì>ŸágΜÝùsçä÷}êéé !•áÂ… ¡Gñùü/¾øBP§T Èwß}×ÝCóÍ7¡¥K—J{JIcc#è÷¢?}Ù»w/B¨¼¼^úøøïò9 àDç°š)™]n ¡¡¡üñB(,,LðÝÆÆF„жmÛà%x¾œ>å›$ IDAT}^nÙ²!TSSÓ݃Κ5 !´wï^éí'‘+W® „ÜÝÝ¥ß|±éééƒ 277+aL|ÏÇ õôôBBB¤·A‡ãââB£Ñ„ÖjÊÊÊŒŒŒ †P{6›mff¶téÒß~û !töìYi kMijO ˜ZÃ<~ü8p kii±³³ÓÓÓòƒËÏÏ×ÖÖ¶³³“àÐW¯^E¹ººJl¼2ÓEMMM $]! ØçüÃEÑeØt8$˜9s&’§«È¢E‹B§NÜÈáp<==Bà"Êïþ%Ð`þøñã’Y®Ì@¦ é×*x<ž½½ýçŸ obÔœ+VjjjN˜0AÊ㊂AˆÕ¾Ÿ~úIpýxáÂ…šššðII‰­­­Ð‹?~¼G‡0ä3fHqy!y „PPPB:‡€Ê0vìXÑ·ÿÕæææììl{{{ÑŠî}ûö-//_»v­dˆæ6¦¦¦¾kaa!”Ã/22²¢¢Ü­AÉûûï¿%;tYYYNN޶¶ö¨Q£$Ûƒ²áççG¥R322jkk%øxiiiII‰³³³ht™¦¦æ·ß~KD™B¢;Õ¬Y³:Ü.h4Zg]ê÷òù|hÖY°¢žž4ëpªkV!Xω‰‰‘l­­­!:Þá»zzz2ÝÐаgÏ Ñ$/ßÿýîÝ»Á ùAÜ@æÎk``pìØ1ÁwÅŸSiJºt¸“«.þþþ %##CúZ$'Nœpqqqss[¾|yeeå7ßíb_’9gΜÉÌÌ\¼x±Pª ‹O?ýT4”æöíÛÕÕÕ!!!óæÍÓÕÕêKÝ"--­©©©wïÞ’eýPN‘C„ÐÆµ´´öìÙ#´}þüù:::„0AXXX@@€½½ýâÅ‹_¿~-Í¡»ÂæÍ›y<Þþýû…*)̘1ÃÐÐè0G-((X·nP²j{{û±cÇŠžEW€µªßR:ÃÚÚÚÑÑ‘Ãá¾{÷n---âÂòe>|øgŸ}ÆúÅ_Ho°dL›6­oß¾°È ãÎçÏŸïBnÈcÇŽÁK!_†ÿýußÝʾÉ;hS@ŠY"ÀM2 ) ¬ÂÕÕÕéêê 6ضm›®®.ñRÈ—ÁÕÕõƒ÷(ÉX±bêÄë•Çã544müä“OìííáÿÅ‹#„Àm^`¡fËDééé!cccÉÒ‘TUU!„\\\:|Wôç€Ã8q‚ÏçihhLŸ>]‚ãvƒ!è¢,HSSq½C¶)ð³‚ËåJæÝ n˜r/#H´!e4+—ËíÛ·/‘ëdذa&&&­­­DX„›:uj‡'2BB:;;â¸Ý½ºÌûõë'Ág•ðñ‘ÆŸX°`©©)›Íæóù @=~üX´ÙÅ‹‰·à‹•ÀO¶ë@ž>"óš/Þ={444ÀfHRÞanšÖÖV fLdSÑÝl‡”””äääÐh4È¢–ÈäVTD\¤_~ùemm-Ä âû˜4ÅtÄ#¦K·»—@W€¯T]½2ýýýÁŸÉhnn¾|ùò¬Y³`”»lÙ2*•Ú¡;CXX˜ƒƒƒzðàÁÿþû/Tƒ~òä $heÍš5IIIššš<ïÕ«WúQ Êx%&&2™L[[[\\V9‘Je@Á]äÏî˜Pô8yòä,Æ_]] Íদ´œ;wŽÍfÿüóÏô÷€ßµ®ªeeeQQQ2­6À)<<\‚  肵ÇrrrfΜIt•™3gž9sFOOÏÖÖ¶¶¶–( Èf³—-[&Ø©6nÜ(£R Àí¥³É§z0räH##£âââÇKðq!AP[[Û¾}û¢Ž”¬ŠŠŠK—.úÄÁJ`@W€Hpp0h”ŽŽŽÞÞÞgΜðòòêÌ#QKK ’fÌî#K¤ô…())¡R©T*µ¤¤¤»Ÿýï¿ÿÐÿ¦7ooo/+++++ƒTÞ111°½OŸ>T*µ»É+** Hìð'èÕ«—PH¡ˆ ùùغ2tèÐO¤Ãœ¸â9tèR»Ø=¢ð,,,$‚€C‡íJãÎüå—’ËåÒét}}ýîÿÓO?EÅÇÇËêиôï¿ÿÊj‡Ê Ty$rñv—†††Îr»¹ávÑ|ŠòƒŠ–×.Î"&$–ŒŒŒÃFÔŒßÿ!äíí-ñüýý;ì6B‰l÷íÛ×a3…ž EL©…ˆ‚RÂb± !Z\\œLvˆ‘9Òú2X[[òx< <á'L˜0xðਨ(BàpE,Ümܸ‘ÇãAD¡<}ú´¬¬Lh#ŸÏŸ0a‚………•••xõnïÞ½ææææææW2233ÓÓÓ/^¼üÙ¹s'꾫*¬N®têÄüùó‘Dž/kÖ¬imm…ê\€©©©………¹¹9è*ëÖ­CmÞ¼¹¥¥¶èëëC§ÒÔÔ¤Ñh¢jëáÇÍÍÍ{÷îýÕW_‰±!11±_¿~–––ÞÞÞ‚+Ì$ßä¤I“:K<©6ÀåpéÒ%6›-§CÀuBB¬ï!„‚ƒƒ+**ÊÊÊ"""B‡êÐo2b|pÿ DŸ"33óéÓ§ .’)õôô$vtÿ pŸ™¸g.—[QQ!ºJ¥:;;3™Ìf('/X¥çùóçt:bCÔ¸"@ä•àã—.]jmmýþûï»Ô¯!.Ò!C†P(”Gu¥'":îÚÚÚ›àVs÷î]¡ìæBÀ%-«T¸ÕLŸ>½3=5`ÆŒZZZIII’yÁ{öìÚÚZØÈf³aä½aâ%äFvuuLÏùòåK'''Ñ=ƒN¢R©br( ê>BEž¸\nkkk\\BhÛ¶m­­­yÓ´µµµ¶¶2 ///ÉrÞðx<¨¬!eÆ;•€ÇãÙÙÙ!Y”ïêÌ—ÿ¾ú÷Ž;„¶C5æ£G momm1bBÈÚںà jëׯ×ÒÒÒÓÓ밾׺uëh4šh>$ÈÛ—™™)ú)}ˆïSÞe´ $ ÒÕÕ• k“É400€:Ä‚ÔÔÔèèèå€$èŠ/CBB„Qx{{‹y477C¡8›ÄÄD¡wëêêÌÍÍ544ÒÓÓ…Þjii!œþø|þªU«´´´D“È‚Â+Z-O HŠìÎÊϦM›BD!ÛnI1?ÿüsQ¤¤$âZ®¨¨ ÑhëׯjSPP@¥R;̺}ûvpÜï Ù»wo …$êŽÎçLJŒk‚ääääååÁÿPUŽN§‹&Nkhhxøð¡D5ɾOÕ‚XA}ðà÷ññ0`€èvcccb1îÿ‚c‚èèhÑ›IMM Láììì3‹J£Ñ ÿùçÑwýüüBýõ—ÐvAtx(°òÁK +´µµØÝa"Cu¼`¶oß.ÁgwìØA¡PˆªíëׯG9\¡ÎÚŸþ)Ôìþýû¡­[·Šî9$$„F£ ÕÏ⯿þ244„j#âMãË””D¥R­­­E]ÈKKKŸ>}*~ÏBHéU„Q2Pššš $‰d7܈ˆðt544 tww‡Lü „[£ L&S4éF»}û¶PË#á×®]Û­oãæÍ›!333Ñq¤Z•&:˹ÝX,è­­­¢ž™%%%úúú eýúõÄ»---.+ª2†Tˆ).P[[KxЈthkk377;v¬èïe/ˆâö@{{{kkë‰'Bÿþûokk«.ßàŽK¤ªV øóäÉ“Ýý éøï¿ÿ„FÌgÆŒ E(ð ú’‡‡d†£ „£ AÆ_@´=ÿ}á!ƒqâĉ††—‘‘qðàAp°a¥¥¥ÅÄÄdâĉB?+ÇA¿[7¼Î™3§ëQ- á+N— %>›Í×ß &¼xñ‚ÇãÕ××_¿~}Μ9 åàÁƒÐ b??~,گƌ£©©)‚×ÚÚJøÒÓét1‹ ‚‰Ö:Œ7nBÈÓÓ399™Ãá´´´DFF®X±BSSóË/¿$šA¾Ò^½z]ºt©©©‰Ë妦¦þøã èJÌ)@„,©qu AV®\‰Z¸paw?)ƶlÙ"tßær¹ð[3½šš¨{½`Á WTTœ={–ÈA#´ç£G]Bè©!H~~>ÑÌÎÎN´Á‹/455©Têwß}ýóíÛ·ÿý···7F#æÄ%0qâD1—@W€'©ƒƒC×?¢¢@¥ ¢P×áp8¶¶¶#FŒ}dƒŸÏãñ–.]J£ÑD NµµµÙÙÙYZZ Bà-СøE ˜ì³³•BŸ€{çÎÇ'ØÁÁ!**ª­­Íf?xð`óæÍãÆëÊ·TWWCŠB6Å(!2Pø|>¸fXèuuuGŽY´h‘§§§¿¿hhèáÇ; €¿uëÖ¦M›'L˜°nÝ:1zíÓ§O7mÚtìØ1ñë0¥¥¥عs§¨'P\\üý÷ßïü_3 œ9s†Ø.(ÆÄÄìÞ½{ÇŽ;vì8pà@W*ÀlDtÁJmUWW·[R7Ç»råÊúõë½¼¼‚ƒƒ·lÙ’šš*Ú299yçΟ}ö™»»ûäÉ“W¯^}óæÍçT‡Ú¶m[nn®˜C³X¬ .¬]»VpåPˆ_ýU¨«üøã¢þwîÜÙñ¿ìܹStS<íoçÎÝú”êÏBMMÍ¢¢" >ë–BŒ;V¨Yff&¸MéèèŒ1bôèÑD‚«[·n 5ÎË˃’¡ýû÷wvhçèèÍ„BÜ£¢¢ˆLH Ò òùüÒÒRÁ,âîîî°=''G4 ³¶¶v‡þb˜9s&Èf¢6üöÛo¡îæ:™:u*ñeÒéô¤¤$Øþý÷ߥI¨T*±î×ahÕĉ;Üù/¿üB´ãJ ˜ÞøçŸî°ÍéÓ§AǤP(D÷èׯŒû#""1‹B¡,]º>UTT$¨~zyyuå;inn†ν{÷ºÒ^E|(BQÍ]¤¼¼œÈTg``«T*uåÊ• ):ñêééÏ—uëÖ÷ &äOJBÈÃÃCÌÑ·nÝJì¡Ã¶MMM°h½š¸oL:UH;zô(HT*•è*ÿ@âÆ! ‹® * 8¸éëëw«øôþýûzB¹Žˆˆ¼±ˆrssÁÅ !dhhŸÕÒÒÚ»w¯èÎapt褰X,³3qüÉ“'DÆ~cccø‡Á`œ;wN°Ù/.u%vïÞÝõ¨(, êˆEFFvýSIII‚‰6‰zÛõõõp—ìííëL™››/Pâ 0´µµ;™5k–3ˆ¥ÓÞ½{w˜«(>>^4³£žžžÐlŽÍfoÙ²ž­šššÄb¡O·®&H?áããÓõ`…/‹¬é¥¥¥ööö,ëÉ“'àBŒ‘€åË—;vlòäÉ·nÝ"Û92vìØ¨¨¨Í›7w–¢óA¢¢¢ÆŽk``PXXH Ôž‰'FDD¬ZµêÈ‘#ÝýlJJŠh( ‡‡‡àÓàp8çÎKMM}öì„¥ 4húôéÝmBB•+WÜÜÜ‚ƒƒ;Kè…zûöí©S§´µµCBBÇÕÕÕà€ÒÐÐøè£B<ï÷߇'.…Bqvv†hŽ–––£G åw Óé+W®$Õ$77Ö ^¼xÅíÕ†ÆÆÆ~ýúÕ××GEEAÔ®Ñy!ƒ%K– „ž?~ûömˆVÕÒÒš5kx®%&&Þ½{Wh'^^^Öñb³Ù×®]KJJúä“OÄi{ôèÑÕ«W=<<¾øâ‹Î‚“ ¯^½š’’R\\loo0wî\ØUVV†……}i̘1ð,ær¹¿ÿþ;D™Q(AU¥3~ùå—õë×;99eeeó"õãÔ©SóçÏïÓ§O~~¾d óoܸñèÑ£´´4]]ÝÁƒ/^¼˜¸¦nݺETÊ422úòË/á)))÷îÝãp8!yóæ ÞJJJNŸ>ÍårçÍ›A‚ÒÒÒrùòåÌÌÌàà`1ƒ®˜˜˜èèhâçÍ›çåå%Ú,77÷Æ)))åååãÆ›1cFgÕ;ÄÓÓ355uß¾}›7oîú§TŸ'Ožlß¾}×®]]üÈ‹/nܸµµµƒƒƒa}¸ªªêäÉ“L&!D¥RÇŒ©²Bííí.\HJJÊÈÈ011:tè²eË:«e}ëÖ­‘#G~þùçb2ù¿zõêôéÓfffsçΜ¦ ÒÔÔtþüù”””ììl+++eË–u˜ÄGÌ%О hoo'2eôéÓÒ#„îÝ»—””˜ –/_.8`ÈÉÉ9}útïÞ½çÌ™#&ÉWmmíÙ³gËÊÊæÎëääÔaƒcÇŽ %Ïb0kÖ¬u OMM OIIa2™ ˜6máVÜZZZììì*++/^¼.Ò%EVrŲeËPçë9˜RRRC'Ožm‹|ß]ƒnÉ–A ÕðæÍ›É6D¡@23ÒÒR²mQa DŸXQ3¾ûî;„ŸŸÙ†¨0mmm0ï• ,…jÁáp@9úûï¿É¶E…ìHFFFÄž¨.YÜØØX]—( ]µjÙ†(ˆšš¨óK¶-* 8 8PL˜3F™ÊðæÍp×LKK“Õ>{kÖ¬A‘mˆ"€[ÉRà` æN—U5 äÑlj˜.BܨÕ5,«ººViº›»CðçŸ"„ú÷ï/AÊ•£G¬œ€…÷ï¾ûŽlC››B¨ÃøLWHOOGRBª(7nDu–TóA\|ºJŒ2 3•ÏçCuŸneïÀùùùà"+&æ_ßuƒÑaö Œx ÜwÍš5dB'Y⼘%K– „&MšD¶!rdÆ ¨£¤˜®ÐÓ–÷{Žã†œˆŽŽ†{rUUÙ¶(šË—/£ÿ €Çt ˆü`Í5£´´Òp¨}M 9‰Nmmm{H•F–*CAA®®.BèÊ•+2ÜmO‚Ã{T¼ ¸3t˜M#H5o``ÐaƯž¤½üꫯÈ6DõÈÍÍ…°,¢H°ZRZZ ¢-vI•XÛ·±±é0¿—Z¹ý{Î)Ë 7räÈ{Cær¹ãfß¾}dÛ¢z¤¥¥Q©T X#ê,mˆêÁd2!/‰`~ŒÒ"K•Ïçÿøã0@a2™²Ý³% uttDkV«1à¹M¶-*C]]d‡>|ø0Ù¶FLL BˆF£‰/ ޲+}òÉ'd"w  „“““š•ê”7UUUýرcdÛ¢8ZZZlmmB?þø#Ù¶¨PR×ÐаǺ%^¸p!¤§§×£|þ¥‡ÇãÁ‚Ahh(Ù¶@qq1Dö?žl[T È/;`À1¤1ʃŒU‹™Ø¿ùæÙîY]imm÷Ô]»v‘m‹¢Y·nBhРAx&ÐEV¬Xrssëá!ijgÏFùúú’mˆ*•ºuuuß¾}K¶-r§¡¡ÁÒÒ‰­0Šjzyyõ´”Z õÓéô‚‚²mQÕû·ß~#Û2 DM:•lCT‰cÇŽAÆÐ˜^ 8pàBÈÊÊ gí:ÙÙÙP%Û˜2eJñô‘+W®D¹»»÷pÕ;;;"ÑÂÃÃɶE5 |¦Ž=J¶-¤Áf³B6l Û• T“m¦«È^eàóù3gÎD¹ºº¶¶¶ÊcÿjCrr2<œ"##ɶ…ÀÛPGGçÙ³gdÛ¢Ô477CâeË–‘m‹Rðë¯ûš IDAT¿"„,,,zTí4‰ùöÛo¡ìSŠ<‡5ÆÏ?ÿœlCT€ööv—›V–ÏçÐét„ÐÍ›7ɶExúô©††…BQûÚÛ]n°ýû÷ǃޮ°páB„ÐðáÃ{šÏ”qqqþ™••E¶-*ÀÅ‹Búúú%%%dÛ‚é*rQ***,,,B+V¬ÇþÕƒºº:ˆ•X°`Ù¶ÉçŸ󟦦&²mQ^BCC!ãIMM Ù¶(íííPElÆŒdÛ¢ì$''ƒ“aTTÙ¶(»òÂ… dÛ¢ììØ±Üw{²l‰¥¬­­{`¹„nA¨ÞK–,!Û¥ ¹¹¹_¿~¡µk×’m‹²A¡P¨Tjrr2Ù¶OHH^”í ååå½{÷F:tˆl[0Ý@.*ŸÏŽŽ¦R©¸Þ„¦N ùÉš››É¶…LêëëAm !Û%åäÉ“ xãºG‚¤¦¦‚+PÊT×]êêê ³ÝÂ… ɶ…vïÞ Es_¿~M¶-Ê ~^,ËÝÝê=ñx<²ÍQ^ GŸ>}°êMp÷î] …‚º~ý:Ù¶(/ïÞ½ëÕ«BhýúõdÛ¢‹²_~ù%Ù¶(/\.b%¼½½qõJÕB^*ŸÏß¶m$wÁé”Do:Ž¥ø|~JJ LOœ8A¶-JÇË—/!1Îc'Ê/¿ü×®7Ñ=\Íär¹cÆŒAyxxô¨h‘®S^^އ¹¹¹¹ø~+†3g΀êO¶-ÊÄM÷„ »Àårýýýa®ˆs~`‘÷ƒìÚµ O'U9ª ííí~~~!OOÏž9ÀíŒÇäúøñãdÛ¢,€ì¢§§‡4R__ù&Mš„×Ö:ä“O>A <ßdDÁj&ŸÏ///‡zØ™YbÈÝݽf îsçÎaß±ÎÈÍÍÕ××GíÙ³‡l[”ŽöööÑ£GãYtg@XVaD4ð†††x-JLL ¨0W¯^%ÛL·‘£ÊÀçóß½{…Ž&Mš„½\€¬¬,ccc„М9sȶE¹˜6mäóËÏÏ'Û¥ ­­ tº¾}ûVWW“mŽ’R[[ ÕæÍ›G¶-ÊÅ“'O°š ÄÄÄhhhàÅ"QÀåÁ`äåå‘m‹±xñbȃS^^N¶-J“É„l8ãÆÃªw‡”””@D@Í¢Ú÷î݃¹âÿýG¶-J±(ëåå…4òîÝ;pµ[µjÙ¶`$A¾*ŸÏOMMå{Þ¼yø±TXXاO„¿¿?^8¢¥¥ÅÇÇêzöØÊ\.÷‹/¾@™˜˜¼|ù’ls”š„„†Úºu+Ù¶( ÙÙÙ¦¦¦XÍ$€ :::>$Ûe᯿þB!„.^¼H¶-ÊEKKË!CÀÅ£'§Ã„ÍfüñÇ!KKKü€Cdd$L§qš:‚´´4DÂé:ƒÈXñé§ŸöðÒ°uuup6lž1©(rWø|~TT,©mÚ´I‡SZª«« „.b¨­­…aÆ566’m™@)r]]]\'¬+œ:u 2oýöÛodÛB>%%%àß1jÔ(¼0ðx<Èæmdd”™™I¶9äsýúuðïøþûïɶEyûö­µµ5B( py<ÞܹsBOŸ>%ÛeçÈ‘#! …röìY²m!Ÿ¼¼ð=*¼Hzƒ‚‚Bt:]íãk<±¾ ,ènÿ2áÉ“'PÖÝݽ¨¨ˆlsäHmm-ŸÿæÍ›áǃ¾»sçNuºíCý …²iÓ&õžá(‹E<¡Ç§N•º9ÎæÍ›aô?jÔ(\­G¶üõ×_P«ÏÇǧ°°lsdÇÛ¿?ør=º§¥J•‹ ÷–uëÖ©åzQmmí§Ÿ~ ç¸yóf²ÍQm²³³¡F¬‰‰ÉÍ›7É6G.$$$À9«· ¡‚Ù³g\†cÇŽU§a ‡ÃùöÛoa<3a„¾ºvçÎÑ£Goß¾=66Vß±˜˜ƒ²··W×TˆW®\122‚sÌËË#ÛŒ,!Meàóù,kÍš5pÛõ÷÷Wô0·nÝ‚åSSÓÛ·o“mŽúpõêU?±°°ˆŠŠ"ÛPXXå(ÊæÍ›±%îܹëü&&&j¶(WYYùñÇÃý344ûÀK—Ë%FÆžžžjV(11 Óétì÷.JJJà¾úꫯX,ÙÉ ·oß>P-œœ^¾|I¶EêÆ… `ßÒÒRÍj‚«k ØâñLSS“––|!ZZZþþþ»vízðàwŒÌÌLGGG„¦¦æÏ?ÿ,kÉ¢­­ˆoõ÷÷///'Û"ŒŒ!SeˆÙ£±±ñü¡ºN åååsçÎ…«ÅÇÇG½=*I!?? ‚R(” ¨nª ‡sèÐ!}}}˜ýb5J®³‚µkתǬ 66ÖÊÊ !¤§§wêÔ)²ÍQy"##!ˆÏÐÐP=’Nñx¼Ÿ~ú 1899eee‘m‘úÀáp¾ùæP¦†®ÊTee%ä)„°š¾-?rss¡¸£:¹ñÞ¾}V׌ÕLÍ—†ÀÀ@$‚ŽŽNPPÐ?üðèÑ£®{Ï555Í™3ö0yòäêêj¹Z®^½zE\ Û·oÇ¡|j ù*ŸÏóæ 1 ðôôT¹ÚÂ\.÷È‘# •Ðh´o¿ýë¸r¢­­mÍš5ðÂÄÄäÏ?ÿT¹‡t||üСC¡·ûùù©¥'¿²!èÉéââ¢ÒnÀ kÖ¬HœëQV”––B,:B(88X¥Ã—²²²|}}ñŒQ®DFFBŠ;ƒqøðaÕ"óx¼'N€Ê¦¯¯UKyÓÖÖöå—_#^•ŽB¯¬¬œ?>œËˆ#ðxFˆª ‚èêêŽ7nïÞ½Ož<éʬáøñãƒÖÊÊêÂ… 89Ááp<+mÑÑÑd[„‘J¡2ðù|÷Ï?ÿ@<*•úå—_ÖÖÖ’mT—HLL„v„ÐèÑ£{T]4²HIIñôô„ïÜËËKUd©ŠŠŠÐÐP˜ëöîÝæÌÝ»w--- _U,psöìY¨Œ‹Z¾|9Ž’-\.wçΰþ¯¯¯èÐ!•Ó‹›šš6nÜNï§OŸîÖÇ333TNº%‹ÒÒÒ€€¸]]]?~L¶EÝ&++kôèÑp îîîXµT/^466†ïŠ+T.«—Ëýý÷߉SØ´i“Z浑†»wïŠWqss늜••E,S3F«¼?xðÀÙÙNAÍR­aDQ•¨©©Yºt)Là Ɩ-[”y&ðäɨìŠ277 #Û¢—Ëýã?à ‡š$Û¢®rùòå>}ú€åÓ§O— àHhh(BÈÔÔtöìÙgΜQݨ4…ÁãñÂÂÂÀ©B¡,\¸PU¾4&“¹iÓ&¤ Ư¿þªºî*Jee%±ð`nn®B )))¾VzÒÒÒȶHY¨®®¾téÒ²e˺.1ØÙÙu½ä'‡Ãùé§ŸÀ@KKkëÖ­---r=)YQQQ1oÞ<8eKK˳gÏ’mFî(—Ê$&&Ydtuu¿úê+es^ŽŽ&®tttV¯^'¤PYY¹dÉX{Y4>>žl£þ‡‚‚‚åË—C-"„¿¿¿J»Gªééé#GŽ„_ÄÙÙùìÙ³Ê<¼ÎÉÉ %V§Uq]9uêTïÞ½¡“L˜0!!!l‹Äqç΢K;::Þ»wO‚ðx<â”*•:bĈݻw§¦¦ªeaYQWW·råJå344ܺu«2k MMM ¼¢fÍš¥¹·UÁ ÊaÆ]½zU™¯µôôô/¾ø‚ˆZ=v옪(õòƒÉd†‡‡oذÁÍÍ 4£naccóöíÛî´¤¤„(deeõóÏ?+sd\EEÅæÍ›!õ©††ÆW_}ÕÐÐ@¶QE Œ*7f̸„´´´æÏŸCîÍ·¾¾þï¿ÿööö«ôôô6lØ€ϤSTT´jÕ*ø]FÖÔÔD¢Iííí‘‘‘³fÍ‚É!BhâĉªèO«®ðx¼ãÇãl‡ãÇ+›ÃgFFÆôéÓa=xðàÇ °Rbnnž-½UW¯^%ÒÃnÚ´éÅ‹29eiˆ_°`!Ó?^Ù|1 @ÙU ==}ÕªU6lضmÛbccÛÚÚätÐòòòsçÎ-^¼r/ÇýùçŸñbŽÒRSSsðàAâ'ëÝ»÷Ò¥K/\¸ ¿3---÷ïßÿöÛo ¿G„……źuë”á^›Í>qâÔ£FQ©Ô1cÆœÊæîˆ—Ë=þ|PPD( „ôôôfÏž}òäI¹z7°X¬¸¸¸mÛ¶ëÒ¡>}úlÞ¼¹ëé 0Š¡®®nïÞ½‚¿”µµõºuëÂÃÃåªIUWW_¾|yÉ’%D¾[„··÷Ÿþ)«:#UUUDÏ— …âââ²fÍšk×®aÅ --mÑ¢EÄ< !4jÔ¨Ÿ~ú)==]®~/^¼8räÈøñã!Ó-ñ`R¡T¦=6›ýï¿ÿŽ=šˆóg0¡¡¡çÏŸ—ë¼±¹¹ùÞ½{_ýµ­­-Ñiû÷ï¿sçNeÎÅ.[X,Ö£GöîÝ;qâD###‰ïŠbî–†††OŸ>•‡ñ±±±3fÌ fI R=zTz§ 1p¹Ü´´´éBFFFK—.Åñ= ŸÏ—ù%$ooß¾óæÍÁ·zõêåø;;;CCCƒa``µµµ™LfSSScc#ü­®®ÎËËËÍÍÍÍÍ}ýúukk+±+MMM//¯€€€qãÆ5J‚œ.Òáñxqqq÷ïßMMMår¹Ä[ºººŽŽŽ8p ƒƒƒ±±1ÑO †žž‹Å"ú ü}ûöí«÷TWW ÈÁÁ!00000pâĉ„W*Fy÷îݹsçNŸ>ýüùsb£££cPPPPP¯¯¯ s“d°ÙìgÏžÅÄÄDGG?~ü˜¸í0ŒiÓ¦…„„øùùI3åÃÈ›ÔÔÔÓ§OŸ?¾ªª ¶Àó"(((00ÐËË‹C•˜†††GÅÄÄÄÄÄÀ@ ¶ÛÙÙÍ;wîܹ„÷L(--ݳgODD„Ð#U@Ïõ÷÷÷÷÷÷óó#¢Í{,mmm·nÝ:}útdd$‡Ã¦¦¦þþþðÔptt”þz/((ˆŽŽŽ‰‰)//‡T*Õßß?$$dÚ´iøÁ¤Šœ9sæÌ™3¹¹¹ÄÆ!C†@Ï=z´ô×W[[[jj*ôœÄÄD6› ÛMLL¦OŸ"¸B®®466>yò$>>>>>>99¹­­M&»566vww‰‰!¶P(==½èèh///™¢C¯\¹rêÔ)a£••<¡ˆ@Q‰áñx999ð„Š‹‹«««ƒíZZZ'N ™4i’à ¦g¢’*ƒ EEE 7$&&¾y󦽽]š½1 '''??¿€€€Q£FÉ$ò £$466ÆÇÇÇÆÆÆÇÇggg755I³7--­þýû{{{Ã-›( ‡Q233¯]»+8ðB™˜˜ 8P3ûõëÇx®®.!G²ÙlB¢ª¬¬ÌàíÛ·‚‚—]@@Àøñã§L™"ýì£0ÚÛÛïÞ½“Ml§P(666èÕ«(˜‚¾x---D')++{%1QDihh 6,00pÒ¤Iò–¼_½zþðáCÁn/ 8øûûûúúöpÅ¡ººúêÕ«QQQqqq‚:µŽŽNÿþý‰»Šƒƒƒ‰‰ ¡zþ<Éd6¾§  €è-¹¹¹ÍÍÍÄ †¯¯o```pp0~6©IIIÿý÷_LLLZZšà@×ÜÜ\ðVceeE,–ÙdB,‹¸ÕTWWçææ§°°Çã- 0a„‰'AõjIEEEü{233ÊÒ ££3jÔ¨1cÆ 6ŒB¡ôîÝ<¼( N¿{÷.QGOÞ]¾|9&&&>>^pЫ¯¯?`ÀXistt´··722‚n£¯¯Oˆž\.—Xf«­­}ýú5ÜmrssóóóY,±Csssÿ1cÆL›6­‡ßç1‚¨¼Ê H{{û›7oˆ[gYYqWX,–¾¾¾†††öööp™ 8È9Q{ˆ1}NNÎÛ·oûISS“ÉÔÑÑ1ø_¬¬¬ Ïr;;;bð‡QoZ[[?~ûôéS1S/*•j`` ©© w1û´±±ñ÷÷ ”~UC:ååå±±±±±±qqq3¼³–ššš<¯©©I̸–F£ 2zˆ¯¯/‘Ba0™ÌèèèðððˆˆˆââbéwQàãÐÃ>ŸÿüùsX yôèQmm­˜Æºººzzz­­­s´³f#GŽÕÛÃÃ?žÔ•¦¦¦øøxx=þœðŽECCC__ŸF£555‰ylQ([[[x©ý’I~~>¡,äååÉj· ,|ôÑGBkø!!!gΜAéè脇‡©4I{{{jj*±(Ëd2;k Þt:½¹¹¹¥¥EÌ>MMM}}}¡Û8;;coŒ(j¥2`0Œ\ár¹‚3¹¹¹ååå„2%4iÔÕÕ%ÔLX«?iÄ(ŒÖÖÖ¼¼¼Ü»wï7ß|£H¸\®®®.›Ívqq¹uë c0˜ž ›ÍNNNŽ‹‹‹‹‹“­â€²´´$OOO,éb0—MÈ YYY²ÊÝÐh4wwwF…C0ÉÀ*FõÈÈÈøøã…üu?¾hÑ"…Ùíääÿ›››ß¼yÓÛÛ[aGÇ`0%„Íf'%%âðäÉÙ*T*ÕÙÙ‡#F899õ'p ¦‡SVVšBrrrJJŠlã Bt:ÝÛÛ”…‘#GbAƒ‘¬2`TŒ§OŸ644m×ÐиråÊgŸ}¦3.^¼8sæL⥶¶vXX˜à ƒéɰX,AÅAV%è ôõõ=== Ñ—ˆÂ`Ô‰––Á8™TºÂÈÈè£>eaøðáê]¹ƒQ{ö ”…¬¬,y¸5!„LLL¼¼¼ >®———‰‰‰<Ž‚Á`ăUŒ Àf³'L˜Óá»ÎÎÎwïÞµ¶¶V˜=MMM†††b®>}úܾ}ÛÕÕUa&a0ŒªÓÐÐ…îAw¨®®–Ó¨Tª½½½ îпì;ÁÈ–ÂÂBàoAAœ&šššnnnD=šÈã( ¦[`•£ÌŸ?ÿÔ©S¾åââcjjªH{žàöرcË—/ÿ`3*•ºÿþ7*À$ ƒQcX,Ö³gÏÑ¡³=2ÄÒÒR0³ÃàÁƒñ4ƒ¤ººZÐU!''‡ÃáÈïp†††DYooosssù ƒÁHV0JMVV–··w‡éÁz÷îýèÑ#Rù¬ZµêèÑ£b@&H„РAƒN:åéé©(Ó0 Fý©ªª¹!111%%E´¶±Ì¡ÑhŽŽŽ‚Îýúõ“÷A1åÇã½~ýZPVx÷î\H£Ñ† é¼½½ D¡PäzD #C°Ê€Q^š››===³³³Eßb0þþ–——+ìèÚÚÚvvv‚ºƒ½½½½½=.oŒQfÚÚÚ^¿~û¿TUUÉû¸T*ÕÁÁÁÍÍÍÕÕÕÕÕÕÝÝÝÊÊJÞÅ`0Š« %EL:†üqË–- ¶‡ ¤¤ÄÆÆFL:^SSC§ÓfƒÁ`:£ªªJPtxñâEkk«"  P(VVV‚ºüƒLb—Ë-,,Š‹‹y<žŽ®««;tèP777P\\\ôôôp\ £x°Ê€QF^½z5lذÓ1Œ7.22’D—Ôˆˆˆ‰'Âÿ¯_¿msóæM\]ƒÁ`”———Gˆ™™™ò+°'ƒ!*=ôíÛWCCCñÆ`Ô’òòr!A!??_®åZ„°´´$477·à’±L« ed„ ‘‘‘¢Û---322zõê¥x“öîÝû믿Μ93$$ÄÃÃÃÍÍ-##C¨ÍW_}õË/¿bƒÁ`º“ÉÌÊÊôw¨««#ËÖ¯_?¡˜‹þýûëëë“eF%hllÌËËÒiƒ††Æ Aƒ@PeW‚À`z,XeÀ(÷îÝ?~¼èv èèh???Å›$HQQ‘µµ5±Ö´mÛ¶~øA¨»»ûÓ§OnƒÁ`d@II !:dff¾zõJ®%úº‚¹¹9¡;ôéÓÇÚÚÚÊÊÊÊʪW¯^8ßdOƒÍfççç ŠÌ?BÀ`0\\\W…!C†à$ À*F¹àr¹nnnYYY¢oíÞ½{Û¶mŠ7I<111AAAB©TjMM‘‘)&a0 F†°Ù윜Btxþü¹¼køuMMMKKK+++Bwü‡Á`m Fr8λwïŠŠŠŠ‹‹áoAAAnnnaa!—Ë%Ť¾}û® nnnvvvXäÂ`0‚UŒrñ÷ß/]ºTt{@@@TT”†óµ¶¶‰F9âÔ  £®ÔÖÖ¾zõêÍ›7ù²˜,===QÂÒÒÒÌÌÌÌÌÌÄÄç€ >Ÿ_YY)(%ÀßâââòòrÅ$eì ]]]GGG௱±1‰ö`0« %‚Éd:88TTTm§ÑhNNN¤XõA|}}ããã…6®_¿þСC¤ØƒÁ`0ÅÓÒÒ"¤;äçç’mÑ ÅØØØ¬#LMM‰ÿñzµ4p8œªªªÊÊÊŠŠŠÊÊÊÊÊÊÚÚZÐŠŠŠJJJ™Ž±3455íìì0`€µµ5þé1ŒdÐÈ6ƒùÿÙ·oŸ¨Ä€Zºt©ÒJ !???Q•áÁƒ¤ƒÁ`0RÐÕÕ2dÈ!C7r¹ÜââbAÝ”§åë>Ÿ_[[[[[›››+¦™†††‰‰‰¨aÐ CWWWa§  Ô××W¾‡Ð_’˜L´C(JŸ>}ÕGGG;;; O 0ŒÌÀ¾ e¡¸¸xàÀ¢eÌ _¿~­ÌuÅ£££ÇŒ#´QCC£¦¦ÆÐГ0 £ÌTWW éùùùeeej0*£R© ¡­­­õ¿[&Éf³›šš»òè Êà‰ 333A5þ¡ÓédÛ…Á`Ô¬2`”… „……‰n?xðàÆnN7è,5ÃíÛ·'MšDŠI ƒQ9Z[[AqŒ¼xûö­’Ïc准†F‡êƒ(ÚÚÚššš|>Ÿ+–öövÑ, „‹EöK…žž!%àL  †°Ê€Q ˜LfïÞ½[ZZ„¶ÛÛÛgggkii‘bU×5jÔãÇ…6nÚ´éÀ¤ØƒÁ`0õ€ÇãºCIIIiiiiié»wïšššÈ¶CšššöööB‚‚••Ùva0ÌÿÁÂ(7nÜ•BP~‰!äïï/ª2ÄÅÅ‘a ƒÁ`Ô*•Ú¯_¿~ýú½Åd2 Å¡T€wïÞý?öî;.ŠãÿìÇÒ›¥ :J{bAEìшѨQcù&jb41Ũ16ì[h¶`E,ˆ‘¢t)*½½ÝÝþþ˜Oæ·ïÝåD%‡Æ×ó<ŽÙ™ÝÙ½…¸¯yMqqqsss—tt"¡PhjjjaaÑó¶¶¶}úô±²²‚õA¯3Ë^ cÇŽ½|ù2«ÐÃÃ#..®Kúó¢®]»6jÔ(V¡P(¬®®ÖÒÒê’.x›UUUqc………åååõõõ]ÝAð(Š222ÂAf@¡gÏžfffM¼‰ ʺ^ii©¹¹¹L&c•ïܹséÒ¥]Ò¥ÕØØ¨««Ë]®ìï¿ÿ7n\—t hOKKKeeeEEEEEùÀý ÁˆNAQ”¾¾¾1s„B=ÄbqW÷:̘]ïôéÓ܃P(ô÷÷ï’þ¼ »wï²ÊoÞ¼ Q¯±XlfföÜ™ü---¼Ñ‡êêjœ1±îµµµ r¹\9ý­hhhàØA÷îÝùÂ:‘€· üÉ]ïÏ?ÿä¾ûî»ÆÆÆÊïÌK>|87Ê©¼¹Äb±¹¹¹¹¹yG*Ó4ÝÐÐÀ>p?“õõõ­­­­­­---øC׎±¥(JSSSKKK[[»#ÿ544466îÖ­[ö^C0ct±ìììÞ½{sË:4oÞ<¥wçå]½zuôèѬB•êêjMMÍ.éðf‘J¥­@¢D[[EQ***B¡ÿ—|Pü_‘H¤¥¥…£šššEuõ5€7Œe]Œw ƒX,ž„Ÿ>}Zùy4MóNô˜WSSSpppZZZfff[[›·····wÿþýçÌ™åàà@*ggg?~üXñ…Baÿþý XåmmmÉÉÉqqqqqqÅÅÅýúõstt;v,ë;BI¥Ò¸¸8²ª±®®®‡‡‰8×ÖÖÆÅÅI¥R„@ èß¿¿¡¡!ÞôìÙ³G)þ÷EQŽŽŽæææøG‰D’ •J)ŠêÓ§••©ÙÚÚzïÞ½ÆÆFücÏž=™—‚hll|ðà>¯ÖÖÖ#FŒ1ÂÞÞþرcáááß~û­““®YQQ‘˜˜ÈRgvÏÖÖ–Ü{Þv4¯“ðÞ¨vvv ]Ý»ÿßÂ… ÛûºvíZW÷ðZóòòRü¿æœœRùûï¿g†LMM›››ñ¦óçÏ«««³ÚÆÄÄÐ4ÝÐÐÀ} f233Û²eK]]9Ppp°H$bU;þ<ÞÊý£÷î»ïÒ4]RRÂíƒOž>^KK‹Õð¯¿þbž”T*ýì³ÏxGâ›mÇŽ¸ò/¿ü"thÜ«¦¦¦\.õ/À̘¯WW×Q£Fq˳³³×®]«üþð:tèﺡ%K–¼ûî»Jîà òðáÃØØXD"ó‰ôøñã4ã-wqqñåË—ñç'Np—ÑÅ\¹Â;V‚(**Z³fÍ´iÓÈÎOž<ÉÍe‹ß½·´´9r„÷@wîÜá]Ê——ššs ÆËÙ¹sg```aa¡‚:dFEEÅÅ‹;¸gkkkòY*•~þùç“&Mª®®æÖ¬¯¯_¹r%s!¡³gÏJ$V5|õB$ãMüLΛÜGq÷Nœ8AöŒjhhøë¯¿ðç3gÎÔÕÕ±Êd2ò¹²²r̘1¿þú+sDEE¾Èð‡ãÇ+ÅÀìwt €·“pÆ ]ÝþG=¸ÿœEÅÅÅ >œ9.´Kܹsgúôé¼ÿ>óöö>uêdd( ¯¯ÿèÑ£ÆÆF]]]š¦[ZZp¹………‘‘‘——×òåËGŽIêËd²””æ££ŠŠÊäÉ“Bêêê?.++ÃÏ666+V¬À©gõôô ñ&¡Phaa¡««ÛÖÖÆ %äääØÚÚ:;;#„ABByT611Y¶lÙG}$ UTTjjj222š››ñÞ|}}7lØ`nn~øðá»wï"„LMM tuu›ššðc­ªªj=tuuñ{{„‡‡‡‚`‘šš:eÊòÜ»víÚ={ö|õÕW½{÷ŽˆˆÀOÈ"‘è·ß~Ê544 rssÉuîÑ£‡žžž.ƒ\.Ç!€åË—“iãÆ;~ü89nÏž=gÍšåééYZZZSSƒ ¥¥¥OŸ>ÅŸñÃkkk¯^½|||¶oߎ;¯««K†BüòË/Ož<ÁŸíììV¯^ÍêƒIX]]]^^Î:MÄ‰Ñ Æ•a}×r¹œ4$±‰<qðððÐÔÔ\µj36A¾\î-ñèÑ#<)¦[·närµ´´0C'{÷îÅQ!&2V…5œôÜÖÖŽ ðññÁÑ777MMÍ™3g2¿o»®L@»Lßuvv...VN7ýýýüMž>>!WW×—¿Xÿ oÎ SSÓ(˜orîÜ9Ry̘1ëׯŸ?>þqË–-Üú}úô!õY32+!”œœŒ §M›F ËÊʘõ‹‹‹É¦mÛ¶17=zôˆlòôô\¿~=ùâ-ZÄ{t¹\N"©©©8…P(Ä=tèÞ4tèPÒdÏž=ä(ãÇoïZ%$$¤¥¥1KêëëÉvvvëׯ_·n^‹däÈ‘ííÀ[¢ àõU[[« ףͽ{÷þÕÈd²C‡áÌ^íqwwgͰ€Žøá‡È_’üüüöª]¿~×0`MÓd”ûÅ‹išž2e ï³+ÍȘ ¦¦0eÊVf[[[ò,77—”øá‡¬½‘áôšššdG©T.•Jq YdÇÊÊŠ´MLLܹsg§¬aIÓôŠ+xÿã%<¹¾ùæ›öþ€_¿~U¹¡¡¹p#ïŸ÷¦¦&R‡¢(’-ÈÆÆZXX°š0#ÑÑÑÌM$(ÀÄ{F™™™¸B÷îÝiÆ5ß»w/óú|þùç¤ Î ‰ýý÷ß ./ $q­]»¶ãûðVàõ¥¥¥uèÐ!Þ5½B¹¹¹ÞÞÞþþþÙÙÙÿÆÑ#""\]]çÏŸO†ÚrM˜0!**Š5Ã:‚ D722²´´|n5<… ­ FŒ¼¬Ér¹œ,%ÐÜÜ|úôéäädff ÐÐPòŒ9à_AZþýû“gl¡P8iÒ$ü:¦iÞ nnnK—.U±í¸mÛ¶8q¢[·nÌ„„Þs7“BèáÇdfœ‰‰ ïŸ÷¬¬,RÇÚÚ÷¤ººš„i\=77·Žtµ?Á„\dÖ-'M[‚ù¤¤¤ÏxI‘Š‹‹{Ñîe¯µáLJ„„´·¬B(88ØÁÁaÙ²eŠW†! ï¼óÎ{ï½—ššª ÚâÅ‹ÃÃÃYÿÒ€"ÏŠÜg]Þj¬GÊðððªª*üdË}vÍÊÊb.~É¢¡¡±lÙ²G‘Å´R©”÷Ù•%;;›änP|R¯hÆŒIIIsçÎe†¡išÞ±cÇ©S§X•Éc¼««kXXXhh(Ž’8::’58’ç!Äœ:ÁÄ|½ïèèˆ?t0õ£ƒƒ3)s“©©iXXXXXžŽ¡­­íààÀÛVàÉÏÏGy¢¢¢***È¡î¿ IDAT)(€T*%ó2tuu_(Q19–P( suuEQÅJ e¯»÷ß?""‚ûoA¢­­í?þèÙ³§½½ý'Ÿ|röìÙ—È ÙÔÔ¿aÃggg7n(¨LQÔ?þ¸{÷nü;xQeee$Å`S?âGJEQ¬×Ý7nÜÀë(î-oêÇÎòàÁƒÏ?ÿœ™‰ðÈ‘#YYY¬¼9¡¡¡Ìóòò*++ñçwÞyÇ××wÒ¤Ifff`Ñ¢Er¹ü§Ÿ~š9s&IÉ“Yb¬5,0©Tú믿’Éi’«‡bE|êêêîܹêOA‚^^^¾¾¾¾¾¾¶¶¶¡>úH(8p €5 €x2666lîÛ¶mÛðÿŒŒÈ÷ûøñã––üYWW—{R 0ã#“'OöõõÅ÷ÆäÉ“MLLÂÃÃþþûïÚ'€ÿ<þ±è¼V†9nÜ8’Ê›WzzzzzúÎ;…B¡½½½‰‰‰¡¡!ù¯P(¬û_õõõ‰$33óñãÇí­Á"‹:4cÆŒN:9ÀÛˆPðÚ¿¢¢¢  &‹>øûûoÚ´ !„—H@|c×™ûßµk^âQ1õ066fÅ,þøãüA(*XO‡»äa' ÈÎξwïybGY[[Ÿ>}º¼¼<** —°æ¸q ;;»®®ÎÈÈèêÕ«xå…~ýúáô ÌiÙÙÙ2™ŒMÞ¿~~>þlllüÉ'ŸpËšräÈ‘úúzüyäÈ‘ÌM)))$–A7nÜ(//755ÍÉÉ Dihh¯X&“‘¹0Ì["221n f8ƒ¹øÈ“'Oš››Œdª¬¬$Ó@È>¼iÓ¦=zÔ××Ïž=»¡¡¡¤¤ä½÷Þëȼ% ÊÞ  ¸}ûö¨Q£dI d2Yjjªâù/ÇÐÐ088¿5€—ÖÁ(©faaAÞB“(yvå Ó¬­­;b@‘‰D"‘Ü?>|8wD‚¼r·³³ëÜ„5ÅÅÅ8Ͻ{÷ž={Ö£G²‰¢({{{e`ÍVà^¡¦¦†³CBBpI÷îÝñæúd®vB ¡Í›7“Ó¬­­%åùùùÌ©($F£¡¡1a„çvOEEÅÔÔ1Æeî!„ÒÓÓñ€ ±XÜ·o_\8yòäeË–Éd2rK0OÆÆÆxL‡\.ß³gÏÊ•+ÑÿŠßµkWJJJxx8‰’0ïRÒ=Š¢ðõ¿téî ³{‚(xƒôéÓçîݻ˗/ SþÑ544V®\¹fÍs7@¶¶¶sçÎáPixx8.TSS;}ú4BH__Ê”)ÌT/<Ø»w/þ,‹CBBƯ¦¦æââbggÇL|Ë|¤lhh !¯»ÕÕÕ÷ïß?~üxü઀]VVB¨¥¥eýúõŸ}ö™™™YjjêG}D†zMŸ>ÕJ"‘„„„àÉÝ ªªºmÛ6„­­íøñãñJœ¯"==Éd#GŽŒŠŠ"kI–••1WÙ$ .ÈåòK—.]¼xÿ( I¬„ ëwGh[[ÛAƒEGGã—,YR\\üþûï———‡††îß¿_*•’&~ø!ÙYû!ôë¯¿š››»¹¹~óÍ7¸|âĉÌï÷öíÛ'Ož$?FGG3WµDŒ(é^VVÖÖ­[ñgmmí3gÎL˜0A[[ÛØØxèС̹~¬á-Æ #{ûꫯärùìÙ³Ÿ>}zûöí;vÄÆÆâ­iii8ÊœœÌ\ÿòáÇø;%ÈR¬>;À¯‹×¸àÅÅÄÄÚ”@(.X° °°°«Ïðfceàúæ›oHå³gÏr+üøãxëW_}E »uëF’¤iš•óññyn÷~üñGV+Ö?£Fbˆ¦i©TúÜàÅ­[·^ýґᘪªªÏòåËßyçUUUR>{ölÒ„9è@155µÖÖVÒ0&&F,+n2dÈ¢¢"fãââXÁ‘HÄüÑÄÄ„ùÿ‘ß~û­ƒÝCÿ,tšÀ×,[¶ ïp×®]Ìòòòrf÷òòò444Xm™—:t¨\.§Û¹ýÚùê_1€ÿÈþÞ<ÞÞÞ7oÞ¼pásHê¿d„ ÉÉÉû÷ï733û·øo#ï~ÛÃLþÏ›QÏÐÐ`,ú÷ïOrTVV’Q ¼ Xµj^>€ ïíBŽŽŽ§Nb%)xøðaqq±âÝ>7 ÑÌÜŠ¡ÖÖÖ»wïîØ±#22ç5 (jêÔ©AAA¤NDDDwîááÁŒx{{?~\KK«½ú«V­ŠŒŒd—‡‡+®ÑÖÖF>ëêꆄ„0ÿ?Òñî™››ã…N#""hšfm%ßìäÉ“É £ÖÖÖ¬oÜÊÊjÿþý¬“b¦·‰D_~ùåõë×q £ãÝ‹ÅÜ55¼å`ÆxS?~ܸq'Ož ½qãFuuu'î\[[{ܸqK–,Qæ  ÀÛ–-[‚ƒƒyW.PWW=zôœ9sHÉÂ… +*****ðݺu=zôÌ™3ñ®®®ãLjˆ …¤!d``°aÆ›7o’ÇQŠ¢¼¼¼˜ÉÚ#‰¢¢¢~þùçßÿd (ªW¯^«W¯þðù«ê899­\¹’L”`166ž2e ^1ááçsŸ#F¤¥¥¥¥¥=~üX*•ŠD"+++ww÷5kÖ0S* „¾ÿþûÇ“¥1Ú£¥¥…@2M:ÕÙÙyÀ€$ÍH$rss8pàĉɤ –­[·º¹¹mܸ‘dLDΟ?íڵ̌¡5kÖ¨©©‘…?Û£¦¦¶hÑ"ü9 --­¨¨ÿ(‹GŒA¶vïÞ=00ðÀ4M3o$bÆŒC‡]»víÍ›7I¦O==½Þ½{Ϙ1cÖ¬YÌÀÄ¢E‹*++ËÊÊwO$M:&`¡¸qqÞ8r¹<11ñúõëׯ_¿sçÎsÿYÉK,÷ëׯ%Æ… o•²²²‚‚mmm++«çNP™LçååE^×·¶¶–––ššš²¦utŠââb??¿gÏž…‡‡[[[—••Y[[wp]„Pmmm~~¾\.·±±y=ŸÀkkkKJJÌÌÌ455»º/þƒ ÊþkZZZRRR*+++++ñ›@ü¡ªªJ hiiiiiijjjýCSSSWW·_¿~vvvÜ7uÞ*?1b„H$š6mÚÝ»w³²²ÊËË{õêåàààèèHÓôµk×’““O:õþûïwug€×Dþ‹‹KJJŠâ:jjj Êéðf¼ !ÔÜÜüøñc„P=FŒáããchh}ïÞ½”””ÆÆÆ=zŒ5jÑ¢EbÚcþOjjjuuõ!CXËFÊårœ ¢«:¼) Ê€Î!èêà?¢ èe@ç€(:DÐ9 Ê€ÎQtˆ2 s@”¢ èe@ç€(:DÐ9 Ê€ÎQtˆ2 s@”¢ è*]Ýà…Éd²{÷îÕ××?·¦¹¹¹££#·¼²²òÎ;ñññ‰‰‰ÆÆÆ^^^ÞÞÞnnn¬j­­­111ÍÍÍÌBŠ¢´´´tttôõõMLLXM¢££iš&%ÖÖÖ½{÷&?–––>|ø°­­”888ôìÙ.**ÊÉÉill$[utt<==…B!÷,ärylllmm-«\SSSGGGGG‡ì–%777//Ù„‘‘‘½½½ºº:o“—ÓÜÜÛÔÔ¤¸EQ½{÷¶¶¶&%4M?xð ²²R&“á¡PاO û©««{ôèQMM ¹þjjjnnn:::¼õ¥Ri\\÷rYXXØÛÛóñÞ½{ññññññb±ØÇÇÇÇÇÇÕÕ5::º´´tÚ´i¼{«­­‹‹‹¿ÿ¾‘‘ÑàÁƒliiyýúu¹\>jÔ(ÞVÏž=‹OOOwpp>>^^^‰$,,láÂ…¼wcmm-¹æêêêø@...·nÝ’H$“'OfVnnnNII‘H$äÔTUU yO¦é„„„ÊÊJÅ×!dllÜ¿n9¾çq÷ÚÚÚèãããîîž‘‘‘0þ|àÿ^ò§¤¤0ÿVð‰DžžžZZZøÇÔÔÔÂÂÂçvOWW×ÃÃ÷ïüëhàMsäÈ‘ŽÿŸîñãǬæ/^400àÖœ={v}}=³æü¡xçƒ –Éd¤ÉÚµkYuAyy9©À}Òóòò"[™OÚÄwß}Ç{"""wÏÉÉéÀÍÍÍÌVÍÍͼO‰¸«½{÷^³f «ÉKûæ›o÷ÐÖÖnmm% CCC¹utuuŸ>}ªàpÜVC‡m¯þ¡C‡:Ø=Š¢ Yͯ^½jjjÊ­¬®®NQEQ---܃ëééq[ሕ¹¹9·Ikkëš5k(Šb5Ý»wG-\¸Y¿¬¬LMM{ˆ°°°ö.…““S/ÅŒ3Xm›šš–,YÂ[¹[·n¡¥K—r˜——7pà@n¡Pˆ;ñâEn«ˆˆcccn+ Š¢„B¡T*eÖß°a·rß¾}ۻï^½ÚÁ뀊g5OHH°µµåÖTUU‰DèÿõéÓ§ƒúàƒp“Çw¼{§OŸnï뀌eðæñöööõõ­®®Ž‹‹kjj²µµ577çVKLL¬««+,,´±±!…ß|óͦM›hšvttœ8q¢‡‡Gqqqttô™3gŽ?ž˜˜xîܹ^½záÊcÆŒY´h‘D"9}ú4BhĈø¡®¦¦&&&F"‘DGGGGGóÍ7ß}÷n2mÚ´„„„«W¯ªªªúùùQeooÏ|qºvíÚóçÏK¥ÒìììÄÄÄ>}ú|ñÅdëâÅ‹¯_¿ÞÒÒR\\œ••¥ªªÚÚÚºuëÖÏ?ÿœû^×ÝÝ}ùò奥¥/^¬¯¯÷ððÀ=ollŒ---MMM]°`AddäñãÇI+±X¼`Á‚K—.¥§§ãWÁE444deemÙ²åï¿ÿ>~ü¸³³ó«}QèÉ“'!æ`ììl \"—Ëoß¾][[[SSC.Ô€¦OŸ^RRBÓ4þ–UUU%ÉüñÃ?´w8__ßÒÒÒÚÚZü>Y$µµµÝºuëöíÛC† i¯{fffd @UUUjjª@ `Ö‰‰imm}öì™™™.¡izíÚµ?ýôMÓ“&Mrww¯­­½zõjhh(y^\\liiIöÓÒÒ²|ùò}ûö!„†>zôhWWׂ‚‚K—.]¹r¥¤¤!T]]Íêd~~~@@@\\œP(œ5k–§§§]llì¥K—îÞ½[ZZÊmehh˜––&“ɲ³³‹ŠŠð´iÓ&___ß”§§'¹ÍRRRª««-,,H䫬¬,==×$233ýýýSSSE"Ñ|àååeggéÒ¥ëׯ744àëÀ:\HHÈ‚ jjjÌÍÍgÍšåî£ž™™‰°°ZÉåòÕ«Woݺ•¦iooï‰'º»»K$’+W®„……UUU!„d2YYY3ô3zôèää䪪*š¦oݺ…‰D¡¡¡3fÌhï:1Pñññ!)@ÿümyò䉻»;iûÛo¿­Y³¦­­ÍÞÞ~êÔ©x¾%ÈèƒââbòçËÛÛ[,ã’ääd‰Dbiiiee…KJKK322È5Ǹ¿>¡þýû“ñiiiååå¬o ”§+CÀ«Á‡;vìàÝŠÿ!~ëÖ-Rò÷ßãÿýÍ™3‡õ2322pà}õ_#GFF’™L–””4}út„@ HHH ›îÝ»‡ øúë¯B›7oæÝ:g΄Ж-[ðÛàÇ+Ø.ìß¿ŸY˜™™¹råJ|¾ÁÁÁ¬&x|øï™9"iðàÁ¡ãÇ“’+W®àjóæÍklldî³  €L­º~ý:)ÇßxQQ)Á·ëúõëIÉ©S§BÞÞÞøG|ººº’ dvUll,)œ;w.j üÛ û#€·…T*ýì³ÏB>>>G%ï±#Fàþ·nÝ:sæÌs÷&\\\>¬­­-—Ë™“ð@h¹\ž——G srr’’’È5B¨  !Ä;¾º®®.$$D,/\¸pæÌ™¡½{÷¾àé¢Þ½{oݺµ_¿~¡‹/v¤‰©©éO?ý”––¦««+‘HV¯^­¸¾T*mmmUP§´PœëA à¸oú†ãÇK¥ÒiÓ¦-^¼X,—––ž={ö¹'røða„М9s>þøc„Ppp0~×ýÝCÿ û'Ý«­­ÅóbfÍšµeËÖÔw—£GâÏ**ÿÿ Ñœœœ-[¶ „¾üòËÕ«W³¦?Œ??“³2#ìß¿?..!:bÄVÇ~ýõ×¾}ûr[IIIÉÉɶ¶¶K—.õòòBá‘,4Mãï‘wžŸä™iJöíÛ—œœLQTxx¸··7«þŽ;† †"C°O?ý´¥¥ÅÒÒòâÅ‹FFFÌMZZZ.\Ày4˜­ª««qTnþüù›6mb]óà¸÷Xž3wî\|Kܼy333“[ ËŠ¯â\ ©TºbÅ „ÐðáÃ:ĺ£,,,ÂÃÃñ7Nº‡gÓ<÷X¬u°{øŽe%”¥(€ÿ”Gýõ×_ø3žýN¢ ÇŽKOOGµ—,`ìØ±8äš5k:x8±XŒ3;&%%‘B]]]þøãñãÇ“qï¡Ï>û¬¥¥E__Ÿ9A† ‡“𘌄3&L˜àããÃm"‹§L™‚Ú´ÆW¿½Ç7Ò‰'¸iSÉ©)¸°¢-uuuøÉÊ”)¼y…Bá¶mÛÌÌ‚yíÚµ . „Ö­[Çž$ÿ\2™,77ý“ºÀÃH”áÒ¥KxA<þS0–5@@æðb]‡û÷ïãî-Z´¨½&®®®·oßff@ÀWOMM ÿ®ñš?þÝ»w™«fàVãÆS°ÈHPPPxx8樂þú«±±ñ½÷Þó¢ðõ**Šì·UQQa ªR| Wü…å€(€7^llìᤤ¤455በ øâ‹/Èk^<@šùz™‹Œ,àMÍRTT´téRü ÅJªÇŠ2DDD¨ªªÚÚÚÞ¸q×—J¥………FFFÜårrrîܹc``ðÞ{ïá’Å‹#„Ž;Æ\áò¹*++7n܈G1øùùu¼!úg± „PFFoü:š /X,--E"Ñssé;88…Bn(„ù*!„ßBÓ4ÔÞ®è’2àGk„ÐG}$222pò?V÷pzNÅÝÉqNA™L†ßZ³VŽT,??w Z ‚ÀÀ@æ2=ÂxCQ˜žžÞºuëxn/\¸PQQ1hÐ  QSS›7oâ ¢©©©¯¯ß§Oæ.kkk 2X€ ®QÐ=.ÜÊÚÚºã‹,¶¶¶â`Ù ˆ ßH8[BhöìÙZZZ•••!!!¬š8‡ƒƒƒââ[‚dÅ'õBÝÃkÍÚÛÛs—a²±±QWW'ÂA–çvÏÁÁ¢(Ò ”­ sB¯¨½g6Þø!6 @ÁI¦·={ö0Ëñ“À”)SV¬X±bÅŠ9sæ0ßc/^¼˜µŸŸþý“ôN&“¼óÎ;xxù¡C‡hšÆ)Èí®Æ\ü¯±±ÏþÀm¹ppdäÈ‘¸{ ,`>½Œ;–¹Ö&Æ›ý‘ ¿j}ú0 'Nœˆš5k·>+û oöGš¦I"Lb@ÿ›Òò¹ÎŸ?[;w®ã­ð+w@À»"æs½ÿþû¬;9++ ßÌd¥˜D"a…›ý‘¦éššš¦¦&üyáÂ…!‘HÄÊŨRL˜0¡ãM’““ñÕÛµkWÇ[ÙÙÙ!===æ âk˛ꕕô”7û#MÓxš¦kkkñUýì³Ï^¨cÕÕÕ¬kÎÍþHÓ´D"aæ‘eu7û#·(ŒeðÆ›7oÞÉð¦9ÀjkkÑ?3–ÛC†"ó& Ù¾}ûöíÛ;†'JØÙÙíÙ³?ú21Ç2ÄÅÅUVVŽ;(Fí'eËåøž¼ŠG©««·÷šéÚµk¸{HKK£iÚÌÌìûï¿¿pá‚@ðÂÿÇÇû% ïÖ€€€üÑÅÅÅÞÞ~Ó¦Md¸‹P(ÄcÔÌÅ>±sçÎUWWûøø0¯Ò¬Y³´´´ÊÊÊÚÏœlBdI‚•}°=8ÑB¨¢¢ «2™¬ù‘Ô˜$÷$·•¸•ššoþÅÊÊÊþþûo±XÌ̉`gg÷î»ï"¾ù#:::9ж¶6Ic/…††wTBkk+ëR¼§ø+à^š¦›9hšF/{Í P `ž ¾%nݺÅ­C¾kÅÈЛÊÊJÜOî¸$¹\Îêsކ®®nG®¹ŽŽsVE»×ÁjðoP4.x#ôï߯(‰:uêTQQïÀï¾}û>xð@ñòd+ž/À²fÍš¾}ûŸ?>&&†¢¨ï¿ÿžùGà(C^^ž\.dz ÆŒãììliiyíÚµÚÚÚö’2DFF>yòD(îÞ½›¼(**BÝ»w/%%…,õÇ2þü¡C‡VUU]¹råòåË¡åË—w<“% mÑÞlUUÕ5kÖ¼ôÎ;Ç êëëq„…ÐÖÖ®««Û»w/NÉT__ƒ8ÑÑÑÌVr¹œ¢¨–––#GެZµêUz…×ì@œ95“I IDATiiiÜ)-;vìøä“OÈeÌÎÎf&5T ·jll,,,äMj¨ÀŸþ)•Juuu?ýôSf98qâ—_~y¡W¿~ýÂÂÂjjjJKK™³]–/_þû￳*ëéé=yòDSS³oß¾IIIÜI½{÷ÎÉÉaNš4)<<¼½kžœœìããýæ{öì!©"HØ.==u#©««755íÛ·oëÖ­>i–––¬îUVVöêÕ‹¯\½z5^mþ« Êà?eãÆÓ§OçêlooÿàÁæê’\d+^ e̘1x5ÁÕ«W7îêÕ«³fÍ222â.1hcc#‰ZZZ #""ÌÌÌphÀ××wûöí.\Àc¸Qüh-“Éx×D@íÛ·oçμ› „Ÿ£V­ZxàÀ/¿üÒÄÄDAš=ð@ ¼D…òã@IJJJJJ ·BdddNNë㘠‹2íÛ·ï£ &&&%%%dꦫ«kggG†~J¥R <ÏßÞÞ^ Èåòöò\ð"?##ãE£ øFª¨¨à½‘êëëOœ8¡ kcGàÜ¡´´4f”¡W¯^VVVøõ~SSSYY™ŠŠŠ››áè蘔””‘‘Aÿ3‰ì gHEUUUÕÕÕéèèà+`jjª¯¯_UU•––Æì€žžž­­-yŒÇ×ÜÊʪgÏž¤Î7pèðæÍ›¼©L9²yóæç®3¢Ní‘ÀꞆ†Fß¾}IÙÒÒÒæææîÝ»óF0à¿¢ þSœœœÚ{0Æ)Ó ð³×íÛ·B"‘HÁÌ „P(£fggã|{... ªµ´´Èåò箫÷Ž;&“Ɇ Æ»zªU«òòò‚‚‚Xï„ñ£õªU«† ÂjRUUµ`Á‚ÌÌÌ›7o6ìUúæèèXRRrûö튊 2ÑÃÌÌŒ¹\hïÞ½³³³wî܉SBhhhôêÕ+;;ûìÙ³?üðCg@A+gΜÁ3:(111%%EOOïàÁƒÜ­‡>{öì¾}û:+ÊÆ ´áä øóÅ‹'L˜`iiyýúuf«ÆÆÆË—/3W{ #Ÿ—.]ºk×®¹sçnܸ‘´ºuëÖÍ›7«««q¶„……IÙ€²¶¶ÎÏÏß½{7s·‡BÍ;—›µ­­mΜ9UUU!!!³fÍzÅK‘ðèÑ£ììl’,F]]¯kƒ½û‘‘ëÖ­[°`Á« Þ]™x5øô;vìèH墢"œváã?æ­PXXˆç?/[¶Œµ ¿tŒŒd^½z—òÉ'ܽáÜ{øq÷ôéÓ¸P*•©««{zz"N>9¼toJHš¦% .ûì³ÐÐÐ{÷î­X±ÂÀÀÀÙÙ¹G¡ÜÜ\ü†¶¡¡áæÍ›Ýºu+))ÉÍÍÍÊÊ:vì^ŒcíÚµí]É+W®°~üâ‹/Ú«Œû†Xâ¹ëõõõø+SUUõôô$K{Ð4’’òË/¿ „\\\¢¢¢ŒœœH:O™L–ššZZZêêê»}ûvœP?|öêÕëêÕ«666ÌË[WW—ššª®®®¦¦ÖÜܼiÓ¦eË–1+dggçææÒÿ¼ç—Éd¸{B¡y=‰íÛ·ß¹s§²²ò£>ºxñâ×_íää$‹kjjnݺuãÆ |²L`÷îÝÆ «¯¯Ÿ={öÙ³gýüü<<<ŠŠŠ""""""ðà===fZKKËM›6­Zµ*33ÓÓÓsÅŠÆ ÃY""".]ºTXXˆ9r$~—^PPpòäÉÊÊJ]]ÝÚÚÚèèhgggf–ÇÜÜÜÇ»¹¹ÅÆÆžýôS¼è#ï7ëïïOöS\\Ì=Sæü ¯¿þº½¾!„Nœ8Á{)ÂÂÂLLLH5}}}Ö2Š~~~¬&­­­ëÖ­‰D¤Ž……+ÛHPP«UQQsx‹H$b]s‘H”——GÓ4T±ÄÄÄ]áaM,8ÒDÓt[[wYJÂÄÄ„÷:ÔÔÔ’jÀÚÚšyŽ¡Û·o³Z­^½º½!„‚ƒƒyÅý‹A¨¨¨ÔÔÔð¶倱 Þ<žžž&LÀo\™TUUñdr´´´N:5vìØ¿þú+>>¾´´T(:;;{yy}ýõ×ø5,1dÈ÷Þ{¹Tž††-OŒ1âàÁƒ8[á”)SH¹››ÛĉUUUY9öÄbqPPО={–/_N .\xñâEòZR,“IØÒ¥KoݺE*ˆD"ggg___2Ô_©S§2öéÓ篿þúý÷ß›ššŒRWW $ÃïÛÚÚZZZtuu------mllüýýŒÁ¦L™²k×®cÇŽµ´´Ìš5 Oåh­­­¿¿YYw“P(dvØÙÙyÆŒÅÅŤÄÀÀwóòòò÷÷///'%FFF“&M¢iÁÀû´²²233#u¦N*‘HHŠ¢IÂNƒ¹sçææær»GQó;eêÞ½{hhè™3g‚ƒƒ“’’?~Œ÷ ­­meeåëë;wî\nÑ^½zݾ}û?þ¸víZBB>S“®Y³Odà?~|jjêÏ?ÿ›˜˜X__ÏqâĉŸþ9Ií©®®¾dÉ’¤¤$2b¿[·nÌõ>srrd2.ÑÐÐ?~<©0zô踸8r›1ijjâ\¾¾¾C‡ݲeK\\\rr2~!/LMM]]]çÌ™Ãú•A‰D¢o¿ýÖÏÏï÷ßOJJzôè^ B,÷èÑcĈ|ðó{ÇLMMÏ;wòäÉÐÐPæ5×Ñѱ²²òóó›;w.ÎÎ0bÄ???ÜÜæX†qãÆ¥§§3w,--É=£¢¢²pá„„Þóm/{¨¶¶vPP¿¿ÿ‘#G’““322ð,’nݺYXX¼÷Þ{|ð77íØ±c“’’x¯¹¶¶ö€x5oÞ<œó‚ËÎÎNAˆ”€¢iº«ût™'Ož°VˆàE544ššš2§')SSSMMMÅ{khh8qâDRRRZZš‰‰ÉСC‡*‘Höïß¿|ùr777R311±¢¢‚u¹,,,ìíí×y!ùùùqqqqqqÙÙÙ...ƒ8p ššÚ‘#GFeiiÉmR\\|çÎøøøäädKKK//¯r{ÕÔÔt÷îݶ¶6¡Pèàà@Ö«gJNN...FéééyzzRÕÖÖvïÞ=æ7ˆihhôèÑÃÜÜ\UU•»ŸôôôgÏžÉd2V¹ªªª···††ï¹ß¿¿²²ò¹×ÜÊʪoß¾øsuuu||¼\.WUUuuuÕ××gUÆwZUUBÈÜÜÜÉÉ !TTT”••ÕÜܬø@jjj>>>ø[[[SSS«««¥R©»»;EQ¤ffffAAé¹–––——^\ðéÓ§iiiϽÏÅb±§§ç«/ó™——WPP@N¢(CCÃ(nõàÁƒÊÊJ©TŠ …vvvä÷N±ÊÊJ|Ç&%%YXX >¾­­Mq(Šrqq111ánª««‹OHHÐ××Çݳ¶¶ŽŠŠjjj7nï cccãããÓÒÒìííìã㣣£sìØ1///rû1Ñ4ýèÑ#|¬’’ooïÁƒ»»»744œ>}zÆŒ:::ÌÊøš“ß¡PØ»woÞ_p,==½  @ñu@ÿ{ï1Éd²ÄÄDܽÒÒR/////¯ºººààà… òþVÖÕÕÅÆÆÆÅÅÅÇÇ«ªªúøøøøø¸¹¹Ý½{·¤¤dÚ´i¼}¨­­ÅMîß¿odd„¯¹¥¥åõë×e2ÙèÑ£™•+**233ëëëÉ¦¦»»»ššïΛššbccŸûËKQTß¾}Éõ,--MNN~îß‘HäîîÎü¦jkkÓÒÒjjjH÷ÔÕÕÝÜÜ´µµï ”„%š3gŽ‚¿HB¡pêÔ©ÑÑѬVü›¶jÕ*ܤOŸ>¬McÇŽ%;üâ‹/¸m9ÒÁijj¶¶¶v¤{êêê .ÄOt¼‚‚‚ºwïÎm(BŸ~ú)©yçÎv!ôìÙ³NùÊššš–.]ÊÝ¿P(466F}þùçÜVGå}4ýôÓOÉuþüòK²UKK+77—µ«0÷pûömš¦wïÞ­àÜ)Šrrr:xð`KK ÙϳgÏÚ{hD-Y²„÷ô###Ÿ{©ÉAKJJp+___RniiYWWÇÚ-ó¤(ª¬¬Œ¦éކ֭[ǽz¡ï¾ûNñù:toå}ôåµ|ùrÅwÈsÕÖÖjiiq÷|ìØ1­.^¼Èm¢¥¥•——÷Ü#îÝ»W]]ÛÜÔÔ!äééɪoccí¼aÆöö?{öì^={{{nó³gÏp+›˜˜àø ·I[[Û×_ÿ&0Q…¿Ê¹sçr[•””Œ3†{ 555Ï=yò$³~XX·²ŽŽÎ“'Ox¯CII ·KíÙ¿?«ù“'O† ­)ð×Ê=èµk×ð÷È¢®®ŽClÍÍÍÜV!!!¼!l|ÍMMMYõy;È{hÎo¢zzzR©·rvvî`«éÓ§37oÞþü„ H«ùó禤¤P5tèPîžKKK322 ñ}ôÑ¡C‡>|ˆë«©©}ðÁ¤²¯¯offfMMÍÓ§Osssõôô&Nœhgg§©©éïï_^^ÛÔÔÔ»woÞÎÞ¹s§¾¾¾¦¦ÆÐÐ!ôÅ_„‡‡?~ü866VCCcâĉ¸Znnîƒššš‚‚‚Ž?çèèÈÚÕÑ£G.\ˆš8qâ¼y󬬬ž>}³}ûvüZ¬¬¬ŒT¶··Ÿ9sfIIɃª««-,,¬­­¹ÝKHHhhh(,,477ïÀw¢Hff¦¿¿jjªªªêܹs `mm}÷î݈ˆˆøøxÜ7‰DÂl"—Ë/^„òòò;v¬››[^^Þ­[·ÂÃÃûí·{÷î………‘ÀJ@@@UUÕ¾}ûBuuuûöíûᇘ;ܱcþ`bb2{öl„И1c¦L™RUU•‘‘Q\\lllܯ_?„Pkkë³gÏðH–?üpçÎwîÜÁO,&&&~øann®T*MNN–H$={ö´±±¡(JWWwÊ”)¼WÀÉÉiÆŒøšK$KKKÞwéñññÅÅÅø¼–,Y" CBBB!!!ÌÛ¯¥¥Ÿ/B¨OŸ>3gÎÄ£l¯\¹òôéÓG©¨¨ 4ˆ{ ¢¢¢ììlrŸOžüÿµwßaQ\ßÃÀ/»ìÒ{± "ň  ˆ¨QcìDLÐbAKL,hhìhTbŒF±'V01bD‚Déˆ ‚ "(ÒÛ.ûþqžÜg¾³³ËbHÌóþÎ笯¯OKKÓÐИ:uª““!¤½½½¢¢‚2f̉HOOohh°°°èÓ§,yñâEQQQqq1gË(NKKkÉ’%YYY"‘èéÓ§ÅÅÅB¡°­­mçÎrºë¶¶¶sæÌ)//—H$pI …ÂúúúìÛ·OÖ^uuuÞÞÞÐòüñ¸q㬭­óóó£££ããã!#¦¦¦†µ×Ò¥KãââZ[[ËËË=z‡·ÿ~ÎgéÐ&VVVp „˜:uª­­miiittôüŠôá•””xxx$''óx¼yóæ9::80555:::))IÖ^±±±óæÍ«¬¬400˜?¾¾¾~llldddQQÜ^X_^{{{–Á%- kkk:´{÷név(--íèèPQQaæ†$&&B†ª«« K=zT^^ÎjŠ«W¯.\¸°¦¦¾×Ç700ˆˆˆÈË˃Ì5ø¼(‰D²aÆ   ŽŽ—áÇ744ÄÄÄ\¾|ùÕ«W°Yyy9óKÚÚÚºjÕªÐÐPBȸqã¦L™2tèÐâââèè蘘h=V;B¼¼¼455›šš^¿~ 7À¶¶¶Ó§OoÛ¶3ß ÎNú룡¡1|øpX"‹“’’jjj 1ö1b Šåää°îíUUUyyy¬Ösuu}õêU]]]ssó½{÷A{{{|||JJ +O!„Þwå@ýŸtïÞ=¸566Ò…---·o߆$jCCCÈeŠŽŽ&„¨¨¨p¾æéÓ§ !îîîtÉÇá]îܹ#ëH "ÈZþÞ{ïBŽ;ƹŒ€¨ªªb.üùçŸ !¦¦¦Ì…õõõÑÑÑÐÛ·±±a½Nee%äßîØ±ƒµ*55~£3S0(Hî]¿~=çáÁó±»wïr®U\[[<]755MIIa­;w.4¯··7s9Ä!k×®‹ÅÌU—.]‚Ös9èQ¨«««©©™™™uttÐUð!B_ŽóI¯¯/!dîܹ̅åååëÖ­ƒÃðòò’Þk„ „…B"‘H$ãÇ'„lÙ²…s-$«gffÒ%™™™ôÈ'OžÌÜøÊ•+t•tÅ/¿üB100à|£ƒB|||˜ ÃÃÃé?ëŸ|ò k—œœBˆµµ5]R[[+ý´µµ%„ìß¿Ÿ.9r䈬+ð­3†òÃ?ÀcçÄÄÄNw©®® …ZZZ~200à|X |||!ªªª'Ožd­¢‘ Y»/X°€²{÷n¸Piê ¤/EDDÐ%_}õ!ÄÙÙ™.)**"„ðù|æŽ;wî$„ðx¼ÀÀ@æu.‘Hbbb /@II‰¹¼££ÍÐÐ0&&†u$kÖ¬“b¾µD")--…ÛÔˆ#X™---ðYB:Äy‚ÊÊʺºº;vì „³RdW±ÚâV±±±t $C1¿nÏž=ƒ~õøñã!D544С4ûöíc®:uê,÷÷÷ooog®ÊÊÊ¢ù2>d®Ú²e |»wïfµydd$\‡²þY‘H$ß|ó !$ ÀÔÔ”üoº“««+«=CBBX·ýÖÖV8BzÊpÿg¦ç@îÉ×_M—@‚‰çûBª—‡‡\$ .”u"!ôoÂê¡ÿ •1cÆ@µººúîÝ»ó---á‡×ñãÇ97¨¨¨ˆŠŠâñxÌçÌÝKSSsÊ”){÷î%„äää”””0×Þ¾}»¥¥E[[{ýúõ¬‡¾|ùrBH[[Û?tl ÎËËãñx‘‘‘ŽŽŽ¬µGŽéÛ·/!„Yæ ¾¾~ãÆ„Ï>ûlïÞ½¬lêÙ³gÃ/ï‹/2GÀcU--­3f<þüÎ;tUXX!ÄÃÃn¦ˆž={îÙ³géÒ¥„ððpéB ÿ8Z+++›¸¸8fNJXX˜ššš‹‹ éÊIujôèÑW®\‰‹‹SäØ!²™èi˯‡"‹iß©SEEEIII½zõúüóÏ?úè#B}útæ8²µk×¶´´èééqÖâ!]qqq%%%ƒ òõõUVV†¡Ò[*Ø2€¦ á9E.$Î`„ízôè1yòäÙ³g6559sFþ1 „п£ ¡ÿ–¢¢"èrsDdÉÈÈXºt)¤ŒNœ8ñ»ï¾ƒ‡ÔgŸ}¦­­ÝÐÐÀL)§à)···"¶zõjºåÑ£G?ÞéJêÑ£Gð?¬“‚•åå圿 ÁÚµk!£SžžžðKtÏž=ÁÁÁ Pðð8ݹs§±±‘È8mÞ¼yóæÍ2RRR!Æ “UÕL(BG155•ö„i‡|Ú´iºººáááðø7777//ÏÝÝæ éj”~@ÿP.ÃÖ­[çÌ™ |ÿý÷`„.„@ ðððPRR¢¡“ÈÈȆ†wwwx€©ÈI%''/[¶ìܹs„?þ8((ò\¤-Y²ÄÆÆ&77;È×I§SŸ@UV.Ã… ‚ƒƒ+++kkkOž<ÙiV}, £\\\z÷îÝÚÚ*¿äjNNNFF†©©)ŒXÎÿíÛ·óóóY[ÖÔÔ¤§§B|||dužgΜ £¤A×ÏÖÖÆ·ÓqLŠ4 ††Œ  ÅhÜÜÜ8K?BìííO:B¹gggC œ8§+V®]»–.7âñxÌï&ËÉ“'ׯ_Ï,C¥§§çææöïßn>ðÖñññ0„IÁ "ž´bbb!ÊÊÊ0¼…Ó¼yó’““™õPa¯‰'BÙN‡¢ƒ !‰$66–2gÎZ$‚ÅÑÑñøñãÁÁÁœki´…Ò«W/\r^êoÑð_%%%Y³ÛHïÂß9sæðù|øJ‘ü „ú§a”!ôRPP?‹555'NœÈ¹X,>ý—Ë—/B௺ºúW_}Ūү®®}ZéA)))ùùùúúú3gΔu<ÉÉÉô½^¼xoD™:uªt>6§ŽŽŽŒŒ ³mnn• ©qãÆÁ4 Ë–-›1cÆÙ³gËÊÊyYpÿþ}zxÐé‚#ttt\µj•œù‘——ÿ#'Zall¼mÛ6æ|„5 ®Aè$´µµ=}ú–@O[( …ÂY³fUUUA߆Kt©CΔ@QUU…ÂÝ"++‹¶ù£G:::àQ¼““ÓŠ+˜ùØ4tbff6zôè;wîÀù†……ijj:;;Ë´¶¶Ò7Šˆˆ „TUUB´µµýýýe}(|>ƤlÞ¼YNrA=TUU¥k‘² 0@EE…³Ö!äÚµkÌ?¯_¿.ÿÕâãã‹‹‹mll ¥¬¬ )èœÝx ºysçÎ…´‹aÆAMé½|8dÀÀ ÐÔÔÏÉå—X²d }/Ej7BêëëCþ]WWÇãñœÿüóO(wÇ2~üø'OžlÚ´ÉÎ΢MMM™™™tqqùè£äd7Ìœ9“,­»À“pÎAݲ466ÂØù À´×J«”1£ ãÇïÝ»÷•+WþüóÏÂÂBwwwBH§#&ÒÓÓW¯^½zõê/¾øbÖ¬Y €± ƒ–ÿ¨¼«fÍšEÛœêçÄ<)777eeå .üþûïÍÍÍŠœ”¦¦&}£€€€.äwß}§ªªzäÈÚG•¦¯¯¯HðEOOOÖƒVWW×   ;;»Aƒmß¾}áÂ…r^§®®îòåË|>†Áˆ£ÉÊñ¾~ýúË—/‡ ÆÌQòððÐÕÕ}ýú5«$ÍÝèÒE $ÍÃìZ«ªªB GúRQQQ¤î‰P(¤‰úowx°—@ P||!òkÞ¢!W¯^}ýúµ““óùÿܹsµ´´ªªª¤k@*…422¢7jH¹â<¼)9¥ydÒ{‰ÅbÖ.4ùw. Â# “®©¬¬ÜiˆÂçóiÌ‚¢££#'ÌMikkK_g^±ä¯l‹ððpé¹9Bèß„¹ ¡w)44T(üòË/EEEººº?þø£¬!ý€Çãѧ¦yyyÛ·o‡‰ÇåðññY¹r%<ü„.ÓåË—ëêêlmméS Nô½Ž=*8-M__ÿûï¿—H$™™™—.]ª¨¨077?vì˜¬Ô BˆŽŽÎöíÛ·oßÞØØ˜ýäÉ“´´´Ó§O×ÖÖÆÇÇ/\¸$KÊÎΖ5œÅÒÒòĉÐg#„ܽ{wÈ!Ò=Ãyóæ­[·®ªªêêÕ«³fÍ" —P°î# ‚É,!¯_¿fÕ€ðë|Ñ¢EK—.urrzüøñ¤I“ÒÒÒ:ÍŒÕÐÐ5jÔ¨Q£æÍ›·cÇ__ß°°°7n¤§§3kp øðÃáùjmmmQQQ§»ÈGÇZ(þRƒ~ùò%-¸À‰®…â—ä;ä„ùóçïß¿???ôèÑ0¼¢Ó(Ø1c`F: >}úôéÓÇÐÐP~’‹‡NLL\¼x±ü ‘o¾ùfÚ´ið±¾yóæÉ“'öööt-ë¤,X•ŸŸïãã§£xIK[[ÛcÇŽÑá3)))C‡•ÿpû믿>uêÔ7®^½*¿|À¿ž»ÖÖÖrÖz„Ìú…„êêjèÝ=xð€3)#)))//~ éL(>¤µºtxb±XV)Ê£G:t¨K¯Ébii)ÚÛÛYá0ù˜'¥x”ÁÚÚúÖ­[?noo—?查¢¢&P¸ÿ>Œk`¹yóæ[qX† r÷îÝÂÂB‘HÄL¨±²²¢“ÕÔÔÔÕÕikkCÐY__¿W¯^åååtÐÕÕ0`@MM üùâÅ ‘HÔ·o_333òW=ˆŽŽŽ.µ9 WÂÅ‹97 }‡QÛB"##97 Å(BèÂ(Bè?ÁÈÈ(""bĈÕÕÕË–-»zõª"{ñù|)¸uëÖ¸qãüüüöíÛÇÚLOOÏÕÕõüùó'Nœ˜5kÖÓ§OTTTæÎ«ø2;œ“'O.,,lhh_©ÁÊÊê§Ÿ~ruu}ðàÁæÍ›ƒ‚‚XÌŸ?¿²²òüùóÒOq555¿ùæÖ‘™™Ùi?À€ô§¿——WDDDII ÌùvhFIXX˜âQ++«„„„ìììÚÚZY9&·oß&„˜˜˜ÐœsV‡ÜÎÎîÀ™™™kÖ¬%Ð!‹Å¬n effÖi]ÅÕ××B  †–––4PâééUQQA§a”»»{nnnuuõÖ­[a œ”"Å&šñúõëÎÎÎ7n„I+eQWW òôô\»v­¬nR·hkk‰DòÇÈ}zìØ1é[Y—@³­­-22’Y|nwô½öïßïáá±gϺWyyyRRRUU•‘‘,ìÕ«Wff&ÝkРA€—USSƒª.»víRdl …÷îÝ+]Ó!77wÓ¦Mׯ_/--ý;÷Ø¿RNüýýGÅZUUUµdÉ’$''K¯E¡‰!„þu÷î݃[Pcc#s9”ë#„œ={Vz/xȦ¢¢Âùš0¤»»;çÚ¸¸8BÇ+))jnnnrŽÆ$;vŒs-ôŸ«ªª˜ áW©©©)kc7ËçóïÞ½ËZÉü;vìà|—öövøY|ñâE֪ɓ'BÖ¯_Ϲ# ‘~»®‚¹UTT?~,k›ÆÆÆ¦¦&úgnn.D^dTvv6|Ä»ví¢ ¡üðÃþýûwttœ8qRa»4\¢KïÅÒ»wo±X¼hÑ"ÖƒkHz?xð ôDô„k×®ÁöŽŽŽÿÜáÉqèÐ!@ÐÚÚêêê ¿k™$É™3gȬmaees‘îÛ·/''‡µK}}ýªU«!æææÌ‡¥¬ÇþÒèCÈ®Nfù¯‘nsæœ1!ÿä áñx0MC·;{öìÉ“'ß¼yÓØØxþüyf9&éùöXAf‘Åìì쬬,--­O?ý”s////uuõšššK—.Ñ…ëׯ‡á!+W®„Ž"KrròÈ‘#{öìYZZJrù£ttt ééï—]°`Ä}vîÜI#LyyyÓ¦M322JNN¦ ÷íÛ§©©)‘H<<<˜Ïí©+W®XYY½÷Þ{ííí°DKKëûï¿'„<{öÌÃÃCzNÓ–––o¿ýÖÔÔ”Y;0555//OWW×ÅÅ…óø½½½UTTªªª~ûí·.8‹¡¡áîÝ» !OŸ>õõõU¤Þ !ÄÙÙù“O>!„œ:uJñÏÂ××îŸÛ¶m;{ö¬ô÷ïߟ4i’‘‘Qjj*]ŸÎ¼yó8G]ñùü%K–BŽ?Þ]7Û.Û9s¦¬¤Ë—/'„\ºt‰Ž%A¡Ž˜@ý«êëëÓÓÓiÿ3**ÊÄÄdذaÐÃäóù§OŸ6lØëׯ}}}ììì444^¾|ùðáô´4BHGGgÿs1¥¤¤äããóÍ7ßìÙ³§¹¹¹OŸ>“&M’ÞL$åääTUUÁßÜÜ\Î÷‰DÌ?«ªª²³³á¤ZZZ®]»Ö§O:žž^hhèŒ3òòòüüü¼¼¼ììì ó©££SUUUQQ1~üø‹/:::B;ˆÅâ‹/Â/ÅY³fõë×yšPqýÉ“'œ‡ ÿßàÁƒ7lذmÛ¶ììl{{û5kÖŒ3ÆÒÒòÎ;ÑÑÑÑÑÑ š={6s¯íÛ·_¹r¥¬¬lÔ¨Qtvv622jnn¾wïÞòåËóòòø|~pp0 äææfddB^½z9hÐ fвD"ÉËË£±±±|ð‰‰‰H$ºsçNSStËÊÊþøãBŸÏ·³³300à<£G‹D"(ÂÿôéSÎd•ÈÉÉJ„¢¢"Î]˜õçÄbqVV”©{þüytt´ ³ÔH{{{nn.\0 ÖÖÖYYY„¶¶6Î7bK'„”––æææB^¾|­¢¢bkk«§§G±··÷öö†gõœÓÒÒ`€7\6ùùùð¾=zô°µµ•SÛ‚UW2&&fãÆÒÇvùòåÒÒR555‘H”””dmmÍJóüùó¡C‡ÆÅÅ]¾|9&&ÆÑѱ¸¸›ÛØØÜ¾}ÛÈÈÈÚÚš¡:::rssËËËííí“’’~øá‡AƒÙÙÙ)++«ªªþøã3gά®®ž>}º··÷´iÓìíí £¢¢¢££a|¾™™\!UUU‰‰‰III„„„+++šO©¨¨ÈÏχ̦{÷î;wnòäÉtƒŽŽŽŒŒ ø2>{öŒ~„uuuGGGVо’’Ò?þ8f̘ºººE‹]½zuöìÙ•••QQQQQQYYY‰DGGÊ “={ö|ùå—EEE#GŽ\µjÕ¸qㆠ’‘‘'URRB;v,3Nçááqîܹk×®EDD :ÔÏÏÏÑѱgÏžqqqQQQqqqðqÈ ‰D’““³wï^Bˆ­­mBB‚±±±µµ5$‹sss+**ìììRRRBBB,,,è´8„W¯^effÂQ"‘BRSS!êÑ¿Zç•òõõ½páÂÍ›7Ï;wïÞ½ýû÷;99éëë···§¦¦Þ¼y“³Ü@HHHRRRuuõÒ¥K###7mÚdmm­¢¢R[[{ëÖ­„„fðˆ¶ùáÇǎÛÐÐ0þüˆˆWWW‡²²2h=øºéééÁü»µµµ÷î݃©4zôèoiiibbB_ðÕ«W¹¹¹ËPZZzàÀwwwæ·;;;ІBQÆúúz¸$„Báˆ#8‹Ñ¶´´¤¥¥AM Ö½]__øðátœQSSSFF„íÌÍÍoܸaaaÁ,ØQ__Ÿ““£©©) ›››wîܹ|ùò·›Û!„þ–w™Hú¿‡5í8räs:—²f͉D¢x]9™óeeeôGÿ¶mÛ8·"p ª©©½¤×&$$0_¦ÄG……Ìb„UUU''§Q£FÑN²sŒ@bb¢â‡—žžþV[XX˜¬ÚÔÔÔ6lØÐÞÞÎÚ¥²²’ÄéÕ«í®˜˜˜Üºu‹n)ï  ™ í0¬€©W¯^‰DN)> Î)..–. Gbb¢D"‰U|—û÷ïKþ¿ÀÔ§Oæ‘|ûí·¬ Æ/‘H ¤à-]º”¾­AÙÙÙ1? èÕsŽ˜€G²²Ü¸qCÎ…Áz }øðaÖ"‘HúYëÔ©SéoÞ¼‘*?mÚ4é#9pà€œK‚üo’ff& `‘¦¤¤4{öl:¸ƒV= È<é2´cÇŽ¥k™iÒ8ÛíéÓ§|ð¬½>üðCÎJÑÑѲæ©_~ù%sà‹Åß~û­¬!##£'NÀ–7nÜÞ€y[æ,íñÛo¿Ñ œœœd‘’’Ryy¹ôµ··2“}LMMY•/<ÈÚ«²²ÒÕÕ•n ¬¬Ü¿æ÷šÏç?zôˆµWQQ‘œ#œ8qâ³gÏ`KéËOWW—9BdĈ¬ ÌÍÍéZ˜–BYÿŸ_ZZJ7.O£ªª*}m „Ð? sBÿªY³f½xñ‚9Ó¸žž«B•¿¿}}}RR’²²2 R…ÙÚ%‰ü …>>>²ÖöêÕk÷îÝ{öìéß¿ÿ—_~ɹƒƒÃÇ\__ßéôööö´Pœ——ëÇqÏž=é$jà‡~PQQÉÏÏ×ÐР# lmm322¼¼¼´´´ÂªªªàG*dz´´\·n——³ÀäÀ]]]_½zÕéáõíÛWºõvÜÜÜF½wïÞÔÔÔÌÌ̦¦&@`nnîêêêççgll,½‹±±qttôÁƒ¯]»–ššZ^^.†>jÔ¨M›61K]öéÓz}ð'œ8<‡666Ì !Ð[3fÌôéÓ¥s­•••9³T!†††îîîeeeŠÌ=ѧOø˜ ôé§Ÿ¾~ýºÓ½úõëº \Eô ¦5vìX˜¢¤¤cï,XÓéu®ªªÊLï÷ññINN¦{©©©}üñÇt­±±ñÞ½{W¬XÁÂpqqyòä +7èééÑyF8¹¸¸9räÌ™3žžž^^^¬ ø|þŠ+RRRhV¹ºº:³¤££³téÒ¼¼“––gÚ£G‘#Gúûû=šs¯)S¦Ü¿ÿ»ï¾KIIÉÈȨ¯¯çóùfffÎÎÎþþþ¦¦¦Ò»ðx¼õë×O™2åðáÃiiiŸašÕÑÑ122Rü_¼xѳgOY 8UVVª««w©ÍBu FB!„B!Ô=pŽ „B!„BuŒ2 „B!„B¨{`”!„B!„BÝ£ !„B!„êe@!„B!„P÷À(B!„B!„ºFB!„B!Ô=0Ê€B!„B¡îQ„B!„BuŒ2 „B!„B¨{`”!„B!„BÝ£ !„B!„êe@!„B!„P÷À(B!„B!„ºFB!„B!Ô=0Ê€B!„B¡îQ„B!„BuŒ2 „B!„B¨{`”!„B!„BÝ£ !„B!„êe@!„B!„P÷À(B!„B!„ºFB!„B!Ô=0Ê€B!„B¡îQ„B!„BuŒ2 „B!„B¨{`”!„B!„BÝ£ !„B!„êe@!„B!„P÷À(B!„B!„ºFB!„B!Ô=0Ê€B!„B¡îQ„B!„Buÿ•.]SúÇ»IEND®B`‚abyss-2.2.4/Unittest/PairedDBG/test.svg000066400000000000000000001243341361462241400177120ustar00rootroot00000000000000 image/svg+xml GC..TA TA..GC GG..TT AA..CC TG..AT AT..CA AT..CA TG..AT CA..CC GG..TG AC..CC GG..GT AA..TC GA..TT CA..GC GC..TG CC..GG CC..GG CC..TG CA..GG TC..AT AT..GA FORWARD:TAATGCCATGGGATGTT REVERSE COMPLEMENT:AACATCCCATGGCATTA INPUT SEQUENCE Forward pair Reverse complement pair pair Adaptation of Figure 4.35 from:Phillip Compeau, Pavel Pevzner. Bioinformatics Algorithms: An Active Learning Approach. Illustrated edition, 2014. abyss-2.2.4/_config.yml000066400000000000000000000000321361462241400147650ustar00rootroot00000000000000theme: jekyll-theme-caymanabyss-2.2.4/autogen.sh000077500000000000000000000000721361462241400146430ustar00rootroot00000000000000#!/bin/sh set -ex aclocal autoconf autoheader automake -a abyss-2.2.4/azure-pipelines.yml000066400000000000000000000151221361462241400165030ustar00rootroot00000000000000jobs: - job: linux_gcc8_32bit pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq gcc-8 g++-8 displayName: Install gcc-8 - script: sudo apt-get install gcc-8-multilib g++-8-multilib displayName: Install 32-bit compilation support - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=\"gcc-8 -m32\" CXX=\"g++-8 -m32\" --build=i386-linux-gnu" ./configure CC=gcc-8 CXX=g++-8 --build=i686-linux-gnu "CFLAGS=-m32" "CXXFLAGS=-m32" "LDFLAGS=-m32" --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with gcc-8 - job: linux_clang6 pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq clang-6.0 displayName: Install clang-6.0 - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=clang-6.0 CXX=clang++-6.0" ./configure CC=clang-6.0 CXX=clang++-6.0 --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with clang 6.0 - job: linux_gcc5 pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq gcc-5 g++-5 displayName: Install gcc-5 - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-5 CXX=g++-5" ./configure CC=gcc-5 CXX=g++-5 --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with gcc-5 - job: linux_gcc6 pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq gcc-6 g++-6 displayName: Install gcc-6 - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-6 CXX=g++-6" ./configure CC=gcc-6 CXX=g++-6 --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with gcc-6 - job: linux_gcc7 pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq gcc-7 g++-7 displayName: Install gcc-7 - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-7 CXX=g++-7" ./configure CC=gcc-7 CXX=g++-7 --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with gcc-7 - job: linux_gcc8 pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq gcc-8 g++-8 displayName: Install gcc-8 - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-8 CXX=g++-8" ./configure CC=gcc-8 CXX=g++-8 --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with gcc-8 - job: clang_format pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: | ./autogen.sh ./configure displayName: Configuring - script: | curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" sudo apt-get update sudo apt-get install -y --no-install-recommends clang-format-8 sudo ln -s clang-format-8 /usr/bin/clang-format displayName: Install clang-format - script: make clang-format displayName: Run clang-format - job: macOS_default_gcc pool: vmImage: macOS-10.14 steps: - script: | brew update brew install automake boost openmpi google-sparsehash make pandoc ghc displayName: Install common - script: | ./autogen.sh ./configure --with-boost=/usr/local/opt/boost/include --with-mpi=/usr/local/Cellar/open-mpi/4.0.1_2 CPPFLAGS=-I/usr/local/Cellar/google-sparsehash/2.0.3/include make -j12 distcheck displayName: Compiling ABySS with default gcc - job: linux_gcc9 pool: vmImage: Ubuntu 16.04 steps: - script: | sudo apt-get update -qq sudo apt-get install -qq software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -qq sudo apt-get install -qq autoconf automake gcc g++ libboost-dev libgtest-dev libopenmpi-dev libsparsehash-dev make pandoc displayName: Install common - script: sudo apt-get install -qq gcc-9 g++-9 displayName: Install gcc-9 - script: | ./autogen.sh export DISTCHECK_CONFIGURE_FLAGS="CC=gcc-9 CXX=g++-9" ./configure CC=gcc-9 CXX=g++-9 --with-mpi=/usr/lib/openmpi make -j12 distcheck displayName: Compiling ABySS with gcc-9 abyss-2.2.4/bin/000077500000000000000000000000001361462241400134135ustar00rootroot00000000000000abyss-2.2.4/bin/Makefile.am000066400000000000000000000006751361462241400154570ustar00rootroot00000000000000if !HAVE_LIBMPI nompi=ABYSS-P endif ABYSS-P: $(top_builddir)/bin/abyss-nompi cp $< $@ dist_bin_SCRIPTS = \ abyss-bowtie \ abyss-bowtie2 \ abyss-bwa \ abyss-bwasw \ abyss-bwamem \ abyss-fatoagp \ abyss-kaligner \ abyss-pe \ abyss-samtoafg \ abyss-tabtomd \ abyss-bloom-dist.mk \ abyss-dida \ abyss-stack-size \ $(nompi) dist_noinst_SCRIPTS = \ abyss-adjtodot.pl \ abyss-cstont \ abyss-fac.pl \ abyss-joindist \ abyss-nompi abyss-2.2.4/bin/abyss-adjtodot.pl000077500000000000000000000017231361462241400167050ustar00rootroot00000000000000#!/usr/bin/env perl # Convert an ABySS adjacency file to GraphViz dot format. # Written by Shaun Jackman . use strict; print "digraph adj {\n"; while (<>) { chomp; my ($id, $length, $coverage, $a, $b); if (/;.*;/) { ($id, $length, $coverage, $a, $b) = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s;\s*(.*)\s;\s*(.*)$/; } elsif (/;/) { ($id, $length, $a, $b) = /^([^ ]+)\s+([^ ]+)\s*(.*)\s;\s*(.*)$/; } else { s/,0/+/g; s/,1/-/g; ($id, $length, $a, $b) = /(.*) (.*) \[(.*)\] \[(.*)\]/; } my @a = split ' ', $a; my @b = split ' ', $b; my $attr = "l=$length"; $attr .= " C=$coverage" if defined $coverage; print qq{"$id+" \[$attr];\n}; print qq{"$id+"}; if (@a > 0) { print ' -> {'; print qq{ "$_"} for @a; print ' }'; } print ";\n"; print qq{"$id-" \[$attr];\n}; print qq{"$id-"}; if (@b > 0) { print ' -> {'; for (@b) { my $x = $_; $x =~ y/+-/-+/; print qq{ "$x"}; } print ' }'; } print ";\n"; } print "}\n"; abyss-2.2.4/bin/abyss-bloom-dist.mk000077500000000000000000000145331361462241400171450ustar00rootroot00000000000000#!/usr/bin/make -rRf # Setting the SHELL variable does not work under SGE's qmake utility, # so we must do this instead. BEGIN_SHELL=/bin/bash -o pipefail -c ' END_SHELL=' #------------------------------------------------------------ # optional params #------------------------------------------------------------ # Number of levels in counting bloom filter. # Note: Changing this value will currently break the script. l:=2 #------------------------------------------------------------ # global vars #------------------------------------------------------------ PROGRAM_NAME=abyss-bloom-dist.mk # convert bloom filter size from kilobytes/megs/gigs to bytes override b:=$(shell echo '$b' | \ sed 's/k/*1024/I' | \ sed 's/m/*1024^2/I' | \ sed 's/g/*1024^3/I' | \ bc) # strip leading or trailing whitespace from files list override files:=$(strip $(files)) # compute mem limits (in gigabytes) for SGE_RREQ lines below b_gb:=$(shell echo '$b / 1024^3' | bc -l) l1_mem_gb:=$(shell echo '$(b_gb) / $w + 1.05' | bc -l | xargs printf '%.1f') l2_mem_gb:=$(shell echo '2 * $(l1_mem_gb)' | bc -l) union_mem_gb:=$(shell echo '$(b_gb) + 2.05' | bc -l | xargs printf '%.1f') # a single space character space:=$(noop) $(noop) b_times_l:=$(shell echo '$b * $l' | bc) b_mod_w:=$(shell echo '$b % $w' | bc) windows:=$(shell seq 1 $w) l1_bloom_files:=\ $(foreach window,$(windows),\ $(foreach file,$(files),\ $(name)_l1_w$(window)_$(notdir $(file)).bloom.gz)) l2_bloom_files:=\ $(foreach window,$(windows),\ $(foreach file,$(files),\ $(name)_l2_w$(window)_$(notdir $(file)).bloom.gz)) #------------------------------------------------------------ # functions #------------------------------------------------------------ # arg 1: filename of the form $(name)_l_w_.bloom # output: list of filename parts, split by '_' splitBloomFilename=$(subst _, ,$(subst .bloom.gz,,$1)) # arg 1: filename of the form $(name)_l_w_.bloom # output: getWindow=$(subst w,,$(word 3,$(call splitBloomFilename,$1))) # arg 1: filename of the form $(name)_l_w_.bloom # output: getReadFilename=$(subst $(space),_,$(wordlist 4,999,$(call splitBloomFilename,$1))) getReadFilePath=$(filter %$(call getReadFilename,$1),$(files)) # arg 1: filename of the form $(name)_l1_w_.bloom # output: list of bloom filter files for level 1, window , excluding # input (arg 1). getSiblingBloomFiles=$(filter-out $1,$(filter $(name)_l1_w$(call getWindow,$1)_%.bloom.gz,$(l1_bloom_files))) #------------------------------------------------------------ # special rules #------------------------------------------------------------ .PHONY: args_check build # don't automatically delete intermediate bloom files, because they can # take a long time to build! .SECONDARY: $(l1_bloom_files) $(l2_bloom_files) default: build #------------------------------------------------------------ # parameter checking rule #------------------------------------------------------------ args_check: ifndef name $(error $(PROGRAM_NAME): missing required parameter 'name') endif ifeq (_,$(findstring _,$(name))) $(error $(PROGRAM_NAME): sorry, 'name' parameter ('$(name)') must not contain underscores) endif ifndef k $(error $(PROGRAM_NAME): missing required parameter 'k') endif ifndef b $(error $(PROGRAM_NAME): missing required parameter 'b') endif ifndef w $(error $(PROGRAM_NAME): missing required parameter 'w') endif ifndef files $(error $(PROGRAM_NAME): missing required parameter 'files') endif ifneq ($(b_mod_w), 0) $(error $(PROGRAM_NAME): `b' ($b) must be divisible by `w' ($w)) endif #------------------------------------------------------------ # main rules #------------------------------------------------------------ build: args_check $(name).bloom.gz # level 1 bloom filter files $(name)_l1_%.bloom.gz: $(files) SGE_RREQ="-N $(name)_l1 -l mem_token=$(l1_mem_gb)G,mem_free=$(l1_mem_gb)G,h_vmem=$(l1_mem_gb)G" \ $(BEGIN_SHELL) \ abyss-bloom build -v -k$k $(build_opts) -b$b -w$(call getWindow,$@)/$w \ - $(call getReadFilePath,$@) | gzip -c > $@.incomplete && \ mv $@.incomplete $@ \ $(END_SHELL) # level 2 bloom filter files ifeq (1,$(words $(files))) $(name)_l2_%.bloom.gz: $(l1_bloom_files) SGE_RREQ="-N $(name)_l2 -l mem_token=$(l2_mem_gb)G,mem_free=$(l2_mem_gb)G,h_vmem=$(l2_mem_gb)G" \ $(BEGIN_SHELL) \ abyss-bloom build -v -k$k $(build_opts) -b$(b_times_l) -l2 \ -w$(call getWindow,$@)/$w \ - $(call getReadFilePath,$@) | \ gzip -c > $@.incomplete && \ mv $@.incomplete $@ \ $(END_SHELL) else $(name)_l2_%.bloom.gz: $(l1_bloom_files) SGE_RREQ="-N $(name)_l2 -l mem_token=$(l2_mem_gb)G,mem_free=$(l2_mem_gb)G,h_vmem=$(l2_mem_gb)G" \ $(BEGIN_SHELL) \ $(if $(word 2,$(files)), zcat $(call getSiblingBloomFiles,$(subst l2,l1,$@)) |,) \ abyss-bloom build -v -k$k $(build_opts) -b$(b_times_l) -l2 \ -w$(call getWindow,$@)/$w \ $(foreach i,$(wordlist 2,999,$(files)),-L1=-) \ - $(call getReadFilePath,$@) | \ gzip -c > $@.incomplete && \ mv $@.incomplete $@ \ $(END_SHELL) endif # final output file ifeq (1,$(words $(l2_bloom_files))) $(name).bloom.gz: $(l2_bloom_files) cp $< $@ else $(name).bloom.gz: $(l2_bloom_files) SGE_RREQ="-N $(name)_union -l mem_token=$(union_mem_gb)G,mem_free=$(union_mem_gb)G,h_vmem=$(union_mem_gb)G" \ $(BEGIN_SHELL) \ zcat $(l2_bloom_files) | \ abyss-bloom union -v -k$k - \ $(foreach i,$(l2_bloom_files),-) | \ gzip -c > $@.incomplete && \ mv $@.incomplete $@ \ $(END_SHELL) endif #------------------------------------------------------------ # debugging rules #------------------------------------------------------------ debug: @echo 'b=$b' @echo 'b_times_l=$(b_times_l)' @echo 'b_mod_w=$(b_mod_w)' @echo 'b_gb=$(b_gb)' @echo 'l1_mem_gb=$(l1_mem_gb)' @echo 'l2_mem_gb=$(l2_mem_gb)' @echo 'union_mem_gb=$(union_mem_gb)' @echo 'l1_bloom_files="$(l1_bloom_files)"' @echo 'l2_bloom_files="$(l2_bloom_files)"' @echo '$$(call getWindow, $(word 1,$(l1_bloom_files))): $(call getWindow,$(word 1,$(l1_bloom_files)))' @echo '$$(call getReadFilename, $(word 1,$(l1_bloom_files))): $(call getReadFilename,$(word 1,$(l1_bloom_files)))' @echo '$$(call getReadFilePath, $(word 1,$(l1_bloom_files))): $(call getReadFilePath,$(word 1,$(l1_bloom_files)))' @echo '$$(call getSiblingBloomFiles, $(word 1,$(l1_bloom_files))): $(call getSiblingBloomFiles,$(word 1,$(l1_bloom_files)))' abyss-2.2.4/bin/abyss-bowtie000077500000000000000000000021571361462241400157560ustar00rootroot00000000000000#!/bin/bash set -eu case $1 in --help) cat <&2 "abyss-bowtie: invalid option: $OPTARG"; exit 1;; esac done shift $((OPTIND-1)) query=("$@") target=${query[${#query[@]}-1]} unset query[${#query[@]}-1] index=$target.1.ebwt # Build the index. if [ ! -r $index ]; then echo >&2 "Building the index $index..." echo >&2 bowtie-build $target $target bowtie-build $target $target 1>&2 elif [ $index -ot $target ]; then echo >&2 "The index $index is stale. Rebuilding the index..." echo >&2 bowtie-build $target $target bowtie-build $target $target 1>&2 else echo >&2 "The index $index is up to date." fi # Map the reads. echo >&2 $bowtie $target "${query[@]}" exec abyss-tofastq -i "${query[@]}" |$bowtie $target - abyss-2.2.4/bin/abyss-bowtie2000077500000000000000000000022501361462241400160320ustar00rootroot00000000000000#!/bin/bash set -eu case $1 in --help) cat <&2 "abyss-bowtie2: invalid option: $OPTARG" exit 1;; esac done shift $((OPTIND-1)) query=("$@") target=${query[${#query[@]}-1]} unset query[${#query[@]}-1] index=$target.1.bt2 # Build the index. if [ ! -r $index ]; then echo >&2 "Building the index $index..." echo >&2 bowtie2-build $target $target bowtie2-build $target $target 1>&2 elif [ $index -ot $target ]; then echo >&2 "The index $index is stale. Rebuilding the index..." echo >&2 bowtie2-build $target $target bowtie2-build $target $target 1>&2 else echo >&2 "The index $index is up to date." fi # Map the reads. echo >&2 $bowtie2_align $target "${query[@]}" exec abyss-tofastq -i "${query[@]}" |$bowtie2_align $target - abyss-2.2.4/bin/abyss-bwa000077500000000000000000000022701361462241400152320ustar00rootroot00000000000000#!/bin/bash set -eu case $1 in --help) cat <&1 |head -n4 exit ;; esac # Parse the command line. bwa_aln='bwa aln' bwa_index='bwa index -a bwtsw' while getopts :j:l:v opt; do case $opt in j) bwa_aln="$bwa_aln -t$OPTARG";; l) ;; v) ;; \?) echo >&2 "abyss-bwa: invalid option: $OPTARG"; exit 1;; esac done shift $((OPTIND-1)) query=("$@") target=${query[${#query[@]}-1]} unset query[${#query[@]}-1] index=$target.bwt # Build the index. if [ ! -r $index ]; then echo >&2 "Building the index $index..." echo >&2 $bwa_index $target $target $bwa_index $target $target 1>&2 elif [ $index -ot $target ]; then echo >&2 "The index $index is stale. Rebuilding the index..." echo >&2 $bwa_index $target $target $bwa_index $target $target 1>&2 else echo >&2 "The index $index is up to date." fi # Map the reads. echo >&2 $bwa_aln $target "${query[@]}" exec abyss-tofastq -i "${query[@]}" \ |$bwa_aln $target - \ |bwa samse $target - <(abyss-tofastq -i "${query[@]}") abyss-2.2.4/bin/abyss-bwamem000077500000000000000000000026561361462241400157410ustar00rootroot00000000000000#!/bin/bash set -eu case $1 in --help) cat <&1 |head -n4 exit ;; esac # Parse the command line. bwamem='bwa mem' bwa_index='bwa index' while getopts :j:l:v opt; do case $opt in j) bwamem="$bwamem -t$OPTARG";; l) bwamem="$bwamem -k$OPTARG";; v) ;; \?) echo >&2 "abyss-bwamem: invalid option: $OPTARG"; exit 1;; esac done shift $((OPTIND-1)) query=("$@") target=${query[${#query[@]}-1]} unset query[${#query[@]}-1] index=$target.bwt # Build the index. if [ ! -r $index ]; then echo >&2 "Building the index $index..." echo >&2 $bwa_index $target $target $bwa_index $target $target 1>&2 elif [ $index -ot $target ]; then echo >&2 "The index $index is stale. Rebuilding the index..." echo >&2 $bwa_index $target $target $bwa_index $target $target 1>&2 else echo >&2 "The index $index is up to date." fi # Map the reads. echo >&2 $bwamem $target "${query[@]}" #exec $bwamem $target "${query[@]}" | abyss-tofastq -i "${query[@]}" exec abyss-tofastq "${query[@]}" \ |$bwamem $target - \ |awk ' BEGIN { OFS = "\t" } /^@/ { print; next } $1 == x { next } { x = $1 } sub("/1$", "", $1) > 0 { $2 = or($2, 0x41) print; next } sub("/[23]$", "", $1) > 0 { $2 = or($2, 0x81) print; next } { print } ' abyss-2.2.4/bin/abyss-bwasw000077500000000000000000000025221361462241400156040ustar00rootroot00000000000000#!/bin/bash set -eu case $1 in --help) cat <&1 |head -n4 exit ;; esac # Parse the command line. bwasw='bwa bwasw' bwa_index='bwa index -a bwtsw' while getopts :j:l:v opt; do case $opt in j) bwasw="$bwasw -t$OPTARG";; l) ;; v) ;; \?) echo >&2 "abyss-bwasw: invalid option: $OPTARG"; exit 1;; esac done shift $((OPTIND-1)) query=("$@") target=${query[${#query[@]}-1]} unset query[${#query[@]}-1] index=$target.bwt # Build the index. if [ ! -r $index ]; then echo >&2 "Building the index $index..." echo >&2 $bwa_index $target $target $bwa_index $target $target 1>&2 elif [ $index -ot $target ]; then echo >&2 "The index $index is stale. Rebuilding the index..." echo >&2 $bwa_index $target $target $bwa_index $target $target 1>&2 else echo >&2 "The index $index is up to date." fi # Map the reads. echo >&2 $bwasw $target "${query[@]}" exec abyss-tofastq -i "${query[@]}" \ |$bwasw $target - \ |awk ' BEGIN { OFS = "\t" } /^@/ { print; next } $1 == x { next } { x = $1 } sub("/1$", "", $1) > 0 { $2 = or($2, 0x41) print; next } sub("/[23]$", "", $1) > 0 { $2 = or($2, 0x81) print; next } { print } ' abyss-2.2.4/bin/abyss-cstont000077500000000000000000000037211361462241400157750ustar00rootroot00000000000000#!/usr/bin/env perl # Convert colour-space FASTA sequences to nucleotide FASTA sequences. # Written by Shaun Jackman . # Usage: cstofasta data.csfa >data.fa use strict; use Getopt::Long; use Pod::Usage; my %opt; GetOptions(\%opt, qw'help man'); pod2usage(-verbose => 1) if $opt{help}; pod2usage(-verbose => 2) if $opt{man}; my %table = ( 'A' => ['A', 'C', 'G', 'T'], 'C' => ['C', 'A', 'T', 'G'], 'G' => ['G', 'T', 'A', 'C'], 'T' => ['T', 'G', 'C', 'A'] ); sub cs_to_nt($$) { my $seed = shift; my $cs = shift; for (my $i = 0; $i < length $cs; $i++) { my $p = \substr($cs, $i, 1); $$p = $seed = $table{$seed}[$$p]; } return $cs; } my ($id, $comment); while (<>) { chomp; if (/^[ACGT]/) { my $seed = substr $_, 0, 1, ''; print "$id$comment\n", substr(cs_to_nt($seed, $_), 1), "\n"; } elsif (/^[0123]/) { for my $seed (qw'A C G T') { print "${id}_$seed$comment\n$seed", cs_to_nt($seed, $_), "\n"; } } elsif (/^>/) { ($id, $comment) = split ' ', $_, 2; $comment = ' ' . $comment if $comment; } elsif (/^#/) { print "$_\n"; } else { die "error: what is `$_'"; } } =pod =head1 NAME abyss-cstont - convert colour-space FASTA sequences to nucleotide FASTA sequences =head1 SYNOPSIS B F >F =head1 DESCRIPTION Either reads or contigs may be converted from colour-space sequences to nucleotide sequences. If the first character of the input sequence is not a nucleotide, each colour-space contig will be converted to four nucleotide contigs, one for each possible starting nucleotide. =head1 EXAMPLE $ printf '>1\nA0000' |abyss-cstont >1 AAA $ printf '>1\n0000' |abyss-cstont >1_A AAAAA >1_C CCCCC >1_G GGGGG >1_T TTTTT =head1 AUTHOR Written by Shaun Jackman. =head1 REPORTING BUGS Report bugs to . =head1 COPYRIGHT Copyright 2009 Canada's Michael Smith Genome Science Centre =head1 SEE ALSO L http://www.bcgsc.ca/platform/bioinfo/software/abyss abyss-2.2.4/bin/abyss-dida000077500000000000000000000052631361462241400153670ustar00rootroot00000000000000#!/bin/bash set -eu -o pipefail #------------------------------------------------------------ # parse command line options #------------------------------------------------------------ case $1 in --help) cat <&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=($(echo "$@" | xargs -n1 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 abyss-2.2.4/bin/abyss-fac.pl000077500000000000000000000047501361462241400156310ustar00rootroot00000000000000#!/usr/bin/env perl # abyss-fac (FASTA count) # Calculate assembly contiguity statistics, such as N50. # Written by Shaun Jackman . use strict; use Getopt::Std qw'getopts'; $| = 1; my %opt; getopts 'g:hHjt:', \%opt; my $opt_threshold = defined $opt{'t'} ? $opt{'t'} : 200; my $opt_filename = $opt{'H'} || (@ARGV > 1 && !$opt{'h'}); my $opt_jira = $opt{'j'}; my $opt_genome_size = $opt{'g'}; sub eng($) { my $x = shift; return $x if $x < 10000000; return substr($x / 1000000, 0, 5) . 'e6' if $x < 1000000000; return substr($x / 1000000000, 0, 5) . 'e9'; } my ($short, $sum); my @x; sub count($$) { my $id = shift; my $seq = uc shift; my $x = $seq =~ tr/ACGT//; my $colourspace = $seq =~ tr/0123//; die unless $x == 0 || $colourspace == 0; $x = $colourspace if $x == 0; if ($x < $opt_threshold) { $short++; return; } $sum += $x; push @x, $x; } sub fac($) { my $path = shift; $short = $sum = 0; @x = (); my $id; my $seq; open IN, "<$path" or die "$path: $!\n"; while () { chomp; if (/^>/) { count $id, $seq if defined $id; $id = $_; $seq = ''; } else { $seq .= $_; } } count $id, $seq if defined $id; close IN; my $n = @x; if ($n > 0) { @x = sort { $a <=> $b } @x; my $min = $x[0]; my $max = $x[-1]; my $n50_target = defined $opt_genome_size ? $opt_genome_size : $sum; my ($n20, $n20sum, $nn50, $n50, $n50sum, $n80, $n80sum); while (@x > 0 && $n80sum < 0.8 * $n50_target) { my $x = pop @x; if ($n20sum < 0.2 * $n50_target) { $n20 = $x; $n20sum += $x; } if ($n50sum < 0.5 * $n50_target) { $nn50++; $n50 = $x; $n50sum += $x; } if ($n80sum < 0.8 * $n50_target) { $n80 = $x; $n80sum += $x; } } my $ntotal = $short + $n; format Spaces = @<<<<<<<@<<<<<<<@<<<<<<<@<<<<<<<@<<<<<<<@<<<<<<<@<<<<<<<@<<<<<<<@<<<<<<<@* eng($ntotal), eng($n), $nn50, $min, $n80, $n50, $n20, $max, eng($sum), $path . format Pipes = |@<<<<<<|@<<<<<<|@<<<<<<|@<<<<<<|@<<<<<<|@<<<<<<|@<<<<<<|@<<<<<<|@<<<<<<|@*| eng($ntotal), eng($n), $nn50, $min, $n80, $n50, $n20, $max, eng($sum), $path . $~ = $opt_jira ? 'Pipes' : 'Spaces'; $^ = $opt_jira ? 'Pipes_TOP' : 'Spaces_TOP'; write; } else { print STDERR "warning: `$path' is empty\n"; } } format Spaces_TOP = n n:@<<<< L50 min N80 N50 N20 max sum $opt_threshold . format Pipes_TOP = ||n ||n:@<<<||L50 ||min ||N80 ||N50 ||N20 ||max ||sum || $opt_threshold . @ARGV = ('-') if @ARGV == 0; fac $_ foreach @ARGV; abyss-2.2.4/bin/abyss-fatoagp000077500000000000000000000040161361462241400161020ustar00rootroot00000000000000#!/usr/bin/env perl # Convert a FASTA file of scaffolds to a FASTA file of contigs and an # AGP file. # Written by Shaun Jackman . use strict; use Getopt::Std qw'getopts'; my %opt; getopts 'f:s:S:', \%opt; my $opt_fasta = $opt{'f'}; # scaffolds shorter than this length will be excluded my $opt_min_scaf_len = defined $opt{'s'} ? $opt{'s'} : 200; # scaftigs shorter than this length will be masked with "N"s my $opt_min_ctg_len = defined $opt{'S'} ? $opt{'S'} : 50; open FASTA, ">$opt_fasta" or die "error: `$opt_fasta': $!\n" if $opt_fasta; while (<>) { die unless /^>/; chomp; my ($scafid, undef) = split ' ', $_, 2; substr $scafid, 0, 1, ''; my $scafseq = <>; chomp $scafseq; # mask scaftigs shorter than -S threshold with "N"s my @ctgseqs = split /([Nn]+)/, $scafseq; foreach my $ctgseq (@ctgseqs) { next if /^[nN]/; if (length($ctgseq) < $opt_min_ctg_len) { $ctgseq = "N" x length($ctgseq); } } # rejoin and split to merge adjacent stretches of "N"s $scafseq = join '', @ctgseqs; next unless $scafseq =~ /[^nN]/; # trim leading/trailing "N"s that may result # from masking short contigs (-S option) $scafseq =~ s/^[nN]+//g; $scafseq =~ s/[nN]+$//g; # skip scaffold if length less than -s threshold my $scaflen = $scafseq =~ tr/ACGTacgt//; next if $scaflen < $opt_min_scaf_len; @ctgseqs = split /([Nn]+)/, $scafseq; my $i = 0; 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", $x + $len, "\t", $i + 1, "\t"; if ($ctgseq =~ /^[nN]/) { # component_type gap_length gap_type linkage print "N\t", $len, "\tscaffold\tyes\tpaired-ends\n"; } else { my $ctgid = 'contig' . $scafid . '_' . ($i / 2); # component_type component_id # component_beg component_end orientation print "W\t", $ctgid, "\t1\t", $len, "\t+\n"; print FASTA '>', $ctgid, "\n", $ctgseq, "\n" if $opt_fasta; } $i++; $x += $len; } } abyss-2.2.4/bin/abyss-joindist000077500000000000000000000027161361462241400163110ustar00rootroot00000000000000#!/usr/bin/env perl # Join multiple ABySS distance estimate files. # Written by Shaun Jackman . use strict; use Getopt::Long; use Pod::Usage; my %opt; GetOptions(\%opt, qw'help man'); pod2usage(-verbose => 1) if $opt{help}; pod2usage(-verbose => 2) if $opt{man}; my (%id, %a, %b); while (<>) { chomp; my ($id, $rest) = split ' ', $_, 2; my ($a, $b) = split ';', $rest, 2; my @a = split ' ', $a; my @b = split ' ', $b; $id{$id} = 1; for (@a) { my ($to, $d, $n, $sd) = split ','; if (!exists $a{$id}{$to} || $sd < $a{$id}{$to}) { $a{$id}{$to} = "$sd $d $n"; } } for (@b) { my ($to, $d, $n, $sd) = split ','; if (!exists $b{$id}{$to} || $sd < $b{$id}{$to}) { $b{$id}{$to} = "$sd $d $n"; } } } for my $id (sort {$a<=>$b} keys %id) { print $id; for my $to (sort {$a<=>$b} keys %{$a{$id}}) { my ($sd, $d, $n) = split ' ', $a{$id}{$to}; print " $to,$d,$n,$sd"; } print ' ;'; for my $to (sort {$a<=>$b} keys %{$b{$id}}) { my ($sd, $d, $n) = split ' ', $b{$id}{$to}; print " $to,$d,$n,$sd"; } print "\n"; } =pod =head1 NAME abyss-joindist - Join multiple ABySS distance estimate files. =head1 SYNOPSIS B F... >F =head1 AUTHOR Written by Shaun Jackman. =head1 REPORTING BUGS Report bugs to . =head1 COPYRIGHT Copyright 2009 Canada's Michael Smith Genome Science Centre =head1 SEE ALSO L http://www.bcgsc.ca/platform/bioinfo/software/abyss abyss-2.2.4/bin/abyss-kaligner000077500000000000000000000000471361462241400162550ustar00rootroot00000000000000#!/bin/bash set -eu exec KAligner "$@" abyss-2.2.4/bin/abyss-nompi000077500000000000000000000003501361462241400156000ustar00rootroot00000000000000#!/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 abyss-2.2.4/bin/abyss-pe000077500000000000000000000536361361462241400151010ustar00rootroot00000000000000#!/usr/bin/make -rRf # Run the ABySS assembler. # Written by Shaun Jackman and # Anthony Raymond . SHELL=bash -e -o pipefail ifeq ($(shell zsh -e -o pipefail -c 'true' 2>/dev/null; echo $$?), 0) # Set pipefail to ensure that all commands of a pipe succeed. SHELL=zsh -e -o pipefail # Report run time and memory usage with zsh. export REPORTTIME=1 export TIMEFMT=time user=%U system=%S elapsed=%E cpu=%P memory=%M job=%J endif # Record run time and memory usage in a file using GNU time. ifdef time ifneq ($(shell command -v gtime),) gtime=command gtime -v -o $@.time else gtime=command time -v -o $@.time endif endif # Wrapper script for commands that require an increased stack size limit stack=abyss-stack-size 65536 # Define this environment variable on Mac OS X to read # compressed files. export DYLD_FORCE_FLAT_NAMESPACE=1 # Integrate with Sun Grid Engine (SGE) ifdef JOB_NAME name?=$(JOB_NAME) endif ifdef SGE_TASK_ID k?=$(SGE_TASK_ID) endif ifdef NSLOTS ifneq ($(NSLOTS), 1) np?=$(NSLOTS) endif endif # Integrate with Portable Batch System (PBS) ifdef PBS_JOBNAME name?=$(PBS_JOBNAME) endif ifdef PBS_ARRAYID k?=$(PBS_ARRAYID) endif ifdef PBS_NODEFILE NSLOTS=$(shell wc -l <$(PBS_NODEFILE)) ifneq ($(NSLOTS), 1) np?=$(NSLOTS) endif endif # Integrate with Load Sharing Facility (LSF) ifdef LSB_JOBNAME name?=$(LSB_JOBNAME) endif ifdef LSB_JOBINDEX k?=$(LSB_JOBINDEX) endif ifdef LSB_DJOB_NUMPROC ifneq ($(LSB_DJOB_NUMPROC), 1) np?=$(LSB_DJOB_NUMPROC) endif endif ifdef LSF_BINDIR mpirun?=$(LSF_BINDIR)/mpirun.lsf endif # Integrate with IBM LoadLeveler ifdef LOADL_JOB_NAME name?=$(LOADL_JOB_NAME) endif ifdef LOADL_STEP_ID k?=$(LOADL_STEP_ID) endif ifdef LOADL_HOSTFILE NSLOTS=$(shell wc -l <$(LOADL_HOSTFILE)) ifneq ($(NSLOTS), 1) np?=$(NSLOTS) endif endif # Integrate with SLURM ifdef SLURM_JOB_NAME name?=$(SLURM_JOB_NAME) endif ifdef SLURM_ARRAY_TASK_ID k?=$(SLURM_ARRAY_TASK_ID) endif ifdef SLURM_NTASKS np?=$(SLURM_NTASKS) endif # Determine the path to mpirun mpirun?=$(shell command -v mpirun) ifeq ($(mpirun),) mpirun=mpirun endif # Use pigz or bgzip for parallel compression if available. ifneq ($(shell command -v pigz),) gzip=pigz -p$j else ifneq ($(shell command -v bgzip),) gzip=bgzip -@$j else gzip=gzip endif endif ifndef preserve_path # Determine the path to the ABySS executables path?=$(shell dirname `command -v $(MAKEFILE_LIST)`) ifdef path PATH:=$(path):$(PATH) endif endif ifdef db # Determine the location of sqlite database override dbopt:=--db=$(db) # Track data details for database library ?= "" strain ?= "" species ?= "" endif # Programs MARKDOWN=pandoc map=$(foreach a,$(2),$(call $(1),$(a))) deref=$($1) ifdef lr ifndef lib lib:=$(pe) $(lr) endif endif ifdef lib in?=$(call map, deref, $(lib)) else ifdef in lib?=$(name) $(lib)?=$(in) endif endif pe?=$(lib) mp?=$(pe) # Strip spaces from the file paths ifdef in override in:=$(strip $(in)) endif ifdef se override se:=$(strip $(se)) endif ifdef lr override lr_reads=$(strip $(call map, deref, $(lr))) endif # Graph file format graph?=dot # g is private. Use graph instead. override g:=$(graph) # Number of threads ifdef PE_HOSTFILE hostname?=$(shell hostname -f) j?=$(shell awk '$$1 == "$(hostname)" {print $$2}' $(PE_HOSTFILE)) endif ifeq ($j,) j:=$(np) endif ifeq ($j,) j:=2 endif # ABYSS parameters q ?= 3 abyssopt += -k$k -q$q ifdef K abyssopt += -K$K endif ifdef e abyssopt += -e$e endif ifdef E abyssopt += -E$E endif ifdef t abyssopt += -t$t endif ifdef c abyssopt += -c$c endif ifdef kc abyssopt += --kc=$(kc) endif ifdef b abyssopt += -b$b pbopt += -b$b endif ifdef Q abyssopt += -Q$Q endif ifdef ss SS=--SS endif abyssopt += $v # additional params for Bloom filter assembly (`abyss-bloom-dbg`) ifdef B abyssopt += -b$B ifdef H abyssopt += -H$H endif ifdef j abyssopt += -j$j endif ifdef x abyssopt += -s$x endif else abyssopt += $(dbopt) $(SS) --coverage-hist=coverage.hist -s $*-bubbles.fa endif # AdjList parameters m?=0 alopt += $v $(dbopt) $(SS) -k$k -m$m ifndef B ifdef K alopt += -K$K endif endif # filtergraph parameters ifndef B ifdef K fgopt += --assemble --shim-max-degree=2 endif endif ifdef xtip fgopt += -t$(shell echo $k*2 |bc) endif # PopBubbles parameters p?=0.9 pbopt += -p$p ifdef a pbopt += -a$a endif # Keep sequence and quality strings of read alignments ifdef ssq ssq_t :=-ssq endif # Aligner parameters aligner?=map$(ssq_t) ifeq ($(SS),--SS) ifneq ($(aligner),map$(ssq_t)) $(warning warning: setting aligner to abyss-map$(ssq_t) since other aligners do not support ss=1) override aligner=map$(ssq_t) endif endif align?=abyss-$(aligner) 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) fixmate?=ParseAligns else fixmate?=abyss-fixmate$(ssq_t) endif fmopt=$v $(dbopt) -l$($*_l) $(FIXMATE_OPTIONS) # DistanceEst parameters DistanceEst?=DistanceEst$(ssq_t) l?=40 s?=1000 n?=10 $(foreach i,$(pe),$(eval $i_l?=$l)) $(foreach i,$(pe),$(eval $i_s?=$s)) $(foreach i,$(pe),$(eval $i_n?=$n)) override deopt=$v $(dbopt) -j$j -k$k $(DISTANCEEST_OPTIONS) -l$($*_l) -s$($*_s) -n$($*_n) $($*_de) # SimpleGraph parameters sgopt += $(dbopt) -s$s -n$n ifdef d sgopt += -d$d endif # MergePaths parameters mpopt += $v $(dbopt) -j$j -k$k -s$s ifdef G mpopt += -G$G endif # 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 L?=$l S?=1000-10000 N?=$n SCAFFOLD_DE_S?=$(shell echo $S | sed 's/-.*//') SCAFFOLD_DE_N?=$N SCAFFOLD_DE_OPTIONS?=$(DISTANCEEST_OPTIONS) $(foreach i,$(mp),$(eval $i_l?=$L)) $(foreach i,$(mp),$(eval $i_s?=$(SCAFFOLD_DE_S))) $(foreach i,$(mp),$(eval $i_n?=$(SCAFFOLD_DE_N))) override scaffold_deopt=$v $(dbopt) --dot --median -j$j -k$k $(SCAFFOLD_DE_OPTIONS) -l$($*_l) -s$($*_s) -n$($*_n) $($*_de) scopt += $v $(dbopt) $(SS) -k$k ifdef G scopt += -G$G endif # abyss-fac parameters ifdef G override facopt = -G$G endif # BWA-SW parameters bwaswopt=-t$j BWASW_OPTIONS='-b9 -q16 -r1 -w500' # Remove environment variables unexport in se $(lib) $(pe) $(mp) $(long) # Check the mandatory parameters ifndef name error:: @>&2 echo 'abyss-pe: missing parameter `name`' endif ifndef k error:: @>&2 echo 'abyss-pe: missing parameter `k`' endif ifeq ($(lib)$(in)$(se)$(lr),) error:: @>&2 echo 'abyss-pe: missing parameter `lib`, `in`, `se`, or `lr`' endif default: error:: @>&2 echo 'Try `abyss-pe help` for more information.' @false # Help and version messages help: @echo 'Usage: abyss-pe [OPTION]... [PARAMETER=VALUE]... [COMMAND]...' @echo 'Assemble reads into contigs and scaffolds. ABySS is a de novo' @echo 'sequence assembler intended for short paired-end reads and large' @echo 'genomes. See the abyss-pe man page for documentation of assembly' @echo 'parameters and commands. abyss-pe is a Makefile script, and so' @echo 'options of `make` may also be used with abyss-pe. See the `make`' @echo 'man page for documentation.' @echo @echo 'Report bugs to https://github.com/bcgsc/abyss/issues or abyss-users@bcgsc.ca.' version: @echo "abyss-pe (ABySS) 2.2.4" @echo "Written by Shaun Jackman and Anthony Raymond." @echo @echo "Copyright 2012 Canada's Michael Smith Genome Science Centre" versions: version @echo PATH=$(PATH) @ABYSS --version; echo @-ABYSS-P --version; echo @AdjList --version; echo @DistanceEst --version; echo @MergeContigs --version; echo @MergePaths --version; echo @Overlap --version; echo @PathConsensus --version; echo @PathOverlap --version; echo @PopBubbles --version; echo @SimpleGraph --version; echo @abyss-fac --version; echo @abyss-filtergraph --version; echo @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 @sort --version; echo @-mpirun --version # Determine the default target ifdef db default: startDb endif default: unitigs ifneq ($(in),) default: contigs contigs-graph endif ifneq ($(mp),) default: scaffolds scaffolds-graph ifneq ($(long),) 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-graph: $(name)-unitigs.$g pe-index: $(name)-3.fa.fm pe-sam: $(addsuffix -3.sam.gz, $(pe)) pe-bam: $(addsuffix -3.bam.bai, $(pe)) contigs: $(name)-contigs.fa contigs-graph: $(name)-contigs.$g mp-index: $(name)-6.fa.fm mp-sam: $(addsuffix -6.sam.gz, $(mp)) mp-bam: $(addsuffix -6.bam.bai, $(mp)) scaffolds: $(name)-scaffolds.fa 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-graph: $(name)-long-scaffs.$g all: default bam stats clean: 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-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 $< %.bam: %.sam.gz samtools view -Sb $< -o $@ %.bam.bai: %.bam samtools index $< # 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 B %-1.fa: $(gtime) $(stack) abyss-bloom-dbg $(abyssopt) $(ABYSS_OPTIONS) $(in) $(se) > $@ else ifdef K ifdef np %-1.fa: $(gtime) $(mpirun) -np $(np) abyss-paired-dbg-mpi $(abyssopt) $(ABYSS_OPTIONS) -o $*-1.fa $(in) $(se) else %-1.fa %-1.$g: $(gtime) abyss-paired-dbg $(abyssopt) $(ABYSS_OPTIONS) -o $*-1.fa -g $*-1.$g $(in) $(se) endif else ifdef np %-1.fa: $(gtime) $(mpirun) -np $(np) ABYSS-P $(abyssopt) $(ABYSS_OPTIONS) -o $@ $(in) $(se) else %-1.fa: $(gtime) ABYSS $(abyssopt) $(ABYSS_OPTIONS) -o $@ $(in) $(se) endif # Find overlapping contigs %-1.$g: %-1.fa $(gtime) AdjList $(alopt) --$g $< >$@ # Remove shim contigs %-2.$g1 %-1.path: %-1.$g %-1.fa $(gtime) abyss-filtergraph $v --$g $(fgopt) $(FILTERGRAPH_OPTIONS) -k$k -g $*-2.$g1 $^ >$*-1.path %-2.fa %-2.$g: %-1.fa %-2.$g1 %-1.path $(gtime) MergeContigs --$g $(mcopt) -g $*-2.$g -o $*-2.fa $^ # Pop bubbles %-2.path %-3.$g: %-2.fa %-2.$g $(gtime) PopBubbles $v --$g -j$j -k$k $(SS) $(pbopt) $(POPBUBBLES_OPTIONS) -g $*-3.$g $^ >$*-2.path %-3.fa: %-2.fa %-2.$g %-2.path $(gtime) MergeContigs $(mcopt) -o $@ $^ awk '!/^>/ {x[">" $$1]=1; next} {getline s} $$1 in x {print $$0 "\n" s}' \ $*-2.path $*-1.fa >$*-indel.fa %-unitigs.fa: %-3.fa ln -sf $< $@ %-unitigs.$g: %-3.$g ln -sf $< $@ # Estimate distances between unitigs %-3.sam.gz %-3.hist: $(name)-3.fa $(gtime) $(align) $(mapopt) $(strip $($*)) $< \ |$(fixmate) $(fmopt) -h $*-3.hist \ |sort -snk3 -k4 \ |$(gzip) >$*-3.sam.gz %-3.bam %-3.hist: $(name)-3.fa $(gtime) $(align) $(mapopt) $(strip $($*)) $< \ |$(fixmate) $(fmopt) -h $*-3.hist \ |sort -snk3 -k4 \ |samtools view -Sb - -o $*-3.bam %-3.dist: %-3.sam.gz %-3.hist gunzip -c $< \ |$(gtime) $(DistanceEst) $(deopt) -o $@ $*-3.hist %-3.dist: %-3.bam %-3.hist $(gtime) samtools view -h $< \ |$(DistanceEst) $(deopt) -o $@ $*-3.hist %-3.dist: $(name)-3.fa $(gtime) $(align) $(mapopt) $(strip $($*)) $< \ |$(fixmate) $(fmopt) -h $*-3.hist \ |sort -snk3 -k4 \ |$(DistanceEst) $(deopt) -o $@ $*-3.hist dist=$(addsuffix -3.dist, $(pe)) ifneq ($(name)-3.dist, $(dist)) $(name)-3.dist: $(name)-3.fa $(dist) $(gtime) abyss-todot $v --dist -e $^ >$@ $(name)-3.bam: $(addsuffix -3.bam, $(pe)) $(gtime) samtools merge -r $@ $^ endif # Find overlaps between contigs %-4.fa %-4.$g: %-3.fa %-3.$g %-3.dist $(gtime) Overlap $v --$g $(SS) $(OVERLAP_OPTIONS) -k$k -g $*-4.$g -o $*-4.fa $^ # Assemble contigs %-4.path1: %-4.$g %-3.dist $(gtime) $(stack) SimpleGraph $v $(sgopt) $(SIMPLEGRAPH_OPTIONS) -j$j -k$k -o $@ $^ %-4.path2: %-4.path1 %-3.fa.fai %-4.fa.fai cat $*-3.fa.fai $*-4.fa.fai \ |$(gtime) MergePaths $(mpopt) $(MERGEPATHS_OPTIONS) -o $@ - $< %-4.path3: %-4.$g %-4.path2 PathOverlap --assemble $(poopt) $(SS) $^ >$@ ifndef cs %-5.path %-5.fa %-5.$g: %-3.fa %-4.fa %-4.$g %-4.path3 cat $(wordlist 1, 2, $^) \ |$(gtime) $(stack) PathConsensus $v --$g -k$k $(pcopt) $(PATHCONSENSUS_OPTIONS) -o $*-5.path -s $*-5.fa -g $*-5.$g - $(wordlist 3, 4, $^) %-6.fa: %-3.fa %-4.fa %-5.fa %-5.$g %-5.path cat $(wordlist 1, 3, $^) |$(gtime) MergeContigs $(mcopt) -o $@ - $(wordlist 4, 5, $^) else %-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.$g %-4.path3 cat $(wordlist 1, 2, $^) |$(gtime) MergeContigs $(mcopt) -o $@ - $(wordlist 3, 4, $^) # Convert colour-space sequence to nucleotides %-6.fa: %-cs.fa $(gtime) KAligner $v --seq -m -j$j -l$l $(in) $(se) $< \ |Consensus $v -o $@ $< endif %-6.$g: %-5.$g %-5.path $(gtime) PathOverlap --overlap $(poopt) --$g $^ >$@ %-contigs.fa: %-6.fa ln -sf $< $@ %-contigs.$g: %-6.$g ln -sf $< $@ # Estimate distances between contigs %-6.sam.gz %-6.hist: $(name)-6.fa $(gtime) $(align) $(mapopt) $(strip $($*)) $< \ |$(fixmate) $(fmopt) -h $*-6.hist \ |sort -snk3 -k4 \ |$(gzip) >$*-6.sam.gz %-6.bam %-6.hist: $(name)-6.fa $(gtime) $(align) $(mapopt) $(strip $($*)) $< \ |$(fixmate) $(fmopt) -h $*-6.hist \ |sort -snk3 -k4 \ |samtools view -Sb - -o $*-6.bam %-6.dist.dot: %-6.sam.gz %-6.hist gunzip -c $< \ |$(gtime) $(DistanceEst) $(scaffold_deopt) -o $@ $*-6.hist %-6.dist.dot: %-6.bam %-6.hist samtools view -h $< \ |$(gtime) $(DistanceEst) $(scaffold_deopt) -o $@ $*-6.hist %-6.dist.dot: $(name)-6.fa $(gtime) $(align) $(mapopt) $(strip $($*)) $< \ |$(fixmate) $(fmopt) -h $*-6.hist \ |sort -snk3 -k4 \ |$(DistanceEst) $(scaffold_deopt) -o $@ $*-6.hist # Scaffold %-6.path: $(name)-6.$g $(addsuffix -6.dist.dot, $(mp)) $(gtime) abyss-scaffold $(scopt) -s$S -n$N -g $@.dot $(SCAFFOLD_OPTIONS) $^ >$@ %-7.path %-7.$g %-7.fa: %-6.fa %-6.$g %-6.path $(gtime) $(stack) PathConsensus $v --$g -k$k $(pcopt) $(PATHCONSENSUS_OPTIONS) -s $*-7.fa -g $*-7.$g -o $*-7.path $^ %-8.fa: %-6.fa %-7.fa %-7.$g %-7.path cat $(wordlist 1, 2, $^) \ |$(gtime) MergeContigs $(mcopt) -o $@ - $(wordlist 3, 4, $^) %-8.$g: %-7.$g %-7.path $(gtime) PathOverlap --overlap $(poopt) --$g $^ >$@ # Scaffold using linked reads ifdef lr # Tigmint # Options for mapping the reads to the draft assembly. lr_l?=$l override lrmapopt=$v -j$j -l$(lr_l) $(LR_MAP_OPTIONS) # Options for abyss-scaffold lr_s?=1000-100000 lr_n?=5-20 # Minimum AS/Read length ratio tigmint_as?=0.65 # Maximum number of mismatches tigmint_nm?=5 # Minimum mapping quality threshold tigmint_mapq?=0 # Maximum distance between reads to be considered the same molecule tigmint_d?=50000 # Minimum number of spanning molecules tigmint_n?=10 # Size of the window that must be spanned by moecules tigmint_w?=1000 # Align paired-end reads to the draft genome, sort by BX tag, # and create molecule extents BED. %.lr.bed: %.fa.fai $(gtime) $(align) $(lrmapopt) $(lr_reads) $*.fa \ | samtools sort -@$j -tBX -l0 -T$$(mktemp -u -t $@.XXXXXX) \ | tigmint-molecule -a $(tigmint_as) -n $(tigmint_nm) -q $(tigmint_mapq) -d $(tigmint_d) - \ | sort -k1,1 -k2,2n -k3,3n >$@ # Align paired-end reads to the draft genome and sort by BX tag. %.lr.sortbx.bam: %.fa.fai $(gtime) $(align) $(lrmapopt) $(lr_reads) $*.fa \ | samtools sort -@$j -tBX -T$$(mktemp -u -t $@.XXXXXX) -o $@ # Filter the BAM file, create molecule extents BED. %.lr.bed: %.lr.sortbx.bam $(gtime) tigmint-molecule -a $(tigmint_as) -n $(tigmint_nm) -q $(tigmint_mapq) -d $(tigmint_d) $< \ | sort -k1,1 -k2,2n -k3,3n >$@ # Cut sequences at assembly errors. %.tigmint.fa: %.lr.bed %.fa %.fa.fai $(gtime) tigmint-cut -p$j -n$(tigmint_n) -w$(tigmint_w) -o $@ $*.fa $< # ARCS arcs_c?=2 arcs_d?=0 arcs_e?=30000 arcs_l?=0 arcs_m?=4-20000 arcs_r?=0.05 arcs_s?=98 arcs_z?=500 # Align reads and create a graph of linked contigs using ARCS. %.arcs.dist.gv: %.fa $(gtime) $(align) $(lrmapopt) $(lr_reads) $< \ | abyss-fixmate-ssq --all --qname $v -l$(lr_l) $(FIXMATE_OPTIONS) \ | arcs $v -c$(arcs_c) -d$(arcs_d) -e$(arcs_e) -l$(arcs_l) -m$(arcs_m) -r$(arcs_r) -s$(arcs_s) -z$(arcs_z) \ -g $*.arcs.dist.gv --tsv=$*.arcs.tsv --barcode-counts=$*.arcs.barcode-counts.tsv /dev/stdin # Align paired-end reads to the draft genome and do not sort. %.lr.sortn.sam.gz: %.fa $(gtime) $(align) $(lrmapopt) $(lr_reads) $< \ | abyss-fixmate-ssq --all --qname $v -l$(lr_l) $(FIXMATE_OPTIONS) \ | $(gzip) >$@ # Create a graph of linked contigs using ARCS. %.arcs.dist.gv: %.lr.sortn.sam.gz gunzip -c $< \ |$(gtime) arcs $v -c$(arcs_c) -d$(arcs_d) -e$(arcs_e) -l$(arcs_l) -m$(arcs_m) -r$(arcs_r) -s$(arcs_s) -z$(arcs_z) \ -g $*.arcs.dist.gv --tsv=$*.arcs.tsv --barcode-counts=$*.arcs.barcode-counts.tsv /dev/stdin # Scaffold using ARCS and abyss-scaffold. %.arcs.path: %.arcs.dist.gv $(gtime) abyss-scaffold $(scopt) -s$(lr_s) -n$(lr_n) -g $@.dot $(LR_SCAFFOLD_OPTIONS) $< >$@ # Create the FASTA file of ARCS scaffolds. %.arcs.fa: %.fa %.arcs.path $(gtime) MergeContigs $(mcopt) -o $@ $^ %-scaffolds.fa: %-8.tigmint.arcs.fa ln -sf $< $@ else %-scaffolds.fa: %-8.fa ln -sf $< $@ endif %-scaffolds.$g: %-8.$g ln -sf $< $@ # Sealed Scaffold sealer_ks?=-k90 -k80 -k70 -k60 -k50 -k40 -k30 %-8_scaffold.fa: %-8.fa $(gtime) 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 ln -sf $< $@ %-scaftigs.agp: %-scaffolds.agp ln -sf $< $@ # Transcriptome assisted scaffolding %.fa.bwt: %.fa $(gtime) bwa index $< %-8.sam.gz: $(name)-8.fa.bwt $(gtime) bwa mem -a -t$j -S -P -k$l $(name)-8.fa $(strip $($*)) \ |$(gzip) >$@ %-8.dist.dot: %-8.sam.gz $(gtime) abyss-longseqdist -k$k $(LONGSEQDIST_OPTIONS) $< \ |grep -v "l=" >$@ %-8.path: $(name)-8.$g $(addsuffix -8.dist.dot, $(long)) $(gtime) abyss-scaffold $(scopt) -s$S -n1 -g $@.$g $(SCAFFOLD_OPTIONS) $^ >$@ %-9.path %-9.$g %-9.fa: %-8.fa %-8.$g %-8.path $(gtime) $(stack) PathConsensus $v --$g -k$k $(pcopt) $(PATHCONSENSUS_OPTIONS) -s $*-9.fa -g $*-9.$g -o $*-9.path $^ %-10.fa: %-8.fa %-9.fa %-9.$g %-9.path cat $(wordlist 1, 2, $^) \ |$(gtime) MergeContigs $(mcopt) -o $@ - $(wordlist 3, 4, $^) %-10.$g: %-9.$g %-9.path $(gtime) PathOverlap --overlap $(poopt) --$g $^ >$@ %-long-scaffs.fa: %-10.fa ln -sf $< $@ %-long-scaffs.$g: %-10.$g ln -sf $< $@ ifdef db finishDb: @rm -f db.txt endif # Create the final BAM file ifneq ($(mp),) bam: $(name)-scaffolds.bam.bai else ifneq ($(in),) bam: $(name)-contigs.bam.bai else bam: $(name)-unitigs.bam.bai endif endif $(name)-unitigs.bam: %.bam: %.fa $(gtime) $(align) $v -j$j -l$l $(ALIGNER_OPTIONS) $(se) $< \ |samtools view -Su - |samtools sort -o - - >$@ $(name)-contigs.bam $(name)-scaffolds.bam: %.bam: %.fa $(gtime) $(align) $v -j$j -l$l $(ALIGNER_OPTIONS) \ $(call map, deref, $(sort $(lib) $(pe) $(mp))) $< \ |$(fixmate) $v $(FIXMATE_OPTIONS) \ |sort -snk3 -k4 \ |samtools view -Sb - >$@ # Align the variants to the assembly %-variants.bam: %.fa.bwt $(gtime) bwa bwasw -t$j $*.fa <(cat $(name)-bubbles.fa $(name)-indel.fa) \ |samtools view -Su - |samtools sort -o - - >$@ %-variants.vcf.gz: %.fa %-variants.bam $(gtime) samtools mpileup -Buf $^ |bcftools view -vp1 - |bgzip >$@ %.gz.tbi: %.gz $(gtime) tabix -pvcf $< # Calculate assembly contiguity statistics stats: $(name)-stats.tab $(name)-stats $(name)-stats.csv $(name)-stats.md ifneq ($(shell command -v $(MARKDOWN)),) stats: $(name)-stats.html endif %-stats: %-stats.tab ln -sf $< $@ $(name)-stats.tab: %-stats.tab: %-unitigs.fa ifneq ($(in),) $(name)-stats.tab: %-stats.tab: %-contigs.fa endif ifneq ($(mp),) $(name)-stats.tab: %-stats.tab: %-scaffolds.fa endif ifneq ($(long),) $(name)-stats.tab: %-stats.tab: %-long-scaffs.fa endif $(name)-stats.tab: abyss-fac $(facopt) $(FAC_OPTIONS) $^ |tee $@ %.csv: %.tab tr '\t' , <$< >$@ %.md: %.tab abyss-tabtomd $< >$@ %.html: %.md $(MARKDOWN) $< >$@ # Create an AGP file and FASTA file of scaftigs from scaffolds %.agp %-agp.fa: %.fa $(gtime) abyss-fatoagp $(FATOAGP_OPTIONS) -f $*-agp.fa $< >$*.agp # Align the contigs to the reference %-$(ref).sam.gz: %.fa $(gtime) bwa bwasw $(bwaswopt) $(BWASW_OPTIONS) $($(ref)) $< |$(gzip) >$@ # Find breakpoints in the alignments %.break: %.sam.gz $(gtime) abyss-samtobreak $(SAMTOBREAK_OPTIONS) $< >$@ # Report ABySS configuration variable(s) and value(s) currently set. override varList := a b c d e E G j k l m n N p q s S t v cs pi \ np pe lib mp se SS hostname xtip \ ssq ssq_ti path name in mpirun \ aligner long ref fixmate DistanceEst \ map deref abyssopt fgopt pbopt \ align mapopt fmopt deopt \ pcopt sgopt bwaswopt \ ABYSS_OPTIONS FILTERGRAPH_OPTIONS POPBUBBLES_OPTIONS \ OVERLAP_OPTIONS SIMPLEGRAPH_OPTIONS MERGEPATHS_OPTIONS \ SCAFFOLD_OPTIONS ALIGNER_OPTIONS MAP_OPTIONS FAC_OPTIONS \ FIXMATE_OPTIONS BWASW_OPTIONS FATOAGP_OPTIONS SAMTOBREAK_OPTIONS \ MARKDOWN env: @echo 'List of ABySS configuration variables currently set:' @echo '[environment], if variable was inherited from the environment.' @echo '[command line], if variable was defined on the command line.' @echo '[file], if variable was defined in (this) makefile.' @echo '[override], if variable was defined with an override directive in (this) makefile.' @$(foreach var,$(varList),\ echo -e $(var)" = "$($(var))"\t["$(origin $(var))"]";) abyss-2.2.4/bin/abyss-samtoafg000077500000000000000000000106311361462241400162620ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use Getopt::Long; use Pod::Usage; sub version { print < \$opt_eid, 'iid|i=s' => \$opt_iid, 'mean|m=i' => \$opt_mean, 'sd|s=i' => \$opt_sd, 'help' => sub { pod2usage(-verbose => 1) }, 'man' => sub { pod2usage(-verbose => 2) }, 'version' => \&version); for (@ARGV) { die "cannot read `$_'" unless $_ eq '-' || -r } # Output the library record (LIB). print "{LIB\neid:$opt_eid\niid:$opt_iid\n"; print "{DST\nmea:$opt_mean\nstd:$opt_sd\n}\n" if defined $opt_mean && defined $opt_sd; print "}\n"; sub getMateID($) { my $id = shift; return $id =~ s%/1$%/2% || $id =~ s%/2$%/1% ? $id : undef; } my ($g_red_iid, $g_frg_iid, @ctg_eids, @ctg_seqs, %reds, %frgs, %tles); # Output a read (RED) and possibly a fragment (FRG). sub createRead($$$) { my ($eid, $seq, $qlt) = @_; die "error: duplicate sequence ID `$eid'" if exists $reds{$eid}; my $red_iid = ++$g_red_iid; (my $frg_eid = $eid) =~ s/\/[12]$//; my ($my_frg_iid, $mate_iid); if (exists $frgs{$frg_eid}) { $my_frg_iid = delete $frgs{$frg_eid}; my $mate_eid = getMateID($eid); die unless defined $mate_eid; $mate_iid = delete $reds{$mate_eid}; die unless defined $mate_iid; } else { $my_frg_iid = $frgs{$frg_eid} = ++$g_frg_iid; $reds{$eid} = $red_iid; } # Output a read (RED) record. my $qlength = length $seq; print "{RED\nclr:0,$qlength\niid:$red_iid\neid:$eid\n", "frg:$my_frg_iid\n", "seq:\n$seq\n.\nqlt:\n$qlt\n.\n}\n"; # Output a fragment (FRG) record. if (defined $mate_iid) { print "{FRG\nrds:$mate_iid,$red_iid\nlib:$opt_iid\n", "eid:$frg_eid\niid:$my_frg_iid\ntyp:I\n}\n"; } return $red_iid; } # Return the left and right soft clipping of this CIGAR string. sub parseCigar($) { my $cigar = shift; my $clipLeft = $cigar =~ /^([0-9]+)S/ ? $1 : 0; my $clipRight = $cigar =~ /([0-9]+)S$/ ? $1 : 0; return ($clipLeft, $clipRight); } # Record the alignment (TLE) records. while (<>) { chomp; next if /^#/ || /^@/; if (/^>([^ ]+)/) { my $eid = $1; chomp (my $seq = <>); push @ctg_eids, $eid; push @ctg_seqs, $seq; next; } my ($qid, $flag, $tid, $tstart, $mapq, $cigar, $rnext, $pnext, $tlen, $qseq, $qqual) = split '\t'; die unless defined $qqual; $tstart--; # convert to zero-based coordinate next if $flag & 0x100; # secondary alignment $qid .= "/1" if $flag & 0x40; #FREAD1 $qid .= "/2" if $flag & 0x80; #FREAD2 my $rc = $flag & 0x10; #FREVERSE if ($rc) { # Reverse and complement the sequence. $qseq =~ tr/ACGTacgt/TGCAtgca/; $qseq = reverse $qseq; $qqual = reverse $qqual; } my $riid = createRead($qid, $qseq, $qqual); next if $flag & 0x4; #FUNMAP my $qlength = length $qseq; die if length $qqual != $qlength; my ($qstart, $clipRight) = parseCigar($cigar); my $qend = $qlength - $clipRight; die unless $qstart < $qend; my $clr = $rc ? "$qend,$qstart" : "$qstart,$qend"; $tles{$tid} .= "{TLE\nclr:$clr\noff:$tstart\nsrc:$riid\n}\n"; } # Output the contig (CTG) and alignment (TLE) records. my $ctg_iid = 0; for my $ctg_eid (@ctg_eids) { my $seq = shift @ctg_seqs; next if length $tles{$ctg_eid} == 0; # Split long lines. my $qlt = 'I' x (length $seq); $seq =~ s/.{60}/$&\n/sg; $qlt =~ s/.{60}/$&\n/sg; # Contig sequence. $ctg_iid++; print "{CTG\niid:$ctg_iid\n", "eid:$ctg_eid\n", "seq:\n", $seq, "\n.\n", "qlt:\n", $qlt, "\n.\n"; print $tles{$ctg_eid}; print "}\n"; } =pod =head1 NAME abyss-samtoafg - create an AMOS AFG file from a SAM file =head1 SYNOPSIS B F F >F B B<-cb> F B<-m> F B F =head1 DESCRIPTION Create an AMOS AFG file from a FASTA file and a SAM file. =head1 OPTIONS =over =item B<-e>,B<--eid> the EID of the library =item B<-i>,B<--iid> the IID of the library =item B<-m>,B<--mean> the mean of the fragment-size =item B<-s>,B<--sd> the standard deviation of the fragment-size =back =head1 AUTHOR Written by Shaun Jackman. =head1 REPORTING BUGS Report bugs to . =head1 COPYRIGHT Copyright 2012 Canada's Michael Smith Genome Science Centre =head1 SEE ALSO http://www.bcgsc.ca/platform/bioinfo/software/abyss http://amos.sourceforge.net/hawkeye abyss-2.2.4/bin/abyss-stack-size000077500000000000000000000012371361462241400165400ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ]; then echo "Usage: $(basename $0) " >&2 echo "Run COMMAND in a shell with a maximum stack size of" >&2 echo "at least STACK_SIZE in kilobytes." >&2 exit 1 fi min_stack=$1; shift # Note: A max stack size of "unlimited" may not actually # be unlimited. For example, on Linux, using "unlimited" # results in a max stack size of 2 MB, which # is less than the default max stack size of 8 MB. # How confusing! stack=$(ulimit -s) if [ "$stack" = "unlimited" ] || [ "$stack" -lt "$min_stack" ]; then ulimit -s $min_stack fi stack=$(ulimit -s) echo "Running with max stack size of $stack KB: $*" >&2 exec /bin/sh -c "$*" abyss-2.2.4/bin/abyss-tabtomd000077500000000000000000000003211361462241400161060ustar00rootroot00000000000000#!/bin/sh set -eu exec awk ' BEGIN { FS = "\t"; OFS = "\t|" } { $1 = $1; print } NR == 1 { printf "%s", "---" for (i = 1; i < NF; ++i) printf "%s", OFS "---" print "" } ' "$@" |column -ts"$(printf '\t')" abyss-2.2.4/configure.ac000066400000000000000000000232221361462241400151320ustar00rootroot00000000000000AC_PREREQ(2.62) AC_INIT(ABySS, 2.2.4, abyss-users@bcgsc.ca, abyss, http://www.bcgsc.ca/platform/bioinfo/software/abyss) AC_CONFIG_MACRO_DIR([m4]) m4_include(m4/m4_ax_pthread.m4) m4_include([m4/ax_cxx_compile_stdcxx.m4]) AX_CXX_COMPILE_STDCXX(11, noext, mandatory) AM_INIT_AUTOMAKE(1.9.6 foreign subdir-objects) AC_CONFIG_SRCDIR([ABYSS/abyss.cc]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AC_PROG_INSTALL AC_PROG_RANLIB AC_CHECK_TOOL(GHC, ghc) AM_CONDITIONAL([HAVE_GHC], ["$GHC" --version]) 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 \ stddef.h stdint.h stdlib.h sys/param.h]) AC_HEADER_STDBOOL AC_HEADER_STDC # Checks for typedefs, structures, and compiler characteristics. AC_C_BIGENDIAN AC_C_CONST AC_C_INLINE AC_CHECK_TYPES([ptrdiff_t]) AC_TYPE_MODE_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_INT64_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T # Check for std::hash and std::tr1::hash. AC_LANG_PUSH([C++]) AC_CHECK_TYPE([std::hash], AC_DEFINE(HAVE_STD_HASH, [1], [Define if the system provides std::hash]), [], [ #ifdef __FUJITSU #include #else #include #endif]) AC_CHECK_TYPE([std::tr1::hash], AC_DEFINE(HAVE_STD_TR1_HASH, [1], [Define if the system provides std::tr1::hash]), [], [#include ]) AC_CHECK_TYPE([std::tr1::tuple], AC_DEFINE(HAVE_STD_TR1_TUPLE, [1], [Define if the system provides std::tr1::tuple]), [], [#include ]) if test "x$ac_cv_type_std__tr1__tuple_int_" = "xyes"; then # Avoid double-declaration of std::tr1::tuple by boost. # See http://stackoverflow.com/questions/1156003/c-namespace-collision-with-gtest-and-boost # for explanation. AC_DEFINE(BOOST_HAS_TR1_TUPLE, [1], [Define to disable declaration of std::tr1::tuple by boost]) fi AM_CONDITIONAL([HAVE_TR1_TUPLE], [test x"$ac_cv_type_std__tr1__tuple_int_" = x"yes"]) AC_LANG_POP([C++]) # Checks for library functions. AC_CHECK_FUNCS([dup2 gethostname getopt_long getpagesize \ memset strdup strerror strtoul]) AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_REALLOC AC_FUNC_SETVBUF_REVERSED AC_FUNC_VPRINTF # Checks for library constants. AC_CHECK_DECL(HOST_NAME_MAX, [], AC_DEFINE(HOST_NAME_MAX, [_POSIX_HOST_NAME_MAX], [Define if the system does not provide HOST_NAME_MAX]), [#include ]) # Options to configure. # Boost 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 -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" 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], [use MPICH (default is to use Open MPI)])) 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" if test -d "$with_sqlite/lib64"; then sqlite_ldflags="-L$with_sqlite/lib64 -lsqlite3" else sqlite_ldflags="-L$with_sqlite/lib -lsqlite3" fi fi # SparseHash AC_ARG_WITH(sparsehash, AS_HELP_STRING([--with-sparsehash=PATH], [specify prefix directory for the installed sparsehash 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]) 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 128)]), [], [enable_maxk=128]) AC_DEFINE_UNQUOTED(MAX_KMER, [$enable_maxk], [maximum k-mer length]) AC_ARG_ENABLE(max-hashes, AS_HELP_STRING([--enable-max-hashes], [set the maximum number of Bloom filter hash functions (default is 32)]), [], [enable_max_hashes=32]) AC_DEFINE_UNQUOTED(MAX_HASHES, [$enable_max_hashes], [maximum Bloom filter hash functions]) # Find the absolute path to the source. my_abs_srcdir=$(cd $srcdir; pwd) # Set compiler flags. boost_ver=1.56.0 boost_ver_dir=boost_1_56_0 AC_SUBST(CPPFLAGS, "-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" AC_DEFINE(MPICH_SKIP_MPICXX, 1, [Define to disable MPICH C++ bindings]) AC_DEFINE(OMPI_SKIP_MPICXX, 1, [Define to disable OpenMPI C++ bindings]) AC_CHECK_HEADERS([mpi.h]) if test "$enable_mpich"; then AC_CHECK_LIB([pthread], [pthread_create]) AC_CHECK_LIB([mpl], [MPL_env2int]) AC_CHECK_LIB([mpich], [MPI_Init]) ac_cv_lib_mpi_MPI_Init=$ac_cv_lib_mpich_MPI_Init elif test "$enable_lammpi"; then AC_CHECK_LIB([pthread], [pthread_create]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([lam], [lam_mutex_lock]) AC_CHECK_LIB([mpi], [MPI_Init]) AC_LANG_PUSH([C++]) AC_CHECK_LIB([lammpi++], [main]) AC_LANG_POP([C++]) else AC_CHECK_LIB([mpi], [MPI_Init]) fi AM_CONDITIONAL([HAVE_LIBMPI], [test $ac_cv_header_mpi_h = yes -a $ac_cv_lib_mpi_MPI_Init = yes]) AC_SUBST(MPI_LIBS, "$LIBS") LIBS="$libs" # Check for the math library. AC_CHECK_LIB([m], [sqrt]) AC_CHECK_FUNCS([pow sqrt]) AC_CHECK_FUNC(ceilf, [], AC_DEFINE(ceilf, [ceil], [Define if the system does not provide ceilf])) # Check for the dynamic linking library. AC_CHECK_LIB([dl], [dlsym]) # Check for popcnt instruction. AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ], [uint64_t x = 0;]], [[__asm__("popcnt %1,%0" : "=r" (x) : "r" (x));]])], [AC_DEFINE([HAVE_POPCNT], 1, [Define to 1 if you have popcnt.])], [AC_DEFINE([HAVE_POPCNT], 0, [Define to 0 if you do not have popcnt.])]) # Check for the hash table implementation. AC_LANG([C++]) AC_CHECK_HEADERS([ \ functional \ tr1/functional \ boost/functional/hash.hpp \ boost/property_map/property_map.hpp \ google/sparse_hash_map \ unordered_map tr1/unordered_map \ unordered_set tr1/unordered_set \ boost/unordered_set.hpp \ ]) # Check for Boost. if test $ac_cv_header_boost_property_map_property_map_hpp != yes; then AC_MSG_ERROR([ABySS requires the Boost C++ libraries, which may be downloaded from here: http://www.boost.org/users/download/ It is not necessary to compile Boost before installing it. The following commands will download and install Boost for ABySS: cd $my_abs_srcdir wget http://downloads.sourceforge.net/project/boost/boost/$boost_ver/$boost_ver_dir.tar.bz2 tar jxf $boost_ver_dir.tar.bz2 cd -]) fi # Check for SQLite 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 AM_CONDITIONAL(HAVE_SQLITE3, [test "$ac_cv_header_sqlite3_h" = "yes" -a "$ac_cv_lib_sqlite3_main" = "yes"], [Define to 1 if you have sqlite lib/header]) AC_SUBST(SQLITE_LIBS, "$LIBS") LIBS=$libs # Check for OpenMP. AC_OPENMP if test -z $OPENMP_CXXFLAGS; then OPENMP_CXXFLAGS=-Wno-unknown-pragmas fi # Set compiler flags. 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 -Werror') fi # Build abyss-paired-dbg and abyss-paired-dbg-mpi AM_CONDITIONAL([PAIRED_DBG], [true]) AC_CONFIG_FILES([ Makefile ABYSS/Makefile Align/Makefile Assembly/Makefile Common/Makefile DataLayer/Makefile FMIndex/Makefile Graph/Makefile Parallel/Makefile bin/Makefile doc/Makefile dialign/Makefile kmerprint/Makefile AdjList/Makefile Konnector/Makefile DAssembler/Makefile DistanceEst/Makefile Layout/Makefile Map/Makefile Overlap/Makefile PopBubbles/Makefile Scaffold/Makefile SimpleGraph/Makefile MergePaths/Makefile KAligner/Makefile PairedDBG/Makefile ParseAligns/Makefile PathOverlap/Makefile Consensus/Makefile FilterGraph/Makefile GapFiller/Makefile Sealer/Makefile vendor/gtest-1.7.0/Makefile Unittest/Makefile LogKmerCount/Makefile Bloom/Makefile BloomDBG/Makefile DataBase/Makefile vendor/Makefile vendor/nthash/Makefile ]) 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: https://code.google.com/p/sparsehash/ If you do not wish to use sparsehash, specify --without-sparsehash.]) fi if test x"$have_pthread" != x"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 abyss-2.2.4/dialign/000077500000000000000000000000001361462241400142525ustar00rootroot00000000000000abyss-2.2.4/dialign/Makefile.am000066400000000000000000000004271361462241400163110ustar00rootroot00000000000000noinst_LIBRARIES = libdialign.a noinst_PROGRAMS = dialign libdialign_a_SOURCES = \ alig.c \ assemble.c \ diag.c \ io.c io.h \ orf.c orf.h \ parameters.c parameters.h \ prob.c \ struct.h \ translate.c translate.h dialign_SOURCES = museq.c dialign_LDADD = libdialign.a abyss-2.2.4/dialign/alig.c000066400000000000000000000734461361462241400153500ustar00rootroot00000000000000#include #include #include #include #include #include #include "parameters.h" #include "struct.h" extern void error(char *message); extern void merror(char *msg1, char *msg2); extern inline void calc_weight(struct diag* dg, struct scr_matrix* smatrix, struct prob_dist *pdist); extern inline void calc_ov_weight(struct diag* dg, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist); //extern struct seq_part* create_seq_part(int num, struct seq* aSeq, unsigned int startpos); extern struct diag* create_diag(struct seq_part* part1, struct seq_part* part2, int dlength); extern void free_diag(struct diag* dg); // long balance = 0; //unsigned long allocss = 0; //unsigned long freess = 0; long sslen; /** * * alig.c: Takes care of the alignment data structure * * 2003-10-31 A.R.Subramanian * (Initial) */ /** * creates initial empty alignment data structure * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct alignment* create_empty_alignment(struct seq_col *scol) { /* printf("before\n"); sleep(5); */ struct alignment* algn = malloc(sizeof(struct alignment)); sslen = scol->length; //allocss += sizeof(struct alignment); if(algn==NULL) error("create_empty_alignment(): (1) Out of memory !"); //long xsize = sizeof(struct alignment); algn->next = NULL; // algn->prev = NULL; algn->total_weight = 0.0; //algn->pos = 0; algn->max_pos = -1; algn->scol = scol; //algn->aligned_diags_amount=0; //algn->aligned_diags = malloc(sizeof(struct diag*)*diag_amount); //algn->max_aligned_diags_amount = diag_amount; //algn->orig_max_aligned_diags_amount = diag_amount; //algn->backlog_diags = NULL; ////allocss += (sizeof(struct diag*)*diag_amount); //if(algn->aligned_diags==NULL) // error("create_empty_alignment(): (1.5) Out of memory !"); unsigned int slen = scol->length; algn->seq_is_orphane = calloc(slen, sizeof(char)); //allocss += (sizeof(char)*slen); //xsize += slen*sizeof(char); if(algn->seq_is_orphane==NULL) error("create_empty_alignment(): (2) Out of memory !"); // memset(algn->seq_is_orphane, 1, slen*sizeof(char)); algn->algn = malloc(sizeof(struct algn_pos *)*slen); //allocss += sizeof(struct algn_pos *)*slen; //xsize += slen*sizeof(struct algn_pos *); if(algn->algn==NULL) error("create_empty_alignment(): (3) Out of memory !"); //algn->redo_seqs = calloc(slen*slen, sizeof(char)); int i,j; struct seq* sq; for(i=0;iseqs[i]); algn->seq_is_orphane[i]=1; algn->algn[i] = malloc(sizeof(struct algn_pos)*sq->length ); //allocss += sizeof(struct algn_pos )*sq->length; //xsize += sq->length*sizeof(struct algn_pos *); if(algn->algn[i]==NULL) error("create_empty_alignment(): (4) Out of memory !"); for(j=0;jlength;j++) { algn->algn[i][j].state = para->STATE_ORPHANE; // algn->algn[i][j].isInherited = 0; algn->algn[i][j].predFPos = -1; algn->algn[i][j].succFPos = -1; algn->algn[i][j].eqcParent= &(algn->algn[i][j]); //if(j==442) printf(" parent: %i\n", algn->algn[i][j].eqcParent); algn->algn[i][j].eqcRank= 0; algn->algn[i][j].eqcAlgnPos=calloc(1, sizeof(int));; //allocss += sizeof(int); *algn->algn[i][j].eqcAlgnPos=j; algn->algn[i][j].proceed=calloc(1, sizeof(char));; //allocss += sizeof(char); *algn->algn[i][j].proceed = 0; algn->algn[i][j].predF = NULL; algn->algn[i][j].succF = NULL; algn->algn[i][j].row = i; algn->algn[i][j].col = j; algn->algn[i][j].dg_cont = NULL; //xsize += sizeof(char) + sizeof(int); } } /* printf("after\n"); sleep(5); printf("gone\n"); */ // printf(" algnsize=%i\n",xsize); return algn; } /** * free alignment * */ void free_alignment(struct alignment *algn) { struct seq_col *scol = algn->scol; int slen = scol->length; int i,j; struct algn_pos *apos; struct algn_pos *o_apos; struct algn_pos *tpos; struct seq *sq; struct diag_cont *dgc,*ndgc; if(algn->seq_is_orphane!=NULL) { free(algn->seq_is_orphane); //freess += sizeof(char)*slen; } for(i=0;iseqs[i]); for(j=0;jlength;j++) { apos = &(algn->algn[i][j]); if(! (apos->state & para->STATE_INHERITED) && ! (apos->state & para->STATE_ORPHANE)) { //if(! (apos->state & para->STATE_INHERITED) && ! (apos->state & para->STATE_ORPHANE)) { if(apos->predF!=NULL) { free(apos->predF); //freess += sizeof(int)*slen; } if(apos->succF!=NULL) { free(apos->succF); //freess += sizeof(int)*slen; } } if(! (apos->state & para->STATE_INHERITED) || (apos->state & para->STATE_ORPHANE) ) { free(apos->eqcAlgnPos); free(apos->proceed); //freess += sizeof(int)+sizeof(char); } dgc = apos->dg_cont; while(dgc!=NULL) { ndgc = dgc->next; //printf(" free %i %i %i %i\n", i,j,dgc, dgc->next); free(dgc); //freess += sizeof(struct diag_cont); dgc = ndgc; } } free(algn->algn[i]); //freess += sizeof(struct algn_pos)*sq->length; } //dgc = algn->backlog_diags; //while(dgc!=NULL) { // ndgc = dgc->next; // free(dgc); // //freess += sizeof(struct diag_cont); // dgc = ndgc; //} //free(algn->aligned_diags); ////freess += sizeof(struct diag *)*algn->; free(algn->algn); free(algn); ////freess += sizeof(struct algn_pos *)*slen + sizeof(struct alignment); } /** * returnes the representative of the equivalence class */ struct algn_pos *_find_eqc(struct algn_pos *ap) { if(ap!=ap->eqcParent) { // if(doprint) printf(" FIND: %i %i\n", ap, ap->eqcParent); /** if(ap->eqcParent->eqcAlgnPos!=NULL) { if( (ap->eqcAlgnPos!=NULL) && *ap->eqcParent->eqcAlgnPos < *ap->eqcAlgnPos) { // if(doprint) printf(" 1.1 ALGNPOS: %i %i\n", ap, ap->eqcParent); *ap->eqcParent->eqcAlgnPos = *ap->eqcAlgnPos; } } else { // ap->eqcParent->eqcAlgnPos = ap->eqcAlgnPos; } */ ap->eqcParent = _find_eqc(ap->eqcParent); } // if(doprint) printf(" 1.ALGNPOS: %i %i\n", ap, ap->eqcParent); // if(doprint) printf(" 2.ALGNPOS: %i %i\n", ap, ap->eqcParent); return ap->eqcParent; } /** * returnes the representative of the equivalence class */ struct algn_pos *find_eqc(struct algn_pos **ap, int seqnum, int pos) { //if(1) printf("%i %i %i\n", ap, seqnum,pos); struct algn_pos *tap = &ap[seqnum][pos]; struct algn_pos *eq_ap; eq_ap = _find_eqc(tap); struct diag_cont *old_dgc; // if(eq_ap->eqcAlgnPos != tap->eqcAlgnPos) { if(eq_ap != tap) { /* if(tap->state & para->STATE_ORPHANE) { printf(" ALARM ORPHANE %i %i\n", eq_ap->state, tap->state); } if(eq_ap->state & para->STATE_ORPHANE) { printf(" ALARM ORPHANE %i %i\n", eq_ap->state, tap->state); } */ //if((tap->eqcAlgnPos!=NULL) && (*tap->eqcAlgnPos > *eq_ap->eqcAlgnPos)) // *eq_ap->eqcAlgnPos = *tap->eqcAlgnPos; // if(eq_ap->eqcAlgnPos != tap->eqcAlgnPos) if( (!(tap->state & para->STATE_INHERITED))) { //&& !oldparentIsInherited) { if(tap->eqcAlgnPos !=NULL) { //if(pos==175) printf("free eqcAlgnPos: %i\n", tap->eqcAlgnPos); //balance -= sizeof(int); free(tap->eqcAlgnPos); tap->eqcAlgnPos = NULL; //freess += sizeof(int); } if(tap->proceed !=NULL) { //printf("free proceed: %i\n", tap->proceed); //balance -= sizeof(char); free(tap->proceed); //freess += sizeof(char); //printf("after free proceed: %i\n", tap->proceed); tap->proceed = NULL; } //if(tap->predFPos>=0) if( (eq_ap->predF != tap->predF) && (1 || (tap->predFPos<0)) && (tap->predF!=NULL)){ //printf(" free predF: %i %i %i %i\n", tap->predF, tap->isInherited, seqnum, pos); //balance -= sizeof(int)*sslen; //printf (" 3. free: %i %i %i\n",allocs, frees, allocs-frees); //freess += sizeof(int)*sslen; free(tap->predF); //printf(" after free predF: %i\n", tap->predF); tap->predF=NULL; } //if(tap->succFPos>=0) if((eq_ap->succF != tap->succF) && (1 || (tap->succFPos<0)) && (tap->succF!=NULL)) { //printf("free succ: %i\n", tap->succF); //balance -= sizeof(int)*sslen; //printf (" 4. free: %i %i %i\n",allocs, frees, allocs-frees); //freess += sizeof(int)*sslen; free(tap->succF); //printf("after free succ: %i\n", tap->succF); tap->succF=NULL; } } /*else { if(eq_ap->state & para->STATE_INHERITED) { printf(" inherited alarm!\n"); } if(eq_ap->state & para->STATE_ORPHANE) { printf(" orphane alarm!\n"); } }*/ old_dgc = tap->dg_cont; *tap = *eq_ap; tap->dg_cont = old_dgc; tap->row = seqnum; tap->col = pos; tap->state = (tap->state | para->STATE_INHERITED); } //if(seqnum==0 &&pos==175) printf("after !=\n"); // tap = eq_ap; struct algn_pos *ttap; if(tap->predFPos>=0 ) { //if(seqnum==0 && pos==175) printf(" alarm predF: %i %i %i %i\n", tap->predF, tap->predFPos, seqnum, pos); // printf ("PRE Pos %i %i \n", tap->predFPos, pos); if( (tap->predFPos==pos)|| !(tap->state & para->STATE_ORPHANE)) { printf("pred ALARM %i %i\n", tap->predFPos, pos); exit(99); } ttap=find_eqc(ap, seqnum, tap->predFPos); tap->predF = ttap->predF; } if(tap->succFPos>=0) { //if(seqnum==0 && pos==175) printf(" alarm succF: %i %i %i %i\n", tap->succF, tap->succFPos, seqnum, pos); //printf ("2. PRE Pos %i %i \n", tap->predFPos, tap->succFPos); if( (tap->succFPos==pos)|| !(tap->state & para->STATE_ORPHANE)) { printf("succ ALARM %i %i\n", tap->succFPos, pos); exit(99); } ttap = find_eqc(ap, seqnum, tap->succFPos); tap->succF = ttap->succF; } //if(seqnum==0 && pos==175) printf(" end qgc\n"); return tap; } /** * copy alignment * * doDgc = 0: ignore all backlogdiags and position dg_cont's * doDgc = 1: free the target backlogdiags and dg_conts' * doDgc = 2: same as 1 but also copy the original backlog diags and dg_conts to the target struct alignment* copy_alignment( struct alignment *o_algn, struct alignment *algn, char doDgc) { struct seq_col *scol = o_algn->scol; int slen = scol->length; int i,j; struct algn_pos *apos; struct algn_pos *o_apos; struct algn_pos *tpos; struct seq *sq; struct diag_cont *ptdgc, *tdgc, *o_tdgc; if(doDgc>0) { tdgc = algn->backlog_diags; while(tdgc!=NULL) { algn->backlog_diags = algn->backlog_diags->next; free(tdgc); tdgc = algn->backlog_diags; } if(doDgc>1) { o_tdgc = o_algn->backlog_diags; ptdgc = NULL; while(o_tdgc!=NULL) { tdgc = malloc(sizeof(struct diag_cont)); *tdgc = *o_tdgc; if(ptdgc == NULL) { algn->backlog_diags = tdgc; } else { ptdgc->next = tdgc; } ptdgc = tdgc; } } } memcpy(algn->seq_is_orphane, o_algn->seq_is_orphane, sizeof(char)*slen); algn->total_weight = o_algn->total_weight; // printf(" enter copy\n"); for(i=0;iseqs[i]); for(j=0;jlength;j++) { apos = &(algn->algn[i][j]); o_apos = &(o_algn->algn[i][j]); if(doDgc>0) { tdgc = apos->dg_cont; while(tdgc!=NULL) { apos->dg_cont = apos->dg_cont->next; free(tdgc); tdgc = apos->dg_cont; } if(doDgc>1) { o_tdgc = o_apos->dg_cont; ptdgc = NULL; while(o_tdgc!=NULL) { tdgc = malloc(sizeof(struct diag_cont)); *tdgc = *o_tdgc; if(ptdgc == NULL) { apos->dg_cont = tdgc; } else { ptdgc->next = tdgc; } ptdgc = tdgc; } } } if(! (apos->state & para->STATE_ORPHANE)) { if(o_apos->state & para->STATE_ORPHANE) { if(!(apos->state & para->STATE_INHERITED)) { // printf (" free1\n") //frees += sizeof(int)*slen*2; //printf (" 1. frees: %i %i %i\n",allocs, frees, allocs-frees); free(apos->predF); free(apos->succF); //balance -= 2*sizeof(int)*slen; } apos->predF=NULL; apos->succF=NULL; } else { if(apos->state & para->STATE_INHERITED) { if(! (o_apos->state & para->STATE_INHERITED)) { //printf (" 1. malloc: %i %i %i\n",allocs, frees, allocs-frees); apos->predF=malloc(sizeof(int)*slen); apos->succF=malloc(sizeof(int)*slen); //allocss += sizeof(int)*slen*2; //balance += 2*sizeof(int)*slen; if( (apos->predF==NULL) || (apos->succF==NULL)) error("copy_alignment(): (1) Out of memory !"); memcpy(apos->predF, o_apos->predF, sizeof(int)*slen); memcpy(apos->succF, o_apos->succF, sizeof(int)*slen); } else { apos->predF=NULL; apos->succF=NULL; } } else { if(! (o_apos->state & para->STATE_INHERITED)) { memcpy(apos->predF, o_apos->predF, sizeof(int)*slen); memcpy(apos->succF, o_apos->succF, sizeof(int)*slen); } else { // printf (" free2\n") //frees += sizeof(int)*slen*2; //printf (" 2. frees: %i %i %i\n",allocs, frees, allocs-frees); free(apos->predF); free(apos->succF); //freess += sizeof(int)*slen*2; //balance -= 2*sizeof(int)*slen; apos->predF=NULL; apos->succF=NULL; } } } } else { if( !(o_apos->state & para->STATE_ORPHANE)) { if(o_apos->state & para->STATE_INHERITED) { apos->predF=NULL; apos->succF=NULL; } else { //allocs += sizeof(int)*slen*2; //printf (" 2. malloc: %i %i %i\n",allocs, frees, allocs-frees); apos->predF=malloc(sizeof(int)*slen); apos->succF=malloc(sizeof(int)*slen); //allocss += sizeof(int)*slen*2; //balance += 2*sizeof(int)*slen; if( (apos->predF==NULL) || (apos->succF==NULL)) error("copy_alignment(): (2) Out of memory !"); memcpy(apos->predF, o_apos->predF, sizeof(int)*slen); memcpy(apos->succF, o_apos->succF, sizeof(int)*slen); } } else { apos->predF=NULL; apos->succF=NULL; } } apos->predFPos = o_apos->predFPos; apos->succFPos = o_apos->succFPos; //printf(" before %i %i\n", i,j); apos->eqcRank = o_apos->eqcRank; tpos = o_apos->eqcParent; apos->eqcParent = &(algn->algn[tpos->row][tpos->col]); if( (apos->state & para->STATE_INHERITED)) { if( !(o_apos->state & para->STATE_INHERITED)) { //allocs += sizeof(int)+sizeof(char); apos->eqcAlgnPos = malloc(sizeof(int)); *(apos->eqcAlgnPos)=j; apos->proceed = malloc(sizeof(char)); *(apos->proceed)=0; //allocss += sizeof(int)+sizeof(char); } } else { if((o_apos->state & para->STATE_INHERITED)) { //frees += sizeof(int)+sizeof(char); free(apos->eqcAlgnPos); free(apos->proceed); apos->eqcAlgnPos=NULL; apos->proceed=NULL; //balance -= sizeof(int)+sizeof(char); } } //printf(" after %i %i\n", i,j); apos->state = o_apos->state; } } // printf(" leave copy\n"); return algn; } */ /** * adds the given diagional to the given alignment and updates the * datastructure (i.e. frontiers). The given diag must be consistent * to the given alignment ! */ char align_diag(struct alignment *algn, struct scr_matrix *smatrix, struct diag* dg) { char alignedSomething = 0; int i,j,k; char al; if(dg->multi_dg) { //return 0; for(i=0;imulti_length;i++) { if(dg->multi_cont[i]!=NULL) { //printf(" before %f %f\n", dg->total_weight, dg->multi_cont[i]->weight); al = align_diag(algn,smatrix, dg->multi_cont[i]); if(al) algn->total_weight -= dg->multi_cont[i]->total_weight; alignedSomething = alignedSomething || al; //printf(" after \n"); } } return alignedSomething; } //if((dg->length==0) ) return 0; if((dg->length==0) || (!dg->meetsThreshold && !dg->anchor)) return 0; /* printf(" dg %i %i %i\n", dg, dg->multi_dg, dg->length); char adapted = adapt_diag(algn, smatrix, dg); if(adapted) { printf(" dg %i %i %i\n", dg, dg->multi_dg, dg->length); error(" inconsistent diag!\n"); } */ struct seq_col *scol = algn->scol; int s1 = dg->seq_p1.num; int s2 = dg->seq_p2.num; //printf("%i %i\n", s1,s2); //char o1 = algn->seq_is_orphane[s1]; //char o2 = algn->seq_is_orphane[s2]; int length = dg->length; int sp1 = dg->seq_p1.startpos; int sp2 = dg->seq_p2.startpos; struct algn_pos **ap=algn->algn; struct algn_pos *tp; struct algn_pos *apos1, *apos2, *tpos; int p1, p2,plen; int p; struct seq *sq = scol->seqs; int s, slen = scol->length; int *oldpredF, *oldsuccF, *otherpredF, *othersuccF; int pF,sF; int *c2n = smatrix->char2num; int *sdata = smatrix ->data; char *data1 = dg->seq_p1.sq->data; char *data2 = dg->seq_p2.sq->data; int smatrixlen = smatrix->length; int a1,a2; int score1; char seenNonOrphane; int opos; int ms; char skip = 0; char found; struct diag_cont *dgc, *dgc_next; double ttim; /* int nextpos[slen]; int firstpos; int oldpos; char firstRound; */ for(i=0;ilength); skip = 0; //if(sp1==30) printf("%i %i %i %i %i \n", p1,p2,dg->length, dg->seq_p1.sq->length, dg->seq_p2.sq->length); /* // if(dg->onlyOverThres==1) { a1 = c2n[data1[p1]]; a2 = c2n[data2[p2]]; score1 = sdata[smatrixlen*a1+a2]; if( (score1<=3) && (i>length/3)) { skip = 1; } //} */ // printf(" %i %i %i\n",p1,p2,skip); //} else { /* a1 = c2n[data1[p1]]; a2 = c2n[data2[p2]]; score1 = sdata[smatrixlen*a1+a2]; if(score1<=4) { skip = 1; } */ //if( (i==(length-1)) ){ //ttim = clock(); //tim += (clock()-ttim)/CLOCKS_PER_SEC; // printf(" tim %f\n", tim); //printf(" diag n1=%i s1=%i n2=%i s2=%i l=%i\n", s1,sp1,s2,sp2,length); //allocss += 2*sizeof(struct diag_cont ); //} // TODO: tune ration is 1:45 (minor) /* dgc_next = ap[s1][p1].dg_cont; dgc = malloc(sizeof(struct diag_cont)); dgc->dg = dg; dgc->next = dgc_next; ap[s1][p1].dg_cont = dgc; //if((s1==0) && (p1==133)) printf(" dddgc %i %i\n", dgc, dgc->next); dgc_next = ap[s2][p2].dg_cont; dgc = malloc(sizeof(struct diag_cont)); dgc->dg = dg; dgc->next = dgc_next; ap[s2][p2].dg_cont = dgc; */ if(! skip) { //printf("apos1 %i %i\n", s1, p1); apos1 = find_eqc(ap, s1,p1);//&(ap[s1][p1]); //printf("apos2 %i %i %i\n", s2, p2, scol->seqs[s2].length); apos2 = find_eqc(ap, s2,p2); //&(ap[s2][p2]); //printf("after apos2 %i %i\n", s2, p2); oldpredF = apos1->predF; oldsuccF = apos1->succF; if(oldpredF!=NULL && oldsuccF!=NULL) if(oldpredF[s2]==p2 && oldsuccF[s2]==p2) skip = 1; if(para->DEBUG>4) { if(!skip) { if(oldpredF!=NULL) if(oldpredF[s2]>=p2) { printf(" Incons1 %i %i %i\n", s2, p2,oldpredF[p2]); error(" ERROR"); } if(oldsuccF!=NULL) if(oldsuccF[s2]<=p2) { printf(" Incons2 %i %i %i\n",s2, p2,oldsuccF[p2]); error(" ERROR"); } oldpredF=apos2->predF; oldsuccF=apos2->succF; if(oldpredF!=NULL) if(oldpredF[s1]>=p1) { printf(" Incons3 %i %i %i\n", s1, p1,oldpredF[p1]); error(" ERROR"); } if(oldsuccF!=NULL) if(oldsuccF[s1]<=p1) { printf(" Incons4 %i %i %i\n",s1, p1,oldsuccF[p1]); error(" ERROR"); } } } } //} if(! skip) { alignedSomething = 1; for(k=0;k<2;k++) { tpos = (k==0 ? apos1 : apos2); //printf("tpos %i\n", tpos); oldpredF = tpos->predF; oldsuccF = tpos->succF; otherpredF = (k==0 ? apos2->predF : apos1->predF); othersuccF = (k==0 ? apos2->succF : apos1->succF); //printf("pre isorphane %i\n", tpos); if(tpos->state & para->STATE_ORPHANE) { //if(scol->length>21) printf("isorphane %i %i\n", tpos,sizeof(int)*scol->length); //printf("step 1\n"); // printf (" 3. malloc: %i\n",sizeof(int)*slen*2); //allocs += sizeof(int)*slen*2; // printf (" 3. malloc: %i %i %i\n",allocs, frees, allocs-frees); //balance += sizeof(int)*slen*2; tpos->predF = malloc(sizeof(int)*scol->length); //if(k==0) printf(" apos1->predF = %i\n",tpos->predF), //printf("pre succForphane %i %i\n", tpos->succF, scol->length); //printf(" step 2\n"); tpos->succF = malloc(sizeof(int)*scol->length); //allocss += 2*sizeof(int )*scol->length; //printf(" step 3\n"); //printf("succForphane %i\n", tpos); if( (tpos->predF==NULL) || (tpos->succF==NULL)) error("align_diag(): (1) Out of memory !"); } // printf("init loop %i\n", tpos); for(j=0;jlength;j++) { pF = -1; sF = sq[j].length; // propagate predF and succF if(oldpredF!=NULL && oldpredF[j]>pF) pF = oldpredF[j]; //if(j==0) printf("1 pf=%i\n", pF); if(otherpredF!=NULL && otherpredF[j]> pF) pF = otherpredF[j]; //if(j==0) printf("2 pf=%i\n", pF); if(oldsuccF!=NULL && oldsuccF[j] sF) { if(oldpredF!=NULL) printf(" PRE 1. ALARM oldpredF: %i \n",oldpredF[j] ); if(oldsuccF!=NULL) printf(" PRE 1. ALARM oldsuccF: %i \n",oldsuccF[j] ); if(otherpredF!=NULL) printf(" PRE 1. ALARM otherpredF: %i \n",otherpredF[j] ); if(othersuccF!=NULL) printf(" PRE 1. ALARM othersuccF: %i \n",othersuccF[j] ); printf("1. ALARM j=%i %i %i %i %i %i %i %i\n", j, (k==0 ? s1 : s2), (k==0 ? p1 : p2), (k==0 ? p2 : p1), oldpredF!=NULL ? oldpredF[k==0 ? s2 : s1] : -2, oldsuccF!=NULL ? oldsuccF[k==0 ? s2 : s1]: 99999, tpos->predFPos, tpos->succFPos); exit(1); } */ //if(pF==sF && pF==0 && j==0) printf("pf=%i sf=%i j=%i s1=%i s2=%i p1=%i p2=%i iso=%i opf=%i osf=%i otpf=%i otsf=%i\n", pF,sF,j,s1,s2,p1,p2,tpos->isOrphane,oldpredF, oldsuccF, otherpredF, othersuccF); tpos->predF[j]=pF; tpos->succF[j]=sF; } //if(s1==0 && p1==0) printf(" SET IT 1\n"); //if(s2==0 && p2==0) printf(" SET IT 2\n"); //if(tpos->state & para->STATE_ORPHANE) tpos->state = tpos->state & (tpos->state ^ para->STATE_ORPHANE); tpos->predFPos = -1; tpos->succFPos = -1; } //printf("end pre/succ %i\n", tpos); apos1->predF[s1]=p1; apos1->succF[s1]=p1; apos2->predF[s2]=p2; apos2->succF[s2]=p2; apos1->predF[s2]=p2; apos1->succF[s2]=p2; apos2->predF[s1]=p1; apos2->succF[s1]=p1; if(apos2->eqcRank< apos1->eqcRank) { apos2->eqcParent = apos1; } else { apos1->eqcParent = apos2; if(apos2->eqcRank==apos1->eqcRank) apos2->eqcRank++; } //printf("end ranking %i, %i %i\n", s1,p1,apos1->predF); apos1 = find_eqc(ap, s1,p1);//&(ap[s1][p1]); //printf("end first egc %i\n", tpos); apos2 = find_eqc(ap, s2,p2); //&(ap[s2][p2]); //printf("end second egc %i\n", tpos); // update the other affected sites for(ms=0;mspredF[ms]==apos1->succF[ms]) { p = apos1->predF[ms]; // -( (apos1->predF[ms]==apos1->succF[ms]) ? 1 : 0); // GOGOGOGO opos=apos1->predF[ms]; // printf("SUPERPRE WHILE %i %i %i\n",k,s1,s2); tp = ap[ms]; //printf("PRE WHILE %i\n",k); seenNonOrphane=0; found = 1; //firstRound = 1; //firstpos = 0; while( (p>=0)&& found) { // && tp[p].isOrphane) { //printf(" WHILE %i\n",p); if(tp[p].state & para->STATE_ORPHANE) { if( (! seenNonOrphane)) { // if(ms==0 && p==0) printf("setting s1=%i p1=%i iso=%i ms=%i p=%i opos=%i\n",s1,p1, tp[p].isOrphane, ms,p,opos); tp[p].succFPos = opos; } else p = tp[p].predFPos+1; } else { if( (p!=opos) || (apos1->succF[ms]!=apos1->predF[ms])) seenNonOrphane = 1; //if(p==442) printf(" pre find %i %i %i\n",s1, ms,p); tpos = find_eqc(ap, ms,p);//&(ap[s1][p1]); //if(p==442)printf(" post find %i %i\n",ms,p); if(! (tpos->state & para->STATE_ORPHANE) && ! (tpos->state & para->STATE_INHERITED)) { //printf(" %i %i %i %i\n",ms,p,s1,p1); if(seenNonOrphane) found = 0; for(s=0;ssuccF[s]>apos1->succF[s]) { tpos->succF[s]=apos1->succF[s]; found = 1; } } /* oldpos = firstpos; s = firstpos; while(ssuccF[s]>apos1->succF[s]) { tpos->succF[s]=apos1->succF[s]; found = 1; oldpos = s; } else { if(! firstRound) { nextpos[oldpos] = nextpos[s]; if(oldpos==firstpos) { firstpos=nextpos[oldpos]; oldpos = firstpos; } } } if(firstRound) { oldpos = s; s++; } else { s = nextpos[s]; } } */ } } //firstRound = 0; p--; } //printf("END WHILE\n"); //printf(" PRE 2 %i %i %i\n", apos1->predF, apos1->succF,ms ); p = apos1->succF[ms]; // +( (apos1->predF[ms]==apos1->succF[ms]) ? 1 : 0); // GOGOGOGO ; opos= apos1->succF[ms]; plen = scol->seqs[ms].length; seenNonOrphane=0; //printf("2. PRE WHILE %i\n",k); // if(opos>=plen) opos = -1; found = 1; while( (pSTATE_ORPHANE) { if( (! seenNonOrphane)) { /* if(p==opos) { printf("ALARM set predFPos s1=%i s2=%i p1=%i p2=%i ms=%i sF=%i pF=%i p=%i opos=%i iso=%i %i %i %i\n", s1,s2,p1,p2,ms, apos1->succF[ms], apos1->predF[ms],p,opos, tp[p].state,(int) &tp[p],(int) apos1, (int) apos2); exit(98); } */ tp[p].predFPos = opos; } else { if(tp[p].succFPos < 0) p = plen+1; else p = tp[p].succFPos-1; } } else { if( (p!=opos)|| (apos1->succF[ms]!=apos1->predF[ms])) seenNonOrphane = 1; //printf(" pre find %i %i\n",ms,p); tpos = find_eqc(ap, ms,p);//&(ap[s1][p1]); //printf(" end find\n"); if(! (tpos->state & para->STATE_ORPHANE) && !(tpos->state & para->STATE_INHERITED)) { if(seenNonOrphane) found = 0; for(s=0;spredF=%i\n",s,slen,tpos->predF); if( tpos->predF[s]predF[s]) { //printf(" inner before s=%i slen=%i\n",s,slen); tpos->predF[s]=apos1->predF[s]; //printf(" inner after s=%i slen=%i\n",s,slen); found = 1; } } } } p++; } //printf("2. END WHILE %i\n",k); } } } // printf("s1: %i s2: %i\n", algn->seq_is_orphane[s2],s2); algn->seq_is_orphane[s1]=0; algn->seq_is_orphane[s2]=0; int maxposs1 = dg->seq_p1.startpos + dg->length-1; int maxposs2 = dg->seq_p2.startpos + dg->length-1; if(dg->seq_p1.sq->max_seen < maxposs1) dg->seq_p1.sq->max_seen = maxposs1; if(dg->seq_p2.sq->max_seen < maxposs2) dg->seq_p2.sq->max_seen = maxposs2; //if(alignedSomething) { /* if(algn->aligned_diags_amount >= algn->max_aligned_diags_amount) { algn->max_aligned_diags_amount = algn->aligned_diags_amount + 16; algn->aligned_diags = realloc(algn->aligned_diags, sizeof(struct diag*)*algn->max_aligned_diags_amount); if(algn->aligned_diags==NULL) error(" align_diag(): Out of Memory!"); } algn->aligned_diags[algn->aligned_diags_amount++] = dg; */ /* } else { dgc = malloc(sizeof(struct diag_cont)); dgc->dg = dg; dgc->next = NULL; algn->backlog_diags = enter_sorted(algn->backlog_diags, dgc); } */ //printf(" diaglen: %i\n", algn->aligned_diags_amount); if(! dg->anchor) algn->total_weight += dg->weight;//*dg->weight_fac; return(alignedSomething); } /** * * prepares the alignment: calculates the position number of each residue * */ void prepare_alignment(struct alignment *algn) { struct seq_col *scol = algn->scol; unsigned int slen = scol->length; unsigned int i,j,s,ts, hasmore, max; int *predF, *succF; struct seq* sq; struct algn_pos **ap = algn->algn; int tproc[slen]; // char proceed[slen]; for(i=0;iseqs[s]; if(tproc[s]length) { ap1 = find_eqc(ap,s,tproc[s]); *ap1->proceed = 1; } } for(s=0;sseqs[s]; if(tproc[s]length) { //printf(" DO IT %i %i %i %i\n",j,s,tproc[s], *ap1->eqcAlgnPos); ap1 = find_eqc(ap,s,tproc[s]); // printf("alig.c ap1 = %d\tap = %d\n",ap1,ap); if(j>=*ap1->eqcAlgnPos) { predF = ap1->predF; succF = ap1->succF; *ap1->eqcAlgnPos=j;// *tap1->eqcAlgnPos; if(predF!=NULL) { for(ts=0;tseqcAlgnPos=j+1;// *tap1->eqcAlgnPos; //printf(" 2. MIST %i %i %i %i %i %i %i\n",j,s,ts,tproc[s], tproc[ts], predF[ts], succF!=NULL ? succF[ts]: 99999); *ap1->proceed = 0; break; } else { /* *ap1->eqcAlgnPos=j;// *tap1->eqcAlgnPos; *ap1->proceed = 1; */ } } } } else { *ap1->proceed = 0; } /* if(j>=143) { printf("ALARM j=%i s=%i tproc[s]=%i algnPos=%i\n",j,s,tproc[s],*ap[s][tproc[s]].eqcAlgnPos); } */ } } alarmHasProceed=0; for(s=0;sseqs[s]; if(tproc[s]length) { ap1 = find_eqc(ap,s,tproc[s]); if(*ap1->proceed) { alarmHasProceed = 1; tproc[s]++; } } if(tproc[s]length) hasmore = 1; //printf("%i %i\n", sq->length,tproc[s]); } if(! alarmHasProceed && hasmore) { printf("IO ALARM! %i\n",j); exit(1); hasmore=0; } if(!hasmore) max = j+1; } algn->max_pos= max; } abyss-2.2.4/dialign/assemble.c000066400000000000000000001123271361462241400162170ustar00rootroot00000000000000#include #include #include #include #include #include #include "parameters.h" #include "struct.h" extern void error(char *message); extern void merror(char *msg1, char *msg2); extern inline void calc_weight(struct diag* dg, struct scr_matrix* smatrix, struct prob_dist *pdist); extern inline void calc_ov_weight(struct diag* dg, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist); //extern struct seq_part* create_seq_part(int num, struct seq* aSeq, unsigned int startpos); extern long double** create_tmp_pdist(struct prob_dist *pdist); extern void free_tmp_pdist(long double **dist, int length); extern struct diag* create_diag(int n1, struct seq* sq1, unsigned int sp1, int n2, struct seq* sq2, unsigned int sp2, int dlength); extern void free_diag(struct diag* dg); extern inline struct simple_diag_col* find_diags_guided(struct scr_matrix *smatrix, struct prob_dist *pdist, struct gt_node* n1, struct gt_node* n2, struct alignment *algn, double thres_weight, int *** diag_info); extern struct alignment* create_empty_alignment(struct seq_col *scol); extern void free_alignment(struct alignment *algn); extern inline struct algn_pos *find_eqc(struct algn_pos **ap, int seqnum, int pos); extern struct alignment* copy_alignment( struct alignment *o_algn, struct alignment *algn, char doDgc); //extern char adapt_diag(struct alignment *algn, struct scr_matrix *smatrix, struct diag* dg); extern inline char align_diag(struct alignment *algn, struct scr_matrix *smatrix, struct diag* dg); //extern inline struct diag_cont* enter_sorted(struct diag_cont* backlog_diags, struct diag_cont *cand); //extern inline char fit_fpos_diag(struct alignment *algn, struct diag* dg); //extern unsigned long allocss; //extern unsigned long freess; /** * * assemble.c: assembles the alignment from the diagonals * */ //double tim = 0; /** * enters the candidate in a sorted way to the list and returns pointer to the first element */ inline struct diag_cont* enter_sorted(struct diag_cont* backlog_diags, struct diag_cont *cand) { if(backlog_diags==NULL) { cand->next=NULL; return cand; } struct diag_cont *prev = backlog_diags; struct diag_cont *actual = backlog_diags; //printf(" before %f %i\n", cand->dg->total_weight, backlog_diags->dg); // if( (cand==backlog_diags) || (backlog_diags->next==cand)) error(" enter_sorted(): critical error"); if((cand->dg->total_weight >= backlog_diags->dg->total_weight)) { cand->next = backlog_diags; return cand; } while( (actual!=NULL) && (cand->dg->total_weight < actual->dg->total_weight)) { prev = actual; actual = actual->next; } prev->next = cand; cand->next = actual; //printf(" after\n"); return backlog_diags; } /** * returns whether the given first position of the diag fits intho the given alignment */ inline char fit_fpos_diag(struct alignment *algn, struct diag* dg) { unsigned int s1 = dg->seq_p1.num; unsigned int s2 = dg->seq_p2.num; char o1 = algn->seq_is_orphane[s1]; char o2 = algn->seq_is_orphane[s2]; // if any sequence is orphane the diag is always consistent if( o1 || o2) return 1; int sp1 = dg->seq_p1.startpos; int sp2 = dg->seq_p2.startpos; int ep1 = sp1+dg->length-1; int ep2 = sp2+dg->length-1; struct algn_pos **ap=algn->algn; int predF, succF; struct algn_pos *tap; tap = find_eqc(ap, s1, sp1); if(tap->predF!=NULL) { //&& tap->succF!=NULL) { predF = tap->predF[s2]; } else { predF=-1; } if(tap->succF!=NULL) { succF = tap->succF[s2]; } else { succF = ep2+1; } if( ( (predF>=sp2)|| (succF<=sp2) ) && !(predF==sp2 && succF==sp2)) { //printf(" leave fit_fpos 0 \n"); return 0; } else { // printf(" leave fit_fpos 1 \n"); return 1; } } /** * changes the startpos's and length of the diag such that * it becomes consistent with the given alignment. If the diag * has more than one part that is consistent the leftmost will be chosen * The return value is 1 if any changes were made otherwise 0. * (The weight of the diag is not recalculated !). * */ char adapt_diag(struct alignment *algn, struct scr_matrix *smatrix, struct diag* dg) { //char adapt_diag(struct alignment *algn, struct diag* dg) { //printf(" ENTER adapt\n"); if(dg->multi_dg) { char adapted = 0; int i; for(i=0;imulti_length;i++) { if(dg->multi_cont[i]!=NULL) { if(dg->multi_cont[i]->length > 0) { //printf(" adapted before %i %i\n", adapted, dg->multi_cont[i]->length); adapted = adapted || adapt_diag(algn, smatrix, dg->multi_cont[i]); /* if(dg->multi_cont[i]->length == 0) { dg->multi_cont[i]->meetsThreshold = 0; }*/ //printf(" adapted after %i %i\n", adapted, dg->multi_cont[i]->length); } if(dg->multi_cont[i]->length==0) { free(dg->multi_cont[i]); dg->multi_cont[i]=NULL; } } } return adapted; } unsigned int s1 = dg->seq_p1.num; unsigned int s2 = dg->seq_p2.num; char o1 = algn->seq_is_orphane[s1]; char o2 = algn->seq_is_orphane[s2]; // if any sequence is orphane the diag is always consistent if( o1 || o2) return 0; int sp1 = dg->seq_p1.startpos; int sp2 = dg->seq_p2.startpos; int ep1 = sp1+dg->length-1; int ep2 = sp2+dg->length-1; struct algn_pos **ap=algn->algn; int predF, succF; int rlen; // cut off the beginning of the diag struct algn_pos *tap;// = find_eqc(ap, s1, sp1); sp1--; sp2--; // jump to a consistent position //char included = 1; do { sp1++; sp2++; if(sp1<=ep1) { tap = find_eqc(ap, s1, sp1); if(tap->predF!=NULL) { //&& tap->succF!=NULL) { predF = tap->predF[s2]; } else { predF=-1; } if(tap->succF!=NULL) { succF = tap->succF[s2]; } else { succF = ep2+1; } } //if(predF!=sp2 || succF!=sp2) included = 0; } while( ( (predF>=sp2)|| (succF<=sp2) ) && !(predF==sp2 && succF==sp2) && sp1<=ep1); // cutoff low scoring positions at the beginning /* while( (sp1<=ep1)) { a1 = c2n[data1[sp1]]; a2 = c2n[data2[sp2]]; score1 = sdata[smatrixlen*a1+a2]; if(score1length, score1); sp1++; sp2++; } else { break; } } */ // check whether the diagonal has been cut off to zero length if(sp1>ep1) { // printf(" OUT OF RANGE %i %i %i \n",predF, succF, sp2); //if(included) // dg->weight = 0.0; //else // dg->weight = -1.0; dg->length=0; return 1; } // cut off the end of the diag rlen=0; do { rlen++; //printf(" rlen: %i %i %i %i %i\n", ep1, sp1, sp2, dg->length, sp1+rlen-1); if((sp1+rlen-1)>ep1) { break; }else { tap = find_eqc(ap, s1, sp1+rlen-1); //printf(" after rlen: %i\n", rlen); if(tap->predF!=NULL) { predF = tap->predF[s2]; } else { predF=-1; } if(tap->succF!=NULL) { succF = tap->succF[s2]; } else { succF = sp2+rlen; } } } while( ( ((succF>=(sp2+rlen)) && (predF<(sp2+rlen-1))) || ((succF==(sp2+rlen-1)) && (predF==(sp2+rlen-1)))) && ((sp1+rlen-1)<=ep1)); rlen--; // cutoff low scoring positions at the end /* while(rlen>0) { a1 = c2n[data1[sp1+rlen-1]]; a2 = c2n[data2[sp2+rlen-1]]; //printf(" %i %i %i\n", a1, a2,smatrixlen); score1 = sdata[smatrixlen*a1+a2]; break; if(score1length=0; //printf("sp1: %i\n", sp1); return 1; } int oldlen = dg->length; //printf("sp1: %i\n", sp1); dg->length = rlen; dg->seq_p1.startpos=sp1; dg->seq_p2.startpos=sp2; if(oldlen==rlen) { return 0; } return 1; } /** * heapify void heapify_diag_array(struct diag **diags, int pos, int length, int up) { struct diag *dg = diags[pos]; if(up) { if(pos<=3) return; int parent = (pos-1)/2; struct diag *pdg = diags[parent]; if(pdg->total_weighttotal_weight) { diags[parent]=dg; diags[pos] = pdg; // printf("heapify: %i %i %i %i %i\n", pos,parent, length, dg, pdg); heapify_diag_array(diags, parent,length,up); } } else { int lchild = 2*pos+1; if( (lchild)>=length) return; int rchild = lchild+1; //struct diag *dg = diags[pos]; struct diag *ldg = diags[lchild]; struct diag *rdg = (rchild>=length ? ldg : diags[rchild]); int greatest = pos; if(ldg->total_weight > diags[greatest]->total_weight) greatest = lchild; if( (rchildtotal_weight > diags[greatest]->total_weight)) greatest = rchild; if(greatest != pos) { diags[pos] = diags[greatest]; diags[greatest] = dg; heapify_diag_array(diags, greatest,length,up); } } } */ /** * heapify */ void heapify_diag_array(struct diag **diags, int pos, int length, int up) { struct diag *dg = diags[pos]; if(up) { if(pos<=3) return; int parent = (pos-1)/2; struct diag *pdg = diags[parent]; if( (pdg->total_weight*pdg->weight_fac)< (dg->total_weight*dg->weight_fac)) { //if( (pow(pdg->total_weight,2)*pdg->weight_fac)< (pow(dg->total_weight,2)*dg->weight_fac)) { diags[parent]=dg; diags[pos] = pdg; // printf("heapify: %i %i %i %i %i\n", pos,parent, length, dg, pdg); heapify_diag_array(diags, parent,length,up); } } else { int lchild = 2*pos+1; if( (lchild)>=length) return; int rchild = lchild+1; //struct diag *dg = diags[pos]; struct diag *ldg = diags[lchild]; struct diag *rdg = (rchild>=length ? ldg : diags[rchild]); int greatest = pos; if( (ldg->total_weight*ldg->weight_fac) > (diags[greatest]->total_weight * diags[greatest]->weight_fac)) greatest = lchild; //if( (pow(ldg->total_weight,2)*ldg->weight_fac) > (pow(diags[greatest]->total_weight,2) * diags[greatest]->weight_fac)) greatest = lchild; if( (rchildtotal_weight*rdg->weight_fac) > (diags[greatest]->total_weight*diags[greatest]->weight_fac))) greatest = rchild; //if( (rchildtotal_weight,2)*rdg->weight_fac) > (pow(diags[greatest]->total_weight,2) *diags[greatest]->weight_fac))) greatest = rchild; if(greatest != pos) { diags[pos] = diags[greatest]; diags[greatest] = dg; heapify_diag_array(diags, greatest,length,up); } } } /** *------------------------------------------------------------------------------------------ * SIMPLE ALIGNER SECTION *------------------------------------------------------------------------------------------ */ /** * test function that constructs an arbitrary consistent alignment.this function * is used to check the the correctness of adapt_diag() and align_diag() * * Returns whether something new could be aligned */ char simple_aligner(struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct alignment *algn, int round) { int dlen = dcol->diag_amount; int i; struct diag * dg,*tdg; char changed; char alignedSomething = 0; // compute counter weights // heapify struct diag **diags = dcol->diags; //calloc(dlen, sizeof(struct diag *)); int alloc_dlen = dlen; for(i= (dlen+1)/2-1;i>=0;i--) { heapify_diag_array(diags, i, dlen,0); } //memset(algn->redo_seqs, 0, sizeof(char)*slen*slen); double oldweight=0.0, prevweight; i=0; double total_weight = 0.0; double alig_time = 0.0; double tclock; struct diag tmp_diag; int tmp_end; int offset; struct diag *hookdg; while(dlen>0) { // printf(" dlen %i\n", dlen); dg = diags[0]; //if(dg->score==217) print_diag(dg); changed = 0; // print_diag(dg); // hookdg = NULL; if(dg!=NULL) { if((dg->length>0) && (dg->meetsThreshold || dg->anchor) ) { /* if(oldweight > 0.0) if(dg->weight > oldweight) { //printf(" ALARM %.20f %.20f\n", oldweight, dg->weight); //print_diag(&odg); //print_diag(dg); //intf(" %i %i \n", odg, dg); } */ //odg = *dg; //printf(" pre changed\n"); prevweight = dg->weight; tmp_diag = *dg; changed= adapt_diag(algn,smatrix, dg); //changed= adapt_diag(algn,NULL, dg); //print_diag(dg); //printf(" after changed %i\n", dg->length); //if(dg!=NULL) printf(" diag %i %i %i %i %.20f %i %i\n", dg, dg->multi_dg, dg->length, dg->meetsThreshold,dg->weight, dg->multi_length,changed); if(changed) { //printf("\nCHANGED\n"); //print_diag(dg); //printf(" pre recalc\n"); calc_weight(dg, smatrix, pdist); if(dg->anchor) { *dg = tmp_diag; } if( (dg->length > 0) && !(dg->anchor)) { tmp_end = tmp_diag.seq_p1.startpos+tmp_diag.length-1; if( ((dg->seq_p1.startpos+dg->length-1)< tmp_end) && !(dg->multi_dg)) { offset = dg->seq_p1.startpos+dg->length-tmp_diag.seq_p1.startpos; tmp_diag.seq_p1.startpos += offset; tmp_diag.seq_p2.startpos += offset; tmp_diag.length -= offset; adapt_diag(algn,smatrix, &tmp_diag); tmp_diag.length = tmp_end - tmp_diag.seq_p1.startpos+1; calc_weight(&tmp_diag, smatrix, pdist); if((tmp_diag.length>0)&& tmp_diag.meetsThreshold) { hookdg = malloc(sizeof(struct diag)); *hookdg = tmp_diag; hookdg->marked = 1; dcol->diag_amount++; if(dcol->diag_amount>alloc_dlen) { //printf("\n\n\nresize %i %i\n\n\n", dlen, alloc_dlen); alloc_dlen += 8; dcol->diags = (diags = realloc(diags, sizeof(struct diag*)*alloc_dlen)); if(diags==NULL) error("Error increasing diag heap durign aligning."); } //print_diag(hookdg); //printf("dlen %i damount %i %i\n", dlen, dcol->diag_amount, hookdg); //free(diags[dcol->diag_amount-1]); dlen++; diags[dcol->diag_amount-1] = diags[dlen-1]; diags[dlen-1]=hookdg; if(dlen>=2) { //printf("heapify: %i\n", dlen-1); heapify_diag_array(diags,dlen-1,dlen,1); } //print_diag(hookdg); } } } else { dg->meetsThreshold=0; } //printf(" \nafter recalc %i %.20f %.20f\n",dg->length, oldweight, dg->weight); //printf("%.20f %.20f\n", oldweight, dg->weight); //if(dg->weightmeetsThreshold = 0; // TODO: reactivate !!! //(dg->weightweight>oldweight) printf(" WEIGHT %e %e\n", dg->weight, oldweight); //algn->redo_seqs[dg->seq_p1.num*slen+dg->seq_p2.num] = 1; //algn->redo_seqs[dg->seq_p2.num*slen+dg->seq_p1.num] = 1; // DELETE THIS: //dg->meetsThreshold = 0; //if(para->DO_OVERLAP) calc_ov_weight(dg, dcol, smatrix, pdist); } else { //printf(" Pre align\n"); //print_diag(dg); if(para->DEBUG >1) tclock = clock(); //if(dg->anchor) printf(" ANCHOR %.20f %.20f\n", dg->weight, dg->total_weight); alignedSomething = align_diag(algn, smatrix, dg) || alignedSomething; if(para->DEBUG >1) alig_time += clock()-tclock; if(para->DEBUG >1) total_weight += dg->total_weight; //printf(" After align\n"); //if(para->DEBUG >2) printf(" aligned diag %i %e\n", i, dg->weight); //dg->length = 0; //dg->weight = 0.0; dg->meetsThreshold = 0; } } else { // printf("ALARM %i %i %Le\n", i, dg->length, dg->weight); oldweight = dg->weight; } } if((dg==NULL) || (!dg->meetsThreshold)) { tdg = diags[dlen-1]; diags[dlen-1]=dg; diags[0] = tdg; dlen--; } heapify_diag_array(diags, 0, dlen,0); } // if(para->DEBUG >1) printf(" Total Weight: %.20f (total %f) with pure alignment time %f \n", total_weight, algn->total_weight, alig_time/CLOCKS_PER_SEC); if(para->DEBUG >1) printf(" Total Weight: %.20f with pure alignment time %f \n", total_weight, alig_time/CLOCKS_PER_SEC); // return algn; return alignedSomething; } /** *------------------------------------------------------------------------------------------ * COMPLEX ALIGNER SECTION *------------------------------------------------------------------------------------------ */ /** * returns a value >0 if the given diags are in conflict within the given alignment * returns a value <0 if there is an non-conflicting overlap * returns 0 in all other non-conflicting cases */ static char confl_diag(struct alignment *algn, char *layer, struct diag *dg1, struct diag *dg2) { // if(dg1->multi_dg || dg2->multi_dg) error(" confl_diag(): cannot accept multi dgs!"); int s1_1 = dg1->seq_p1.num; int s1_2 = dg1->seq_p2.num; int s2_1 = dg2->seq_p1.num; int s2_2 = dg2->seq_p2.num; int ts; int sp1_1 = dg1->seq_p1.startpos; int sp1_2 = dg1->seq_p2.startpos; int sp2_1 = dg2->seq_p1.startpos; int sp2_2 = dg2->seq_p2.startpos; int tsp; int sl1_1 = dg1->seq_p1.sq->length; int sl1_2 = dg1->seq_p2.sq->length; int sl2_1 = dg2->seq_p1.sq->length; int sl2_2 = dg2->seq_p2.sq->length; int tsl; struct algn_pos* ap1_1; struct algn_pos* ap1_2; struct algn_pos* ap2_1; struct algn_pos* ap2_2; int p1_1, p1_2, p2_1, p2_2; int off1, off2; int l1 = dg1->length; int l2 = dg2->length; int pF1, pF2, sF1, sF2; int opF1, opF2, osF1, osF2; int pos2[4]; int lpos2 = 0; int ret = 0; signed char ucmp,lcmp; //l1=1;l2=1; /* int step1 = (l1>10) ? 3 : 1; int step2 = (l2>10) ? 3 : 1;; if(step1==0) step1 = 1; if(step2==0) step2 = 1; */ if(layer[dg1->seq_p1.num]!=1) { ts = s1_2; s1_2 = s1_1; s1_1 = ts; tsl = sl1_2; sl1_2 = sl1_1; sl1_1 = tsl; tsp = sp1_2; sp1_2 = sp1_1; sp1_1 = tsp; } if(layer[dg2->seq_p1.num]!=1) { ts = s2_2; s2_2 = s2_1; s2_1 = ts; tsl = sl2_2; sl2_2 = sl2_1; sl2_1 = tsl; tsp = sp2_2; sp2_2 = sp2_1; sp2_1 = tsp; } // if one is included in the other we define it as a conflict //if( (s1_1==s2_1) && (s1_2==s2_2)) { // //} opF1 = -1; osF1 = sl2_1; opF2 = -1; osF2 = sl2_2; for(off1=0;off1seq_p1.startpos+off1; p1_2 = sp1_2; // dg1->seq_p2.startpos+off1; ap1_1 = find_eqc(algn->algn, s1_1, p1_1); ap1_2 = find_eqc(algn->algn, s1_2, p1_2); // calculate the positions in dg2 that have to be considered for conflicts if(ap1_1->predF!=NULL) { pF1 = ap1_1->predF[s2_1]; } else { pF1 = opF1; } if(ap1_1->succF!=NULL) { sF1 = ap1_1->succF[s2_1]; } else { sF1 = osF1; } if(ap1_2->predF!=NULL) { pF2 = ap1_2->predF[s2_2]; } else { pF2 = opF2; } if(ap1_2->succF!=NULL) { sF1 = ap1_2->succF[s2_2]; } else { sF2 = osF2; } /* //if(ret==0) if( (pF1>=sp2_1) && (pF1!=opF1) && (pF1=sp2_1) && (sF1!=osF1)&& (sF1=sp2_2) && (pF2!=opF2) && (pF2=sp2_2) && (sF2!=osF2)&& (sF2= sp2_1+l2) { pF1 = sp2_1+l2-1; off1 = l1; } if(sF1 < sp2_1) { sF1 = sp2_1; off1 = l1; } if(sF1 >= sp2_1+l2) { sF1 = sp2_1+l2-1; } if(pF2 < sp2_2) { pF2 = sp2_2; } if(pF2 >= sp2_2+l2) { pF2 = sp2_2+l2-1; off1 = l1; } if(sF2 < sp2_2) { sF2 = sp2_2; off1 = l1; } if(sF2 >= sp2_2+l2) { sF2 = sp2_2+l2-1; } lpos2 = 0; if((pF1!=opF1)) { pos2[lpos2++] = pF1-sp2_1; } if((pF2!=opF2)) { pos2[lpos2++] = pF2-sp2_2; } if((sF1!=osF1)) { pos2[lpos2++] = sF1-sp2_1; } if((sF2!=opF2)) { pos2[lpos2++] = sF2-sp2_2; } opF1 = pF1; opF2 = pF2; osF1 = sF1; osF2 = sF2; //for(off2=0;off2algn, s2_1, p2_1); ap2_2 = find_eqc(algn->algn, s2_2, p2_2); ucmp = -1; lcmp = -1; // upper compare if(s1_1==s2_1) { if(p1_1 == p2_1) ucmp = 0; if(p1_1 < p2_1) ucmp = 1; if(p1_1 > p2_1) ucmp = 2; } else if( (ap1_1->succF!=NULL) && (ap1_1->predF!=NULL) && (ap1_1->succF[s2_1]==ap1_1->predF[s2_1]) && (ap1_1->predF[s2_1]==p2_1)) { ucmp = 0; } else if( ( (ap1_1->succF!=NULL) && ( ap1_1->succF[s2_1]<=p2_1))) { ucmp = 1; } else if( ( (ap1_1->predF!=NULL) && ( ap1_1->predF[s2_1]>=p2_1))) { ucmp = 2; } // lower compare if(s1_2==s2_2) { if(p1_2 == p2_2) lcmp = 0; if(p1_2 < p2_2) lcmp = 1; if(p1_2 > p2_2) lcmp = 2; } else if( (ap1_2->succF!=NULL) && (ap1_2->predF!=NULL) && (ap1_2->succF[s2_2]==ap1_2->predF[s2_2]) && (ap1_2->predF[s2_2]==p2_2)) { lcmp = 0; } else if( ( (ap1_2->succF!=NULL) && ( ap1_2->succF[s2_2]<=p2_2))) { lcmp = 1; } else if( ( (ap1_2->predF!=NULL) && ( ap1_2->predF[s2_2]>=p2_2))) { lcmp = 2; } if( (ucmp>=0) && (lcmp>=0)) { if(ucmp!=lcmp) return 1; } } } /* ret = -ret; if((ret<=l1*0.1)&&(ret<=l2*0.1)) { return 0; } else { return -1; } */ return ret; } /** * determine the best diags that fit into the alignment struct simple_diag_col *determine_diags((struct alignment *algn, struct seq_col *scol, struct scr_matrix *smatrix, struct prob_dist *pdist, char *layer, struct diag **diags, int diag_amount) { struct simple_diag_col scol; // TODO return scol; } */ /** * guided aligner recursion * * doHigher: >0 - only higher and equal than threshold weight * doHigher: 0 - only lower than threshold weight */ struct alignment* guided_aligner_rec(struct alignment *palgn, struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct gt_node *gtn, double thres_weight, char doHigher, int round) { if(palgn==NULL) { palgn = create_empty_alignment(scol); } // recursion as per the guide tree if(gtn->isLeaf) return palgn; palgn = guided_aligner_rec(palgn,scol,dcol,smatrix,pdist, gtn->succ1, thres_weight,doHigher,round); palgn = guided_aligner_rec(palgn,scol,dcol,smatrix,pdist, gtn->succ2, thres_weight,doHigher,round); // now align the fragments that are between succ1 and succ2 of gtn int scol_len = scol->length; struct diag *dg, *tdg, *sdg, *stdg; int i,j,si,sj,k,l, l1,l2; struct gt_node *n1, *n2; n1 = gtn->succ1; n2 = gtn->succ2; int diag_amount = dcol->diag_amount;//n1->seq_num_length + n2->seq_num_length; double multi_weight_fac = 0.0; int diag_p=0; struct diag **all_diags = malloc(sizeof( struct diag*)*diag_amount); //struct diag *looser_diags[diag_amount]; int diag_l=0; struct simple_diag_col *sdcol; //char crossing[scol_len*scol_len]; char changed; char layer[scol_len]; // memset(crossing, 0, sizeof(char)*scol_len*scol_len); memset(layer, 0, sizeof(char)*scol_len); for(i=0;iseq_num_length;i++) { si = n1->seq_num[i]; layer[si]=1; for(j=0;jseq_num_length;j++) { sj = n2->seq_num[j]; if(i==0) layer[sj]=2; //printf(" %i %i %i %i\n", i,j,si,sj); //crossing[si*scol_len+sj] = 1; //crossing[sj*scol_len+si] = 1; if(sj>si) { sdcol = dcol->diag_matrix[scol_len*si+sj]; } else { sdcol = dcol->diag_matrix[scol_len*sj+si]; } multi_weight_fac += pow(sdcol->weight_fac,0.5); for(k=0;klength;k++) { dg = (sdcol->data[k]); //changed = adapt_diag(palgn, smatrix, dg); //if(changed) { //calc_weight(dg, smatrix, pdist); //} if(dg->meetsThreshold) { if(doHigher>0) { if((dg->total_weight) >= thres_weight) { all_diags[diag_p++] = dg; } } else { if((dg->total_weight) < thres_weight) { all_diags[diag_p++] = dg; } } } } } } multi_weight_fac = pow(multi_weight_fac/((double)n1->seq_num_length*n2->seq_num_length),2.0); struct diag_col tdcol; int survive; /* tdcol.diags = all_diags; tdcol.diag_amount = diag_p; simple_aligner(scol, &tdcol, smatrix, pdist, palgn, 0); return palgn; */ /* struct simple_diag_col ssdcol = split_diags(palgn, scol, smatrix, pdist, all_diags, diag_p); struct diag **sall_diags = ssdcol.data; int sdiag_p = ssdcol.length; printf(" diags split before:%i after:%i\n", diag_p, sdiag_p); */ int sdiag_p = diag_p; struct diag **sall_diags = all_diags; // if both successor nodes are leaf align directly if(n1->isLeaf && n2->isLeaf) { tdcol.diags = all_diags; tdcol.diag_amount = diag_p; //printf(" before inner rec %i %i %i\n",all_diags,diag_p,diag_amount); simple_aligner(scol, &tdcol, smatrix, pdist, palgn, 0); //printf(" after inner rec %i\n",all_diags); free(all_diags); //printf(" after inner rec\n"); return palgn; } //if( (n1->seq_num_length > 1) && (n2->seq_num_length > 1)) { // OMIT for the time being /* if( ((n1->seq_num_length>1) || (n2->seq_num_length>1)) && ((n1->seq_num_length*n2->seq_num_length)>=4.0) && ((n1->seq_num_length > sqrt(scol->length)) || (n2->seq_num_length > sqrt(scol->length)))) { int ***diag_info; diag_info = malloc(sizeof(int **)*n1->seq_num_length); for(i=0;iseq_num_length;i++) { diag_info[i] = malloc(sizeof(int *)*n2->seq_num_length); } struct seq *seq1, *seq2; int maxk; for(i=0;iseq_num_length;i++) { si = n1->seq_num[i]; for(j=0;jseq_num_length;j++) { sj = n2->seq_num[j]; seq1 = &(scol->seqs[si]); seq2 = &(scol->seqs[sj]); // prepare diag info diag_info[i][j] = malloc(sizeof(int)*seq1->length); for(k=0;klength;k++) { diag_info[i][j][k] = -1; } if(sj>si) { sdcol = dcol->diag_matrix[scol_len*si+sj]; } else { sdcol = dcol->diag_matrix[scol_len*sj+si]; } for(k=0;klength;k++) { dg = (sdcol->data[k]); if(dg->meetsThreshold) { for(l=0;llength;l++) { if( (dg->weight >= thres_weight)) { if(dg->seq_p1.num==si) { //printf(" 1) %i %i %i\n",dg->seq_p1.startpos+l, dg->length, seq1->length); diag_info[i][j][dg->seq_p1.startpos+l] = dg->seq_p2.startpos+l; } else { //printf(" 2) %i %i %i \n",dg->seq_p2.startpos+l,dg->length, seq1->length); diag_info[i][j][dg->seq_p2.startpos+l] = dg->seq_p1.startpos+l; } } } } } } } //printf(" before guided diags\n"); struct simple_diag_col *mscol = find_diags_guided(smatrix, pdist,n1, n2, palgn, thres_weight, diag_info); //printf(" after guided diags\n"); for(i=0;iseq_num_length;i++) { si = n1->seq_num[i]; for(j=0;jseq_num_length;j++) { sj = n2->seq_num[j]; free(diag_info[i][j]); // free_tmp_pdist(tmp_dist[sj][si], pdist->max_dlen); } free(diag_info[i]); } free(diag_info); diag_amount += mscol->length; all_diags = realloc(all_diags, sizeof( struct diag*)*diag_amount); sall_diags = all_diags; for(i=0;ilength;i++) { //printf(" multi dg %i %i %.20f\n", mscol->length,mscol->data[i], mscol->data[i]->weight); //survive = 1; dg = mscol->data[i]; survive = 0; dg->weight = 0.0; for(j=0;jmulti_length;j++) { if( (dg->multi_cont[j]!=NULL) && (dg->multi_cont[j]->weight >= thres_weight)) { survive++; dg->weight += dg->multi_cont[j]->weight; } else { free_diag(dg->multi_cont[j]); dg->multi_cont[j]=NULL; } } dg->total_weight = dg->weight; if(survive>1) { sall_diags[sdiag_p++] = mscol->data[i]; mscol->data[i]->weight_fac = multi_weight_fac; mscol->data[i]->pred_diag = NULL; } else { free_diag(mscol->data[i]); } } // free data free(mscol->data); free(mscol); } if(para->DEBUG>1) printf(" Found %i relevant multi diags\n", sdiag_p - diag_p); */ diag_p = sdiag_p; struct diag **looser_diags = malloc(sizeof( struct diag*)*diag_amount); /* // sort diags for(i=0;itotal_weight*dg->weight_fac) > (dg->total_weight*dg->weight_fac)) { if( (tdg->total_weight) > (dg->total_weight)) { sall_diags[i] = tdg; sall_diags[j]= dg; } } } // align the good diags first diag_l=0; for(i=0;iDEBUG>2) printf(" BEGIN: calc conflict of #diags: %i\n", sdiag_p); // build vertex cover graph char confl; int multilen1; int multipos1; int multilen2; int multipos2; char multi1, multi2; for(i=0;iweight_fac = 1.0; dg->weight_sum = dg->total_weight;//*dg->weight_fac; multilen1 = 1; multipos1 = 0; multi1 = dg->multi_dg; if(multi1) multilen1 = dg->multi_length; //dg->weight_sum = dg->total_weight; //printf(" degree %i\n", dg->degree); sdg = dg; while(multipos1multi_cont[multipos1]; if(dg!=NULL) { for(j=i+1;jmulti_dg; if(multi2) multilen2 = tdg->multi_length; stdg = tdg; while(multipos2multi_cont[multipos2]; if(tdg!=NULL) { confl = confl_diag(palgn, layer, dg, tdg) ; if( (confl>0) ) { //printf(" conflict %i %i !\n",i,j); sdg->degree++; if(sdg->degree > sdg->max_degree) { sdg->max_degree += 64; sdg->neighbours = realloc(sdg->neighbours, sizeof(struct diag *)*sdg->max_degree); } sdg->neighbours[sdg->degree - 1] = stdg; stdg->degree++; if(stdg->degree > stdg->max_degree) { stdg->max_degree += 64; stdg->neighbours = realloc(stdg->neighbours, sizeof(struct diag *)*stdg->max_degree); } stdg->neighbours[stdg->degree - 1] = sdg; //printf(" CONFLICT FOUND %i %i!\n", i,j); } } multipos2++; } } } multipos1++; } } // if(para->DEBUG>2) printf(" END: calc conflict of #diags: %i\n", sdiag_p); // perform clarkson vertex cover int max_n; double max_d; double t_d; while(1) { max_n = -1; max_d = -1.0; for(i=0;idegree); //printf(" before %i %i %i\n",i,sdiag_p,dg); //printf(" degree %i\n", dg->degree); //printf(" after\n"); if(dg->degree > 0) { t_d = dg->degree / dg->weight_sum; if((max_dmulti_dg, dg->total_weight); //printf(" 0sall[0] %i \n",sall_diags[0]); //i=11; //printf(" 00sall[0] %i \n",sall_diags[0]); for(i=0; i < dg->degree; i++) { //printf(" 1sall[0] %i i=%i\n",sall_diags[0],i); //printf(" %i %i\n",i,dg->degree); dg->neighbours[i]->weight_sum -= max_d; tdg = dg->neighbours[i]; //printf(" before loop %i %i\n",i,dg->degree); for(j=0;jdegree;j++) { if(tdg->neighbours[j]==dg) { //printf(" MATCH \n"); tdg->neighbours[j]=tdg->neighbours[tdg->degree-1]; tdg->degree--; j=tdg->degree;//break; } } //printf(" 2sall[0] %i\n",sall_diags[0]); } free(dg->neighbours); dg->neighbours=NULL; dg->degree = 0; dg->max_degree=0; } /* struct algn_pos *ap1 = find_eqc(palgn->algn,4,19); if(ap1->predF!=NULL)printf(" 4-19 predF-0 %i\n", ap1->predF[0]); ap1 = find_eqc(palgn->algn,0,4); if(ap1->succF!=NULL)printf(" 0-4 succF-4 %i\n", ap1->succF[4]); */ //if( (sdiag_p>60) && (sall_diags[60]!=NULL)) sall_diags[0]=sall_diags[60]; /* if((sdiag_p>60) && (sall_diags[60]!=NULL) && (sall_diags[52]!=NULL)) { printf(" conflict pre %i\n", confl_diag(palgn, layer, sall_diags[52], sall_diags[60])); } */ /* for(i=0;iseq_p1.num, dg->seq_p1.startpos, dg->length); //printf(" b) %i %i %i\n\n", dg->seq_p2.num, dg->seq_p2.startpos, dg->length); //rdg = *dg; //printf(" before adapt %i %i\n", i, sdiag_p); changed = adapt_diag(palgn, smatrix, dg); //printf(" after adapt %i %i %i %i %i\n", changed, i, sdiag_p, rdg.length,dg->length); if(changed) { calc_weight(dg, smatrix, pdist); looser_diags[diag_l++] = dg; } else { //if(dg->meetsThreshold) { align_diag(palgn, smatrix, dg); //} dg->meetsThreshold = 0; } if(dg->neighbours!=NULL) { free(dg->neighbours); dg->neighbours = NULL; } } else { } } */ // align the winners first tdcol.diags = all_diags; tdcol.diag_amount = 0; for(i=0;imulti_dg, sall_diags[i]->total_weight); all_diags[tdcol.diag_amount++] = sall_diags[i]; } } simple_aligner(scol, &tdcol, smatrix, pdist, palgn, 0); all_diags = tdcol.diags; for(i=0;imarked ) { //printf(" free %i %i %i\n", all_diags[i], all_diags[i]->multi_dg, looser_diags[0]); free_diag(all_diags[i]); //printf(" free end%i\n", all_diags[i]); } else { if(all_diags[i]->neighbours!=NULL) { free(all_diags[i]->neighbours); all_diags[i]->neighbours=NULL; } all_diags[i]->meetsThreshold = 0; } } // align the loosers afterwards tdcol.diags = looser_diags; tdcol.diag_amount = diag_l; simple_aligner(scol, &tdcol, smatrix, pdist, palgn, 0); looser_diags = tdcol.diags; for(i=0;imarked ) { //printf(" lfree %i %i %i %i %i %i\n", i, diag_l, tdcol.diag_amount, looser_diags[i], all_diags[i]->multi_dg, looser_diags[0]); free_diag(looser_diags[i]); //printf(" lfree end%i\n", all_diags[i]); } else { if(looser_diags[i]->neighbours!=NULL) { free(looser_diags[i]->neighbours); looser_diags[i]->neighbours=NULL; } looser_diags[i]->meetsThreshold = 0; } } //printf("-----------------END GUIDED ALIGNER RECURSION STEP-------------------\n"); // TODO: free/remove used diags //free(sall_diags); free(all_diags); free(looser_diags); return palgn; } /** * guided aligner method * NOTE: all diags are freeded within this routine */ struct alignment* guided_aligner(struct alignment *palgn, struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct gt_node *gtn, int round) { struct diag **all_diags = dcol->diags; int diag_p = dcol->diag_amount; struct diag *dg, *tdg; int i,j,k; /* // sort diags for(i=0;itotal_weight*dg->weight_fac) > (dg->total_weight*dg->weight_fac)) { if( (tdg->total_weight) > (dg->total_weight)) { all_diags[i] = tdg; all_diags[j]= dg; } } } */ int slen = scol->length; double tavg, ttavg; double avg_weight = 0.0; struct simple_diag_col *sdcol; int tsdlen=0; ttavg = 0; for(i=0;idiag_matrix[slen*i+j]; for(k=0; klength; k++) { tavg +=sdcol->data[k]->total_weight; ttavg += sdcol->data[k]->total_weight; tsdlen++; } if(sdcol->length >0) { tavg = (tavg/sdcol->length); } /* tavg = 0.0; tsdlen = 0; for(k=0; klength; k++) { if(sdcol->data[k]->total_weight >= ttavg) { tavg +=sdcol->data[k]->total_weight; tsdlen++; } } tavg = tavg / tsdlen; */ avg_weight += tavg; } } avg_weight = avg_weight/ (slen*(slen-1)/2.0); double thres_weight = ttavg/tsdlen;//1.0*avg_weight; //all_diags[ 0]->total_weight*0.05; palgn = guided_aligner_rec(palgn,scol,dcol,smatrix,pdist,gtn,thres_weight,1,round); //palgn = guided_aligner_rec(palgn,scol,dcol,smatrix,pdist,gtn,thres_weight,0,round); //printf(" intermediate alignment weight %f %f\n",palgn->total_weight, thres_weight); struct diag_col tdcol; struct diag **sall_diags = malloc(sizeof(struct diag*)*diag_p); int sdiag_p=0; for(i=0;imeetsThreshold && (all_diags[i]->total_weight < thres_weight)) { sall_diags[sdiag_p++] = all_diags[i]; } else { free(all_diags[i]); } } tdcol.diags = sall_diags; tdcol.diag_amount = sdiag_p; simple_aligner(scol, &tdcol, smatrix, pdist, palgn, 0); sall_diags = tdcol.diags; for(i=0;idiag_amount = diag_p; return palgn; } abyss-2.2.4/dialign/diag.c000066400000000000000000001623111361462241400153260ustar00rootroot00000000000000#include #include #include #include #include #include #include "parameters.h" #include "struct.h" #include "io.h" extern void error(char *message); extern void merror(char *msg1, char *msg2); extern struct algn_pos *find_eqc(struct algn_pos **ap, int seqnum, int pos); extern void prepare_alignment(struct alignment *algn); /** * * diag.c: Creation of diagonals & calculation of scores and weights * */ /** * factory method that creates a diagonal from the given sequence parts * * The pointer returned has to be deallocted explicitely from memory. */ struct diag* create_diag(int n1, struct seq* sq1, unsigned int sp1, int n2, struct seq* sq2, unsigned int sp2, int dlength) { struct diag* dg = malloc(sizeof(struct diag)); if(dg==NULL) error("create_diag(): Out of Memory !"); if(sq1->length < sp1+dlength) { printf(" startpos=%i diaglength=%i seqlength=%i\n",sp1,dlength,sq1->length); merror("create_diag(): startpos+diaglength exceeds sequence length in diag ", sq1->name); } if(sq2->length < sp2+dlength) { printf(" startpos=%i diaglength=%i seqlength=%i\n",sp2,dlength,sq2->length); merror("create_diag(): startpos+diaglength exceeds sequence length in diag ", sq2->name); } dg->seq_p1.num = n1; dg->seq_p1.sq = sq1; dg->seq_p1.startpos = sp1; //dg->seq_p1.leftmargin = sp1; //dg->seq_p1.rightmargin = sq1->length - dlength - sp1; dg->seq_p2.num = n2; dg->seq_p2.sq = sq2; dg->seq_p2.startpos = sp2; //dg->seq_p1.leftmargin = sp2; //dg->seq_p1.rightmargin = sq2->length - dlength - sp2; dg->pred_diag = NULL; dg->col_pred_diag = NULL; dg->length = dlength; //dg->onlyOverThres= 0; dg->score= -1; dg->orig_score= -1; dg->weight = 0.0; dg->weight_sum = 0.0; dg->ov_weight = 0.0; dg->weight_fac = 1.0; dg->anchor = 0; dg->marked = 0; dg->multi_dg = 0; dg->multi_cont = NULL; dg->multi_length = 0; dg->meetsThreshold = 0; dg->neighbours = NULL; dg->degree = 0; dg->max_degree= 0; return dg; } /** * frees the memory of the given diagonal and the included seq_parts */ void free_diag(struct diag* dg) { if(dg->multi_dg) { int i; for(i=0;imulti_length;i++) { if(dg->multi_cont[i]!=NULL) free_diag(dg->multi_cont[i]); } free(dg->multi_cont); } free(dg); } /** * frees the (sub) tree of the given gt_node */ void free_gt_node(struct gt_node *gtn) { if(! gtn->isLeaf) { free_gt_node(gtn->succ1); free_gt_node(gtn->succ2); } free(gtn->seq_num); free(gtn); } /** * calculuates "m over n" */ unsigned long binomial(long m, long n) { double result=1.0; long i; for(i=0;imax_dlen; struct scr_matrix *smatrix = pdist->smatrix; long double **dist = calloc(length+1, sizeof(long double *)); if(dist==NULL) error("create_tmp_pdist(): (1) Out of memory when allocating data !"); int i; long mxscr, sm_max_scr=smatrix->max_score; for(i=0;i<=length;i++) { mxscr = i *sm_max_scr; dist[i] = calloc(mxscr+1, sizeof(long double )); if(dist[i]==NULL) error("create_tmp_pdist(): (3) Out of memory at iteration" ); } return dist; } /** * frees temporary probability distribution */ void free_tmp_pdist(long double **dist, int length) { int i; for(i=0;i<=length;i++) { free(dist[i]); } free(dist); } void fill_tmp_pdist(struct prob_dist *pdist, long double **tmp_dist, int slen1, int slen2) { unsigned int length = pdist->max_dlen; struct scr_matrix * smatrix = pdist->smatrix; unsigned int i; long mxscr, sm_max_scr=smatrix->max_score,scr; long double factor, np, np2,prob; long double seq_factor= (((long double)slen1)*(slen2)); for(i=1;i<=length;i++) { mxscr = i *sm_max_scr; factor = (long double)(seq_factor)/(long double)(4.0*i*i); // original ! for(scr=0;scr<=mxscr;scr++) { prob = pdist->data[i][scr]; np2 =prob * (factor); if(np2>=para->DIAG_CALC_WEIGHT_THRESHOLD) { // curent np = (long double)1.0- pow(1.0-prob,factor); // current } else { np = np2; } tmp_dist[i][scr] = -log(np); } } } /** * calculates the score of the given diag by using the given score matrix. the * resulting score is stored within the diag * omitScore = -1: score calculation but weight interpolation with seqlen = 100 * omitScore = 0: normal * omitScore = 1: no score calculation */ static void real_calc_weight(struct diag* dg, struct scr_matrix* smatrix, struct prob_dist *pdist, char omitScore, long double **tmp_dist, struct alignment *algn ) { if(dg->multi_dg) { int i; dg->weight = 0.0; dg->meetsThreshold = 0; dg->length = 0; for(i=0;imulti_length;i++) { if(dg->multi_cont[i]!=NULL) { //printf(" before real calc %i %i %f\n", dg->length, dg->score, dg->weight); real_calc_weight(dg->multi_cont[i],smatrix, pdist, omitScore, tmp_dist, algn); if(dg->multi_cont[i]->length > dg->length) dg->length = dg->multi_cont[i]->length; //printf(" real calc %i %i %f\n", dg->length, dg->score,dg->weight); dg->weight += dg->multi_cont[i]->weight; dg->meetsThreshold = dg->meetsThreshold | dg->multi_cont[i]->meetsThreshold; //printf(" readjusted %i %i %i %i %i %i %f %f %i\n", dg, dg->multi_cont[i],dg->multi_cont[i], dg->multi_dg, dg->multi_length, dg->weight, dg->multi_cont[i]->weight, dg->length); } } if(dg->length<=0) dg->meetsThreshold = 0; dg->total_weight = dg->weight; return; } if(dg->length==0) { dg->score = 0; dg->weight = 0.0; dg->meetsThreshold = 0; return; } unsigned int len = dg->length; int pos; long double np=0.0,np2; if(omitScore<=0) { unsigned int sp1=dg->seq_p1.startpos; unsigned int sp2=dg->seq_p2.startpos; char *data1 = dg->seq_p1.sq->data; char *data2 = dg->seq_p2.sq->data; int a1, a2; int *c2n = smatrix->char2num; int *sdata = smatrix ->data; int slen = smatrix->length; dg->score = 0; for(pos=0;posscore+=(long)sdata[slen*a1+a2]; } } long double prob; long double factor; dg->meetsThreshold = 0; if(dg->score <= pdist->smatrix->avg_sim_score*dg->length) { dg->total_weight = 0.0; dg->ov_weight = 0.0; dg->weight_fac = 1.0; dg->weight = 0.0; return; } // interpolate only for splitted diags that fall beyond the threshold /* if( (dg->orig_score>0)) { //if( (dg->weight<=0.0) && (dg->orig_score>0)) { dg->weight = ((double)dg->score)/((double)dg->orig_score)*dg->weight_sum; // printf(" ws %.20f %.20f \n", dg->weight, dg->weight_sum); //if(dg->weight_sum>0.0) dg->weight = dg->weight_sum; }else */ if(len<=pdist->max_dlen) { if(tmp_dist==NULL) { prob =pdist->data[len][dg->score]; /* if(omitScore>=0) { factor = (long double)((len + dg->seq_p1.leftmargin + dg->seq_p1.rightmargin )* (len + dg->seq_p2.leftmargin + dg->seq_p2.rightmargin ))/(long double)(4.0*len*len); // original } else { factor = (long double)(10000.0)/(long double)(4.0*len*len); } */ //printf(" %i %i\n", dg->seq_p1.sq->length, len+dg->seq_p1.leftmargin+dg->seq_p1.rightmargin); if(omitScore>=0) { factor = (long double)((dg->seq_p1.sq->length )* (dg->seq_p2.sq->length ))/(long double)(4.0*len*len); // original } else { factor = (long double)(10000.0)/(long double)(4.0*len*len); } np2 =prob * (factor); if(np2>=para->DIAG_CALC_WEIGHT_THRESHOLD) { np = (long double)1.0- pow(1.0-prob,factor); // current } else { np = np2; } dg->weight = -log(np); } else { dg->weight = tmp_dist[len][dg->score]; } } dg->total_weight = (dg->weight);//+dg->ov_weight);//* dg->weight_fac; if( (dg->length >= para->DIAG_MIN_LENGTH) && (dg->weight > para->DIAG_THRESHOLD_WEIGHT)) { dg->meetsThreshold = 1; } else { } } void calc_weight(struct diag* dg, struct scr_matrix* smatrix, struct prob_dist *pdist) { real_calc_weight(dg, smatrix, pdist, 0,NULL,NULL); } /** * calculates the overlap weight for the given diag */ void calc_ov_weight(struct diag* dg, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist) { int sn1 = dg->seq_p1.num; int sn2 = dg->seq_p2.num; int snt, sn; struct seq *seq1 = dg->seq_p1.sq; struct seq *seq2 = dg->seq_p1.sq; struct diag* tdg = create_diag(sn1, seq1,0, 1, seq2,0,0); struct diag* dg2; struct simple_diag_col *sdcol; int i,j, slen=dcol->seq_amount, dlen; int sp1 = dg->seq_p2.startpos,tsp1; int tep1,t; double w; struct seq_part *seq_p, *d_seq_p1, *d_seq_p2; dg->ov_weight = 0.0; int tstartpos; if(dg->length >0) { for(sn=0;sn<2;sn++) { tstartpos = (sn==0 ? dg->seq_p1.startpos : dg->seq_p2.startpos); tdg->seq_p1.sq = (sn==0 ? seq1 : seq2); tdg->seq_p1.num = (sn==0 ? sn1 : sn2);; // other way seq_p = (sn==0 ? &dg->seq_p2 : &dg->seq_p1); tsp1 = seq_p->startpos; tep1 = seq_p->startpos+dg->length-1; snt = (sn==0 ? sn2 : sn1); //printf(" slen %i\n", slen); for(i=0; idiag_matrix[(snt < i) ? (snt*slen + i) : (i*slen+snt)]; tdg->seq_p2.num=i; dlen = sdcol->length; for(j=0;jdata[j]; if(sntseq_p1; d_seq_p2 = &dg2->seq_p2; } else { d_seq_p1 = &dg2->seq_p2; d_seq_p2 = &dg2->seq_p1; } if(j==0) { tdg->seq_p2.sq = d_seq_p2->sq; } if(dg2->length >0) { if(d_seq_p1->startpos>tsp1) tsp1 = d_seq_p1->startpos; t=d_seq_p1->startpos+dg2->length-1; if(tseq_p2.sq=dg2->seq_p2.sq; tdg->seq_p1.startpos = tstartpos + tsp1- sp1; tdg->seq_p2.startpos = d_seq_p2->startpos + tsp1- d_seq_p1->startpos; tdg->length = tep1-tsp1+1; //real_calc_weight(tdg, smatrix, pdist,-1,NULL,NULL); real_calc_weight(tdg, smatrix, pdist,0,NULL,NULL); if(tdg->meetsThreshold ) { w = tdg->weight; //printf("add %.20f\n",w); dg->ov_weight += w/2.0; //dg2->ov_weight += w; } } } } } } } } dg->total_weight = (dg->weight);//+dg->ov_weight)*dg->weight_fac;// + dg->ov_weight; free_diag(tdg); } /** * creates the collection of all diags * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct diag_col* create_diag_col(int seq_amount) { struct diag_col *dc = calloc(1, sizeof(struct diag_col)); if(dc==NULL) error("create_diag_col(): (1) Out of memory !"); //printf("go for k\n"); dc->diag_matrix = malloc(seq_amount*seq_amount* sizeof(struct simple_diag_col *)); //printf("2go for k\n"); dc->gt_root = NULL; if(dc->diag_matrix==NULL) error("create_diag_col(): (2) Out of memory !"); return dc; } /** * frees a diagcol and all data included in it */ void free_diag_col(struct diag_col* dcol) { int s1,s2,sl=dcol->seq_amount; // printf("damount: %i\n", dcol->diag_amount); //printf("--------------------------------\n"); for(s1 =0;s1diag_amount;s1++) { // print_diag(dcol->diags[s1]); //printf(" NO FREEEEEEEEEE %i %i\n", s1,dcol->diags[s1]); free_diag(dcol->diags[s1]); } free(dcol->diags); for(s1=0;s1diag_matrix[s1+sl*s2]->data); free(dcol->diag_matrix[s1+sl*s2]); } } free(dcol->diag_matrix); if(dcol->gt_root!=NULL) free_gt_node(dcol->gt_root); free(dcol); } /** * finds all relevant multi diags with respect to the given alignment * and two groups of sequences that come from the guided method * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ inline struct simple_diag_col* find_diags_guided(struct scr_matrix *smatrix, struct prob_dist *pdist, struct gt_node* n1, struct gt_node* n2, struct alignment *algn, double thres_weight, int*** diag_info) { struct simple_diag_col* dcol = calloc(1, sizeof(struct simple_diag_col)); if(dcol==NULL) error("find_diags_guided(): (1) Out of memory !"); prepare_alignment(algn); struct seq_col *scol = algn->scol; struct seq *seq1 = &(scol->seqs[n1->seq_num[0]]); struct seq *seq2 = &(scol->seqs[n2->seq_num[0]]); int slen = scol->length; int ni1, ni2; struct seq *seq_n1, *seq_n2; unsigned int size = 16; int length = 0; struct diag **data = calloc(size, sizeof(struct diag* )); // printf("go for k\n"); if(data==NULL) error("find_diags_guided(): (2) Out of memory !"); struct algn_pos *tap;// = find_eqc(algn->algn, seq1->num, seq1->length-1); long slen1 = algn->max_pos; long slen2 = slen1; unsigned int max_dlen = pdist->max_dlen; struct diag *sdg, *tsdg; struct diag *dg = create_diag(seq1->num, seq1,0, seq2->num, seq2,0,0); struct diag* tdg,*tdg2; int i,j,k,l,kposi,kposj,jmin=0,jmax=slen2; int sn1 = seq1->num; int sn2 = seq2->num; int *c2n = smatrix->char2num; int *sdata = smatrix ->data; char *data1;// = seq1->data; char *data2;// = seq2->data; int smatrixlen = smatrix->length; int a1,a2; int maxslen = slen1; if(slen2>maxslen) maxslen = slen2; //long double **tmp_dist = create_tmp_pdist(pdist); //fill_tmp_pdist(pdist, tmp_dist, slen1, slen1); int max_pool = (slen1+slen2-1); struct diag **diag_col = malloc(sizeof(struct diag*)*(slen1+1)); struct diag **diag_row = malloc(sizeof(struct diag*)*(slen2+1)); struct diag **pool_diags=malloc(sizeof(struct diag *)*max_pool); int pooled = 0; double thres_sim_score =para->PROT_SIM_SCORE_THRESHOLD; char hasAli = (algn!=NULL); double diag_thres = para->DIAG_THRESHOLD_WEIGHT; double avg_sim_score = pdist->smatrix->avg_sim_score; int maxd,maxd2,cons_maxd; int score1=0,score2 = 0; char prevail; int extended,passed;//,actuals; int passed2; int max_under = 0;//para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS; int max_under_inner =0;//2*para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS; double dg_thres_weight = thres_weight;// * n1->seq_num_length*n2->seq_num_length; //int min_motives = n1->seq_num_length; //if(n2->seq_num_length > min_motives) min_motives = n2->seq_num_length; //min_motives++; int min_motives = sqrt(n1->seq_num_length * n2->seq_num_length); if(min_motives<2) min_motives = 2; // if(min_motives>(n1->seq_num_length*n2->seq_num_length)) min_motives = (n1->seq_num_length * n2->seq_num_length); char stst; char mstatus; int slensq = slen*slen; int sqind; char startstop[slensq]; char startstop_pre[slen]; int c_klen[slensq]; int c_kscore[slensq]; int rev_pos[slen][slen1]; struct gt_node *tgtn; // build reverse algn pos int iterlen = 0; int iter[slen*slen]; for(ni1=0;ni1seq_num_length;ni1++) { sn1 = n1->seq_num[ni1]; for(ni2=0;ni2seq_num_length;ni2++) { //printf(" begin MARKER MARKER MARKER %i %i %i\n",i,j,k); sn2 = n2->seq_num[ni2]; sqind = sn1*slen+sn2; iter[iterlen++] = sqind; } } dg->multi_dg = 1; dg->marked = 1; dg->multi_length = slensq; dg->multi_cont = malloc(sizeof(struct diag *)*slensq); memset(dg->multi_cont, 0, sizeof(struct diag *)*slensq); for(i=0;imulti_cont[i]=NULL; } maxd = n1->seq_num_length + n2->seq_num_length; for(i=0;i=n1->seq_num_length) { k-=n1->seq_num_length; tgtn = n2; } ni1 = tgtn->seq_num[k]; seq_n1 = &(scol->seqs[ni1]); for(j=0;jlength;j++) { tap = find_eqc(algn->algn, seq_n1->num, j); rev_pos[ni1][*(tap->eqcAlgnPos)] = j; } } // DIALIGN for(k=0;k<=slen1;k++) { //printf(" begin %i %i %i %i\n",k,slen, seq1->num, seq2->num); diag_col[k]=create_diag(seq1->num, seq1,0, seq2->num, seq2,0,0); //printf(" middle\n"); diag_col[k]->multi_dg = 1; diag_col[k]->marked = 1; diag_col[k]->multi_length = 0; //diag_col[k]->length = 1; diag_col[k]->weight_sum = 0.0; diag_col[k]->weight = 0.0; diag_col[k]->meetsThreshold = 0; pool_diags[pooled] = diag_col[k]; pool_diags[pooled]->pool_pos = pooled; pooled++; //printf(" end %i %i\n",k,slen); } for(k=0;k<=slen2;k++) { diag_row[k] = diag_col[0]; } double old_weight; if(max_dlen> slen1/2.0) max_dlen = slen1/2.0; if(max_dlen> slen2/2.0) max_dlen = slen2/2.0; for(i=0;i<=slen1;i++) { // merge row/col //printf("before \n"); if(i>0) { tdg = diag_col[i]; while(tdg!=NULL) { kposi = tdg->seq_p2.startpos+tdg->length; //printf(" kposi %i %i %i\n", diag_row[kposi], kposi, slen2); if(tdg->weight_sum > diag_row[kposi]->weight_sum) { diag_row[kposi] = tdg; prevail = 1; } else { prevail = 0; } tdg2 = tdg; tdg = tdg->col_pred_diag; if(! prevail) { pool_diags[tdg2->pool_pos]=NULL; //printf(" BEFORE\n"); free_diag(tdg2); //printf(" AFTER\n"); } } } //printf("after \n"); for(j=1;j<=slen2;j++) { if(diag_row[j-1]->weight_sum > diag_row[j]->weight_sum) { diag_row[j] = diag_row[j-1]; } } if(i==slen1) break; for(j=jmin;jslen1) maxd = slen1-i; if( (j+maxd)>slen1) maxd = slen1-j; /* for(l=0;lmulti_cont[iter[l]]; if(sdg!=NULL) { free_diag(sdg); dg->multi_cont[iter[l]]=NULL; } } */ dg->seq_p1.startpos = i; dg->seq_p2.startpos = j; passed = 0; passed2 = 0; // actuals = 0; for(k=1;k<=maxd;k++) { //printf(" %i %i %i %i\n",i,j,k,slen1); kposi = i+k-1; kposj = j+k-1; maxd2 = maxd; maxd = 0; //printf(" k= %i\n",k); extended = 0; //mstatus = 0; for(ni1=0;ni1seq_num_length;ni1++) { sn1 = n1->seq_num[ni1]; seq_n1 = &(scol->seqs[sn1]); if( (rev_pos[sn1][kposi]>=0)&& (startstop_pre[sn1]!=2) ) { data1 = seq_n1->data; startstop_pre[sn1]=2; for(ni2=0;ni2seq_num_length;ni2++) { //printf(" begin MARKER MARKER MARKER %i %i %i\n",i,j,k); sn2 = n2->seq_num[ni2]; seq_n2 = &(scol->seqs[sn2]); sqind = sn1*slen+sn2; stst = startstop[sqind]; //if(stst==1) mstatus += stst; //printf(" end MARKER MARKER MARKER %i %i\n",sn2, kpos); if( (rev_pos[sn2][kposj]>=0) && (stst!=2) && (diag_info[ni1][ni2][rev_pos[sn1][kposi]]==rev_pos[sn2][kposj]) ) { dg->length = k; data2 = seq_n2->data; a1 = c2n[(int) data1[rev_pos[sn1][kposi]]]; a2 = c2n[(int) data2[rev_pos[sn2][kposj]]]; score2 = sdata[smatrixlen*a1+a2]; sdg = NULL; if( (stst==0) && (score2 >= thres_sim_score)) { //if(rev_pos[sn1][kpos]>1000) printf(" %i %i %i\n", sn1,kpos, rev_pos[sn1][kpos]); sdg = dg->multi_cont[sqind]; if(sdg==NULL) { sdg = create_diag(sn1, seq_n1, rev_pos[sn1][kposi], sn2, seq_n2, rev_pos[sn2][kposj],0); } else { sdg->seq_p1.num = sn1; sdg->seq_p1.sq = seq_n1; sdg->seq_p1.startpos = rev_pos[sn1][kposi]; sdg->seq_p2.num = sn2; sdg->seq_p2.sq = seq_n2; sdg->seq_p2.startpos = rev_pos[sn2][kposj]; sdg->length = 0; } sdg->score = 0; dg->multi_cont[sqind] = sdg; startstop[sqind] = 1; passed++; c_klen[sqind] = 0; c_kscore[sqind] = 0; } else if(stst==1) { sdg = dg->multi_cont[sqind]; } else { //startstop[sqind]=2; if(k>max_under) startstop[sqind] = 2; sdg == NULL; } if(sdg!=NULL) { maxd = maxd2; // reallow next k //printf(" length compare %i %i %i %i\n",sqind, sdg->length+1,k,sdg); c_klen[sqind]++; c_kscore[sqind]+=score2; // if( (sdg->seq_p1.startpos==20) && (sdg->seq_p2.startpos==2) ) printf(" %i %i %i %i %i\n", k, c_klen[sqind], sdg->seq_p1.startpos, sdg->seq_p2.startpos); if(((sdg->score+c_kscore[sqind]) < (avg_sim_score*(sdg->length+c_klen[sqind])))) { if( (sdg->length+c_klen[sqind])>max_under_inner) startstop[sqind]=2; } /* if( (c_klen[sqind]>=1) && (c_kscore[sqind]< (para->PROT_DIAG_AVG_SCORE_THRESHOLD*c_klen[sqind]))) { passed--; startstop[sqind]=2; } */ if( (c_klen[sqind]>=para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS) && (c_kscore[sqind]< (para->PROT_DIAG_AVG_SCORE_THRESHOLD*c_klen[sqind]))) { if ( ((sdg->length+c_klen[sqind])>para->PROT_DIAG_MIN_LENGTH_THRESHOLD)) { passed--; startstop[sqind]=2; } } //printf(" diag length %i %i %i %i %i\n", sn1, sn2, i,j, sdg->length); if( (score2 >= thres_sim_score) && (startstop[sqind]==1)) { //printf(" very before score %i\n", sdg->score); sdg->score += c_kscore[sqind]; sdg->length += c_klen[sqind]; //printf(" begin CONSIDER SDG %i %i %i %f %f\n",sn1,sn2,sdg->length,sdg->weight, diag_thres); //sdg->weight = tmp_dist[sdg->length][sdg->score]; calc_weight(sdg, smatrix, pdist); //printf(" before score %i %i %.20f %i %i\n", sdg->score, sdg->length, sdg->weight, c_kscore[sqind], c_klen[sqind]); /* score1 = sdg->score; if(score1!=sdg->score) { print_diag(sdg); printf(" score %i %i %i %.20f sc %i %i len %i %i %i \n", score1, sdg->score, sdg->length, sdg->weight, c_kscore[sqind],score2, c_klen[sqind],a1,a2); error(" score changed!\n"); } */ //printf(" after score %i %i %.20f\n", sdg->score, sdg->length, sdg->weight); //printf(" END\n"); //if(sdg->weight>0.0) printf(" end CONSIDER SDG %i %i %i %i %f %f\n",sn1, sn2, sdg->length, sdg->score, sdg->weight, diag_thres); c_klen[sqind]=0; c_kscore[sqind]=0; sdg->meetsThreshold = (sdg->weight>diag_thres ? 1 : 0); extended++; } } } else { if(startstop[sqind]==1) { startstop[sqind]=2; passed--; } } if(startstop[sqind]!=2) startstop_pre[sn1]=0; } } else { for(ni2=0;ni2seq_num_length;ni2++) { sn2 = n2->seq_num[ni2]; sqind = sn1*slen+sn2; if(startstop[sqind]==1) { startstop[sqind]=2; passed--; } } } } // if no inner starting diag break if( (k==1) && !extended) maxd = 0; // if only one inner diag and proceeded max_under further then break if( (passed2>=0) && (passed=max_under)) { //printf(" break %i\n"); maxd = 0; } // find the last k where >=2 inner diags where active if(passed >= min_motives) passed2 = k; if( ((extended) && (passed>=min_motives))) { // && (passed>1)){// && (mstatus>1)) { dg->weight = 0.0; extended = 0; for(l=0;lmulti_cont[iter[l]]; if( (sdg!=NULL) && (startstop[iter[l]]>0) && (sdg->weight >= thres_weight)) { extended++; dg->weight += sdg->weight; } } dg->meetsThreshold = (dg->weight>diag_thres ? 1 : 0); if(dg->meetsThreshold && (extended >=min_motives) && (dg->weight>=old_weight) && (dg->weight>=dg_thres_weight)) { old_weight = dg->weight; if(max_pool<=pooled) { max_pool += maxslen; pool_diags = realloc(pool_diags, sizeof(struct diag*)*max_pool); //printf(" pool size %i %.20f %.20f\n", max_pool, dg->weight, old_weight); } tdg = malloc(sizeof(struct diag)); pool_diags[pooled] = tdg; dg->pool_pos = pooled; pooled++; *tdg = *dg; tdg->pred_diag = diag_row[j]; tdg->weight_sum = diag_row[j]->weight_sum+tdg->weight; tdg->col_pred_diag = diag_col[i+k]; diag_col[i+k] = tdg; dg->multi_cont = malloc(sizeof(struct diag *)*slensq); memset(dg->multi_cont, 0, sizeof(struct diag *)*slensq); for(l=0;lmulti_cont[iter[l]]; if((tsdg!=NULL)) { // && (startstop[iter[l]]==1)){ sdg = malloc(sizeof(struct diag)); if(startstop[iter[l]]==0) { tsdg->length = 0; tsdg->score = 0; tsdg->weight = 0.0; tsdg->total_weight = 0.0; } *sdg = *tsdg; dg->multi_cont[iter[l]]=sdg; } else { dg->multi_cont[iter[l]]=NULL; } //dg->multi_cont[iter[l]]=NULL; } } } //if(k > 20) printf(" maxk= %i\n",k); } } } //printf(" after main %i\n",k); tdg = diag_row[slen2]; dcol->total_weight = 0; double lencomp = (log(slen1)+log(slen2)); length = 0; while((tdg!=NULL)) { //if (tdg->weight <=0.0) break; if(tdg->meetsThreshold) { // printf(" add tdg %i %i %i\n", tdg, tdg->length, tdg->meetsThreshold); dcol->total_weight += tdg->weight+lencomp; data[length] = tdg; l = 0; tdg->weight = 0.0; for(i=0;imulti_cont[i]; if(sdg!=NULL) { calc_weight(sdg, smatrix, pdist); if ((sdg->length>0) && (sdg->meetsThreshold) && (sdg->weight > thres_weight)){ tdg->multi_cont[l++] = sdg; tdg->weight += sdg->weight; //printf (" tdg %i %f %f\n", tdg, tdg->weight, sdg->weight); } } } tdg->multi_length = l; if( (tdg->multi_length>=min_motives) && (tdg->weight >= dg_thres_weight)) { tdg->marked = 1; tdg->total_weight = tdg->weight; tdg->weight_sum = -1.0; length++; } else { // TODO free ?? } if(length >= size) { size += 64; data = realloc(data, sizeof(struct diag *)*size); if(data==NULL) error("find_diags(): (3) Out of memory !"); } } tdg = tdg->pred_diag; } for(k=0;kweight_sum>-1.0) { free_diag(pool_diags[k]); } } free(pool_diags); free(diag_col); free(diag_row); free_diag(dg); //free_tmp_pdist(tmp_dist, pdist->max_dlen); dcol->length = length; data = realloc(data, sizeof(struct diag *)*length); dcol->data = data; return dcol; } /** * finds all relevant diags by the DIALIGN METHOD * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct simple_diag_col* find_diags_dialign(struct scr_matrix *smatrix, struct prob_dist *pdist, struct seq* seq1, struct seq* seq2, struct alignment *algn, long double **tmp_dist, int round) { struct simple_diag_col* dcol = calloc(1, sizeof(struct simple_diag_col)); if(dcol==NULL) error("find_diags_dialign(): (1) Out of memory !"); unsigned int size = 16; int length = 0; struct diag **data = calloc(size, sizeof(struct diag* )); // printf("go for k\n"); if(data==NULL) error("find_diags_dialign(): (2) Out of memory !"); long slen1 = seq1->length; long slen2 = seq2->length; unsigned int max_dlen = pdist->max_dlen; struct diag *dg = create_diag(seq1->num, seq1,0, seq2->num, seq2,0,0); struct diag* tdg,*tdg2; int i,j,k,kpos,jmin=0,jmax=slen2; int sn1 = seq1->num; int sn2 = seq2->num; int *c2n = smatrix->char2num; int *sdata = smatrix ->data; char *data1 = seq1->data; char *data2 = seq2->data; int smatrixlen = smatrix->length; int a1,a2; int c_klen,c_kscore; int maxslen = slen1; if(slen2>maxslen) maxslen = slen2; int max_pool = (slen1+slen2-1); struct diag **diag_col = malloc(sizeof(struct diag*)*(slen1+1)); struct diag **diag_row = malloc(sizeof(struct diag*)*(slen2+1)); struct diag **pool_diags=malloc(sizeof(struct diag *)*max_pool); int pooled = 0; double thres_sim_score =para->PROT_SIM_SCORE_THRESHOLD; char hasAli = (round>1); //(algn!=NULL); struct algn_pos **ap,*tap; double diag_thres = para->DIAG_THRESHOLD_WEIGHT; double avg_sim_score = pdist->smatrix->avg_sim_score; int maxd,maxd2,cons_maxd; double score1=0,score2 = 0; char prevail; if(hasAli || para->DO_ANCHOR) { ap = algn->algn; } // DIALIGN for(k=0;k<=slen1;k++) { diag_col[k]=create_diag(seq1->num, seq1,0, seq2->num, seq2,0,1); //diag_col[k]->length = 1; diag_col[k]->weight_sum = 0.0; diag_col[k]->weight = 0.0; pool_diags[pooled] = diag_col[k]; pool_diags[pooled]->pool_pos = pooled; pooled++; } for(k=0;k<=slen2;k++) { diag_row[k] = diag_col[0]; } double old_weight; if(max_dlen> slen1/2.0) max_dlen = slen1/2.0; if(max_dlen> slen2/2.0) max_dlen = slen2/2.0; for(i=0;i<=slen1;i++) { // merge row/col if(i>0) { tdg = diag_col[i]; while(tdg!=NULL) { kpos = tdg->seq_p2.startpos+tdg->length; if(tdg->weight_sum > diag_row[kpos]->weight_sum) { diag_row[kpos] = tdg; prevail = 1; } else { prevail = 0; } tdg2 = tdg; tdg = tdg->col_pred_diag; if(! prevail) { pool_diags[tdg2->pool_pos]=NULL; free_diag(tdg2); } } } for(j=1;j<=slen2;j++) { if(diag_row[j-1]->weight_sum > diag_row[j]->weight_sum) { diag_row[j] = diag_row[j-1]; } } if(i==slen1) break; if(hasAli || para->DO_ANCHOR) { tap = find_eqc(ap, sn1, i); if(tap->predF!=NULL) { jmin = tap->predF[sn2]+1; } else { jmin = 0; } if(tap->succF!=NULL) { jmax = tap->succF[sn2]; }else { jmax = slen2; } if(jmin<0) jmin = 0; } if(para->DO_ANCHOR) { if( (jmin-1)==jmax) { jmin--; jmax++; } } for(j=jmin;j=thres_sim_score) { maxd = slen1 - i; maxd2 = slen2 - j; if(maxd >maxd2) maxd = maxd2; if(maxd > max_dlen) maxd = max_dlen; dg->seq_p1.startpos = i; dg->seq_p2.startpos = j; dg->score = score1; cons_maxd = maxd+1; old_weight = 0.0; c_klen = 0; c_kscore = 0; for(k=1;k<=maxd;k++) { dg->length = k; kpos = i+k; if(hasAli || para->DO_ANCHOR) { a1 = i+k-1; a2 = j+k-1; tap = find_eqc(ap, sn1, a1); if (! ( (para->DO_ANCHOR) && (tap->predF!=NULL) && (tap->succF!=NULL) && (tap->predF[sn2]==tap->succF[sn2]) && (tap->predF[sn2]==a2) ) ) { if(tap->predF!=NULL) { if( (tap->predF[sn2] - a2)>0) break; /* if(tap->predF[sn2]==a2) { if( (tap->succF==NULL) || (tap->predF[sn2]!=tap->succF[sn2])) break; } */ } if(tap->succF!=NULL) { if((a2 - tap->succF[sn2])>0) break; /* if(tap->succF[sn2]==a2) { if( (tap->predF==NULL) || (tap->predF[sn2]!=tap->succF[sn2])) break; } */ } } } if(k>1) { a1 = c2n[(int) data1[kpos-1]]; a2 = c2n[(int) data2[j+k-1]]; score2 = sdata[smatrixlen*a1+a2]; dg->score += score2; } else { score2 = score1; } if( dg->score < (avg_sim_score*(double)k)) { break; } c_klen++; c_kscore+=score2; if( (c_klen>=para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS) && (c_kscore< (para->PROT_DIAG_AVG_SCORE_THRESHOLD*c_klen))) { if ( (k>para->PROT_DIAG_MIN_LENGTH_THRESHOLD)) { break; } else { if(maxd>para->PROT_DIAG_MIN_LENGTH_THRESHOLD) maxd = para->PROT_DIAG_MIN_LENGTH_THRESHOLD; } } if(score2 >= thres_sim_score) { c_klen=0; c_kscore=0; if(1) { if(!hasAli) { dg->weight = tmp_dist[k][dg->score]; dg->meetsThreshold = (dg->weight>diag_thres ? 1 : 0); } else { real_calc_weight(dg, smatrix, pdist,1,tmp_dist,algn); } if(dg->meetsThreshold && (dg->weight>=old_weight)) { old_weight = dg->weight; if(max_pool<=pooled) { max_pool += maxslen; pool_diags = realloc(pool_diags, sizeof(struct diag*)*max_pool); //printf(" old pool size %i\n", max_pool); } tdg = malloc(sizeof(struct diag)); pool_diags[pooled] = tdg; dg->pool_pos = pooled; pooled++; *tdg = *dg; tdg->pred_diag = diag_row[j]; tdg->weight_sum = diag_row[j]->weight_sum+tdg->weight; tdg->col_pred_diag = diag_col[kpos]; diag_col[kpos] = tdg; } } } } } } } tdg = diag_row[slen2]; dcol->total_weight = 0; double lencomp = (log(slen1)+log(slen2)); while((tdg!=NULL)) { if (tdg->weight <=0.0) break; if(1) { dcol->total_weight += tdg->weight+lencomp; data[length] = tdg; tdg->weight_sum = -1.0; length++; if(length >= size) { size += 64; data = realloc(data, sizeof(struct diag *)*size); if(data==NULL) error("find_diags(): (3) Out of memory !"); } } tdg = tdg->pred_diag; } for(k=0;kweight_sum>-1.0) { free(pool_diags[k]); } } free(pool_diags); free(diag_col); free(diag_row); free_diag(dg); dcol->length = length; data = realloc(data, sizeof(struct diag *)*length); dcol->data = data; if(para->DEBUG>5) { for(i=0;ilength; int slen2 = seq2->length; unsigned int max_dlen = pdist->max_dlen; struct diag* dg = create_diag(seq1->num, seq1,0, seq2->num, seq2,0,0); struct diag* tdg; int i,j,d; int sn1 = seq1->num; int sn2 = seq2->num; // printf("%i\n",slen2); int *c2n = smatrix->char2num; int *sdata = smatrix ->data; char *data1 = seq1->data; char *data2 = seq2->data; int slen = smatrix->length; int a1,a2; int score1=0,score2 = 0; int maxslen = slen1; if(slen2>maxslen) maxslen = slen2; double avslen = ((double)slen1+slen2)/2.0; int delta; int sim_thr_pred_pos[maxslen]; //int sim_thr_succ_pos[maxslen]; int scores[maxslen]; long score_sum[maxslen]; long s_sum; int old_thr_pos; //double *dyn_weight = calloc(maxslen, sizeof(double)); double weight; struct diag **dyn_diags=malloc(sizeof(struct diag *)*maxslen); int max_pool = maxslen; struct diag **pool_diags=malloc(sizeof(struct diag *)*max_pool); int pooled = 0; int thres_sim_score = para->PROT_SIM_SCORE_THRESHOLD; int kscore, klen; char hasAli = (algn!=NULL); double diag_thres = para->DIAG_THRESHOLD_WEIGHT; double avg_sim_score = pdist->smatrix->avg_sim_score; struct algn_pos **ap,*tap; if(hasAli) { ap = algn->algn; thres_sim_score =thres_sim_score/2; if(thres_sim_score<4) thres_sim_score = 4; diag_thres = 0.0; } for(d=-slen1+1;dpredF!=NULL) { if( (tap->predF[sn2] - a2)>0) break; } if(tap->succF!=NULL) { if((a2 - tap->succF[sn2])>0) break; } } a1 = c2n[(int) data1[i+k]]; a2 = c2n[(int) data2[j+k]]; score1 = sdata[slen*a1+a2]; scores[k] = score1; s_sum+= score1; score_sum[k] = s_sum; if(score1 < thres_sim_score) { sim_thr_pred_pos[k] = old_thr_pos; } else { //if(old_thr_pos>=0) sim_thr_succ_pos[old_thr_pos] = k; old_thr_pos = k; } } maxl = k; //if(old_thr_pos>=0) sim_thr_succ_pos[old_thr_pos] = maxl; dyn_diags[0] = create_diag(seq1->num, seq1,0, seq2->num, seq2,0,0); dyn_diags[0]->weight_sum = 0.0; dyn_diags[0]->weight = 0.0; pool_diags[0] = dyn_diags[0]; pooled = 1; lastk=0; for(k=0;k0) { dyn_diags[k] = dyn_diags[lastk]; //dyn_weight[k] = dyn_weight[lastk]; } if(hasAli) { a1 = i+k; a2 = j+k; //printf("pre %i\n", a1); tap = find_eqc(ap, sn1, a1); //printf("after %i\n", a1); if(tap->predF!=NULL) { if( (tap->predF[sn2] - a2)>0) break; } if(tap->succF!=NULL) { if((a2 - tap->succF[sn2])>0) break; } } score1 = scores[k]; if(score1>=thres_sim_score) { for(l=para->DIAG_MIN_LENGTH;l<=max_dlen; l++) { delta = k-l+1; dg->seq_p1.startpos = i+delta; dg->seq_p2.startpos = j+delta; kscore = 0; klen = 0; if((dg->seq_p1.startpos<0) || (dg->seq_p2.startpos<0)) { break; } else { dg->length = l; //printf("%i %i \n", i-l+1, j-l+1); score2 = scores[delta]; klen++; kscore += score2; if( (kscore < avg_sim_score*klen)) { // && (dg->score>1.2*k*avg_sim_score)) { /* experiment */ if( ( (k>=0.2*avslen) || (k>=20) || ( (i-j)>0.3*avslen)) && klen>=4) break; } if(kscore >= avg_sim_score*klen ) { //if(score2 >= thres_sim_score) { kscore = 0; klen = 0; dg->score = score_sum[k] - (delta > 0 ? score_sum[delta-1] : 0); if(dg->score <= avg_sim_score*dg->length) break; if(!hasAli) { dg->weight = tmp_dist[dg->length][dg->score]; dg->meetsThreshold = (dg->weight>diag_thres ? 1 : 0); } else { real_calc_weight(dg, smatrix, pdist,1,tmp_dist,algn); } if(dg->meetsThreshold) { if(max_pool<=pooled) { max_pool += maxslen; pool_diags = realloc(pool_diags, sizeof(struct diag*)*max_pool); } if(delta==0) { if(dg->weight > dyn_diags[k]->weight_sum) { dg->weight_sum = dg->weight; dyn_diags[k] = malloc(sizeof(struct diag)); pool_diags[pooled] = dyn_diags[k]; pooled++; *dyn_diags[k] = *dg; dyn_diags[k]->pred_diag = NULL; } } else { weight = dg->weight + dyn_diags[delta-1]->weight_sum; if( (weight) >= dyn_diags[k]->weight_sum) { dg->weight_sum = weight; dyn_diags[k] = malloc(sizeof(struct diag)); pool_diags[pooled] = dyn_diags[k]; pooled++; *dyn_diags[k] = *dg; if(dyn_diags[delta-1]->weight >0) { dyn_diags[k]->pred_diag = dyn_diags[delta-1]; } else { dyn_diags[k]->pred_diag = NULL; } } } lastk = k; } } else { l += (delta - sim_thr_pred_pos[delta])-1; } } } } } tdg = dyn_diags[lastk]; while((tdg!=NULL)) { if (tdg->weight <=0.0) break; data[length] = tdg; tdg->weight_sum = -1.0; length++; if(length >= size) { size += 64; data = realloc(data, sizeof(struct diag *)*size); if(data==NULL) error("find_diags(): (3) Out of memory !"); } tdg = tdg->pred_diag; } for(k=0;kweight_sum>-1.0) free(pool_diags[k]); } } data = realloc(data, sizeof(struct diag *)*length); free(pool_diags); free(dyn_diags); free_diag(dg); dcol->length = length; dcol->data = data; if(para->DEBUG>5) { for(i=0;ilength; unsigned int dl, d, si,k; unsigned int odgpos1[sl]; unsigned int odgpos2[sl]; int min,max,xpos,txpos1, txpos2; unsigned int odglen; char next; char hasSplit=1; while(hasSplit) { //printf("hasSplit %i\n",hasSplit); hasSplit = 0; for(s1=0;s1diag_matrix[s1+sl*s2]; dl = sdcol->length; data = sdcol->data; memset(odgpos1,0,sl*sizeof(int)); memset(odgpos2,0,sl*sizeof(int)); pdg=NULL; for(d=0;dweight_sum = dg->weight; dg->orig_score = dg->score; if(pdg!=NULL) pdg->pred_diag = dg; pdg = dg; dg->pred_diag=NULL; next=0; while(! next) { next = 1; xpos = -1; // round 1 //print_diag(dg); //printf(" %i %i min=%i max=%i\n", s1,s2, min,max); min = dg->seq_p1.startpos; max = dg->seq_p1.startpos+dg->length-1; for(si=0;sidiag_matrix[s1+sl*si]->length; n_data = all_diags->diag_matrix[s1+sl*si]->data; } else { odglen = all_diags->diag_matrix[si+sl*s1]->length; n_data = all_diags->diag_matrix[si+sl*s1]->data; } //printf(" %i %i %i\n", si, odglen, odgpos1[si]); while( (odgpos1[si]seq_p2.num) ? sdg->seq_p2.startpos : sdg->seq_p1.startpos; txpos2 = txpos1 + sdg->length-1; //if( (s1==0) && (s2==2) && (si==3)) printf(" pppp %i %i %i %i\n", min,max,txpos1, txpos2); if(txpos2min) && (txpos1<=max) && ((txpos1seq_p2.startpos; max = dg->seq_p2.startpos+dg->length-1; if(xpos>=0) xpos = dg->seq_p2.startpos + (xpos-dg->seq_p1.startpos); for(si=0;sidiag_matrix[s2+sl*si]->length; n_data = all_diags->diag_matrix[s2+sl*si]->data; } else { odglen = all_diags->diag_matrix[si+sl*s2]->length; n_data = all_diags->diag_matrix[si+sl*s2]->data; } while( (odgpos2[si]seq_p2.num) ? sdg->seq_p2.startpos : sdg->seq_p1.startpos; txpos2 = txpos1 + sdg->length-1; if(txpos2min) && (txpos1<=max) && ((txpos1=0) && (xpos<=max) && (xpos>min)) { hasSplit = 1; next = 0; //print_diag(dg); tdg = create_diag(dg->seq_p1.num, dg->seq_p1.sq, xpos-min+dg->seq_p1.startpos, dg->seq_p2.num, dg->seq_p2.sq, xpos, max-xpos+1); tdg->weight_sum = dg->weight_sum; tdg->orig_score = dg->score; dg->length = xpos - min; //print_diag(dg); //print_diag(tdg); //if( (s1==0) && (s2==2)) printf(" SPLIT %i %i %i %i %i !\n", dg, dg->seq_p1.startpos, dg->length, tdg->seq_p1.startpos, tdg->length); //printf(" 2SPLIT %i !\n", dg->length); sdcol->length++; dg->pred_diag = tdg; tdg->pred_diag=NULL; dg = tdg; pdg = dg; } else { //if(s1==0) printf(" ELSE %i %i %i !\n", dg, dg->seq_p1.startpos, dg->length); } } } dl = sdcol->length; if(dl>0) dg=sdcol->data[0]; //printf(" before realloc %i\n", sdcol->length); sdcol->data=realloc(sdcol->data, sdcol->length*sizeof(struct diag*)); //printf(" after realloc %i\n", sdcol->length); if( (dl>0)&& (sdcol->data==NULL)) { error(" split_diags: Out of Memory - reallocating!\n"); } for(k=0;kseq_p1.num, dg->seq_p2.num, dg->seq_p1.startpos, dg->length); sdcol->data[k] = dg; dg = dg->pred_diag; } } } } } */ /** * builds the upgma guide tree in the given diag_col */ void build_guide_tree(struct diag_col *dcol) { int slen = dcol->seq_amount; double weights[slen][slen]; struct gt_node *nodes[slen]; struct gt_node *gtn, *gtn1, *gtn2; int max1=0, max2=1; int i,j,k; for(i=0;iisLeaf = 1; gtn->seq_num = malloc(sizeof(int)*1); gtn->seq_num[0] = i; gtn->seq_num_length = 1; gtn->succ1 = NULL; gtn->succ2 = NULL; nodes[i] = gtn; for(j=i+1;jdiag_matrix[slen*i+j]->total_weight; weights[j][i] = weights[i][j]; if(weights[i][j] > weights[max1][max2]) { max1 = i; max2 = j; } } } for(k=0;k<(slen-1);k++) { gtn1 = nodes[max1]; gtn2 = nodes[max2]; gtn = malloc(sizeof(struct gt_node )); gtn->isLeaf = 0; gtn->seq_num_length = gtn1->seq_num_length + gtn2->seq_num_length; gtn->seq_num = malloc(sizeof(int)*gtn->seq_num_length); for(i=0;iseq_num_length;i++) { gtn->seq_num[i] = gtn1->seq_num[i]; } for(i=0;iseq_num_length;i++) { gtn->seq_num[gtn1->seq_num_length+i] = gtn2->seq_num[i]; } gtn->succ1 = gtn1; gtn->succ2 = gtn2; nodes[max1] = gtn; nodes[max2] = NULL; for(i=0;i weights[i][max2]) ? weights[i][max1] : weights[i][max2]); //weights[i][max1] = 1.0*(weights[i][max1]+weights[i][max2]) + 0.0* ( (weights[i][max1] > weights[i][max2]) ? weights[i][max1] : weights[i][max2]); weights[max1][i] = weights[i][max1]; } } max1 = -1; max2 = -1; for(i=0;igt_root = nodes[0]; /* printf(" root %i\n", nodes[0]); printf(" left1 %i\n", nodes[0]->succ1->succ1->seq_num); printf(" left2 %i\n", nodes[0]->succ1->succ2->seq_num); printf(" right %i\n", nodes[0]->succ2->seq_num); */ } /** * Finds all diags of each pair of sequences in in_seq_col by using * the function above * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct diag_col *find_all_diags(struct scr_matrix *smatrix, struct prob_dist *pdist, struct seq_col *in_seq_col, struct alignment *algn, int round) { unsigned int s1, s2, rs2, sl = in_seq_col->length, sp, ap; struct diag_col *all_diags = create_diag_col(sl); struct simple_diag_col *sdcol; unsigned int diag_amount = 0; struct diag *dg; char hasAli = (round >1);//(algn!=NULL); long double **tmp_dist = NULL; if(!hasAli) tmp_dist = create_tmp_pdist(pdist); int s2max = sl; int s2width =(int) sqrt(sl); double total=0.0; //double imp[sl]; // for(s1=0;s1FAST_PAIRWISE_ALIGNMENT && s2width+1seqs[s1].length,in_seq_col->seqs[rs2].length ); } if(para->DEBUG>5) printf("%i %i\n", s1,s2); //time1 = clock(); //sdcol=find_diags_dyn(smatrix, pdist, &in_seq_col->seqs[s1], // &in_seq_col->seqs[s2],algn,tmp_dist); /* doAlign = 1; if(hasAli) { if(algn->redo_seqs[s1*sl+s2]==0) doAlign = 0; } if(doAlign) { */ if(in_seq_col->seqs[s1].length > 0 && in_seq_col->seqs[s2].length > 0) { //if(para->DEBUG>1) printf(" %i %i %i\n", s1, rs2,sl-1); // printf("find diags %i %i\n",s1,s2); sdcol=find_diags_dialign(smatrix, pdist, &in_seq_col->seqs[s1], &in_seq_col->seqs[rs2],algn,tmp_dist, round); // imp[s1] += sdcol->total_weight; //imp[s2] += sdcol->total_weight; total += sdcol->total_weight; //totala[s1] +=sdcol->total_weight; //totala[s2] +=sdcol->total_weight; //printf(" num of diags:%i\n ", sdcol->length); /* } else { sdcol = calloc(1, sizeof(struct simple_diag_col)); sdcol->length = 0; } */ //printf("%i %i %f\n", s1,s2, (clock()-time1)/CLOCKS_PER_SEC); all_diags->diag_matrix[s1+sl*rs2] = sdcol; all_diags->diag_matrix[rs2+sl*s1] = sdcol; diag_amount += sdcol->length; } } } if(!hasAli) free_tmp_pdist(tmp_dist, pdist->max_dlen); all_diags->diags= calloc(diag_amount, sizeof(struct diag*)); if(all_diags->diags==NULL) error("find_all_diags(): (1) Out of memory !"); ap=0; for(s1=0;s1diag_matrix[s1+sl*s2]; if(sdcol!=NULL) { for(sp=0;splength;sp++) { // if(hasAli || (sdcol->data[sp]->weight >0.01*(sdcol->total_weight/sdcol->length))) { sdcol->data[sp]->pred_diag = NULL; all_diags->diags[ap]=sdcol->data[sp]; ap++; //} else { // free(sdcol->data[sp]); //diag_amount--; // } } } } } all_diags->seq_amount = sl; for(s1=0;s1diag_matrix[sl*s1+s2]; if(sdcol!=NULL) { sdcol->weight_fac =pow(sdcol->total_weight/total,2.0); for(sp=0;splength;sp++) { dg = sdcol->data[sp]; // if(hasAli) print_diag(dg); dg->weight_fac = sdcol->weight_fac; // dg->ov_weight = sdcol->total_weight; /* if(1 || !hasAli) { dg->weight_fac = sdcol->total_weight*totala[s1]/(sl-1)*sdcol->total_weight*totala[s2]/(sl-1); } */ //dg->weight_fac =pow(sdcol->total_weight*(sl-1),2.0)/(totala[s1]*totala[s2]); if(!hasAli) { if(para->DO_OVERLAP) { //printf(" do overlap\n"); //dg->weight_fac = 1.0; calc_ov_weight(dg,all_diags, smatrix,pdist); } dg->total_weight = (dg->weight);//+dg->ov_weight);// *dg->weight_fac; } else { // changed in TX 1.0.0 if(para->FAST_MODE) dg->weight_fac = 1.0; dg->total_weight = (dg->weight);//+dg->ov_weight);// *dg->weight_fac; } //if(sp==sdcol->length-1) sdcol->total_weight *= dg->weight_fac; } } } } all_diags->diag_amount = diag_amount; if(! hasAli) build_guide_tree(all_diags); return all_diags; } /** * Finds all diags of each pair of sequences in in_seq_col by using * the function above * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct diag_col *old_find_all_diags(struct scr_matrix *smatrix, struct prob_dist *pdist, struct seq_col *in_seq_col, struct alignment *algn, int round ) { unsigned int s1, s2, rs2, sl = in_seq_col->length, sp, ap; struct diag_col *all_diags = create_diag_col(sl); struct simple_diag_col *sdcol; unsigned int diag_amount = 0; struct diag *dg; char hasAli = (round >1);//(algn!=NULL); long double **tmp_dist = NULL; if(!hasAli) tmp_dist = create_tmp_pdist(pdist); int s2max = sl; int s2width =(int) sqrt(sl); double total=0.0; //double imp[sl]; // for(s1=0;s1FAST_PAIRWISE_ALIGNMENT && s2width+1seqs[s1].length,in_seq_col->seqs[rs2].length ); } if(para->DEBUG>5) printf("%i %i\n", s1,s2); //time1 = clock(); //sdcol=find_diags_dyn(smatrix, pdist, &in_seq_col->seqs[s1], // &in_seq_col->seqs[s2],algn,tmp_dist); /* doAlign = 1; if(hasAli) { if(algn->redo_seqs[s1*sl+s2]==0) doAlign = 0; } if(doAlign) { */ if(in_seq_col->seqs[s1].length > 0 && in_seq_col->seqs[s2].length > 0) { //if(para->DEBUG>1) printf(" %i %i %i\n", s1, rs2,sl-1); // printf("find diags %i %i\n",s1,s2); sdcol=find_diags_dialign(smatrix, pdist, &in_seq_col->seqs[s1], &in_seq_col->seqs[rs2],algn,tmp_dist, round); // imp[s1] += sdcol->total_weight; //imp[s2] += sdcol->total_weight; total += sdcol->total_weight; //totala[s1] +=sdcol->total_weight; //totala[s2] +=sdcol->total_weight; //printf(" num of diags:%i\n ", sdcol->length); /* } else { sdcol = calloc(1, sizeof(struct simple_diag_col)); sdcol->length = 0; } */ //printf("%i %i %f\n", s1,s2, (clock()-time1)/CLOCKS_PER_SEC); all_diags->diag_matrix[s1+sl*rs2] = sdcol; all_diags->diag_matrix[rs2+sl*s1] = sdcol; diag_amount += sdcol->length; } } } // new: call of split function //printf("before split\n"); /* if(! hasAli) { diag_amount = 0; split_diags(in_seq_col, all_diags); //total=0.0; for(s1=0;s1diag_matrix[s1+sl*s2]; if(sdcol!=NULL) { //sdcol->total_weight = 0.0; for(sp=0;splength;sp++) { dg = sdcol->data[sp]; real_calc_weight(dg, smatrix, pdist, 0, NULL,algn); //sdcol->total_weight += dg->weight; //total += dg->weight; } diag_amount +=sdcol->length; } } } } */ //all_diags->diag_amount = diag_amount; // printf("after split\n"); //double max = 0.0; all_diags->diags= calloc(diag_amount, sizeof(struct diag*)); if(all_diags->diags==NULL) error("find_all_diags(): (1) Out of memory !"); double sdtotal; ap=0; for(s1=0;s1diag_matrix[s1+sl*s2]; if(sdcol!=NULL) { for(sp=0;splength;sp++) { // if(hasAli || (sdcol->data[sp]->weight >0.01*(sdcol->total_weight/sdcol->length))) { all_diags->diags[ap]=sdcol->data[sp]; ap++; //} else { // free(sdcol->data[sp]); //diag_amount--; // } } } } } all_diags->seq_amount = sl; all_diags->total_weight = 0.0; for(s1=0;s1diag_matrix[sl*s1+s2]; sdcol->total_weight = 0.0; sdtotal = 0.0; if(sdcol!=NULL) { for(sp=0;splength;sp++) { dg = sdcol->data[sp]; // if(hasAli) print_diag(dg); dg->weight_fac = pow(sdcol->total_weight/total,2.0); //dg->weight_fac = 1.0; // dg->ov_weight = sdcol->total_weight; /* if(1 || !hasAli) { dg->weight_fac = sdcol->total_weight*totala[s1]/(sl-1)*sdcol->total_weight*totala[s2]/(sl-1); } */ // dg->weight_fac =pow(sdcol->total_weight*(sl-1),2.0)/(totala[s1]*totala[s2]); if(!hasAli) { if(para->DO_OVERLAP) { //dg->weight_fac = 1.0; //error("calc ov\n"); calc_ov_weight(dg,all_diags, smatrix,pdist); } //dg->total_weight = (dg->weight+dg->ov_weight) *dg->weight_fac; } else { dg->weight_fac = 1.0; } dg->total_weight = (dg->weight+dg->ov_weight);//*dg->weight_fac; //if(dg->total_weight > max) max = dg->total_weight; //dg->weight = dg->score; // print_diag(dg); sdtotal += dg->weight; all_diags->total_weight += dg->total_weight; } sdcol->total_weight = sdtotal; } } } all_diags->average_weight = all_diags->total_weight / all_diags->diag_amount; //printf(" max %f\n", max); if(!hasAli) free_tmp_pdist(tmp_dist, pdist->max_dlen); all_diags->diag_amount = diag_amount; if(! hasAli) build_guide_tree(all_diags); return all_diags; } abyss-2.2.4/dialign/io.c000066400000000000000000000730171361462241400150350ustar00rootroot00000000000000/** * * io.c: IO operations, e.g. read input files, console output etc. * * A.R.Subramanian */ #include #include #include #include #include #include #include "parameters.h" #include "struct.h" #include "translate.h" #include "io.h" // alig.c extern struct algn_pos *find_eqc(struct algn_pos **ap, int seqnum, int pos); extern void prepare_alignment(struct alignment *algn); extern struct diag* create_diag(int n1, struct seq* sq1, unsigned int sp1, int n2, struct seq* sq2, unsigned int sp2, int dlength); extern int errno; /** * print version */ void version() { printf(" This is DIALIGN-TX Version %s - A Multiple Sequence alignment program.\n",para->VERSION ); printf(" Author: Amarendran R. Subramanian, 2004-2008 \n"); printf(" subraman@informatik.uni-tuebingen.de\n\n"); printf(" \n"); printf(" Research work using DIALIGN-TX should cite:\n\n"); printf(" DIALIGN-TX: improvement of the segment-based approach for multiple\n"); printf(" sequence alignment by combining greedy and progressive alignment strategies\n"); printf(" Amarendran R. Subramanian, Michael Kaufmann, Burkhard Morgenstern,\n"); printf(" Algorithms for Molecular Biology 3:6, 2008\n\n"); printf(" DIALIGN-T: An improved algorithm for segment-based multiple sequence alignment\n"); printf(" Amarendran R. Subramanian, Jan Weyer-Menkhoff, Michael Kaufmann,\n"); printf(" Burkhard Morgenstern, BMC Bioinformatics 6:66, 2005\n"); // printf(" Special Thanks to:\n"); //printf(" Burkhard Morgenstern\n"); //printf(" Michael Kaufmann\n"); //printf(" David Mathog\n"); //printf(" Numereous DIALIGN-T/X Users\n"); } /** * print error message and exit */ void error(char *message) { printf("ERROR: %s\n", message); // if(errno) perror("perror()"); exit(1); } /** * print error message and exit */ void merror(char *msg1, char *msg2) { printf("ERROR: %s %s\n", msg1, msg2); // if(errno) perror("perror()"); exit(1); } /** * strips off leading whitespace characters */ void strip_leading_ws( char *str ) { int s,d; for(s=d=0; str[s]==' ' || str[s]=='\t'; s++){} for(;;s++,d++){ str[d]=str[s]; if( str[s] == '\0')break; } } /** * builds a pathname from a dir-name and a filename. * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ char* build_pathname(char *dir, char *file) { int dirslen = strlen(dir); char *pathn = calloc(dirslen+strlen(file)+2, sizeof(char)); if(pathn==NULL) error("build_pathname(): out of memory !"); strcpy(pathn, dir); if(dirslen>0 && dir[dirslen-1]!='/') strcat(pathn, "/"); strcat(pathn, file); // if(para->DEBUG) // printf("DEBUG build_pathname(): Created filename: %s from dir=%s and file=%s\n", pathn, dir, file); return pathn; } /** * prints a sequence */ void print_seq(struct seq * aSeq) { int row; int slen = aSeq->length; int maxrow = slen/para->PRINT_SEQ_LINE_LENGTH; int row_residue = slen % para->PRINT_SEQ_LINE_LENGTH; printf("Sequence: %s\nLength: %i\n", aSeq->name, slen); char line[para->PRINT_SEQ_LINE_LENGTH+1]; for(row=0;row <=maxrow; row++) { if(rowdata[row*para->PRINT_SEQ_LINE_LENGTH]), para->PRINT_SEQ_LINE_LENGTH); line[para->PRINT_SEQ_LINE_LENGTH]='\0'; } else{ if(row_residue==0) break; strncpy(line, &(aSeq->data[row*para->PRINT_SEQ_LINE_LENGTH]), row_residue); line[row_residue]='\0'; } printf("%s\n", line); } } /** * prints a diagional */ void print_diag(struct diag *aDiag) { int row; int slen = aDiag->length; int maxrow = slen/para->PRINT_SEQ_LINE_LENGTH; int row_residue = slen % para->PRINT_SEQ_LINE_LENGTH; printf("Diag: %s\n %s\nLength: %i startpos1: %i startpos2: %i\n", aDiag->seq_p1.sq->name, aDiag->seq_p2.sq->name, slen, aDiag->seq_p1.startpos,aDiag->seq_p2.startpos ); char *data1 =aDiag->seq_p1.sq->data; char *data2 =aDiag->seq_p2.sq->data; char *data; int startpos1 = aDiag->seq_p1.startpos; int startpos2 = aDiag->seq_p2.startpos; int snum, startpos; char line[para->PRINT_SEQ_LINE_LENGTH+1]; for(row=0;row <=maxrow; row++) { for (snum=0;snum<2;snum++) { startpos = (snum==0 ? startpos1 : startpos2); data = (snum==0 ? data1 : data2); if(rowPRINT_SEQ_LINE_LENGTH]), para->PRINT_SEQ_LINE_LENGTH); line[para->PRINT_SEQ_LINE_LENGTH]='\0'; } else{ if(row_residue==0) break; strncpy(line, &(data[startpos+row*para->PRINT_SEQ_LINE_LENGTH]), row_residue); line[row_residue]='\0'; } printf("%s\n", line); } if(rowscore, aDiag->weight); } /** * prints a score matrix */ void print_scr_matrix(struct scr_matrix *aSmatrix) { int len =aSmatrix->length; printf("Length: %i, maximal score: %i\n", len, aSmatrix->max_score); int r, c; for (r=-1; rnum2char[c]); } else if(cdata[len*r+c]); } else { printf(" %c ", aSmatrix->num2char[r]); } } printf("\n"); } } /** * reads score matrix from the file * indicated by filename parameter. * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct scr_matrix* read_scr_matrix(char *filename) { if(para->DEBUG) printf("DEBUG read_scr_matrix(): Processing input file: %s\n", filename); int length = 0; struct scr_matrix *smatrix = calloc(1, sizeof(struct scr_matrix)); int *char2num = (smatrix->char2num =calloc(256, sizeof(int))); int *num2char = (smatrix->num2char =calloc(256, sizeof(int))); if(smatrix==NULL || char2num==NULL) error("read_scr_matrix(): Out of memory !"); FILE *fp; char rline[100]; if( (fp = fopen( filename , "r")) == NULL) { merror("read_scr_matrix(): Cannot open input score matrix file", filename ); } int sret; char amino; while( (sret=fscanf(fp, " %c ", &amino))!=EOF && sret>0) { if(amino=='#') { break; } else { num2char[length]=amino; char2num[(int)amino]=length++; } } num2char[length]='?'; char2num[(int)'?']=length++; num2char[length]='#'; char2num[(int)'#']=length++; num2char[length]='$'; char2num[(int)'$']=length++; int additional=3; if(sret==EOF) merror("read_scr_matrix(): Unexpected end of file ",filename); if(length==0) merror("read_scr_matrix(): Invalid format of file ",filename); smatrix->length = length; int *data = (smatrix->data = calloc(length*length, sizeof(int))); if(data==NULL) error("read_scr_matrix(): Out of memory when allocating data !"); // read the matrix entries int r,c; int is;//,tis; long double frac = (long double)2.0/(long double)(length*length); long double avg_score = 0.0; // generate Array from Matrix for( r=0; rSCR_MATRIX_ADD; if(smatrix->max_scoremax_score =is; avg_score += (long double)is*frac; data[length*r+c] = is; // ensure symmetry of the weight matrix data[length*c+r] = is; } fscanf(fp, "%s\n", rline); } fclose(fp); // Array is a symmetric Matrix /************************************ vvv Vorsicht !!! ***********/ smatrix->avg_sim_score = para->PROT_SIM_SCORE_THRESHOLD; int ms = smatrix->max_score; int *dist = (smatrix->dist=calloc(ms+1, sizeof(int))); for(r=0;r='A') && (num2char[r]<='Z')) if(num2char[c]!='X' && (num2char[c] >='A') && (num2char[c]<='Z')) dist[data[length*r+c]]++; } } return smatrix; } /** * reads the probability distribution for diagonal lengths from the file * indicated by filename parameter. * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct prob_dist* read_diag_prob_dist(struct scr_matrix* smatrix, char *filename) { if(para->DEBUG>1) printf("DEBUG read_diag_prob_dist(): Processing input file: %s\n", filename); int length = 0; struct prob_dist *pdist = calloc(1, sizeof(struct prob_dist)); pdist->smatrix = smatrix; if(pdist==NULL) error("read_diag_prob_dist(): Out of memory !"); FILE *fp; if( (fp = fopen( filename , "r")) == NULL) { merror("read_diag_prob_dist(): Cannot open input file", filename ); } int sret; sret=fscanf(fp, "%i\n", &length); if(sret<=0) merror("read_diag_prob_dist(): Invalid format in file", filename ); if(length==0) merror("read_scr_matrix(): Invalid format of file ",filename); // fscanf(fp, "%s\n", rline); // printf("rline:%s %i\n",rline, length); // length=40; pdist->max_dlen = length; pdist->data = calloc(length+1, sizeof(long double *)); long double **dist =pdist->data; if(dist==NULL) error("read_diag_prob_dist(): (1) Out of memory when allocating data !"); pdist->log_data = calloc(length+1, sizeof(double *)); double **log_dist =pdist->log_data; if(log_dist==NULL) error("read_diag_prob_dist(): (1.1) Out of memory when allocating data !"); // read the entries unsigned long i, scr, mxscr, sm_max_scr=smatrix->max_score; unsigned long ti, tscr; long double weight; long size=0; for( i=1; i<=length; i++) { mxscr = i*sm_max_scr; size += mxscr+1; dist[i] = calloc(mxscr+1, sizeof(long double )); log_dist[i] = calloc(mxscr+1, sizeof(long double )); if(dist[i]==NULL) error("read_diag_prob_dist(): (3) Out of memory at iteration" ); for(scr=0;scr<=mxscr;scr++) { dist[i][scr]=1.0; } for(scr=0;scr<=mxscr;scr++) { dist[i][scr]=1.0; fscanf( fp, "%li %li %Le\n", &ti,&tscr,&weight ); //if(i!=ti || tscr!=scr) merror("read_scr_matrix(): (4) Invalid format of file ",filename); scr = tscr; if(weight==0.0) weight = 1.0; dist[i][scr]=weight; log_dist[i][scr]=-log(weight); if(para->DEBUG>5)printf("%li %li %Le\n", i, scr,dist[i][scr] ); } } if(para->DEBUG >1) printf("DEBUG: PROB DIST SIZE: %li bytes\n", size*sizeof(long double)+length*sizeof(long double *)); //pdist->avg_sim_score = 4; return pdist; } /** * reads sequence collection (seq_col) from the file * indicated by filename parameter. * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct seq_col* read_fasta(char *filename) { if(para->DEBUG) printf("DEBUG read_seq_col(): Processing input file: %s\n", filename); struct seq_col *scol = calloc(1, sizeof(struct seq_col)); struct seq* seqs = (scol->seqs = calloc(para->MAX_SEQ_AMOUNT, sizeof(struct seq))); struct seq* seq; if(scol==NULL || seqs==NULL) error("read_fasta(): Out of memory !"); FILE *fp; char rline[para->MAX_FASTA_LINE_LENGTH]; if( (fp = fopen( filename , "r")) == NULL) { merror("read_fasta(): Cannot open input FASTA file", filename ); } scol->length = 0; char *data; char ch; unsigned int *slen; int data_maxlen; int c, rlen; int valid =0; char long_name=0; int name_length; while( fgets( rline , para->MAX_FASTA_LINE_LENGTH+1, fp ) != NULL ) { // if(para->DEBUG) // printf(rline); strip_leading_ws(rline); rlen = strlen(rline); if(rline[0] == '>') { valid = 1; long_name=1; seq = &(scol->seqs[scol->length]); seq->max_seen = 0; seq->name = calloc(rlen, sizeof(char)); seq->num = scol->length; seq->orf_frame=0; seq->crick_strand=0; strncpy(seq->name, &(rline[1]), rlen-2); slen = (unsigned int *) &(seq->length); *slen = 0; data_maxlen = 1024; seq->data = (data = calloc(data_maxlen, sizeof(char))); if(data==NULL) error("read_fasta(): Out of memory: seq->data alloc"); scol->length++; if(rlen < para->MAX_FASTA_LINE_LENGTH) { long_name = 0; // if relen = then line is longer } } else if(long_name) { long_name=1; if(rlen < para->MAX_FASTA_LINE_LENGTH) { long_name = 0; // if relen = then line is longer rline[rlen-1]='\0'; } name_length = strlen(seq->name); if(NULL == (seq->name = realloc(seq->name,rlen + name_length) ) ) { error("read_fasta(): Out of memory: seq->data realloc"); } strcat(seq->name, rline); } else { for( c=0;c= 65 && ch < 91) || (ch >= 97 && ch < 123)) { if(! valid) merror("read_fasta(): File is not in FASTA format:", filename); // realloc memory when necessary if(*slen >= data_maxlen) { data_maxlen += 1024; seq->data = (data = realloc(data, data_maxlen*sizeof(char))); if(data==NULL) error("read_fasta(): Out of memory: seq->data alloc"); } data[(*slen)++] = ((ch >= 97) ? toupper(ch) : ch); } } } } int avg=0; for(c=0;clength;c++) { avg += scol->seqs[c].length; } scol->avg_length = avg/scol->length; if(para->DEBUG) printf("\n"); fclose(fp); return scol; } /** * reads the given anchor file and returns the accordingly created * simple_diag_col structure pointer */ struct simple_diag_col* read_anchors(char *filename, struct seq_col* scol) { if(para->DEBUG) printf("DEBUG read_anchors(): Processing anchor file: %s\n", filename); struct simple_diag_col *sdcol = malloc(sizeof(struct simple_diag_col)); FILE *fp; if( (fp = fopen( filename , "r")) == NULL) { merror("read_anchros(): Cannot open input anchor file", filename ); } //fscanf( fp, "%li %li %Le\n", &ti,&tscr,&weight ); long int s1,s2,sp1,sp2,len; double score; int alloc_size = 64; sdcol->data = malloc(sizeof (struct diag*)*alloc_size); sdcol->length=0; while( fscanf(fp,"%li %li %li %li %li %le\n",&s1,&s2,&sp1,&sp2,&len,&score ) == 6) { if(sdcol->length >= alloc_size) { alloc_size+=16; sdcol->data = realloc(sdcol->data,sizeof (struct diag*)*alloc_size); } sdcol->data[sdcol->length]= create_diag(s1-1,&(scol->seqs[s1-1]),sp1-1, s2-1,&(scol->seqs[s2-1]),sp2-1,len); sdcol->data[sdcol->length]->anchor = 1; sdcol->data[sdcol->length]->meetsThreshold = 1; //printf(" total weight %e\n", score); sdcol->data[sdcol->length++]->total_weight = score; } if(para->DEBUG) printf("DEBUG read_anchors(): Read %i anchors from file\n", sdcol->length); fclose(fp); return sdcol; } /** * prints the given alignment in a simple way. */ void simple_print_alignment_default(struct alignment *algn) { struct seq_col *scol = algn->scol; unsigned int slen = scol->length; unsigned int i,j,s,pos,max,tmax; struct seq* sq; struct algn_pos **ap = algn->algn; int proc[slen]; // char proceed[slen]; for(i=0;imax_pos; struct algn_pos *ap1; // // print block // WARNING! print_info reallocates memory, this loses the algn pointer // since the new one is not stored when it is returned here, so it cannot // be freed later. In the present version the leak is relatively minor and // should not crash anything. // printf("%s",print_info(algn)); printf("\n ALIGNMENT OUTPUT:\n"); printf(" -----------------\n\n"); // printf("%i\n", max); for(pos=0;posmax) tmax = max; for(s=0;sseqs[s]; for(j=pos;jname, proc[s]+1); } else if( (j%10)==0) { printf(" "); } if(proc[s]length) { ap1 = find_eqc(ap,s,proc[s]); if( (*ap1->eqcAlgnPos) < j) { printf ("\nALARM %i %i %i %i\n", s,j, proc[s], *ap1->eqcAlgnPos); } // if(proc[0]==244 && s==0) printf("\nMOVE FORWARD: %i %i %i\n",j, *ap[0][244].eqcAlgnPos, *ap[1][241].eqcAlgnPos); if( (*ap1->eqcAlgnPos) == j) { if(ap1->state & para->STATE_ORPHANE) { printf("%c", tolower(sq->data[proc[s]])); } else { printf("%c", toupper(sq->data[proc[s]])); } proc[s]++; } else { printf("-"); //printf("%i",*ap[s][proc[s]].maxpos); } } else { printf("-"); //printf("%i",*ap[s][proc[s]].maxpos); // printf("\n%i %i %i\n", s, j,proc[s]); } } printf("\n"); } printf("\n"); printf("\n"); } } void simple_print_alignment_dna_retranslate(struct alignment *algn) { char *tmp = "000"; struct seq_col *scol = algn->scol; unsigned int slen = scol->length; unsigned int i,j,s,pos,max,tmax; struct seq* sq; struct algn_pos **ap = algn->algn; int proc[slen]; // char proceed[slen]; for(i=0;imax_pos; struct algn_pos *ap1; // // print block // printf("%s",print_info(algn)); printf("\n ALIGNMENT OUTPUT:\n"); printf(" -----------------\n\n"); // printf("%i\n", max); for(pos=0;posmax) tmax = max; for(s=0;sseqs[s]; for(j=pos;jname, ((proc[s])*3)+1); } else if( (j%4)==0) { printf(" "); } if(proc[s]length) { ap1 = find_eqc(ap,s,proc[s]); if( (*ap1->eqcAlgnPos) < j) { printf ("\nALARM %i %i %i %i\n", s,j, proc[s], *ap1->eqcAlgnPos); } // if(proc[0]==244 && s==0) printf("\nMOVE FORWARD: %i %i %i\n",j, *ap[0][244].eqcAlgnPos, *ap[1][241].eqcAlgnPos); if( (*ap1->eqcAlgnPos) == j) { tmp = retranslate(sq->dna_num[proc[s]]); if(ap1->state & para->STATE_ORPHANE) { printf("%c%c%c", tolower(tmp[0]),tolower(tmp[1]), tolower(tmp[2]) ); } else { printf("%c%c%c", toupper(tmp[0]), toupper(tmp[1]), toupper(tmp[2]) ); } proc[s]++; } else { printf("---"); //printf("%i",*ap[s][proc[s]].maxpos); } } else { printf("---"); //printf("%i",*ap[s][proc[s]].maxpos); // printf("\n%i %i %i\n", s, j,proc[s]); } } printf("\n"); } printf("\n"); printf("\n"); } } /** * prints the given alignment in fasta format * to the given file. */ void fasta_print_alignment_default(struct alignment *algn, char *filename) { struct seq_col *scol = algn->scol; unsigned int slen = scol->length; unsigned int j,s,proc, max; struct seq* sq; struct algn_pos **ap = algn->algn; prepare_alignment(algn); max = algn->max_pos; struct algn_pos *ap1; FILE *fp; if( (fp = fopen( filename , "w")) == NULL) { merror("fasta_print_alignment(): Cannot open file", filename ); } // fprintf(fp,"%s",print_info(algn)); max = algn->max_pos; for(s=0;sseqs[s]); fprintf(fp, ">%s",sq->name); proc = 0; for(j=0;jlength) { if( (j%60)==0) fprintf(fp,"\n"); ap1 = find_eqc(ap,s,proc); if(*ap1->eqcAlgnPos==j) { if(ap1->state & para->STATE_ORPHANE) { fprintf(fp, "%c", tolower(sq->data[proc])); } else { fprintf(fp, "%c", toupper(sq->data[proc])); } proc++; } else { fprintf(fp,"-"); } } else { if( (j%60)==0) fprintf(fp,"\n"); fprintf(fp,"-"); } } fprintf(fp,"\n"); } fclose(fp); } void fasta_print_alignment_dna_retranslate(struct alignment *algn, char *filename) { char *tmp = "000"; struct seq_col *scol = algn->scol; unsigned int slen = scol->length; unsigned int j,s,proc, max; struct seq* sq; struct algn_pos **ap = algn->algn; prepare_alignment(algn); max = algn->max_pos; struct algn_pos *ap1; FILE *fp; if( (fp = fopen( filename , "w")) == NULL) { merror("fasta_print_alignment(): Cannot open file", filename ); } // fprintf(fp,"%s",print_info(algn)); max = algn->max_pos; for(s=0;sseqs[s]); fprintf(fp, ">%s",sq->name); proc = 0; for(j=0;jlength) { if( (j%20)==0) fprintf(fp,"\n"); ap1 = find_eqc(ap,s,proc); if(*ap1->eqcAlgnPos==j) { tmp = retranslate(sq->dna_num[proc]); // printf(fp,"%c,\n",sq->dna_num[proc]); if(ap1->state & para->STATE_ORPHANE) { fprintf(fp, "%c%c%c", tolower(tmp[0]),tolower(tmp[1]), tolower(tmp[2])); } else { fprintf(fp, "%c%c%c", toupper(tmp[0]), toupper(tmp[1]), toupper(tmp[2])); } proc++; } else { fprintf(fp,"---"); } } else { if( (j%20)==0) fprintf(fp,"\n"); fprintf(fp,"---"); } } fprintf(fp,"\n"); } fclose(fp); } char* print_info(struct alignment *algn) { int i; char *output; char *line, *line2; if(NULL == ( output = (calloc(63,sizeof(char))))) { error("print_info(): Out of memory !"); } strcat(output, "\n"); for(i=0;i!=60; ++i) { strcat(output, "*"); } strcat(output, "\n"); if (para->DNA_TRANSLATION) { if(para->FIND_ORF){ if(!para->ORF_FRAME){ // -L : if(NULL == ( line = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } if(NULL == ( output = (realloc(output,strlen(output)+15*61)))) { error("print_info(): Out of memory !"); } line = "Multiple Sequence Alignment (with translation)"; line = output_line(line); strcat(output, line); line = "Input sequences in DNA"; line = output_line(line); strcat(output, line); if(!para->OUTPUT) line = "Alignment output in aminoacids"; else line = "Alignment output in DNA"; line = output_line(line); strcat(output, line); line = "Sequences translated into aminoacids"; line = output_line(line); strcat(output, line); line = "Only longest open reading frames aligned"; line = output_line(line); strcat(output, line); line = "Sequence lengths cut mod 3 = 0"; line = output_line(line); strcat(output, line); strcat(output,blank_line()); line = "reading frame 1 : 123 123 123 123 ..."; line = output_line_left(line); strcat(output, line); line = "reading frame 2 : X 123 123 123 123 ..."; line = output_line_left(line); strcat(output, line); line = "reading frame 3 : XX 123 123 123 123 ..."; line = output_line_left(line); strcat(output, line); line = "reading frame 4 : ... 321 321 321 321 XX"; line = output_line_left(line); strcat(output, line); line = "reading frame 5 : ... 321 321 321 321 X"; line = output_line_left(line); strcat(output, line); line = "reading frame 6 : ... 321 321 321 321"; line = output_line_left(line); strcat(output, line); strcat(output,blank_line()); strcat(output,blank_line()); for (i = 0; i != algn->scol->length; ++i) { int k; char *tmp; int tmp2; tmp = " : reading frame = "; line[0] = algn->scol->seqs[i].name[0]; for(k=1; k!=12 ; ++k) { line[k]=algn->scol->seqs[i].name[k]; tmp2=algn->scol->seqs[i].orf_frame+48; } line[12]='\0'; strcat(line, tmp); line[strlen(line)-1]=tmp2; line[strlen(line)]='\0'; if(NULL == ( output = (realloc(output,strlen(output)+62)))) { error("print_info(): Out of memory !"); } line = output_line(line); strcat(output, line); } free(line); } else{ // -O : if(NULL == ( line = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } if(NULL == ( output = (realloc(output,strlen(output)+15*61)))) { error("print_info(): Out of memory !"); } line = "Multiple Sequence Alignment (with translation)"; line = output_line(line); strcat(output, line); line = "Input sequences in DNA"; line = output_line(line); strcat(output, line); if(!para->OUTPUT) line = "Alignment output in aminoacids"; else line = "Alignment output in DNA"; line = output_line(line); strcat(output, line); line = "Sequences translated into aminoacids"; line = output_line(line); strcat(output, line); line = "reading frames found due to longest ORF"; line = output_line(line); strcat(output, line); line = "Sequence lengths cut mod 3 = 0"; line = output_line(line); strcat(output, line); strcat(output,blank_line()); line = "reading frame 1 : 123 123 123 123 ..."; line = output_line_left(line); strcat(output, line); line = "reading frame 2 : X 123 123 123 123 ..."; line = output_line_left(line); strcat(output, line); line = "reading frame 3 : XX 123 123 123 123 ..."; line = output_line_left(line); strcat(output, line); line = "reading frame 4 : ... 321 321 321 321 XX"; line = output_line_left(line); strcat(output, line); line = "reading frame 5 : ... 321 321 321 321 X"; line = output_line_left(line); strcat(output, line); line = "reading frame 6 : ... 321 321 321 321"; line = output_line_left(line); strcat(output, line); strcat(output,blank_line()); strcat(output,blank_line()); for (i = 0; i != algn->scol->length; ++i) { int k; char *tmp; int tmp2; tmp = " : reading frame = "; line[0] = algn->scol->seqs[i].name[0]; for(k=1; k!=12 ; ++k) { line[k]=algn->scol->seqs[i].name[k]; tmp2=algn->scol->seqs[i].orf_frame+48; } line[12]='\0'; strcat(line, tmp); line[strlen(line)-1]=tmp2; line[strlen(line)]='\0'; if(NULL == ( output = (realloc(output,strlen(output)+62)))) { error("print_info(): Out of memory !"); } line = output_line(line); strcat(output, line); } free(line); } } else{ // -T : if(NULL == ( line = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } if(NULL == ( output = (realloc(output,strlen(output)+5*61)))) { error("print_info(): Out of memory !"); } line = "Multiple Sequence Alignment (with translation)"; line = output_line(line); strcat(output, line); line = "Input sequences in DNA"; line = output_line(line); strcat(output, line); if(!para->OUTPUT) line = "Alignment output in aminoacids"; else line = "Alignment output in DNA"; line = output_line(line); strcat(output, line); line = "Sequences translated into aminoacids"; line = output_line(line); strcat(output, line); line = "Sequence lengths cut mod 3 = 0"; line = output_line(line); strcat(output, line); free(line); } } else{ // -D : if(NULL == ( line = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } if(NULL == ( line2 = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } if(NULL == ( output = (realloc(output,strlen(output)+3*61+1)))) { error("print_info(): Out of memory !"); } (void) strcpy(line,"Multiple Sequence Alignment"); line = output_line(line); strcat(output, line); if(para->DNA_PARAMETERS) (void) strcpy(line2,"in DNA"); else (void) strcpy(line2,"in aminoacids"); sprintf(line,"Input sequences %s", line2); line = output_line(line); strcat(output, line); if(para->DNA_PARAMETERS) (void) strcpy(line2,"in DNA"); else (void) strcpy(line2,"in aminoacids"); sprintf(line,"Alignment output %s", line2); line = output_line(line); strcat(output, line); free(line); free(line2); } if(NULL == ( output = (realloc(output,strlen(output)+63)))) { error("print_info(): Out of memory !"); } for(i=0;i!=60; ++i) { strcat(output, "*"); } strcat(output, "\n\n"); return output; } /*SIDE EFFECT, releases original memory held by string */ char* output_line(char *string) { char *tmp; if(NULL == ( tmp = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } int x, i, y; y = 0; if (strlen(string) %2 == 0) y = 1; x = (60 - strlen(string)) /2 ; strcat(tmp, "*"); for (i = 0; i != x-y; ++i) { strcat(tmp, " "); } strcat(tmp,string); for (i = 0; i != x-1; ++i) { strcat(tmp, " "); } strcat(tmp, "*\n"); free(string); string=&(tmp[0]); return string; } /*SIDE EFFECT, releases original memory held by string */ char* output_line_left(char *string) { char *tmp; if(NULL == ( tmp = (calloc(62, sizeof(char))))) { error("print_info(): Out of memory !"); } int x, i, y; y = 0; x = (60 - strlen(string)-3) ; strcat(tmp, "* "); strcat(tmp,string); for (i = 0; i != x; ++i) { strcat(tmp, " "); } strcat(tmp, "*\n"); free(string); string=&(tmp[0]); return string; } char* blank_line() { int i; char *string; if(NULL == ( string = (calloc(62,sizeof(char))))) { error("print_info(): Out of memory !"); } strcat(string, "*"); for (i = 0; i != 58; ++i) { strcat(string, " "); } strcat(string, "*\n"); return string; } void print_pdist_matrix(struct prob_dist *sdist, char *filename) { int lh, scr, mxscr; FILE *fp; if( (fp = fopen( filename , "w")) == NULL) { merror("fasta_print_alignment(): Cannot open file", filename ); } fprintf(fp,"%d\n",sdist->max_dlen); for(lh=1; lh!=sdist->max_dlen+1; ++lh) { mxscr = lh * sdist->smatrix->max_score; for(scr=0; scr!=mxscr+1; ++scr) { fprintf(fp,"%d %d %Le\n",lh,scr,sdist->data[lh][scr]); } } } abyss-2.2.4/dialign/io.h000066400000000000000000000036671361462241400150460ustar00rootroot00000000000000/** * * io.h: * * 2004-08-30 Dorothea Emig Volker Menrad * */ /************************************************/ /* */ /* structs */ /* */ /************************************************/ /************************************************/ /* */ /* global variable */ /* */ /************************************************/ /*********************************************/ /* */ /* functions from io.c */ /* */ /*********************************************/ void version(); // prints version on stdout void print_scr_matrix(struct scr_matrix* aSmatrix); struct scr_matrix* read_scr_matrix(char *filename); void print_seq(struct seq* aSeq); struct seq_col* read_fasta(char *filename); void print_diag(struct diag* aDiag); struct prob_dist* read_diag_prob_dist(struct scr_matrix* smatrix, char *filename); void simple_print_alignment_default(struct alignment *algn); void simple_print_alignment_dna_retranslate(struct alignment *algn); //void simple_print_alignment_dna(struct alignment *algn); void fasta_print_alignment_default(struct alignment *algn, char *filename); void fasta_print_alignment_dna_retranslate(struct alignment *algn, char *filename); //void fasta_print_alignment_dna(struct alignment *algn, char *filename); char *print_info(struct alignment *align); char *output_line(char *string); char *output_line_left(char *string); char *blank_line(); void print_pdist_matrix(struct prob_dist *sdist,char *filename); void error(char *message); void merror(char *msg1, char *msg2); char* build_pathname(char *dir, char *file); abyss-2.2.4/dialign/museq.c000066400000000000000000000224241361462241400155540ustar00rootroot00000000000000/** * * museq.c: Main program control * Author: A.R.Subramanian * */ /** * TODO LIST: * - option: multi diags as optional argument */ #include #include #include #include #include #include #include "parameters.h" #include "struct.h" #include "translate.h" #include "orf.h" #include "io.h" /** * external functions definitions */ // diag.c //extern struct seq_part* create_seq_part(int num, struct seq* aSeq, // unsigned int startpos); //extern struct diag* create_diag(struct seq_part* part1, struct seq_part* part2, // int dlength); //extern void calc_weight(struct diag* dg, struct scr_matrix* smatrix, // struct prob_dist *pdist); //extern struct diag_col *create_diag_col(int seq_amount); extern void free_diag(struct diag* dg); extern void free_diag_col(struct diag_col* dcol); extern struct diag_col *find_all_diags(struct scr_matrix *smatrix, struct prob_dist *pdist, struct seq_col *in_seq_col, struct alignment *algn, int round); // prob.c //extern struct seq* create_random_seq(struct scr_matrix *smatrix, int length); //extern double* approx_prob(struct scr_matrix *smatrix, struct prob_dist *sdist, // int diaglen, int seqlen); extern struct prob_dist* calc_score_dist(struct scr_matrix *smatrix, int mxdlen); // alig.c extern void free_alignment(struct alignment *algn); extern struct alignment* create_empty_alignment(struct seq_col *scol); //extern char adapt_diag(struct alignment *algn, struct scr_matrix *smatrix, struct diag* dg); extern int simple_aligner(struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct alignment *algn, int round); extern struct simple_diag_col* read_anchors(char *filename, struct seq_col* scol); extern struct alignment* guided_aligner(struct alignment *palgn, struct seq_col *scol, struct diag_col *dcol, struct scr_matrix* smatrix, struct prob_dist *pdist, struct gt_node *gtn, int round); /** * main program routine */ int main(int argc, char **argv) { parameters(argc, argv); version(); // read similarity matrix char *smatrixfile = (char *)build_pathname(para->conf_dir,para->SCR_MATRIX_FILE_NAME); struct scr_matrix *smatrix = read_scr_matrix(smatrixfile); // print the score matrix if( para->DEBUG >5) { print_scr_matrix(smatrix); } // read the probability distribution for diagonals char *pdistfilename = (char *)build_pathname(para->conf_dir,para->DIAG_PROB_FILE_NAME); int i; struct seq_col *in_seq_col; struct prob_dist *pdist; if(!para->COMPUTE_PROB){ pdist = read_diag_prob_dist(smatrix, pdistfilename); in_seq_col = read_fasta(para->in_file); if(para->DNA_TRANSLATION){ if(para->FIND_ORF){ if(para->ORF_FRAME){ translate_sequence_collection_orf_frame(in_seq_col); } else { in_seq_col = set_longest_orf(in_seq_col); } } else{ translate_sequence_collection_default(in_seq_col); } } } // print read input sequences if(para->DEBUG>5) { int sc,scl = in_seq_col->length; for(sc=0; sc < scl;sc++) { print_seq(&(in_seq_col->seqs[sc])); printf("\n"); } } // ---------------------------------------------------------------------- // probability table generation area // ---------------------------------------------------------------------- if(para->COMPUTE_PROB) { char *prob_table_output_file = (char *)build_pathname(para->conf_dir,"prob_table"); struct prob_dist *sdist = calc_score_dist(smatrix, 100); print_pdist_matrix(sdist, prob_table_output_file); exit(0); } double tim = clock(),tim2; // fast mode has higher threshold weights if(para->FAST_MODE) { para->PROT_SIM_SCORE_THRESHOLD += 0.25; } // ---------------------------------------------------------------------- // Consider Anchors // ---------------------------------------------------------------------- struct simple_diag_col *anchors = NULL; struct diag_col adcol; struct alignment *algn= NULL; if(! para->FAST_MODE) { algn = create_empty_alignment(in_seq_col); } struct alignment *salgn = create_empty_alignment(in_seq_col); if(para->DO_ANCHOR>0) { anchors = read_anchors(para->ANCHOR_FILE_NAME, in_seq_col); adcol.diags = anchors->data; adcol.diag_amount = anchors->length; simple_aligner(in_seq_col, &adcol,smatrix,pdist,salgn,1); if(! para->FAST_MODE) simple_aligner(in_seq_col, &adcol,smatrix,pdist,algn,1); if(anchors!=NULL) { for(i=0;iDNA_PARAMETERS && (para->SENS_MODE>0)) { // para->DIAG_THRESHOLD_WEIGHT = -log(0.875); //} struct diag_col *all_diags = find_all_diags(smatrix, pdist, in_seq_col,salgn,1); double duration = (clock()-tim)/CLOCKS_PER_SEC; if(para->DEBUG >1) printf("Found %i diags in %f secs\n", all_diags->diag_amount, duration); int diag_amount = all_diags->diag_amount; // ---------------------------------------------------------------------- // Compute alignment // ---------------------------------------------------------------------- tim2=clock(); if(! para->FAST_MODE) { struct diag *cp_diags[all_diags->diag_amount]; for(i=0;idiags[i]); } guided_aligner(algn, in_seq_col, all_diags,smatrix,pdist,all_diags->gt_root, 1); for(i=0;idiags[i] = cp_diags[i]; } all_diags->diag_amount = diag_amount; } //struct alignment *algn = salgn; simple_aligner(in_seq_col, all_diags,smatrix,pdist,salgn,1); duration = (clock()-tim2)/CLOCKS_PER_SEC; if(! para->FAST_MODE) { if(para->DEBUG >1) printf("First alignment after %f secs. simple: %f guided: %f\n", duration, salgn->total_weight, algn->total_weight); } else { if(para->DEBUG >1) printf("First alignment after %f secs. simple: %f \n", duration, salgn->total_weight); } //if(para->DEBUG >1) printf("First alignment after %f secs. guided: %f\n", duration, algn->total_weight); free_diag_col(all_diags); para->DO_ANCHOR = 0; // anchors done // round 2+ int round; char newFound = 0; int type; //printf(" SENS %i\n", para->SENS_MODE); // consider sensitivity level if(! para->FAST_MODE) { if(para->SENS_MODE==0) { para->DIAG_THRESHOLD_WEIGHT = 0.0; } else if(para->SENS_MODE==1) { if(para->DNA_PARAMETERS) para->DIAG_THRESHOLD_WEIGHT = -log(0.75);//-log(.875+0.125/2.0); else para->DIAG_THRESHOLD_WEIGHT = -log(0.75); }else if(para->SENS_MODE==2) { if(para->DNA_PARAMETERS) para->DIAG_THRESHOLD_WEIGHT = -log(0.5);//-log(0.875); else para->DIAG_THRESHOLD_WEIGHT = -log(0.5); } } int stype = (para->FAST_MODE ? 1 : 0); for(type=stype;type<2;type++) { for(round=2;round<=20;round++) { //for(round=2;round<=1;round++) { tim2=clock(); all_diags = find_all_diags(smatrix, pdist, in_seq_col,(type ? salgn : algn), round); //all_diags = find_all_diags(smatrix, pdist, in_seq_col, algn); duration = (clock()-tim2)/CLOCKS_PER_SEC; if(para->DEBUG >1) printf("Found %i diags after %f secs\n", all_diags->diag_amount, duration); if(all_diags->diag_amount ==0) { free_diag_col(all_diags); break; } else { // round 2 and further we use the simple aligner newFound = simple_aligner(in_seq_col, all_diags,smatrix,pdist,(type ? salgn : algn),round); //newFound = simple_aligner(in_seq_col, all_diags,smatrix,pdist,algn,round); // newFound = complex_aligner(in_seq_col, all_diags,smatrix,pdist,algn,round); free_diag_col(all_diags); if(!newFound) break; } } } if(para->DEBUG >1) printf("Alignment ready!\n"); if(! para->FAST_MODE) { if(para->DEBUG >1) printf("Final alignment simple: %f guided: %f\n", salgn->total_weight, algn->total_weight); } else { if(para->DEBUG >1) printf("Final alignment simple: %f \n", salgn->total_weight); } //if(para->DEBUG >1) printf("Final alignment guided: %f\n", algn->total_weight); if( ( para->FAST_MODE) || (salgn->total_weight > algn->total_weight)) { if(! para->FAST_MODE) free_alignment(algn); algn = salgn; } //algn = salgn; if(para->out_file==NULL) { if(para->OUTPUT){ if(para->DNA_TRANSLATION) simple_print_alignment_dna_retranslate(algn); else simple_print_alignment_default(algn); } else{ simple_print_alignment_default(algn); } }else { if(para->OUTPUT){ if(para->DNA_TRANSLATION) { fasta_print_alignment_dna_retranslate(algn, para->out_file); } else { fasta_print_alignment_default(algn, para->out_file); } } else{ fasta_print_alignment_default(algn, para->out_file); } } duration = (clock()-tim)/CLOCKS_PER_SEC; printf("Total time: %f secs\n", duration); printf("Total weight: %f \n", algn->total_weight); exit(EXIT_SUCCESS); } abyss-2.2.4/dialign/orf.c000066400000000000000000001121231361462241400152040ustar00rootroot00000000000000/** * * orf.c: find the longest Open Reading Frame * * 2004-08-24 Dorothea Emig Volker Menrad * */ #include #include #include "parameters.h" #include "struct.h" #include "translate.h" #include "orf.h" #include "io.h" struct seq_col* set_longest_orf(struct seq_col *in_seq_col) { int i; struct seq_col *ret_seq_col; struct seq *seq, *input_seq; if((ret_seq_col = calloc(1,sizeof(struct seq_col)))==NULL) { error("set_longest_orf(): Out of memory "); } if((ret_seq_col->seqs = calloc((in_seq_col->length),sizeof(struct seq)))==NULL) { error("set_longest_orf(): Out of memory "); } input_seq = &(in_seq_col->seqs[0]); for(i=0; i!= in_seq_col->length; ++i) { seq = orf_finder(input_seq); ++input_seq; ret_seq_col->seqs[i].dna_num = seq->dna_num; ret_seq_col->seqs[i].orf_frame = seq->orf_frame; ret_seq_col->seqs[i].data = seq->data; ret_seq_col->seqs[i].name = seq->name; ret_seq_col->seqs[i].num = seq->num; ret_seq_col->seqs[i].length = seq->length; ++seq; } ret_seq_col->length=in_seq_col->length; return ret_seq_col; } struct seq* orf_finder(struct seq *in_seq) { char flag_no_start = 1; struct seq *ret_seq; struct orf **orfs; int i, max_length, max_orf; char a,b,c,d,e,f; // first three possible reading frames and last three int help, j, x; // XXX........XXX j = (in_seq->length)/3; help = in_seq->length-1; // index of last element in sequence a=0;b=0;c=0;d=0;e=0;f=0; if((orfs = (calloc (12, sizeof(struct orf *)))) == NULL) // We need 12 because we look for the longest orf in every reading frame // and save the longest for every reading frame = 6 // orf[0] && orf[1] for reading frame a // orf[2] && orf[3] for reading frame b // orf[4] && orf[5] for reading frame c // orf[6] && orf[7] for reading frame d // orf[8] && orf[9] for reading frame e // orf[10] && orf[11] for reading frame f { error("orf_finder(): Out of memory !"); } for (x = 0; x != 12; ++x) { if((orfs[x] = (calloc(1,sizeof(struct orf))))==NULL) { error("orf_finder(): Out of memory !"); } if((orfs[x]->sequence = (calloc(j+1,sizeof(char))))==NULL) { error("orf_finder(2): Out of memory !"); } if((orfs[x]->dna_num = (calloc(j+1,sizeof(char))))==NULL) { error("orf_finder(3): Out of memory !"); } orfs[x]->finish = 0; } for (i = 0; i < (j*3)-3; ++i) { /****************************************************************************************/ if (a == 1) { if(!(orfs[0]->finish)) { if((in_seq->data[i] == 'T' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'A') || (in_seq->data[i] == 'U' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'A') || (in_seq->data[i] == 'T' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'G') || (in_seq->data[i] == 'U' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'G') || (in_seq->data[i] == 'T' && in_seq->data[i+1] == 'G' && in_seq->data[i+2] == 'A') || (in_seq->data[i] == 'U' && in_seq->data[i+1] == 'G' && in_seq->data[i+2] == 'A') ) //Stop-Codon then end orf { orfs[0]->finish = 1; // end orf a=0; // wait for new ATG-Start-Codon } orfs[0]->sequence[(orfs[0]->length)] = translate(in_seq->data[i], in_seq->data[i+1], in_seq->data[i+2], &(orfs[0]->dna_num[(orfs[0]->length)]) ); // translate in aminoacid and safe in orf ++orfs[0]->length; } else { if((in_seq->data[i] == 'T' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'A') || (in_seq->data[i] == 'U' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'A') || (in_seq->data[i] == 'T' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'G') || (in_seq->data[i] == 'U' && in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'G') || (in_seq->data[i] == 'T' && in_seq->data[i+1] == 'G' && in_seq->data[i+2] == 'A') || (in_seq->data[i] == 'U' && in_seq->data[i+1] == 'G' && in_seq->data[i+2] == 'A') ) { orfs[1]->finish = 1; a=0; } orfs[1]->sequence[(orfs[1]->length)] = translate(in_seq->data[i], in_seq->data[i+1], in_seq->data[i+2],&(orfs[1]->dna_num[(orfs[1]->length)])); ++orfs[1]->length; } } /****************************************************************************************/ if (b == 1) { if(!(orfs[2]->finish)) { if((in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'A') || (in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'A') || (in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'G') || (in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'G') || (in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'G' && in_seq->data[i+3] == 'A') || (in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'G' && in_seq->data[i+3] == 'A') ) //Stop-Codon then end orf { orfs[2]->finish = 1; // end orf b=0; // wait for new ATG-Start-Codon } orfs[2]->sequence[(orfs[2]->length)] = translate(in_seq->data[i+1], in_seq->data[i+2], in_seq->data[i+3],&(orfs[2]->dna_num[(orfs[2]->length)]) ); // translate in aminoacid and safe in orf ++orfs[2]->length; } else { if((in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'A') || (in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'A') || (in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'G') || (in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'G') || (in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'G' && in_seq->data[i+3] == 'A') || (in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'G' && in_seq->data[i+3] == 'A') ) { orfs[3]->finish = 1; b=0; } orfs[3]->sequence[(orfs[3]->length)] = translate(in_seq->data[i+1], in_seq->data[i+2], in_seq->data[i+3],&(orfs[3]->dna_num[(orfs[3]->length)]) ); ++orfs[3]->length; } } /****************************************************************************************/ if (c == 1) { if(!(orfs[4]->finish)) { if((in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'A') || (in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'A') || (in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'G') || (in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'G') || (in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'G' && in_seq->data[i+4] == 'A') || (in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'G' && in_seq->data[i+4] == 'A') ) //Stop-Codon then end orf { orfs[4]->finish = 1; // end orf c=0; // wait for new ATG-Start-Codon } orfs[4]->sequence[(orfs[4]->length)] = translate(in_seq->data[i+2], in_seq->data[i+3], in_seq->data[i+4],&(orfs[4]->dna_num[(orfs[4]->length)])); // translate in aminoacid and safe in orf ++orfs[4]->length; } else { if((in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'A') || (in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'A') || (in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'G') || (in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'A' && in_seq->data[i+4] == 'G') || (in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'G' && in_seq->data[i+4] == 'A') || (in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'G' && in_seq->data[i+4] == 'A') ) { orfs[5]->finish = 1; c=0; } orfs[5]->sequence[(orfs[5]->length)] = translate(in_seq->data[i+2], in_seq->data[i+3], in_seq->data[i+4],&(orfs[5]->dna_num[(orfs[5]->length)]) ); ++orfs[5]->length; } } /****************************************************************************************/ /****************************************************************************************/ if (d == 1) { if(!(orfs[6]->finish)) /* Da Crick-Strand : TAA -> ATT UAA -> AUU TAG -> ATC UAG -> AUC TGA -> ACT UGA -> ACU */ { if((in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'T' && in_seq->data[help-(i+4)] == 'T') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'U' && in_seq->data[help-(i+4)] == 'U') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'T' && in_seq->data[help-(i+4)] == 'C') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'U' && in_seq->data[help-(i+4)] == 'C') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'C' && in_seq->data[help-(i+4)] == 'T') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'C' && in_seq->data[help-(i+4)] == 'U') ) //Stop-Codon then end orf { orfs[6]->finish = 1; // end orf d=0; // wait for new ATG-Start-Codon } orfs[6]->sequence[(orfs[6]->length)] = translate(inverse(in_seq->data[help-(i+2)]), inverse(in_seq->data[help-(i+3)]), inverse(in_seq->data[help-(i+4)]),&(orfs[6]->dna_num[(orfs[6]->length)]) ); // translate in aminoacid and safe in orf ++orfs[6]->length; } else { if((in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'T' && in_seq->data[help-(i+4)] == 'T') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'U' && in_seq->data[help-(i+4)] == 'U') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'T' && in_seq->data[help-(i+4)] == 'C') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'U' && in_seq->data[help-(i+4)] == 'C') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'C' && in_seq->data[help-(i+4)] == 'T') || (in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'C' && in_seq->data[help-(i+4)] == 'U') ) { orfs[7]->finish = 1; d=0; } orfs[7]->sequence[(orfs[7]->length)] = translate(inverse(in_seq->data[help-(i+2)]), inverse(in_seq->data[help-(i+3)]), inverse(in_seq->data[help-(i+4)]),&(orfs[7]->dna_num[(orfs[7]->length)]) ); ++orfs[7]->length; } } /****************************************************************************************/ if (e == 1) { if(!(orfs[8]->finish)) { if((in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'T' && in_seq->data[help-(i+3)] == 'T') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'U' && in_seq->data[help-(i+3)] == 'U') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'T' && in_seq->data[help-(i+3)] == 'C') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'U' && in_seq->data[help-(i+3)] == 'C') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'C' && in_seq->data[help-(i+3)] == 'T') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'C' && in_seq->data[help-(i+3)] == 'U') ) //Stop-Codon then end orf { orfs[8]->finish = 1; // end orf e=0; // wait for new ATG-Start-Codon } orfs[8]->sequence[(orfs[8]->length)] = translate(inverse(in_seq->data[help-(i+1)]), inverse(in_seq->data[help-(i+2)]), inverse(in_seq->data[help-(i+3)]),&(orfs[8]->dna_num[(orfs[8]->length)]) ); // translate in aminoacid and safe in orf ++orfs[8]->length; } else { if((in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'T' && in_seq->data[help-(i+3)] == 'T') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'U' && in_seq->data[help-(i+3)] == 'U') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'T' && in_seq->data[help-(i+3)] == 'C') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'U' && in_seq->data[help-(i+3)] == 'C') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'C' && in_seq->data[help-(i+3)] == 'T') || (in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'C' && in_seq->data[help-(i+3)] == 'U') ) { orfs[9]->finish = 1; e=0; } orfs[9]->sequence[(orfs[9]->length)] = translate(inverse(in_seq->data[help-(i+1)]), inverse(in_seq->data[help-(i+2)]), inverse(in_seq->data[help-(i+3)]), &(orfs[9]->dna_num[(orfs[9]->length)]) ); ++orfs[9]->length; } } /****************************************************************************************/ if (f == 1) { if(!(orfs[10]->finish)) { if((in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'T' && in_seq->data[help-(i+2)] == 'T') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'U' && in_seq->data[help-(i+2)] == 'U') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'T' && in_seq->data[help-(i+2)] == 'C') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'U' && in_seq->data[help-(i+2)] == 'C') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'C' && in_seq->data[help-(i+2)] == 'T') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'C' && in_seq->data[help-(i+2)] == 'U') ) //Stop-Codon then end orf { orfs[10]->finish = 1; // end orf f=0; // wait for new ATG-Start-Codon } orfs[10]->sequence[(orfs[10]->length)] = translate(inverse(in_seq->data[help-(i)]), inverse(in_seq->data[help-(i+1)]), inverse(in_seq->data[help-(i+2)]), &(orfs[10]->dna_num[(orfs[10]->length)])); // translate in aminoacid and safe in orf ++orfs[10]->length; } else { if((in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'T' && in_seq->data[help-(i+2)] == 'T') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'U' && in_seq->data[help-(i+2)] == 'T') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'T' && in_seq->data[help-(i+2)] == 'C') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'U' && in_seq->data[help-(i+2)] == 'C') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'C' && in_seq->data[help-(i+2)] == 'T') || (in_seq->data[help-(i)] == 'A' && in_seq->data[help-(i+1)] == 'C' && in_seq->data[help-(i+2)] == 'U') ) { orfs[11]->finish = 1; f=0; } orfs[11]->sequence[(orfs[11]->length)] = translate(inverse(in_seq->data[help-(i)]), inverse(in_seq->data[help-(i+1)]), inverse(in_seq->data[help-(i+2)]), &(orfs[11]->dna_num[(orfs[11]->length)])); ++orfs[11]->length; } } /****************************************************************************************/ /****************************************************************************************/ if(((in_seq->data[i] == 'A' && in_seq->data[i+1] == 'T' && in_seq->data[i+2] == 'G') && (a==0)) || ( (in_seq->data[i] == 'A' && in_seq->data[i+1] == 'U' && in_seq->data[i+2] == 'G') && (a==0))) { a=1; // start found in first reading frame flag_no_start=0; if(!(orfs[0]->finish)) // orf not yet started in orfs[0] { orfs[0]->length=0; orfs[0]->sequence[(orfs[0]->length)] = translate(in_seq->data[i],in_seq->data[i+1],in_seq->data[i+2], &(orfs[0]->dna_num[(orfs[0]->length)]) ); ++orfs[0]->length; } else if(!(orfs[1]->finish))// orf not yet started in orfs[1] { orfs[1]->length=0; orfs[1]->sequence[(orfs[1]->length)] = translate(in_seq->data[i],in_seq->data[i+1],in_seq->data[i+2], &(orfs[1]->dna_num[(orfs[1]->length)]) ); ++orfs[1]->length; } else // orf finished in orfs[1] and orfs[0], so find the max and delete the min { if((orfs[0]->length) >= (orfs[1]->length)) // orfs[0] = Max { free(orfs[1]->sequence); free(orfs[1]->dna_num); free(orfs[1]); if((orfs[1] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[1]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[1]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[1]->length=0; // new init orfs[1]->finish = 0; orfs[1]->sequence[(orfs[1]->length)] = translate(in_seq->data[i],in_seq->data[i+1],in_seq->data[i+2], &(orfs[1]->dna_num[(orfs[1]->length)]) ); ++orfs[1]->length; } else { free(orfs[0]->dna_num); free(orfs[0]->sequence); free(orfs[0]); if((orfs[0] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[0]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[0]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[0]->length = 0; // new init orfs[0]->finish = 0; orfs[0]->sequence[(orfs[0]->length)] = translate(in_seq->data[i],in_seq->data[i+1],in_seq->data[i+2], &(orfs[0]->dna_num[(orfs[0]->length)]) ); ++orfs[0]->length; } } } /****************************************************************************************/ if(((in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'T' && in_seq->data[i+3] == 'G') && (b==0)) || ( (in_seq->data[i+1] == 'A' && in_seq->data[i+2] == 'U' && in_seq->data[i+3] == 'G') && (b==0))) { b=1; // start found in second reading frame flag_no_start=0; if(!(orfs[2]->finish)) // orf not yet started in orfs[2] { orfs[2]->length=0; orfs[2]->sequence[(orfs[2]->length)] = translate(in_seq->data[i+1],in_seq->data[i+2],in_seq->data[i+3], &(orfs[2]->dna_num[(orfs[2]->length)]) ); ++orfs[2]->length; } else if(!(orfs[3]->finish))// orf not yet started in orfs[3] { orfs[3]->length=0; orfs[3]->sequence[(orfs[3]->length)] = translate(in_seq->data[i+1],in_seq->data[i+2],in_seq->data[i+3], &(orfs[3]->dna_num[(orfs[3]->length)]) ); ++orfs[3]->length; } else // orf finished in orfs[3] and orfs[2], so find the max and delete the min { if((orfs[2]->length) >= (orfs[3]->length)) // orfs[2] = Max { free(orfs[3]->dna_num); free(orfs[3]->sequence); free(orfs[3]); if((orfs[3] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[3]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[3]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[3]->length=0; // new init orfs[3]->finish = 0; orfs[3]->sequence[(orfs[3]->length)] = translate(in_seq->data[i+1],in_seq->data[i+2],in_seq->data[i+3], &(orfs[3]->dna_num[(orfs[3]->length)]) ); ++orfs[3]->length; } else { free(orfs[2]->dna_num); free(orfs[2]->sequence); free(orfs[2]); if((orfs[2] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[2]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[2]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[2]->length = 0; // new init orfs[2]->finish = 0; orfs[2]->sequence[(orfs[2]->length)] = translate(in_seq->data[i+1],in_seq->data[i+2],in_seq->data[i+3], &(orfs[2]->dna_num[(orfs[2]->length)]) ); ++orfs[2]->length; } } } /****************************************************************************************/ if(((in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'T' && in_seq->data[i+4] == 'G') && (c==0)) || ( (in_seq->data[i+2] == 'A' && in_seq->data[i+3] == 'U' && in_seq->data[i+4] == 'G') && (c==0) )) { c=1; // start found in third reading frame flag_no_start=0; if(!(orfs[4]->finish)) // orf not yet started in orfs[4] { orfs[4]->length=0; orfs[4]->sequence[(orfs[4]->length)] = translate(in_seq->data[i+2],in_seq->data[i+3],in_seq->data[i+4], &(orfs[4]->dna_num[(orfs[4]->length)]) ); ++orfs[4]->length; } else if(!(orfs[5]->finish))// orf not yet started in orfs[5] { orfs[5]->length=0; orfs[5]->sequence[(orfs[5]->length)] = translate(in_seq->data[i+2],in_seq->data[i+3],in_seq->data[i+4], &(orfs[5]->dna_num[(orfs[5]->length)]) ); ++orfs[5]->length; } else // orf finished in orfs[5] and orfs[4], so find the max and delete the min { if((orfs[4]->length) >= (orfs[5]->length)) // orfs[4] = Max { free(orfs[5]->dna_num); free(orfs[5]->sequence); free(orfs[5]); if((orfs[5] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[5]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[5]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[5]->length=0; // new init orfs[5]->finish = 0; orfs[5]->sequence[(orfs[5]->length)] = translate(in_seq->data[i+2],in_seq->data[i+3],in_seq->data[i+4], &(orfs[5]->dna_num[(orfs[5]->length)]) ); ++orfs[5]->length; } else { free(orfs[4]->dna_num); free(orfs[4]->sequence); free(orfs[4]); if((orfs[4] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[4]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[4]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[4]->length = 0; // new init orfs[4]->finish = 0; orfs[4]->sequence[(orfs[4]->length)] = translate(in_seq->data[i+2],in_seq->data[i+3],in_seq->data[i+4], &(orfs[4]->dna_num[(orfs[4]->length)]) ); ++orfs[4]->length; } } } /****************************************************************************************/ /****************************************************************************************/ if(((in_seq->data[help-(i+2)] == 'T' && in_seq->data[help-(i+3)] == 'A' && in_seq->data[help-(i+4)] == 'C') && (d==0)) || ( (in_seq->data[help-(i+2)] == 'U' && in_seq->data[help-(i+3)] == 'A' && in_seq->data[help-(i+4)] == 'C') && (d==0) )) { d=1; // start found in last but two reading frame flag_no_start=0; if(!(orfs[6]->finish)) // orf not yet started in orfs[6] { orfs[6]->length=0; orfs[6]->sequence[(orfs[6]->length)] = translate(in_seq->data[help-(i+2)],in_seq->data[help-(i+3)],in_seq->data[help-(i+4)], &(orfs[6]->dna_num[(orfs[6]->length)]) ); ++orfs[6]->length; } else if(!(orfs[7]->finish))// orf not yet started in orfs[7] { orfs[7]->length=0; orfs[7]->sequence[(orfs[7]->length)] = translate(in_seq->data[help-(i+2)],in_seq->data[help-(i+3)],in_seq->data[help-(i+4)], &(orfs[7]->dna_num[(orfs[7]->length)]) ); ++orfs[7]->length; } else // orf finished in orfs[7] and orfs[6], so find the max and delete the min { if((orfs[6]->length) >= (orfs[7]->length)) // orfs[6] = Max { free(orfs[7]->dna_num); free(orfs[7]->sequence); free(orfs[7]); if((orfs[7] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[7]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[7]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[7]->length=0; // new init orfs[7]->finish = 0; orfs[7]->sequence[(orfs[7]->length)] = translate(in_seq->data[help-(i+2)],in_seq->data[help-(i+3)],in_seq->data[help-(i+4)], &(orfs[7]->dna_num[(orfs[7]->length)]) ); ++orfs[7]->length; } else { free(orfs[6]->dna_num); free(orfs[6]->sequence); free(orfs[6]); if((orfs[6] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[6]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[6]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[6]->length = 0; // new init orfs[6]->finish = 0; orfs[6]->sequence[(orfs[6]->length)] = translate(in_seq->data[help-(i+2)],in_seq->data[help-(i+3)],in_seq->data[help-(i+4)], &(orfs[6]->dna_num[(orfs[6]->length)]) ); ++orfs[6]->length; } } } /****************************************************************************************/ if(((in_seq->data[help-(i+1)] == 'T' && in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'C') && (e==0)) || ( (in_seq->data[help-(i+1)] == 'U' && in_seq->data[help-(i+2)] == 'A' && in_seq->data[help-(i+3)] == 'C') && (e==0))) { e=1; // start found in last but one reading frame flag_no_start=0; if(!(orfs[8]->finish)) // orf not yet started in orfs[8] { orfs[8]->length=0; orfs[8]->sequence[(orfs[8]->length)] = translate(in_seq->data[help-(i+1)],in_seq->data[help-(i+2)],in_seq->data[help-(i+3)], &(orfs[8]->dna_num[(orfs[8]->length)]) ); ++orfs[8]->length; } else if(!(orfs[9]->finish))// orf not yet started in orfs[9] { orfs[9]->length=0; orfs[9]->sequence[(orfs[9]->length)] = translate(in_seq->data[help-(i+1)],in_seq->data[help-(i+2)],in_seq->data[help-(i+3)], &(orfs[9]->dna_num[(orfs[9]->length)]) ); ++orfs[9]->length; } else // orf finished in orfs[9] and orfs[8], so find the max and delete the min { if((orfs[8]->length) >= (orfs[9]->length)) // orfs[8] = Max { free(orfs[9]->dna_num); free(orfs[9]->sequence); free(orfs[9]); if((orfs[9] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[9]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[9]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[9]->length=0; // new init orfs[9]->finish = 0; orfs[9]->sequence[(orfs[9]->length)] = translate(in_seq->data[help-(i+1)],in_seq->data[help-(i+2)],in_seq->data[help-(i+3)], &(orfs[9]->dna_num[(orfs[9]->length)]) ); ++orfs[9]->length; } else { // printf(" im else also orf[0]dna_num); free(orfs[8]->sequence); free(orfs[8]); if((orfs[8] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[8]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[8]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[8]->length = 0; // new init orfs[8]->finish = 0; orfs[8]->sequence[(orfs[8]->length)] = translate(in_seq->data[help-(i+1)],in_seq->data[help-(i+2)],in_seq->data[help-(i+3)], &(orfs[8]->dna_num[(orfs[8]->length)]) ); ++orfs[8]->length; } } } /****************************************************************************************/ if(((in_seq->data[help-i] == 'T' && in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'C') && (f==0)) || ( (in_seq->data[help-i] == 'U' && in_seq->data[help-(i+1)] == 'A' && in_seq->data[help-(i+2)] == 'C') && (f==0))) { f=1; // start found in last reading frame flag_no_start=0; if(!(orfs[10]->finish)) // orf not yet started in orfs[10] { orfs[10]->length=0; orfs[10]->sequence[(orfs[10]->length)] = translate(in_seq->data[help-(i)],in_seq->data[help-(i+1)],in_seq->data[help-(i+2)], &(orfs[10]->dna_num[(orfs[10]->length)]) ); ++orfs[10]->length; } else if(!(orfs[11]->finish))// orf not yet started in orfs[11] { orfs[11]->length=0; orfs[11]->sequence[(orfs[11]->length)] = translate(in_seq->data[help-(i)],in_seq->data[help-(i+1)],in_seq->data[help-(i+2)], &(orfs[11]->dna_num[(orfs[11]->length)]) ); ++orfs[11]->length; } else // orf finished in orfs[11] and orfs[10], so find the max and delete the min { if((orfs[10]->length) >= (orfs[11]->length)) // orfs[10] = Max { free(orfs[11]->dna_num); free(orfs[11]->sequence); free(orfs[11]); if((orfs[11] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[11]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[11]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[11]->length=0; // new init orfs[11]->finish = 0; orfs[11]->sequence[(orfs[11]->length)] = translate(in_seq->data[help-(i)],in_seq->data[help-(i+1)],in_seq->data[help-(i+2)], &(orfs[11]->dna_num[(orfs[11]->length)]) ); ++orfs[11]->length; } else { free(orfs[10]->dna_num); free(orfs[10]->sequence); free(orfs[10]); if((orfs[10] = calloc(1, sizeof(struct orf))) == NULL) // free memory error("orf_finder(): Out of memory!"); if((orfs[10]->sequence = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); if((orfs[10]->dna_num = calloc(j+1, sizeof(char))) == NULL) error("orf_finder(): Out of memory!"); orfs[10]->length = 0; // new init orfs[10]->finish = 0; orfs[10]->sequence[(orfs[10]->length)] = translate(in_seq->data[help-(i)],in_seq->data[help-(i+1)],in_seq->data[help-(i+2)], &(orfs[10]->dna_num[(orfs[10]->length)]) ); ++orfs[10]->length; } } } /****************************************************************************************/ /****************************************************************************************/ i = i+2; } // if last codon in reading frame is no stop codon -> translate last codon if available if (((help+1) % 3) == 0) // length = last index + 1 ;translate last codon for orf 1 and orf 6 { // a: if (!orfs[0]->finish && orfs[0]->length) // open orf && already started before { orfs[0]->sequence[(orfs[0]->length)] = translate(in_seq->data[help-2], in_seq->data[help-1], in_seq->data[help], &(orfs[0]->dna_num[(orfs[0]->length)])); ++orfs[0]->length; } else if (!orfs[1]->finish && orfs[1]->length) { orfs[1]->sequence[(orfs[1]->length)] = translate(in_seq->data[help-2], in_seq->data[help-1], in_seq->data[help], &(orfs[1]->dna_num[(orfs[1]->length)])); ++orfs[1]->length; } // f: if (!(orfs[10]->finish) && orfs[10]->length ) { orfs[10]->sequence[(orfs[10]->length)] = translate(inverse(in_seq->data[2]), inverse(in_seq->data[1]), inverse(in_seq->data[0]), &(orfs[10]->dna_num[(orfs[10]->length)]) ); ++orfs[10]->length; } else if (!orfs[11]->finish && orfs[11]->length ) { orfs[11]->sequence[(orfs[11]->length)] = translate(inverse(in_seq->data[2]), inverse(in_seq->data[1]), inverse(in_seq->data[0]), &(orfs[11]->dna_num[(orfs[11]->length)]) ); ++orfs[11]->length; } } else if (((help+1) % 3) == 1) { // a: if (!orfs[0]->finish && orfs[0]->length) // open orf && already started before { orfs[0]->sequence[(orfs[0]->length)] = translate(in_seq->data[help-3], in_seq->data[help-2], in_seq->data[help-1], &(orfs[0]->dna_num[(orfs[0]->length)]) ); ++orfs[0]->length; } else if (!orfs[1]->finish && orfs[1]->length) { orfs[1]->sequence[(orfs[1]->length)] = translate(in_seq->data[help-3], in_seq->data[help-2], in_seq->data[help-1], &(orfs[1]->dna_num[(orfs[1]->length)]) ); ++orfs[1]->length; } // b: if (!orfs[2]->finish && orfs[2]->length) // open orf && already started before { orfs[2]->sequence[(orfs[2]->length)] = translate(in_seq->data[help-2], in_seq->data[help-1], in_seq->data[help], &(orfs[2]->dna_num[(orfs[2]->length)]) ); ++orfs[2]->length; } else if (!orfs[3]->finish && orfs[3]->length) { orfs[3]->sequence[(orfs[3]->length)] = translate(in_seq->data[help-2], in_seq->data[help-1], in_seq->data[help], &(orfs[3]->dna_num[(orfs[3]->length)]) ); ++orfs[3]->length; } // e: if (!(orfs[8]->finish) && orfs[8]->length ) { orfs[8]->sequence[(orfs[8]->length)] = translate(inverse(in_seq->data[2]), inverse(in_seq->data[1]), inverse(in_seq->data[0]), &(orfs[8]->dna_num[(orfs[8]->length)]) ); ++orfs[8]->length; } else if (!orfs[9]->finish && orfs[9]->length ) { orfs[9]->sequence[(orfs[9]->length)] = translate(inverse(in_seq->data[2]), inverse(in_seq->data[1]), inverse(in_seq->data[0]), &(orfs[9]->dna_num[(orfs[9]->length)]) ); ++orfs[9]->length; } // f: if (!(orfs[10]->finish) && orfs[10]->length ) { orfs[10]->sequence[(orfs[10]->length)] = translate(inverse(in_seq->data[3]), inverse(in_seq->data[2]), inverse(in_seq->data[1]), &(orfs[10]->dna_num[(orfs[10]->length)]) ); ++orfs[10]->length; } else if (!orfs[11]->finish && orfs[11]->length ) { orfs[11]->sequence[(orfs[11]->length)] = translate(inverse(in_seq->data[3]), inverse(in_seq->data[2]), inverse(in_seq->data[1]), &(orfs[11]->dna_num[(orfs[11]->length)]) ); ++orfs[11]->length; } } else { // a: if (!orfs[0]->finish && orfs[0]->length) // open orf && already started before { orfs[0]->sequence[(orfs[0]->length)] = translate(in_seq->data[help-4], in_seq->data[help-3], in_seq->data[help-2], &(orfs[0]->dna_num[(orfs[0]->length)]) ); ++orfs[0]->length; } else if (!orfs[1]->finish && orfs[1]->length) { orfs[1]->sequence[(orfs[1]->length)] = translate(in_seq->data[help-4], in_seq->data[help-3], in_seq->data[help-2], &(orfs[1]->dna_num[(orfs[1]->length)])); ++orfs[1]->length; } // b: if (!orfs[2]->finish && orfs[2]->length) // open orf && already started before { orfs[2]->sequence[(orfs[2]->length)] = translate(in_seq->data[help-3], in_seq->data[help-2], in_seq->data[help-1], &(orfs[2]->dna_num[(orfs[2]->length)]) ); ++orfs[2]->length; } else if (!orfs[3]->finish && orfs[3]->length) { orfs[3]->sequence[(orfs[3]->length)] = translate(in_seq->data[help-3], in_seq->data[help-2], in_seq->data[help-1], &(orfs[3]->dna_num[(orfs[3]->length)]) ); ++orfs[3]->length; } // c: if (!orfs[4]->finish && orfs[4]->length) // open orf && already started before { orfs[4]->sequence[(orfs[4]->length)] = translate(in_seq->data[help-2], in_seq->data[help-1], in_seq->data[help],&(orfs[4]->dna_num[(orfs[4]->length)]) ); ++orfs[4]->length; } else if (!orfs[5]->finish && orfs[5]->length) { orfs[5]->sequence[(orfs[5]->length)] = translate(in_seq->data[help-2], in_seq->data[help-1], in_seq->data[help],&(orfs[5]->dna_num[(orfs[5]->length)]) ); ++orfs[5]->length; } // d: if (!(orfs[6]->finish) && orfs[6]->length ) { orfs[6]->sequence[(orfs[6]->length)] = translate(inverse(in_seq->data[2]), inverse(in_seq->data[1]), inverse(in_seq->data[0]), &(orfs[6]->dna_num[(orfs[6]->length)]) ); ++orfs[6]->length; } else if (!orfs[7]->finish && orfs[7]->length ) { orfs[7]->sequence[(orfs[7]->length)] = translate(inverse(in_seq->data[2]), inverse(in_seq->data[1]), inverse(in_seq->data[0]), &(orfs[7]->dna_num[(orfs[7]->length)]) ); ++orfs[7]->length; } // e: if (!(orfs[8]->finish) && orfs[8]->length ) { orfs[8]->sequence[(orfs[8]->length)] = translate(inverse(in_seq->data[3]), inverse(in_seq->data[2]), inverse(in_seq->data[1]), &(orfs[8]->dna_num[(orfs[8]->length)]) ); ++orfs[8]->length; } else if (!orfs[9]->finish && orfs[9]->length ) { orfs[9]->sequence[(orfs[9]->length)] = translate(inverse(in_seq->data[3]), inverse(in_seq->data[2]), inverse(in_seq->data[1]), &(orfs[9]->dna_num[(orfs[9]->length)]) ); ++orfs[9]->length; } // f: if (!(orfs[10]->finish) && orfs[10]->length ) { orfs[10]->sequence[(orfs[10]->length)] = translate(inverse(in_seq->data[4]), inverse(in_seq->data[3]), inverse(in_seq->data[2]), &(orfs[10]->dna_num[(orfs[10]->length)]) ); ++orfs[10]->length; } else if (!orfs[11]->finish && orfs[11]->length ) { orfs[11]->sequence[(orfs[11]->length)] = translate(inverse(in_seq->data[4]), inverse(in_seq->data[3]), inverse(in_seq->data[2]), &(orfs[11]->dna_num[(orfs[11]->length)]) ); ++orfs[11]->length; } } // now we got 12 orfs and we search for the longest if((ret_seq = calloc(1,sizeof(struct seq)))==NULL) { error("orf_finder(): Out of memory"); } max_length=orfs[0]->length; max_orf=0; for (i=1; i != 12; ++i) { if(max_lengthlength) { max_length=orfs[i]->length; max_orf=i; } } if((ret_seq->data = calloc(max_length+1, sizeof(char)))==NULL) { error("orf_finder(): Out of memory"); } if((ret_seq->dna_num = calloc(max_length+1, sizeof(char)))==NULL) { error("orf_finder(): Out of memory"); } if(max_orf >5)ret_seq->crick_strand=1; ret_seq->name=in_seq->name; ret_seq->length = max_length; ret_seq->num=in_seq->num; ret_seq->orf_frame=max_orf/2; // As orf[1] && orf[0] = Reading frame 0 ,... for(i=0; i!= max_length; i++) { ret_seq->dna_num[i]=orfs[max_orf]->dna_num[i]; ret_seq->data[i]=orfs[max_orf]->sequence[i]; } // free memory for (x = 0; x != 12; ++x) { free(orfs[x]->dna_num); free(orfs[x]->sequence); free(orfs[x]); } free(orfs); if(flag_no_start){ char tmp[300]; sprintf(tmp,"orf_finder(): No Startcodon found in Sequence %s !\n", in_seq->name ); if(para->ORF_FRAME) printf("\n%sStarting translation for Sequence %s in reading frame 0\n\n", tmp,in_seq->name); else error(tmp); } return ret_seq; } abyss-2.2.4/dialign/orf.h000066400000000000000000000024241361462241400152130ustar00rootroot00000000000000/** * * orf.h: * * 2004-08-24 Dorothea Emig Volker Menrad * */ /************************************************/ /* */ /* structs */ /* */ /************************************************/ struct orf { int length; // length of found orf char *sequence; // part of the sequence in the orf char finish; char *dna_num; // retranslation }; /************************************************/ /* */ /* global variable */ /* */ /************************************************/ /*********************************************/ /* */ /* functions from parameters.c */ /* */ /*********************************************/ struct seq_col* set_longest_orf(struct seq_col *in_seq_col); struct seq* orf_finder(struct seq *in_seq_col); //char inverse(char base); //char translate(char first_base, char second_base, char third_base,char* dna_number_for_retranslate); abyss-2.2.4/dialign/parameters.c000066400000000000000000000240421361462241400165630ustar00rootroot00000000000000/** * * parameters.c: Read from stdin * * */ #include #include #include #include #include #include #include #include "parameters.h" #include "struct.h" #include "io.h" #ifdef __unix__ #include #include #else #include #endif extern char *optarg; extern int optind, opterr, optopt; struct parameters* para; /**************************** * PROTEIN DEFAULT VALUES! * ****************************/ void init_parameters() { if((para =(struct parameters *) malloc(sizeof(struct parameters)) ) == NULL) { error("init_parameters(): Out of memory when allocating data !"); } para->VERSION = "1.0.2"; para->DEBUG = 0; para->MAX_SEQ_AMOUNT = 5000; para->MAX_FASTA_LINE_LENGTH = 100; para->PRINT_SEQ_LINE_LENGTH = 80; para->SCR_MATRIX_FILE_NAME="BLOSUM.scr"; para->DIAG_CALC_WEIGHT_THRESHOLD = 0.000000065; para->DIAG_PROB_FILE_NAME="BLOSUM.diag_prob_t10"; para->SCR_MATRIX_ADD = 0; para->PROT_SIM_SCORE_THRESHOLD = 4.0; //para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS = 4; //para->PROT_DIAG_MIN_LENGTH_THRESHOLD = 10.0; para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS = 4; para->PROT_DIAG_MIN_LENGTH_THRESHOLD = 40.0; para->PROT_DIAG_AVG_SCORE_THRESHOLD = 4.0; para->DO_ANCHOR = 0; para->ANCHOR_FILE_NAME = NULL; para->DO_OVERLAP = 0; para->DIAG_MIN_LENGTH = 1; para->FAST_MODE = 0; para->SENS_MODE = 0; para->DIAG_THRESHOLD_WEIGHT = -log(0.5); para->FAST_PAIRWISE_ALIGNMENT = 0; para->conf_dir = NULL; para->in_file = NULL; para->out_file = NULL; para->COMPUTE_PROB=0; para->STATE_ORPHANE=1; para->STATE_INHERITED=2; para->DNA_PARAMETERS = 0; para->DNA_TRANSLATION = 0; para->FIND_ORF = 0; para->ORF_FRAME = 0; para->OUTPUT = 0; } /**************************** * DNA DEFAULT VALUES! * ****************************/ void set_parameters_dna() { para->VERSION = "1.0.2"; para->DEBUG = 0; para->MAX_SEQ_AMOUNT = 5000; para->MAX_FASTA_LINE_LENGTH = 100; para->PRINT_SEQ_LINE_LENGTH = 80; para->SCR_MATRIX_FILE_NAME="dna_matrix.scr"; para->DIAG_CALC_WEIGHT_THRESHOLD = 0.000000065; para->DIAG_PROB_FILE_NAME="dna_diag_prob_100_exp_550000"; para->SCR_MATRIX_ADD = 0; para->PROT_SIM_SCORE_THRESHOLD = 0.25; para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS = 4; // 1 para->PROT_DIAG_MIN_LENGTH_THRESHOLD = 40.0;//40.0; // 1 para->PROT_DIAG_AVG_SCORE_THRESHOLD = 0.25; //1.0 para->DO_ANCHOR = 0; para->ANCHOR_FILE_NAME = NULL; para->DO_OVERLAP = 0; para->DIAG_MIN_LENGTH = 1; para->FAST_MODE = 0; para->SENS_MODE = 0; para->DIAG_THRESHOLD_WEIGHT = -log(0.5);//-log(0.875); para->FAST_PAIRWISE_ALIGNMENT = 0; para->conf_dir = NULL; para->in_file = NULL; para->out_file = NULL; para->COMPUTE_PROB=0; para->STATE_ORPHANE=1; para->STATE_INHERITED=2; para->DNA_PARAMETERS = 1; para->DNA_TRANSLATION = 0; para->FIND_ORF = 0; para->ORF_FRAME = 0; para->OUTPUT = 1; } void check_input(int argc, char** argv) { int flag_protein_output = 0; opterr = 1; optind = 0; int opt, only_config_dir = 0; while((opt = getopt(argc, argv,"PDTLOCFHhA:d:s:a:c:l:m:w:p:v:t:n:g:o:r:u"))!= -1){ switch(opt){ case 'd': para->DEBUG = atoi(optarg); break; case 's': para->MAX_SEQ_AMOUNT = atoi(optarg); break; case 'a': para->MAX_FASTA_LINE_LENGTH = atoi(optarg); break; case 'c': para->PRINT_SEQ_LINE_LENGTH = atoi(optarg); break; case 'l': para->SENS_MODE = atoi(optarg); break; case 'A': para->ANCHOR_FILE_NAME = optarg; para->DO_ANCHOR = 1; break; case 'm': para->SCR_MATRIX_FILE_NAME = optarg; break; case 'w': para->DIAG_CALC_WEIGHT_THRESHOLD = atof(optarg); break; case 'p': para->DIAG_PROB_FILE_NAME = optarg; break; case 'v': para->SCR_MATRIX_ADD = atoi(optarg); break; case 't': para->PROT_SIM_SCORE_THRESHOLD = atoi(optarg); break; case 'n': para->PROT_DIAG_MAX_UNDER_THRESHOLD_POS = atoi(optarg); break; case 'g': para->PROT_DIAG_MIN_LENGTH_THRESHOLD = atof(optarg); break; case 'r': para->PROT_DIAG_AVG_SCORE_THRESHOLD = atof(optarg); break; case 'o': para->DO_OVERLAP = atoi(optarg); break; case 'u': para->DIAG_MIN_LENGTH = atoi(optarg); break; case 'h': wrong_input(); case 'H': wrong_input(); case 'C': only_config_dir = 1; para->COMPUTE_PROB = 1; break; case 'F': para->DIAG_THRESHOLD_WEIGHT = 0.0; para->FAST_MODE = 1; break; case 'O': para->DNA_PARAMETERS = 0; para->DNA_TRANSLATION = 1; para->FIND_ORF = 1; para->ORF_FRAME = 1; para->OUTPUT = 1; break; case 'L': para->DNA_PARAMETERS = 0; para->DNA_TRANSLATION = 1; para->FIND_ORF = 1; para->ORF_FRAME = 0; para->OUTPUT = 1; break; case 'T': para->DNA_PARAMETERS = 0; para->DNA_TRANSLATION = 1; para->FIND_ORF = 0; para->ORF_FRAME = 0; para->OUTPUT = 1; break; case 'D': break; case 'P': flag_protein_output = 1; break; case '?': break; } } if(flag_protein_output){ para->OUTPUT = 0; } if(argc-optind == 0 ){ wrong_input(); error("conf-directory and infile needed !"); } else if(argc-optind > 3){ wrong_input(); error("too many arguments -> conf-directory, infile, [outfile] !"); } else{ struct stat attribut_dir; if(only_config_dir){ if(stat(argv[optind],&attribut_dir)==-1){ wrong_input(); error("conf-directory doesn't exist"); } else { if(attribut_dir.st_mode & S_IFDIR){ para->conf_dir = argv[optind++]; } else { wrong_input(); error("conf-directory is no directory"); } } } else{ struct stat attribut_file; if(stat(argv[optind],&attribut_dir)==-1){ wrong_input(); error("conf-directory doesn't exist"); } else{ if(attribut_dir.st_mode & S_IFDIR){ para->conf_dir = argv[optind++]; if(stat(argv[optind],&attribut_file)==-1){ wrong_input(); error("infile doesn't exist"); } else{ if(attribut_file.st_mode & S_IFREG){ para->in_file = argv[optind++]; } else{ wrong_input(); error("infile isn't a regular file!"); } } } else{ wrong_input(); error("conf-directory is no directory"); } } if(argv-optind >0) para->out_file = argv[optind]; } } return; } void wrong_input() { printf("Usage: dialign-t [OPTIONS] []\n"); printf("\n -d\tDebug-Mode [DEFAULT 0]\n"); printf(" \t\t 0 no debug statements\n"); printf(" \t\t 1 debugs the current phase of the processing\n"); printf(" \t\t 2 very loquacious debugging\n"); printf(" \t\t 5 hardcore debugging\n"); printf(" -s\tmaximum amount of input sequences [DEFAULT 5000]\n"); printf(" -a\tmaximum number of characters per line in a FASTA file [DEFAULT 100]\n"); printf(" -c\tmaximum amount of characters per line when printing a sequence\n \t[DEFAULT 80]\n"); printf(" -l\tsensitivity mode, the higher the level the less likely\n"); printf(" \tspurious random fragments are aligned in local alignments \n \t[DEFAULT 0]\n"); printf(" \t\t 0 switched off \n"); printf(" \t\t 1 level-1, reduced sensitivity\n"); printf(" \t\t 2 level-2, strongly reduced sensitivity\n"); printf(" -m\tscore matrix file name (in the configuration directory)\n \t\t[DEFAULT PROTEIN: BLOSUM.scr]\n \t\t[DEFAULT DNA: dna_matrix.scr]\n"); printf(" -w\tdefines the minimum weight when the weight formula is changed\n \tto 1-pow(1-prob, factor) [DEFAULT 0.000000065]\n"); printf(" -p\tprobability distribution file name (in the configuration\n \tdirectory) \n \t\t[DEFAULT PROTEIN: BLOSUM.diag_prob_t10]\n\t\t[DEFAULT DNA: dna_diag_prob_100_exp_550000]\n"); printf(" -v\tadd to each score (to prevent negative values) [DEFAULT 0]\n"); printf(" -t\t\"even\" threshold for low score for sequences alignment \n \t\t[DEFAULT PROTEIN: 4]\n\t\t[DEFAULT DNA: 0]\n"); printf(" -n\tmaximum number of consecutive positions for window containing\n \tlow scoring positions \n \t\t[DEFAULT PROTEIN: 4]\n\t\t[DEFAULT DNA: 4]\n"); printf(" -g\tglobal minimum fragment length for stop criterion \n \t\t[DEFAULT PROTEIN: 40] \n\t\t[DEFAULT DNA: 40]\n"); printf(" -m\tminimal allowed average score in frag window containing low \n \tscoring positions \n \t\t[DEFAULT PROTEIN: 4.0]\n\t\t[DEFAULT DNA: 0.25]\n"); printf(" -o\twhether overlap weights are calculated or not [DEFAULT 0]\n"); printf(" -f\tminimum fragment length [DEFAULT 1]\n"); printf(" -r\tthreshold weight to consider the fragment at all [DEFAULT 0.0]\n"); printf(" -u\t[DEFAULT 0]\n"); printf(" \t\t1: only use a sqrt(amount_of_seqs) stripe of neighbour\n \t\t sequences to calculate pairwise alignments (increase performance)\n"); printf(" \t\t0: all pairwise alignments will be calculated\n"); printf(" -A\toptional anchor file [DEFAULT none]\n"); printf(" -D\tinput is DNA-sequence\n"); printf(" -T\ttranslate DNA into aminoacids from begin to end (length will be cut to mod 3 = 0)\n\tWARNING: Do not use -D with this option \n\t(Default values for PROTEIN input will be loaded)\n"); printf(" -L\tcompare only longest Open Reading Frame\n\tWARNING: Do not use -D with this option \n\t(Default values for PROTEIN input will be loaded)\n"); printf(" -O\ttranslate DNA to aminoacids, reading frame for each sequence calculated due to its longest ORF\n\tWARNING: Do not use -D with this option \n\t(Default values for PROTEIN input will be loaded)\n"); printf(" -P\toutput in aminoacids, no retranslation of DNA sequences\n\t[DEFAULT: input = output]\n"); printf(" -F\tfast mode (implies -l0, since it already significantly reduces sensitivity)\n"); printf(" -C\tgenerate probability table saved in /prob_table and exit\n"); printf(" -H -h\tprint this message\n\n"); exit(1); } void parameters(int argc, char** argv) { init_parameters(); int opt_flag = 0; int opt; opterr = 0; while((opt = getopt(argc, argv, "D") )!=-1){ switch(opt){ case 'D': opt_flag = 1; break; case '?': break; } } if(opt_flag) set_parameters_dna(); check_input(argc, argv); } abyss-2.2.4/dialign/parameters.h000066400000000000000000000114151361462241400165700ustar00rootroot00000000000000/** * * parameters.h: * * 2004-08-13 Dorothea Emig Volker Menrad * */ /************************************************/ /* */ /* structs */ /* */ /************************************************/ struct parameters { char *VERSION; // 0 no debug statements // 1 debugs the current phase of the processing // 2 very loquacious debugging // 5 hardcore debugging int DEBUG; // = 0; // maximum amount of input sequences int MAX_SEQ_AMOUNT; // = 5000; // maximum number of characters per line in a FASTA file int MAX_FASTA_LINE_LENGTH; // = 100; // maximum amount of characters per line when printing a sequence int PRINT_SEQ_LINE_LENGTH; // = 80; /******************************* * * PROTEIN SCORING/WEIGHTING SECTION * *****************************/ // score matrix (e.g. BLOSUM) file name (in the configuration directory) //#define SCR_MATRIX_FILE_NAME "BLOSUM75.scr" char *SCR_MATRIX_FILE_NAME; // = "BLOSUM.scr"; //#define SCR_MATRIX_FILE_NAME "BLOSUM90.scr" // defines the minimum weight when the weight is changed to // 1-pow(1-prob, factor) double DIAG_CALC_WEIGHT_THRESHOLD; // = 0.000000065; //#define DIAG_CALC_WEIGHT_THRESHOLD 0.0000002 // diag prob. distribution file name (in the configuration directory) char *DIAG_PROB_FILE_NAME; // = "BLOSUM.diag_prob_t10"; //#define DIAG_PROB_FILE_NAME "BLOSUM.diag_prob_t7" // current //#define DIAG_PROB_FILE_NAME "BLOSUM75.diag_prob_t2" // //#define DIAG_PROB_FILE_NAME "BLOSUM75.diag_prob_t1" //#define DIAG_PROB_FILE_NAME "BLOSUM90.diag_prob" //#define DIAG_PROB_FILE_NAME "BLOSUM75.diag_prob" //#define DIAG_PROB_FILE_NAME "tp400_prot" // add to each score (to prevent negative values) int SCR_MATRIX_ADD; // = 0; // BLOSUM(62) //#define SCR_MATRIX_ADD 5 // BLOSUM75 //#define SCR_MATRIX_ADD 6 // BLOSUM90 /******************************* * * PROTEIN QUALITY SECTION * *****************************/ // "even" sim score threshold for protein sequences alignment //#define PROT_SIM_SCORE_THRESHOLD 6 //BLOSUM90 //#define PROT_SIM_SCORE_THRESHOLD 5 //BLOSUM75 double PROT_SIM_SCORE_THRESHOLD; // = 4; // BLOSUM62 // maximum number of consecutive positions for frag-window int PROT_DIAG_MAX_UNDER_THRESHOLD_POS; // = 4; // old was 4 // minimum diagonal length for breaking double PROT_DIAG_MIN_LENGTH_THRESHOLD; // = 40.0; // old was 40 // minimal allowed average csore in frag window double PROT_DIAG_AVG_SCORE_THRESHOLD; // = 4.0; // BLOSUM62 //#define PROT_DIAG_AVG_SCORE_THRESHOLD 5.0 // BLOSUM75 /******************************* * * GLOBAL QUALITY/SPEED SECTION * *****************************/ // whether overlap weights are calculated or not int DO_OVERLAP; // = 0; // minimum diag length int DIAG_MIN_LENGTH;// = 1; // diag threshold weight double DIAG_THRESHOLD_WEIGHT;// = -log(0.5); // if there are anchors char DO_ANCHOR; // = 0; // name of optional anchor file char *ANCHOR_FILE_NAME; // = NULL; // sensitivity mode, does not set // DIAG_THRESHOLD_WEIGHT to 0 four rounds >1 char SENS_MODE;// = 0; // fast mode - behaves like dialign t 0.2.2 char FAST_MODE;// = 0; // 1: only use a sqrt(amount_of_seqs) stripe of neighbour sequences to // calculate pairwise alignments // 0: all pairwise alignments will be calculated int FAST_PAIRWISE_ALIGNMENT;// = 0; char *conf_dir ; char *in_file ; char *out_file ; char COMPUTE_PROB; int DNA_PARAMETERS; // default Einstellungen für DNA holen int DNA_TRANSLATION; // Vergleich auf Proteinebene, input DNA int FIND_ORF; // Vergleich auf Proteinebene, input DNA, mit ORF Finder int ORF_FRAME; // Vergleich auf Proteinebene, input DNA, nur longest ORF wird aligned int OUTPUT; // für DNA = 1, für Aminosäuren = 0 int STATE_ORPHANE; int STATE_INHERITED; }; /************************************************/ /* */ /* global variable */ /* */ /************************************************/ extern struct parameters* para; /*********************************************/ /* */ /* functions from parameters.c */ /* */ /*********************************************/ //struct parameters* //initialises the parameters with default values void init_parameters(); // check, whether there are enough arguments and if options are used void check_input(int length, char** arguments); //error message void wrong_input(); void parameters(int argc, char** argv); void set_parameters_dna(); abyss-2.2.4/dialign/prob.c000066400000000000000000000165421361462241400153700ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "struct.h" #include "parameters.h" extern void error(char *message); extern void merror(char *msg1, char *msg2); // io.c# extern void print_diag(struct diag* aDiag); // diag.c //extern struct seq_part* create_seq_part(int num, struct seq* aSeq, // long startpos); extern struct diag* create_diag(struct seq_part* part1, struct seq_part* part2, int dlength); /** * * prob.c: Probability measurement (Creation of random sequences, diags,...) * * 2003-10-14 A.R.Subramanian * (Initial) */ /** * auxiliary method that fills random data into the sequence (see next func.) */ void fill_random_seq(struct seq* sq, struct scr_matrix *smatrix) { long length = sq->length; char *data = sq->data; int *n2c = smatrix->num2char; float slen = (float)smatrix->length; int pos, rnd; for(pos=0; pos'Z')); } } /** * create random squence of the given length using the characters * of the given score matrix * * The pointer returned (and the ones included in the struct) * has to be deallocted explicitely from memory. */ struct seq* create_random_seq(struct scr_matrix *smatrix, int length) { struct seq* sq = calloc(1, sizeof(struct seq)); sq->length=length; sq->data = calloc(length, sizeof(char)); sq->name = calloc(strlen("random")+1, sizeof(char)); strcpy(sq->name, "random"); fill_random_seq(sq, smatrix); return sq; } /** * calculates the score distribution up to the given maximum diaglen * * The pointer returned and the included dist pointer has to be deallocted * explicitely from memory. */ struct prob_dist* calc_score_dist(struct scr_matrix *smatrix, int mxdlen) { long sm_max_scr = smatrix->max_score; long maxdlen = mxdlen; struct prob_dist *sdist = calloc(1, sizeof(struct prob_dist)); long **edist = (calloc(maxdlen+1, sizeof(long *))); long **tdist = (calloc(maxdlen+1, sizeof(long *))); long double **dist = (sdist->data=calloc(maxdlen+1, sizeof(long double *))); if(sdist==NULL || dist==NULL || edist==NULL|| tdist==NULL) error("calc_score_dist(): Out of memory !"); sdist->max_dlen = maxdlen; int *sdata = smatrix->data; int *smdist = smatrix->dist; sdist->smatrix = smatrix; sdist->max_dlen = maxdlen; int reduce = 3; // special characters '?', '#', '%', we don't account for if(smatrix->char2num['X']>0) reduce++; // don't account for 'X' long double square = (smatrix->length-reduce) * (smatrix->length-reduce); long scr; unsigned long i,j, scr2, mxscr, omxscr; for(i=1;i<=maxdlen;i++) { mxscr = i*sm_max_scr; dist[i] = calloc(mxscr+1, sizeof(long double )); edist[i] = calloc(mxscr+1, sizeof(long )); tdist[i] = calloc(mxscr+1, sizeof(long )); if(dist[i]==NULL) error("calc_score_dist(): Out of memory at iteration" ); if(i==1) { for(j=0;j<=mxscr;j++) { dist[i][j] = smdist[j]; //static, wie oft kommt ein score j in der scr-Matrix vor, nur für Fragmentlänge 1, ansonsten initialisiere mit Null edist[i][j]=0; tdist[i][j]=0; } } else { for(scr=0;scr<=mxscr;scr++) { dist[i][scr]=0.0; edist[i][scr]=0; tdist[i][scr]=0; omxscr = (i-1)*sm_max_scr; for(j=0;j<=sm_max_scr;j++) { if((scr-j)<=omxscr) dist[i][scr] += dist[1][j]*dist[i-1][scr-j]; // statisch wenn größer eins } } } } struct seq *sq1, *sq2; long max_experiment=550000, ex, found; struct diag dg; char *data1; char *data2; int *c2n = smatrix->char2num; int a1, a2,pos,dpos1,dpos2; long double experiment,oldprob,opf,opf2; int dlen = 100; // int maxdlen=100; long double factor = (long double)dlen*dlen; //long double expect; for(i=1;i<=maxdlen;i++) { // printf(" Diag of length %i\n", i); mxscr = i*sm_max_scr; //expect =0.0; dlen = i; factor = (long double)dlen*dlen; for(scr=0;scr<=mxscr;scr++) { //expect += ((long double)scr) * dist[i][scr]*pow(1.0/square,i);; //printf(" max %i\n", mxscr); for(scr2=scr+1;scr2<=mxscr;scr2++) { dist[i][scr] += dist[i][scr2]; } dist[i][scr] = dist[i][scr]*pow(1.0/square,i); } } // EXPERIMENTS: srandom((int)time(NULL)); sq1 = create_random_seq(smatrix, 2*maxdlen); sq2 = create_random_seq(smatrix, 2*maxdlen); dg.seq_p1.sq = sq1; dg.seq_p2.sq = sq2; dg.length =2*maxdlen; //printf(" pre random\n"); // for(ex=0;(exdata; data2 = sq2->data; for(dpos1=0;dpos1<=maxdlen;dpos1++) { for(dpos2=0;dpos2<=maxdlen;dpos2++) { dg.seq_p1.startpos = dpos1;//(int)( (100*random())/(RAND_MAX+1.0)); dg.seq_p2.startpos = dpos2; //(int)( (100*random())/(RAND_MAX+1.0)); dg.score = 0; for(pos=0;poslength*a1+a2]; if(dpos1<=pos+1 && dpos2<=pos+1) // t6 tdist[pos+1][dg.score]=1; // kann mehrmals dasselbe sein?? kann immer wieder überschrieben werden, warum? } } } for(i=1;i<=maxdlen;i++) { //printf(" Diag of length %i\n", i); mxscr = i*sm_max_scr; seenmax =0; for(scr=mxscr;scr>=0;scr--) { if(!seenmax) { if(tdist[i][scr]==1) { edist[i][scr]=edist[i][scr]+1; //für jedes Exp. maximalen score der jeweiligen Fragmentlänge hochzählen seenmax = 1; } } tdist[i][scr]=0; // alles wieder auf Null setzen ! } } } free(sq1); free(sq2); for(i=1;i<=maxdlen;i++) { // printf(" Diag of length %i\n", i); mxscr = i*sm_max_scr; //expect =0.0; dlen = i; factor = (long double)(dlen+1)*(dlen+1); // t6 //factor = (long double)10201.0; for(scr=0;scr<=mxscr;scr++) { for(scr2=scr+1;scr2<=mxscr;scr2++) { edist[i][scr] += edist[i][scr2]; // da in scr2 ja auch schon der scr1 beinhaltet ist; durch aufsummieren bekommen wir die Anzahl, wie viele Fragmente der Länge i min. den score scr haben (oder mehr) } found = edist[i][scr]; // random exp. oldprob = dist[i][scr]; // statisch opf2 = (long double)oldprob*factor; opf = (long double)1.0-pow(1.0-oldprob,factor); experiment =((long double)found)/ ( ((long double)(max_experiment))); //if(switcher==0 && oldprob<0.000001) { // old 0.00001 t3 //if(found==0) //printf ("%Le %Le %Le %Le %Le %Le %i\n",experiment,opf,opf2,oldprob,factor,square,found); if(scr>0 && (found==0 || (experiment>opf || experiment>opf2 || experiment<10.0/max_experiment))) { if( (opf<=dist[i][scr-1]) && ( (opf > opf2) || (opf2 > dist[i][scr-1]))) { experiment = opf; } if( ( (opf2 <= dist[i][scr-1]))) { experiment = opf2; } } if(experiment == 0.0) { experiment = dist[i][scr-1]; } dist[i][scr] = experiment; //if(isnan(dist[i][scr]) || isinf(dist[i][scr])) dist[i][scr]=1.0; if(para->DEBUG>1)printf("%li %li %Le\n", i, scr,dist[i][scr] ); } // printf("%i %Le\n", i, expect); } return sdist; } abyss-2.2.4/dialign/struct.h000066400000000000000000000153571361462241400157620ustar00rootroot00000000000000/** * * struct.h: Basic data structures * * Author: A.R.Subramanian */ /** * score matrix (e.g. BLOSUM62) */ struct scr_matrix { int length; // number of amino acids int max_score; // maximum among all entries in the data array int *char2num; // resolves the character of an amino acid to its number int *num2char; // resolves the number of an amino acid to its character int *data; // contains the matrix indexed by the number of the particular amino acid int *dist; // number of pairs of amino acids (i,j) having score at equal to // the value of the index long double **raw_dist; double avg_sim_score; }; /** * raw sequence */ struct seq { char *data; // sequence data char *name; // name/description of the sequence int num; // number of the sequence int length; // length of sequence int max_seen; char *dna_num; // Numbers fo retranslation from Protein to DNA int orf_frame; // reading frame of the longest orf char crick_strand; // orf translation or sequence translation on crickstrand }; /** * sequence collection */ struct seq_col { struct seq *seqs; // array of the sequences int avg_length; // average length of sequences int length; // number of sequences }; /** * probability distribution of scores in diagonals */ struct prob_dist { struct scr_matrix *smatrix; // pointer to the associated score matrix long double **data; // distribution of scores dist[i][j] contains the // probability of a diags of length i having score >=j double **log_data; // distribution of scores dist[i][j] contains the // -log(probability of a diags of length i having score >=j) // long double *expect; // score expectancy for each diaglen unsigned int max_dlen; // maximum diaglength in dist }; /** * part of a sequence (auxiliary data structure) */ struct seq_part { int num; // a number that indicates a position in an array struct seq* sq; // the pointer to the sequence int startpos; // startpos in the sequence //int leftmargin; //int rightmargin; }; /** * diagonal in the dotmatrix */ struct diag { struct seq_part seq_p1; // first sequence part struct seq_part seq_p2; // seconde sequence part unsigned int length; // length of the diag long score; // score of the diag long orig_score; // orig score of the diag struct diag *pred_diag; // predecessor diag for dynamic programming struct diag *col_pred_diag; // col predecessor diag for dynamic programming int pool_pos; // position in diag pool char meetsThreshold; // whether diag meets threshold // for vertex cover int degree; int max_degree; struct diag **neighbours; char anchor; // if this is an anchor diag char marked; // marking flag for arbitrary use char multi_dg; // is >0 if this is a multi dg struct diag **multi_cont; // the contained dgs of this is a multi dg int multi_length; // size of multi_cont // char onlyOverThres; double weight; // weight of the diag = -log(prob) double weight_sum; // weight sum for dialign double weight_fac; // weight factor double ov_weight; // overlap weight double total_weight; // total_weight = weight+o_weight }; /** * collection of diag */ struct simple_diag_col { unsigned int length; // number of diags double total_weight; // total weight double weight_fac; // weight factor struct diag** data; // the array of diags }; /** * guide tree node */ struct gt_node { char isLeaf; // whether it is leaf int *seq_num; // the sequence numbers int seq_num_length; // length of sequence numbers array struct gt_node *succ1; // successor nodes struct gt_node *succ2; }; /** * vertex cover node struct vc_node { double weight; struct diag *dg; int degree; struct vc_node *adjacents; } */ /** * collection of all diagonals sorted by the sequences */ struct diag_col { int seq_amount; // number of sequences involved struct simple_diag_col** diag_matrix; // diag_matrix[i +seq_amount *j] contains // all diags found involving the sequences i and j double total_weight; // total weight double average_weight; // average_weight struct diag** diags; // all diags unordered unsigned int diag_amount; // number of diags found struct gt_node *gt_root; }; /** * diag container */ struct diag_cont { struct diag* dg; struct diag_cont *next; }; /** * alignment position */ struct algn_pos { // int seq_num; // sequence number // unsigned long pos_in_seq; // position in the sequence char state; // orphane: not aligned to any pos, struct diag_cont *dg_cont; // diags that are aligned with that position int row; int col; // unsigned int succFPos; // if orphane, the position holding the succF // unsigned int predFPos; // analogous to succFPos // char* isAli; // if alignemnt at the positions exist int* predF; // predecessor frontier, only filled if non-orphane int* succF; // successor frontier, only filled if non-orphane char *proceed; // for output //char isInherited; // whether the pointers are inherited int predFPos; // in case of orphane, where to find the predF or succF int succFPos; int *eqcAlgnPos; // equivalence class minimum alignment position (for output) struct algn_pos *eqcParent; // equivalence class parent int eqcRank; // equivalence class rank (>= maximum number of children) // unsigned int *maxpos; // needed for output of the alignment }; /** * alignment */ struct alignment { //int seq_amount; // number of sequences involved //char *redo_seqs; // which pairs of sequences are to be aligned again char *seq_is_orphane; // boolean array indicating for each sequence // whether it is orphane or not int max_pos; // the greatest position in the alignment (including all -'s) // if <0: the alignment has not yet been prepared struct seq_col *scol; // all the sequences involved struct algn_pos **algn; // the alignment double total_weight; // the total weight of the alignment struct alignment *next; // pointer to next alignment in the sorted linked list //struct alignment *prev; // pointer to previous alignment in the sorted linked list //unsigned long pos; // position in the sorted linked list //struct diag** aligned_diags; // all aligned diags //int aligned_diags_amount; //int max_aligned_diags_amount; //int orig_max_aligned_diags_amount; //struct diag_cont* backlog_diags; // all backlog diags }; abyss-2.2.4/dialign/translate.c000066400000000000000000000431541361462241400164220ustar00rootroot00000000000000/** * * translate.c: * * 2004-08-30 Dorothea Emig Volker Menrad * */ #include #include #include #include "struct.h" #include "translate.h" #include "parameters.h" #include "orf.h" #include "io.h" void translate_sequence_collection_orf_frame(struct seq_col *in_seq_col) { int i; struct seq_col* tmp; tmp = set_longest_orf(in_seq_col); /************** reading frames : 0: 123 123 123 123 123 ... 1: X 123 123 123 123 123 ... 2: XX 123 123 123 123 123 ... 3: ... 321 321 321 321 321 XX 4: ... 321 321 321 321 321 X 5: ... 321 321 321 321 321 **************/ for(i=0; i!= in_seq_col->length; ++i){ in_seq_col->seqs[i].orf_frame = tmp->seqs[i].orf_frame; translate_sequence( &(in_seq_col->seqs[i]) ); free(tmp->seqs[i].data); free(tmp->seqs[i].dna_num); } free(tmp); } void translate_sequence_collection_default(struct seq_col *in_seq_col) { int i; for(i=0; i!= in_seq_col->length; ++i) translate_sequence( &(in_seq_col->seqs[i]) ); } void translate_sequence(struct seq *in_seq) { int i, rest; // printf("%d\t%s\n%s\n%d\n\n\n",in_seq->num, in_seq->name, in_seq->data, in_seq->orf_frame ); switch(in_seq->orf_frame) { case 0: break; case 1: --in_seq->length; in_seq->data=&(in_seq->data[1]); break; case 2: in_seq->length= in_seq->length-2; in_seq->data=&(in_seq->data[2]); break; case 3: in_seq->crick_strand=1; in_seq->length= in_seq->length-2; in_seq->data[in_seq->length]='\0'; break; case 4: in_seq->crick_strand=1; --in_seq->length; in_seq->data[in_seq->length]='\0'; break; case 5: in_seq->crick_strand=1; break; } struct seq* new; if(NULL == ( new = (calloc(1,sizeof(struct seq))))) { error("translate_sequence: Out of memory! "); } if(NULL == (new->data = (calloc(in_seq->length/3+1, sizeof(char))))) { error("translate_sequence: Out of memory! "); } if(NULL == (new->dna_num = (calloc(in_seq->length/3+1, sizeof(char))))) { error("translate_sequence: Out of memory! "); } rest = in_seq->length%3; for(i=0; i < (in_seq->length) - rest ; ++i) { int help = in_seq->length-1; if(in_seq->crick_strand==0) { new->data[new->length] = translate(in_seq->data[i], in_seq->data[i+1], in_seq->data[i+2], &(new->dna_num[new->length]) ); ++new->length; } else { new->data[new->length] = translate(inverse(in_seq->data[help - i]), inverse(in_seq->data[help - (i+1)]), inverse(in_seq->data[help - (i+2)]), &(new->dna_num[new->length]) ); ++new->length; } i=i+2; } switch(in_seq->orf_frame) { case 1: --in_seq->data; free(in_seq->data); break; case 2: in_seq->data = in_seq->data-2; free(in_seq->data); break; default: free(in_seq->data); } in_seq->data = &(new->data[0]); in_seq->length = new->length; in_seq->dna_num = new->dna_num; } char translate(char first_base, char second_base, char third_base, char *dna_number) { switch(first_base) { case 'A': switch(second_base) { case 'A': switch(third_base) { case 'A': *dna_number = 0; // AAA return('K'); // Lysin = K case 'T': *dna_number = 1; // AAT return('N'); // Asparagin = N case 'U': *dna_number = 2; // AAU return('N'); // Asparagin = N case 'G': *dna_number = 3; // AAG return('K'); //Lysin = K case 'C': *dna_number = 4; // AAC return('N'); //Asparagin = N default: error("No regular aminoacid !"); } case 'T': switch(third_base) { case 'A': *dna_number = 5; // ATA return('I'); // Isoleucin = I case 'T': *dna_number = 6; // ATT return('I'); // Isoleucin = I case 'G': *dna_number = 7; // ATG return('M'); // Methionin = M case 'C': *dna_number = 8; // ATC return('I'); // Isoleucin = I default: error("No regular aminoacid !"); } case 'U': switch(third_base) { case 'A': *dna_number = 9; // AUA return('I'); // Isoleucin = I case 'U': *dna_number = 10; // AUU return('I'); // Isoleucin = I case 'G': *dna_number = 11; // AUG return('M'); // Methionin= M case 'C': *dna_number = 12; // AUC return('I'); // Isoleucin = I default: error("No regular aminoacid !"); } case 'G': switch(third_base) { case 'A': *dna_number = 13; // AGA return('R'); // Arginin = R case 'T': *dna_number = 14; // AGT return('S'); // Serin = S case 'U': *dna_number = 15; // AGU return('S'); // Serin = S case 'G': *dna_number = 16; // AGG return('R'); // Arginin = R case 'C': *dna_number = 17; // AGC return('S'); // Serin = S default: error("No regular aminoacid !"); } case 'C': switch(third_base) { case 'A': *dna_number = 18; // ACA return('T'); // Threonin = T case 'T': *dna_number = 19; // ACT return('T'); // Threonin = T case 'U': *dna_number = 20; // ACU return('T'); // Threonin = T case 'G': *dna_number = 21; // ACG return('T'); // Threonin = T case 'C': *dna_number = 22; // ACC return('T'); // Threonin = T default: error("No regular aminoacid !"); } default: error("No regular aminoacid !"); } case 'T': switch(second_base) { case 'A': switch(third_base) { case 'A': *dna_number = 23; // TAA return('X'); // Stop case 'T': *dna_number = 24; // TAT return('Y'); // Tyrosin case 'G': *dna_number = 25; // TAG return('X'); // Stop case 'C': *dna_number = 26; // TAC return('Y'); // Tyrosin default: error("No regular aminoacid !"); } case 'T': switch(third_base) { case 'A': *dna_number = 27; // TTA return('L'); // Leucin case 'T': *dna_number = 28; // TTT return('F'); // Phenylalanin case 'G': *dna_number = 29; // TTG return('L'); // Leucin case 'C': *dna_number = 30; // TTC return('F'); // Phenylalanin default: error("No regular aminoacid !"); } case 'G': switch(third_base) { case 'A': *dna_number = 31; // TGA return('X'); // Stop case 'T': *dna_number = 32; // TGT return('C'); // Cystein case 'G': *dna_number = 33; // TGG return('W'); // Tryptophan case 'C': *dna_number = 34; // TGC return('C'); // Cystein default: error("No regular aminoacid !"); } case 'C': switch(third_base) { case 'A': *dna_number = 35; // TCA return('S'); // Serin case 'T': *dna_number = 36; // TCT return('S'); // Serin case 'G': *dna_number = 37; // TCG return('S'); // Serin case 'C': *dna_number = 38; // TCC return('S'); // Serin default: error("No regular aminoacid !"); } default: error("no regular Aminoacid !"); } case 'U': switch(second_base) { case 'A': switch(third_base) { case 'A': *dna_number = 39; // UAA return('X'); // Stop case 'U': *dna_number = 40; // UAU return('Y'); // Tyrosin case 'G': *dna_number = 41; // UAG return('X'); // Stop case 'C': *dna_number = 42; // UAC return('Y'); // Tyrosin default: error("No regular aminoacid !"); } case 'U': switch(third_base) { case 'A': *dna_number = 43; // UUA return('L'); // Leucin case 'U': *dna_number = 44; // UUU return('F'); // Phenylalanin case 'G': *dna_number = 45; // UUG return('L'); // Leucin case 'C': *dna_number = 46; // UUC return('F'); // Phenylalanin default: error("No regular aminoacid !"); } case 'G': switch(third_base) { case 'A': *dna_number = 47; // UGA return('X'); // Stop case 'U': *dna_number = 48; // UGU return('C'); // Cystein case 'G': *dna_number = 49; // UGG return('W'); // Tryptophan case 'C': *dna_number = 50; // UGC return('C'); // Cystein default: error("No regular aminoacid !"); } case 'C': switch(third_base) { case 'A': *dna_number = 51; // UCA return('S'); // Serin case 'U': *dna_number = 52; // UCU return('S'); // Serin case 'G': *dna_number = 53; // UCG return('S'); // Serin case 'C': *dna_number = 54; // UCC return('S'); // Serin default: error("No regular aminoacid !"); } default: error("no regular Aminoacid !"); } case 'G': switch(second_base) { case 'A': switch(third_base) { case 'A': *dna_number = 55; // GAA return('E'); // Glutaminsaeure case 'T': *dna_number = 56; // GAT return('D'); // Asparaginsaeure case 'U': *dna_number = 57; // GAU return('D'); // Asparaginsaeure case 'G': *dna_number = 58; // GAG return('E'); // Glutaminsaeure case 'C': *dna_number = 59; // GAC return('D'); // Asparaginsaeure default: error("No regular aminoacid !"); } case 'T': switch(third_base) { case 'A': *dna_number = 60; // GTA return('V'); // Valin case 'T': *dna_number = 61; // GTT return('V'); // Valin case 'G': *dna_number = 62; // GTG return('V'); // Valin case 'C': *dna_number = 63; // GTC return('V'); // Valin default: error("No regular aminoacid !"); } case 'U': switch(third_base) { case 'A': *dna_number = 64; // GUA return('V'); // Valin case 'U': *dna_number = 65; // GUU return('V'); // Valin case 'G': *dna_number = 66; // GUG return('V'); // Valin case 'C': *dna_number = 67; // GUC return('V'); // Valin default: error("No regular aminoacid !"); } case 'G': switch(third_base) { case 'A': *dna_number = 68; // GGA return('G'); // Glycin case 'T': *dna_number = 69; // GGT return('G'); // Glycin case 'U': *dna_number = 70; // GGU return('G'); // Glycin case 'G': *dna_number = 71; // GGG return('G'); // Glycin case 'C': *dna_number = 72; // GGC return('G'); // Glycin default: error("No regular aminoacid !"); } case 'C': switch(third_base) { case 'A': *dna_number = 73; // GCA return('A'); // Alanin case 'T': *dna_number = 74; // GCT return('A'); // Alanin case 'U': *dna_number = 75; // GCU return('A'); // Alanin case 'G': *dna_number = 76; // GCG return('A'); // Alanin case 'C': *dna_number = 77; // GCC return('A'); // Alanin default: error("No regular aminoacid !"); } default: error("No regular aminoacid !"); } case 'C': switch(second_base) { case 'A': switch(third_base) { case 'A': *dna_number = 78; // CAA return('Q'); // Glutamin case 'T': *dna_number = 79; // CAT return('H'); // Histidin case 'U': *dna_number = 80; // CAU return('H'); // Histidin case 'G': *dna_number = 81; // CAG return('Q'); // Glutamin case 'C': *dna_number = 82; // CAC return('H'); // Histidin default: error("No regular aminoacid !"); } case 'T': switch(third_base) { case 'A': *dna_number = 83; // CTA return('L'); // Leucin case 'T': *dna_number = 84; // CTT return('L'); // Leucin case 'G': *dna_number = 85; // CTG return('L'); // Leucin case 'C': *dna_number = 86; // CTC return('L'); // Leucin default: error("No regular aminoacid !"); } case 'U': switch(third_base) { case 'A': *dna_number = 87; // CUA return('L'); // Leucin case 'U': *dna_number = 88; // CUU return('L'); // Leucin case 'G': *dna_number = 89; // CUG return('L'); // Leucin case 'C': *dna_number = 90; // CUC return('L'); // Leucin default: error("No regular aminoacid !"); } case 'G': switch(third_base) { case 'A': *dna_number = 91; // CGA return('R'); // Arginin case 'T': *dna_number = 92; // CGT return('R'); // Arginin case 'U': *dna_number = 93; // CGU return('R'); // Arginin case 'G': *dna_number = 94; // CGG return('R'); // Arginin case 'C': *dna_number = 95; // CGC return('R'); // Arginin default: error("No regular aminoacid !"); } case 'C': switch(third_base) { case 'A': *dna_number = 96; // CCA return('P'); // Prolin case 'T': *dna_number = 97; // CCT return('P'); // Prolin case 'U': *dna_number = 98; // CCU return('P'); // Prolin case 'G': *dna_number = 99; // CCG return('P'); // Prolin case 'C': *dna_number = 100; // CCC return('P'); // Prolin default: error("No regular aminoacid !"); } default: error("No regular aminoacid !"); } default: error("No regular aminoacid !"); } abort(); } char inverse(char base) { switch(base) { case 'A': return('T'); case 'T': return('A'); case 'U': return('A'); case 'C': return('G'); case 'G': return('C'); } abort(); } void retranslate_sequence(struct seq *in_seq) { char *tmp_char= "000"; int i; struct seq* tmp; if(NULL == ( tmp =(calloc(1,sizeof(struct seq))))) { error("retranslate_sequence(): Out of memory !"); } if(NULL == ( tmp->data =(calloc((in_seq->length)*3+1,sizeof(char))))) { error("retranslate_sequence(): Out of memory !"); } for(i=0; i!=in_seq->length; ++i) { tmp_char = retranslate(in_seq->dna_num[i]); strcat(tmp->data,tmp_char); } in_seq->length = strlen(tmp->data); free(in_seq->data); free(in_seq->dna_num); in_seq->data = tmp->data; } char* retranslate(char amino) { switch(amino) { case 0: return "AAA"; case 1: return "AAT"; case 2: return "AAU"; case 3: return "AAG"; case 4: return "AAC"; case 5: return "ATA"; case 6: return "ATT"; case 7: return "ATG"; case 8: return "ATC"; case 9: return "AUA"; case 10: return "AUU"; case 11: return "AUG"; case 12: return "AUC"; case 13: return "AGA"; case 14: return "AGT"; case 15: return "AGU"; case 16: return "AGG"; case 17: return "AGC"; case 18: return "ACA"; case 19: return "ACT"; case 20: return "ACU"; case 21: return "ACG"; case 22: return "ACC"; case 23: return "TAA"; case 24: return "TAT"; case 25: return "TAG"; case 26: return "TAC"; case 27: return "TTA"; case 28: return "TTT"; case 29: return "TTG"; case 30: return "TTC"; case 31: return "TGA"; case 32: return "TGT"; case 33: return "TGG"; case 34: return "TGC"; case 35: return "TCA"; case 36: return "TCT"; case 37: return "TCG"; case 38: return "TCC"; case 39: return "UAA"; case 40: return "UAU"; case 41: return "UAG"; case 42: return "UAC"; case 43: return "UUA"; case 44: return "UUU"; case 45: return "UUG"; case 46: return "UUC"; case 47: return "UGA"; case 48: return "UGU"; case 49: return "UGG"; case 50: return "UGC"; case 51: return "UCA"; case 52: return "UCU"; case 53: return "UCG"; case 54: return "UCC"; case 55: return "GAA"; case 56: return "GAT"; case 57: return "GAU"; case 58: return "GAG"; case 59: return "GAC"; case 60: return "GTA"; case 61: return "GTT"; case 62: return "GTG"; case 63: return "GTC"; case 64: return "GUA"; case 65: return "GUU"; case 66: return "GUG"; case 67: return "GUC"; case 68: return "GGA"; case 69: return "GGT"; case 70: return "GGU"; case 71: return "GGG"; case 72: return "GGC"; case 73: return "GCA"; case 74: return "GCT"; case 75: return "GCU"; case 76: return "GCG"; case 77: return "GCC"; case 78: return "CAA"; case 79: return "CAT"; case 80: return "CAU"; case 81: return "CAG"; case 82: return "CAC"; case 83: return "CTA"; case 84: return "CTT"; case 85: return "CTG"; case 86: return "CTC"; case 87: return "CUA"; case 88: return "CUU"; case 89: return "CUG"; case 90: return "CUC"; case 91: return "CGA"; case 92: return "CGT"; case 93: return "CGU"; case 94: return "CGG"; case 95: return "CGC"; case 96: return "CCA"; case 97: return "CCT"; case 98: return "CCU"; case 99: return "CCG"; case 100: return "CCC"; default: error("Sorry something wrong while retranslation !"); } abort(); } abyss-2.2.4/dialign/translate.h000066400000000000000000000025331361462241400164230ustar00rootroot00000000000000/** * * translate.h: * * 2004-08-30 Dorothea Emig Volker Menrad * */ /************************************************/ /* */ /* structs */ /* */ /************************************************/ /************************************************/ /* */ /* global variable */ /* */ /************************************************/ /*********************************************/ /* */ /* functions from translate.c */ /* */ /*********************************************/ void translate_sequence_collection(struct seq_col *in_sequence_collection); void translate_sequence(struct seq *in_sequence); char translate(char first_base, char second_base, char third_base, char *dna_number); char inverse(char base); void retranslate_sequence(struct seq *in_sequence); char* retranslate(char amino); void translate_sequence_collection_orf_frame(struct seq_col *in_seq_col); void translate_sequence_collection_default(struct seq_col *in_seq_col); abyss-2.2.4/doc/000077500000000000000000000000001361462241400134105ustar00rootroot00000000000000abyss-2.2.4/doc/ABYSS.1000066400000000000000000000053301361462241400143540ustar00rootroot00000000000000.TH ABYSS "1" "2015-May" "ABYSS (ABySS) 2.2.4" "User Commands" .SH NAME ABYSS \- assemble short reads into contigs .SH SYNOPSIS .B ABYSS [\fIOPTION\fR]... \fIFILE\fR... .SH DESCRIPTION Assemble all input files, FILE, which may be in FASTA, FASTQ, qseq, export, SRA, SAM or BAM format and may be compressed with gz, bz2 or xz and may be tarred. Users wishing to run a full assembly with ABySS are recommended to use abyss-pe as their entry point rather than the ABYSS program. abyss-pe is a Makefile that coordinates many of the ABySS tools (including ABYSS) in order to run the full ABySS assembly pipeline. abyss-pe is capable of doing many things that ABYSS is not, such as leveraging the distance information provided by paired end reads and mate pair reads. .TP \fB--chastity\fR discard unchaste reads [default] .TP \fB--no-chastity\fR do not discard unchaste reads .TP \fB--trim-masked\fR trim masked bases from the ends of reads [default] .TP \fB--no-trim-masked\fR do not trim masked bases from the ends of reads .TP \fB-q\fR, \fB--trim-quality\fR=\fITHRESHOLD\fR trim bases from the ends of reads whose quality is less than the threshold .TP \fB-Q\fR, \fB--mask-quality\fR=\fITHRESHOLD\fR mask all bases in reads whose quality is less than the threshold .TP \fB--standard-quality\fR zero quality is `!' (33) .br default for FASTQ and SAM files .TP \fB--illumina-quality\fR zero quality is `@' (64) .br default for qseq and export files .TP \fB\-o\fR, \fB\-\-out\fR=\fIFILE\fR write the contigs to FILE .TP \fB\-k\fR, \fB\-\-kmer\fR=\fIKMER_SIZE\fR k\-mer size .TP \fB\-t\fR, \fB\-\-trim\-length\fR=\fITRIM_LENGTH\fR maximum length of dangling edges to trim .TP \fB\-c\fR, \fB\-\-coverage\fR=\fICOVERAGE\fR remove contigs with mean k-mer coverage less than this threshold .TP \fB\-b\fR, \fB\-\-bubbles\fR=\fIN\fR pop bubbles shorter than N bp (default: 3*k). .TP \fB\-b\fR0, \fB\-\-no\-bubbles\fR do not pop bubbles .TP \fB\-e\fR, \fB\-\-erode\fR=\fICOVERAGE\fR erode bases at the ends of blunt contigs with coverage less than this threshold .TP \fB\-E\fR, \fB\-\-erode-strand\fR=\fICOVERAGE\fR erode bases at the ends of blunt contigs with coverage less than this threshold on either strand .TP \fB\-\-coverage-hist\fR=\fIFILE\fR record the k-mer coverage histogram in FILE .TP \fB\-g\fR, \fB\-\-graph\fR=\fIFILE\fR generate a graph in dot format .TP \fB\-s\fR, \fB\-\-snp\fR=\fIFILE\fR record popped bubbles in FILE .TP \fB\-v\fR, \fB\-\-verbose\fR display verbose output .TP \fB\-\-help\fR display this help and exit .TP \fB\-\-version\fR output version information and exit .SH AUTHOR Written by Jared Simpson and Shaun Jackman. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright 2015 Canada's Michael Smith Genome Sciences Centre abyss-2.2.4/doc/Makefile.am000066400000000000000000000001521361462241400154420ustar00rootroot00000000000000dist_man_MANS = ABYSS.1 abyss-pe.1 abyss-tofastq.1 dist_doc_DATA = flowchart.pdf flowchart_simplified.pdf abyss-2.2.4/doc/abyss-pe.1000066400000000000000000000216701361462241400152230ustar00rootroot00000000000000.TH abyss-pe "1" "2015-May" "abyss-pe (ABySS) 2.2.4" "User Commands" .SH NAME abyss-pe - assemble reads into contigs .SH SYNOPSIS .B abyss-pe [\fIOPTION\fR]... [\fIPARAMETER\fR=\fIVALUE\fR]... [\fIMAKE_TARGET\fR]... .SH DESCRIPTION Assemble the reads of the input files into contigs. The reads may be in FASTA, FASTQ, qseq, export, SRA, SAM or BAM format and may be compressed with gz, bz2 or xz and may be tarred. abyss-pe is a Makefile script. Any options of make may also be used with abyss-pe. .SS "Parameters of abyss-pe" .TP \fBname\fR, \fBJOB_NAME\fR The name of this assembly. The resulting scaffolds will be stored in ${name}-scaffolds.fa. .TP .B in input files. Use this variable when assembling data from a single library. .TP .B lib a quoted list of whitespace-separated paired-end library names. Use this variable when assembling data from multiple paired-end libraries. For each library name in lib, the user must define a variable on the command line with the same name, which indicates the read files for that library. See \fBEXAMPLES\fR below for a concrete example of usage. .TP .B pe list of paired-end libraries that will be used only for merging unitigs into contigs and will not contribute toward the consensus sequence. .TP .B mp list of mate-pair libraries that will be used for scaffolding. Mate-pair libraries do not contribute toward the consensus sequence. .TP .B long list of long sequence libraries that will be used for rescaffolding. long sequence libraries do not contribute toward the consensus sequence. .TP .B se files containing single-end reads .TP .B a maximum number of branches of a bubble [2] .TP .B b maximum length of a bubble (bp) [""] .br abyss-pe has two bubble popping stages. The default limits are 3*k bp for ABYSS and 10000 bp for PopBubbles. .TP .B c minimum mean k-mer coverage of a unitig [sqrt(median)] .TP .B d allowable error of a distance estimate (bp) [6] .TP .B e minimum erosion k-mer coverage [round(sqrt(median))] .TP .B E minimum erosion k-mer coverage per strand [1 if sqrt(median) > 2 else 0] .TP .B j number of threads [2] .TP .B k 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) [40] .TP .B m minimum overlap of two unitigs (bp) [k-1] .TP .B n minimum number of pairs required for building contigs [10] .TP .B N minimum number of pairs required for building scaffolds [n] .TP .B p minimum sequence identity of a bubble [0.9] .TP .B q minimum base quality when trimming [3] .br Trim bases from the ends of reads whose quality is less q. .TP .B Q minimum base quality [0] .br Mask all bases of reads whose quality is less than Q as `N'. .TP .B s minimum unitig size required for building contigs (bp) [1000] .br The seed length should be at least twice the value of k. If more sequence is assembled than the expected genome size, try increasing s. .TP .B S minimum contig size required for building scaffolds (bp) [1000-10000] .TP .B SS SS=--SS to assemble in strand-specific mode .br Requires that all libraries are strand-specific RNA-Seq libraries. Assumes that the first read in a read pair is reversed WRT the transcripts sequenced. .TP .B t maximum length of blunt contigs to trim [k] .TP .B v v=-v to enable verbose logging .TP \fBnp\fR, \fBNSLOTS\fR the number of processes of an MPI assembly .TP .B mpirun the path to mpirun .TP .B aligner The program to use to align the reads to the contigs [map]. .br 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 .SS "Options of make" .TP \fB-n\fR, \fB--dry-run\fR Print the commands that would be executed, but do not execute them. .SS "Make targets for abyss-pe" .TP .B default Equivalent to `scaffolds scaffolds-dot stats'. .TP .B unitigs Assemble unitigs. .TP .B unitigs-dot Output the unitig overlap graph. .TP .B pe-sam Map paired-end reads to the unitigs and output a SAM file. SAM file will only contain reads mapping to different contigs, and the read ID, sequence and quality strings will be replaced with '*' characters. .TP .B pe-bam Map paired-end reads to the unitigs and output a BAM file. BAM file will only contain reads mapping to different contigs, and the read ID, sequence and quality strings will be replaced with '*' characters. .TP .B pe-index Generate an index of the unitigs used by abyss-map. .TP .B contigs Assemble contigs. .TP .B contigs-dot Output the contig overlap graph. .TP .B mp-sam Map mate-pair reads to the contigs and output a SAM file. SAM file will only contain reads mapping to different contigs, and the read ID, sequence and quality strings will be replaced with '*' characters. .TP .B mp-bam Map mate-pair reads to the contigs and output a BAM file. BAM file will only contain reads mapping to different contigs, and the read ID, sequence and quality strings will be replaced with '*' characters. .TP .B mp-index Generate an index of the contigs used by abyss-map. .TP .B scaffolds Assemble scaffolds. .TP .B scaffolds-dot Output the scaffold overlap graph. .TP .B scaftigs Break scaffolds and generate AGP file. .TP .B long-scaffs Rescaffold using RNA-Seq assembled contigs. .TP .B long-scaffs-dot Output the RNA scaffold overlap graph. .TP .B stats Display assembly contiguity statistics. .TP .B clean Remove intermediate files. .TP .B version Display the version of abyss-pe. .TP .B versions Display the versions of all programs used by abyss-pe. .TP .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 recommended 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. .TP .B PATH must contain the directory where the ABySS executables are installed. Use `abyss-pe versions` to check that PATH is configured correctly. .TP .B TMPDIR specifies a directory to use for temporary files .SS "Scheduler integration" ABySS integrates well with cluster job schedulers, such as: * SGE (Sun Grid Engine) * Portable Batch System (PBS) * Load Sharing Facility (LSF) * IBM LoadLeveler The SGE environment variables JOB_NAME, SGE_TASK_ID and NSLOTS may be used to specify the parameters name, k and np, respectively, and similarly for other schedulers. .SH EXAMPLES .SS "One paired-end library" abyss-pe k=64 name=ecoli in='reads1.fa reads2.fa' .SS "Multiple paired-end libraries" abyss-pe k=64 name=ecoli lib='lib1 lib2' \\ .br lib1='lib1_1.fa lib1_2.fa' lib2='lib2_1.fa lib2_2.fa' \\ .br se='se1.fa se2.fa' .SS "Paired-end and mate-pair libraries abyss-pe k=64 name=ecoli lib='pe1 pe2' mp='mp1 mp2' \\ .br pe1='pe1_1.fa pe1_2.fa' pe2='pe2_1.fa pe2_2.fa' \\ .br mp1='mp1_1.fa mp1_2.fa' mp2='mp2_1.fa mp2_2.fa' \\ .br se='se1.fa se2.fa' .SS "Including RNA-Seq assemblies abyss-pe k=64 name=ecoli lib=pe1 mp=mp1 long=long1 \\ .br pe1='pe1_1.fa pe1_2.fa' mp1='mp1_1.fa mp1_2.fa' \\ .br long1=long1.fa .SS MPI abyss-pe np=8 k=64 name=ecoli in='reads1.fa reads2.fa' .SS SGE qsub -N ecoli -t 64 -pe openmpi 8 \\ .br abyss-pe n=10 in='reads1.fa reads2.fa' .SH "SEE ALSO" make(1), ABYSS(1) .SH AUTHOR Written by Shaun Jackman. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright 2015 Canada's Michael Smith Genome Sciences Centre abyss-2.2.4/doc/abyss-tofastq.1000066400000000000000000000012241361462241400162710ustar00rootroot00000000000000.TH abyss-tofastq "1" "2015-May" "ABySS 2.2.4" "User Commands" .SH NAME abyss-tofastq \- convert various file formats to FASTQ format .br abyss-tofasta \- convert various file formats to FASTA format .SH SYNOPSIS \fBabyss-tofastq\fR [\fIFILE\fR]... .br or .br \fBabyss-tofasta\fR [\fIFILE\fR]... .SH DESCRIPTION Convert the input files to FASTA or FASTQ format. FILE may be in FASTA, FASTQ, qseq, export, SRA, SAM or BAM format and may be compressed with gz, bz2 or xz and may be tarred. .SH AUTHOR Written by Shaun Jackman. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright 2015 Canada's Michael Smith Genome Sciences Centre abyss-2.2.4/doc/flowchart.graffle000066400000000000000000005763411361462241400167510ustar00rootroot00000000000000 ActiveLayerIndex 0 ApplicationVersion com.omnigroup.OmniGraffle 139.18.0.187838 AutoAdjust BackgroundGraphic Bounds {{0, 0}, {1097.8582763671875, 3342.57470703125}} Class SolidGraphic ID 2 Style shadow Draws NO stroke Draws NO BaseZoom 0 CanvasOrigin {0, 0} ColumnAlign 1 ColumnSpacing 36 CreationDate 2010-09-03 17:10:07 +0000 Creator Rod Docking DisplayScale 1 0/72 in = 1.0000 in GraphDocumentVersion 8 GraphicsList Class LineGraphic Head ID 309 ID 312 Points {861.5, 641.5999755859375} {899, 641.5999755859375} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 310 Class LineGraphic Head ID 310 Info 4 ID 311 Points {504.6875, 623.59996871948238} {589, 638} {746, 641} {811, 641.5999755859375} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 209 Bounds {{811, 623.5999755859375}, {50.5, 36}} Class ShapedGraphic ID 310 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ln} VerticalPad 0 Bounds {{899, 632.5999755859375}, {117.75, 18}} Class ShapedGraphic ID 309 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-unitigs.fa} VerticalPad 0 Class LineGraphic Head ID 305 ID 308 Points {632.4375, 2588.650146484375} {631.9375, 2625.0004119873047} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 303 Class LineGraphic Head ID 303 ID 307 Points {631.6875, 2534.2999649047852} {632.4375, 2570.650146484375} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 285 Class LineGraphic Head ID 304 ID 306 Points {631.9375, 2661.0004119873047} {631.59375, 2697.3503723144531} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 305 Bounds {{606.6875, 2625.0004119873047}, {50.5, 36}} Class ShapedGraphic ID 305 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ln} VerticalPad 0 Bounds {{572.1875, 2697.3503723144531}, {118.8125, 18}} Class ShapedGraphic ID 304 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-scaffolds.dot} VerticalPad 0 Bounds {{587.4375, 2570.650146484375}, {90, 18}} Class ShapedGraphic ID 303 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-8.dot} VerticalPad 0 Class LineGraphic Head ID 285 ID 302 Points {631.93753814697266, 2379.4999351501465} {631.6875, 2498.2999649047852} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 289 Class LineGraphic Head ID 285 ID 301 Points {507.9375, 2379.4999675750732} {631.6875, 2498.2999649047852} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 260 Class LineGraphic Head ID 267 ID 300 Points {508.1875, 2661} {507.9375, 2697.3499603271484} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 297 Class LineGraphic Head ID 297 ID 299 Points {507.9375, 2588.6500396728516} {508.1875, 2625} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 296 Class LineGraphic Head ID 296 ID 298 Points {507.9375, 2534.3000801086428} {507.9375, 2570.6500396728516} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 263 Bounds {{482.9375, 2625}, {50.5, 36}} Class ShapedGraphic ID 297 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ln} VerticalPad 0 Bounds {{462.9375, 2570.6500396728516}, {90, 18}} Class ShapedGraphic ID 296 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-8.fa} VerticalPad 0 Class LineGraphic Head ID 263 ID 295 Points {631.93753814697266, 2379.4999351501465} {507.9375, 2498.3000801086428} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 289 Class LineGraphic Head ID 263 Info 2 ID 294 Points {389.9375, 2449.8999671936035} {507.9375, 2498.3000801086428} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 287 Info 1 Class LineGraphic Head ID 289 Info 2 ID 293 Points {507.9375, 2327.0999687194826} {631.93753814697266, 2361.4999351501465} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 257 Info 1 Class LineGraphic Head ID 288 Info 2 ID 292 Points {507.9375, 2327.0999687194826} {389.93749267578119, 2361.4999675750732} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 257 Info 1 Class LineGraphic Head ID 287 ID 291 Points {389.93749267578119, 2379.4999675750732} {389.9375, 2413.8999671936035} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 288 Class LineGraphic Head ID 287 ID 290 Points {506.9375, 1823.3999687194826} {295, 2015.4999687194825} {310, 2337} {389.9375, 2413.8999671936035} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 216 Bounds {{586.93753814697266, 2361.4999351501465}, {90, 18}} Class ShapedGraphic ID 289 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-7.adj} VerticalPad 0 Bounds {{344.93749267578119, 2361.4999675750732}, {90, 18}} Class ShapedGraphic ID 288 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-7.fa} VerticalPad 0 Bounds {{364.6875, 2413.8999671936035}, {50.5, 36}} Class ShapedGraphic ID 287 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 cat} VerticalPad 0 Bounds {{584.4375, 2498.2999649047852}, {94.5, 36}} Class ShapedGraphic ID 285 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 PathOverlap\ --overlap} VerticalPad 0 Bounds {{27.9375, 324.5999641418457}, {117, 14}} Class ShapedGraphic FitText YES Flow Resize ID 284 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Filter out shim contigs} VerticalPad 0 Wrap NO Class LineGraphic Head ID 63 ID 283 Points {505.1875, 396.59997940063477} {504.6875, 426.79996871948242} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 280 Bounds {{460.1875, 378.59997940063477}, {90, 18}} Class ShapedGraphic ID 280 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-2.adj} VerticalPad 0 Class LineGraphic Head ID 278 ID 279 Points {504.75, 284} {505.1875, 313.59998893737793} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 57 Bounds {{460.1875, 313.59998893737793}, {90, 36}} Class ShapedGraphic ID 278 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 FilterGraph} VerticalPad 0 Bounds {{27.9375, 2188.0999687194826}, {220.0625, 28}} Class ShapedGraphic FitText Vertical Flow Resize ID 275 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Align 0 Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural \f0\fs24 \cf0 Scaffold contigs using the distance estimate graph} VerticalPad 0 Class LineGraphic Head ID 271 Info 3 ID 274 Points {506.47121081998512, 1823.5804524742123} {321.90350000000001, 1895.0199687194824} {279.40350000000001, 1908.0199687194824} {229.9142468622905, 1916.836874470187} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 216 Info 1 Class LineGraphic Head ID 149 ID 273 Points {177.9375, 1917.0999687194826} {154.6875, 1917.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 271 Class LineGraphic Head ID 180 ID 272 Points {177.9375, 1865.1999687194825} {154.6875, 1865.1999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 269 Info 4 Bounds {{177.9375, 1899.0999687194826}, {50.5, 36}} Class ShapedGraphic ID 271 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ln} VerticalPad 0 Class LineGraphic Head ID 269 ID 270 Points {375.8125, 1820.8399687194826} {320.9375, 1842.1999687194825} {278.4375, 1855.1999687194825} {228.4375, 1865.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 217 Info 1 Bounds {{177.9375, 1847.1999687194825}, {50.5, 36}} Class ShapedGraphic ID 269 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ln} VerticalPad 0 Bounds {{453.4375, 2697.3499603271484}, {109, 18}} Class ShapedGraphic ID 267 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-scaffolds.fa} VerticalPad 0 Class LineGraphic Head ID 263 Info 2 ID 265 Points {373.44343345780555, 1827.206745795535} {261, 2030.2999649047852} {295.9375, 2404.2999649047852} {506.10916667576845, 2497.4894030185069} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 254 Position 0.014218973927199841 Class LineGraphic Head ID 263 Info 2 ID 264 Points {507.9375, 2379.4999675750732} {507.9375, 2498.3000801086428} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 260 Bounds {{460.6875, 2498.3000801086428}, {94.5, 36}} Class ShapedGraphic ID 263 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 MergeContigs} VerticalPad 0 Class LineGraphic Head ID 257 Info 2 ID 262 Points {373.7929382890427, 1826.2928611449695} {304, 1986} {336, 2188.0999687194826} {507.9375, 2291.0999687194826} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 254 Position 0.012177241034805775 Class LineGraphic Head ID 257 Info 2 ID 261 Points {506.9375, 1823.3999687194826} {330.8125, 1982} {358, 2184} {506.31004202611257, 2289.9374796950851} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 216 Info 1 Bounds {{462.9375, 2361.4999675750732}, {90, 18}} Class ShapedGraphic ID 260 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-7.path} VerticalPad 0 Class LineGraphic Head ID 260 Info 2 ID 259 Points {507.9375, 2327.0999687194826} {507.9375, 2361.4999675750732} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 257 Info 1 Class LineGraphic Head ID 257 Info 2 ID 258 Points {507.9375, 2260.6999687194825} {507.9375, 2291.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 253 Info 1 Bounds {{454.9375, 2291.0999687194826}, {106, 36}} Class ShapedGraphic ID 257 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 PathConsensus} VerticalPad 0 Class LineGraphic Head ID 255 Info 2 ID 256 Points {506.74250000000006, 2213.0999687194826} {622.4375, 2242.6999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 245 Bounds {{567.9375, 2242.6999687194825}, {109, 18}} Class ShapedGraphic ID 255 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-6.path1.dot} VerticalPad 0 Class LineGraphic Head ID 242 Info 2 ID 254 Points {375.8125, 1820.8399687194826} {322.9375, 1967.8999687194826} {357.9375, 2118.1999687194825} {508.32221747843306, 2176.3783586011227} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 217 Bounds {{462.9375, 2242.6999687194825}, {90, 18}} Class ShapedGraphic ID 253 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-6.path1} VerticalPad 0 Class LineGraphic Head ID 218 Info 2 ID 252 Points {728.0625, 1823.3999687194826} {506.9375, 1866.2999687194824} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 249 Info 1 Class LineGraphic Head ID 218 Info 2 ID 251 Points {638.0625, 1823.3999687194826} {506.9375, 1866.2999687194824} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 248 Info 1 Bounds {{637.3125, 1787.3999687194826}, {90, 18}} Class ShapedGraphic ID 250 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 mpet_lib} VerticalPad 0 Bounds {{683.0625, 1805.3999687194826}, {90, 18}} Class ShapedGraphic ID 249 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 mp_2.fq.gz} VerticalPad 0 Bounds {{593.0625, 1805.3999687194826}, {90, 18}} Class ShapedGraphic ID 248 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 mp_1.fq.gz} VerticalPad 0 Class LineGraphic Head ID 218 ID 246 Points {506.9375, 1823.3999687194826} {506.9375, 1866.2999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 216 Info 1 Class LineGraphic ID 245 Points {506.74250000000006, 2213.0999687194826} {506.74250000000006, 2242.6999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 242 ID 244 Points {509.6875, 2151.2999687194824} {510.14874758577207, 2175.1003441453217} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{462.9375, 2177.0999687194826}, {94.5, 36}} Class ShapedGraphic ID 242 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-scaffold} VerticalPad 0 Class LineGraphic Head ID 228 ID 229 Points {509.1875, 2103.6999687194825} {509.1875, 2133.2999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{464.1875, 2133.2999687194824}, {90, 18}} Class ShapedGraphic ID 228 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib1-6.dist.dot} VerticalPad 0 Class LineGraphic Head ID 226 Info 1 ID 227 Points {389.9375, 2015.4999687194825} {509.6875, 2063.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 221 Info 1 Class LineGraphic ID 226 Points {509.6875, 2033.4999687194822} {509.6875, 2063.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{462.4375, 2063.0999687194826}, {94.5, 36}} Class ShapedGraphic ID 225 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 DistanceEst --dot} VerticalPad 0 Bounds {{481.6875, 1997.4999687194825}, {50.5, 36}} Class ShapedGraphic ID 224 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 sort} VerticalPad 0 Class LineGraphic ID 223 Points {506.9375, 1967.8999687194826} {506.9375, 1997.4999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 221 Info 2 ID 222 Points {506.9375, 1967.8999687194826} {389.9375, 1997.4999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{344.9375, 1997.4999687194825}, {90, 18}} Class ShapedGraphic ID 221 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib1-6.hist} VerticalPad 0 Class LineGraphic ID 220 Points {506.9375, 1902.2999687194824} {506.9375, 1931.8999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{459.6875, 1931.8999687194826}, {94.5, 36}} Class ShapedGraphic ID 219 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-fixmate} VerticalPad 0 Bounds {{459.6875, 1866.2999687194824}, {94.5, 36}} Class ShapedGraphic ID 218 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-map} VerticalPad 0 Bounds {{330.8125, 1802.8399687194826}, {90, 18}} Class ShapedGraphic ID 217 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-6.dot} VerticalPad 0 Bounds {{461.9375, 1805.3999687194826}, {90, 18}} Class ShapedGraphic ID 216 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-6.fa} VerticalPad 0 Bounds {{27.9375, 1756.6999687194825}, {247, 14}} Class ShapedGraphic FitText YES Flow Resize ID 215 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Merge paths of contigs to create larger contigs} VerticalPad 0 Wrap NO Bounds {{27.9375, 1734.6999687194825}, {197, 14}} Class ShapedGraphic FitText YES Flow Resize ID 214 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Find paths that overlap, output graph} VerticalPad 0 Wrap NO Class LineGraphic ID 213 Points {375.3125, 1773.2499687194825} {375.3125, 1802.8499687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 210 ID 212 Points {395.99250000000001, 1639.5999687194826} {375.8125, 1734.6999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 210 Info 2 ID 211 Points {505.4375, 1637.9999687194825} {375.8125, 1734.6999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{328.5625, 1734.6999687194825}, {94.5, 36}} Class ShapedGraphic ID 210 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 PathOverlap\ --overlap} VerticalPad 0 Class LineGraphic Head ID 204 ID 209 Points {504.6875, 623.59996871948238} {855, 743.79996871948242} {773.9375, 1525.1999687194825} {624.9375, 1668.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Class LineGraphic Head ID 204 ID 208 Points {635.9375, 1162.0999687194826} {751.9375, 1317.1999687194825} {723.4375, 1588.1999687194825} {624.9375, 1668.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Class LineGraphic Head ID 216 Info 2 ID 207 Points {507.24250000000001, 1770.6999687194825} {506.9375, 1805.3999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 201 Class LineGraphic Head ID 201 Info 2 ID 206 Points {620.9375, 1704.1999687194825} {509.17420075564866, 1734.1817676284295} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Class LineGraphic Head ID 204 ID 205 Points {624.9375, 1639.5999687129283} {624.9375, 1668.1999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 195 Bounds {{599.6875, 1668.1999687194825}, {50.5, 36}} Class ShapedGraphic ID 204 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 cat} VerticalPad 0 Class LineGraphic Head ID 201 Info 2 ID 203 Points {396.49250000000001, 1639.0999687194826} {507.24250000000001, 1734.6999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 197 Info 1 Class LineGraphic Head ID 201 ID 202 Points {507.24250000000001, 1639.0999687194826} {507.24250000000001, 1734.6999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 193 Bounds {{459.99250000000001, 1734.6999687194825}, {94.5, 36}} Class ShapedGraphic ID 201 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 MergeContigs} VerticalPad 0 Class LineGraphic Head ID 190 Info 2 ID 200 Points {698.1875, 1353.1999687194825} {657.9375, 1440.1999687194825} {579.4375, 1521.1999687194825} {512.03442547098064, 1554.6117102664928} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 133 Info 1 Class LineGraphic Head ID 190 Info 2 ID 199 Points {508.1875, 1513.9999687194825} {510.24250000000001, 1555.4999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 189 Info 1 Class LineGraphic Head ID 190 Info 2 ID 198 Points {506.4375, 1163.3999687194826} {606.4375, 1218.1999687194825} {624.9375, 1430.3999687194826} {510.24250000000001, 1555.4999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Bounds {{351.49250000000001, 1621.0999687194826}, {90, 18}} Class ShapedGraphic ID 197 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-5.adj} VerticalPad 0 Class LineGraphic ID 196 Points {506.74250000000006, 1591.4999687194825} {395.99250000000001, 1621.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 192 Bounds {{579.9375, 1621.0999687194826}, {90, 18}} Class ShapedGraphic ID 195 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-5.fa} VerticalPad 0 Class LineGraphic ID 194 Points {506.74250000000006, 1591.4999687194825} {628.49249999999995, 1621.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 192 Bounds {{462.24250000000001, 1621.0999687194826}, {90, 18}} Class ShapedGraphic ID 193 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-5.path} VerticalPad 0 Class LineGraphic ID 192 Points {506.74250000000006, 1591.4999687194825} {506.74250000000006, 1621.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{457.24250000000001, 1555.4999687194825}, {106, 36}} Class ShapedGraphic ID 190 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 PathConsensus} VerticalPad 0 Bounds {{463.1875, 1495.9999687194825}, {90, 18}} Class ShapedGraphic ID 189 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-4.path3} VerticalPad 0 Class LineGraphic ID 188 Points {507.6875, 1466.3999687194826} {507.6875, 1495.9999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 123 Info 2 ID 187 Points {391.9375, 510.99996871948247} {379, 632.5999755859375} {294, 901} {507.62877024092643, 1072.7468280883497} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Class LineGraphic Head ID 74 Info 2 ID 186 Points {501.36750000000006, 510.99996871948247} {448.9375, 522.1999687194824} {392.6875, 531.1999687194824} {327.9375, 539.99996871948247} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Class LineGraphic Head ID 70 Info 2 ID 185 Points {504.6875, 510.99996871948247} {505.1875, 539.99996871948247} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 66 Info 1 Class LineGraphic Head ID 70 ID 184 Points {505.1875, 396.59997940063477} {563, 426.79996871948242} {562, 510.99996871948247} {505.1875, 539.99996871948247} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 280 Class LineGraphic Head ID 63 ID 183 Points {517.43135067823948, 174.92420095495595} {570, 200.40000000000001} {570.9375, 379.1999687194824} {506.31173042826481, 425.63297447970274} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 35 Position 0.03043123334646225 Class LineGraphic Head ID 74 Info 2 ID 182 Points {504.32400650842607, 171.06178148053633} {398, 236.40000000000001} {342.75, 444.29998970031738} {327.9375, 539.99996871948247} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 53 Info 1 Bounds {{27.9375, 1565.5199687194824}, {327, 14}} Class ShapedGraphic FitText YES Flow Resize ID 181 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Align sequences of ambiguous paths and output a consensus} VerticalPad 0 Wrap NO Bounds {{36.9375, 1856.1999687194825}, {117.75, 18}} Class ShapedGraphic ID 180 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-contigs.dot} VerticalPad 0 Class LineGraphic Head ID 150 Info 1 ID 178 Points {505.1875, 1162.0999687194826} {417, 1220.5999687194826} {432.6875, 1386.1999687194825} {507.6875, 1430.3999687194826} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 126 Info 1 Class LineGraphic Head ID 133 ID 174 Points {504.6875, 623.59996871948238} {766, 689.1999687194824} {807, 974.1999687194824} {698.1875, 1317.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 79 Class LineGraphic Head ID 133 Info 2 ID 172 Points {636.6875, 1162.0999687194826} {698.1875, 1317.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 128 Info 1 Bounds {{672.9375, 1317.1999687194825}, {50.5, 36}} Class ShapedGraphic ID 133 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 cat} VerticalPad 0 Bounds {{27.9375, 1441.3999687194826}, {288, 14}} Class ShapedGraphic FitText YES Flow Resize ID 170 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Find paths that overlap, assembling overlapping paths} VerticalPad 0 Wrap NO Bounds {{27.9375, 1328.1999687194825}, {172, 14}} Class ShapedGraphic FitText YES Flow Resize ID 169 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Merge sequences of contigs IDs} VerticalPad 0 Wrap NO Bounds {{27.9375, 1206.5999687194826}, {277, 14}} Class ShapedGraphic FitText YES Flow Resize ID 168 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Find paths through contigs using distance estimates} VerticalPad 0 Wrap NO Bounds {{27.9375, 1084.9999687194822}, {192, 14}} Class ShapedGraphic FitText YES Flow Resize ID 167 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Find overlaps between blunt contigs} VerticalPad 0 Wrap NO Bounds {{27.9375, 974.1999687194824}, {137, 14}} Class ShapedGraphic FitText YES Flow Resize ID 166 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Merge distance estimates} VerticalPad 0 Wrap NO Bounds {{27.9375, 860.99996871948235}, {191, 14}} Class ShapedGraphic FitText YES Flow Resize ID 165 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Estimate distances between contigs} VerticalPad 0 Wrap NO Bounds {{27.9375, 729.79996871948242}, {174, 14}} Class ShapedGraphic FitText YES Flow Resize ID 164 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Find pairs of reads in alignments} VerticalPad 0 Wrap NO Bounds {{27.9375, 664.1999687194824}, {115, 14}} Class ShapedGraphic FitText YES Flow Resize ID 163 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Align reads to contigs} VerticalPad 0 Wrap NO Bounds {{27.9375, 550.99996871948247}, {251, 14}} Class ShapedGraphic FitText YES Flow Resize ID 162 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Merge paths of contigs to create larger contigs.} VerticalPad 0 Wrap NO Bounds {{27.9375, 437.79996871948242}, {169, 14}} Class ShapedGraphic FitText YES Flow Resize ID 161 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Identify and pop simple bubbles} VerticalPad 0 Wrap NO Bounds {{27.9375, 210.80199999999999}, {151, 14}} Class ShapedGraphic FitText YES Flow Resize ID 160 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Find overlaps of [m,k) bases} VerticalPad 0 Wrap NO Bounds {{27.9375, 97.004000000000005}, {127, 14}} Class ShapedGraphic FitText YES Flow Resize ID 159 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Assemble the input files} VerticalPad 0 Wrap NO Bounds {{865.125, 240.60300000000001}, {117.75, 18}} Class ShapedGraphic ID 157 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 output file} VerticalPad 0 Bounds {{870, 208.80199999999999}, {108, 18}} Class ShapedGraphic ID 156 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 intermediate file} VerticalPad 0 Bounds {{879, 177.001}, {90, 18}} Class ShapedGraphic ID 155 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 input file} VerticalPad 0 Bounds {{898.75, 127.20099999999999}, {50.5, 36}} Class ShapedGraphic ID 154 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 unix tool} VerticalPad 0 Bounds {{879, 77.399900000000002}, {90, 36}} Class ShapedGraphic ID 153 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Cap 2 Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ABySS tool} VerticalPad 0 Bounds {{778.75, 40}, {268, 17}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica-Bold Size 14 ID 152 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\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 2.0.3} VerticalPad 0 Wrap NO Class LineGraphic ID 150 Points {507.6875, 1400.7999687194824} {507.6875, 1430.3999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{36.9375, 1908.0999687194826}, {117.75, 18}} Class ShapedGraphic ID 149 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-contigs.fa} VerticalPad 0 Bounds {{460.9375, 1430.3999687194826}, {94.5, 36}} Class ShapedGraphic ID 147 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 PathOverlap\ --assemble} VerticalPad 0 Class LineGraphic Head ID 145 Info 1 ID 146 Points {505.1875, 1162.0999687194826} {432.6875, 1203.1999687194825} {433.9375, 1279.7999687194824} {506.4375, 1317.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 126 Class LineGraphic ID 145 Points {506.4375, 1287.5999687194826} {506.4375, 1317.1999687194825} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{463.1875, 1382.7999687194824}, {90, 18}} Class ShapedGraphic ID 144 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-4.path2} VerticalPad 0 Class LineGraphic ID 143 Points {507.6875, 1353.1999687194825} {507.6875, 1382.7999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{459.6875, 1317.1999687194825}, {94.5, 36}} Class ShapedGraphic ID 142 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 MergePaths} VerticalPad 0 Bounds {{461.9375, 1261.7999687194824}, {90, 18}} Class ShapedGraphic ID 141 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-4.path1} VerticalPad 0 Class LineGraphic ID 140 Points {506.4375, 1232.1999687194825} {506.4375, 1261.7999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 137 Info 2 ID 139 Points {560.9375, 1046.7999687194824} {572.9375, 1109.9999687194825} {556.4375, 1175.1999687194825} {506.9375, 1196.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 127 Class LineGraphic Head ID 137 Info 2 ID 138 Points {505.1875, 1162.0999687194826} {506.9375, 1196.1999687194825} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 126 Bounds {{459.6875, 1196.1999687194825}, {94.5, 36}} Class ShapedGraphic ID 137 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 SimpleGraph} VerticalPad 0 Class LineGraphic Head ID 123 Info 2 ID 130 Points {505.1875, 623.59996871948238} {372.9375, 685.59996871948238} {311.4375, 907.59996871948238} {509.1875, 1073.9999687194822} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 71 Info 1 Class LineGraphic Head ID 128 Info 2 ID 129 Points {506.9375, 1109.9999687194825} {636.2039216974481, 1143.9728780056712} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{589.4375, 1144.0999687194826}, {94.5, 18}} Class ShapedGraphic ID 128 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-4.fa} VerticalPad 0 Class LineGraphic Head ID 123 ID 127 Points {560.9375, 1046.7999687194824} {510.95785563837956, 1073.0694629539958} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{460.1875, 1144.0999687194826}, {90, 18}} Class ShapedGraphic ID 126 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-4.adj} VerticalPad 0 Class LineGraphic Head ID 126 Info 2 ID 124 Points {504.6875, 1109.9999687194825} {505.1875, 1144.0999687194826} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{461.9375, 1073.9999687194822}, {94.5, 36}} Class ShapedGraphic ID 123 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 Overlap} VerticalPad 0 Class LineGraphic Head ID 121 ID 122 Points {561.4375, 999.19996871948251} {561.4375, 1028.2999687259262} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{516.4375, 1028.7999687194824}, {90, 18}} Class ShapedGraphic ID 121 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-3.dist} VerticalPad 0 Class LineGraphic Head ID 118 ID 120 Points {507.4375, 938.1999687194824} {563.6875, 963.1999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 118 ID 119 Points {626.6875, 938.1999687194824} {563.6875, 963.1999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{516.4375, 963.1999687194824}, {94.5, 36}} Class ShapedGraphic ID 118 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-joindist} VerticalPad 0 Bounds {{585.75, 21}, {90, 18}} Class ShapedGraphic ID 117 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib2} VerticalPad 0 Bounds {{347, 21}, {90, 18}} Class ShapedGraphic ID 116 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib1} VerticalPad 0 Class LineGraphic Head ID 102 ID 115 Points {720.75, 48} {772, 163.20099999999999} {689, 481} {625.63485355620992, 651.32548270089467} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 99 Info 3 Class LineGraphic Head ID 102 Info 2 ID 114 Points {504.6875, 623.59996871948238} {622.99547020199293, 652.72193061535768} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 79 Class LineGraphic Head ID 112 ID 113 Points {627.1875, 890.59996871948238} {627.1875, 919.69996872592617} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{582.1875, 920.1999687194824}, {90, 18}} Class ShapedGraphic ID 112 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib2-3.dist} VerticalPad 0 Class LineGraphic Head ID 110 Info 1 ID 111 Points {738.7405, 802.39996871948244} {627.6875, 849.99996871948235} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 105 Info 1 Class LineGraphic ID 110 Points {627.6875, 820.39996871948244} {627.6875, 849.99996871948235} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{580.4375, 849.99996871948235}, {94.5, 36}} Class ShapedGraphic ID 109 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 DistanceEst} VerticalPad 0 Bounds {{599.6875, 784.39996871948244}, {50.5, 36}} Class ShapedGraphic ID 108 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 sort} VerticalPad 0 Class LineGraphic ID 107 Points {624.9375, 754.79996871948242} {624.9375, 784.39996871948244} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 105 Info 2 ID 106 Points {624.9375, 754.79996871948242} {738.25660037834405, 784.27410710949846} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{693.7405, 784.39996871948244}, {90, 18}} Class ShapedGraphic ID 105 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib2-3.hist} VerticalPad 0 Class LineGraphic ID 104 Points {624.9375, 689.1999687194824} {624.9375, 718.79996871948242} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{577.6875, 718.79996871948242}, {94.5, 36}} Class ShapedGraphic ID 103 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-fixmate} VerticalPad 0 Bounds {{577.6875, 653.1999687194824}, {94.5, 36}} Class ShapedGraphic ID 102 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-map} VerticalPad 0 Class LineGraphic Head ID 10 Info 2 ID 101 Points {675.75, 57} {504.75, 87.1999} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 99 Info 1 Class LineGraphic Head ID 10 Info 2 ID 100 Points {585.75, 57} {504.75, 87.1999} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 98 Info 1 Bounds {{630.75, 39}, {90, 18}} Class ShapedGraphic ID 99 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 reads_2.fq.gz} VerticalPad 0 Bounds {{540.75, 39}, {90, 18}} Class ShapedGraphic ID 98 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 reads_1.fq.gz} VerticalPad 0 Class LineGraphic Head ID 93 ID 94 Points {506.9375, 890.59996871948238} {506.9375, 919.69996872592617} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{461.9375, 920.1999687194824}, {90, 18}} Class ShapedGraphic ID 93 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib1-3.dist} VerticalPad 0 Class LineGraphic Head ID 91 Info 1 ID 31 Points {387.6875, 802.39996871948244} {507.4375, 849.99996871948235} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 85 Info 1 Class LineGraphic ID 91 Points {507.4375, 820.39996871948244} {507.4375, 849.99996871948235} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{460.1875, 849.99996871948235}, {94.5, 36}} Class ShapedGraphic ID 90 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 DistanceEst} VerticalPad 0 Bounds {{479.4375, 784.39996871948244}, {50.5, 36}} Class ShapedGraphic ID 88 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 sort} VerticalPad 0 Class LineGraphic ID 87 Points {504.6875, 754.79996871948242} {504.6875, 784.39996871948244} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 85 Info 2 ID 86 Points {504.6875, 754.79996871948242} {388.17222815072813, 784.27733664032394} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{342.6875, 784.39996871948244}, {90, 18}} Class ShapedGraphic ID 85 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 lib1-3.hist} VerticalPad 0 Class LineGraphic ID 84 Points {504.6875, 689.1999687194824} {504.6875, 718.79996871948242} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{457.4375, 718.79996871948242}, {94.5, 36}} Class ShapedGraphic ID 83 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-fixmate} VerticalPad 0 Class LineGraphic Head ID 78 ID 80 Points {482.75, 48} {731.4375, 152.19996871948243} {610.4375, 575.99996871948247} {504.6875, 653.1999687194824} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 51 Info 3 Class LineGraphic ID 79 Points {504.6875, 623.59996871948238} {504.6875, 653.1999687194824} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{457.4375, 653.1999687194824}, {94.5, 36}} Class ShapedGraphic ID 78 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 abyss-map} VerticalPad 0 Class LineGraphic Head ID 76 ID 77 Points {327.9375, 575.99996871948247} {327.9375, 605.09996872592603} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{282.9375, 605.59996871948238}, {90, 18}} Class ShapedGraphic ID 76 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-indel.fa} VerticalPad 0 Bounds {{302.6875, 539.99996871948247}, {50.5, 36}} Class ShapedGraphic ID 74 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.00241076 g 0.229592 r 0 GapRatio 0.5 Width 3 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 awk} VerticalPad 0 Class LineGraphic Head ID 70 ID 35 Points {505.19342901477512, 171.03102104226556} {585.75, 213} {578.4375, 494.59996871948238} {506.8874612237708, 538.94634087567101} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 53 Info 1 Class LineGraphic Head ID 71 ID 72 Points {505.1875, 575.99996871948247} {505.1875, 605.59996871948238} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 70 Info 1 Bounds {{460.1875, 605.59996871948238}, {90, 18}} Class ShapedGraphic ID 71 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-3.fa} VerticalPad 0 Bounds {{457.9375, 539.99996871948247}, {94.5, 36}} Class ShapedGraphic ID 70 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 MergeContigs} VerticalPad 0 Class LineGraphic Head ID 66 Info 2 ID 68 Points {504.6875, 462.79996871948242} {504.6875, 492.99996871948247} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Class LineGraphic Head ID 65 Info 2 ID 67 Points {504.6875, 462.79996871948242} {398.9375, 492.99996871948247} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{459.6875, 492.99996871948247}, {90, 18}} Class ShapedGraphic ID 66 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-2.path} VerticalPad 0 Bounds {{353.9375, 492.99996871948247}, {90, 18}} Class ShapedGraphic ID 65 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-3.adj} VerticalPad 0 Class LineGraphic Head ID 280 ID 64 Points {505.1875, 349.59998893737793} {505.1875, 378.59997940063477} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 278 Bounds {{459.6875, 426.79996871948242}, {90, 36}} Class ShapedGraphic ID 63 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 PopBubbles} VerticalPad 0 Class LineGraphic Head ID 57 ID 62 Points {504.75, 236.40000000000001} {504.75, 266} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 56 Info 1 Class LineGraphic ID 61 Points {504.75, 171.2999999935563} {504.75, 200.40000000000001} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 53 Class LineGraphic Head ID 54 Info 2 ID 60 Points {504.75, 123.2} {387.75, 152.80000000000001} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 58 Class LineGraphic Head ID 53 ID 59 Points {504.75, 123.2} {504.75, 152.80000000000001} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 58 Class LineGraphic Head ID 55 Info 2 ID 58 Points {504.75, 123.2} {630.75, 152.80000000000001} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Bounds {{459.75, 266}, {90, 18}} Class ShapedGraphic ID 57 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-1.adj} VerticalPad 0 Bounds {{459.75, 200.40000000000001}, {90, 36}} Class ShapedGraphic ID 56 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 AdjList} VerticalPad 0 Bounds {{576.75, 152.80000000000001}, {108, 18}} Class ShapedGraphic ID 55 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-bubbles.fa} VerticalPad 0 Bounds {{342.75, 152.80000000000001}, {90, 18}} Class ShapedGraphic ID 54 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0.501961 g 0 r 0.501961 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 coverage.hist} VerticalPad 0 Bounds {{459.75, 152.80000000000001}, {90, 18}} Class ShapedGraphic ID 53 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ecoli-1.fa} VerticalPad 0 Class LineGraphic Head ID 10 Info 2 ID 52 Points {437.75, 57} {504.75, 87.1999} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 51 Info 1 Class LineGraphic Head ID 10 Info 2 ID 39 Points {347.75, 57} {504.75, 87.1999} Style stroke HeadArrow FilledArrow Legacy TailArrow 0 Tail ID 17 Info 1 Bounds {{392.75, 39}, {90, 18}} Class ShapedGraphic ID 51 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 reads_2.fq.gz} VerticalPad 0 Bounds {{302.75, 39}, {90, 18}} Class ShapedGraphic ID 17 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Color b 0 g 0 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 reads_1.fq.gz} VerticalPad 0 Bounds {{459.75, 87.1999}, {90, 36}} Class ShapedGraphic ID 10 Magnets {0, 1} {0, -1} {1, 0} {-1, 0} Shape Rectangle Style stroke Cap 2 Color b 0.501961 g 0 r 0 GapRatio 0.5 Width 4 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\b\fs24 \cf0 ABYSS} VerticalPad 0 GridInfo GuidesLocked NO GuidesVisible YES HPages 1 ImageCounter 1 KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo Animate NO circoMinDist 18 circoSeparation 0.0 layoutEngine dot neatoSeparation 0.0 twopiSeparation 0.0 LinksVisible NO MagnetsVisible NO MasterSheets ModificationDate 2014-05-07 21:55:17 +0000 Modifier Tony Raymond NotesVisible NO Orientation 2 OriginVisible NO PageBreaks YES PrintInfo NSBottomMargin float 41 NSHorizonalPagination coded BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG NSLeftMargin float 18 NSPaperName string E409205B-47EF-41DB-B00B-53E0115DBFAE NSPaperSize size {1133.8582763671875, 3401.57470703125} NSPrintReverseOrientation int 0 NSRightMargin float 18 NSTopMargin float 18 PrintOnePage ReadOnly NO RowAlign 1 RowSpacing 36 SheetTitle Canvas 1 SmartAlignmentGuidesActive YES SmartDistanceGuidesActive YES UniqueID 1 UseEntirePage VPages 1 WindowInfo CurrentSheet 0 ExpandedCanvases name Canvas 1 Frame {{337, 419}, {1256, 933}} ListView OutlineWidth 142 RightSidebar ShowRuler Sidebar SidebarWidth 120 VisibleRegion {{-4, 0}, {1107, 794}} Zoom 1 ZoomValues Canvas 1 1 1 abyss-2.2.4/doc/flowchart.pdf000066400000000000000000005026231361462241400161040ustar00rootroot00000000000000%PDF-1.3 %Äåòåë§ó ÐÄÆ 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xÕÛ®dÉqžïë)êrpoVÕªã¥Dц’<†-£ÖŒ‡t·¨é‰²ÖÏâïSæ:TÕÚ=CZAÌ®è•LjŒsFþ°ý›íÛÿÛíá2œ¶Ÿ¾Ýþ—í?nù«ÏûíûÏÛ½ýïóûí»ýùõÄ'ÇÿùHƒëþu8]²ùÐ ïλÃëîr¼l?D«òý´§ï¶¿üëo?½ÿöŸ~üço>l?ývóÃv¿?ڬλíq8¼÷¼Û½Û÷·¿üËûí_üÞf¾ßì;›ûÙ¿;_˜ŸwØÌ¿ÎóþŽÃ`ýNÃë…þ6Œ{\øn`[4¿üNó;Õwƒö–Eì¶§Ó®}·ñùë»ùz×Ë+°õ^ÚwµÞœßQøˆþ®í»Ñþí¯fÈÚJ4Ã[û²z—×ã`_î‡ês¿[øTƒG§ú4ÑÒáåÖð·‹^÷G03osԨ׳Mu²oÙka‡©i3!ŠÃåã:]ÂÏátÎñûNŠömª‡ÛëÍ6`7_‡œj‡¥ù§ûÛùZ»º_B”Äöj;^÷Ùk᪭êxÚûøûÛŽýÍõw¸jãs*l«öסíêaW'߀ýåz®#tèpUpÚÛЉ–0uÞuÆ<…§}ÛRQ½J¿¥‡Qµ¤út´¥­9¡œ9ã‡ãî´mé¡Õ¶ôtaËER£-=txêÆ?Äî¶´ðÔñšÓé»?ÚÒQµ¥ÃAìòp¾žŠöá ó%N7ßz};:t8ªi¯×˜æåЈtXÂÒñô¼?_.E¤ÃžŽ¼ýý¹;ûC‡§ZQÒýé|x=æ\;<]옊çñ(ÿ4(j(†%D‡sàt8Àñ£WQ¸êzb³§Æ¤ [´ ®¿æw¹]_Ùg‡«bÓWξè„yð…¨FÏ×ËÞ¥¼üp»eKxºžêñS;Þ’™ššhºÅÃÇÛåõ|»fŸ Km9×áúz–´;žO¯×›ä¢¤ ’>v©Íô|L,ÙÖg¯ K­×ܤ+Ì"1|Œ£mR–œŽ81!!Ž,ûrdªû=gçyjÚ‰¡ãpŠw½ÄÑ©ÃQžD¼û4{-4ubàlÞn~Ôk‡§Žš8Eúô®Ùiá©íhãe»ý­ÄөᩱÝa·Ý Q£> KÝDµ|[Ó&)œÐêŠêkõ<Ø«O„Óùœíð4Z’æër Ô#¶«Óù—±ÔèóÜá© ¿çI8_vIöçBRÛ¤ãéè|ä|Ûew‚ºAº;ƒ©Äú¹ÃO Ì ÎN4Âì³ð3âa±—'Qt.»ÃOõyB …9j/Ùõìs ?gÔ—öeö¹„±Ž«áê¨>;ôÔèbu¶•ÇóðšçýÒЧˆz:î»/cž—†žà!RÓSyntó¼‚F£0£Ðo—1:æ1¶¿³»4$µ‰gG'Ÿžv»”JàwƘøw_ÓÍ9•¼Ka©‘R}xAäV’ŠyKx¹â:@#Iž—%,•ô$½ªÚ N>’>(Õåv;UÇ WM.]Q‘u;á4(õZˆj}^®&>w¦ìÞct÷Ëÿüí‡o~üí¿|û«ßøý§ß~üöÇO¿}‰»•æÂñ?œáùÖô ý«ýþ¿7èRÙ?´ïã÷÷ =|·=nÿ°=lƒ½þ;·Þõ•m’qÞo¾úƾoÛ»=V¸4MLþ›ãâˆÊ¢dvrØ4§ãÀ¤°G?²óÈ´¼MB˜(›öó¦ú¹¹'áþ$„ãYãg“ÐÞÌ'±™õ£IàÒ€fSpgt;!•š•Î ÁˆçÏ¿ÞÆ™yÇߡŸ/ûëu{Ü|¾óõ×WVóõwÛÿ¶}ù³_lß¡‹m_þ<ÿø¯_}õ‹íßn¿þÍö×_û¨ŸÎ‘r`‹§Íá‚=*OÊ€r.Üûïõû|ù}Øú÷²!ü÷÷‰6ß1í¯p¯CqEÆÞ–‹Ìß·ü›qíïÍIn›øÆþþ>Y‹G9 {ßÈ›ääf²èŽÃñ|f·ómü”»÷mþñMþñ¿ØØNÀßåûüãõ[ûä»âüøý¿ #£ƒ1FÆ€ e_vÉ߉ÿžÓY™öð]O_Ó“Ö6¡èârÚ°µ²ý½u8b…¦ÛG8¢o%ßL^üÑpø2ˆFŸR)Þ"–°I7¤ÐI…†>n×3›Å6lÒGéýq¨å4®Çƒ3ÖóI$~¼î^w7ì ˜-¼m¯ÆÇ Fôy¯3Ýu8q_¹ZÇDÃÿ÷¡'NÔUÃâ`¹÷ŸñIƒ‚ҫɽ¡ijPØ ,Ÿ´eÂB°ŸåßÉj{µÄ¯‘úýá kXó€ÊöÇtÂí£e¯8l53ܶGTYÁ…;“.ÚŽÍì»3‚ÜŽQkæVÛñhf' „†e;Žû¶–6eF TDÍð¨ý`Ô X½â҉혷õ ‘øŠCržè\´‘’Ó~ƒÆúm~9FÉïãw“œÙƒ¸§KÍ;»Ý ¦½Ùh%ýg“Œ8®ZYH¤øY2Ñ>p£81kcrˆQtw»Ûåb\t3FÅ<ßçÁü}0Àñß߯ßMxçæå;î©%uU<1wí¸ï³æü­}õ}í{AsÐRh&"ñüó¾ì†£É«DƒoÎ@¢!ƾçÇ…†‰OÐ0àh'íÑÙíۯߴ¹D®¬f¦¼¼ÿý¿|ûé›ÿñíë÷¿ýüã/¶_ÿîŽFp:‡W'væ|–3p{ýaë¿™Lìe}_{[ÚÛ´|ºptr×>nÏW¼hù“ÁâgìZ~\›˜€›xÆŸ<ÝÄ^±’â~=þTZþû êŽÿþ}h Oâ¯ãQªDê ˆÓ3”å}ÏtìwÇtÌoß1øL”F®®›àzNùÒÚ‚§PšéâÿY è ˾1 üY ([‹UòÍ}9ãÌ,›†BþpàÍß©á'”³bá|~ä6“#‡B>àXwº)ä/ö¿ûÛ&³Nêw ÿÝp)cU"º¾ß‰Kœ ê>âê·+!÷ÙWDÜg‰Bd®”ƒÄçµGŸýhȳVkdÞY1Ë©äÀiènŸý»ŽÆ‚äpõûžäؾtšº«á¿ë%É#F„KQœƒòÀ†œAáU´aZ»fóPùÙœlŸ6¹Oþ“‰®Ä)ÔãÒiÄ´p(ûoÔ.Ó=Y¿ý»ÿÞ@T“µÝ Ïj^RA79Ü †Î˜—tÛÑç+V+²ÍVAa‰áˆƒNTXÎ%—#z=ª¾Ñ€AöØ•¨•áûp‚º»ßïQOlÉŽØ“p±ÐöéúMý`ÓèÇ €qd@_Q¬ùS¸>\M– ô¬1EøX]ÑÆmCÿx¢z6ìo÷h$æ*ŠM½É{àvPá§X‡{ÌØWbÞ~ux·oW­:ÂRaÖQµ $ÖãgÃz|^Xß<±¡\W0 VD èý~BãG‚ÿG¶/iüˆÑc\3Vš¿ÛZ­;ó–ÕΊÆ!ŸH¬6Öjós_-¶Jª î˜%pRÖJqqãƒÔ2a ‹eÑi-Xöä D’ÏJEB4,EÂÜ¥ò™_µBT‰à²ÈxIÓž˜Pô²É^´ð±JñÀt½7…èímS öà ÑJ¹Ðþw¢G>>[Âá€3aɰÂÓŒz›»§6xùþ:í¨ ³¼}MçtÙ÷HçüÛM:å¯[£0œv‘è2IFŽØ ¡ûǢ͡å=š$PŠ"&úañõ+kH市²Vº½I|ížçP9)#aÞ«“pÎR^£éèàäÒ¢QÌüÍ€YeÊ Îå±ägá 4‰v­òýBOO ~­i€Ÿ[âx3ÿ1rýÜè§Îhüëi/öTûO̸õˆ2'Þg -èp,÷GRÛ†t ¤ÍóXmK¥ V6ef‰iÎÁ¨ G#fûß×Á!#f–==t—&«á›ü+vuäïÉŸ¾õõqb¢Þú&:±ˆ ÒÓäýqÑýzæ5M¦Rùñû7hÐv`yÎ9y¨œx#LJ+y…wtè¯B };ïê‰:ÜÈ|¹îð 1Z ¤Ú´Ç± ­×ý…Ð÷´5´XÅ#ß jûëEÃJz㆕ÞÜ¡¼jXPôº?þ瀡dàˆÜoÌ)ëC¤ÎBkg«thcw¹SÒj|ëä4mL’VÐ×g@PRÏdÃŽ8Ä5q»Ú^ M#9¸ŠòÄ8#Ù@JŒ&%}c4K×8FŒóˆöíl’ëk¨TÎ`¢cZ‚–näV«€|¡\°èé‹t˜)á8bÝʶ8]e•P’ÍQ?™NýDËõõ±ý”®ÑZ‡Ú¼^ÓhM'‹w¼a`Z?æI8ûëRì…\Âè7è~ÁøþOÅ<* –«o±ñð⯒}§&ò¡‰ü˜†y6Á¹uÇ›:©QÏSíVl¼‡ˆ> BجôÏøÆ!ÁÆûvor„à·órF 8ƒÔÊþ4€E~hdQMaH½CÝ»å- 0 $ã§’ögr­O$íÔµÞi¥s~:NV‘kªH'tVLƒMPà=eÏ0h'Þ˜AO镽íaïð$þˆÀÐn%ÏŠ9žqnÙ”²³dÚ¡ì% Sö¢QäºÇ ÝÀ`7™×X¿;¤›‚ÏGzßv âH ÄabGB¨{ìŠÝ…¬#‚kæx&ôô~{ÂpÃAN¼¶‡„dË IJžGHÒCè–ŠIá{$s“âFDï2ìõõzÀÑ£„Ê9I›¹»=b Wž¥Ú²LŠ Šº`ÞWZÄÆ/dzÃÎt Ÿƒ«G |‡ë|ƒ#AÓ’“Ö+ñ‚…£†š)=*ØGøîu¯aO ¯'¤-‡§<©O,X0!hÒš.¹"¾¡,—p)W”vôcòAêwABŠt­Ýu°’+Cå/ü΂A²Òð³ˆiŽìñùANƒ9f 9›‹ ©ß6Y0í§I%7øÇ!`°ñÖ¶nÄâó”3ª7“m9–õå–ÏäñÐ!‰˜a×MÄ,‡¤øÂÛ3aóòÍþç,…ï_ÿ’I|å!„Àìí!ZQAB8t­12î`ÑSxÉ3Ú­šÞ÷™ µÄý]wpÉ€–JZ–))* $CkR¢"A›ìeåNß(P¹ZH *i¾àKw'AŠìwù‡ óÍË?„P¯.2t•FÛ8PõÌ…`GCy†¦{Aì^ý4?È=ëU¢]h7¨ º€l`XÇ‚]0m÷\¦Œæ(ñ “¾“ŽYZBµ­"Œ•+ÉF’þEÊGRW]ëÝáè0ÃQ®Euqpˆôœ‚Xê¹ìzoE`- päYO_¤kÒdm ÊÇÐ:OyåÇRIcÚg,“Õ$®«—Mö"Z~‹F¼8…èímSØöSxî{Ûá´Zʰ#oL.þóŒaÉ÷VVqºÖþWªÂÆ­?Þ}Ì«V×R‡7–Œ·ÞïúîÙ8ˆT± ?Éïüc®Š¹Ü)ÉK QC(äØA\è—Ù™íVŠüœT3HÞ§ùxÖ,%ìÓ|L@g>*õIçB+I?òü%¦2É72Ú…sxŽæ2æúºùFÀ,êv!û|Â7‚ÛœóE~ʤ¡)Z&ÝèÂ/˜÷®n¡Ô‘p>²IbfÚ%4Ø\$KF ÃÕOrTFSô1¤$^ ÚnÏôNÒJ˜Ô¥ÝÙúÚ Ä_R Ã˹#¯Z“A s\`ÜH_F$Ï×B$NcÍc9¬ø>|—@½Œ*ŠÉ3c}\—gÍ „TuíÂŽ0,Gr6 vŽ3ÔZ„5Xýï¶#烒Þà|Ђ\*r§Y."Ùq¼™[З”¾ÇÔ²I˜Y‚’'ؤý¾™üpFx3'±É1kÄÜ™Déõ–Rñ2cˆg1ëJÙ›fÉÊ%A {®áo_>ÿþÓ$9vÓ_—QÑ×j4zR¥1k‡°´Á°ò€†·Úà%t‹›õäZI¶uΈò8sW™Ã}‚“ØÜô“iÔOOøO÷ôÕ~иܧMÆ»Z Á«Í¶êk4°õ´~`.PäÀw‘ŠoÔ×ߥ½” 4°lªé2Ô_¤Š2çùßd #ãå)_ǯ—%ÄuÆ…0®œ%? ƒ#˜à\aÁæ(À§ËÒárr'„“­ã*{Aöß8dŽÛϧÜqª‡ü‚‘%@ܱVâ\y®g`û8}šÒ ¥aqqYi{U€÷ˆC݃ Šãb—S]qc¼Ã|+1tä.80ÜzÄlµh°Gÿn Îì>koÍa«ÖO7ÃEÒYÃ"Ì•½iª˜¹ÅOו% D§a˜{ «ï0÷|X…G¦­ÇbƒEŠ–™—nÌëÀ–y䱎0¡öWleÏí˜BÄ:¦=­J"áºÓÍ ¾?ò÷@R+ý=7yíµÔj±I/Zäøü¶ôma2HUµËÓ0Wéy ¡È‘:Ÿx…ž—>ËlÒâÍJ=/ÂÑ¢{à†‹Q# ^¸ìÕ8•’pE±ºQäÇTå´›Ü1ÄnPE´[I«9),s‚09Ûi›¥p‰)ØŒ®ƒ;i4¢ÏÞåvÏdb|¬íf(‰Äö¯¼éD ßçoúŸôШÒü8O®üîKÇîuž±ÓüoÆõ¿íòa|ƒúgëéZÌ©°9È@Qo‡3:úœ¡ì¸ ºà=¯xÉ…rå%¥…u7AÃ.?ùó› ~ˆÌpši1>Rl¢ÇЇú˜bHÙå}‹ÜÍý¡mË4ÞÛ6¡ä‰1d0Œÿm(dú Ë}JR¼¿ kÌ5“EJþî@ádÓ帷tîØ†±(élî@®4.:»\G¼PVÇax2]²X0 5¿„8k<îÙNñ©ã~’K ÁBö"‚ žÃNKª:&¹‘ü´á6äï›pÚÚùÅSAÆQŠœ«="¶¼×mY–†êV²åQ÷ËVÿÔ&;‚ëS0UŒñeb6.'½éf«3Íý¸ñj®É‰ r=ãyÈ Ñ Æ› ï2?¹q¹Ôx”C™=²ÛÎ=il×j£ñÈ£úRfDDÊ”Má ¼¬A"¢“­úOÂ26$eNõÒö~ƒ‰pâ:¿M!C#ç¬A–1žßM«¯&`éú¢O6fñq³&¦P1ž·L¡zñ›‰Cô,¡DïáÿyŒ'5übêrÅW!ÁŽ( Ò‘‰{É%Í“¸šß¼Áн§7[…›t3*ÒYÝæöêÈ£ù˳—ðp¿Í–ÌÆåéÎË_žb6î²oMÐ(´zYIÿÿúËU*ÊhÜb³ŠHÇó¢(:Wœ<ýÞ犒#¢Ì_®Ûk¦§r«1ýåóvO9® Ì6©ð—Ÿ3Nž³Ô5[GÐZri‹þò³î¢{½Åpš]äöT– ïx¶êýå sǬDPÓXéIJLfå/—‹T€rn ÝãçhÒùË ´Æ_~!Fa#ü¼þòÊýþ#øËí~Ü\pé£Ù% $ËþZ¤P©›bÀÒ—3õ GÔQIdVÍ5.ŽE·rð|R² –Z¯¢Ô‹Lo kÈ»ái,_*ÃÊ5~¥¼&C\DÀVx£’¦<2 ­Í]~ñÖZ]ŠìGäTÔîUä_iuTçOÎo <µá¯3[îòQ‹µîò†µð|·óîò<¯5»þ¼.¹Ë‰Ã¢YÌ=3zÝ.;H8Ç»Vå.ï`?›»ü„ƒÇ¤tt+0.5®Üå (wy5ižêe/†ûÕîòYóÓû“F³Ê1«IÓ¥Äñò˜ñÄ]^*ÒÕ]NZ3w V¹»\¦`ø@ ¢¥$œãÙªw—' __ôôveûƆv¿3°>7w—·ŸvÌOõq¸Ëðîòlï)Üåù Dü¥}<x…»œ{¾NÌðÿ_îr±÷ ÃýÅñà‘»\\0‚/á.—Ç#!îCäµc¼U2¢›”{¾åñiÇ,Å?GqÇ\ZøØWºË©Eâ2ß•±M®äb·š»|w#òìîr•¸qÙ0Üå\­Öö!™ˆÃÈ·‚²T `¯:ÕWÒŒH2Á•Ã[nŸî…¼h8Þ9MŒjÞr\!e‹äQb©×iFbíøÅUtr\\.5vq);‰Ü_¥¼k›³¼¬¤pŸ‹q„y]ÎòlÅÃ}Wœõ´JÉ#=Ý©&åe…¤³¼Â7Þš”³¼Ø{¹Üç,¹ùotzƒPNgù%/]˜_ì,mÛ”ÓY^€‡ÎòŽO…Ó[ÅyìÜMîÎr ¨1DÇÖùTñgy›T8ËulmÚé,×±m?¹4tQó°;}>t~yH-V’Éš:a\«%¿N.ê¨Ò½ú²Üo¢FòòÈ ÜsÊÏ ¨2¹Xb~nÝÙŸÑ3Í‹tP” …s©õÓsëT¦a-+HçVŽL {Vn°ëÜÂ"ÏÖÜ6`"vÅ[ã»!§Ð[¯Ø1Œp#[ÊæFqå-9Ó(Pq¼¡M*1’,H¹J{Ê™èêÌž î­(_“cŒ…ˆs~2ˆ¡È&n¤+Ò{(L±(.ÑPWî=5ªˆ’Á{"¹ïºW $ éFØaâPθtÆ¿°ÑÜòôLM«[ŒÂÏ^O9)MUO*šN˜-áJm½(WJ2 '‚vÙÙ%í OµgJxÖ(:’íJ‰Á)‘”ŒR–¬1õ•Æ<“/In”{àgMÁFUb’3Ço­w?q7sˆô¯*ýIoù±~Úz­ßô´Üû) ¢3âòÜïb P¹ôÃñ‡•–Ô?ÙÊ‹¯4íq±*ܾ¬a§n rq©ô›?P¦gáBôˇßþ=©a}ųQRlj’ùŠ…žIoh¿Ùùü;SßÇÆÉýÔ·Ú|uL'Ï\å¾?á6·‰ob—ú6*Kœ±Wœ8•<ý¢½Bbô{E½Xh73k6wÍþB¥‹bwÞ!¨° ‚Zä™ßÕJ#]*cOzz“F/–¢KozsŸ0F}:ÀªM—*ÂîÝŽ&Û€¼©N¼¶xm*̸ñl ²m!Ì·M^æXnìã¤âN–qDÝÎÅ ºöøgœÝ¸² œÌ`ú£ ÔÎ’Þò’×|SQÈ´™¬†›ðЅ޲*×ä̈^Åálaž~~‰`îéåãŒRcgÆ6Õ] ½ÝVr„»Í`ñÄæˆ3AB[1çî‰%øŸP®ËÍÚ²ý«Øö !sÔ ”ùVýnà*ÏÍ  ž‘‚,w×E¨Ò!åÃ%+–ki+F•cÛd+EåàŠm²-3QOÊ!˜»‚“Æ-['~ME¨#°Ç.ûæŽXSÆ;îQUĵ»iºJ û”Id‰n·PW`<ýGo gÖtÝ   cDÕQ4Îd}®{ËIQI@Œhó·\LqÓQÓУtÌ£ÓòM=ÔQ®0€CÀzƒ ÆE…ÙŠê•ai•9=­bÛ•ïÌÒ°ö5pªk±‚ˆìÂ1@evü?š@¦:D„ÎøêéÛn×T÷ÓÞî˜æ@V-ÔŸÆ·™ðìiO›vY5=kj¡šbÍ ý°›øÍ…ã‚L¥Tpq½‰UU1ËŽåN‰˜4KXÎ 3½‹p†(|g¥æeÎò5ULiakå옴^G¸rWXÃ¥—ذ’6,(øKzÍ qcV4ë@%Ai2m,Z‹ýÈï§Ö#®ª¾!IsZ‰K†¤Þ"ZÕ[«¢Þ&3‰žR¯‰&γ—ÔËUÔdÈA½$¨÷ÔZ9„Š,ÎÁ#ê•ÓØ»Ô[…j~fêWø¡)B3…3óZMTaTËŽÀ™¤s`>éà"­ž!îí¢ Ãò¸,2äb$õ¨7^=Ï\/µ" …j#ýÉ9kü”Ru¶ë¤7Uõ\_š0'ÅÝã:FW†(yKs“üMzÛÖ4.:5¿d/󿛑ôKJó œ|L¡3Ùp¤0è4Þ29°/û㦳 }Ow ©ä©ÁÖ^¸x;È+Fâ·«I–C`\ù‹² ¡ Ýt\(º"Å ƒW“¸sŒú§º9øåpØSk›]ÙÁ6ˆ}„CNï`è0 $’аá÷Û£ÊÂÓ $aà²%à0·ìÚ>Å5æMê‰4 Lâ,â` Š15=N­U²SÉâ,ZîŸ4_&m—Ä ;ù)äþ6;N˜A` Boâ´yj… ˆ‹ÁqO_® b^ûÈp©O.‚wî&U\Õ|äªU@TÆ©`Ù“Þj­pÜZb§F}Ã<¤þÌzzÄäÚ5¥°§†8ºhîYV_¥YTW¡³„bZVe{ý‡ð§DZy'¡³É¨ÖâzÓÏö&”Ñ«´w8•ŸqÓUÚm¦#¶ûÓøÛ9Ô|(›‰ìB0²•¨T~€ÚˆÈëj¨‡Î*KÚå£, Wž0Œb•„&|ß®hrp•MmS†Õ2ª;ªUðð )š“ÆuÆgôlÏP°ƒM¬€ZõÐkX¯‡›ª™>*a±A)Éø×¹SK/º%~†Ø ²Aa®0Ÿ@ .^Œu,<¾¡®/憉q¢5×ò IÈ®çËI0Àbø†J]Y<î9 ÄÀxñ4n¸åÆlm¯ÄŽx,˜9È£¥È¬6K¸TkÿÒ[·YõŒøº’¥C©O–&Hcà ÆãBD •QN©--§ jsàhÞZ'ð‰{˹ožÎV’˜IçåAIŒPPWíÐêê¨ßüOHÔê7ÿEµjiØ‘Ôm³Ýj’u WÿS%Ëi9¹öujíÚ­‚uº›EOš»{³ê˜C$rGÄÖt²Õî"yP_EOOK‰´Ä)èB`².oD¼?mÿ[-ÂÊV $ L <­§u<÷¨f4•‰YĪÏþ7Ë7v±ÔçY”¼¶®ò¨Â­ù¹‰µKbÉ+…©2a](å&PµÁ’Ô®Rš¾Éî-ºC„«¯ÙÓ›cMÂñÄÖHfoôè–Iè&=Un,³ÂdJVfO›Él‹ûÜóýÌZw£NæÁÌÞ<{AÁîøã^YªUª¬Šˆ AègM•Ó¿žŽF kÄsê“®^ùòÅÑ2„cvp´$¸N8G ûYÁ;ôøœ“ &LO‚9Ó›FQšã+µCÌ­dq5+]’tÄò‰™#ó\"§/+g.7j7gqõÏEsØpÈ DǦ  gqf¢cS_EO+Yœ`¤+Â>Îâ¢3)ˆX\BTÖÙY܈jc[OY\¡¯õ¿Gp·Qð06Qۤ–©JÁ€›K˜Š¦…‹Ÿ:€J¾’Uc›ôI…i1xÃt0mÒär@D´Óv+‰6ÅžŠZ¬)¯8Ô<›\Ι÷rÙÚÑ>×!åç4g²ûe¢ÇЉM×£”«=ëDP@¼4„ï[ =—*D d_@gWE„"M”¿®| 2p6i‘hžz ÙwÎŬ¿8xQˆèø}eKc“Ö‡s»{8oUÀ M“8¢&»V VAÉ]=‘Ç`T—êUV¯÷ˆ‹è€ë…J®·Ieâ+•k55Ò›:PM 7è‘ÏŸQAae I’-C¢å¢éšeÁ:°t¦@ .¸’Oš¾©hv)‰3¦ºæË¥è†kz‘ó­ <+ì¾Ü  %D,eÚÓÄŠfäও#ôD–ÓËË£GD=]÷3ˆ&Õ ðoóp·V›©£=•D¶øêW<=óÖݨÖßl̬kõd÷%r²;|oH«N1 =ºûnX¸í¿ nÿ*ª6ýKz¶Kí zû’6vÉj´»EׄâÝéÉVáGèrþ(ð»w5D¥9Ä›¦Ž– Ó+r~̼M+%}4'ß…¤8‹âw&cNDp¤E7Õ"~SʸïÃŽè~ÃÃ.I¼«é½ÛOÒÐÎ<ÅÄ5w§ ÂlÂÝ|­:Å­QÈíšöÓÉJNÆÏPsˆY˜w\²ž1'摇¹2§ vEÏÙ™ÊBåzZ®«\ïÅîë9øo(Ô¼=fõ÷–ItKéáLÆ}¡LL)Eܽü\eʱÜ+J‘†òÏÿøÛ…'dJ'CúïchÜäøA¤ÌÙìCêRj¶Yyºœ›¨.Žg$@0€²pøB8Œ&‡£^$¶X¤ð÷X¶Jˆˆ¯¨dÏ`$ù‹¡•j€§D‰ ÆGò³p6’ß>–\¾¡0Jq+O¨î7Tw)Õ‰ ¶ .&;O6žÂßèÛ¼ü˜|=+ê¦0AxÔ©^Øw4/5•Y°ÒäÊP’¥^瀯B—¸¤a8|Áú£IØ‚i/2ç|ÏY×ËN7#Ì4ed²8óÃêâBf«öœ/ýО÷-»C²ÌDOhŠE-èŠÓD‚fœÃF§{®JĮÕ¸-ý¼þišÃ\Z~k½U£kºGŸ§™áTW2b„,DŸXp‚„®axë+6ÏRš¼@ìà¼7ö&åÞx/ákéÙ*{ÎSš“<`6'‡0¥„ÈyÈ7Ì([%„PoÁª§§h•‹G9:s´¢F’@.»„Ö”wùºåã³´½w–Ì,kg©ã”„äÌÜâ]dEIw›Ï΄C•‹+:Ü›_~ý59o0&%¯?.úùˆ¥çDÆ ö?êß’pH‡·øÂ÷©²Í¾€t½-üÂÿ`‘þËö?²ïuóòæŽüÓÝ‚ñ·ù‚ïŸ,öd8ÊÍõFŒÔ‰†¨ÆÒQ†KWrï?g÷µ€5áü§šSÒ:—£¸U7Õ¸æÿ¾š×VÊB¶ü‡äÕ¨þ¨s‹Ìa‚§4ˆŠf'Ž4´¼N¨Œg./Ó`†®‘jÂ9Ï"–~·|žv+›WµÇÕO¢ªí_ûøÎ™µ¸{¸Ý¥è"¨åƒ½èM æ G®NÓÕˆ)i ŽI£sÖ×bg¤Q½Ô™+©YßþÒ"÷y‘œ\–Õ†’ïFn 8=0ŸŽ Ú‰R„yÕÇÓíD1}´ÁqärºSžÖ6j*_gÿ²yùTè©}©¥UóéáÆÌD[¶ªŽ›šS[_cåÇqD:¾\Äþ¥G$&–G¤mBQÍ=~õrTf ,A7±û3¢A÷zÇóŽrBbA]H ¥i¹”vVZûUó«íZà ?žƒÓ‘;ùY1Tm1俌³ð9›{{CJilŽEáø¥²â/o*™ÒwãqE 5ýdõ/E4ù/¹=µo°¥DSñˆjUcÿ»ÉîÖe@"²ç̦øE¡°¶|2‘íËh"A´5LM¤þXÑu|Ûe'ç.ÔþŒÐ;sžóM-rLÔ¾á:))ÜÔá üžÒ¬,™EWe‘_)œyQ¾ Û@PBq”S=LSóœ/EßHR"Ò‡ÈN¥uPí`ÎTúQyÒË-§›#ÛèBÂ9WƒHhR…>"9]WÎ( c9EJC’GúLÚ¨lÉØÁ ?ºŽß;p6/¥8¥¾ô4f7µËâ™jÌ¥l5E®”¬RÛB;ï\•¥¯—Z:Zõ8×»r9ý V¾ûå%ÈOjÂ5RvWÕ¬ò_²mÍ  fAÛÑÚìÏÿœŽ‘‚˜±Å>ákIèñ®61]–»µÜ® €%åt#Œä¦«,E\‰Ù@°p•2bD9GXÝ –ˆ.®¤êºÊ‰›¨„9\×á­FlŠ \Rï$­ûUÂ%Ñ“¢u6ÎÞö…K_nÜÖàæÄâ Ìx°÷Fy¹E-E¯35áHYÐ%wøŠ¸ëU·å€±+{#îJÜû ˜îÔ{!·¥Ö«8-r$V7O8ŠÅÛ²4¬E…ö¤ï€HP|Ç^ÞC¸Ka‚éL[·%zs7yÌX…³a'ÙA—‚dÛèn(Ç{à´mUpÐehŒ ¶’-$ŽY=(ü쥡eŸÎTô„”¡*¬xmöæ†ÙVØê8PÐvû²©Ä‘eeí@ªpj×1ÿq(±Ò±#‹ KªA ;Ñöü7’TiƯ¸ëÐÀÙ°¢C®ø ê ­WaEŒD÷¤dB³Ԧб24,VÝqwöÅšv‡%ÞXü¤58-¬<°m¿Iǽ ãí2ž­´'‰ôpŒN]xa€v“³ˆö$o&¤O+ÏvµÏ$^L '±8´ž€`ÑŠow‰å‚˜µÙM>Úù>¸éÇ‘ÏÕp[‰ÈÜ»uÝ„•Šh]­U@XWƒEOÍü¡…F{%U‡ ïÿaÄ¢€c¶.j¦$´ß*ˆÎИ/þïþ›‚ßÊzÐúîå·œ~UføIAµ?ñé¡7åf~ß#ü‡·Ì!oÉM¶‡]ÖoÒ¸]ŽÆoþí@˜©ïí·ðRëa~-úI~ùŸ º(SÐ¥'#v¼‡@"¡¢LÍH¤µ Si°èI¸Z“qn”2k£æÌÚ<€Ü›‡•T™®è1Íà`pÀ–¨†óÉÓ…óQÐݱKbÛ¬_¥yŸæ¼;x*;ÿ¡²yfÿ‚}™.‚æXã1v]„ì G¥mXjBT¦I:GlÅØ_,}0öõ_J¾ÞbMA‘NÊ1ŒÛAÀÅìîY®ãy¢A2+ÍS²YD˜óÔ Ô1ÄõDŽюij5buUÂÿ™Óã¬ßCÄì b•Ž”C8rÑ¡ª¯¢§§ÌNÜæˆÈÖaº¡ÃWÑw_—A˜@ƒèÆš±¼ú& L`ÖÓc.ôÉa¹ÄøÐ±ü±cÙßàã:%¿ZÒÑk¹?T¢QîÉ 6Ò´³ 2­>¯E‰pnJÅX&WÑȹW”nkOpœÍ™-ãšêïR#”¢‘E¬ÏP.ñQH£[j¼Šj­Hšj%ÞðhÊ„®UϨð*7ChòRþTÃFÅ@¤bSŽÆSâUYpíɱ†„ž$H5[õÄ›0ßI•UÄKcSWñª0X$®ñv ÕlźŠxÖzzD¼í]%ü‹Ä+×üŽçEvâ}S½<ç#.w8ê T,Âa/tŸŽ"·EÖªr øŒ`QF«Ä¿d`w™#H0…0?t_œ»œN¿×“ U¼M ­Ÿ«N±<(^ýíää’ƒ ‚2yµ‚a[¡Ö¶T}EȰØmØik&]¬VO‡òn€ÒÏ¥·µÂäFºn Ö®•CÖ,zZE­Šû íI`8«¥‚À"Î^ Í®UQk‹žQ+QÂ÷.µVmÒHƒïµ…ŸÂj‹Åf´`umRðžQ (ÁLaùÀ6–§jUÚe;X¥<¿<šQ­p‡šé/H̆V#^x&¼Š§QwŒInV}¬W9œ•Ok¡L™þzMŠ*[p>OÀÂF¢PÉÝ»Wµjoᢠˆ)æ‡*v¡mT°4õew‡«ø“"¯z˜™‰Ó çO‚„ [9-ŽÐÎ*ÊÔ¥ž\Qż,Ô-eeÞvÕYÂ~ÇîV+Ôƒë†A¥¸hPÀÅCȱ‘ã…¡=¨˜¦NR¶Õ‡ìµ…¾ˆ/­(›±È©L!­S^ÕâWá9.)2€º’ªFf¡!„@ê›T`ìA^{hÛ”5ªè &ÝÊæ7k u¬Üœû6ªL8}Ó¦àзQ­ò:¯v³+Ò@mTÁB ïÓÆÎ_îŠtG…¢}W²4ô'W)k·ÄDZVÞHŽ颴²b‚,!YùÄU±sÏûÚ|CÐÄZ‰Žp±¿è zéF‚Ìþ;ªeÎM\!YV3c© 9qi‘’Aæð­½]î´³4=¶#¡Íh—$ Ã)»sÍz}N42ó¤ˆzeÛ%¢æ­W"Še1¬¨w³»lå´aóbõŠ•åÀBä¾s½EŽ\µZ­G (0䌘vðCì¬Ë‡H鼂OÄ™£‘LÒ-Üû™”Ñ=м¼u¿¬ˆ[’è&.I¬|’§"5¼ ¸³ävTQ¯hå³$ =‰J×X´f´ÕZ|·jý­š‡|Ó³ž4û^0ÈLQÐnæd¹è©›Õ Ö@—`Ê~Æ­Kz-X¸ò] u7k`Ët7rj…ÕdbZ¼/!„ÿŒ„bæv¬ëi„&…ycŽ=žU~×L2‘hH'J´{ÎÝŽ­Yá´5Ú‡±ùÌsžvšm¸„x5ˆøJí ŒÌϵ:$¹k=±1’tjùS4—½¼‚êÌ.Zz­H ”ÃÓir ã 4wo1¢˜|&È_‡SÛ€6øŠ«ñ:^ƒVLÜâBtàˆb+Ô±·Œª÷'PÅV$.6ê…ÜÖFU,dÚØ÷…é©BF¾f«šãÄ>軽‚ëL$Ε»7w¨¨ò[d+– âÇŠóUOí~þž _,¹©Çd­d»ö;Ÿ EG…ïi‘ ¢Ü+AZ«„|¿Ð“m¾©?„³ã>ÿ•´>m\È«û¦™,ô¤™Üã;Í’ÛIVãù%K†Þ‰ÍÉɰ|ÇÒDÏÚìuÌ}Ì2¤žºŒ'”°Yè ‚@(dž6NA|ܳvOOˆ©/mV ïk8jLcÎyæƒÑÐMÌœáÆíÖ³ ™Þ½ä:ÏëÛ*j£G*ø¥­Q|E}§“qV´GÞ¬ íÖ*‡K;âh£9‘JÀ9vE7[‹gdë§;bÔŠvyϰâz‘PSĭ°ð γGd#ðL8ÊÓ]ÐcR¿ž¶¶ÓòX¿žpoøbUDL Û0„ö"HFÂᨰ”B›R­™Ñ­ìF„¢Äþ¢>îðc¿ì5H*]»5›ä#¾n!0’3˜¶‚¤á|NxÇ`à±=Í“´FߊqÛ7ˆŒy£@Œis[ªL<ÕüÁ áIB°¼í­è( X7lþ¥*Üzþµ?8 â˜é W1ïÙ {Kf W(3´QEõzñ…URö‚ìUIÞÓÄ ÿ¦=ÚÈVX<”šú„ÙùÃÕi{%Ž´ñpà„Qut±Ê˜ º!ÁWÞ8EsA)7€HܰʦfSгù Œÿa,`îõÑ›‚¥¥Œ)MNcjêÒ©%„à;f¦—º-ú¯‚Ô25•«yReÝôŰÚ*\VwdB齦¨lúLÚñ)¦sÁÔ)Rm‚ekía¶^uÍ×)’GÅœôÜŒÞÐÎÀNmXMQþÀ35rÓjXY¥$û2˜ÀBkgOÝr¨àÚøŽÔhK²j riM±3ufñ !¤´/LUm¹ÚÚPJYñÉÍÚ=¥iymbWbÌB Ñ¥Í5'¦Òܶ#×äMC£ºgþ?öC„f?w»VÒì~ÚEïJF/”Éèí¶af¡Ïþ¥¢ù/ùe$¿oÆ×#ƒùU«{zO3šo_ºÜy÷ U“î_<É!‡®œÿOóq"œ¼ùõלªŽ¹ró'v¢]Úm…=ä=©§¢ú§“«/ïVN«&^³Ê=‹}Þ¼ÔM„Zþô®ÃÂ5€ì¥»ó·P«»ü¤ºÍ9½_(‘Ç6/ù1’Êo:Ô.H?®§â(ìf=Žn+¤\¢T™&OxÇó H»0›Ú˜0àõzOnSÊ…7 T¢—§‘Aø|TƒŒzI5Î{{ŒÃ!Œ^ÆË*1G’Ìm €ÈûÛ`ÑSA,—ùUQ9ͬüsJàœy]A?KûœXÍŒq{† «Önì•=·«  ^·Cb "½Õ!ò·ÒZ%Dšë¸BEÝ‘ìsÿXÿfPz±ñYÄÂTèvÁ$½°@úKÈèȵ…yoÐÑ”/tdÄòôÇ…D_²ã/ ÔÎð‘ñY¯åÆp>K%+ª;+âŸûŸ,mZq?°öÀ"“Ò X‰ÅÀˆ«@g%AÑËäæ“f<¢gž)‹XZÒ!:7>ŠêZ#05¤²û[Â\ –= Qkl ;¿³Ö9*'ÚfÖæ¡kMwæÑŸ[?{â»Î/–3&̽às¶bçKôR–Ò†ô*¹\IõÇ»*©XwÒ5«HóÒ²hQleÄë4¡f/.½žDГHô2'‘õúǨ¹¡c›£.Dd„å“IÄ!#ÔdOkIDˆif­Ñˉ¼aX òÕüŸhxE"x=nä‹W`¸Ú2Ky‰dÓÍëÍ„VµÍF4kL=áÐ<Œæìó£3‚`›Üq“›TÍ®ø½Q¢-°fòúŠ_Vº½òCG(NžÓ®ÑÚ¨Z•Ávߌè¢ùfóS¾GÿÛóBb-DK\tp]D×mý$pÖOf]?-=°}Ù‚ Øx마ˆ‚ç°s‚ºdqPÌ ‡ÀÓ Â=%w5W«‚ pg=ME^§€$ŬâòDârÒåP‰{‰÷! ÒäeåddUEýÝDÐm_Pƒ×e“âpzj”y_Cè‰ÑX{‡«’ 8àŽ, .§Bw\²UñLãäÄij •1Tã_&®c<Ñò0Ê“Aî˜|¼VX†î¸ñScÒ0«8±Ú1;ü¿(À-f%0¹óA±ô¨XçgÊGX×ÓÆ†Qª‡*zLN4©…}ꎱîű͵B "<¾NíÒxûSjþ{Ý)ÍFO·bÂG@” ¥vNcJÝI È謪]p\U·ð¦ÚøyÓóŽÆŸõáR?íñXÝàñõÓ4öØYÿiA]“xJ3HÈÕQÖ MÓÐ-ÆW³+ŒV ÑÔí÷|¿.¨›íQ½~ÊL„ï˜IëiÊTz¥¾É<Ey;Bš3¯ßŠtÈãÚ7þ™‚ôòù÷ŸÐ‚³ÎÌD‘¥g \iÌdSê¦$‡¤k[5 +Pô2WpžÝ…Q„IÃâCÃO)t㉲™D ŽC6¤Mµþhæ2ëI›¼ZžµÎQsfm@îÍÃNÄtE‘­¬¶Àóâ=œ…¦¿R‡þ"-Ó¹@(å'o¼TµŒº óë&>ÒÑýwQžè­ÖÑ|§uãð³R"A.×Îçñ¢ÔïÞÝ7Õ6Ãgk½çaÅqw•ÅæEùýÆ®sÄ—pÏÓ,.%Æ8€T3¯=@6zÊ®%¹¤DÅŒðj qO˜^áÚç(F&_ó"v=i׋¬žOô"KœSùìqpLÁÑ8¹W‚ ˆf´-$4¡#‚ª´M\ã&·XÿŽhÿÆÊ qqÙ¸*Ns _}§·q€i;æ­Ÿîˆ 0¤µ†ådcC"¸5E†ÕÙ ¼Ó0sN÷r'4å¹v «Tµ† Tk-¦ 2™m3•G-ų¬x°ÝiÄy0üìÑ$Z]‚²—U è‘P§¨†Ê?H$ÆË> ˆØGÐÞ,l§µhÅ]쀈M{zÆ>ŒZ)ݰlB·…cÕs¬G®P=ýàZõJSAïp¯ØöåþÑM?€¨ˆÒM Wo‹80f±ÌÞÂ;§9™q/ƒ*ÎÓ9}œ˜NÍÇYLÀÔJÚ­9b¶šÀä4ǬcŽ:ÍcˆŸæ€©ÝLùBG6Afo’ˆl”ƒ!y訦JgÐéˆ&+¾ê'rÚË—'òr´œ‡èõÇ1ÃCDÇ QªŠ§D¯· HˆÁqOBáq,æÙz´QÙ¶6êæ¡ó\sËžŸ§8£d+,ŠcL’XIéŸi\Ä8Jäæqzä’ªóó>Õü»ïÒ‘™‘oŽVÇk¤¤óÛ”$Î^ØD '‚•1[>p>C6[õ¸HXëé..°¶?.xdq\íðKqAÖ£'…p…^å‚á|(À&£ÌJ”ô/lãu(zyÂ${¯!!LÒØð`éÌs¯,3E ¨©“­À…&wÖÓ#\(Ñ#´8ò–‚—8c¨Ã³¬NÏŽEe6üX$EyZêè»ùú7[K³X“2¦ûsA“FpCèd;’ÆôHOtß7{ùgê¶'¡”´¼ð¬’É ­“¯)]@–×b¥ÀPw7%ªËà›·^ÿáÖºø£\c=ÄÅæIмÀ‹LÖ˜B„Ü`X«g¦aqÆÅæ¬1¤ †8¤F(]}¾SÔ’³™ I¸Ý™Â kmG5*m7N-¦ë3*>B]eô ’x¥pÀª²ÔGÔUC×8´1jm[­W%imDè qÊ7|hc4,›Á˽*üî4* ô,ô6—nóƾ1’pº²›æ€îßZלIhBH°œP 7¯†NŸ Š^žÂÒ"šºä¶§Þ ‡0zƒ(gùt­22 ²§GÇW †"åc)9Iy?G!¢IHæN=|ˆÄ¦´??`Æx&BÃó1ðåà är·Ñ+ ·¸Er\xd`*aDå UÉ͵½Ï‡ïl©÷\Asy$öQœÔP<(ÜBÓõ° =ó­4(ª ú•o¦ô#.®á’\ªRŠÒ² A p2;Åv<9‹Â-ÉÈíTÏ:OñíüË®‹ãfP¢¨J Ù~CD‰T~ÃãÂu©ˆønêdÂlUÏù̼íJ>C#ƒjvð¿.ΉÝñ l s]É€!<$n÷\WT[‡z[Íb™~j5õ6O“òî;€ôÄiû¸¶X µ§ÉŒ!Öegö)ï|aß:Hœ&·‹oÂ2Lç’ž¦ªDpï4ÁTzRYpJ—ð+óÔœM8 p>9Mc¥æ±» .¸›&–U{ºF%U¬ÄÖÒ5Ÿ‘û˜Grõ?¨ûŒr±ã^çARÌü#Ê1ÅN&+f¯«7°70Ì_úH♣fÚH4…gÓU´­ÛdôÈé â^ G(eØ@4 _”†ä#L®¼t³Ðt,(¸¸çr§§"ÅS^P³®T‰O¨ký£IR#(닼O w·’på…—¶) ¢Ý-ˆx›yŸªUB˜SÁô„‹zÒÂW{ŸÆ­Q<Ú¨ÞßÎ#T˜Þ6ëõ˜&ÄÈ”[ µºh éÜ­ˆ¤VU„2 ´pkÜÿ¡œOuV3Jÿ²QV±õ I±5®'?c#$LÊ}﬌hèÇS²Nd‘üèºåèè737*ÙLA4Zu²rFœ#U–ñ ç¨{cˆ$F[‰·óCõô.Ckè„ÚoŠjâ$Û± [Åäp¿ªhêâ3ö RÒc²ÑÓ=¨ŒaEÙ›–SP{Sj{~¬]œ/éŸc ”Äíkª›úÉÑ©ŸçXJ*šÜÁðœ‚Xë§z§±Žróꎋ¥ „–¹¡öº ŒJfëf¢†n­ÂF6Xô”’ré>TYêñV°õÈeÏÇÑ1FIñ†Ùx8´NßsIy™ÚôéúvRè›æ=ÒÉÄ!ƒs«~'‘ ܽçý÷.÷VTù†UmUu>“†yzYº&ò eJš¥|âø‹t%Ãy¦èQê£N¤”‘¾ç²NU”ç©×cJ&ÂQ5¡¥aåÈ©ÊdAÐÉk+™M ‹dÄa\7´ëojrP* .~53+¸‡Ãazf×ÁÑzÓµ~zXœ©‘í¤a™zA±'Ôs†Áóaƒ%÷ ¶ªœ2ª55ÁlX£iëb÷/Áê”*Íìr6¨;^|q`éTˆÊ <Šà¨fÿA¸e~—‚üÀxOÝbƒ»=è @1Ÿa= °p)JZ?Çñ Ã~VFÈœB(ʬA÷øgª—¡$éjï°­²&ÑçºÕ2÷X§Yu£ŽTGÃ0î qÊ ¡{0!{×R‹dÀ=HÝd)(Þò^ˆÍ[¯ÄŽưèHhü§*œ¯a™¢ì{qXé_W ‚ezVgbÔšI;vØbÕ_Syyä##È<*|`áû„‰¹%Œb߉ÃeÛ€ùJ š­¿Pur»;öl» sP+s³°÷¾½`É(S¾€€˜Ý0o÷FÕ©z´Öü5êæ!B˜õ”|xù.HØÿÐ+U¢@çfR‹Ýþß|W6\>õúÅT Ô؃iVKÈ~iÿä&YéÁÔ›h‚‰ôSuê`:q“Ö~¸^=íãöc%Ï8Íš•ómʃAÜ.*Û­àƒP|Æ WSAö»€©”o W»åÅà£p”È“ †”B~©ÁQ‡/D¾ Ôõ&º£¨;Š‚ ’?ì#BÅÕJ£kHïæ ÃO¨jï\-D¨ê?3ûˆi®ÂtA]æåþ´¡K ¿Â_€cyâ"y W2‘¼B$Â>»]í¯„•7Þt 9÷’*RX!#l6DMDÊTePú‚CêñxqCùžlT¦Oñ`â†,{ܸ˜¡yÚ  +Âi„œ÷™ X0˜aÂpžûwŒmYgÁXçBMñCÔ‘¥Q«òÏÇ÷«¹ûì¦-iKɦ¢Ø™á æW ½Vçhˆ†ÐQ‚˜Ý¼·UÌåB@lÏ3’C×$~ª¥,¹P!»1ÓÒ¦ûR/´5˜ª”ØÖñÞçᣟèý²Ècµ&عo èåËÞÉ”¸S.‡P´K8f„öiS Sj„¿t¿®•Cw,z2JG—_—%œíqÞþ”™pèæ==¢1¹ s½Î–•Ÿ@êRš0¤Í3 (‹3oÝËìþL^kÜsðçþj‚´D/œ3ãM†c2?•¾„×ZÁfP(Ñ%¦*X,§wTPlõŠx¹Òá8ü§T˜´Ú$ÝTyóŠ;@ê¾D¯ÝDìëöÄS;DM0¾PïøªT£Ó‹LÚÁ³ê݈ŠGcd» ¨Ê½¢#4e蜑‚b‘m²Ðx_>HílrŒ.Æ©ùR-Á?(¡å‘gïʬ5ˆ’Æ–£­€Ñ Y:¥– ÝŸRô§”­×ÚÚ‘`rJ£—ŸžÓŸ”ÍÄ1ä5íΦAúÓÊÃ+æ×k­2>­ÑÓŸÖŸ2“ñiífÒ{özéÜN«‚6!þ4§5·QÇAgæ õœd¶äŽVI)WèžÏt>t8(Zd‚ç¯&€/±F¢³FO…±sdD?£ñ¦©¶Y‹HOQxªkWn¨‡Å3´û¹)ЦyžcëÞ £¬Úð¦ÃÚ–¬klšVl oéî»ÍjÔˆI=Ý›R­eaJðN\ÝÔ|Ê=¸Á»äüî÷ ÛÙÄ×TccV¡YåYåHÝi¦EJÄ“yN 7ƒ’ÎЉ öÈ™rÅÍ#‡9‹ÐwÒrå®!Þ»‘Ÿ¥·xy' “^ñ"DÔd˜'¥Ä ‚꼜à$%ú…õP»IŸ@ÈšVLü†2Fåì`å¤ýQDS¤©ãÄIc)JÐÀà}7„åwÅTPÀPñÍ\пiÖ?Ũ”LtŠïéÜ(óˆën&¹WÏÀä½’™¥I&H?³ÆA¬w9†¶™gŠÍ[š£w,ªø 2].Æ…â&_½oÙ¤¿€Ü ³¿d¡Œ*qQÕ*¥¹>¸+‰ëjhdeм4RåF>àS‡Ý§Uô#?ÎQÙcûRÎÐü¢fU½}ÎFµ8ÔŸùû¾ù¢”ÊzÝŽ ¡ÿ@íh]]AðãОøjk5­5œ_?Ó¸kù÷ ® ĘŒ¨£¥/ºÕa¢û@sòÕô9b—@ Ad}ƒQ‹Ñ/ªÄŠ Xëé‹"uÚ99gÌ•¤Òj6À‡×˜R`æw«&`B²BoêEœku®ú›L!z{Û¬F\N¡Î¤?€÷æ›ÿÄÉ©W|tNBø¶Q|Iq˜Þ÷U œµŒ~gF˜®•;Ê?þC|Z€¢°ŠʱiT¾Vs74”dz§½èH\wƒ:*ç°Ä‰¨E[Ô[n#êiÉÕÓÃÜp”aÇÃ}DYÃ+,ŠÃ Ìe(N°‹Ýäų¶OY­¶Õ_i¼Á%ígȉÉ0†×®œ?½ oüš”£Üï~Ma]B¯t:}'nYmÆ9€o´õøðz‹^ýê1ÐgôfžRËèMœd«†%‰ŒiO‰“¥ø¸˜aÉ–>7^~.ýo’ªô“ô?_£»¨¬öÑB¨r–ë2>'åÒñÆ’<0,”·ÈLñ„(yä·Ú×N¹ ø¦t¹ˆ”t©3€ »²³Ü;!&AT’äzé„ÊÓeŸT—€®xâqAéÍ+¢2~dëö÷÷ &a7p1–N‰Àâ±ãô*¯†`1n4§É» vz%GÄO:5ÔEYª;müTRõ9P²Öp?ù¥Õiâ9o…¯QƒHîÒ¨Š7kT rî#˜µfÎÆÈåO|üÎw«?‘é B!Õ‘ê ›Ê&¼),«zÎ~(Ñlbu¦ ÍE+=Ý 1ònxÜdüư3À.h:vñA|*~3B7¾°¶r)Ð 5f1µææ‰ã<†è&A_=,\âþâ@¤o‰¡[-Åû­²õÍ R«ˆ ݤÐñ!ä@δõZß2ž\½)F´Ì¬TOÉR- k<ÇU ;•ºŽÿV €ºyd¤¸ÐºhâþθYqZL,÷³ëþ)GKŒ¹Zªº:ãµ? £vÆn¨q4•ÊÃYaHU|J7(S‚²ÁÉà&ÔBãUr&ǹŸY~4'ø1º,y[6Ax¦ÝMÑFª”䄿qÙZ¦Ùzžø!-B3MFö)tÂÓ.è6ð'Õ¬öó¢T³îËqL‰’B |+}_ÁU²Q”9'bV6îg}'†'ËXÉ\ ­ŸîŒ;`Héóaáƒ<Ë©ùí@Ö(B¼KÙtTfװʳ€âÝ3iͤkgs½äáG0¹ˆn!ÕfI«3eÙàú—ñ‡EÏë— " ›ë8šôKH&¦HbHÆ%É&›a6¶íŠÆ+¯îé“$Œåû]ɨŠ!ù¨Ì‰÷}ìîžîIiTs(Xu|„6ñ‘ikߘ°*z   6†T‘€þ"'×–-ˆªò8˜;þÝ5 L¿Np{²9Tgª£’¼|‡áS'ƒ=Ž$á±€õ@üËö#ZÄomFߨýr»M§Ý7[u D$éÑo‘ˆÿFýáà8wˆïí7“™ô`TÈÄÿ`¶ê»ñ!•LZwã-Ï¥šïƒñï“…X{Í…dW[qC=Nté QÇ<ÑÅ=mÒ&×ÝCÂ>Wê¢n1#cÒ›$—æ2GÕprìùLÌ3î± zzCñ…ø& `%Úqû=Ú­äÖ)fåܲñ2“š3•£1Nh‚Ä‘fM!=ÔzƲ=¼¶ZR¡ãx‡úÒ¢xߊ´MÜžR‚µܵ&BжM5r ví0Γ4p´e¶Ö÷cÔôévøÌ˜†DùWV’¶5¢M í‚#¢\l èså&ƒK®QÓðÅ®*!CCó…éÄùVð.’ÿ R‹%æ^ï®ë.<\ÛÁl(¢C0ƒûeÒi´ÀxíïÈy`ÃȃÖ.«ÖOwÄÅ9X¶„γèÐX[Ÿ6A±|O€!´ &$(dÜöÍ’²\êñ*± Ér[–:“Gfªl*ÉrKF ‚éVT|5¹Mþ³‘úGTUòýêÆRë§Û"B‘7ø°JÞµ°˜ž ƒld?»¼!•{ UòÝȇºÓÆë‰e®ä›Êþ•ýÔ‚N¡»ËR6œŽí¹5û̲º­TÂw[*Ú¬c-›¢yÓ§":Ñ4¨óÚΪ=¶Ö&íÝô)ØÀyÌÛ:™„f#W‰qÓc }ÜŸº9=†¹óÅaÒnôtYm Â,¨4¾¥ã<´×t"Íð+G{VÙ@©ãk”_%ˆi4ࢎ3 " 1Îö¥ãh}.ÒúÜ( .ìjêiT¹\â ZŽ_ÙÌó\ËÉÜï#ŠŒ×òÒ£¨æ–Iº+ ›——Ð  m•Å +[u0v)¡ÕÔò¢2ЂäŒ?ŸŒ=©(‡óYâd*LÙrºí—çnƒÄöy—ÎÝ€•.R½§~H–qaH>ž}gB é1FâGÁ@¦Û>ÁØD/¦swE垦so^R™mhv‚x‚fX±m©TYR ½i¨/˜N ŸY¸S¶í` ;¡ÙÚNæà~ë7)Äôm.ˆs©ÞzZ>HÀ”Íî·)—Ý÷¡lvS—1AµMÙ}Ä.¦­»ñFã#Iß0þ#j3þ'‰¤]jûÓ¨¼M2¹cL]×C‘–ÀîÍ5^“7{tWMÈÄQäH‚(*H±‰§ ‘V†> endobj 6 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs2 188 0 R /Cs1 7 0 R >> /Font << /TT1.0 189 0 R /TT2.0 190 0 R >> /XObject << /Im58 122 0 R /Im74 154 0 R /Im52 110 0 R /Im41 88 0 R /Im45 96 0 R /Im10 26 0 R /Im54 114 0 R /Im5 16 0 R /Im89 184 0 R /Im68 142 0 R /Im49 104 0 R /Im67 140 0 R /Im44 94 0 R /Im84 174 0 R /Im7 20 0 R /Im26 58 0 R /Im70 146 0 R /Im66 138 0 R /Im15 36 0 R /Im8 22 0 R /Im53 112 0 R /Im79 164 0 R /Im42 90 0 R /Im36 78 0 R /Im2 10 0 R /Im72 150 0 R /Im32 70 0 R /Im11 28 0 R /Im17 40 0 R /Im61 128 0 R /Im60 126 0 R /Im81 168 0 R /Im90 186 0 R /Im87 180 0 R /Im88 182 0 R /Im69 144 0 R /Im80 166 0 R /Im31 68 0 R /Im40 86 0 R /Im14 34 0 R /Im27 60 0 R /Im65 136 0 R /Im6 18 0 R /Im57 120 0 R /Im43 92 0 R /Im62 130 0 R /Im71 148 0 R /Im22 50 0 R /Im25 56 0 R /Im50 106 0 R /Im29 64 0 R /Im76 158 0 R /Im18 42 0 R /Im30 66 0 R /Im33 72 0 R /Im47 100 0 R /Im34 74 0 R /Im63 132 0 R /Im83 172 0 R /Im23 52 0 R /Im9 24 0 R /Im85 176 0 R /Im37 80 0 R /Im1 8 0 R /Im3 12 0 R /Im19 44 0 R /Im16 38 0 R /Im73 152 0 R /Im48 102 0 R /Im46 98 0 R /Im51 108 0 R /Im86 178 0 R /Im13 32 0 R /Im4 14 0 R /Im82 170 0 R /Im24 54 0 R /Im59 124 0 R /Im75 156 0 R /Im56 118 0 R /Im64 134 0 R /Im21 48 0 R /Im12 30 0 R /Im20 46 0 R /Im77 160 0 R /Im55 116 0 R /Im78 162 0 R /Im35 76 0 R /Im28 62 0 R /Im38 82 0 R /Im39 84 0 R >> >> endobj 122 0 obj << /Length 123 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 192 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 123 0 obj 82 endobj 154 0 obj << /Length 155 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 194 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 155 0 obj 117 endobj 110 0 obj << /Length 111 0 R /Type /XObject /Subtype /Image /Width 113 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 196 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€¯4ø endstream endobj 111 0 obj 83 endobj 88 0 obj << /Length 89 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 198 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 89 0 obj 117 endobj 96 0 obj << /Length 97 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 200 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 97 0 obj 82 endobj 26 0 obj << /Length 27 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 202 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 27 0 obj 82 endobj 114 0 obj << /Length 115 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 204 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 115 0 obj 82 endobj 16 0 obj << /Length 17 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 206 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 17 0 obj 82 endobj 184 0 obj << /Length 185 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 208 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùSßà…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ðA  endstream endobj 185 0 obj 97 endobj 142 0 obj << /Length 143 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 210 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 143 0 obj 82 endobj 104 0 obj << /Length 105 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 212 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùSßà…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ðA  endstream endobj 105 0 obj 97 endobj 140 0 obj << /Length 141 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 214 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 141 0 obj 82 endobj 94 0 obj << /Length 95 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 216 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 95 0 obj 83 endobj 174 0 obj << /Length 175 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 218 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 175 0 obj 82 endobj 20 0 obj << /Length 21 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 220 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ ¼ P( endstream endobj 21 0 obj 113 endobj 58 0 obj << /Length 59 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 222 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 59 0 obj 82 endobj 146 0 obj << /Length 147 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 224 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 147 0 obj 82 endobj 138 0 obj << /Length 139 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 226 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 139 0 obj 117 endobj 36 0 obj << /Length 37 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 228 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 37 0 obj 82 endobj 22 0 obj << /Length 23 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 230 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 23 0 obj 82 endobj 112 0 obj << /Length 113 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 232 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 113 0 obj 82 endobj 164 0 obj << /Length 165 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 234 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 165 0 obj 82 endobj 90 0 obj << /Length 91 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 236 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùSßà…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ðA  endstream endobj 91 0 obj 97 endobj 78 0 obj << /Length 79 0 R /Type /XObject /Subtype /Image /Width 117 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 238 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm /ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€~6Ø endstream endobj 79 0 obj 85 endobj 10 0 obj << /Length 11 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 240 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 11 0 obj 82 endobj 150 0 obj << /Length 151 0 R /Type /XObject /Subtype /Image /Width 130 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 242 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Om7ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`ào`[h endstream endobj 151 0 obj 125 endobj 70 0 obj << /Length 71 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 244 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 71 0 obj 117 endobj 28 0 obj << /Length 29 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 246 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 29 0 obj 82 endobj 40 0 obj << /Length 41 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 248 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 41 0 obj 117 endobj 128 0 obj << /Length 129 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 250 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 129 0 obj 117 endobj 126 0 obj << /Length 127 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 252 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 127 0 obj 117 endobj 168 0 obj << /Length 169 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 254 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 169 0 obj 83 endobj 186 0 obj << /Length 187 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 256 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 187 0 obj 83 endobj 180 0 obj << /Length 181 0 R /Type /XObject /Subtype /Image /Width 141 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 258 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð80B endstream endobj 181 0 obj 97 endobj 182 0 obj << /Length 183 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 260 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 183 0 obj 83 endobj 144 0 obj << /Length 145 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 262 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 145 0 obj 82 endobj 166 0 obj << /Length 167 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 264 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 167 0 obj 117 endobj 68 0 obj << /Length 69 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 266 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 69 0 obj 82 endobj 86 0 obj << /Length 87 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 268 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 87 0 obj 82 endobj 34 0 obj << /Length 35 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 270 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 35 0 obj 83 endobj 60 0 obj << /Length 61 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 272 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 61 0 obj 83 endobj 136 0 obj << /Length 137 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 274 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 137 0 obj 82 endobj 18 0 obj << /Length 19 0 R /Type /XObject /Subtype /Image /Width 130 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 276 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÏÀ<ð endstream endobj 19 0 obj 92 endobj 120 0 obj << /Length 121 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 278 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 121 0 obj 117 endobj 92 0 obj << /Length 93 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 280 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ ¼ P( endstream endobj 93 0 obj 113 endobj 130 0 obj << /Length 131 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 282 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 131 0 obj 82 endobj 148 0 obj << /Length 149 0 R /Type /XObject /Subtype /Image /Width 131 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 284 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùSä…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€¯=h endstream endobj 149 0 obj 91 endobj 50 0 obj << /Length 51 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 286 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 51 0 obj 82 endobj 56 0 obj << /Length 57 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 288 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 57 0 obj 117 endobj 106 0 obj << /Length 107 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 290 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 107 0 obj 82 endobj 64 0 obj << /Length 65 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 292 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 65 0 obj 82 endobj 158 0 obj << /Length 159 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 294 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 159 0 obj 83 endobj 42 0 obj << /Length 43 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 296 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 43 0 obj 82 endobj 66 0 obj << /Length 67 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 298 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 67 0 obj 82 endobj 72 0 obj << /Length 73 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 300 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 73 0 obj 82 endobj 100 0 obj << /Length 101 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 302 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùSßà…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ðA  endstream endobj 101 0 obj 97 endobj 74 0 obj << /Length 75 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 304 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 75 0 obj 117 endobj 132 0 obj << /Length 133 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 306 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 133 0 obj 83 endobj 172 0 obj << /Length 173 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 308 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 173 0 obj 82 endobj 52 0 obj << /Length 53 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 310 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 53 0 obj 82 endobj 24 0 obj << /Length 25 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 312 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ ¼ P( endstream endobj 25 0 obj 113 endobj 176 0 obj << /Length 177 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 314 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 177 0 obj 83 endobj 80 0 obj << /Length 81 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 316 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 81 0 obj 117 endobj 8 0 obj << /Length 9 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 318 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ ¼ P( endstream endobj 9 0 obj 113 endobj 12 0 obj << /Length 13 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 320 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 13 0 obj 82 endobj 44 0 obj << /Length 45 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 322 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 45 0 obj 83 endobj 38 0 obj << /Length 39 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 324 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 39 0 obj 117 endobj 152 0 obj << /Length 153 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 326 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 153 0 obj 82 endobj 102 0 obj << /Length 103 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 328 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 103 0 obj 83 endobj 98 0 obj << /Length 99 0 R /Type /XObject /Subtype /Image /Width 130 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 330 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÏÀ<ð endstream endobj 99 0 obj 92 endobj 108 0 obj << /Length 109 0 R /Type /XObject /Subtype /Image /Width 131 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 332 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm /ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`ÀÀc`\ endstream endobj 109 0 obj 126 endobj 178 0 obj << /Length 179 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 334 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 179 0 obj 82 endobj 32 0 obj << /Length 33 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 336 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 33 0 obj 82 endobj 14 0 obj << /Length 15 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 338 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 15 0 obj 82 endobj 170 0 obj << /Length 171 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 340 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 171 0 obj 82 endobj 54 0 obj << /Length 55 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 342 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 55 0 obj 117 endobj 124 0 obj << /Length 125 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 344 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 125 0 obj 82 endobj 156 0 obj << /Length 157 0 R /Type /XObject /Subtype /Image /Width 131 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 346 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùSä…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€¯=h endstream endobj 157 0 obj 91 endobj 118 0 obj << /Length 119 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 348 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 119 0 obj 83 endobj 134 0 obj << /Length 135 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 350 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 135 0 obj 117 endobj 48 0 obj << /Length 49 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 352 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 49 0 obj 82 endobj 30 0 obj << /Length 31 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 354 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 31 0 obj 117 endobj 46 0 obj << /Length 47 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 356 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 47 0 obj 117 endobj 160 0 obj << /Length 161 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 358 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm Oˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ÿÀ4¼ endstream endobj 161 0 obj 83 endobj 116 0 obj << /Length 117 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 360 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 117 0 obj 117 endobj 162 0 obj << /Length 163 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 362 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOm ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ ¼ P( endstream endobj 163 0 obj 113 endobj 76 0 obj << /Length 77 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 364 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 77 0 obj 82 endobj 62 0 obj << /Length 63 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 366 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 63 0 obj 117 endobj 82 0 obj << /Length 83 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /Interpolate true /ColorSpace 191 0 R /SMask 368 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐàùS_à…PaÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€?04€ endstream endobj 83 0 obj 82 endobj 84 0 obj << /Length 85 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /Interpolate true /ColorSpace 191 0 R /SMask 370 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ øÀS¬ endstream endobj 85 0 obj 117 endobj 334 0 obj << /Length 335 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 335 0 obj 588 endobj 292 0 obj << /Length 293 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 293 0 obj 588 endobj 358 0 obj << /Length 359 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 359 0 obj 581 endobj 226 0 obj << /Length 227 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 227 0 obj 627 endobj 368 0 obj << /Length 369 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 369 0 obj 588 endobj 332 0 obj << /Length 333 0 R /Type /XObject /Subtype /Image /Width 131 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x홽kêPÆóuâÁ¤©‘¶!&BŠ Xã"Ò1“.¢drÒ¡…6B§ ¢ tpñcrh‹‚‹A)DÄ­Þ ©ör×ÓdÈoÉ–/†ùxÍ'~ ÿÏ»žN@à/  âAÑ0Èr\ˆGNˆãØ ¤)‚8µ'd¸ð¥‘ä(bd)"\†9òÄœåY‰Å“)1©d<¦ÈÏBp²Ù°¨$Ò™»\^CL>w—I'1ÌBê¸`xñZÍj…R¹ª#¦Z.´¬z-ò 8J !w¥¨÷ÅJ­þøl4‘b> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 207 0 obj 588 endobj 288 0 obj << /Length 289 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 289 0 obj 627 endobj 330 0 obj << /Length 331 0 R /Type /XObject /Subtype /Image /Width 130 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇóëÖ˜›Ø¦1‘¤i£C‹•¶ºdqhh#¸éЂDÚ¡2´X:8)ºÅÉBppQ:ˆPáýk/ÈÓøúÞ¯)> stream xí—¿OêPÇé+¥·EkiI›«…AƒD-K-  šˆ:uÐ LXHL L˜4 ,B"‰ÿÚë#Êó½7^hòøLít¿ýÞÓs¾ÇçÛâQ0´üû«1 Ç ’ë€$ ǰßÅ8ç“ÀOÑ2 ‹†¦ü€tT¬ŠÀ @ÁàÞ~Hè…Ðþ^R€XÕ€;–åˆr¤FQ£)YäØÀ»6à äe%v’8×’¨ÑÎ'1EæƒàÚ€‘ËËj\ÓSƵ™F‹ym¤t-®ÊòÝÿ[ƒöÀ˜Â 뻵 ë»ïÃzY Nd)¡M,å’Y F@o$¸Ñnpó@|õÍC¼´Ö/ÍCü".ø|Xe ›^èܵ–AÍr­u¯aþ´ñåþ›žíëéÀ—¡ endstream endobj 347 0 obj 591 endobj 192 0 obj << /Length 193 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 193 0 obj 588 endobj 298 0 obj << /Length 299 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 299 0 obj 588 endobj 230 0 obj << /Length 231 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 231 0 obj 588 endobj 280 0 obj << /Length 281 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혽kêP‡óuô`ÒÔHÛ!EP¬qi‹˜IQ29éÐB›B§ ¢ tpñcrh‹‚‹A)DÄíÊE­ré.ÇÃò,B†<9/¿HÞA¸œt$I’üóÁ72ž¯š¢Ž­Åx ãy¿€?Ïs>èa(êà $ Ë.Å ¬„£ÈAñ2À³Ðß§$)9ATÔp$×Eª" ߃¥È$5šHÞ¥3:b2é»d"ªJ2û¹R€¤k-¥gó…’˜R!ŸÕSÚµ$°`o¤!¥j÷¹b¹òøl¾ Å|~¬”‹¹{M½â!½Ëãäh*gTÍšUo4‘Ò¨[5³jäRQYð1[# Ø 5¡«¯V«Ýéõ‘Òë´[Ökµ¨'Ô lÓJ‚31œÌ–Më­;øŽ2ütß,³œM†Å³½ÑÃK‘Û|¥Öê¾'ö)ödüÞmÕ*ùÛˆÄ{vgôžcéƒÕŒíÙ|”ùÌÚÖC! ž{÷F¿|“)=Õ;“Ù—ã,â8_³ÉG§þTÊÜÈþ£× ³ÑÚsgµZ#dµræö°×0 =®ìôú6·:2Âí_…¦/ÍþhºX¢®×ËÅtÔo¾º\#ªéºSu³úoYr“ã&ÇMÎOpß÷íø)¿þ¿$÷×#é=2bøBÞ±oØ7üÛþûVN`oüí þ K†¿ $°·½Ñ%ì­õï†o3¿«!Ý_$ø!á endstream endobj 281 0 obj 594 endobj 266 0 obj << /Length 267 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 267 0 obj 588 endobj 340 0 obj << /Length 341 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 341 0 obj 588 endobj 268 0 obj << /Length 269 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 269 0 obj 588 endobj 286 0 obj << /Length 287 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 287 0 obj 588 endobj 194 0 obj << /Length 195 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 195 0 obj 627 endobj 366 0 obj << /Length 367 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 367 0 obj 627 endobj 296 0 obj << /Length 297 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 297 0 obj 588 endobj 328 0 obj << /Length 329 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 329 0 obj 581 endobj 278 0 obj << /Length 279 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 279 0 obj 627 endobj 316 0 obj << /Length 317 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 317 0 obj 627 endobj 246 0 obj << /Length 247 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 247 0 obj 588 endobj 256 0 obj << /Length 257 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 257 0 obj 581 endobj 200 0 obj << /Length 201 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 201 0 obj 588 endobj 228 0 obj << /Length 229 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 229 0 obj 588 endobj 204 0 obj << /Length 205 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 205 0 obj 588 endobj 364 0 obj << /Length 365 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 365 0 obj 588 endobj 254 0 obj << /Length 255 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 255 0 obj 581 endobj 294 0 obj << /Length 295 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 295 0 obj 581 endobj 326 0 obj << /Length 327 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 327 0 obj 588 endobj 276 0 obj << /Length 277 0 R /Type /XObject /Subtype /Image /Width 130 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇóëÖ˜›Ø¦1‘¤i£C‹•¶ºdqhh#¸éЂDÚ¡2´X:8)ºÅÉBppQ:ˆPáýk/ÈÓøúÞ¯)> stream x혽kêP‡óuô`ÒÔHÛ!EP¬qi‹˜IQ29éÐB›B§ ¢ tpñcrh‹‚‹A)DÄíÊE­ré.ÇÃò,B†<9/¿HÞA¸œt$I’üóÁ72ž¯š¢Ž­Åx ãy¿€?Ïs>èa(êà $ Ë.Å ¬„£ÈAñ2À³Ðß§$)9ATÔp$×Eª" ߃¥È$5šHÞ¥3:b2é»d"ªJ2û¹R€¤k-¥gó…’˜R!ŸÕSÚµ$°`o¤!¥j÷¹b¹òøl¾ Å|~¬”‹¹{M½â!½Ëãäh*gTÍšUo4‘Ò¨[5³jäRQYð1[# Ø 5¡«¯V«Ýéõ‘Òë´[Ökµ¨'Ô lÓJ‚31œÌ–Më­;øŽ2ütß,³œM†Å³½ÑÃK‘Û|¥Öê¾'ö)ödüÞmÕ*ùÛˆÄ{vgôžcéƒÕŒíÙ|”ùÌÚÖC! ž{÷F¿|“)=Õ;“Ù—ã,â8_³ÉG§þTÊÜÈþ£× ³ÑÚsgµZ#dµræö°×0 =®ìôú6·:2Âí_…¦/ÍþhºX¢®×ËÅtÔo¾º\#ªéºSu³úoYr“ã&ÇMÎOpß÷íø)¿þ¿$÷×#é=2bøBÞ±oØ7üÛþûVN`oüí þ K†¿ $°·½Ñ%ì­õï†o3¿«!Ý_$ø!á endstream endobj 313 0 obj 594 endobj 244 0 obj << /Length 245 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 245 0 obj 627 endobj 210 0 obj << /Length 211 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 211 0 obj 588 endobj 258 0 obj << /Length 259 0 R /Type /XObject /Subtype /Image /Width 141 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`C2ép‡##3 +} 3#š«€.aaeçàâææáá¥àáááææä`geAs3+7Ÿ€ˆ¨˜8ý€˜¨ˆ ?/+3Rà01³qò ŠIÉ*()«Ð(+ÊËHŠð]ƒUL¬œ|ÂR ªZz†Æ&ôFºš*rB¼¬ˆ adáà–RÖ1¶´svs÷ pwu²µ0ÔT”äfG +· ¤²ž¥³wPDtÝ@lTX€§ƒ¹¶‚¸'+<ž˜ØyEt,݃ãÒr KJéŠó³’£\L5eE¸ñÄÄÁ/©j윘SV×ÒÞA'ÐÞÖTS’ço¯¯,ÎÇO4Ìœ‚²š–Þ±9U­½“§Ï ˜6©»©<3ÒÍTMJ€î.ay]» Ô²Ö ³.YF'°tñ¼é½E‰>VZ²‚̰’†…[DÑÀ)<§®wÖ’Uë7Ð ¬]±pZWUz®œ'’cD•\£ Z&/XµiÛ:í[7,ŸÛ_Ÿꨯ Â…ä1e÷ØâöéKÖoÛ½‡^`ç–5 '7åE8 ;†•G\ÅÄ#®´cƲ ;öì§Ø»{ÛÚES[ò#œ E¸Y`ifÔ1û‡BȰp¢ÌÂ=¨²ö *ô˜‘ªƒô®Ъƒª(§b­(aMˆ„jB(!7!à«X`㪘^m«’"ì+V®ÁÓì°¹#¨A®€Ú gwU$¨«"ŽÚUa˜Nœ2öNÐ5Ò½ÁÖ½e`@êø;äôØ;þ ƒhHÖÌ¥GC€pNd endstream endobj 259 0 obj 617 endobj 324 0 obj << /Length 325 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 325 0 obj 627 endobj 310 0 obj << /Length 311 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 311 0 obj 588 endobj 220 0 obj << /Length 221 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혽kêP‡óuô`ÒÔHÛ!EP¬qi‹˜IQ29éÐB›B§ ¢ tpñcrh‹‚‹A)DÄíÊE­ré.ÇÃò,B†<9/¿HÞA¸œt$I’üóÁ72ž¯š¢Ž­Åx ãy¿€?Ïs>èa(êà $ Ë.Å ¬„£ÈAñ2À³Ðß§$)9ATÔp$×Eª" ߃¥È$5šHÞ¥3:b2é»d"ªJ2û¹R€¤k-¥gó…’˜R!ŸÕSÚµ$°`o¤!¥j÷¹b¹òøl¾ Å|~¬”‹¹{M½â!½Ëãäh*gTÍšUo4‘Ò¨[5³jäRQYð1[# Ø 5¡«¯V«Ýéõ‘Òë´[Ökµ¨'Ô lÓJ‚31œÌ–Më­;øŽ2ütß,³œM†Å³½ÑÃK‘Û|¥Öê¾'ö)ödüÞmÕ*ùÛˆÄ{vgôžcéƒÕŒíÙ|”ùÌÚÖC! ž{÷F¿|“)=Õ;“Ù—ã,â8_³ÉG§þTÊÜÈþ£× ³ÑÚsgµZ#dµræö°×0 =®ìôú6·:2Âí_…¦/ÍþhºX¢®×ËÅtÔo¾º\#ªéºSu³úoYr“ã&ÇMÎOpß÷íø)¿þ¿$÷×#é=2bøBÞ±oØ7üÛþûVN`oüí þ K†¿ $°·½Ñ%ì­õï†o3¿«!Ý_$ø!á endstream endobj 221 0 obj 594 endobj 216 0 obj << /Length 217 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 217 0 obj 581 endobj 360 0 obj << /Length 361 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 361 0 obj 627 endobj 252 0 obj << /Length 253 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 253 0 obj 627 endobj 262 0 obj << /Length 263 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 263 0 obj 588 endobj 274 0 obj << /Length 275 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 275 0 obj 588 endobj 354 0 obj << /Length 355 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 355 0 obj 627 endobj 290 0 obj << /Length 291 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 291 0 obj 588 endobj 348 0 obj << /Length 349 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 349 0 obj 581 endobj 202 0 obj << /Length 203 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 203 0 obj 588 endobj 214 0 obj << /Length 215 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 215 0 obj 588 endobj 282 0 obj << /Length 283 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 283 0 obj 588 endobj 308 0 obj << /Length 309 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 309 0 obj 588 endobj 284 0 obj << /Length 285 0 R /Type /XObject /Subtype /Image /Width 131 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿OêPÇé+¥·EkiI›«…AƒD-K-  šˆ:uÐ LXHL L˜4 ,B"‰ÿÚë#Êó½7^hòøLít¿ýÞÓs¾ÇçÛâQ0´üû«1 Ç ’ë€$ ǰßÅ8ç“ÀOÑ2 ‹†¦ü€tT¬ŠÀ @ÁàÞ~Hè…Ðþ^R€XÕ€;–åˆr¤FQ£)YäØÀ»6à äe%v’8×’¨ÑÎ'1EæƒàÚ€‘ËËj\ÓSƵ™F‹ym¤t-®ÊòÝÿ[ƒöÀ˜Â 뻵 ë»ïÃzY Nd)¡M,å’Y F@o$¸Ñnpó@|õÍC¼´Ö/ÍCü".ø|Xe ›^èܵ–AÍr­u¯aþ´ñåþ›žíëéÀ—¡ endstream endobj 285 0 obj 591 endobj 306 0 obj << /Length 307 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 307 0 obj 581 endobj 234 0 obj << /Length 235 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 235 0 obj 588 endobj 260 0 obj << /Length 261 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 261 0 obj 581 endobj 322 0 obj << /Length 323 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 323 0 obj 581 endobj 198 0 obj << /Length 199 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 199 0 obj 627 endobj 344 0 obj << /Length 345 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 345 0 obj 588 endobj 240 0 obj << /Length 241 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 241 0 obj 588 endobj 300 0 obj << /Length 301 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 301 0 obj 588 endobj 356 0 obj << /Length 357 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 357 0 obj 627 endobj 304 0 obj << /Length 305 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 305 0 obj 627 endobj 248 0 obj << /Length 249 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 249 0 obj 627 endobj 250 0 obj << /Length 251 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 251 0 obj 627 endobj 320 0 obj << /Length 321 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 321 0 obj 588 endobj 238 0 obj << /Length 239 0 R /Type /XObject /Subtype /Image /Width 117 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`t F*<Žgddbbfaa¥ `affbbD³h# +;77/•77'+3šµL̬Ü|B"¢bâÔb"‚|<œì¬(¶21³qò ŠIÉ*()«P(++ÈI‹‹ðss ØÊÄÊÉ',¥ ª¥ghlB}`¤¯£¡,+&ÀÍ΂ˆWF^a)ecK;g7wj7Gs}u9q.V&xbbbå”TÖ³töŠˆŽ£:ˆ õw·3Ñáã`FXÊÎ+ª cé—–SXRJmP”Ÿ™áë`¨*%ÈÉ‚°”ƒ_RÕØ981§¬®¥½ƒÚ ­±º(=ÚÇJGN„›©Ìœ‚²š–Þ±9U­½“§Ï 6˜:±«¡$-ÔÑPYœa) —°¼®]PjYë„Y —,£6X> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 353 0 obj 588 endobj 302 0 obj << /Length 303 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`C/ép‡ ##3 +] 3#š£€aaeçàâææáá¥àáááææä`geAs 3+7Ÿ€ˆ¨˜8Ý€˜¨ˆ ?/;+3RÐ01³qò ŠIÉ*()«Ð (+ÊËHˆðp°2#Å+'Ÿ°”‚ª–ž¡± Ý€‘ަ²œ¸ Ð1ˆ€adáà–RÖ1¶´svs÷ pwu²57ÔTäfc†G+· ¤²ž¥³wPDt½@lTX€§ƒ™–‚8?' <’˜ØyEt,݃ãÒr KJéŠò³’£ýM4d…¹‘ÄÄÁ/©j윘SV×ÒÞAÐÞÖTSœëo«¯(ÆÇO0Ìœ‚²š–Þ±9U­½“§Ï ˜6©»±,#ÂÕDM’Ÿî.ay]» Ô²Ö ³.YF°tñ¼é½E >–šÒ‚HnáQ4p Ï©ëµdÕú tkW,œÚY‘`«#‹âQe#×è‚–É VmÚ¶ƒ>`ûÖ ËçôÕe…8èÊ s"âˆ[LÙÄ=¶¸}ú’õÛvï¡عeÍ‚I9aŽúòHnaåW1ñˆ+혱lÃŽ=ûéöîÞ¶vá䦼p'}.xa7ê–Á.,ƒ(í²p¦<=Pe]FYÇŒT, oPˆ^ LÝ8kÝk3$ @›Á­ÍoKÅÛRÅtjJ•€ÚRQ˜m)V®AÓÆ¨¶·#–¶7¸O"9(ú$ ÒWS†öÕ¸Qûj@Ç DVDK–©oìtÓ @úöÌh}{†Á3æïBŽ2FCo2½~z endstream endobj 303 0 obj 619 endobj 318 0 obj << /Length 319 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혽kêP‡óuô`ÒÔHÛ!EP¬qi‹˜IQ29éÐB›B§ ¢ tpñcrh‹‚‹A)DÄíÊE­ré.ÇÃò,B†<9/¿HÞA¸œt$I’üóÁ72ž¯š¢Ž­Åx ãy¿€?Ïs>èa(êà $ Ë.Å ¬„£ÈAñ2À³Ðß§$)9ATÔp$×Eª" ߃¥È$5šHÞ¥3:b2é»d"ªJ2û¹R€¤k-¥gó…’˜R!ŸÕSÚµ$°`o¤!¥j÷¹b¹òøl¾ Å|~¬”‹¹{M½â!½Ëãäh*gTÍšUo4‘Ò¨[5³jäRQYð1[# Ø 5¡«¯V«Ýéõ‘Òë´[Ökµ¨'Ô lÓJ‚31œÌ–Më­;øŽ2ütß,³œM†Å³½ÑÃK‘Û|¥Öê¾'ö)ödüÞmÕ*ùÛˆÄ{vgôžcéƒÕŒíÙ|”ùÌÚÖC! ž{÷F¿|“)=Õ;“Ù—ã,â8_³ÉG§þTÊÜÈþ£× ³ÑÚsgµZ#dµræö°×0 =®ìôú6·:2Âí_…¦/ÍþhºX¢®×ËÅtÔo¾º\#ªéºSu³úoYr“ã&ÇMÎOpß÷íø)¿þ¿$÷×#é=2bøBÞ±oØ7üÛþûVN`oüí þ K†¿ $°·½Ñ%ì­õï†o3¿«!Ý_$ø!á endstream endobj 319 0 obj 594 endobj 224 0 obj << /Length 225 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 225 0 obj 588 endobj 362 0 obj << /Length 363 0 R /Type /XObject /Subtype /Image /Width 114 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혽kêP‡óuô`ÒÔHÛ!EP¬qi‹˜IQ29éÐB›B§ ¢ tpñcrh‹‚‹A)DÄíÊE­ré.ÇÃò,B†<9/¿HÞA¸œt$I’üóÁ72ž¯š¢Ž­Åx ãy¿€?Ïs>èa(êà $ Ë.Å ¬„£ÈAñ2À³Ðß§$)9ATÔp$×Eª" ߃¥È$5šHÞ¥3:b2é»d"ªJ2û¹R€¤k-¥gó…’˜R!ŸÕSÚµ$°`o¤!¥j÷¹b¹òøl¾ Å|~¬”‹¹{M½â!½Ëãäh*gTÍšUo4‘Ò¨[5³jäRQYð1[# Ø 5¡«¯V«Ýéõ‘Òë´[Ökµ¨'Ô lÓJ‚31œÌ–Më­;øŽ2ütß,³œM†Å³½ÑÃK‘Û|¥Öê¾'ö)ödüÞmÕ*ùÛˆÄ{vgôžcéƒÕŒíÙ|”ùÌÚÖC! ž{÷F¿|“)=Õ;“Ù—ã,â8_³ÉG§þTÊÜÈþ£× ³ÑÚsgµZ#dµræö°×0 =®ìôú6·:2Âí_…¦/ÍþhºX¢®×ËÅtÔo¾º\#ªéºSu³úoYr“ã&ÇMÎOpß÷íø)¿þ¿$÷×#é=2bøBÞ±oØ7üÛþûVN`oüí þ K†¿ $°·½Ñ%ì­õï†o3¿«!Ý_$ø!á endstream endobj 363 0 obj 594 endobj 272 0 obj << /Length 273 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 273 0 obj 581 endobj 342 0 obj << /Length 343 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 343 0 obj 627 endobj 236 0 obj << /Length 237 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`C/ép‡ ##3 +] 3#š£€aaeçàâææáá¥àáááææä`geAs 3+7Ÿ€ˆ¨˜8Ý€˜¨ˆ ?/;+3RÐ01³qò ŠIÉ*()«Ð (+ÊËHˆðp°2#Å+'Ÿ°”‚ª–ž¡± Ý€‘ަ²œ¸ Ð1ˆ€adáà–RÖ1¶´svs÷ pwu²57ÔTäfc†G+· ¤²ž¥³wPDt½@lTX€§ƒ™–‚8?' <’˜ØyEt,݃ãÒr KJéŠò³’£ýM4d…¹‘ÄÄÁ/©j윘SV×ÒÞAÐÞÖTSœëo«¯(ÆÇO0Ìœ‚²š–Þ±9U­½“§Ï ˜6©»±,#ÂÕDM’Ÿî.ay]» Ô²Ö ³.YF°tñ¼é½E >–šÒ‚HnáQ4p Ï©ëµdÕú tkW,œÚY‘`«#‹âQe#×è‚–É VmÚ¶ƒ>`ûÖ ËçôÕe…8èÊ s"âˆ[LÙÄ=¶¸}ú’õÛvï¡عeÍ‚I9aŽúòHnaåW1ñˆ+혱lÃŽ=ûéöîÞ¶vá䦼p'}.xa7ê–Á.,ƒ(í²p¦<=Pe]FYÇŒT, oPˆ^ LÝ8kÝk3$ @›Á­ÍoKÅÛRÅtjJ•€ÚRQ˜m)V®AÓÆ¨¶·#–¶7¸O"9(ú$ ÒWS†öÕ¸Qûj@Ç DVDK–©oìtÓ @úöÌh}{†Á3æïBŽ2FCo2½~z endstream endobj 237 0 obj 619 endobj 222 0 obj << /Length 223 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 223 0 obj 588 endobj 232 0 obj << /Length 233 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 233 0 obj 588 endobj 212 0 obj << /Length 213 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`C/ép‡ ##3 +] 3#š£€aaeçàâææáá¥àáááææä`geAs 3+7Ÿ€ˆ¨˜8Ý€˜¨ˆ ?/;+3RÐ01³qò ŠIÉ*()«Ð (+ÊËHˆðp°2#Å+'Ÿ°”‚ª–ž¡± Ý€‘ަ²œ¸ Ð1ˆ€adáà–RÖ1¶´svs÷ pwu²57ÔTäfc†G+· ¤²ž¥³wPDt½@lTX€§ƒ™–‚8?' <’˜ØyEt,݃ãÒr KJéŠò³’£ýM4d…¹‘ÄÄÁ/©j윘SV×ÒÞAÐÞÖTSœëo«¯(ÆÇO0Ìœ‚²š–Þ±9U­½“§Ï ˜6©»±,#ÂÕDM’Ÿî.ay]» Ô²Ö ³.YF°tñ¼é½E >–šÒ‚HnáQ4p Ï©ëµdÕú tkW,œÚY‘`«#‹âQe#×è‚–É VmÚ¶ƒ>`ûÖ ËçôÕe…8èÊ s"âˆ[LÙÄ=¶¸}ú’õÛvï¡عeÍ‚I9aŽúòHnaåW1ñˆ+혱lÃŽ=ûéöîÞ¶vá䦼p'}.xa7ê–Á.,ƒ(í²p¦<=Pe]FYÇŒT, oPˆ^ LÝ8kÝk3$ @›Á­ÍoKÅÛRÅtjJ•€ÚRQ˜m)V®AÓÆ¨¶·#–¶7¸O"9(ú$ ÒWS†öÕ¸Qûj@Ç DVDK–©oìtÓ @úöÌh}{†Á3æïBŽ2FCo2½~z endstream endobj 213 0 obj 619 endobj 242 0 obj << /Length 243 0 R /Type /XObject /Subtype /Image /Width 130 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x홿kò@ÆóëâaÒÔHÛ!EP¬qi‹˜IQ29éÐB›B§ ¢ tpñÇäÐ!.‚RˆˆÿÚëû¢VyçëuÈgÉ–{òÜ÷îò}Ž <~•$Iý$ùÿ‡o§`}ðð±Ðuª‚¢úyAˆÈ ï‡,CQGF4€œ¼”BŠFŒª„¤Ë ÀA@»@Rò¢¤j‘h<¡#&F4Uy¾'‚b ”µX2u—ɈÉfîRɘ&yÈæœ(_ëi#W(–MÄ”‹…œ‘Ö¯e‘4®4ý>_ªTŸ­¤XÏÕJ)¯kW¤÷µÈøE%–Λ5«n7š-¤4vݪ™ùtLýÌN ¸ -i”j¯v»ÓíÒïvÚök­d$µ ìV ΤH*W±ì·Þðs4FÊèsØ{³­J.‘Î XAŽÞªõvï}2ufHq¦“÷^»^-ÜFeÝ{à;Å3Å»3œ8óÅ)‹¹3vì‡b&:÷”›lù©Ñý˜Î¿\w…×ýšO?º§röF )P†i5û#gá®×„¬×îÂõ›–i$Ôƒ Ž ûêp·%QP ë†ùÒŒgËZ›Íj9Z/¦¡‡EOçWÞZðöoOôÎïlüûïáÕçÁo®Üë¤ïD†Že«{׆½sÅß½ãO0°§8ö$‹ÀŸæáO4ñ§ºø“m{ºOØo8û-Ï¿„ïM×>f÷žXøK½- endstream endobj 243 0 obj 592 endobj 264 0 obj << /Length 265 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 265 0 obj 627 endobj 270 0 obj << /Length 271 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 271 0 obj 581 endobj 370 0 obj << /Length 371 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 371 0 obj 627 endobj 218 0 obj << /Length 219 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 219 0 obj 588 endobj 196 0 obj << /Length 197 0 R /Type /XObject /Subtype /Image /Width 113 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{A1íë{ÃãxÐÏ”Lßœ“{Î÷{C¡o6Þ !ùX Ãq‚$rH’Àq û$íª‘ LÑ2 ‹†¦Â€t5?Hâ `tg7&ˆq¤ˆBlw' )@|Pĉ­ˉrB9P“HQ”„,rld‹À}%â åe%u”9Õ²HÑN3G)Eæ£à+#)–—Õ´¦çŒK3óÒÈéZZ•y–"דԌnŠ×å RÊ×Å‚¡gT‰ƒ`ÝS<Ì JZ7K•{ûñ©†§Gû¾R2õ´"°aŸ µ-¥4£tk×Ív!íf£nß– -%mS„wjˆ—8Ô –ýÜêöú„ô{ÝÖ³môÃG“ž Ió{ǹâ]½õ2|uÆq^‡/­ú]1w¼ÇCŸ ŒíŸœ_ÙîЙLg™Nœa·a_ŸìÇ XWõì¢üÐì&oóBæo“Q¯ùP¾8SÆ/(ªYÓª¶ûÎtþ¾DÈû|êôÛUË̪¢O0ñd6_©uãÙbù!ËÅl<èÔ*ùl2Îoò¿ÿ½Çh) >4dðcðà¾Õ6B»ÚF_®¶À—7þËžn6cO7¿Ù“gÀ–kÀU„þ[«ºl}aÀ€Þ|Ä }#ðZÅDis1QZÅDÏC¡Àƒ°«lÔwk\_f¤x—_CW_×>Ë¿ÿOø ?ùë endstream endobj 197 0 obj 589 endobj 350 0 obj << /Length 351 0 R /Type /XObject /Subtype /Image /Width 119 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`ô FF&FFFLÏmdfeecç `gcceafB³™‰‰…ƒ‹‡O@&@€Ÿ—›“ÕbFfVn>!Qq)iYZ) 1^N6$32±rðŠË((«ijëÐhki¨*ÉIŠðq³³0Ác˜‰…ƒGHRA]×ÈÜÊÆ–ÀÚÂÄ@KEV”Ÿ‹ ÉZVnAIE[gO߀ Z7K5Y>x²bæàSбpñˆKÉÈÌ¢>ÈLKŒö´3T“âf…{—…KPZÝÄ%(>³¨¢¦®žú ®ª47%ÒÇVOQœf-#+·ˆ‚®­|nESgß„‰Ôý=muEián&jRkyÅ•œ#2+Zû§Ï¿€ú`Þ¬É]õ… ¾VÚ²BœÌФÌÈÆ'©fæWÔÔ?{ñŠÕk¨V¯Z6ojgUFˆƒ¾‚ ÌZv~)M+ßäŠÎé‹Woܲ•ê`ËæuËçNhÌ‹p6TáFX+ ­e^Ó7gÅÆí»ví¦2صkç–µ‹¦¶Ÿ+‹![+£m”Y7aþê-»öîÝOe°wïží–Îh/‰s7A²–‰CÙZ*[ 2ÅZVhÜ2qÊêØeÕO\°fënغÏŽ Ëft”Æy˜¨ˆó°B‹©Qk©Ô£Ì0š¤F“ù!0šF3ù©«ÎÑ$5š¤°& òW’+#;еôjž­˜ÎÈÀt½¨£É:0ÝêD`˜!† b˜á°ü ¡N†Øe`˜al†´ž ÀtÐf”¢I&Ég4 endstream endobj 351 0 obj 627 endobj 336 0 obj << /Length 337 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 337 0 obj 588 endobj 338 0 obj << /Length 339 0 R /Type /XObject /Subtype /Image /Width 112 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí—¿kêPÇÍ[cnb›ÆD¦-VÚÆ%‹CCÁM‡$Ò픡ÅêÐÁIÑE(8(N‚ƒ‹ÒA„ ï_{AžÆ××·<®~¦dúæœÜs¾ßlÙl0„üýK1 Ç ’È!IÇ1ìweWŒAІaX„0 „4¤+¹®ˆ€‚á½ýˆ F‘" ‘ý½0¤±.ˆ;!–å˜r¤Æ‘¢)1YäØÐ{â æe%q’:×ÒHÑÎS' EæÃ!àˆ‘ËËjRÓ3Ƶ™Eˆymdt-©ÊszÀCOFÏ.oìZ»ïŒÆ„ŒGN¿]³o.Ï#¬êƒ‚zqU|ªw£é !ÓÑ S*^]¨³¦'ªiÓ*7»Îxú9GÈçtìt›eËL«¢§˜h<-UZ½ád6ÿùl2ìµ*¥l:eÁrà·zÿÚâïûIBÏ éû<ø;ïÄÚ> Ýgƒïö™ßûÿåGw›ñ£»¯~´ò[ËõÛ2B»­”]¿µþô[@o>OÐ^žð;/yPÚ\”ypi€ßy×ô5Ï»z÷)«ûŠ×ÍÅ“¿÷±/âÛ×ÿ¦?æùë endstream endobj 339 0 obj 588 endobj 208 0 obj << /Length 209 0 R /Type /XObject /Subtype /Image /Width 140 /Height 40 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`C/ép‡ ##3 +] 3#š£€aaeçàâææáá¥àáááææä`geAs 3+7Ÿ€ˆ¨˜8Ý€˜¨ˆ ?/;+3RÐ01³qò ŠIÉ*()«Ð (+ÊËHˆðp°2#Å+'Ÿ°”‚ª–ž¡± Ý€‘ަ²œ¸ Ð1ˆ€adáà–RÖ1¶´svs÷ pwu²57ÔTäfc†G+· ¤²ž¥³wPDt½@lTX€§ƒ™–‚8?' <’˜ØyEt,݃ãÒr KJéŠò³’£ýM4d…¹‘ÄÄÁ/©j윘SV×ÒÞAÐÞÖTSœëo«¯(ÆÇO0Ìœ‚²š–Þ±9U­½“§Ï ˜6©»±,#ÂÕDM’Ÿî.ay]» Ô²Ö ³.YF°tñ¼é½E >–šÒ‚HnáQ4p Ï©ëµdÕú tkW,œÚY‘`«#‹âQe#×è‚–É VmÚ¶ƒ>`ûÖ ËçôÕe…8èÊ s"âˆ[LÙÄ=¶¸}ú’õÛvï¡عeÍ‚I9aŽúòHnaåW1ñˆ+혱lÃŽ=ûéöîÞ¶vá䦼p'}.xa7ê–Á.,ƒ(í²p¦<=Pe]FYÇŒT, oPˆ^ LÝ8kÝk3$ @›Á­ÍoKÅÛRÅtjJ•€ÚRQ˜m)V®AÓÆ¨¶·#–¶7¸O"9(ú$ ÒWS†öÕ¸Qûj@Ç DVDK–©oìtÓ @úöÌh}{†Á3æïBŽ2FCo2½~z endstream endobj 209 0 obj 619 endobj 314 0 obj << /Length 315 0 R /Type /XObject /Subtype /Image /Width 75 /Height 60 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`y€‘€7T™˜˜YXXI,,ÌLLLŒè¦21±°²sprsó ¸¹¹89ØX™Ñ cbfåàâ'ˆ‰ òqs²± ˜ÅÈÌÊÉ#(*)+¯¨¬B$PVR“æãfgaBò#+¯¤¼ª¦®‘ ±ÀP_G]IFT€›^ŒÌJ[i’…†?;’Q¢ÊF®ÑÍ“¬Ú´mQ`û–õËfõT§ù[iJ %¦lâ[Ü>}Éúm»övn^5¯¿.3ÐV[Ý(÷¸’öK7lß³Ÿ(°w×–Õó'Ôe‚%,FVq¸ÒŽË6ì Ò¨ý»·®Y0±>+ÈVGVcÔ(¼á?V£é ž@FÃhbቅXR¥ò‚E­*•Š=ÕšÌÔkQ±©FÅ$›µÔklS± À@½Ž »K ÔëÄ10P¯k ì£P­Ã ïï€ % «1lElW endstream endobj 315 0 obj 581 endobj 372 0 obj << /Length 373 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream x–wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû endstream endobj 373 0 obj 2612 endobj 191 0 obj [ /ICCBased 372 0 R ] endobj 374 0 obj << /Length 375 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >> stream x…UMlUgתŠ´U+•'þZEi´ * ®:i"×ÍRm×ÏñÖ›Ýewí6QO¹T!® „z¨Z~ÔæÒ^ЍTTÈ©H­ ª8â›õÚY‡CÖzö÷æÍÌ›ùfÆKÔ}Ñð<»KÍ;¡_˜Ìξ<{Ltß .Ò¨‡ðfàeK¥ ÆŽëHþí|î}K)–ÜÜ˾:Ï6Ý¥Ë20¡uË-æD|ÿÝXÏU·©ºú$Ö~uB}NR‡I¨/¨ÔçÕ<¤ÃêþÈÆ‡í¼®çÁ7ޅצ§×¨žŒçÜŽúÏ{ç%ÿUËüæÍß:,ÝvÜsˆ«¹ksöÜ$GÈ­ëÿ³!“|];ûåöD„bU½xüfϵ³t$Y‹¨:åµHßNßI¯âûVz-é#ýCz Ÿ[”E½ìˆÙydÇʈëx0q€ˆê¨+G¿·#Ç؅бéGœ¹‘U€ ü ËZÄT²æ‰žèÈ—sgWœs;<ïć̫|½x¯HK}úÇú/úúwú¯úªþÐÏÑ´ú¤Õ%Q÷)o)Ÿ)_)—”Ï•ë$”+ÊŠrY¹ª|¤|ݧ®(—à…u[=×ì±vfšq1ܱAÄk3o,mEp gë™Kä¶ñ†Î~nߥÔvjjyíaíqmBëÕöi´mÚ Ö€6ªíÆÉÎvߨq5y¶’=kÑlÄf³’UüúˆÒÀg=.žS‹f·E§#‚¨fàÿÓÊs…¹H½‚ÞµÔ]ê€:ÏQV݇I!ž´ÌH&ŸÉ’Èôf†3™ÃŒ}sÊDf7N‡ñ=ÒΈY1“:yÉ„sÚd{}^ø_‰{‰½4€mìd(ÏàE”s½ßš«†bPןY¼"¥sÌþ>aضˆŽáË@ú Yî'~ÿ²ÑG£÷jjëu³î7š2J¥¾&ú"jˆê endstream endobj 375 0 obj 1088 endobj 188 0 obj [ /ICCBased 374 0 R ] endobj 376 0 obj << /Length 377 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream x…UßoÛT>‰oR¤? XG‡ŠÅ¯US[¹­ÆI“¥íJ¥éØ*$ä:7‰©Û鶪O{7ü@ÙH§kk?ì<Ê»øÎí¾kktüqóÝ‹mÇ6°nÆ¶ÂøØ¯±-ümR;`zŠ–¡Êðv x#=\Ó% ëoàYÐÚRÚ±£¥êùÐ#&Á?È>ÌÒ¹áЪþ¢þ©n¨_¨Ôß;j„;¦$}*}+ý(}'}/ýLŠtYº"ý$]•¾‘.9»ï½Ÿ%Ø{¯_aÝŠ]hÕkŸ5'SNÊ{äå”ü¼ü²<°¹_“§ä½ðì öÍ ý½t ³jMµ{-ñ4%ׯTÅ„«tYÛŸ“¦R6ÈÆØô#§v\œå–Šx:žŠ'H‰ï‹OÄÇâ3·ž¼ø^ø&°¦õþ“0::àm,L%È3â:qVEô t›ÐÍ]~ߢI«vÖ6ÊWÙ¯ª¯) |ʸ2]ÕG‡Í4Ïå(6w¸½Â‹£$¾ƒ"ŽèAÞû¾EvÝ mî[D‡ÿÂ;ëVh[¨}íõ¿Ú†ðN|æ3¢‹õº½âç£Hä‘S:°ßûéKâÝt·Ñx€÷UÏ'D;7ÿ®7;_"ÿÑeó?Yqx endstream endobj 377 0 obj 1047 endobj 7 0 obj [ /ICCBased 376 0 R ] endobj 3 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 2 0 R ] >> endobj 378 0 obj << /Type /Catalog /Pages 3 0 R /Version /1.4 >> endobj 190 0 obj << /Type /Font /Subtype /TrueType /BaseFont /YJGVXL+Helvetica /FontDescriptor 379 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 222 /Widths [ 278 0 0 0 0 0 0 0 0 333 0 0 278 0 278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 667 0 0 722 667 611 0 0 278 0 0 0 833 0 0 0 0 0 667 0 0 0 0 0 0 0 278 0 0 0 0 0 556 556 500 556 556 278 556 556 222 0 500 222 833 556 556 556 556 333 500 278 556 500 722 0 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 ] >> endobj 379 0 obj << /Type /FontDescriptor /FontName /YJGVXL+Helvetica /Flags 32 /FontBBox [-951 -481 1445 1122] /ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 717 /StemV 0 /XHeight 637 /MaxWidth 1500 /FontFile2 380 0 R >> endobj 380 0 obj << /Length 381 0 R /Length1 13976 /Filter /FlateDecode >> stream xÕ;{|”ŵ3ó=÷™}¿²›ÝÍfw³Ù¼C!,!/‰@$˜ðª€Ä 7*DyVÅ„PÍRX x)EÖ«`”ªµW´ÔÛÔÞ^´Èî=ómˆÞöçýõ÷»ûåÌÌ™™ï›3çœ9sÎ|_–-]ÞŒT¨ 1h´¦ÅsôË #D®ÎZÔ´8Žë«ÂÛgµ.sÅq.!fáœÅsÅqñi„䎹 WößoLGÈq­¥¹iv¼Ý„¼ *â8yJË¢eÄq]äO/¼oV»áSÀÇ/jz |ôà®4-j†~y› IY|ßýË$å¹ _¸xis\ô½ƒ0ÔzÑSH† ¤«!áªÜXh¥íð[°±wæ½ Å_#­(á÷V?!åç~Vü—o›oú[Ä¿B…ìVšóh!%†ö^Å–é>H¼TŒ 1%ùÁà( jÃ{Ñ“/0hÞˆVlx€(íì(ÞØÍŠ¡cx%²á±!ëœl°:-r…óÝæ{žs~hùì8¶‚ô~‹­Ý*$%Ç/àçÑläį /~U¡T¼ëP`¡³šö£ÅmŒ”b¼¿;)×ù:NG^Ã=>”ÄâÃÎßåd8?ωÜí<å°ý, °P‚ó¤ã9ç¿;æ:_8oê @ÃÎýŽ…Î­I¼«Ûù”#‚áž-ñl¹n=ì\Øîœ#µß!º…Ð>%¤p s;óWœYþˆˆÏpŒw¦åü‡3n„n.x¨7¤uÚ[á)ÉQîpwâÝ( ïîöŽuƒ"L÷ИÀ°íüÃCU©9Þ~0TP•º=På÷Æ;½ ¿ÊSÎ k„{„QB®RŸàƒ¨5¢ZTŠrQ…þqw‰“?Ž `ËC"/rüT²Çñ«Rå«GDV$" ‘ا ¼"ø@†– p˜—J|¿z(^õjÈÉÒ+5h-C)"X$h, ãÇ#¹îàœPsYwk¨µÜÓTVhféÒ†;ÆÚ00ÖÒÒÿc¬Rú°¥t¬™Ò}ƒÆj Í3éX t¬:ÖÌÐLi,:ùòyµ¥÷/ít•Ïç §Ö†ÇLœVv5Õ—Eð^¨,[ޏ“HÃ@©\²±YȉPìC€Ë4Þû‚;ƒ4ÑE±ÿfŠ@¨G)hI1:‰G»QâQ”SÑ ´ÃóamOG=è"NB™`{YAãÑ[8»€æ —¡ÿ2t mC‘îY„ŒÐº{c‚òL´&ö"JAÃÐcè*„§nF½±ý±CÐ: Ý:Ѹÿ—ØC²úØk±+HDá™k åBl|¬ éP:*E v z{™Ë±dAE@ݳèy´ý ý?‚{b-±ÖØùØoAU-ÈŽjáZ…{ðo™.ö±Ø³±/cQàD*JƒQÑVô<¿ ®“`ZËñ¼ oÅÛHˆÃvÔ‹¾. ¬Ã6œ‹«áªÁwá9x~ƒëu‰–o‚Ȉ–˜‰Ô’™di#ï“6&‘IcÆ2Ó˜.¸Î2™Ì –cõ¬‘­dÇ Mì"v\{Ù¶›}‡+äFr5Ü®ÛÀmbfq¸‹üj~3ßÍÅÿ Ìâxá>aHçèìÏ@—¿û±8¨ÏE?@³pž‰¶ƒ4öà&ÔÚ5¯~-F©±f5SI²A^G?mÝ…V¡ Ìt´'öÓ‰.¦,„G¶¡}l)rp;@: lТþ+H ¤ú}ÞO²Û&ßžh³ZÌ&£A¯ÓjTJ…\& <Ç2£ôrOE£+ìk ³>OUUÅ=MPÑt[E#,eW¸âÎ>a½¯ šî肞sõ Å{†zb«g¤»Ê=®ð”y\vÈ3Ò©á!}pnZ¦=ÊÃ6OYyØê2´1Þò¦Ùá ëÊËÝîz¨ƒªIu0FFú¼0Љ6*g{foŒ„ÐÌFZjš^fšêä‘>K ›=eaóƒŸ[¾Co•Ê7ÝÖ&ÞŠ¦æöŠp¨q#0—¢kÚظZ<–¬­¯ ãµýDPç¥”Üøžàmœï Ë<¥ž–öùÀ\4©®Û²IÆ7Œ&Ôu[CV ÉH?jY]ä†ÙÍ•1ŠæEnËêxþ»Gãõ¹eõéO!7i€˜rÀ3è »fIƒx€Øa4i†Úg >Á¯Ã4ç=£Ãt†ñ†9p[í-2ZÊâÄ5Î/ë–YmÒ&TZýÛ5ÃARÐ_ãqµ »u£§÷wÖ4õ×ð^Í׈6RAèJ7Ý*·ÒÍÒ ³n±xZ¨|[%™î±”ßV8e ¥9l€ |B;쪇 ð&ÓÇElBÝAŒ7×Gplm•9Ž‚ÊÜ;šÓ©ªÍ+ƒñÉH‡Š47”2Ó]0rÕW»«}ÌìvW…«”‰õJ944·×gkë€Oh2ŒªO(6×ׇçdÑçÀ-н½ž0¿ÿ KUY}Ð);6SÆ7¡nb]¸­,1*«)€úžœP> š[_½r(ŠWͳôÓœ 4ç¤A{^ü)à»´Á#êÛÛé3kë<îðÉööÄvºÞâx£Á¡þŠ¢](Ë#¸mÜ ™Ç(ÉÀíqYõ”§C@¥oiøìÿ˜ÃtÃCÚ‰ÃÃþI.ü>þ½8\4@é.š‹(‡Güë8<ò—üc‡è"Gµ!‰Ã¥ÿ$þ>.û^. ôWÍå”Õÿ:WÝÁá1ÿ˜Ãcè"ǵc%ÿ'q¸úûp¸æ{qø®Jïàð ù.Êá‰ÿ:OºƒÃµÿ˜Ã“è"ïj'KžòOâðÔïÃáºïÅáúJïàð4 ¹žrøž‡Ãèv;Ü6È좺až~ËÁSât¨”BàÜ‰Ê ïè⦠$ˆÁ^¼‹ý uAÝ9¾í¼Êmìýh@+áE¨‚z;ä#Öà3h ´µA¾î[CëhßV€bk´ÓqÍ€·AYãé 7ج[çIJÄãõ€»Ð¿Óð~ÐH8)Üö=~œÔ‡‡ó«øá”¬ÿùm÷*n+Ó¢ò6\…Ô(ν´óé‘bI„LYÙP"Pî@IŹ ^I†6Ïm÷þÿ.¦ô“?"¯Vˆ¿ÏâÉø0¾NÒI9Ï<ËœeŸbor«¹/ù ·¢OÜ.FdCdOÊEùƒò?*†( ÊÙÊ×U“ÕD½S}‚¯RÛy8`@%ñ3>1 1QAè<Å¡Ì|A,‚²ð:w 4%x žÂAž“§uký¥ìæÈÍÿäN\a«oÀyhMYt1sïƒÄ BJQ‹ôF³ÙÆŽOÐÇÏB~6$­ã_Ü%?„ƒœškÕ½ïõ~Ü[SÞ\ö*)ÉÉÖë†h5~“—„ÍIبx¦òùÌŠ‰¹[WîåËÌ(: 6_ÂnìþÓÓØôÍýÍ«®-‰~pu[ô‰†Îèy܆.ƒþd„LÈ£–Ïå C"ŸDk¬fK°Fs­º¸ïÖ¸”ˆœlsÁЂü!>¿'?Ïhà…Îr{&‹.6¶^PÞ‘&(„Ë¿XÑCÕæÙ ƒA¾§1rÀ³‘•åf»étj}ýÓª†‡Í3zº.\¸ /pÄ š‹¸ ‚äpjp94¡ ×á̬gv°;åûåYDΧÊ1xQ&ƒDŽo ë2Èå^Ô8Ϋƒ ÇÈä,ÏaÁ "I‚Áõ!„š¼LÎp€u„t*ÐÈ=‡Ÿ“[•ª=îM3€JkÍ5Ku_ŸU¢´¢Ì‚JÌÅ%ÅÕ}Å}ÅÚ¬՟¶0k]fp•fxÄìÉÄ0{º~]¦¥¿‚ æt}°¿ï:Mq±“PV`}ö0nƃ™Í¿é]û[b¼¼­ïøóo‘'É4²¡o3ëúh‰VIÜxø2 J*XçsCÎuÚí:’+*’J2‹bŽÞfSyÕV«í¢»uÃ-.k¾©îE%}%}9Ù£W†|ؤõ}¼À ¬ÀDàx¹FÌÅØ‰L§ÈÅ‚N‚A ¦ƒ7xs‡‚äAöâqk·ËlÒÀä|ó¨ec‹l þwôù³¤gíÛV·;úX_W§Ñ_ýÆÚJ¬Å™7vrúK§¢¾<íÙªl/ÌAö¬&”"$±¬‚I‚cS™˜$WˆJ¢TÄÏ#E2›š½ÈªRG°â{Û­ ×ÀŒ®]†fÁšQ”÷B¦§wÝÚ~À]lÖÍ­LðæûÌC7N'w¢'ZÚUwÁÐð“t”íD† CJ…¬Ÿ ~¶)¤‘办 #ÔÏJiä+tÐÁzº˜7ß"ú²ÎHuõͦcœƒä)ƒAfú¦àT!”„sAjNHVvŽ>Oë9wî5иÞ@˜¡¿ý2T_†Ç‚bcÂVææôØÎ‰Ê©¸ŽyÿšyOñk¥œ•³ªròa'’„䩪aòaªJ2•´Á;[%'ŒŽÁD¡Ô1¼(Y½w‡Tr'£àû”˜ô©œ:¨9¬GVCëbi탆_±^+,„?Ë•>˜uÜþPÝ×™ áØø JÁ=Ê¢ÎnB˜u\uæƒ}ìªÓë¸xž“–.ÁK–èÝ2ìÖz´C ò± &£Ö³;ð^ü¶`£ oD§q¯s'nøØË×G3³2ί¸`/e|<äæ$iŒ½Ï~Ã}޲à<)šHð{|¾u¾»Ò7Ó÷ zEŠlhQ›½¤^Ý¢îLfäêáÉ)Ér†µ[3deíà ;<(Ë&rµ¨MIv¦fgk-^óÑ›jËuzµc7Ëš“û‚{~¿–õ^ë¥j¨–N ë$ß[B+4½Z`Df_^ÃiQU§fjH$>âËðò^›IGA”‘)e\šÄ½3ˆ– ¶ZpD2¿"ˆ½ œ e!I’Î&H@S‚A– ¦X*J)¬Å‡‹a2›ò`Iæñû²°ÏïË’’—Ë=Pô$óFƒÙä¤}ŒÖãòû†bœ$ ™u}ñôîqã_<ó󉛰îÆïðèã 9÷\ïšVtþím7Eô_Ñ?îÞÍj|yUÍS®‘/<—ëÍHÏŸ~äÍèo¾n-¹ÿé™ s]ÙYÉEsO_{wÓÆ?²àœ`Ô]ÛÞØóCvÆŽ4¬]Ðɨe]²Š²?¹æIë‡ÚÍkÅ·Œ¾d`Áz´yFwn»x1ÚÆÙú×·¶Âj™ûH:áL€³ëbôqhXZ6–k@÷íþ¼*Í<Ù|P(ê”2&1WH‘94JGQdŠŽ‘¢Ü4¯N#p¢ÝŸl¶Gp{Ècv8¿#SAùŠb¡¸Øni)¶‘‰ûØÿ0눑?Å;ÀQ:Š·£øRïÿ•¾Óq+b/éÉS±7€åÉìÍì¥æ_k.” µ`¨1a«$¸‘%)ÑL.lÁÉh(q#›ÃìÆF7$T¶ýb‹³!Eç¬Æ ˜x#Žï³žd<#q^.ÈRk€N0„{’ý>?Í@îCõX½´æÞúíî–ÜE3sjqÏH£òÑ/rË;¸¿¼t¢u¹Ù«LÒ¦¥ûÒL²¡o?´íıíïLK³w‹ÑΫUö¬¹x¡˜nɘ^;>­öÍÝUU;ûvØ“f­’/õ„ªæÿdý¶—õø µÛ­±OX/w <Î$´8”¹WØg¿dg’Å„$άÙÁ Zy’C¡0øE›Ë–©ÉĤµ:]ëÜ'nÉÿÊiQ!à&üia甸gÑ™x¹‰7ø°N‰Q0û°^–ä‹ïBTëÁLRVè´"qÀèI¡ÎH¿Âçµv½Üxö¯ß\~prná^2gË–ÇxÔWyŠ;Õ÷_Õ£½ÑkÑh¸ÈS½aÕÕ×÷røÂŽ%»§úÌy¶Fò˜÷…²öYñNK‡ØiaÆŠÚ݆1ð› r€ÕÍ¿3~¢µ9ä~³Õ¯:…Cú5fV\Ý[XHíÃm†BšàX^¥QîCj½f©MÐVÀ8ĸ1&,£0©|(A‰ÌÂû0‹y7ì¿’ªP )–,]þ Èdöd‚€ªÄµ"ªÉ× <\üÌÜ¥YºúÇc³×?µøQkWÒŸŽ¿{ëÞ³³5áK³íXôž6¬xÿ œ÷¼’Î\‡Å.3½ Wr ¡Ü¡êJõTõ>v"ç $Á¡A¢Ã!èåÄaVp™úLM@«³9~›5ɹν´ôöé÷]ÝñNÙÚ,v™alQÀÜì +ñ!y¢èƒ Ÿ´ tT½ûå‰Ì&³vÅ|:-”?D—÷ÍS{VíÙûàúý¸½6{Ä«/–üø¾CÑë_}‚ï½zéÜ/~þdè¤qÄq}ä¶Yu8ãú—x*تØeÖoIìðFÍ‹•¡•;Äglûœ §& œÁ¨Ö% !eÈ lxœâ0s¿ÉœIü@üPvÑùçªùªGqF{FG¦‹œ;%a—É‘RÈ ‚Éí° r‡IávØ÷ÙÀ`½¦¯³Ê•‚VíOpø9›?%Sð[­>ÿ{î½qå‡URý÷ú$Qr³ô¼º§Ä—Cò°¯ 0ÇòNŸV£Óè5 Ë+½É‰)>ˆé>œä™RÕ>¬R{ln¨â - W* $Ò6"ÙIyÒ‚iã% h ø°?€Uq'Á’×l ÜÖ‚Ñ=Ö•€IÏÅa:Íͯ¸'w<>9ÛpP¸+gÒÊQ“ÎF¿Ä–ÿÄNEêØWêà°‡­\p÷Ä…c_|醂ʢ-™ìØçÁ1Ç¥QßòŠGµcú¡ìOCüó.ĩա ààå' M*^'·Â¶¡Vif KP;!6»i°Z¬7ÝsWÇU¬¯¡ðteÔ­pˆn(%RlQQ^®Él¤ë‚7B,ÞÄ)ù?ñ”ôhSÌv«b’«»§{Û6®tÈtB^&øî×6ßœÍ<»¹èbЈhstʼn2àÍí‘PuaŒ8FV'ÖËÖ+÷'v8öû÷&*B"cJ¨OË“aKaù€Ã*×9ä ™Bf&gg2M™Ζ­TûU#}~»5+û¶r­·j@ß•¯û=Wº§”ôJbË=Ý“jKRhS¼Ÿ'ÉçC©6H´ µ%¨•*¯#Ù‡ý‰°J[’.7î!ÄW]9ùyàœóîdŸ?¯ßQv‹*Yrí·à?`òÐŒ¼ü½Å‹£ç^ýƒúˆÊ?âÑwB>¦`çª×¢7°p —½üo¯Wx·>tê®ôè¶t¤gôº›¹oµ^ÞýJ•¿ø©)OšðpâT83ºçd÷½»~r¢kÖ’!Éy 0•Úª ¥ÃªÍ‚Yô³~ýra¹(êUD¢ÖÁ F¥\Û,Ø@&«Ù_ÀrÏŒÛ*ÞþíÄ »E!¦ DÚ `ŒoŒàUÆý­gMO(oê#¿¯Í8š”³nñá0þMt¾Tÿ\ßDòRëк]ûÎR=$ðvá"É/ · Ÿ³ œ<#§® èm@`¨çÒù%§ûŠO¨] X©ã®‹gÍø±i7.r'Þ’æÞsÿž­@ûB³ë .b+fæ§rs¹•üÂ:î(s޹ Q1ÇÇ)2†¬!OƒR2¤ÂV–ƒ— ü"pMàu(ÇËD¶8b^.ðrÞ¦’y) PívÏ<ŠMq¯…2¬ØZ£ùâÔbðÕK¨·‚ÖUgÅUšŸ±4,màViNjÄbQŠAÁ,…©à<,YAëi{¿ýEt>øE´{ǫ܉›ð™è}}3‰½=úi~€w46gP RìíI1Ý߯2ÞwÇÀ¬ ==R”CíðŸ÷²•ȇֆŠQPó fѬ6'øE?˜Ð*ëÅ\…Òã•Û«œ°f¯Ûav¨xñ‰v/£—§‚ ´ø8wÛô›¤ì1™^XVj«nW¢+šk½×n6@ |¯ä¿Sî–Fû5Ê|ËãÅ’Ü · hXwhHý’¶šô”â›?¨I;¾ zþ3GlÅsöõ°Y;ïJQ’R1¥öÙÉ›û†’« &lÞÛ·…_”;î¹w¨æIzÇô‚¡gt3B9Gø3…^;—–ø°`†§‚’Ü ô!¬D4sĨ!‘œ#šÁ)JÑÑhHrMy:ØÅˆ<É!útmöøc¯lßþ|”s3ú—£7±îwü2œ°wûŒ§ov¸Â\ŽþÜþèk8xœðõ‰Z£w³^˜ºÎN—…Ò÷‹ûÌ$UtÙµjÞaxµÃ®HV¿Å–"O×HN°zRþOOW2òZIÏàôÅnJDœÍÇúP"LŒ3A‚­jbÌÒœ¤iQ—z·q™Ñ€.çÅõ>” û4„ZysŸ·âØñr/¤ÑÌ®‚Ð=?<=²l×ÊIÙE=+õnÛôƒÇgïzhê^æàæ1©ÅÑßÃ_Ü~o~Ò˜¾©.Gï]¬„9ºÐƒ¡¼a–*K¥ïã:ì|ª¨33 ‡KÐóŒÃ¦0©püL£Á–¬ö;¬îäÛö5Éï•¿þ©Æ73{¢S©‚à|$æ§tB‚ì ¸&IŠ~ϯßõû.œ¥ìßÃ?ãS e*YV-jˆZ¦•)ý"]nZ¹hÓcêÛ"«NÁå`@ânUXfôôµºätßi0…ÔnÄ÷!i‰ ø`ã_^ÀYšDÍú§À$-ØM˜×Òµ´o'åyiìs˜>FÎ =1L¶“Û®{ưӸ3OMñú ÜîÊ”Jÿ””©þ9)s}+•+U+Õ­že)˼Ë|{“:Òõ ¸|\›©G6c¢Ùn1f2SóDŸ·ÀK¼É*9Ô[Þ´;ôëÈÜTd 2µ†(ËesZL¿ydªOð§ÚrÔN¿f$ògZ³sºüT0•q?¥P%:ÝÂ,HûO?hLw•ø±ÇxœA|F8îp«n$ƒÏ.1œx¸—%‡ê 7v%$»‘;Y­ýr7öyer8q÷¶$iínzêŒãŽäÕHKáÖ‡°G/¹3·{H€ð·ç°@|~ü•è-똽s„ÿþ'6ŒZöë£^0štr¾‘ÏÌ™WžZ³âTé¼?ùꌀà Ó²§N½§<<üä´1ïüéæi-#r+kBiV½#+½üé'Îøù+ì[æØWDÆM+8é'ªLùI5Žà’—5š^-×Ú`[‚/ÐȨ6&0N†07Mp >l”8ȇ͢›Q_q¯¦ïŠäQPÏ•®÷[±¾/Ÿº±‡ðsTIçhÿêi[¶pÓ¢ïoí+¦W`²Y&><—¼±t ¶ØgÌ'`·è{ ¡áÃY‘éEƒUo5¤ò+˜KàT N-G¼Jζ „ž™ò€Ra³á%öÝ[^O55ÒTýAüñˆ¶¤˜*U}܀㄂#Iƒµ¡Rü‡QZ/fË~ô§eÞžNâ2wëçµô(¶¯pÒÆŽi?"êž‘6ù™IÈ6ê ÀAó%›o×H(³¿ š‹ZH 3—_Ç®çö¡"—…¤œË=Ænàΰg9qLêý©ô¶)<€3ÉHlqL.6‚=Â0‹tp: G†’xð¦`$ŽgŒ9Âð K.Rau‘c˜zƒká.Þ?ïÿôÓþêGÁ‰¿NZñºBÜ(MÍ•j!žÇM\ò’€ŽaX€ ¯ÝñppÚº8ôÝs û ãïžÌ š üÁëÍà¨T†áuþ'áàÑ…'£Ëá{'Órãpû>Äí’»B«+ÙNˆWcë˜vq­üä4ó¦pN|S~N¡˜#Ì›åó­ÂJ±U¾R±VhWÈi_Rɬ@pÌÔTS*Dàl.bŸÀO°¼ŒÅŒ‚€Ã©ä/ÊŒ Wà Án‘aOˉì´áÝJ«ŠòMúrDšT<˜8YÀ58)£RrÀ¾Õ)• n& ®|ï'à!=Øj"ð,G;ò‚L”ÉA²Cj #J˜¶t+¦^ì:ͪÓŽº±àϾ!Ö­Òœ¨¡¯U–,Y^m"ÉK¤¼T;/½}áïþº'zîøå_þXÚÃŒ¿y”©¼qqóçÀPX;Æè)¤oPúA»q½eŸ…¡~û0]•®N7WXÁ¬6vÂÛçÆ¦æÔaÒT¡qÆJó9#[ƽɑuÜ^´—î¡f.%•³Í&ˆ+ŒJE‚CTS‡È” ¥:a6Zº”O˜À/z/®Á zÕW,w02¾ì€Å¹Ö, xô ˆ…XÒÈdZ¤3›-ÆT¹-ðв†f"äÀ…œì%pXÔ€óx†D2Šù4à/:Î0ŒûŒïÑ™¥Ï¶=ë $e¥ir³4ÜHutÙ[؉٬¹Ñ-Ñ?¼ÓË/«x·E|:…­U|„úƒÇ3Hq|"ÄÌM¡‚ÄÏ­è»xÞ½S+wÃ\“çß„õ.÷»î¹ý'G&ñ"Äöý!/Ô.Òྤçdÿ½øÞ ï"0?ç}üþ6Úw¾õÖ™%[ |åÝŒš¥ÂàÄ  ø» à7¤ ?| €o«³Q‰ÊP9ª¾vøÓoškÐ]ÒWדàKêÉð}ó4Õ¡z4 MG'áItåbiÞÙ£ú±•SêÆ«š¶6/›7«Iê!5CB_ÓS xG„h¸úÀU€oá1"€ `@@@ ÀëvtDÎ|pà[PrÀ 0     à€õ;:"g>ˆõÿ€4PÆÈ5 ÂÓᙃðQƒð²Axù ¼bÉôTÂká÷ Â)×oŸÏÌAø¬AøìA¸¤7·ñcΠö¹ƒpàñãÍ„/„/„Kÿ“uÛx4¿þûá‹áKáKá÷Â¥ÿÁºm¼åƒÚ[á+á+ïÄo`Šÿ/%ú endstream endobj 381 0 obj 9124 endobj 189 0 obj << /Type /Font /Subtype /TrueType /BaseFont /UBQVCU+Helvetica-Bold /FontDescriptor 382 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 222 /Widths [ 278 0 0 0 0 0 0 0 0 0 0 0 0 333 278 0 0 556 556 556 556 556 556 556 556 0 0 0 0 0 0 0 0 722 722 722 722 667 611 778 0 0 0 0 611 833 0 778 667 0 0 667 0 0 0 0 0 667 0 0 0 0 0 556 0 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556 333 611 556 778 556 556 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 611 ] >> endobj 382 0 obj << /Type /FontDescriptor /FontName /UBQVCU+Helvetica-Bold /Flags 32 /FontBBox [-1018 -481 1436 1159] /ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 741 /StemV 0 /XHeight 549 /MaxWidth 1500 /FontFile2 383 0 R >> endobj 383 0 obj << /Length 384 0 R /Length1 17212 /Filter /FlateDecode >> stream xÕ| xTEÖhÕÝ{M/é5Kw§»ÓÙ7²5rHÂNH0YDVA5pYeTq ÁÁF‡ATT˜AÅeüD1.…¾ýNÝnbÈ›7Ÿß÷æ›÷½îœ[U·êÞ:uΩS眪Îüy·· Zh4rBóœiHþG#Ä$M™Õ<'\69¦,˜)ù°iÑ«§Í¹yV¸,¼ŒjãÍ3Gž·xòµ¶4O ×£kæ·ÂpçBêi5Q¸] 鉙³§DêÍ(Ϝռ(Ò?: eç­Í³ZÂí}iҜٷ͔› ]7g^K¤=®ü>@îæ¡%Hf"QH_À¿ Úˆ¨%õoœUôÒ p¡'}+Húö_‹._>}ͧZ®ír{RÏpÉR2Bj õŸ¨–÷ÔZòÉ  †Ô P 0  %u· ¾ŠDÑÝ¢;¤rœ´}ûΜ—¯8CTkbʪ"Ç”U«*“K¸ 09p9òÈiY§ç9Gêô¸!N¨Î‚8(!QQàq &;®,Æ8®xþà¸ ð³§Øñ“'Ûñ´;^Pá8VõŽwS$ïx £GÖß²©V×±¡jL]Ç®¸úŽ’ ÅÕ÷ªÿ¿É¶”ÂÓU£ï½øbmy‹»¼É]ÞÐÔ±vA«µcÅd§s÷ÅŤÂÙA'6MžÒJÒæ–ŽÅî–²Ž‹î2çîÑòs}ªkIõhwÙnT[>¶nw­ØRÖ9Z]în.«ß3²¼rø }­é髲ü_ôUN^VIú)?×§¯á¤z$ék8ék8ék¤8Rî+5µ|ú˜RÄDzöJg7¢8¦Å!:ð I¥1¡ïØãH †ºhÐn8À™«8½„xô Zç}´ +uáô1ŽÃ)è$’Ð'è­EOÀµ]À?ƒ¦ù 'A›|´=†ÍAsP1|/`™P!ú*´4t$ô *Eíè0æ±Ç…ö¡LÔß-h+VS“C»‘U£… ÙW¢·Ñ©Pgèkx>:‡õ8“úŒ…;~´íB¯`vã|SèÜ·Ž hW¨&´žûZe¢áh)ôö9vàDœŠ·àÏè®ÐŠÐý0¶X¨‡¦Àwº mB[Ñ r«ÉL,k‚÷—¡*¨»EÐ%PºÉ¸/¢>¤¿¦¿g0[B‡qÐ_zÓ@‡§â9øü2~ÿLPÍ´Ÿþ™ÃlÜÆ¡Õh:€ÞB OÑEÔ…~EAÌNƒð¼ÿžûªÕH-£ÖQ§¨ïèlú3†gÖ²÷°ûCLèÃЯ€sGß¡ËÀ±Xøºp.Ä#ñ(Àp&ž…ïÄ›Ã]x/`¹ïGáðUøJÈF)¨tê&ª™Z ß-hõL5í¢“ètºŠú~ÞM_b¼Ìf.³”ig61³±ì@v<;îg÷²ï²ÿ`¿c»¹8®ÛνÌ}À |.¿‰—pàâÄ^ô2z ¤n=Ê4ß \­EGAz»Ðè*úD;p’hÂÍÄÐ6­n@¢ï@Eè!êÔ°P1½“VàœÐexWð«ç+¦$'ù½w‚Ë鈋±Û¬³)ÚhÐ뢴µJ©xŽeh £´r÷&gGbS“讬L'ew3Ühîu£©Ã ·†ÜئÃIžk†ªZŠÐrZŸ–b¸¥ØÓëœE¨(=ÍYîvv+s;x¨:ÈßWæ®wvtÉù9ÿ œ×@Þ傜åÖÖ2gnr–w YÐÚ^ÞT–ž†÷‰°(ÓÓÐ>„D¤"/î@ƒ›—rEƒI‹ò»»¬¼Ãæ†<ÔÑÞòæ©#GÕ•—Ÿ\õéixð÷ää.íˆJ`›'S¸à?DáÂßCaÿï¢pÿLo ðÀ¹?¡pÑÂo ð Oáâ¼I°-–)\ò¢péï¡ðàßEá²Lo p9à\F(<ä¿GáŠ(\ùï)<´o@r`;T¦pÕˆÂÕ¿‡Â5¿‹ÂÃ{0½Â#çá„Â#ÿ{u…Gÿ{ éÁ ØŽ‘)<î?DáÚßCáñ¿‹Âu=˜Þ@ázÀ¹ŽPxB…ŘÔ[¯è£vÑ\1ßtÉþ=É{XOôe’Oú‘¼é÷¼ùw‘|r¦7| à<™|êÿC’·ô"9bßB[(?„,v¡LHW0·¡ûD€ü^@ʹ¤ ís¶4lekÑÓÌh+çGãätÚù¸ÿÀ87<‡@ýRH+ -†4ú4A¾  ú^ €û+!]ËÇ.p?R¿ Ò":­„úÒÈsË o‡¾´$0A8ÆíbÁîÇ !؇8¼ÊNô˜ù?|(ˆ¤’^-ž¦Æ–©þ·ÖjˆøiQD$õÈÐSkDÑ7?H>ù¾X{åm·£À.¹ðæ£1ØIi©ùT7K¿È1/²Nv»“=Å5p+Á;ÈoÊ„—…¿)æ)ÞQ*V%ªÖ©9õHõÝê#š‰šåÚDííѨ”¨{£ŽëjuOèºõuú †|Ãߌ9ÆÇ ê°bÞ!öCG‰.–‹ß’áãh¤d™8š¦ì ŽÃÈ&(v¹fAàmxwQM°h¸îç¢]°‹dgõÓ»ô>€-ÌSkÇØC¿ 0£¯¾HF„Q&~™šE‘~\¢%ÐØÎžÛ6†ýеlyíÙFÝù”Ù•eté]™Ô à!êt ­€¼1%%ŠFœD+Y‹ÅŽç‡ç¸î ãT„ØWÙyT\yÁ œ)½‡S¤„û¿âæ<» d3GŒOfý,¥ÁGŒZ­Úƒ…Nu–ºIÝ¡fÔQZÝ‚ÃÖgv¡ââîcÙY¨Ñ˜—_ óÈïo˯Í÷U]ÒiúÂ!NmôûJ|Æ_ké €«ÄÅî¹]-6óј‰ácgh&ΆÍÖi¸‰™ÌÝl߈×S›ìÏ`²él¹¶¼X&ÖÆPL|”R4²ñÛ\êøX†Öò{Ì·90¥u‡c‡Î…ç¸V¸t=áêpw}ïâ]áa\çž­éîòûuÝ]z‹‹»>… nÌÎjœ‹æ^Ç=7ÑÀs¼ Ê®ÆÍsQX‹y—ÉUV<ð‹7ú×O›´23†•.òEó°û<Ö5?8ï–1ÔâkŽ­w=ôä}'ÍmXÒ\¸dß¼Cïo[6fÚ¨ê²ô«aúæ‡NËãÎB ö*œxSÎ `A,J³Ä{½ªŸg«Ï¨)µ:Í(ƳŒ˜¦ñzyÝl¿*Y½Î<Årš’¼C—••E=‘Õ‘u<ëû,&+§"û·ÑuuÏëºNtü™¨¸«˜¤AÿÀL«î˜øñ\m1÷ËÉÏËõ%º »òÈp9 mÁ Ü/Â(0øN¡ÜN_¢Í]3vÙüÒû×Lj®k™DI?3.wUá–9ÇCÕY¹¾¡³B¿JGóøÀxÿôÛf>s”²¥¬Ӻ▙Íã*ûåô§uу[^ H_½}Ë °@@1™ì6ÐŒô€X®UWª+5¨O«Y‡×ñKø5üf~'ϲš!šUšh½3,¢Õ  *’V«5šŸ ÇsjžQj.#6€«E­Öð¬šÞ£Üûƒœ)ð³{8V™F5'º‹Î‹ô~`~7™~?nËHe–éÞˆŠŠÊÎÂóæ6¢ys±¤×•‡]ú~.=f2·K_Á3aq»T.­Ç…Ò\ø =çÚj^ð~è#?t xº´ðDѬŠÚf0Œí!£B´Xâ Û¢ÿŒm´§Ñ Ä­²G½Žfk í;œ .Ýp2•ÎÖœ véº;ÿYà^˜}A÷a‚# øÅƒÂy ’4ð­‘RäJðøðh}SÌ٭·æ&N¡i´#øRn©wPýËX-IRèïÒÏQøîÆ–õsgoÖXK ðwIz=Uk¹ôåÛÒáÏŽ_DK €µ. Ý.­ÖT§5hÒ˜‚ÄñF*M¯¤L‚hµÆûôb2ë¤ÄxR­™v;;ÆtV=;f‡.!+š“°"áÁ„':Ž'|ŸÀ'dT¤Gèß8wøÙšà9]LA`B—þ@H»üz¿TnD(,žò$4a"¦d6Ñ4DDRŸ{]V-xâòæI³î˜0´p,~(&£qí§:oÝ„¿^¾’¾]Ù¢µUz{Ý;ßGáÚG˜wg[ZÉCÔb'oi¥°MRrŠJ®U¹H¹šYÍm¡×3›¸]ôÓÌN.€Ê#øˆò$}RiÂ<ÇQHP(à¢ÄMzzâóexÔ¯ƒÈ¢,[Û€6ÍS€]˜ŒêÅ´g™ü½ÐÜf¦b•)ûPJ¥Jñ ±:6ß:BWà°§"•×gKIý3އv4˜²=6Gj`îd9ÂÌ +, zWdQ 9²,€êGd€ÉG-vƒ^ÄoáÍ‹G–ß"ý2ù“'å5á!sËʇͽ­4¥¸â¯sƒS©£Ì!iÿÐÆ›]–à[ÒB{ÖêÛ`ÿ‘ÎÛ½óбǞ—éÀÙIȳthï^êAfü{{»×´ÏÈo’~¸råò ÿ¼¤÷Ã-´Ƹø¸Tæ£s0/øxŸºÎ0ð”YG·3í†Mô&f“áZC¥˜) |®@g·a¯Éfµ°sktd0A2bwÁz¬×Ýù0³Á¤ã©d`%p+öTmæ}ï¸éѦšÂOHÁ{¨¥Ì¡kƒ>ZðÔç?HñýVßBó¥SG¥.ÂÐO®äU(“œ^xܪ‚Ó œ.€ðqôªìÕTAñjHJƒ·S•š• KfÏ—ùìZ7u4˜Kg]}Šñ3¤·BHºGºL:Á„Ìnö ¼¸@´ð) £ S¥¸Ø®¢¯Â¦Tp, ù¹Þ² c±,¶aë7ÜÛVÆŒ£Ú‚‹¥¿±¥ ôB7ÍÇ…>f_b/ÈžÑ=bÕááWû/.&™JrùUÖzÓ&×›¶CqW £Òp¡M‰Š20%nm”%…ÛÚ[C' TàŽIx>Jg÷ò167€ïÜãzaq/É:Ö ²¥7Xü™`mÉV,‹XtÜŠp),`zQº®<—Þí†ØYzBdÁÌR÷êêÆÎsW{ôM‹ô5í¨£¾bI§ôÉþ×ßx—ag .¢ÞXä’~”.IßÿÏž‡~¾öU`zjÕ»Gñd<íäIé‹ñ%`M„λ€ä,J£E•°mç)/²qüô®#^A°ø:e·â\êÔÕKì¡«Òeù]áÔ ™²tP|PxAP°z³`S$#ŸªðèS |žP¤(4Ì@-úÅèvýt¯~ ڠ߉žÑ¿…. W±¬ T˜«‚á vÞ®´ÀqÕgòÅÊbÃÃ>Å^Ã[m¥¤”Q½B@¬–§hƒ’§µzDiZˆíM1´2Di´¾(›q4°´6(8›îôik°HñrŠÀç¦`PÆèaeFsÁn”57l<m61ÂÌ,¼_úœ’¾’>”.RÒçø VçŒ>—úhÊÕTæÃ”GS¯Å9“5«tÖ× ³T²^"úÌj³Ám³o´³lI¬…V•D)b©‚XcŒ=^(0Úââϸ.öÑEMD s!/—’u¡Ÿ‡çd½#K„ŬÇô™>zå•S§^¡Ù!–ïøç?wà"\´ãLpÐi¬ýå Ž’.ýò‹tiÉÏ?ÿ¾¯÷ùçß•n¡ÕD¿>óY|¬šØx#G©aÊié”( '`g7ѯÖm à¸^Z†x¯a5Cl4Y„É+bH²Œ‰>µxË1k1Ζ®ü$½%ýZù˜¦ÉÒð·IÁ“ÁoÙCg¿"sò«º‘¨ÄSâ ! NÉ$ÚT¶(‹Ë’8MÝ¢™žp.]•¬K6%Ù}ýM…ö}¦wL§Mï§]4^4ÿbüÕüKz”éU V‡×"x´*Æšq"Õz"¶$3šfJR™Ö ™zËaC’=Û‘¯ò3lYÙSö:ºåå ‹LÚˆå²pDf,(S²õ0ÃôÍËE0èÈRÁ™À›r`hC p'ÊÃx©6¹jגּ»DqÍÖóuë±[¾ÂCé¤0³ò–…÷Iÿƒ´cÜÝÒ»ÒyéŸÒ^j~«%ç&kƲ¡I¾xwîÀi¿‰¹Ëï)ô6ÕŽðÙÝ“·¾ñŽôæÏ3I@?7ð²Tæ¥í«÷¡½ ç©dv5Œ@M`§ ÏRϲ/ o_¿ Z•€Y+Çy åK·VÃÂi£=Î 0‰‰)ä£Jˆ1§õwð)JUZŽª¿±ÕdôÏK”h/²×Ĥ 5y¶EÆ60£*ñ‹3 (21ÎêýÇ΋èúà1 1ø@×€¦HHGaPò²U‘_à»îsƒA1€ðè£-ñØbre`y9H)ûÃH}S%Nð•Žêßð(ýˆ„ZRâ•R—¢b.6îY»–¢cc¥wÀPÓ0ÿ‘¿>:îé9”AoR¨ußè¡%3øNe/Ü/Ç[ü@ÃoHêÜa…IšW¯˜ž÷ì£oOÈ6á@z­¥¡/˜­°&•Š^…S¥5¨‘ÍcàUJ§‡U™î¦ì q¥CãSÙ\ ›\#‡‡…#Ø}6¢)ºÀ$)Ö‡§’ýµ°#MDUGÕ Ï#âÐjÐÏþøýGm£³ýÒW86¿¤f¡wI¼ó£ýã︓™ ½ó“$uæ;G®a»«“r®Íï|h~õƒ÷U-\G‡¾à«æßI ôV±|³y§™j‹ÅCMu†VÃ"åbCÀô–ñˆI°R÷>㉷óf­R­{Eí‰VÅëò£(?Þgw ù›ÃÙæªŒŒ'b+‚¿D¸+{ä°šË)áé\0—å…œ Cަ€©Ht6•§CàŒ[0­\Y-æÅÆö»oêXv+ÇÞ+ý"ž6üp æ£Cí˜]ú@õòECWϬ]9?D`e/ |…·Ëc+™n^è`t#Ä´ jðrLq”ŽFŽç”q¥ÊDÛÎAû»Ãž¯±Å;6¹*ËÃ,‘‡|EF\¾0W@<ÉZƒÌ¢ºóÀžO@åël‘¹B-Ù’…]ÒÅ[çÿEºŠñG¯,o4zÙí 3 ãk(áWqcsλ„-X¼6ïåŽÔæX·ñO0c3!¶Õøf3Ø\ωC‡mÑñfð³°‚åt¬½Š¢ê¼ßÕæPÒfÚb4-•Bµ¹Ú2ÔÞ`n°L°ŸÆŸ0_Å}é¼ìÔ ÃCt«ÙU:ܳõb¿ÚIÚÙZZ«á< .ÞbH‹Q™i*η,MˆoR¯€È™ÝC9´ëãmnâºtálÛÿlWf˜ǶYcðº9€`.f`w>(r‹™wEt¾ÌU ‘^‡`||–ïç—Þ´úT…hTQA3×<`L]A¼»UÖ];.ÂŽsÑôü;f̽ýâ´[›WTÝ·½49'&«yêãX3p ï…†è>¢Ö²ïAtÿ®’L(Ñk¡ Š?¬èI ˜àŽZª€ÿ 0@S-xÇ6¸kÈ¿ZÓ9#û ˆ÷k¡lDCkœÝ³a-p  δEt÷YÐÝE'º#6Q1‰Kw5B4Æo¶˜200ÞÔÏDÂ^î¼~D÷ô£rÒ­sS÷ï—Î>¾uÀ .ö=š¾@ÓyNgÑÛ×¢g¿=ä¥ÒÉ€C©TÊLžkä]† ¢®= ëÉÊä œWãHE±èŒu¦Y£²(‡Ááõe¥í9±wǤ+òÓlÙ9½D6¬Võ~[˜wÁc$<œ"Vnô\{ÉSÎŒë¼RöºÎ°DÏ’€E®¡_u }Õ­üñÎþT[ElªX"=óžtE‹óÕ1³¶ä&$gŽ[ýþÕKŸÝôõƧ}ò¾ª[' k§çÙRoûãÕŸ?¸%°ý©³ïæÒ­C†¸K°ïÚ¸Šó¯ |—‰ìàD±èe)U§mÕ2ÑR{,¼ŽW ù¬ÝfÔùô෽晒òf1§€ø #åÕÁ zŸ˜Ÿr˜‹“ Q=„ºèÁOç¥GKŸÆûfͽ]:‹c=5™8¤rà]WPëò«7® v²‚—'Uœ(8+ˆð.ö]àˆ Õ¨7 8¹¤‰ã• ²Äs>ÌÃEçu”ä Šðv@±¼!Š ƒ »¤3 d`àˆ©´ðêk¤…T‰_’û1¢ä|û«ÀzïPÞ!:NñéRFò¦Ó(€tàJ3‰§ˆ qØSŒ„3aøÑÀµD~IúÇI¬ÑBJ*Ž[ùš¦_"éû—©NÀ¼puøÓÁ® |0œDÌ,à }/vŠÔöuŽb¢À·Ç®aîW¼Á¾#|ÌŸN+Tgå2éL&‰Mç èB®š®äézn=[Ĭf6Òëùgé—˜]ÜN~/`Þ¤ßfìUÜ0¾–]ͬ³G„é™OùS‚ŠU(–åT*8ÇÍCÎ*)'M¿kV&†£J†æ”¼ü%»+}HåTe©D£²©5m®‘_yy­QŽÇ| †qRˆá`ñ·Õüf>F¸ç÷GµéBðôÜFØöÁ.˜S¼Þµ[ñÜ,­Âë¤ÒÕÒöÀµóx‹4)8¿¿Tz–Ðj-\H|F^ÑH!,ï !†}¡QèÙÿOŽì$¼€‡àù0Ž­ÌØKºý#é´%eÁCù± KŒÙumÓ™†ÝÇ‚ ÔÆÚŒ±KKZ‚€âXo)™ ÓÁ®ÚÊ´·,À1ÉBcA½Z½ZG[4Ö¨išõX£y•G«²Z*ßb· ùz›ÍÀ öô,»aKÞ‰*"Þã<Ø[‰¨qÙÒðÈ.øSNdÂÔÅ{ï]¶¬­m•!}#} ßop4˜D6üàíÎíÛwïÞ¾½sšô÷ý7x‚ôÌ7”´\&a¶€lj@*†‰É£ ŒµS'o産ʦ4VM¾ÎžÀ9bVŸí_Ú­²U [I`º†$y×!bÝåˆ à&–,ÈJX@èù·Ý–jKÑè…Ëâ°B ]Y›™.ÇúŒÜI«¨Çýaø¢×jÒ›)?xz߯÷~‰§zïég¬:üþò1wNqÿ3Ïέ\C¯œ8þÉ_uTAéÍ8ãÖá!ÝK]eÀâ¶Ѹb¥|…h3òN­tRY”HÑ&¥Ñª|j9®0ukä´ësôDØlÔ Þ'@:ˆQ &q zˆL}ª2Ƥhžà‚ø‚®4{ä ¦cØN¦æ¯ ^fJ_›•48LËÒÐ'pf½Y>ó°\¡Ðq‰6 ­`\*U•r¨ªÂUæ¬Lþˆâœj%cNeÌö´4Ϥ%©ÒÒ¢LJgœ¹&7¥ó5^{†ÅÕD¥£šT[zF/¯€ÄÍe?GŽõÉA‚pð xLw ”wvÖÄÆ‰°ó#›²§ã•°ŸrCÀ@V@°ä9!^0EŸ÷ÀØ)IIRh_uu×GG1°ã Ζ9·qDJJh׸±?\“B?Áþ†j§?''Ëf˜Q^¶bãÇO)pöïïË6[ “F^úä±wÒ0Á¾ }M-b[A¿ Û«K‹r¨Óô¯â¹ˆÁ ¢™G æ¬Àš(®›QøÐÃÀ'kk÷¸š{N Òî"ŸokäC ]Å`APPÞÓ'F"‰Žç˜x‚!zÓ&lß½;a¼&NÛöΰ,zÖ»8K:þnðà`Ʋ|Mö4êq2OC˜q ól°T‹J³Ýœb.4×ò-}bð×OÈ4÷ûaÕ$JƒïŽÐ±Ÿ†lSÀTÍÓ{ñ6³oÞÃùð é"ã4^6öÒØLü SœÝ˜9f8uõµ-lޱ(íŦýÔCq@;;èæñL)¬D‰#|ÜXn*÷4÷'ø-‡uTT-¡æÓ ®Nµ±Ùì+ìúK|+h'Ãø `PNØ•1À+8Š…Ÿëq4¥(X4XÝI³0SÔ{ßBèmë½ÙdÓ½ aPèd—©gƒiIýáž½%È“1ÃaT¯‘öâi¡ô´‹_0¥W_cJ¯†qhaÍvÁ8ÔÈO~u ˜@‚ú4€¬1ò ÚDô¯çÔ‘±ÑbHòŽ•‘jîgvád?~òÜ ÒIéo8gtö­¿úm¿vò‘˜3¡áH~¦€iq£KÅ3FÆ®„€­‡IäR”ùŒ_YÎ UŽcê•ë™ÍÊ'˜—”/3¯ðû•‡™w”ï3Ÿ(Ï1— C[–ö( ¶þ­ Íú `ß+V¥Já3@øY©²** 5F˜á• âXØáSAÈX©àÁF£±RÉPü~Žì÷ Ï"ØáSkž Kz„òáý½šLëaÝa0¶HD‹ìÀHì8AA][ª°LiéÞ°êØ¶ÔeBïROÛ¦³þÖ’¸Úsqc?0Õ€ŽpUa;ž/mÅ{;ñi äÿøçTe•ã¢`Wð\!힘¤  ß$ЯÑècqŽOY«œ¦\¯Ü®ü@ Æ&æ¸X^¯Içš|¶¦Šoä‰å°_¬ÑX¢ò5mŠÕªMª€Š‹ŽV Ê©Vû *•’ã)‡ ø`_”d5J“è1@ä ÒŒ]T4oi5*5Èç¨PB*ª ¶“¹‡fÝ5g­×€>"[£ ÄáäÂY0´äÝQ'r`… àèEKÞè^’'aøÌë aSrâÄ–2*ììö¤TÛm©Œ4üösØmŸ¹ü@bF^ùE) ú™jfÞµÓ´çêqéõ˜æ¢É:ê£åo@/rÎîa±I +é·iº€)TÜͬU|È|G³˜D&Yr§(5´Jñó¨b;óœâef¿âuæг ýf³‚RÐdCH”V '0üXó ^ †¼’Q`𵫱`#ô™Q–•-1"8ÄÎ).&Ão[Ffê<+2B¸ÃQE·+ÍzŸÅû0±r€c¿³4ú‰³ŸφW]YÅ@ `‘Râð‘]8@Žõ‰Ð°…餳R0?.:1fp< Ô”Ÿ`ß•®µ_}}¡.`*B¥ð›Âr4~¿W‰†Âc«à—Ž5ð+Äà Œ‚3cÐXø`-¿î«GÐMEi„ßœ‘Õ‘h òáHf\é¨ÚÁãR+[f.h™?}Jszéì™SI«ëŸÓ¹pnÂñ     `Àj€M;GN\¸‚*X’ *êZ¬Ø° pà$À€+@$À PP PÐ °`5À&€€#'.\¡¬¡È‡ °'AÞn,§÷)Ë¡«^í³ûÔçô)ËgM{µ‡37ôG¸Þ»8vC¹ O¹°O¹¤O¹´OY6 {õ_Ö§¾¼O Ûú¯èS&ÿŸ 7¾5}Ê#ú”eÑïÕÿ˜>õõ}Ê“ú”›û”'÷)OéS¡½?y®õêZŸú›û”[û”§÷)ÏèS¾¥OyfŸ²ü!zõkŸúÙ}Êsú”çö)ÏëS†Sà7Œw~Ÿòí}Ê ú”ö)/êS†MÞÞ¿äÆòUYCü/‚(g endstream endobj 384 0 obj 11420 endobj 385 0 obj (flowchart.graffle) endobj 386 0 obj (Mac OS X 10.7.5 Quartz PDFContext) endobj 387 0 obj (Rod Docking\012Tony Raymond) endobj 388 0 obj (OmniGraffle 5.4.4) endobj 389 0 obj (D:20140709220331Z00'00') endobj 1 0 obj << /Title 385 0 R /Author 387 0 R /Producer 386 0 R /Creator 388 0 R /CreationDate 389 0 R /ModDate 389 0 R >> endobj xref 0 390 0000000000 65535 f 0000157179 00000 n 0000026001 00000 n 0000134286 00000 n 0000000022 00000 n 0000025980 00000 n 0000026107 00000 n 0000134249 00000 n 0000047334 00000 n 0000047647 00000 n 0000034979 00000 n 0000035263 00000 n 0000047666 00000 n 0000047950 00000 n 0000050496 00000 n 0000050780 00000 n 0000029685 00000 n 0000029969 00000 n 0000040702 00000 n 0000040996 00000 n 0000031851 00000 n 0000032166 00000 n 0000033440 00000 n 0000033724 00000 n 0000046354 00000 n 0000046669 00000 n 0000029076 00000 n 0000029360 00000 n 0000035971 00000 n 0000036255 00000 n 0000053016 00000 n 0000053335 00000 n 0000050193 00000 n 0000050477 00000 n 0000039790 00000 n 0000040074 00000 n 0000033137 00000 n 0000033421 00000 n 0000048272 00000 n 0000048591 00000 n 0000036274 00000 n 0000036593 00000 n 0000043870 00000 n 0000044154 00000 n 0000047969 00000 n 0000048253 00000 n 0000053355 00000 n 0000053674 00000 n 0000052713 00000 n 0000052997 00000 n 0000042313 00000 n 0000042597 00000 n 0000046051 00000 n 0000046335 00000 n 0000051105 00000 n 0000051424 00000 n 0000042616 00000 n 0000042935 00000 n 0000032186 00000 n 0000032470 00000 n 0000040093 00000 n 0000040377 00000 n 0000054983 00000 n 0000055302 00000 n 0000043261 00000 n 0000043545 00000 n 0000044173 00000 n 0000044457 00000 n 0000039184 00000 n 0000039468 00000 n 0000035632 00000 n 0000035951 00000 n 0000044476 00000 n 0000044760 00000 n 0000045100 00000 n 0000045419 00000 n 0000054680 00000 n 0000054964 00000 n 0000034673 00000 n 0000034960 00000 n 0000046995 00000 n 0000047314 00000 n 0000055322 00000 n 0000055606 00000 n 0000055625 00000 n 0000055944 00000 n 0000039487 00000 n 0000039771 00000 n 0000028434 00000 n 0000028753 00000 n 0000034355 00000 n 0000034654 00000 n 0000041357 00000 n 0000041672 00000 n 0000031242 00000 n 0000031526 00000 n 0000028773 00000 n 0000029057 00000 n 0000049223 00000 n 0000049517 00000 n 0000044779 00000 n 0000045080 00000 n 0000048917 00000 n 0000049203 00000 n 0000030615 00000 n 0000030916 00000 n 0000042955 00000 n 0000043241 00000 n 0000049536 00000 n 0000049866 00000 n 0000028127 00000 n 0000028414 00000 n 0000033743 00000 n 0000034029 00000 n 0000029379 00000 n 0000029665 00000 n 0000054000 00000 n 0000054321 00000 n 0000052065 00000 n 0000052351 00000 n 0000041015 00000 n 0000041336 00000 n 0000027479 00000 n 0000027765 00000 n 0000051444 00000 n 0000051730 00000 n 0000036955 00000 n 0000037276 00000 n 0000036613 00000 n 0000036934 00000 n 0000041692 00000 n 0000041978 00000 n 0000045439 00000 n 0000045725 00000 n 0000052371 00000 n 0000052692 00000 n 0000040396 00000 n 0000040682 00000 n 0000032795 00000 n 0000033116 00000 n 0000030936 00000 n 0000031222 00000 n 0000030309 00000 n 0000030595 00000 n 0000038536 00000 n 0000038822 00000 n 0000032489 00000 n 0000032775 00000 n 0000041998 00000 n 0000042293 00000 n 0000035282 00000 n 0000035611 00000 n 0000048611 00000 n 0000048897 00000 n 0000027785 00000 n 0000028106 00000 n 0000051750 00000 n 0000052045 00000 n 0000043564 00000 n 0000043850 00000 n 0000053694 00000 n 0000053980 00000 n 0000054342 00000 n 0000054659 00000 n 0000034049 00000 n 0000034335 00000 n 0000038842 00000 n 0000039163 00000 n 0000037297 00000 n 0000037583 00000 n 0000050799 00000 n 0000051085 00000 n 0000045745 00000 n 0000046031 00000 n 0000031545 00000 n 0000031831 00000 n 0000046689 00000 n 0000046975 00000 n 0000049887 00000 n 0000050173 00000 n 0000037909 00000 n 0000038210 00000 n 0000038230 00000 n 0000038516 00000 n 0000029988 00000 n 0000030289 00000 n 0000037603 00000 n 0000037889 00000 n 0000133036 00000 n 0000144528 00000 n 0000134434 00000 n 0000131781 00000 n 0000064069 00000 n 0000064850 00000 n 0000070491 00000 n 0000071311 00000 n 0000124167 00000 n 0000124949 00000 n 0000102895 00000 n 0000103715 00000 n 0000077047 00000 n 0000077828 00000 n 0000095698 00000 n 0000096479 00000 n 0000078651 00000 n 0000079432 00000 n 0000060818 00000 n 0000061599 00000 n 0000127415 00000 n 0000128227 00000 n 0000085097 00000 n 0000085878 00000 n 0000119250 00000 n 0000120062 00000 n 0000096500 00000 n 0000097281 00000 n 0000089181 00000 n 0000089954 00000 n 0000123365 00000 n 0000124146 00000 n 0000088373 00000 n 0000089160 00000 n 0000117646 00000 n 0000118427 00000 n 0000113568 00000 n 0000114349 00000 n 0000058362 00000 n 0000059182 00000 n 0000077849 00000 n 0000078630 00000 n 0000065673 00000 n 0000066454 00000 n 0000118448 00000 n 0000119229 00000 n 0000100505 00000 n 0000101286 00000 n 0000116813 00000 n 0000117625 00000 n 0000110308 00000 n 0000111104 00000 n 0000104538 00000 n 0000105319 00000 n 0000120083 00000 n 0000120868 00000 n 0000084256 00000 n 0000085076 00000 n 0000075451 00000 n 0000076232 00000 n 0000107824 00000 n 0000108644 00000 n 0000108665 00000 n 0000109485 00000 n 0000090816 00000 n 0000091636 00000 n 0000080255 00000 n 0000081028 00000 n 0000076253 00000 n 0000077026 00000 n 0000085899 00000 n 0000086709 00000 n 0000101307 00000 n 0000102080 00000 n 0000091657 00000 n 0000092438 00000 n 0000120889 00000 n 0000121709 00000 n 0000067283 00000 n 0000068064 00000 n 0000068887 00000 n 0000069668 00000 n 0000121730 00000 n 0000122503 00000 n 0000115178 00000 n 0000115951 00000 n 0000092459 00000 n 0000093240 00000 n 0000082645 00000 n 0000083427 00000 n 0000073769 00000 n 0000074589 00000 n 0000066475 00000 n 0000067262 00000 n 0000097302 00000 n 0000098083 00000 n 0000098906 00000 n 0000099690 00000 n 0000069689 00000 n 0000070470 00000 n 0000061620 00000 n 0000062440 00000 n 0000094102 00000 n 0000094883 00000 n 0000056766 00000 n 0000057547 00000 n 0000081049 00000 n 0000081822 00000 n 0000072173 00000 n 0000072954 00000 n 0000064871 00000 n 0000065652 00000 n 0000105340 00000 n 0000106121 00000 n 0000111927 00000 n 0000112739 00000 n 0000106983 00000 n 0000107803 00000 n 0000099711 00000 n 0000100484 00000 n 0000098104 00000 n 0000098885 00000 n 0000087571 00000 n 0000088352 00000 n 0000083448 00000 n 0000084235 00000 n 0000128248 00000 n 0000129021 00000 n 0000074610 00000 n 0000075430 00000 n 0000112760 00000 n 0000113547 00000 n 0000109506 00000 n 0000110287 00000 n 0000102101 00000 n 0000102874 00000 n 0000086730 00000 n 0000087550 00000 n 0000081843 00000 n 0000082624 00000 n 0000072975 00000 n 0000073748 00000 n 0000062461 00000 n 0000063243 00000 n 0000060005 00000 n 0000060797 00000 n 0000055964 00000 n 0000056745 00000 n 0000125811 00000 n 0000126592 00000 n 0000126613 00000 n 0000127394 00000 n 0000068085 00000 n 0000068866 00000 n 0000115972 00000 n 0000116792 00000 n 0000103736 00000 n 0000104517 00000 n 0000063264 00000 n 0000064048 00000 n 0000094904 00000 n 0000095677 00000 n 0000124970 00000 n 0000125790 00000 n 0000111125 00000 n 0000111906 00000 n 0000093261 00000 n 0000094081 00000 n 0000106142 00000 n 0000106962 00000 n 0000057568 00000 n 0000058341 00000 n 0000089975 00000 n 0000090795 00000 n 0000114370 00000 n 0000115157 00000 n 0000079453 00000 n 0000080234 00000 n 0000071332 00000 n 0000072152 00000 n 0000059203 00000 n 0000059984 00000 n 0000122524 00000 n 0000123344 00000 n 0000129042 00000 n 0000131759 00000 n 0000131820 00000 n 0000133014 00000 n 0000133075 00000 n 0000134227 00000 n 0000134369 00000 n 0000135062 00000 n 0000135289 00000 n 0000144506 00000 n 0000145193 00000 n 0000145426 00000 n 0000156939 00000 n 0000156962 00000 n 0000156999 00000 n 0000157052 00000 n 0000157099 00000 n 0000157136 00000 n trailer << /Size 390 /Root 378 0 R /Info 1 0 R /ID [ <42aeeb2a164b17e4f08ad9cac8d56625> <42aeeb2a164b17e4f08ad9cac8d56625> ] >> startxref 157305 %%EOF abyss-2.2.4/doc/flowchart_simplified.graffle000066400000000000000000001177421361462241400211520ustar00rootroot00000000000000 ActiveLayerIndex 0 ApplicationVersion com.omnigroup.OmniGraffle 139.18.0.187838 AutoAdjust BackgroundGraphic Bounds {{0, 0}, {1099, 928}} Class SolidGraphic ID 2 Style shadow Draws NO stroke Draws NO BaseZoom 0 CanvasOrigin {0, 0} CanvasSize {1099, 928} ColumnAlign 1 ColumnSpacing 36 CreationDate 2012-12-05 00:56:47 +0000 Creator Tony Raymond DisplayScale 1 0/72 in = 1.0000 in FileType flat GraphDocumentVersion 8 GraphicsList Class LineGraphic Head ID 43461 ID 43597 Points {179.69920329269712, 194.47751115583006} {227.95678889313632, 219.55307955830477} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43460 Bounds {{238.47937393188568, 445.99996613762551}, {39, 14}} Class ShapedGraphic FitText YES Flow Resize ID 43544 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 ABySS} VerticalPad 0 Wrap NO Bounds {{325.81455612182708, 445.99998139641457}, {65, 14}} Class ShapedGraphic FitText YES Flow Resize ID 43543 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Output Files} VerticalPad 0 Wrap NO Bounds {{131.56212997436614, 445.99999617836647}, {56, 14}} Class ShapedGraphic FitText YES Flow Resize ID 43542 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Pad 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc \f0\fs24 \cf0 Input Files} VerticalPad 0 Wrap NO Bounds {{293.35941696167083, 441.99998139641457}, {22.108642578125, 22}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43541 Shape Rectangle Style fill Color b 1 g 0.85076 r 0.722565 Text VerticalPad 0 Bounds {{206.02423477172943, 441.99996613762551}, {22.108642578125, 22}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43540 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text VerticalPad 0 Bounds {{99.106990814210349, 441.99999617836647}, {22.108642578125, 22}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43539 Shape Rectangle Style fill Color b 0.791123 g 1 r 0.777435 Text VerticalPad 0 Class LineGraphic Head ID 43472 ID 43491 Points {408.87020861788773, 371.97922164079642} {443.87019417847011, 371.9805196971426} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43489 Class LineGraphic Head ID 43489 ID 43490 Points {300.87023859886983, 371.97785281522317} {335.87020859878953, 371.97785281522317} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43469 Bounds {{336.37020860618236, 349.47786795290506}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43489 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 MPET Algorithms} VerticalPad 0 Class LineGraphic Head ID 43462 ID 43488 Points {409.33649444336606, 238.48993113034226} {444.77252131555792, 238.48993113034226} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43486 Class LineGraphic Head ID 43486 ID 43487 Points {300.90046643683979, 238.48993352202285} {336.33649444580089, 238.48993352202285} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43461 Bounds {{336.83649445260335, 215.98992172901012}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43486 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 PET Algorithms} VerticalPad 0 Class LineGraphic Head ID 43594 ID 43591 Points {408.34666043418969, 105.00532664588899} {444.36664927522622, 105.00466117135421} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43593 Class LineGraphic Head ID 43593 ID 43592 Points {300.12791644743027, 105.0059899548778} {335.34666041392916, 105.0059899548778} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43595 Bounds {{335.84666043658603, 82.506000988699725}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43593 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Filter Unitig Graph} VerticalPad 0 Class LineGraphic Head ID 43461 ID 43478 Points {180.40917205306428, 238.48991831012302} {227.90046643507853, 238.48991831012302} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43477 Bounds {{92, 215.98990487358742}, {87.909172058105469, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43477 Shape Rectangle Style fill Color b 0.791123 g 1 r 0.777435 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 'pe' Libraries} VerticalPad 0 Class LineGraphic Head ID 43461 ID 43476 Points {444.44106247849021, 127.46617088472254} {300.82605322437695, 216.02773035415149} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43594 Class LineGraphic Head ID 43469 ID 43475 Points {180.40917205123054, 371.98047036292445} {227.87023859835193, 371.97899281733066} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43474 Bounds {{92, 349.48185431154764}, {87.909172058105469, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43474 Shape Rectangle Style fill Color b 0.791123 g 1 r 0.777435 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 'mp' Libraries} VerticalPad 0 Bounds {{444.37019419017543, 349.48187338503396}, {72, 45.000000000000014}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43472 Shape Rectangle Style fill Color b 1 g 0.85076 r 0.722565 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Scaffolds} VerticalPad 0 Class LineGraphic Head ID 43469 ID 43471 Points {444.84670056819556, 260.90741868331719} {300.79605932960209, 349.56035223582666} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43462 Bounds {{228.370238591477, 349.47785650881326}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43469 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Align Reads to Contigs} VerticalPad 0 Class LineGraphic Head ID 43595 ID 43466 Points {179.43947386612567, 149.01533349400736} {227.18480744900279, 124.05656008745486} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43460 Class LineGraphic Head ID 43595 ID 43465 Points {180.40917203904971, 105.00074959034995} {227.12791644382912, 105.00369770906197} Style stroke HeadArrow FilledArrow Legacy LineType 1 TailArrow 0 Tail ID 43459 Bounds {{444.86664927282982, 82.503986828543475}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43594 Shape Rectangle Style fill Color b 1 g 0.85076 r 0.722565 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Unitigs} VerticalPad 0 Bounds {{227.62791642477339, 82.506000988699725}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43595 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Pre-Unitig} VerticalPad 0 Bounds {{445.27252130632064, 215.98991441033058}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43462 Shape Rectangle Style fill Color b 1 g 0.85076 r 0.722565 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Contigs} VerticalPad 0 Bounds {{228.40046643003734, 215.98991441033058}, {72, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43461 Shape Rectangle Style fill Color b 0.591099 g 0.787961 r 1 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 Align Reads to Unitigs} VerticalPad 0 Bounds {{92, 149.24696778557472}, {87.909172058105469, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43460 Shape Rectangle Style fill Color b 0.791123 g 1 r 0.777435 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 'lib' Libraries} VerticalPad 0 Bounds {{92, 82.497944348074725}, {87.909172058105469, 45}} Class ShapedGraphic FontInfo Color w 0 Font Helvetica NSKern 0.0 Size 12 ID 43459 Shape Rectangle Style fill Color b 0.791123 g 1 r 0.777435 Text Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \expnd0\expndtw0\kerning0 'se' Files} VerticalPad 0 Bounds {{212.49812316894531, 193.48792471098125}, {317.00189208984375, 90.004020690917969}} Class ShapedGraphic ID 43496 Magnets {1, 0.5} {1, -0.5} {-1, 0.5} {-1, -0.5} {0.5, 1} {-0.5, 1} {0.5, -1} {-0.5, -1} Shape Rectangle Style fill Draws NO shadow Draws NO stroke Cap 0 CornerRadius 5 Join 0 Pattern 1 Text Align 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 \f0\fs20 \cf0 Contigs} VerticalPad 0 TextPlacement 0 Bounds {{212.49811788989803, 326.97584270519633}, {317.00189208984375, 90.004020690917969}} Class ShapedGraphic ID 43495 Magnets {1, 0.5} {1, -0.5} {-1, 0.5} {-1, -0.5} {0.5, 1} {-0.5, 1} {0.5, -1} {-0.5, -1} Shape Rectangle Style fill Draws NO shadow Draws NO stroke Cap 0 CornerRadius 5 Join 0 Pattern 1 Text Align 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 \f0\fs20 \cf0 Scaffolds} VerticalPad 0 TextPlacement 0 Bounds {{210.60791960427923, 60}, {318.89206799795477, 90.004020690917969}} Class ShapedGraphic ID 43596 Magnets {1, 0.5} {1, -0.5} {-1, 0.5} {-1, -0.5} {0.5, 1} {-0.5, 1} {0.5, -1} {-0.5, -1} Shape Rectangle Style fill Draws NO shadow Draws NO stroke Cap 0 CornerRadius 5 Join 0 Pattern 1 Text Align 0 Text {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 \f0\fs20 \cf0 Unitigs} VerticalPad 0 TextPlacement 0 GridInfo ShowsGrid YES GuidesLocked NO GuidesVisible YES HPages 2 ImageCounter 8 KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo Animate NO HierarchicalOrientation 0 LineLength 0.4643835723400116 circoMinDist 18 circoSeparation 0.0 layoutEngine dot neatoSeparation 0.0 twopiSeparation 0.0 LinksVisible NO MagnetsVisible NO MasterSheets ModificationDate 2013-09-19 18:08:36 +0000 Modifier Tony Raymond NotesVisible NO Orientation 2 OriginVisible NO OutlineStyle Basic PageBreaks NO PrintInfo NSBottomMargin float 41 NSHorizonalPagination coded BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG NSLeftMargin float 18 NSPaperSize size {612, 792} NSPrintReverseOrientation int 0 NSRightMargin float 18 NSTopMargin float 18 PrintOnePage ReadOnly NO RowAlign 1 RowSpacing 36 SheetTitle Canvas SmartAlignmentGuidesActive YES SmartDistanceGuidesActive YES UniqueID 7 UseEntirePage VPages 2 WindowInfo CurrentSheet 0 ExpandedCanvases Frame {{439, 332}, {1378, 1037}} ListView OutlineWidth 142 RightSidebar Sidebar SidebarWidth 138 VisibleRegion {{1, 1}, {1097, 927}} Zoom 1 ZoomValues Canvas 1 1 abyss-2.2.4/doc/flowchart_simplified.pdf000066400000000000000000001175411361462241400203120ustar00rootroot00000000000000%PDF-1.3 %Äåòåë§ó ÐÄÆ 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x¥[Ér%ÅÝ×WäÎO UWŽUµ„68 ì0 ^,°P·DHÝ 5Žðßûœ›cMOC4­:ÊùÎ'“ßÔ·ê75à_çñÇhõt«þ¥>¨7ßÜ>ÝÜþúé÷ŸÔÓ=ÚhÍVƒ #þcm臭oÕ›¯µúëÇŽ-™0÷ÆÛÔÆ L6»<ŽÆ(n¼2ƒé½òp¶Û4µÞöf4›¦noTß3ÎX¤ïçÙuq~ÛÒzÓO!„Ô2¤•†mK®ÔŽƒQØÒ`ŒÎƒŽÛ¦´4Õ“ÎûŸrÓÅq<4òi‘ón£Õñ@›ó1Îö“ƒl–›Ö”ÌêÔsýdÃæ(õŽ„Ø¶lû¶iØU×y‘¦sjìõæY«Ë¡w3þ &«G‘Rm­µÃI:“[‡ óØERµµto=4'=i—ÇNÒúA9üû#ó³zóÝíÃOŸîÿsûöãÃǧûÇÛOO÷7´øÍÛg­Þ^ÉŠuõ–+—XµŒ½ýˆÿBe쨱!Q£Y=ª0Qëgõ€ŸL?¨?Ãä•uº7v é+“ŸœÁ'=»½Qw]>ª+(N}Æ=ß´'g&l;³£…½M<¼Ï¯Õ€ÍÁ`®oTr—øûR{×;Ô%l¿tw r}­û¢¸~§N߸ÿtÿþùB]ÿ¢¾¸Ý=##õ L}ôS•?i•&"›0L=¬˜‡ïUЃtNr 3?ç¹£¨ñÛÙö£ƒÂg¹ád3…w˜?(º¼šŒáØÇºÆ®´ÃGZs¸AâÌXHÅòâ(ÂØ³+«Ï£×ÍÕ5¤ÁXf^YF£DëÊÑRˆ°Y iââ’—³½†¹JOéa$Hïuººùé‚fjÔéÝ…Òc?Ê|Ì¿yÈ?üœ€ÀT×_Cä1›eڊÞÜûŒ"/ŸÕ@UÆ:ÊÑ® ¬(~Œ±s4U£w³ŽÖí•X­·­ú€ÉÐ# øuü ˜òÁ¬Š¼¶Ë‚«g¤+37"wcZ\y]}yÞ\YCW…È šD^=^¹qC ¿År»å ?™îÛ–¦+þöæ¹úqõœ»g­¥At²sJ$Õ<õó0k„°Œ=4˜‡‡@£d¯ôû¾[òs|?¿¨b08vñqôõ6hÈV‰ÁÓ ³©D17 [a»;V »KP3Ö9 '8{çévé®c…“GfŠu‰¿/ ô<@DÊ­]$Œì/8H­NÏ·Ù~2¢øØÞ—éïûÜ ™\w*]ªÉEçŽô ÎýXTˆWL窤:› FPfrÒJäT?¢˜ÊïÚøÑF^æét \´1]•@‚Z¡ æ°U‘Iù¾Kâueœ×Iî/%­+XdƳò(~­û¿óù¯ô÷ø‹î´múT<èSùåy©‰]Á"‰‚)Ïz@t¢AÁc‚ —% 6NWÏ+ gW0økiñ¥¾©¤¸3â¡0%š0Çw3”~BX}D©Úb_Á¼E B;`6÷m0³Œ6#ž­FûxK7×›¶È°ôËv¬í³­Xßg±~È?ÀðR[æ,›é©â+Õb¦¨%ë5úTØúwy†¢E=~¾èb¤}Îfÿ)™}‰´tYMÚÖ8# ÔΓS8£òã · ½~]‰1wè'?Œí¡“6ÀAH%WuÒ!õ^bPˆ„µúWû¶:YÑ:â¡NòôÃ@/‡b2ksDò%†D"cþ•¾CDºÛñœNBÓ†: ã-Issúf€vÚëÝþaÈ­Çßz„Šcæ¨(¨è¦%D!Œ%4ÝAî!˜'½AËh‡ŸFiÞ1Nú!`vÚ=! ¹„¢+ˆ6B´ùÁj´sg®Q·E^@ê) ×vˆíŒnÚuñß<û»ü>›d±þâ§³àýEWýBJˆewME¼ðrœr<È>Z’@• ‘Ŏܱ@8ž–Ñ…“­U"ØUƒ°€¢M…#å-”¹…ŠE,ºž¯!í<§M‰p„ŠùüúÀŠ7ÚÚÃk«GnX¨Éö³ÀîXJ0¡EC ðkߘI‚&¡nLbÁnk$‰ŒA5jGfŠ8I˜`#’Z‚ £Ý,;câwøküùE5EY›Eû¡âÐXduQ\0'˜!Ë‚Ó&0é„Z˜HÄN›Î4—œ.çÉ8(2Fàj˜K!P1†K±¯‘:$LÞ¢üÅ­ùå2»0JZÍCk6£ J¥íÔOÃ8v…Fö³îÝœ óã-[#»?嘘ªt4žÓºëqF°”Ñs6dq¨«õl(#zžÝô¾BzèD±d²šNœŒ)Ô‹i±ŽÒ"kˆÉ˜@I»‹iÕ²75âшÃ1NBLB4(©Ãt©K,úÔˆQ]Ù.¦W ,©ÉvÄón¹“Æ‚8èÒ«uC‚óŠôª;Ëcv¦_–RmzÕµlÓKéU"2ŽÒ«?¾¬¼žÖéçiáÏ*“0…£’ädð’l#߂ϙa ¨+>ðhPÐÞiüžZ=;z?èáÆ¯§œ˜‘¼×âÚÀ•MbA;_´[ê¯ó2sRDædÕL¥á¤Á EÑ ¤ ¾ˆeš“äBX7q·é ·DM=®ÕÄÀ¹s*„Ò%Ã+11Záïc|•v4Ú„Å»ìýJ£õ vÅh'øC†Z½Âk3F£e»Uû&LŒ¶¢tqÄsFËp—N£åaHQ²0Z%%ˆ›]²|Â8€í“¿SéÑJÕ´Cò½Šq÷ŠÅA®…ÊŽ¢`I*È¡æ ŽzJ'Í-B:Ý㉴(—|€…w(4!³A¡êXe”Ù Òï|îSØ ¡^¹_ÆÂ…QQ3"Bí#S ¿æ¼4#ê)Ø D6¨ÿ‡l8wv%• L@'”û1Cp¢åÄÆÙBf‹¦ÞÉÔÛ±ÎùÝbê+ʽM–,òf§Ãnšíºz©Ióo2´¶øîT˜È×Ó‹ÞROx$ÐõFyP1ÐÜX<É.P2V->^2{—≷¼øý1àâz¢-kÁ¬`8îŠñ—| @-ÓnÕ*Ztû¬—Bšû«f}ÑK% 7“‰w„Ñëàe2~Ý;Z=á^L‹¬ã|äF°E Km!ì¦BR¹³B¨ -ÛŽö*MÇ¥UÌ+ãâáN$ILLª@•q)+„„k;ÚBÛ;ȶу›Ô¸_(ɦ¸†„UˆÅK» lró£K uÊ4KÑÿ§¬ø{ÜLbIs§†›I þQu±³ƒnÅiz_?NôK+j;ø[JŠªÍÓ½k‰¡æÔÖE?˹È[1³‰¤JùY^{$è¡KrX’õ6nÛÉ>¤¶õy‚HRˆÂUˆEd vºke¼Yí„k¼fiP{WWË2[(¾ ÑêcîV]aÖѾâ}Þ^„úMÎC.©ë{Àà‰Ò„ržýdŒÞ'c•O7däyPÅè¶#¾Ò!eàp%²bßÈxˆÕ¨I±XºF?,éû.nA›IÖ>OÓŠZpí‹ôZë>„iöxÙ°.ÀaÄß|qÌøØOìᬧøŠ÷'»~¢r ïs_®pò%`W¼Þ]nó¸¸Ã=ëD Ømè»Ôý,ÇûB¸Æ}h똮¡»A8a1\“(X®÷z¿èJ$¥/ÖG_RÖ\ÂuÅÚpÍlš½»’Œ¬ÜÉ[….ŠÆ4]=bxÕf¸êN&¹ÎJ© Ά®#a%•©X9¼ ;Y÷~ñlF=²e.§¤Zg^"°r6kÏfÓ»¸ÚœÊ,®‘iü•è@iÁ=Âu,±èN£ÇE3Ö ¹oæ@Sy²3â+ÝI¤D:©­#ß)Þ_J¹ÌÆŒfÁmb)Ì^ÖXÌiˆ¶#.’&¬eæ@œmýPª¹°cNðrßüãuþd=É:ñÀfÿ´?Y%DΟÈ¥à‡’?iªbá˜Ó’¦à}âKÓ„±â——> ÆŠí¤´ER³îý¢Íd²\_ô'“š_ÖL’Ú±æ zB´Ë;.6“Ò“óþ¤9,M1ö×á&èSö'$K2¢g^òÚ™œÆK¦'‚éȆ&þdÛûų‰þU§MŽ£?‰;÷Á³‰KLˆXò!‹éÉ¢w:x©ûṵ̀}÷5ŧÂpx!€¸Ð°âø CÍßðcBêåöü¾7€òØ8ð*ßÁ*€J£Â!Õ1kÇOø©ô©ðNŸ¹­|Åú«ö=H½XþhÖò®™{C=Kw>o¥dµ‚¡´Í÷”±Ü7cq¯mF<¼È¥,¥®ãÓê¸QÞÌž6š?ÓFkã´Ó È1q«Ýâ¶âÄNFfÇ7Ùi]Ôjƒ›BÀµ G™±´+jzîÛ5ygij;u—ˆ\vJlæìQ¤õS¶V§V ì4åHè—Nœz¼ðD@Ã…a,bñîR‹ï›Ϩ¸!ÍãÓØÓW~ýý“úòþávÿq³Á³O‹˜ƒCÇÿÅæÁLxކ*>ìûü¿WW¯{  –h˜=²áQ%LðÍ#*fP‡x6Ìò¦~7Lç1#é=bTã©> endobj 6 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs2 40 0 R /Cs1 39 0 R >> /Font << /TT1.0 41 0 R >> /XObject << /Im2 9 0 R /Im4 13 0 R /Im11 27 0 R /Im1 7 0 R /Im9 23 0 R /Im5 15 0 R /Im14 33 0 R /Im15 35 0 R /Im10 25 0 R /Im6 17 0 R /Im13 31 0 R /Im8 21 0 R /Im16 37 0 R /Im7 19 0 R /Im12 29 0 R /Im3 11 0 R >> >> endobj 9 0 obj << /Length 10 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 43 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Om7ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€V^ endstream endobj 10 0 obj 120 endobj 13 0 obj << /Length 14 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 45 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 14 0 obj 106 endobj 27 0 obj << /Length 28 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 47 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 28 0 obj 106 endobj 7 0 obj << /Length 8 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 49 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Om7ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€V^ endstream endobj 8 0 obj 120 endobj 23 0 obj << /Length 24 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 51 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Om7ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€V^ endstream endobj 24 0 obj 120 endobj 15 0 obj << /Length 16 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 53 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 16 0 obj 106 endobj 33 0 obj << /Length 34 0 R /Type /XObject /Subtype /Image /Width 45 /Height 44 /Interpolate true /ColorSpace 42 0 R /SMask 55 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 4 endstream endobj 34 0 obj 49 endobj 35 0 obj << /Length 36 0 R /Type /XObject /Subtype /Image /Width 45 /Height 44 /Interpolate true /ColorSpace 42 0 R /SMask 57 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 4 endstream endobj 36 0 obj 49 endobj 25 0 obj << /Length 26 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 59 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Om7ˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€V^ endstream endobj 26 0 obj 120 endobj 17 0 obj << /Length 18 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 61 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 18 0 obj 106 endobj 31 0 obj << /Length 32 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 63 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 32 0 obj 106 endobj 21 0 obj << /Length 22 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 65 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 22 0 obj 106 endobj 37 0 obj << /Length 38 0 R /Type /XObject /Subtype /Image /Width 45 /Height 44 /Interpolate true /ColorSpace 42 0 R /SMask 67 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ  ÷Oíì( 0`À€ 0`À€ 0`À€ 4 endstream endobj 38 0 obj 49 endobj 19 0 obj << /Length 20 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 69 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 20 0 obj 106 endobj 29 0 obj << /Length 30 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 71 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 30 0 obj 106 endobj 11 0 obj << /Length 12 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /Interpolate true /ColorSpace 42 0 R /SMask 73 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xíÐ1 õOmoˆ@aÀ€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0`À€ 0ð IÎ endstream endobj 12 0 obj 106 endobj 49 0 obj << /Length 50 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí™ëkRaÇç2ç²yô§†y9š¸å L¨1çj/bŽØÈ´E%,爨Aéæ ¤Ëh“½¨5Ü`ƒR‚l”Ñ¿Ö)ð2ñ¼8ð!8ß7Â~|}>p^<Ÿ‚”ÈE@,âÿP¥‚aE1ÀAQ†U=µBŠ©q‚$)ŠŠ¢H’ÀÕ çú`ÃÉa­Žå £càX–&q 鮃‘! ÍÌ›ƒÞnµ˜8†êºh˜fXo¶9]“^`|Þ‰q§Õ¤£q¬s8ŠÓz3ïö‡¦"3±Y`‰E×.ø\³ŽÂ;‡ƒ1’1ñ“¡È\|)‘˜Äâü•pÐí02Dçp°šælîPl!u/óp%,¹læÎx4è:ËÒCm”0>brú# ·2«kÅÒ&¨”J…gùôòü´—7Žàí6DÃXÆCsÉÌ“õòÖNX¶ß• Ó‰ËÁsgi}r(¡·NLÅï®®¿ÙýT=•ƒêÇÊëBþöÕ‹n‹^Ói#Y»'¼˜Y+ïVku`ùr´_yùôþµéó6–@Ûg#9ÞMd‹[{Ç_' ò½Q?úðöùƒ¥ˆÇÎ’]m>KæJ;ÕZãgX~|û¼ÿ¾˜½õ:¸NFŽfSùÍÊaý¤ùT~5µêöƣČ7X‹¤Ò&°BR22‘…¤Éc…¤dd" I0’Ç IÉÈD’"`$’’‘‰,($EÀH+$%#Y!‰’ƒ¼¿¡¾›òÞt9…=Ù‚|¾äU_ÒrAË€]ÐÆ ÁÝìuAmÏ•> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 66 0 obj 627 endobj 61 0 obj << /Length 62 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 62 0 obj 627 endobj 63 0 obj << /Length 64 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 64 0 obj 627 endobj 67 0 obj << /Length 68 0 R /Type /XObject /Subtype /Image /Width 45 /Height 44 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`¤€ ð8‘‘‰‰™……°°03112¢iªdaeçàâææáá…nn.V TåL̬Ü|B"¢bâp &*"$ÀÇÍÁÆ‚¢š‰™“WPLJVAIY”•d¥Ä„ø¸€ª‘\ÂÄÊÉ',¥ ª¥ghlƆúÚj R"@Õ̇0²pð K)ë[Ú9»¹{@»›³½•‰ŽŠŒ’ÑL¬Ü‚’Êz–ÎÞAÑqpìãbe "%Ä͆p;¯¨‚Ž¥{p\ZNaI)”æ¤Å…zZë*Šóq0ÃÍÄÁ/©j윘SV×ÒÞí-uùÉ¡n¦êÒ‚œ,pÅÌœ‚²š–Þ±9U­½“§Ï€‚éSúÚjòü¬uäD¸YáŠY¸„åuí‚RËZ'ÌZ¸d,Y8{R{EF¨£¢(²bnE§ðœºÞYKV­ßëW/™Ýßíj¬,΃d2·¨²‘ktAËä«6mÛÛ6¯^8µ­8ÎÃTUœY±˜²‰{lqûô%ë·íÞ»·oX6³³,ÁË\MI1+¸Š‰G\iÇŒevìÙ{vn\>»«"ÉÛ\M’ …£ŠÉ n"……´è&!!1#%Ñ„’(¾ÄžøaÙ*G¶’BÎVð  ̰Ű [Œ#òra/ ‚€E>ZQ@R!Ã.¾$1‹/=,ÅI#P5ž"—µÈe`@*ÌyàT˜³•¢Ï Ò†„j^8 -«† endstream endobj 68 0 obj 580 endobj 69 0 obj << /Length 70 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 70 0 obj 627 endobj 47 0 obj << /Length 48 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 48 0 obj 627 endobj 51 0 obj << /Length 52 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí™ëkRaÇç2ç²yô§†y9š¸å L¨1çj/bŽØÈ´E%,爨Aéæ ¤Ëh“½¨5Ü`ƒR‚l”Ñ¿Ö)ð2ñ¼8ð!8ß7Â~|}>p^<Ÿ‚”ÈE@,âÿP¥‚aE1ÀAQ†U=µBŠ©q‚$)ŠŠ¢H’ÀÕ çú`ÃÉa­Žå £càX–&q 鮃‘! ÍÌ›ƒÞnµ˜8†êºh˜fXo¶9]“^`|Þ‰q§Õ¤£q¬s8ŠÓz3ïö‡¦"3±Y`‰E×.ø\³ŽÂ;‡ƒ1’1ñ“¡È\|)‘˜Äâü•pÐí02Dçp°šælîPl!u/óp%,¹læÎx4è:ËÒCm”0>brú# ·2«kÅÒ&¨”J…gùôòü´—7Žàí6DÃXÆCsÉÌ“õòÖNX¶ß• Ó‰ËÁsgi}r(¡·NLÅï®®¿ÙýT=•ƒêÇÊëBþöÕ‹n‹^Ói#Y»'¼˜Y+ïVku`ùr´_yùôþµéó6–@Ûg#9ÞMd‹[{Ç_' ò½Q?úðöùƒ¥ˆÇÎ’]m>KæJ;ÕZãgX~|û¼ÿ¾˜½õ:¸NFŽfSùÍÊaý¤ùT~5µêöƣČ7X‹¤Ò&°BR22‘…¤Éc…¤dd" I0’Ç IÉÈD’"`$’’‘‰,($EÀH+$%#Y!‰’ƒ¼¿¡¾›òÞt9…=Ù‚|¾äU_ÒrAË€]ÐÆ ÁÝìuAmÏ•> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 72 0 obj 627 endobj 59 0 obj << /Length 60 0 R /Type /XObject /Subtype /Image /Width 110 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xí™ëkRaÇç2ç²yô§†y9š¸å L¨1çj/bŽØÈ´E%,爨Aéæ ¤Ëh“½¨5Ü`ƒR‚l”Ñ¿Ö)ð2ñ¼8ð!8ß7Â~|}>p^<Ÿ‚”ÈE@,âÿP¥‚aE1ÀAQ†U=µBŠ©q‚$)ŠŠ¢H’ÀÕ çú`ÃÉa­Žå £càX–&q 鮃‘! ÍÌ›ƒÞnµ˜8†êºh˜fXo¶9]“^`|Þ‰q§Õ¤£q¬s8ŠÓz3ïö‡¦"3±Y`‰E×.ø\³ŽÂ;‡ƒ1’1ñ“¡È\|)‘˜Äâü•pÐí02Dçp°šælîPl!u/óp%,¹læÎx4è:ËÒCm”0>brú# ·2«kÅÒ&¨”J…gùôòü´—7Žàí6DÃXÆCsÉÌ“õòÖNX¶ß• Ó‰ËÁsgi}r(¡·NLÅï®®¿ÙýT=•ƒêÇÊëBþöÕ‹n‹^Ói#Y»'¼˜Y+ïVku`ùr´_yùôþµéó6–@Ûg#9ÞMd‹[{Ç_' ò½Q?úðöùƒ¥ˆÇÎ’]m>KæJ;ÕZãgX~|û¼ÿ¾˜½õ:¸NFŽfSùÍÊaý¤ùT~5µêöƣČ7X‹¤Ò&°BR22‘…¤Éc…¤dd" I0’Ç IÉÈD’"`$’’‘‰,($EÀH+$%#Y!‰’ƒ¼¿¡¾›òÞt9…=Ù‚|¾äU_ÒrAË€]ÐÆ ÁÝìuAmÏ•> stream xí™ëkRaÇç2ç²yô§†y9š¸å L¨1çj/bŽØÈ´E%,爨Aéæ ¤Ëh“½¨5Ü`ƒR‚l”Ñ¿Ö)ð2ñ¼8ð!8ß7Â~|}>p^<Ÿ‚”ÈE@,âÿP¥‚aE1ÀAQ†U=µBŠ©q‚$)ŠŠ¢H’ÀÕ çú`ÃÉa­Žå £càX–&q 鮃‘! ÍÌ›ƒÞnµ˜8†êºh˜fXo¶9]“^`|Þ‰q§Õ¤£q¬s8ŠÓz3ïö‡¦"3±Y`‰E×.ø\³ŽÂ;‡ƒ1’1ñ“¡È\|)‘˜Äâü•pÐí02Dçp°šælîPl!u/óp%,¹læÎx4è:ËÒCm”0>brú# ·2«kÅÒ&¨”J…gùôòü´—7Žàí6DÃXÆCsÉÌ“õòÖNX¶ß• Ó‰ËÁsgi}r(¡·NLÅï®®¿ÙýT=•ƒêÇÊëBþöÕ‹n‹^Ói#Y»'¼˜Y+ïVku`ùr´_yùôþµéó6–@Ûg#9ÞMd‹[{Ç_' ò½Q?úðöùƒ¥ˆÇÎ’]m>KæJ;ÕZãgX~|û¼ÿ¾˜½õ:¸NFŽfSùÍÊaý¤ùT~5µêöƣČ7X‹¤Ò&°BR22‘…¤Éc…¤dd" I0’Ç IÉÈD’"`$’’‘‰,($EÀH+$%#Y!‰’ƒ¼¿¡¾›òÞt9…=Ù‚|¾äU_ÒrAË€]ÐÆ ÁÝìuAmÏ•> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 46 0 obj 627 endobj 53 0 obj << /Length 54 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 54 0 obj 627 endobj 57 0 obj << /Length 58 0 R /Type /XObject /Subtype /Image /Width 45 /Height 44 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`¤€ ð8‘‘‰‰™……°°03112¢iªdaeçàâææáá…nn.V TåL̬Ü|B"¢bâp &*"$ÀÇÍÁÆ‚¢š‰™“WPLJVAIY”•d¥Ä„ø¸€ª‘\ÂÄÊÉ',¥ ª¥ghlƆúÚj R"@Õ̇0²pð K)ë[Ú9»¹{@»›³½•‰ŽŠŒ’ÑL¬Ü‚’Êz–ÎÞAÑqpìãbe "%Ä͆p;¯¨‚Ž¥{p\ZNaI)”æ¤Å…zZë*Šóq0ÃÍÄÁ/©j윘SV×ÒÞí-uùÉ¡n¦êÒ‚œ,pÅÌœ‚²š–Þ±9U­½“§Ï€‚éSúÚjòü¬uäD¸YáŠY¸„åuí‚RËZ'ÌZ¸d,Y8{R{EF¨£¢(²bnE§ðœºÞYKV­ßëW/™Ýßíj¬,΃d2·¨²‘ktAËä«6mÛÛ6¯^8µ­8ÎÃTUœY±˜²‰{lqûô%ë·íÞ»·oX6³³,ÁË\MI1+¸Š‰G\iÇŒevìÙ{vn\>»«"ÉÛ\M’ …£ŠÉ n"……´è&!!1#%Ñ„’(¾ÄžøaÙ*G¶’BÎVð  ̰Ű [Œ#òra/ ‚€E>ZQ@R!Ã.¾$1‹/=,ÅI#P5ž"—µÈe`@*ÌyàT˜³•¢Ï Ò†„j^8 -«† endstream endobj 58 0 obj 580 endobj 55 0 obj << /Length 56 0 R /Type /XObject /Subtype /Image /Width 45 /Height 44 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xc`¤€ ð8‘‘‰‰™……°°03112¢iªdaeçàâææáá…nn.V TåL̬Ü|B"¢bâp &*"$ÀÇÍÁÆ‚¢š‰™“WPLJVAIY”•d¥Ä„ø¸€ª‘\ÂÄÊÉ',¥ ª¥ghlƆúÚj R"@Õ̇0²pð K)ë[Ú9»¹{@»›³½•‰ŽŠŒ’ÑL¬Ü‚’Êz–ÎÞAÑqpìãbe "%Ä͆p;¯¨‚Ž¥{p\ZNaI)”æ¤Å…zZë*Šóq0ÃÍÄÁ/©j윘SV×ÒÞí-uùÉ¡n¦êÒ‚œ,pÅÌœ‚²š–Þ±9U­½“§Ï€‚éSúÚjòü¬uäD¸YáŠY¸„åuí‚RËZ'ÌZ¸d,Y8{R{EF¨£¢(²bnE§ðœºÞYKV­ßëW/™Ýßíj¬,΃d2·¨²‘ktAËä«6mÛÛ6¯^8µ­8ÎÃTUœY±˜²‰{lqûô%ë·íÞ»·oX6³³,ÁË\MI1+¸Š‰G\iÇŒevìÙ{vn\>»«"ÉÛ\M’ …£ŠÉ n"……´è&!!1#%Ñ„’(¾ÄžøaÙ*G¶’BÎVð  ̰Ű [Œ#òra/ ‚€E>ZQ@R!Ã.¾$1‹/=,ÅI#P5ž"—µÈe`@*ÌyàT˜³•¢Ï Ò†„j^8 -«† endstream endobj 56 0 obj 580 endobj 73 0 obj << /Length 74 0 R /Type /XObject /Subtype /Image /Width 94 /Height 67 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x혿kêPÅÍ[£7±M5ŠiÚèÐb¥m\²84´ÜthA”vh§ -V‡NŠ.BÁAq² .J*ø¯Uäi|} Èj[ž¤v<#Ò‘µ|$EÄ Ïyv(Ò¼< <>¿(ÅNçJÒÊyâ$&‰~Ÿ˜—'h†ó‹r\QSÚµžFF¿ÖRª—E?ÇÐçIù°œPµLö6_´Aþ6›ÑÔ„æ!ØXCº9AŠ«z®øh<¿”‘yy6‹9]Kç6Õ™ÝpLÑr÷F¥Zk4‘iÔªã>§)±ð.C­_+åá#Çj¦`¼Ö[íN™N»U5 õ8Â{éµ:íõœ¦²•ú[ï}0DfðÞ{«W²©Ó?4Õaàðìòƨ¶zƒÑx‚Ìx4赪ÆÍåÙa‚ÍÝ¡ _\åŸjíþèc:Cfú1ê·kOù« Y`·ÔƒrR/”Áxú9Gæs:t¥‚ž”ƒ¦:`CÑdºXnv‡“Ù|Ì|6v›åb: q`ýwÂê‹vÆj©°3Ø+¬æxg°3VXÍñÎ`g¬°šãÁÎX9`5ÿyghèä÷;ípöp27Q[™¯o'óõÊ|ÎæUòOÖ¾û¬}÷=koz‚²'(!×åÒ²'(üÛïow^³ãp¶Ÿq­º¥ðouKáU·´ò.—³½ØRÞÁNoy{³dm°é#M_V¿œìR¿…wà ·n¸L endstream endobj 74 0 obj 627 endobj 75 0 obj << /Length 76 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >> stream x…UMlUgתŠ´U+•'þZEi´ * ®:i"×ÍRm×ÏñÖ›Ýewí6QO¹T!® „z¨Z~ÔæÒ^ЍTTÈ©H­ ª8â›õÚY‡CÖzö÷æÍÌ›ùfÆKÔ}Ñð<»KÍ;¡_˜Ìξ<{Ltß .Ò¨‡ðfàeK¥ ÆŽëHþí|î}K)–ÜÜ˾:Ï6Ý¥Ë20¡uË-æD|ÿÝXÏU·©ºú$Ö~uB}NR‡I¨/¨ÔçÕ<¤ÃêþÈÆ‡í¼®çÁ7ޅצ§×¨žŒçÜŽúÏ{ç%ÿUËüæÍß:,ÝvÜsˆ«¹ksöÜ$GÈ­ëÿ³!“|];ûåöD„bU½xüfϵ³t$Y‹¨:åµHßNßI¯âûVz-é#ýCz Ÿ[”E½ìˆÙydÇʈëx0q€ˆê¨+G¿·#Ç؅бéGœ¹‘U€ ü ËZÄT²æ‰žèÈ—sgWœs;<ïć̫|½x¯HK}úÇú/úúwú¯úªþÐÏÑ´ú¤Õ%Q÷)o)Ÿ)_)—”Ï•ë$”+ÊŠrY¹ª|¤|ݧ®(—à…u[=×ì±vfšq1ܱAÄk3o,mEp gë™Kä¶ñ†Î~nߥÔvjjyíaíqmBëÕöi´mÚ Ö€6ªíÆÉÎvߨq5y¶’=kÑlÄf³’UüúˆÒÀg=.žS‹f·E§#‚¨fàÿÓÊs…¹H½‚ÞµÔ]ê€:ÏQV݇I!ž´ÌH&ŸÉ’Èôf†3™ÃŒ}sÊDf7N‡ñ=ÒΈY1“:yÉ„sÚd{}^ø_‰{‰½4€mìd(ÏàE”s½ßš«†bPןY¼"¥sÌþ>aضˆŽáË@ú Yî'~ÿ²ÑG£÷jjëu³î7š2J¥¾&ú"jˆê endstream endobj 76 0 obj 1088 endobj 40 0 obj [ /ICCBased 75 0 R ] endobj 77 0 obj << /Length 78 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream x–wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû endstream endobj 78 0 obj 2612 endobj 42 0 obj [ /ICCBased 77 0 R ] endobj 79 0 obj << /Length 80 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream x…UßoÛT>‰oR¤? XG‡ŠÅ¯US[¹­ÆI“¥íJ¥éØ*$ä:7‰©Û鶪O{7ü@ÙH§kk?ì<Ê»øÎí¾kktüqóÝ‹mÇ6°nÆ¶ÂøØ¯±-ümR;`zŠ–¡Êðv x#=\Ó% ëoàYÐÚRÚ±£¥êùÐ#&Á?È>ÌÒ¹áЪþ¢þ©n¨_¨Ôß;j„;¦$}*}+ý(}'}/ýLŠtYº"ý$]•¾‘.9»ï½Ÿ%Ø{¯_aÝŠ]hÕkŸ5'SNÊ{äå”ü¼ü²<°¹_“§ä½ðì öÍ ý½t ³jMµ{-ñ4%ׯTÅ„«tYÛŸ“¦R6ÈÆØô#§v\œå–Šx:žŠ'H‰ï‹OÄÇâ3·ž¼ø^ø&°¦õþ“0::àm,L%È3â:qVEô t›ÐÍ]~ߢI«vÖ6ÊWÙ¯ª¯) |ʸ2]ÕG‡Í4Ïå(6w¸½Â‹£$¾ƒ"ŽèAÞû¾EvÝ mî[D‡ÿÂ;ëVh[¨}íõ¿Ú†ðN|æ3¢‹õº½âç£Hä‘S:°ßûéKâÝt·Ñx€÷UÏ'D;7ÿ®7;_"ÿÑeó?Yqx endstream endobj 80 0 obj 1047 endobj 39 0 obj [ /ICCBased 79 0 R ] endobj 3 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 2 0 R ] >> endobj 81 0 obj << /Type /Catalog /Pages 3 0 R /Version /1.4 >> endobj 41 0 obj << /Type /Font /Subtype /TrueType /BaseFont /LSHHQU+Helvetica /FontDescriptor 82 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 121 /Widths [ 278 0 0 0 0 0 0 191 0 0 0 0 0 333 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 667 667 722 0 667 611 778 0 278 0 0 556 833 0 778 667 0 722 667 611 722 0 0 0 0 0 0 0 0 0 0 0 556 556 500 556 556 278 556 556 222 0 0 222 833 556 556 556 0 333 500 278 556 0 0 0 500 ] >> endobj 82 0 obj << /Type /FontDescriptor /FontName /LSHHQU+Helvetica /Flags 32 /FontBBox [-951 -481 1445 1122] /ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 737 /StemV 0 /XHeight 637 /MaxWidth 1500 /FontFile2 83 0 R >> endobj 83 0 obj << /Length 84 0 R /Length1 13956 /Filter /FlateDecode >> stream x½{{|TÅõøÌ}ï3û~¿n6»›Í; d ID <$˜ð 0¡Â7*ˆDDyhE-O1KHaáK)Š´VÑú¤jmEk[SÛþжÝýž¹bÈÏöãýtoÎÌœ;sgΜ9ssoZ—-Ÿ‹T¨ÑhÂôæ%óô+x!ªwöâæ%I\?ò×f·µz’8›Ž½hÞ’ù‹“¸ðBrçüE+ûž7´ äÚØ2·yN²õB^Ô7’8yZËâÖ{“¸®ò‹îžÝWo°^»¸ùÞ¾ñч€{~мxn²}é7mÉÝ÷´&ñÐ5È—,Y6·¯=®úÞ@îúÑ$Cw!QHW#Bür'b –ÔÃï®GzfÝ™Rú5Ò ~gÍcR~é§¥ÿÇÜÞ€b³ðO¸!»Ùžä\0DH‰¡¾G±¹¿FzÕeFÑ€2€B€ÌÌÛ,¨ïC<@£ø´`À“Lé `'ñ#]Œ>…W"V0îÉ«Û"W¸ßŠb®ûi÷–OOc+¬Þo±µK…d·Éñ3øGhrã#^…ªQ:Þu,¸ÈÝUÑ€vZJ1>Øå ¹Ïâ,äc0<ãG.wÿ>?ÛýY~”Â]îó(ÙO]€…SÜçœO»ÿ×9ß}àp²êPZwt.rouEñ®.÷gÃ3›“Ùr'Š_è*ss§ñaTl9|Là6Š_„›Ìi|Dºyä„À”€C4ñ /F†(>Ü­!%(ç¤ÅGŽ%o »Rb¤ EÊ@Š(,Ph,ŠàG£Zgj+³”éFj‹«*þUÒ$ÕÜL3ÿõÏ‚‘íãêê#‡œ ‘)$œ 7›[nþeÞºªæ–gfŽ›´òXÛ’…ó*çz+›¼•sš"´µX"í³<ž£ — O„ö7ÍšÝBò湑%Þ¹‘…Þ ÏÑ6é¹AÕóHu›·â(šW9¹þè¼ðÜŠ®¶p[¥·¹¢áجòe·Œµ¡¬eåß1V9élk–ôÜ ±Iõ,2V#«‘Œ5+ñbâ*ÐDès-Ô¼™ŸèD:”…ÊѸ»Å>úJ¢YP P·ýíE?E_âpw¢%Ñ–¸œø-ˆª9P\«q7þ-ÝÉ<”Ø“øc"œHG0jÚŠžƒþ;á:ªµß…[ñV¼ SPÝÌ:Ö‚h4\Õènô0pà$º€þ†þ‰¿¢,´†n¥_N&þR q0K2“¹¨ ®õpm‚9ÆÎãð¼?·á_QÔªžZAÝK}N×Ò3è•ô¯˜{˜.v#»“SÄ¿NœN\L¼ƒÌȉî@ËИÝyt]C×1 }9°—àr<®v¼›:‰÷â“Ô|_¦áßàOñWøÅRJÊHeR­ÔVê0užz^@o£Ÿ¤CÍŒd)v/ûçãŸß=Q’ømâ b$ÂÊ”£Zt'j†Ù.ACÐÿÀ,ŽÀÕ «v½Œ.I×§ØzÐ?€ ë° ‡p \µøv</ÀOãSp•hù†‚… d”–2SªŽšE-¦Ú©w¨vÚNgÐcéét'\¯ÒïÒ7è Ëè#3šƒ62‹™]píc0]Ìl1;’­e§²íìv#=›}“}—[Ãm⺸¯¸¿€ZÏßÍo„Õ¹2ûSåo NêCèh6®À³ÐvX½¸u€tÍÁ¿– ôD#½†Må4œE?iÝ…V£ ô ´7ñ>}½’²ºlGû™rädwÀê<€ò@Šú®p0#˜ðûÒ¼©¢T¾Ãn³ZÌ&£A¯ÓjTJ…\&ðËÐFY•Þª&OÄßaüÞêêl‚{›áFó€M°•=‘ª[ÛD<ä¹f¨º¥eZÎÔ2œlîo‰5žRTšå©ôz"¿¬ðz¢xúÄz(?ZámðDz¤rT~\*« ,Šð€§ÒÒRá‰à&Oe¤ª­¥£²©"; Ÿ ;äÙYDq„‘‚tA£šWƒ‚E£H‹ÊˆÍ[Q±z¡ u´¯²yNdÂÄúÊ »(6À=¸5©ÆÈÎZ:Ñ#Ê9Þ9DÃhV)5ϨÐÍ ª‰ô¥ÍŒ˜½óªÏ,ߢ7K•TF(_UóÜŽªH¸é`.A›Ö¼°què–Z×PÁëúˆ 4.J ¹I›àkZè‰È¼åÞ–Ž…MÀ\4©¾Ë¶IÊ7‚&ÔwYÃV ÉÎ:iYS"ÂìOfß–}ÉKDËšdþû“÷ß:GrËš Ÿ@>nR?0á€w ÐñÌ–ñ±ÃH2wê˜= ø¿ Ó\ôŒŠP 3´/ÂúÆ4GÚën’ÑR‘$®iaE—Ìj“ŒPy´oêÐ ‡•‚ö¯§ãk°ÖMÞž/o½ÓÜw‡ói¾F¤’,t¿¬DpóÍr1–>˜u‹ÅÛBÖ·MZSÀ½–Ê7'¬!4G `À'Ô‹OÜo2k\É&ÔÅxSC'ÖEQ…ó$ø¨ô3¡:‹ˆÚ‚ ì,¸‘!B)'ËS#WYñtx:ÆÌéðTyZ@˜Ÿ”CÅÜŽ†\à`]=ð M†à öþâ܆†áÐO.éæ Ðþ —n寠Q^SÚ?¡~b}¤½Â W4À*€øž›P9’ÛЭòû)ŠW/°ôÑšó3 ¾ Ù ø.íÐECGé³®Þ+FÎutØ;È~KâQŒß÷݈"Ò„°<ŠÛ'À³yE»´¢W²O‡€Hß”(ðÙÿ=‡‹úé†'‡µE‡‡ý‡8\ü}8<ü{q¸¤ŸÒ[8\ 4—øïqxä-.û÷÷Ó DÞÔ†%—ÿ‡8<êûp¸â{q¸²ŸÒ[8\4Wþïq¸úù÷ÛO79¨+qxüˆÃ5߇õߋ÷÷Sz ‡'Í·OüïqxÒ-®û÷žÜO79¨,qxêˆÃÓ¾‡ë¿‡ú)½…ÃÓæÂá;ú9¶GÐ@=Ü>Hí¢ÿ¸bž1€åà)±:TNCì¼í¡¡)ìTäØ1ØtÈ;™OQ'WŒfC›KÌ=hwí|©ƒ6Ý7Aʇ ~@ç%¨†çX‹/J°úXKpÒ® ÆÝÏ:Ì€·CÙ¤Ýë¤@Wªq=nÁôÃôf§ü <*‹Ê¹t9F<ÇaJÉ ‘#žÅ1Íx r¹O÷ ,ëÓA…‚¥er†c±‚Â4¢\¼Å a„?œLN³€ëT*˜#û4~ZnUªöŠgÂ,­µ×,5±˜UšiU…•™KËJkb¥±RmqÖꊋáO[œ»>'sµfxiÌ9{„¹Ð°>ÇÒwƒ†ô…†Ì¾¶ë5¥¥<°¬±5bÖ`/-Ò^LoúMϺßRÆ+Ûb§ôõ85Ú[AϾ> GãÕÒjì¾0P’ƒ,¦£Â櫦kR U µ«¨"?FU­¥œ‚;…që‡Áe¦®€ÀäÛ¤ä{m2£/Ýd fDñÇĶyÒB’ùÔj¾©é¹ÖƒÊbe=ºâÜX1™[~Þ¨•aÅÆ Vçç-L&fmB&F™Ž|î¿f€CC‹ ‡ü^Q; H‹kòoJæAL]XSõƒååÄŸÂGNÔæ?6~u|ùϨ˜Z¾=X³tØì†uñc[é Þ¡=rÄ‹cÓŽºó™áîØ V¿ëŽ4ä2‹šnºçŠé‰+ìRö3DvßÑp‰Ý·³´»™ðzvƒž­臜Z­‘Ã2årYé|ªD“¯µydùV«Û³W\˜d@MOßôa樬¬Gbä¦?9Ì>½_í³û&Y© šÖiS4¼0Ñ!Œ)†–[”!”¢ƒD°q!Ì`HȹÖ”jJ33“)¹q#n°Ù›ƒ½©H«Ñ‡p<'z~­fh‘èe\xˆö¼ør×ñ¯ÿúÕ‡÷Œp·m錿—@/~öÂ)<:ý,~åô¦}ñ7â/Çãñÿ=ذù‹§Îìþ%~W^þ¤':AOô€œýVNã] £ ]p\*\r… ¤”J q ¨™MM >dU©£XqLܶ¡okKqí*áˆ{Y©$ɽª…ýJw2¹½[éÌÞwèûnœ§Üì™îxù¡¸º†–ô¡ã 2T¶*d}Tpwa›BY®ˆâi0ò‡G¾J< ·“¾Ñûõf,÷¢4Pglщ³ó#Iû¾içÂë(Ú‰ÝìCxƒã¸‡ )ŒÑDk›Ö˜¨“VÅ<”ªÑºô:‘žJÕp›ÌKy½´KÅãšɧK4>½Í'ÏwYÓà |þ1qá’$}²Óôô1§$Ø<’n7ö©I|²ì"R:|?ö)ír1!LÑ,£pªBHææC˜¥ ÷7F"+ÈlÒ÷ ‹JÓ‹…¢ÖñÞ˜ýùŽ_翜ö»^‹ÿásÌ\Ä,B­kÏ›[ûàÏã7^úå«gqŽÈ~:ážø'{·Æ_¿¿?ñ{Lý¸÷ÏgîÎ{ðm¼ /½r™ØU 'Vo5£‘™¼q9%ßœL8_%¦…ÊÍË×h½—.]"&ƒØ XãqОEùa=¢hÊŰmã1å…ÏÁ»€:P5D›Ö^Kª°¤PÂFÈ(î¹H}Ñ;ºû['ô:Ž3Czô‹pCJËh¶ÒïaV´AaWNÃõôÛø×ôÛŠ_+匜QURQÌDjEåéªaòaªÑÔ4ªâ}sTrŠÖјR(u4'AË3Ä í«änZÁÅ”˜Š©Ü°ô»ë‘ÕÐ ]«!¤^µ^+.†?ËU¢ “Ǝ蹎óª”Q|¨›ÂáC]E¯gkrVŘÕÖ³É=Ëž¹ág®\EÏξ¼âFy/»è£!½OÁºÀ»ÅÄ;ì ç)à{8PG8k=8_ñϨW…Krn”`žBÛ‡ó2åp(tù´ÍeÉWX®÷©¹~%' hÙT œ2ë7©-!ðrt!l ¤á dVCXOAb•ÛCHË@BdSRn’ÂÛ@³I«á©>¦‘®Pƒˆv3èDšÙ}zËþ ñmñ#çyÅocÍõgñʯáh¹4~1þƵøQv&ìq¢Gþ2!úšÃ… ” t+•«tLµ¡ÞÐbXe`xÁ¥ÕhäXB´œ\ 8’‘ ùŒÍ”"g4}‡‚‹ia)“úM“ܸ1?¯Q/†Àzq`Ó¼H2mb¨¨°“Úvá/ï~]¤Ûï-¿'ÞŠ7>´Ÿ=óÑ«/$b[™“ÃÝqzÙãDÁ«,ö^ U†艰ŽWÁÕl®g°s ÷²‚é4À[‘;Âå^ÑãoÒ-Õ-7Ð:—Ûà0Ò¢Ëd`üº4Ÿ ÉdvÞ¥ ü»àñÝ>Ÿ²Àn ~_@nM¾+n»Õ€_ëy.Ø\¥e±ätеfÉ’/¥ôU&q;0Ì&i²i1Dì3Ç»°ƒ©6AÕäb¿4i/=zãsËFÌ‹Û.R,~cñ¬©ÓXžVèr®É•Œ’ŸS¼*^r‘v,ÙòT± \·½ù3ckx—µ¿<9Xeõ¥S¿~<ßëž4%Þa¾ÙÍ…3êxxf0%àõû‹Ô…âhÿ,ÿ*õŠ4Ù]‚EmöQ êõ¡TZ®žš–*§‡å!Cnn¦c¸f†gÊò(¹ZЦ¥ºÓóò´ŸyŒàK·…Ü>íä˵懞öY0pf¾5ê:-øiŒ;YùœXAãRiÔ¤çhÝH ü”?ÛÇùl~: e¢ì)c3ÀçqêÝ™Èn´db«g3™HPdbŸç@™BâÒ9 Ò‰´C4I™“=B<ò»ÿþûÁã>£O–@buá´‚cô®§rFƒÙ$­…ÑÀ ?c?döõ%3ºÆöâÏ&nĺ¿Ç£N§äßq%²kzÉå×·MÜêOñ?ïÞMS5øÊêÚ-ž‘ÏÜ[òegÎ8ñJü7_·•ÝóĬE!O^njÉü ×ÞÚøÈŸÑõ"ì+Ðã Û0çB<Å2âëß hËÜà¬q„AÖ\ w­Ïå—ô7ȸ^­XÈ\Škײg:¯ÿUÃf%ûàØå\è›DM¥a¯™ °Ã4´QìpÌD›L™Oi³`ŸÁj¶<#n»Å¾ÞTR¥°±x"±L[T4´ßŠEÜZÚð«Øù?óP|c|ãº1Ô(öLoë3 Ÿ92óGôÆÞ‹ñ¿n‰ƒå[p ] úsRâCéMN ¼£+E…‡eäa¹l‰#PP­Y [¨á‹RFÛC|šÌ©Q:K2©œ`ɉª$”áÓixVpRÍŽ(î€é8Ý|À™£ œ…ŠR¾´ÔaàƒÒl#íAÇØ”À0눑/áÀà“x;êó’"y5váæìÀÓ׈"Ùœ9=9=Äw€=+ ezÑPc*ÂV.J‘Å®„Éc±˜Š†R"²9Í",$}~÷"Ö˜&ñkVã ®‚ù—Ü;m¯5@#B žhÀ ™¿pHÑP=V/«½³a»ØZ<+¿w4*\õh‰(?Àþý¹3mËÍ>¥K›‘åoÌ0Ɇ¾~ß¶3§vt¼1=k̾ÍF§V9rçãEB–%{FÝøŒºWvWWïŒíp¤Òô:%Wî W/üÉÃÛž×ã«DFÚ3>ö<ÄÝ.´$œ³ßïxÏA§ ).ŠEÈìdy­ÜåT( Áæ±åhrpiÁu_/ži¼éP\½*mt~;üi!“¸gÑ™8¹‰3ø±N‰‘7û±^æò³Àx‘Îa…Nk $½iI&I›° ­³äù¦WÿùÍ•U“CÅû¨y›7?úÓþÑçÙó±?ÕLŒ÷įÅã‘o͆Õ_œ=øññ7wÌ<*É=¼½¤/3µÒÁþpî~+Þi9 ²ÐcínM8§W9Á‹áív³& Ãt€ÒÚœò€Ùê€O:øcâ²Õßúš¥5=ÅÅÄÁ ¼¤ AVÁ§4ÊýH­×À,ILb bQŠI&•bHdÎObñ;b¢’‘)‘€¨$¥¢€ˆv¼€§ÞýÔÜ©Y¶æ…±yoYò µÓõ—Óo]Ǻ·Lmä½ÙXüÌÞ7¬xçe\ð9¼zκK\¡{`]ȉV„CCÕ£ÕÓÔû™ƒvÖ'¨§ N'¯—SN³‚ÍÑçh‚ZÍ­ج.÷zqYùÀéÇ®B4pëÚÚ,™alQÀÜ +åGr»à‡ J« ³Òñ–„ž3‚‹båá-$ÓB…CtßlÙ»zï¾UÄuy#Ž<[öÂÝÇâ׿úßùÅ{—~ñ³Ë?§†q£œ×Gn›]³¯ÿOR¸ÂØàm°Îy|X^¹CxÒ¶ßM³j*…5Õº£!¬ „  S§/âWè‹ö÷…dïºß÷~aþ«¸¨½¨£f¬˜–²ËäL+æxÞ$:¼ÜiRøøŽýްŸ)Åç`­r%¯URœÖHËáV«?ð¶¸/)üà¡J¢ÿvL:…#rûåäfD"IKò2, ¯Ú1Ëpnˆ4u½Æ a8¥/Õžæ‡,§»œ23ïG £ÚUj¯M„[,$‚äJ¥$éü%CZÐ7™÷ã¥h)œeÿÁd]°¥HH«Æ k8)ÈE’K‘ÊALÐýî°"¦÷+öñNÎ3åoÏŸ´ò¶I¯Æÿˆ-¿ÃnEúØ#÷`±—}×”‰‹Æ>ûÜËE£K6çLphÀo†Ã\÷/¯zàX&´ s€"1³oÁÉ\M8“wrr'S Å&§“[Á”©UÚ YÇëRÔn5¥î5X-Ö^qþš¤ˆÅ‹/H¡Û@ÃV^T~žnhQA\¢ÎX`ô‚©óþÄ[Ö­M3;¬ŠIž®î®mÛØò!3(êy OyqSïzϦ@FÄKè/@VÜ(¾P9®)2ŒÆÈê…ÙÃʃö΃}™'튰@›Rƒê òT0) tZå:§<%‡ÏÉatŽ)';ÈÚò”ê€j¤?à°ææ Ø ×zЉÄ®~ÝŒ’’ D¥uÏò¦Û\ mšOã÷ºü~”nƒD«P‹(E­Tùœ©~°AO(Áqï3$}þŠä®SX …³1Õ(ès^$k‘¦õ€$£"i 01˜ºofAá¾Ò%ñKG¾TŸPF<øFØOí\ýbüæOáŠçÿçl•oë}çoÏŠ¿É”ôŽZßz­íÊîWJ·LýhÒ„¿CP¤Â9ñ½çºîÜõ“3³×RÙÒ:¯¦bBuá,Ø5‚™7 & _Î/½ŠÒÃé±ÖÉñF¥\”ƒga "øð¥ß1qVR§ôŸu—,Y‹bLι$c62i!JKúbZïÚîpÁ´þP—}Ò•¿~ÉñnPþN‹Ÿkx:6‘z®mhý®wc¯9¤à+ „KÀß!g³EaÿÂÉÑrâNÜy¶ìз”\ˆ•^è;é•ÖZ´µ'àÇdÜx—=óš4÷ Ð79¥Q0 ³¤åä<úDäDv@—§&ÃÔdlíÝÐÝ-EédŸ}œ _s® —ð¯æRÌ‚YmN P1ÕÖ©Šù ¥×'·9½V9Ř}¢ÓìTq<âì­—§Ã˜Ú |¤‡»lAòm"ëâ5ŪL¾ª¹Ösíæ1ÄÌà0öÀI2¹ÉqcÇÍ7=`¼ä“8¹ºÂC–¶×f¥•>;÷ýÚŒÓwÕ,|ò„-¸dÞþn&wçíi#ÊÒª¦Ö홼)6”úâ® ›öÅ6S§‡Æ=ýYi]è؇äÔ~f8ÿw‘£ÎÀ m\+Ï””Á¢Oq…ÜÆÛlH”Ù8Ç´"«ܽ[Ä'©r“öæÕaEŸað(Œ¦Bf:P!ÔÇk?ÔruBÖ gÞšppì°l{7ÞôÏœô£iÏYšU:Ge*/\º ö +]’ø€ÁPJoì¶kž4ý˜9 ìÓ4E…W…÷˜ÏÔ0(‡ œÓÂ+:…•·ZT Åf—ŒV›=ŠeàMôY‹d@ÔïI$Õ¼zñ+ô2ÐìZÊy3”X”ä¥a $‚ œZ q0¥$ÌkšN "IÄb*ÐÁQ&%‚e•†OÖå?õãíÛŸƒózãÿ(Þ‹u¿çZqʾí3Ÿèí:|•¾ÿܧXüEœÙ Nj˜ø mñ)Œ¦®†“¼ÖpÖAa¿™J<­šsùNít(RÕTÀbK“ƒ'(SS¬Þ´ïô%wA FQš£ÃdG¬ÍÏø‘&Æš ÁVµÑfiNÒŒˆ?H¼¿äš‘ ¬$å>˜"v \d­—ze¿¯êÔéJ¤ñœÎ¢ð?<?Ѻk夼’î•¿z«}ÆÑÓsvÝ7m}tÓ˜ôÒø`ŽÏn¿³Ð5&öÙƒ°©-°µèö°?@ûUCéÑ £4”Z¦•)C­\°é1ñ‰U§âJØXIsEΤjá¥IYYMÙ…ØÐù}çôDI¢×o¯´Þ ‡ÏßÅZœ»æá-°UNí¦è³4Õ¹,¶“ì‹òÄ{ôqfئ\œ~l˜l'»]÷¤a§qg—žæ ‰Uâè´Ñ©iÓóÒæûW*WªVªÛ¼­i­¾Vÿ>×,= ®›Íäè‘Íh7;,ÆlCNzŠbœPù(_ªJÎdê-¯8œzžqæìÊTäò2µ†âQ®˜ks[L–€ydºŸ¤ÛòÕî€f$ äXóò»úýP!IûV¬™nq. ’‘<‰žˆJI†ðãq6å7Bè.ªÝ"’ÁgÉ¢w±PrêàžÝ`±'%UDbªZ%ä"öûdrˆæEø—Ö!’>Q%í¥“û¤ÐKñ‚wzÉ JâÒÂK–ƒÿÿcx%ø*ÌÙ9"pÏcnkýõÉ¿Ý5Š:ÄúG>9oAezíŠóå >øø«‹<>'LÏ›6íŽÊ4ð S3ÆÜ¿ó¥MÓ[F„F׆«2¬zgnVå]þàêŸ KæÄW”ŒÚaÒOT9òsjÅeac*6ÓœZ®µº†/4ƒÈ¨6¦Ðnš¢{MV« |Ÿ¾èbï“K”t¬´G»*ÌG ¼ûbD!q?|ØoÌW¹ îQ5Ó7of§ÇßÙ«¦W`j“L¸>õòVɶ'>¥?†ýLޘΠ^5P2½`°ê­†tný˜pĪåˆSÉYÐ]Þb%GT*l6$ľuÓZJ¯hˆø÷û9e¥D ˆé†­'Þ¡’ßz}x˜-ïÁ—*|݇(ïù[?«Ë&¯,bÅ“†4˜þ¥¾ñæÓ#2&?9iõ¾ì c|Œä³‘w¼?ÿ Ãø°e¿…æ937LW­«×ÍçWÐ+ø†ð¦|§q‡i‡ù:`ÒT£qÆÑæKF¦‚}…¥Ö³ûÐ>¼Ÿ=`fÓÒY‹Ñl?À¨T¤85QÐ&;¬ ‹p§ÙhéT>f=ývÒ!…×5W-±âbøK¾s´$ÕuM¬8d͵ÀÉ^)ÙópúÖá`Å´Xg6[XŒÃ{k ¼„Ô¬¾ eä˜n-…à®p4ÅS’0½hèH<`š/úœU¾§}?èÊÍЄr5ìHu¼õ58drçÇ7Ç¿|1>¯›žWq¢Ex"©íÝI?@x%ýsáûâïúA&‡wê)Ï‘_-gÀÓä0nc!*BCáëë T‰ª¤¯™ÇÀüä›åÛ¥oª'ÁwÒSàÝù4TfH`x7¥½¢ñuÕÕ§dVÏ]Ô6·uÁìf¨IÖ’&ϼðñ H¨ð%@/4R8²JÆÌXpÀF€=/¼ðÀ‡_ôÂÄ•€,€R€ñ3ܰ`À /¼ð!À—‰¾ÐúËyáA8ñ~¶¿m^>5¯„W ÂGÂÁù¸e¼ñƒðšAøíƒð ƒðIƒðºAøäAø”A8YÙóŸ5Ÿ=Ÿ3—äs¿ç ªŸ?o„/„/„Kÿ¿5 ÿ ª¿{¾d¾l~Ï ¼u¾|¾’àÿõ“W- endstream endobj 84 0 obj 9300 endobj 85 0 obj (Mac OS X 10.7.5 Quartz PDFContext) endobj 86 0 obj (Tony Raymond) endobj 87 0 obj (OmniGraffle 5.4.4) endobj 88 0 obj (D:20130919180507Z00'00') endobj 1 0 obj << /Author 86 0 R /Producer 85 0 R /Creator 87 0 R /CreationDate 88 0 R /ModDate 88 0 R >> endobj xref 0 89 0000000000 65535 f 0000038757 00000 n 0000004135 00000 n 0000028386 00000 n 0000000022 00000 n 0000004115 00000 n 0000004241 00000 n 0000005579 00000 n 0000005897 00000 n 0000004590 00000 n 0000004909 00000 n 0000009347 00000 n 0000009652 00000 n 0000004929 00000 n 0000005234 00000 n 0000006256 00000 n 0000006561 00000 n 0000007455 00000 n 0000007760 00000 n 0000008697 00000 n 0000009002 00000 n 0000008105 00000 n 0000008410 00000 n 0000005916 00000 n 0000006236 00000 n 0000007115 00000 n 0000007435 00000 n 0000005254 00000 n 0000005559 00000 n 0000009022 00000 n 0000009327 00000 n 0000007780 00000 n 0000008085 00000 n 0000006581 00000 n 0000006829 00000 n 0000006848 00000 n 0000007096 00000 n 0000008430 00000 n 0000008678 00000 n 0000028349 00000 n 0000024368 00000 n 0000028533 00000 n 0000027141 00000 n 0000018169 00000 n 0000019044 00000 n 0000019064 00000 n 0000019881 00000 n 0000014705 00000 n 0000015522 00000 n 0000009672 00000 n 0000010547 00000 n 0000015542 00000 n 0000016417 00000 n 0000019901 00000 n 0000020718 00000 n 0000021528 00000 n 0000022298 00000 n 0000020738 00000 n 0000021508 00000 n 0000017274 00000 n 0000018149 00000 n 0000011404 00000 n 0000012221 00000 n 0000012241 00000 n 0000013058 00000 n 0000010567 00000 n 0000011384 00000 n 0000013078 00000 n 0000013848 00000 n 0000013868 00000 n 0000014685 00000 n 0000016437 00000 n 0000017254 00000 n 0000022318 00000 n 0000023135 00000 n 0000023155 00000 n 0000024347 00000 n 0000024405 00000 n 0000027120 00000 n 0000027178 00000 n 0000028328 00000 n 0000028469 00000 n 0000028959 00000 n 0000029184 00000 n 0000038575 00000 n 0000038596 00000 n 0000038648 00000 n 0000038679 00000 n 0000038715 00000 n trailer << /Size 89 /Root 81 0 R /Info 1 0 R /ID [ <8b679f89bbe65216fd699706f18e3180> <8b679f89bbe65216fd699706f18e3180> ] >> startxref 38863 %%EOF abyss-2.2.4/doxygen.conf000066400000000000000000001441251361462241400151760ustar00rootroot00000000000000# Doxyfile 1.4.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = ABySS # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = YES abyss-2.2.4/kmerprint/000077500000000000000000000000001361462241400146565ustar00rootroot00000000000000abyss-2.2.4/kmerprint/Makefile.am000066400000000000000000000005061361462241400167130ustar00rootroot00000000000000noinst_PROGRAMS = kmerprint kmerprint_CPPFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/Assembly \ -I$(top_srcdir)/Common \ -I$(top_srcdir)/DataLayer kmerprint_LDADD = \ $(top_builddir)/Assembly/libassembly.a \ $(top_builddir)/DataLayer/libdatalayer.a \ $(top_builddir)/Common/libcommon.a kmerprint_SOURCES = kmerprint.cc abyss-2.2.4/kmerprint/kmerprint.cc000066400000000000000000000066111361462241400172040ustar00rootroot00000000000000/** * Print a kmer file. A kmer file is a serialized Google sparsehash. * Written by Shaun Jackman . */ #include "Sequence.h" #include "SequenceCollection.h" #include "Uncompress.h" #include #include #include #include #include using namespace std; #define PROGRAM "kmerprint" static const char VERSION_MESSAGE[] = PROGRAM " (" PACKAGE_NAME ") " VERSION "\n" "Written by Shaun Jackman.\n" "\n" "Copyright 2013 Shaun Jackman\n"; static const char USAGE_MESSAGE[] = "Usage: " PROGRAM " -k [OPTION]... GRAPH...\n" "Convert a binary de Bruijn graph to plain text.\n" "\n" " Arguments:\n" "\n" " GRAPH the binary de Bruijn graph\n" "\n" " Options:\n" "\n" " -k, --kmer=N length of a k-mer\n" " --ray output in Ray Cloud Browser format\n" " --tsv output in TSV format [default]\n" " --help display this help and exit\n" " --version output version information and exit\n" "\n" "Report bugs to <" PACKAGE_BUGREPORT ">.\n"; namespace opt { static unsigned k; static bool strands; /** The output field separator character. */ static int ofsInt = '\t'; static char ofs; } static const char shortopts[] = "k:"; enum { OPT_HELP = 1, OPT_VERSION }; static const struct option longopts[] = { { "kmer", required_argument, NULL, 'k' }, { "ray", no_argument, &opt::ofsInt, ';' }, { "tsv", no_argument, &opt::ofsInt, '\t' }, { "help", no_argument, NULL, OPT_HELP }, { "version", no_argument, NULL, OPT_VERSION }, { NULL, 0, NULL, 0 } }; static void print(const SequenceCollectionHash::value_type& seq) { const KmerData& data = seq.second; cout << seq.first.str() << opt::ofs << data.getMultiplicity() << opt::ofs << data.getExtension(SENSE) << opt::ofs << data.getExtension(ANTISENSE) << '\n'; } static void print(const SequenceCollectionHash::value_type& seq, extDirection sense) { const KmerData& data = seq.second; cout << (sense ? reverseComplement(seq.first).str() : seq.first.str()) << opt::ofs << data.getMultiplicity(sense) << opt::ofs << data.getExtension(sense) << '\n'; } static void printFile(const char* path) { SequenceCollectionHash c; c.load(path); for (SequenceCollectionHash::const_iterator it = c.begin(); it != c.end(); ++it) { if (it->second.deleted()) continue; if (opt::strands) { print(*it, SENSE); print(*it, ANTISENSE); } else print(*it); } } 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 '?': exit(EXIT_FAILURE); case 'k': arg >> opt::k; break; case OPT_HELP: cout << USAGE_MESSAGE; exit(EXIT_SUCCESS); case OPT_VERSION: cout << VERSION_MESSAGE; exit(EXIT_SUCCESS); } if (optarg != NULL && !arg.eof()) { cerr << PROGRAM ": invalid option: `-" << (char)c << optarg << "'\n"; exit(EXIT_FAILURE); } } opt::ofs = opt::ofsInt; if (opt::k <= 0) { cerr << PROGRAM ": " << "missing -k,--kmer option\n"; die = true; } if (argc - optind < 1) { cerr << PROGRAM ": missing arguments\n"; die = true; } if (die) { cerr << "Try `" << PROGRAM << " --help' for more information.\n"; exit(EXIT_FAILURE); } Kmer::setLength(opt::k); for_each(argv + optind, argv + argc, printFile); return 0; } abyss-2.2.4/m4/000077500000000000000000000000001361462241400131635ustar00rootroot00000000000000abyss-2.2.4/m4/ax_cxx_compile_stdcxx.m4000066400000000000000000000454561361462241400200420ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and # CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) # or '14' (for the C++14 standard). # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is # required and that the macro should error out if no mode with that # support is found. If specified 'optional', then configuration proceeds # regardless, after defining HAVE_CXX${VERSION} if and only if a # supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 10 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], [$2], [noext], [], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do switch="-std=gnu++${alternative}" cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done fi]) m4_if([$2], [ext], [], [dnl if test x$ac_success = xno; then dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx$1_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi fi if test x$ac_success = xno; then HAVE_CXX$1=0 AC_MSG_NOTICE([No compiler with C++$1 support was found]) else HAVE_CXX$1=1 AC_DEFINE(HAVE_CXX$1,1, [define if the compiler supports basic C++$1 syntax]) fi AC_SUBST(HAVE_CXX$1) ]) dnl Test body for checking C++11 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 ) dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201103L #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual void f() {} }; struct Derived : public Base { virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L ]]) dnl Tests for new features in C++14 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L ]]) dnl Tests for new features in C++17 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // __cplusplus < 201703L ]]) abyss-2.2.4/m4/m4_ax_pthread.m4000066400000000000000000000326761361462241400161620ustar00rootroot00000000000000# =========================================================================== # 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 # Copyright (c) 2011 Daniel Richard G. # # 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 . # # 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 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 ], [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 ]], [[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 abyss-2.2.4/vendor/000077500000000000000000000000001361462241400141405ustar00rootroot00000000000000abyss-2.2.4/vendor/Makefile.am000066400000000000000000000006421361462241400161760ustar00rootroot00000000000000noinst_HEADERS = \ btl_bloomfilter/BloomFilter.hpp \ btl_bloomfilter/BloomFilterUtil.h \ btl_bloomfilter/CountingBloomFilter.hpp \ btl_bloomfilter/vendor/cpptoml/include/cpptoml.h \ btl_bloomfilter/vendor/IOUtil.h \ btl_bloomfilter/vendor/nthash.hpp \ btl_bloomfilter/vendor/ntHashIterator.hpp \ btl_bloomfilter/vendor/ssHashIterator.hpp \ btl_bloomfilter/vendor/stHashIterator.hpp abyss-2.2.4/vendor/btl_bloomfilter/000077500000000000000000000000001361462241400173175ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/.clang-format000066400000000000000000000003031361462241400216660ustar00rootroot00000000000000BasedOnStyle: Mozilla AlignAfterOpenBracket: AlwaysBreak AlignOperands: true ColumnLimit: 100 ContinuationIndentWidth: 4 IndentCaseLabels: false IndentWidth: 4 TabWidth: 4 UseTab: ForIndentation abyss-2.2.4/vendor/btl_bloomfilter/.gitignore000066400000000000000000000005171361462241400213120ustar00rootroot00000000000000INSTALL Makefile Makefile.in Tests/AdHoc/BloomFilterTests Tests/AdHoc/ParallelFilter Tests/Unit/BloomFilterTests aclocal.m4 autom4te.cache autoscan-*.log autoscan.log compile config.guess config.h config.h.in config.status config.sub configure configure.scan depcomp install-sh missing stamp-h1 test-driver *.Po *.Tpo *.log *.o *.trs abyss-2.2.4/vendor/btl_bloomfilter/AUTHORS000066400000000000000000000000131361462241400203610ustar00rootroot00000000000000Justin Chu abyss-2.2.4/vendor/btl_bloomfilter/BloomFilter.hpp000066400000000000000000000274261361462241400222610ustar00rootroot00000000000000/* * * BloomFilter.hpp * * Created on: Aug 10, 2012 * Author: cjustin */ #ifndef BLOOMFILTER_H_ #define BLOOMFILTER_H_ #include "vendor/IOUtil.h" #include "vendor/cpptoml/include/cpptoml.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const uint8_t bitsPerChar = 0x08; static const unsigned char bitMask[0x08] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; inline unsigned popCnt(unsigned char x) { return ((0x876543210 >> (((0x4332322132212110 >> ((x & 0xF) << 2)) & 0xF) << 2)) >> ((0x4332322132212110 >> (((x & 0xF0) >> 2)) & 0xF) << 2)) & 0xf; } class BloomFilter { public: /* * Default constructor. */ BloomFilter() : m_filter(NULL) , m_size(0) , m_sizeInBytes(0) , m_hashNum(0) , m_kmerSize(0) , m_dFPR(0) , m_nEntry(0) , m_tEntry(0) {} /* De novo filter constructor. * * preconditions: * filterSize must be a multiple of 64 * * kmerSize refers to the number of bases the kmer has */ BloomFilter(size_t filterSize, unsigned hashNum, unsigned kmerSize) : m_filter(NULL) , m_size(filterSize) , m_hashNum(hashNum) , m_kmerSize(kmerSize) , m_dFPR(0) , m_nEntry(0) , m_tEntry(0) { initSize(m_size); } /* De novo filter constructor. * Allocates a filter size based on the number of expected elements and FPR * * If hashNum is set to 0, an optimal value is computed based on the FPR */ BloomFilter(size_t expectedElemNum, double fpr, unsigned hashNum, unsigned kmerSize) : m_size(0) , m_hashNum(hashNum) , m_kmerSize(kmerSize) , m_dFPR(fpr) , m_nEntry(0) , m_tEntry(0) { if (m_hashNum == 0) { m_hashNum = calcOptiHashNum(m_dFPR); } if (m_size == 0) { m_size = calcOptimalSize(expectedElemNum, m_dFPR); } initSize(m_size); } BloomFilter(const string& filterFilePath) : m_filter(NULL) { loadFilter(filterFilePath); } void loadFilter(const string& filterFilePath) { std::ifstream file(filterFilePath); assert_good(file, filterFilePath); loadHeader(file); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) file.read(reinterpret_cast(m_filter), m_sizeInBytes); assert_good(file, filterFilePath); file.close(); } void loadHeader(std::istream& file) { std::string magic_header(MAGIC_HEADER_STRING); (magic_header.insert(0, "[")).append("]"); std::string line; std::getline(file, line); if (line != magic_header) { std::cerr << "ERROR: magic string does not match (likely version mismatch)\n" << "Your magic string: " << line << "\n" << "CountingBloomFilter magic string: " << magic_header << std::endl; exit(EXIT_FAILURE); } /* Read bloom filter line by line until it sees "[HeaderEnd]" which is used to mark the end of the header section and assigns the header to a char array*/ std::string headerEnd = "[HeaderEnd]"; std::string toml_buffer((line + "\n")); bool headerEndCheck = false; while (std::getline(file, line)) { toml_buffer.append(line + "\n"); if (line == headerEnd) { headerEndCheck = true; break; } } if (!headerEndCheck) { std::cerr << "ERROR: pre-built bloom filter does not have the correct header end." << std::endl; exit(EXIT_FAILURE); } // Send the char array to a stringstream for the cpptoml parser to parse std::istringstream toml_stream(toml_buffer); cpptoml::parser toml_parser(toml_stream); auto header_config = toml_parser.parse(); // Obtain header values from toml parser and assign them to class members std::string magic(MAGIC_HEADER_STRING); auto bloomFilterTable = header_config->get_table(magic); m_size = *bloomFilterTable->get_as("BloomFilterSize"); m_hashNum = *bloomFilterTable->get_as("HashNum"); m_kmerSize = *bloomFilterTable->get_as("KmerSize"); m_sizeInBytes = *bloomFilterTable->get_as("BloomFilterSizeInBytes"); m_dFPR = *bloomFilterTable->get_as("dFPR"); m_nEntry = *bloomFilterTable->get_as("nEntry"); m_tEntry = *bloomFilterTable->get_as("Entry"); initSize(m_size); } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. */ void insert(vector const& precomputed) { // iterates through hashed values adding it to the filter for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t normalizedValue = precomputed.at(i) % m_size; __sync_or_and_fetch( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); } } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. */ void insert(const uint64_t precomputed[]) { // iterates through hashed values adding it to the filter for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t normalizedValue = precomputed[i] % m_size; __sync_or_and_fetch( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); } } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. * Returns if already inserted */ bool insertAndCheck(const uint64_t precomputed[]) { // iterates through hashed values adding it to the filter bool found = true; for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t normalizedValue = precomputed[i] % m_size; found &= __sync_fetch_and_or( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]) >> (normalizedValue % bitsPerChar) & 1; } return found; } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. * Returns if already inserted */ bool insertAndCheck(vector const& precomputed) { // iterates through hashed values adding it to the filter bool found = true; for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t normalizedValue = precomputed.at(i) % m_size; found &= __sync_fetch_and_or( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]) >> (normalizedValue % bitsPerChar) & 1; } return found; } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. */ bool contains(vector const& precomputed) const { for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t normalizedValue = precomputed.at(i) % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) != bit) { return false; } } return true; } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. */ bool contains(const uint64_t precomputed[]) const { for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t normalizedValue = precomputed[i] % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) != bit) { return false; } } return true; } void writeHeader(std::ostream& out) const { /* Initialize cpptoml root table Note: Tables and fields are unordered Ordering of table is maintained by directing the table to the output stream immediately after completion */ std::shared_ptr root = cpptoml::make_table(); /* Initialize bloom filter section and insert fields and output to ostream */ auto header = cpptoml::make_table(); header->insert("KmerSize", m_kmerSize); header->insert("HashNum", m_hashNum); header->insert("BloomFilterSize", m_size); header->insert("BloomFilterSizeInBytes", m_sizeInBytes); header->insert("dFPR", m_dFPR); header->insert("nEntry", m_nEntry); header->insert("Entry", m_tEntry); std::string magic(MAGIC_HEADER_STRING); root->insert(magic, header); out << *root; // Output [HeaderEnd]\n to ostream to mark the end of the header out << "[HeaderEnd]\n"; } /** Serialize the Bloom filter to a stream */ friend std::ostream& operator<<(std::ostream& out, const BloomFilter& bloom) { bloom.writeHeader(out); // NOLINTNEXTLINE(google-readability-casting) out.write(reinterpret_cast(bloom.m_filter), bloom.m_sizeInBytes); return out; } /* * Stores the filter as a binary file to the path specified * Stores uncompressed because the random data tends to * compress poorly anyway */ void storeFilter(const string& filterFilePath) const { std::ofstream ofs(filterFilePath.c_str(), std::ios::out | std::ios::binary); assert_good(ofs, filterFilePath); std::cerr << "Writing a " << m_sizeInBytes << " byte filter to " << filterFilePath << " on disk.\n"; ofs << *this; ofs.flush(); assert_good(ofs, filterFilePath); ofs.close(); } uint64_t getPop() const { uint64_t i, popBF = 0; //#pragma omp parallel for reduction(+:popBF) for (i = 0; i < (m_size + 7) / 8; i++) popBF = popBF + popCnt(m_filter[i]); return popBF; } unsigned getHashNum() const { return m_hashNum; } unsigned getKmerSize() const { return m_kmerSize; } /* * Calculates that False positive rate that a redundant entry is actually * a unique entry */ double getRedudancyFPR() { assert(m_nEntry > 0); double total = log(calcFPR_numInserted(1)); for (uint64_t i = 2; i < m_nEntry; ++i) { total = log(exp(total) + calcFPR_numInserted(i)); } return exp(total) / m_nEntry; } /* * Return FPR based on popcount */ double getFPR() const { return pow(double(getPop()) / double(m_size), double(m_hashNum)); } /* * Return FPR based on number of inserted elements */ double getFPR_numEle() const { assert(m_nEntry > 0); return calcFPR_numInserted(m_nEntry); } uint64_t getnEntry() { return m_nEntry; } uint64_t gettEntry() { return m_tEntry; } void setnEntry(uint64_t value) { m_nEntry = value; } void settEntry(uint64_t value) { m_tEntry = value; } uint64_t getFilterSize() const { return m_size; } uint64_t sizeInBytes() const { return m_sizeInBytes; } ~BloomFilter() { delete[] m_filter; } protected: BloomFilter(const BloomFilter& that); // to prevent copy construction /* * Checks filter size and initializes filter */ void initSize(size_t size) { if (size % 8 != 0) { cerr << "ERROR: Filter Size \"" << size << "\" is not a multiple of 8." << endl; exit(1); } m_sizeInBytes = size / bitsPerChar; if (m_filter != NULL) delete[] m_filter; m_filter = new unsigned char[m_sizeInBytes](); } /* * Only returns multiples of 64 for filter building purposes * Is an estimated size using approximations of FPR formula * given the number of hash functions */ size_t calcOptimalSize(size_t entries, double fpr) const { size_t non64ApproxVal = size_t( -double(entries) * double(m_hashNum) / log(1.0 - pow(fpr, double(1 / double(m_hashNum))))); return non64ApproxVal + (64 - non64ApproxVal % 64); } /* * Calculates the optimal number of hash function to use * Calculation assumes optimal ratio of bytes per entry given a fpr */ static unsigned calcOptiHashNum(double fpr) { return unsigned(-log(fpr) / log(2)); } /* * Calculate FPR based on hash functions, size and number of entries * see http://en.wikipedia.org/wiki/Bloom_filter */ double calcFPR_numInserted(size_t numEntr) const { return pow( 1.0 - pow(1.0 - 1.0 / double(m_size), double(numEntr) * m_hashNum), double(m_hashNum)); } /* * Calculates the optimal FPR to use based on hash functions */ double calcFPR_hashNum(unsigned hashFunctNum) const { return pow(2, -double(hashFunctNum)); } uint8_t* m_filter; size_t m_size; size_t m_sizeInBytes; unsigned m_hashNum; unsigned m_kmerSize; double m_dFPR; uint64_t m_nEntry; uint64_t m_tEntry; static constexpr const char* MAGIC_HEADER_STRING = "BTLBloomFilter_v1"; }; #endif /* BLOOMFILTER_H_ */ abyss-2.2.4/vendor/btl_bloomfilter/BloomFilterUtil.h000066400000000000000000000022461361462241400225500ustar00rootroot00000000000000#ifndef BLOOM_FILTER_UTIL #define BLOOM_FILTER_UTIL 1 #include "KmerBloomFilter.hpp" #include "vendor/ntHashIterator.hpp" using namespace std; void insertSeq(BloomFilter& bloom, const string& seq, unsigned hashNum, unsigned kmerSize) { ntHashIterator itr(seq, hashNum, kmerSize); while (itr != itr.end()) { bloom.insert(*itr); ++itr; } } // functions for calculations regarding bloomfilter // todo: Tweak calculations as they are approximations and may not be 100% optimal // see http://en.wikipedia.org/wiki/Bloom_filter // Private functions /* * Calculate FPR based on hash functions, size and number of entries * see http://en.wikipedia.org/wiki/Bloom_filter */ double calcApproxFPR(size_t size, size_t numEntr, unsigned hashFunctNum) { return pow( 1.0 - pow(1.0 - 1.0 / double(size), double(numEntr) * hashFunctNum), double(hashFunctNum)); } /* * Calculates redundancy FPR */ double calcRedunancyFPR(size_t size, size_t numEntr, unsigned hashFunctNum) { double total = log(calcApproxFPR(size, 1, hashFunctNum)); for (size_t i = 2; i < numEntr; ++i) { total = log(exp(total) + calcApproxFPR(size, i, hashFunctNum)); } return exp(total) / numEntr; } #endif abyss-2.2.4/vendor/btl_bloomfilter/ChangeLog000066400000000000000000000000001361462241400210570ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/CountingBloomFilter.hpp000066400000000000000000000261371361462241400237660ustar00rootroot00000000000000// Written by Johnathan Wong and Sauparna Palchowdhury. #ifndef COUNTINGBLOOMFILTER_HPP // NOLINT(llvm-header-guard) #define COUNTINGBLOOMFILTER_HPP #include "vendor/IOUtil.h" #include "vendor/cpptoml/include/cpptoml.h" #include #include #include #include #include #include #include // Forward declaraions. template class CountingBloomFilter; // Method declarations. template std::ostream& operator<<(std::ostream& out, const CountingBloomFilter& bloom); template class CountingBloomFilter { public: CountingBloomFilter() = default; CountingBloomFilter( size_t sizeInBytes, unsigned hashNum, unsigned kmerSize, unsigned countThreshold) : m_hashNum(hashNum) , m_kmerSize(kmerSize) , m_countThreshold(countThreshold) { int remainder = sizeInBytes % 8; if (remainder == 0) { m_sizeInBytes = sizeInBytes; m_size = m_sizeInBytes / sizeof(T); m_filter.resize(m_size, 0); } else { m_sizeInBytes = sizeInBytes + 8 - remainder; m_size = m_sizeInBytes / sizeof(T); m_filter.resize(m_size, 0); } } CountingBloomFilter(const std::string& path, unsigned countThreshold); T operator[](size_t i) { return m_filter[i]; } template T minCount(const U& hashes) const { T min = m_filter[hashes[0] % m_size]; for (size_t i = 1; i < m_hashNum; ++i) { size_t pos = hashes[i] % m_size; if (m_filter[pos] < min) { min = m_filter[pos]; } } return min; } template bool contains(const U& hashes) const; template void insert(const U& hashes); template bool insertAndCheck(const U& hashes); template void incrementMin(const U& hashes); template void incrementAll(const U& hashes); unsigned getKmerSize() const { return m_kmerSize; }; unsigned getHashNum() const { return m_hashNum; }; unsigned threshold() const { return m_countThreshold; }; size_t size() const { return m_size; }; size_t sizeInBytes() const { return m_sizeInBytes; }; size_t popCount() const; size_t filtered_popcount() const; double FPR() const; double filtered_FPR() const; void loadHeader(std::istream& file); void loadFilter(const std::string& path); void storeHeader(std::ostream& out) const; void storeFilter(const std::string& path) const; friend std::ostream& operator<<<>(std::ostream&, const CountingBloomFilter&); private: // m_filter : A vector of elements of type T. // m_size : Size of bloom filter (size of m_filter array). // m_sizeInBytes : Size of the bloom filter in bytes, that is, // (m_size * sizeof(T)). // m_hashNum : Number of hash functions. // m_kmerSize : Size of a k-mer. // m_countThreshold : A count greater or equal to this threshold // establishes existence of an element in the filter. // m_bitsPerCounter : Number of bits per counter. // MAGIC_HEADER_STRING : Magic string used to identify the type of bloom filter. std::vector m_filter; size_t m_size = 0; size_t m_sizeInBytes = 0; unsigned m_hashNum = 0; unsigned m_kmerSize = 0; unsigned m_countThreshold = 0; // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) unsigned m_bitsPerCounter = 8; static constexpr const char* MAGIC_HEADER_STRING = "BTLCountingBloomFilter_v1"; }; // Method definitions // Bloom filter operations /* Use of atomic increments in incrementMin() and incrementAll(): A atomic compare-and-swap (CAS) operation increments m_filter[pos]. The CAS operation takes a memory location and a value that the caller believes the location currently stores. If the memory location still holds that value when the atomic compare-and-swap executes, then a new value is stored and 'true' returned; otherwise, memory is left unchanged and 'false' returned. The value of m_filter[pos] may be changed by another thread between a read from that memory location and a write to it. The CAS operation is called in a loop until it succeeds, which ensures that a write does not happen if some other thread has incremented the value between this thread's read and write. Note that CAS operations suffer from the ABA problem. */ // Of the m_hashNum counters, increment all the minimum values. template template inline void CountingBloomFilter::incrementMin(const U& hashes) { // update flag to track if increment is done on at least one counter bool updateDone = false; T newVal; T minVal = minCount(hashes); while (!updateDone) { // Simple check to deal with overflow newVal = minVal + 1; if (minVal > newVal) { return; } for (size_t i = 0; i < m_hashNum; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg) if (__sync_bool_compare_and_swap(&m_filter[hashes[i] % m_size], minVal, newVal)) { updateDone = true; } } // Recalculate minval because if increment fails, it needs a new minval to use and // if it doesnt hava a new one, the while loop runs forever. if (!updateDone) { minVal = minCount(hashes); } } } // Increment all the m_hashNum counters. template template inline void CountingBloomFilter::incrementAll(const U& hashes) { T currentVal; T newVal; for (size_t i = 0; i < m_hashNum; ++i) { size_t pos = hashes[i] % m_size; do { currentVal = m_filter[pos]; newVal = currentVal + 1; if (newVal < currentVal) { break; } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg) } while (!__sync_bool_compare_and_swap(&m_filter[pos], currentVal, newVal)); } } // Check if an element exists. If the minimum count at the m_hashNum positions // of m_filter is more than or equal to a predefined count threshold, then the // element is said to be present in the Bloom filter. count() therefore returns // true when this condition is satisfied, or else, false. template template inline bool CountingBloomFilter::contains(const U& hashes) const { return minCount(hashes) >= m_countThreshold; } template template inline void CountingBloomFilter::insert(const U& hashes) { incrementMin(hashes); } template template inline bool CountingBloomFilter::insertAndCheck(const U& hashes) { bool found = contains(hashes); incrementMin(hashes); return found; } /* Count the number of non-zero counters. */ template size_t CountingBloomFilter::popCount() const { size_t count = 0; for (size_t i = 0; i < m_size; ++i) { if (m_filter[i] != 0) { ++count; } } return count; } /* Count the number of above threshold counters. */ template size_t CountingBloomFilter::filtered_popcount() const { size_t count = 0; for (size_t i = 0; i < m_size; ++i) { if (m_filter[i] >= m_countThreshold) { ++count; } } return count; } template double CountingBloomFilter::FPR() const { // NOLINTNEXTLINE(google-readability-casting) return std::pow((double)popCount() / (double)m_size, m_hashNum); } template double CountingBloomFilter::filtered_FPR() const { // NOLINTNEXTLINE(google-readability-casting) return std::pow((double)filtered_popcount() / (double)m_size, m_hashNum); } // Serialization interface. template CountingBloomFilter::CountingBloomFilter(const std::string& path, unsigned countThreshold) : m_countThreshold(countThreshold) { loadFilter(path); } template void CountingBloomFilter::loadFilter(const std::string& path) { std::ifstream file(path); assert_good(file, path); loadHeader(file); m_filter.resize(m_sizeInBytes); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) file.read(reinterpret_cast(m_filter.data()), m_sizeInBytes); assert_good(file, path); file.close(); } template void CountingBloomFilter::loadHeader(std::istream& file) { std::string magic_header(MAGIC_HEADER_STRING); (magic_header.insert(0, "[")).append("]"); std::string line; std::getline(file, line); if (line != magic_header) { std::cerr << "ERROR: magic string does not match (likely version mismatch)\n" << "Your magic string: " << line << "\n" << "CountingBloomFilter magic string: " << magic_header << std::endl; exit(EXIT_FAILURE); } /* Read bloom filter line by line until it sees "[HeaderEnd]" which is used to mark the end of the header section and assigns the header to a char array*/ std::string headerEnd = "[HeaderEnd]"; std::string toml_buffer((line + "\n")); bool headerEndCheck = false; while (std::getline(file, line)) { toml_buffer.append(line + "\n"); if (line == headerEnd) { headerEndCheck = true; break; } } if (!headerEndCheck) { std::cerr << "ERROR: pre-built bloom filter does not have the correct header end." << std::endl; exit(EXIT_FAILURE); } // Send the char array to a stringstream for the cpptoml parser to parse std::istringstream toml_stream(toml_buffer); cpptoml::parser toml_parser(toml_stream); auto header_config = toml_parser.parse(); // Obtain header values from toml parser and assign them to class members std::string magic(MAGIC_HEADER_STRING); auto bloomFilterTable = header_config->get_table(magic); m_size = *bloomFilterTable->get_as("BloomFilterSize"); m_hashNum = *bloomFilterTable->get_as("HashNum"); m_kmerSize = *bloomFilterTable->get_as("KmerSize"); m_sizeInBytes = *bloomFilterTable->get_as("BloomFilterSizeInBytes"); m_bitsPerCounter = *bloomFilterTable->get_as("BitsPerCounter"); } template void CountingBloomFilter::storeFilter(const std::string& path) const { std::ofstream ofs(path.c_str(), std::ios::out | std::ios::binary); assert_good(ofs, path); std::cerr << "Writing a " << m_sizeInBytes << " byte filter to " << path << " on disk.\n"; ofs << *this; ofs.flush(); assert_good(ofs, path); ofs.close(); } template void CountingBloomFilter::storeHeader(std::ostream& out) const { /* Initialize cpptoml root table Note: Tables and fields are unordered Ordering of table is maintained by directing the table to the output stream immediately after completion */ std::shared_ptr root = cpptoml::make_table(); /* Initialize bloom filter section and insert fields and output to ostream */ auto header = cpptoml::make_table(); header->insert("BitsPerCounter", m_bitsPerCounter); header->insert("KmerSize", m_kmerSize); header->insert("HashNum", m_hashNum); header->insert("BloomFilterSize", m_size); header->insert("BloomFilterSizeInBytes", m_sizeInBytes); std::string magic(MAGIC_HEADER_STRING); root->insert(magic, header); out << *root; // Output [HeaderEnd]\n to ostream to mark the end of the header out << "[HeaderEnd]\n"; } // Serialize the bloom filter to a C++ stream template std::ostream& operator<<(std::ostream& out, const CountingBloomFilter& bloom) { bloom.storeHeader(out); // NOLINTNEXTLINE(google-readability-casting) out.write((const char*)bloom.m_filter.data(), bloom.m_sizeInBytes); return out; } #endif // COUNTINGBLOOMFILTER_HPP abyss-2.2.4/vendor/btl_bloomfilter/Examples/000077500000000000000000000000001361462241400210755ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/Examples/RollingFilterLoad.cpp000066400000000000000000000024131361462241400251550ustar00rootroot00000000000000#include "BloomFilter.hpp" #include #include using namespace std; /** stores state between calls to rolling hash */ struct RollingHashState { /* seed hash value for current k-mer */ uint64_t hash; /* seed hash value for reverse complement of current k-mer */ uint64_t rcHash; }; int main(int argc, char** argv) { /* test sequence */ const string seq = "TAGAATCACCCAAAGA"; /* k-mer size */ const unsigned k = 5; /* number of Bloom filter hash functions */ const unsigned numHashes = 4; /* size of Bloom filter (in bits) */ const unsigned size = 1000; /* hash values for current k-mer */ vector hashes; /* init Bloom filter */ BloomFilter bloom(size, numHashes, k); /* init rolling hash state and compute hash values for first k-mer */ RollingHashState state; string kmer0 = seq.substr(0, k); hashes = bloom.multiHash(kmer0.c_str(), state.hash, state.rcHash); /* load k-mers into Bloom filter using rolling hash */ for (unsigned i = 1; i < seq.length() - k + 1; ++i) { /* "roll" hash values right to current k-mer */ char charOut = seq[i - 1]; char charIn = seq[i + k - 1]; hashes = bloom.multiHash(state.hash, state.rcHash, charOut, charIn); /* insert current k-mer into Bloom filter */ bloom.insert(hashes); } return 0; } abyss-2.2.4/vendor/btl_bloomfilter/KmerBloomFilter.hpp000066400000000000000000000035311361462241400230670ustar00rootroot00000000000000/* * * BloomFilter.hpp * * Created on: Aug 10, 2012 * Author: cjustin */ #ifndef KMERBLOOMFILTER_H_ #define KMERBLOOMFILTER_H_ #include "BloomFilter.hpp" #include "vendor/nthash.hpp" using namespace std; class KmerBloomFilter : public BloomFilter { public: /* * Default constructor. */ KmerBloomFilter() : BloomFilter() {} /* De novo filter constructor. * * preconditions: * filterSize must be a multiple of 64 * * kmerSize refers to the number of bases the kmer has */ KmerBloomFilter(size_t filterSize, unsigned hashNum, unsigned kmerSize) : BloomFilter(filterSize, hashNum, kmerSize) {} KmerBloomFilter(const string& filterFilePath) : BloomFilter(filterFilePath) {} using BloomFilter::contains; using BloomFilter::insert; /* * Single pass filtering, computes hash values on the fly */ bool contains(const char* kmer) const { uint64_t hVal = NTC64(kmer, m_kmerSize); size_t normalizedValue = hVal % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) == 0) return false; for (unsigned i = 1; i < m_hashNum; i++) { normalizedValue = NTE64(hVal, m_kmerSize, i) % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) == 0) return false; } return true; } void insert(const char* kmer) { uint64_t hVal = NTC64(kmer, m_kmerSize); size_t normalizedValue = hVal % m_size; __sync_fetch_and_or( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); for (unsigned i = 1; i < m_hashNum; i++) { size_t normalizedValue = NTE64(hVal, m_kmerSize, i) % m_size; __sync_fetch_and_or( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); } } }; #endif /* KMERBLOOMFILTER_H_ */ abyss-2.2.4/vendor/btl_bloomfilter/LICENSE000066400000000000000000001045151361462241400203320ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . abyss-2.2.4/vendor/btl_bloomfilter/MIBFQuerySupport.hpp000066400000000000000000000436521361462241400232020ustar00rootroot00000000000000/* * MIBFQuerySupport.hpp * * Purpose: To provide support for complex classification * * Functions for most accurate classification and faster heuristic classification * are split into sections. * * Contains support objects intended to be private per thread (copied) * * * Created on: Jun 6, 2018 * Author: justin */ #ifndef MIBFQUERYSUPPORT_HPP_ #define MIBFQUERYSUPPORT_HPP_ #include "MIBloomFilter.hpp" //#include #include "vendor/ntHashIterator.hpp" #include "vendor/stHashIterator.hpp" #include using namespace std; using boost::math::binomial; // T = T type, H = rolling hash itr template class MIBFQuerySupport { public: MIBFQuerySupport( const MIBloomFilter& miBF, const vector& perFrameProb, unsigned extraCount, unsigned extraFrameLimit, unsigned maxMiss, unsigned minCount, bool bestHitAgree) : m_miBF(miBF) , m_perFrameProb(perFrameProb) , m_extraCount(extraCount) , m_extraFrameLimit(extraFrameLimit) , m_maxMiss(maxMiss) , m_minCount(minCount) , m_bestHitAgree(bestHitAgree) , m_satCount(0) , m_evalCount(0) , m_bestCounts({ 0, 0, 0, 0, 0, 0, 0 }) , m_secondBestNonSatFrameCount(0) , m_rankPos(miBF.getHashNum()) , m_hits(miBF.getHashNum(), true) , m_counts(vector(perFrameProb.size(), { 0, 0, 0, 0, 0, 0, 0 })) , m_totalReads(0) { // this should always be a small array m_seenSet.reserve(miBF.getHashNum()); } struct QueryResult { T id; uint16_t count; uint16_t nonSatCount; uint16_t totalCount; uint16_t totalNonSatCount; uint16_t nonSatFrameCount; uint16_t solidCount; double frameProb; }; struct CountResult { uint16_t count; uint16_t nonSatCount; uint16_t totalCount; uint16_t totalNonSatCount; uint16_t nonSatFrameCount; uint16_t solidCount; size_t readCount; // determines if count should be reset }; // For returning an empty result const vector& emptyResult() { init(); return m_signifResults; } /* * totalTrials = number of possible trials that can be checked */ template const vector& query(ITR& itr, const vector& minCount) { init(); unsigned extraFrame = 0; bool candidateFound = false; while (itr != itr.end() && !candidateFound) { candidateFound = updateCounts(itr, minCount, extraFrame); ++itr; } summarizeCandiates(); return m_signifResults; } template const vector& query(ITR& itr1, ITR& itr2, const vector& minCount) { init(); unsigned extraFrame = 0; unsigned frameCount = 0; bool candidateFound = false; while ((itr1 != itr1.end() || itr2 != itr2.end()) && !candidateFound) { auto& itr = frameCount % 2 == 0 && itr1 != itr1.end() ? itr1 : itr2 != itr2.end() ? itr2 : itr1; candidateFound = updateCounts(itr, minCount, extraFrame); ++itr; ++frameCount; } summarizeCandiates(); return m_signifResults; } unsigned getSatCount() const { return m_satCount; } unsigned getEvalCount() const { return m_evalCount; } // debugging functions: void printAllCounts(const vector& ids) { for (size_t i = 0; i < m_counts.size(); ++i) { if (m_counts[i].totalCount > 0) { cout << i << "\t" << ids[i] << "\t" << m_counts[i].nonSatFrameCount << "\t" << m_counts[i].count << "\t" << m_counts[i].solidCount << "\t" << m_counts[i].nonSatCount << "\t" << m_counts[i].totalNonSatCount << "\t" << m_counts[i].totalCount << "\n"; } } } /* * Debugging * Computes criteria used for judging a read consisting of: * Position of matches * Number of actually evaluated k-mers * Return count of matching k-mers to set */ // TODO saturation not handle correctly inline vector getMatchSignature( const string& seq, unsigned& evaluatedSeeds, vector>>& hitsPattern) { vector matchPos; matchPos.reserve(seq.size() - m_miBF.getKmerSize()); if (m_miBF.getSeedValues().size() > 0) { stHashIterator itr( seq, m_miBF.getSeedValues(), m_miBF.getHashNum(), m_miBF.getKmerSize()); while (itr != itr.end()) { if (m_maxMiss >= m_miBF.atRank(*itr, m_rankPos, m_hits, m_maxMiss)) { vector results = m_miBF.getData(m_rankPos); vector> processedResults(results.size(), pair(0, false)); for (unsigned i = 0; i < m_miBF.getHashNum(); ++i) { if (m_hits[i]) { T tempResult = results[i]; if (tempResult > MIBloomFilter::s_mask) { processedResults[i] = pair(tempResult & MIBloomFilter::s_antiMask, true); } else { processedResults[i] = pair(tempResult & MIBloomFilter::s_antiMask, false); } } } matchPos.push_back(itr.pos()); hitsPattern.push_back(processedResults); } ++itr; ++evaluatedSeeds; } } else { ntHashIterator itr(seq, m_miBF.getHashNum(), m_miBF.getKmerSize()); while (itr != itr.end()) { if (m_miBF.atRank(*itr, m_rankPos)) { vector results = m_miBF.getData(m_rankPos); vector> processedResults(results.size(), pair(0, false)); if (results.size() > 0) { for (unsigned i = 0; i < m_miBF.getHashNum(); ++i) { T tempResult = results[i]; if (tempResult > MIBloomFilter::s_mask) { processedResults[i] = pair(tempResult & MIBloomFilter::s_antiMask, true); } else { processedResults[i] = pair(tempResult & MIBloomFilter::s_antiMask, false); } } matchPos.push_back(itr.pos()); hitsPattern.push_back(processedResults); } } ++itr; ++evaluatedSeeds; } } return matchPos; } private: /* * Sort in order of * nonSatFrameCount * count * solidCount * nonSatCount * totalNonSatCount * totalCount * frameProb */ static inline bool sortCandidates(const QueryResult& a, const QueryResult& b) { return ( b.nonSatFrameCount == a.nonSatFrameCount ? (b.count == a.count ? (b.solidCount == a.solidCount ? (b.nonSatCount == a.nonSatCount ? (b.totalNonSatCount == a.totalNonSatCount ? (b.totalCount == a.totalCount ? (a.frameProb > b.frameProb) : a.totalCount > b.totalCount) : a.totalNonSatCount > b.totalNonSatCount) : a.nonSatCount > b.nonSatCount) : a.solidCount > b.solidCount) : a.count > b.count) : a.nonSatFrameCount > b.nonSatFrameCount); } // static inline bool sortCandidates(const QueryResult &a, // const QueryResult &b, unsigned extraCount ) { // return (isRoughlyEqual(b.count, a.count, extraCount) ? // (isRoughlyEqual(b.totalNonSatCount, a.totalNonSatCount, extraCount) ? // (isRoughlyEqual(b.nonSatFrameCount, a.nonSatFrameCount, extraCount) ? // (isRoughlyEqual(b.solidCount, a.solidCount, extraCount) ? // (isRoughlyEqual(b.nonSatCount, a.nonSatCount, extraCount) ? // (isRoughlyEqual(b.totalCount, a.totalCount, extraCount) ? // (a.frameProb > b.frameProb) : // a.totalCount > b.totalCount) : // a.nonSatCount > b.nonSatCount) : // a.solidCount > b.solidCount) : // a.nonSatFrameCount > b.nonSatFrameCount) : // a.totalNonSatCount > b.totalNonSatCount) : // a.count > b.count); // } // static inline bool sortCandidates(const QueryResult &a, // const QueryResult &b ) { // return (compareStdErr(b.count, a.count) ? // (compareStdErr(b.totalNonSatCount, a.totalNonSatCount) ? // (compareStdErr(b.nonSatFrameCount, a.nonSatFrameCount) ? // (compareStdErr(b.solidCount, a.solidCount) ? // (compareStdErr(b.nonSatCount, a.nonSatCount) ? // (compareStdErr(b.totalCount, a.totalCount) ? // (a.frameProb > b.frameProb) : // a.totalCount > b.totalCount) : // a.nonSatCount > b.nonSatCount) : // a.solidCount > b.solidCount) : // a.nonSatFrameCount > b.nonSatFrameCount) : // a.totalNonSatCount > b.totalNonSatCount) : // a.count > b.count); // } /* * Returns true if considered roughly equal */ static inline bool isRoughlyEqual(unsigned a, unsigned b, unsigned extraCount) { if (a > b) { return a <= b + extraCount; } return b <= a + extraCount; } /* * Returns true if considered roughly equal */ static inline bool compareStdErr(unsigned a, unsigned b) { double stderrA = sqrt(a); double stderrB = sqrt(b); if (a > b) { return (double(a) - stderrA) <= (double(b) + stderrB); } return (double(b) - stderrB) <= (double(a) + stderrA); } /* * Returns true if considered roughly equal or b is larger */ inline bool compareStdErrLarger(unsigned a, unsigned b) const { double stderrA = sqrt(a) * m_extraCount; double stderrB = sqrt(b) * m_extraCount; return (double(a) - stderrA) <= (double(b) + stderrB); } /* * Returns true if considered roughly equal */ bool isRoughlyEqual(const CountResult& a, const CountResult& b, unsigned extraCount) const { return ( isRoughlyEqual(b.count, a.count, extraCount) && isRoughlyEqual(b.totalNonSatCount, a.totalNonSatCount, extraCount) && isRoughlyEqual(b.nonSatFrameCount, a.nonSatFrameCount, extraCount) && isRoughlyEqual(b.solidCount, a.solidCount, extraCount) && isRoughlyEqual(b.nonSatCount, a.nonSatCount, extraCount) && isRoughlyEqual(b.totalCount, a.totalCount, extraCount)); } /* * Returns true if considered roughly equal */ bool isValid(const CountResult& a, const CountResult& b) const { return ( compareStdErr(b.count, a.count) || compareStdErr(b.totalNonSatCount, a.totalNonSatCount) || compareStdErr(b.nonSatFrameCount, a.nonSatFrameCount) || compareStdErr(b.solidCount, a.solidCount) || compareStdErr(b.nonSatCount, a.nonSatCount) || compareStdErr(b.totalCount, a.totalCount)); } /* * Returns true if considered roughly equal */ bool isRoughlyEqualOrLarger(const QueryResult& a, const QueryResult& b) const { return ( compareStdErrLarger(a.count, b.count) && compareStdErrLarger(a.totalNonSatCount, b.totalNonSatCount) && compareStdErrLarger(a.nonSatFrameCount, b.nonSatFrameCount) && compareStdErrLarger(a.solidCount, b.solidCount) && compareStdErrLarger(a.nonSatCount, b.nonSatCount) && compareStdErrLarger(a.totalCount, b.totalCount)); } bool checkCountAgreement(QueryResult b, QueryResult a) { return ( b.nonSatFrameCount >= a.nonSatFrameCount && b.count >= a.count && b.solidCount >= a.solidCount && b.nonSatCount >= a.nonSatCount && b.totalNonSatCount >= a.totalNonSatCount && b.totalCount >= a.totalCount); } // contains reference to parent const MIBloomFilter& m_miBF; const vector& m_perFrameProb; // not references, but shared other objects or static variables const double m_extraCount; const unsigned m_extraFrameLimit; const unsigned m_maxMiss; const unsigned m_minCount; const bool m_bestHitAgree; // const double m_rateSaturated; // resusable variables unsigned m_satCount; unsigned m_evalCount; // current bestCounts CountResult m_bestCounts; uint16_t m_secondBestNonSatFrameCount; // resusable objects vector m_rankPos; vector m_hits; vector m_signifResults; vector m_counts; vector m_candidateMatches; vector m_seenSet; // Number of reads processed by object size_t m_totalReads; bool updateCounts(const stHashIterator& itr, const vector& minCount, unsigned& extraFrame) { bool candidateFound = false; unsigned misses = m_miBF.atRank(*itr, m_rankPos, m_hits, m_maxMiss); if (misses <= m_maxMiss) { candidateFound = updatesCounts(minCount, extraFrame, misses); } return candidateFound; } bool updateCounts(const ntHashIterator& itr, const vector& minCount, unsigned& extraFrame) { bool candidateFound = false; if (m_miBF.atRank(*itr, m_rankPos)) { candidateFound = updatesCounts(minCount, extraFrame); } ++m_evalCount; return candidateFound; } void init() { m_candidateMatches.clear(); m_signifResults.clear(); m_satCount = 0; m_evalCount = 0; m_bestCounts = { 0, 0, 0, 0, 0, 0, 0 }; m_secondBestNonSatFrameCount = 0; ++m_totalReads; } bool updatesCounts(const vector& minCount, unsigned& extraFrame, unsigned misses = 0) { m_seenSet.clear(); unsigned satCount = 0; for (unsigned i = 0; i < m_miBF.getHashNum(); ++i) { if (m_hits[i]) { T resultRaw = m_miBF.getData(m_rankPos[i]); ++m_evalCount; bool saturated = false; T result = resultRaw; // check for saturation if (result > m_miBF.s_mask) { result &= m_miBF.s_antiMask; saturated = true; satCount++; // detemines if count should be reset if (m_totalReads != m_counts[result].readCount) { m_counts[result] = { 0, 0, 0, 0, 0, 0, m_totalReads }; } } else { if (m_totalReads != m_counts[result].readCount) { m_counts[result] = { 0, 0, 0, 0, 0, 0, m_totalReads }; } ++m_counts[result].totalNonSatCount; } ++m_counts[result].totalCount; if (find(m_seenSet.begin(), m_seenSet.end(), resultRaw) == m_seenSet.end()) { // check for saturation if (saturated) { // if the non-saturated version has not been seen before if (find(m_seenSet.begin(), m_seenSet.end(), result) == m_seenSet.end()) { // check is count is exceeded ++m_counts[result].count; } } else { ++m_counts[result].nonSatCount; // check is count is exceeded ++m_counts[result].count; } m_seenSet.push_back(resultRaw); } } } if (satCount == 0) { for (typename vector::iterator itr = m_seenSet.begin(); itr != m_seenSet.end(); ++itr) { ++m_counts[*itr].nonSatFrameCount; if (misses == 0) { ++m_counts[*itr].solidCount; } } } else { ++m_satCount; } for (typename vector::iterator itr = m_seenSet.begin(); itr != m_seenSet.end(); ++itr) { T result = *itr; if (result > m_miBF.s_mask) { // if non-saturated version already exists if (find(m_seenSet.begin(), m_seenSet.end(), result & m_miBF.s_antiMask) != m_seenSet.end()) { continue; } result &= m_miBF.s_antiMask; } if (m_counts[result].count >= minCount[result]) { if (find(m_candidateMatches.begin(), m_candidateMatches.end(), result) == m_candidateMatches.end()) { m_candidateMatches.push_back(result); } updateMaxCounts(m_counts[result]); } else if (m_candidateMatches.size() && m_counts[result].count >= m_bestCounts.count) { if (find(m_candidateMatches.begin(), m_candidateMatches.end(), result) == m_candidateMatches.end()) { m_candidateMatches.push_back(result); } updateMaxCounts(m_counts[result]); } } if (compareStdErr(m_bestCounts.totalNonSatCount, m_secondBestNonSatFrameCount)) { extraFrame = 0; } if (m_bestCounts.nonSatFrameCount > m_secondBestNonSatFrameCount) { if (m_extraFrameLimit < extraFrame++) { return true; } } return false; } void updateMaxCounts(const CountResult& count) { if (count.nonSatFrameCount > m_bestCounts.nonSatFrameCount) { m_bestCounts.nonSatFrameCount = count.nonSatFrameCount; } else if (count.nonSatFrameCount > m_secondBestNonSatFrameCount) { m_secondBestNonSatFrameCount = count.nonSatFrameCount; } if (count.count > m_bestCounts.count) { m_bestCounts.count = count.count; } if (count.nonSatCount > m_bestCounts.nonSatCount) { m_bestCounts.nonSatCount = count.nonSatCount; } if (count.solidCount > m_bestCounts.solidCount) { m_bestCounts.solidCount = count.solidCount; } if (count.totalCount > m_bestCounts.totalCount) { m_bestCounts.totalCount = count.totalCount; } if (count.totalNonSatCount > m_bestCounts.totalNonSatCount) { m_bestCounts.totalNonSatCount = count.totalNonSatCount; } } double calcSat(unsigned evaluatedValues, double singleEventProbSaturted, unsigned saturatedCount) { double probSaturated = 0; if (saturatedCount) { binomial bin(evaluatedValues, singleEventProbSaturted); probSaturated = cdf(bin, saturatedCount - 1); } return probSaturated; } void summarizeCandiates() { if (m_candidateMatches.size() && m_minCount <= m_bestCounts.nonSatFrameCount) { vector signifResults; for (typename vector::const_iterator candidate = m_candidateMatches.begin(); candidate != m_candidateMatches.end(); candidate++) { const CountResult& resultCount = m_counts[*candidate]; if (isValid(resultCount, m_bestCounts)) { QueryResult result; result.id = *candidate; result.count = resultCount.count; result.nonSatCount = resultCount.nonSatCount; result.totalCount = resultCount.totalCount; result.totalNonSatCount = resultCount.totalNonSatCount; result.nonSatFrameCount = resultCount.nonSatFrameCount; result.solidCount = resultCount.solidCount; result.frameProb = m_perFrameProb.at(*candidate); signifResults.push_back(result); } } if (signifResults.size() > 1) { sort(signifResults.begin(), signifResults.end(), sortCandidates); // sort(signifResults.begin(), signifResults.end(), // bind(sortCandidates, placeholders::_1, placeholders::_2, // m_extraCount)); for (typename vector::iterator candidate = signifResults.begin(); candidate != signifResults.end(); candidate++) { if (isRoughlyEqualOrLarger(signifResults[0], *candidate)) { m_signifResults.push_back(*candidate); } } if (m_bestHitAgree && m_signifResults.size() >= 2 && !checkCountAgreement(m_signifResults[0], m_signifResults[1])) { m_signifResults.clear(); } } else { m_signifResults.push_back(signifResults[0]); } } } }; #endif /* MIBFQUERYSUPPORT_HPP_ */ abyss-2.2.4/vendor/btl_bloomfilter/MIBloomFilter.hpp000066400000000000000000000520331361462241400224770ustar00rootroot00000000000000/* * MIBloomFilter.hpp * * Agnostic of hash function used -> cannot call contains without an array of hash values * * Created on: Jan 14, 2016 * Author: cjustin */ #ifndef MIBLOOMFILTER_HPP_ #define MIBLOOMFILTER_HPP_ #include // std::random_shuffle #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; template class MIBloomFilter { public: static const T s_mask = 1 << (sizeof(T) * 8 - 1); static const T s_antiMask = (T)~s_mask; static const T s_strand = 1 << (sizeof(T) * 8 - 2); static const T s_antiStrand = (T)~s_strand; static const T s_idMask = s_antiStrand & s_antiMask; static const unsigned BLOCKSIZE = 512; // static methods /* * Parses spaced seed string (string consisting of 1s and 0s) to vector */ static inline vector> parseSeedString(const vector& spacedSeeds) { vector> seeds(spacedSeeds.size(), vector()); for (unsigned i = 0; i < spacedSeeds.size(); ++i) { const string ss = spacedSeeds.at(i); for (unsigned j = 0; j < ss.size(); ++j) { if (ss.at(j) == '0') { seeds[i].push_back(j); } } } return seeds; } // helper methods // calculates the per frame probability of a random match for single value static inline double calcProbSingleFrame(double occupancy, unsigned hashNum, double freq, unsigned allowedMisses) { double probTotal = 0.0; for (unsigned i = hashNum - allowedMisses; i <= hashNum; i++) { double prob = nChoosek(hashNum, i); prob *= pow(occupancy, i); prob *= pow(1.0 - occupancy, hashNum - i); prob *= (1.0 - pow(1.0 - freq, i)); probTotal += prob; } return probTotal; } static inline double calcProbSingle(double occupancy, double freq) { return occupancy * freq; } /* * Returns an a filter size large enough to maintain an occupancy specified */ static size_t calcOptimalSize(size_t entries, unsigned hashNum, double occupancy) { size_t non64ApproxVal = size_t(-double(entries) * double(hashNum) / log(1.0 - occupancy)); return non64ApproxVal + (64 - non64ApproxVal % 64); } /* * Inserts a set of hash values into an sdsl bitvector and returns the number of collisions * Thread safe on the bv, though return values will not be the same run to run */ static unsigned insert(sdsl::bit_vector& bv, uint64_t* hashValues, unsigned hashNum) { unsigned colliCount = 0; for (unsigned i = 0; i < hashNum; ++i) { uint64_t pos = hashValues[i] % bv.size(); uint64_t* dataIndex = bv.data() + (pos >> 6); uint64_t bitMaskValue = (uint64_t)1 << (pos & 0x3F); colliCount += __sync_fetch_and_or(dataIndex, bitMaskValue) >> (pos & 0x3F) & 1; } return colliCount; } // TODO: include allowed miss in header #pragma pack(1) // to maintain consistent values across platforms struct FileHeader { char magic[8]; uint32_t hlen; // header length (including spaced seeds) uint64_t size; uint32_t nhash; uint32_t kmer; uint32_t version; // uint8_t allowedMiss; }; /* * Constructor using a prebuilt bitvector */ MIBloomFilter( unsigned hashNum, unsigned kmerSize, sdsl::bit_vector& bv, const vector seeds = vector(0)) : m_dSize(0) , m_hashNum(hashNum) , m_kmerSize(kmerSize) , m_sseeds(seeds) , m_probSaturated(0) { m_bv = sdsl::bit_vector_il(bv); bv = sdsl::bit_vector(); if (!seeds.empty()) { m_ssVal = parseSeedString(m_sseeds); assert(m_sseeds[0].size() == kmerSize); for (vector::const_iterator itr = m_sseeds.begin(); itr != m_sseeds.end(); ++itr) { // check if spaced seeds are all the same length assert(m_kmerSize == itr->size()); } } m_rankSupport = sdsl::rank_support_il<1>(&m_bv); m_dSize = getPop(); m_data = new T[m_dSize](); } MIBloomFilter(const string& filterFilePath) { #pragma omp parallel for for (unsigned i = 0; i < 2; ++i) { if (i == 0) { FILE* file = fopen(filterFilePath.c_str(), "rb"); if (file == NULL) { #pragma omp critical(stderr) cerr << "file \"" << filterFilePath << "\" could not be read." << endl; exit(1); } FileHeader header; if (fread(&header, sizeof(struct FileHeader), 1, file) == 1) { #pragma omp critical(stderr) cerr << "Loading header..." << endl; } else { #pragma omp critical(stderr) cerr << "Failed to Load header" << endl; exit(1); } char magic[9]; memcpy(magic, header.magic, 8); magic[8] = '\0'; #pragma omp critical(stderr) cerr << "Loaded header... magic: " << magic << " hlen: " << header.hlen << " size: " << header.size << " nhash: " << header.nhash << " kmer: " << header.kmer << endl; m_hashNum = header.nhash; m_kmerSize = header.kmer; m_dSize = header.size; m_data = new T[m_dSize](); if (header.hlen > sizeof(struct FileHeader)) { // load seeds for (unsigned i = 0; i < header.nhash; ++i) { char temp[header.kmer]; if (fread(temp, header.kmer, 1, file) != 1) { cerr << "Failed to load spaced seed string" << endl; exit(1); } else { cerr << "Spaced Seed " << i << ": " << string(temp, header.kmer) << endl; } m_sseeds.push_back(string(temp, header.kmer)); } m_ssVal = parseSeedString(m_sseeds); assert(m_sseeds[0].size() == m_kmerSize); for (vector::const_iterator itr = m_sseeds.begin(); itr != m_sseeds.end(); ++itr) { // check if spaced seeds are all the same length assert(m_kmerSize == itr->size()); } } if (header.hlen != (sizeof(FileHeader) + m_kmerSize * m_sseeds.size())) { cerr << "Multi Index Bloom Filter header length: " << header.hlen << " does not match expected length: " << (sizeof(FileHeader) + m_kmerSize * m_sseeds.size()) << " (likely version mismatch)" << endl; exit(1); } if (strcmp(magic, "MIBLOOMF")) { cerr << "Bloom Filter type does not match " << endl; exit(1); } if (header.version != MIBloomFilter_VERSION) { cerr << "Multi Index Bloom Filter version does not match: " << header.version << " expected: " << MIBloomFilter_VERSION << endl; exit(1); } #pragma omp critical(stderr) cerr << "Loading data vector" << endl; long int lCurPos = ftell(file); fseek(file, 0, 2); size_t fileSize = ftell(file) - header.hlen; fseek(file, lCurPos, 0); if (fileSize != m_dSize * sizeof(T)) { cerr << "Error: " << filterFilePath << " does not match size given by its header. Size: " << fileSize << " vs " << m_dSize * sizeof(T) << " bytes." << endl; exit(1); } size_t countRead = fread(m_data, fileSize, 1, file); if (countRead != 1 && fclose(file) != 0) { cerr << "file \"" << filterFilePath << "\" could not be read." << endl; exit(1); } } else { string bvFilename = filterFilePath + ".sdsl"; #pragma omp critical(stderr) cerr << "Loading sdsl interleaved bit vector from: " << bvFilename << endl; load_from_file(m_bv, bvFilename); m_rankSupport = sdsl::rank_support_il<1>(&m_bv); } } cerr << "Bit Vector Size: " << m_bv.size() << endl; cerr << "Popcount: " << getPop() << endl; // TODO make more streamlined m_probSaturated = pow(double(getPopSaturated()) / double(getPop()), m_hashNum); } /* * Stores the filter as a binary file to the path specified * Stores uncompressed because the random data tends to * compress poorly anyway */ void store(string const& filterFilePath) const { #pragma omp parallel for for (unsigned i = 0; i < 2; ++i) { if (i == 0) { ofstream myFile(filterFilePath.c_str(), ios::out | ios::binary); assert(myFile); writeHeader(myFile); // cerr << "Storing filter. Filter is " << m_dSize * sizeof(T) // << " bytes." << endl; // write out each block myFile.write(reinterpret_cast(m_data), m_dSize * sizeof(T)); myFile.close(); assert(myFile); FILE* file = fopen(filterFilePath.c_str(), "rb"); if (file == NULL) { cerr << "file \"" << filterFilePath << "\" could not be read." << endl; exit(1); } } else { string bvFilename = filterFilePath + ".sdsl"; // cerr << "Storing sdsl interleaved bit vector to: " << bvFilename // << endl; store_to_file(m_bv, bvFilename); // cerr << "Number of bit vector buckets is " << m_bv.size() // << endl; // cerr << "Uncompressed bit vector size is " // << (m_bv.size() + m_bv.size() * 64 / BLOCKSIZE) / 8 // << " bytes" << endl; } } } /* * Returns false if unable to insert hashes values * Contains strand information * Inserts hash functions in random order */ bool insert(const uint64_t* hashes, const bool* strand, T val, unsigned max) { unsigned count = 0; std::vector hashOrder; bool saturated = true; // for random number generator seed uint64_t randValue = val; bool strandDir = max % 2; // check values and if value set for (unsigned i = 0; i < m_hashNum; ++i) { // check if values are already set uint64_t pos = m_rankSupport(hashes[i] % m_bv.size()); T value = strandDir ^ strand[i] ? val | s_strand : val; // check for saturation T oldVal = m_data[pos]; if (oldVal > s_mask) { oldVal = oldVal & s_antiMask; } else { saturated = false; } if (oldVal == value) { ++count; } else { hashOrder.push_back(i); } if (count >= max) { return true; } randValue ^= hashes[i]; } std::minstd_rand g(randValue); std::shuffle(hashOrder.begin(), hashOrder.end(), g); // insert seeds in random order for (std::vector::iterator itr = hashOrder.begin(); itr != hashOrder.end(); ++itr) { uint64_t pos = m_rankSupport(hashes[*itr] % m_bv.size()); T value = strandDir ^ strand[*itr] ? val | s_strand : val; // check for saturation T oldVal = setVal(&m_data[pos], value); if (oldVal > s_mask) { oldVal = oldVal & s_antiMask; } else { saturated = false; } if (oldVal == 0) { ++count; } if (count >= max) { return true; } } if (count == 0) { if (!saturated) { assert(max == 1); // if this triggers then spaced seed is probably not symmetric saturate(hashes); } return false; } return true; } /* * Returns false if unable to insert hashes values * Inserts hash functions in random order */ bool insert(const uint64_t* hashes, T value, unsigned max) { unsigned count = 0; std::vector hashOrder; // for random number generator seed uint64_t randValue = value; bool saturated = true; // check values and if value set for (unsigned i = 0; i < m_hashNum; ++i) { // check if values are already set uint64_t pos = m_rankSupport(hashes[i] % m_bv.size()); // check for saturation T oldVal = m_data[pos]; if (oldVal > s_mask) { oldVal = oldVal & s_antiMask; } else { saturated = false; } if (oldVal == value) { ++count; } else { hashOrder.push_back(i); } if (count >= max) { return true; } randValue ^= hashes[i]; } std::minstd_rand g(randValue); std::shuffle(hashOrder.begin(), hashOrder.end(), g); // insert seeds in random order for (std::vector::iterator itr = hashOrder.begin(); itr != hashOrder.end(); ++itr) { uint64_t pos = m_rankSupport(hashes[*itr] % m_bv.size()); // check for saturation T oldVal = setVal(&m_data[pos], value); if (oldVal > s_mask) { oldVal = oldVal & s_antiMask; } else { saturated = false; } if (oldVal == 0) { ++count; } if (count >= max) { return true; } } if (count == 0) { if (!saturated) { assert(max == 1); // if this triggers then spaced seed is probably not symmetric saturate(hashes); } return false; } return true; } void saturate(const uint64_t* hashes) { for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t pos = m_rankSupport(hashes[i] % m_bv.size()); __sync_or_and_fetch(&m_data[pos], s_mask); } } inline vector at(const uint64_t* hashes, bool& saturated, unsigned maxMiss = 0) { vector results(m_hashNum); unsigned misses = 0; for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t pos = hashes[i] % m_bv.size(); if (m_bv[pos] == 0) { ++misses; saturated = false; if (misses > maxMiss) { return vector(); } } else { uint64_t rankPos = m_rankSupport(pos); T tempResult = m_data[rankPos]; if (tempResult > s_mask) { results[i] = m_data[rankPos] & s_antiMask; } else { results[i] = m_data[rankPos]; saturated = false; } } } return results; } /* * Populates rank pos vector. Boolean vector is use to confirm if hits are good * Returns total number of misses found */ unsigned atRank( const uint64_t* hashes, vector& rankPos, vector& hits, unsigned maxMiss) const { unsigned misses = 0; for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t pos = hashes[i] % m_bv.size(); if (m_bv[pos]) { rankPos[i] = m_rankSupport(pos); hits[i] = true; } else { if (++misses > maxMiss) { return misses; } hits[i] = false; } } return misses; } /* * For k-mers * Returns if match succeeded */ bool atRank(const uint64_t* hashes, vector& rankPos) const { for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t pos = hashes[i] % m_bv.size(); if (m_bv[pos]) { rankPos[i] = m_rankSupport(pos); } else { return false; } } return true; } vector getRankPos(const uint64_t* hashes) const { vector rankPos(m_hashNum); for (unsigned i = 0; i < m_hashNum; ++i) { uint64_t pos = hashes[i] % m_bv.size(); rankPos[i] = m_rankSupport(pos); } return rankPos; } uint64_t getRankPos(const uint64_t hash) const { return m_rankSupport(hash % m_bv.size()); } const vector>& getSeedValues() const { return m_ssVal; } unsigned getKmerSize() const { return m_kmerSize; } unsigned getHashNum() const { return m_hashNum; } /* * Computes id frequency based on data vector contents * Returns counts of repetitive sequence */ size_t getIDCounts(vector& counts) const { size_t saturatedCounts = 0; for (size_t i = 0; i < m_dSize; ++i) { if (m_data[i] > s_mask) { ++counts[m_data[i] & s_antiMask]; ++saturatedCounts; } else { ++counts[m_data[i]]; } } return saturatedCounts; } /* * computes id frequency based on datavector * Returns counts of repetitive sequence */ size_t getIDCountsStrand(vector& counts) const { size_t saturatedCounts = 0; for (size_t i = 0; i < m_dSize; ++i) { if (m_data[i] > s_mask) { ++counts[m_data[i] & s_idMask]; ++saturatedCounts; } else { ++counts[m_data[i] & s_antiStrand]; } } return saturatedCounts; } size_t getPop() const { size_t index = m_bv.size() - 1; while (m_bv[index] == 0) { --index; } return m_rankSupport(index) + 1; } /* * Mostly for debugging * should equal getPop if fully populated */ size_t getPopNonZero() const { size_t count = 0; for (size_t i = 0; i < m_dSize; ++i) { if (m_data[i] != 0) { ++count; } } return count; } /* * Checks data array for abnormal IDs * (i.e. values greater than what is possible) * Returns first abnormal ID or value of maxVal if no abnormal IDs are found * For debugging */ T checkValues(T maxVal) const { for (size_t i = 0; i < m_dSize; ++i) { if ((m_data[i] & s_antiMask) > maxVal) { return m_data[i]; } } return maxVal; } size_t getPopSaturated() const { size_t count = 0; for (size_t i = 0; i < m_dSize; ++i) { if (m_data[i] > s_mask) { ++count; } } return count; } size_t size() const { return m_bv.size(); } // overwrites existing value CAS void setData(uint64_t pos, T id) { T oldValue; do { oldValue = m_data[pos]; if (oldValue > s_mask) { id |= s_mask; } } while (!__sync_bool_compare_and_swap(&m_data[pos], oldValue, id)); } // saturates values void saturateData(uint64_t pos) { #pragma omp critical m_data[pos] |= s_mask; } // Does not overwrite void setDataIfEmpty(uint64_t pos, T id) { setVal(&m_data[pos], id); } vector getData(const vector& rankPos) const { vector results(rankPos.size()); for (unsigned i = 0; i < m_hashNum; ++i) { results[i] = m_data[rankPos[i]]; } return results; } T getData(uint64_t rank) const { return m_data[rank]; } /* * Preconditions: * frameProbs but be equal in size to multiMatchProbs * frameProbs must be preallocated to correct size (number of ids + 1) * Max value is the largest value seen in your set of possible values * Returns proportion of saturated elements relative to all elements */ double calcFrameProbs(vector& frameProbs, unsigned allowedMiss) { double occupancy = double(getPop()) / double(size()); vector countTable = vector(frameProbs.size(), 0); double satProp = double(getIDCounts(countTable)); size_t sum = 0; for (size_t i = 1; i < countTable.size(); ++i) { sum += countTable[i]; } satProp /= double(sum); for (size_t i = 1; i < countTable.size(); ++i) { frameProbs[i] = calcProbSingleFrame( occupancy, m_hashNum, double(countTable[i]) / double(sum), allowedMiss); } return satProp; } /* * Preconditions: * frameProbs but be equal in size to multiMatchProbs * frameProbs must be preallocated to correct size (number of ids + 1) * Max value is the largest value seen in your set of possible values * Returns proportion of saturated elements relative to all elements */ double calcFrameProbsStrand(vector& frameProbs, unsigned allowedMiss) { double occupancy = double(getPop()) / double(size()); vector countTable = vector(frameProbs.size(), 0); double satProp = double(getIDCountsStrand(countTable)); size_t sum = 0; for (vector::const_iterator itr = countTable.begin(); itr != countTable.end(); ++itr) { sum += *itr; } satProp /= double(sum); #pragma omp parallel for for (size_t i = 1; i < countTable.size(); ++i) { frameProbs[i] = calcProbSingleFrame( occupancy, m_hashNum, double(countTable[i]) / double(sum), allowedMiss); // frameProbs[i] = calcProbSingle(occupancy, // double(countTable[i]) / double(sum)); } return satProp; } ~MIBloomFilter() { delete[] m_data; } private: // Driver function to sort the vector elements // by second element of pairs static bool sortbysec(const pair& a, const pair& b) { return (a.second < b.second); } /* * Helper function for header storage */ void writeHeader(ofstream& out) const { FileHeader header; memcpy(header.magic, "MIBLOOMF", 8); header.hlen = sizeof(struct FileHeader) + m_kmerSize * m_sseeds.size(); header.kmer = m_kmerSize; header.size = m_dSize; header.nhash = m_hashNum; header.version = MIBloomFilter_VERSION; // cerr << "Writing header... magic: " << magic << " hlen: " << header.hlen // << " nhash: " << header.nhash << " size: " << header.size // << endl; out.write(reinterpret_cast(&header), sizeof(struct FileHeader)); for (vector::const_iterator itr = m_sseeds.begin(); itr != m_sseeds.end(); ++itr) { out.write(itr->c_str(), m_kmerSize); } } /* * Calculates the optimal number of hash function to use * Calculation assumes optimal ratio of bytes per entry given a fpr */ inline static unsigned calcOptiHashNum(double fpr) { return unsigned(-log(fpr) / log(2)); } /* * Calculate FPR based on hash functions, size and number of entries * see http://en.wikipedia.org/wiki/Bloom_filter */ double calcFPR_numInserted(size_t numEntr) const { return pow( 1.0 - pow(1.0 - 1.0 / double(m_bv.size()), double(numEntr) * double(m_hashNum)), double(m_hashNum)); } /* * Calculates the optimal FPR to use based on hash functions */ double calcFPR_hashNum(int hashFunctNum) const { return pow(2.0, -hashFunctNum); } /* * Returns old value that was inside * Does not overwrite if non-zero value already exists */ T setVal(T* val, T newVal) { T oldValue; do { oldValue = *val; if (oldValue != 0) break; } while (!__sync_bool_compare_and_swap(val, oldValue, newVal)); return oldValue; } static inline unsigned nChoosek(unsigned n, unsigned k) { if (k > n) return 0; if (k * 2 > n) k = n - k; if (k == 0) return 1; int result = n; for (unsigned i = 2; i <= k; ++i) { result *= (n - i + 1); result /= i; } return result; } // size of bitvector size_t m_dSize; sdsl::bit_vector_il m_bv; T* m_data; sdsl::rank_support_il<1> m_rankSupport; unsigned m_hashNum; unsigned m_kmerSize; typedef vector> SeedVal; vector m_sseeds; double m_probSaturated; SeedVal m_ssVal; static const uint32_t MIBloomFilter_VERSION = 1; }; #endif /* MIBLOOMFILTER_HPP_ */ abyss-2.2.4/vendor/btl_bloomfilter/Makefile.am000066400000000000000000000012031361462241400213470ustar00rootroot00000000000000SUBDIRS = \ Tests/AdHoc \ Tests/Unit include_HEADERS = \ BloomFilter.hpp \ CountingBloomFilter.hpp \ KmerBloomFilter.hpp \ MIBFQuerySupport.hpp \ MIBloomFilter.hpp \ vendor/catch.hpp \ vendor/nthash.hpp \ vendor/ntHashIterator.hpp \ vendor/ssHashIterator.hpp \ vendor/stHashIterator.hpp \ vendor/IOUtil.h \ vendor/cpptoml/include/cpptoml.h dist_doc_DATA = \ README.md EXTRA_DIST = autogen.sh clang-format: for i in *.hpp *.h */*.cpp Tests/*/*.*pp; do clang-format -style=file $$i >$$i.fixed; done for i in *.hpp *.h */*.cpp Tests/*/*.*pp; do diff -su $$i $$i.fixed && rm -f $$i.fixed; done if ls *.fixed; then exit 1; fi abyss-2.2.4/vendor/btl_bloomfilter/NEWS000066400000000000000000000000001361462241400200040ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/README000066400000000000000000000003431361462241400201770ustar00rootroot00000000000000Refer to manual for details on install and tool usage, which can be found on the BCGSC Website. If you have any have found any bugs, questions, comments, or even feature requests please contact Justin Chu (cjustin@bcgsc.ca). abyss-2.2.4/vendor/btl_bloomfilter/README.md000066400000000000000000000116541361462241400206050ustar00rootroot00000000000000# bloomfilter The BTL C/C++ Common Bloom filters for bioinformatics projects, as well as any APIs created for other programming languages. # usage example (C++) Fast Bloom filter loading using the rolling hash function. ```C++ #include "BloomFilter.hpp" #include #include #include "vendor/ntHashIterator.hpp" using namespace std; int main(int argc, char** argv) { /* test sequence */ const string seq = "TAGAATCACCCAAAGA"; /* k-mer size */ const unsigned k = 5; /* number of Bloom filter hash functions */ const unsigned numHashes = 4; /* size of Bloom filter (in bits) */ const unsigned size = 1000; //Building the filter { /* init Bloom filter */ BloomFilter bloom(size, numHashes, k); /* init rolling hash state and compute hash values for first k-mer */ ntHashIterator itr(seq, numHashes, k); while (itr != itr.end()) { bloom.insert(*itr); ++itr; } /* store the bloom filter */ bloom.storeFilter("filterPathname.bf"); } //After building { /* load the bloom filter */ BloomFilter bloom("filterPathname.bf"); /* query the bloom filter */ /* init rolling hash state and compute hash values for first k-mer */ ntHashIterator itr(seq, numHashes, k); while (itr != itr.end()) { bloom.contains(*itr); ++itr; } } return 0; } ``` Fast Counting Bloom filter loading using the rolling hash function. ```C++ #include "CountingBloomFilter.hpp" #include #include #include "vendor/ntHashIterator.hpp" using namespace std; int main(int argc, char** argv) { /* test sequence */ const string seq = "TAGAATCACCCAAAGA"; /* k-mer size */ const unsigned k = 5; /* number of Bloom filter hash functions */ const unsigned numHashes = 4; /* size of Bloom filter (in bytes) */ size_t size = 1000; /* counts to threshold bloom filter on*/ const unsigned threshold = 1; //Building the filter { /* init Bloom filter */ CountingBloomFilter bloom(size, numHashes, k, threshold); /* init rolling hash state and compute hash values for first k-mer */ ntHashIterator itr(seq, numHashes, k); while (itr != itr.end()) { bloom.insert(*itr); ++itr; } /* store the bloom filter */ bloom.storeFilter("filterPathname.bf"); } //After building { /* load the bloom filter */ CountingBloomFilter bloom("filterPathname.bf", threshold); /* query the bloom filter */ /* init rolling hash state and compute hash values for first k-mer */ ntHashIterator itr(seq, numHashes, k); while (itr != itr.end()) { bloom.contains(*itr); ++itr; } } return 0; } ``` # files * `BloomFilter.hpp`: main Bloom filter class * `CountingBloomFilter.hpp`: Counting Bloom filter class * `RollingHashIterator.h`: Enable rolling hashing on a string * `RollingHash.h`: rolling hash interface (required by `RollingHashIterator.h`) * `rolling.h`: rolling hash function (required by `BloomFilter.hpp` and `RollingHash.h`) * `Tests/Unit`: unit tests * `Tests/AdHoc`: ad-hoc tests # unit tests The unit tests may be compiled and run with: $ ./autogen.sh $ ./configure $ make check To see more detailed output for the individual tests, run the binaries in `Tests/Unit` from the command line. (The ad-hoc tests in `Tests/AdHoc` may also be run in this way.) # acknowledgements This projects uses: * [CATCH](https://github.com/philsquared/Catch) unit test framework for C/C++ * [nthash](https://github.com/bcgsc/ntHash) rolling hash implementation by Hamid Mohamadi * [cpptoml](https://github.com/skystrife/cpptoml) TOML parser and serializer implemented by Chase Geigle # Bloom filter file format The specification of the Bloom filter file format is as follows: 1. magic header string * Description: bf magic string * Type: string * Value: BTLBloomFilter_v1 or BTLCountingBloomFilter_v1 2. header * Description: Plain header text * Type: string * Value: * size * Description: The size of Bloom filter * Type: size_t * Value: * sizeInBytes * Description: The size of Bloom filter in bytes * Type: size_t * Value: * hashNum * Description: number of hashes * Type: unsigned * Value: * kmerSize * Description: k-mer size * Type: unsigned * Value: * dFPR [optional] * Description: desired false positve rate * Type: double * Value: * nEntry [optional] * Description: number of entries * Type: uint64_t * Value: * tEntry [optional] * Description: total number of entries * Type: uint64_t * Value: * seed [optional] \(Not yet implimented\) * Description: initial seeds for different hashes * Type: uint64_t[nhash] * Value: [0,1, ..., nhash-1] * bitsPerCounter [optional] * Description: bits per each counter in the counting bloom filter * Type: unsigned * Value: 8 3. filter * Description: Bloom filter content * Type: uchar[sizeInBytes] * Value: abyss-2.2.4/vendor/btl_bloomfilter/Tests/000077500000000000000000000000001361462241400204215ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/Tests/AdHoc/000077500000000000000000000000001361462241400213775ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/Tests/AdHoc/BloomFilterTests.cpp000066400000000000000000000101111361462241400253360ustar00rootroot00000000000000/* * BloomFilterTests.cpp * Unit Tests for hashmanager and bloomfilter classes * Created on: Aug 14, 2012 * Author: cjustin */ #include "BloomFilter.hpp" #include "vendor/ntHashIterator.hpp" #include #include #include #include #include #include #if _OPENMP #include #endif using namespace std; // returns memory of program in kb unsigned memory_usage() { unsigned mem = 0; ifstream proc("/proc/self/status"); string s; while (getline(proc, s), !proc.fail()) { if (s.substr(0, 6) == "VmSize") { stringstream convert(s.substr(s.find_last_of('\t'), s.find_last_of('k') - 1)); if (!(convert >> mem)) { return 0; } return mem; } } return mem; } int main() { // memory usage from before int memUsage = memory_usage(); size_t filterSize = 1000000; const unsigned numHashes = 3; const unsigned k = 4; const char* seq = "ACGTAC"; BloomFilter filter(filterSize, numHashes, k); // insert k-mers ACGT, CGTA, GTAC ntHashIterator insertIt(seq, numHashes, k); while (insertIt != insertIt.end()) { filter.insert(*insertIt); ++insertIt; } // check that k-mers were correctly inserted ntHashIterator queryIt(seq, numHashes, k); while (queryIt != queryIt.end()) { assert(filter.contains(*queryIt)); ++queryIt; } // should be size of bf (amortized) cout << memory_usage() - memUsage << "kb" << endl; cout << "de novo bf tests done" << endl; // Check storage can occur properly string filename = "/tmp/bloomFilter.bf"; filter.storeFilter(filename); ifstream ifile(filename.c_str()); assert(ifile.is_open()); // Read header line by line std::string headerEnd = "[HeaderEnd]"; std::string line; bool headerEndCheck = false; while (std::getline(ifile, line)) { if (line == headerEnd) { headerEndCheck = true; break; } } assert(headerEndCheck); // Get header and file size size_t currPos = ifile.tellg(); ifile.seekg(0, ios::end); // move to end of file size_t fileSize = ifile.tellg(); // file size in bytes // file size - header size should be same as filter size (Round to block size) if (filterSize % 64 > 0) { assert((filterSize + (64 - (filterSize % 64))) == (fileSize - currPos) * 8); } else { assert(filterSize == (fileSize - currPos) * 8); } ifile.close(); // should be roughly same size still (amortized) cout << memory_usage() - memUsage << "kb" << endl; // check loading of stored filter BloomFilter filter2(filename); // should be double size of bf (amortized) cout << memory_usage() - memUsage << "kb" << endl; // Check if loaded filter is able to report expected results ntHashIterator queryIt2(seq, numHashes, k); while (queryIt2 != queryIt2.end()) { assert(filter2.contains(*queryIt2)); ++queryIt2; } cout << "premade bf tests done" << endl; #if __linux__ // memory leak tests BloomFilter* filter3 = new BloomFilter(filterSize, 5, 20); size_t tempMem = memory_usage() - memUsage; cout << memory_usage() - memUsage << "kb" << endl; delete (filter3); cout << memory_usage() - memUsage << "kb" << endl; assert(tempMem != memory_usage() - memUsage); // vector > test(1, vector(1, 1)); // vector test; // test.push_back(filter2); cout << "memory leak prevention tests done" << endl; cout << memory_usage() - memUsage << "kb" << endl; #endif remove(filename.c_str()); // //check parallelized code speed // cout << "testing code parallelization" << endl; // double start_s = omp_get_wtime(); // // cout << "parallelization" << endl; // for( int i =0; i < 10000000; i++) // { // vector values = multiHash("ATCGGGTCATCAACCAATAA", 5, 20); // filter.contains(values); // } // double stop_s=omp_get_wtime(); // cout << "time: " << stop_s-start_s << endl; // // start_s = omp_get_wtime(); // cout << "non parallelization" << endl; // for( int i =0; i < 10000000; i++) // { // vector values = multiHashNonPara("ATCGGGTCATCAACCAATAA", 5, 20); // filter.contains(values); // } // stop_s=omp_get_wtime(); // cout << "time: " << stop_s-start_s << endl; cout << "done" << endl; return 0; } abyss-2.2.4/vendor/btl_bloomfilter/Tests/AdHoc/Makefile.am000066400000000000000000000010111361462241400234240ustar00rootroot00000000000000# programs that will only be compiled with 'make check' check_PROGRAMS = BloomFilterTests \ ParallelFilter BloomFilterTests_SOURCES = BloomFilterTests.cpp BloomFilterTests_CPPFLAGS = -I$(top_srcdir) BloomFilterTests_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) -std=c++11 ParallelFilter_SOURCES = ParallelFilter.cpp ParallelFilter_CPPFLAGS = -I$(top_srcdir) ParallelFilter_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) -std=c++11 # programs that will be run by 'make check' (after compiling) TESTS = $(check_PROGRAMS) abyss-2.2.4/vendor/btl_bloomfilter/Tests/AdHoc/ParallelFilter.cpp000066400000000000000000000130651361462241400250120ustar00rootroot00000000000000#include #include #include #include "BloomFilter.hpp" #include "vendor/ntHashIterator.hpp" #include #include #include #include #include #ifdef _OPENMP #include #endif namespace opt { /** default size of the Bloom filter in bits (1MB) */ size_t bloomBits = 1024 * 1024 * 8; unsigned kmerLen = 64; unsigned ibits = 64; unsigned nhash = 5; } using namespace std; static const unsigned char b2r[256] = { 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 0 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 1 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 2 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 3 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'T', 'N', 'G', 'N', 'N', 'N', 'C', // 4 'A' 'C' 'G' 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'A', 'N', 'N', 'N', // 5 'T' 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'T', 'N', 'G', 'N', 'N', 'N', 'C', // 6 'a' 'c' 'g' 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'A', 'N', 'N', 'N', // 7 't' 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 8 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 9 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 10 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 11 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 12 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 13 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 14 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', // 15 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N' }; void getCanon(std::string& bMer) { int p = 0, hLen = (opt::kmerLen - 1) / 2; while (bMer[p] == b2r[(unsigned char)bMer[opt::kmerLen - 1 - p]]) { ++p; if (p >= hLen) break; } if (bMer[p] > b2r[(unsigned char)bMer[opt::kmerLen - 1 - p]]) { for (int lIndex = p, rIndex = opt::kmerLen - 1 - p; lIndex <= rIndex; ++lIndex, --rIndex) { char tmp = b2r[(unsigned char)bMer[rIndex]]; bMer[rIndex] = b2r[(unsigned char)bMer[lIndex]]; bMer[lIndex] = tmp; } } } void loadSeq(BloomFilter& BloomFilterFilter, const string& seq) { if (seq.size() < opt::kmerLen) return; ntHashIterator insertIt(seq, BloomFilterFilter.getHashNum(), BloomFilterFilter.getKmerSize()); while (insertIt != insertIt.end()) { BloomFilterFilter.insert(*insertIt); ++insertIt; } } void loadSeqr(BloomFilter& BloomFilterFilter, const string& seq) { if (seq.size() < opt::kmerLen) return; string kmer = seq.substr(0, opt::kmerLen); ntHashIterator itr(seq, opt::kmerLen, opt::nhash); while (itr != itr.end()) { BloomFilterFilter.insert(*itr); ++itr; } } void loadBf(BloomFilter& BloomFilterFilter, const char* faqFile) { ifstream uFile(faqFile); bool good = true; #pragma omp parallel for (string line, hline; good;) { #pragma omp critical(uFile) { good = static_cast(getline(uFile, hline)); good = static_cast(getline(uFile, line)); // good = getline(uFile, hline); // good = getline(uFile, hline); } if (good) loadSeqr(BloomFilterFilter, line); } uFile.close(); } int main(int argc, const char* argv[]) { /*BloomFilter myFilter(40857600000, 2, 30); string mystr="AGAGACGTGCATCGGGTCATCAACCAATAT"; myFilter.insert(mystr.c_str()); if (myFilter.search(mystr.c_str())) cerr << mystr << " is in Bloom filter.\n"; else cerr << mystr << " is not in Bloom filter.\n"; return 0;*/ if (argc < 2) cerr << "error!\n"; #ifdef _OPENMP double sTime = omp_get_wtime(); #endif /* * Note: The previous Bloom filter size here was * 48,857,600,000 bits (~6GB). I reduced it to 1024*1024*8 * (1MB) by default, so that it would run safely on any machine. * -BV */ BloomFilter myFilter(opt::bloomBits, opt::nhash, opt::kmerLen); loadBf(myFilter, argv[1]); cerr << "|popBF|=" << myFilter.getPop() << " "; #ifdef _OPENMP cerr << setprecision(4) << fixed << omp_get_wtime() - sTime << "\n"; #else cerr << "\n"; #endif // myFilter.store("filter3.bf"); /*BloomFilter filter2(40857600000, 5, 30, "filter1.bf"); cerr << "|popBF|=" << filter2.getPop() << " "; cerr << setprecision(4) << fixed << omp_get_wtime() - sTime << "\n"; filter2.store("filter2.bf");*/ return 0; } abyss-2.2.4/vendor/btl_bloomfilter/Tests/Unit/000077500000000000000000000000001361462241400213405ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/Tests/Unit/BloomFilterTests.cpp000066400000000000000000000063271361462241400253150ustar00rootroot00000000000000/* * BloomFilterTests.cpp * Unit Tests for hashmanager and bloomfilter classes * Created on: Aug 14, 2012 * Author: cjustin */ /* automatically create main() function to run tests */ #define CATCH_CONFIG_MAIN /* lightweight unit test framework */ #include "BloomFilter.hpp" #include "vendor/catch.hpp" #include "vendor/ntHashIterator.hpp" #include #include #include #include #include #include using namespace std; /** create a uniquely-named temp file (tedious!) */ string createTempFile() { const unsigned MAX_FILENAME_SIZE = 1024; const char* fileTemplate = "/XXXXXX"; char filename[MAX_FILENAME_SIZE + 1]; /* allow override of default tmp dir */ char* tmpdir = getenv("TMPDIR"); if (tmpdir) strcpy(filename, tmpdir); else strcpy(filename, "/tmp"); assert(strlen(filename) + strlen(fileTemplate) <= MAX_FILENAME_SIZE); strcat(filename, fileTemplate); int fd = mkstemp(filename); if (fd == -1) { perror("failed to create temp file"); exit(EXIT_FAILURE); } close(fd); return string(filename); } TEST_CASE("test fixture", "[BloomFilter]") { /* * NOTES: * - The SECTION blocks below are separate tests that share the * same setup code * - The common setup code is _re-run_ before each SECTION * - In unit test terminology, this type of setup is known as a * "test fixture" * - See * https://github.com/philsquared/Catch/blob/master/docs/tutorial.md#test-cases-and-sections for * details */ /* START COMMON SETUP CODE */ const size_t filterSize = 1000000000; const unsigned numHashes = 5; const unsigned k = 4; const char* seq = "ACGTAC"; BloomFilter filter(filterSize, numHashes, k); /* insert k-mers ACGT, CGTA, GTAC */ ntHashIterator insertIt(seq, numHashes, k); while (insertIt != insertIt.end()) { filter.insert(*insertIt); ++insertIt; } /* END COMMON SETUP CODE */ SECTION("query elements") { /* check that k-mers were correctly inserted */ ntHashIterator queryIt(seq, numHashes, k); while (queryIt != queryIt.end()) { assert(filter.contains(*queryIt)); ++queryIt; } } SECTION("save/load Bloom file") { /* write filter */ string filename = createTempFile(); filter.storeFilter(filename); ifstream ifile(filename.c_str()); /* check size of newly-created file */ assert(ifile.is_open()); /* File header has no fixed element but "[HeaderEnd]" so check for "[HeaderEnd]" in file*/ std::string headerEnd = "[HeaderEnd]"; std::string line; bool headerEndCheck = false; while (std::getline(ifile, line)) { if (line == headerEnd) { headerEndCheck = true; break; } } assert(headerEndCheck); size_t currPos = ifile.tellg(); ifile.seekg(0, ios::end); size_t endPos = ifile.tellg(); ifile.close(); /* check loading of stored filter */ BloomFilter filter2(filename); // Checking if sizeInBytes correspond to filesize - header assert((endPos - currPos) == filter2.sizeInBytes()); /* check if loaded filter is able to report expected results */ ntHashIterator queryIt(seq, numHashes, k); while (queryIt != queryIt.end()) { assert(filter2.contains(*queryIt)); ++queryIt; } /* cleanup */ remove(filename.c_str()); } } /* end test fixture */ abyss-2.2.4/vendor/btl_bloomfilter/Tests/Unit/CountingBloomFilterTests.cpp000066400000000000000000000134511361462241400270200ustar00rootroot00000000000000/* * CountingBloomFilterTests.cpp * Unit Tests for CountingBloomFilter class * Adapted from BloomFilterTests.cpp * Created on: July 15, 2019 * Author: Johnathan Wong */ /* automatically create main() function to run tests */ #define CATCH_CONFIG_MAIN /* lightweight unit test framework */ #include "CountingBloomFilter.hpp" #include "vendor/catch.hpp" #include "vendor/ntHashIterator.hpp" #include #include #include #include #include #include using namespace std; /** create a uniquely-named temp file (tedious!) */ string createTempFile() { const unsigned MAX_FILENAME_SIZE = 1024; const char* fileTemplate = "/XXXXXX"; char filename[MAX_FILENAME_SIZE + 1]; /* allow override of default tmp dir */ char* tmpdir = getenv("TMPDIR"); if (tmpdir) strcpy(filename, tmpdir); else strcpy(filename, "/tmp"); assert(strlen(filename) + strlen(fileTemplate) <= MAX_FILENAME_SIZE); strcat(filename, fileTemplate); int fd = mkstemp(filename); if (fd == -1) { perror("failed to create temp file"); exit(EXIT_FAILURE); } close(fd); return string(filename); } TEST_CASE("test fixture", "[CountingBloomFilter]") { /* * NOTES: * - The SECTION blocks below are separate tests that share the * same setup code * - The common setup code is _re-run_ before each SECTION * - In unit test terminology, this type of setup is known as a * "test fixture" * - See * https://github.com/philsquared/Catch/blob/master/docs/tutorial.md#test-cases-and-sections for * details */ /* START COMMON SETUP CODE */ const size_t filterSize = 100001; const unsigned numHashes = 5; const unsigned threshold = 1; const unsigned k = 8; const char* seq = "ACGTACACTGGACTGAGTCT"; CountingBloomFilter filter(filterSize, numHashes, k, threshold); /* insert k-mers ACGT, CGTA, GTAC */ ntHashIterator insertIt(seq, numHashes, k); while (insertIt != insertIt.end()) { filter.insert(*insertIt); ++insertIt; } CountingBloomFilter filter_64bit(filterSize, numHashes, k, threshold); /* insert k-mers ACGT, CGTA, GTAC */ ntHashIterator insertIt2(seq, numHashes, k); while (insertIt2 != insertIt2.end()) { filter_64bit.insert(*insertIt2); ++insertIt2; } /* END COMMON SETUP CODE */ SECTION("query elements") { /* check that k-mers were correctly inserted */ ntHashIterator queryIt(seq, numHashes, k); while (queryIt != queryIt.end()) { assert(filter.contains(*queryIt)); assert(filter_64bit.contains(*queryIt)); ++queryIt; } /* check that k-mers were not incorrectly inserted */ string seq2; string DNA = "ATCG"; srand(time(0)); for (int i = 0; i < 60; i++) { seq2 += DNA[rand() % 4]; } ntHashIterator queryIt2(seq2.c_str(), numHashes, k); while (queryIt2 != queryIt2.end()) { assert(!filter.contains(*queryIt2)); assert(!filter_64bit.contains(*queryIt2)); ++queryIt2; } } SECTION("save/load 8 bit Bloom file") { /* write filter */ string filename = createTempFile(); filter.storeFilter(filename); ifstream ifile(filename.c_str()); /* check size of newly-created file */ assert(ifile.is_open()); /* File header has no fixed element but "[HeaderEnd]" so check for "[HeaderEnd]" in file*/ std::string headerEnd = "[HeaderEnd]"; std::string line; bool headerEndCheck = false; while (std::getline(ifile, line)) { if (line == headerEnd) { headerEndCheck = true; break; } } assert(headerEndCheck); size_t currPos = ifile.tellg(); ifile.seekg(0, ios::end); size_t endPos = ifile.tellg(); // file size - header should be same as filter size rounded to multiple of 64 int remainder = filterSize % 8; assert((endPos - currPos) == (filterSize + 8 - remainder)); ifile.close(); /* check loading of stored filter */ CountingBloomFilter filter2(filename, threshold); // Checking if sizeInBytes correspond to filesize - header assert((endPos - currPos) == filter2.sizeInBytes()); // In a 8bit filter, size should be equal to size_in_bytes assert(filter2.size() == filter2.sizeInBytes()); /* check if loaded filter is able to report expected results */ ntHashIterator queryIt(seq, numHashes, k); while (queryIt != queryIt.end()) { assert(filter2.contains(*queryIt)); ++queryIt; } /* cleanup */ remove(filename.c_str()); } SECTION("save/load 64 bit Bloom file") { /* write filter */ string filename = createTempFile(); filter_64bit.storeFilter(filename); ifstream ifile(filename.c_str()); /* check size of newly-created file */ assert(ifile.is_open()); /* File header has no fixed element but "[HeaderEnd]" so check for "[HeaderEnd]" in file*/ std::string headerEnd = "[HeaderEnd]"; std::string line; bool headerEndCheck = false; while (std::getline(ifile, line)) { if (line == headerEnd) { headerEndCheck = true; break; } } assert(headerEndCheck); size_t currPos = ifile.tellg(); ifile.seekg(0, ios::end); size_t endPos = ifile.tellg(); // file size - header should be same as filter size rounded to multiple of 64 int remainder = filterSize % 8; assert((endPos - currPos) == (filterSize + 8 - remainder)); ifile.close(); /* check loading of stored filter */ CountingBloomFilter filter_64bit2(filename, threshold); // Checking if sizeInBytes correspond to filesize - header assert((endPos - currPos) == filter_64bit2.sizeInBytes()); // In a 64bit filter, size * 8 should be equal to size_in_bytes assert((filter_64bit2.size() * 8) == filter_64bit2.sizeInBytes()); /* check if loaded filter is able to report expected results */ ntHashIterator queryIt(seq, numHashes, k); while (queryIt != queryIt.end()) { assert(filter_64bit2.contains(*queryIt)); ++queryIt; } /* cleanup */ remove(filename.c_str()); } } /* end test fixture */ abyss-2.2.4/vendor/btl_bloomfilter/Tests/Unit/Makefile.am000066400000000000000000000011041361462241400233700ustar00rootroot00000000000000# programs that will only be compiled with 'make check' check_PROGRAMS = \ BloomFilterTests \ CountingBloomFilterTests BloomFilterTests_SOURCES = BloomFilterTests.cpp BloomFilterTests_CPPFLAGS = -I$(top_srcdir) BloomFilterTests_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) -std=c++11 CountingBloomFilterTests_SOURCES = CountingBloomFilterTests.cpp CountingBloomFilterTests_CPPFLAGS = -I$(top_srcdir) CountingBloomFilterTests_CXXFLAGS = $(AM_CXXFLAGS) $(OPENMP_CXXFLAGS) -std=c++11 # programs that will be run by 'make check' (after compiling) TESTS = $(check_PROGRAMS) abyss-2.2.4/vendor/btl_bloomfilter/autogen.sh000077500000000000000000000000721361462241400213170ustar00rootroot00000000000000#!/bin/sh set -ex aclocal autoconf autoheader automake -a abyss-2.2.4/vendor/btl_bloomfilter/azure-pipelines.yml000066400000000000000000000023321361462241400231560ustar00rootroot00000000000000jobs: - job: linux_gcc_default pool: vmImage: "Ubuntu 16.04" steps: - script: | ./autogen.sh ./configure make distcheck displayName: "Compile btl_bloomfilter with gcc_default" - script: | curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" sudo apt-get update sudo apt-get install -y --no-install-recommends clang-format-8 sudo ln -s clang-format-8 /usr/bin/clang-format displayName: Install clang-format - script: make clang-format displayName: Run clang-format - job: linux_clang6 pool: vmImage: "Ubuntu 16.04" steps: - script: sudo apt-get install -qq clang-6.0 displayName: Install clang-6.0 - script: | ./autogen.sh ./configure CC=clang-6.0 CXX=clang++-6.0 make distcheck displayName: "Compile btl_bloomfilter with clang 6.0" - job: macOS_gcc_default pool: vmImage: macOS-10.14 steps: - script: | brew update brew install automake displayName: Install automake - script: | ./autogen.sh ./configure make distcheck displayName: "Compile btl_bloomfilter with default gcc" abyss-2.2.4/vendor/btl_bloomfilter/configure.ac000066400000000000000000000015531361462241400216110ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) AC_INIT(BLOOMFILTER, 1.2.1, cjustin@bcgsc.ca) AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE() AC_CONFIG_HEADER([config.h]) AC_PROG_RANLIB # Checks for programs. AC_PROG_CXX # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T # Find the absolute paths. my_abs_srcdir=$(cd $srcdir; pwd) # Checks for header files. AC_LANG([C++]) #sets the auto conf to look for c++ headers # Check for OpenMP. AC_OPENMP if test -z $OPENMP_CXXFLAGS; then OPENMP_CXXFLAGS=-Wno-unknown-pragmas fi # Set compiler flags. AC_SUBST(AM_CXXFLAGS, '-Wall -Wextra -Werror') # Checks for typedefs, structures, and compiler characteristics. AC_CONFIG_FILES([ Makefile Tests/Unit/Makefile Tests/AdHoc/Makefile ]) AC_OUTPUT abyss-2.2.4/vendor/btl_bloomfilter/pythonInterface/000077500000000000000000000000001361462241400224615ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/pythonInterface/BloomFilter_pythonwrapper.cpp000066400000000000000000000264101361462241400304100ustar00rootroot00000000000000/* * * BloomFilter_pythonwrapper.cpp * * Created on: Dec 28, 2015 * */ #include #include #include #ifndef BLOOMFILTER_H_ #define BLOOMFILTER_H_ #include "rolling.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const uint8_t bitsPerChar = 0x08; static const unsigned char bitMask[0x08] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; inline unsigned popCnt(unsigned char x) { return ((0x876543210 >> (((0x4332322132212110 >> ((x & 0xF) << 2)) & 0xF) << 2)) >> ((0x4332322132212110 >> (((x & 0xF0) >> 2)) & 0xF) << 2)) & 0xf; } class BloomFilter { public: /* * Default constructor. */ BloomFilter() : m_filter(NULL) , m_size(0) , m_sizeInBytes(0) , m_hashNum(0) , m_kmerSize(0) {} /* De novo filter constructor. * * preconditions: * filterSize must be a multiple of 64 * kmerSize refers to the number of bases the kmer has * k-mers supplied to this object should be binary (2 bits per base) */ BloomFilter(size_t filterSize, unsigned hashNum, unsigned kmerSize) : m_size(filterSize) , m_hashNum(hashNum) , m_kmerSize(kmerSize) { initSize(m_size); memset(m_filter, 0, m_sizeInBytes); } /* * Loads the filter (file is a .bf file) from path specified */ BloomFilter( size_t filterSize, unsigned hashNum, unsigned kmerSize, string const& filterFilePath) : m_size(filterSize) , m_hashNum(hashNum) , m_kmerSize(kmerSize) { initSize(m_size); FILE* file = fopen(filterFilePath.c_str(), "rb"); if (file == NULL) { cerr << "file \"" << filterFilePath << "\" could not be read." << endl; exit(1); } long int lCurPos = ftell(file); fseek(file, 0, 2); size_t fileSize = ftell(file); fseek(file, lCurPos, 0); if (fileSize != m_sizeInBytes) { cerr << "Error: " << filterFilePath << " does not match size given by its information file. Size: " << fileSize << " vs " << m_sizeInBytes << " bytes." << endl; exit(1); } size_t countRead = fread(m_filter, fileSize, 1, file); if (countRead != 1 && fclose(file) != 0) { cerr << "file \"" << filterFilePath << "\" could not be read." << endl; exit(1); } } /* * For precomputing hash values. kmerSize is the number of bytes of the original string used. */ vector multiHash(const char* kmer) const { vector tempHashValues(m_hashNum); uint64_t hVal = getChval(kmer, m_kmerSize); for (size_t i = 0; i < m_hashNum; ++i) { tempHashValues[i] = (rol(varSeed, i) ^ hVal); } return tempHashValues; } /* * For precomputing hash values. kmerSize is the number of bytes of the original string used. */ vector multiHash(const char* kmer, uint64_t& fhVal, uint64_t& rhVal) const { vector tempHashValues(m_hashNum); fhVal = getFhval(kmer, m_kmerSize); rhVal = getRhval(kmer, m_kmerSize); uint64_t hVal = (rhVal < fhVal) ? rhVal : fhVal; for (unsigned i = 0; i < m_hashNum; i++) { tempHashValues[i] = (rol(varSeed, i) ^ hVal); } return tempHashValues; } /* * For precomputing hash values. kmerSize is the number of bytes of the original string used. */ vector multiHash(uint64_t& fhVal, uint64_t& rhVal, const char charOut, const char charIn) const { vector tempHashValues(m_hashNum); fhVal = rol(fhVal, 1) ^ rol(seedTab[(unsigned char)charOut], m_kmerSize) ^ seedTab[(unsigned char)charIn]; rhVal = ror(rhVal, 1) ^ ror(seedTab[(unsigned char)(charOut + cpOff)], 1) ^ rol(seedTab[(unsigned char)(charIn + cpOff)], m_kmerSize - 1); uint64_t hVal = (rhVal < fhVal) ? rhVal : fhVal; for (unsigned i = 0; i < m_hashNum; i++) { tempHashValues[i] = (rol(varSeed, i) ^ hVal); } return tempHashValues; } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. */ void insert(vector const& precomputed) { // iterates through hashed values adding it to the filter for (size_t i = 0; i < m_hashNum; ++i) { size_t normalizedValue = precomputed.at(i) % m_size; __sync_or_and_fetch( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); // m_filter[normalizedValue / bitsPerChar] |= bitMask[normalizedValue // % bitsPerChar]; } } void insert(const char* kmer) { uint64_t hVal = getChval(kmer, m_kmerSize); for (unsigned i = 0; i < m_hashNum; i++) { size_t normalizedValue = (rol(varSeed, i) ^ hVal) % m_size; __sync_or_and_fetch( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); } } void insert(const char* kmer, uint64_t& fhVal, uint64_t& rhVal) { fhVal = getFhval(kmer, m_kmerSize); rhVal = getRhval(kmer, m_kmerSize); uint64_t hVal = (rhVal < fhVal) ? rhVal : fhVal; for (unsigned i = 0; i < m_hashNum; i++) { size_t normalizedValue = (rol(varSeed, i) ^ hVal) % m_size; __sync_or_and_fetch( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); } } void insert(uint64_t& fhVal, uint64_t& rhVal, const char charOut, const char charIn) { fhVal = rol(fhVal, 1) ^ rol(seedTab[(unsigned char)charOut], m_kmerSize) ^ seedTab[(unsigned char)charIn]; rhVal = ror(rhVal, 1) ^ ror(seedTab[(unsigned char)(charOut + cpOff)], 1) ^ rol(seedTab[(unsigned char)(charIn + cpOff)], m_kmerSize - 1); uint64_t hVal = (rhVal < fhVal) ? rhVal : fhVal; for (unsigned i = 0; i < m_hashNum; i++) { size_t normalizedValue = (rol(varSeed, i) ^ hVal) % m_size; __sync_or_and_fetch( &m_filter[normalizedValue / bitsPerChar], bitMask[normalizedValue % bitsPerChar]); } } /* * Accepts a list of precomputed hash values. Faster than rehashing each time. */ bool contains(vector const& values) { for (size_t i = 0; i < m_hashNum; ++i) { size_t normalizedValue = values.at(i) % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) != bit) { return false; } } return true; } /* * Single pass filtering, computes hash values on the fly */ bool contains(const char* kmer) { uint64_t hVal = getChval(kmer, m_kmerSize); for (unsigned i = 0; i < m_hashNum; i++) { size_t normalizedValue = (rol(varSeed, i) ^ hVal) % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) == 0) return false; } return true; } bool contains(const char* kmer, uint64_t& fhVal, uint64_t& rhVal) { fhVal = getFhval(kmer, m_kmerSize); rhVal = getRhval(kmer, m_kmerSize); uint64_t hVal = (rhVal < fhVal) ? rhVal : fhVal; for (unsigned i = 0; i < m_hashNum; i++) { size_t normalizedValue = (rol(varSeed, i) ^ hVal) % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) == 0) return false; } return true; } bool contains(uint64_t& fhVal, uint64_t& rhVal, const char charOut, const char charIn) { fhVal = rol(fhVal, 1) ^ rol(seedTab[(unsigned char)charOut], m_kmerSize) ^ seedTab[(unsigned char)charIn]; rhVal = ror(rhVal, 1) ^ ror(seedTab[(unsigned char)(charOut + cpOff)], 1) ^ rol(seedTab[(unsigned char)(charIn + cpOff)], m_kmerSize - 1); uint64_t hVal = (rhVal < fhVal) ? rhVal : fhVal; for (unsigned i = 0; i < m_hashNum; i++) { size_t normalizedValue = (rol(varSeed, i) ^ hVal) % m_size; unsigned char bit = bitMask[normalizedValue % bitsPerChar]; if ((m_filter[normalizedValue / bitsPerChar] & bit) == 0) return false; } return true; } /* * Stores the filter as a binary file to the path specified * Stores uncompressed because the random data tends to * compress poorly anyway */ void storeFilter(string const& filterFilePath) const { ofstream myFile(filterFilePath.c_str(), ios::out | ios::binary); cerr << "Storing filter. Filter is " << m_sizeInBytes << "bytes." << endl; assert(myFile); // write out each block myFile.write(reinterpret_cast(m_filter), m_sizeInBytes); myFile.close(); assert(myFile); } size_t getPop() const { size_t i, popBF = 0; #pragma omp parallel for reduction(+ : popBF) for (i = 0; i < (m_size + 7) / 8; i++) popBF = popBF + popCnt(m_filter[i]); return popBF; } unsigned getHashNum() const { return m_hashNum; } unsigned getKmerSize() const { return m_kmerSize; } size_t getFilterSize() const { return m_size; } ~BloomFilter() { delete[] m_filter; } // private: // BloomFilter(const BloomFilter& that); //to prevent copy construction /* * Checks filter size and initializes filter */ void initSize(size_t size) { if (size % 8 != 0) { cerr << "ERROR: Filter Size \"" << size << "\" is not a multiple of 8." << endl; exit(1); } m_sizeInBytes = size / bitsPerChar; m_filter = new unsigned char[m_sizeInBytes]; } uint8_t* m_filter; size_t m_size; size_t m_sizeInBytes; unsigned m_hashNum; unsigned m_kmerSize; }; #endif /* BLOOMFILTER_H_ */ // Introducing member function pointer variables for multiHash: vector (BloomFilter::*fx1)(const char*) const = &BloomFilter::multiHash; vector (BloomFilter::*fx2)(const char*, uint64_t&, uint64_t&) const = &BloomFilter::multiHash; vector (BloomFilter::*fx3)(uint64_t&, uint64_t&, const char, const char) const = &BloomFilter::multiHash; // Introducing member function pointer variables for contains: bool (BloomFilter::*fx4)(vector const&) = &BloomFilter::contains; bool (BloomFilter::*fx5)(const char*) = &BloomFilter::contains; bool (BloomFilter::*fx6)(const char*, uint64_t&, uint64_t&) = &BloomFilter::contains; bool (BloomFilter::*fx7)(uint64_t&, uint64_t&, const char, const char) = &BloomFilter::contains; // Introducing member function pointer variables for insert: void (BloomFilter::*fx8)(vector const&) = &BloomFilter::insert; void (BloomFilter::*fx9)(const char*) = &BloomFilter::insert; void (BloomFilter::*fx10)(const char*, uint64_t&, uint64_t&) = &BloomFilter::insert; void (BloomFilter::*fx11)(uint64_t&, uint64_t&, const char, const char) = &BloomFilter::insert; BOOST_PYTHON_MODULE(bloomfilter_ext) { using namespace boost::python; class_("BloomFilter", init()) .def(init()) .def_readwrite("m_filter", &BloomFilter::m_filter) .def_readwrite("m_size", &BloomFilter::m_size) .def_readwrite("m_sizeInBytes", &BloomFilter::m_sizeInBytes) .def_readwrite("m_hashNum", &BloomFilter::m_hashNum) .def_readwrite("m_kmerSize", &BloomFilter::m_kmerSize) .def("multiHash", fx1) .def("multiHash", fx2) .def("multiHash", fx3) .def("contains", fx4) .def("contains", fx5) .def("contains", fx6) .def("contains", fx7) .def("insert", fx8) .def("insert", fx9) .def("insert", fx10) .def("insert", fx11) .def("storeFilter", &BloomFilter::storeFilter) .def("getPop", &BloomFilter::getPop) .def("getHashNum", &BloomFilter::getHashNum) .def("getKmerSize", &BloomFilter::getKmerSize) .def("getFilterSize", &BloomFilter::getFilterSize) .def("initSize", &BloomFilter::initSize) ; } abyss-2.2.4/vendor/btl_bloomfilter/pythonInterface/Jamroot000066400000000000000000000031411361462241400240160ustar00rootroot00000000000000# Copyright David Abrahams 2006. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) import python ; if ! [ python.configured ] { ECHO "notice: no Python configured in user-config.jam" ; ECHO "notice: will use default configuration" ; using python ; } # Specify the path to the Boost project. If you move this project, # adjust this path to refer to the Boost root directory. use-project boost : /projects/btl/hkhan/source/boost_1_60_0 ; # Set up the project-wide requirements that everything uses the # boost_python library from the project whose global ID is # /boost/python. project : requirements /boost/python//boost_python /boost//headers : usage-requirements /boost//headers ; # Declare the three extension modules. You can specify multiple # source files after the colon separated by spaces. python-extension bloomfilter_ext : BloomFilter_pythonwrapper.cpp ; # Put the extension and Boost.Python DLL in the current directory, so # that running script by hand works. install convenient_copy : bloomfilter_ext : on SHARED_LIB PYTHON_EXTENSION . ; # A little "rule" (function) to clean up the syntax of declaring tests # of these extension modules. local rule run-test ( test-name : sources + ) { import testing ; testing.make-test run-pyd : $(sources) : : $(test-name) ; } # Declare test targets run-test Bloom : bloomfilter_ext bloomfilter.py ; abyss-2.2.4/vendor/btl_bloomfilter/pythonInterface/bloomfilter.py000066400000000000000000000001361361462241400253510ustar00rootroot00000000000000import bloomfilter_ext a= bloomfilter_ext.BloomFilter(1000, 5, 4); print a; print "Works!" abyss-2.2.4/vendor/btl_bloomfilter/pythonInterface/python_wrapper.readme000066400000000000000000000021031361462241400267150ustar00rootroot00000000000000Python wrapper for BloomFilter.hpp Requirements - Boost python library (http://www.boost.org/doc/libs/1_60_0/libs/python/doc/html/building.html) Available at - /projects/btl/hkhan/source/boost_1_60_0 -This script has the wrapper code for all constructors and member functions. -The script uses bjam to build the 'bloomfilter_ext' python module. (bjam is the build tool that comes bundled with every boost distribution) -The Jamroot file is a minimalist bjam script that builds the DLLs. It has a number of information such as the boost library path, cpp file name, python module name, python file name, etc. Build instructions - bjam The script runs without any errors. The user should refer the individual constructors/functions and use the appropriate arguments. As many datatypes in C++ are not available in python, users should use NumPy data types objects. (http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html) For more info, please refer - Boost python library (http://www.boost.org/doc/libs/1_60_0/libs/python/doc/html/tutorial/index.html#tutorial.quickstart) abyss-2.2.4/vendor/btl_bloomfilter/swig/000077500000000000000000000000001361462241400202705ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/swig/BloomFilter.i000066400000000000000000000027641361462241400226710ustar00rootroot00000000000000%module BloomFilter %include "std_string.i" %include "stdint.i" %include "std_vector.i" /*%apply const uint64_t& { uint64_t & };*/ /*%apply uint64_t& INOUT {uint64_t& fhVal, uint64_t& rhVal};*/ namespace std { %template(SizetVector) vector; } %{ #include "../KmerBloomFilter.hpp" #include "../vendor/ntHashIterator.hpp" #include "../BloomFilterUtil.h" %} %rename(BloomFilter) KmerBloomFilter; using namespace std; class KmerBloomFilter { public: KmerBloomFilter(); ~KmerBloomFilter(); KmerBloomFilter(uint64_t filterSize, unsigned hashNum, unsigned kmerSize); KmerBloomFilter(const string &filterFilePath); void insert(vector const &precomputed); void insert(const char* kmer); bool contains(vector const &values); bool contains(const char* kmer); void storeFilter(string const &filterFilePath); uint64_t getPop(); unsigned getHashNum(); unsigned getKmerSize(); uint64_t getFilterSize(); }; /* class ntHashIterator { public: ntHashIterator(); ~ntHashIterator(); ntHashIterator(const string& seq, unsigned numHashes, unsigned k); const uint64_t* operator*(); const uint64_t* operator->(); bool operator==(const ntHashIterator& it); bool operator!=(const ntHashIterator& it); ntHashIterator& operator++(); static const ntHashIterator end(); }; */ void insertSeq(KmerBloomFilter &bloom, const string& seq, unsigned numHashes, unsigned k); abyss-2.2.4/vendor/btl_bloomfilter/swig/README.md000066400000000000000000000026641361462241400215570ustar00rootroot00000000000000# Swig Make sure you have swig installed and included in your path. To build a Perl5 module (run in swig/): ``` preinst-swig -Wall -c++ -perl5 BloomFilter.i g++ -std=c++11 -c BloomFilter_wrap.cxx -I/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE -fPIC g++ -std=c++11 -Wall -shared BloomFilter_wrap.o -o BloomFilter.so ``` On mac you may need to instead run: ``` preinst-swig -Wall -c++ -perl5 BloomFilter.i g++ -std=c++11 -c `perl -MConfig -e 'print join(" ", @Config{qw(ccflags optimize cccdlflags)}, "-I$Config{archlib}/CORE")'` BloomFilter_wrap.cxx -Wno-reserved-user-defined-literal g++ -std=c++11 `perl -MConfig -e 'print $Config{lddlflags}'` BloomFilter_wrap.o -o BloomFilter.so ``` To run tests: ``` # To test insertions: ./writeBloom_rolling.pl Usage: ./writeBloom_rolling.pl -f sequences to scaffold (Multi-FASTA format, required) -k k-mer value (default -k 15, optional) -p Bloom filter false positive rate (default -p 0.0001, optional - increase to prevent memory allocation errors) # To test queries: ./testBloom_rolling.pl Usage: ./testBloom_rolling.pl -f sequences to test (Multi-FASTA format, required) -k k-mer value (default -k 15, optional) -b Bloom filter (required) ``` In order to compile, swig needs the following Perl5 headers: ```C++ #include "Extern.h" #include "perl.h" #include "XSUB.h" ``` If they are not located in /usr/lib64/perl5, you can run "perl -e 'use Config; print $Config{archlib};" to locate them. abyss-2.2.4/vendor/btl_bloomfilter/swig/test.pl000077500000000000000000000043421361462241400216120ustar00rootroot00000000000000#!/usr/bin/env perl use FindBin; use lib "$FindBin::Bin/./"; use BloomFilter; #Same inputs as the adhoc tests $filterSize = 1000000000; #Check if filter is able to report expected results $filter = BloomFilter::BloomFilter->new($filterSize, 5, 20); $filter->insert("ATCGGGTCATCAACCAATAT"); $filter->insert("ATCGGGTCATCAACCAATAC"); $filter->insert("ATCGGGTCATCAACCAATAG"); $filter->insert("ATCGGGTCATCAACCAATAA"); if (!$filter->contains("ATCGGGTCATCAACCAATAT") &&!$filter->contains("ATCGGGTCATCAACCAATAC") && !$filter->contains("ATCGGGTCATCAACCAATAG") && !BloomFilter::BloomFilter::contains($filter, "ATCGGGTCATCAACCAATAA")) { print "Filter did not contain expected. \n"; } if ($filter->contains("ATCGGGTCATCAACCAATTA") && $filter->("ATCGGGTCATCAACCAATTC")) { print "Filter contained unexpected. \n"; } print "de novo bf tests done \n"; #Check storage can occur properly $fileName = "BloomFilter.bf"; $filter->storeFilter($fileName); $filter2 = new BloomFilter::BloomFilter($fileName); if (!$filter2->contains("ATCGGGTCATCAACCAATAT") &&!$filter2->contains("ATCGGGTCATCAACCAATAC") && !$filter2->contains("ATCGGGTCATCAACCAATAG") && !$filter2->contains("ATCGGGTCATCAACCAATAA")) { print "Filter2 did not contain expected. \n"; } if ($filter2->contains("ATCGGGTCATCAACCAATTA") && $filter2->contains("ATCGGGTCATCAACCAATTC")) { print "Filter2 contained unexpected. \n"; } print "premade bf tests done\n"; $pop = $filter2->getPop(); $hash = $filter2->getHashNum(); $ksize = $filter2->getKmerSize(); $size = $filter2->getFilterSize(); print "Filter Info: Pop - $pop, numHash - $hash, kmerSize - $ksize, size - $size\n"; #RollingHashIterator tests my $k = 5; $str = "TAGAATCACCCAAAGA"; $bloom = new BloomFilter::BloomFilter(10000, 4, $k); #$itr = new BloomFilter::RollingHashIterator($str, 4, $k); BloomFilter::insertSeq($bloom, $str, 4, $k); #my $count = 0; #my $next = $itr->getNext(); #while ($next) { # $bloom->insert($next); # print substr($str, $count, $k) . " " . $count++ . "\n"; # $next = $itr->getNext(); #} for (my $i = 0; $i < length($str) - $k + 1; $i++) { my $kmer = substr($str, $i, $k); print $i . " "; if($bloom->contains($kmer)){ print $kmer . " found\n"; } else{ print $kmer . " not found\n"; } } print "Done!\n"; exit; abyss-2.2.4/vendor/btl_bloomfilter/swig/testBloom_rolling.cpp000066400000000000000000000057241361462241400245020ustar00rootroot00000000000000#include "../BloomFilterUtil.h" #include #include #include #include #include #include using namespace std; int getFileSize(string file) { ifstream is(file.c_str(), ifstream::ate | ifstream::binary); return is.tellg(); } void containSeq(BloomFilter& bloom, const string& seq, unsigned hashNum, unsigned kmerSize) { int total = 0; int hits = 0; for (int i = 0; i < seq.length() - kmerSize; i++) { total++; string kmer = seq.substr(i, kmerSize); if (bloom.contains(kmer.c_str())) hits++; else cout << "Missing: " << kmer << endl; } cerr << "Found " << hits << " out of " << total << endl; } void contigsToBloom(const string& file, BloomFilter& bloom, unsigned hashNum, unsigned kmerSize) { ifstream infile(file.c_str()); clock_t t; if (!infile) { cerr << "Can't open file " << file << std::endl; exit(EXIT_FAILURE); } cout << "Contigs processed k=" << kmerSize << ":\n"; string line; string seq = ""; string prevHead = ""; int cttig = 0; while (getline(infile, line)) { if (line.compare(0, 1, ">") == 0) { if (line.compare(prevHead) != 0 && seq.length() != 0 && prevHead.length() != 0) { cttig++; cout << cttig << endl; containSeq(bloom, seq, hashNum, kmerSize); } seq = ""; prevHead = line; } else { seq += line; } } cttig++; cout << cttig << endl; containSeq(bloom, seq, hashNum, kmerSize); infile.close(); } int main(int argc, const char* argv[]) { string myFile; double fpr = 0.0001; unsigned kmerSize = 15; if (argc < 3) { cerr << "Usage: " << endl; cerr << "-f sequences to scaffold (Multi-FASTA format, required)" << endl; cerr << "-k k-mer value (default -k " << kmerSize << ", optional)" << endl; cerr << "-p Bloom filter false positive rate (default -p " << fpr << " optional - increase to prevent memory allocation errors)" << endl; return 1; } for (int i = 1; i < argc; i++) { string arg = argv[i]; if (arg == "-f") { if (i + 1 < argc) { myFile = argv[++i]; } else cerr << "Must have an argument after the -f option" << endl; } else if (arg == "-k") { if (i + 1 < argc) { kmerSize = atoi(((string)argv[++i]).c_str()); } } else if (arg == "-p") { if (i + 1 < argc) { fpr = atof(((string)argv[++i]).c_str()); } } } if (myFile.size() == 0) { cerr << "Must include the -f option" << endl; return 1; } int bfelements = getFileSize(myFile); size_t size = ceil((-1 * bfelements * log(fpr)) / (log(2) * log(2))); size += 64 - (size % 64); unsigned hashNum = floor((size / bfelements) * log(2)); cout << "***** Bloom filter specs: \nelements = " << bfelements << "\nFPR = " << fpr << "\nsize (bits) = " << size << "\nhash functions = " << hashNum << endl; BloomFilter bloom("BloomFilter.bf"); cout << "Shredding supplied sequence file (-f " << myFile << ") into " << kmerSize << "-mers..\n"; contigsToBloom(myFile, bloom, hashNum, kmerSize); cout << "Done!" << endl; return 0; } abyss-2.2.4/vendor/btl_bloomfilter/swig/testBloom_rolling.pl000077500000000000000000000076411361462241400243360ustar00rootroot00000000000000#!/usr/bin/env perl #AUTHOR # Rene Warren # rwarren at bcgsc.ca #NAME #writeBloom #SYNOPSIS #DOCUMENTATION # LINKS-readme.txt distributed with this software @ www.bcgsc.ca # http://www.bcgsc.ca/platform/bioinfo/software/links # We hope this code is useful to you -- Please send comments & suggestions to rwarren * bcgsc.ca # If you use LINKS, the LINKS code or ideas, please cite our work #LICENSE # LINKS Copyright (c) 2014-2015 Canada's Michael Smith Genome Science Centre. All rights reserved. #LINKS is released under the BC Cancer Agency software license agreement (academic use). Details of the license can be accessed at: http://www.bcgsc.ca/platform/bioinfo/license/bcca_2010 #For commercial use, please contact rwarren@bcgsc.ca use strict; use POSIX; use FindBin; #perl 5.8.8 #use lib "$FindBin::Bin/./lib/Bloom-Faster-1.6/bloom/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi"; #perl 5.10.0 #use lib "/projects/rwarren_prj2/LINKS/paper/links_v1.5.2/lib/Bloom-Faster-1.7/bloom5-16-3/lib/site_perl/5.16.3/x86_64-linux";###rebuild against PERL version or replace by pre-built #use Bloom::Faster; use lib "$FindBin::Bin/./"; use BloomFilter; use Getopt::Std; use Net::SMTP; use vars qw($opt_f $opt_k $opt_b); getopts('f:k:b:'); my ($k,$bf_file)=(15,""); #------------------------------------------------- if(! $opt_f ){ print "Usage: $0\n"; print "-f sequences to test (Multi-FASTA format, required)\n"; print "-k k-mer value (default -k $k, optional)\n"; die "-b Bloom filter (required)\n"; } my $assemblyfile = $opt_f; $k = $opt_k if($opt_k); $bf_file = $opt_b if($opt_b); print "\nRunning:$0 -f $assemblyfile -k $k -b $bf_file\n\n"; if(! -e $assemblyfile){ my $file_message = "\nInvalid file: $assemblyfile -- fatal\n"; print $file_message; exit; }elsif(! -e $bf_file){ my $file_message = "\nInvalid file: $bf_file -- fatal\n"; print $file_message; exit; }else{ my $file_message = "Checking sequence target file $assemblyfile...ok\n"; print $file_message; } my $date = `date`; chomp($date); eval{ my $bloom = new BloomFilter::BloomFilter($bf_file); my $date = `date`; chomp($date); print "$date:Shredding supplied sequence file (-f $assemblyfile) into $k-mers and testing against your Bloom filter..\n"; &contigsToBloom($assemblyfile,$k,$bloom); my $date = `date`; chomp($date); }; if($@){ my $message = $@; my $failure = "\nSomething went wrong running $0 $date\n$message\n"; print $failure; }else{ my $success = "\n$date:$0 executed normally\n"; print $success; } exit 1; #---------------- sub contigsToBloom{ my ($file,$k,$bloom) = @_; my $prevhead = ""; my $seq = ""; my $cttig=0; my ($ct_hit,$ct_total) = (0,0); open(IN,$file) || die "Error reading $file -- fatal.\n"; print "Contigs processed k=$k:\n"; ### while(){ chomp; if(/^\>(\S+)/){ my $head=$1; if ($head ne $prevhead && $seq ne '' && $prevhead ne ''){ $cttig++; print "\r$cttig"; $|++; ($ct_hit,$ct_total) = &kmerizeContigBloom(uc($seq),$bloom,$k,$ct_hit,$ct_total); } $seq = ''; $prevhead = $head; }else{ $seq .= $_; } } $cttig++; print "\r$cttig"; $|++; ($ct_hit,$ct_total) = &kmerizeContigBloom(uc($seq),$bloom,$k,$ct_hit,$ct_total); ### close IN; print "\n\nFound $ct_hit out of $ct_total kmers probable in your Bloom filter\n"; } #---------------- sub kmerizeContigBloom{ my ($seq,$bloom,$k,$ct_hit,$ct_total) = @_; for(my $pos=0;$pos<=(length($seq)-$k);$pos++){ $ct_total++; my $kmer = substr($seq,$pos,$k); if($bloom->contains($kmer)){ $ct_hit++; } else { print "Missing: $kmer\n"; } } return $ct_hit,$ct_total; } #----------------------- sub reverseComplement{ $_ = shift; $_ = uc(); tr/ATGCYRKMBDHV/TACGRYMKVHDB/; return (reverse()); } abyss-2.2.4/vendor/btl_bloomfilter/swig/writeBloom_rolling.cpp000066400000000000000000000055351361462241400246550ustar00rootroot00000000000000#include "../BloomFilterUtil.h" #include #include #include #include #include #include using namespace std; int getFileSize(string file) { ifstream is(file.c_str(), ifstream::ate | ifstream::binary); return is.tellg(); } void contigsToBloom(const string& file, BloomFilter& bloom, unsigned hashNum, unsigned kmerSize) { ifstream infile(file.c_str()); clock_t t; if (!infile) { cerr << "Can't open file " << file << std::endl; exit(EXIT_FAILURE); } cout << "Contigs processed k=" << kmerSize << ":\n"; string line; string seq = ""; string prevHead = ""; int cttig = 0; while (getline(infile, line)) { if (line.compare(0, 1, ">") == 0) { if (line.compare(prevHead) != 0 && seq.length() != 0 && prevHead.length() != 0) { cttig++; cout << cttig << endl; t = clock(); insertSeq(bloom, seq, hashNum, kmerSize); t = clock() - t; printf("Time: %f\n", ((float)t) / CLOCKS_PER_SEC); } seq = ""; prevHead = line; } else { seq += line; } } cttig++; cout << cttig << endl; t = clock(); insertSeq(bloom, seq, hashNum, kmerSize); t = clock() - t; printf("Time: %f\n", ((float)t) / CLOCKS_PER_SEC); infile.close(); } int main(int argc, const char* argv[]) { string myFile; double fpr = 0.0001; unsigned kmerSize = 15; if (argc < 3) { cerr << "Usage: " << endl; cerr << "-f sequences to scaffold (Multi-FASTA format, required)" << endl; cerr << "-k k-mer value (default -k " << kmerSize << ", optional)" << endl; cerr << "-p Bloom filter false positive rate (default -p " << fpr << " optional - increase to prevent memory allocation errors)" << endl; return 1; } for (int i = 1; i < argc; i++) { string arg = argv[i]; if (arg == "-f") { if (i + 1 < argc) { myFile = argv[++i]; } else cerr << "Must have an argument after the -f option" << endl; } else if (arg == "-k") { if (i + 1 < argc) { kmerSize = atoi(((string)argv[++i]).c_str()); } } else if (arg == "-p") { if (i + 1 < argc) { fpr = atof(((string)argv[++i]).c_str()); } } } if (myFile.size() == 0) { cerr << "Must include the -f option" << endl; return 1; } int bfelements = getFileSize(myFile); size_t size = ceil((-1 * bfelements * log(fpr)) / (log(2) * log(2))); size += 64 - (size % 64); unsigned hashNum = floor((size / bfelements) * log(2)); cout << "***** Bloom filter specs: \nelements = " << bfelements << "\nFPR = " << fpr << "\nsize (bits) = " << size << "\nhash functions = " << hashNum << endl; BloomFilter bloom(size, hashNum, kmerSize); cout << "Shredding supplied sequence file (-f " << myFile << ") into " << kmerSize << "-mers..\n"; contigsToBloom(myFile, bloom, hashNum, kmerSize); cout << "Writing Bloom filter to disk ...\n"; bloom.storeFilter("BloomFilter.bf"); cout << "Done!" << endl; return 0; } abyss-2.2.4/vendor/btl_bloomfilter/swig/writeBloom_rolling.pl000077500000000000000000000125551361462241400245110ustar00rootroot00000000000000#!/usr/bin/env perl #AUTHOR # Rene Warren # rwarren at bcgsc.ca #NAME #writeBloom #SYNOPSIS #DOCUMENTATION # LINKS-readme.txt distributed with this software @ www.bcgsc.ca # http://www.bcgsc.ca/platform/bioinfo/software/links # We hope this code is useful to you -- Please send comments & suggestions to rwarren * bcgsc.ca # If you use LINKS, the LINKS code or ideas, please cite our work #LICENSE # LINKS Copyright (c) 2014-2015 Canada's Michael Smith Genome Science Centre. All rights reserved. #LINKS is released under the BC Cancer Agency software license agreement (academic use). Details of the license can be accessed at: http://www.bcgsc.ca/platform/bioinfo/license/bcca_2010 #For commercial use, please contact rwarren@bcgsc.ca use strict; use POSIX; use FindBin; #perl 5.8.8 #use lib "$FindBin::Bin/./lib/Bloom-Faster-1.6/bloom/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi"; #perl 5.10.0 #use lib "$FindBin::Bin/../lib/Bloom-Faster-1.7/bloom5-16-3/lib/site_perl/5.16.3/x86_64-linux";###rebuild against PERL version or replace by pre-built #use Bloom::Faster; use lib "$FindBin::Bin/./"; use BloomFilter; use Getopt::Std; use Net::SMTP; use Time::HiRes; use vars qw($opt_f $opt_k $opt_p); getopts('f:k:p:'); my ($k,$fpr)=(15,0.0001); #------------------------------------------------- if(! $opt_f ){ print "Usage: $0\n"; print "-f sequences to scaffold (Multi-FASTA format, required)\n"; print "-k k-mer value (default -k $k, optional)\n"; die "-p Bloom filter false positive rate (default -p $fpr, optional - increase to prevent memory allocation errors)\n"; } my $assemblyfile = $opt_f; $k = $opt_k if($opt_k); $fpr = $opt_p if($opt_p); print "\nRunning:$0 -f $assemblyfile -k $k -p $fpr\n\n"; my $bfout = $assemblyfile . "_k" . $k . "_p" . $fpr . "_rolling.bf"; if(! -e $assemblyfile){ my $file_message = "\nInvalid file: $assemblyfile -- fatal\n"; print $file_message; exit; }else{ my $file_message = "Checking sequence target file $assemblyfile...ok\n"; print $file_message; } my $date = `date`; chomp($date); my $bloom; eval{ print "$date:Estimating number of elements from file size\n"; my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($assemblyfile); my $bfelements = int($size); my $date = `date`; chomp($date); #$bfelements *= 2;###twice the kmer when looking at both strands my $m = ceil((-1 * $bfelements * log($fpr)) / (log(2) * log(2))); #the number of bits my $rem = 64 - ($m % 64); $m = $m + $rem; my $hashfct = floor(($m / $bfelements) * log(2));# the number of hash functions print "*****\nBloom filter specs\nelements=$bfelements\nFPR=$fpr\nsize (bits)=$m\nhash functions=$hashfct\n*****\n"; #$bloom = new Bloom::Faster({m=>$m,k=>$hashfct}); $bloom = new BloomFilter::BloomFilter($m, $hashfct, $k); print "$date:Shredding supplied sequence file (-f $assemblyfile) into $k-mers..\n"; $bloom = &contigsToBloom($assemblyfile,$hashfct,$k,$bloom); my $date = `date`; chomp($date); my $writing_tigbloom_message = "\n$date:Writing Bloom filter to disk ($bfout)\n"; print $writing_tigbloom_message; $bloom->storeFilter($bfout); #$bloom->to_file($bfout);###write BF to disk }; if($@){ my $message = $@; my $failure = "\nSomething went wrong running $0 $date\n$message\n"; print $failure; }else{ my $success = "\n$date:$0 executed normally\n"; print $success; } # manually free the data structures $bloom->DESTROY; exit 1; #---------------- sub contigsToBloom{ my ($file,$hashfct,$k,$bloom) = @_; my $prevhead = ""; my $seq = ""; my $cttig=0; open(IN,$file) || die "Error reading $file -- fatal.\n"; print "Contigs processed k=$k:\n"; ### while(){ chomp; if(/^\>(\S+)/){ my $head=$1; if ($head ne $prevhead && $seq ne '' && $prevhead ne ''){ $cttig++; print "\r$cttig"; $|++; $bloom = &kmerizeContigBloom_newloop(uc($seq),$bloom,$hashfct,$k); #$bloom = &kmerizeContigBloom(uc($seq),$bloom,$k,$cttig,0); #my $revcomp = &reverseComplement(uc($seq)); #$bloom = &kmerizeContigBloom($revcomp,$bloom,$k,$cttig,1); } $seq = ''; $prevhead = $head; }else{ $seq .= $_; } } $cttig++; print "\r$cttig"; $|++; $bloom = &kmerizeContigBloom_newloop(uc($seq),$bloom,$hashfct,$k); #$bloom = &kmerizeContigBloom(uc($seq),$bloom,$k,$cttig,0); #my $revcomp = &reverseComplement(uc($seq)); #$bloom = &kmerizeContigBloom($revcomp,$bloom,$k,$cttig,1); ### close IN; return $bloom; } #---------------- sub kmerizeContigBloom{ my ($seq,$bloom,$hashfuct, $k) = @_; for(my $pos=0;$pos<=(length($seq)-$k);$pos++){ my $kmer = substr($seq,$pos,$k); $bloom->insert($kmer); } return $bloom; } #sub kmerizeContigBloom_new{ # my ($seq,$bloom,$hashfct,$k) = @_; # # my $itr = new BloomFilter::ntHashIterator($seq, $hashfct, $k); # while($itr.neq(BloomFilter::ntHashIterator::end())) { # $bloom->insert($itr->deref()); # $itr->incr(); # } # return $bloom; #} sub kmerizeContigBloom_newloop{ my ($seq,$bloom,$hashfct,$k) = @_; BloomFilter::insertSeq($bloom, $seq, $hashfct, $k); return $bloom } #----------------------- sub reverseComplement{ $_ = shift; $_ = uc(); tr/ATGCYRKMBDHV/TACGRYMKVHDB/; return (reverse()); } abyss-2.2.4/vendor/btl_bloomfilter/vendor/000077500000000000000000000000001361462241400206145ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/vendor/IOUtil.h000066400000000000000000000060451361462241400221370ustar00rootroot00000000000000#ifndef IOUTIL_H #define IOUTIL_H 1 #include #include #include #include // for strerror #include #include #include // for numeric_limits #include /** Print an error message and exit if stream is not good. */ static inline void assert_good(const std::ios& stream, const std::string& path) { if (!stream.good()) { std::cerr << "error: `" << path << "': " << strerror(errno) << std::endl; exit(EXIT_FAILURE); } } /** Print an error message and exit if stream is not eof. */ static inline void assert_eof(std::istream& in, const std::string& path) { if (!in.eof()) { in.clear(); std::string s; std::getline(in, s); std::cerr << "error: `" << path << "': " "Expected end-of-file and saw `" << s << "'\n"; exit(EXIT_FAILURE); } } /** This input stream manipulator skips the specified string. */ struct expect { const char* s; expect(const char* s) : s(s) { } }; static inline std::istream& operator>>(std::istream& in, expect o) { for (const char* p = o.s; *p != '\0'; ++p) { if (*p == ' ') { in >> std::ws; } else { char c = in.get(); if (!in || c != *p) { std::cerr << "error: Expected `" << p << "' and saw "; if (in) { std::cerr << '`' << c << "'\n"; std::string s; if (getline(in, s) && !s.empty()) std::cerr << "near: " << c << s << '\n'; } else if (in.eof()) std::cerr << "end-of-file\n"; else std::cerr << "I/O error\n"; exit(EXIT_FAILURE); } } } return in; } /** This input stream manipulator discards characters until reaching * the delimeter. */ struct Ignore { const char delim; size_t n; Ignore(const char delim, size_t n = std::numeric_limits::max()) : delim(delim), n(n) { } }; static inline std::istream& operator>>(std::istream& in, Ignore o) { return in.ignore(o.n, o.delim); } /** Skip the specified character if it's next in the input stream. */ struct Skip { char c; Skip(const char c) : c(c) { } }; static inline std::istream& operator>>(std::istream& in, Skip o) { if (in.peek() == o.c) in.ignore(1); return in; } /** Read a file and store it in the specified vector. */ template static inline void readFile(const char* path, Vector& s) { std::ifstream in(path); assert_good(in, path); in.seekg(0, std::ios::end); ssize_t n = in.tellg(); assert(n > 0); s.resize(n); in.seekg(0, std::ios::beg); assert_good(in, path); char *p = reinterpret_cast(&s[0]); #if __MACH__ // Read 1 GB at a time. Reads of 2 GB or more fail. const ssize_t N = 1024 * 1024 * 1024; for (; n > N; n -= N, p += N) { in.read(p, N); assert_good(in, path); assert(in.gcount() == N); } #endif in.read(p, n); assert_good(in, path); assert(in.gcount() == n); } /** Copy a file */ inline static void copyFile(const std::string& srcPath, const std::string& dstPath) { assert(srcPath != dstPath); std::ifstream src(srcPath.c_str(), std::ios::binary); std::ofstream dst(dstPath.c_str(), std::ios::binary); dst << src.rdbuf(); assert(dst); } #endif abyss-2.2.4/vendor/btl_bloomfilter/vendor/catch.hpp000066400000000000000000013176241361462241400224250ustar00rootroot00000000000000/* * Catch v1.3.0 * Generated: 2015-12-04 10:18:17.055188 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // #included from: internal/catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic ignored "-Wglobal-constructors" # pragma clang diagnostic ignored "-Wvariadic-macros" # pragma clang diagnostic ignored "-Wc99-extensions" # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // #included from: internal/catch_notimplemented_exception.h #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED // #included from: catch_common.h #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) #include #include #include // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED // Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // // CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? // CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported // CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? // CATCH_CONFIG_CPP11_OVERRIDE : is override supported? // CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 #ifdef __clang__ # if __has_feature(cxx_nullptr) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # if __has_feature(cxx_noexcept) # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Borland #ifdef __BORLANDC__ #endif // __BORLANDC__ //////////////////////////////////////////////////////////////////////////////// // EDG #ifdef __EDG_VERSION__ #endif // __EDG_VERSION__ //////////////////////////////////////////////////////////////////////////////// // Digital Mars #ifdef __DMC__ #endif // __DMC__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ #if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif // - otherwise more recent versions define __cplusplus >= 201103L // and will get picked up below #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __GNUC__ && __GNUC__ >= 3 ) || \ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) #define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS #endif //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 #if defined(__cplusplus) && __cplusplus >= 201103L # define CATCH_CPP11_OR_GREATER # if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE # define CATCH_INTERNAL_CONFIG_CPP11_TUPLE # endif # ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) # define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) # define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE # endif # if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR # endif #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured #if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NULLPTR #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NOEXCEPT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_GENERATED_METHODS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_IS_ENUM #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) # define CATCH_CONFIG_VARIADIC_MACROS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_LONG_LONG #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_OVERRIDE #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) # define CATCH_NOEXCEPT noexcept # define CATCH_NOEXCEPT_IS(x) noexcept(x) #else # define CATCH_NOEXCEPT throw() # define CATCH_NOEXCEPT_IS(x) #endif // nullptr support #ifdef CATCH_CONFIG_CPP11_NULLPTR # define CATCH_NULL nullptr #else # define CATCH_NULL NULL #endif // override support #ifdef CATCH_CONFIG_CPP11_OVERRIDE # define CATCH_OVERRIDE override #else # define CATCH_OVERRIDE #endif // unique_ptr support #ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR # define CATCH_AUTO_PTR( T ) std::unique_ptr #else # define CATCH_AUTO_PTR( T ) std::auto_ptr #endif namespace Catch { struct IConfig; struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; #else NonCopyable( NonCopyable const& info ); NonCopyable& operator = ( NonCopyable const& ); #endif protected: NonCopyable() {} virtual ~NonCopyable(); }; class SafeBool { public: typedef void (SafeBool::*type)() const; static type makeSafe( bool value ) { return value ? &SafeBool::trueValue : 0; } private: void trueValue() const {} }; template inline void deleteAll( ContainerT& container ) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete *it; } template inline void deleteAllValues( AssociativeContainerT& container ) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete it->second; } bool startsWith( std::string const& s, std::string const& prefix ); bool endsWith( std::string const& s, std::string const& suffix ); bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); std::string trim( std::string const& str ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { pluralise( std::size_t count, std::string const& label ); friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); std::size_t m_count; std::string m_label; }; struct SourceLineInfo { SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); SourceLineInfo( SourceLineInfo const& other ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; # endif bool empty() const; bool operator == ( SourceLineInfo const& other ) const; bool operator < ( SourceLineInfo const& other ) const; std::string file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals inline bool isTrue( bool value ){ return value; } inline bool alwaysTrue() { return true; } inline bool alwaysFalse() { return false; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); void seedRng( IConfig const& config ); unsigned int rngSeed(); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() { return std::string(); } }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); #include namespace Catch { class NotImplementedException : public std::exception { public: NotImplementedException( SourceLineInfo const& lineInfo ); NotImplementedException( NotImplementedException const& ) {} virtual ~NotImplementedException() CATCH_NOEXCEPT {} virtual const char* what() const CATCH_NOEXCEPT; private: std::string m_what; SourceLineInfo m_lineInfo; }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) // #included from: internal/catch_context.h #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED // #included from: catch_interfaces_generators.h #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED #include namespace Catch { struct IGeneratorInfo { virtual ~IGeneratorInfo(); virtual bool moveNext() = 0; virtual std::size_t getCurrentIndex() const = 0; }; struct IGeneratorsForTest { virtual ~IGeneratorsForTest(); virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; virtual bool moveNext() = 0; }; IGeneratorsForTest* createGeneratorsForTest(); } // end namespace Catch // #included from: catch_ptr.hpp #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { // An intrusive reference counting smart pointer. // T must implement addRef() and release() methods // typically implementing the IShared interface template class Ptr { public: Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); } Ptr( Ptr const& other ) : m_p( other.m_p ){ if( m_p ) m_p->addRef(); } ~Ptr(){ if( m_p ) m_p->release(); } void reset() { if( m_p ) m_p->release(); m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); swap( temp ); return *this; } Ptr& operator = ( Ptr const& other ){ Ptr temp( other ); swap( temp ); return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } bool operator !() const { return m_p == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; }; struct IShared : NonCopyable { virtual ~IShared(); virtual void addRef() const = 0; virtual void release() const = 0; }; template struct SharedImpl : T { SharedImpl() : m_rc( 0 ){} virtual void addRef() const { ++m_rc; } virtual void release() const { if( --m_rc == 0 ) delete this; } mutable unsigned int m_rc; }; } // end namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif #include #include #include namespace Catch { class TestCase; class Stream; struct IResultCapture; struct IRunner; struct IGeneratorsForTest; struct IConfig; struct IContext { virtual ~IContext(); virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; virtual bool advanceGeneratorsForCurrentTest() = 0; virtual Ptr getConfig() const = 0; }; struct IMutableContext : IContext { virtual ~IMutableContext(); virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setRunner( IRunner* runner ) = 0; virtual void setConfig( Ptr const& config ) = 0; }; IContext& getCurrentContext(); IMutableContext& getCurrentMutableContext(); void cleanUpContext(); Stream createStream( std::string const& streamName ); } // #included from: internal/catch_test_registry.hpp #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED // #included from: catch_interfaces_testcase.h #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED #include namespace Catch { class TestSpec; struct ITestCase : IShared { virtual void invoke () const = 0; protected: virtual ~ITestCase(); }; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } namespace Catch { template class MethodTestCase : public SharedImpl { public: MethodTestCase( void (C::*method)() ) : m_method( method ) {} virtual void invoke() const { C obj; (obj.*m_method)(); } private: virtual ~MethodTestCase() {} void (C::*m_method)(); }; typedef void(*TestFunction)(); struct NameAndDesc { NameAndDesc( const char* _name = "", const char* _description= "" ) : name( _name ), description( _description ) {} const char* name; const char* description; }; void registerTestCase ( ITestCase* testCase, char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ); struct AutoReg { AutoReg ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); template AutoReg ( void (C::*method)(), char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { registerTestCase ( new MethodTestCase( method ), className, nameAndDesc, lineInfo ); } ~AutoReg(); private: AutoReg( AutoReg const& ); void operator= ( AutoReg const& ); }; void registerTestCaseFunction ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( ... ) \ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ namespace{ \ struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ namespace{ \ struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); #endif // #included from: internal/catch_capture.hpp #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED // #included from: catch_result_builder.h #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED // #included from: catch_result_type.h #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2, FatalErrorCondition = 0x200 | FailureBit }; }; inline bool isOk( ResultWas::OfType resultType ) { return ( resultType & ResultWas::FailureBit ) == 0; } inline bool isJustInfo( int flags ) { return flags == ResultWas::Info; } // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x01, ContinueOnFailure = 0x02, // Failures fail test, but execution continues FalseTest = 0x04, // Prefix expression with ! SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { return static_cast( static_cast( lhs ) | static_cast( rhs ) ); } inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // #included from: catch_assertionresult.h #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include namespace Catch { struct AssertionInfo { AssertionInfo() {} AssertionInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, std::string const& _capturedExpression, ResultDisposition::Flags _resultDisposition ); std::string macroName; SourceLineInfo lineInfo; std::string capturedExpression; ResultDisposition::Flags resultDisposition; }; struct AssertionResultData { AssertionResultData() : resultType( ResultWas::Unknown ) {} std::string reconstructedExpression; std::string message; ResultWas::OfType resultType; }; class AssertionResult { public: AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionResult( AssertionResult const& ) = default; AssertionResult( AssertionResult && ) = default; AssertionResult& operator = ( AssertionResult const& ) = default; AssertionResult& operator = ( AssertionResult && ) = default; # endif bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; std::string getExpressionInMacro() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch // #included from: catch_matchers.hpp #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED namespace Catch { namespace Matchers { namespace Impl { namespace Generic { template class AllOf; template class AnyOf; template class Not; } template struct Matcher : SharedImpl { typedef ExpressionT ExpressionType; virtual ~Matcher() {} virtual Ptr clone() const = 0; virtual bool match( ExpressionT const& expr ) const = 0; virtual std::string toString() const = 0; Generic::AllOf operator && ( Matcher const& other ) const; Generic::AnyOf operator || ( Matcher const& other ) const; Generic::Not operator ! () const; }; template struct MatcherImpl : Matcher { virtual Ptr > clone() const { return Ptr >( new DerivedT( static_cast( *this ) ) ); } }; namespace Generic { template class Not : public MatcherImpl, ExpressionT> { public: explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} Not( Not const& other ) : m_matcher( other.m_matcher ) {} virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { return !m_matcher->match( expr ); } virtual std::string toString() const CATCH_OVERRIDE { return "not " + m_matcher->toString(); } private: Ptr< Matcher > m_matcher; }; template class AllOf : public MatcherImpl, ExpressionT> { public: AllOf() {} AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} AllOf& add( Matcher const& matcher ) { m_matchers.push_back( matcher.clone() ); return *this; } virtual bool match( ExpressionT const& expr ) const { for( std::size_t i = 0; i < m_matchers.size(); ++i ) if( !m_matchers[i]->match( expr ) ) return false; return true; } virtual std::string toString() const { std::ostringstream oss; oss << "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) oss << " and "; oss << m_matchers[i]->toString(); } oss << " )"; return oss.str(); } AllOf operator && ( Matcher const& other ) const { AllOf allOfExpr( *this ); allOfExpr.add( other ); return allOfExpr; } private: std::vector > > m_matchers; }; template class AnyOf : public MatcherImpl, ExpressionT> { public: AnyOf() {} AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} AnyOf& add( Matcher const& matcher ) { m_matchers.push_back( matcher.clone() ); return *this; } virtual bool match( ExpressionT const& expr ) const { for( std::size_t i = 0; i < m_matchers.size(); ++i ) if( m_matchers[i]->match( expr ) ) return true; return false; } virtual std::string toString() const { std::ostringstream oss; oss << "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) oss << " or "; oss << m_matchers[i]->toString(); } oss << " )"; return oss.str(); } AnyOf operator || ( Matcher const& other ) const { AnyOf anyOfExpr( *this ); anyOfExpr.add( other ); return anyOfExpr; } private: std::vector > > m_matchers; }; } // namespace Generic template Generic::AllOf Matcher::operator && ( Matcher const& other ) const { Generic::AllOf allOfExpr; allOfExpr.add( *this ); allOfExpr.add( other ); return allOfExpr; } template Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { Generic::AnyOf anyOfExpr; anyOfExpr.add( *this ); anyOfExpr.add( other ); return anyOfExpr; } template Generic::Not Matcher::operator ! () const { return Generic::Not( *this ); } namespace StdString { inline std::string makeString( std::string const& str ) { return str; } inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } struct CasedString { CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_str( adjustString( str ) ) {} std::string adjustString( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } std::string toStringSuffix() const { return m_caseSensitivity == CaseSensitive::No ? " (case insensitive)" : ""; } CaseSensitive::Choice m_caseSensitivity; std::string m_str; }; struct Equals : MatcherImpl { Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) : m_data( str, caseSensitivity ) {} Equals( Equals const& other ) : m_data( other.m_data ){} virtual ~Equals(); virtual bool match( std::string const& expr ) const { return m_data.m_str == m_data.adjustString( expr );; } virtual std::string toString() const { return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } CasedString m_data; }; struct Contains : MatcherImpl { Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) : m_data( substr, caseSensitivity ){} Contains( Contains const& other ) : m_data( other.m_data ){} virtual ~Contains(); virtual bool match( std::string const& expr ) const { return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; } virtual std::string toString() const { return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } CasedString m_data; }; struct StartsWith : MatcherImpl { StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) : m_data( substr, caseSensitivity ){} StartsWith( StartsWith const& other ) : m_data( other.m_data ){} virtual ~StartsWith(); virtual bool match( std::string const& expr ) const { return m_data.adjustString( expr ).find( m_data.m_str ) == 0; } virtual std::string toString() const { return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } CasedString m_data; }; struct EndsWith : MatcherImpl { EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) : m_data( substr, caseSensitivity ){} EndsWith( EndsWith const& other ) : m_data( other.m_data ){} virtual ~EndsWith(); virtual bool match( std::string const& expr ) const { return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); } virtual std::string toString() const { return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); } CasedString m_data; }; } // namespace StdString } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred template inline Impl::Generic::Not Not( Impl::Matcher const& m ) { return Impl::Generic::Not( m ); } template inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, Impl::Matcher const& m2 ) { return Impl::Generic::AllOf().add( m1 ).add( m2 ); } template inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, Impl::Matcher const& m2, Impl::Matcher const& m3 ) { return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); } template inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, Impl::Matcher const& m2 ) { return Impl::Generic::AnyOf().add( m1 ).add( m2 ); } template inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, Impl::Matcher const& m2, Impl::Matcher const& m3 ) { return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); } inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { return Impl::StdString::Equals( str, caseSensitivity ); } inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); } inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { return Impl::StdString::Contains( substr, caseSensitivity ); } inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); } inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { return Impl::StdString::StartsWith( substr ); } inline Impl::StdString::StartsWith StartsWith( const char* substr ) { return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); } inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { return Impl::StdString::EndsWith( substr ); } inline Impl::StdString::EndsWith EndsWith( const char* substr ) { return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); } } // namespace Matchers using namespace Matchers; } // namespace Catch namespace Catch { struct TestFailureException{}; template class ExpressionLhs; struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; struct CopyableStream { CopyableStream() {} CopyableStream( CopyableStream const& other ) { oss << other.oss.str(); } CopyableStream& operator=( CopyableStream const& other ) { oss.str(""); oss << other.oss.str(); return *this; } std::ostringstream oss; }; class ResultBuilder { public: ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg = "" ); template ExpressionLhs operator <= ( T const& operand ); ExpressionLhs operator <= ( bool value ); template ResultBuilder& operator << ( T const& value ) { m_stream.oss << value; return *this; } template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); ResultBuilder& setResultType( ResultWas::OfType result ); ResultBuilder& setResultType( bool result ); ResultBuilder& setLhs( std::string const& lhs ); ResultBuilder& setRhs( std::string const& rhs ); ResultBuilder& setOp( std::string const& op ); void endExpression(); std::string reconstructExpression() const; AssertionResult build() const; void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); void captureExpectedException( std::string const& expectedMessage ); void captureExpectedException( Matchers::Impl::Matcher const& matcher ); void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; private: AssertionInfo m_assertionInfo; AssertionResultData m_data; struct ExprComponents { ExprComponents() : testFalse( false ) {} bool testFalse; std::string lhs, rhs, op; } m_exprComponents; CopyableStream m_stream; bool m_shouldDebugBreak; bool m_shouldThrow; }; } // namespace Catch // Include after due to circular dependency: // #included from: catch_expression_lhs.hpp #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED // #included from: catch_evaluate.hpp #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch #endif #include namespace Catch { namespace Internal { enum Operator { IsEqualTo, IsNotEqualTo, IsLessThan, IsGreaterThan, IsLessThanOrEqualTo, IsGreaterThanOrEqualTo }; template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; template inline T& opCast(T const& t) { return const_cast(t); } // nullptr_t support based on pull request #154 from Konstantin Baumann #ifdef CATCH_CONFIG_CPP11_NULLPTR inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } #endif // CATCH_CONFIG_CPP11_NULLPTR // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template class Evaluator{}; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs) { return opCast( lhs ) == opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) != opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) < opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) > opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) >= opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) <= opCast( rhs ); } }; template bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // This level of indirection allows us to specialise for integer types // to avoid signed/ unsigned warnings // "base" overload template bool compare( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // unsigned X to int template bool compare( unsigned int lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // unsigned X to long template bool compare( unsigned int lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // int to unsigned X template bool compare( int lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // long to unsigned X template bool compare( long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long (when comparing against NULL) template bool compare( long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } // pointer to int (when comparing against NULL) template bool compare( int lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, int rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #ifdef CATCH_CONFIG_CPP11_LONG_LONG // long long to unsigned X template bool compare( long long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned long long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // unsigned long long to X template bool compare( unsigned long long lhs, int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, long long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( unsigned long long lhs, char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long long (when comparing against NULL) template bool compare( long long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #endif // CATCH_CONFIG_CPP11_LONG_LONG #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR } // end of namespace Internal } // end of namespace Catch #ifdef _MSC_VER #pragma warning(pop) #endif // #included from: catch_tostring.h #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED #include #include #include #include #include #ifdef __OBJC__ // #included from: catch_objc_arc.hpp #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) #else #define CATCH_ARC_ENABLED 0 #endif void arcSafeRelease( NSObject* obj ); id performOptionalSelector( id obj, SEL sel ); #if !CATCH_ARC_ENABLED inline void arcSafeRelease( NSObject* obj ) { [obj release]; } inline id performOptionalSelector( id obj, SEL sel ) { if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG #else inline void arcSafeRelease( NSObject* ){} inline id performOptionalSelector( id obj, SEL sel ) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; #ifdef __clang__ #pragma clang diagnostic pop #endif return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong #endif #endif #ifdef CATCH_CONFIG_CPP11_TUPLE #include #endif #ifdef CATCH_CONFIG_CPP11_IS_ENUM #include #endif namespace Catch { // Why we're here. template std::string toString( T const& value ); // Built in overloads std::string toString( std::string const& value ); std::string toString( std::wstring const& value ); std::string toString( const char* const value ); std::string toString( char* const value ); std::string toString( const wchar_t* const value ); std::string toString( wchar_t* const value ); std::string toString( int value ); std::string toString( unsigned long value ); std::string toString( unsigned int value ); std::string toString( const double value ); std::string toString( const float value ); std::string toString( bool value ); std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); #ifdef CATCH_CONFIG_CPP11_LONG_LONG std::string toString( long long value ); std::string toString( unsigned long long value ); #endif #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ); std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); std::string toString( NSObject* const& nsObject ); #endif namespace Detail { extern const std::string unprintableString; struct BorgType { template BorgType( T const& ); }; struct TrueType { char sizer[1]; }; struct FalseType { char sizer[2]; }; TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); FalseType operator<<( std::ostream const&, BorgType const& ); template struct IsStreamInsertable { static std::ostream &s; static T const&t; enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template::value > struct EnumStringMaker { static std::string convert( T const& ) { return unprintableString; } }; template struct EnumStringMaker { static std::string convert( T const& v ) { return ::Catch::toString( static_cast::type>(v) ); } }; #endif template struct StringMakerBase { #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template static std::string convert( T const& v ) { return EnumStringMaker::convert( v ); } #else template static std::string convert( T const& ) { return unprintableString; } #endif }; template<> struct StringMakerBase { template static std::string convert( T const& _value ) { std::ostringstream oss; oss << _value; return oss.str(); } }; std::string rawMemoryToString( const void *object, std::size_t size ); template inline std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } } // end namespace Detail template struct StringMaker : Detail::StringMakerBase::value> {}; template struct StringMaker { template static std::string convert( U* p ) { if( !p ) return "NULL"; else return Detail::rawMemoryToString( p ); } }; template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) return "NULL"; else return Detail::rawMemoryToString( p ); } }; namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ); } //template //struct StringMaker > { // static std::string convert( std::vector const& v ) { // return Detail::rangeToString( v.begin(), v.end() ); // } //}; template std::string toString( std::vector const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } #ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size::value) > struct ElementPrinter { static void print( const Tuple& tuple, std::ostream& os ) { os << ( N ? ", " : " " ) << Catch::toString(std::get(tuple)); ElementPrinter::print(tuple,os); } }; template< typename Tuple, std::size_t N > struct ElementPrinter { static void print( const Tuple&, std::ostream& ) {} }; } template struct StringMaker> { static std::string convert( const std::tuple& tuple ) { std::ostringstream os; os << '{'; TupleDetail::ElementPrinter>::print( tuple, os ); os << " }"; return os.str(); } }; #endif // CATCH_CONFIG_CPP11_TUPLE namespace Detail { template std::string makeString( T const& value ) { return StringMaker::convert( value ); } } // end namespace Detail /// \brief converts any type to a string /// /// The default template forwards on to ostringstream - except when an /// ostringstream overload does not exist - in which case it attempts to detect /// that and writes {?}. /// Overload (not specialise) this template for custom typs that you don't want /// to provide an ostream overload for. template std::string toString( T const& value ) { return StringMaker::convert( value ); } namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { oss << Catch::toString( *first ); for( ++first ; first != last ; ++first ) oss << ", " << Catch::toString( *first ); } oss << " }"; return oss.str(); } } } // end namespace Catch namespace Catch { // Wraps the LHS of an expression and captures the operator and RHS (if any) - // wrapping them all in a ResultBuilder object template class ExpressionLhs { ExpressionLhs& operator = ( ExpressionLhs const& ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs& operator = ( ExpressionLhs && ) = delete; # endif public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs( ExpressionLhs const& ) = default; ExpressionLhs( ExpressionLhs && ) = default; # endif template ResultBuilder& operator == ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator != ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator < ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator > ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator <= ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator >= ( RhsT const& rhs ) { return captureExpression( rhs ); } ResultBuilder& operator == ( bool rhs ) { return captureExpression( rhs ); } ResultBuilder& operator != ( bool rhs ) { return captureExpression( rhs ); } void endExpression() { bool value = m_lhs ? true : false; m_rb .setLhs( Catch::toString( value ) ) .setResultType( value ) .endExpression(); } // Only simple binary expressions are allowed on the LHS. // If more complex compositions are required then place the sub expression in parentheses template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); private: template ResultBuilder& captureExpression( RhsT const& rhs ) { return m_rb .setResultType( Internal::compare( m_lhs, rhs ) ) .setLhs( Catch::toString( m_lhs ) ) .setRhs( Catch::toString( rhs ) ) .setOp( Internal::OperatorTraits::getName() ); } private: ResultBuilder& m_rb; T m_lhs; }; } // end namespace Catch namespace Catch { template inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { return ExpressionLhs( *this, value ); } } // namespace Catch // #included from: catch_message.h #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED #include namespace Catch { struct MessageInfo { MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); std::string macroName; SourceLineInfo lineInfo; ResultWas::OfType type; std::string message; unsigned int sequence; bool operator == ( MessageInfo const& other ) const { return sequence == other.sequence; } bool operator < ( MessageInfo const& other ) const { return sequence < other.sequence; } private: static unsigned int globalCount; }; struct MessageBuilder { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ) : m_info( macroName, lineInfo, type ) {} template MessageBuilder& operator << ( T const& value ) { m_stream << value; return *this; } MessageInfo m_info; std::ostringstream m_stream; }; class ScopedMessage { public: ScopedMessage( MessageBuilder const& builder ); ScopedMessage( ScopedMessage const& other ); ~ScopedMessage(); MessageInfo m_info; }; } // end namespace Catch // #included from: catch_interfaces_capture.h #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include namespace Catch { class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; struct IResultCapture { virtual ~IResultCapture(); virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; virtual void handleFatalErrorCondition( std::string const& message ) = 0; }; IResultCapture& getResultCapture(); } // #included from: catch_debugger.h #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED // #included from: catch_platform.h #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) #define CATCH_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) #define CATCH_PLATFORM_IPHONE #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) #define CATCH_PLATFORM_WINDOWS #endif #include namespace Catch{ bool isDebuggerActive(); void writeToDebugConsole( std::string const& text ); } #ifdef CATCH_PLATFORM_MAC // The following code snippet based on: // http://cocoawithlove.com/2008/03/break-into-debugger.html #ifdef DEBUG #if defined(__ppc64__) || defined(__ppc__) #define CATCH_BREAK_INTO_DEBUGGER() \ if( Catch::isDebuggerActive() ) { \ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ : : : "memory","r0","r3","r4" ); \ } #else #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} #endif #endif #elif defined(_MSC_VER) #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } #endif #ifndef CATCH_BREAK_INTO_DEBUGGER #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif // #included from: catch_interfaces_runner.h #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED namespace Catch { class TestCase; struct IRunner { virtual ~IRunner(); virtual bool aborting() const = 0; }; } /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ resultBuilder.react(); /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ ( __catchResult <= expr ).endExpression(); \ } \ catch( ... ) { \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ if( Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ if( !Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType ) { \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << log + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( log, macroName ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ try { \ std::string matcherAsString = (matcher).toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ .setResultType( (matcher).match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) // #included from: internal/catch_section.h #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} Counts operator - ( Counts const& other ) const { Counts diff; diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; return diff; } Counts& operator += ( Counts const& other ) { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; return *this; } std::size_t total() const { return passed + failed + failedButOk; } bool allPassed() const { return failed == 0 && failedButOk == 0; } bool allOk() const { return failed == 0; } std::size_t passed; std::size_t failed; std::size_t failedButOk; }; struct Totals { Totals operator - ( Totals const& other ) const { Totals diff; diff.assertions = assertions - other.assertions; diff.testCases = testCases - other.testCases; return diff; } Totals delta( Totals const& prevTotals ) const { Totals diff = *this - prevTotals; if( diff.assertions.failed > 0 ) ++diff.testCases.failed; else if( diff.assertions.failedButOk > 0 ) ++diff.testCases.failedButOk; else ++diff.testCases.passed; return diff; } Totals& operator += ( Totals const& other ) { assertions += other.assertions; testCases += other.testCases; return *this; } Counts assertions; Counts testCases; }; } namespace Catch { struct SectionInfo { SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description = std::string() ); std::string name; std::string description; SourceLineInfo lineInfo; }; struct SectionEndInfo { SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) {} SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; }; } // end namespace Catch // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED #ifdef CATCH_PLATFORM_WINDOWS typedef unsigned long long uint64_t; #else #include #endif namespace Catch { class Timer { public: Timer() : m_ticks( 0 ) {} void start(); unsigned int getElapsedMicroseconds() const; unsigned int getElapsedMilliseconds() const; double getElapsedSeconds() const; private: uint64_t m_ticks; }; } // namespace Catch #include namespace Catch { class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); // This indicates whether the section should be executed or not operator bool() const; private: SectionInfo m_info; std::string m_name; Counts m_assertions; bool m_sectionIncluded; Timer m_timer; }; } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) #else #define INTERNAL_CATCH_SECTION( name, desc ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) #endif // #included from: internal/catch_generators.hpp #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED #include #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator() {} virtual T getValue( std::size_t index ) const = 0; virtual std::size_t size () const = 0; }; template class BetweenGenerator : public IGenerator { public: BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} virtual T getValue( std::size_t index ) const { return m_from+static_cast( index ); } virtual std::size_t size() const { return static_cast( 1+m_to-m_from ); } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { public: ValuesGenerator(){} void add( T value ) { m_values.push_back( value ); } virtual T getValue( std::size_t index ) const { return m_values[index]; } virtual std::size_t size() const { return m_values.size(); } private: std::vector m_values; }; template class CompositeGenerator { public: CompositeGenerator() : m_totalSize( 0 ) {} // *** Move semantics, similar to auto_ptr *** CompositeGenerator( CompositeGenerator& other ) : m_fileInfo( other.m_fileInfo ), m_totalSize( 0 ) { move( other ); } CompositeGenerator& setFileInfo( const char* fileInfo ) { m_fileInfo = fileInfo; return *this; } ~CompositeGenerator() { deleteAll( m_composed ); } operator T () const { size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); typename std::vector*>::const_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for( size_t index = 0; it != itEnd; ++it ) { const IGenerator* generator = *it; if( overallIndex >= index && overallIndex < index + generator->size() ) { return generator->getValue( overallIndex-index ); } index += generator->size(); } CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so } void add( const IGenerator* generator ) { m_totalSize += generator->size(); m_composed.push_back( generator ); } CompositeGenerator& then( CompositeGenerator& other ) { move( other ); return *this; } CompositeGenerator& then( T value ) { ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( value ); add( valuesGen ); return *this; } private: void move( CompositeGenerator& other ) { std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); m_totalSize += other.m_totalSize; other.m_composed.clear(); } std::vector*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { template CompositeGenerator between( T from, T to ) { CompositeGenerator generators; generators.add( new BetweenGenerator( from, to ) ); return generators; } template CompositeGenerator values( T val1, T val2 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3 ){ CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3, T val4 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); valuesGen->add( val4 ); generators.add( valuesGen ); return generators; } } // end namespace Generators using namespace Generators; } // end namespace Catch #define INTERNAL_CATCH_LINESTR2( line ) #line #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) // #included from: internal/catch_interfaces_exception.h #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include #include // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #include namespace Catch { class TestCase; struct ITestCaseRegistry; struct IExceptionTranslatorRegistry; struct IExceptionTranslator; struct IReporterRegistry; struct IReporterFactory; struct IRegistryHub { virtual ~IRegistryHub(); virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; IRegistryHub& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } namespace Catch { typedef std::string(*exceptionTranslateFunction)(); struct IExceptionTranslator; typedef std::vector ExceptionTranslators; struct IExceptionTranslator { virtual ~IExceptionTranslator(); virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { virtual ~IExceptionTranslatorRegistry(); virtual std::string translateActiveException() const = 0; }; class ExceptionTranslatorRegistrar { template class ExceptionTranslator : public IExceptionTranslator { public: ExceptionTranslator( std::string(*translateFunction)( T& ) ) : m_translateFunction( translateFunction ) {} virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { if( it == itEnd ) throw; else return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); } } protected: std::string(*m_translateFunction)( T& ); }; public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { getMutableRegistryHub().registerTranslator ( new ExceptionTranslator( translateFunction ) ); } }; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) // #included from: internal/catch_approx.hpp #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED #include #include namespace Catch { namespace Detail { class Approx { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), m_scale( 1.0 ), m_value( value ) {} Approx( Approx const& other ) : m_epsilon( other.m_epsilon ), m_scale( other.m_scale ), m_value( other.m_value ) {} static Approx custom() { return Approx( 0 ); } Approx operator()( double value ) { Approx approx( value ); approx.epsilon( m_epsilon ); approx.scale( m_scale ); return approx; } friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); } friend bool operator == ( Approx const& lhs, double rhs ) { return operator==( rhs, lhs ); } friend bool operator != ( double lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } friend bool operator != ( Approx const& lhs, double rhs ) { return !operator==( rhs, lhs ); } Approx& epsilon( double newEpsilon ) { m_epsilon = newEpsilon; return *this; } Approx& scale( double newScale ) { m_scale = newScale; return *this; } std::string toString() const { std::ostringstream oss; oss << "Approx( " << Catch::toString( m_value ) << " )"; return oss.str(); } private: double m_epsilon; double m_scale; double m_value; }; } template<> inline std::string toString( Detail::Approx const& value ) { return value.toString(); } } // end namespace Catch // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED // #included from: catch_tag_alias.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED #include namespace Catch { struct TagAlias { TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} std::string tag; SourceLineInfo lineInfo; }; struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } // #included from: catch_option.hpp #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED namespace Catch { // An optional type template class Option { public: Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { reset(); } Option& operator= ( Option const& _other ) { if( &_other != this ) { reset(); if( _other ) nullableValue = new( storage ) T( *_other ); } return *this; } Option& operator = ( T const& _value ) { reset(); nullableValue = new( storage ) T( _value ); return *this; } void reset() { if( nullableValue ) nullableValue->~T(); nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } T const& operator*() const { return *nullableValue; } T* operator->() { return nullableValue; } const T* operator->() const { return nullableValue; } T valueOr( T const& defaultValue ) const { return nullableValue ? *nullableValue : defaultValue; } bool some() const { return nullableValue != CATCH_NULL; } bool none() const { return nullableValue == CATCH_NULL; } bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } private: T* nullableValue; char storage[sizeof(T)]; }; } // end namespace Catch namespace Catch { struct ITagAliasRegistry { virtual ~ITagAliasRegistry(); virtual Option find( std::string const& alias ) const = 0; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; static ITagAliasRegistry const& get(); }; } // end namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections // #included from: internal/catch_test_case_info.h #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include #include #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { struct ITestCase; struct TestCaseInfo { enum SpecialProperties{ None = 0, IsHidden = 1 << 1, ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ); TestCaseInfo( TestCaseInfo const& other ); friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; std::string name; std::string className; std::string description; std::set tags; std::set lcaseTags; std::string tagsAsString; SourceLineInfo lineInfo; SpecialProperties properties; }; class TestCase : public TestCaseInfo { public: TestCase( ITestCase* testCase, TestCaseInfo const& info ); TestCase( TestCase const& other ); TestCase withName( std::string const& _newName ) const; void invoke() const; TestCaseInfo const& getTestCaseInfo() const; void swap( TestCase& other ); bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; TestCase& operator = ( TestCase const& other ); private: Ptr test; }; TestCase makeTestCase( ITestCase* testCase, std::string const& className, std::string const& name, std::string const& description, SourceLineInfo const& lineInfo ); } #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef __OBJC__ // #included from: internal/catch_objc.hpp #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import #include // NB. Any general catch headers included here must be included // in catch.hpp first to make sure they are included by the single // header for non obj-usage /////////////////////////////////////////////////////////////////////////////// // This protocol is really only here for (self) documenting purposes, since // all its methods are optional. @protocol OcFixture @optional -(void) setUp; -(void) tearDown; @end namespace Catch { class OcMethod : public SharedImpl { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} virtual void invoke() const { id obj = [[m_cls alloc] init]; performOptionalSelector( obj, @selector(setUp) ); performOptionalSelector( obj, m_sel ); performOptionalSelector( obj, @selector(tearDown) ); arcSafeRelease( obj ); } private: virtual ~OcMethod() {} Class m_cls; SEL m_sel; }; namespace Detail{ inline std::string getAnnotation( Class cls, std::string const& annotationName, std::string const& testCaseName ) { NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; SEL sel = NSSelectorFromString( selStr ); arcSafeRelease( selStr ); id value = performOptionalSelector( cls, sel ); if( value ) return [(NSString*)value UTF8String]; return ""; } } inline size_t registerTestMethods() { size_t noTestMethods = 0; int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); for( int c = 0; c < noClasses; c++ ) { Class cls = classes[c]; { u_int count; Method* methods = class_copyMethodList( cls, &count ); for( u_int m = 0; m < count ; m++ ) { SEL selector = method_getName(methods[m]); std::string methodName = sel_getName(selector); if( startsWith( methodName, "Catch_TestCase_" ) ) { std::string testCaseName = methodName.substr( 15 ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); noTestMethods++; } } free(methods); } } return noTestMethods; } namespace Matchers { namespace Impl { namespace NSStringMatchers { template struct StringHolder : MatcherImpl{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } NSString* m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } virtual std::string toString() const { return "equals string: " + Catch::toString( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string toString() const { return "contains string: " + Catch::toString( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } virtual std::string toString() const { return "starts with: " + Catch::toString( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string toString() const { return "ends with: " + Catch::toString( m_substr ); } }; } // namespace NSStringMatchers } // namespace Impl inline Impl::NSStringMatchers::Equals Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } inline Impl::NSStringMatchers::Contains Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } inline Impl::NSStringMatchers::StartsWith StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } inline Impl::NSStringMatchers::EndsWith EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } } // namespace Matchers using namespace Matchers; } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define OC_TEST_CASE( name, desc )\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ {\ return @ name; \ }\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ { \ return @ desc; \ } \ -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) #endif #ifdef CATCH_IMPL // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED // Collect all the implementation files together here // These are the equivalent of what would usually be cpp files #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #endif // #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED // #included from: catch_config.hpp #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED // #included from: catch_test_spec_parser.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_test_spec.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_wildcard_pattern.hpp #define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED namespace Catch { class WildcardPattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) : m_caseSensitivity( caseSensitivity ), m_wildcard( NoWildcard ), m_pattern( adjustCase( pattern ) ) { if( startsWith( m_pattern, "*" ) ) { m_pattern = m_pattern.substr( 1 ); m_wildcard = WildcardAtStart; } if( endsWith( m_pattern, "*" ) ) { m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); } } virtual ~WildcardPattern(); virtual bool matches( std::string const& str ) const { switch( m_wildcard ) { case NoWildcard: return m_pattern == adjustCase( str ); case WildcardAtStart: return endsWith( adjustCase( str ), m_pattern ); case WildcardAtEnd: return startsWith( adjustCase( str ), m_pattern ); case WildcardAtBothEnds: return contains( adjustCase( str ), m_pattern ); } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif throw std::logic_error( "Unknown enum" ); #ifdef __clang__ #pragma clang diagnostic pop #endif } private: std::string adjustCase( std::string const& str ) const { return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; } CaseSensitive::Choice m_caseSensitivity; WildcardPosition m_wildcard; std::string m_pattern; }; } #include #include namespace Catch { class TestSpec { struct Pattern : SharedImpl<> { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { public: NamePattern( std::string const& name ) : m_wildcardPattern( toLower( name ), CaseSensitive::No ) {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: WildcardPattern m_wildcardPattern; }; class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} virtual ~TagPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); } private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} virtual ~ExcludedPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } private: Ptr m_underlyingPattern; }; struct Filter { std::vector > m_patterns; bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) if( !(*it)->matches( testCase ) ) return false; return true; } }; public: bool hasFilters() const { return !m_filters.empty(); } bool matches( TestCaseInfo const& testCase ) const { // A TestSpec matches if any filter matches for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) if( it->matches( testCase ) ) return true; return false; } private: std::vector m_filters; friend class TestSpecParser; }; } #ifdef __clang__ #pragma clang diagnostic pop #endif namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag }; Mode m_mode; bool m_exclusion; std::size_t m_start, m_pos; std::string m_arg; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; ITagAliasRegistry const* m_tagAliases; public: TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} TestSpecParser& parse( std::string const& arg ) { m_mode = None; m_exclusion = false; m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) visitChar( m_arg[m_pos] ); if( m_mode == Name ) addPattern(); return *this; } TestSpec testSpec() { addFilter(); return m_testSpec; } private: void visitChar( char c ) { if( m_mode == None ) { switch( c ) { case ' ': return; case '~': m_exclusion = true; return; case '[': return startNewMode( Tag, ++m_pos ); case '"': return startNewMode( QuotedName, ++m_pos ); default: startNewMode( Name, m_pos ); break; } } if( m_mode == Name ) { if( c == ',' ) { addPattern(); addFilter(); } else if( c == '[' ) { if( subString() == "exclude:" ) m_exclusion = true; else addPattern(); startNewMode( Tag, ++m_pos ); } } else if( m_mode == QuotedName && c == '"' ) addPattern(); else if( m_mode == Tag && c == ']' ) addPattern(); } void startNewMode( Mode mode, std::size_t start ) { m_mode = mode; m_start = start; } std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } template void addPattern() { std::string token = subString(); if( startsWith( token, "exclude:" ) ) { m_exclusion = true; token = token.substr( 8 ); } if( !token.empty() ) { Ptr pattern = new T( token ); if( m_exclusion ) pattern = new TestSpec::ExcludedPattern( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } void addFilter() { if( !m_currentFilter.m_patterns.empty() ) { m_testSpec.m_filters.push_back( m_currentFilter ); m_currentFilter = TestSpec::Filter(); } } }; inline TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_interfaces_config.h #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED #include #include #include namespace Catch { struct Verbosity { enum Level { NoOutput = 0, Quiet, Normal }; }; struct WarnAbout { enum What { Nothing = 0x00, NoAssertions = 0x01 }; }; struct ShowDurations { enum OrNot { DefaultForReporter, Always, Never }; }; struct RunTests { enum InWhatOrder { InDeclarationOrder, InLexicographicalOrder, InRandomOrder }; }; class TestSpec; struct IConfig : IShared { virtual ~IConfig(); virtual bool allowThrows() const = 0; virtual std::ostream& stream() const = 0; virtual std::string name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual bool forceColour() const = 0; }; } // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED // #included from: catch_streambuf.h #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED #include namespace Catch { class StreamBufBase : public std::streambuf { public: virtual ~StreamBufBase() CATCH_NOEXCEPT; }; } #include #include #include namespace Catch { std::ostream& cout(); std::ostream& cerr(); struct IStream { virtual ~IStream() CATCH_NOEXCEPT; virtual std::ostream& stream() const = 0; }; class FileStream : public IStream { mutable std::ofstream m_ofs; public: FileStream( std::string const& filename ); virtual ~FileStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; class CoutStream : public IStream { mutable std::ostream m_os; public: CoutStream(); virtual ~CoutStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; class DebugOutStream : public IStream { std::auto_ptr m_streamBuf; mutable std::ostream m_os; public: DebugOutStream(); virtual ~DebugOutStream() CATCH_NOEXCEPT; public: // IStream virtual std::ostream& stream() const CATCH_OVERRIDE; }; } #include #include #include #include #include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif namespace Catch { struct ConfigData { ConfigData() : listTests( false ), listTags( false ), listReporters( false ), listTestNamesOnly( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), showHelp( false ), showInvisibles( false ), forceColour( false ), filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ), runOrder( RunTests::InDeclarationOrder ) {} bool listTests; bool listTags; bool listReporters; bool listTestNamesOnly; bool showSuccessfulTests; bool shouldDebugBreak; bool noThrow; bool showHelp; bool showInvisibles; bool forceColour; bool filenamesAsTags; int abortAfter; unsigned int rngSeed; Verbosity::Level verbosity; WarnAbout::What warnings; ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; std::string outputFilename; std::string name; std::string processName; std::vector reporterNames; std::vector testsOrTags; }; class Config : public SharedImpl { private: Config( Config const& other ); Config& operator = ( Config const& other ); virtual void dummy(); public: Config() {} Config( ConfigData const& data ) : m_data( data ), m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) parser.parse( data.testsOrTags[i] ); m_testSpec = parser.testSpec(); } } virtual ~Config() { } std::string const& getFilename() const { return m_data.outputFilename ; } bool listTests() const { return m_data.listTests; } bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool listTags() const { return m_data.listTags; } bool listReporters() const { return m_data.listReporters; } std::string getProcessName() const { return m_data.processName; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } std::vector getReporterNames() const { return m_data.reporterNames; } int abortAfter() const { return m_data.abortAfter; } TestSpec const& testSpec() const { return m_testSpec; } bool showHelp() const { return m_data.showHelp; } bool showInvisibles() const { return m_data.showInvisibles; } // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } virtual std::ostream& stream() const { return m_stream->stream(); } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } virtual unsigned int rngSeed() const { return m_data.rngSeed; } virtual bool forceColour() const { return m_data.forceColour; } private: IStream const* openStream() { if( m_data.outputFilename.empty() ) return new CoutStream(); else if( m_data.outputFilename[0] == '%' ) { if( m_data.outputFilename == "%debug" ) return new DebugOutStream(); else throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); } else return new FileStream( m_data.outputFilename ); } ConfigData m_data; std::auto_ptr m_stream; TestSpec m_testSpec; }; } // end namespace Catch // #included from: catch_clara.h #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED // Use Catch's value for console width (store Clara's off to the side, if present) #ifdef CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH #undef CLARA_CONFIG_CONSOLE_WIDTH #endif #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH // Declare Clara inside the Catch namespace #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: ../external/clara.h // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #ifndef STITCH_CLARA_OPEN_NAMESPACE #define TWOBLUECUBES_CLARA_H_INCLUDED #define STITCH_CLARA_OPEN_NAMESPACE #define STITCH_CLARA_CLOSE_NAMESPACE #else #define STITCH_CLARA_CLOSE_NAMESPACE } #endif #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE // ----------- #included from tbc_text_format.h ----------- // Only use header guard if we are not using an outer namespace #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE #define TBC_TEXT_FORMAT_H_INCLUDED #endif #include #include #include // Use optional outer namespace #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ), tabChar( '\t' ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { std::string wrappableChars = " [({.,/|\\-"; std::size_t indent = _attr.initialIndent != std::string::npos ? _attr.initialIndent : _attr.indent; std::string remainder = _str; while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::size_t tabPos = std::string::npos; std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); std::size_t pos = remainder.find_first_of( '\n' ); if( pos <= width ) { width = pos; } pos = remainder.find_last_of( _attr.tabChar, width ); if( pos != std::string::npos ) { tabPos = pos; if( remainder[width] == '\n' ) width--; remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); } if( width == remainder.size() ) { spliceLine( indent, remainder, width ); } else if( remainder[width] == '\n' ) { spliceLine( indent, remainder, width ); if( width <= 1 || remainder.size() != 1 ) remainder = remainder.substr( 1 ); indent = _attr.indent; } else { pos = remainder.find_last_of( wrappableChars, width ); if( pos != std::string::npos && pos > 0 ) { spliceLine( indent, remainder, pos ); if( remainder[0] == ' ' ) remainder = remainder.substr( 1 ); } else { spliceLine( indent, remainder, width-1 ); lines.back() += "-"; } if( lines.size() == 1 ) indent = _attr.indent; if( tabPos != std::string::npos ) indent += tabPos; } } } void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); _remainder = _remainder.substr( _pos ); } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TBC_TEXT_FORMAT_H_INCLUDED // ----------- end of #include from tbc_text_format.h ----------- // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE #include #include #include #include // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE #endif namespace Clara { struct UnpositionalTag {}; extern UnpositionalTag _; #ifdef CLARA_CONFIG_MAIN UnpositionalTag _; #endif namespace Detail { #ifdef CLARA_CONSOLE_WIDTH const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif using namespace Tbc; inline bool startsWith( std::string const& str, std::string const& prefix ) { return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; } template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct IsBool { static const bool value = false; }; template<> struct IsBool { static const bool value = true; }; template void convertInto( std::string const& _source, T& _dest ) { std::stringstream ss; ss << _source; ss >> _dest; if( ss.fail() ) throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); } inline void convertInto( std::string const& _source, std::string& _dest ) { _dest = _source; } inline void convertInto( std::string const& _source, bool& _dest ) { std::string sourceLC = _source; std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) _dest = true; else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) _dest = false; else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } inline void convertInto( bool _source, bool& _dest ) { _dest = _source; } template inline void convertInto( bool, T& ) { throw std::runtime_error( "Invalid conversion" ); } template struct IArgFunction { virtual ~IArgFunction() {} # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; # endif virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual void setFlag( ConfigT& config ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; template class BoundArgFunction { public: BoundArgFunction() : functionObj( CATCH_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; delete functionObj; functionObj = newFunctionObj; return *this; } ~BoundArgFunction() { delete functionObj; } void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } void setFlag( ConfigT& config ) const { functionObj->setFlag( config ); } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { return functionObj != CATCH_NULL; } private: IArgFunction* functionObj; }; template struct NullBinder : IArgFunction{ virtual void set( C&, std::string const& ) const {} virtual void setFlag( C& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction* clone() const { return new NullBinder( *this ); } }; template struct BoundDataMember : IArgFunction{ BoundDataMember( M C::* _member ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } virtual void setFlag( C& p ) const { convertInto( true, p.*member ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } M C::* member; }; template struct BoundUnaryMethod : IArgFunction{ BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); (p.*member)( value ); } virtual void setFlag( C& p ) const { typename RemoveConstRef::type value; convertInto( true, value ); (p.*member)( value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); }; template struct BoundNullaryMethod : IArgFunction{ BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) (p.*member)(); } virtual void setFlag( C& p ) const { (p.*member)(); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); }; template struct BoundUnaryFunction : IArgFunction{ BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) function( obj ); } virtual void setFlag( C& p ) const { function( p ); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); }; template struct BoundBinaryFunction : IArgFunction{ BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); function( obj, value ); } virtual void setFlag( C& obj ) const { typename RemoveConstRef::type value; convertInto( true, value ); function( obj, value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); }; } // namespace Detail struct Parser { Parser() : separators( " \t=:" ) {} struct Token { enum Type { Positional, ShortOpt, LongOpt }; Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} Type type; std::string data; }; void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { const std::string doubleDash = "--"; for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) parseIntoTokens( argv[i] , tokens); } void parseIntoTokens( std::string arg, std::vector& tokens ) const { while( !arg.empty() ) { Parser::Token token( Parser::Token::Positional, arg ); arg = ""; if( token.data[0] == '-' ) { if( token.data.size() > 1 && token.data[1] == '-' ) { token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); } else { token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { arg = "-" + token.data.substr( 1 ); token.data = token.data.substr( 0, 1 ); } } } if( token.type != Parser::Token::Positional ) { std::size_t pos = token.data.find_first_of( separators ); if( pos != std::string::npos ) { arg = token.data.substr( pos+1 ); token.data = token.data.substr( 0, pos ); } } tokens.push_back( token ); } } std::string separators; }; template struct CommonArgProperties { CommonArgProperties() {} CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} Detail::BoundArgFunction boundField; std::string description; std::string detail; std::string placeholder; // Only value if boundField takes an arg bool takesArg() const { return !placeholder.empty(); } void validate() const { if( !boundField.isSet() ) throw std::logic_error( "option not bound" ); } }; struct OptionArgProperties { std::vector shortNames; std::string longName; bool hasShortName( std::string const& shortName ) const { return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); } bool hasLongName( std::string const& _longName ) const { return _longName == longName; } }; struct PositionalArgProperties { PositionalArgProperties() : position( -1 ) {} int position; // -1 means non-positional (floating) bool isFixedPositional() const { return position != -1; } }; template class CommandLine { struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { Arg() {} Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} using CommonArgProperties::placeholder; // !TBD std::string dbgName() const { if( !longName.empty() ) return "--" + longName; if( !shortNames.empty() ) return "-" + shortNames[0]; return "positional args"; } std::string commands() const { std::ostringstream oss; bool first = true; std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); for(; it != itEnd; ++it ) { if( first ) first = false; else oss << ", "; oss << "-" << *it; } if( !longName.empty() ) { if( !first ) oss << ", "; oss << "--" << longName; } if( !placeholder.empty() ) oss << " <" << placeholder << ">"; return oss.str(); } }; typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { if( optName.empty() ) return; if( Detail::startsWith( optName, "--" ) ) { if( !arg.longName.empty() ) throw std::logic_error( "Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'" ); arg.longName = optName.substr( 2 ); } else if( Detail::startsWith( optName, "-" ) ) arg.shortNames.push_back( optName.substr( 1 ) ); else throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); } friend void setPositionalArg( Arg& arg, int position ) { arg.position = position; } class ArgBuilder { public: ArgBuilder( Arg* arg ) : m_arg( arg ) {} // Bind a non-boolean data member (requires placeholder string) template void bind( M C::* field, std::string const& placeholder ) { m_arg->boundField = new Detail::BoundDataMember( field ); m_arg->placeholder = placeholder; } // Bind a boolean data member (no placeholder required) template void bind( bool C::* field ) { m_arg->boundField = new Detail::BoundDataMember( field ); } // Bind a method taking a single, non-boolean argument (requires a placeholder string) template void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); m_arg->placeholder = placeholder; } // Bind a method taking a single, boolean argument (no placeholder string required) template void bind( void (C::* unaryMethod)( bool ) ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); } // Bind a method that takes no arguments (will be called if opt is present) template void bind( void (C::* nullaryMethod)() ) { m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); } // Bind a free function taking a single argument - the object to operate on (no placeholder string required) template void bind( void (* unaryFunction)( C& ) ) { m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); } // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) template void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); m_arg->placeholder = placeholder; } ArgBuilder& describe( std::string const& description ) { m_arg->description = description; return *this; } ArgBuilder& detail( std::string const& _detail ) { m_arg->detail = _detail; return *this; } protected: Arg* m_arg; }; class OptBuilder : public ArgBuilder { public: OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} OptBuilder& operator[]( std::string const& optName ) { addOptName( *ArgBuilder::m_arg, optName ); return *this; } }; public: CommandLine() : m_boundProcessName( new Detail::NullBinder() ), m_highestSpecifiedArgPosition( 0 ), m_throwOnUnrecognisedTokens( false ) {} CommandLine( CommandLine const& other ) : m_boundProcessName( other.m_boundProcessName ), m_options ( other.m_options ), m_positionalArgs( other.m_positionalArgs ), m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) { if( other.m_floatingArg.get() ) m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); } CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { m_throwOnUnrecognisedTokens = shouldThrow; return *this; } OptBuilder operator[]( std::string const& optName ) { m_options.push_back( Arg() ); addOptName( m_options.back(), optName ); OptBuilder builder( &m_options.back() ); return builder; } ArgBuilder operator[]( int position ) { m_positionalArgs.insert( std::make_pair( position, Arg() ) ); if( position > m_highestSpecifiedArgPosition ) m_highestSpecifiedArgPosition = position; setPositionalArg( m_positionalArgs[position], position ); ArgBuilder builder( &m_positionalArgs[position] ); return builder; } // Invoke this with the _ instance ArgBuilder operator[]( UnpositionalTag ) { if( m_floatingArg.get() ) throw std::logic_error( "Only one unpositional argument can be added" ); m_floatingArg.reset( new Arg() ); ArgBuilder builder( m_floatingArg.get() ); return builder; } template void bindProcessName( M C::* field ) { m_boundProcessName = new Detail::BoundDataMember( field ); } template void bindProcessName( void (C::*_unaryMethod)( M ) ) { m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); } void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; std::size_t maxWidth = 0; for( it = itBegin; it != itEnd; ++it ) maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { Detail::Text usageText( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { std::string usageCol = i < usageText.size() ? usageText[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) << desc[i]; os << "\n"; } } } std::string optUsage() const { std::ostringstream oss; optUsage( oss ); return oss.str(); } void argSynopsis( std::ostream& os ) const { for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { if( i > 1 ) os << " "; typename std::map::const_iterator it = m_positionalArgs.find( i ); if( it != m_positionalArgs.end() ) os << "<" << it->second.placeholder << ">"; else if( m_floatingArg.get() ) os << "<" << m_floatingArg->placeholder << ">"; else throw std::logic_error( "non consecutive positional arguments with no floating args" ); } // !TBD No indication of mandatory args if( m_floatingArg.get() ) { if( m_highestSpecifiedArgPosition > 1 ) os << " "; os << "[<" << m_floatingArg->placeholder << "> ...]"; } } std::string argSynopsis() const { std::ostringstream oss; argSynopsis( oss ); return oss.str(); } void usage( std::ostream& os, std::string const& procName ) const { validate(); os << "usage:\n " << procName << " "; argSynopsis( os ); if( !m_options.empty() ) { os << " [options]\n\nwhere options are: \n"; optUsage( os, 2 ); } os << "\n"; } std::string usage( std::string const& procName ) const { std::ostringstream oss; usage( oss, procName ); return oss.str(); } ConfigT parse( int argc, char const * const * argv ) const { ConfigT config; parseInto( argc, argv, config ); return config; } std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { std::string processName = argv[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector tokens; Parser parser; parser.parseIntoTokens( argc, argv, tokens ); return populate( tokens, config ); } std::vector populate( std::vector const& tokens, ConfigT& config ) const { validate(); std::vector unusedTokens = populateOptions( tokens, config ); unusedTokens = populateFixedArgs( unusedTokens, config ); unusedTokens = populateFloatingArgs( unusedTokens, config ); return unusedTokens; } std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; std::vector errors; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); for(; it != itEnd; ++it ) { Arg const& arg = *it; try { if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { if( arg.takesArg() ) { if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) errors.push_back( "Expected argument to option: " + token.data ); else arg.boundField.set( config, tokens[++i].data ); } else { arg.boundField.setFlag( config ); } break; } } catch( std::exception& ex ) { errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); } } if( it == itEnd ) { if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) unusedTokens.push_back( token ); else if( errors.empty() && m_throwOnUnrecognisedTokens ) errors.push_back( "unrecognised option: " + token.data ); } } if( !errors.empty() ) { std::ostringstream oss; for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); it != itEnd; ++it ) { if( it != errors.begin() ) oss << "\n"; oss << *it; } throw std::runtime_error( oss.str() ); } return unusedTokens; } std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; int position = 1; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::map::const_iterator it = m_positionalArgs.find( position ); if( it != m_positionalArgs.end() ) it->second.boundField.set( config, token.data ); else unusedTokens.push_back( token ); if( token.type == Parser::Token::Positional ) position++; } return unusedTokens; } std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { if( !m_floatingArg.get() ) return tokens; std::vector unusedTokens; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; if( token.type == Parser::Token::Positional ) m_floatingArg->boundField.set( config, token.data ); else unusedTokens.push_back( token ); } return unusedTokens; } void validate() const { if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) throw std::logic_error( "No options or arguments specified" ); for( typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); it != itEnd; ++it ) it->validate(); } private: Detail::BoundArgFunction m_boundProcessName; std::vector m_options; std::map m_positionalArgs; ArgAutoPtr m_floatingArg; int m_highestSpecifiedArgPosition; bool m_throwOnUnrecognisedTokens; }; } // end namespace Clara STITCH_CLARA_CLOSE_NAMESPACE #undef STITCH_CLARA_OPEN_NAMESPACE #undef STITCH_CLARA_CLOSE_NAMESPACE #endif // TWOBLUECUBES_CLARA_H_INCLUDED #undef STITCH_CLARA_OPEN_NAMESPACE // Restore Clara's value for console width, if present #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #endif #include namespace Catch { inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } inline void abortAfterX( ConfigData& config, int x ) { if( x < 1 ) throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); else throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); } inline void setOrder( ConfigData& config, std::string const& order ) { if( startsWith( "declared", order ) ) config.runOrder = RunTests::InDeclarationOrder; else if( startsWith( "lexical", order ) ) config.runOrder = RunTests::InLexicographicalOrder; else if( startsWith( "random", order ) ) config.runOrder = RunTests::InRandomOrder; else throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); } inline void setRngSeed( ConfigData& config, std::string const& seed ) { if( seed == "time" ) { config.rngSeed = static_cast( std::time(0) ); } else { std::stringstream ss; ss << seed; ss >> config.rngSeed; if( ss.fail() ) throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); } } inline void setVerbosity( ConfigData& config, int level ) { // !TBD: accept strings? config.verbosity = static_cast( level ); } inline void setShowDurations( ConfigData& config, bool _showDurations ) { config.showDurations = _showDurations ? ShowDurations::Always : ShowDurations::Never; } inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { std::ifstream f( _filename.c_str() ); if( !f.is_open() ) throw std::domain_error( "Unable to load input file: " + _filename ); std::string line; while( std::getline( f, line ) ) { line = trim(line); if( !line.empty() && !startsWith( line, "#" ) ) addTestOrTags( config, "\"" + line + "\"," ); } } inline Clara::CommandLine makeCommandLineParser() { using namespace Clara; CommandLine cli; cli.bindProcessName( &ConfigData::processName ); cli["-?"]["-h"]["--help"] .describe( "display usage information" ) .bind( &ConfigData::showHelp ); cli["-l"]["--list-tests"] .describe( "list all/matching test cases" ) .bind( &ConfigData::listTests ); cli["-t"]["--list-tags"] .describe( "list all/matching tags" ) .bind( &ConfigData::listTags ); cli["-s"]["--success"] .describe( "include successful tests in output" ) .bind( &ConfigData::showSuccessfulTests ); cli["-b"]["--break"] .describe( "break into debugger on failure" ) .bind( &ConfigData::shouldDebugBreak ); cli["-e"]["--nothrow"] .describe( "skip exception tests" ) .bind( &ConfigData::noThrow ); cli["-i"]["--invisibles"] .describe( "show invisibles (tabs, newlines)" ) .bind( &ConfigData::showInvisibles ); cli["-o"]["--out"] .describe( "output filename" ) .bind( &ConfigData::outputFilename, "filename" ); cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) .bind( &ConfigData::name, "name" ); cli["-a"]["--abort"] .describe( "abort at first failure" ) .bind( &abortAfterFirst ); cli["-x"]["--abortx"] .describe( "abort after x failures" ) .bind( &abortAfterX, "no. failures" ); cli["-w"]["--warn"] .describe( "enable warnings" ) .bind( &addWarning, "warning name" ); // - needs updating if reinstated // cli.into( &setVerbosity ) // .describe( "level of verbosity (0=no output)" ) // .shortOpt( "v") // .longOpt( "verbosity" ) // .placeholder( "level" ); cli[_] .describe( "which test or tests to use" ) .bind( &addTestOrTags, "test name, pattern or tags" ); cli["-d"]["--durations"] .describe( "show test durations" ) .bind( &setShowDurations, "yes/no" ); cli["-f"]["--input-file"] .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); cli["-#"]["--filenames-as-tags"] .describe( "adds a tag for the filename" ) .bind( &ConfigData::filenamesAsTags ); // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) .bind( &ConfigData::listTestNamesOnly ); cli["--list-reporters"] .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); cli["--order"] .describe( "test case order (defaults to decl)" ) .bind( &setOrder, "decl|lex|rand" ); cli["--rng-seed"] .describe( "set a specific seed for random numbers" ) .bind( &setRngSeed, "'time'|number" ); cli["--force-colour"] .describe( "force colourised output" ) .bind( &ConfigData::forceColour ); return cli; } } // end namespace Catch // #included from: internal/catch_list.hpp #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED // #included from: catch_text.h #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch // #included from: ../external/tbc_text_format.h // Only use header guard if we are not using an outer namespace #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # endif # else # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # endif #endif #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #include #include #include // Use optional outer namespace #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ), tabChar( '\t' ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { std::string wrappableChars = " [({.,/|\\-"; std::size_t indent = _attr.initialIndent != std::string::npos ? _attr.initialIndent : _attr.indent; std::string remainder = _str; while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::size_t tabPos = std::string::npos; std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); std::size_t pos = remainder.find_first_of( '\n' ); if( pos <= width ) { width = pos; } pos = remainder.find_last_of( _attr.tabChar, width ); if( pos != std::string::npos ) { tabPos = pos; if( remainder[width] == '\n' ) width--; remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); } if( width == remainder.size() ) { spliceLine( indent, remainder, width ); } else if( remainder[width] == '\n' ) { spliceLine( indent, remainder, width ); if( width <= 1 || remainder.size() != 1 ) remainder = remainder.substr( 1 ); indent = _attr.indent; } else { pos = remainder.find_last_of( wrappableChars, width ); if( pos != std::string::npos && pos > 0 ) { spliceLine( indent, remainder, pos ); if( remainder[0] == ' ' ) remainder = remainder.substr( 1 ); } else { spliceLine( indent, remainder, width-1 ); lines.back() += "-"; } if( lines.size() == 1 ) indent = _attr.indent; if( tabPos != std::string::npos ) indent += tabPos; } } } void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); _remainder = _remainder.substr( _pos ); } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace Catch { using Tbc::Text; using Tbc::TextAttributes; } // #included from: catch_console_colour.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED namespace Catch { struct Colour { enum Code { None = 0, White, Red, Green, Blue, Cyan, Yellow, Grey, Bright = 0x10, BrightRed = Bright | Red, BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, // By intention FileName = LightGrey, Warning = Yellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, Error = BrightRed, Success = Green, OriginalExpression = Cyan, ReconstructedExpression = Yellow, SecondaryText = LightGrey, Headers = White }; // Use constructed object for RAII guard Colour( Code _colourCode ); Colour( Colour const& other ); ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: bool m_moved; }; inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } } // end namespace Catch // #included from: catch_interfaces_reporter.h #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED #include #include #include #include namespace Catch { struct ReporterConfig { explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; Ptr m_fullConfig; }; struct ReporterPreferences { ReporterPreferences() : shouldRedirectStdOut( false ) {} bool shouldRedirectStdOut; }; template struct LazyStat : Option { LazyStat() : used( false ) {} LazyStat& operator=( T const& _value ) { Option::operator=( _value ); used = false; return *this; } void reset() { Option::reset(); used = false; } bool used; }; struct TestRunInfo { TestRunInfo( std::string const& _name ) : name( _name ) {} std::string name; }; struct GroupInfo { GroupInfo( std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount ) : name( _name ), groupIndex( _groupIndex ), groupsCounts( _groupsCount ) {} std::string name; std::size_t groupIndex; std::size_t groupsCounts; }; struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ) : assertionResult( _assertionResult ), infoMessages( _infoMessages ), totals( _totals ) { if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); builder << assertionResult.getMessage(); builder.m_info.message = builder.m_stream.str(); infoMessages.push_back( builder.m_info ); } } virtual ~AssertionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; AssertionStats& operator = ( AssertionStats && ) = default; # endif AssertionResult assertionResult; std::vector infoMessages; Totals totals; }; struct SectionStats { SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) : sectionInfo( _sectionInfo ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) {} virtual ~SectionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; SectionStats& operator = ( SectionStats && ) = default; # endif SectionInfo sectionInfo; Counts assertions; double durationInSeconds; bool missingAssertions; }; struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, bool _aborting ) : testInfo( _testInfo ), totals( _totals ), stdOut( _stdOut ), stdErr( _stdErr ), aborting( _aborting ) {} virtual ~TestCaseStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; TestCaseStats& operator = ( TestCaseStats && ) = default; # endif TestCaseInfo testInfo; Totals totals; std::string stdOut; std::string stdErr; bool aborting; }; struct TestGroupStats { TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting ) : groupInfo( _groupInfo ), totals( _totals ), aborting( _aborting ) {} TestGroupStats( GroupInfo const& _groupInfo ) : groupInfo( _groupInfo ), aborting( false ) {} virtual ~TestGroupStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; TestGroupStats& operator = ( TestGroupStats && ) = default; # endif GroupInfo groupInfo; Totals totals; bool aborting; }; struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ) : runInfo( _runInfo ), totals( _totals ), aborting( _aborting ) {} virtual ~TestRunStats(); # ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS TestRunStats( TestRunStats const& _other ) : runInfo( _other.runInfo ), totals( _other.totals ), aborting( _other.aborting ) {} # else TestRunStats( TestRunStats const& ) = default; TestRunStats( TestRunStats && ) = default; TestRunStats& operator = ( TestRunStats const& ) = default; TestRunStats& operator = ( TestRunStats && ) = default; # endif TestRunInfo runInfo; Totals totals; bool aborting; }; struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); // Implementing class must also provide the following static method: // static std::string getDescription(); virtual ReporterPreferences getPreferences() const = 0; virtual void noMatchingTestCases( std::string const& spec ) = 0; virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { typedef std::map > FactoryMap; typedef std::vector > Listeners; virtual ~IReporterRegistry(); virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; virtual Listeners const& getListeners() const = 0; }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); } #include #include namespace Catch { inline std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::size_t matchedTests = 0; TextAttributes nameAttr, tagsAttr; nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); Colour::Code colour = testCaseInfo.isHidden() ? Colour::SecondaryText : Colour::None; Colour colourGuard( colour ); Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; if( !testCaseInfo.tags.empty() ) Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; } if( !config.testSpec().hasFilters() ) Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; else Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; return matchedTests; } inline std::size_t listTestsNamesOnly( Config const& config ) { TestSpec testSpec = config.testSpec(); if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } struct TagInfo { TagInfo() : count ( 0 ) {} void add( std::string const& spelling ) { ++count; spellings.insert( spelling ); } std::string all() const { std::string out; for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); it != itEnd; ++it ) out += "[" + *it + "]"; return out; } std::set spellings; std::size_t count; }; inline std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), tagItEnd = it->getTestCaseInfo().tags.end(); tagIt != tagItEnd; ++tagIt ) { std::string tagName = *tagIt; std::string lcaseTagName = toLower( tagName ); std::map::iterator countIt = tagCounts.find( lcaseTagName ); if( countIt == tagCounts.end() ) countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; countIt->second.add( tagName ); } } for( std::map::const_iterator countIt = tagCounts.begin(), countItEnd = tagCounts.end(); countIt != countItEnd; ++countIt ) { std::ostringstream oss; oss << " " << std::setw(2) << countIt->second.count << " "; Text wrapper( countIt->second.all(), TextAttributes() .setInitialIndent( 0 ) .setIndent( oss.str().size() ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); Catch::cout() << oss.str() << wrapper << "\n"; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; return tagCounts.size(); } inline std::size_t listReporters( Config const& /*config*/ ) { Catch::cout() << "Available reporters:\n"; IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; std::size_t maxNameLen = 0; for(it = itBegin; it != itEnd; ++it ) maxNameLen = (std::max)( maxNameLen, it->first.size() ); for(it = itBegin; it != itEnd; ++it ) { Text wrapper( it->second->getDescription(), TextAttributes() .setInitialIndent( 0 ) .setIndent( 7+maxNameLen ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); Catch::cout() << " " << it->first << ":" << std::string( maxNameLen - it->first.size() + 2, ' ' ) << wrapper << "\n"; } Catch::cout() << std::endl; return factories.size(); } inline Option list( Config const& config ) { Option listedCount; if( config.listTests() ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); if( config.listTags() ) listedCount = listedCount.valueOr(0) + listTags( config ); if( config.listReporters() ) listedCount = listedCount.valueOr(0) + listReporters( config ); return listedCount; } } // end namespace Catch // #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #include #include #include #include namespace Catch { namespace TestCaseTracking { struct ITracker : SharedImpl<> { virtual ~ITracker(); // static queries virtual std::string name() const = 0; // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; virtual ITracker& parent() = 0; // actions virtual void close() = 0; // Successfully complete virtual void fail() = 0; virtual void markAsNeedingAnotherRun() = 0; virtual void addChild( Ptr const& child ) = 0; virtual ITracker* findChild( std::string const& name ) = 0; virtual void openChild() = 0; }; class TrackerContext { enum RunState { NotStarted, Executing, CompletedCycle }; Ptr m_rootTracker; ITracker* m_currentTracker; RunState m_runState; public: static TrackerContext& instance() { static TrackerContext s_instance; return s_instance; } TrackerContext() : m_currentTracker( CATCH_NULL ), m_runState( NotStarted ) {} ITracker& startRun(); void endRun() { m_rootTracker.reset(); m_currentTracker = CATCH_NULL; m_runState = NotStarted; } void startCycle() { m_currentTracker = m_rootTracker.get(); m_runState = Executing; } void completeCycle() { m_runState = CompletedCycle; } bool completedCycle() const { return m_runState == CompletedCycle; } ITracker& currentTracker() { return *m_currentTracker; } void setCurrentTracker( ITracker* tracker ) { m_currentTracker = tracker; } }; class TrackerBase : public ITracker { protected: enum CycleState { NotStarted, Executing, ExecutingChildren, NeedsAnotherRun, CompletedSuccessfully, Failed }; class TrackerHasName { std::string m_name; public: TrackerHasName( std::string const& name ) : m_name( name ) {} bool operator ()( Ptr const& tracker ) { return tracker->name() == m_name; } }; typedef std::vector > Children; std::string m_name; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; CycleState m_runState; public: TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) : m_name( name ), m_ctx( ctx ), m_parent( parent ), m_runState( NotStarted ) {} virtual ~TrackerBase(); virtual std::string name() const CATCH_OVERRIDE { return m_name; } virtual bool isComplete() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully || m_runState == Failed; } virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { return m_runState == CompletedSuccessfully; } virtual bool isOpen() const CATCH_OVERRIDE { return m_runState != NotStarted && !isComplete(); } virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { m_children.push_back( child ); } virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); return( it != m_children.end() ) ? it->get() : CATCH_NULL; } virtual ITracker& parent() CATCH_OVERRIDE { assert( m_parent ); // Should always be non-null except for root return *m_parent; } virtual void openChild() CATCH_OVERRIDE { if( m_runState != ExecutingChildren ) { m_runState = ExecutingChildren; if( m_parent ) m_parent->openChild(); } } void open() { m_runState = Executing; moveToThis(); if( m_parent ) m_parent->openChild(); } virtual void close() CATCH_OVERRIDE { // Close any still open children (e.g. generators) while( &m_ctx.currentTracker() != this ) m_ctx.currentTracker().close(); switch( m_runState ) { case NotStarted: case CompletedSuccessfully: case Failed: throw std::logic_error( "Illogical state" ); case NeedsAnotherRun: break;; case Executing: m_runState = CompletedSuccessfully; break; case ExecutingChildren: if( m_children.empty() || m_children.back()->isComplete() ) m_runState = CompletedSuccessfully; break; default: throw std::logic_error( "Unexpected state" ); } moveToParent(); m_ctx.completeCycle(); } virtual void fail() CATCH_OVERRIDE { m_runState = Failed; if( m_parent ) m_parent->markAsNeedingAnotherRun(); moveToParent(); m_ctx.completeCycle(); } virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { m_runState = NeedsAnotherRun; } private: void moveToParent() { assert( m_parent ); m_ctx.setCurrentTracker( m_parent ); } void moveToThis() { m_ctx.setCurrentTracker( this ); } }; class SectionTracker : public TrackerBase { public: SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) : TrackerBase( name, ctx, parent ) {} virtual ~SectionTracker(); static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { SectionTracker* section = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { section = dynamic_cast( childTracker ); assert( section ); } else { section = new SectionTracker( name, ctx, ¤tTracker ); currentTracker.addChild( section ); } if( !ctx.completedCycle() && !section->isComplete() ) { section->open(); } return *section; } }; class IndexTracker : public TrackerBase { int m_size; int m_index; public: IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) : TrackerBase( name, ctx, parent ), m_size( size ), m_index( -1 ) {} virtual ~IndexTracker(); static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { IndexTracker* tracker = CATCH_NULL; ITracker& currentTracker = ctx.currentTracker(); if( ITracker* childTracker = currentTracker.findChild( name ) ) { tracker = dynamic_cast( childTracker ); assert( tracker ); } else { tracker = new IndexTracker( name, ctx, ¤tTracker, size ); currentTracker.addChild( tracker ); } if( !ctx.completedCycle() && !tracker->isComplete() ) { if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) tracker->moveNext(); tracker->open(); } return *tracker; } int index() const { return m_index; } void moveNext() { m_index++; m_children.clear(); } virtual void close() CATCH_OVERRIDE { TrackerBase::close(); if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) m_runState = Executing; } }; inline ITracker& TrackerContext::startRun() { m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); m_currentTracker = CATCH_NULL; m_runState = Executing; return *m_rootTracker; } } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; using TestCaseTracking::IndexTracker; } // namespace Catch // #included from: catch_fatal_condition.hpp #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED namespace Catch { // Report the error condition then exit the process inline void fatal( std::string const& message, int exitCode ) { IContext& context = Catch::getCurrentContext(); IResultCapture* resultCapture = context.getResultCapture(); resultCapture->handleFatalErrorCondition( message ); if( Catch::alwaysTrue() ) // avoids "no return" warnings exit( exitCode ); } } // namespace Catch #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// namespace Catch { struct FatalConditionHandler { void reset() {} }; } // namespace Catch #else // Not Windows - assumed to be POSIX compatible ////////////////////////// #include namespace Catch { struct SignalDefs { int id; const char* name; }; extern SignalDefs signalDefs[]; SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, { SIGFPE, "SIGFPE - Floating point error signal" }, { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, { SIGTERM, "SIGTERM - Termination request signal" }, { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; struct FatalConditionHandler { static void handleSignal( int sig ) { for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) if( sig == signalDefs[i].id ) fatal( signalDefs[i].name, -sig ); fatal( "", -sig ); } FatalConditionHandler() : m_isSet( true ) { for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) signal( signalDefs[i].id, handleSignal ); } ~FatalConditionHandler() { reset(); } void reset() { if( m_isSet ) { for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) signal( signalDefs[i].id, SIG_DFL ); m_isSet = false; } } bool m_isSet; }; } // namespace Catch #endif // not Windows #include #include namespace Catch { class StreamRedirect { public: StreamRedirect( std::ostream& stream, std::string& targetString ) : m_stream( stream ), m_prevBuf( stream.rdbuf() ), m_targetString( targetString ) { stream.rdbuf( m_oss.rdbuf() ); } ~StreamRedirect() { m_targetString += m_oss.str(); m_stream.rdbuf( m_prevBuf ); } private: std::ostream& m_stream; std::streambuf* m_prevBuf; std::ostringstream m_oss; std::string& m_targetString; }; /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { RunContext( RunContext const& ); void operator =( RunContext const& ); public: explicit RunContext( Ptr const& _config, Ptr const& reporter ) : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), m_activeTestCase( CATCH_NULL ), m_config( _config ), m_reporter( reporter ) { m_context.setRunner( this ); m_context.setConfig( m_config ); m_context.setResultCapture( this ); m_reporter->testRunStarting( m_runInfo ); } virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); } void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); } Totals runTest( TestCase const& testCase ) { Totals prevTotals = m_totals; std::string redirectedCout; std::string redirectedCerr; TestCaseInfo testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; do { m_trackerContext.startRun(); do { m_trackerContext.startCycle(); m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); runCurrentTest( redirectedCout, redirectedCerr ); } while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, redirectedCout, redirectedCerr, aborting() ) ); m_activeTestCase = CATCH_NULL; m_testCaseTracker = CATCH_NULL; return deltaTotals; } Ptr config() const { return m_config; } private: // IResultCapture virtual void assertionEnded( AssertionResult const& result ) { if( result.getResultType() == ResultWas::Ok ) { m_totals.assertions.passed++; } else if( !result.isOk() ) { m_totals.assertions.failed++; } if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) m_messages.clear(); // Reset working state m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); m_lastResult = result; } virtual bool sectionStarted ( SectionInfo const& sectionInfo, Counts& assertions ) { std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); if( !sectionTracker.isOpen() ) return false; m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting( sectionInfo ); assertions = m_totals.assertions; return true; } bool testForMissingAssertions( Counts& assertions ) { if( assertions.total() != 0 ) return false; if( !m_config->warnAboutMissingAssertions() ) return false; if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } virtual void sectionEnded( SectionEndInfo const& endInfo ) { Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( !m_activeSections.empty() ) { m_activeSections.back()->close(); m_activeSections.pop_back(); } m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { if( m_unfinishedSections.empty() ) m_activeSections.back()->fail(); else m_activeSections.back()->close(); m_activeSections.pop_back(); m_unfinishedSections.push_back( endInfo ); } virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } virtual void popScopedMessage( MessageInfo const& message ) { m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); } virtual std::string getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name : ""; } virtual const AssertionResult* getLastResult() const { return &m_lastResult; } virtual void handleFatalErrorCondition( std::string const& message ) { ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); resultBuilder.setResultType( ResultWas::FatalErrorCondition ); resultBuilder << message; resultBuilder.captureExpression(); handleUnfinishedSections(); // Recreate section for test case (as we will lose the one that was in scope) TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); Counts assertions; assertions.failed = 1; SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); m_reporter->sectionEnded( testCaseSectionStats ); TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); Totals deltaTotals; deltaTotals.testCases.failed = 1; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, "", "", false ) ); m_totals.testCases.failed++; testGroupEnded( "", m_totals, 1, 1 ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); } public: // !TBD We need to do this another way! bool aborting() const { return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); } private: void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); m_reporter->sectionStarting( testCaseSection ); Counts prevAssertions = m_totals.assertions; double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); seedRng( *m_config ); Timer timer; timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); invokeActiveTestCase(); } else { invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); } catch( TestFailureException& ) { // This just means the test was aborted due to failure } catch(...) { makeUnexpectedResultBuilder().useActiveException(); } m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( testCaseInfo.okToFail() ) { std::swap( assertions.failedButOk, assertions.failed ); m_totals.assertions.failed -= assertions.failedButOk; m_totals.assertions.failedButOk += assertions.failedButOk; } SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); m_reporter->sectionEnded( testCaseSectionStats ); } void invokeActiveTestCase() { FatalConditionHandler fatalConditionHandler; // Handle signals m_activeTestCase->invoke(); fatalConditionHandler.reset(); } private: ResultBuilder makeUnexpectedResultBuilder() const { return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), m_lastAssertionInfo.lineInfo, m_lastAssertionInfo.capturedExpression.c_str(), m_lastAssertionInfo.resultDisposition ); } void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) sectionEnded( *it ); m_unfinishedSections.clear(); } TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; ITracker* m_testCaseTracker; ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; }; IResultCapture& getResultCapture() { if( IResultCapture* capture = getCurrentContext().getResultCapture() ) return *capture; else throw std::logic_error( "No result capture instance" ); } } // end namespace Catch // #included from: internal/catch_version.h #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED namespace Catch { // Versioning information struct Version { Version( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, std::string const& _branchName, unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; unsigned int const patchNumber; // buildNumber is only used if branchName is not null std::string const branchName; unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); private: void operator=( Version const& ); }; extern Version libraryVersion; } #include #include #include namespace Catch { Ptr createReporter( std::string const& reporterName, Ptr const& config ) { Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); if( !reporter ) { std::ostringstream oss; oss << "No reporter registered with name: '" << reporterName << "'"; throw std::domain_error( oss.str() ); } return reporter; } Ptr makeReporter( Ptr const& config ) { std::vector reporters = config->getReporterNames(); if( reporters.empty() ) reporters.push_back( "console" ); Ptr reporter; for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); it != itEnd; ++it ) reporter = addReporter( reporter, createReporter( *it, config ) ); return reporter; } Ptr addListeners( Ptr const& config, Ptr reporters ) { IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); it != itEnd; ++it ) reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); return reporters; } Totals runTests( Ptr const& config ) { Ptr iconfig = config.get(); Ptr reporter = makeReporter( config ); reporter = addListeners( iconfig, reporter ); RunContext context( iconfig, reporter ); Totals totals; context.testGroupStarting( config->name(), 1, 1 ); TestSpec testSpec = config->testSpec(); if( !testSpec.hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); it != itEnd; ++it ) { if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) totals += context.runTest( *it ); else reporter->skipTest( *it ); } context.testGroupEnded( iconfig->name(), totals, 1, 1 ); return totals; } void applyFilenamesAsTags( IConfig const& config ) { std::vector const& tests = getAllTestCasesSorted( config ); for(std::size_t i = 0; i < tests.size(); ++i ) { TestCase& test = const_cast( tests[i] ); std::set tags = test.tags; std::string filename = test.lineInfo.file; std::string::size_type lastSlash = filename.find_last_of( "\\/" ); if( lastSlash != std::string::npos ) filename = filename.substr( lastSlash+1 ); std::string::size_type lastDot = filename.find_last_of( "." ); if( lastDot != std::string::npos ) filename = filename.substr( 0, lastDot ); tags.insert( "#" + filename ); setTags( test, tags ); } } class Session : NonCopyable { static bool alreadyInstantiated; public: struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; Session() : m_cli( makeCommandLineParser() ) { if( alreadyInstantiated ) { std::string msg = "Only one instance of Catch::Session can ever be used"; Catch::cerr() << msg << std::endl; throw std::logic_error( msg ); } alreadyInstantiated = true; } ~Session() { Catch::cleanUp(); } void showHelp( std::string const& processName ) { Catch::cout() << "\nCatch v" << libraryVersion << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); } catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); Catch::cerr() << "\nError(s) in input:\n" << Text( ex.what(), TextAttributes().setIndent(2) ) << "\n\n"; } m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); } return 0; } void useConfigData( ConfigData const& _configData ) { m_configData = _configData; m_config.reset(); } int run( int argc, char const* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } int run() { if( m_configData.showHelp ) return 0; try { config(); // Force config to be constructed seedRng( *m_config ); if( m_configData.filenamesAsTags ) applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } Clara::CommandLine const& cli() const { return m_cli; } std::vector const& unusedTokens() const { return m_unusedTokens; } ConfigData& configData() { return m_configData; } Config& config() { if( !m_config ) m_config = new Config( m_configData ); return *m_config; } private: Clara::CommandLine m_cli; std::vector m_unusedTokens; ConfigData m_configData; Ptr m_config; }; bool Session::alreadyInstantiated = false; } // end namespace Catch // #included from: catch_registry_hub.hpp #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED // #included from: catch_test_case_registry_impl.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED #include #include #include #include #include namespace Catch { struct LexSort { bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { std::vector sorted = unsortedTestCases; switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: std::sort( sorted.begin(), sorted.end(), LexSort() ); break; case RunTests::InRandomOrder: { seedRng( config ); RandomNumberGenerator rng; std::random_shuffle( sorted.begin(), sorted.end(), rng ); } break; case RunTests::InDeclarationOrder: // already in declaration order break; } return sorted; } bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); } void enforceNoDuplicateTestCases( std::vector const& functions ) { std::set seenFunctions; for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); it != itEnd; ++it ) { std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); if( !prev.second ){ Catch::cerr() << Colour( Colour::Red ) << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; exit(1); } } } std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); it != itEnd; ++it ) if( matchTest( *it, testSpec, config ) ) filtered.push_back( *it ); return filtered; } std::vector const& getAllTestCasesSorted( IConfig const& config ) { return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); } class TestRegistry : public ITestCaseRegistry { public: TestRegistry() : m_unnamedCount( 0 ) {} virtual ~TestRegistry(); virtual void registerTest( TestCase const& testCase ) { std::string name = testCase.getTestCaseInfo().name; if( name == "" ) { std::ostringstream oss; oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { return m_functions; } virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { if( m_sortedFunctions.empty() ) enforceNoDuplicateTestCases( m_functions ); if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { m_sortedFunctions = sortTests( config, m_functions ); m_currentSortOrder = config.runOrder(); } return m_sortedFunctions; } private: std::vector m_functions; mutable RunTests::InWhatOrder m_currentSortOrder; mutable std::vector m_sortedFunctions; size_t m_unnamedCount; std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// class FreeFunctionTestCase : public SharedImpl { public: FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} virtual void invoke() const { m_fun(); } private: virtual ~FreeFunctionTestCase(); TestFunction m_fun; }; inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, "&" ) ) { std::size_t lastColons = className.rfind( "::" ); std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); if( penultimateColons == std::string::npos ) penultimateColons = 1; className = className.substr( penultimateColons, lastColons-penultimateColons ); } return className; } void registerTestCase ( ITestCase* testCase, char const* classOrQualifiedMethodName, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { getMutableRegistryHub().registerTest ( makeTestCase ( testCase, extractClassName( classOrQualifiedMethodName ), nameAndDesc.name, nameAndDesc.description, lineInfo ) ); } void registerTestCaseFunction ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } /////////////////////////////////////////////////////////////////////////// AutoReg::AutoReg ( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCaseFunction( function, lineInfo, nameAndDesc ); } AutoReg::~AutoReg() {} } // end namespace Catch // #included from: catch_reporter_registry.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED #include namespace Catch { class ReporterRegistry : public IReporterRegistry { public: virtual ~ReporterRegistry() CATCH_OVERRIDE {} virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } void registerListener( Ptr const& factory ) { m_listeners.push_back( factory ); } virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } virtual Listeners const& getListeners() const CATCH_OVERRIDE { return m_listeners; } private: FactoryMap m_factories; Listeners m_listeners; }; } // #included from: catch_exception_translator_registry.hpp #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED #ifdef __OBJC__ #import "Foundation/Foundation.h" #endif namespace Catch { class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { public: ~ExceptionTranslatorRegistry() { deleteAll( m_translators ); } virtual void registerTranslator( const IExceptionTranslator* translator ) { m_translators.push_back( translator ); } virtual std::string translateActiveException() const { try { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else return tryTranslators(); #endif } catch( TestFailureException& ) { throw; } catch( std::exception& ex ) { return ex.what(); } catch( std::string& msg ) { return msg; } catch( const char* msg ) { return msg; } catch(...) { return "Unknown exception"; } } std::string tryTranslators() const { if( m_translators.empty() ) throw; else return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: std::vector m_translators; }; } namespace Catch { namespace { class RegistryHub : public IRegistryHub, public IMutableRegistryHub { RegistryHub( RegistryHub const& ); void operator=( RegistryHub const& ); public: // IRegistryHub RegistryHub() { } virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerListener( factory ); } virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } private: TestRegistry m_testCaseRegistry; ReporterRegistry m_reporterRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; }; // Single, global, instance inline RegistryHub*& getTheRegistryHub() { static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; } } IRegistryHub& getRegistryHub() { return *getTheRegistryHub(); } IMutableRegistryHub& getMutableRegistryHub() { return *getTheRegistryHub(); } void cleanUp() { delete getTheRegistryHub(); getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); } } // end namespace Catch // #included from: catch_notimplemented_exception.hpp #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED #include namespace Catch { NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) : m_lineInfo( lineInfo ) { std::ostringstream oss; oss << lineInfo << ": function "; oss << "not implemented"; m_what = oss.str(); } const char* NotImplementedException::what() const CATCH_NOEXCEPT { return m_what.c_str(); } } // end namespace Catch // #included from: catch_context_impl.hpp #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED #include #include #include namespace Catch { template class StreamBufImpl : public StreamBufBase { char data[bufferSize]; WriterF m_writer; public: StreamBufImpl() { setp( data, data + sizeof(data) ); } ~StreamBufImpl() CATCH_NOEXCEPT { sync(); } private: int overflow( int c ) { sync(); if( c != EOF ) { if( pbase() == epptr() ) m_writer( std::string( 1, static_cast( c ) ) ); else sputc( static_cast( c ) ); } return 0; } int sync() { if( pbase() != pptr() ) { m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); setp( pbase(), epptr() ); } return 0; } }; /////////////////////////////////////////////////////////////////////////// FileStream::FileStream( std::string const& filename ) { m_ofs.open( filename.c_str() ); if( m_ofs.fail() ) { std::ostringstream oss; oss << "Unable to open file: '" << filename << "'"; throw std::domain_error( oss.str() ); } } std::ostream& FileStream::stream() const { return m_ofs; } struct OutputDebugWriter { void operator()( std::string const&str ) { writeToDebugConsole( str ); } }; DebugOutStream::DebugOutStream() : m_streamBuf( new StreamBufImpl() ), m_os( m_streamBuf.get() ) {} std::ostream& DebugOutStream::stream() const { return m_os; } // Store the streambuf from cout up-front because // cout may get redirected when running tests CoutStream::CoutStream() : m_os( Catch::cout().rdbuf() ) {} std::ostream& CoutStream::stream() const { return m_os; } #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } std::ostream& cerr() { return std::cerr; } #endif } namespace Catch { class Context : public IMutableContext { Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); public: // IContext virtual IResultCapture* getResultCapture() { return m_resultCapture; } virtual IRunner* getRunner() { return m_runner; } virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { return getGeneratorsForCurrentTest() .getGeneratorInfo( fileInfo, totalSize ) .getCurrentIndex(); } virtual bool advanceGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); return generators && generators->moveNext(); } virtual Ptr getConfig() const { return m_config; } public: // IMutableContext virtual void setResultCapture( IResultCapture* resultCapture ) { m_resultCapture = resultCapture; } virtual void setRunner( IRunner* runner ) { m_runner = runner; } virtual void setConfig( Ptr const& config ) { m_config = config; } friend IMutableContext& getCurrentMutableContext(); private: IGeneratorsForTest* findGeneratorsForCurrentTest() { std::string testName = getResultCapture()->getCurrentTestName(); std::map::const_iterator it = m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); if( !generators ) { std::string testName = getResultCapture()->getCurrentTestName(); generators = createGeneratorsForTest(); m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); } return *generators; } private: Ptr m_config; IRunner* m_runner; IResultCapture* m_resultCapture; std::map m_generatorsByTestName; }; namespace { Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) currentContext = new Context(); return *currentContext; } IContext& getCurrentContext() { return getCurrentMutableContext(); } void cleanUpContext() { delete currentContext; currentContext = CATCH_NULL; } } // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED namespace Catch { namespace { struct IColourImpl { virtual ~IColourImpl() {} virtual void use( Colour::Code _colourCode ) = 0; }; struct NoColourImpl : IColourImpl { void use( Colour::Code ) {} static IColourImpl* instance() { static NoColourImpl s_instance; return &s_instance; } }; } // anon namespace } // namespace Catch #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) # ifdef CATCH_PLATFORM_WINDOWS # define CATCH_CONFIG_COLOUR_WINDOWS # else # define CATCH_CONFIG_COLOUR_ANSI # endif #endif #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// #ifndef NOMINMAX #define NOMINMAX #endif #ifdef __AFXDLL #include #else #include #endif namespace Catch { namespace { class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Grey: return setTextAttribute( 0 ); case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } private: void setTextAttribute( WORD _textAttribute ) { SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; WORD originalForegroundAttributes; WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; return &s_instance; } } // end anon namespace } // end namespace Catch #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include namespace Catch { namespace { // use POSIX/ ANSI console terminal codes // Thanks to Adam Strzelecki for original contribution // (http://github.com/nanoant) // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); case Colour::Red: return setColour( "[0;31m" ); case Colour::Green: return setColour( "[0;32m" ); case Colour::Blue: return setColour( "[0:34m" ); case Colour::Cyan: return setColour( "[0;36m" ); case Colour::Yellow: return setColour( "[0;33m" ); case Colour::Grey: return setColour( "[1;30m" ); case Colour::LightGrey: return setColour( "[0;37m" ); case Colour::BrightRed: return setColour( "[1;31m" ); case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } static IColourImpl* instance() { static PosixColourImpl s_instance; return &s_instance; } private: void setColour( const char* _escapeCode ) { Catch::cout() << '\033' << _escapeCode; } }; IColourImpl* platformColourInstance() { Ptr config = getCurrentContext().getConfig(); return (config && config->forceColour()) || isatty(STDOUT_FILENO) ? PosixColourImpl::instance() : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch #endif // Windows/ ANSI/ None namespace Catch { Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { static IColourImpl* impl = isDebuggerActive() ? NoColourImpl::instance() : platformColourInstance(); impl->use( _colourCode ); } } // end namespace Catch // #included from: catch_generators_impl.hpp #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED #include #include #include namespace Catch { struct GeneratorInfo : IGeneratorInfo { GeneratorInfo( std::size_t size ) : m_size( size ), m_currentIndex( 0 ) {} bool moveNext() { if( ++m_currentIndex == m_size ) { m_currentIndex = 0; return false; } return true; } std::size_t getCurrentIndex() const { return m_currentIndex; } std::size_t m_size; std::size_t m_currentIndex; }; /////////////////////////////////////////////////////////////////////////// class GeneratorsForTest : public IGeneratorsForTest { public: ~GeneratorsForTest() { deleteAll( m_generatorsInOrder ); } IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { std::map::const_iterator it = m_generatorsByName.find( fileInfo ); if( it == m_generatorsByName.end() ) { IGeneratorInfo* info = new GeneratorInfo( size ); m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); m_generatorsInOrder.push_back( info ); return *info; } return *it->second; } bool moveNext() { std::vector::const_iterator it = m_generatorsInOrder.begin(); std::vector::const_iterator itEnd = m_generatorsInOrder.end(); for(; it != itEnd; ++it ) { if( (*it)->moveNext() ) return true; } return false; } private: std::map m_generatorsByName; std::vector m_generatorsInOrder; }; IGeneratorsForTest* createGeneratorsForTest() { return new GeneratorsForTest(); } } // end namespace Catch // #included from: catch_assertionresult.hpp #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED namespace Catch { AssertionInfo::AssertionInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, std::string const& _capturedExpression, ResultDisposition::Flags _resultDisposition ) : macroName( _macroName ), lineInfo( _lineInfo ), capturedExpression( _capturedExpression ), resultDisposition( _resultDisposition ) {} AssertionResult::AssertionResult() {} AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) : m_info( info ), m_resultData( data ) {} AssertionResult::~AssertionResult() {} // Result was a success bool AssertionResult::succeeded() const { return Catch::isOk( m_resultData.resultType ); } // Result was a success, or failure is suppressed bool AssertionResult::isOk() const { return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); } ResultWas::OfType AssertionResult::getResultType() const { return m_resultData.resultType; } bool AssertionResult::hasExpression() const { return !m_info.capturedExpression.empty(); } bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) return "!" + m_info.capturedExpression; else return m_info.capturedExpression; } std::string AssertionResult::getExpressionInMacro() const { if( m_info.macroName.empty() ) return m_info.capturedExpression; else return m_info.macroName + "( " + m_info.capturedExpression + " )"; } bool AssertionResult::hasExpandedExpression() const { return hasExpression() && getExpandedExpression() != getExpression(); } std::string AssertionResult::getExpandedExpression() const { return m_resultData.reconstructedExpression; } std::string AssertionResult::getMessage() const { return m_resultData.message; } SourceLineInfo AssertionResult::getSourceInfo() const { return m_info.lineInfo; } std::string AssertionResult::getTestMacroName() const { return m_info.macroName; } } // end namespace Catch // #included from: catch_test_case_info.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { if( startsWith( tag, "." ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; else if( tag == "!throws" ) return TestCaseInfo::Throws; else if( tag == "!shouldfail" ) return TestCaseInfo::ShouldFail; else if( tag == "!mayfail" ) return TestCaseInfo::MayFail; else return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { if( isReservedTag( tag ) ) { { Colour colourGuard( Colour::Red ); Catch::cerr() << "Tag name [" << tag << "] not allowed.\n" << "Tag names starting with non alpha-numeric characters are reserved\n"; } { Colour colourGuard( Colour::FileName ); Catch::cerr() << _lineInfo << std::endl; } exit(1); } } TestCase makeTestCase( ITestCase* _testCase, std::string const& _className, std::string const& _name, std::string const& _descOrTags, SourceLineInfo const& _lineInfo ) { bool isHidden( startsWith( _name, "./" ) ); // Legacy support // Parse out tags std::set tags; std::string desc, tag; bool inTag = false; for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { char c = _descOrTags[i]; if( !inTag ) { if( c == '[' ) inTag = true; else desc += c; } else { if( c == ']' ) { TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); if( prop == TestCaseInfo::IsHidden ) isHidden = true; else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); tags.insert( tag ); tag.clear(); inTag = false; } else tag += c; } } if( isHidden ) { tags.insert( "hide" ); tags.insert( "." ); } TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); return TestCase( _testCase, info ); } void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) { testCaseInfo.tags = tags; testCaseInfo.lcaseTags.clear(); std::ostringstream oss; for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { oss << "[" << *it << "]"; std::string lcaseTag = toLower( *it ); testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); testCaseInfo.lcaseTags.insert( lcaseTag ); } testCaseInfo.tagsAsString = oss.str(); } TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ) : name( _name ), className( _className ), description( _description ), lineInfo( _lineInfo ), properties( None ) { setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) : name( other.name ), className( other.className ), description( other.description ), tags( other.tags ), lcaseTags( other.lcaseTags ), tagsAsString( other.tagsAsString ), lineInfo( other.lineInfo ), properties( other.properties ) {} bool TestCaseInfo::isHidden() const { return ( properties & IsHidden ) != 0; } bool TestCaseInfo::throws() const { return ( properties & Throws ) != 0; } bool TestCaseInfo::okToFail() const { return ( properties & (ShouldFail | MayFail ) ) != 0; } bool TestCaseInfo::expectedToFail() const { return ( properties & (ShouldFail ) ) != 0; } TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} TestCase::TestCase( TestCase const& other ) : TestCaseInfo( other ), test( other.test ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); other.name = _newName; return other; } void TestCase::swap( TestCase& other ) { test.swap( other.test ); name.swap( other.name ); className.swap( other.className ); description.swap( other.description ); tags.swap( other.tags ); lcaseTags.swap( other.lcaseTags ); tagsAsString.swap( other.tagsAsString ); std::swap( TestCaseInfo::properties, static_cast( other ).properties ); std::swap( lineInfo, other.lineInfo ); } void TestCase::invoke() const { test->invoke(); } bool TestCase::operator == ( TestCase const& other ) const { return test.get() == other.test.get() && name == other.name && className == other.className; } bool TestCase::operator < ( TestCase const& other ) const { return name < other.name; } TestCase& TestCase::operator = ( TestCase const& other ) { TestCase temp( other ); swap( temp ); return *this; } TestCaseInfo const& TestCase::getTestCaseInfo() const { return *this; } } // end namespace Catch // #included from: catch_version.hpp #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED namespace Catch { Version::Version ( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, std::string const& _branchName, unsigned int _buildNumber ) : majorVersion( _majorVersion ), minorVersion( _minorVersion ), patchNumber( _patchNumber ), branchName( _branchName ), buildNumber( _buildNumber ) {} std::ostream& operator << ( std::ostream& os, Version const& version ) { os << version.majorVersion << "." << version.minorVersion << "." << version.patchNumber; if( !version.branchName.empty() ) { os << "-" << version.branchName << "." << version.buildNumber; } return os; } Version libraryVersion( 1, 3, 0, "", 0 ); } // #included from: catch_message.hpp #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED namespace Catch { MessageInfo::MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), sequence( ++globalCount ) {} // This may need protecting if threading support is added unsigned int MessageInfo::globalCount = 0; //////////////////////////////////////////////////////////////////////////// ScopedMessage::ScopedMessage( MessageBuilder const& builder ) : m_info( builder.m_info ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } ScopedMessage::ScopedMessage( ScopedMessage const& other ) : m_info( other.m_info ) {} ScopedMessage::~ScopedMessage() { getResultCapture().popScopedMessage( m_info ); } } // end namespace Catch // #included from: catch_legacy_reporter_adapter.hpp #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED // #included from: catch_legacy_reporter_adapter.h #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED namespace Catch { // Deprecated struct IReporter : IShared { virtual ~IReporter(); virtual bool shouldRedirectStdout() const = 0; virtual void StartTesting() = 0; virtual void EndTesting( Totals const& totals ) = 0; virtual void StartGroup( std::string const& groupName ) = 0; virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; virtual void Aborted() = 0; virtual void Result( AssertionResult const& result ) = 0; }; class LegacyReporterAdapter : public SharedImpl { public: LegacyReporterAdapter( Ptr const& legacyReporter ); virtual ~LegacyReporterAdapter(); virtual ReporterPreferences getPreferences() const; virtual void noMatchingTestCases( std::string const& ); virtual void testRunStarting( TestRunInfo const& ); virtual void testGroupStarting( GroupInfo const& groupInfo ); virtual void testCaseStarting( TestCaseInfo const& testInfo ); virtual void sectionStarting( SectionInfo const& sectionInfo ); virtual void assertionStarting( AssertionInfo const& ); virtual bool assertionEnded( AssertionStats const& assertionStats ); virtual void sectionEnded( SectionStats const& sectionStats ); virtual void testCaseEnded( TestCaseStats const& testCaseStats ); virtual void testGroupEnded( TestGroupStats const& testGroupStats ); virtual void testRunEnded( TestRunStats const& testRunStats ); virtual void skipTest( TestCaseInfo const& ); private: Ptr m_legacyReporter; }; } namespace Catch { LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) : m_legacyReporter( legacyReporter ) {} LegacyReporterAdapter::~LegacyReporterAdapter() {} ReporterPreferences LegacyReporterAdapter::getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); return prefs; } void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { m_legacyReporter->StartTesting(); } void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { m_legacyReporter->StartGroup( groupInfo.name ); } void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { m_legacyReporter->StartTestCase( testInfo ); } void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); } void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { // Not on legacy interface } bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); rb << it->message; rb.setResultType( ResultWas::Info ); AssertionResult result = rb.build(); m_legacyReporter->Result( result ); } } } m_legacyReporter->Result( assertionStats.assertionResult ); return true; } void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { if( sectionStats.missingAssertions ) m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); } void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { m_legacyReporter->EndTestCase ( testCaseStats.testInfo, testCaseStats.totals, testCaseStats.stdOut, testCaseStats.stdErr ); } void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { if( testGroupStats.aborting ) m_legacyReporter->Aborted(); m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); } void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { m_legacyReporter->EndTesting( testRunStats.totals ); } void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { } } // #included from: catch_timer.hpp #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++11-long-long" #endif #ifdef CATCH_PLATFORM_WINDOWS #include #else #include #endif namespace Catch { namespace { #ifdef CATCH_PLATFORM_WINDOWS uint64_t getCurrentTicks() { static uint64_t hz=0, hzo=0; if (!hz) { QueryPerformanceFrequency( reinterpret_cast( &hz ) ); QueryPerformanceCounter( reinterpret_cast( &hzo ) ); } uint64_t t; QueryPerformanceCounter( reinterpret_cast( &t ) ); return ((t-hzo)*1000000)/hz; } #else uint64_t getCurrentTicks() { timeval t; gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif } void Timer::start() { m_ticks = getCurrentTicks(); } unsigned int Timer::getElapsedMicroseconds() const { return static_cast(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { return getElapsedMicroseconds()/1000000.0; } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_common.hpp #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; } bool endsWith( std::string const& s, std::string const& suffix ) { return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; } bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), ::tolower ); } std::string toLower( std::string const& s ) { std::string lc = s; toLowerInPlace( lc ); return lc; } std::string trim( std::string const& str ) { static char const* whitespaceChars = "\n\r\t "; std::string::size_type start = str.find_first_not_of( whitespaceChars ); std::string::size_type end = str.find_last_not_of( whitespaceChars ); return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; } bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); while( i != std::string::npos ) { replaced = true; str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); if( i < str.size()-withThis.size() ) i = str.find( replaceThis, i+withThis.size() ); else i = std::string::npos; } return replaced; } pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) {} std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { os << pluraliser.m_count << " " << pluraliser.m_label; if( pluraliser.m_count != 1 ) os << "s"; return os; } SourceLineInfo::SourceLineInfo() : line( 0 ){} SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) : file( _file ), line( _line ) {} SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) : file( other.file ), line( other.line ) {} bool SourceLineInfo::empty() const { return file.empty(); } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { return line == other.line && file == other.file; } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { return line < other.line || ( line == other.line && file < other.file ); } void seedRng( IConfig const& config ) { if( config.rngSeed() != 0 ) std::srand( config.rngSeed() ); } unsigned int rngSeed() { return getCurrentContext().getConfig()->rngSeed(); } std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; #else os << info.file << ":" << info.line; #endif return os; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { std::ostringstream oss; oss << locationInfo << ": Internal Catch error: '" << message << "'"; if( alwaysTrue() ) throw std::logic_error( oss.str() ); } } // #included from: catch_section.hpp #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description ) : name( _name ), description( _description ), lineInfo( _lineInfo ) {} Section::Section( SectionInfo const& info ) : m_info( info ), m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) { m_timer.start(); } Section::~Section() { if( m_sectionIncluded ) { SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); if( std::uncaught_exception() ) getResultCapture().sectionEndedEarly( endInfo ); else getResultCapture().sectionEnded( endInfo ); } } // This indicates whether the section should be executed or not Section::operator bool() const { return m_sectionIncluded; } } // end namespace Catch // #included from: catch_debugger.hpp #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #include #ifdef CATCH_PLATFORM_MAC #include #include #include #include #include namespace Catch{ // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ int mib[4]; struct kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } // We're being debugged if the P_TRACED flag is set. return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #else namespace Catch { inline bool isDebuggerActive() { return false; } } #endif // Platform #ifdef CATCH_PLATFORM_WINDOWS extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); namespace Catch { void writeToDebugConsole( std::string const& text ) { ::OutputDebugStringA( text.c_str() ); } } #else namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs Catch::cout() << text; } } #endif // Platform // #included from: catch_tostring.hpp #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED namespace Catch { namespace Detail { const std::string unprintableString = "{?}"; namespace { const int hexThreshold = 255; struct Endianness { enum Arch { Big, Little }; static Arch which() { union _{ int asInt; char asChar[sizeof (int)]; } u; u.asInt = 1; return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; } }; } std::string rawMemoryToString( const void *object, std::size_t size ) { // Reverse order for little endian architectures int i = 0, end = static_cast( size ), inc = 1; if( Endianness::which() == Endianness::Little ) { i = end-1; end = inc = -1; } unsigned char const *bytes = static_cast(object); std::ostringstream os; os << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) os << std::setw(2) << static_cast(bytes[i]); return os.str(); } } std::string toString( std::string const& value ) { std::string s = value; if( getCurrentContext().getConfig()->showInvisibles() ) { for(size_t i = 0; i < s.size(); ++i ) { std::string subs; switch( s[i] ) { case '\n': subs = "\\n"; break; case '\t': subs = "\\t"; break; default: break; } if( !subs.empty() ) { s = s.substr( 0, i ) + subs + s.substr( i+1 ); ++i; } } } return "\"" + s + "\""; } std::string toString( std::wstring const& value ) { std::string s; s.reserve( value.size() ); for(size_t i = 0; i < value.size(); ++i ) s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; return Catch::toString( s ); } std::string toString( const char* const value ) { return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); } std::string toString( char* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( const wchar_t* const value ) { return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); } std::string toString( wchar_t* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( int value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned int value ) { return Catch::toString( static_cast( value ) ); } template std::string fpToString( T value, int precision ) { std::ostringstream oss; oss << std::setprecision( precision ) << std::fixed << value; std::string d = oss.str(); std::size_t i = d.find_last_not_of( '0' ); if( i != std::string::npos && i != d.size()-1 ) { if( d[i] == '.' ) i++; d = d.substr( 0, i+1 ); } return d; } std::string toString( const double value ) { return fpToString( value, 10 ); } std::string toString( const float value ) { return fpToString( value, 5 ) + "f"; } std::string toString( bool value ) { return value ? "true" : "false"; } std::string toString( char value ) { return value < ' ' ? toString( static_cast( value ) ) : Detail::makeString( value ); } std::string toString( signed char value ) { return toString( static_cast( value ) ); } std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } #ifdef CATCH_CONFIG_CPP11_LONG_LONG std::string toString( long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned long long value ) { std::ostringstream oss; oss << value; if( value > Detail::hexThreshold ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } #endif #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; } #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSObject* const& nsObject ) { return toString( [nsObject description] ); } #endif } // end namespace Catch // #included from: catch_result_builder.hpp #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED namespace Catch { std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { return secondArg.empty() || secondArg == "\"\"" ? capturedExpression : capturedExpression + ", " + secondArg; } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition, char const* secondArg ) : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { m_data.resultType = result; return *this; } ResultBuilder& ResultBuilder::setResultType( bool result ) { m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; return *this; } ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { m_exprComponents.lhs = lhs; return *this; } ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { m_exprComponents.rhs = rhs; return *this; } ResultBuilder& ResultBuilder::setOp( std::string const& op ) { m_exprComponents.op = op; return *this; } void ResultBuilder::endExpression() { m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); captureExpression(); } void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; m_stream.oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } void ResultBuilder::captureResult( ResultWas::OfType resultType ) { setResultType( resultType ); captureExpression(); } void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { if( expectedMessage.empty() ) captureExpectedException( Matchers::Impl::Generic::AllOf() ); else captureExpectedException( Matchers::Equals( expectedMessage ) ); } void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { assert( m_exprComponents.testFalse == false ); AssertionResultData data = m_data; data.resultType = ResultWas::Ok; data.reconstructedExpression = m_assertionInfo.capturedExpression; std::string actualMessage = Catch::translateActiveException(); if( !matcher.match( actualMessage ) ) { data.resultType = ResultWas::ExpressionFailed; data.reconstructedExpression = actualMessage; } AssertionResult result( m_assertionInfo, data ); handleResult( result ); } void ResultBuilder::captureExpression() { AssertionResult result = build(); handleResult( result ); } void ResultBuilder::handleResult( AssertionResult const& result ) { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { if( getCurrentContext().getConfig()->shouldDebugBreak() ) m_shouldDebugBreak = true; if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) m_shouldThrow = true; } } void ResultBuilder::react() { if( m_shouldThrow ) throw Catch::TestFailureException(); } bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } AssertionResult ResultBuilder::build() const { assert( m_data.resultType != ResultWas::Unknown ); AssertionResultData data = m_data; // Flip bool results if testFalse is set if( m_exprComponents.testFalse ) { if( data.resultType == ResultWas::Ok ) data.resultType = ResultWas::ExpressionFailed; else if( data.resultType == ResultWas::ExpressionFailed ) data.resultType = ResultWas::Ok; } data.message = m_stream.oss.str(); data.reconstructedExpression = reconstructExpression(); if( m_exprComponents.testFalse ) { if( m_exprComponents.op == "" ) data.reconstructedExpression = "!" + data.reconstructedExpression; else data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; } return AssertionResult( m_assertionInfo, data ); } std::string ResultBuilder::reconstructExpression() const { if( m_exprComponents.op == "" ) return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; else if( m_exprComponents.op == "matches" ) return m_exprComponents.lhs + " " + m_exprComponents.rhs; else if( m_exprComponents.op != "!" ) { if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && m_exprComponents.lhs.find("\n") == std::string::npos && m_exprComponents.rhs.find("\n") == std::string::npos ) return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; else return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; } else return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; } } // end namespace Catch // #included from: catch_tag_alias_registry.hpp #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED // #included from: catch_tag_alias_registry.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED #include namespace Catch { class TagAliasRegistry : public ITagAliasRegistry { public: virtual ~TagAliasRegistry(); virtual Option find( std::string const& alias ) const; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); static TagAliasRegistry& get(); private: std::map m_registry; }; } // end namespace Catch #include #include namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} Option TagAliasRegistry::find( std::string const& alias ) const { std::map::const_iterator it = m_registry.find( alias ); if( it != m_registry.end() ) return it->second; else return Option(); } std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { std::string expandedTestSpec = unexpandedTestSpec; for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); it != itEnd; ++it ) { std::size_t pos = expandedTestSpec.find( it->first ); if( pos != std::string::npos ) { expandedTestSpec = expandedTestSpec.substr( 0, pos ) + it->second.tag + expandedTestSpec.substr( pos + it->first.size() ); } } return expandedTestSpec; } void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { std::ostringstream oss; oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; throw std::domain_error( oss.str().c_str() ); } if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { std::ostringstream oss; oss << "error: tag alias, \"" << alias << "\" already registered.\n" << "\tFirst seen at " << find(alias)->lineInfo << "\n" << "\tRedefined at " << lineInfo; throw std::domain_error( oss.str().c_str() ); } } TagAliasRegistry& TagAliasRegistry::get() { static TagAliasRegistry instance; return instance; } ITagAliasRegistry::~ITagAliasRegistry() {} ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { try { TagAliasRegistry::get().add( alias, tag, lineInfo ); } catch( std::exception& ex ) { Colour colourGuard( Colour::Red ); Catch::cerr() << ex.what() << std::endl; exit(1); } } } // end namespace Catch // #included from: ../reporters/catch_reporter_multi.hpp #define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED namespace Catch { class MultipleReporters : public SharedImpl { typedef std::vector > Reporters; Reporters m_reporters; public: void add( Ptr const& reporter ) { m_reporters.push_back( reporter ); } public: // IStreamingReporter virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporters[0]->getPreferences(); } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->noMatchingTestCases( spec ); } virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testRunStarting( testRunInfo ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testGroupStarting( groupInfo ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testCaseStarting( testInfo ); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->sectionStarting( sectionInfo ); } virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->assertionStarting( assertionInfo ); } // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { bool clearBuffer = false; for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) clearBuffer |= (*it)->assertionEnded( assertionStats ); return clearBuffer; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->sectionEnded( sectionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testGroupEnded( testGroupStats ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->testRunEnded( testRunStats ); } virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); it != itEnd; ++it ) (*it)->skipTest( testInfo ); } }; Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { Ptr resultingReporter; if( existingReporter ) { MultipleReporters* multi = dynamic_cast( existingReporter.get() ); if( !multi ) { multi = new MultipleReporters; resultingReporter = Ptr( multi ); if( existingReporter ) multi->add( existingReporter ); } else resultingReporter = existingReporter; multi->add( additionalReporter ); } else resultingReporter = additionalReporter; return resultingReporter; } } // end namespace Catch // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED // #included from: catch_reporter_bases.hpp #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #include namespace Catch { struct StreamingReporterBase : SharedImpl { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; } virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporterPrefs; } virtual ~StreamingReporterBase() CATCH_OVERRIDE; virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; LazyStat currentGroupInfo; LazyStat currentTestCaseInfo; std::vector m_sectionStack; ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { template struct Node : SharedImpl<> { explicit Node( T const& _value ) : value( _value ) {} virtual ~Node() {} typedef std::vector > ChildNodes; T value; ChildNodes children; }; struct SectionNode : SharedImpl<> { explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} virtual ~SectionNode(); bool operator == ( SectionNode const& other ) const { return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; } bool operator == ( Ptr const& other ) const { return operator==( *other ); } SectionStats stats; typedef std::vector > ChildSections; typedef std::vector Assertions; ChildSections childSections; Assertions assertions; std::string stdOut; std::string stdErr; }; struct BySectionInfo { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() ( Ptr const& node ) const { return node->stats.sectionInfo.lineInfo == m_other.lineInfo; } private: void operator=( BySectionInfo const& ); SectionInfo const& m_other; }; typedef Node TestCaseNode; typedef Node TestGroupNode; typedef Node TestRunNode; CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = false; } ~CumulativeReporterBase(); virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { return m_reporterPrefs; } virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { if( !m_rootSection ) m_rootSection = new SectionNode( incompleteStats ); node = m_rootSection; } else { SectionNode& parentNode = *m_sectionStack.back(); SectionNode::ChildSections::const_iterator it = std::find_if( parentNode.childSections.begin(), parentNode.childSections.end(), BySectionInfo( sectionInfo ) ); if( it == parentNode.childSections.end() ) { node = new SectionNode( incompleteStats ); parentNode.childSections.push_back( node ); } else node = *it; } m_sectionStack.push_back( node ); m_deepestSection = node; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); m_testCases.push_back( node ); m_rootSection.reset(); assert( m_deepestSection ); m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); testRunEndedCumulative(); } virtual void testRunEndedCumulative() = 0; virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; std::vector > m_testCases; std::vector > m_testGroups; std::vector > m_testRuns; Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; ReporterPreferences m_reporterPrefs; }; template char const* getLineOfChars() { static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; if( !*line ) { memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } return line; } struct TestEventListenerBase : StreamingReporterBase { TestEventListenerBase( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { return false; } }; } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED namespace Catch { template class LegacyReporterRegistrar { class ReporterFactory : public IReporterFactory { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new LegacyReporterAdapter( new T( config ) ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: LegacyReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ReporterRegistrar { class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register // your custom reporter class be aware that the native reporter interface has changed // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. // However please consider updating to the new interface as the old one is now // deprecated and will probably be removed quite soon! // Please contact me via github if you have any questions at all about this. // In fact, ideally, please contact me anyway to let me know you've hit this - as I have // no idea who is actually using custom reporters at all (possibly no-one!). // The new interface is designed to minimise exposure to interface changes in the future. virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ListenerRegistrar { class ListenerFactory : public SharedImpl { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return ""; } }; public: ListenerRegistrar() { getMutableRegistryHub().registerListener( new ListenerFactory() ); } }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } #define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include #include namespace Catch { class XmlEncode { public: enum ForWhat { ForTextNodes, ForAttributes }; XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) : m_str( str ), m_forWhat( forWhat ) {} void encodeTo( std::ostream& os ) const { // Apostrophe escaping not necessary if we always use " to write attributes // (see: http://www.w3.org/TR/xml/#syntax) for( std::size_t i = 0; i < m_str.size(); ++ i ) { char c = m_str[i]; switch( c ) { case '<': os << "<"; break; case '&': os << "&"; break; case '>': // See: http://www.w3.org/TR/xml/#syntax if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) os << ">"; else os << c; break; case '\"': if( m_forWhat == ForAttributes ) os << """; else os << c; break; default: // Escape control chars - based on contribution by @espenalb in PR #465 if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) os << "&#x" << std::uppercase << std::hex << static_cast( c ); else os << c; } } } friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { xmlEncode.encodeTo( os ); return os; } private: std::string m_str; ForWhat m_forWhat; }; class XmlWriter { public: class ScopedElement { public: ScopedElement( XmlWriter* writer ) : m_writer( writer ) {} ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ other.m_writer = CATCH_NULL; } ~ScopedElement() { if( m_writer ) m_writer->endElement(); } ScopedElement& writeText( std::string const& text, bool indent = true ) { m_writer->writeText( text, indent ); return *this; } template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { m_writer->writeAttribute( name, attribute ); return *this; } private: mutable XmlWriter* m_writer; }; XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &Catch::cout() ) {} XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &os ) {} ~XmlWriter() { while( !m_tags.empty() ) endElement(); } XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); stream() << m_indent << "<" << name; m_tags.push_back( name ); m_indent += " "; m_tagIsOpen = true; return *this; } ScopedElement scopedElement( std::string const& name ) { ScopedElement scoped( this ); startElement( name ); return scoped; } XmlWriter& endElement() { newlineIfNecessary(); m_indent = m_indent.substr( 0, m_indent.size()-2 ); if( m_tagIsOpen ) { stream() << "/>\n"; m_tagIsOpen = false; } else { stream() << m_indent << "\n"; } m_tags.pop_back(); return *this; } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { if( !name.empty() && !attribute.empty() ) stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } XmlWriter& writeAttribute( std::string const& name, bool attribute ) { stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; return *this; } template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { std::ostringstream oss; oss << attribute; return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { if( !text.empty() ){ bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; stream() << XmlEncode( text ); m_needsNewline = true; } return *this; } XmlWriter& writeComment( std::string const& text ) { ensureTagClosed(); stream() << m_indent << ""; m_needsNewline = true; return *this; } XmlWriter& writeBlankLine() { ensureTagClosed(); stream() << "\n"; return *this; } void setStream( std::ostream& os ) { m_os = &os; } private: XmlWriter( XmlWriter const& ); void operator=( XmlWriter const& ); std::ostream& stream() { return *m_os; } void ensureTagClosed() { if( m_tagIsOpen ) { stream() << ">\n"; m_tagIsOpen = false; } } void newlineIfNecessary() { if( m_needsNewline ) { stream() << "\n"; m_needsNewline = false; } } bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; std::string m_indent; std::ostream* m_os; }; } // #included from: catch_reenable_warnings.h #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(pop) # else # pragma clang diagnostic pop # endif #elif defined __GNUC__ # pragma GCC diagnostic pop #endif namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) { m_reporterPrefs.shouldRedirectStdOut = true; } virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); } virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) .writeAttribute( "name", trim( sectionInfo.name ) ) .writeAttribute( "description", sectionInfo.description ); } } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { const AssertionResult& assertionResult = assertionStats.assertionResult; // Print any info messages in tags. if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { m_xml.scopedElement( "Info" ) .writeText( it->message ); } else if ( it->type == ResultWas::Warning ) { m_xml.scopedElement( "Warning" ) .writeText( it->message ); } } } // Drop out if result was successful but we're not printing them. if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) return true; // Print the expression if there is one. if( assertionResult.hasExpression() ) { m_xml.startElement( "Expression" ) .writeAttribute( "success", assertionResult.succeeded() ) .writeAttribute( "type", assertionResult.getTestMacroName() ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ); m_xml.scopedElement( "Original" ) .writeText( assertionResult.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( assertionResult.getExpandedExpression() ); } // And... Print a result applicable to each result type. switch( assertionResult.getResultType() ) { case ResultWas::ThrewException: m_xml.scopedElement( "Exception" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); break; case ResultWas::FatalErrorCondition: m_xml.scopedElement( "Fatal Error Condition" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) .writeText( assertionResult.getMessage() ); break; case ResultWas::Warning: // Warning will already have been written break; case ResultWas::ExplicitFailure: m_xml.scopedElement( "Failure" ) .writeText( assertionResult.getMessage() ); break; default: break; } if( assertionResult.hasExpression() ) m_xml.endElement(); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); e.writeAttribute( "successes", sectionStats.assertions.passed ); e.writeAttribute( "failures", sectionStats.assertions.failed ); e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); m_xml.endElement(); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); m_xml.endElement(); } virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); m_xml.endElement(); } private: Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth; }; INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_junit.hpp #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED #include namespace Catch { class JunitReporter : public CumulativeReporterBase { public: JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = true; } virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); unexpectedExceptions = 0; CumulativeReporterBase::testGroupStarting( groupInfo ); } virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); xml.writeAttribute( "tests", stats.totals.assertions.total() ); xml.writeAttribute( "hostname", "tbd" ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else xml.writeAttribute( "time", suiteTime ); xml.writeAttribute( "timestamp", "tbd" ); // !TBD // Write test cases for( TestGroupNode::ChildNodes::const_iterator it = groupNode.children.begin(), itEnd = groupNode.children.end(); it != itEnd; ++it ) writeTestCase( **it ); xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); } void writeTestCase( TestCaseNode const& testCaseNode ) { TestCaseStats const& stats = testCaseNode.value; // All test cases have exactly one section - which represents the // test case itself. That section may have 0-n nested sections assert( testCaseNode.children.size() == 1 ); SectionNode const& rootSection = *testCaseNode.children.front(); std::string className = stats.testInfo.className; if( className.empty() ) { if( rootSection.childSections.empty() ) className = "global"; } writeSection( className, "", rootSection ); } void writeSection( std::string const& className, std::string const& rootName, SectionNode const& sectionNode ) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + "/" + name; if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty() ) { XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); if( className.empty() ) { xml.writeAttribute( "classname", name ); xml.writeAttribute( "name", "root" ); } else { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); writeAssertions( sectionNode ); if( !sectionNode.stdOut.empty() ) xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); if( !sectionNode.stdErr.empty() ) xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } for( SectionNode::ChildSections::const_iterator it = sectionNode.childSections.begin(), itEnd = sectionNode.childSections.end(); it != itEnd; ++it ) if( className.empty() ) writeSection( name, "", **it ); else writeSection( className, name, **it ); } void writeAssertions( SectionNode const& sectionNode ) { for( SectionNode::Assertions::const_iterator it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); it != itEnd; ++it ) writeAssertion( *it ); } void writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; if( !result.isOk() ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: elementName = "failure"; break; case ResultWas::ExpressionFailed: elementName = "failure"; break; case ResultWas::DidntThrowException: elementName = "failure"; break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: case ResultWas::Ok: case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: elementName = "internalError"; break; } XmlWriter::ScopedElement e = xml.scopedElement( elementName ); xml.writeAttribute( "message", result.getExpandedExpression() ); xml.writeAttribute( "type", result.getTestMacroName() ); std::ostringstream oss; if( !result.getMessage().empty() ) oss << result.getMessage() << "\n"; for( std::vector::const_iterator it = stats.infoMessages.begin(), itEnd = stats.infoMessages.end(); it != itEnd; ++it ) if( it->type == ResultWas::Info ) oss << it->message << "\n"; oss << "at " << result.getSourceInfo(); xml.writeText( oss.str(), false ); } } XmlWriter xml; Timer suiteTimer; std::ostringstream stdOutForSuite; std::ostringstream stdErrForSuite; unsigned int unexpectedExceptions; }; INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED namespace Catch { struct ConsoleReporter : StreamingReporterBase { ConsoleReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_headerPrinted( false ) {} virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << "'" << std::endl; } virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } lazyPrint(); AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); if( m_sectionStack.size() > 1 ) stream << "\nNo assertions in section"; else stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } if( m_headerPrinted ) { if( m_config->showDurations() == ShowDurations::Always ) stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; m_headerPrinted = false; } else { if( m_config->showDurations() == ShowDurations::Always ) stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; } StreamingReporterBase::sectionEnded( _sectionStats ); } virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals( _testGroupStats.totals ); stream << "\n" << std::endl; } StreamingReporterBase::testGroupEnded( _testGroupStats ); } virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ), stats( _stats ), result( _stats.assertionResult ), colour( Colour::None ), message( result.getMessage() ), messages( _stats.infoMessages ), printInfoMessages( _printInfoMessages ) { switch( result.getResultType() ) { case ResultWas::Ok: colour = Colour::Success; passOrFail = "PASSED"; //if( result.hasMessage() ) if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ExpressionFailed: if( result.isOk() ) { colour = Colour::Success; passOrFail = "FAILED - but was ok"; } else { colour = Colour::Error; passOrFail = "FAILED"; } if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to unexpected exception with message"; break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to a fatal error condition"; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "because no exception was thrown where one was expected"; break; case ResultWas::Info: messageLabel = "info"; break; case ResultWas::Warning: messageLabel = "warning"; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"; colour = Colour::Error; if( _stats.infoMessages.size() == 1 ) messageLabel = "explicitly with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "explicitly with messages"; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: passOrFail = "** internal error **"; colour = Colour::Error; break; } } void print() const { printSourceInfo(); if( stats.totals.assertions.total() > 0 ) { if( result.isOk() ) stream << "\n"; printResultType(); printOriginalExpression(); printReconstructedExpression(); } else { stream << "\n"; } printMessage(); } private: void printResultType() const { if( !passOrFail.empty() ) { Colour colourGuard( colour ); stream << passOrFail << ":\n"; } } void printOriginalExpression() const { if( result.hasExpression() ) { Colour colourGuard( Colour::OriginalExpression ); stream << " "; stream << result.getExpressionInMacro(); stream << "\n"; } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; } } void printMessage() const { if( !messageLabel.empty() ) stream << messageLabel << ":" << "\n"; for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); it != itEnd; ++it ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || it->type != ResultWas::Info ) stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; } } void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ": "; } std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; Colour::Code colour; std::string passOrFail; std::string messageLabel; std::string message; std::vector messages; bool printInfoMessages; }; void lazyPrint() { if( !currentTestRunInfo.used ) lazyPrintRunInfo(); if( !currentGroupInfo.used ) lazyPrintGroupInfo(); if( !m_headerPrinted ) { printTestCaseAndSectionHeader(); m_headerPrinted = true; } } void lazyPrintRunInfo() { stream << "\n" << getLineOfChars<'~'>() << "\n"; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name << " is a Catch v" << libraryVersion << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; currentTestRunInfo.used = true; } void lazyPrintGroupInfo() { if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { printClosedHeader( "Group: " + currentGroupInfo->name ); currentGroupInfo.used = true; } } void printTestCaseAndSectionHeader() { assert( !m_sectionStack.empty() ); printOpenHeader( currentTestCaseInfo->name ); if( m_sectionStack.size() > 1 ) { Colour colourGuard( Colour::Headers ); std::vector::const_iterator it = m_sectionStack.begin()+1, // Skip first section (test case) itEnd = m_sectionStack.end(); for( ; it != itEnd; ++it ) printHeaderString( it->name, 2 ); } SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; if( !lineInfo.empty() ){ stream << getLineOfChars<'-'>() << "\n"; Colour colourGuard( Colour::FileName ); stream << lineInfo << "\n"; } stream << getLineOfChars<'.'>() << "\n" << std::endl; } void printClosedHeader( std::string const& _name ) { printOpenHeader( _name ); stream << getLineOfChars<'.'>() << "\n"; } void printOpenHeader( std::string const& _name ) { stream << getLineOfChars<'-'>() << "\n"; { Colour colourGuard( Colour::Headers ); printHeaderString( _name ); } } // if string has a : in first line will set indent to follow it on // subsequent lines void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { std::size_t i = _string.find( ": " ); if( i != std::string::npos ) i+=2; else i = 0; stream << Text( _string, TextAttributes() .setIndent( indent+i) .setInitialIndent( indent ) ) << "\n"; } struct SummaryColumn { SummaryColumn( std::string const& _label, Colour::Code _colour ) : label( _label ), colour( _colour ) {} SummaryColumn addRow( std::size_t count ) { std::ostringstream oss; oss << count; std::string row = oss.str(); for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { while( it->size() < row.size() ) *it = " " + *it; while( it->size() > row.size() ) row = " " + row; } rows.push_back( row ); return *this; } std::string label; Colour::Code colour; std::vector rows; }; void printTotals( Totals const& totals ) { if( totals.testCases.total() == 0 ) { stream << Colour( Colour::Warning ) << "No tests ran\n"; } else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << " (" << pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.testCases.passed, "test case" ) << ")" << "\n"; } else { std::vector columns; columns.push_back( SummaryColumn( "", Colour::None ) .addRow( totals.testCases.total() ) .addRow( totals.assertions.total() ) ); columns.push_back( SummaryColumn( "passed", Colour::Success ) .addRow( totals.testCases.passed ) .addRow( totals.assertions.passed ) ); columns.push_back( SummaryColumn( "failed", Colour::ResultError ) .addRow( totals.testCases.failed ) .addRow( totals.assertions.failed ) ); columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) .addRow( totals.testCases.failedButOk ) .addRow( totals.assertions.failedButOk ) ); printSummaryRow( "test cases", columns, 0 ); printSummaryRow( "assertions", columns, 1 ); } } void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { std::string value = it->rows[row]; if( it->label.empty() ) { stream << label << ": "; if( value != "0" ) stream << value; else stream << Colour( Colour::Warning ) << "- none -"; } else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; stream << Colour( it->colour ) << value << " " << it->label; } } stream << "\n"; } static std::size_t makeRatio( std::size_t number, std::size_t total ) { std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; return ( ratio == 0 && number > 0 ) ? 1 : ratio; } static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { if( i > j && i > k ) return i; else if( j > k ) return j; else return k; } void printTotalsDivider( Totals const& totals ) { if( totals.testCases.total() > 0 ) { std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )++; while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )--; stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); if( totals.testCases.allPassed() ) stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); else stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); } else { stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); } stream << "\n"; } void printSummaryDivider() { stream << getLineOfChars<'-'>() << "\n"; } private: bool m_headerPrinted; }; INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_compact.hpp #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED namespace Catch { struct CompactReporter : StreamingReporterBase { CompactReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual ~CompactReporter(); static std::string getDescription() { return "Reports test results on a single line, suitable for IDEs"; } virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } virtual void noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << "'" << std::endl; } virtual void assertionStarting( AssertionInfo const& ) { } virtual bool assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } virtual void testRunEnded( TestRunStats const& _testRunStats ) { printTotals( _testRunStats.totals ); stream << "\n" << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ) , stats( _stats ) , result( _stats.assertionResult ) , messages( _stats.infoMessages ) , itMessage( _stats.infoMessages.begin() ) , printInfoMessages( _printInfoMessages ) {} void print() { printSourceInfo(); itMessage = messages.begin(); switch( result.getResultType() ) { case ResultWas::Ok: printResultType( Colour::ResultSuccess, passedString() ); printOriginalExpression(); printReconstructedExpression(); if ( ! result.hasExpression() ) printRemainingMessages( Colour::None ); else printRemainingMessages(); break; case ResultWas::ExpressionFailed: if( result.isOk() ) printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); else printResultType( Colour::Error, failedString() ); printOriginalExpression(); printReconstructedExpression(); printRemainingMessages(); break; case ResultWas::ThrewException: printResultType( Colour::Error, failedString() ); printIssue( "unexpected exception with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::FatalErrorCondition: printResultType( Colour::Error, failedString() ); printIssue( "fatal error condition with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::DidntThrowException: printResultType( Colour::Error, failedString() ); printIssue( "expected exception, got none" ); printExpressionWas(); printRemainingMessages(); break; case ResultWas::Info: printResultType( Colour::None, "info" ); printMessage(); printRemainingMessages(); break; case ResultWas::Warning: printResultType( Colour::None, "warning" ); printMessage(); printRemainingMessages(); break; case ResultWas::ExplicitFailure: printResultType( Colour::Error, failedString() ); printIssue( "explicitly" ); printRemainingMessages( Colour::None ); break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: printResultType( Colour::Error, "** internal error **" ); break; } } private: // Colour::LightGrey static Colour::Code dimColour() { return Colour::FileName; } #ifdef CATCH_PLATFORM_MAC static const char* failedString() { return "FAILED"; } static const char* passedString() { return "PASSED"; } #else static const char* failedString() { return "failed"; } static const char* passedString() { return "passed"; } #endif void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ":"; } void printResultType( Colour::Code colour, std::string passOrFail ) const { if( !passOrFail.empty() ) { { Colour colourGuard( colour ); stream << " " << passOrFail; } stream << ":"; } } void printIssue( std::string issue ) const { stream << " " << issue; } void printExpressionWas() { if( result.hasExpression() ) { stream << ";"; { Colour colour( dimColour() ); stream << " expression was:"; } printOriginalExpression(); } } void printOriginalExpression() const { if( result.hasExpression() ) { stream << " " << result.getExpression(); } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { { Colour colour( dimColour() ); stream << " for: "; } stream << result.getExpandedExpression(); } } void printMessage() { if ( itMessage != messages.end() ) { stream << " '" << itMessage->message << "'"; ++itMessage; } } void printRemainingMessages( Colour::Code colour = dimColour() ) { if ( itMessage == messages.end() ) return; // using messages.end() directly yields compilation error: std::vector::const_iterator itEnd = messages.end(); const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); { Colour colourGuard( colour ); stream << " with " << pluralise( N, "message" ) << ":"; } for(; itMessage != itEnd; ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || itMessage->type != ResultWas::Info ) { stream << " '" << itMessage->message << "'"; if ( ++itMessage != itEnd ) { Colour colourGuard( dimColour() ); stream << " and"; } } } } private: std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; std::vector messages; std::vector::const_iterator itMessage; bool printInfoMessages; }; // Colour, message variants: // - white: No tests ran. // - red: Failed [both/all] N test cases, failed [both/all] M assertions. // - white: Passed [both/all] N test cases (no assertions). // - red: Failed N tests cases, failed M assertions. // - green: Passed [both/all] N tests cases with M assertions. std::string bothOrAll( std::size_t count ) const { return count == 1 ? "" : count == 2 ? "both " : "all " ; } void printTotals( const Totals& totals ) const { if( totals.testCases.total() == 0 ) { stream << "No tests ran."; } else if( totals.testCases.failed == totals.testCases.total() ) { Colour colour( Colour::ResultError ); const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() ? bothOrAll( totals.assertions.failed ) : ""; stream << "Failed " << bothOrAll( totals.testCases.failed ) << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << qualify_assertions_failed << pluralise( totals.assertions.failed, "assertion" ) << "."; } else if( totals.assertions.total() == 0 ) { stream << "Passed " << bothOrAll( totals.testCases.total() ) << pluralise( totals.testCases.total(), "test case" ) << " (no assertions)."; } else if( totals.assertions.failed ) { Colour colour( Colour::ResultError ); stream << "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; } else { Colour colour( Colour::ResultSuccess ); stream << "Passed " << bothOrAll( totals.testCases.passed ) << pluralise( totals.testCases.passed, "test case" ) << " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; } } }; INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch namespace Catch { // These are all here to avoid warnings about not having any out of line // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} IStream::~IStream() CATCH_NOEXCEPT {} FileStream::~FileStream() CATCH_NOEXCEPT {} CoutStream::~CoutStream() CATCH_NOEXCEPT {} DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} ITestCase::~ITestCase() {} ITestCaseRegistry::~ITestCaseRegistry() {} IRegistryHub::~IRegistryHub() {} IMutableRegistryHub::~IMutableRegistryHub() {} IExceptionTranslator::~IExceptionTranslator() {} IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} IReporter::~IReporter() {} IReporterFactory::~IReporterFactory() {} IReporterRegistry::~IReporterRegistry() {} IStreamingReporter::~IStreamingReporter() {} AssertionStats::~AssertionStats() {} SectionStats::~SectionStats() {} TestCaseStats::~TestCaseStats() {} TestGroupStats::~TestGroupStats() {} TestRunStats::~TestRunStats() {} CumulativeReporterBase::SectionNode::~SectionNode() {} CumulativeReporterBase::~CumulativeReporterBase() {} StreamingReporterBase::~StreamingReporterBase() {} ConsoleReporter::~ConsoleReporter() {} CompactReporter::~CompactReporter() {} IRunner::~IRunner() {} IMutableContext::~IMutableContext() {} IConfig::~IConfig() {} XmlReporter::~XmlReporter() {} JunitReporter::~JunitReporter() {} TestRegistry::~TestRegistry() {} FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} TestSpec::ExcludedPattern::~ExcludedPattern() {} Matchers::Impl::StdString::Equals::~Equals() {} Matchers::Impl::StdString::Contains::~Contains() {} Matchers::Impl::StdString::StartsWith::~StartsWith() {} Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} namespace TestCaseTracking { ITracker::~ITracker() {} TrackerBase::~TrackerBase() {} SectionTracker::~SectionTracker() {} IndexTracker::~IndexTracker() {} } } #ifdef __clang__ #pragma clang diagnostic pop #endif #endif #ifdef CATCH_CONFIG_MAIN // #included from: internal/catch_default_main.hpp #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED #ifndef __OBJC__ // Standard C/C++ main entry point int main (int argc, char * const argv[]) { return Catch::Session().run( argc, argv ); } #else // __OBJC__ // Objective-C entry point int main (int argc, char * const argv[]) { #if !CATCH_ARC_ENABLED NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; #endif Catch::registerTestMethods(); int result = Catch::Session().run( argc, (char* const*)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif return result; } #endif // __OBJC__ #endif #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) #else #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) #endif #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) #define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) #define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) #define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) #define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) #define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) #define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) #define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) #else #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) #endif #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) #define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) #define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) #define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) #define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED abyss-2.2.4/vendor/btl_bloomfilter/vendor/cpptoml/000077500000000000000000000000001361462241400222725ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/vendor/cpptoml/include/000077500000000000000000000000001361462241400237155ustar00rootroot00000000000000abyss-2.2.4/vendor/btl_bloomfilter/vendor/cpptoml/include/cpptoml.h000066400000000000000000002736431361462241400255630ustar00rootroot00000000000000/** * @file cpptoml.h * @author Chase Geigle * @date May 2013 */ #ifndef CPPTOML_H #define CPPTOML_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __cplusplus > 201103L #define CPPTOML_DEPRECATED(reason) [[deprecated(reason)]] #elif defined(__clang__) #define CPPTOML_DEPRECATED(reason) __attribute__((deprecated(reason))) #elif defined(__GNUG__) #define CPPTOML_DEPRECATED(reason) __attribute__((deprecated)) #elif defined(_MSC_VER) #if _MSC_VER < 1910 #define CPPTOML_DEPRECATED(reason) __declspec(deprecated) #else #define CPPTOML_DEPRECATED(reason) [[deprecated(reason)]] #endif #endif namespace cpptoml { class writer; // forward declaration class base; // forward declaration #if defined(CPPTOML_USE_MAP) // a std::map will ensure that entries a sorted, albeit at a slight // performance penalty relative to the (default) unordered_map using string_to_base_map = std::map>; #else // by default an unordered_map is used for best performance as the // toml specification does not require entries to be sorted using string_to_base_map = std::unordered_map>; #endif // if defined, `base` will retain type information in form of an enum class // such that static_cast can be used instead of dynamic_cast // #define CPPTOML_NO_RTTI template class option { public: option() : empty_{true} { // nothing } option(T value) : empty_{false}, value_(std::move(value)) { // nothing } explicit operator bool() const { return !empty_; } const T& operator*() const { return value_; } const T* operator->() const { return &value_; } template T value_or(U&& alternative) const { if (!empty_) return value_; return static_cast(std::forward(alternative)); } private: bool empty_; T value_; }; struct local_date { int year = 0; int month = 0; int day = 0; }; struct local_time { int hour = 0; int minute = 0; int second = 0; int microsecond = 0; }; struct zone_offset { int hour_offset = 0; int minute_offset = 0; }; struct local_datetime : local_date, local_time { }; struct offset_datetime : local_datetime, zone_offset { static inline struct offset_datetime from_zoned(const struct tm& t) { offset_datetime dt; dt.year = t.tm_year + 1900; dt.month = t.tm_mon + 1; dt.day = t.tm_mday; dt.hour = t.tm_hour; dt.minute = t.tm_min; dt.second = t.tm_sec; char buf[16]; strftime(buf, 16, "%z", &t); int offset = std::stoi(buf); dt.hour_offset = offset / 100; dt.minute_offset = offset % 100; return dt; } CPPTOML_DEPRECATED("from_local has been renamed to from_zoned") static inline struct offset_datetime from_local(const struct tm& t) { return from_zoned(t); } static inline struct offset_datetime from_utc(const struct tm& t) { offset_datetime dt; dt.year = t.tm_year + 1900; dt.month = t.tm_mon + 1; dt.day = t.tm_mday; dt.hour = t.tm_hour; dt.minute = t.tm_min; dt.second = t.tm_sec; return dt; } }; CPPTOML_DEPRECATED("datetime has been renamed to offset_datetime") typedef offset_datetime datetime; class fill_guard { public: fill_guard(std::ostream& os) : os_(os), fill_{os.fill()} { // nothing } ~fill_guard() { os_.fill(fill_); } private: std::ostream& os_; std::ostream::char_type fill_; }; inline std::ostream& operator<<(std::ostream& os, const local_date& dt) { fill_guard g{os}; os.fill('0'); using std::setw; os << setw(4) << dt.year << "-" << setw(2) << dt.month << "-" << setw(2) << dt.day; return os; } inline std::ostream& operator<<(std::ostream& os, const local_time& ltime) { fill_guard g{os}; os.fill('0'); using std::setw; os << setw(2) << ltime.hour << ":" << setw(2) << ltime.minute << ":" << setw(2) << ltime.second; if (ltime.microsecond > 0) { os << "."; int power = 100000; for (int curr_us = ltime.microsecond; curr_us; power /= 10) { auto num = curr_us / power; os << num; curr_us -= num * power; } } return os; } inline std::ostream& operator<<(std::ostream& os, const zone_offset& zo) { fill_guard g{os}; os.fill('0'); using std::setw; if (zo.hour_offset != 0 || zo.minute_offset != 0) { if (zo.hour_offset > 0) { os << "+"; } else { os << "-"; } os << setw(2) << std::abs(zo.hour_offset) << ":" << setw(2) << std::abs(zo.minute_offset); } else { os << "Z"; } return os; } inline std::ostream& operator<<(std::ostream& os, const local_datetime& dt) { return os << static_cast(dt) << "T" << static_cast(dt); } inline std::ostream& operator<<(std::ostream& os, const offset_datetime& dt) { return os << static_cast(dt) << static_cast(dt); } template struct is_one_of; template struct is_one_of : std::is_same { }; template struct is_one_of { const static bool value = std::is_same::value || is_one_of::value; }; template class value; template struct valid_value : is_one_of { }; template struct value_traits; template struct valid_value_or_string_convertible { const static bool value = valid_value::type>::value || std::is_convertible::value; }; template struct value_traits::value>::type> { using value_type = typename std::conditional< valid_value::type>::value, typename std::decay::type, std::string>::type; using type = value; static value_type construct(T&& val) { return value_type(val); } }; template struct value_traits< T, typename std::enable_if< !valid_value_or_string_convertible::value && std::is_floating_point::type>::value>::type> { using value_type = typename std::decay::type; using type = value; static value_type construct(T&& val) { return value_type(val); } }; template struct value_traits< T, typename std::enable_if< !valid_value_or_string_convertible::value && !std::is_floating_point::type>::value && std::is_signed::type>::value>::type> { using value_type = int64_t; using type = value; static value_type construct(T&& val) { if (val < (std::numeric_limits::min)()) throw std::underflow_error{"constructed value cannot be " "represented by a 64-bit signed " "integer"}; if (val > (std::numeric_limits::max)()) throw std::overflow_error{"constructed value cannot be represented " "by a 64-bit signed integer"}; return static_cast(val); } }; template struct value_traits< T, typename std::enable_if< !valid_value_or_string_convertible::value && std::is_unsigned::type>::value>::type> { using value_type = int64_t; using type = value; static value_type construct(T&& val) { if (val > static_cast((std::numeric_limits::max)())) throw std::overflow_error{"constructed value cannot be represented " "by a 64-bit signed integer"}; return static_cast(val); } }; class array; class table; class table_array; template struct array_of_trait { using return_type = option>; }; template <> struct array_of_trait { using return_type = option>>; }; template inline std::shared_ptr::type> make_value(T&& val); inline std::shared_ptr make_array(); namespace detail { template inline std::shared_ptr make_element(); } inline std::shared_ptr make_table(); inline std::shared_ptr make_table_array(bool is_inline = false); #if defined(CPPTOML_NO_RTTI) /// Base type used to store underlying data type explicitly if RTTI is disabled enum class base_type { NONE, STRING, LOCAL_TIME, LOCAL_DATE, LOCAL_DATETIME, OFFSET_DATETIME, INT, FLOAT, BOOL, TABLE, ARRAY, TABLE_ARRAY }; /// Type traits class to convert C++ types to enum member template struct base_type_traits; template <> struct base_type_traits { static const base_type type = base_type::STRING; }; template <> struct base_type_traits { static const base_type type = base_type::LOCAL_TIME; }; template <> struct base_type_traits { static const base_type type = base_type::LOCAL_DATE; }; template <> struct base_type_traits { static const base_type type = base_type::LOCAL_DATETIME; }; template <> struct base_type_traits { static const base_type type = base_type::OFFSET_DATETIME; }; template <> struct base_type_traits { static const base_type type = base_type::INT; }; template <> struct base_type_traits { static const base_type type = base_type::FLOAT; }; template <> struct base_type_traits { static const base_type type = base_type::BOOL; }; template <> struct base_type_traits
{ static const base_type type = base_type::TABLE; }; template <> struct base_type_traits { static const base_type type = base_type::ARRAY; }; template <> struct base_type_traits { static const base_type type = base_type::TABLE_ARRAY; }; #endif /** * A generic base TOML value used for type erasure. */ class base : public std::enable_shared_from_this { public: virtual ~base() = default; virtual std::shared_ptr clone() const = 0; /** * Determines if the given TOML element is a value. */ virtual bool is_value() const { return false; } /** * Determines if the given TOML element is a table. */ virtual bool is_table() const { return false; } /** * Converts the TOML element into a table. */ std::shared_ptr
as_table() { if (is_table()) return std::static_pointer_cast
(shared_from_this()); return nullptr; } /** * Determines if the TOML element is an array of "leaf" elements. */ virtual bool is_array() const { return false; } /** * Converts the TOML element to an array. */ std::shared_ptr as_array() { if (is_array()) return std::static_pointer_cast(shared_from_this()); return nullptr; } /** * Determines if the given TOML element is an array of tables. */ virtual bool is_table_array() const { return false; } /** * Converts the TOML element into a table array. */ std::shared_ptr as_table_array() { if (is_table_array()) return std::static_pointer_cast(shared_from_this()); return nullptr; } /** * Attempts to coerce the TOML element into a concrete TOML value * of type T. */ template std::shared_ptr> as(); template std::shared_ptr> as() const; template void accept(Visitor&& visitor, Args&&... args) const; #if defined(CPPTOML_NO_RTTI) base_type type() const { return type_; } protected: base(const base_type t) : type_(t) { // nothing } private: const base_type type_ = base_type::NONE; #else protected: base() { // nothing } #endif }; /** * A concrete TOML value representing the "leaves" of the "tree". */ template class value : public base { struct make_shared_enabler { // nothing; this is a private key accessible only to friends }; template friend std::shared_ptr::type> cpptoml::make_value(U&& val); public: static_assert(valid_value::value, "invalid value type"); std::shared_ptr clone() const override; value(const make_shared_enabler&, const T& val) : value(val) { // nothing; note that users cannot actually invoke this function // because they lack access to the make_shared_enabler. } bool is_value() const override { return true; } /** * Gets the data associated with this value. */ T& get() { return data_; } /** * Gets the data associated with this value. Const version. */ const T& get() const { return data_; } private: T data_; /** * Constructs a value from the given data. */ #if defined(CPPTOML_NO_RTTI) value(const T& val) : base(base_type_traits::type), data_(val) { } #else value(const T& val) : data_(val) { } #endif value(const value& val) = delete; value& operator=(const value& val) = delete; }; template std::shared_ptr::type> make_value(T&& val) { using value_type = typename value_traits::type; using enabler = typename value_type::make_shared_enabler; return std::make_shared( enabler{}, value_traits::construct(std::forward(val))); } template inline std::shared_ptr> base::as() { #if defined(CPPTOML_NO_RTTI) if (type() == base_type_traits::type) return std::static_pointer_cast>(shared_from_this()); else return nullptr; #else return std::dynamic_pointer_cast>(shared_from_this()); #endif } // special case value to allow getting an integer parameter as a // double value template <> inline std::shared_ptr> base::as() { #if defined(CPPTOML_NO_RTTI) if (type() == base_type::FLOAT) return std::static_pointer_cast>(shared_from_this()); if (type() == base_type::INT) { auto v = std::static_pointer_cast>(shared_from_this()); return make_value(static_cast(v->get())); } #else if (auto v = std::dynamic_pointer_cast>(shared_from_this())) return v; if (auto v = std::dynamic_pointer_cast>(shared_from_this())) return make_value(static_cast(v->get())); #endif return nullptr; } template inline std::shared_ptr> base::as() const { #if defined(CPPTOML_NO_RTTI) if (type() == base_type_traits::type) return std::static_pointer_cast>(shared_from_this()); else return nullptr; #else return std::dynamic_pointer_cast>(shared_from_this()); #endif } // special case value to allow getting an integer parameter as a // double value template <> inline std::shared_ptr> base::as() const { #if defined(CPPTOML_NO_RTTI) if (type() == base_type::FLOAT) return std::static_pointer_cast>( shared_from_this()); if (type() == base_type::INT) { auto v = as(); // the below has to be a non-const value due to a bug in // libc++: https://llvm.org/bugs/show_bug.cgi?id=18843 return make_value(static_cast(v->get())); } #else if (auto v = std::dynamic_pointer_cast>(shared_from_this())) return v; if (auto v = as()) { // the below has to be a non-const value due to a bug in // libc++: https://llvm.org/bugs/show_bug.cgi?id=18843 return make_value(static_cast(v->get())); } #endif return nullptr; } /** * Exception class for array insertion errors. */ class array_exception : public std::runtime_error { public: array_exception(const std::string& err) : std::runtime_error{err} { } }; class array : public base { public: friend std::shared_ptr make_array(); std::shared_ptr clone() const override; virtual bool is_array() const override { return true; } using size_type = std::size_t; /** * arrays can be iterated over */ using iterator = std::vector>::iterator; /** * arrays can be iterated over. Const version. */ using const_iterator = std::vector>::const_iterator; iterator begin() { return values_.begin(); } const_iterator begin() const { return values_.begin(); } iterator end() { return values_.end(); } const_iterator end() const { return values_.end(); } /** * Obtains the array (vector) of base values. */ std::vector>& get() { return values_; } /** * Obtains the array (vector) of base values. Const version. */ const std::vector>& get() const { return values_; } std::shared_ptr at(size_t idx) const { return values_.at(idx); } /** * Obtains an array of values. Note that elements may be * nullptr if they cannot be converted to a value. */ template std::vector>> array_of() const { std::vector>> result(values_.size()); std::transform(values_.begin(), values_.end(), result.begin(), [&](std::shared_ptr v) { return v->as(); }); return result; } /** * Obtains a option>. The option will be empty if the array * contains values that are not of type T. */ template inline typename array_of_trait::return_type get_array_of() const { std::vector result; result.reserve(values_.size()); for (const auto& val : values_) { if (auto v = val->as()) result.push_back(v->get()); else return {}; } return {std::move(result)}; } /** * Obtains an array of arrays. Note that elements may be nullptr * if they cannot be converted to a array. */ std::vector> nested_array() const { std::vector> result(values_.size()); std::transform(values_.begin(), values_.end(), result.begin(), [&](std::shared_ptr v) -> std::shared_ptr { if (v->is_array()) return std::static_pointer_cast(v); return std::shared_ptr{}; }); return result; } /** * Add a value to the end of the array */ template void push_back(const std::shared_ptr>& val) { if (values_.empty() || values_[0]->as()) { values_.push_back(val); } else { throw array_exception{"Arrays must be homogenous."}; } } /** * Add an array to the end of the array */ void push_back(const std::shared_ptr& val) { if (values_.empty() || values_[0]->is_array()) { values_.push_back(val); } else { throw array_exception{"Arrays must be homogenous."}; } } /** * Convenience function for adding a simple element to the end * of the array. */ template void push_back(T&& val, typename value_traits::type* = 0) { push_back(make_value(std::forward(val))); } /** * Insert a value into the array */ template iterator insert(iterator position, const std::shared_ptr>& value) { if (values_.empty() || values_[0]->as()) { return values_.insert(position, value); } else { throw array_exception{"Arrays must be homogenous."}; } } /** * Insert an array into the array */ iterator insert(iterator position, const std::shared_ptr& value) { if (values_.empty() || values_[0]->is_array()) { return values_.insert(position, value); } else { throw array_exception{"Arrays must be homogenous."}; } } /** * Convenience function for inserting a simple element in the array */ template iterator insert(iterator position, T&& val, typename value_traits::type* = 0) { return insert(position, make_value(std::forward(val))); } /** * Erase an element from the array */ iterator erase(iterator position) { return values_.erase(position); } /** * Clear the array */ void clear() { values_.clear(); } /** * Reserve space for n values. */ void reserve(size_type n) { values_.reserve(n); } private: #if defined(CPPTOML_NO_RTTI) array() : base(base_type::ARRAY) { // empty } #else array() = default; #endif template array(InputIterator begin, InputIterator end) : values_{begin, end} { // nothing } array(const array& obj) = delete; array& operator=(const array& obj) = delete; std::vector> values_; }; inline std::shared_ptr make_array() { struct make_shared_enabler : public array { make_shared_enabler() { // nothing } }; return std::make_shared(); } namespace detail { template <> inline std::shared_ptr make_element() { return make_array(); } } // namespace detail /** * Obtains a option>. The option will be empty if the array * contains values that are not of type T. */ template <> inline typename array_of_trait::return_type array::get_array_of() const { std::vector> result; result.reserve(values_.size()); for (const auto& val : values_) { if (auto v = val->as_array()) result.push_back(v); else return {}; } return {std::move(result)}; } class table; class table_array : public base { friend class table; friend std::shared_ptr make_table_array(bool); public: std::shared_ptr clone() const override; using size_type = std::size_t; /** * arrays can be iterated over */ using iterator = std::vector>::iterator; /** * arrays can be iterated over. Const version. */ using const_iterator = std::vector>::const_iterator; iterator begin() { return array_.begin(); } const_iterator begin() const { return array_.begin(); } iterator end() { return array_.end(); } const_iterator end() const { return array_.end(); } virtual bool is_table_array() const override { return true; } std::vector>& get() { return array_; } const std::vector>& get() const { return array_; } /** * Add a table to the end of the array */ void push_back(const std::shared_ptr
& val) { array_.push_back(val); } /** * Insert a table into the array */ iterator insert(iterator position, const std::shared_ptr
& value) { return array_.insert(position, value); } /** * Erase an element from the array */ iterator erase(iterator position) { return array_.erase(position); } /** * Clear the array */ void clear() { array_.clear(); } /** * Reserve space for n tables. */ void reserve(size_type n) { array_.reserve(n); } /** * Whether or not the table array is declared inline. This mostly * matters for parsing, where statically defined arrays cannot be * appended to using the array-of-table syntax. */ bool is_inline() const { return is_inline_; } private: #if defined(CPPTOML_NO_RTTI) table_array(bool is_inline = false) : base(base_type::TABLE_ARRAY), is_inline_(is_inline) { // nothing } #else table_array(bool is_inline = false) : is_inline_(is_inline) { // nothing } #endif table_array(const table_array& obj) = delete; table_array& operator=(const table_array& rhs) = delete; std::vector> array_; const bool is_inline_ = false; }; inline std::shared_ptr make_table_array(bool is_inline) { struct make_shared_enabler : public table_array { make_shared_enabler(bool mse_is_inline) : table_array(mse_is_inline) { // nothing } }; return std::make_shared(is_inline); } namespace detail { template <> inline std::shared_ptr make_element() { return make_table_array(true); } } // namespace detail // The below are overloads for fetching specific value types out of a value // where special casting behavior (like bounds checking) is desired template typename std::enable_if::value && std::is_signed::value, option>::type get_impl(const std::shared_ptr& elem) { if (auto v = elem->as()) { if (v->get() < (std::numeric_limits::min)()) throw std::underflow_error{ "T cannot represent the value requested in get"}; if (v->get() > (std::numeric_limits::max)()) throw std::overflow_error{ "T cannot represent the value requested in get"}; return {static_cast(v->get())}; } else { return {}; } } template typename std::enable_if::value && std::is_unsigned::value, option>::type get_impl(const std::shared_ptr& elem) { if (auto v = elem->as()) { if (v->get() < 0) throw std::underflow_error{"T cannot store negative value in get"}; if (static_cast(v->get()) > (std::numeric_limits::max)()) throw std::overflow_error{ "T cannot represent the value requested in get"}; return {static_cast(v->get())}; } else { return {}; } } template typename std::enable_if::value || std::is_same::value, option>::type get_impl(const std::shared_ptr& elem) { if (auto v = elem->as()) { return {v->get()}; } else { return {}; } } /** * Represents a TOML keytable. */ class table : public base { public: friend class table_array; friend std::shared_ptr
make_table(); std::shared_ptr clone() const override; /** * tables can be iterated over. */ using iterator = string_to_base_map::iterator; /** * tables can be iterated over. Const version. */ using const_iterator = string_to_base_map::const_iterator; iterator begin() { return map_.begin(); } const_iterator begin() const { return map_.begin(); } iterator end() { return map_.end(); } const_iterator end() const { return map_.end(); } bool is_table() const override { return true; } bool empty() const { return map_.empty(); } /** * Determines if this key table contains the given key. */ bool contains(const std::string& key) const { return map_.find(key) != map_.end(); } /** * Determines if this key table contains the given key. Will * resolve "qualified keys". Qualified keys are the full access * path separated with dots like "grandparent.parent.child". */ bool contains_qualified(const std::string& key) const { return resolve_qualified(key); } /** * Obtains the base for a given key. * @throw std::out_of_range if the key does not exist */ std::shared_ptr get(const std::string& key) const { return map_.at(key); } /** * Obtains the base for a given key. Will resolve "qualified * keys". Qualified keys are the full access path separated with * dots like "grandparent.parent.child". * * @throw std::out_of_range if the key does not exist */ std::shared_ptr get_qualified(const std::string& key) const { std::shared_ptr p; resolve_qualified(key, &p); return p; } /** * Obtains a table for a given key, if possible. */ std::shared_ptr
get_table(const std::string& key) const { if (contains(key) && get(key)->is_table()) return std::static_pointer_cast
(get(key)); return nullptr; } /** * Obtains a table for a given key, if possible. Will resolve * "qualified keys". */ std::shared_ptr
get_table_qualified(const std::string& key) const { if (contains_qualified(key) && get_qualified(key)->is_table()) return std::static_pointer_cast
(get_qualified(key)); return nullptr; } /** * Obtains an array for a given key. */ std::shared_ptr get_array(const std::string& key) const { if (!contains(key)) return nullptr; return get(key)->as_array(); } /** * Obtains an array for a given key. Will resolve "qualified keys". */ std::shared_ptr get_array_qualified(const std::string& key) const { if (!contains_qualified(key)) return nullptr; return get_qualified(key)->as_array(); } /** * Obtains a table_array for a given key, if possible. */ std::shared_ptr get_table_array(const std::string& key) const { if (!contains(key)) return nullptr; return get(key)->as_table_array(); } /** * Obtains a table_array for a given key, if possible. Will resolve * "qualified keys". */ std::shared_ptr get_table_array_qualified(const std::string& key) const { if (!contains_qualified(key)) return nullptr; return get_qualified(key)->as_table_array(); } /** * Helper function that attempts to get a value corresponding * to the template parameter from a given key. */ template option get_as(const std::string& key) const { try { return get_impl(get(key)); } catch (const std::out_of_range&) { return {}; } } /** * Helper function that attempts to get a value corresponding * to the template parameter from a given key. Will resolve "qualified * keys". */ template option get_qualified_as(const std::string& key) const { try { return get_impl(get_qualified(key)); } catch (const std::out_of_range&) { return {}; } } /** * Helper function that attempts to get an array of values of a given * type corresponding to the template parameter for a given key. * * If the key doesn't exist, doesn't exist as an array type, or one or * more keys inside the array type are not of type T, an empty option * is returned. Otherwise, an option containing a vector of the values * is returned. */ template inline typename array_of_trait::return_type get_array_of(const std::string& key) const { if (auto v = get_array(key)) { std::vector result; result.reserve(v->get().size()); for (const auto& b : v->get()) { if (auto val = b->as()) result.push_back(val->get()); else return {}; } return {std::move(result)}; } return {}; } /** * Helper function that attempts to get an array of values of a given * type corresponding to the template parameter for a given key. Will * resolve "qualified keys". * * If the key doesn't exist, doesn't exist as an array type, or one or * more keys inside the array type are not of type T, an empty option * is returned. Otherwise, an option containing a vector of the values * is returned. */ template inline typename array_of_trait::return_type get_qualified_array_of(const std::string& key) const { if (auto v = get_array_qualified(key)) { std::vector result; result.reserve(v->get().size()); for (const auto& b : v->get()) { if (auto val = b->as()) result.push_back(val->get()); else return {}; } return {std::move(result)}; } return {}; } /** * Adds an element to the keytable. */ void insert(const std::string& key, const std::shared_ptr& value) { map_[key] = value; } /** * Convenience shorthand for adding a simple element to the * keytable. */ template void insert(const std::string& key, T&& val, typename value_traits::type* = 0) { insert(key, make_value(std::forward(val))); } /** * Removes an element from the table. */ void erase(const std::string& key) { map_.erase(key); } private: #if defined(CPPTOML_NO_RTTI) table() : base(base_type::TABLE) { // nothing } #else table() { // nothing } #endif table(const table& obj) = delete; table& operator=(const table& rhs) = delete; std::vector split(const std::string& value, char separator) const { std::vector result; std::string::size_type p = 0; std::string::size_type q; while ((q = value.find(separator, p)) != std::string::npos) { result.emplace_back(value, p, q - p); p = q + 1; } result.emplace_back(value, p); return result; } // If output parameter p is specified, fill it with the pointer to the // specified entry and throw std::out_of_range if it couldn't be found. // // Otherwise, just return true if the entry could be found or false // otherwise and do not throw. bool resolve_qualified(const std::string& key, std::shared_ptr* p = nullptr) const { auto parts = split(key, '.'); auto last_key = parts.back(); parts.pop_back(); auto cur_table = this; for (const auto& part : parts) { cur_table = cur_table->get_table(part).get(); if (!cur_table) { if (!p) return false; throw std::out_of_range{key + " is not a valid key"}; } } if (!p) return cur_table->map_.count(last_key) != 0; *p = cur_table->map_.at(last_key); return true; } string_to_base_map map_; }; /** * Helper function that attempts to get an array of arrays for a given * key. * * If the key doesn't exist, doesn't exist as an array type, or one or * more keys inside the array type are not of type T, an empty option * is returned. Otherwise, an option containing a vector of the values * is returned. */ template <> inline typename array_of_trait::return_type table::get_array_of(const std::string& key) const { if (auto v = get_array(key)) { std::vector> result; result.reserve(v->get().size()); for (const auto& b : v->get()) { if (auto val = b->as_array()) result.push_back(val); else return {}; } return {std::move(result)}; } return {}; } /** * Helper function that attempts to get an array of arrays for a given * key. Will resolve "qualified keys". * * If the key doesn't exist, doesn't exist as an array type, or one or * more keys inside the array type are not of type T, an empty option * is returned. Otherwise, an option containing a vector of the values * is returned. */ template <> inline typename array_of_trait::return_type table::get_qualified_array_of(const std::string& key) const { if (auto v = get_array_qualified(key)) { std::vector> result; result.reserve(v->get().size()); for (const auto& b : v->get()) { if (auto val = b->as_array()) result.push_back(val); else return {}; } return {std::move(result)}; } return {}; } std::shared_ptr
make_table() { struct make_shared_enabler : public table { make_shared_enabler() { // nothing } }; return std::make_shared(); } namespace detail { template <> inline std::shared_ptr
make_element
() { return make_table(); } } // namespace detail template std::shared_ptr value::clone() const { return make_value(data_); } inline std::shared_ptr array::clone() const { auto result = make_array(); result->reserve(values_.size()); for (const auto& ptr : values_) result->values_.push_back(ptr->clone()); return result; } inline std::shared_ptr table_array::clone() const { auto result = make_table_array(is_inline()); result->reserve(array_.size()); for (const auto& ptr : array_) result->array_.push_back(ptr->clone()->as_table()); return result; } inline std::shared_ptr table::clone() const { auto result = make_table(); for (const auto& pr : map_) result->insert(pr.first, pr.second->clone()); return result; } /** * Exception class for all TOML parsing errors. */ class parse_exception : public std::runtime_error { public: parse_exception(const std::string& err) : std::runtime_error{err} { } parse_exception(const std::string& err, std::size_t line_number) : std::runtime_error{err + " at line " + std::to_string(line_number)} { } }; inline bool is_number(char c) { return c >= '0' && c <= '9'; } inline bool is_hex(char c) { return is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } /** * Helper object for consuming expected characters. */ template class consumer { public: consumer(std::string::iterator& it, const std::string::iterator& end, OnError&& on_error) : it_(it), end_(end), on_error_(std::forward(on_error)) { // nothing } void operator()(char c) { if (it_ == end_ || *it_ != c) on_error_(); ++it_; } template void operator()(const char (&str)[N]) { std::for_each(std::begin(str), std::end(str) - 1, [&](char c) { (*this)(c); }); } void eat_or(char a, char b) { if (it_ == end_ || (*it_ != a && *it_ != b)) on_error_(); ++it_; } int eat_digits(int len) { int val = 0; for (int i = 0; i < len; ++i) { if (!is_number(*it_) || it_ == end_) on_error_(); val = 10 * val + (*it_++ - '0'); } return val; } void error() { on_error_(); } private: std::string::iterator& it_; const std::string::iterator& end_; OnError on_error_; }; template consumer make_consumer(std::string::iterator& it, const std::string::iterator& end, OnError&& on_error) { return consumer(it, end, std::forward(on_error)); } // replacement for std::getline to handle incorrectly line-ended files // https://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf namespace detail { inline std::istream& getline(std::istream& input, std::string& line) { line.clear(); std::istream::sentry sentry{input, true}; auto sb = input.rdbuf(); while (true) { auto c = sb->sbumpc(); if (c == '\r') { if (sb->sgetc() == '\n') c = sb->sbumpc(); } if (c == '\n') return input; if (c == std::istream::traits_type::eof()) { if (line.empty()) input.setstate(std::ios::eofbit); return input; } line.push_back(static_cast(c)); } } } // namespace detail /** * The parser class. */ class parser { public: /** * Parsers are constructed from streams. */ parser(std::istream& stream) : input_(stream) { // nothing } parser& operator=(const parser& parser) = delete; /** * Parses the stream this parser was created on until EOF. * @throw parse_exception if there are errors in parsing */ std::shared_ptr
parse() { std::shared_ptr
root = make_table(); table* curr_table = root.get(); while (detail::getline(input_, line_)) { line_number_++; auto it = line_.begin(); auto end = line_.end(); consume_whitespace(it, end); if (it == end || *it == '#') continue; if (*it == '[') { curr_table = root.get(); parse_table(it, end, curr_table); } else { parse_key_value(it, end, curr_table); consume_whitespace(it, end); eol_or_comment(it, end); } } return root; } private: #if defined _MSC_VER __declspec(noreturn) #elif defined __GNUC__ __attribute__((noreturn)) #endif void throw_parse_exception(const std::string& err) { throw parse_exception{err, line_number_}; } void parse_table(std::string::iterator& it, const std::string::iterator& end, table*& curr_table) { // remove the beginning keytable marker ++it; if (it == end) throw_parse_exception("Unexpected end of table"); if (*it == '[') parse_table_array(it, end, curr_table); else parse_single_table(it, end, curr_table); } void parse_single_table(std::string::iterator& it, const std::string::iterator& end, table*& curr_table) { if (it == end || *it == ']') throw_parse_exception("Table name cannot be empty"); std::string full_table_name; bool inserted = false; auto key_end = [](char c) { return c == ']'; }; auto key_part_handler = [&](const std::string& part) { if (part.empty()) throw_parse_exception("Empty component of table name"); if (!full_table_name.empty()) full_table_name += '.'; full_table_name += part; if (curr_table->contains(part)) { #if !defined(__PGI) auto b = curr_table->get(part); #else // Workaround for PGI compiler std::shared_ptr b = curr_table->get(part); #endif if (b->is_table()) curr_table = static_cast(b.get()); else if (b->is_table_array()) curr_table = std::static_pointer_cast(b) ->get() .back() .get(); else throw_parse_exception("Key " + full_table_name + "already exists as a value"); } else { inserted = true; curr_table->insert(part, make_table()); curr_table = static_cast(curr_table->get(part).get()); } }; key_part_handler(parse_key(it, end, key_end, key_part_handler)); if (it == end) throw_parse_exception( "Unterminated table declaration; did you forget a ']'?"); if (*it != ']') { std::string errmsg{"Unexpected character in table definition: "}; errmsg += '"'; errmsg += *it; errmsg += '"'; throw_parse_exception(errmsg); } // table already existed if (!inserted) { auto is_value = [](const std::pair&>& p) { return p.second->is_value(); }; // if there are any values, we can't add values to this table // since it has already been defined. If there aren't any // values, then it was implicitly created by something like // [a.b] if (curr_table->empty() || std::any_of(curr_table->begin(), curr_table->end(), is_value)) { throw_parse_exception("Redefinition of table " + full_table_name); } } ++it; consume_whitespace(it, end); eol_or_comment(it, end); } void parse_table_array(std::string::iterator& it, const std::string::iterator& end, table*& curr_table) { ++it; if (it == end || *it == ']') throw_parse_exception("Table array name cannot be empty"); auto key_end = [](char c) { return c == ']'; }; std::string full_ta_name; auto key_part_handler = [&](const std::string& part) { if (part.empty()) throw_parse_exception("Empty component of table array name"); if (!full_ta_name.empty()) full_ta_name += '.'; full_ta_name += part; if (curr_table->contains(part)) { #if !defined(__PGI) auto b = curr_table->get(part); #else // Workaround for PGI compiler std::shared_ptr b = curr_table->get(part); #endif // if this is the end of the table array name, add an // element to the table array that we just looked up, // provided it was not declared inline if (it != end && *it == ']') { if (!b->is_table_array()) { throw_parse_exception("Key " + full_ta_name + " is not a table array"); } auto v = b->as_table_array(); if (v->is_inline()) { throw_parse_exception("Static array " + full_ta_name + " cannot be appended to"); } v->get().push_back(make_table()); curr_table = v->get().back().get(); } // otherwise, just keep traversing down the key name else { if (b->is_table()) curr_table = static_cast(b.get()); else if (b->is_table_array()) curr_table = std::static_pointer_cast(b) ->get() .back() .get(); else throw_parse_exception("Key " + full_ta_name + " already exists as a value"); } } else { // if this is the end of the table array name, add a new // table array and a new table inside that array for us to // add keys to next if (it != end && *it == ']') { curr_table->insert(part, make_table_array()); auto arr = std::static_pointer_cast( curr_table->get(part)); arr->get().push_back(make_table()); curr_table = arr->get().back().get(); } // otherwise, create the implicitly defined table and move // down to it else { curr_table->insert(part, make_table()); curr_table = static_cast(curr_table->get(part).get()); } } }; key_part_handler(parse_key(it, end, key_end, key_part_handler)); // consume the last "]]" auto eat = make_consumer(it, end, [this]() { throw_parse_exception("Unterminated table array name"); }); eat(']'); eat(']'); consume_whitespace(it, end); eol_or_comment(it, end); } void parse_key_value(std::string::iterator& it, std::string::iterator& end, table* curr_table) { auto key_end = [](char c) { return c == '='; }; auto key_part_handler = [&](const std::string& part) { // two cases: this key part exists already, in which case it must // be a table, or it doesn't exist in which case we must create // an implicitly defined table if (curr_table->contains(part)) { auto val = curr_table->get(part); if (val->is_table()) { curr_table = static_cast(val.get()); } else { throw_parse_exception("Key " + part + " already exists as a value"); } } else { auto newtable = make_table(); curr_table->insert(part, newtable); curr_table = newtable.get(); } }; auto key = parse_key(it, end, key_end, key_part_handler); if (curr_table->contains(key)) throw_parse_exception("Key " + key + " already present"); if (it == end || *it != '=') throw_parse_exception("Value must follow after a '='"); ++it; consume_whitespace(it, end); curr_table->insert(key, parse_value(it, end)); consume_whitespace(it, end); } template std::string parse_key(std::string::iterator& it, const std::string::iterator& end, KeyEndFinder&& key_end, KeyPartHandler&& key_part_handler) { // parse the key as a series of one or more simple-keys joined with '.' while (it != end && !key_end(*it)) { auto part = parse_simple_key(it, end); consume_whitespace(it, end); if (it == end || key_end(*it)) { return part; } if (*it != '.') { std::string errmsg{"Unexpected character in key: "}; errmsg += '"'; errmsg += *it; errmsg += '"'; throw_parse_exception(errmsg); } key_part_handler(part); // consume the dot ++it; } throw_parse_exception("Unexpected end of key"); } std::string parse_simple_key(std::string::iterator& it, const std::string::iterator& end) { consume_whitespace(it, end); if (it == end) throw_parse_exception("Unexpected end of key (blank key?)"); if (*it == '"' || *it == '\'') { return string_literal(it, end, *it); } else { auto bke = std::find_if(it, end, [](char c) { return c == '.' || c == '=' || c == ']'; }); return parse_bare_key(it, bke); } } std::string parse_bare_key(std::string::iterator& it, const std::string::iterator& end) { if (it == end) { throw_parse_exception("Bare key missing name"); } auto key_end = end; --key_end; consume_backwards_whitespace(key_end, it); ++key_end; std::string key{it, key_end}; if (std::find(it, key_end, '#') != key_end) { throw_parse_exception("Bare key " + key + " cannot contain #"); } if (std::find_if(it, key_end, [](char c) { return c == ' ' || c == '\t'; }) != key_end) { throw_parse_exception("Bare key " + key + " cannot contain whitespace"); } if (std::find_if(it, key_end, [](char c) { return c == '[' || c == ']'; }) != key_end) { throw_parse_exception("Bare key " + key + " cannot contain '[' or ']'"); } it = end; return key; } enum class parse_type { STRING = 1, LOCAL_TIME, LOCAL_DATE, LOCAL_DATETIME, OFFSET_DATETIME, INT, FLOAT, BOOL, ARRAY, INLINE_TABLE }; std::shared_ptr parse_value(std::string::iterator& it, std::string::iterator& end) { parse_type type = determine_value_type(it, end); switch (type) { case parse_type::STRING: return parse_string(it, end); case parse_type::LOCAL_TIME: return parse_time(it, end); case parse_type::LOCAL_DATE: case parse_type::LOCAL_DATETIME: case parse_type::OFFSET_DATETIME: return parse_date(it, end); case parse_type::INT: case parse_type::FLOAT: return parse_number(it, end); case parse_type::BOOL: return parse_bool(it, end); case parse_type::ARRAY: return parse_array(it, end); case parse_type::INLINE_TABLE: return parse_inline_table(it, end); default: throw_parse_exception("Failed to parse value"); } } parse_type determine_value_type(const std::string::iterator& it, const std::string::iterator& end) { if (it == end) { throw_parse_exception("Failed to parse value type"); } if (*it == '"' || *it == '\'') { return parse_type::STRING; } else if (is_time(it, end)) { return parse_type::LOCAL_TIME; } else if (auto dtype = date_type(it, end)) { return *dtype; } else if (is_number(*it) || *it == '-' || *it == '+' || (*it == 'i' && it + 1 != end && it[1] == 'n' && it + 2 != end && it[2] == 'f') || (*it == 'n' && it + 1 != end && it[1] == 'a' && it + 2 != end && it[2] == 'n')) { return determine_number_type(it, end); } else if (*it == 't' || *it == 'f') { return parse_type::BOOL; } else if (*it == '[') { return parse_type::ARRAY; } else if (*it == '{') { return parse_type::INLINE_TABLE; } throw_parse_exception("Failed to parse value type"); } parse_type determine_number_type(const std::string::iterator& it, const std::string::iterator& end) { // determine if we are an integer or a float auto check_it = it; if (*check_it == '-' || *check_it == '+') ++check_it; if (check_it == end) throw_parse_exception("Malformed number"); if (*check_it == 'i' || *check_it == 'n') return parse_type::FLOAT; while (check_it != end && is_number(*check_it)) ++check_it; if (check_it != end && *check_it == '.') { ++check_it; while (check_it != end && is_number(*check_it)) ++check_it; return parse_type::FLOAT; } else { return parse_type::INT; } } std::shared_ptr> parse_string(std::string::iterator& it, std::string::iterator& end) { auto delim = *it; assert(delim == '"' || delim == '\''); // end is non-const here because we have to be able to potentially // parse multiple lines in a string, not just one auto check_it = it; ++check_it; if (check_it != end && *check_it == delim) { ++check_it; if (check_it != end && *check_it == delim) { it = ++check_it; return parse_multiline_string(it, end, delim); } } return make_value(string_literal(it, end, delim)); } std::shared_ptr> parse_multiline_string(std::string::iterator& it, std::string::iterator& end, char delim) { std::stringstream ss; auto is_ws = [](char c) { return c == ' ' || c == '\t'; }; bool consuming = false; std::shared_ptr> ret; auto handle_line = [&](std::string::iterator& local_it, std::string::iterator& local_end) { if (consuming) { local_it = std::find_if_not(local_it, local_end, is_ws); // whole line is whitespace if (local_it == local_end) return; } consuming = false; while (local_it != local_end) { // handle escaped characters if (delim == '"' && *local_it == '\\') { auto check = local_it; // check if this is an actual escape sequence or a // whitespace escaping backslash ++check; consume_whitespace(check, local_end); if (check == local_end) { consuming = true; break; } ss << parse_escape_code(local_it, local_end); continue; } // if we can end the string if (std::distance(local_it, local_end) >= 3) { auto check = local_it; // check for """ if (*check++ == delim && *check++ == delim && *check++ == delim) { local_it = check; ret = make_value(ss.str()); break; } } ss << *local_it++; } }; // handle the remainder of the current line handle_line(it, end); if (ret) return ret; // start eating lines while (detail::getline(input_, line_)) { ++line_number_; it = line_.begin(); end = line_.end(); handle_line(it, end); if (ret) return ret; if (!consuming) ss << std::endl; } throw_parse_exception("Unterminated multi-line basic string"); } std::string string_literal(std::string::iterator& it, const std::string::iterator& end, char delim) { ++it; std::string val; while (it != end) { // handle escaped characters if (delim == '"' && *it == '\\') { val += parse_escape_code(it, end); } else if (*it == delim) { ++it; consume_whitespace(it, end); return val; } else { val += *it++; } } throw_parse_exception("Unterminated string literal"); } std::string parse_escape_code(std::string::iterator& it, const std::string::iterator& end) { ++it; if (it == end) throw_parse_exception("Invalid escape sequence"); char value; if (*it == 'b') { value = '\b'; } else if (*it == 't') { value = '\t'; } else if (*it == 'n') { value = '\n'; } else if (*it == 'f') { value = '\f'; } else if (*it == 'r') { value = '\r'; } else if (*it == '"') { value = '"'; } else if (*it == '\\') { value = '\\'; } else if (*it == 'u' || *it == 'U') { return parse_unicode(it, end); } else { throw_parse_exception("Invalid escape sequence"); } ++it; return std::string(1, value); } std::string parse_unicode(std::string::iterator& it, const std::string::iterator& end) { bool large = *it++ == 'U'; auto codepoint = parse_hex(it, end, large ? 0x10000000 : 0x1000); if ((codepoint > 0xd7ff && codepoint < 0xe000) || codepoint > 0x10ffff) { throw_parse_exception( "Unicode escape sequence is not a Unicode scalar value"); } std::string result; // See Table 3-6 of the Unicode standard if (codepoint <= 0x7f) { // 1-byte codepoints: 00000000 0xxxxxxx // repr: 0xxxxxxx result += static_cast(codepoint & 0x7f); } else if (codepoint <= 0x7ff) { // 2-byte codepoints: 00000yyy yyxxxxxx // repr: 110yyyyy 10xxxxxx // // 0x1f = 00011111 // 0xc0 = 11000000 // result += static_cast(0xc0 | ((codepoint >> 6) & 0x1f)); // // 0x80 = 10000000 // 0x3f = 00111111 // result += static_cast(0x80 | (codepoint & 0x3f)); } else if (codepoint <= 0xffff) { // 3-byte codepoints: zzzzyyyy yyxxxxxx // repr: 1110zzzz 10yyyyyy 10xxxxxx // // 0xe0 = 11100000 // 0x0f = 00001111 // result += static_cast(0xe0 | ((codepoint >> 12) & 0x0f)); result += static_cast(0x80 | ((codepoint >> 6) & 0x1f)); result += static_cast(0x80 | (codepoint & 0x3f)); } else { // 4-byte codepoints: 000uuuuu zzzzyyyy yyxxxxxx // repr: 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx // // 0xf0 = 11110000 // 0x07 = 00000111 // result += static_cast(0xf0 | ((codepoint >> 18) & 0x07)); result += static_cast(0x80 | ((codepoint >> 12) & 0x3f)); result += static_cast(0x80 | ((codepoint >> 6) & 0x3f)); result += static_cast(0x80 | (codepoint & 0x3f)); } return result; } uint32_t parse_hex(std::string::iterator& it, const std::string::iterator& end, uint32_t place) { uint32_t value = 0; while (place > 0) { if (it == end) throw_parse_exception("Unexpected end of unicode sequence"); if (!is_hex(*it)) throw_parse_exception("Invalid unicode escape sequence"); value += place * hex_to_digit(*it++); place /= 16; } return value; } uint32_t hex_to_digit(char c) { if (is_number(c)) return static_cast(c - '0'); return 10 + static_cast(c - ((c >= 'a' && c <= 'f') ? 'a' : 'A')); } std::shared_ptr parse_number(std::string::iterator& it, const std::string::iterator& end) { auto check_it = it; auto check_end = find_end_of_number(it, end); auto eat_sign = [&]() { if (check_it != end && (*check_it == '-' || *check_it == '+')) ++check_it; }; auto check_no_leading_zero = [&]() { if (check_it != end && *check_it == '0' && check_it + 1 != check_end && check_it[1] != '.') { throw_parse_exception("Numbers may not have leading zeros"); } }; auto eat_digits = [&](bool (*check_char)(char)) { auto beg = check_it; while (check_it != end && check_char(*check_it)) { ++check_it; if (check_it != end && *check_it == '_') { ++check_it; if (check_it == end || !check_char(*check_it)) throw_parse_exception("Malformed number"); } } if (check_it == beg) throw_parse_exception("Malformed number"); }; auto eat_hex = [&]() { eat_digits(&is_hex); }; auto eat_numbers = [&]() { eat_digits(&is_number); }; if (check_it != end && *check_it == '0' && check_it + 1 != check_end && (check_it[1] == 'x' || check_it[1] == 'o' || check_it[1] == 'b')) { ++check_it; char base = *check_it; ++check_it; if (base == 'x') { eat_hex(); return parse_int(it, check_it, 16); } else if (base == 'o') { auto start = check_it; eat_numbers(); auto val = parse_int(start, check_it, 8, "0"); it = start; return val; } else // if (base == 'b') { auto start = check_it; eat_numbers(); auto val = parse_int(start, check_it, 2); it = start; return val; } } eat_sign(); check_no_leading_zero(); if (check_it != end && check_it + 1 != end && check_it + 2 != end) { if (check_it[0] == 'i' && check_it[1] == 'n' && check_it[2] == 'f') { auto val = std::numeric_limits::infinity(); if (*it == '-') val = -val; it = check_it + 3; return make_value(val); } else if (check_it[0] == 'n' && check_it[1] == 'a' && check_it[2] == 'n') { auto val = std::numeric_limits::quiet_NaN(); if (*it == '-') val = -val; it = check_it + 3; return make_value(val); } } eat_numbers(); if (check_it != end && (*check_it == '.' || *check_it == 'e' || *check_it == 'E')) { bool is_exp = *check_it == 'e' || *check_it == 'E'; ++check_it; if (check_it == end) throw_parse_exception("Floats must have trailing digits"); auto eat_exp = [&]() { eat_sign(); check_no_leading_zero(); eat_numbers(); }; if (is_exp) eat_exp(); else eat_numbers(); if (!is_exp && check_it != end && (*check_it == 'e' || *check_it == 'E')) { ++check_it; eat_exp(); } return parse_float(it, check_it); } else { return parse_int(it, check_it); } } std::shared_ptr> parse_int(std::string::iterator& it, const std::string::iterator& end, int base = 10, const char* prefix = "") { std::string v{it, end}; v = prefix + v; v.erase(std::remove(v.begin(), v.end(), '_'), v.end()); it = end; try { return make_value(std::stoll(v, nullptr, base)); } catch (const std::invalid_argument& ex) { throw_parse_exception("Malformed number (invalid argument: " + std::string{ex.what()} + ")"); } catch (const std::out_of_range& ex) { throw_parse_exception("Malformed number (out of range: " + std::string{ex.what()} + ")"); } } std::shared_ptr> parse_float(std::string::iterator& it, const std::string::iterator& end) { std::string v{it, end}; v.erase(std::remove(v.begin(), v.end(), '_'), v.end()); it = end; char decimal_point = std::localeconv()->decimal_point[0]; std::replace(v.begin(), v.end(), '.', decimal_point); try { return make_value(std::stod(v)); } catch (const std::invalid_argument& ex) { throw_parse_exception("Malformed number (invalid argument: " + std::string{ex.what()} + ")"); } catch (const std::out_of_range& ex) { throw_parse_exception("Malformed number (out of range: " + std::string{ex.what()} + ")"); } } std::shared_ptr> parse_bool(std::string::iterator& it, const std::string::iterator& end) { auto eat = make_consumer(it, end, [this]() { throw_parse_exception("Attempted to parse invalid boolean value"); }); if (*it == 't') { eat("true"); return make_value(true); } else if (*it == 'f') { eat("false"); return make_value(false); } eat.error(); return nullptr; } std::string::iterator find_end_of_number(std::string::iterator it, std::string::iterator end) { auto ret = std::find_if(it, end, [](char c) { return !is_number(c) && c != '_' && c != '.' && c != 'e' && c != 'E' && c != '-' && c != '+' && c != 'x' && c != 'o' && c != 'b'; }); if (ret != end && ret + 1 != end && ret + 2 != end) { if ((ret[0] == 'i' && ret[1] == 'n' && ret[2] == 'f') || (ret[0] == 'n' && ret[1] == 'a' && ret[2] == 'n')) { ret = ret + 3; } } return ret; } std::string::iterator find_end_of_date(std::string::iterator it, std::string::iterator end) { auto end_of_date = std::find_if(it, end, [](char c) { return !is_number(c) && c != '-'; }); if (end_of_date != end && *end_of_date == ' ' && end_of_date + 1 != end && is_number(end_of_date[1])) end_of_date++; return std::find_if(end_of_date, end, [](char c) { return !is_number(c) && c != 'T' && c != 'Z' && c != ':' && c != '-' && c != '+' && c != '.'; }); } std::string::iterator find_end_of_time(std::string::iterator it, std::string::iterator end) { return std::find_if(it, end, [](char c) { return !is_number(c) && c != ':' && c != '.'; }); } local_time read_time(std::string::iterator& it, const std::string::iterator& end) { auto time_end = find_end_of_time(it, end); auto eat = make_consumer( it, time_end, [&]() { throw_parse_exception("Malformed time"); }); local_time ltime; ltime.hour = eat.eat_digits(2); eat(':'); ltime.minute = eat.eat_digits(2); eat(':'); ltime.second = eat.eat_digits(2); int power = 100000; if (it != time_end && *it == '.') { ++it; while (it != time_end && is_number(*it)) { ltime.microsecond += power * (*it++ - '0'); power /= 10; } } if (it != time_end) throw_parse_exception("Malformed time"); return ltime; } std::shared_ptr> parse_time(std::string::iterator& it, const std::string::iterator& end) { return make_value(read_time(it, end)); } std::shared_ptr parse_date(std::string::iterator& it, const std::string::iterator& end) { auto date_end = find_end_of_date(it, end); auto eat = make_consumer( it, date_end, [&]() { throw_parse_exception("Malformed date"); }); local_date ldate; ldate.year = eat.eat_digits(4); eat('-'); ldate.month = eat.eat_digits(2); eat('-'); ldate.day = eat.eat_digits(2); if (it == date_end) return make_value(ldate); eat.eat_or('T', ' '); local_datetime ldt; static_cast(ldt) = ldate; static_cast(ldt) = read_time(it, date_end); if (it == date_end) return make_value(ldt); offset_datetime dt; static_cast(dt) = ldt; int hoff = 0; int moff = 0; if (*it == '+' || *it == '-') { auto plus = *it == '+'; ++it; hoff = eat.eat_digits(2); dt.hour_offset = (plus) ? hoff : -hoff; eat(':'); moff = eat.eat_digits(2); dt.minute_offset = (plus) ? moff : -moff; } else if (*it == 'Z') { ++it; } if (it != date_end) throw_parse_exception("Malformed date"); return make_value(dt); } std::shared_ptr parse_array(std::string::iterator& it, std::string::iterator& end) { // this gets ugly because of the "homogeneity" restriction: // arrays can either be of only one type, or contain arrays // (each of those arrays could be of different types, though) // // because of the latter portion, we don't really have a choice // but to represent them as arrays of base values... ++it; // ugh---have to read the first value to determine array type... skip_whitespace_and_comments(it, end); // edge case---empty array if (*it == ']') { ++it; return make_array(); } auto val_end = std::find_if( it, end, [](char c) { return c == ',' || c == ']' || c == '#'; }); parse_type type = determine_value_type(it, val_end); switch (type) { case parse_type::STRING: return parse_value_array(it, end); case parse_type::LOCAL_TIME: return parse_value_array(it, end); case parse_type::LOCAL_DATE: return parse_value_array(it, end); case parse_type::LOCAL_DATETIME: return parse_value_array(it, end); case parse_type::OFFSET_DATETIME: return parse_value_array(it, end); case parse_type::INT: return parse_value_array(it, end); case parse_type::FLOAT: return parse_value_array(it, end); case parse_type::BOOL: return parse_value_array(it, end); case parse_type::ARRAY: return parse_object_array(&parser::parse_array, '[', it, end); case parse_type::INLINE_TABLE: return parse_object_array( &parser::parse_inline_table, '{', it, end); default: throw_parse_exception("Unable to parse array"); } } template std::shared_ptr parse_value_array(std::string::iterator& it, std::string::iterator& end) { auto arr = make_array(); while (it != end && *it != ']') { auto val = parse_value(it, end); if (auto v = val->as()) arr->get().push_back(val); else throw_parse_exception("Arrays must be homogeneous"); skip_whitespace_and_comments(it, end); if (*it != ',') break; ++it; skip_whitespace_and_comments(it, end); } if (it != end) ++it; return arr; } template std::shared_ptr parse_object_array(Function&& fun, char delim, std::string::iterator& it, std::string::iterator& end) { auto arr = detail::make_element(); while (it != end && *it != ']') { if (*it != delim) throw_parse_exception("Unexpected character in array"); arr->get().push_back(((*this).*fun)(it, end)); skip_whitespace_and_comments(it, end); if (it == end || *it != ',') break; ++it; skip_whitespace_and_comments(it, end); } if (it == end || *it != ']') throw_parse_exception("Unterminated array"); ++it; return arr; } std::shared_ptr
parse_inline_table(std::string::iterator& it, std::string::iterator& end) { auto tbl = make_table(); do { ++it; if (it == end) throw_parse_exception("Unterminated inline table"); consume_whitespace(it, end); if (it != end && *it != '}') { parse_key_value(it, end, tbl.get()); consume_whitespace(it, end); } } while (*it == ','); if (it == end || *it != '}') throw_parse_exception("Unterminated inline table"); ++it; consume_whitespace(it, end); return tbl; } void skip_whitespace_and_comments(std::string::iterator& start, std::string::iterator& end) { consume_whitespace(start, end); while (start == end || *start == '#') { if (!detail::getline(input_, line_)) throw_parse_exception("Unclosed array"); line_number_++; start = line_.begin(); end = line_.end(); consume_whitespace(start, end); } } void consume_whitespace(std::string::iterator& it, const std::string::iterator& end) { while (it != end && (*it == ' ' || *it == '\t')) ++it; } void consume_backwards_whitespace(std::string::iterator& back, const std::string::iterator& front) { while (back != front && (*back == ' ' || *back == '\t')) --back; } void eol_or_comment(const std::string::iterator& it, const std::string::iterator& end) { if (it != end && *it != '#') throw_parse_exception("Unidentified trailing character '" + std::string{*it} + "'---did you forget a '#'?"); } bool is_time(const std::string::iterator& it, const std::string::iterator& end) { auto time_end = find_end_of_time(it, end); auto len = std::distance(it, time_end); if (len < 8) return false; if (it[2] != ':' || it[5] != ':') return false; if (len > 8) return it[8] == '.' && len > 9; return true; } option date_type(const std::string::iterator& it, const std::string::iterator& end) { auto date_end = find_end_of_date(it, end); auto len = std::distance(it, date_end); if (len < 10) return {}; if (it[4] != '-' || it[7] != '-') return {}; if (len >= 19 && (it[10] == 'T' || it[10] == ' ') && is_time(it + 11, date_end)) { // datetime type auto time_end = find_end_of_time(it + 11, date_end); if (time_end == date_end) return {parse_type::LOCAL_DATETIME}; else return {parse_type::OFFSET_DATETIME}; } else if (len == 10) { // just a regular date return {parse_type::LOCAL_DATE}; } return {}; } std::istream& input_; std::string line_; std::size_t line_number_ = 0; }; /** * Utility function to parse a file as a TOML file. Returns the root table. * Throws a parse_exception if the file cannot be opened. */ inline std::shared_ptr
parse_file(const std::string& filename) { #if defined(BOOST_NOWIDE_FSTREAM_INCLUDED_HPP) boost::nowide::ifstream file{filename.c_str()}; #elif defined(NOWIDE_FSTREAM_INCLUDED_HPP) nowide::ifstream file{filename.c_str()}; #else std::ifstream file{filename}; #endif if (!file.is_open()) throw parse_exception{filename + " could not be opened for parsing"}; parser p{file}; return p.parse(); } template struct value_accept; template <> struct value_accept<> { template static void accept(const base&, Visitor&&, Args&&...) { // nothing } }; template struct value_accept { template static void accept(const base& b, Visitor&& visitor, Args&&... args) { if (auto v = b.as()) { visitor.visit(*v, std::forward(args)...); } else { value_accept::accept(b, std::forward(visitor), std::forward(args)...); } } }; /** * base implementation of accept() that calls visitor.visit() on the concrete * class. */ template void base::accept(Visitor&& visitor, Args&&... args) const { if (is_value()) { using value_acceptor = value_accept; value_acceptor::accept(*this, std::forward(visitor), std::forward(args)...); } else if (is_table()) { visitor.visit(static_cast(*this), std::forward(args)...); } else if (is_array()) { visitor.visit(static_cast(*this), std::forward(args)...); } else if (is_table_array()) { visitor.visit(static_cast(*this), std::forward(args)...); } } /** * Writer that can be passed to accept() functions of cpptoml objects and * will output valid TOML to a stream. */ class toml_writer { public: /** * Construct a toml_writer that will write to the given stream */ toml_writer(std::ostream& s, const std::string& indent_space = "\t") : stream_(s), indent_(indent_space), has_naked_endline_(false) { // nothing } public: /** * Output a base value of the TOML tree. */ template void visit(const value& v, bool = false) { write(v); } /** * Output a table element of the TOML tree */ void visit(const table& t, bool in_array = false) { write_table_header(in_array); std::vector values; std::vector tables; for (const auto& i : t) { if (i.second->is_table() || i.second->is_table_array()) { tables.push_back(i.first); } else { values.push_back(i.first); } } for (unsigned int i = 0; i < values.size(); ++i) { path_.push_back(values[i]); if (i > 0) endline(); write_table_item_header(*t.get(values[i])); t.get(values[i])->accept(*this, false); path_.pop_back(); } for (unsigned int i = 0; i < tables.size(); ++i) { path_.push_back(tables[i]); if (values.size() > 0 || i > 0) endline(); write_table_item_header(*t.get(tables[i])); t.get(tables[i])->accept(*this, false); path_.pop_back(); } endline(); } /** * Output an array element of the TOML tree */ void visit(const array& a, bool = false) { write("["); for (unsigned int i = 0; i < a.get().size(); ++i) { if (i > 0) write(", "); if (a.get()[i]->is_array()) { a.get()[i]->as_array()->accept(*this, true); } else { a.get()[i]->accept(*this, true); } } write("]"); } /** * Output a table_array element of the TOML tree */ void visit(const table_array& t, bool = false) { for (unsigned int j = 0; j < t.get().size(); ++j) { if (j > 0) endline(); t.get()[j]->accept(*this, true); } endline(); } /** * Escape a string for output. */ static std::string escape_string(const std::string& str) { std::string res; for (auto it = str.begin(); it != str.end(); ++it) { if (*it == '\b') { res += "\\b"; } else if (*it == '\t') { res += "\\t"; } else if (*it == '\n') { res += "\\n"; } else if (*it == '\f') { res += "\\f"; } else if (*it == '\r') { res += "\\r"; } else if (*it == '"') { res += "\\\""; } else if (*it == '\\') { res += "\\\\"; } else if (static_cast(*it) <= UINT32_C(0x001f)) { res += "\\u"; std::stringstream ss; ss << std::hex << static_cast(*it); res += ss.str(); } else { res += *it; } } return res; } protected: /** * Write out a string. */ void write(const value& v) { write("\""); write(escape_string(v.get())); write("\""); } /** * Write out a double. */ void write(const value& v) { std::stringstream ss; ss << std::showpoint << std::setprecision(std::numeric_limits::max_digits10) << v.get(); auto double_str = ss.str(); auto pos = double_str.find("e0"); if (pos != std::string::npos) double_str.replace(pos, 2, "e"); pos = double_str.find("e-0"); if (pos != std::string::npos) double_str.replace(pos, 3, "e-"); stream_ << double_str; has_naked_endline_ = false; } /** * Write out an integer, local_date, local_time, local_datetime, or * offset_datetime. */ template typename std::enable_if< is_one_of::value>::type write(const value& v) { write(v.get()); } /** * Write out a boolean. */ void write(const value& v) { write((v.get() ? "true" : "false")); } /** * Write out the header of a table. */ void write_table_header(bool in_array = false) { if (!path_.empty()) { indent(); write("["); if (in_array) { write("["); } for (unsigned int i = 0; i < path_.size(); ++i) { if (i > 0) { write("."); } if (path_[i].find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde" "fghijklmnopqrstuvwxyz0123456789" "_-") == std::string::npos) { write(path_[i]); } else { write("\""); write(escape_string(path_[i])); write("\""); } } if (in_array) { write("]"); } write("]"); endline(); } } /** * Write out the identifier for an item in a table. */ void write_table_item_header(const base& b) { if (!b.is_table() && !b.is_table_array()) { indent(); if (path_.back().find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde" "fghijklmnopqrstuvwxyz0123456789" "_-") == std::string::npos) { write(path_.back()); } else { write("\""); write(escape_string(path_.back())); write("\""); } write(" = "); } } private: /** * Indent the proper number of tabs given the size of * the path. */ void indent() { for (std::size_t i = 1; i < path_.size(); ++i) write(indent_); } /** * Write a value out to the stream. */ template void write(const T& v) { stream_ << v; has_naked_endline_ = false; } /** * Write an endline out to the stream */ void endline() { if (!has_naked_endline_) { stream_ << "\n"; has_naked_endline_ = true; } } private: std::ostream& stream_; const std::string indent_; std::vector path_; bool has_naked_endline_; }; inline std::ostream& operator<<(std::ostream& stream, const base& b) { toml_writer writer{stream}; b.accept(writer); return stream; } template std::ostream& operator<<(std::ostream& stream, const value& v) { toml_writer writer{stream}; v.accept(writer); return stream; } inline std::ostream& operator<<(std::ostream& stream, const table& t) { toml_writer writer{stream}; t.accept(writer); return stream; } inline std::ostream& operator<<(std::ostream& stream, const table_array& t) { toml_writer writer{stream}; t.accept(writer); return stream; } inline std::ostream& operator<<(std::ostream& stream, const array& a) { toml_writer writer{stream}; a.accept(writer); return stream; } } // namespace cpptoml #endif // CPPTOML_H abyss-2.2.4/vendor/btl_bloomfilter/vendor/ntHashIterator.hpp000066400000000000000000000065341361462241400242740ustar00rootroot00000000000000#ifndef NTHASH__ITERATOR_H #define NTHASH__ITERATOR_H 1 #include #include #include "nthash.hpp" /** * Iterate over hash values for k-mers in a * given DNA sequence. * * This implementation uses ntHash * function to efficiently calculate * hash values for successive k-mers. */ class ntHashIterator { public: /** * Default constructor. Creates an iterator pointing to * the end of the iterator range. */ ntHashIterator(): m_hVec(NULL), m_pos(std::numeric_limits::max()) {} /** * Constructor. * @param seq address of DNA sequence to be hashed * @param k k-mer size * @param h number of hashes */ ntHashIterator(const std::string& seq, unsigned h, unsigned k): m_seq(seq), m_h(h), m_k(k), m_hVec(new uint64_t[h]), m_pos(0) { init(); } /** Copy constructor */ ntHashIterator(const ntHashIterator &nth) { m_seq = nth.m_seq; m_h = nth.m_h; m_k = nth.m_k; m_hVec = new uint64_t[m_h]; for (unsigned i=0; i m_seq.length()) { m_pos = std::numeric_limits::max(); return; } unsigned locN=0; while (m_pos= m_seq.length()-m_k+1) m_pos = std::numeric_limits::max(); } /** Advance iterator right to the next valid k-mer */ void next() { ++m_pos; if (m_pos >= m_seq.length()-m_k+1) { m_pos = std::numeric_limits::max(); return; } if(seedTab[(unsigned char)(m_seq.at(m_pos+m_k-1))]==seedN) { m_pos+=m_k; init(); } else NTMC64(m_seq.at(m_pos-1), m_seq.at(m_pos-1+m_k), m_k, m_h, m_fhVal, m_rhVal, m_hVec); } size_t pos() const{ return m_pos; } /** get pointer to hash values for current k-mer */ const uint64_t* operator*() const { return m_hVec; } /** test equality with another iterator */ bool operator==(const ntHashIterator& it) const { return m_pos == it.m_pos; } /** test inequality with another iterator */ bool operator!=(const ntHashIterator& it) const { return !(*this == it); } /** pre-increment operator */ ntHashIterator& operator++() { next(); return *this; } /** iterator pointing to one past last element */ static const ntHashIterator end() { return ntHashIterator(); } /** destructor */ ~ntHashIterator() { if(m_hVec!=NULL) delete [] m_hVec; } private: /** DNA sequence */ std::string m_seq; /** number of hashes */ unsigned m_h; /** k-mer size */ unsigned m_k; /** hash values */ uint64_t *m_hVec; /** position of current k-mer */ size_t m_pos; /** forward-strand k-mer hash value */ uint64_t m_fhVal; /** reverse-complement k-mer hash value */ uint64_t m_rhVal; }; #endif abyss-2.2.4/vendor/btl_bloomfilter/vendor/nthash.hpp000066400000000000000000000643321361462241400226220ustar00rootroot00000000000000/* * * nthash.hpp * Author: Hamid Mohamadi * Genome Sciences Centre, * British Columbia Cancer Agency */ #ifndef NT_HASH_H #define NT_HASH_H #include #include // offset for the complement base in the random seeds table const uint8_t cpOff = 0x07; // shift for gerenerating multiple hash values const int multiShift = 27; // seed for gerenerating multiple hash values static const uint64_t multiSeed = 0x90b45d39fb6da1fa; // 64-bit random seeds corresponding to bases and their complements static const uint64_t seedA = 0x3c8bfbb395c60474; static const uint64_t seedC = 0x3193c18562a02b4c; static const uint64_t seedG = 0x20323ed082572324; static const uint64_t seedT = 0x295549f54be24456; static const uint64_t seedN = 0x0000000000000000; static const uint64_t seedTab[256] = { seedN, seedT, seedN, seedG, seedA, seedN, seedN, seedC, // 0..7 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 8..15 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 16..23 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 24..31 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 32..39 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 40..47 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 48..55 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 56..63 seedN, seedA, seedN, seedC, seedN, seedN, seedN, seedG, // 64..71 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 72..79 seedN, seedN, seedN, seedN, seedT, seedN, seedN, seedN, // 80..87 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 88..95 seedN, seedA, seedN, seedC, seedN, seedN, seedN, seedG, // 96..103 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 104..111 seedN, seedN, seedN, seedN, seedT, seedN, seedN, seedN, // 112..119 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 120..127 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 128..135 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 136..143 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 144..151 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 152..159 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 160..167 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 168..175 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 176..183 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 184..191 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 192..199 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 200..207 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 208..215 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 216..223 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 224..231 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 232..239 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 240..247 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN // 248..255 }; static const uint64_t A33r[33] = { 0x195c60474,0x12b8c08e9,0x571811d3,0xae3023a6,0x15c60474c,0xb8c08e99,0x171811d32,0xe3023a65,0x1c60474ca,0x18c08e995,0x11811d32b,0x3023a657,0x60474cae,0xc08e995c,0x1811d32b8,0x1023a6571,0x474cae3,0x8e995c6,0x11d32b8c,0x23a65718,0x474cae30,0x8e995c60,0x11d32b8c0,0x3a657181,0x74cae302,0xe995c604,0x1d32b8c08,0x1a6571811,0x14cae3023,0x995c6047,0x132b8c08e,0x6571811d,0xcae3023a }; static const uint64_t A31l[31] = { 0x3c8bfbb200000000,0x7917f76400000000,0xf22feec800000000,0xe45fdd9200000000,0xc8bfbb2600000000,0x917f764e00000000,0x22feec9e00000000,0x45fdd93c00000000,0x8bfbb27800000000,0x17f764f200000000,0x2feec9e400000000,0x5fdd93c800000000,0xbfbb279000000000,0x7f764f2200000000,0xfeec9e4400000000,0xfdd93c8a00000000,0xfbb2791600000000,0xf764f22e00000000,0xeec9e45e00000000,0xdd93c8be00000000,0xbb27917e00000000,0x764f22fe00000000,0xec9e45fc00000000,0xd93c8bfa00000000,0xb27917f600000000,0x64f22fee00000000,0xc9e45fdc00000000,0x93c8bfba00000000,0x27917f7600000000,0x4f22feec00000000,0x9e45fdd800000000 }; static const uint64_t C33r[33] = { 0x162a02b4c,0xc5405699,0x18a80ad32,0x115015a65,0x2a02b4cb,0x54056996,0xa80ad32c,0x15015a658,0xa02b4cb1,0x140569962,0x80ad32c5,0x1015a658a,0x2b4cb15,0x569962a,0xad32c54,0x15a658a8,0x2b4cb150,0x569962a0,0xad32c540,0x15a658a80,0xb4cb1501,0x169962a02,0xd32c5405,0x1a658a80a,0x14cb15015,0x9962a02b,0x132c54056,0x658a80ad,0xcb15015a,0x1962a02b4,0x12c540569,0x58a80ad3,0xb15015a6 }; static const uint64_t C31l[31] = { 0x3193c18400000000,0x6327830800000000,0xc64f061000000000,0x8c9e0c2200000000,0x193c184600000000,0x3278308c00000000,0x64f0611800000000,0xc9e0c23000000000,0x93c1846200000000,0x278308c600000000,0x4f06118c00000000,0x9e0c231800000000,0x3c18463200000000,0x78308c6400000000,0xf06118c800000000,0xe0c2319200000000,0xc184632600000000,0x8308c64e00000000,0x6118c9e00000000,0xc23193c00000000,0x1846327800000000,0x308c64f000000000,0x6118c9e000000000,0xc23193c000000000,0x8463278200000000,0x8c64f0600000000,0x118c9e0c00000000,0x23193c1800000000,0x4632783000000000,0x8c64f06000000000,0x18c9e0c200000000 }; static const uint64_t G33r[33] = { 0x82572324,0x104ae4648,0x95c8c91,0x12b91922,0x25723244,0x4ae46488,0x95c8c910,0x12b919220,0x57232441,0xae464882,0x15c8c9104,0xb9192209,0x172324412,0xe4648825,0x1c8c9104a,0x191922095,0x12324412b,0x46488257,0x8c9104ae,0x11922095c,0x324412b9,0x64882572,0xc9104ae4,0x1922095c8,0x124412b91,0x48825723,0x9104ae46,0x122095c8c,0x4412b919,0x88257232,0x1104ae464,0x2095c8c9,0x412b9192 }; static const uint64_t G31l[31] = { 0x20323ed000000000,0x40647da000000000,0x80c8fb4000000000,0x191f68200000000,0x323ed0400000000,0x647da0800000000,0xc8fb41000000000,0x191f682000000000,0x323ed04000000000,0x647da08000000000,0xc8fb410000000000,0x91f6820200000000,0x23ed040600000000,0x47da080c00000000,0x8fb4101800000000,0x1f68203200000000,0x3ed0406400000000,0x7da080c800000000,0xfb41019000000000,0xf682032200000000,0xed04064600000000,0xda080c8e00000000,0xb410191e00000000,0x6820323e00000000,0xd040647c00000000,0xa080c8fa00000000,0x410191f600000000,0x820323ec00000000,0x40647da00000000,0x80c8fb400000000,0x10191f6800000000 }; static const uint64_t T33r[33] = { 0x14be24456,0x97c488ad,0x12f89115a,0x5f1222b5,0xbe24456a,0x17c488ad4,0xf89115a9,0x1f1222b52,0x1e24456a5,0x1c488ad4b,0x189115a97,0x11222b52f,0x24456a5f,0x488ad4be,0x9115a97c,0x1222b52f8,0x4456a5f1,0x88ad4be2,0x1115a97c4,0x22b52f89,0x456a5f12,0x8ad4be24,0x115a97c48,0x2b52f891,0x56a5f122,0xad4be244,0x15a97c488,0xb52f8911,0x16a5f1222,0xd4be2445,0x1a97c488a,0x152f89115,0xa5f1222b }; static const uint64_t T31l[31] = { 0x295549f400000000,0x52aa93e800000000,0xa55527d000000000,0x4aaa4fa200000000,0x95549f4400000000,0x2aa93e8a00000000,0x55527d1400000000,0xaaa4fa2800000000,0x5549f45200000000,0xaa93e8a400000000,0x5527d14a00000000,0xaa4fa29400000000,0x549f452a00000000,0xa93e8a5400000000,0x527d14aa00000000,0xa4fa295400000000,0x49f452aa00000000,0x93e8a55400000000,0x27d14aaa00000000,0x4fa2955400000000,0x9f452aa800000000,0x3e8a555200000000,0x7d14aaa400000000,0xfa29554800000000,0xf452aa9200000000,0xe8a5552600000000,0xd14aaa4e00000000,0xa295549e00000000,0x452aa93e00000000,0x8a55527c00000000,0x14aaa4fa00000000 }; static const uint64_t N33r[33] = { seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN }; static const uint64_t N31l[31] = { seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN,seedN,seedN,seedN,seedN,seedN,seedN,seedN, seedN,seedN,seedN,seedN,seedN,seedN,seedN }; static const uint64_t *msTab33r[256] = { N33r, T33r, N33r, G33r, A33r, N33r, N33r, C33r, // 0..7 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 8..15 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 16..23 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 24..31 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 32..39 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 40..47 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 48..55 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 56..63 N33r, A33r, N33r, C33r, N33r, N33r, N33r, G33r, // 64..71 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 72..79 N33r, N33r, N33r, N33r, T33r, N33r, N33r, N33r, // 80..87 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 88..95 N33r, A33r, N33r, C33r, N33r, N33r, N33r, G33r, // 96..103 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 104..111 N33r, N33r, N33r, N33r, T33r, N33r, N33r, N33r, // 112..119 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 120..127 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 128..135 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 136..143 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 144..151 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 152..159 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 160..167 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 168..175 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 176..183 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 184..191 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 192..199 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 200..207 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 208..215 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 216..223 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 224..231 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 232..239 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r, // 240..247 N33r, N33r, N33r, N33r, N33r, N33r, N33r, N33r // 248..255 }; static const uint64_t *msTab31l[256] = { N31l, T31l, N31l, G31l, A31l, N31l, N31l, C31l, // 0..7 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 8..15 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 16..23 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 24..31 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 32..39 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 40..47 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 48..55 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 56..63 N31l, A31l, N31l, C31l, N31l, N31l, N31l, G31l, // 64..71 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 72..79 N31l, N31l, N31l, N31l, T31l, N31l, N31l, N31l, // 80..87 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 88..95 N31l, A31l, N31l, C31l, N31l, N31l, N31l, G31l, // 96..103 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 104..111 N31l, N31l, N31l, N31l, T31l, N31l, N31l, N31l, // 112..119 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 120..127 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 128..135 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 136..143 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 144..151 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 152..159 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 160..167 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 168..175 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 176..183 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 184..191 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 192..199 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 200..207 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 208..215 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 216..223 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 224..231 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 232..239 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l, // 240..247 N31l, N31l, N31l, N31l, N31l, N31l, N31l, N31l // 248..255 }; // rotate "v" to the left 1 position inline uint64_t rol1(const uint64_t v) { return (v << 1) | (v >> 63); } // rotate "v" to the right by 1 position inline uint64_t ror1(const uint64_t v) { return (v >> 1) | (v << 63); } // rotate 31-left bits of "v" to the left by "s" positions inline uint64_t rol31(const uint64_t v, unsigned s) { s%=31; return ((v << s) | (v >> (31 - s))) & 0x7FFFFFFF; } // rotate 33-right bits of "v" to the left by "s" positions inline uint64_t rol33(const uint64_t v, unsigned s) { s%=33; return ((v << s) | (v >> (33 - s))) & 0x1FFFFFFFF; } // swap bit 0 with bit 33 in "v" inline uint64_t swapbits033(const uint64_t v) { uint64_t x = (v ^ (v >> 33)) & 1; return v ^ (x | (x << 33)); } // swap bit 32 with bit 63 in "v" inline uint64_t swapbits3263(const uint64_t v) { uint64_t x = ((v >> 32) ^ (v >> 63)) & 1; return v ^ ((x << 32) | (x << 63)); } // forward-strand hash value of the base kmer, i.e. fhval(kmer_0) inline uint64_t NTF64(const char * kmerSeq, const unsigned k) { uint64_t hVal=0; for(unsigned i=0; i> multiShift; return hVal; } // canonical ntBase with seeding option inline uint64_t NTC64(const char * kmerSeq, const unsigned k, const unsigned seed) { uint64_t hVal = NTC64(kmerSeq,k); if(seed==0) return hVal; hVal *= seed ^ k * multiSeed; hVal ^= hVal >> multiShift; return hVal; } // multihash ntHash, ntBase inline void NTM64(const char * kmerSeq, const unsigned k, const unsigned m, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTF64(kmerSeq, k); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // one extra hash for given base hash inline uint64_t NTE64(const uint64_t hVal, const unsigned k, const unsigned i) { uint64_t tVal = hVal; tVal *= (i ^ k * multiSeed); tVal ^= tVal >> multiShift; return tVal; } // multihash ntHash for sliding k-mers inline void NTM64(const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTF64(hVal[0], k, charOut, charIn); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // canonical multihash ntBase inline void NTMC64(const char * kmerSeq, const unsigned k, const unsigned m, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTC64(kmerSeq, k); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // canonical multihash ntHash inline void NTMC64(const char * kmerSeq, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTC64(kmerSeq, k, fhVal, rhVal); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // canonical multihash ntHash for sliding k-mers inline void NTMC64(const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTC64(charOut, charIn, k, fhVal, rhVal); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } /* * ignoring k-mers containing nonACGT using ntHash function */ // canonical ntBase inline bool NTC4(const char *kmerSeq, const unsigned k, uint64_t& hVal, unsigned& locN) { hVal=0; locN=0; uint64_t fhVal=0,rhVal=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } hVal = (rhVal=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } bVal = (rhVal> multiShift; hVal[i] = tVal; } return true; } // canonical ntHash inline bool NTC64(const char *kmerSeq, const unsigned k, uint64_t& fhVal, uint64_t& rhVal, uint64_t& hVal, unsigned& locN) { hVal=fhVal=rhVal=0; locN=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } hVal = (rhVal=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } bVal = (rhVal> multiShift; hVal[i] = tVal; } return true; } // strand-aware canonical multihash ntHash inline bool NTMC64(const char *kmerSeq, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, unsigned& locN, uint64_t* hVal, bool& hStn) { fhVal=rhVal=0; uint64_t bVal=0, tVal=0; locN=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } hStn = rhVal> multiShift; hVal[i] = tVal; } return true; } // starnd-aware canonical multihash ntHash for sliding k-mers inline void NTMC64(const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal, bool &hStn) { uint64_t bVal=0, tVal=0; bVal = NTC64(charOut, charIn, k, fhVal, rhVal); hStn = rhVal> multiShift; hVal[i] = tVal; } } // masking canonical ntHash using spaced seed pattern inline uint64_t maskHash(uint64_t &fkVal, uint64_t &rkVal, const char * seedSeq, const char * kmerSeq, const unsigned k) { uint64_t fsVal=fkVal, rsVal=rkVal; for(unsigned i=0; i &seed, const unsigned k, uint64_t &hVal) { hVal=0; uint64_t sVal = 0; for(unsigned i=0; i &seed, const unsigned char charOut, const unsigned char charIn, const unsigned k, uint64_t &hVal) { hVal = NTF64(hVal,k,charOut,charIn); uint64_t sVal = hVal; for(unsigned i=0; i > &seedSeq, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, unsigned& locN, uint64_t* hVal, bool *hStn) { fhVal=rhVal=0; locN=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } for(unsigned j=0; j::const_iterator i=seedSeq[j].begin(); i!=seedSeq[j].end(); ++i) { fsVal ^= (msTab31l[(unsigned char)kmerSeq[*i]][(k-1-*i)%31] | msTab33r[(unsigned char)kmerSeq[*i]][(k-1-*i)%33]); rsVal ^= (msTab31l[(unsigned char)kmerSeq[*i]&cpOff][*i%31] | msTab33r[(unsigned char)kmerSeq[*i]&cpOff][*i%33]); } hStn[j] = rsVal > &seedSeq, const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal, bool *hStn) { fhVal = NTF64(fhVal,k,charOut,charIn); rhVal = NTR64(rhVal,k,charOut,charIn); for(unsigned j=0; j::const_iterator i=seedSeq[j].begin(); i!=seedSeq[j].end(); ++i) { fsVal ^= (msTab31l[(unsigned char)kmerSeq[*i]][(k-1-*i)%31] | msTab33r[(unsigned char)kmerSeq[*i]][(k-1-*i)%33]); rsVal ^= (msTab31l[(unsigned char)kmerSeq[*i]&cpOff][*i%31] | msTab33r[(unsigned char)kmerSeq[*i]&cpOff][*i%33]);; } hStn[j] = rsVal #include #include "nthash.hpp" /** * Iterate over hash values for k-mers in a * given DNA sequence. * * This implementation uses ntHash * function to efficiently calculate * hash values for successive k-mers. */ class ssHashIterator { public: /** * Default constructor. Creates an iterator pointing to * the end of the iterator range. */ ssHashIterator(): m_pos(std::numeric_limits::max()) {} /** * Constructor. * @param seq address of DNA sequence to be hashed * @param k k-mer size * @param h number of hashes */ ssHashIterator(const std::string& seq, const std::vector& seed, unsigned k): m_seq(seq), m_seed(seed), m_k(k), m_hVal(0), m_sVal(0), m_pos(0) { init(); } /** Initialize internal state of iterator */ void init() { if (m_k > m_seq.length()) { m_pos = std::numeric_limits::max(); return; } m_sVal = NTS64(m_seq.data()+m_pos, m_seed, m_k, m_hVal); } /** Advance iterator right to the next valid k-mer */ void next() { ++m_pos; if (m_pos >= m_seq.length()-m_k+1) { m_pos = std::numeric_limits::max(); return; } m_sVal = NTS64(m_seq.data()+m_pos, m_seed, m_seq.at(m_pos-1), m_seq.at(m_pos-1+m_k), m_k, m_hVal); } size_t pos() const { return m_pos; } /** get pointer to hash values for current k-mer */ uint64_t operator*() const { return m_sVal; } /** test equality with another iterator */ bool operator==(const ssHashIterator& it) const { return m_pos == it.m_pos; } /** test inequality with another iterator */ bool operator!=(const ssHashIterator& it) const { return !(*this == it); } /** pre-increment operator */ ssHashIterator& operator++() { next(); return *this; } /** iterator pointing to one past last element */ static const ssHashIterator end() { return ssHashIterator(); } /** destructor */ ~ssHashIterator() { } private: /** DNA sequence */ std::string m_seq; /** spaced seed */ std::vector m_seed; /** k-mer size */ unsigned m_k; /** hash value */ uint64_t m_hVal; /** hash value */ uint64_t m_sVal; /** position of current k-mer */ size_t m_pos; }; #endif abyss-2.2.4/vendor/btl_bloomfilter/vendor/stHashIterator.hpp000066400000000000000000000100121361462241400242630ustar00rootroot00000000000000#ifndef STHASH__ITERATOR_H #define STHASH__ITERATOR_H 1 #include #include #include "nthash.hpp" /** * Iterate over hash values for k-mers in a * given DNA sequence. * * This implementation uses ntHash * function to efficiently calculate * hash values for successive k-mers. */ class stHashIterator { public: static std::vector > parseSeed(const std::vector &seedString) { std::vector > seedSet; for (unsigned i=0; i< seedString.size(); i++) { std::vector sSeed; for (unsigned j=0; j < seedString[i].size(); j++) { if(seedString[i][j]!='1') sSeed.push_back(j); } seedSet.push_back(sSeed); } return seedSet; } /** * Default constructor. Creates an iterator pointing to * the end of the iterator range. */ stHashIterator(): m_hVec(NULL), m_hStn(NULL), m_pos(std::numeric_limits::max()) {} /** * Constructor. * @param seq address of DNA sequence to be hashed * @param seed address of spaced seed * @param k k-mer size * @param h number of hashes */ stHashIterator(const std::string& seq, const std::vector >& seed, unsigned h, unsigned k): m_seq(seq), m_seed(seed), m_h(h), m_k(k), m_hVec(new uint64_t[h]), m_hStn(new bool[h]), m_pos(0) { init(); } /** Initialize internal state of iterator */ void init() { if (m_k > m_seq.length()) { m_pos = std::numeric_limits::max(); return; } unsigned locN=0; while (m_pos= m_seq.length()-m_k+1) m_pos = std::numeric_limits::max(); } /** Advance iterator right to the next valid k-mer */ void next() { ++m_pos; if (m_pos >= m_seq.length()-m_k+1) { m_pos = std::numeric_limits::max(); return; } if(seedTab[(unsigned char)(m_seq.at(m_pos+m_k-1))]==seedN) { m_pos+=m_k; init(); } else NTMS64(m_seq.data()+m_pos, m_seed, m_seq.at(m_pos-1), m_seq.at(m_pos-1+m_k), m_k, m_h, m_fhVal, m_rhVal, m_hVec, m_hStn); } size_t pos() const{ return m_pos; } /** get pointer to hash values for current k-mer */ const bool* strandArray() const { return m_hStn; } /** get pointer to hash values for current k-mer */ const uint64_t* operator*() const { return m_hVec; } /** test equality with another iterator */ bool operator==(const stHashIterator& it) const { return m_pos == it.m_pos; } /** test inequality with another iterator */ bool operator!=(const stHashIterator& it) const { return !(*this == it); } /** pre-increment operator */ stHashIterator& operator++() { next(); return *this; } /** iterator pointing to one past last element */ static const stHashIterator end() { return stHashIterator(); } /** destructor */ ~stHashIterator() { if(m_hVec!=NULL) { delete [] m_hVec; delete [] m_hStn; } } private: /** DNA sequence */ std::string m_seq; /** Spaced Seed sequence */ std::vector > m_seed; /** number of hashes */ unsigned m_h; /** k-mer size */ unsigned m_k; /** hash values */ uint64_t *m_hVec; /** hash strands, forward = 0, reverse-complement = 1 */ bool *m_hStn; /** position of current k-mer */ size_t m_pos; /** forward-strand k-mer hash value */ uint64_t m_fhVal; /** reverse-complement k-mer hash value */ uint64_t m_rhVal; }; #endif abyss-2.2.4/vendor/gtest-1.7.0/000077500000000000000000000000001361462241400157275ustar00rootroot00000000000000abyss-2.2.4/vendor/gtest-1.7.0/CHANGES000066400000000000000000000147651361462241400167370ustar00rootroot00000000000000Changes 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 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 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 abyss-2.2.4/vendor/gtest-1.7.0/CONTRIBUTORS000066400000000000000000000025161361462241400176130ustar00rootroot00000000000000# 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 Balázs Dán Bharat Mediratta Chandler Carruth Chris Prince Chris Taylor Dan Egnor Eric Roman Hady Zalek Jeffrey Yasskin Jói Sigurðsson Keir Mierle Keith Ray Kenton Varda Manuel Klimek Markus Heule Mika Raento Miklós Fazekas Pasi Valminen Patrick Hanna Patrick Riley Peter Kaminski Preston Jackson Rainer Klaffenboeck Russ Cox Russ Rufer Sean Mcafee Sigurður Ãsgeirsson Tracy Bialik Vadim Berman Vlad Losev Zhanyong Wan abyss-2.2.4/vendor/gtest-1.7.0/LICENSE000066400000000000000000000027031361462241400167360ustar00rootroot00000000000000Copyright 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. abyss-2.2.4/vendor/gtest-1.7.0/Makefile.am000066400000000000000000000031031361462241400177600ustar00rootroot00000000000000check_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)/vendor/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)/vendor/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 abyss-2.2.4/vendor/gtest-1.7.0/README000066400000000000000000000373321361462241400166170ustar00rootroot00000000000000Google 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@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 ) 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! abyss-2.2.4/vendor/gtest-1.7.0/include/000077500000000000000000000000001361462241400173525ustar00rootroot00000000000000abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/000077500000000000000000000000001361462241400205005ustar00rootroot00000000000000abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-death-test.h000066400000000000000000000264031361462241400240440ustar00rootroot00000000000000// 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@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 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@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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-message.h000066400000000000000000000217421361462241400234270ustar00rootroot00000000000000// 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@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 #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 inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template 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 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 inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } } template 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 std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-param-test.h000066400000000000000000002241301361462241400240540ustar00rootroot00000000000000// 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@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 (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam 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 { // 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 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, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam 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 { // 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 #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 { ... }; // // 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 internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator 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 GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator 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 internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 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(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 internal::ValueArray25 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(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 internal::ValueArray26 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(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 internal::ValueArray27 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(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 internal::ValueArray28 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(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 internal::ValueArray29 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(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 internal::ValueArray30 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(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 internal::ValueArray31 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(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 internal::ValueArray32 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(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 internal::ValueArray33 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(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 internal::ValueArray34 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(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 internal::ValueArray35 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(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 internal::ValueArray36 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(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 internal::ValueArray37 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(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 internal::ValueArray38 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(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 internal::ValueArray39 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(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 internal::ValueArray40 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(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 internal::ValueArray41 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(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 internal::ValueArray42 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(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 internal::ValueArray43 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(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 internal::ValueArray44 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(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 internal::ValueArray45 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(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 internal::ValueArray46 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(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 internal::ValueArray47 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(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 internal::ValueArray48 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(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 internal::ValueArray49 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(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 internal::ValueArray50 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(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 { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator 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 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 > {...}; // // 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 > { // 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 internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 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( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 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( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 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( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 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( 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, __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 \ 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, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-param-test.h.pump000066400000000000000000000445541361462241400250460ustar00rootroot00000000000000$$ -*- 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@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 (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam 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 { // 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 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, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam 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 { // 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 #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 { ... }; // // 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 internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator 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 GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator 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 { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator 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 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 > {...}; // // 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 > { // 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, __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 \ 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, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-printers.h000066400000000000000000000755711361462241400236620ustar00rootroot00000000000000// 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@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::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 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 // NOLINT #include #include #include #include #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::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 class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo(reinterpret_cast(&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 class TypeWithoutFormatter { 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 class TypeWithoutFormatter { 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::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 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, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : internal::ImplicitlyConvertible::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 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::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 class UniversalPrinter; template 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 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 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::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( reinterpret_cast(p)); } } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template 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::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 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(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::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(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_(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_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(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_(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 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 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 void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo( const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template void PrintTo(const ::std::pair& 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::Print(value.first, os); *os << ", "; UniversalPrinter::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 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 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@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 class UniversalPrinter { 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 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 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(&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 class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T (&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { 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 { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::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 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::Print(value, os); } #if GTEST_HAS_TR1_TUPLE typedef ::std::vector 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::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. // The inductive case. template struct TuplePrefixPrinter { // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); *os << ", "; UniversalPrinter::type> ::Print(::std::tr1::get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; UniversalTersePrint(::std::tr1::get(t), &ss); strings->push_back(ss.str()); } }; // Base cases. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} template 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 static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { UniversalPrinter::type>:: Print(::std::tr1::get<0>(t), os); } template 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 void PrintTupleTo(const T& t, ::std::ostream* os) { *os << "("; TuplePrefixPrinter< ::std::tr1::tuple_size::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 Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: TersePrintPrefixToStrings(value, &result); return result; } #endif // GTEST_HAS_TR1_TUPLE } // namespace internal template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-spi.h000066400000000000000000000233401361462241400225720ustar00rootroot00000000000000// 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@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(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_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(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_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(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_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(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-test-part.h000066400000000000000000000145551361462241400237320ustar00rootroot00000000000000// 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@google.com (Markus Heule) // #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include #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 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest-typed-test.h000066400000000000000000000240021361462241400240750ustar00rootroot00000000000000// 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@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 class FooTest : public testing::Test { public: ... typedef std::list 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 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 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 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) # define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) # define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName 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 \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::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 \ class TestName : public CaseName { \ private: \ typedef CaseName 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 \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::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) # define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest.h000066400000000000000000002545621361462241400220150ustar00rootroot00000000000000// 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@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@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include #include #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@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 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 element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding 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 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& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& 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 test_part_results_; // The vector of TestProperties std::vector 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 type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr 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& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& 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 type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector 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 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::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 class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::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 \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(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 { \ 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 std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // The helper function for {ASSERT|EXPECT}_EQ. template 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 class EqHelper { public: // This templatized version is for the general case. template 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 { 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 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::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 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(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 \ 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 AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; ::std::stringstream actual_ss; actual_ss << std::setprecision(std::numeric_limits::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 { // 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 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::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 and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = NULL; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; #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::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::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, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ 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() 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 by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { (void)internal::StaticAssertTypeEqHelper(); 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()) } // 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest_pred_impl.h000066400000000000000000000354511361462241400240420ustar00rootroot00000000000000// 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@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 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 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 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 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 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/gtest_prod.h000066400000000000000000000044241361462241400230270ustar00rootroot00000000000000// 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@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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/000077500000000000000000000000001361462241400223145ustar00rootroot00000000000000abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-death-test-internal.h000066400000000000000000000321651361462241400274740ustar00rootroot00000000000000// 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@google.com (Zhanyong Wan), eefacm@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 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, >est_regex, \ __FILE__, __LINE__, >est_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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-filepath.h000066400000000000000000000226031361462241400254100ustar00rootroot00000000000000// 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@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 . // 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_.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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-internal.h000066400000000000000000001261611361462241400254340ustar00rootroot00000000000000// 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@google.com (Zhanyong Wan), eefacm@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 # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include #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 ::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 class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::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::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(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(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::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint 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 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::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() 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 TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::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 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 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::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 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 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().c_str(), NULL, // No value parameter. GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::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 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::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { 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 will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; // 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 struct RemoveReference { typedef T type; }; // NOLINT template struct RemoveReference { 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::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 struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { 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 struct RemoveConst { typedef typename RemoveConst::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 struct RemoveConst { typedef typename RemoveConst::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::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 struct AddReference { typedef T& type; }; // NOLINT template struct AddReference { 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::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::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. template 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 const bool ImplicitlyConvertible::value; // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template struct IsAProtocolMessage : public bool_constant< ImplicitlyConvertible::value || ImplicitlyConvertible::value> { }; // When the compiler sees expression IsContainerTest(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(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 IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // EnableIf::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::type* = 0" as the last parameter. template struct EnableIf; template<> struct EnableIf { 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 bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template 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 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 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 void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template 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 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 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(StaticAssertTypeEqHelper()); 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-linked_ptr.h000066400000000000000000000176451361462241400257610ustar00rootroot00000000000000// 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@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@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 #include #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(obj) vs linked_ptr(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. 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, linked_ptr, and // linked_ptr). 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 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 linked_ptr(linked_ptr 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 linked_ptr& operator=(linked_ptr 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 bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template 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 void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h000066400000000000000000005672601361462241400276400ustar00rootroot00000000000000// 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@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@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 internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(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 class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_), static_cast(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 class CartesianProductGenerator2 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& 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* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(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 CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(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 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 operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(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 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 operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(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 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 operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(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 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 operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(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 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 operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(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 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 operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-param-util-generated.h.pump000066400000000000000000000223101361462241400305760ustar00rootroot00000000000000$$ -*- 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@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@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 internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() 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 operator ParamGenerator() const { const T array[] = {$for j, [[static_cast(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& g$j]]) : $for j, [[g$(j)_(g$j)]] {} virtual ~CartesianProductGenerator$i() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); } virtual ParamIteratorInterface* End() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, $for j, [[ const ParamGenerator& g$j, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin$(j)_; const typename ParamGenerator::iterator end$(j)_; typename ParamGenerator::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 g$(j)_; ]] }; // class CartesianProductGenerator$i ]] // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator 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 >(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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-param-util.h000066400000000000000000000571771361462241400257050ustar00rootroot00000000000000// 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@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 #include #include // 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 class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template 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* 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. 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::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::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template 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* 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; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* 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 > 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 class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& 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(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* 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 class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* 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& 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(&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(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* 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 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 ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} virtual Test* CreateTest() { TestClass::SetParam(¶meter_); 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 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 TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(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 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(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(); } // 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* meta_factory) { tests_.push_back(linked_ptr(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 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 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::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* 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 > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > 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 ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* 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()) { // 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 >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(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 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-port.h000066400000000000000000002062741361462241400246100ustar00rootroot00000000000000// 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@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 // 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@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 // for isspace, etc #include // for ptrdiff_t #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include // NOLINT #include // 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 # include #elif !GTEST_OS_WINDOWS_MOBILE # include # include #endif #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // 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, 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, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // 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@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 when RTTI // is enabled. #if GTEST_HAS_RTTI # include #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 when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // 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 or . # 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 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 // 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 , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED # include # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . # if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. # else # include // 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 // 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 // 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 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 struct CompileAssert { }; #define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(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 // // 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 struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; #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 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 . 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@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@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_(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 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(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(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 // use like this: DownCast_(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_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); #endif return static_cast(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 Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(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& GetInjectableArgvs(); void SetInjectableArgvs(const ::std::vector* new_argvs); // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector 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(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 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 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. 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(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal 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 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(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(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 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 struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; template struct IteratorTraits { typedef typename Iterator::value_type value_type; }; template struct IteratorTraits { typedef T value_type; }; template struct IteratorTraits { 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(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(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(_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(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(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(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 class TypeWithSize { public: // This prevents the user from using TypeWithSize 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-string.h000066400000000000000000000154701361462241400251260ustar00rootroot00000000000000// 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@google.com (Zhanyong Wan), eefacm@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 . // 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 #endif #include #include #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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-tuple.h000066400000000000000000000670771361462241400247630ustar00rootroot00000000000000// 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@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 // 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 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 #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // 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 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::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template 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 tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_4_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_5_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_6_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_7_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_8_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_9_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class tuple { public: template 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 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 tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template 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 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 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 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 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 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 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 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 struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::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::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 struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-tuple.h.pump000066400000000000000000000220121361462241400257170ustar00rootroot00000000000000$$ -*- 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@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 // 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 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::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; $for i [[ template struct TupleElement { 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 class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { public: template 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 tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} $if k == 2 [[ template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} ]] tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { return CopyFrom(t); } $if k == 2 [[ template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } ]] GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } $for k [[ $range m 0..k-1 template 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 struct tuple_size; $for j [[ template struct tuple_size { static const int value = $j; }; ]] template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { $for i [[ template <> class Get<$i> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) Field(Tuple& t) { return t.f$(i)_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) ConstField(const Tuple& t) { return t.f$(i)_; } }; ]] } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(const GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::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::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 struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, const GTEST_$(n)_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template 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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-type-util.h000066400000000000000000005525021361462241400255560ustar00rootroot00000000000000// 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@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@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 # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() 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 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 ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::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 struct AssertTypeEq; template struct AssertTypeEq { 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, Type, 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 // 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 struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 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 // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::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, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN 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 struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 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 // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 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 struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::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_ abyss-2.2.4/vendor/gtest-1.7.0/include/gtest/internal/gtest-type-util.h.pump000066400000000000000000000221451361462241400265310ustar00rootroot00000000000000$$ -*- 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@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@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 # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() 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 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 ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::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 struct AssertTypeEq; template struct AssertTypeEq { 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, Type, 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 // 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 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 // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN 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 class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::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, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN 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 struct Templates1 { typedef TemplateSel 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 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 // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN 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 struct TypeList { typedef Types1 type; }; $range i 1..n template <$for i, [[typename T$i]]> struct TypeList > { 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_ abyss-2.2.4/vendor/gtest-1.7.0/src/000077500000000000000000000000001361462241400165165ustar00rootroot00000000000000abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-all.cc000066400000000000000000000041611361462241400207230ustar00rootroot00000000000000// 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@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" abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-death-test.cc000066400000000000000000001434051361462241400222220ustar00rootroot00000000000000// 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@google.com (Zhanyong Wan), vladl@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 # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # 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@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(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(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(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(::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(write_handle)) + "|" + StreamableToString(reinterpret_cast(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(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 GetArgvsForDeathTestChildProcess() { ::std::vector 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::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::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 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(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(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && reinterpret_cast(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@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(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(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(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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-filepath.cc000066400000000000000000000336361361462241400217600ustar00rootroot00000000000000// 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@gmail.com (Keith Ray) #include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-port.h" #include #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include # include // 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@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_.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@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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-internal-inl.h000066400000000000000000001326011361462241400224120ustar00rootroot00000000000000// 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@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 #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #include "gtest/internal/gtest-port.h" #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // 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(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(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 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 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 inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(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 void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(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 inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template 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& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& 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 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 environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector 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 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 internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > 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 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@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(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& 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(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 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_ abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-port.cc000066400000000000000000000655121361462241400211460ustar00rootroot00000000000000// 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@google.com (Zhanyong Wan) #include "gtest/internal/gtest-port.h" #include #include #include #include #if GTEST_OS_WINDOWS_MOBILE # include // For TerminateProcess() #elif GTEST_OS_WINDOWS # include # include #else # include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_QNX # include # include #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(thread_list), sizeof(thread_t) * thread_count); return static_cast(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(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(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 , 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@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(-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(pattern_)); free(const_cast(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(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(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 g_argvs; static const ::std::vector* g_injected_test_argvs = NULL; // Owned. void SetInjectableArgvs(const ::std::vector* argvs) { if (g_injected_test_argvs != argvs) delete g_injected_test_argvs; g_injected_test_argvs = argvs; } const ::std::vector& 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(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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-printers.cc000066400000000000000000000277631361462241400220360ustar00rootroot00000000000000// 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@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::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 #include #include // NOLINT #include #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 static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { switch (static_cast(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(c); return kAsIs; } else { *os << "\\x" + String::FormatHexInt(static_cast(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(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(static_cast(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 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(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(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(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(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(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 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 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_(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_(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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-test-part.cc000066400000000000000000000100771361462241400221010ustar00rootroot00000000000000// 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@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(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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest-typed-test.cc000066400000000000000000000072621361462241400222620ustar00rootroot00000000000000// 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@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_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 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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest.cc000066400000000000000000005475161361462241400201750ustar00rootroot00000000000000// 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@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) #include "gtest/gtest.h" #include "gtest/gtest-spi.h" #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_SYMBIAN # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@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 // NOLINT # endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@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 // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // 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& 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@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(); } // 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(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(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@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@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(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(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(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::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 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 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::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::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(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(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 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 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(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(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(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(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(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(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(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(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(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::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 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 element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time" }; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param" }; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector 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(); } static std::string FormatWordList(const std::vector& 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& 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(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(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 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(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 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(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(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); } // 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(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(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(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 listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@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(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(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(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: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // 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(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 << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } 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& 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 << " \n"; } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); const string summary = location + "\n" + part.summary(); *stream << " "; const string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \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 << " \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 << "\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 << "\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(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(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(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@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); // Deletes every Environment. ForEach(environments_, internal::Delete); 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::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(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(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(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@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@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-@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@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@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@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@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@D defaults to @Gtest_details.xml@D.\n" #if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@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@Y|@Gthreadsafe@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@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@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@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@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@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 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, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_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 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 abyss-2.2.4/vendor/gtest-1.7.0/src/gtest_main.cc000066400000000000000000000033451361462241400211640ustar00rootroot00000000000000// 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 #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(); } abyss-2.2.4/vendor/nthash/000077500000000000000000000000001361462241400154255ustar00rootroot00000000000000abyss-2.2.4/vendor/nthash/Makefile.am000066400000000000000000000000661361462241400174630ustar00rootroot00000000000000dist_doc_DATA = README.md noinst_HEADERS = nthash.hpp abyss-2.2.4/vendor/nthash/README.md000066400000000000000000000001151361462241400167010ustar00rootroot00000000000000nthash.hpp is taken from https://github.com/bcgsc/ntHash.git, commit 07e3f4d abyss-2.2.4/vendor/nthash/nthash.hpp000066400000000000000000000364671361462241400174430ustar00rootroot00000000000000/* * * nthash.hpp * Author: Hamid Mohamadi * Genome Sciences Centre, * British Columbia Cancer Agency */ #ifndef NT_HASH_H #define NT_HASH_H #include // offset for the complement base in the random seeds table const uint8_t cpOff = 0x07; // shift for gerenerating multiple hash values const int multiShift = 27; // seed for gerenerating multiple hash values static const uint64_t multiSeed = 0x90b45d39fb6da1fa; // 64-bit random seeds corresponding to bases and their complements static const uint64_t seedA = 0x3c8bfbb395c60474; static const uint64_t seedC = 0x3193c18562a02b4c; static const uint64_t seedG = 0x20323ed082572324; static const uint64_t seedT = 0x295549f54be24456; static const uint64_t seedN = 0x0000000000000000; static const uint64_t seedTab[256] = { seedN, seedT, seedN, seedG, seedA, seedN, seedN, seedC, // 0..7 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 8..15 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 16..23 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 24..31 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 32..39 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 40..47 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 48..55 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 56..63 seedN, seedA, seedN, seedC, seedN, seedN, seedN, seedG, // 64..71 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 72..79 seedN, seedN, seedN, seedN, seedT, seedN, seedN, seedN, // 80..87 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 88..95 seedN, seedA, seedN, seedC, seedN, seedN, seedN, seedG, // 96..103 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 104..111 seedN, seedN, seedN, seedN, seedT, seedN, seedN, seedN, // 112..119 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 120..127 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 128..135 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 136..143 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 144..151 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 152..159 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 160..167 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 168..175 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 176..183 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 184..191 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 192..199 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 200..207 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 208..215 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 216..223 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 224..231 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 232..239 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN, // 240..247 seedN, seedN, seedN, seedN, seedN, seedN, seedN, seedN // 248..255 }; // rotate "v" to the left 1 position inline uint64_t rol1(const uint64_t v) { return (v << 1) | (v >> 63); } // rotate "v" to the right by 1 position inline uint64_t ror1(const uint64_t v) { return (v >> 1) | (v << 63); } // rotate 31-left bits of "v" to the left by "s" positions inline uint64_t rol31(const uint64_t v, unsigned s) { s%=31; return ((v << s) | (v >> (31 - s))) & 0x7FFFFFFF; } // rotate 33-right bits of "v" to the left by "s" positions inline uint64_t rol33(const uint64_t v, unsigned s) { s%=33; return ((v << s) | (v >> (33 - s))) & 0x1FFFFFFFF; } // swap bit 0 with bit 33 in "v" inline uint64_t swapbits033(const uint64_t v) { uint64_t x = (v ^ (v >> 33)) & 1; return v ^ (x | (x << 33)); } // swap bit 32 with bit 63 in "v" inline uint64_t swapbits3263(const uint64_t v) { uint64_t x = ((v >> 32) ^ (v >> 63)) & 1; return v ^ ((x << 32) | (x << 63)); } // forward-strand hash value of the base kmer, i.e. fhval(kmer_0) inline uint64_t NTF64(const char * kmerSeq, const unsigned k) { uint64_t hVal=0; for(unsigned i=0; i> 33; uint64_t rBits = seedTab[charOut] & 0x1FFFFFFFF; uint64_t sOut = (rol31(lBits,k) << 33) | (rol33(rBits,k)); hVal ^= sOut; return hVal; } // reverse-complement ntHash for sliding k-mers inline uint64_t NTR64(const uint64_t rhVal, const unsigned k, const unsigned char charOut, const unsigned char charIn) { uint64_t lBits = seedTab[charIn&cpOff] >> 33; uint64_t rBits = seedTab[charIn&cpOff] & 0x1FFFFFFFF; uint64_t sIn = (rol31(lBits,k) << 33) | (rol33(rBits,k)); uint64_t hVal = rhVal ^ sIn; hVal ^= seedTab[charOut&cpOff]; hVal = ror1(hVal); hVal = swapbits3263(hVal); return hVal; } // canonical ntBase inline uint64_t NTC64(const char * kmerSeq, const unsigned k) { uint64_t fhVal=0, rhVal=0; fhVal=NTF64(kmerSeq, k); rhVal=NTR64(kmerSeq, k); return (rhVal> 33; uint64_t rBits = seedTab[charIn] & 0x1FFFFFFFF; uint64_t sIn = (rol31(lBits,k) << 33) | (rol33(rBits,k)); uint64_t hVal = rhVal ^ sIn; hVal ^= seedTab[charOut]; hVal = ror1(hVal); hVal = swapbits3263(hVal); return hVal; } // reverse-complement ntHash for sliding k-mers to the left inline uint64_t NTR64L(const uint64_t fhVal, const unsigned k, const unsigned char charOut, const unsigned char charIn) { uint64_t hVal = rol1(fhVal); hVal = swapbits033(hVal); hVal ^= seedTab[charIn&cpOff]; uint64_t lBits = seedTab[charOut&cpOff] >> 33; uint64_t rBits = seedTab[charOut&cpOff] & 0x1FFFFFFFF; uint64_t sOut = (rol31(lBits,k) << 33) | (rol33(rBits,k)); hVal ^= sOut; return hVal; } // canonical ntHash for sliding k-mers to the left inline uint64_t NTC64L(const unsigned char charOut, const unsigned char charIn, const unsigned k, uint64_t& fhVal, uint64_t& rhVal) { fhVal = NTF64L(fhVal, k, charOut, charIn); rhVal = NTR64L(rhVal, k, charOut, charIn); return (rhVal> multiShift; return hVal; } // canonical ntBase with seeding option inline uint64_t NTC64(const char * kmerSeq, const unsigned k, const unsigned seed) { uint64_t hVal = NTC64(kmerSeq,k); if(seed==0) return hVal; hVal *= seed ^ k * multiSeed; hVal ^= hVal >> multiShift; return hVal; } // multihash ntHash, ntBase inline void NTM64(const char * kmerSeq, const unsigned k, const unsigned m, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTF64(kmerSeq, k); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // one extra hash for given base hash inline uint64_t NTE64(const uint64_t hVal, const unsigned k, const unsigned i) { uint64_t tVal = hVal; tVal *= (i ^ k * multiSeed); tVal ^= tVal >> multiShift; return tVal; } // multihash ntHash for sliding k-mers inline void NTM64(const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTF64(hVal[0], k, charOut, charIn); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // canonical multihash ntBase inline void NTMC64(const char * kmerSeq, const unsigned k, const unsigned m, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTC64(kmerSeq, k); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // canonical multihash ntHash inline void NTMC64(const char * kmerSeq, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTC64(kmerSeq, k, fhVal, rhVal); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } // canonical multihash ntHash for sliding k-mers inline void NTMC64(const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal) { uint64_t bVal=0, tVal=0; bVal = NTC64(charOut, charIn, k, fhVal, rhVal); hVal[0] = bVal; for(unsigned i=1; i> multiShift; hVal[i] = tVal; } } /* * ignoring k-mers containing nonACGT using ntHash function */ // canonical ntBase inline bool NTC4(const char *kmerSeq, const unsigned k, uint64_t& hVal, unsigned& locN) { hVal=0; locN=0; uint64_t fhVal=0,rhVal=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } hVal = (rhVal=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } bVal = (rhVal> multiShift; hVal[i] = tVal; } return true; } // canonical ntHash inline bool NTC64(const char *kmerSeq, const unsigned k, uint64_t& fhVal, uint64_t& rhVal, uint64_t& hVal, unsigned& locN) { hVal=fhVal=rhVal=0; locN=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } hVal = (rhVal=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } bVal = (rhVal> multiShift; hVal[i] = tVal; } return true; } // strand-aware canonical multihash ntHash inline bool NTMC64(const char *kmerSeq, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, unsigned& locN, uint64_t* hVal, bool& hStn) { fhVal=rhVal=0; uint64_t bVal=0, tVal=0; locN=0; for(int i=k-1; i>=0; i--) { if(seedTab[(unsigned char)kmerSeq[i]]==seedN) { locN=i; return false; } fhVal = rol1(fhVal); fhVal = swapbits033(fhVal); fhVal ^= seedTab[(unsigned char)kmerSeq[k-1-i]]; rhVal = rol1(rhVal); rhVal = swapbits033(rhVal); rhVal ^= seedTab[(unsigned char)kmerSeq[i]&cpOff]; } hStn = rhVal> multiShift; hVal[i] = tVal; } return true; } // starnd-aware canonical multihash ntHash for sliding k-mers inline void NTMC64(const unsigned char charOut, const unsigned char charIn, const unsigned k, const unsigned m, uint64_t& fhVal, uint64_t& rhVal, uint64_t *hVal, bool &hStn) { uint64_t bVal=0, tVal=0; bVal = NTC64(charOut, charIn, k, fhVal, rhVal); hStn = rhVal> multiShift; hVal[i] = tVal; } } // masking canonical ntHash using spaced seed pattern inline uint64_t maskHash(uint64_t &fkVal, uint64_t &rkVal, const char * seedSeq, const char * kmerSeq, const unsigned k) { uint64_t fsVal=fkVal, rsVal=rkVal; for(unsigned i=0; i> 33; uint64_t rfBits = seedTab[(unsigned char)kmerSeq[i]] & 0x1FFFFFFFF; uint64_t sfMask = (rol31(lfBits,k-1-i) << 33) | (rol33(rfBits,k-1-i)); fsVal ^= sfMask; uint64_t lrBits = seedTab[(unsigned char)kmerSeq[i]&cpOff] >> 33; uint64_t rrBits = seedTab[(unsigned char)kmerSeq[i]&cpOff] & 0x1FFFFFFFF; uint64_t srMask = (rol31(lrBits,i) << 33) | (rol33(rrBits,i)); rsVal ^= srMask; } } return (rsVal