libStatGen Software
1
|
00001 /* 00002 * Copyright (C) 2010 Regents of the University of Michigan 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 #include "GreedyTupleAligner.h" 00018 #include <vector> 00019 #include <iostream> 00020 #include <sstream> 00021 #include <gtest/gtest.h> 00022 00023 // design a mock class for GenomeSequence 00024 class MockGenomeSequence{ 00025 public: 00026 MockGenomeSequence(std::string sequence) : 00027 sequence(sequence) {}; 00028 char operator[] (int index) const { 00029 if (index < 0 || index >= (int)sequence.size()) { 00030 std::cerr << "exceeds boundary! at " << __FILE__ << ":" <<__LINE__ << std::endl; 00031 return 'N'; 00032 } 00033 return sequence[index]; 00034 } 00035 char& operator[] (int index) { 00036 if (index < 0 || index >= (int)sequence.size()) { 00037 std::cerr << "exceeds boundary! at " << __FILE__ << ":" <<__LINE__ << std::endl; 00038 return sequence[0]; 00039 } 00040 return sequence[index]; 00041 } 00042 00043 int getNumberBases() const{ 00044 return sequence.size(); 00045 } 00046 private: 00047 std::string sequence; 00048 }; 00049 00050 void printRefQueryCigar(const std::vector<char>& prettyPrintReference, 00051 const std::vector<char>& prettyPrintQuery, 00052 CigarRoller& cs, 00053 std::ostream& out){ 00054 out << " ref = "; 00055 for(std::vector<char>::const_iterator i=prettyPrintReference.begin(); i<prettyPrintReference.end(); i++) out << *i; 00056 out << std::endl; 00057 out <<"query = "; 00058 for(std::vector<char>::const_iterator i=prettyPrintQuery.begin(); i<prettyPrintQuery.end(); i++) out << *i; 00059 out << std::endl; 00060 out << "cigar = "; 00061 out << cs.getString(); 00062 out << " "; 00063 } 00064 00065 void runAlign(const char *query, const char *ref, CigarRoller& cs, int& matchPosition) { 00066 Weight wt; 00067 MockGenomeSequence reference (ref); 00068 GreedyTupleAligner<const char *, MockGenomeSequence, int> ga(wt); 00069 ga.Align(query, strlen(query), reference, 0, strlen(ref), cs, matchPosition); 00070 } 00071 00072 void computePrettyOutput (std::vector<char>& prettyPrintReference, 00073 const char* ref, 00074 std::vector<char>& prettyPrintQuery, 00075 const char* query, 00076 const int matchPosition, 00077 const CigarRoller& expectedCigar) 00078 { 00079 const char* pRef = ref; 00080 const char* pQuery = query; 00081 for (int index = 0; index < matchPosition; index++){ 00082 prettyPrintReference.push_back(*pRef++); 00083 prettyPrintQuery.push_back(' '); 00084 } 00085 for (int i = 0; i< expectedCigar.size(); i++) { 00086 switch( expectedCigar[i].operation) { 00087 case CigarRoller::mismatch: 00088 case CigarRoller::match: 00089 for (unsigned int j = 0; j < expectedCigar[i].count; j++){ 00090 prettyPrintReference.push_back(*pRef++); 00091 prettyPrintQuery.push_back(*pQuery++); 00092 } 00093 break; 00094 case CigarRoller::del: 00095 for (unsigned int j = 0; j < expectedCigar[i].count; j++){ 00096 prettyPrintReference.push_back(*pRef++); 00097 prettyPrintQuery.push_back(' '); 00098 } 00099 break; 00100 case CigarRoller::insert: 00101 for (unsigned int j = 0; j < expectedCigar[i].count; j++){ 00102 prettyPrintReference.push_back(' '); 00103 prettyPrintQuery.push_back(*pQuery++); 00104 } 00105 break; 00106 default: 00107 break; 00108 } 00109 } /// end for 00110 while (*pRef !='\0') 00111 prettyPrintReference.push_back(*pRef++); 00112 while (*pQuery !='\0') 00113 prettyPrintReference.push_back(*pQuery++); 00114 } 00115 00116 bool verifyAlign(const char *query, const char *ref, const char *expectedCigarString, std::ostream& out = std::cout) { 00117 out.seekp(std::ios_base::beg); 00118 00119 CigarRoller cs; 00120 int matchPosition; 00121 CigarRoller expectedCigar(expectedCigarString); 00122 00123 runAlign(query, ref, cs, matchPosition); 00124 00125 00126 if (matchPosition < 0) { 00127 fprintf(stderr, "No match in %s, %d \n", __FILE__, __LINE__); 00128 return false; 00129 } 00130 00131 std::vector<char> prettyPrintReference,prettyPrintQuery; 00132 computePrettyOutput( prettyPrintReference, ref, 00133 prettyPrintQuery, query, 00134 matchPosition, 00135 expectedCigar); 00136 00137 const char *str = cs.getString(); 00138 00139 if((unsigned int)expectedCigar.getExpectedQueryBaseCount() != strlen(query)) { 00140 printRefQueryCigar(prettyPrintReference, prettyPrintQuery, cs, out); 00141 out << std::endl; 00142 out << "Expected Cigar string length " << expectedCigar.getExpectedQueryBaseCount() << " does not match the length of the query " << strlen(query) << ". Please fix test case." << std::endl; 00143 return false; 00144 } 00145 if((unsigned int)cs.getExpectedQueryBaseCount() != strlen(query)) { 00146 printRefQueryCigar(prettyPrintReference, prettyPrintQuery, cs, out); 00147 out << std::endl; 00148 out << "Query Length of " << strlen(query) << " does not match computed cigar string length of " << cs.getExpectedQueryBaseCount() << std::endl; 00149 return false; 00150 } 00151 if (strcmp(expectedCigarString, str) == 0) { 00152 // printf("[Correct Answer = %s] \n", expectedCigarString) ; 00153 return true; 00154 } else { 00155 printRefQueryCigar(prettyPrintReference, prettyPrintQuery, cs, out); 00156 out << "[Correct Answer = " << expectedCigarString << "] --------------------- Wrong!" << std::endl; 00157 return false; 00158 } 00159 return true; 00160 } 00161 00162 TEST(GreedyTupleAlignerTest, AlignToShortReference) { 00163 std::stringstream ss(std::stringstream::out); 00164 #if 0 00165 //exact align 00166 EXPECT_TRUE( verifyAlign("12345", "123456789", "5M") ) << ss.str().c_str(); 00167 EXPECT_TRUE( verifyAlign("23456", "123456789", "5M") ) << ss.str().c_str(); 00168 //mismatch 00169 EXPECT_TRUE( verifyAlign("123B567", "123456789", "7M") ) << ss.str().c_str(); 00170 EXPECT_TRUE( verifyAlign("234D678", "123456789", "7M") ) << ss.str().c_str(); 00171 // del 00172 EXPECT_TRUE( verifyAlign("123467890","1234567890", "4M1D5M") ) << ss.str().c_str(); 00173 EXPECT_TRUE( verifyAlign("123467890","B1234567890B", "4M1D5M") ) << ss.str().c_str(); 00174 // ins 00175 EXPECT_TRUE( verifyAlign("12345067890","1234567890", "5M1I5M") ) << ss.str().c_str(); 00176 EXPECT_TRUE( verifyAlign("12345067890","BBBB1234567890BBBB", "5M1I5M") ) << ss.str().c_str(); 00177 // soft clip 00178 EXPECT_TRUE( verifyAlign("1234", "1235", "3M1S") ) << ss.str().c_str(); 00179 // The following will treat as two mismatches 00180 // EXPECT_TRUE( verifyAlign("123456700", "123456789", "7M2S", ss) ) << ss.str().c_str(); 00181 #endif 00182 EXPECT_TRUE( verifyAlign("1023456700", "123456789","1I7M2S") ) << ss.str().c_str(); 00183 } 00184 00185 TEST(GreedyTupleTestAligner, AlignToLongReference) { 00186 std::stringstream ss(std::stringstream::out); 00187 00188 EXPECT_TRUE( verifyAlign("TTAGAATGCTATTGTGTTTGGAGATTTGAGGAAAGTGGGCGTGAAGACTTAGTGTTCATTTCCTCAACCTCTCTCTGTGTGAACATACGTCATCGGTCAGAAATTGGG","CCGAGATTGTGCCATTGCACTCCTGCCTGGGTAACAGAGTCAGACCCTGTCTCAAAAAAAAAAAAAAAAAAAAAAAAGATTAGGTTTTATAGATGGAAAATTCACAGCTCTCTCCAGATCAGAAATCTCCAAGAGTAAATTAGTGTCTTAAAGGGGTTGTAATAACTTTCCTATGTGACTAAGTGCATTATTAATCAATTTTTCTATGATCAAGTACTCCTTTACATACCTGCTAATACAATTTTTGATATGAAATCAGTCCTAGAGGGAATCAATGTAAGATACAGACTTGATGAGTGCTTGCAGTTTTTTATTGACAATCTGAAGAATGACTTGACTCTAAATTGCAGCTCAAGGCTTAGAATGCTATTGTGTTTGGAGATTTGAGGAAAGTGGGCGTGAAGACTTAGTGTTCATTTCCTCAACCTCTCTCTGTGTGAACATACAGGAATCAAATCTGTCTAGCCTCTCTTTTTGGCAAGGTTAAGAACAATTCCACTTCATCCTAATCCCAATGATTCCTGCCGACCCTCTTCCAAAAACTATTTAAAGACATGTTCTTCAAAGTTATATTTGTCTTTCCTTCAGGGAGAAAAAGAATACCAATCACTTATAATATGGAAACTAGCAGAAATGGGTCACATAAGTCATCTGTCAGAAATTGGGAAAATAGAGTAGGTCAGTCTTTCCAGTCATGGTACTTTTACCTTCAATCA", "88M200D20M") ) << ss.str().c_str(); 00189 00190 // This reads cigar string is the wrong length. By that I mean that the number 00191 // of matches listed in the cigar should be the same as the length of 00192 // the original read. 00193 // 00194 EXPECT_TRUE( verifyAlign("GTGAAACTCCATCTCAAAAATAAGTAAATAAATAAATACATACATAGGCACAGTGCAGTTGTTAGTCAGAATTAGGTCACACTGGATTAGGGTGAGTACTTAATGCAACAGGTCTGGGG","GTGCCAGAGTTTAATTAATAGGATAAGGTTATGAGTCAGACTGTGTACCCCAAAAAAGATATGTTGAACTCCTAAGCCCCTGAACCACAGAATGGGATCCTATTCAGAAATAGGCACAGTGTCCGGGCACCATGGCTCACACTGGTAATCCCAGCACTCTGGGAGGCTGAGGTGGGTGCATCACCTGAGGTCAGGAGTTTGAGACCAGCCTGGCCAACATGGTGAAACCCCATCTCTACTAAAAATACAAACAGAACAGTTAGCCAGGTGTGGTGGTGGGCACCTGTAATCCCAGCTACTTGGGAGGCTGAGACAGGAGAATGGCTTGAACCCAGGAGGTGGAGGTTGCAGTGAGCCGAGATCGTGCCATTGCACTTCAGCCTGGGCCACAAGAGTGAAACTCCATCTCAAAAATAAGTAAATAAATAAATACATACGTAGGCACAGTGCAGTTGTTGTTAGTTAGAATTAGGTCACACTGGATTAGGGTGAGTCCTTAATCCAACAGGTCTGGTGTCCTTACAAATAGACAAATACACAGAAGGAACATGGCCACATGGAGATACAGACACACCAAAACATCATATTGAGATGTGGGCAAAGATTGGAGAGACACTTCTCCAAGTCAAGGAACATCTGGGACTACCCAGAAACTGTAAGAGGCAGAGAAAGGTCCTTCCCTGTAGGCTTTAGAGGAACATGGCCCTGCCAACATCTTGATCTTGGATTTCCAGCCTCCAGCATGTGAGACAAGTTTCTGGGTTTTTTTGGAGACAGAGTCTCACTCTTGTCACCCAGGCTGGAGTGCAGTGGCATGAACTTGGCTCACTGCAACCTCCTCCCAGGATCAAGGTATTGTCCTGCCTCAGCCTCCCGAGTAGCTGGGATGACAGGGGCCCGCCACCACGCCAGCTCATTTTTGTATTTTTTACTAGAGAAGGGGTTTCACCATGTTGGCCAGGCTGGTCTTGAACTCCTGACCTCAAGTGATCCACCCGCCTTGGCCTCCCAAAGTGCTAGGATTACAGGTGTGAGCCACTGCGCCTGGCAAGTTTCTGTTGCCTTAAGCCACTCTTTCTGTGGTAATTTGTTATCATGGCCCTAAGAAATGACTAGAGAGAGAAAGCAAATCCCTTTGTTTCTGCATTTACTGAAACAGATGAATAGATTTCTAGCTCCCTTGGGGTCTGAACTTTTAAAAGAGAGATTTCTTATACATATGATAATCATGATATTGT", "63M3D56M") ) << ss.str().c_str(); 00195 00196 EXPECT_TRUE( verifyAlign("ATATTGTTTTTTTCAATGCATATCAAAACAATGTTTACAATATACTACAGCCTAAGTGTGCAATAGCATTATGTGTAGAAATGCACATACCATAATTAGTTTTTTTTTTTGAAAAAACT","GTTCCAAAAGATTATATTTGTTAGGTTAGAGAATTTTAACTTATTTATATAATGGAGATTTTCTAATACTGAGAATACCTTAATTCTTATTGTAAGCCTACTTAACAGTGACAAAATGTTATTATAACGTGGTATTGAAATTAATATGATAGTATTTTATATGGATATTTGCATATGCAATTGACATATATTGTATATACAATATATAACTGTGTATTATATATTATATTTATATAATGTTATATTGTATATGAATATATTTGAATTATATGTATATACATATATATAGGCATTCATCAGAAATATTGCAGGTTTGGTTTCAGACGACTATAATAAAGTGAATATTGCAATAAAGCGAATCACAAGAAATTATTGTTTTTTTCAATGCATATCAAAACAATGTTTACAATATACTACAGCCTAAGTGTGCAATAGCATTATGTGTAGAAATGCACATACCATAATTAGTTTTTTTTTTGAAAAAACTGTTAATGATTATCTGAGCCTTCAGTGAGTTGTAATCTTTTCATGGTGGAGGATCATACCTCTACGTTGATGTCAGCTGACTGATCAGGGTAGTAGTTGCTGAAGGCTTGGGTGGCTGTGGCAATTTCTTAAAATAGGATAACAATGGCATTTACCACATTAATTGACTCCTTCTTTCACAAAAGATTTCTCTGTCTCATGCAATGCTGTTTGACAGCATTTTCCCCACAGTAGAATTTCTTTAAAAATTGG", "109M249D10M") ) << ss.str().c_str(); 00197 00198 EXPECT_TRUE( verifyAlign("CCAGACTATCTCAAGCAATCAACAGATTTAATGTAAGGAGTGTCAAAATCTGAATGATGCTTTTTGCAGAAATAGAAAATCCCTTTCTAATATTTTTATATTTTTGAC","TTATCGAGGCTGGCGGATTTTGTGAGGCCAGGAGTTCAAGACCAGCCTGGCCAACATGGCAAAACTCTGTCTCTACTAAAAATACAAAAGTTAGCTGGGCATAGTGGCACATGTCTATAGTTCTAGCTATGTGGGAGGCTGAGACACGAGAATCGCTTGAACCCAGGAGGTGGAGGTTGTGGTGAGCCGAGCTCACGCCATTGCTCTCCAGCCTGGGCAACAGAGCAAGACTGTCTCAAAAACAAAAACAAAAAACACAAAAACTACAAGACTTTTATGAAATAACTTAAGGAAGATATAAATAAATGGAAAGATATCCCATGTTCCTGACTTGGAAGACTTAATTTTGTTAAGATGTCCATACTATCTCAAGCAATCAACAGATTTAATGTAAGGAGTGTCAAAATCTGAATGATGCTTTTTGCAGAAATAGAAAATCCCTTTCTAATATTTTTATGTAATCTCAAGGGACCCCAAATAGCCAAAAGAATCCTGAAAAAGTAGAATAAAGCTGGAGGACTCATGATTCCTGATTTGAAAACTTACTACCAGATACAATAATCAAAACAGTTCCGTGCTTGTCATAAAGACAAACATATAGACCAATGGAACAGAATAGAGATTACAGGGACAAATCCTCATATATATGGTCAAATGATTTTTGACCAGTGCCAAGATCATTCATGGGTGAAAAGACAATCTTTTCAATAAAAGAT", "99M200D9M") ) << ss.str().c_str(); 00199 00200 // this is by no mean works, since our local aligner generates the output 00201 // 54M200D34M47D8M7D2M1I5M4S , since local aligner prefer gapped alignment. 00202 EXPECT_FALSE( verifyAlign("ATGAGGTCAGGAGATGGAGACCATCCTGGCTAACATGGTGAAACCCCATCTCTAAAAAAAGTGTAACAGAGGTGCATACTCAAAACTACAAAAGTCTCGTGAAAGGAA","CAAGAAAAAGAAATAAAATACATTTTAGTAGGAAAGGAAGAAGTTAAATTGTCTCCATTTGGTGACAACATGAGCTTATATGCAGAAAACCTAAAGACTCTACCAAAAAAACTGCTGGAACTGATAAATGAATTCGGTGAAGTCCTAGGGTATAAAATCAATGTACAAAATAAGTGGTGTTTCTATATTCTAATAAATTATTCAAAAGGGAAATTAAGAAATCAATCCCATTTTCAATAGCAACAACAAAAAAAATGACAATGCCAAAGTATAAATTTAACCAAGAAGCTACAAGAGTCTGGGCGCAGTGGCTTATGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGTGGATCATGAGGTCAGGAGATGGAGACCATCCTGGCTAACATGGTGAAACCCCATCTCTACTAAAAAAAAATAATAATAATAATAATAATAATAATAATTAGCCGGGCGTGGTGGTAGGCATCTGTAGTCCCAGCTACTCGGGAGGCTGAGGTAGGAGAATGGCATGAACCTGGGAGGTGGAGCTTGCAGTGAGCAGAGATCACACCCCTGCACTCCAGCCTGGGTGACAGGGCGAGACTCCGTCTCAAAAAAAAAAAAAAAAAAAGTGTAACAGAGTTGCATACTGAAAACTATAAAATTCTGATGAAAGAAAATGAAGCAACAAATAATTAATATAATAAAAAAGTCCATACTATCCAAAAT", "54M200D54M") ) << ss.str().c_str(); 00203 00204 } 00205 00206 #if 0 00207 // 00208 // In this test case, there is no indel that I am aware of, however, the 00209 // aligner produces quite a long cigar string with many insertions 00210 // and deletions. For now, I filter this case out later, but it would 00211 // be nice if it would limit itself to one or a small number of indels. 00212 // 00213 EXPECT_TRUE( verifyAlign("GAATCAATACGCTCGGGATGCAGCGCCTAGCCGTTGGTTTGAGAATGGTTCTCTAGAGTTATCTTCACCCTCTACCTTGTGTGGCACTATTTCTTCTATGACCTTGAC","TGGCTCAAGACCTGACCTTGTGCACGTCTTGGATGCCAGTTCTATTCCCCTCACAGGCCATATGAATCCTGTCCTTTCTGCCTCAAAATGCCCATCCAGAGCCTCTACATTGATTAGCTTTTCCCTCCCTTCCAGAAAAGTTCAAAGGCTACCTCCTCCTTGAAGCCTTCACAAATACCTTAATCTAACTGTTTATAACCCTCTGCCATCTTAGCACTGTGGAAAATACATAAACTTGGGGTTAGAACATCATCAGTTTTAATGTAAGCACCATCCTTTCTAGCTGTACAGCCCTCCTGAGCCTTAGTTCTTACATCTTGAAGATGGAACCAGCTCAACAAGCATAGGGATGTAGCAAGAATCAAGACACTGTAGATGCAGCACCTGGCCGGTGGTAAGAGCTTGGTTATCACAAGTTATCTTCACCCTCTACCTTGTGTGGCACTATTTCTTCTATGACCTTGACTGCTCTCTGCTCTGATCTGGAAGTTCGCTGGGAAAAGGTGTCCCCTTTTTTATTACCTACCGGGAGAACCATGAGTGATGCTCTACTTGTAGTATATATACCCTGAGATGATTATTCTTAAAGACTAGTTCTCATGACTTGAGAGTTTGCTCTGTGTTAGGTACCATTCTAACACTGGATGTTGACTATGTATGTTATTTAATACTTCCATCAACCCCATAATGTAGGGAGAATCATTATGCCCATTTTA", "108M") ) << ss.str().c_str(); 00214 #endif 00215 00216 00217 TEST(GreedyTupleTestAligner, EquivalentAlignment) { 00218 std::stringstream ss(std::stringstream::out); 00219 // The test cases here are different to what we expected, 00220 // but hte alignment are both valid. See the example: 00221 // ref: AAAT TGGGG (4M5D5M) 00222 // ref: AAA TTGGGG (3M5D6M) 00223 // read: AAAT CCCC TTGGGG 00224 00225 // We obtain 89M200D19M, the correct is 87M200D21M, 00226 // the 2 matched bases shifted to the right 00227 // if you check the output, you will see the 2 bases can be put before '200D' or after '200D' 00228 // and they are essentially the same 00229 EXPECT_FALSE( verifyAlign("TTTTCTTTTCAAAAATTTAAAAGTGACATACAAAATTATATGTGTATGTACAACAAAAGCTTAACTATAACACCTTGTTACATACTTTGGAATTGAAAGGCAGGAATG","CAGCACCCTAATTCACTATGCCCTAAGCTTCAAGGGCTTCAGAGTAAGCTCTCAGTGGAGTCTGATTGGAATCCCTCTTCGCCAGCTTGTGAGGTATGGGGCTAGGTTCCACAATATTCCCTTTGAGGGAGTAGATCTTCCAGCCTTCTGGGGCATGCTCTGAAAGTCCTCTTTGCAGAAGTAGCTCTTTAAAATCATATTCTCTTTCCAATTTGACCTCTTTTTTTATCCTTGTTCTGTCCATGCTGTCCAAAGCATCTTGGACTAAGTTTTGACTTTTTTTTTAAGTGCTGCATTTCCATTTGACATTTTACCTTTGTAAATTTCTATTTTTTTACCTTTGTGACTTATTAAAATATTTTCTTTTCAAAAATTTAAAAGTGACATACAAAATTATATGTGTATGTACAACAAAAGCTTAACTATAACACCTTGTTACATACTTTGCTATCCAGGCCACTGATCCTTTCTTACATAGTAAGTCAGCTATAGTTCATTAGCTTACAGTTTTTAGATACAAGTCTTAATCCATCCCTTCTCCTTTTGTATTCTTTACTTTCTGCAATATTTAAGACTTTTTGCGTTCTGACTAAAAGAAACCACCTGAAATTGGCATATGCAACTGTTCATGAATGAGAACTCGCATGGAATTGAAAGGCAGGAATGCAGCTTGACCTTAGAATGGATTTGATCCAGGAACTAGAAGGTGGGTAGGA", "87M200D21M") ) << ss.str().c_str(); 00230 00231 // for the same reason as before 00232 EXPECT_FALSE( verifyAlign("AACAGTTGAGAGGTACTAAAATTGAGTTTTCTTGAAAAATATATTTAATCTAAAGTACTGAAAATTTGGGGGAAAATGCTTAAGGTCATATTCCTTTTTTGAAAAGAT","TCATCTTTCTCCCATACTGGCTGTTTCCTGCCCTCAAACACTGGACTCCAAGTTCTTCAGCTTGTGGACTCTTGGACCTACAACCAGTGGTCTGCCAGGGCCCTTTGGGCCTTCGGCCACAGACTGATGGCTACACTGTCGGCTCCCCTACTTTTGAGGTTTTGTGTCTTGGACTGGCTTTCTTGCTCCTCAGCTTGCAGACAGCCTACTGTAGGACTTCACTTTGTGACTATTTGAGTCAATACTCCTTAATAAACACCCTTTCATATATACATATATCCTATTAGTCCTGTTCCTCTAGAGAACCCTAATACAGTGTTGTACATTGAAATAAATATAATTATTCTGGTTTTGGTTGAACAGTTGAGAGGTACTAAAATTGAGTTTTCTTGAAAAATATATTTAATCTAAAGTACTGAAAATTTGGGGGAAAATGCTTCTGTAAATCCTAAGTTATTATTTCTTCAACTATATTCTGTAGTTAATTTCTCCAGCAATTCTTAATTTCAGCACAAATTAGCCACTGTTTGAATTAGGAATACTGAATCGTCTCCATTGCAGTGCAGTTAATAAGTCATTTCTTGATGAAGTAGTCCATGTAGGACTTGAAATCTTGTCTTTTTCATGATACATTATCATAAGGTCATATTCCTTTTTTGAAAAGATTGATGATACTATTCTGAAAGACACTAGTAGAGTTAGGCTTGGTTTTATGA", "80M200D28M") ) << ss.str().c_str(); 00233 00234 } 00235