1 /** 2 Defines bindings and utilities to/for the dazzler commands. 3 4 Copyright: © 2018 Arne Ludwig <arne.ludwig@posteo.de> 5 License: Subject to the terms of the MIT license, as written in the 6 included LICENSE file. 7 Authors: Arne Ludwig <arne.ludwig@posteo.de> 8 */ 9 module dentist.dazzler; 10 11 import core.memory : GC; 12 import dentist.common : ReferenceInterval, ReferenceRegion; 13 import dentist.common.alignments : AlignmentChain, coord_t, diff_t, id_t, trace_point_t; 14 import dentist.common.binio : CompressedSequence; 15 import dentist.util.algorithm : sliceUntil; 16 import dentist.util.fasta : parseFastaRecord, reverseComplement; 17 import dentist.util.log; 18 import dentist.util.math : absdiff, floor, ceil, RoundingMode; 19 import dentist.util.range : arrayChunks, takeExactly; 20 import dentist.util.region : findTilings, min, sup; 21 import dentist.util..string : 22 EditOp, 23 findAlignment, 24 longestInputsLength, 25 memoryRequired, 26 score_t, 27 SequenceAlignment; 28 import dentist.util.tempfile : mkstemp; 29 import std.algorithm : 30 all, 31 among, 32 cache, 33 canFind, 34 copy, 35 countUntil, 36 cumulativeFold, 37 endsWith, 38 filter, 39 find, 40 isSorted, 41 joiner, 42 map, 43 max, 44 maxElement, 45 min, 46 minElement, 47 remove, 48 sort, 49 splitter, 50 startsWith, 51 sum, 52 SwapStrategy, 53 uniq, 54 until; 55 import std.array : appender, Appender, array, uninitializedArray; 56 import std.conv : to; 57 import std.exception : enforce; 58 import std.file : exists, remove; 59 import std.format : format, formattedRead; 60 import std.meta : AliasSeq; 61 import std.path : 62 absolutePath, 63 baseName, 64 buildPath, 65 dirName, 66 relativePath, 67 stripExtension, 68 withExtension; 69 import std.process : Config, escapeShellCommand, kill, pipeProcess, 70 ProcessPipes, Redirect, wait; 71 import std.range : 72 chain, 73 chunks, 74 drop, 75 enumerate, 76 generate, 77 only, 78 repeat, 79 slide, 80 takeExactly, 81 zip; 82 import std.range.primitives : 83 ElementType, 84 empty, 85 front, 86 isForwardRange, 87 isInputRange, 88 popFront, 89 save, 90 walkLength; 91 import std.stdio : File; 92 import std..string : lineSplitter, outdent; 93 import std.traits : isArray, isIntegral, isSomeString, ReturnType, Unqual; 94 import std.typecons : Flag, No, tuple, Tuple, Yes; 95 import std.variant : Algebraic; 96 import vibe.data.json : Json, toJson = serializeToJson; 97 98 debug import std.stdio : writeln; 99 100 /// File suffixes of hidden .db files. 101 private enum hiddenDbFileSuffixes = [".bps", ".idx"]; 102 103 /// File suffixes of hidden .dam files. 104 private enum hiddenDamFileSuffixes = [".bps", ".hdr", ".idx"]; 105 106 /// Constant holding the .db file extension. 107 enum dbFileExtension = ".db"; 108 109 /// Constant holding the .dam file extension. 110 enum damFileExtension = ".dam"; 111 112 /// The Dazzler tools require sequence of a least minSequenceLength base pairs. 113 enum minSequenceLength = 14; 114 115 enum isOptionsList(T) = isArray!T && isSomeString!(ElementType!T); 116 117 /** 118 Return a list of hidden files associated to every `.dam`/`.db` file. These 119 files contain the actual data used in all the computation. Thus, we 120 carefully check for their existence. 121 */ 122 auto getHiddenDbFiles(string dbFile) 123 { 124 import std.algorithm : map; 125 126 assert(dbFile.endsWith(dbFileExtension, damFileExtension), "must use with Dazzler DB"); 127 auto suffixes = dbFile.endsWith(dbFileExtension) 128 ? hiddenDbFileSuffixes 129 : hiddenDamFileSuffixes; 130 131 return suffixes.map!(suffix => buildPath(dbFile.dirName, 132 "." ~ dbFile.baseName.withExtension(suffix).to!string)); 133 } 134 135 class DazzlerCommandException : Exception 136 { 137 pure nothrow @nogc @safe this(string msg, string file = __FILE__, 138 size_t line = __LINE__, Throwable nextInChain = null) 139 { 140 super(msg, file, line, nextInChain); 141 } 142 } 143 144 /// Determines how data should be provided in the working directory. 145 enum ProvideMethod 146 { 147 copy, 148 symlink, 149 } 150 enum provideMethods = __traits(allMembers, ProvideMethod); 151 152 /** 153 Provide dbFile in `workdir`. 154 155 Returns: Path of the dbFile in `workdir`. 156 */ 157 string provideDamFileInWorkdir(in string dbFile, ProvideMethod provideMethod, in string workdir) 158 { 159 foreach (hiddenDbFile; getHiddenDbFiles(dbFile)) 160 { 161 provideFileInWorkdir(hiddenDbFile, provideMethod, workdir); 162 } 163 164 return provideFileInWorkdir(dbFile, provideMethod, workdir); 165 } 166 167 /** 168 Provide lasFile in `workdir`. 169 170 Returns: Path of the lasFile in `workdir`. 171 */ 172 string provideLasFileInWorkdir(in string lasFile, ProvideMethod provideMethod, in string workdir) 173 { 174 return provideFileInWorkdir(lasFile, provideMethod, workdir); 175 } 176 177 /// Provide file in `workdir`. 178 string provideFileInWorkdir(in string file, ProvideMethod provideMethod, in string workdir) 179 { 180 import std.file : copy, symlink; 181 import std.path : absolutePath; 182 183 auto fileInWorkdir = buildPath(workdir, file.baseName); 184 185 final switch (provideMethod) 186 { 187 case ProvideMethod.copy: 188 copy(file.absolutePath, fileInWorkdir); 189 break; 190 case ProvideMethod.symlink: 191 symlink(file.absolutePath, fileInWorkdir); 192 break; 193 } 194 195 return fileInWorkdir; 196 } 197 198 /// Returns true iff lasFile contains zero parts. 199 bool lasEmpty(in string lasFile, in string dbA, in string workdir) 200 { 201 return lasEmpty(lasFile, dbA, null, workdir); 202 } 203 204 /// ditto 205 bool lasEmpty(in string lasFile, in string dbA, in string dbB, in string workdir) 206 { 207 auto dumpHeader = ladump(lasFile, dbA, dbB, [], workdir); 208 209 if (dumpHeader.empty) 210 { 211 return true; 212 } 213 214 size_t numParts; 215 216 dumpHeader.front.formattedRead!"+ P %d"(numParts); 217 218 return numParts == 0; 219 } 220 221 /// Build a new .dam file by using the given subset of reads in inDbFile. 222 string dbSubset(Options, R)(in string inDbFile, R readIds, in Options options) 223 if (isSomeString!(typeof(options.workdir)) && 224 isOptionsList!(typeof(options.dbsplitOptions))) 225 { 226 enum outDbNameTemplate = "subset-XXXXXX"; 227 228 auto outDbTemplate = buildPath(options.workdir, outDbNameTemplate); 229 auto outDb = mkstemp(outDbTemplate, damFileExtension); 230 231 outDb.file.close(); 232 remove(outDb.name); 233 buildSubsetDb(inDbFile, outDb.name, readIds, options.workdir); 234 dbsplit(outDb.name, options.dbsplitOptions, options.workdir); 235 236 return outDb.name; 237 } 238 239 AlignmentChain[] getLocalAlignments(Options)(in string dbA, in Options options) 240 if (isOptionsList!(typeof(options.dalignerOptions)) && 241 isOptionsList!(typeof(options.ladumpOptions)) && 242 isSomeString!(typeof(options.workdir))) 243 { 244 if (!lasFileGenerated(dbA, options.workdir)) 245 { 246 dalign(dbA, options.dalignerOptions, options.workdir); 247 } 248 249 return getGeneratedAlignments(dbA, null, options); 250 } 251 252 AlignmentChain[] getLocalAlignments(Options)(in string dbA, in string dbB, in Options options) 253 if (isOptionsList!(typeof(options.dalignerOptions)) && 254 isOptionsList!(typeof(options.ladumpOptions)) && 255 isSomeString!(typeof(options.workdir))) 256 { 257 if (!lasFileGenerated(dbA, dbB, options.workdir)) 258 { 259 dalign(dbA, dbB, options.dalignerOptions, options.workdir); 260 } 261 262 return getGeneratedAlignments(dbA, dbB, options); 263 } 264 265 void computeLocalAlignments(Options)(in string[] dbList, in Options options) 266 if (isOptionsList!(typeof(options.dalignerOptions)) && 267 isSomeString!(typeof(options.workdir))) 268 { 269 dalign(dbList, options.dalignerOptions, options.workdir); 270 } 271 272 AlignmentChain[] getMappings(Options)(in string dbA, in string dbB, in Options options) 273 if (isOptionsList!(typeof(options.damapperOptions)) && 274 isOptionsList!(typeof(options.ladumpOptions)) && 275 isSomeString!(typeof(options.workdir))) 276 { 277 if (!lasFileGenerated(dbA, dbB, options.workdir)) 278 { 279 damapper(dbA, dbB, options.damapperOptions, options.workdir); 280 } 281 282 return getGeneratedAlignments(dbA, dbB, options); 283 } 284 285 void computeMappings(Options)(in string[] dbList, in Options options) 286 if (isOptionsList!(typeof(options.damapperOptions)) && 287 isOptionsList!(typeof(options.ladumpOptions)) && 288 isSomeString!(typeof(options.workdir))) 289 { 290 damapper(dbList, options.damapperOptions, options.workdir); 291 } 292 293 private AlignmentChain[] getGeneratedAlignments(Options)( 294 in string dbA, 295 in string dbB, 296 in Options options 297 ) 298 if (isOptionsList!(typeof(options.ladumpOptions)) && 299 isSomeString!(typeof(options.workdir))) 300 { 301 auto lasFile = getLasFile(dbA, dbB, options.workdir); 302 303 return getAlignments(dbA, dbB, lasFile, options); 304 } 305 306 AlignmentChain[] getAlignments( 307 in string dbA, 308 in string lasFile, 309 in string workdir, 310 in trace_point_t tracePointDistance = 0, 311 ) 312 { 313 return getAlignments(dbA, null, lasFile, workdir, tracePointDistance); 314 } 315 316 AlignmentChain[] getAlignments( 317 in string dbA, 318 in string dbB, 319 in string lasFile, 320 in string workdir, 321 in trace_point_t tracePointDistance = 0, 322 ) 323 { 324 string[] ladumpOptions = [ 325 LAdumpOptions.coordinates, 326 LAdumpOptions.numDiffs, 327 LAdumpOptions.lengths, 328 ]; 329 330 if (tracePointDistance > 0) 331 ladumpOptions ~= LAdumpOptions.tracePoints; 332 333 auto alignmentChains = readLasDump(ladump( 334 lasFile, 335 dbA, 336 dbB, 337 ladumpOptions, 338 workdir, 339 )).array; 340 alignmentChains.sort!("a < b", SwapStrategy.stable); 341 342 if (tracePointDistance > 0) 343 foreach (ref alignmentChain; alignmentChains) 344 alignmentChain.tracePointDistance = tracePointDistance; 345 346 return alignmentChains; 347 } 348 349 void attachTracePoints( 350 AlignmentChain*[] alignmentChains, 351 in string dbA, 352 in string dbB, 353 in string lasFile, 354 in trace_point_t tracePointDistance, 355 in string workdir 356 ) 357 { 358 static enum ladumpOptions = [ 359 LAdumpOptions.coordinates, 360 LAdumpOptions.tracePoints, 361 ]; 362 363 // NOTE: dump only for matching A reads; better would be for matching 364 // B reads but that is not possible with `LAdump`. 365 auto aReadIds = alignmentChains.map!"a.contigA.id".uniq.array; 366 auto acsWithTracePoints = readLasDump(ladump( 367 lasFile, 368 dbA, 369 dbB, 370 aReadIds, 371 ladumpOptions, 372 workdir, 373 )).array; 374 acsWithTracePoints.sort!"a < b"; 375 assert(isSorted!"*a < *b"(alignmentChains), "alignmentChains must be sorted"); 376 377 auto numAttached = alignmentChains.attachTracePoints(acsWithTracePoints, tracePointDistance); 378 assert(numAttached == alignmentChains.length, 379 "missing trace point lists for some alignment chains"); 380 381 debug logJsonDebug("acsWithTracePoints", acsWithTracePoints.toJson); 382 version (assert) 383 { 384 // ensure all alignment chains are valid... 385 foreach (alignmentChain; alignmentChains) 386 { 387 // trigger invariant of AlignmentChain 388 cast(void) alignmentChain.first; 389 } 390 } 391 } 392 393 auto fingerprint(in AlignmentChain* alignmentChain) pure nothrow 394 { 395 return tuple( 396 alignmentChain.contigA.id, 397 alignmentChain.contigB.id, 398 alignmentChain.first.contigA.begin + 0, 399 alignmentChain.first.contigB.begin + 0, 400 alignmentChain.last.contigA.end + 0, 401 alignmentChain.last.contigB.end + 0, 402 ); 403 } 404 405 private id_t attachTracePoints(AlignmentChain*[] alignmentChains, 406 ref AlignmentChain[] acsWithTracePoints, in trace_point_t tracePointDistance) pure 407 { 408 assert(tracePointDistance > 0); 409 410 id_t numAlignmentChainsAffected = 0; 411 id_t numLoops = 0; 412 id_t i = 0; 413 id_t j = 0; 414 415 while (i < alignmentChains.length && j < acsWithTracePoints.length 416 && numLoops < alignmentChains.length + acsWithTracePoints.length) 417 { 418 auto alignmentChain = alignmentChains[i]; 419 auto acWithTracePoints = &acsWithTracePoints[j]; 420 auto acFingerprint = alignmentChain.fingerprint; 421 auto tpFingerprint = acWithTracePoints.fingerprint; 422 423 debug logJsonDebug( 424 "acFingerprint", acFingerprint.toJson, 425 "tpFingerprint", tpFingerprint.toJson, 426 ); 427 428 if (acFingerprint == tpFingerprint) 429 { 430 foreach (k, ref localAlignment; alignmentChain.localAlignments) 431 { 432 localAlignment.tracePoints = acWithTracePoints.localAlignments[k].tracePoints; 433 } 434 alignmentChain.tracePointDistance = tracePointDistance; 435 numAlignmentChainsAffected = i + 1; 436 ++i; 437 } 438 else if (tpFingerprint < acFingerprint) 439 { 440 ++j; 441 } 442 else 443 { 444 assert(tpFingerprint > acFingerprint); 445 throw new Exception( 446 format!"missing trace point data for alignment chain: %s"(*alignmentChain)); 447 } 448 449 ++numLoops; 450 } 451 452 return numAlignmentChainsAffected; 453 } 454 455 unittest 456 { 457 with (AlignmentChain) with (LocalAlignment) 458 { 459 auto alignmentChains = [ 460 new AlignmentChain( 461 1, 462 Contig(1, 1337), 463 Contig(1, 307), 464 emptyFlags, 465 [ 466 LocalAlignment(Locus(0, 1337), Locus(0, 307), 1), 467 ], 468 ), 469 new AlignmentChain( 470 2, 471 Contig(1, 1338), 472 Contig(1, 309), 473 emptyFlags, 474 [ 475 LocalAlignment(Locus(0, 1338), Locus(0, 309), 2), 476 ], 477 ), 478 new AlignmentChain( 479 3, 480 Contig(1, 1340), 481 Contig(3, 508), 482 emptyFlags, 483 [ 484 LocalAlignment(Locus(0, 1339), Locus(0, 403), 3), 485 LocalAlignment(Locus(0, 1340), Locus(404, 508), 4), 486 ], 487 ), 488 ]; 489 auto acsWithTracePoints = [ 490 AlignmentChain( 491 1, 492 Contig(1, 1337), 493 Contig(1, 307), 494 emptyFlags, 495 [ 496 LocalAlignment(Locus(0, 1337), Locus(0, 307), 0, [ 497 TracePoint(1, 102), 498 TracePoint(2, 101), 499 TracePoint(3, 104), 500 ]), 501 ], 502 101 503 ), 504 AlignmentChain( 505 2, 506 Contig(1, 1338), 507 Contig(1, 309), 508 emptyFlags, 509 [ 510 LocalAlignment(Locus(0, 1338), Locus(0, 309), 0, [ 511 TracePoint(4, 103), 512 TracePoint(5, 104), 513 TracePoint(6, 102), 514 ]), 515 ], 516 101 517 ), 518 AlignmentChain( 519 3, 520 Contig(1, 1340), 521 Contig(3, 508), 522 emptyFlags, 523 [ 524 LocalAlignment(Locus(0, 1339), Locus(0, 403), 0, [ 525 TracePoint(7, 105), 526 TracePoint(8, 101), 527 TracePoint(9, 100), 528 TracePoint(10, 97), 529 ]), 530 LocalAlignment(Locus(0, 1340), Locus(404, 508), 0, [ 531 TracePoint(11, 2), 532 TracePoint(12, 102), 533 ]), 534 ], 535 101 536 ), 537 ]; 538 auto expectedAlignmentChains = [ 539 AlignmentChain( 540 1, 541 Contig(1, 1337), 542 Contig(1, 307), 543 emptyFlags, 544 [ 545 LocalAlignment(Locus(0, 1337), Locus(0, 307), 1, [ 546 TracePoint(1, 102), 547 TracePoint(2, 101), 548 TracePoint(3, 104), 549 ]), 550 ], 551 101 552 ), 553 AlignmentChain( 554 2, 555 Contig(1, 1338), 556 Contig(1, 309), 557 emptyFlags, 558 [ 559 LocalAlignment(Locus(0, 1338), Locus(0, 309), 2, [ 560 TracePoint(4, 103), 561 TracePoint(5, 104), 562 TracePoint(6, 102), 563 ]), 564 ], 565 101 566 ), 567 AlignmentChain( 568 3, 569 Contig(1, 1340), 570 Contig(3, 508), 571 emptyFlags, 572 [ 573 LocalAlignment(Locus(0, 1339), Locus(0, 403), 3, [ 574 TracePoint(7, 105), 575 TracePoint(8, 101), 576 TracePoint(9, 100), 577 TracePoint(10, 97), 578 ]), 579 LocalAlignment(Locus(0, 1340), Locus(404, 508), 4, [ 580 TracePoint(11, 2), 581 TracePoint(12, 102), 582 ]), 583 ], 584 101 585 ), 586 ]; 587 588 assert(alignmentChains.attachTracePoints(acsWithTracePoints, 101) == 3); 589 assert(alignmentChains.map!"*a".array == expectedAlignmentChains); 590 } 591 } 592 593 private struct LasDumpLineFormatTuple 594 { 595 char indicator; 596 char subIndicator; 597 string format; 598 } 599 600 private enum LasDumpLineFormat 601 { 602 totalChainPartsCount = LasDumpLineFormatTuple('+', 'P', "+ P %d"), 603 totalTracePointsCount = LasDumpLineFormatTuple('+', 'T', "+ T %d"), 604 maxChainPartsCountPerPile = LasDumpLineFormatTuple('%', 'P', "% P %d"), 605 maxTracePointsCountPerPile = LasDumpLineFormatTuple('%', 'T', "% T %d"), 606 maxTracePointCount = LasDumpLineFormatTuple('@', 'T', "@ T %d"), 607 chainPart = LasDumpLineFormatTuple('P', '\0', "P %d %d %c %c"), 608 lengths = LasDumpLineFormatTuple('L', '\0', "L %d %d"), 609 coordinates = LasDumpLineFormatTuple('C', '\0', "C %d %d %d %d"), 610 numDiffs = LasDumpLineFormatTuple('D', '\0', "D %d"), 611 tracePointBegin = LasDumpLineFormatTuple('T', '\0', "T %d"), 612 tracePoint = LasDumpLineFormatTuple(' ', '\0', " %d %d"), 613 } 614 615 private enum ChainPartType 616 { 617 start = '>', 618 continuation = '-', 619 alternateStart = '+', 620 noChainInFile = '.', 621 } 622 623 private struct LasDumpReader(S) if (isInputRange!S && isSomeString!(ElementType!S)) 624 { 625 static alias dstring = immutable(dchar)[]; 626 static alias LasDump = ReturnType!getDumpLines; 627 static alias LocalAlignment = AlignmentChain.LocalAlignment; 628 static alias TracePoint = LocalAlignment.TracePoint; 629 630 private: 631 LasDump lasDump; 632 bool _empty; 633 AlignmentChain currentAC; 634 id_t currentACID; 635 Appender!(LocalAlignment[]) localAlignmentsAcc; 636 Appender!(TracePoint[]) tracePointsAcc; 637 dstring currentDumpLine; 638 size_t currentDumpLineNumber; 639 dchar currentLineType; 640 dchar currentLineSubType; 641 size_t maxTracePointCount; 642 debug dchar[] allowedLineTypes; 643 644 public: 645 this(S lasDump) 646 { 647 this.lasDump = getDumpLines(lasDump); 648 debug with (LasDumpLineFormat) 649 { 650 this.allowedLineTypes = [ 651 totalChainPartsCount.indicator, 652 totalTracePointsCount.indicator, 653 maxChainPartsCountPerPile.indicator, 654 maxTracePointsCountPerPile.indicator, 655 maxTracePointCount.indicator, 656 chainPart.indicator, 657 ]; 658 } 659 this.popFront(); 660 } 661 662 void popFront() 663 { 664 assert(!empty, "Attempting to popFront an empty LasDumpReader"); 665 666 if (lasDump.empty) 667 { 668 return setEmpty(); 669 } 670 671 readNextAlignmentChain(); 672 } 673 674 @property bool empty() const pure nothrow 675 { 676 return _empty; 677 } 678 679 @property AlignmentChain front() pure nothrow 680 { 681 assert(!empty, "Attempting to fetch the front of an empty LasDumpReader"); 682 683 return currentAC; 684 } 685 686 private: 687 688 static auto getDumpLines(S lasDump) 689 { 690 return lasDump.enumerate(1).filter!"!a[1].empty"; 691 } 692 693 void setEmpty() pure nothrow 694 { 695 _empty = true; 696 } 697 698 void readNextAlignmentChain() 699 { 700 currentAC = AlignmentChain.init; 701 localAlignmentsAcc.clear(); 702 tracePointsAcc.clear(); 703 peekDumpLine(); 704 705 while (true) 706 { 707 debug _enforce(allowedLineTypes.canFind(currentLineType), format!"forbidden line type `%c`"(currentLineType)); 708 709 with (LasDumpLineFormat) 710 { 711 switch (currentLineType) 712 { 713 case totalChainPartsCount.indicator: goto case; 714 case maxChainPartsCountPerPile.indicator: 715 break; // ignore 716 case maxTracePointCount.indicator: 717 _enforce(currentLineSubType == maxTracePointCount.subIndicator, "expected `@ T` line"); 718 readMaxTracePointCount(); 719 debug disallowCurrentLineType(); 720 break; 721 case chainPart.indicator: 722 if (readChainPart() == No.wasDumpPartConsumed) 723 { 724 debug allowedLineTypes = [chainPart.indicator]; 725 726 return; // chain completed; stay on current dump line 727 } 728 else 729 { 730 debug allowedLineTypes = [ 731 chainPart.indicator, 732 lengths.indicator, 733 coordinates.indicator, 734 ]; 735 break; 736 } 737 case lengths.indicator: 738 readLengths(); 739 debug disallowCurrentLineType(); 740 break; 741 case coordinates.indicator: 742 readCoordinates(); 743 debug 744 { 745 disallowCurrentLineType(); 746 allowedLineTypes ~= [ 747 numDiffs.indicator, 748 tracePointBegin.indicator, 749 ]; 750 } 751 break; 752 case numDiffs.indicator: 753 readNumDiffs(); 754 debug disallowCurrentLineType(); 755 break; 756 case tracePointBegin.indicator: 757 readTracePointBegin(); 758 debug allowedLineTypes = [tracePoint.indicator]; 759 break; 760 case tracePoint.indicator: 761 readTracePoint(); 762 debug allowedLineTypes = [tracePoint.indicator, chainPart.indicator]; 763 break; 764 default: 765 error(format!"unknown line type `%c`"(currentLineType)); 766 } 767 } 768 769 if (popDumpLine() == Yes.empty) 770 { 771 finishCurrentAC(); 772 773 return; // EOF reached 774 } 775 } 776 } 777 778 void peekDumpLine() 779 { 780 auto currentLine = lasDump.front; 781 782 currentDumpLineNumber = currentLine[0]; 783 currentDumpLine = currentLine[1].array; 784 currentLineType = currentDumpLine[0]; 785 currentLineSubType = currentDumpLine.length >= 3 ? currentDumpLine[2] : '\0'; 786 } 787 788 Flag!"empty" popDumpLine() 789 { 790 if (lasDump.empty) 791 { 792 return Yes.empty; 793 } 794 795 lasDump.popFront(); 796 ++currentDumpLineNumber; 797 798 if (lasDump.empty) 799 { 800 return Yes.empty; 801 } 802 else 803 { 804 peekDumpLine(); 805 806 return No.empty; 807 } 808 } 809 810 void readMaxTracePointCount() 811 { 812 enum maxTracePointCountFormat = LasDumpLineFormat.maxTracePointCount.format; 813 814 currentDumpLine[].formattedRead!maxTracePointCountFormat(maxTracePointCount); 815 816 tracePointsAcc.reserve(maxTracePointCount); 817 } 818 819 Flag!"wasDumpPartConsumed" readChainPart() 820 { 821 enum chainPartFormat = LasDumpLineFormat.chainPart.format; 822 enum yesComplement = AlignmentChain.Flags(AlignmentChain.Flag.complement); 823 enum noComplement = AlignmentChain.emptyFlags; 824 id_t contigAID; 825 id_t contigBID; 826 char rawComplement; 827 char rawChainPartType; 828 829 currentDumpLine[].formattedRead!chainPartFormat( 830 contigAID, 831 contigBID, 832 rawComplement, 833 rawChainPartType, 834 ); 835 836 auto flags = rawComplement == 'c' ? yesComplement : noComplement; 837 auto chainPartType = rawChainPartType.to!ChainPartType; 838 auto startingNewChain = currentAC == AlignmentChain.init; 839 840 if (startingNewChain) 841 { 842 currentAC.contigA.id = contigAID; 843 currentAC.contigB.id = contigBID; 844 currentAC.flags = flags; 845 846 return Yes.wasDumpPartConsumed; 847 } 848 else if (isChainContinuation(contigAID, contigBID, chainPartType)) 849 { 850 _enforce(currentAC.flags == flags, "matching both strands in one alignment chain"); 851 finishCurrentLA(); 852 853 return Yes.wasDumpPartConsumed; 854 } 855 else 856 { 857 finishCurrentAC(); 858 859 return No.wasDumpPartConsumed; 860 } 861 862 } 863 864 bool isChainContinuation(in size_t contigAID, in size_t contigBID, in ChainPartType chainPartType) 865 { 866 return currentAC.contigA.id == contigAID && 867 currentAC.contigB.id == contigBID && 868 chainPartType == ChainPartType.continuation; 869 } 870 871 void finishCurrentLA() 872 { 873 assert(localAlignmentsAcc.data.length > 0); 874 875 localAlignmentsAcc.data[$ - 1].tracePoints = tracePointsAcc.data.dup; 876 } 877 878 void finishCurrentLAs() 879 { 880 if (localAlignmentsAcc.data.length > 0) 881 { 882 finishCurrentLA(); 883 } 884 885 currentAC.localAlignments = localAlignmentsAcc.data.dup; 886 } 887 888 void finishCurrentAC() 889 { 890 finishCurrentLAs(); 891 currentAC.id = currentACID++; 892 } 893 894 void readLengths() 895 { 896 enum lengthsFormat = LasDumpLineFormat.lengths.format; 897 898 currentDumpLine[].formattedRead!lengthsFormat( 899 currentAC.contigA.length, 900 currentAC.contigB.length, 901 ); 902 } 903 void readCoordinates() 904 { 905 enum coordinatesFormat = LasDumpLineFormat.coordinates.format; 906 LocalAlignment currentLA; 907 908 currentDumpLine[].formattedRead!coordinatesFormat( 909 currentLA.contigA.begin, 910 currentLA.contigA.end, 911 currentLA.contigB.begin, 912 currentLA.contigB.end, 913 ); 914 915 localAlignmentsAcc ~= currentLA; 916 } 917 918 void readNumDiffs() 919 { 920 enum numDiffsFormat = LasDumpLineFormat.numDiffs.format; 921 922 currentDumpLine[].formattedRead!numDiffsFormat( 923 localAlignmentsAcc.data[$ - 1].numDiffs, 924 ); 925 } 926 927 void readTracePointBegin() 928 { 929 enum tracePointBeginFormat = LasDumpLineFormat.tracePointBegin.format; 930 size_t numTracePoints; 931 932 currentDumpLine[].formattedRead!tracePointBeginFormat(numTracePoints); 933 934 tracePointsAcc.clear(); 935 tracePointsAcc.reserve(numTracePoints); 936 } 937 938 void readTracePoint() 939 { 940 enum tracePointFormat = LasDumpLineFormat.tracePoint.format; 941 TracePoint currentTP; 942 943 currentDumpLine[].formattedRead!tracePointFormat( 944 currentTP.numDiffs, 945 currentTP.numBasePairs, 946 ); 947 948 tracePointsAcc ~= currentTP; 949 } 950 951 debug void disallowCurrentLineType() { 952 allowedLineTypes = allowedLineTypes 953 .filter!(type => type != currentLineType) 954 .array; 955 } 956 957 void error(in string reason) 958 { 959 _enforce(false, reason); 960 } 961 962 void _enforce(bool condition, lazy string reason) 963 { 964 enforce!DazzlerCommandException(condition, format!"ill-formatted LAdump output: %s (line %d)"(reason, currentDumpLineNumber)); 965 } 966 } 967 968 private auto readLasDump(S)(S lasDump) 969 { 970 return LasDumpReader!S(lasDump); 971 } 972 973 unittest 974 { 975 import std.algorithm : equal; 976 977 enum testLasDump = [ 978 "+ P 9", 979 "% P 9", 980 "+ T 12", 981 "% T 12", 982 "@ T 4", 983 "P 1 2 n >", 984 "L 8 9", 985 "C 3 4 5 6", 986 "D 7", 987 "P 1 2 n -", 988 "L 8 9", 989 "C 12 13 14 15", 990 "D 16", 991 "P 19 20 c +", 992 "L 26 27", 993 "C 21 22 23 24", 994 "D 25", 995 "P 19 20 c -", 996 "L 26 27", 997 "C 30 31 32 33", 998 "D 34", 999 "T 1", 1000 " 0 1", 1001 "P 37 38 n .", 1002 "L 35 36", 1003 "C 39 40 41 42", 1004 "D 43", 1005 "P 46 47 c .", 1006 "L 53 54", 1007 "C 48 49 50 51", 1008 "D 52", 1009 "T 3", 1010 " 2 102", 1011 " 3 101", 1012 " 4 104", 1013 "P 46 47 n .", 1014 "L 53 54", 1015 "C 57 58 59 60", 1016 "D 61", 1017 "T 3", 1018 " 3 101", 1019 " 4 104", 1020 " 2 102", 1021 "P 64 65 c >", 1022 "L 71 72", 1023 "C 66 67 68 69", 1024 "D 70", 1025 "T 4", 1026 " 6 105", 1027 " 1 101", 1028 " 2 100", 1029 " 3 97", 1030 "P 55 56 c -", 1031 "L 80 81", 1032 "C 75 76 77 78", 1033 "D 79", 1034 "T 2", 1035 " 0 2", 1036 " 2 102", 1037 "P 1 3197 c >", 1038 "C 0 71 12 86", 1039 "T 1", 1040 " 3 74", 1041 "P 1 3197 c -", 1042 "C 0 8300 0 318", 1043 "T 3", 1044 " 6 105", 1045 " 9 108", 1046 " 7 105", 1047 ]; 1048 1049 with (AlignmentChain) with (Flag) with (LocalAlignment) 1050 { 1051 auto alignmentChains = readLasDump(testLasDump).array; 1052 auto expectedResult = [ 1053 AlignmentChain( 1054 0, 1055 Contig(1, 8), 1056 Contig(2, 9), 1057 emptyFlags, 1058 [ 1059 LocalAlignment( 1060 Locus(3, 4), 1061 Locus(5, 6), 1062 7, 1063 ), 1064 LocalAlignment( 1065 Locus(12, 13), 1066 Locus(14, 15), 1067 16, 1068 ), 1069 ], 1070 ), 1071 AlignmentChain( 1072 1, 1073 Contig(19, 26), 1074 Contig(20, 27), 1075 Flags(complement), 1076 [ 1077 LocalAlignment( 1078 Locus(21, 22), 1079 Locus(23, 24), 1080 25, 1081 ), 1082 LocalAlignment( 1083 Locus(30, 31), 1084 Locus(32, 33), 1085 34, 1086 [ 1087 TracePoint(0, 1), 1088 ] 1089 ), 1090 ], 1091 ), 1092 AlignmentChain( 1093 2, 1094 Contig(37, 35), 1095 Contig(38, 36), 1096 emptyFlags, 1097 [ 1098 LocalAlignment( 1099 Locus(39, 40), 1100 Locus(41, 42), 1101 43, 1102 ), 1103 ], 1104 ), 1105 AlignmentChain( 1106 3, 1107 Contig(46, 53), 1108 Contig(47, 54), 1109 Flags(complement), 1110 [ 1111 LocalAlignment( 1112 Locus(48, 49), 1113 Locus(50, 51), 1114 52, 1115 [ 1116 TracePoint(2, 102), 1117 TracePoint(3, 101), 1118 TracePoint(4, 104), 1119 ], 1120 ), 1121 ], 1122 ), 1123 AlignmentChain( 1124 4, 1125 Contig(46, 53), 1126 Contig(47, 54), 1127 emptyFlags, 1128 [ 1129 LocalAlignment( 1130 Locus(57, 58), 1131 Locus(59, 60), 1132 61, 1133 [ 1134 TracePoint(3, 101), 1135 TracePoint(4, 104), 1136 TracePoint(2, 102), 1137 ], 1138 ), 1139 ], 1140 ), 1141 AlignmentChain( 1142 5, 1143 Contig(64, 71), 1144 Contig(65, 72), 1145 Flags(complement), 1146 [ 1147 LocalAlignment( 1148 Locus(66, 67), 1149 Locus(68, 69), 1150 70, 1151 [ 1152 TracePoint(6, 105), 1153 TracePoint(1, 101), 1154 TracePoint(2, 100), 1155 TracePoint(3, 97), 1156 ], 1157 ), 1158 ], 1159 ), 1160 AlignmentChain( 1161 6, 1162 Contig(55, 80), 1163 Contig(56, 81), 1164 Flags(complement), 1165 [ 1166 LocalAlignment( 1167 Locus(75, 76), 1168 Locus(77, 78), 1169 79, 1170 [ 1171 TracePoint(0, 2), 1172 TracePoint(2, 102), 1173 ], 1174 ), 1175 ], 1176 ), 1177 AlignmentChain( 1178 7, 1179 Contig(1, 0), 1180 Contig(3197, 0), 1181 Flags(complement), 1182 [ 1183 LocalAlignment( 1184 Locus(0, 71), 1185 Locus(12, 86), 1186 0, 1187 [ 1188 TracePoint(3, 74), 1189 ], 1190 ), 1191 LocalAlignment( 1192 Locus(0, 8300), 1193 Locus(0, 318), 1194 0, 1195 [ 1196 TracePoint(6, 105), 1197 TracePoint(9, 108), 1198 TracePoint(7, 105), 1199 ], 1200 ), 1201 ], 1202 ), 1203 ]; 1204 1205 assert(alignmentChains == expectedResult); 1206 } 1207 } 1208 1209 trace_point_t getTracePointDistance(in string[] dazzlerOptions = []) pure 1210 { 1211 enum defaultTracePointDistance = 100; 1212 1213 foreach (option; dazzlerOptions) 1214 { 1215 if (option.startsWith(cast(const(string)) DalignerOptions.tracePointDistance)) 1216 { 1217 return option[2 .. $].to!trace_point_t; 1218 } 1219 } 1220 1221 return defaultTracePointDistance; 1222 } 1223 1224 unittest 1225 { 1226 with (DalignerOptions) 1227 { 1228 assert(getTracePointDistance([]) == 100); 1229 assert(getTracePointDistance([identity]) == 100); 1230 assert(getTracePointDistance([ 1231 tracePointDistance ~ "42", 1232 averageCorrelationRate ~ ".8", 1233 identity, 1234 ]) == 42); 1235 assert(getTracePointDistance([ 1236 identity, 1237 tracePointDistance ~ "42", 1238 averageCorrelationRate ~ ".8", 1239 ]) == 42); 1240 assert(getTracePointDistance([ 1241 averageCorrelationRate ~ ".8", 1242 identity, 1243 tracePointDistance ~ "42", 1244 ]) == 42); 1245 } 1246 } 1247 1248 auto getExactAlignment( 1249 in string dbA, 1250 in string dbB, 1251 in AlignmentChain ac, 1252 in string workdir, 1253 in size_t memoryLimit = 2^^20, 1254 ) 1255 { 1256 return getExactAlignment( 1257 dbA, 1258 dbB, 1259 ac, 1260 ac.first.contigA.begin, 1261 ac.last.contigA.end, 1262 workdir, 1263 memoryLimit, 1264 ); 1265 } 1266 1267 auto getExactAlignment( 1268 in string dbA, 1269 in string dbB, 1270 in AlignmentChain ac, 1271 in coord_t beginA, 1272 in coord_t endA, 1273 in string workdir, 1274 in size_t memoryLimit = 2^^20, 1275 ) 1276 { 1277 assert(ac.tracePointDistance > 0, "trace points required for getExactAlignment"); 1278 assert( 1279 ac.first.contigA.begin <= beginA && 1280 beginA < endA && 1281 endA <= ac.last.contigA.end 1282 ); 1283 1284 // Translate input coords to tracepoints to get exact alignments 1285 auto begin = ac.translateTracePoint(beginA, RoundingMode.floor); 1286 auto end = ac.translateTracePoint(endA, RoundingMode.ceil); 1287 1288 // Fetch relevant sequences from DBs 1289 auto aSequence = getFastaSequence(dbA, ac.contigA.id, workdir); 1290 auto bSequence = getFastaSequence(dbB, ac.contigB.id, workdir); 1291 1292 // Slice sequences to translated coordinates 1293 aSequence = aSequence[begin.contigA .. end.contigA]; 1294 if (ac.flags.complement) 1295 bSequence = reverseComplement(bSequence[$ - end.contigB .. $ - begin.contigB]); 1296 else 1297 bSequence = bSequence[begin.contigB .. end.contigB]; 1298 1299 auto paddedAlignment = getPaddedAlignment( 1300 ac, 1301 begin, 1302 end, 1303 aSequence, 1304 bSequence, 1305 memoryLimit, 1306 ); 1307 1308 assert(begin.contigA <= beginA); 1309 1310 return paddedAlignment[(beginA - begin.contigA) .. min(endA - begin.contigA, $)]; 1311 } 1312 1313 auto getPaddedAlignment(S, TranslatedTracePoint)( 1314 in AlignmentChain ac, 1315 in TranslatedTracePoint begin, 1316 in TranslatedTracePoint end, 1317 S aSequence, 1318 S bSequence, 1319 in size_t memoryLimit = 2^^20, 1320 ) 1321 { 1322 static struct AlignmentPadder 1323 { 1324 static enum indelPenalty = 1; 1325 1326 alias LocalAlignment = AlignmentChain.LocalAlignment; 1327 1328 private const AlignmentChain ac; 1329 private const TranslatedTracePoint begin; 1330 private const TranslatedTracePoint end; 1331 private S aSequence; 1332 private S bSequence; 1333 private const size_t memoryLimit; 1334 private SequenceAlignment!S _paddedAlignment; 1335 1336 this( 1337 in AlignmentChain ac, 1338 in TranslatedTracePoint begin, 1339 in TranslatedTracePoint end, 1340 S aSequence, 1341 S bSequence, 1342 in size_t memoryLimit = 2^^20, 1343 ) 1344 { 1345 this.ac = ac; 1346 this.begin = begin; 1347 this.end = end; 1348 this.aSequence = aSequence; 1349 this.bSequence = bSequence; 1350 this.memoryLimit = memoryLimit; 1351 this._paddedAlignment = typeof(this._paddedAlignment)( 1352 0, 1353 [], 1354 aSequence[0 .. 0], 1355 bSequence[0 .. 0], 1356 indelPenalty, 1357 No.freeShift, 1358 ); 1359 this._paddedAlignment.editPath.reserve(aSequence.length + bSequence.length); 1360 } 1361 1362 @property auto paddedAlignment() 1363 { 1364 if (_paddedAlignment.editPath.length == 0) 1365 computePaddedAlignment(); 1366 1367 return _paddedAlignment; 1368 } 1369 1370 private: 1371 1372 coord_t aSeqPos; 1373 coord_t bSeqPos; 1374 1375 void computePaddedAlignment() 1376 { 1377 aSeqPos = begin.contigA + 0; 1378 bSeqPos = begin.contigB + 0; 1379 auto cleanedLocalAlignments = cleanUpLocalAlignments(ac.localAlignments); 1380 auto coveringLocalAlignments = cleanedLocalAlignments 1381 .find!(la => la.contigA.begin <= begin.contigA) 1382 .sliceUntil!(la => end.contigA < la.contigA.begin); 1383 assert(!coveringLocalAlignments.empty); 1384 1385 foreach (i, localAlignment; coveringLocalAlignments.enumerate) 1386 { 1387 if (i > 0) 1388 { 1389 if ( 1390 aSeqPos <= localAlignment.contigA.begin && 1391 bSeqPos <= localAlignment.contigB.begin 1392 ) 1393 addGapAlignment(localAlignment); 1394 else 1395 resolveOverlappingAlignments( 1396 coveringLocalAlignments[i - 1], 1397 localAlignment, 1398 ); 1399 } 1400 1401 auto skip = skipTracePointsToASeqPos(localAlignment); 1402 foreach (tracePoint; localAlignment.tracePoints[skip .. $]) 1403 { 1404 if (aSeqPos >= end.contigA) 1405 return; 1406 1407 addTracePointAlignment(localAlignment, tracePoint); 1408 } 1409 } 1410 } 1411 1412 // NOTE: damapper may produce false/bad chains that include a 1413 // complete stack of local alignments that have nearly 1414 // 100% overlap. In most cases they decrease performance 1415 // drastically and in some cases they can even cause 1416 // errors in this procedure. So let's ignore them at 1417 // this point. 1418 const(LocalAlignment[]) cleanUpLocalAlignments(in LocalAlignment[] localAlignments) 1419 { 1420 ReferenceInterval toInterval(in LocalAlignment* la) pure 1421 { 1422 return ReferenceInterval( 1423 0, 1424 la.contigA.begin, 1425 la.contigA.end, 1426 ); 1427 } 1428 1429 auto combinations = findTilings!toInterval( 1430 localAlignments.map!((ref la) => &la).array, 1431 longestInputsLength(memoryLimit), 1432 ); 1433 1434 alias Combination = typeof(combinations[0]); 1435 auto combinationScore(in Combination combination) 1436 { 1437 long coveredBasePairs = combination.region.size; 1438 long score = combination.region.size 1439 - combination.totalOverlap 1440 - combination.elements.map!"a.numDiffs".sum; 1441 1442 return score; 1443 } 1444 1445 return combinations.maxElement!combinationScore.elements.map!"*a".array; 1446 } 1447 1448 size_t skipTracePointsToASeqPos(in LocalAlignment localAlignment) 1449 { 1450 return localAlignment.tracePointsUpTo!"contigA"( 1451 aSeqPos, 1452 ac.tracePointDistance, 1453 RoundingMode.floor, 1454 ); 1455 } 1456 1457 void addTracePointAlignment( 1458 in AlignmentChain.LocalAlignment la, 1459 in AlignmentChain.LocalAlignment.TracePoint tracePoint, 1460 ) 1461 { 1462 auto aSeqBegin = aSeqPos - begin.contigA; 1463 auto aSeqEnd = nextTracePoint(la, aSeqPos) - begin.contigA; 1464 auto bSeqBegin = bSeqPos - begin.contigB; 1465 auto bSeqEnd = bSeqBegin + tracePoint.numBasePairs; 1466 1467 auto tracePointAlignment = findAlignment( 1468 aSequence[aSeqBegin .. aSeqEnd], 1469 bSequence[bSeqBegin .. bSeqEnd], 1470 indelPenalty, 1471 No.freeShift, 1472 memoryLimit, 1473 ); 1474 1475 appendPartialAlignment(tracePointAlignment, aSeqEnd, bSeqEnd, No.freeShift); 1476 aSeqPos = nextTracePoint(la, aSeqPos); 1477 bSeqPos += tracePoint.numBasePairs; 1478 } 1479 1480 void addGapAlignment(in AlignmentChain.LocalAlignment afterGap) 1481 { 1482 auto aSeqBegin = aSeqPos - begin.contigA; 1483 auto aSeqEnd = afterGap.contigA.begin - begin.contigA; 1484 auto bSeqBegin = bSeqPos - begin.contigB; 1485 auto bSeqEnd = afterGap.contigB.begin - begin.contigB; 1486 auto aSubsequence = aSequence[aSeqBegin .. aSeqEnd]; 1487 auto bSubsequence = bSequence[bSeqBegin .. bSeqEnd]; 1488 1489 if (memoryRequired(aSubsequence, bSubsequence) <= memoryLimit) 1490 { 1491 GC.collect(); 1492 auto gapAlignment = findAlignment( 1493 aSubsequence, 1494 bSubsequence, 1495 indelPenalty, 1496 Yes.freeShift, 1497 memoryLimit, 1498 ); 1499 1500 appendPartialAlignment(gapAlignment, aSeqEnd, bSeqEnd, Yes.freeShift); 1501 } 1502 else 1503 { 1504 auto numIndels = cast(score_t) absdiff(aSubsequence.length, bSubsequence.length); 1505 auto numSubst = cast(score_t) min(aSubsequence.length, bSubsequence.length); 1506 auto indelOp = aSubsequence.length < bSubsequence.length 1507 ? EditOp.insertion 1508 : EditOp.deletetion; 1509 1510 logJsonWarn( 1511 "info", "faking too long alignment gap", 1512 "gapSize", aSubsequence.length, 1513 "acFingerprint", [fingerprint(&ac).expand].toJson, 1514 ); 1515 auto fakeAlignment = typeof(_paddedAlignment)( 1516 0, 1517 chain(indelOp.repeat(numIndels), EditOp.substitution.repeat(numSubst)).array, 1518 aSubsequence, 1519 bSubsequence, 1520 indelPenalty, 1521 Yes.freeShift, 1522 ); 1523 fakeAlignment.score = fakeAlignment.computeScore(); 1524 assert(fakeAlignment.isValid()); 1525 appendPartialAlignment(fakeAlignment, aSeqEnd, bSeqEnd, Yes.freeShift); 1526 } 1527 1528 aSeqPos = afterGap.contigA.begin; 1529 bSeqPos = afterGap.contigB.begin; 1530 } 1531 1532 void resolveOverlappingAlignments( 1533 in AlignmentChain.LocalAlignment lhs, 1534 in AlignmentChain.LocalAlignment rhs, 1535 ) 1536 { 1537 auto overlap = getNonOverlappingCoordinates(lhs, rhs); 1538 1539 assert(aSeqPos >= overlap.begin.contigA); 1540 assert(bSeqPos >= overlap.begin.contigB); 1541 1542 auto aSeqBegin = overlap.begin.contigA - begin.contigA; 1543 auto aSeqEnd = overlap.end.contigA - begin.contigA; 1544 // Crop alignment according to aSeqPos 1545 _paddedAlignment = _paddedAlignment[0 .. aSeqBegin]; 1546 // Use resulting position on contig B as it may differ from 1547 // trace points due to previous overlap resolution 1548 auto bSeqBegin = _paddedAlignment.query.length; 1549 auto bSeqEnd = overlap.end.contigB - begin.contigB; 1550 1551 GC.collect(); 1552 auto overlapAlignment = findAlignment( 1553 aSequence[aSeqBegin .. aSeqEnd], 1554 bSequence[bSeqBegin .. bSeqEnd], 1555 indelPenalty, 1556 Yes.freeShift, 1557 memoryLimit, 1558 ); 1559 appendPartialAlignment(overlapAlignment, aSeqEnd, bSeqEnd, Yes.freeShift); 1560 aSeqPos = overlap.end.contigA; 1561 bSeqPos = overlap.end.contigB; 1562 } 1563 1564 auto getNonOverlappingCoordinates( 1565 in AlignmentChain.LocalAlignment lhs, 1566 in AlignmentChain.LocalAlignment rhs, 1567 ) 1568 { 1569 alias TranslatedTracePoint = AlignmentChain.TranslatedTracePoint; 1570 alias ResolvedCoords = Tuple!( 1571 TranslatedTracePoint, "begin", 1572 TranslatedTracePoint, "end", 1573 ); 1574 1575 alias resolveOn(string contig) = () => ResolvedCoords( 1576 lhs.translateTracePoint!contig( 1577 mixin(`rhs.` ~ contig ~ `.begin`), 1578 ac.tracePointDistance, 1579 RoundingMode.floor, 1580 ), 1581 rhs.translateTracePoint!contig( 1582 mixin(`lhs.` ~ contig ~ `.end`), 1583 ac.tracePointDistance, 1584 RoundingMode.ceil, 1585 ), 1586 ); 1587 1588 if ( 1589 lhs.contigA.end > rhs.contigA.begin && 1590 lhs.contigB.end > rhs.contigB.begin 1591 ) 1592 { 1593 auto resolvedOnContigA = resolveOn!"contigA"(); 1594 auto resolvedOnContigB = resolveOn!"contigB"(); 1595 1596 return ResolvedCoords( 1597 minElement!"a.contigA"(only( 1598 resolvedOnContigA.begin, 1599 resolvedOnContigB.begin, 1600 )), 1601 maxElement!"a.contigA"(only( 1602 resolvedOnContigA.end, 1603 resolvedOnContigB.end, 1604 )), 1605 ); 1606 } 1607 else if (lhs.contigA.end > rhs.contigA.begin) 1608 return resolveOn!"contigA"(); 1609 else if (lhs.contigB.end > rhs.contigB.begin) 1610 return resolveOn!"contigB"(); 1611 else 1612 assert(0, "unreachable"); 1613 } 1614 1615 void appendPartialAlignment(PartialAlignment, FreeShift)( 1616 PartialAlignment partialAlignment, 1617 in size_t aSeqEnd, 1618 in size_t bSeqEnd, 1619 in FreeShift freeShift, 1620 ) 1621 { 1622 if (freeShift) 1623 { 1624 auto firstSubstitution = partialAlignment.editPath.countUntil(EditOp.substitution); 1625 1626 _paddedAlignment.score += indelPenalty * (firstSubstitution < 0 1627 ? partialAlignment.editPath.length 1628 : firstSubstitution); 1629 } 1630 1631 _paddedAlignment.score += partialAlignment.score; 1632 _paddedAlignment.editPath ~= partialAlignment.editPath; 1633 _paddedAlignment.reference = aSequence[0 .. aSeqEnd]; 1634 _paddedAlignment.query = bSequence[0 .. bSeqEnd]; 1635 assert( 1636 _paddedAlignment.isValid(), 1637 format 1638 !"exact alignment invalid after stitching: %1$d %2$d [%3$d, %5$d) [%4$d, %6$d)" 1639 (fingerprint(&ac).expand), 1640 ); 1641 } 1642 1643 coord_t nextTracePoint( 1644 in AlignmentChain.LocalAlignment la, 1645 coord_t contigAPos, 1646 ) 1647 { 1648 alias isAlignedTracePoint = (pos) => pos % ac.tracePointDistance == 0; 1649 1650 return min( 1651 la.contigA.end, 1652 isAlignedTracePoint(contigAPos) 1653 ? contigAPos + ac.tracePointDistance 1654 : ceil(contigAPos, ac.tracePointDistance), 1655 ); 1656 } 1657 } 1658 1659 return AlignmentPadder(ac, begin, end, aSequence, bSequence, memoryLimit).paddedAlignment; 1660 } 1661 1662 unittest 1663 { 1664 enum tracePointDistance = 100; 1665 enum complement = AlignmentChain.Flag.complement; 1666 alias Contig = AlignmentChain.Contig; 1667 alias LocalAlignment = AlignmentChain.LocalAlignment; 1668 alias Flags = AlignmentChain.Flags; 1669 alias Locus = AlignmentChain.LocalAlignment.Locus; 1670 alias TracePoint = AlignmentChain.LocalAlignment.TracePoint; 1671 1672 auto ac = AlignmentChain( 1673 0, 1674 Contig(1, 1092), 1675 Contig(12407, 12767), 1676 Flags(complement), 1677 [ 1678 LocalAlignment( 1679 Locus(0, 439), 1680 Locus(6604, 7076), 1681 67, 1682 [ 1683 TracePoint(16, 105), 1684 TracePoint(17, 106), 1685 TracePoint(11, 108), 1686 TracePoint(19, 111), 1687 TracePoint( 4, 42), 1688 ], 1689 ), 1690 LocalAlignment( 1691 Locus(400, 439), 1692 Locus(7034, 7076), 1693 4, 1694 [ 1695 TracePoint( 4, 42), 1696 ], 1697 ), 1698 LocalAlignment( 1699 Locus(590, 798), 1700 Locus(7263, 7475), 1701 41, 1702 [ 1703 TracePoint( 1, 10), 1704 TracePoint(20, 107), 1705 TracePoint(20, 95), 1706 ], 1707 ), 1708 ], 1709 tracePointDistance, 1710 ); 1711 auto begin = ac.translateTracePoint(400, RoundingMode.floor); 1712 auto end = ac.translateTracePoint(600, RoundingMode.ceil); 1713 auto aSequence = "agtgctggccccagtcaagggcatgtacctgggttgcaggttccccagcc" ~ 1714 "cccgtaggggtgtgtgtgtggaaggcaaccaattgatgtgtctcctttat" ~ 1715 "gttgatgtttctctttctctctccctcctccctgtcttccactctctcta" ~ 1716 "gaaatcaatgggaaaaatatcctcaagtgaagattaaaaaaaaaaaaagg"; 1717 auto bSequence = "agatgatggccccagtgcaagggcatgtacctggtgttgcagcggttcca" ~ 1718 "gccagcacccgtacggggcgtgcgtgtggaaagggcaaccaatttgatgt" ~ 1719 "ccctacgttttcatgttgatgttttctcttttctctctctctctcccttc" ~ 1720 "cttcccacttttcttcccagcttctctctagaaaacaagggaaaagtgtc" ~ 1721 "ctttcagtgtaggatttttaaaaaaagccaaaaaaaggg"; 1722 1723 auto exactAlignment = getPaddedAlignment(ac, begin, end, aSequence, bSequence); 1724 1725 assert(exactAlignment.toString(50) == 1726 "ag-tgctggccccagt-caagggcatgtacctgg-gttgcag--gttcc-\n" ~ 1727 "|| ||*|||||||||| ||||||||||||||||| ||||||| ||||| \n" ~ 1728 "agatgatggccccagtgcaagggcatgtacctggtgttgcagcggttcca\n" ~ 1729 "\n" ~ 1730 "-ccagcccccgta-ggggtgtgtgtgtggaa-gg-caaccaatt-gatgt\n" ~ 1731 " |||||*|||||| ||||*|||*|||||||| || ||||||||| |||||\n" ~ 1732 "gccagcacccgtacggggcgtgcgtgtggaaagggcaaccaatttgatgt\n" ~ 1733 "\n" ~ 1734 "gtct-ccttt--atgttgatgttt-ctcttt-ctctctc-c-ctcc-t-c\n" ~ 1735 "**|| |*||| |||||||||||| |||||| ||||||| | |||| | |\n" ~ 1736 "ccctacgttttcatgttgatgttttctcttttctctctctctctcccttc\n" ~ 1737 "\n" ~ 1738 "c--c----tgt-cttcc-a-ct-ctctctagaaatcaatgggaaaaatat\n" ~ 1739 "| | |*| ||||| | || |||||||||||*||| |||||||*|*|\n" ~ 1740 "cttcccacttttcttcccagcttctctctagaaaacaa-gggaaaagtgt\n" ~ 1741 "\n" ~ 1742 "cct--caagtgaag-att---aaaaa-----aaaaaaaagg\n" ~ 1743 "||| || |||*|| ||| ||||| |||||||*||\n" ~ 1744 "cctttca-gtgtaggatttttaaaaaaagccaaaaaaaggg"); 1745 } 1746 1747 unittest 1748 { 1749 import std.range : repeat; 1750 enum complement = AlignmentChain.Flag.complement; 1751 alias Contig = AlignmentChain.Contig; 1752 alias LocalAlignment = AlignmentChain.LocalAlignment; 1753 alias Flags = AlignmentChain.Flags; 1754 alias Locus = AlignmentChain.LocalAlignment.Locus; 1755 alias TracePoint = AlignmentChain.LocalAlignment.TracePoint; 1756 1757 // TODO reduce test case to two consecutive "overlap" scenarios 1758 auto ac = AlignmentChain( 1759 574, 1760 Contig(5, 33046024), 1761 Contig(344, 73824), 1762 Flags(complement), 1763 [ 1764 LocalAlignment( 1765 Locus(8372381, 8419325), 1766 Locus(0, 46966), 1767 388, 1768 array(chain( 1769 only(TracePoint(3, 19), TracePoint(4, 102), TracePoint(5, 101), TracePoint(3, 99), TracePoint(4, 100), TracePoint(5, 98), TracePoint(3, 99), TracePoint(2, 100), TracePoint(3, 99), TracePoint(1, 101), TracePoint(5, 101), TracePoint(5, 103), TracePoint(8, 102), TracePoint(8, 102), TracePoint(6, 101), TracePoint(3, 101), TracePoint(3, 99), TracePoint(7, 103), TracePoint(5, 99), TracePoint(4, 99), TracePoint(2, 102), TracePoint(5, 101), TracePoint(6, 96), TracePoint(3, 99), TracePoint(4, 100), TracePoint(7, 101), TracePoint(1, 101), TracePoint(4, 98), TracePoint(3, 101), TracePoint(4, 102), TracePoint(3, 101), TracePoint(4, 104), TracePoint(7, 105), TracePoint(2, 102), TracePoint(8, 102), TracePoint(3, 99), TracePoint(10, 104), TracePoint(5, 99), TracePoint(5, 95), TracePoint(3, 101), TracePoint(3, 101), TracePoint(4, 99), TracePoint(3, 99), TracePoint(4, 100), TracePoint(7, 98), TracePoint(8, 105), TracePoint(4, 98), TracePoint(6, 98), TracePoint(8, 100), TracePoint(4, 100), TracePoint(8, 101), TracePoint(2, 98), TracePoint(5, 99), TracePoint(3, 101), TracePoint(3, 98), TracePoint(1, 101)), 1770 TracePoint(0, 100).repeat(17), 1771 only(TracePoint(8, 104), TracePoint(2, 102), TracePoint(2, 100), TracePoint(3, 101), TracePoint(2, 98), TracePoint(9, 97), TracePoint(3, 99), TracePoint(4, 98), TracePoint(2, 98), TracePoint(2, 99), TracePoint(4, 101), TracePoint(3, 99), TracePoint(5, 101), TracePoint(4, 99), TracePoint(5, 100), TracePoint(4, 98), TracePoint(1, 99), TracePoint(1, 99), TracePoint(3, 99), TracePoint(3, 101), TracePoint(5, 101), TracePoint(4, 100), TracePoint(4, 102), TracePoint(1, 99), TracePoint(4, 104)), 1772 TracePoint(0, 100).repeat(138), 1773 only(TracePoint(3, 102), TracePoint(5, 99), TracePoint(4, 100), TracePoint(5, 101), TracePoint(5, 97), TracePoint(1, 101)), 1774 TracePoint(0, 100).repeat(163), 1775 only(TracePoint(7, 103)), 1776 TracePoint(0, 100).repeat(47), 1777 only(TracePoint(3, 102), TracePoint(5, 99), TracePoint(1, 99), TracePoint(4, 100), TracePoint(4, 104), TracePoint(4, 99)), 1778 TracePoint(0, 100).repeat(11), 1779 only(TracePoint(0, 25)), 1780 )), 1781 ), 1782 LocalAlignment( 1783 Locus(8419319, 8419520), 1784 Locus(46907, 47119), 1785 27, 1786 [ 1787 TracePoint(10, 87), 1788 TracePoint(16, 104), 1789 TracePoint(1, 21), 1790 ], 1791 ), 1792 LocalAlignment( 1793 Locus(8419355, 8446270), 1794 Locus(46907, 73824), 1795 31, 1796 array(chain( 1797 only(TracePoint(6, 47), TracePoint(24, 99), TracePoint(1, 101)), 1798 TracePoint(0, 100).repeat(266), 1799 only(TracePoint(0, 70)), 1800 )), 1801 ), 1802 ], 1803 100, 1804 ); 1805 auto begin = ac.translateTracePoint(ac.first.contigA.begin, RoundingMode.floor); 1806 auto end = ac.translateTracePoint(ac.last.contigA.end, RoundingMode.ceil); 1807 auto aSequence = "aaagaaggtgtagagattagccaaagaacatatatgcaaagcccacgaacccagaaaacagtgtggtgaaggccagagaggggtgggtagggactgggtggaagtgggcaaaggggggaggaatgggggacatgtgtaatagtgttaacaataaaaaacccaaaaccaaaaccaagaaggaatattaccactattcactattaatgattaagacatcacatgtgactcatcaggaaaaaacagtttacagtttcatatcctaagtggagtacgtacatttaatagttaaacaagttggctttgggatatggaaattataagggagaataaatatttaagcccatgatgcaatttaatttattttttctgtgacttactgaactaagcatgatcagtgagactatgacttagagaatcaaatgtctcctttgagccttgctgaggcaagatttatatttctcagatgtctacacttggaagacatgatcagaaataaaaatgtctgtgaaacgccgccgattgacttgcacggtttgcagaacaggatccagttttaagtgctgtcttttgtgttcctgcagtagctgtgagggagggaactctggtccatgcaaggaaaaggagcagatagctccctgttccaacaagaacagtttgtgcaattaagtttttcacagccaccttgcatgatagatagtaggctcatttcacggaacttttatcaacgtgtaaatccaatcagcactccaacatcctgtttattagaaggtttctgaaatcatagctccattgtgtgtgtgtgtgcgcacatgtggatgtgggttgtcattaatgtgcctgcttcccactgcagcccctgcttgataaagaatgtgaagtatgagggtggagcatgactgaatttttctgagttgagaagcccggtcagccctccctggcatggctgagctaagcgtgtgtggtcccatttgtgtgtcacagttttggtcctttggcaatcaggctgagagtattttgtgattctgcatcaagtttatctgtttaatattgtcacctgcattttaagggcctccttttgcattaaatagctgtgtcaagcaatcaactggatttctttgagatgtgccaagtgtataacactgaactaccaatgtgaccatagaaatccagatacttgtacatcataaagttgtgtattataataaaatggacaatattgataaatttaaatgtgacatgtaccatttgccccatggttttactttattgaggataaattattactgataaatttgttttattattgtgcaatttgttgttgtttatcctcactggattttttttcattgatatttttagaaagagtggaagggaggggtggagggagagagaaaaatatcgatgtgagagagacacatcgattggttgcctgcccaggtatgttcccttgactgggaatcaaacctgagacccttcagtgcacaggctgatgctctaaccgctgagacacactggccagagcatcttatgcaattttcaaaatactttgtggtgagttgtgagagagcagacaagaacaggaattaaaatcagggacgtagacccagaaggatcatgcagtcaaatgtttggactgttaacaaataaactatacttgtaagtatgaaataattttaaatcttatcatgttatgttttcaaattttggtggtagagtggagttttagtcaatgttgctactgaattatttacaaataatatgaaaataccaggtgataactacaatggaatgtgtgacactgtagctgaatagtataacacaccactcagatttcaaggtcacctgtgagtcatcttttggggacaatttccattaggattttaatttttgtcatctgagtcttaggaacccaggcaatggcttcatgggtttgcttatggaaactgtctggcttgggccatctgagagaaatttttatttgtaatgcttggtttaggtctcttgattaaaaaaaaataatttcattttatttcattcgttgggataatttttgtattgaaccttcccctctcacaagtttaaagtataatttacatccagtgaaatgcacacatcctaaatgtatacaaatatataagtactagtggcccggtgcacaaaattcgtgcatggagcggggggttcccttagcccagtctgcaccctctccaattggggaccccttgggggatgtcccacagggatttggactaaaccggcagtcagacatccctcttgcaatcggagactgctggctcctaaccactcacctgccttcctgcataatcgtccctaactgcctctgcctgcctgattgcccctaacccctctgactgcctgcctgatcacccctaactgccctcccctgccggcctgatctcgccccctacagccatcccctgcagcctgatctcgcccccaactgccctctcctgccagcctgattgcccctaactgcctctacctgcctgataatccctaactgccctcctctgctgtcctgatctgcccccaactgctctcccctgcaggcctgatcttgcccccaactgccctcccctgctggccaatttggttctgattggtcagtttctatgccagtcagcatcaaaagctctgcctcctaggcagccattggctcctcactgttcacccagatttggttctgattggttagtttctatgccagtcaacatctctgggcctatctccaggcctgatcagagaggtgggactgataagcagccccctcacggaggccttgagagaaagaggcgtggctgctggtgaagcccggggagagagagagagaggcaacagttgatcaacagctgccatggaggctgcagatcagaccgtgcctctctctctgggcctgatccgcagctccctcggcagtcagtgctgggttgctgtgcccgcaccggcggtagtcagtgctgggtcgccacggcagcccagcactgactgcaggactgctggtgttcagttgagccttcggtaggtcgttatggatcctgggtttttatatattaggatacttacaccatatgtatatgtactcaaatatccatgtgactaagacctggacaaaatgtaaaatgtcaccgtcagctgagaaagttcccctgtgcccctttcaatcaataagcccacctttctcagaagataaccactattctgacttctatcatcacaacttgcttgtttattaacctcacgtaaatgtgattatacattagctacccttttctgtctggcttcatttgttcaacataatgttattgagactcatccatgttggagaatgtatcagtaggtacacctggtattatcaatcttttacattttagccatatagtatatgtatatatatgtaaacattcttaattggtatttttttatggtttaaagtattacatatgtctcccttttccctgattgacccgccccccaaccactcccacccctgaggaaaagtccccaccgccccagtgtctgtgtccattggctatgctaatatgcatgcataatgcatacaagtcctttagttgatctctaaccaccgcccatgccacttgtccctggatctatttttgttcacagtttttgttgatcattatatcccacatcttagtgagatcatgtgatatttatctttctccaactggcttatttcccttagcataatgctctccagttccatccatgctgtttcatccatcccccagcccagcttgcaccctctccaatccagggccccttgggggatgtccgactgccggtttaggcccgatccccagaataaggcctaaaccggcagttggacatccctctcacaatctgagactgctggcttctaactgctcacctgcctgcctgcctgatcacccccaactgccctcctgctggcctggttgcccccaactgccccccgctggcctggttgccccatgcagcctgctgttcagtggtttggtcgtccctctctaacccccctgcaggcctggtcaccccacgcagcctgctgttcagtcatttggtcatccttcactaaatccctgcctgcctggtcgccttatgcagcctgctgttcagtcgtttgattgtccctcactaatccccctgccggccttgtcgccccatgcagcctgctgttcggtcatccagcccgttgttttggttgtgacagcccctggctttttatatattaggaatagtattccattgtgtaggtgtaccacagttttttaatccactcatctgctgatgggcacttaggctgtttccaaatcttagctattgtaaattgtgctgctatgaacataggggtgcatatatcctttctgattggtgtttctagtttcttgggatgtagtcctagaagtgggattactgggtcaaatgggaattccatttttaattttttgaggaaattccatactgtcttccacagtggctgcaccagtctgcattcccaccagcagtgcatgaaggttcctttttctccacatccttgccagtacttgtcctttgttgatttgttgatgatagccattcttacaagtgtgagatggtatctcattgttgttttgatttgcatctctcagaggattagtgactttgagcatgttttcatatgtctcttggccttctctatgtcctcttttgaaaagtgtctatttaggtccattgcccattttttgattggagtgtttatcttccttttgttaagttgtatgagttctctgtaaattttggagattaaacccttatctgaaatagcattggcaaatgttctcccatgcagtgggctttcttgttgttttgttgatgatttcttttgctgtgcagaagctttttattttgatgtagtcctatttgtctatgttctccttattttccattgccctagaacagccgtgggcaaactacggcccgccggccggatccggcccatttgaaatgaataaaactaaaaaaaacccaaaaaacagaccatacccttttatgtaatgatgtttactttgaatttatattagttcacacaaacactccatccatgcttttgttccggccttccagtccagtttaagaacccattgtggccctcgagtcaaaacgtttgcccacccctgccctagaagctgtatcagtaaagatattgctgtgacatatgcctgatattttgctgcctatgtagtcttttaagatttttatggtttcccatcttaaatttaagtcctttaaccattttgagtttgtttttgtgtatggtataggttggtgatctagtttcatttttttttttggtatgtatttgaccaaatttcccagtaccatttattgaagagactgtcttaactccattgtatgctcttgcttcctttgtcaaatattaattgagcataatggcttgggtcaatttctgggttctctgttctgttccggtgcaaaagtatatttgtatacaaaagtatgaaggttaatttcatttgtcaacttgactgggccatgagtgctcagaaatttggttaagcataattctggatgtgtctgtaatggtgtttattctctgcatgagttcagcatttgaatcgatagactgagtaaagcaaataaccttctttaatgtaggcaagccccatcgaatccactggaggactggatagaataaaaggcaggccaagaaagcattctttctctctgactgcctatctttaagctgggacatccatcttttcccgcctttggacttagacttgaactagaatttacactagtggctctcttcgttctcaggcctttaggctcaggctggaactataccctcagctctccttgtgtccctaccttttgactgtagatcttaaacttctcagcctccattattgtgtgagctagttccttataataaaaccaaacaactaatctctctctctctctctctctctctctctctctctctctctctctctctctttctctcaatatatatatgtacacacacacacacacacacacacacacacaaattcattctttctttattataaagtgatctaggcttactggttatttctgcctccttttcagatgttatcttatctacccatttccctgatgttgtaccatgaaacatacaagacaatggctaacaaagagtctttcttgcggggaaggaaggaggcacaagctaatacatattgtctctgctgcaaataattttaaaaataacatcaagatgctttctgataacagttaacaatcactttttatgaagctacaaacactcagctctccacattatgagactctccaagagtagtgttttctaacagatattttctgaagtcatttcctctagaggacacaatgagtcaccttaaaatggctcaaaactcattccctcctctccctcgccatgaaatgacttacaacatttcattgttacttcaactttagggacaacctttcttagtattattactgtgtctggtatccaattaaacaataaggagtaatgtagaaagaattgcccataaaatgtatttatttttctgaattgaaaattaaaaataagagtttttgaatgtgctcagtgagagtctatacctactttgcttccaatatttgagttcctctataggactgtagggacacaactagatgctgatctgatgcccagagcagagtggcagggtggagggacgcatgtgctgtctatgtcactggcaggtcagctttcctctccctgtctccagttgcaagagtgtggacaggcttgtatgatccagcgcacacctggatactcacatctaaagaaagagaccagagctttcctgtttgtttcactcatcaagtcagagtcagagcttcctgttccctatatactttggctgtcactgacaggtctaaagtttcatggtgatataatcctatctaataaaagagaaacatgcaaattgaccataaccccaacacccttcccaggatatgcaggatatcagcaggatatgcaaattaactgccaaccaagatggcggccagcagccacgcagctgaagcgaacaggaggcttgcttgctccagtgatggaggaagccaacattcccggcctgccatgaccagcctctgagctacactctaagcaactatgttgcaattatagaagctaaacaagctccagagacctgctttcagccagcttaggcctcagagcttagagctgcagtgatggcaacagagtttcaattatagaagccaaacagacccagaacctgctttcagcccccagagctggagcctgctctcagctccagtgacagctatacaaggtaaataaatcccagaataaaaaaaaaaagaaaaaaaaggagaggctgggagcttaagttgccctccagcctgaaaatggctctcaggccctcacccagactggccaggcaccccagtggggacccccacctgaagggggtgtgaccagatgcaaacagccatcatcccctcatgcaggctggccaggcacccaagcgggacccccaccctgatctgggacactttcagggcaaaccagccagcccccacccgtgcaccaggcctctatcctatactactggcagggcgggacagctcgagctgccatccgggccccatgtgcagccctgggtagtggggcataagtcctgcccccagccgggatccctgtgtgccacctgatcccccagctgggatccccgtgctgcctaagccctgcactgctaagccccgcccccagccgggaccctatgactattggagagcaggaaagtgccgctgggccctgggtcactgtgttgatctggccatcggtaagtagaaaagtgcagcctgtaggcagcccccagctgcacctgatctgggagcaggaaagcaagcctggcctgtgggcagccccaagctgggcctgaaacgggagcaggaaagcctggcctgcgggcagcccccagataggcctgcttcccagtcaccatggggatccgggaacaggagaacaagcccggcctgcgggcagctccaagctgggcctgctccctggttgccatggagacctgggagcaggaaagcccagcctgtgggcagctcccagctgggcctgctccccggacgccatggcgatccaggagcaggaaagtctggcttgcaagcacccccatcctggccatagctcaagggagagtacaacatgcagtggaggcccggagcctaagagatcaacacagaggggctcctgctccaagcctctatggtgtggctgggggcaggcccccagcagacacacacacacacacacacacacacacacacacacacagtgcctgctctgagcctccaatgtggctggggacagacccccagtggggacacacacacacacacacacacacacacacacacacacacacggcaattgctttgagcctacgtggcgtgccgggagccggtccatgcttgctgtttcaagggacctggcatatatggcatactgttcttaatatgtttgctcaccttcttggcactatgtgttttaaccaaggtctctgagaaaggttgtttccccaggtagggatttttcactgaagttagggagggaataaaacctcttaactaagtgccaggcgggtaattaatcactttaactatgaacaatcatgcttaagctacataatctttactccctggaatggagataagaaacgccctaacctttggaatagagattgataggattggaatcaactggtataaatacagatgtaacaacacagaacttaggagacagaacttagaacacagaactaagaagacagaactaagaacacagaacctacacagaacctagagacagaagaactttgctggagagaacatggcaaaagatcctggactgaacctgactacagaaattggcaagagaacctgactagaacctggtgactgagcctggctggagaacctggacacaacctggctggagaacctagtgagggaacatggctacagaacctggctggagaacctggagaacctagcaagagaacatggacacagaacctggctggagatcctaaccagaacctcactggagatcctgaccagaacgtggctagagaaccttgctatgatgatcatctgaatgccctctccgtgtcattccttcttcgctgactccgtccacacctttggggacccctggacccgctggggttggaccccggcagtggcgcggatgggggcaggccctagcagacacacacacacacacacacacacacacacacacacacacacgggacgcctgctccgagcctctgctgccagactgtggccatcagtaggacatccactgagggctcccggactgtgagagggacaggctaggctgagggaaccccacccccccagtgcacaaattttgtgcaccaggcctctagtcctatataataaaaggctaatatgcaaatcaacccaatggtagaaggactggttgctatgatgcgcactggccaccagggggcagacactcaatgcaggagctgcccccctggtggtcagtgtgctcccacaggggaagcgccgctcagccagaagccgggctcatggcagtctgacatcccctgagggctcccagactgcaagagggtgcaggccaagctttgggaacccctccctgaatgcacgaattttgtgcactgggcctctcgttttatatgaaaaggaaacatggtgtgtaccccctgaaaagccttcatgtcacaaaggaaaaatgccgtgaccaaaaaggcaaatttgttccatgcaagttgtctactgaaatcatttcctatttccaaatgtcttcattaaaacaaaacagataataaatcacttacacatctcccaacaatcctctcaatttaaaaaaaaaaaaaaatagagccctggctgatgttgctcaatggttggagcgtcggcctgcatgttgaagagtctcaggttatatttccaatctagggcacgtaagttcccttgggttgcaaatttgatccttggcctcggttagggtgcacacggagggaaccaatcgattgtctctcttacatccatatttctctctgtccctctctcaccccctccctcccactatctctaaaaatcaatgggaaaaatatccttgggtgaggattaagaacaacaacaaaaaacagtaaaaattcagtcacatgattttccattttgaatgaattaatctaagtggatgggaaacccaaatgcagcagagtccaggaggccattttcagttagctccattcaaaatgattaggaacactttttagaaaagtcttctttttgagtaatgccattggatatagaaaagctgctttcccaaaatgaaaaatcattggtaaaaataactgacatttatcttccagcatgatttgatttttaaaaaaatatattttattgattttttacagagtggaaggaagaggaatagagagttagaaacatcctgcacaccccctattggggatgtgctcacaactaaggtacatgcccttgactggaattgaacctgggacccttcagtccacagaccaacactctatccactgagccaaaccggttaccaccccagcatgattttaaatagcgttcctatatgtcttaatttattaagaaaagcatcaataccaaaatatttcattctatatcataaagtagaatgtacttttaataaaaatcggaggaaaaatttcagatgtttaaagaaaatgtagtttgacataataatttggagctctatccttgaggtgaaaaatgaattttactaaaagcaatataatttttttctggaaattaagcaaaggattattttttttttgtggtctcttagccaacggacaagggggaaaagaaaagaactggtctattctttttagaatcagagagaaggcaattgaaagttccctgtgaaagtaattttttttcccctcaagggctcttgagggttcacactgaaatgtcaatgaccttgtttgttcagagtttgtaacagccattttcaactgccctctgtgcttcgataaatatgttccagtcattgtaggttctgtgtctaaaacctatcaacatcattccctaagcatcaaggggatgctttttatgacaaaacatgctttatgcaggactctcactaaacccatgtgattccgagaacatccatcccaaagtgcagcgttaagaaattacacaatataaaattatttggaggcagttctggtgaattattttaatagtcctaaggcttggaaattccagacaatctcaacaaaccatacaacggacaactggcaaagatggtctatattttttaagaaaagccaagttattatttcaccatcttttcttaggataggtttcaaaattctgatcaactctagaccaccaggtagcccaacttagaacagtttaccagaagggccttacttatttctgctacttagtatagaaaatttttatttgagtgaagtaagcataaagagactttgactgatttgggattttcctcgtcaacacatattaaaaactaaaattaaattatatatattttaatttattttctctccatcataatcataaatgatagctactatttatggaattcttctattcctaggctttgcaataatactgttccatgtattttatcacttaatatttacactgatgtgtgaggtgttccacaatgatcttttcttatcactgaagaaattgaaaattagagaggttaagtaatttatccaatgatcttgctcaagaactccaagacacacacacacacacacacacacacacacacacacacacacacactcatatatattaaccactctgtcatattgcttagtatgtttaactaggggcccagtgcacgaattcatgcaccttgaaaggaactgtgggctgcgaggctgcagtgggcacaggggcgggtctcggctcatcctccatgcccttgcctggactctcccactgcacccccagtcccttgtctgccagcagccctgctcccgccaccaccactccagcgcactgacagtgctggccctgctcgtacccactgaaggtgcggagcaattgggtcctggcaccagcaatgggtatgagtagggctggcgccatcatcgggtgcaagcagcagttgctgccctgttcgcccctcaggagcaggtggaggtggagaagccctcaggggcaattgggattggcagccacagcttgcacccactgatggcaccgagagattggggctggcgccgggtgccagcagtgggtgcgaatggggccagcactggcagcaggtgcaagcaccaggcaggaccatggtacacaagagcaaagaattttcagtaaccaccagatgcttgcctcaatgacagcaaccggcgccctgccttggtctggtgcccccactcacctgctccaccatcccgtcgcagcggatgcctgccatgttttgcgcacgccccctggtggtcagtgcatgtcatagcaactggttgttcggttgttcggctgttctaccatttggtctatttgcatattagccttttattatataggatactgtcgtggaccttttatgattattctacatcagcaggctataaataggctgcagaggatatggatgtagaactgtaaaaaccagaaacacaattctctttttccttctttttcccagacctcccttcttcctctcttttttcttctatgccacaaggtctgccctcctatggtttgaaatataattgagaagacaacatatgtaattctcaaaagtaaaacatagaaaagtttgataacattgagtaaagatggagaggaagtaggtaatcatatttttttaatttctgaaatattccaatagccaaataaatgaatcattctcaaaaataggaaaataaagttttaataggaaaagagaatggagtaactgggggaaatcacaatgtgcctttcttatagtttttaattcctttaagtttattgaatgattcagattttctattcctttttatgtcagtttgagtaagttgtattttttcctagaaacttgtccaatttacctaaattttcaaatttaggaacataaagttgttaataataaatatcattaaatgattttataataataaaaaaaatatctgtaggctctgtagtgagatatccctttccatttctggttcattttcttgaggtacaggacattgtatgtgaaaaaaaagttacaattatttgaggcctagaattatcttcctccaaggaagacttacatttgcctttggtaggtggttagggccccagctatcttagatcaccttcatctaattatagggactgaacccagctggcatggctcagtggttgagcatcaacctatgagccaggaggtcacagttaaattccccattagggcacacaccgggtttcaggcttcacctgcagtaggggtcttgcaggaggcagctgatcaatgagtctcgtcactaatgtttctatctctctcatttcctctctgaaatcaataaaaaatattttttaattatagggactgtgatgatttaaactttagtgcagctccaagttttttccagttactccttactcataggtggagccctttgggatcccatctagatgtgtgaacatttaccagagttcactcctgaacagaactttgattttttgctaaattatatatatatatatattttatttactttaaccatctagccctatgggtctgccaaaacctctgccgaaattctaccttaatcatctcttccagaaccatcaaccaatcctaggattcacctctctggtttccttttcttctttatttcataattctttactatcttggtggctataagatttaaatttttttatcttgctttgttaatttgtcttagcagaggtagtttatgttatgtgcatgttttgtgtatttttaaaaaaatattcctgcaaagcaaaggttcttcacactttgttttaaatattttaccattgatctgtgatttcttggggtcattttgcatatgttcatatttttccccataatatggaagttcattagggctatgacaagtgctgagatggctgggatcacccaattggtccaccagctggtattagaatcaacagtaatactaggagcttctgaagacttggttatcatttgtctgtcctctggacgaagctcccgagtgctatatgttttggacagttctctggcatctgtagagttccaggtgtcctcaaagtttttggtagcatcacctccagcttgttccctcaggacttctgccccaccaggatgctcctccaaaaatctggtcaaatcatgcaccttttggtgcaggatcggtcaggtgctcctgctgtggctgtgcttctggagcccttccagggtgtatgtctgatggccttgggaacgaggcaagcctctggccctgcagacaccagtgagctgggcagaggtaatagctgcaattttaaagcccactttcagaggaatgaacacaatgtaccagctactgagtagcatcatttttttttttttttttttgagaagtgaggttgtaaacttagaacaggataaaacatcagtgagagagaaacatcatcaattggcagtttcctgcatgcccccgactggggactgagccagcaacctggcatgtgccctgactgggaattgaacctgaatctgagacctcttggttcatgggttgacactcaaccactgatccatagcggcaagactgtttcttaacatttttgagcatcattctgagatcaaggatgttgggccgatgcaaattatgatcatcatggtaaagcagtgaaaattcttgattaccccgctcataacataaattcactcagtggttactcatacttgtttagaaggttccgctatagcccatgtattttggtaatattagcttcagattgttttggaaacttattcgggaagatctacctttcttgttcttttatatctctggatctaaatttcatgagtgtacttctctgatttggtctttgcaaataaaagcaggttgatcacttgcatttacctgtatagaaatctggtttggccttgtgatctccaggtaggcccaggagtatctttaactgtcacctttatcttcattaaatggtaataggtttttgaaaattgctcccaaaggagtcctactttgattgctggaatacctgaagttgtagttgacttctctgtgttaaataagaagggattgtgaaaaatagtgtaaaatgaagaaatttgaatgcaaatataataatttactttggggagtgctcacgatttatttttttttctttaggaactgatcattttttagtttctagtccactgcttctgactttacatcataatcccaattcacaaacacataggggtgcacccaccaccaccacacatttatatcctttccctcccccgctttgtctcactaaagtgaagtatggtagctatggttcttgtctgcctatcatgtctttccttaatccctgctttctagaaatagaaatcctctttctcataaatttattccatgtggtccaagtggacagtcttctcagaatcgttagcaatggggacaggaagcataaagctactagtgcccatcttggcaaggctgtctgacaataaagccaatgctcaggtaagagggcatgggctaaaaggagagtgagaatgcctgggtgatatagtctttttcagcttaaatttttttttttttttttttttttactatttttgtaagtactcaaatagtcataaaatcattctatgcacataaactttctcctttttaaaaatatattttttattgatttcagagaggaagggagagagagagaagtagaaacatcaatgatgagagagaatcattgactggctgcctcctgcacaccccctactgggaattgaaccgtgaccttctagatcagcgttcaaccacggagccatgccaggtgagctcttttgtagctttaaaatgaggggttggtccacagtcatgtcagtggctaccatacactgaaatttcattttatgctaaactaggggctcagtgcacaaattcatgcaccttgaaagaaactgtgggccgtgaggctaccataggcataggggcaggtctcagcccatcctccatgcccccgcccagcccctcccaccacagccccctggtcccctgtctgccagcagtcccactcctgccgctcccatgcactgacgatgccagcccctttcatacctgctgaaggtacggagtgattgaggctgatgctagcagcgggtgtgagcagcagctgctgtcccgatcacccccaggagcagggggaggtggagaagccctcaggggcgatcagggccagcagccacacttgcacccattgatggcattgagtgattgggactggtgcagagcatcggcagtaggtgtgagcggtggttccagcactggctgaaggtgcgagcagtggctccggtgctggtagcaggtggaagctctgggcaagaccacagtgcacaggagcaaagaattttcagtaaccacaggaggctcgacccgatgacaatgaatggcacctcaccttggtctggtgtcccctgctcacctgctccaccatcctgccatggccaacacccaccatgttccgcacatgccccctggtggtcaacgcatgtcacagtgactggttgtttggttgtttggttgtttcaccgttcagtctatttgcatattagccttttattatataggatattttccatgcattaatttcatttaatattaatgacaactctatgaggcatatgtttttatctttctcccactcctataactaagaaaactgaataccactgagaaaagcaatgtagtgtaagctagtaagagaagttatattcatcattttaagtttgtttctatcagtgtctggcttaatggtgagatatcaaaaataattgatcaagtaaatagataaagcacgatctctttgacttcaaagtccatgtccataaccaccatcaataacttaaaacattattaacttgagcaactgtctaaactcactgagtggtatctaggtcaataagtctatgtttctaacaaatttgaaatgattaaagatagaagcaaacatgtacttccctcaccattcctaaacacaaaactgaatctacccctggttctaatacaagaataggtgaaataggctttggggtttggcctgagacgctgaccaccctctggaacaaaaaaaaaagcattcaaaagccctagccggtttggctccttggatagagtgctggcctgcagactgaagggtccttggtttgatactggtcaggggcacatgcccgggttgcgggctcgattcccagtagggggcgtgcaggaggcagccaatccatgattctctctcatcattgatgtttctattatctctccctctcccttcctctctgaaatcaataacaataaaaaaaaatgcattcaaaggtctaaaaaaaaccccacaaaaaacaaaacccacagatttacaagcaaacttttgcaatcttgccaactcgaaactgaacacagagagagaaacatcaatgtgagagagacacaccaactggttgcttccagcatgcatcagagtgggggcagggagcaaacctcaaacccaggtacacgcccttgaccaggactcccagagatactatttaagaaagcattctagatgcagtgcagaactttatggcaagaaaactcagtgcttatttagtttctcaaatagagggatttaggttgtttgtgaggtccagtttctgtgcttcaaaaaataacacgtgacttagagaggttttgagttcatatcaaaacatggatcatgatcctaatactcagaaccagaccatttctgtatttataccacataaacagattctaagaactctatccccaacacttaaatcaccggtctatggaattgaaatgaaaattagaatcaggtgaaggtttatgtttaaggaacatctgatccaaaacaaaatgaaacttaaggcttaaattctgttcttcctgagattctagtttctccctgtcattgcaattggccaaaactctttgtgtgaagaaccagctctttggaaagcttttaggaaataactttcagagactgtgttctgctaacatgccatgaaccatagctgcaggaactatgaccaggtctccaagtcattttatgcctcctacttggtgtgggaattctatgatcaaatcccttagcgttagtttggttgccaaccctggtcccttccaatgaaattgtggtaattagagtatgttaaacagtccagtggcaccaactgtgtagtttgtttggtgaaacattcagggcttgtactgacaagtccagagaggtgttaagcataagatcaagaggacaagtaggaactggagaagaaatctattgaaagctaattttttttcaggcactttgtctggcttttcatatatgtgtatatatatcctatataataaaagcctaggtggcattgtgcaacgtcctcacatgatatcatcacaagatggtttccacgacattgtcacaagatggccaccacaagatggccgccataggatggctagcaagggagggaagttgtgggcaatcaggtcggcaggggagggcagctgggagcaatcaggcctgcaggcgagggaagttgcgggggaccaggcctgcaggggagggcagttgggagtgattgggccagcaggggagggtagttggaggtgatcggccggcaggggagcagttaggcatcaatcaagctggcaggagaagttaggaggtgatcaggctggcgggcagaagctgttaggggcaatcagacaggcaggcaggtgaatggttaggagctagcagttctggattgtgagagggatgtccgactgccagttgagggattcacatggattaggcctaaaccggcagtcagacattttccacgggggtcccagattggagagggtgcaggctgagctgagggacaccccccctcctgtgcacgaattttgtgcactgggctatacatatatatatatatatatatatatatatatatatatatatatatatatgtctcatctatttattcttccttaaatgtcctagaaacaactactcctgcacaattctggatgctaacaccatcagaaagatatttgtgatatttgtgcctggctggtgtggctcagtgattgagcattgacccatgaaccaggaggttacagttcaattcccagtcagggcgggctcaaaccccagtaaggggcatgcagaaggcagtgatcgagggttctctctcatcattgatgtttctctttctccctctcccttcctctctgaaatcaataaaaacatattttttaaaaaataaataaaacagagtgttttctggtttttgttgttgttttgttttgttttttgttttttttaagatacttgtcctcatgtgcctcagtcaggagacttctaagatcatgaattggctgctaatacctagcccctctctctggtctaacccatagactcagatcatctcatttcctcctggggacacaaacactccataaaggcagctcttctagggctctgagcaggaccatcctgacattgttttcactcctcttccagcctgcaagcaaatgaaaaacagctccatctcacaggagggctggggaaccttgataaagaacagatctccaattgccttttagactgaaataattggacctgttagatatttttgaaagatttatttactgcatttcaacaattaaggtgaattttataggcccatctctcgtgggtatatttgttttaatcatgaattaaagactataccctggctgatggctcagttggatggagtgtcatcccgaacaccaaaaggttgtgggtttgattcctggtcagggcacatacccaggatgcatgtttaatcccccgtcagggtgtgtctgggaggtaaccaatccatgtttctctctcacatcgatgtttctttctctctctgtgtcccttcctctgtctctaaaaatcaattaaaaacatatcctaaggtggagattaaaaaaaaaaaaaaagattagcgcacatttcccccctgcacaaacatcatgacccataaggttaacgcatgaaatcctttcatcacgaactaggattacactctattccaaatcaagccacgtcaacatagatgatgccagaccaccaaacagtgttttctcaggctctaaaagggcagagtaactgtcacccgtgggccatacgtgtggtccggtgggaagagtaagctttggaggatggaatccgagctcacgggctgggaggtccaggtccatcacttaatctcccgggaacccggtgctcagtgtcaggaggctcttgactcacaacagagtatagtagacaacaaagagagactatacattttcactggcttgaaaattcctagaagacagggcctgcgtgtttagcttgtagcaacaatgtttatcacttatctaataaatcctatattaacatgttcatcagaaaaaaacacctaaatgtatcgacaatcaagtatacctgttaagattctccttgcaaaagccacatagggaagacaaaacaaaactcaattcacattttccaggggacattgttcagtgtcattgaaacaaagcaacatctgttttcctagaagttactatatatgactaaatattctaattagtatttctcttaggccataaatattttaccataattttaaaaacttgataaactaatgtaaaagatggctctttgaaaaaaaattaataaaacagacaaacatcacagcaagattgattaggaaaaagacaggaaaaaacacaatgctagtatataattgcattagaaataaaaaaagaggctacaaatactgtgcatatttataaaaataacttgagacaacaaatataaaactaaaatttttctaacatatataccttttgtttttaagaagtgaagcaaggcagtgctgtggtgaagctggtatagttcatactgtgagggcaggttgtttaccctctttaagcctttgctcatttgtaaaatggaggtggtagtgtcctcacttcttatttacaggattattatgacatcagtggaattaatactgtacatgcaaaagaaatttaatctaaggaagagatgagagagagagagagagagagagagagagagagagagagagagaaagaaagagagagagaagacactagtagatattgagaataaatatgaatgaagagtctatgaatcaggctgacttggaaggaaagaatggaaatctgagtagaaccaatgatgactgagaagtatagcttttcccccagaaggtctaccactaacttcaccctcccagacaccagcaggctcatgtcgtaaggagtcccggtctcttagtttccttgactggggcagggagtccttaactcacttggacaggagaagggaagcatgaaaatattccttgtgttcccagtagtttcttgggcatattaagttagaaagacattattaaacatagtgttgggtgctagaatatttctggtgatgcttaagggacatggtaaataaaacctgagagtgaattctggcttgcagctgattatgggatggtattagatgcctggcatcttaggggttaaaaagtctttggtaggccagccagaaagtttaataagcatgtaaaacacattccaaacaaatgactgctggaacataaccctgtaagttggggactgcctgtttttataacctttgccaaagttactaaaattagcagcataatcgaaataaaaaaattatatattcttatgactgaacagcatggcagcatcttcaaacccagagctgaattttaaagtcaaaattattttttgggcattttctagaaccaaagagaatgatttggcaagccatcccctctggcaatatgaatggagaaattttgcttttatctttataattaaagtagctctgtgcagtttcattcccagtgtgaacgggggcacaggtggtatctgctgatgttacaaaacagagaaatagcaaatatgttaggtaaaagacacaaacattctgtttctcacccatctccttgatttctcaaaccaaaatgctaacagttcagaggatcattttgtatatgtaatggaggaaagcactggaatgtttagcttagaaaagacttcttataccagggaggaggaaagtcattaaatagaagtgacgttctttctgatttggtctatggcagtggttctcaaccttctggccctttaaatacagttcctcatgttgtgacccaaccataaaattattttcgttgctacttcataactgtaatgttgctactgttatgaatcataatgtaaatgcctgatatgcaggatggtcttaggcgacccctgtgaaagggtcgttcgactgccaaaggggttgcgacccacaggttgagaaccgctggtctgtggggatttagtggacacatctaagaccaatggtggtagattttctccagtgtaggaaaggttaacagaattcttcaacaacgagatagtaagtttccttcctttattcaaaggacgactatcatgaatcaagtacaggagattcttacactgggtagaaagttaaagcagatggtctacttttccaatactaaagttctgtaagttcatgaaaatcataataactagtccctctttctttcccaagcaatatgatatcctcaaaattgccaatgaggaaattcaagtggatgctaagaccccagttggtcatacaattgtgcaatcaagttttaagtgtttctgatggagccagccaacctgagactgcccatctccttactcatggagatgtagttttggaaaccaaaatctgtagtaggcaaaaactggtccaagccatgtggctttccaacagggtatgattataaaagaggccagaattattgtagctcagaaggggaaatgtcagcggaatttattatccttataaaacatattctttgatccttccttctatcgtattgcacgcctgtttcttggactgactagtggtcagtgaggtcaagataatgttgtatagatcacattgcctttattttggctttagagagactaagagccaagattagtctctttttagaatagttattatttaggagatgtaagtttttcattgttggaagccatttggagtgctctaataggtggcagttgcctctgcctgatctttgtaagtgatagcaccagggcgttgcagtgtgctcaggaagaaagtcacaatggaagtctatttgtcttctttacaaacccaccacacttgtaattattttttaaatatatttttattaatttcagagaggaagggggggggagagagagagagagagagagagagagagagagagagatcaatgatgagagagaatcattgatctgctgcctcctgcacaccccctactggggattgagcccacaacccaggcatgtgcccccaaatctgggacccttcagtccacaggctgacactctatctatggagccaaaccagctagggccacacttgtaatttttttttttttttacatattttattgatttttttacagagaggaagggagagagatagagagttagaaacatcgatgagagagaaacatcgatcagctgcctcctgcacatctcctactggggatgtagcccgcaacccaggtacatgcccttgaccggaatcgaacctgggacctttcagtccgcaggccgacgctctatccactgagccaaaccggtttcggctaattttttttatcaacattggccgtccatctggaatgcaatttcatgagagtaaggccaaattatcttgtgcagcattccatttccattagctagcacagtgccagcactcaaaaaatatccaattgaaacaataaatctagcaaggaaatgatgacccgctccctccaatgctctttatatcttccacatcaattcctctcccccttacacacatggggcaggatagtcctaagaataaaattatattggtttgtatattgtctacttattccataaacacctatgcataatatttcatttgatctttgtaataatacttcaaggtagttgacagatattattattattgctattcccatctttttttccatatacaaaactgcaggatttaaatgaccatttgagggttaaagtgctagctagaggcaatgctgggtcttgatctccaggagacaaagcagtgtgtgtagcaatagcaggactaaagcctgtggaattccaactccatctgttatctatgtaacctcggaaaaatcctttgcatttgcttagctttagttttttaaaaatatgtctttattgatttcagagaggaagggagaggggagagagagagagaaacatcaatgataagagagaatcattgctcagcagactcctgcatgcccccaactggggattgagcccatagtgctcaaccactgagtaaccatggccaagcagctttagtttttttaaaaatatatatttttaaatggggctaaagaggtaaaaagggaagggcagaggcaatatttatcttgttcacctcatggaattattatgagatggggataacaaaggtcgtagggtgtaactgtgagatggtgtcactctaagaagaataatacttcccaacagagatgaatagatggggctttggggcccgagggtccgagcaccatgcctttctagcggtatgacctcaactgagttcctgaacctttagtttcctcatctttaaaatgggaacaataaaacctgcctcataaggctgacatgtggattaaatgagattaagtacagaaaatagaagtaactaactgtatgataatagtggtagcagaataatttaaatagtaattttctctccagttgaagaaactgaggtttagaagcttactagatttggtttcagggtacccagagagcagagcagagacttggtagaccagtgtgaagtcttgaatttgcttcggaagaacagatctggtgagtggaagctggacgagaagaaacttttttcttttcctctccatcccaccagctccacccacctcagtccacaaggtctatttctttaggatttgggaaaacaggagccactggagggccaaggagaaaccagtacaagagcgatttccctcctttattgctgtcagaatcccaagaaatcgtagacaagagattggatgtttagtggtgccattgcttaaagcccaggttttccccaattactgggacaacatttccttccctggaggacctggtctgaatttctggcccccttaggcaactagaagtaaacctttgagataaaatcctcttgtatgttggtgctccttctgtgccgggagccggtccatgcttgctgtttcaagggacctggcatatatggcatactgttcttaatatgtttgctcaccttcttggcactatgtgttttaaccaaggtctctgagaaagggtgtttccccaggtagggattttcccctgaagttagggagggaataaaacctcttaactaagtgccaggcgggtaattaatcactttaactatgaacagtcatgcttaagctacataatctttactccctggaatggagataagaaacaccctaacctttgaaatagagattgacaggattgaatcaactggtataaatacagatgtaactagacagcaagacacagaacttagaacacagaacttagaataagacagaacttagaacacagaactaagaagacagaaccaagagagacagaaccaggaggcacagaacctacacagaacgttctctagagacagaagaacctcactggagagaacatggcaaaagatcctggactgaacctgactacagaaattggcaagagaacctgactagaacctggtgactgaacctggctggagaacctagcgagggaacatggctacagaacctggctggagaacctggagaacctagcaagagaacatggacacagaacctggctggagatcctagccagaacttcgctggagatccagaccagaacttggctggagatcctggatgggctgctgatcagctgaacgctgtctctgtgtctttccttcttcgccaactccgtccacacctttggggacccctggacctgctggggttggaccccggcacttctgctggttggctgaaagcttactatgacagagcaacgtgactcagaaaattctgaaataaacaaatagtagtcatttcctgggtcataggagaaagtttccaagaataaagaagaactgtagtcatgtgtggcatttgtattgcacaataattcatttaaaaatagttcaaatctcccaggaaagggagtagacactggggaagcaaagagcatccaaacagtcaaatagctgggccacttaactgctctgagcttctgattattctgtaagttgaggattctccgtcagaattgttttgagaattaaataaaataagataatgtaagctattcatacattctaaaccactatacaaatagtagcaattatttaaatcttttttcttctttccatgttcattgccctttacctctgttacagactttaacatattgcatgagagaaaagtttacgtccagtttcctgactggaatgtgattgactcaagaagaaaggctattacactttttatacaacccacaacccaaaacactgaccagcacatacaggtcagtgctttaataagtaccttttccctttaatttttttgaaaaccagaactaagtgatcctttctagtctaacatttatttccccaaattccctggaaattccacatagtgacttctgagatttatgagttgattgctttatcactctctgggcttgttggtgtaaatgaatttaaagtagcttctcgccctgaccaggtggctcagttggttggagcatcatcccatgcaccagaaggttgtaggttcaactcctagtgagggcacatacttgggttgcgggtttgatccctagtcagggtgtgtattagaggttgccaatcagtgtttctctctctcccccttcctctctttctaaaaatcattaaaactatgtcctcggggaataattaaaaaaacaaaacacataaaaaaaaaataaagcagcttctccaccaatatgtcagctgattttgatctgcaatgatctgttcaaagtgtaaagtttatgattagaccttccttaggctcctgtttgtcaaccgttttcatctgctaacttcacagtatcccctggcagtcaactgacccttcaattctccttctccactctgaacactacttcaaaaggtccccttctgtgggtgcctcccactaataatttatcttcaatttccagactttttttttttttttacttctccttcaccagtatctgacattggaatctggaaagagtggcagcgttaataataaaatgaagcagaatccttggacctgtcatcattaattgctttcaaagtctggcctgtctttatgagatttgtttctttatttcctctttgaaaacaaacctgggttattgaacatctgggctggaatttctgctgaagaaaaacattcagaggctcttgaagtctgtccaagctctcaagtctttttcgtaagtggatagaaccacttgcttgagaaaagaatcccccccccacccccttcccacttcagtgtttttttgtcatgtgtgctggtgagcaactttcattgtaggtatgagttacatatggggatagagagtgataggctaaaggatggacttttgtactgtattgagtgatttcatgggaagaggagtttataggtcttttaattttgaatcataagatcagatgagaatatatagttttttaaaaagccatgtatggatttgcaaattactcgtgattaagagagaaaaatcaggacatgttcaatctgtgttttaatcttcttattcatcacagtcactatttacttgtataaaacgtttaacaattattcctgttgcaggccactctcttaaagaaaactgccaccagttttgtgtttctagcatcagtgtatttaaaatctaacccagtaaaagtcacaacaggctgagcttcagggatagtttgttggccacatcttacatgcacctgtgttccactctggactcaaatgaaaggcctcccaatagggcatggaagccatctttccagggagccatagaaggggccagatgacacaaaggaagtgcagggagtaacttggatcaatgagaaacaggaggtgggtgagttccttctcatgaactgccgcaaagcacggccttcacagagcctgtccacaggtaccccgtgtggccgtgcagaggcacttgccacattacctgctgggtttctcctgtctctttgggaaggaagcacggcccccccccccccaccccccgccttacttctcttgttcttcactctcacattagcaagttaactctgttttccagggaacccaggataagatggctattggttaaaaagatctactagccagcacactgaaggttcacttcaatcctggataattttgtgaatctgctatgtgcaaggcactaggttaggtatcctaagggaagcaaaggtgaatgaataccattcaatccctgaccttaggtgccaatagtctagaacaaccgtgggcaaactacggcccacgggccagatccggcccgtttgaaatgaataaaattaaaaaaaaaaaaaaaagaccgtacccttttatgtaatgatgtttactttgaatttatattagttcacacaaacactccatccatgcttttgttccggccctccggtccagtttaagaacctattgtggccctcgagtcaaaaagtttgcccacccctggtctagaagataaaacaattgcaaagtcagcatcactctgaaagaggaattcaggactgttaggctcccctgagagcaatagaagccaatgatctgttacacagggaattgaggacctcatccacagtacattttataattattactctggctgctgtgtttaataagcacagaagaaactccatttatagtggctcaggtgggaaacaatgatggtggtgtgaactttgatagcaataacaagaatggaatcgagatagattgaagacatgtttagattggtaatgattatggatttgatattaggaatgagagagaagacagtatcaaggataactctatgctgtttgttttgaggatctgggaaaatgtgaactattcactgagatccctacacagaaagagttttggctaagaagataatgaggtcacttttagaaatgctaaatgttaggaatctgtaagctatctttataggcagatggataatatagacctagtgctcagaagagacctagcctaaagatctgaaatggaaattcatgagagtctcatttgatgtgtgaatgggagttgacaaggtggctggtggaagtgtggcctgaaaagagaacctaagaaacatcaagtaagtattaggtagaggaaaagaagcttgtaaagaaaaatccaaggaagtgcaaactgaaaagataaaaaaaaaaaagaaaggatgtgacagctctggaaatgtgccactctgatctccctccaagaaacagctttctgtttaactgtcaagaagacatttgctaccagcctctatctgtagcacatttgggatctgtcacatgtttgaaccaaggccctaatcttcctggtaagcccacagctaatggatgagcatggcaggggcactagggcctggctgttatgcccaatgtggggcccctctcacaagccgtcttcactaagagttccccactgggttggccaagactttgtccaatttgcagagaatgtgaggctgtatctaccaagtcctgcttcctctctctttatctttcacagatgttacctcctgcaaaccacatgcattcccaactctgtctcagcatttgctccagtataactgaacttggttaatgggtcatttgatttggtatgtagatgttttttcaatatgtccacctaaaatgaacatactgaatttggctgcatgtggccttgaaagacagcagcaagagaaaatcttcctaatgggaggatttcatggaaaagttgcctgagataagactacatatggaatcgtgagcaaaaggattgcccagctagtcaggggcctgggaagaaaaagttaataattttgcagagaaaaaaatctgggctagatgcttgtggatgaatatatgagagtgggtatgaaatgtgaagatcttcgtatcatatattaatgaccaccaaagcttggccaccacagaagaagcattgaatagccaagacaaaattgattagttgacagtagccatcttttgtcattggccgctccagaattagcatgattggcacattaacagaatgaacattacatgtcaatagcatggactcccctacttatcaaggctgatctactactactatcattgagagtccaaccagtttgcaagagagatcaatgtaacactattacttgaggggaccacatggccacttggtggcaagatgaccactttgagccttttcttactggaagggccagtgatttattgttatagtagtaggcacttattcttggcagcctagagcctcagctagcaccactatctgggagatttcaaagtatctgatctaggcatacagtctcatataacataccatctgatcatgagactcacttcacagagaaggagatagggaggtaagcccatggccatatcaagtgccacacaatccagaagcaattggttttacagagcaataaagtcacctgccaaaggcacatggaagtgctaacttgtaggtaatacttctgccatgataggataccatcatgcagattacagaatgatttacaaactatttggatgttgtgtcctgttagcaagaatatataggtctaggaaccaagggacagaagcagaagtggtcccagttgccattatggtcaatgacccaccacggaattctgtgcttcccatccccacaattctaggctctgcagggaactacaagctatgattcctacctggacattttggattccttatgttcagggacataggatggcagtaattgatgggagtaactgattctgatcaccaggaagaggtagtagacatttgttatataatgatggcagggggaaatatgtatagaattcaggaatccacctggccatgtcatagtacttgctcaattatgactaaaatagtcaattctagcaaccctagtgtgagaagagtatggttaccacaggcctagatctctgaggaatgagatcttggatcatatcagataagtcatcaaggccagaagggatgagagctggggaatttagaatagtcagtggaggatagagatggtaagtaccaattgtggtcctgagaccaactgctgctattgaaaatgaagatactagacacactataaaaagaaagcattgcatccccaagtcaccctacttttcttggtcatgagagacatactttctggaaagtgccaagtttcttatgaataaagggaattcataggtacgttagaatgtctattatctcacagaactgaatcagacagaacctgaacggatcctttcatgcttcatagagcacgtttcagagcttctggatttgctgttttagatcctggggatggaggctggttgtgaaatggcaacttggttatgctacctaagaagaccagccaagcattaagtagggacatctggagagtttggaaatactaacaggcttttcagccaaaatctgacattgaacagataaaatccttcttacagagttatggaccctattgggacagaaatacccaatagggtccagtcagaatttcggccactttacactacaaacagtaactccccagggataagtatctctggcagaagacaagaaatcctgtaaatctttaaaatgtcccttttgcatggaggacatgtgtttgctcttcttactaaggctgcacagccctcaagcctaacagctgctgaatggtccctgcgtgagagcttgacctctacaaactgatgtaatgcccacactgccgggtctgggtctcagacccactactgcattagtgataatagttaacttgtgatcaaagctttattctggtttaccaggtatttcatgtagagctgctagcattatctcgcgtgatcctcaaaaccactctgtgacgtagctgcagcagatctcattagtttgttcatcttgtgagttgagcaaatggtctcccacatagtgagttggtggagagctagaatttgaatgcacatcttcctagaaacccaagcccagagtgggctggaaagaaatagctgagaagtaagctctggtaaacagaaggggaagactactctatttctctcattgaaccttttttaaaaaaattcatagcaaattttctttattagcatgttgattaaattttttaatggagaaacacaataagacatagaagccaatgttattatgagaaaacccattacaaaaaggatactgtttgagttctgcagcttccctagaacagagaaaagtcctttgcataagtattggctctttaaagggtaaagagttaacggacaatgactcatgcattgctatgaagtcacctctttctagaagtgttgacgaagattgccatgggatgcaaaagggataagcggttggtgttcctcagccaactggctagaaacacttcactggccggggactcttaaaacctgtgacatggggaagcaatttcatggttctaagcctctgagaataagcatgggcattcttgctgttcagatggttagatataaggtgtaaggcatttagacatggagtgggactgctctctactccagtgtgtcagaaatgaatctgcctgaaacatcctgaaagtacctaaagcttggcctcttgacctgtgttttcccctcaggccacttgtctggctgcccacaccctttccatccctacagtgtgcatgaaacatgaaaacactgctaagtatgtaaaaaaagccaggcacagaggtcacatgtgatatgattccatttatataaactgtccagaatagacaaattcatagagacagaagcagattagtggttgcttgggcaatgggcagagaggggatggggagtgactggagagtcaagtgcagggtcttaccttccaccctggagcttttctgtcactatctgggaactctttcttcatttatacacaagaaacatggaaggttggtgcaattaacaccctgacccaggggactagaagctgatggatgtaatttccctttcctccctcctagagcaagggtcctgagatgcatagcatcggaattcacagggagtcccatgggatcagcaactatttgcttcgaagcagcagccgactctccctccctgccaatgtcattcccccatcctaccgttctgctcccccaaatcacacaccccagtaagaattgtcacacaggctctgatttctggagaacccaggctaagacattaactcttgatttcactcagactccacacagtctgttaggaaatcctgttggctttgccttcatcataaaatccaagattcaaccatatttcacctccttccccgctgttaagctggtccaagccattgtcatcacttactgattaacaaacacagttgccagggtgatcctaataaaatgtaaatcagttcatgtgattttttttgaactaaatatcctattaagcttcttatcccatttagaacatatacatatttaatgtcttatagtgtctacaaagtacatcatctgtcttataacttctctgatctcattttccataaccctctctggttcagccacatttctctctttattacttcttaaatatacacatttctcttcttgttacttctaaaatatacatgcatgctcctcccatgtactcctacctcgaggtctttgcatttattcagaatttctctcccaagattgatattcaaatgtcacctgctcagtgaggccttctcggaccatttaaaatgcaacttccagcattccttctccctctcccttaatttttctccattatacttatcaccatctgacattctatgtgtattattattattagtattattattatctggctatttccccctgctagaatgtcagatcaatgaggtcatgtattagatatcaccaatgcctaaaatagtacctgtgtatataggtgatcaataaatatttattgaaaaaaaagaagaatggtaggaaggaagaaaagctgcaataaaatgccacctgtccagaggtaaggtttctggtcatctcaaatccttggatggccacgtagccagaaataactgagaagagtgttgagaaggaaacagagcagtcacaaagcccactcaacactgttatgttcattgttttgtacagatcatttccctgaggtcaggtttctcctttcccgttcacaaaagatggaaataacaaaatacggagtgacagtagctggcagtaagaagagacgctttcaatccctgctctggagtaattacaataacactcaggagtgggtaaaattaagctaatgcctccaagatgtaagcccaaggcttcacatatcatataaatacagggatcaggtttttcaaagaaaaactgggacacagggaactcttcccaggtgcaagaggggtgtggaaaattgagttaagatgatgatgaaatatttgagtttctggactatcctgagggtaaaatattttaaatagggctggagcagaaaaatccagggcatatttacatgtcactacatgtaagagaacaacatttataagatggtttaaaaatcacgactgctgctttgtcattttaagaaaaaaatttttgaaacaccctgaatgttcttaaggattcaaccaaagtcaagcaaagtaagtagagtcttatacctaaatggaaccctttaaaaatccaatttgcagctttgaacacatgggaccatttcccccatacatttccttcaactgtgttttaattgcaccaatgaaaggcaaaatggtaattaagcatcccacccagcgtcagtgaaaatggaaacagggccagtatggagcatttaatgtcagatacgaggcatcagaaacttgtaaaatctgtttgtaaactactttaaaatacatttagtgaacttctgcatgaagagcctatttaagggctaagtgcaagacatcacgaggtaatacagtgtttcagagaaaaaatatcacatccgaaggtcaggcaaatttttatttatttaaaaatatgttttagtgttctttatcctatataataaaagcctaatatgctaagtgtctggtcatccagtttgccattcaaccaatcaaaacgtaatatgctagtgatatgctaaggctgctcaaccgcttgctatgacatgcactgaccaccaggggagcagactctttgactggtaggttagctggctgctggggtctggcggatcaggactgagagagatgggaccgacacgccctggagccctcccagggtccctccctggctggccaacctcccgcatccctccctgaccccgattgtgcactggttgggtccctcagcctggcctgcactgtcttgcaatcccagctgagaggacctcccaccccgagtgcacaaatttcatgcactgggcctctagtaataaaaggactgagtcacatttaataccaaatatacagttattaaacaaaaatgccaaattctcccaaaacacaatttcttgacttttttgggggtggggttaagggcacctctggaaatctgagcaaggttatagattcagcagtttacttgtattcaaaatttcatttcatcacagattcccaggaggactgaatggacccccacgaagcccatgaacctccaggtaattaatcttcatctgaagggtaataaacatactttgtacaacaaggaaattttaaaataatcaaatagatcaattcaagttaacaatttctcagctctggagggaaaaaactttttcaattgattgataaagcagataaaattcactcacttaataatatgttttatgtgtattactatgctatcagagctgaagtaagaaaatagatgccattttgctgcctgtaaagtcttgtatgatttttatggtttcccatcttacatgaaaatcctttagccattttgagtttgtttttgtgtatagtgtaagttggtcatctagtttctttcttttcttttttttttttgcatgtatctgaccaaatttcccaacaccatttattgaagagactgtcttgactccattgtatgctcttgcctctcttgtcaaatattaattgagcataataatggcttgggtaaatttctgggttctctgttctgttccactggtctgtatgtctgttcttgtgccagtaccaggcagttttgagaaccgtggcttggtaatatagcttgatatctggttttgtgatccctccaactttgtttttctttctcaggattactgtggctatttggtgtctttttttattccagatgaatttttggagagtttgttctagacctttgaaatattttagtggggattgcattgaatctgtagcaattcctttaccgacacagctcctagggcaatggagactaaggagaatataaacaaataggactacatcaaaataaaaagcttttgcacagcaaaacaaactatcaacaaaacaacaagaaagcccactgcatgggagaacatatttgccaatgctatttcagataagggtttaatctccaaaatttacaaagaattcatacaacttaacaaaaggaattcatataacttaacaaaaggaagataaacaatccaatcaaaaaatgggcaaaggacctaaatagacactttttgaaagaggacatacagaagggaatccactgtgacttttcaaaactttgtggggcagtagagttctattgccccacaaaattttcaaaaatcagtttgctactgttgtagatggttgtagtcattatttaaattagcataccactttacccatacttttaaatgttctcttctctatctcagaataacttaattcttcagaatagtcccaccgccttcctccccctaattgtttttaaggtcagattctccttgctcctgtctctatccagttcttagcctttgtggctcagtggattccctcttgagcatcacagacatcagaaagcacctaactaaaccctctgttttacccagaaggaaacttgggttcttctaaatccatgatctcacctaatttcaccatcagtgagaggggggtaaagagaatgcaggtttcctgactcctcctccatcgctctttctctgatgttaccctttctcctcatcatttggtggaattgacaggatgaatccaaattcacttccactgtcagagcctcatttctcttcaatgacttggaattctgccacctttaaagaagtccccgaagaagtgatctctctggccttctttatcctcacagcgaataatgagactagcatatttatgttcggtcattcactcacttaaacttttttttgaacatcaaagtagttctaaggttgaatgacagggtttccgtgttagaggagctcgtgtcctacttggtaggcatgcaaagaaataagttacagaaaagcatgccatgtttaaggactaggatagaggttgtgcacagaatgttggggggggggggggagctcacccagtctaggggtcatagatcaagagaggcttctggaaagaacggacccctaatctgtatctttaaaaaatatatgcttatattgatttcagagaaaggaagggggagggagagagagatagaaagatcaatgatgagagaatcatccatcagcagcttcctgcactcccctcagagcacagaacctgtactgcaacattaatcaccaaacaacattcaccactatttaatgtccctatcagctacagtcctgagaaaatcctgaagtgcaacttcatcattgcttttcatgtatctacattaataacttgtattatcttacctgaactaggtttaaccagcctaggttgttttactatttttttttttctttgtgctccatttttaaccacccaagaaagcctttttcctggcttttgtctgtaattatcctttcaatggtcattgatttaaatgcctcttaaggaataagcatacaatagaacttgttgacccttgtttttaatttggcaacttttaaaaataaattttatctattacagttgacatacatattacatgaggttcaggtgtacagcatagtgattagacatttatataacttactagaagcccggtgcacaaaatgcatgcatgggtagggtccctaggccaggccagtgatcaggaccaatctgtggggcgactggtggggtgatcgggggggcccccgctggcacccatcttggccggcctggtgccgctcaccagctagccccatcccctgatcgccccatcccctgatcaccccgtcgctgcagccagttgcctccctctgcagggtgacccacaggatgatcggggggatcccccactggcacctgcctaggctggcttgggacctgcaggctgggggcagctcctgcgttgagcgtctgcccccctgtggtcagtgcacatcatagcaaccggtcgtcccgctggtcattctgctgtttggtcaatttgcatattaggcttttattatataggatgaagtgataacaccccaataaggctaataaccatctgacaatttttggcatcatttaatatgcagataaaatgcattttatgaaattttacctctttattcctctcccatgcctatggcaaaggaaacttctggatccactatgttagtgggcagttaacctttgagaaagtaactcaggtacttcatacaaagttaccttcatggaaaatataaagggtatattttaaaaaagaatacctgactaaattttttcaactatttgatgaaccagcaagaccagctaagataatttcccattttggaagactaaaaggagaaatacattttttttgcaaatttttattacccaatatcaaatagaaaagtcagttcttgaattgctactaatcttgttcatacctgaggtaaaaggaagatttagcctgggcgaggagcagggaatatgcagaatagctcatcttgtaccaaagttttgttaccgtttcctgtgttattaaataactatgaggtcagcaatcccaaatttatgggattgagtttttattcattgcgcgcgcgtgcgcgcgcacacacacacacacacacacacacacacacacacacacaccctttggcctgttctcaagttctttttgtgcacttccgtccacctttccggctgcccttggcctctgggacctaccctctcctctcccaggtactcacagagtctgtgtcccgggcggtaggactgggatgcgatggatatccttgcaggtgactctgaagttgtcctcctggtggcactcacagggcggagaagcacaccctttcccccctaagctcctgggcaggccgagaagcagcgccagctgcagtaggggcatcggcctcattttccaggggtccgaggccatttcttcttcctccactatcgcctcattctcagccctctgtgctccgagctccccgcgcggaaggagcgagggaggagtgggagaaagaggactcctggtggttgtgacttcagcaccaaagaggaggctggagagggcaaagaggctctcaagtgttctgtttccctaggcaactctccacgcaaacaagcccattggctttactttcctagccctgagccacgcagcccgctctgtctgttccctgacacttaacaccagtccctgctgtccccaccctgctttccagccagcctcgcgcgttccttccattagctctttccagagcctagttcagaagcgccccccccccccgccgccctttccttgtcgttaagtccagtgggccaccttttcccgtgggtagattccgaaaagcgctgcctgtcaggacccctctcccccgctcccccttctcccccaaggctcgcacgcactgcagagaaaacttcccgcaaaatgcaccgtccagggcagacgcgggtcaagatccttctggcctaaggtgcctctgaggatgccagcctgaggtgcggagaagccggggcgcaatacctctggcggaccctcactgctccccaacttcagcgcaaacccgaccgctttgcacagaaattgtattgaggagtcacctggaggcgtcagctcacattgcagcaggcggacttggctctaggcgggccgggaactaggctctggggccatctgctgggcagaaccaggaatggcaggaacaggtctggtgctctggagccggccttccgacctggcttgaagcctaaaggtaaattctggactgccaggaatgttattgcatcatatagctccgctttccccaaaatccccccaaagatgggaagaaaaataacacttaagtggcacaccatcatctacttaccattcttcacacagtagccaaaaataataatttaaaatataaatcagattgtgccatttccttcttaaaagccttcagttactaattcttcttgggatgaaaagaacatcaattcttcacgtactgtgtaattccatttatatgactttctgggacagaatggggggaactatagtgatggaaatcagaacacgatttaggggagactgattcaaaaaagataggagagcactcaccagggttatagaaatgttctatatcttaattagactggaggtaagagaatgcataatttttttcaaagttcattggactgtatgtttaaaatttgtatatttcaatggttttagggctttattcataattaacccaaactggaaacaacccaagtgttcctcaactaggcaatgggtaaacaaacagtgatacatccatacagtggaatattatccaatataatcatcctatataataaaagggtaatgtgcaaattgaccctaatggcaaaatgaccagaatgaccgctggaccagtcactatgaggtgcactgaccacctcttggtccctttccctggccagcaggctctgatggcctgatggccgtggcaggggtggggctggcgagtgggcaggaacagccaacctctcggtcccttcccctggccgtcaggcaccgatcattcaatggcaaacagggaaccgggggttggtggcggcgggggcagggccggctgtgggcagctggggaagatggccttgatcgcaggccaggacaaggaaccgtatgtatgcacgaatttcatgcaccgggcctctagtttttcaataaaaaaacaaaacaaaaaacagccctggtcagtgtggctgagttggttggagcatcattcagtacactgaaaggtggatttgattccaagtcagggcacatatctatgttgtgggttcaatccctggttggggcacatgtaggaggcaactgattgatgtttctctctcacatcaacgtttctctctctctctctctctctctctctctctctctctatatatatatatatatatatatatatataaaatctcactccccccttcctctctctaaaatcaattaaaaaaatacataatcttgcttttactttgaacacttttgttaacatttcttgtggtacagatctgttgggtatgcattattccatcttttttgtgtctgaacaagtattaattttgccttcatttttcaaggatagcattactaggcacagagttatagattgaaagtatttttttcctttcagtactttaaaaatattgctccactatcttattatttccaaggacaaatgttctgtcattattttcttttgcaacatgcttttttctccctcagaatgcttttaagactagttatcgctggttggaagtattttgattatcatatgctttgatgtactttcttcatatttcttctgcagtattttgaggttcttgaatttttgcatttatgtttgtttttaaaaatgttttattgattttagagagagaggaagggaggtggagagagagagagaaacatcaatgagagggaaatatccatcagcttcctcctgcacaacctctattggggactgaatccacaacctgggtatgtgccctgactgggaatcgagcccactatcttttggtgtactggacgatgttccaaccaactcaactatactgctagggtgaatttctgtttttcgtcacttttggaaaaatttctgccattatttctccatttatttttatgtccccttatgtctctctactctttccaattattacacgtatattaggctaattaaagttgttctacaaaaaagctcatttatgctttttttgtttttgttttttgtttcattgatgcttttttaaattacaaattaattttctctctttttcattttgcatagtttcttttttatatcttcaaattcaatattctttttttttttttttctgaaatagttcatctgccactgattccatcagtatattttttatgtcaggtgaaatgttcatgtctagaagttcaatttgggcctttttcatatttcccctgtctctatgtaacttttgacatctaaaacacttttgatgtctgtgttagactcctagagctactgtaacaaagtaccacatacttgatggctgaaagcaacagaaatgaattcactcacagttctggtggctggaagtccaaaattaagctgttggcagggtcatggctccctctgaaggttctaagggcgattccttccctgcctcttcccagatcctgatggttgccagcagtccttggtgcccttggttcgcatcaccccagtctctcctctgtcatcacacagtattctctcttgtgtctctgctctaaattccctctttccatgaaagcatcagtcactggattagggcccatattaattcagcatgacctcaatttaacttgcatatctgcaaacaccctgtttccaaataaagtcacaatccaggtattagaacttcaacttatcttttcaggggacacaattctacccctaacaatgtccctgtttgataactctaatatctttatcagttctgggtaagtttcaattggttgatttttctccttaaaatgagttgcatttttcttcttctttgcatgactggtaatctttatttggattgtagacattgtaaatttcacctctttgggtactggattatttgttttcatagaaatatttttgagatttgttatcagacgtgggaaaattacttggaaatagtttgatatttttgggtcttgctttcaaggcttgtgaggtgggatgggaatagcatttaatttagcaccaattactcctccctcctgaggcaagactcttctgagcactctacataatactacgtgaattaagaggtgtctccatccggctggtggaaataatcatcattcctggccctgtgtgagtgacaggtactttctcctccccagtcttggtagatgcttccttctccagcctccgtttcttcacgtattcatctgaatattccaagaagacgttccctagttctttagagttttctctgtatgtagctctcttctctttgctactttgtccatctacactggttttcacaaactcccatctctgtcttgtcaactcaaagcatccacggagctctgcctgggttccttctccttgagccatggcctggaaattctctcaaggtaggaagttgtggggatcacaaggctcatgttgtttctttcctgtctgttaggaaatcactggcctttatataatgtctattgtctgaaaaagcattgtttcatatgttttgtatgtttcctttttcttttttaaaaatatttttttgttgatttcagagaggaagggagagggagagagatagaaacatcaatgatgagagaatccttgattggctgtctcctgcatgctccccattagggatcaagcccaaaacccaggcatgtgccctgattggaattgaaccttgacttcctggttcataggtcaactggctcaaccatgctggctagtggtgtctttttactttttaaaaattctgggtgcagggaaagtctgctctctgcttctatgctattccatctttgctgggaacataagtggtatgccaaaaatctgtaacattttaatcaagacttaggcaacatgaaattggctcagtggtggtcataatgtaggtaaaatcttccatgcttacctgtttcatttcaggaaagtggaccaaatcttcagggtaaccatctctatatataaaaagccagtaactgaaacactgtaactaccagaacgaccagccgctatgacgcccactgtggccagagaaccggcctgatctgggggtggggccagctgaccaatctcctgcagcccctccccctggccaaccccacccctgatttccccctctaccctaatagggggcagggccagccagccaactgcatgaagccgctccccctggctggcctcacccccaatgggtccccaccaccccaatcggcctgaggcccctccccccagccagctctgtccccgatcacaccccacacaccaatcgggggtggggcttgcagaccaaactcccatggcccctcccctggccaatgacccctgattggcccccccccccccccccccaatcgggggcagggcctgctggccaatcacccacggtccctccccccagctggcccgaccctgatctgcctgattggggcagactggctggccaacctcctgccatctcctcttccctacaggcctggacccaatctgcccctattggggctgggctggctggaccccacctgtacacaaattcatgcactgggcctctaatattttaataaccttctcaacaaattgctatgataatcagtaaggcacttttctttccttagcctaactttgaaactggggccaataaaagcatgggatgagaagatcaaccagtttaagtaagagagaagtgtttacattctgatccattaaccacaaaaatgcttttaaatataacagatgaatgagaatggcttaagaacattacattttccttcttgtagaagaattgttagcatggtccagatatcagaaagtagtatttagcatggcattactgtctagtgttttatccaccccccccccccccccacacacacaaaggtacctattaaagtggagcacaggctatctgagttagctataataaaaatattttatgattttggatttgtgcattaatagttattcattttgacttaaatgcaaacacattgctgtgttttacatttgtgatgctcttgacagtgacatatacctataattaataagtgtgtggctgaaaagaatattatgggatcaatggcacacatgaatagctgaagatgattccttgagtagttggcaataccatctttgcaacatcttgtcttctattttaactttcccagattttcagttagcttgaaaagttgatgcaggaagagttaacaatcattaatgatcattttgtgctttggttcagagagaattttgggtagttccaattaggatgttggagatttctctttaaccttacccatagcatcccacttcggagctctgtcttccttcttatcccttataattgtctggtgatattacaaggaggctcgaccatctagtggctagatggaacaatgtggaatggaacagatggttactacttgtgctggacaaccactgggtaaaatgcaggctgtcttctcttcacgccaatgcgcggacagcgaggtccagactatgaatagtacttgcttgagtagaagctgagcagtctatggacatgggctttcctccaccaccttcaggtctgcattgcacccccagccccgaaatctccaactctccattctgggactcttttctctgtttcttatcacattcccactcaggaatcccttttctcttggcactgctcttcttcatattttcttgactctgagcaacatgagggcagaaactaggttgttattattctcattttcattacatttcaagtgtctaatataatgtctggatcctagaaagattcagcatacatttgctgaattaaatgaatgagtacaattgttttttttagtacaattgttttgaaaaattaaaatgtaaacaaataaaggtactctaatgcttctgcatgtgcatggggcaatttaatgactgttcctatttatgttaacatttgtgtccggtgcagtgtattctcttttcttttcttctttcttttcttttctttttcttttcttttcttttcttttcttttcttttcttcttttctttttttcttttcttttcttttcttttcttttcttttctttttctttcttttttctttcttttctttccttttcctttccttttcccttccttcccttcctttcctttcctctttcttttcttccttcccttcccttcccttcccttcccttcccttcccttcccttccttcccttcccttcccttcccttcccttcccttcccttcccttcccttcccttcccttttctttttttcttttctttcttaatatggaacgcttcatgcatttgcatgtcatcctcgagcaggggccatgctaatcttctctgtatcattccaattgtagtatatgtgctgccgaagcgagcatgagtgtattcttgaatacagctgtgagcaagcaacgtgaagacagatgcaaatacataggtatgtccttagaataatcatcttatgttcaaaccggttataaaataacatctacctcacagtattggccagccaggaaaaatattttaatgcttctgatatatcaaatatgatataatagatcataattattaatgtgtgtgtgtgagagggagggagagagagagagagagaggcagagagagagagagagagagagagacagagagagagagaagggaggatggaaattttaacaggttaggtccctgtgtttgaaaggcttagaatctaatgtaagtaccaacagggaatggataattacagcacacaatgattaggatagggaatccatgtcgttaaagtgatcttgctttatctgtgtaggaaggcttcacagataaagtaaaacttgactttagccttgaggaggaaagaaagcatcaacagcagaaggaaaggaccatcttcgtgacgaatttggattttcacttcttcttagcttttccaaagctcagttccttgttgaagtttttaaagttactttttcgcaattgaaaccgacttctctgagcggactatgtctctttcaggttccacaataagcggagagatgacaccctggcagcagttttgaagtgacattctcaaattccacttttaatttgtcatcagtgagcttactttttccaggcctaaaaggtgtgactagataatcttctgtttccttccggatctaagaatttgtgaaccacaagacattgggcactggtattattacacgaaggggattttaacatttctctgctggaaattacacctgcctgttccccaaggaataacaaaaatatagtctatgttagtattgcaactactttgattttttttttaagtaaaggaaatatcttagactttcctgattaaattacagtctgggccaaggcagctctctctctagctggtgtttgtcttcaatatacgcttctggccctttaaaaaaacaaaacagggaaagagggtgcgtcctagggcctcaggtgccgacgaatcctgcttcttccgggaaagtcaccgaagacaatcgtttggcatcctgggacttgcagtttcttttaggggcagagtcccttagttaactcattgctttagaggacgatgcggactacaactcccagagggccaagcggcaccagtagggtcctgtactcttgccgcggctgggcggctagttcaagttgccatagctgccagtctgggcacagctcagttcgttgcgccaccgcgtcgggtcagttgcaccttctcggtcacaggtggccgtgggagccgggtggggcctcggcgatgatccggcattaaggacctgggctctcaatctcaggtaattgcccgccaccgcccgtggccctttctttgccacttccctgtcctgtagacgttttaagtcccacttctccttgtcccaggggtggggacactggccgcgcggagatgtggggtggggccgcggcttggtagtgtgagcgccagggtggggagagacggggtgcccggcctgcgaccccctccgcatgggcatccacagcctggtctgtgccaagctattcagggaatttgaacttcctggtcctccttttgcgagcggcatgtcctgagctgtcaaggagatcggactcattttggaggtgactcgcctggcctgggatagagctgggatagcgctggccgttttgtacctgttctctagtcacagacgctgtatcgctgtatcggcctctcctgtgccaccatgggaattgccccaacgttagctgcccgtgatatgagttatttcgtaggaacatctgacattgaattccagctgcaactgtgatcggtttgatggggcccagtggcttccgcaggctcctcgtaggaccgcactgtaacgttgttccaagtatgaagcaaagtatctagcacagggcctgacacattggaagtactcagtatttgttatttatatttactaattatgcagaacagtgccgtcaagtagaaatattatgtgagacacacacacacacacacacacacacacacacacacacacacacacgtttaaattttccagtatccacattgtaccagtaaaaaggaaactggtgatgttaattttaatagtttatttagcacaatttatttatatacaaaatgttttcatttcaacatgtaatcagtatggaaacttattgattgaggcattttacagccttaaatgtatatatgtttttaatgtttctaagtgtccaaaatgtgcattgtatatttacagcacctgtgagctcaaactgggcagatttcaagagctcagtagccacgtatggagtgactactgtattgcacagtgtagattcaaggtgaaatctttagcagcttcatattggcacagagaaattgggatgtgtctgtgacccagcccatggggtgaaggttatgctctgttagaagagtgaagtatgcataaaacctgagtgctctcagcgtgtccgctctgccattgcaagacctgtgttgtttggagctctccacagtttattttgattaacttttccaggatagttttttactttttcttgaagtggtttatagatgtagtctcaggtcttcttatgtgacaactactagttctctggatacttcctgtgatttcctacagactgctttaaaagcagtcacaaagaattgaaaatatttctgtccacagactttcttacaaccaaagacattttatggttacttatttaattgcagtactaaatgtgtgtggtactgggtagcttacgaaatatatcgtttaggcgtactagcatatatagttcgttaactggcttagaaattcaactgggtcattaaattcagaagtatcatgttaaattaattatttgacttagtttaccctctgatagacatgctgaaagagagagtccttttaggtggacttgggctacaattgcatgatctggccagccctagggatgaccaggcatgggcagaagtaacaagtgaggagtatgttggttgggcacttggatgtggagagtttttttgagttcagtggggcttttgcatgacccaaggagcattttctctgttctctgatatgccatgaactgtatatagtgagggtgagcttattttcatcttttatttctttaacaaatttaaagttgtaggtgtgttttaatccttgtttcatttatctgtaggtggtttggggaaaatatagaggcaaccaaagattatctacttgactaggccttttgccctgaacctcatgaagaaatgataggaggcagacatatgtgcctaagaagagcactgagctcagtggagagcaacacggcgatttgggggtgtgctttgtaagtatgctttctcccggtgtttctaaacacatttttgcatatttatagtggaaaagagtatgtcaacaaataagcttttgagaggcaagaagtccctttctaacagcgtaaaatttaaatagaatggttgtgcgtgagagttataaaaattcaagggaacagactagataccttaacaaaaacaaaaatgatgcaattgtttccattagacaaacatttgagaacctattttgccccaggcacagtaatagaaaccttctatgtgacatatatatataatatttttattacactattctttaaaaaaaatatttttattgattttagagaggaagggagagggagagagagagaaacatcaatgatgagagagaatcatggattagttgcctcctgcacaccccctactggggattgagcccacaacctggtcatgtgccctaaccgggaatcgaactgtgacctcttggttcatagtagaggcttaatcgctgagccatgctggctggacattattatgctactagagttccgatacatgaaatttgtacaagagtaggcctttcttcccttggctgccggcaccaggacctgggcttccttcgcagagggaggccctgtccacctgccacagcccaccagtcggtggccttggcctccctctttggggtgatgtggagccccctattgatcgccccgcaggccggtggcctgggtcttcctccacggggcgataatggggcgatggccgggcctccgaccaatcgcatcgcacctaccttggctggcctggcgccagtgggtgtcatagcatggtcccggatggttgtccggatggtcattccgctgttcagacgtttggtcgattttcatattatgcttttattatataggattctttgttttataaatgagacagttgaagctcagatggtacatgtgatttgctggggattctggagcacaaagagtggttttcattcccgggtgttctttctacaaatctcaatcctgcccagtatgaagaggtgccgttgctgtctaagattgccctcagtgggatttgattgacagtcagcatttttagattaagagtaccatataagcaaaatttactgttatttatcttttatttatttattcagaaaaatatatttttattatagatttcagagaggaagggagatgggctatttaatctctttaaatattcaaagggttctattatcttagtttttccaagatataatggttcttacattattattgaggtaaagagttataattcgtgattactgtaaaatgaacatattcagcatgaattgtcattgataatgaaggatgtagtattaagaactcaagttttcagatgtagaggtaaaactctggacactttttagcattttcctcttgcattttgataagggacacttaaacctatataggagaccctttagggccttatgaaaacactgtccaagatctatgctgcacaaagttcttagaattaaagaattttagagctggaagagccagataaggtcatataatcacaaattctcagatgtaatcttgacatatttgggaataatataaaaataatctagagtagattcagtggtatccatgtagtatcactgagctgattctaatatgaaatgtttcaatatattcatgttattctgtagtgtgtatttaattgttgcaataatgtagtattacatgtcagtacataaaattctataatgtctcttttaactgctacataatattccaaatgactatatttaatgtatcccttatcagtagatttgtaattctttcttattttcttttttactattttaattctgcaattaaactctttctacatatacacatgaaatgtatacatacatcttaaacatcttttgttttcctaggatactatacagggtggggcaaaagtaggtttatagttgctcgtatggaaaacaatacaataattaataaataataatataagaataaactctgttgtgcatacttacaactataaacctacttttgccctaccctgtacatagaattagactatctgggtcaaaacatacgcatattatttattttttacttgtcttgccagattgttctccagaaaagctatctatttcagttaatattcttacagcaaggtgtgcccttgtcaatcctggaggtgagagctattttttttaaatttgtacaaaacagataaacaagcatatcatattattattttaattttcaattttttgattaggaatataaagaacattctatacttgttagggccatttgtattctgtgaattgcctgtttatataccctttgcatcttttagtactggtttgttcttttaaaatcattttttcagagagatgatgaatcctttggtttcgatataatgcgaatatttttccgtttgtccttctttccccctaaccttgcttctagtatctttttatcaataattgtaaatgctcctaacaggctacagggtccttatcagatattcactcctccctgaaattcacgtaacccttaacattgatcagtacaatgctgttgtgtgggtgtttgggagatggacatatatgtgtttatatgtatccatttagctgaagaacatagaatctacaatgtgcacagggtttgccatgacacaggtgctcaggatgaatggataagtgaagaagagagacattgtggaagaagtgaacgatgattgttattttaaagaaagaagagataagcagttttaaaaaattatttgtttatttttaagtacagcttacattcagtattattttgtatgagtttcaggtgtatagcatagtgactagaccaggggtggacaaactttttgactcgagggccacaatgggttcttaaactgtaccagagtgccggaacaaaagcatggatggagtgtttgtgtgaactaatataaattcaaagtaaacatcattacataaaagggtacggtctttttttttattttattttagttttattcatttcaaactggccggatctggcccgcgggctgtagtttgcccacggctggactagacaatcatatactttacaatgttccccctgatatttctagtactcacctgtcaccaatcatagttattacaatattttggactatatttcctatgctatactttatattcccttaactgttttgtgtaactagcaatctgtacttttcaatcccttcacctttttcacccagtctcccagccccctctcctctggcaaccattagtctgttctctgtgtctatgagtctgtttctgctttgtttgcttgtttgtattgttctttagattccatgtataagtgaaatcatatggtatttgtctttctctggctgactatttcacttaccataataccctctaggggagataaagtaattttatagattgtagaaaaaaggaaaaggctccatggtgagagactgaaggctttaaattggcaagaaatgggtttgcttatgagcagcaattggtacattgaaagcatactgagaatggacctagatgataaagaacctaagtaatttggagtgtagtgctttatagtacagacaaataataattgaggagtgcagatagctgtagatgacaataatgtatttaaatgatttgcaataattcaaacaagcttaagtgtgattcatttgttttaacgcatttattcaaatggatttaaagtgtttatctttgttttctctataaaggacatattatcaagtgttcatatttttactattttgcagtttaatccatattgtttggagatgtaagataattaatctaggccatttctacaagaatcattttacccaacaattatttaattagtatttactaattgcaaggtcctgtactttgaaattcatctctggattaatcagacaggataataagaaaatgtaattgtaaattcatttaaaagtgttccaactacatgccaggaaatatgctaggtgttgaaatacaaccatggattacataaatagtctctggtaagatttccagtctagtggggagagagacaagtaaatagccagttagcaatctctgggcagtgttgagttggtatccactatggatacttggtgggctaggggtggggggagtgaaagaagactttctaggggaagtttcctttgagctgagacttgaaagaaaagtagaagttagcaaagggaaaacgaagtgaaaagaatgttccaagtggtgaatccagcataggtttgatgacaaaatgaacatgacatattctgtgacagccctggccagatggctcagttgattgcagcatcatcccttacaccaaaaaagttttgggtttgattccccatcagggcacatacctaggttgtggcttgatccctggtctggacacctgtgggggcaactgattgatgtttctctctcacattggtgtttctctctctctcccttcctctctctcagaccaataaaacatatccttaggtgagcataaagaaaaatttaaaaaaattctgtggcacaaataattgtatttcatgcagatattttgacatttcataaatgttttgctataattatagagctatacaaatgcagaggaaggaaagatcacttctggctagaggtggacagcttcattgagattgtgttatttgagctatgcctggacaagtgagtgtttaaataggtggcaatactagatagcagaaggcattccacccagacctaatgacattaatgaggggtggcagtgggggaagaatagttgttgtaatagctgaatgtaggccttaagttttctgtggttcttttattaagacaggtggcttgccgagggccttgaattcctgattcaagaacctagattcagtcaggtggccagtggagttggaatgtataggaaaagactcaaaagtcaaagaaaccattttggtggctagaaatgagttgagaaaaagtcttaaatttatgagtagtgcacgtggcagtgagcacggttagatggtcagaaatctggaccttggagaaagattcaagactcagctctgctacttagtagctgtgtagccttgagtacctttcttagtgcctttaagcctcttaggtatatatcatgacagtgtactgaccttgtagggttattgtcaaacaacaatctgatattgaaacattagttattcagcattattcaacttgagtttcttgaaggtttttgaaattgaggttcttaacttcagtcctcatccatttactcccaataattcaatttcattataattggatttctatctaatccagtatctttaaaaattttttatgtacatttaaaaacattccaggaaacagttcatggggaaatcaaagttaagaacttcaattagctttttttcttaaaatttagaagtctatacattttgaaaagaatatgccaattattctgtttatccactttgaaaattaagaacaagaaataaaattgaggatattatgttaagcaaaataaagtcagccagaaaacctaagaaccatatgatttcactcatatatgggatataaaactgaaactcatagtttccagaggagagggggtggaggattagtaaaggataaatgggaccaaatatatggtcacagaaaatggtttgactttggatggtgggcacacagtgcaatatatagatcatgtatcatagaaatgtacccttgaaacctatataatcttattaaccaatgccaccccaataaatttaataatgataaaaaagaaatacaaaactcttgaaatgtatttcagtcctttattatagaagagttaaaaggaaagatctaaatatataaagtaagtgtggggcaaggaagaaatatgggaattgagaagagtggaggaaaaagagaaatagaaaatacgtgtacaccaaaaagaaaatacaatttaaaaaataaaatttaagattttatgatgtttctgaaaaaaaaaaagaaaaaaaaagaatgcttttctgcctgaagaggtaaatattcttaacaagagaaagggttatttaaaagacattttaaaatagttgtagaaagttggatttataggatatttacatattatcttgtattcattatagaaatctctagttttaagtagataagcacatatggatgacatactctggccttaaatgcatttcttgggggagtgagggtgataagaaatatgatagggatggacaaagaaaatatttcagtgattgggcaatgtatttagaatttacacagttctgctcctagaaatgtagtggaaaagcactggcttagagacacaagatatgggttctagttctgttactgtaactttttatcaaagcaatggtgggcaagtattttattcaaagctttgtttttcttagcagtaaaataaagagttgcaattatacccactttgtaggattgaatggaagtcaaaagagaaagtgctaaagaaaatgctttgtaagctataaagcaacatagaaatttgaggtataaatagcagtcagaaatatttccctttcttaaaatttttagtggtgttttttcactaggaaagtcaagaggagtttctgtttctactttaaaaaataggaggaaaaaaaccaagtattatgctttataatatatttaagaaacagcttgtttcttatgaaaatcttaatgttatggggagtagattaaatagccccaattgctatttatgattgcctagtttttctctctcaataattgctagtctgtcacttgtcatatcaattgcttatgcttattttgtgcatcctaatttgaatttgccctccccactccctcctcaccaccagaagacagtctgaaaacaacttgttttctcaaggagagtagtctttagaggaaacttcaggaaattaaattttttctgaaccaataaaatgatttattagtaaactacatattgtcaacagatgatcattggtgccaattcaacgccaacaggaatccccaatttggggtgtggtgaagaaggaaaatttattcagtgcaaaacagctcaattgtgataaagcatagccgtgaaaacagcaagccgatgaggtggacctggggccaggcccctctctgctagagatctctgttccttgctggtctgttcagctatgtgctggtctgctcttctccattctgtgtttggtgcctgtcttctctggcccatgttggtctgttcagctctgctccagtgagacagagatatctttggtgttttatctcagccagggatcagtctttggtggaaaggaaaggtgcactctcagagccagaggggagctggcttatatagacagaagcccttgcctgtgaccttgattggtctgtcctcatgcaaacaaggactccagatccttgtagttggatttgtccaaaaggcactttcctgattggtcagaaaagagctgctctgattggtcagtgaagatgttgatggggataaagctgtaagctctgtttggatgggggaagcctcagtcccattggttgaaataggattccagcacttcctttataagggctggctcagcagacagaaaaacagtgcaggcaggcagttcagtgcaggcttctgtgtgaagtgcagtttgtgtggaaatggctgctagtctctgtttttaaaatttgagcccagttagccaccaggagaccttcttggtaggtatcttctttcgcagtgttcacaatatatataccacttagcttttgctgcataacaaataaaacatacaaggcgtccgcatatataaaagcctaagcgactgatgactgaatgactggaacgaccagttgaccagttgctatgacgtgtgctgaccaccagggggcagacgcttaatgcaggagctgccccctggtggtcagtgcgctcccacagccaacctcctgtggctggtcggcagcttcagcgtccggcgtccattccttccgtgaccgtcgcctcctctcccaaccctgctgggacctttggcccagggctgggatggggaaccagggtgggtggtggtggatgtgacccctttcccagggggctgagggccggttcccttgtagaggctggaggccaacctcccataccccatccctcctcccagctggcaggccccaattggcctgcagtccctctctttgtccccccccccccccagttgtcggcccagccctaatcactggccaggcctagggaccccacctgtgcacaaattcatgcaccaggtttctagtacaacaataactttatcgcttgtacagttagtcagctaagctatctgcttattatgactggactcacttatttatctgggttcagctggctgatcacctggtctgctgacctaagctggaagcctctggtgcaactatgtattcccacaccttccaacaggataacaggatatcctgggcatgtcttcttggagatgggataggtgcagggaggcaagttccagtgtgtaatgccttttcgtgactccacttgtgccatgttagctagaatcccattgaccaaagcaggtcacatagctgagcccagaggaaggggcctgggcaggtaactcgacctctgagagcagtgcacgtagggatgggtaaagaattggagctaaatcatgaaaggtactacattttttatctgaatttagtttttgatatatatataatagtaggaaaatgttctaagtagatggattaaaatcaagcccttttgtttgtagtggtattttgttctggttttggagttagtaggcatggctgatatcaaagctgttacattaactctcaagcatttaaccctgactaattcttcccaatcaaattggtcatttttaactagggaaactcctttaaaaaggtaaacttcctttgtcttggttctttattcaaaatagggttgcaaactttgctagtaagtgggaccaatcggttaacacactgggtgaagcagctagctagtgggaacttaggccaacagaaaggtacatgcccaactccaaggcattcatggtttatgtccatgttgccatgggaaaattcatcccagtgttgccagatctctgggttttttaagagaagctggaaattaaaatttttatatgaaatttagttgttttaaaattagtgttttaaaataacatagtgagtgttattttcaaatacatgttagtcagctgggtttggtctatagtcctccagttttcatcctctgatttaagcaaagtggtgtcagaaactcgggattctagctccatctttgtccaggctgatctcttgcccagcctggggcagtttggacaatcagtagaagttgtctgtacccccagaggactttattcgtatctgctattttaagaatattgtagtatatatttcattttcaatcggttagaaaatgcaaaagtccaattccagggtgtaactacaagtaatagatccatctcgagtttgctagcatttctctgtaattttcttgagtttttgttgttatttttaatcttgactttttaaaagctttttacttaattttgtaaactgcctcatttattttagaagtgtgtgtgggtgtatgaatctaaaatatctgtgtcattctgcttgtgagacagggaggaggttattaagtaactttcttttaaaactgcattgatctttaacaagtggcacatatgtaattatctgagcaacaactaatttttttctctgtgcctgaataaggagtcattttgtatgctgcttgtccttttccagaaatgcccctgctccctgcttggtgggcactggtccctgtgactctttccctggactcaggagctggagcgaggggagcaaagtgcatctgggagctgagcctgacccgctccacccataggatagagggtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtataagagagagagagggaggaaagggagggcagcaacaggaataagtggaacatctatactaataaaagggtaatatgctaattagaccagacatcttctggatgaccgtctagacgtccttccggacacagccactgtggtggggccgaggcagaggcagttaggggcaatcaggcgaaaaggggggagtggttagggggatcaggcaggcaggggagagcagttggagtgatcgggcaggcaggcagagaggttaggggcgactgggcagttggacatcccccgagggatcctggattggagagggtgcaggccaagctgagggaccccctcccccccccccgccgtgcacgaatatcatgcaccgggcctcttgtacaatataaaatcaaatctagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtataataattaaaaacattaattctctaagtcagaagtctcaaagtgggatgattttacccagtcacccctccctaccccagggacatttagcagtactggagatgggtttaaatccattccctgatggaagaatgcaaggtgctttgcttatttgtaccttctctagttcttctgaaaaagaagttttctaactggatcccctatccttgtctcatctatttgtcaaacttatgctcctccagatgggtgggaggatcctgaccccactgctccggcgttttgttgtagtacttagctccctgtagagagcacttttacagctctttatctcccatcaaggactgtcacttaatttacttactttcatctttaatttctaatgcagatataattgagtaaatgattgcacaaatatgttcaactttctctctctctctccttttaatcacctgaggatattttttttattgattttagagagacagaaagggggagagagagagggagaaacatctatgtcagagagaaacattgattagttgcctctcagtggatctctgatcgggatcaaaccctcaaccttggtatgtgtcctgactaggaattgaaccggaaacctgcaggggatgatgctctaaccaactgagtcacccagccaggattcatgtatctctttgatttttcccctatgtcttatgttatctattgacttcacagggaattggctgttgattttgatcttatatgaacttaccaaaagggtttgaggagattaagttacagaggagtattgatatcaagaagccaggcatgactgagaattgtttgtacatgataacttttcctggctagttcactttgtctcttgaaggaggaggcaaagctctcaagacctgcagctgttgaaacagtgagaaatgccttctaaaatttgaactttgataatgattaagcttagaatacactccccacatcctgtgatccccttaaatatcaacatcatttccttgaatgtgttctttgaggacagttgccttggacagggatggctgaggcacttggaggccacagaagtaatcacctacttaacatgcactagtcagcttttgtaaaatgtcacccttgatgctgggtgcttatcttttatggaacagcttgcaaattctaattgttttaaactggctctgaggaaaagagacttgagaatcaataaattacagctctcatacatacaaatatgcatcattataatgaggacaatctgatggctttttaggtcaaataacagaagaggtggacttgagtttgtacagactcactgccagtcctcttattacagggccaaatgcacttttactccccctgctcacagtgttcaagtttgcacatgggcatttgtttttgatggactttttcctcagtgggagcgaattgaggagcttcattactcactctggtggcggtatgtcatctttataaggctcgttaaggcagaagcaacaatatttatgcctttaaatactgatgtgttgggaacagaaaaataaagtatttttagagttctaccatctggtttcagacccagagctttctctaagactatggagactttcacccaaggttgcctgtcctagtcctctctagtcttggagaaagctcaatgtctgaaaagcagacagatcaatgctattgcttcctgatcaatgagaagttttgttgtactagatggtggtagtaagagaatattttctgctttttctccagttgaaggaaacgcttttctctcctttaatcagaatttgggtgattcagttttttaaaattgttctttaagagttcttcaatcgttcttcaaatttagcaattcttttccccccaacagatgtcatgttgaaacttcttgtgataatgagaatggatttttaatccaactgaactttttccttttgaatatttcaaaagaatgatgaagattttccttgagcatacatagatgtttttctaccagtcttaataattcttctttgggcttcatattgtaattgtggttaatataattcatgaaccatttaaatttgtttttcaaagcagaatttgattgcatactttatgtgagtacacattaatgtgttttcacatagtccttcaacttttaagttgagccttggccaatgtggctcagttggttgagctttgtctcattcacctagaggtcagggaagggcagttgtgggcgatcaggccggcaggggagggcagttgtaggtgatggggccggcaggggagggcagttgtggccaatcaggccagcaggggtgggcagttgtgggcaattgggctggcaggggagggcagttgcgggtgatcaggccggcaggggagggcagtagtgggtgatcgggccagcaggggagcagttaggcgtcaatcaggtcagcaggggaatggttaggggcgatcaggctggcaggcagaagcggttaggggcaatcaggcaggcaggcaggcaggcgagtggttaggagacagcggtccctgtgggatcaggcctaaactggcagtcggatagcccccaaggggtcccagattggagagggtgcatgctgggctgagggacacccccccccacccctgtccacaaattttgtgcaccaggcctctagttggtatataagaaggccatagatttctgggtgttaattttgtatcctgctacattgccgaattcatttattaagtctagtagttttttggtggagttctttagggttttcaatgtacattcccatgtcatctgcaaataatgacagttttacttcttcttttccaatttggatgccttttatttcttcttcttgtgtgattcctatggctagcatttccagcactatgttgaacaggagtggtgaaagtggacatgtctgtcttgttcctgttcttaggggaaatggttttagtttttgcccattgagtatgatttggctgtaggtttgtcatataaggcttttattatgttgaggtatcatccctctagtcccactttgctgagagttttttttttttttttttataaaaaaagggtgttggattttgtcaaatgccttttctgtatcaattgatatgatcatgtgatttttgtttctcaatttgtttatgtgatgtatcacatttattgatttgcatatattgtaccagccttgcatctctggaataaatctcacttggtcatggtgcatgatctttctaatgtactgctggatccgatttgctagaattttgttgaggattttagcatctatgttcattggggatattggtctgtaattctcttttttttgtggtgtctttatctggttttggaattggtgtaatgctggcttcatggagcttggaagtgtgccttcctcttgaatttttggaatagtctgagaattgaactgtgacctcctggttcataggtcgatgctcaaccactgagtcacatcggccgggcaggagttgctcttttaaagcagaaaaaacaaaggagggagaattacgtgaggaagtgacttatattttcaaattgtatgcaattattatgataaaccaaaggactaatgtaataaatactgtaaaagatcaaaagtaaatagctaaattaatctcttattcccattctctttaccatttgcttgaccatgatctgaattcatttttaaggatttgtgtacatcaatggcagaatcctccagtgattcagaccacttccgctgtcatgaccggttgagtcgatgggctgccaggtcaatacacagggatattagaaatcgtcctacagtcgatgtcaccaagaaggtcaacactatcacaagtactttacaggttagtttaacactggatgctttaaatcaatattaagtaataaatagttaagctgagtaatagtttcagtcactgtattagtttttttgcgcccataacaaattaccacaaaattaatgtcttaaataacagaaatttatttttttaaaattctgtaggtcagaatcggacactaatctcattgggcagtaatgagggtgttggtagggctgcatttctttctggagaccctagggaaatacctctcctcttgcctttttctagcttctaggctgcccatattttctgtcttgtggccccgttcatctccaaagccatcaggggtgggttgagtccttctcatagcatatcagtctgactacctctcctgcttctctcttccacttttaaggacatttgtgatcacattgagtgcacccagtaatccaggatattgctcatctcagcatccttaatttaatcacatctgcacaatcccttttgacatgtaaagttccaggaattagggtttgaacatctttggaagcccttattctgcttaccacagttagtaaggatatttgaaatatatgataggttgtggaaagtgttatatttccaaataaaatattataggaatgaaaacattagggattaccatcctttagcttcttgtggacatgtgccttggagaaattgctcatattttggcttgggtaaatatatcaatcagatagattgccaactagatgatatacatttagcttctattgaatttgaaagtgttaagtcagagggggaagaactcaggacttgaattaaactgagagttactgattattcatccaagccaaactatgattattcatggatgaataatagtgagagtccattttgatttggaggctaactttgacagtgtttggagatttgagtgagggcagttttcattcttccataaaaggggcttgggaaatgaggtgggggaaggtactacagtcacaatgggaaaaagaaaactcagaaatagaattttttcctcctacttattactcccttacctttgttttacctggataagcatggattttggctttttattgctctgggttaatatgcttagattaaaaaaaggctaatttctagtggagaggccataatttgatttaatttttctttttaaacttaatatggcaatgaattttggagtacaaattcttgtactttcccaccacagagacacattagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtattaaattatcacctaaggagtgaggctatttttttgcattggttttaaagagagtggaaggaaggggggttgggtagaaagagaaacatcattgtgacagagagacatcaattggttcctcccacattcaccctgattgggggtgggaattgttatctgtgacccagctacctgcccttgacctggatttgaactcaagacatttcggtgggcaggccagcgctctaaccattgacccacaccagccggggcagtaagtatatatttttgaaagaaatacctccattaatctctcaggtgaaacctagcatatttaggtagaaaccatttttgttatgattagagctaaatttgttgtttatagctaaaggttaaaggatacttttcccccctcctaattcagttctcagataaagcaataattgaaataacatgaatcccaatgatttgcttctcttgtagataatctactagattagttcttttagcattctttttcatgaagggatgtgaattagttgaggtgtacaagttgataatgagggttttttccagtttatggttttgttgctgacttacggaaccttggataaggatttaaattaggtactttagatttcacacaagtaaattgcagatggattttagtttctctctcagttgtgttaagatttatttgatatttatgaaatatagatatctgacttaactatgatataaattgtacctttgcaaatggttgacttagctgtttgaaatactactatgactgattgggaaaaacatcaactaataaagtccattttctttctcaaggacaccagtcgaaacctgcgacaagtagaccagatgcttggacagtatcgagactatagtaacggacaggcgggtgctatagaacacgtaagatgtttgcatgtttgtattttctcttaccttcttgggaatgcagagctgagtattagggatgtgagctaaaggagataataattgttaacagctttaacttttaaactgctccactattttgtagtataaatttaggttagctcatcagttagattgccaactagatgatatacatttagcttctattgaatttgaaagtgttaagtcagaggggaaagaactcaggatatgaattaaactgagagttactaactttgggctctcatggggaggtaaaaattttaaggacagtaaaaaaattttaaagtaatccatgctcattgtttaaataataaaactccgatctcatagcccttttgagtcccattccaaaaaggtaacagttttgatagtttcttatatattttttcaaacattttctatgcatgcataaacttacatgtgattgctttataaattgtaatcatatgtattgttatgcagactttttcatttagtaatatatgtattattttccatatgacacattcttttgaaattacattatactgcatagtataggtgtattaagtttttttgtttttttttttttttggtattgtaaataatgcaccaatgaccatcatggttctcatgtttttctgtaatcatatgtgattcatgggaacagagttgctgggttgaaggatatgtatacttacaatttgctagatatttcaaaattgccctcccaaggaagtgccagtttgtacttacttcacatgggggtgtaagaaggaaacatatccttattctggagtaaaaggaatatttttttattaatattttgttaatgtaatctatattattttctcttttgaaatttgttaattcatctgcaaactcttggaaatccaattaaatttatttctccatgttttcaatatgagtttacactttaataagactagaattatatttgtactataatgattgccatatatatacatatcctatataataaaagcctaatatgctaagtgcctggtggtctgttcaaccaatcaaagcataatatactaatgatatgctaagtctgctcaaccgctcactgtgacgtgcactgaccaccagggggcagatagtcgactggtcgaccagtcactatgacatgcactgaccaccagggggcagacgctgaatgcaggagctgctccctggtggtcagtgcgctcccacaggaggagctccgctcagccagaagccaggcttatgactggcaagtgcatcgggggtggtgggagcctggcagttggcagttggacatctcccaagggctctcagactgctagagggcacagggcaggctgagggacacccccccgttcccccccgagtgcacgaatttcatgcaccaggcctctagtgtgtgatattcaatatatatatactgaattgtcacataacttcctagttataattgaagatttggtattttctttttataaaacagaagaatagttagcattatttgcttgtaattggaaactaattgcttgtgcacagggaaatgtatcttctgtcttaaggtttcccactatcatttagaaaataaacttggatttttgcagctaaaagattttcatgatttatgatgtatttgacagatggagctatagattttgtatatttgggtagctcattaaatgctgtagattaaactactttattaataatgggagttaatactctgccttttaattttagtgaacaattaaaaacactaatagcagagaacaatcctactttgtcatagtgaatattagatgcttgcttatagtagcaaattttctttgaatttgcaattgggaaatgaaattaagaattagagaaacttctgtgcaataagcatttaaaacacaaagtatgttctactatggcagtaagcctttgtggtaggccttgagttgaataatgctgaactctgggggctttatatatgggaagtaaatacattcaacaggtacttcatttccatctgagttgtaagtacatagtatgcaaagccactttataaaaaataagacacaggagagcaagtgtctttctttggcttcagactttttcttagtttggtctagagtctcctcctgaatttctccaaattcttgtcctgttaaagcagttggttctcagtgattttccctgccaacaaatcagaggagtaatgtcactcattgcctgacattatactcacttgatagagcagtgatcttcatcgccccacctataagttacctggggagcatctgccataatctattggaagatgtgcaactcaggaagagtatttctcacaataagtgattctgatgggctcctcaatgaaaattgttttcttagcattaaaatatttactgttatggaatattttacacctaaaaatgagtatatgtaatgtgctaaggatcatgtgatttatctgaatctttctatttatattctttttttaaaaacatatttttattgattttagagaggaagggagtggaagggaaagatagaaatatcaatgatgagagagaatcattgactggttgcctcctgcacacttcctactggggatcgagcctgcaatccaggcacgtgccctgactgggaaccgaaacgtgacctcctggttcattggtcgatgctcaaccactgagcaacaccagttgggctctatttatattcttgaagtccttgaagtacatggtagtattacccattttttcttttcttttaatcaatgtgtgcattgtttagggaggaaccctggaaattgatgtttttatttttgaggctatgctacaacttatacaagtcctcttgctgtgaaacttgttataaaaaaaaaaaaaatcccgttacagtttaatctgttttaaccagtactcaactgttaagaattttctcgctgctaaatatctattgcctcattgaaatgagcaattcttttttaaaatataagggatttcctagaaaatgagatcaactcttttgctttagggaagacaagaatttttattattaacttagattttataaatgattctattgctaagcctcaggacatggatgttttatatatgtatttaacatagttatttgattggggtttaattttgtgaacataatttgccagttggtgagagggaatataaataatcgatggggtgttttcctcctgaggtgacctcacccaacaagagaactatgagaatcattgctgttggttttgtgaggtcttagggtcaagagtcatgttgggtcatatttttgactacttttccttgaaatgtacataatttcattgttgaccccttgaatctttctaacatagatttaattctttttttttttttaaaaaatatatattttattgatttttttatagagaggaagggagagggatagagagttagaaacattgatgagagagaaacatcaatcagctgcctcctgcacactccctactggggatgtgcctgcaaccaaggtacatgcccacaaccaaggtacatgcccttgaccggaatcgaacctgggacctttcagtctgtaggccgacgctgtccactgagccaagccggttagggccatagatttaattctttgcttataatatgtgaagctgagcagtgttagagggtagcagggcatctgtagtgttttgtagagaagcagcacctgccttttcacagtttccctgggaatttctctgtaagcttagcatatcccaggtgcttttaaactatcaactcatttaattctctcaccaatcctgttaggtagatactattattttcctcatttacaagataaaaaactgggacacagaatggttgctaacttgcccatagtctcttagctagtcagtaacagtctacgatgttattctaaaacctagtgcctggattcatttacctcatttacctcatggttgctcacatttttgtgatgttgtgaatctatagttctgaaaattgggggtttgaactcaaagcttaaagggttatataattcacattgataaactagattttggagattaccttaactgattgaaaaacagaagcccattgtcacacaagtcattagtgttgtagctggtgctgtgtcagaaattagagttagatggaacaaatacagaaacagcattgggaagaaatctggtgctgagctaggactggcatggacagattgtcagggttggcagttttggctggcacttaggcaacatggtggattctgcagcttccctacaccatcattgacttccccttttctcccgagtaacaaccattgatttttcactattccagccagtgagccatatttagttggatacaatgacatagggtctttgggctccttgactttcataaccttaaagaagggtcattatttctcattctgtaaatttcttgggaggtctgagaacatttgggtcaaagaggacctgtggggaaggttttagttaaaagcttattttaaacatttgttatatagtgcaattgattagcttggtgtttagaatatttctagaactctgtgttcctattcataagacaatagggactgtttttgagttaatgctataaaaatggagtgccctcaagaaagaatattcaacataaaaagttaatgctttctgcagtggaagtgtagctgatgatgctagagtagttcatattgggtataaaagcaaaatacagttcccttgattcagatcagctgatttattcatttttaaggtaaagatgggtgaaaatatagtaatagcaaattaagccttagaggcttgaattaataggtaatttttctcctaattaagtgttctgtttaaaatttcttttgggagtaataggatgttaccatctggtacatgaactttggaagaatttaaatgttaaataataaactccaggtttttgttctatttggtgggtttcagttgtcaaatatactgagtgataccctaaggttaatggtttagagccaggcacaagccacttgtaatctctcaaagctgaaggcatgtgcccctttctctctggccaggttttactagttgtcctgaagttgagaaccagtcacagtcttttaataactttaatgctagatagtaagagtctatgagtaagaacttgtaatcgaacaattaaagtcttctggcttctttttgtaaatacatttcaaatcttagaaattaggttcttagaattctgtttaaaattttattaccaagtctcacatgaaacaactggataagagaatattttttacagacttttgctttgagtctagaggaaaaatctagattttggaatcagacttccaattgaatattgatttttctgctagaaaccatttagttactttgggcaagctactaaaccacctctatgttcatgagtaaatcgtctgcccacccaaaatacagtaatgtactattaagggtaccttccattttacatagtagtaatgcttcagtttttttcggtctaatatcaaatgagcagaggtaaaagaatagatttaacatgtaaatgaagcatttatagcagattgtgaaaatgtcattgcatgttttgtgatgtgggacagagagaaatggaatcatcacttggtctgtggtgatgttgtcatgctagactctaagaatctgcacttaaaaaaatttttttttttaatttcagagagagaaaaagagagggagatagagatagaaacatcgatgagagagaaatatcgatcgactgcctcctgcttggcccctgctggggatcgagcccgcagactgggcatgtgccctaatcaggaattgaccttctggttcataggttgacattcacccactgagccacactggctgggcaagaatctgtacctttggaatcagtaccacagtctcctgtggagcattgttttcatttcagcatagtagcatactgaattaatgttaaattgagctttattagtgttgttttgttttatttaacttcaagttttagtttgcttttgcacctagttaggagttataatcctaaaacatttgaagaaacttttattattttacattttgtctcttcatctctttgattttgtgtttcaggagtgatcaggttagtttcatgcatcatgcttagattttgtgcagtgtctgctgtgttattgctactttaagtgtatattttaattctgttacatttttagttttgtattgtaggtggaggacatgtttttgccttgatattaaaaaaatctttatcctgcttatttacttttgcatttcattttttggtctttatcagcctgttcatctgttcaatggcttttgatataccttttaaagtttaaaatgaagtttcaaatagtttatcttctgaaatgattaatttctcttgttctgcaatatttttccctatgttccatggtggctttccccccatttttgttaacgggttgtgtgagtgtgtgtgtaagtttattttattcatcagcttttagttacagctcaggatttgttagcaaagaagcccacgtaaaaaggatgctggcatactctgcctctagcatcagtagataagattattttggatctactctcttactctgaacaactagaaagg"; 1808 auto bSequence = reverseComplement("cctttctagttgttcagagtaagagagtagatccaaaataatcttatctactgatgctagaggcagagtatgccagcatcctttttacgtgggcttctttgctaacaaatcctgagctgtaactaaaagctgatgaataaaataaacttacacacacactcacacaacccgttaacaaaaatggggggaaagccaccatggaacatagggaaaaatattgcagaacaagagaaattaatcatttcagaagataaactatttgaaacttcattttaaactttaaaaggtatatcaaaagccattgaacagatgaacaggctgataaagaccaaaaaatgaaatgcaaaagtaaataagcaggataaagatttttttaatatcaaggcaaaaacatgtcctccacctacaatacaaaactaaaaatgtaacagaattaaaatatacacttaaagtagcaataacacagcagacactgcacaaaatctaagcatgatgcatgaaactaacctgatcactcctgaaacacaaaatcaaagagatgaagagacaaaatgtaaaataataaaagtttcttcaaatgttttaggattataactcctaactaggtgcaaaagcaaactaaaacttgaagttaaataaaacaaaacaacactaataaagctcaatttaacattaattcagtatgctactatgctgaaatgaaaacaatgctccacaggagactgtggtactgattccaaaggtacagattcttgcccagccagtgtggctcagtgggtgaatgtcaacctatgaaccagaaggtcaattcctgattagggcacatgcccagtctgcgggctcgatccccagcaggggccaagcaggaggcagtcgatcgatatttctctctcatcgatgtttctatctctatctccctctctttttctctctctgaaattaaaaaaaaaaatttttttaagtgcagattcttagagtctagcatgacaacatcaccacagaccaagtgatgattccatttctctctgtcccacatcacaaaacatgcaatgacattttcacaatctgctataaatgcttcatttacatgttaaatctattcttttacctctgctcatttgatattagaccgaaaaaaactgaagcattactactatgtaaaatggaaggtacccttaatagtacattactgtattttgggtgggcagacgatttactcatgaacatagaggtggtttagtagcttgcccaaagtaactaaatggtttctagcagaaaaatcaatattcaattggaagtctgattccaaaatctagatttttcctctagactcaaagcaaaagtctgtaaaaaatattctcttatccagttgtttcatgtgagacttggtaataaaattttaaacagaattctaagaacctaatttctaagatttgaaatgtatttacaaaaagaagccagaagactttaattgttcgattacaagttcttactcatagactcttactatctagcattaaagttattaaaagactgtgactggttctcaacttcaggacaactagtaaaacctggccagagagaaaggggcacatgccttcagctttgagagattacaagtggcttgtgcctggctctaaaccattaaccttagggtatcactcagtatatttgacaactgaaacccaccaaatagaacaaaaacctggagtttattatttaacatttaaattcttccaaagttcatgtaccagatggtaacatcctattactcccaaaagaaattttaaacagaacacttaattaggagaaaaattacctattaattcaagcctctaaggcttaatttgctattactatattttcacccatctttaccttaaaaatgaataaatcagctgatctgaatcaagggaactgtattttgcttttatacccaatatgaactactctagcatcatcagctacacttccactgcagaaagcattaactttttatgttgaatattctttcttgagggcactccatttttatagcattaactcaaaaacagtccctattgtcttatgaataggaacacagagttctagaaatattctaaacaccaagctaatcaattgcactatataacaaatgtttaaaataagcttttaactaaaaccttccccacaggtcctctttgacccaaatgttctcagacctcccaagaaatttacagaatgagaaataatgacccttctttaaggttatgaaagtcaaggagcccaaagaccctatgtcattgtatccaactaaatatggctcactggctggaatagtgaaaaatcaatggttgttactcgggagaaaaggggaagtcaatgatggtgtagggaagctgcagaatccaccatgttgcctaagtgccagccaaaactgccaaccctgacaatctgtccatgccagtcctagctcagcaccagatttcttcccaatgctgtttctgtatttgttccatctaactctaatttctgacacagcaccagctacaacactaatgacttgtgtgacaatgggcttctgtttttcaatcagttaaggtaatctccaaaatctagtttatcaatgtgaattatataaccctttaagctttgagttcaaacccccaattttcagaactatagattcacaacatcacaaaaatgtgagcaaccatgaggtaaatgaggtaaatgaatccaggcactaggttttagaataacatcgtagactgttactgactagctaagagactatgggcaagttagcaaccattctgtgtcccagttttttatcttgtaaatgaggaaaataatagtatctacctaacaggattggtgagagaattaaatgagttgatagtttaaaagcacctgggatatgctaagcttacagagaaattcccagggaaactgtgaaaaggcaggtgctgcttctctacaaaacactacagatgccctgctaccctctaacactgctcagcttcacatattataagcaaagaattaaatctatggccctaaccggcttggctcagtggacagcgtcggcctacagactgaaaggtcccaggttcgattccggtcaagggcatgtaccttggttgtgggcatgtaccttggttgcaggcacatccccagtagggagtgtgcaggaggcagctgattgatgtttctctctcatcaatgtttctaactctctatccctctcccttcctctctataaaaaaatcaataaaatatatattttttaaaaaaaaaaaaagaattaaatctatgttagaaagattcaaggggtcaacaatgaaattatgtacatttcaaggaaaagtagtcaaaaatatgacccaacatgactcttgaccctaagacctcacaaaaccaacagcaatgattctcatagttctcttgttgggtgaggtcacctcaggaggaaaacaccccatcgattatttatattccctctcaccaactggcaaattatgttcacaaaattaaaccccaatcaaataactatgttaaatacatatataaaacatccatgtcctgaggcttagcaatagaatcatttataaaatctaagttaataataaaaattcttgtcttccctaaagcaaaagagttgatctcattttctaggaaatcccttatattttaaaaaagaattgctcatttcaatgaggcaatagatatttagcagcgagaaaattcttaacagttgagtactggttaaaacagattaaactgtaacgggattttttttttttttataacaagtttcacagcaagaggacttgtataagttgtagcatagcctcaaaaataaaaacatcaatttccagggttcctccctaaacaatgcacacattgattaaaagaaaagaaaaaatgggtaatactaccatgtacttcaaggacttcaagaatataaatagagcccaactggtgttgctcagtggttgagcatcgaccaatgaaccaggaggtcacgtttcggttcccagtcagggcacgtgcctggattgcaggctcgatccccagtaggaagtgtgcaggaggcaaccagtcaatgattctctctcatcattgatatttctatctttcccttccactcccttcctctctaaaatcaataaaaatatgtttttaaaaaaagaatataaatagaaagattcagataaatcacatgatccttagcacattacatatactcatttttaggtgtaaaatattccataacagtaaatattttaatgctaagaaaacaattttcattgaggagcccatcagaatcacttattgtgagaaatactcttcctgagttgcacatcttccaatagattatggcagatgctccccaggtaacttataggtggggcgatgaagatcactgctctatcaagtgagtataatgtcaggcaatgagtgacattactcctctgatttgttggcagggaaaatcactgagaaccaactgctttaacaggacaagaatttggagaaattcaggaggagactctagaccaaactaagaaaaagtctgaagccaaagaaagacacttgctctcctgtgtcttattttttataaagtggctttgcatactatgtacttacaactcagatggaaatgaagtacctgttgaatgtatttacttcccatatataaagcccccagagttcagcattattcaactcaaggcctaccacaaaggcttactgccatagtagaacatactttgtgttttaaatgcttattgcacagaagtttctctaattcttaatttcatttcccaattgcaaattcaaagaaaatttgctactataagcaagcatctaatattcactatgacaaagtaggattgttctctgctattagtgtttttaattgttcactaaaattaaaaggcagagtattaactcccattattaataaagtagtttaatctacagcatttaatgagctacccaaatatacaaaatctatagctccatctgtcaaatacatcataaatcatgaaaatcttttagctgcaaaaatccaagtttattttctaaatgatagtgggaaaccttaagacagaagatacatttccctgtgcacaagcaattagtttccaattacaagcaaataatgctaactattcttctgttttataaaaagaaaataccaaatcttcaattataactaggaagttatgtgacaattcagtatatatatattgaatatcacacactagaggcctggtgcatgaaattcgtgcactcgggggggaacgggggggtgtccctcagcctgccctgtgccctctagcagtctgagagcccttgggagatgtccaactgccaactgccaggctcccaccacccccgatgcacttgccagtcataagcctggcttctggctgagcggagctcctcctgtgggagcgcactgaccaccagggagcagctcctgcattcagcgtctgccccctggtggtcagtgcatgtcatagtgactggtcgaccagtcgactatctgccccctggtggtcagtgcacgtcacagtgagcggttgagcagacttagcatatcattagtatattatgctttgattggttgaacagaccaccaggcacttagcatattaggcttttattatataggatatgtatatatatggcaatcattatagtacaaatataattctagtcttattaaagtgtaaactcatattgaaaacatggagaaataaatttaattggatttccaagagtttgcagatgaattaacaaatttcaaaagagaaaataatatagattacattaacaaaatattaataaaaaaatattccttttactccagaataaggatatgtttccttcttacacccccatgtgaagtaagtacaaactggcacttccttgggagggcaattttgaaatatctagcaaattgtaagtatacatatccttcaacccagcaactctgttcccatgaatcacatatgattacagaaaaacatgagaaccatgatggtcattggtgcattatttacaataccaaaaaaaaaaaaaaacaaaaaaacttaatacacctatactatgcagtataatgtaatttcaaaagaatgtgtcatatggaaaataatacatatattactaaatgaaaaagtctgcataacaatacatatgattacaatttataaagcaatcacatgtaagtttatgcatgcatagaaaatgtttgaaaaaatatataagaaactatcaaaactgttacctttttggaatgggactcaaaagggctatgagatcggagttttattatttaaacaatgagcatggattactttaaaatttttttactgtccttaaaatttttacctccccatgagagcccaaagttagtaactctcagtttaattcatatcctgagttctttcccctctgacttaacactttcaaattcaatagaagctaaatgtatatcatctagttggcaatctaactgatgagctaacctaaatttatactacaaaatagtggagcagtttaaaagttaaagctgttaacaattattatctcctttagctcacatccctaatactcagctctgcattcccaagaaggtaagagaaaatacaaacatgcaaacatcttacgtgttctatagcacccgcctgtccgttactatagtctcgatactgtccaagcatctggtctacttgtcgcaggtttcgactggtgtccttgagaaagaaaatggactttattagttgatgtttttcccaatcagtcatagtagtatttcaaacagctaagtcaaccatttgcaaaggtacaatttatatcatagttaagtcagatatctatatttcataaatatcaaataaatcttaacacaactgagagagaaactaaaatccatctgcaatttacttgtgtgaaatctaaagtacctaatttaaatccttatccaaggttccgtaagtcagcaacaaaaccataaactggaaaaaaccctcattatcaacttgtacacctcaactaattcacatcccttcatgaaaaagaatgctaaaagaactaatctagtagattatctacaagagaagcaaatcattgggattcatgttatttcaattattgctttatctgagaactgaattaggaggggggaaaagtatcctttaacctttagctataaacaacaaatttagctctaatcataacaaaaatggtttctacctaaatatgctaggtttcacctgagagattaatggaggtatttctttcaaaaatatatacttactgccccggctggtgtgggtcaatggttagagcgctggcctgcccaccgaaatgtcttgagttcaaatccaggtcaagggcaggtagctgggtcacagataacaattcccacccccaatcagggtgaatgtgggaggaaccaattgatgtctctctgtcacaatgatgtttctctttctacccaaccccccttccttccactctctttaaaaccaatgcaaaaaaatagcctcactccttaggtgataatttaatacacacacacacacacacacacacacacacactaatgtgtctctgtggtgggaaagtacaagaatttgtactccaaaattcattgccatattaagtttaaaaagaaaaattaaatcaaattatggcctctccactagaaattagcctttttttaatctaagcatattaacccagagcaataaaaagccaaaatccatgcttatccaggtaaaacaaaggtaagggagtaataagtaggaggaaaaaattctatttctgagttttctttttcccattgtgactgtagtaccttcccccacctcatttcccaagccccttttatggaagaatgaaaactgccctcactcaaatctccaaacactgtcaaagttagcctccaaatcaaaatggactctcactattattcatccatgaataatcatagtttggcttggatgaataatcagtaactctcagtttaattcaagtcctgagttcttccccctctgacttaacactttcaaattcaatagaagctaaatgtatatcatctagttggcaatctatctgattgatatatttacccaagccaaaatatgagcaatttctccaaggcacatgtccacaagaagctaaaggatggtaatccctaatgttttcattcctataatattttatttggaaatataacactttccacaacctatcatatatttcaaatatccttactaactgtggtaagcagaataagggcttccaaagatgttcaaaccctaattcctggaactttacatgtcaaaagggattgtgcagatgtgattaaattaaggatgctgagatgagcaatatcctggattactgggtgcactcaatgtgatcacaaatgtccttaaaagtggaagagagaagcaggagaggtagtcagactgatatgctatgagaaggactcaacccacccctgatggctttggagatgaacggggccacaagacagaaaatatgggcagcctagaagctagaaaaaggcaagaggagaggtatttccctagggtctccagaaagaaatgcagccctaccaacaccctcattactgcccaatgagattagtgtccgattctgacctacagaattttaaaaaaataaatttctgttatttaagacattaattttgtggtaatttgttatgggcgcaaaaaaactaatacagtgactgaaactattactcagcttaactatttattacttaatattgatttaaagcatccagtgttaaactaacctgtaaagtacttgtgatagtgttgaccttcttggtgacatcgactgtaggacgatttctaatatccctgtgtattgacctggcagcccatcgactcaaccggtcatgacagcggaagtggtctgaatcactggaggattctgccattgatgtacacaaatccttaaaaatgaattcagatcatggtcaagcaaatggtaaagagaatgggaataagagattaatttagctatttacttttgatcttttacagtatttattacattagtcctttggtttatcataataattgcatacaatttgaaaatataagtcacttcctcacgtaattctccctcctttgttttttctgctttaaaagagcaactcctgcccggccgatgtgactcagtggttgagcatcgacctatgaaccaggaggtcacagttcaattctcagactattccaaaaattcaagaggaaggcacacttccaagctccatgaagccagcattacaccaattccaaaaccagataaagacaccacaaaaaaaagagaattacagaccaatatccccaatgaacatagatgctaaaatcctcaacaaaattctagcaaatcggatccagcagtacattagaaagatcatgcaccatgaccaagtgagatttattccagagatgcaaggctggtacaatatatgcaaatcaataaatgtgatacatcacataaacaaattgagaaacaaaaatcacatgatcatatcaattgatacagaaaaggcatttgacaaaatccaacaccctttttttataaaaaaaaaaaaaaaaaactctcagcaaagtgggactagagggatgatacctcaacataataaaagccttatatgacaaacctacagccaaatcatactcaatgggcaaaaactaaaaccatttcccctaagaacaggaacaagacagacatgtccactttcaccactcctgttcaacatagtgctggaaatgctagccataggaatcacacaagaagaagaaataaaaggcatccaaattggaaaagaagaagtaaaactgtcattatttgcagatgacatgggaatgtacattgaaaaccctaaagaactccaccaaaaaactactagacttaataaatgaattcggcaatgtagcaggatacaaaattaacacccagaaatctatggccttcttatataccaactagaggcctggtgcacaaaatttgtggacaggggtgggggggggtgtccctcagcccagcatgcaccctctccaatctgggaccccttgggggctatccgactgccagtttaggcctgatcccacagggaccgctgtctcctaaccactcgcctgcctgcctgcctgcctgattgcccctaaccgcttctgcctgccagcctgatcgcccctaaccattcccctgctgacctgattgacgcctaactgctcccctgctggcccgatcacccactactgccctcccctgccggcctgatcacccgcaactgccctcccctgccagcccaattgcccacaactgcccacccctgctggcctgattggccacaactgccctcccctgccggccccatcacctacaactgccctcccctgccggcctgatcgcccacaactgcccttccctgacctctaggtgaatgagacaaagctcaaccaactgagccacattggccaaggctcaacttaaaagttgaaggactatgtgaaaacacattaatgtgtactcacataaagtatgcaatcaaattctgctttgaaaaacaaatttaaatggttcatgaattatattaaccacaattacaatatgaagcccaaagaagaattattaagactggtagaaaaacatctatgtatgctcaaggaaaatcttcatcattcttttgaaatattcaaaaggaaaaagttcagttggattaaaaatccattctcattatcacaagaagtttcaacatgacatctgttggggggaaaagaattgctaaatttgaagaacgattgaagaactcttaaagaacaattttaaaaaactgaatcacccaaattctgattaaaggagagaaaagcgtttccttcaactggagaaaaagcagaaaatattctcttactaccaccatctagtacaacaaaacttctcattgatcaggaagcaatagcattgatctgtctgcttttcagacattgagctttctccaagactagagaggactaggacaggcaaccttgggtgaaagtctccatagtcttagagaaagctctgggtctgaaaccagatggtagaactctaaaaatactttatttttctgttcccaacacatcagtatttaaaggcataaatattgttgcttctgccttaacgagccttataaagatgacataccgccaccagagtgagtaatgaagctcctcaattcgctcccactgaggaaaaagtccatcaaaaacaaatgcccatgtgcaaacttgaacactgtgagcagggggagtaaaagtgcatttggccctgtaataagaggactggcagtgagtctgtacaaactcaagtccacctcttctgttatttgacctaaaaagccatcagattgtcctcattataatgatgcatatttgtatgtatgagagctgtaatttattgattctcaagtctcttttcctcagagccagtttaaaacaattagaatttgcaagctgttccataaaagataagcacccagcatcaagggtgacattttacaaaagctgactagtgcatgttaagtaggtgattacttctgtggcctccaagtgcctcagccatccctgtccaaggcaactgtcctcaaagaacacattcaaggaaatgatgttgatatttaaggggatcacaggatgtggggagtgtattctaagcttaatcattatcaaagttcaaattttagaaggcatttctcactgtttcaacagctgcaggtcttgagagctttgcctcctccttcaagagacaaagtgaactagccaggaaaagttatcatgtacaaacaattctcagtcatgcctggcttcttgatatcaatactcctctgtaacttaatctcctcaaacccttttggtaagttcatataagatcaaaatcaacagccaattccctgtgaagtcaatagataacataagacataggggaaaaatcaaagagatacatgaatcctggctgggtgactcagttggttagagcatcatcccctgcaggtttccggttcaattcctagtcaggacacataccaaggttgagggtttgatcccgatcagagatccactgagaggcaactaatcaatgtttctctctgacatagatgtttctccctctctctctccccctttctgtctctctaaaatcaataaaaaaaatatcctcaggtgattaaaaggagagagagagagaaagttgaacatatttgtgcaatcatttactcaattatatctgcattagaaattaaagatgaaagtaagtaaattaagtgacagtccttgatgggagataaagagctgtaaaagtgctctctacagggagctaagtactacaacaaaacgccggagcagtggggtcaggatcctcccacccatctggaggagcataagtttgacaaatagatgagacaaggataggggatccagttagaaaacttctttttcagaagaactagagaaggtacaaataagcaaagcaccttgcattcttccatcagggaatggatttaaacccatctccagtactgctaaatgtccctggggtagggaggggtgactgggtaaaatcatcccactttgagacttctgacttagagaattaatgtttttaattattatacacacacacacacacacacacacacacacacacacacacacactagatttgattttatattgtacaagaggcccggtgcatgatattcgtgcacggcgggggggggggagggggtccctcagcttggcctgcaccctctccaatccaggatccctcgggggatgtccaactgcccagtcgcccctaacctctctgcctgcctgcccgatcactccaactgctctcccctgcctgcctgatccccctaaccactccccccttttcgcctgattgcccctaactgcctctgcctcggccccaccacagtggctgtgtccggaaggacgtctagacggtcatccagaagatgtctggtctaattagcatattacccttttattagtatagatgttccacttattcctgttgctgccctccctttcctccctctctctctcttatacacacacacacacacacacacacacacacaccctctatcctatgggtggagcgggtcaggctcagctcccagatgcactttgctcccctcgctccagctcctgagtccagggaaagagtcacagggaccagtgcccaccaagcagggagcaggggcatttctggaaaaggacaagcagcatacaaaatgactccttattcaggcacagagaaaaaaattagttgttgctcagataattacatatgtgccacttgttaaagatcaatgcagttttaaaagaaagttacttaataacctcctccctgtctcacaagcagaatgacacagatattttagattcatacacccacacacacttctaaaataaatgaggcagtttacaaaattaagtaaaaagcttttaaaaagtcaagattaaaaataacaacaaaaactcaagaaaattacagagaaatgctagcaaactcgagatggatctattacttgtagttacaccctggaattggacttttgcattttctaaccgattgaaaatgaaatatatactacaatattcttaaaatagcagatacgaataaagtcctctgggggtacagacaacttctactgattgtccaaactgccccaggctgggcaagagatcagcctggacaaagatggagctagaatcccgagtttctgacaccactttgcttaaatcagaggatgaaaactggaggactatagaccaaacccagctgactaacatgtatttgaaaataacactcactatgttattttaaaacactaattttaaaacaactaaatttcatataaaaattttaatttccagcttctcttaaaaaacccagagatctggcaacactgggatgaattttcccatggcaacatggacataaaccatgaatgccttggagttgggcatgtacctttctgttggcctaagttcccactagctagctgcttcacccagtgtgttaaccgattggtcccacttactagcaaagtttgcaaccctattttgaataaagaaccaagacaaaggaagtttacctttttaaaggagtttccctagttaaaaatgaccaatttgattgggaagaattagtcagggttaaatgcttgagagttaatgtaacagctttgatatcagccatgcctactaactccaaaaccagaacaaaataccactacaaacaaaagggcttgattttaatccatctacttagaacattttcctactattatatatatatcaaaaactaaattcagataaaaaatgtagtacctttcatgatttagctccaattctttacccatccctacgtgcactgctctcagaggtcgagttacctgcccaggccccttcctctgggctcagctatgtgacctgctttggtcaatgggattctagctaacatggcacaagtggagtcacgaaaaggcattacacactggaacttgcctccctgcacctatcccatctccaagaagacatgcccaggatatcctgttatcctgttggaaggtgtgggaatacatagttgcaccagaggcttccagcttaggtcagcagaccaggtgatcagccagctgaacccagataaataagtgagtccagtcataataagcagatagcttagctgactaactgtacaagcgataaagttattgttgtactagaaacctggtgcatgaatttgtgcacaggtggggtccctaggcctggccagtgattagggctgggccgacaactggggggggggggggacaaagagagggactgcaggccaattggggcctgccagctgggaggagggatggggtatgggaggttggcctccagcctctacaagggaaccggccctcagccccctgggaaaggggtcacatccaccaccacccaccctggttccccatcccagccctgggccaaaggtcccagcagggttgggagaggaggcgacggtcacggaaggaatggacgccggacgctgaagctgccgaccagccacaggaggttggctgtgggagcgcactgaccaccagggggcagctcctgcattaagcgtctgccccctggtggtcagcacacgtcatagcaactggtcaactggtcgttccagtcattcagtcatcagtcgcttaggcttttatatatgcggacgccttgtatgttttatttgttatgcagcaaaagctaagtggtatatatattgtgaacactgcgaaagaagatacctaccaagaaggtctcctggtggctaactgggctcaaattttaaaaacagagactagcagccatttccacacaaactgcacttcacacagaagcctgcactgaactgcctgcctgcactgtttttctgtctgctgagccagcccttataaaggaagtgctggaatcctatttcaaccaatgggactgaggcttcccccatccaaacagagcttacagctttatccccatcaacatcttcactgaccaatcagagcagctcttttctgaccaatcaggaaagtgccttttggacaaatccaactacaaggatctggagtccttgtttgcatgaggacagaccaatcaaggtcacaggcaagggcttctgtctatataagccagctcccctctggctctgagagtgcacctttcctttccaccaaagactgatccctggctgagataaaacaccaaagatatctctgtctcactggagcagagctgaacagaccaacatgggccagagaagacaggcaccaaacacagaatggagaagagcagaccagcacatagctgaacagaccagcaaggaacagagatctctagcagagaggggcctggccccaggtccacctcatcggcttgctgttttcacggctatgctttatcacaattgagctgttttgcactgaataaattttccttcttcaccacaccccaaattggggattcctgttggcgttgaattggcaccaatgatcatctgttgacaatatgtagtttactaataaatcattttattggttcagaaaaaatttaatttcctgaagtttcctctaaagactactctccttgagaaaacaagttgttttcagactgtcttctggtggtgaggagggagtggggagggcaaattcaaattaggatgcacaaaataagcataagcaattgatatgacaagtgacagactagcaattattgagagagaaaaactaggcaatcataaatagcaattggggctatttaatctactccccataacattaagattttcataagaaacaagctgtttcttaaatatattataaagcataatacttggtttttttcctcctattttttaaagtagaaacagaaactcctcttgactttcctagtgaaaaaacaccactaaaaattttaagaaagggaaatatttctgactgctatttatacctcaaatttctatgttgctttatagcttacaaagcattttctttagcactttctcttttgacttccattcaatcctacaaagtgggtataattgcaactctttattttactgctaagaaaaacaaagctttgaataaaatacttgcccaccattgctttgataaaaagttacagtaacagaactagaacccatatcttgtgtctctaagccagtgcttttccactacatttctaggagcagaactgtgtaaattctaaatacattgcccaatcactgaaatattttctttgtccatccctatcatatttcttatcaccctcactcccccaagaaatgcatttaaggccagagtatgtcatccatatgtgcttatctacttaaaactagagatttctataatgaatacaagataatatgtaaatatcctataaatccaactttctacaactattttaaaatgtcttttaaataaccctttctcttgttaagaatatttacctcttcaggcagaaaagcattctttttttttctttttttttttcagaaacatcataaaatcttaaattttattttttaaattgtattttctttttggtgtacacgtattttctatttctctttttcctccactcttctcaattcccatatttcttccttgccccacacttactttatatatttagatctttccttttaactcttctataataaaggactgaaatacatttcaagagttttgtatttcttttttatcattattaaatttattggggtggcattggttaataagattatataggtttcaagggtacatttctatgatacatgatctatatattgcactgtgtgcccaccatccaaagtcaaaccattttctgtgaccatatatttggtcccatttatcctttactaatcctccaccccctctcctctggaaactatgagtttcagttttatatcccatatatgagtgaaatcatatggttcttaggttttctggctgactttattttgcttaacataatatcctcaattttatttcttgttcttaattttcaaagtggataaacagaataattggcatattcttttcaaaatgtatagacttctaaattttaagaaaaaaagctaattgaagttcttaactttgatttccccatgaactgtttcctggaatgtttttaaatgtacataaaaaatttttaaagatactggattagatagaaatccaattataatgaaattgaattattgggagtaaatggatgaggactgaagttaagaacctcaatttcaaaaaccttcaagaaactcaagttgaataatgctgaataactaatgtttcaatatcagattgttgtttgacaataaccctacaaggtcagtacactgtcatgatatatacctaagaggcttaaaggcactaagaaaggtactcaaggctacacagctactaagtagcagagctgagtcttgaatctttctccaaggtccagatttctgaccatctaaccgtgctcactgccacgtgcactactcataaatttaagactttttctcaactcatttctagccaccaaaatggtttctttgacttttgagtcttttcctatacattccaactccactggccacctgactgaatctaggttcttgaatcaggaattcaaggccctcggcaagccacctgtcttaataaaagaaccacagaaaacttaaggcctacattcagctattacaacaactattcttcccccactgccacccctcattaatgtcattaggtctgggtggaatgccttctgctatctagtattgccacctatttaaacactcacttgtccaggcatagctcaaataacacaatctcaatgaagctgtccacctctagccagaagtgatctttccttcctctgcatttgtatagctctataattatagcaaaacatttatgaaatgtcaaaatatctgcatgaaatacaattatttgtgccacagaatttttttaaatttttctttatgctcacctaaggatatgttttattggtctgagagagaggaagggagagagagagaaacaccaatgtgagagagaaacatcaatcagttgcccccacaggtgtccagaccagggatcaagccacaacctaggtatgtgccctgatggggaatcaaacccaaaacttttttggtgtaagggatgatgctgcaatcaactgagccatctggccagggctgtcacagaatatgtcatgttcattttgtcatcaaacctatgctggattcaccacttggaacattcttttcacttcgttttccctttgctaacttctacttttctttcaagtctcagctcaaaggaaacttcccctagaaagtcttctttcactccccccacccctagcccaccaagtatccatagtggataccaactcaacactgcccagagattgctaactggctatttacttgtctctctccccactagactggaaatcttaccagagactatttatgtaatccatggttgtatttcaacacctagcatatttcctggcatgtagttggaacacttttaaatgaatttacaattacattttcttattatcctgtctgattaatccagagatgaatttcaaagtacaggaccttgcaattagtaaatactaattaaataattgttgggtaaaatgattcttgtagaaatggcctagattaattatcttacatctccaaacaatatggattaaactgcaaaatagtaaaaatatgaacacttgataatatgtcctttatagagaaaacaaagataaacactttaaatccatttgaataaatgcgttaaaacaaatgaatcacacttaagcttgtttgaattattgcaaatcatttaaatacattattgtcatctacagctatctgcactcctcaattattatttgtctgtactataaagcactacactccaaattacttaggttctttatcatctaggtccattctcagtatgctttcaatgtaccaattgctgctcataagcaaacccatttcttgccaatttaaagccttcagtctctcaccatggagccttttccttttttctacaatctataaaattactttatctcccctagagggtattatggtaagtgaaatagtcagccagagaaagacaaataccatatgatttcacttatacatggaatctaaagaacaatacaaacaagcaaacaaagcagaaacagactcatagacacagagaacagactaatggttgccagaggagagggggctgggagactgggtgaaaaaggtgaagggattgaaaagtacagattgctagttacacaaaacagttaagggaatataaagtatagcataggaaatatagtccaaaatattgtaataactatgattggtgacaggtgagtactagaaatatcagggggaacattgtaaagtatatgattgtctagtccagccgtgggcaaactacagcccgcgggccagatccggccagtttgaaatgaataaaactaaaataaaataaaaaaaaagaccgtacccttttatgtaatgatgtttactttgaatttatattagttcacacaaacactccatccatgcttttgttccggcactctggtacagtttaagaacccattgtggccctcgagtcaaaaagtttgtccacccctggtctagtcactatgctatacacctgaaactcatacaaaataatactgaatgtaagctgtacttaaaaataaacaaataattttttaaaactgcttatctcttctttctttaaaataacaatcatcgttcacttcttccacaatgtctctcttcttcacttatccattcatcctgagcacctgtgtcatggcaaaccctgtgcacattgtagattctatgttcttcagctaaatggatacatataaacacatatatgtccatctcccaaacacccacacaacagcattgtactgatcaatgttaagggttacgtgaatttcagggaggagtgaatatctgataaggaccctgtagcctgttaggagcatttacaattattgataaaaagatactagaagcaaggttagggggaaagaaggacaaacggaaaaatattcgcattatatcgaaaccaaaggattcatcatctctctgaaaaaatgattttaaaagaacaaaccagtactaaaagatgcaaagggtatataaacaggcaattcacagaatacaaatggccctaacaagtatagaatgttctttatattcctaatcaaaaaattgaaaattaaaataataatatgatatgcttgtttatctgttttgtacaaatttaaaaaaaatagctctcacctccaggattgacaagggcacaccttgctgtaagaatattaactgaaatagatagcttttctggagaacaatctggcaagacaagtaaaaaataaataatatgcgtatgttttgacccagatagtctaattctatgtacagggtagggcaaaagtaggtttatagttgtaagtatgcacaacagagtttattcttatattattatttattaattattgtattgttttccatacgagcaactataaacctacttttgccccaccctgtatagtatcctaggaaaacaaaagatgtttaagatgtatgtatacatttcatgtgtatatgtagaaagagtttaattgcagaattaaaatagtaaaaaagaaaataagaaagaattacaaatctactgataagggatacattaaatatagtcatttggaatattatgtagcagttaaaagagacattatagaattttatgtactgacatgtaatactacattattgcaacaattaaatacacactacagaataacatgaatatattgaaacatttcatattagaatcagctcagtgatactacatggataccactgaatctactctagattatttttatattattcccaaatatgtcaagattacatctgagaatttgtgattatatgaccttatctggctcttccagctctaaaattctttaattctaagaactttgtgcagcatagatcttggacagtgttttcataaggccctaaagggtctcctatataggtttaagtgtcccttatcaaaatgcaagaggaaaatgctaaaaagtgtccagagttttacctctacatctgaaaacttgagttcttaatactacatccttcattatcaatgacaattcatgctgaatatgttcattttacagtaatcacgaattataactctttacctcaataataatgtaagaaccattatatcttggaaaaactaagataatagaaccctttgaatatttaaagagattaaatagcccatctcccttcctctctgaaatctataataaaaatatatttttctgaataaataaataaaagataaataacagtaaattttgcttatatggtactcttaatctaaaaatgctgactgtcaatcaaatcccactgagggcaatcttagacagcaacggcacctcttcatactgggcaggattgagatttgtagaaagaacacccgggaatgaaaaccactctttgtgctccagaatccccagcaaatcacatgtaccatctgagcttcaactgtctcatttataaaacaaagaatcctatataataaaagcataatatgaaaatcgaccaaacgtctgaacagcggaatgaccatccggacaaccatccgggaccatgctatgacacccactggcgccaggccagccaaggtaggtgcgatgcgattggtcggaggcccggccatcgccccattatcgccccgtggaggaagacccaggccaccggcctgcggggcgatcaatagggggctccacatcaccccaaagagggaggccaaggccaccgactggtgggctgtggcaggtggacagggcctccctctgcgaaggaagcccaggtcctggtgccggcagccaagggaagaaaggcctactcttgtacaaatttcatgtatcggaactctagtagcataataatgtccagccagcatggctcagcgattaagcctctactatgaaccaagaggtcacagttcgattcccggttagggcacatgaccaggttgtgggctcaatccccagtagggggtgtgcaggaggcaactaatccatgattctctctcatcattgatgtttctctctctctccctctcccttcctctctaaaatcaataaaaatattttttttaaagaatagtgtaataaaaatattatatatatatgtcacatagaaggtttctattactgtgcctggggcaaaataggttctcaaatgtttgtctaatggaaacaattgcatcatttttgtttttgttaaggtatctagtctgttcccttgaatttttataactctcacgcacaaccattctatttaaattttacgctgttagaaagggacttcttgcctctcaaaagcttatttgttgacatactcttttccactataaatatgcaaaaatgtgtttagaaacaccgggagaaagcatacttacaaagcacacccccaaatcgccgtgttgctctccactgagctcagtgctcttcttaggcacatatgtctgcctcctatcatttcttcatgaggttcagggcaaaaggcctagtcaagtagataatctttggttgcctctatattttccccaaaccacctacagataaatgaaacaaggattaaaacacacctacaactttaaatttgttaaagaaataaaagatgaaaataagctcaccctcactatatacagttcatggcatatcagagaacagagaaaatgctccttgggtcatgcaaaagccccactgaactcaaaaaaactctccacatccaagtgcccaaccaacatactcctcacttgttacttctgcccatgcctggtcatccctagggctggccagatcatgcaattgtagcccaagtccacctaaaaggactctctctttcagcatgtctatcagagggtaaactaagtcaaataattaatttaacatgatacttctgaatttaatgacccagttgaatttctaagccagttaacgaactatatatgctagtacgcctaaacgatatatttcgtaagctacccagtaccacacacatttagtactgcaattaaataagtaaccataaaatgtctttggttgtaagaaagtctgtggacagaaatattttcaattctttgtgactgcttttaaagcagtctgtaggaaatcacaggaagtatccagagaactagtagttgtcacataagaagacctgagactacatctataaaccacttcaagaaaaagtaaaaaactatcctggaaaagttaatcaaaataaactgtggagagctccaaacaacacaggtcttgcaatggcagagcggacacgctgagagcactcaggttttatgcatacttcactcttctaacagagcataaccttcaccccatgggctgggtcacagacacatcccaatttctctgtgccaatatgaagctgctaaagatttcaccttgaatctacactgtgcaatacagtagtcactccatacgtggctactgagctcttgaaatctgcccagtttgagctcacaggtgctgtaaatatacaatgcacattttggacacttagaaacattaaaaacatatatacatttaaggctgtaaaatgcctcaatcaataagtttccatactgattacatgttgaaatgaaaacattttgtatataaataaattgtgctaaataaactattaaaattaacatcaccagtttcctttttactggtacaatgtggatactggaaaatttaaacgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtctcacataatatttctacttgacggcactgttctgcataattagtaaatataaataacaaatactgagtacttccaatgtgtcaggccctgtgctagatactttgcttcatacttggaacaacgttacagtgcggtcctacgaggagcctgcggaagccactgggccccatcaaaccgatcacagttgcagctggaattcaatgtcagatgttcctacgaaataactcatatcacgggcagctaacgttggggcaattcccatggtggcacaggagaggccgatacagcgatacagcgtctgtgactagagaacaggtacaaaacggccagcgctatcccagctctatcccaggccaggcgagtcacctccaaaatgagtccgatctccttgacagctcaggacatgccgctcgcaaaaggaggaccaggaagttcaaattccctgaatagcttggcacagaccaggctgtggatgcccatgcggagggggtcgcaggccgggcaccccgtctctccccaccctggcgctcacactaccaagccgcggccccaccccacatctccgcgcggccagtgtccccacccctgggacaaggagaagtgggacttaaaacgtctacaggacagggaagtggcaaagaaagggccacgggcggtggcgggcaattacctgagattgagagcccaggtccttaatgccggatcatcgccgaggccccacccggctcccacggccacctgtgaccgagaaggtgcaactgacccgacgcggtggcgcaacgaactgagctgtgcccagactggcagctatggcaacttgaactagccgcccagccgcggcaagagtacaggaccctactggtgccgcttggccctctgggagttgtagtccgcatcgtcctctaaagcaatgagttaactaagggactctgcccctaaaagaaactgcaagtcccaggatgccaaacgattgtcttcggtgactttcccggaagaagcaggattcgtcggcacctgaggccctaggacgcaccctctttccctgttttgtttttttaaagggccagaagcgtatattgaagacaaacaccagctagagagagagctgccttggcccagactgtaatttaatcaggaaagtctaagatatttcctttacttaaaaaaaaaatcaaagtagttgcaatactaacatagactatatttttgttattccttggggaacaggcaggtgtaatttccagcagagaaatgttaaaatccccttcgtgtaataataccagtgcccaatgtcttgtggttcacaaattcttagatccggaaggaaacagaagattatctagtcacaccttttaggcctggaaaaagtaagctcactgatgacaaattaaaagtggaatttgagaatgtcacttcaaaactgctgccagggtgtcatctctccgcttattgtggaacctgaaagagacatagtccgctcagagaagtcggtttcaattgcgaaaaagtaactttaaaaacttcaacaaggaactgagctttggaaaagctaagaagaagtgaaaatccaaattcgtcacgaagatggtcctttccttctgctgttgatgctttctttcctcctcaaggctaaagtcaagttttactttatctgtgaagccttcctacacagataaagcaagatcactttaacgacatggattccctatcctaatcattgtgtgctgtaattatccattccctgttggtacttacattagattctaagcctttcaaacacagggacctaacctgttaaaatttccatcctcccttctctctctctctgtctctctctctctctctctctctctgcctctctctctctctctctccctccctctcacacacacacattaataattatgatctattatatcatatttgatatatcagaagcattaaaatatttttcctggctggccaatactgtgaggtagatgttattttataaccggtttgaacataagatgattattctaaggacatacctatgtatttgcatctgtcttcacgttgcttgctcacagctgtattcaagaatacactcatgctcgcttcggcagcacatatactacaattggaatgatacagagaagattagcatggcccctgctcgaggatgacatgcaaatgcatgaagcgttccatattaagaaagaaaagaaaaaaagaaaagggaagggaagggaagggaagggaagggaagggaagggaaggggaagggaagggaaggaagggaagggaggagagaaaagaaagaggaaaggaaaggaagggaaggaagggaaaaggaaggaaaaggaagaaaagaaagaaaaaagaaagaaaaagaaaagaaaagaaaagaaaagaaaaagaaaagaaaagaaagaagaaaagaaaagagaatacactgcaccggacacaaatgttaacataaataggaacagtcattaaattgccccatgcacatgcagaagcattagagtacctttatttgtttacattttaatttttcaaaacaattgtactaaaaaaaacaattgtactcattcatttaattcagcaaatgtatgctgaatctttctaggatccagacattatattagacacttgaaatgtaatgaaaatgagaataataacaacctagtttctgccctcatgttgctcagagtcaagaaaatatgaagaagagcagtgccaagagaaaagggattcctgagtgggaatgtgataagaaacagagaaaagagtcccagaatggagagttggagatttcggggctgggggtgcaatgcagacctgaaggtggtggaggaaagcccatgtccatagactgctcagcttctactcaagcaagtactattcatagtctggacctcgctgtccgcgcattggcgtgaagagaagacagcctgcattttacccagtggttgtccagcacaagtagtaaccatctgttccattccacattgttccatctagccactagatggtcgagcctccttgtaatatcaccagacaattataagggataagaaggaagacagagctccgaagtgggatgctatgggtaaggttaaagagaaatctccaacatcctaattggaactacccaaaattctctctgaaccaaagcacaaaatgatcattaatgattgttaactcttcctgcatcaacttttcaagctaactgaaaatctgggaaagttaaaatagaagacaagatgttgcaaagatggtattgccaactactcaaggaatcatcttcagctattcatgtgtgccattgatcccataatattcttttcagccacacacttattaattataggtatatgtcactgtcaagagcatcacaaatgtaaaacacagcaatgtgtttgcatttaagtcaaaatgaataactattaatgcacaaatccaaaatcataaaatatttttattatagctaactcagatagcctgtgctccactttaataggtacctttgtgtgtggtcggggggggggggggtggataaacactagacagtaatgccatgctaaatactactttctgatatctggaccatgctaacaattcttctaacaagaaggaaaatgtaatgttcttaagccatttctcattcattctgtttatatttaaaagcatttttgtggttaatggatcagaatgtaaacacttcttctcttacttaaactggttgatctctcatcccatgcttttattggccccagtttcaaaagttaggctaaggaaagaaaagtgcctactgattatcatagcaatttgttgagaaggttattaaatattagaggcccagtgcatgaatttgtgtacaggtggggtccagccagcccagccccaataggggcagattggtccaggcctgtagggaagaggagatggcaggaggtttggccagccagttcgccccaatcagcagatcagggtcgggccagctggggggagggaccgtgggtgattggccagcaggccctgcccccgattgggggggggggggggggttgggcaatcaggggtcattggccaggggaggggccatgggagtttggtctgcaagccccacccccgattggtgtgtggggtgtgatcggggacagagctggctggggggaggggcctcaggccgattggggtggtggggacccattgggggtgaggccagccagggggagcggcttcatgcagttggctggctggccctgccccctattagggtagagggggaaatcaggggtggggttggccagggggaggggctgcaggagattggtcagctggccccacccccagatcaggccggttctctggccacagtgggcgtcatagcggctggtcgttctggtagttacagtgtttcagttactggctttttatatatagagatggttaccctgaagatttggtccactttcctgaaatgaaacaggtaagcatggaagattttacctacattatgaccaccactgagccaatttcatgttgcctaagtcttgattaaaatgttacagatttttggcataccacttatgttcccagcaaagatggaatagcatagaagcagagagcagactttccctgcacccagaatttttaaaaagtaaaaagacaccactagccagcatggttgagccagttgacctatgaaccaggaagtcaaggttcaattccaatcagggcacatgcctgggttttgggcttgatccctaatggggagcatgcaggagacagccaatcaaggattctctcatcattgatgtttctatctctctccctctcccttcctctctgaaatcaacaaaaaaatatttttaaaaaagaaaaaggaaacatacaaaacatatgaaacaatgctttttcagacaatagacattatataaaggccagtgatttcctaacagacaggaaagaaacaacatgagccttgtgatccccacaacttcctaccttgagagaatttccaggccatggctcaaggagaaggaacccaggcagagctccgtggatgctttgagttgacaagacagagatgggagtttgtgaaaaccagtgtagatggacaaagtagcaaagagaagagagctacatacagagaaaactctaaagaactagggaacgtcttcttggaatattcagatgaatacgtgaagaaacggaggctggagaaggaagcatctaccaagactggggaggagaaagtacctgtcactcacacagggccaggaatgatgattatttccaccagccggatggagacacctcttaattcacgtagtattatgtagagtgctcagaagagtcttgcctcaggagggaggagtaattggtgctaaattaaatgctattcccatcccacctcacaagccttgaaagcaagacccaaaaatatcaaactatttccaagtaattttcccacgtctgataacaaatctcaaaaatatttctatgaaaacaaataatccagtacccaaagaggtgaaatttacaatgtctacaatccaaataaagattaccagtcatgcaaagaagaagaaaaatgcaactcattttaaggagaaaaatcaaccaattgaaacttacccagaactgataaagatattagagttatcaaacagggacattgttaggggtagaattgtgtcccctgaaaagataagttgaagttctaatacctggattgtgactttatttggaaacagggtgtttgcagatatgcaagttaaattgaggtcatgctgaattaatatgggccctaatccagtgactgatgctttcatggaaagagggaatttagagcagagacacaagagagaatactgtgtgatgacagaggagagactggggtgatgcgaaccaagggcaccaaggactgctggcaaccatcaggatctgggaagaggcagggaaggaatcgcccttagaaccttcagagggagccatgaccctgccaacagcttaattttggacttccagccaccagaactgtgagtgaattcatttctgttgctttcagccatcaagtatgtggtactttgttacagtagctctaggagtctaacacagacatcaaaagtgttttagatgtcaaaagttacatagagacaggggaaatatgaaaaaggcccaaattgaacttctagacatgaacatttcacctgacataaaaaatatactgatggaatcagtggcagatgaactatttcagaaaaaaaaaaaaaaagaatattgaatttgaagatataaaaaagaaactatgcaaaatgaaaaagagagaaaattaatttgtaatttaaaaaagcatcaatgaaacaaaaaacaaaaacaaaaaaagcataaatgagcttttttgtagaacaactttaattagcctaatatacgtgtaataattggaaagagtagagagacataaggggacataaaaataaatggagaaataatggcagaaatttttccaaaagtgacgaaaaacagaaattcaccctagcagtatagttgagttggttggaacatcgtccagtacaccaaaagatagtgggctcgattcccagtcagggcacatacccaggttgtggattcagtccccaatagaggttgtgcaggaggaagctgatggatatttccctctcattgatgtttctctctctctctccacctcccttcctctctctctaaaatcaataaaacatttttaaaaacaaacataaatgcaaaaattcaagaacctcaaaatactgcagaagaaatatgaagaaagtacatcaaagcatatgataatcaaaatacttccaaccagcgataactagtcttaaaagcattctgagggagaaaaaagcatgttgcaaaagaaaataatgacagaacatttgtccttggaaataataagatagtggagcaatatttttaaagtactgaaaggaaaaaaatactttcaatctataactctgtgcctagtaatgctatccttgaaaaatgaaggcaaaattaatacttgttcagacacaaaaaagatggaataatgcatacccaacagatctgtaccacaagaaatgttaacaaaagtgttcaaagtaaaagcaagattatgtatttttttaattgattttagagagaggaaggggggagtgagattttatatatatatatatatatatatatatatagagagagagagagagagagagagagagagagagagaaacgttgatgtgagagagaaacatcaatcagttgcctcctacatgtgccccaaccagggattgaacccacaacatagatatgtgccctgacttggaatcaaatccacctttcagtgtactgaatgatgctccaaccaactcagccacactgaccagggctgttttttgttttgtttttttattgaaaaactagaggcccggtgcatgaaattcgtgcatacatacggttccttgtcctggcctgcgatcaaggccatcttccccagctgcccacagccggccctgcccccgccgccaccaacccccggttccctgtttgccattgaatgatcggtgcctgacggccaggggaagggaccgagaggttggctgttcctgcccactcgccagccccacccctgccacggccatcaggccatcagagcctgctggccagggaaagggaccaagaggtggtcagtgcacctcatagtgactggtccagcggtcattctggtcattttgccattagggtcaatttgcacattacccttttattatataggatgattatattggataatattccactgtatggatgtatcactgtttgtttacccattgcctagttgaggaacacttgggttgtttccagtttgggttaattatgaataaagccctaaaaccattgaaatatacaaattttaaacatacagtccaatgaactttgaaaaaaattatgcattctcttacctccagtctaattaagatatagaacatttctataaccctggtgagtgctctcctatcttttttgaatcagtctcccctaaatcgtgttctgatttccatcactatagttccccccattctgtcccagaaagtcatataaatggaattacacagtacgtgaagaattgatgttcttttcatcccaagaagaattagtaactgaaggcttttaagaaggaaatggcacaatctgatttatattttaaattattatttttggctactgtgtgaagaatggtaagtagatgatggtgtgccacttaagtgttatttttcttcccatctttggggggattttggggaaagcggagctatatgatgcaataacattcctggcagtccagaatttacctttaggcttcaagccaggtcggaaggccggctccagagcaccagacctgttcctgccattcctggttctgcccagcagatggccccagagcctagttcccggcccgcctagagccaagtccgcctgctgcaatgtgagctgacgcctccaggtgactcctcaatacaatttctgtgcaaagcggtcgggtttgcgctgaagttggggagcagtgagggtccgccagaggtattgcgccccggcttctccgcacctcaggctggcatcctcagaggcaccttaggccagaaggatcttgacccgcgtctgccctggacggtgcattttgcgggaagttttctctgcagtgcgtgcgagccttgggggagaagggggagcgggggagaggggtcctgacaggcagcgcttttcggaatctacccacgggaaaaggtggcccactggacttaacgacaagggaagggcggcgggggggggggcgctctccggaacatatggctctggaaagagctaatggaaggaacgcgcgaggctggctggaaagcagggtggggacagcagggactggtgttaagtgtcagggaacagacagagcgggctgcgtggctcagggctaggaaagtaaagccaatgggcttgtttgcgtggagagttgcctagggaaacagaacacttgagagcctctttgccctctccagcctcctctttggtgctgaagtcacaaccaccaggagtcctctttctcccactcctccctcgctccttccgcgcggggagctcggagcacagagggctgagaatgaggcgatagtggaggaagaagaaatggcctcggacccctggaaaatgaggccgatgcccctactgcagctggcgctgcttctcggcctgcccaggagcttaggggggaaagggtgtgcttctccgccctgtgagtgccaccaggaggacaacttcagagtcacctgcaaggatatccatcgcatcccagtcctaccgcccgggacacagactctgtgagtacctgggagaggagagggtaggtcccagaggccaagggcagccggaaaggtggacggaagtgcacaaaaagaacttgagaacaggccaaagggtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgcgcgcgcacgcgcgcgcaatgaataaaaactcaatcccataaatttgggattgctgacctcatagttatttaataacacaggaaacggtaacaaaactttggtacaagatgagctattctgcatattccctgctcctcgcccaggctaaatcttccttttacctcaggtatgaacaagattagtagcaattcaagaactgacttttctatttgatattgggtaataaaaatttgcaaaaaaaatgtatttctccttttagtcttccaaaatgggaaattatcttagctggtcttgctggttcatcaaatagttgaaaaaatttagtcaggtattcttttttaaaatataccctttatattttccatgaaggtaactttgtatgaagtacctgagttactttctcaaaggttaactgcccactaacatagtggatccagaagtttcctttgccataggcatgggagaggaataaagaggtaaaatttcataaaatgcattttatctgcatattaaatgatgccaaaaattgtcagatggttattagccttattggggtgttatcacttcatcctatataataaaagcctaatatgcaaattgaccaaacagcagaatgaccagcgggacgaccggttgctatgatgtgcactgaccacaggggggcagacgctcaacgcaggagctgcccccagcctgcaggtcccaagccagcctaggcaggtgccagtgggggatccccccgatcatcctgtgggtcaccctgcagagggaggcaactggctgcagcgacggggtgatcaggggatggggcgatcaggggatggggctagctggtgagcggcaccaggccggccaagatgggtgccagcgggggcccccccgatcaccccaccagtcgccccacagattggtcctgatcactggcctggcctagggaccctacccatgcatgcattttgtgcaccgggcttctagtaagttatataaatgtctaatcactatgctgtacacctgaacctcatgtaatatgtatgtcaactgtaatagataaaatttatttttaaaagttgccaaattaaaaacaagggtcaacaagttctattgtatgcttattccttaagaggcatttaaatcaatgaccattgaaaggataattacagacaaaagccaggaaaaaggctttcttgggtggttaaaaatggagcacaaagaaaaaaaaaaatagtaaaacaacctaggctggttaaacctagttcaggtaagataatacaagttattaatgtagatacatgaaaagcaatgatgaagttgcacttcaggattttctcaggactgtagctgatagggacattaaatagtggtgaatgttgtttggtgattaatgttgcagtacaggttctgtgctctgaggggagtgcaggaagctgctgatggatgattctctcatcattgatctttctatctctctctccctcccccttcctttctctgaaatcaatataagcatatattttttaaagatacagattaggggtccgttctttccagaagcctctcttgatctatgacccctagactgggtgagctccccccccccccccaacattctgtgcacaacctctatcctagtccttaaacatggcatgcttttctgtaacttatttctttgcatgcctaccaagtaggacacgagctcctctaacacggaaaccctgtcattcaaccttagaactactttgatgttcaaaaaaaagtttaagtgagtgaatgaccgaacataaatatgctagtctcattattcgctgtgaggataaagaaggccagagagatcacttcttcggggacttctttaaaggtggcagaattccaagtcattgaagagaaatgaggctctgacagtggaagtgaatttggattcatcctgtcaattccaccaaatgatgaggagaaagggtaacatcagagaaagagcgatggaggaggagtcaggaaacctgcattctctttacccccctctcactgatggtgaaattaggtgagatcatggatttagaagaacccaagtttccttctgggtaaaacagagggtttagttaggtgctttctgatgtctgtgatgctcaagagggaatccactgagccacaaaggctaagaactggatagagacaggagcaaggagaatctgaccttaaaaacaattagggggaggaaggcggtgggactattctgaagaattaagttattctgagatagagaagagaacatttaaaagtatgggtaaagtggtatgctaatttaaataatgactacaaccatctacaacagtagcaaactgatttttgaaaattttgtggggcaatagaactctactgccccacaaagttttgaaaagtcacagtggattcccttctgtatgtcctctttcaaaaagtgtctatttaggtcctttgcccattttttgattggattgtttatcttccttttgttaagttatatgaattccttttgttaagttgtatgaattctttgtaaattttggagattaaacccttatctgaaatagcattggcaaatatgttctcccatgcagtgggctttcttgttgttttgttgatagtttgttttgctgtgcaaaagctttttattttgatgtagtcctatttgtttatattctccttagtctccattgccctaggagctgtgtcggtaaaggaattgctacagattcaatgcaatccccactaaaatatttcaaaggtctagaacaaactctccaaaaattcatctggaataaaaaaagacaccaaatagccacagtaatcctgagaaagaaaaacaaagttggagggatcacaaaaccagatatcaagctatattaccaagccacggttctcaaaactgcctggtactggcacaagaacagacatacagaccagtggaacagaacagagaacccagaaatttacccaagccattattatgctcaattaatatttgacaagagaggcaagagcatacaatggagtcaagacagtctcttcaataaatggtgttgggaaatttggtcagatacatgcaaaaaaaaaaaagaaaagaaagaaactagatgaccaacttacactatacacaaaaacaaactcaaaatggctaaaggattttcatgtaagatgggaaaccataaaaatcatacaagactttacaggcagcaaaatggcatctattttcttacttcagctctgatagcatagtaatacacataaaacatattattaagtgagtgaattttatctgctttatcaatcaattgaaaaagttttttccctccagagctgagaaattgttaacttgaattgatctatttgattattttaaaatttccttgttgtacaaagtatgtttattacccttcagatgaagattaattacctggaggttcatgggcttcgtgggggtccattcagtcctcctgggaatctgtgatgaaatgaaattttgaatacaagtaaactgctgaatctataaccttgctcagatttccagaggtgcccttaaccccacccccaaaaaagtcaagaaattgtgttttgggagaatttggcatttttgtttaataactgtatatttggtattaaatgtgactcagtccttttattactagaggcccagtgcatgaaatttgtgcactcggggtgggaggtcctctcagctgggattgcaagacagtgcaggccaggctgagggacccaaccagtgcacaatcggggtcagggagggatgcgggaggttggccagccagggagggaccctgggagggctccagggcgtgtcggtcccatctctctcagtcctgatccgccagaccccagcagccagctaacctaccagtcaaagagtctgctcccctggtggtcagtgcatgtcatagcaagcggttgagcagccttagcatatcactagcatattacgttttgattggttgaatggcaaactggatgaccagacacttagcatattaggcttttattatataggataaagaacactaaaacatatttttaaataaataaaaatttgcctgaccttcggatgtgatattttttctctgaaacactgtattacctcgtgatgtcttgcacttagcccttaaataggctcttcatgcagaagttcactaaatgtattttaaagtagtttacaaacagattttacaagtttctgatgcctcgtatctgacattaaatgctccatactggccctgtttccattttcactgacgctgggtgggatgcttaattaccattttgcctttcattggtgcaattaaaacacagttgaaggaaatgtatgggggaaatggtcccatgtgttcaaagctgcaaattggatttttaaagggttccatttaggtataagactctacttactttgcttgactttggttgaatccttaagaacattcagggtgtttcaaaaatttttttcttaaaatgacaaagcagcagtcgtgatttttaaaccatcttataaatgttgttctcttacatgtagtgacatgtaaatatgccctggatttttctgctccagccctatttaaaatattttaccctcaggatagtccagaaactcaaatatttcatcatcatcttaactcaattttccacacccctcttgcacctgggaagagttccctgtgtcccagtttttctttgaaaaacctgatccctgtatttatatgatatgtgaagccttgggcttacatcttggaggcattagcttaattttacccactcctgagtgttattgtaattactccagagcagggattgaaagcgtctcttcttactgccagctactgtcactccgtattttgttatttccatcttttgtgaacgggaaaggagaaacctgacctcagggaaatgatctgtacaaaacaatgaacataacagtgttgagtgggctttgtgactgctctgtttccttctcaacactcttctcagttatttctggctacgtggccatccaaggatttgagatgaccagaaaccttacctctggacaggtggcattttattgcagcttttcttccttcctaccattcttcttttttttcaataaatatttattgatcacctatatacacaggtactattttaggcattggtgatatctaatacatgacctcattgatctgacattctagcagggggaaatagccagataataataatactaataataataatacacatagaatgtcagatggtgataagtataatggagaaaaattaagggagagggagaaggaatgctggaagttgcattttaaatggtccgagaaggcctcactgagcaggtgacatttgaatatcaatcttgggagagaaattctgaataaatgcaaagacctcgaggtaggagtacatgggaggagcatgcatgtatattttagaagtaacaagaagagaaatgtgtatatttaagaagtaataaagagagaaatgtggctgaaccagagagggttatggaaaatgagatcagagaagttataagacagatgatgtactttgtagacactataagacattaaatatgtatatgttctaaatgggataagaagcttaataggatatttagttcaaaaaaaatcacatgaactgatttacattttattaggatcaccctggcaactgtgtttgttaatcagtaagtgatgacaatggcttggaccagcttaacagcggggaaggaggtgaaatatggttgaatcttggattttatgatgaaggcaaagccaacaggatttcctaacagactgtgtggagtctgagtgaaatcaagagttaatgtcttagcctgggttctccagaaatcagagcctgtgtgacaattcttactggggtgtgtgatttgggggagcagaacggtaggatgggggaatgacattggcagggagggagagtcggctgctgcttcgaagcaaatagttgctgatcccatgggactccctgtgaattccgatgctatgcatctcaggacccttgctctaggagggaggaaagggaaattacatccatcagcttctagtcccctgggtcagggtgttaattgcaccaaccttccatgtttcttgtgtataaatgaagaaagagttcccagatagtgacagaaaagctccagggtggaaggtaagaccctgcacttgactctccagtcactccccatcccctctctgcccattgcccaagcaaccactaatctgcttctgtctctatgaatttgtctattctggacagtttatataaatggaatcatatcacatgtgacctctgtgcctggctttttttacatacttagcagtgttttcatgtttcatgcacactgtagggatggaaagggtgtgggcagccagacaagtggcctgaggggaaaacacaggtcaagaggccaagctttaggtactttcaggatgtttcaggcagattcatttctgacacactggagtagagagcagtcccactccatgtctaaatgccttacaccttatatctaaccatctgaacagcaagaatgcccatgcttattctcagaggcttagaaccatgaaattgcttccccatgtcacaggttttaagagtccccggccagtgaagtgtttctagccagttggctgaggaacaccaaccgcttatcccttttgcatcccatggcaatcttcgtcaacacttctagaaagaggtgacttcatagcaatgcatgagtcattgtccgttaactctttaccctttaaagagccaatacttatgcaaaggacttttctctgttctagggaagctgcagaactcaaacagtatcctttttgtaatgggttttctcataataacattggcttctatgtcttattgtgtttctccattaaaaaatttaatcaacatgctaataaagaaaatttgctatgaatttttttaaaaaaggttcaatgagagaaatagagtagtcttccccttctgtttaccagagcttacttctcagctatttctttccagcccactctgggcttgggtttctaggaagatgtgcattcaaattctagctctccaccaactcactatgtgggagaccatttgctcaactcacaagatgaacaaactaatgagatctgctgcagctacgtcacagagtggttttgaggatcacgcgagataatgctagcagctctacatgaaatacctggtaaaccagaataaagctttgatcacaagttaactattatcactaatgcagtagtgggtctgagacccagacccggcagtgtgggcattacatcagtttgtagaggtcaagctctcacgcagggaccattcagcagctgttaggcttgagggctgtgcagccttagtaagaagagcaaacacatgtcctccatgcaaaagggacattttaaagatttacaggatttcttgtcttctgccagagatacttatccctggggagttactgtttgtagtgtaaagtggccgaaattctgactggaccctattgggtatttctgtcccaatagggtccataactctgtaagaaggattttatctgttcaatgtcagattttggctgaaaagcctgttagtatttccaaactctccagatgtccctacttaatgcttggctggtcttcttaggtagcataaccaagttgccatttcacaaccagcctccatccccaggatctaaaacagcaaatccagaagctctgaaacgtgctctatgaagcatgaaaggatccgttcaggttctgtctgattcagttctgtgagataatagacattctaacgtacctatgaattccctttattcataagaaacttggcactttccagaaagtatgtctctcatgaccaagaaaagtagggtgacttggggatgcaatgctttctttttatagtgtgtctagtatcttcattttcaatagcagcagttggtctcaggaccacaattggtacttaccatctctatcctccactgactattctaaattccccagctctcatcccttctggccttgatgacttatctgatatgatccaagatctcattcctcagagatctaggcctgtggtaaccatactcttctcacactagggttgctagaattgactattttagtcataattgagcaagtactatgacatggccaggtggattcctgaattctatacatatttccccctgccatcattatataacaaatgtctactacctcttcctggtgatcagaatcagttactcccatcaattactgccatcctatgtccctgaacataaggaatccaaaatgtccaggtaggaatcatagcttgtagttccctgcagagcctagaattgtggggatgggaagcacagaattccgtggtgggtcattgaccataatggcaactgggaccacttctgcttctgtcccttggttcctagacctatatattcttgctaacaggacacaacatccaaatagtttgtaaatcattctgtaatctgcatgatggtatcctatcatggcagaagtattacctacaagttagcacttccatgtgcctttggcaggtgactttattgctctgtaaaaccaattgcttctggattgtgtggcacttgatatggccatgggcttacctccctatctccttctctgtgaagtgagtctcatgatcagatggtatgttatatgagactgtatgcctagatcagatactttgaaatctcccagatagtggtgctagctgaggctctaggctgccaagaataagtgcctactactataacaataaatcactggcccttccagtaagaaaaggctcaaagtggtcatcttgccaccaagtggccatgtggtcccctcaagtaatagtgttacattgatctctcttgcaaactggttggactctcaatgatagtagtagtagatcagccttgataagtaggggagtccatgctattgacatgtaatgttcattctgttaatgtgccaatcatgctaattctggagcggccaatgacaaaagatggctactgtcaactaatcaattttgtcttggctattcaatgcttcttctgtggtggccaagctttggtggtcattaatatatgatacgaagatcttcacatttcatacccactctcatatattcatccacaagcatctagcccagatttttttctctgcaaaattattaactttttcttcccaggcccctgactagctgggcaatccttttgctcacgattccatatgtagtcttatctcaggcaacttttccatgaaatcctcccattaggaagattttctcttgctgctgtctttcaaggccacatgcagccaaattcagtatgttcattttaggtggacatattgaaaaaacatctacataccaaatcaaatgacccattaaccaagttcagttatactggagcaaatgctgagacagagttgggaatgcatgtggtttgcaggaggtaacatctgtgaaagataaagagagaggaagcaggacttggtagatacagcctcacattctctgcaaattggacaaagtcttggccaacccagtggggaactcttagtgaagacggcttgtgagaggggccccacattgggcataacagccaggccctagtgcccctgccatgctcatccattagctgtgggcttaccaggaagattagggccttggttcaaacatgtgacagatcccaaatgtgctacagatagaggctggtagcaaatgtcttcttgacagttaaacagaaagctgtttcttggagggagatcagagtggcacatttccagagctgtcacatcctttcttttttttttttatcttttcagtttgcacttccttggatttttctttacaagcttcttttcctctacctaatacttacttgatgtttcttaggttctcttttcaggccacacttccaccagccaccttgtcaactcccattcacacatcaaatgagactctcatgaatttccatttcagatctttaggctaggtctcttctgagcactaggtctatattatccatctgcctataaagatagcttacagattcctaacatttagcatttctaaaagtgacctcattatcttcttagccaaaactctttctgtgtagggatctcagtgaatagttcacattttcccagatcctcaaaacaaacagcatagagttatccttgatactgtcttctctctcattcctaatatcaaatccataatcattaccaatctaaacatgtcttcaatctatctcgattccattcttgttattgctatcaaagttcacaccaccatcattgtttcccacctgagccactataaatggagtttcttctgtgcttattaaacacagcagccagagtaataattataaaatgtactgtggatgaggtcctcaattccctgtgtaacagatcattggcttctattgctctcaggggagcctaacagtcctgaattcctctttcagagtgatgctgactttgcaattgttttatcttctagaccaggggtgggcaaactttttgactcgagggccacaataggttcttaaactggaccggagggccggaacaaaagcatggatggagtgtttgtgtgaactaatataaattcaaagtaaacatcattacataaaagggtacggtcttttttttttttttttaattttattcatttcaaacgggccggatctggcccgtgggccgtagtttgcccacggttgttctagactattggcacctaaggtcagggattgaatggtattcattcacctttgcttcccttaggatacctaacctagtgccttgcacatagcagattcacaaaattatccaggattgaagtgaaccttcagtgtgctggctagtagatctttttaaccaatagccatcttatcctgggttccctggaaaacagagttaacttgctaatgtgagagtgaagaacaagagaagtaaggcggggggtgggggggggggggccgtgcttccttcccaaagagacaggagaaacccagcaggtaatgtggcaagtgcctctgcacggccacacggggtacctgtggacaggctctgtgaaggccgtgctttgcggcagttcatgagaaggaactcacccacctcctgtttctcattgatccaagttactccctgcacttcctttgtgtcatctggccccttctatggctccctggaaagatggcttccatgccctattgggaggcctttcatttgagtccagagtggaacacaggtgcatgtaagatgtggccaacaaactatccctgaagctcagcctgttgtgacttttactgggttagattttaaatacactgatgctagaaacacaaaactggtggcagttttctttaagagagtggcctgcaacaggaataattgttaaacgttttatacaagtaaatagtgactgtgatgaataagaagattaaaacacagattgaacatgtcctgatttttctctcttaatcacgagtaatttgcaaatccatacatggctttttaaaaaactatatattctcatctgatcttatgattcaaaattaaaagacctataaactcctcttcccatgaaatcactcaatacagtacaaaagtccatcctttagcctatcactctctatccccatatgtaactcatacctacaatgaaagttgctcaccagcacacatgacaaaaaaacactgaagtgggaagggggtgggggggggattcttttctcaagcaagtggttctatccacttacgaaaaagacttgagagcttggacagacttcaagagcctctgaatgtttttcttcagcagaaattccagcccagatgttcaataacccaggtttgttttcaaagaggaaataaagaaacaaatctcataaagacaggccagactttgaaagcaattaatgatgacaggtccaaggattctgcttcattttattattaacgctgccactctttccagattccaatgtcagatactggtgaaggagaagtaaaaaaaaaaaaaaagtctggaaattgaagataaattattagtgggaggcacccacagaaggggaccttttgaagtagtgttcagagtggagaaggagaattgaagggtcagttgactgccaggggatactgtgaagttagcagatgaaaacggttgacaaacaggagcctaaggaaggtctaatcataaactttacactttgaacagatcattgcagatcaaaatcagctgacatattggtggagaagctgctttattttttttttatgtgttttgtttttttaattattccccgaggacatagttttaatgatttttagaaagagaggaagggggagagagagaaacactgattggcaacctctaatacacaccctgactagggatcaaacccgcaacccaagtatgtgccctcactaggagttgaacctacaaccttctggtgcatgggatgatgctccaaccaactgagccacctggtcagggcgagaagctactttaaattcatttacaccaacaagcccagagagtgataaagcaatcaactcataaatctcagaagtcactatgtggaatttccagggaatttggggaaataaatgttagactagaaaggatcacttagttctggttttcaaaaaaattaaagggaaaaggtacttattaaagcactgacctgtatgtgctggtcagtgttttgggttgtgggttgtataaaaagtgtaatagcctttcttcttgagtcaatcacattccagtcaggaaactggacgtaaacttttctctcatgcaatatgttaaagtctgtaacagaggtaaagggcaatgaacatggaaagaagaaaaaagatttaaataattgctactatttgtatagtggtttagaatgtatgaatagcttacattatcttattttatttaattctcaaaacaattctgacggagaatcctcaacttacagaataatcagaagctcagagcagttaagtggcccagctatttgactgtttggatgctctttgcttccccagtgtctactccctttcctgggagatttgaactatttttaaatgaattattgtgcaatacaaatgccacacatgactacagttcttctttattcttggaaactttctcctatgacccaggaaatgactactatttgtttatttcagaattttctgagtcacgttgctctgtcatagtaagctttcagccaaccagcagaagtgccggggtccaaccccagcaggtccaggggtccccaaaggtgtggacggagttggcgaagaaggaaagacacagagacagcgttcagctgatcagcagcccatccaggatctccagccaagttctggtctggatctccagcgaagttctggctaggatctccagccaggttctgtgtccatgttctcttgctaggttctccaggttctccagccaggttctgtagccatgttccctcgctaggttctccagccaggttcagtcaccaggttctagtcaggttctcttgccaatttctgtagtcaggttcagtccaggatcttttgccatgttctctccagtgaggttcttctgtctctagagaacgttctgtgtaggttctgtgcctcctggttctgtctctcttggttctgtcttcttagttctgtgttctaagttctgtcttattctaagttctgtgttctaagttctgtgtcttgctgtctagttacatctgtatttataccagttgattcaatcctgtcaatctctatttcaaaggttagggtgtttcttatctccattccagggagtaaagattatgtagcttaagcatgactgttcatagttaaagtgattaattacccgcctggcacttagttaagaggttttattccctccctaacttcaggggaaaatccctacctggggaaacaccctttctcagagaccttggttaaaacacatagtgccaagaaggtgagcaaacatattaagaacagtatgccatatatgccaggtcccttgaaacagcaagcatggaccggctcccggcacagaaggagcaccaacatacaagaggattttatctcaaaggtttacttctagttgcctaagggggccagaaattcagaccaggtcctccagggaaggaaatgttgtcccagtaattggggaaaacctgggctttaagcaatggcaccactaaacatccaatctcttgtctacgatttcttgggattctgacagcaataaaggagggaaatcgctcttgtactggtttctccttggccctccagtggctcctgttttcccaaatcctaaagaaatagaccttgtggactgaggtgggtggagctggtgggatggagaggaaaagaaaaaagtttcttctcgtccagcttccactcaccagatctgttcttccgaagcaaattcaagacttcacactggtctaccaagtctctgctctgctctctgggtaccctgaaaccaaatctagtaagcttctaaacctcagtttcttcaactggagagaaaattactatttaaattattctgctaccactattatcatacagttagttacttctattttctgtacttaatctcatttaatccacatgtcagccttatgaggcaggttttattgttcccattttaaagatgaggaaactaaaggttcaggaactcagttgaggtcataccgctagaaaggcatggtgctcggaccctcgggccccaaagccccatctattcatctctgttgggaagtattattcttcttagagtgacaccatctcacagttacaccctacgacctttgttatccccatctcataataattccatgaggtgaacaagataaatattgcctctgcccttccctttttacctctttagccccatttaaaaatatatatttttaaaaaaactaaagctgcttggccatggttactcagtggttgagcactatgggctcaatccccagttgggggcatgcaggagtctgctgagcaatgattctctcttatcattgatgtttctctctctctctcccctctcccttcctctctgaaatcaataaagacatatttttaaaaaactaaagctaagcaaatgcaaaggatttttccgaggttacatagataacagatggagttggaattccacaggctttagtcctgctattgctacacacactgctttgtctcctggagatcaagacccagcattgcctctagctagcactttaaccctcaaatggtcatttaaatcctgcagttttgtatatggaaaaaaagatgggaatagcaataataataatatctgtcaactaccttgaagtattattacaaagatcaaatgaaatattatgcataggtgtttatggaataagtagacaatatacaaaccaatataattttattcttaggactatcctgccccatgtgtgtaagggggagaggaattgatgtggaagatataaagagcattggagggagcgggtcatcatttccttgctagatttattgtttcaattggatattttttgagtgctggcactgtgctagctaatggaaatggaatgctgcacaagataatttggccttactctcatgaaattgcattccagatggacggccaatgttgataaaaaaaattagccgaaaccggtttggctcagtggatagagcgtcggcctgcgtgactgaaaggtcccaggtcgatccggtcaagggctgtacctgggtgcgggctacatccccagtaggagatgtgcaggagggcagctgatcgatgtttctctctcatcgatgtttctactctctatcttcttcccttcctctctgtaaaaaaaatcaataaaatatgtaaaaaaaaaaaaaaattacaagtgtggccctagcttggtttggctccatagatagagttgtcagcctgtgactgaagggtcccagatttgggggcacatcctgggttgtgggcttcaatccccagtagggggtgtgcaggagagcagatcatgattctctctcatcattgatctctctctctctctctctctctctctctctctctctctccccccccttcctctctgaaattaaataaaaataaatttaaaaaataattacaagtgtggtgaggttctgtaaagaagacaaatagacttccattgtgactttcttcctgagcacactgcaacgccctggtgctatcacttacaaagatcaggcagaggcaactgccacctattagagcactccaaatggcttccaacaatgaaaaacttacatctcctaaataataactattctaaaaagagactaatcttggctcttagtctctctaaagccaaaataaaggcaatgtgatctatacaacattatcttgacctcactgaccactagtcagtccaagaaacaggcgtgcaatacgatagaaggaaggatcaaagaatatgttttataaggataataaattccgctgacatttccccttctgagctacaataattctggcctcttttataatcataccctgttggaaagccacatggcttggaccagtttttgcctactacagattttggtttccaaaactacatctccatgagtaaggagatgggcagtctcaggttggctggctccatcagaaacacttaaaacttgattgcacaattgtatgaccaactggggtcttagcatccacttgaatttcctcattggcaattttgaggatatcatattgcttgggaaagaaagagggactagttattatgattttcatgaacttacagaactttagtattggaaaagtagaccatctgctttaactttctacccagtgtaagaatctcctgtacttgattcatgatagtcgtcctttgaataaaggaaggaaacttactatctcgttgttgaagaattctgttaacctttcctacactggagaaaatctaccaccattggtcttagatgtgtccactaaatccccacagaccagcggttctcaacctgtgggtcgcaacccctttggcagtcgaacgaccctttcacaggggtcgcctaagaccatcctgcatatcaggcatttacattatgattcataacagtagcaacattacagttatgaagtagcaacgaaaataattttatggttgggtcacaacatgaggaactgtatttaaagggccagaaggttgagaaccactgccatagaccaaatcagaaagaacgtcacttctatttaatgactttcctcctccctggtataagaagtcttttctaagctaaacattccagtgctttcctccattacatatacaaaatgatcctctgaactgttagcattttggtttgagaaatcaaggagatgggtgagaaacagaatgtttgtgtcttttacctaacatatttgctatttctctgttttgtaacatcagcagataccacctgtgcccccgttcacactgggaatgaaactgcacagagctactttaattataaagataaaagcaaaatttctccattcatattgccagaggggatggcttgccaaatcattctctttggttctagaaaatgcccaaaaaataattttgactttaaaattcagctctgggtttgaagatgctgccatgctgttcagtcataagaatatataatttttttatttcgattatgctgctaattttagtaactttggcaaaggttataaaaacaggcagtccccaacttacagggttatgttccagcagtcatttgtttggaatgtgttttacatgcttattaaactttctggctggcctaccaaagactttttaacccctaagatgccaggcatctaataccatcccataatcagctgcaagccagaattcactctcaggttttatttaccatgtcccttaagcatcaccagaaatattctagcacccaacactatgtttaataatgtctttctaacttaatatgcccaagaaactactgggaacacaaggaatattttcatgcttcccttctcctgtccaagtgagttaaggactccctgccccagtcaaggaaactaagagaccgggactccttacgacatgagcctgctggtgtctgggagggtgaagttagtggtagaccttctgggggaaaagctatacttctcagtcatcattggttctactcagatttccattctttccttccaagtcagcctgattcatagactcttcattcatatttattctcaatatctactagtgtcttctctctctctttctttctctctctctctctctctctctctctctctctctctctctctcatctcttccttagattaaatttcttttgcatgtacagtattaattccactgatgtcataataatcctgtaaataagaagtgaggacactaccacctccattttacaaatgagcaaaggcttaaagagggtaaacaacctgccctcacagtatgaactataccagcttcaccacagcactgccttgcttcacttcttaaaaacaaaaggtatatatgttagaaaaattttagttttatatttgttgtctcaagttatttttataaatatgcacagtatttgtagcctctttttttatttctaatgcaattatatactagcattgtgttttttcctgtctttttcctaatcaatcttgctgtgatgtttgtctgttttattaattttttttcaaagagccatcttttacattagtttatcaagtttttaaaattatggtaaaatatttatggcctaagagaaatactaattagaatatttagtcatatatagtaacttctaggaaaacagatgttgctttgtttcaatgacactgaacaatgtcccctggaaaatgtgaattgagttttgttttgtcttccctatgtggcttttgcaaggagaatcttaacaggtatacttgattgtcgatacatttaggtgtttttttctgatgaacatgttaatataggatttattagataagtgataaacattgttgctacaagctaaacacgcaggccctgtcttctaggaattttcaagccagtgaaaatgtatagtctctctttgttgtctactatactctgttgtgagtcaagagcctcctgacactgagcaccgggttcccgggagattaagtgatggacctggacctcccagcccgtgagctcggattccatcctccaaagcttactcttcccaccggaccacacgtatggcccacgggtgacagttactctgcccttttagagcctgagaaaacactgtttggtggtctggcatcatctatgttgacgtggcttgatttggaatagagtgtaatcctagttcgtgatgaaaggatttcatgcgttaaccttatgggtcatgatgtttgtgcaggggggaaatgtgcgctaatctttttttttttttttaatctccaccttaggatatgtttttaattgatttttagagacagaggaagggacacagagagagaaagaaacatcgatgtgagagagaaacatggattggttacctcccagacacaccctgacgggggattaaacatgcatcctgggtatgtgccctgaccaggaatcaaacccacaaccttttggtgttcgggatgacactccatccaactgagccatcagccagggtatagtctttaattcatgattaaaacaaatatacccacgagagatgggcctataaaattcaccttaattgttgaaatgcagtaaataaatctttcaaaaatatctaacaggtccaattatttcagtctaaaaggcaattggagatctgttctttatcaaggttccccagccctcctgtgagatggagctgtttttcatttgcttgcaggctggaagaggagtgaaaacaatgtcaggatggtcctgctcagagccctagaagagctgcctttatggagtgtttgtgtccccaggaggaaatgagatgatctgagtctatgggttagaccagagagaggggctaggtattagcagccaattcatgatcttagaagtctcctgactgaggcacatgaggacaagtatcttaaaaaaaacaaaaaacaaaacaaaacaacaacaaaaaccagaaaacactctgttttatttattttttaaaaaatatgtttttattgatttcagagaggaagggagagggagaaagagaaacatcaatgatgagagagaaccctcgatcactgccttctgcatgccccttactggggtttgagcccgccctgactgggaattgaactgtaacctcctggttcatgggtcaatgctcaatcactgagccacaccagccaggcacaaatatcacaaatatctttctgatggtgttagcatccagaattgtgcaggagtagttgtttctaggacatttaaggaagaataaatagatgagacatatatatatatatatatatatatatatatatatatatatatatatatgtatagcccagtgcacaaaattcgtgcacaggagggggggtgtccctcagctcagcctgcaccctctccaatctgggacccccgtggaaaatgtctgactgccggtttaggcctaatccatgtgaatccctcaactggcagtcggacatccctctcacaatccagaactgctagctcctaaccattcacctgcctgcctgtctgattgcccctaacagcttctgcccgccagcctgatcacctcctaacttctcctgccagcttgattgatgcctaactgctcccctgccggccgatcacctccaactaccctcccctgctggcccaatcactcccaactgccctcccctgcaggcctggtcccccgcaacttccctcgcctgcaggcctgattgctcccagctgccctcccctgccgacctgattgcccacaacttccctcccttgctagccatcctatggcggccatcttgtggtggccatcttgtgacaatgtcgtggaaaccatcttgtgatgatatcatgtgaggacgttgcacaatgccacctaggcttttattatataggatatatatacacatatatgaaaagccagacaaagtgcctgaaaaaaaattagctttcaatagatttcttctccagttcctacttgtcctcttgatcttatgcttaacacctctctggacttgtcagtacaagccctgaatgtttcaccaaacaaactacacagttggtgccactggactgtttaacatactctaattaccacaatttcattggaagggaccagggttggcaaccaaactaacgctaagggatttgatcatagaattcccacaccaagtaggaggcataaaatgacttggagacctggtcatagttcctgcagctatggttcatggcatgttagcagaacacagtctctgaaagttatttcctaaaagctttccaaagagctggttcttcacacaaagagttttggccaattgcaatgacagggagaaactagaatctcaggaagaacagaatttaagccttaagtttcattttgttttggatcagatgttccttaaacataaaccttcacctgattctaattttcatttcaattccatagaccggtgatttaagtgttggggatagagttcttagaatctgtttatgtggtataaatacagaaatggtctggttctgagtattaggatcatgatccatgttttgatatgaactcaaaacctctctaagtcacgtgttattttttgaagcacagaaactggacctcacaaacaacctaaatccctctatttgagaaactaaataagcactgagttttcttgccataaagttctgcactgcatctagaatgctttcttaaatagtatctctgggagtcctggtcaagggcgtgtacctgggtttgaggtttgctccctgcccccactctgatgcatgctggaagcaaccagttggtgtgtctctctcacattgatgtttctctctctgtgttcagtttcgagttggcaagattgcaaaagtttgcttgtaaatctgtgggttttgttttttgtggggttttttttagacctttgaatgcatttttttttattgttattgatttcagagaggaagggagagggagagataatagaaacatcaatgatgagagagaatcatggattggctgcctcctgcacgccccctactgggaatcgagcccgcaacccgggcatgtgcccctgaccagtatcaaaccaaggacccttcagtctgcaggccagcactctatccaaggagccaaaccggctagggcttttgaatgcttttttttttgttccagagggtggtcagcgtctcaggccaaaccccaaagcctatttcacctattcttgtattagaaccaggggtagattcagttttgtgtttaggaatggtgagggaagtacatgtttgcttctatctttaatcatttcaaatttgttagaaacatagacttattgacctagataccactcagtgagtttagacagttgctcaagttaataatgttttaagttattgatggtggttatggacatggactttgaagtcaaagagatcgtgctttatctatttacttgatcaattatttttgatatctcaccattaagccagacactgatagaaacaaacttaaaatgatgaatataacttctcttactagcttacactacattgcttttctcagtggtattcagttttcttagttataggagtgggagaaagataaaaacatatgcctcatagagttgtcattaatattaaatgaaattaatgcatggaaaatatcctatataataaaaggctaatatgcaaatagactgaacggtgaaacaaccaaacaaccaaacaaccagtcactgtgacatgcgttgaccaccagggggcatgtgcggaacatggtgggtgttggccatggcaggatggtggagcaggtgagcaggggacaccagaccaaggtgaggtgccattcattgtcatcgggtcgagcctcctgtggttactgaaaattctttgctcctgtgcactgtggtcttgcccagagcttccacctgctaccagcaccggagccactgctcgcaccttcagccagtgctggaaccaccgctcacacctactgccgatgctctgcaccagtcccaatcactcaatgccatcaatgggtgcaagtgtggctgctggccctgatcgcccctgagggcttctccacctccccctgctcctgggggtgatcgggacagcagctgctgctcacacccgctgctagcatcagcctcaatcactccgtaccttcagcaggtatgaaaggggctggcatcgtcagtgcatgggagcggcaggagtgggactgctggcagacaggggaccagggggctgtggtgggaggggctgggcgggggcatggaggatgggctgagacctgcccctatgcctatggtagcctcacggcccacagtttctttcaaggtgcatgaatttgtgcactgagcccctagtttagcataaaatgaaatttcagtgtatggtagccactgacatgactgtggaccaacccctcattttaaagctacaaaagagctcacctggcatggctccgtggttgaacgctgatctagaaggtcacggttcaattcccagtagggggtgtgcaggaggcagccagtcaatgattctctctcatcattgatgtttctacttctctctctctcccttcctctctgaaatcaataaaaaatatatttttaaaaaggagaaagtttatgtgcatagaatgattttatgactatttgagtacttacaaaaatagtaaaaaaaaaaaaaaaaaaaaaaatttaagctgaaaaagactatatcacccaggcattctcactctccttttagcccatgccctcttacctgagcattggctttattgtcagacagccttgccaagatgggcactagtagctttatgcttcctgtccccattgctaacgattctgagaagactgtccacttggaccacatggaataaatttatgagaaagaggatttctatttctagaaagcagggattaaggaaagacatgataggcagacaagaaccatagctaccatacttcactttagtgagacaaagcgggggagggaaaggatataaatgtgtggtggtggtgggtgcacccctatgtgtttgtgaattgggattatgatgtaaagtcagaagcagtggactagaaactaaaaaatgatcagttcctaaagaaaaaaaaataaatcgtgagcactccccaaagtaaattattatatttgcattcaaatttcttcattttacactatttttcacaatcccttcttatttaacacagagaagtcaactacaacttcaggtattccagcaatcaaagtaggactcctttgggagcaattttcaaaaacctattaccatttaatgaagataaaggtgacagttaaagatactcctgggcctacctggagatcacaaggccaaaccagatttctatacaggtaaatgcaagtgatcaacctgcttttatttgcaaagaccaaatcagagaagtacactcatgaaatttagatccagagatataaaagaacaagaaaggtagatcttcccgaataagtttccaaaacaatctgaagctaatattaccaaaatacatgggctatagcggaaccttctaaacaagtatgagtaaccactgagtgaatttatgttatgagcggggtaatcaagaattttcactgctttaccatgatgatcataatttgcatcggcccaacatccttgatctcagaatgatgctcaaaaatgttaagaaacagtcttgccgctatggatcagtggttgagtgtcaacccatgaaccaagaggtctcagattcaggttcaattcccagtcagggcacatgccaggttgctggctcagtccccagtcgggggcatgcaggaaactgccaattgatgatgtttctctctcactgatgttttatcctgttctaagtttacaacctcacttctcaaaaaaaaaaaaaaaaaaatgatgctactcagtagctggtacattgtgttcattcctctgaaagtgggctttaaaattgcagctattacctctgcccagctcactggtgtctgcagggccagaggcttgcctcgttcccaaggccatcagacatacaccctggaagggctccagaagcacagccacagcaggagcacctgaccgatcctgcaccaaaaggtgcatgatttgaccagatttttggaggagcatcctggtggggcagaagtcctgagggaacaagctggaggtgatgctaccaaaaactttgaggacacctggaactctacagatgccagagaactgtccaaaacatatagcactcgggagcttcgtccagaggacagacaaatgataaccaagtcttcagaagctcctagtattactgttgattctaataccagctggtggaccaattgggtgatcccagccatctcagcacttgtcatagccctaatgaacttccatattatggggaaaaatatgaacatatgcaaaatgaccccaagaaatcacagatcaatggtaaaatatttaaaacaaagtgtgaagaacctttgctttgcaggaatatttttttaaaaatacacaaaacatgcacataacataaactacctctgctaagacaaattaacaaagcaagataaaaaaatttaaatcttatagccaccaagatagtaaagaattatgaaataaagaagaaaaggaaaccagagaggtgaatcctaggattggttgatggttctggaagagatgattaaggtagaatttcggcagaggttttggcagacccatagggctagatggttaaagtaaataaaatatatatatatatataatttagcaaaaaatcaaagttctgttcaggagtgaactctggtaaatgttcacacatctagatgggatcccaaagggctccacctatgagtaaggagtaactggaaaaaacttggagctgcactaaagtttaaatcatcacagtccctataattaaaaaatattttttattgatttcagagaggaaatgagagagatagaaacattagtgacgagactcattgatcagctgcctcctgcaagacccctactgcaggtgaagcctgaaacccggtgtgtgccctaatggggaatttaactgtgacctcctggctcataggttgatgctcaaccactgagccatgccagctgggttcagtccctataattagatgaaggtgatctaagatagctggggccctaaccacctaccaaaggcaaatgtaagtcttccttggaggaagataattctaggcctcaaataattgtaacttttttttcacatacaatgtcctgtacctcaagaaaatgaaccagaaatggaaagggatatctcactacagagcctacagatattttttttattattataaaatcatttaatgatatttattattaacaactttatgttcctaaatttgaaaatttaggtaaattggacaagtttctaggaaaaaatacaacttactcaaactgacataaaaaggaatagaaaatctgaatcattcaataaacttaaaggaattaaaaactataagaaaggcacattgtgatttcccccagttactccattctcttttcctattaaaactttattttcctatttttgagaatgattcatttatttggctattggaatatttcagaaattaaaaaaatatgattacctacttcctctccatctttactcaatgttatcaaacttttctatgttttacttttgagaattacatatgttgtcttctcaattatatttcaaaccataggagggcagaccttgtggcatagaagaaaaaagagaggaagaagggaggtctgggaaaaagaaggaaaaagagaattgtgtttctggtttttacagttctacatccatatcctctgcagcctatttatagcctgctgatgtagaataatcataaaaggtccacgacagtatcctatataataaaaggctaatatgcaaatagaccaaatggtagaacagccgaacaaccgaacaaccagttgctatgacatgcactgaccaccagggggcgtgcgcaaaacatggcaggcatccgctgcgacgggatggtggagcaggtgagtgggggcaccagaccaaggcagggcgccggttgctgtcattgaggcaagcatctggtggttactgaaaattctttgctcttgtgtaccatggtcctgcctggtgcttgcacctgctgccagtgctggccccattcgcacccactgctggcacccggcgccagccccaatctctcggtgccatcagtgggtgcaagctgtggctgccaatcccaattgcccctgagggcttctccacctccacctgctcctgaggggcgaacagggcagcaactgctgcttgcacccgatgatggcgccagccctactcatacccattgctggtgccaggacccaattgctccgcaccttcagtgggtacgagcagggccagcactgtcagtgcgctggagtggtggtggcgggagcagggctgctggcagacaagggactgggggtgcagtgggagagtccaggcaagggcatggaggatgagccgagacccgcccctgtgcccactgcagcctcgcagcccacagttcctttcaaggtgcatgaattcgtgcactgggcccctagttaaacatactaagcaatatgacagagtggttaatatatatgagtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtcttggagttcttgagcaagatcattggataaattacttaacctctctaattttcaatttcttcagtgataagaaaagatcattgtggaacacctcacacatcagtgtaaatattaagtgataaaatacatggaacagtattattgcaaagcctaggaatagaagaattccataaatagtagctatcatttatgattatgatggagagaaaataaattaaaatatatataatttaattttagtttttaatatgtgttgacgaggaaaatcccaaatcagtcaaagtctctttatgcttacttcactcaaataaaaattttctatactaagtagcagaaataagtaaggcccttctggtaaactgttctaagttgggctacctggtggtctagagttgatcagaattttgaaacctatcctaagaaaagatggtgaaataataacttggcttttcttaaaaaatatagaccatctttgccagttgtccgttgtatggtttgttgagattgtctggaatttccaagccttaggactattaaaataattcaccagaactgcctccaaataattttatattgtgtaatttcttaacgctgcactttgggatggatgttctcggaatcacatgggtttagtgagagtcctgcataaagcatgttttgtcataaaaagcatccccttgatgcttagggaatgatgttgataggttttagacacagaacctacaatgactggaacatatttatcgaagcacagagggcagttgaaaatggctgttacaaactctgaacaaacaaggtcattgacatttcagtgtgaaccctcaagagcccttgaggggaaaaaaaattactttcacagggaactttcaattgccttctctctgattctaaaaagaatagaccagttcttttcttttcccccttgtccgttggctaagagaccacaaaaaaaaaataatcctttgcttaatttccagaaaaaaattatattgcttttagtaaaattcatttttcacctcaaggatagagctccaaattattatgtcaaactacattttctttaaacatctgaaatttttcctccgatttttattaaaagtacattctactttatgatatagaatgaaatattttggtattgatgcttttcttaataaattaagacatataggaacgctatttaaaatcatgctggggtggtaaccggtttggctcagtggatagagtgttggtctgtggactgaagggtcccaggttcaattccagtcaagggcatgtaccttagttgtgagcacatccccaatagggggtgtgcaggatgtttctaactctctattcctcttccttccactctgtaaaaaatcaataaaatatatttttttaaaaatcaaatcatgctggaagataaatgtcagttatttttaccaatgatttttcattttgggaaagcagcttttctatatccaatggcattactcaaaaagaagacttttctaaaaagtgttcctaatcattttgaatggagctaactgaaaatggcctcctggactctgctgcatttgggtttcccatccacttagattaattcattcaaaatggaaaatcatgtgactgaatttttactgttttttgttgttgttcttaatcctcacccaaggatatttttcccattgatttttagagatagtgggagggagggggtgagagagggacagagagaaatatggatgtaagagagacaatcgattggttccctccgtgtgcaccctaaccgaggccaaggatcaaatttgcaacccaagggaacttacgtgccctagattggaaatataacctgagactcttcaacatgcaggccgacgctccaaccattgagcaacatcagccagggctctatttttttttttttttaaattgagaggattgttgggagatgtgtaagtgatttattatctgttttgttttaatgaagacatttggaaataggaaatgatttcagtagacaacttgcatggaacaaatttgcctttttggtcacggcatttttcctttgtgacatgaaggcttttcagggggtacacaccatgtttccttttcatataaaacgagaggcccagtgcacaaaattcgtgcattcagggaggggttcccaaagcttggcctgcaccctcttgcagtctgggagccctcaggggatgtcagacatgccaatgagcccggcttctgtggctgagcggcgcttcccctgtgggagcacactgaccaccaggggggcagctcctgcattgagtgtctgccccctggtggccagtgcgcatcatagcaaccagtccttctaccattgggttgattgcatattagccttttattatataggactagaggcctggtgcacaaaatttgtgcactctgggggggtgggttccctcagcctagcctgtccctctccacagtccgggagccctcagtggatgtcctactgatggccacagtctggagcagaggctcggagcaggcgtcccgtgtgtgtgtgtgtgtgtgtgtgttgtgtgtgtgttgtgtgtctgctaggggcctgcccccatccgcgcactgccggggtccaaccccagcggggtcaggggtcccccaaaggtgtggacggagtcagcgaagaaggaatgacacgggagagggcattcagatgatcatcatagcaaggttctctagccacgttctggtcaggatctccagtgaggtcttggttaggatctccagccaggttctgtgtccatggttctcttgctaggttctccaggttctcagccagttctgtagccatgttccctcactaggttcttccagccaggttgtgtccaggttctccagccaggctcagtcaccaggttctagtcaggttctcttgccaatttctgtagtcaggttcagtccaggatctttgccatgttctctccagcaaagttcttctgtctctaggttctgtgtaggttctgtgttcttagttctgtcttcttagttctgtgtctaagttctgtctcctaagttctgtgttgttacatctgtatttataccagttgattccaatcctatcaatctctattccaaaggttagggcgtttctatctccattccagggagtaaagattatgtagcttagcatgttgttcattagtatagttgattaattacccgcctggcacttagttaagaggttttattccctccctaacttcagtgaaaatcccctacctggggaaacaacctttctcagagaccttggttaaaacacatagtccaagaaggtgacaaacatattaaggaacagtatgccatatattccaggtcccttgaaacagcaagcatggaccggctcccggcacgccacgtaggctcaaagcaatattgccgtgtgttgtgtgtgtgtgttgtgtgtgtgtgtgtgtgtgtcccccactgggggtctgtccccagccacattggaggctcagagcaggcactgtgtgtgtgtgtgtgtgtgtgtgtgttgtgtgtgtgttctgctgggggcctgcccccagcacaccatagaggcttggagcaggagcccctctgtgttgatctcttaggctccgggcccccaccttgcatgttgtacctcccttgagctatggccaggatgggggtgcttgcaagccagactttcctgctcctggatcgccatggcgtccggggagcaggcccagctgggagctgcccacaggctgggctttcctgctcccaggtctccgggcaaccagggagcagcccagcttggagctgcccgcaggccgggcttgttctcctgttcccggatccccatggtgactgggaagcaggcctatcgggggctgcccgccaggccaggctttcctgctcccgtttcaggcccagcttggggctgcccacaggccaggctgctttccctcccagatcaggtgcagctgggggctgcctacaggctgcacttttctacttacgatggccagattcaacacagtgacccagggcccagcggcactttcctgctctccaatagtcataggtcccgggcgtggggcggggcttagcagtgcaggcttaggcagcacgggatccccagctggggatcaggtggcacacagggatccggcgggggcaggacttatgcccactacccagggctgcacatgggcccggatggcagctcgagctgtcccgccctgccagtagtataggatagaggcctggtgcacgggtgggggctggctggtttgccctgaaagtgtcccagatcagggtggggggtcccgcttgggtggcctggccagctgcatgaggggatgatggctgtttgcatctggtcacacccccttcaggtgggggtccccactggggtgcctggccagtctgggtgagggcctgagagccattttcaggctggagggcaacttaagctcccacgctctccttttttttcttttttttttttattctgggattttatttaccttgtatagctgtcactggagctgagagcaggctccagctctgggggctgaaagcaggttctgggcttttttggcttctataattgaaactctgttgcccatcactgcagctctaagctctgagggcctaagctggctgaaagcaagtctcgtggaggcttgtttagcttctataattgcaacatagttgcttagagtgtagctcagaggctggtcatggcaggccgggaatgttggcttcctccatcactggagcaagcaagcctcctgttcgcttcagctgcgtggctgctggccgccatcttggttggcagttaatttgcatatcctgctgatatcctgcatatcctgggaagggtgttggggttatggtcaatttgcatgtttctcttttattagataggattatatcaccatgaaactttagacctgtcagtgacagccaaagtatatagggaacaggaagctctgactctgacttgatgagtgaaacaaacaggaaagctctggtctctttctttagatgtgagtatccaggtgtgcgctggatcatacaagcctgtccacactcttgcaactggagacagggagaggaaagctgacctgccagtgacatagacagcacatgcgtccctccaccctgccactctgctctgggcatcagatcagcatctagttgtgtccctacagtcctatagaggaactcaaatattggaagcaaagtaggtatagactctcactgagcacattcaaaaactcttatttttaattttcaattcagaaaaataaatacattttatgggcaattctttctacattactccttattgtttaattggataccagacacagtaataatactaagaaaggttgtccctaaagttgaagtaacaatgaaatgttgtaagtcatttcatggcgagggagaggagggaatgagttttgagccattttaaggtgactcattgtgtcctctagaggaaatgacttcagaaaatatctgttagaaaacactactcttggagagtctcataatgtggagagctgagtgtttgtagcttcataaaaagtgattgttaactgttatcagaaagcatcttgatgttatttttaaaattatttgcagcagagacaatatgtattagcttgtgcctccttccttccccgcaagaaagactctttgttagccattgtcttgtatgtttcatggtacaacatcagggaaatgggtagataagataacatctgaaaaggaggcagaaataaccagtaagcctagatcactttataataaagaaagaatgaatttgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtacatatatatattgagagaaagagagagagagagagagagagagagagagagagagagagagagagagagattagttgtttggttttattataaggaactagctcacacaataatggaggctgagaagtttaagatctacagtcaaaaggtagggacacaaggagagctgagggtatagttccagcctgagcctaaaggcctgagaacgaagagagccactagtgtaaattctagttcaagtctaagtccaaaggcgggaaaagatggatgtcccagcttaaagataggcagtcagagagaaagaatgctttcttggcctgccttttattctatccagtcctccagtggattcgatggggcttgcctacattaaagaaggttatttgctttactcagtctatcgattcaaatgctgaactcatgcagagaataaacaccattacagacacatccagaattatgcttaaccaaatttctgagcactcatggcccagtcaagttgacaaatgaaattaaccttcatacttttgtatacaaatatacttttgcaccggaacagaacagagaacccagaaattgacccaagccattatgctcaattaatatttgacaaaaggaagcaagagcatacaatggagtaagacagtctcttcaataatggtactgggaaatttggtcaaatccataccaaaaaaaaaaatgaaactagatcaccaacctataccatacacaaaaacaaactcaaaatggttaaaggacttaaatttaagatgggaaaccaaaaaatcttaaaagactacataggcagcaaaaaatatcaggcatatgtcacagcaatatctttactgatacagcttctagggacgggtgggcaaacgttttgaatcgagggccacaatgggttcttaaactggacgtgaaggccggaacaaaagcatggatggagtgtttgtgtgaactaatataaattcaaagtaaacatcatacataaaagggtatggtctgtttttgggttttttttagttttatcatttcaaatgggccggatcgcccggcgggccgtagtttgcccaggctgttctaagggcaatgggaaaataagggagaacatagaccaaataggactacatcaaaataaaaagctttctgcacagcaaaagaaatcatcaacaaaacaacaagaagcccactggcatgggagaacatttgccaatgctattcagataagggtttatcctccaaaattttacagagaacttcatacaactacaaaaggaagataaacactcaatcaaaaaatgggcaatggacctaaattagacacttttaaaagaggacatagaaaggccaagagacaatgaaacatgctcaaagtcactaatcctctgaggagatgcaaatcaaaaacaacaatgagataccactcacactgtaagaatggctatcatcaacaaataacaaaggacaagtactggcaaggatggtggagaaaaaggaaccttcatgcactgctggtgggaatgcagactgggtgcagccaactgttggaagacgtatggaatttcctccaaaaattaaaaatggaattcccatttgacccagttaattcccacttctagagactaccatcccaagaactagaacaccaatcagaaaggatatatgccaccctatgttcatagcagcacaatttacaatagctagatttgaaaacagcctaagtgccccatcagcagatgagtggattaaaaaactgtggtacacctaacacaatggaatactattcctaatatataaaaagccaggggctgtaaaccaaaacaaacgggctggatgaccgaacagcaggctgcatggggcgacaaggccggcagggggattagtgagggacaatcaacgactgaacagcagctgcataaggcgaccaggcaggcagggattttagtgaaggatgaccaaatgactgaacagcagctgcgtggggtgacccgcctgcaggggggttagagagggacgaccaaaccactgaacagcaggctgcatggggcaaccaggccagcggggggcagttgggggcaacacggccagcaggagggcagttgggggtgattcaggcagcaggcaggtgagcagttagaaggccagcagtctcagattgtgagaggggatgtccaactgccggtttaggccttattctggggatcgggcctaaaccggcagtcgacacccccaaggggccctgattggagagggtgcaagctggctgggggatggatgaaacagcatggtggaactggagagcattatgctaagggaaataagccagttggagaaagataatatatcacatgatactcactagatgtgggatataatgatcaacaaaactgtgaacaaaatagatccagggacaagtggcatgggcggtgggttagaagatcaacctaaagacttgtatgcatatatatgcatattagcattagccaatggacacagacactggggggcggtggggacttttcctcaggggttgggagtggttgggggcgggtcaatcagggaaaagggagacatatgtaatactttaaaccataaaaaataccaattaagaatgtttacatatatatacattatctatagtgctaaaatgtaaaagattgatataccaggtgtacctacttgatacatttctccaacatggatggagtctcaataacattatgtttgaacaaatgaagccagacagaaaagggtagctaatgtataatcacatttacgtgaggttaataaacaagcaagttggtgatgatagaagtcagaatagtggtgttatccttctgagaaaggtgggcttattggattgaaaggggcacaggggaactttctccagctgacggtgacaattttacatttttccaggtcttagtcacatggatatttgagtaacatataacatatggtgtaagtatcctaatattataaaaacccagggatccataacgacctaccgaaggctcaactgaacaccagcagtcctgcagtcagtgctggggctgccgtggcgaccagcactgactaccgccggtgcgggcacagccaacccagcactgactgccgagggagctgcggatcaggcccagagagagaggcacgtctgatctgcaggcctccatggcagctgttgatcaactgttgcctcttctctctctctccccgggcttcaccagcagcccacgctctttctctcaaggcctccgtgagggggctgcttatcagtcccaccttctctgatcaggcctgggagataggcccagagatgttgactggcatagaaactaaccaatcagaccaaatctgggtgacagtaggagccaatggctgcctaggaggcagagcttttgatgctgactggcatagaaacttgaccaatcagaaccaaattggccagcaggggagggcagttgggggcaaagatcaggcctgcaggggagagcagttgggggcagatcaggacagcagaggagggcagttagggattatcaggcaggtagaggcagtagggcaattcagctggcaaggagagggcagtttgggggcgagatcaggctgcaggggatggctggtagggggcgagatcaggccggcaggggagggcaggttaggggtgatcaggcaggcagtcagaggggttaggggcaatcaggcaggcagaggagttagggaccgatatgcaggaaggcaggtgagtggttaggagccagcagtctccgattgcaaggagggatgtctgactgccggtttagtccaaatccctgtgggacatccccaagggtccccaaatggagagggtgcagactgggctaagggaacccccgctccatgcggattttgtgcaccgggccactagtacttatatattgtatacatttaggatgtgtgcatttcactggatgtaaattatactttaaacttgtgaggaggggaggttcaatacaaaaattattcccaacgaatgaaataaatgaaatttatttttttttaatcaagagacctaaaccaagcattacaaataaaaatttctctcagatgggcccaagccagacagtttccataagcaaacccatgaaagccattgcctgggttcctaagactcagatgacaaaatttaaaatcctatggaattgtccccaaaaagatgactcacaggtgaccttgaaatctgagtggtgtgtatactatttcagctacagtgtcacacattccattgtagttatcacctggtatttcataattatttgtaaataattcagtagcaacattgactaaactccactctaccaccaaaattgaaaacataacattgatagattttaaaattatttcatacttacaagtattagtttatttgttaacaggtccaaacattttgactgcatggatccttctgggtctacgtcctgattttaattcctgttctgtctgctctctcacaactcaccacaaagtattttgaaaattgcataagatgctctggccagtgtgtctcagcgggttagagatcagcctgtgcactggaagggtctcaggtttgattcccagtcaagggaacatacctgggcaggcaaccaatcgatgtgtcttctctcacatcgatattttttctctccccctccaccctcccttccactctttctaaaaaatatcaatgaaaaaaatccagtgaggataaacaacaacaaattgcaccaataataaaaccaaattatcagtaataatttattcctaataaagataaaaccatggggccaaatggtacatgtcacatttaatttatcaatattgtcatttattataatacacaactttatgatgtcaaagtatctggatttctatggtcacattgggtagttcagtgttatacacctttgggcacatctcaaaagaatccagttgattcgcttgacacaggctatttaatgcaaaaggaggcccttaaaatgcaggtgacaatattaaacagataaacttgatgcagaaatcacaaatacctctcagcctgattgcccaaagaccaaaactgtgacacacaaatgggaccacacacgcttagctcagccatgccaggggagggctgaccgggcttctcaactcagaaaaattcagtcatgctccaccctcatacttcacatttctttatcaagcaggggctgcagtgggaagcaggcacattaatgacaacccacattccacatgtgcgcacacacaccacaatggagctatgatttcagaaaccttctaataaacaggatgttggagtgctgattgatttacacgttgataaaagttccgttgaaatgagcctactatctatcatgcaagtggctgtgaaaaacttaattgcacaaactgttcttgttggaacagggagctatctgctccttttccttgcatggaccagagttcctccctcacagctactgcaggacacaaaaagacagcacttaaaactggatcctgttctgcaaaccgtgcaagtcaatccggcgccgttcacagacatttttatttctgatcatgtctccaagtgtagacatctgagaaatataatcttgcctcagcaaggctcaaaggagacatttgatctctaagtcatagtctcactgatcatgcttagttagtaagtcacagaaaaaataaattaaattgcatcatgggcttaaaatattttattctcccttataatttccatatcccaaagccaacttgtttaactattaaatgtacgtactccacttaggaatgaaaactgtaaactgttttttcctgatgagcacatgtgatgtctttatcattaatagtgaataggtggtaatattccttcttggttttgtttttgggttttttatgttaacactattacacatgtcccccattccttccccccttttgcccacttccacccagtccctacccacccctctctggccttcaccaccactgttttctgggttcgtgggcttgcatatattgttctttggctaatcctctacacttcctt"); 1809 auto exactAlignment = getPaddedAlignment(ac, begin, end, aSequence, bSequence); 1810 1811 cast(void) exactAlignment[47139 .. 73889]; 1812 } 1813 1814 /** 1815 Get the FASTA sequences of the designated records. 1816 1817 Throws: DazzlerCommandException if recordNumber is not in dbFile 1818 */ 1819 auto getFastaSequences(Range)(in string dbFile, Range recordNumbers, in string workdir) 1820 if (isForwardRange!Range && is(ElementType!Range : size_t)) 1821 { 1822 string[] dbdumpOptions = [DBdumpOptions.sequenceString]; 1823 auto numRecords = recordNumbers.save.walkLength; 1824 auto sequences = readSequences(dbdump(dbFile, recordNumbers, dbdumpOptions, workdir)); 1825 size_t numFoundSequences; 1826 1827 string countedSequences() 1828 { 1829 enforce!DazzlerCommandException( 1830 !sequences.empty || numFoundSequences >= numRecords, 1831 "cannot read sequence: dump too short" 1832 ); 1833 1834 if (sequences.empty) 1835 { 1836 assert(numFoundSequences == numRecords, "unexpected excessive sequence in dump"); 1837 return null; 1838 } 1839 1840 ++numFoundSequences; 1841 auto currentSequence = sequences.front; 1842 sequences.popFront(); 1843 1844 return currentSequence; 1845 } 1846 1847 return generate!countedSequences.takeExactly(numRecords); 1848 } 1849 1850 /** 1851 Get the FASTA sequence of the designated record with prefetching to reduce `fork`s. 1852 1853 Throws: DazzlerCommandException if recordNumber is not in dbFile 1854 */ 1855 auto getFastaSequence(in string dbFile, id_t recordNumber, in string workdir, in id_t cacheSize = 1024) 1856 { 1857 // FIXME the cache size should limit the number of `char`s retrieved, ie. control the memory 1858 // requirements of this function 1859 static uint _dbIdx; 1860 static id_t[2] _firstRecord; 1861 static string[2] _dbFile; 1862 static id_t[2] _numRecords; 1863 static string[][2] _cache; 1864 1865 if (!dbFile.among(_dbFile[0], _dbFile[1])) 1866 { 1867 // Select least recently used DB cache 1868 _dbIdx = 1 - _dbIdx; 1869 _firstRecord[_dbIdx] = 0; 1870 _dbFile[_dbIdx] = dbFile; 1871 _numRecords[_dbIdx] = cast(id_t) getNumContigs(dbFile, workdir); 1872 _cache[_dbIdx].length = 0; 1873 } 1874 1875 _dbIdx = _dbFile[0] == dbFile ? 0 : 1; 1876 assert(_dbFile[_dbIdx] == dbFile); 1877 1878 if ( 1879 recordNumber >= _firstRecord[_dbIdx] + _cache[_dbIdx].length || 1880 recordNumber < _firstRecord[_dbIdx] 1881 ) 1882 { 1883 enum string[] dbdumpOptions = [DBdumpOptions.sequenceString]; 1884 _cache[_dbIdx].length = cacheSize; 1885 auto bufferRest = readSequences(dbdump( 1886 dbFile, 1887 recordNumber, 1888 min(recordNumber + cacheSize - 1, _numRecords[_dbIdx]), 1889 dbdumpOptions, 1890 workdir, 1891 )).copy(_cache[_dbIdx]); 1892 _cache[_dbIdx] = _cache[_dbIdx][0 .. $ - bufferRest.length]; 1893 _firstRecord[_dbIdx] = recordNumber; 1894 enforce!DazzlerCommandException(_cache[_dbIdx].length > 0, "cannot read sequence: empty dump"); 1895 } 1896 1897 1898 return _cache[_dbIdx][recordNumber - _firstRecord[_dbIdx]]; 1899 } 1900 1901 private auto readSequences(R)(R dbdump) 1902 { 1903 enum baseLetters = AliasSeq!('A', 'C', 'G', 'N', 'T', 'a', 'c', 'g', 'n', 't'); 1904 1905 return dbdump 1906 .filter!(dumpLine => dumpLine[0] == 'S') 1907 .map!(dumpLine => dumpLine.find!(among!baseLetters)); 1908 } 1909 1910 unittest 1911 { 1912 import std.algorithm : equal; 1913 1914 enum testDbDump = q"EOF 1915 + R 2 1916 + M 0 1917 + S 100 1918 @ S 100 1919 S 58 tgtgatatcggtacagtaaaccacagttgggtttaaggagggacgatcaacgaacacc 1920 S 42 atgccaactactttgaacgcgccgcaaggcacaggtgcgcct 1921 EOF".outdent; 1922 1923 size_t[] recordIds = []; 1924 auto fastaSequences = readSequences(testDbDump.lineSplitter); 1925 assert(fastaSequences.equal([ 1926 "tgtgatatcggtacagtaaaccacagttgggtttaaggagggacgatcaacgaacacc", 1927 "atgccaactactttgaacgcgccgcaaggcacaggtgcgcct", 1928 ])); 1929 } 1930 1931 /** 1932 Get the designated set of records in FASTA format. If recordNumbers is 1933 empty the whole DB will be converted. 1934 */ 1935 auto getFastaEntries(Options, Range)(in string dbFile, Range recordNumbers, in Options options) 1936 if (isIntegral!(typeof(options.fastaLineWidth)) && 1937 isSomeString!(typeof(options.workdir)) && 1938 isInputRange!Range && is(ElementType!Range : size_t)) 1939 { 1940 string[] dbdumpOptions = [ 1941 DBdumpOptions.readNumber, 1942 DBdumpOptions.originalHeader, 1943 DBdumpOptions.sequenceString, 1944 ]; 1945 1946 return readDbDump(dbdump(dbFile, recordNumbers, dbdumpOptions, 1947 options.workdir), recordNumbers, options.fastaLineWidth); 1948 } 1949 1950 private auto readDbDump(S, Range)(S dbDump, Range recordNumbers, in size_t lineLength) 1951 if (isInputRange!S && isSomeString!(ElementType!S) 1952 && isInputRange!Range && is(ElementType!Range : size_t)) 1953 { 1954 import std.algorithm : count, filter, sort; 1955 import std.array : appender; 1956 import std.range : chunks, drop; 1957 1958 enum lineSeparator = '\n'; 1959 enum subrecordSeparator = ';'; 1960 enum recordFormat = "R %d;H %d %s;L %d %d %d;S %d %s"; 1961 enum numRecordLines = recordFormat.count(subrecordSeparator) + 1; 1962 1963 /// Build chunks of numRecordLines lines. 1964 alias byRecordSplitter = dbDump => dbDump.drop(6).arrayChunks(numRecordLines); 1965 /// Parse chunks of numRecordLines lines into FASTA format. 1966 alias parseRecord = recordLines => { 1967 size_t recordNumber; 1968 size_t headerLineLength; 1969 string headerLine; 1970 size_t locationWell; 1971 size_t locationPulseStart; 1972 size_t locationPulseEnd; 1973 size_t sequenceLength; 1974 string sequence; 1975 1976 auto joinedLines = recordLines.joiner(only(subrecordSeparator)).array; 1977 1978 int numMatches = joinedLines 1979 .formattedRead!recordFormat( 1980 recordNumber, 1981 headerLineLength, 1982 headerLine, 1983 locationWell, 1984 locationPulseStart, 1985 locationPulseEnd, 1986 sequenceLength, 1987 sequence, 1988 ); 1989 assert(numMatches == 8, format!"%d matches in chunk: `%s`"(numMatches, joinedLines.array)); 1990 1991 bool isSkipping = recordNumbers.length > 0 && !recordNumbers.canFind(recordNumber); 1992 1993 debug logJsonDebug( 1994 "isSkipping", isSkipping, 1995 "wantedRecordNumbers", recordNumbers.toJson, 1996 "recordNumber", recordNumber, 1997 "headerLine", headerLine, 1998 ); 1999 2000 // skip unwanted records 2001 if (isSkipping) 2002 return null; 2003 2004 auto fastaData = appender!string; 2005 fastaData.reserve(headerLine.length + sequence.length + sequence.length / lineLength + 1); 2006 2007 fastaData ~= headerLine ~ lineSeparator; 2008 fastaData ~= sequence.chunks(lineLength).joiner(only(lineSeparator)); 2009 2010 return fastaData.data; 2011 }; 2012 2013 return byRecordSplitter(dbDump).map!parseRecord 2014 .map!"a()" 2015 .cache 2016 .filter!"a !is null"; 2017 } 2018 2019 unittest 2020 { 2021 enum testDbDump = q"EOF 2022 + R 4 2023 + M 0 2024 + H 104539 2025 @ H 26 2026 + S 38 2027 @ S 19574 2028 R 1 2029 H 22 >Sim/1/0_14 RQ=0.975 2030 L 0 0 14 2031 S 14 ggcccaggcagccc 2032 R 2 2033 H 22 >Sim/2/0_9 RQ=0.975 2034 L 0 0 9 2035 S 9 cacattgtg 2036 R 3 2037 H 23 >Sim/3/0_11 RQ=0.975 2038 L 0 0 11 2039 S 11 gagtgcagtgg 2040 R 4 2041 H 23 >Sim/4/0_4 RQ=0.975 2042 L 0 0 4 2043 S 4 gagc 2044 R 5 2045 H 24 >Sim/5/0_60 RQ=0.975 2046 L 0 0 60 2047 S 60 gagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagc 2048 EOF".outdent; 2049 2050 { 2051 size_t[] recordIds = []; 2052 auto fastaEntries = readDbDump(testDbDump.lineSplitter, recordIds, 50).array; 2053 assert(fastaEntries == [ 2054 ">Sim/1/0_14 RQ=0.975\nggcccaggcagccc", 2055 ">Sim/2/0_9 RQ=0.975\ncacattgtg", 2056 ">Sim/3/0_11 RQ=0.975\ngagtgcagtgg", 2057 ">Sim/4/0_4 RQ=0.975\ngagc", 2058 ">Sim/5/0_60 RQ=0.975\ngagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagcgagcga\ngcgagcgagc", 2059 ], fastaEntries.to!string); 2060 } 2061 { 2062 size_t[] recordIds = [1, 3]; 2063 auto fastaEntries = readDbDump(testDbDump.lineSplitter, recordIds, 50).array; 2064 assert(fastaEntries == [ 2065 ">Sim/1/0_14 RQ=0.975\nggcccaggcagccc", 2066 ">Sim/3/0_11 RQ=0.975\ngagtgcagtgg", 2067 ], fastaEntries.to!string); 2068 } 2069 } 2070 2071 /// Build a .dam file with the given set of FASTA records. 2072 string buildDamFile(Range)(Range fastaRecords, in string workdir, in string[] dbsplitOptions = []) 2073 if (isInputRange!Range && isSomeString!(ElementType!Range)) 2074 { 2075 enum tempDbNameTemplate = "auxiliary-XXXXXX"; 2076 2077 auto tempDbTemplate = buildPath(workdir, tempDbNameTemplate); 2078 auto tempDb = mkstemp(tempDbTemplate, damFileExtension); 2079 2080 tempDb.file.close(); 2081 remove(tempDb.name); 2082 fasta2dam(tempDb.name, fastaRecords, workdir); 2083 dbsplit(tempDb.name, dbsplitOptions, workdir); 2084 2085 return tempDb.name; 2086 } 2087 2088 unittest 2089 { 2090 import dentist.util.tempfile : mkdtemp; 2091 import std.file : rmdirRecurse, isFile; 2092 2093 auto fastaRecords = [ 2094 ">Sim/1/0_14 RQ=0.975\nggcccacccaggcagccc", 2095 ">Sim/3/0_11 RQ=0.975\ngagtgcgtgcagtgg", 2096 ]; 2097 2098 auto tmpDir = mkdtemp("./.unittest-XXXXXX"); 2099 scope (exit) 2100 rmdirRecurse(tmpDir); 2101 2102 string dbName = buildDamFile(fastaRecords[], tmpDir); 2103 2104 assert(dbName.isFile); 2105 foreach (hiddenDbFile; getHiddenDbFiles(dbName)) 2106 { 2107 assert(hiddenDbFile.isFile); 2108 } 2109 } 2110 2111 /** 2112 Self-dalign dbFile and build consensus using daccord. 2113 2114 Returns: list of consensus DBs. 2115 */ 2116 string getConsensus(Options)(in string dbFile, in size_t readId, in Options options) 2117 if (isOptionsList!(typeof(options.daccordOptions)) && 2118 isOptionsList!(typeof(options.lasFilterAlignmentsOptions)) && 2119 isOptionsList!(typeof(options.dalignerOptions)) && 2120 isOptionsList!(typeof(options.dbsplitOptions)) && 2121 isSomeString!(typeof(options.workdir))) 2122 { 2123 static struct ModifiedOptions 2124 { 2125 string[] daccordOptions; 2126 string[] dalignerOptions; 2127 string[] dbsplitOptions; 2128 string[] lasFilterAlignmentsOptions; 2129 string workdir; 2130 } 2131 2132 auto readIdx = readId - 1; 2133 auto consensusDb = getConsensus(dbFile, const(ModifiedOptions)( 2134 options.daccordOptions ~ format!"%s%d,%d"(cast(string) DaccordOptions.readInterval, readIdx, readIdx), 2135 options.dalignerOptions, 2136 options.dbsplitOptions, 2137 options.lasFilterAlignmentsOptions, 2138 options.workdir, 2139 )); 2140 2141 if (consensusDb is null) 2142 { 2143 throw new Exception("empty consensus"); 2144 } 2145 2146 return consensusDb; 2147 } 2148 2149 /// ditto 2150 string getConsensus(Options)(in string dbFile, in Options options) 2151 if (isOptionsList!(typeof(options.daccordOptions)) && 2152 isOptionsList!(typeof(options.lasFilterAlignmentsOptions)) && 2153 isOptionsList!(typeof(options.dalignerOptions)) && 2154 isOptionsList!(typeof(options.dbsplitOptions)) && 2155 isSomeString!(typeof(options.workdir))) 2156 { 2157 dalign(dbFile, options.dalignerOptions, options.workdir); 2158 auto lasFile = getLasFile(dbFile, options.workdir); 2159 enforce!DazzlerCommandException( 2160 !lasEmpty( 2161 lasFile, 2162 dbFile, 2163 null, 2164 options.workdir, 2165 ), 2166 "empty pre-consensus alignment", 2167 ); 2168 2169 computeIntrinsticQualityValuesForConsensus(dbFile, options); 2170 // FIXME remove if bug in lasfilteralignments is fixed 2171 version(unittest) 2172 auto filteredLasFile = lasFile; 2173 else 2174 auto filteredLasFile = filterAlignmentsForConsensus(dbFile, options); 2175 enforce!DazzlerCommandException( 2176 !lasEmpty( 2177 filteredLasFile, 2178 dbFile, 2179 null, 2180 options.workdir, 2181 ), 2182 "empty pre-consensus alignment", 2183 ); 2184 2185 computeErrorProfile(dbFile, filteredLasFile, options); 2186 2187 auto consensusDb = daccord(dbFile, filteredLasFile, options.daccordOptions, options.workdir); 2188 dbsplit(consensusDb, options.dbsplitOptions, options.workdir); 2189 2190 return consensusDb; 2191 } 2192 2193 private void computeIntrinsticQualityValuesForConsensus(Options)(in string dbFile, in Options options) 2194 if (isSomeString!(typeof(options.workdir))) 2195 { 2196 auto readDepth = getNumContigs(dbFile, options.workdir); 2197 auto lasFile = getLasFile(dbFile, options.workdir); 2198 2199 computeIntrinsicQV(dbFile, lasFile, readDepth, options.workdir); 2200 } 2201 2202 private string filterAlignmentsForConsensus(Options)(in string dbFile, in Options options) 2203 if (isOptionsList!(typeof(options.lasFilterAlignmentsOptions)) && 2204 isSomeString!(typeof(options.workdir))) 2205 { 2206 auto lasFile = getLasFile(dbFile, options.workdir); 2207 auto filteredLasFile = lasFilterAlignments(dbFile, lasFile, options.lasFilterAlignmentsOptions, options.workdir); 2208 2209 return filteredLasFile; 2210 } 2211 2212 private void computeErrorProfile(Options)(in string dbFile, in string lasFile, in Options options) 2213 if (isOptionsList!(typeof(options.daccordOptions)) && 2214 isSomeString!(typeof(options.workdir))) 2215 { 2216 auto eProfOptions = options 2217 .daccordOptions 2218 .filter!(option => !option.startsWith( 2219 cast(string) DaccordOptions.produceFullSequences, 2220 cast(string) DaccordOptions.readsPart, 2221 cast(string) DaccordOptions.errorProfileFileName, 2222 )) 2223 .chain(only(DaccordOptions.computeErrorProfileOnly)) 2224 .array; 2225 2226 // Produce error profile 2227 silentDaccord(dbFile, lasFile, eProfOptions, options.workdir); 2228 } 2229 2230 2231 unittest 2232 { 2233 import dentist.util.tempfile : mkdtemp; 2234 import std.file : rmdirRecurse, isFile; 2235 2236 auto fastaRecords = [ 2237 ">Sim/1/0_1050 RQ=0.975\nattTgaggcatcagccactgcacccagccttgtgccctttctgagagccgggaagatgctcccaggagccctcg\nggaggcttccctccggtcgtcgtggccagaattgtctcctgctcgtgtggagtcggtggcgggccaggcgaatg\nggagctaccggggctgccgctttggactgctcggcatttgccccatggggctgcacaggggcccaggctggctg\nagaatgtccctgggtccaggaggcagacggaggtacagcccagcagccaggaggtgttcaggatgttccccagt\ncagcacccgtggaggggagggaggaggcagggtgggcgaggaaggtccaacagtggacggcctgcccacaagag\nagctctgagctgggagctggcagagttgctgcaagtgggtgtgggccaggactgactgggcctgtgcacctgcc\ntggatgcatcagtggtcgtggtgctgcccgggaagggcgtgaagctccctgcagccaaggatcctggaggtgca\ngacatcacccagcccaccggacaacagcctgccctacttcgaggagctctgggcagcccagccccatgtccccc\ntcacgccccaccccacactgacaaaaagaccacaggattccaacagtccaaccagggggaggccgttgaattcg\nggggacaaccagaaacgcctgaaacagagataaagagactgatatggaaaagactgggctggcatggtggctcc\ncaactgggatcccagtgcttgtgagaggccgaggcgggaggatcacttgagcccagaagttcaagaccagcgtg\nggcaacatagtgagaccccgtctcttttaaaaatccttttttaattaggcaggcataggtagttgcgtgcctgc\nttttcccagctgctagggaggtagaggcaggagaatcacgggagtttcgaagtccaaggtcacagtgagctgtg\nattgcaccactgcactccagcctgggcaacatggcaagaccccatctctaaaagaaagaaacaagaagacatgg\nagagaaatatccaa", 2238 ">Sim/2/0_1050 RQ=0.975\nattagagCcatcagccactgcacccagccttgtgccctttctgagagccgggaagatgctcccaggagccctcg\nggaggcttccctccggtcgtcgtggccagaattgtctcctgctcgtgtggagtcggtggcgggccaggcgaatg\nggagctaccggggctgccgctttggactgctcggcatttgccccatggggctgcacaggggcccaggctggctg\nagaatgtccctgggtccaggaggcagacggaggtacagcccagcagccaggaggtgttcaggatgttccccagt\ncagcacccgtggaggggagggaggaggcagggtgggcgaggaaggtccaacagtggacggcctgcccacaagag\nagctctgagctgggagctggcagagttgctgcaagtgggtgtgggccaggactgactgggcctgtgcacctgcc\ntggatgcatcagtggtcgtggtgctgcccgggaagggcgtgaagctccctgcagccaaggatcctggaggtgca\ngacatcacccagcccaccggacaacagcctgccctacttcgaggagctctgggcagcccagccccatgtccccc\ntcacgccccaccccacactgacaaaaagaccacaggattccaacagtccaaccagggggaggccgttgaattcg\nggggacaaccagaaacgcctgaaacagagataaagagactgatatggaaaagactgggctggcatggtggctcc\ncaactgggatcccagtgcttgtgagaggccgaggcgggaggatcacttgagcccagaagttcaagaccagcgtg\nggcaacatagtgagaccccgtctcttttaaaaatccttttttaattaggcaggcataggtagttgcgtgcctgc\nttttcccagctgctagggaggtagaggcaggagaatcacgggagtttcgaagtccaaggtcacagtgagctgtg\nattgcaccactgcactccagcctgggcaacatggcaagaccccatctctaaaagaaagaaacaagaagacatgg\nagagaaatatccaa", 2239 ">Sim/3/0_1050 RQ=0.975\nattagaggcatcagccactgcacccagccttgtgccctttctgagagccgggaagatgctcccaggagccctcg\nggaggcttccctccggtcgtcgtggccagaattgtctcctgctcgtgtggagtcggtggcgggccaggcgaatg\nggagctaccggggctgccgctttggactgctcggcatttgccccatggggctgcacaggggcccaggctggctg\nagaatgtccctgggtccaggaggcagacggaggtacagcccagcagccaggaggtgttcaggatgttccccagt\ncagcacccgtggaggggagggaggaggcagggtgggcgaggaaggtccaacagtggacggcctgcccacaagag\nagctctgagctgggagctggcagagttgctgcaagtgggtgtgggccaggactgactgggcctgtgcacctgcc\ntggatgcatcagtggtcgtggtgctgcccgggaagggcgtgaagctccctgcagccaaggatcctggaggtgca\ngacatcacccagcccaccggacaacagcctgccctacttcgaggagctctgggcagcccagccccatgtccccc\ntcacgccccaccccacactgacaaaaagaccacaggattccaacagtccaaccagggggaggccgttgaattcg\nggggacaaccagaaacgcctgaaacagagataaagagactgatatggaaaagactgggctggcatggtggctcc\ncaactgggatcccagtgcttgtgagaggccgaggcgggaggatcacttgagcccagaagttcaagaccagcgtg\nggcaacatagtgagaccccgtctcttttaaaaatccttttttaattaggcaggcataggtagttgcgtgcctgc\nttttcccagctgctagggaggtagaggcaggagaatcacgggagtttcgaagtccaaggtcacagtgagctgtg\nattgcaccactgcactccagcctgggcaacatggcaagaccccatctctaaaagaaagaaacaagaagacatgg\nagagaaatatccaa", 2240 ]; 2241 2242 struct Options 2243 { 2244 string[] dbsplitOptions; 2245 string[] dalignerOptions; 2246 string[] daccordOptions; 2247 string[] lasFilterAlignmentsOptions; 2248 size_t fastaLineWidth; 2249 string workdir; 2250 } 2251 2252 auto tmpDir = mkdtemp("./.unittest-XXXXXX"); 2253 auto options = Options( 2254 [], 2255 [DalignerOptions.minAlignmentLength ~ "15"], 2256 [], 2257 [ 2258 LasFilterAlignmentsOptions.errorThresold ~ (0.05).to!string, 2259 ], 2260 74, 2261 tmpDir, 2262 ); 2263 scope (exit) 2264 rmdirRecurse(tmpDir); 2265 2266 string dbName = buildDamFile(fastaRecords[], tmpDir); 2267 string consensusDb = getConsensus(dbName, options); 2268 assert(consensusDb !is null); 2269 auto consensusFasta = getFastaEntries(consensusDb, cast(size_t[])[], options); 2270 auto expectedSequence = fastaRecords[$ - 1].lineSplitter.drop(1).joiner.array; 2271 auto consensusSequence = consensusFasta.front.lineSplitter.drop(1).joiner.array; 2272 2273 assert(expectedSequence == consensusSequence, 2274 format!"expected %s but got %s"(expectedSequence, consensusSequence)); 2275 } 2276 2277 string getLasFile(in string dbA, in string baseDirectory) 2278 { 2279 return getLasFile(dbA, null, baseDirectory); 2280 } 2281 2282 string getLasFile(in string dbA, in string dbB, in string baseDirectory) 2283 { 2284 alias dbName = dbFile => dbFile.baseName.stripExtension; 2285 2286 enum fileTemplate = "%s/%s.%s.las"; 2287 auto dbAName = dbName(dbA); 2288 auto dbBName = dbB is null ? dbAName : dbName(dbB); 2289 2290 return format!fileTemplate(baseDirectory, dbAName, dbBName); 2291 } 2292 2293 bool lasFileGenerated(in string dbA, in string baseDirectory) 2294 { 2295 return lasFileGenerated(dbA, null, baseDirectory); 2296 } 2297 2298 bool lasFileGenerated(in string dbA, in string dbB, in string baseDirectory) 2299 { 2300 return getLasFile(dbA, dbB, baseDirectory).exists; 2301 } 2302 2303 id_t getNumBlocks(in string damFile) 2304 { 2305 // see also in dazzler's DB.h:394 2306 // #define DB_NBLOCK "blocks = %9d\n" // number of blocks 2307 enum blockNumFormat = "blocks = %d"; 2308 enum blockNumFormatStart = blockNumFormat[0 .. 6]; 2309 id_t numBlocks; 2310 auto matchingLine = File(damFile.stripBlock).byLine.filter!( 2311 line => line.startsWith(blockNumFormatStart)).front; 2312 2313 if (!matchingLine) 2314 { 2315 auto errorMessage = format!"could not read the block count in `%s`"(damFile.stripBlock); 2316 throw new DazzlerCommandException(errorMessage); 2317 } 2318 2319 if (formattedRead!blockNumFormat(matchingLine, numBlocks) != 1) 2320 { 2321 auto errorMessage = format!"could not read the block count in `%s`"(damFile.stripBlock); 2322 throw new DazzlerCommandException(errorMessage); 2323 } 2324 2325 return numBlocks; 2326 } 2327 2328 id_t getNumContigs(in string damFile, in string workdir) 2329 { 2330 enum contigNumFormat = "+ R %d"; 2331 enum contigNumFormatStart = contigNumFormat[0 .. 4]; 2332 id_t numContigs; 2333 id_t[] empty; 2334 auto matchingLine = dbdump(damFile, empty, [], workdir) 2335 .filter!(line => line.startsWith(contigNumFormatStart)) 2336 .front; 2337 2338 if (!matchingLine) 2339 { 2340 auto errorMessage = format!"could not read the contig count in `%s`"(damFile); 2341 throw new DazzlerCommandException(errorMessage); 2342 } 2343 2344 if (formattedRead!contigNumFormat(matchingLine, numContigs) != 1) 2345 { 2346 auto errorMessage = format!"could not read the contig count in `%s`"(damFile); 2347 throw new DazzlerCommandException(errorMessage); 2348 } 2349 2350 return numContigs; 2351 } 2352 2353 auto getScaffoldStructure(in string damFile) 2354 { 2355 enum string[] dbshowOptions = [DBshowOptions.noSequence]; 2356 2357 auto rawScaffoldInfo = dbshow(damFile, dbshowOptions); 2358 2359 return ScaffoldStructureReader(rawScaffoldInfo); 2360 } 2361 2362 alias ScaffoldSegment = Algebraic!(ContigSegment, GapSegment); 2363 2364 struct ContigSegment 2365 { 2366 size_t globalContigId; 2367 size_t scaffoldId; 2368 size_t contigId; 2369 size_t begin; 2370 size_t end; 2371 string header; 2372 2373 invariant 2374 { 2375 assert(begin < end); 2376 } 2377 2378 @property size_t length() const pure nothrow 2379 { 2380 return end - begin; 2381 } 2382 } 2383 2384 struct GapSegment 2385 { 2386 size_t beginGlobalContigId; 2387 size_t endGlobalContigId; 2388 size_t scaffoldId; 2389 size_t beginContigId; 2390 size_t endContigId; 2391 size_t begin; 2392 size_t end; 2393 2394 invariant 2395 { 2396 assert(begin < end); 2397 } 2398 2399 @property size_t length() const pure nothrow 2400 { 2401 return end - begin; 2402 } 2403 } 2404 2405 private struct ScaffoldStructureReader 2406 { 2407 static enum scaffoldInfoLineFormat = "%s:: Contig %d[%d,%d]"; 2408 alias RawScaffoldInfo = typeof("".lineSplitter); 2409 2410 private RawScaffoldInfo rawScaffoldInfo; 2411 private ContigSegment lastContigPart; 2412 private ScaffoldSegment currentPart; 2413 private bool _empty; 2414 2415 this(string rawScaffoldInfo) 2416 { 2417 this.rawScaffoldInfo = rawScaffoldInfo.lineSplitter; 2418 // Force the first element to be a contigPart. 2419 this.currentPart = GapSegment(); 2420 // Make `scaffoldId`s start at 0. 2421 this.lastContigPart.scaffoldId = -1UL; 2422 2423 if (!empty) 2424 { 2425 popFront(); 2426 } 2427 } 2428 2429 void popFront() 2430 { 2431 assert(!empty, "Attempting to popFront an empty ScaffoldStructureReader"); 2432 2433 if (rawScaffoldInfo.empty) 2434 { 2435 _empty = true; 2436 2437 return; 2438 } 2439 2440 auto nextContigPart = ContigSegment( 2441 lastContigPart.globalContigId + 1, 2442 lastContigPart.scaffoldId, 2443 ); 2444 2445 rawScaffoldInfo.front.formattedRead!scaffoldInfoLineFormat( 2446 nextContigPart.header, 2447 nextContigPart.contigId, 2448 nextContigPart.begin, 2449 nextContigPart.end, 2450 ); 2451 auto hasHeaderChanged = lastContigPart.header != nextContigPart.header[0 .. $ - 1]; 2452 2453 if (hasHeaderChanged) 2454 ++nextContigPart.scaffoldId; 2455 2456 if (currentPart.peek!GapSegment !is null 2457 || lastContigPart.scaffoldId != nextContigPart.scaffoldId) 2458 { 2459 assert(nextContigPart.header[$ - 1] == ' '); 2460 // Remove the trailing space 2461 nextContigPart.header = nextContigPart.header[0 .. $ - 1]; 2462 lastContigPart = nextContigPart; 2463 currentPart = nextContigPart; 2464 rawScaffoldInfo.popFront(); 2465 } 2466 else 2467 { 2468 currentPart = GapSegment( 2469 lastContigPart.globalContigId, 2470 nextContigPart.globalContigId, 2471 lastContigPart.scaffoldId, 2472 lastContigPart.contigId, 2473 nextContigPart.contigId, 2474 lastContigPart.end, 2475 nextContigPart.begin, 2476 ); 2477 } 2478 } 2479 2480 @property ScaffoldSegment front() const 2481 { 2482 assert(!empty, "Attempting to fetch the front of an empty ScaffoldStructureReader"); 2483 return currentPart; 2484 } 2485 2486 @property bool empty() const 2487 { 2488 return _empty; 2489 } 2490 2491 ScaffoldStructureReader save() 2492 { 2493 ScaffoldStructureReader copy; 2494 2495 copy.rawScaffoldInfo = this.rawScaffoldInfo.save; 2496 copy.lastContigPart = this.lastContigPart; 2497 copy.currentPart = this.currentPart; 2498 copy._empty = this._empty; 2499 2500 return copy; 2501 } 2502 } 2503 2504 unittest 2505 { 2506 auto exampleDump = q"EOS 2507 >reference_mod/1/0_837550 RQ=0.850 :: Contig 0[0,8300] 2508 >reference_mod/1/0_837550 RQ=0.850 :: Contig 1[12400,20750] 2509 >reference_mod/1/0_837550 RQ=0.850 :: Contig 2[29200,154900] 2510 >reference_mod/1/0_837550 RQ=0.850 :: Contig 3[159900,169900] 2511 >reference_mod/1/0_837550 RQ=0.850 :: Contig 4[174900,200650] 2512 >reference_mod/1/0_837550 RQ=0.850 :: Contig 5[203650,216400] 2513 >reference_mod/1/0_837550 RQ=0.850 :: Contig 6[218900,235150] 2514 >reference_mod/1/0_837550 RQ=0.850 :: Contig 7[238750,260150] 2515 >reference_mod/1/0_837550 RQ=0.850 :: Contig 8[263650,837500] 2516 >reference_mod/2/0_1450 RQ=0.850 :: Contig 0[0,1450] 2517 EOS"; 2518 2519 auto reader = ScaffoldStructureReader(exampleDump); 2520 auto scaffoldStructure = reader.array; 2521 2522 assert(scaffoldStructure == [ 2523 ScaffoldSegment(ContigSegment( 2524 1, 0, 0, 0, 8300, 2525 ">reference_mod/1/0_837550 RQ=0.850", 2526 )), 2527 ScaffoldSegment(GapSegment(1, 2, 0, 0, 1, 8300, 12400)), 2528 ScaffoldSegment(ContigSegment( 2529 2, 0, 1, 12400, 20750, 2530 ">reference_mod/1/0_837550 RQ=0.850", 2531 )), 2532 ScaffoldSegment(GapSegment(2, 3, 0, 1, 2, 20750, 29200)), 2533 ScaffoldSegment(ContigSegment( 2534 3, 0, 2, 29200, 154900, 2535 ">reference_mod/1/0_837550 RQ=0.850", 2536 )), 2537 ScaffoldSegment(GapSegment(3, 4, 0, 2, 3, 154900, 159900)), 2538 ScaffoldSegment(ContigSegment( 2539 4, 0, 3, 159900, 169900, 2540 ">reference_mod/1/0_837550 RQ=0.850", 2541 )), 2542 ScaffoldSegment(GapSegment(4, 5, 0, 3, 4, 169900, 174900)), 2543 ScaffoldSegment(ContigSegment( 2544 5, 0, 4, 174900, 200650, 2545 ">reference_mod/1/0_837550 RQ=0.850", 2546 )), 2547 ScaffoldSegment(GapSegment(5, 6, 0, 4, 5, 200650, 203650)), 2548 ScaffoldSegment(ContigSegment( 2549 6, 0, 5, 203650, 216400, 2550 ">reference_mod/1/0_837550 RQ=0.850", 2551 )), 2552 ScaffoldSegment(GapSegment(6, 7, 0, 5, 6, 216400, 218900)), 2553 ScaffoldSegment(ContigSegment( 2554 7, 0, 6, 218900, 235150, 2555 ">reference_mod/1/0_837550 RQ=0.850", 2556 )), 2557 ScaffoldSegment(GapSegment(7, 8, 0, 6, 7, 235150, 238750)), 2558 ScaffoldSegment(ContigSegment( 2559 8, 0, 7, 238750, 260150, 2560 ">reference_mod/1/0_837550 RQ=0.850", 2561 )), 2562 ScaffoldSegment(GapSegment(8, 9, 0, 7, 8, 260150, 263650)), 2563 ScaffoldSegment(ContigSegment( 2564 9, 0, 8, 263650, 837500, 2565 ">reference_mod/1/0_837550 RQ=0.850", 2566 )), 2567 ScaffoldSegment(ContigSegment( 2568 10, 1, 0, 0, 1450, 2569 ">reference_mod/2/0_1450 RQ=0.850", 2570 )), 2571 ]); 2572 } 2573 2574 /** 2575 Get the hidden files comprising the designated mask. 2576 */ 2577 auto getMaskFiles(in string dbFile, in string maskDestination) 2578 { 2579 auto destinationDir = maskDestination.dirName; 2580 auto maskName = maskDestination.baseName; 2581 auto dbName = dbFile.baseName.stripExtension; 2582 auto maskHeader = format!"%s/.%s.%s.anno"(destinationDir, dbName, maskName); 2583 auto maskData = format!"%s/.%s.%s.data"(destinationDir, dbName, maskName); 2584 2585 return tuple!("header", "data")(maskHeader, maskData); 2586 } 2587 2588 /// Thrown on failure while reading a Dazzler mask. 2589 /// 2590 /// See_Also: `readMask` 2591 class MaskReaderException : Exception 2592 { 2593 pure nothrow @nogc @safe this(string msg, string file = __FILE__, 2594 size_t line = __LINE__, Throwable nextInChain = null) 2595 { 2596 super(msg, file, line, nextInChain); 2597 } 2598 } 2599 2600 private 2601 { 2602 alias MaskHeaderEntry = int; 2603 alias MaskDataPointer = long; 2604 alias MaskDataEntry = int; 2605 } 2606 2607 /** 2608 Read the `Region`s of a Dazzler mask for `dbFile`. 2609 2610 Throws: MaskReaderException 2611 See_Also: `writeMask`, `getMaskFiles` 2612 */ 2613 Region[] readMask(Region)(in string dbFile, in string maskDestination, in string workdir) 2614 { 2615 alias _enforce = enforce!MaskReaderException; 2616 2617 auto maskFileNames = getMaskFiles(dbFile, maskDestination); 2618 auto maskHeader = readMaskHeader(maskFileNames.header); 2619 auto maskData = getBinaryFile!MaskDataEntry(maskFileNames.data); 2620 2621 auto maskRegions = appender!(Region[]); 2622 alias RegionContigId = typeof(maskRegions.data[0].tag); 2623 alias RegionBegin = typeof(maskRegions.data[0].begin); 2624 alias RegionEnd = typeof(maskRegions.data[0].end); 2625 auto numReads = getNumContigs(dbFile, workdir).to!int; 2626 2627 size_t currentContig = 1; 2628 2629 if (maskHeader.numReads != numReads) 2630 logJsonWarn( 2631 "info", 2632 "mask does not match DB: number of reads does not match", 2633 ); 2634 _enforce(maskHeader.size == 0, "corrupted mask: expected 0"); 2635 _enforce(maskHeader.dataPointers.length == maskHeader.numReads + 1, 2636 "corrupted mask: unexpected number of data pointers"); 2637 2638 foreach (dataPtrRange; maskHeader.dataPointers[].slide!(No.withPartial)(2)) 2639 { 2640 auto dataPtrs = dataPtrRange.map!(ptr => ptr / MaskDataEntry.sizeof) 2641 .takeExactly!2; 2642 _enforce(0 <= dataPtrs[0] && dataPtrs[0] <= dataPtrs[1] 2643 && dataPtrs[1] <= maskData.length, "corrupted mask: data pointer out of bounds"); 2644 _enforce(dataPtrs[0] % 2 == 0 && dataPtrs[1] % 2 == 0, 2645 "corrupted mask: non-sense data pointers"); 2646 2647 foreach (interval; maskData[dataPtrs[0] .. dataPtrs[1]].chunks(2)) 2648 { 2649 enforce!MaskReaderException(interval.length == 2 && 0 <= interval[0] 2650 && interval[0] <= interval[1], "corrupted mask: invalid interval"); 2651 2652 Region newRegion; 2653 newRegion.tag = currentContig.to!RegionContigId; 2654 newRegion.begin = interval[0].to!RegionBegin; 2655 newRegion.end = interval[1].to!RegionEnd; 2656 2657 maskRegions ~= newRegion; 2658 } 2659 2660 ++currentContig; 2661 } 2662 2663 return maskRegions.data; 2664 } 2665 2666 private auto readMaskHeader(in string fileName) 2667 { 2668 auto headerFile = File(fileName, "rb"); 2669 MaskHeaderEntry[2] headerBuffer; 2670 auto numPointers = (headerFile.size - headerBuffer.sizeof) / MaskDataPointer.sizeof; 2671 auto pointerBuffer = uninitializedArray!(MaskDataPointer[])(numPointers); 2672 2673 enforce!MaskReaderException(headerFile.rawRead(headerBuffer).length == headerBuffer.length, 2674 format!"error while reading mask header `%s`: file too short"(fileName)); 2675 enforce!MaskReaderException(headerFile.rawRead(pointerBuffer).length == numPointers, 2676 format!"error while reading mask header `%s`: file too short"(fileName)); 2677 2678 return tuple!("numReads", "size", "dataPointers")(headerBuffer[0], 2679 headerBuffer[1], pointerBuffer); 2680 } 2681 2682 private T[] getBinaryFile(T)(in string fileName) 2683 { 2684 auto file = File(fileName, "rb"); 2685 auto bufferLength = file.size / T.sizeof; 2686 auto dataBuffer = file.rawRead(uninitializedArray!(T[])(bufferLength)); 2687 2688 enforce!MaskReaderException(dataBuffer.length == bufferLength, 2689 format!"error while reading binary file `%s`: expected %d bytes of data but read only %d"( 2690 fileName, bufferLength * T.sizeof, dataBuffer.length * T.sizeof)); 2691 2692 return dataBuffer; 2693 } 2694 2695 /** 2696 Write the list of regions to a Dazzler mask for `dbFile`. 2697 2698 See_Also: `readMask`, `getMaskFiles` 2699 */ 2700 void writeMask(Region)( 2701 in string dbFile, 2702 in string maskDestination, 2703 in Region[] regions, 2704 in string workdir, 2705 ) 2706 { 2707 alias MaskRegion = Tuple!( 2708 MaskHeaderEntry, "tag", 2709 MaskDataEntry, "begin", 2710 MaskDataEntry, "end", 2711 ); 2712 2713 if (regions.length == 0) 2714 { 2715 logJsonDiagnostic( 2716 "notice", "skipping empty mask", 2717 "dbFile", dbFile, 2718 "maskDestination", maskDestination, 2719 ); 2720 2721 return; 2722 } 2723 2724 auto maskFileNames = getMaskFiles(dbFile, maskDestination); 2725 auto maskHeader = File(maskFileNames.header, "wb"); 2726 auto maskData = File(maskFileNames.data, "wb"); 2727 2728 auto maskRegions = regions 2729 .map!(region => MaskRegion( 2730 region.tag.to!MaskHeaderEntry, 2731 region.begin.to!MaskDataEntry, 2732 region.end.to!MaskDataEntry, 2733 )) 2734 .array; 2735 maskRegions.sort(); 2736 2737 auto numReads = getNumContigs(dbFile, workdir).to!MaskHeaderEntry; 2738 MaskHeaderEntry size = 0; // Mark the DAZZ_TRACK as a mask (see DAZZ_DB/DB.c:1183) 2739 MaskHeaderEntry currentContig = 1; 2740 MaskDataPointer dataPointer = 0; 2741 2742 maskHeader.rawWrite([numReads, size]); 2743 maskHeader.rawWrite([dataPointer]); 2744 foreach (maskRegion; maskRegions) 2745 { 2746 assert(maskRegion.tag >= currentContig); 2747 2748 while (maskRegion.tag > currentContig) 2749 { 2750 maskHeader.rawWrite([dataPointer]); 2751 ++currentContig; 2752 } 2753 2754 if (maskRegion.tag == currentContig) 2755 { 2756 maskData.rawWrite([maskRegion.begin, maskRegion.end]); 2757 dataPointer += typeof(maskRegion.begin).sizeof + typeof(maskRegion.end).sizeof; 2758 } 2759 } 2760 2761 foreach (emptyContig; currentContig .. numReads + 1) 2762 { 2763 maskHeader.rawWrite([dataPointer]); 2764 } 2765 } 2766 2767 /// Options for `daccord`. 2768 enum DaccordOptions : string 2769 { 2770 /// number of threads (default 4) 2771 numberOfThreads = "-t", 2772 /// window size (default 40) 2773 windowSize = "-w", 2774 /// advance size (default 10) 2775 advanceSize = "-a", 2776 /// max depth (default 18446744073709551615) 2777 maxDepth = "-d", 2778 /// produce full sequences (default 0) 2779 produceFullSequences = "-f", 2780 /// verbosity (default 18446744073709551615) 2781 verbosity = "-V", 2782 /// read interval (default 0,18446744073709551615) 2783 readInterval = "-I", 2784 /// reads part (default 0,1) 2785 readsPart = "-J", 2786 /// error profile file name (default input.las.eprof) 2787 errorProfileFileName = "-E", 2788 /// minimum window coverage (default 3) 2789 minWindowCoverage = "-m", 2790 /// maximum window error (default 18446744073709551615) 2791 maxWindowError = "-e", 2792 /// minimum length of output (default 0) 2793 minLengthOfOutput = "-l", 2794 /// minimum k-mer filter frequency (default 0) 2795 minKMerFilterFrequency = "--minfilterfreq", 2796 /// maximum k-mer filter frequency (default 2) 2797 maxKMerFilterFrequency = "--maxfilterfreq", 2798 /// temporary file prefix (default daccord_ozelot_4500_1529654843) 2799 temporaryFilePrefix = "-T", 2800 /// maximum number of alignments considered per read (default 5000) 2801 maxAlignmentsPerRead = "-D", 2802 /// maximum number of alignments considered per read (default 0) 2803 maxAlignmentsPerReadVard = "--vard", 2804 /// compute error profile only (default disable) 2805 computeErrorProfileOnly = "--eprofonly", 2806 /// compute error distribution estimate (default disable) 2807 computeErrorDistributionEstimate = "--deepprofileonly", 2808 /// kmer size (default 8) 2809 kmerSize = "-k", 2810 } 2811 2812 /// Options for `daligner`. 2813 enum DalignerOptions : string 2814 { 2815 verbose = "-v", 2816 /// If the -b option is set, then the daligner assumes the data has a 2817 /// strong compositional bias (e.g. >65% AT rich). 2818 strongCompositionalBias = "-b", 2819 /// If the -A option is set (“A” for “asymmetric”) then just overlaps 2820 /// where the a-read is in block X and the b-read is in block Y are 2821 /// reported, and if X = Y then it further reports only those overlaps 2822 /// where the a-read index is less than the b-read index. 2823 asymmetric = "-A", 2824 /// If the -I option is set (“I” for “identity”) then when X = Y, overlaps 2825 /// between different portions of the same read will also be found and 2826 /// reported. 2827 identity = "-I", 2828 /// Search code looks for a pair of diagonal bands of width 2^^w 2829 /// (default 26 = 64) that contain a collection of exact matching k-mers 2830 /// (default 14) between the two reads, such that the total number of 2831 /// bases covered by the k-mer hits is h (default 35). 2832 kMerSize = "-k", 2833 /// ditto 2834 bandWidth = "-w", 2835 /// ditto 2836 hitBaseCoverage = "-h", 2837 /// Suppresses the use of any k-mer that occurs more than t times in 2838 /// either the subject or target block. 2839 maxKmerOccurence = "-t", 2840 /// Let the program automatically select a value of t that meets a given 2841 /// memory usage limit specified (in Gb) by the -M parameter. 2842 maxKmerMemory = "-M", 2843 tempDir = "-P", 2844 /// Searching for local alignments involving at least -l base pairs 2845 /// (default 1000) or more, that have an average correlation rate of 2846 /// -e (default 70%). 2847 minAlignmentLength = "-l", 2848 /// ditto 2849 averageCorrelationRate = "-e", 2850 /// The local alignments found will be output in a sparse encoding where 2851 /// a trace point on the alignment is recorded every -s base pairs of 2852 /// the a-read (default 100bp). 2853 tracePointDistance = "-s", 2854 /// By setting the -H parameter to say N, one alters daligner so that it 2855 /// only reports overlaps where the a-read is over N base-pairs long. 2856 minAReadLength = "-H", 2857 /// The program runs with 4 threads by default, but this may be set to 2858 /// any power of 2 with the -T option. 2859 numThreads = "-T", 2860 /// If there are one or more interval tracks specified with the -m option 2861 /// (m for mask), then the reads of the DB or DB’s to which the track 2862 /// applies are soft masked with the union of the intervals of all the 2863 /// interval tracks that apply, that is any k-mers that contain any bases 2864 /// in any of the masked intervals are ignored for the purposes of seeding 2865 /// a match. 2866 masks = "-m", 2867 } 2868 2869 /// Options for `damapper`. 2870 enum DamapperOptions : string 2871 { 2872 verbose = "-v", 2873 /// If the -b option is set, then the daligner assumes the data has a 2874 /// strong compositional bias (e.g. >65% AT rich). 2875 strongCompositionalBias = "-b", 2876 /// Search code looks for a pair of diagonal bands of width 2^^w 2877 /// (default 26 = 64) that contain a collection of exact matching k-mers 2878 /// (default 14) between the two reads, such that the total number of 2879 /// bases covered by the k-mer hits is h (default 35). 2880 kMerSize = "-k", 2881 /// Suppresses the use of any k-mer that occurs more than t times in 2882 /// either the subject or target block. 2883 maxKmerOccurence = "-t", 2884 /// Let the program automatically select a value of t that meets a given 2885 /// memory usage limit specified (in Gb) by the -M parameter. 2886 maxKmerMemory = "-M", 2887 /// ditto 2888 averageCorrelationRate = "-e", 2889 /// The local alignments found will be output in a sparse encoding where 2890 /// a trace point on the alignment is recorded every -s base pairs of 2891 /// the a-read (default 100bp). 2892 tracePointDistance = "-s", 2893 /// The program runs with 4 threads by default, but this may be set to 2894 /// any power of 2 with the -T option. 2895 numThreads = "-T", 2896 /// If there are one or more interval tracks specified with the -m option 2897 /// (m for mask), then the reads of the DB or DB’s to which the track 2898 /// applies are soft masked with the union of the intervals of all the 2899 /// interval tracks that apply, that is any k-mers that contain any bases 2900 /// in any of the masked intervals are ignored for the purposes of seeding 2901 /// a match. 2902 masks = "-m", 2903 /// If the -n option is given then all chains that are within the given 2904 /// fraction of the best are also reported, e.g. -n.95 reports all 2905 /// matches within 95% of the top match. 2906 bestMatches = "-n", 2907 /// The -p option requests that damapper produce a repeat profile track 2908 /// for each read. 2909 repeatProfileTrack = "-p", 2910 /// The parameter -z asks that LAs are sorted in pile order as opposed to 2911 /// map order (see the -a option of daligner for which this is the 2912 /// negation). 2913 sortPileOrder = "-z", 2914 /// If the -C option is set, then damapper also outputs a file Y.X.las 2915 /// for a given block pair that contains all the same matches as in 2916 /// X.Y.las but where the A-read is a contig of the reference and the 2917 /// B-read is a mapped read. And if the -N options is set, then the file 2918 /// Y.X.las is not produced. 2919 symmetric = "-C", 2920 /// ditto 2921 oneDirection = "-N", 2922 } 2923 2924 /// Options for `DBdump`. 2925 enum DBdumpOptions 2926 { 2927 readNumber = "-r", 2928 originalHeader = "-h", 2929 sequenceString = "-s", 2930 sNROfACGTChannels = "-a", 2931 intrinsicQualityVector = "-i", 2932 quivaValues = "-q", 2933 repeatProfileVector = "-p", 2934 masks = "-m", 2935 untrimmedDatabase = "-u", 2936 upperCase = "-U", 2937 } 2938 2939 /// Options for `DBshow`. 2940 enum DBshowOptions 2941 { 2942 untrimmedDatabase = "-u", 2943 showQuiva = "-q", 2944 showArrowPulseSequence = "-a", 2945 noSequence = "-n", 2946 masks = "-m", 2947 produceQuivaFile = "-Q", 2948 produceArrowFile = "-A", 2949 upperCase = "-U", 2950 fastaLineWidth = "-w", 2951 } 2952 2953 /// Options for `fasta2DAM` and `fasta2DB`. 2954 enum Fasta2DazzlerOptions 2955 { 2956 verbose = "-v", 2957 /// Import files listed 1/line in given file. 2958 fromFile = "-f", 2959 /// Import data from stdin, use optional name as data source. 2960 fromStdin = "-i", 2961 } 2962 2963 /// Options for `LAdump`. 2964 enum LAdumpOptions 2965 { 2966 coordinates = "-c", 2967 numDiffs = "-d", 2968 tracePoints = "-t", 2969 lengths = "-l", 2970 properOverlapsOnly = "-o", 2971 } 2972 2973 /// Options for `computeintrinsicqv`. 2974 enum ComputeIntrinsicQVOptions 2975 { 2976 /// Read depth aka. read coverage. (mandatory) 2977 readDepth = "-d", 2978 } 2979 2980 /// Options for `lasfilteralignments`. 2981 enum LasFilterAlignmentsOptions 2982 { 2983 /// Error threshold for proper alignment termination (default: 0.35) 2984 errorThresold = "-e", 2985 } 2986 2987 private 2988 { 2989 2990 void dalign(in string refDam, in string[] dalignerOpts, in string workdir) 2991 { 2992 dalign([refDam], dalignerOpts, workdir); 2993 } 2994 2995 void dalign(in string refDam, in string readsDam, in string[] dalignerOpts, in string workdir) 2996 { 2997 dalign([refDam, readsDam], dalignerOpts, workdir); 2998 } 2999 3000 void dalign(in string[] dbList, in string[] dalignerOpts, in string workdir) 3001 { 3002 assert(dbList.length >= 1); 3003 auto isSelfAlignment = dbList.length == 1; 3004 auto additionalOptions = only(isSelfAlignment ? DalignerOptions.identity : null); 3005 auto inputFiles = isSelfAlignment ? [dbList[0], dbList[0]] : dbList; 3006 const(string[]) inputFilesRelativeToWorkDir = inputFiles.map!( 3007 f => f.relativeToWorkdir(workdir)).array; 3008 3009 executeCommand(chain(only("daligner"), additionalOptions, dalignerOpts, 3010 inputFilesRelativeToWorkDir), workdir); 3011 } 3012 3013 void damapper(in string refDam, in string readsDam, in string[] damapperOpts, in string workdir) 3014 { 3015 damapper([refDam, readsDam], damapperOpts, workdir); 3016 } 3017 3018 void damapper(in string[] dbList, in string[] damapperOpts, in string workdir) 3019 { 3020 const(string[]) dbListRelativeToWorkDir = dbList.map!( 3021 f => f.relativeToWorkdir(workdir)).array; 3022 3023 executeCommand(chain(only("damapper", DamapperOptions.symmetric), 3024 damapperOpts, dbListRelativeToWorkDir), workdir); 3025 } 3026 3027 void computeIntrinsicQV(in string dbFile, in string lasFile, in size_t readDepth, 3028 in string workdir) 3029 { 3030 executeCommand(chain( 3031 only("computeintrinsicqv"), 3032 only( 3033 ComputeIntrinsicQVOptions.readDepth ~ readDepth.to!string, 3034 dbFile.stripBlock.relativeToWorkdir(workdir), 3035 lasFile.relativeToWorkdir(workdir), 3036 ), 3037 ), workdir); 3038 } 3039 3040 string lasFilterAlignments(in string dbFile, in string lasFile, in string[] options, 3041 in string workdir) 3042 { 3043 string filteredLasFile = lasFile.stripExtension.to!string ~ "-filtered.las"; 3044 3045 executeCommand(chain( 3046 only("lasfilteralignments"), 3047 options, 3048 only( 3049 filteredLasFile.relativeToWorkdir(workdir), 3050 dbFile.stripBlock.relativeToWorkdir(workdir), 3051 lasFile.relativeToWorkdir(workdir), 3052 ), 3053 ), workdir); 3054 3055 return filteredLasFile; 3056 } 3057 3058 string daccord(in string dbFile, in string lasFile, in string[] daccordOpts, in string workdir) 3059 { 3060 alias esc = escapeShellCommand; 3061 string daccordedDb = dbFile.stripExtension.to!string ~ "-daccord.dam"; 3062 3063 executeShell(chain( 3064 only("daccord"), 3065 only(esc(daccordOpts)), 3066 only(esc(lasFile.relativeToWorkdir(workdir))), 3067 only(esc(dbFile.stripBlock.relativeToWorkdir(workdir))), 3068 only("|"), 3069 only("fasta2DAM", Fasta2DazzlerOptions.fromStdin), 3070 only(esc(daccordedDb.relativeToWorkdir(workdir))), 3071 ), workdir); 3072 3073 return daccordedDb; 3074 } 3075 3076 void silentDaccord(in string dbFile, in string lasFile, in string[] daccordOpts, 3077 in string workdir) 3078 { 3079 executeCommand(chain( 3080 only("daccord"), 3081 daccordOpts, 3082 only(lasFile.relativeToWorkdir(workdir)), 3083 only(dbFile.stripBlock.relativeToWorkdir(workdir)), 3084 ), workdir); 3085 } 3086 3087 void buildSubsetDb(R)(in string inDbFile, in string outDbFile, R readIds, in string workdir) 3088 { 3089 alias esc = escapeShellCommand; 3090 auto escapedReadIds = readIds 3091 .map!(to!size_t) 3092 .map!(to!string) 3093 .map!esc; 3094 3095 executeShell(chain( 3096 only("DBshow"), 3097 only(esc(inDbFile.relativeToWorkdir(workdir))), 3098 escapedReadIds, 3099 only("|"), 3100 only("fasta2DAM", Fasta2DazzlerOptions.fromStdin), 3101 only(esc(outDbFile.relativeToWorkdir(workdir))), 3102 ), workdir); 3103 } 3104 3105 void fasta2dam(Range)(in string outFile, Range fastaRecords, in string workdir) 3106 if (isInputRange!(Unqual!Range) && isSomeString!(ElementType!(Unqual!Range))) 3107 { 3108 import std.algorithm : each, joiner; 3109 import std.process : Config, pipeProcess, Redirect, wait; 3110 import std.range : chunks; 3111 3112 enum writeChunkSize = 1024 * 1024; 3113 auto outFileArg = outFile.relativeToWorkdir(workdir); 3114 auto command = ["fasta2DAM", Fasta2DazzlerOptions.fromStdin, outFileArg]; 3115 3116 if (shouldLog(LogLevel.diagnostic)) 3117 { 3118 static if (isForwardRange!Range) 3119 auto input = fastaRecords 3120 .save 3121 .map!(record => record[0 .. min(1024, $)].toJson) 3122 .array[0 .. min(1024, $)] 3123 .toJson; 3124 else 3125 auto input = toJson(null); 3126 3127 logJsonDiagnostic( 3128 "action", "execute", 3129 "type", "pipe", 3130 "command", command.map!Json.array, 3131 "input", input, 3132 "state", "pre", 3133 ); 3134 } 3135 3136 auto process = pipeProcess( 3137 ["fasta2DAM", Fasta2DazzlerOptions.fromStdin, outFileArg], 3138 Redirect.stdin, 3139 null, // env 3140 Config.none, 3141 workdir 3142 ); 3143 fastaRecords 3144 .filter!(fastaRecord => parseFastaRecord(fastaRecord).length >= minSequenceLength) 3145 .joiner(only('\n')) 3146 .chain("\n") 3147 .chunks(writeChunkSize) 3148 .each!(chunk => process.stdin.write(chunk.array)); 3149 process.stdin.close(); 3150 auto exitStatus = wait(process.pid); 3151 if (exitStatus != 0) 3152 { 3153 throw new DazzlerCommandException( 3154 format!"command `fasta2dam` failed with exit code %d"(exitStatus)); 3155 } 3156 3157 return; 3158 } 3159 3160 void fasta2dam(in string inFile, in string outFile, in string workdir) 3161 { 3162 executeCommand(only("fasta2DAM", outFile.relativeToWorkdir(workdir), inFile), workdir); 3163 } 3164 3165 void dbsplit(in string dbFile, in string[] dbsplitOptions, in string workdir) 3166 { 3167 executeCommand(chain(only("DBsplit"), dbsplitOptions, 3168 only(dbFile.stripBlock.relativeToWorkdir(workdir))), workdir); 3169 } 3170 3171 auto ladump(in string lasFile, in string dbA, in string dbB, 3172 in string[] ladumpOpts, in string workdir) 3173 { 3174 return ladump(lasFile, dbA, dbB, [], ladumpOpts, workdir); 3175 } 3176 3177 auto ladump(in string lasFile, in string dbA, in string dbB, in id_t[] readIds, 3178 in string[] ladumpOpts, in string workdir) 3179 { 3180 return executePipe(chain( 3181 only("LAdump"), 3182 ladumpOpts, 3183 only( 3184 dbA.stripBlock.relativeToWorkdir(workdir), 3185 dbB.stripBlock.relativeToWorkdir(workdir), 3186 lasFile.relativeToWorkdir(workdir) 3187 ), 3188 readIds.map!(to!string), 3189 ), workdir); 3190 } 3191 3192 auto dbdump(Range)(in string dbFile, Range recordNumbers, 3193 in string[] dbdumpOptions, in string workdir) 3194 if (isForwardRange!Range && is(ElementType!Range : size_t)) 3195 { 3196 return executePipe(chain( 3197 only("DBdump"), 3198 dbdumpOptions, 3199 only(dbFile.relativeToWorkdir(workdir)), 3200 recordNumbers.map!(to!string) 3201 ), workdir); 3202 } 3203 3204 auto dbdump( 3205 in string dbFile, 3206 id_t firstRecord, 3207 id_t lastRecord, 3208 in string[] dbdumpOptions, 3209 in string workdir, 3210 ) 3211 { 3212 return executePipe(chain( 3213 only("DBdump"), 3214 dbdumpOptions, 3215 only( 3216 dbFile.relativeToWorkdir(workdir), 3217 format!"%d-%d"(firstRecord, lastRecord), 3218 ), 3219 ), workdir); 3220 } 3221 3222 string dbshow(in string dbFile, in string contigId) 3223 { 3224 return executeCommand(only("DBshow", dbFile, contigId)); 3225 } 3226 3227 string dbshow(in string dbFile, in string[] dbshowOptions) 3228 { 3229 return executeCommand(chain(only("DBshow"), dbshowOptions, only(dbFile))); 3230 } 3231 3232 auto executePipe(Range)(Range command, in string workdir = null) 3233 if (isInputRange!Range && isSomeString!(ElementType!Range)) 3234 { 3235 static final class LinesPipe 3236 { 3237 static enum lineTerminator = "\n"; 3238 3239 private const string[] command; 3240 private const string workdir; 3241 private ProcessPipes process; 3242 private string currentLine; 3243 3244 this(in string[] command, in string workdir) 3245 { 3246 this.command = command; 3247 this.workdir = workdir; 3248 } 3249 3250 ~this() 3251 { 3252 if (!(process.pid is null)) 3253 releaseProcess(); 3254 } 3255 3256 void releaseProcess() 3257 { 3258 if (!process.stdout.isOpen) 3259 return; 3260 3261 process.stdout.close(); 3262 3263 version (Posix) 3264 { 3265 import core.sys.posix.signal : SIGKILL; 3266 3267 process.pid.kill(SIGKILL); 3268 } 3269 else 3270 { 3271 static assert(0, "Only intended for use on POSIX compliant OS."); 3272 } 3273 process.pid.wait(); 3274 } 3275 3276 private void ensureInitialized() 3277 { 3278 if (!(process.pid is null)) 3279 return; 3280 3281 logJsonDiagnostic( 3282 "action", "execute", 3283 "type", "pipe", 3284 "command", command.toJson, 3285 "state", "pre", 3286 ); 3287 process = pipeProcess(command, Redirect.stdout, null, Config.none, workdir); 3288 3289 if (!empty) 3290 popFront(); 3291 } 3292 3293 void popFront() 3294 { 3295 ensureInitialized(); 3296 assert(!empty, "Attempting to popFront an empty LinesPipe"); 3297 currentLine = process.stdout.readln(); 3298 3299 if (currentLine.empty) 3300 { 3301 currentLine = null; 3302 releaseProcess(); 3303 } 3304 3305 if (currentLine.endsWith(lineTerminator)) 3306 currentLine = currentLine[0 .. $ - lineTerminator.length]; 3307 } 3308 3309 @property string front() 3310 { 3311 ensureInitialized(); 3312 assert(!empty, "Attempting to fetch the front of an empty LinesPipe"); 3313 3314 return currentLine; 3315 } 3316 3317 @property bool empty() 3318 { 3319 ensureInitialized(); 3320 3321 if (!process.stdout.isOpen || process.stdout.eof) 3322 { 3323 releaseProcess(); 3324 3325 return true; 3326 } 3327 else 3328 { 3329 return false; 3330 } 3331 } 3332 } 3333 3334 auto sanitizedCommand = command.filter!"a != null".array; 3335 3336 return new LinesPipe(sanitizedCommand, workdir); 3337 } 3338 3339 unittest 3340 { 3341 import std.algorithm : equal; 3342 import std.range : take; 3343 3344 auto cheers = executePipe(only("yes", "Cheers!"), "."); 3345 assert(cheers.take(5).equal([ 3346 "Cheers!", 3347 "Cheers!", 3348 "Cheers!", 3349 "Cheers!", 3350 "Cheers!", 3351 ])); 3352 3353 auto helloWorld = executePipe(only("echo", "Hello World!"), "."); 3354 assert(helloWorld.equal(["Hello World!"])); 3355 } 3356 3357 string executeCommand(Range)(in Range command, in string workdir = null) 3358 if (isInputRange!(Unqual!Range) && isSomeString!(ElementType!(Unqual!Range))) 3359 { 3360 import std.process : Config, execute; 3361 3362 string output = command.executeWrapper!("command", 3363 sCmd => execute(sCmd, null, // env 3364 Config.none, size_t.max, workdir)); 3365 return output; 3366 } 3367 3368 void executeShell(Range)(in Range command, in string workdir = null) 3369 if (isInputRange!(Unqual!Range) && isSomeString!(ElementType!(Unqual!Range))) 3370 { 3371 import std.algorithm : joiner; 3372 import std.process : Config, executeShell; 3373 3374 string output = command.executeWrapper!("shell", 3375 sCmd => executeShell(sCmd.joiner(" ").array.to!string, null, // env 3376 Config.none, size_t.max, workdir)); 3377 } 3378 3379 void executeScript(Range)(in Range command, in string workdir = null) 3380 if (isInputRange!(Unqual!Range) && isSomeString!(ElementType!(Unqual!Range))) 3381 { 3382 import std.process : Config, executeShell; 3383 3384 string output = command.executeWrapper!("script", 3385 sCmd => executeShell(sCmd.buildScriptLine, null, // env 3386 Config.none, size_t.max, workdir)); 3387 } 3388 3389 string executeWrapper(string type, alias execCall, Range)(in Range command) 3390 if (isInputRange!(Unqual!Range) && isSomeString!(ElementType!(Unqual!Range))) 3391 { 3392 import std.array : array; 3393 import std.algorithm : filter; 3394 import std..string : lineSplitter; 3395 3396 auto sanitizedCommand = command.filter!"a != null".array; 3397 3398 logJsonDiagnostic( 3399 "action", "execute", 3400 "type", type, 3401 "command", sanitizedCommand.map!Json.array, 3402 "state", "pre", 3403 ); 3404 auto result = execCall(sanitizedCommand); 3405 logJsonDiagnostic( 3406 "action", "execute", 3407 "type", type, 3408 "command", sanitizedCommand.map!Json.array, 3409 "output", result 3410 .output[0 .. min(1024, $)] 3411 .lineSplitter 3412 .map!Json 3413 .array, 3414 "exitStatus", result.status, 3415 "state", "post", 3416 ); 3417 if (result.status > 0) 3418 { 3419 throw new DazzlerCommandException( 3420 format("process %s returned with non-zero exit code %d: %s", 3421 sanitizedCommand[0], result.status, result.output)); 3422 } 3423 3424 return result.output; 3425 } 3426 3427 string buildScriptLine(in string[] command) 3428 { 3429 return escapeShellCommand(command) ~ " | sh -sve"; 3430 } 3431 3432 string stripBlock(in string fileName) 3433 { 3434 import std.regex : ctRegex, replaceFirst; 3435 3436 enum blockNumRegex = ctRegex!(`\.[1-9][0-9]*\.(dam|db)$`); 3437 3438 return fileName.replaceFirst(blockNumRegex, `.$1`); 3439 } 3440 3441 unittest 3442 { 3443 assert("foo_bar.1.dam".stripBlock == "foo_bar.dam"); 3444 assert("foo_bar.1024.db".stripBlock == "foo_bar.db"); 3445 assert("foo_bar.dam".stripBlock == "foo_bar.dam"); 3446 assert("foo_bar.db".stripBlock == "foo_bar.db"); 3447 } 3448 3449 string relativeToWorkdir(in string fileName, in string workdir) 3450 { 3451 return relativePath(absolutePath(fileName), absolutePath(workdir)); 3452 } 3453 }