ngmlr-0.2.7+git20210816.a2a31fb/000077500000000000000000000000001410636150300153575ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/.gitignore000066400000000000000000000002361410636150300173500ustar00rootroot00000000000000/bin /build /.settings .project .cproject /ngm-0.4.4 /.kdev4 .pydevproject lib/libgff /docs/ .DS_Store /cibiv.sh /cshl.sh /Release/ /build-linux/ test_env.sh ngmlr-0.2.7+git20210816.a2a31fb/.travis.yml000066400000000000000000000005051410636150300174700ustar00rootroot00000000000000language: cpp sudo: false dist: trusty cache: apt: true addons: apt: packages: - vim - bedtools - samtools compiler: g++ before_script: - mkdir build - cd build - cmake .. script: - make && cd .. # - bin/ngmlr*/ngmlr -h - test/test_travis.sh ngmlr-0.2.7+git20210816.a2a31fb/.vscode/000077500000000000000000000000001410636150300167205ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/.vscode/.gitignore000066400000000000000000000000271410636150300207070ustar00rootroot00000000000000/c_cpp_properties.json ngmlr-0.2.7+git20210816.a2a31fb/CMakeLists.txt000066400000000000000000000025301410636150300201170ustar00rootroot00000000000000 cmake_minimum_required(VERSION 2.8) project(ngmlr) include(CheckCXXCompilerFlag) option(STATIC "Build static binary" OFF) set( NGM_VERSION_MAJOR 0 ) set( NGM_VERSION_MINOR 2 ) IF(CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS "Building in debug mode!") set( NGM_VERSION_BUILD 8-debug ) else() set( NGM_VERSION_BUILD 8 ) ENDIF() find_package( ZLIB REQUIRED ) find_package ( Threads REQUIRED ) CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) if(COMPILER_SUPPORTS_CXX11) IF(NOT APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") ELSE() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++") ENDIF() else() message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") endif() set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/ngmlr-${NGM_VERSION_MAJOR}.${NGM_VERSION_MINOR}.${NGM_VERSION_BUILD}/) file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) # Set a default build type for single-configuration # CMake generators if no build type is set. # RELEASE, RELWITHDEBINFO, DEBUG IF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) message(STATUS "No build type specified. Using 'RELWITHDEBINFO'") SET(CMAKE_BUILD_TYPE RELWITHDEBINFO) ENDIF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) add_subdirectory(src)ngmlr-0.2.7+git20210816.a2a31fb/LICENSE000066400000000000000000000020751410636150300163700ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2017 Philipp Rescheneder Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.ngmlr-0.2.7+git20210816.a2a31fb/README.md000066400000000000000000000174711410636150300166500ustar00rootroot00000000000000### Quick start Download [binary](https://github.com/philres/ngmlr/releases/tag/v0.2.6) from github and unzip or [![install with bioconda](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?style=flat-square)](http://bioconda.github.io/recipes/ngmlr/README.html) or pull docker [![Docker Automated buil](https://img.shields.io/docker/automated/jrottenberg/ffmpeg.svg)](https://hub.docker.com/r/philres/ngmlr/). For updates follow [![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social&style=plastic)](https://twitter.com/philres1) Download precompiled version: ```bash wget https://github.com/philres/ngmlr/releases/download/v0.2.7/ngmlr-0.2.7-linux-x86_64.tar.gz tar xvzf ngmlr-0.2.7-linux-x86_64.tar.gz cd ngmlr-0.2.7/ ``` For PacBio data run: ```bash ngmlr -t 4 -r reference.fasta -q reads.fastq -o test.sam ``` For Oxford Nanopore run: ```bash ngmlr -t 4 -r reference.fasta -q reads.fastq -o test.sam -x ont ``` ### Introduction CoNvex Gap-cost alignMents for Long Reads (ngmlr) is a long-read mapper designed to sensitively align PacBio or Oxford Nanopore to (large) reference genomes. It was designed to quickly and correctly align the reads, including those spanning (complex) structural variations. Ngmlr uses an SV aware k-mer search to find approximate mapping locations for a read and then a banded Smith-Waterman alignment algorithm to compute the final alignment. Ngmlr uses a convex gap cost model that penalizes gap extensions for longer gaps less than for shorter ones to compute precise alignments. The gap model allows ngmlr to account for both the sequencing error and real genomic variations at the same time and makes it especially effective at more precisely identifying the position of breakpoints stemming from structural variations. The k-mer search helps to detect and split reads that cannot be aligned linearly, enabling ngmlr to reliably align reads to a wide range of different structural variations including nested SVs (e.g. inversions flanked by deletions). With 10 cores (AMD Opteron 6348), ngmlr currently takes about 90 minutes and 10 GB RAM for aligning 3Gbp (~ 1x human data) of PacBio reads. ### Citation: Please see and cite our paper: https://www.nature.com/articles/s41592-018-0001-7 **Poster & Talks:** [Accurate and fast detection of complex and nested structural variations using long read technologies](http://schatzlab.cshl.edu/presentations/2016/2016.10.28.BIODATA.PacBioSV.pdf)
Biological Data Science, Cold Spring Harbor Laboratory, Cold Spring Harbor, NY, 26 - 29.10.2016 [NGMLR: Highly accurate read mapping of third generation sequencing reads for improved structural variation analysis](http://www.cibiv.at/~philipp_/files/gi2016_poster_phr.pdf)
Genome Informatics 2016, Wellcome Genome Campus Conference Centre, Hinxton, Cambridge, UK, 19.09.-2.09.2016 ### Parameters ``` Usage: ngmlr [options] -r -q [-o ] Input/Output: -r , --reference (required) Path to the reference genome (FASTA/Q, can be gzipped) -q , --query Path to the read file (FASTA/Q) [/dev/stdin] -o , --output Path to output file [stdout] --skip-write Don't write reference index to disk [false] --bam-fix Report reads with > 64k CIGAR operations as unmapped. Required to be compatible with the BAM format [false] --rg-id Adds RG:Z: to all alignments in SAM/BAM [none] --rg-sm RG header: Sample [none] --rg-lb RG header: Library [none] --rg-pl RG header: Platform [none] --rg-ds RG header: Description [none] --rg-dt RG header: Date (format: YYYY-MM-DD) [none] --rg-pu RG header: Platform unit [none] --rg-pi RG header: Median insert size [none] --rg-pg RG header: Programs [none] --rg-cn RG header: sequencing center [none] --rg-fo RG header: Flow order [none] --rg-ks RG header: Key sequence [none] General: -t , --threads Number of threads [1] -x , --presets Parameter presets for different sequencing technologies [pacbio] -i <0-1>, --min-identity <0-1> Alignments with an identity lower than this threshold will be discarded [0.65] -R , --min-residues Alignments containing less than or ( * read length) residues will be discarded [0.25] --no-smallinv Don't detect small inversions [false] --no-lowqualitysplit Split alignments with poor quality [false] --verbose Debug output [false] --no-progress Don't print progress info while mapping [false] Advanced: --match Match score [2] --mismatch Mismatch score [-5] --gap-open Gap open score [-5] --gap-extend-max Gap open extend max [-5] --gap-extend-min Gap open extend min [-1] --gap-decay Gap extend decay [0.15] -k <10-15>, --kmer-length <10-15> K-mer length in bases [13] --kmer-skip Number of k-mers to skip when building the lookup table from the reference [2] --bin-size Sets the size of the grid used during candidate search [4] --max-segments Max number of segments allowed for a read per kb [1] --subread-length Length of fragments reads are split into [256] --subread-corridor Length of corridor sub-reads are aligned with [40] ``` ### Running with docker ```bash docker run -ti -v /home/user/data/:/home/user/data/ philres/ngmlr ngmlr -r /home/user/data/ref.fa -q /home/user/data/reads.fasta -o /home/user/data/output.sam ``` ### Building ngmlr from source OS: Linux and Mac OSX: Requirements: zlib-dev, cmake, gcc/g++ (>=4.8.2) ```bash git clone https://github.com/philres/ngmlr.git cd ngmlr/ mkdir -p build cd build/ cmake .. make cd ../bin/ngmlr-*/ ./ngmlr ``` ### Building ngmlr for linux with docker ```bash git clone https://github.com/philres/ngmlr.git mkdir -p ngmlr/build docker run -v `pwd`/ngmlr:/ngmlr philres/nextgenmaplr-buildenv bash -c "cd /ngmlr/build && cmake .. && make" `pwd`/ngmlr/bin/ngmlr-*/ngmlr ``` ### NGMLR progress information Example: ``` Processed: 92198 (0.66), R/S: 37.44, RL: 8857, Time: 2.00 5.00 11.62, Align: 0.96, 490, 0.81 ``` 92198 reads were processed so far 66 % of the 92198 reads were mapped (with > 25 % of their bp mapped) 37.44 are mapped on average per second 8857 is the average read length so far "Time" and "Align" are for debugging purpose and will be removed. ### Datasets used in the mansucript: We provide the NGMLR aligned reads and the Sniffles calls for the data sets used: Arabidopsis trio: [http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/Arabidopsis_trio](http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/Arabidopsis_trio) . Genome in a Bottle trio: + Mappings: [ftp://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/data/AshkenazimTrio/HG002_NA24385_son/PacBio_MtSinai_NIST/Baylor_NGMLR_bam_GRCh37/](ftp://ftp-trace.ncbi.nlm.nih.gov/giab/ftp/data/AshkenazimTrio/HG002_NA24385_son/PacBio_MtSinai_NIST/Baylor_NGMLR_bam_GRCh37/) . + SV calls: [http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/GiaB/](http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/GiaB/) NA12878: [http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/NA12878/](http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/NA12878/) . SKBR3: [http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/Skbr3/](http://labshare.cshl.edu/shares/schatzlab/www-data/fsedlaze/Sniffles/Skbr3/) . ngmlr-0.2.7+git20210816.a2a31fb/docker/000077500000000000000000000000001410636150300166265ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/docker/build-env/000077500000000000000000000000001410636150300205135ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/docker/build-env/Dockerfile000066400000000000000000000006741410636150300225140ustar00rootroot00000000000000FROM ubuntu MAINTAINER Philipp Rescheneder ENV NEXTGENMAP_LR_BUILD_ENV 1.0.2 #ENV SLAMDUNK_DOWNLOAD_URL https://github.com/t-neumann/slamdunk.git # binutils is required to run opencl programs RUN buildDeps='git wget gcc g++ libc6-dev make cmake zlib1g-dev gdb samtools bedtools vim gcc-4.8 g++-4.8' \ && set -x \ && apt-get update && apt-get install -y $buildDeps $runDeps --no-install-recommends ngmlr-0.2.7+git20210816.a2a31fb/docker/ngmlr/000077500000000000000000000000001410636150300177455ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/docker/ngmlr/Dockerfile000066400000000000000000000012131410636150300217340ustar00rootroot00000000000000FROM alpine:3.3 MAINTAINER Philipp Rescheneder ARG VERSION_ARG # Get most recent ngmlr version from github RUN apk --update upgrade && \ apk add build-base gcc abuild binutils binutils-doc gcc-doc zlib-dev git cmake curl ca-certificates && \ update-ca-certificates && \ git clone https://github.com/philres/ngmlr.git && cd ngmlr && git checkout $VERSION_ARG && mkdir -p build && cd build && cmake .. && make && cp ../bin/ngmlr-*/ngmlr /bin/ && cd .. && rm -rf ngmlr && \ apk del build-base abuild binutils binutils-doc gcc-doc zlib-dev git cmake curl ca-certificates && \ rm -rf /var/cache/apk/* ngmlr-0.2.7+git20210816.a2a31fb/docker/ngmlr/hooks/000077500000000000000000000000001410636150300210705ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/docker/ngmlr/hooks/build000066400000000000000000000011651410636150300221150ustar00rootroot00000000000000#!/usr/bin/env sh if [ "$DOCKER_TAG" = "latest" ]; then echo "Building :latest, without VERSION_ARG" TAG=`curl -s https://api.github.com/repos/philres/ngmlr/releases | grep tag_name | head -n 1 | cut -d '"' -f 4` echo $TAG docker build --build-arg VERSION_ARG="$TAG" -t ${IMAGE_NAME} . else echo "Building :$DOCKER_TAG, with VERSION_ARG=\"--vers $DOCKER_TAG\"" docker build --build-arg VERSION_ARG="$DOCKER_TAG" -t ${IMAGE_NAME} . fi # if [ "$DOCKER_TAG" = "master" ]; then # echo "Building :$DOCKER_TAG, from git" # docker build --build-arg VERSION_ARG="" -f Dockerfile.git -t ${IMAGE_NAME} . # else # fingmlr-0.2.7+git20210816.a2a31fb/lib/000077500000000000000000000000001410636150300161255ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/lib/intervaltree/000077500000000000000000000000001410636150300206315ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/lib/intervaltree/IntervalTree.h000066400000000000000000000113771410636150300234170ustar00rootroot00000000000000#ifndef __INTERVAL_TREE_H #define __INTERVAL_TREE_H #include #include #include namespace IntervalTree { template class Interval { public: K start; K stop; T value; Interval(K s, K e, const T& v) : start(s), stop(e), value(v) { } }; template int intervalStart(const Interval& i) { return i.start; } template int intervalStop(const Interval& i) { return i.stop; } template std::ostream& operator<<(std::ostream& out, Interval& i) { out << "Interval(" << i.start << ", " << i.stop << "): " << i.value; return out; } template class IntervalStartSorter { public: bool operator()(const Interval& a, const Interval& b) { return a.start < b.start; } }; template class IntervalTree { public: typedef Interval interval; typedef std::vector intervalVector; typedef IntervalTree intervalTree; intervalVector intervals; intervalTree* left; intervalTree* right; int center; IntervalTree(void) : left(NULL), right(NULL), center(0) { } IntervalTree(const intervalTree& other) : left(NULL), right(NULL) { center = other.center; intervals = other.intervals; if (other.left) { left = new intervalTree(*other.left); } if (other.right) { right = new intervalTree(*other.right); } } IntervalTree& operator=(const intervalTree& other) { center = other.center; intervals = other.intervals; if (other.left) { left = new intervalTree(*other.left); } else { if (left) delete left; left = NULL; } if (other.right) { right = new intervalTree(*other.right); } else { if (right) delete right; right = NULL; } return *this; } IntervalTree(intervalVector& ivals, unsigned int depth = 16, unsigned int minbucket = 64, int leftextent = 0, int rightextent = 0, unsigned int maxbucket = 512) : left(NULL), right(NULL) { --depth; IntervalStartSorter intervalStartSorter; if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) { std::sort(ivals.begin(), ivals.end(), intervalStartSorter); intervals = ivals; } else { if (leftextent == 0 && rightextent == 0) { // sort intervals by start std::sort(ivals.begin(), ivals.end(), intervalStartSorter); } int leftp = 0; int rightp = 0; int centerp = 0; if (leftextent || rightextent) { leftp = leftextent; rightp = rightextent; } else { leftp = ivals.front().start; std::vector stops; stops.resize(ivals.size()); transform(ivals.begin(), ivals.end(), stops.begin(), intervalStop); rightp = *max_element(stops.begin(), stops.end()); } //centerp = ( leftp + rightp ) / 2; centerp = ivals.at(ivals.size() / 2).start; center = centerp; intervalVector lefts; intervalVector rights; for (typename intervalVector::iterator i = ivals.begin(); i != ivals.end(); ++i) { interval& interval = *i; if (interval.stop < center) { lefts.push_back(interval); } else if (interval.start > center) { rights.push_back(interval); } else { intervals.push_back(interval); } } if (!lefts.empty()) { left = new intervalTree(lefts, depth, minbucket, leftp, centerp); } if (!rights.empty()) { right = new intervalTree(rights, depth, minbucket, centerp, rightp); } } } void findOverlapping(K start, K stop, intervalVector& overlapping) const { if (!intervals.empty() && !(stop < intervals.front().start)) { for (typename intervalVector::const_iterator i = intervals.begin(); i != intervals.end(); ++i) { const interval& interval = *i; if (interval.stop >= start && interval.start <= stop) { overlapping.push_back(interval); } } } if (left && start <= center) { left->findOverlapping(start, stop, overlapping); } if (right && stop >= center) { right->findOverlapping(start, stop, overlapping); } } void findContained(K start, K stop, intervalVector& contained) const { if (!intervals.empty() && !(stop < intervals.front().start)) { for (typename intervalVector::const_iterator i = intervals.begin(); i != intervals.end(); ++i) { const interval& interval = *i; if (interval.start >= start && interval.stop <= stop) { contained.push_back(interval); } } } if (left && start <= center) { left->findContained(start, stop, contained); } if (right && stop >= center) { right->findContained(start, stop, contained); } } ~IntervalTree(void) { // traverse the left and right // delete them all the way down if (left) { delete left; } if (right) { delete right; } } }; } #endif ngmlr-0.2.7+git20210816.a2a31fb/lib/intervaltree/LICENSE000066400000000000000000000020411410636150300216330ustar00rootroot00000000000000Copyright (c) 2011 Erik Garrison Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ngmlr-0.2.7+git20210816.a2a31fb/lib/intervaltree/README000066400000000000000000000022701410636150300215120ustar00rootroot00000000000000Overview: An interval tree can be used to efficiently find a set of numeric intervals overlapping or containing another interval. This library provides a basic implementation of an interval tree using C++ templates, allowing the insertion of arbitrary types into the tree. Usage: Add #include "IntervalTree.h" to the source files in which you will use the interval tree. To make an IntervalTree to contain objects of class T, use: vector > intervals; T a, b, c; intervals.push_back(Interval(2, 10, a)); intervals.push_back(Interval(3, 4, b)); intervals.push_back(Interval(20, 100, c)); IntervalTree tree; tree = IntervalTree(intervals); Now, it's possible to query the tree and obtain a set of intervals which are contained within the start and stop coordinates. vector > results; tree.findContained(start, stop, results); cout << "found " << results.size() << " overlapping intervals" << endl; The function IntervalTree::findOverlapping provides a method to find all those intervals which are contained or partially overlap the interval (start, stop). Author: Erik Garrison License: MIT ngmlr-0.2.7+git20210816.a2a31fb/src/000077500000000000000000000000001410636150300161465ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/src/.gitignore000066400000000000000000000000221410636150300201300ustar00rootroot00000000000000/ReadProvider.cpp ngmlr-0.2.7+git20210816.a2a31fb/src/AlignmentBuffer.cpp000066400000000000000000003530521410636150300217320ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "AlignmentBuffer.h" #include #include #include #include #include //Eclipse #include #include "Timing.h" #include "SequenceProvider.h" #include "StrippedSW.h" #include "OutputReadBuffer.h" //#include "MemCheck.h" using std::vector; bool AlignmentBuffer::first = true; void AlignmentBuffer::debugAlgnFinished(MappedRead * read) { Log.Debug(32, "READ_%d\tALGN\tAll alignments computed (%d)", read->ReadId, read->numScores()); if(read->numScores() > 0) { for(int i = 0; i < read->numScores(); ++i) { LocationScore score = read->Scores[i]; Align align = read->Alignments[i]; SequenceLocation loc = score.Location; SequenceProvider.convert(loc); int refNameLength = 0; //TODO_GENOMESIZE: Re-enable me //Log.Debug(128, "READ_%d\tALGN_RESULTS\tCMR_%d\t%f\t%f\t%d\t%s\t%s\t%d\t%s", read->ReadId, i, score.Score.f, align.Identity, align.NM, align.pBuffer1, align.pBuffer2, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength)); } } #ifdef _DEBUGCMRS SequenceLocation rloc = SequenceProvider.convert(cur_read, cur_read->Scores[scoreId].Location.m_Location); int refNameLength = 0; fprintf(cmrBed, "%s\t%d\t%d\t%s_%d\t%f\t%c\n", SequenceProvider.GetRefName(rloc.getrefId(), refNameLength), rloc.m_Location - (corridor >> 1), rloc.m_Location - (corridor >> 1) + refMaxLen, cur_read->name, scoreId, cur_read->Scores[scoreId].Score.f, (rloc.isReverse()) ? '-' : '+'); #endif } CorridorLine * getCorridorOriginal(int const corridor, char const * readSeq, int & corridorHeight) { int const corridorWidth = corridor; int const qryLen = strlen(readSeq); corridorHeight = qryLen; CorridorLine * corridorLines = new CorridorLine[corridorHeight]; NGM.Stats->corridorLen += corridorWidth; for (int i = 0; i < corridorHeight; ++i) { corridorLines[i].offset = i; // - corridorWidth / 2; corridorLines[i].length = corridorWidth; } return corridorLines; } CorridorLine * getCorridorLinear(int const corridor, char const * readSeq, int & corridorHeight) { int const corridorWidth = corridor; int const qryLen = strlen(readSeq); corridorHeight = qryLen; CorridorLine * corridorLines = new CorridorLine[corridorHeight]; NGM.Stats->corridorLen += corridorWidth; for (int i = 0; i < corridorHeight; ++i) { corridorLines[i].offset = i - corridorWidth / 2; corridorLines[i].length = corridorWidth; } return corridorLines; } CorridorLine * getCorridorFull(int const corridor, char const * readSeq, int & corridorHeight) { int const corridorWidth = corridor; int const qryLen = strlen(readSeq); corridorHeight = qryLen; CorridorLine * corridorLines = new CorridorLine[corridorHeight]; NGM.Stats->corridorLen += corridorWidth; for (int i = 0; i < corridorHeight; ++i) { /** * 20% corridor width added on both sides for * ConvexAlign "out of corridor" detection * (Checks if backtracking path goes into * the left/right most 10% of the corridor) * TODO: fix in ConvexAlign.cpp */ corridorLines[i].offset = (int)(corridorWidth * -0.2); corridorLines[i].length = corridorWidth + (int)(corridorWidth * 0.2); } return corridorLines; } CorridorLine * getCorridorEndpoints(Interval const * interval, int const corridor, char const * refSeq, char const * readSeq, int & corridorHeight, bool const realign) { int corridorWidth = corridor / (realign ? 1 : 4); int const qryLen = strlen(readSeq); int const refLen = strlen(refSeq); corridorHeight = qryLen; CorridorLine * corridorLines = new CorridorLine[corridorHeight]; float k = qryLen * 1.0f / refLen; float d = corridorWidth / 2.0f; NGM.Stats->corridorLen += corridorWidth; for (int i = 0; i < corridorHeight; ++i) { corridorLines[i].offset = (i - d) / k; corridorLines[i].length = corridorWidth; } return corridorLines; } CorridorLine * AlignmentBuffer::getCorridorEndpointsWithAnchors(Interval const * interval, int const corridorMultiplier, char const * refSeq, char const * readSeq, int & corridorHeight, int const externalQStart, int const readPartLength, int const fullReadLength, bool const realign) { int const qryLen = strlen(readSeq); int const refLen = strlen(refSeq); /* * Find optimal corridor */ float corridorLeft = 0.0f; float corridorRight = 0.0f; float k_align = qryLen * 1.0f / refLen; float d_align = 0; for (int i = 0; i < interval->anchorLength; ++i) { int anchor_x = 0; int anchor_y = 0; if (interval->anchors[i].isReverse) { anchor_x = interval->anchors[i].onRef - interval->onRefStart; anchor_y = fullReadLength - interval->anchors[i].onRead - (readPartLength) - externalQStart; } else { anchor_x = interval->anchors[i].onRef - interval->onRefStart; anchor_y = interval->anchors[i].onRead - externalQStart; } // Log.Message("Anchor %d: %d, %d", i, anchor_x, anchor_y); float x_found = anchor_x; float x_expect = (anchor_y - d_align) / k_align; // Log.Message("x_found: %f - x_expect: %f", x_found, x_expect); float diff = x_expect - x_found; if (diff > 0) { corridorRight = std::max(corridorRight, diff); } else { corridorLeft = std::max(corridorLeft, diff * -1.0f); } // Log.Message("%f - %f", corridorLeft, corridorRight); } corridorHeight = qryLen; CorridorLine * corridorLines = new CorridorLine[corridorHeight]; corridorLeft += 128; corridorRight += 128; corridorLeft = corridorLeft + (corridorLeft + corridorRight) * 0.1f; corridorRight = corridorRight + (corridorLeft + corridorRight) * 0.1f; corridorLeft = corridorLeft * corridorMultiplier; corridorRight = corridorRight * corridorMultiplier; int corridorWidth = corridorLeft + corridorRight; NGM.Stats->corridorLen += corridorWidth; for (int i = 0; i < corridorHeight; ++i) { corridorLines[i].offset = ((i - d_align) / k_align) - corridorRight; corridorLines[i].length = corridorWidth; } verbose(0, true, "Corridor length estimated from anchors is: %d", corridorWidth); return corridorLines; } char const * const AlignmentBuffer::extractReferenceSequenceForAlignment(Interval const*& interval, int & refSeqLength) { return extractReferenceSequenceForAlignment(interval->onRefStart, interval->onRefStop, refSeqLength); } char const * const AlignmentBuffer::extractReferenceSequenceForAlignment(loc const onRefStart, loc const onRefStop, int & refSeqLength) { char * refSeq = 0; if(onRefStart >= onRefStop) { Log.Message("Could not decode reference for alignment: %llu >= %llu.", onRefStart, onRefStop); return 0; } refSeqLength = onRefStop - onRefStart + 1; if (refSeqLength > 0) { //TODO: check why decoded/SequenceProvider writes outside of refSeqLen: This makes + 100 necessary refSeq = new char[refSeqLength + 100]; //decode reference refSeqLength verbose(0, true, "RefStart: %llu, RefLength: %d", onRefStart, refSeqLength); if (!SequenceProvider.DecodeRefSequenceExact(refSeq, onRefStart, refSeqLength, 0)) { //Log.Warning("Could not decode reference for alignment (read: %s): %llu, %d", cur_read->Scores[scoreID].Location.m_Location - (corridor >> 1), cur_read->length + corridor, cur_read->name); Log.Warning("Could not decode reference for alignment"); delete[] refSeq; refSeq = 0; } } return refSeq; } Align * AlignmentBuffer::computeAlignment(Interval const * interval, int corridor, char const * const readSeq, size_t const readLength, int const externalQStart, int const externalQEnd, int fullReadLength, MappedRead const * const read, bool realign, bool const fullAlignment, bool const shortRead = false) { if (pacbioDebug) { Log.Message("Read name: %s", read->name); Log.Message("Alignment type: realign %d, full %d, shortRead %d", realign, fullAlignment, shortRead); } if(readSeq == nullptr) { return 0; } static int alignmentId = 0; bool validAlignment = false; Align * align = new Align(); try { #ifdef TEST_ALIGNER Align * alignFast = new Align(); #endif int refSeqLen = 0; char const * refSeq = extractReferenceSequenceForAlignment(interval, refSeqLen); int alignedBp = 0; if (refSeq != 0) { int retryCount = 5; if (fullAlignment) { retryCount = 1; } // Corridor > refSeqLen * 2 doesn't make sense -> full matrix is computed already int const maxCorridorSize = refSeqLen * 2; corridor = std::min(corridor, maxCorridorSize); int const minAlignedBp = 0.05f * std::min((int) readLength, refSeqLen); //initialize arrays for CIGAR and MD string align->maxBufferLength = readLength * 4; align->maxMdBufferLength = readLength * 4; align->pBuffer1 = new char[align->maxBufferLength]; align->pBuffer2 = new char[align->maxMdBufferLength]; align->pBuffer1[0] = '\0'; align->pBuffer2[0] = '\0'; align->nmPerPostionLength = (readLength + 1) * 2; align->nmPerPosition = new PositionNM[align->nmPerPostionLength]; #ifdef TEST_ALIGNER alignFast->pBuffer1 = new char[readLength * 4]; alignFast->pBuffer2 = new char[readLength * 4]; alignFast->pBuffer1[0] = '\0'; alignFast->pBuffer2[0] = '\0'; alignFast->nmPerPostionLength = (readLength + 1) * 2; alignFast->nmPerPosition = new PositionNM[alignFast->nmPerPostionLength]; #endif int corridorMultiplier = 1; while (!validAlignment && (corridor * corridorMultiplier) <= maxCorridorSize && retryCount-- > 0) { //Local alignment if (pacbioDebug) { Log.Message("Aligning %d bp to %d bp", readLength, refSeqLen); Log.Message("Ref: %.*s ... %.*s", 250, refSeq, 250, refSeq + refSeqLen - 250); Log.Message("Read: %.*s ... %.*s", 250, readSeq, 250, readSeq - readLength - 250); } int corridorHeight = 0; // CorridorLine * corridorLines = getCorridorLinear(corridor, readSeq, // corridorHeight); // When realigning currently there are no anchors available -> larger corridor //TODO: Use anchors from original interval, or extract anchors from first alignment! CorridorLine * corridorLines = 0; if(fullAlignment) { corridorLines = getCorridorFull(refSeqLen, readSeq, corridorHeight); } else { if(shortRead) { verbose(0, true, "Corridor width: %d", corridor * corridorMultiplier); corridorLines = getCorridorLinear(corridor * corridorMultiplier, readSeq, corridorHeight); } else { if(corridorMultiplier < 3 && !realign && interval->anchorLength > 0) { corridorLines = getCorridorEndpointsWithAnchors(interval, corridorMultiplier, refSeq, readSeq, corridorHeight, externalQStart, readPartLength, fullReadLength, realign); } else { verbose(0, true, "Corridor width: %d", corridor * corridorMultiplier); corridorLines = getCorridorEndpoints(interval, corridor * corridorMultiplier, refSeq, readSeq, corridorHeight, realign); } } } Timer algnTimer; algnTimer.ST(); if (stdoutPrintAlignCorridor) { for(int x = 0; x < interval->anchorLength; ++x) { if(interval->anchors[x].isReverse) { printf("%d\t%d\t%lld\t%d\t%d\n", alignmentId, read->ReadId, interval->anchors[x].onRef - interval->onRefStart, fullReadLength - interval->anchors[x].onRead - (readPartLength) - externalQStart, 3); } else { printf("%d\t%d\t%lld\t%d\t%d\n", alignmentId, read->ReadId, interval->anchors[x].onRef - interval->onRefStart, interval->anchors[x].onRead - externalQStart, 3); } } printf("%d\t%d\t%d\t%s\t%d\n", alignmentId, read->ReadId, read->ReadId, read->name, -4); printf("%d\t%d\t%d\t%d\t%d\n", alignmentId, read->ReadId, interval->isReverse, corridorLines[0].length, -5); printf("%d\t%d\t%d\t%d\t%d\n", alignmentId, read->ReadId, externalQStart, externalQEnd, -6); } if(pacbioDebug) { int cellCount = 0; for(int i = 0; i < corridorHeight; ++i) { cellCount += corridorLines[i].length; } Log.Message("Computing %d cells of alignment Matrix", cellCount); } //Hack to pass readId to convex alignment class for plotting //TODO: remove align->svType = read->ReadId; #ifdef TEST_ALIGNER alignFast->svType = read->ReadId; #endif #ifdef TEST_ALIGNER Timer tmr1; tmr1.ST(); #endif if(pacbioDebug) { Log.Message("ExternalQstart: %d, ExternalQEnd: %d", externalQStart, externalQEnd); } int cigarLength = aligner->SingleAlign(alignmentId, corridorLines, corridorHeight, (char const * const ) refSeq, (char const * const ) readSeq, *align, externalQStart, externalQEnd, 0); // cigarLength = -1; #ifdef TEST_ALIGNER float time1 = tmr1.ET(); Timer tmr2; tmr2.ST(); int const cigarLengthFast = alignerFast->SingleAlign(alignmentId, corridorLines, corridorHeight, (char const * const ) refSeq, (char const * const ) readSeq, *alignFast, externalQStart, externalQEnd, 0); float time2 = tmr2.ET(); Log.Message("%d/%d bp: %f - %f", strlen(refSeq), strlen(readSeq), time1, time2); if(!(cigarLengthFast == cigarLength && alignFast->Score == align->Score && strcmp(align->pBuffer1, alignFast->pBuffer1) == 0 && strcmp(align->pBuffer2, alignFast->pBuffer2) == 0)) { Log.Message("Ref: %s", refSeq); Log.Message("Read: %s", readSeq); Log.Message("Convex: %d %f %s", cigarLength, align->Score, align->pBuffer1); Log.Message("ConvexFast: %d %f %s", cigarLengthFast, alignFast->Score, alignFast->pBuffer1); Log.Error("Not equal"); } #endif alignmentId += 1; if (pacbioDebug) { Log.Message("Aligning took %f seconds", algnTimer.ET()); Log.Message("CIGAR: %.*s", 250, align->pBuffer1); Log.Message("MD: %.*s", 250, align->pBuffer2); } delete[] corridorLines; corridorLines = 0; alignedBp = readLength - (align->QStart - externalQStart) - (align->QEnd - externalQEnd); validAlignment = cigarLength == fullReadLength; // && alignedBp > minAlignedBp; if(!validAlignment) { //corridor = corridor * 2; corridorMultiplier += 1; if (pacbioDebug) { Log.Message("Invalid alignment found. Running again with corridor %d, %d attempts left", corridor * corridorMultiplier, retryCount); } NGM.Stats->invalidAligmentCount += 1; } } delete[] refSeq; refSeq = 0; #ifdef TEST_ALIGNER delete alignFast; alignFast = 0; #endif } else { Log.Error("Could not extract reference sequence for read %s.", read->name); validAlignment = false; } if (validAlignment) { if (pacbioDebug) { Log.Message("%d of %d bp successfully aligned with score %f and identity %f", alignedBp, readLength, align->Score, align->Identity); } NGM.Stats->alignmentCount += 1; } else { if (pacbioDebug) { Log.Message("Could not align sequences."); } // If alignment failed delete align object and return 0 if(align != 0) { align->clearBuffer(); align->clearNmPerPosition(); delete align; align = 0; } } } catch (...) { Log.Message("Warning: could not compute alignment for read %s", read->name); // If alignment failed delete align object and return 0 if(align != 0) { align->clearBuffer(); align->clearNmPerPosition(); delete align; align = 0; } } return align; } void AlignmentBuffer::printDotPlotLine(int const id, char const * const name, int const onReadStart, int const onReadStop, loc const onRefStart, loc const onRefStop, float const score, bool const isReverse, int const type, int const status) { if (stdoutPrintDotPlot) { printf("%d\t%s\t%d\t%d\t%llu\t%llu\t%f\t%d\t%d\t%d\n", id, name, onReadStart, onReadStop, onRefStart, onRefStop, score, isReverse, type, status); } } void AlignmentBuffer::printDotPlotLine(int const id, char const * const name, REAL const m, REAL const b, REAL const r, float const score, bool const isReverse, int const type, int const status) { if (stdoutPrintDotPlot) { printf("%d\t%s\t%.*f\t%.*f\t%.*f\t%f\t%f\t%d\t%d\t%d\n", id, name, DBL_DIG, m, DBL_DIG, b, DBL_DIG, r, 0.0f, score, isReverse, type, status); } } /* Finds longest increasing subsequence of reference positions in the * anchor list. Anchors are ordered by read position! */ int * AlignmentBuffer::cLIS(Anchor * anchors, int const anchorsLenght, int & lisLength) { int * DP = 0; int * trace = 0; int * lis = new int[anchorsLenght]; lisLength = 0; if (anchorsLenght > 0) { DP = new int[anchorsLenght]; trace = new int[anchorsLenght]; int maxLength = 1; int bestEnd = 0; DP[0] = 1; trace[0] = -1; for (int i = 0; i < anchorsLenght; i++) { DP[i] = 1; trace[i] = -1; for (int j = i - 1; j >= 0; j--) { loc iRef = anchors[i].onRef; loc jRef = anchors[j].onRef; loc refDiff = 0; if (anchors[j].isReverse) { refDiff = jRef - iRef; } else { refDiff = iRef - jRef; } loc readDiff = anchors[i].onRead - anchors[j].onRead; loc diff = llabs(refDiff - readDiff); loc maxDiff = std::max(llabs(refDiff), readDiff) * 0.25; loc maxRefDiff = readPartLength * 2.0f; // Log.Message("cLIS: (rev %d, %d) ref %lld - %lld = %lld; read %d - %d = %d; diff %lld < %lld", anchors[j].isReverse, anchors[i].isReverse, iRef, jRef, refDiff, anchors[i].onRead, anchors[j].onRead, readDiff, diff, maxDiff); if (DP[j] + 1 > DP[i] // New LIS must be longer then best so far && anchors[j].isReverse == anchors[i].isReverse //Anchors have to be on the same strand to be joined! && (diff < maxDiff // The distance between the two anchors on the read and on the reference should not exceed a threshold. Adhoc threshold of 15% (INDEL sequencing error was to littel). 25% works better. || (anchors[i].onRead == anchors[j].onRead && llabs(refDiff) <= readPartLength) // if anchors stem from the same read position accept ref positions that are in close proximity (to avoid additional segments caused be anchors that are only a few bp off) ) && refDiff < maxRefDiff // Distance between anchors must be smaller than twice the anchor length. With this, gaps break the segment even if they are on the same "diagonal" && refDiff >= 0 // And is not allowed to be negative (only if read position is the same, see above) ) { // Log.Message("---> OK!"); DP[i] = DP[j] + 1; trace[i] = j; } } if (DP[i] > maxLength) { bestEnd = i; maxLength = DP[i]; } } while (trace[bestEnd] != -1) { lis[lisLength++] = bestEnd; bestEnd = trace[bestEnd]; } lis[lisLength++] = bestEnd; delete[] DP; DP = 0; delete[] trace; trace = 0; } return lis; } bool AlignmentBuffer::isSameDirection(Interval const * a, Interval const * b) { return a->isReverse == b->isReverse; } bool isAnchorInCorridor(REAL k, REAL d, REAL corridor, Anchor const & testee) { loc onRefStart = testee.onRef; bool inCorridor = false; REAL y = testee.onRead; loc upperRefStart = (loc) round((y - (d + corridor)) / k); loc lowerRefStart = (loc) round((y - (d - corridor)) / k); if (upperRefStart < lowerRefStart) { REAL tmp = upperRefStart; upperRefStart = lowerRefStart; lowerRefStart = tmp; } inCorridor = inCorridor || (onRefStart <= upperRefStart && onRefStart >= lowerRefStart); // Log.Message("Start: %llu <= %llu <= %llu", testee.onRefStart, lowerRefStart, upperRefStart); return inCorridor; } bool AlignmentBuffer::isIntervalInCorridor(REAL k, REAL d, REAL corridor, Interval const * testee, bool const switched) { loc onRefStart = testee->onRefStart; loc onRefStop = testee->onRefStop; if (switched) { onRefStart = testee->onRefStop; onRefStop = testee->onRefStart; } bool inCorridor = false; REAL y = testee->onReadStart; loc upperRefStart = (loc) round((y - (d + corridor)) / k); loc lowerRefStart = (loc) round((y - (d - corridor)) / k); if (upperRefStart < lowerRefStart) { REAL tmp = upperRefStart; upperRefStart = lowerRefStart; lowerRefStart = tmp; } verbose(3, true, "%llu <= %llu && %llu >= %llu", onRefStart, upperRefStart, onRefStart, lowerRefStart); verbose(3, true, "onRefStart <= upperRefStart = %d, onRefStart >= lowerRefStart = %d", onRefStart <= upperRefStart, onRefStart >= lowerRefStart); inCorridor = inCorridor || (onRefStart <= upperRefStart && onRefStart >= lowerRefStart); // Log.Message("Start: %llu <= %llu <= %llu", testee.onRefStart, lowerRefStart, upperRefStart); y = testee->onReadStop; loc upperRefStop = (loc) round((y - (d + corridor)) / k); loc lowerRefStop = (loc) round((y - (d - corridor)) / k); if (upperRefStop < lowerRefStop) { REAL tmp = upperRefStop; upperRefStop = lowerRefStop; lowerRefStop = tmp; } inCorridor = inCorridor && (onRefStop <= upperRefStop && onRefStop >= lowerRefStop); verbose(3, true, "%llu <= %llu && %llu >= %llu", onRefStop, upperRefStop, onRefStop, lowerRefStop); verbose(3, true, "onRefStop <= upperRefStop = %d, onRefStop >= lowerRefStop = %d", onRefStop <= upperRefStop, onRefStop >= lowerRefStop); // Log.Message("Stop: %llu <= %llu <= %llu", testee.onRefStop, lowerRefStop, upperRefStop); //TODO: add max distance on read return inCorridor; } Interval * AlignmentBuffer::toInterval(Anchor const & anchor) { // if (intervalBufferIndex >= 1000) { // return 0; // } Interval * interval = new Interval(); // intervalBuffer[intervalBufferIndex++] = interval; interval->isReverse = anchor.isReverse; interval->score = anchor.score; interval->onReadStart = interval->onReadStop = anchor.onRead; interval->onRefStart = interval->onRefStop = anchor.onRef; interval->anchorLength = 1; interval->anchors = new Anchor[interval->anchorLength]; interval->anchors[0] = anchor; // To avoid that single anchor intervals that didn't pass cLIS // start a new mapped segment interval->isAssigned = true; return interval; } void AlignmentBuffer::addAnchorAsInterval(Anchor const & anchor, MappedSegment & segment) { if (segment.length < 1000) { Interval * interval = toInterval(anchor); if (interval != 0) { segment.list[segment.length++] = interval; } } } //bool AlignmentBuffer::isCompatible(Anchor const & anchor, // Interval const * interval) { // bool isCompatible = false; // // REAL corridorSize = 512; // // if (anchor.isReverse == interval->isReverse) { //// isCompatible = (anchor.onRead < interval->onReadStart //// || anchor.onRead > interval->onReadStop) //// && (anchor.onRef < interval->onRefStart //// || anchor.onRef > interval->onRefStop); // // isCompatible = isAnchorInCorridor(interval->m, interval->b, // corridorSize, anchor); // } // // return isCompatible; //} //bool AlignmentBuffer::isCompatible(Anchor const & anchor, // MappedSegment const & segment) { // bool compatible = false; // // for (int i = 0; i < segment.length && !compatible; ++i) { // // compatible = isCompatible(anchor, segment.list[i]); // } // // return compatible; //} // Checks whether a is compatible (is located in the "corridor" // of b. bool AlignmentBuffer::isCompatible(Interval const * a, Interval const * b, REAL corridorSize) { bool isCompatible = false; // Trade off (at the moment): // Bigger corridor: higher chance that alignment won't span event (score too low) // and a part of the reads is not aligned // Smaller corridor: reads are split, SVs are not visible in one alignment // TODO: after alignment add check if whole read was aligned. if not, // realign unanligned part // REAL corridorSize = 2048 * 4; // Check if regression worked on read if (b->m != 0 && b->b != 0 && (b->r * b->r) > 0.8f) { if (a->isReverse == b->isReverse) { // a and b are on the same strand isCompatible = isIntervalInCorridor(b->m, b->b, corridorSize, a, false); } else { if (pacbioDebug) { Log.Message("Intervals not on same strand"); } /* * a and b are on different strands * Check if reads spans an inversion * If read spans an inversion, the * inverted part must be added to the segment * in order to keep consolidateSegements * to join the non inverted parts * through the inversion. */ // Switches the direction of the testee isCompatible = isIntervalInCorridor(b->m, b->b, corridorSize, a, true); // Switches the direction of the tester and uses the testeee regression // to check whether both are compatible isCompatible = isCompatible || isIntervalInCorridor(a->m, a->b, corridorSize, b, true); } } return isCompatible; } bool AlignmentBuffer::canSpanDeletionInsertion(Interval const * a, Interval const * b, REAL corridorSize) { bool merge = true; int distanceOnRead = getDistanceOnRead(a, b); loc distanceOnRef = getDistanceOnRef(a, b); verbose(3, true, "DistOnRef: %llu, DistOnRead: %d, Corridor: %f", distanceOnRef, distanceOnRead, corridorSize); if(distanceOnRead < (2 * readPartLength)) { //Possible deletion merge = abs(distanceOnRef - distanceOnRead) < corridorSize; } else if(distanceOnRef < (2 * readPartLength)) { //Possible insertion merge = abs(distanceOnRead - distanceOnRef) < corridorSize; } else { /** * Do nothing, intervals show a larger gap. Probably, poor quality read. * Better to merge than to risk fragmented alignments */ merge = abs(distanceOnRead - distanceOnRef) < corridorSize; } return merge; } bool AlignmentBuffer::spansChromosomeBorder(Interval const * a, Interval const * b) { _SequenceProvider::Chromosome chrA = SequenceProvider.getChrStart((a->onRefStop + a->onRefStart) / 2); _SequenceProvider::Chromosome chrB = SequenceProvider.getChrStart((b->onRefStop + b->onRefStart) / 2); verbose(0, true, "#### Intervals on same chr:"); verbose(0, true, "#### 1: %llu", (a->onRefStop + a->onRefStart) / 2); verbose(0, true, "#### 2: %llu", (b->onRefStop + b->onRefStart) / 2); verbose(0, true, "#### Chr1: %llu - %llu", chrA.start, chrA.end); verbose(0, true, "#### Chr2: %llu - %llu", chrB.start, chrB.end); return chrA.start != chrB.start; } bool AlignmentBuffer::isContained(Interval const * a, Interval const * b) { return a->onReadStart >= b->onReadStart && a->onReadStop <= b->onReadStop && a->onRefStart >= b->onRefStart && a->onRefStop <= b->onRefStop && a->isReverse == b->isReverse; } Interval * AlignmentBuffer::mergeIntervals(Interval * a, Interval * b) { if (a->onReadStart > b->onReadStart) { a->onReadStart = b->onReadStart; a->onRefStart = b->onRefStart; } if (a->onReadStop < b->onReadStop) { a->onReadStop = b->onReadStop; a->onRefStop = b->onRefStop; } a->score += b->score; int anchorCount = a->anchorLength + b->anchorLength; Anchor * tmpA = a->anchors; a->anchors = new Anchor[anchorCount]; memcpy(a->anchors, tmpA, a->anchorLength * (sizeof(Anchor))); memcpy(a->anchors + a->anchorLength, b->anchors, b->anchorLength * (sizeof(Anchor))); a->anchorLength = anchorCount; delete[] tmpA; tmpA = 0; a->isAssigned = a->isAssigned && b->isAssigned; return a; } /** * Overlap on ref coordinates >= readPartLength * Overlap on read coordinadtes <= readPartLength * Difference in overlap must be > 0 * a and b must be on same strand! */ bool AlignmentBuffer::isDuplication(Interval const * a, Interval const * b, loc & dupLength) { verbose(3, true, "isDuplication:"); verbose(3, "", a); verbose(3, "", b); int overlapOnRead = getOverlapOnRead(a, b); loc overlapOnRef = 0; if (a->isReverse) { // if a and b are on reverse strand, refstart and refstop must be switched overlapOnRef = std::max(0ll, std::min(a->onRefStart, b->onRefStart) - std::max(a->onRefStop, b->onRefStop)); } else { overlapOnRef = std::max(0ll, std::min(a->onRefStop, b->onRefStop) - std::max(a->onRefStart, b->onRefStart)); } verbose(2, true, "overlap on read: %d, overlap on ref: %lld", overlapOnRead, overlapOnRef); loc overlapDiff = std::max(0ll, overlapOnRef - overlapOnRead); dupLength = overlapDiff; return overlapOnRef >= (int) (1.0f * readPartLength) && overlapOnRead <= (int) (readPartLength * 1.0f) && overlapDiff > 0ll; // overlapDiff > (int)round(readPartLength / 2.0); } bool sortIntervalsInSegment(Interval const * a, Interval const * b) { return a->onReadStart < b->onReadStart; } bool sortIntervalsByScore(Interval const * a, Interval const * b) { return a->score > b->score; } /** * - Sort sub-reads by read position * - Compute max. number of HSP (based on read length) * - Run cLIS algorithm on reference positions to retrieve HSP * - If isUnique, build Interval from sub-read set and compute regression */ Interval * * AlignmentBuffer::getIntervalsFromAnchors(int & intervalsIndex, Anchor * allFwdAnchors, int allFwdAnchorsLength, Anchor * allRevAnchors, int allRevAnchorsLength, MappedRead * read) { verbose(0, true, "Finding LIS for read %d", read->ReadId); //Sort by position on read. Probably not necessary!! std::sort(allFwdAnchors, allFwdAnchors + allFwdAnchorsLength, sortAnchorOnRead); // Change lo maxSegmentCount = std::max(10, Config.getMaxSegmentNumberPerKb(read->length) * 2); int const maxcLISRunNumber = maxSegmentCount; Interval * * intervals = new Interval * [maxcLISRunNumber]; intervalsIndex = 0; int cLISRunNumber = 0; //int const maxRunNumber = std::min(maxcLISRunNumber, Config.getMaxCLISRuns()); int const maxRunNumber = Config.getMaxCLISRuns(); verbose(0, true, "maxRunNumber: %d, maxcLISRunNumber: %d, MaxCLISRuns: %d", maxRunNumber, maxcLISRunNumber, Config.getMaxCLISRuns()); int runNumber = 0; bool finished = false; // TODO: find better stop criteria! while (cLISRunNumber < maxcLISRunNumber && !finished && ++runNumber < maxRunNumber) { if (allFwdAnchorsLength > 0) { //Find constrained LIS int lisLength = 0; int * lis = cLIS(allFwdAnchors, allFwdAnchorsLength, lisLength); if(lisLength < 1) { //Nothing found finished = true; } else { int minOnRead = INT_MAX; int maxOnRead = 0; loc minOnRef = LLONG_MAX; loc maxOnRef = 0; bool isReverse = false; float intervalScore = 0.0f; verbose(1, false, "cLIS %d:", cLISRunNumber); //Remove LIS from candidates int posInLIS = lisLength - 1; allRevAnchorsLength = 0; std::unique_ptr regX(new REAL[std::max(2, allFwdAnchorsLength)]); std::unique_ptr regY(new REAL[std::max(2, allFwdAnchorsLength)]); int pointNumber = 0; //Find intervall that covers all anchors best Interval * interval = new Interval(); interval->anchors = new Anchor[lisLength + 1]; interval->anchorLength = 0; /** * Only intervals that have at least one * unique (only on mapping position) anchor * are considered. */ // bool isUnique = lisLength >= 4; bool isUnique = false; for (int i = 0; i < allFwdAnchorsLength; ++i) { if (posInLIS >= 0 && i == lis[posInLIS]) { interval->anchors[interval->anchorLength++] = allFwdAnchors[lis[posInLIS]]; isUnique = isUnique || allFwdAnchors[lis[posInLIS]].isUnique; int onRead = allFwdAnchors[lis[posInLIS]].onRead; //Print current LIS verbose(0, false, "%d, ", lis[posInLIS]); isReverse = allFwdAnchors[lis[posInLIS]].isReverse; intervalScore += allFwdAnchors[lis[posInLIS]].score; if(isReverse) { if(onRead < minOnRead) { minOnRead = onRead; minOnRef = allFwdAnchors[lis[posInLIS]].onRef + readPartLength; } if((onRead + readPartLength) > maxOnRead) { maxOnRead = onRead + readPartLength; maxOnRef = allFwdAnchors[lis[posInLIS]].onRef; } } else { if(onRead < minOnRead) { minOnRead = onRead; minOnRef = allFwdAnchors[lis[posInLIS]].onRef; } if((onRead + readPartLength) > maxOnRead) { maxOnRead = onRead + readPartLength; maxOnRef = allFwdAnchors[lis[posInLIS]].onRef + readPartLength; } } regY[pointNumber] = onRead; if(isReverse) { regX[pointNumber] = allFwdAnchors[lis[posInLIS]].onRef + readPartLength; } else { regX[pointNumber] = allFwdAnchors[lis[posInLIS]].onRef; } pointNumber += 1; //Remove from remaining elements posInLIS -= 1; } else { //Add to second array allRevAnchors[allRevAnchorsLength++] = allFwdAnchors[i]; } } verbose(0, true, ""); if(isUnique) { //Debug print anchors used in cLIS for(int i = 0; i < interval->anchorLength; ++i) { Anchor & anchor = interval->anchors[i]; if(anchor.isReverse) { printDotPlotLine(read->ReadId, read->name, anchor.onRead, anchor.onRead + readPartLength, anchor.onRef + readPartLength, anchor.onRef, anchor.score, anchor.isReverse, DP_TYPE_CLIS + cLISRunNumber, DP_STATUS_OK); } else { printDotPlotLine(read->ReadId, read->name, anchor.onRead, anchor.onRead + readPartLength, anchor.onRef, anchor.onRef + readPartLength, anchor.score, anchor.isReverse, DP_TYPE_CLIS + cLISRunNumber, DP_STATUS_OK); } } // Linear regression for segment REAL m,b,r; if(pointNumber == 1) { regX[0] = minOnRef; regY[0] = minOnRead; regX[1] = maxOnRef; regY[1] = maxOnRead; pointNumber = 2; } linreg(pointNumber,regX,regY,&m,&b,&r); verbose(0, true, "Regression: m=%.*f b=%.*f r=%.*f\n", DBL_DIG,m,DBL_DIG,b,DBL_DIG,r); interval->isReverse = isReverse; interval->score = intervalScore; interval->onReadStart = minOnRead; interval->onReadStop = maxOnRead; interval->onRefStart = minOnRef; interval->onRefStop = maxOnRef; interval->m = m; interval->b = b; interval->r = r; if(interval->lengthOnRead() > 0 && interval->lengthOnRef() > 0ll) { verbose(0, true, "New interval: "); verbose(1, "", interval); intervals[intervalsIndex++] = interval; } else { if(pacbioDebug) { Log.Message("Skipping interval. Too short. Deleting."); if(interval != 0) { delete interval; interval = 0; } } } cLISRunNumber += 1; // if(interval->m != 0.0) { // printDotPlotLine(read->ReadId, read->name, // interval->m, interval->b, r, // interval->score, // interval->isReverse, // DP_TYPE_SEQMENTS_REG + cLISRunNumber, DP_STATUS_NOCOORDS); // // } printDotPlotLine(read->ReadId, read->name, interval->onReadStart, interval->onReadStop, interval->onRefStart, interval->onRefStop, interval->score, interval->isReverse, DP_TYPE_SEQMENTS + cLISRunNumber, DP_STATUS_OK); //TODO: check chromosome borders } else { if(interval != 0) { delete interval; interval = 0; } // if(lisLength == 1) { // finished = true; // } } //Switch first with second list Anchor * tmp = allFwdAnchors; allFwdAnchors = allRevAnchors; allFwdAnchorsLength = allRevAnchorsLength; allRevAnchors = tmp; allRevAnchorsLength = 0; } lisLength = 0; delete[] lis; } else { // If no unprocessed anchors are found anymore finished = true; } verbose(0, true, "cLISRunNumber %d < maxcLISRunNumber %d && !finished %d && ++runNumber %d < maxRunNumber %d", cLISRunNumber, maxcLISRunNumber, !finished, runNumber, maxRunNumber); } return intervals; } static inline char cplBase(char c) { if (c == 'A') return 'T'; else if (c == 'T') return 'A'; else if (c == 'C') return 'G'; else if (c == 'G') return 'C'; else return c; } void computeReverseSeq(char * Seq, char * RevSeq, int const length) { //static int const qryMaxLen = Config.GetInt("qry_max_len"); // RevSeq = new char[length + 1]; // memset(RevSeq, 0, length + 1); char * fwd = Seq; char * rev = RevSeq + length - 1; for (int i = 0; i < length; ++i) { *rev-- = cplBase(*fwd++); } } bool inline isInversion(float const nm) { float const minIdentity = 0.0; float const maxIdentity = 0.75; return nm > minIdentity && nm < maxIdentity; } void printLocation(char const * title, uloc position) { int len = 0; SequenceLocation loc; loc.m_Location = position; SequenceProvider.convert(loc); Log.Message("%s %s:%llu", title, SequenceProvider.GetRefName(loc.getrefId(), len), loc.m_Location); } int AlignmentBuffer::checkForSV(Align const * const align, Interval const * interval, char const * const fullReadSeq, uloc inversionMidpointOnRef, uloc inversionMidpointOnRead, int const inversionLength, MappedRead * read) { int inversionNumber = 0; static bool const noLowQualSplit = !Config.getLowQualitySplit(); int const readCheckLength = 50; // Length of regions that will be checked left and right to the midpoint of the // inversion on the reference int const refCheckLength = 250; int const minInversionLength = 10; int svType = SV_NONE; if (inversionLength > minInversionLength) { inversionNumber += 1; SequenceLocation inversionCheckLocation; inversionCheckLocation.m_Location = interval->onRefStart + align->PositionOffset + inversionMidpointOnRef - refCheckLength - (inversionLength / 2); // svType = alignmentCheckForInversion(inversionLength, refCheckLength, inversionCheckLocation, inversionMidpointOnRead, read->name, inversionNumber, fullReadSeq); int const fullReadSeqLength = strlen(fullReadSeq); // TODO: don't allocate and delete every time. Can be done once // and reused const int readSeqLenght = readCheckLength * 2 + 10; char* readSeq = new char[readSeqLenght]; char* revreadSeq = new char[readSeqLenght]; memset(readSeq, '\0', readSeqLenght * sizeof(char)); memset(revreadSeq, '\0', readSeqLenght * sizeof(char)); const int refSeqLength = inversionLength + 2 * refCheckLength; char* refSeq = new char[refSeqLength + 10]; memset(refSeq, '\0', (refSeqLength + 10) * sizeof(char)); SequenceProvider.DecodeRefSequence(refSeq, 0, inversionCheckLocation.m_Location, refSeqLength); // Extract sequence from read. if (pacbioDebug) { Log.Message("CheckLength: %d, Midpoint: %d, readSeqLength: %d", readCheckLength, inversionMidpointOnRead, readSeqLenght); } if (readCheckLength <= inversionMidpointOnRead && (inversionMidpointOnRead + readCheckLength) < fullReadSeqLength) { strncpy(readSeq, fullReadSeq + inversionMidpointOnRead - readCheckLength, readCheckLength * 2); } if (strlen(readSeq) > 0) { // Reverse complement computeReverseSeq(readSeq, revreadSeq, readCheckLength * 2); if (pacbioDebug) { Log.Message("Ref: %s", refSeq); Log.Message("Read: %s", readSeq); Log.Message("RevRead: %s", revreadSeq); } if (printInvCandidateFa) { printf(">%s_%d/1\n%s\n", read->name, inversionNumber, refSeq); printf(">%s_%d/2\n%s\n", read->name, inversionNumber, revreadSeq); } IAlignment * lqCheckAligner = new StrippedSW(); float scoreFwd = 0.0f; float scoreRev = 0.0f; static const float minScore = 1.0f * readCheckLength / 4.0f; //Formula from Moritz -> p-val > 0.05 for Match:1, mismacth: -4, gap open: -2, gap extend -1 // const float minScore = 15.0f; lqCheckAligner->SingleScore(10, 0, refSeq, readSeq, scoreFwd, 0); lqCheckAligner->SingleScore(10, 0, refSeq, revreadSeq, scoreRev, 0); delete lqCheckAligner; lqCheckAligner = 0; if ((scoreRev / scoreFwd) > Config.getInvScoreRatio() && scoreRev > minScore) { // if (scoreRev >= scoreFwd && scoreRev > minScore) { svType = SV_INVERSION; } else if (scoreRev < minScore && scoreFwd < minScore && !noLowQualSplit) { svType = SV_TRANSLOCATION; } // inversionVerified = scoreRev > scoreFwd || scoreFwd < minScore; } else { verbose(0, true, "Skipping alignment. Readpart not long enough."); } delete[] refSeq; refSeq = 0; delete[] readSeq; readSeq = 0; delete[] revreadSeq; revreadSeq = 0; if (svType != SV_NONE) { if (pacbioDebug) { if (svType == SV_INVERSION) { Log.Message("Inversion detected: %llu, %llu", inversionMidpointOnRef, inversionMidpointOnRead); } else if(svType == SV_TRANSLOCATION) { Log.Message("Translocation detected: %llu, %llu", inversionMidpointOnRef, inversionMidpointOnRead); } } } } else { if(pacbioDebug) { Log.Message("Inversion too short!"); } } return svType; } int AlignmentBuffer::detectMisalignment(Align const * const align, Interval const * alignedInterval, char const * const readPartSeq, Interval * leftOfInv, Interval * rightOfInv, MappedRead * read) { //*********************// //Detect inversions //*********************// uloc bestInversionMidpointOnRead = 0; uloc bestInversionMidpointOnRef = 0; //Half of window size used to compute NM in SWCPU.cpp int const inversionPositionShift = 0; /** * Max number of peaks allowed for read. * If more peaks are found, read is considered to be * of bad quality and no split is performed */ int const maxCheckCount = std::max(1, (int)((read->length / 1000.0f) / 2.0f)); //Peaks (isInversion(nm) == true) that are less than maxDistance apart will be merged int const maxDistance = 20; int distance = maxDistance; int startInv = -1; int stopInv = -1; int startInvRead = -1; int stopInvRead = -1; SequenceLocation mappingLocation; mappingLocation.m_Location = alignedInterval->onRefStart + align->PositionOffset; SequenceProvider.convert(mappingLocation); if (stdoutErrorProfile) { int len = 0; for (int i = 0; i < align->alignmentLength; ++i) { printf("%s\t%llu\t%d\t%s\n", SequenceProvider.GetRefName(mappingLocation.getrefId(), len), mappingLocation.m_Location + align->nmPerPosition[i].refPosition, align->nmPerPosition[i].nm, read->name); } } /** * Reconds number of detected peaks */ int checkCount = 0; // Extremely simple "peak-finding" algorithm int len = 0; int result = SV_NONE; int bestResult = SV_NONE; for (int i = 0; i < align->alignmentLength /*&& result == SV_NONE*/; ++i) { float nm = (32 - align->nmPerPosition[i].nm) / 32.0f; //Log.Message("Inv: %d - %d", startInvRead, stopInvRead); if (startInv == -1) { if (isInversion(nm)) { startInv = align->nmPerPosition[i].refPosition - inversionPositionShift; startInvRead = align->nmPerPosition[i].readPosition - inversionPositionShift; stopInv = align->nmPerPosition[i].refPosition - inversionPositionShift; stopInvRead = align->nmPerPosition[i].readPosition - inversionPositionShift; } } else { // if(stopInv == -1) { if (isInversion(nm)) { stopInv = align->nmPerPosition[i].refPosition - inversionPositionShift; stopInvRead = align->nmPerPosition[i].readPosition - inversionPositionShift; distance = maxDistance; } else { if (distance == 0) { if (stdoutInversionBed) { printf("%s\t%llu\t%llu\t%s\t%d\n", SequenceProvider.GetRefName(mappingLocation.getrefId(), len), mappingLocation.m_Location + startInv, mappingLocation.m_Location + stopInv, read->name, 0); } if (pacbioDebug) { Log.Message("Low alignment quality region detected: %d - %d, %d - %d (length: %d) on read %s", startInv, stopInv, startInvRead, stopInvRead, abs(stopInv - startInv), read->name); } uloc inversionMidpointOnRef = (startInv + stopInv) / 2; uloc inversionMidpointOnRead = (startInvRead + stopInvRead) / 2; int inversionLength = abs(stopInv - startInv); // char * test = new char[stopInvRead - startInvRead + 100]; // strncpy(test, readPartSeq + startInvRead, (stopInvRead - startInvRead)); // test[(stopInvRead - startInvRead)] = '\n'; // // SequenceLocation inversionCheckLocation; // inversionCheckLocation.m_Location = alignedInterval->onRefStart + align->PositionOffset + startInv; // char * refSeq = new char[inversionLength + 100]; // SequenceProvider.DecodeRefSequence(refSeq, 0, inversionCheckLocation.m_Location, inversionLength); // // Log.Message("Inv read sequence: %s", test); // Log.Message("Inv read sequence: %s", refSeq); checkCount += 1; result = checkForSV(align, alignedInterval, readPartSeq, inversionMidpointOnRef, inversionMidpointOnRead, inversionLength, read); if(bestResult == SV_NONE || result == SV_INVERSION) { bestResult = result; bestInversionMidpointOnRef = inversionMidpointOnRef; bestInversionMidpointOnRead = inversionMidpointOnRead; } startInv = -1; stopInv = -1; startInvRead = -1; stopInvRead = -1; distance = maxDistance; } else { distance -= 1; } } } } if(checkCount <= maxCheckCount) { if (bestResult != SV_NONE) { if (alignedInterval->isReverse) { // alignStartOnRead is not relative to the full read, but to the part (interval) // that was aligned in the first place (the alignemnt that is scanned for an inversion) // Qstart is realtive to the full read. // However leftOfInv must be relative to the full read as well. // To define the stop position (start on the fwd strand) QStart can be used // For the start position (stop on the fwd strand) we use the position were // the inversion was detected. Since this position in relative to the aligned part // of the read (interval) we have to add additionalQstart int additionalQStart = align->QStart - align->firstPosition.readPosition; leftOfInv->onReadStop = read->length - (align->QStart); leftOfInv->onReadStart = read->length - (additionalQStart + bestInversionMidpointOnRead); // Position on the reference works perfectly with the mapping position // from the intial alignment. No need to account for the fact that only // a part of the read was aligned leftOfInv->onRefStart = alignedInterval->onRefStart + align->PositionOffset + align->firstPosition.refPosition; leftOfInv->onRefStop = alignedInterval->onRefStart + align->PositionOffset + bestInversionMidpointOnRef; leftOfInv->isReverse = alignedInterval->isReverse; // Same as for leftOfInv rightOfInv->onReadStart = read->length - (align->lastPosition.readPosition + additionalQStart); rightOfInv->onReadStop = read->length - (bestInversionMidpointOnRead + additionalQStart); rightOfInv->onRefStart = alignedInterval->onRefStart + align->PositionOffset + bestInversionMidpointOnRef; rightOfInv->onRefStop = alignedInterval->onRefStart + align->PositionOffset + align->lastPosition.refPosition; rightOfInv->isReverse = alignedInterval->isReverse; } else { leftOfInv->onReadStart = alignedInterval->onReadStart + align->firstPosition.readPosition; leftOfInv->onReadStop = alignedInterval->onReadStart + bestInversionMidpointOnRead; leftOfInv->onRefStart = alignedInterval->onRefStart + align->PositionOffset + align->firstPosition.refPosition; leftOfInv->onRefStop = alignedInterval->onRefStart + align->PositionOffset + bestInversionMidpointOnRef; leftOfInv->isReverse = alignedInterval->isReverse; rightOfInv->onReadStart = alignedInterval->onReadStart + bestInversionMidpointOnRead; rightOfInv->onReadStop = alignedInterval->onReadStart + align->lastPosition.readPosition; rightOfInv->onRefStart = alignedInterval->onRefStart + align->PositionOffset + bestInversionMidpointOnRef; rightOfInv->onRefStop = alignedInterval->onRefStart + align->PositionOffset + align->lastPosition.refPosition; rightOfInv->isReverse = alignedInterval->isReverse; } } } else { verbose(0, true, "Too many peaks detected! %d > %d allowed for read length of %d", checkCount, maxCheckCount, read->length); bestResult = SV_NONE; } return bestResult; } int AlignmentBuffer::estimateCorridor(Interval const * interval) { int corridor = 8192; int onRead = interval->onReadStop - interval->onReadStart; int onRef = interval->onRefStop - interval->onRefStart; int diff = onRead - onRef; int corridorFromDiff = (int) ((abs(diff) * 2.1f)); int corridorFromLength = (int) ((abs(onRead) * 0.20f)); corridor = std::min(corridor, std::max(corridorFromDiff, corridorFromLength)); if (pacbioDebug) Log.Message("Corridor estimation - onRead: %d, onRef: %d, diff: %d, corridor: %d", onRead, onRef, diff, corridor); return corridor; } Align * AlignmentBuffer::alignInterval(MappedRead const * const read, Interval const * interval, char const * const readSeq, size_t const readSeqLen, bool const realign, bool const fullAlignment) { Align * align = 0; if(readSeq == nullptr) { return align; } Timer alignTimer; alignTimer.ST(); int const minReadSeqLength = 10; if (!(llabs(interval->onReadStart - interval->onReadStop) == 0 || llabs(interval->onRefStart - interval->onRefStop) == 0 || readSeqLen < minReadSeqLength)) { int corridor = estimateCorridor(interval); int QStart = 0; int QEnd = 0; if (interval->isReverse) { QEnd = interval->onReadStart; QStart = read->length - interval->onReadStop; } else { QStart = interval->onReadStart; QEnd = read->length - interval->onReadStop; } if (pacbioDebug) { Log.Message("Computing alignment - Start pos: %d, Length: %d", interval->onReadStart, readSeqLen); } align = computeAlignment(interval, corridor, readSeq, readSeqLen, QStart, QEnd, read->length, read, realign, fullAlignment, false); } else { verbose(0, "Tried to align invalid interval:", interval); } alignTime += alignTimer.ET(); return align; } unique_ptr AlignmentBuffer::extractReadSeq(int const readSeqLen, int const onReadStart, bool const isReverse, MappedRead* read, bool const revComp) { // > 500000 very basic check for overflows (this is terrible) if(readSeqLen <= 0 || readSeqLen > 200000000) { return 0; } unique_ptr readSeq(new char[readSeqLen + 1]); if (isReverse) { read->computeReverseSeq(); computeReverseSeq(read->Seq + onReadStart, readSeq.get(), readSeqLen); readSeq[readSeqLen] = '\0'; } else { strncpy(readSeq.get(), read->Seq + onReadStart, readSeqLen); readSeq[readSeqLen] = '\0'; } if(revComp) { unique_ptr tmp(new char[readSeqLen + 1]); computeReverseSeq(readSeq.get(), tmp.get(), readSeqLen); tmp[readSeqLen] = '\0'; return tmp; } else { return readSeq; } } unique_ptr AlignmentBuffer::extractReadSeq(int const readSeqLen, Interval const * interval, MappedRead* read, bool const revComp) { return extractReadSeq(readSeqLen, interval->onReadStart, interval->isReverse, read, revComp); } int AlignmentBuffer::realign(int const svTypeDetected, Interval const * interval, Interval * leftOfInv, Interval * rightOfInv, MappedRead * read, Align * tmpAling, int & alignIxndex, LocationScore * tmpScore, int mq) { verbose(0, true, "***********************************"); verbose(0, true, "Realigning read!"); verbose(0, "Interval: ", interval); float realignScore = 0.0f; int svTypeResult = 0; /**********************************************/ //Align part of read that is left of inversion /**********************************************/ verbose(0, "Left Interval:", leftOfInv); int readSeqLen = leftOfInv->onReadStop - leftOfInv->onReadStart; Align * alignLeft = 0; alignLeft = alignInterval(read, leftOfInv, extractReadSeq(readSeqLen, leftOfInv, read).get(), readSeqLen, true, false); LocationScore scoreLeft; Align * alignRight = 0; LocationScore scoreRight; Align * alignInv = 0; LocationScore scoreInv; // Defines the inverted part of the alignment // start and end are computed from the alignments // left and right to it Interval * inv = new Interval(); if (alignLeft != 0 && alignLeft->Score > 0.0f) { alignLeft->MQ = mq; scoreLeft.Location.m_Location = leftOfInv->onRefStart + alignLeft->PositionOffset;//- (corridor >> 1); handled in computeAlingment scoreLeft.Location.setReverse(leftOfInv->isReverse); scoreLeft.Score.f = alignLeft->Score; /**********************************************/ //QEnd from first read part, gives length of //inversion that was covered by left part /**********************************************/ // Set start of inverted read part inv->onReadStart = read->length - alignLeft->QEnd; inv->onRefStart = scoreLeft.Location.m_Location + alignLeft->lastPosition.refPosition; inv->isReverse = !leftOfInv->isReverse; realignScore += alignLeft->Score; /**********************************************/ //Align part of read that is right of inversion /**********************************************/ verbose(0, "Right Interval: ", rightOfInv); readSeqLen = rightOfInv->onReadStop - rightOfInv->onReadStart; alignRight = alignInterval(read, rightOfInv, extractReadSeq(readSeqLen, rightOfInv, read).get(), readSeqLen, true, false); if (alignRight != 0 && alignRight->Score > 0.0f) { alignRight->MQ = mq; scoreRight.Location.m_Location = rightOfInv->onRefStart + alignRight->PositionOffset;//- (corridor >> 1); handled in computeAlingment scoreRight.Location.setReverse(rightOfInv->isReverse); scoreRight.Score.f = alignRight->Score; // Set end of inverted read part /**********************************************/ //QStart from second read part, gives length //of inversion that was covered by second read /**********************************************/ inv->onReadStop = alignRight->QStart; inv->onRefStop = scoreRight.Location.m_Location + alignRight->firstPosition.refPosition; realignScore += alignRight->Score; /**********************************************/ //Align inverted part, length was inferred //from left and right part /**********************************************/ if(!inv->isReverse) { // Reverse coordinates on read uloc tmp = read->length - inv->onReadStart; inv->onReadStart = read->length - inv->onReadStop; inv->onReadStop = tmp; } // Extend int inversionLength = llabs(inv->onRefStop - inv->onRefStart); int const minInversionLength = Config.getMinInversionLength(); verbose(0, true, "Length of inversion is %d", inversionLength); verbose(0, "Inverted Interval: ", inv); if(inversionLength > minInversionLength) { readSeqLen = inv->onReadStop - inv->onReadStart; alignInv = alignInterval(read, inv, extractReadSeq(readSeqLen, inv, read).get(), readSeqLen, true, true); if(pacbioDebug && alignInv != 0) { Log.Message("Inversion alignment score: %f", alignInv->Score); } Align * alignInvRev = 0; alignInvRev = alignInterval(read, inv, extractReadSeq(readSeqLen, inv, read, true).get(), readSeqLen, true, true); if(pacbioDebug && alignInvRev != 0) { Log.Message("Inversion alignment score: %f", alignInvRev->Score); } if (alignInv != 0 && alignInv->Score > 0.0f && alignInv->getAlignedReadBp(read->length) > minInversionLength && (alignInvRev == 0 || alignInvRev->Score < alignInv->Score)) { alignInv->MQ = mq; // alignInv->svType = SV_INVERSION; scoreInv.Location.m_Location = inv->onRefStart + alignInv->PositionOffset; //- (corridor >> 1); handled in computeAlingment scoreInv.Location.setReverse(inv->isReverse); scoreInv.Score.f = alignInv->Score; SequenceLocation inversionStartRef; inversionStartRef.m_Location = inv->onRefStart; SequenceProvider.convert(inversionStartRef); SequenceLocation inversionStopRef; inversionStopRef.m_Location = inv->onRefStop; SequenceProvider.convert(inversionStopRef); realignScore += alignInv->Score; svTypeResult = SV_INVERSION; } else { if (pacbioDebug) { Log.Message("Alignment of inverted part failed or score not high enough. Reporting translocation."); } svTypeResult = SV_TRANSLOCATION; } if (alignInvRev != 0) { alignInvRev->clearBuffer(); alignInvRev->clearNmPerPosition(); delete alignInvRev; alignInvRev = 0; } } else { if (pacbioDebug) { Log.Message("Inversion/Translocation too short."); } svTypeResult = SV_NONE; } } else { if (pacbioDebug) { Log.Message("Alignment right failed"); } svTypeResult = SV_NONE; } } else { if (pacbioDebug) { Log.Message("Alignment left failed"); } svTypeResult = SV_NONE; } delete inv; inv = 0; if(svTypeResult == SV_NONE || (alignLeft == 0 || alignLeft->Score <= 0.0f) || (alignRight == 0 || alignRight->Score <= 0.0f)) { if(alignLeft != 0) { alignLeft->clearBuffer(); alignLeft->clearNmPerPosition(); delete alignLeft; alignLeft = 0; } if(alignRight != 0) { alignRight->clearBuffer(); alignRight->clearNmPerPosition(); delete alignRight; alignRight = 0; } if(alignInv != 0) { alignInv->clearBuffer(); alignInv->clearNmPerPosition(); delete alignInv; alignInv = 0; } svTypeResult = SV_NONE; } else { // Add alignLeft->clearNmPerPosition(); tmpAling[alignIxndex] = *alignLeft; delete alignLeft; alignLeft = 0; tmpScore[alignIxndex] = scoreLeft; tmpAling[alignIxndex].mappedInterval = getIntervalFromAlign(&tmpAling[alignIxndex], &tmpScore[alignIxndex], alignIxndex, read->length); alignIxndex += 1; read->Calculated += 1; alignRight->clearNmPerPosition(); tmpAling[alignIxndex] = *alignRight; delete alignRight; alignRight = 0; tmpScore[alignIxndex] = scoreRight; tmpAling[alignIxndex].mappedInterval = getIntervalFromAlign(&tmpAling[alignIxndex], &tmpScore[alignIxndex], alignIxndex, read->length); alignIxndex += 1; read->Calculated += 1; if(svTypeResult == SV_INVERSION && alignInv != 0) { alignInv->clearNmPerPosition(); tmpAling[alignIxndex] = *alignInv; delete alignInv; alignInv = 0; tmpScore[alignIxndex] = scoreInv; tmpAling[alignIxndex].mappedInterval = getIntervalFromAlign(&tmpAling[alignIxndex], &tmpScore[alignIxndex], alignIxndex, read->length); alignIxndex += 1; read->Calculated += 1; } else { if(alignInv != 0) { alignInv->clearBuffer(); alignInv->clearNmPerPosition(); delete alignInv; alignInv = 0; } } } if(pacbioDebug) { Log.Message("Realign score: %f", realignScore); } return svTypeResult; } bool satisfiesConstraints(Align * align, int const readLength) { //TODO: check threshold static float minResidues = 50.0f;//Config.getMinResidues(); static float minIdentity = Config.getMinIdentity(); if (minResidues <= 1.0f) { minResidues = readLength * minResidues; } return (align->Score > 0.0f) && (align->Identity >= minIdentity) && ((float) (readLength - align->QStart - align->QEnd) >= minResidues); } void AlignmentBuffer::alignSingleOrMultipleIntervals(MappedRead * read, Interval const * const interval, LocationScore * tmp, Align * tmpAling, int & alignIndex) { int readSeqLen = interval->onReadStop - interval->onReadStart; auto readPartSeq = extractReadSeq(readSeqLen, interval, read); if (readPartSeq != 0) { Align * align = alignInterval(read, interval, readPartSeq.get(), readSeqLen, false, false); if (align != 0) { if (align->Score > 0.0f) { int svType = SV_NONE; if (Config.getSmallInversionDetection() || Config.getLowQualitySplit()) { Interval * leftOfInv = new Interval(); Interval * rightOfInv = new Interval(); svType = SV_UNKNOWN; bool inversionAligned = false; svType = detectMisalignment(align, interval, readPartSeq.get(), leftOfInv, rightOfInv, read); if (svType != SV_NONE) { int mq = computeMappingQuality(*align, read->length); int assumedSvType = svType; svType = realign(svType, interval, leftOfInv, rightOfInv, read, tmpAling, alignIndex, tmp, mq); } else { verbose(0, true, "No SV detected!"); } if (leftOfInv != 0) { delete leftOfInv; leftOfInv = 0; } if (rightOfInv != 0) { delete rightOfInv; rightOfInv = 0; } } if (svType == SV_NONE) { verbose(0, true, "No SV was detected. Keeping single alignment!"); /**********************************************/ // No inversion detected /**********************************************/ if (satisfiesConstraints(align, read->length)) { align->MQ = computeMappingQuality(*align, read->length); align->clearNmPerPosition(); tmpAling[alignIndex] = *align; delete align; align = 0; tmp[alignIndex].Location.m_Location = interval->onRefStart + tmpAling[alignIndex].PositionOffset; //- (corridor >> 1); handled in computeAlingment tmp[alignIndex].Location.setReverse(interval->isReverse); tmp[alignIndex].Score.f = tmpAling[alignIndex].Score; tmpAling[alignIndex].mappedInterval = getIntervalFromAlign(&tmpAling[alignIndex], &tmp[alignIndex], alignIndex, read->length); read->Calculated += 1; alignIndex += 1; } else { align->clearBuffer(); align->clearNmPerPosition(); delete align; align = 0; verbose(0, true, "Alignment did not satisfiesConstraints"); } } //else { if (align != 0) { align->clearBuffer(); align->clearNmPerPosition(); delete align; align = 0; } // } } else { if (align != 0) { align->clearBuffer(); align->clearNmPerPosition(); delete align; align = 0; } verbose(0, true, "Alignment failed"); } } } else { Log.Message("Extracting read sequence failed for read %s. Please report this on https://github.com/philres/ngmlr", read->name); } } int AlignmentBuffer::computeMappingQuality(Align const & alignment, int readLength) { std::vector > results; verbose(0, true, "Computing mapping quality:"); readCoordsTree->findOverlapping(alignment.QStart, readLength - alignment.QEnd, results); int mqSum = 0; int mqCount = 0; for (int j = 0; j < results.size(); ++j) { //verbose(1, false, "%d, ", results[j].value); mqSum += results[j].value; mqCount += 1; } // verbose(1, true, ""); if (mqCount == 0) return 0; verbose(1, true, "%d / %d = %d", mqSum, mqCount, (int) (mqSum * 1.0f / mqCount)); return (int) (mqSum * 1.0f / mqCount); // std::vector > results; // // readCoordsTree->findOverlapping(alignment.QStart, // readLength - alignment.QEnd, results); // int mq = 0; // // verbose(0, true, "Computing mq (readlength %d): ", readLength); // int * mqs = new int[results.size()]; // for (int j = 0; j < results.size(); ++j) { // mqs[j] = results[j].value; // verbose(1, false, "%d, ", mqs[j]); // } // std::sort(mqs, mqs + results.size(), std::greater()); // // int length = std::min((int)results.size(), std::max(2, (int)(results.size() * 0.2f + 0.5f))); // verbose(1, false, "\nUsing (%d): ", length); // // int mqSum = 0; // int mqCount = 0; // for (int j = 0; j < length; ++j) { // mqSum += mqs[j]; // mqCount += 1; // verbose(0, false, "%d, ", mqs[j]); // } // mq = (int) (mqSum * 1.0f / mqCount); // verbose(1, true, "\nMapping quality: %d", mq); // // delete[] mqs; mqs = 0; // // return mq; } bool sortMappedSegements(Interval * a, Interval * b) { return a->score > b->score; // int aLen = a.value->onReadStop - a.value->onReadStart; // int bLen = b.value->onReadStop - b.value->onReadStart; // return (aLen == bLen && a.value->score > b.value->score) || aLen > bLen; } bool isContainedOnRead(Interval * shortInterval, Interval * longInterval, float minOverlap) { int threshold = minOverlap * abs(shortInterval->onReadStop - shortInterval->onReadStart); int overlap = 0; if (longInterval->onReadStart > shortInterval->onReadStart) { // Interval * tmp = longInterval; // longInterval = shortInterval; // shortInterval = tmp; overlap = std::max(0, shortInterval->onReadStop - longInterval->onReadStart); } else { overlap = std::max(0, longInterval->onReadStop - shortInterval->onReadStart); } // int overlap = abs(longInterval->onReadStart - shortInterval->onReadStart) // + abs(longInterval->onReadStop - shortInterval->onReadStop); return overlap > threshold; } bool isFullyContainedOnRead(Interval * shortInterval, Interval * longInterval) { // int threshold = 0.01f * (longInterval->onReadStop - longInterval->onReadStart); int threshold = 10; return (longInterval->onReadStart - shortInterval->onReadStart) <= threshold && (longInterval->onReadStop - shortInterval->onReadStop) >= -threshold; } bool isFullyContainedOnRef(Interval * shortInterval, Interval * longInterval) { // int threshold = 0.10f * (longInterval->onReadStop - longInterval->onReadStart); int threshold = 10; return (longInterval->onRefStart - shortInterval->onRefStart) <= threshold && (longInterval->onRefStop - shortInterval->onRefStop) >= -threshold; } bool isFullyContained(Interval * shortInterval, Interval * longInterval) { return isFullyContainedOnRead(shortInterval, longInterval) && isFullyContainedOnRef(shortInterval, longInterval); } bool isValidOverlap(Interval * shortInterval, Interval * longInterval) { return true; } bool isValidOverlapRef(Interval * shortInterval, Interval * longInterval) { // return shortInterval->isReverse == longInterval->isReverse // && shortInterval->onRefStart <= longInterval->onRefStop // && shortInterval->onRefStop >= longInterval->onRefStart; return shortInterval->isReverse == longInterval->isReverse && (longInterval->onRefStop - shortInterval->onRefStart) > 50 && (shortInterval->onRefStop - longInterval->onRefStart) > 50; } bool isValidOverlapRead(Interval * shortInterval, Interval * longInterval) { // return shortInterval->isReverse == longInterval->isReverse // && shortInterval->onRefStart <= longInterval->onRefStop // && shortInterval->onRefStop >= longInterval->onRefStart; return shortInterval->isReverse == longInterval->isReverse && (longInterval->onReadStop - shortInterval->onReadStart) > 50 && (shortInterval->onReadStop - longInterval->onReadStart) > 50; } float getBestSegmentCombination(int const maxLength, std::vector const & mappedSegements, std::vector & segmentList) { float result = 0.0f; // field i = score for best fragment (combination) in range 0 to i float * bestScore = new float[maxLength]; int * lastBest = new int[maxLength]; int * lastFragment = new int[maxLength]; int const maxOverlap = 50; bestScore[0] = 0; lastFragment[0] = -1; lastBest[0] = 0; for (int i = 1; i < maxLength; ++i) { // Init bestScore[i] = bestScore[i - 1]; lastFragment[i] = lastFragment[i - 1]; lastBest[i] = lastBest[i - 1]; // Find fragment (combination) with the highest score that fits into interval 0 to i for (int j = 0; j < mappedSegements.size(); ++j) { if (!mappedSegements[j]->isProcessed && mappedSegements[j]->onReadStop <= i && abs(mappedSegements[j]->onReadStop - mappedSegements[j]->onReadStart) > maxOverlap) { int const start = std::min(maxLength, mappedSegements[j]->onReadStart + maxOverlap); float currentScore = mappedSegements[j]->score + bestScore[start]; if (currentScore > bestScore[i]) { bestScore[i] = currentScore; lastFragment[i] = j; lastBest[i] = start; } } else { // Fragment doesn't fit into range 0 to i } } } int i = maxLength - 1; result = bestScore[i]; while (lastFragment[i] > -1) { //Log.Message("Fragment: %d", lastFragment[i]); segmentList.push_back(lastFragment[i]); i = lastBest[i]; } delete[] bestScore; bestScore = 0; delete[] lastBest; lastBest = 0; delete[] lastFragment; lastFragment = 0; return result; } Interval * AlignmentBuffer::getIntervalFromAlign(Align const * const align, LocationScore const * const score, int const i, int const readLength) { int diffOnRef = align->lastPosition.refPosition - align->firstPosition.refPosition; Interval * mappedSegement = new Interval(); mappedSegement->id = i; mappedSegement->onRefStart = score->Location.m_Location; mappedSegement->onRefStop = score->Location.m_Location + diffOnRef; mappedSegement->isReverse = score->Location.isReverse(); mappedSegement->isProcessed = false; mappedSegement->score = align->Score; if (mappedSegement->isReverse) { // If mapped to the reverse strand, QStart and QEnd have to be translated to // plus strand mappedSegement->onReadStart = align->QEnd; mappedSegement->onReadStop = readLength - align->QStart - 1; } else { mappedSegement->onReadStart = align->QStart; mappedSegement->onReadStop = readLength - align->QEnd - 1; } return mappedSegement; } bool AlignmentBuffer::reconcileRead(ReadGroup * group) { bool mapped = false; std::vector mappedSegements; MappedRead * read = group->fullRead; // Not the best strategy, however only used for debug // plots at the moment (ngm itself doesn't rely on read strand information) bool readIsReverse = read->Scores[0].Location.isReverse(); if (pacbioDebug) { Log.Message("Reconciling read: %s with length %d (%d)", read->name, read->length, read->ReadId); } // Convert Score + Alignment info to Interval (mappedSegement) object // mappedSegemnts will be used to detect overlaps in alignments // TODO: create mapped segments in an early stage of the algorithm // maybe merge Align and Interval classes for (int i = 0; i < read->Calculated; ++i) { int diffOnRef = read->Alignments[i].lastPosition.refPosition - read->Alignments[i].firstPosition.refPosition; Interval * mappedSegement = new Interval(); mappedSegement->id = i; mappedSegement->onRefStart = read->Scores[i].Location.m_Location; mappedSegement->onRefStop = read->Scores[i].Location.m_Location + diffOnRef; mappedSegement->isReverse = read->Scores[i].Location.isReverse(); mappedSegement->isProcessed = false; mappedSegement->score = read->Alignments[i].Score; if (mappedSegement->isReverse) { // If mapped to the reverse strand, QStart and QEnd have to be translated to // plus strand mappedSegement->onReadStart = read->Alignments[i].QEnd; mappedSegement->onReadStop = read->length - read->Alignments[i].QStart - 1; } else { mappedSegement->onReadStart = read->Alignments[i].QStart; mappedSegement->onReadStop = read->length - read->Alignments[i].QEnd - 1; } mappedSegements.push_back(mappedSegement); if (stdoutPrintMappedSegments) { fprintf(stdout, "%s\t%d\t%d\t%d\t%d\t%d\t%d\t%f\n", read->name, i, read->length, mappedSegement->onReadStart, mappedSegement->onReadStop, read->Scores[i].Location.isReverse(), read->Alignments[i].MQ, read->Alignments[i].Score); } } // // Sort segments by score // std::sort(mappedSegements.begin(), mappedSegements.end(), // sortMappedSegements); // DEBUG code: print segments for dotplot and log for (int i = 0; i < mappedSegements.size(); ++i) { if (pacbioDebug) { Log.Message("%d: Read: %d - %d, Ref: %llu - %llu (%d) - %f (%f, %d) - %d", mappedSegements[i]->id, mappedSegements[i]->onReadStart, mappedSegements[i]->onReadStop, mappedSegements[i]->onRefStart, mappedSegements[i]->onRefStop, mappedSegements[i]->isReverse, mappedSegements[i]->score, read->Alignments[mappedSegements[i]->id].Identity, (read->length - read->Alignments[mappedSegements[i]->id].QStart - read->Alignments[mappedSegements[i]->id].QEnd), mappedSegements[i]->isProcessed); } if(!readIsReverse) { printDotPlotLine(read->ReadId, read->name, mappedSegements[i]->onReadStart, mappedSegements[i]->onReadStop, mappedSegements[i]->onRefStart, mappedSegements[i]->onRefStop, mappedSegements[i]->score, mappedSegements[i]->isReverse, DP_TYPE_RESULT + mappedSegements[i]->id, DP_STATUS_OK); } else { printDotPlotLine(read->ReadId, read->name, mappedSegements[i]->onReadStop, mappedSegements[i]->onReadStart, mappedSegements[i]->onRefStart, mappedSegements[i]->onRefStop, mappedSegements[i]->score, mappedSegements[i]->isReverse, DP_TYPE_RESULT + mappedSegements[i]->id, DP_STATUS_OK); } } int const maxLength = read->length; std::vector bestSegments; float bestScore = getBestSegmentCombination(maxLength, mappedSegements, bestSegments); if (pacbioDebug) { Log.Message("Best score: %f", bestScore); } float topFragmentScore = 0.0f; int fragmentWithHighestScore = 0; int alignedBpSum = 0; for(int i = 0; i < bestSegments.size(); ++i) { int index = bestSegments[i]; if (pacbioDebug) { Log.Message("\tFragment: %d", index); } mappedSegements[index]->isProcessed = true; alignedBpSum += (mappedSegements[index]->onReadStop - mappedSegements[index]->onReadStart); if(mappedSegements[index]->score > topFragmentScore) { fragmentWithHighestScore = index; topFragmentScore = mappedSegements[index]->score; } } // Set the alignment with the highest score as primary if(bestSegments.size() > 0) { read->Alignments[mappedSegements[fragmentWithHighestScore]->id].primary = true; } float aligned = alignedBpSum * 1.0f / read->length; if(pacbioDebug) { Log.Message("Aligned %.2f%% of read", aligned * 100.0f); } mapped = (Config.getMinResidues() < 1.0) ? aligned > Config.getMinResidues() : alignedBpSum > Config.getMinResidues(); if (pacbioDebug) { Log.Message("%f > %f = %d", aligned, Config.getMinResidues(), mapped); } NGM.Stats->avgAlignPerc += aligned; bestSegments.clear(); float secondBestScore = getBestSegmentCombination(maxLength, mappedSegements, bestSegments); if(pacbioDebug) { Log.Message("Second best score: %f", secondBestScore); } /** * Filter short isolated intervals * TODO: improve */ verbose(0, true, "Filter short isolated alignments"); int const minOnReadLength = 1000; for (int i = 0; i < mappedSegements.size(); ++i) { Interval * a = mappedSegements[i]; if (a->isProcessed) { verbose(1, "Testee: ", a); bool keep = a->lengthOnRead() > std::min(minOnReadLength, (int)(read->length * 0.5f)); for (int j = 0; j < mappedSegements.size() && !keep; ++j) { Interval * b = mappedSegements[j]; if (b != 0 && b->isProcessed) { verbose(2, "Compare: ", b); int distance = getDistanceOnRead(a, b); loc distanceOnRef = (b->onRefStart < a->onRefStart) ? std::max(0ll, a->onRefStart - b->onRefStop) : std::max(0ll, b->onRefStart - a->onRefStop); loc const maxDistance = a->lengthOnRead(); keep = (distance < maxDistance || distanceOnRef < maxDistance) && b->lengthOnRead() > std::min(minOnReadLength, (int)(read->length * 0.5f)); verbose(2, true, "dist: %d, a length * 2: %d, b length: %d -> %d", distance, a->lengthOnRead() * 2, b->lengthOnRead(), keep); } } if (!keep) { verbose(2, true, "Delete"); a->isProcessed = false; } } } // Mark remaining as skipped (will not be written to SAM file) for (int i = 0; i < mappedSegements.size(); ++i) { if(!mappedSegements[i]->isProcessed) { read->Alignments[mappedSegements[i]->id].skip = true; } } int segmentCount = 0; // Set 0x1 (full read is aligned) + debug code for (int i = 0; i < read->Calculated; ++i) { if (!read->Alignments[mappedSegements[i]->id].skip) { if(aligned > 0.95f) { read->Alignments[mappedSegements[i]->id].setBitFlag(0x2); } segmentCount += 1; if (!readIsReverse) { printDotPlotLine(read->ReadId, read->name, mappedSegements[i]->onReadStart, mappedSegements[i]->onReadStop, mappedSegements[i]->onRefStart, mappedSegements[i]->onRefStop, mappedSegements[i]->score, mappedSegements[i]->isReverse, DP_TYPE_RESULT_CONS + mappedSegements[i]->id, DP_STATUS_OK); } else { printDotPlotLine(read->ReadId, read->name, mappedSegements[i]->onReadStop, mappedSegements[i]->onReadStart, mappedSegements[i]->onRefStart, mappedSegements[i]->onRefStop, mappedSegements[i]->score, mappedSegements[i]->isReverse, DP_TYPE_RESULT_CONS + mappedSegements[i]->id, DP_STATUS_OK); } } } int maxSplits = Config.getMaxSegmentNumberPerKb(read->length); mapped = mapped && (segmentCount - 1) <= maxSplits; verbose(0, true, "Splits detected: %d < %d = %d (%d)", segmentCount - 1, maxSplits, mapped, read->length); // Delete all mapped segments for (int i = 0; i < mappedSegements.size(); ++i) { delete mappedSegements[i]; mappedSegements[i] = 0; } if(mapped) { verbose(0, true, "%s (%d) mapped %f with %d fragments", read->name, read->length, aligned * 100.0f, segmentCount); } return mapped; } void sortRead(ReadGroup * group) { MappedRead * read = group->fullRead; float highestScore = 0.0f; int highestScoreIndex = 0; for (int i = 0; i < read->Calculated; ++i) { if (read->Alignments[i].Score > highestScore) { highestScore = read->Alignments[i].Score; highestScoreIndex = i; } } if (highestScoreIndex != 0) { Align tmp = read->Alignments[0]; read->Alignments[0] = read->Alignments[highestScoreIndex]; read->Alignments[highestScoreIndex] = tmp; LocationScore tmpScore = read->Scores[0]; read->Scores[0] = read->Scores[highestScoreIndex]; read->Scores[highestScoreIndex] = tmpScore; } } int AlignmentBuffer::getOverlapOnRead(Interval const * a, Interval const * b) { return std::max(0, std::min(a->onReadStop, b->onReadStop) - std::max(a->onReadStart, b->onReadStart)); } int AlignmentBuffer::getDistanceOnRead(Interval const * a, Interval const * b) { if(b->onReadStart < a->onReadStart) { return std::max(0, a->onReadStart - b->onReadStop); } else { return std::max(0, b->onReadStart - a->onReadStop); } } loc AlignmentBuffer::getDistanceOnRef(Interval const * a, Interval const * b) { if (b->isReverse) { if (b->onRefStop < a->onRefStop) { return std::max(0ll, a->onRefStop - b->onRefStart); } else { return std::max(0ll, b->onRefStop - a->onRefStart); } } else { if (b->onRefStart < a->onRefStart) { return std::max(0ll, a->onRefStart - b->onRefStop); } else { return std::max(0ll, b->onRefStart - a->onRefStop); } } } void AlignmentBuffer::verbose(int const tabs, char const * const s, Interval const * const interval) { verbose(tabs, false, "%s", s); verbose(0, true, "Interval: %d - %d on read, %lu - %lu on ref, Reverse: %d, Score: %f, Anchors: %d", interval->onReadStart, interval->onReadStop, interval->onRefStart, interval->onRefStop, interval->isReverse, interval->score, interval->anchorLength); } void AlignmentBuffer::verbose(int const tabs, bool const newLine, char const * const s, ...) { if(pacbioDebug) { for(int i = 0; i < tabs; ++i) { fprintf(stderr, "\t"); } va_list args; va_start(args, s); vfprintf(stderr, s, args); va_end(args); if(newLine) { fprintf(stderr, "\n"); } } } bool AlignmentBuffer::extendIntervalStop(Interval * interval, int const readBp, int const readLength) { bool extended = false; verbose(0, true, "## Extending interval stop:"); verbose(0, "## ", interval); _SequenceProvider::Chromosome chr = SequenceProvider.getChrBorders(interval->onRefStart, interval->onRefStop); //verbose(0, true, "extendIntervalEnd fro %llu - %llu by %d -- Located on chr %llu - %llu", interval->onRefStart, interval->onRefStop, readBp, chr.start, chr.end); if (chr.start != 0 || chr.end != 0) { verbose(0, true, "extendIntervalStop - Located on chr %llu %llu", chr.start, chr.end); double lengthRatio = std::min(1.0f, interval->lengthOnRead() * 1.0f / interval->lengthOnRef() * 1.0f); int extendOnRead = std::min(readLength - interval->onReadStop, readBp); int extendOnRef = (int) round(extendOnRead / lengthRatio); loc maxExtendOnRef = interval->onRefStop > chr.end ? 0 : chr.end - interval->onRefStop; if (interval->isReverse) { maxExtendOnRef = interval->onRefStop < chr.start ? 0 : interval->onRefStop - chr.start; } if (extendOnRef > maxExtendOnRef) { extendOnRef = maxExtendOnRef; extendOnRead = std::min(extendOnRead, std::max(0, (int) round(extendOnRef * lengthRatio) - 1)); } verbose(1, true, "Min/Max extend on ref: %d/%lld", extendOnRef, maxExtendOnRef); interval->onReadStop += extendOnRead; extended = true; if (interval->isReverse) { interval->onRefStop -= extendOnRef; } else { interval->onRefStop += extendOnRef; } } else { verbose(0, true, "Could not get chromosome for interval"); getchar(); } return extended; } bool AlignmentBuffer::extendIntervalStart(Interval * interval, int const readBp) { bool extended = false; _SequenceProvider::Chromosome chr = SequenceProvider.getChrBorders(interval->onRefStart, interval->onRefStop); verbose(0, true, "extendIntervalStart fro %llu - %llu by %d -- Located on chr %llu - %llu", interval->onRefStart, interval->onRefStop, readBp, chr.start, chr.end); if (chr.start != 0 || chr.end != 0) { double lengthRatio = std::min(1.0f, interval->lengthOnRead() * 1.0f / interval->lengthOnRef() * 1.0f); int extendOnRead = std::min(interval->onReadStart, readBp); int extendOnRef = (int) round(extendOnRead / lengthRatio); loc maxExtendOnRef = interval->onRefStart < chr.start ? 0 : interval->onRefStart - chr.start; if (interval->isReverse) { maxExtendOnRef = interval->onRefStart > chr.end ? 0 : chr.end - interval->onRefStart; } verbose(1, true, "Min/Max extend on ref: %d/%lld", extendOnRef, maxExtendOnRef); if (extendOnRef > maxExtendOnRef) { extendOnRef = maxExtendOnRef; extendOnRead = std::min(extendOnRead, std::max(0, (int) round(extendOnRef * lengthRatio) - 1)); } interval->onReadStart -= extendOnRead; extended = true; if (interval->isReverse) { interval->onRefStart += extendOnRef; } else { interval->onRefStart -= extendOnRef; } } else { verbose(0, true, "Could not get chromosome for interval"); // getchar(); } return extended; } bool AlignmentBuffer::shortenIntervalStart(Interval * interval, int const readBp) { bool shortened = false; if (interval->onReadStart < interval->onReadStop) { double lengthRatio = std::max(1.1f, interval->lengthOnRead() * 1.0f / interval->lengthOnRef() * 1.0f); // lengthRatio = 1.1; int refBp = (int) round(readBp / lengthRatio); if (readBp < interval->lengthOnRead() && refBp < interval->lengthOnRef()) { interval->onReadStart = interval->onReadStart + readBp; interval->onRefStart = interval->isReverse ? interval->onRefStart - refBp : interval->onRefStart + refBp; shortened = true; } } return shortened; } bool AlignmentBuffer::shortenIntervalEnd(Interval * interval, int const readBp) { bool shortened = false; if (interval->onReadStart < interval->onReadStop) { double lengthRatio = std::max(1.1f, interval->lengthOnRead() * 1.0f / interval->lengthOnRef() * 1.0f); // lengthRatio = 1.1; int refBp = (int) round(readBp / lengthRatio); verbose(1, true, "%llu %d", interval->onRefStop, refBp); if (readBp < interval->lengthOnRead() && refBp < interval->lengthOnRef()) { interval->onReadStop = interval->onReadStop - readBp; interval->onRefStop = interval->isReverse ? interval->onRefStop + refBp : interval->onRefStop - refBp; shortened = true; } } return shortened; } float AlignmentBuffer::scoreInterval(Interval * interval, MappedRead * read) { float score = 0.0f; int const tabs = 3; if (interval->onReadStart < interval->onReadStop) { int onReadStart = interval->onReadStart; int onReadStop = interval->onReadStop; auto readSeq = extractReadSeq(interval->lengthOnRead(), onReadStart, interval->isReverse, read, false); if (readSeq != nullptr) { verbose(0, "", interval); loc onRefStart = interval->isReverse ? interval->onRefStop : interval->onRefStart; loc onRefStop = interval->isReverse ? interval->onRefStart : interval->onRefStop; if (onRefStart < onRefStop) { int refSeqLength = 0; auto refSeq = extractReferenceSequenceForAlignment(onRefStart, onRefStop, refSeqLength); if (readSeq != nullptr) { if (refSeq != nullptr) { verbose(tabs, true, "RefSeq: %s", refSeq); verbose(tabs, true, "ReadSeq: %s", readSeq.get()); overlapCheckAligner->SingleScore(0, 0, refSeq, readSeq.get(), score, 0); delete[] refSeq; refSeq = 0; } } } } } return score; } void AlignmentBuffer::processShortRead(MappedRead * read) { // Read is shorter then anchor length verbose(0, true, "Read too short for long read cLIS"); verbose(0, true, "Processing ShortRead: %d - %s (lenght %d)", read->ReadId, read->name, read->length); if (read->numScores() > 0) { //part->Scores[0].Score.f; read->Alignments = new Align[read->numScores()]; LocationScore * tmpScore = new LocationScore[read->numScores()]; int alignIndex = 0; int lastScore = 0; for (int k = 0; k < read->numScores() && ((int) read->Scores[k].Score.f >= lastScore || alignIndex < 2); ++k) { LocationScore loc = read->Scores[k]; lastScore = read->Scores[k].Score.f; if (pacbioDebug) { Log.Message("Hit found with score %f", loc.Score.f); } Interval * interval = new Interval(); int const refExtend = read->length * 0.15f; interval->onReadStart = 0; interval->onReadStop = read->length; interval->onRefStart = loc.Location.m_Location - refExtend; interval->onRefStop = loc.Location.m_Location + read->length + refExtend; interval->isReverse = loc.Location.isReverse(); verbose(0, "Aligning interval: ", interval); int const shortReadCorridor = readPartLength * 1 + 2 * refExtend; Align * align = 0; auto readPartSeq = extractReadSeq(read->length, interval, read); // Align * align = alignInterval(read, interval, read->Seq, read->length, false); if(readPartSeq != nullptr) { align = computeAlignment(interval, shortReadCorridor, readPartSeq.get(), read->length, 0, 0, read->length, read, false, false, true); } bool mapped = align != 0 && align->Score > 0.0f; if(mapped) { if (Config.getMinResidues() < 1.0) { mapped = ((read->length - align->QStart - align->QEnd) * 1.0f / read->length) > Config.getMinResidues(); } else { mapped = (read->length - align->QStart - align->QEnd) > Config.getMinResidues(); } } if (mapped) { align->clearNmPerPosition(); align->MQ = read->mappingQlty; loc.Location.m_Location = interval->onRefStart + align->PositionOffset;//- (corridor >> 1); handled in computeAlingment loc.Location.setReverse(interval->isReverse); loc.Score.f = align->Score; read->Alignments[alignIndex] = *align; read->Calculated += 1; delete align; align = 0; tmpScore[alignIndex] = loc; alignIndex += 1; } else { verbose(0, true, "Alignment failed"); if(align != 0) { align->clearBuffer(); align->clearNmPerPosition(); delete align; align = 0; } } delete interval; interval = 0; } if (read->Scores != 0) { delete[] read->Scores; read->Scores = 0; } read->AllocScores(tmpScore, alignIndex); read->Calculated = alignIndex; delete[] tmpScore; tmpScore = 0; if (alignIndex > 0) { read->Alignments[0].primary = true; WriteRead(read, true); } else { WriteRead(read, false); } } else { WriteRead(read, false); } } bool AlignmentBuffer::gapOverlapsWithInterval(Interval * first, Interval * second, IntervalTree::IntervalTree * intervalsTree, MappedRead * read) { Interval gap; gap.onReadStart = first->onReadStop + 1; gap.onReadStop = std::max(0, second->onReadStart - 1); gap.onRefStart = first->onRefStop; //gap.onRefStart = first->isReverse ? first->onRefStart : first->onRefStop; gap.onRefStop = second->onRefStart; //gap.onRefStop = first->isReverse ? second->onRefStop : second->onRefStart; gap.isReverse = first->isReverse; // verbose(0, "First: ", first); // verbose(0, "Second: ", second); // verbose(0, "Gap: ", &gap); return gapOverlapsWithInterval(&gap, intervalsTree, read); } bool AlignmentBuffer::gapOverlapsWithInterval(Interval * gap, IntervalTree::IntervalTree * intervalsTree, MappedRead * read) { float const minOverlap = 50.0; int const maxLengthAlignmentCheck = 1000; int const minGapLength = (int) (readPartLength * 1.5f); bool overlaps = false; if (gap->onReadStart < gap->onReadStop) { verbose(2, true, "Looking for overlap on read: %d - %d", gap->onReadStart, gap->onReadStop); if (gap->lengthOnRead() > minGapLength) { std::vector > results; intervalsTree->findOverlapping(gap->onReadStart, gap->onReadStop, results); for (auto node : results) { if (!node.value->isProcessed) { verbose(3, "", node.value); Interval * interval = new Interval(); interval->onReadStart = gap->onReadStart; interval->onReadStop = gap->onReadStop; interval->onRefStart = node.value->onRefStart; interval->onRefStop = node.value->onRefStop; interval->isReverse = node.value->isReverse; /** * Long matches to different region (e.g. secondary mappings) should not count as overlap */ //if (node.value->lengthOnRead() < (2 * readPartLength + gap->lengthOnRead())) { if (node.value->lengthOnRead() < ((int)(4.5f * readPartLength) + gap->lengthOnRead())) { int overlap = getOverlapOnRead(node.value, gap); float overlapPercent = overlap * 100.0f / gap->lengthOnRead(); verbose(3, "DEBUG: ", interval); verbose(3, true, "Overlap: %d (%f %%)", overlap, overlapPercent); bool betterScore = true; if (overlapPercent > minOverlap) { if (read != 0 && gap->lengthOnRead() < maxLengthAlignmentCheck) { // Check scores float score1 = scoreInterval(interval, read) / interval->lengthOnRead(); float score2 = scoreInterval(gap, read) / gap->lengthOnRead(); verbose(3, "true", "Short overlap found. Verifying with alignment score per position: %f vs %f", score1, score2); betterScore = score1 > score2; } } overlaps = overlaps || (overlapPercent > minOverlap && betterScore); } else { verbose(3, true, "Overlapping interval too long (%d >= %d)", node.value->lengthOnRead(), (2 * readPartLength + gap->lengthOnRead())); } delete interval; interval = 0; } } } else { verbose(2, true, "Gap too short (%d bp), skipping check", gap->lengthOnRead()); } } return overlaps; } bool AlignmentBuffer::gapToEndOverlapsWithInterval(Interval * second, int const readLength, IntervalTree::IntervalTree * intervalsTree, MappedRead * read) { Interval gap; gap.onReadStart = std::min(readLength, second->onReadStop + 1); gap.onReadStop = readLength; // gap.onRefStart = second->isReverse ? first->onRefStart : first->onRefStop; // gap.onRefStop = second->isReverse ? second->onRefStop : second->onRefStart; return gapOverlapsWithInterval(&gap, intervalsTree, 0); } bool AlignmentBuffer::gapFromStartOverlapsWithInterval(Interval * second, IntervalTree::IntervalTree * intervalsTree, MappedRead * read) { Interval gap; gap.onReadStart = 0; gap.onReadStop = std::max(0, second->onReadStart - 1); // gap.onRefStart = second->isReverse ? first->onRefStart : first->onRefStop; // gap.onRefStop = second->isReverse ? second->onRefStop : second->onRefStart; return gapOverlapsWithInterval(&gap, intervalsTree, 0); } void AlignmentBuffer::closeGapOnRead(Interval * first, Interval * second, int const readLength) { if (first->onReadStop < second->onReadStop) { int distance = getDistanceOnRead(first, second); int maxDistance = (int)(0.25f * readLength); //2 * std::max(first->lengthOnRead(), second->lengthOnRead()); if (distance > 0 && distance < maxDistance) { verbose(3, true, "Closing gap of %d bp", distance); verbose(3, "First: ", first); verbose(3, "Second: ", second); extendIntervalStop(first, distance, readLength); extendIntervalStart(second, distance); verbose(3, "New first: ", first); verbose(3, "New second: ", second); } else { verbose(3, true, "Not closing gap distance > %d", maxDistance); } } } void AlignmentBuffer::extendToReadStart(Interval * interval, int const readLength, IntervalTree::IntervalTree * intervalsTree, MappedRead * read) { //TODO: add interval tree check float const maxReadStartExtend = 0.25f; int const maxExtend = std::min((int) round(readLength * maxReadStartExtend), interval->lengthOnRead()); int extend = interval->onReadStart; if (extend > 0) { if (extend > (readPartLength)) { verbose(2, true, "Extending to read start: %d < %d (%d, %d)", extend, maxExtend, (int) round(readLength * maxReadStartExtend), interval->lengthOnRead()); if (extend <= maxExtend) { if (!gapFromStartOverlapsWithInterval(interval, intervalsTree, read)) { verbose(2, true, "Extending first interval to read start"); extendIntervalStart(interval, extend); } else { verbose(2, true, "Not extending first interval to read start. Overlaps with other interval."); } } else { verbose(2, true, "Not extending first interval to read start. Distance to big."); } } else { verbose(2, true, "Extending first interval to read start"); extendIntervalStart(interval, extend); } } } void AlignmentBuffer::extendToReadStop(Interval * interval, int const readLength, IntervalTree::IntervalTree * intervalsTree, MappedRead * read) { //TODO: add interval tree check float const maxReadStopExtend = 0.25f; int const maxExtend = std::min((int) round(readLength * maxReadStopExtend), interval->lengthOnRead()); int extend = readLength - interval->onReadStop; if (extend > 0) { if (extend > (readPartLength)) { verbose(2, true, "Extending to read stop: %d < %d (%d, %d)", extend, maxExtend, (int) round(readLength * maxReadStopExtend), interval->lengthOnRead()); if (extend <= maxExtend) { if (!gapToEndOverlapsWithInterval(interval, readLength, intervalsTree, read)) { verbose(2, true, "Extending last interval to read stop"); extendIntervalStop(interval, extend, readLength); } else { verbose(2, true, "Not extending last interval to read stop. Overlaps with other interval."); } } else { verbose(2, true, "Not extending last interval to read stop. Distance to big."); } } else { verbose(2, true, "Extending last interval to read stop"); extendIntervalStart(interval, extend); } } } void AlignmentBuffer::processLongReadLIS(ReadGroup * group) { MappedRead * read = group->fullRead; int maxAnchorNumber = 10000; int const maxNumScores = 1000; /** * Get all mapping positions from anchors (non overlapping 256bp parts of reads) * and convert them to Anchor objects * TODO: remove fixed length of 100 */ int maxCandidatesPerReadPart = 100; Timer overallTmr; overallTmr.ST(); if (read->length <= readPartLength) { Log.Message("Should not be here. Short read in long read pipeline."); WriteRead(group->fullRead, false); } /* * Parts of read that were aligned plus MQ of subalignments */ std::vector > treeIntervals; // Log.Message("Processing LongReadLIS: %d - %s (length %d)", read->ReadId, read->name, read->length); verbose(0, true, "Processing LongReadLIS: %d - %s (length %d)", read->ReadId, read->name, read->length); verbose(0, true, "Anchor list:"); Anchor * anchorsFwd = new Anchor[maxAnchorNumber]; int anchorFwdIndex = 0; // float * bestScores = new float[group->readNumber]; // int bestScoresIndex = 0; // for (int j = 0; j < group->readNumber; ++j) { // MappedRead * part = group->reads[j]; // if(part->numScores() > 0) { // bestScores[bestScoresIndex++] = part->Scores[0].Score.f; // } // } // // std::sort(bestScores, bestScores + bestScoresIndex); // // for(int i = 0; i < bestScoresIndex; ++i) { // verbose(1, false, "%f, ", bestScores[i]); // } // verbose(0, true, ""); // float const minScore = bestScores[(int)(bestScoresIndex * 0.8f)]; // verbose(1, true, "Min score: %f", minScore); // // delete[] bestScores; // bestScores = 0; // Log.Message("Read: %s", group->fullRead->name); // Log.Message("Parts: %d", group->readNumber); // for (int j = 0; j < group->readNumber; ++j) { // MappedRead * part = group->reads[j]; // // int positionOnRead = j * readPartLength; // // Log.Message("\tPart %d:", j); // Log.Message("\t\tName: %s", part->name); // Log.Message("\t\tMappings: %d", part->numScores()); // Log.Message("\t\tQuality: %d", part->mappingQlty); // // for (int k = 0; k < part->numScores(); ++k) { // Log.Message("\t\t\t%d, %llu, %f", positionOnRead, part->Scores[k].Location.m_Location, part->Scores[k].Score.f ); // } // // } /** * Collect sub-read mapping locations and * build interval tree with read locations * plus mapping quality */ for (int j = 0; j < group->readNumber; ++j) { MappedRead * part = group->reads[j]; int positionOnRead = j * readPartLength; verbose(1, false, "%d: ", positionOnRead); if (part->numScores() < maxNumScores) { if (part->numScores() > 0) { /** * Add mapped read parts + mapping quality. * Used to estimate MQ for read(part)s */ treeIntervals.push_back(IntervalTree::Interval(positionOnRead, positionOnRead + readPartLength, part->mappingQlty)); for (int k = 0; k < part->numScores(); ++k) { if (stdoutPrintScores) { printf("%f\n", part->Scores[k].Score.f); } /** * Anchor is valid and will be used */ if (anchorFwdIndex >= (maxAnchorNumber - 1)) { verbose(0, true, "Anchor array too small - reallocating."); maxAnchorNumber = maxAnchorNumber * 2; Anchor * anchorsTmp = new Anchor[maxAnchorNumber]; memcpy(anchorsTmp, anchorsFwd, anchorFwdIndex * sizeof(Anchor)); delete[] anchorsFwd; anchorsFwd = anchorsTmp; } Anchor & anchor = anchorsFwd[anchorFwdIndex++]; anchor.score = part->Scores[k].Score.f; anchor.isReverse = part->Scores[k].Location.isReverse(); anchor.type = DP_STATUS_OK; anchor.isUnique = part->numScores() == 1; // || anchor.score > minScore; /** * It would be best to convert reads or read parts that map to the negative strand * Immediately to plus strand. * If somebody tells me how to do this properly, I'll happily change this. * For now Anchors can be on the plus or minus strand! * Problem: Transforming coordinates from negative anchors to plus strand * is not possible without knowing if the read originates from the plus * or the minus strand. This is difficult for reads with few matching anchors * and reads that originate from e.g. an inverted translocation. */ anchor.onRead = positionOnRead; anchor.onRef = part->Scores[k].Location.m_Location; if (anchor.isReverse) { printDotPlotLine(group->fullRead->ReadId, group->fullRead->name, anchor.onRead, anchor.onRead + readPartLength, part->Scores[k].Location.m_Location + readPartLength, part->Scores[k].Location.m_Location, part->Scores[k].Score.f, part->Scores[k].Location.isReverse(), DP_TYPE_UNFILTERED, anchor.isUnique ? DP_STATUS_OK : DP_STATUS_LOWSCORE); } else { printDotPlotLine(group->fullRead->ReadId, group->fullRead->name, anchor.onRead, anchor.onRead + readPartLength, part->Scores[k].Location.m_Location, part->Scores[k].Location.m_Location + readPartLength, part->Scores[k].Score.f, part->Scores[k].Location.isReverse(), DP_TYPE_UNFILTERED, anchor.isUnique ? DP_STATUS_OK : DP_STATUS_LOWSCORE); } if (k < 3) { double const K = 1 / 3; double const lambda = 1.098612; double const n = 256; double const m = 3000000000; double const Y = part->Scores[k].Score.f; double pVal = 1 - exp(-K * n * m * exp(-lambda * Y)); verbose(0, false, "%f (%f) at %llu, ", part->Scores[k].Score.f, pVal, part->Scores[k].Location.m_Location); } else if (k == 3) { verbose(0, false, "... (%d)", part->numScores()); } } verbose(0, true, ""); } else { verbose(0, true, "no hits found"); printDotPlotLine(group->fullRead->ReadId, group->fullRead->name, positionOnRead, positionOnRead + readPartLength, 0, 0, 0.0f, 0, DP_TYPE_UNFILTERED, DP_STATUS_NOHIT); } } else { verbose(0, true, "too many hits found"); printDotPlotLine(group->fullRead->ReadId, group->fullRead->name, positionOnRead, positionOnRead + readPartLength, 0, 0, 0.0f, 0, DP_TYPE_UNFILTERED, DP_STATUS_NOHIT); } } Anchor * anchorsRev = new Anchor[maxAnchorNumber]; int anchorRevIndex = 0; /** * Tree contains all mapped read parts + MQ */ readCoordsTree = new IntervalTree::IntervalTree(treeIntervals); /** * Build HSP from sub read mappings (cLIS) * - Sort sub-reads by read position * - Compute max. number of HSP (based on read length) * - Run cLIS algorithm on reference positions to retrieve HSP * - If isUnique, build Interval from sub-read set and compute regression */ int nIntervals = 0; Interval * * intervals = getIntervalsFromAnchors(nIntervals, anchorsFwd, anchorFwdIndex, anchorsRev, anchorRevIndex, group->fullRead); verbose(0, true, "\nIntervals after cLIS:"); for (int i = 0; i < nIntervals; ++i) { verbose(0, "", intervals[i]); } verbose(0, true, ""); std::sort(intervals, intervals + nIntervals, sortIntervalsInSegment); std::vector > intervalList; verbose(0, true, "\n\nBuilding segments:\n"); /** * A segment is a list of intervals that are located in on alignment corridor * Intervals that are contained in others will be deleted. All the others * will be added to a segment */ int const maxMappedSegementCount = nIntervals + 1; MappedSegment * segments = new MappedSegment[maxMappedSegementCount]; size_t segementsIndex = 0; for (int i = 0; i < nIntervals; ++i) { Interval * interval = intervals[i]; bool intervalProcessed = false; verbose(0, "Current interval: ", interval); for (int j = 0; j < segementsIndex && !intervalProcessed; ++j) { verbose(1, true, "Checking segment %d", j); for (int k = 0; k < segments[j].length && !intervalProcessed; ++k) { Interval * processedInterval = segments[j].list[k]; verbose(2, "Comparing to interval: ", processedInterval); if (isContained(interval, processedInterval)) { // Interval is contained in already processed interval and therefore ignored intervalProcessed = true; verbose(3, true, "Is contained. Deleting interval."); delete intervals[i]; intervals[i] = 0; interval = 0; } else { if (isCompatible(interval, processedInterval)) { verbose(3, true, "Is compatible"); // Interval fits corridor of segment if (segments[j].length < segments[j].maxLength) { segments[j].list[segments[j].length++] = interval; intervalProcessed = true; intervalList.push_back(IntervalTree::Interval(interval->onReadStart, interval->onReadStop, interval)); } } else { verbose(3, true, "Not contained and not compatible"); } } } } if (!intervalProcessed) { // Creating new segment for interval verbose(1, true, "Creating new segment %d", segementsIndex); if (segementsIndex < maxMappedSegementCount) { segments[segementsIndex].list[0] = interval; segments[segementsIndex++].length = 1; intervalList.push_back(IntervalTree::Interval(interval->onReadStart, interval->onReadStop, interval)); } else { Log.Error("Could not create new segment (%d, %d) for read %s", segementsIndex, maxMappedSegementCount, read->name); } } } /** * All intervals are either deleted or added to segments. */ delete[] intervals; intervals = 0; // Join segments if (pacbioDebug) { Log.Message("\nSegments identified: %d", segementsIndex); for(int i = 0; i < segementsIndex; ++i) { Log.Message("Segment %d contains %d intervals", i, segments[i].length); } } IntervalTree::IntervalTree * intervalsTree = new IntervalTree::IntervalTree(intervalList); verbose(0, true, "\n\nMerging segments:\n"); // Final interval list intervals = new Interval *[maxSegmentCount + 1]; nIntervals = 0; Interval * * delIntervals = new Interval *[maxSegmentCount + 1]; int nDelIntervals = 0; /** * Joins segments to full length alignments * - try to identify all segments that fall into an alignment corridor * - merge segments that are separated by regions with high error rate * - merge segments that are separated by small indels (only if both segments are long enough to compensate the score penalty of the deletion) * - Extend unmerged segments to cover the full read an compensate for missed subread mappings * - Don't merge segments if separated by a read part that maps to a different place on the genome or is inverted (balanced translocation) */ verbose(0, true, "Joining segments to intervals:"); for (int i = 0; i < segementsIndex; ++i) { // Sort intervals by position on read std::sort(segments[i].list, segments[i].list + segments[i].length, sortIntervalsInSegment); if (pacbioDebug) { Log.Message("Segment %d:", i); for(int j = 0; j < segments[i].length; ++j) { verbose(0, "Interval: ", segments[i].list[j]); } } Interval * lastInterval = segments[i].list[0]; extendIntervalStart(lastInterval, 2 * readPartLength); bool isFirstInterval = true; Interval * currentInterval = 0; for (int j = 1; j < segments[i].length; ++j) { currentInterval = segments[i].list[j]; verbose(1, "Last: ", lastInterval); verbose(1, "Current: ", currentInterval); if (isSameDirection(currentInterval, lastInterval)) { verbose(2, true, "Same direction."); loc dupLength = 0; if (!isDuplication(currentInterval, lastInterval, dupLength)) { if(gapOverlapsWithInterval(lastInterval, currentInterval, intervalsTree, read)) { /*** * Possible translocation */ verbose(2, true, "Overlap found in other corridor."); verbose(2, true, "Saving last interval. Using current to go on."); if (isFirstInterval) { extendToReadStart(lastInterval, read->length, intervalsTree, read); isFirstInterval = false; } //TODO: close gap on read (imporve) extendIntervalStop(lastInterval, 2 * readPartLength, read->length); extendIntervalStart(currentInterval, 2 * readPartLength); //Add lastInterval intervals[nIntervals++] = lastInterval; lastInterval = currentInterval; } else { /** * Insertion, deletion or gap */ REAL const corridorSize = std::min(4096, std::min(currentInterval->lengthOnRead(), lastInterval->lengthOnRead())); verbose(2, true, "IsContained in corridor of %f.", corridorSize); if (canSpanDeletionInsertion(currentInterval, lastInterval, corridorSize) && !spansChromosomeBorder(currentInterval, lastInterval)) { /** * Deletion or insertion small enough for alignment without split */ verbose(2, true, "Not a duplication, not overlapping with other corridor. Merging current and last interval. Deleting current interval."); lastInterval = mergeIntervals(lastInterval, currentInterval); segments[i].list[j]->isProcessed = true; delIntervals[nDelIntervals++] = segments[i].list[j]; } else { /** * Deletion, insertion or gap */ verbose(2, true, "Diagonal offset between intervals too big (max %f) or spans chromosome border.", corridorSize); verbose(2, true, "Saving last interval. Using current to go on."); if (isFirstInterval) { extendToReadStart(lastInterval, read->length, intervalsTree, read); isFirstInterval = false; } closeGapOnRead(lastInterval, currentInterval, read->length); extendIntervalStop(lastInterval, 2 * readPartLength, read->length); extendIntervalStart(currentInterval, 2 * readPartLength); //Add lastInterval intervals[nIntervals++] = lastInterval; lastInterval = currentInterval; } } } else { /** * Duplication */ verbose(2, true, "Covers possible duplication."); verbose(2, true, "Saving last interval. Using current to go on."); if (isFirstInterval) { extendToReadStart(lastInterval, read->length, intervalsTree, read); isFirstInterval = false; } closeGapOnRead(lastInterval, currentInterval, read->length); // Extension necessary since border can be wrong even if there is no gap on the read int maxExtend = std::min(std::max(currentInterval->onReadStart - lastInterval->onReadStop + (int)dupLength, 0), 2 * readPartLength); verbose(2, true, "Duplication stats: %d - %d + %d, %d => %d", currentInterval->onReadStart, lastInterval->onReadStop, (int)dupLength, 2 * readPartLength, maxExtend); // int maxExtend = 2 * readPartLength; extendIntervalStop(lastInterval, maxExtend, read->length); extendIntervalStart(currentInterval, maxExtend); //Add lastInterval intervals[nIntervals++] = lastInterval; lastInterval = currentInterval; } } else { /** * Inversion */ verbose(2, true, "Not in same direction."); verbose(2, true, "Saving last interval. Using current to go on."); if (isFirstInterval) { extendToReadStart(lastInterval, read->length, intervalsTree, read); isFirstInterval = false; } closeGapOnRead(lastInterval, currentInterval, read->length); extendIntervalStop(lastInterval, 2 * readPartLength, read->length); extendIntervalStart(currentInterval, 2 * readPartLength); //Add lastInterval intervals[nIntervals++] = lastInterval; lastInterval = currentInterval; } } if (isFirstInterval) { extendToReadStart(lastInterval, read->length, intervalsTree, read); isFirstInterval = false; } extendIntervalStop(lastInterval, 2 * readPartLength, read->length); verbose(2, true, "Extending last interval to read end", intervalsTree); extendToReadStop(lastInterval, read->length, intervalsTree, read); verbose(1, "Last: ", lastInterval); verbose(2, true, "Saving last interval."); intervals[nIntervals++] = lastInterval; } delete[] segments; segments = 0; delete intervalsTree; intervalsTree = 0; for (int i = 0; i < nDelIntervals; ++i) { delete delIntervals[i]; delIntervals[i] = 0; } delete[] delIntervals; delIntervals = 0; nDelIntervals = 0; verbose(0, true, "Joined intervals:"); for (int i = 0; i < nIntervals; ++i) { verbose(1, "", intervals[i]); } verbose(0, true, "Sorting intervals by read start"); std::sort(intervals, intervals + nIntervals, sortIntervalsInSegment); if (nIntervals > 0) { Interval * lastInterval = intervals[0]; for (int i = 1; i < nIntervals; ++i) { Interval * currentIntervl = intervals[i]; if (currentIntervl->anchorLength > 1) { verbose(1, "a:", lastInterval); verbose(1, "b: ", currentIntervl); if (!isCompatible(lastInterval, currentIntervl) && getDistanceOnRead(lastInterval, currentIntervl) > 0 && (currentIntervl->anchorLength > 2 || lastInterval->anchorLength > 2)) { verbose(1, true, "Closing gap between:"); closeGapOnRead(lastInterval, currentIntervl, read->length); } else { verbose(1, true, "Skip"); } } if (currentIntervl->anchorLength > 1 || lastInterval->anchorLength == 1) { lastInterval = currentIntervl; } } } /** * Sort intervals by score * Important because, we trust intervals with higher * score more. Thus we align them first. Aligned intervals * are considered fixed. Therefore, all unangliend intervals will * be trimmed in order to not overlap with fixed intervals. */ verbose(0, true, "Sorting intervals by score"); std::sort(intervals, intervals + nIntervals, sortIntervalsByScore); int readBpCovered = 0; verbose(0, true, "\nFinal intervals:"); for (int i = 0; i < nIntervals; ++i) { verbose(1, "", intervals[i]); printDotPlotLine(read->ReadId, read->name, intervals[i]->onReadStart, intervals[i]->onReadStop, intervals[i]->onRefStart, intervals[i]->onRefStop, intervals[i]->score, intervals[i]->isReverse, DP_TYPE_SEQMENTS_CONS + i, DP_STATUS_OK); readBpCovered += intervals[i]->lengthOnRead(); } float aligned = readBpCovered * 1.0f / read->length; verbose(0, true, "Intervals cover %.2f%% of read", aligned * 100.0f); bool mapped = (Config.getMinResidues() < 1.0) ? aligned > Config.getMinResidues() : readBpCovered > Config.getMinResidues(); if (!mapped) { verbose(0, true, "Clearing intervals -> read unmapped"); for (int i = 0; i < nIntervals; ++i) { if (intervals[i] != 0) { delete intervals[i]; intervals[i] = 0; } } delete[] intervals; intervals = 0; nIntervals = 0; } /** * Align final intervals to the reference */ if (nIntervals != 0) { // Since we don't know how many segments of the read we have to align in the // end we need temp arrays to store them // TODO: remove fixed upper limit LocationScore * tmpLocationScores = new LocationScore[nIntervals * 4]; Align * tmpAlingments = new Align[nIntervals * 4]; int nTempAlignments = 0; read->Calculated = 0; Timer tmr; if (pacbioDebug) { tmr.ST(); } /** * Aligning intervals */ for (int i = 0; i < nIntervals; ++i) { Interval * currentInterval = intervals[i]; /** * Adjust unanglined intervals to not overlap with already * aligned intervals */ verbose(0, "Aligning interval: ", currentInterval); for (int j = 0; j < nTempAlignments; ++j) { Interval * alignedInterval = tmpAlingments[j].mappedInterval; verbose(1, "Check overlap with: ", alignedInterval); int overlap = getOverlapOnRead(currentInterval, alignedInterval); verbose(1, true, "Overlap: %d", overlap); if (overlap > 0 && overlap < currentInterval->lengthOnRead() * 0.95f) { verbose(0, true, "Adjusting interval"); if (currentInterval->onReadStart < alignedInterval->onReadStart) { shortenIntervalEnd(currentInterval, overlap); } else { shortenIntervalStart(currentInterval, overlap); } } } verbose(0, "New interval: ", currentInterval); /** * Convert intervals on reverse strand to forward strand */ if (currentInterval->onRefStart > currentInterval->onRefStop) { loc tmp = currentInterval->onRefStart; currentInterval->onRefStart = currentInterval->onRefStop; currentInterval->onRefStop = tmp; } verbose(0, "Aligning interval: ", currentInterval); if (!Config.getSkipalign()) { alignSingleOrMultipleIntervals(read, currentInterval, tmpLocationScores, tmpAlingments, nTempAlignments); } else { Log.Message("Skipping alignment computation."); } if (nTempAlignments > 0) { verbose(0, "Aligned interval: ", tmpAlingments[nTempAlignments - 1].mappedInterval); } } if (pacbioDebug) { Log.Message("Alignment took %fs", tmr.ET()); } read->AllocScores(tmpLocationScores, nTempAlignments); read->Alignments = tmpAlingments; delete[] tmpLocationScores; tmpLocationScores = 0; /** * Process alignments: removed short alignments, choos combination of aligned segments * that have the highest score and cover the read best */ if (read->Calculated > 0) { bool mapped = reconcileRead(group); if (mapped) { sortRead(group); } else { verbose(0, true, "%s (%d) not mapped", read, read->length); } WriteRead(group->fullRead, mapped); } else { verbose(0, true, "%s (%d) not mapped", read, read->length); WriteRead(group->fullRead, false); } } else { verbose(0, true, "%s (%d) not mapped. No candidates found for read: unmapped.", read, read->length); //No candidates found for read WriteRead(group->fullRead, false); } delete[] anchorsFwd; anchorsFwd = 0; delete[] anchorsRev; anchorsRev = 0; if (intervals != 0) { for (int i = 0; i < nIntervals; ++i) { if (intervals[i] != 0) { delete intervals[i]; intervals[i] = 0; } } delete[] intervals; intervals = 0; nIntervals = 0; } delete readCoordsTree; readCoordsTree = 0; processTime += overallTmr.ET(); verbose(0, true, "###########################################"); verbose(0, true, "###########################################"); verbose(0, true, "###########################################"); verbose(0, true, ""); } void AlignmentBuffer::SaveRead(MappedRead * read, bool mapped) { WriteRead(read, mapped); } void AlignmentBuffer::WriteRead(MappedRead* read, bool mapped) { if (mapped) { //Convert mapping position to RefId and position for (int i = 0; i < read->Calculated; ++i) { //TODO: fix for -n > 1 //Instead of setting mapped to false set score to 0 and don't print it in the end mapped = SequenceProvider.convert(read->Scores[i].Location); } } m_Writer->WriteRead(read, mapped); NGM.GetReadProvider()->DisposeRead(read); } ngmlr-0.2.7+git20210816.a2a31fb/src/AlignmentBuffer.h000066400000000000000000000320271410636150300213730ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __OUTPUT_H__ #define __OUTPUT_H__ #include "GenericReadWriter.h" #include #include "ILog.h" #include "IConfig.h" #include "intervaltree/IntervalTree.h" #include "LinearRegression.h" #include "ConvexAlign.h" #include "ConvexAlignFast.h" #include "StrippedSW.h" #include "SAMWriter.h" #undef module_name #define module_name "OUTPUT" using std::unique_ptr; //#define TEST_ALIGNER static bool sortAnchorOnRead(Anchor a, Anchor b) { return a.onRead < b.onRead; } static bool sortAnchorOnReadRev(Anchor a, Anchor b) { return a.onRead > b.onRead; } static bool sortAnchorOnRef(Anchor a, Anchor b) { return a.onRef < b.onRef; } class AlignmentBuffer { private: struct Alignment { MappedRead * read; int scoreId; }; float processTime; float alignTime; // float overallTime; GenericReadWriter* m_Writer; static bool first; IAlignment * aligner; #ifdef TEST_ALIGNER IAlignment * alignerFast; #endif IAlignment * overlapCheckAligner; bool const pacbioDebug; bool stdoutPrintDotPlot; bool stdoutInversionBed; bool stdoutErrorProfile; bool printInvCandidateFa; bool stdoutPrintMappedSegments; bool stdoutPrintAlignCorridor; bool stdoutPrintScores; IntervalTree::IntervalTree * readCoordsTree; int const readPartLength; int maxSegmentCount; // float const maxIntervalNumberPerKb; // int intervalBufferIndex; // Interval ** intervalBuffer; void debugAlgnFinished(MappedRead * read); // int alignmentCheckForInversion(int const inversionLength, // const int refCheckLength, SequenceLocation inversionCheckLocation, // uloc inversionMidpointOnRead, const char* const readName, // int inversionNumber, char* fullReadSeq); public: #define DP_TYPE_UNFILTERED 0 #define DP_TYPE_CLIS 1 #define DP_TYPE_SEQMENTS 200 #define DP_TYPE_SEQMENTS_REG 300 #define DP_TYPE_SEQMENTS_CONS 400 #define DP_TYPE_RESULT 600 #define DP_TYPE_RESULT_CONS 800 #define DP_STATUS_OK 0 #define DP_STATUS_REPETITIVE 1 #define DP_STATUS_NOHIT 2 #define DP_STATUS_LOWSCORE 3 #define DP_STATUS_NOCOORDS 4 #define SV_NONE 0 #define SV_INVERSION 1 #define SV_TRANSLOCATION 2 #define SV_UNKNOWN 3 // A list of intervals that are "compatible" meaning they are located in // a "corridor" that is small enough to be handled by the alignment // algorithm // TODO: remove fixed length! struct MappedSegment { static int const maxLength = 1000; Interval * list[maxLength]; size_t length; MappedSegment() { length = 0; } }; int * cLIS(Anchor * anchors, int const anchorsLenght, int & lisLength); /** * Checks if shorter interval is long enough to span deletion/insertion * (if present). Only if intervals are close on read or on reference. * Returns true if there is a large gap between intervals */ bool canSpanDeletionInsertion(Interval const * a, Interval const * b, REAL corridorSize); /** * Checks whether the gap between two intervals spans a chromosome border */ bool spansChromosomeBorder(Interval const * a, Interval const * b); void addAnchorAsInterval(Anchor const & anchor, MappedSegment & segment); Interval * toInterval(Anchor const & anchor); /** * Test if interval is contained in corridor */ bool isIntervalInCorridor(REAL k, REAL d, REAL corridor, Interval const * testee, bool const switched); bool isCompatible(Interval const * a, Interval const * b, REAL corridorSize = 8192.0); // bool isCompatible(Anchor const & anchor, MappedSegment const & segment); // bool isCompatible(Anchor const & anchor, Interval const * interval); bool isContained(Interval const * a, Interval const * b); bool isSameDirection(Interval const * a, Interval const * b); bool isDuplication(Interval const *, Interval const *, loc & dupLength); /** * Distance between two intervals on read */ int getDistanceOnRead(Interval const * a, Interval const * b); /** * Distance between two intervals on ref */ loc getDistanceOnRef(Interval const * a, Interval const * b); /** * Returns the number of overlapping read bps between the two intervals */ int getOverlapOnRead(Interval const * a, Interval const * b); /** * Prints message if --verbose is specified. * Adds tabstops before printing */ void verbose(int const tabs, bool const newLine, char const * const s, ...); /** * Print interval if --verbose is specified */ void verbose(int const tabs, char const * const s, Interval const * const interval); /** * Removes bp from the start of an interval. * RefBp are estimated from the ratio of total ref and read bp in * the interval. */ bool shortenIntervalStart(Interval * interval, int const readBp); /** * Removes bp from the end of an interval. * RefBp are estimated from the ratio of total ref and read bp in * the interval. */ bool shortenIntervalEnd(Interval * interval, int const readBp); bool extendIntervalStart(Interval * interval, int const readBp); bool extendIntervalStop(Interval * interval, int const readBp, int const readLength); /** * Check if gap between first and second interval overlaps with another interval */ bool gapOverlapsWithInterval(Interval * first, Interval * second, IntervalTree::IntervalTree * intervalsTree, MappedRead * read); /** * Checks if interval overlaps with any other interval in interval tree */ bool gapOverlapsWithInterval(Interval * gap, IntervalTree::IntervalTree * intervalsTree, MappedRead * read); /** * Checks if gap between second and read end overlaps with any other interval */ bool gapToEndOverlapsWithInterval(Interval * second, int const readLength, IntervalTree::IntervalTree * intervalsTree, MappedRead * read); /** * Checks if gap between read start and second overlaps with any other interval */ bool gapFromStartOverlapsWithInterval(Interval * second, IntervalTree::IntervalTree * intervalsTree, MappedRead * read); /** * Extends both intervals to close the gap on the read */ void closeGapOnRead(Interval * first, Interval * second, int const readLength); /** * Extends interval to read start, if not overlapping with other interval */ void extendToReadStart(Interval * interval, int const readLength, IntervalTree::IntervalTree * intervalsTree, MappedRead * read); /** * Extends interval to read stop, if not overlapping with other interval */ void extendToReadStop(Interval * interval, int const readLength, IntervalTree::IntervalTree * intervalsTree, MappedRead * read); /** * Compute alignment band with fixed length from anchors */ CorridorLine * getCorridorEndpointsWithAnchors(Interval const * interval, int const corridorMultiplier, char const * refSeq, char const * readSeq, int & corridorHeight, int const externalQStart, int const readPartLength, int const fullReadLength, bool const realign); Interval * mergeIntervals(Interval * a, Interval * b); Interval * * infereCMRsfromAnchors(int & intervalsIndex, Anchor * allFwdAnchors, int allFwdAnchorsLength, Anchor * allRevAnchors, int allRevAnchorsLength, MappedRead * read); Interval * * getIntervalsFromAnchors(int & intervalsIndex, Anchor * allFwdAnchors, int allFwdAnchorsLength, Anchor * allRevAnchors, int allRevAnchorsLength, MappedRead * read); Align computeAlignment(MappedRead* read, int const scoreId, int const corridor); Align * computeAlignment(Interval const * interval, int const corridor, char const * const readSeq, size_t const readLength, int const QStart, int const QEnd, int fullReadLength, MappedRead const * const read, bool const realign, bool const fullAlignment, bool const shortRead); int estimateCorridor(Interval const * interval); unique_ptr extractReadSeq(int const readSeqLen, Interval const * interval, MappedRead* read, bool const revComp = false); unique_ptr extractReadSeq(int const readSeqLen, int const onReadStart, bool const isReverse, MappedRead* read, bool const revComp); Align * alignInterval(MappedRead const * const read, Interval const * interval, char const * const readSeq, size_t const readSeqLen, bool const realign, bool const fullAlignment); void alignSingleOrMultipleIntervals(MappedRead * read, Interval const * const interval, LocationScore * tmp, Align * tmpAling, int & alignIndex); int realign(int const svType, Interval const * interval, Interval * leftOfInv, Interval * rightOfInv, MappedRead * read, Align * tmpAling, int & alignIndex, LocationScore * tmp, int mq); bool constructMappedSegements(MappedSegment * segments, Interval * interval, size_t & segmentsIndex); bool reconcileRead(ReadGroup * group); Interval * getIntervalFromAlign(Align const * const align, LocationScore const * const score, int const i, int const readLength); Interval * * consolidateSegments(MappedSegment * segments, size_t segmentsIndex, int & intervalsIndex); void consolidateSegment(Interval * interval, int & intervalsIndex, MappedSegment segment); int detectMisalignment(Align const * const align, Interval const * interval, char const * const readPartSeq, Interval * leftOfInv, Interval * rightOfInv, MappedRead * read); int checkForSV(Align const * const align, Interval const * interval, char const * const fullReadSeq, uloc inversionMidpointOnRef, uloc inversionMidpointOnRead, int inversionLength, MappedRead * read); /** * Align interval using StrippedSW and return score */ float scoreInterval(Interval * interval, MappedRead * read); /** * Extracts sequence from reference genome */ char const * const extractReferenceSequenceForAlignment(Interval const*& interval, int & refSeqLength); /** * Extracts sequence from reference genome */ char const * const extractReferenceSequenceForAlignment(loc const onRefStart, loc const onRefStop, int & refSeqLength); void processLongReadLIS(ReadGroup * group); void processShortRead(MappedRead * read); int computeMappingQuality(Align const & alignment, int readLength); void printDotPlotLine(int const id, char const * const name, int const onReadStart, int const onReadStop, loc const onRefStart, loc const onRefStop, float const score, bool const isReverse, int const type, int const status); void printDotPlotLine(int const id, char const * const name, REAL const m, REAL const b, REAL const r, float const score, bool const isReverse, int const type, int const status); AlignmentBuffer(const char* const filename) : pacbioDebug(Config.getVerbose()), readCoordsTree(0), readPartLength(Config.getReadPartLength()), maxSegmentCount(0)/*, maxIntervalNumberPerKb(Config.getMaxSegmentNumberPerKb())*/ { m_Writer = (GenericReadWriter*) new SAMWriter((FileWriter*) NGM.getWriter()); if (first) { m_Writer->WriteProlog(); first = false; } processTime = 0.0f; // overallTime = 0.0f; alignTime = 0.0f; stdoutPrintDotPlot = Config.getStdoutMode() == 1; stdoutInversionBed = Config.getStdoutMode() == 2; stdoutErrorProfile = Config.getStdoutMode() == 3; printInvCandidateFa = Config.getStdoutMode() == 4; stdoutPrintMappedSegments = Config.getStdoutMode() == 5; stdoutPrintAlignCorridor = Config.getStdoutMode() == 6; stdoutPrintScores = Config.getStdoutMode() == 7; Log.Verbose("Alignment batchsize = %i", batchSize); // IAlignment * aligner = new StrippedSW(); if (Config.getNoSSE()) { aligner = new Convex::ConvexAlign( Config.getStdoutMode(), Config.getScoreMatch(), Config.getScoreMismatch(), Config.getScoreGapOpen(), Config.getScoreExtendMax(), Config.getScoreExtendMin(), Config.getScoreGapDecay()); } else { aligner = new Convex::ConvexAlignFast( Config.getStdoutMode(), Config.getScoreMatch(), Config.getScoreMismatch(), Config.getScoreGapOpen(), Config.getScoreExtendMax(), Config.getScoreExtendMin(), Config.getScoreGapDecay()); } #ifdef TEST_ALIGNER alignerFast = new Convex::ConvexAlignFast(0); #endif overlapCheckAligner = new StrippedSW(); } virtual ~AlignmentBuffer() { delete m_Writer; m_Writer = nullptr; delete aligner; aligner = nullptr; #ifdef TEST_ALIGNER delete alignerFast; alignerFast = nullptr; #endif if(overlapCheckAligner != nullptr) { delete overlapCheckAligner; overlapCheckAligner = nullptr; } } int GetStage() const { return 4; } inline const char* GetName() const { return "Output"; } float getTime() { // float tmp = overallTime; // overallTime = 0; return 0; } float getProcessTime() { float tmp = processTime; // processTime = 0; return tmp; } float getAlignTime() { float tmp = alignTime; // alignTime = 0; return tmp; } void SaveRead(MappedRead* read, bool mapped = true); void WriteRead(MappedRead* read, bool mapped); } ; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/AlignmentMatrix.cpp000066400000000000000000000122001410636150300217500ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "AlignmentMatrix.h" #include #include using std::cerr; namespace Convex { AlignmentMatrix::AlignmentMatrix() : STOP(CIGAR_STOP), defaultMatrixSize((ulong) 30000 * (ulong) 9000) { privateMatrixHeight = 0; privateMatrixWidth = 0; corridorLines = 0; privateMatrixSize = defaultMatrixSize; directionMatrix = new char[privateMatrixSize]; currentLine = 0; lastLine = 0; lastY = 0; currentY = 0; } void AlignmentMatrix::prepare(int const width, int const height, CorridorLine * corridor, int const corridorHeight) { privateMatrixHeight = height; privateMatrixWidth = width; corridorLines = corridor; ulong matrixSize = 0; int maxCorridorLength = 0; for (int i = 0; i < corridorHeight; ++i) { corridorLines[i].offsetInMatrix = matrixSize; matrixSize += corridorLines[i].length; maxCorridorLength = std::max(maxCorridorLength, corridorLines[i].length); } if (matrixSize > privateMatrixSize) { //fprintf(stderr, "Reallocating matrix for alignment\n"); delete[] directionMatrix; directionMatrix = 0; directionMatrix = new char[matrixSize]; privateMatrixSize = matrixSize; } currentLine = new MatrixElement[maxCorridorLength]; lastLine = new MatrixElement[maxCorridorLength]; } void AlignmentMatrix::clean() { if (currentLine != 0) { delete[] currentLine; currentLine = 0; } if (lastLine != 0) { delete[] lastLine; lastLine = 0; } if (privateMatrixSize > defaultMatrixSize) { delete[] directionMatrix; privateMatrixSize = defaultMatrixSize; directionMatrix = new char[privateMatrixSize]; } } AlignmentMatrix::~AlignmentMatrix() { if (directionMatrix != 0) { delete[] directionMatrix; directionMatrix = 0; } if (currentLine != 0) { delete[] currentLine; currentLine = 0; } if (lastLine != 0) { delete[] lastLine; lastLine = 0; } } void AlignmentMatrix::printMatrix(char const * refSeq, char const * qrySeg) { fprintf(stderr, " - "); for (int x = 0; x < privateMatrixWidth; ++x) { fprintf(stderr, " %c ", refSeq[x]); } fprintf(stderr, "\n"); for (int y = -1; y < privateMatrixHeight; ++y) { if (y == -1) { fprintf(stderr, "-: "); } else { fprintf(stderr, "%c: ", qrySeg[y]); } for (int x = -1; x < privateMatrixWidth; ++x) { fprintf(stderr, "%*d ", 3, (int) *getDirection(x, y)); } fprintf(stderr, "\n"); } } AlignmentMatrix::Score AlignmentMatrix::getScore(int const x, int const y) { return getElement(x, y)->score; } int AlignmentMatrix::getCorridorOffset(int const y) const { return corridorLines[y].offset; } int AlignmentMatrix::getCorridorLength(int const y) const { return corridorLines[y].length; } int AlignmentMatrix::getHeight() const { return privateMatrixHeight; } int AlignmentMatrix::getWidth() const { return privateMatrixWidth; } AlignmentMatrix::MatrixElement * AlignmentMatrix::getElement(int const x, int const y) { if (y < 0 || x < 0) { return ∅ } if (y != currentY && y != lastY) { fprintf(stderr, "Index not found\n"); throw "Index not found"; } else if (y == currentY) { if (x < currentCorridor.offset || x >= (currentCorridor.offset + currentCorridor.length)) { return ∅ } return currentLine + (x - currentCorridor.offset); } else { // y == lastY if (x < lastCorridor.offset || x >= (lastCorridor.offset + lastCorridor.length)) { return ∅ } return lastLine + (x - lastCorridor.offset); } return 0; } AlignmentMatrix::MatrixElement * AlignmentMatrix::getElementEdit(int const x, int const y) { if (y < 0 || x < 0) { fprintf(stderr, "Element not found in alignment matrix.\n"); throw ""; } if (y != currentY && y != lastY) { fprintf(stderr, "Index not found\n"); throw "Index not found"; } else if (y == currentY) { if (x < currentCorridor.offset || x >= (currentCorridor.offset + currentCorridor.length)) { fprintf(stderr, "Element not found in alignment matrix.\n"); throw ""; } return currentLine + (x - currentCorridor.offset); } else { // y == lastY if (x < lastCorridor.offset || x >= (lastCorridor.offset + lastCorridor.length)) { fprintf(stderr, "Element not found in alignment matrix.\n"); throw ""; } return lastLine + (x - lastCorridor.offset); } return 0; } char * AlignmentMatrix::getDirection(int const x, int const y) { if (y < 0 || y > (privateMatrixHeight - 1) || x < 0) { return &STOP; } else { CorridorLine line = corridorLines[y]; if (x < line.offset || x >= (line.offset + line.length)) { return &STOP; } return directionMatrix + line.offsetInMatrix + (x - line.offset); } } bool AlignmentMatrix::prepareLine(int const y) { if (y < 0 || y > getHeight()) { return false; } MatrixElement * tmp = lastLine; lastLine = currentLine; lastY = currentY; lastCorridor = currentCorridor; currentLine = tmp; currentY = y; currentCorridor = corridorLines[currentY]; return true; } bool AlignmentMatrix::validPath(int const x, int const y) { int width = corridorLines[y].length; int minCorridor = corridorLines[y].offset + 0.1f * width; int maxCorridor = minCorridor + width - 0.1f * width; return x > minCorridor && x < maxCorridor; } } // namespace Convex ngmlr-0.2.7+git20210816.a2a31fb/src/AlignmentMatrix.h000066400000000000000000000072061410636150300214270ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef ALIGNMENT_MATRIX_ #define ALIGNMENT_MATRIX_ #include "IAlignment.h" #include "Types.h" /** * Used in directionMatrix */ //TOOD: replace #define by statics constants #define CIGAR_M 0 #define CIGAR_I 1 #define CIGAR_D 2 #define CIGAR_N 3 #define CIGAR_S 4 #define CIGAR_H 5 #define CIGAR_P 6 #define CIGAR_EQ 7 #define CIGAR_X 8 #define CIGAR_STOP 10 namespace Convex { class AlignmentMatrix { public: typedef float Score; struct MatrixElement { /** * Score of the current element */ Score score; /** * Number of indels that preceded this cell (heuristic!!!) */ short indelRun; /** * From where (up, left, diag) the score of this cell was derived */ char direction; MatrixElement() { score = 0.0f; indelRun = 0; direction = CIGAR_STOP; } }; AlignmentMatrix(); virtual ~AlignmentMatrix(); int getCorridorOffset(int const y) const; int getCorridorLength(int const y) const; int getHeight() const; int getWidth() const; MatrixElement * getElement(int const x, int const y); MatrixElement * getElementEdit(int const x, int const y); char * getDirection(int const x, int const y); Score getScore(int const x, int const y); /** * Deletes allocated memory. * Must be used after alignment computation */ void clean(); /** * Allocates memory and sets up the corridor layout * Has to be called before filling the matrix */ void prepare(int const width, int const height, CorridorLine * corridor, int const corridorHeight); /** * Swaps current and last line. * Has to be used after currentLine is filled */ bool prepareLine(int const y); /** * Prints matrix to stderr */ void printMatrix(char const * refSeq, char const * qrySeg); /** * Returns false if backtracking path * is "too close" to the corridor borders * (heuristics) */ bool validPath(int const x, int const y); private: /** * Default size of alignment (char) matrix */ ulong const defaultMatrixSize; /** * Height of the alignment matrix */ int privateMatrixHeight; /** * Width of the alignment matrix */ int privateMatrixWidth; /** * Current size of the matrix. If an alignment * requires more then defaultMatrixSize, the matrix * is reallocated to fit the alignment computation. * After finishing the alignment, the matrix is * reallocated again with defaultMatrixSize. */ ulong privateMatrixSize; /** * The row of the matrix that is filled. * Only the current and last row are kept * in memory. For backtracking only * the directionMatrix is required */ MatrixElement * currentLine; /** * Holds the information on * where in the full alignment matrix * the currentLine starts and ends */ CorridorLine currentCorridor; int currentY; /** * The last row of the matrix that is * required to fill the current line. */ MatrixElement * lastLine; /** * Holds the information on * where in the full alignment matrix * the lastLine starts and ends */ CorridorLine lastCorridor; int lastY; /** * Matrix that holds the backtracking pointers * for the alignment computation. */ //TODO: reduce memory by fitting directions //of two cells into one char? char * directionMatrix; /** * Empty matrix element. Is returned for * all cells that are outside of the * alignment corridor */ MatrixElement empty; /** * Stop operation. Is returned for all * cells that are outside of the alignment * corridor */ char STOP; /** * Set of corridorLines that * defines the alignment corridor */ CorridorLine * corridorLines; }; #endif /* ALIGNMENT_MATRIX_ */ } // namespace Convex ngmlr-0.2.7+git20210816.a2a31fb/src/AlignmentMatrixFast.cpp000066400000000000000000000134671410636150300226060ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "AlignmentMatrixFast.h" #include #include using std::cerr; namespace Convex { AlignmentMatrixFast::AlignmentMatrixFast(ulong const pMaxMatrixSizeMB) : STOP(CIGAR_STOP), defaultMatrixSize((ulong) 30000 * (ulong) 9000), maxMatrixSizeMB(pMaxMatrixSizeMB) { privateMatrixHeight = 0; privateMatrixWidth = 0; corridorLines = 0; privateMatrixSize = defaultMatrixSize; directionMatrix = new char[privateMatrixSize]; currentLine = 0; lastLine = 0; lastY = 0; currentY = 0; } bool AlignmentMatrixFast::prepare(int const width, int const height, CorridorLine * corridor, int const corridorHeight) { privateMatrixHeight = height; privateMatrixWidth = width; corridorLines = corridor; uloc matrixSize = 0; int maxCorridorLength = 0; for (int i = 0; i < corridorHeight; ++i) { corridorLines[i].offsetInMatrix = matrixSize; matrixSize += corridorLines[i].length; maxCorridorLength = std::max(maxCorridorLength, corridorLines[i].length); } if ((ulong) (matrixSize * sizeof(char) / 1000.0f / 1000.0f) < maxMatrixSizeMB) { if (matrixSize > privateMatrixSize) { // fprintf(stderr, "Reallocating matrix for alignment (size %llu)\n\n", (long long) (matrixSize * sizeof(char) / 1000.0f / 1000.0f)); delete[] directionMatrix; directionMatrix = 0; directionMatrix = new char[matrixSize]; privateMatrixSize = matrixSize; } currentLine = new MatrixElement[maxCorridorLength]; lastLine = new MatrixElement[maxCorridorLength]; } else { fprintf(stderr, "Warning: Couldn't allocate alignment matrix. Required memory (%llu) > max matrix size (%lu)\n\n", (long long) (matrixSize * sizeof(char) / 1000.0f / 1000.0f), maxMatrixSizeMB); return false; } return true; } void AlignmentMatrixFast::clean() { if (currentLine != 0) { delete[] currentLine; currentLine = 0; } if (lastLine != 0) { delete[] lastLine; lastLine = 0; } if (privateMatrixSize > defaultMatrixSize) { delete[] directionMatrix; privateMatrixSize = defaultMatrixSize; directionMatrix = new char[privateMatrixSize]; } } AlignmentMatrixFast::~AlignmentMatrixFast() { if (directionMatrix != 0) { delete[] directionMatrix; directionMatrix = 0; } if (currentLine != 0) { delete[] currentLine; currentLine = 0; } if (lastLine != 0) { delete[] lastLine; lastLine = 0; } } void AlignmentMatrixFast::printMatrix(char const * refSeq, char const * qrySeg) { fprintf(stderr, " - "); for (int x = 0; x < privateMatrixWidth; ++x) { fprintf(stderr, " %c ", refSeq[x]); } fprintf(stderr, "\n"); for (int y = -1; y < privateMatrixHeight; ++y) { if (y == -1) { fprintf(stderr, "-: "); } else { fprintf(stderr, "%c: ", qrySeg[y]); } for (int x = -1; x < privateMatrixWidth; ++x) { fprintf(stderr, "%*d ", 3, (int) *getDirection(x, y)); } fprintf(stderr, "\n"); } } AlignmentMatrixFast::Score AlignmentMatrixFast::getScore(int const x, int const y) { return getElement(x, y)->score; } int AlignmentMatrixFast::getCorridorOffset(int const y) const { return corridorLines[y].offset; } int AlignmentMatrixFast::getCorridorLength(int const y) const { return corridorLines[y].length; } int AlignmentMatrixFast::getHeight() const { return privateMatrixHeight; } int AlignmentMatrixFast::getWidth() const { return privateMatrixWidth; } AlignmentMatrixFast::MatrixElement * AlignmentMatrixFast::getElement(int const x, int const y) { if (y < 0 || x < 0) { return ∅ } if (y != currentY && y != lastY) { fprintf(stderr, "Index not found\n"); throw "Index not found"; } else if (y == currentY) { if (x < currentCorridor.offset || x >= (currentCorridor.offset + currentCorridor.length)) { return ∅ } return currentLine + (x - currentCorridor.offset); } else { // y == lastY if (x < lastCorridor.offset || x >= (lastCorridor.offset + lastCorridor.length)) { return ∅ } return lastLine + (x - lastCorridor.offset); } return 0; } AlignmentMatrixFast::MatrixElement * AlignmentMatrixFast::getElementEdit(int const x, int const y) { if (y < 0 || x < 0) { fprintf(stderr, "Element not found in alignment matrix.\n"); throw ""; } if (y != currentY && y != lastY) { fprintf(stderr, "Index not found\n"); throw "Index not found"; } else if (y == currentY) { if (x < currentCorridor.offset || x >= (currentCorridor.offset + currentCorridor.length)) { fprintf(stderr, "Element not found in alignment matrix.\n"); throw ""; } return currentLine + (x - currentCorridor.offset); } else { // y == lastY if (x < lastCorridor.offset || x >= (lastCorridor.offset + lastCorridor.length)) { fprintf(stderr, "Element not found in alignment matrix.\n"); throw ""; } return lastLine + (x - lastCorridor.offset); } return 0; } char * AlignmentMatrixFast::getDirection(int const x, int const y) { if (y < 0 || y > (privateMatrixHeight - 1) || x < 0) { return &STOP; } else { CorridorLine line = corridorLines[y]; if (x < line.offset || x >= (line.offset + line.length)) { return &STOP; } return directionMatrix + line.offsetInMatrix + (x - line.offset); } } bool AlignmentMatrixFast::prepareLine(int const y) { if (y < 0 || y > getHeight()) { return false; } MatrixElement * tmp = lastLine; lastLine = currentLine; lastY = currentY; lastCorridor = currentCorridor; currentLine = tmp; currentY = y; currentCorridor = corridorLines[currentY]; return true; } bool AlignmentMatrixFast::validPath(int const x, int const y) { int width = corridorLines[y].length; int minCorridor = corridorLines[y].offset + 0.1f * width; int maxCorridor = minCorridor + width - 0.1f * width; // fprintf(stderr, "offest: %d, length: %d\n", corridorLines[y].offset, width); // fprintf(stderr, "%d < %d < %d\n", minCorridor, x, maxCorridor); return x > minCorridor && x < maxCorridor; } } // namespace Convex ngmlr-0.2.7+git20210816.a2a31fb/src/AlignmentMatrixFast.h000066400000000000000000000132421410636150300222420ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef ALIGNMENT_MATRIX_FAST_ #define ALIGNMENT_MATRIX_FAST_ #include "IAlignment.h" #include "Types.h" /** * Used in directionMatrix */ //TOOD: replace #define by statics constants #define CIGAR_M 0 #define CIGAR_I 1 #define CIGAR_D 2 #define CIGAR_N 3 #define CIGAR_S 4 #define CIGAR_H 5 #define CIGAR_P 6 #define CIGAR_EQ 7 #define CIGAR_X 8 #define CIGAR_STOP 10 namespace Convex { class AlignmentMatrixFast { public: typedef float Score; struct MatrixElement { /** * Score of the current element */ Score score; /** * Number of indels that preceded this cell (heuristic!!!) */ short indelRun; /** * From where (up, left, diag) the score of this cell was derived */ char direction; MatrixElement() { score = 0.0f; indelRun = 0; direction = CIGAR_STOP; } }; AlignmentMatrixFast(ulong const pMaxMatrixSizeMB); virtual ~AlignmentMatrixFast(); int getCorridorOffset(int const y) const; int getCorridorLength(int const y) const; int getHeight() const; int getWidth() const; MatrixElement * getElement(int const x, int const y); MatrixElement * getElementEdit(int const x, int const y); //SAFE FUNCTIONS inline MatrixElement * getElementUp(int const x, int const y) { if (y < 0 || x < 0) { return ∅ } if (x < 0) { return ∅ } if (x < lastCorridor.offset || x >= (lastCorridor.offset + lastCorridor.length)) { return ∅ } return lastLine + (x - lastCorridor.offset); } inline MatrixElement * getElementUpUnprotected(int const x, int const y) { return lastLine + (x - lastCorridor.offset); } inline MatrixElement * getElementCurr(int const x, int const y) { if (y < 0 || x < 0) { return ∅ } if (x < currentCorridor.offset || x >= (currentCorridor.offset + currentCorridor.length)) { return ∅ } if (x < 0) { return ∅ } return currentLine + (x - currentCorridor.offset); } inline MatrixElement * getElementCurrUnprotected(int const x, int const y) { return currentLine + (x - currentCorridor.offset); } inline MatrixElement * getElementEditCurr(int const x, int const y) { if (y < 0 || x < 0) { return ∅ } if (x < currentCorridor.offset || x >= (currentCorridor.offset + currentCorridor.length)) { return ∅ } return currentLine + (x - currentCorridor.offset); } //END SAFE FUNCTIONS //FAST FUNCTIONS /* inline MatrixElement * getElementUpFast(int const x, int const y) { throw ""; return lastLine + (x - lastCorridor.offset); } inline MatrixElement * getElementCurrFast(int const x, int const y) { throw ""; return currentLine + (x - currentCorridor.offset); } inline MatrixElement * getElementEditCurrFast(int const x, int const y) { throw ""; return currentLine + (x - currentCorridor.offset); } inline char * getDirectionCurrFast(int const x, int const y) { throw ""; CorridorLine line = corridorLines[y]; return directionMatrix + line.offsetInMatrix + (x - line.offset); }*/ //END FAST FUNCTIONS char * getDirection(int const x, int const y); Score getScore(int const x, int const y); /** * Deletes allocated memory. * Must be used after alignment computation */ void clean(); /** * Allocates memory and sets up the corridor layout * Has to be called before filling the matrix */ bool prepare(int const width, int const height, CorridorLine * corridor, int const corridorHeight); /** * Swaps current and last line. * Has to be used after currentLine is filled */ bool prepareLine(int const y); /** * Prints matrix to stderr */ void printMatrix(char const * refSeq, char const * qrySeg); /** * Returns false if backtracking path * is "too close" to the corridor borders * (heuristics) */ bool validPath(int const x, int const y); public: /** * Default size of alignment (char) matrix */ uloc const defaultMatrixSize; /** * Height of the alignment matrix */ int privateMatrixHeight; /** * Width of the alignment matrix */ int privateMatrixWidth; /** * Current size of the matrix. If an alignment * requires more then defaultMatrixSize, the matrix * is reallocated to fit the alignment computation. * After finishing the alignment, the matrix is * reallocated again with defaultMatrixSize. */ uloc privateMatrixSize; /** * The row of the matrix that is filled. * Only the current and last row are kept * in memory. For backtracking only * the directionMatrix is required */ MatrixElement * currentLine; /** * Holds the information on * where in the full alignment matrix * the currentLine starts and ends */ CorridorLine currentCorridor; int currentY; /** * The last row of the matrix that is * required to fill the current line. */ MatrixElement * lastLine; /** * Holds the information on * where in the full alignment matrix * the lastLine starts and ends */ CorridorLine lastCorridor; int lastY; /** * Matrix that holds the backtracking pointers * for the alignment computation. */ //TODO: reduce memory by fitting directions //of two cells into one char? char * directionMatrix; /** * Empty matrix element. Is returned for * all cells that are outside of the * alignment corridor */ MatrixElement empty; /** * Stop operation. Is returned for all * cells that are outside of the alignment * corridor */ char STOP; /** * Set of corridorLines that * defines the alignment corridor */ CorridorLine * corridorLines; /** * Maximums allowed memory for matrix in MB */ ulong maxMatrixSizeMB; }; #endif /* ALIGNMENT_MATRIX_ */ } // namespace Convex ngmlr-0.2.7+git20210816.a2a31fb/src/ArgParseOutput.h000066400000000000000000000017521410636150300212510ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include #include #include using std::cerr; using std::cout; using std::endl; class ArgParseOutput : public TCLAP::StdOutput { private: std::string usageStr; std::string versionStr; public: ArgParseOutput(std::string usage, std::string version) { usageStr = usage; versionStr = version; } virtual ~ArgParseOutput() { } virtual void failure(TCLAP::CmdLineInterface& c, TCLAP::ArgException& e) { cerr << "Error:" << endl; cerr << " " << e.error() << endl; cerr << endl; cerr << "Short usage:" << endl; cerr << " ngmlr [-t ] -r -q [-o ]" << endl; cerr << endl; cerr << "For complete USAGE and HELP type:" << endl; cerr << " ngmlr --help" << endl; cerr << endl; exit(1); } virtual void usage(TCLAP::CmdLineInterface& c) { cerr << usageStr << std::endl; } virtual void version(TCLAP::CmdLineInterface& c) { } }; ngmlr-0.2.7+git20210816.a2a31fb/src/ArgParser.cpp000066400000000000000000000332611410636150300205450ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "ArgParser.h" #include #include #include #include "ArgParseOutput.h" #include "Version.h" #include "Log.h" #include "PlatformSpecifics.h" #undef module_name #define module_name "ARGPARSER" ArgParser::ArgParser(int argc, char * * argv) { outDefault = "stdout"; noneDefault = "none"; ParseArguments(argc, (char const * *) argv); } ArgParser::~ArgParser() { } char * ArgParser::fromString(std::string str) { char * cstr = 0; if(str.size() > 0 && str != outDefault && str != noneDefault) { cstr = new char[str.size() + 1]; strcpy(cstr, str.c_str()); } return cstr; } template void printParameter(std::stringstream & usage, TCLAP::ValueArg & arg) { usage << " " << arg.longID() << std::endl; usage << " " << arg.getDescription(); if(!arg.isRequired()) { usage << " [" << arg.getValue() << "]"; } usage << std::endl; } void printParameter(std::stringstream & usage, TCLAP::SwitchArg & arg) { usage << " " << arg.longID() << std::endl; usage << " " << arg.getDescription(); if(!arg.isRequired()) { usage << " [" << (arg.getValue() ? "true" : "false") << "]"; } usage << std::endl; } void ArgParser::ParseArguments(int argc, char const * argv[]) { argv[0] = "ngmlr"; TCLAP::CmdLine cmd("", ' ', "", true); TCLAP::ValueArg queryArg("q", "query", "Path to the read file (FASTA/Q)", false, "/dev/stdin", "file", cmd); TCLAP::ValueArg refArg("r", "reference", "Path to the reference genome (FASTA/Q, can be gzipped)", true, noneDefault, "file", cmd); TCLAP::ValueArg outArg("o", "output", "Path to output file", false, noneDefault, "string", cmd); TCLAP::ValueArg vcfArg("", "vcf", "SNPs will be taken into account when building reference index", false, noneDefault, "file", cmd); TCLAP::ValueArg bedfilterArg("", "bed-filter", "Only reads in the regions specified by the BED file are read from the input file (requires BAM input)", false, noneDefault, "file", cmd); TCLAP::ValueArg rgIdArg("", "rg-id", "Adds RG:Z: to all alignments in SAM/BAM", false, noneDefault, "string", cmd); TCLAP::ValueArg rgSmArg("", "rg-sm", "RG header: Sample", false, noneDefault, "string", cmd); TCLAP::ValueArg rgLbArg("", "rg-lb", "RG header: Library", false, noneDefault, "string", cmd); TCLAP::ValueArg rgPlArg("", "rg-pl", "RG header: Platform", false, noneDefault, "string", cmd); TCLAP::ValueArg rgDsArg("", "rg-ds", "RG header: Description", false, noneDefault, "string", cmd); TCLAP::ValueArg rgDtArg("", "rg-dt", "RG header: Date (format: YYYY-MM-DD)", false, noneDefault, "string", cmd); TCLAP::ValueArg rgPuArg("", "rg-pu", "RG header: Platform unit", false, noneDefault, "string", cmd); TCLAP::ValueArg rgPiArg("", "rg-pi", "RG header: Median insert size", false, noneDefault, "string", cmd); TCLAP::ValueArg rgPgArg("", "rg-pg", "RG header: Programs", false, noneDefault, "string", cmd); TCLAP::ValueArg rgCnArg("", "rg-cn", "RG header: sequencing center", false, noneDefault, "string", cmd); TCLAP::ValueArg rgFoArg("", "rg-fo", "RG header: Flow order", false, noneDefault, "string", cmd); TCLAP::ValueArg rgKsArg("", "rg-ks", "RG header: Key sequence", false, noneDefault, "string", cmd); TCLAP::ValueArg presetArgs("x", "presets", "Parameter presets for different sequencing technologies", false, "pacbio", "pacbio, ont", cmd); TCLAP::ValueArg minIdentityArg("i", "min-identity", "Alignments with an identity lower than this threshold will be discarded", false, minIdentity, "0-1", cmd); TCLAP::ValueArg minResiduesArg("R", "min-residues", "Alignments containing less than or ( * read length) residues will be discarded", false, minResidues, "int/float", cmd); TCLAP::ValueArg sensitivityArg("s", "sensitivity", "", false, sensitivity, "0-1", cmd); TCLAP::ValueArg threadsArg("t", "threads", "Number of threads", false, 1, "int", cmd); TCLAP::ValueArg binSizeArg("", "bin-size", "Sets the size of the grid used during candidate search", false, binSize, "int", cmd); TCLAP::ValueArg kmerLengthArg("k", "kmer-length", "K-mer length in bases", false, kmerLength, "10-15", cmd); TCLAP::ValueArg kmerSkipArg("", "kmer-skip", "Number of k-mers to skip when building the lookup table from the reference", false, kmerSkip, "int", cmd); TCLAP::ValueArg maxInitialSegmentsArg("", "max-segments", "Max number of segments allowed for a read per kb", false, maxSegmentNumberPerKb, "int", cmd); TCLAP::ValueArg scoreMatchArg("", "match", "Match score", false, scoreMatch, "float", cmd); TCLAP::ValueArg scoreMismatchArg("", "mismatch", "Mismatch score", false, scoreMismatch, "float", cmd); TCLAP::ValueArg scoreGapOpenArg("", "gap-open", "Gap open score", false, scoreGapOpen, "float", cmd); TCLAP::ValueArg scoreGapExtendMaxArg("", "gap-extend-max", "Gap open extend max", false, scoreGapExtendMax, "float", cmd); TCLAP::ValueArg scoreGapExtendMinArg("", "gap-extend-min", "Gap open extend min", false, scoreGapExtendMin, "float", cmd); TCLAP::ValueArg scoreGapDecayArg("", "gap-decay", "Gap extend decay", false, scoreGapDecay, "float", cmd); TCLAP::ValueArg stdoutArg("", "stdout", "Debug mode", false, stdoutMode, "0-7", cmd); TCLAP::ValueArg subreadAligner("", "subread-aligner", "Choose subread aligning method", false, subreadaligner, "0-3", cmd); TCLAP::ValueArg readpartLengthArg("", "subread-length", "Length of fragments reads are split into", false, readPartLength, "int", cmd); TCLAP::ValueArg readpartCorridorArg("", "subread-corridor", "Length of corridor sub-reads are aligned with", false, readPartCorridor, "int", cmd); //csSearchTableLength = 0; //logLevel = 0; //16383, 255 //minKmerHits = 0; //maxCMRs = INT_MAX; TCLAP::SwitchArg noprogressArg("", "no-progress", "Don't print progress info while mapping", cmd, false); TCLAP::SwitchArg verboseArg("", "verbose", "Debug output", cmd, false); //bam = false; TCLAP::SwitchArg colorArg("", "color", "Colored command line output", cmd, false); //hardClip = false; //log = false; TCLAP::SwitchArg lowqualitysplitArg("", "no-lowqualitysplit", "Split alignments with poor quality", cmd, false); TCLAP::SwitchArg nosmallInversionArg("", "no-smallinv", "Don't detect small inversions", cmd, false); TCLAP::SwitchArg printAllAlignmentsArg("", "print-all", "Print all alignments. Disable filtering. (debug)", cmd, false); TCLAP::SwitchArg skipWriteArg("", "skip-write", "Don't write reference index to disk", cmd, skipSave); //skipSave = false; //updateCheck = false; //writeUnmapped = true; TCLAP::SwitchArg noSSEArg("", "nosse", "Debug switch (don't use if you don't know what you are doing)", cmd, false); TCLAP::SwitchArg bamFixArg("", "bam-fix", "Report reads with > 64k CIGAR operations as unmapped. Required to be compatibel to BAM format", cmd, false); TCLAP::SwitchArg skipAlignArg("", "skip-align", "Skip alignment step. Only for debugging purpose", cmd, false); std::stringstream usage; usage << "" << std::endl; usage << "Usage: ngmlr [options] -r -q [-o ]" << std::endl; usage << "" << std::endl; usage << "Input/Output:" << std::endl; printParameter(usage, refArg); printParameter(usage, queryArg); printParameter(usage, outArg); printParameter(usage, skipWriteArg); printParameter(usage, bamFixArg); printParameter(usage, rgIdArg); printParameter(usage, rgSmArg); printParameter(usage, rgLbArg); printParameter(usage, rgPlArg); printParameter(usage, rgDsArg); printParameter(usage, rgDtArg); printParameter(usage, rgPuArg); printParameter(usage, rgPiArg); printParameter(usage, rgPgArg); printParameter(usage, rgCnArg); printParameter(usage, rgFoArg); printParameter(usage, rgKsArg); usage << "" << std::endl; usage << "General:" << std::endl; printParameter(usage, threadsArg); printParameter(usage, presetArgs); printParameter(usage, minIdentityArg); printParameter(usage, minResiduesArg); printParameter(usage, nosmallInversionArg); printParameter(usage, lowqualitysplitArg); printParameter(usage, verboseArg); printParameter(usage, noprogressArg); usage << "" << std::endl; usage << "Advanced:" << std::endl; printParameter(usage, scoreMatchArg); printParameter(usage, scoreMismatchArg); printParameter(usage, scoreGapOpenArg); printParameter(usage, scoreGapExtendMaxArg); printParameter(usage, scoreGapExtendMinArg); printParameter(usage, scoreGapDecayArg); printParameter(usage, kmerLengthArg); printParameter(usage, kmerSkipArg); printParameter(usage, binSizeArg); printParameter(usage, maxInitialSegmentsArg); printParameter(usage, readpartLengthArg); printParameter(usage, readpartCorridorArg); //printParameter(usage, vcfArg); //printParameter(usage, bedfilterArg); cmd.setOutput(new ArgParseOutput(usage.str(), "")); cmd.parse(argc, argv); queryFile = fromString(queryArg.getValue()); referenceFile = fromString(refArg.getValue()); outputFile = fromString(outArg.getValue()); vcfFile = fromString(vcfArg.getValue()); bedFile = fromString(bedfilterArg.getValue()); rgId = fromString(rgIdArg.getValue()); rgSm = fromString(rgSmArg.getValue()); rgLb = fromString(rgLbArg.getValue()); rgPl = fromString(rgPlArg.getValue()); rgDs = fromString(rgDsArg.getValue()); rgDt = fromString(rgDtArg.getValue()); rgPu = fromString(rgPuArg.getValue()); rgPi = fromString(rgPiArg.getValue()); rgPg = fromString(rgPgArg.getValue()); rgCn = fromString(rgCnArg.getValue()); rgFo = fromString(rgFoArg.getValue()); rgKs = fromString(rgKsArg.getValue()); minIdentity = minIdentityArg.getValue(); minResidues = minResiduesArg.getValue(); binSize = binSizeArg.getValue(); kmerLength = kmerLengthArg.getValue(); threads = threadsArg.getValue(); kmerSkip = kmerSkipArg.getValue(); maxSegmentNumberPerKb = maxInitialSegmentsArg.getValue(); scoreMatch = scoreMatchArg.getValue(); if(scoreMatch < 0.0f) { Log.Message("--match must not be smaller than zero. changing from %f to %f", scoreMatch, scoreMatch * -1.0f); scoreMatch = scoreMatch * -1.0f; } scoreMismatch = scoreMismatchArg.getValue(); if (scoreMismatch > 0.0f) { Log.Message("--mismatch must not be greater than zero. changing from %f to %f", scoreMismatch, scoreMismatch * -1.0f); scoreMismatch = scoreMismatch * -1.0f; } scoreGapOpen = scoreGapOpenArg.getValue(); if (scoreGapOpen > 0.0f) { Log.Message("--gap-open must not be greater than zero. changing from %f to %f", scoreGapOpen, scoreGapOpen * -1.0f); scoreGapOpen = scoreGapOpen * -1.0f; } scoreGapExtendMax = scoreGapExtendMaxArg.getValue(); if (scoreGapExtendMax > 0.0f) { Log.Message("--gap-extend-max must not be greater than zero. changing from %f to %f", scoreGapExtendMax, scoreGapExtendMax * -1.0f); scoreGapExtendMax = scoreGapExtendMax * -1.0f; } scoreGapExtendMin = scoreGapExtendMinArg.getValue(); if (scoreGapExtendMin > 0.0f) { Log.Message("--gap-extend-min must not be greater than zero. changing from %f to %f", scoreGapExtendMin, scoreGapExtendMin * -1.0f); scoreGapExtendMin = scoreGapExtendMin * -1.0f; } scoreGapDecay = scoreGapDecayArg.getValue(); if (scoreGapDecay < 0.0f) { Log.Message("--gap-decay must not be smaller than zero. changing from %f to %f", scoreGapDecay, scoreGapDecay * -1.0f); scoreGapDecay = scoreGapDecay * -1.0f; } subreadaligner = subreadAligner.getValue(); stdoutMode = stdoutArg.getValue(); readPartCorridor = readpartCorridorArg.getValue(); readPartLength = readpartLengthArg.getValue(); progress = !noprogressArg.getValue(); color = colorArg.getValue(); verbose = verboseArg.getValue(); lowQualitySplit = !lowqualitysplitArg.getValue(); smallInversionDetection = !nosmallInversionArg.getValue(); printAllAlignments = printAllAlignmentsArg.getValue(); skipSave = skipWriteArg.getValue(); nosse = noSSEArg.getValue(); bamCigarFix = bamFixArg.getValue(); skipAlign = skipAlignArg.getValue(); if (presetArgs.getValue() == "pacbio") { //Do nothing. Defaults are for Pacbio } else if (presetArgs.getValue() == "ont") { // lowQualitySplit = (lowqualitysplitArg.isSet()) ? lowQualitySplit : false; // smallInversionDetection = (nosmallInversionArg.isSet()) ? smallInversionDetection : false; // scoreMatch = (scoreMatchArg.isSet()) ? scoreMatch : 3; // scoreMismatch = (scoreMatchArg.isSet()) ? scoreMismatch : -3; //scoreGapOpen = (scoreGapOpenArg.isSet()) ? scoreGapOpen : -1; //scoreGapExtendMax = (scoreGapExtendMaxArg.isSet()) ? scoreGapExtendMax : -1; //scoreGapExtendMax = (scoreGapExtendMinArg.isSet()) ? scoreGapExtendMin : -0.5; scoreGapDecay = (scoreGapDecayArg.isSet()) ? scoreGapDecay : 0.15; } else { std::cerr << "Preset " << presetArgs.getValue() << " not found" << std::endl; } std::stringstream fullCmd; fullCmd << std::string(argv[0]); for(int i = 1; i < argc; ++i) { fullCmd << " " << std::string(argv[i]); } fullCommandLineCall = fromString(fullCmd.str()); if(!FileExists(queryFile)) { Log.Error("Query file (%s) does not exist.", queryFile); } if(!FileExists(referenceFile)) { Log.Error("Reference file (%s) does not exist.", referenceFile); } if(bedFile != 0 && !FileExists(bedFile)) { Log.Error("BED filter file (%s) does not exist.", bedFile); } if(vcfFile != 0 && !FileExists(vcfFile)) { Log.Error("SNP file (%s) does not exist.", vcfFile); } } ngmlr-0.2.7+git20210816.a2a31fb/src/ArgParser.h000066400000000000000000000007151410636150300202100ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __ARGPARSER_H__ #define __ARGPARSER_H__ #include "IConfig.h" #include class ArgParser : public IConfig { private: std::string outDefault; std::string noneDefault; void ParseArguments(int argc, char const * * argv); char * fromString(std::string str); public: ArgParser(int argc, char * argv[]); virtual ~ArgParser(); }; #endif //__ARGPARSER_H__ ngmlr-0.2.7+git20210816.a2a31fb/src/CMakeLists.txt000066400000000000000000000031041410636150300207040ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) project(ngmlr) include_directories (../lib/seqan-library-2.2.0/include) include_directories (../lib/Complete-Striped-Smith-Waterman-Library/src) include_directories (../lib) include_directories( ${ZLIB_INCLUDE_DIRS} ) configure_file( Version.h.in ${CMAKE_SOURCE_DIR}/src/Version.h ) IF(STATIC) IF(APPLE) message(FATAL_ERROR "MacOSX does not support static linking. Please use -DSTATIC=OFF") ENDIF() SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") SET(BUILD_SHARED_LIBRARIES OFF) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") ENDIF() add_executable(ngmlr AlignmentMatrix.cpp AlignmentMatrixFast.cpp ArgParser.cpp CS.cpp CSstatic.cpp ConvexAlign.cpp ConvexAlignFast.cpp LinearRegression.cpp Logging.cpp MappedRead.cpp main.cpp NGM.cpp NGMTask.cpp AlignmentBuffer.cpp PrefixTable.cpp ReadProvider.cpp SamParser.cpp SAMWriter.cpp SequenceProvider.cpp OutputReadBuffer.cpp ScoreBuffer.cpp StrippedSW.cpp ../lib/Complete-Striped-Smith-Waterman-Library/src/ssw.c unix.cpp unix_threads.cpp) ADD_CUSTOM_TARGET(recompile_always ALL touch "${CMAKE_SOURCE_DIR}/src/main.cpp") #SET_TARGET_PROPERTIES(ngmlr PROPERTIES COMPILE_FLAGS " -g -O3 -DNDEBUG") TARGET_LINK_LIBRARIES(ngmlr ${ZLIB_LIBRARIES}) TARGET_LINK_LIBRARIES(ngmlr ${CMAKE_THREAD_LIBS_INIT}) install (TARGETS ngmlr DESTINATION bin)ngmlr-0.2.7+git20210816.a2a31fb/src/CS.cpp000066400000000000000000000425471410636150300171730ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "CS.h" #include #include #include #include "NGM.h" #include "Timing.h" #include "AlignmentBuffer.h" #undef module_name #define module_name "CS" bool stdoutPrintRunningTime = false; //static const int cInvalidLocation = -99999999; static const SequenceLocation sInvalidLocation(9223372036854775808u, 0, false); volatile int CS::s_ThreadCount = 0; bool up = false; int kCount = 0; //Default values int x_SrchTableBitLen = 24; //Number of bases per batch //Default batch size //int const cBatchSize = 1800000; // Reduced batch size (for low read number PacBio samples) int const cBatchSize = 10; //int const cBatchSize = 10000; uint const cPrefixBaseSkip = 0; float const cOverflowThresh = 0.1f; float const cOverflowLimit = 10; void CS::PrefixIteration(char const * sequence, uloc length, PrefixIterationFn func, ulong mutateFrom, ulong mutateTo, void* data, uint prefixskip, uloc offset, int prefixBaseCount) { prefixBasecount = prefixBaseCount; prefixBits = prefixBasecount * 2; prefixMask = ((ulong) 1 << prefixBits) - 1; CS::PrefixIteration(sequence, length, func, mutateFrom, mutateTo, data, prefixskip, offset); prefixBasecount = Config.getKmerLength(); prefixBits = prefixBasecount * 2; prefixMask = ((ulong) 1 << prefixBits) - 1; } void CS::PrefixSearch(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data) { CS * cs = (CS*) data; RefEntry const * entries = cs->m_RefProvider->GetRefEntry(prefix, cs->m_entry); // Liefert eine liste aller Vorkommen dieses Praefixes in der Referenz RefEntry const * cur = entries; int const readLength = cs->m_CurrentReadLength; if (cur != 0 && cur->refTotal == 0) { kCount += 1; } for (int i = 0; i < cs->m_entryCount; i++) { //Get kmer-weight. //float weight = cur->weight / 100.0f; //cs->weightSum += cur->weight; float weight = 1.0f; uloc correction = (cur->reverse) ? (readLength - (pos + CS::prefixBasecount)) : pos; //#ifdef _DEBUGCSVERBOSE // Log.Message("Qry Seq %i - Prefix 0x%x got %i locs (sum %i)", cs->m_CurrentSeq, prefix, cur->refTotal); //#endif int const n = cur->refCount; for (int i = 0; i < n; ++i) { uloc loc = cur->getRealLocation(cur->ref[i]); cs->AddLocationStd(GetBin(loc - correction), cur->reverse, weight); //cs->AddLocationStd(GetBin(loc - (int) (correction * 0.95f)), // cur->reverse, weight); } cur++; } } void CS::AddLocationStd(uloc const m_Location, bool const reverse, double const freq) { bool newEntry = false; CSTableEntry* entry = rTable + Hash(m_Location); CSTableEntry* const maxEntry = rTable + c_SrchTableLen; //uint hpo = Hash( m_Location ); while ((newEntry = (entry->state & 0x7FFFFFFF) == currentState) && !(entry->m_Location == m_Location)) { ++entry; if (entry >= maxEntry) entry = rTable; if (--hpoc == 0) { throw 1; } } float score = freq; if (!newEntry) { entry->m_Location = m_Location; entry->state = currentState & 0x7FFFFFFF; if (reverse) { entry->fScore = 0.0f; entry->rScore = score; } else { entry->fScore = score; entry->rScore = 0.0f; } } else { //Add kmer-weight to position if (reverse) { score = (entry->rScore += freq); } else { score = (entry->fScore += freq); } } //Compute max k-mer weight for this read if (score > maxHitNumber) { maxHitNumber = score; //currentThresh = round(maxHitNumber * m_CsSensitivity); currentThresh = maxHitNumber * m_CsSensitivity; } //If kmer-weight larger than threshold -> add to rList. if (!(entry->state & 0x80000000) && score >= currentThresh) { entry->state |= 0x80000000; rList[rListLength++] = entry - rTable; } } void CS::AddLocationFallback(SequenceLocation const & loc, double const freq) { throw "Not implemented (AddLocationFallback)"; } #include #include void CS::debugCS(MappedRead * read, int& n, float& mi_Threshhold) { std::stringstream ss; ss << std::string(Config.getOutputFile()) << "_kmer-profile/" << read->ReadId << ".csv"; Log.Message("Opening %s", ss.str().c_str()); FILE * kmerCount = fopen(ss.str().c_str(), "w"); int count = 0; int accepted = 0; float max = 0.0f; for (int i = 0; i < c_SrchTableLen; ++i) { if ((rTable[i].state & 0x7FFFFFFF) == currentState) { max = std::max(std::max(max, rTable[i].fScore), rTable[i].rScore); //Correct position SequenceLocation loc; loc.m_Location = ResolveBin(rTable[i].m_Location); // Log.Message("Could not convert location %llu", ResolveBin(rTable[i].m_Location)); // if (!SequenceProvider.convert(loc)) { // Log.Message("ERROR"); // loc.m_Location = ResolveBin(rTable[i].m_Location); // loc.setRefId(0); // // } int refNameLength = 0; if (rTable[i].fScore > 0.0f) { if (rTable[i].fScore >= mi_Threshhold) { Log.Debug(8192, "READ_%d\tCS_RESULTS\tInternal location: %llu (+), Location: %llu (Ref: %s), Score: %f (ACCEPT)", read->ReadId, rTable[i].m_Location, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength), rTable[i].fScore); // Log.Message("READ_%d\tCS_RESULTS\tInternal location: %llu (+), Location: %llu (Ref: %s), Score: %f (ACCEPT)", read->ReadId, rTable[i].m_Location, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength), rTable[i].fScore); accepted += 1; fprintf(kmerCount, "%s;%llu;%f;1;%d\n", read->name, ResolveBin(rTable[i].m_Location), rTable[i].fScore, read->length); } else { Log.Debug(4096, "READ_%d\tCS_DETAILS\tInternal location: %llu (+), Location: %llu (Ref: %s), Score: %f (REJECT)", read->ReadId, rTable[i].m_Location, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength), rTable[i].fScore); fprintf(kmerCount, "%s;%llu;%f;0;%d\n", read->name, ResolveBin(rTable[i].m_Location), rTable[i].fScore, read->length); } count += 1; } if (rTable[i].rScore > 0.0f) { if (rTable[i].rScore >= mi_Threshhold) { Log.Debug(8192, "READ_%d\tCS_RESULTS\tInternal location: %llu (-), Location: %llu (Ref: %s), Score: %f (ACCEPT)", read->ReadId, rTable[i].m_Location, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength), rTable[i].rScore * -1.0f); // Log.Message("READ_%d\tCS_RESULTS\tInternal location: %llu (-), Location: %llu (Ref: %s), Score: %f (ACCEPT)", read->ReadId, rTable[i].m_Location, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength), rTable[i].rScore); accepted += 1; fprintf(kmerCount, "%s;%llu;%f;1;%d\n", read->name, ResolveBin(rTable[i].m_Location), rTable[i].rScore * -1.0f, read->length); } else { Log.Debug(4096, "READ_%d\tCS_DETAILS\tInternal location: %llu (-), Location: %llu (Ref: %s), Score: %f (REJECT)", read->ReadId, rTable[i].m_Location, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength), rTable[i].rScore * -1.0f); fprintf(kmerCount, "%s;%llu;%f;0;%d\n", read->name, ResolveBin(rTable[i].m_Location), rTable[i].rScore * -1.0f, read->length); } count += 1; } } } Log.Debug(8, "%s\tCS\tSummary: %d CMRs (%d without filter), %d accepted, theta: %f, max: %f", read->name, n, count, accepted, mi_Threshhold, max); fclose(kmerCount); } int CS::CollectResultsStd(MappedRead * read) { static float const mink = Config.getMinKmerHits(); int max = (read->length - CS::prefixBasecount + 1) * 0.9; if (kCount > max) read->mappingQlty = 0; read->s = maxHitNumber; float mi_Threshhold = std::max(mink, currentThresh); int n = rListLength; //#ifdef DEBUGLOG //if(Config.GetInt(LOG_LVL) > 0) { //if (strcmp(read->name, "SRR1284073.163322") == 0) { //debugCS(read, n, mi_Threshhold); //} //} //#endif int index = 0; if (2 * n > tmpSize) { tmpSize = 2 * n * 1.5f; Log.Debug(LOG_CS_DETAILS, "Increasing size of location buffer to %d", tmpSize); delete[] tmp; tmp = new LocationScore[tmpSize]; } for (int i = 0; i < n; ++i) { CSTableEntry temp = rTable[rList[i]]; if (temp.fScore >= mi_Threshhold) { LocationScore * toInsert = &tmp[index++]; toInsert->Score.f = temp.fScore; toInsert->Location.m_Location = ResolveBin(temp.m_Location); toInsert->Location.setReverse(false); } if (temp.rScore >= mi_Threshhold) { LocationScore * toInsert = &tmp[index++]; toInsert->Score.f = temp.rScore; toInsert->Location.m_Location = ResolveBin(temp.m_Location); toInsert->Location.setReverse(true); } } static int const maxScores = Config.getMaxCMRs(); if (index < maxScores) read->AllocScores(tmp, index); return index; } int CS::CollectResultsFallback(MappedRead * read) { throw "Not implemented (CollectResultsFallback)"; return 0; } void CS::SendToBuffer(MappedRead * read, ScoreBuffer * sw, AlignmentBuffer * out) { if (read == 0) return; int count = read->numScores(); if (read->group != 0) { /* * Read is a long read (long enough for splitting) */ if (count == 0) { /* * Current sub-read does not have mapping locations */ read->Calculated = 0; read->mappingQlty = 0; read->group->readsFinished += 1; if (read->group->readsFinished == read->group->readNumber) { out->processLongReadLIS(read->group); } } else { /* * Current sub-read has mapping locations * -> compute scores */ read->Calculated = 0; sw->addRead(read, count); } } else { /* * Read length is too short for splitting */ if (count == 0) { out->WriteRead(read, false); } else { read->Calculated = 0; sw->scoreShortRead(read); } } } void CS::Cleanup() { NGM.ReleaseWriter(); } int CS::RunRead(MappedRead * currentRead, PrefixIterationFn pFunc, ScoreBuffer * sw, AlignmentBuffer * out) { int nScoresSum = 0; m_CurrentSeq = currentRead->ReadId; //m_CurrentSeq = i; //currentState = 2 * i; currentState++; rListLength = 0; maxHitNumber = 0.0f; currentThresh = 0.0f; //weightSum = 0.0f; kCount = 0; m_CurrentReadLength = currentRead->length; ++m_ProcessedReads; bool fallback = m_Fallback; char const * const qrySeq = currentRead->Seq; uloc qryLen = currentRead->length; // SetSearchTableBitLen(24); if (!fallback) { try { hpoc = c_SrchTableLen * 0.333f; PrefixIteration(qrySeq, qryLen, pFunc, 0, 0, this, m_PrefixBaseSkip); int nScores = CollectResultsStd(currentRead); nScoresSum += nScores; } catch (int overflow) { ++m_Overflows; // Initiate fallback fallback = true; } } if (fallback) { int c_SrchTableBitLenBackup = c_SrchTableBitLen; int x = 2; while (fallback && (c_SrchTableBitLenBackup + x) <= 20) { fallback = false; try { SetSearchTableBitLen(c_SrchTableBitLenBackup + x); rListLength = 0; //currentState = 2 * i + 1; currentState++; maxHitNumber = 0.0f; currentThresh = 0.0f; hpoc = c_SrchTableLen * 0.777f; PrefixIteration(qrySeq, qryLen, pFunc, 0, 0, this, m_PrefixBaseSkip); nScoresSum += CollectResultsStd(currentRead); } catch (int overflow) { // Log.Message("Overflow in fallback for read %s!", currentRead->name); fallback = true; x += 1; } } if (fallback) { Log.Message("Couldn't find candidate for read %s (too many candidates)", currentRead->name); } SetSearchTableBitLen(c_SrchTableBitLenBackup); } SendToBuffer(currentRead, sw, out); return nScoresSum; } int CS::RunBatch(ScoreBuffer * sw, AlignmentBuffer * out) { PrefixIterationFn pFunc = &CS::PrefixSearch; int nScoresSum = 0; for (size_t i = 0; i < m_CurrentBatch.size(); ++i) { MappedRead * currentRead = m_CurrentBatch[i]; nScoresSum += RunRead(currentRead, pFunc, sw, out); } return nScoresSum; } void CS::DoRun() { NGM.AquireOutputLock(); oclAligner = NGM.CreateAlignment(0); alignmentBuffer = new AlignmentBuffer(Config.getOutputFile()); ScoreBuffer * scoreBuffer = new ScoreBuffer(oclAligner, alignmentBuffer); NGM.ReleaseOutputLock(); int x_SrchTableLen = (int) pow(2, x_SrchTableBitLen); rTable = new CSTableEntry[x_SrchTableLen]; Log.Debug(LOG_CS_DETAILS, "Sizeof CSTableEntry %d (%d)", sizeof(CSTableEntry), sizeof(SequenceLocation)); Log.Debug(LOG_CS_DETAILS, "rTable: %d (%d x (%d + %d))", (sizeof(CSTableEntry) + sizeof(int)) * x_SrchTableLen, x_SrchTableLen, sizeof(CSTableEntry), sizeof(int)); rList = new int[x_SrchTableLen]; for (int i = 0; i < x_SrchTableLen; ++i) { rTable[i].m_Location = sInvalidLocation.m_Location; rTable[i].state = -1; rList[i] = -1; } m_CsSensitivity = Config.getSensitivity(); m_RefProvider = 0; int batchId = 0; Timer tmr; tmr.ST(); m_RefProvider = NGM.GetRefProvider(m_TID); AllocRefEntryChain(); while (NGM.ThreadActive(m_TID, GetStage()) && ((m_CurrentBatch = NGM.GetNextReadBatch(m_BatchSize)), (m_CurrentBatch.size() > 0))) { Log.Debug(LOG_CS_DETAILS, "CS Thread %i got batch (len %i)", m_TID, m_CurrentBatch.size()); // Log.Message("CS Thread %i got batch %d (len %i)", m_TID, ++batchId, m_CurrentBatch.size()); int nCRMsSum = RunBatch(scoreBuffer, alignmentBuffer); Log.Verbose("CS Thread %i flushing scoreBuffer for batch %d", m_TID, batchId); scoreBuffer->flush(); float elapsed = tmr.ET(); Log.Debug(LOG_CS_DETAILS, "CS Thread %i finished batch (len %i) with %i overflows, length %d (elapsed: %.3fs)", m_TID, m_CurrentBatch.size(), m_Overflows, c_SrchTableBitLen, elapsed); // Log.Message("CS Thread %i finished batch %d (len %i) with %i overflows, length %d (elapsed: %.3fs)", m_TID, batchId, m_CurrentBatch.size(), m_Overflows, c_SrchTableBitLen, elapsed); float alignmentTime = alignmentBuffer->getAlignTime(); float longReadProcessingTime = alignmentBuffer->getProcessTime() - alignmentTime; float shortReadScoringTime = scoreBuffer->getTime() - alignmentBuffer->getProcessTime(); float kmerSearchTime = elapsed - scoreBuffer->getTime(); // if(stdoutPrintRunningTime) { // fprintf(stdout, "%f\t%f\t%f\t%f\t%f\n", elapsed, // scoreBuffer->getTime(), // alignmentBuffer->getTime(), // alignmentBuffer->getProcessTime(), // alignmentBuffer->getAlignTime()); // fprintf(stdout, "%f (%d)\t%f(%d)\t%f(%d)\t%f(%d)\n", // kmerSearchTime, (int)(kmerSearchTime / elapsed * 100.0f), // shortReadScoringTime, (int)(shortReadScoringTime / elapsed * 100.0f), // longReadProcessingTime, (int)(longReadProcessingTime / elapsed * 100.0f), // alignmentTime, (int)(alignmentTime / elapsed * 100.0f)); // fflush(stdout); // } NGM.Stats->alignTime = (NGM.Stats->alignTime + (int)(alignmentTime / elapsed * 100.0f)) / 2; NGM.Stats->scoreTime = (NGM.Stats->scoreTime + (int)(shortReadScoringTime / elapsed * 100.0f)) / 2; NGM.Stats->csTime = (NGM.Stats->csTime + (int)(kmerSearchTime / elapsed * 100.0f)) / 2; NGM.Stats->csLength = c_SrchTableBitLen; NGM.Stats->csOverflows = m_Overflows; NGM.Stats->avgnCRMS = nCRMsSum / m_CurrentBatch.size(); if (Config.getCsSearchTableLength() == 0) { if (m_Overflows <= 5 && !up && c_SrchTableBitLen > 8) { SetSearchTableBitLen( c_SrchTableBitLen - 1 ); Log.Debug(LOG_CS_DETAILS, "Overflow: Switching to %d bits (%d, %d)", c_SrchTableBitLen, c_BitShift, c_SrchTableLen); } else if (m_Overflows > m_BatchSize * 0.01f) { SetSearchTableBitLen( c_SrchTableBitLen + 1 ); up = true; Log.Debug(LOG_CS_DETAILS, "Overflow: Switching to %d bits (%d, %d)", c_SrchTableBitLen, c_BitShift, c_SrchTableLen); } } m_Overflows = 0; } delete scoreBuffer; scoreBuffer = 0; delete alignmentBuffer; alignmentBuffer = 0; NGM.DeleteAlignment(oclAligner); Log.Debug(LOG_CS_DETAILS, "CS Thread %i finished (%i reads processed, %i reads written, %i reads discarded)", m_TID, m_ProcessedReads, m_WrittenReads, m_DiscardedReads); // Log.Message("CS Thread %i finished (%i reads processed, %i reads written, %i reads discarded)", m_TID, m_ProcessedReads, m_WrittenReads, m_DiscardedReads); } void CS::Init() { prefixBasecount = Config.getKmerLength(); prefixBits = prefixBasecount * 2; prefixMask = ((ulong) 1 << prefixBits) - 1; } CS::CS(bool useBuffer) : m_CSThreadID((useBuffer) ? (AtomicInc(&s_ThreadCount) - 1) : -1), m_BatchSize( cBatchSize), m_ProcessedReads(0), m_DiscardedReads( 0), m_Overflows(0), m_entry(0), m_PrefixBaseSkip( 0), m_Fallback(false), alignmentBuffer(0), c_SrchTableLen(0), rListLength(0), m_CurrentSeq(0), c_SrchTableBitLen(0), oclAligner(0), m_CurrentReadLength(0), hpoc(0), m_CsSensitivity(0.0f), maxHitNumber(0.0f), rList(0), m_entryCount(0), c_BitShift(0), m_RefProvider(0), currentThresh(0.0f) { SetSearchTableBitLen(Config.getCsSearchTableLength() != 0 ? Config.getCsSearchTableLength() : 16); rTable = 0; Log.Debug(LOG_CS_DETAILS, "SearchTabLen: %d (%d)", c_SrchTableLen, c_SrchTableBitLen); currentState = 0; tmpSize = 10000; tmp = new LocationScore[tmpSize]; } void CS::AllocRefEntryChain() { m_entryCount = m_RefProvider->GetRefEntryChainLength(); m_entry = new RefEntry[m_entryCount]; } CS::~CS() { if (tmp != 0) { delete[] tmp; tmp = 0; } if (rTable != 0) delete[] rTable; if (rList != 0) { delete[] rList; } if (m_entry != 0) { delete[] m_entry; m_entry = 0; } } void CS::CheckFallback() { } ngmlr-0.2.7+git20210816.a2a31fb/src/CS.h000066400000000000000000000120431410636150300166240ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __CS_H__ #define __CS_H__ //#include "NGM.h" #include "SequenceLocation.h" #include "MappedRead.h" #include "ScoreBuffer.h" #include #include #include #include #include /* Candidate Search: Initialisierung: Iteriere ueber jeden Praefix der definierten Referenzen (config:ref_mode mit -1=alle, 0..n eine einzelne referenz) Fuege in RefTable fuer diesen Praefix seine Position und die Id des Referenzstrings ein Suche: Iteriere ueber jeden Pruefix des Reads Lies fuer diesen Praefix die Positionsliste aus RefTable Fuer jede Position dieses Praefixes Offset um die Position des Praefixes (=normalisierung auf den Read-Anfang) fast_mode: Pruefe rTable-Capactiy, wenn overflow -> Neustart der Suche im safe_mode Schreibe in rTable mit linearem Kollisionshandling save_mode: Schreibe in iTable Sammle Ergebnisse ein: Iteriere ueber jedes Element in fast_mode:rTable / save_mode:iTable Wenn count > threshhold, schicke es zur weiterverarbeitung */ class CS: public NGMTask { protected: static volatile int s_ThreadCount; const int m_CSThreadID; const int m_BatchSize; std::vector m_CurrentBatch; int m_CurrentSeq; int m_CurrentReadLength; int m_ProcessedReads; int m_DiscardedReads; // volatile int m_Candidates; int m_Overflows; //float weightSum; const IRefProvider* m_RefProvider; RefEntry* m_entry; uint m_entryCount; int c_SrchTableBitLen; int c_BitShift; int c_SrchTableLen; uint m_PrefixBaseSkip; bool m_Fallback; typedef void (*PrefixIterationFn)(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); typedef void (CS::*AddLocationFn)(const SequenceLocation& loc, const double freq); static void BuildPrefixTable(ulong prefix, uloc pos, void* data); static void PrefixSearch(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); virtual int CollectResultsStd(MappedRead* read); int CollectResultsFallback(MappedRead* read); void FilterScore(LocationScore* score); void CheckFallback(); virtual int RunBatch(ScoreBuffer * sw, AlignmentBuffer * out); int RunRead(MappedRead * currentRead, PrefixIterationFn pFunc, ScoreBuffer * sw, AlignmentBuffer * out); void SendToBuffer(MappedRead* read, ScoreBuffer * sw, AlignmentBuffer * out); void AllocRefEntryChain(); CSTableEntry* rTable; // standard int currentState; int* rList; int rListLength; float m_CsSensitivity; float currentThresh; float maxHitNumber; uint hpoc; inline uint Hash(uloc n) { //Multiplication Method (Corment) //static float A = 0.5f * (sqrt(5) - 1); //static uloc m = floor(A * pow(2, 64)); //static uint m = 2654435761; static uloc m = 11400714819323199488u; return uint((n * m) >> c_BitShift); } inline void SetSearchTableBitLen(int bitLen) { if (bitLen >= 24) { Log.Error("SearchTable exceeded length."); } c_SrchTableBitLen = bitLen; c_BitShift = 64 - c_SrchTableBitLen; c_SrchTableLen = (int) pow(2, c_SrchTableBitLen); } private: static const int estimateCount = 40000; void debugCS(MappedRead * read, int& n, float& mi_Threshhold); Align computeAlignment(MappedRead* read, int const scoreId, int const corridor); float scoreReadPart(char const * const readSeq, int const qryLen, int const bin, long const refBin); LocationScore * tmp; int tmpSize; IAlignment * oclAligner; AlignmentBuffer * alignmentBuffer; public: //AddLocationFn AddLocation; virtual void AddLocationStd(const uloc loc, const bool reverse, const double freq); void AddLocationFallback(const SequenceLocation& loc, const double freq); static uint prefixBasecount; static uint prefixBits; static ulong prefixMask; inline static const uint GetPrefixLength() { return prefixBasecount; } static void Init(); static void Cleanup(); static void PrefixIteration(const char* sequence, uloc length, PrefixIterationFn func, ulong mutateFrom, ulong mutateTo, void* data, uint prefixskip = 0, uloc offset = 0); static void PrefixIteration(const char* sequence, uloc length, PrefixIterationFn func, ulong mutateFrom, ulong mutateTo, void* data, uint prefixskip, uloc offset, int prefixBaseCount); CS(bool useBuffer = true); ~CS(); void DoRun(); inline int GetStage() const { return 0; } inline const char* GetName() const { return "CS"; } }; //int const static csBitShift = 2; //inline static int calc_binshift() { // int corridor = 4; // int l = 0; // while ((corridor >>= 1) > 0) // ++l; // return l; //} inline uloc GetBin(uloc pos) { static int const csBitShift = Config.getBinSize(); // static int shift = calc_binshift(); return pos >> csBitShift; } inline uloc ResolveBin(uloc bin) { static int const csBitShift = Config.getBinSize(); // static int shift = calc_binshift(); static uint offset = (csBitShift > 0) ? 1 << (csBitShift - 1) : 0; return (bin << csBitShift) + offset; } #endif ngmlr-0.2.7+git20210816.a2a31fb/src/CSstatic.cpp000066400000000000000000000032341410636150300203710ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "CS.h" uint CS::prefixBasecount = 13; uint CS::prefixBits = prefixBasecount * 2; ulong CS::prefixMask = ((ulong) 1 << prefixBits) - 1; inline int min(int a, int b) { return (a < b) ? a : b; } // A->0 C->1 T->2 G->3 inline char encode(char c) { return (c >> 1) & 3; } // Iteriert ueber jeden Praefix in sequence und fuehrt fuer diesen die Funktion func aus void CS::PrefixIteration(char const * sequence, uloc length, PrefixIterationFn func, ulong mutateFrom, ulong mutateTo, void* data, uint prefixskip, uloc offset) { if (length < prefixBasecount) return; if (*sequence == 'N') { uint n_skip = 1; while (*(sequence + n_skip) == 'N') ++n_skip; sequence += n_skip; if (n_skip >= (length - prefixBasecount)) return; length -= n_skip; offset += n_skip; } ulong prefix = 0; for (uloc i = 0; i < prefixBasecount - 1; ++i) { char c = *(sequence + i); if (c == 'N') { PrefixIteration(sequence + i + 1, length - i - 1, func, mutateFrom, mutateTo, data, prefixskip, offset + i + 1); return; } prefix = prefix << 2; char cx = encode(c); prefix |= cx; } uint skipcount = prefixskip; for (uloc i = prefixBasecount - 1; i < length; ++i) { char c = *(sequence + i); if (c == 'N') { PrefixIteration(sequence + i + 1, length - i - 1, func, mutateFrom, mutateTo, data, prefixskip, offset + i + 1); return; } prefix = prefix << 2; char cx = encode(*(sequence + i)); prefix |= cx; prefix &= prefixMask; if (skipcount == prefixskip) { func(prefix, offset + i + 1 - prefixBasecount, mutateFrom, mutateTo, data); skipcount = 0; } else { ++skipcount; } } } ngmlr-0.2.7+git20210816.a2a31fb/src/ConvexAlign.cpp000066400000000000000000000476711410636150300211060ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "ConvexAlign.h" #include #include #include #include #include //TODO: remove #define pRef pBuffer1 #define pQry pBuffer2 namespace Convex { int alignmentId = 0; int NumberOfSetBits(uint32_t i) { // Java: use >>> instead of >> // C or C++: use uint32_t i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; } ConvexAlign::ConvexAlign(int const stdOutMode, float const match, float const mismatch, float const gapOpen, float const gapExtend, float const gapExtendMin, float const gapDecay): maxBinaryCigarLength(200000), pacbioDebug(false), stdoutPrintAlignCorridor(stdOutMode) { mat = match; mis = mismatch; gap_open_read = gapOpen; gap_open_ref = gapOpen; gap_ext = gapExtend; gap_decay = gapDecay; gap_ext_min = gapExtendMin; if(pacbioDebug) { fprintf(stderr, "mat: %f mis: %f gap_open_read: %f gap_open_ref: %f gap_ext: %f gap_decay: %f gapExtendMin: %f\n", mat, mis, gap_open_read, gap_open_ref, gap_ext, gap_decay, gapExtendMin); } matrix = new AlignmentMatrix(); binaryCigar = new int[maxBinaryCigarLength]; } ConvexAlign::~ConvexAlign() { delete matrix; matrix = 0; delete[] binaryCigar; binaryCigar = 0; } int ConvexAlign::printCigarElement(char const op, int const length, char * cigar) { int offset = 0; offset = sprintf(cigar, "%d%c", length, op); return offset; } void addPosition(Align & result, int & nmIndex, int posInRef, int posInRead, int Yi) { if (posInRead > 16 && posInRef > 16) { if (nmIndex >= result.nmPerPostionLength) { fprintf(stderr, "Debug: PositionNM reallocated.\n"); int const tmpLength = result.nmPerPostionLength * 2; PositionNM * tmp = new PositionNM[tmpLength]; if (result.nmPerPosition != 0) { memcpy(tmp, result.nmPerPosition, result.nmPerPostionLength * sizeof(PositionNM)); delete[] result.nmPerPosition; result.nmPerPosition = 0; } result.nmPerPosition = tmp; result.nmPerPostionLength = tmpLength; } result.nmPerPosition[nmIndex].readPosition = posInRead - 16; result.nmPerPosition[nmIndex].refPosition = posInRef - 16; result.nmPerPosition[nmIndex].nm = Yi; nmIndex += 1; } } int ConvexAlign::convertCigar(char const * const refSeq, Align & result, FwdResults & fwdResults, int const externalQStart, int const externalQEnd) { //*********************// //Inversion detection init //*********************// uint buffer = 0; int posInRef = 0; int posInRead = 0; //*********************// //General init //*********************// int nmIndex = 0; int exactAlignmentLength = 0; int finalCigarLength = 0; int cigar_offset = 0; int md_offset = 0; int binaryCigarIndex = fwdResults.alignment_offset; //*********************// // Set QStart //*********************// result.QStart = ((binaryCigar[binaryCigarIndex] >> 4) + externalQStart); if (result.QStart > 0) { cigar_offset += printCigarElement('S', result.QStart, result.pRef + cigar_offset); finalCigarLength += result.QStart; } posInRead = binaryCigar[binaryCigarIndex] >> 4; //Positions in read and ref for start of alignment result.firstPosition.refPosition = posInRef; result.firstPosition.readPosition = posInRead; //QStart of aligned sequence, but not for full read (like result.QStart) //*********************// // Translate CIGAR to char and compute MD //*********************// int matches = 0; int alignmentLength = 0; int cigar_m_length = 0; int md_eq_length = 0; int ref_index = 0; int overallMatchCount = 0; //uint const maxIndelLength = 5; uint const maxIndelLength = 1; //Inversion detection Arndt int Yi = 0; for (int j = binaryCigarIndex + 1; j < (maxBinaryCigarLength - 1); ++j) { int cigarOp = binaryCigar[j] & 15; int cigarOpLength = binaryCigar[j] >> 4; alignmentLength += cigarOpLength; switch (cigarOp) { case CIGAR_X: cigar_m_length += cigarOpLength; //Produces: [0-9]+(([A-Z]+|\^[A-Z]+)[0-9]+)* //instead of: [0-9]+(([A-Z]|\^[A-Z]+)[0-9]+)* for (int k = 0; k < cigarOpLength; ++k) { md_offset += sprintf(result.pQry + md_offset, "%d", md_eq_length); md_eq_length = 0; md_offset += sprintf(result.pQry + md_offset, "%c", refSeq[ref_index++]); buffer = buffer << 1; buffer = buffer | 1; // Yi = std::max(0, Yi + 1); Yi = NumberOfSetBits(buffer); addPosition(result, nmIndex, posInRef++, posInRead++, Yi); } exactAlignmentLength += cigarOpLength; break; case CIGAR_EQ: cigar_m_length += cigarOpLength; md_eq_length += cigarOpLength; matches += cigarOpLength; overallMatchCount += cigarOpLength; for (int k = 0; k < cigarOpLength; ++k) { buffer = buffer << 1; // Yi = std::max(0, Yi - 1); Yi = NumberOfSetBits(buffer); addPosition(result, nmIndex, posInRef++, posInRead++, Yi); } ref_index += cigarOpLength; exactAlignmentLength += cigarOpLength; break; case CIGAR_D: if (cigar_m_length > 0) { cigar_offset += printCigarElement('M', cigar_m_length, result.pRef + cigar_offset); finalCigarLength += cigar_m_length; cigar_m_length = 0; } cigar_offset += printCigarElement('D', cigarOpLength, result.pRef + cigar_offset); md_offset += sprintf(result.pQry + md_offset, "%d", md_eq_length); md_eq_length = 0; result.pQry[md_offset++] = '^'; for (int k = 0; k < cigarOpLength; ++k) { result.pQry[md_offset++] = refSeq[ref_index++]; buffer = buffer << 1; if (k < maxIndelLength) { buffer = buffer | 1; Yi = std::max(0, Yi + 1); } addPosition(result, nmIndex, posInRef++, posInRead, Yi); } exactAlignmentLength += cigarOpLength; break; case CIGAR_I: if (cigar_m_length > 0) { cigar_offset += printCigarElement('M', cigar_m_length, result.pRef + cigar_offset); finalCigarLength += cigar_m_length; cigar_m_length = 0; } cigar_offset += printCigarElement('I', cigarOpLength, result.pRef + cigar_offset); finalCigarLength += cigarOpLength; for (int k = 0; k < cigarOpLength; ++k) { buffer = buffer << 1; if (k < maxIndelLength) { buffer = buffer | 1; Yi = std::max(0, Yi + 1); } // addPosition(result, nmIndex, posInRef++, posInRead, Yi); posInRead += 1; } exactAlignmentLength += cigarOpLength; break; default: fprintf(stderr, "Invalid cigar string: %d\n", cigarOp); throw 1; } } //*********************// //Print last element //*********************// md_offset += sprintf(result.pQry + md_offset, "%d", md_eq_length); if (cigar_m_length > 0) { cigar_offset += printCigarElement('M', cigar_m_length, result.pRef + cigar_offset); finalCigarLength += cigar_m_length; cigar_m_length = 0; } //*********************// //Set QEnd //*********************// result.QEnd = ((binaryCigar[maxBinaryCigarLength - 1] >> 4) + externalQEnd); if (result.QEnd > 0) { cigar_offset += printCigarElement('S', result.QEnd, result.pRef + cigar_offset); } finalCigarLength += result.QEnd; result.Identity = matches * 1.0f / alignmentLength; result.pRef[cigar_offset] = '\0'; result.pQry[md_offset] = '\0'; result.NM = alignmentLength - matches; result.alignmentLength = exactAlignmentLength; // if (nmPerPositionLength < exactAlignmentLength) { // fprintf(stderr, "Alignmentlength (%d) < exactAlingmentlength (%d)\n", // nmPerPositionLength, exactAlignmentLength); // throw 1; // } // fprintf(stderr, "\n==== Matches: %d of %d ====\n", overallMatchCount, // posInRead); //Positions in read and ref for end of alignment result.lastPosition.refPosition = posInRef; result.lastPosition.readPosition = posInRead; // extData[edIndex++] = posInRef; // extData[edIndex++] = posInRead; //QEnd of aligned sequence, but not for full read (like result.QEnd) return finalCigarLength; } bool ConvexAlign::revBacktrack(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId) { if (fwdResults.best_read_index <= 0) { return false; } bool validAlignment = true; int binaryCigarIndex = maxBinaryCigarLength - 1; int cigar_element = CIGAR_S; int cigar_element_length = fwdResults.qend; int cigarStringLength = fwdResults.qend; int x = fwdResults.best_ref_index; int y = fwdResults.best_read_index; // AlignmentMatrix::MatrixElement currentElement; char currentElement = 0; // while ((currentElement = matrix->getElement(x, y)->direction) != CIGAR_STOP) { while ((currentElement = *matrix->getDirection(x, y)) != CIGAR_STOP) { // if (x < 0 || y < 0 || x > matrix->getWidth() // || y > matrix->getHeight()) { // fprintf(stderr, "Error in backtracking. x, y indexing error.\n"); // return false; // } //TODO: add corridor check. backtracking path too close to corridor end if (!matrix->validPath(x, y)) { if (pacbioDebug) { fprintf(stderr, "Corridor probably too small\n"); } return false; } if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", readId, alignmentId, x, y, 2); } if (currentElement == CIGAR_X || currentElement == CIGAR_EQ) { y -= 1; x -= 1; cigarStringLength += 1; } else if (currentElement == CIGAR_I) { y -= 1; cigarStringLength += 1; } else if (currentElement == CIGAR_D) { x -= 1; } else { fprintf(stderr, "Error in backtracking. Invalid CIGAR operation found\n"); return false; } if (currentElement == cigar_element) { cigar_element_length += 1; } else { binaryCigar[binaryCigarIndex--] = (cigar_element_length << 4 | cigar_element); cigar_element = currentElement; cigar_element_length = 1; } } // Add last element to binary cigar binaryCigar[binaryCigarIndex--] = (cigar_element_length << 4 | cigar_element); if (binaryCigarIndex < 0) { fprintf(stderr, "Error in backtracking. CIGAR buffer not long enough\n"); return false; } binaryCigar[binaryCigarIndex--] = ((y + 1) << 4 | CIGAR_S); cigarStringLength += (y + 1); fwdResults.ref_position = x + 1; fwdResults.qstart = (y + 1); //qend was set by "forward" kernel fwdResults.alignment_offset = binaryCigarIndex + 1; if (matrix->getHeight() != cigarStringLength) { fprintf(stderr, "Error read length != cigar length: %d vs %d\n", matrix->getHeight(), cigarStringLength); validAlignment = false; } return validAlignment; } int ConvexAlign::GetScoreBatchSize() const { return 0; } int ConvexAlign::GetAlignBatchSize() const { return 0; } int ConvexAlign::BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData) { throw "Not implemented"; fprintf(stderr, "Unsupported alignment mode %i\n", mode); return 0; } int ConvexAlign::SingleAlign(int const mode, CorridorLine * corridorLines, int const corridorHeight, char const * const refSeq, char const * const qrySeq, Align & align, int const externalQStart, int const externalQEnd, void * extData) { alignmentId = align.svType; align.Score = -1.0f; int finalCigarLength = -1; try { int const refLen = strlen(refSeq); int const qryLen = strlen(qrySeq); matrix->prepare(refLen, qryLen, corridorLines, corridorHeight); align.pBuffer2[0] = '\0'; FwdResults fwdResults; // Debug: rscript convex-align-vis.r if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", mode, alignmentId, refLen, qryLen, -1); } AlignmentMatrix::Score score = fwdFillMatrix(refSeq, qrySeq, fwdResults, mode); bool validAlignment = revBacktrack(refSeq, qrySeq, fwdResults, mode); if (validAlignment) { finalCigarLength = convertCigar(refSeq + fwdResults.ref_position, align, fwdResults, externalQStart, externalQEnd); align.PositionOffset = fwdResults.ref_position; align.Score = score; } if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", mode, alignmentId, (int) score, finalCigarLength, -3); } } catch (...) { align.Score = -1.0f; finalCigarLength = -1; } matrix->clean(); return finalCigarLength; } int ConvexAlign::SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & align, void * extData) { fprintf(stderr, "SingleAlign not implemented"); throw "Not implemented"; } AlignmentMatrix::Score ConvexAlign::fwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResult, int readId) { AlignmentMatrix::Score curr_max = -1.0f; for (int y = 0; y < matrix->getHeight(); ++y) { matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); // Debug: rscript convex-align-vis.r if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", readId, alignmentId, xOffset, y, 0); printf("%d\t%d\t%d\t%d\t%d\n", readId, alignmentId, xOffset + matrix->getCorridorLength(y), y, 1); } char const read_char_cache = qrySeq[y]; for (int x = xOffset; x < (xOffset + matrix->getCorridorLength(y)); ++x) { if (x >= matrix->getWidth() || x < 0) { continue; } // AlignmentMatrix::MatrixElement const & diag = // matrix->getElementConst(x - 1, y - 1); AlignmentMatrix::Score diag_score = matrix->getScore(x - 1, y - 1); AlignmentMatrix::MatrixElement const & up = *matrix->getElement(x, y - 1); AlignmentMatrix::MatrixElement const & left = *matrix->getElement( x - 1, y); bool const eq = read_char_cache == refSeq[x]; AlignmentMatrix::Score const diag_cell = diag_score + ((eq) ? mat : ((refSeq[x] != 'x') ? mis : mis * 100.0f)); AlignmentMatrix::Score up_cell = 0; AlignmentMatrix::Score left_cell = 0; int ins_run = 0; int del_run = 0; if (up.direction == CIGAR_I) { ins_run = up.indelRun; if (up.score == 0) { up_cell = 0; } else { up_cell = up.score + std::min(gap_ext_min, gap_ext + ins_run * gap_decay); } } else { up_cell = up.score + gap_open_read; } if (left.direction == CIGAR_D) { del_run = left.indelRun; if (left.score == 0) { left_cell = 0; } else { left_cell = left.score + std::min(gap_ext_min, gap_ext + del_run * gap_decay); } } else { left_cell = left.score + gap_open_ref; } //find max AlignmentMatrix::Score max_cell = 0; max_cell = std::max(left_cell, max_cell); max_cell = std::max(diag_cell, max_cell); max_cell = std::max(up_cell, max_cell); AlignmentMatrix::MatrixElement * current = matrix->getElementEdit(x, y); char & currentDirection = *matrix->getDirection(x, y); if (del_run > 0 && max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = del_run + 1; } else if (ins_run > 0 && max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = ins_run + 1; } else if (max_cell == diag_cell) { current->score = max_cell; if (eq) { current->direction = CIGAR_EQ; currentDirection = CIGAR_EQ; } else { current->direction = CIGAR_X; currentDirection = CIGAR_X; } current->indelRun = 0; } else if (max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = 1; } else if (max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = 1; } else { current->score = 0; current->direction = CIGAR_STOP; currentDirection = CIGAR_STOP; current->indelRun = 0; } if (max_cell > curr_max) { curr_max = max_cell; fwdResult.best_ref_index = x; fwdResult.best_read_index = y; fwdResult.max_score = curr_max; } } } fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; if (matrix->getHeight() == 0) { fwdResult.best_read_index = fwdResult.best_ref_index = 0; } return curr_max; } int ConvexAlign::BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData) { throw "Not implemented"; return 0; } } // g++ -I ../include/ ConvexAlign.cpp -o ConvexAlign && ./ConvexAlign //int main(int argc, char **argv) { // // IAlignment * aligner = new Convex::ConvexAlign(0); // //// char const * ref = //// "TCAAGATGCCATTGTCCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCTCCTGCC"; // char const * ref = // "AGATACATTGTTACTAACTAAGGCCCTACACCAGCAAAGATACATTGTTACTAAGTAAGGCCCTGCACCAACACAG"; ////// char const * qry = ////// "TCAAGATGCCAATTGTCCCCCGGCCCCCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC"; //// char const * qry = //// "CGGGGCCACGGCCACCGCTGCCCTGCC"; //// // char const * qry = // "CCAGAGCAAGTTCCCGGGGGGTGGCGCATAGATGCAGCGGTCTGGGTTCTGTGGCTGGGGGAGTTGGCTTGGGGTCCGTGGCTTGGGTCAGTCTTCAAGAGCCACCCTGGGTGGCACTCCAGGTTCTCTTGGTCTGGGGGGAATTACCCTGACCCCAGCGGTTTCACGGCCTCCTCCCCACTCAGCCTGGGGGAGAGTCCAGGGTCGGCCTGTCCCCCTCCCCCCACTCCTGTCACTATCAGTCCCCTGTGCTCAGCTTACTGGCAGGGTTCCTCCTGGCTGTCCCCTCCTGCCTCCAGCGCTCTTTCCTCAGGTGTCCACGAGCTCGTCCTCATCCCTTTCTGGTCCTGCTCAGATGCCGCCTGAGGCTCCCAAAACAGGGTCTCACTCTGTCACCCAGGGTGGAGTGCAGTGGTGCAATCCAGCTCACTGCATCCTTGACCTCCCAGGCTCAAGCGACCTCTGCCAGCGAGCTTGTTCAATTCCTGCACCAACACGATACATTGTTCTAACTAGGCCCTACACACAGCAAAGATACATTGTACTTAAGTAAGGGCCCTGCACCAACACAGATACATTGTTACTAAGTAGAGGCCCTGCACCAACACACGATACACTTGTTACTAACTAAGGCCCTGCACCAACACAGATACGTTAGTTACTAAGTAAGGCCCTGCACCAACACAGATACGTTGTTACTAAATAAGGCCCTGTACCAACACAGATACATTGTTACTAACTAAGGCCCTGCACCAACACAGATACTTGTTACTAAGTAAGGCCCTGCTACCAACACAGATACATTGTTACTAACTAAGCCCTGCACCAGCCACAGATACATTGTTACTAAGGGCCCTACACCAGCACAGATACATTGTTACTAAGGCCCTGCACCAACACAGATACGTTGTTACTAAGTGAGCCCTGCACCAACACAGATACATTGTTACTAAGTAAGGCCCTGCACCAGCACGAGATACATTGTTACTAAGGCCCTACACCAGCACAGGATAACATTGTCTACTAACTAAGGCCCTGCACGCAACAAAGATACGTATGTTACTAAGTAAGGCCCTGCACCAACACAGATACATTGTTACTAACTAAGGCCCCATGCACCAACACAGATAATTGTTACAAGGCCCTGCACCAACACAGATACATTGTTACTAACTAAGGCCCTGCACCAACACAGATACGTTGTTACTAAGTAAGGCCCTTGCACCAACACAATACATTGTTACTAAATAAGGCCCTGTACCAACATTCAGATACATTGTTACTAACTAAGGCCTGCACCAACACAGATACGTTGTTACTAAGTAAGGCCCTGTACCAACCAGGACTACATTGTTACTAACTAAGGCCCTGCACCACACAGATCGTTGTTTACTAAGTAAGGCCCTGGCACCAACACAGATACATTGTTACTAACTAAGGCCCTGCACAACACAATACATTGTTACTAAGGCCCTGCACCAACACAGATACATTGTTACTAAGTAAGGCCCTGCACCAACACGATACATTGTTACTACTAAGGCCCTGCACCAACACAAATACGTTCTTACTAAGTAAGGCCCTGCACCAACACAGATACATTGTACTAACTAAGGCCCTGTACAACACAGATACGTTGTTACTAAGTAAGGCCCTGCACCAACACAGACTACATTGTTACTAGGCCCTGCACCAAACACAGATACATTGTACTAAGTAAGGCCCTGCAGCCAACTACCAGATGACATTGTTACTAACTAAGGCCCTGCACCAGCACAGATATATTGTTACTAAAGGCCCTGCACCAACCTACAGATACATTGTTACTAACTAAGGCCTGCACCAACAAGATATGTTGTTACTAAGGCCCTGCACTCACACAGATACATTGTTACTAAGTAAGGGCCCTGCACCAACACAGATACATTGTTACTAACTAAAGGCCCCTGCACCAACACAGATAGTTGTTACTAAGTATGGCCCTCACCAACACAGATACATTGTTACTAAGGCCCTGCACCAACACAGATACATGTTACTAAGTAAGGCCCTTGCACCAACACAGATACATTTGTTACTAACTAAGGCCCTGCACCAACACAGATACATTGTACTAAGGCCCTACACCGAGAATGGATACATTGTCACATGGTTACCTAAAGCCTTGCACCAACATGGACACATCATTACTAAACTAAGGCCCTGCACCAACACAGATACATTGTTACTAAGGCCCTGCACCAACACAGATACATTGTTACTAAGATAAGAGCCCTGCACCAACACAGAGTACATTGTTACTAACAAGGCCCTCACCAGCACAGATATATTGTTACTAAGGCCCTGACTCAACACAGATAATTGTTACTAACTCAAGGCCCTGCACCAACCAGATATGTTGTTACTAAGGCCCTGCACCCCAACACAGATACATTGTTACTAAGGCCCGCACCAACACAAGATACATTGTTACTAAGTAAGGCCCTGCACCAACACAGATACGTTGTTACTAACTAAGGCCCTGCACCAACACAGATACGTTGTTACTCGAAGTAAGGCCCTGCACCAATCACAATACATTGTTACTAAGGCCCTGCACCAAACAGATACATTGTTACTAAGTAAGGCCCTGCACCATACACAGATGCATTTTAGCTAACTAAGGCCCTGTACCAACACAGATACATTGTTACTAGCTAAGGCCCTGCACCAACACAAGATACATTGTTACTAAGTAAGGCCCTGTACCAACACAGATATATTGTTACTAACTAAGGCCCTGCACCAACACAGATACGGTTGTTACTAAGTAAGGC"; // fprintf(stderr, "Ref: %s\n", ref); // fprintf(stderr, "Read: %s\n", qry); // // Align align; // // align.pBuffer1 = new char[strlen(ref) * 4]; // align.pBuffer2 = new char[strlen(ref) * 4]; // // int result = aligner->SingleAlign(0, 20, ref, qry, align, 0); // fprintf(stderr, "Alignment terminated with: %d\n", result); // fprintf(stderr, "Score: %f\n", align.Score); // fprintf(stderr, "Cigar: %s\n", align.pBuffer1); // fprintf(stderr, "MD: %s\n", align.pBuffer2); // // delete aligner; // aligner = 0; // // return 0; //} ngmlr-0.2.7+git20210816.a2a31fb/src/ConvexAlign.h000066400000000000000000000063501410636150300205400ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef CONVEXALIGN_H_ #define CONVEXALIGN_H_ #include "IAlignment.h" #include "Types.h" #include "AlignmentMatrix.h" namespace Convex { class ConvexAlign: public IAlignment { public: ConvexAlign(int const stdOutMode, float const match, float const mismatch, float const gapOpen, float const gapExtend, float const gapExtendMin, float const gapDecay); virtual ~ConvexAlign(); virtual int GetScoreBatchSize() const; virtual int GetAlignBatchSize() const; /** * Not implemented! */ virtual int BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData); /** * Not implemented! */ virtual int BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData); virtual int SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & result, void * extData); /** * Main function. Compute alignment based on "corridor layout" */ virtual int SingleAlign(int const mode, CorridorLine * corridor, int const corridorHeight, char const * const refSeq, char const * const qrySeq, Align & result, int const externalQStart, int const externalQEnd, void * extData); private: /** * Information that hase to be passed * from fwd to backward and compute cigar step */ struct FwdResults { int best_ref_index; int best_read_index; int max_score; int qend; int qstart; int ref_position; int alignment_offset; }; /** * Scoring function */ AlignmentMatrix::Score mat; AlignmentMatrix::Score mis; AlignmentMatrix::Score gap_open_read; AlignmentMatrix::Score gap_open_ref; AlignmentMatrix::Score gap_ext; AlignmentMatrix::Score gap_ext_min; AlignmentMatrix::Score gap_decay; AlignmentMatrix * matrix; /** Temporary storage for binary * representation of the CIGAR string * produced by backtracking step. */ int * binaryCigar; /** * Max length of binaryCigar */ int const maxBinaryCigarLength; /** * Debug flag * TODO: convert to preprocessor define */ bool const pacbioDebug; /** * Prints debug information for * aligment corridor visualization * to stdout */ int const stdoutPrintAlignCorridor; /** * Print CIGAR element to cigar string * Helper function used by convertCigar */ int printCigarElement(char const op, int const length, char * cigar); /** * Forward step of alignment * Fills directionMatrix */ AlignmentMatrix::Score fwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); /** * Follows direction matrix (backtracking) * Creates reversed binary representation of the cigar string */ bool revBacktrack(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); /** * Converts CIGAR to text and computes MD flag + stats */ int convertCigar(char const * const refSeq, Align & result, FwdResults & fwdResults, int const externalQStart, int const externalQEnd); }; #endif /* CONVEXALIGN_H_ */ } // namespace Convex ngmlr-0.2.7+git20210816.a2a31fb/src/ConvexAlignFast.cpp000066400000000000000000001322101410636150300217040ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "ConvexAlignFast.h" #include #include #include #include #include #include "IConfig.h" //TODO: remove #define pRef pBuffer1 #define pQry pBuffer2 namespace Convex { int ConvexAlignFast::NumberOfSetBits(uint32_t i) { // Java: use >>> instead of >> // C or C++: use uint32_t i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; } ConvexAlignFast::ConvexAlignFast(int const stdOutMode, float const match, float const mismatch, float const gapOpen, float const gapExtend, float const gapExtendMin, float const gapDecay): defaultMaxBinaryCigarLength(200000), pacbioDebug(false), stdoutPrintAlignCorridor(stdOutMode) { mat = match; mis = mismatch; gap_open_read = gapOpen; gap_open_ref = gapOpen; gap_ext = gapExtend; gap_decay = gapDecay; gap_ext_min = gapExtendMin; if(pacbioDebug) { fprintf(stderr, "mat: %f mis: %f gap_open_read: %f gap_open_ref: %f gap_ext: %f gap_decay: %f gapExtendMin: %f\n", mat, mis, gap_open_read, gap_open_ref, gap_ext, gap_decay, gapExtendMin); } matrix = new AlignmentMatrixFast(Config.getMaxMatrixSizeMB()); maxBinaryCigarLength = defaultMaxBinaryCigarLength; binaryCigar = new int[maxBinaryCigarLength]; alignmentId = 0; } ConvexAlignFast::~ConvexAlignFast() { delete matrix; matrix = 0; delete[] binaryCigar; binaryCigar = 0; } int ConvexAlignFast::printCigarElement(char const op, int const length, char * cigar, int & cigarOpCount, int cigarMaxLength) { int offset = 0; offset = sprintf(cigar, "%d%c", length, op); cigarOpCount += 1; return offset; } void ConvexAlignFast::addPosition(Align & result, int & nmIndex, int posInRef, int posInRead, int Yi) { if (posInRead > 16 && posInRef > 16) { if(nmIndex >= result.nmPerPostionLength) { fprintf(stderr, "Debug: PositionNM reallocated.\n"); int const tmpLength = result.nmPerPostionLength * 2; PositionNM * tmp = new PositionNM[tmpLength]; if(result.nmPerPosition != 0) { memcpy(tmp, result.nmPerPosition, result.nmPerPostionLength * sizeof(PositionNM)); delete[] result.nmPerPosition; result.nmPerPosition = 0; } result.nmPerPosition = tmp; result.nmPerPostionLength = tmpLength; } result.nmPerPosition[nmIndex].readPosition = posInRead - 16; result.nmPerPosition[nmIndex].refPosition = posInRef - 16; result.nmPerPosition[nmIndex].nm = Yi; nmIndex += 1; } } void ConvexAlignFast::checkMdBufferLength(int md_offset, Align& result, int const minDiff) { if (md_offset > (int) ((result.maxMdBufferLength * 0.9f)) || minDiff > (result.maxMdBufferLength - md_offset)) { result.maxMdBufferLength *= 2; char* tmp = new char[result.maxMdBufferLength]; memcpy(tmp, result.pQry, sizeof(char) * (result.maxMdBufferLength / 2)); delete[] result.pQry; result.pQry = tmp; tmp = 0; // fprintf(stderr, "Reallocating MD buffer (%d)\n", result.maxMdBufferLength); } } int ConvexAlignFast::convertCigar(char const * const refSeq, int const refSeqLength, Align & result, FwdResults & fwdResults, int const externalQStart, int const externalQEnd) { //*********************// //Inversion detection init //*********************// uint buffer = 0; int posInRef = 0; int posInRead = 0; //*********************// //General init //*********************// // Number of CIGAR operations. Currently BAM only supports < 64k CIGAR operations int cigarOpCount = 0; int nmIndex = 0; int exactAlignmentLength = 0; int finalCigarLength = 0; int cigar_offset = 0; int md_offset = 0; int binaryCigarIndex = fwdResults.alignment_offset; result.svType = 0; //*********************// // Set QStart //*********************// result.QStart = ((binaryCigar[binaryCigarIndex] >> 4) + externalQStart); if (result.QStart > 0) { cigar_offset += printCigarElement('S', result.QStart, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); finalCigarLength += result.QStart; } posInRead = binaryCigar[binaryCigarIndex] >> 4; //Positions in read and ref for start of alignment result.firstPosition.refPosition = posInRef; result.firstPosition.readPosition = posInRead; //QStart of aligned sequence, but not for full read (like result.QStart) //*********************// // Translate CIGAR to char and compute MD //*********************// int matches = 0; int alignmentLength = 0; int cigar_m_length = 0; int md_eq_length = 0; int ref_index = 0; int overallMatchCount = 0; //uint const maxIndelLength = 5; uint const maxIndelLength = 1; //Inversion detection Arndt int Yi = 0; for (int j = binaryCigarIndex + 1; j < (maxBinaryCigarLength - 1); ++j) { int cigarOp = binaryCigar[j] & 15; int cigarOpLength = binaryCigar[j] >> 4; alignmentLength += cigarOpLength; switch (cigarOp) { case CIGAR_X: cigar_m_length += cigarOpLength; //Produces: [0-9]+(([A-Z]+|\^[A-Z]+)[0-9]+)* //instead of: [0-9]+(([A-Z]|\^[A-Z]+)[0-9]+)* for (int k = 0; k < cigarOpLength; ++k) { checkMdBufferLength(md_offset, result, 100); md_offset += sprintf(result.pQry + md_offset, "%d", md_eq_length); md_eq_length = 0; md_offset += sprintf(result.pQry + md_offset, "%c", refSeq[ref_index++]); buffer = buffer << 1; buffer = buffer | 1; // Yi = std::max(0, Yi + 1); Yi = NumberOfSetBits(buffer); addPosition(result, nmIndex, posInRef++, posInRead++, Yi); } exactAlignmentLength += cigarOpLength; break; case CIGAR_EQ: cigar_m_length += cigarOpLength; md_eq_length += cigarOpLength; matches += cigarOpLength; overallMatchCount += cigarOpLength; for (int k = 0; k < cigarOpLength; ++k) { buffer = buffer << 1; // Yi = std::max(0, Yi - 1); Yi = NumberOfSetBits(buffer); addPosition(result, nmIndex, posInRef++, posInRead++, Yi); } ref_index += cigarOpLength; exactAlignmentLength += cigarOpLength; break; case CIGAR_D: if (cigar_m_length > 0) { cigar_offset += printCigarElement('M', cigar_m_length, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); finalCigarLength += cigar_m_length; cigar_m_length = 0; } cigar_offset += printCigarElement('D', cigarOpLength, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); checkMdBufferLength(md_offset, result, 100 + cigarOpLength); md_offset += sprintf(result.pQry + md_offset, "%d", md_eq_length); md_eq_length = 0; result.pQry[md_offset++] = '^'; for (int k = 0; k < cigarOpLength; ++k) { result.pQry[md_offset++] = refSeq[ref_index++]; buffer = buffer << 1; if (k < maxIndelLength) { buffer = buffer | 1; Yi = std::max(0, Yi + 1); } addPosition(result, nmIndex, posInRef++, posInRead, Yi); } exactAlignmentLength += cigarOpLength; break; case CIGAR_I: if (cigar_m_length > 0) { cigar_offset += printCigarElement('M', cigar_m_length, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); finalCigarLength += cigar_m_length; cigar_m_length = 0; } cigar_offset += printCigarElement('I', cigarOpLength, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); finalCigarLength += cigarOpLength; for (int k = 0; k < cigarOpLength; ++k) { buffer = buffer << 1; if (k < maxIndelLength) { buffer = buffer | 1; Yi = std::max(0, Yi + 1); } // addPosition(result, nmIndex, posInRef++, posInRead, Yi); posInRead += 1; } exactAlignmentLength += cigarOpLength; break; default: fprintf(stderr, "Invalid cigar string: %d\n", cigarOp); throw 1; } } //*********************// //Print last element //*********************// checkMdBufferLength(md_offset, result, 100); md_offset += sprintf(result.pQry + md_offset, "%d", md_eq_length); if (cigar_m_length > 0) { cigar_offset += printCigarElement('M', cigar_m_length, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); finalCigarLength += cigar_m_length; cigar_m_length = 0; } //*********************// //Set QEnd //*********************// result.QEnd = ((binaryCigar[maxBinaryCigarLength - 1] >> 4) + externalQEnd); if (result.QEnd > 0) { cigar_offset += printCigarElement('S', result.QEnd, result.pRef + cigar_offset, cigarOpCount, result.maxBufferLength); } finalCigarLength += result.QEnd; // fprintf(stderr, "CIGAR: %d, MD: %d, Length: %d\n", cigar_offset, md_offset, result.maxBufferLength); if(cigar_offset > result.maxBufferLength || md_offset > result.maxMdBufferLength) { fprintf(stderr, "CIGAR/MD buffer not long enough (%d %d > %d %d). Please report this!\n", cigar_offset, md_offset, result.maxBufferLength, result.maxMdBufferLength); fprintf(stderr, "CIGAR; %s\n", result.pBuffer1); fprintf(stderr, "MD; %s\n", result.pBuffer2); throw 1; } result.Identity = matches * 1.0f / alignmentLength; result.pRef[cigar_offset] = '\0'; result.pQry[md_offset] = '\0'; result.NM = alignmentLength - matches; result.alignmentLength = exactAlignmentLength; // if (nmPerPositionLength < exactAlignmentLength) { // fprintf(stderr, "Alignmentlength (%d) < exactAlingmentlength (%d)\n", // nmPerPositionLength, exactAlignmentLength); // throw 1; // } // fprintf(stderr, "\n==== Matches: %d of %d ====\n", overallMatchCount, // posInRead); //Positions in read and ref for end of alignment result.lastPosition.refPosition = posInRef; result.lastPosition.readPosition = posInRead; result.cigarOpCount = cigarOpCount; // extData[edIndex++] = posInRef; // extData[edIndex++] = posInRead; //QEnd of aligned sequence, but not for full read (like result.QEnd) return finalCigarLength; } bool ConvexAlignFast::revBacktrack(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId) { if (fwdResults.best_read_index <= 0) { return false; } bool validAlignment = true; int binaryCigarIndex = maxBinaryCigarLength - 1; int cigar_element = CIGAR_S; int cigar_element_length = fwdResults.qend; int cigarStringLength = fwdResults.qend; int x = fwdResults.best_ref_index; int y = fwdResults.best_read_index; // AlignmentMatrixFast::MatrixElement currentElement; char currentElement = 0; // while ((currentElement = matrix->getElement(x, y)->direction) != CIGAR_STOP) { while ((currentElement = *matrix->getDirection(x, y)) != CIGAR_STOP) { // if (x < 0 || y < 0 || x > matrix->getWidth() // || y > matrix->getHeight()) { // fprintf(stderr, "Error in backtracking. x, y indexing error.\n"); // return false; // } //TODO: add corridor check. backtracking path too close to corridor end if (!matrix->validPath(x, y)) { if (pacbioDebug) { fprintf(stderr, "Corridor probably too small\n"); } return false; } if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", readId, alignmentId, x, y, 2); } if (currentElement == CIGAR_X || currentElement == CIGAR_EQ) { y -= 1; x -= 1; cigarStringLength += 1; } else if (currentElement == CIGAR_I) { y -= 1; cigarStringLength += 1; } else if (currentElement == CIGAR_D) { x -= 1; } else { fprintf(stderr, "Error in backtracking. Invalid CIGAR operation found\n"); return false; } if (currentElement == cigar_element) { cigar_element_length += 1; } else { binaryCigar[binaryCigarIndex--] = (cigar_element_length << 4 | cigar_element); cigar_element = currentElement; cigar_element_length = 1; } if (binaryCigarIndex < 0) { fprintf(stderr, "Error in backtracking. CIGAR buffer not long enough. Please report this!\n"); throw 1; } } // Add last element to binary cigar binaryCigar[binaryCigarIndex--] = (cigar_element_length << 4 | cigar_element); binaryCigar[binaryCigarIndex--] = ((y + 1) << 4 | CIGAR_S); cigarStringLength += (y + 1); fwdResults.ref_position = x + 1; fwdResults.qstart = (y + 1); //qend was set by "forward" kernel fwdResults.alignment_offset = binaryCigarIndex + 1; if (matrix->getHeight() != cigarStringLength) { fprintf(stderr, "Error read length != cigar length: %d vs %d\n", matrix->getHeight(), cigarStringLength); validAlignment = false; } return validAlignment; } int ConvexAlignFast::GetScoreBatchSize() const { return 0; } int ConvexAlignFast::GetAlignBatchSize() const { return 0; } int ConvexAlignFast::BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData) { throw "Not implemented"; fprintf(stderr, "Unsupported alignment mode %i\n", mode); return 0; } int ConvexAlignFast::SingleAlign(int const mode, CorridorLine * corridorLines, int const corridorHeight, char const * const refSeq, char const * const qrySeq, Align & align, int const externalQStart, int const externalQEnd, void * extData) { alignmentId = align.svType; align.svType = 0; align.Score = -1.0f; int finalCigarLength = -1; // try { int const refLen = strlen(refSeq); int const qryLen = strlen(qrySeq); bool allocated = matrix->prepare(refLen, qryLen, corridorLines, corridorHeight); if (allocated) { align.pBuffer2[0] = '\0'; FwdResults fwdResults; // Debug: rscript convex-align-vis.r if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", mode, alignmentId, refLen, qryLen, -1); } AlignmentMatrixFast::Score score = fwdFillMatrixSSESimple(refSeq, qrySeq, fwdResults, mode); if (maxBinaryCigarLength < qryLen) { maxBinaryCigarLength = qryLen + 1; delete[] binaryCigar; binaryCigar = 0; binaryCigar = new int[maxBinaryCigarLength]; } bool validAlignment = revBacktrack(refSeq, qrySeq, fwdResults, mode); if (validAlignment) { finalCigarLength = convertCigar(refSeq + fwdResults.ref_position, refLen - fwdResults.ref_position, align, fwdResults, externalQStart, externalQEnd); align.PositionOffset = fwdResults.ref_position; align.Score = score; /** * Check if Qstart clipping was caused by N in reference */ int const ntestLength = 100; int nCount = 0; int probeCount = 0; for (int k = fwdResults.ref_position; k > std::max(0, fwdResults.ref_position - ntestLength); --k) { /** * Decode from SequenceProvider decodes N to X */ if (refSeq[k] == 'X') { nCount += 1; } probeCount += 1; } if (nCount > (probeCount * 0.8f)) { align.setBitFlag(0x1); } /** * Check if QEnd clipping was caused by N in reference */ nCount = 0; probeCount = 0; for (int k = align.lastPosition.refPosition; k < std::min(align.lastPosition.refPosition + ntestLength, refLen - fwdResults.ref_position); ++k) { /** * Decode from SequenceProvider decodes N to X */ if (refSeq[fwdResults.ref_position + k] == 'X') { nCount += 1; } probeCount += 1; } if (nCount > (probeCount * 0.8f)) { align.setBitFlag(0x1); } } else { // matrix->printMatrix(refSeq, qrySeq); // fprintf(stderr, "%d, %d, %d, %d\n", fwdResults.best_read_index, fwdResults.best_ref_index, fwdResults.ref_position, fwdResults.alignment_offset); if (pacbioDebug) { fprintf(stderr, "Could not backtrack alignment with score %f\n", score); } align.Score = -1.0f; finalCigarLength = -1; } if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", mode, alignmentId, (int) score, finalCigarLength, -3); } } // } catch (...) { // fprintf(stderr, "Exception in singlealign\n"); // align.Score = -1.0f; // finalCigarLength = -1; // } matrix->clean(); if (maxBinaryCigarLength != defaultMaxBinaryCigarLength) { maxBinaryCigarLength = defaultMaxBinaryCigarLength; delete[] binaryCigar; binaryCigar = 0; binaryCigar = new int[maxBinaryCigarLength]; } return finalCigarLength; } int ConvexAlignFast::SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & align, void * extData) { fprintf(stderr, "SingleAlign not implemented"); throw "Not implemented"; } //#define DEBUG_SSE #ifdef DEBUG_SSE #define SZ 100000 float** scorematrix=0; float** upcellmatrix=0; float** diagcellmatrix=0; float** leftcellmatrix=0; float** maxcellmatrix=0; int** dirmatrix=0; int** runmatrix=0; int** insrunmatrix=0; int** delrunmatrix=0; int** alloci() { int** ptr=new int*[SZ]; for(int i=0;igetHeight(); ++y) { matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); // Debug: rscript convex-align-vis.r if (stdoutPrintAlignCorridor == 6) { printf("%d\t%d\t%d\t%d\t%d\n", readId, alignmentId, xOffset, y, 0); printf("%d\t%d\t%d\t%d\t%d\n", readId, alignmentId, xOffset + matrix->getCorridorLength(y), y, 1); } char const read_char_cache = qrySeq[y]; for (int x = xOffset; x < (xOffset + matrix->getCorridorLength(y)); ++x) { if (x >= matrix->getWidth() || x < 0) { continue; } // AlignmentMatrixFast::MatrixElement const & diag = // matrix->getElementConst(x - 1, y - 1); AlignmentMatrixFast::Score diag_score = matrix->getScore(x - 1, y - 1); AlignmentMatrixFast::MatrixElement const & up = *matrix->getElement(x, y - 1); AlignmentMatrixFast::MatrixElement const & left = *matrix->getElement( x - 1, y); bool const eq = read_char_cache == refSeq[x]; AlignmentMatrixFast::Score const diag_cell = diag_score + ((eq) ? mat : mis); AlignmentMatrixFast::Score up_cell = 0; AlignmentMatrixFast::Score left_cell = 0; int ins_run = 0; int del_run = 0; if (up.direction == CIGAR_I) { ins_run = up.indelRun; if (up.score == 0) { up_cell = 0; } else { up_cell = up.score + std::min(gap_ext_min, gap_ext + ins_run * gap_decay); } } else { up_cell = up.score + gap_open_read; } if (left.direction == CIGAR_D) { del_run = left.indelRun; if (left.score == 0) { left_cell = 0; } else { left_cell = left.score + std::min(gap_ext_min, gap_ext + del_run * gap_decay); } } else { left_cell = left.score + gap_open_ref; } //find max AlignmentMatrixFast::Score max_cell = 0; max_cell = std::max(left_cell, max_cell); max_cell = std::max(diag_cell, max_cell); max_cell = std::max(up_cell, max_cell); AlignmentMatrixFast::MatrixElement * current = matrix->getElementEdit(x, y); char & currentDirection = *matrix->getDirection(x, y); if (del_run > 0 && max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = del_run + 1; } else if (ins_run > 0 && max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = ins_run + 1; } else if (max_cell == diag_cell) { current->score = max_cell; if (eq) { current->direction = CIGAR_EQ; currentDirection = CIGAR_EQ; } else { current->direction = CIGAR_X; currentDirection = CIGAR_X; } current->indelRun = 0; } else if (max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = 1; } else if (max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = 1; } else { current->score = 0; current->direction = CIGAR_STOP; currentDirection = CIGAR_STOP; current->indelRun = 0; } #ifdef DEBUG_SSE if(xscore; dirmatrix[x][y]=current->direction; runmatrix[x][y]=current->indelRun; upcellmatrix[x][y]=up_cell; leftcellmatrix[x][y]=left_cell; diagcellmatrix[x][y]=diag_cell; maxcellmatrix[x][y]=max_cell; insrunmatrix[x][y]=ins_run; delrunmatrix[x][y]=del_run; } #endif //printf("x=%d, y=%d, score=%f, dir=%d, run=%d\n",x,y,current->score,current->direction,current->indelRun); if (max_cell > curr_max) { curr_max = max_cell; fwdResult.best_ref_index = x; fwdResult.best_read_index = y; fwdResult.max_score = curr_max; } } } fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; if (matrix->getHeight() == 0) { fwdResult.best_read_index = fwdResult.best_ref_index = 0; } return curr_max; } AlignmentMatrixFast::Score ConvexAlignFast::FastfwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResult, int readId) { AlignmentMatrixFast::Score curr_max = -1.0f; for (int y = 0; y < matrix->getHeight(); ++y) { matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); char const read_char_cache = qrySeq[y]; int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); for (int x = std::max(0, xOffset); x < xMax; ++x) { AlignmentMatrixFast::Score diag_score = matrix->getElementUp(x - 1, y - 1)->score; AlignmentMatrixFast::MatrixElement const & up = *matrix->getElementUp(x,y - 1); AlignmentMatrixFast::MatrixElement const & left = *matrix->getElementCurr(x - 1, y); bool const eq = read_char_cache == refSeq[x]; AlignmentMatrixFast::Score const diag_cell = diag_score + ((eq) ? mat : mis); AlignmentMatrixFast::Score up_cell = 0; AlignmentMatrixFast::Score left_cell = 0; int ins_run = 0; int del_run = 0; if (up.direction == CIGAR_I) { ins_run = up.indelRun; if (up.score == 0) { up_cell = 0; } else { up_cell = up.score + std::min(gap_ext_min, gap_ext + ins_run * gap_decay); } } else { up_cell = up.score + gap_open_read; } if (left.direction == CIGAR_D) { del_run = left.indelRun; if (left.score == 0) { left_cell = 0; } else { left_cell = left.score + std::min(gap_ext_min, gap_ext + del_run * gap_decay); } } else { left_cell = left.score + gap_open_ref; } //find max AlignmentMatrixFast::Score max_cell = 0; max_cell = std::max(left_cell, max_cell); max_cell = std::max(diag_cell, max_cell); max_cell = std::max(up_cell, max_cell); AlignmentMatrixFast::MatrixElement * current = matrix->getElementEditCurr(x,y); char & currentDirection = *matrix->getDirection(x, y); if (del_run > 0 && max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = del_run + 1; } else if (ins_run > 0 && max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = ins_run + 1; } else if (max_cell == diag_cell) { current->score = max_cell; if (eq) { current->direction = CIGAR_EQ; currentDirection = CIGAR_EQ; } else { current->direction = CIGAR_X; currentDirection = CIGAR_X; } current->indelRun = 0; } else if (max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = 1; } else if (max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = 1; } else { current->score = 0; current->direction = CIGAR_STOP; currentDirection = CIGAR_STOP; current->indelRun = 0; } if (max_cell > curr_max) { curr_max = max_cell; fwdResult.best_ref_index = x; fwdResult.best_read_index = y; fwdResult.max_score = curr_max; } } } fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; if (matrix->getHeight() == 0) { fwdResult.best_read_index = fwdResult.best_ref_index = 0; } return curr_max; } #define SIMD_LEVEL 4 typedef union { __m128 v; float a[SIMD_LEVEL]; } SSEFloat; float ssat(__m128 d, int i) { SSEFloat f; f.v=d; return f.a[i]; } AlignmentMatrixFast::Score ConvexAlignFast::fwdFillMatrixSSESimple(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResult, int readId) { #ifdef DEBUG_SSE fwdFillMatrix(refSeq,qrySeq,fwdResult,readId); #endif AlignmentMatrixFast::Score curr_max = -1.0f; __m128 mat_sse = _mm_set1_ps(mat); __m128 mis_sse = _mm_set1_ps(mis); __m128 CIGAR_I_SSE = _mm_set1_ps(CIGAR_I); __m128 CIGAR_D_SSE = _mm_set1_ps(CIGAR_D); __m128 CIGAR_STOP_SSE = _mm_set1_ps(CIGAR_STOP); __m128 CIGAR_X_SSE = _mm_set1_ps(CIGAR_X); __m128 CIGAR_EQ_SSE = _mm_set1_ps(CIGAR_EQ); __m128 zero_sse = _mm_set1_ps(0); __m128 one_sse = _mm_set1_ps(1); __m128 gap_ext_min_sse = _mm_set1_ps(gap_ext_min); __m128 gap_ext_sse = _mm_set1_ps(gap_ext); __m128 gap_decay_sse = _mm_set1_ps(gap_decay); __m128 gap_open_read_sse = _mm_set1_ps(gap_open_read); for (int y = 0; y < matrix->getHeight(); ++y) { matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); char const read_char_cache = qrySeq[y]; __m128 read_char_cache_sse = _mm_set1_ps((float)read_char_cache); int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); for (int x = std::max(0, xOffset); x < xMax-SIMD_LEVEL; x+=SIMD_LEVEL) { //COMPUTE DIAGONAL SCORE __m128 ref_char_cache_sse = _mm_setr_ps((float)refSeq[x],(float)refSeq[x+1],(float)refSeq[x+2],(float)refSeq[x+3]); __m128 eq_sse = _mm_cmpeq_ps(read_char_cache_sse,ref_char_cache_sse); __m128 diag_score_sse; __m128 diag_cell_sse; __m128 up_score_sse; __m128 up_dir_sse; __m128 up_run_sse; //COMPUTE UP CELL if(x<1 || y==0 || x-1 < matrix->lastCorridor.offset || x+3 >= (matrix->lastCorridor.offset + matrix->lastCorridor.length) ) { const AlignmentMatrixFast::MatrixElement& up0 = *matrix->getElementUp(x, y - 1); const AlignmentMatrixFast::MatrixElement& up1 = *matrix->getElementUp(x + 1, y - 1); const AlignmentMatrixFast::MatrixElement& up2 = *matrix->getElementUp(x + 2, y - 1); const AlignmentMatrixFast::MatrixElement& up3 = *matrix->getElementUp(x + 3, y - 1); diag_score_sse = _mm_setr_ps(matrix->getElementUp(x - 1, y - 1)->score,up0.score,up1.score,up2.score); diag_cell_sse = _mm_add_ps(diag_score_sse, _mm_or_ps(_mm_and_ps(eq_sse, mat_sse),_mm_andnot_ps(eq_sse, mis_sse))); up_score_sse = _mm_setr_ps(up0.score,up1.score,up2.score,up3.score); up_dir_sse = _mm_setr_ps(up0.direction,up1.direction,up2.direction,up3.direction); up_run_sse = _mm_setr_ps(up0.indelRun,up1.indelRun,up2.indelRun,up3.indelRun); } else { const AlignmentMatrixFast::MatrixElement& up0 = *matrix->getElementUpUnprotected(x, y - 1); const AlignmentMatrixFast::MatrixElement& up1 = *matrix->getElementUpUnprotected(x + 1, y - 1); const AlignmentMatrixFast::MatrixElement& up2 = *matrix->getElementUpUnprotected(x + 2, y - 1); const AlignmentMatrixFast::MatrixElement& up3 = *matrix->getElementUpUnprotected(x + 3, y - 1); diag_score_sse = _mm_setr_ps(matrix->getElementUpUnprotected(x - 1, y - 1)->score,up0.score,up1.score,up2.score); diag_cell_sse = _mm_add_ps(diag_score_sse, _mm_or_ps(_mm_and_ps(eq_sse, mat_sse),_mm_andnot_ps(eq_sse, mis_sse))); up_score_sse = _mm_setr_ps(up0.score,up1.score,up2.score,up3.score); up_dir_sse = _mm_setr_ps(up0.direction,up1.direction,up2.direction,up3.direction); up_run_sse = _mm_setr_ps(up0.indelRun,up1.indelRun,up2.indelRun,up3.indelRun); } //if (up.direction == CIGAR_I) { // ins_run = up.indelRun; // if (up.score == 0) { // up_cell = 0; // } else { // up_cell = up.score // + std::min(gap_ext_min, // gap_ext + ins_run * gap_decay); // } //} else { // up_cell = up.score + gap_open_read; //} __m128 up_dir_eq_cigari_sse=_mm_cmpeq_ps(up_dir_sse,CIGAR_I_SSE); __m128 up_score_eq_zero_sse=_mm_cmpeq_ps(up_score_sse,zero_sse); __m128 up_cell_sse=_mm_or_ps( _mm_andnot_ps(up_dir_eq_cigari_sse,_mm_add_ps(up_score_sse,gap_open_read_sse) ), _mm_and_ps(up_dir_eq_cigari_sse, _mm_andnot_ps(up_score_eq_zero_sse, _mm_add_ps(up_score_sse, _mm_min_ps(gap_ext_min_sse, _mm_add_ps(gap_ext_sse, _mm_mul_ps(up_run_sse,gap_decay_sse) ) ) ) ) ) ); //__m128 left_dir_eq_cigard_sse=_mm_cmpeq_ps(left_dir_sse,CIGAR_I_SSE); //AlignmentMatrixFast::Score left_cell = 0; //if (left.direction == CIGAR_D) { // del_run = left.indelRun; // if (left.score == 0) { // left_cell = 0; // } else { // left_cell = left.score // + std::min(gap_ext_min, // gap_ext + del_run * gap_decay); // } //} else { // left_cell = left.score + gap_open_ref; //} __m128 curr_dir_sse=CIGAR_STOP_SSE; __m128 curr_run_sse=zero_sse; __m128 max_cell_sse=_mm_max_ps(zero_sse,_mm_max_ps(up_cell_sse,diag_cell_sse)); //} else if (max_cell == up_cell) { // current->score = max_cell; // current->direction = CIGAR_I; // currentDirection = CIGAR_I; // current->indelRun = 1; __m128 cmp_c_sse=_mm_cmpeq_ps(max_cell_sse,up_cell_sse); curr_dir_sse=_mm_or_ps( _mm_andnot_ps(cmp_c_sse,curr_dir_sse), _mm_and_ps(cmp_c_sse,CIGAR_I_SSE ) ); curr_run_sse=_mm_or_ps( _mm_andnot_ps(cmp_c_sse,curr_run_sse), _mm_and_ps(cmp_c_sse,one_sse) ); //} else if (max_cell == diag_cell) { // current->score = max_cell; // if (eq) { // current->direction = CIGAR_EQ; // currentDirection = CIGAR_EQ; // } else { // current->direction = CIGAR_X; // currentDirection = CIGAR_X; // } // current->indelRun = 0; __m128 cmp_b_sse=_mm_cmpeq_ps(max_cell_sse,diag_cell_sse); curr_dir_sse=_mm_or_ps( _mm_andnot_ps(cmp_b_sse,curr_dir_sse), _mm_and_ps(cmp_b_sse, _mm_or_ps( _mm_and_ps(eq_sse,CIGAR_EQ_SSE), _mm_andnot_ps(eq_sse,CIGAR_X_SSE) ) ) ); curr_run_sse=_mm_or_ps( _mm_andnot_ps(cmp_b_sse,curr_run_sse), _mm_and_ps(cmp_b_sse,zero_sse) ); //} else if (ins_run > 0 && max_cell == up_cell) { // current->score = max_cell; // current->direction = CIGAR_I; // currentDirection = CIGAR_I; // current->indelRun = ins_run + 1; __m128 cmp_a_sse=_mm_and_ps(_mm_cmpgt_ps(up_run_sse,zero_sse), _mm_cmpeq_ps(max_cell_sse,up_cell_sse)); curr_dir_sse=_mm_or_ps( _mm_andnot_ps(cmp_a_sse,curr_dir_sse), _mm_and_ps(cmp_a_sse, CIGAR_I_SSE) ); curr_run_sse=_mm_or_ps( _mm_andnot_ps(cmp_a_sse,curr_run_sse), _mm_and_ps(cmp_a_sse, _mm_add_ps(up_run_sse,one_sse) ) ); SSEFloat score_t; score_t.v=max_cell_sse; SSEFloat dir_t; dir_t.v=curr_dir_sse; SSEFloat run_t; run_t.v=curr_run_sse; AlignmentMatrixFast::MatrixElement left = *matrix->getElementCurr(x-1,y); for(int j=0;jgetElementCurrUnprotected(x+j,y); char & currentDirection = *matrix->getDirection(x+j, y); current.score = score_t.a[j]; current.direction = dir_t.a[j]; current.indelRun = run_t.a[j]; currentDirection = dir_t.a[j]; if(left_cell>=current.score) { if(left.indelRun > 0) { current.score=left_cell; currentDirection=CIGAR_D; current.direction=CIGAR_D; current.indelRun=left.indelRun+1; } else if ( left_cell>current.score || currentDirection==CIGAR_STOP || (currentDirection==CIGAR_I && ssat(up_run_sse,j)<=0) ) { current.score=left_cell; currentDirection=CIGAR_D; current.direction=CIGAR_D; current.indelRun=1; } } #ifdef DEBUG_SSE if(x+j curr_max) { curr_max = current.score; fwdResult.best_ref_index = x+j; fwdResult.best_read_index = y; fwdResult.max_score = curr_max; } left=current; } } for (int x = std::max(std::max(0,xOffset),xMax-SIMD_LEVEL-8); x < xMax; ++x) { //for (int x = std::max(0,xOffset); x < xMax; ++x) { AlignmentMatrixFast::Score diag_score = matrix->getElementUp(x - 1, y - 1)->score; AlignmentMatrixFast::MatrixElement const & up = *matrix->getElementUp(x,y - 1); AlignmentMatrixFast::MatrixElement const & left = *matrix->getElementCurr(x - 1, y); bool const eq = read_char_cache == refSeq[x]; AlignmentMatrixFast::Score const diag_cell = diag_score + ((eq) ? mat : mis); AlignmentMatrixFast::Score up_cell = 0; AlignmentMatrixFast::Score left_cell = 0; int ins_run = 0; int del_run = 0; if (up.direction == CIGAR_I) { ins_run = up.indelRun; if (up.score == 0) { up_cell = 0; } else { up_cell = up.score + std::min(gap_ext_min, gap_ext + ins_run * gap_decay); } } else { up_cell = up.score + gap_open_read; } if (left.direction == CIGAR_D) { del_run = left.indelRun; if (left.score == 0) { left_cell = 0; } else { left_cell = left.score + std::min(gap_ext_min, gap_ext + del_run * gap_decay); } } else { left_cell = left.score + gap_open_ref; } //find max AlignmentMatrixFast::Score max_cell = 0; max_cell = std::max(left_cell, max_cell); max_cell = std::max(diag_cell, max_cell); max_cell = std::max(up_cell, max_cell); AlignmentMatrixFast::MatrixElement * current = matrix->getElementEditCurr(x,y); char & currentDirection = *matrix->getDirection(x, y); if (del_run > 0 && max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = del_run + 1; } else if (ins_run > 0 && max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = ins_run + 1; } else if (max_cell == diag_cell) { current->score = max_cell; if (eq) { current->direction = CIGAR_EQ; currentDirection = CIGAR_EQ; } else { current->direction = CIGAR_X; currentDirection = CIGAR_X; } current->indelRun = 0; } else if (max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = 1; } else if (max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = 1; } else { current->score = 0; current->direction = CIGAR_STOP; currentDirection = CIGAR_STOP; current->indelRun = 0; } if (max_cell > curr_max) { curr_max = max_cell; fwdResult.best_ref_index = x; fwdResult.best_read_index = y; fwdResult.max_score = curr_max; } } } fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; if (matrix->getHeight() == 0) { fwdResult.best_read_index = fwdResult.best_ref_index = 0; } return curr_max; } /* AlignmentMatrixFast::Score ConvexAlignFast::FastUnrolledfwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResult, int readId) { AlignmentMatrixFast::Score curr_max = -1.0f; for (int y = 0; y < matrix->getHeight(); ++y) { matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); char const read_char_cache = qrySeq[y]; int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); for (int x = std::max(0, xOffset); x < xMax; ++x) { AlignmentMatrixFast::Score diag_score; AlignmentMatrixFast::MatrixElement const * p_up; AlignmentMatrixFast::MatrixElement const * p_left; AlignmentMatrixFast::MatrixElement * current; if(y==0 || (x-1 <= (matrix->getCorridorOffset(y-1)) ) || (x >= (matrix->getCorridorOffset(y-1)+matrix->getCorridorLength(y-1)) ) ) { diag_score = matrix->getElementUp(x - 1, y - 1)->score; p_up = matrix->getElementUp(x,y - 1); p_left = matrix->getElementCurr(x - 1, y); current = matrix->getElementEditCurr(x,y); } else { diag_score = matrix->getElementUpFast(x - 1, y - 1)->score; p_up = matrix->getElementUpFast(x,y - 1); p_left = matrix->getElementCurrFast(x - 1, y); current = matrix->getElementEditCurrFast(x,y); } AlignmentMatrixFast::MatrixElement const & up=*p_up; AlignmentMatrixFast::MatrixElement const & left=*p_left; char & currentDirection = *matrix->getDirectionCurrFast(x, y); bool const eq = read_char_cache == refSeq[x]; AlignmentMatrixFast::Score const diag_cell = diag_score + ((eq) ? mat : mis); AlignmentMatrixFast::Score up_cell = 0; AlignmentMatrixFast::Score left_cell = 0; int ins_run = 0; int del_run = 0; if (up.direction == CIGAR_I) { ins_run = up.indelRun; if (up.score == 0) { up_cell = 0; } else { up_cell = up.score + std::min(gap_ext_min, gap_ext + ins_run * gap_decay); } } else { up_cell = up.score + gap_open_read; } if (left.direction == CIGAR_D) { del_run = left.indelRun; if (left.score == 0) { left_cell = 0; } else { left_cell = left.score + std::min(gap_ext_min, gap_ext + del_run * gap_decay); } } else { left_cell = left.score + gap_open_ref; } //find max AlignmentMatrixFast::Score max_cell = 0; max_cell = std::max(left_cell, max_cell); max_cell = std::max(diag_cell, max_cell); max_cell = std::max(up_cell, max_cell); if (del_run > 0 && max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = del_run + 1; } else if (ins_run > 0 && max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = ins_run + 1; } else if (max_cell == diag_cell) { current->score = max_cell; if (eq) { current->direction = CIGAR_EQ; currentDirection = CIGAR_EQ; } else { current->direction = CIGAR_X; currentDirection = CIGAR_X; } current->indelRun = 0; } else if (max_cell == left_cell) { current->score = max_cell; current->direction = CIGAR_D; currentDirection = CIGAR_D; current->indelRun = 1; } else if (max_cell == up_cell) { current->score = max_cell; current->direction = CIGAR_I; currentDirection = CIGAR_I; current->indelRun = 1; } else { current->score = 0; current->direction = CIGAR_STOP; currentDirection = CIGAR_STOP; current->indelRun = 0; } if (max_cell > curr_max) { curr_max = max_cell; fwdResult.best_ref_index = x; fwdResult.best_read_index = y; fwdResult.max_score = curr_max; } } } fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; if (matrix->getHeight() == 0) { fwdResult.best_read_index = fwdResult.best_ref_index = 0; } return curr_max; } */ int ConvexAlignFast::BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData) { throw "Not implemented"; return 0; } } // g++ -I ../include/ ConvexAlignFast.cpp -o ConvexAlignFast && ./ConvexAlignFast //int main(int argc, char **argv) { // // IAlignment * aligner = new Convex::ConvexAlignFast(0); // //// char const * ref = //// "TCAAGATGCCATTGTCCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCTCCTGCC"; // char const * ref = // "AGATACATTGTTACTAACTAAGGCCCTACACCAGCAAAGATACATTGTTACTAAGTAAGGCCCTGCACCAACACAG"; ////// char const * qry = ////// "TCAAGATGCCAATTGTCCCCCGGCCCCCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC"; //// char const * qry = //// "CGGGGCCACGGCCACCGCTGCCCTGCC"; //// // char const * qry = // "CCAGAGCAAGTTCCCGGGGGGTGGCGCATAGATGCAGCGGTCTGGGTTCTGTGGCTGGGGGAGTTGGCTTGGGGTCCGTGGCTTGGGTCAGTCTTCAAGAGCCACCCTGGGTGGCACTCCAGGTTCTCTTGGTCTGGGGGGAATTACCCTGACCCCAGCGGTTTCACGGCCTCCTCCCCACTCAGCCTGGGGGAGAGTCCAGGGTCGGCCTGTCCCCCTCCCCCCACTCCTGTCACTATCAGTCCCCTGTGCTCAGCTTACTGGCAGGGTTCCTCCTGGCTGTCCCCTCCTGCCTCCAGCGCTCTTTCCTCAGGTGTCCACGAGCTCGTCCTCATCCCTTTCTGGTCCTGCTCAGATGCCGCCTGAGGCTCCCAAAACAGGGTCTCACTCTGTCACCCAGGGTGGAGTGCAGTGGTGCAATCCAGCTCACTGCATCCTTGACCTCCCAGGCTCAAGCGACCTCTGCCAGCGAGCTTGTTCAATTCCTGCACCAACACGATACATTGTTCTAACTAGGCCCTACACACAGCAAAGATACATTGTACTTAAGTAAGGGCCCTGCACCAACACAGATACATTGTTACTAAGTAGAGGCCCTGCACCAACACACGATACACTTGTTACTAACTAAGGCCCTGCACCAACACAGATACGTTAGTTACTAAGTAAGGCCCTGCACCAACACAGATACGTTGTTACTAAATAAGGCCCTGTACCAACACAGATACATTGTTACTAACTAAGGCCCTGCACCAACACAGATACTTGTTACTAAGTAAGGCCCTGCTACCAACACAGATACATTGTTACTAACTAAGCCCTGCACCAGCCACAGATACATTGTTACTAAGGGCCCTACACCAGCACAGATACATTGTTACTAAGGCCCTGCACCAACACAGATACGTTGTTACTAAGTGAGCCCTGCACCAACACAGATACATTGTTACTAAGTAAGGCCCTGCACCAGCACGAGATACATTGTTACTAAGGCCCTACACCAGCACAGGATAACATTGTCTACTAACTAAGGCCCTGCACGCAACAAAGATACGTATGTTACTAAGTAAGGCCCTGCACCAACACAGATACATTGTTACTAACTAAGGCCCCATGCACCAACACAGATAATTGTTACAAGGCCCTGCACCAACACAGATACATTGTTACTAACTAAGGCCCTGCACCAACACAGATACGTTGTTACTAAGTAAGGCCCTTGCACCAACACAATACATTGTTACTAAATAAGGCCCTGTACCAACATTCAGATACATTGTTACTAACTAAGGCCTGCACCAACACAGATACGTTGTTACTAAGTAAGGCCCTGTACCAACCAGGACTACATTGTTACTAACTAAGGCCCTGCACCACACAGATCGTTGTTTACTAAGTAAGGCCCTGGCACCAACACAGATACATTGTTACTAACTAAGGCCCTGCACAACACAATACATTGTTACTAAGGCCCTGCACCAACACAGATACATTGTTACTAAGTAAGGCCCTGCACCAACACGATACATTGTTACTACTAAGGCCCTGCACCAACACAAATACGTTCTTACTAAGTAAGGCCCTGCACCAACACAGATACATTGTACTAACTAAGGCCCTGTACAACACAGATACGTTGTTACTAAGTAAGGCCCTGCACCAACACAGACTACATTGTTACTAGGCCCTGCACCAAACACAGATACATTGTACTAAGTAAGGCCCTGCAGCCAACTACCAGATGACATTGTTACTAACTAAGGCCCTGCACCAGCACAGATATATTGTTACTAAAGGCCCTGCACCAACCTACAGATACATTGTTACTAACTAAGGCCTGCACCAACAAGATATGTTGTTACTAAGGCCCTGCACTCACACAGATACATTGTTACTAAGTAAGGGCCCTGCACCAACACAGATACATTGTTACTAACTAAAGGCCCCTGCACCAACACAGATAGTTGTTACTAAGTATGGCCCTCACCAACACAGATACATTGTTACTAAGGCCCTGCACCAACACAGATACATGTTACTAAGTAAGGCCCTTGCACCAACACAGATACATTTGTTACTAACTAAGGCCCTGCACCAACACAGATACATTGTACTAAGGCCCTACACCGAGAATGGATACATTGTCACATGGTTACCTAAAGCCTTGCACCAACATGGACACATCATTACTAAACTAAGGCCCTGCACCAACACAGATACATTGTTACTAAGGCCCTGCACCAACACAGATACATTGTTACTAAGATAAGAGCCCTGCACCAACACAGAGTACATTGTTACTAACAAGGCCCTCACCAGCACAGATATATTGTTACTAAGGCCCTGACTCAACACAGATAATTGTTACTAACTCAAGGCCCTGCACCAACCAGATATGTTGTTACTAAGGCCCTGCACCCCAACACAGATACATTGTTACTAAGGCCCGCACCAACACAAGATACATTGTTACTAAGTAAGGCCCTGCACCAACACAGATACGTTGTTACTAACTAAGGCCCTGCACCAACACAGATACGTTGTTACTCGAAGTAAGGCCCTGCACCAATCACAATACATTGTTACTAAGGCCCTGCACCAAACAGATACATTGTTACTAAGTAAGGCCCTGCACCATACACAGATGCATTTTAGCTAACTAAGGCCCTGTACCAACACAGATACATTGTTACTAGCTAAGGCCCTGCACCAACACAAGATACATTGTTACTAAGTAAGGCCCTGTACCAACACAGATATATTGTTACTAACTAAGGCCCTGCACCAACACAGATACGGTTGTTACTAAGTAAGGC"; // fprintf(stderr, "Ref: %s\n", ref); // fprintf(stderr, "Read: %s\n", qry); // // Align align; // // align.pBuffer1 = new char[strlen(ref) * 4]; // align.pBuffer2 = new char[strlen(ref) * 4]; // // int result = aligner->SingleAlign(0, 20, ref, qry, align, 0); // fprintf(stderr, "Alignment terminated with: %d\n", result); // fprintf(stderr, "Score: %f\n", align.Score); // fprintf(stderr, "Cigar: %s\n", align.pBuffer1); // fprintf(stderr, "MD: %s\n", align.pBuffer2); // // delete aligner; // aligner = 0; // // return 0; //} ngmlr-0.2.7+git20210816.a2a31fb/src/ConvexAlignFast.h000066400000000000000000000454431410636150300213640ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef CONVEXALIGN_FAST_H_ #define CONVEXALIGN_FAST_H_ #include "IAlignment.h" #include #include #include "Types.h" #include "AlignmentMatrixFast.h" namespace Convex { class ConvexAlignFast: public IAlignment { public: ConvexAlignFast(int const stdOutMode, float const match, float const mismatch, float const gapOpen, float const gapExtend, float const gapExtendMin, float const gapDecay); virtual ~ConvexAlignFast(); virtual int GetScoreBatchSize() const; virtual int GetAlignBatchSize() const; /** * Not implemented! */ virtual int BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData); /** * Not implemented! */ virtual int BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData); virtual int SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & result, void * extData); /** * Main function. Compute alignment based on "corridor layout" */ virtual int SingleAlign(int const mode, CorridorLine * corridor, int const corridorHeight, char const * const refSeq, char const * const qrySeq, Align & result, int const externalQStart, int const externalQEnd, void * extData); private: /** * Information that hase to be passed * from fwd to backward and compute cigar step */ struct FwdResults { int best_ref_index; int best_read_index; int max_score; int qend; int qstart; int ref_position; int alignment_offset; }; /** * Scoring function */ AlignmentMatrixFast::Score mat; AlignmentMatrixFast::Score mis; AlignmentMatrixFast::Score gap_open_read; AlignmentMatrixFast::Score gap_open_ref; AlignmentMatrixFast::Score gap_ext; AlignmentMatrixFast::Score gap_ext_min; AlignmentMatrixFast::Score gap_decay; AlignmentMatrixFast * matrix; /** Temporary storage for binary * representation of the CIGAR string * produced by backtracking step. */ int * binaryCigar; /** * Default Max length of binaryCigar */ int const defaultMaxBinaryCigarLength; /** * Max length of binaryCigar * If too small -> reallocate -> align -> set back to default */ int maxBinaryCigarLength; /** * Debug flag * TODO: convert to preprocessor define */ bool const pacbioDebug; /** * Prints debug information for * aligment corridor visualization * to stdout */ int const stdoutPrintAlignCorridor; /** * Debug */ int alignmentId; /** * Print CIGAR element to cigar string * Helper function used by convertCigar */ int printCigarElement(char const op, int const length, char * cigar, int & cigarOpCount, int cigarMaxLength); /** * Forward step of alignment * Fills directionMatrix */ AlignmentMatrixFast::Score fwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); AlignmentMatrixFast::Score FastfwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); AlignmentMatrixFast::Score FastUnrolledfwdFillMatrix(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); AlignmentMatrixFast::Score fwdFillMatrixSSESimple(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); /*AlignmentMatrixFast::Score FastUnrolledfwdFillMatrixMaster(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); AlignmentMatrixFast::Score FastUnrolledfwdFillMatrixLine(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId, AlignmentMatrixFast::Score diag_score, AlignmentMatrixFast::MatrixElement const & up, AlignmentMatrixFast::MatrixElement const & left, AlignmentMatrixFast::MatrixElement * current, char & currentDirection, AlignmentMatrixFast::Score & curr_max, int x, int y);*/ /*#define FILLMATRIX(DIAG_SCORE,UP_REF,LEFT_REF,CURRENT,CURRENT_DIR) {\ diag_score=DIAG_SCORE;\ AlignmentMatrixFast::MatrixElement const & up = UP_REF;\ AlignmentMatrixFast::MatrixElement const & left = LEFT_REF;\ AlignmentMatrixFast::MatrixElement * current=CURRENT;\ char & currentDirection=CURRENT_DIR;\ bool const eq = read_char_cache == refSeq[x]; \ diag_cell = diag_score + (eq ? mat : mis);\ \ up_cell = 0;\ left_cell = 0;\ \ ins_run = 0;\ del_run = 0;\ \ if (up.direction == CIGAR_I) {\ ins_run = up.indelRun;\ if (up.score == 0) {\ up_cell = 0;\ } else {\ up_cell = up.score\ + std::min(gap_ext_min,\ gap_ext + ins_run * gap_decay);\ }\ } else {\ up_cell = up.score + gap_open_read;\ }\ \ if (left.direction == CIGAR_D) {\ del_run = left.indelRun;\ if (left.score == 0) {\ left_cell = 0;\ } else {\ left_cell = left.score\ + std::min(gap_ext_min,\ gap_ext + del_run * gap_decay);\ }\ } else {\ left_cell = left.score + gap_open_ref;\ }\ \ AlignmentMatrixFast::Score max_cell = 0;\ max_cell = std::max(left_cell, max_cell);\ max_cell = std::max(diag_cell, max_cell);\ max_cell = std::max(up_cell, max_cell);\ \ if (del_run > 0 && max_cell == left_cell) {\ current->score = max_cell;\ current->direction = CIGAR_D;\ currentDirection = CIGAR_D;\ current->indelRun = del_run + 1;\ } else if (ins_run > 0 && max_cell == up_cell) {\ current->score = max_cell;\ current->direction = CIGAR_I;\ currentDirection = CIGAR_I;\ current->indelRun = ins_run + 1;\ } else if (max_cell == diag_cell) {\ current->score = max_cell;\ if (eq) {\ current->direction = CIGAR_EQ;\ currentDirection = CIGAR_EQ;\ } else {\ current->direction = CIGAR_X;\ currentDirection = CIGAR_X;\ }\ current->indelRun = 0;\ } else if (max_cell == left_cell) {\ current->score = max_cell;\ current->direction = CIGAR_D;\ currentDirection = CIGAR_D;\ current->indelRun = 1;\ } else if (max_cell == up_cell) {\ current->score = max_cell;\ current->direction = CIGAR_I;\ currentDirection = CIGAR_I;\ current->indelRun = 1;\ } else {\ current->score = 0;\ current->direction = CIGAR_STOP;\ currentDirection = CIGAR_STOP;\ current->indelRun = 0;\ }\ \ if (max_cell > curr_max) {\ curr_max = max_cell;\ fwdResult.best_ref_index = x;\ fwdResult.best_read_index = y;\ fwdResult.max_score = curr_max;\ }\ } inline AlignmentMatrixFast::Score FastUnrolledfwdFillMatrixMaster(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResult, int readId) { AlignmentMatrixFast::Score curr_max = -1.0f; int const matrix_height=matrix->getHeight(); AlignmentMatrixFast::Score diag_score; AlignmentMatrixFast::Score diag_cell; AlignmentMatrixFast::Score left_cell; AlignmentMatrixFast::Score up_cell; int ins_run; int del_run; { int y=0; matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); char const read_char_cache = qrySeq[y]; for (int x = std::max(0, xOffset); x < xMax; ++x) { FILLMATRIX(matrix->empty.score,matrix->empty,*matrix->getElementCurr(x - 1, y),matrix->getElementEditCurrFast(x,y),*matrix->getDirectionCurrFast(x, y)); } } for (int y = 1; y < matrix_height; ++y) { matrix->prepareLine(y); int xOffset = matrix->getCorridorOffset(y); int xMin=std::max(0, xOffset); int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); int xFastMin=std::max(0,matrix->getCorridorOffset(y-1)+1); int xFastMax=std::min(matrix->getCorridorOffset(y-1)+matrix->getCorridorLength(y-1),matrix->getWidth()); char const read_char_cache = qrySeq[y]; if(xMin>xFastMin || xFastMax>xMax) { for(int x=xMin; xgetElementUp(x - 1, y - 1)->score,*matrix->getElementUp(x,y - 1),*matrix->getElementCurr(x - 1, y),matrix->getElementEditCurrFast(x,y),*matrix->getDirectionCurrFast(x, y)); } } else { for(int x=xMin; x<=xFastMin; x++) { FILLMATRIX(matrix->getElementUp(x - 1, y - 1)->score,*matrix->getElementUp(x,y - 1),*matrix->getElementCurr(x - 1, y),matrix->getElementEditCurrFast(x,y),*matrix->getDirectionCurrFast(x, y)); } for(int x=xFastMin+1; xgetElementUpFast(x - 1, y - 1)->score,*matrix->getElementUpFast(x,y - 1),*matrix->getElementCurrFast(x - 1, y),matrix->getElementEditCurrFast(x,y),*matrix->getDirectionCurrFast(x, y)); } for(int x=xFastMax; xgetElementUp(x - 1, y - 1)->score,*matrix->getElementUp(x,y - 1),*matrix->getElementCurr(x - 1, y),matrix->getElementEditCurrFast(x,y),*matrix->getDirectionCurrFast(x, y)); } } } fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; if (matrix->getHeight() == 0) { fwdResult.best_read_index = fwdResult.best_ref_index = 0; } return curr_max; } // inline AlignmentMatrixFast::Score FastUnrolledfwdFillMatrixMaster(char const * const refSeq, // char const * const qrySeq, FwdResults & fwdResult, int readId) { // AlignmentMatrixFast::Score curr_max = -1.0f; // int matrix_height=matrix->getHeight(); // { // int y=0; // matrix->prepareLine(y); // int xOffset = matrix->getCorridorOffset(y); // int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); // for (int x = std::max(0, xOffset); x < xMax; ++x) { // ConvexAlignFast::FastUnrolledfwdFillMatrixLine(refSeq,qrySeq,fwdResult,readId, // matrix->empty.score, // matrix->empty, // *matrix->getElementCurr(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y, // qrySeq[0]); // } // } // for (int y = 1; y < matrix_height; ++y) { // matrix->prepareLine(y); // int xOffset = matrix->getCorridorOffset(y); // int xMin=std::max(0, xOffset); // int xMax=std::min(xOffset + matrix->getCorridorLength(y),matrix->getWidth()); // int xFastMin=std::max(0,matrix->getCorridorOffset(y-1)+1); // int xFastMax=std::min(matrix->getCorridorOffset(y-1)+matrix->getCorridorLength(y-1),matrix->getWidth()); // char const read_char_cache = qrySeq[y]; // if(xMin>xFastMin || xFastMax>xMax) // { // for(int x=xMin; xgetElementUp(x - 1, y - 1)->score, // *matrix->getElementUp(x,y - 1), // *matrix->getElementCurr(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y, // read_char_cache); // } // } else { // for(int x=xMin; x<=xFastMin; x++) // { // ConvexAlignFast::FastUnrolledfwdFillMatrixLine(refSeq,qrySeq,fwdResult,readId, // matrix->getElementUp(x - 1, y - 1)->score, // *matrix->getElementUp(x,y - 1), // *matrix->getElementCurr(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y, // read_char_cache); // } // for(int x=xFastMin+1; xgetElementUpFast(x - 1, y - 1)->score, // *matrix->getElementUpFast(x,y - 1), // *matrix->getElementCurrFast(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y, // read_char_cache); // } // for(int x=xFastMax; xgetElementUp(x - 1, y - 1)->score, // *matrix->getElementUp(x,y - 1), // *matrix->getElementCurr(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y, // read_char_cache); // } // } // for (int x = std::max(0, xOffset); x < xMax; ++x) { // if(y==0 || // (x-1 <= (matrix->getCorridorOffset(y-1)) ) || // (x >= (matrix->getCorridorOffset(y-1)+matrix->getCorridorLength(y-1)) ) ) { // ConvexAlignFast::FastUnrolledfwdFillMatrixLine(refSeq,qrySeq,fwdResult,readId, // matrix->getElementUp(x - 1, y - 1)->score, // *matrix->getElementUp(x,y - 1), // *matrix->getElementCurr(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y); // } else { // ConvexAlignFast::FastUnrolledfwdFillMatrixLine(refSeq,qrySeq,fwdResult,readId, // matrix->getElementUpFast(x - 1, y - 1)->score, // *matrix->getElementUpFast(x,y - 1), // *matrix->getElementCurrFast(x - 1, y), // matrix->getElementEditCurrFast(x,y), // *matrix->getDirectionCurrFast(x, y), // curr_max, // x, // y); // } // } // } // fwdResult.qend = (matrix->getHeight() - fwdResult.best_read_index) - 1; // if (matrix->getHeight() == 0) { // fwdResult.best_read_index = fwdResult.best_ref_index = 0; // } // return curr_max; // } // inline void FastUnrolledfwdFillMatrixLine(char const * const refSeq, // char const * const qrySeq, FwdResults & fwdResult, int readId, // AlignmentMatrixFast::Score diag_score, // AlignmentMatrixFast::MatrixElement const & up, // AlignmentMatrixFast::MatrixElement const & left, // AlignmentMatrixFast::MatrixElement * current, // char & currentDirection, // AlignmentMatrixFast::Score & curr_max, // int x, // int y, // char read_char_cache) { // bool const eq = read_char_cache == refSeq[x]; // AlignmentMatrixFast::Score const diag_cell = diag_score + (eq ? mat : mis); // AlignmentMatrixFast::Score up_cell = 0; // AlignmentMatrixFast::Score left_cell = 0; // int ins_run = 0; // int del_run = 0; // if (up.direction == CIGAR_I) { // ins_run = up.indelRun; // if (up.score == 0) { // up_cell = 0; // } else { // up_cell = up.score // + std::min(gap_ext_min, // gap_ext + ins_run * gap_decay); // } // } else { // up_cell = up.score + gap_open_read; // } // if (left.direction == CIGAR_D) { // del_run = left.indelRun; // if (left.score == 0) { // left_cell = 0; // } else { // left_cell = left.score // + std::min(gap_ext_min, // gap_ext + del_run * gap_decay); // } // } else { // left_cell = left.score + gap_open_ref; // } // //find max // AlignmentMatrixFast::Score max_cell = 0; // max_cell = std::max(left_cell, max_cell); // max_cell = std::max(diag_cell, max_cell); // max_cell = std::max(up_cell, max_cell); // int a=del_run > 0 && max_cell == left_cell; // int b=(!a) && ins_run > 0 && max_cell == up_cell; // int c=(!a && !b) && max_cell == diag_cell; // int d=(!a && !b && !c) && max_cell == left_cell; // int e=(!a && !b && !c && !d) && max_cell == up_cell; // int f=!(a*b*c*d*e); // current->score = a*max_cell; // current->direction = a*CIGAR_D; // currentDirection = a*CIGAR_D; // current->indelRun = a*(del_run + 1); // current->score = (!b)*current->score + b*max_cell; // current->direction = (!b)*current->direction + b*CIGAR_I; // currentDirection = (!b)*currentDirection + b*CIGAR_I; // current->indelRun = (!b)*current->indelRun + b*(ins_run + 1); // current->score = (!c)*current->score + c*max_cell; // current->direction = (!c)*current->direction + (c*eq*CIGAR_EQ) + (c*(!eq)*CIGAR_X); // currentDirection = (!c)*currentDirection + (c*eq*CIGAR_EQ) + (c*(!eq)*CIGAR_X); // current->indelRun = (!c)*current->indelRun + c*0; // current->score = (!d)*current->score + d*max_cell; // current->direction = (!d)*current->direction + d*CIGAR_D; // currentDirection = (!d)*currentDirection + d*CIGAR_D; // current->indelRun = (!d)*current->indelRun + d*1; // current->score = (!e)*current->score + e*max_cell; // current->direction = (!e)*current->direction + e*CIGAR_I; // currentDirection = (!e)*currentDirection + e*CIGAR_I; // current->indelRun = (!e)*current->indelRun + e*1; // current->score = (!f)*current->score + 0; // current->direction = (!f)*current->direction + f*CIGAR_STOP; // currentDirection = (!f)*currentDirection + f*CIGAR_STOP; // current->indelRun = (!f)*current->indelRun + 0;*/ // if (del_run > 0 && max_cell == left_cell) { // current->score = max_cell; // current->direction = CIGAR_D; // currentDirection = CIGAR_D; // current->indelRun = del_run + 1; // } else if (ins_run > 0 && max_cell == up_cell) { // current->score = max_cell; // current->direction = CIGAR_I; // currentDirection = CIGAR_I; // current->indelRun = ins_run + 1; // } else if (max_cell == diag_cell) { // current->score = max_cell; // if (eq) { // current->direction = CIGAR_EQ; // currentDirection = CIGAR_EQ; // } else { // current->direction = CIGAR_X; // currentDirection = CIGAR_X; // } // current->indelRun = 0; // } else if (max_cell == left_cell) { // current->score = max_cell; // current->direction = CIGAR_D; // currentDirection = CIGAR_D; // current->indelRun = 1; // } else if (max_cell == up_cell) { // current->score = max_cell; // current->direction = CIGAR_I; // currentDirection = CIGAR_I; // current->indelRun = 1; // } else { // current->score = 0; // current->direction = CIGAR_STOP; // currentDirection = CIGAR_STOP; // current->indelRun = 0; // } // if (max_cell > curr_max) { // curr_max = max_cell; // fwdResult.best_ref_index = x; // fwdResult.best_read_index = y; // fwdResult.max_score = curr_max; // } // }*/ /** * Follows direction matrix (backtracking) * Creates reversed binary representation of the cigar string */ bool revBacktrack(char const * const refSeq, char const * const qrySeq, FwdResults & fwdResults, int readId); /** * Converts CIGAR to text and computes MD flag + stats */ int convertCigar(char const * const refSeq, int const refSeqLength, Align & result, FwdResults & fwdResults, int const externalQStart, int const externalQEnd); int NumberOfSetBits(uint32_t i); void addPosition(Align & result, int & nmIndex, int posInRef, int posInRead, int Yi); void checkMdBufferLength(int md_offset, Align& result, int const minDiff = 0); }; #endif /* CONVEXALIGN_H_ */ } // namespace Convex ngmlr-0.2.7+git20210816.a2a31fb/src/FastxParser.h000066400000000000000000000014041410636150300205600ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef FASTXPARSER_H_ #define FASTXPARSER_H_ #include "IParser.h" #include class FastXParser: public IParser { private: gzFile fp; kseq_t * tmp; public: FastXParser(int const p_qryMaxLen) : IParser(p_qryMaxLen) { fp = 0; tmp = 0; } virtual ~FastXParser() { if(tmp != 0) { kseq_destroy(tmp); tmp = 0; } gzclose(fp); } virtual void init(char const * fileName) { fp = gzopen(fileName, "r"); tmp = kseq_init(fp); } virtual int doParseRead(MappedRead * read) { int l = kseq_read(tmp); return copyToRead(read, tmp, l); } // virtual int doParseRead(SAMRecord * read) { // int l = kseq_read(tmp); // return copyToRead(read, tmp, l); // } }; #endif /* FASTXPARSER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/FileWriter.h000066400000000000000000000011671410636150300204000ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef FILEWRITER_H_ #define FILEWRITER_H_ #include "NGMThreads.h" class FileWriter { public: NGMMutex m_OutputMutex; FileWriter() { NGMInitMutex(&m_OutputMutex); } virtual ~FileWriter() { } void Flush(int & bufferPosition, int const BUFFER_LIMIT, char * writeBuffer, bool last = false) { NGMLock(&m_OutputMutex); doFlush(bufferPosition, BUFFER_LIMIT, writeBuffer, last); NGMUnlock(&m_OutputMutex); } protected: virtual void doFlush(int & bufferPosition, int const BUFFER_LIMIT, char * writeBuffer, bool last = false) = 0; }; #endif /* FILEWRITER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/GZFileWriter.h000066400000000000000000000022011410636150300206270ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef GZFILEWRITER_H_ #define GZFILEWRITER_H_ #include #include #include #include #include "NGMThreads.h" #include "ILog.h" #include "zlib.h" class GZFileWriter : public FileWriter { public: gzFile m_Output; GZFileWriter(char const * const filename) { std::string strFilename = std::string(filename); if(!hasSuffix(strFilename, ".gz")) { strFilename += ".gz"; } if (!(m_Output = gzopen(strFilename.c_str(), "wb"))) { Log.Error("Unable to open output file %s", filename); } } ~GZFileWriter() { gzclose(m_Output); } void doFlush(int & bufferPosition, int const BUFFER_LIMIT, char * writeBuffer, bool last = false) { if (bufferPosition > BUFFER_LIMIT || last) { if(gzwrite(m_Output, writeBuffer, bufferPosition) < 0) { Log.Error("Writing"); } bufferPosition = 0; } } private: bool hasSuffix(const std::string &str, const std::string &suffix) { return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } }; #endif /* GZFILEWRITER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/GenericReadWriter.h000066400000000000000000000053701410636150300216710ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __GENERICREADWRITER_H__ #define __GENERICREADWRITER_H__ #include #include #include #include "ILog.h" #include "IConfig.h" #include "NGM.h" #include "MappedRead.h" #include "FileWriter.h" #undef module_name #define module_name "OUTPUT" class GenericReadWriter { protected: virtual void DoWriteProlog() = 0; virtual void DoWriteRead(MappedRead const * const read, int const scoreID) = 0; virtual void DoWritePair(MappedRead const * const read1, int const scoreId1, MappedRead const * const read2, int const scoreId2) = 0; virtual void DoWriteUnmappedRead(MappedRead const * const read, int flags = 0x4) = 0; virtual void DoWriteEpilog() = 0; float identity; bool writeUnmapped; // See you soon! Fixing it for good would have been a // better idea then changing it from 3.2 mb to 100 mb static int const BUFFER_SIZE = 100000000; static int const BUFFER_LIMIT = 10000000; char * writeBuffer; int bufferPosition; int Print(const char *format, ...) { int done; va_list arg; va_start(arg, format); done = vsprintf(writeBuffer + bufferPosition, format, arg); bufferPosition += done; if(bufferPosition >= BUFFER_SIZE) { Log.Error("Size of write buffer exceeded"); } va_end(arg); return done; } public: GenericReadWriter() { writeBuffer = new char[BUFFER_SIZE]; bufferPosition = 0; identity = Config.getMinIdentity(); writeUnmapped = Config.getWriteUnampped(); } virtual ~GenericReadWriter() { if (writeBuffer != 0) { delete[] writeBuffer; writeBuffer = 0; } } void WriteProlog() { DoWriteProlog(); } void WriteRead(MappedRead const * const read, bool mapped = true) { bool mappedOnce = false; for (int i = 0; i < read->Calculated && mapped; ++i) { bool mappedCurrent = !read->Alignments[i].skip; if(Config.getBamCigarFix() && mappedCurrent) { int const maxInBAM = 0x10000; if (read->Alignments[i].cigarOpCount >= maxInBAM) { Log.Message("Skipping alignment %d for %s: number of CIGAR operations %d > 64k.", i, read->name, read->Alignments[i].cigarOpCount); } } mappedOnce = mappedOnce || mappedCurrent; if(mappedCurrent) { DoWriteRead(read, i); } } if (mappedOnce) { Log.Debug(4, "READ_%d\tOUTPUT\tRead was mapped", read->ReadId); NGM.AddMappedRead(read->ReadId); } else { if(read->HasFlag(NGMNames::Empty)) { Log.Debug(4, "READ_%d\tOUTPUT\tRead empty (discard read)", read->ReadId); } else { Log.Debug(4, "READ_%d\tOUTPUT\tRead unmapped", read->ReadId); DoWriteUnmappedRead(read); } } } void WriteEpilog() { DoWriteEpilog(); } } ; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/IAlignment.h000066400000000000000000000132011410636150300203430ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __IALIGNMENT_H__ #define __IALIGNMENT_H__ #include // Signed position on the reference // For cLIS reverse positions are represented as negative // numbers (TODO: check whether this in neccessary!) typedef long long loc; struct PositionNM { PositionNM() : refPosition(0), readPosition(0), nm(0) { } int refPosition; int readPosition; int nm; }; struct CorridorLine { int offset; int length; unsigned long offsetInMatrix; }; // Non overlapping part of the reads that are mapped to the reference // using NextGenMap short-read mapping code (only candidate search and score computation) struct Anchor { // Position of anchor on the read int onRead; // Position of anchor on the reference loc onRef; // Alignment score of anchor float score; // Anchor was mapped to the reverse strand bool isReverse; // Used for visualization only! int type; //0: normal, 1: repetitive, 2: nothing found, 3: socre too low, 4: no coordinates // Unique anchors can be used as single intervals, non-unique anchors won't form // intervals alone during cLIS bool isUnique; }; struct Interval { public: Anchor * anchors; int anchorLength; int onReadStart; int onReadStop; loc onRefStart; loc onRefStop; double m; double b; double r; float score; short id; bool isReverse; bool isProcessed; bool isAssigned; Interval() { anchors = 0; anchorLength = 0; onReadStart = 0; onReadStop = 0; onRefStart = 0; onRefStop = 0; m = 0.0; b = 0.0; r = 0.0; score = 0.0f; id = 0; isReverse = false; isProcessed = false; isAssigned = false; } int lengthOnRead() const { return onReadStop - onReadStart; } loc lengthOnRef() const { return llabs(onRefStop - onRefStart); } virtual ~Interval() { if (anchors != 0) { delete[] anchors; anchors = 0; anchorLength = 0; } } private: Interval(const Interval & src); }; struct Align { public: // static volatile int sInstanceCount; Align() : pBuffer1(0), pBuffer2(0), mappedInterval(0), nmPerPosition(0), nmPerPostionLength(0), alignmentLength( 0), PositionOffset(0), QStart(0), QEnd(0), Score(0.0f), Identity( 0.0f), NM(0), MQ(0), cigarOpCount(0), maxBufferLength(20000), maxMdBufferLength(20000), skip(false), primary(false), svType(0) { } virtual ~Align() { } char * pBuffer1; // = pCigar = pRef char * pBuffer2; // = pMD = pQry PositionNM * nmPerPosition; // void * ExtendedData; Interval * mappedInterval; PositionNM firstPosition; PositionNM lastPosition; int nmPerPostionLength; int alignmentLength; int PositionOffset; // Position in Ref, an der das Alignment beginnt int QStart; // Anzahl Basen, die beim Qry am Anfang abgeschnitten wurden int QEnd; // Anzahl Basen, die beim Qry am Ende abgeschnitten wurden float Score; float Identity; int NM; int MQ; int cigarOpCount; int maxBufferLength; int maxMdBufferLength; bool skip; bool primary; /** * Bitflag: * 0x1 - Start clipping because of N * 0x2 - End clipping because of N */ int svType; void setBitFlag(int const i) { svType = svType | i; } int getAlignedReadBp(int const readLength) { return readLength - QStart - QEnd; } void clearBuffer() { if (pBuffer1 != 0) { delete[] pBuffer1; pBuffer1 = 0; } if (pBuffer2 != 0) { delete[] pBuffer2; pBuffer2 = 0; } if (mappedInterval != 0) { delete[] mappedInterval; mappedInterval = 0; } } void clearNmPerPosition() { if (nmPerPosition != 0) { delete[] nmPerPosition; nmPerPosition = 0; nmPerPostionLength = 0; } } //private: // Align(const Align & src); }; static int const cCookie = 0x10201130; /* Anmerkung zum Parameter mode: int AlignmentType = mode & 0xFF; // 0..Smith-Waterman, 1..Needleman-Wunsch int ReportType = (mode >> 8) & 0xFF; // 0..Plain alignment (Ref+Qry), 1..SAM (Cigar+MD) bool BSMappingActive = mode & 0x10000; Anmerkung BS-Mapping: extData zeigt bei BSMappingActive == true auf ein Flag-Array (char*) der L�nge batchSize, wobei bei 0 die TC-Match-Funktion, bei 1 die AG-Match-Funktion verwendet werden soll: if (extData[i] == 0) -> TC-Matching f�r ref/qry-Paar i if (extData[i] == 1) -> AG-Matching - "" - */ class IAlignment { public: virtual int GetScoreBatchSize() const = 0; virtual int GetAlignBatchSize() const = 0; virtual int BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData) = 0; virtual int SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & result, void * extData) { return 0; } virtual int SingleAlign(int const mode, CorridorLine * corridor, int const corridorHeight, char const * const refSeq, char const * const qrySeq, Align & result, int const externalQStart, int const externalQEnd, void * extData) { return 0; } virtual int SingleScore(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, float & result, void * extData) { return 0; } virtual int BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData) = 0; virtual ~IAlignment() { } }; typedef IAlignment * (*pfCreateAlignment)(int const gpu_id); typedef void (*pfDeleteAlignment)(IAlignment*); #endif ngmlr-0.2.7+git20210816.a2a31fb/src/IConfig.h000066400000000000000000000134141410636150300176400ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __ICONF_H__ #define __ICONF_H__ #include "Types.h" #include #include class IConfig { protected: /** ****************** * Default values * ****************** */ float minIdentity = 0.65f; float minResidues = 0.25f; float sensitivity = 0.8f; int binSize = 4; int csSearchTableLength = 0; int kmerLength = 13; int kmerSkip = 2; int logLevel = 0; //16383, 255 int minInversionLength = 70; //Advanced int minKmerHits = 0; int maxCMRs = INT_MAX; int maxSegmentNumberPerKb = 1; int maxCLISRuns = 100; int readPartCorridor = 40; int readPartLength = 256; int stdoutMode = 0; int subreadaligner = 2; int threads = 1; int maxReadNameLength = 500; ulong maxMatrixSizeMB = 10000; float invScoreRatio = 1.0f; float scoreMatch = 2.0f; float scoreMismatch = -5.0f; float scoreGapOpen = -5.0f; float scoreGapExtendMax = -5.0f; float scoreGapExtendMin = -1.0f; float scoreGapDecay = 0.15f; bool bam = false; bool color = false; bool hardClip = false; bool log = false; bool lowQualitySplit = false; bool printAllAlignments = false; bool progress = true; bool skipSave = false; bool smallInversionDetection = true; bool updateCheck = false; bool verbose = false; bool writeUnmapped = true; bool nosse = false; //Debug bool bamCigarFix = false; bool skipAlign = false; char * queryFile = 0; char * referenceFile = 0; char * outputFile = 0; char * rgId = 0; char * rgSm = 0; char * rgLb = 0; char * rgPl = 0; char * rgDs = 0; char * rgDt = 0; char * rgPu = 0; char * rgPi = 0; char * rgPg = 0; char * rgCn = 0; char * rgFo = 0; char * rgKs = 0; /* * If specified, only reads in the regions specified * by the BED file are read from the input BAM file * (requires BAM input) */ char * bedFile = 0; char * fullCommandLineCall = 0; char * vcfFile = 0; public: char const * const getQueryFile() const { return queryFile; } char const * const getReferenceFile() const { return referenceFile; } char const * const getBedFile() const { return bedFile; } char const * const getOutputFile() const { return outputFile; } char const * const getRgId() const { return rgId; } char const * const getRgSm() const { return rgSm; } char const * const getRgLb() const { return rgLb; } char const * const getRgPl() const { return rgPl; } char const * const getRgDs() const { return rgDs; } char const * const getRgDt() const { return rgDt; } char const * const getRgPu() const { return rgPu; } char const * const getRgPi() const { return rgPi; } char const * const getRgPg() const { return rgPg; } char const * const getRgCn() const { return rgCn; } char const * const getRgFo() const { return rgFo; } char const * const getRgKs() const { return rgKs; } char const * const getFullCommandLineCall() const { return fullCommandLineCall; } char const * const getVcfFile() const { return vcfFile; } float getMinIdentity() const { return minIdentity; } float getMinResidues() const { return minResidues; } float getSensitivity() const { return sensitivity; } int getBinSize() const { return binSize; } int getCsSearchTableLength() const { return csSearchTableLength; } int getKmerLength() const { return kmerLength; } int getKmerSkip() const { return kmerSkip; } int getLogLevel() const { return logLevel; } int getMinInversionLength() const { return minInversionLength; } int getMinKmerHits() const { return minKmerHits; } int getMaxSegmentNumberPerKb(int const readLength) const { //int maxSplits = int((read->length / 1000.0) * Config.getMaxSegmentNumberPerKb() + 0.5); int maxSegments = (int)((readLength / 1000.0) * maxSegmentNumberPerKb + 0.5); return maxSegments < 1 ? 1 : maxSegments; } int getMaxCLISRuns() const { return maxCLISRuns; } int getMaxCMRs() const { return maxCMRs; } int getReadPartCorridor() const { return readPartCorridor; } int getReadPartLength() const { return readPartLength; } float getInvScoreRatio() const { return invScoreRatio; } float getScoreMatch() const { return scoreMatch; } float getScoreMismatch() const { return scoreMismatch; } float getScoreGapOpen() const { return scoreGapOpen; } float getScoreExtendMax() const { return scoreGapExtendMax; } float getScoreExtendMin() const { return scoreGapExtendMin; } float getScoreGapDecay() const { return scoreGapDecay; } int getStdoutMode() const { return stdoutMode; } int getSubreadAligner() const { return subreadaligner; } int getThreads() const { return threads; } int getMaxReadNameLength() const { return maxReadNameLength; } ulong getMaxMatrixSizeMB() const { return maxMatrixSizeMB; } bool getNoSSE() const { return nosse; } bool getBamCigarFix() const { return bamCigarFix; } bool getSkipalign() const { return skipAlign; } bool getBAM() const { return bam; } bool getColor() const { return color; } bool getHardClip() const { return hardClip; } bool getLog() const { return log; } bool getLowQualitySplit() const { return lowQualitySplit; } bool getSmallInversionDetection() const { return smallInversionDetection; } bool getPrtintAll() const { return printAllAlignments; } bool getProgress() const { return progress; } bool getSkipSave() const { return skipSave; } bool getUpdateCheck() const { return updateCheck; } bool getVerbose() const { return verbose; } bool getWriteUnampped() const { return writeUnmapped; } bool isStdIn() const { return strcmp(getQueryFile(), "/dev/stdin") == 0; } IConfig() { } virtual ~IConfig() { } }; #endif //__CONF_H__ typedef void (*pfSetConfig)(IConfig const *); extern IConfig* _config; #define Config (*_config) ngmlr-0.2.7+git20210816.a2a31fb/src/ILog.h000066400000000000000000000030051410636150300171470ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __ILOG_H__ #define __ILOG_H__ class ILog { public: virtual void _Message(int const lvl, char const * const title, char const * const msg, ...) const = 0; virtual void _Debug (int const lvl, char const * const title, char const * const msg, ...) const = 0; virtual ~ILog() {}; void * null; }; enum { LOG_INFO = 1, LOG_INPUT = 2, LOG_OUTPUT = 4, LOG_CS = 8, LOG_SCORES = 16, LOG_ALIGN = 32, LOG_RESULTS_SCORES = 64, LOG_RESULTS_ALIGN = 128, LOG_BUFFER_SCORES = 256, LOG_BUFFER_ALIGN = 512, LOG_SCORE_DETAILS = 1024, LOG_ALIGN_DETAILS = 2048, LOG_CS_DETAILS = 4096, LOG_RESULTS_CS = 8192, LOG_INPUT_DETAILS = 16384, LOG_OUTPUT_DETAILS = 32768 }; typedef void (*pfSetLog)(ILog const *); extern ILog const * _log; #define Log (*_log) #undef module_name #define module_name 0 #define Message(s, ...) _Message(0, module_name, s , ##__VA_ARGS__) #define Warning(s, ...) _Message(1, module_name, s , ##__VA_ARGS__) #define Error(s, ...) _Message(2, module_name, s , ##__VA_ARGS__) #define Green(s, ...) _Message(3, module_name, s , ##__VA_ARGS__) #define Progress(s, ...) _Message(99, "Progress", s , ##__VA_ARGS__) //#define VERBOSE #ifdef VERBOSE #define Verbose(s, ...) _Message(0, module_name, s, ##__VA_ARGS__) #else #define Verbose(s, ...) null #endif #ifdef DEBUGLOG #define Debug(lvl, s, ...) _Debug(lvl, module_name, s, ##__VA_ARGS__) #else #define Debug(lvl, s, ...) null #endif #endif ngmlr-0.2.7+git20210816.a2a31fb/src/IParser.h000066400000000000000000000071031410636150300176650ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef PARSER_H_ #define PARSER_H_ #include "MappedRead.h" #include #include #include #include "kseq.h" KSEQ_INIT(gzFile, gzread) class IParser { public: static size_t const MAX_READNAME_LENGTH = 250; IParser(int const qrymaxlen) : qryMaxLen(qrymaxlen) { } virtual ~IParser() { } virtual void init(char const * fileName) = 0; int parseRead(MappedRead * pRead) { assert(pRead != 0); return doParseRead(pRead); } // int parseSAMRecord(SAMRecord * pRead) { // assert(pRead != 0); // return doParseRead(pRead); // } protected: int const qryMaxLen; virtual int doParseRead(MappedRead * pRead) = 0; // virtual int doParseRead(SAMRecord * pRead) = 0; int copyToRead(MappedRead * read, kseq_t * kseq, int const l) { int nameLength = 0; if (l >= 0) { if (kseq->seq.l == kseq->qual.l || kseq->qual.l == 0) { nameLength = std::min(MAX_READNAME_LENGTH - 1, kseq->name.l); memcpy(read->name, kseq->name.s, nameLength); read->name[nameLength] = '\0'; //Sequence if (kseq->seq.l != 0) { // read->length = std::min(kseq->seq.l, // (size_t) qryMaxLen - 1); read->length = kseq->seq.l; read->Seq = new char[std::max(qryMaxLen, read->length + 1)]; int nCount = 0; for (int i = 0; i < read->length; ++i) { char c = toupper(kseq->seq.s[i]); if (c == 'A' || c == 'T' || c == 'C' || c == 'G') { read->Seq[i] = c; } else { read->Seq[i] = 'N'; nCount += 1; } } read->Seq[read->length] = '\0'; } else { fprintf(stderr, "Empty read found!\n"); read->length = qryMaxLen; read->Seq = new char[read->length]; memset(read->Seq, 'N', read->length - 1); read->Seq[read->length] = '\0'; read->SetFlag(NGMNames::Empty); } //Quality if (kseq->qual.l > 0) { read->qlty = new char[read->length + 1]; memcpy(read->qlty, kseq->qual.s, read->length); read->qlty[read->length] = '\0'; } else { read->qlty = new char[2]; read->qlty[0] = '*'; read->qlty[1] = '\0'; } } else { throw "Error while parsing. Read length not equal to length of quality values!"; //Log.Error("Discarding read %s. Length of read not equal length of quality values.", parser->read->name.s); } } else { switch (l) { case -1: //End of file break; case -2: //Length of read not equal to length of quality values nameLength = std::min(MAX_READNAME_LENGTH - 1, kseq->name.l); memcpy(read->name, kseq->name.s, nameLength); read->name[nameLength] = '\0'; break; default: //Unknown error. Should not happen. throw "Unknown error while parsing. Please check whether the input file is corrupted!"; } } return l; } // int copyToRead(SAMRecord * read, kseq_t * kseq, int const l) { // // if (l >= 0) { // if (kseq->seq.l == kseq->qual.l || kseq->qual.l == 0) { // read->set_read_name(string(kseq->name.s)); // read->set_sequence(string(kseq->seq.s)); // read->set_qualities(string(kseq->qual.s)); // } else { // throw "Error while parsing. Read length not equal to length of quality values!"; // } // } else { // switch (l) { // case -1: //End of file // break; // case -2: // //Length of read not equal to length of quality values // read->set_read_name(string(kseq->name.s)); // break; // default: // //Unknown error. Should not happen. // throw "Unknown error while parsing. Please check whether the input file is corrupted!"; // } // } // return l; // } } ; #endif /* PARSER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/IReadProvider.h000066400000000000000000000006371410636150300210240ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef IREADPROVIDER_H_ #define IREADPROVIDER_H_ #include "MappedRead.h" class IReadProvider { public: virtual ~IReadProvider() { } virtual uint init() = 0; virtual bool GenerateRead(int const readid1, MappedRead * & read1, int const readid2, MappedRead * & read2) = 0; virtual void DisposeRead(MappedRead * read) = 0; }; #endif /* IREADPROVIDER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/IRefProvider.h000066400000000000000000000020451410636150300206600ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __IREFPROVIDER_H__ #define __IREFPROVIDER_H__ #include "Types.h" struct Location { uint m_Location; bool used() { return m_Location != 0; //TODO_GENOMESIZE: May be null (first loc in second hashtable/) } }; struct RefEntry { //static const int cIncrements[] = { 10, 20, 50, 100 }; //static int MaxRefsPerEntry; //UNUSED RefEntry(int locs = 0) { ref = 0; offset = 0; reverse = false; weight = 0.0f; refCount = 0; refTotal = 0; } ~RefEntry() { //delete[] ref; } inline uloc getRealLocation(const Location& loc) const { return loc.m_Location + offset; } Location * ref; uloc offset; //Offset for all Locations bool reverse; float weight; int refCount; int refTotal; private: RefEntry(void const * pEntries, int count); friend class PrefixTable; }; class IRefProvider { public: virtual RefEntry const * GetRefEntry(ulong prefix, RefEntry * entry = 0) const = 0; virtual uint GetRefEntryChainLength() const = 0; virtual ~IRefProvider() { } ; }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/LinearRegression.cpp000066400000000000000000000022641410636150300221310ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "LinearRegression.h" #include #include /* math functions */ int linreg(int n, std::unique_ptr const & x, std::unique_ptr const & y, REAL* m, REAL* b, REAL* r) { //int linreg(int n, const REAL x[], const REAL y[], REAL* m, REAL* b, REAL* r) { REAL sumx = 0.0; /* sum of x */ REAL sumx2 = 0.0; /* sum of x**2 */ REAL sumxy = 0.0; /* sum of x * y */ REAL sumy = 0.0; /* sum of y */ REAL sumy2 = 0.0; /* sum of y**2 */ for (int i = 0; i < n; i++) { sumx += x[i]; sumx2 += sqr(x[i]); sumxy += x[i] * y[i]; sumy += y[i]; sumy2 += sqr(y[i]); } REAL denom = (n * sumx2 - sqr(sumx)); if (denom == 0) { // singular matrix. can't solve the problem. *m = 0; *b = 0; if (r) *r = 0; return 1; } *m = (n * sumxy - sumx * sumy) / denom; *b = (sumy * sumx2 - sumx * sumxy) / denom; if (r != NULL) { *r = (sumxy - sumx * sumy / n) / /* compute correlation coeff */ sqrt((sumx2 - sqr(sumx) / n) * (sumy2 - sqr(sumy) / n)); } return 0; } ngmlr-0.2.7+git20210816.a2a31fb/src/LinearRegression.h000066400000000000000000000010601410636150300215670ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __LINEAR_REGRESSION_H__ #define __LINEAR_REGRESSION_H__ #include #include /* math functions */ #include //#define REAL float #define REAL double inline static REAL sqr(REAL x) { return x * x; } //int linreg(int n, const REAL x[], const REAL y[], REAL* m, REAL* b, REAL* r); int linreg(int n, std::unique_ptr const & x, std::unique_ptr const & y, REAL* m, REAL* b, REAL* r); #endif //__LINEAR_REGRESSION_H__ ngmlr-0.2.7+git20210816.a2a31fb/src/LocationScore.h000066400000000000000000000015251410636150300210660ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __LOCATIONSCORE_H__ #define __LOCATIONSCORE_H__ #include "SequenceLocation.h" #include "PlatformSpecifics.h" struct MappedRead; struct CSTableEntry { uint m_Location; uint state; float fScore; float rScore; }; union UScore { int i; float f; }; struct LocationScore { UScore Score; SequenceLocation Location; #ifdef INSTANCE_COUNTING static volatile int sInstanceCount; #endif LocationScore() { #ifdef INSTANCE_COUNTING AtomicInc(&sInstanceCount); #endif } ~LocationScore() { #ifdef INSTANCE_COUNTING AtomicDec(&sInstanceCount); #endif } LocationScore(SequenceLocation location, int score) { Score.i = score; Location = location; #ifdef INSTANCE_COUNTING AtomicInc(&sInstanceCount); #endif } }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/Log.h000066400000000000000000000013701410636150300170410ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __LOGGING_H__ #define __LOGGING_H__ #include "ILog.h" namespace __Log { void Init(); } class _Log : public ILog { public: static _Log const & Instance(); static void Init(char const * logFile, int logLvl); static void FilterLevel(int const lvl); static void setColor(bool const color); static void Cleanup(); void _Message(int const lvl, char const * const title, char const * const msg, ...) const; void _Debug (int const lvl, char const * const title, char const * const msg, ...) const; void Fatal(); private: _Log(); ~_Log(); friend void __Log::Init(); }; #undef Log #define Log _Log::Instance() #define Logger _Log::Instance() #endif ngmlr-0.2.7+git20210816.a2a31fb/src/Logging.cpp000066400000000000000000000122451410636150300202440ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "Log.h" #include #include #include #include #include #include #include "PlatformSpecifics.h" #include "NGMThreads.h" #include "zlib.h" namespace __Log { _Log * pInstance = 0; NGMMutex mutex; NGMOnceControl once_control = NGM_ONCE_INIT; int rwd; int warningCount = 0; void Init() { pInstance = new _Log(); InitConsole(); NGMInitMutex(&mutex); } int filterlvl = 0; int logLvl; bool color = false; bool init = false; char preBuffer[1024]; bool preInit = true; bool logToFile = false; std::vector & msgLog() { static std::vector * res = new std::vector(); return *res; } gzFile fp = 0; char const * lvlStr[] = { "", "[WARNING]", "[ERROR]", "" }; void LogToFile(int lvl, char const * const title, char const * const s, va_list args) { if (!logToFile && !preInit) return; int written = 0; if (title != 0) written += sprintf(preBuffer, "%s[%s] ", lvlStr[lvl], title); else written += sprintf(preBuffer, "%d\t", lvl); vsprintf(preBuffer + written, s, args); if (preInit) msgLog().push_back(std::string(preBuffer)); if (logToFile) { // gzprintf(fp, "%s\n", preBuffer); printf("%s\n", preBuffer); //gzflush(fp); } } // rewind lines inline void rwl() { for (int i = 0; i < rwd; ++i) fprintf(stderr, "\033[A\033[2K"); rwd = 0; } void LogToConsole(bool color, int lvl, char const * const title, char const * const s, va_list args) { if (lvl < filterlvl) return; bool progress = lvl == 99; if (progress) lvl = 0; rwl(); // if (title != 0) { // if (lvl > 0 && color) // SetConsoleColor((ConsoleColor) (MessageTitle + (lvl * 2))); // fprintf(stderr, "[%s] ", title); // } if (color) SetConsoleColor((ConsoleColor) (Message + (lvl * 2))); if (args != 0) vfprintf(stderr, s, args); else fprintf(stderr, "%s", s); if (color) ResetConsoleColor(); fprintf(stderr, "\n"); if (progress) { rwd = 1; } } } using namespace __Log; std::string add_timestamp(std::string str) { std::string::size_type pos = str.find("%s"); if (pos != std::string::npos) { //char months[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0"; const time_t t = time(0); tm * tm = localtime(&t); char timestamp[20]; sprintf(timestamp, "%4i-%02i-%02i_%02i-%02i-%02i", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); //months+m*4 return str.replace(pos, 2, timestamp); } return str; } void _Log::Init(char const * logFile, int pLogLvl) { logLvl = pLogLvl; init = true; NGMLock(&__Log::mutex); try { if (logFile != 0) { //fp = gzopen(logFile, "w"); //if (fp != 0) { for (uint i = 0; i < msgLog().size(); ++i) { //gzprintf(fp, "%s\n", msgLog()[i].c_str()); printf("%s\n", msgLog()[i].c_str()); } msgLog().clear(); logToFile = true; //} else { //LogToConsole(2, "LOG", "Unable to open logfile, logging to file disabled.", 0); //Log.Error("Unable to open logfile, logging to file disabled."); //logToFile = false; //} preInit = false; } } catch (...) { NGMUnlock(&__Log::mutex); init = false; throw; } NGMUnlock(&__Log::mutex); init = false; } _Log const & _Log::Instance() { NGMOnce(&__Log::once_control, __Log::Init); return *__Log::pInstance; } void _Log::_Debug(int lvl, char const * const title, char const * const s, ...) const { va_list args; if (init) { fprintf(stderr, "Log Init active - Message blocked.\n"); fprintf(stderr, "(lvl = %i) (t)%s %s\n", lvl, title, s); return; } NGMLock(&__Log::mutex); if (logLvl & lvl) { va_start(args, s); LogToFile(lvl, 0, s, args); va_end(args); } NGMUnlock(&__Log::mutex); } //LogToFile(int lvl, char const * const title, char const * const s, va_list args) void _Log::_Message(int lvl, char const * const title, char const * const s, ...) const { va_list args; if (init) { fprintf(stderr, "Log Init active - Message blocked.\n"); fprintf(stderr, "(lvl = %i) (t)%s %s\n", lvl, title, s); return; } NGMLock(&__Log::mutex); va_start(args, s); LogToConsole(color, lvl, title, s, args); va_end(args); /*// File Logging disabled (use "tee") va_start(args, s); LogToFile(lvl, title, s, args); va_end(args); */ NGMUnlock(&__Log::mutex); bool terminate = false; if (lvl == 1) { warningCount += 1; if (warningCount > 100) { fprintf(stderr, "Max number of warnings reached!\nPlease report this issue on http://github.com/Cibiv/NextGenMap/issues!\n"); terminate = true; } } if (lvl == 2) { fprintf(stderr, "Terminating\n"); terminate = true; } if(terminate) { ResetConsole(); if (fp != 0) { gzclose(fp); } exit(1); } } void _Log::Cleanup() { if (fp != 0) { gzclose(fp); } delete pInstance; } _Log::_Log() { } _Log::~_Log() { } void _Log::setColor(bool const pColor) { __Log::color = pColor; } void _Log::FilterLevel(int const lvl) { __Log::filterlvl = lvl; } ngmlr-0.2.7+git20210816.a2a31fb/src/MappedRead.cpp000066400000000000000000000064451410636150300206650ustar00rootroot00000000000000/** * * Contact: philipp.rescheneder@gmail.com */ #include "MappedRead.h" #include #undef module_name #define module_name "READ" //volatile int MappedRead::sInstanceCount = 0; // //#ifdef INSTANCE_COUNTING //volatile int MappedRead::sInstanceCount = 0; //volatile int LocationScore::sInstanceCount = 0; //#endif //volatile int Align::sInstanceCount = 0; MappedRead::MappedRead(int const readid, int const qrymaxlen) : ReadId(readid), Calculated(-1), qryMaxLen(qrymaxlen), Scores(0), Alignments(0), iScores(0), Status(0), mappingQlty(255), s(0), length(0), RevSeq(0), Seq(0), qlty(0), name(0), AdditionalInfo(0), group(0) { //#ifdef INSTANCE_COUNTING // AtomicInc(&sInstanceCount); // maxSeqCount = std::max(sInstanceCount, maxSeqCount); //#endif //Name static size_t const MAX_READNAME_LENGTH = 250; name = new char[MAX_READNAME_LENGTH]; } static inline char cpl(char c) { if (c == 'A') return 'T'; else if (c == 'T') return 'A'; else if (c == 'C') return 'G'; else if (c == 'G') return 'C'; else return c; } //// swaps two bases and complements them //static inline void rc(char & c1, char & c2) //{ // char x = c1; // c1 = cpl(c2); // c2 = cpl(x); //} char const * MappedRead::computeReverseSeq() { if (RevSeq == 0) { // RevSeq = new char[length + 1]; // memset(RevSeq, 0, length + 1); int revLength = std::max(qryMaxLen, length + 16); RevSeq = new char[revLength]; memset(RevSeq, 0, revLength); char * fwd = Seq; char * rev = RevSeq + length - 1; for (int i = 0; i < length; ++i) { *rev-- = cpl(*fwd++); //Seq[i] = cpl(RevSeq[length - i - 1]); } } return RevSeq; } void MappedRead::DeleteReadSeq() { if (Seq != 0) delete[] Seq; Seq = 0; if (RevSeq != 0) delete[] RevSeq; RevSeq = 0; } MappedRead::~MappedRead() { if (Scores != 0) { delete[] Scores; Scores = 0; iScores = 0; } if (Alignments != 0) { for (int i = 0; i < Calculated; ++i) { if (Alignments[i].pBuffer1 != 0) { delete[] Alignments[i].pBuffer1; Alignments[i].pBuffer1 = 0; } if (Alignments[i].pBuffer2 != 0) { delete[] Alignments[i].pBuffer2; Alignments[i].pBuffer2 = 0; } if (Alignments[i].nmPerPosition != 0) { delete[] Alignments[i].nmPerPosition; Alignments[i].nmPerPosition = 0; } } delete[] Alignments; Alignments = 0; } DeleteReadSeq(); if (qlty != 0) { delete[] qlty; qlty = 0; } if (name != 0) { delete[] name; name = 0; } //#ifdef INSTANCE_COUNTING // AtomicDec(&sInstanceCount); //#endif } void MappedRead::AllocScores(LocationScore * tmp, int const n) { iScores = n; if (iScores > 0) { Scores = new LocationScore[iScores]; memcpy(Scores, tmp, n * sizeof(LocationScore)); } } //void MappedRead::reallocScores(int const n) { // if (Scores != 0) { // Scores = (LocationScore *) realloc(Scores, n * sizeof(LocationScore)); // } //} void MappedRead::clearScores(int const TopScore) { if (Scores != 0) { if (TopScore != -1) { LocationScore tmp = Scores[TopScore]; delete[] Scores; Scores = new LocationScore[1]; //Scores = (LocationScore *)realloc(Scores, 1 * sizeof(LocationScore)); Scores[0] = tmp; iScores = 1; } else { delete[] Scores; iScores = 0; Scores = 0; } } } int MappedRead::numScores() const { return iScores; } bool MappedRead::hasCandidates() const { return iScores > 0; } ngmlr-0.2.7+git20210816.a2a31fb/src/MappedRead.h000066400000000000000000000044611410636150300203260ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __MAPPEDREAD_H__ #define __MAPPEDREAD_H__ #include #include #include #include "Types.h" #include "IAlignment.h" #include "ReadStatus.h" #include "LocationScore.h" struct MappedRead; typedef struct { MappedRead * fullRead; MappedRead * * reads; size_t readNumber; size_t readsFinished; size_t fwdMapped; size_t reverseMapped; int bestScoreSum; int readId; } ReadGroup; using NGMNames::ReadStatus; // A read with a list of scores fitting the initial predicate // (i.e., each score is greater than cs_threshhold) struct MappedRead { private: public: int const ReadId; //Calculated is initialized with -1. This shows that the read has not passed the candidate search //When the read is submitted to the score computation calculated is set to 0. Each time a score //is computed for this read, Calculated is increased by one int Calculated; // Amount of Scores updated by SW int const qryMaxLen; LocationScore * Scores; Align * Alignments; int iScores; uint Status; int mappingQlty; float s; int length; char * RevSeq; char * Seq; char * qlty; char * name; char * AdditionalInfo; ReadGroup * group; //#ifdef INSTANCE_COUNTING // static volatile int sInstanceCount; //#endif MappedRead(int const readid, int const qrymaxlen); ~MappedRead(); void AllocScores(LocationScore * tmp, int const n); // void reallocScores(int const n); void clearScores(int const TopScore = -1); int numScores() const; bool hasCandidates() const; void AllocBuffers(); inline void SetFlag(ReadStatus const flag) { Status |= flag; } inline bool HasFlag(ReadStatus const flag) const { return (Status & flag) != 0; } char const * computeReverseSeq(); private: void DeleteReadSeq(); static bool SortPred(LocationScore * lhs, LocationScore * rhs) { return lhs->Score.f > rhs->Score.f; } // static bool UniquePred(LocationScore * lhs, LocationScore * rhs) { // if (lhs == 0 || rhs == 0) // return false; // return (lhs->Location.m_Location == rhs->Location.m_Location) && (lhs->Location.m_RefId == rhs->Location.m_RefId); // } static bool IsZero(LocationScore * arg) { return (arg == 0); } }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/MemCheck.h000066400000000000000000000021031410636150300177670ustar00rootroot00000000000000 #ifndef __MEMCHECK_H__ #define __MEMCHECK_H__ #include #include #include #include void *operator new(size_t size, const char *file, int lineno) { void *p = malloc(size); if (p == NULL) throw std::bad_alloc(); fprintf(stdout, "MEMCHECK\tNEW\t%s:%d\t%p\t%lu\n", file, lineno, p, size); return p; } /* ---------------------------------------- operator delete */ void operator delete(void *p) { if (p == NULL) return; fprintf(stdout, "MEMCHECK\tDEL\t-\t%p\t-\n", p); free(p); } /* ---------------------------------------- operator new[] */ void *operator new[](size_t size, const char *file, int lineno) { void *p = malloc(size); if (p == NULL) throw std::bad_alloc(); fprintf(stdout, "MEMCHECK\tNEW\t%s:%d\t%p\t%lu\n", file, lineno, p, size); return p; } /* ---------------------------------------- operator delete[] */ void operator delete[](void *p) { if (p == NULL) return; fprintf(stdout, "MEMCHECK\tDEL\t-\t%p\t-\n", p); free(p); } #define new new(__FILE__, __LINE__) //#define new NEW_DEBUG #endif //__MEMCHECK_H__ ngmlr-0.2.7+git20210816.a2a31fb/src/NGM.cpp000066400000000000000000000246661410636150300173110ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "NGM.h" #include #include #include #include "CS.h" #include "PrefixTable.h" #include "ReadProvider.h" #include "PlainFileWriter.h" #include "SAMWriter.h" #include "Timing.h" #include "StrippedSW.h" #undef module_name #define module_name "NGM" _NGM * _NGM::pInstance = 0; NGMOnceControl _NGM::once_control = NGM_ONCE_INIT; char const * _NGM::AppName = 0; namespace __NGM { inline int min(int a, int b) { return (a < b) ? a : b; } } void _NGM::Init() { pInstance = new _NGM(); } _NGM & _NGM::Instance() { NGMOnce(&_NGM::once_control, Init); return *pInstance; } _NGM::_NGM() : Stats(new NGMStats()), m_ActiveThreads(0), m_NextThread(0), m_CurStart(0), m_CurCount(0), m_SchedulerMutex(), m_SchedulerWait(), m_TrackUnmappedReads(false), m_UnmappedReads(0), m_MappedReads(0), m_WrittenReads(0), m_ReadReads(0), m_RefProvider(0), m_ReadProvider(0) { char const * const output_name = Config.getOutputFile(); // if (!Config.getBAM()) { if (output_name != 0) { Log.Message("Opening for output (SAM): %s", output_name); } else { Log.Message("Writing output (SAM) to stdout"); } m_Output = new PlainFileWriter(output_name); // } else { // if (output_name != 0) { // Log.Message("Opening for output (BAM): %s", output_name); // } else { // Log.Message("Wrinting output (BAM) to stdout"); // } // m_Output = new FileWriterBam(output_name); // } Log.Verbose("NGM Core initialization"); NGMInitMutex(&m_Mutex); NGMInitMutex(&m_OutputMutex); NGMInitMutex(&m_UMRMutex); NGMInitWait(&m_CSWait); NGMInitMutex(&m_SchedulerMutex); NGMInitWait(&m_SchedulerWait); writer = 0; memset(m_StageThreadCount, 0, cMaxStage * sizeof(int)); memset(m_BlockedThreads, 0, cMaxStage * sizeof(int)); memset(m_ToBlock, 0, cMaxStage * sizeof(int)); } void _NGM::InitProviders() { CS::Init(); SequenceProvider.Init(); // Prepares input data m_RefProvider = new CompactPrefixTable(); m_ReadProvider = new ReadProvider(); uint readCount = m_ReadProvider->init(); } _NGM::~_NGM() { delete Stats; Stats = 0; if (m_RefProvider != 0) delete m_RefProvider; if (m_ReadProvider != 0) delete m_ReadProvider; } void _NGM::StartThread(NGMTask * task, int cpu) { Log.Verbose("Starting thread %i <%s> on cpu %i", m_NextThread, task->GetName(), cpu); NGMLock(&m_Mutex); task->m_TID = m_NextThread; m_Tasks[m_NextThread] = task; m_Threads[m_NextThread] = NGMCreateThread(&_NGM::ThreadFunc, task, false); ++m_StageThreadCount[task->GetStage()]; ++m_NextThread; ++m_ActiveThreads; NGMUnlock(&m_Mutex); } void * _NGM::getWriter() { return m_Output; } void _NGM::ReleaseWriter() { if (m_Output != 0) { // if (!Config.getBAM()) { delete (FileWriter*) m_Output; // } else { // delete (FileWriterBam*) m_Output; // } m_Output = 0; } } void _NGM::AddUnmappedRead(MappedRead const * const read, int reason) { AtomicInc(&m_UnmappedReads); Log.Debug(LOG_OUTPUT_DETAILS, "Read %s (%i) not mapped (%i)", read->name, read->ReadId, reason); } int _NGM::GetUnmappedReadCount() const { return m_UnmappedReads; } void _NGM::AddMappedRead(int readid) { AtomicInc(&m_MappedReads); } int _NGM::GetMappedReadCount() const { return m_MappedReads; } void _NGM::AddWrittenRead(int readid) { AtomicInc(&m_WrittenReads); } int _NGM::GetWrittenReadCount() const { return m_WrittenReads; } void _NGM::AddReadRead(int readid) { AtomicInc(&m_ReadReads); } int _NGM::GetReadReadCount() const { return m_ReadReads; } int _NGM::GetStageThreadCount(int stage) { NGMLock(&m_Mutex); int cnt = 0; for (int i = 0; i <= stage; ++i) { cnt += m_StageThreadCount[i]; } NGMUnlock(&m_Mutex); return cnt; } void _NGM::FinishStage(int tid) { NGMLock(&m_Mutex); int stage = m_Tasks[tid]->GetStage(); --m_StageThreadCount[stage]; NGMUnlock(&m_Mutex); Log.Verbose("Thread %i finished its stage (Stage %i, now %i active)", tid, stage, m_StageThreadCount[stage]); } void _NGM::FinishThread(int tid) { AtomicDec(&m_ActiveThreads); Log.Verbose("Thread %i finished (%i worker threads remaining)", tid, m_ActiveThreads); m_Tasks[tid]->FinishStage(); delete m_Tasks[tid]; m_Tasks[tid] = 0; } bool eof = false; std::vector _NGM::GetNextReadBatch(int desBatchSize) { NGMLock(&m_Mutex); std::vector list; desBatchSize &= ~1; if (m_CurCount == 0) { m_CurStart = 0; NGMSignal(&m_CSWait); } list.reserve(desBatchSize); int count = 0; //Long PacBio reads are split into smaller parts. //Each part should have its own id. int idJump = 2000; int i = 0; while (count < desBatchSize && !eof) { MappedRead * read1 = 0; eof = !NGM.GetReadProvider()->GenerateRead(m_CurStart + i * idJump, read1, 0, read1); i += 1; if (!eof) { if (read1 != 0) { count += 1; Stats->readLengthSum += read1->length; if (read1->group == 0) { // Short read found: not split into read group list.push_back(read1); } else { // Long read found: push subreads for (int j = 0; j < read1->group->readNumber; ++j) { list.push_back(read1->group->reads[j]); } } } } } m_CurStart += count; m_CurCount -= desBatchSize; NGMUnlock(&m_Mutex); #ifdef _DEBUGCS if(m_CurStart > 100000) { Log.Warning("Debug CS mode: quitting after 100000 reads!"); list.clear(); } #endif return list; } NGMTHREADFUNC _NGM::ThreadFunc(void* data) { NGMTask * task = (NGMTask*) data; int tid = task->m_TID; try { Log.Verbose("Running thread %i", tid); task->Run(); Log.Verbose("Thread %i run return, finishing", tid); NGM.FinishThread(tid); Log.Verbose("Thread %i finished", tid); } catch (...) { Log.Error("Unhandled exception in thread %i", tid); NGM.FinishThread(tid); } Log.Verbose("ThreadFunc on thread %i returning", tid); return 0; } void _NGM::InitQuit() { static int quitState = 0; ++quitState; if (quitState == 1) { Log.Warning("Hit 'Q' two more times to quit program."); } else if (quitState >= 3) { CleanupPlatform(); Log.Error("Terminate by user request"); Log.Message("%i Threads still active", m_ActiveThreads); for (int i = 0; i < cMaxStage; ++i) { if (m_StageThreadCount[i] > 0) Log.Message("Stage %i got %i threads still running", i, m_StageThreadCount[i]); } exit(-1); } } void _NGM::AquireOutputLock() { NGMLock(&m_OutputMutex); } void _NGM::ReleaseOutputLock() { NGMUnlock(&m_OutputMutex); } IRefProvider const * _NGM::GetRefProvider(int const tid) { return m_RefProvider; } IReadProvider * _NGM::GetReadProvider() { return m_ReadProvider; } bool _NGM::ThreadActive(int tid, int stage) { if (m_ToBlock[stage] > 0) { NGMLock(&m_SchedulerMutex); bool blocked = false; if (m_ToBlock[stage] > 0) { --m_ToBlock[stage]; blocked = true; m_BlockedThreads[stage]++; while (blocked) { Log.Green("Block %i @ %i", tid, stage); NGMWait(&m_SchedulerMutex, &m_SchedulerWait); if (m_ToBlock[stage] < 0) { ++m_ToBlock[stage]; blocked = false; m_BlockedThreads[stage]--; Log.Green("Unblock %i @ %i", tid, stage); } } } NGMUnlock(&m_SchedulerMutex); } return true; } void _NGM::StopThreads() { } void _NGM::StartThreads() { StartCS(Config.getThreads()); } void _NGM::StartCS(int cs_threadcount) { for (int i = 0; i < cs_threadcount; ++i) { NGMTask * cs = 0; cs = new CS(); StartThread(cs, -1); } } IAlignment * _NGM::CreateAlignment(int const mode) { IAlignment * instance = 0; switch (Config.getSubreadAligner()) { case 2: instance = new StrippedSW(); break; default: Log.Error("Invalid subread alignerd: %d", Config.getSubreadAligner()); throw ""; } return instance; } void _NGM::DeleteAlignment(IAlignment* instance) { Log.Verbose("Delete alignment called"); if (instance != 0) { delete instance; instance = 0; } } void _NGM::MainLoop() { Timer tmr; tmr.ST(); bool const progress = Config.getProgress(); int processed = 0; float runTime = 0.0f; float readsPerSecond = 0.0f; float alignSuccessRatio = 0.0f; int avgCorridor = 0; while (Running()) { Sleep(2000); if (progress) { processed = std::max(1, NGM.GetMappedReadCount() + NGM.GetUnmappedReadCount()); runTime = tmr.ET(); readsPerSecond = processed / runTime; if((NGM.Stats->alignmentCount + NGM.Stats->invalidAligmentCount) > 0) { avgCorridor = NGM.Stats->corridorLen / (NGM.Stats->alignmentCount + NGM.Stats->invalidAligmentCount); alignSuccessRatio = NGM.Stats->alignmentCount * 1.0f / (NGM.Stats->alignmentCount + NGM.Stats->invalidAligmentCount); } float avgAlignPerc = 0.0f; int avgReadLenght = 0; float alignRate = 0.0f; if(processed > 0) { avgAlignPerc = NGM.Stats->avgAlignPerc / std::max(1, NGM.GetMappedReadCount()); avgReadLenght = (int)(NGM.Stats->readLengthSum / processed); alignRate = NGM.GetMappedReadCount() * 1.0f / processed; } Log.Progress("Processed: %d (%.2f), R/S: %.2f, RL: %d, Time: %.2f %.2f %.2f, Align: %.2f, %d, %.2f", processed, alignRate, readsPerSecond, avgReadLenght, NGM.Stats->csTime, NGM.Stats->scoreTime, NGM.Stats->alignTime, alignSuccessRatio, avgCorridor, avgAlignPerc); } } if (progress) { processed = std::max(1, NGM.GetMappedReadCount() + NGM.GetUnmappedReadCount()); runTime = tmr.ET(); readsPerSecond = processed / runTime; if((NGM.Stats->alignmentCount + NGM.Stats->invalidAligmentCount) > 0) { alignSuccessRatio = NGM.Stats->alignmentCount * 1.0f / (NGM.Stats->alignmentCount + NGM.Stats->invalidAligmentCount); avgCorridor = NGM.Stats->corridorLen / (NGM.Stats->alignmentCount + NGM.Stats->invalidAligmentCount); } float avgAlignPerc = 0.0f; int avgReadLenght = 0; float alignRate = 0.0f; if(processed > 0) { avgAlignPerc = NGM.Stats->avgAlignPerc / std::max(1, NGM.GetMappedReadCount()); avgReadLenght = (int)(NGM.Stats->readLengthSum / processed); alignRate = NGM.GetMappedReadCount() * 1.0f / processed; } Log.Message("Processed: %d (%.2f), R/S: %.2f, RL: %d, Time: %.2f %.2f %.2f, Align: %.2f, %d, %.2f", processed, alignRate, readsPerSecond, avgReadLenght, NGM.Stats->csTime, NGM.Stats->scoreTime, NGM.Stats->alignTime, alignSuccessRatio, avgCorridor, avgAlignPerc); } } ngmlr-0.2.7+git20210816.a2a31fb/src/NGM.h000066400000000000000000000066001410636150300167420ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __COMMON_H__ #define __COMMON_H__ #include #include "Types.h" #include "Log.h" #include "IConfig.h" #include "PlatformSpecifics.h" #include "SequenceProvider.h" #include "NGMThreads.h" #include "MappedRead.h" #include "NGMStats.h" #include "NGMTask.h" #include "IRefProvider.h" #include "IReadProvider.h" #include "IAlignment.h" #include "FileWriter.h" #ifdef _WIN32 #define _CRTDBG_MAP_ALLOC #include #include #ifndef NDEBUG #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) #define new DEBUG_NEW #endif #endif #undef module_name #define module_name "NGM" class GenericReadWriter; class _NGM { public: static _NGM & Instance(); // Liefert den nächsten Batch an Reads, oder einen leeren Vektor wenn keien Reads mehr zu mappen sind std::vector GetNextReadBatch(int batchSize); inline bool Running() const { return m_ActiveThreads > 0; } void GeneratePartitions(); _NGM(); ~_NGM(); void InitProviders(); IAlignment * CreateAlignment(int const mode); void DeleteAlignment(IAlignment* instance); void StartThread( NGMTask * task, int cpu = -1 ); void AddUnmappedRead(MappedRead const * const read, int reason ); int GetUnmappedReadCount() const; void AddMappedRead( int readid ); int GetMappedReadCount() const; void AddWrittenRead( int readid ); int GetWrittenReadCount() const; void AddReadRead( int readid ); int GetReadReadCount() const; void DisposeRead(MappedRead * read); void AquireOutputLock(); void ReleaseOutputLock(); void InitQuit(); void StartThreads(); void StopThreads(); void MainLoop(); void * getWriter(); void ReleaseWriter(); bool StageActive( int stage ) { return GetStageThreadCount(stage) > 0; } bool SingleStageActive( int stage ) { return m_StageThreadCount[stage] > 0; } int GetStageThreadCount( int stage ); bool ThreadActive( int tid, int stage ); IRefProvider const * GetRefProvider(int const tid); IReadProvider * GetReadProvider(); void FinishStage( int tid ); void FinishThread( int tid ); NGMStats * Stats; static char const * AppName; private: static NGMTHREADFUNC ThreadFunc(void*); static void Init(); friend void NGMTask::FinishStage(); void StartCS(int threads); friend int main(int argc, char* argv[]); static _NGM * pInstance; static NGMOnceControl once_control; static const int cMaxThreads = 1024; static const int cMaxStage = 8; volatile int m_ActiveThreads; int m_NextThread; //TODO: hack - fix this!!! void * m_Output; volatile int m_CurStart; volatile int m_CurCount; GenericReadWriter * writer; NGMMutex m_Mutex; NGMMutex m_OutputMutex; int m_StageThreadCount[cMaxStage]; NGMThread m_Threads[cMaxThreads]; NGMTask * m_Tasks[cMaxThreads]; int m_BlockedThreads[cMaxStage]; int m_ToBlock[cMaxStage]; NGMMutex m_SchedulerMutex; NGMThreadWait m_SchedulerWait; NGMMutex m_UMRMutex; NGMThreadWait m_CSWait; bool m_TrackUnmappedReads; volatile int m_UnmappedReads; volatile int m_MappedReads; volatile int m_WrittenReads; volatile int m_ReadReads; IRefProvider * m_RefProvider; IReadProvider * m_ReadProvider; friend class _SequenceProvider; }; #undef module_name #define module_name 0 #define NGM _NGM::Instance() #endif ngmlr-0.2.7+git20210816.a2a31fb/src/NGMStats.h000066400000000000000000000012571410636150300177640ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __NGMSTATS_H__ #define __NGMSTATS_H__ #include "Types.h" struct NGMStats { float csTime; float scoreTime; float alignTime; int csLength; int csOverflows; int avgnCRMS; float avgAlignPerc; long long corridorLen; long long readLengthSum; int readsInProcess; uint invalidAligmentCount; uint alignmentCount; public: NGMStats() { csTime = 0.0f; scoreTime = 0.0f; alignTime = 0.0f; csLength = 0; csOverflows = 0; avgnCRMS = 0; avgAlignPerc = 0.0f; corridorLen = 0; readLengthSum = 0ll; readsInProcess = 0; invalidAligmentCount = 0; alignmentCount = 0; } ~NGMStats() { } }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/NGMTask.cpp000066400000000000000000000010471410636150300201200ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "NGM.h" #include "Log.h" void NGMTask::FinishStage() { if (!m_FinishedStage) { NGM.FinishStage(m_TID); m_FinishedStage = true; } } void NGMTask::Run() { m_FinishedStage = false; try { DoRun(); } catch (std::bad_alloc & ex) { Log.Error("Exception bad_alloc occured in thread %i. This usually means you ran out of physical or virtual memory (try ulimit -v)", m_TID); } catch (...) { Log.Error("Exception in thread %i", m_TID); throw; } } ngmlr-0.2.7+git20210816.a2a31fb/src/NGMTask.h000066400000000000000000000006321410636150300175640ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __NGMTASK_H__ #define __NGMTASK_H__ class NGMTask { int m_ReadProvider; protected: friend class _NGM; int m_TID; bool m_FinishedStage; public: void Run(); void FinishStage(); virtual void DoRun() = 0; virtual int GetStage() const = 0; const virtual char* GetName() const = 0; virtual ~NGMTask() {} }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/NGMThreads.h000066400000000000000000000026701410636150300202600ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __NGMTHREADS_H__ #define __NGMTHREADS_H__ // Simple Windows/pThread wrapper #ifdef _WIN32 // Windows Threads #define NOMINMAX #include #define NGMTHREADFUNC DWORD WINAPI typedef CRITICAL_SECTION NGMMutex; typedef HANDLE NGMThread; typedef HANDLE NGMThreadWait; struct NGMOnceControl { bool done; LPCRITICAL_SECTION cs; NGMOnceControl(); ~NGMOnceControl(); }; #define NGM_ONCE_INIT NGMOnceControl(); #endif #ifndef _WIN32 // POSIX Threads #include "pthread.h" #include "sched.h" #define NGMTHREADFUNC void* typedef pthread_t NGMThread; typedef pthread_cond_t NGMThreadWait; typedef pthread_mutex_t NGMMutex; typedef pthread_once_t NGMOnceControl; #define NGM_ONCE_INIT PTHREAD_ONCE_INIT #endif typedef NGMTHREADFUNC NGMThreadFunc(void*); typedef NGMThreadFunc* pNGMThreadFunc; NGMThread NGMCreateThread(pNGMThreadFunc func, void * data, bool detached = false); void NGMJoin(NGMThread * thread); void NGMJoinAll(NGMThread * thread, int count); void NGMSetThreadAffinity(NGMThread * thread, int cpu); void NGMInitWait(NGMThreadWait * wait); void NGMWait(NGMMutex * mutex, NGMThreadWait * wait); void NGMSignal(NGMThreadWait * wait); void NGMInitMutex(NGMMutex * mutex); void NGMLock(NGMMutex * mutex); void NGMUnlock(NGMMutex * mutex); void NGMOnce(NGMOnceControl * once_control, void (*init_func)()); #endif ngmlr-0.2.7+git20210816.a2a31fb/src/OutputReadBuffer.cpp000066400000000000000000000025421410636150300221030ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "OutputReadBuffer.h" OutputReadBuffer * OutputReadBuffer::pInstance = 0; OutputReadBuffer::OutputReadBuffer() { NGMInitMutex(&m_OutputMutex); currentReadId = 0; } OutputReadBuffer::~OutputReadBuffer() { if(outputBuffer.size() > 0) { throw "Elements left in buffer!"; } } //#include // ////g++ ../../src/OutputReadBuffer.cpp ../../src/core/unix_threads.cpp ../../src/MappedRead.cpp -I ../../src/core/ -I ../../include/ -o buffer -pthread // //void write(OutputReadBuffer & buffer) { // std::pair pair; // while ((pair = buffer.getNextRead()).first != 0) { // std::cout << "Printing read: " << pair.first->ReadId << std::endl; // } // std::cout << "---------------" << std::endl; //} // //int main() { // OutputReadBuffer & buffer = OutputReadBuffer::getInstance(); // // buffer.addRead(new MappedRead(4, 100), false); // write(buffer); // buffer.addRead(new MappedRead(1, 100), false); // write(buffer); // buffer.addRead(new MappedRead(0, 100), false); // write(buffer); // buffer.addRead(new MappedRead(2, 100), false); // write(buffer); // // // buffer.addRead(new MappedRead(3, 100), false); // write(buffer); // buffer.addRead(new MappedRead(5, 100), false); // write(buffer); // buffer.addRead(new MappedRead(6, 100), false); // write(buffer); // // // // return 0; //} ngmlr-0.2.7+git20210816.a2a31fb/src/OutputReadBuffer.h000066400000000000000000000046641410636150300215570ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef OUTPUTREADBUFFER_H_ #define OUTPUTREADBUFFER_H_ #include #include "NGMThreads.h" #include "MappedRead.h" #include "GenericReadWriter.h" using std::list; class OutputReadBuffer { static OutputReadBuffer * pInstance; NGMMutex m_OutputMutex; list > outputBuffer; int currentReadId; static int const maxSize = 100000; OutputReadBuffer(); OutputReadBuffer(const OutputReadBuffer& rs) { pInstance = rs.pInstance; currentReadId = 0; } OutputReadBuffer& operator =(const OutputReadBuffer& rs) { if (this != &rs) { pInstance = rs.pInstance; } return *this; } ~OutputReadBuffer(); public: /*Is used by multiple threads but initialized by main thread (before other threads are started), thus no locking is required*/ static OutputReadBuffer& getInstance() { static OutputReadBuffer theInstance; pInstance = &theInstance; return *pInstance; } void addRead(MappedRead * read, bool mapped) { NGMLock(&m_OutputMutex); int index = 0; std::list >::iterator it = outputBuffer.begin(); while (it != outputBuffer.end() && read->ReadId > (*it).first->ReadId) { it++; } outputBuffer.insert(it, std::pair(read, mapped)); if (outputBuffer.size() > maxSize) { throw "Max buffer size reached."; } // if(outputBuffer.size() >= 2) { // for (it=outputBuffer.begin(); it!=outputBuffer.end(); ++it) { // std::cout << (*it).first << " " << (*it).first->ReadId << " " << (*it).second << " -- "; // } // std::cout << std::endl; // getchar(); // } NGMUnlock(&m_OutputMutex); } std::pair getNextRead(GenericReadWriter * writer) { std::pair pair; pair.first = 0; pair.second = false; NGMLock(&m_OutputMutex); //Log.Message("%d (%s) %d %d", outputBuffer.front().first->ReadId, outputBuffer.front().first->name, currentReadId, outputBuffer.size()); while (outputBuffer.size() > 0 && outputBuffer.front().first->ReadId == currentReadId) { // Log.Message("%s: %d %d", outputBuffer.front().first->name, outputBuffer.front().first->ReadId, currentReadId); pair = outputBuffer.front(); outputBuffer.pop_front(); currentReadId += 1; writer->WriteRead(pair.first, pair.second); NGM.GetReadProvider()->DisposeRead(pair.first); } NGMUnlock(&m_OutputMutex); return pair; } }; #endif /* OUTPUTREADBUFFER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/PlainFileWriter.h000066400000000000000000000017451410636150300213660ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef PLAINFILEWRITER_H_ #define PLAINFILEWRITER_H_ #include #include #include #include #include "NGMThreads.h" #include "ILog.h" #include "IConfig.h" #include "FileWriter.h" class PlainFileWriter: public FileWriter { public: FILE * m_Output; PlainFileWriter(char const * const filename) { if (filename == 0) { m_Output = stdout; } else { if (!(m_Output = fopen(filename, "w"))) { Log.Error("Unable to open output file %s", filename); } } } ~PlainFileWriter() { fclose(m_Output); } void doFlush(int & bufferPosition, int const BUFFER_LIMIT, char * writeBuffer, bool last = false) { if (bufferPosition > BUFFER_LIMIT || last) { #ifdef __APPLE__ fwrite(writeBuffer, sizeof(char), bufferPosition, m_Output); #else fwrite_unlocked(writeBuffer, sizeof(char), bufferPosition, m_Output); #endif bufferPosition = 0; } } }; #endif /* PLAINFILEWRITER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/PlatformSpecifics.h000066400000000000000000000032411410636150300217340ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __PLATFORMSPECIFICS_H__ #define __PLATFORMSPECIFICS_H__ #include "Types.h" enum ConsoleColor { Message, MessageTitle, Warning, WarningTitle, Error, ErrorTitle }; void InitPlatform(); void CleanupPlatform(); void InitConsole(); void ClearConsole(); void SetConsoleColor(ConsoleColor const color); void ResetConsoleColor(); void ResetConsole(); #ifndef _WIN32 ulong GetTickCount(); #endif int GetPID(); // Blocking wait for msec milliseconds void Sleep(int msec); bool const FileExists(char const * const filename); uloc const FileSize(char const * const filename); int const CreateMapping(char const * const filename, char const * &pData); void Remap(int const mapping, char const * & pData); void CloseMapping(int const mapping); uloc GetMapLength(int const map); //bool CheckDLL(char const * const filename); //int const InitDLL(char const * const filename); //void * GetDLLFunc(int const dll, char const * const name, bool required = true); #ifndef _WIN32 int _kbhit(void); int _getch(); #endif #ifdef _WIN32 #define NOMINMAX #include #endif // Atomically increment *pi and return the incremented value // _asm: LOCK INC DWORD PTR pi inline int AtomicInc(volatile int * pi) { #ifdef _WIN32 return (int)InterlockedIncrement((volatile long*)pi); #endif #ifndef _WIN32 // GCC Builtin return __sync_add_and_fetch(pi, 1); #endif } inline int AtomicDec(volatile int * pi) { #ifdef _WIN32 return (int)InterlockedDecrement((volatile long*)pi); #endif #ifndef _WIN32 return __sync_add_and_fetch(pi, -1); #endif } #endif ngmlr-0.2.7+git20210816.a2a31fb/src/PrefixTable.cpp000066400000000000000000000471661410636150300210750ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "PrefixTable.h" #include #include #include #include #include #include "CS.h" #include "Timing.h" #undef module_name #define module_name "PREPROCESS" extern int lastSeqTotal; static uint const refTabCookie = 0x1701E; //static uint const refTabEndCookie = 0xC0FFEE; uloc CompactPrefixTable::c_tableLocMax = 4294967296 - 1; int lastSeqTotal = 0; int CompactPrefixTable::maxPrefixFreq = 1000; ulong CompactPrefixTable::lastPrefix; loc CompactPrefixTable::lastBin; loc CompactPrefixTable::lastPos; uint CompactPrefixTable::skipCount; uint CompactPrefixTable::skipBuild; TableUnit* CompactPrefixTable::CurrentUnit; //Used to control which kmers should be counted for index building, only locations //that will be in the unit should also be in the index uloc CompactPrefixTable::kmerCountMinLocation; uloc CompactPrefixTable::kmerCountMaxLocation; static const unsigned char ReverseTable16[] = { 0x00, 0x04, 0x08, 0x0C, 0x01, 0x05, 0x09, 0x0D, 0x02, 0x06, 0x0A, 0x0E, 0x03, 0x07, 0x0B, 0x0F }; //static const unsigned char ReverseTable256[] = { 0, 64, 128, 192, 16, 80, 144, // 208, 32, 96, 160, 224, 48, 112, 176, 240, 4, 68, 132, 196, 20, 84, 148, // 212, 36, 100, 164, 228, 52, 116, 180, 244, 8, 72, 136, 200, 24, 88, 152, // 216, 40, 104, 168, 232, 56, 120, 184, 248, 12, 76, 140, 204, 28, 92, // 156, 220, 44, 108, 172, 236, 60, 124, 188, 252, 1, 65, 129, 193, 17, 81, // 145, 209, 33, 97, 161, 225, 49, 113, 177, 241, 5, 69, 133, 197, 21, 85, // 149, 213, 37, 101, 165, 229, 53, 117, 181, 245, 9, 73, 137, 201, 25, 89, // 153, 217, 41, 105, 169, 233, 57, 121, 185, 249, 13, 77, 141, 205, 29, // 93, 157, 221, 45, 109, 173, 237, 61, 125, 189, 253, 2, 66, 130, 194, 18, // 82, 146, 210, 34, 98, 162, 226, 50, 114, 178, 242, 6, 70, 134, 198, 22, // 86, 150, 214, 38, 102, 166, 230, 54, 118, 182, 246, 10, 74, 138, 202, // 26, 90, 154, 218, 42, 106, 170, 234, 58, 122, 186, 250, 14, 78, 142, // 206, 30, 94, 158, 222, 46, 110, 174, 238, 62, 126, 190, 254, 3, 67, 131, // 195, 19, 83, 147, 211, 35, 99, 163, 227, 51, 115, 179, 243, 7, 71, 135, // 199, 23, 87, 151, 215, 39, 103, 167, 231, 55, 119, 183, 247, 11, 75, // 139, 203, 27, 91, 155, 219, 43, 107, 171, 235, 59, 123, 187, 251, 15, // 79, 143, 207, 31, 95, 159, 223, 47, 111, 175, 239, 63, 127, 191, 255 }; /////////////////////////////////////////////////////////////////////////////// // HELPERS /////////////////////////////////////////////////////////////////////////////// //Works only for 4 byte inline ulong revComp(ulong prefix) { static const int shift = 32 - CS::prefixBits; //Compute complement ulong compPrefix = (prefix ^ 0xAAAAAAAA) & CS::prefixMask; //Reverse compPrefix = compPrefix << shift; ulong compRevPrefix = (ReverseTable16[compPrefix & 0x0f] << 28) | (ReverseTable16[(compPrefix >> 4) & 0x0f] << 24) | (ReverseTable16[(compPrefix >> 8) & 0x0f] << 20) | (ReverseTable16[(compPrefix >> 12) & 0x0f] << 16) | (ReverseTable16[(compPrefix >> 16) & 0x0f] << 12) | (ReverseTable16[(compPrefix >> 20) & 0x0f] << 8) | (ReverseTable16[(compPrefix >> 24) & 0x0f] << 4) | (ReverseTable16[(compPrefix >> 28) & 0x0f]); // ulong compRevPrefix = (ReverseTable256[compPrefix & 0xff] << 24) // | (ReverseTable256[(compPrefix >> 8) & 0xff] << 16) // | (ReverseTable256[(compPrefix >> 16) & 0xff] << 8) // | (ReverseTable256[(compPrefix >> 24) & 0xff]); return compRevPrefix; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// uint CompactPrefixTable::GetRefEntryChainLength() const { return m_UnitCount * 2; } CompactPrefixTable::CompactPrefixTable(bool const dualStrand, bool const skip) : DualStrand(dualStrand), skipRep(skip) { m_RefSkip = Config.getKmerSkip(); m_PrefixLength = CS::prefixBasecount; uint indexLength = (int) pow(4.0, (double) m_PrefixLength) + 1; std::stringstream refFileName; refFileName << std::string(Config.getReferenceFile()) << "-ht-" << m_PrefixLength << "-" << m_RefSkip << ".2.ngm"; char * cacheFile = new char[refFileName.str().size() + 1]; strcpy(cacheFile, refFileName.str().c_str()); if (!readFromFile(cacheFile)) { Log.Verbose("Building reference table"); kmerCountMinLocation = 0; kmerCountMaxLocation = c_tableLocMax; uloc genomeSize = SequenceProvider.GetConcatRefLen(); m_UnitCount = 1 + genomeSize / c_tableLocMax; m_Units = new TableUnit[m_UnitCount]; Log.Verbose("Allocated %d hashtable units (tableLocMax=2^%f, genomeSize=2^%f)",m_UnitCount,log(c_tableLocMax)*M_LOG2E,log(genomeSize)*M_LOG2E); CreateTable(indexLength); saveToFile(cacheFile, indexLength); } delete[] cacheFile; cacheFile = 0; // test(); } void CompactPrefixTable::test() { uint indexLength = (int) pow(4.0, (double) m_PrefixLength); Log.Message("Index length: %u", indexLength); for (int i = 0; i < m_UnitCount; ++i) { TableUnit * unit = &m_Units[i]; Index * index = unit->RefTableIndex; for (int j = 0; j < indexLength; ++j) { uloc start = index[j].m_TabIndex - 1; //TODO: Fix Invalid read of size 4 int maxLength = index[j + 1].m_TabIndex - 1 - start; if (!(maxLength >= 0 && maxLength <= 1000 && start < unit->cRefTableLen)) { printf("Error in index:\n"); printf("%d: %u %d %d\n", j - 1, index[j - 1].m_TabIndex, index[j - 1].m_RevCompIndex, index[j - 1].used()); printf("%d: %u %d %d -> %llu %d\n", j, index[j].m_TabIndex, index[j].m_RevCompIndex, index[j].used(), start, maxLength); printf("%d: %u %d %d\n", j + 1, index[j + 1].m_TabIndex, index[j + 1].m_RevCompIndex, index[j + 1].used()); printf("%d: %u %d %d\n", j + 2, index[j + 2].m_TabIndex, index[j + 2].m_RevCompIndex, index[j + 2].used()); } fflush(stdout); } uint tableLen = unit->cRefTableLen; Location * positions = unit->RefTable; Log.Message("Table length: %u", tableLen); for (uint j = 0; j < tableLen; ++j) { uloc pos = positions[j].m_Location + unit->Offset; if (!(pos < SequenceProvider.GetConcatRefLen())) { printf("Error in table"); printf("%u: %u\n", j, positions[j].m_Location); } } } RefEntry* m_entry; int m_entryCount = GetRefEntryChainLength(); m_entry = new RefEntry[m_entryCount]; for (int i = 0; i < indexLength; ++i) { printf("%d:", i); RefEntry const * entries = GetRefEntry(i, m_entry); // Liefert eine liste aller Vorkommen dieses Praefixes in der Referenz RefEntry const * cur = entries; for (int i = 0; i < m_entryCount; i++) { //Get kmer-weight. float weight = cur->weight / 100.0f; int const n = cur->refCount; printf("\t%f\t%d", weight, n); for (int i = 0; i < n; ++i) { uloc loc = cur->getRealLocation(cur->ref[i]); printf("\t%llu", loc); } cur++; } printf("\n"); } } CompactPrefixTable::~CompactPrefixTable() { Log.Verbose("Clearing prefix table"); Clear(); Log.Verbose("Cleanup done"); } void CompactPrefixTable::Clear() { delete[] m_Units; } int * CompactPrefixTable::CountKmerFreq(uint length) { Log.Verbose("\tNumber of k-mers: %d", length); int * freq = new int[length]; memset(freq, 0, length); for (int i = 0; i < SequenceProvider.GetRefCount(); ++i) { lastPrefix = 111111; lastBin = -1; m_CurGenSeq = i; if (!DualStrand || !(m_CurGenSeq % 2)) { uloc offset = SequenceProvider.GetRefStart(m_CurGenSeq); uloc len = SequenceProvider.GetRefLen(m_CurGenSeq); char * seq = new char[len + 2]; SequenceProvider.DecodeRefSequence(seq, m_CurGenSeq, offset, len); if(skipRep) { CS::PrefixIteration(seq, len, &CompactPrefixTable::CountKmer, 0, 0, freq, m_RefSkip, offset); } else { CS::PrefixIteration(seq, len, &CompactPrefixTable::CountKmerwoSkip, 0, 0, freq, m_RefSkip, offset); } delete[] seq; seq = 0; } } return freq; } void CompactPrefixTable::Generate() { int i = 0; for (int i = 0; i < SequenceProvider.GetRefCount(); ++i) { lastPrefix = 111111; lastBin = -1; m_CurGenSeq = i; if (!DualStrand || !(m_CurGenSeq % 2)) { Timer t; t.ST(); uloc offset = SequenceProvider.GetRefStart(m_CurGenSeq); uloc len = SequenceProvider.GetRefLen(m_CurGenSeq); char * seq = new char[len + 2]; SequenceProvider.DecodeRefSequence(seq, m_CurGenSeq, offset, len); if(skipRep) { CS::PrefixIteration(seq, len, &CompactPrefixTable::BuildPrefixTable, 0, 0, this, m_RefSkip, offset); } else { CS::PrefixIteration(seq, len, &CompactPrefixTable::BuildPrefixTablewoSkip, 0, 0, this, m_RefSkip, offset); } Log.Verbose("Create table for chr %d. Start: %d, Length: %u (%.2fs)", m_CurGenSeq, 0, len, t.ET()); delete[] seq; seq = 0; } } if (skipBuild == skipCount) { Log.Verbose("\tNumber of repetitive k-mers ignored: %d", skipBuild); } else { Log.Error("\tSkipBuild (%d) != SkipCount (%d)", skipCount, skipBuild); } } uint CompactPrefixTable::createRefTableIndex(uint const length) { Timer freqT; freqT.ST(); int * freqs = CountKmerFreq(length); Log.Verbose("\tCounting kmers took %.2fs", freqT.ET()); Timer t; t.ST(); CurrentUnit->RefTableIndex = new Index[length + 1]; uint next = 0; int ignoredPrefixes = 0; int usedPrefixes = 0; int maxFreq = 0; long sum = 0; uint i = 0; for (i = 0; i < length - 1; i++) { //Add for each kmer ref to the reverse complement kmer ulong compRevPrefix = revComp(i); //Create index based on kmer frequencies int freq = freqs[i]; int total_freq = freq + freqs[compRevPrefix]; maxFreq = std::max(maxFreq, total_freq); if (freq > 0 && total_freq < maxPrefixFreq) { CurrentUnit->RefTableIndex[i].m_TabIndex = next + 1; CurrentUnit->RefTableIndex[i].m_RevCompIndex = (maxPrefixFreq - total_freq) * 100.0f / maxPrefixFreq; next += freq; sum += freq; usedPrefixes += 1; } else { CurrentUnit->RefTableIndex[i].m_TabIndex = next + 1; if (freq > 0) { ignoredPrefixes += 1; } } } CurrentUnit->RefTableIndex[i].m_TabIndex = next + 1; float avg = sum * 1.0 / (usedPrefixes + ignoredPrefixes) * 1.0; delete[] freqs; freqs = 0; Log.Verbose("\tAverage number of positions per prefix: %f", avg); Log.Message("%d prefixes were ignored due to the frequency cutoff (%d)", ignoredPrefixes, maxPrefixFreq); Log.Verbose("\tIndex size: %d byte (%d x %d)", length * sizeof(Index), length, sizeof(Index)); Log.Verbose("\tGenerating index took %.2fs", t.ET()); return next; } void CompactPrefixTable::CreateTable(uint const length) { for (int i = 0; i < m_UnitCount; ++i) { CurrentUnit = &m_Units[i]; CurrentUnit->Offset = kmerCountMinLocation; Log.Message("Building reference index #%d (kmer length: %d, reference skip: %d)", i, m_PrefixLength, m_RefSkip); Timer gtmr; gtmr.ST(); CurrentUnit->cRefTableLen = createRefTableIndex(length); Timer tmr; tmr.ST(); CurrentUnit->RefTable = new Location[CurrentUnit->cRefTableLen + 1]; for (uint i = 0; i < CurrentUnit->cRefTableLen + 1; ++i) { CurrentUnit->RefTable[i].m_Location = 0; } Log.Verbose("\tAllocating and initializing prefix Table took %.2fs", tmr.ET()); Log.Verbose("\tNumber of prefix positions is %d (%d)", CurrentUnit->cRefTableLen, sizeof(Location)); Log.Verbose("\tSize of RefTable is %ld", (ulong)CurrentUnit->cRefTableLen * (ulong)sizeof(Location)); Generate(); Log.Message("Overall time for creating RefTable: %.2fs", gtmr.ET()); kmerCountMinLocation += c_tableLocMax; kmerCountMaxLocation += c_tableLocMax; } // long count = 0; // RefEntry * dummy = new RefEntry(0); // for (uint i = 0; i < length; i++) { // RefEntry const * entry = GetRefEntry(i, dummy); // int lastBin = -1; // for (int j = 0; j < entry->refCount; ++j) { // int currentBin = GetBin(entry->ref[j].m_Location); // if (currentBin == lastBin) { //// entry->ref[j].m_RefId = -1; // count += 1; // Log.Message("Prefix %d:\t%d\t%d (%d)\t(%ld)", i, entry->ref[j].m_RefId, entry->ref[j].m_Location, currentBin, count); // } // lastBin = currentBin; // } //// Log.Message("-----------------------------------------------"); // } } void CompactPrefixTable::CountKmer(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data) { if (pos < kmerCountMinLocation || pos > kmerCountMaxLocation) return; int * freq = (int *) data; if (prefix == lastPrefix) { loc currentBin = GetBin(pos); if (currentBin != lastBin || lastBin == -1) { freq[prefix] += 1; } else { skipCount += 1; // Log.Message("Prefix %d (skip):\t%d (%d)\t%d (%d)\t(%ld)", prefix, lastPos, lastBin, pos, currentBin, skipCount); } lastBin = currentBin; lastPos = pos; } else { lastBin = -1; lastPos = -1; freq[prefix] += 1; } lastPrefix = prefix; } void CompactPrefixTable::CountKmerwoSkip(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data) { if (pos < kmerCountMinLocation || pos > kmerCountMaxLocation) return; int * freq = (int *) data; freq[prefix] += 1; } void CompactPrefixTable::BuildPrefixTable(ulong prefix, uloc real_pos, ulong mutateFrom, ulong mutateTo, void* data) { if (real_pos < kmerCountMinLocation || real_pos > kmerCountMaxLocation) return; //Rebase position using current hashtable unit offset uloc temp_pos = real_pos - CurrentUnit->Offset; uint reduced_pos = temp_pos; CompactPrefixTable * _this = (CompactPrefixTable*) data; // _this->m_BCalls++; if (prefix == lastPrefix) { int currentBin = GetBin(real_pos); if (currentBin != lastBin || lastBin == -1) { if (CurrentUnit->RefTableIndex[prefix].used()) { Location tmp = { reduced_pos }; _this->SaveToRefTable(prefix, tmp); } } else { skipBuild += 1; // Log.Message("Prefix %d (skip):\t%d (%d)\t%d (%d)\t(%ld)", prefix, lastPos, lastBin, pos, currentBin, skipCount); } lastBin = currentBin; lastPos = real_pos; } else { lastBin = -1; lastPos = -1; if (CurrentUnit->RefTableIndex[prefix].used()) { Location tmp = { reduced_pos }; _this->SaveToRefTable(prefix, tmp); } } lastPrefix = prefix; } void CompactPrefixTable::BuildPrefixTablewoSkip(ulong prefix, uloc real_pos, ulong mutateFrom, ulong mutateTo, void* data) { if (real_pos < kmerCountMinLocation || real_pos > kmerCountMaxLocation) return; //Rebase position using current hashtable unit offset uloc temp_pos = real_pos - CurrentUnit->Offset; uint reduced_pos = temp_pos; CompactPrefixTable * _this = (CompactPrefixTable*) data; // _this->m_BCalls++; if (CurrentUnit->RefTableIndex[prefix].used()) { Location tmp = { reduced_pos }; _this->SaveToRefTable(prefix, tmp); } } void CompactPrefixTable::SaveToRefTable(ulong prefix, Location loc) { uint start = CurrentUnit->RefTableIndex[prefix].m_TabIndex - 1; uint maxLength = CurrentUnit->RefTableIndex[prefix + 1].m_TabIndex - 1 - start; uint i = 0; while (CurrentUnit->RefTable[start + i].used() && i < maxLength) { i += 1; } if (CurrentUnit->RefTable[start + i].used()) { Log.Message( "Tried to insert kmer %d starting at position %d, number of slots %d. Position: %d", prefix, start, maxLength, i); throw; } else { CurrentUnit->RefTable[start + i] = loc; } } RefEntry const * CompactPrefixTable::GetRefEntry(ulong prefix, RefEntry * entries) const { if(prefix > (int) pow(4.0, (double) m_PrefixLength) + 1) { Log.Error("Wrong prefix!!"); } for (int i = 0; i < m_UnitCount; i++) { RefEntry* entry = &entries[i * 2]; uint cRefTableLen = m_Units[i].cRefTableLen; Location* RefTable = m_Units[i].RefTable; Index* RefTableIndex = m_Units[i].RefTableIndex; uint start = 0; uint maxLength = 0; if (RefTableIndex[prefix].used()) { start = RefTableIndex[prefix].m_TabIndex - 1; //TODO: Fix Invalid read of size 4 maxLength = RefTableIndex[prefix + 1].m_TabIndex - 1 - start; entry->ref = RefTable + start; entry->reverse = false; entry->weight = RefTableIndex[prefix].m_RevCompIndex; // entry->weight = 1.0f; entry->refCount = maxLength; entry->refTotal = maxLength; entry->offset = m_Units[i].Offset; } else { entry->weight = 0.0f; entry->refCount = 0; entry->refTotal = 0; entry->offset = m_Units[i].Offset; } ulong compRevPrefix = revComp(prefix); RefEntry * revEntry = &entries[i * 2 + 1]; if (RefTableIndex[compRevPrefix].used()) { start = RefTableIndex[compRevPrefix].m_TabIndex - 1; //TODO: Fix Invalid read of size 4 maxLength = RefTableIndex[compRevPrefix + 1].m_TabIndex - 1 - start; revEntry->ref = RefTable + start; revEntry->reverse = true; revEntry->weight = RefTableIndex[compRevPrefix].m_RevCompIndex; // revEntry->weight = 1.0f; revEntry->refCount = maxLength; entry->refTotal = revEntry->refTotal = entry->refTotal + maxLength; revEntry->offset = m_Units[i].Offset; } else { revEntry->weight = 0.0f; revEntry->refCount = 0; revEntry->refTotal = 0; revEntry->offset = m_Units[i].Offset; } } return entries; } void CompactPrefixTable::saveToFile(char const * fileName, uint const refIndexSize) { if (!Config.getSkipSave()) { Timer wtmr; wtmr.ST(); Log.Message("Writing reference index to %s", fileName); FILE *fp; if (!(fp = fopen(fileName, "wb"))) { Log.Warning("WARNING: Could not write reference index to disk: Error while opening file %s for writing. Please check file permissions.", fileName); } else { fwrite(&refTabCookie, sizeof(uint), 1, fp); fwrite(&m_PrefixLength, sizeof(uint), 1, fp); fwrite(&m_RefSkip, sizeof(uint), 1, fp); fwrite(&m_UnitCount, sizeof(uint), 1, fp); fwrite(&refIndexSize, sizeof(uint), 1, fp); for (int i = 0; i < m_UnitCount; ++i) { TableUnit& curr = m_Units[i]; fwrite(&curr.cRefTableLen, sizeof(uint), 1, fp); fwrite(curr.RefTableIndex, sizeof(Index), refIndexSize, fp); fwrite(curr.RefTable, sizeof(Location), curr.cRefTableLen, fp); fwrite(&curr.Offset, sizeof(uloc), 1, fp); } uint signature = refTabCookie+m_PrefixLength+m_RefSkip+m_UnitCount+refIndexSize; fwrite(&signature, sizeof(uint), 1, fp); fclose(fp); Log.Message("Writing to disk took %.2fs", wtmr.ET()); } } else { Log.Warning("Reference index not saved to disk! (--skip-save)"); } } bool CompactPrefixTable::readFromFile(char const * fileName) { if(!FileExists(fileName)) return false; Log.Message("Reading reference index from %s", fileName); Timer wtmr; wtmr.ST(); size_t read = 0; uint refIndexSize = 0; uint refTableSize = 0; uint prefixBasecount = 0; uint refskip = 0; uint cookie = 0; uint endCookie=0; FILE *fp; fp = fopen(fileName, "rb"); if (!fp) { Log.Error("Couldn't open file %s for reading.", fileName); } read = fread(&cookie, sizeof(uint), 1, fp); read = fread(&prefixBasecount, sizeof(uint), 1, fp); read = fread(&refskip, sizeof(uint), 1, fp); if (cookie != refTabCookie || prefixBasecount != m_PrefixLength || refskip != m_RefSkip) { fclose(fp); Log.Error("Invalid reference table found: %s. Please delete it and run NGM again.", fileName); } read = fread(&m_UnitCount, sizeof(uint), 1, fp ); read = fread(&refIndexSize, sizeof(uint), 1, fp); uint readSignature=0; uint signature=cookie+prefixBasecount+refskip+m_UnitCount+refIndexSize; //Check signature at end of file uloc pos = ftell(fp); fseek(fp,-sizeof(uint),SEEK_END); read = fread(&readSignature, sizeof(uint), 1, fp); fseek(fp,pos,SEEK_SET); if(readSignature != signature) { Log.Warning("Reference table corrupted, rebuilding..."); return false; } m_Units = new TableUnit[ m_UnitCount ]; for( int i = 0; i < m_UnitCount; ++ i ) { TableUnit& curr = m_Units[ i ]; read = fread(&curr.cRefTableLen, sizeof(uint), 1, fp); curr.RefTableIndex = new Index[refIndexSize + 1]; read = fread(curr.RefTableIndex, sizeof(Index), refIndexSize, fp); curr.RefTable = new Location[curr.cRefTableLen + 1]; read = fread(curr.RefTable, sizeof(Location), curr.cRefTableLen, fp); read = fread(&curr.Offset, sizeof(uloc), 1, fp); } fclose(fp); Log.Message("Reading from disk took %.2fs", wtmr.ET()); return true; } ngmlr-0.2.7+git20210816.a2a31fb/src/PrefixTable.h000066400000000000000000000071711410636150300205320ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef COMPACTPREFIXTABLE_H_ #define COMPACTPREFIXTABLE_H_ #include "IRefProvider.h" #include "Types.h" #include #include #pragma pack(push) #pragma pack(1) struct Index { uint m_TabIndex; char m_RevCompIndex; Index() { m_TabIndex = 0; m_RevCompIndex = 0; } bool used() { //return m_RevCompIndex; return m_RevCompIndex != 0; //return m_RevCompIndex & 0x80000000; } // void setUsed() { // //m_RevCompIndex = m_RevCompIndex | 0x80000000; // m_RevCompIndex = true; // } // void setRevCompIndex(uint prefix) { // if(used()) { // m_RevCompIndex = prefix; // setUsed(); // } else { // m_RevCompIndex = prefix; // } // } // // uint getRevCompIndex() { // return m_RevCompIndex & 0x7FFFFFFF; // } }; //Represents a single hashtable unit //For genomes < 4GB, we always only use one unit with no genomic offset //In order to support larger genomes (genomic kmer position can be > INT_MAX), //we create another hashtable unit, assign it an offset value, and store all the large //kmer positions there. struct TableUnit { TableUnit() : cRefTableLen(0), RefTable(0), RefTableIndex(0) { Offset = 0; } ~TableUnit() { delete[] RefTable; RefTable = 0; delete[] RefTableIndex; RefTableIndex = 0; } uint cRefTableLen; Location* RefTable; Index* RefTableIndex; uloc Offset; }; #pragma pack(pop) class CompactPrefixTable: public IRefProvider { public: CompactPrefixTable(bool const dualStrand = true, bool const skip = true); virtual ~CompactPrefixTable(); const RefEntry* GetRefEntry(ulong prefix, RefEntry* entry) const; uint GetRefEntryChainLength() const; static int maxPrefixFreq; private: //Biggest location value supported by a single table (precision of used location data type) //=> Determines: How many table units do we need? // Table units created: // Reference genome size divided by c_tableLocMax, offsets increasing every table by c_tableLocMax static uloc c_tableLocMax; //4294967296; //UINT_MAX //Table units array TableUnit* m_Units; uint m_UnitCount; //Static members used to direct generation of table units static TableUnit* CurrentUnit; /********************************************************************/ /*************Used only for building reference table*****************/ /********************************************************************/ //Used to control which kmers should be counted for index building, only locations //that will be in the unit should also be in the index static uloc kmerCountMinLocation; static uloc kmerCountMaxLocation; int m_CurGenSeq; static ulong lastPrefix; static loc lastBin; static loc lastPos; static uint skipCount; static uint skipBuild; uint m_RefSkip; uint m_PrefixLength; /********************************************************************/ //Config values bool DualStrand; bool skipRep; void Generate(); void CreateTable(const uint length); int* CountKmerFreq(const uint length); uint createRefTableIndex(const uint length); static void CountKmer(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); static void CountKmerwoSkip(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); static void BuildPrefixTable(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); static void BuildPrefixTablewoSkip(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); void SaveToRefTable(ulong prefix, Location loc); void Clear(); void saveToFile(const char* fileName, const uint refIndexSize); bool readFromFile(const char* fileName); void test(); }; #endif /* COMPACTPREFIXTABLE_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/ReadProvider.cpp000066400000000000000000000152621410636150300212460ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "ReadProvider.h" #include #include #include #include #include #include "IConfig.h" #include "Log.h" #include "Timing.h" #include "CS.h" #include "MappedRead.h" #include "FastxParser.h" //#include "BamParser.h" #include "SamParser.h" using NGMNames::ReadStatus; #undef module_name #define module_name "INPUT" ReadProvider::ReadProvider() : //bufferLength based on max read length of 1MB and read part length of readPartLength readPartLength(Config.getReadPartLength()), bufferLength(2000), parsedReads(0), /*readBuffer( new MappedRead *[bufferLength]),*/readsInBuffer(0), parser1(0) { } uint ReadProvider::init() { typedef void (*PrefixIterationFn)(ulong prefix, uloc pos, ulong mutateFrom, ulong mutateTo, void* data); char const * const fileName1 = Config.getQueryFile(); Log.Verbose("Initializing ReadProvider"); Log.Message("Opening query file %s", fileName1); size_t maxLen = readPartLength + 16; parser1 = DetermineParser(fileName1, maxLen); return 0; } ReadProvider::~ReadProvider() { if (parser1 != 0) { delete parser1; parser1 = 0; } } void ReadProvider::splitRead(MappedRead * read) { int splitNumber = read->length / readPartLength; // int splitNumber = read->length / (readPartLength / 2); int nameLength = strlen(read->name); ReadGroup * group = new ReadGroup(); group->fullRead = read; group->readId = read->ReadId; group->bestScoreSum = 0; group->fwdMapped = 0; group->reverseMapped = 0; group->readsFinished = 0; read->group = group; if (splitNumber == 0) { splitNumber = 1; group->readNumber = splitNumber; group->reads = new MappedRead *[splitNumber]; MappedRead * readPart = new MappedRead(read->ReadId + 1, readPartLength + 16); // readPart->name = new char[nameLength + 1]; strcpy(readPart->name, read->name); int length = read->length; readPart->length = length; if ((readPartLength + 16) <= length) { Log.Message("ERror ereroeroeroeor"); } readPart->Seq = new char[readPartLength + 16]; memset(readPart->Seq, '\0', readPartLength + 16); // memset(readPart->Seq, 'N', readPartLength); strncpy(readPart->Seq, read->Seq, length); //readPart->qlty = new char[readPartLength + 1]; //memset(readPart->qlty, '\0', readPartLength + 1); //strncpy(readPart->qlty, read->qlty + i * readPartLength, length); readPart->qlty = 0; readPart->group = group; group->reads[0] = readPart; } else { group->readNumber = splitNumber; group->reads = new MappedRead *[splitNumber]; memset(group->reads, 0, sizeof(MappedRead *) * splitNumber); for (int i = splitNumber - 1; i >= 0; --i) { MappedRead * readPart = new MappedRead(read->ReadId + i, readPartLength + 16); strcpy(readPart->name, read->name); int length = std::min(readPartLength, read->length - i * readPartLength); readPart->length = length; readPart->Seq = new char[readPartLength + 16]; memset(readPart->Seq, '\0', readPartLength + 16); strncpy(readPart->Seq, read->Seq + i * readPartLength, length); // strncpy(readPart->Seq, read->Seq + i * (readPartLength / 2), length); readPart->qlty = 0; readPart->group = group; readPart->group->reads[i] = readPart; } } } MappedRead * ReadProvider::NextRead(IParser * parser, int const id) { int l = 0; // if (readsInBuffer == 0 && ++parsedReads <= 20) { // if (readsInBuffer == 0) { try { static int const qryMaxLen = readPartLength + 16; MappedRead * read = new MappedRead(id, qryMaxLen); l = parser->parseRead(read); // Log.Message("Parsing next read: %s (%d)", read->name, read->length); if (l >= 0) { Log.Debug(2, "READ_%d\tINPUT\t%s", id, read->name); Log.Debug(16384, "READ_%d\tINPUT_DETAILS\t%s\t%s\t%s\t%s", id, read->Seq, read->qlty, read->AdditionalInfo); if(l > readPartLength) { splitRead(read); } else { read->group = 0; } NGM.AddReadRead(read->ReadId); NGM.Stats->readsInProcess += 1; return read; } else { Log.Debug(2, "READ_%d\tINPUT\t%s error while reading", id, read->name); if(l == -2) { Log.Error("Read %s: Length of read not equal length of quality values.", read->name); } else if (l != -1) { //TODO correct number when paired Log.Error("Unknown error while parsing read number %d (error code: %d)", id + 1, l); } } delete read; read = 0; } catch (char * ex) { Log.Error("%s", ex); } // } // if (readsInBuffer == 0) { return 0; // } else { //// Log.Message("Sending already paresed read %d", readBuffer[readsInBuffer - 1]->ReadId); // return readBuffer[readsInBuffer-- - 1]; // } } IParser * ReadProvider::DetermineParser(char const * fileName, int const qryMaxLen) { IParser * parser = 0; parser = new FastXParser(qryMaxLen); parser->init(fileName); // gzFile fp = gzopen(fileName, "r"); // if (fp == 0) { // //File does not exist // Log.Error("File %s does not exist!",fileName); // throw "File not found."; // } else { // char * buffer = new char[1000]; // while (gzgets(fp, buffer, 1000) > 0 && buffer[0] == '@') { // } // // int count = 0; // for (size_t i = 0; i < 1000 && buffer[i] != '\0' && buffer[i] != '\n'; // i++) { // if (buffer[i] == '\t') { // count++; // } // } // if (count >= 10) { // Log.Message("Input is SAM"); // parser = new SamParser(qryMaxLen); // } else { // if (strncmp(buffer, "BAM", 3) == 0) { //// Log.Message("Input is BAM"); //// parser= new BamParser(qryMaxLen); // Log.Error("BAM input is currently not supported!"); // } else { // if (buffer[0] == '>') { // Log.Message("Input is Fasta"); // } else { // Log.Message("Input is Fastq"); // } // parser = new FastXParser(qryMaxLen); // } // } // gzclose(fp); // delete[] buffer; // buffer = 0; // parser->init(fileName); // } return parser; } MappedRead * ReadProvider::GenerateSingleRead(int const readid) { MappedRead * read = 0; read = NextRead(parser1, readid); // return read; } // Sequential (important for pairs!) read generation bool ReadProvider::GenerateRead(int const readid1, MappedRead * & read1, int const readid2, MappedRead * & read2) { read1 = GenerateSingleRead(readid1); // Log.Message("Readseq: %s", read1->Seq); return read1 != 0; } void ReadProvider::DisposeRead(MappedRead * read) { // Log.Message("Disposing read %s", read->name); if (read->group != 0) { for (int j = 0; j < read->group->readNumber; ++j) { if (read->group->reads[j] != 0) { delete read->group->reads[j]; read->group->reads[j] = 0; } } delete[] read->group->reads; read->group->reads = 0; Log.Verbose("Deleting group"); delete read->group; read->group = 0; } // Single mode or no existing pair delete read; NGM.Stats->readsInProcess -= 1; } ngmlr-0.2.7+git20210816.a2a31fb/src/ReadProvider.h000066400000000000000000000015761410636150300207160ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef READPROVIDER_H_ #define READPROVIDER_H_ #include "IReadProvider.h" #include "IRefProvider.h" #include "IParser.h" #include "kseq.h" class ReadProvider: public IReadProvider { public: ReadProvider(); virtual ~ReadProvider(); virtual uint init(); virtual bool GenerateRead(int const readid1, MappedRead * & read1, int const readid2, MappedRead * & read2); virtual void DisposeRead(MappedRead * read); private: size_t const readPartLength; size_t const bufferLength; size_t parsedReads; // MappedRead * * readBuffer; size_t readsInBuffer; IParser * parser1; void splitRead(MappedRead * read); virtual MappedRead * NextRead(IParser * parser, int const id); MappedRead * GenerateSingleRead(int const readid); IParser * DetermineParser(char const * fileName, int const qryMaxLen); }; #endif /* READPROVIDER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/ReadStatus.h000066400000000000000000000004451410636150300204010ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __READSTATUS_H__ #define __READSTATUS_H__ namespace NGMNames { enum ReadStatus { Unknown = 0x000, NoSrcPair = 0x010, PairedFail = 0x020, Empty = 0x040, DeletionPending = 0x100 }; } #endif ngmlr-0.2.7+git20210816.a2a31fb/src/SAMWriter.cpp000066400000000000000000000265241410636150300205000ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "SAMWriter.h" #include #include #include #include #include #include "IConfig.h" #include "SequenceProvider.h" #include "NGM.h" #include "Version.h" //Format: http://samtools.sourceforge.net/SAM1.pdf static int const report_offset = 1; void SAMWriter::DoWriteProlog() { //TODO: check correct format char const * refName = 0; int refNameLength = 0; Print("@HD\tVN:1.0\tSO:unsorted\n"); for (int i = 0; i < SequenceProvider.GetRefCount(); ++i) { refName = SequenceProvider.GetRefName(i, refNameLength); Print("@SQ\tSN:%.*s\tLN:%llu\n", refNameLength, refName,SequenceProvider.GetRefLen(i)); ++i; m_Writer->Flush(bufferPosition, BUFFER_LIMIT, writeBuffer, false); } std::stringstream version; version << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUILD; Print("@PG\tID:ngmlr\tPN:nextgenmap-lr\tVN:%s\tCL:%s\n", version.str().c_str(), Config.getFullCommandLineCall()); if (rgId != 0) { Print("@RG\tID:%s", rgId); char const * rgSm = Config.getRgSm(); if(rgSm != 0) Print("\tSM:%s", rgSm); char const * rgLb = Config.getRgLb(); if(rgLb != 0) Print("\tLB:%s", rgLb); char const * rgPl = Config.getRgPl(); if(rgPl != 0) Print("\tPL:%s", rgPl); char const * rgDs = Config.getRgDs(); if(rgDs != 0) Print("\tDS:%s", rgDs); char const * rgDt = Config.getRgDt(); if(rgDt != 0) Print("\tDT:%s", rgDt); char const * rgPu = Config.getRgPu(); if(rgPu != 0) Print("\tPU:%s", rgPu); char const * rgPi = Config.getRgPi(); if(rgPi != 0) Print("\tPI:%s", rgPi); char const * rgPg = Config.getRgPg(); if(rgPg != 0) Print("\tPG:%s", rgPg); char const * rgCn = Config.getRgCn(); if(rgCn != 0) Print("\tCN:%s", rgCn); char const * rgFo = Config.getRgFo(); if(rgFo != 0) Print("\tFO:%s", rgFo); char const * rgKs = Config.getRgKs(); if(rgKs != 0) Print("\tKS:%s", rgKs); Print("\n"); } m_Writer->Flush(bufferPosition, BUFFER_LIMIT, writeBuffer, true); } void SAMWriter::DoWriteRead(MappedRead const * const read, int const scoreID) { DoWriteReadGeneric(read, scoreID, "*", -1, 0, read->mappingQlty); m_Writer->Flush(bufferPosition, BUFFER_LIMIT, writeBuffer); } void SAMWriter::DoWriteReadGeneric(MappedRead const * const read, int const scoreID, char const * pRefName, int const pLoc, int const pDist, int const mappingQlty, int flags) { NGM.AddWrittenRead(read->ReadId); static bool const hardClip = Config.getHardClip(); char const * readseq = read->Seq; char * readname = read->name; char * qltystr = read->qlty; //if (scoreID != 0) { if(!read->Alignments[scoreID].primary) { flags |= 0x800; } if (read->Scores[scoreID].Location.isReverse()) { readseq = read->RevSeq; if (qltystr != 0 && strlen(qltystr) > 0) { std::reverse(qltystr, &qltystr[read->length]); } flags |= 0x10; } int refnamelen = 0; char const * refname = SequenceProvider.GetRefName(read->Scores[scoreID].Location.getrefId(), refnamelen); //mandatory fields Print("%s\t", readname); Print("%d\t", flags); Print("%.*s\t", refnamelen, refname); Print("%u\t", read->Scores[scoreID].Location.m_Location + report_offset ); // Print("%d\t", mappingQlty); Print("%d\t", read->Alignments[scoreID].MQ); int printLongCigar = (Config.getBamCigarFix() && !read->Alignments[scoreID].skip && read->Alignments[scoreID].cigarOpCount >= 0x10000); if (printLongCigar) { // write S int clip_length = read->length; if (hardClip) clip_length = read->length - read->Alignments[scoreID].QStart - read->Alignments[scoreID].QEnd; Print("%dS\t", clip_length); } else { Print("%s\t", read->Alignments[scoreID].pBuffer1); } Print("%s\t", pRefName);//Ref. name of the mate/next fragment Print("%u\t", pLoc + report_offset);//Position of the mate/next fragment Print("%d\t", pDist);//observed Template LENgth if (hardClip) { Print("%.*s\t", read->length - read->Alignments[scoreID].QStart - read->Alignments[scoreID].QEnd, readseq + read->Alignments[scoreID].QStart); } else { Print("%.*s\t", read->length, readseq); } if (qltystr != 0) { if (hardClip) Print("%.*s\t", read->length - read->Alignments[scoreID].QStart - read->Alignments[scoreID].QEnd, qltystr + read->Alignments[scoreID].QStart); else Print("%.*s\t", read->length, qltystr); } else { Print("*\t"); } //Optional fields if(rgId != 0) { Print("RG:Z:%s\t", rgId); } Print("AS:i:%d\t", (int) read->Scores[scoreID].Score.f); Print("NM:i:%d\t", read->Alignments[scoreID].NM); float identity = round(read->Alignments[scoreID].Identity * 10000.0f) / 10000.0f; Print("XI:f:%g\t", identity); Print("XS:i:%d\t", (int) 0.0f); Print("XE:i:%d\t", (int) read->Scores[scoreID].Score.f); Print("XR:i:%d\t", read->length - read->Alignments[scoreID].QStart - read->Alignments[scoreID].QEnd); Print("MD:Z:%s\t", read->Alignments[scoreID].pBuffer2); if(read->Alignments[scoreID].svType > -1) { Print("SV:i:%d\t", read->Alignments[scoreID].svType); } if(read->Calculated > 1) { bool first = true; for(int i = 0; i < read->Calculated; ++i) { if(i != scoreID && !read->Alignments[i].skip) { int refnamelen = 0; char const * refname = SequenceProvider.GetRefName(read->Scores[i].Location.getrefId(), refnamelen); char strand = '+'; if (read->Scores[i].Location.isReverse()) { strand = '-'; } if(first) { Print("SA:Z:"); first = false; } Print("%.*s,%d,%c,%s,%d,%d;", refnamelen, refname, read->Scores[i].Location.m_Location + report_offset, strand, read->Alignments[i].pBuffer1, read->Alignments[i].MQ, read->Alignments[i].NM); } } if(!first) { Print("\t"); } } Print("QS:i:%d\t", read->Alignments[scoreID].QStart); Print("QE:i:%d\t", read->length - read->Alignments[scoreID].QEnd); int clipped = read->Alignments[scoreID].QStart + read->Alignments[scoreID].QEnd; float covered = (read->length - clipped) * 100.0f / read->length; Print("CV:f:%f", covered); if (printLongCigar) { // write the real CIGAR at the CG:B,I tag Print("\tCG:B:I"); char *p = read->Alignments[scoreID].pBuffer1; for (int i = 0; i < read->Alignments[scoreID].cigarOpCount; ++i) { long len = strtol(p, &p, 10); int op = 0; if (*p == 'M') op = 0; else if (*p == 'I') op = 1; else if (*p == 'D') op = 2; else if (*p == 'N') op = 3; else if (*p == 'S') op = 4; else if (*p == 'H') op = 5; else if (*p == '=') op = 7; else if (*p == 'X') op = 8; ++p; unsigned int cigar1 = (unsigned int)len<<4 | op; // this is the binary representation of a CIGAR operation Print(",%d", cigar1); } } Print("\n"); } void SAMWriter::DoWritePair(MappedRead const * const read1, int const scoreId1, MappedRead const * const read2, int const scoreId2) { //Proper pair int flags1 = 0x1; int flags2 = 0x1; if (read1->ReadId & 0x1) { //if read1 is the second pair flags1 |= 0x80; flags2 |= 0x40; } else { //if read1 is the first pair flags1 |= 0x40; flags2 |= 0x80; } if (!read1->hasCandidates() && !read2->hasCandidates()) { //Both mates unmapped DoWriteUnmappedRead(read2, flags2 | 0x8); DoWriteUnmappedRead(read1, flags1 | 0x8); } else if (!read1->hasCandidates()) { //First mate unmapped DoWriteReadGeneric(read2, scoreId2, "=", read2->Scores[scoreId2].Location.m_Location, 0, read2->mappingQlty, flags2 | 0x8); DoWriteUnmappedReadGeneric(read1, read2->Scores[scoreId2].Location.getrefId(), '=', read2->Scores[scoreId2].Location.m_Location, read2->Scores[scoreId2].Location.m_Location, 0, 0, flags1); } else if (!read2->hasCandidates()) { //Second mate unmapped DoWriteUnmappedReadGeneric(read2, read1->Scores[scoreId1].Location.getrefId(), '=', read1->Scores[scoreId1].Location.m_Location, read1->Scores[scoreId1].Location.m_Location, 0, 0, flags2); DoWriteReadGeneric(read1, scoreId1, "=", read1->Scores[scoreId1].Location.m_Location, 0, read1->mappingQlty, flags1 | 0x8); } else { if (!read1->HasFlag(NGMNames::PairedFail)) { //TODO: Check if correct! int distance = 0; flags1 |= 0x2; flags2 |= 0x2; if (!read1->Scores[scoreId1].Location.isReverse()) { distance = (read2->Scores[scoreId2].Location.m_Location + read2->length - read2->Alignments[scoreId2].QStart - read2->Alignments[scoreId2].QEnd) - read1->Scores[scoreId1].Location.m_Location; DoWriteReadGeneric(read2, scoreId2, "=", read1->Scores[scoreId1].Location.m_Location, distance * -1, read2->mappingQlty, flags2); DoWriteReadGeneric(read1, scoreId1, "=", read2->Scores[scoreId2].Location.m_Location, distance, read1->mappingQlty, flags1 | 0x20); } else if (!read2->Scores[scoreId2].Location.isReverse()) { distance = (read1->Scores[scoreId1].Location.m_Location + read1->length - read1->Alignments[scoreId1].QStart - read1->Alignments[scoreId1].QEnd) - read2->Scores[scoreId2].Location.m_Location; DoWriteReadGeneric(read2, scoreId2, "=", read1->Scores[scoreId1].Location.m_Location, distance, read2->mappingQlty, flags2 | 0x20); DoWriteReadGeneric(read1, scoreId1, "=", read2->Scores[scoreId2].Location.m_Location, distance * -1, read1->mappingQlty, flags1); } } else { int distance = 0; if (read1->Scores[scoreId1].Location.isReverse()) { flags2 |= 0x20; } if (read2->Scores[scoreId2].Location.isReverse()) { flags1 |= 0x20; } DoWriteReadGeneric(read2, scoreId2, SequenceProvider.GetRefName(read1->Scores[scoreId1].Location.getrefId(), distance), read1->Scores[scoreId1].Location.m_Location, 0, read2->mappingQlty, flags2); DoWriteReadGeneric(read1, scoreId1, SequenceProvider.GetRefName(read2->Scores[scoreId2].Location.getrefId(), distance), read2->Scores[scoreId2].Location.m_Location, 0, read1->mappingQlty, flags1); } } m_Writer->Flush(bufferPosition, BUFFER_LIMIT, writeBuffer); } void SAMWriter::DoWriteUnmappedReadGeneric(MappedRead const * const read, int const refId, char const pRefName, int const loc, int const pLoc, int const pDist, int const mappingQlty, int flags = 0) { //SRR002320.10000027.1 4 * 0 0 * * 0 0 TTTATGTTGTTAATGTGTTGGGTGAGTGCGCCCCAT IIIIIIIIIIIIIIIIIIIIIIIIII NGM.AddUnmappedRead(read, 0); if(writeUnmapped) { NGM.AddWrittenRead(read->ReadId); flags |= 0x4; char const * readseq = read->Seq; int readlen = read->length; char * readname = read->name; char * qltystr = read->qlty; int qltylen = readlen; //mandatory fields Print("%s\t", readname); Print("%d\t", flags); if (refId > -1) { int refnamelen = 0; char const * refname = SequenceProvider.GetRefName(refId, refnamelen); Print("%.*s\t", refnamelen, refname); } else { Print("*\t"); } Print("%d\t", loc + report_offset); Print("0\t"); Print("*\t"); Print("%c\t", pRefName); //Ref. name of the mate/next fragment Print("%d\t", pLoc + report_offset);//Position of the mate/next fragment Print("%d\t", pDist);//observed Template LENgth Print("%.*s\t", read->length, readseq); if (qltystr != 0) { Print("%.*s", qltylen, qltystr); } else { Print("*"); } if(rgId != 0) { Print("\tRG:Z:%s", rgId); } Print("\n"); } } void SAMWriter::DoWriteUnmappedRead(MappedRead const * const read, int flags) { DoWriteUnmappedReadGeneric(read, -1, '*', -1, -1, 0, 0, flags | 0x04); m_Writer->Flush(bufferPosition, BUFFER_LIMIT, writeBuffer); } void SAMWriter::DoWriteEpilog() { } ngmlr-0.2.7+git20210816.a2a31fb/src/SAMWriter.h000066400000000000000000000022621410636150300201360ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __CIGARWRITER_H__ #define __CIGARWRITER_H__ #include "GenericReadWriter.h" class SAMWriter: public GenericReadWriter { public: SAMWriter(FileWriter * writer) : GenericReadWriter() { rgId = Config.getRgId(); m_Writer = writer; } virtual ~SAMWriter() { m_Writer->Flush(bufferPosition, BUFFER_LIMIT, writeBuffer, true); } protected: virtual void DoWriteProlog(); virtual void DoWriteRead(MappedRead const * const read, int const scoreID); virtual void DoWritePair(MappedRead const * const read1, int const scoreId1, MappedRead const * const read2, int const scoreId2); virtual void DoWriteReadGeneric(MappedRead const * const read, int const scoreID, char const * pRefName, int const pLoc, int const pDist, int const mappingQlty, int flags = 0); virtual void DoWriteUnmappedReadGeneric(MappedRead const * const read, int const refId, char const pRefName, int const loc, int const pLoc, int const pDist, int const mappingQlty, int flags); virtual void DoWriteUnmappedRead(MappedRead const * const read, int flags = 0x4); virtual void DoWriteEpilog(); private: FileWriter * m_Writer; char const * rgId; }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/SamParser.cpp000066400000000000000000000144301410636150300205510ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "SamParser.h" #include #include #include "Log.h" void SamParser::init(char const * fileName) { fp = gzopen(fileName, "r"); if (!fp) { //File does not exist Log.Error("File does not exist ",fileName); } buffer = new char[buffer_size]; //parse_all = Config.Exists("parse_all") && Config.GetInt("parse_all") == 1; parse_all = true; if (!parse_all) { Log.Warning("Skipping all mapped reads in SAM file."); } tmp = kseq_init(fp); } static inline char * readField(char * lineBuffer, kstring_t & str) { while (*lineBuffer != '\t' && *lineBuffer != '\0' && *lineBuffer != '\n') { if (str.l + 1 > str.m) { str.m = str.l + 2; kroundup32(str.m); str.s = (char*) realloc(str.s, str.m); } str.s[str.l++] = *lineBuffer++; } str.s[str.l] = '\0'; return lineBuffer; } static inline char cpl(char c) { if (c == 'A') return 'T'; else if (c == 'T') return 'A'; else if (c == 'C') return 'G'; else if (c == 'G') return 'C'; else return c; } //// swaps two bases and complements them //static inline void rc(char & c1, char & c2) //{ // char x = c1; // c1 = cpl(c2); // c2 = cpl(x); //} void computeReverseSeq(char * Seq, int qryMaxLen) { char * RevSeq = new char[qryMaxLen + 1]; memset(RevSeq, 0, qryMaxLen + 1); memcpy(RevSeq, Seq, qryMaxLen); char * fwd = RevSeq; char * rev = Seq + qryMaxLen - 1; for (int i = 0; i < qryMaxLen; ++i) { *rev-- = cpl(*fwd++); } delete[] RevSeq; RevSeq = 0; } /* Return value: >=0 length of the sequence (normal) -1 end-of-file -2 truncated quality string */ int SamParser::doParseRead(MappedRead * read) { tmp->name.l = 0; tmp->seq.l = 0; tmp->qual.l = 0; while (gzgets(fp, buffer, buffer_size) != NULL) { char * lineBuffer = buffer; if (*lineBuffer != '@' && *lineBuffer != '\n') { //Name lineBuffer = readField(lineBuffer, tmp->name); if (*lineBuffer == '\0') return 0; //Skip one \t lineBuffer += 1; //Flags bool reverse = atoi(lineBuffer) & 0x10; int skip = 8; while (skip > 0 && *lineBuffer != '\0') { if (*lineBuffer++ == '\t') skip -= 1; } if (*lineBuffer == '\0') return 0; //Sequence lineBuffer = readField(lineBuffer, tmp->seq); if (reverse) { computeReverseSeq(tmp->seq.s, tmp->seq.l); } if (*lineBuffer == '\0') return 0; //Skip one \t lineBuffer += 1; //Quality lineBuffer = readField(lineBuffer, tmp->qual); if (reverse) { std::reverse(tmp->qual.s, &tmp->qual.s[strlen(tmp->qual.s)]); } if (tmp->qual.l == tmp->seq.l || (tmp->qual.l == 1 && tmp->qual.s[0] == '*')) { return copyToRead(read, tmp, tmp->seq.l); } else { //if (tmp->qual.l == 1 && tmp->qual.s[0] == '*') { // tmp->qual.l = 0; // return 0; //} else { return copyToRead(read, tmp, -2); //} } } } return -1; } ///* Return value: // >=0 length of the sequence (normal) // -1 end-of-file // -2 truncated quality string // */ //size_t SamParser::parseRead(kseq_t *& read) { // while (gzgets(fp, buffer, buffer_size) != NULL) { // read->name.s = &buffer[0]; //name // int count = 0; // int len = 0; // for (int i = 0; i < buffer_size && buffer[i] != '\0' && buffer[i] != '\n'; i++) { // if (count == 1 && buffer[i - 1] == '\t') { // std::string a; // a = buffer[i]; // read->name.l = i - 2; // read->name.m = i - 2; // if (!(atoi(&buffer[i]) & 0x4) && !parse_all) { // break; //TODO print line to output file // } // } // if (count == 9 && buffer[i - 1] == '\t') { // // read->seq.s = &buffer[i]; // } // if (count == 9 && buffer[i] != '\t') { // len++; // } // if (count == 10 && buffer[i - 1] == '\t') { //point to the qv values; // read->seq.l = len; // read->seq.m = len; // if (buffer[i] != '*') { // read->qual.s = &buffer[i]; // read->qual.l = len; // read->qual.m = len; // } else { // read->qual.l = 0; // read->qual.m = 0; // } // return len; // } // if (buffer[i] == '\t') { // count++; // } // } // } // return -1; //} //int SamParser::doParseRead(SAMRecord * read) { // // while (gzgets(fp, buffer, buffer_size) != NULL) { // char * lineBuffer = buffer; // // if (*lineBuffer != '@' && *lineBuffer != '\n') { // //Name // string name; // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // name += *lineBuffer; // lineBuffer++; // } // read->set_read_name(name); // name.clear(); // // //Skip one \t // lineBuffer ++; // // //Flags // read->set_mapped_flag(atoi(lineBuffer)); // } // // if(read->is_mapped()){ // //Skip the rest: // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // lineBuffer++; // } // //Skip one \t // lineBuffer ++; // string chr; // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // chr += *lineBuffer; // lineBuffer++; // } // read->set_chr(chr); // chr.clear(); // //Skip one \t // lineBuffer ++; // read->set_mapping_pos(atoi(lineBuffer)); // //Skip the rest: // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // lineBuffer++; // } // //Skip one \t // lineBuffer++; // read->set_mapping_quality(atoi(lineBuffer)); // //Skip the rest: // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // lineBuffer++; // } // //Skip one \t // lineBuffer ++; // string cigar; // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // cigar += *lineBuffer; // lineBuffer++; // } // read->set_CIGAR(cigar); // cigar.clear(); // // int skip = 4; // while (skip > 0 && *lineBuffer != '\0') { // if (*lineBuffer++ == '\t') // skip -= 1; // } // if (*lineBuffer == '\0') { // return 0; // } // string seq; // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // seq += *lineBuffer; // lineBuffer++; // } // read->set_sequence(seq); // seq.clear(); // //Skip one \t // lineBuffer ++; // string qual; // while (*lineBuffer != '\0' && *lineBuffer != '\t') { // qual += *lineBuffer; // lineBuffer++; // } // read->set_qualities(qual); // qual.clear(); // //Skip one \t // lineBuffer++; // string tags; // while (*lineBuffer != '\0') { // tags += *lineBuffer; // lineBuffer++; // } // read->set_tags(tags); // tags.clear(); // return read->get_sequence().size(); // } // } // return -1; //} ngmlr-0.2.7+git20210816.a2a31fb/src/SamParser.h000066400000000000000000000013351410636150300202160ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef SAMPARSER_H_ #define SAMPARSER_H_ #include "IParser.h" #include #include #include "kseq.h" int const buffer_size = 10000; class SamParser: public IParser { private: gzFile fp; bool parse_all; char *buffer; kseq_t * tmp; public: SamParser(int const p_qryMaxLen) : IParser(p_qryMaxLen) { fp = 0; parse_all = true; buffer = 0; tmp = 0; } virtual ~SamParser() { if (tmp != 0) { kseq_destroy(tmp); tmp = 0; } delete[] buffer; buffer = 0; gzclose(fp); } virtual void init(char const * fileName); virtual int doParseRead(MappedRead * read); // virtual int doParseRead(SAMRecord * read); }; #endif /* SAMPARSER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/ScoreBuffer.cpp000066400000000000000000000202751410636150300210650ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "ScoreBuffer.h" #include #include #include "NGMTask.h" #include "Timing.h" #include "CS.h" #include "AlignmentBuffer.h" #include "StrippedSW.h" float const MAX_MQ = 60.0f; struct PairScore { float score; int insertSize; int iRead; int iMate; }; bool sortLocationScore(LocationScore a, LocationScore b) { return a.Score.f > b.Score.f; } bool sortLocationScoreLocation(LocationScore a, LocationScore b) { return a.Location.m_Location < b.Location.m_Location; } int ScoreBuffer::computeMQ(float bestScore, float secondBestScore) { int mq = ceil(MAX_MQ * (bestScore - secondBestScore) / bestScore); return mq; } void ScoreBuffer::computeMQ(MappedRead* read) { //compute mapping quality int mq = MAX_MQ; if (read->numScores() > 1) { mq = computeMQ(read->Scores[0].Score.f, read->Scores[1].Score.f); } read->mappingQlty = mq; } void ScoreBuffer::debugScoresFinished(MappedRead * read) { Log.Debug(16, "READ_%d\tSCORES\tAll scores computed (%d)", read->ReadId, read->numScores()); if(read->numScores() > 0) { LocationScore * tmpScores = new LocationScore[read->numScores()]; memcpy(tmpScores, read->Scores, sizeof(LocationScore) * read->numScores()); //TODO: sort by location std::sort(tmpScores, tmpScores + read->numScores(), sortLocationScore); for(int i = 0; i < read->numScores(); ++i) { LocationScore score = tmpScores[i]; SequenceLocation loc = score.Location; SequenceProvider.convert(loc); int refNameLength = 0; Log.Debug(64, "READ_%d\tSCORES_RESULTS\tCMR_%d\t%f\t%llu\t%s", read->ReadId, i, score.Score.f, loc.m_Location, SequenceProvider.GetRefName(loc.getrefId(), refNameLength)); } delete[] tmpScores; tmpScores = 0; } } ReadGroup* ScoreBuffer::updateGroupInfo(MappedRead* cur_read) { ReadGroup* group = cur_read->group; if (group != 0) { //TODO: make atomic, parts from a group can end up in different threads! group->readsFinished += 1; // Log.Message("Scorecount for %s (%d): %d - %d", cur_read->name, cur_read->ReadId, cur_read->numScores(), cur_read->Calculated); if (cur_read->Scores[0].Location.isReverse()) { group->reverseMapped += 1; } else { group->fwdMapped += 1; } group->bestScoreSum += (int) (cur_read->Scores[0].Score.f); } return group; } void ScoreBuffer::DoRun() { if (iScores != 0) { Log.Debug(16, "INFO\tSCORES\tSubmitting %d score computations.", iScores); Timer tmr; tmr.ST(); //Prepare for score computation for (int i = 0; i < iScores; ++i) { MappedRead * cur_read = scores[i].read; int scoreId = scores[i].scoreId; //Initialize buffers for score computation SequenceLocation loc = cur_read->Scores[scoreId].Location; if (loc.isReverse()) { // RefId auf +-Strang setzen //--loc.m_RefId; cur_read->computeReverseSeq(); m_QryBuffer[i] = cur_read->RevSeq; } else { m_QryBuffer[i] = cur_read->Seq; } //decode reference sequence if (!SequenceProvider.DecodeRefSequence(const_cast(m_RefBuffer[i]), 0, loc.m_Location - (corridor >> 1), refMaxLen)) { // loc.m_Location - (corridor >> 1), cur_read->length + corridor)) { Log.Warning("Could not decode reference for alignment (read: %s): %llu, %d", loc.m_Location - (corridor >> 1), cur_read->length + corridor, cur_read->name); //Log.Warning("Read sequence: %s", cur_read->Seq); memset(const_cast(m_RefBuffer[i]), 'N', refMaxLen); } //Log.Message("Ref: %s\nSeq: %s\n", m_RefBuffer[i], m_QryBuffer[i]); m_ScoreBuffer[i] = -1; } //Compute scores int res = aligner->BatchScore(0, iScores, m_RefBuffer, m_QryBuffer, m_ScoreBuffer, 0); Log.Debug(16, "INFO\tSCORES\t%d scores computed (out of %d)", res, iScores); if (res != iScores) Log.Error("Kernel couldn't calculate all scores (%i out of %i)", res, iScores); //Process results for (int i = 0; i < iScores; ++i) { MappedRead * cur_read = scores[i].read; int scoreId = scores[i].scoreId; cur_read->Scores[scoreId].Score.f = m_ScoreBuffer[i]; //TODO_GENOMESIZE: Re-enable me //Log.Debug(1024, "READ_%d\tSCORES_DETAILS\tCMR_%d\t%f\t%.*s\t%s", cur_read->ReadId, scoreId, m_ScoreBuffer[i], refMaxLen, m_RefBuffer[i], m_QryBuffer[i]); if (++cur_read->Calculated == cur_read->numScores()) { //all scores computed for single end read assert(cur_read->hasCandidates()); #ifdef DEBUGLOG debugScoresFinished(cur_read); #endif topNSE(cur_read); ReadGroup* group = updateGroupInfo(cur_read); if(group != 0) { //If all reads from group are finished if(group->readsFinished == group->readNumber) { out->processLongReadLIS(group); // out->WriteRead(group->fullRead, false); } } else { out->processShortRead(cur_read); } } } scoreTime += tmr.ET(); } else { Log.Debug(16, "INFO\tSCORES\tEmpty buffer submitted."); } } void ScoreBuffer::topNSE(MappedRead* read) { //Sort scores std::sort(read->Scores, read->Scores + read->numScores(), sortLocationScore); int numScores = read->numScores(); if(numScores > 1) { float const minScore = read->Scores[0].Score.f * 0.75f; int i = 1; while(i < numScores && read->Scores[i].Score.f > minScore) { i += 1; } numScores = i; } //compute mapping quality computeMQ(read); //numScores alignments will be computed in the next step read->Calculated = numScores; } void ScoreBuffer::addRead(MappedRead * read, int count) { LocationScore * newScores = read->Scores; if (count == 0) { Log.Error("Internal error (count == 0). Please report this on https://github.com/Cibiv/NextGenMap/issues"); } //Adding scores to buffer. If buffer full, submit to CPU/GPU for score computation for (int i = 0; i < count; ++i) { Log.Debug(256, "READ_%d\tSCORES_BUFFER\tCMR_%d %f (location %llu) added to score buffer at position %d", read->ReadId, i, newScores[i].Score.f, newScores[i].Location.m_Location, iScores); scores[iScores].read = read; scores[iScores++].scoreId = i; if(iScores == swBatchSize) { DoRun(); iScores = 0; } } } void ScoreBuffer::scoreShortRead(MappedRead * read) { IAlignment * aligner = new StrippedSW(); static int const readPartLength = Config.getReadPartLength(); // Remove redundant candidates (CMRs in close proximity) LocationScore * tmpScore = new LocationScore[read->numScores()]; int tmpScoreIndex = 0; std::sort(read->Scores, read->Scores + read->numScores(), sortLocationScoreLocation); uloc lastLocation = 0; for (int i = 0; i < read->numScores(); ++i) { if(lastLocation - read->Scores[i].Location.m_Location > readPartLength) { tmpScore[tmpScoreIndex++] = read->Scores[i]; } lastLocation = read->Scores[i].Location.m_Location; } delete[] read->Scores; read->Scores = 0; read->AllocScores(tmpScore, tmpScoreIndex); delete[] tmpScore; tmpScore = 0; for (int i = 0; i < read->numScores(); ++i) { int corridor = read->length * 0.3 + 256; char * qrySeq = 0; char * refSeq = new char[read->length + corridor + 10]; memset(refSeq, '\0', read->length + corridor + 10); if (read->Scores[i].Location.isReverse()) { read->computeReverseSeq(); qrySeq = read->RevSeq; } else { qrySeq = read->Seq; } //decode reference sequence if (!SequenceProvider.DecodeRefSequence(refSeq, 0, read->Scores[i].Location.m_Location - (corridor >> 1), read->length + corridor)) { // loc.m_Location - (corridor >> 1), cur_read->length + corridor)) { // Log.Warning("Could not decode reference for alignment (read: %s): %llu, %d", loc.m_Location - (corridor >> 1), cur_read->length + corridor, cur_read->name); //Log.Warning("Read sequence: %s", cur_read->Seq); memset(refSeq, 'N', read->length + corridor); } float score = 0.0f; aligner->SingleScore(0, corridor, refSeq, qrySeq, score, 0); read->Scores[i].Score.f = score; delete[] refSeq; refSeq = 0; } std::sort(read->Scores, read->Scores + read->numScores(), sortLocationScore); // Log.Message("Read: %s", read->name); // for (int i = 0; i < read->numScores(); ++i) { // Log.Message("Score %d: %f", i, read->Scores[i].Score.f); // } computeMQ(read); out->processShortRead(read); delete aligner; } void ScoreBuffer::flush() { //Force submitting remaining computation from buffer to CPU/GPU DoRun(); iScores = 0; // out->flush(); } ngmlr-0.2.7+git20210816.a2a31fb/src/ScoreBuffer.h000066400000000000000000000040411410636150300205230ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef SWWOBUFFER_H_ #define SWWOBUFFER_H_ #include #include "IAlignment.h" #include "NGM.h" #include "AlignmentBuffer.h" #undef module_name #define module_name "FILTER" class ScoreBuffer { public: private: struct Score { MappedRead * read; int scoreId; }; private: void topNSE(MappedRead* read); void DoRun(); void computeMQ(MappedRead* read); int computeMQ(float bestScore, float secondBestScore); void debugScoresFinished(MappedRead * read); ReadGroup* updateGroupInfo(MappedRead* cur_read); const char** m_QryBuffer; const char** m_RefBuffer; float* m_ScoreBuffer; int qryMaxLen; uloc refMaxLen; int corridor; Score * scores; int iScores; IAlignment * aligner; AlignmentBuffer * out; const int swBatchSize; float scoreTime; public: ScoreBuffer(IAlignment * mAligner, AlignmentBuffer * mOut) : aligner(mAligner), out(mOut), swBatchSize(aligner->GetScoreBatchSize()) { m_QryBuffer = 0; m_RefBuffer = 0; m_ScoreBuffer = 0; corridor = Config.getReadPartCorridor(); m_QryBuffer = new char const *[swBatchSize]; m_RefBuffer = new char const *[swBatchSize]; m_ScoreBuffer = new float[swBatchSize]; qryMaxLen = Config.getReadPartLength() + 10; refMaxLen = ((qryMaxLen + corridor) | 1) + 1; for (int i = 0; i < swBatchSize; ++i) { m_RefBuffer[i] = new char[refMaxLen]; } scores = new Score[swBatchSize]; iScores = 0; scoreTime = 0.0f; } ~ScoreBuffer() { delete[] scores; scores = 0; delete[] m_ScoreBuffer; m_ScoreBuffer = 0; for (int i = 0; i < swBatchSize; ++i) { delete[] m_RefBuffer[i]; m_RefBuffer[i] = 0; } delete[] m_RefBuffer; m_RefBuffer = 0; delete[] m_QryBuffer; m_QryBuffer = 0; } void addRead(MappedRead * read, int count); void scoreShortRead(MappedRead * read); void flush(); float getTime() { float tmp = scoreTime; // scoreTime = 0.0f; return tmp; } inline int GetStage() const { return 2; } inline const char* GetName() const {return "SW";} }; #endif /* SWWOBUFFER_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/SequenceLocation.h000066400000000000000000000030731410636150300215630ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __SEQUENCELOCATION_H__ #define __SEQUENCELOCATION_H__ #include #include #include "Types.h" #include "IRefProvider.h" struct SequenceLocation { uloc m_Location; bool used() const { return m_Location != 0; } int getrefId() const { return m_RefId & 0x7FFFFFFF; } void setRefId(int const id) { //assert(id >= 0); m_RefId = id | (m_RefId & 0x80000000); } bool isReverse() const { //return m_Reverse; return m_RefId & 0x80000000; } void setReverse(bool const reverse) { if (reverse) { m_RefId |= 0x80000000; } else { m_RefId = getrefId(); } } bool operator<(SequenceLocation const & rhs) const { if (m_Location < rhs.m_Location) return true; else if (m_Location == rhs.m_Location) //m_RefId instead of getRefId. Strand is important. Equal positions on the same reference but not on the same strand are not equal. //To objects are deemed equal if !(a < b) && !(b < a): important for map in ReadProvider return (m_RefId < rhs.m_RefId); return false; } SequenceLocation() { m_Location = 0; m_RefId = 0; } SequenceLocation(uloc const loc, short const refid, bool const reverse) { m_Location = loc; setRefId(refid); setReverse(reverse); } SequenceLocation(Location const & other, uloc offset) { m_Location = other.m_Location + offset; setRefId(0); } private: //bool m_Reverse; //unsigned short m_RefId; unsigned int m_RefId; }; //#pragma pack(pop) #endif ngmlr-0.2.7+git20210816.a2a31fb/src/SequenceProvider.cpp000066400000000000000000000500541410636150300221410ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "SequenceProvider.h" #include #include #include #include #include #include #include #include #include #include "IConfig.h" #include "Log.h" #include "Timing.h" #include "kseq.h" KSEQ_INIT(gzFile, gzread) #undef module_name #define module_name "SEQPROV" _SequenceProvider * _SequenceProvider::pInstance = 0; _SequenceProvider & _SequenceProvider::Instance() { if (pInstance == 0) pInstance = new _SequenceProvider(); return *pInstance; } //static int const maxRefCount = 32768; static int const maxRefCount = 2147483647; static uint const refEncCookie = 0x74656; std::string CheckFile(std::string filename, char const * const name) { if (!FileExists(filename.c_str())) { Log.Error("%s file not found (%s)", name, filename.c_str()); } return filename; } //static inline char enc4(char c) { // c = toupper(c); // switch (c) { // case 'A': // return 0x1; // case 'T': // return 0x4; // case 'G': // return 0x7; // case 'C': // return 0x3; // } // return 0xE; //} // //static inline char dec4High(unsigned char c) { // c = (c >> 4) | 0x40; // if (c == 0x44) // c |= 0x10; // return c; //} // //static inline char dec4Low(unsigned char c) { // c = (c & 0xF) | 0x40; // if (c == 0x44) // c |= 0x10; // return c; //} static inline char enc4(char c) { c = toupper(c); switch (c) { case 'A': return 0; case 'T': return 1; case 'G': return 2; case 'C': return 3; } return 4; } static inline char dec4(char c) { switch (c) { case 0: return 'A'; case 1: return 'T'; case 2: return 'G'; case 3: return 'C'; case 4: return 'N'; } throw "Error in ref encoding!"; } static inline char dec4High(unsigned char c) { return dec4(c >> 4); } static inline char dec4Low(unsigned char c) { return dec4(c & 0xF); } _SequenceProvider::Chromosome _SequenceProvider::getChrBorders( loc start, loc stop) { if(start > stop) { loc tmp = start; start = stop; stop = tmp; } if(start < 1000) { start = 1001; stop = std::max(1002ll, stop); } // Log.Message("Detecting chromosome for: %lld %lld", start, stop); uloc * upperStart = std::upper_bound(refStartPos, refStartPos + (refCount / 2) + 1, start); if ((*upperStart - start) < 1000) { upperStart += 1; // Log.Message("Start in spacer"); } uloc * upperStop= std::upper_bound(refStartPos, refStartPos + (refCount / 2) + 1, stop); // if ((*upperStop - stop) < 1000) don't do anything. Probably still same chromosome // Log.Message("Upper: %llu - %llu", *upperStart, *upperStop); Chromosome chr; if(upperStart == upperStop) { chr.start = *(upperStart - 1); chr.end = *(upperStart) - 1000; // Log.Message("## Chr: %llu - %llu", chr.start, chr.end); } else { // throw "Could not determine chromosome for interval."; chr.start = 0; chr.end = 0; // Log.Message("## Chr1: %llu - %llu", *(upperStart - 1), *(upperStart) - 1000); // Log.Message("## Chr1: %llu - %llu", *(upperStop - 1), *(upperStop) - 1000); } return chr; } _SequenceProvider::Chromosome _SequenceProvider::getChrStart( uloc const position) { if (position < 1000) { Log.Verbose("Can't get starting position of chromosome (%llu).", position); // upper += 1; // Fatal(); } //Find the next larger chromosome start position in the concatenated reference for the mapping location uloc * upper = std::upper_bound(refStartPos, refStartPos + (refCount / 2) + 1, position); //Check whether the mapping position is in one of the spacer regions between the chromosomes if ((*upper - position) < 1000) { Log.Verbose("Can't get starting position of chromosome (%llu - %llu = %llu).", *upper, position, *upper - position); // Fatal(); upper += 1; } Chromosome chr; chr.start = *(upper - 1); chr.end = *(upper) - 1000; return chr; } bool _SequenceProvider::convert(SequenceLocation & m_Location) { //Convert position back to Chromosome+Position SequenceLocation loc = m_Location; //Find the next larger chromosome start position in the concatenated reference for the mapping location uloc * upper = std::upper_bound(refStartPos, refStartPos + (refCount / ((DualStrand) ? 2 : 1)) + 1, loc.m_Location); //Check whether the mapping position is in one of the spacer regions between the chromosomes if ((*upper - loc.m_Location) < 1000) { Log.Verbose("Read start position < chromosome start!"); Log.Verbose("Loc: %u (%d) < %u < %u (%d)", (uloc)*(upper-1), ((upper - 2) - refStartPos) * ((DualStrand) ? 2 : 1), loc.m_Location, (uint)*(upper), ((upper - 1) - refStartPos) * ((DualStrand) ? 2 : 1)); //Report read/position as unmapped (only happens for --end-to-end) return false; } //Compute actual start position loc.m_Location -= *(upper - 1); std::ptrdiff_t refId = ((upper - 1) - refStartPos) * ((DualStrand) ? 2 : 1); Log.Verbose("Location: %u - Upper: %u - Location: %d, RefId: %d ", m_Location.m_Location, *(upper - 1), loc.m_Location, refId); loc.setRefId(refId); m_Location = loc; return true; } int _SequenceProvider::readEncRefFromFile(char const * fileName, const uloc maxLen) { Log.Message("Reading encoded reference from %s", fileName); Timer wtmr; wtmr.ST(); uloc encRefSize = 0; uint refCount = 0; uint cookie = 0; FILE * fp = 0; fp = fopen(fileName, "rb"); size_t read = 0; read = fread(&cookie, sizeof(uint), 1, fp); read = fread(&refCount, sizeof(uint), 1, fp); read = fread(&binRefIndex, sizeof(uloc), 1, fp); read = fread(&encRefSize, sizeof(uloc), 1, fp); if (cookie != refEncCookie) { fclose(fp); Log.Error("Invalid encoded reference file found: %s. Please delete it and run NGM again.", fileName); } if(refCount > maxRefCount) { Log.Error("Currently NextGenMap can't handle more than %d reference sequences.", maxRefCount); } if((encRefSize * 2) > maxLen) { Log.Message("Size of reference is %llu Mbp.", encRefSize * 2 / 1000 / 1000); Log.Message("With a bin size of 2^%d NextGenMap can only handle a max. reference size of %llu Mbp", Config.getBinSize(), maxLen / 1000 / 1000); Log.Message("Please increase --bin-size"); Log.Error("Max genome size equals 4 GB * 2^bin_size. E.g. with bin size 4 it is 4 GB * 2^4 = 64 GB"); } binRefIdx = new RefIdx[refCount]; read = fread(binRefIdx, sizeof(RefIdx), refCount, fp); binRef = new char[encRefSize]; read = fread(binRef, sizeof(char), encRefSize, fp); fclose(fp); Log.Message("Reading %llu Mbp from disk took %.2fs", encRefSize * 2 / 1000 / 1000, wtmr.ET()); return refCount; } void _SequenceProvider::writeEncRefToFile(char const * fileName, uint const refCount, uloc const encRefSize) { if (!Config.getSkipSave()) { Timer wtmr; wtmr.ST(); Log.Message("Writing encoded reference to %s", fileName); FILE *fp; if (!(fp = fopen(fileName, "wb"))) { Log.Warning("WARNING: Could not write encoded reference file to disk: Unable to open output file %s. Please check file permissions.", fileName); } else { fwrite(&refEncCookie, sizeof(uint), 1, fp); fwrite(&refCount, sizeof(uint), 1, fp); fwrite(&binRefIndex, sizeof(uloc), 1, fp); fwrite(&encRefSize, sizeof(uloc), 1, fp); fwrite(binRefIdx, sizeof(RefIdx), refCount, fp); fwrite(binRef, sizeof(char), encRefSize, fp); fclose(fp); Log.Message("Writing to disk took %.2fs", wtmr.ET()); } } } uloc getSize(char const * const file) { gzFile gzfp; kseq_t *seq; gzfp = gzopen(Config.getReferenceFile(), "r"); seq = kseq_init(gzfp); int l = 0; //1000 -> padding at beginning uloc size = 1000; while ((l = kseq_read(seq)) >= 0) { //1000 -> 1000 x N padding int s = (seq->seq.l | 1) + 1; size += s + 1000; } kseq_destroy(seq); gzclose(gzfp); return size; } void _SequenceProvider::Init(bool dualstrand) { DualStrand = dualstrand; Log.Verbose("Init sequence provider."); refFileName = std::string(Config.getReferenceFile()) + std::string("-enc.2.ngm"); //uint64 used everywhere but in CS rTable, there GetBin division increases range const uloc REF_LEN_MAX = UINT_MAX * std::max(1.0, pow(2.0, Config.getBinSize())); if (FileExists(refFileName.c_str())) { //Read refCount = readEncRefFromFile(refFileName.c_str(), REF_LEN_MAX); } else { Log.Message("Encoding reference sequence."); std::map binRefMap; uloc size = getSize(Config.getReferenceFile()); Log.Message("Size of reference genome %llu Mbp (max. %llu Mbp)", size / 1000 / 1000, REF_LEN_MAX / 1000 / 1000); //Theoretical limit would be uloc max (INT64_MAX), but for speed reasons uint is used in CSTableEntry for bin //positions if (size > REF_LEN_MAX) { Log.Message("With a bin size of 2^%d NextGenMap can only handle a max. reference size of %llu Mbp", Config.getBinSize(), REF_LEN_MAX / 1000 / 1000); Log.Message("Please increase --bin-size to handle larger genomes."); Log.Error("Max genome size equals 4 GB * 2^bin_size. E.g. with bin size 4 it is 4 GB * 2^4 = 64 GB"); } uloc const binRefSize = ((size / 2) | 1) + 1; Log.Verbose("Allocating %llu (%llu) bytes for the reference.", binRefSize, FileSize(Config.getReferenceFile())); binRef = new char[binRefSize]; gzFile gzfp; kseq_t *seq; gzfp = gzopen(Config.getReferenceFile(), "r"); seq = kseq_init(gzfp); Timer tt; tt.ST(); int l = 0; int j = 0; char const spacer = 'N'; //Padding to avoid negative mapping positions for (int i = 0; i < 500; ++i) { char c = enc4(spacer) << 4; c |= enc4(spacer); binRef[binRefIndex++] = c; } int skipped = 0; while ((l = kseq_read(seq)) >= 0) { if(j >= maxRefCount) { Log.Error("Currently NextGenMap can't handle more than %d reference sequences.", maxRefCount); } if(seq->seq.l > minRefSeqLen) { binRefMap[j].SeqStart = binRefIndex * 2; binRefMap[j].SeqLen = seq->seq.l; binRefMap[j].SeqId = j; Log.Verbose("Ref %d: %s (%d), Index: %d", j, seq->name.s, seq->seq.l, binRefIndex); int nameLength = std::min((size_t) maxRefNameLength, seq->name.l); strncpy(binRefMap[j].name, seq->name.s, nameLength); binRefMap[j].NameLen = nameLength; j += 1; char * ref = seq->seq.s; for (size_t i = 0; i < seq->seq.l / 2 * 2; i += 2) { char c = enc4(ref[i]) << 4; c |= enc4(ref[i + 1]); binRef[binRefIndex++] = c; } if (seq->seq.l & 1) { char c = enc4(ref[seq->seq.l - 1]) << 4; c |= enc4(spacer); binRef[binRefIndex++] = c; } for (int i = 0; i < 500; ++i) { //N char c = enc4(spacer) << 4; c |= enc4(spacer); binRef[binRefIndex++] = c; } } else { Log.Verbose("Reference sequence %s too short (%d). Skipping.", seq->name.s, seq->seq.l); skipped += 1; } } refCount = j; Log.Verbose("BinRef length: %ull (elapsed %f)", binRefIndex, tt.ET()); Log.Message("%d reference sequences were skipped (length < %d).", skipped, minRefSeqLen); kseq_destroy(seq); gzclose(gzfp); binRefIndex = binRefIndex * 2; if (binRefMap.size() != (size_t) refCount) { Log.Error("Error while building ref index."); } binRefIdx = new RefIdx[refCount]; for (int i = 0; i < refCount; ++i) { if (binRefMap.find(i) != binRefMap.end()) { binRefIdx[i] = binRefMap[i]; // binRefIdx[i].SeqStart = 0; //binRefIdx[i].SeqLen = 2 * binRefIndex - 1; } else { Log.Error("Error while building ref index."); } } writeEncRefToFile(refFileName.c_str(), (uint) refCount, binRefSize); } if (DualStrand) refCount *= 2; #ifdef VERBOSE for (int i = 0; i < refCount; ++i) { int len = 0; char const * test = GetRefName(i, len); Log.Message("%d: Ref: %.*s, Length: %d",i, len, test, (int)GetRefLen(i)); } #endif int refCount = SequenceProvider.GetRefCount(); refStartPos = new uloc[refCount / ((DualStrand) ? 2 : 1) + 1]; int i = 0; int j = 0; while (i < refCount) { refStartPos[j++] = SequenceProvider.GetRefStart(i); i += (DualStrand) ? 2 : 1; } //Add artificial start position as upper bound for all all reads that map to the last chromosome refStartPos[j] = refStartPos[j - 1] + SequenceProvider.GetRefLen(refCount - 1) + 1000; // //Test decode // char * sequence = new char[10000]; // int corridor = 12; // int decodeLenght = 100; // // DecodeRefSequenceExact(sequence, 2000, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // DecodeRefSequenceExact(sequence, 2001, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // decodeLenght = 101; // DecodeRefSequenceExact(sequence, 2000, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // DecodeRefSequenceExact(sequence, 2001, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // DecodeRefSequenceExact(sequence, 1000, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // corridor = 24; // DecodeRefSequenceExact(sequence, 1000, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // corridor = 10000; // DecodeRefSequenceExact(sequence, 4642603, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // corridor = 10000; // DecodeRefSequenceExact(sequence, 1000, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // corridor = 10000; // DecodeRefSequenceExact(sequence, 1502, decodeLenght + corridor + 1, // corridor); // Log.Message("Decoded sequence: %s", sequence); // // exit(0); } uloc _SequenceProvider::decode(uloc startPosition, uloc endPosition, char * const sequence) { Log.Verbose("DEBUG - Start: %llu, End: %llu", startPosition, endPosition); uint codedIndex = 0; //Position in encoded ref sequence (2 bases per byte) uloc start = (startPosition + 1) / 2;//TODO: Check if equiv to ceil(offset / 2.0); size_t decodeLength = (endPosition - startPosition + 1) / 2; if (startPosition & 1) { sequence[codedIndex++] = dec4Low(binRef[start - 1]); } for (uloc i = 0; i < decodeLength; ++i) { sequence[codedIndex++] = dec4High(binRef[start + i]); sequence[codedIndex++] = dec4Low(binRef[start + i]); } return codedIndex; } //TODO: remove unnecessary variables bool _SequenceProvider::DecodeRefSequenceExact(char * const sequence, uloc startPosition, uloc sequenceLength, int corridor) { if (startPosition >= GetConcatRefLen()) { Log.Verbose("Invalid reference location. Offset: %d", startPosition); return false; } memset(sequence, 'x', sequenceLength); int halfCorridor = corridor / 2; Chromosome chr = getChrStart(startPosition); //Log.Message("DEBUG - Chr: %llu - %llu", chr.start, chr.end); //First position of the requested sequence (incl corridor) uloc decodeStartPosition = startPosition - halfCorridor; //Last position of the requested sequence (incl corridor) uloc endPosition = startPosition + sequenceLength - halfCorridor; uloc decodeEndPosition = endPosition; //Requested sequence is longer than the chromosome if(endPosition > chr.end) { Log.Verbose("Correcting end position"); uloc diff = endPosition - chr.end; //Set end position to last bp of chromosome decodeEndPosition -= diff; } if(halfCorridor > startPosition) { Log.Verbose("DecodeStartPosition < 0"); //DecodeStartPosition < 0 decodeStartPosition = chr.start; uloc diff = halfCorridor - decodeStartPosition + 1000 - (startPosition - chr.start); //Log.Message("Start diff: %llu", diff); decode(decodeStartPosition, decodeEndPosition, sequence + diff); } else if(decodeStartPosition < chr.start) { if(decodeEndPosition > chr.start) { Log.Verbose("Decoding startposition is in one of the spacer regions"); //Decoding startposition is in one of the spacer regions //Start decoding at chrStartPos, everything before stays N uloc diff = chr.start - decodeStartPosition; //Log.Message("Start diff: %llu", diff); decodeStartPosition += diff; decode(decodeStartPosition, decodeEndPosition, sequence + diff); } else { Log.Verbose("Full interval is in spacer region!"); } } else { Log.Verbose("Full decode!"); SequenceLocation start; start.m_Location = decodeStartPosition; SequenceLocation end; end.m_Location = decodeEndPosition; convert(start); convert(end); int len = 0; Log.Verbose("Decoding: %s:%llu-%llu", GetRefName(start.getrefId(), len), start.m_Location, end.m_Location); //Decode full sequence uloc decodedBp = decode(decodeStartPosition, decodeEndPosition, sequence); Log.Verbose("copied %llu to %llu", decodedBp, sequenceLength); } sequence[sequenceLength - 1] = '\0'; return true; } bool _SequenceProvider::DecodeRefSequence(char * const sequence, int refId, uloc position, uloc bufferLength) { uloc len = bufferLength - 2; if (DualStrand) { refId >>= 1; } // Log.Message("%u %u %u", position, bufferLength, binRefIdx[refId].SeqLen); //if (position >= binRefIdx[refId].SeqLen || position < 0) { if (position >= GetConcatRefLen()) { Log.Verbose("Invalid reference location. Offset: %d", position); return false; } // int nCount = 0; // if (position < 0) { // nCount = abs(position); // len -= nCount; // position = 0; // } uloc end = 0; if ((position + len) > GetConcatRefLen()) { end = (position + len) - GetConcatRefLen(); len -= end; } // uint end = std::min((uint)0, binRefIdx[refId].SeqLen - (position + len)); // if (end < 0) { // end = abs(end); // len -= end; // } // int start = binRefIdx[n].SeqStart + ceil(position / 2.0); uloc start = (position + 1) / 2; //TODO: Check if equiv to ceil(position / 2.0); uint codedIndex = 0; // for (int i = 0; i < nCount; ++i) { // sequence[codedIndex++] = 'x'; // } if (position & 1) { sequence[codedIndex++] = dec4Low(binRef[start - 1]); } for (uloc i = 0; i < (len + 1) / 2; ++i) { sequence[codedIndex++] = dec4High(binRef[start + i]); sequence[codedIndex++] = dec4Low(binRef[start + i]); } if (len & 1) { sequence[codedIndex - 1] = 'x'; } for (uloc i = 0; i < end; ++i) { sequence[codedIndex++] = 'x'; } if (codedIndex > bufferLength) { Log.Message("nCount: %d, position: %d, len: %d (%d), seqlen: %d, end: %d, start: %d, index: %d", 0, position, bufferLength, (len+1)/2, binRefIdx[refId].SeqLen, end, start, codedIndex); Log.Error("%.*s", bufferLength, sequence); } for (uint i = codedIndex; i < bufferLength; ++i) { sequence[i] = '\0'; } return true; } char const * _SequenceProvider::GetRefName(int n, int & len) const { if (CheckRefNr(n)) { if (DualStrand) n >>= 1; len = binRefIdx[n].NameLen; return binRefIdx[n].name; } return 0; } uloc _SequenceProvider::GetConcatRefLen() const { return binRefIndex - 1; } uloc _SequenceProvider::GetRefLen(int n) const { if (CheckRefNr(n)) { if (DualStrand) n >>= 1; return binRefIdx[n].SeqLen; } else { return 0; } } uloc _SequenceProvider::GetRefStart(int n) const { if (CheckRefNr(n)) { if (DualStrand) n >>= 1; return binRefIdx[n].SeqStart; } else { return 0; } } int _SequenceProvider::GetRefCount() const { return refCount; } bool _SequenceProvider::CheckRefNr(int n) const { if (n >= refCount || n < 0) { Log.Error("Tried to access invalid reference sequence (%i %x).", n, n); return false; } return true; } _SequenceProvider::_SequenceProvider() : binRef(0), refStartPos(0), refCount(0) { binRefIndex = 0; binRefSize = 0; binRefIdx = 0; DualStrand = true; } _SequenceProvider::~_SequenceProvider() { delete[] binRef; binRef = 0; delete[] refStartPos; refStartPos = 0; if (binRefIdx != 0) { delete[] binRefIdx; binRefIdx = 0; } } void _SequenceProvider::Cleanup() { delete pInstance; } void _SequenceProvider::PagingUpdate() { //TODO: remove } ngmlr-0.2.7+git20210816.a2a31fb/src/SequenceProvider.h000066400000000000000000000037211410636150300216050ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __SEQUENCEPROVIDER_H__ #define __SEQUENCEPROVIDER_H__ #include #include #include "Types.h" #include "NGMThreads.h" #include "SequenceLocation.h" #include "MappedRead.h" class _SequenceProvider { public: static _SequenceProvider & Instance(); static void Cleanup(); virtual void Init(bool dualstrand = true); struct Chromosome { uloc start; uloc end; }; bool DecodeRefSequenceExact(char * const buffer, uloc offset, uloc bufferLength, int corridor); bool DecodeRefSequence(char* const buffer, int n, uloc offset, uloc len); // Gets the length of read/reference string n virtual uloc GetRefLen(int n) const; virtual uloc GetConcatRefLen() const; virtual int GetRefCount() const; const virtual char* GetRefName(int n, int& len) const; virtual uloc GetRefStart(int n) const; virtual void PagingUpdate(); static const int maxRefNameLength = 100; bool convert(SequenceLocation & m_Location); Chromosome getChrBorders(loc start, loc stop); Chromosome getChrStart(uloc const position); private: _SequenceProvider(); ~_SequenceProvider(); bool CheckQryNr(int n) const; bool CheckRefNr(int n) const; bool DualStrand; static _SequenceProvider* pInstance; struct RefIdx { uint SeqId; uint Flags; uloc SeqStart; uint SeqLen; uint NameLen; char name[maxRefNameLength]; }; RefIdx * binRefIdx; char* binRef; uloc binRefIndex; // Files std::string refFileName; std::string refBaseFileName; uloc binRefSize; int refCount; uloc * refStartPos; static const int minRefSeqLen = 10; void writeEncRefToFile(char const * fileName, uint const refCount, uloc const encRefSize); int readEncRefFromFile(char const * fileName, const uloc maxLen); uloc decode(uloc startPosition, uloc endPosition, char* const sequence); }; #define SequenceProvider _SequenceProvider::Instance() #endif ngmlr-0.2.7+git20210816.a2a31fb/src/StrippedSW.cpp000066400000000000000000000237031410636150300207230ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "StrippedSW.h" #include #include #include #include "ssw.h" // Print the BLAST like output. static void ssw_write(const s_align* a, const char* ref_seq, const char* read_seq, const int8_t* table) { fprintf(stdout, "optimal_alignment_score: %d\tsub-optimal_alignment_score: %d\t", a->score1, a->score2); if (a->ref_begin1 + 1) fprintf(stdout, "target_begin: %d\t", a->ref_begin1 + 1); fprintf(stdout, "target_end: %d\t", a->ref_end1 + 1); if (a->read_begin1 + 1) fprintf(stdout, "query_begin: %d\t", a->read_begin1 + 1); fprintf(stdout, "query_end: %d\n\n", a->read_end1 + 1); if (a->cigar) { int32_t c = 0, left = 0, e = 0, qb = a->ref_begin1, pb = a->read_begin1; uint32_t i; while (e < a->cigarLen || left > 0) { int32_t count = 0; int32_t q = qb; int32_t p = pb; fprintf(stdout, "Target: %8d ", q + 1); for (c = e; c < a->cigarLen; ++c) { char letter = cigar_int_to_op(a->cigar[c]); uint32_t length = cigar_int_to_len(a->cigar[c]); uint32_t l = (count == 0 && left > 0) ? left : length; for (i = 0; i < l; ++i) { if (letter == 'I') fprintf(stdout, "-"); else { fprintf(stdout, "%c", *(ref_seq + q)); ++q; } ++count; if (count == 60) goto step2; } } step2: fprintf(stdout, " %d\n ", q); q = qb; count = 0; for (c = e; c < a->cigarLen; ++c) { char letter = cigar_int_to_op(a->cigar[c]); uint32_t length = cigar_int_to_len(a->cigar[c]); uint32_t l = (count == 0 && left > 0) ? left : length; for (i = 0; i < l; ++i) { if (letter == 'M') { if (table[(int) *(ref_seq + q)] == table[(int) *(read_seq + p)]) fprintf(stdout, "|"); else fprintf(stdout, "*"); ++q; ++p; } else { fprintf(stdout, "*"); if (letter == 'I') ++p; else ++q; } ++count; if (count == 60) { qb = q; goto step3; } } } step3: p = pb; fprintf(stdout, "\nQuery: %8d ", p + 1); count = 0; for (c = e; c < a->cigarLen; ++c) { char letter = cigar_int_to_op(a->cigar[c]); uint32_t length = cigar_int_to_len(a->cigar[c]); uint32_t l = (count == 0 && left > 0) ? left : length; for (i = 0; i < l; ++i) { if (letter == 'D') fprintf(stdout, "-"); else { fprintf(stdout, "%c", *(read_seq + p)); ++p; } ++count; if (count == 60) { pb = p; left = l - i - 1; e = (left == 0) ? (c + 1) : c; goto end; } } } e = c; left = 0; end: fprintf(stdout, " %d\n\n", p); } } } /* This table is used to transform nucleotide letters into numbers. */ static const int8_t nt_table[128] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 1, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; int StrippedSW::BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData) { for (int i = 0; i < batchSize; ++i) { char const * const ref_seq = refSeqList[i]; char const * const read_seq = qrySeqList[i]; //Log.Message("Ref: %s", ref_seq); //Log.Message("Read: %s", read_seq); int read_len = strlen(read_seq) + 1; int ref_len = strlen(ref_seq) + 1; if (read_len >= maxSeqLen || ref_len >= maxSeqLen) { results[i] = -1.0f; } else { s_profile* profile; s_align* result; for (int32_t m = 0; m < read_len; ++m) num[m] = nt_table[(int) read_seq[m]]; num[read_len] = nt_table[(int) '\0']; profile = ssw_init(num, read_len, mat, 5, 1); for (int32_t m = 0; m < ref_len; ++m) ref_num[m] = nt_table[(int) ref_seq[m]]; ref_num[ref_len] = nt_table[(int) '\0']; // Only the 8 bit of the flag is setted. ssw_align will always return the best alignment beginning position and cigar. result = ssw_align(profile, ref_num, ref_len, gap_open, gap_extension, 0, 0, 0, 0); //ssw_write(result, ref_seq, read_seq, nt_table); //fprintf(stderr, "%d\n", result->score1); results[i] = result->score1; align_destroy(result); init_destroy(profile); } } return batchSize; } int StrippedSW::SingleScore(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, float & resultScore, void * extData) { char const * const ref_seq = refSeq; char const * const read_seq = qrySeq; //Log.Message("Ref: %s", ref_seq); //Log.Message("Read: %s", read_seq); int read_len = strlen(read_seq) + 1; int ref_len = strlen(ref_seq) + 1; if(read_len >= maxSeqLen || ref_len >= maxSeqLen) { resultScore = -1.0f; return 0; } s_profile* profile; s_align * result; for (int32_t m = 0; m < read_len; ++m) num[m] = nt_table[(int) read_seq[m]]; num[read_len] = nt_table[(int) '\0']; profile = ssw_init(num, read_len, mat, 5, 1); for (int32_t m = 0; m < ref_len; ++m) ref_num[m] = nt_table[(int) ref_seq[m]]; ref_num[ref_len] = nt_table[(int) '\0']; // Only the 8 bit of the flag is setted. ssw_align will always return the best alignment beginning position and cigar. result = ssw_align(profile, ref_num, ref_len, gap_open, gap_extension, 0, 0, 0, 0); //ssw_write(result, ref_seq, read_seq, nt_table); //fprintf(stderr, "%d\n", result->score1); resultScore = result->score1; align_destroy(result); init_destroy(profile); return 1; } int StrippedSW::SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & results, void * extData) { char const * const ref_seq = refSeq; char const * const read_seq = qrySeq; Log.Message("Aligning with StrippedSW"); // Log.Message("Ref: %s", ref_seq); // Log.Message("Read: %s", read_seq); int read_len = strlen(read_seq) + 1; int ref_len = strlen(ref_seq) + 1; s_profile* profile; s_align * result; for (int32_t m = 0; m < read_len; ++m) num[m] = nt_table[(int) read_seq[m]]; num[read_len] = nt_table[(int) '\0']; profile = ssw_init(num, read_len, mat, 5, 1); for (int32_t m = 0; m < ref_len; ++m) ref_num[m] = nt_table[(int) ref_seq[m]]; ref_num[ref_len] = nt_table[(int) '\0']; // Only the 8 bit of the flag is setted. ssw_align will always return the best alignment beginning position and cigar. result = ssw_align(profile, ref_num, ref_len, gap_open, gap_extension, 1, 0, 0, 0); //ssw_write(result, ref_seq, read_seq, nt_table); //Log.Message("%d", result->score1); Align & align = results; char * outcigar = align.pBuffer1; read_len -= 1; int sum = 0; align.QStart = result->read_begin1; sum += align.QStart; if (align.QStart > 0) { outcigar += sprintf(outcigar, "%d%c", align.QStart, 'S'); } for (int i = 0; i < result->cigarLen; ++i) { if (cigar_int_to_op(result->cigar[i]) != 'D') { sum += cigar_int_to_len(result->cigar[i]); } outcigar += sprintf(outcigar, "%d%c", cigar_int_to_len(result->cigar[i]), cigar_int_to_op(result->cigar[i])); } align.QEnd = (read_len - result->read_end1 - 1); sum += align.QEnd; if (align.QEnd > 0) { outcigar += sprintf(outcigar, "%d%c", align.QEnd, 'S'); } *outcigar = '\0'; if (sum != read_len) { fprintf(stderr, "%d == %d -- %d %d %d\n", sum, read_len, align.QStart, align.QEnd, read_len); ssw_write(result, ref_seq, read_seq, nt_table); fprintf(stderr, "%s\n", align.pBuffer1); } //results[i] = result->score1; align.PositionOffset = result->ref_begin1; align.Identity = 1.0f; align.NM = 0; align_destroy(result); init_destroy(profile); return 1; } int StrippedSW::BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData) { for (int i = 0; i < batchSize; ++i) { char const * const ref_seq = refSeqList[i]; char const * const read_seq = qrySeqList[i]; //Log.Message("Ref: %s", ref_seq); //Log.Message("Read: %s", read_seq); int read_len = strlen(read_seq) + 1; int ref_len = strlen(ref_seq) + 1; s_profile* profile; s_align* result; for (int32_t m = 0; m < read_len; ++m) num[m] = nt_table[(int) read_seq[m]]; num[read_len] = nt_table[(int) '\0']; profile = ssw_init(num, read_len, mat, 5, 1); for (int32_t m = 0; m < ref_len; ++m) ref_num[m] = nt_table[(int) ref_seq[m]]; ref_num[ref_len] = nt_table[(int) '\0']; // Only the 8 bit of the flag is setted. ssw_align will always return the best alignment beginning position and cigar. result = ssw_align(profile, ref_num, ref_len, gap_open, gap_extension, 1, 0, 0, 0); //ssw_write(result, ref_seq, read_seq, nt_table); //Log.Message("%d", result->score1); Align & align = results[i]; char * outcigar = align.pBuffer1; read_len -= 1; int sum = 0; align.QStart = result->read_begin1; sum += align.QStart; if (align.QStart > 0) { outcigar += sprintf(outcigar, "%d%c", align.QStart, 'S'); } for (int i = 0; i < result->cigarLen; ++i) { if (cigar_int_to_op(result->cigar[i]) != 'D') { sum += cigar_int_to_len(result->cigar[i]); } outcigar += sprintf(outcigar, "%d%c", cigar_int_to_len(result->cigar[i]), cigar_int_to_op(result->cigar[i])); } align.QEnd = (read_len - result->read_end1 - 1); sum += align.QEnd; if (align.QEnd > 0) { outcigar += sprintf(outcigar, "%d%c", align.QEnd, 'S'); } *outcigar = '\0'; if (sum != read_len) { fprintf(stderr, "%d == %d -- %d %d %d\n", sum, read_len, align.QStart, align.QEnd, read_len); ssw_write(result, ref_seq, read_seq, nt_table); fprintf(stderr, "%s\n", align.pBuffer1); } //results[i] = result->score1; align.PositionOffset = result->ref_begin1; align.Identity = 1.0f; align.NM = 0; align_destroy(result); init_destroy(profile); } return batchSize; } ngmlr-0.2.7+git20210816.a2a31fb/src/StrippedSW.h000066400000000000000000000045141410636150300203670ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef STRIPPEDSW_H_ #define STRIPPEDSW_H_ #include "ssw.h" #include "IAlignment.h" #include "ILog.h" #include "IConfig.h" class StrippedSW: public IAlignment { public: StrippedSW() { //scoringScheme = Score(Config.GetFloat(MATCH_BONUS), Config.GetFloat(MISMATCH_PENALTY) * -1.0f, Config.GetFloat(GAP_EXTEND_PENALTY) * -1.0f, Config.GetFloat(GAP_READ_PENALTY) * -1.0f); gap_open = -1; gap_extension = -1; match = 1; mismatch = -1; int32_t l, m, k; // default parameters for genome sequence alignment // initialize scoring matrix for genome sequences // A C G T N (or other ambiguous code) // 2 -2 -2 -2 0 A // -2 2 -2 -2 0 C // -2 -2 2 -2 0 G // -2 -2 -2 2 0 T // 0 0 0 0 0 N (or other ambiguous code) mat = (int8_t*) calloc(25, sizeof(int8_t)); for (l = k = 0; l < 4; ++l) { for (m = 0; m < 4; ++m) mat[k++] = l == m ? match : mismatch; /* weight_match : -weight_mismatch */ mat[k++] = 0; // ambiguous base: no penalty } for (m = 0; m < 5; ++m) mat[k++] = 0; num = (int8_t*) malloc(maxSeqLen); // the read sequence represented in numbers ref_num = (int8_t*) malloc(maxSeqLen); // the read sequence represented in numbers memset(num, 0, maxSeqLen); memset(ref_num, 0, maxSeqLen); } virtual ~StrippedSW() { free(ref_num); free(num); free(mat); } virtual int GetScoreBatchSize() const { return 1024; } virtual int GetAlignBatchSize() const { return 1024; } virtual int BatchScore(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, float * const results, void * extData); virtual int BatchAlign(int const mode, int const batchSize, char const * const * const refSeqList, char const * const * const qrySeqList, Align * const results, void * extData); virtual int SingleAlign(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, Align & result, void * extData); virtual int SingleScore(int const mode, int const corridor, char const * const refSeq, char const * const qrySeq, float & result, void * extData); private: int8_t* mat; int32_t match, mismatch, gap_open, gap_extension; int8_t* num; int8_t* ref_num; int const maxSeqLen = 100000; }; #endif /* STRIPPEDSW_H_ */ ngmlr-0.2.7+git20210816.a2a31fb/src/Timing.h000066400000000000000000000007661410636150300175570ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __TIMING2_H__ #define __TIMING2_H__ #include #include #include #include #include class Timer { private: timeval start, end; public: void ST() { gettimeofday(&start, NULL); } inline volatile float ET() { gettimeofday(&end, NULL); return (float)(end.tv_sec - start.tv_sec) + (float)(end.tv_usec - start.tv_usec) / 1000000.0f; } }; #endif ngmlr-0.2.7+git20210816.a2a31fb/src/Types.h000066400000000000000000000005451410636150300174270ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef __TYPES_H__ #define __TYPES_H__ typedef unsigned int uint; //Type for holding genomic locations typedef long long loc; typedef unsigned long long uloc; #ifndef _WIN32 typedef unsigned long ulong; #endif #ifdef _WIN32 typedef unsigned long long ulong; #endif //#define INSTANCE_COUNTING #endif ngmlr-0.2.7+git20210816.a2a31fb/src/Version.h000066400000000000000000000002121410636150300177370ustar00rootroot00000000000000#ifndef VERSION_H #define VERSION_H #define VERSION_MAJOR "0" #define VERSION_MINOR "2" #define VERSION_BUILD "8" #endif // VERSION_H ngmlr-0.2.7+git20210816.a2a31fb/src/Version.h.in000066400000000000000000000003001410636150300203420ustar00rootroot00000000000000#ifndef VERSION_H #define VERSION_H #define VERSION_MAJOR "@NGM_VERSION_MAJOR@" #define VERSION_MINOR "@NGM_VERSION_MINOR@" #define VERSION_BUILD "@NGM_VERSION_BUILD@" #endif // VERSION_H ngmlr-0.2.7+git20210816.a2a31fb/src/main.cpp000066400000000000000000000077031410636150300176050ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #include "NGM.h" #include #include #ifdef _WIN32 #include #endif #ifdef _WIN32 #include #endif #include #include #include "Log.h" #include "CS.h" #include "Version.h" #include "Timing.h" //#include "UpdateCheck.h" #include "ArgParser.h" #undef module_name #define module_name "MAIN" // Get current date/time, format is YYYY-MM-DD.HH:mm:ss const std::string currentDateTime() { time_t now = time(0); struct tm tstruct; char buf[80]; tstruct = *localtime(&now); // Visit http://www.cplusplus.com/reference/clibrary/ctime/strftime/ // for more information about date/time format strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct); return buf; } #ifdef NDEBUG bool cDebug = false; #else bool cDebug = true; #endif ILog const * _log = 0; IConfig * _config = 0; int main(int argc, char * argv[]) { std::stringstream version; version << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUILD; Log.Message("ngmlr %s%s (build: %s %s, start: %s)", version.str().c_str(), cDebug ? " debug" : "", __DATE__, __TIME__, currentDateTime().c_str()); Log.Message("Contact: fritz.sedlazeck@gmail.com, philipp.rescheneder@gmail.com"); Timer tmr; tmr.ST(); _NGM::AppName = argv[0]; _config = new ArgParser(argc, argv); // Parses command line & parameter file _log = &Log; #ifdef DEBUGLOG if (Config.getLog()) { Log.Message("Writing debug log to stdout. Please use -o/--output for SAM/BAM output."); //Init checks if first parameter is != 0. Thus "LOG" is passed as a dummy string. _Log::Init("LOG", Config.getLogLevel());// Inits logging to file } #else _Log::Init(0, 0); // Inits logging to file #endif // if (Config.getUpdateCheck()) { // UpdateCheckInterface::remoteCheck(); // exit(0); // } _Log::setColor(Config.getColor()); NGM; // Init Core NGM.InitProviders(); try { NGM.StartThreads(); bool const progress = Config.getProgress(); if(!progress) { Log.Message("No progress information (use --progress)"); } Log.Message("Mapping reads..."); if(Config.isStdIn()) { Log.Message("Waiting for data from stdin"); } NGM.MainLoop(); int discarded = NGM.GetReadReadCount() - (NGM.GetMappedReadCount()+NGM.GetUnmappedReadCount()); if (discarded != 0) { Log.Message("Done (%i reads mapped (%.2f%%), %i reads not mapped (%i discarded), %i lines written)(elapsed: %dm, %d r/s)", NGM.GetMappedReadCount(), (float)NGM.GetMappedReadCount() * 100.0f / (float)(std::max(1, NGM.GetMappedReadCount()+NGM.GetUnmappedReadCount() + discarded)),NGM.GetUnmappedReadCount() + discarded, discarded, NGM.GetWrittenReadCount(), (int) (tmr.ET() / 60.0f), (int)(NGM.GetMappedReadCount() * 1.0f / tmr.ET())); } else { Log.Message("Done (%i reads mapped (%.2f%%), %i reads not mapped, %i lines written)(elapsed: %dm, %d r/s)", NGM.GetMappedReadCount(), (float)NGM.GetMappedReadCount() * 100.0f / (float)(std::max(1, NGM.GetMappedReadCount()+NGM.GetUnmappedReadCount())),NGM.GetUnmappedReadCount(),NGM.GetWrittenReadCount(), (int) (tmr.ET() / 60.0f), (int)(NGM.GetMappedReadCount() * 1.0f / tmr.ET())); } NGM.StopThreads(); } catch (...) { Log.Error("Unhandled exception in control thread."); } // if (! Config.getUpdateCheck()) { // UpdateCheckInterface::reminder(); // } CS::Cleanup(); _SequenceProvider::Cleanup(); delete _config; delete _NGM::pInstance; _Log::Cleanup(); CleanupPlatform(); return 0; } // actually platform specific.../care uloc const FileSize(char const * const filename) { FILE * fp = fopen(filename, "rb"); if (fp == 0) { Log.Warning("Tried to get size of nonexistent file %s", filename); return 0; } if (fseek(fp, 0, SEEK_END) != 0) return 0; #ifdef __APPLE__ uloc end = ftello(fp); #else uloc end = ftello64(fp); #endif fclose(fp); return end; } ngmlr-0.2.7+git20210816.a2a31fb/src/unix.cpp000066400000000000000000000117431410636150300176430ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef _WIN32 #include #include #include #include #include #include #include #include #include "Log.h" #include #include #include #include #include #include #include "PlatformSpecifics.h" #include #undef module_name #define module_name "P:UNIX" namespace _PlatformSpecifics_unix { char const * const colors[] = { "0", "1;30", "0;33", "1;33", "0;31", "1;31", "0;32", "1;32" }; std::map & loadedDLLs() { static std::map * res = new std::map(); return *res; } std::map > & mappings() { static std::map > * res = new std::map >(); return *res; } } using namespace _PlatformSpecifics_unix; void SetConsoleColor(ConsoleColor color) { fprintf(stderr, "\e[%sm", colors[color]); } void ResetConsoleColor() { fprintf(stderr, "\e[0m"); } void ClearConsole() { } void Sleep(int msec) { timespec tme; int sec = 0; if (msec > 1000) { sec = msec / 1000; msec -= sec*1000; } tme.tv_sec = sec; tme.tv_nsec = msec * 1000000; nanosleep(&tme, 0); } int GetPID() { return getpid(); } bool const FileExists(char const * const filename) { FILE * fp = fopen(filename, "r"); if (fp) { fclose(fp); return true; } return false; } int const CreateMapping(char const * const filename, char const * &pData) { int fd = open(filename, O_RDONLY); if (fd == -1) { Log.Error("Error opening file %s for mapping (error %i).", filename, errno); } uloc len = FileSize(filename); #ifdef __APPLE__ pData = (const char*) mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0); #else pData = (const char*) mmap64(0, len, PROT_READ, MAP_PRIVATE, fd, 0); #endif if (pData == MAP_FAILED) { if (errno == EINVAL) { Log.Message("Error mapping file %s into memory (Error returned from mmap: %i)", filename, errno); Log.Error("Args: Addr=0, Len=%llu, Offset=0", len); } else if (errno == ENOMEM) { Log.Message("Error mapping file %s into memory (Error returned from mmap: %i)", filename, errno); Log.Error("Try \"ulimit -v\""); } else { Log.Error("Error mapping file %s into memory (Error returned from mmap: %i)", filename, errno); } } mappings()[fd] = std::pair(pData, len); return fd; } uloc GetMapLength(int const map) { if (mappings().count(map) != 1) { Log.Error("Couldnt get size of invalid mapping %i", map); return 0; } else return mappings()[map].second; } void Remap(int const mapping, char const * & pData) { if (mappings().count(mapping) != 1) { Log.Error("Remap error: Invalid mapping %i", mapping); return; } void const * addr = mappings()[mapping].first; uloc len = mappings()[mapping].second; int ret = munmap((void*) addr, len); //TODO_GENOMESIZE: munmap64? if (ret != 0) Log.Error("Remap error: Unmap returned %i (addr = 0x%x, len = %llu)", errno, addr, len); #ifdef __APPLE__ pData = (const char*)mmap(0, len, PROT_READ, MAP_PRIVATE, mapping, 0); #else pData = (const char*)mmap64(0, len, PROT_READ, MAP_PRIVATE, mapping, 0); #endif mappings()[mapping].first = pData; if (pData == MAP_FAILED) { Log.Error("Error remapping %i (Error returned from mmap: %i)", mapping, errno); } } void CloseMapping(int const mapping) { munmap((void*) mappings()[mapping].first, mappings()[mapping].second); close(mapping); } struct termios alt; int _getch() { static int ch = -1, fd = 0; struct termios neu; fd = fileno(stdin); tcgetattr(fd, &alt); neu = alt; neu.c_lflag &= ~(ICANON | ECHO); tcsetattr(fd, TCSANOW, &neu); ch = getchar(); tcsetattr(fd, TCSANOW, &alt); return ch; } int _kbhit(void) { struct termios term, oterm; int fd = 0; int c = 0; tcgetattr(fd, &oterm); memcpy(&term, &oterm, sizeof(term)); term.c_lflag = term.c_lflag & (!ICANON); term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &term); c = getchar(); tcsetattr(fd, TCSANOW, &oterm); if (c != -1) ungetc(c, stdin); return ((c != -1) ? 1 : 0); } void InitConsole() { tcgetattr(STDIN_FILENO, &alt); } void ResetConsole() { tcsetattr(STDIN_FILENO, TCSANOW, &alt); } void HandleSignal(int sig) { Log.Error("System sent signal %i", sig); } void MuteSignal(int sig) { ResetConsoleColor(); fprintf(stderr, "Resources freed by OS. Exiting normally...\n"); exit(0); } void CleanupPlatform() { signal(SIGSEGV, MuteSignal); } ulong GetCurrentTicks() { timeval tv; gettimeofday(&tv, 0); return (tv.tv_sec * 1000ul + tv.tv_usec / 1000ul); } const ulong programStart = GetCurrentTicks(); ulong GetTickCount() { return GetCurrentTicks() - programStart; } #endif ngmlr-0.2.7+git20210816.a2a31fb/src/unix_threads.cpp000066400000000000000000000022401410636150300213450ustar00rootroot00000000000000/** * Contact: philipp.rescheneder@gmail.com */ #ifndef _WIN32 #include "NGMThreads.h" NGMThread NGMCreateThread(pNGMThreadFunc func, int tid) { return NGMCreateThread(func, new int(tid)); } NGMThread NGMCreateThread(pNGMThreadFunc func, void* data, bool detached) { pthread_t hThread; pthread_create(&hThread, 0, func, data); if (detached) pthread_detach(hThread); return hThread; } void NGMJoin(NGMThread * thread) { pthread_join(*thread, 0); } void NGMJoinAll(NGMThread * thread, int count) { for (int i = 0; i < count; ++i) NGMJoin(&thread[i]); } void NGMInitWait(NGMThreadWait * wait) { pthread_cond_init(wait, 0); } void NGMWait(NGMMutex * mutex, NGMThreadWait * wait) { pthread_cond_wait(wait, mutex); } void NGMSignal(NGMThreadWait * wait) { pthread_cond_broadcast(wait); } void NGMInitMutex(NGMMutex * mutex) { pthread_mutex_init(mutex, 0); } void NGMLock(NGMMutex * mutex) { pthread_mutex_lock(mutex); } void NGMUnlock(NGMMutex * mutex) { pthread_mutex_unlock(mutex); } void NGMOnce(NGMOnceControl * once_control, void (*init_func)()) { pthread_once(once_control, init_func); } #endif ngmlr-0.2.7+git20210816.a2a31fb/test/000077500000000000000000000000001410636150300163365ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/.gitignore000066400000000000000000000000061410636150300203220ustar00rootroot00000000000000/tmp/ ngmlr-0.2.7+git20210816.a2a31fb/test/data/000077500000000000000000000000001410636150300172475ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_1/000077500000000000000000000000001410636150300204465ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_1/expected.txt000066400000000000000000000023651410636150300230160ustar00rootroot00000000000000m140612_020550_42156_c100652082550000001823118110071460_s1_p0/49/0_11124>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/1019_13505>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/13545_26663>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/26699_39808 m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157671/0_4333>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157674/0_6303>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157676/0_14740>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157677/3585_9506>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157664/5106_6916>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157668/1089_6689 m140612_020550_42156_c100652082550000001823118110071460_s1_p0/49/0_11124>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/1019_13505>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/13545_26663>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/26699_39808>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157671/0_4333>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157674/0_6303>m140612_020550_42156_c1006520825500000018231 ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_1/long_name.fa000066400000000000000000000320361410636150300227210ustar00rootroot00000000000000>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/49/0_11124>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/1019_13505>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/13545_26663>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/26699_39808 AAAATATCAGTAAAATCAGATTGACCTCAAACCCTGTATCTTTCAAAAAAGACATAATTTTGTTTTTCAAGCATTGTTATTAGGTATAGTAAAAATGATTTTTTTTCTTTGTTTTTTTGTTTTGAGACAGAGTCTTTCTCACTCTGTTGCCCAGGCTGGAGTGCAGTGGCGTGATCTTGGCTCACTGCAACCTCCACCTCCCAGGTTCAAGCAATTCTCTTGCCTCAGCCTCCCCAGTAGCTGGGATTACAGGTTTGTGCCACCACACCCAGTTAATCTTCATATTTTTGTAGAGAAACGGTTTTGCTATGTTGGCCAGGCTGGTCTCAAACTCCTGACCTCAAGTGATCTGCCCACGTAGGCCTCCCAAAGTGCTGGGATTACAGGTGTGAGCCACCATGCCCAGTCTATAGGTTATATCTCCTTAATGTTACAAATTGATGAAGATTAAGTAAATAAACCTCAGCAATGACTAATACATATTTTTAAACATCTACTTTTGCTTCTCATAATCACTGAGCATCCATTTGAGCTTTATTCTTCTTTTCTTCCTTTTTTTGATAATGCTGGCAGACTTGATGAACCAATAGCATCTGACCTTCACAAACTAGGCAGAGTTTCAAAATAAGGTGACTCGTTACATTTGTTTGGATTACTTTTTGAATCCCCACATTTTCTCACGTTGGCACAATTTTGCTTCAAGTGCATCATGGAATAGATGAGACAACAGGAAGCGATAGGCTTTCCCTATTCAGTGAGTCAGGCAGTAACCAAGAGATTAATGTGAATGAATTCAGGGCTTGTGAAGGCATCATTTCTCATCAAATGGAACTGTACCCTGCTGGACGGAAGTCTGAATATGTGTGATCTAATGCAGAGGTTCCAACTGATGTGACCCACAATGTTGTCACCACCACCTCCCTCCTTGTCCTCGCTAATGACCTAAGGTGTGTCCACCATGGAAAAATCTTTCTGTTACCAGAAACGGATCCCCATCCAGACTCTAAGAGAGGGTTCTTGGACCTTGTGCAAGAAAGAATTCAGGGCAAGTCCATAGAGCAAAGTGAAAGCAAATTTATTAAGAAAGTAGAGGAATAAAGAATGGGGGCTGGGCGCGGTGGCTCATGCCTGTAATCCCAGCACTTGGGAGGACGAGGCAAGCGGATCACGAGGTCAGGAGATCGAGACCATCCTGGCTAACACAGTGAAACCCTGTCTCTACCAAAAATACAAAAAAGTTAGCCGGGCGTGGTGGCGGGCACCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATGGCATGAACCCGGGAGGTGGAGGTCGCAGTGAGCTGAGATCATGCCACTGCACTCTAGCCTCTAGCCTGGGTGACAGAGCGAGACTCCGTCTCAAAAAAAAAAAAAAAAAAAAAAAAGAATGGCTATTCCATAGCTAGAGCAGCCTTGAGAACTGCTGGTTGGCCACTTTTATGGTATTTTCTTGATTATGTGCTAAACAAGAGGTGGATTATTCATGAGTTTTCCAGGAAAGGGGTGAGCTATTCCCAGAACTGAGGGTTCCCCCCATTTTAGACCATATAGGATGATTCCCTACATTGCCATGGCATTTGTAAACTGTCATGGTGCTGGTGGAAGTGTCTTTTAGCATGCTAATATATTATAATTAACATCTAATGAGCATTGAGCACAACCAACAGTGACTTTCATCTCCATTTTCATTTTGGTGAGATTTAGCCAGCTTCTTTACAGCAAACCGCTTTGTCAGCAAGGTCTTTGGGACCTGTATTTTTGGCTGACCTCCTATTTTATCCTGTGACTAAAAATGCCCAGCCTCCTTGGAAGGCAACCCCATAGGTCTTAGCCTCATTTTACCTAGCCCCTATGCAAGATAGAGTTGCTCTGGTTCCAAAGCCTCTGAAATTTCATGTCTAATTGATGATCCCAAGATATTCAACCGTGTGTTCTGTGTCCTGGATGCTCCCCCTTCACCTTTGGCTGCCAATGCTGAGAGGCAGAAATAGGAGAGAATAGGCTCTGGGGGTCTGCTGGGCATTCATTCACGGAAACTGGAAGGATGGCTGGTCCTCTAAGGACACCAATTCTGGTCCACAGGCCAGACCTGCTAGCCCTTACCTCCTGTGATGGTTACTTTCAGGTGTTAACTGACTGGATAGCTGGTTAAGCACCATTTCCGGGTGTGTCTGTGAAAGTATGTTTGTGTGCGAATCCGGGGACTGACGGGGGAAGATCGGCTCTCATTGTGGGTGGGCATCATCCAATCAGCAGGGTGCCTAGATAGGACAAAAAGGCAGAGGAAAGGTGAATTTGTTTTTCCAAAAAGGATATTCTGGAACTGGGATGTCTCTTTTCTCCTGTCCTTGGACATCAGAACTCCAGGGTCTTAGGCCTTTGAACTTGGGAACTTGCGCCAGCAGACCCCTGGGCTCTCAGGCCTTCAGCCTCAGACTGAGAGTCACATCATGAACTTTCCTGGTTGTGAGGCCTTCAGCCTTGGACAGCTATGCTGCTGGCTCCCCTGGTTCTCCAGCTTGCAGAAAGCCTATCATGGGACTTCTCAGGCTCCGTAATTGCATAAGCCAATCAATTCCCTTAATAAATCCTCTCTCTCGTATACCTATCTATACCTCTCTACATATTAATATATCCTATTTGTTCTGTCTCTGGAGAACTCTTAACTAATATACTTCCATTACGTGGGAATTTCCCAGATGCTGAATTGAGGAAAATGACATTTTTTTTAACGTTACTGTTGGTTACCTCCCTATATAGTCAGTTCTTTTGCATCTGTTTGTTTGGATCAGCAGAAGGCAACAGTGAGACCCCACCCAATATCTTCTCTTCTCTCTAGAAAGTACTCTGAACATATAATGCTGTGAACATGGCAGGTCTTATCATGTTTTCAAGATGATGAGATATGTATTGCATATTAAATATTCATACCTGGATATTAAATACTCAGGTTTTTAAAAAATCTTATAACCATTCTAACTGACCATGATCCCAGATGGAACCCCTGCCCGCGTCATTGCTTTTGTCTCTGCCACCTGGCTGCCCCTCTAGACAGCTTCCTTTCCTTCCTGGGCTGCTCCCAGGCAACTCAAAAAACTCAACTTCCTCCCCCAAAACTCAAATTCTTACTTTTTACGTAGAGCAAATGAAGTCTGTCTCAGCTTTCTTGTGAAGGAAAAGCTGCTTCAGTCAGTTGTGTTTTTAAATAACACCCCTTCCCACTTTGTGTAACAGAATGTTTTAGAAGCTTATGCTTAAAAATTTTTTTTCAGCCACAAATTGAGGCAGACTCCTTTGATCAAGGTATTTTGTATTGGCTGAAAGTGTGCTTCTGTGGAGGGCTGGTGCAGGGAGCTGTAATTGAGAGAGTGGGAGGAGTAGCCAGGAAGGAAACTGTTGATGAGCATGACTGTATGGGGGGGTCAGCCCAGCTGGAAAAAGGCCAGGACTTATGGAGAAAGGGCATGTGAGGCAGAGAGACGAGGGGGGAGTTTATTGGCTTCTACTGAGTTACTGAATGTTCTTTCTTCTTAGATCTATAAGAAAAATTAAGTAATAAATCCTAAAAAGGCAAATGACAAAATTTACATTCTTTATTTTTCAAAAAGAACTTAGAAAACAAGGACAAGAAGGATATTTTTAAAATGTAATATAGACCATATTAAACCAATATTATGGTTGACAGTATTTAAGAGAAAAAGACAAATGACTAAAATTGATATTAAAACATTTATTGAGCATTTACTGTGTGTGAGGCATTGGATTTGTTGCCTAACATGAATTAGTTCATTTAAACCTCATAAAAGTCATACAAGGTATATATTCTAATACCCCTATTTAAATAATTAGGAAACTGAGGCAAAAGGAGTTTAAATAAGTTGCCTAATTATTAAGTCTCCT >m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157671/0_4333>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157674/0_6303>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157676/0_14740>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157677/3585_9506>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157664/5106_6916>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157668/1089_6689 AAAATATCAGTAAAATCAGATTGACCTCAAACCCTGTATCTTTCAAAAAAGACATAATTTTGTTTTTCAAGCATTGTTATTAGGTATAGTAAAAATGATTTTTTTTCTTTGTTTTTTTGTTTTGAGACAGAGTCTTTCTCACTCTGTTGCCCAGGCTGGAGTGCAGTGGCGTGATCTTGGCTCACTGCAACCTCCACCTCCCAGGTTCAAGCAATTCTCTTGCCTCAGCCTCCCCAGTAGCTGGGATTACAGGTTTGTGCCACCACACCCAGTTAATCTTCATATTTTTGTAGAGAAACGGTTTTGCTATGTTGGCCAGGCTGGTCTCAAACTCCTGACCTCAAGTGATCTGCCCACGTAGGCCTCCCAAAGTGCTGGGATTACAGGTGTGAGCCACCATGCCCAGTCTATAGGTTATATCTCCTTAATGTTACAAATTGATGAAGATTAAGTAAATAAACCTCAGCAATGACTAATACATATTTTTAAACATCTACTTTTGCTTCTCATAATCACTGAGCATCCATTTGAGCTTTATTCTTCTTTTCTTCCTTTTTTTGATAATGCTGGCAGACTTGATGAACCAATAGCATCTGACCTTCACAAACTAGGCAGAGTTTCAAAATAAGGTGACTCGTTACATTTGTTTGGATTACTTTTTGAATCCCCACATTTTCTCACGTTGGCACAATTTTGCTTCAAGTGCATCATGGAATAGATGAGACAACAGGAAGCGATAGGCTTTCCCTATTCAGTGAGTCAGGCAGTAACCAAGAGATTAATGTGAATGAATTCAGGGCTTGTGAAGGCATCATTTCTCATCAAATGGAACTGTACCCTGCTGGACGGAAGTCTGAATATGTGTGATCTAATGCAGAGGTTCCAACTGATGTGACCCACAATGTTGTCACCACCACCTCCCTCCTTGTCCTCGCTAATGACCTAAGGTGTGTCCACCATGGAAAAATCTTTCTGTTACCAGAAACGGATCCCCATCCAGACTCTAAGAGAGGGTTCTTGGACCTTGTGCAAGAAAGAATTCAGGGCAAGTCCATAGAGCAAAGTGAAAGCAAATTTATTAAGAAAGTAGAGGAATAAAGAATGGGGGCTGGGCGCGGTGGCTCATGCCTGTAATCCCAGCACTTGGGAGGACGAGGCAAGCGGATCACGAGGTCAGGAGATCGAGACCATCCTGGCTAACACAGTGAAACCCTGTCTCTACCAAAAATACAAAAAAGTTAGCCGGGCGTGGTGGCGGGCACCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATGGCATGAACCCGGGAGGTGGAGGTCGCAGTGAGCTGAGATCATGCCACTGCACTCTAGCCTCTAGCCTGGGTGACAGAGCGAGACTCCGTCTCAAAAAAAAAAAAAAAAAAAAAAAAGAATGGCTATTCCATAGCTAGAGCAGCCTTGAGAACTGCTGGTTGGCCACTTTTATGGTATTTTCTTGATTATGTGCTAAACAAGAGGTGGATTATTCATGAGTTTTCCAGGAAAGGGGTGAGCTATTCCCAGAACTGAGGGTTCCCCCCATTTTAGACCATATAGGATGATTCCCTACATTGCCATGGCATTTGTAAACTGTCATGGTGCTGGTGGAAGTGTCTTTTAGCATGCTAATATATTATAATTAACATCTAATGAGCATTGAGCACAACCAACAGTGACTTTCATCTCCATTTTCATTTTGGTGAGATTTAGCCAGCTTCTTTACAGCAAACCGCTTTGTCAGCAAGGTCTTTGGGACCTGTATTTTTGGCTGACCTCCTATTTTATCCTGTGACTAAAAATGCCCAGCCTCCTTGGAAGGCAACCCCATAGGTCTTAGCCTCATTTTACCTAGCCCCTATGCAAGATAGAGTTGCTCTGGTTCCAAAGCCTCTGAAATTTCATGTCTAATTGATGATCCCAAGATATTCAACCGTGTGTTCTGTGTCCTGGATGCTCCCCCTTCACCTTTGGCTGCCAATGCTGAGAGGCAGAAATAGGAGAGAATAGGCTCTGGGGGTCTGCTGGGCATTCATTCACGGAAACTGGAAGGATGGCTGGTCCTCTAAGGACACCAATTCTGGTCCACAGGCCAGACCTGCTAGCCCTTACCTCCTGTGATGGTTACTTTCAGGTGTTAACTGACTGGATAGCTGGTTAAGCACCATTTCCGGGTGTGTCTGTGAAAGTATGTTTGTGTGCGAATCCGGGGACTGACGGGGGAAGATCGGCTCTCATTGTGGGTGGGCATCATCCAATCAGCAGGGTGCCTAGATAGGACAAAAAGGCAGAGGAAAGGTGAATTTGTTTTTCCAAAAAGGATATTCTGGAACTGGGATGTCTCTTTTCTCCTGTCCTTGGACATCAGAACTCCAGGGTCTTAGGCCTTTGAACTTGGGAACTTGCGCCAGCAGACCCCTGGGCTCTCAGGCCTTCAGCCTCAGACTGAGAGTCACATCATGAACTTTCCTGGTTGTGAGGCCTTCAGCCTTGGACAGCTATGCTGCTGGCTCCCCTGGTTCTCCAGCTTGCAGAAAGCCTATCATGGGACTTCTCAGGCTCCGTAATTGCATAAGCCAATCAATTCCCTTAATAAATCCTCTCTCTCGTATACCTATCTATACCTCTCTACATATTAATATATCCTATTTGTTCTGTCTCTGGAGAACTCTTAACTAATATACTTCCATTACGTGGGAATTTCCCAGATGCTGAATTGAGGAAAATGACATTTTTTTTAACGTTACTGTTGGTTACCTCCCTATATAGTCAGTTCTTTTGCATCTGTTTGTTTGGATCAGCAGAAGGCAACAGTGAGACCCCACCCAATATCTTCTCTTCTCTCTAGAAAGTACTCTGAACATATAATGCTGTGAACATGGCAGGTCTTATCATGTTTTCAAGATGATGAGATATGTATTGCATATTAAATATTCATACCTGGATATTAAATACTCAGGTTTTTAAAAAATCTTATAACCATTCTAACTGACCATGATCCCAGATGGAACCCCTGCCCGCGTCATTGCTTTTGTCTCTGCCACCTGGCTGCCCCTCTAGACAGCTTCCTTTCCTTCCTGGGCTGCTCCCAGGCAACTCAAAAAACTCAACTTCCTCCCCCAAAACTCAAATTCTTACTTTTTACGTAGAGCAAATGAAGTCTGTCTCAGCTTTCTTGTGAAGGAAAAGCTGCTTCAGTCAGTTGTGTTTTTAAATAACACCCCTTCCCACTTTGTGTAACAGAATGTTTTAGAAGCTTATGCTTAAAAATTTTTTTTCAGCCACAAATTGAGGCAGACTCCTTTGATCAAGGTATTTTGTATTGGCTGAAAGTGTGCTTCTGTGGAGGGCTGGTGCAGGGAGCTGTAATTGAGAGAGTGGGAGGAGTAGCCAGGAAGGAAACTGTTGATGAGCATGACTGTATGGGGGGGTCAGCCCAGCTGGAAAAAGGCCAGGACTTATGGAGAAAGGGCATGTGAGGCAGAGAGACGAGGGGGGAGTTTATTGGCTTCTACTGAGTTACTGAATGTTCTTTCTTCTTAGATCTATAAGAAAAATTAAGTAATAAATCCTAAAAAGGCAAATGACAAAATTTACATTCTTTATTTTTCAAAAAGAACTTAGAAAACAAGGACAAGAAGGATATTTTTAAAATGTAATATAGACCATATTAAACCAATATTATGGTTGACAGTATTTAAGAGAAAAAGACAAATGACTAAAATTGATATTAAAACATTTATTGAGCATTTACTGTGTGTGAGGCATTGGATTTGTTGCCTAACATGAATTAGTTCATTTAAACCTCATAAAAGTCATACAAGGTATATATTCTAATACCCCTATTTAAATAATTAGGAAACTGAGGCAAAAGGAGTTTAAATAAGTTGCCTAATTATTAAGTCTCCT >m140612_020550_42156_c100652082550000001823118110071460_s1_p0/49/0_11124>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/1019_13505>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/13545_26663>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/66/26699_39808>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157671/0_4333>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157674/0_6303>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157676/0_14740>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157677/3585_9506>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157664/5106_6916>m140612_020550_42156_c100652082550000001823118110071460_s1_p0/157668/1089_6689 AAAATATCAGTAAAATCAGATTGACCTCAAACCCTGTATCTTTCAAAAAAGACATAATTTTGTTTTTCAAGCATTGTTATTAGGTATAGTAAAAATGATTTTTTTTCTTTGTTTTTTTGTTTTGAGACAGAGTCTTTCTCACTCTGTTGCCCAGGCTGGAGTGCAGTGGCGTGATCTTGGCTCACTGCAACCTCCACCTCCCAGGTTCAAGCAATTCTCTTGCCTCAGCCTCCCCAGTAGCTGGGATTACAGGTTTGTGCCACCACACCCAGTTAATCTTCATATTTTTGTAGAGAAACGGTTTTGCTATGTTGGCCAGGCTGGTCTCAAACTCCTGACCTCAAGTGATCTGCCCACGTAGGCCTCCCAAAGTGCTGGGATTACAGGTGTGAGCCACCATGCCCAGTCTATAGGTTATATCTCCTTAATGTTACAAATTGATGAAGATTAAGTAAATAAACCTCAGCAATGACTAATACATATTTTTAAACATCTACTTTTGCTTCTCATAATCACTGAGCATCCATTTGAGCTTTATTCTTCTTTTCTTCCTTTTTTTGATAATGCTGGCAGACTTGATGAACCAATAGCATCTGACCTTCACAAACTAGGCAGAGTTTCAAAATAAGGTGACTCGTTACATTTGTTTGGATTACTTTTTGAATCCCCACATTTTCTCACGTTGGCACAATTTTGCTTCAAGTGCATCATGGAATAGATGAGACAACAGGAAGCGATAGGCTTTCCCTATTCAGTGAGTCAGGCAGTAACCAAGAGATTAATGTGAATGAATTCAGGGCTTGTGAAGGCATCATTTCTCATCAAATGGAACTGTACCCTGCTGGACGGAAGTCTGAATATGTGTGATCTAATGCAGAGGTTCCAACTGATGTGACCCACAATGTTGTCACCACCACCTCCCTCCTTGTCCTCGCTAATGACCTAAGGTGTGTCCACCATGGAAAAATCTTTCTGTTACCAGAAACGGATCCCCATCCAGACTCTAAGAGAGGGTTCTTGGACCTTGTGCAAGAAAGAATTCAGGGCAAGTCCATAGAGCAAAGTGAAAGCAAATTTATTAAGAAAGTAGAGGAATAAAGAATGGGGGCTGGGCGCGGTGGCTCATGCCTGTAATCCCAGCACTTGGGAGGACGAGGCAAGCGGATCACGAGGTCAGGAGATCGAGACCATCCTGGCTAACACAGTGAAACCCTGTCTCTACCAAAAATACAAAAAAGTTAGCCGGGCGTGGTGGCGGGCACCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATGGCATGAACCCGGGAGGTGGAGGTCGCAGTGAGCTGAGATCATGCCACTGCACTCTAGCCTCTAGCCTGGGTGACAGAGCGAGACTCCGTCTCAAAAAAAAAAAAAAAAAAAAAAAAGAATGGCTATTCCATAGCTAGAGCAGCCTTGAGAACTGCTGGTTGGCCACTTTTATGGTATTTTCTTGATTATGTGCTAAACAAGAGGTGGATTATTCATGAGTTTTCCAGGAAAGGGGTGAGCTATTCCCAGAACTGAGGGTTCCCCCCATTTTAGACCATATAGGATGATTCCCTACATTGCCATGGCATTTGTAAACTGTCATGGTGCTGGTGGAAGTGTCTTTTAGCATGCTAATATATTATAATTAACATCTAATGAGCATTGAGCACAACCAACAGTGACTTTCATCTCCATTTTCATTTTGGTGAGATTTAGCCAGCTTCTTTACAGCAAACCGCTTTGTCAGCAAGGTCTTTGGGACCTGTATTTTTGGCTGACCTCCTATTTTATCCTGTGACTAAAAATGCCCAGCCTCCTTGGAAGGCAACCCCATAGGTCTTAGCCTCATTTTACCTAGCCCCTATGCAAGATAGAGTTGCTCTGGTTCCAAAGCCTCTGAAATTTCATGTCTAATTGATGATCCCAAGATATTCAACCGTGTGTTCTGTGTCCTGGATGCTCCCCCTTCACCTTTGGCTGCCAATGCTGAGAGGCAGAAATAGGAGAGAATAGGCTCTGGGGGTCTGCTGGGCATTCATTCACGGAAACTGGAAGGATGGCTGGTCCTCTAAGGACACCAATTCTGGTCCACAGGCCAGACCTGCTAGCCCTTACCTCCTGTGATGGTTACTTTCAGGTGTTAACTGACTGGATAGCTGGTTAAGCACCATTTCCGGGTGTGTCTGTGAAAGTATGTTTGTGTGCGAATCCGGGGACTGACGGGGGAAGATCGGCTCTCATTGTGGGTGGGCATCATCCAATCAGCAGGGTGCCTAGATAGGACAAAAAGGCAGAGGAAAGGTGAATTTGTTTTTCCAAAAAGGATATTCTGGAACTGGGATGTCTCTTTTCTCCTGTCCTTGGACATCAGAACTCCAGGGTCTTAGGCCTTTGAACTTGGGAACTTGCGCCAGCAGACCCCTGGGCTCTCAGGCCTTCAGCCTCAGACTGAGAGTCACATCATGAACTTTCCTGGTTGTGAGGCCTTCAGCCTTGGACAGCTATGCTGCTGGCTCCCCTGGTTCTCCAGCTTGCAGAAAGCCTATCATGGGACTTCTCAGGCTCCGTAATTGCATAAGCCAATCAATTCCCTTAATAAATCCTCTCTCTCGTATACCTATCTATACCTCTCTACATATTAATATATCCTATTTGTTCTGTCTCTGGAGAACTCTTAACTAATATACTTCCATTACGTGGGAATTTCCCAGATGCTGAATTGAGGAAAATGACATTTTTTTTAACGTTACTGTTGGTTACCTCCCTATATAGTCAGTTCTTTTGCATCTGTTTGTTTGGATCAGCAGAAGGCAACAGTGAGACCCCACCCAATATCTTCTCTTCTCTCTAGAAAGTACTCTGAACATATAATGCTGTGAACATGGCAGGTCTTATCATGTTTTCAAGATGATGAGATATGTATTGCATATTAAATATTCATACCTGGATATTAAATACTCAGGTTTTTAAAAAATCTTATAACCATTCTAACTGACCATGATCCCAGATGGAACCCCTGCCCGCGTCATTGCTTTTGTCTCTGCCACCTGGCTGCCCCTCTAGACAGCTTCCTTTCCTTCCTGGGCTGCTCCCAGGCAACTCAAAAAACTCAACTTCCTCCCCCAAAACTCAAATTCTTACTTTTTACGTAGAGCAAATGAAGTCTGTCTCAGCTTTCTTGTGAAGGAAAAGCTGCTTCAGTCAGTTGTGTTTTTAAATAACACCCCTTCCCACTTTGTGTAACAGAATGTTTTAGAAGCTTATGCTTAAAAATTTTTTTTCAGCCACAAATTGAGGCAGACTCCTTTGATCAAGGTATTTTGTATTGGCTGAAAGTGTGCTTCTGTGGAGGGCTGGTGCAGGGAGCTGTAATTGAGAGAGTGGGAGGAGTAGCCAGGAAGGAAACTGTTGATGAGCATGACTGTATGGGGGGGTCAGCCCAGCTGGAAAAAGGCCAGGACTTATGGAGAAAGGGCATGTGAGGCAGAGAGACGAGGGGGGAGTTTATTGGCTTCTACTGAGTTACTGAATGTTCTTTCTTCTTAGATCTATAAGAAAAATTAAGTAATAAATCCTAAAAAGGCAAATGACAAAATTTACATTCTTTATTTTTCAAAAAGAACTTAGAAAACAAGGACAAGAAGGATATTTTTAAAATGTAATATAGACCATATTAAACCAATATTATGGTTGACAGTATTTAAGAGAAAAAGACAAATGACTAAAATTGATATTAAAACATTTATTGAGCATTTACTGTGTGTGAGGCATTGGATTTGTTGCCTAACATGAATTAGTTCATTTAAACCTCATAAAAGTCATACAAGGTATATATTCTAATACCCCTATTTAAATAATTAGGAAACTGAGGCAAAAGGAGTTTAAATAAGTTGCCTAATTATTAAGTCTCCTngmlr-0.2.7+git20210816.a2a31fb/test/data/test_1/ref_chr6_140kb.fa000066400000000000000000004206501410636150300233640ustar00rootroot00000000000000>6 6:112,565,266-112,706,826 hs37d5 GTCTCTTATGAATGGAATTTCAGGGTGTCTATTGGCATTAATGGTGGCAGACAACAATTTCAAAGGAACAATATAAAATGAGGCAATTATTCATGTACTACAATTAAACCGCAGCCCATCTCCAGATATTCAGACCATTTAATCTCCAAATAGCAGGCATTTAACACCTCATCTGTGACCTGGGGGTTGACAGAACCACCTAGGACTCAGGACAGATAGCAGGAAAAGAGGTAACACTTAGGTAACACCTTCAGCTTGTCAAATTGTATCACTGTTCATCAAAGGGAAACACACACATGTAGCCATGAAGTTTGAAAGGCATCCTGGACTACCTCTGCTGTGGAAGAAGAGGCTTGCCAGGGTTTTCAGAACCCGAATTTGTGCTGTGGCTCTGTGTTGTGATTCTAGAGGGTTCTATAGTCCTAGCATCCCAGGGCCTGAGGCTTACTAGACATTTCTCTTCCCTTTGGCTGGTGTCTATGTTATGTGTTTCTTTGGACTGACATTTGGCTTTCTAGAGCTGCTTGGTTCAGCATGCCATGTTGCATTTCACTTTGTACATAGACAACAGTGTTCCATGTAATAGTTGTGTGTGTGAGGGAAGTTTTAGTGAAGGTACTTTTGATTCCTAGAGTCCTTGATTTCCTTTGAAGCAATCATGCCACTCCAAAATGGCATAATTTCAAAATAAATATTAATATGCAAAGTCTTCATCATGCTCAGGGGCCCTTTTAGCTGTAGAGTACAGCCTGGATGACTGGTCTACTCTGCAAAGACTTGTGCTAATGCAGCTGTTAATGTTACGGGATTTCTCTAACTCATCAGTTCTCATGAAGTAAAAAATGTGTATACTTCACTCCATTTAGGTAAACACGGATCTCTAGCCTCCACCAAAACACAACATAAAAACTAAGAAAGTCCTGGGAGTGAAAAGAAGGTCATTTTGCATATTACTCAAATTATATTCACCCGTCTCTCCTCCCGCTTTTAACAGAATTTGTTTATGTATTTTTTTCTTTATGGAGAGGATTTGGGCTGAATATGGAAATTTTCCCATTACCATTCAGCTTCAGAATGTTGTTTCCCCCAAGTTTCTCATGATAAAAAGACTCAGATTCAGAGCCGAACTGCTGGCAGCTGAATTTCATTAAGACTTTGATGGGAAACTTAAGTTGGAATTACAAACATCTGTGGTTAAACTTCCCTTTAGTAAACCATTTCCCAGAATTTAACTTTACCACACCAAGAGCCAAAAAGAAAAACAGTTGAAAAAAGAATGCTGCTCTTTTGCAAATATGAGTAGGTATTTAAATATTCTTCTGTATGGTCACTATACATCAATAGACTAGGTTTACTTATTTTAGAAAAAAATGATTGTTTGGAAATGCTAAGGTTTGGACTCAAAGCATATACTAGCAATCTGGTTTTAATGGCTTTTAACCAATCAAAGTTCTCAAAATTATGTCTGGCCATCATTATATTTATGTGGTTACTATAAGCCAGAAAAAACTCTAAAGTAGGGGAGTGTTTTTGGCATTTTAATTCAAGAAACTGTGACAAGTCAGATTTAGTATTTAATTATGAGAGGAAAAAAGGTATTATCCTTGTCATATCAAAGCTGCTTTTTTTTTTTTTTTTTTGAGATAGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAATGGCACAATCTCCGCTCACTGCAACCTCCGCCTCCCGAGTTCAAGGAATTCTCTGCTTCAGCCTCCCAAGTAGCTGGGATTACAGGCACCTGCCACCATGTCCAGCTAATTTTTTTGTATTTTTAGTAGAGGCGGGGTCTCACCATCTTGGCCAGGCTGGTCTTGAACTCCTGACTTTGTGATCCACCCATCTTGGCCTCCCAAAGTGTTGGGATTACAGGCGTGAGCCACCGTGCCCAGCTGCTGTTGGCTTTTTTCTTTAGCTTTTCTAGGGATTTAGCATTCATTTCTCTTAACTGCTCAGATCCTCCTATTGCTGGGGAAAGGCTGTTTAAAGAACCATAAAAGACACAATGATTATAAAAACTAAATGACAGCCTTCTTCTCCAATGTTGGATAATCAGCAAATTTTAAGCAAAAGTTAAAAGTACTCGAATTTATGGAATAAGTAAAGAGTTTGATAACAAAATACTTTTAACAAGATAGTGTAGAGCTTTACCTGAAGATAGACAGAGGCAGAGAGTGGAAAAATGAGGGAAAGGAAGGAGGGACAGACTGAGAGAAATGAGGGCTAACTTTGTGTTGGGCAGCTTACATATATTATTTCATTTAAATTTCACAAGAATTTTGCAAGGCAGGTGTATTTCTATTTATTTTACAATCAAAGGAACTGAGTATCTAAAAGATGGTCCAATTTGCCCAAAGTCAAACAGCTAGAAAGTTGTGGAGCTGGATTCACAGCGCATCTGTCTGGTTGTAAGCCCATATTCTGCCTGTAACGAAAGGTGAACTTCAAAATATTGTAAAGCAGAGGCTGCAAATAAATGATCTTTAGGCTGAATCTGGCCCTCAGATGTACTCAGCCTACAGGGCATTAAAAAAAATTTGAGTCAGCAATTTCACTTATGAATCCAAATTCTGTCTTCTTTTGAAAAAGACACAACAAAACAAAACAAAACCAGAAGACCTGGCAATGCTGAGAGGTGGCTGCCACTCTGGAAGAGGGATTCTTCCATTTCCTGTTATCGAGGCCCACCACTCACAGGATGCGTTTCTTTACCGAGCTAGATTCACTCAATTCTTTTTTACCTGGCCCCTATAAGACTCCAAGTCTTAAAACTTTCTCTGTACCATATGATCCAGCAATTCCACTTCTAGGTATACACTCCCAAAAAACTGAAAGCAAGAACTCAAACAGAGGCTTGTACAGCAATATTCATAGCAGCATTACTCACAGTAGCCAAAAGGTAGAAACGACCCAAATGTCCATCAACAAAATGAATGGACAAAACATAGTGTACATATAAACAGAGTATTATTCAGTTTTAAAAAGGAATGCAATTCTGACACATGCTACAACATGGGTGAGCCTCAAAGACATTATGCCAAATGAAATAAGCTAGGCACAAAAGGATAAGTACTGCATGATTATGTATATGGAGTATTTAGAGTAGTTAAATTCATAGAGACAAAGTAGAATTGTTGTTGCCAGGGGCTGGAGGAAGGAGTTAATCGGAAGTTATCATTTAATGGGTTTCAGTTTGGGAAAATGAAAAAGTTCTGGAGATTGATGGTGATGGTTTTATAACAATGTGAATATAGTCAATGCCACTGAACTGTGCCCTTAAAAATAGTTCAAATGGCCAGGTGCAGTGGCTCATGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCAGGCAGATCACAAGGTCAGGAGATTGAGACCATCCTGGCTAACACGGTGAAACCCGTCTCTACTAAAAATACAAAAAATTAGCCAGGCATGGTGGCACACGCTTGTAGTCCCAGCTACTCGGGAGGCTGATGCAGGAGAATTGCTTGAACCCGGGAGGCAGAGGTTGCAGCGAGCCAAGATAGCACCACTGTACTCCAGCCTGGGTGACAGAGGGAGACTCTGTCTCAAAAAAAAAAAAAAAAAAAGTTCAAATGGCAAAGTTTCTGTTATTTTTATTTTATCATGTTAAAAGAAAAGACTTCCTCTGGTTAAATCAGAGAACCCTGGAACACTAGGGAATGGAATTCTTTACTTTTTAGCAATGTTATAATAAATTCCATAACATAGACCAGGTATTCCATAGGTAATACTGTTATGAATTTCCTACTTATTAATCTAAATCAACAGCTTTTAAGATAGACTGTAGCATCACGTGGAGGACACACCCTAGAATATCATTATAAAGAGAAAATAGGATAAGGAGACTCTATAGTTGAAAAAAAAAGTGCTCTATCAGGAAGACTCCCTGGTATACAGAAAGCAGAGAAAGGAATATGAAAATTTGGTTAAGGTAATTACCACTCTTAAATGTCAATGAACTCATCTGTAAAATGGGTATAATTTTCACTATTTAGTATTAAGACAATTCATGGAGGTTGATGGGACATAGTAGAAGTCAACAAGTATTAGTTTTTTTCTTTCTTACGTGAGTAGTTTTAAAAAGTAGTCATTAGGCTAGACGGAGAAGGGAAGTTATCTCAACTTTTTGTAACTTATGCTACTCATCTAACAAGCACTGCAAAAATGGTCTTTAAATTGCATTTTATATTTCTTCATTTAAAGAAATTCCCAGCAGGGTGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGTGGATCATAAGGTCAGGTGATAGAGACTATCTTGGCCAACATGGTGAAACCCTGTCTCTACTAAAATACGAAAAATTAGTTGGGCGTTGTGGCATGTGCCTGTAATCCCAGCTACTTGGGAGGCTGAGGCAGGGGAATCGCTTTAACTCAGGAGGCAGGGGTTGCAGTGAGCTGAGATCAAGCCACTGCACTCCAGACAGGCAATAGAGCAAGACTCTGTTTCAAAAAAAAAAAAAAAAAAAAAAAAAAGGAATTCCCAAAACTTTGACTAGAAGTATTCCTATATATATTTCTATTTACCTAATCACCTCTTCCTAGCTACTTTTGCACAGTTGAACTGCTTTTATAAACTCCTTCCTAGCTGTGCTGCTTACAAGCAGGGGCCTGGGCAAATGCTCTGTGCCTCGGTTTCTATGTGTATCAAATGAGATAATAACGATACCAGTCACATTGATTTGTCATGAAAGTTACTGGAAATTACTCATGGGAAGTGTTTACATCAGTATCGGCATGTGGTAAGTACTCAACGAGTATCAGCTATGAGCCATACTATTATTGCTATTACCACCACTGCTATATTCCAGTTCTTCTAAAATAAGGTTTTTGAAGCCTATTTTGGTGTTTGGCAAGTAAGTTTTGTGCCCTACTGGTCTAGCACAGGAATAATACTTTTTTCACATTACCTCCATGGCACTTACCTTGTAGCCACTCTTATAGAATGTTAGTACATTGTTCTGTATATAATGGCCACTTATTTTTTTTCTCTCTTCAATTGCTCACCCCTGAGGGCAAAGATGAGACTATACCTTCTTTCTATTGCTCCTTGTACCTATTTTATTGCTCTTTCGAGGTAAGGCTCCAAACCAGCTTGTTGGGTGAATAAATGAATGAAATAATGACTGCATGTAAGGGGTTCAGATTACCTAATTGAATTGTTGGAACAGCAATGTAGAGTGATAACCCAGGCTAGCAACTGGAGGTCTTAGTGTGATCTCAAGGGACCTTTTTCAAAGCAAGTGACCAAGATAAGAAAAAAGAAAGCAGATGGTTAAAGAGATCTAAAATGTTTTTATTAAACATTCTGCAATCTTTTAATGGCAGGACCCTAACAATGTGCTGGGACATGGGGTCACGTATCAACAAGGAAAAAAGTCAAGAGGAAAAGTCCCTCAGAGTTAGTCTGCTTTATAGAGTTTCTTTTTAGCAAGTCAGTTTTTCCAGTGTAAGGTATGTTCATGGGCACTGATCTTCTTGGAGTGAAGTTAACACAACAATAATGACAACAATAGCAAAACTGAGGTTTCTAGGAGAGAAATTCCTCTTTTCCCCTCTGAGGGGCAACTCATTGACAACTCAATGTTGTCAATTGTATCCCTTATTCTATCATTTATCTGTGAAAGCCAGTAATAGCACCGTCACCTCCTCCACCACCTTCCACCTTGCCCTGTCAGAAGAGTCCTTGCCTTCTCAGTTTCTCAGTCTCTGTGTGGCTTCTTTCCAGCCACACAATGTAACCTCCAACCTCATGTTCTTGACCTTGTTTAGTTCCTACTTCTTTTTGATGGACAAGAATCTCATTCTTCCTAAGGACATTCTGTTACTGGCTTCTTGTGGGGGTGTTCCCATCTTCATTCCTGCCCCCACACCAGTTCTTTTCCATATCTACCATATCTATATTGGTCAAGAAGAGTTTGGCCTAGTTTTTCCTGCTATAGTGTGTGTGGTGGAATGAATAGACTTTCTTTTCCTTAATGTGAAATATTAGAATACTGATTATCATTATTGAAACTGCCCAGTCTTCCCTTTTGAGAATCACCTGTTGAGAATCACTGTTCTCACCATAAACTCAGCAATAAAGGACTCAGTAGATTAAGTGTCAAGAAGCAAAGGTGGGAAAATCCTCCCCACAACTAGTACGGAGTTACCCACAGGTGCTCTTCTTTTCAAATACTTTGCATCTGGGGGGAAGCTTTGGCTTGTTTTACAAGGAAAAGAGGAGACTTCCTTTTTGGTCAGCCAACAATCTCTATCCTTTTATTCCGTGCATATTTCATGTATTTGTTCCCCAGCTCACATGGAGCAATACAGCATGCCAGAGTTTGTGTCTTGGGCCAAGTACTCAGGGATGGAGAGTCCACAAGCTGGGCTATTGAAGAGCTTAGGAGAACCTCAGGAAGGCCTTCAGCCAAGCACCTCCCACTGCTCCATGCTTGCCTTAATATTTTTCTTCATTCCCTCTGAAGGAGAATTGCAGAATAACCATTCATATAAATCCAAGTAAAGAGAATGTATTTTTAGAATATCTTCCCATCCACACATTGAACCTCTCCCATGAATAATGTGTCCGTGTTCTCTTTCTCTCTCCACATATACACAAATACAGTCTCCTGAGCCAACCCAGTAAAGTGTTTGTACCATGTTATTAAGTCTCCGGAATGTATTTGGTTTAAGGTCTGGTTACTGCTATAAAGAGCATGGGAAACCTGATGGTGGGGCGTTGGGATCGCCATGGGACCGCAGGCTAACTGGAGGCATTATGTGAAACTATGCAGTGGGAACATAATTACCTCAATCTCACCCTTTCTACACCATATACTTTGACCTTCCTGGAATGACTAATATCTTCTTTCTGTTTTTCAAAACTGAAGGCCTCCACTGGCATTCTGAACCTATTAGACTCTGACATTACTACAAATTTAATTCACTACGTGACATTTTTTTTCCAGCTGGAAGAATATAGATAAACAGATATAATAATATTAAGTAAAAGAAAACCATAAACATAAGGTTCTAAGGAATATTCTCAAATAAGGGTTTCTTTTAATCTGATCATCATCCACATTTTTTATAGTAACAATTGTAACAACTCTTGGCATATATAGGGCATTTATACTATGTCAAGCACTATGCTAAGCACTCTATTTTATCTAATTTCATTACAATAAAAGTATGAGGTATGAAGCAGGCATCAATAAATTCTGTCAGTATCAGTTTATCTGCAGTCTGGGGATCTGTAACTTGACCAAGGTCAAAGAGCTTGAAATTTCAACTTGGGACCATCAGACTGAAAACCTGCAATCTGAAACACTTTGCTGTGCTGCCTTCCTATTATTTCACCAAACATATGAGCACATAAGAAATTTCCTAGGGTCTTAGCATTAATTTTAAGGTTCTCTAAAACTCAAAAAATTACTTTCCTATTTTTTTTGTGGGATGAGAGTTACAAAAAACAGTTGTATATGGCTTGTCTCTTTAGACCTAACAGATACAAATACAGGATGCCCGGATAAATTTGAATTTCAGATGAACAATGAAAACAAATTTTAATATAAATATGTCCTCTGCAGTATTTGGGATGTGATCAAAATTCATTCATTATTTATCTGAAATTCACATTTGAGTGTCCTGCAATTTATCTGCCAATTTTACTCTTAAGTAAAATTAAGCATTTCATTCAGGGACTTTACGTGCTCAAAGCAACAGGTGGAGATAATGCTTCCCTGGGGTTAATTCCAAGCCTGTAGAGAAGCAAAGCCTTCCCATTGCATGAAGTCCCTCCTGGTCTGGCTTCTCCCCAAGTTTCTGGGTATGAAGTTGACCAGAAGCCATGCTCCCTCTTTTTCATGGAGGCTACATTTTATACCACAGTGAGAGGTTGGCATATTCTGACCCTGTCCACTCTCTTTTTTGGGGCAATGTGGGTAGGGCTTACTCTGAAGAAGGACCATGTTCATGCACCTTATTTTTAATCATCAATAATTAATAACTATAATTGTACTAACAATTAACAGAATTCATAGCAATAATCCATGCATCAGTGATGTTAGAAATGGTGTCAATCCACATAACTGTTTTAGTTGTACAGTTGCTGTAACCATAGCTATAGAGTGTGGTGTTTGTTTTGCTAGGTCAATTGCTCCTTCCTTTCCCATGAACTTAGGTGACTTTATTTTCCTCCCTCTTAGCATGTCCCATGCAATGGGCATGCTGTTGTCTGTTTCAGTTCAGGGGTTCTTAAATCACTTGTTCTGGATTCATTCTCCTTTACCAGACCTCTACATTCTGGTTTTGTTTCCAACTTAAAAGCTATTGTAAGGTATTCAAACAGCAGCTCTTTGAATAAACATATTATCAATAGCATATCCTGAGGCTTGATTTTAATGGAAACATCTTGTTTCTGGAATACAATGGCTCGTTTCTACTTAAGATACCCTCTCAGCAGTTGTCTAACAGCTCCTTTCATGACCAGCCACTCTCACTCACCCCCTCACCTTCCCTGCTGCAGAAGACTTCTTGTCTAATATGAGACAAAAAGATCCTGCAGTAGTGTTCCCACTGTCCTAACAGCACAGAGGAGCAGGAAGCCAGTGACAGGGCACACACGTTAAGTGCCGTGGCTTGACAAAATGACTACTGGGACACGCAAGTGGCAGAAGTCACCGATGTGCTGCTGCAGTCCCCGGTGAGAGTCTAGCGGATGAACTCAGAGCACCAACACATGCACTCTCACCCCTTTGAGCAGACACATTCCGAAGCCTCAACTTTCAACTCTCAACATCCAAATGCAACTTACAAAGGAAAACTCTTTATTTCAAGTTTCCGAACTGACCTAGCCCAGGTGAAACTCTCAAGGCACTGGGGAGAGGAAAGAGGCGGAGAGAGAGAGAAGGACGAGTGTGGCACAGCCCGCGGGGGCGCAGGTGCCCCAGCAGGGTGGCAATGGCAGGGACACTGTACCTCGGCCGCAGGCGGCAGGCGTCCCAGAGCCACGCGGGGTTCGCTCGTCTCAGGCGGGTCTTGCCTGCCAACCGCTGAGCTCCCTTCAATGTCAAAAGGAAAAGCGTTGTCGTCCCCGGACGCGGCGCGGGAGCAGGCAGCGCTCCAGAGGAGCCACAGAGGCAGAACCGAGCGCCAGGCTGAGCTCAAAGCCATTTCTCCGCTGACATCCAGTAGTGCTCTTCCAGGGCTCGGGCGCTGTGGGTCTCCGTAGGTCTCCCGCGTGGTGCGGCGGTGCCTCGCTTATTTTCCCTCCTCTCCGTGTGCAGTATCCCGAGGTGGCTGCGCAACCAGCAGCTTAGGAAATAAAGGGAAAGTGCGAGAGTAAGGGAGAGTTCCAGCCTCTCTCTCCCTCTCTCTCTCTCCCCTTCTCCCCCTCTCTCTCCCTCTCCCTCTCCCTCTTTCACTTTTTCTCCTTCCCGCAGAGGTTCTGGCTCAAGAACCTACAGATGGACGGAGCTTACAGTACGGCATCAAAAGGCAGACGGATTGGGGTGAGCCCCGCCAGCGCTAGGCCACCTCCTCTCCCTGGCCGTTCGGGACTGGGGACTGCGCTGTCCTGGCTTCCTTCTCACATTCATTCTCACCACTCCCTTTTTACCTTCTACTCCCAGGCCCTCCCACTCTAAGCTGGCTTTTCAGACACTGAGGTCCGCCTTTCCCTGCGGTCTTCCCTCCCCTCTCAGTTTGGAGCCCCTCCAAGGGCTCCAGAAGAATATTCAGCTTTTGTGACGCTTCCTCACCACTCTTATTTATGTAGTCAAGGTACCGGATGTCTTATCTATATTTACATAGATATTTTATGTGGCCCCCGCTAGTTTGCAGGAAAGTGGGTGGAAAAGGGATTCCAGGGCAGGAACCAAAGGTAGATGATCTCTGAAGGCAGAGGGTCAGGGTGCCCACTTTCTTGAGCAAGGTTTCTCGGGTTTTTTCTGGGGGATAGACTGTTGCACTCTTTGTGCTAATATCTTCTCTTCAGATTCACTGGCCACCCCTCTTCCTCCCTCCAGTCCTCACCCAGAGGGCTTGGGAGAAGAATATCTTTCACTGCAGCGCTGGAAAATGACTTCATTACCCAAATGCATGAACTTTTATTTACAAAGACCATCTTGTTTTCATCCTAAAGAGGTGCTTTGTAAGGGGCCCGGAACAAGGCTTGCAGTGTATGAGCCTGTCAAGTATACTGCCTACAGCCCCGGCCTCTTCCTCTTGGCCTGTAATCTCATGCCTACTACATCTGTCTGAATCATGTAACCTTTCCAAGACTTCAGGGTGAAGTTGGGCTACAGCTATGTCAGGGGTGCCCCTGTGGATGGGATAGTGTCTGCAACAGCTGATAGGTACCTTTGTTTACATTGGCTTCATAACGAGCTCTAAACATTTCCACAAGATCCAACCATGGTTTAAAAATGGTCAGATGAGACAACCATAAAATGACACCCAGGTAAGCTTCCAGGTGAAATAAAGCATTTTTGTATAACCTAATCATAAAATAAATAAATAAAGCCTTTCCATAAAACCTAATCATTAGCTCCATTTCATAGAACAAAAGTCATTTTATCTAAGTGTAAGCAAAACCATTTATTTTGCACCTAACATGTGCCAGATACTTGGCATATGCTATTTGTAAACCTCAGCATTCCTGCAAAGTAGTACCATTATTTTCCTTTTACAGAAGAAGAAAGTGAGGTTCAGAGAGACTAGGACATTTGCCCAAGGTCGCACAGCTGGTGGAAAGCAGAGATGGGGTTTGGATCCAGGCCTCACTGATTCCAAAGCTCTCTTTTACATCTGTATACACGACACTGCAACTTTAAAATAAAGAGTATGAATTCAGAGGTGAAGGAAATGGACACTTTTATTTTTTGAGTGCCTCCCATGTGCAAAAAAATCACATAAATTGTCTCATTTAGGGCTGGGCGTGGTGGCTCATGCCTGTAATCCCAGCACTTTGGGAGGCCAAGGTGGGTGGATCATGAGGTCAGGAGTTCGATACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAATTTAGCCAGGCATGGTGGGAGGCGCCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATTGCTTGAACCCGGGAGGTGGAGGTTGCAGTGAGCAGAGATTTTACCACTGACTCCAGCCTGGGTGACAGAGAAAGACTCCAGCTCAAAAAAAAAAAAAAAAAAAAAAAAAAAAATTGTCTCATTTAATTTCATCTTTATGATAATCTCATGAAGTAGGGATTGTCATACACATTTGGCCATGGGTAAGTGGTAAAATTACTACTATAGCCCAGGTAAATCTGATGGTAAGATCTTTGATTTTAAATGATAAAATTGTATGATACAAAAGAACCAAAGCCAAAGGAAGCAAAAATAATTCCTATAGGTTTTAAAGTGATATTTTGATTTTAAAATATTAAAATAGTATTGCAAGGGACTATTAAGCTAAATTATGATACTCTTCTTTTACATAGACTTGTTAACCTACTAAATTAAGTGGGAGAAGTTAAAAACATGTTTGGTTTAGTTGAGAGACTGATATTGGGAAAAAAGATAGCCAGACTCTGAGACAAAACAGATTATGCTCAGTTATACTGACCCAGTCACCCTTTAAAAGAACATTAAATAATAATAATATTAATTATATATGATGTATATTAAATATTCTGACTTCAGATACAGATCTCTTCAGCTCACCAAAACTCATATATTTGTTTTCTGAAGGATTTCATCTTGTTCTTTACTAGCTGCCAATTAATCACACACTTTTTAATTTAATCTGGGCCCTCTTCTGTCTGCCTGCCCAGTGCTGGTAGGAGTGTATTCGTCCAAGACCTATGGACTTCTTATTTTTGGTTAAATATGTGCTCCCAGCTCTTCCTCTTCATCTTCTTTCTGTGGGTACTATTATTGTTTTTGAGACAAAATGGCATAATATGCAGGGGGATGGGTTTTGTATAAAATAAAACAGGGTTCAAATCCTGGGTCTGCATGTAGTACTTTTGGGAGCTTGGCATGTAACTTAGTCCCTCTGAAAGTTTCCTTCCCTGTAAAATGGGCATAATGATGCCTTTTTGTCATAGGCATTTCAACTAGAGCAATTCCATCTTGAATAGGGGCTGGGTAAAATAGGACTGAGACCTACTGGGCTGCGTTTGGAGGAGGTTAGGCATTCTAACTCACTGGATGAGACAGGAGATCAGCATAAGATACAGGTCACAAAGACCTTGCTGATAAAACAGCATGCGGTAAAGAAGGCAGTCAAATCCCAACAAAACCAAGGTGGTGACCTTGGTCGGACTCACTGCTCATTATACGTGAATTATATTGCGCTAACATGCTAAAATACACTCCCACCAGCACCATGACAGCTTATAAATGCCATGGCAACATCAGGGAGTTACCCTATATGGTCTAAAAAAGGGAGGAACCCTTAGGTTCCCAGAAATTGCCGACTCCTTTCCCAGGAAACTCATGAATAATCCACACCCTGTTTAGCATATAATCAAGAAATAACCATAAAGATAGGCAATCAGCAGCCCTTGAGGCTGCTCTGCCTGTGGAGTAGCCATTCTTTTATTCCTTTACTTTCTGAATAAACTTGGCTTTACTTAACTCTATGGACTCGCCTGGAATTTTTTGTTGCGTGAGATCCAAGAACCTTCTCTTGGGGTCTGGATTGAAACCTCTTTCTGGTAACATTTTCACTGAATTATTATGGGTAGTAAATGAAAGAATATAAATAAACATTAACACAGACTAGCATGTAGTCAGAGCTCAATAAATACTATTTAATTATACAATAAGCCCCCATTTAACATTATCTATATGTTCTTGGAAACTGCAACTTTAAGCAAAACAACATACAATGAAGCCAATTTTACCTTAGGCTAATTGACATAATTAAGATTTATTTAAATTCCTATGACATAGTTCTGGTCACAAAAACATCACTAAACTTCTAAAGAAAGACCAAAATGCTTCTAATGGTAAATATGAAAATAAATGTGAGCTATACGTACATTTCAGAAAGATTAATAGAAACAAGTGTGAGAATTATTTACCCAATGTTTGGTGAATCAGTGAGTGACAGCAGTCATAGTGGTGGTGGGTTAAAGCAAGGAATAAATGTTTTAAAGCAAAAATTATAAGCACCTCCTACCACCATGCAATTCAAAAAAACCCAACAACAAATATGATGGGCTCGCTGAACGCTTCCATGCAGCATCATTTATTGTCATATGCCTGTATGATTATTGTAGACTTCATGAATTTTTATTTGATAACAATTTTTGTTCATTATTCAATCATTTTCCAACCTGCTTTTTCCAACTCAGAGTGTTGGGTGGCTGGAGCCCATACTGGCAGCTCAGAGTTCAAGCTGGGGACCCTGGACAGAAGGCCATTCCATTGCCGGGCACGCTCACACACACACAGCCACACTCACTAAGACTGGAACCATGCAGACGTACCAAGGAACGAGGATATCTTTGAGATGTGGGAGGAAACTGAAGTACCTGGAGAAAACTCACGTGAGAACTTGCAAATTCCACACAGACAGTGGCTCCAGCCAGGAATTGATTTTTTTTTTTTTCTCACCAATATTATGACAAAGCAACATTGAAAGAAACAATGTTATTCTGGGACCTGCCTTACTATATTTTCAAATCTTAAAGAAGAACAAAATGACTATTGTAAAAGAGGAAAGGCAACCATTTTATTTATCCTGGTGTAGGTAACCTCCCATGTTTGAGAATAGCCATTCACATTTCTGGCTGCTACTGGGCCCTTCCTTGCATTAACCAGGAATGAGGCAGTCATGGGCCACAGAGTCATAGGTCAAGCAGATGAGGAGAGAGCACGGCTGACTAATTTACAGCAAGTTAAAAGGCAGCAGAAACCTTTGGTGAGTTACCTCCTCACCAAAGGGCCACTCCTTGACCACCAAACACCTGAGTGTAGGAGGATTTTATTCCTGCCACAAGGGCAACTGGGAAGCATTTCTAGTGCGGCTGCTTTCTTATCACGGCTCTCCCTTTCTCTCCCTCCTGGGATTGAGGCTTGGTGTTCACCCAGTCTTTTCATGGCTGTCATCGTTTTCGGGACACCTATCTACCCCGTGATGACAGGGGTGCTGCTCCATCATCCACAATGCATAGAAGACAGCACGGACATGCAGAGACGCTCACAGTGCCTACAAGGACACTAAGCCCGTTAGTACAAAACGAGGGCCCCCACACCATCCAACTCCCAGACCAATACTTTCCCAACTAGGCCGAGCTATTTTTGGTTCTGGCAGCAGCAGATCTGATGATTTTGAGGTTTTATCAAAAGAAGCTTCTGGAATTCCCTTTTGAGGACCCTAGTGTGATAATCAGCAGATAAATATCAGGGCTGCCTACCCCTTCAGAGCTTGGCTGTTAGACCTGTCCTCAGCATCCAAAGCCCTAAGGAGGGTGTTATTAACACATCCCATGTGCCCTTCTGTAAATAGAAAGTCACGTCAGATGCTATTTTGAACTTGTAAGTGCTAATCTTGACATAACTAGACAGAGGATTGTTGTGGGGACTGTGTACTAGTGACAATAATTTTGTGATGAGATGAGTCAGAGAAGCAAGTATGAACTATCCCCCACCATGAGGTCTCTAACTGGCACTCAAGTAGCAGGACCAGAAAGTGTAAGATGGCGTCTCTTTTTTTCTGCTGATCCTGCTGTCCTCTCAGACCAAGATTCCCTTCTATGAACGACTCTGGTGGATGTTCAGTCTCTGTGAGGAGGAGCAGCAGCGAGAGTGCTAGGAGGTGAATAGGGTTTAAAAGTTGTTCTTCCTGGCTGGGCATGGTGGCTCATGCCTGTAATCTCAGCACTCTGGGAGACCTAGGCAGGCGGATCACCTGAGGTCGGGAGTTCGAGACCAGCCTGACAAACATGGAGAAACCCCATCTCTACTAAAACTACGAAATTAGCCAGGTGAGGTGGTGCATGCCTGTAATCCCAGCTACTCGGGAGGCCGAGGCAGGAGAATCGCTGGAACCCAAGAGGCGGAGGTTGCGGTGAGCCGAGGTTGAGCTATTGCGCTCCAGCCTGGGCAACAAGAGTGAGATTCCATTTCAAAACAAAAAACAAAAAACTTGTTGTTTCTTCTGTTAGTTTTCTCAGGCTTTTGCCCAGGACATGAATAGTATGTGCTATCTATGCTTCCTCTGCAGTCATAGACTCATTTGGCTTTTAGTATATGCTATCAGCATTCTTCATCATTCATTCTTTCATCCATCCATCTATTCATATATTATTTATTTAATCATCATTTGTTAAGTAGCTCAGTACACCAGGTTTAGATGCTGAGGATAAAATGCTAAAGACATTATTCTGTCAAGTGTGTTAAAAAAATATTTATTTATTTATTTATTTGTTTTGAGACAGAGTCTCACTCTTGCCCAGGCTGGAGTGCAGTGGTGCAATCTAGGCTCACTGCAACCTCCACCTCCCAGGCTCAAGAGATTCTCCTGCCTCAGTTTCCCGAGTAGCTGGGATTACAGGCGCATGCCACCACACCCGGCTAAATTTTGTATTTTTTAGTAGAAACAGGGTTTCACCATGTTGACCAGAGGCTGGGCTCGAACTCCTAACCTCAGGTGATCCTCCTGCCTTGGCCTCCCAAAGTGCTGGGATTATAGGCGTGAGCCACCACGCCCAGCTGACTGTCAAGGAGTTTTTTAAGAGTCTGGTTGGACTCTGTAAGGAATGCAATGATTAACAGGAGTTCAAAGAGAAAGTGCAGAAATGCTTCTGATAAAACATATCGAACAAGCCTTTTATCCAGATGCACTTCAAATAGGAAGTGCAGAAAGGCTTCTGATAAAATATATCAAACAAGCCTTTTACCCAGGGGAAGTCAGAGAGGCTTGAGAAGAAGAGAGCAACCGGGCTGAGTCTGAACTGATGGGAGAAGGGGAAGGATGGTGCTCCAGAAGTGAAGTGCAGATGCAGAAGGACAGACAAGTCTGGGCACAGTGGCTCATGCCTGTAATTCCAGTATTTTGGGAGGCTCAGGCGGCGGATCACCTGAGCCCAGAAGTTTGAGACCAGCCTAGGCAACATGGTGAGACCCCATATCTACAAGAACAAAAAACAAAAAAAAACCAAAAAACAAAAACCCCAAATATTAGCCAGGCATGGTGCTATGTGCCTGTAGTCCCAGCTACACGAGAGACTGAGGTGGGAGGATCACCTGAACCTGGGAAGTCAAGGCCGCTGTGAGATCGCACCACTGTACTACAGCCTGGGTGACAGAGTGAGAGCTTGTCTTAAAAAACTAAAATAAAATAAACCAGAGGAACAGACACATCAGGGAACATGATGCCATGGGAGGGTGAGAAAGCCATATGATTTCTAGTTGCTCTCTGAGCCCCGCCAACCGTTCACAGGGTACCGTCCCTGCTGTCAGGCCCACAGAGCCTGCAGGAAAAGAAAGAACTTCCCCAGCCTCCTACTGCTCTCTCAGCACTGCACACCAATCCAGGCCCAGTAAGTAACAGAGGATCCTTCCCCATTGCAAATCTGAACACTGGGAGCTGTTAGGCCTAGTATTTACACCCTGAGCAAAAACCCAATAAAACTGATGGGAGAAAGAACAACTTTTAAAAGGCCTCCATGCCTCTCCTAGCACCCTTGCTGTGCTGTTGCACCTCAAACAGCCTGAACTTCCACCAAAGTCAGTCATAAAAGAGAATCTCCATCTGAGAGGAGAATCAGCAGAAAAAGAGACACTGTCCCTCTTAAACGTTTCATTCCTACCATTGGGTACCAGTTAGGGTACAGGGTGGGGGAGAGCTGGTGCTTGCATCTCTGACTGATCTTACCATAAAATTGTCTTCACTGTTTTTTAGGTGAATAAATTTAAGTGTAGAAATGACATGATCATATTTGCATTAACTTTATTTTTTTTGTTTTGAGACAGAGTCTTGCTCTGTTGCCTGGCGCAATCTCAGCTGGCTGTAGCCTCTGCCTCCTAGGTTCTAGTGATTCTCCTGCCTCAGCCTCCCAAGTAGCTGGGATTACGGGCACACGCCACCATGCCCAGCTAATTTTCTAATATATGTAATTTTTAATTTTACTATAATTACTTTATCTGGTACATTTAAAATTTTATACAAAAATTAGCTGGGCGTGGTGGCATGCACCTGTAGTCCCAGCTACTCAGCGAGGCTGAGGCAGGAGAATCACTTGAACCTGGGATGTGGAGGCTGCAGTGAGCCAAGATCATGCCACTGCACTCCAGCCTGAGCGACAGAGCGAGACTCCGTCTCAAAAAAAAAAAAAAAAAGAAAGAAAGAAAAAAAGGAAAAGAAATTACATGTATCACAAAAGGTGGAAATAATAGTTACCAGAAATCATACTATTCTGGGGCAATAACTTACAACACTGAAAACGTTTTGGTGTAAATACCTTCAGACTTTTGTGACATCTATATTAATGTGACCCATCTATTTTTATATTTTATATATTTTATTATATATTATATATATGTTTTGTACGTATTCATTTTGTCTATTCCATCTATTTTTTTTTTTTTGCAAAAATGAATCCAACTGTACATAATATATTTCAACTTTTTCTCCATGTCAGTGTAACTCCAGTATGTTACCATGAATAGCTTGCAGTGTTCAGATTTGAATTTTGGGAAGACCTCCTGGTGTGGATGGGGCCTGGAATTGAGGACAGTGCTAAGAGACCAGTTAGGAGGCTGGGAAAGCCCTTGCTTCTCATGCAAGCTCTGTTAACCCCAAGGGCAGGGACTATACTCATGAACTGGGGACTCAGGAAGCTTTTGGGGATGATAGTAGCAATGATTGGGTTGGCCTGATGGAGAGTGAAACAAACAGATGAGAGCATGGTCCTAACAAGGATTATTGACCAGCCTCTGCTGTGGCCATTCCTTTAGGTCTAATAGGATAATTACTTCATCAGCAATAAAGGAAAGTGATGGATGCTCCCGGTAATGTTTTCAATAGAGAACAGCAGGTGTCAACATCAATTAGCTCAGTTGATGAGATCAATATAACATAGGAGCTCCTGGGACCTGTTAATGAAATGATATAATTAAGAAGAATGGAACAACTTTCAAAAAAGGAGGCCTAAGAAACTGACTTTTGTGTCCGTACATCCACCCCCACTCCCAGTACCACAAAGGAACTATCCGTTAAGAACAGGATTGCTGTCAGCATGGTGGGAAGATACACAGAATGAAATGTTAAAATCTGTTCTAACCTGCTCTGTGTGAGCAGCTGCAGAAACTAGTCTGTGAGATTTTAACTCAAAAGCTCTATAATGGAAAATGCATGCTGGACATGCTCACTTTAGGATATCAACTGACTTCAGAAGAAACTTTGGAAGTAGGGAGGGCATAACCATAATAGTGCTTCAAATTTTCACAGTGCCTTATGATTTGAAATTGATATATAGTTCTTTCTTCTTCTACAAGTGAGACTGATCTGGCTTTAAATGCCAAGCATAGACTCAGACTTTTAGGAGAAAGATTCCTATATCACAGTCCACCACATCCCTTATTCCTTGAGTATTTAATAATCGAAATAAGATGTTAAATTCACCATCCATTCATTCAACATCAATTCACCATCCATTCACCATCCATTCATTCAACAAATATTTTTCAAATGTCTACTTTGCAACCTGCATTTTTCTAGGCTCCATAGCAAAGAAGAAATCAGACAAAAATTCCTGCCTTCATGGAGTTTACATCTAACTGAAGCAAGGTAGAAGACAGCTAAAGAATAAACAATCAGACAAGATAAATGTATAGTAGGTCACATGGTAAATACTTTGGAGAAAAATAGAGCAGAGTGGGGGTGGGGGTGGTAGAGCATGTAAGCTGAGAAAAGTGGGATGAAAGTATTTTAAATTAGGTCATCAGGGCCAGGTGCAGCAGCTCACACCTGTGTTCCCAGCAATTTGGGAGGCCAAGGTGGGTGGATCACTTGAGGTCAGGAGTTCGAGACCAGCTTGGCCAACATGGCGAAAACTGGTCTCTACTAAAAATACAAAAATTAGCCAGGCATGGTGGCACACACCTATAATCCCAGCTACTCAGGAGGCTGAGACACAAGAATCTCTTGAACCTGAGAGGTGGAGGTTGCAGTAAGCTGAGATGGCACCACTGAACTACAGCCTGGGTGACAGAGCAAGACCCAGTCTAAAAAAAAAAAAAAAAAAAATTGGGTCATCAGGGAGGCCTCACTGACAAGACAATATTTGAGCAGAATCTGGGATATGAGGGGGCAATCCAGGCAGCTATTAATGTAGAAGAGCAGGGCAGAGAGAAGAAACAGGAACTGAGTAATAGAAAGGAAGAAGGTGTTTCTCTCATTGAGGAAGAGACTGGAATGAAGTGATGGAAGTAAAGCATAGCTGGAGATAAAGTCAGAAATGTAGGAGCTGTGGGGAGGATGATTATGTAGGACCTTTGGGATCATTATGTACAAAGACTTTGGCTTCTTCCCTGAGTGAGTGGGGAAGAATTTGGAGGGTCTTGTGCAGAGAAGTGACATGATCTGACTTATTCTTTCTGTGATGTGGGGAGTAGATTGTAGGGAAAGAGGTAAGGAAAGAGGCAGGGAGGCTATTTAAAGGCTATTGCAATAATACAGTTGAGCCATGATGATGACTTGGGTTAGGATGTTGGCATTATGTATGAAAAGTACTTAAATTCTTGATTTATTGTGAATGTTAAATCAATGGGATTTGCTGGATATGGGGAATGAGAGTAAGAAAGAAATCCAGGCTGCTGTACATGTTTTGTCCTGAGCAGGCTGGAATGACGAATTTGCTATTAAGAGAATGTGAAGGACTATGGGAAGAGCAGGTCAGGGTAATTGAAACACGAAAAGTTTAGTTTTGAACAAGACTTTTTTGAGGCTGTGTGCGGTGGCTTACGCCTGTAATCCCAGCACTTTGGGAGGCCAAGGTGGGGGGATCATGAGGTCAGGAGTTTGAGACCAGCCTGGACAACATAGCGAAACCGCGTCTCTACTAAAAATACAAAAAAATTAGCCGGGTATGGTGGTATGTGCCTGTAGTCCCAGCTACTCAGGAGGCTGAGGCAGGAGAATCACTTGAATCCAGGAGGCAGAGGCTGCAGTGAGCTGAGACTGTGCCATTGCACTCCAGCCTGAGTGACAGAGTGAGACTCCATCTCAAAAAAAAAAAAAGGCTTCTTTTTGAAATCTAACTCAGATCATATTCTTACTAAGAATTCCTTATTGTATTCCTTACTTAAAGATACTTACTTTTAAACATTATATATCCATACTTATTTTAAACATTATATATCCATAATATGTAAGGCATACTTTTTTTCTGGAATCTATTACGGGCAAGGAACTGTAGATAAAACTATAGGACATCCTTATTGTCTAGTAAGAAAGATTTGTAGCATGAACTCCATTACCTACAATTCAAATCACCTAGTGCTCAAGATGGGCAAAAGTCCATTGCCTTTGGGAGAGATAGCAGGAAGGGATCACTTTGAACTCCATGAGAAGAGAAGGGATTAAAGATTTGAACTGGGGCCAGGTGCAGTGAGTGGCTCATGCCTGTAATCCCAACACTTTGGGAGGCTGAGGCGGGCAGATGGCTTGAGCTCAGGAGTTGAAGACTAGCCTGGGCAACATAGTGAAACTCTGTCTCTACAAAAAACACAAAAGTTAGCTGGATGTGGTGGCTAATTTTTAATCAGCCTGTGGTCCCAGCTACTCAAGAGGCTGAGGTGGGAGGATTACTTGAGCCCAGGAGGTCAAGACTACAGTAAGCCGAGATCATACCACCGTACTCCAGCCTGGGAGACAGAAGAGACCCTGTTAAAAAAAAAAAAAATGAGCAGGATCTCTTAAGTATAGGAATTAGATGTGGGAAGATGGGTGTGGAAGGTGCACAAGGAAAGGAATTTCTGGCAAATGGAACAGCATAGGCTCAGGTGTAGGAATGGAAAAACACATTCATGTTCAGGCAAAGGCAAGTTGATAGATGGCTGAGCACTGCACAAAGCTGGTTTGGGTGAATAATGGGAGGTAATATAGGTAAGATAGGTATGGCCTGATTATTTTATAGTTTGCTGCTAGAAGAAAGAGAGAAGATCACCAGAGAGTTAAGAAGGGTTCATCGGATAACCATGTGGAGGTTGCACTGCAGTGGAGAGAGACTGGAGGCTGGTCCAGCTGGGAGATTGCTGCAGTAATAATGTAGGCCTCAAGTGGGGACAAAGAATAACGTTTATGAACTGTCACTGTCCACGAACACAATGTCCCATCCCTGAGTTAATCCAGGTGTAATGCAGACAACTAATTTTGTAAAACTACTATTTCCTTGAAACCGACATGAATTTTAGCTTGAATGGAATCAGTCAATGGAAGGATAGGCCAGGAAAGAAGGCAATGCTTGATACGGGTGTTTCCCAACCGACACACACTGTGTGGCGTCTACTAAGCCACAGGCTGGCTCCTCCGCCAGGGGAAGGTTTTGCCTGACAGCAATTCCTATGAGATAGCTTCTTCCTTTTTTTTTTTTTTTTTGAGGGGGCAGGAAGTAGGAGGGGGCAGCATGGCGGAAGCCCTTGTGAGTGCAGGGGTCTTCTGGAAAGAGAAGTTCTCATTCTTTGGAGAGAGCTTCCAAAGGTGGACAGCTTTTTTTTCTGTTTTATGTGGAAGAGAGACTTTGTTGCCCTTGGAGTTGTTGACAGTCCGAGGGGAAGCCAGGTTTAGCAGAAACTGACTCCATAGAAGGCAGAGTGGAAGGAGAAGAGAAAATGGGTCCCAGAAGATGATATTTAGCTGTGGAATCTGAACTTTCCAATTTCACAAGCCCAAAAATACCCTTTATTGCCAAGTTGAGTTAGATTTTCTGTTAGAACAAAAAGGTTTCTAACTGATACAAGAACAGTAGGGATTTGAGAAACGTGATTTTGGAAGAGACTGTGATGAGTGAATTAGTGAGAAATAGGAGGTGGTTTGTTGAACAGAAATGTCTTTTAGAGGAAGTCCTCAGGAAAGCAAAACTAATATAGAGAATATCTTGATTTTCCACAATTCATCAATCTGTAGACATTTATTAGAAGAGAAGTTAGATGTTAAAAACTCAGCCTATGGATTCAGACTGTGAACCTGTGTATTGTAGTTTGTTTTTATAGCCTTTAATTCTCCAACTTATCAACTCTGTGAACTTGAGAAATTATTTCATTCTCAAAACCTCAGCTGCCGCATCTGTAAAAAGGGAACTGTATCTATCTCCTAGAGTTTTTGTGAGTGTAAAATAAGGTTGTGTATGAAAATTGCCCAGAATAATGCCTGGCACATAGAGAATGCTTAATAAACTTTAGCTGCTATTATTATTACTACTACTACTAATATTAACAGTTAGATGTCTAATTTGTTCTGGAGAAAACTAGAAGACAGACAGGTAGGTTGATAACTATAAAATTAATAGAATTTTCTGTTACCTGTAGCATAATGCATAAGTATTCTTGTTTTCTTTCATTTGTTTTAATATTCAGAAGCTATAACAACAATTATAGACACATTATTATCAACGTGGTATGTAATATTTGTTAAGGTTTCTCAGAGGCTGCTAACCAGGCTTCCACAGGGTTACAGTCTCATTAGGGGCCGAAGACAACATCTAGCCCTTGGCTACAGGTCCTATCTTAATTCTTAGCACCATCCAGGTAATTCACGGCTTCAGCTACTCTGTCCTTAATTACTTGGCTCCTTCAGTCCATAGTTATTTTAGTATGAGTTCTCCATCCTTAACGGACTCAGTTCTGTATTTGAATTTCATTTGTAGACTCAGACGTAGTAAAACTCCCTAGGAATAAGTGCCTAAAAATGAATAGGCTTTTCTAGGAGACTGGACCATAATTTGGAGGACAGTTTTCTCTCTGGCATTGTCAGGCACTGATTCAGACTCTGTAATTACTAAAGGTTTTTCAAATTATGGCATTTTACATTGGTTTTAATTTTTCATCATTTTGAGTATGCAGACTACTATCACGACATTGTCTCAAATAATTCTCCCGGCATCTCTGTGAGGTAAGCATAATTATCCAACTTGAAGCTAAGAAACAGAGTCATGGGTGAGCAGTGGAAAATGACCCAGTGACTGATCTTCAGGCTCCCAGGCTGATGCAATTTCTTCCCATTCCTCCTGGCTCCTGGAGTTGTCAACCTTTGACATTTTAAACTTTACAACCCAACTTAAGTAACAGCTGAGCAGCAGAAATACAAAGACAGCAGCATTCAAAATTTCTGTCCCTCAGATTTTGAGGAAGAATTCAATTATTATCATTCTTAAATTAATAATTATTAGAAAACAAGAACACCAATGACAAGAAGTCGATTGTGGGCTAGAGGGAGAGAAGGATCATATGGAAGGAGGCACATTTCATCTTTAAATAACTGAATAAAAGTGAAGGCTTGTTTTCTCTGTCTTTATTAACTAGAATGTCAGAGCACAGAGAATTTAAAAATTGGGCTTGCCATGGCTCAGGCTTGTAGGGAAGAGATCTTCCCAGTGAATACGATTATGTATCAAAGACCTTGAAATGAGCATTTCCTCCAGCCAGCTACTAAAAATGGGCCTGTGGCATTTCTGTGCTTAATTCAGCTGGATAGCCTTTGGGAAAGGGCTGGTGCAATTTTAAATCTGGTGTTAAGATGAGTGATAAAGAACAGTTCCATCGAGGGCATGGGACAGAGCACACAGAGGAGAAAAAGTTCTGGACTGGGGCCTGGAAGCCTGGTATTCTCATCCCAGGGCTGCCTCTTGTGAGCCACAGTCTTGAGCTAGTTTCTTAAGCTCCCTGGCTTTCACTTTCCCCACTGTATGAAAATGAAAAGTGAGACAAGATGAGCCTGGGGTCCCATTCAGCTTCGAAGCCCTGATGTTCTAAAAGCACCTATCCCCAGACACTGACTGTTCTGGCCATGGCCAAGAGCAGATGGATGGTTTAGAAAGCAACACATAGAGGACTATTCCATGGCGCTACCTGCTGAAATCATTAAACCCAGGGTCTGGTAATTTGTGCCCAAAGCTATATTTTAGGTGCCGAAAAAAGCCTGTGGACAGTTCATGTAACAAATTAAATGCAACGAAAGGAAGAGAAATATGAGTTATTACTTTAAACTCTGCCAGATTCAGAACTGTAGGCCAGAAAAGAGATAATGCTGCTTGAGACCACAAAAGGAAAAGAATTAGGAAATGCGTCTCCTTTCCCTGATTCACCCCTCTGTGATATCGCCCTCCACTGGCATTGTGGTGTGTGCTTCCTAGAACAATAGGCCATCAAATCATGTAGTGCCACAGATGGAAAAAGACCAGACAAACTACACAGGACACTGAAACAGGAACTTGTGACTCTGCCAGCAGAACACGGTAGTTTCTCTCAGCCATTAGTTCACCTGCAGGGTCATTAAAAAAAAACATTTATTGAGTAACAAGTCTTTCAATGAAGTTGAATTTTATTTTCTTTATTTAGCCTCTATTGTTCTTAGCTGTGAATAATGTTATTCTTGCCGTTTGCAAAGACCCTAAATGTATTAGGTTGGTGCAAAAGTAATTGCTGTTTTTGCCATTGAAAGTAACGGCAAAAGCTGCAGTTACGTTTGCACCAACCTAATATAATTACAAATGGTAAAAAGCAAAAGGGAGAACTATGACAAAATGTACGTGAACTCCACAAATCCAAGGCCCAGTGTAGACACAAGCCTGGCTGAACTGTGTAGGACAGGGAGCACCTGCTTTTTGCAGGATGCTGAGGAACATGGAAGATTAGTATGTATGTAATTTTAGCTATAGATTCCTTGCTTATTCATTGATTTTACATAATCTATGACATAGACTAAGTAGAACACAATCTTTCCTGGAAAATTTTCTTATTTAACCCTATGAAATAGCTATGAAACCCAGATCATTAAGCAGTTTTGAGTAACATCTATGTCCAAAGTAGAACACAGGCAAACCCAGCCCTTCTGGTCTACGTGTGACACAGTCATGAGGACAAACCCACAACAAGAAAAGAAATTTAAAAATAAACAAAAAACCACAAGCCAGGAGCGTTAAAACACAAAGCAATCACACAGAGATCAGAGGAACATTGTCTGTGCCTTCCGTCTCCCCACTCCCAGCCCTTTTAATAACTTAAACAGTTGCCTCTGATCCTTCCTTGGATGGTGGACAATACCAAAAGCTGAGATCCACCCTCCACCCTGGCAATTCCATTACTGCATCATGGCTGGACATCTGAAAGAGTCTGGGAATAGCCAGCTGGTTTTAGGCAGAAGGCCCAATATCAACAGTGTGTCTGGTGGGCAGCTGGAATAAGGCTGGTGAGTGGCTGAGCCTCTATTCCATAAACAACTGGCAGGATGTTTTAGCCTTTATCAGCCACTGCCTTAATGAAGGCCTGAGCTGCTAATAAAACCTACTCAAAATGGTAGGTCAAAGTCTACCCCCAGGATCCTGGGAATTAGCAGACATTTTGATTTCATGTTTAAATAAGCCAATGGGTACTGCTGTTACAATTGAGGCAACACTTCTATCCACTTACCTAATCATAACATTAGCAAAGCTATGATGCTTTGGATGAAAGTGGGGCAAGCCAGTGGCCTGTCGTCTGAGTCAATCAGTCACTCCAACAGCCACTCTGTTGGTCATCAGTGTAACAACCAACCTCTCAGTTTGCTGCCATTTTCCTAAGCTTGGCATTTTTCTCATTAGCTGACAAGTTTCAGCTTCTCACTCTGTCATTTATTATTATGAAACACTTTTCACCTCCCAGGACTCACCACCAGGCCCTCTCACCATCTTATCTACTCCCCACTCCCTTTTCCTGCTTCTGCTCTCATTCATAGGTTTTCTGGCATTGCCACAGAATGCTATGGAATAATATGGACTTAATACCACTATTCTTTGGTTTTAACCTTATCAGCATCCTCACAAATGCCTGGCGATCCATCTGTTCATCTGTTTTGAATTTTTTTTGCATATTTTTAGAAGCTGTTGTACTGGACTGGCACTGTCACTCACAAATTGTGTTGTTTGGCAAGTCCTTTAACATCCTCTTCTGTAAAGTGGGTGGTTGGACTGAAAGGTCTTCAAAGTCTCCCTGGATGTAAAACAGAGGTCATGTTCTGAACCTTCTCAGTCTTCCTCAGATGTCGGTCCTTCATCACTACCCTTATTCTCACGGACCACCCTGGCTTCTGCTTTATTGAGGCACATGTTTGGTTCCCTAGTTTTGACTCCTTTCTATAACTTCTCTGTCATTCACTCCTCTCTTTCAGGAAGAGGGCACATGACTCTTGCAAAGGCTAACTTATCCTCCTGCACTCTTTTTCCCTTTTCTTCAGTGATTTTATATATTTTATTGATAGATTGAAATTATGAATGAAATTCATATTTGTAAACATTTAATAATAATTAATTAAAAGAATGACTTCCCATCCAATCCTACTTTATAAAGATAACCATTTTAATTTGCTGGGTATTCTTCCAGAATGTTTACACATATGTATCACATTTATCCAATATATATATTATATATTATATAATGTTTTATATATATAAATGTTTTAAATATATATCTATAAAACAAATGTGAATCATGTTATACATGCTATTCTGCAACATATTTTAAAAACTCAACATTCTGCTTCATCCAATAAGTATTTATTGAACATTTACTAACTGTGGGTCAAGCTCTATGCCAGGGCATGGATATACAAGGATGAGAAATACAAGGATGAGAAAGCAGATATGGTCCCTGCCACAGTGGAACTCACAATGCAGTGGAGGGATATTTTGAGCTTCATTCCATTTTAGTACATACACATTTTGCTCATTGTTTCTAATAATTGCACGGTGTTCTGTAGAAGAGGTTTACCATAATTTACTTAAACATTTGTCTATTGAAGGACACTTGGGTTCTCCATTTTTTCCTATTGCAACTAATATTATAATGAATACCCTTGGACATTTGCATGAGTTTTTCTGTGGGACAGAATCATATTAGTGAAATTGCCCAGGTAGAAGGCAATTTAAAATTTTATGCATATTTAAGAATATACATATTTAAAATTTCAATATTTTCACATTACTTTATAAAAAGGCTGTAGCAATATATCTTCCCTCATTAGCAGCCAGACTTCTGACCCCAGTCCCCCCATCATCTTTGAAATTTTACTTATCAACTATTCTCCCTTTACTTGCATCCACAATCACTCCGTTAACCTATAAAAAAGCTTAGGCAATCCTGCCCCCCTGCCCCTTTTCTTTTTTTTTTTTTTTGAGATGAAATCTCACTCTGTCACCCAGGCTGGAGTGCAATGGTGTGGTCTCGGCTCATTGCAACCTCTGCTTCCTGGGTTCAAGCAATTCTCCTGCCTCAGCCTCCTGAGTAGCTGGGACTACAGGTGCATGCCATCACACCCGGCTAATTTTTTTAATTTTTTTTTTGTATTTTTAGTAGAGACGGGGTTTTACTATGTTGGCCAGGCTAGTCTCGAACTCCTGACCTTGTCATCTGCTCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGGGCCATCACACCCGGCCTGTGATTTCTTAAGTTACCTATCTTTCTCATTTCCTCTTGGCCATTACTTCCCTCAATTCATAATCCTTTCCATAAGGTTTAGGTCCGCATCATAATGCCACAGTGCTCTCAAGGAGCTCCCCAGTCACCTCAAATCACTACGTCCAATGAGGGCTTAGTCTTTTTAACCCCCATGGAACGTTTCTTCCTTCTCAAGACCTTCTCTTTTACAGAAACATTCTTCTGTTTTTCTCTTCCTAGCTTTCTGATGTGGCCCCCTTAATACAGGGAGACATTTGGCCTTTGGCATTCTTTCTTCTCCCTTTATCATTTCCTCCTGATCTAATCTACTGCCCTGGCTTTCATTATTGCTTCTGTATGTGTCTGAACTCTTCATCTCTGGTCAAGGTCATTCTAATAAGCTCTAGACCTGAATTTCCAACTGCAGAAATGTTATACCCAAAAGACACCCTTACGCCAATCTCAGTATGCTCAGAATGGAATTCATTTTCTCCACCTGAAACCTTCCTTATGCTTGTTTTTTTTTTTTTTTTTTTTTTGTGACAGAGTCCAGCTCTGTCGCCAGGCTGGAGTGCAGTGGCACAATCTCAGCTCACTGCAGCCTCTGCCTCCCGGGTTCAAGCAATTCTCCTGCCTCAGCCTCCCGAGTAGCCGGGACTCAGGGGCGTGCCACCACGACTGGCTAATTTGTGTGTGTCTGTGTGTGTGTGTGTCTGTGTGTGTTTTAGTAGAGATGGGATTTCACCATGTTGCCCAGGCTGGTCTCAAACTCCTGAGCTCAGGCAATCTGCCCACCTGGGCCTCCCAAAGTGCAAGGATTACAGGTGTGAGCCACCGTGTCTGGCTGGCTGGCCGGCCGGCCTGCCTGCCTGCCTGCCTTCCTTCCTTCCTTCCCTTCTTCCCTTCTTTTCTTTCCTTTCTTTCTCTGTCTTTCTTTCTTTCTCTCTCTCTCTTTCTTTTTCCTTCCTTCCTTCCTTCCCTTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCCTCCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTTCTTCTTTCTTTTCTTTCTTGCCTTCTTTTTAACAGAATCACTATTCTTCCAGTCATCTAGGCTCAAAATGTCAGCGTGTTTTTACTACTATCTTGTTCTTGACTCTCATTTCCCATCCATTGCCAAGTCAATAGATTCTACTAAGGCTGCATTTCACACACCAGCATCTTACAGAATAATGGGTTAAACAAAGTTAAAAAACATTAAACTGCAATACCTCTTATACCTTTGCATCATGAATCCCTAAAAAGGACAGTTCCTATGCATTTCTCCCCTTATAGAGCAAATACATTTTTATTTTCAAGAGAAATCTATTGAAGTTTCTCAGGAAGTTAAGGAATATATTTTGGTAAATGCATGCATAGAAAAAATGTCGTTCTCTAAAACAGCATTTTGATGTGTCATTTCACTGAATTCATTCAGAAAGAAGCTATATGAAAGGGCCAGATCTGGTGAAAGCCATGCAGAATGGGTGGTGGGCTTCTTCCTAACATTGTTGCTGATTCCAGACAGTAAACATCCGTGCAGTTCATTGCAAGTGAGTTTCATAATTGGTGTAAAAGTAATTACAGATGCACAGGCATTTAGAAATGGGTTAAAACAATTTTGTGCTTACTCAGTATCACTCTGGCTCAAAATTCTTTTAAGTGTTCATCAGACATCTCACTCTGTCTATAATTTGGTCCTGCTTGGGTTTTAAAAATAGGTGTCTTTTAAGTGGTATATATTAATTTCCTTTGAGAGCCACTATTTCCATGTATCATCAAGTAAAAAAAACTGTGCTCCAAAATTATTCAAACACACTGATACATTTGGCTTCTATAAAAAGTTAATTACAAGCTGACATAGATAAACAATATCTTATACTTTCTTTTAGGTCCTAGAACTGACTTTGGTTATATCTACATTAGCCGATATGTAGCTCTAAATTATAGCCTAGAAATGATATTCATTGCTACTATGGCATTATTTTATGTTTCTTTTCACATCAGATAATATTCACAAAATGTAATAAAATAAAAATGTATGAAAAGAAGGAAAATAACTACCTCATTTGTATCTATTTCTCTTAACAAATGATATGAATTTTATGCAATGGCTGTAAAATGTTTAATGCAAGTGACACATTTCTAGCTGCCAGGTGGCATGTTCTGCTGTACAGGAAGTGAGTGCCCAAGGAAGGCAAAGTATGAGTTAGAATGCAAGAAACTGAACACTCCTACTCACACTGGCATGGACAACAGGGAAATTCAGGTTCTCTTTAACAAGAGGCTTGGAAGTGGCATAAGCACAGGATGTGAGAGCTCCAGCTCTGCTCTTCTGAGAATGTTTGGGTTCTTTCCTCTATATGTTGGTTTTATTCTTAGGCTGGGAACAAAACGGCTACAGCAGTTCCAGGTCTCACAGCCAGACTTGACATTATTTAGAAGCAGAGAAGCATCCATTCCTCCAGCAGACCACCCCTCAGATTTCACTGGCCAAAAGGGATCACTACTCATTACTCACCAAGCAATGATAATAGATCAGTTACAGCCTGTAGCTATCAATGGCTTAGGCAATGTGCCACAAACAACAAGACAATAGATCGATGGCTTAGATCAATCAAGACTTAGTCTTAGAGAAGGGAATTAGGTCACTATCCTTTGATTTACTTGAATTAATTTGCACTCTGCTAGCAAGAAAGGAGGGAGAATGGATGTTGAATGTATGAGTGGCCTATGATGGAGTAATAAACCACCCAAAACATAGTGCTTAAAATAACTACCATTTATTTAGTTCATTTTTCTGGGGTCAGCAATTCAGGCTGGGGTCAGCAATTTAGGCTGGGCTCATCTGGATGGTTCTTTGAATTTGTATGGTCTTTCATGTATGACTGAAGTCAGCTGTGGGTTGACTAGTGGCTCTGCTTTTGTGGGTAGGCTGGCTGTCAGCTGGGGTACTTGGTTCTCCTTCAGAAGTTCTCTCATTCTCCAGAAGGCTAACCTGGACCTCTTCACATGGTTGAGGCAGGTTACAGGAATAAGAGGGCAAGTTTCAATGTGCAAGCAAGGGCAAGGAAGTGGATAAGTCTCTGGGCATATTTGCAATATACCATATTGAGTTTGCCATCATCTGGTATGGCAAAATTTAGTCAAAGATCATTAAAAATATATGCTGCTCTCTTTGTCCTTTTCCTTCATTTTACCCACTTAAACACAATAGTACTTTATATAATAGTTTAAGCAAAACTTAGAAGATATCTAGATATCCAATATTTTGGACTTTTTCTCTTCACCCATATATCTGCCTTAGGACCTGGCATGATGTTATTGTACCAGGTAGAATATTTGTTAGGAAAGCCCAGCTTCTCGGCCCCTTGCCTAATGAAAGGCTTAGAAACTTGAGACTTTTTTTCTAGAGATTTCTAAGCAGAGGCCAACATGCCCCAAGGTATTCTTAATTCTTTAGGATAATGCTTTGTGGTGGGAAAGGCCTTGCAGTGGAAGATTTAGGTACACGATGATGATCAAGGCTTTAAAAAAAAAAAAAAACTTTTATTTCAAGTTCAGGGGATACAAGTTCAGGTTTGTTATGCAGGTAAACTTGTGTCATGAGAGTTTGTTGTACAGATTATTTCATCACCCAGGTATTAAGTCTAGTACCCATTAGTTATTTTTCTTATCCTCTCCCTCCTCCCACCCTCCACCCTCCAATAGGCCCCAGTGTATGTTGCTCCCCTGTATGTGTCCATGTGTTCTCATTATTTAGCTCCCACTTATAAGTGAGAACATGTGGTATTTGGTTTTCTGTTCTTGTTAGCTAAGGGTAATGGCCTCCATCTCCATTACCCTTCAAAAGACATGATCTCATGCTTTATATGGCTGCATAGTATTCCATGGTGTACATGGTGTATATGTAGCACATTTTCTTGATCCAGTCTATCATTGATGTGCATTTAGGTTGAGTTCACATCTTTGCTATTGTGAATAGTGCTGCAATGAGCATATGGGTGCGTGTGTCTTCATAACAGAATGATTTATATACATTACTGGATCAAGGCTTTCTATACCTGAAGAGAGGTGGCTGTTTAATTTCATAGATGCATAAACTGAGAGGTATAAAGGATGATATAGTTGCTTAGTCATAGCCATCAAATGTCAGAATTGAAACAGAACCTGAACTGTGGTCTAAATCTTCTGTCCAACCATCTTAAATAGTTGGAATTTGGCTGTTTAATAAACTCTCTCACCCAAAACACAACTAGGAACAAAAGCATGAGCAAAAGGAGCCTTTAACCCTAAAAAGTATGTCATAAAGTCCATGAAATTCACTTTATTTGGAAAAAATCCTCTTCGGATTGTCGATCAGAGTCTGTTTACTCTTATGCTACACACAACTATAACAGTGGCTTTCTTTCTTTCTTTCTTTTTGAGATGGAGTCTTGCTCTGTCACTCAGGCTGGAGTGCAGTAGCGCAGTCTCGGCTCATTGCAACCTCTGCTTTCCGGTTTCAAGCTATTCTCCTGCCTCAGCCTCCTGAGTAGCTGGTGTACACCACCACGCGGGGTGAATTTTTTTTTTTTTTTTTTTTGTATTTTTAGTAGGGACGGGGTTTCACCATGTTGGCCAGACAGGTCTTGAACTCCTGACCTCAGGCAATCTGCCTTCCTCAGCCTCCCAAAATGCTGGGATTACAGGTGTGAGCCACCATGCCCAGCCCTGGCTAGTGGTTTCTAAGTCCACAGTGTATTAAAAAAGTACTTCAAAGGGGGAAAAATAGACATAATTATAAGAGAATGTGAAGTGATATTTGATAATTTGACAGGAGGGAGAAGAGAGAAAACTTTTAAAAATAAAATTCAGGGATTAAAAAATACAACATTTGGAGCCTTTCTTAAAAATGAAAATAGCTCTCTCTATCTAACTGGAATGGAGGGGCATCACTATAATTGTGGTTCATGTAACATACACACATAAATCTATAAGGCAGTATCTATAGACAGTATAACTTATCTAATTGCTGGCTTCAGATACCAGAATTTTGTTACATATGTTAGTGTCCCTCGCATCTCTCCCCTAGTACAAGGATTAACCATAGCAATATTTAGAAAAGCGTCTTAATTTGGAGGTTCATAAAGCAAGAAAAGAATTTATTGAGAATGATTGAGCCTGCACACTACAGAAATAACTTTCCTCAGTTTATGAAATAGCTAACTTAATCATAAAAGATACACCACAAAACACAGCTTTTCACCAACATGCTTCCAATGTTAACTTTGAGCCCCTCCACACCAGAATTAGCAAAGCCCTCTGCTATCTGTGACCTGGGGCCCATCACCATGCTTGGATGGCCACTGTTTAGAGTCTGCATTGGCCACTGACACATCTTCTTTAGGATGGGGCCCCTTTTTGAATGTAAACTAAGGGGCACACTTGCCTCAGAATGTTTGACTTTATGTTGTGAGGCTGAACATCCTCACACACTGTGGCCCAGCTGTTCTACTCCTAAGTATATCCCCAATGGAAACTCTGTCACATGCCTCATAGGACATGTGCATAAGAATATTATACTGCTCATAGCAAAACAAAAACACAAAACAGTCCAAATCCCCTGCCAATGGGATACTGGGTGAACAAACTGATAATGCTTAGACACAGGAAGATGACCGTCTAAATGAATGATTAATTTTAGCCATATAATATTAAGTTAAAAACATTAAGTCCCCAAAGAATACCTATGGTATGTTACTCTTTTTTAAAGTTAAGAACAAGTGAAATAAAAATATGAATTTTGGAATGTGTATAGATGTAATAAGACAATTTTAAAAAGGAAAGCAAGGGAATGATCAACCCTGTATTCAGGATGAGGTTATTTGGTGGGGAGTGGGAGTTGAGATGAGGAGGAGCCATACGGATATAGGTAGGTTATTTCCAAAGCTCTAGACTTTTAAGGGTAGCGATAGTCTCATAGGCACTTATTAAATTATTTAAAATATTAAATTAAATAGATAACTAGGTAAAGAAAAGCAGGACATACATATATCACTGAAGAGAGTGTGTCAGCAAACAGGATTACAATTAATATAATTATTTGTATCAGAAGGCCAATGGAAGGTCCAGGAAGAAACTTAGGTAAATTAGCAGCTGAGGTTTCCAAGAGTCAATTTGTGGGAGATCTGTTCTCTAAATTACCTCGCCTCTGCGCCACTGAAGGAGGACAGAGAGGGAGGTTTGCAATGGTGCCTTGGTGAAGTGGGAAGGAAAGGGCATGGTATTATAAAGTGGTAAATTCACAGCCATCCCCAAATCTTAGCTCACCAGTAGGTTGCCTTGCTAAGTGCAGAGGCTAACTCCATTTCCCCTATTGCACATCAGAAGCTCACCAGAATCCATGCTGTGTGCGATTGTGACCCTGGAACCCAGCCCATTTCAATGTATTTTGCATGTCCTCCTCTGAAGCATGCTGGAGATAAAGAATGATGAACGAGCAAGAGTAAGTTTAATTAGCACATGACTTGCAATATTTCCCCACTCTGAGGACTAACCATGCTTTTTCTGGTTTTGGACGGAATCTTAAATCCAAGTTTTTAAAAGGGTCTTACTTTCTTAATATAGTTTTAGATTAGATTTTAGAATCAGCACATTATGCACGAATCTAAGAAATAGACATTTTGCACAATCCAAGGTGGAGGTTAGTCATCATTTTGCCTCTCTCTACAGTTTGTGAGAGAGAAATTATAGCAACCAGAACAGCACTCTAGTCCTCTAGAGAGCAATGTTTCTGCTAAAATAAAAAGGGAATGGACTACAGGATAAAGATAATTATGAACATACAACAAAGATGCAAACCTTGGCTCCATCTCCTCCTGCTTCCCACCCTGTGCTGTTCTATTCCTTGGAGAAACAGCTAAAGCAAGGCCCTGCCACTTAGCAAGACTCAGCCTGTGGCTCGGCAGCTGTGTTTCTTATACAGCATATTTGCCTTACAGTATTTGTACTAAAGCTGTATCTTTTCCCTTCTCCACCCAAATGAAATCATTTCCTTTTACCATCCTGCAGCTTAATTCTTATGGAAGAGAGGAGTTACATTTGTAAGGGAGACAGGGTGGGATGGGCAGGGAAGGAACAGCCAGCTTATAAACATGCCAGGGCTTAATATGGGAGCCAGGGAGAAAGCTCACACTTGCAGAAAGACGACAGTGCTTAAGGCCTGCAGCCGCTGTGTTTGTGAGGGATCACTTTTCCCATCTTCACCAAGCCAGACCCTGAAAATGTACCACACCATCCTCTGAAAAGAATTCTTGTTAATTAGCTATGTTTTATTTTTGGAGCTTGACAATATCAAAATCTTTTTGGGAGTTAAGCAATTTTCAGTCATGTTAAAGCACAGGATGGAGAAAGTACTCCCTAATTCTCATAAACTTGCAAGAATGGAAAATGGCAAACTTTGCCTTTTATCTACAGCATATGAAATTTGAAAAATAGCATAAATAAAGACTGTATCCAAGCCCCTTCTGTGCCCTAAAAATGGCATTGCAATGTAGAGAATGAATATATGCATTCACATGTATTGTCAGCTGTCTTGATAAAATGATGTTTTCATAATATAGTGTTATTTCTTTAAACCACATTCAATATTCTTGGCTGCCAGATGACAAGATGGAGAAAACAAAATACGTTTTGGGCAGAGGACAAAGACTTAAGGACTGAGTGGGTCATGGGAGGGAGTCAAATGATAGTTTGAAATTTGCTGCTCTTCTTGCCTGTTCTATTTAATTTTTGAGATGAGTGGGGAAGAGACACATAACACAGGAGATTTGGGGAAGACCAGTTGTCTCAATGTTGGCAATGATTTGTAGGGCATTTTGCATTTATTCTAACAACAAAATCCAAGGGCCAAAGTTGGGTGAGTCTGGACAGATAGCAAGAGAAAAAGACTCTGCTACTTCTAAGCAGCCTTCAAGGAGGTGCCCCGGTGACTGATGTTATAAGGGCTGGCCTCTCCAGAATTTACTTTCAAATAGGGCAGTCATGAATGGAATGAGTTATTGGCTTAAGATATTTAATAAGGATGTGGTAGAATCTGAGCATTGTATTCCAAGTCTGACCTCTCCTAGTACACACACACATATATACACACACACACATGCATGCACACACACCCTTTAGTTTTAATTCTGTTTAAGAGAGAGTTTTATTTTTTATCCTTAAATACCATACTTCATGCCAAATTATTTTCAGTTTTGTTACATACAATGGCAAAAGTGAGTAGCTTGAGAAGCTGGCCGGTGGAGGAGCCTTTTGAAGATTCCCTTTTATTAAAGAGTTTAGAGGCTTCGAAGGACTTGAAAATTGTTGACAGTGAAAAAAAAAGTTAATTGAGACTATAAATTCTTAACCCTGTTTATTATATGTTCAAGGAAGATTGTTCCTTTGGCCTCATTTTCATCCATGTCAACACATTTTGGATTGTAAGTCATTTGGGAGTAGGAGCAGTGACTATGTGCCCTAGATTTTCTAAGATATCCCTGAGTTCCCATGTTCTGCTCTGTGGTCCTTGAAATGCCCTCAAATTGATGTGAAGATTTTTCCCCCATAGCTACTCTGTTTACACAGTCTCATATTCAGAAAGGGTCTTAAAGCTTTGCAGTGGGCCAGGCGCGGTGGCTCACACCTGTAATCCCAGCACTTTGGGAGGCCAAGGTGGGCGGATCACGAGGTCAGGAGTTCGAGACCAGCCTGGCCAATATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGTGTGGTGGTGCACACCTGTAATTCCAGCTACTCAGGAGGTTGAGGCAGCAGAATCGCTTGAACAAGAAGGCGGAGGTTGCAGTGAGCCAAGATCATACCTCTGTACTCCAGCCTGGGCAACAAGAGTGAAACTCCATCTCAGAAAACAAACAAACAAACCAAAAACCTTTGCAGTGATGTAGTGGTGTAGGGAGCTTAAACAGCATGTCCTAATTCATAGCTGGTTAGTGGGGACACCCAGGTTAGGGTCTCCTGTTGCAGTGCTGAACTTACAAGTGGACACTTCAGTTTTGTTGCTATCAGTGATCCAGAGGAAGGAGAAAAGTCCCACAAAAGCACCAGAGTTAATTTTATTTGTAAAAAATTGTGAGCCTAAGCAGTTTTTCTTGATAAAGTAAAATTTACTCCAGTGTTGGCAGGGATTGTACAAATGTCTTATTTTCAGGAAATGATCTTCAGCTCATAAATTTTGCCAAAACATAAATATAATTAAAATATATCCCTAAGTGAACTTAAAATCATTCTGGAACAACAAAGTTCCCCAGTGAGATGAGATGTGCCTTTTCTCCTTTTCTTTTTTTCAGTTAATCATTGAGAATTAAATTTTGCTTATTTTCTTTCCCTCTTTAGTTTTCTTGATAACTTCTTCTGCAGTTCAGTGGAAGAATCATCTTTTTTTTTTTTTTCATTCCAATGGAATACTACAATGATTTAAGAACTTTACTTGCTTCAATTTGGATCTTATGCCTTAATCCACCCCCGGCCTCTCCTCCCCATACACACACACACTGGGAATGCGGCTCTCTGAGTCGCTGACTCAAGCAGCAGAACGACATCTGCTGTGGATGTTCAGCAGCACAGCTGACATGTATTTGAAAAGTGAAGTGTTGGAGTCATTTAGGGAGCAGAGCAATTTCCTCTGTCAGAGATGAACACTTGGATTAACAGAGAGTACTTCATTCCCATACAAGTTGATTCTGAAAGTGCCTGAAGCAAATCTCTTGACCCTGAAGTTGAGGCTAACCACTCCTGGGCAGGGTCAGAAGTTTAAAAAAATGCTGTTTTAGAGGTTAATGGGGTGAGGGCTATTTCCAGCTGAGTCTTCAAAAGTGCTTCAGACTGCAATTAGCATTTACTGTTTGCTTAAAAAAATGACTTCACTCATTCACAGCCATTGATTCTTATTTATGAATATTACTTTTTAAAGAGACATTAAAGTAATATAATTAAAATACTTAATGTTTATCTTTAGTCTTTTCCCTTCCTGCTCTAGCAATACCAAAGTTCTTAAAATTTTCTGAATAAGCTATGTCATTTTGTTGTTAACCTTTAAACATGCTGTTTTTTGTTTTAGGAAAACTATATTTTCCCCTGCTTCTCTTTGCCTGGCTAATTCCTACTCGTCTTTTAGGTCTTGAGCTTCCAGCTGGGTGGTGTGTTGCTCCTGTGAGCTCCCTGGACCCCACCCCTTTCCTTACCCGCTACCCACCTTGTCACATTTTTTCTTGTCTACCAGGACCTTCCACCACTGCACCATAGCTATCCACTTGGCACACATTAAGTACTCAACAGATATTTGTTGGATGGATGGATACATGAAGAAAGGAGGAATAGAGGAATGAACAAATGGGTAAATCACTTTCCAATTAGTGGAGGTAGAGTTGCTTTCAAATGTTATTGTGCTTCACAATCACTTGGGGTACTTTGATAAAAATGTGTATTCTCAGGTTCTAACTGCAAGGATTTTTCATGACATATAGGGGTATATGTGGCAAGCCTCAAATAATTCATGACTACAGAACATAATATGTGAGACAGAAAGCGGGGAAGAGCCTGCCAATGAGCCTGGGTTAGATCTGCAGTACAGATGATGGGGAGCCAGCAAAGGATTTCAAGGATGGTCACATTTCTGGTATCTGTGTAGAAATTAGATTCAGCATTGATCTTCAACCTTGGCTGCATGCTGGAATTACCTGAAGAACTTTAACAAGTAAGTAATGATGCCTGGGTCCACCTCAAGAGGTTTGTATTTAATTGGTCTGAGGTGTGGCCTGGGCTCTGGAATGGTGTTAGAGCTTCTCAGGTGATTCTAATAGAACACCAAGATTGAGAACTACTAGAAGAGAGGAGAAAATTCATCCATACAATTTGGCAATCAATCAACTCTCCTCTGACATCTTTTAAGTATTGTGTATTGGCAAAAAGCAGTTAAAAACCACAATGCGATATTACTGCATACCTACCAGAATGGCTAAAATAAACAATGGTGATAACATTAAATGCTGGAGAGAATGTGGAAAAACTAGTTTTCCGATATGTATGGCGTACGTATGGTGGGAATGAATGGCAATTTCTTAAAAGCTAACCATGCAACTATTATGTGACCCAGAGTAGGGTAAATGCATCTGATCACAATAACTTAGGCATACTCTGATAATGACCCTGTGTGGCAGAGACACCTGAATGTATGTTCCTAGCTAGGGAAGCTGGGAGCAGACAACCTGAAGATTAATTCTTTTTCTATGTGGAACGTCTGGGTCTCCGGCTCATCCCATGGAACACCAGCCACACAGGATATTGAAGCTCCAGGTTTTGGGTTGAATGAAGGTTGCCAGGTGGAAGTTTTAGAGAAAGGGTGCTAAGTGAAAATGCTGTAATAAACTGGATGCTTTTTGCAAGCTGTTGCAGTTTTCTTGCCCAGCCCACCTCCACTGGGCTGTGTAGTTCTCCTGTCTAGCCTGCTGCCACGGGACTCTCTCCCCTAAATATAAGCCCTAAATAAAACCCCATGTCTCATTTGCTGTCTGAGTCTCTTCTTCAGCCTCTTGAACCTGGTGCCATCTCTATTGAGGTTAATAGGTGTTCAGCCTGACACCCAGCATTTGCACTCCTGGCATTTATCCCGGAGAAATGAAAATGTAGGTTGGCAAAAAAATAGTACATGAATGCTCATAGCAGCTAAACTGTAATAACCAAAAATTGGAAATAACACAAATGTCCTTTAATGGGTAAATGGTTAAACAAACTGGTGTGTCTATATCATGGAATACTCTTCAGCAATAAGATGAACAAATGATTGGCACATGCAACAACTTGGAGGGATTTCATGGGCATTATGCTTAGTGAAAAAACCAATCTCAAAAGTTTGCATACTATATGATTCTATTTATATAACATTCTTGAAATGACAAAATGATAGAAATAGAGAACAGATTAGTGGTTACCAGGAGACAGTGAAGAAGGTGGTGTGAGTACAAAGGGGTAGGCCCTGCTCATTGCTTTATGGCAATAGAACCATTCTGTATCCTGATTGTGATGGTGGTTACAGGAATCCATACAGGGGATTCAATTTTGCAAAAGACTATACTTACTCACACTTACTTGTTCATACCCCCACACATAATGCCCCCTCTCCCCAACTGAGTGGCAGGTAAAAACTGCTGAAAACTGAATGAAGCCTGTAGTCTAGTTAGCATTATTGTGCAAATGTCAACTTCCTGGTTTTGATATTGTACTACAGTAATGGAAAATGGTAGCTTGGAAGCTTGGGTAAGAGTTCACTGGACTCTGTGAACTCTTTTTCTGACTTCCTATGTGTCTACAGTTATTTTAAAATAAAAAAATGATAGTTGCATGTTTTTATTTACTGGCTGTATTTTAAAAAATGTCACGCATATATACATACTTTAATTCCATGGCTAGACTGTAGATTTTAGTATAGTGGCAACGTCTCATTGTGCTCATTCAAGTAAATTTAGCTCAATTCAGTTAAACTCAGTTCATCTCAATAAATATTTGAGGGCCTACTAGACACAAAAGGAATGATGTTAGTCCTCTTACCCTTAATCTTATATTGTCCATCCAGACTATGTACACTGATAGGTACACAATAAGACCTCAAAAAATGGCATCTAGTGATTGGACAATTGCCTTATTAATTTTTATGGTGCTGTGTGATACATCCCTTATTCGTATAAAGGCTGCATTTCTTTTACTTTGTTTTCTTTCTCTGAAAAGACCAAAATTTATGTAAGGAAAATACATTTTCCAAATTAATTTCTTATACCTCATTACCAGGATTGATGAAAACATTAATATACTCCACAAATTTATTTCAGGTTTTAAGCTGTAAGCATGTTTTAGTATATTATTTTACATCAAAAGACATGTGGTGCCTTGAAACCAGGACAAAACAGCTAGACTACCAAATAATATTCTTGGTCTTTTTTTTTTGAGATGGAGTCTTGCTCTGTCGCCCAGGCTGGTGTGCAGTGGCATGATCTCGGCTCACTGCAACCTCCACCTCCCGGGTTCAAACAATTCTCCTGTCTCAGCCTCCTAAGTAGCTGGGACTACAGTATTCTTGGTCTTTTTTATTTTTATTTTTAACAATCACCAAGCTTAAATTTGTGGGGAGGAGTGCAGTTTCCTTAATGTTTTCTACTTGGTTCAACATTCCCAGACAGCAATTACAAGGCAAATATCATTTCAGTAAATGAGAAATTCTTGTTTTCATGTACTGATTGGCTTTATGACACACTAAGGTTAATTGGGAAGCTTCTCAGGCTTATCTGAGTGATAACAAACAGCTGCAATAGATTGCACTCCCTTATCCCCCACATCATTTTGACAGAGCAACACCAAAACAAAACCTCATGAAATGTGTCATTAAACCGCACCGCAAACCTGGTTGCAATTGTGTCTGAGATAGCATCACAGGAAGCCAGAAGGAAACCAATAGCCTGAGAGAAAATGTTTAAATTAGCAAGGGTAGCCAGCCACCCTAGACCACAGCAGCTATAGGATTTGGTTACTGGAGTTCCAATATATGGCAATCTAGATAGTTCTTTATCTCACATGAATACATAGTGCTACTCCAAGCAAAAATATACTTGTCTAATGCAAATGCCCTAAATGCCAGATTTTTATATCTCTAATATAAGAATCACATTGCTGATTTCACTAGTAAAGTAAAAATGGATATCTTTGACTGCTTTGAAGAGCTTATAAAGGGCTTTACTTGCCATAATTTTTAAGTAACAACAGCTAATCTGTTTGAGCACTTATTAGAGCCCAAGCACTGGACTGTTTCTCATGTATCATCTCAGTTAATCCTCCCTGTAATCCTAGGATAGAATTATTATGCATGCATTACAAATGATGCCTAGCACACATACGAATCTTGTTCAAGGTCACAGAGTCAGTAGGTGTTAGAGCCTGGACTTGAGTCCAGGTACATCTTTTCCCAAAGACTCACTCTTATACTAATGAGTAGGTTAACAGAGAATGTTTTACAGGGAACTCATTGAGAGAAAGTTGCCTGGTAGAGTAGTTTTTAGGTCAGCAGATGTTTTTCCAGTTCAGTTGCCAGTTGGCCAGGTCACCAAGTGGATAACCAGTAGTCTCTCTGGTTATCTATGTGCATATTTGGGATGAGATTTCTTCCACTGTGTGGTATGATGCTGCTGCAGTGTTTTTAGGGAGTGTGTGGGTCAAAGCAACTTGCTCAATGATGGAAAAAAAGAGTTAGCCTGTAATGCTTTAGTTGGAAGATGGATATGTGCCATTGGTGTCCCTTTACTGGCTTCTGCTCATCCAGAGGCTCCTCTTTCTTGCTCCTACCTCTTTGTCCTCTTCCACACAGTCTGGTCCAATCATGCTCTTCATTTGGGCCTTGAAGGGGCATATCAACTAGTTGTTCATCCTGCTGTTTGTTTTTCAAATAGCCCCATTTGTGTCTCTTACCTTTCTGGTGTACAAAGCAGGGAAGTGGAGCAATAGCTTAGGACTGCCGATTTGGAGTCAGACAGACTTAGGTTCAAATCCCAGTATAGGCACTTGCTGACACTTACACATGAATTTTGGTCAAGCCATTTAATTTCCCTGAGCCTCCGTTTCCTCATCTGTAAAATTAAACAATGACACAATCTTATTGGGTTGTTGTGAGACTTAAATGAGATAATTTATGTAAAGCTGAATTCTTGGTATTGGAAGGGCTCAAATGTTAGTTATAATATGTTAGTTATAAATAATTGTCATCAATAGTTCAACCTCACTTATTTTTAATCCATTATTACCGTTCTTTCCATAATTTGGAATTTCTTTTTGCTTTGCTAATCTTTGAACTGCCTTAGCCTCAACATACTACAGTCACCCTTCTGTATACATGGGGGATTGGTTCCAGGATACATTCCCCATCCCTCTTCTTGGCTAATACTGTACTTTTGTTAGTGTTTGGTTGGGAAAAATCCCAGTAGAAGTGAACTCTCATAGTTCAAACCCGTGTTGTTCAGTGGTCAACTGTATTTAGTACCATGAAGGCTTTCAAAACTTACATTGATCTATATTCCAGTTGTCAAGCATGTAATAATCTTCACTTTCTTAATTTTTCTTTCCCTGATATGCTATTTAGCACCTGTGTAAACCTATGCAGCTGTGCTCAGCTATGTATAAATGTTTGCTTATGTGCTTCTGTTATGTTTATTTATGTGATGCTGTGGAGAGCCAGTTGCTCTATTAAATTATAAGCTCCTCAGAGGCCAAGGACCACACTTTCTGTTTCTGCTCCAAGTCCGGATGTCCTTCCAAGGACGGATTTTAGGAAGGCTGAAACTCAAACATACAGAACAGCTTTAATAAGATGTTAATGACAAATTTTCAAACATTGTGTTCTTTTCTAGGGTATCATCTCTTAAAGTAATTTCAGTCATAGCTTATAGAATTGTTCAACTTGGGGGCCTTTAGTGGGTGACTTTTTACATTTAAAAATTAATAAGTCTACAATTTGAGAAACAAATGAATAATAAAGAATAAAAAGGATTTAGTAACTGTTACTCTCCAGAAAATTTCAGGCCATATTTCCTTTGATCGGCTAAGTGATTGATACATTAGATTAAGAAAAGATCAAGTCATGCATAATGGAAATAATAATAGCTACACTTTTAGAACACTTAGTAGATACTAGGTACCTTGCCAGGAGCTTGGTTTGTCTTATTCAATCTTCCTGCCACTATTGTGAGGTAGGTACCATGTTTCTTTCTGTTTTGCTTATAAGGAAACTGAAATTAAAAATGGTGTGACTCATGTCTGTAATCCCAGTACTTTGGGAGGCCCAAGGATCACTTGAGCCCAGGAGTTCCAGGCTGCAATGAACTATGATTATAGCACTGCACTCCAGCCTTGGTGGAAAAAGAAAAAAGAAAGGCTACCCTTTGTCCAGGATGCAGCTGAAAAGTGATGGAGCCAGGCCCAGCACCCAAAACCCATGCTAATCACTAAACTTTGTTGCCTGCCACAAAAGAGAAGGAGTTTCATAGATGCATTACAAAGATAATTATAATATTCTTTTTCTTCTTCTACAACACCATTCCCTCACCCCTCCACCCTAAGGAAAGGAAATTCTATTAGTATATAAAATTTGATTAATGTAGACAAATACACTGCAGAAGTTTTGGATAGTTTGCAAGAACAATTTAAAAAAAATTATCTCACTGGCTGTTTGCCTTCATATGCTCCTCTTCTCCAAAGGCCCAGCTCTTGCTCACTGCCTAACAGTGGAGTCCTCAGGGAGTGTTGTCTCTGTCAGAGTGAAGCCATTAGGGACAATGTCTCATTGCCTTTCAAGAGGACAGACAGGAAATATATTTTGCTTCCCTCTCTCTTACCCAATCCTCTATCTTTTCCCTTCTCAGCTATATTCTTTTGGCATAAATAAAGGCTAACTTCTCCCAGGAGTTCAGTAACTTGAGCCCTCCCCAAGCACTGTCTGAGAAAGCTGGCTCTAAACACACACACACACCACAGGCAGCTGCTTGGGGGCCCTGTTCTTTGGCAACATCACAACTCCCGCCTGCTTTTTCTGGATTTCAGGACCCAGCAATTACAAAGCCGGCCTCTGGGCCTGCACGTAGAGCATGCTTTAATAGTAAAAGCATCTAGTGGGTCTCTTCCAACTTCGAGCATTCTGGGAGTCTCTCAGCCTTGAATCTTACAGGGTCCAAGAACCTCTCAGTGGAGTCAGGATTATGCTGTAGCCAATCTGTAGCAGAATTCTTACATTTGTTCTGTTTTACAGCAAGGGTACCAAGAGAGCTTCCAAGTCACTGCAACATGCTGTGCATATAATGTGAAGGAGGAGCGCAGAGGTGGCTGTACCTGGGGGCTGATGATGCCTGGGCTTCGGGCTGCATAAGTGCCTGGATTCTGGCAGGCAGCGGCCCTGTTGCATTCATAATTCATCATTCTGTCTTCAGTTTCTTAAACATGGCCTCCCCAGTTGTATAATCTTTAAGCCACTTCGAACATTAACCTGCCCCTGGTTGAGTGTCTTTTTGAGCAGTAGTTCAATCTACGCCATGTTTGACTAACATGTTCCTATTGCAAGACATTGAAGCCATTGAAGATTAAATATAAGAAAGCTAGTGCAAATAATATGGAAAGTTAGTTTTTTTGTCTTTTCATGTATGATCATTTTTCTTATATTTACCATTTTCTTGTAAGCATTTTTTTCATATTAGCTCCTTGAATCCTCACAACAACCCTAAGCAGTAAAATCTATAATTACCTCATTTTTGAGATGGGAATACGAAGTTAAATAACTCACACTAGGGCTCTAGCCAGTAAGTGACAAAGGCTGGATTTGAACTCTGGCAGTGCAGAGCATATCCTGTTAGCCACAATGTACAATGCTGGTGTTGACTGACAGCTTGTGTTTCGCCTCCATCTCTCTTGATGTCTTTGTTCTTTGTACTCAGTCAATAAACTTCTTTTTTTTTTTTTTTTGAGATGGAGTCTCACTCCATCGCCGAGGCTGGAGTGCAGTGGCGTGATCTCGGCTCACTGCAACCTCCACCTCCCCGGTTCAAGTGATTCTTGTGCCTCAGCCTCTCGAATAGCTGGAATGACAGGCATGCACCACCATGCCTGGCTAATTTTTGTATTTTTGGTAGAGATGGGGTTTCACCATGTTGGCCAGGCTGGTCTCAAACTCCTGTCAGTCAATGAACTTCTTTTTGCCTTACTCTCCCCATTAGAAAATGTTATCTCTCTGCTTCTCGGAAAAGAGAATGGATTAACATAATACAGGAGATAGTGTTTAATATAGGAGACAGCAATAAAAAAATCTGGAAAATGTATTTCAACTGAAATCCAGAGAAGGTAGTGGCTTGCCACTTGGCAATGGAACTGGAATTAGACTCAAGTCTCTACCTCTCACTACTCACCATGGAGGCTCTTGTACAGAACATACTTCCGTCGTAATAAAGTATGGACTGGTATAGTAGAGTAAGTGAGGAGTGTAGAGAAGAATTTCTATTTGTGTTCAGTTAAGGTTTGATTTAAACCAGTGTTCGTACCTTAATTTGAAAAAGTAAATGTAATTTAAATATTTCTTTTTTCTTGTAAATAAATGTATATTTGTTCGCATCAAAACAAATTTCAAGTTGCACTGCAAAAGGGAAGAGTAAACTTCTGTAACTCACATCATTGTTTTTTTAAAGAGCCATTTAATAAATAGTCTATATTTCAGTTCAGTATTATTTATGTTTTCAATATGTCCTTCTATAAAGTGTATGAATCAGTTGTTGTTAGTTCAGACAAGATTAAAACCTTTACTCCCACATGAAGAATGAAATGTCAATTTTTCTTTTGATATTTAGATGTTGCTTACAGAATTATAGTGGCTAACTGGAGTTCCATCCATAGTCAAGGTCATTTCATTTTTGAAACCCTCAGGAAACACATTGTATTATTGTTCTTGAACCACTTGAACATTATAGGTTGACTGACTTCAAAAACTGTATCATGGGTAAAAAGCATAAAGTTGTATTCTTATGCTTTTTTTTTCAAGTAATCCTAGATTTTAAAATGATAGCTTCAATTTTGTATGACAAAAGCTTCCCCAAACACTAAACCTTTTAAATAAATGACATTCTTTATTATTTTCTCTTTTATTCCCTACGGGTAATTGTGAAATCTCACAGTATCTTCTGTTAGCTCTGCTTTTGCCTAACCCACACTAAGAATTTCCTTTTTTTTTTTTTTCTCATTGCACAATTATTCCTCCCTAAGCTTTTGGGCTACAAAGGTAACTTGAAAGTCAAGAGACACAACTGTCCTGGTCAGATTTCTGTCAGCCTTCTGAGCCTTCTCACCTCCAACCCTTTGGCTTCTCAGTCTCCTTGATCCTAATGAGGAAAGAAAGAAAGGAAATAATATCTCTTTTCTACCATAACTTCTGCTCAAGATGCCACACTATGCTTCTGGTTTCTTTTCACCTTCACATTCTTAGAAGGAGGGGTGACATTTGTTACCTTAGTGTCCTCATCTCTTTTGGTCCTTTGGAAATTTTTTTATTTTTTATGACAGCAGCACCCCATTCTCACAACTCTCTGCTATGTTTACTTTCTAGACACTACTCATATCTGGTTGTCTTCTTAGCTCTTGAACTACTTTTTTTCCTCCCTGTATCCTTTGCTAGTACCTCTTTCCCTGCCCAAATCTTAAATGTTATCTGAATTTCCAACCTATTTGTTGTTCTTTTCATCAGCTTTGCAAGTCCCCCTGAGTGATGTCACCCAATCTCTTGGCTTGAGCGCCACCATTTTCTCTACAATTCCTGCCTCCAGCTTGATCTTCTCATCTAGGCACCAGACACAGACTTCCAAATAAGTGTGGAACTGCTTTAGCTGGAAGACCTGAAGCACCTCAAACTCAGCACAGCCAGAGCTAAAACCATTATCTTCTTTCTAAAGCCTGTCTTTTGATTTGTGCTTTTTATGGACATTGGTAAATGTTCTCACTGTTGACAGGTCTATTGCATCTTAAAACATCAGAGTCCTTCAAGTCTTCCTTCTACCTCACTCTAATATTTAATCATTTCAGGGATTCTTTTCCCAAATCTTAAGAAAACTTCAGACACACCGAAATTGAGGGATGTTCTACAAAATATCTGACACTCCTAAAGAGTGTCAAAGCCAGTAAAAACAAGAAAGATTGAGTAACTTTCACAGATTGAAGATGACTAAGGAGGCACGATGAATACAAGCAAGGTCATACCCTGGACCAGATCCCTTGAAAGTAAAGGACATTAGTGGTCAAATGTGAACGAAATCTGTAGTTCGTTAATGGTAATGTGCCAATGTTAATTTCAGTTTTTTACAAATGTTCTGTGGGTCTAGCAGATATAAAGATTAGGGAAAGCTGGGTGAAAGGCATAAGGAAACTCTATGCTATCTTAGCTACATTTCTACAAATCAACAATTTTTCTAAAACAACAACTAAAAAGCAAAACAAAAAGCATGGCTTCCCACTGTTTATGCGGTGTTTCTCAACTTATTTTGAAAAACTCATCTGGATTTTTTTTTTTTTTAATATATGTGGCTGGGCCCCACCTGGGATATTTAGATTCAGCAGGACTGTGGTGGAGCCAAGGAAGCTGCATAATTGTCAGGTGCCACAGGATATTTTTAAATACTCCAGGTATTGCAAAATTACTTGTCTACAGGACAAACAGAGCTTGCCTATGACATTTCCTTGATATAGACTTCTAAATTTTTTTTATAGAGAGCATTGCTCAGATATCATAGACAGCCAGAATTATCTTTTGTAATAAAGAATATACTACTGGCTGGGCACTGTGGCTCACACCTGAAATCCCAGCACTCTAGGAGACCGAGGCAGGTGGATCACTTGAATTCAGGAGTTCAAGACCGGCCTGGCCAACATGCTAAAACCCTGTCTCTACTAAAAATACAAAAATGAGCTGGAGGTGGTGGTGCATGCCTGTAACCCCAGCTACACGGGAGGCTGAGGCAGGAGAATGGCTTGAACCTGGAAGGCAGAGGCTGCAGTGAGATCATGTCACTGTACTCCAGCCTGGGCAACAGAGCAAGACTCCATCTCAAAAAAAAAAAAAAAAACAGGAATATACTACTTAATAAGACTGAAGTGATCCTGAGTGTAAGGAATAAAACTGATATGTTGAATAGTTTTTCACTTAAAGAATTGCATGAAACCCATATATTTTATTTTTAAATATAGTATATTGTAAGTTTGCCACTTGATTTCAATGACTCTAAAGGCTTATTAAATATTTATGAGTGAGGGAATTATTTCCACAGCATTTTGCATTCCTTTTGCTTTGAAGTGAAAATTTGCACATGATACATTTCCAGCAGGATTTTCATATGGTCAGCGTATACTTGCAAGCTTCTTGGGAAATGGAAACACTGCAAGGTTATTTCAATAAACAGGAAAAAAAAATGCCCAACTTGGAAAAATGTTACAGAGATCTTTAAAAAACATACGAGTAATGAAAGAGTGAAATTAGAGAGGTCATGTGTGTATGTATATGTCTCTGTGAGTGTATGTGTGCATGAAGCCTCTCACTGGGCTGCATGAGATTTATGAGGAGATGTCAGGAGTTCCTTGGACTCTCTGAAATTGAAGGAAAATACATGTATGTACATATTGTTGAGGATTCTCAATAAGGACAGTGAGCAAAAAAGCAGTCAGAAACACTGACCATGGGGAATCTTTTGAGAAGCAATGGCATAATTTTAGGTGGCCTAAATTATTGTTTTAAATCAAATAAGTAAAAGGTAGAGGCATTGTGATATGATCTTGTAATAAGACCTATTGCTAATGTACAGCTTATTTACTTTTCCCAATAGAGGATTGAGAAAAGTCTTAGAATGCAATGAACATTTCCTGAAATGATCCAAACTGAAGCCTTGGTATAAGAATAGGTTATTAAAATAGTTTGTCAAATGTTTATTAAGACCTTACTATGTACCGAGCGAAGTTCTAGAGCTTTAGTTCACATTAGTGAACAAAACAGACAAATATCGATCTCTAATCAATTTTACATTCAGTTAGGGAAGATAGACCTTAAAGAATAAACAAAATAAGTAAATTGCATAGTATGTTAGAGTGTGATATAAATGCTATGGAAAAAAATAAAAAAAAAAAGAGCAGGGTAAGATGGGTTGGACCAGCCACTTGGGGGTATGGAGAAGTTGCATATTAAATAGGGTGAAAGGATGGACCCATCTGAATAGGTAAGATTTGAGCAAAGATTCCAAGGAGGTAAGAGATTTAGCTCAGTGGATCCTGAAGTGGGGATAGGGGTGGGGTGGTGGGACATTCCAAGTAGAGGGAAAGAGCAATGGTGACATTTGGGGAGCTGTGAGGAGGCCTCACTGTGAGGAATGAAGTGATCAGTAAGCTAGGAGAAGAGTAGGAAAAGAAGCCAGAGGAGTAACTGAGGCAGTGAGGGCTTTGCAGCCACTGTAGGACTTGGGCTTTCTCTCTGTATGTGATGGGAACCAGCACAGATGTTTTTTGTTTGTTTTATAGATCCACAAGTATAAACTTCAATATACTTTGGTCAGAAATGGATAAATCAAGTCAACACAAAATATGTAAATCCAGAGGGAATTTGATAAAATTAACATAACAACCAGCTCTAAAAGTAGACAATGTGGCTGGGTGGCTCATGCCTATAATTCCAGAACTCTGGGAGGCCAAGGTGAAAAGATCACTTGAGGCCAGGAGTTTGAGACCAGCCTAGACAACATAGTGAGACCTCCTGTTTCTATAAAAAAAAAGAAAAGAAAAAATAGCTGGGCATGGTGGTATATGCCTTAGTTCCAGCTTCTTGGGAGGCTGAGGTAAGAAGTTCGCTTAAGCCTAGAAGTTTGAGGCTGCAGTGAGCTATGATTGTACTACTAGCACTCCGGCCTGAGCTACAAAGTGAGACCCCTGTCTCTTAAAAAAAAAAAAAAAAGTTGAGAATGCATTTGCTTTCAAACACACAGGGGCAGTTTATAAACATTGTCCATGTATCAGACCTCAAATAAAGTCTCACCATGTTCAAGAAGAGACCATGCACAACATATTATCTTACAACAGTGCAACAAAAGTAGACGTTAACAAGATTTGAATAGTTTTTTTCTTAAATATAAATATTTAAAGATTTAAAAGCACGCTTTCACATATCTCTTGGTTTAACAGGCATATCAAACCCGAAATTACAAACTATGGAAAAATTAACAACAGAAAATACAGTGCAGTTCGAAAGTAGCCTGGCCAACATGGTGAAATCCCATCTCTACTAAAAGTACAAAAATTAGCTGGGCATGGTGGCAAGTGCCTGTAATTCCTGCTACTTGGGAGGCTGAGGCAGGAGAATCACTTGAACCTGGGAGGCAGAGGTTGCAGTGAGCTAAGGTAGCACCATTACACTCCAGTCTGGGTGACGAGAGCAAAACTCTCTTTCTCTCAAATAATAATAATCATAATAATAATAATAATAAAATAAAAACAAAAACATTGCACAGTGAAACCCATATGATATAATTAATATGCTGCCCAGAAGTAGTAAATTGAATTCAAAACCTCTCAGGATATCTTACATTGAAATTTCAGTATTATTTGCGAAGCAGTGACCGGCAAAACTGGGATGAGAACATGCAAGTCAACTCTAATGTAGCTGAAGAAATTGAACTTTTGAATTCAGCTTACGTTACCAGTAGAAGTGGCTTTTCTTCTTTAACAGAGAAAGCATCTCCCCTGGCTTGAAGAATCTGCACTAGCCTCCCTTGAGGAAAGAATTGTCTTGCTAGGGAATTTGTAGGACCGTAGGTTTTTGTTACTGTTGTTGTTTTAAAAGAGAGAGTCTCGCTCTGTCACCCAGGCTAGAGTACTGTGGCATGATGACAGCAGAGGATAACAACTTGTTTCAAATGAATCACTGGCTGTTGTGTTGCAGAGGACACTAGGGGGCAACAGTGTGGATGCCAGGAGACTAGGAGGCTATTATAGTAACCCAGATGAGAGAGGACAGCAACTGGGACAGTCCTGGGAGCAGTAGGGGTGGTGGAAAGTAGTCACTCTTGATATATTCTGTATGTAAAGCCAGCATGATCTCCTGATTTGTTGTGAGGGGATGTGGGGAGAGAAGAAGAGTCAAGGATAACTCCAAGGTCTTACCCCACAGAGATGGAGAAGATTGCAGGCAGGAGCAGCTTTGGAAGGAAGATTACGAGCTCAGTTTCAAATGTTAAGTCTGAGAAGTTAAGCTCCAAGTGGAGATATGGAGGAGACAACTGGCTATGTGGGCCTAGAAATTTGGAGAGAGATCTGCCTTGGAGATATAAATTTAGGAGTCATCAGCATGTAAATGATGTGTAAGGGTCATAGGACTAGAGATCACCAAGGGAGAGAGGGTAGCTGGCAAAGAGAAGAGGCCAAGGACTGGGTCTTGGGGCTCTTTCTAACACTAAGTCATCAGGGGGAAGCAGAAGAACCAATCAAGGAGACTGAAAAGAAGCAGCCTGGTAGGAAGAAGGAAAGCCAAGAATGTGTTGTCCTGGAAACCACACAGAGTAACTGTATTAAGGAAGAGTGAAAGACAGACTTTGGCACATACTGACCTGACAGATCAAGTAAGATAATCAATGAGCACTGACCAATGGATTCAGTAATATGGCTATTACTGATGACTTTGTCAAGAACAGTTCAGTTGAGTGGTAAGGGCAAAAGCCTGATTGAGTGGATTCAAGACAGAATTTGAGGAAAGAAACTAGACAGCCAGGTGATTTGCTGCCAAGGGGAGCAAAGGAATGGGGCAGGAGCTGGTAGGAAGGTGAGGCCAAACGAGTGTGTGTAGTTTTTTTTTTTCTATTTAAGGTAAGACAAAAAATAGCGTGTTTGAGTCCTGGTAGAATGACCCAACAGACAGTGTAAAATGAATGGTGTTGGAGATAGAGAGGAGAACTGGCAGATTGATATTCTCCATTAGGCAAAAGGGATGGGATCTATTACATAAAGGGTGGGTGGGGCTCACAGAAAAACGGAAATTTCATCTATGGAAGAGACGGGAACATGGAGAATGTAGGTAGATACTTTGGTAGAAGCCTGCGGATATTTTCCTCTAACTGCTTCTATTTTCTCAGTGAAGGGAGAATTAAGGTGAGCAGCTAAAAGCAAGGGTAGTCCAAAAATTCTATGAAGATATAAATATGTCAGAAACTTATTACTGTGGTGCTCCTTCTATTAAACTGTTTATTTGCCAGAGTGTCACTTGAGTAGAATTAATGAAAGTGTATTAGTCCATTTCACACAGCTATAAAGAAATATCTGAGACTGGGTAATTTAGAAAGAAAAGAGGTTTAATTGACTCACAGTTCCGCATGGCTAGGGAGGCCTCAGGTCACTTACAATAATGGCAGAAGGCGAAGGAGAAGCAAGTACCTTCTTCACAAGGTGGCAGGAAAGAGAGAGTGTGCAAGGGAAACTTCCACTTATGAACCATCAGATCTCATGAGAAATCACTCACCATCACAAGAACAGCATGGGAAAAACCACCCCCATTATCCAACCACCTCCCAGTGGGTCCCTCCCTGGACACCTGAGGATTACAGTTCCAGACGAGATTTGGTGGGGACACAGAGCCAAACCATATCAGAAGGCAGAAGAAGTACCATAATAATGTGATACAAAGAACATCTGCCCTGTGGTACTCCTGTCTAGCTGTTTGATATATAACTAAATGCTACTCTTCCCGAACTCAGCATACAGGGAGGGAAATTTCAGGGCCTCCATCCCTGGGAGAATATTCTGAAAGAAGGGTAACCCTTAGCAACTGCACAAACTGCTCCCAGATGACTCACCAGAGAGCTTCTGGGTGGAAATCCAGTGGAAATAATGCAAACACATTCATCTTGACCCCAGAGGTCTAACTCCACCCAAGGCTTAAGTTTCTTTCCTCTGTTGTACCCTGTGAGTTTCCTGGAGCAAATATTCATGCTTAGCTCCCATGTCTCTTCCCATTTAGCTGTCAGTTCCACTTAGGTATGCAAAGGCACTCAGTTCTCACTGCTTTTAAAATTTCATGATTTTCCCCTGGCGTTCTCCTGAGATTCCTCCCAGTATTGCACCTTCATGCTCGCCTTCATAGGCGAGCAGCATTAACGCCTGGGCTTCCTGAGCATCAGCAGCAGCTTTCAAACAGAGAAGCACATTAGGAAAGCGAATTCACTCAGTCATTTAACTGTTCATTCTTCTATTTAGAACTTAAGAATGTACAAGTCACCTCAGACATTAAGGCCTTCTTGAGAAACGAGGGGAATATTTAAAAGCAGTTTTAAAAAAGAAAACATTAGCTCTGCAATTTTTATCTGTGTCTTGGATAGTTAACCTACAGAGAAAATTAATTTCTTACCACATTATATTTCTCTCTCTCTCTCTCTCTCTCTCTCTGTGTGTGTGTGTGCGTGTGTGTGTGTGTAAATCTGGGAAGATCCCATGAACTTTTACTTACTCTGGTAGAACAGGCAGTTTAAGTCACAAGAAGTCTCAAATTTCTAAATGTCTAGTCCAAGGTATGAATCAGCACACCATTTCCATTCTAGGAGAAGTCCCTTCTCCTCTCCCTCCCAGCCGCAGATCTGTTATGGAAGGGCAGGCTTCTGCTCTCTGCCCCACTCCTTCAGGCTGGCTGATTCCTCAGGGTGGAAGGTGGAAGGGAAGGTATGGGGAAGTGGAGGTGGTTGTGATGTGTGAAAGTATTGCCTCCTGAGAGCCACTTAAATATCAGGAATGTTATAAGCTGGTTGTTAAACTGCTGGTAGCTTGAGATTAGTCATGGTGGGTGTATCTACACCACAGAGACTAGCAAATATTTCAGATCAAGGCTTCCCCATCCCTGCCCTTGGAGAGCTGTTTTATTAACACATCACTGGCTTAGGGAATAGGAAATTCTTCCGGGGTTTAGGTGGCTTTGAGTGCTATAGTCTTGGCAGACAGTTCACCTGAGTCTTTCCCTACGTGTGAGTTCTTTGGAGACCACTATCATCAGGTACCTCTCTCCAGCCCCTGGGATACTATGGGCTGTTCATGTTGTCCTTGGGCAGGCTGCTTCCAATTCTCAGTCAGCTTCTGCTTGTAGAAGATGACCAGCCCCACACATTTCCTGCTGTTGGGACCCCTTTGGGCTCTGGGCAGGATTCACTTTGATACTATCCCAGAGCAACATTCCTTTTATATTAGTTTTCTATTGCTGTATAAAAAGTGACTACAATCTCAGTGGATTAAAACAACACATATATATTTTTTAATCTCAGTTTCTGTGGGTCATGAGTCTGGGCCTGGCTTAAGCAGGCTCCTCTACTCAAGTCCTCACAATGCTGCAATCAAGATGTCTGATGGGCTGCATCCTCTCTGGAGCTTGGGGTCCTCTTCCAAGTGCTTGTGGTTCTTGTTGGAATTCAGTTCTGGGCAGTTGTAGGACTGAGGTCCTTGTTTTCTTGCTGGTTGTCAGCTGGGGTCTTCTCTCAGCTCCTGGAGGCCACTTGCAGTTCTTTGCTCTCTTAGCTTCCTCTCTTAGGTCCTTTGATCAGATGTCTTGCAAAGACAGAAAGATAATCTAACTGGTTTACCTATATGGATGTAATGTAATGATGGGAGTGACTATCCTATCACCTTTGCCTAACCAAGGTAGAGACATCCCGTTCCTTTTCCACACCATGTAACATAATCAAGGGAGTGACATCCAACTACCTTTGTCATATGCTATTGACCAGAAGCAAGATACAGGCTCTGCCTACATTAAACAGGAGGGGATTGTACAGAAGAATCATGACTCATTGGAGGTCATCTTTGGGTATGCCCACCATACCTACTACATCTGGTCCTTGAATTTCACAGACCTGTGATCATCTGTCAGAGGGGAGCCAGTTTCTTCCCACAGAGCCTCAACTTTCTGCCTGTTCTGCCATGAAAGCCGCCTGCTGACCTCTCTCTCTCCTTCTGGATTTCCAGAAGTGCAGCACATGTCTATTGTGTTCCCGCTGCAGGGTCCTGTGGATCCCTCTGATGGTCACTTTGGAGCCTACTGTTTTTAGACTTGAGGCAAAGCAAGTTGAAACTGACATAGCATTCCTGTCCTTGAGGTGAAAAGGGGGCTAGTAGTCACAGCACCAATTTCTCCAAAGAATGCTCCTGAAATTTTCTTTCCTCTTCGTATTCTGAGTTCTTTGTGTAAATTTGATCTTGTCAATGGGCTCAAAAGTCAGTAGAATCTCCAACTTTCACATAGGAAATCAATAGAGTACAGTGTAAACTTTATAAACAATGAATAGCAGCATGTGTAGAATGTTTAAAAATGTGAAGGTGAATATTAGAAAAAATAGTTAAAAGAATAAAAACTGGTGCCATTGGAAAGCAGGGCAGGATAAGGGTGGGGCAGATATAGTGCTATTTTTCTTTATATTCCTTTTAGCATTACTTAATTTTTTCAGATATCTTCCTGTATTGTTTGGATTTTTTAAAATATATGCCCAAAGAGGCACTGTTTTCATCTAGTCTTTGTACTTGTATATCCTACTGCAGGACTAGACATAAGAATTTTTATACTTCAGTTTACTCATCTGCTAAATAAGCACAGTAATGCTTTAAAAATTAAGAGATGAAAACTCTTGATAAAATATTTTGAAACCTCTAAGGAAATATGCTTTAAAATATCAGTTGTGATGAGCCAATTTGCTATCACCAAGTCTTCTAAACATTGAATCAAATAGTCTTTGTCTAAGTTATTTCTGTGCCAAAGTTACCATTCAGTCTCAGCTGAAAATGTATTTACTAAACACAGCTACAACTATGGCTTGTATTTATTATAGCTTAATGGTGAATTGTGGATTGCATGTTTGACATTTTTGGAAGTCAATGCTCACTTTATTGAAATATCTTCTGTCTAAAATGTATACCAATGTTCTTCATCATACCAATCTACATTAATATCTTAGACATATTGATATACAGACATGTTGGGCACATAGACCATGTGGAACAGGAAACCAAAGAAAATGTCAGACTGTTGAAATCAGCATTCAGAGATGAGAAACAATTGGCCAGTGTGGCATGGGGCAGCCTGTTTCAGAGATTACAAGGATTAGACCAAAGTCACAAACAAGGATAGTCCCTGGCATCAGCAGCTAGAATTGTCAGTCAATATCCAGGCACGAGGGGCTGCTACTCAAGGGAGTCTTTTCTGAGCTGCACTTTTCAACACTTGAAAGGCAAATTAGAGAGTAGCAGCTCTTCCTATTAAACTTAATTATGGATAGCAAATTGATCCATGCCATTTTAGAAATGCTCACCTCTTCAGTTATATTTGGCAGAAAATAGGAGGTTCCAACAAGTTCGATGTGAGTGAAGTTTAGTTCTTCTCTCACCACCTTAACATCATGTGCTGATGAAATAGAGTCTCACAATTCCGAGTCACAATTCTGAGTGGAGACATTTGTTACCATTGATTACAAAGTGAGGCCAGGCCGGTTCATGCCACCTATTGTTTTTTTCTTTAAATAAATCTTATTGTGTATATTTGAGGTTTATCACATGATGTTATGGGATACAAATAGATAGTAAAATGGTTACTGTAGTGAAGCAAATCAAAACATATTCCTCTCACATTACTACTTTCTTGTGACAAAAGCAGCTAAAAATCTACCAAACAGAATTCCCTAATATAATTTTATTAACTGTAGTCCTCACATTGTACATGGAATCACTAGACTTGCCCATCCTACATATCTTCTACCTTACATGCCACCTACTGTAAGTCTCAGGAGTTCCTAGGTCTTTTCTTTAGGTGATTCATCCACTTGTTACATGGAAGGTTGATTTACTTGAGGCAGACACACTGATTTCCCAAAAGCAGAATCGTTTTATCCTGAGAGTTGACATCAGAGAAACAGAAGTTTTATGACCTTTCAACAGGATTCAGGTCACAAGGGCACAGGCCACAGGCCTTATCAGGTTCTTATTCTAGTGTGAGGAGTATCTTGAAACCATTTCCTTGGCTCATCTGTATATCTAGCATGTCATTAATTCATCATTGAGAGCCTATTTCTGATATTCTTTATGATAATTTCCTAAGCCTCCGTGCAAGAAGACTTGTGCTAGCCTCTGGAGTGCAGACTTCCCAACTAACTGCTGACTAGCTAACTAAGCAACCCGAGGGCAGAAATTTCTGCTTCAGATAACAGATAATACCTAAGGCTGTACTTAAACCAATACATGCTGTTTGTGCTGAGGGTTTTTTTTTTTTTTTTTTTGTAAGACAGTTTTGTTGGGATGCAATTTACTTTCCTTTAATATAAACTTTATCTATTGTAAGTGTACAATTTAGTAATTTTAGAAAATGTATAGGGTTGTGCACCCATCACAGCAATCCAATTTTATAATATTTTTGTCACTCAGAAAGATTCCTCTTGCCCATTTGCAGCCAATTTCGAATTCCATCTCCAGTTCCAGGCAACCACTAATCTATTATCTATTTCTATAGGTTTGGATTTTCTGAATATTTCATGTAAGTTGAATTATATAATGTGTGGATTTTGTATCTGGCTTATTTCATTTAGCATAATCTTTTGAGGTTCAGCCACATTGTAACATGTATCAGTAGTTCACCCTTTTTGGTTGCTGAATAGTATTTCATTGCATATACACACTGAATTTTGTCATTCATTCACTATGAACATATATATATATATATACATAGTGAATGAACATATATATAGTTGTTTCCCCTTTTTGACTATTACAAATAATGCTGCTATGAACATATATATATATATATATATATATATATATGTCTTATATATATATAGGTCCTTGAGTGAACATATGTTTTCATTCATTTAGGGTAGATAGCTAGGAGTTGGACCAATGTTAAAGTGAAGTTTAAGCATTTTAAGAAACTGCCAACCTGTTTTCCTAAGTGACTGCACCATTTTTACATTCCATCAACGATGTAGGATGGTTCCAGTTTCCCCACATCTTCACCAGCCTTGTTATTGTTAAAGCAAACTAAACATGGCCTGAGAAGGAATCCGTACTTCCATATTTGAGTCCTTGTGGATGAACAGGAACCTAACTTAATAGTTAGACAAGACTGAAAATCTAACTTAAGAGTGTGAGCCTGTAATAATAGCTAGGTCTTGGCCAATCCCAGTGGCCGTACTTCAACCATTCATACACTGCTGAGTGTTCAAACTGTGTTCAAATAAGGCAAATGCCAACCTGTAACCAATCCAGCTGTTCTGTACTTCACTTCCAATTTCTGTACCTCATTTCCTTTTTGTTTGTCTATAAATCTCATTCCACCACTTGACTGTGCTGCAGTCTCTGAATCTGCTGTGATTCTGGGGGCTGCCTGATTCGCGAATTGTTCATTGCTCAGTTAAACTCCTTTAAATTTAATTTGGCTGAAGGTTTTCTTTTAACATTATTATTTGTGTTTTTTATTATAGCCATCCTAGTGGGTGTGAAGTAATATCTCATTGTGATGTTGTTTTTATTGTATTTTTAAAAATTTCCTTTTAAATTTAAGATTCAGGGGGTACATGTGCAGGTTTGTCACAAGGGTATATTGTGTGATGCTGAGAGTTGGGTGTCTGCTGATCTCATCACCCAGATGGTGAATATAATACCCAATAGGAAGTTTTTCAGCCCTTGCCCCTCCTCTTCCCTCCCCAGTCTAGTAGTCCCCAGTGTCTGTTGTGCCAATGGTTATGTCCATGTGAACCCAAGATTTAGCTCCCACTTATAAGAACATGCGATATTTGGTTTCCTGTTTCTGTGTTAATTCGCTTAGAATAACAGCCTCCAGCTGCATCCATGTTGTTGCAAAAGACATTATTTCATTCTTTTTTTTATGGCTGTACAGTATTCCATGGTGTATATGTACCACATGTTCTTTATCCAGCCCACCACTGATGGGCACTTGAGCTAATTCCATGTCTTAGCTGTTGTGAATAGTACTCTGATAAACATACTAGTGCAGGTGTCCTTTTGGTAGACCGATTTATTTTCCTTTGAGTATATACCCAGAAATGGTATTGCTGGGTTAAATGGTAGTTCTGTTTTTAGTTGTTTGATGATCTCTAAACTGCTTTCCTCAAGGGCTGAATTAATTTGCATTACCACCAACAGTGTATAAGTGTTCTCTTTTTCTCTGCAACCTCACCAAAATCTGTTATTTTTGACTTTTTAATAATAGCCATTCTGACTGTTGTGAGATGGTATCTCATTGTGATTTTGATTTTCATCTCTCTGATGATTAGAGATGTTGAGAGTTTTGTCATATGTTTGTTGGCTGTGTGTATGTCTTCTTTTGAGAAGTGTCTGTTCATGTCCTTTACCCACTTTTTAATGGTTGTTTGTTTTTATTTCTTGCTGGTTTGTTTGAGTTTCTTACATATTCTGGTATGCTGAAGTATTTTAAAGAAAAACACAGACATCATAACAACACCCACTCGATGGATTATATGCAGCTGCATTTTCTACTAAACATCAGTTCTCCTGGAGCAGGCAAGCACATTAGAAAACAAAACACTTGAGGGAATGATATTACATTAATCTCCAACACTGAAGCTTGTTTCAGCTATGGACTAAGGGAGAATATAAATTTTGTTGTTGCACTTCATTCTTTTTCCATTTCTGATATAAACTTGGCAAGAAGTCTGTGCACTCCTGATCATCACTAACTAAGGTGCCTTGATCCATTGGAAGTTCTTCATCTTTTCTCAGTGGCATTAGCAGAAAATTGATGTTTCATACATGGCATTAGTTGGAGCATAATGCCATCTGTCAAGCAGAGGCATACTCTTTATTTCATTACTGTACTCCCAGGTTGACTAAAGGAAGAAACTAGTCTCTCTCTTTCTCTTCCTCTCTCTTCCTTTCTCTGTTCCCACTTCTTGCTTCTCTTTTCTATATCCTGCATTGTTATAAAATTTTTCTTCTAATAAGATAATTGATAGCTTGGTTCTTTGTAAAAACAAGATTGAGCTATTTTTACAAAGAAAGCTGGTTAAATTTCCATTATTCCATGCCCTAAGAAAGATCTTCCAACTATAGCAGCTTCTGTTGTTTCTGCTACATGTTTTAAATGTTCTGCACCTACAGGTTACCCCTTGGCCAATAACATGGAATCTGGGTTAGCAGCACCCCTCTGCAGCCTTTTCTTTTTTGAGACGGAGTCTCACTCTGTCACCCAGGCTGGAGTGCAGTGGCACGATCTCAGCTCACTGCAACTTCCACCTTCCGAGTTCAAGTGATTCTCCTGCTTCAGCCTCCCCAGTAGCTGGGACTACAGGCGCCTGCCACCATGCCCGGCTAATTTTTTTGTATTTTTAGTAAGACAGAGTTTTACCATGTTGGCCAGGATGGTCTCGATCTCCTGAGCTCTTGATCTGCCCTCTTCGGCCTCCCAGTGATGGGATTATAGGTGTGAGCCACCGCAACCGGCCTGTCTCAGAGATTTTTCTTGGCGTCTTTGTTTCCTTCCACCAGGTGTTATAGATCATTAGTTCCCACAGGCAGGCACTTAAACAATCAGGTTGCTTTTGGTCATTTATTTATTCTTTCACTCATTCATTAAATATTTACTGATCATATCTGCTCAAGACGAGGAGAATACACATATAAATGAGGGAAATACACCATCTAACCACAACGAGAGAGTTATTAACAGCTTTTTAACAGTAGTGCTTGAATACTTCTCTGGCGCTCTTTCCCCTACAATATTGAGCATCTAGTGAATGGCAGGCATGTTAATTCCCCTTCAAAAAGCTATGGGTTGAGACAGTAAACCTAGGGACTAGAATTAACCTTAGCCTTTTTTTCCTCCTCCCTCCCTCCATCTCTTCTCCTCTTCCTCTTTCTCTTCCTTCCTCTCTTCCATCCATCCTTCTTTCCTTTCTTTTTAAAAAATCTGGTTTTAGGACTGGACTAAGAACTCAGTTAAGTGAAGCAAGCAAGAATTTCCCAAGTGATGCCAACTCAAAATGAATTATATCAAGAAAGGAAAAGCAGCTTTTTCATCTGGAAAGAACTGGAGACCTTGAACCTAGGCAGCATGTGCCTTGAACCTAGGATCAGTAAACAACAAGGATGGAAAAGACAGTAAGAATTTGGTCAGATCACCATATCTTTCCGTTGTGCCTTTAGAACAAAAGGAAAGAAAATATCTCTTTGGCTCACAGAGAAAATATGTTGAGAAATGAAGTACAACCCCTCACTGTGCTGGGCACAGAGCAGGTGCTCGGTAAATAAATAGTGTACGTGTTCGCTGAGTAACATTTGACTTGAATTGCCTTTAAGCACTTTGAATGATCCAGTGGTATTTATGGACCTCCCAGGCACAGCCCTGCACCAGCTTTCTCAGAGTAGTGTCTCCATACAGGCAAGCCTTTTAATCCCCAGTAAAACAAAAAGATGGCGATAAATATTCAGTATCTTAAAAATTTAAGTAAATATGCAGTGTCCTACCTCTCACTCACATCGCAAATGATCTTAGTTTGTTCCTTGGAGAGGAACCAAATGCTTTAGTGGATGGTAGCACATTCTCTCTCCCTTTGCTTGTATAGACCTGACCTAACTTAAAAATAAATGTTTAGTTAAGATGATCTCCAGCTTAACCTCTCTGAAGGTATAGGAAGCTGGATCAGGTGTAGCTGTCCCTGGCTATAGGTTGGAGTATCTTGATGTAGGTGAAGCAGTGTTCCTAAGGGGAAGTCCTTCCTTGTTCACCAACTGGTTGTGTTCATGCCTTTTAGTATTTGCCCAAGTATTCACCAAGTCAAAGTCTGTGGGGTAATAGGTACATTGAATAATAGGGATTGGATTTTAATTTTTCTCTTAAACTAATGTGACACATTGAGATGCTTGTAACTGATGAGTGAGTTTGGTTCAGCATTCAGTATGGCTAATGATAACAATTTGTAAAAAGCATGTAGGGGTATTCACTGGGATAGACTGATGGCTGTGCTTATGAAATGTGGCTGTTCCCTTTCATTTTCCTGGAGTAATCTAGTTCAAAAGCTTTCAGGTTGTGTATAGGTAAATTGACTTATCAAGAACCAGTGAAAGGAGGATGATATTGGTATTTAAATCCTATCTCTTATTTAATATGTAAACTTAGGGAAACATCTTCCCCTCCTTTAGAATTAATTTCTTAATCTTGTAAAACTGTGACACCAGGGTTTTCCCTGGTGTCCTCGGATTGTCAGTAAGGCTAAAAGTAGAGAATATGCCCCAAATTCTAAGCCCCAATAACTGCAGCTACTGGGGCCCACTAGCTCCTTGCAGGGTTTTCTGAGAGGCATTATTCCAACAGGCTTGAACACACTGCTTCACTGTCGCTTGATCCCTGCTGACCTTAGAAAACTGAGAAGAGAGTCATCTGGGGGAAGAAAAGTGTTCATTTCCCCTCTTCATCTCCTCTGTTAGAGGCAAGAAGGGGAAGTCCAAGAGAATCATTCATAAATGTGGGGGTGGCCAAAAAGGGCAGGCAGACACTTCATTCCATGGTTGAGTGCCTGCTTAGTTAGCAGAGCTGGTGGCCTGCCTTTGAACTGCTAGGGTGTGTGTGTGTGTATGTGTGCGTTCACACATGGGCACGTATGTGTGACCTTGAGTTTAAAAAAAGTTAATGGCAGCTACTTATAGGATAACTTGAAATCAGGAGAGACTGGGGTAGGATCGAGGTGGTGAGGAAACACAGGGTCACCAACTTGCATGTTGGGAAAAGGACTATCAGGTGGAGAGGTCACCAGGATTTCTCACTGCCCCCCCTTCCCCGCCCCCATTAACATAGGCCCCTTTTCAAGAGATACTGACATGGCTCTTCCTTGCAGACTTAGGAACTGGCCACAGGGTATAGATGAGGTTGCAGTGTTAAATAATTAAATGGGGGTCATTAGACTGAGGTGACTCTAATGCCCTGGGTTCCTATGTAAGCAAACCTAAATCTAACTCAGAATTTAAAAGAAAATAAAACTTAAGTTCATTCAATCACAGGCAGCCAAATGGGCATTAGCTGTATTGTCTTAAACTTCCCACTGGGCTAGTTCAAATAAGGCAGTTGCTCAAACTTCAACCAATCAAACAATTTCTTTGATTCACCTCATAAAAACGTCCCCTCATGTCTCTTTGTCAAAGCTCTGAATTACCTCTGGTTTGGAGCTGCCTGATTCATGAATTGCCATGTGCTCTAATAAACTCTTTAAAATTTTAACATGCCAGAGGTTTTCCTATAACAGGGGCAATTATCTCTAGAGCAATTCCCCAGTGAGGGACAAAGAAATGTGATGCAATAATGTCAGCTGGGGTCAGCCAGAGATGTGGCCAAATTTCTCAAGGAGCTTCCAGTGTCAAGAGCTGCTTCATGGAGGGAGCATGTTGGAGAAGGTGAAGCATGGTGGAGCCACAGACAAGCAGAGGGGGCTGTGCAGGAGAGGTCTGCAACCTCACTGTCCTGCCCCAATACTCAAGGAATAGCTCAGGGAAGAGGGAGGAAAGGGAAAGCATGTGATAAAGACTACACCCCTGGCTAGGGAAAGGGAAAGGAAGTTTTGAATGAGATACAACATGCAATCTAAATGAAACAAAGAGACTAAGAAAACATGGAATAGGGCTCAGGTGTTGTTAGGGAGGATTTGATCTGGGATTATTGGGGACAGTTATTGGAAGAAAATAAAATTTGTATTTATAGCTGAATGAATTGAGACTCTTTAATACCACCTCCCTGATTATAGTCCACTGTTCTTTCTGCCATATGGTGCTTTACCGCTGACGTTCTCTAAATGTCTTCACTCTCATAACCTCATCCTGTTCATAGCATCTTGAATATTTGATCCTACACCTCAATTTTACAAACTCTTGGAATTTGTGTCAAATCTTGCCTCTTCCCAGAAGTCTTCCTTAATAACCCCAGGTCCACATTCCTCCCTGTCTTTCCCCCATTGCCCTCCACCATTTCAGCATTTTCTAGAATCCATCCTTGCTTTTCATTCCAATCTTCCACGCCCTAGTTCAGGATCCCATCCAATCCTCCTTCTGCATGGTTGCCACACACTGCCTGAGGACAACTGGCTGAGGCCCTGCTGCATTTGGCAAGCCACCTGCTCTGAAACAGGGTGGTGTCAACCCAGAGGGGCACCATTTTCTCAATTGCCCAAGGGCTGTCTTAGTTCACCAGGTGTGCATGGGGTCCTGTAGGCTCAGAGGGAGTGTCTTTTCCTAAGTTGCACGAAGGTGACACTGTATTTCCTAACCACCTCGATCCCACCCCAGTCTCTTCTCATTTCAAGTTGTCCTATACATAGCTGACATTAATTTTTTTTTAAACTCAAGCAAATCTCCTTTTCTACGTAAAAGCCACACTCTAGGGCATCATCAATATCATGTGTATTGGGAACTGTCGAAGGGCTAGGATGAAACAGCCTGGATGTGGACTGTGAAGAGAAATAAAAAGCTTCCTAGCACCACGAATCTCAAACCTTCATGTGCACACAAATCACTATTGGATCTCATTAAAATGAAGATTCTGATTCAGAAGGTCTGAGTGAGACCTGAGATTCTGAATTTCTAGCAAGTGCCCAGGTGATGCTGAAGATGTTAGTCCAAGGACAACACTGTAAGTAGCAGTAAGTAACATTTAATTTAATACACTGTGAGTAGCATTTAATTTTCACAAAAATCCCTATAGGGTTATTATTATTATTATTGTTATTATTGCAATTTTTTAGAGACAAGTTCTTGCTCTCTTACCCAGGCTGCAATACAGTGGTATGATCCTGGGCTCAAGCTATCTGCCCTCCTGAGTAATTGGGACTATGAGTGGGCACCACCATGCCACCATGCCTGGCTAATTTTTTTATTTTTAATTTTTTGTAAAGATGGGGTCTCCCCGTGTTGCCCAGGATGGTCTTGAACTCCTGGGTTCAAGCAATTCATCTGCCTTGACCTCTCGAAGTGCTGGGATTATGGGAATAGGGATTTAAATTCATGTCTGCCTGATTGAAGACTCCTTTTTAGCCACTATGGTGTATTCCCTCTAGAAGGACTGGAGAGGAGAGAATGGACTTGAGGGAAGAATTTCATTCAGGAAGTAAAACAAGAAAACTTGGGGATGGGTTGGCCTTGATCTTCTCAGTGGAGTTGGTGAGAAGGTCACTTAGCTCTGGTGGTGGGAATGAAAGGCCTAAGTGATCTGGGGGAATTGGGGCTAGCTGCAGAGGGCCATGTGCTGGAGGAAGAGCAAAAAGGGCTGCCAGTAGAAGGGAGCGCCCAGATAAAGCTGGGAGGATTGAACTTGCCAAAGCACTAAATCAGTGGTTTCCAAACTTCACAGTAGAATCACTTGGGGATCTTTTAAAAGTTCAGGTTATTCCCCAGGCCAATTAAGTCACAATCTCAGGCAAGGACACAAACATCAATAATTTTTGAAGCTACCCAGTAATTCCAAAGTACAGATTATTTTGGGAACCAGTGCTGCAGATGATTAGGTTATAGTGTTAAAGGGGCAAATCTTGCATTATTTTAAATAACCCAAGGAGCATTGAATAATGGTTTTGGCATTTTGCATAGTTCGGAGTTTGGCAAACTTTTTCTGTATTAAGTCAAATGGAAAAAAAAAAAATTAAGCTTTGTGGGCCAAGAGGCAAAATTGAGAGTATCATGTAAGTACTTACATAATAGGAGAAGAAAACAGATTTCCACAAAATTTTTATTGATGAAATTTGAAACTTTATGAATACTGAACTTGGAATTTTATATAATTTTATGTGTTATAAAATGTTAGAATTCTTTTGATTTTTGCAGTCATTTAAAAATGTAAAAATAATTCTCAGCTTTCAGGCCGTACAAAAACAGGCAGTGGCTGGGTTTGGCCCCCACTATGTTATAATTTGCTGACTCCTAGTGTAGTTAGTGATATACCTTGTGATGAATCCAAAGAAGCCATCAAAAATATGCATCTCCATAAAAATAAATCAGCATTCAAATGAGTGCTTGATTGACCTACAACAAAACTGGCCTTTGAAAAAAATCATTGCATTTTCTATGGACAAAGTGCAAAATGAATGACAACACTTTGAGGCAAAGGCTACTTTAACTCATATTTCCATAATAAATAAAAAAATAGCTGGTTGAAAACATGGATGACCTACACAGAGTCTACTATATAGAGTACTGTTTTCTGTAAATAACTCAAAATACTTTCAAAATATCTTTTAAAAGTATAAATAGTATTTTGATTTATTTTGAAACCATTTTGGTGTTTCACCAGATGTCAGTTCTCCTCAAGGCCTCAAATTATTAAAGATTCCTAGCTGTTGAGTACAGCTCCCTTGCGTTTGTAATGTCTACATTTGGATACCAGGATTATAGGTTAAAAAAATGGCAATTTTCTGGAAATGTTGTTTATGTAATCAGGTGGATAATCTGAAATACTTTAGAGAGGCTATAGAAATCCCTCTACTGTCTTTGGGCATTTTACATCCAGAACCTTCTGAATTATTGCATTAATAACTTCAATAGTTTCTGATTAGCAAAAAGCACAGTGAGGAAAACAAAATTAAAGAGAAAAAGGAATTTTAGCACCTGCAGGTCTAAATATTGTATTTGTAATTTATTTACTAATGGATAGTTGTTTTTTTTTTCTCTTATGTATAGAAAATTTCGAATGGAACCAGAGGTTACCAGAAACGTGCCCCATTTGTAGTTTCTCTGCTTTGAGAATTTGCCAGGCGTTGAGGGGAGCCCTCTGCTGTTAGTTTTATTTATTACAGTAAAATTTGAATTACATTTGTTTTATGCCCTTCCTTGAACCTTCTCAGGTTTTTGATGTTTCTGTTATGATTGTACATTTTACATAACAAAGAAAACATAAATTCCACGATGCCAGTTGGCATAGTTAATAATCCATCAATTCTGCCCTTTTTGAACTATATCAGAGCATTGAAAAATCTGGCGGTTTCCAATTTCCATGTTAGAGTAGGGTTTTGACCTCTATTTCACTTTCAAATGGGTCTCCTTGGCAGAATAACTCGGCTTTCTCGATTAATTTTACTGTTCACCCCCTTAACAGTGAATATGGAGGTTTAAACCTGATGCTTTAGAAGGTAATTGTACAGTTTTCGGAGAGTCAGAGGAAACTGACTCTCCCCTGCTCCTTAATTGCCCTTGTTACATTCTCTCATCCACTAACTGTGAATGCTCCTTGAATCTTACTTCTAGGACCTCTAATTTTGTTGTTGTCATTGTTGTTATTTTTACATTTGTTGCATCTGTGGACTCATCTATTGTCACAATCCTAGTTATAATGTCTAAATTAGTAACCTCTTAAGCTGTGTTGTCTTGGAGACTAGGCAGGAAACAAACATTTATTGGGTGCCTGCTACTTGAGCACAGTGGTAACATATATATACATATATATACACATACATATATATACATATATACATACACATACATATATACATATATACATATACGTGTATATATACATATATACGTGTATATATAAATATATACGTGTATATATACATATATACGTGTATATATACATATATACGTATATATACAAGTATACATATGTGTGTGTAATATATAGAAAATATATACATAAATATAATATATAAGCATATATAGATGTATTTTATCTAGCCCTTTTTTCCAACTTTTTTTCCAAATACTATATGTCCCCACAGTTGTCTTGGTCATTTCCCTTCCTAAGCAAAACTCTCTCTTTGCCCATCTTCTTTTCCTGGCATCAGAGTATCTCCACTTCCTGGTGCTCAACACTTGGGAACAAGATTTTCAGCATTTCTGATTTGAAATTTACTTCTTTTATTGTCTCTTTTTTTTTATCCCCACTACCATCATAAAGGCCTCGTCACTTCACATCTGGATGGCTGTTTTCTCATTTTAACTATTTTTTCTGGCATCTTTTCCTTCTATCTGTTCAGCATGTACTCATCATACCCCTTTTTTTAAAGAACACTCTTTAATCATTTCCCTCTCCCTTGTAAAATAACTGCAATGCATCTCCATTGCTCAAAGGTTCAGTTTGAAAAATTTCACCCTGATATTCTAGGCCCTTCAAATCCTGATTTGATTTATCTAGCCTAATACCCTGCTCCTAACAATGCTTATTCCAATCAGGTCGGCCTCCTTCCTGCCCATACCAGGCTGGCACTCCTACCTCAGTACTTTCTCATCCTCTTCTGTCTGAAATGTTTTCTTTCTCTCTACCTGCCAATATCCAACTCCCATTTGAAATACAAATATTTCCATCAAATCTTCTTTAATAATCCAGCCAACATTGGTATAATCCTTTCTCAGTTACCTGTTTGGCGTTTATTATTAGTATGATGCATTATAGTATTTTATTGTATTTATGTATTAATCTTATTAGTATTTAATTTGTGTATATTCTCTTGAGTACTCTTAATTGTTCCTTCAGCTTATCCCAACTGTATGTTTCTGATGATAAGAATATAGTCTAGAATTTCACTCTGGGATACCATACTGGGTTTAGTCAATTAAGCTCTCTGAAATTAATTTTCTTCTTTTGTAAGATGGAGATAATAATACCCCTCTACTTGTCTCATTTTGACACTTGAGGTTAAAAATAGTATGAAGAAATGCTTCAAAGTTTTCAAACTAATTTATTACCATGGTGGTGATGATGATGATGATCCAGAATGTATTTTCCCCCTTGAGATACCACCTAATATAGGGTTGTAGGGGTGGAGAGGATATGATCTCTTTCCTCCTTATCATAAAGGGTCATGACTGACACCCCATAACAACAAAAAACAGGTTAATCAAAGAAAAGCATAACAAGTTTATTATAGTCCTATTATGTGCACACATGTGTATGGGAGTCATATAAAATATGAACTCAAGGAGGGACCAGATGGTTTAGGCTTAAGTGCCCTCTTCATAAGGGAGAGGGAAGTAAGATGTATCGGAGTAAGTGATTTTCAGGGGAAACAAAAGGCCCAGTGCTCAGACAATGGTCCACAGAAACAGCCTCTTAGGTAATCTCTTGAAGCTGCCTTCAGATGAATTGATGAAGTCTGTCTGGGTATGGTGATGACTCCCAGTCTTCTCTGTCCTCCAGTAGTTGATCTTTCCAGGTTATTTGATGAGATCTCTAGGGAATGAGTCTTGAGACAATTGCATTTCTTTTGGAAAGAAGCTTTCTTGGTCAGACAAGAAAATTTCAGAAAGAGTCCCTCATTGACTTGTAGGGTGAGGAAAAGACAAGGTTGAATGGACCTTGATTCTGAGGCAGCTTTTAAGGCCTCCCAGCAGGCCAAAGCACCAGTCTTTGGGGTATCACATTCTGAGGCCCAAAAGGGTCATAGAGTTCCTTTCTGAGGATAGAGGTTGTAACCAAAGATGGTCACTACCACCATGAGGAAGAAACATCATCTCTCTGAAGGCATATCTGATCTGCCAGAGTTCAAGATCAAAGTCAGTACCTTCACCTTAACTTTTACCCCCACCTGTAGCCTATGATGCTGCCAATTTCCCTTCACACAAAAGCTTGTGAACTATTGGTCTGCGCTTATTGCTTATACTCTTGCAATCTGGGGTCAAAGCTCACAAGTACAAGAAATTTCTTCTAAAAGTGCTCAAAGACATTCTAATTGTTTAATCAGGTAGCTGCTTTTTGGTCATCTTCCTAGACCTTTCTGCAGCATTAGATGTCATTAAGAAGAGTTGTAATATAAGGTTTTAAGGAAAAGAGAGATGTTTCAATGAAAGGGATAACAAAAGAAAAGACAGATTTGACTACGTTGCATTTCCCCAAACTTAGAACATATTTACTATGTGTTTGGCAGCCATATCACTATTTCTAACATTAAAAACTCTGAATAATACAGAAAAGGATAAACACTGTAATAGAAAAATCGGCAAATGTCATGAACATACAAATCACAGAAAAGACATAAATGCACATACAATATAATGTTCAACTTTAATAATTAAAAAGTATGTGGCCAGTTTTAGGTCCCACTTTTTTCTTTTGTAAATGTTTCAGGAGTATATTCAACTTCTTTTGAATAGTTTTCATAAAAAGTTCTGATTAACCTGCATGGAGTCCTTTTTCTTGAGCCCAAAATGGTGGATCATGCTCACTATGCTTGCTGGAATATGTCCACTGGGTACAAGTTTTCTTTTTTTTCCCCAAGAATGTGATGGAACACTTGTATCCTAGTAACAATCCAGATGATAGCACTATCTTGCAAAGACGTGTTTATATCAAGCTATGCTATGAATAAAGTATATATGCTCTCTCTCATTCAACAAAGAATAGAACCTAGGAGAGACAGACAAAATTGTGTTAGGTCTTGTTGAAAGAATGAGTAATGGGTTGTTTAGAAAGGCAAAGAATGGAACAATTATTTTCCATCTGAACATTGCTTATGTCAGTATTGCAGGTTTTTATCCTTGGTTCAAGGTTACAAATCTTCCTCGGGATACATCAGCTGCCAGACATAAAGTCATATGCCATGCTGCGAAGAGTTTTTTTTACAGACTTCAACCTGTCTCCCCATCCCACACCCAATATTAAAATATGCCCTTTGGGACATGAGTCTAGAAAAACATCCCTTCTTTTAGAGCTAATCATTACAAATGGAGCGAATATTGCAAAAATCCTACAAATGATCTCTTCTGCCCTTGCAACCAAGGCACTGTTACTGAGTGTAACATGCCATGCATGTTACATAAACAATTCATTTAACTTTGTGGGGCCTCTTCAGGATAGGATAGGATAGGTATTTTTTTTCTCACATTTTGCAGAGAAAAATTGGTGCCTCAGATAAAATAAATAACTCACTGAAGTTTATATGCTACTAAGAGGGCTACTCTCAATTGAATTCAGTTATACCTGACTCCAGAACCCCTGATTCTTACCTCATTTTATTCTGTGTGTTTCTTTCAAAATGTAACTTTCATACCATGTTCATTTTAAAATTAATGCAAGGCTTACCATGCTTCTTCAGTGGTATGGATTTGTATCCCATGTAAGATGCTTTGAAACTCTGTATATGGACACCATTCCTGATGGTTTCCACTTACCCTATAAAATGATCTACCTACTGCATCTGGAAGCACCTGGAAGTTCTTATCATGAGAAAGTTGAAGAATTCCCATTCTAAAATGAAAAATAAAACAGGCTGTTAGACCTCAAAACGCAGTGTGATATTAGAATTATTAATGGTCACAGCTAGATGATCTGATAAACGGGAAGTTTATGTTATGTTCTGAGTTCACACAGGAGGCTTTGTGGCAAGGTTCTGTAAACAACTCTTGCTCTGGAATATTTGTGAATGGCCATCCATACAATTGATATTGAATGCTCTTGCTTGACTTTTATTTATTTATTTATTTATTTATTTTGAGACAGAGTCTCACTCTGTCGCCCAGGCTGGAGAGCAGTGGTGCGATCTCGGCTCACTGCAAGCTCCAACTTCCCGTTTCACGCCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTGCAGGCGCCCGCCACCATGCCTGGCTAATTGTTTGTATTTTTAGTAGAGTCGGGGTTTCACCGTGTTAGCCAGGATTGTCTTGGTCTTCTGACCTTGTGATCCACCCGCCTCTGCCTCCCAAAGTGCTGGGATTACAGGCGTGAACCACCGCACCCGGCCGTTTGACTTTTTTTCTGGGGAGCTGTCTTTAGTGTAGAGATTCTAGTGTCATTTGGACACTTTCGATTTATAATGAAGAGATCAGTGTCTTCACCAACCCATGGGTTGCCTAGTGAGGGCAAGGGAGGTATTAAGTTAAGTAAGCAGGAGGCCATTAGCCTGAGGCTGACTCCATACTTTGAGTTCCTACATAGCAAACCATAAACTGAATAAATAAACAAGCTAAAACCTAACATAAGAGTATAAAAAATGACGGAATTTTAGCCAATCACAGGAACCCCAGGTTTTAGCCAATCACAGTAGCCAACTCATCACATCATGCCCAAATAAGCCAAATGTCTCATCACACAATGTCCAAATAAGGCAGGTTGAGGTGGAAGGATTGCTTGAGCCCAGGAATTCAAAACTTCAGTGAGCTAGGATCATGCCACCGCACTCCAGACTGCGCAACAGAGCAAGACTCTGTCAAACAAACAAACAAACAAACAAACAACAGCTTACTGCTTACACTGCCAGGCAGAGTTCTTTGAACCTCTCTTCTGGTTCTCAGTGCTGTCCCATTCATGAATTGTTCTTGGCTCAAATAAACTCCGTTAAATTTAATTTGTCAAAAATTTTTCTTTTAACATAGGATACAAGGGAAATTGTCTTTCTTCCTTTCCTAGAGCTCATGGTTATGGCAGGGGAGATGCCTCTGCTAGGTTCAAGTTTTGGCTTTGCTACTTGATAGCATGCTTGGTTCACTTAGTTATCTGATGAGATTTGTTCAGTCAGTAGCAAATTTAATCAAGGTAAATCTTTTTTTTTTTTTTTTTTTTTTTTGAGGCTGGAGTGCAGTGGCGCCATCTTGGCTTACTGCAAGTTCTGCCTCCTGGGTTCACGCCATTCTCCTGCCTCAGCCTCCCCAGTAGCTGGGACTATAGGCGCCCGCCACCACGCCCAGCTAATTGTTTGTATTTTTAGTAGAGTCGGGGTTTCACTGCGTTAGCCAGGATGGTCTCCATCTCCTAACCTCGTGATCCGCCCACCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGACACTGCACCCAGCCCGGTAAATCATTTTTAATTCTCAATTTTTCTAAAATAGTTTACTATAGTTTCTGAGGGAATAAATCTGCTCTATGTCCAGAATTTTGCTCTTAGGATTTATGTTGTTTGTAGGCTCCTAACTTAAAAAAACGTTATCTTAAAAAACAAAGCAAAACAATTCTGTCCATAGCAATTAGTTCACTGGACTGTAATATATTTTTATTTATCTTCTCTCAGTGCATTGCATAGTCTTCAAGGATAAGGAGTTGTGTTTTATTTAATTTTGAATCTCGTGGGCTTGACACAGTCAGGGCTCAGCAAGGGTTTTATAGAATAATGAATAAGTAAATGAACTCAGAGCACAAGGTGAGCAGAAATACGAATATTTACCTGATAAACTGGGACACAAAGATGGCCACTCTGATTTGAGTGAGTATTACTCAGAGCCGGGTAGGCTGAATGTGGAGGTTTTCAGTATTCACAAGTTATCTTCAAGGGCCCATGGCAAGTATAAATTTGTACTCAGTTTGAATTTCACAGGCTTTGACAAAAACACATTTGTGAGAGAATTTCTTCTCGCATGAGTGCACGTAATTGGCCACCTATCAATTACATTTAAAACTGGTGTACAAGTATCCAGTTAGCCTTTCATTGAAGAAAGAGAGGGAAAATAATTTTTTGTAGTAACTGCGTTCCAGAATTTGGAGATGCTAGAAGGCCTCCAGAATCATCCTTTGAGAAGTAGTGATGGTCTACACTATCAAAAATGATTTTTAAAAAAGTTTAATGTAAAATAAATATAAAATTGGGATTGTGACAAGATTAGGTAGATTAGGGGAAAATGACCTAGACAAGTTGCTATGAGACAGTGAGCAGGCTCCTCCACCTTACAACCTGTAGTGTGTGTAGGGGTCTCATTGGAATCCACTGTCACTCCAGGTCTTCTTTAGTAAAGGGATCAGTTTGCTTGGACTTATCCAGCTGTATCACATGCCCGAGGCTGTCATCCATTGTGCCATCTCTACTCCTCCACCACCAGCTGAGAGTGTGTGAGTGAAACTTGGTCCAAATAGGAAAACTGAAAAGGGCTAAATTGCAAAGGCACACACTTCTGGCAGACAAAGGTGCAATTTGTGGGTCGAACTGGCACAGTTCACAGTCCACTGATTCCTGCCTCTCCTCTTTTTAATACTTCTGACAACAGGACAATTTATGTGGTAGAGGATGCCTTTCTTTTTGTTTTCTGCCGCCCGAAAGAGTAACACTTTACTTTTCATCTTTTATTATCTGGCTAGCTGTTCACTAGTGAGGCCAGTGTCCTGTCATCTTTCTATATTTGCAGAGCATAACCTTGACATATTGATACCTTTGAAGGCCTCCCTAAGTGTACGCACTCATTTATGAGTTGAAACTGCATTGTTTCTGGCTAATTTATCCTGAACCAGATTTTACACACTGACCCAGTAACTTACTTTGGGCATATTGAGGAATTTGAGTTTCTTCAACGCTATTCTATTATATTATAAACAACTATATTTTCCTGGGATATGACCCAGGCAACATAGTTCTTTTATAATTTTCTTTGTAGTCAAAGCTTCTCCTCATTGGATAGGAAAACTCAAAGTACTAGGTAGGAATCAAGACTTGTTGGATGGAAAAGAAGCAGAGAGAACAATAGTCAGCCTCATTCGCTAAGTGAAGACACCAGGTTTAATCAGCTGAAGTGCCCCTTAGCTAAACTAAAGCTGGGTTGAAGTTCATTGTAAGGGTAGAGCAGAAACTTGGTCTTATTTACTTACTGCTTAACAAGTATTTATTATCTGTTTAGTGACTGGGATTATTAATAGGAGTAAGATTAATTTTTTGCTCTTGAAGTGTTCATGATGCATTGAAGAAGATAGATAAGAATCAACAGTGCCCCTATGTACTGCTGGTGGGAATGCAAATTAGTACAGCCACTATGGAGAACAGTATAGAGGTTCCTTAAAAAACTAAAAATAGAATTACCATGTGACCCTGCAATCCCACTGCTAGGTATATACCCAAAAGAAAAGAAATCAGTAAATCGAAGAGCTATCTGCACTCCCATGTTTGTTGCAGCACTATTCACTACAGCTAAGATTTGGAATTAATCTGAGTGCCCATCAACAGACAAATGAATAAGAACATGTGGTACATATATACAATGGAGTACTATTCAGCCGTAAAAAAGAATGAGATCCTGTCATTTGCAAAAACATGGATGGAACTGGAGGTCATTATTTTAAGTAAAATAAGCCAGACACAGAAAGACAAACTTTGCACGTTCTCACTTATTTGTGGAAGCTAAAAATTAAAACAAATGAATACATGAAGATGGTAGAATGATGGCTACTAGAGGCTGGAAAGGGTAGTGGGGAGTGGGGGAAAATGGGGACGGTTAATGGGGAGAAAAATGTAGTTAGATAGAATGAATAAGATCTAGCATTAGGTAGAAAAACAGGGTGACTACAGTAAATGTAATTTATCATACACTTTAAAATAACTGAAAGAGTATAATTGAATGTTTATAATACAAAGAAATGATAAATCCTTGAGGTTATGGATACCCTCTTTACCCTGATGTGATTATTGCATCATATGCCTGTATCAAAATATCTCATGTACCCCATACATATATACACCTACCATGTACCATAAAAATAAAAAAGAATCAACGGTGCTGGGTGCTGTGAAAGAGGCAAGCTGTGTGCGCTGACATGGGGCACGGGGTGGGGACATCTCACACTCCAGATTGGGAGACTGATGGAGGAGAGACAGGCACATTTAGGGGGCCCTCACCACCATCTGATGGCTAAAGTTTAAACCTTGATGTTCGGAGATGTTAGGAACTTGATGTCCTTGAGTCTTAAATGTAAAGAATATGTGCTCAGAGGTGAAGTTTTCCCTGCTGATTCAGAGGAAGCTGACTCTCAGCCCCATGGAATCTTTTGAACTGGGAAGTCATTACTATTTGATTACTCTGTTATCACAGAAAACTTAAGCAAACATTTTTTGGCAAGAGTAGCAACAACAATAGCTGTTTTGAAAATATTCTTTCATTTCATCGTCTCTGTTAAGGACGTTGCTTATAATTTTTGTAAAAACCGTATAAAATAGTACTAAAATAGTATTACTCTACCTATTTTGTGAAAATGAAAATAGACATATAGAGATGTTAACTTAATAATTTAGGCACTCAGGTAGTAAGTTTTAGAGTAAGGGTTTTAGTCCATAATATACTGCCTTTTTGCAAATCCCTGTTTTTAGCTATATTAAATCTGCAAAAATTGCAATCTCTTACTTAGCCCAACTTATCCTTGCCAGAAAATACTTCTTGAATGATGTCTCTGGCTAGCTTCTAAAATTCTTTAAAATGCACATTTTTAAGTGTTTAAGGAATAAGACTCACATAAACAATTTTAGAGAAAGGAAACAAAAAGATTACATTCTAATATGAGAGATAGCAGGATACAAGAGCAGAATTAGATTCTTGTTCTGAATGTTGCTGAAAATTCTTTACCCCCTTGGACTGGAGTTTCTAGAGAGTTTCCTCCTCTACAAATTAAAGATGTGACCTACCTGATCTTAGCTCTCTCTTCCAACTCTAAAATTCTTTTTAGGATTTTAGATGTCATAAGGAAGTTATGACATTTCTGTCATGATTTGTGAACCAAGGAAGAACTTTGTTTCTTTGGAGAGATTGTCAAAACTGGCCACATTCTTGTCTGTGACAGTCGGGGAAAAATTCCATCTCAGGGCCATACCACAAACACTGTTTTGAATTCAGAGTATGCCCATCCATTTTCTCCATGGGATGTGTAGGGGTTAATGCATATTTCTTGGTTTCTAATGTTTTGCTGTAAGGATCTGATTTAAAAGCTCATTTCCTTACACACCAGGAGCAATGTTTGTAGGTCAAGCTCCCACACTGTGAAATACTTGAACTCTCTAGGAAATATCCTGGGCGTATGATTTAACTTTTGGCTCAACTTGGTCTTGAATAGGGGTGTTGGAAAATATGGAACAGGGAGAAAAACCTCACCAACACTGGTGCAAGAGCCTCAGTTTATTTCTGGCCTGCAATAATTCTTGCCAGTCACCTTGCATCTTGATTACTACATCGTTTCACTGCTTTCACAAGCAAAACTGAACGCTGGCTCTATCTGCCTGCTCTGCTTTCCTGCTCAGGAGAGTAATCACTCTGGATGAAAAGACACATCTCCTGACAGAATAGGGAATGCTAAACAACTGACTGCGAGCCTCGAGCCTTCACAGAGTCCTTAGCAGTTCCTGTCAATGCTTTCACTTGTTCGTAAGTTGTTGAACTCTCCAGTTCCCTCAGAGATTTCCAATGCTCACCACACTTCTGCCCCCTTTTAGTGCCCTCTTTCTCAGTCTTAGCAGATGATCTTGCTGTTCCTTTAGTGAGGACAGTTAGGTCCCAGGTAAGCCCTCTATCAGCCAACAGCTGGTACCTACCTGCTGTCCTTCTTCACATTCACGTGGGTTCCCATGATCTGTCTTCCTGTCTCAGAGGAGGGCTTGCTCCTTTTTCAGGTCGAAGTCCTCTAGGCCACTGACCTAAATCATGAATCCTCAGGTCACTCTGAACTCTGACATCTCATTCCTATAGTCATTGTCCCTGTCTTGTGTGCCTCCACCCTCTCCTCCACAGGTTCCTAAAAAGGGAAACTGGCTTTGGTGCTATTTGTCCTTCTAGCCACCATCAAGTCTCTCTCCTCTTTTTGAGAACTCAAAATTTCCAAAGGAGTGGACTGTACCCCTGACTCTGCTTTCTTACCTCATACAGGTGTCTGGCTTTTGACTCCACCATTCCTTAACTGCTTTCACTAAGGTCACCAAAATTCCCTTTTCATCAAGATGTGATTGGCCTTTTGTGGTCCATGCCTTCATGGGTCTGTGTGTGGCACTTGGCTAAGGTGACCAATCCCTCTTCTTTAAAACATGGTGTTGCTTCCTTTTTCTGACATTATGTACTTCTTTTGGTAGTCTCCATCCCAACCGGGTTGTGCTTCTCTTGCACGCAGGCTCCCCTTCCTCTGCCATTATGGAAAAGTTCACCGAAGGCTGGATTGGGTGGTCATTATGAGTGAAGGTTTTTGAGTCAGATTGTCTCCTTTTTTTCCTTTCTTTTTTTGAGACAAGATCTTGCTCTGTTTTGCCCAGGCTGGAGAGAAGTGGCCTGATCACAGCTCATTGCAGCCTTGACCTCCAGGGCTCAAGTGATCCTCCCATCTCAGCCTCTTAAGTAGCTGGGGATACAAGCATGCACCACCATGCCTGGATAATTTTTTTTTTTTTTTTTGAAATGGAGCCTCACTCTGTCGCCCAGGCTGGGGTGTAGTGGCGCGATCTCGGTTCACTGCAACCTCTGCCTCCTGGGTTCAAGCGATTTTCCTGCCTCAGCTTCCCGAGTAGCTGGGACTACAGGCATGTGCCACCACACCTGGCTATTTTTCTTTTTTTTTTTTTAATTTTTAGTAGAGATGGGGTTTTACCATGTTGGCCAGGCTGGTCTCGAATTCCTGACCTTAGGTGATACGCCTGCCTTGGCCTCCCACAGTGCTGGGATTACAGGTATGAGCCACCATGCCTGGCCCAGCTCATCTCTTACTATCTGTGCTTCCATAGGTTCTTAGTAAACTCCTCTGTACCCCAGTTTCATCATCTTTTAAAATGGATTTGATAATATTTCACATTGTTAAGAGGATGATTAAATCAGATAATGCAGGAACAGCACTTAATGTGTTCTTCTTTTTTTCAGAAAGAAAACTTAATCATTATGAGATAATTATATAAAGCAGCATTCAGAAATGAAAGATCAGGTTTCCAATTTGCAGTTTTACAATAACAGCACGCCGATATTCCATCATGCTTTAGGCTTTTCCAACTGTAAATATTATAGGAACTCTTGGAAAAATAAAAGAAAGGTGCTTTTCTGAATTTGTCATGAAAGAGCCAATTAGAATTTTTAGTTATTGAGGGACATTTTGAGGGATTTTAGAGCATCTAAGACTTAAAATAACAGGACATCCAGTTTTGATGACTACTGGAGATTTTTTAATAACGTTACTACAACTAAAATGAAAATTCAACACCACAAAGAATCTCAAAAGCACCTGCATTATACAATTATAATATATAATAATATATAATTATATACAATATATAATATATAGTATATAATTATATATACCTGGATTATACAATTAAAGCAAGTCATGATTAGATTAAAAATAGGTAAGTTCAGCCTTTATTTCTGATAAATTAATACAATTACCAGGGATTTTCTGGCTTCTAAATATAAATATGATAATAAAGTATACCTGAACCAAATAAGGTTGATTTCAAACTTAAGTGTGGAGCCCATCATAAATTACAGCAAATGACCATTAAAATTCTCATAAAATTATGATACATGAATTTTAAAAATCTTACAATTTTGACTTGATATTTTTGCTATTTCTTATTTGGTTATCCTAAAAAATAAAAAACCTATGTCAATATTTCAGATTTCTGTTGCACTTTTCCCCCCAAATCTCTATTTAACTATTTTGATCGGAAGTTTACAGAGTCTTCTGAAGGTCATTAATCCTGCAGAATGTTAAGCTATTGCTTAGTAAATTTTTTTTACTCACTAAATAATATTTTGGCTTTCTAATTTTTTGAATCTGAACATCAATTATAATTTTATGTATCAGTGTGAAATGAAAGATTAAACTTCATAAGTCAACTATACTATTAGATGGCATAACTTTTGATGTAACACCAATAAGGAGATGTAAATTTATCTGCATATATATACCATATATGTGTATATGTGTATATATATAAATGCACACAATATTATTTACCTATATAATCAAATGTCATGATTAAATTATCACTTAGATAATTAGATAGGTAGATATTAGTTTGGTGCAAAAGTAATTACAGTTTTTGCCATCACTTAATGGCAAAACTGCAATTACTTTTGAACCAACCTAATAATTAGCTATGTACATAAAGACAAAACTATATACAAGAGCCAATAGAACACTGTATTGCTTATCAATTATTTCCAGGCTCACTTTAGACCGACTGCCTTAGTACTCAAAGATGTTTAATATTGTTAACATTTATTGCTTGGTTATTGTCTGCAAACCACTGATCCCAACACAACAAGCCAACAAAACAGGTGCTGTTAATAACCTTATTATAGGCAAGAGGAAAGGGAGGCGGAGGGAGAGTAAGTAATTTGCCCAGCATCACATAACTAGATGCTGGTGGAGTCAGCATTAAAAAGAAAGCTGCATGGCTCCAGAGACTATTTTTTTTTTCAGAGTTTACAAAAATGTATTTGTTTATGAAAGCCATGATTTAGAACATTTAAAAAAAGCCCTCCTGGGAACATAACTTGGGGAGAAATGTGGTGAGAGGGCGAGACTCGGCCACCCACAGGCATGTCACAAGATGTGCCCCGGCTCTCTGGGGTGAACTCTGCTCTGACTTCAGGCCAGAGGTGTCTGCCCCAGCAGCGCCCTGACAAGCTGAGTGGTCGGAAGGCCCTGGCTGGAGAGAATTCATTTGGAACCTTTCTTCTTTTTCTTATTTTTCATTGGTGTTTCTTTCAGCGTAGTGTCCATTGCTACCTCTACTGGCTTTGCAGCTTTTTTTTTTCCTCTTGTCTTTTTGGGCTTCAGGGTGAAATCCTGGCCATCAGGTGGCTGCACACAATTCCCTGCACCCTGAGCAGAGGCCTCAGAACTCTCTTCCCAGCAGAGGCCTCTGCACTGTCCGTCTGTCCGTGCTCTTTTCTCCTTGGATGCCGACTTCTGGACCTTGTCTCTCTTAGGCTTTCCCTCTTTAGGCCGCTTGGCCTTAGGCTGTGTTGGGGGGTAACTCTCCCCATTTTTACCTGTTGCCTCTTTGTTTCTTTTCTTCCCCCTTTTGCATTCCACTTGGGTCTTGGAAATGTCAGGCCCTGGAGCTGCAACCTGGGGCTTGTTCTTCAGTGCTGCCATTCGCTTGGCAAAACGCTCCTGGATGGTGAAGGCATGGGTTGTCATCGTGGTTTTGTTCTGTCTGGAGTGGAGGGACTGGAATTACCCTCGGGAGTCTTCTTACTCTGTTTTTTCCCAAAAATGCAGTCACGATCTGTTTTGCTCCGAGATGATAGATCCTTTTCTTTTGTAAATTTCCTATGATGAACACAGTTTTTGAAGATTTTGGAATTTCTTCAAGACTAAAATATTTCTTTTTCTTGTTGTCTAAGGAGTCTGCTGTTTCCTGCCTCTGACAAGTGTTCAGTTCCGCCAGAAGCCAGTTAAAATCATCTTGATGGGCAATCCAGTTGGCTTCATTATTGATTGTAGCTTGAAGTCCCAGGTCGTTATTTTTAACTTGAACTTTAATATCATCTGGGCCTCCTTGCTCCTGAACCCCTAAACCCCTTCCTTTAGACCATTCCATCTTCTCTAGTATCCTCTGGCCAAATTTAGAATCAGCATTACTCCAGGCAGTGTTTTGAGTATTCACAGCCCACTTCTGCTTCTGCTGCTGCTCAGCCAGCATCAACATGTCATGGAGACTGTGACACCACGACCTCCAGACCTGAAGGACTTCGGCCACTGGGCGGGCAGCAAGATCTGGGACAATCTGGACAGATGGGACTCCCTTGCCAGGTGGACAGCAGCCCAGAGACTATGTTCTTAATTCCTAGGTGAACTGGTTCCCTTATTTCACTGAATCCTTGTAACAACCTTAGGGGTAGGTGCCCTTTAGGTTGAGGTATATGAAATTGCTAATATTTACCCATTTTAACTTAATACACAAACAGCACTTTCATCTGCTACAACCACATAGCATTCCTATTTTATATTTTATTTTATTTTATTTTATTTTATTTGAGACAGGGTCTTGCTCTGTCTCCCAGGCTGGAGCGCAGTGGTGTGATCATAGCTTACTGCAATCTGGAATGCCTGGGCTCAAGCAGTGCTCCTGTCTCAGCGTCTTGAGTAGAGGGATTACAGGTTCAAGCTATGGTGCCCAGCTTATCCTCATTTTAATAAGTGGAAACAGTAGCTTACATTGTTAAGTAACTCACCCAAGGTCAGGTTGTGTGGAATGGAGCCAGGATTCAAATCCAGGGCCGGTGGATTTCACAGCCCATCCTTGCCATTACTCTATATCACAGTAGTATGTTTTCTCATTACCCTTGTGATCTAATCTCTTTGTCCTCATTCCTTGCACTCAAACCACTAGGCAACCAGTGTCTTTGTAGTCCCCAGATTCAAACTACTTTTGGATAAGTACCTGTTGTTCTACTACCACTTCCAATCATGTTTAGCTTCAAATTTTATTGTCACTTCCTTTTCCATTGACTCTTAGACCTTAATGGCTCATGCTAATAAATTTTGGTTCTCTTCTGCTTCTCAAATTGTTTAATAAATTTTCCTTACAAGTAAAGTATCATATACTATGTGAGCTCTAGATGAAGACTAATTGGGGTACTTAGTAATTTCTGCAAGAAGCAGAAGTCCTATTTAAACTTTTAATGAAGAAGACACAGTATATCCTTATTAACAGGCGATAAGTAGTTTTGCTTTGATATTTTCCTCTATGACTTGTTTGGCTCTCATATAAATTATTGAATAGCTGTCAATATTTCCAATTCCTATTGAACATTTTCCTCAGGGACCCAGCCTCACAATGGATACTAAGCTCTGGTTGAAGTGCAGATTCTTATTCTAATTAGGTTAATGGAGTATATGTTTTGTGAACAGGAAGTTCTTTACTGTAGAATAGTTATCAAAAATTCCCTGTGGGACCCAAGGACAAAAGAGATCAATATTTTACTGGCAGAAAATTTCACTAGAGGAAACTTCCTTTCTGTGTCTGCTGATTTTTCTGTGGTCATTCATTAGAAAGCCTGACCCAATGGGGTTATAGACTTTGGGATGGTTATTGCTCTCAGCATAAAGGAAGAAGTCAAGAAGAAACAAATCTGTTTTAACTTTTCTTAGAAGGAAACATCACAAAACAGCTCTTGGAAAGGACATGGGTATTAGTCTTTTCCACAAGCACATCATGTTAAATCCTGTCATCTGCATTCATGGACATTCATATTTATACAGCGCTTTCTGCAGCATAAGTCCAATAAATAATACATCTCTTCCATTTCACTAATTCTGAGGTAAGTTTGCAATTATAACAACTAGGCAATGGATTCATGTTTTAAGCAAAGGGCACATTTTAGGCTTGCTAGGGTGACCAATTGCGGTAGTTTTTCCATATCCATCCTGGTTTCAGCACTGAAAGTCCCTTGTCTTGGGAAACTCTTTAGTCCCAGGTGAATTGGGACAGTTGGCCACTGTAGGTTTGGATATCGGGGGACCAGCCCCCGATATTTCAACATAGGTTCTTTTCTATTTTCTCTAAGTGTTGGCCGGTCTGATAAATAAAGGGAAAGAGTACAAAAGAGAGAAATTTTAAAGCTGGGTGTCTGGGGAAGACATCACATGTTGGCAGGTTCTGTGATGCTCCCTGAGCTGCAAAAGCAGCAAGTTTTTATTAGAAATTTTCCAAGGGGAGGGAGTGTACGAATAGGGTGTGGGCCGCAGATATCACATGCTTCATAGGCCAATAAAAGATCACAAGGCAGAAGGTCAGAGCGAGATCACAAGGTCAGGGCAAAACTAGAATTGCTAATGAAGGTCCATGTCCTGTTGGGCACACATTGTCATTGATAAACATCTTAGCAGGAAACAAGGTTCAAGAGCAGAGAACCGGTCTGACTAGAATTCACCAGGCTGGAATTTCCTAATCCTAGCAAGCCTGGGGGTGCTGCAGAAGACTAGGGCGTGTTTCATTCCTTATCTACAACTGCATAAAGCAGACACTCCCAGAGTGGCCATTTTAGAGACCTATCCCTGGGAATGCATTCTCTTTCTCAGGGCTGTTCCTTGCTGAGAAAAAGAATTCAGCAATATTTCTCCTATTCACTTTTGTAAGAAGAGAAATATGACTCTGTTCTGTCTGGCCCCACAGGCAGTCAGGCCCAATGGTTACCTCCCTTGTTCCCTGAAAATCACAGCTATCCTGTTCCTTTTGGATGCCCAGATTTCATATTGTTCAAACACACATGCTGTACAAGCAATTTGTGCAGATAATGCAATCATCACAGGATCCTGAGGTGACATGCATCCTCAGTTTACGAAGATGATGGGATTAAGAGATTAAAGTAAAGACAGGCATAGGAAATTAGAGAATTGATTGGGGAAGTGAAAAATGTCCATGAAATCTTCACAATTTATGTTCAGAGATTGCAGTAAAGACAGGTGTAAGAAATTATAAAAGTATTAATTTGGGGAACTAATAAATGTCCATGAAATCTTCACAACTTATGTTCTTCTGCCATGGCTTCAGCCCGTCCCTCTGTTCAGGGTCCCTGACTTCCCACAACATTTGGACAAATCCACCATGTGGGCTGATCAAAATTTTCTCTTTGTGTCAAATAATAATGACAACAACAAAAACCCCACAAAACCCCAGTGCTTTCAACTCTTATTTCCTTAATTAGAAACAGTCAAAGACACTGATTTCAAGTTGCAAGGAGCACAGCCAGATTTATTTACATACTTGATTTCATGTTTATTTTTCTTGTAACCTGAGGCTGAATGGTAGAAGTAAACATTCTCAGATCAAAATGGATCAAGTTGGGTCTACATTTTGAACATCAGATATTTGAATACATTCCATATCTGTATCAAGAGATCGTTTATTTTTGCCATCTCCTCATTGCTTAGAAATAGGACTTACGACAAAAGACTCAAGCATCTTTACATTTGTAGGACCACAGTACCATGAGAGGAGATTCAACTCTTGGCTTCACTATTCTCATTTTGGTTTATTTCATTTACAGTTTATTCACCCACTACACCATGCATCTTTTACTCCCCCTCTGGGAAGAAGTAGAAAACTGCATCAGTTTCTAGGACATTCCATATCAAAGAGACACAATGAAAACTGGCAGCAAGTGGCACTGCCATTGAGTGACTTCTCCCTCAACCATCTCTGCTGTGTGGTGCAATTTAAGGTGGATGAATGGCATACTCTGGGCTCCAGGCCAGCTAACTGGCCCTGGGGGAAATCATTCACACCCACGCTGATGCACACACCCTTTAAACTCTCTTTCCTGCCCTGCAGCCCCCCAGATGAAATCCTTATACTCCAGGAAGCAGCAGGTCCTTTCATTGCTGTCTCTGGGCTACAGGAATCAAAGAGCAAAATGAATGTTTTCCTCTGAGAACTGGCACTGAATAGAAGGAAGGAAATGCCTACTCCAATTCAAGCATGTTTTAATCTCTGGAGAAGTGGGTACTGGGGAGGGGCAATATTGGCTGAGGAATCAGTGGGAAAGTCATAAATTTTGTCTCTTATCCCAGCAACTAAAATTCTTCCTTTAGAGTGCCACCCACTCTTTTTTTTTTCTCCTAAAAGGATTTGGATAATGAACAATCACTTTCTAAATTCTCAAGTTCAAAAATCTCTCAGTGGAGGAAGAAAAGGGAGTTTTTGAGTAAATCTCCAAAGGCTAGATGAATCATTGAAAAACATGCTCAGAAATTTCAAGATTCACACACACCTCATGAATATACCATCTGAATCTAATCTGAAGAATCTGGCACTAAAACAAATCAACAGTTCCTTACCTCTTCCTCTCTTTGACACTTTTAATATCTAACAAGGCCAACTCATTTAATTTTTTTAAAAACAATTATCTCTCATTCAAAGATACAGATGAATAGTAAAACACCAGTGTGATCGACTTCTCAAAAGTCTGACCCACAGTCAGACAAAAACAGATTGGTGGTGGTGTGGGGGGAGGGGATTCTACATGTCAAGTGACATGGACTCATCACAATGTCAGTGTCCCGGAAACCTTAAAAAAAAAAAAAGTGGTGCTTGTGCTGGCTGTTCTAAAGTAAATGAGATTTAAGGGACATGACAAGCAAATAGAATGTAGAAACTTGGAGCTTAATTCTTAATTGTGATAGTGTGATTATAAAGGAGAATGCCTTTTTTCTTAGGTGCTACATGCTGAAGTATTTAAAGACAAAATGTCTTGACATGTCCAGCTTATTTTTAAAAGTTATCATCAATGAGAGACAGAGAATGACAGAAAGAAAAGGAGGCAAATGTTAAACAAACAAACAAATTCTGGGCTAAATATTGATTTGGAGCTCGCACTGGAAAATTCCCTGTTGCTTGTTCAAGTCCAGGCAAGTCTATGAGTTCGCCAATTGGCTTCAGGGTATAAATTGGACTATTTTGACACGTTCTAAAGATCTATCGTTAGCCTGGCTTCCATTCAAGTTTTAGCTAACAGGAAGCACTTGATTCTCTGAAGAGGTGTGTCAGAGCAGAATTACTTACAGATGTTCCTTACAGACATATTCCAAATTTGTTTCTCTCAATTAATTTTTCAATCAATTTCTACACCCACTTCATTAGATTTTACATTTAATTTGCAAGTAAAATGGCATTTGCATTTTCTTGAGTAACTGTGTCCCTTCTATTCCCTCCCATCCCCATTTCTAGAATCTCAATTATGTTATGATACGTCCCACAATAATTGCATTATAAAATGTCATGAACCATGATTATAGGGAGGCTATTCAGAAAAAATTCCCTCACTGTCTATTCACACTAAAGCCTTGATTCATAAATTTGAAAAAAAAGTTCCATGGTTATATGAGCCAGTGGAGAATCTTTGTGTTTTAATAGGTCAGATTGCCCAGGGTATTGGACCTGCTCATATATGGGAGTTTTTGAACATGATTTTAAAGTAAGTCTTTGGAGCCTCTTTTAACAATATCAAAAGTAGTTTGAAGGAAATTTACTTTTTTTTAAAAAAGAATCCTCATTGCAAATTTGACCATTTTATTCTTTTGTTGGGTCACCATTTTTGAACATCTGGCAGTCAGCACATGGGTGCAAAAGGCTCATCTTCAGCAGTTCCTTGGCAAGATCAGTAACCTAAAAATTCGGCCCTAATTCTTTGATATCTTTGAAAGACTAACCTCTCTGTCCATTGCTTACTCTTTCGTTCCACTTGTACTTGAAGTTTCATTTTTTTTTTTCTCAAAAGCATTCTGTAATTGAAGTCATTCCAATGGAAATTTTAGTGATGCTATGCTGGGCATTGTGCGGGGCAATGCAGGCGAGACATGGAGGAGTAGAATGTGGCCTCCTGGTTTGTAAGGAGAATGTGACCCAGCAGGAAATAGAAGACACATGTGCTAATTACTCTTATGTAGTGTATGGAATATTCCACATGGGAGTTGTAAACAAAGGATTCCTTACCCATGACTCCAGCACAATTAGAGGCTCTTTCCTCATGATTCAAGTGTCCATCTTCCTCATCCCCCAACATCCGGAGTCAGGCAACTACCTACTCTATTAGGGTTAGTTGGGTTACCAGTCTAGAGTGAATTTCTTGAGTCAAAGTCAGTGACATTCATTTTATACCTTTAGCACCCATCAGTGTTTTTGGTATATAGGAAGGCCTTGAAAATTATTGTAGCACAGAATGGGTGGCTGGCAGGATGATGAATGGTTATCCCAAAAGCTGACATCTCTAAATACTTCCATAATTAGACTGATACAAGCTTCAGGGTTTGGAGACCTTTGGTTTCAATCTCTTACCGATATTGCTTTATGAACCCAGGGATGAAATCACCATGGTGAGAAAAATGACAAGGAATTAGATTCTCTCATGTATATATCTGCTATTTTTTCTTTTGTAACAAACTGAAAAAATACAAGAGCATATCTTCATCTCTACTACCATGATCTTAGAAATTAGCTTCTGTACCTCCACTCACTACTTGCTCAATCTCTGGCCCAGTTTTATCATTTTATCACCAATTCCCTCTGGGACCAACTGTATCCTAGGTCAATAATTCAATTCTGGGACAACAGAGCTCCTTGCTCATCTCTGCAGGTTAGTGAGAAGATTGTAACACAGTCACTCATTAGTAAGTAGAAATAAAGTCTAGGTTTAATGGACACACTACTTCCAGTGATAAAAAGTAATCCTTGAAATATTTTTAAAGTATAAAGAGCTTTGGCTAGGAGTGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCTGAGGCGGGTGGATCACTAGGTCAGGAGTTCGAGGCCAGCCTGACCAACATGGTGAAACCCTATCTCTACCAAAAATACAAATATTAGCCAGGTGTGGTGGCGTGTGCCTGTAATCCCAGTTACTCAGGAAGCTGAGGCAGGATAATCACTTGAACCCAGGAGGCAGAGGTTTCAGTGAGCTGAGATTGTGCCACTGCACTCCAGCCTGGGCGACAGAGTGAGTTTCTGTCTCAAACAAACAAACAAACAAACAAAAAAACAAAGAAACCCTAAATATATATATATATAATATATATATACACACACACATATATATACACATATATACACATACACACACACACACATACACACACACACATATATATATACACACATATATATAAAGATCTTTGAGTCCGTCTGATTACTTCCACAGGATGGGAAAGGGTTAACTCACTTTCAAACCACTTGGATTAATAGTAACATTATTTGTATAATATAAAGCCAGCTTCAAATAAATATCAAGAGGTTAATTCTATTAAATAACTTCTAAATTTTGTTACTCAGTACAATCAGTAAATGGTAAATGAAGCAAGGAAAAATACTTTTTCTTGAGTAAATGTTAAGCAAATGGTGGTATACATATAAACCCCACTGGTGACTTCTGCCTCTTTTTAGTATTATCATTGTGATGATTTGAGTTGTGACTACATGCCAGAATGATAAGTGCTTTACAAATATTATCTCTAATCCTCACAGTACTATAAATTAGGCTCTATTTTCCCTAATTCACAGATGAGAAAACTAAGTTTCAGAGGTTAAATAACTTGTCTTGGATCACGCATCTAGGAAAAGCCTCCTGGAAACCAAATTTCACTATATGAGTTAATAAAATTCATGTCTGACGTTGACCTAATCAAGGAATCTAGTGGTAGTACATGCTTGACAAGTGATAGAGTAGGTTCCATGTAACACCAGAAAGTAGATGAGGTCTGACTTCAGCACTTTCAGCCTTTTGATAATGTTCAGTATAGGACTGGGCCACCATTCTTTTCCTCTTTCCTCCACAAGTCTTGTCTTAATGAAAATCACAATAACAGAGCTATATACCTCAGTGAACTTGTTTTGTTATTTCTCTTAGGGAGATCAGAAGTTTTAGCCTCCGTCTAATTGTTAATAAAATGTTTTAACTGTGTTATGAGGATTTCAGGTGTAAGTTAGTAAGAGACAGGTATATTTTGAAGGGCCTTCCTTTTGCACATGAAATTCACAAAGATACAAATTTGTGAATTTCATGTGCAAAATTGGCTGCATAGTCATCTGTGTATTAGTTATTCTGTAGATAATCATTCATTGAAGATATATTTATTGAGTACCTTCAGTATGTCAAGCCCTATTCTAGTTGCAAGATAGACTACATAATTTGCAGGTCTCAGTTCTAAATTAAAATATGGAGTTCCTTGTTCCAAAATTAAGAATTTTAAGACGGCGACAGCAGAGCATTAAACAAGGCATACAGCCCTTCTAAGCTCTTCTATGTAACTGTGTAGCTCACACATCCACGAAGCTGACCCTGGCTGGGTGCTCAGGATATAACGGTGAGTAGAAACTGTTTATCCCCTCATGTAATTCATAGTCTATTAAGGGAGACAGATTGTAAACCAATGATCACATTAAACAATTTGATTATTTGATAAAAATAAAAACACACTAGTAATTATATACCAAAATAATTACCCCAAAGGGAAAGAGTGAAGTTCCAGAAGACAGTTTGTCAAAGAAAGATATCTAGGTTTATGCTCAGAGAAAGCTTTCAGGAGAAGTAATGTTTAAAGGCTAGGGAGAAATAAACTAGATGATGAGGGGAGGGAGGTGACCTCCAGGACAAGAGAGTATTTTATCAGAACACGCTCAGGTACTGTGGGGCAGGGTGTAGCATGTCATAGAACTGAAGGAAGGATTGTGTATGGCGAATAAAGGGGGAGTGTGGTGGGAGCCCAGATCAAAGAGATAGACACACCCAGACACTGAGCAAAACCTGGCCTTGTAGGCTTGTGTAAGGATTTCAGTCTTTATCTCAGGGACAATGGGGATCCACTAAAGAGTTTTAACCAGGGGGCTCAGAGTAAAGGGTCTGAGGCTGAAAGGGGTACAGAGTGGATACAGAGCCACCATTTAGGAGGCTGCTGTGGCAGTTAGGCTAGAGATAATATTGGCTTAGCCTGGGATAATGGCCAAGGTGGTGGGAGATGTGGGGAGTTCTTTGGGCAGGCACATACAGAAAGGAAGGAAAAACAGAAGACTTGGAGAATTTCTGGATGAACTTGTATAAGCATGATGCTAGCAGAGGAAGTTTAAAATGAGAGCCCAAATCACAGTTTGCTTGGCCTTGCCCATCCTAGAAACTAATTAGAAAAATGAGATAAATAAATATTTTGAAGTATGAGAAAGAGCAAAACACTTTCCTCTTCTACAAACCCATCTCACTTTGAAGAGGAGAAAAATCAGTGATTTTGTTTAGTCCCTTGAGTAATGAGAGCTGTGGGTGGTCACAGTTAGAGGTCTGAAGCCTCCTCTAACTCTACAGGAGCTGGATTGTACTAAAATGTCAGATCAGTCTGGAGGGGAAATGAATCAGAACAGCTGAAATGCAGAATTTTTGCTGTGTTCTCCCTTACCTAAGGGACAGCCATGGCTTTGCAACCGTTAACTTTCCTTGAAAAGGAATTCAGACTGCCTCTGAAAGATCTGCAGAGCTGTGAAGGCTGAAAAGCAAGTTATTCTTGCAAAGGTCTTTAAGTAAAACTGGCTGCTAAAAAACAACAACAACAAAACTATTCTTCCCTTGACATAGTCAACTTAAAAAAATTGTAATGGAGCCTTCTTAGCTTTTAAATTGAGGAACAAGTGGGTAAGAACAAACCAGAATCAAATAGTAAAGCAGGAGTTCCTTCTTCCTTTTCTTTCAATGCCCTTGCTTTCTCCCCACTATGCTGCCACAACTCCTACATCTTTTTAGATGCTTTTGTTTTCCAGGGACTGAATTCTCACTTCCCTGCTCAAGGGATCATCTCAACTTGTTATTCTCCTTAGAGTAATTTTTACAAGAACATGTTTATCATATTAGGAACAAATGTGTTTGGAACTGGGGTGTTTTAAACTCTCTGTTAATGCACAATGCTTTTCGGCAGCTGGCTAACTCCTAGCAAACTTGGCCTTACAAGAGGTCACCAGAATTAGGTACTAGGACTATGTACCAACCATGTACTAGGCACAGCTTATAAATACCTATTAAAGTGAAACCCACCCAGTATTCAGTTAGCAGTATGGGTGATTTGGTGAATTAAATCCATAATGAAATCCTATCAAAATCTCTCCCTCCCCACTGATCTATCAGAATTGCTAAAGAGCTCAGCTAACAAGCCTGTGTGCGACAGTTCAGTGTTATGCACAATCTGCTTTCTTTGGTCTTACTGTTGCAGAGAAATGGCAGGAAGTTAGGTATAAGGATTAAAAATAGGAGCATATAGACCAAATGTAGGCTGTTGACCTTTAAAAAAACTGATGCCTAGTTACACTAGAAGAATGTTATACAAGTATTTCTTTTATAATTGAAACATCTGCATGAATGCTTTCTTTTCTTCCACATATACATAATTTAGACATCTTAATTACAGTTGTATGCTTTGGGGTTTGATTGTAAAAAAACCAGGATGTCTTTTTGTCTGTTCTCCCTGATGTCAAAAAATTGATTACAAATTTTATAAACTGGTTTTTCTCAGTGAGGAAATTTCTTGTCTAATTTTAGCACCCCCCAACCATTCCTAAAACCATCGTCCCATGGATCTCCATGAATCGAACTGCATACGTGCACATCTCTCATTTGCATCTTTTCCTGATATTCATAAAACCTCCCACAAGTGAAAGGAAGGAAAGTGATACTCATGGATTGGTTTCCTGCCCACCATCAAGGCCTGGGATCATAAATAAAGTCTGGGGCTCCACTTGCTGCAGAGACACAGTAGATGGCAGTGTGCAACACAGAAGTGTGAGATTCCCGACCGTCTCAGCCTTGGATGGGCAACTGACTGGGAGGAGGTTGAATCTCTGGGCACGGATGCTGTTTTTCCAGCCTAGTCAGAGAGAGAGGTTGTCTTCCTAGGAAATGCTTTTTCTGCATAAACTTGGTTTTGCTGATTCAGTCAACTGCAGTTATTTGGGCTACTTTGGCACCAAAGAATGTTAAGCTTCTTTAAGCCTGAAAAATGTCTGTACTTCAAAACTCTACTTAAATGCATAAAATAATCTTTCACTTATATGATATGCTTCACTTGTCACTTATATGAACCTCCTTGTGCTTCATATTTTATTAATTTTATTAAAACAAGATCACTATGGATAACCTACAGATAAGCACTCTGGACATTTCATAAGCACATGTTGGATACACCAGGACTTGGTGGTTTGACTTTTCAGCATCGTAGGTGGACTAATATGAGTACCCCCATATACTCTCAAAGACCATATTTAATTAGGTGACTGTGTTGGATATTTTAAATCATTTTTATATTTCTGCATTATATGTTCCCCAAAATTTAGTAGTAATTCCTCAATAGACTTAAAGTATATTTAAACTTTTTTTTATTATAGAAGGTACAGGCGACTGGGGTCATTTTGCTGAATATTAAAATTACTTTCTTAATATAATTACTTTCTTATTATAAGCAAATAAATCATTTCTAGTATGATACTTATTATTAAACATTAGCAAAGGAGACCTTACTCAGCACCAGTAACAGATATTTTTAAAAAGAGAATTTCCCGAGAGGAAGAGGTCTCAGAGGAAAGGAGATATGTCGTATACAAATCATGTACAGCACTTAATTACCTTGAGATTTATTCATTTCAATAGACACACACCCACACACATTTTCTCAAGCCTTCCCTCCTGGCTGGATTTGTGTCTTAGGATTAGGGGCTTTGCTCTGATCTCTGTTTTACAGTGTTTGGCCTGTGTAGACTTTCCTACTTGGACTAATGTGCTCAATTGTATTTATCTTTCCAGACCTCTTGTTCATTTAGATTTCAGAGTTCTGTCCAATTCCATGGTCTCTTGGAAGTCCCAGCTTTGGCTTTTCCTGGCCTGACTCATTCTGTTGGCACCCAAGGCTGGCCCAGTTAGGCTGAACCACTGGGCATTTTCAGAGTTGCCACCATTTGACTAGAAGTCTTGGAATTCCAAACTTGGGTTGTTGACTGCAGGGTTCTCCTTCCTCAGTGTCTGAGACACAGGCTTTTGGTGATTGCCTTTCCCCTTGCGTTAAATGCTGCTGTTTCTCAGGGCTCTGACTCTAGGCCCTTCTTTCTCACTCTGCACAGTTTTCCTGGGCCGTCTCAACCACTTTTCTGGTTCCCAGTTGCCATTCCACTTCCGTGCTGATCACTTCCAAGTCGTTGTTGGTAGCCTAGATCCCTTGCCTGACCTTCAGAACTGTAGGCCCTCACATCTACAGAGACACTGACATGTCTCACTGGCACTTCCGTAAGACCAACATTTCACGCTTTGTTTATCCCACATATTGTTCTTCCTGCTTATCCCACTGATGTCAGCATCCATATCTGTGTCTAGGCCAGAAATCTCATATTCATTCTTGATTTCTTTTTGTTCCTCCAAAGAATGACTAAGTCCTGTTGATTCTGGCTCCTAAATATATTGGGAAACTATTGAAATTTTTTTTTCACCAGTTTCTTCTGCTGTTTCCTTCTATCAGGCCACCATCATCTTTTACTTGGATCTCTGTGACAGCCTGCTGACTGATCTCCTTGACTTCAGCCTTGCTCCTTTGCAATCCATTTCCCATGCTGCAGCTGAATTATATCCCTTGAATGCTCATTTGACCATGTTTTTTCTTGCTTAAAAAAACCAAAAAACTCTTCTATGGCTTACTTCCCTTGCTCTGACTCCTTCTTCTCAGCCATTAGGCCTCCACCTAGTCCACCTAGATTCCATTTTCTCTCTCTCTCTCTTTTTTGTTTTCTGAGACAGAGTCTTGCTCTGTCTTGAGTGCAGTGGCCTGATCTTGATTCACTGCAACCTCCGTCTCCCAGGTTCAAGCGATTCTTCTGCCTCAGCCTCCTGAGTAGCTGGGACTACAGGCGTGCGCCACCATGCCTGCTTAATTTTTGTATTTTTAGTAGAGACAGGGTTTCAACATGTTAGCCAGGCTGGTCTCAAACTCCTGACCTCAGGCAATCCACCTGCCTCGGCCTCCCAAAGTGCTGGAATTACAGGCGTGAGCCACCGTACCCAGCTGATTCCATTTTCTCCTAATACCTATCCTGATCCTTTCAAGCTTGTGCAAAGCACTCTTTCATCTGCTCTATAGCACGATGTGCTTTCCCTACCATAACATTTACAGAACATGTTACATTTGCTAGTTTACTTGTCTCTAACCCTCACTAGTCTGCAAGTTCAGGAACTATACTTAGCTTGCTCATCTATTTTATATCTATAACTTAGGAAATTACCCCAAATATTGTAGGGACATGGGATACAGGGGTATAGTAGTGTATTATTTGTGGTAAGAATACATGAAGAAATAAACTCATTGCAAATTATCAATGCATAATACTTGTTGGTCACTTCCCGTAGGACGGTTATGGTAATGGGTAATTGGAATTGTGTTAGGGTGGGAGGAAGGCTTGTTTAGAAAAGTAAAGCTATAGCAATTATCTTGAATCCATTCATGTAGGATAGGTTCATTAACACTGGTTTGGAAGGTCTTTGATGATTTTTTTTTTTTTTTTTTTTTTGAGACGGAGTCTCGCTCTGTCGCCCAGGCTGGAGTGCAGTGGCGCGATCTCGGCTCACTGCAAGCTCCGCCTCCCGGGTGCACGCCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCGCCCGTTACCACGCCCGGCTAATTTTTTTTTATATTTTTAGTAGAGACGGGGTTTCACCGTGTCAGCCAGGATGGTCTCGATCTCCTGACCTCGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCGCCCGGCCGGTCTTTGATGATTTTAAGAAATAAACGTAACTTGTATGGAGGTTCTGGAAAGAGAATGTCTGAAACAAGTCAAAATACATTCTCCTTTTTTATATATATGTAGATGTGATTAAAAAGGTATATATGTAAGCAGCAGTCCACTGCAACATACTATAGACAGTCTTGTCTACTTCACAACATTATTTCCCTTCTCACGTACTGGTCTTATCTCCCTTCATCATGCTATAACACAAAGGACATCGGCTGTGCCATTCCATGATTTTTTTCTGGAAGGGATCCTAGTACTTAACGGAGTACCTCAAAGATAGTAGACGCTCAATAGATGTTCATGTGCTCTTGGGTGTTGCTGGCTTTCCTGGTAACTTCTGAAGAAGAATATTTATTTTGATTAGTTTATTTTGCCTAACGTCCTGACAATGGGCAACATGCTACTAAGATCATGTGTTGTGTTTAGATGACAGTTAATTGAAAGATTTCACTGCATAATTGAAAGATTTGACTCTCTCTACTGAGTTCACAGGACTGTGCTGACTCTGCTAATTAGTTATTATCTTTTCTTGTTTTGCAATAATACCATGCTAGGGAACCCACTAATAGAATTTTTTAAAAGCTGAAGAGCTAGTCAGACAGCCAAGTACTGACAAGGACATTTAAAAGTATAGCAAAAGATCAGGCACAGTGGCTCATCGTGCTGTAATCCCAGCACTTTGGGAGGCCAAGGCAGGCAGATTACTTGACGTCAGGAGTTTGAGACCAGCCCGGCCAACATGGGGAAACCCTGTCTCTACTAAAAATACAGATATTAGCTGGGTGTGGTGGCACGTGCCTGTAGTCCCAGCTATTTTGGAGGCTGAAGCAGGAGAATCACTTGAACCTGAGAGGCAGTGGTGGCAGTGAGCCGAGATTGCGCCACTGCACTCCAGCCTGGGTGACAGAGTGAGACTCTGTCTCAAAAAAAAAATTAATAATAATAGTATGGTAGTTCTAATGAATCATATCTGTCTCTTCAGTTAGGATGTAAACTATCAGTAAAATATAAGATATGAACCAGGCATGGTGGCTCATGCCTATAATCCCAGTACCTGGAGAAGCTGAGGTGAGAGGATTGCTTGAGCCTAGGAGTTTGAGACCAGCCTGGGTAAGACTCTGTCTCCACAGAAAATAAGTAAAAACTAGCTGGGTGTGGTGGCACACAACTGTGGTCCCAGCTACTTGGGAGGCTGAGGTGGGGGATCTCTTGAGCCCGGGTGATCGAGGCTGCAGTGAGCTGAGATTGCACCACTGCACTCCAGCCTGGGCAACAGAGAGAGAGACCCTGTCAAAAAAAAAAAAAAAAAAAAGATACAGTAGAAAATGAAGATGGGATTTGTGATTCTGGATTTCCAGGTTCATGGATGAAGTCTGATGAGTTGCTATGACTGTCAAAATAGCATAGATTCATAGTTCCATGAAGGTAAAGGAATTAGGTTAGCATCTGGTTTAATTAAACTTTGATTGGATTGAATGCACAAAATAGAAAAATTATAAAATACACTGGTTTAAACAAGATAGAAGTTTATTTCCATCTCATGTGAAAGATGGCCAGAGCTAGGCAATCCAGACAGGTGTTAGTAACACATCAAGATCACACAGCTTGGGGGTGGCGCAACCCTTAAATTCATTATCCAAGAGATTAAGATGATAATAGCACCTACCTCATAGAGCTAAGAGGATTTAATAATAAAAACCATATGAAGTACTTGAATAAACACCTGGCACATATAACATGCTCAATAGGTGTTATGTATTAATGTGAGGGAGCCACAGATTACTCAAGTGATGAATAAATAGTAACTAACATTCTGATAACTTACATGGAGGAAGGATGAGGGATCTAGGAGAGGACATCACAGGGGTTTCTCATCTAGTTTGGAGGCTCTGGGAATACTCTTCTGAGGAACTAATGCCCCAGATATATCTGAAAGATGACTAGGTGTTAGTTGGGTGGCCGGCTGGGGATGGTTCCAATCAGAGAGAAACCACCTGTCCTGGATTAGGAGGGGCACCAGAAAGTAGTGAAAGGAGGCTTTGTGTCTTGATTTCAGAAGATGAGGCTGGAGAGCAGCAGGGCCAAGGCCAGGATACCTGTTAGGGATTTGGGTCCTTATCTGGAGACTAATGGGCAACCACCAACGAGGATCAATCAGTTGGAGGAGGAAGTTACCATGAGGCTGGATCTCTGCTTGTGTCCAGAGCTCCCAACCCCCAGGGGCTGATGCTCCCAGGTGGGACTGACCGTAGACAGCTTGCCTCGATGTATCTTGCATCCTGGAGTAGGGGTGGGGCTCCAGCCATTTTGAGAGATTCATAGTGTGCATTTGATAACACATTGAATGCCAGATAGCTGGGTGGAAAGGAAGCTTATTTTGATTCACACTTCCTCATTCACACAAAAATATTCTGAAAGCCCTAAACTAGAGGAGAGAATGTATGCATAATCTGAAAACACTTATATTTGGCTCTAGAAACCACAAAAGTAAAGAGTTCAAGTGGCATGGTCACCTGTGTGTCCATATTCTTGAACTCCTCAAATTCCCTTGGATTCACACTGTCCCCCTCTGGCCCCTGCTTGGGGTCTGGGACCTATCAGTGAAAGAAGGGTGCGCACACTTGGGGTAACTGAGCACTACTCATTTATTCCACAGTGGCTATGGTTGTTGAAACTTACATAGGGACTCAGGTGAGAGCAAACTATTCTTGCAGATAATATGCTGTAGAAGTGGAAATCTGTTGTTGGTTCTTATACAGCTATAAGCACACCATGTGCATAAAATGCACGAACATTATTCAATTTTTTCTTAACATGTTTGACAAAAATTTTAGAGGAACAAAAATAAAGGAGTTCATTAATAGAACTATAGTAGGAACTACATGTTATCAAATATGTAACTATGGAGTCTAATCATGTCATCTCTGGTTTTTACTGTAGTCTGTACTCTAAAACAAGTGTGGAAGTGGAGCACTCTACATATCCTAAGTGCCAAAAATATTCCTCTTCATGAAATTCGCCAGATCTGCAAAACACAGCTCCTTTTGAAGAGAAGAGCCAGGGAACTCCATTAGCAGGCTTTGATGGCATTAATAATTCAGAGAGATGCCCTCTATCTTCTTTAAGATAGACAGAAGGGTCCCTTTTAATGTATAACCAGGCAGAAAAGAGGAGAGGACACGGGTGGGAGAGAAGAGGAGGTTGCAAGCCAGCACCTGCCCCACACCAGGGGATGGAAGCTAATTGTGAAAAGCTGCCCCACTACAGCTGCTGCCTCTTGAAAAATGCAAACTGTGTTTTGAGCAAACATATCATCCACTTGTAAGTATCTTAGATTCCTGACAGATCTGATTATTCCCTCCTCCCCACTAGTGGCTTCATCTTATCTAATTAGCATGTGTGAAAGTTGATTCCTTTTTTAATCAGGAAGCTATGGAAACAAAATTAATTTGTGATTTAATCTTAACTCATGGAAGCATTAATGATAATTAAAAATTATTTTAAAAATTAAAAAAATTTTCATGCACATTTTTGATATGTTGTCATGAGAGTATTAAGATATCACAGATAAGTGGCTTCCAATATTTCCAGCACTTGAAAATTAAAAAAAATGGTGCTTCTCTCTGAATTCAGTATTCCTGTAATAATGGAGAATCTGGGAATCAAAGTGAGTACTTCTGGGAAAAAAAATATTTCTCCTGGCAGACAAAAGCTTAGAGGCATGAAGTCAGTGTATGGTCCAGCCACAGTCAGAGCTGGCTGAAAAATGTAAGAGTCAGTAAGGAATGATGTTTTTTGTTATTATCAACATCTGTTGAGGGCCTAGTAGGTGTTATTCAGTGATAGAGAAAAACTTGATTTGGAATCATCACTGCAGTTAAATAAATTAAATGGAAAAGTGAAAAAAGCCTCATCATTATTGGAAAAAGGAGAGAAAATGTTCCATATTTAGCCATATCATATGTATTAGTTTTGAGATGGCAGAAGCCAGACGAAAAGATGGCTGGATGCATCATTAGAGTTTTTGGTTACCAAGGAACTAAGATTTGCTGCTGCCACTTAGAGTTATAGAATTTGTAGTAGGGCAATGATCTTTGAATAGTTTAGAGAGGTCCTGGAGGTCCCTGAGACACTTTTAGTGAGTCTGCAGAATCTTCCCTTTTCCAACTAAACATCTGTGGGAAGCCACATTTTTTTTCACATATTTAAATCAAAGCAACATATCACAACAGGTTCAGCAAAAGTAGATGTAAGAATCCAGATGTCTTTTATTAAGCAAAAATTACAGAGGTTTGCAAACATTCAAGACAATGGAACTCTTCTAAGTAATTGTTTTTGTTTTAGAAAATAGTTATTTGTTTAAATAAAACTATATTATTTATGTTAACATGTAATAGTTTTATTTTAATTAATTAGAGCTTTAAAAAATTCTCAGTTTGAATTTCTAATATTGTAAATATGAAGAAATATAATTCATATGAACAAAAAGCTTTTTGGATTTCTCATTTATGTATAAGAGTGCAAATGATATCACCTTACACCTGTAAGAATAATTTTTTCTTTCTTTCTTTTTTTTTTGAGACGGAGTCTTGCTCTGTCTCCCAGGCTGGAGTGCAGTGGTGCGACCTCGGCTCACTGCAATCTCCGCCTCCTAGGTTCAAGCAATTCTATGCCTCAGCCTCACAAGTAGCTGGAATTACAGGTGCCCGCCACCACGCCTTGCTAATTTTTTTATTTTTAGTAGAAACGGGGTTTTAGCATCTTGGCCAGGCTTGTCTTGAACTCCTAACCTCGCGATTCACCCGCCTTGGCCTCCCAAAGTGCTGGGATTACAGGCATGAGAAAAAAGTAAATAAATAAAAAAGAGAAGAGATAACAAATGCTGGCAAAGATATGAAGAAAAGAGAAACCTCGTACACCATTGGTGGGAATGTAAATTAGCACAGCTATTATGAAAACTAGTATGGGGGTTCTTCAAAGAACTAAAAATAGAGCTACTATGTGATCTAGCAATTCTACTTCTGAATATATATCCAAAGAAAATAAAATCAGTACATTGAAGAGATATCTGCTCTCCTATGTTCATAACAGCATTATTCACAGTAGCCAAGATAGAGAATCAACTTATATTCATCAACTGATGAATGCATAAAGAATCAGGATATTCCTCAATAGATGAATACATAAAGAAAACATGGTACATGTACATGATGGAATACTATCGAGTCTTAAGAAATTCTATCATTTTCAACAACATGGAACCTGGAGGACATTATGTTGAGTGAAATAAGCTGGTACCGAAAGGCAAATGCTGCATGATTTCACCTATACGTGGAATGGAAAAAAGTAAAAAAAAATGAACTCATGGAAGCATGGAGTAGAATGGTGGCTACCAGGCACTGGGATGAAAAGAAGACTGAAATGGGGAGATATTGGTTAAAAGGTACAAAATTTTCAGGTAGATAGAAGGAATACTCTTTGGAGATCCATTGTACATCATGGTGGATATAACTAATGATAATGTATAGCACACCTAAAAATTGCTAAGATAGTAGATTTTGAACATTTTCATGACAAAATGATAAGTATGTGAAGTGACAGATATGTTAATTGGCTTGATTTAATCAGTTCACAGTGTATACATACATCAGACAATTAAAAAACAAATAGTAAATCTGGGTAAAGAATATATCTCTTTTTACTATTCCTACAAATTTTCTGTGTCTAAAATTATTTCAAAATAAAATGAAAGAAAAAATAAAATGACATTTTTGAATAATTAAAAAAGAGAGTGTAAGGATTCTTGAGATTAAAATCTCAAGTTTAAAGGGTCTTGAGATTACAATTTAAAAAGTTTGAGCTCCTAAACTTATGTGATCTGCCCACCTTGGCCTCCTGTAATCCCAGCTACTAGGGAGGCTGAGGCACAAGAATCACTTGAACCTGGGAGGTGGAGGTTGCAATGAGCCGAGACTGAGCCACTGCACTCCAACCTGGGAGACAGAGCAAGATTGTGTCAAAAATCAAAACAAAAAAAAACCCCAGCAACGCTTGAGACCTGCTCCTGCAAGTATTTAACTCACAGAAAAGGAGATAGCACCAGGTAAAAATGAAGTAAAAGCTGTGTAAGCTGTGTGTTGGGCCTTGCAGAACAGGAAGCCTGAGAAAGGAGAGGTTATTTAGAATGCAGCCTCTCTTGGGGAAAACGTATATTCCAGCGATCCTCTCTACAATGGGACTTCATTCACCCTCCAAATCCTTTTTTGGAAGTTTGTGTCTTAGCTTTCCTCTGTTGTGACTTTTACTGCTCCTTCTGCTCTCGATACAGACACCATAAAATTTACCGTTCATCCAAGAACACTTTTGAGAGTAAAAAATGGAATTATTAATAATTACAGGACAATAGCCTTGCCTAGCTGCCATCTTTCTTATCCTGTCCAGTAAGTACCCCTAAGAGTAGAATTGTTGAGTCAAAGGACATGAAAACTGTTGTAGATCCTGTCCGCTCATGATTCTATCAGGAATAGGAACACCAATGATTACATTAGCCACGAGGTGATTAGGTTTCAGCAGTGCATTTCTGTATTTGATCTCCAACACATTTTGCTTTTTAAAGTTGAGTTCTGAAATTAGAGACAAGAGCAGATGGCAGTAGATTCACTCTAATTCAGGGAGTTATTAAGAAATTTTGAATTTTTTTACTATATAATTTGAAGCCTGCTTTAATGTCATCATCATAAACGGAAGGGTGGGTTGATGAGTTTACTCAGATTAGAGTGGTACAACCTTTGGGGCGGAGCCTCTGACTCTGATTGGTTGGACAATGTTTTCCAGGCAGTATAAAAACGCTGGTGTCTCTCCGCGGAAACTCCGAGAGGAGCAGAGGTCTGTAGAGGTAGAGACGTAGGCTTCGGATCTTTTAGAATTCTGCTGGAAGTCTCCAAGTCAAGGTAAGTTATACCTTCTGTTTAAGCTATTTCCAATGTCCTATTCTGTCTTTGGCTACAAACTGGTGTTTTCGAATGCCTTTAACTATTTATTTTAGAGGAGAAAGAACTAGTTTTTTCCTGTGCCAGGGAGCTTTCTTCACCTTTAACTATAACTTTGCCATTTAAATTTTTACATATGAACCTCAGGTCACTCTTTGCATGAACTTGTATTTTTATGTGTTTTCAACTACAATGGATTTAAATGGTTTTAAAATGGTTTCTTTTTATTTTCCAACATTTCTTAAAAGATTTCTGGGTTTTCGGCCGGGCGCCATGGTTCGCGCCTGCGCTTTGGGAGGCTGAGGTGGGTGGATCACGAGGTCAAGAGACCAGCCTGTCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAACTTAGCCGGACGTGGTGGCACATGCTTGTAATCCCAGCTACTCAGGAGACCGAGGCAGGAGAATTGCTTGAACCCGGGAGGCAGAGGTTGCAGTGAGCCGAGATGGAGCCACTGCACCCCCAGCCTGGGCGACAGAGCAAGACTCCGTCTCAAAAAAAAAAAAAGACTTCACTTCGGGTTTTCACTTAAATATACTTGGCCACTTTTAGTAGTTGTGTCATAATTAGCTGAATCATTTTATTATTGTTAGATAATTCGATTGTTCCTGATCATTTGGGATGGTAGTTAACACTGAAATGAACAACTTGTGAATAAGTGTAGCATTTTTTTTCTTTTGTAAAATTGTTTTCTTAGATACATTCCAAGGTGGGTTAGGCAATTAGATTTCCAGCACCATGTTAAATTTCCCATTAAATTGAAAAAGATAACAGAATTTAAGAAAGAGGTAATCTCTGGTTGTCCGCCAGCCAGGCACCATGAGATTGGAATGCTGATCAGGACTTGGAAGACAAAGTTTTATGTGGGCAGATACCCTGTTTATTACACACGTTTGTGTTTCCAGAGTCCAGTTGAGGCCAAGAGCACAGAAGGGGCTCAATAAGTATTTGTTGGAAAGAGATTAGAGAATGTGTTCTGGGATGTAGGACAGTTCTAGTAACTCAGTCTTAGGCTGGCCTCATCGGTGTTCATCACTTCCTCTCTCTGGTAATGTTGATGCTGCTCCTCTTTCTGTCCCTCATTCTGTTACTACTGTCACCACTGAATGTGTGATTTGTGGGTTCTTGGTAAGGAGTTCTGCTAGTTACTGCTCAGTGCAGGCTCTTATTGGAGAACAGTCCTCTGTTCACATAATCTCAAAGGTGCTGTCCAGCTTTGCGAGGCTGTCTTTGGGTCATGGGTCTAGCCTGGTCCAATATGCTGTGCCCAGCATGTCAGAGACAGCTCACTCAAAGAATAATAGCCATGGTGGGAAGTCCTCTGGGAGCACCAGAGGCTCTCAAGCTTTGGGAGCAGTTGGGGTAACAGGAGGGCATCTTCCTTGTCTGGAACATCTTTTTGGTTTGTATTCAGGCATGATTATTTTGGAGAAGTTGATGACTATTATATTTTTATTCACATTAATTCAAGCCTTAATTAGTTTTCTTAGAGTGCTTTAAAGCATTTCATCTAATAACACTTTGTCCTTAAACTTGATTCTTTTATGGGCTTCTCATTTTGCAGTGGATTTTGCTGGCTTTACTCACATGTGGTAATTTTCCTGGAAATTCTGAGGATTCCTTAGAGTCACTTTTCTGTGATGATTAATGTAGAATTGGCTTTATTTTCATTATTGAATTTAGACATGAACATTCTTTTTCCTGAACTGCAGAGGATCTACAAAGAAATACTGAGTGGAGACTATACTGAGATTCTGTTAAAGACCCACTTGAATTCAGCCCCCATTAGGAGAAACTTTGGCCGGAGCAGCCAACACATCACCTGGAAGTCTTCAGACTAGGTAAGCTGCACTGTCTGAAAAGAAAGTTTCCACTGTCCTATTTCTGTCTTGTGATTATCTAGAGTTTGAAGAGTTTCGAAATCATTTTTATCACCATGACTACATTACTGTGATTCTCTAGCAATTTAGTGTCACTTTCATACACAAACTGCAGAAATATTATTTTTTTGTTATTCTTAATTTCTTAGTTAATAAATTTATTATTATTTATTAAATAATATAATTCATTTATGTATGCCAATAACTTATTTATTAATTTATATTATTTAATCTTGGATTTAGACTATTGAAGAGTGGATTGTGTACTGAGGGCTCCCAAGTGCTTCCAGAAGCCAATAAAGGATCACTTCAGTTTACTTCACGGCTAAGGAGTAACCCTTAAGAACCATGGCCAAACGCCTGCAAGCAGAGTTGTCCTGTCCAGTTTGCCTGGATTTTTTCTCCTGTTCCATTTCTCTCTCTTGTACACACGTGTTCTGCTTTGATTGCATCCAGAGGTATATACTAGAAAACCATGATTTTAGAGCGATGTGCCCCTTGTGTCGAGACGTGGTGAAGGTACCTGCTTTGGAAGAATGGCAAGTGAGCGTCCTAACACTTATGACCAAGCAGCACAATAGCCGACTTGAGCAAAGTCTGCACGTGAGGGAGGAGCTCCGGCATTTTCGGGAGGATGTGACCCTGGATGCAGCCACTGCCAGCTCCCTCCTTGTCTTCTCCAATGATCTAAGAAGCGCTCAGTGTAAGAAGATCCACCACGATCTGACAAAAGATCCCAGGCTGGCCTGTGTCCTGGGTACTCCCTGCTTCTCCTCCGGCCAACATTACTGGGAGGTTGAAGTGGGAGAGGTGAAGTCATGGTCCCTGGGCGTCTGCAAGGAGCCGGCTGACAGAAAGAGCAATGATTTATTCCCTGAGCATGGCTTCTGGATCAGCATGAAGGCAGGAGCAATCCATGCTAACACCCACCTGGAGAGAATTCCTGCAAGCCCTCGCCTTCGCCGTGTGGGAATTTTCCTGGATGCTGACTTAGAAGAAATCCAGTTTTTTGATGTTGACAATAATGTCCTCATCTATACACATGATGGTTTCTTCTCTTTGGAGCTTTTGTGTCCATTCTTCTGTCTTGAGCTCTTGGGAGAAGGGGAGAGTGGCAACGTCCTGACCATCTGCCCATGAGAAAGTCAGCCCTTCCTAGAAGCTTTCTGAGAGGTGAAAGAGAATTTTGGCCTGAGAAAGGTCAGCATGATTGAGGAAGAGATAATGTGCTATAGTGCAAAGACTTGGTAAATTTTTAAAGTAGATTTTGTAGACTTTGTAGCAAAACAATTTTCGGATTTTTGGGGTAAATTTTGTGGAATTTGTAGCTAGGTAACTGGGGTCTTTAGGGATGTTATTAAGTACTGTAAGCTTCAGTTTTCTAGTCTGTAGATGCGGATAATTGTATCTCAGTCAAACAGCTGTGGTAATTAGAGACAATACTATGCCTTTGTCTTATAGTAAATAACAAATAGAGAAATCTTAGATTGTAAGTAAGCTAGATATTAGGTTTTGTGGATAGACAATATCTTTTTCATTATTTCAAGCTGTTTTGTGTAATTCCTGATAATGTCTGAGGAGGAAGAAAAATTCAACAGCCAGTGTGAGTTATTTTGTTGATACAGCATGAAATTTCAGAGAGACAAACTGATATTGGGGAAGAACTAAGTTTTTCATTTTTATTTTCTTTGAAACACAGCCACATAAGTTTTCTTGAAAGACAAAGAACTTTGACCAAAATGCATTGTTAATGGTGATTCATATTCTTATGGGAAGTGTCATTTACCCATCTCAATAATTGGACTATTGTGATTTATAAGAATTCTTATCAACCATGTTAACTAACACATATTCATCAAAAATTGTTTTCAAGGTTGCTTTTGGATTTTTTATTTGTAGAATTTATTTTCTTGCAAATAAATTTATAAAGCATTGGATGTGTTCATGTTTATGCTGTTTGGTCCGTCTCTCACATACAGTCTGAAGTTGGTACCCCTCTTCCTCCACCACAGCTACATGGTCCCAGACTGTGATTTCCAATATGTCATCCTTATACACTCATGATGGCTCCTTTTCAAAATATTCAGGTCTCTTAGGGTTGTATTTTTTCTGATTTACTGAGTCAGCCACTTCTGAGATTACAACTGCCCCAAAAGGGCTGGGGTCTGAGCATGTTCTGGAATCTGCCTTTGACTTCCTTTCTAGAGAGACCCAGAATTGTCATTTCCCTTCTCTTTCCAACTTCACTGGGAGTAGGGAGATAGCCATTTTCCTCTCTTTATTCTCTTTTGATCTCTACAACTTTATTTCAGGGGACTCATTGCCCTTCCCTAACACTGGGCAAAATTTCAGGATACAAAATAAATGTACAAAAATCACTAGCATTCTTATATGCCAACAGGAGTCAAGCTGACAGCCAAATCAGGAATGAACTCCCATTCACAATTGCCACAAAAAGAATAAAATACCTAGGAATGTAGCTAACTAAGGGAGGTGAAAGATCTCTACAAGAACTATAAACCACTGTTCAAAGAAATCAGAGATGACACAAACAAATGGAGAAACATTCCATGGTCATTAAAAGGAAGAATCGATATTGTTAAAATGGCCATACTGTCCAAAGCAATTTATAGATTCAATGCTATTCCTATTAAACTACCATTGAGACTCCTCACAGGACTAGACAAAACTATTTTGAAATTCATATGGAACCAAAAAAGAACCTGAATAGCCAAGGCTATTTTTTAGCCAAAGCTAAGCAAAAGGAACAAAGCTGGAGACATCACAAGGCTACAGTAGTATAGTTTGTATCAATACCAAAACAGCATGGTATTGGTACAAAAACAGACATATAGACCAATGGAACAGATTAGAAAACCCAGAAACAAGACCACATACCCACAACTATTTGATCTTTGACAAACCTGACAAAAGCAAGCAATGGAGAAAGGATTCCTTTTTCAATAAATAGTGCTGGGATAACCGGCTAGCCATATGCAGAAGATTGAAACCAGACCCATTCCTTACACCACATACAAAAATCAACTCAAGATAGATGAAAGATTTAAATGTAAAACCCCAAACCATAAAAACCCTGGAAGACAACCTAGGCAACACCATTCAGGACATAGGCATGGGCAAAGAGTTCATGACAAAGATGGCAATTGCAGCAAAAGCAAAAATGGACAAATGGGATCAAATTAAACTAAAGAACTTCTGCACAGCAAAAGAAACTATCAACAGATTGAACAGGCAACCTAAAGAATGACAGCAAAATTTTGCAAACTATGCATGTGACAAAGGTCTAATATCCAGCATCTATAAGGAACTTAAGTGTACAAGAAAAAAACCAAACAACCTCATTAAAAAGTGGCAAAGGACACTAACAGAAGTTTTTCTAAAGAACACATGTGGCCAACAAGCATATGAAAATAAGCTCAACATCAATGATTATTAGAGAAATGCAAATCAAAACCGCAATGACATACCATCTCACACCAGTCAGAATGGCTATAACTAAAACATCAAAAAGTAACAGATGCTGGTGAGGTTGTGAAGAAAAAGGAATACTTATATACTATTTATGGGGGTGTAAATTAGTTCAACCATTGTGGAAGCCAATGTGGTGATTCCCCAAAGACATAAAGACAGAAATACAGTACACTAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAGAAACTGGCTGCTTATTGTAATGACCCAAATGTTTATTCTCCTTAATATTGGGATTTAGAACTTTCTGTAAGACAGAGGCTGTTGTGCAGGCCTTGCTCTTTTCATAGGAAGCAACCAGGAAAAAATGGCGAAATCTTCTACCCCTTAAGAGGTTACTGTCTTTGGACAGCCTGCAAATATTGGCTAAGAATTTGGTGGAATGCTGTTGCTTCTCATAGGTGGCAGATTCAGTTGTGCCTCTAAAATGTATGTATAGATGCTGCATGCATCTATCTCAGCTCTTAGCATGGCAGCTTCTAGGAACCTCCCTTAAGGGACAGCTGGTTCTCTCTCCTTGCCTACTTTTAGTTCTCTTCCTGCACCCCTGCTGCCTGGAGTGCAGACAATTGGGCCACAGGGATGAGGGGCCTGAGAGAACAGTGAACTGGAATAGGCCTGCACTCTTGAAGGCTACAGGGATCCCTGAGGGCTACAGAGTCACTCTGACAGCTCTGGGACACTTACCTCTGTCTTCATTAATGTGATAAAGAAACCCCATGAGGCTAGTTTACCTGCATAACAAACCTGTGCATGTAACCCTGAACTTAAAATAAAAGTTAAAAAAAGTATTCTATATCTCAGCAAAAATAAATGAGAAATATTTGAGGTGATGAATGTGTTAATTAGCCTGATTTGATCATTCCACAACGTATACATGTATCAGAACATCATGCAGTACCCACAAATATATACAATTATTTGTCAATTAAAAACAAAACTTAAGAAGAGAATAAACACTTTCTGTTTTAAGCCACTGTTATTTTTTGTGTTCTGCCTGCCCTTGAACTTATTCCTAACTCCTGTTCTATTGTACCAAGAGTTCTGAAGACCTGCTGGGCAGCCTCAAAAACGCTTTCTATTTTGCTTTGCCCTTCTCAGCTCTGGCCATTAGAACTTTGGTGAGTGTCTTCCAAGTGTCTCACAGTTTGCCCTTGGCTTCCTTCTCCTACCTTTCTATGACCAGCTTCAATAAATTAAAAAGTAGAAGTAAAACTTGCCTCAGTTGTATTTTTTAATGGAAAATTTTAAACATACAAAAATAGAGAATAGTATAATGAATCCACATGTACCTATCACTCAGTTTCAATAATAGCAACAATGGCCAACCTCCTGCCCCCAGATTATTTAAGATCAAATCTTATACATCATATCATTTCATTCATAAATTCTTATGAATATCTCTAAATGAAATGTACTTAGGAAAATGTAATTATGATGCCATTATCATAGATAAAAATGAATAATTCCTTAGTATAATCAATGAATAATTCCTTAATATAATCAAATATCCAATCAACATTCACAGTCCTTTCTGATTCAGCTGTGAGTGTTTCCATTTAAGCAGTTCCAGCTTTTCTGAACTGGTCTAATGAGTGTTTGCTTGCATTTGACTCTTTGTGTTTTCTGTATTTAAGATTTCCAACCTCAAAATAGGCAGTCACTTTCTATTTTCCAGTCCTCTTTTCGATACTTAAGAAAAACCAACTAGGGCTCTCCTCACCTCCTCCTCATCCCCAAGTCATTATACCACCCTAATGCCTGCCTGGGGCTCCTGGGCATCCCTGCCACAGTCACCCAGGTATAGTTTGCTTTAAGGACACCAATGATCTTAAACTTCAACTTTCAAATTTGCGTCCAGGTGAAAATGTGAAAAATTCACATTCATAGATAGCACGTATGTGTCACATTCTGAGACACGTTACTTAGGCAACATCTAAGTTCTATGGACTCCTCATTTGGCTCTGGGGTAGCATTGTCTGAAGATTGTTTCTATTTTCTTTATAAGTTTCCTCAGTAATGAGGGAGTAATTTCTGGGATTAGTGGCCAGATCCACTCTTTACTGAACCTGTGGGCTCTTAGTGTGGGCAGATTATCTAGCGGTAAATGTTCTCCCTCAACAAGTGAAGACATTCCTTTTAAAGAAATTGCATTAGAGAGCATAGGTTTGTGGGTGATCTTCCAAATCAATAGCAAGGTGAAAATGAATCTATATTTCTTCCTAGGAGAATGATTTAAGTATCAAAGACTAAGAGAGGCCTTTGGAAAAATGGAAACGTTCATGCCAAAAGCATCCTGTTTATGGTTTTGCCACTAAAGTTAGCCACAAATTAGGATTGGAGATTTTATCCAATTATGTTAGAAAAATTACTTGATTCAGTCTTTGCTCAGTTGAAGGAGTTGTGCTCAGTTGCAATGATCATCTAACCTATGTTATAGCTAAAGTAGAATTAATCTAATTTTAATAGTCTTTAATTGTTTAAGATGACATTTCAAACAAAATTTTTATTATTTTTCTATAAAAAAGTTCTTCCTCTTTAAACTTTATTTTCCATAAATATTTATAATCATTCATTTGCTATGTGCATATTTTGGGATTTTTTTTCTTTTTTTTCTTCACCCAGGCCGGAGTGCAGTGGCGCTATCTCGGCTCACTGCAAGCTTCGCCTCCCGGGTGCACGCCATTCTGCCTCAGCCTCCCGAGTAGCTGGGATTACAGGCGCCTGCCACCGCGCGCGGATACTTTTTTGTATTTTTAGTAGAGACGGGGTTTCACTGTGTTAGCCAGGATGGTCTCGATCTCCTGACCTTGTGATCTGCCCGCCTCTGCCTCCTAAAGTATTTTGGGATTTTTTGTGCTTCAGACTTTTCTTTTTTTAGAAACTGATGTTTATTTTCCATTAACCTTATTTCCATGTTGCTTAAGAGCCCGTGCAAGGGCAGCTTAAGACCATTCAGCGGTTGCTTCTACCCATTCAGTGATTGCTTTTACCCATTCGGTGGCCTGAGACTAGAAGCTGCAGACCAGTCTTCTGTGGCAGGCTGAGCATTTCACTCTTCAGCAGGGAACTGCTGAATAGTCACAGAGGGCACCTGCATGCCTTCAGACCAGTCTGCAACCTCAGGCTGAGTAGCAGTGAACTCAGGAGCTGAAGCAGTCCATTCACCCTGAAATTCTTTCTTGGTCACAGCTTTTTTAGCAGCAGCCTGCTCTTCTTTTTCAATCTCTTCAGGATCTCTGTAGAAGTAGAGATCAGGCATGACCTCCCACGGGTGTTCGCAGGAAATGGTGCCACGCATGCGCAGAACTTCCCGAGCCGGTGTCCACCACATCAAACCCACCGAGTGAGCTCCCTTGTTGTTGCATGCGATGGCAATGTCCACATAGCACAAGGAGAATCTGTGTTACAGAGCAATGGTAGGTAGGTTAACATAAGATGCCTCCGTGAGAGGCTGGTGGTCAGCCCTGGGGTCAGTAACCACAAGAAGCCGTGGCTCCCAGAAAGCTGCCTGGATCTGGTTAGTGAAGGTTCCAGGAGTGAAGCGGCCAGCAATTGGAGTGGCTCCAGTGGCAGCAGCAAACTTCAGCACAGCCCTCTGGCCAATATTCCTGGAGGATATAACACTGACATCTGCAGGGTTTTCAATGGCAGCAATGGCATGAGCTGCCAGCAGAAGCTTCTCCCAGGTCCTCTTCAGATTTATGATGTAGATGCCATCACTTGTCCTTTTACAGATGTACTGTTCCATCTGGAAGTCAAGATTGGTGCCACCTAAGTGGGTTCCTGCTGCAAGGACATCCTCCTCCTTCATTTGCAGGACATCAAGGGCTCTGGACGTTGTGAAAGTTTCCCTTTAAGTTACAACAGGAATTCAGAACAATGCTGTATGGACCCCTCTGTGGGTAGCGTGGAAAGGCTTCAGACTTTTTTAACCAGCTAATAAACGCATGGGGTCCAATATTTAAAATGCCACATAGTGAAACTGTTTCCTGACACTCCCCATTTATTCATTCTCCCTGAAAACGACTCCTGTTACCAATTGCTTGAGGATTCTTCCAAAGGTATTCTATATGTGTATATATATGTATGTATTTCGCCTATATATAAATTTAGTACTACCTATACATTAGTTTGCACCTTTTTTTCACTTGAGAATATTTAAGGAGATTGACTTCAAACAGTCTTTTTTCAGGACTCAGATAAAACTTTTTGTATTACATTTATCAACTTAGTCAATTTTGTGCTAACAATTCTCAATCAGATTTATAAGATAAATTTTCCCTTAAGCTTTCCAGGAAGTCATTAACACCTGTCACTCCAAAATGCATGACATCATAGCTGCCATCAAAGGACTTCTAGAAGATCTAATTCCTACAAAATATCAGTAAAATCAGATTGACCTCAAACCCTGTATCTTTCAAAAAAGACATAATTTTGTTTTTCAAGCATTGTTATTAGGTATAGTAAAAATGATTTTTTTTCTTTGTTTTTTTGTTTTGAGACAGAGTCTTTCTCACTCTGTTGCCCAGGCTGGAGTGCAGTGGCGTGATCTTGGCTCACTGCAACCTCCACCTCCCAGGTTCAAGCAATTCTCTTGCCTCAGCCTCCCCAGTAGCTGGGATTACAGGTTTGTGCCACCACACCCAGTTAATCTTCATATTTTTGTAGAGAAACGGTTTTGCTATGTTGGCCAGGCTGGTCTCAAACTCCTGACCTCAAGTGATCTGCCCACGTAGGCCTCCCAAAGTGCTGGGATTACAGGTGTGAGCCACCATGCCCAGTCTATAGGTTATATCTCCTTAATGTTACAAATTGATGAAGATTAAGTAAATAAACCTCAGCAATGACTAATACATATTTTTAAACATCTACTTTTGCTTCTCATAATCACTGAGCATCCATTTGAGCTTTATTCTTCTTTTCTTCCTTTTTTTGATAATGCTGGCAGACTTGATGAACCAATAGCATCTGACCTTCACAAACTAGGCAGAGTTTCAAAATAAGGTGACTCGTTACATTTGTTTGGATTACTTTTTGAATCCCCACATTTTCTCACGTTGGCACAATTTTGCTTCAAGTGCATCATGGAATAGATGAGACAACAGGAAGCGATAGGCTTTCCCTATTCAGTGAGTCAGGCAGTAACCAAGAGATTAATGTGAATGAATTCAGGGCTTGTGAAGGCATCATTTCTCATCAAATGGAACTGTACCCTGCTGGACGGAAGTCTGAATATGTGTGATCTAATGCAGAGGTTCCAACTGATGTGACCCACAATGTTGTCACCACCACCTCCCTCCTTGTCCTCGCTAATGACCTAAGGTGTGTCCACCATGGAAAAATCTTTCTGTTACCAGAAACGGATCCCCATCCAGACTCTAAGAGAGGGTTCTTGGACCTTGTGCAAGAAAGAATTCAGGGCAAGTCCATAGAGCAAAGTGAAAGCAAATTTATTAAGAAAGTAGAGGAATAAAGAATGGGGGCTGGGCGCGGTGGCTCATGCCTGTAATCCCAGCACTTGGGAGGACGAGGCAAGCGGATCACGAGGTCAGGAGATCGAGACCATCCTGGCTAACACAGTGAAACCCTGTCTCTACCAAAAATACAAAAAAGTTAGCCGGGCGTGGTGGCGGGCACCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATGGCATGAACCCGGGAGGTGGAGGTCGCAGTGAGCTGAGATCATGCCACTGCACTCTAGCCTCTAGCCTGGGTGACAGAGCGAGACTCCGTCTCAAAAAAAAAAAAAAAAAAAAAAAAGAATGGCTATTCCATAGCTAGAGCAGCCTTGAGAACTGCTGGTTGGCCACTTTTATGGTATTTTCTTGATTATGTGCTAAACAAGAGGTGGATTATTCATGAGTTTTCCAGGAAAGGGGTGAGCTATTCCCAGAACTGAGGGTTCCCCCCATTTTAGACCATATAGGATGATTCCCTACATTGCCATGGCATTTGTAAACTGTCATGGTGCTGGTGGAAGTGTCTTTTAGCATGCTAATATATTATAATTAACATCTAATGAGCATTGAGCACAACCAACAGTGACTTTCATCTCCATTTTCATTTTGGTGAGATTTAGCCAGCTTCTTTACAGCAAACCGCTTTGTCAGCAAGGTCTTTGGGACCTGTATTTTTGGCTGACCTCCTATTTTATCCTGTGACTAAAAATGCCCAGCCTCCTTGGAAGGCAACCCCATAGGTCTTAGCCTCATTTTACCTAGCCCCTATGCAAGATAGAGTTGCTCTGGTTCCAAAGCCTCTGAAATTTCATGTCTAATTGATGATCCCAAGATATTCAACCGTGTGTTCTGTGTCCTGGATGCTCCCCCTTCACCTTTGGCTGCCAATGCTGAGAGGCAGAAATAGGAGAGAATAGGCTCTGGGGGTCTGCTGGGCATTCATTCACGGAAACTGGAAGGATGGCTGGTCCTCTAAGGACACCAATTCTGGTCCACAGGCCAGACCTGCTAGCCCTTACCTCCTGTGATGGTTACTTTCAGGTGTTAACTGACTGGATAGCTGGTTAAGCACCATTTCCGGGTGTGTCTGTGAAAGTATGTTTGTGTGCGAATCCGGGGACTGACGGGGGAAGATCGGCTCTCATTGTGGGTGGGCATCATCCAATCAGCAGGGTGCCTAGATAGGACAAAAAGGCAGAGGAAAGGTGAATTTGTTTTTCCAAAAAGGATATTCTGGAACTGGGATGTCTCTTTTCTCCTGTCCTTGGACATCAGAACTCCAGGGTCTTAGGCCTTTGAACTTGGGAACTTGCGCCAGCAGACCCCTGGGCTCTCAGGCCTTCAGCCTCAGACTGAGAGTCACATCATGAACTTTCCTGGTTGTGAGGCCTTCAGCCTTGGACAGCTATGCTGCTGGCTCCCCTGGTTCTCCAGCTTGCAGAAAGCCTATCATGGGACTTCTCAGGCTCCGTAATTGCATAAGCCAATCAATTCCCTTAATAAATCCTCTCTCTCGTATACCTATCTATACCTCTCTACATATTAATATATCCTATTTGTTCTGTCTCTGGAGAACTCTTAACTAATATACTTCCATTACGTGGGAATTTCCCAGATGCTGAATTGAGGAAAATGACATTTTTTTTAACGTTACTGTTGGTTACCTCCCTATATAGTCAGTTCTTTTGCATCTGTTTGTTTGGATCAGCAGAAGGCAACAGTGAGACCCCACCCAATATCTTCTCTTCTCTCTAGAAAGTACTCTGAACATATAATGCTGTGAACATGGCAGGTCTTATCATGTTTTCAAGATGATGAGATATGTATTGCATATTAAATATTCATACCTGGATATTAAATACTCAGGTTTTTAAAAAATCTTATAACCATTCTAACTGACCATGATCCCAGATGGAACCCCTGCCCGCGTCATTGCTTTTGTCTCTGCCACCTGGCTGCCCCTCTAGACAGCTTCCTTTCCTTCCTGGGCTGCTCCCAGGCAACTCAAAAAACTCAACTTCCTCCCCCAAAACTCAAATTCTTACTTTTTACGTAGAGCAAATGAAGTCTGTCTCAGCTTTCTTGTGAAGGAAAAGCTGCTTCAGTCAGTTGTGTTTTTAAATAACACCCCTTCCCACTTTGTGTAACAGAATGTTTTAGAAGCTTATGCTTAAAAATTTTTTTTCAGCCACAAATTGAGGCAGACTCCTTTGATCAAGGTATTTTGTATTGGCTGAAAGTGTGCTTCTGTGGAGGGCTGGTGCAGGGAGCTGTAATTGAGAGAGTGGGAGGAGTAGCCAGGAAGGAAACTGTTGATGAGCATGACTGTATGGGGGGGTCAGCCCAGCTGGAAAAAGGCCAGGACTTATGGAGAAAGGGCATGTGAGGCAGAGAGACGAGGGGGGAGTTTATTGGCTTCTACTGAGTTACTGAATGTTCTTTCTTCTTAGATCTATAAGAAAAATTAAGTAATAAATCCTAAAAAGGCAAATGACAAAATTTACATTCTTTATTTTTCAAAAAGAACTTAGAAAACAAGGACAAGAAGGATATTTTTAAAATGTAATATAGACCATATTAAACCAATATTATGGTTGACAGTATTTAAGAGAAAAAGACAAATGACTAAAATTGATATTAAAACATTTATTGAGCATTTACTGTGTGTGAGGCATTGGATTTGTTGCCTAACATGAATTAGTTCATTTAAACCTCATAAAAGTCATACAAGGTATATATTCTAATACCCCTATTTAAATAATTAGGAAACTGAGGCAAAAGGAGTTTAAATAAGTTGCCTAATTATTAAGTCTCCTCACTTCCTAAGTAGTCTATAGCCTAGGAAAGATAAAAATAGACTGTGGATCTCAACAGTTCACTCAGAGAGCATAGTCTTCATCGTGGGGCAGATGTGGGGCACTGCTGTGCTTAGCCATTTTCTCCTCCCCAGTCCTTGGTCAGCATCTCTAATTGACAATGACACTCCATCTTTCTTTCTTTCTTTTTTTAACCTCTGAATTTTTATTGGCGTCCTGCTCCCTAAAGGGTCCCCTGCTTCTGCTGGCTTAATGTCTCAGAACTTTGGTGTGGTTGGTCTCAGACACAACTTTGCCATCCACTATCCAGCGGCTGTTGGTCTTTTGGATGGTTTGCATGGAGGTGCTGCTGTCCAGGGCATTAAGAAGATTGAAGTTCTTGCCATCTTCCAGCAGGTTGTTGTAGGTGGCTATCTCAGCCTCCAGCTTGACCTTAATGTTCAGCAGGGCCTCATACTCCTGGGCCTGGTGCTGTCCCTCTGCCCGGGTCTGTGCCAGCTCTGACTCCAGGTGCAGCAGGATCCCATTGAGCTGTTCCATCTGCAGGGCATAGCGGGCCTCCACCTCCCTCAGGCTGTTCTCCAAGCTGGCCTTCAGATTTCTCATGGAGTCCAGGTCGATCTCCAAAGACTGGACTGTACGTCTCAGCTTTGTGAGTGTCATCTCTGCAGCTCCAACCTCGGTGGACTGCGTGGTGACCACTGTGCTGCTCTCCTCAATCTGCTGAGACCAGTACTTGTCCAGCTCCTCTCTGTTCTTCCGAGACAGCTCGTTATATTGGGCCTGGATGTCTGCCATGATCTTGGAATGGTCCTGAGATTTGGGGGCATCTACCTCCACAGTCAACCCAGAGCTGGCAATCTGGACTTGTAGGCCTTTTAATTCCTCTTAGTGGTTCTTCTTCATGAGCAGCAGCTCCTCCTTTAGAGCCTCGATCTCTGTCTCCAGCTGCAGCCAAGTGACATTGGTGTCATCAGTGACTTTGCGGAGCCCATGGATATCGCTCTCCACAGACTGGCACATGGTCAGCTCTGTCTCATACTTGACTCTGAAGTCATCAGCAGCAAGACAGGCATTGTCTGTCTGCAGAACGATGCGGGCATTGTCCACAGTATTTGCGAGGTTCTGAGCCCTTAGGTCCTGGATAGTCTTGAAGTAATGGCTCCAGTGTCTGATCTGGGGTCCCTTCTTCTCCAGGTGCTTCCGGATTTTGCTCTCCAGCTTCCAGTTCTCGGTCTCCAGGCTCCTCATTCTGTCCAGGTAGGAGGCCAGGCGGTTGTTTAGGCTTTGCATGGTCTCCTTGTTCTGGATGCTTCCCATTCCTGCCAGACCCCCGGCCATCCCGGCAGCCAGGGCCCCAGACCCCAAGCCGCCCCGGAAGCTGGTGGAGCAGGACACGGAGTTCCCGGAACCAGAACCCCCGGCGCCTGCATAGACGCTGGCTGTGCTGCTGACTGGCCGGGCGTGTAGCTGGGCACCTGGACAGAGCCCAGGGAACGGTAGTAGGTGGAAAAGGTGGAGCGAGTGGTGAAGCTCATGCTGTCCGGGGAAGAGAACGAGGGGACAGGACTCAGGCTTTGCCGACGACCGACATTCCCTTTTTCTAAGTCCAGATACAGAGCTCCAAGAACCCACTAGCATGTAATCAAATGGAGCACACAGGGAGCAAGTTATTTGCGGCTGGATACTAAAGCATCAGGGTGAAGGAAAGGCTGCTTGCTGCTATCATTGCTATTTAACATTGCTCTCTAAATAGAGGCTAAATAAATTATAAGCAGCACTGCCGGCTCCTGTTTGTATGGGCTCTAGACTGCTGACTGGGTCCCAACTCTGCATTCAGTGACGTCATGTTGCAGCTTCACATTGGTCGTGTTAGAGGTAATTATACTGGCAAACAGGCAAATGTTACAGTTAAAACCTTTTTTCTTTTTCTTGCTTCTCTTTTCTCTTAATTTTTGAGAATCAGTTGTTAGACATTTACTAGCATGACACTGATTTATAAGCTAGTAATAAAGCTAACTATTGAAAAGGGGAGATCAAATGATCATCACTTAGAGAACATATGAGTTCATACACTAAAAACCTTAGAGGGGAAACAGTTCTCTCAGAGGTAACAACATTTCTGTACAATATTGTTACAGACTGCTGATTCATTCCTTCTAGACAGACAACATTCCTTCAGCATTGGATGAGTTTGCAGGTTGCAAATCTTGGTGCAGACAGCATCTGTGATTTCCATCATGTGGAGAAGGCTCATATCAAGGGAGAAAAAGAAGTCAGCATTTTGTGAGAGGCTGTGGTGGTGGGAGACTAACTGTGACATTTCACATCCCAGGTTCTAAAAGGTCTGGGGCCCAACAGCGTCCTGGCTTCCTTTGTTCTTTGGCTCTGCCCTGAAACACTGTAGTGTCCCTTCCTCTAAACTCCACTTTTTGTTTAAGCCAGTCCAATAAGAGGTTTCTTTCATTCCAGTCAAAATCAGCTTAATTAACAAAGTCATCTATTTATTCTTACTGAATCTATAAAGGAAAAGCCTCTAACTTCCTCCCTTGCCCCGATACTCTCCTTGCAGAAACATTAATGCTTTGCACAAGGATCAATAGGACTCTTCTTGTAACAACCTCAATACAAACTAGGTATTTTCTTAAGTTTTCTGGAATGATGTATTTAAATGTTATATAAATTGACATTGATTTGTGGTGATAAATGTAATTAATGAAGTTGGGGGACAACACTCTGATGTTAAACTAAGGGATCTGATTTTAAAAATACTGATCTCTAAAAAGACAGATATCTCATTAAAAACAGGCAAAAGATTTGAATAGACGTTTCTCAAAAGAAGACATACAAGGCCAGGAATGGTGGTTTATGCCTGTAATTCCAGCACTTTGGGAAGCTGAGGCAGAAGGACTGCTTAAGCCCAGGAGTTCAAGACCAGCCTGGGCAACATAGAGAGACTGTGTCTCTACCAAAAATTAAACAAAAAAATTAGCTGGGCGTGGTGGTGAACACCTGTAGTCCCAGATACTCGGGAGGCTGAGGCAGGAAGATTGCTTGAGCCTTGGAAGTCGAGGCTGCAGTGGGCCATGATGGTACTACTGTAATCCAGCCTGAGCAACAGAGCGAGACCCTGTCTCAAAATAAAATAAATAAATAAATAAAAAATAAAAAAAGACATACAAACGGCCAAGAGGTATATGAAAAAATACTCAGCGTCACTAATCATCAGGGAAATGCAAATTAAACTACAATGAGATATTGTCTCACCCCAGTTAGAATGCCTATGATTAAAAAGACAAAAAATAACATGCAAGCAATATGCAGAGAAACGAGAACCCTTATACTCTTATACACTGTTGGTACAAATGTAAATTAGTACAACCATTATGAAAAACAGTATGAAGATTTCTCAAAAATCTAAACATAGAACTACCATAAGATCCAGCAACGTCATTACTAAGTATCTATCCAAAGAAAGGGAAATCAGTATATCAAAGGGATAGCTGCACTTGCATGACTACTGTAGACCTATTCAAAATAGTAAAAATACAAAATTAACCTAAACGTCCATCGATGAATGAATGGATAAAGAAAATATGAAAATGTGGTATACGTACACAATGAAATATTGTTAGACCATAAAAAGAATGAAATCATGTGATTTGTAGCAACATGGATGCAAATGAAGGTTGTTATGTTAACGAAAATAAGCCAGACATAGAAAGACAAAGACTGCACGTTCTTACTCATATGAGGGAGCTAAAAAACTTGATCTTATGGACACAGAGAATAGAGTAATAGATATGAGAGACTGGGAAGGGTAGGTGGAGGGGAGGGGGAAATGAAGAGAGGTTGGTTATGGTGTAAATATACATTTAGATAGAATAAGTTCTAATGTTTGATAGCAGACGAGGGTGACTATACTTGGCGGCAATATTAAATATATTTCAACATAATTAGAAGAGAGTACTTGAAATGATGCCAATACATGCAATTGATAAACGCTCAAGTGATGGATACCCCGAATACCCTGGCTTGATCATTACACATTTTAAGCATGTAACAGACATATGTGCCCCATAAATCTGTGAAATATTATGTATTAATAAAAGAAGAAATGACTGATCTCTGTAGTGATGATAAATAACTGACTACTAGTCATGTCTTCATCATCAGCACTGTGCTGAAAATTTTGAGATTCCTTCTTTCTAGACCTGATTTTCTTATTGGCAATCAAACCCTCCCCTCCTCGTGGAGCCTCCCCCCATTCCCCACTCAAGGTGTACATTGGTGACATTCAAAGAATTTCCACCTCAGTCTGCTTCTTGATACTGTATCTAAATATATCTGCAGGTGTGAACAAAGCCTTCTGGTTAAAGTTCATAGGCCCAGAAAACATGTTACCATCTCTTGGAATGATGAGAAAGAAGTACCAAAGAGACCGAACTTGTAACAATTTTGAGAATGGGCAGCTGGAAAACTGTATGTTTTATATGGATTTCTGAAATTTAGAAAAAGCATCTGGGCTCTTTTTAGCAAATAATAGAACCGCGTGCAGGGAGGTGAATCTGCCTCCATTTGTGGTCCACATTTGTGGTGTCCTTGCCCACAGCCATGTGCAGAGGGGTGAAGCTGTTCTTGCCCCTTGGTGCACACTTGAGCAGGTGGTAGATGGTCTGGTGCTTCAGGTGCTCCTGGCTAGGGGTGCACTCCACTTCCTCCAACAGATACAGAAGGTAGAGGATGATGTCCAGCGCCTTGGTGAACTGGGCCGCGTCTTCAGGCTCCTTGGGCAGCGGCAGCTCCTTGGGTCCTGGAAACGTTCCATTTGCCAGACCCCTTTCGTGAGAACCCCTATGAGGTCTGCAAAGCCAATTTGTATGCCCAAGCTGCTTTTGGCCGCCCGGTCCTGCAGCACGTAAGGAAAGAGTTCCGCGAAGGAGAGGAAGCTGCTGGCGGTCATGGGGCTCAGAGGCTGGCTGACCTGCTGCATGGCCAGGTCCCACTTCCGCAAGTGGATGCAGCGCTGGAAATTGCCGCAGGCCGCCTACACCGCGCCCCAGTAACGGATGTAACAGGAAGTGTCGGAGTGAGAGGCGCAGAGGATTCGCTAACAGATCAACAGGGTCTGTATGCGCATCTCATCTGGGTGGTTTATCAGAGCTTCCAAGTCTTCGGTGGTGTGGATCTCCCTGGAATAGCCATAGGCCAAGACCAGCCTCTGGGGTTCTGGTTTGGGCAGGTGACTCCATGGCTCGTCTCCAGTGTTTAAGGATCCCAAGCAGATCTCGCTTCTTTTCCACATACGTGGCTCCCAGAAATTCCAAGGCTTCCAAGGCAGCTTCCAAGGCAGCTTCCAAGGCAACTTCCGGGCTGGTGGGACAGCAGCTTTCATAGGATTCCCCGTTCAGTGGTTCCTCCGCGGAGGAGCTGCAGCATGGAGTCCCTGAGGCTGCGTGCACCCCTGGCTGGTGGAGGGCCTTCTTGAGGTAGCCCTGGCTGAGCCTCTCTCCCGGCGTCCTGCTCCTGGCTGGGCTGCTCCTGGATGAGGTACTCCACTATGCTAGTGTGGCCCGTCACGCTGGCAGCAGCAGCGGAGTCCTGCGAAGGCAATCCCATGCGGGTCTGCCACCACAGCAGCAGCTGCAGGCTCTCCAGGCTGCCAGACTCGGCTCAGTAGTGTAGGGCCGTGTTGCCACTGGCGCTGCGCCGGTTCACCTGGGCGCCCTGCTTCAGCAGGTAGCGGGCGATCTCTCGGTGGCCCTTGTAGCACAAGATCATGAGGCACATGTGGCCGTGCCGGTTGGCCACCTCCGGGTAGGTCTGGTTCTCGCCAGTGGCCATGGAAGCAGGCGGCGCTCAGGGGCGTGGAGTTGGTGCTCCTGGTGCGGTTCGCCGAGGCCCTGTGAGGCAGCAGGCTCCGCATCACGTCCAGGTGGCCGGCGGCAGAGGCGGCCCACAGCGGCGGCGAGCCCTCGATGGTCCCGCCACCGAAGGGTCCCTAGCCGTCAGCCTCCACCCTCGCGCCGCACCGGTTCACCGGGTATCCTACTGCGTCCAGGTGGCCGGAGCGTGCTGGGGGTGCACTCCACTTTCTCCAACAAGTAGAGCAGGTGGATGAGCAGCGGCGTCCCCCGAGCTGGCCACCTCGCCTGTCAGCTTGTCCAGCTCCTCCGGGCTCCGGCAGGTGAACACCTTCTAGAGCAGCTGCAGCTACCGTTGCGGGCGGCGTCGTACACCGCGGTGCGGAGGTACATAGTCTGGGCGCCGCGGGACACGGAGACAGCGGATTAGAGCCGGGATGGGCTGGCGGGCGGCAGCCTTCACCGTCTCCCCCGCCGCCACCTGAGGGGTTCCCGTATCATTTCGTCTATACATATTTACTGTATATATCTCTTAGAGAACCAAATCCTTTAAAAATAATCAAAATATTATCACATCTAAAAATATAGTTTTTAAAAAATATCAAGCGTCCATTGTTCACATTTCCTAAATTGTCTTACACATTGTTTATCCAGTGTGTACGTTTGAACTGAAATCCGAGTAAGATACAAACATTGCTGTTGGCTGATGTAGTTATACATTTTCCCCTTCACTTCTTTCCCTTGAGAGTCTTTGGCTGAAGAAGCTGGGTTGAAGAGATCTCAGTGTCAGGATTTTGCTGAGTGTGTCAGTTATAAAGATTACTGATAAAAAGACTTCAATGTCCGGTGGATTTCAGTGGGTTCCTTCTTATCGAGCTTTGCTTTTGAGGATGTGAGGTGAGGAAGAAACCCCCTTTACAGGGACCTTCTCTCTTTGGCCAGAACTGGCCTCCCTTGTGGAAGGAGGGGAAAAAGTGATTTCAAATGCTTTTGAGTATTAATCCCAATGTCCAGTTACAAAATCTGTAACTTATCTGGGAATTACCTTTAAGTGCATCATACTTATATAAGTAAAGTATATAAAAGAAACATAAAAAAATTGGAGGTAAATCATGTTCATGGATGGGATAATTTAATATTTTAAATATTTAAGGCAGTTGAATTAAAATCCCAGTAAACTTTTTTTTTTTTTGCGTTTGCATCTTCACTAGCTGATTTCCAGATGAACATAGATGAATGAATGTGTATAAATAGCTAAGCTAATTTAGAAAATGAGGAGTAGTAAGGGGGCAAAAAATTATCTGAGTTTAATTTATTATTCAAAGAAATAGAAATGAAAAAAATACACATAAATACACTTAGAATTTGATCTTTGGAAAATGAATGAGTTACTTAATAAATAGTGTTGGGAGACTTGGACAGAATATAAAGTATGGAATAGGAGGAAAAATTAAGTTAGAGAAGCAGGTAGATTTAAAAAATTAAATTTGAAAGCTAAAACTGTAAAGCTAATAGAAGAAAATTCAGAAATTTTTCTTTGTGATTGGGCATGTAGATAGATTCTAAAATAAATCCATCAGATAGAGTGACCTTGGACCATAAATAAATAATAAATCCTTCAAGTATAAACTATAAAGAGAAAAATTAATATATTTCATTACATCAGAATGAACTGTTACCTGGCTACCCTAACTTCTAGAGTCTGGAAAGGTGGCATTTTAGCTTTCTAGTCAGTACTTAATAAAGGACAATCAAAAACACCACAAACAAAATTTAGGAATGGGGTTTCATTTGGAGAAAATGAAAACAAAACTTAGGATAAGTGACAGTTTGAGAGAAGATCTATAATATATTTATCACCAAGAAATAATTAATATTTAGAATAATAAAATAAATTTTTGTAAATAAGCAAGAAAAAAACAACATAAAAAGTCAAAGATTATGATTAAGACATACCCTAATGGCTGACAAATGACATGCAAAAATGAGTTGTTTAACTTCATTTTAATCAACAAAATATAACTTAAAACTCTGAGATACTGCTTACTGAAGTGCAAAAAATTAGAACATTGCATATCAAATGCTGGTGGGACTATGGAGAGATGGGAAACCTCGTGTACTGCTGGGAGATATGGACTGGTATGGTCACCTTAGAAAGCTATAAAGCAGTACTTAGTGGAATTGATTCATTACTCTGTAGACCCTAAACACTATAGAAATTCTCACAAGCATGCACCAGAGATATTTAAGAGGATGTTTATCTCAGCATTATTTGTGCTAGCAAAGAACCAGGGGATACTTAGGCTAAATTTAGATTATACAGCAGTCACAAGAAATGAACAAAGTAGATATTTAGCCACATGAACAGATCTCGAAAACATAATTTTTGTAGTCTAGCACTATTTATGTAAATTACATGTACACAAATATTAATGTTCATATTTTAAAGACATTCACAGATATAGAAATATATATATTGGAGGTTGAAGGTACAAATAAAAATATTGGAGGTTGAAGGTACAAATATGAAATACTTTAGGTTGGGAGCCTGTGGAGGGGAAGAGAAATTGGATTGTATAAGATGGAGATAAAAATAAGATAAGAAACAAAGATAATGTGTCATGAATTGATGGCATGATTAATCCCATTAATCCCATTCTACCCATCTGACATGCCTACAATAAACAAGCTTATAAATCCACCAGCTTCTCTTGAGAAATAGGAAGATTTGACCACGTAAGATCTGGTATGGTGGAAGCCAGGAGGTGAGACAGATGTGGAGCAAGGCTTTGCAGCTCCCCTCCCCGTTGTCTATCACCAGTCAATGGAAGACAAGTTTATTGGTCTCTGGTTTCTGTAAGCATTTGTACTAAGGCCTCTGCTCTACAGAGGTGTGAAAACTTTATTCCAGAGGGGGTTTCAGGAGTAGGTGACCTCATGGGCATGGACCAGTTTCATAAGCCTAATGGAGTGAATTCATTTATCCTAAAAGCTGTTGCTATGCTGTTAAGTTGCCTGGGCTGAGAACCCCAAAGACAGAGCCATTCAGAAATTTTATAGGCACTGAAGTCAATATTCACCCTAGGCAGGACTCCCCCTGAAGATCCAAATAGATTAAGGGAAATAATTCTAAATGAAGTCCATAAGGAAACTTTTATAAGAGTGTAATATCTTCTTCCATCATGAATAATTCAGTTAAGAGACCTATGAAGAGCACACCTCTTTTCCCCTTTGACCGTTCTGCTATTGGAAATGGTCGAACTTTCAGTCCCTGATTAAAGTTTTCAATTTACCCCACTGAAAATGTGCCAATTAATTCTGACGCCTGTAGGCCCATGTCAGAAAGTAGCAGCTTTTCCAGTCACGACCTTGTTTGGTTAAAATGCTAAGAATGTTCTATTTTAGAATAGCTAATAACTTGAGACCACCTTCCAAAATAGACTCTTTGGGATGAAGTAAGAGAAATAATCTCAAAACAGCTTAAAAAAGATATTTTCTTTTTGAAAGAAAAGGGTTTGTCTGTAAGCCATAGGTGAAATAAGGTTAGTTACTACATTCATCACTGATGTATAACAGGTGGAAAAAGATTAAGAGAGCTTCAATAAAAGTGCTTACTTAGGGCAAAGGAAAGTCAAAGCAAACACAGGACCCCTCCATACATTGGTCATCTGTAGAGAATGTGTATTACTTTTCATAGGGCAGTATTAGCAAGAACAGTGAATCTAATGGACTTCACCTTATTGAATATCTTCTTTGTTAACAGAGACTAACAGCCAAGGCCCATTTTGCCAGAGTGTGTTAATATATTTTTTTTTAATGCTGTGCTTGATAATGTAAAAAAAAATAAATAAAAAATAAGTCTGCATTTAGCTATGTGTAGCTGTGGTCATATTATGGACTTGTGCCATGTTAGGGGAACCATTTTCTGAATTTCAACCCACTTTGCTGCCACCCAGGAGAGCAGTGACGTCAATATGCACTGGAGGTTAACATGCTTTGCAATAAACACTCACCATCATGACCCAATCCTGGTGAGCACCAGTTACTCCACATTGATAGCTGAAGGACTGAATTTGAAAGTCTGCTCTTACGTTACTAAAAACACATGGCTTCTAATATGAGGCAGTTTATTGCCAGTGGTGGTGTAGAATGATATAAAATGCAGACAAGCACCCAGATTTCAGGACTATGTATCATCATTCCCCGAAATGAACCAGTTCTCCCTTGAGGGGAGCGACTGCTTAACTTGGGCAGGAAGAGCAAGATAGATCTGGAACATCTTAGCTGAATGGGAGTGATGATGATACTTTCAGAAATTTCTGGGGTAGTGTTAAGAGGTGAAAAGAGGTCAGCCTTATAAAAATGAATAAGTGGCGACAAATGAAAGTCAACTATTACCACAATGTGAAACAGGTTGAGTTTAAACAGGAGCCTTGGTTTTATATATATATATCTCACACAAAATACAACAACAAAAACAACAGGTGTCTTGGCATGTGCTAAGAGGCTATGGAAAGACAATTGTATTAAACACAAGCATGCATTTTCAGCTGAAGAAAATATAATATATGGAATGAGGATATTGTGAGGATTATACTAAAATTGCTATTGGGAAAACGTTTTTGTTCATTTACTTAATAATGAATATCAGTAATCTCAGATGTCCAACTTTGGATTTGCCCCTTCCCACTCTCCTTATGAAAGTTTGCATGGGGTAACAGGTAACTCTGATCTGATGTTAAAGCCTCCACTGTTGGGTTGGCCATAACCTGACAGTTAACAGCTTCCCCTACTGATTCTTCATTGACAAGGAAGCCTGCTTGGAGTTAACAAGCTCATGGGAACAACTACCCTCCTCTGATATAGTAGCAAAGAGACAAGCGCTACTATAAAAAGGGCCAAGCTTCTTTGGTCAAACAGGGTTTTGCATAGCATGTCATAGCTATTCTGTCTGGTTACTATCCTGAGGTGCATCTCTTCCCCTCCATCTTTTCTCCAAGAAGCTTGGTTGTAGTGGGGAGTGTGTGTGTGCATGTGTGTGTATGTGTGTGTGTGTGTGTGTGCAGAAAGCACAGACCATAGTGCATATGGTGCCAGCCACATTCATCCTAAGGTTGAGAATTCCAGATGAAGAAATTATTCTGCCACTGGACTAATGGTAGATAGTTGTTGCTACTTCCATTTTTGTCCACTAGACCCACTAAATATGACTTTTCTGGCTATTATTTTTCTTGAAATCTAATGTTGAGGACTTAATATAGTGGAGCATTTGAATAGATTGACTTTAATATTACTATTTAGGAGTCATCTTCAATAATTTGGAAAGAAATAGTGCACCCTCTAGTGAACATTTTAAGGACTAGCATAGACCACTGTGCAAAACAGGTTGCATTTGGGTCAGTTAATGGGGAGTAACGTTACACATCCTTGGCACCCTTTAGTCTGTAGCTTACTGGTTGCCGTCTTTGTGGTAACATGAGGAGTATGAAGGACTAACCACAGGACCAGAAGACAACAATGGTTGGAAGAGGGGAGTGTGTATGTAGAATGTAGTAGAGTCCTTGCTGCTTCACTCTACTGCCCTTTGCAGAGTGTAGGAAGAATAGGGCAAAGTTTTGCAGGGAATTTGGAGAGACACTCTCACAGAAAAGAAAATCGGAGCATCTGGGTATCATGACATGGAAATATAAAAACGTGAAAAAAACCTGTGATCGTGAAATTAGAAAAATTATTTTAATTCTTATTAGACTAAAGTCACTTGGCATACAGAGAATTGGCTAAGTTGTGAAAAGCAGGAAGAAATTTTGCTCTTGAAATCCTATGATTTTGTCTTCACCGACCCCAGTCAATTAACTTTGGGAAGACTGTGGAATGGCAATATTTCCATGGAATGAGATAGAAAGTGTGATGGATAAAAGTGGCAGTATGGTTACCTAATATCCTAAAAGCCATTACTAGCAGATATTATTCTTTTCTATTTTTTAATTTTTTGAAGTAATGTTTCTTTTGACAATGTCCAAGTATCAATTTTTTTAAAATTCAGACAGATGTAATATATATGAACTAGGTTAAAAGTGTGCTCCGAAGGTAATAAAAATAGATCAATTGTTAGAAATAATAAACCCCATATATATAATTTGAATTGTTTGATTTGCAATGTATGTTTATTTATATTTTGAAACTAGTAAGGGCCTTTTTACTTTGTTCTTGTGTGACATTTCTGATGGGCTTGCCAGCAATTTGTTATTTTTGAAATCATGGTTACTTGCTCCAAACCTCCAAACAAGAATCTTTGTGAATTTGATTTATTAGAAAAGTTTTTGACTATATATACTTTGCAATTTATTTGGTTTTCTCTTAAAGCAAAATGTAAGATTAAACAGAACTCTATGCTATAAGGTTAAACATATAATTATATAGTATTTTTAAACAATCAAGTACTTTATATAAATTAGATGTAATAACTTTTAAAGAAATGTTATCCTGAAAGTGATTTTCTGTGACTTTGCCAGGAATTCACTGGGAAAGGGCACTAAAGAGGAAGTGTGCTCAGAAATCGAGATAGCCAGAGATTCTTTTTAATCAAAGGTACGTAGAAGCTCACCAGTTGCCCCAGAGACAGAAGTGAAAATCTTGCTAGACCACAGTAAAAGTTGGCTCAAATCTTCTCTAGGGTGAGAGGGAGAAACACACACAGGGGGATACCTAGTAGCGTTGGTAAAGTTCCAAATGGAATTAAATAAACTGGCCCTTTGAAATCAGAATCACAAATTAAATTATGCATTTTGGTTTTGTTTGGACATTTCCATACTGACTGATTGCTTTTCTTTTAAAGGACTCTTTTTTGGTGGAGGGGGTGAATTTAAACTGAGAAATTGTATATACTTGCTGGCAAGCTGCAGCTTCACTAACCATGTAACGCTAAATTTTGTGGGATGGAGGCATGGAGGTATACAGCCCAGTGACTCCCAGACTTAGTGAGCTTAAATGTTATGTGGAAAGACTGTCACAGATGTGTAGGCATCAAGCCCAGGGGTTCGGATTCAGTAGTTCTGAGAGGGGGATGAGAAGGCATCATTTTAAACAAGAACCCCAACCCCAGGTGACTTGGAAGCAACTGGTCTAGGGATTATCACTGAGAGAAACACCAGCTGACCTGAGGTCAATAATGTGGAGGTGTGCAACCATTTATAAATGAATTTATTGAGAAAAGTTCAGTGATAGTTATTTCTGAGAAGTCTGCACGTGTTTTGGAAAAATTGGGAGGTGGGCCAATGATGACTGAAATATAATTGCACTGGTATACAAATCTGAATGCATTACAAAATGCAGGCTCTTCAGGGCATGTGCTAGAGCCAGGGCAGAACTCCTCAGCCCCACTCTGCATTCTTGCAGCAGGGCTTCCATTCCTGCTCCTTCCTCTGCTGGGGATGCTCTTCTTCTTGTCCTCCTGACTTTCTCTAATCAGTCAGACTCTGCTATCTTGTCACCTCTCAGGAGCCTTCTATGAAACCATCAATAAAACTCCTTTCCCAGCCACTACCCTTCCCTTTTCCTACTTCATCTTTCTTTATAGCACTTGCAATTTGCTGAAATAATATTGTTGATCTGTTTACTTTTTTAGTGTTTCTTCTTTGAGACTAAACTCCAGGAGGTCAGGGATTTTGTTTGTTTCATGCGTAGCTGTATATCCAGCACCTAGAATTAAGTAGTGAAAGAAATCCAATTCCTTTTCCAATCAAAATTTAACTGGTTTTGTGGCCTATTTTCCAGGGGTTTGTGCTCTAATATGGGAGAATACACTGACTCCCTGAACAAGTCCATTCTTGAACCATGGGGAGTTCAGTGTTATGCCCATTTTCCCCAATGATTGAGAAACTTACTTTGATATTCCCTTTTACTCTTGATAGCTATCACTTTTTGAAAACTTGAGCTTGGTAATAGACAATGTATTTCTCACTGTCTTTAATACAATAGGTTAAAGATTAATGAATAAATATGGCATATCTTGAAATGAGATGTGTGTATTTAGCATTCATCTGAGTGTCACCACACAATGGTAGACGATGGATGGGATTAAGAGAGAATATTTGTCAGTGCTCATTCAGGAAAACAGCTCATGCCAACTAGTTCAATAGAAGGCATCCAATATGGGAAACTACAGCAGTGATGCAAGATCCAAAATGGCAGGAAGGGAAAAAAGAGGCATTCCCATTATTATCCACAGCAGGAATTTCCTACCAGCTTTAGAATGGAGGAAAGGGGGAAAAGGGAGGTAGTACGGCCAGAGTCTAGAGGGGCTGGGAGCACAGAAGGAGAGGCTGTCCAGAGGAATCTGGAAGTCCTGGAGGATGTCCAGCCACTTCTGAGGATGCCTCCAAAACAGAGAGGTAGGTGAAGAAATGCCCTGGCCTCTTCTTTTTTCACCCTCAAATATTCTGCCAGTGTTCCCACTGCCTGAACCCAATTACAAGGCAGTAGGAAATGGAATTTGCAGGGATCAGCCCAGGCCACTACAGAAGAGATTAGAGAAAGGGCTGGAATGGGTCCGAGAGCACACAAGGACAGAAGGAATTTGGAGAAGTGTAAATGATATAATCATCTTGGTTCAGGTTTGTGCTGCATATGAATTATTCTAACTGCGTGGTGTGAAGCTCACCATGTGATATAAAATTTCCTAAGATCCTGCCACAAAGCTGTCTTATTTGCATGAGTCCAAAAACTGCAGGCTAGAAAGGTGACTGAAAGTTACAAAATGGTTACATAAATGATCAGCAATCCACATGGGCTTGTTTTGGATTTAATACCATTATTTTTTATTTTATTATTTTAGTGCTACTGTTATACTGCATCAAACCTTGTTTTCCTGTGGGGTCTTTGGCTCCCTTAATGACAACTCAAGTCATTTCTGTAATCTTTCAAACACTTTTAGTTATTAAGAGAGGTGAATTTCAAATATTAGACCTAACCTTGTGCATCCTCTGTTCCTCTTCCCATGAATACAGGTGGACTTAAAGCTTTACCAGCTGGGAACTGTGGACATTGGTATAGTTATTCTCTCACTCACCTTCTTTCCTGCACTTGCCCTCCTGGTGTTGAGAGGAGAAGGAAAATGAGGGAGGGAGGTTTCACACATACCTGCAGGTTTTTTCCTCCTATTGTTCATCAATGAGTCCAGATGGGACTGTCGGTTTCCTCAGAGCAGCAGGCTGTCCTGGGTGGTGGGTTGTATGTTTGGCTCCTTGGAGAGGCAGTCCCTTCAGAGGCCCTGGTAAAGGACCAGCAATTGAACTTGTGTTTTTCTCACCTGTAGCCCCTACAACAAGTTATCCAGATTATCTTGTTGCTGCTAGGGTTGCCTCACCCGGAAGTGGCTCTCTTGAAGGGGCCAGTACAATGAGTGGCTGAATCCCTACCACCTGCTACAGGGTTTGCTCGAACATCTGTAGGAAATCCACAGATGTTTACACATCAAATGGTAACGCAGTCCAACTAGGTTCTCTCTCTGCACCAAGGCCACTCTTCTGCCCATTTCTTTATGCTTCCACCATCAGACTTGGGGAAACAGGCACTGTGTGAGAACAGAGGTTCAGCATTTTTACACGAAAGATAATTGAAAATCTTGAGCCCAGTGGCTTAGGTATCTCCAGTATCACACGGCTGGCACAGGGGGATTGATAGAATGGCCCTATCCTGAAAGATAGAAGAGGAGGAATGGATGGTTTGCTACTCCACAAATTATGCATCTCTATTCTCCCGACCTGTGGCAAACTTGCATCCCTTCTCTAGTCCTCTGGTAGTTTTATATTAATACAGATTCTGCTGAAATGGTCCTTCTGTGTCCAGAGTTGGTTCCTTCCGGTGGGCTCATGGTCTCACTGACTTCAAGAATGAAGCCGCAGACCTTTGTGGTGAGTGTTACAGCTCTTAAAGGTGGCACGGACTCAAAGAATGAGCAGCAGCAAGATTTTCTGTGAAGAGCAAAAGAACAAAGCTTCCACAGCGTGGAAGGGGACCCGAGTGGGTTGCCTCTGCTGGCTGGGGTGGCTAGCTTTTATTCCCTTATTTGTCCCCACCCATGTCCTGCTGATTGGTCCATTTTACAGAGCGCTGATTGGTCCATTTTACAAACCTCTAGCTAGCTACAGAGCACTGATTGGAGCATTTTTACAGAGTACTGGTTGGTACATTTTACAAACCTCTAGCTAGCTACAGAATGTTGATTGGTGTGTTTTACAAACCTCTTGTAAGAATTGTACCTCTTAAAAGAATTCTTTAACTTATTAACTTATTCATTTTAACTATCCAGCACTTAACAATTGCTAGGGATTTAGCTGGTCATTGAGGATAAAATGAACAATGTACGGTTGCTGCCTTGAGAAGCCTCCAGATGGATAAATGGATAAATAACAGGAACTAATTGTGGAGCATTTATTCAAGGCCAGATGGTTTGTCAACTTAGTTTAACTTCTCATAGTTCTGTTGCAAAGCGAGAATTATTATCACTAGTACACCAATGAGGAAATGGTTATAAAAGTGATATAACTCATAGAGTTTAGATAACTTAACCAGGACTGCTCGGGCGTTGGGAATCATGACCAAGTGTTGGTCCTGGAACCATCAGTGCACCTTATTTCCTCAGGGGTCCTCACTTTCCTCAGAGTCAAATGTCTCTTTGCTTTCAGAAAATTCCAGAAACTGTAGTGATGATCAGGGTTTGTGACTTAGTTTTATTTATTTTGGGAGCAGGTTCAGGCATGTGTATAGACTGGAGGCGGTCAATGGTATGAAGACGTTGACAGAAAATGACCAACGGTGAAATTGTTCAGCTCCTGTGGACAAGACTAGCTAACTCATAGCTAAAACTCCCAGATGTGAAAAATTTAAGGCCAGGGTTAAATTTCTCAAATTTGAAAATCTTATAAACTTAAGAAAATTTGATTTTGTAAACTCATATCAGAAAATGGCGTTCAATTCTTAGTTGTAAATTAACTCAATTTGAATTGAAGAATAAAGCAGAGTTAAAAAATAAAATAACTTATCCTTCCAAAGCAATTAGCCTCTCAACCCTGCAGATATAAGGAAAACAGATAAAAGTACTTTAAACATTTGATTCACCTGAATTAGCAATTTAATTGAGGATAATGGCTTTTTTGTGGAGCCACAAAGGCAACTTTTTTTTTTTTGAGAAGGAGTCTCGCTCTGGAGTGCAGTGGCGAGATCTCGGCTCACTGCAAGCTCCGCCTCCCGGGTTCACGCCCTTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCGCCCGCAGCCACGCCCGGCTAATTTTTTTGTATTTTTAGTAGAGATGGGGTTTCACCGTGTTAGCCAGGATGGTCTCGATCTGCTGACCTCGTGATCCGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCAGGAGCCACTGCGCCCGGCCACAAAGGCAACTCTTTACTCAAATACACACATAAACACACACACTAGCTTCTTATTGATAGAGACGATGTTATCTAACACAGCAAGGTGTCATAATATTCTGCTAAGAATATAGACACTGTCCATGTAGCACAGTATTTTTAGTTGTTTAAATTGAGTCTAATACACATTCAGCGAAGAGTACAAATTACGTGTTTTTTTTTTTTTTTCCAAAATGAGCACACCCATGTAAACAGCCAGATCAAAAAACAATCAAGAGCTTGAAGTAAATGAAATCAGTATTTGCTCTTTTGTGTCTGGCTTCCTTCACTTGGGATTATGTTTATGAGGTTTATGTTTATTGTTGTATATAGTTGTATATACTCTTTCTGAATAGTATCAATGGGGAGTAGAACTACATAGTATTCTATTATCTGAATGTACCACAATTTATGTTTCATTCTTGATGGACATTTGGGTATATTCCAGTTTTTGGCTACTATAAAAAGTGCTCCTATGAACATTCATTTTGTATCTTTTGGTGAACATATGTATACACATCTTTTGTGTATAGAGGGTCATAAGACAGGCATATGTTCAGCATTAGTAAATACTACCAGATAGTTTTTCCAGTATGTTTGCATCAATTTTCACTCCCACCATCAGTATATGAGAGTTTAGGTTGTTATACATTCTTGCCAACACTGGGTATTTCTTTCTTTGCGTTTTGCTTTTAATTTGCATAGTCATGATGCCTAATCACATTGTGTACCTTAAGTGCTTAAGTCATTTTCTCCATTTTCCAACAAGTTGTCTTTTTCTTATTAGTTTGCAGTTCTTGGTATATTTTGGATGCAAATTCTATATTGGGTAAATATATTGCAAATATATTACATTATGTGGGTCGCCTTTTTATTCTCAATAATGTCTTTTGATGAACAGAGTTTTGTCTTGGTGCAGTCCAATTTATAATCTTTTCTTTATTAGAGCTCTGTTTGGAACTCTTTGTCTGCTATGAAAACATCCTCCAACATTTTCTTCAAAAACTTTTATTGCTTTAATGGTTACAATTATATTTGCAGTCTACTTAGACTGTGTTTTAATGGTTTGAGAATGATATACGTTTTGTTTTCCATATGGATATCCAATGAATTAAACCTGGTAGCACAATTAAAAAATATGTAATATGTTTTAATTTGAATAATGGTACTATTGTTACAAGGAATGGATTGTATCCCAAATTATTCTGTAAGTATTTAAGTAGTTAAATTTATGGAGTCTTTGTATCACATACTATGAATATTTCTTATTAATATGCTTTCACATGATCAGATCCTATCAAATAAATGAAACCTTGGGTGATAAATAGCTTTGGAAATACTTTCTCAAATCCATTATATATATAATGAGTAGATTAGAGATAGTGAATCCAGAAACCTTCAATATTTAAGCATATTGACTCAAATAAATTAACATTCATTATTTGCTATAACACTTTATAGAAATGTGCAGAAAACATTTGAAGCAACTTGAAGAAAGTAGTTTATATATATCATATAAAAAAACCCAGACAATGAAAGTTGGGCAGAGATAGTACTTTTTCTGAGGGATTTAATTAGAAAAGGAAGAGAGGAGACAGTGACAAACAGTGCTAAATAGAAAACATTTGCATGAACCTGTGATTTTGAAAAATTCTTATTCAGTAACAAAAACAACTTTTTCTACTCTGCTGACACTCTATCTACTTCAATATGAAGAGAGTAAAAAGGCAACCTGCAGGATGGAAGAGCATCTGTTGCCAGTACTTGGCTGGAATGAGATCACCTGCAGGTAGCCCCCAGATCACGATTCTTTGCATGGGCTTTTACTAAAAGCAGAGTGGGCTCTCTAGAACAAAGCCATTATTAGCTCTAGAGTCAGGAAAAGCAAGACAGTCCCAGACTATCTCATGGCAGAGAGGCAAAGATGGCTTGGCAGATATCTGGAGTAAAACTGAAATGGTTAAAGGTGCCAACCCCCAGAAGAAGGCTTTGCTCAAATTGTAAGAATTCTCTACTACAGTTTTTAATCAACACCAGAGTTAATTCACTCCTTGGACTCAGAAGGCATTTTGTTCTTTAGAAGGCTTTCTTTCTTTCTCCACTGGCTTTATTGAGGTGTAGTTGAGAAATTAAAAAAAGTATACTCAGAGTGTACAATGTGATGCTTTGATATACCTATACATTGTATAATGATTTCCACAAACTAATCAACACATTCATCACCATGCATACTCCTTTTTTGGGGGTGTATTTGTGGTTAGGACACTTAAGATCTACTCCTTCAGCAAATTTCAAGTAAATAACACAATATTAATCAGTCACCATGGCTAACCATTAGATTTGCAGAACTTATCTATTATACCTGAAAGTTCGTGCCTTTTGACCAACATTTCCCCACATTCCCCCTACAACAACATGGATGAACCTGGAGGACGTTCTGCTAAGTGAAATAAGCCAGACACAGAAAGACTAATACTGTACAATTTCATTTATATGTGGACCCTAAAAAGTCAAGCTCGTAGAGAGTAAAACGGTTGCTGGTGGGGCTTCTGAAGAGGGGGATTCTTCTCTGGTGTGGCAGATCTTGCCTGTTAGCAGAATGGGAATTTAATGTGTAATTCTAGTTTACCATCACATAGGGCATATTGCAAGCTTTATTTTGTTTAATTTTACTTATGTATTTTATTTTATTTCTATACATTCTGTGCCCAGGCTGGAGTGCAGTGGCACAATCACAGCTCACTGCAGCCTCCACACACTGGGCTCAAGTGATCCTCCTGCCTTAGCTTCTCAAGTAACTGGGACGGCAGGCGTGAGCCACTGTGTCCAGCCCTGTTTAATTTTCTAGCAGGAATTAAGCACCACATAGAGATGATTTTTTTGATTATTTAGGAACAAGGCAGAGTCTTTGGTGAATGAAGGGGAAGCACTCTGCAAGATATTAACAGGCCAGTATAGTGTACTTTCCTAAGAACGGAAATTACAAGTGTTTCATTAAGAAATATAAATTGTTGACATAATTTTAATCCACAGCATTATTTAAATTGCCTAGTTCAAGATTATTTTGAGAAAACAATTAACTGTGGCAATTCTAATTAAATTCCCTTGATGTGTATATTGGAAAAATATATAAAGCACAGATTGTAAAATAAAGAACAGCATTGGAAAGTTTCAAAATATATATTTTTAAGAAAAGCTAAAATAAGAGTCAAAATGAATTTGTTTGGATTCAGATTTTGAGTATATTTTGGTTCAGAATTTTCTGCTTGAAGTAAATAGAGACAGTTTAAAACTGATTAACATAATCGAGCCACCAAAATACTTTAAATTCTGTCACTAAACTGGAATTTAATCTGTGTTTCCTGAAGTAAGATAAAGCAATCCAACTTTTGATAATTAGACTGGTACTTCTTGGAGGAGTAAATAAGCCAAGGATAAGTAATTCCCACCTCTGCTCTAAGAGTCTTAGCATGTGGAATACTGAGGGGAGAAGACCAGGCCCTGGTGGACAAGAGAGAGTGGGAGATGGGAACTCTACTGAGTCTTGGTCACCAGGAACAATGCTGCCTTTAATCTACTACCTGAGTTGGCTGTATAATTTCTGGTACCCAATGCAAAATGAAAATTTTGGGCCCCTTAATGAAAAACAGGAAAAAAAGTGCTTTTAAGGTTCTAAAGTATAAAGCTTTGTTTCTGTATTCCATGGGCCCTCTCTCTCATCTTCTCATGGTGGTTTTTGTTATTTAATGTCCTAAATGAAATAAATTATTAGCATAAATTTTTACCATTCATCTTTATAATGTACAATGCCCGTTTTAAATGCAAATACAAAAGTATTTAACTTGGATGCAGAATCACTGAACTCACATAATTTGAATTTTATACATGCATATGTATTTTGTTCTTCCCAGCATAGTGGAAAACCTGCTGAAAATAACCCAAATGTTTTTATTTTACTTCTTGATATGTGTACAATATGGGTTACCCTGTCTTTCTCTTTCTTTTCCTTTCCTTCTGTATCATCACTTTCGGTGTAAGTCCTTGAATAATACAGGAAAGTGATACAAGTAAGAAAGAATATGATAGTTTCTTAGTCATGAATGTTCTAGAACATCATTGCCTCCTTTCTGAGATCTGGGTTGAAGGGAAAATGTGGCTATCAATGTCCCATTTACTCAGTCGTGGATATAACACATTCATCCTGCACTTTGAGTGTTGCTGGACTCCCATGCATTGCTGGTCCACTGGAACTTTACACTCATGGGACTCTTGAATGCTATATGCAAATAGGGCAGCAAGGCATGCCCTAAATGCAGACTGTGTGCAGCTCCTCTGCTCGTGCTTCATTGTGTTTTCAGACTTCACTTACAAAAAAGTTCAAAGATAGTATCATTAAGAATCCAAAGACGGTGACAGCTAGAGCATGAAACCAAGTGCAGGGCTCTTCTGCACATGGCTTCCTGTACAATTGCACTGGTTATAAAGCCATGGAACCAGCCTTGCCTGCAACAGTCAATTTGTTCAGATAGCACCTCGAGATTTACACTATTTGTCTTTAGAGTAGCAGGCCTTCCAGGGCATGAGGCTCAGTCAAAAGGAGGCCCACGAGGAAACATTCACAATGCATTTAGCACTAGCTCCTTCACCTCAGTGGTGAATTCCTACACTACACGATGATCTGCCCTTGTGCCCAGGCCACAGTCCAAACTGTGAGATCAGTTGTCAAAATGTCTGGAAGTGGGTGGGACATGTTAAAGATTCCCAGGGGATTCCAAAGTGTAGATTATGTTAAGAACCACTACTTCACTGCTACTTCTTCTTGTTACTGAAAGTATGACCCCTAGACCAGTAACATCAGCATCAATCACCTGGCAGCTTGCCAGGAACACAGAACCTCAGGCCCCACACCTACCATGTCAGGTCAGAATCTGCATTTTCATCTGCAATTACACTTTGAGAAGCATGGCTGCAGCTGGATGGGCCCTTTGTAACACCTAGAAGTTGACTCCTTAGGCTCTTCTATAAACACTGGTTATTAGCCCTGGTTGTACATTTAAATGATCTGTTTTATTCTAGCACCTAAGTATATACATTCATTACATTTATTTTTATGTTTAATAATTGTTTATCAGAATTGTGCAATTGGATTATTTTAACCAATTGAGTTTTATTAACAACAAATGTCATTAAGATTTATTTTAATGCTTGGAAACATATAATCATAAAATTAAAATATGTTTTAATGTTTTAACCTACATATGAAATTTGGCTACAGAGAAATATAATGTGTGACCAAAAAAACCTATAAATATATTAAAGCATAAATTAGATTTCAGTAGTAAAAAGTATGTGAAGAAGTAGATTGGAAATATGAAATAAAGGAGAAAATGCGCATAAAAATTTTGACTGTTCAAGATGGACATGTTCATGTATTTTTTAAGTGGCTGATGATAGATGTAAAATCCTGATGGTTTTTTCATTCCATTGGATACACTTAAAAGAGTAATATAACAGTTTTATTTTAAGATATTAAAAGGTCAATACTTGAAATAGGCCAACAACTAAATTACTTCTAACTGTTTACATTTATGATGATGAAAACACTAGACAACAATGTCTTTATTTTGGTTTCAATATTTATAATATACCAGGGATTATGTTATTTGCAACAATTTAAATTTCTGATGAAACATATTAAATGCCAGTATGTGAGAGGTACATAATTTTTCAAAATTCTACAGATGTAAAATAATTTGAAGACCACTGAGATACATGGGAGGACCTAAGAATCTCATGGGCATCTTTGAATTTCTCAGCCTGCAGCCTCCCTGTGGTCCACTTACCAGCACACATTCATTTTCTAGTATCCTACGCATCACTTTGAGAGGAACATGAAGGACAATTCTTTTGCTGAGTCTTCTGTGTTGCCTAAACTTTTCCTTCTCACTGGTGAGGCTACTTAAACCTGGGCATGGCCTGAGTTGTTGAACAATCACAGACTTACTTGTTATTGTATTCCCCCGAngmlr-0.2.7+git20210816.a2a31fb/test/data/test_2/000077500000000000000000000000001410636150300204475ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_2/expected.bed000066400000000000000000000005151410636150300227250ustar00rootroot00000000000000chr21 8913 9010 100bp 60 + chr21 8913 9109 200bp 60 + chr21 8913 9208 300bp 60 + chr21 8913 9308 400bp 60 + chr21 8913 9405 500bp 60 + chr21 8913 9504 600bp 60 + chr21 8913 9700 800bp 60 + chr21 8913 9897 1000bp 60 + chr21 8913 10090 1200bp 60 + chr21 8913 10285 1400bp 48 + chr21 8913 10672 1800bp 50 + chr21 8913 11063 2200bp 52 + ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_2/reads_100_2200bp.fa000066400000000000000000000246571410636150300234400ustar00rootroot00000000000000>100bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT >200bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC >300bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT >400bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC >500bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT >600bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG >800bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG TTTCTTCATCCCCTTATACAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAAC CAACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATAAAAGAGTAGGTGTTACCTTT >1000bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG TTTCTTCATCCCCTTATACAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAAC CAACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATAAAAGAGTAGGTGTTACCTTT AAAATATAAAATATGAAAAGTAAACAAGAGAAGAAGCATAGGTTTTGTGAACAAATCTGTGCTTCTGTAAGAAAGCAGCTAAATAGAAGAAAATACATC AGGCTTTGCCAATCAAAATTGATACTAAACATTTAGCTGTGCAAACTTAGAAAAATAAGCTCTCCTCTCTCAGCTTCACTTCTGACCTGTAAGACCAAA >1200bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG TTTCTTCATCCCCTTATACAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAAC CAACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATAAAAGAGTAGGTGTTACCTTT AAAATATAAAATATGAAAAGTAAACAAGAGAAGAAGCATAGGTTTTGTGAACAAATCTGTGCTTCTGTAAGAAAGCAGCTAAATAGAAGAAAATACATC AGGCTTTGCCAATCAAAATTGATACTAAACATTTAGCTGTGCAAACTTAGAAAAATAAGCTCTCCTCTCTCAGCTTCACTTCTGACCTGTAAGACCAAA AGAATAGTTTTCTGTATATCATGGACAATGCTTGTTACATCGATTAAGAAAAAAAGTGTCAGTTTTCTAGTTTCTACTTCTTCTAGGATGTCTGTAAAT TCAAAATGGTTGTCCAGCTCTGTGAAGTTAAAATTTATTCACAAATTCCTATAAACAGATTTGTTTTTTTGCCATGTGTTTCTGCCCAAGACTTTTTAA >1400bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG TTTCTTCATCCCCTTATACAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAAC CAACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATAAAAGAGTAGGTGTTACCTTT AAAATATAAAATATGAAAAGTAAACAAGAGAAGAAGCATAGGTTTTGTGAACAAATCTGTGCTTCTGTAAGAAAGCAGCTAAATAGAAGAAAATACATC AGGCTTTGCCAATCAAAATTGATACTAAACATTTAGCTGTGCAAACTTAGAAAAATAAGCTCTCCTCTCTCAGCTTCACTTCTGACCTGTAAGACCAAA AGAATAGTTTTCTGTATATCATGGACAATGCTTGTTACATCGATTAAGAAAAAAAGTGTCAGTTTTCTAGTTTCTACTTCTTCTAGGATGTCTGTAAAT TCAAAATGGTTGTCCAGCTCTGTGAAGTTAAAATTTATTCACAAATTCCTATAAACAGATTTGTTTTTTTGCCATGTGTTTCTGCCCAAGACTTTTTAA GTCCTCAGAATGAATCCTGACTTGTTATTGTGGCCACTTTCTATGTTGATGTGCGCAGCACACCATAGTCCATCAAAGTCGTTCCTCTGCAGTTAGTTA ATTCACTGGGGCCACAGGCTACCCACACCAATGGCTACAAGGCTACAGAAATCTAATACATCATCTTCTTTTCACTGTAGCAGAACATCTCTTTTCCTT >1800bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG TTTCTTCATCCCCTTATACAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAAC CAACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATAAAAGAGTAGGTGTTACCTTT AAAATATAAAATATGAAAAGTAAACAAGAGAAGAAGCATAGGTTTTGTGAACAAATCTGTGCTTCTGTAAGAAAGCAGCTAAATAGAAGAAAATACATC AGGCTTTGCCAATCAAAATTGATACTAAACATTTAGCTGTGCAAACTTAGAAAAATAAGCTCTCCTCTCTCAGCTTCACTTCTGACCTGTAAGACCAAA AGAATAGTTTTCTGTATATCATGGACAATGCTTGTTACATCGATTAAGAAAAAAAGTGTCAGTTTTCTAGTTTCTACTTCTTCTAGGATGTCTGTAAAT TCAAAATGGTTGTCCAGCTCTGTGAAGTTAAAATTTATTCACAAATTCCTATAAACAGATTTGTTTTTTTGCCATGTGTTTCTGCCCAAGACTTTTTAA GTCCTCAGAATGAATCCTGACTTGTTATTGTGGCCACTTTCTATGTTGATGTGCGCAGCACACCATAGTCCATCAAAGTCGTTCCTCTGCAGTTAGTTA ATTCACTGGGGCCACAGGCTACCCACACCAATGGCTACAAGGCTACAGAAATCTAATACATCATCTTCTTTTCACTGTAGCAGAACATCTCTTTTCCTT TTAACTATAATTGCAAAACCTGCATAGAGGGACAAGATTAACAAAAATATGCTCTCCTATCCACTTTAAACAGCCTAAAAAAATGGCTCTCTGCAACAA CATGGACTAATCTGAGAGAACAATTTAAATGTACAACCTTTGTCCTTTCCATTTGGGTGGATTTGGCAACAGATAACCCAATAATCTGATTTCCATGAA GGGTCCAGAATAAAATTCATATTTTGTGCCAGAATAATATTTAGTTTTACACTCGCAAAACTAACAACTGTATTTGGCAATGCAATGGTAAACTAGTTA GAAAAGCCCCCTGCTCTGAAGAACTTAAGAATTGAAATGACTGCGAGATCCAATTTAAGTCAAAATAAGAGTGTGTGTGTGTGGCTGTGTGTGTGTGTG >2200bp GGGGGTCTCCCCCATTGACTTTCAGATGGCCACTTTCTCCTGTGTCTATCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCT GTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATC ACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTT AATATTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTAAAAATATGTTCATATTTTTGACATACAAATTTTC CTGGGTTTTTATAAATACACAAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAAT AGTAAACAAAAGTTCATTCTGGAATTAGATTGCCTGGATTTTGTTATAGTCTCTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGG TTTCTTCATCCCCTTATACAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAAC CAACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATAAAAGAGTAGGTGTTACCTTT AAAATATAAAATATGAAAAGTAAACAAGAGAAGAAGCATAGGTTTTGTGAACAAATCTGTGCTTCTGTAAGAAAGCAGCTAAATAGAAGAAAATACATC AGGCTTTGCCAATCAAAATTGATACTAAACATTTAGCTGTGCAAACTTAGAAAAATAAGCTCTCCTCTCTCAGCTTCACTTCTGACCTGTAAGACCAAA AGAATAGTTTTCTGTATATCATGGACAATGCTTGTTACATCGATTAAGAAAAAAAGTGTCAGTTTTCTAGTTTCTACTTCTTCTAGGATGTCTGTAAAT TCAAAATGGTTGTCCAGCTCTGTGAAGTTAAAATTTATTCACAAATTCCTATAAACAGATTTGTTTTTTTGCCATGTGTTTCTGCCCAAGACTTTTTAA GTCCTCAGAATGAATCCTGACTTGTTATTGTGGCCACTTTCTATGTTGATGTGCGCAGCACACCATAGTCCATCAAAGTCGTTCCTCTGCAGTTAGTTA ATTCACTGGGGCCACAGGCTACCCACACCAATGGCTACAAGGCTACAGAAATCTAATACATCATCTTCTTTTCACTGTAGCAGAACATCTCTTTTCCTT TTAACTATAATTGCAAAACCTGCATAGAGGGACAAGATTAACAAAAATATGCTCTCCTATCCACTTTAAACAGCCTAAAAAAATGGCTCTCTGCAACAA CATGGACTAATCTGAGAGAACAATTTAAATGTACAACCTTTGTCCTTTCCATTTGGGTGGATTTGGCAACAGATAACCCAATAATCTGATTTCCATGAA GGGTCCAGAATAAAATTCATATTTTGTGCCAGAATAATATTTAGTTTTACACTCGCAAAACTAACAACTGTATTTGGCAATGCAATGGTAAACTAGTTA GAAAAGCCCCCTGCTCTGAAGAACTTAAGAATTGAAATGACTGCGAGATCCAATTTAAGTCAAAATAAGAGTGTGTGTGTGTGGCTGTGTGTGTGTGTG TGTGTATGAATAAAGGCAGGTAATATTCCATGTCAAATTCTGTATAGAATGTGAAAGAGAAAACAGATTGAGAATAGATGAACTTGGCAATCAGAAGAT TTACAGTAGAATAGAGGAAAGATTATAGTAGTATAGTTTGTGAGTAGTGGGTATTACTATGTTTGAAATAAAAAAGCTATTTTTAGTAATTTAATAAAA TATTTAGTTGATAGTACTTTTATTTTTGATCGATAAATATAAATGCATTGTTTATATTTTGTGAAAACACACATGGAAGATATTACCCAGGTGTGCTGA ATGTTTCCCATTCCTCCCTACCTTACATCCCTGTTGACCTCCAGGAGGCTATCCAGGAAGCTGATCTCAGTAAACTGCATATGCATACAGAGTGTTCAT philipp_@kronig(4639.ngmlr_test:0):/project/ngs/philipp/sv-paper/testcases/hs37d5$ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_2/ref_chr21_20kb.fa000066400000000000000000000463061410636150300233610ustar00rootroot00000000000000>chr21 21:21,444,718-21,464,625 hs37d5 ATACTGACATCCATGTAGATACATTTTTCCTGAAATGATGATTAGTGAAAAATTGAGTCTACATTATTTCACTTCAATAATTTAAAATTTTATTGAAGAGTTTATTATACAGCAATAATAAAAAAAGATAAGTATTTCCATTCTCATGATGATTTTGGCCACAATGAAAAGGGAGGTGCATTCCAGGACTATAATAATGGTTCAATACTGGGAAATTTATTAATACAGACTAATATACACAAATTAAGTTATAGGCCTTAGGAAAAAACTATATGTGTATATTTGCAATACTTTAAAGCCTTTCAGAGAAGTCAGCATCCATTCCTAATTACATATATTTTTCATGAGAATGTAGAAAGATATGGTTAATTCCTTCAAGCGATAAAATATATATACCTCAATTGGAAAGTCCACATCTTAATGGGTAAAAACATACAGGTAGTCCCACAAGAGTACTGAAAAAAAGTGCATGCCCACTCTCCTCACTGTTATTTAATATTGTTATTAGTTGATGCAGTTAGATACAATTGTCACACAAACTAGAGCAGCAGAAAAAAAAGTGTCTCTATTTGCAGATGACAATAATATATATCAATAATATATATAGATGCCTAAATGATAAAATATAAAATAATGCAAGTTGGCAGGTTATATTTTTAAAAAATCACTATTATATCTATATTCGCCTACTTATCTGTTTATTATCTATTTGCCATCCAACTTTCTGTTTATGCCAATTAGATAATGGAAAGACATCCTTTTTTCCTCATTTAGAACCACTCAACATCATCATGAAGTCATTTCTACATAATTGATTTATAAATTTGACGTTATCCCAAGATAAATCATAAGCGTTTTTATTTATGAAGCTAAATAAATGAATACTAAAATTATTATAAAAATAAATACACAGAATAGAGAAATATTTAAAAGTAAAGCTGTGAGGGAGGACTAGCCTTATTGAATATAAAAATAGTTCACTAAGGTTTTATCATTGAAATGATAACTATGTGTGGATACCCAAGAGAAGGGTATAGAAAGCTGAAAATAGACCCAGTTACATATATTAATCTAGTTAATAATGAAGGTGTTATCTCAAATTACTGAAGAAAATTGAACTTCTTAATACATGAATATTTATTTGAAATATGGTAAAATCAGATTTAATACTCAGAGCTTATATAGGAGAAAAACCCAAATTGTTCAGAGATCTAAATGTCAAGCATAGAATGTTGAGAGGCAAGAAAGAACCCCATGGTTTGAATTGGAATAAGGGATTTCAATGTGAACTTATGATGTCTAAAATATGTATATGCATGCATATATGCATATGTAATATATATTTCACTTATGTATAAATATGTGTTTTATAATAAATAATATATTTGTACACTTCTGCATTTACTTATCTCTATTTGTTAAAATGATCTAAATGCAAAATCATTCCAATAGCAATGAGTTCATATAACTATCTAACATCCAGATCTTGTTTTTTAATACCATTCTTCACTAAAAGAAGTCAGCTCTTTCACAGAATTGCTGATTCTAAGGGTAGGCCAGAGGAGGTAAAACATGAGTCTGGAAAATTTTATTTGCCATAAAGGAGGAATGTGATCAAACAGTAGAAAATTATGGAGATAAACAATGTTGAACATATATCACAAAGACACAGGAATCAGCTTAAAGGGGTTCCTCATAGCCAAGTCTAGGACCATTTGAGCACCTAAGTATTTAAACTCAGTGATAAATAATACACCCTTAAGTATAAGAATTCAGGGGTCCATAACTATAAGAAGAAATATGTGGGGACTTGTTACAGATCATAGATTAGTAAATAAAAAAAATGGCAATCATGCTGTGGACAAAATCAGCAAATATCATTCGCCAGGTGGTCCAAATTAACATCACTAATGCCAGGCAGATGGCATGAGTTTCCAGATGTTACTTTCTGTCAAGGACATGTTGGACTTAGGTAATAGGCAGCCTGAGGATGTGTAAGCTTCATTTATAAAGAAGGAAGTATAATACATATTTAAAAATCAATTTTAATAAAATTGGAAAATAAAAAGGGAAAAAGACTGAAAACTTCTATGTCAATTTAAGAAAAGTATGAAGAATTTTTCTAGATTGAAGTAGACTAAAGAGAAATGATATGCAAATGTAACAGGTGATCCCAGAATGGATTTTCCTTGGAGAGAGAAAAATGTGCTATAAATCATATTATGTGCTCAGTTGGCAAAAATGGGTATGGAAGGTACTGTATCAGAGTTAAATTTGTTGAAGTTGATAATGTCATTTTTTAAAGGAATTTTCTTGTTCCTAATATATTTAATGTAAAGATCGATGATATATGCATCTAACTCTCAAATAGTTCAGCAAAATTATATATATATAACTACATATGTGTGTACATATATATGTACACATATATCTAATACATAAGATGTATATATACATGCATACATACCTACACAGAGAGCGCAATGGGGCAAAATATCAATGAGAGGTGAATCTGACTGGTAAAGGATACTCTTTGTACTATTCTTGAAATGCTTTGTAAGTTCAAAATTATATCTGAAATAAAACAAAAAAATTTCAAACTGAAGATATTTTGATTATATTGAGACTGATGTTTTAAAGTCCCAAGAAGCAGGTCCTGAGATAAAAATGGGTAAGTCAATGATTTTTATAAAACCTGGTGGCAAGACAAACAGGTAAATCAATGGCAAATTTAAGATTAGGAAGTGGAACGAGCTCAACAAGGATATGATTTCATCCTTGAAGACAGTGTTCAGCTTGATCCCATAGGGAACTTAGAAATGAAGTCAAGCCCCAGTATTGTTCTGCTCCATCAATGGCAAGGGAGCTGAACTTCTGGCTTTCCTGGATGGCAGAAAAAGGAGGCTCCCATTAGGAGGAGTGCAATTCTCAGAAGAATTTGGGTGGCTGGCCTGTGGAAAACGGATGCAGTAGGAAGTGAGGATGAGGGCTTACAGAAAAGGTAGAAAGGAATCTCAGAAGAGCTAGATGAAACACTACCTCATGCTTTTATAGTTTAAAATTCCCCTGAATAGATTTTTAAAGTAACATGTAAATTTGGAAGAGATGAAAACTTTGAATTATTTAAATACAGAGATGATGGTTGTTCCATTCCAGACATCATTTTTGAAGGTTAGCTATCATGTGCCAGATGTCTTACAAAAAATAGGTGTGTGTGTGTGTGTGTGTGTGTGTGCTGTTTTTGTTATTATTTATCTTAAACTCTCTGGACATATAAAACCTGTTTTGCTTTAGTAATTAAAGGCAACTTTTTTTCTAAAACTTAGTGCTAAGTGCTCAATACCTAAGGAGAGAATTAGATCAAACAATGTGGTTTTAATATACTTTTTGTCTTCACTAATATAAGGAGATAACCTATTGGGGGTTTCATATTTTCTCCATAATGTTCATAAGGTGTGCTATCGGCATTTCAGCAATATAGCCTCCTTGTGGGCTATAGCATTTCAATCATTACAGGAAATTTCACTTCTCTGGACTCCATCTGCAAAAGATCAGTAGCGCTCTTCCTCCCCCACATTGAATTACATAAAAAACTGCTTTCATCTGTATATAACATGTGATTCTAAACATCCCTTAGGTTTAAGTGGCTATAGTATGTATTAGCATAATATTGAAGTTTAAGGAAAGTAAGAGTTTAAACATTCAATGTAGACATTGCTAAATGTTTTCTTCCAATTTGAAGGGTTACAGCATGTTACTTTTTTTCTTGAGTGTTATCAAACTCAAAAGATAATAGCTAATTTACAGAACATTATTTCTACTGGGAAAAAATAATCACATTTAATGTTATCAAAGATATGGATATAATCTAAATAATTTTAACTGTGCTTAGGTTATATTTAAACATTAAAGATAGCATTTCTTAAAAATTAGTATTTTTTAAATTTTATTTTATTTTTTATTATACTTTAAGTTTTAGGGTACATGTGCACATTGTGCAGGTTAGTTACATATGTATACATGTGCCATGCTGGTGCGCTGCACCCACTAACTCGTCATCTAGCATTAGGTATATCTCCCAATGCTATCCCTCCCCCCTCCCCCCCCCACCCCACAATAGTCCCCAGAGTGTGATGTTCCCCTTCCTGTGTCCATGTGATCTCATTGTTCAATTCCCACCTATGAGTGAGAATATGCGGTGTCTGGTTTTTTGTTCTTGAGATAGTTTACTGAGAATGATGATTTCCAATTTCATCCTTGTCCCTACAAAGGACATGAACTCATCATTTTTATGGCTGCATATTATTCCATGGTGTATATGTGCCACATTTTCTTAATCCAGTCTATCATTGTTGGACATTTGGGTTGGTTCCAAGTCTTTGCTATTGTGAATAATGCCGCAATAAACATACGTGTGCATGTGTCTTTATAGCAGCATGATTTATAGTCCTTTGGGTATATACCCAGTAATGGGATGGCTGGGTCAAATGGTATTTCTAGTTCTAGATCCCTGAGGAATCGCCACACTGACTTCCACAATGGTTGAACTAGTTTACAGTCCCACCAACAGTGTAAAAGTGTTCCTATTTCTCCACATCCTCTCCAGCACCTGTTGTTTCCTGACTTTTTAATGATTGCCATTCTAACTGGTGTGAGATGGTATCTCATTGTGGTTTTGATTTGCATTTCTCTGATGGCCAGTGATGATGAGCATTTTTTCATGTGTTTTTTGGCTGCATAAATGTCTTCTTTTGAGAAGTGTCTGTTCATGTCCTTTGCCCACTTTTTGATGGGGTTGTTTGTTTTTTTCTTGTAAATTTGTTTGAGTTCATTGTAGATGCTGGATATTAGCCCTTTGTCAGACGAGTAGGTTGCGAAAATTTTCTCCCATTTTGTAGGTTGCCTGTTCACTCTGATGGCAGTTTCTTTTGCTGTGCAGAAGCTCTTTAGTTTAATTAGATCCCATTTGTCAATTTTGTCTTTTGTTGCCATTGCTTTTGGTGTTTTAGACATGAAGTCCTTGCCTATGCCTATGTCCTGAATGGTAATGCCTAGGTTTTCTTCTAGGGTTTTTATGGTTTTAGGTCTAACGTTTAAGTCTTTAATCCATCTTGAATTGATTTTTGTATAAGGTGTAAGGAAGGGATCCAGTTTCAGCTTTCTACATATGGCTAGCCAGTTTTCCCAGCACCATTTATTAAATAGGGAATCCTTTCCCCATTGCTTGTTCTTCTCAGGTTTGTCAAAGATCAGATAGTTGTAAATATGCGGCGTTATTTCTGAGGGCTCTGGATCATTTTAACGTGCATTTCTCACTTTATGTTCTTTGCTAATGACTTACTTCTTGCTGTTTATTTTATATGTATTTTAGACCATGGAAATCATATTAGACAAAAAGCAATTTCAAGCAATTTTCTTATTCTAGTTCAAAATGGGCCATAAAGCAGTGGATACAACTCACAACATCAACAACACGTTTGGCCCAGGAACTGCTAACAAACTTACAGTGCAGTGATGGTTCAAGAAGTTTTGTAAAGGAGACAAAAGCCTTGAAGTTGAGGAGCATAGTTGCCGGTCACTGGAAGTTGACAAGGACGAATTGAGAGCAATTGTTGAAGCTGATCTTCTTACAACTGCATGAGAAGTTGCTGAAGAAATCAATACTGACCATTCTATGGTCATTTAGCATTTGAAGCAAATTGAAAAAGTAAAAAAGCTCAGTAAGTGGGTGCCTCATGAGATGAACAAAACTAAAAATAAAAGTAGATTGTCATTTTTAAGTGTCATCTTCTCTTTTTCTATGCGACAACACGAAACCGTTTCTTGATAGGATTGTGACGTGCGACAAAAAGTGGATTTTATATAACAACCGGCAATGACTAGCTCAGTGGTTGGGCCGAGAAGAAGTTCCAAAGCACTTCCCAAAGCCGAACTTGCACCAGAAAAAGGTCATGGTCACTGTTGGGTGGTCTGCTGCCAGTCTGATCCACTACAGCTTTGTGAATCCCAGAGAAACCATCACATCTCAGAAGTGTGCTCAGCAAATCGATGAGATGCATCAAAACGGCAAGGCCTGCAGCTGGCACTCATCAACAGAAAGGGGCTAATTCTTCACAAGGTCCAGTGGCACGTCACACAACCAACACTTCAAAAGTTGAATGAGGCCGGGCGTGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGTGGGCGGATCACGAGGTCAGGAGATCCAGACCATCCTGGCTAATTTATTAGAAACCCCGTCTCTAATAAAAATACAAAAAATTAGTTGGGGGTAGTGGCGGCGCCTGTAGTCCCAGCTACTCCGGAGGCTGAGGCAGGAGAATGGCGTGAACCTGGGAGGCAGAACTTGCAGGGAGCTGAGATCGCCCCACTGCACTCCATCCTGGGTGACAGAGCAAGACTCCGTCTCAAAAAATAAAATAAAATAAAAATAAAAATAAAAATAAAAAGTTGAATGAATTGGGCTATGAAGTTTTGCCTCATCCACCATATTCAGCTGACCTCTTGCCAACCGACTACCACTTCTTCAAGCATCTTGACAACTTTTTGCAGGGAAAATGCTTCCACAACCAGCAGGATGCAGAAAATGCTTTCCAAGAGTTCATCAAATCCCAAAGCACGGATTTTTACGCTACAGGAATAAACAAACTTATTTCTCATTGGCAAAAATGGGTCGATTGTAATCATTCCTATTTTGATTAATAAAAATGTGTTTGAGCCTAGTTATAATGATTTAAAATTTATGGTCCAAAACCGCAATTAACTTTGCACCTATCTAATATATTAGGAGATACACAAACTGAAAAATAGATGAAATGTTCTTATTCTTATTTTGATATATGACTAAATAAAAGAGGTTAAAAAGAGGGAAAATACATTTGTGTGTGTGTGTCTGTGCGCCTGAGTGTGTGTGTTTAAGTCAAGTGTGGGAATTGTTTACACAGGTCAGAATTAATTATAATCCCTGAGGTAGTATCAAATAAGGTAACAATAGCAAACCAAGTATAGTGACTCATAGTCTTTGACAACTATAATAAAGTATATCAAAAAAAATATTTTTGAGAGTTAGCTATGTATAAGAAAATAATGTTATGTTATGTCTTCATAAAAAAACTATCACAGAGACATTGCTCATTGTGATTAAAATGAAATGTTTCATTTTAAGTATGTGTATGGACAGTTTAAAATGGAATTTAATGGAATGTCTGGAAAAAGAGTATATATACTTCAGAATCCTTATAAAATAAAATTGAAACTATAAGAAACATGAGATAAAATATTTTATAAATACATAACAATTATTTTTTAATCAACTGATTGTAAGTCTAGCAATTATTTGGTATATTTGTTAGAGATATAATCAAGTCACTTTCAGTCTAACATTTTGGCATTGAGAGGTTAGTTTTCAAAAACATAATAATCTTAAAGTCCATGATTGACCAAAGAAATATAAAAGTCAGCTAAAGCCACTGAAAGCCCACTCAGTGTAGAGTATTTGATGACATATTTGAGATAATATAAGTCAAATTCTATGAATTTAATGGAAAGATGAGAATGGAGGTAAAACTTGAACTTGTACCTTTAAAGAGGTAATGAATTATAATAGGCTATCTTATTCCCTCATATAAATATGAATTCATGTAGATGAACATTTTATTTCCAAAATAGTTATCTTAGCTCTCAGAGACATTACATTTCCAAGAGTAAGACATAGGCTTACTGTAAGACTTTCTAGTAGTCCAAAAATGTGGTGATTGAACAAAGATCCATAACTTTTTATTTCCCAAACTTACATAGCTTTGTCTAAAATATCAAAAATGTATATCCGTTTCCTAGGATTAATGAGTAACTTCAGTATTGAAAATATTAAAATTTATATTTTTAAAGTAAAATTTGGTAATTAACAAAGTTATTTTAATGCTTAGAGGCTTTCAATATATATAAACAATATAAGACATTTATTTTTACTTTCTTACATGGACGTGGCAGTTTATTATTTTAAAATACACAGGTCTAAATTTTTGAAAAATTGTTTATTTTGACAGGACAAAGTATAGAATTTTTCTTATCAATAGCAGACTCAAGGCTAATTTTGGTTTTAAGAGAAGTGAAATAATCATACTACATATAAAAGGATTATAAATTGATATAATTATACTAGACTCTCTTTCATAGTATATTTCATGAAGCATTAAAACATTTGTATTTATAATTTTATCATTTCTACTTCTAGAAATCCAGCCAAGAGAAATGATCCTACATATGCAAAGTTTTATACAGAAAAATGTTCACTGTGGTGTTACTACTAATGATAAAAATATGTAATCTAGATATAAAATATATTTGATGGTTTGATAATCATATGAAATCCATTAACATAACCATCAGGGAGTAATTGAAATTGTACTTACAATAACATTTAATCACTTGGAAAATTTCTAATTTTCTTTTGCTAAGCTAAAAAGCAAGATACAGGTTTGCACACAATATAACATTAGTTTTAATTATGAAAATGACCTAGACTTGGGACAGAAATTGTCAAGAAATGTATTAATTTACAGCATCATAAGTGATTTATGTGCATAACAATTTCACCATATTCTTTTAAACACTTCTCATTTTAAGAGTCTTAAATTTTCCTAATGTGAGGGTTATAAAACATTCTATCATTAAAGTCTACATCTGTGTCTACCTAACAGTTAGAAAATGTGTAAATAATTTTATTTCCTATAAGCTATTTGCATTAGTTTCCTAGGGTTGCCAGAGCAAAATGGAGGCCAGACAAAACATAAAAGGCCAGACAAAACATAACAAAAAGTTCACACCTCTAGAGGCCAGAAGTTCAAGATCAAGGTGTTGGCACGTTTGGTTTCTTCTGAGGGGGTCTCCCCTTGACTTTCAGATGGCCACTTTCTCGCTGTGTCTTCACATGGTCTTCGCTCTGTGTACACGTGCCCCTGGTGTCTGTCTCCCTCTGTGTCCTAATCTTCCCTTCTTATAAAGACACCACGCATATTGGATCAGGGCCTGGGTTAACTTAATTATCTTTTAAAGGCCCTATTTCCAAATATAATCACATTCTGAGGTACTGGGAGTGCTTTGACATAAGAATTTTGGAGATACACAATTCATCCCACGACACCATTCATCATTTCTCTTCAGAGAATCAGGTTTAATATTTTCTATATCTTTCTCCTTACTTCTTGTTTTCTTAATGATTTTGCATAAGACAATTTATTTAAAAATATTTCATGATTTTTGACATACAAAGTTTCCTGGGTTTTATAAATACATAATTTTTTTTGGTCTCTTGATTCTTTTCAGCTCTGTTATTTCCAATGATTTCGTATTGTGTGTGATAGAAGCAGAATAGTAAACAAAAGCTTCATTTCTGGAATTAGATTGCCTGGATTTTGTTATAGTTTTCCCACTTACTATCTGAGTAACTTTGAGCTCGTCCCTTCCATTGGTTTCTTCATCCCTTATAAGGGAAAATAGAACCAACCTTGTAGAGTTGTTGTCAGAATTTAAGTAATATGGGCAAAGCACACAGAACAGTTTCTAAACCACATTAAACAACAAATGATTAACACTTAGGAATGACACCTTTAGATAGCTCCATGATTAGTACATAAGAATCATATCAAAAGAGTAGGTGTTACCTTTAAAATATAAAATATGAAAAGTAAACAAGAGAAGAAGCATAGGTTTTGTGAACAAATCTGTGCTTCTGTAAGAAAGCAGTAAATAGAAGAAAATACATCAGGCTTTGCCATCAAAATTGATACTAAACATTTTAGCTGTGCAAACTTAGAAAAATAAGCTCTCCTCTCTCAGCTTCACTTCTGACCTGTAAGACCAAAAGAATATTTTCTGTATATCAGGACAATGCTTGTTACATCGATTAAGAAAAAAAGTGTCAGTTTTCTAGTTTCTACTTCTTCAGGATGTCTGTAAATTCAAAATGGTTGTCCAGCTCTGTGAAGTTAAAATTTATTCACAATTCTATAAACAGATTTGTTTTTTTGCCATGTGTTTCTGCCCAAGACTTTTTAAGTCCTCAGAATGAATCCTGACTTGTTATTGTGGCCACTTTCTATGTTGATGTGCGCAGCACACATGTCCATCAAAGTCTTCCTCTGCAGTTAGTTAATTCACTGGGGCACAGGCTACCCACACCAATGGCACAAGGCTACAGAAATCTAATACATCATCTTCCTTTTCACTGTAGCAGAACATCTCTTTTCACTTTTAACTATATGTGCAAAACCGCATAGAGGGAAAGATTAACAAAAATATGCTCTCCATCCACTTTAAACAGCCTAAAAAAATGGCTCTCTGCAACAACATGGACTAATCTGAGAGAACAATTTAAATGTAAACCTTTGTCCTTTCCATTTGGGTGGATTTGGCAACAGATAACCCAATAATCTGATTTCCATGAAGGGTCCAGAATAAAATTCATATTTTGGCCAGAATAATATTTATGTTTTACACTCGCAAAATAACAACTGTATATTGGCAATGCAATGGTAAACTAGTTAAAAAGCCCCCTGCTCTGAAGAACTTAAGAATTGAATACTGCGAATCAATTTAAGTCAAAATAAGAGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTGTATGAATAAAGGAGGTAATATTCCATGTCAAATTCTGTAAGAATGGAAAGAGAAAACAGATTGAGAATAGATGAACTTGGCAATCAGAAATTTACAGTAGAATAGAGGAAAATTATAGTAGTATAGTTTGTGAGTAGTGGAGATATTACTATGTTTGAAATAAAAAAGCATATTTTTAGTAATTTAATAAAATATTTAGTTGATAGTACTTTTATTTTTGATGATAAATATAAATGCATTGTTTTATATTTTGTGAAAACACACATGGAAGATATTACCCAGGTGTGCTGAATGTTTCCCATTCCTCCCTCCTTACATCCCTGTTGACCTCCAGGAGGCTATCCAGGAAGCTGATCTCAATAAACTGCATATGCATACAGAGTTTTCATGACCTTTGGCCTCTAGGTGGCTTTGACTACAGGAGGTACTCATGAATCACAGGGTGTTATGGACTGAATTGTGTCCACATAAATGTGTATGTTGAAGACCTATCTCACATTTCCTCAGAATGGGACTATATTTGGAGATGGAGCTTTTAAAGACAGCAGTACATTCATTAAAATGTGGCCTTTGGAGTGGACCTTAATCCAATATAATTGGTAGCCTTTGTTTAAATAAAAAAGATTAGGACATGCAGGGGGAAAAACCAAGAATGTTCCTGTACAGAGAAAAGACTAAGATGAAGACAAAGTGAGAAGGTGACATCTGCAAGCCAAACAGAGAGCCACAGAAAAAGCCAAACCAGGCAACATCTTGATTCCAGATCAAGCCTCTAGCACTGTGAGAAAATCAGTTGTTGTTGTCAAAGCCCCTGATCTGTAGTAATTTGTATGGCAATCCTAGGAAACTAATATGGAGATCAACATATTTTTTCCCAATCCCCCAACTCTCCCTCCATGCAGGTTGCAGTTTGGCAGTGGCTGAAGTCCAGAGCCACAGCTTCTGTTGGGCAGCCCTCTCCCACAGACACAGTTCTCATTAGGTGGTTTCCTTTATGAAAGCAAAAAGTGTCTGCTGTCTTCTGTTGGCTTTTCTGTCTAATAACTCTGTCTATTAGTGTCTTTCTTCTCTGTGTAAGCTTTTATATTGTCTCTTCCTTAAATTCTCTGCAACTGTCCCTTTGAAACATGTGATTAGTTTTCTTTTTTTTGAGATGAAGTTTTGCTCTTGTTGACCAAGCTGGAGTGCAATGGTGCGATCTTGGCTCACTGCAACCTCTGCCTCCTGGGTTCAAGCGATTCTCCTGCCTCGGCCTCCTGAGTAGATGGGATTACAGGTGCGTGCCACCATGCCCACCTAAATTTTTGTATTTTTTTTTTAGTCGAAACAGGGTTTCACCATGTTGGCCAGGCTGATCTCGAACTCCTGACCTCAGGTGATCCACCTACCTCGGCCTCCCAAAGGGCTAGGATAACATAGATGCCCATTAATGAGGAAAATCAAGGATGTGTTTTCAGGGCATAGTGTTATGTTATGATAAAGTGACTTGGATTCATTATATATTATATATTATATGTTATATAATAATGCATTATTTGTCATATTCTATACACCATATCTTATATGTTATATGCAATATATTGTATATTTTCCATTATATCACTGCCAGTGGTGGATACATTTTGATGTTTGTAATATAAAGTCAGATGATCAAGTCATTAGAGAGGTACATCTTTTTCTGTACATCAGAGGTATTTATTCACATACTGGAGATATTCAGTTGAATGAATAGATTTCTTTATTCTATGAGTTGTTGTTATGGTTTGGCTACATCCCCACCTAACTCTCATCTTGAATTGTAGTTCCCATAATGCCCACATATCCTGGGAGGGACCTGGTGGGAGGTAATTTAATCATGGGGGCAGTTACCCCTATGCTATTCTCTTAACAGTAAGTTCTCACAAGATTTCATGAGGTCTGATGGTTTTATAAGGGGCTTTCCCGTTCACTTGGCTCTCATTCTTCTTCCTGCCACCCTGTGAAGAAGGATGTATTTGCTTCCCCTTCCACCATGATTGTAAGTTTCTTGAGGCTTCCCCAGCCATGCTTACTGTGACTCAATTCAACTTATTTTCTTTATAAATTACCCAGTCTTGGGTATGTCCTTATAGCAGAATGAGAATGGACTAATACAGTTGTCTAACAAGGTATATTTGTGACATATAAATTCTCAAAAAAATAGACACAATGGAACAGAATACATGGATTCATTAAGTCTCCTTAAAACCTCAGCTTGAACCCAGAGGTTCAAGAAAATAGGGCTCTTTTTTACTATTAGAAGGAAATCAGTTTTGTCATACCAGTTTCTAACTCTCAATAGAAGATGTACAGTAATTTTCTTTTATTCGATTTAAAACCCAACTCCTAGAAATATGGCCCAATTGATGTTTTTGAACATGAATCTACCCTTGCTTCTCCTCTTTGGGGGTCTGTCTCCATTTGTCCTGCATAATCCTTATGAGTGATTGGAGCAAGAAGAAGGAAAATATCTGTGCTTCCCCTAGAGTTAGTATGATTATTACTTCACCACTCATAGCACACTTACCATATGCTGAGCTCTGGGAACAACTTGGGGAAGCAAAAGGAAAAAGAAAACACACACATCTTTGGGTTTAAGAAGAAAGCCAGCAAACAAAACAACAAAGCAAAAAAAACAAAACACATTAATGACATAAAATTGCACATCCCAGGTGGATGTTGGTGAGGGAGGAGCAAATATTCTCTGATCAAGATACTAATGATTGCACTAGAGGTTCAAATAGCATCCTTCCAGGTGGAGAAAAACTGAGTTGGGTTATGCATAGAAATCTTGTCAGGCAAGTATTTAAAATGTGGAGGGTTGTCCACAGGCAGGCATTCCTAAGTACTATATTAAGGTAAAAAGGTAGGACTCTAGCTCACGCCTGTAATCCCAGCATTTTGGGAGGCCAAGGTGGGTGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCCACATGGTGAAACCCCGTCTCTACTAAAAATACCAAAAATTAGTCGGTCGTAGTGGTGGGTGCCTGTAATCCCAGCTACTCAGTAGGCGAGACAGGAGAATCGCTTGAACCTGGGAGGCGGAGGTTGCAGTGAACTAAGATCATGCCATTGCACTCCAGCCTGGGTAACAAGAGCAAAACTCTGTCTAAAAAATAACAATTAAAAAAAATGTAGGATTCTAGTCATCATGAAGGGGAAGATCCTGACAGACCCTCATCCTCACAGGAAACTAAAGTACTATTTTAGTTACTGGAAGAGTTATTCCAGATAGCACCCAGAAGACTGGGGACAGGAGGTAAGAAAACTTTGCCTTCTCAGTACAAGATTAGGGGATCCAAGTACGAGAGTGGAAGCTGCAGCAGGGCTGAACTGAAGCTGATGAGACAGAATATTCACCATTTGCTTTTCCACTATTGCATTGCATTTTAAGCATACTGGTCATCCCGGGAGATATGTATCAGGGTGATAGAAGGGAAGATGCAATAATGTCCTGCCTGAAATGGGGAAATATGAGTGGTTTAACCACTTATTGCTTTAAGCCTCACATTGACTGGGAACTGAGACAGGCCTGAGCTTGACAGATAAAGAAGCCAATGCACGTAGGGGGAGTGGAGGAGACCGAGGCTGGACAGACACTTGGCACTGGTAGGTGATAAGATGATGTGGAACAAAAGTCCTCCTCTCAAAGTCATTTTCAGACTCCAGCTATCATCATTCATCCAAGAATCATTCCATATTTCAGGGATTCATAGAATTTATAGCAAAGGCCTTCAGTCGCCTAGGAATGTTTAAATTTTGTAGCAGTATGTTTTTTGAGTATGCTTACACTGACTTAGTTTGGCCAATTGTGTTGTGTAGTGTAAACAATCAAACAAATGACATGGTGGGATTTCTGAGCAGCACTGTCTGGTATCTTGCTGATGGTGTCTTTAATAATAGATGGCACTTGATTTTAGATATAAATACATGAAAATAGTTTGAATGTTGATATTGTTTACTTTGACTTTATGTTGCTGCAGGTTTACAAATCTGAGAAAAAAAATATTTCTGGAAAACATAGGAACTGCATTTTGTTTTCTGTTGCTGCATGATACTGAATAAAGAATGACAGCAATCCATGATGGGAGCAGGTTTCAGCACATCAAATCATCATCCTACCGACTGTCCAGGAACAGTTATTGGATGTTTTCCTGGGATGTCAATAATTTTGAGTGATTCATAAACCATATAAATTAGGTTTCAAAATAATTACACTTGTGTGTACAAAGTTTGCCTTCCTACTGGCGGGTATCACATTCCAAATTGTAACAAATCAAATAGTGTCACAAACATACAAATCAACCTATAAATAATATATGAAAAGCCATAAATAATAAATACCTTCTTATCGTATCTCAAGTTAACACCAAACTCAGTTTCTTCTGTGAAATTTGTAATTTATATTTCAGTAAAAATCACTGTTTCCTCAGTATTTTATAAAAATCGATCTGTCATATCTTGTGTGTCTTAGACCTCAGCCAGGCTCCATAAAATGAAAACAAAGTTAAACAACTTCACAAGAGACAGAAATGGCCTTTTAAGATTCATAGGAGTGTGCCTTCTTGTCTAATCTGAGCAGCCATCATGGCAAGATTGATGTACATTGGCTGAGAAGCGTTTCGTGAGGCGGCTGTCTGCTCAGTAGTACCAGAATGGAGCTATCTGTCTTCATTGTACCCCATTAACATGCCCCTCAGATCTATCAGGCAAATGTCTGCATACCTACTTTATAAATTATTACAAGCGACAGTTAAATATTTCAGAACTTGTTTGGGGATATCACTCACCTTATAGTTTTTAATTTATACACACTCATGATTTTAAACATTTTAAGTTCAAGGATTACTTGGAACTACTTTTATATTTTCACTTTACATGAGCTTATTCTGCTGATAGTAATCCATCCAGTTTTGAAAAGTGCGGTCAGTGTATTGAAGTAAATTTTAAAAATTCAAATTATTCACTAACAAACAGCACATTTTCTTTAACAATTAAGTAGCCAAGATTTCATAGCAATATAATAAAAAAAAAATGTTATTCGTTTTCCTTTTAATGCAAAATAATTCTGAACTAAAAAGAATGCATTCAAATCATGTTTATCTGAAACTTTTGCTTTTTAAATTACTTTTATTTACTCACTTAAATTTTATTAGCCTACTGACACACAATATTTCAATTTGTAGTAATAATGCTTTAAAAGCCCAAGGTTTTACTTTAATAATTTTAGTGTGTTAATTTTTAAGAACTCAAATTGTTAAGTATTATTCATAGAACAATTATTCCAATGTTCTCCTGAACTATAAAGCTACTGTACACGAGAGTGAATTGGTTATAGAAATGGAGACAGGGAGCAGATTTTTTTCAATGTAATTAAAATAAATTTGAACTGAATAAAGTTCAATGTATTTCAGATTTAATAGGCATTGTATTTACTAATAAAAAAATTGCATGCTTGAACTTACTTAACCTTGGAGAGTAGAGGTAGCTTTTCATTAATCTCCTTTTTTAAAGTTGGATGAGGTTATGTAACTGAAATAGACATTAAAATTGAAGAGACATTCTTCATGGATTACAGAACAGTATTTGGAAGGAAACCAAATCATTAAAATATCACCAATAAATAATTAAATTTGCTTATTACATTGAAAGGACAGAACTAGAATAAAATTTATTGAGGCTACTGTGAGCCAAAGGCTTTATATAAATTATTATGTTATATCTTCATAATACTCTTTTGTGGTAGATATTTTCTCATATATTAAAGTTGGAAAAACAGGTTTAGGGAAGTTAAGTCAATTTCAAAAATACCAAATGAGTAAGAAGTACAAATCAGGATCTTATCTAGTTCTGTCTGACTCCAGTGGCAGTGATGTGTGCATTACATATTTGCGTGTGTGTGTCAAAAGAAGAGCAAAGGAGACTTTAGAAGAGATGCTGATTAAAGAAGATCAGAGGCAGAGACGGGCGGATCATGAGGTCAAGAGATTGAGACCATCCCGGCCAACATGGTGAAACCCTGTCTCTGCTAAAAATAGAAAAGTTAGCCAGGCATGGTGGCGGGTGCCTGTAGCCCCAGCTACTCAGGCGGCTGAGGCAGGAGAATGATTTGAACCTGGGAGGGGGAGGTTGCAGTGAGCCGAGATCACGCCACTGCACTCCAACCTGGAGACAGAGCAACACTCTGTCTCAACAAAAAAAAAAAAAAAAAAAAAGAAGATCAGAAATATCTTTTTTACTTTCTCTTCCCATTTTTTTAGAATTTTATTGAAGTATAAATGAAATACCATAAACTGCAAATATTGATAAATTTTGATACGTGTATGTCTAGTGCAAATAATGAAGATAATGAAAATATTGCATATCTGTCAACCAAAAATATGTTATTTATACCCGTTTGTACTTTCTCCATCCTGCCTCTTTTTACTACTTCCTCCCACTCCTAACAACAGCTGATCTGCTTTCTGTCACTATAAGATTAGTTAGTATTTTGTATAAATGGACTGATTACAGGAGCCACCTTTTTTTCTGACTTTTTTCATTTAGGATAATTATTTTGAGATTAATCCATGTAGCTACAGGTATCAAAAATCTGTTCCTTTGTATTGTTGAGTAGTATTCCATTGTAAGGATATACTGTAATTTGTTTGTTTATACACTTAATGGACATTTGGATTTTACTAGTTCCTGGTTATTGCAAAGAGAGCTTCATCCTTTTCCAGAGTTCATATGAACCTACACTTTTTCTCCTATTCATGCAACTCATAGCACCTATCATATGCTATGTGAATGTTTATGTGTGTATATATAAAAACATATATATACACACATATAAACATATATACACATATATAAACATATATACATATATAAACATATATACACACATATATAAACATATATATACACATATATAAACATATATAAACATATATATATACACATATATAAACATATATATACACACATATATATATATTTGATTAAACTCTTTTTGGAGTAGTTGTACCATTTTACACTCGCATCAGCAGTATATGAGAGTTCTAGTTCAACCACATCCTTGTCAACACTTTGTATTTTTTCTTAATTTTCTTTTTGAAAAAAATCTAGCCTTCTAATAAATGTGCATTGACATACTATTACAGATTTGCTTTGTATTTCCCTAAAGACTAATGATTTCCAGCCTCTTTTAATAAATTTATTTGCCATTCGTATATCCTTTTTTATGAAGAGCCTCTTCATATCTTGAGCACAGTTTTAAAATTTGAGTTTTTTTCTTATTATTGTATTTTACAAGTGCATCATATATCTTAAATAAAATCCTTTACCGCATACAAGATTTACAAATATTTTTTCTAATATCTGGCTTAAATTTTTATTTTATTTCTAATGTCTTCCAAAAATTAGAAGTTCTTCAATTCGATAAAGCACATTTTATCAATTCATTTATTTTTTAAATAAATTATGATTTTGTTGTCTTATTTAGGAAAACTTTGCCTATTTCATGGTCACACAGATGTTCTCTTAAGGTTTCTTCTAGAAGATTCTGTTTTAGATTTTAACTTTAGGTCTATGGTGCATAGTAAGGATAAAGATACCATGCATATTTCCTTTTTTTAAAAAAAATGGACATTAATTATTGGTTTTGTTTGTTTGTGTTTTGAGACAGAGTCTCAGTTTGTTGCCCAGACTGGAGTACAGTGGCGTGAACACAGCTCACTGCAGCCTTGAACTTCTGGGCTCAAGTGATCCTCCCACGTCAGCCTCCCCAAGTAGCTGGGACTACAGGTATGGATCATCACGCTCATCTAATTTTTGTATTTTTTGTAGAGACTAGATTTTGCTATGTTGCCTAGGTTGGTCTCAAACTCTTGGGCTCAAGTGATCAGCCCACCTACGCCTCCCAAAGTGCTGGAATTACAGCCTGAGCCACCGTGTCGGCCATTAATTGTTTTACCACTGTGATAATCAGCCTTATGTGTAAAGCTGATTAAGCTATAGTTCCTAATTATTCAATCTAACATCTAAGTTTTGTTCAAAGACGTTTCTGTAGATATTATTAAGTGAGGAAGATGATTCTAGATAATCACGGTGGGCCTGAATCAGTCAGTTGAAAAGCCTTAAGAGAAGGCGGGAGTTTTCCCTGAGGAGGAAGCCATTCTGCCCATGGACTGCAACCTCAGCTCATGTCTAGAATACGTGAAGTGTTTCAGCTTGCCCTCCCTGACAGCCTTCCCTATGCCAATGCCTTGCGATAAATCTCTGTCCTCTCTCTCTCTCCTTCGCTCCCACCTTCTCTCTCCCACTTACTTACCCTACTGGTTCTGTTCTCTGGTGGAACACTGACTGATGCTACCACCGTTTCCTGAAAAAGATTATTTCTTTTCTCCGTAAATTGCCTTTACATTTTTGTCGAAGATCAATTGTATGAATATGTGTAAGTCCATTACTAGGCTTTCCTATTTTTTGAGACTGAGTCTTACTCTGTCACCCAGGCTAGAGTGCAGTGGCGCGACCTCGGCTCCCTGCAAGCTCCGCCTCCCAGGTTCACGCCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCGCCCACCACCACGCCCGGCTAATTTTTTGTATTTTTAGTAGAGACGGGGTTTCACCGTGTTAGCCAGGATAGTCTCGATCTCCTGACCTGGTGATCTGCCCGGCTCGGCCTCCCAAAGTGCTGGGATTACAGGTGTCGCCACTGAGCCCGGCCGTCCATTACTAGACTCTTATCTGTTCTATTAATTTGTTGGACTATCCACCACTACCTACCATGCTGTCTTGACTACTGCATTTTTATCATATATATTGGAATCAGATAGCATAAATTTTCATGGGAGAGAAGCTGAGATAAngmlr-0.2.7+git20210816.a2a31fb/test/data/test_2/result.bed000066400000000000000000000005151410636150300224420ustar00rootroot00000000000000chr21 8913 9010 100bp 60 + chr21 8913 9109 200bp 60 + chr21 8913 9208 300bp 60 + chr21 8913 9308 400bp 60 + chr21 8913 9405 500bp 60 + chr21 8913 9504 600bp 60 + chr21 8913 9700 800bp 60 + chr21 8913 9897 1000bp 60 + chr21 8913 10090 1200bp 60 + chr21 8913 10285 1400bp 48 + chr21 8913 10672 1800bp 50 + chr21 8913 11063 2200bp 52 + ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_3/000077500000000000000000000000001410636150300204505ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_3/read.fa.gz000066400000000000000000014523021410636150300223210ustar00rootroot00000000000000TXread.faKmdDAtY7|֎,J2K$T9'32}/~ۿ|ח?~돿:?L̯ߜ__<_Uq>x>_+>w=Ux_/{ȏW?&~]6z^}g<;)W:|a?~ ~|_?g_+ϋp>|0^K0sŵڗx_?m?C>?o/xgs/<|/ -{~a'g}xy75<ϝUg}g:+>^gMsS%߰Kk~k^zn~g<+vL>ųqX*ݧ{ўe[l,(lͮK^{Ͼ~G{Mc7}ڍ+αQ˾}ޥe~xL&>?,ݔ?޳ϸl+[݌W{wgA|&x?_U<6=sgSC-_\<ѝyyȳk=W<vA{~aijv9Yd- v]sP]vӻGnyҞ~>W=.w޽ܞ+ od },oJyb?nc[L}{NQN>z2| vwo:x. y=`7gC/ư- ]YqO<{ ~QYkޣjve~"gz=}.vw^]>ʾs0UF?m|yٳPWzb[ σ{|o{)mOE:칲oܒgaOxbWEnoSz}R~e-52K,Bn?7÷>>s?Wv7~F5{;'sO2uzi˳^#2[|R<}Nql%>{>M= rK<vX z^q{xBG?~mw짵lB:ZRV9]F]P6v^u8JJ`WrR9iq6ϒI\ڷ`QkHnO'rtEl^" mot0Ϻ߶lX[8>^B+N7ѭcvm7cSsc^y[ە]^ѳk3%pGX+|5t:>ms}y.q4Ko ϱQ絉vO ~RٿhSm<0Vz|yE#Ĺ{(󧵏@oݜk=:N齗&4;"wϩ[Ŷ,mO-3-Blw6{'/#yy }r{-Auj]Eo|+CEAh@ e>a=k_Nc wb$DhQL ׾+Z?dg8'=;$x\MJqs1S:Yg/ϿAtc*f;t҂]mq<@e-kfO= 6b~D=-4l5]B%&ŨTex ThI*yUEu +TO-"9c 6)wDdFj, ?bC-X[SmMQ.J'kpˎ -2pfeϥt ;εN6s'pϖȽj个-RSQw*?ژZ%;uNa4uǵ*P%?M`zV%3aדyJtSl{k߃bb wJTn\8!5HP߮}@sy%.ٿ[7 oEeOm۹efC+-6 ng̝A{ַPDo+x(4;x3qi/|~&t5\|mWS38.%ne1UAdEoV|3LݽHmNrǞ^&tN[ϪA٭~EqޒxzPw`to E4BrD\3OpJ˥ݣE6fe?;[=)R{*(7`R# >~J׭s OgLY:SHKQԾUFڃFuvleHmҎTg' O >~q֌xل$lq@~PS@l͔`9?q,1ȴ-m,mq6˘n[8ȞWӕOv2f[gʸBnqOٝ`GS&p+Zm斑<4sO&'tVS9lҽ\)lk\l=`dھ1aeeղ*ୁm=4 l<;B?{R%.^]@MCx hv3D[In[Bd֟+W_lʹLyԞO?$[6';ْinTvz!N/Nt*qAuΤ/Vrז V9Ue,bֹr6Np]8AꇡjqmekqdU_/ٱs j\4p7[q.$q?әm x@`yx̝l;XPP cwޙ#ApSiʌ4*A; Zj/b͑fqLE,v0r1YmɦḤ}q*5eaE_ZchK*acGAoNI&4bdzYr[ۭ1|>W0'YPUB|wH%/ܖXER轼mefV г~aj}?_|b iv.d>E JaxV`rբu7dpC[|v=[t$ʁWaA.B q~Q@2~8owLhP8 &keYD]GQl;\g@9`a\0߮_2ʖ{UwGI)3 H==5$6sHėpBh a zx`g `q(r;<˹VO'Dr{,Ƙ-QX:VED{f:uIn*y>>Fc&(̝d.'xf9Y߁+Gap[ʜ;y'h hFzatpkmDZt3 $:(DXRRmF{ EzrabU0eOn{}'0:@9[Le _iTBswDI-ihRwxJ C/ۓ[5 %Ǣ|2s2?fQYNLbqVȶ謅z:i', s*o;mW3:g.Ơ鉭E!a.i6, Hb옾PQSFfelVܶxۖ4[`m rjVM 85I x˪iw׆*w* xƅgDkMK ,tA_5G !4:W8d;$Z${KґZ+˒v_q;f-MFK@,!RBa *:sAB ~b嶢WK_9fP@g9|w<&K m߰߭M >DjЭH$=LĠDYh] K} ˃мh>1BJЪ,9d=Qmn^:)rWvRWqY"~bDR)ȑks'Q ;}cۈl@MeLKD^gKiϥ(TCjE_z.4l' GfDaCVV_X)H!kK8J{[A&Qtd#+ߑ ;xBo"S 4'U 3R5 TkTp~% J^>@Ҟv /8}dvUQZKbe>@"JzLUo!Z :KkV'!_PB֩?܏6z ޑˈhOց<Ƕ_ Hp3yθB- J~k0g_h@NUwj+Zb9==(NqxRЦÇax GOk>QG]l5GI,ꘖCN՞LK)|͎g :JX8O X;n _w;NOPG$q`+-,Q;d !9)ꌶPҐъYE߱(R wZ evw(fQ?l92 *\ir$rU+Uͭ7z?Oa~="<j *3bHPn"em⺉v}tNGYIَ_*`rI~=6:7

K9 B , J tz# P'G ՟4{{X;@ѓy= 㜽\I)}Aq*(wݓ6 .kȃkI`%S }6qB?׶2Uߣl. \HܥStv5;0y@Ƣp#,gC:F%F5U ”ka|q ޝ`lT }弪 Ie9Vo=e"Y#9Z ?S m*kTMW\/q=s};uu9ک dU!e| Oq~¡Ʉmw(SZħ#~jً|d"l`i>`"B^wžPybPXa,}bd[@TdlmIYd7( _ JXH@f {GC(0,dCGR>wZ*阏)ߞyBl7m_8n\Uo+\` 5CrGbѾlkt.9HKNJaOE˱*#EݐPzA; +.d>';cd+<X Y*i,v2BSU$ϵvTLlR27i% u5JR],e<ʉ΃&Mh̃˱[CF!QXCWb|Ra?f19&u{hRZ 8ޛe֐ѝdr@lldδs/ɤ2 8…>Ѿ x#Jfp1 ;3o a3ڍNQJ }E )7.I ;NZ!ԙdh|Xo`_3DϮ[)S*Gf(\C荁@+C\s߁ 8]}0ާ(+1=i4~=kryk);ȞbB+r9 ;*qT`Ҍ;%L_E'>5Kӻх0L85!{\Li 7J$A>7 ])n s̀Q{\0M%K<1Y {c5ab;6>1ƛ 7<* t`jt H6v9 .e8U X^H4C}e0rQc=tdTNt`c~:=ӈ‘lF>ˋm"ǃ1/ɓ"#۷wSuV ̒RrmT {@V|. SR y׳$IX&ys>k\/c-}q7HP]$Fy{0kU'(ǯE%ɳۦiڥrE4^>-Es)s.&F[ D۴pH';팒qH4ZZ^ wd ݋8 nqp93׋rچ U2 , ݫ'w0wP(}ON֪#ƾJGBCF^{і3Rc_Hi4vt*9@VW|- ׯTrj&n*+s*8$^wy{0Wypr]cyu ZSMd dᐏuj}=Xs 6'pɖ]:h2lmKivn*Ayr 0|+icTc2*x1ue*zwdݬI/Qޒ]» BKt֍Ƌ#JR/X((;4iG$)!6XmrOԽ\R\8 .%{ksOXODzqfئ^`=[7չj@+ t룶8M/dž?kzZЃNzxg uz< Υ$[OT}16hMX+ r'\ wSB(7U3jON e0* T7⣉H+~utQ2X>f52rg&]ՙ< Vt28b֋`^Tlv/jg(48e —)յԨk+QegZ(TR ^ 'K GX%zy1:\Q|pw%ݘNK_sc yŤJ3qG0>V-:n0OOMH4-#"Ãzcub*i:8kbS7o>Yq2&ЩX mU1B#dلZ19PHUp$Tvai XkZr&#LD$#uH.,ve\-H+>{iXL?1~viX&kE4-db_vNrd \" O1e+zj W2u7#uwM$¨LǴq(Cdnđ<1i݌vp⳦/hMԋ煡{,#_9>MOܚו!b ǮѪj4;^AKR:d\͵TH`+89#ŠZ\*;0 dѴ$AeuCy3cq""{‹ jO#yErhГ՘5Kǘ|Dd2<uLd!^ P+ -{(4 WXH7R D>I_|@2Z2wpA tHl2ଟh+N%R^>57!K6&L!U4RrVv 4]`Lهd"$N7E} ymEc +. 1rMNBK_RWA ֶ`=~9c [j#yD8^98u '}σZDŴCqRF=8>w 9aPmp+5-p:,D.M?sJXDᔊrdUqҩՑHInK9Q>mb ]פ<~nVQ2|(𒠼Tr#C!8o|hSV9\}] o5n`5!;Lcώ'9Jk`F%F}GO7uZ5_bF!|3u8-o:I7^6]QI}ngksPϜX7%0<04ɊskkZ9^p>W*z)+i5| [:U4d7O$$(?$-t֒v{:c(6&H˗4h_ I WX,)Eaw <GI'LD {HR@7%30lycG A 8pnf/vPlѡ%_b%#4s46;WWXziFwqLՙ$9Ign²j@cdu#rZK /pG rĘs 8ՕGfUGbR+Z8ŽCFcaBC]$J߸hW8-̉zɛHRl]c!o6C7f9! CNFTwi7uMϹȣfێzW3*F6e?}\8QFt0 ]R Ffn=,\\Z ƣڲT(6XWWhų̔w[Itt< e65Xpo+iԉ5ՍŤ8L*iŢMVsѷsJ>:P~,xdDE'JDJҳMF+sAWfX2\48MQa'-R;`4òTOC>BU*blQÐk 4nlоl=P f7XxFt-b Гd+kI=kis˭'#|C]'ylDAnKD2?{\4| ~" l|2`,a?tWRo%%j~IkANsD ks%c3󲑁-0'qzyŻuVM86(&)i]d!e\鼽*2øMxUUOmC.5]@:-9ob*Mc29i)p5!t?s=aaxm&bZr+E 3I [5 H4=[ 0a򤲘x3w~ؒkL5S+?B/`wBfzn+ `N)Djm$"LЈtqF,}pf{2Jqg%}1?5M)#&7:4Fؘuo@n 'Wzt#Fkı-`_'LWmY oʐHu?ɐE;Xqʦі6l(ΏM{3e AܹDG.$-9/iN\IkcP zpo_\u+͔ҶN]`dTNNk {Q]&m™}<9kdrN<35;yx{9 RK҉uhF ''e\ꜲU+Lq MN:"xB5Zd\"/X8_&_~׿ H`vc;L]㳍M8u>e|sj%E=ɗr=pxZ'AYt=1i4~fRɠNHر#Kh6)3u )\ၔ` W1d ""%Ž λ#bVWK{nvaZ}J~-*r}jH17I̴:R ?5W^܋$(c0G9SXSbRg+ۼzn'x`94RpI}+u $ӊG~  +'FrQ(=s~|#x4h&k_4lkseIʼn]N@A2}&T Ʃ 8yf&6YZwE__27󽷀ֿv.|u=92Տ^ct'910=Qڑ g!$$Dig^@Cې(* XӒ8%Lm7x ?~ۂzg+bb% j_iF!WX)8ؑ3ĹRʤ@ExQCc{n[䙶OP\p0qmaxH4&Ԟsහ0/c(͵bFqSc$YVsc0j_d`5$DIjhӌ1.dyŞ,(vutFsqMPV¼L;UMP~"uVKipw&+[^9%u u˙D;I=絜l1$)'l<6&KV8NaZ'8sBŠu˥ [B='h|¿ۃf4psL T FOKmDEmҨwM0O`m6Q$_W.*)B]3[nF"ڡ%dSQ|HT0Qh2ZGw}R&`v?}^9}g$)@A AD/Jf*F4n3r֛Xvna'5 Wo|(ms5s4F#H$y,AM]SW׶ L1ƕh~7&!Uc(7{F`=x2%$PAƏk%=-&䮜(F_e`ʘUMWu͗B ײ_ C +qD87 ţƛ 7ȼ)BgrM7<%QXZ:1-;*VŰN)) c9 z -99׸UQo ܰFZ2N:@٣-u; HRGz'3EVE.O! Kb:Qc~HٓYF W2}#OrOf=9|>)t!}g shDƏ&H-@.G"< _KfȂ_KT e{ˎ1G\5&eCz6fGM{^'daIJ;O26VbY,kR1CnprAœdO":`cF!+\&b&A<(JH V,d=O;+0dir~1nm[,+y`KѠQ|H rǹ@}tlzKU"[n7fLOǞQg i=v<;;@ >UFq f>P&1qZۿ~/6I8VoPS1 +ie~b~qe~8y7h禆Gf_׼}& bw(l&F#uk<UdO%}ڐvLU:+ 2tHph-;1Fd!7Z;d+նb7Y*$W=Dˎ8FR>B2ȼJ:nbXGSҴya*D!J-,iӖ-%xysaMْOD~%tbBCY\hqaWQ;dn/fd?B*-ۄ0l!PP3]3P#HcbpjHS1OC馨\yȏTM}Iu_7L F4 ~ G!Ώ_E {;[ g})uSfެyr/#Xa6F [5v>&c-|HZTnk_^8/f\"u8qGW;hΝUQNo$g cK敦mJaF{2i"fԲm. Vsw1pCzb(5y[H캙g'8ek3DLO)ns JԠ;Q{퉬-b@DRuhY&&ty^[-5䎸gڞl &"D#8:<;H5`7{vw籇0lEM+C89w#U\@1HA6s*|UݛĈȃ\ql0~e/ky޳ ;>F㭓\R=~]Y_Out)"O:׈¹3n8p;FrQt1<Z_d=pnsߢAԇ[CA8΅Il6D8 {bGj %4c7.qF4oS&Ynʲ>JãB֞us+vls@Tsr6|ZmGD8O^;6[YX?bmwrmMVcgz~큉Ll-Ќ25Ĉzb) @&0F@jőTmALS-3P#T" MJ!녷LW mɉ.tedc:piPX6qr:!"FicP$C%K)+W/3:6)oC K.'xկwxk-1V{(/L~^͛Až8"^e uC*:@u4N'#Nom"WUVn,i).5gS %vڮ2]T !똎ԁΗz:-p6M7pdm +8ƼXkWkĚ3q婇+Άhd{1@Hts.s|s@Yݵ%b|iWl7?!˒[ͫ6ֈ:f.u(t*`ZMAΧ苂STh *i- 1e>0A_ЉU5K_%8@R@_Ga;}Q29 bY3ca%gcVBR-If^zr+%nPc$(mn`9CI8e:׋ y JLSNPcKey xNR;0 snnFehX՗yM]iTmD"kA2aZp޴AjwNfOǤL' r}RɌvހNkDIյWe2VV~wı1n7UckY*LQFtLr1FhǥLo"ZǠB"[o 2!xmZδظ 0X-.A56ҁ}HIc'n2 lH qLN/A,CԌx"YX{;3(x睓=s"5XrԧKÀ+m2%0媤=rdޘ;oWYt{+ZҘK.UzA㲋OeRe!C?-b8l:D%iprELptjH&jb[Ag(p@DGȘWBظ֩"a,[1 8/1'vTeRA|Q( j#92ZX \UX2*"1l)]\ĉC7].e鼌4xmĚ>E{C 1k`99Sͧ~ۙ.<cK!AzҴ…xɠ \t$H~J o~{z>L,/ysvn'Z1R e{/2c9oz66lWQSV"}^:SK(jwb& "m%K4Zt H"t ,sH}29$`M Jr?A #Q}e!ΉE8[Ȩdc&{Ybs/ѶkMvchUpJ̲a[uI(j[cݴJ(3BbK`@V*_wM4Qy*@9Nሃ̸ cg q(R#69ը‿~ GGIbig!:.qS[Uz0GFehK2z7Tv3qX-m8rĭNϋBTFFx".IPuŸ̤F씝D='ktu}CMޑϱB:QrrnSb_Sb1^q]t\e6,Z8?#גxX-QY# ,~I6`Hbych4LLWz:ھ&@z8b;юm$ek}lDLeYCa@+;5,%yW:J$Hۀ}翾󯿿ooʤcΈPeq-VBPou;y4IJ$[U|Z,Ή\؍&s8X ZI7P brf2edsv*Ydם5X?W+*\_l3MgvuƊ#5C+Be})FgA8"z~&ѷxؚ{cC90G=qH(;;Vwn>9KeI&M~ ˋճ&޺sA扡/$Hԑ\7 r̐Vn/OԧYcL[`E 53?2^9bPc*,ecn0ծd<^{޺HMcf-_cKS BGܒ^:]DϹG;%9CTȮ>SΖؚ]J|jp9RTeT\ZtRGE]Ql$@]'~١`Db4:=A[:'MM(ogVe̵m Xp! I&n'Z ;Q]fz >u"#`\9s !}#'J$c$F]Nk˪>|(6/O4HV2ÚVPh wQq Jfq)5ܾ1A$Ntl@qTvYyb fM FrP2f0Pe ^oo>!F"5sHݯ4$,[FT%GdH'OؽfN'2fnqP㙛l;nSЈϒ5GveF7U,EJ0M0Xqn tING`glG4MB!ce3Gg|Nɐi&nڮ Ah BMD;:ZBQE B8Zed}rl1a Q-$+p㻁v(ŜԭcOT 39<\g^^9֍BNX A=q{֪?ØVZ%cEׂ%(#gpPK(.TVkg\ۉ跉ۀX'~FqĂ1{£E@v1Ze{ihNtbCm}T$aJus}O$4=Li%%wE"M̶DI$+%玀ղgg\ʅa]h|2'䇺sũEZB@\κnֿ!p)[]wWKȫ6~=,s_a'bt~$+\ };nଃWz@?0qzRSnw"RC&8V*XJ9oǗs$P[K[oTFU TZE7WFcIfu)CewTmxƘ*Є0%C /=2qΪAEoҟOn&iĹË+WG/%S>}P\Зk2Պu;{(u˾ L͉ o:أϼsr)nq!X΃$DK*8~זD+.T5荙_U"pbĎn bSa cwTM`T^D%~^.|o:dB3H77 d&=dxVw)___ T j> ~/ BEݙZ^;>.xʒ ak>Z%5_}Δt^41#CMzD89/3eD;V=ϘVsq?2`P%ztf.zgKO  oI%Ņ(r%aJ4(I97ק?hOWntu=>uSFj3 x*UWe)"91#Pbzg|ؠ'>`s>Ҡ >3C,vGUr'9N;XeƤ08U*ύTT?h(+Л̖]+bZ|>SxTLZqQ^ [%ӲXsx{SK<ظ=+8}4ΠV(d8GDKꕾ9$+Ź#!X GAx\~n&Xf;oMg´+i`l쪝~[ Z#S݀;+QE!9f;8GܩxKqGPaJs-1s&k垵N4J65ZanzSa2n\IlsdԊ`qfB;DIX`L9(J&Dh>Ǝ_ɀL2* 概Rwidb|"Lo7o: x,2}¤@D7E1t>aWVf&{2-Kg\ 2 cȜ裲] !,,Y}L*-uqo7mE1\cRyq M콤 !Y `2WЁu6Z'-\T26Qǃ%8;\T?X… g|W0jJh.QÏ<nB2#S7F0s )tIb+Ԗ}/gD~.F]}@DddZv}=L1Ѱ^'yys.L$Gc튃ay$0mv^FFklQnOk~γZP}& Ek hWBRX5E8χM=OE'4˓ZD "a\I) Q9? ?dRB ${BU@?&n$YZ+]Ͱ9*Ys9f0!owCmØ^H`V2D6kE j1㭛LlxǡmBs'pqM}|rIU0SwAZO1X"F-{ү!0&մ9-Đ,/SvepPc8gf'uuq)-}Tϛ L#h OUTs^3C!W g[WkX*Kv:hP'۴|dB#+Kșiwvj b 'A<2p/H\?xL)ZXϵ>mks ;ft%ĭbNYWLu3 +H*03y㰦^3ӄ\[S)OaVVS5hx Za߇x'ޞvx2>'#X{$Q6\&0{.M5C Զ(mT7ރ?olKH|Rlbũ)_Xɚ=Ka$ +f]b3똁c=/q zS tXa0I1\aUUQ5W7 & 'I)A5 L"48e;us,7qe Qf<Ձ&S&cn[WR$VWwɓ6ܴX)pۇ(_)ynFrdɬi`[4zdIWT2E5`qplrMuq+BI3MItiFug~ nn~Uc/} ;u}rCi-d$3#F{A+ۗ!hX#.{;N!dة2G^$]-&%Q #O1(_4 knihB-"Ǝ 3SL~<֎ ڬ558(Y0*T-rvKlwDqpϿׯZq]t@t h5҇Qy:ɎqW8AdCq /*Ɗ"NI'a:ELAƀ7f_IW׭d5T.nm|6~3+H[Dt& d\ ,\)-68Gj64"CO$DTՉ%N[vidF_ C 14&ySþ8F%U5=3/ $ӝ&ʳ<_TG. Li52הbwr!#g.y>@p.èph)vQ&\ԛsiCˍ2_1,u%J!Vx1*IKWa ~ܯ>Wܑ[z'D[I;6I ^(Du ?X)V9_QJ9?oχoq< |ۂat7)g@UΞE=/ pi3ڄ%pnxbْR)*MrSz.#ݣ8o:nGԷ0%㻉 'C|D9s#X ƹ9`\(V|G.y"t]{5fRȠ ݆zd(Oż~8 Ta#ݼ a5ˡO M:&i&_CWo^VzN4r3ݭ.9dkŁ^^58ZQś|Q+4TlI M}XV^` p(Gzf~BH'J"* 03NMqaT7a`4H$]KSVvM?aTGyLROy)`1DdF^Wm0auc 4~Жm8Gs`D(S^9{J4Gؖĝ^\z1+@Ʊp0( E푫' Rܷ7Nw0@J,Ck#ʤ[07#lG쳓5un{U0#0Y! ֿ$ay@`Tޖ>jA.[u5;ϩuWP^kаC+ m/EH5I3-&|.4U3;W ծӑs茤N !b$+Ӽ 9QW4PO1(2m{j2Vd>mX N SoI8\*ؘ˙!PU"Sck@f%Ms&E`R8k !N2MCztƒ20cṯJg&Q(Iz ;>.Fǐ'[ۃ(VK1'~˷}(巎IlGLi(<FGFʨRBԱl|vr_ןgNMdY3VzA:ҶTBēoc՚`Tϼ+S?x @GTD*+ Kdgu$OM[:4_T+uu+|߱Ǜswk 2tPҩV'rެ1'z1m#zĞ[^At嘎8*˄+ٝt(I&n qyFkHux/SMNVyE>[^$F'';>i}mpFmomQH$]Hn^MdH!I, 3BmNmuBz ]о7uLTn9M'U0Me8?́WO^'^ꦣ49q\s>Eauy]F%ylr V9>O !iG1})A2~e0nMbp-9-)r]_8ZD" ơKDkT3UU>B%J@.K+m>%/&ruY1fMIeT#])^8H4%R" u}'( @ORh+J[ bn X.Z^ JYHq[)xhB1O섢q bChtgR;ԑeEܐB zз<8/iIrI-;@HYP5a 9t*h/ J{N2V< /Ķ40hr{;bKI )N%h(ƹMLjj|tً*/bPOyB6lSԲ ?~6'1t!Aʩ* ߾ c0E^uPIajzEbxΨP!M:[Y㣃̟;U vxrC"ߕ*Cy_@`lcJeazzeO:]9ClےsM;QG%3<8^&ՋJu_ d¦óx_F5-2Wi&;-/$Pۑ]ꓝؖ$Ud$KX I+pxH ؇-?~j&'V69FK&cΛwl#4~bL)ZBM; jGğ*IID~*z6QXTH5\ví`A!H$>$ҍDFyB`̯SLqθcNէ2T0zQaר|-`C'mq8j]G`Ԑa.KcZ ĉjg^0kQ8wY]_ lV)[C?݄cXKq N," ƈxRUճ QlO"'c~QbSS:. xlMӤ6*pPU"k1r^9Oc-= $Yq3َmd^!A1ue.]qœc&׵#fg@D, >uYrS'3-UuP\$kwȴbt"y7S:h@4r&,(hR:NVdrg  IaO$'bp_yyObkqlfѯagDw8D$w7ԧ7yom4Wgx| #PNtcӎeo"iW_t*τqsO ѫL.o53r^,WS᪫e;_jn+}'RG9rm͘V}p&yYp4-Iux(7lC8:Ùj#c,ߖ]N5&ұ*݊yI*1jx5NZ/;,V< PMve|*p5׺Լ3/4z$Qn[ea?Hkox5(og\$;c9fi|~l`9Q*d *+3↻}TEQ8qg'b8(Jz̕%qC4-~7pJdśD1^'c %O[g$Ē>fReq\q3':w~P|~0G޼p)E_X;LxgYWx]q> uԞ9Lv|~jT>M](p}ֳ-C 1bk4v,.'.CҶaћ`lC(w924{_鏊3N< иRi'Qp"e.8A\IJ9h3y^R39;w?uJFMݝ3d>kzB»ccU=km8E:&`Ӿ.FS#2nm:{x|djȸfh 氷PEv "K6#E뮝2s R&ve=%<˸XO6)AJd_FnT.G~eeZJQ>J>ahw 2,OEJ`ثeג+*úE<-l\n/)xP8Y "578Sg8t|iQ(9vZNvQFƎl.[j < J 9|q w_ ]P ]&m'Z vq۵r3CZi 98:ƓNv.\oE(DgcL;j%ܙ)' [ =bsYȿ]|'a kWS}OP{RYq|B*Lݎ|_}ݽb5%s87$DQG6P}[h%[V/P RPJpf>V08_.Ho߉o=Y F<ɏ(ǐN4׮Xh]dr̜)^]bl^*Uh~?Zb6"leuDoTT^fcЏ}&}>ikWWn^e\4Jq#˰ ESghv9ı! $56֕r}]QunM?k;n[kuSh?W;Nbܷ+cͥ^5wsqll^}KYq4je8 I \;R7~y7fyƅµSˏ7=UvC!L ]byMxbk+I ^=病MűJ 79Ywg45EO9l/ls5؎P q`׬";d^{M ]LF^wΣ ҐBHT3V(:Mq:MZE>&궞k3ZuNb@(g|L ,0ز l;I%͖wz*OYGԓog|b^  [e#if0? _ GFC~Jp΅*  yIQy$o@Vn!ue$`l#\Y3t֖l*[A;CM+pk>_7yUU1L?Wv&b!ЗƊ rCRzǢR0ք)uaX$Rߠ6Nm-h3$ֵcJd9 ǘpZSYȂ5e>)8vQ$GOS!荒vb >=_k;A8n4M64ςs?g=!{JghXD!hM1fr(W{͞tT)攑yVP؄}^>Dޖ\[k|"V9;PZ1=Re];9^HcE2+KW=<^?ba̅0./߿=(y"?n.$%q'`%τ 6Izz/Ju߭zP,!ϘlS<09xЎa3 ꅄ}50uєIyEZlS 1Ǐ3I=2 XS/[s 3:=;LĦ>lb tu`a#Wp" #4PP xMߘi`AԤ97;X@v>Kp U./3 e{]gg{䩻[(mG|*ħ'ܥBliT&Ӧ{(N'%~@v(ۯ/0ox28B. 21\&k$]LrwwKf&l*N{0at3s_&d"Y`w&HP:՛\&#efwa@P%;3b=6ᜉ0YUiFwN VBMûqJy@x;]NqIҷTk\U%ee5>l]^1>}ge|2ILJʳs~;|_a86&y%Y`E g0.j S.HEHͤ{ST̩ŗq7󓈣@?Bаק!l\i#=H޽nf9z IZ?8sڦ Q⊾8h&1Ꙛ%r0HDQ,Kw+t w'#r5;(ũ0?LT)MFv.ӊۑwQwbd3+4qcl:;7mkz) toGLk.sB-o0={YؒxCptDsUH=kO0IOE)GU^N97s=Ñ*uHn )OnFmתrgi9"Y]K;[=tܲ4Є:a$d[FK..ׅcLHBl̮-OEQ$l+%k/S^/;՘Wq&X-?߅~O lv/QՓst7>9oo^Y-̛IuYlҶfo3ic _ ,iqp3H\LmS( Q?7zD2?NQ{G*FHS$wYإ\m Hh**˹H;mHO s?2tL1p۫uŮ."rnן8n+RDt O+-#/|~'&֡FWU/GaC)س `_|QArQQ\ +1YILihN-W y/TIҽ[˛!C. %lq) ;tۺpU$Ѱ-wg qp)?,)ISKy PBJI <9 eԙM|\J^wFj6\}we> ?Or> TǑ!dνE5kר*TϟZ)1d{#]YcX@g۶[+(D'Qp xM܌hO==zUM;pGݳ`nB3SO<3¾NbQl 7rT;0eF3ɛA0{kq~cW4ЈjAi!=_LjiE'(dGf3%u :nSq4˦iX喓˲URPEQ5+Z8NJ^ڭ ߙ\ "4yѦ/(Ks21K8>7 jؖ^xO8VE*JG>>WeAe*4Ebx00:!)4#{ǽI#.-FG=lKw;ǾGj &Ա9;NheҮJ_|_ V,拏.QSGZ%bqjBrAaw 8 "Z\Ρ[I:FA%ADlt0t#fDŽlBn>0Yp=fшhȗ{xv[*ҧ8 < %)f5Dd:i,Kn)W_4hȋByD䗇..ۍ &51vwc5'%5F'+c`D,%IP\pO^H~|T 瘌uFiX +T=Y1+$Y9IPE = ~ign-s[ Aw)Dm4ͭSPs" [?S4V/<HȕW bߎ5`$5l~_?~__~⃱7OD^ϣ▻ K"2\ ;(PС"RcDmcdORM*a .-(\dSJ$T'\K[EY69v< ]>6q:GCr__ ?UEC$Eq>|.wEtTCJf)t_wæf(KF%θrGR!-pv ^b0s.\H̊w w#'xC-eLІ @PI[9^Q5ԩdlE/1sBkU1 q;v(cQ{U l9$wp(K`$~S) @HGP;hQ uCd(9%C? EpU/4oh֝̋J*2Qƛ1q <"H-]r&(?2σa<:i"e0aqvF;w*_ K! _q^w K}?4Gt{e@+WZ3VnJ٥D`k>Ϣ܌M54٩ &::1:)uE{F 5d bVVy$S}hyע t=u7F ܗ]b6g";Rhn*W_G^ERA?8'hB&@/H8 6B$?h*Vz}Wfav$;:,ЏFě&o0 iM8R`e"(5UO:tot_]RYދp+'s2k| Q2:ر#NR~,T.E Y\A@u?4I'VWD]$i* D[NoMVN;JdJSrKַ:s$fSEZ󻣬Ԓ)xhn޲;+D_ת%P0t 7`rg0V$K#;e 荾WaN?zFFoaX}+'^pPǘ `?:7uiUEQ3zbj6ex~q"/e(N^2$:ENʨ7#ÝCe ~GƠ!LzΪWfTql6B^ ƧWQ w+0D_ "#dP'ͳ*u.k w"4*ZѤj>1|FhN''~ M -c)ᛏ(顏+Cb وu&2Hډj2p#jZjhA;q2ֳNAQ:- й]̜j&E0}4uw|&LX"#qJʷTʨb7 ve|;!ӵzÁ$fٯ牜`8n)ZEɴblWm/^}w =FmPf~ "<}< vcՑD?@wfoMs[^H@އ[Iz,+iRÎ&O'/ʄwbS 7 ËUta$wR u?d 8*oܷeq{@'ɖxuRDžUB`0gQt3Ҝ )Myə!8nꌋ3Qc̥D@QJ*zl~4,N,dCy\Y)Zc=qwQ{t o'xg'Z 8YX:*ojw9#L;P?6,y\pND>}.vyTumdO$i*crcJh8T3-"CDo2Pb@-u9kEVʰQ'2#"Am_U DI07]aDΉ!t6$3t">+}2(S":H]T|M <Y!D(Χctl㒼FxaBbH6x0dh!U!Ԣ@ EhOqpLr~ rAj}+yjPQܟUp./&VP1EUFfcnsa.:Y5ىJ'o__ KUfԃ `; Pc|/hLRXTͭdꫤ# Fd;br$k>$w\#j"5{vI!uf`(hF3c7}^'ZYzfU](vNhػAaJ֣ g6fӒ 'FTj`73ymjɞV[ƧNYwk)#6޼eM^.XJqƷuĬhksr (HG<饉#pS,H # `j CWoU]L1MCqt_SP c=ΐX8u% yel"࣌@G lwlGsXaccT^̕HIzt#oG-=ЃϘzv]aC3$9O~}+limJk+`o2Q"́rSCeWgpfY'بÚr[2ĴQ (f aJH6^Z;I&̌F ]{dUΉ]*t81RCYG(GAf0ʵCv‰h50 'e O#7}<7D9HRh(n3^IhG؂{VWG,g9;.-Xdz5&Lmf)/+تzfS Otan$B$ʫqxRn ݣN*Zr #J9͞875^'m8H]c%}W-Y12u}ŨGeng,!SH:O=FLlz#F!ysoY!+pC426z\z4cFފC"Nߣobml[*SC0)^)މ:ڜ{ů@l>>F;Ik$^BsP#4"c'9@} DGX A&"5#1F&^"S橐rpŽNOO,!.JwaG+ZY{ZCPՈ>YSO=Д**(\kmw+i7̋>RűҙԩP4d8ؑϠ^-qɑ;$LX[Q3 jmս^I;}wtDV(Wm®V➦rsc Ȃmgt%yi[+5Z.Vi,%^Jci[]3h%Ѯ-e~;q9Hى'f6| 6ZYUQ֯§& Q]vݎغ&΢}< "sIJ>\g1zo*퐛Yg g"U/Bjs`z\ ; ׌}5显A2I;tn lL~tXvY|Qj5cAP+9|XjYx})`T/MAaY?$cK:ēSoa'J]@ad0GgiKGXWnGh_Es|cTˏt{عq~b/8#Mp˪ʫ2Qq}̫?FԜRAg$ًۦ{]hM'|)h/gzǟY+{HwDI)'$R~DF="5=xVXDA!zU;(t|T*XJjbًej \U]6W3Kh`^UY|9aN#R:M|aOiEF_m& 6bSuԆy` ˌuh**Sv%c='p<1PC}Tkp8e 1~53RIGmvbNv-Wj!o&>ys nʤ `ڙi_?㟕_%s[Myp 9VH&Y8!9N;lq/xFqύ }1z %pT+ ]P3NwLXhc 0 >bUH-Ýo!l^$k˜0֘LW'6(Dn" U67ݸFDب} dK@cjD58uwZclEqo:UB|'u} 1D@ZxF :4a$m&)&<()wTuĝ sL3?/|Dp3jOj;}J_aGנ5Ipz8/{LK/;C%t]$g*]d`[q0.Є[r/ݏxYTezt&zl"ԺžiX4@4RfIM2kdCnDDlx:OYz ryp<Z}XK!1#q`Rղ;Z9[l2dq8G0Yt/P- o0t~3TppDw 0gQY.# UR#m- x Ѧ-zIi? /E߽()\67AlKL Ugx։E.VQ X - 1'Q"3MBuw:I\<f>-@Sv,g2ehXkGP3B&[m$ΤuESvzs>'Rk}$'ʢ,?Wp3rCAen)FTCXk:Ib 8%k1R-M9C'#YoPgM^?9.3tjXaA$sN8ʾ;UYUg} .A'0|xxǣQklqlxcv6@~77@saU!xg "n=r^#PMۢs mcE Fy(H;ΣNr¡aJa0ZL(-A?DBЂ$Ѭݮ/9 |!]e>pHP?b6^킕!1g įIEL]\\%.JԿߥ@1d=گmIKBuSz6w+`=8PL/R=l9ػDq=d(ަy$l:M<*Hb昸$ōTj.ݩ\Ȓ"zjàocP| = \azI0$O;᪝Ȕ#(PPۣvtUwc'mS#\g8ELۥ%oa}~*-`yUۮ.tL%wˤݍI, I=IOv%?V El[P'-"\B]g;;Ǯd}Z2[wr ]%K$A?1 |  [۬b_~;\}߽mί"\֎1Ci+v76'$3c$ X2G7]Ϭ0)::: *5?!]$Iu%JZmLYh8<ܽnݖJ*"SNhoj>l  f*_ JVݣ$8Jqu%58@gY' )t ;I2ΈY%Q([CQeG Ō[O|LUN/iX;xWK&GۏIΏzp6g}SڤD0Dg?"&H+gb79~"{K::[_SlvWWԁUzEcyX1'4b@tݦF.i2kidS8WSzSf,GdIҴYI-$j:91YB VF2&'%ɩ/)6Z ]p)%BKeq=sv<2n.]zB)$C~6Os85ÆQa[!4r27 _=6tQ𪓦P„pm"~`7eGt(6D6dVrdz=]JYx8U&M(C̾g1+J"_;Q;M ! j9#(E WP7M U]Гrz@OFmZ?hI վ)vX 24bw|'֭lZ+isHvzó4;D@bj83LI}1>;5 gC+Ks|zFj bT-Iizs,Q1OzNBko8۬';Vï9J?J!D9\ED``&wNH9TT6҇S-io(ӯ!_d6 }1u%ϸŎ)Ucm0@M (8!:@Q!D;> )L*xgN-JA..G:thK$pRvtB!ʝy ނEk=PIa{h5S0S%|}^9bC/pdstX7> R?a4 ֲ%>Oו|5cxU_wr,hy=4ff4g8ӉB?"++ȡki:{/G*")dSG=}=D̋l!ΓئRg5n?1,w>@ktf/}h^1XNt^e4c+V0Cɲg@LR,wo胳NrY xU;jIhxkUKKߚ+&Өm&<C? ڛ>ۨ =ys#G ۓּ`Qٞ'MRq zK8+XU51}8^5hprXkۖNJʩihwmt\!Ʋ:=6o{{`-ZaKڼ"Xv1ό(tHk2ف\'uMPgg!걌9z-CĹA8UjP@dl7\M7OIYƶB eOwb=]W$@Ca.‰^İgYNrB%e?8L)')<*wniϣ(zJ40k"21fhxvp;1$cL`.3 tSh7z3AoxI,2[") 1eVf{g51lzd%05b,N]/Lۊ 4_k/'I(j48#j7,|ƻnW@ ^(XJB`ύ&L(GglwmXZB6p524o*O$D+x9 NW"c]"kPTdW#ASoRD9׹z֌l=9xk=Ec;ZYP8,P̎[Őh];iC>2,]x`N%G jbÄB _-{z}bV3Ir < Ő&dn'Ff!g w3uM ٔk&KFҼ{zϸ U'Q.1'M~G5ݮ ef]-(=+VC<#2~$XHIQ-wgF  $Hk.,QS̕pXA r[y#q^it1 J4ahu$4]VGH ެ'D OU t_#,E! uۢȽ.aJyDe oaYqHWOTɔ^VG6GiJIr+䂡cfƶSE(ZZ|&hIMR·g#tTŦrPKbX-!i+Շ("m;A!j `'Č.M?~V$ʮ=GHNnWPO_x5ZJ ӫ`M&Oӳ,O6% QJ߸kXj'jvߢf dQ~/h@iPv>5rƚ~qfeBQ!Aqsyz EKAfh!floa) O w[7Fwm/'TC :Q"9,<]=y0esb8SpKfhJ6=5dujcn4Ώa-nqF&(E&,ѧΝ7+i6znU\e/萳!Bdʼn`KIop+*->@c Ydgڂ'Ⴡ ز29U/X:? (zXE HJ4AR4*2a,5;3)yjٕGx*L|C4cSߍt6l3"s6{ly}КO+B,k 8Ieˌ-7l_щv"ѸWֳr0^ 3 {96uǷH-U\U@[ԍ@w*-YabgT\pz*7KO}){ɻd[0uQm\7gwԼȨȻ ٱ33Dg3au4 `X)g~] U#HIY ZUAZC>|Z2 %@ΎvӏlfόG!M mU-@W@*1PІESӅL7@/ v8p햀YFng͊gc,A[PKBtNgly,y'O]߶#-ƀ(I/+Mvc` X6$"ˠ]6 k0)Qep`>x^w0;m3 Ηx-< SU]Lwj {0=,o-AE"]r? ~s fYIN?c 9kv-R'[K +%+WT&Í&@ BDnjH3ZeXD#pZs]^c!13TVGUbN] Jve`4ũ4 hV.H9nlF0 ߹BIdqbB"Jx%F瑺^ZŋT*79qXKYI7on7SiGH0t8O`gPyd|'rbK7MhQkUƩӊU ́~65:3xބ:e%ZM 0ݛ+cSnmhJ %-JaL4+{,<\#ziNBb$LDZ7pT"US9!3M@bp3? V9?GGz:Ш㡡@O`ET: WS/>,IwvA൉K PbvO@<"@|tc xPh8[<5_[43]JGxLS#/#kPMb@/i 5Kfٸ"JO:A{Y|gL $ٝmiɺ5^fw|JS^oK&߫Ep-*Z/DŭC5#ʊ2~M<З<_ܐ o~6 ~) ː9\lˑLy9m|F6OL QjPJQ15zVD.5c maQl"'kΒQv4|oD|,H?$hn9:'|eLDx} w(JQjuC9p'}"a\n<H gI(sؔ ̝d'Rx5A{u~(}<]h 7XЏu﬎3^P:Ɵ?LDWN΃~c*Xb–QUqٖuαUX)wDP[g:rUG&ɹ>qL;.+# e))'˿90|):ZnzscR FbK'j6Vx\=aI;~w-j5W"ġm Õ}`MxmnKwYe%#լ^RklOt\Y,MJڋT-:CchU4!R; C5,P9k?'0; 5ݞPw1wecwgLHydJ/:<'/:iƆ2Mrȳ$k;2뙑74V|Ti 9g6&nB }Nv*ld"sŔf"UmdQ4A飑4[#%cf%vffHTNrhB8!Fmbc6 cLdh`q31@:#:ڪ#+P}Kb,Hțx2?-KEh3ԭԮa$,dGBwZ*2h8DG5d3 P1(:p*OX@QbS.Ȣp5F=.4-9oǐѩt" tzHZfn:kt sW`r3k<Vn kDk^uޟ#ȈGCM(rA6MMC+;Rɚ|q,9\N%|:oo~__?~㷟z¬GM[(.9q7oJE¤{o#+'TnWao]۴F#VtG xˑ?9:n=%ᓌ9 lJ^zؤH 4VN˭ O3| p IC@7_؍0q2@x+fO3q _8® VjO򃽄T.dJZy\8?qkD]QȪ(TJL\XA}? q|AD{`: MW{6۴]ʴFK&6O_ng(5n#ZR-Ib'y'b88 p=@t*D{dOfsvxYF[:®ϰa3 )qTuf,ŭOCL@ڭ'q[(gfH 0.l(k:%fmΩЛ1z֗XӲ:vP[ph7+p'&Ud:!qt6kͬ a!֓)am(@h uy#[mĬ}[PJ ػpZ68 IR"Z8g O` ^#H UKHV[ 'R')2>O1@{4ъ2++X *4ANuLAB'jb'+ZNymxJnL<rIK,/DZN9gVښnsM*3_bBh*,)yN!E0Tw?/d=~SNe~!QnB(֝1cӤV2zhA'w'F1=&Yt~k. 4 G[̾\'w^gϐ2a6_ W./U~93'F oroyx>/_L8S?oS"b<x;o:jZW{v*ҭNocx>_]gg>~gO/Vz&%mdpN}?BZ cAҳs,z[îse.t%(*-&I0'g#ޔsKyz' )}SÝ5 {OӑzYޞT&.nwzH֡z(Oqzs!v#c9kIc5⨲ΓLX`abʰ!x/ >$fǯ58. 00ū,VQ!FVÛʂDy< .>K+bs Pj3;17D{lD7իC=e@Yϒ$trE< '*c#؆2^ضwq[4ocmZ&-zG1gg;gT+٩څ0ߺe\\ףfDj $,h "n=f-%X=[y=J 8qզ8N/zIc>j;P(jB??~_o?Nj{;-q~2`8Q+usdNN*d)p^b{Q2f X꺾QY.Nd&:q=,G ~O'Nr>է|6mIaV{tP7. M-p?Bh$. ) 06 2R- f|kXEIJq%xYRklcɘMz#G 2!&7c@$(:3 (A} 7ݩ xaNA8bsJmo׹;*W<YɗGtxU',b[L%NGOx{ [ͮC~]w_j%Ntڇ4r]ϣ>Nyw.-WrAqPM$~3> %8y*_Bf.T 3P\\3Ոp݀t45Uə g_$ uNqv ­1"xzȢj?F#o I`P*RN+R&Hg}T~hu- 1r.ޡ)y&,^Ev}=nq$e܂vM9O ˣ69jH0qInAD2dhCTJ-91_vcNHpD+PCrځek< %gVB`W1x^Vtp?&Â4urki;EWn_Ji4\8EUΉֿmoJ_"UI"/z8!"|$q!:߱Hk4KT’ydgB'ylj{Z".&pe^I8Y{ 4Lj5Ajـ`4^L$k)!)d,h+$GcڠpfјK6 >4;K6Juǭf.LQ]Ʃ5ԭ7q" 0\7fRCaUxIž0g}xQz @/ئrw3 UNty[&U’c )aR:c3la7r7ƫ-KԔW9VNUtn:Ewޑt]Rעè nq`꣛!q-S:Gh6Ys⺲Mf %V'}00Vk{b0U Ǹ$qr kN CfmZs⡐Z6Q)b Vj# j>O* b'(pePB:J aM'R*)/۪$O2Mt@n!ČM+E6r ] ?ڊCr F(I<ll:v蒜'X?D&Ly|˕*q"&y;` NK=He?Jեb43q.2.YAHQρ9JX $щQ$Djy Z`s@DLr"ӞWJPOVee4!PL+\e6viPp9@$k8LY$ԽւƵ,O!=iT4lCW#NI݊ ],pYB [ԙM"Zzr: H2UEsÎ~;4`+2~LbЊi7,!`9otϬkV i ^C;wz%L5!+eR¢ k(f\7 ~at 3]d"x NQ|ˎ2@.2GȁqO>~ ­=I'RBlS?I\棒xC]ap4{9;)>ˢe)hVVfgL.TԔ!C hB'nK+њNJwN;p+'?UW.ƕ%iT47w9m t Zrw`1nE:DsɞE2rD GlKpgCύ5lz|;a9xlղ{:bQgu"a+Fͦ&RZ?476YM)Vcj,JxI7{}HZM@߿.3+ed|T*3A՛B~->4WVg5&z`H.'[׏*1#1Dk<հ9 @cD]+4 Z=;g/g~|Z&*PF#}\hOgLG,,o7 r8{ǒ%(F`Zq5Ȱ?PCu|$.K|foN栕1P W,F78v)|1+ /.Bbh[PD~JT*ޛuDMd/xAY1]iw22I@23B8"AGxjnޢnfCS #ԣx67(Jg~f/>W#Z2auڤ(;Wd+bPk+g!=ܘ.07p=(0#]"bf Ю},`*%q+UsIc6;'%\W҄_˽Ev? S'pwFYx~I^!Ab!q b[h𵍬Q @lEо5v/dNXj (ԄnsHݮp?_M{kyVğZI*T~1Y7:e q< |?ן'&j?CHu[%Ğ[+[ALT<ϋv>2%t=d5>lׁ\qEyTZfJ64/s,gNokyC7W&$cXNM,Ab$ 9b O⻽3"F/#  Λ%Cw&w:K:?IutUQJC`c͆əaqHYF%kMrV%L1K\Y{H,A~!xCvζ) c$${EBr߿qR L)^+f{$a+}IH| fw$%XUnb#gy,O߼rk/ t3WדQțϛrVoWbG1Njeܤ6. ̔>#3\i!<)0C3Q\r%kF"lXӉY<#'+1wWXqLM2\n*oAVZ iN6]|?uB˧m7|]XlnNg"FZ \0Dб^^-Ks0JpaAaǂٴ"Y=H'S:B;&ϓ47D½5 pu4 5I+;1NtۉW5 |2s(taòƄ}&N5eƧ͢_#"Tʱao&q,9 HJ?X<@CݫC@*sg-KpxDp⎒b5Gf1z ʋd\PJX ~ m^Eb(LRVQ[r;"{YM8GJ);LUm o}k Gծ)n䂖D[Oj #bIHam!Αq\ƨX?f6>PǪ* ŖRf4ViDtY Y1'1q\; m^sYnXE8H Hx.'jWbݮf;^xBTPeveT]XՎY$Qc<<^lOE9F+u$g~]Ͳ*Ah>t1+# f_gJhM$ԁ2[o@=54ȕjIs9;- 64n7d=J-Sr NRJH'3ǘj(Q\Lt-ѳ-*4ayhy*#O u DVߏYT (%m 9߶R/zIy>,4M{k-)JyqOga6/hw["/[+wﲳO#!7)ʿؗTH5 3|r}z-7Jx"5:e~Ԩa5]2=_^iAPH(ɯP^T EjfT!v{y0"rA&3%( ^؇,׳i5Lgz^IS&㳿\RNtC}a8:6- ZUz[WT ׊,t$'=By*0RyDjzg1o%״(|NPt3cl*]~T.%3ZOPѴҺ1mj dࡎEre+u$~Lk 2CBѸ\hO@8` yR jeK6^a'&Ig'mU*G˅(e=(<ˆ m,ICGQ@9TgyDBd[@&G.WVe126U *RbJF#?-M- \A2'P2A^%BFT&;1Q >gB$Sbmlv_W-1{%P'! oJLmc:1kZFhT''Z&5Јq)aw߾I6V;3*7V_؞0Q^2lb9i#tz Ce&Z$ߨQ"\3?i%JF(NNn(8*yJ{X_6YO{DF?!59e֒ ؛J$fRŜ,2x(=@;%/hEFӹ$ei K!퇭DB1-u#؏ײZ M?;rm!\Q8k?}#֪кXgV 7x '{Nj>}!cYb[v(\;]hQI7[n3ƨdtCk :з[];a=UζQ41czچ}F2)e˾TY@Q~!>ء)13Mgj]״R8MG7BȎ>j<̃DyLO>´ZR66 6x5vM*0YV<{B ̦%2QO?^: tNi 2 i{9NvbpQ![QJGI/f/ fKhsUw\ ImʸFDJ|;!گ7e6k޹"1)ǍiZk.p觹ױ=W̝yc/&!_ SEЇUZoT<q?.lPT=rSW߰0E` uNuR+g_`; WXu'6%/Lec$Y$4̈E6Ш'ť> 0"PS$ˑ#=\ C>\)c|1H cӅaEIJ(tmò9[r7+2.\b;xl !+N ƍ_wCLKZw 5ol]t]g6Q[x̓Pmu-ʰ~QsV0Oi\T 3I0:`/~kR%mڊ{}=ғӑzύ=$tX%\oRfvo XM5c/m`#zs'˖x3E.Hb2HeZə"?wKܡ00yJph2ׁ]t=w&`1$EaRƃO%:Qo]'tɸX%(&jKDLSDA%0-xph0ZF UDvsHp>Kk&L?yf1 bQ }8mLL?H,ʌQ)-L{4Y+$HaDž$; }h#ӳ&N~lA .\P4 y7>#jOr/ԝh#ۯ#PHSƱpf:R\ԣt*Q@@C2i=@^sԾ&tœˍs QCd&Rql<$|ؐ՞-@3[>Mr{g{z&d}uʉb.7ɭ=,{SFNTNId6l%g *Js6qDQ\$5"Zvh* qSV`ϸ4_pT*CS uis}mN:,@sA-I#*jEݻ YBOgQ'Q v^j_AǸ7&Jyfr5 cxz㐄@{ma3q#HO&K [= ['E x>lWF>88`4ֆ>i>q`kp&Ek4, h)2,=nYx Ӽc,䥝iWWvfCoRBs Z=6,Fg_[#0jX޶D:t"pԤk,f~R{>/oFs7*w=mkG ֚#IPF#c?V](.bZyHc*#H Dv rlU&/X/v'wNܥM=Kz Y$vIe,1hJ|ze>.9`9>Qfo'37>'<]}ϛ3Vd1! žfJ ДOHpyN-{Oe:ds§5m2I91;Aj-Ec=>ʡ>Cy1l26fXt"giXMwϪ[ D҂Oֻ06)c8R2aα̖B_{%`h6[\^PH% eW 8$ t tJ-1T&{ wn#mÐ,|û~$%4 {ڴa\ "z7YYO+#keaFJt*UvC&$C&nv&I:BiY9Kļ'e5sJ]8/(5)3miA؊Http쓍+͛&^(|ZQQ#Z d72AOL-Aƙ-)A~ؔCc1m:+|O03͖>$&0X{V|L2:u&l NeCOrS qL;~Ѝ"NHpIRtIČٗMnI䈈äRd6tt>_gixfL)U( 81 jB fmg*2wqx2/9IynhNFu^*t5rLj9xN b&܆Ȉ$3N08q#!~Ӻ F`/Q ʨ **|VB)ߪ P+ c4hDRM`Fem~Ghҝgvwx]=ZnA3cJhQv0i%'W߭5J^ 9d[2r ŧCTYxwkB7<z)-Nr0nLlD?e @ 5uwp%~V$rXe WCDf[\BF >+bcC:FI} Ƃ|43,G@MqkԶ<;P IY1?o$#gʸJcrJ+ nQXaN(%/qH`)fvjġ JAe8jX(}dm!K~f_ՄI6S\iG2fN{#*\h-0%4mebF I: (hr={ѲVXꈀ%^PP<ѐzkq5AbvWEsM p1 2:OŖJnJ ?Uy Rbdhl" .~&tGVO//q@/UүiyNNE֥(@VL቗aF> <ڮ7Ĥ`G(ә{(^gxEFjcA"խ&C,1H>IlIfGѼVM_.CsL:]MG o.H',L܁ʝSWtތ$שbTqPJ2?QoM;&87_ n!Dz'c;`PH H'y@*^1!ϚdT= ؚ%zL,4C\'} cp4G2ajBD a _ZQ}P֊%2Hl =8%|ӹ)񢷝#T^[~fK[9Y_ p?^a %`ӛC\׎"kS;u aeYZ83=>2! a'azEb:0iW%<^O>?"zBfIPK330 c::5 "-kR 0a_J)fG ~,X ,r{m6ԙhel0T,yTj ANxr0T>hdybR@8J|G /?ys OFA gqPԬ,NZF2#/6Nm cc/V ư|e/\5&*+#|2Yฬ.F/u ݽn}:1]/WDVy=BWeB()!]T=˵27,1hX3naTD/޲>ȧygJ[=;@ -j@(#=  NQ('~\=jͿɓ((:3?݉&U0ܟdƨlg8 k,5r|L浤x5 {E1"XH1J@BE(_2D[v*.a-^< \'qV ZGAj{6s4~SK%cNg!qq`)g;-ɿ$J5cVl8E{sHpTYӟzQeKNwPP4gQ!evt𭋴$QAnZ͌c9oqfSpgMf*̘1=UvT T|f* uC"2D!KA>+7 ۑ `YX!L܏͆!4;֩|F3mt@ʠ pPFДg|s_{4#la£>[Q5FWՇ]T>0B;\CngeǁJ IҌ"=^քUu.D"I28[e;ݨ(&DK0{Nt"4BM=f%, hA!1s_;&~Ifvsfd]*_TVy Jcˑl>UՉ|bm{4oљȲy ʑ ;3/ތ$#"+!5FbB؏SB>Rf*d'l$Gtc18f,hIo~|/iM'2YRf:erMCU2 9kY[:oy/=Szdt O-!_ .:dŔm__ , '7HZpf-twÒ?mpqSdp#7B|9+!;Kk쫯ECD=ƎPjmM|s#[ M~A34Aw ?u5TM̭fp[!w3 Mh"b\+"gUP݇䠙6nu8W^YS*MMbda HR Uvny?֮bYh gYO=&TW_=TX4O\p -MuQ-x ڕL 8$sʁIB5&zXҳ'&Ћ J[Tɍ >TAi*$6~'Ō%|r`N{; 9hU/ WG#' :r8'&PSqݏDQ7ԙo?e +kQl`8O:?'=|~*_ζb l 4r $C#*yfĹQ˺3md90V  d$N[c,>7td³?oK;)wwV2U4Ucz\FHNc[3XP9vO$J#IX.L獉cqef5OwۅuGI=eyR39u;<=f}%Q`eh8} hG`.ÿb&uH_2[J$2_jo{X4Y՚.ؙ_GAY$>( 5pR￸(܀UGpWlydc! hhBX"F]rb|SVS|I l,se `22ū,NIǎ>Pcdo8̭$72[i R:} @fĜI\ѾO;L/(/gQZml"Ő *cDDs9h"c kⲑuE ?rXaS?y</ׂ"bDK|e'Ыu(X&ٴ+wjU'Xy>275Ss7p8v24Rf+oDr?+_7O x SY>ŅJ kJn?uvJH8OMȴHNgN8z g/8fP fA3>+Bgq4e9zq"NݎYPic$o ǖb%SY{?hh&6,2\!iD=ܣaqaSj<#̛= } jV'`2R̪ᯏ}) s*~] 'Uٱ]ɹT<-=%^]TNhv"0^E#⭶!)!ZS>2*޾{Ah\?gBy:yk%~_B2>uJbce%':f?dGl>YF3Uo7freU6/&\m. MrS,[Kigk)9*;oWBX\Tb  >݁΋0Y*ƃ&<:j*gf}^N8w *$|0ZCN{"R'XS \04Sg: [7@ AoVV΢wLp!̣SBg*U2}(e$yϽ|`p +bSM`/jobydypbmuWƾjǓ P ɆU~-g*H*#dj8;a%5>kMՊU~Hq 3а_M*4 ] [5 >S:?㛄TKGd];/u8w$7[e+ Rz7?sFE̵e^孈mBP:]EEhey+貚b?%}$`6Lf`PGCf )nT|Y&;.5=/~=1x2>JdqNKc9h$YU`_~׷߿/ '}]m21zИ2ю. ƿe֬(C}mKyd-q^ɋ"v á9\Q;˿)״[42Kd2S\mzRW^:_/L2jHbGj_;[v%1+|qj`coM ͣ|11eC Z-`KXCu)Ď nyG.ѹd*"-*a/7-3_G| M+@YڏگBL|+Z sJhjν{Xf2LR5BPE:? fdJ dw3wՕs&)7وfӦ_^*N6GUE4 -Pzj>3r"C񌚸A#~(#iS2oy)')EN/10VttWPz*gv'*YD 2.&b6!\ϳȔ< Qq…hW:cdG;VfvoJ %+4z-z&f86k<ڙ#vYjMS']mp +Q"^ \gn܇*Ah1Ig%q&+ddעVj[փȸPhe\7Ywy4gNsO7JزfsqbƔG?|ILd:elYdV@/ڕ˭wzexe뽧V7^gGb>3jQRh\>^J:%nfZ,Fe,P Qη}B\&hc0b~J z?5u nA&H>|GnU木k͌эt<^񵄍`ɠ-}= V'e<.XAdetl{D`D3%-0[\iqXjMִI؀c.l7ji;*R]OZ\CLαݬzhͬ=bI`QJ/SN[cӭ-o^7c;.p{qGzZET{{"cn}dj&BI ]BJ`*5D;gN%Lab3\4|N@BbAUS MYM,OpMpgZԆѓ1NPF%?%-FJv6+~uçR guv.%J|X&bV-hKjY~SG [tZߪ9 vv,—e=L|ʟ@-袵<'r{R,ދѸD5@4PLb PAzd?܎sπq) xfw"q[ w [Opܝ, r8ѕ> P@YCm9ϊGx66kazr`̓  >շ|Ɲa)83v}[-E&"9g;%K)Qpn#*Uգޏ)f\6DX=_1Q[GWP>0 !in!Of* @.$&o!#"%"}POLkp3\gIRB-4Xr?ʴ5U4}Xٜq99K '@s˼.SJ4blhZnkC;4?ed2Em\=,S[BbY tZJN!q87׫. <%am+ԀFFjao2 lZ(7C_9'#&6{5L֧.I9W1J2<售fL!c"[ 'ÇU uQ24T/RA }!`=-F|`Jbȹn1wIJ_ab5ԓmeJC ;bB"GU[ 81He=Y MrH`nRh&*:g\2ӕ90}'řYH"Du 2&*ͳ@f~+ʴN((W`FP`Ѻc_΋T) 5q:8RTZX!|M0~<G!NMcѩ]o9rmH(6M,(`C*.(+n'P:j8rG{bڝui7<*SWO z8rw'v2&/'$=ܒ9|s*,#XF"&'s3<уXr5+boB_ccX"/.RC%֚WM%\2!7votvycNZd1+B?Ʊb=`+FwLo* ]v[UMJԷ?c~9:횼+ `wsOj!3dtD ҃28s2:tywRy*mD4e x.2R Z,4؞g;(O.0A&b[t[@Br*hePWvL)byU槟hj[ 8|C`}7h}oQP|U"iy Ƅp&9#"*tjR_h^xH@& w ~8 V[+0 ;qXWWRl ).]}Xj'xZ ㈊QC 6}b`>2J[ FlcS;* ōwzsxGI5蠮kZ|gr!ϣ,*6xuov(+9 YQ!tkN4Ŏ -oJބ+Paztv'G`jV(wpSPMX`*fxNX20ky+r_F꺜# )DMp>,YH$LF2(;$1e2ln_^R+$gU?&v 0NMZ rvNA$/B.8=VUzŅ궃;YVH.Ak4$&ޑQ^rB%] :J$@,X)ԬTB^8 8R|g`*7šd;<ORՖL#S#A!O!%DD4tm3ƈ8pAc.fdcލLQUג7 Q+$M'R1.݌,sdӦ3K#.$7-xݡlmͦ0T9 ?Trj N8o=~@9Fo$IQ_D"Bغv"xK!^vp IqwdjUDQ5!8{{&r?v'Jvu t641䥡 Cϫ1m8Fk;gR6Ak^(H;8pn0z`uuQs>=&@OTJ&T=PG4#9 y4mq{7Np\޲.V$l7GlEňF[caJrDQ~g =qA;s`긭s5_nwgy}cc,bjCGYJ2{$)Ysc૳6g*lƠ|N _D4:_yߓӳx^(AFS6I<]H@r'ݑ^Ĺm U_ǿ7|–I@(mRUatX雜fʆ5m6Cv:T dDq9 ۆ!ȅtvz.؁X9`NF:W $ EDiQ!Ӧ(4v2 z %|{a]#,d(FG_ X_+DoIr`thɊSj<``s&`x8YH!! @J(0IL l^!d#2fb&DS'BoߠotAgn5 T/ ,h#z0*yx:L1~$X\srpgd,F>g|x>HkC7D T*Y`l:r6޷bUB|a3d H󀽯<5Oܲ4(;Ͽn 7$5Rk։tIB6$֎0Tn0q3{#,d.H ').At.Z1d1tm! 6҃^I+ޠצ)j.Iˠst1 (B[+с߿7N%Ľ>ky"-/;MEd5ɣǾ2*;ȩ"Ĭx7½@t,[*3g֫]qN TGʜI& D͝Q~s$YܸjHb?&..*O9$]&',>v,ݡt\ƒ E K˜`׶@1z O%';hQ$Ȝ{Q7wm"qR39ʋQtuؙ&f4&JX!$d8XYt8FHI S.T(+Gv__s'idC.4lt!獴5pD@*>%W^oѳ(NWj>Y .UF bEH+4KVR LE~%+'m"gzYģܣtP8',=Â*cb% r/dsv=?LG?_߾}߿_qI5q+'IfLzt) Q$[-<(D|Al*A)zU()><db<;;ͺ8LrDUI(K׳IOY45k4*R5_p d(s]O|bP0 hݺXK621$WQ"?@)?sRquF Z`_c:rp c(ԊB|f8)h@)g9)w}\*i^F8X!<if#7GcNHᨀfg4"jkx_˟ǣx FUѓ/8,"pUql;ʬ2N7(c(+-ԑ$ρ?1 V>4&H*cs#=8_,eصPVe,5_qUL_tImT+M A.r"W+:J&iq?Vc4p>$p)VպI:(g@<k4\@*WyH\ W7>g4ǂdp *;.9A]x5mS(` a87BdAΗ4v54H/U9^tM'vaf3,O#,cȧ"y116CL_'cz8'A?&9l^ ]Ga=Y )8x.:Ď 4@T:Nhe8 "B'DK8bIW^%|,*n9YgZDOyJ?OT .cR|rٜyeC"hs7K]lOx' TxYj~]I-XOtwr/M6EU0A{ieO𐆵FͶ~?x[fJqv/OcǖAt'?#"9~VpMޑ*N'IҐ'ȠEIkZYcoFwY6$ -^OZA+6'4 >һ;_Ax^ muheFO1\WYd):ZY?mƍ4F4GP;BBjq{DzB<9p_\G! :1iyx{s'C9jD{7 b6>(C|BYKP ʐ Ћr,-'6/n( pY~N:䦀>!T'XYWO[Cˈn&P nóA4Yzp Sp Ն N^ ~ U2|Fv#Vz#:/I?7>`9=h"k|)Qn0>_DjV!,I ADQ"&PtV@,PL"ERq0)-)ZEL96b:=kl9"sYٶTxt)p:#8SLh-K,0inj/ B PMYe}RJ9 Lrʝ,-|&U",+4{KvQ!_5#UD1Gc1zAFxc~EF!8(#lb#|.P F6*nnQy57zܷ>(IFyMy6z8D] SI<:fɖk䠁"#v-{9%,o1Cޠ:&Id%Dhf2eL/J[F]p;qy$5&yLIQsГLs?G>CK([ՉD)p>/JIIUPZI=پ8KW$BA(/P <%$ Zҕ|e* W>Jծf67Oː?I|T=Q~.B_@s oiw9KyV 3Ú013U 4nYD}"j1̣Dc$o<9p8z} сLuud‰9y+?[iBwqkc;+NƔvc،přq҉\*Jy ^d#.R߼ uQe h?G+YzO4NHA۴whfv+0/=+Q` pT\rj#HNG:ڡI>Mr){Y*" FƗZM=$wQ%cTt|I?̝Ӊ( qۈtd\O=HeƲ j$%p>vTFHPU{.ʪgAa>IxOЩJbִ,w\*ż%V#<{dū̅2 iLem%ф0"QcǬm^?7H2N1,Z瓽Y}Jl -s:;{iǯvђ bJO'q!'#3bt~3:`"p2" $-VVR鏪:xa413⺝bA~ن4D{zz+G3_-13Y\n/5HE֛2&r< J|2n]?6u+/W NWV{Z 9j39t'q+ƻկ9.Ƕ9\d)t̅o pƖ`tHl*la9!YQ?pƶT1=K"88ΝM ܮNYLeQ[)cXߚ0C68$4ϳ,r9%IMI]m#( ed&Xu[b|&;0ZY܉J I/uy^P |:*&)n޻(֟):Ֆ7`-^L.#~_.G;r_ە @q_7_6Dӊo; |A9ֳ1oa#b^|-lS4' Ʊ,2^Wz4e#J2<'jiu䞦?sRXĎ+ԯn@ݴ@FuA<A1b,vXڢޒH7N& Xe! Ǔ2ܢF5aa  qV_TL&T$As6XP|.8St}PL(\[s[cTPҘ 'ij$ltvЮThkw!sd >Q\8Mg LQw\P ;h)wE1,Q. ^q$9.zJ0vνCNJ0d8(,xRn,arq]yal}#Y58ls堃%;CM&BΓͻ(F˲9XP@' m7 Tô Ҙm5KpBnZi#q8y{Ahw6wSVL3'7ۯ_\TeY+Xh^^em7Ĭ/"O6J'Y5)EBE5m<̺]pE՚!68{wfǤ3-Cfl,=xߝ3pi8 +σ4Cm$~yqINOj?IK֕x;u8ɍnyKD~\}x3zP*td e)uj>"EN"N~%{V&:23 m,j=$MG%nx4!"&2%XH(=밣on3%j ДݩY[ZYA2qL_DTdw0?'&c&28φ6d،م"f:*a:[S /[phQqY\՚ps=;vn иUi]TH_ƝHD6+i"L}Ч4/NO怖=!<|$٠$MIIJ8H:4)"~y /N#i;v[U.T=:M֪DɁA*BH[B|9.+:9; #cN&( &b}WAiX#ԗ"yA)'r$$[j]LbRBQbxbY'4DK8Cp>eɸ07Ɋ2,P:}ېXĉ$w2W|yj !oᱟMN }+'dчKLdGjW&Rb R܂|I,#MmǸ#环ܮ~ƞ- l78+:g\=^uq Vb+Iu-5ӯjhy!dR(=:u#(.=]v=P,MSmS)Xe%k̈Mbڝ!N(S7ԱƐ%vmzo][ YN@߈f:W@\Le)y0UI YkJ{˫ I|6'GМrsoRQnwS)ݟȴ8zC4ήؾ܇M}Wc^ P +*bH& 3C;9-[R(W6$icuղm7g"R:N_H3=Y Xd W+ *;t2og,m6RiG<Csk "AMg^hQ@d2j]>H$ؖgVִ;(UiFzZ:f1zq\ A]:Gp $n]4L z229#/Rs,kwJڬ'^#JMqjJYHg"пHzjo?8GvWYp0@!|??_v֚B<14R}}qG1˘-0%@1 =tc_|rÕo4Y1g| 8~ AYV4 ^C?anMO²0mP5n2 #*J>zQ#nDkՇF'Y<`ǢY&?oeLw" :< `a3fI+ShLatb͝٥P(2BT'&FhSRd(SΉu2Y<993 ΪgcZc_XXW ޸*02UElsܩװRԆehZ*=mgX\ܟDT"LjP.l,uQ$>6 +]t r'r49IFo(p4`˒[ `h[Xpk?pOuY&1ӎ7<NՓO7ۯ?T݋2"?o=y]:KNKImߩyd}12!FMJ@nFSF7똍*%AI<8e ^TQ6]BJ` *ZyjV}ײxǧ:=^uMNl}sp;,ifyoɅ=b.]Rt5 \מ DO]d(;E􋛋 f ^n+FZ@bQ8*i&8:R:ݣQn9d(&VgeX%ΰcH''*f͐-#A:N+/fI~&"![3ք!ћ|F sU6ssi#/cڞ䬌=$fkauAjj[vp^op(u 5D^"/7B؆* O%*/B2w_" :V O1rn_G:8*3e~֘ T[8ꯧaNd\ޮ'y7c(N[(Ș-lONRvn w@bx«O>4k()GaF"EМAVwCL_fb73H)֔,"g߃{x[seZB';j*~ḅd[~gtwc(gBYJ ˚*Yq!\TuRY '>fB,c*'2JbxG_G-B$sbƝ}efaOO"MK%C}Y3}5ga.۴S_ 3J^ZC1Gt#;T(; `6))H3)ÐM+qI&g6Ɣh|`1 =q#3'8N; T@2O~$V1yrO4Xu?;-MTcg5ᴆN`ܓoSQ%϶"xŞ|ޟLJeZ+ \-VkL 86Ѳ*n`u;4ȟj'{Zfcm{6v[K"ؽ0Ϡp #$$*It?۠|~3Ԧ٭3 N,,!YPP:)Pp\U0ZUp>DibUFzr"8xR}VY@;Ž_^%^>%1jeoXيA <:?03%pDH0)Y#1~S K?Yygjŝi#?k[aA !2(FH z^M̓'R;5 6cꤵCgQPEvbˀ-QԦq*ė(J_1Uþz>+ c|4P"G煺؇Wu4-֎N8UhӰjd'N6"֫M~Q(u夊,j 3Lv'" s2>#+fl/*΍WƒW,;?;(a/.*5޻3Lux#N}26/毮YSD?jW yO^ k1~G Λ+ U!8|ei2m-2ߛM|fmX%A$=<-w?2ޟ2rdQ]&jc0q}'tʇQLq g]*^x-` "+ Z*%uω@<8G==hQwRl2ЧmkI$g6:%H+ZC*ER:OՉ9|jRٙY\oQInDXg8JB?WaxG !V;AVU<1;l>AtL7L)nl%9YC!'jH]۴P I}Qh_6!uf#/eY(Rh.rƮ ]b)5%vg iN< ܌z=%*X.R E]ckSgٜ>H~&ѱ#ގ+KE !]Gyi_XCY#pL1"E"ױLџ)־2 Howk?;9io-T$E1\EmGEmX%&(lyͽ$s$]/ cUeLT샙f'zw,hY7˃6ˎ9J։*YX}ܗk1&%W%N136;Moq«2Y |9=4SY(d)Z4;[zN;uĩ)F_MC~[ҏCM(dg 2&Z[V7yu9F]3}7n/X@hfP+Hص!xu8S9%~T`FK5c)N^ճe @/PDqZ5"pfMt:)D ܴ3p,] N3aDBMb[R8xl?d89ۨ^Ǜx6S|JCv$FTϵLk`ChTϽﴤ AJK̀BNƒZѮa Mz6rfǣ֑"[T @:$%#kB*KeCwι?N^la&a+D>g$(%[-mAg5 ANǯ׳* YMSk !rtcʅS#`Amow@)4#R+PeL_DǧiV}7]O> {PWr@mpO5q Ie({qo6ڸA;|>W0 1<,B#kˆ&#"z,Oێ*NknB:|1/75n;Z|5y. f2E%ty?PF{873.Yy`LojVbx57vQzK|,x=Mnefӽ&/[zCьwB̭}Ta_*xFHыhȒwZARdAS4@3+|% 5"Eu0\lFsAc1,oʰ)mԭZn1e-\KhOgR_pyNMN5`N5~OEM1a،YÙ 3?) x_i `b}pq֗%8yR~ldFP mɨw $Vm:|{1ϲo@8 kc9,(P{wșA@ߩjek"$]1nּi $ILҩ[rwZyO"лphY|L b |<ǵ֝}s9fQٕ(;&~ԩI.ĸP\uL3I$>m@өqP~B-G؟co}a=(w^Rfi$YL(&dBY~~K`bs"{uq0,5vYjrTΗL9c͉oGo?~$bZ;&!`="pbŪ8⌮ G};&G!(%:Z8@p?wqRSPK/%YךFcM>]/cMu N!(3 i3Ǥpv!ˍC[X$?+8wѸ|!%C]$} m _Ƈ`ASJ}1S~R$4#8<g}xоQYE"dX}i\ɾ>HV4L[4R z8#=#{˓IG4Nќ ga\[LD48*|C7b|w>rrs 4d'ǘhyńo<^Ww:O`0e2ޫN<qZLi03({> nXk&%iX >waLZ1F)Y_Z 'f2ʑ3o"zvOުu>^ja hUSq`Š"+a~E}bT|BnT'>Sl;j[.8oq؉9\O{:'`dHi݊1A\6yW dܹEM -͑՚<=贞o$YE"qoY8!_vMDmw* GеsG"` Rw{;{|<0e"',`y2D)f١{Lq?Hr%G`bjf֌ u-{L)q` g=|LOױӞhӊ&U9EQb>Ӊh%D/l1f@xϜ`G'z;;XhV\iP1TplE OBgcy^u$4\IV^{vtq[̕Dp2;D D][f|X ^Uzx@d(U$Q{NbIͬ` #2:!Kګ7o~3y:6Nxxj$"Jׅ|t@r)sxL[ZM̉ՑғT A ,Ja8s()6*1(Qē?'B:暶:se>2hOyO0$t"$ŲV>O\] Rd/tm۹jG(F6'%1аN<~OOI:Dw %&Ag&vXIH[ɩm$w ]86uIO=,9ό?jѧJPVų&e kۭǬ*ge h:h"Yh)WnZ>lCYqtųM/Mx{U}G9T1s%2dL}#}{:PHUqK~}jDvFB(Q`TQLg7JTolF ^ ?#ҝbS]78rX+E9U0Mќ/nFj&\x8⿵h9WAh'y'|wg˷62z/##[8tIșDz,"b\-S}ܬs˔dS# 蹣rԞWL)]0$:~&m&CgFzFԟn'$`XnJ~!7K`Ʉ';K܋N,BcbGdx"#ŲtYkեݿ{3܏d|p '6<BeFf#i]}:K -T.6AN2gR>@IŘx&&ĉvo2ƦԋD~l-Zl[ OؑHQ_-FJQ,]hAmM8J7nl&kJ(_hw ґʉ錌B3)M5V9va#(D:]]So  /)b?z*JcZk%+<*Ȏ++PV NjI̝7Op%t38\g>iDQܸm[0G;kl?S#$ BUUσT/0dY&%p E][Gl64MT:dRB!V @}^nFB Ej\ dlfS28O"DkeUBڢKwNPjHH3,8ahoQ O!2 ˉ࿁RN񓈉$lNPo;УOS~W`Q>A98U?r vZp\C Z3t2,.2sdA*Gۮ6([ n`NsQ2[spe3嶞`M_}IBZLӶE4}v$4~=CMv-B|U6À9H#rt4h9bƻhS,#Ѓ>-}$eҽX!NgQ ' s1%Kܸۅ!N6+u?ݴT|ԛZk?ÞgjGphk~j1|[i-> чIc=Rξ`gwutd42kdvb:ԂL(0.%!'>Aga>B! u=pmfH ɱ&*&dhC*ƷTJL -8p%k;Q憍ŀ5L#a•x^ RCzlٟAB޼k Pwqi;*)Lˊ-#kTXwiFSV'GTV7dr%TeG-׻lѥ(8b06Ow?BT mo4jâYabd*l,-2ܭWe96]X',~;II Ktef"-4IW-zR҂/a}  \K.Һ $ACm1U[6Q,*_2IFdw%:AwU:I֧`(6oF*݄|N_'>p=3Hrla=1g_m¿xdeo"mINuf=3M/]NzQwivm"^VTc1U8|jԟSՄBVA<>/χ%̬>dz$9+Bq̱0:= ^Z3mIJLVW5;9-BTQާGϸ$ib3[~lɳQ9哶TLn#m/1%_{Mrpw0Or+Ds=4ڬho18 ;I4ຶĞb"f2 SqO)p~$LWƃGP'j kX'{9 -B7:I!1>*s_GqGX5M:n1mfJ5@yЖ g.6f`XȱCVdP) ȹ2_f9yIJ?bgD{…& #f(\@P>8B8z/&˭s WDz']Uk1،m q97&3I E3#vݡ|y$ldC ۵ڨ-F%d7aLpF冥]&Ժ-j'yb蠙铛ttčW39ݶfcrF |{!Ƕבx_NH_.L{Rj߿o?œNe>y'H=N'= Poyz!K- t-|#脅'R5u@2^y$k2}>ZHRų#sruUClYD]/c4F) Tw³=}fHnO@hwr&z3<EFR(In"ZmK2Ћ=QҞ,4%_p\.1&Bu'awYMh)O ZЙ |7~>|]j*wĥm[3+eYFߏ5UdvQV/|`>",K=/Y|IIB%s`'d7<w٘l2O3,(bDXGjZJ, ͼ8:?5hp5'ˉl9"C3F|KGhr&َ}u'MFRc8(&΍)*"nij`u*-E[luRvd'xQ_5I\,Ab<_0NV岱|'[Mn$`&Y&O6}Hz| n&zK/EGP2HorDQp&*'u!kTԅ^ncԁ:˖UUڎeZg~`!* rj'_m&Jyb?fn`+I"db_E"l2)l), Dm詪NhQ;$W-L9&~DrBZ%.eFqq^>3ü-I.o^3CezVx@?WoT2 A6Uer`nyhل>f\k0INK?kW<*9+S(P@,7ƃOh}\d ] A) “-d6O ҅Zmgɣ|m0:Թ^-gZ*#=Q{BqC ~K>gi ӷn]ndSZQ@ Wc;k̅ gyLR1y 2c6ܟ$ |V=ќl+b$>,*jJ((UAN@fo˄JŇRz\&@^ˈ?9AcK: <\$6lmu^?|x;DMVIP[dzG'm(SX|+ Yj7b7Ip;IT Kj:E7V-{3bHRR˫vThl3ɽ"[م" .k#NLA(5䞯 سDTn.V!,hr2S /2(Hl̓1wB*6cIנ< ёl}9qb@| D`,+lN-g Z0ݥ(ʻñS sh^gmI]'obw fUXY'ma'<%4@&ؠNU\LU)fVpZM M,Mw :}=XݍUqOdcLu"~E +ѽ٣fɁH@'g ~I7Y3~\8 yd=QVpid'+UdNNQK/42c^K%KY'gTΤ]k¯A-|sX^Z\ɩOvӡVy~[,1{,+tgxa eN{Ljτ~O+o}?ҙݠ̪|xgx^.-U0+:Z -o !3̻}Isv48(sJvk=x%@(&&'34f=B4;lҧw3KVzczM/]Ip.l f,z@2r6](mq/EfӉ }RJD 07/\v(k7eo0=o&O<9 R%ɑ]Zϖ `3kʄC/gY&_c9&2Ϙ.\V D~NґGlIAXd ]U+BVнmp=G*r5 F_yg3HqOܫD)Dl5$&@GZqDC͈N]*EqʮP: 2%,xPy6jtʐtI1l5ҵP/ZWNFXSQT| AV(QZ"UkH?!I3.5mK^0sG5xl??1 fvdV(zdh zWOhߓi92)P8ߓIh mUͪ ngPL1-Am3Rt:Z z!#,iYf @ޏ\r9t%)f79\#-yͩw`ZL s3|Y,m3G' t{uGbK׊BxldȇRZcH9A1~bl߹3n_ciU s$@HuXYiUr.K>kICePcܨjݹˀ\eJ2g]~+n {q:]+׬'/Z9S ] V0D A\ez (!6H-ԥY Xo`qZR' @!rF /NI%C~(&'ͻMfGX1+\I} QN4t;ѷ<"E>^<|e so7/1RX8g )a.bNjJf\Eٜ'D~։#|a?DX/'+|< u>MϬz4.I$~xss&)Tŵ?H-Ka>ǜݠXkt2ډ*,Q0LrwA8(:PR7݄]N(v'vro Lo4[;^'~Ϙ,tD)P-v q\(EpAXʜ'.ḧ́Q=yRk C7VOg8CWdc KLWʃBw8bZCqlҭbJ5Dž =n8jI??:8Yˡbl7@mP᫩[Tp8W:t3k#ٶHR>foǯY-&R"1$XzPS5@u\~ {DJn҆J6 ny)s%4;A\vCWX>b=wySX,H=ܸ[p\='j0kخ{nOw 7%ȣW,H6Iؾ+$7 aJAM37<*EW|P$CPoE4 ٗCP|鮘3&? iEHNLy[.CK+2JA!bԈԡ=R@qOh$aB9zhc{`f+tBea&IS2lbUL5B>[ln7IJl ͺPt'l{I0}g$k]*KCbm஢NeTd\ &3^a0ѻ[@2dvHJD@,c?38[3Ak_F\̨:jZݩq%Re٧#bDprM;Pi@A[ĸ˼O hfķ40GsGޝ4![/({MQaK.`9gNwU!gy'|=: O|LWGX$@5;EЭ Yknf(>P`;*~l;9 ?dQ#<&͔UZv%_DLuQa6Owr54Q!#L̤[%]'GMqԻY7*42*"oP;?E`"p:x)Z8$r]ôzW]S|wR/ Y) BK90mOG>ֲmctnѻ(4n}@jc۬U<qm2P%[c^bѐ%wTr;\]g{@ 5f2>)N8›eN}L >wKY8)- g9+DLŠ.M,Mu*\ ˙quN #em3=ǰ2 ϕm>l>uU-.Ĉ돴0jͳYfdikYZl>y]?H$Mؐ=)*k tOҿY_/0ҙI6$(/aT1ck431#&)ڹ v'}(j'n nm+'NsgUdVqzv\*1E`&vv äG^_@n,'9@gQfh2s(YCfeWMpLeWtm"BcÈ*+qTN򌄁|o9cW罋un8l3Ĕ1Qk1Yz(C&Eh)RwdxZ6Vd)Cr#@?|B70)K>TZCnM4zkE@'@*aZ CTVӻk XI~SU&P ?!W="m;l}]-m||<6`DvH[ TjR[قeԩY'vJ"ه84x.?SXĴHyz=,n3͍5}k݊,!h .`F+(Upv||^X. 08̚ҳȟ+yz-+j!1:*6yP C%G.rY4(wsVByjv%'!6EƎu4v:8q[eX(>-]oRzgDu}!`h GazX4?Sh_jɬx']ǥV%ZzRiMv5gVX("yu>'r^y6^:Teˆ9ms rth)rᬦ<4QFbr掿ۓ8u?ɓ\ L2'Md=<{Ts34Lf~3-0h[ojj2kSxzYI!Zu="?71S6j?wmᘔJ)68` PnW0z +MvSCVQg~>+4gװe6sKoTf<&ֆM+23y52/GJ Ҍ.-ZR8;I an|rWr ]r_@h֪mmú"T&pW.tBsmxGO8'+uR<ptk3{`2m%t~;(MX+hvϥ/{C|.9!пYcoe-.(l1h,KUj𦖏v^@k<|xoq<M·BxP%!/bt+NMtHJ۟MKa2Y~DLzs$P9y&y^w:Uc [|'?q$znw 4IdXi eI425 cKPnɖ$\H}S73]0!uٱ Eq%pwK6~âzxOr +}e0BCҫ0:F 1 :ҥB歖 'rњ$HƬLCɪ?{$_?MԠc8/v>SdLKK]Y8AqG,ac ԋŐ pmIkX"c25V eig-&b޹ٜ!ar$76]dSƯj*XsB>S^[C'ѐu%J|+FXiݽe,nDQ )5.MšwYԱyB%;cQ,!i- 5Gl ;SxsnJLFpoʵaNH>.3y"7v#ھTvĦpvv#aƝlC;>Ԁ\]*V݃z2xb=lqd34$bLJoZўAMĤ&̈́˖9 4qȾ5FpNtɅI3^ɵ>:߇]}kʜ o$ EVH}R߼ҫ{dA׀n^1WƷnT-v)Xqu·4wLr, leGFKVOД/ I”R~@#23|xtLyā?'cno=^(R]rV~cփoI˧ī5mguⰊ3Sn`J-o`IxYaZ-IoK~I~-$gQ9j sjʀ6m!BC?}]礢yÝw}G[56{}=!}f'aNeDRq14uFQH݁I$,eTŔ3JďGeyȏFϓ[W>Y ㆎWbtoJ)EoR1@;Opb;SFįq Iu?1Q][ %Jb<="y1AKC̈́iX{D%_Z ? VݙMu[q;&^)L^aHzTj;ίӟK'ƣM>?o×E%OyWi#̵s}lIOKa(LAZ?u$t͉hݣ;Ql7fdP<(ݦI*3{Eq:+|5naE؉ĵ`nv}LjMa\2O2hZ֩;!fa$)А?F*\} WNx;UBEN\ Gpn *Ry3ZrZsd~$ʃ>Xuޣ2F}g8PzE":Ǫ JN70'm YYsKsz2x³k&['.e;`Q}^髁5K!S,H-QХ'+R#ļ~`[{"Mi"ˁ%۫:Oc&/~wB΂OwUj6_ci nh˧*&c%bY798vz'fWF Zbpv5]mI>@F}:T(-oʥaNP+"7!J.jcIJ"w#Խ-=앑1O܃v|)Ex(L/ѺI"ⱨZ~Q'u`Rcs i={h$ZJ$nqI&;'"@MeXo*VF2l-nUϚ1Y,kQDbul0~'22LeJE7\dI})᾿rknZA Vim.}PĔ5?N⁠wf3¬q~޳Ǯ8c".xϷ%ɟKzW[07HJnxRBl>AyEL5k+Bc\"i7/w\3XL2SWC6YYp+gqdq!sߕSz %bh}<Gm+~q褽#*dBRxgjWSc)|:d!VP  Yn#yfZ*(w b'nbcVq'6&s˓gqCpDá}Ud E4#=Yqb]z#eX-hc kc uLG0zct6=!/[TĸI~zt@:"Df'ZmE x/ ?uIg-VzaՊr;>.%s)TP+? "+Iwvܧ}2O~OKS,t5wĶA'WR}iSit6z?TD9*+C/Y9 weF&T'ouEz@g: ػ!iScWr?R+aW7"Vy"Q*|Z|6}ϟ9*'ʿ2O8vWI&20T >bkDŽ~<šΜ!lZaIvdp6ՙ]dlOo9/l,N -D⩗0~R'U tWxsz?H㚒oy@('_^蓘ŒKg":hb?(f7ĬTz0!D8]YOrJOH6B 4YqTz81u˄m%^4shHr5`ꎞLO|34 LT=W,;,c*>U+KJr9,@f~x+zy ŞfpWkSa5&0aEIamfqejەхet79y XA΢T}Z/7rRk>v>!~ʉYAj#}5ʺϙ\XmsaT&O!SӻY/(՞&wb7T]-TYmPI Nkb6Q%IR6?﬇ _o<IcU=|jJba;q%w ̠Luϼ@U.9.@Q DvlBy$ʽa|m_v @p,8@cyaa#L;coDĊY[lJ`hh"Dڡ]F0TuH3 \ϓ$OC$2$5kz'iE-|W_D,/fGV,G^&t8jcjeԣyEoirG'~:W~@(&P(\ ӫ`ftETAsN:LBdݔ&h3N5r>I}LSօ`ƽ֝Btğ *%`Bk(O"I$H_z^Dr{ 4ۿoHo߿2'Y-ZrX4k7K=6/,W4U@vC\Yy}iϵşEuc?JmYG` Z"srh.Mq E^1{4ܽ_k &5J*%1!uRxTIe,8c>IWIQ ZF4w$CN|ir'U# y9*^;*Cm=:#G뢒Eq;5wk4&2n31'6#l(.&тHZ ZM(y;/=$6|} _CbKfs 4tV=lwr$i2ID}==:J))L$f5fW#5)\1h{_;v DBc0L.dU VM?ێ[>vMrEȵI_Z͓PHuiEmWў7> OZvD vLr˽c}bz*-b.1ik"-/֡W A^hFB":ǧtU+==OcTMZyDt::+꟎^G#S7\L(c (n3[I‰ @^h3g̀ 0;`)A%t%qN>]\N;?GxAF?X Y&~"r v3I(] :{? 2R2aYI]CcXf(a_ !8brH%r@XhP |d)fKHMA/*O$}\LQFJ4>@øo)@pb\T"@| P*iة~́6QղloPb[;TC&㿢  r lpZKvud&Pl%cXQ#>;JӜ ;ٞ=81-0t|g2QBvύHw:qE[%cAE؟ITy g p"i3%֬Fbztp oa4kIԼ.'j%_~٠'v y/5DEQ􄯎Ne5z=Q,oFb*O,xcԤka wba$"6eAtG5P|pJx[3j-zS2+2Lf5n{o($*=A:uxs+Y c `F0٧j9(BYo; Dw KJzX-7kVOOFi e~?GmPFO}S=GyiZ=qs@OGf'T 5K5L&b+BSqo'<6+W+H!_p+MC?%eBlN1vg#*S[zIԯ`xzo$gJ&@֜i ǫv{>Չz<)m3]q¶ޠ@}S~^vnQrj@NNLJ2ʪPUXa;=ێfO$Ǹnp杻^VEd;`0;\a1$ _sXkyee9''sH#'6azFA+,g>I98e* mwL/V(H'xTнjsu {!u0e i5JWϛB{0\']2GZJ>P6_[w+IJEfcs'Ieg0]ɾ %9/]&fʽIn>N>_'}:w_͎jR(9418G %[ ]kKUHI55[*5Ys5杢XJHU4F_NJ^"dYτTYcZsU[d[ÝջӖ?Yxξ# jUAn) IT8R`ifs4L݉H%wL}I~~T++ptG:TI`]1*5W+c ;q$z9D(~"T̐VNPYgU+ ΩChQ^8T".]E~dmуWVŔ~{tƚ=wUJM.y2xgM7`S'{x1jG گ`M{e3־OᠧL\0?ߓ"DRvRZwʕҲLúზLTsLw0pbQę:l!,EJ ,+_HN$Dq.{7c&5Ke4>.)j֛_(x&ڠ>ڴNK_||O\0.{uJ+7B5-HWV"K }2 k/T曯Ë8ȕQmG}X'dX ME.re7Nbd6q_ApMjj~"22J;K5ffgvଔbVg籬iy׫O4fe] w* ) (đ5)cij}-m-m=wʐ>v } 7 {]ƃ5yL[i̐d,zjլD8h e̒zj1MC}/g8uȝL^2H R&)>ހuɅ}7F+ִLU}9iO؋\^0n<:,Ìݾҫ~Ye1upj]6!=k;w O"c< ?+ nlhgSgLSxyZϢ@}Wq !4en j6/wBZ16-iiNrI?aI8m1I٬/9kx6j:?ٲD8gXQ {Or.JC?70AIN I\ "zAwT]՛wd-p2JCv^C s.-lYg,ge'j}`׉i29E>"nGU@r=aq􈙞ʬ\J =>/9-*Hmvwc8y%'sλOPRPO*u#cI^ g'+ ֶ+TZ0Zj 94μ/KyA*%Pѯ \jYL'Q8U{YѰM z̷ىݢY1Z, ^z'-D<:A_D:ryF1x)L14:KǭLIfg*#=:'Ǖ$Nù8@`B j?/y/wJ5Nͫ/Y"6"U- 61)m{Ϯp S<A(i;[=ط+DeLd7w7E _y)]<URIHecl8rA3T=~_1.l۟V"ݵKޭp{)ӤVBct$:$]ΣSv{l,y9VU[|J }ޣ&13 3:/ײ~43wԬ\M=P5kwg^{z( Quu@ڛĐ##zeJ\Μ_V3$`x->^b?}{qF \xdo&|Z)ޖ[0SiÎ2»7Qm [x-yc&mϴΦ9&ew]K]grV|wݗZ.}z6I(bLFnTȜMu𡶶RX4:L  pS*Ż7(;$Qd`G&Hyݗ <]ZuՏ-iZ.}'Nb[)~7 %p~7ҙm{ul^oS Tw)[O}!n$(yo:-=llٗC1YuD}1{pzJWe}:2Gugy(2 &/MGY3NgÖ yT}?4'b$w>]!NL2cMb @w'GLf~W;VSfEXx{c ɵVn4:Iqw,KPN^lb {^y/v|)g|g')sMUfݏ5ڗE/-]:^%4, y!+c8dޫ68ȹ9e_4Sb1q<  ߛ]bǢ|} ?zgO<39C_q$ RR?y2r.!m#mAShp#UXHo;=@qۇh%R1w}͖1:i t $X)Ὡqoo\UA@HjS^mͩLR*s ~q{]9L{a͉0sK{lfiFՍ~"K^hϋw־J+$N?Ʋ .CZD xw 7-a, D0[fտ$g^t-@6"RЂcyh*68{Ũ[SdaFmmPo9a{Earvim-ΌI.e~B.Mu} U$m5IN;dGǹ}'c|iCSYBV8"<=m ! I.EsnYk,uB#4΢̨^3Z ovlMay~T<& U9Xa%lv©qŅQ-5_¸w^=9ոVyԳfIʋoNQv#_Ny^> GAԝG_o|Su%+' -nMh Lш/ދ&fkob j]g#{6 _zK~q/⧠rLj.stuyPDXF;4lt}^Pf8Lz~GC u"{[鮏*]I1f"EM;|Qߖ]ʫBg(vSbZeT.I8, b:[m}l'yW^6#W2>S|0z6&pjkz; q, FuT b<޼~ϗA>eO^cʻ`bDcqt{ ܺn3FLx_uH!lغpn"' oGߙgQ5F}yx?"\ahˈyI坨JITG`ʼ bUqci5O n2*%$Lcz_:nVeDF:7{"јPܚЧlYON0_ͯ=e?_.Z?緿Ņ篿r/J>HQyRNMfˑ^@3ā/՝v2slY+ Zޢ ; X{\&WC$% yeDSfL(NQ҈%଍W3 Qj KH-updS:iWfOV3:H d^+R︐P' /I5$|DIvj}Z*{MQ: u1W6iڤpo0x|nc\(-Ջ㐗+zQX@W E0 Œl^?w%hޭ\Ix+vzᏃR3?f㔳 sz~Nek!GncٛAq5SsfD) Ջ^윕ʰ%!p0[ﯜeݪBkIr+qa/l2KҹG!NP<qOFH?xfLF:`cG}ad2G7Ԇm]:Ms^^W̅vRDFnfLq ,fhYЭnD/ 'Iq-vI8F}k>ӱ82s9^|ԣ RL㰉B@dR@W9)n`64?IukhFu*@',:{4I|@%X#*왍 D&u\E;$!W B*J M29J0zw0bPp/yVoG{"%sj" h#z`n=OzrbDv'֑mI%1lۭ=.fAY-n]wWV/ףh_ы*Zߙ*Cw,b{՛Rkt^(5l9c+Wδ 8bL YLJ˛$Oқ~7藢+vyY>>1ޥlWHI9펱8ͫ73 hj-/K+O w+_B F_q@IY}ٲ _F[bb'DR^WM?cg[yP;˖@9@X%r6$gRns.eܭvy;aUYzm)&e`njXWEdumA4Mk]vٲ ׆ΚR8!9lz= c(hc+ͨ0lnRsz- C$FW5=71Xɻ,$;\9[P3NVĞeuGY[M;ߋ=L[aM0L%@NFhrPh9"@ 9Q^owO{(M KUfND<~p4B:2 :aϓ!bKzҐ/zJ.Q:"Xi&[Ec.2}@2,.5rarai<MomgVR }T#-n8X1_ 8Jvl5ar'Y S2&~x&^XO߇ژ ɛUӑ\d}v:CNBǞ|[I=;Of0 ,T!IܚTZ4gcM{^K#HhwfjFPy|=O^qW;Vq2TҠiB7վ,Br*Ix kYzio* G4 uK, vqaDpVyv6&9{`1"^Z${_|C~M={ª (8mpqִ5_D1*)P a~(؊0̈́]ljs\'g0j\15otFm03,^iλҰ,WFFoQpYv0CG7~$2n.~=IHvӁwObb*'hgd_+WMhY;IwVQ묆N[hv[?T` EUcfM57[ɩ"!2@pq":#V )(`A1L8QEF5uFhVGhZGZoH]g\(ѝpcf65.GVj˻I0@rB&\8Sbl hSbW ܎ oǼVʥnIoh>䮤[L0Y{#詽@Vr&rݪloںMPo~Nwc`]{̠'pE!8ľ ;awxߪq%CN-u?,Mr3O} yts1OX ZJO^(-b 3SYSD||bhŽ "WuΓp9Tq4̤3K;+r'^~ImH #]2uԂy\ "MԱזo\I!-ΪυZu*7_spm9oesWAE~Pw-]lb/rJ_'*L\p|>$P-VsB<ߧ4Us?Mt:rȘ;~ ?$ynN֜1Ϗf§;#F#@/ /0ߝz.=˹MLI(߁Y;; 8]m!uЪ/8ipE_1z՚% |~jEg ui؉&IuL} LG-{,͙fqJC18~uQHp{_Jmzc!F` [_E"R+O_bP^0;EKe M۪Rw\;BΪeS3䣄NJS<=wg PcFE=h$ ` G6b-*@oBe2'~e"hV7YKBVHq7)!Gҩ1/t+ c2qEq,'$WU赒.Bg{D*xX$, o~[s)朤0g #Rl `he $B5i(s3 4ϐ(]iC٭Hcg9ySB<3"GT&'ٽ!0$s@}d*zkdg8dr.weA/duJ6Vꆧj19P'Tv'~'l ӧj5rcOlmW_)k!RN6w`dErP;s 63-mqa1OK/f^)YRD kBNGkO؃J^n+ys=+P`tG_9=AXr zH1G}^047ށU4Éӕ_yE6⹣2#)lYt(fRQ⨝@Rvg:1仧$SșQ/(k`*Tӛv>,K6ݝ=,!UDNP1X:Yt<&wX{r q<7c 1/%IH\p)Vgy'o|7L EcEV j< _'QWp) EIqMiyp"wɊ>BR$H+ 'mbg:OgbWFٔqNgb;XPPs4QSzaNI&W6f^(=nt^h"~*,;o\&F+Abhu&Xa9JpuQphGkU/;q=IJkQ;igq4~v8|̙5pb5#%Jp"|'-ߏ0ƱKY%kgO$<1$V['UĜ(b:ټ"-c5Qd.l/WEuk fzG|猉A`ZXt/*i 1|zG68N(%6 ED9mCGd45XP;+X*iw@D}Lxϙvy:Ւsi<j)q~Gö Cz. *" qcY5BRe06vzFL[.)qQ}N233YGy;Qs0XuV̤ڱ6M0fq\'/?[[y(L`(Ä[k&!ܬ> 4S964'c[b- N~,4׳y =$ vZǝ&B1G֑+h:?ɵ_dqY^mdp]`5ҕ[lfX$6'!Y|ղrI~~/ؠ)i) tfO6( cc9B8^Z2VBzt %0ZW]mFYxi5!(Lgdݒ;[Wv Yږ:X薢j>'bbLQuzt"#^**C<{-3.j׬$ jrM!+*B{諂)pM0?feX" 0)*Gg=V!̺L5<ة7 r~4'YsrRcMw (jCIxeK'RuKxɔؑ2s>=EU݅+Qʃ{'\HK,v}{5q>v:繣lz #fOw!7HÉ,`G'hAP5z;w+-76#-"L[xKAa8K skE#3bOTQ>0&Sq9ق61(#< 5 G=QeDA7'=o; L2BVh-æΙߺ/?EI8p5 65b1G,z)5(|?LTsrKWνٜ }8HPەO80ձJ-#Md$ʡ lQbq m"QDU!jțC2˘][Q:rJ՟HzFgo#λi?a wHb !p<e-uW-!LV=$P '6X9G-"?BZww&(u6)YfҥW^LE'#Q)*u+I`ݫ7;'Nzl<Oc$R&rY(9qpCOna]si/%ٮ[z*7߬a- Փo"~REZ`ɟ-^ /:XgZD9L;o6]gwVq-YF2+w=@>,ևfI 321URO2=jD |dz, Y k4r9$ߓ1H Oa˪5Ń5'5n\ oIW% IV$x*.ԫ86}<7+c=PDG1֏`')yY#h(ǒ-:DLs?NF@2.d @FͰ'ӍgD~-^=okV"⼀( g`!^ɏ XP]!-+\WVr+m2iZiu1yp_{#_o?PI^T-wAw~Og4jKd0'2NE?僬8$I>7W>8Wv6[!}C!97/>~YO0`Y 6I+1; OuH*%jOĈHvP`c*Q.7; δBa+qjcj'~NP?&dIx2}ݻ8ϫՉn'DȊM8z-Q Ӟ%.LTFlـ| ˀU$ܚ{b1m dԬJ& z$-ˍ˟}r-`3gAz]4j$[WVƟNN ubO2tyQ|6wRס0U)*. x ݚ$r'yV3 1H8z'矿߾/ +k+YA_^\]pJ04Gh!),#T3lMQyAk^Jo9[d|=if6}- M늴TB"|YgԔ7h2wJ lR@1s0$e}5YTٸmU+A*[ l4:<qY,wE;T̏n̊7 ɠh i$ r)֝\}D@YRGm;:?5Mf@7& BH0r!9| 0^/b$hQK?uu'yMGIbedYBdq_6-TV]؈Z.|f^2MOhμꎺb~V d+r]]^xAJ7&ЮhvB?QHbQHN8Ĥ76w(iQsR>?)RF$LфCsgS昕|AcP#K8IU;qD,|P6)7z"Xb~1†@AU>CQ̓E&HF#D:E5d<)+3ǍTi K{Yy]le귗*5'^L:A0ޏj[ I.q417Wc=8QT{HF(6Ny `O+0h_y)`p% ҴEY-GF >KǜvjyB8"2,p8;z֞c\тU ΩX2O":!͘«qnɰ9_zhW:!2vZgE}rNrZA`1>#U}iozf瘃d/V:ʻ2v\ l8!7[ZluWe!TZHH*I觏S$A|z" 6ߕd7*r*:?qm1ɉj1珠<14 cY[컵%8$lUl~zKf7 C?>g9'XUғoteHQ G)zY^u6M+~٥ߦ9ow'xG\e,$)s)/jI2 m2fLrboPប0 p`I{j);S}LI>>$颡x&< }~ϯϿ۷폿ۿ/'k]ZOb/&=)l<ˏdU[CbXvu'g㷽 ZQs&Pɦx@d.*C֎d"?UtꕓB+}|[^V1!*JK™G ל/Ys'oFgMv|x㵌>'`q=Ol䑻6zհv _8)hFA$3Jlpڱ GRBLT:[\{S8Vք1>ޝePPiJh HUw-&vl_ FBu!f/rUlzZqxFLvaR{0 pF}jZ34>32xX?v*n6.v%y-KNXJI u?>%/8p  v6j>g)@]H"2(|ɼB;&gj X[VmA๛{Z-kź Η:5iޮg]\rƇTY$8,C U W4]Ecf<T7ھTm֮Ҹ9'yo{`liu8OZ gk]y0J_:$0Jۜ)MɆvtM N]2ˤEb˗1YeydZ~:"fAdK(OѤ.n՘]ARMZ#{^x`҂Ulac|2 T.ZcݛmPdQ:$*p!i&(%7H;8=U\|D6xb:Al\'y{dE=ATqSC!b`-o@-(5"T4ė~RGxI*eFzK^S- PKgcG&( LnlI^@,h+x01dAtSNcfmceIy։zlӓ<%^u}Zq,1)\f-{]Ƶz3rdL'j)+'_=NaDg[Fj&3+#6ᓈw8#H*kR#c6ڇ`bQ z9sԺY žR[>Z_3uљͯ8몆;#$ͲVil'9'ċz< nS=N%3hN X z߄6nd' _:"W[,'FnȘL`"v'HFʊs+.FAP}VK#$ x"b{>Q!r4U8̿ V‚!ڞA$TfNzm|٩4{ W&n|s$f8J.o =y^ 1DS(dIr[HpgVAa VȟXxwT@<'_[7?}s]oEO]"E?`s[{G|]B׶f )ԮM6wNCEx7]_F(ݱitb !~Q ~8e~T+;; o7/$z @ʀ+V7j}7~ny&]=`AHv!$3EO}ae:ivrš+yVb#n3K/Seڧ].ًew!d&3k4zn * ;FC~#a.uԖC5W+O!*VQXr>7c0Oų̏Ha~7wIUЇ? @I/yGKli.;,f>R clNIxjV `}Pv_N@fk -V~qMi<1*=,U?랊KCM\+ SֶxN}Vy>+s{#Cl$er,_G:( &IR^P~6hD3!>dn ЉS OBFgH* YSC7qd"$W'I%Yvj"'饈bNHM8E]'aAJ={=+mNE>B1zGH̅7BgȾ\y%ϭ҃%"֢xXj,<KRIfՓL_gGND\<шQQg{Qfh|/(uU c61,t|GӫQR0>C-N>@# @͞ 6c;M''"%0|* dFAxS VeѻŒɒdjwbU$iKۻ$ xFjx1ǀuxL!M,3Qс(w3j9I)bpvoŰ1(7O>~ z"bzخ UI۪l_E[ qqh[v~VLhCQ|: ѳG7pd~GD^}F|@ȃ&7ǫ vuָ_oro,nnH-MՁ:8},ѕS7YqhPۖ:/<%~Fx$P I9 օԳ 7c21t?br H&e!/ew,.*@{LI"Q PP1d.[n% R ,0p8':i8xʓ{ <# @p d$XA` wIJ[ULCK|$~JzRlړK]?~uGjd#瘝rxlL)vY=t".6o,&+Iͅ7QW= F#mΦ or.IryjkaԎhNͲzl$ -Hv:#9Yq…g/VT.FX,ÉE2mIJ<,2GY tYG+Ӡ}߁QеZT@P :;#Ӕ.͆5*~BxbhP+Zr$H$GOb-5 (އgੜ`!fhY0%QDqDrC[!qJzjƫ5ݜ+s= !& ͅ2]qUc73u$yU#*+:D ި6F%3J-Ġe` ~ U*znpt9@N3%V3GV@ .j4qoB}C\8IskS%jg)AՕ86l MڼmNԢ@R(Inm 1Y)96eh"6eU: YʳUc 4+ʌd_Tx( Z蜤;e*6"4{s+'ZcVZ~4NqF,lia3ÜZLĊ1ë1G] Γe,Pw))Q%GXD : <׾[g;!`ΖD1;.74n\Y8iȇn&l eb%MJx ȑ!|@HkH4 icWDZG]ٖ(ZIu8ϓ n\0ۿ257ĸE-%TӺSD*~h1r1`%V7 $+®0UWTUhWKo!p[&B =T[s_ŋ(f'L΂rNSg2UR{wO[2mp0O8펠Q?bqQ: *t_z'{֭'IMQ5ZM^p,gLY-\@/ 1.{w/-z@˼I;8a^/%pIT47҂G6$R\Lyh~r}fǼ-T<7GKb歰+HPWFo aXᦥ%53v&P\8̉/x>U{(9b%ry(qNJdQcH;s{L mgFHL/&(+U ܎L1lۗ%GHNzoQTμZa1p\H 4@*$'01 lg%> ܒ^z+3071nHĉpAk}L7gHǼc\wN/uxح?dHQ/.1'|$5,@3cf ȉՙ=M%NmK5RI.l vI m|Qid)݋I M}|Z9 h$"<=Y校m g6"Acyz7<4(7zTP 9ֽ Is )*\Wq}?r+C4"5j`IOڝC8̩<lAjN>\7Bp?x|$Q97; ¶D`Vdbm*/ {y#[=͓T!wPE|kVT"0D azA?e ˔VTI_l_փ^rwI_ȭ _5% +k:Zk+@>A]#kt$\_\?ܥ[FO(eQfu}fͮYM:S1cc{ƯoT=`d-5Q$;]ؚl8i4m}w N2/F-'mP Ob;"AL𢡄x'k#-CS ,BM5C$vR娛%Bk4%mfPX-A<-=T-j}`d x_v0j?Xn"ii=clvu#&8ƻ|igy5gt-a'r'ӝc?x05 ˑO,3%н* dSh#ٽgI$WsBV!4piS\zk]_Rg"ƉHe0"ciuMM,\J?0ʊ^Lj 䰧\?`Y3EؤWdhf[~,ɰxGdڊyƠfw&b;Ủq#0f5hxsK Db_11yu٦N8m"ny4vΉ);6ѶZb[X'7.KDSxv˯GguzX)mCoD-עW< 6C2Ðl&:&xɖ@HWGs+!?5C8M$w&_"ήC ZZ~hdߍ`u~ֳ2M e~B);FBhCgRO C={.NX]n\s+ Y:=&c5q&(+o=h!pu>Z;eqZɅ!pCS|̻- m)`"Gcฒ:JRG^~=c;{.\̓CUBi$rϛ9b^jxb*,Yc>1yAeyDæz0!riTqiQ06uԨ$Jh})x1HVc{|OH.#gk'TĜJRrK'xJM6ӡ|c 5+g5$lDYO.0P9>`O"yr ϏO!e+eic4览G KWLrwphG^4-v?I-ͭbe^ݘw)1|:]⊊Wpw|E.ff % ӐuA1mzZQ~p s+ Ll\q֕- T)ʫ<~F^Fw;uq4W@si=ƶK #>WG"aM':sCxrfQYpDTVHy;n/NA*tNXPaDzh#q0Pp5F,0i o9 )66G$6?.]Cc^c(} /*0b$]mWwLDxq sr! ~z '硨ɓdIX_[`kH#2rJփb"Ȃd(%>]7βR7.#T\%);7¬%:@cx=.I O2ئ$Vi8Jeʊ2^Iyy8ieu݋$G 3y&dZrdތsGIVH;,pDnቂ5'a LXw ;"g0%#+F= #3MNV=8iazL;r4'h#lV2O á;Nj.JI{`(X#2j#49wZ<{߁ُg8؝e:]vX.o bIiwRpjrWhIb (x,Rt1#XdEܣYV4jj-f,aXQ6 0Sk$VV_llOHDrB!6̩#׫e샋Pֱfl<23);[;}ҏYL LVtF]ia) W!#R!ɽs+j_\@e`O pRCBVƍhpRǎKe&9l/]?Pb[wic<ѣZN`?;1I"H^?dXd%D~}{Pak ^(ٲx(ls5Y1Y08^nIa&Dk|(?+.KnGݘݙI{gyRyLKARA8&t(kAy$RZ=O8\Cb2E(ʞK32 }X=A^J;Rf(Osou0$2Lٕ6] i0r frB%z &o-È\o#QV]*h &yJֈ3ApG U*InI`nޚwڴ/7=ǞO)}c-InT!M^&hz?PT'(*V&ןG𨄚ީ:ճ0)c)1H6zMe\3LVV;[eRQF~@c(> 2~TniRCSսY͉>dWFIOGPx*3af;=dQ#&\BPI>y u\G"QT*@yT/jFT^ 0jS.aQ;5iB_XOC.O„De~DALo}su|/J.BĪ=8szbQ\Ga¡:ˡz,aw(LdT]$*Gԅ5yATVx>!Te&⑕P2Zx,90~V&A DEӋ:wJq'(>aR^-">T7<-HKR٧e;RJuMG@R}|]g9JaRY@SR zsT'.3&c|b >TH?T&/ueRPN/R C16E+ʡȳp?joG2pXCSTeSŶ3M;yhXXͨFN@,]t˥8me`* J&nJo{FI  >UzyZNtG3xz>F$fa*}3O&ad餕=>dI`3;ЫWrTi7ATh&zp# 3MZL444ܵWcʊd6/ $ʑ[5:/]jE¥Y2JaD IsLEOTPMɠsmit"k (,߱WgQjŝfFvOײ&^#LXY3#Rn%l^4cCdJFr;`_ϥUDV"Bsh D`TQ[^Y o0dR%3zxɢN%jrwbn}W@IdDdVP@[Y7&5“8isN7@%+bh)(D90incQ0e¹>gE|'ݝ9w0J&!1iZH.v%[UhgwK,#/ɀн(yRU܋\]y+|lM~ϓq@@Lq.(jl'xb˓{v:&?uϼgt߱~ ,:QrIkK;*aGOM"aG4svh QuV; OC`1tU6bWa'JQWr1F:CrYC?"NJbYi9_RS&04ESAၓ&ڹ}xܵ&~/WZ@b+{cUα08E;@%Q? d pN94Z6sv}i+߉{(6`ޘ=pz)*.vOˇgaAdzu Ŀ"뭜ے+K211GϢ} .,1>aLED-KFV@e6pYW1.(\EM:Cou @{%]sB&d)BQlbLR̄(;c'pTOq5k. #kdu,т}N$H4M,ZjIRޓ½>KPtH(M'*H7p %~/ (% nfYI/Gm6<)Өsl}#76f6D2%s41Pȹ}u=;gXtFu@N%k[U!Wc>#֕ic j`5f8#Xh)'՚f8p܁?HtpWwq1LY%UJ8pLX >4NKjEP/MQ|ȌOX+lZ{D2bSVVaDY]4)C%^u)@suAB8e/&0˜dbVج&Fja< :\1UF0rTo8w?rjA6;DgԔ\`%56bB>ƱPG&'ULYmRx8.zRYc,9%)Ɲbp>9~3%?ݬ:,nD5d\4W^>ֆ SVM ^w8s?%½g8+&GF.]9{T=#% L1&:hFL͙4?`ue63  BPi>wiVv) \Ej{ʵULvO)$u;&Դ"+i| m WG!j"." Jw#,5ΨM @QTE}|l#fcԏPA1o/o/o?rw(rjߤW$*:v;;{ꢁuw}B5z}aHs1~X6Qsup~0 Ǒ(3+ W常5Ae=<ޕo|e ?S>Hџ17tˀWd @bsM;Iff~ԆHWBU({oPMh$Bij'YZ!z虀:We{u|_5v_^#ӵ1^lڲ;=6*h DZ1qmmYٍNb؁6Kgѹ m2%K[8EQ#8˫,h7E%CTڷzBjZ*"VR/Mjj%u k"r}jiu/x>Wh_4gg?wƍֱyV/8(tJ\.*q7+µeJQtĺ;ھo?X]\c&(9| RGљ|- }H")ws!7x_OW/KzcR7gDq-f )MYq"pn63 4`)L="ٗ⇩{ St48&2TxlIt 8}wi͜Aq|{Ia. \$= DO,4|jŔ0y6-8QTp4r=(ϰzA;)HC ]=MkA[cXlW.ʒY>b 8U狩$XI9rQ?<?j1։=+ 9/|h`B[٫6 |z pM'xٟlV\a=M"#/=;^|GU$= ݭ[[u )1G. e@OYsЙYAP*Ҡ)tVOz8"¶ɗI6l B>ޡȣ H *aKmDl(Hi[R@80&`rϡ,w/^3HO۟y0E WSˁ{/". _ice6sJonm CO/@kx+ 03 j J_ Z]\$Bq>Q." yOEzИ}@B9D`gJZ2 qhZt ֙(Ӟd_(OȆј lUn&$GZfP`>fVБUMA6[ހg`-{'3tae$xo cˆ ڤoЉPp$tu}'-︬͌}u:&c1/ެu4X +nt}?Q1_v@Z%gU>锶.0oIC`ww߁x >'mu]6|Ew>Q}Kbh7i!.!uׂCx7E8?) m۸ P__Ka7@qTsڦ%auld *.rq-9y=d$!Ix9T5ފX(ySedc3<3gqE#bDyǚ;ƅX*m;69/Y 잉xOa> 1k>'18̴yWvVˉ s",βjm#Co0TUY=^ ea(^ # h]َԞE5A9: 9LSj(Xb O^ n]n#jn)c?ug.EAF!5!󄺂|K)\.˾VL;mY)|N&BcRZُBgKL : $S|b4Ӱ9Nx\5bvQ~c'&P]S=?9Ed}Ʌ\ЖTFז֠MXK (jckrQJYG Q J6|HJ<#BL8`wfXd9%]?9npH Αbo{caNH=;}r6JA.>Oe 8T+1u@HtmRHQk܈ cسa;$-]M \_J 5[˨'P:ʙT+nDl1EAp^-҆_[ 1B ]EQ@~K2]ʞ RQ!'=+#Խ (0,&nFJ2@ QC4IN Z]Wz _BK/ I4+ Z̍|U#i/_%e/GZ9w={yajYE׬9ڔWMC襾u<.%py<}uQ0~:*СCoXKCwc-U\剠P\G,_d}^*~c[UIv/t׿~*<~UzuۙG3TA.+ڟ' ʨ=88oTy!JD@TZo%qɞ2n]s#Zku(aH':{ɷӭ5B$xB\aҺmd>pƃۃQy80! Sm46=H:>Pn ~ AɍnU_v[0ZHuR XEm{ЎPbGr52sʒ>w1Rzjt xk j ,y_&(/5Azi|Hh>o{a;0n&8?8+8 T+ $RԠ"m)MXG:Em @.VFaڥfV$v?"䌼v <V@3lԔ>ѸB@%)пGYW_j΁s_k] _@d 772oM%L}9%my- S1 fLLmO % h>^IՎʀ3!g&r4PBNy=^c}_N9Ym4[1SK{3%&J΋<\;iGlL2aNtR瘺P.SH>kqܚW1٘O-1B}"C|TKQЈ쾿(`>C t}-ZOC=.`Qk2Dm2U=FP3&#G#X:%0-hpf>ŷk*ÖJquܟ12 Enc5lyժ;FRs7̰d3if N=w[>#]'!9ţ16dE} !L`cͥ$EcV_otXVĸjj#Q,.ʾ7>+%#v/<'EyPq,5D4={;llCK.zl1[`܄Q9&R:߶7OX̩w?t<,[ -SK-[{mb~0Ѭ6zw4ބy&z+=/SHRH+iƼΓ:=ygrT}Tbc3%8@K <)X+6^)\'4L4 waVX%UO=$*1U? ) QRf!/@Rz/2yx IguluRyte K[vic DH֥|6fO @;(lxQ,ut1|Cp5ᚭN7+%ne_^GF [2Ć0Pv>.*(&lڒ^Xv43&%u¢"/g>r@zUJ=W o01< .W2sCv1eZ3+cFը_1i,cnF3 n ,(:"w3UH\pxmp,·>5 :ddܦ].U%m8.4j{o nhϰK,D*Uꪈzq k6 b"6N]]jteBE2B}BƋ=I)4ygW+Aթ6vg z=i;-b1\#vRhnz!O_ E mLzv&Ahq糫x %͇cJk8q5#/MS0UlZR0@O2 -,i&0J"%V G,ΊWZmrpT j|6J[9}y=e2*CsH9@-<2OVtA (_ʲ?:xy:߱x񏂻uǬ\OB" |"9w27(Qu1T HB qüɣo&0:1tXuVQoCԓ8N8#z[!\X\P:fy7ĭ~ܼ??Ќ̹הy6% Yll؅2 {RKŻf`[i9AJ,$nC!<Vav liWm&wE5{ eMZ֨~d/$~2 f?..MjfC 'ءO!˯/]1w)fP8H}ٶpXM͆V֧!{j玿' K 7L5厘Ί$HVdαbVɮsA:FY0FPZ}јO+ݥ/:. (*Y6?;KMБqbSf&JeNij+XB@lJլ2`K50! Da3 ="UeJr&G8p j>Ծ>꼭 ы<'+S9xfw6Bid+?~_׿&PE5H\Bm nr;hƖ;ҹ dm(M}9f`b#W>-I7&О\~fw48_zl({m!bTkw2#qT1<\8">x]ɠ䠔'%C5cE+U\Ap,Z*Bh#5Fftw~vMȸrtfPC0 o5d377$ۊy76-8 Y\\w$;Ý NzcPAh#P LP҉2$񰟞 UPGc$Z"9~g.,[L[MHc:5 >؁;01eH*Ɵ36sI7*Zs~}Ǎpޠ/ u TѠtW9v,21Ն?uQ!̤*~_ Ԭ^fd6cތdfbV%raG*),2f_  |TFw8-s::p*_KǻniF9jP+ucyJl4rƄ %nHj E1Ra,)dVy0 5M0hNqsylܻ ذ U~yS73EuKԏx8g?ޖ,25%*x??ǿoן6J{P;$+WVtԴܣEetk zqqS gCT+6%Gm0ܚw'<ޤ (C$ߠBET]OLS C3mYq|h|8 _'X؎S"oJht;-yZʇGTci_"pXЧ(E%9!y{ޣ m2M[N Q! L*)3!:JIL[_U_Ja~gމ}#L:Kq9vf1=$̓-}[9.לuhRbZF",AC+A,bS7RQp:B0cJ>% .j e[a\1hA~' %v@J"֞ Xgiv&BHANz*p塚H a]Ē,[`B)H #?&D1F$(ۋzQnH=GX|,P ߻΍P=a*c\6Υ>0\Q9o;EQ|Ҭ,džZCFHd7$Զݚ cnKS"̀:sx1gsAS'BO .2,\@(mr~L؊~̞pPZ9}=N!4bL?JLJ{s+n51Hc{}c]O3/@RD%ͩCt2rcԃ(M޻C>3Y]>_ VS\/=}.諚LeU׶}JI_7ޫL°|s*44eH:Ϝ6'6$pA3x9{06-`$LJ)hƥnHo'JRĻ 5o]_ߥz;/B(VejĠ zB4@shn'еִd_T7ԄJDEtii+WSHXʼn xo `Ͱy'b0!ܺI0~± [#pkafȍsNV~wSdU{|]Hk^V!syj%Qecȁ8aƒKd۾GRl_n 2ֻ!anb .vR`ɪٞժe $5A)Z< žq^4U0j$ߖ N8=Z JW"<[;(--˦anB%s:$Nndfym1Xkn.M84dfMB;oWsiDBqUغ,+Wg ܉9(>LZb։Va>  Gϡ/rI$jRp'9M0 vdՑ?~ӶN='mR/ He G΄x0$0K\E&`ZJGwc08IXƖ:V=Aj:<2TZ*-ըx# FpkB)PqC WO@dQ"Uu=^6 c:ƽ(TOtR@v,OdH!fMS\xkr ubǢ_#9c1:ko ީ 5) Cȥw <5 ]DjD콗<>9)'J C ]s>c*K@x?v[Bј Սzb[`heN_y\IE%n艨چq˜!5c&}?cSU("znJ!8S9@2M~IspAGSlhy6J=Z ~'Rk^_i%o2+<&t, [ P,Ѵ9PR٪OiT{"\9fTKGlFlZJ^)n `D{rTxG]ƃ@gVl? Sw [{ߛoAY%ݽ MfkH,,d&l2ZJx0 =^>o&Y]4oFt׃12Sw([ cmR{7rC; j'tnNAn$h#1 s~$X?36[Ջs$]ҘNEK.7'ִΘS, 1w ,ZEڏ}0jۍ7dSW/Ɠs>5*uaz= xM+.۷Qk9e~.Z@/dT:#`VK'jJpN1(\28c::aS($Sa $H)o(em3Se6_ p8U'PKDH(sʼd_#4ʫ_6Dl>deVJbf5_X9bk%|뿘!AdAM>=8|$M/{Dc~h72tL.`dhĦnX{YtX#Y2@c#?AM=M;YGڣ4m)PjRNbaņ&+> MSԘHBA:/X;?[c7T^y'QWet61e2i50d5nV-Uΰ_5p֑wkJQ z;<@+!\j>jxo9~ ФF,S6Y'>}"9mGg9.3;EҤEfMhKš*Vm3!6L {9qB>RW9q8%I^ɼnEpD^ڃT)?.xu}7Dfu6TٶT4z| _4[3t{ab\EDHa5J5To2q,,rU:ΘwQ=t{LjN]pr~X֝.h,']Lgvg~ljqqf`JV"v#wA!Ǽp?|xR"iqs@@Z,87ѺyA +W]{͞hFFc6mNlj8aju,fɘ^sAY}e])G:ogdYjy9*%%Eqs)H<Z5񈁜whB-1IQqT7KT~b@YZQy/uRٽH_GHM@˜։I܄n+x@s/.UZ0wr 0 F1Ex67 'RYloeL6oQclJ+rL4DjܟxĴl/kuuL YizkcXW\п!4 :WR'WOT6O!Fyºn+1W&Xte-S#eaSoRo9 }{pGT>"xٽӑu~˺3F\ =oԧ\.Iciɧ: mS2WՅ,T(,-Iz^Ubb?tXEha1;%,27aTx׻>7cF}^dBYCJ"EuI &iC!93٠kBZx4NWL GhS.-9Cu*.O}HBfy\V'L$"U@OK2эP-o^%/ֹwqӢCTm.fdmk3Qzf=[LtxQČv%׳{0ARZTLv5{KRY#ɬHmv^f2m:.Uu6EB~/Kbv;>O5w곤 ݋L9$Le8\mҵ3V֍_>sk'`Maxy[5j }uM6A $ږwDmNxh3-}6~#œv˲m ,bVvN,WɌptw9@aq8&Gl{2?~/ށjlt8:{ 7:$o6Tʳ{*J弧n9Dp'lB1B?{'%b3I8qT7k _"f٬f5"_~`8{mMF8V/Rij QI3w}~+@!\n.tXHg5¢ ??祙46v1fMf"?-M--Ma #f9 s]F5.]L { {u3w'&m5<݅ U-AaadQD? YTJe͛VJEGY@I~TQ97 6+hݚ8V =c`>;-+D岤#/QRS$6"3 U?Vw#pNfNbX ՗Y8h&ꨛda74 L qk?S,者- /AEw\]ԱG~t1 |\c,}7R?77NGWаM3}IfnL:"kK_npCstmr7U5%38$Y2ࠏ90-e_!Tv1'$;/ A_&, h!F[vqwwtxNJCqd4p/[f@ o\$s9*мl\7Q1wAGw֡mE\ *!#!ՙ[yʯ7)*f*n:sn~\,ܪ.?qDN2y"DN;a*Sa6%Kĸ/as'a#8%XzS76?PW) 7e' dUYb1n2?޻' N66u85G|˯.C0$U1ǒCfVſ|C}N3& {\Ij,bia}Br!Qw`etSv n{e:iβFM@zvDgflXѢ'Iu,%^vY=:S̫l^wL}LrׂD.b8a зt33axG qSB IDIƯ вH:%12(=~BKd16۬䑊ˑckD ve^2C=*{RQnj+n;;R` {?~bI}ny=ƀ=CI6˖FͧRHảhY}rN-B[ߛjCӣoL6trR3x0ͩR}FӶ/Z#NZ-6M ]$͒䣛vgg]\Wtlo|Cqu>3l\fFC6-vXREVup?F0A,_SZns`W>W5D3|$=x;"Q$WM)Q.߈2Y; ft~s!6u0C^?#P E#FkqQY& t"~7 U}oG7[\c_$P]p,( N{Oዡ t&&8;k8[t|fEBK§)2hc< y߼%36l\x`QmB6*Srۤ /£3+k mj5 -&?k~lԬ?#x<, ֕zf)1+0;&m|W|<%]yԌ+pʝsZ߀5MFK-Ǽ.ӵU"L-?jv'Uĥ*~&HN+5E`kM_%L|aF5{u>Zqz6XQM;+kAX0\e:VgKcgzjXxoc朚of׆lxy񺻘I0YL_؂&P"]AV{T Dg~wu"0e-E&h=1,u#'ÂݹMi]3Վ@c W`kJ?TUd\.G%z꣍4AfL'1 Q b=`GRN"UfŘ&.gDQw}RӦ%z!ඎ DI.J(!T9[cFK)a{t46.8՟0ձDe4x=b jo8&~6A}h-ߎ!HG|+,"Qȡ0״M"k 97|,C)3%5!I& Ëq+2Ń=iG&S]yG Ao"(MƟ~.&4U4q [3p @K&s XâBmAۣpV?nٽGfqHi"ƠMVi ؿl(z$ĜV1[T反*yÛb_]h|vA7K!rӉ0X‘H'~&q Itf<auG GwTF%_#VG6$,In"b|ScߪlmuF]=HJpw Q#R>)W _(Lg;h`E+ŝ~>T#USy9Aēշ掑,Tب(_C7?ˇұ Kt,A$&^<|v7%u]'9d~}/4CZ.tZ~DD؂sE؃v|nP[r}B.DN*-),P̓6`E {]uj(k:{5%J?b6i:v c}g5JWla?]YH we3. ƛG$?K*kVhnUNPxᰲ )&m΀M^ᅦK>pAl@P-ٌ7z.c8Krn@00xUO7[ꛭf_Cc#| -:0 >2 -A>ica'M=0i+#<&{J76 ֞Oۘ&OcsV? .q@?3_8 / FqLPBlc?(%=7.#cΜz3|Kt^5)P8ӚR8.;f/*#۝\T{1XRErn(5̇L Y)vӱ/m섐k!W1^):n(1Xo3a+9X)wP2QRrL.ƣ$O"Ȟ,vjM-fb% j4 &AlGҙHdnSoR2yؿPi;uj.mXSk#n\5\1X|k[=ÞmFdPB N腡uaD#JS>æ vr xa3X̤>#O)-DRvƫ[j?)f!mjq!WRV}xbÕxSm¹4d TZ" \ W _dC8LI<{ɲ%pt\bl1c!QE#RY0²^6M#t )O5Y\8WV %c%2KpJ&GKR$8<d#@r4<T.~c:6g}־5g P$#ɵ.i"\d#D{MցtVWfJ_|Uȵa=.PH,yӋBM:M>ϠMf33uKl%<]tnoX1։\`q]7KYN?8"z~nҢUqY1h½XWFu te&j748BLo(`I#||0lzL4WTw9 j=@s~Ef7L2~Kgt=a'#2<Hfopnr+Vm;gHT'\tG|B)'+76)ʟOxeBrk1eF*v/A(&n–WI]72`sV_帛'ӆKaJyOM+ݧU?ЍmP!aΚ >L̹HIu+~omu $Aa,nI**wVu ^$ 9];C9>,sQWN/Jsu}:RmPA`Ho[Z:ohRmn*0?S4&2I)8M#F&Jd8iuub":|=ĵlbÝ(Q 6;Zf@# CM!|f׺;z6F˙"~?c_HdPaV8?2r҉]γU0Ag)vs !sLo%;ϙ1))0wVNc7sOl=2BZ7ϡmG^] P8\g7YdE_WD|1&:D~4EHubZJ&"I}]#" 5׵s3`Ж8N=ˍE" ua:nkG < ]-OtR(UNvX2g%ɿk)Z;$>E03I bS5;^>2TE2'emp&9&Nԩܓ&ێqZ3Q#7uٓfNyiW-?F:;q)oWŀ\`(UόY r_^5G.z)%AT#6j@u?B) #50L%ƅ :mL} Sg=Y Y`Vu_qIK]*FZVKId3MErFLn͝So;?xYJv$<+?ڎ<9镶W(Ȃ\C(ܺ&Zf2bwr#~5 6\f Ze;G}p I>c\ 5L06iTtyp>%Aؖ<{|Wk:0^,[*Wjt_՟*(*JkzkgyFIM&wacڮj7֥ns%3L hڴ"59ɟ7q^8ÐCwռi/t`kY o›3$^.@͹nVSEa(inH 7uߔ3gv;obf@G#όaֳECvs,''1tۤFqسM]P]+1^nFB<'Gzw)*NiíC8mRG'tʍT`4PL]L#N+&-18χhn6,s'ߓueb8٨Wt{1L4G#K|E >ƆzuINaXTT o[@:q-) <Ӛ>; Ԕ'iJC:_> Drד <Q isV z?%}h8 9>*Vïq $Ws^36- l\ lϚQN4G+C>ܶx4Fl w3g/)VHmy f. }*Vݱ^NVvWnvt|>r=y*p 4^JOfD)\CKkDk} P/(B,GˇP5ޒgr[s0O?kmB%j1,0ř_,jU /W+u24}|]'j |& ,݂&B!a|V4r@"|83ay]>f.n .C@;1 [úq^,|&DX{pNZ9蕣ekAZܬ %^!uɘ _Z[ G{%[)1m/nJ h:ѸŠJ3na9pvzVןnJE+0 d6$GШ|1[o~\[`[I9q.xutfa:U! 8e_ PɴqTLs;H= לeM44}b޳Ǜ.[=)мCKѠ5Fe2]ߢ`twvU֫{.S&Jڇki1Pv!Mrh$" _~y}EK~fLȨC*М徝DwϹi@`$X"w ,jdڠ*9mA1Ŏ8s@<,ϙfx%>3a5q^Ѐ$fP<2a~FFM0%"C 74y2"Ag.,X} R\Uq{HωPtN!N,H!7 [s\? J~&w u*\atWR90$݂tMnho]Ρ. {iL˲1b5B?g+JvNFU.Z8Doi/iWzuo/ B8HGd9!cY?3*(@st#Jyh>L=Yv8-i}RÛ%Kzy ӈ(QQ? SQlVD\WS^tPmߪHλ(Rg3s]H.rqX$_OX1REų{!Ov(}qz!NX!q0aLe¡L}Zy\x3(-/cl@>R ii6N ٱqro34i%+J\'IJ( L^$:8$Ъ>l5an) dVD6WN~yn<"]q~PjH3&6ic<[0>?OY.07i瓞S2Zw6툀q:qfYuzEI_/pd'&fAD&;m(|݉;Lj}!)K"5pKHleT- ́?VFM}E+V{32RFGk]Ľs% F}#}3mȁ j5Br&TxG]VK܂:[Q>u1_V,"rtQhLN5|0$74#eC{s>Y]/:$E||>"F'j%{ XGaVc&&ұ(@Q GyS%F@s3tSW1;ACR4ꚇ+Ocgii+P0c%^Ö%7xsS;|SqZ%;e\tS_/@R1@rXQL43B}%e%_u#^@5-:̮WGfEqeԶWjgC&|ܩi*{rTH2'.֞u6+=`1x⪉ }#5BA{{cgp\0}.Pi.:A0>ی[.!Cci`,x 8 h+m݌ #jrY: xHoDe@KxW)ᘿ}(dCJD'!|OϺʸqŲkwcqțb+R5D"д/. t;.(2t;o2&:l1 yKQbtBLǘk@\%CaN" X|R?Ctf'E:&L\WGY锈x|y:v/ a*miӫjZLQߴ}.d ."yN'{((R S{&uQxc 6tHa6 l4BL~ OZ {:$#3H"HVo+)uqCu<ìsa*,WcjYt7JCvsN{4h@[E>e3MjF4C]C`'ۙV(;qbbG,#܂Ez X +!q|Ӳyn+voHK"|{71 &Wͫhc=B+w uG E8[Cژl2"":ħQTR@1W>S~%p%R&Y}ߴ+tebuc^+Uz`ͥvj4 菸=q`q;r-?^x9CF˵73**V~ΖXP?&ܴS!˛ H^eo3dWR_r;Tp~Ǘ|~x/!TTWf0EMNe\*̧ V p)]MЬdݍ>S8ePUI v6B)0Pnb-Bb$EV&MlU(9c8]!X0 $Jb8;L՜P>?GM,Xw"q# ='҂`qI* 8_(>^^!{-Q^)H%-4m&;y_D+FR#7FKw֊EYg}|b&$!npq,b)963 "&o}HeeeZۜ!rz 2 zI2_Ӟjj{ |9g*ֈpY}}ڤ~>.ݠ^4 wy* waDsi&[T߸C~인<0s9df@'j5͕rлoDNH?]5}Qɑtunى4l=I+:Q RXJh'1q7I19f\D1] 6?y` ޿۷ yb>b-^nF?&uV2۔%h.c78"*2+΄(#^~ס~};XXr1KD8JXMzY 1({(]Gsgq'X&T+BFp)U >O~85hSnͬ}0#:ޤtvN !.;u}KB'2=hA67VS6Zŗ}dV9fj)Η'ͩ<a/& yc, -|Ul%OՍCW{ 2ü~ՓcWvY<0MLv.0"ȴ"1FdѶn_W0s^D*f2wZtDS"M?"F -()4;tz^yߡ(hh&Frсe\˩ވ11ۅQ1r/7x:'*\[4$K;U$Ѱ&m6R:y.FG\{NٶzldR$Ӓ,J'4Cź 'Fߣa<׷[n5gtI3K=3i| Ӏn Ň]oᨽцiNFRJ]ׇG?::_GqZrPރpHpIM6o]=#y.5hFNÄV{򘽠0Vbj#M};څѠ7x dN٩bI.fywjJN39%xei!ST]5VoWw g~-'"K9̢P^c(LɆ;"{4ׂveR9F{oZQ.G룇?8&"OP>v.Oɶ,\fTVQBDW =C}4S·l2r뜒X׆mJ<ǧ::" x2ԝ@kOu%kWtHgVZ^5G`X:'4Oæߞdsvӡ r~er<:ꔍ Ԍ wҟ|T?aWR`L.#!w2DcJf»W kщK;JVɧvNte5Iɔ-Cz%se!@Ղ8C|0w`t6a Oad#er^C=d4kK{S, *yhHBf B&$x0nBS XqW39 | (Qzw @ϸy]Z˥e1u}eko]}eE_R0wP騲ǬE@KߑJD7j2-/r)+̤o`'O^p4 Į KY?mT&lrU6;ӡ{ɇcI`3%Ob.4s %/(vaQNHbl]g*-x%Qws# U0̦d)C0v$i}J[|1-t֔'rЇs!쳵~d~JU{ey I޷Lj9ՎLIXΉׅĬ ƫ}p7X:B J<C@ϊNyQd}ng]U29kaK:y~gtZ$gU7ˮPbB+I'*zs!$C7,/NVTaճϴ p*Y|!qAwmbuXK_ڈw=罉 >ihY%aOu᪼:k~"0dz+ =,TlnfBQ(be<xiogT`ZNs>?ݞx&l#+mwOV7-ԀWFQu>g`CsXA>}%NmuJ-Z ʧ՗_8L%v#exk bv=&'{nAXa`]C "*[­- fV,tnG:JOZ{MAT" lwO/1ܟgyPI)vB> |$VlQvwfЗ&cN' XE^sw"&[| %ApdxVWZƮЦ6K\$*ǫVz6mcUu ֞ز1co]_4M{ErB:6㺇' {1/rv!'h/AVjq y̰؝.ކJ.˒R|<Wda$nX &CbkBq fiTG0T[fn?ۇTf2B3Ԕy(Xg͗p>>Nt.16rRӽZmͯ7p5ql8+9zWGړ{DlβZC~rͭݽ +68uq/y6}D\)INWLO3ђ0SvD<+5OjW pON1nQS*;@Q´XĈ'Z1|viؓ5vrG<0c":Ɨ :pJlj='v1KA̔yX?,MC09[}%[fA2}ғz2͸Er#^$`&= ʞ?9 '#]捔9 i-. N\ZM~D#r <`Hlzxi-MJyKۣ92q`=o8'=g?g.tbSA咗&mUO|5tҶ/R;|\4> g+8U!nc_z7_-w#xHRw2R2IgDv^kU"@X+{"j\: T%&('ܣ8V݆̉j )=RvVb"u9(6%\- UZaumL+NdOרZ1Yi~0r9dy7[ k 4cPT}>.qd^k֛a\}1$QœЧ{D(Y%Q5;lSyR󸩼[CәȪT'b*[502^4##'J>.<*^3} 6[G8f_I=MNjO|ѷ "a}XZx(Qu.'31#!#iH9'}tWM̌$I'aՙ!1p3P0K+8IG.IIEcYJ[5<^{lB::j;^&5%EjX2pqX&wvMhԯ~KE|Yb4uC1ҫu)V͊ ?Aw?eHrY# ل(}`}*LHJZnE;`|$P1 51 !KJX֟ {;nݣh-ŗtRI 6)R`F\ŨDrtz(l/nU o&tGnLDP'>shtx;FŘ"ɰsqN12aaDF9ZL&#? 79: "Ng3]2Tm|6v0Kaww7"/K}C?2{/5#i~\>ҟ$xz^n*M=A1iU7(lH|0f;i0^e+Ԛus9*c"';[j'ȩ92Ldg[onxփChn[֩~F#Ok#辽4;|.ئ$/;Wȡy\4C /kٯyHbp#]Djq=>]O LAFr=z&y&#u5VD%QėKQY?"FȎsT^I3F^>L1lz>;4Y8|lJEcXs@V-isFNEc!׻Ӻ;H?\Ϟr c6AUb[9ˈ(z _km`ST?ʑHl˻{tS  iZO0X<jxfyn@4 BC^CAś\0DssuʨKq !H22|ʾ=ax\BgO rw4ظ[<1j8Dc4%(ڐOU'*PIiדtFd^ڿ;*NK$;u.!Y^Ի7rjG( K"y ^Q&ҏ!S"e:,;o B|乃b@@Mpjnzy'c$:KAj{%+ñ/~g+5Uk2O/iq~T-ig$,eo} X4 XgY75L$*u'ʤVw0ݟiĞ_fMV Wdw18 N<(HǨk&eG_~&ޏ mDɷ4cg?R*JHvUZ0BJ.jKhH^-uˆ1̌6S\aIWnFD"dAl3o^VXI<?rA96֔?y蚢AUT`c`h19{ǏY'A2'4HIKx\{WiEHw.&)^*M^t֤tXyRug&J߂Nچ&^Z<-4#5LΨq b|qqݎ|Ow2G('~XUJLrDY9 l֠Ov. Yf ٧Uo,AL:czŇVŧ{_M1&+Cy{Xϰ1exםw[NA_֧oY^Ԙυ`I0 !9A`(L2uT[i|Ř!HLߜ,TUb17Lˎp0 LZ}ZQ2߆Y< ^ !_C{pO n}i`t5~KVPB|ˉdpY9va5gi܆ё 62iU[:%Ʈ*J)X<?R83HHc\[ |kުg4JVkvCk.DlܑF*$-bui*2`TwNr1!UW2N|1<2c֮c,!fz/+⫳ gZ˫j$nӽ5X;X'T3uwgWw U0Ɠe.Ym 2CX +3>oU1~>0]ye<>k"Ҍ0Ga|+6`w&4=.t ء`Ir﮻bLd77[.M1QB؍Ji4>'Z145ZrV\ H$\3-;~ڭ]NG$1SӔ>-%zۏϱM ђ7/x;8 4CqӔpkᔸ|6#n`\1^2 Dy$-a'F$T2gPYȴg'q\rG0MZ|`:rcvJ(i)_tEsh`yw fGKDq ,[6rx+b"/H}D˛ q^K6tOCĆ8 $=H&'pcm :<;: <5QJU>A49eõyrC(v=Y }IT HKu}c4 G]:A8G"͠weD}dbe䮠ՙskL-t2Q}S k=@:bƒ:̀`ZmI+9ÖpEޥ+l;Ub{;2GEF(G25ƾ*cD`糂#+ۊCbVɣà-ҽŖw.;U!W2sf0H>k*ƫ4s͆DC&Fk+k0)h UG^7oX AS$u뉖A@,$ >P{~nugV(;Ku>= 9?buO>OCn2.JBa.Uܠ\P09,wƹB(xd`1*avCʳ:S)[lMmKw2s1±b 5vA@!WG 3=gHam* ѻtZ"ʦJ)NٞdVt:J4PP*2θC|\b 1<"DF!myT+8OMrlm)WS3-GS5G{wo-qm׃JUh:+Behօe21h,fIiN3=9eǹ}F"8;)MӛXte-{T38 Zl/wG Ӝ}KhǏ_~ǿ?˿??7ܭȏ~,,1oȟ9|y'ߴppbV{7ʠ#P'%lv?m8> = e`t+-Yy͝MrV{i%UοZ?UT~KmOut6yXVyNN) ;n:<}ˏJxȷػ "ezU>u$`SHt|rT b6a4`'łZ3v dřf fFfBmFRWofZr2>7+ΆKL"'١o}UaU*΄ |T9A8|@KV gQ/Yavl(1߅lr:dGP ™]\Tr gA_ԣRLf\az(_wpkBry_kU򶉤r2ŹBP=5#ޛs!?*RPXc|vx;tOl`Han{V>VqAr:H9&-u Q0I#xEJjJ+@/ )㐳80`]غ-aԜګw^0{GxPy`4ج{_ĦoVh8mmfiN %KoK^L(9PMTJhXbꂊEf!Hu '_g1 TmNJ2UB|qX8K %K<,g ̇WOB}ޕ LT>YYؾB~yԎq1 3\lyAZũ1N"8=f+{J!J۲hv>}I,C#0={BV+ҁ`(Dq ϰuz}EwXrV}ڎ*N5bXՠ6u1sE+ s&ZK'[m)+:u`GMo(<hrD,STmg\v6&J*B-MV1D~8@Nƀ3кuϥoElTtON>,v.!FJf-(裡K<';U^Aud{\xxDu;՜b@Vc W CpǨjex1 !Qˑza;>5<[U -7ӯ2?wqqWR "i͎8KX|}$YNԊD,1/=!1.77odzJĹaZz[$r&·=讐&Pct%V,";93U)JQ^ 槧k:/[veA'O$dӹb("K:j =ẅ́U}eGLx69cbӐqiu̮f@10y6gZ>ԝ6n8sxMa/cʣ“ӯHL)?5ץpNrr^5n}'';FxkX PG& qj&S!f{u/zbءrXw2pčZd򠵞)9KFHG!h&}7EH cu=jIZJ[j/hO|1Aae3xO+U{v=3=+p2;BfDjDjp4;ΜCɂ#X2,v}w!uYl!/LS)9'ZFe(Γ yz,dI`T- E dQM;3\2$#6m#<z&<#})e2}I>HBkWdm]g;*In./ᅭ5[@zcVm7 +s='tRlO!+ӚQUuDH} x'LL]f$q֊xTLfN#+2R(< 92J-'̈j`62Y͂8l}hi嫑=wM:-йUSzFPT ᖐ'߶ 0m,/rW''~4Dâ?Bή9Ί;2nv8@fƺ%Ak)d4^NwyiCGeB' J~akeҴLxt:`'av_ J=`P54&SтïW])bɳ9vK wG_񾢒*Wp ,Jњc:H0 ['[Ai~p%s 3 scR (vVBϵr3VBHZ@Lv2b!D^}H+3Q"Jsfͬog+πV#g q1vU#B ѾWR''N﬚Jt?E BP2 $^T/s&$b뻣A |Dt me Y=xV)$ޣ@Kf3'q4P&l m3ǿǯǯ?~[TQGWLD ,#5f<۩#s|3qŝFȌ%[v/0'U#zD #(84 G ƴb s']Bʇf3loGl9akr̅=+ :rtG}ޖAjlO-$IQ~cJyYۢZϟOID'HBKe=C~#K!X N+{z=\wrNI{ŖLB~%%)u>̫ᛆ#lVm'9utbYC!`,FZ3C]õM>Zl VD,NauqR=ɓFs(*"-B8}B1:0kUt9 2ϬwƤMH1_j2ڒq\)bH~D Hv /.;jrc;$ĜVJy$=7 x9|a6 4Q*#.Mo͛V1k'u:>㧕M3VsH<6 I,['ԟs'z͟G>O [ITKYgWrO#]'HOoisݑ3W"TA\FѩLDJ"&[s,= Oj'YwKrI IM01ZAtiB6Ԝ<źogWm?BkVyd&<_T%LjKMgrFD q/Ceu y `⋈cn@cUHlW+4j&YQN'̩}%UM9,W:HhXFx>ھ\]ϽχTFWWQMB?_;257sry̵ޮd&2dL5^]HYs!Xƒ0ryR7CGPjGZy@욢3Ȁ~G;b:vzN7B#/ SQ^UsXP+rRlkFix$ ӷ+O#+߫L7 )J"~~BY{oʧy19!1-U99WL2=*zl}S' RUL)a3ۯÇr A#ȫ2./;$mvGUzխvdӳ28&>h@, mbGEn. >ՙ:; Bj+ЋybDtTX12AM< \3$:x>Duiw W9P٥[+`/Ix]| *b3,s D.Ef}B9oY#>7yz1QJJ}L:Q3޼l;;@u_Ebh;&8B1"7\bg箧K@pVox|KHA'SRŢNN0d+ *6ّ Z`҆LNȓBv gO`q|"j`_'p1 rW^N (J{_)Ɯh;s^.JfE@uUڱȬUX+) npI 6؜LxlJ& 3}Pe]z̉WDf5s7Nz*2Ga$Z^,A$:efk/Tݎ}(,2u1s7heScTrrWF~]J""0Oc_?|?B9ح}<]cB\\y>?^Nj _:YD!nRz%_T)ZɸM+?6M*N=plu?Òa( ta0rwln5,\\`( F gqf*$'H$_^XD#J;9&XJ:ē-B(Q\r`9pEh0cĂ?x/?*u.8xۓÙ4J>_ m}+?鹐 .6TdDTmUG]'.߳a|tv?!gSZܨ eBy/쏿 &92>JIp Y=;[dtAz!x@ZN$uB?EM#bTQĿ| bn,+ªlkmy͟X@m}CDh1Hr g2 ; c|N~J[&>29DNdVKAwbTVe yeOJҢQbj4%UۣtτK"kKw+QX5VC\g4.ҒjOsD%F#(2j]4~!SQ\"#=2J5 6ݖQQDip=IqlD9G(;LH>,l8Gqot/h&y_C>Vs8k$eGn,b P(-0<@gF؟ri,Pd KIh5J8+]w\: ;Nd2U2~wynoQ J~ko!~H мHW4e2JG{BF L4m%y4Pjr*k@Y-Y⬧ GQ-ݎvCuv U7v!]|^ I33bk|ⶮ!SzVl KХΦB(޴򑛈#n3E3u>iǚKg!**8 9^TR:@WOLw޼>?S0g [>)1xzMD<*fzRi:dz<@|Eʭ{MF)j!]A_A' *㿍O`M|AzXB捴u1s%WI{Y}:__<[ O97-ਇ-PA.beȽf^?{ ֙fq"rI ٘$+W~ٺE&JcLGeGd:12;cPU]Epk,g]r'ySXfȄV}uZV0eMєcL8#nFGC1.܌;}Fxw$89pڦ} ɑ, u^$v'乞L}xvs>ۜ }4q5g  3ن_0^.1M섹7-@A1#ӮK 'F'7[ō;w \!VlyԘA,䗰 3dRyho>\(/:GUжowY&ފu`)HG,qV͟TfFrn0)WEv|sįPJQ0tƪZ~m(cktfQC^ՍK^9 PdfWRB76L0V{v"3_9˕ Dh[?#uT_؊O3E<9 kࠚERL" YY& ?kCK8gg۬V(."SILTuT~_n1*|EUˆ?r|y~K}sF3^RD'4h9Rđcu[(՗QQ"8cVHTf9(WJ۠d]*r904(Lғ[qv-ҩ:\ G 7OoN4p>q `Q!^Ie4y:DK/~ HMeLj8ni풲YL,xEӫezs=!sZ`T]2kI`Őz-,P =U Mt> AQSkK#*鿡ogﭷE;ii^)9J$-N{k(! [w>4@]t?ϳ4"Ћ!uT*LЩ(;W 6g=z< ^k #x?iQ;l,ORFuagW@ ׁ}p& L(7ǙyݴAF4$6]a^\WE42V@?tՖWZk>9t-$ q ~2sse#z{1qVNO!t'R80EzkkM%LwPbO˩,Ͷb+M<)|"H|xF`5{[rQ<:ayW3Pb=zX-_c[6 8bLlk,o^7NaLyt6z0=ioS0:< & 0*XWD‰YP@h:NzCek Z/6Ft*#k*"H&:V=t">Y\Ǩw4h , 'P]Z6Lw~Qѓ#T4 tw∪I㲏qaZwN=?]s[^඲X_M/ X>{†{^^ 17<2bCFvaW\c8y1^dTFcVYTCɕ>鸟ҀIBN[\?ލTD@7X'Òǭi=5_x}K10vmdB* ֑4D=DGhعfETD*/_`U{" 'N* Qxaߪ|>>V OT1&QM`fywQPtdj3D3^| X+J8ʺf.mcG}CH*y4)HsͲ&&teʽӆ7aw5T'4,FG{BU/?J;|g~gjFC`q0i S .Fdlk:њ6a pv?*dEP涗ro% 1@yoVWX,:#2ݞ_#kaPYYv ;E0Օ=N<]vSs”HXu9rc`N{KB3[Xi#ʔ<^2+{C&IC]< }f J(nUj1޻b.WRG,38+'ZdEw|ꨙd)hh>LȦpy/ǣywށ!`s]WaFYY_ˏ !6g.|7Jy;Ii@pp pEa Ī, *Fw,Ԭ5*w ό5PmTLUQ옗̕U91 S"vʶwm@Î]֊wbl: _ڟ<3e:xsm]-[o&-Dl_rN v : #Rg %{#\bo_~MXIX8LM4E_~o ׃}Pׅ:YAk^Txs6ūs\wB(c vC͙:XV]yV]vUW/o '@t Q  5IwB4A([_N3 x B;r֎НTЂ *rcb[-@8YߢdRعqс_@906#.(aY$TGNQ*2)oJNi$iCQaz{m Rör4.gOkjIR^pޡ(k)G×ƶ6%@>$hC; 9 (IA~odֽj3 Ed zHUljT{ gQ$FXs rb#!Ll:)@ .^o$UM؋ǕQ+'vUl{B+#bӓ`qJbKK[>y!mI /]cO:cնGM|z>ޭ] QbXISB;;aHFPSiϊvj9m*YUShʞ_l; VT/g12ިN}̒[Q >2:(4&g$_Ai}?pEsf-9'PS^>'Dް%I1 Hc!;=o6 >pQ]DtpOBmM=ٸR {mv]5,`NL@3lõlěyl.yp.,iBUO?4S1Z\% -'xԮ.haլ)l?ϳH;Dbƃ/-duf_񋧞] z<> $58w ̜'wT: }b~;yzOx>>?쨞"^^mGG'۫ h) Y!+m062+~zדI:qh(4o>N$g?Dv3^z}Lc,ȔYl\'|[ޥ|7 @f'70cYڹA!s"#rV}!yj1BeN9,B8wiށfh}-Mn+t xO:xP"͉؈ $6q&O aZ q'S7֟5KW֎%`m>c;I%[CbTMsFI 3pg9',@%h@eY<|_ʛ?’IQF^cΘ|9uy4S\9yh~, h̒ wXF:' ΖԴ'GDq0 m:%W+O`A63AHmG>.-zI~[Us1}Ey|Q@d2Ӡ؞ ڐl59c#Rz V:/-PU]y}n1eA٬`8ʶɧ 9* uHXaov bLfoutWP?ra~tUE+s!xF}G|ScF<% ‰uӬE8?nM?Iƹp3Zxm^ b62)Oaq[|w?Lso W+dڇ'n`BCE,OԩobE;f%yrt㾻a%4РC© Hl rjYȔChrxY=c<{NLHLFJejf~,Xvy$DAXqD`V7'hӎEvV!DålwwrAIR#ٗT>YZfp#F.GZ,Z # 5 B\t&㥊i96I>Y^[ 4LMtpD.quAo ;-cQSӔ'"'^1g,%H.&Zځɕ1ߚY`{Xw9T?.^_Hx.`qhz/ |Fs2pٺ3#>OrucoYlefvވ/ gu3<G*0~D&EEtr%K& lЫW/C7t3;?vc5*4HڅC抛5WlnߝuؑA<4]w|lN+ mЎ=2a#(+=1lGSfj`\Kng/G1p\: [ {@ ~[]ry|>!A|o y?L*d/>HI9Ԩtseʎõ~$1JyD(8$>/h+Iύ1j:3myV2pE뼦b uueJ+`⒛oy8&Zl*g|}Ǡ }*/IL3wf6qvr>;>zg#G3g9l+ m/R, L,=e@; lEHPB?}'1<&8i%PO}gK"|f0lvڭ]WA hH@BHt.KT P 57)CP&P`uwt(XSq6:HN\q9or|a8 ;~#$Mu u3H&J0ElF99 K}Ư+Ocf=ᓳX q<+а2VRY.FIm6#"T&@wv,ۡ r*FO7vhzLcE̓:GΉ^h%TOyk:'|jqCݺ{F]Vyp/1f<"?$o$Dދ LlWʲ(TVq}K1x@21ctxr=;9d$8 Ya]IC}or>ʟ t␢XأtusZXAc:KXrZ.]ۀW6,!2'a &A,8KL9"zwVZɝr·[`W1+{ %dL m y/)"l{)u$ ZRu6N57Afֺ#.jƥ)Sm6̊M U\ v|12f҂t:(8Z~HI"Gܞc{tîfWTY-l*G dz &]V }-DlV܏8/v, ʲ.dF3*A)n13 lNnLy_Q$.PoCUA+vTdr! ډ'f9K1i%m=޳%vKKI|aukx Y&( a+W?~o/+&i5 Gۤ[vG}NF)f|ш D{27VJ 7{q7Y50@ ׊ՉuhRwWfMO > OJy:x@6n|&8r݀"XPFPIH}Öӽ;"ZKP)xlC@4ͺX[Lڞݸهȸ'5czs9u`%~v@,괶DJzn# @ZnԱřkDֽ{VX=Hl[,:A$o"XsXjC`[: ɒ :檔iSێ Pi?|' O85$TPI f{8ڮ( JBw44c1W7ziƝq$dT|Xol3/Qrf6 l'OqM~h} y[sG0kyKzCH2/͐V&mpPjR11{"%qo>'LZ~EdpqkA e{}%HtU"HfZ(u&||Gc'l3tpwQ؏>^"*7\0z`^<{kꆣˆ/чs7) {|0&G2>~(UzW%z&-8m]''sƱ}"="% S\"ᘁUUVEncq Ba gL.HȧvA>7u`!qfo#ߖX^ i"_H 5&D usC_4S F'?|ϐ"16!eXAW3\k`:"%ʚ7PAW=1tyȑTeŴw[xWKe˥sni tt]]᎛zW6F^(,ƴFǣ 7m ~*]{XEx:" R=g:K%0*ZCU+zQWyWr'ΊM̉v2C3jt۴XJ^ Zxa޶Aq×cx6eS>xSM$|ɵY9>\r}%B 3vpFJj~9J/:y3m /sXF`Qֆ]#pF?$d񤌁.-0:ՅvČL̛gԵb_p,o|rV(ޜQ ZF*e4؝< ]F8L @oJ)"1N6VCm)6.Z sOlhbO #ZŊލ=K,K^3E{v4͙Hڜ[wb#[WZ;Ҍ(%8^HS}>` [2Dw|%/8lW٣k\5h%<1ӍngݼODFX5=lQXqU|_Z|ZKQ+=;>@nckËy 1OL5Dr+?ÃWJ+ܭd 󵽚{dɴםVKKQYWqӰDd@vT`Ȭ8MU9آ& PT$F0TOm,ZHCN?r lӂ!k5Θ?T8v̚wη`FwM¨KHްe^!N `&A,ԃ.pnǟjOUܳV0{iSZRߔ@^dw]j iϲ#ãmfg\q&{c eׁJ*=rM[- Z>{4-tO*y@(3P+6K3vcEerZD trK]`ʖAhtq##GOж2-*75p:|K7+B0F&ɔF @'Xʹ&@ aԔe i.r{ndeIItwfU[ z ..PzEZ+1xn|W9(1)ô5$l뗿JMGOKt",|ZarӍz'ZP|hMR6kFDfR-]/RnF} hBX`me.s]XM*$6΀f=c]-VМQ%@iJ|D&(%θdM_s:IP3ҮFuc!+0/g˒+g6ȺE]e2vEkr`(S(V|T@\O ?HbTgoS^Ȉ<j9)^<97Q7Mnx'g&lFv,\}uv#HCd6mxTw\$.h3ZU]HR{f?Ȳ#;"O2}X䞞{ wln2nn]DD,A1o7>}DV]#&^_26cc-`gXBP&0-*>b\4%D?Nkѓ:GgR#$̉wFsb-4r Zˢo9zCd+]Q G /v2(-DnL@m~ڻ-W9N3;?|Pd_#yvPO~-هZX܏¶})gR%yJ"'U@J8 ^} RADF2D`I?=}*+-zE7 }nn.oˌB'd`fgG3]{ _9ٓ)rέ^*7ZOQ߹z~&./e}2˽Jb8My+(c8o= B Ҍ%Q!ځқRd+yj J#"HVhqToɔ5ZKwolTFe0Z͜Qx:R|u||>QsHVĥ@zT ƴ[haGUHqhX=ԕsɹaD5àʇVp%sBu)҆[J  첚83c?6e'Asm] *@Q|Ũmoi4T)6v+^7}PE!+[Ibإ(&r3fp9e,=io)%$,"tY6'Rg*}?IT'@JwTl72_|D5B_ۋy894nB=v*;U:+-+[[?O!4(5~WY|[84|m@k)TN+#ɊBݹFB U1 ?f RZd'&]jϊ^WBFS}Qo`f N(=dnB yq%%?1nޞgEşqDϷ!Mҟ;uI:o^4B\lӨ0O(39ITD "ىB.MQE'"f %kww=J$.TM[aoDz;1BQp58#H1e wg ơ߄oB,Nn}Y[=9b9v ؄%Ϻ,/<L<^D(gXlܣn!yb>o|p>@-GaZm7PK[T_#PiF^g˕Ѹ}бYϼ!Q!3(0t­O,󴮊1!i| 뎞1yL]&?P"x뗱M >-2\_G LV\G$EiLK$׍R<%)rc̾GQs +˛t4Y04Px& GÐo{+xQSkB*!%Ų9a~* gwdgSWtFkB o?__Vyks +&ImH'1Ltx(rlO+7Y;Ua^qG0WCREQo|tܹ"sDh|v( KUT#V_͋WpFvp]咁V>[ QϋY=-@\XFFQ N }0x7V-2ڭtc4\sJps3'[cH>-žS%-Z9T&N &V]H4~ ?5ĸfDeh镸m@FtK(q̢ځV)\u+x'\<o.Iu>F .!dHʴ\eJuLK|OӐ}cp&&7^-_1dvcP0+À.aqtLx dSnI>扊 ڳ8W5aZ=ZY)|f)[ 3TIaݏ]"[Olsl[ȡ2ص[M_u}MR1^6"]T_xmThccHAEaД"vUSN {D7wPl/u^OU[0:ح:F7llSΤ/bjVJq^섪Dߌ#̟pfͻ)lC=#I'"}Z$@ߥyw;C\-~)E1c@O&͠Sv2vR{*`хdt|gT~t&]ڻO6H8ahD$MhgE1{=Әz8&ѭ ;Y[||bĺ|lb?4@b̧؋Wݩ_G*0i$'j"bˈ֍oa׍ʧKe>98U~$PNzCMF:IFlfڀwIA$QG7},WF޷>Zɭ$ۤ'n^EJMv˘ I1[*4kB蔥h,hI׿{PfW5gpOezJu#+xe"e0|]~LY[W(FpA1BFelʗ}98#jd%5a ~,tnr7_ёCȗIЦ3rigL@/NdC.LӅFVw?}~" ^xzOO#jY'AJT:Ï$&YqJ1Uɍt30r;L'ߨaׇ !Iey2 }$W)7L*25ȁdÊν6X*KB90tE bJ*p{+x}if J֪a! xa9{{8u˨rIpSPak$Cwi_xsNlGRsZZ㚕ޭ%54yWk g,;C9\X,)nmIm5q 3bҚn}b:̹t6]{m'^m@ 6qMT_ +P\m\1KhJ+:Ł6)3R"P=dti[uv%6GhH?Dm4pBΊ* dInBfw8QAPXio ($=c%dY4_|d4b|sO>Q+M!6LpB=P["3%ܻL\X׽  Ç(%.6 {3J1,:-K{ VV :+fuLh/ mK 4GBMdz>MfY':df(WQFbߚAdgMLkf υݐP!r`*Ru#˘\?a|DB,|J+mzeS|nvz 3k-nLMF!DzLáEH78j(bý-'sh딃;l KyB1#rg:!ky:/{E U & 1bLȪIw_]#t7QNfb:vq) "BVeшL1:? H0cIϦ_ǿ_ooKɩ5z&5gsde&aR!M'/\{m88Sf\GcΖBSP+)4~6*t_l)s9qCQ]Xd9UWupN]>mEV5&ЛP}j16gO·/O9eiP5W9-Rzp,-oH#iem9Bj,Q~טѕa3rS'%:*Mt=cx܅ }2wc*JۏfDO@Oή,!-I Iu=ϳ'eqxR>Yk6D}:*.=D:Z>B}bk94Tx ħ\4 d@hΉ;RN2hC&I=בu]%p0#;<>a]B\5D{~$*#I CAy+Am S5U.]1&z:z\J'HG5f43K8 STr 5x Psu"b]4plp }4!-[0jR-,;{>ү@YD1WÊJ 9ѐ\|G+=M'b#1LZ?)mj`'.EfZ͝)u K<NLhYL3"dZZ=atOw eiN!fӱ!TD:OVvҫLFV\=v=֟]gD`!rC쓎عŻ[f*3` 1_+ג$eth}n@WdVbLPD?+Q og J&#ޛMjD%[a}RBpfvT_?-IsNe uEH8^=:g_wxq@ +t&"Tu@GT}8~\õ.nrOXvr)ZH8JGcZj;#d@I_&?\LnLXˉUě)eωb]Bā IuevDO)]>pLN9AML baKR@gp>ɮO 5FFy.标YbOeK:)VMvY(_X,EueG$53a{OY3j+ ~}M}N*Qph60UƘNdM`5a(}>-HcH,'tb-_P YQћAތZeJkVQBKdm'Dwvh2 PKϢ-*h\w|#A4FdXxVØՒݳ0htDQ@:FIqAG,(8o'"ӭ79 8HkLD̴\^ऴ#5`E~i簟P!zqr¡ zč'HG Q(2a GC5o3_\6\{iȯ1^ow+|Q>5ƍn F1@AƱS~.ƎNE5\AqS$9(xozf<Ɏ9'Lw;2pIH_p,i9(D9V4νgZO $)9\b2,ʊB؟@QbDcp7u9'gߖ^s-p#,m4Sui? JGv}]F%!2h^x,(He?Rk 3*Wxb,`6'jMVnqbEBcH_A8'ƯiuR-!=UkDgfGO 6_w"nVa"s?;jVH~Cm/>_]+k&eEi7FIk ZЬoTق2ĿdAlmۛJ&w#>k`œAJW]|UI7L!}VSKd᷋nm FJP->D hmsXFwdݳg+gLO6?5" 'K uv=u%RԸX2D\}d:~W?x)vMեzs9 cmrE gpHMPxq@(-3В.yS.N}=6>Jh&HoqQ`3tB = s8̗ܟw)G_ zNb9sO{DHZTslCmSr &HrNމmpԟ̂ScJ4O|^AdL:-2 ,ɘpe* )8Gp06L /{T~}/s#qjfx+I bؖc*xB! h\%_W~r]d-GhbM8GP]qJ)E#բS|"'x:5*G}'Tf tCF*h}F-,,tZ{}J >oå%yp!8@]{"Mϙq ]4IQo l EKj<M';JkS.&.PI{A>l2Wn--QgQx;V5 1Dضu9o[ʁSEg>Bx[QWRɢ4#cKn{$RZ›1r?/<u fy@sk `Jk19{O(Gf kn6ߔg);׏忯Bq>?c៬uӯ^ů~>'>gO4r|{AJ?GIf*P!'hߒ ˂l5;+I*)6;x R7ilolL΀+ء',7 4r[FD#Ps)R9Q\ H̩Q?qlr$բuL\$(l 4{)\ *HB%2\r"H10z %WɾRts|ͬjM@dцI*W9TbSe o{0d5dVD*ѭ򄻴 :)2!fII?\tԂ88 -=sFFm9.k;앾`NI$)NrdyR171}\%V!c} 2Vt2eqܻ6-詓fA%b>`qo!9QE> 3nQ㥱JOFέߺχe"Y~\QP9U2# 4vj1j۸5m!F&3=CrJkS%v;f~X_K ]2f+* g:1J2{`pV%$޲lJěeiɑgxnDXD +ۙpĆf4kg5I2e@NJSY /WLX]vI|zK{/\p#sXz j6/$N^`0~e*c{ 'Ҝyc Mn6yxysOz^Cǣ%'^gU ̕G""rcTB~1Žmle4J֝JByٻDǥ^mg<&&ڼL3,<ͧb%{4Eiߑ1Ѱ"#2Fu'1s|67\㯐(}* :tDZQ~8FiNt`Y0^MyA͜-&uOc *RA ffƐ6GՄ N:s{i-l^J)o 5  ;C&uHUj}OܞWu{tDShUp^nhW:HZ$7H}YMahϟ k(jWl ؙ^ [qSp:2>J2phD?#fwO2'$9kџȁKۤ} ENĘ J|L@ͻVd.:eӳ'eU*YCӁUaEm?0S] L OɤF1H8!ŖJ6.LF9!So8EA͑"ʼn:BT(E1œ$ȭ'(Ǜ$_B2Ww(X]ָBL"ܣQOFKP4([%>I3]NMf?n)1$ť*~à5ٸ1ആI,"H+luN<2ąQƱπ+a,&N< )Ruul'sX#Ch lHQ~wt%UY eKkNOx4ҍu8K%`y F0у6k9l74‰lOvg ȰL~% o$Ut44ho6GmRGX:-^t;O\aZogkhFTv qldt.v1Fi<\%0+ޟ(i??~qQ &'d[Mآ:N>O1K9@'ST'x+#j1ri<./E{zmjNA.e[ڪz?p?8;Ӷ@%K|~w֪}\ wQXϾmxp$1E[}gZ N=Lj<ԭ>M}OIc5JBX7!U^@:~98&{/L2l D"y#~?}${Ý2=߆%ZCwB;}f[:M{ߞօaB+p:6i&h{£9/|,'.UNV.2M[K3HJ crO.G%DpV>ZEmcH>I kP UX# #$%cn&V> psrSSWDM6zt-"W߈S}dIk~|r,;uG"ҹiHu{&;1as<$bH]Bbg4JtG0]2tKx>N ha^CYj{aΙa4 %ȏl G dMKkdw҅q9dh&$GqE/)dmw$@^:vbՙ;IF]u)>]YKBfԂ;0K/ `z;^L(u// f`M[ a.wsly#jٟst#QaRcخҧAIB3w0ux0?Aiԃ`[ad ؟Cl;qI설Mw,*` _n֣uM}*y:J?fԝٴYѐNjCdSY^bRhdHӎ=]>G|!mIW#1 xF$[ $_$ԍ DQs U~rӣ#1#aa3'wH?MoֺxC:jv#O)d3Xq"`ۨmyx=~Uw ݗ!!=DAur <̙1mQb C(Jb {mr$mxzlYlƹe\$bT(_1DW.q}]wsjN5ȟA3n%S4&A#c?X-f.<~zSϋ3WOgC_`v"M`PkZŊa9Rsס1>?WLb]y6$&sI`ܗha^0]HXSsthәgub&%6] 0 ܄ҏ|xS`S0Gp! Jl閴gDߔ[I1̙}_yqD,qzڰZ\˹[#PA0rUtzA&WBYf_{gAIVPh9F^W:$K w&r%BzBL)F-A=;T.:9&~I@I#ɸ5Os늏OrD-:*лJ:ej?QЛ$FbNqǁcs` Ọ A0JpIbT9swF,VE+7~jT D`rS!h"K+k` uwDޛHZJ2u'Ѱ aG6`Z{`uA.2ZD~)= q6o0hqu Zrq9ֲo8W/,IZiS=l_RB,u*V NE`NqFmK;6{ D}!h'y+uf߁*I.AJW@otDkM]uȗsԷN_uSRlK'_|35?@=a^+2tN?17R kԣ`%VKؓݲI\ z<ćsޣol8evšEf{k rX ,\Ow,csa [% YM-lU?3<؜)A/Ot8-̐ӰuX(QI,"ADިwQـԵsؾNsboK gvž*FG:x(s{uJM\[E> z%i(O@aev63i''ǶBv6l#;nG;RZ1br)"xapԗEq!)b/<|L{89)4=S]dG}"$WufRWB=xױk4Sj'1ŷ4NS[5Y},?Z?yV >;ǯc7M3#τEC_9tNZ󑞛u%gx.[4 eQcId:]nSEXd`E޸nB[?8[eXc$g ;|ӷ(b[  - 8mGxe82E*)oȺA4Yiz·;)LmXh"^gHMBEPډWp4Hl`(OU| gHg{7iwal3L3Os}3oȹ:ɒEFq2T]S* v`$Mb;d>`@oJs[Kgr/}!_8@q GTkQea5$VDKWXO=GlЛ~}:'jes7`_c# PirD~xWݹ ;1@}~b226F4#pL@gыY&=5?p^0;V.Ô܏F8Iz:π6WG@=ه-ZzD][tg.#M 9/߃2#Ei=$F(FO0VeG^S k })nG61'4w l+ z|#qv$P yPh':ި;ߐIs}(עߘ9dt]{?c|Qg"kta6>q[y\wܾɁ(wLsy6zO:eߣL$cOЌ&:*S t\t )8v9bH?*h((B7t~1&S cd|Ut'󞍷OQUY1|}uw(Ng)@*sZmv wxQ.wc㯳8BMP-D" R}3C|0V¿*14H-uj |%14~jŃa0*5R!{vl8h]bfeI"p6V#0F0<;}#9Q[#.rQVexa(۝ Ug}ʕoV&pbg߽ɂ#bT5$r뱋ͦ8G{dC=g"o\o} BF=֦}d+wwO|>Xl(yC4sF-!ؿ* "o)D;H1R~/B_̿f_/ZO;- ˟~?mR1? OV<1GW9|S͟ߏ?~ß>U?~1Q"(TP8+5>1etw(#>@y›<Q2}T_܏ T,:!bvg\C+i%Kt$YFxA(Hc<#訑&x~Jh9zɥg>nv\ }hõsH8d09:c)NF+ZH=έEoh>D7*(ƊwZ~ B/6ړWY9how>3Ɩ"G^ ;-Zs4~u68n bk3*sLeY\F8䑻f3ŭ2NDЦA.уa"`bNٯr!rvS1fRGc>GgrZQEKGѱLD]#O%JdDl(d`,X҅mSm*"^Hłu}6(7`3g6 _7 TKjwD`Zn}S+oszK.?!YMQ2;7}J%֛hE$p꟒tz0>SNחh$Lp ,+ZS>%Ӏd}1舑3]⫵}McrЛOM{*"6-XPɮ ԨY4WTI}ziZ"uPHdAj'C4Eᅴ0Ȍ7 [#vv NW.QiQS'aQTd;5%A?҆Q MQ۩'# {%M!iM&IL(aojT(qK[!q_,AT&N(yk1f}woP%QۡqXDŖH$P~ elO&;PHsw >E@H{RmJWhYö!.)J2H7'ooؑfB9R/ iQ(Oak=:PR irwdPjtsPBYdd1.UvvL#C­I ڳ+4#qR _ ˊco}yEh"%}c^,[Y#F^74BŴ3m]D$p?%SF@n DUrڼN ɰHz^ԕd3VqqZѮcO:^c V UB}e}/k[6l^84ħ&u˃_~/gv6{6,jcT\b6ϨSARI(b~I(Y4zdHs(C]6B6z&'KK8"$J@hܲtt)5A8y$ֿ+8fl_B.?4RA`|frc/(KܦB}e6ҝTP/ƅP N~Pni¨y()j6qqGR/ݬ&! >'bmб.u2HIm x++`>Y|Udqսfdrz+ubbQe"vB}"xG߼vBf2Tk+s ]eSzam(G{;8nȫh#agM2k'(exgίecpqW:yKYtJ!'=o-"| KDRoU5Y,ʽlzb&<,NƐW2ЭKG0Qjl74£O\gnf{ç'5!l$c%ٖ*+9ɦWSD67M5|-Q ]swK}' A[:$%QE6e<혿ST!īns S4uYEi<;nJa:ܹQgVhgjưvn.Ti;mYU\B^SyfJx Y-Wg@mobzvv!P oPM9ɖ:؅0I*'Bq%/,+WE ׵fI\v1 ID5zy]#l>4+oC)08Ǧۺѯjzg7zu'aab75e"H's3Js nø@~?,<7o$73[\&00}ƇE]vPN B7vb3Q֋VORHH>Eg]J87Iouq3?[9H܆D>B8y< *l)9c{졯IJ[kyr*f/!p&㈪X|ݡ*$BAO`{v_RaOlK4Ⳋƹc(PH6QoۅTn pH o>nd&h H.2Fy!e(wGx?/iBoMrI$ Jlb?5#T6۝k{IB1l-RG,W4dhw4|@&!ʑ%nW牷nraa=9J\qRMI:ua2P:z 䎂4>&l'XC%!E%e#UBetYo3°LKp/9PI uo9(w1|M&s d //˥5߽, u ~_٤q;?N:N.#ݲ^'mqں0h h Ws8#XM\nwZE)M r `t{~]t.8N4Uϓ|,{1jUqP6  tW^A}F攽څԋȥNۆxͅяϫ׌ *$e4lqסӅPmr{':On5j μ{ ya=)Ȃhm(I%`Fҕvm9N}\,}owz;\7fK'Uӿ?iE?xX Bju ! 0d4>ָ0RH'(Q3o*4fs>5ݰSy$8TROA!'KGX玃!O5Zs$ۼɒ w?,t٣-B 'КGa}+ sX&f$jє[J *+C13s FS)3TeJ(9)oYʂQGn:b|Z9I1jnܽGܐ|cQ[dgXB_ `I8n #z]ΟFN(Ah CҬåLoPwZLE_aTqchdBe4 UyiYGY56u z=lb+ei%V T9XnL8VV]uAY<#O#[g73B^&/Z//YF偅3bBtEG{cI[ #@'x \ST+Gti 2f"("#\ҟRj?c#i)7 O PF9@}ሤš69*3?l%њw攠"վ+vNHevKnĚ!7pNZX%^[>P8ȭ0m7 E+H 1 so N*wPE"$u@Jv)-jw|/+Iw^^sOGOt 1OH;p4Vb9.Q! l{I 5wSM:[cJ2n$fc"K&vbI a2vO9#cK%>?ۯW?"rM)%I9*XBā}qɀ˵GAsWc saM8mt#PI|kGwW'<*o4]j9Y"n[j||򑳌pՏxv3. Z ع7a<+ c36Fw29)h"O1akɆ|1Fb5M^ ^2[[oXH[96ה>cOyPAb$W 5E&$8Z_ (XG,R@J%^$C; 90(|V.>c%e\/05 _7P}:$'(t@䮈.*hrA׬ ;a?Ȱ8A v.-ش+#F &KҟmW_fX}qgͤn)|8?P6z )JR𜇗pl_.tpm}IpYg@7ƎiVu$H C0G$] 򾆰1cT3}9N2TnsxfIcbym7 ඀~L| y۲F]2%$n$V:H}12!eΙ:G'NA*#_ǚk6(ڟIёs4j`סQԕ 6ZcZ 03Alw6c0yc"W g]0,!4DUzqwͯ4/NnH.*A FT%y#F:_%d{~"f?0UBT<ވe-=(vnW-_3$7vN| )]V$EHXNڗ4qCZ1?H6X؜7Rқ_vgin] OZe/[9M?cWn6룀;QssMb\vKbX4N` ZnAFGdE%l@EF;bLP pw ORWȖ"yS(tS͠n*ۥFoNgnں#sHeF-QЛ̒'IJDa"?np$kRcr"`v,ㄌ*='3z-05>΀isNXSy%ԉ~S3vMx{Gf2uDaR*m_nQ8[¥x66qc Ύz}-"B[{=VI;C9d7fVク}*k(vj#%ɟL­g~]_6e=EijAwÄ\+_}fIJ%8Vpl u˼Iz`s #XPFϜg3od)KsS& bFM9L,Y\}}sY:4teMPИJ_aT#qbGHX26&{ՑKpdCR]$#,O~:\Fw@馶\CtH~Ǝ8@ϹՓL}f9p.|$fRk֢fPk];з# R 콲LV=R371}G|FS݋ ~LRX%Vx~3>ˤ?ف8[XnfS'B/PU]rl:Z*VmE‡!Ig(䫖\͡ϹQThLK$@'{(66>FѕR`;eB.s>Jkd}Q=UB #*ܢ5ѓ"iT;l4{EN QDVĿi(3x7!Vt?s,kף9SH1[d$#ՔHNvh-pi{=zG%X-_IUɉ_1vYrYm]o?H_f)C[?踁St|rqFԏ~ÄYf:\XV~ηhб 9|rR6w3ߴg#'c$ݽ55};}oeJek/B[Q˔­#嶘A)怀˚lƒGdS՞FKz9BI{h |ʅLx.n'Ik.<?c93N OGG5xPɚ[k?d@b*^卥́*! @ qRDA6"ˋSƂTq5OH7&o"c|$xƎDbui-ksPab&s>\uIcgk&pi۔D6]_W]$S~,~U[ 'Kg {?.f6RFuœ)WYn9}w*f͘{+٫~kt0v.n"Ÿy>\T!2yFeN\j A䐆VAZ:6?Ho< DV?}@r̋:zTR$TfgE,HEq5u£\e|>R/ti?ХJaxc"@&}sF%LSqx6.h@wI8e Aϡ6 ؜=.摙E6 zdFnUQf Mki+-KuLP%,҉y֕ϗA/occ=ϪXՖ"_y&Ka}1ҥud}c]G,+.RyВ~4[!Zd~Q=)>Q]QgI8 ^H{>ШN(UV-:/p8\&ڿXy5˵_Fj~ n\N84CU} һkeǏNʜDcjreMP' IN yt}8S-ܠ| ED? ;}s|4Eg ?{Zg㢭uy=n}Hz.w*Q$-_Հ83SXB!9GxςaGf;(M׿oϿGd""8)Cc%䷓>ctϟ6*ɟh T"CUMug w@>YwCRl;RJWW*9zW: t QtR=>~'GJׇ\Z'ܮ:QT^lv/?f&4VC>D6tvƐƒԠLA!b<9fOqaQg: 1nW MKRdc4hdh'Y*iD8-]-V"Q0Dm\h0}~)q?RK.6gh\Ί4]ʡHiאbD$c|=NY_;?Ph MJsu%?kn{$~\ZXFFHrtY=9D {r |rEEce'aOZ>b }SŬ|zm9 u0o`[-'D.6wryt mc^ϰzC·PY jw֑P39+C(eП**X%'l;) m jmn`'G9&|hqXi?<1pE ΰr$רL=rotCv`_o o}:ڴiaH1S4EA"fy h:1 pp[}G \1兜:7N GO`i2*OiF5vB'U~\8o7r%&8TwJp$3)MDm }A?:u|<e%eU|)|r W~@/́?>dZ?Fc/kmo/tFXK{Uq;b=ږrgQ;#oRg=Q~4D;5u51cYsLsJ ~=V4_/aߜ?RuUV=G jzm9߇9 ͒ZQ$YrU@ Ta'sXgd~NxB* n{pOGzy# O5~ MX:f&b#3\QgL[Z9-pm4 n]pK^/sl=*s#4*H(~9׈DDYn;i!spK6^w>sik^1aB~hdܮ#;RylrʞI*w{做wއ3,$&/{URZ§]h?jA:ݐeٓn뼌j#2gwI,?j5ؗNtvng#AUHHEi7 rS~jNDAw"P22Rrt6@-=UFvO?W10)}Jt46?Nk #/~M.f=v}u-~}ML?FB#.1^ ZU+9}A>ā%I/=\R'@ KEO '6X& ~Hj\+5!iML[!$v54=-rvxg')Z&yk |\vp?2%W(ҭMTJZ^7AG|Dx#;oU*>׌S+a*19? 6.;]E׆ {CkM3Z .V܊,9rڨ"o 8Σ@3S8j\XixUzF| Eo}9 ym4$W= Sώg<k#JI6FD+J()-Ux:9F >(<ԃcKѧt'2]A[+(&M]XŁfPq`NФl>%Z yY˭۳RA&w_wRW=IGS!#Bl/&D,#za^ Ez͖ͣҷ>l'S.:yBˆ{+/AnCQ?Y//~zƸnGRכjXYQBeZ$ak@Tt8OgNLNbXsX4k3ʌ솙CZb$#+POK?UH`f] &rMoC%OΪjDZVC)_`J >Jq3~O 0II7?q:?>pzcIBTY@w>2K b( F :2ZU">o =k3kU%aug('AkO0D@0?m&ϭ 7*T~?h>dlXU7kHKwXL LeX6;9;j: BK29. (#dE!Ĥqoָ< c5ܬ\&~Wx]ASyIni5j%lBcfR=:3n/Joz]-#{"Qנ>V3C{JfL=1ҭBie<ޞ;B7 [_WFw%wUE5@d2}d3s/ s5FN7a+H' CD~2l;"A<4OVKt3iMiNϒtKuUkڙAJˠsg8zP 8KU7P|o/LK)cA T[=)~,z ` $QU=/#}lMޑ-F `R4O.gjp!+`=2x (CY dƗ>qQIϵU4??E'&z%LV1y0qn#TqbP-Uc7i;}ЁrwZE)e䘄\%qI'|ȿ1qc/tnM2-6'Oە#P^JsTn<24S)^I-#w3tMӤ#3O`Ddgݼ'gQAABwUuSbbY t;~(KfTR8  +\K?V(j9< 4E=!ϧF0=VX R-rC2*nzmmL.TAUtX, J-^Zxm:*F ך2>`CEEy)KE(%rlrdc31WEW)H7r%[rdAJ;s8+&<#J£105e/ TB7~?Z*9 DͼÂIU˺QNgF5NUpN®RNλO$ +CF뮐Sꉔt { ZAhQ: 5k- Ekpٓ*ywgz"YN$&j(Pq7ޏSyG+yL?}< [?vִwEw\4FW]9 yv )`]_E(YJ6 F òK?659M:Ӟ؀"}N]_qnѯi+7ަb⴫vWa nv%n(zZЪotN}tapٵ+täPe9ieb|D#a$ |҅ݒ*9~qVyMbXOu*6민Io0W)O;.Zx(h|bG_Rjw@;d%b"߃#PzS\WŕsZ(E |]w͜~!+6#_TQWdxڸ"R yAFXK ?]*NsWi%YGԳ<&: D9ḥ><\v,<'V0{N221mc0VCh:f٦'Q2mqG"MZFlУQ~,hO~A~uB?Z?5uX6neZr<C?l+l%TheRB`iQqb}R ظz8n~e4f7/[:bP15awz=lLEX8+IudC'M$#b3$VTcMg^mYĈ7& q9xBeti6j|ztʅjwz1.#ui6{RN=)BKbYB"[S_=AqRSo<٭Poz9JVC_6k>) 5|r_pȅ8Q0/>0:A8R-0n-"4R yM䴉0ݖ }ϓM-H^˙KS̈́d* eh×H(ţ* ҟsJ%$BxWy%-oGQsWD,M "3W(xy_{ڳ2>Y!έfO(NQ=6oJ ;)xc{SG1ŻqOcNadZݫΒ?(eblz,/.&Zϑ\פoT)tVPw3%N1E `$ G\T>JdL[HAOLG,3xWjQUQ)φhwc4,?'``ScoDo9Mt5ōHbViI>xtn'- 0tXD5=k65Qj" $Ҽ: #z|`" E\"u&R[S]qݢ=8aEՓtKm`ș6tvj,X#'FV0Ic3bxmVC:-_=Ha4uYB\&S}栎)w We5K;jx^"uN2uR;xMRoTVnmq e t@h9J:4 V3ty}&KDiɼ#u3b;ëz'ԇd6>U~Jb:Qć't2Y@Z{,Z̢ (o|3:+[Zf@ٱTt>:桬]KL Kԝt&sV} MB[; "L"e!&VuDCt$KK T8eRTG"zVsnl-?뭑Jt#L^R IjƼ73M@.u"tA`p2cz0;qOX$݆3Y$kSq ֙]ӷ \9 gߜL"k4}EzT j'璉$8<.3o/Nb"j%Nv֞<_5sڪx-yW *@Q?10MRN1wD;n1Cٕ୛f?9hc|%j>~ Ο_Y~租),fЪy~tYrgc8O/O 9ThqJZRLPNP9`syі1Ȝk֘` ܽmؤ' '#I# 8%֗9z901N8W: ɄEKtD#ECOnԠ+{btp/$02zT@fȱK12#b]됌tN*V隸=W_ZL&4ępVR"yN[.V==ԝXNL(psr>(Z$qq`z&4X}>ONQq4/׉څ77 {ڨTMY`*vsfqgרaB^7xmw)u Ub0K蜉 <&P.h)~HˆNÓ^2['l?D?ZO| ~8$t(8n~k`Cgt\pY~l0;-ɮ ۠eLYFyڮ^:8dا-#5eBC_>Z\fq~wc Dc#"bY?(!舝 SϓW7jd *Q߮ =$w'Va[HԫP2՟үR .vMINIyg' x'8px>W2HL_j+3SYlbh;[,|9\o%6xO:LyBXʹҭc2WYcemώpi [)˹QPڽ Vv(f xq} xagp\b\%Թ}FJFr"KM8=2W&^ pƐОܚHqahL%a)ıB.V$=2q~E(!Q4?-縿 R5=Op;{#Q:*0Zn#n+W&;EYbʀޟ|@7'@?c؝<~w04SnG sR P䫩X'OFA )#\d ̲auN<6,y^LPDh# ü:g†ͱCY0j$VNd Щ%yܕ^ $\w@ ٰ`N6 1=]iڐf]xc e毴5][+/~1'Ҡb d87Wyy7"R8-Y>2B$5g)ɠB;&ٯqhܲu!? by\Yz"$zѹ ͪ |JZDw6E-BȫYYH.;抣UP >tx^(NNՄW (|y4J,,l'`g6SYC3*3t]佑t|0nNc@Gf&_Z}d,JR\Y)-L]YH5{ϓF94sư:Z㑭O2)lDx d{&dIsSU/\I5q-Ol!=S!Łd+&4eͬUɭagY=ٙՊFbVK/hV+N.|gdq7XQC3 Cm"M]~+j:!1yZoƈxY?qؑ4CV8!ALխraWrz&"(`R%)W -PFj@3g" @?#Ykhաg"m2r?Wi|7#JIZ<}uLyQmUY sɰ8m?IvlRZq|ϐ f B"RFjsY`X$Eh |F:O'=*z l D[DH'd~/x&7عQtKRy&mn "V&8MكwwJ;I/fB&Ry1e":H/[~ʰ~),u5Y^~hj,9G|h Y@)G0eZƂJ@3tsn< ̜#f6cO2jt]dI$aɠ(vN}fҠ kwIh@%vNȌ}vg|{1JM¨`ݚ%i֬^G&$u-Z#L\jӠOAv?r:(f?VCX+":8= m< n$cydj;nq=hvz,\qf'rUN7I+7S%t6& NC_R[BeX(T:OvXnO 6ڌ~lGZ;o->8x{Z! R,ŀiWs+퐙 C\Lgy+mwIV\l1;ۖ_9RAvJ̐Y6@.wY0UiMp^t쌑F~@«OеʝM%/{;R=4/F,w-fCztXBQ0P$ޕ =p@?s5$=EzFZ895Y`N<^|+ ea~#jmw69xrP# a*F8OI~J󱥰dgr\kvNH%X,:C}!g^Q(Q>B߱\R0eef)٭B̰_a1-8M@=,(Haј WLIXe x-{B͒k&8CLE;T2S۟Db{WS3lĞ8A?/p RLD%܄?]pyH PUܷ$hm;;vLH8p,< /%-w">K8DI9sX߿~ן?IEw/{m;Ӿ1^$=KÕCQfaAڮ6R!K7t_ct?tuRylOoa 4nf)ݥQAA8~]hQK92U:7G(FcU6@AqkDr2U}Vi lPE-[V.4y^k;ᰣ`h"T_!mS*sj@Ql2oV Z3bK*t_ZwܓUN%o٪f@& k(efΠfѐ1X `lIxV*Y:' ❍{hYƬԚְ8N0> &K[ȩ]Ո1\}>pSM_ Fgd|Nrj%+%k^BԮv5uN^af|_HhL?IM_E+f#/ݓW0\QK*Y"8fI c5(Ix0YӐYT3WX:k€=0${+_ xk`>(Lœ/ ٴ%mEZMYfRֺ <%*;;mB|AfVZ]I!|_u'ӳ5ysw ._^ Oy =Ny:BL8s?l_Q/~]ÝĠ>Deڏ^fLM>:"K?1|$Ka4=ҲE̪yӋ=1x8Q&0(rԖ۔5qb s=V`,585ŶѼy#dRŃĘ(Q2TbDl)˩+/X۩0D @; Z㸹_aM*y$_8TFI$+'IX Poh5jm朲,mb kPq)7 W͏s)J_ M`wwƾ ؄AXi)G> jI։y!%, , $N0 `LX|j۸98+EKvShM΂ pD:h<>PW+aޘR$p~F/n ˝ twtlډ[PxzO*L`G@ &ҌKf6!3 ^,NⰃWeq'KU'q$9Tm93'Tz]Ű]^Db8%Av?e+EI4%$QWRzo()qy@ș9_;cM܆; 2GmJqrS-A+x$YEg)ajzy.9L[jl4FevcB}үILȂ}A@VRuQ.TOآg)\D18TBI|ꓺeM\rdP]yQFiv*s*S΅ݫkf{gA8 @dr Z-$< ȴbʄa3PtI3"ڴZt 4kb p qG # Zlg슳*M޽}hs-<w+URFUk"6=,=Jt+kcY R`)e,#ULntK[Ϛ,Z4Y'S2d>04U2~ymƵKYd8Ǵ JO }[XM`,m82~g('V=G.%J%t FK1װ/fDw {x,#V?PѠλC! XϏt~ u =G_? Sn%i,:*oza?v1M j!6fRX*A8vDZ;LJvatRL"U6XnY+_-us4t qv^S<3Mu<;M j{>H?I}Vmjˍ$]SpcM u$^- Ĺ$uFfh%Mjr؄ s*KBToN/Ϫ~L (=A+cezϹH[\W(r0[3<ߖm}G v:ZAl~`fD\gvs?DܘfZk~F!͙WT[*G:;X%\ev 6xK*I|>{eyt@5lEf` . ֨g~>kV}&׸DsfGɈijIμYq%͏ 1~MۻoU 2~ AF|-̬J3aӷ?;1::6KW2ӣ>X;#@[nOd䴐imCPb}KPٻ*]0~"Cf^7b F2qL.KZvxOW$h[ +:n$eEz #EG 9;bйcz ӄ08F2w+I5AꡓH/6X,i|Ϻ/$-!NOؔ>B.5qc$}8o ![)g+YwTB"oPO8 $bc ~ 26·!H{O e**U82̼G.Q )b*;{ƫ;v] ⶪ:/b&RbF\p·^&IW̟2.o('(MJ{$P_+~?o_VȟT^_YsEB1NԒ9G}xMdt'zHfX~Lgx/*b;L$Ǝ^q KGgt [ElGYqH_ :0VڏB!c&=+:FguJx$ I[up[-@R_I6auNޫr$?E;r }WIw\X+dMCVͥ!X~GQ$ C{َKս-w:4wstxIb b^2筃eX8c7T#}z ,(󩨟7KNFoۅ~}|EK;(2wm j: &r&Y}>mA01DMeŶ@^ŧg&nj3|˗`Fck%\bSqM>XBU,SᙹW,h9SM߲W6!&Ub.GϤݿӍ #w۪uNx^ ?TI2^|[XQ'Ӗ؍0Os]HFg!`p߉8yɢY0;|5zEx*؊~mScL&kW+-groKjEI%|t$tFq_'͗`UL@^Խ]SlWlffGK^M{CEɾ{#{ZuayLC C%pR]L=h"'V¹L#k\v_N@[t-v[ qݲ\H ݒAv/ ׆CP~!YR>Q@O]E{'sO=io.v:ň9k'Gz ~@OpUhg|z^%tf|)y񼬹[fY3s19AX %+ g=p6QɵYƥ `adT(1?ܗΎ2M(s.P?N{)0x7`mY|>jbSo )[]3{ҺR(E|\*H#!j2'r>?R3ⴲO)L'/'gȧ7'* s7u}*Qӗ;0-S Om|?v{r29 <_Yn |0{Í.rV#$6s㻜ϱ}z^9[~/N~Q `?jH$Oc Τn> 0]q|J/a_Ec< Ȍ>' ws9= =`{~eC _N  gОzoŌ:x{=|O!/锵W-z>8OKgLC,-U<_x %' nsdQ`OgB`ʎ,!W KɼJJA sPA5Qe ej1Y>\Q?b]P~y\/SCӮ;(lY&5D85F%g>@oMb8F0eOYHR<(<ɚNZxO#<<('~|P!xwNj DN"x$û)ɱ 5Z=Y͸= {`4j#x9( A$-_̞4Yb3}8sY<^@z#X4ȹJ,IVj_-< 3cYe MHJ_Dpš!|EQkvtg`3@݅Hѱ1D)G @ ̃ͼٳc7b05 h\4u1,9^pf9K[rk|͡f 4C+Ȭч\Q !7)lΔLxbB|뀓uҘ<乤B&1,S廽7d[`늡P9j4AѬ $紭u@ayؗA_niYN>1WEcR+p7d+3^š H׊4S1Q$pVm{g|%eL!Y"9ɀqdvlq uvItїiI5B c"\$2կWVF /c{g*B?{2^d uH31yB"]hcg%|b./ K*B CydITSAֵdљd3c`GsfR`ISaS/[[WD>'SRItM9h!l~H;X ,3:t;QC 92 $xs3>YA)9mߊ!fKЮ=d^+m2$ 5IvA+yo}XOIOIN)4mTIJm^t;[ %|L7^cc@>`>VVGv(ئ}tJO!|rw)7cҎ"ؚdq!T>_h =eM a8,a"=A:|7`юU}GF*Oc?l6cص~2מw\ar0b'B{P\8q)!/P~;W%F~u8n%y q BaI @\)i5Ve" <'N$45(Y4\pYƎb 8̊`}CQ g{뒤%G2Fũie }.'i@4Aty ok%@E#s&gf!dyWդ u׊W| k.N-GX\%hn膛ݶ-pέܮm 닷o]gPo`* hXȬr6sU|Pnu%^0t6j&(bw}4a ^[=G{ۭq;FpF[O/@|Kpo@| CކW? N?m<-%2ԤŏC|mkHo`Y2M6?א$1CU4ynJ:̵G:{ E'|$nmbٮ Tle43)?e'̮d[cP`/c;Nd v1 @#$Mp=к@bpY+Ei*blJ2z*Q2_+AE/@6F"a4 m2"G'pZkckPd*ıM\\Hc#F{~+*y(F[L=p"9R*46.Pk|GhR"\TLIDz^ZztЭ`YKX JZ}'M=$.z66rx3+t5kӑDsZj$U+o/P pϳj@/U4Gou /Ӫ%yM΄ol)%H`1.=-YF̻ՁoZۺX/OCjM0H1rn@Y;NR~f_Av诺 KhKsHHb @;'vu%%@9L oeX+Sy/h p/g)gG]C3 awq^ ]eE Pc]1)X50Vۭyjkt]5 5!ck,ŞۄWKWE,M,IܓFa2pc8zr%xUOzdI䒸5 1!P/;+&uf $M7j'g+c W{gf'Y {_ݱ(ɈLbe)IF{bzx_ a hQk ;LMY![i#>H! FԱ.Vb$ܪT?GoQQeNaLb"!:#g_s~惡KVPFʖ<%o5 @%˵Hjҍ|lj2кt/_~_~?ԆpkQ\5IZ=P ltTƊf$:p9䔁1Rt|7Sx,;1:4*1. Ef*8 2F\2k.Qk.Zg=QI]%"H!j rvgn`-FnUK/?dh#~[{\FFHi<*^P}EhnO;a]D;`x h"(}k= >~N\XWx զbBpZ?VJ& Yq`lEq*ZOA8A('©K[TLlYK#ٞw?m&D$uˉk}둸ڦ]Gõ2NsFgMM9P˺DH:.;0nMm0(Loϲ KWH5fCF8|묍nc`+y5ڑNk `EwK{%LF&'Mq_{]C kfd%Bǀ F1i+R F)fxrfm鶛mB;B~HSu! # 4UhՓjwYI9hT^ث 5FՖ |>?83]R Gv;Xn7ZW&k & s>m'Y9g JuT巘Hi=Ȓ񄲬"pvSf'c=ut}$}ʄ IJ |( u}yD7-бwm+#=5V99Nd4ĠX Dyr;7;{20Ky&vRDo|=d(` (ǙDZuG '; ypeF v X]/-@A3a"u?ݶklǮp>p+-;&t.oeرcYo4hloO()*0s۶X ).\S.c_9t|8[ٸnTCb}6p9&1بЩ.JGE|Nya~1#!ּJ>Oz#9Q3u,9R2u.p)[kICҤpF3v+Nj+)d'G)}Z#r A%]8Y 'SM6U<Ԋ}I&06bńQ!xoJLX%hw^י^}ȝoc{XZ, vT#{Tҁ '#IG))(YLG8gLy,&{2¤x}2 m)@ݭoj/ݑ3Î*5M4Hc !iIiuMSF]QKRyMrnuxGYRU^K-KOӟ5Yr 47m@u޸ٸ OFX!;b9ߙ[Q?5T.WbtC^U26Ν;O\/sŬS/ipL+hYwiM{rkx޹)H'46IѴުɈhHHzEy!I"uxlNS{5 7VhXcGT%?ng0a'GuZT+Z%u%iBf9!-$z>V 7?ysYu>YWDa'/(ځǶ^ݍ.io&^EYy>kAq"|ϸMm0/6{nΗwe ]M8y6f~SLj%V3S@~T.e[2aաG 7>a6_@xLr*\dJ$ # +jw߆ P4 ZV{ᜥȺ9&{zDY]+ɇ[)7jG[*,J>gJT;є KlLGlEW* :A`~*ri' tzmN>~pövFr{c6Y bc &H?3;ˠ=l XTܐ/6^EKT($E_`޳$+~i5F[+oX)XY Za>*9#~7fJ/I@:Pв,Ǣ;jT9/mYsxwF"s=At1=ݜȌ G.=:a^28DA/Z<ŷ*-+FhDU}Lԁq񙄳*kMLg"JWni.nP*#Ӓ)S,AڠP/:o@ [e)}l.p^]I%?k6.O7V9P?OK]%-N!~$ZQtALԓ77h<l ~&/q K+@R! %9@ω&T# 2B#s NER PU&ADestiF])6\|g l}NbRYtu8;z`A (케>>҅}!\W 5U.M,2UvG?[vc `L$Y+0 ]S=5F~& l ؕ?lbM()\@W+Ul`dL*ϲFxԝdJl"eŭV˕raW6V襢٨I3wZQ0I.ݜ䵞5`Z؅2w=46%ϑBG&<\E6!p2^X7#g :NZ=Y1ӑqdgT6Vv1ܢ1!WlcofOpB jY$_?[ЅOGhmŸʬ=U~#\12 BG pL\dJ#+hݧ".kTIj`bqS ==q*q(Bb”}bqZbD lEk{C R^G>u'6[)LP;9WцwܬZmG;`İ@4 {a( <J-ZK?@eEAF)Z|wDjW>8ZA~P$7av()돁D'-OlpG$ ̗u_^ 6Blkx ï| OI *.sIC‘^3Q1OX iwFE/HK/ Id:|\C}ݻ!B'a5pa7P&M,5r e'{z<J~x ϲΐ3iIH*v}~0A(D;\8sRÛ1p+ŨQQ{urs¾K}XH$h{RLf`ܧQ{n߃20gK@/@7X7 Oc~Pn{h9 J)&vH @,WhaIlq3,pZ>6kX*.K}/q4 'ZE}/4N'%@T,!nq8|@5% g].1Ҫs-K>\^+,bbJI!ijvM6mW{eovF9lY$Oxa? (Za.%ә[R-ʍ(;+S𜙳cuwo"~ sC=Hhx#Uh9 i8ke+d~N.pg&^cRh;-pgBoNs=Ag#=O;[& ! d9tƐDS*Ǥ%-y_ |kIW!]#W81)U\CLqZXܐ"~2dqVRMɼ &]iKk:a-UN -Ԏ}Tm qkSk'JȽVL8RW3'| Oª#t4"%=&[pؑ;`\^DѯcxkzC\W^lq=Z|7$Yy_m4&,h2/l9gJjc/a{ C)"0qlݗBə}&|i\*$f_ss{PNiyGD38Pqp+sfi\eѐ)%0,#;Wp_{TmEtNq70gU $#6  44qVLvexV +^K<6/ny9Վ6Kw"j 0HIZQo02Q<?OwG IP7^n?0&[Nށ^j~B簞ZǶT0nJ#q _q |S7sR[H=?{nu C&&`hw(w-ߛ<5 i=3N<&dež[;v1VX1Czdd8Ѣn"œ̠Jx[b&RƔ+to ,bxX2w*5g#>; ]IbKlԌbk=߽ zOȅ䕡pqAz;_=]1v.$-^ѨcRqt$^IRwo# U;~OLjT Pg^`uyRᠴ2-Zƃ<2Be/#Fƅ!f?{f u楆[],R+HbM! RKpj҄cWzPoh@-Z7uRP e[ Ѫ|#Gf ɴFx vc2uĹĬ&@7uӉ=0kRcoWe*+ґ^ӓW%MIs0CuefUrħ>9zIxcn5qXRin;>X:din73kG@(|f(Θ*zpG48׏a15-(43дe53ӈύ JpBj^L>7= w]D $ J1ASk7 NxBl!˹EБǽHL#^1-6˪}v:33n?lB447Yyγe~K~JM& 7}LrQa3ي߰'`\`Μ39jdVL{t"Dks2K<5?8xCłsuhp?Ne v\hք#'lXY>2ya:00K1ȭtFԎR/SadI=cÐ*l_&&)Pq$l~$A\E4m2n7#0ޫc[ nҺ:yle5GR/GD|kߧ5L0[@]&@T0kuύqfC͊C 2W+D>G٢Dt }~a=lȖ6ל1K 3tI ڍa;Kde FI)nCm) N1 Ko6 ?zW%x 0a|]0%n)v:L eY7i%<_EU 5p%3p8\ܸORiwRg)V|&3&jԩutD1Dwm(cN Ǫ-QNkzf1Uw{*/#8jG+nZA=|_*q9"~r1"xB(I9U*- p"IGZ: AcSKvhՒV쌜 #4|L\o**Yz[xIC 3)k N} @Dv9ʻoJWS6:oA: Rc3@|y^lf\ʻ38AP 6vkmIASO)_~ xm*?E8o+7+-NP 2ĔyGȒUj\r1Y? 3iտ巿__?SiF-D*A?ߛNsFE<3 _yHܡLU]fgN"]{Ɛ{W#6ı lP|дW! Y>BCÖдM g AoE6)*>69LS#2Uf>skE/nG5E/B)ULP>AL夽윊%͢ G\6n:w5K t- I:RU_x.4z#N/!fUYp"p ^KE90f{3^K[#iUcVdJdGMAV˘Uz&Y5E7YNHL>jXA{HO& k0 3 D bRw[URHbAPl B@H) HJ$+e9nLN@l 7$1qBƁq$<vl6?YFټ}Ešf.ZʁdĔiw;Y&ɛӀo) oMOs8qA Ë m(GP5uNj!|#|+f>B HLXfE OΊ$3nq05lR /NئдY+TjA1OϫUOV"ZHؓ(kmsKRԭ'[H:)oFXOg;õt52aW%L '9 TJV^)f૙g*,X kt5"̉tT!Ot[Q&|MJ!K`bEݻbm?<+RAq4۱# dp# W:nt7'Kq< '= baX)? p45}D*:PTxOcNu0fTH"}뤽fe!f6)9.}dl酓ݡOVbBmmiu&/[ DW[6ϵ$?pb5tTvqf4{$ &n(zۃIN?Ga6"X_nad'!㫒 1р +[/d鎴0hm~cW][+Ȳ1^'oݦ%zRWRKУ*Z,$d=˯I>zEG(s[8Sw0pބDIȄݵ1RAy&dZ7hrj.?Bq!|wI}y(R^ $;lu',e0DH%~ 0cZKp G؝e\9,xMg<ӹk)D}pB♷{%Ւץ)ǩ#aM]j-0Vy7Π Ҏͨ8 X\PB )fmiS))n\z&H^N|}kt.x*=C3tD#!$cHީNʘwL*n ~hF~&*]7}QzϞӓo8or x/` Lga:>$oy>FF_8>)vd+μC"Ǝ·3 ;4K*on 1r'HiT}% o\zыN)Io;H57ƀdIa> p`wT pygvZxcE']z@:&f=<үjٚ*+%o9Uޞa*AMȲҝ G kӫowerPf:c !4V%4rBJz8tWVb˘}! )wd>G5lH&}fǟw(D5i'D>V4 YlM4uަY;{fC5[Ihz&oqWn:] i"Dة(XyX: .^#NǤߗۧ_W)[ɈcY1Sq\kʠpQQI)CRDu'1,:aӅut;(Z3ɀz?2،B5в3 o墎foC;9N\ԅd=vBMIF- lS;WU?;v,(W}* jX mL]$ vIf}[U4=V,ю-;]6 cr'#1$fB3hJ @ vK_g鹵l rߐVš6Āku!w+jFr,F1*;bd qJη s!%ZvJɽJ=%q;ri&wP .(-MzYb 2U))`.tx(+% UfQ`Q*?T#>6^\']Z/׮Ҋٕ/X'aNGH.̈́o"2;>hڔ BPlғUCDm|u{mo)T*!vR\bK qv'B-Km.A[h%/{'0 cc?6?FRzL0i)"9^9(7-J6g[: Ew`\Pp0yCH Q?w_Jf ?~,]?׆a7}gHU#v:8̣K5_^>0֏qY R3498X6CۓΖmVI.˦ >cc֚7Tqƽ[u:(%@'Pmҷtܹ)RX揌Ox`'S,x:`A1]ŕS1?I2O8ֳ꓃Z+2BАBASN ŧ]uoW.J-0bb[e'6)z7eYE02)rlZ [Fv8yذt+2_Jd'{z)<1s߬ISakK;^MG՚8 AVT '-ҌX&O6?)I,Վ/v; hͱ]5ժ3q+(f`pĥ#`NUNNGN ?nFӓژqgJJߕPs,SWp.drWn@6$'tB-úca_V oZi]۾ܫrҵFma% 6a_ŽGyj&$TX6dRAuyf(NMPK4)qDڴZۑDj/_~oK?~; ^3l_Qv>9?GX>S}qox<2nqMZ vS-tZ) mr3t)DgAؗ"tD"/bNx6c?6ƛ噳GL_VjJֱ6^{sH[^!+,<ŎU\÷dc1Prtxta`ZɈ`=!ͿgauGW%$#O)k:XJ/s9|Y7oq ,_K5vVnpq AiECul IVKS9s%9(J J{弎j<%!MC=2u)( X.É i C)o?|$!7)Tc3>Z^#j'ZN[@$p;7cB jRLFIH\{d >#kvmAV LpCApvOI9БMK!Z cThEؼo!0KϝKU}630>2v,-B0C b=I!v U?YUlO;'~93݇xմ?gƛ1*EE{(Wy%jX=!QE joj'Pbى?^)oky&IrGO Y"NkӘ49%ԁKvf[W y_hReUAygPDܢ'h%8jNYb^`EEf.V]QV6Binϳ"3ha6 6c+Dn9BrV1@ QNI Q4W(xO#]GPB9Ap=aVC% VQvNޓW:=?}8iBKZ%6^3? OVh(pl Ad1&.Ft_TbVuIPQ K9P^/K’PW"8+ ]Bu&~2Fm+XQІTR_~qݨKUbv]v !X ):|e,Qw=]Ѐd2w4ɰyF99ǣT;+x8vBo-ظjd_*q?'}̃rրMKKoM )[3/b2xa#vҮ 17:J!|n 5?Oz'Ka i.oTS!S5cc*T'֡t bXf|W_ }4ʇ2ttf1w^ߤ$: B$W3备Kh%$=Gb(ݯ_?6T,WHL&SHD47P ZRF, ?N|Og-uR|9p\XwC? 5sj :f89[u )RF;XGf,yuI|aqUxHф1ƝVmtypnx>aKoW(>冒'KGQ)Ԇӫ󱂾73w+|@*#. R]2j p؟vuq3 XN(l*0܁ ˡϻήI'(g]]0sj$bB˙Un WФ lV8-a>cm6U O3r:ۏƝK7XG} $Mk$HnsNR)_a럿˟LA<U0v淎" 韴G7x0~.AD4:6ӷG$5{fR EE=lW":Y!(jBۆЈmLoLZ*(%vҤݨL&{^ K1 Qy!mp TǬq8PZK+b.]:61U wS^xc]⯧3'đ+ Qxi[ҵ]\{Vgn [?y3`O]>f3dE,[p`;E8xs'o 9yg'=epm%( F Z2Be>zxԱ/'ʏ<@{h/)d @Yvb n-#at?C[S}BLtfN tWZtlVh"쓴ꀆeX'aA]RIcV5X4't&|㏍DcGZjM-؜0lBmsoÊonp#M8dе b5mZp$RM$mѹŲ{W"(Ԁ A=%ҾI-~۾a>v`W`Cbfpr߫7_6oNX>.[;0qq(Z~EO7[`*toHge6/Dt fPko}=ڋ 5awpDDʒxŬ@1Ex'Qr2LI xABOa}EzuS/m6F^xo"FV}7҃C<싟u M&U It>I~ &R`fybc*.˽rpM(gr"V͏mbDHb$yPE/ۆڭ-C \VO1Vy]-FFJ!n7ͪu#17"ijĚо 2Yځ4U1֌rj" R4;)}d]RgqB?cIךGZ8RlCOD8Gz1I*.QJ z}.M*/8켓FZpe@ES(p\JsʩL&10C(@Hę (,q ]`]"Q!@(n*wK P١t+'R"< c1Bv OHMO%MNڀĻv')T+v*ugPeE3# ~Nr3Ҏ6!߃溑y?)qTk䨝QBu86Ȧ1ir;`X~'y6?] JͣZ :wN֌+QP[&>Pf 7=uDB]`B#r"կf'7yf0t2dL y]8}jOFp0馴b$à2zBL?p3}̘5d]prI[]r2P摽BqIљopy3k\eؘ_PQ1u\75i{"'`]+RL~_.%3!6 o欵8(D]s0A M9u|"r PF?+"تPKt)A CCd,\Ǜz[k†"7=(#W;s&/X XR+~zBՌiV}tl=d5qA<ɴDCZE_qKuJ" 5 9(P#t tTI1 ΚT Sըo X4$H vnt*j?w-OXe++v;}һlD01n}Eptl2;tNz4jXJA!POa}[1'HS.7Ү^C!cLƧ4|,ƀ& Ted,^n͘p.ժTTavƣ@ 7O6Ƀ^apna 6"Eh(i.B"V{zn(Ů %Һ-"Ud4kCfI#nmQ ?HlI:7LsamꍨL+{o/(.҄M@>jL!o kr59wEC~?M`u|| x]VVh\|PKxUV֦*UhM'_o3Ԓ#\YlȉyWG%_&CE13\ҠtXHz=U5M6L ^x+RTNwnAi^ "sH߉j 1[N XwhËU/"AȦpoehۚΌe;]ΕnoNЈ^i_7fx1]z:ȉ:TX"*yރIO ]#C7%M!YFVg3jC fKJv7.cd'qr(6sx8ȑEtϱt%s(AyNHJ}addXδ̰2iE`~ 4iq};w AZf^6esYlu \*u"0rΕ4|l{®sרaZ<0{| {nL<ĂjKԈAjVuYuff%TT▿&-'c{2W $ЖxRUG#; `)׊Uxe1e)Y@6G7q:б47Q}*B3Qa?6f|fn0Qb!qM~,&gH !3,n qs!=NgՉf&ljC-woiB0Oa!'xS„Q<]pe6>A DV=wǂ ,FI)RZ꾦:a,p, 3X*7eH> ?W336J@ x#]HktVjC90;f04+@mw/׼1{Co'E+[QK!\}SbVJUXOU ,҅'BlM>eO}a:s'RWmB+?%$. =.x6mbЍ^[ Ω=ÌՄdŽNl!mwzm{`,_8Ljb!8;!=j?mtCmX'(T,F}~BnوoAGhP/┿`[ѫu Ip6NrrD!w:ȟ &ƙz em*}Ln|Y8W뭻($W[!SL*YY_*IC|_Dǿ:R ~J RB7Ԭ[9C1mL\흗2WAe8u8$ĸ?ugÿ?*>.2~*R{\>H/"{%&t2՞[q,;bmqxQr{]q+V I}$} 2RڼG90_:ۻ2#GhT ǡkzfO@_s#s*,VQ 6?sg˥$@'ec+)Lu^#`n DX odԣȴ ;|"ۊUNQ&=+:=_CY;s)b_qAŚsܼ) f2>j+#u_E$ld݈6::4;XF~]uFĹ(0KK=?CqP EYv 9G4ug1 + 4z݌: ' 6bZ[n"_o!&Sz/` *yo ?߭]mVQ)jJ -u\[=q-"i%m){1Τl6:lPa#/?&h5iVTg.N {#p-Y@E;ԟE9?%}6s{c ]SwT#l)=2XuGZjv23h {`4V #V&\fj>vf^seVܼ0˸8Nduwxl=.0=+t'i$xR{$MViJ8ԇ$XAR, 2 H.ol/AW65hFpD}=̌b<Ѳ!{4#Ueӓ@,_HLNqV4wO`5D[\Q cS7N|)֏Uau@_T]2*_K+Lݷ\,K&Е$q8A{ `:EmB'r4ejgsgl<#ҽzAR'w*\ϢaИabhԂq{zj7TVGUQjޡl~\_Ѥ+":p}2UZxMOLF$ӘfZR_R}gl "~@%qTW 7rN}A6noeY5 `j'jH%ބE\m@fRdq9}zk[ '1GU+LGnar!pG衴m wVUY(Vke4%Z hsi)})A=&se ~p8 rJoYZu68K&nxt@&鬴W|9.dRTm D8v;n!6nj X+~`M7Kn[ L2 4KKF QOnQk eӚU"jxaJ*{aUFfu:)y,pe6MߨаFrӡ臣 g9{IZ$&1Iٖ͟ϣKmK<!1n-0*O. `/<>B0 |^%ϗMDU`5*K /$ '8-; )`QnoD !嚔KpS6:'q_|ZY Z;N/Q pc9;Ϲ_׿Tgo 1jmd0 l74H-w?iycr}:z!!ʢ%PfM* O>,K|m *X+I^4FA(q~(fח*D7V<&N kU=zɲnv^dA`VNNK?a.O)OM 7$ƴ&!^FH?}Ktfջ>NJR;4ʭIیwM7cJmeEuQt 4&Q*K\J\խ c(wN6c}S-5kJOOk,ܻOKjO?O^&EM~=lk%2`QI%m0 FBA4b ƳO2=R?YC+̅qZI³Ӣɺ#4v}>>H,yU,7:F$c|uPsēKџTZ*H;af+$!#4NY-4KYVoLSaLw4|`J:olJWx {H/"&PEICOƒ 144I'<9v z>r$-Y9k@Ȕ@&YIs-ivtXV)"VU5)Z.Udb=6h_FG3N",h!:Oz|u,ɉd2WɹN,zUUr/3jO g1TB'scɵBXH=}UkV./?寿O˟ >Â@nq KVIqү1yr ^ѱIhc&6sۺoБ-T%/Hcv;7M\\r!*0,M0ܘ|-ю30bTzR I[v$IHU1ɒn"*g)[*m!۞S@pc=8>ID:x28mD-mr+鑎`Fmo>y@f/~tC<FYOQ d}>Od녪ä(x0p,ĭڿ烮c{h>w]Lbr"B.!"2[}\˥f\R'׬1T mKN7dĀ1CDTa_<[ֺ<m^2=&Q+;Wn`jtc̓ܳp+* fV-1<ʩB󍜦j0!57*H۟cx.lr0 0mpi9D }y5<-}0 gazF= dkl `|eJb@H9P(-p@8\`*Ǒڡl!_h+:fq ާXE90FOoqc5Ư0|Z&`QV,0 $VQ ϽߴO-L11Z=R;JH}S 2\ 苐3ɽʀvHGF׈1&<C (bLO (gՃRݟ4b,+@>_k[>>:}eT$0&i;ζdivQ{(RQlfRH2䓞)A4Y)hN(lM 001^Y&БKPT\.YGxTɣεbg\{: z]n&Uso%GQ'6,D/~"@΁V,v*`lM82C %зL;X'W%+Fc+1)P$* @ad'=ُ*{v#o $"#II'#@dvmN7u7n9sS4P}R hѶמ/qT}zZ0V.dPL/%43 |ᅖ甁$Dh#u4Fʠ]Ydn[Oo!=e\4IHe7xjQlF)Q-'W ݙ/_'`o]dGJiQ1]`G2bv}#PH`%Fmq `F~&OJf8{\}GkQ;!*^k/|R>ra8 1sIk}[&۰ R͌nO YpŹӎE{ԡgCºaO82&i{~_Cg.xirDIK_"NG0&`La^ih&NVPIyUih VU-ly6 H"d|jtQ`6Ax> tc, gXȟK#g,^QH%ݟG'@͏/mz!PUc? >$>y׫: l0i?MyKnKR~J, iӪ 䋻Q|_p9j>if)WiZa(U0ɜiu{Q2j7fVVzGȃ1p}t.!x,Inp[(Lh. 7>˱K$2. fKɦ7GdsJl[? |A*Tp LwF12 BqŭQ¨F6oEIT!쫔 ~5?Y$;?z[]avqG X-V0*-rKL'vOBG!gO4O&o1L./*FEj1,c8"4SXR)^,X4 pbd= E~'(KV!@&u8ݮepkz0z+n'1SFPӕF\NDl+X)~{浖e 愈6Q BP{;yN! mx dbbAn#ܼtJ>I)Z{}$ֵ N#X$W9 TX( {<YЂ{kq{Dʵ $.__Or_i@x"ENfiB!*S1Z8$nE>|siiS<{Ύs"!3<:>}C80^bVh.-#דuY 5XqV{,3|Yܸ#hpCdsXfdW卡?"ZK3( yk?tM6a}X%[z6j:x鍦 ,ĬO6ĭ|s. DthJ8[ ŭmQ"Dd< $~HR]`^qb=3]O` }qN9 0{BTd6(Oo>֖UxMUyGc֟zLaof-HN\L#z}| .لHmFS]~g#\v0Gn9 chmb?^ܻ]p_x6r5}a'6*"VC dVVu(uH.P1]yF2zJ* x؏43!o05B7,hsUΘY$DvuY;r帅m6xeg:"I ;cĕ2?w=%qoA'NzM`sTmɄ跲'Dxޕ-37ƭԐK**&p^_&kGb 0}~ͤXI~p3r^ /D{g3w Y. rxS1=4}*Y,8YY,}h+hg6o>E݋A:PTUx!n~6 |4if(J9:Ker֩if67pNGUbŠ<o7)S {ڽR &+PI:e2F`|.ct{(c'%oiPzkWt;'mtlE~[eݴ*.#48f՞$7*e2]T9ׄcg^!{.UVCg&MlG @ >~m"6 s!V .fFYQ_~;T N,"ghkTERl/XlDҕ"{}"Tra~8MAyg6@-Ô6 fZU':)za|!ppIkngm"%n)us]AeI׵$KE۬'N10& <xE3lN}X}hՖ^3n}b &\nI'XpLã׎;#v3 d9H{V;GwՆ.GHE)yGhAwX6 4o2Y!4y8A{Byimo@{2A٠!ٸ*>'JeɊkF} ` ܊gb=nBlpP|3yxr'rV l/uIS+He'+;JX']]iA¤kl~ $}6\XE lW4u*bRgK@ÅF hMVzd3,B:*N4&l_ru6b&%wWvl}ʯg#@Efg4WV(לG/kRNВQ_ R|f'gq]9J]sG楖˻D@-_H90:9=WaAhs0l6P:n&jؤι8A8@Ug^,1$<)^c}j̱Y/KQ|ڵ,_"R̂5v8(&5m2Ov(S97L"J{;~h>6ZlLhЩGgd*h %ČPحFثP^ߛw>DT%(ƀc Uo=2^Nxoq$I^2wmʗόx_=hC_j$ٿrW! %FnOӇs.j6)'LXQWdӪ;̗*BA|)4/mm4@<~s-#opyKuV"%0X%-j.$^μ#WFyLeLStIEфXRS{(bbW9 3m=CuCgI#\oΥM놥4}iCPGaƮ_-v0M{oK[S{8snL}bS68W>t\ asԆ2KΫ)"6-β 8݉>RYUͮ`O裺%>J5nq|ȩ]lƟ*IkklMŞ+K,Jn&5b{K8 i+ήÚ~(X{35s8%23NҮd%l؟dbZT>>w>4ZS7Mka?ѭ~75bհob m6 M?6UpP֓n#wγOҟSɕ aIem7|lqaW%֑ H,)qM+لl{5;9ÚT&ӵ OYk8lbEN*#&=#*uO|\s1DoEio eo~()GQd ;.;y#&.5BJYn‡0 @|PwM]7.d(ڐOI8pb)0 rQ8ݴ8uo!KtmU[zVSpᘰ(lչZSa&Lr$mLtԒ`Z3:!0İmyF7FgFT s7>+ ',f>hE%=9y'Obe'3{eD&&tW qc`d1@B>V72'𤵴ބ =&̚&>:#4K&\akP ۨ]Z' `{n'&iobCP8*qaԚ4pjrFl'We& j>^(h[B!W.[]%BM y!&c,xڄFKlYET\XĎKϿf嗿O~雝'r sF?ө}ѵQm&۟IV))wM I|N12h tfg,'M Xj2[!: ݉%L,^>ͥK!dr-^8s!?%S+)2u@[9E$S{BH*xR-Sҩj-dtSnU~wSK8$z|SPmBuajt vɧIcCJjP.l.B3L<#륇# T`/*2/%h]_3<}#a fl9ˉ9[Ͽr: {1WA#v_vo]5b`8եYMm.R^ :<4*|c([b~ t>&ɭpQ'n2=F5NFssD/qM rWjӇHxʒail>[hl\UB!NDڠJ 5mffa0Iqd'ĬG  -pse='DaB^>`|bׅHSsb:Qbe&׳ؓ+%0J̦U[uwɑK@/ݯ2+5x>ةYUhT$AFgy*9T /5T9N0o}(6L{wyd>)Y4Le ZzߙA/ Tg=S*^{a [_ OU-cX0ѳ 3Hzv#֕d؆8*rZyWO_ ͣ`2rqG~Azpv-F>9">Y_2u\csM;?DL8Ζ%j&I U82tό39Ky^r$#Y}[Ls`Y>gj Mk{Ģ-m& eO-uk0_vLr@qWYtځ HKx^[BCgj"d no;yOlJ.toJ SRgE65.+vx]I!rZA?tLf iz7Z`=V>m[qY-Dr>0uT 3 S[`gjWZw}f-1Hnv)Mw߱ʷF x;HBa :ŷld?bIvs9m4'@琈|= &~+҃\kMM|O,%2֯I g HKnۼ)ckau}#fZ@*9^aZocν d")R_r1ܭ&W4a+ZBڍ\zbO:n[GAa=K%+?0MĈ0ݚ5qXF"S`c:ݢ!-Gvgm,&upe,h ,~DoCH?AɎ`$l5}8ZT{뭑͓Xk[ 7J-MEGR~p(K2ޗe~y(pMNTۇ'-62z!fBrDP7Q@z_ XZr7Bwp %TrR>e@m>[\h; `>2ф28' T#Ky7@6?/77ێ) &k5(!lQ, TT* T*;0紻jIaYQNE ~z?VAY,$ÃҕUk|BwVFX1DSjae=)Vwg-bMٻdc˹禣weym{r+:|J`ݓ3[qv|ˇ_~o4"8d+zc!ަX?Ymy6T}>w9lYۗ?$e]Tȷ$1D|W#wYOda8xSm!XLeY#4DG?!NsOU{"dRG㋂&_ܾI]/-DSGՕqix4cI(J9K8V/KJ@ j{lrôD'BӧPVsxNLUcokHANMz%G' Q8#QʁJFo]N˒jߢ?|8Mjx].k>\p ^`V͜「auXP5bRuxaDqI,8Dom:4`FH1(~4v^u@!lkJf5Ȥ2 ŐqJ+A{}:a~)7I csmI8e563! Y;۴Gx' D!Ei2A4݃NWnJT*R֑4JLīLMG\8e! ڭ4$b;9`eFH1@bܮLwқ'&g`H dlH $RT4a!*xԸ7KS~|4jcP[Xl-gGYpX #a"Ө-p:*>[|%Ǥ `C}H͐"y})Gy6xi$1PevmQi0WS_j'DiQlIVoRw2FB hr9zs$tZYX)AsֽKh"PuD{pzbcwZΟw{ʈ/X_e(1]1IXŢxuOQgUmfˤZE>apH/^P %l+Ӽ>Fjҧ+@2Nu^1}LEIVa;Ep+^"^ ɸESJKIggO$w4|@cעyZY:!4%M0 'yaeD C TM3_D|l;AZ0]E/zGce)&|P FrIϸ 6R扐lf}U4 cI*-r,/\ SLZ%>#VeVc vhZbfԼ'g#̝ m&)H͇<ΠD@ ιD:>ǥ05 ȹ}vXEA;˺UɖhqcKs[]!TJK? "^kympa[wޅ rD 똡 ?|Mݟ;Ű@fy"2{%/ȤT-nu癲D$lnŘ>^#$Íw}~Ŕ rgR!2t鬋*(m$TgOk[4@CjU9I$e &}2|¢;5 *+jެ.d,-<ǍVmVfpLٴ˕]vM4aHpceRΜIh( ߄Ov02KX]:Nn1JKz̗p-pi!'`Y{ћ\IU=O=֮fKSKjcͣ|VDyHH N97lzx&}Km X$ A: 3%=,.܋bǮ'Vyĩsӡ|C-<ٕhH^|Dܧ 6+g\HnEÑwZ!BMٗA q ;mX2$sAt*x]ј~$W}b$x3)2,7J6UAv{;*ɫ=rL9ƃ[#cuꘀEG QC)ǑwO/[ٯ*MIc22e2fv:x >ą:"QM[r"LB%i330Z{bdDjiu2Ez`qR0Fen:w`IdOxczDbҌͻURK}NjBHra|Bġũ=_;h d*`eIS+/˟lJ9-w&H,|(AI-`(+o9K`fՉfU}$Rʌ5s Pu2 T/暧>+i%x6CG}2[C[/Uy 5Rmܮ&[/݃y2|:LrYk Zஇ&set;wػ1/Jt"$ MNHXOb&{V^@ao`쌫Ɏ$6W$ʆNܲ,C>9y}نTria|fY҇&vigңmF٭FHݟ*lIn %$~븫\v*f[!IT $lA?wGF͍(h|3A,Ml&Nw+cmG BS?ud}ehedvU>w\>w]ʛ`VtKh|tԤ`CGSY+%Ulɩvў]~8®y1%.l>,\CpC k/35=-WaXE2'ť-.c DZ0^G!Q<$_2l6𿲾2KbI"_| *3p[(zr[2RP?c6dTB~LEWӔAXDhzH/r_2]̛KCiR^;埦V2N쓦mzo;jTh&S=@G@V7 vlACj2);M $7+Qcq`< V<[.*>+l;()/s̭me9Rq}I:1gEӈ=Zndۊ<H}b ;k“2Ն.%Xpݣ$c6!ڔi (>-+X6=C *dwSeZsaAta᫞s 7ź oЋ36l{{:{ s@ ^9"8kGʹ!ruz3n™E\ lpr VwaVϢ%n)Ȩ p2wvn}V p~{t[c?V~,gc}ƼYPP^:Ĉģ%+~Sr4n#d j3ua73.` 9s='+{X!We2H?]tJ[OaFL$Reh`?\D'T&cEȅo[MMD Ю!KFD!je3 4o)ʗ!;>\4q @Wq"QdT+j)e`7:!9&֢dg@oT;Xde2g|I{ic f"AЁ[dkRޛ Uy< 7S`!V }Y%-]z8l|ej p;Y 4(YEO)ca8P2G-_ w'sĊ-M br/˱oJ8qH|JNf"1NdS)cyS>~" W! YJ o9([,4X7y63`:OcOp:p¦1_\K ֤{MP$Yx+zWԏCTf୉r`+nGx0`wE{~C;u gά{ UEz_dК \>W5 F嬽.$ק㩕X{6ߒbXǠz\]onWSOdk22G2DEyB,';lɿ_TNg_Sok|?Qɱ}<{Bw`6?l`%aHW])rfXTⓙ`z 4F=7B Tڢd07ܫŠdAzb]wل3"4r'@@ ˅?̓/R:`_YCT1"3BNIpb$ 2TLA*4fmcn^=[U )=Y"%}S:4I ! JB:dK MOhvz_,;t`FE,mZ7U`2DdM8'6Srr_Pbf#(*|Nvbg \ąO0 u*m>]~ ֢tߒOПD3"xM։Y'ӇM2eꘂ S! WI*iZ>&K־J*kŽbҹu\f8i'ˁ$@qv<:YbNfGڪmn<~CyR? YOWr+' %㞳rk#Fb E(Ϙ!C~߸K䤴f[ V+DbbК}a_GwUT8!>&8ψ$(M$]Ft/ӛtJ I ʯQLK#eht觷WwIbp)7C:sm(3Z-LDP<_},wZoۆ+ׅ0xU4,Yo d4YFLtW/KʱR|'_53Hɨ5[fiS^1UmmZ0{̧BL,}p#rYyG 7„OU/jh-mZySy}c!9ީUskQ7|q4z3IGCs̸ưx %7Ԧ b`àϿL,p7.Q4HjEAJlr5p3[V{V55 P;BYD `}G,z6b-]Κ B&Hn,Bu eDfxҽݺݽ8Cֻ?qd=\:OLع‘<[nBYM%$)/`x|%HNVg}QQQ Da>PRDMHꝑp4ڰ9\1C12P_%I lWF  F|֚Ƕ)U2%O-hb &+J| <+9[Aԏ5K!ZeCVpTZ}];fښWCZ񶅵3˴:OGNHU`>,G ϣQw!w?kc|ݻBߍW/J.%&נ]͍&RGGU{϶㘦fFr _Ib,^0!TǴVH ?-En@IYT7ACUL\"FzA JJaD|[Lu9 '9ƴws.I$Œ?' .mIޡDIT`Cߙd* f<,QR'5q0.sldCSKysme`%{e!$,yu0gߢn,VWrLklIcif-rEUoB1$ob﷟?~oAwhk,F\G܋,<2D:SZyU&{_G%, cޭVsf,4Ekɳ MgG5A- ZP CIS\N=Lklդ[dȐqڠ2sMPpEAqABn1<r +,+]&8 [U.æ)[4(\$ Kȑt_Zf[Y+W8n5W8{O0\5* K-)3+#37yHPSX/oTHtp}I?Q;!+gݗ@W/#FG't?rJasOfX߱gtB$IAƥL':[xƇ$_1dBS7fIi H%._D{Qܒ{H NROxKcEz}xp@RɜFL^W$*17#>RK8?b_-2ȕ*Ē}m `g(I20};°?Þ[F-LYIGĪ̫gu/Z'Jrj-S, FGJ|A)̙mP(9hnwԄΪ*bݧɝ'|r$9͙RoӖ;%Z炦sWxMרVw_$W0ȵ|Ds2Mif#1~?/~_~o??a e"jm0ةo#aAT l,&&6# d:}ΒT#;n$ee4{Lylb] J,N;tPy͕Mr/.2N0=mWk;ߤ9x t7S">6a#⮃1p~`]}^U+џ$yw˓#[IVabvfX΃4 j_ƑUȋ>XP ]c*]pNzKt~x'RfOf 4+VpComx|ok];BhD*0Z<#Dݔn2yI\.$"By,eĞbtnƌ+!'\lM2La v|`Ye"=nVoI&@g!ya".r4&cU}pn\bmWXذ&빍аa4iM(EoIh%֍}&l*fiNk#ܒV݂sRXX X9ӛcF IM!cpe rZ zC~."`9x7!#>Iꄉ ^7=e(6G 혰ra`T)h׉}&"2g,K h(ӞR8W~pf_Uیwެ{Vƪ$?[&b!:+gi)1˰!lE}XbIq}'::^kj(]Z(T,CZ­r8鍖0b]-+XԳl- zŊd嵲<{_Lλ+| xtZ-'jN)cfHgMV.2)y &2":4^1GA5tÝ=ȪBg}%σ*3$~či$_)#{%yOqKNc/QC (]OX=uM"$@r9ddRI);>Ԭy[EM$T fۧ9"G79|)* 6z7TxР:?3M ĘNYB٨:U6OY q\aN"4qj@vJYXI<nBuud S~=F v 蓶dA fK[@+q6;HH0D2iN}ϢxnxzRF_$>``'  [V* 6^w㓟ĤXc~?cJ~7 4D)~'#0C5@eOFpbg4 s8%,Z Τt343q݌/HRlJ:օ*8yJ1sRIpYxBJwI <r2JXx1h¿PCP\ozaE1)}BiHw xGIlsM$=Ms-$&_Iku SwP!hR>* LI4Ht3Ԯe&Q;)۲ D$PVB<]uC+)V[ !t'MH\}׹c >JPgYlT+ 7Dyk/q{$,!5d#鷸IՕܕłK$vLZw+r:[uadv1Kx~fu"(z!Vq}a:sց1 H[Q#Qg9>ح6-,?uJg5c%))5Q^T(_m*f)j$V23ᴭTXf}}:d8anW:xr\|R*Jcsn˜4bog#2p_ݝ,"lu?cni݋7LrGzkd>MWΐEWlzͯ6f>a;tHVeǺԣq}Vn!ۑ8S:{PܸIdk&O?jILrq(O_,kC'B>tەF4;2|vSYn<;іȭʽ-'Z% ؂ɵ1'n>C Z*: c4k6A2ĢA ~)Fq|U(d|JG=}|6k|h4d`_2)|B єXpnp|xJ^3NK8;;5<瞘`PV ̊y߶bb=oòKJ7f.ގCkγHe2nY+N"LSI+#ս!7Uyn> z>d2.!\0-7@;Gy=pԱ,XQ=e6YɿG ʊx_G<>i$0Ԉ9'$ a$Cӭs9/6Ŷ^~ } -)/.(.])xaMEN\c8+6By9EpMeR ۢYnpJW2pb<>6K2~ zfKo[pujɪT5{SN󳄞u2&F0zOZ9Tapo??e7ws:r>ķqPM%T/U]_8ĉs'p{V~ɍզ݂TĀ\ 3c {Y?uRIfZwa̜ ]09Xv&)NhAm,[Mq JGTv?ZȉՍ5#ԉU,9pYkADm&:D3wP^(U. p~񨬶|7z5DtJjĊMxE:F5dzz~#Ze}$_R]xΒalƨ;/ɐg "[ܹ+Ct'xp'Qb%d@Zu=Oލ}=6Ռ*tIgjwB8K7+SPEt/]n [7HmS&HqmeRN),b‹8HD1 hOtVc``+Å[AJݲ\>aE;?' aYcGiV)WߦV_%Y1sd mRUi~Gb\>N놪k v"|/q Hέ]kn\ڋa$]_TFJr+u1ꚻ2BnG:|9m`/J d=g GEtnV-H^~]ߚ.)f]^B%#ޏ;?un÷~{ t0m< ?@8akړL1.DՃ(Waԏ,~iaOP50fN2'kEgJ@$Um>r"fl &;bҿjP'?g4{#F{YM6q1ȉh!r/bb!$%YKPZ[l]YDNgS̿}lh FʟUM~O,FB/y|906Tt4z.KVnx _2;u 誀N"+]Pm#HX%3nl,--oH|6'o.ˮdϒЀWHPV+ӆ\Tj?$"=@;ާe]ykH4,%f0&37Ƴ,8Т8+PjϒWoto.uw =jt ?e>/s Z|"$`%v@P\W@ ͯyKѡ?U] "hbx]Vvֈ_)v fg\[Kg[߂=ab}䬤[)ϯJq}T Tug}>uo1qoA%!_6&r?H/ /)6> bHal~`G9?(u14eM|>6j /K6fRNՖ󠄬Rg#~4n;zקJ| }=:$Ψ}ܬONp4j{HnB/ lmH$|đ:@iJXL]%,DihO~TSGCM\C@!-)q;+wjzD3R@bJ!s@apz$+'=2UfOS| >IF _4umGj̊Hlgҋ^*[34\6暚#)~þT^(x&7s"d{W?ao5 O/ Y$!.l!,u޹ʉSN}2TTBLjEN8tΛhXx"Z+Ғùv U]'hҽJsg:OvwxUh-Ђ2oh4^#(3! `a[ޱlPHa:+☥!i_ %#gٚY9{>j*|K(3WsREUnUr. k<oĒGN6pH} '$!z\űzn&ZGF驄i^ NMl0N|s|@m#!`b{/uةsݵㆁOyq^+1FKwEħ1vG; #KLM%IQ⫎zMY0Wۏ ⷧfu NٖDHaK`-Y7hν8SVl ,FԱADqe]Q,H aqL=c:7;5텊J(-+zDg hELP"GKD3fނ hP[!pOxi=ubw;Gyeal̲:dx2~?)Mݷ A{!f H-!OBp[=svj;ǯcX!CΉ6AY$UU+nXiZ 1@M1>rΧW<"{t*ZBtg& ʿ 7PvU$(Qm(Wd߮U$ud, t=sXSLx Z ÓӪeѩ'Nd"ٮլ 3P n`H} 1 mݒu;}}'#HXLf/Qׅκ0Irf;0'+'q}۝.8g&R cI-"]Vt)T7= d4pQj4N?zVO+6J'iCJ }YQZJ[߁qCua#&^yVDPfYR7/fAMZe] QwBCJL`lduɕ Bc72adB#IH>'guJ;4 +}=y<#'a΂sߟ~_/?_~4C`R7$q0hEF9=Cf |$'A!-Ow\[LKlż'f2pvhHuTۦ;ӨP×Nn%a5oaCJO^]2e1KAރid3ӉCL^ ~7^A !8IV]e52bd6΅e!Lrjg>ƝGbwNnU ƚuJPYWVwql*Vc ġ#xD[fB%ayujsJ-7\"i6uSGzyHĮ@F yrTNN2_~I0eSO'~NY+@!fidB5D`q /{<vo鏟ۏ?}ߗ9yl;#iQX^ ;;tKXy23AQ>r/ QC[,~Cr77j~bbVQ`?vRnJ<'FЁv"N_D#"z&:9S3v,AFb^0--7E8AF>Wj !L7jk<t/:87?l]NlW.@_&~6doVtBaw=E֘|h>+tL'[1m~5LjGwhchⷖRCJ]4;i |(TJ(р.{#}cTNKZ,F*+VQN"973)!-/<?g/`*L(g{9 ~>ȟ c̒dy&F ps|X@`ݦXVvXrUHɓztYLzcpXV˘r `RVyG- 5G^ F t%عPy6na-N9DrG%dF.9^t ';n;m撙rQNRX| ӈ4 >~)V-A.An =QNF"m]oCdǤ!?gX0F1;:twz@H͢mn0(n'5pwgdF,iΨo}AٕƩ[L=4ʑHrî1M^ŌJmKkZvI7Bju^<Q 3s+NBBe5 Qp{-P@!Is`EBW.V /N^B0ɬoF$a~ =gP ?]_dn7y/|~wR`Geb@Lo2޺?(L&&)TʿDR䩂!aL*Y]Et~I=| m:caر*vm'@RV'C= E)1:e5#.4C#.¬*. Fl<~귄m/{uDa)'~bg3ˎ!oQu^HR]d&S w.KfWpbnn߀Ȱ1YwwpNAl9Fj+DΑTC[RLzii5I=)tmƾ4"&xQ.:JpFŦŝC(ib"bbC^"?CMw9Xvh=Kg!yiu_5ǫ`B#O r]`dk,+#'40cï;}t߄8;}y|GhVF/1dz6;eMAX9-7|l~I,Z|#uI \<SQI 90q(~6 HC6n2l!Q>"U+c-/%>ȉ]d>2J+yvP= HbAREKӝexe:ݐy/]N (k)`l5X8jd ~,D{a+w@9 F~'):)u= C-9 &jPpq̀< s̻x0b|tf!-w9ގ c[RV֕aMá8+䉒n,~'8NAbhp!. `4 Ē`Fx0W|[M"&qA;Oh&5T`4 }k&{ONUj3r|7'{]re .2ddgNCɳ⇠eH1^ک1p< !47lpV\|u|kd|]*hЯHVyWG<$+sEHv ,u>|O V5x*!cT0lh֚}[%n!JѬCm&eY''4۩<9FkyY5UqlxpnP 2x;ӥ $mO{tK%xCLE%@v1YɑF'CQ=acy{Ok^lǿZ[}ˆb|߶Y["ldϳ}2\|xq7\Z46 _/ l?U/M&-͢=c1 -p I2< {\W 2Bgd =yc2C δjq W}́$χGY)K~(=v c0MĴ^$R¸TzܺgLJR2tÜ@EJԓdn릓u0O>mLnEN=JBlUQ+jikY@oo`#5mtpQkў\SN#}L:*4QEt >||N6D28Cډ?dKON<)RT@%Zj,Xa VlQ&;fXf֖!֦ٚ.C8#DT1)dc9h=&!*bJ@v.wh~r(d1qs왯z3+`'읃"A>k[5£-+3 .<0WO(@{7M-t`.?qvjc0hlo/WOt\r/ídX?1ǧiijIF$es|dvBnYQ+gƪtսgy(siZk=XQk^Rp@˙6Z <&ZʱT s|0W XIj~^C?l ×y5! qhýŠZӵ:s%?i+;k6Ҟ'*ۍ D޳S]f݇6z~/ "9u*HeLfWXEx.%!b#m6=DA~2xiu5*͖%YI&(ґsV,Z!Laإ,Ph{!&NT8oWkpí#13U6cB7s*O @hkf>\ \K,>o0&h7kkI;fJ[ =z Ot:.ZE.c[+0#TR|Cz#Nlh0g nG0^7Q%]&jIHG.J5VV},@͉sv T$ {+o沐Qd;k[',&ˇZĔ^L_}5*`%Vbl`9yZQ4+?/"f'%J/g<_F?{>IQeNKw}n_˘:e* "`4Y* ۏ?_o?LW2E7 ޶'DgdL=f0 R d9hv<΀jwI2ӡbh*0IIz*˜L$n 06vx~6 y1%.9DސwgvR*켆Q8nC󅕼@W4}Hh q?'xŠ;oK*Ad=5ʶ0*|e_8?b X–\Nv$*[Kn-t"7g#Kˏ@1oL~P7Dhʖ.7ؓE픑ZdESKm$i䋊IY+czSɪ1埁zW2{Nē#3$аB-`ZN]<0NCF蠣2A ߾-EY)^IX2xtiQl&l%fjWYCO84ǪC9a&=Lr4OCO0UJW~91wynHB)LM Lnj|wDk@,y'902Ca%YU]ϲsB$v 4̛Obm@Uq"xhmtƘޫ_*O%ѓPyЦ8cFnUR8K8"HJC(RT j!X];fȧSmyCGnV=M掹0݊vtBSjEю[F 梷jM#|3ϑC&x$ \U|s? IG>;C||Ű JJUߨ -30!dkɱPe 5[L<y(PF;s6zU{n$g (Qb.tNIXĮYyboQY"ݯ])Z+myq{D,b;ʪhvId@bG="ַ}&2-fNFɥ[ƛJ=|eTU4/Uh*VL:G.x#e h ^47C6XV _;,a B*1F<)d9. g^*}wܓ 2Fe{Hj"n(ƎЙ*w!"[R ,2(‰me!PXج`!LKEqI#XAxeHld"f%k1^`wA%ta/8XwLH/FjͮVƻ=oo_u[O"#VM*3|38qx9 &!vuY&.5SDըވ7ާy1V-jZqFk>(T:DEbeQh[ Guk7&:eiͼY3ź%Q?ԋn]q ؛ηT: U SV\2,MdYsa@ rTn# QRG(7(!I+1MJn !hT999OY(Ͽ_?zyĦ.l︯Q\>%3fdJysE)'2ٮUc?-?ƺ&3 F#H"zQ7.Z1v!#?3ڹe~FڨSmI*~K 8T1Wqd&Ir}5^ZiwPO 2ev.X)guYϟ5qǬk%--ÝrÎx |_;60"q25,*#F[XԵ,1fLS3 NSn>ta1,s_OS2sunZbW֪)RcnC˷ѝ+ `̩DCb()[G-V rօ7 ow"{C-=]nc7^1eY+nCE+Ŭ9v>T]OHujV[\gv3jXU 2`'#''~$=W )ψ!!Kjk*Әzϟdw{[casT42, 4+ZF:Lf(MdgDZ%9zd2p6fcn ?ǰ` \ɯN,{j ;Re~c\>yޜiԂW+ TI}TE$ TVuX2{zYќIvTSw2SU_d ^&yd.*3TPК;&O^|ԛTd_dlrS<TZ@_?'˂扮7+|{֡?mVa٥1{槦#e LDzZfU'kE=(Ʈ;FP} 鳸d8[<;'I%Q!Ve֚bDؼP6Jc[aU^4rIjrb?mkQo$c<4v4|7BIfYʐ3~m3hA0֕O7®Z|\n ILdNqwh't`sӗw6ȁBB/2d4Nh=7%uG4})3j(^gV=ZeL>zCIt/GYOĭ_(q!WBv۬i9Kḱ }C=%(MyE OK--m*d'I3rUh?hh+2J8ӐfTn/3ikUwߕ,/Ѳ.}KVz^=87^xZJ|KtMmTp| p7>s2LP @eT ^W[V_fs!iOb!Gw5!\;&qpXZT΂9x2'=aRNQ&YBsk3؉O\s47>w M6j³yuA.~8zo` ;Q'1=Z .j?{1+eKxݨ"p@#NuL;{mmX>T e\B<] ߵ+;cD {$s\Bԡ3\}1ĉm۽t;l]4&R_߀ FhOvE 6J1yWQR!sR^fo}%61MK&eKD-~Rǜ^7&ֈ D3Uվ/9_0vwW dK|Ҥ:S6OXs,.ˎk:ӱuFCͪFDLl:+KHtb;1Zl1е^ɵKd\W]q(3-pYHru" ߶Hvf=9% Ѯ\=(*h 'h54 yZimֽ'6T ԑV ^]HVтNn]|þ #|\:Sa]|.ung,<>zp G\d;<x< 2gz0'{9bm&Jl2He"UƼXĂsh~p:q&gnW+ #\Lf&Y6q&v`}-c5YaĢxw^GϣO>'&Ȼ($W0}waT^AMkzUY$_ ~f`]i{{^2zgLynDxBR 64Y- 2PqxZ݋F[HfR^J3Je<'0-@t3tѤp+>LKZ-Tb͉ ~Im9F\h,(F =ÁRq'NV'=G;h0N1kSFTƳk {KY1&[oIdf:AyZT|e/oGR'Fs$Kp J 8~jlV#n Bc8s3*'mTzZ"nFl{ם{Wˡ4 DXω&BbGz"=%S !`cٜ'/ bC%!K۸i(0QOy %bH H.S9zF(!s7و3acUY.@1fkPP"jYAN -&BeY8jNLXqqGB(2#ѯhpWq2ɓjo\48XBďģlUItB>|H]iGEӂYGe ^YĒwrhaSڎ=Py~յCuԟ(5`s(7Î!(>&F Id!aI='+&;\z!kxjJo&6';S(:ݿR/?O|nE2yHIRP(\Z|7 "JGTPn\-J\8:i.҄D1"N4;%ۊF̬lko<~X>zd'brD5ZMN,zԘ DԱq9|B:DA7ُ1su߯Lޤgʭl,[*Q1[f(aJŖIC\ _YX׼ =(w[C_#%D%ƶCPEb5=b"vN/'Z V#؉rQARN~VitO?ӯ?{Х&Pl1+DQrJfٍi\iwf5DX՝e8HM)3 PGKmm¦=#4f^ Cko.?ڛdf1JUUZd(tNa' ",;LqZ]%c (mR9IwG/~|mkHPBkIj/NxX5GC W1\؎8I웁K9 9IM"`E@.dLZ,"ėc-HcpkJH] /"+SCN]rVfR(#h_Dݕ>@' S)WqHv22\vFSQ4;t/M:BDÀ 81>&Aޕ =ZKA;q$sPbZQ_=x`ے9q2 d6/KFþ(w6) `NSAmE%<<ʘj3Bx:L >O6̎'R~_xksTLqܟbn~ we{5[+ #u^:ø~6)l'@eܨۆ)eD|qcas@~ƱFjFc1Q.C(J:iWпrVhP:< % IwX=kfO%춽rßvŬ1J,w<78~c/ޅ$'8wҖJVuqg49f㽩Y d=gQvvʖ]zuV*PV&vjq>J=-Hic5c./A/jvT'! ֟q`5u뚍-]vq؜{aAܜSN~SړN50}Ob%vqei1M_ԋ{\W36,Wtdɏ 2g${Nq3]r!񡃦%9N;\֞~0 O.J!֪`F~Vys'vĈ_B>IBa*'C㉹\>?=wّF7rB8QO! gA?!ƪg?Htgu¤Z.9 ˬDbp_0l9`.rs~gcF݅Ɖ(ѰK\!硸>^ΊQuQ䬬h F%]'BV~mJA)x9U0*$bKkl[㉊W6PypB0.pPSF :Ђ`Cn$+(JGVX \5[!",C=VP{.e $5cVnm_vFկC)Wgip'^%HwN)QSr7s5?r\q6BxC-Z4?o m&BNlvBPli0ѷr bq Wq@DwhxHrp.zK4Y%"FQ K+Lr&!aN]zU|9'[bX0>U qxкh/Ĺ`ȳ|t@}L؝7!g6d$߈'~Dv;ö'5P՘n9}͂_g$%a'J4}*Vt8@'Z0]0iyKmѭ`H89*Xdq.]3w&< N G壮Z{f3qǍﱎ2c TVu,ZPmY}J_IsX  Q50Nfi f; ɻ;$3ՁrMRFtǾ#ɛgW [C;% 5/A `Ђ:W5`\U货Ɯ2!](`@݋o QJ6a774bN~y+۱Or<&=Qr_c1RJx G4 $ZqRQĸ; =+7-e,WObx;:ǁٍƄ![rF(j,Tzo@r/&KHsn681 Ĝ߅ZfYh({{ݼ"ҩw겤T:8ʵYy8<8 f*YYmKz<>ge^2J+;^k SĈSz 6AX:j`tNSV{6e%_`Q*f*.B띐IbCX1"@(/ xjxFL?Иƥ'Ǭ{] ۡMwL={eC],8B t{Ĵaw3ѢC߀WOvӧn`[Qw)19*នHOz7ƚ ]sg ϺF'ZuB=J]-hI (˥ z4iOeZ?g6'-ߒ| :G0*4+YI+3{/ X8g2c:#5r.PDGM8H.pkS^!C7#3{r!v'׼t'˿o#?J-#?) qC,|pT1M\] Z'7vP> }CDk[%ÜfXy%mjQ@׆&/ vJR58j2-5~u8 b{8O/NNV2>5DuwZ=-_돪ܹc؞G @GcYh&gSa߉!O?[b Po_r(/+ҥˬèFOzK%תJ /' CYjTÎ;@ve'qOˮ/-:*F( xoJ[n\$ UGTC-ӐC84WJy=C # 7Nl\!otP*K0cmMF5Cs8d'|QL\_\ AK OZMyfSP}G)5G_f^᥺{z.;aDЋqBٮw"ykPjQna%EY 2P6J7cazQq'r T F@c%U n=$B2xTžQDAcHqi\$\ ׂWVࢴSgHƓ-Dl3>Ɍ?+1-9AOzM 䇎K9u ZYq aIb6l[=Q;JOOZRz$-W~l5Zn ;…8[Y[Fm#1 ]]ld426Ŏ @c(>5(Ka6`z eLy1v(smn4'>;\"!I+1 7!NLBY,mMU2ᶺo%q[ 0#F|kSs S^ ]u$^" LؑS4nl>,S0T? 5!w$$l'gs\|`mxg?&L+[ukēz3ƢXj$f Y%i\z}Y"G,kwB@ݫb<ʋ%GEdtk!N.`cM9\,Pn nXq~Ta/>wCSӪ'ifpvh/tOYb$)u`׊Z CM%kқ =MO-XGs&|EqTǢX=. èWܗs9J452AB"$k 7x"!4G}ݣ<DsEt @t"J]|_V}N.4)/ F{' IşJPVH*⥭W\̸9f rΟ&RBDa!Sy4 G>Ј, QmV?ͬ,t U4Cǡbe^T rQ_f \: E;Rܚa[soVWh5I?n&W'yY)J\3o1\m>F>]>#l.@]nAЏQñr_= ncAB}@I7 ]举ͩdb͕f] γRC^H@črn\I{k ue%!Tpkdc#&Q ˘x' dQ}8NEPΑdFx͠B===.v:(~YBK5#TIZEepJEC Qゝ϶b=eW Rڪ:[CL9ןE. ]i;Tu.}+5 gqx1QLlFkilcF J;!<S5@?^2GΔ}9x&LM 7u x^"-ib>2pxM 3vc%^2#hy b1ָ3WS{اwBPE\g))2i\Cɉ(OR5jN28ڶ7?ɽ&{]2 @AB4ծim<Wb{ok&&FBF!Ggrx0,jkntJf*04*!k'Q Vŋ1St`#2BV20|"?NBn||fk4y,I-,F~9OcLh?oe_vD́2fq-nR[5 emޛ^61yz1ғKu-;cdғT[Oz V驒6T$7?A!AF) cńf|q.{>O6('jA[mXdO =1 9#ۅqʝLO}B,:NoIy+u>1ٓ#`"v|>v׼/evV 6-.o%| U"PE_;{I5}>EHK1?(OB ӻ,Oh&@wQy*\E@JQwYx8QOZ04.įҵ%EQoǓ.? ޺4?KՈ^­+XaBYUtINLX gTNg 76a">=A6Ŝ{52>ފ6WWY Nk~^i3}4=aE^=!e$z9~hj\냜J3"_F]I7n^[J>sϯOyBX(W!/端?cJWxѺks~Dtx1$,bIcV dOC4fup7{0ǭC_!JַB.L<ժ hc4  ۣȮB9bA aJ&ś`hP'H Ar #ܤ|ڭ]cN󔷣w\IPNsH1Ѷ؂&R8mk`DLK)Bp2JV.*i %ܨPq:lSU Z%\jMp1R&)}o`-PˠE3X*yW`4i%*ץ@]E\7fax1L+K_jKH۹n'.*W@?*^ W&S팙9mޟ.nyZr nL`(Z uY9n"A'׭M%8=k9=Je1c鹵r:U0A%eH'z *uomERI\ewq+y'͕Sl=MM w}0DEtI6+ohUcL&xEɲʠ|s4>R- րxZB8hXYJ,&׽pTʰHܿJ-c:6L b\4QdJ2Zfn;2h֫f7Q}u^FִI}܏!%ifCZčI[ <1D:[R62iʍk噰]'kU;I/ ?UnI1BEd_&LZ߸-tLnΙ#TD2/8 /Wհ q´j):HMJ@ yX7cE-/,r"\Ӛ8\ޢ% '%#~rHxIu]Wm8 MΩvm"qW8%HfTLny 9wֽLb {`ej:u$0ً[|*B̪x/^3NۨvzNqiX}>G(.2Qn5q¦6er@_s&*})bc_/ڃJ6MsjNbTk =3W:;-=Q_]Erͣϡ ,o҇c‚E]Nxko 9BHv5&'zw#`}rg8U5w46r3Lˤ_9I;u_q c#`/ꌕHMsfkhtK#oan"Ѥϻ Uwi<*cciǀ2) 0I&@w8-)}"FڌVژJaC%7'XVJ= ~U$֕l{GY[@(ޏ2!"MQ hu'<0&So{ZX+P: /}78L8^,K`lˆ{5lrr[['+P?oD7 Y&Fz!Ft}b,ϘA8eۀwјwE(=ҮE;Cx:hΡnSQ(!<&!~l>"qJwZsl=nanfulIJ6n~檲 re$6”$$iYRk5 2Q r(@[By6|SD{֎[`+HLSzC/ĤYi9{bV|{ӊ,(6Æp>̓͠`s@|Y\{>oDg6tԴ#X2jGgԃÙ%L{U+/&j''ߔOS^. ٜk,By-4-h=uR5ZOwB r}Z )[G4o/DP9 /4"a@ ޑ+8TEU!J7D,12jzӲz;Ro*֞;\LJDwL㞼)w+ d!mgZ_9BOd(;A}KcMT|{b%0|(j/1rF˯ q|UzS23wNma*{ε{ͼNnnIW}|6i9|p3t*l>"1vt(q&fmHUVDI!d&dC19/u9E08e1wI~z*\r'OP3+}SZjA&]/?[6]vhz9z 薴x~ͦ?bc66lLR Tf_i3z-`~RduIRY43KE^E2OKEn/ @`LŠ)n Hega,I(t6VKܾ˓:$ YRYA}#c |na| k3vc>J*acy8~ )Fx[k oK'˃ I@wGWةvUYiNqx=f@(8 3 `hP\+JjYziӢy[6NM%7~y#cl:_J yqfԮTkդ~uM([ 杷f(IP+9hȃ=<\Oi+y$jjpoz갼kcgu`#}; {% i)_bb.t:Xj'܌b[=`ԢFk PõXv"6icfA8,Ӱxb"ı=jT \F0c> Ştq&4^1HƔR8;QbϜ.5y{L>,l9S%SƐ@L'B~o;p ($q{++e9W>kXM13" DpxpOP̕o`zEG󸈽F@a7cL8`G\"HcJ_F|Crچrn( Iʳt٫tՒ\!7˛Dh.kF.7f#~h|' ,Whu:/7x?BSpD( Mc!+z5zXݨ(:Y! U9oaU&=W^S? 'eD{+eɶ$֋!'`MqoN"PocK7>2mybk~&eoUonBLkd& hxY v&5a۷@ @J~܊)3kMv_%TbvlYT? ڛum}"/el\Ү[o||d@sI@vU|$`FzNYPXM-Uv}ۖD%Td.c'o?T;&|, FE2C{MZ` VĖoɝէsA$ƤT`Po,hj>q(Vu[_xn@Uѝp6VLZHz}: Ӿ-] A k pmJɢr04c > ` Z?hs5!:>@횟SIwLJ$ƃRj[R)niڨܬsgqa:+!I9߈1tIw* \'$]E\y`l٫Cnu/^?esiX/97Coq_(_b;NB5:.[ǁ 7 'AJ%Dg͘>6 W9P'Tؤlqއ5Nl_Ps1.I oVO}_ڡ6_5*J '4S-65{ >otZ߷ױ,hHVHcF_ʡ~h~:߃ɫN`pp QJBZ\~Ǖh';u$Ъ$/( CyF9{Ѓst|hjdgMQq$8Gth3NϏ"*+ N;$웇ؾ6 ~2FE4ML 7/܃y8"E։oUw;8V" 3&cΆB8&"B~u) Ssv̻{aSJ1i$Z̈ TFV`ÖBx"r5'9xMHrڣ#-%c:@,\IOMHog 9y^Y&!vmjG̦?ܩ;/|wۥ G!IwilG ģ.J)Ã-!Ud^W!Su @0An",M,eֻz kwHIir|F,o$3Ğ8Aާ(5@4%"Ku,E0X:SPKbUg 0Jb \Dtf/T)٘6VeW^6'2e83OAgMz!|c@I?l <*vF\)Wa|N$g"%oT ̭"[bAzK:tcΚ#= ~-Kҽ;Mt韔XvS[]g7V*C/w<"\Ҏjs^-kܔoV6`dCh6H@FAaB=2'.Tݯ{O(DÉ[?-F3,H2S IȩhR$^TB;O^9l1 Vk=Ng_#:ݰ[Vб5BRrФ~^;} ??A3

qT} Ai-˓xU?L&{<ɸtFY  ]{DprFfnaD{1q.D|Z!6=hCQgTK%VjDbךkSsuNh+XY+{fa_f:wTϖhox?j V}?ǿ믿o~ɢFIϩ8FC X !a:msx {J_s-NVv> v'p#J" Pe9Qp$/M?<׎{6ޛ;i'x+c'V@]Ve.@+;<7ĀJthQ_9wWx"^1. w=d[Yцx#jD+o3CIDǸuf=qWPYk1hvƆY!:;w93>ʀ5MD$ÖqNC,S5{1/7'.8^=H5aw|FS>Z16}RbOS+;nw8tRnx4ECS~3?Frl  .qJw%q $QeEu?Q!Q3q#> 2dDPͽ;Y`a%SmKt[ (i݋@?~ o?XRQ!r'|6> oD /U%R\)biCr Dry WxsDmyN2fW ͼ4e)sؿ6\I *ObΕ=\$A or#f u #Oi67m\SV.e]cqq6y *9H+Ih$//,xl*㞁O+QeR:'(l fŲ>b0Ƌ򆍧y8=Fv+ GSfu{,a\Uv"fy "δ دc/g]N*2HUeT{O<퀓}1OMxMVw~> "݁+ձxQ˸%xGE[GL y{Qnt|P20g CA'+$[} -MŒ> wĴtQ]Geƕ_:OQmlӣ^1n㟊׻+ʂO>1cFLٝ@H YVdf,G‘6/bo4wu P–vJq (p [{&KЗK7IC$摸fi2z;6i14w|GU P9zj61cl.93[8P¿j0|9r:uT:D H3L_}kZ2seMA@uic $.c,'XȊ݉{AoӲQt+ʃD 9xyne"{akQa&U"ZʄvZ@Bz&{&QxY`I^\cc/Hcme/+CQ87a4e$c.PV0}yܲua*Gr t&\{.<;I\yIR^\Y^Ch,TΓ({ڧwwkH#~w_IUeP zGq.үodh%A2C 3WO7R_ A1%Q|Rx {t nZՠ|n }m IYf(ʼnX;YwIW2Mvi"ZUbYu Aj1@)--1KP+fD$VO͡dFDCocrS?P~׈tФl}vLRfoO+=ƯgoB![ my)'[_2l#4Z.jSw9&cm!"FڮW[-XLly^&4A;"|bo>ƍ?y%@jg"(Nk6@CCǂb< - Ta€&6C2B|!Oo'- ,GHUjzs9* ݎ.Fa)kpфmSMj?\2=@{Q'ť2Zs 1ޖe >nL:ΊP)d;٨!.^m6FR ͐U)'q]#Վ|˓ͫ(2rڐ^n7Id3Yo:35sJER1~â}VTGT]|F`[ U;ّ5i2N'6ZUN`>N#ɔIt0;𭋟:\]tH JFDR|6:xYcYæε>FLxp5Pez +Dٌ>4v455q] } `tg|dEWVD.DV: y 13D%|ͷ8SgTPn(kdqBiU}p1(șwp@e#6eЬ,$bxέaݦ{thf]s̕c@= eB0PJO{ =D:O*?OCk^߉D`Vdu_ Wl־cka ?zy9ag{u% ⁁gwzV[\-HNvZohU)/8_6$6Zd$ŗt7;1./*y gяJ*UQqWuoiyOFCQ ౠJ\ۓj0G8tQ{?P4ΪhʰJ|'&˫x4FEv&?SdL|.5iR2};J{[4%P։u#j$qdW#%,@8d&'8?޲L,Մ,Eĕp\<޿x?EO$njNGEi3kJ<:)ž EuʞWxVΏa`~X~ҝĘ<يݧX4Ƃԏ]ȇ eN C kÀҶ|ӆJ}C9l&'E|2W\GX87nH=6w{bt,] ȈDbwn}-oj⧴&c{k$. d+|l͹ɩ5 ek2SODfDfD!m\Јjf%M֞rk$Oye`(3.ūsL",HOIlw>H%o5(7'G&+ %1| ocɬ" ^̛$hߛChϲ[)MTd,MN:|䳫}CTJ&A èÅ#:] 2="G8p1?0?{Y=\'ěGz4 J_q/C9e*%/M+:b֯Īr^Eh(i}^]'{Ѧ5eN?L$-§>-!sCZ!PȖ,7;9>!dG5VΖ޺۴վiɄIB\7sJk^r)@nɪ:I n_lV6s e޵Wo@8\.w~ W~߿/oo/oI ə-"-A3Z>p $p5J~87QJ+2LL(/D'Fb{͝?@t,`-zřj䬔[L>EhTz k_2{]n^!A08nIծTNT"~PBy0vQ'U8 '@Q ;7p3kžnC9޾ 3"pv Ni OU1?kiZĔTS:r:KF#5apy.i8qID' ҵb^vo?ձ B`Ql?.h|gO(x0 O;r&])W[xZn26幒dIeĸ*&3 N#г4nʶnTYLLOD*Qtiv? \Q=,]Ahu7e~1˭KzMg֮9xzxs1侼wY9<7J '0\k[z&ث}dGOX[Lzc;i4$84Y!zXz5Х=Q_IhG 5q ( L+J{j]C>0"R#ȚO,\m' ;k(Sbhq 2K̖_ DOk؇쨭$-9^Q; M;?(ION τK~aae*/.шښ9 uҹu\Pcb05{Ӯ3oMKPOd?yt,w*.)n,fJAge(Ԑ9,ako,Gz"٬cp rN+ VY4&4@F=¾LvPj1ÓS 6BPGҝq2pN{>HdUX!dj]#$2)TfL'^x'$-4]=@sqbk'sh44=~$[Aq$3_(Ȗ qXEtdKs$9MT|nf"+SOX\ ,RqQM(gCnB1U߿ RO;ơEun%+]ib0Z;OAψ36_vca˜k.nZtXčש|Cǂd9hvgLTG%LCB"u)Ne|zKdf}PE`4zjY(-W6FSE`2{?@;xWphO_!t)2wvK+~ x~+j;nȽ=% TZ;ZPKa:h#ge0rCdZO'ȋ `5p^?-믿Ͽ/PO|,LF=fWoygh->i/i]ԐVk}PX@ICPd'z^yv*uit9¨VbiYa< 圂 G%0W'BeEOR~|T=MԎ󵏚]M}kl[ s I()ߤW^ 3'e&PoC#AxhBuĠd%47MYn1G< a?ONqe7SjǼoduӁ^>a@,nu/9Y虛e6AjWVv8Vƀʐ QT| w1)9zj+/1@r$f#PvMȚ_Oj)< /y&QsL{Xmk[o1 | lD8ht[/]{HN#W{?bG xIxӟO뇅iU˼LvQEi=>sɳ]+BïCgHyt&ՠr1u@Ic%FB:d:zu10ld`tO>qonʅIx 5d;PM?IRo6YVG}KڼgؚX5B!cGT:8=c*!9puu[=L~U FnGk_gYH?{%f Uη"FL%pXV6D"`VoȖy!mcaA*KenG4[SLVj>~JƃYNt?f7[zX\*Qd&\5\gMfOO w2t8L]GG^t:Β Ips񱓸5ۘK0#5>o|:Hd4!\Lfl x} G:d:mGh9MYS_9E86@E0KZ~iAdvuL/ buLɓ?!roL<MojkSi٪ "kܸ APȖ6-U'I'# I'xC< u[0{ \:y113Wzo,ȗ3gYvv=ow>_ORv!u9 t,GQcjxك'QHa߿6,xj%qD9{-yHagVT5%f\ rMLZ@6ޟ/Ta$޸ReEGx9H*(l:$'UmNSc줕) 5~a7ؖ±m=䡫~LFcIh։GU\̜k't:_EI_GVFgA=->$JFAhB4q TWsIHMQd4>*(o2+[~L2v+>Z#Ճc{UAu_ GRAw2\l¬ g _<X[l`Njޗg"Phg00X!8u85# ȝT:͉O\BzӄRHu%}2 Z?l 6-'gh}6wgm`3&ָD,5Mj TNڬ6NF˔@$[-ӱ[e@eO)quʁ#)`t$%Q߃a|4vXQ( |p*>$K2 i4CNu(+%Ii|c)୍}q>:r6+]mW'#s`hqԈ]dD[t`.n+B-o.d }?'h[.E n#-/ h)c y6b"bw? ,Ċ ~B?=4H֑xJހH(oUX=.ܳMW˳z&eIKg[=y!1gTT6\S֑VIT.s'7ڸЀdSR^AQ8mdɄbTz}ly2/SFKe|-Ò*Zcs\: 2Tťf(m03{8gBRT[}cm-l+ǣCȥ "d! *]}ZPz # }zϑvPM H1 Zb?#yVN1McZw+~ \\m≭U߰:cKrQTNvsH3F0ZThh4%~_[%e-tFt"x^a1!w"kWuSaT~DY\fLq nt'\/PpݾP7*ōX.dܴ&pDEz]NL!P5M.>vmZJVK1,^ac[iJ^%K(e~hX{a K»b q&G9B^(FaюWEYdj?}NMd/Όl8Ԧ:8m-I ]+LHpe06JXr݌{C0#<.D n3Ki)BP'Zf~@ Z p|d=| ZʇPmptJ``l h %/ + 8X{9#uXym8(t,Lh}Rs;+kآԤFeF-?f޲Zn}7QCϙ.ae@}~x+E&/IrB &_|{i{ 0hbKcN/qg$6O|ۉw? d&1ԝa=իBi%QW.K3gc숨nn.@Mg؛D`-f[jK! lא,te.\Fj$:ltׇM쯤L('액Ϩ&#WBd rnX' vϞ?cפFl038o6.pY,UwB<+/* O)p8̙C{ Yҥ3#14Ւ8+9|elubg/ F(*tbSK &9űb"&G(EhYηb2?wŰdHI@A):@ ,'KGtг?7u]"eRXu+`2+_S ,نsPסSݽ2)*ڴ9Z0PW-^5cF/5bÞ{&?HbWB:V8Tw*Zk հWuϬNyJqmD6%5t~b,gˍ1|ir@3G" P =u}syU(=UBoR0Zw*2jω8$dd]ɖ#$T*s݃Pbr9xCuaa kvHP޹ 7ꓧi-=x0 !s] D^b Lڳ`A(V1D` \?bXg0W׽&qKs-IPezRRhG`dU,% ƎpQO|o\YH?̈́boFMw#?}_xf+N:c}&{J ݼzȜƏ ~>4 Xx*7~"1Vb?"C.+ uy!ݪxI=#@*(Q)qtaDVjzDW_9F\sU;;GWhNB̊]cZ}2Мڔ~|l[gph=FӚ>Yh>8I>TV+{CW`4+M5 ̯ӹ2,yFcYC!ܮF]^?RY#~#㐲~a#\,;ej|ԴbBH-˧ܣbFM@NC%tpR!cd'RV&XؼWD$Vn&AӖ#:vnI`u:MH\ȣ a2=%w (3'y /f ڠ ~$,rx\H"607ɹS !&BlOșĨdA*AyjyD˟o3JS>׃V[շQm崃&`eZbZEsܡ hϳ-AM$Y2C\ b|LC9!*H 1bLh@*UؾQ)%Zcǒ^IPÏ6 rf]׿Ng܊ۑ0F>I5W 7QwfHZIKDnS⤷ ꟞Z2 Og:SIOcVmݮ7t 㰁}@23وd3V_{R,qvV.+ Ceo]G4 lDv/ X&Aۅiڵzn+S\b/r*QJWJ1I IIH*3"$ wو3tt!X[ P!!PL J5.o>;~GjAM.{Ozv 4VQ#|?#ǮJbD ӟWbzGrnDٳe6{@#i}>.DORx:(~P>GjsAL:7h$NmRڝ"Qɇe&[C@6WWjeN\q:cۼduSss7T5(AmFR>T%-513,h7#5J$Q-4KCo0e@dT[ #aCVY2۴4,DRW>dl̾؄7ɧ"m;SDQI_}]N㆘ YިOF7\?uW}FАx2Uϵi7kb`يtŭbސ9ARN-Rږ2b2<7(:c*t!Ů YRȘF܎X#<#~A0B3`]\ 2a$UVi玏?ج w&YOB YmD]-NُiSQXOQe+/21p~3>*n=>WFg(uA$8'Τg;fuU4uBꗘqkt1~YIYVgRHYh5Y#@¸#)Oe niZ!^~k.4ZÑɥވs޻.nH>_ekƙ]AIh%y~OxƣcS^..tʡj&a.cKK t Fu ltCVO-Πucj4z<"d'\ӐnЬ;#UaSLSq\Ny!GB9f4wEpg:Iw3FH &X?},9U{lPPA(olEFQ iB]+Nބ=屌 ˫t`~gNjNśfУ$#P\+@5R!ԯ,':k"7g4?Okc5ψRoDu)Йy3[[M+=14eJUy2iOk/[SsnSo. ЭQJ.7pXAbfʇ 4zWalNK1 }ze;n)G˭%P4[ T¯{@ǗN€Q;.![;  #iS:l?܎b\^]mL'{Emx , 2Rz؟& ]$I]}Pk{cIfH@E͊Ja` k$?vwckHwa:̀ !VnWq?"N1XFX@ Tre=fB Y.EB?a} ٹmmED\l2eNJMaX[v0%.պ4Z+#v)a8\pmnPTȘ-VK搰 #֚M<=mE(D.CqV˱aZU 73Bd$C}xS8tN(:~Nxʗ<>tQz6 22@Q~ԽffXǎ<{FW>c!"+&ˇ2jdqyMuzuƴU %.H,@ ejr%ZDҶVc2|F<(R#!v207OWF6ɛ/4&umNĽ wĝi:TGסoɺڈL7:G kr/.~]UH|1Vdk$ (]ٻFs$wUYP'x5uag5H"фiۢ^}zZ eͪU 9H,]hkġ%q"2aQ<;o~n Wt0*¢qT) :65 ȗs=QUѸ\FTwhYtsclLR`/\8|'I]AnRp&CfH9U%ؠCp-hͪpp#zġ`/=h˹}xeA!veٖ/6:]#:t% ּV GSo3cgsi/sMZ_zdPtW*V%T<YEӅzBh#YD.!2c*]Y "nmh:z144#:%66!k{p`;Ir37"xĞ!>zRR&6;*3&Ӝ8Xf߳Xٔۗ)B:)^WEu]Jw@ dk"-b|_rpwLLt0u{r^: i9RcHgwV ׅddi$~J}_.jD+~)Fo7hw,} r >Z(Mn6@|ULH^y%}C*6=^6\`@s1JbM tf27lދl, wv""*qlk$V8qH`wQzvfJfuxDHS7Ef ~1GUsM E@ |o@fGĜ1G`BT+rRq8p'xS|J':)ݖ2n0V}ZnAǺll$ oy܊3I+.z,f4`I~|'^5I\ lM<ƥŒ5)OZSX#\ iǑf' D&lq[J %iu"6O ^oߟrD +"Հ@fYR HLd4Z2s7٣Cja#i!%? o@hVLOXzBlˎ (kqQ8$[ף `t]Qһe\&ga;!`V%&| 8^P**uV%U]ѷh/?c\w՚lٚƏGvg@¨F/j*0ՂIנ-Qbn< f[3|]e2ق~+%mF,ˑ;ĸZFSQwAQ]g8HljwQ`BЀgnM"83BbDx0̿^}Е֤C9q5BpYp m?4"Tyh <_ qL"ǐ?e`Tms*Zx[e|X/AunL(ś` vRǂMWތ׆4igV=~T)d\>z|܄D65KX8'qWlG9s+>9?TZSM$VCRoNEEvQѤ%?N4tJWYQ=bU# 4Ej3сxy#*jd%)4eiY+<Ό$# ?s>*_8΄: 0ua4KF\Zi2k6ɤϞ%RC%JV7HFIktM^[瞂ĨOUGDSoLMo@#Ei?UixpbS'gbcWQ.pFLLrAECcUo0fe5hipCOY$M<?0muyfdLzOA ΨR4_2z:cJs=يy ̶|\V\Hb;)m$I4VH21d)F$lCx8ÐԘA9&9_9pX&@ 'uZ"%xt!Xdjy'CG3;1d|WO7y$|XVuu~PA1eTVfСM$j"S\317' R$SzW/'7{o;DbvwD^f&S X 3.VEe|2V52!GRr 9xḹnm}{ p6΄7  M(y曅ս셠f7Tb7i-a >'m3?#m̧t:44DU8@Kn.rn'H{ 0VE~K҈.c*W9L3FU*w5sU-Z'S*x)sW#ϯɿ:+⼑7A(Bi.c甔86s3]䀀lt1GuQ"oѥ#39&%=o6/ pہ:['v%6Mh+ڍ"*͖b P%blLe"<7F5X(6ԨR!6g$nnL ؓ8\Bפ*f jD&h-o`6 -`Cy]3`nf^d 1hZshDޠզ۸w[^YIۉ-1drDŽ~[0hsy{福Ym䵸V{p)uIG,(*}bBoL#hWѱXrToe'z>r0{Et$.}: ݩ'9TՙÑև`ښch6[*v3eFiuQf Jar~Q6ۻ٪JV+kg҇^stljվfo*!`oS\[p K,MHBr49͚iX?VQ.9GMN(dΖDv8ZN%vb|ʖ)(N <[(uJ۩@=mlTCMP0agZUy¸S|et:2WѓM Gm "QvMl["C4-ܱH F\dzz;vt;Ojuc^"ɂ>͕pOp-渕i~`)s3hti*G8;õb0wwѓO}[sA=Fq@OJd>~TО4} qN$KZ?dh+l!h8c.-Z3|zaˈRV}W#~]BBi$sC^0GZ5G(|WqQ[."!dPɁD dgW!Lcݖ J[v&6t]l8qN/77$iE$DNX|=l[-yQVH/\.#Wl4 39Bm avufj_D+O`#J p jKKiC8Ft#kbQ:ʺsVg¯igQ`>:eaEx,!3Ma͎~j~Tz܂#Hw|Wkρʮ&N 6e 0_CK~+6M6nǀRn$&2~gf1Jj޷RB1RG:m2a |O\gp~wC`z=m{0!D,%vΩvRL\{Z2Rzw2a h[hq:׃Μjf'Pc,) .V+D-NKzĄda% [`?^v4TcǓUuWBJQxXh"#ָf3W58);G/j~chǀꨶxAgRlBYM&}dh 'phkvZ7cy  *bƌAeCdlN>5gw?&ِ3Y=$ ' w?.nCo$* O(m+681؊=_yqh6uatw[sEpO!bOMV,r7̨d iDU+R{?Daj,l.XбP7M_u{c;̮#Z60Jt-c> p?0x*IfOQebN|V—QOzO\ܞ2-uܜ"lg7-*D7WM^>(6}XpCd7 6CV]j`8k`t~cqR߃C׷93Cĉ[6X6͛}O~(Iw^Ñ lW,E8oU P0mC] DSb'n5,jl]뾑~_#Dߥj)?;rx} QEҊ'V7wUV߀TEq.t`nHyNo̐f|גcFßEGd}3-^&&<϶Pf0ժ;{SArT_ <5ǨY+`2X袶/*/imZ+uGxZ8W3Z WPue;S9yIpL& 6[4=۽Ra̰[ 1jHS}=(nv7]hۺ;c^M`+ Cȧ#(d]/,@Ə:s@Tڕ&}UYЋb3Rw7 fZnv@z g[AO_\RΞ+*Tg£Iv=1ҜO|`8Ř#X Wp9f7Ō0P )&W3kK7pM|*QҚv ְ SQ[6=yM(rB_^G%(۠dSI2p=Dq] v?=+ u ob{R'%jcc6ўL'N˴9.vi 2X 9'?hwZlyX \y l.W,^ YcRf 2E~0iˌjk+@x؇f@d'^fC [zX~A,턕$mFJ9 $"!0rN ?bSb.57Σv5:WAޭgL7) 9NM'f.78.:L˧!1۴d4އw9D',8.ULCo圇Q‹ý@62Y|'GGy8+yZuJ P-I,ǀyU}I*icUcrjWVi~8H!lFֻU|_AZ wJ!:狼Ud*1Q{ޭD>ACз/kaĴs%~4o'~C4X4;]d`$ۉbvkC k:;E&LǶ~?ݓ$ʩ+nce.@9]pP Ts/ӳ(߿}k{0j_a&J/$U U |/F.d$%a{ek0bjXQ(;Nf܉d/1*nnTl&ҭxxDI]_ub gTA4M7ē!X )jE=]tC3Q>N؟z@&ZfʏP\'B?kΑܝUXo&f^ VTjBħBf`d͊zI'A/0ő$uu ah!1`Lp MHP=!bG3ո<#-$je$'jPc벅m괃(JV4Q3m ԭ*PDe既mІQ=o6v7_)ea U']32u|#yrTM\-uXd6un4I&Բvteonh4}>'n~N__g688_CbخP;nzg\3\v&d W<Ь%3`6]O ?"N}fNBHб{ _k~XsVrzW2"_us mLY) 2f>h4)x4r eWծ;Rg,:\3JL3(XDIr⡛:[1JZZZK2Z U|˕PQ?7(_Aqc&[ I+Gva)Y(9 QbF hfM~T)iLpAP˵31Bu~T(` 1t%5$"_YyfoΔ\=|W& GQvi.JMVJ7%BݚI/\F+uNW6(j&a}uDiGygl Ǖ +#1{%GPas;Cn4'$c /`oC/y~uDo?Os?׿o_Kpbb 7}~bkad>?sCA+! RRZhikp  @-cjzfayw܉BēղjeGp[,,{s,yċ8͂ ȁ@i'. Y2dza9Ka~) HXJ2>]O0G0<U/O+$Q/G\#3cx{'b\0V>ղtl9DOr~;Av;en.c*)^9s^w7jvZ07N,co.Ӽ3?mlOD=O#:1C`i RoÐE7=^[npkT]>&ğnOHLwkis루uc/U N"VrjVAxOet42l "4y5F # عq\zoKbGenCzLtӰ#n.TM/O9ےU0&}[2I>-{"Id٥xqA hqƟpHNnDNҏK0  0|D *Ǫc224!":'Gݨq~e0DpVuuUDqn;4wܓ΃ lizP9 s4ݠ%b=f{;uD! ʼn:]BA:V*YFsymhV53 ~`Exi_m>>*8ٗ])n|>jE лr%_v{Zb>qb[Kp^K@݈A_+{!99֏O|WՂ,X +g5OHsݘ8 upDz[7?CC4㙥v$Uc!IjuY/XnDkbRA% j_uOC*a'AΗ lY5NZg{n3){Yw7qG~ ?Hm0]va7.MUCHq+`/EYSIzjRJlTG+#!ӨY a9|qp6Yšhe3KFj eeg;_"討[9<Ŗgk\CJj{:l)}ͻ _T:$wOTZy0R#,2ܤ?{8Ss+.c(qa4 i0 onF ֨:U٤4~˹S- Gw”TM0 WOE`@Iҝd8L9ۡ➓ƸM36G}V;M2k/QOL/Ͽ(ǿsi9m9]& ,os&s9;/xոMZ>R,.c+t`6S}82fPQ]gV<.MmQn6? uWWv߶9gIF|P+QsQ|$B+wVBiUgC~tV aK8g|&bi򢣅yrRledJP`EɔB+E5\Oirm *!MO7fz|@oco-^ F2R\"9Q"l(ƫ=":=l/W݌4*zI‰:hM-\?/w҄ieD,9!D{0?؍eP!5ȗwEտ|c;@64%]OX|{vnٛizXO hkqBcdzLb?sĉ,TOQF:KRdFv?,=~}?‡I~L'@ ߳ Uw=%2|bt|2sYhC:Mz53܇Š//2p")rGL5;7] te_BO8v6oJh\ f9ϑo:<o\[VC1i7?!0vBUuEǁ,P<${5f [+e9'X8TSO4mpd }y^Vl{,XO%G6`O R9#$`6)'94thsӴ}S!*eFbHqo{ZwUoϯ1DfonLo%=mXםŞ#,;.OOI쉹-zv]H4 P֕y'N %;i0u2.?AI2 UґBO a8xd"vn#P bq  |lKEi^T /D3uN*@mU۩?U] ;d뢐%u=dHn\':5pGm#BTK!Sqsf>)Q}KPЕ p6Psoȹ GG {Auٮo[urI^kەݜ;yzgômh/63,7qkIRAbr’Td1y,IXrܐ }mq +×3Z@ҺaYeB ]][@Ui-$!T=eu.taڜ+~!s ZC[kqA\!j G_rAN᧠Gʷ!p5^"lZ}CBOiŠ0 ..wOL,ݤP"ڊ`]l}~P1՘M_"s;ץh=yz$.I?BR x8xߩF[?Ƥ-(7Z+hi[ ֌NRK(c-eOɺPCo#gh+N:G*FM<ʊo~A#gpy9IڻC藡? *BL'gm x6)vՙ*x&URxX47Ë̍!đ*C\ 2lgf?aQt DML׽pYǶpH>/Š 9I)¹^dj,qjW;T]vNg!uO;ks'vzfL6+CWҞeyl$K y>6Og6LsM;v?~_Ϯeh[{g8țR!Ygpd4ORiKPLR m~'Yh`dz&\I82#_f$> }#U^; 7qn=GLD%Fu&/cDi0,=8<_$tnԇ^-)@44l=QE֘hNU 98L7IC/v XOYk3A0|m`˜Rp?0]k7`~J4'n':MXf)Z{#4bIUY |9Yu^eu3Yz$r%QQjD @.Z>*S5uo.n ͏&77H%$e|q 0*coJS clyQW;Y^T` d #[pӃHm 6d7DLې$ .Rrܖ̂\I$gP%-huN |u\`1a xC}OJ_ZԌklTcZo$-(-o3\%Nh Alm]?e"öiewa/31 iTUUhnZwj D޻ X8ѵ1r!KH/ P{z2u"^ Xؤ0mmܝ"ǒPZDOjbQ\m sOu\9Qwt,qhc>cwEqJyd ;ؚPKbA]iM5*o)MIž碒'+H&Bĝ))`bbp̡!eZZ0;s>J$i~+I(0TFp/AH; c OZ8ՙL%|9~y*LzZf2w,, [**q<;lRQڴ6+"N}JəD_[!du[{VE- R)GRgcZ.6kA&Xʍ-E~{PY* }?͖ Z5ۜ=So3EEhRdj:`nhJ֢ROͣCuQ!ٽw >s}U2GƄ ̚?z#|#u|EB׭0u0Vm}0F՞pa1+պ('`hgrkgb L(0=몫kI%zE~6:2kaџx(0IP_q/_2Ypl@'=TH-^{hØy6ݒ,iZӁ|5VjOyz[3F~㖖u߭HLh-*,*㌫1mE_p*c !ZD܇H%َwMv"n[rbB?CgR5 5_5|S<#S"OlN5`?W\sˋF:b9s+ۤ{2h٫9wdăj@qD:*Ôㆦ{#쭄bֽ3{%߈_@|ͦ> `![' xhf "8|尠&Eha'՛R3d]}tTD[`k"IHr,{7I5bbT[_~I0Ďlt.>ƴBiA$&>D40IS*TU"[N%u,Gl'עEmWo>?:vQ"u%f)RF=YM/fZ_jBEܓlY#YF) % հY"BEqD[| s^t"M*aiЛiq?UdjQaa^'DqU\#¥@dc$f7iKum{nuFCdbuJ&AcJLԙĖ\+::OĈV_6 p3'++ᤓ!«C >ALsHG0E5]c̡;WύVe^?nux"RVQ󱴭 uvAVBMG2|5Z>ԙ0UĚ$Jc~ŭ<<=HbQ'v yA7IC 5^T0!9֑vPdL -Qx'xϠF"#fCۭGpڏdIWX0HX?F/}qPe[=~L~;h7r#e4VxMS0-Y%.lhG֝}PL0[ n.pj>R">`/f?1e+uYOdt G,nbkDgPP0f%]ڦvyuL^ :jm̚%jŷ$ zGgd-sӗƅ|cp!L7댹pq%lpEY3FeTB{fA%.u H@iF7”*'-i{ QD2<3B~!. 2̀` *~k (հԼ8e͋snչ).i/l9;>o[Ę'rfw9_x_=+ z"zs>SUNb~ųh4JyqQX%^"j j8s6feMj\293'YqEoze(/Y\ dЬ5s_X J ׁI8U C7 R(` sB] Qaz|6 xwF};=vuN7LdwmbtKh@2`e|:[>Į70xF~FZޔ[5x+(l\QdX#m8^oW٪:FkCD8qq8'N1| a^aMͪ/S.9aNý+]RmKPfRu2L+8wiӟ^@9ͨp ^\2%^ a*SNG) UҶH\ @`.sظABл8uS@ϟUuSƣL (RyBmdGCo=,* I\`ݕwf,{%x?6aU}^g"rر6$Edx{1OA`o玩՚#O·Q/_RUX}o|o}rK™19gTY9r*u孧sV"M-S$_tq`*/BC}u,eewYr4u8r '7щӰ l*A3"m_1cXC(S jf*khbU ez*<컍n"k}#ĜaSYs!|N:G}[bډ6wvӟ* ڎHK+hpGwG̽0ˍ9Uo8%ܫzx?yM]*e, (CayIS%cNahlk$^"j?bAl :d{f?Vq-=g'aq iji*I0R!rwtf@q< nX2Y:gN3eo*,$+DFTҳ͏ޓ24YI$tTԂ?0 'x[X([WIVpLc~֝+!?R\< *SdҴڐٻ%b\37n1H:h92ܾv4;o4ۉbՀ.k숺&'v&IAtOSTIB:g_jbT`~9p` x>8az`;ŸM͊m6AXf69M'F:b xSmy)宎&]Atw(p|9):sٟ4׾ycN폰NajW>T{,,J"FuN]X>ٓFC8l%Y%.YVӁnQh^ƨt پcLz&~$^lmFc>GFTg֞A&A{Ξf|.5%'aK5zYYp W -b.kW>ʌonL %Ι8$F"<֙<=&W wGnbP$Yy TF)RR̾NBcaT z;L õ5DSz ૛F︒M-ILo!sF)h*ʓjtB*ڮ Sy'h=nN@3o0F!8vPs!̕f8Ed%reazE9|O & ґN7k/N>7N< }l %@ ɉ9*qy#O2hVh!×xy.g$[e؎Z,+zPۥ`j \4ޠͣ贊pldjOďA+x<;8C x^R#AINTYf;%0Q%_9s1Fif팅-ė F[OVa~h\17h@ڄt h@3av"\:NDF]iȪFq.CtRav6 *U:i])a+uXYj`T'Xˬ2wTQhhC %r=Kf? (UڙfYé6HFQ6"%\$0O(ÐZ1fXE#W)=1}(  4E^?8Q=J;RwJل*YTKTޘ>!=tg. 5]_qNj&k=`iFSqb|8Zb<)#ҹ.L;X>>ĉJh`Ac9ʬ,(\]R X5hw(laQ+Tʸs T2ч&UE0aXVH|B$=zkw/OR;؜tLGpPytg%TE 떜aI5UP N)I 'l$7 Zq|1^=_ TeAi+Iّ7,%SuMIgIħmLOXqm:B>O@pp> A Dma|) ?Н 2Vfha&Ĕ#sNuƵe*V]R6wn8U`z_uM* w$>F2V|0PR&IмK"~e֐)TArd l  =rXG%,enA΍GÙV4 Tf~&#vF*vlkƹr RN%}t&DNgG"m: .!z&`0יot`u,}QԱC_n.#):$PA8"Cw x@e7ZXג4ηޞ31G$m!SF.q&ܡ7X #gV!Od?mO~7yd~3J>d?ԗ5c^LHU@fe_kV A]^v2U]$OdeCeDEF%XG註^:4 uMB F1Щӯ[(X8~,KlJ ?oooYx|HpB\C  J̛;ap@umPu-+~"ȭצ>E]!\ >2 J/ѹNG !-{ 8]`JGBQb%uěq_zh6XնCGw] ;P4rI""onwl']8s[^`/hDzWTHhI| ȑsܩ^x]B̀Rg`1żB82"'mƘY6=v'/NoskSzrKI'=/I!l烺 f0.=0;Rڌ)X}!Q?5>lSC@gyJMtOO;QbzZ/c%u_% < X-Wi,fՖ l\IfX+++WS9W|ڎSK 901H /xg8&; \NG*\-SR1 $:$,Kɤ5"N=!|52J/B5 65[bн0ݧBw| Xx;]7 | X4 cV3_RO SIްܢeO? B@ es(ACKPyoǗFѧ96+o4Kׄ]܊Ja[7 3 r?-۴n&{Ep-sL5ɼ7SU ?oo_%P|sq\?(y.,W UL1۔-<:A D]%zdD/WʜϫIwLÃGoX*C@:W^] 00h~(G~&koytB,{8A 1+u|!eJõa\ -1Ƥkg:6NE5Mso0HMݯBX0Ik{ܓslt:ʉ#Ly7m *R~DW[Ն@WgD$ds|XcB[#W![f] kyM(!k8m80;!-aw7ۗw6G[+g/Eb'Pߜ*xO\և}qn RBi xq/|z 5)*iOݔ"\]C_ Q5k˸_C 5ѱ^ɛ:DsO+SU=sRwf"6 d'jl\lÄahOFIRJT)J\O$b^x&vu9oɮkz)p] Bw" DP q X(,ßp:sP{CHhgL^З(dpt }@&Ml_P9#6vVϒ*yCcᎂ_'Wٵq,#(_ kYu }P HD-u@κ ERAyz{ 2*`ЯnK%=1>q>k.Y虍8ðAX2re?%ms?sp$y:JW0VV\"ϴ^MʢQfyY#IV396Q R6x=nIzb:Rŋݒ |H` HMWZ$5HV{䡘 =I+tz٦&þzb`W`ƪ18>cӟ.$U_Qhaӭ嘝{[t"x0Hf'W/dU+T2VWZ&8*{\vTwҷ\1޻0 72};*P8~\SKC2 Xo_#!Xd=qΐGZCC9 HG'+X=»ZA&8QƯD~|7ƧV̠}JUYQԛ1I@#16)voiLg:a~Uj~F}859΂#aZca>XH (: ᡚRNgk3Ond jbβ(ޠ;c#mr8k oxALmNDuE?ThG$ᾝW5>7{.~`aMUأ^|;| DJ_Pٻହ|Lh{ʨC'F8g7kl4"ۃ;"TdmQ4.'MN<ͱfe,tTeءfWVtS:]Ի[A+E$ X=80bǁUr#buЎ߷>8GW#Wi hs&ۉ5S_`eK(Co*Ɏ}#-NК{ؐ瑇~\d*Ո C}+B؎ݐI#>XO5Q49$*_"3͂Nt~5.c+>h6ѭjŶ(H:$̦\wGُͥ1 5(s~SItTO l^Oag|`jD jԘv|${i?ua3tsG(Uݤ%Nl>Hseۄz Iusgcr*ggkKC{Cvb-MUL0\~~gO!O`,hK=i$Z:o*tN_ƅDF |};ZQ->pV_W)?)w++,2-Rdž`S@&Y䥝mfZ6=NM3:ئQ|~BAy$5Q#|8C`fsavdt4ݤlvc2WW^IM221?kE_Ի>QN 5d-XI|R[AUקUnc0G]\@h_%:gnRLݮX'E Hn=:,|}Y2)EC'N={[A' t𕿑v57o\TF̪z@Bz> MDA|hŒ&Gɣu@3.MytUX/z{|ؙϴlkX0&upeIU sԏlZ(\]~N1 H": (OC.)Ç?ZԔq7%%ј?ۓ -f\E5t\,xOFOW>MF?a-Kq6jVઔGbp \U+VIX<Ň0)ں~.wAXȦs BqHڠ#"G߸ [[󪛎d'DŽԘuODyf7VwT6bH G D{.!"S_y"hMN'!t7A"@Y(J`d{qh*FGAdB\{=uq!>"wW-co7u!맯iEҝ .R7ԟ#:SXt0b1v oX=@A,2P|Y1AuF4Vb +4[SqKM "?-/_ϯ~B  2CGNvE%+'WJx*&aQ@0@ct[D`gg{ŕG6kܱ;dٸ! c d`cόi`˓ύUa/8,> 'װ|Byivq/ 4u& apg]̆p9p轡kl>'ʎ_bE#ݞR>k~;1laxPT(e#y# NbnzVaPs]{k M+p0EV/PP;Ө:6kQ5zMqSnzA#"y\&e2蘗mzeʣzZc lDW)1 LiJywZYe~6u?q1MtYg]stJvghyV*X`2 7V`Ň,ep.$h2FGAVxgBVr_YKeMchzn.]=L姹T dc VZȱB9(ԾGPٽ~qK@dɆ iU\TIiPKCN9ՁyDr ħtXDb8m2-1SOONFݛyժ~UuXA nϔ2cJ1m^ǖ?-jp*ч͔dUݴ1"p쬔h ePY9GurF-zmWm2-٨tPXuBan]a?ibG8h'3L:Z{/V%, maB\¬an9,nUq 4bP.đR$}AMvj.;L-úL#;wPwȷUJO' +#la({ob6=bb؁\ ΊJ:$2ج?}QOKx˿) *Lˏ t٘YFcf0q` oOHr I閕 ԫ⑴k j0$ҁv`ychj`:1\)D sSAf\mH)nNZokahS<]:dqd*y7A%18w(i{o+j|t_'v.s)Rvu-%R!Ɵ ZEz~-uÓ\8gHC؎]*IH0.iߖ>RlE&R1Y ~pꊇ"]a|"R2}Σ:  *5W c1#jn&o:{^@t4o~L׬ T"ӎerHXFH4\D(~נ+,'ZON<6L<:*'vP"6Eڌh(}#ʕm#)󈋹l&EBSV!ME4gޣ%N-Om6[SKbDُhxO̖p5D;,)+PL/aAǤjv.\lpP͹4~xS S{4aFuxǢ\~;\۳'#=p gb`T\k GaHiハ͵|?>W~뚋~. ׈1B kȐg7F,;%z9JFC,0 |$-YI ˂̰<ؕj?lFq$mhDu}t$E9','sNIwr2Q3Oݐ2wHXb77 y<[lH5gr^ :-˔xpFqf޾_SJ-䔱k7d";2}4!ྉKZ<-snY>YA)tp]Z?:DŽ1&qH@A[Y40ʮnp;8vٯ[68Veħd 6[='b<ݒhN qa}qjR a67ڌ§>WYj? dh% ßZmSQkGsJsN񖧎h")V.ǿf5駯hTa̛b< rn.TĕeMti=4 ϞEKqwE 0~*T^+Y.g~;'Pz=xFiF9kdz|guf:,Jau}T^AmTvIfdBynx䄙tm8O)Hv4N4`p~}R4b >TCcsÒ_7i"kv '}=m#UwFv~猕 mro|BkedےP;?lo ןuQM1J\ U?=\ԵTy yT9S3睙\M{>J QIh`2/436{xFՖ&HQ6떽͏nͪC]@'`n?6ofuE~P{2+v 3霍':gJX鸡2DCq"23},cZk.n-MrIĊv7Ofoߘ6 Fkw m%mhПdL.U{Xr0TzN{A,{k"rfQn8vgf}!gFLlc@xD7$>i1 :ѶO~moC2s̶wgْ_h4n%,Vj9~ɦly< 8Fs%-e ^\__ӹ%˯{Nj3*TFB WM%j}jUouWt{bcn]@q`":uYƂ^'տ??K\/x:kfK5Ə ue/,0ķgY>cc_$X'"\ǐoZ^O.mZ &v}*F䑹'@Ks4tO"|9Lqox#>#" l[L<,+&1f)8Coȹ7*tWο`8RͲ8/CC0 6_5^3Et߼#|ǪSy@'0 +J@(XC/tơ^Q_0Y(ne; rj#d"8ua6 Ł{1xF,뙱.wuGC~J5\F Q~7z6-m AD^49wSyG9]Z8Sa|&l5W[ LGoH@Voqxu,6z+}8e'CT/̦A ؅ ObWq!pI-:[x>G)͖剛&b҈ىC u.Y\Gs3$A7cۀ͹]~"jn@!++2ݯ}TE٤%g qBYaTTpvQ)˓RlGmK)uɨx_=oI_C^3me>p&>#-vIxY0%E^qR$2B)c @RsAMYɆ[7d{MIьwϰeo\a&nJ5UܙOz[R2K*?-6׆"|9Yq 7EUcMlHϓ5ىϜ%snZ#Ӯ1y>Rs1u y")jćz>(D^)=1EZPJ~ ܃+"!>Q+;'e(l&-Ekkhڸ'#s^o$?6GCZT@vl߬,6LqfNH+GCN8|$鄳ExWmYKKiZYmγgMDl6څasrM4uřp/WV !#\d^t$6d>> ' \V- kԑx[H&ygYQHf^aT!ҩS󲩋U'H ,r V:9"2Dׯ8J"eQzc{8xSìxH=.~&)~^K/րĶ(/?a5TH̬CSyser_, I*sLͮ'I!7 sY6" .\zͺ_v<VjYȕh"̣U[R?`l}1yIL01S, E0B,ySu m2EB =Ψ[÷4}0I%][' i5P#n$~9/ ތka%Lr> [o!Z iH!K8W CОi}L!x:3ٟmEMkD U &Fn\*5V?jyx1t[tgwo@% l?Dӣnk23'0G?`QaUneA}l# ޼7n~(|F=nRFcqJ}c8;KaKYJlˀ4 ĒLVfJ }jأdͻa $v/-JN"o<JD3Q^:T3IÕL'>!nP1?A 7]tLR%3kz9;׺'- MD]9m W_i2bp: -Suf ]iy6R#wVovb`G(ܚ"G*rd+9<rS_8ym5M&aU)yxrC}Tv\ܗK*z^oҳoV [/T8GX%iэ/nmixMPD" Q٫97StaY!CFa4[_{a"g|ڛK)q+P8vB-@,H(*Rm4A%})jHUF6u8@,PwdҶ.ckHs_9!"$Tow_2….Fſ[chh8AW(3~! h/hcD@Ngp 6٥!dhBUuOOޮ#zu,w0R7$rE U&~b6:h`j{DxPfgHe슭jAR }_'b̋~$]$ї׭3،/=tS%]<؅_C}pS'v%yŢanA w {QMz`}[n>֝vGT!SaG%rVlqϼWv3aޤ"HR;gY <6)\!yQ˅$;{\!ڴ'M Z yz,-_?߿J7N|?&X jXRBtSH9.Ԩׯxv#:[Ў\o]`S%pv3vҖ=V+)ɨp=X.-seo G"'HUvKN Қ&`#Ad\f"R?d$}.>[ k|oK;VXlE*>K$jeS%  `P-,hM79z,"81#[B0C!f?&`m n bX{54{8$k.Z56^}XW" 4%  /ڌdɧvB]t$ɒXM Fɠ'PtdŨZ*GOE{֜yz[LAbnoKU)=u+0$X''fݠ-!LܪL&G^^G^FoU"QѨ!y%3t5͆qk߄]Vg(̳eD`/nZ ҄wO{7\S70 {D ?t I{8[\:8qm\V/m팟Nt;jh~r=hL/qzI8 ]+1 U&F2a/L$8t|xGk85nQlw\UIiߴy!dOq &lY ׂqWF㜉~{4XpZ#;%tf`L: ZxfY*^55zGϣ:i%f"q9t;Lćtvx'kz9)}%.c}N=[FE=Ke3e}*>qIsGj ÙgTXDDr/K?Jۥ DfVQ^ؖ:~-P#?QubG"n;"LŹ4:-(S&_ꎚőmV^Ha"cUB!POvA(z/$T-ItaHA*eQ<Ӡ(4NtfMsKLVfY+wfa.)D4Bñ29e3 kV' KYy枥`>Oż{uVJF"+=yUc$84QF2Նgl1uP=z8W!ǡi_X9z NJ]Ș|C0Q\&m&$qFBE/{jYh&+=^DqDa/:2ʯcMB5wHS$Yh'o hH_q1GOZ]q+a+%XthsxDe>F"hiK E%(&DQ>H4'd>>&xhUǓÕ'ҫy"*^Ze}_e#IN8hJyrM(=Aj.b=cyؕtuA/\24XH97WRqt(;É uM;VQ:1\p8X>'bT~0:2RhyLmyf,@˘[B$=.$'peHx0k{;'*-]KES45F J D={'vxy;dBJ}%f`wcEᡢ! WޡM| SƩ"Q#Ma0ۦ3SӦVurW("a!!/|R溲lr,geq!EN _dŬUKd PUk7 I.utșأ]CK AdYέrBO(:Wv?) IHL]0zE2mX`9sB<ʊ}]Pi ":636:e1p(;ia Y6  NqdoS˝I (EU"v|wUPsb F-ELN!KAx.oUhG~ě Esh&M[[.kDᓁm%4UN7SZ ot^JQƽ_FDmۛz,<}G%i[N%O65;;PH@5뮠Vl07;:Ph Iv,䕉kjT%|]B˰v0yj ) Y钲HX_OJv \,I5X3q/ax  cd]E<羪@sվm<$ZcV z| ~#-e6kN+V7qLh\>iL" 7VƸOl}6L)KKQMnLח6%\J$2{K=Z#Qt8s 5, ]R}!M_Qy4F '45 q*.Al${܅KrE's`? Q7=P׾Ǘ cef()d?&0?ʄ!kjUj3)wbl(&K^*v5`@ X Ayȕ` _!M#NSGqIεn7: R @(;!잳Iϼ~OV[1Nrdr> oޒ~*qZML8½6&ÖXhT{='%CxloCѩs2k!{(ƙ$eXyQ#nlIi,dr 8p7[Ic!j3G[7 Ѐ;i|o( e% ^J:=N qB[ WkODm<ċ|эm'T&״i qȴ@͘  Un= Mt2++L'Qiez 8Mң|%Sq X:Z)BlL7- ϘG;h#KҘ̈([m E#q:U^Ǘ:ҿ?ًG`g*O4g9l`aC]iȼKwp]Cf86M<]jT~@h K +׷@-Ij7 [z\/?_/n+ "1h a b7j|+<"֥5Fwc'd2.$\s;ž^KwRiӉUSŶc>Ra7*70qaݢJnK1!mD߽Ag{T`lʹ4m>^᜿nކ݉j wOp4dV?-}wRGhq$|Db; Hڍ5"ԡ+*< ;A0َIP`Vcl=Yk)^S  á˅m& X(i!hBDefN%*~NL=Le&db1u6J&捵Lv ғ7y3:ݥqXOÖ4zщ[_f0PPzAw`1QfwX?zI45ne.M{.=BP(ԗ;&F&b;{qӖ"\̴qdDR֤3,D%;HwֲCK1i-_zyP oŻmȚr河0Q Rfj|zA$XBfСonjyL~kG IEJH׌Lmv1Q Vnk>!. ,j*)mӷ~/f/O|Ck2~3~$v?<xfpAJc!) 'SJe,(H LdƷ%yT7J;3M IOp7k֬/I8,<1k p +sIqD1`,T p d]C4TG դKh5A8J=:a4[) ݤ1J}gwX1++iP߶ pAhA]N1l GgVUވsؖ`);`SiƬ 1g~au2:7Cs70eJzCOc䕦]TL_Y;D0?w/-yO{=4"IN ɲbJ!!7bŀǭh+wIGe5I9lNΊ?0L"\cyMb?gžpڼB+6%!Vo:q“OLn(ho&5&)hXZ4d']uΓW0rCiHF'G>b2V0$f+Pu\Q6A2H^MVjT)ڵ_o&>cFÚ$FEAs:Zi1g )yiL#8n[n|GϫSxOQnӚF3;1^A%j]0:Nszg&{iڪYy|`|lBA3"O7秵絩 U9@ UDj߹QVYBQY``&y-= I->o-J)/7FD㪦[|Cay$j|\e؎?KXp/r-j,BÕC:H +[ҷk;rwO\}'0# "5EHPQG2T΍'OL<νVUXFrڒMץ} 9.7V R^y- xpіF)Bo)ȣA+Rc?/ۿ~S}~&C*OK)><\۳꠩}L%hm^=Ѳh,?~z T0F:vbl @-(:ˡEr0ۮ⎬vT$nڛn""zsfe& u@_G|bM1 kCEZe4I)z+K*SIߘW(;';ZS qGͦQPձo83( NFUvKh4>_lI_P=.n}m툭۞*AoEEvbd$]JJhlCTSD@[ж ˢA>R~oU$7Bqʳn4ɬvQ]O.~RRN\ & 7ZiLOv JIf 6DW//P$]g+K"JW:HJ5-[?Hcd?hlH0J̫hP[lłmꔘ!w{nj ]p)wjg@l =SاD%f@YBߴ OZ3 grcb(\es2{w_S#rWs%d,hgCEJ ^@`> M]!u@YGFM4WT1ڢp MqqNtEbd5؉m2CoY*&rvD,5Tes+X ďA]D*46XhboBH:Ѕ(G7E&ivv屬nGU$v2 ˑ=@}? Dˬ}QxDba 'Y޹)1>'Mb,br][¸,Q x~gi Yd姴y.aj?ЧZ& _n_jIUR0}!gb̚ybg4)ߐ$u'$[w+8Ob|{nX[߂C"6j<Cf8'Ĩ~3)ZK ޅ7E N 4!:Y L$JAZBȼϜ]5Qjw}p{F3-Mgga8~/¶5pУÏ#O/4LI.D{8:7b1 Xb~ $lp5#'=m+m䯼?JR?n+ƻj߼k$z p:=O!h׿EO7ׄ*plQ冣^Hɇ`4MTZ 9'i=!d6P[fSYqE?` #Z\. iD+ErOhCཞF$_?__(% ^r G-c1nyU9.ݮ;ht-LFv rΨn ۰2٦PaLOXz Cч00Ab?f pvmri)jZ[j fm{ilJXXV]e=5I Cu6zտZ72IG{az`7Cc1|QB`' |D?1Dkb4]4 .\ϱ]~#X_?ĩ ^٥01:U,-RTMzTrfC㽁s؝Q<|eAhZ{m+A~Rfp U/.B=l;e6"k\ хj/:.aoR3٨y6*{bHqC1A&HT j^9?&@Vk\q`8J[c7{%o(A&xɄ6m*&.L* &1CkIH-_':tj TVH:ЖCrx @- ~#uZ`E .+la4V{loo)ѸW+J(XO7yZ?Zvm51Vu,A5n.)GڐjnJJK@)ILCO H[海uri߬aXM! kRU97t0^%ExE&FBЭXukҖ\; xWkfQhCkJ8X lI I`ߊk pvUnUʦ!?H6.0OPG^U4_XteX jĂ$Xe/U~mꬫZQ {Uńzm&?,G`ݹS^DʮoW^cڟ*u cHr6b~Zr$5|)vGٹY G=3,IMb6vfItSO2e 4'y~ּ1X##2?$Z14ǛZI_W q{4޸oi@?ngC5r^vB3dj< sD¶\Iw#p@9KcAͧ8Y]gh0E^zsD[U{#V0^cե?1ZWM1e'3{wG'Q՚)qVY1nTҷpƳ&xǏ;"5}S!Jp' o7Y3?1e῵qZ}K.Ĥ3l\ o~C$P,qUPV&BrZbM;+<5FȝXw'AahVx^~Ф@a^{(@%1ɩU4Ur@Il_~e9pд\²􍂌oZCƫc^ R&;ARdKd߫.Kܽ~tA oH@zyF{!2Bb&}J X̜߽nӢǁu8 ͡N\2ʓ^ ChɈÖq{%'^]578v"1'%bG( Vt6 v٠ؓ.G& 7ϘU\ *ày1mDV6eⰶ>1N[}]!/ڵ㫄J1ܣ6xZ$:2zHn#}h6j]mяyy@*iuP${Ua8$!r^wt@-b!ES`Ԯnq _y???P*~f#6yo_ZrVZҖy1B<k"0e2hgڴƐSW13dH.xʰ;l^rJ$rfHOa!&}]CM?|d]!e@EP?y'$}P.YM"ޕ}G J8 jV@2( JpkͫP{̏&=ynd5܃q.fӫ uJZ 961ʚEiDǢ]茮EV!e2|AΏI #~{)StSCy>us~EZ3hyrgP&w<@S; u10+i# (Mk$hZ a:=V&bRZBx(O&vrZ:&+yc/:%_kkXJ( cw3{$.+R/3?학F 65ZF:v,bF*Wlkh0[fZ)Mqȼ#&G\j2o}bo WLJ hpx@p⩽lzR׃4#û#\ تrC46dΒ$6a9(Jdܧ2ukIe{xuK\A)Ua]acܞ-G[1TT(سp rU₤aeKò̰H~/b)G3,(N,8n~V3'xr@mVҲ?PJNk]x E#4~՛e;cX:s*7ą^zfmTؗ5jI_Vר}MZz@[9g+l~WNYWP^~M#O\ vuTœrl+Sz ' ?91ANwGײ9o]}HU}'F󉕉49dT blarkm_*nD͒L8H'0#@Uz1=tJj DKXpXm)Wΐ0zg>vb>NԻvS3lZZQW ]m>ѰO^6Ɉ'xz&L050Lm_9YSMnЄf (ڇ?fQKČǞ[Uՙ# J|j~^Jz@Gq(TO=L/ngNam}-^\tJWŨRQ8`Nu7D]H\p3h8Jރ 491pm')@;uϕ&\\2k+3iə/?\ {[ɍ_nZϯBGZݹ4?nN㺙4 d_,~M(kp·&gU+!/(<>$2%;Qp}a\?!ЕJήTrpR>wVQSdmm ͸",SKٷ vk\hl턯QmBԗǛ%XE4E~'f$mcʣ2!Wo1/Nwf4 - Mw1|7lVZnQc]wʼn$¤i*݌`:׵Af(nAyRy5@mqJHl}gkj7>"Ʀ&׆cL*D1jn[Q1S‰sܟTqq9" J(-]SZў!qBGE\(-\Pi k@tՋZF&":,`־3`VHtA`G+ô%PrFşBg;8٨n-;lSVeP(h$1So8z봈Y@J JhSUt 00D` X>5X*yW\lVn \OpGrsfǘ^Q[Gt4r*ŀ͘"I됗>?qi(HuL`xJF6"U䜻LBOjOX F>\/6PXCz@:vEWl~`QZ7o&%cjňnf!̼'9DH*r[Κ0n5m_~}6 hY(2g8]<+ףՆ}gw}1PaLgFyؙ-"i.}~BٙPg9PrMy,{;okĆFg„(r2.HMB!;.;~cYH-L C%/>;uƬRYߖA{d%N^M/OsS@Ń079}Ct~ϘOvkFbm \ؙ SjN]8S.7N;;7Zbc-g<xwoB2|m|3l1M]IAy3\WA U¥[xⵞbT<dǨv hp}Pk8.o ݨw‘.;rD]* "f@%3]\nS_<'ZjܛdR7buE.W}]P1tB\}=@+rzk&U&V_T{h-cR:C RAEPZæ>0_W>:`09Xf'ydA eB $R~&:7r^h8a&@Fk[FY&ۆ|yf `Ⱥca0Í BD4y7EϏcV/ <(Z8wm@7Qs>iCMc|b7sK=ډַ_&lV|6$ >8BZf`=*d9~sa!#6/\`8&dMNɝ ȹ3 Śzi|;YJw׷. H/4^(<:l*+b37~^s[8]o ޢ(Ѱm!28$N,zՉ|B,3iN@a5c-mpſUO ncs)<38w|.͡t` `9#/A{LFY2͔W]$끐]y&z>n`c:59i!q(Ҷ& מ4>ψs \#Ǐ MnB|ܢ%u?EHV9T,I6|- >XSL3J|R^dMTkol\ZאM1k\^I67. g=a *_u|rS83N0.83^Y=ͨWS2a\R>Iv8!57%8>N 6`NSic[Rg<#Y&Ȗu>V7pcMYE_wY$`&&VĞ%AS'i埪~ TR-\o#]Z7s+,:Z*ntHj"UΰU-@t#iN;a7CF~ ufyCFԇEpQiQ#9 q`n(0Xu%wz&0q<*>h<("_ebTm0:Ggź39:񚽰2#3̗tԔQ%{%ڈj']^}ŌxxP^BH.3ɢmSx!/%' 1nT]:O$K)͑>3I\MbXGNg廥z"m] R b$놸We_ gIQgZmnkwO1MFxy`Z6ՋI/5 e9*zӐ usm6׀IH<Z.S?ˎK 3#ܭ\p1XIYypp/: 1fK}NXP]Lӿ߿˯__?%ds ͍ܘ>T FXS%i>RSDg> 21#(|o1ݞ@ۗ{翙HndH" #,*:յuz%/|rG a65ڑ. p]Omk;BLDCލ1X+d1!NAdq'|?с݉wnMㄼf F~^}صGmoWj~[2"ʾELn[1O+K"X.XNgz5C@1FK/#E$I-*rFH'[Ng xg^X]fsFQ!ܫ9ofb(dkF{*2U{tc?bDx ,Y`J7( BC<s`Z?`(Z݂!,].dSH+D 3v,e4q;E=-XOOGXyĜ&rY5}E. 4\:@] SɑMT5x1Sx]GHl!K OӶ Yn֎IMIe|'"~5Og'iOl?.}J}ļ?cGo0zy 45JMaD;hAk^=-E׆65M:hSdZ^OjC?wT[e>n'JizP X"hլ/dm%ၱzu;,F2 %de-ōd;ˏ\ڡArqڸP(l,Z4B5U}шdrv] GY=2yX$m }j m1O'̃z*ըYAyplѹvTQ iXP]"đ/9m>wDjvpG؄| FK=>I02'x!*Ml"E^Nv %14p3BH&hõ M^!ffx3&ZkN@/o@4*JYZf1-Js\鿲ʣaY:*({|>Up?c@́ "H#@榸UY`.іhevYij iYGUN8?w$g3A[Bc TMSp`6/ ˿Be |_@h< Mz/R򨰖"v9X4G&YbGX7I30޹4c!Zʞ}?<.Ce@Zct<$ćُw'B^9m?+L V~j!ٜbE T \+۰n(P_ (TnBws 2C@~7d Ny֨ғB>]yo8$jȭ >Q+OUۻڏuz_b{T=m9~p\bY1„ nTM3$}?^ېk-!)|G GPܠԆ#T-*,|I)LҸ['BbeYDG2Ω" |e,,6ww79AM2)c"!;4xv3U-5-Yj l,.8lF'>=< *0>([|NU(e]#p& 00xFO#Y!3a:ٟPޟAyE1 `},`7qF7 ap>YP/;g]! ׵~GaN=ڡNDS^jvQ"T\^9D,AJm8}?2{El)q9k59e0'EրD-k"n fVR%P*Ӌ;hEM媦/>io3m/#{4§}ڹ(;byZsh~Fcn2RNf'BU2 CC(6+]X҄ %]S0.nDL8Ǩ~zD$nSk71)G@tvmQ=Y۵XN InBƌO^gd`rvC(k[_9g<+3-$I9ƠM]=%^&{ ˜[m)(/LJlym^Q4̞m/v*[a-o'Cz[?zr 4$-BYlʉ,UPپfo虨UD?+p0 QIN4Ö& 趶-f'Yx'טtN2wWRSM`2;U]I,ޯ4,C{ƣ;/)oMK;MXe߿'m趪~ ?)󻯘/xc~>MPalNOsس Zӧa[s}C\G+Qd rrqxtqժ5{Grr@'[\2̡H|^e%J݁&.i]L8@<թ*נg˞AgDH6$&擂1yYsa؅0*&$TI2Q54!*@H)rthtW0}Cm !#c>iU^OMmO8}$DJ4rp4B{3y|mjÈBFⵍt7U_0 Zc:ͯ낋 Yv-OM6~08VsSOϕaMޒ0)}p?7#ps2 }c!4NÝrt;UJ LU{!md7x#T {19oӝJM_O96G9Jeee:Ц0{.jq% PyFyiCZeq b;MJZ>pͱn] BUd"?h[Qlop f"O 읆qhە{znz:?{YD}w޿U![~|+G d~/^2˾W F}zľFx=n:8Ng';KZs/{PϽㅱ9Dhx&VJ(#Y7\NI s[g|]fG XMtueĘtn:6@8۷d q['fRt'Mld&٣;zTIv$q:N4ڣJ<$kQ]LEE7~tZ\A r9+P%ef`P2&~O}tW uP,}2dΣ@V=(PX ¨{9ks|VQsS$_u< Wz6!wdV& ?5LD@|Tsϴ&eu6D%%߼5|O,LfPO)]ۗ9(g䩡20$N4"vuup*~T٩XJF@:5޸TV̙5r~. y7x숢x_JO4ɘ9(* Ln &30Է/}6}Ae =_1 %ZF<^\!tbFPȆ K}9&Wrfi6|O|/?6C~+L,|glkt'&=QX x5ei3J7IEylX,q1Z*qkexflcaGO oqF)ț20 7pwSXa !w>K̳+oMf3qGaj wN*^E8jq^Lr9P‰ӎ?#;NX/kWU' & NE.fo~E|mhGAI̺#_.Bgr8F_+`X3^J"j},@(s>qTћtìUIthnLη# O=#uR?dgfU~Q᥏r]g G9b= ae$2t%A#`D1 Hh>E1w}nUU|MM QɔW`v& l*q߫-'3hR,=0sH~@"!C3ǐ,J:s (MP[gz9,Xݬ&efJq8=SaW7vU-w,6}UĊQ,ݹ,[] 5A_bcD6B>HoѼev`MHnaK70I!5IvpZj>̍0!"JW#*m}y'MYG~$;+%.AiL4I]/KTi}dM}2S"猻{J6 V|sMtzF+OLf!#= =&B] V27NwbTR)D߶>{As`Yynr_]WG2!C74D7ªήt-ط5?KIeH][ ugr;حO{f0.jsnѬH3Dh9$oEc4 2C%I#{]f3#QZa `BfL@V$"Ղ[i7!XZH1dz_,/ o2't:FЍC{9@ۚO|W}r8qkh$Ncl?oBpK97:A- |<ۮ.l|5! ṂEf~U 47aA>cǂ􅚜 8_T+O mqvA ^]$' FVBϙ1W'41Xj\*NJ#|#yn?v',` _OxlZ7 weVs׏]F\8Yo=r]p5Z6sP g?)JšallNiϜ*Aw^=hbFZ~jxQtiNu5MxK{QyfV6za0j-֊QhCg{6ʥ5c7Y5s@ z|H>I])BPkQCB? t>g}'sN`2L 4#='aՓ=[L1O:l2oAn* (auWTl?};!Li֪ _),|͟_T:*(*O혦k&NXΖ%X@ &pʛ7Ȧx,9syXvU<"qt$xA  >**dm!qe[!rgyxb(Esqv&_49xπ7g1 '-PbـMw)ӽ:jղ^21ZbQ -b2d_@蘵(9w!DQO**jZۂyH4?٢}I2;N4=Ĭ(gܖso1lK}  |5@Գ &0yθ#5ǻ>>{.Xt>zl>Hs%V>W%k= Mxa6@vwBe$̎̒s) |hʏed!KD4i o ]rؖ,,E~e@~56;-ʣĒߝpWNqN>}{;R,\81cU|35䊂SAN8>b_ 8._Dr@DHVPRxܚ5vFE3iyjm̀a<)f)ɚhj4;2adFc:ZQ-ղC[5LVN^vtVBˁtpy&#JUQ<>&lˡH,2vjAr:DM22U\?PLJ]TsmG'_KX&7@9I; 1 9`{K x_9+[B[ZXn ‚޻_ʕBF!LwF}rⅾ '8o^c-NڊXiɠȞ)o%рS~4ie_ێgt;KR烗Tf ?cg93t3Y,6Գ(ه8pVɗF+V2R>{:rj>#9]K_ˣŎ %sľ+ƭ tA#d ߏoRT(ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_3/reference.fasta.gz000066400000000000000000001112541410636150300240510ustar00rootroot00000000000000TXreference.fastaK,tH$Jh-,405YJmCdV~%%p oǟ?ϓ]_CFd?^gǿ#j~:k~)_{_?oq^oѯ{W}}'^zro[_u|qկD_wzݣÔ>&}yX_;^^?:1_gɛ!{ӯs_^r/__|~)~@>+߸W!ǽ-Ag~uOf릺W%܋:o3{/iFxUQ^81wOuͭ4G0䜀w=/g>&NG:ϋsz.\{p{}=Wu ^:3q KsW};zL}{*܃ >Vc~PdQg:o{ޕEvi>9/>{}}ZNbn;s{ {5H=^kXM}?܍o*߼~53Oܯ?v/=1fΒ +ν#DqY"gI}]nn׽=KבOHcV> ,9G==m]g~=:ٽfe׫㹋k-c.K_/pf5߫Y#ZO~RA:.I*?I'OR)G~=yׁäOs,=Gs#FkyV?Yߞ)3x=n3p]I]:s q[;tϷ&p?Tާj -ǙMϙnxxX2x}ΏKEP>{guj%3Z_gޗ,ZYS,ڮgГz{,  ]o%$c~\'11oV֘=;CV^ p)h<{ۭ̓:۾8G=nS1_?jPsyW|ާ|^2?1[g6Ӹ}zjgXi۳ai7fGPz[v^z+Dkj`g9?;]{$* 3pn{^R=.= ^1T P}Rze{FuK/n'7nPsm^'F$x~B^d<[#@ޛDuo G0αA{?v'>Ti.u(9C 5긗 8>֭+s)n%p+=%N :Pl|(YT=؝ E"r]LUOءӻ+^9La:msM6aqʸA7n`*[)5g|V k8 ({!Z>VGǯ5}%u|QA 8wpί~O}etթ? ׎y˷tNۆtϛWҫl?nHsed+mH7Ƥ3'\koќwTaC68@@q?4!Y$=8ϒnny[_x!ܷ6)Y=ɘW߸p$uS~f>jn4M025,jM+F%p9滙qSC;7X͎7)զIg[}vdr?Lkr.ʼR}Q*>M1ڃ!ۜ"ciJAY\p[cS"LS`(޻](⧲磿ȷsZqYZTCǷ1ѩyjTg۴>FjQ@C) ?0wo3"aTr<jF5{/b!;:>[vE'[ʷx2~ C"uלTWxey_'6`nCZ EEN݋X}~}fՑtDz֞W, lY\fy>oךj!Ւהn(= KBzW㒘33~ PLӽaN wKvV{k ;yOё:WSckcqٯ>bI{ut<^:}.zuWyuzsܹc-URl>}s!EHF>RƄTHHd=a@zF6٤kkHw p(1'nu _gKjx[Q\Y4E^~aM/T.ʰMCLIFϞK^y\/nRks^.yj !PmL \Gǽ@Zg Lئ_"&i )RttAőʙN)#18xU~w-xjۡq~*6V&Xm Њ4ci,sUAΔR%)CA:\۝%4 3lTO7 ךgSdaI2wKΓ7U#)5F,̓iro1T_FlS{OӊjF>rqc`*x=s 3%xJVSGD:9Z&5 [,46ce OED-Hp^VnQX1]c#/`4OCǡGjDtN[iBJm./={3ol>n3wx[|vxanԳ:g^se H-|$#tqȽ[dN,ݡW/6<2m(a9z}EsD#!̂zv$2H"~]mU[,fR*ߠ -,lOL*6"Q/yvi"Sl=7 )\bnADj5%)vyz;3=8yU R|4hZVżgοȼst< Lq0w Jf{p <iRh# =oU8J~J1 !9R] 㮟ȵ*>zޠ֖QYt4)\275qʂ䌊Yz[S[񎀾R=jBE&'g,'S'}Lw|P뾨?+!,=Hs|p9H2į:kd'ii.iRϞ=ҡޒV?TI1 nQn9 17=4)zw1 կy93vZ=bS>iHZ/4阹׺~۟0ԚJ[|)Rȥ!֎`. Cutc1mk#~d7$1iBEi~a]´r,\М5'L 4z;hCC$@3t0*"xIt'K+0 @bKM-"kSwkI\bd\MQj~fgyj]$DZ J0ï4z- *IRܡ5E6W@pq]|(1K|TJC5`Ż>ρS"_CDPc/Ϧ:<)EI;RY)cPk?G-M% "Z `NTg>FCjs8j<:"u*dʵ+ } ( U/)8J1̟V"$&܊R'Ml.)%Z LH j Zm1)%5`@]gg*ײ;l湩yDgZ`Ō&OYȔ~-Flfh, T0# JlwR=:]e͋E )"4Wpm8! EWJwb.-Ӭ8(۟fPKSiT4s{?k&KH& Tʳv|h%U~$wdG$W⨡ KFIJ.0gPdV? pR괈yG^++@"F0Y[nnQ:bUx̩ePBͳP¿^l)^u[0]+9јwG{O+ DӇT,o8]{ҽ?J h)sMSDy#RlϼǷn |PDDq"hA Pf[>ژ?ih(FsQDC(J6N}36~C)|ǘ [> #IɜG]uVKicTziprSQT/BVұ@ndh1*2Y/>.LT*SR9gvD3{'dlCI؀nmXK@u4GO8 /E?ܪYm &ih5XTzRK\ 6bCXۙ rY"OSjZN#h/ھek}6,4FWQ.Wy:%.EP&1-b$=/$ cB5Gǘt%~@BHS>Utrbrzu7g,\7G-w50Ռ%#9Z֗; 4˭T##9VU(!Μ')e:uf '"tź2NG78t hK9Rj_G2]A! jɆ)@Z&R^hmUqb-GlfJW_ `+s԰UT^5G")FF|*@1LvL |L@}R!f˽eGu?-"><[$S]v؜_2qr˂*ܛhI Jg4 WXv(*2X aAVVfrnz^  &0<VmWV9 Tу^CB|@\G+"_B'$-kV^@]tD"!5ϖd5LJN\IOɮXNg3f3fJoBhr_~RLiY+WKju像$e!yaFgj3ѪAJ@#>U휴 ;1`IQYl.!O:cpe\AmRƠ^{tUlВ6lgUɤۼV_frkL!:/~5}Db |z_@*yhbKG c<|IKKe`!iIP4="4J|y r)S3<񢊉gUƼ43(ykM(g9:b/oKkW"@E.,bB{p(mZco>:h)MzˡNtHh MiÎ L}>T/\^í]ru0LvCJAΔ@Dm WH`%)wocr cA\M' #=Yְ.6Gx-^<F¾3j~Xu J3+iD"qĢgSJ(iP-om2dMԍ1#ּ.qFBԨm<⇚)jpM/3/Ep]5 *v1:PwC-VJLfk1Oc,b"{2`6 Usǽ!εR{-SE A%g]ZR] QD!jIMidvFQ!oëCVպzsR+@AvIA;UIGGuݒ3Bsf2: h2=.Fv#̽A,m^`H6^s tǵm1}:LT]8MPiw 9<:#EyִDyHF#rۈeUS_'{!s;+菉gid0DW.z]0K "VMbyRX4(U o\70p DoIr;Pץ(J;ڙGfWOpl ]8!s`_.; ]BQl'MIR()jg X𽆵k @1 7-[|vtA"딚,raƪVźգm+%kL}ڢ[S=ܺ͑-F8L~#IOo"'q9ŧp>r9+"z7lʧ%ϩ2h=7@#O$ 鉔3n gk&M-+lP.WC:ʮh#Kq54s: Oml*NK]h mZĉe&h}1{|pFi>zHYik {~H|ϸJ>$zΧMG|w\t~֨9w'F8|6c砽|a`P3l1"TCf҃aD$\dՉ¹oM++ ߖJY]hdSx|v7{X+_jB_Oy4_Xu}z%r3aZ[J!gW١2+~Ȩkx+0~?ǟ1?C0Q;e5 hXGwI }ZΑDRxvGfMWͱ(vGho ةZGt\oA=g}~{<co^C^⥘w.Z\ۇ.i^ Ve6@dPˎK!T,RV=qlyk,\Al`Mn{P-qk[n .DZlm͚NH4[T:z 0,c%%dZu!k`¯zr2;(:b:zAeφʇpħ2Lajk,0-\zN#泥Ϋm }uGWAPzHިa5b_ jYmt{]~\һ(XdkL`yO3DKQGR> Q#0|}2G3 P6:բ1?5:~#~˳8oMeےӎ쎋TD:m2V ; c nX*:pGތ&ܸf3M657.Rfz)j^JvO!*m y19b=5!0AJ'һqDMt(byJv7P`kvOOu?R[xauC8e@gOu^!yFO*J *r0ŚJhT8v+ỉ`EIsLDkr֤UOJtZfzL҂sѫ*qX`i$b!@.ך, ģCyqKft x4e2*i&el+;KGUnP …0FBR _L]8lTܻFmQ<Ia(eMxnl'[Ya(ɔuYJ5$ߨqYYb;q/)(-KЮzp0 ɜ,6;,m8S$IZ[}<D%0vaiܫl m06- vs|,@D)ݩ'AEyEݫF'PIRpa6?{TCV&ڪu?!7&,$Ϧ`Eu\tr!i~蚄= @: {uF[YV@ ]g~9JOnɽHc=@9q}]=omk_qP V' pA@Ip夽Su<E+a͏<9pPCm GZsഎ tԌIl?b4*1QK)pm'ep|^KVED 2m$[hUhM'+T$frM%9jbaFV$5*B掀u,m{WBJYv+K.q:Wz?J&u `p$<`Is"ƌ-D8g~xO?zgoG&+/8(2^Dʸ7` ?(yl׏"}EŽc߁dнQ4t9-=z[cM)H#䌿GZ6.e%4u2{ (KyHrނ:lJ /Q_5 UD&pR 525QB ?SapJ5 i@{6ruk"Oka{5 uKg' /ӞtUiN!H%9@xa QƸ3BC5L&;亸uXXXwu~ߪ].x<Qm3\6P(D)~U= Vxjw.DWv(V+6W2擰D|y_,pDVE @i|T9vo8o⵲Xc F8c눏cMl.Ǵw;o*ArXh%R׬ʠ±6#Q4~%T(`QӐCU]=5Mρ-!#V7{*LMeO 0#hS4i1ߒ^mWܞ*.IÏӿ[YYs6T HI?N}łӪ+NiN\f{#iFh\"{P ~MڪQm15sę@: Wqd͒t饔 $\##!\TRAUGA3Br΀c믁Kf~aS,YM 7Ӣnf-J)TdQđng ]%j l*ޥơ?ggm/NE^'5d"7Y?Dw'<5҆X9U׹Iӡya9uMJY0a7T]rQeX&|ΆlIpCŎDCҦ' -ӟx%ewT1M@cν:(Ul'epB2ír=\/0VGb;g`diM(=lWʛ&ūU]$fR2>ٙ)L`mfgW(p*CS?jd!'}rCN읖8 e؟&:~Z"DVsa7ؐw I%) rslUORKKuJzd0I_t$Rr941g25t| S*c͍ed's4cI$fWM/%xwDݠRY8cmgs~zo4DŽ&lpU1pⅹR5HmK9lȔ;2:-a)v /ܨTNT4C>V$#Uu8[`cd8bi) kʽp>}v^bP'3J?%Eq]N>(e{a,Uxpց'NC:#iPͼG\!XJҔ1h`y0(COWaٌ@y ̇ۿ~㟿߿H/h3lj3v9h ۥ^$v$f< #6 AGԬP?$=P>^%K4EenAmeɬ#C 5puz6aH$bڽ3ƥ_oDCvposzesjZhzX9m.s* b:Rwi'o2m>{)-OƵrN glp$tځW&fc" CRݑ:B0W<*o3=>UY9#T&&[ɀMy^y# 4)K.V=xS:8~?O6SÓ>3ؑtfTE_UM-OyE2IJiֵ}7r)B&ThxOVñ)PaѺȋ[s:bM)J͵/p5IteM+Kҁb&Q'5%Olðo@нCƁB:a] s6H!P J܌cOiz dB$0$I0A<1>Vj9plǨF8$ "{L}P !D8oA=[;H~i^CC܂ƺqwpEPRt G8bS^?BSHXH~Jpm%T)O#>jl S%4G"Gέ2 y5!uU(/"5k5;S|ɿ\w@B2MQjc3LC"wqeʅ{Q,+TC\4tke 6k̕TlOh<mdVsUjO i A@Г0kc%jӔC2&Ο]oiyKڈ[(2UYjRxt^Ve>D2o0c0ps j#iЎ?nN{{Z*ʠXW+"AD*|K.Wt 1(Vr E. r&YMԺMIYQ]Fm^cyr-ٽ:Mxه<3e%f$`9ٵNd=Tex-N?gZ6`ЌqiT|2IfJ)X陒"XӖW7$BȋbUQwX)FG L 3.[G*4h޼g%s_A,$=-q\{lis@5ΗLpQaDMτ]XZe2MdN?^A n{}Ɓe?~*h݈b׌N?;U(3 NsW躭eGvr TsFTnZէN^T+.ʗJx3`JB$* sspkjci}'1h31p<)G ے+SptcXmxv2VygB^u l<퉿,,~(suܚ\aѴIr= _XT7IדQTAOo26ay̨& _9жtŶ`抭4T:VD.\$1Hh 0ͿӯehHЇ&%8K(S뼳wBUqAB`t9yRWߕDq%C-(<^1M4AOOߏo\b185Vy"j(.0Qw(v"') XDƀ6qTd/},PRtBg/kO҃vj[U8F.b}VӘQ",oS}˓K"|ci?Ԓs|͠EӚ_ak'lA+ŒԄÀ8 @[A{fDC/O`1IJn WӦ߄<Ň&41oN51D+K"b9GSD2v!U# Cg"+<Yb+tD_ߡr܆((^Bms p8Q/q H hQQeaPDRޖs+r!3!ee(ɤtўD $TyKklY{*-KyaKv83zagQ)Ov4(a#@y[0ϯEw#ڢf -=wQ8jsweDh όPdT?U턋\r= 0S}6fĦ_I7spb3df c sQBͭ5eUTU2^uGHe*p+C<Ў o{=^'zhDW\\SD./ZBHPWdzM[O0 U2.7BP~|`cTz%jesF6PL@`?̍b#Z4{}tFA^yӔ06z!&) Ĥp`L5fI:bC k?m.s  ,;V8|]D6}$T2iG62AGJo6U/vK@FABeP`CV͑G +69mΥåA*ԑ]VX w3U9a HIxVALZ)BBӨpnp=ِ#uuj,tYX_cy$uq6LOAFU&aVlDԞE@kԒO%-9kstgV柌7A=#0ޱ6:'Ďl=ب=OnSulCXlJF&EZ܅᥂ 1 dT |l̽ Ϧ n4\n3!Ơ2Ӱ`m,pe6(pf5 PèN>kgQr3N +=3m"U^| >ZkartCGܙ3LPj:*8̦y5UDT}cH.ȣP$6.{Chj|^;3dgQDwgf;Xzԩ:W!x͕('jKB5r t)KBD̨Q yᾄ)!hJSװI)z5gH!$M+KB|Se̡.>gĦOT+\hsqԸuqp?X-^i vfT3,%=?Gm#V))Y.$ ֞SP{65Ṷ)E"LWz?S<ܽ#Rs !I$Q'S!},tYw;瓸5JE8(TYBeעIcDaSp0P!kJY@֦X/_JWNoXNg "UxX&y^kUT8jS;t҇O/{!& g DƝm%[!>2^Xd8A|,?zjRG``;\Pq;eo;a>$,,ǹSCl+;h%ډwsd’ KeNbs76]\ib e0+%iz3(#Վy53d RD_dG?鯤wuh+dQJ~^"=O!ʘ`u4m&܎;xDt:M>,HksaL4@mBbF!~0m]6ك}mN6lֿ#ٌO/)s{>m> QgG=^BViOs8XyH+Qo~㨼MH h+Ԏ .:i,p}LbtUlrMcn$K()D')39)4g[uvb]K]4cI#O5kÖ8bL,V+xBb8M~vK)f^d*򂚎/u1 fvR"nH1,,\kZQr0Tp8%OGrr^C+g]uCqJ֓Է5#BC{ ̜L勢߰Y@'ln棰")bNֈipH lv r "E Wv_)"/rUc sp#@1F fi[<: D־<9ԼOfai8:!溿ÑA+5`8JZqʹoz.gp[T>95mTv`yoGN(Ъ欚m.e'mW c7|z\u^aiQ1f{Zw"\Xw{3f8񵅔LɋPEi޵Dw4F ]4r,ݽ !#,BԲ/Jg.xal-٭HG7S0Xvx -AP@?I2B<+gbCk lʤsϩkaNw癪9yvd9$.^i6 rϦ $q"|(rUmCՏS*z&Τ6 υM:KI`Ő?%"v#>v5i$zN "GS ߣu )blt WN#h0 ͥ;z)˲10k)- %"Wh׶ee6rjR>i6j=@))O'P)¯(7iq"e! fإtvU񷝠)AB1a*?] r4482o 8BFߤXhcZe׆rAUcPrZ|+LTI(;CL?RXjEATV|*{ if%IqB'R<۾Rm I(8V9@ T\ |EzOGNXCӨYGVLGsJP"m#3ŽpD'BjH:>A4hՔ#cPz6c獜BkZ3X;.wa(!l eͅim"2(ՆJºUQqc"\)Cq!sN11A 7v/IΒ%yAZ⾤vafqo]qqъZE7P:0!-4.uw6P\g rEi U\*VގΏ!ao~k_zw;i OLSpi 2xZyC5gr`Y$-oH%|FTJ2.sNI:6"(Wn%t*$ڿk !nb0"3ÞUv[ MB?.'&: WL܉1gMIjر\o F=#s2}-*Hi9}U h4fyyhQ{eh)N2T2+&EzF@&sZ$aRJZz B,Z%\g8Ԭ`|X\;|Y}Kwzű#}a[Oߕk~hDOf|r0 HTXQYd"s0HNgo\aCj.;LÔ }fJ1ɸ9#&.,5 OF)y4fwaSLE+BPi-qGvr+K\jtlp𽸧3G2o,>X@ MWK{? M7 ikF05$FZ$4|@&:AK%g>]RAfo?ZsG:dk=M;I,1 S1m֠+wH&n2&6c%T>˄ooNtAd.]G߶IFg*@A@2 iQ V@<5d3Qna⹏IGԩ##D34 2kR촧U#v<goݔ> P^Cཋ|jcQFH$)@v`}6[,ׅՠlf><#˾"LItݹQ zXƁyC+;i)6.`l׬>ʫ'ёN(,@ VxҩwhKC$~9X)2 p]qџR0G|nZU%Cpף0]tEnR[-?ۚ,2 Zb!৾;a=*m`YfB:{=%k X0@ee@VKIK ;m'w r\N-6^&GF8,0oW.cjLJ< -:4SN6FQ i f̱)UVYDJm,-f-}Cɍ°q\UIr5DSEǤ.t3=f?l 9ZM%6ЀC!` ;n-).<;%hy!fwRvlL;c?$rb[ocYp~Fr5>lެIqzy?X;|5ԓ6 I2Υr&H!0qwTv e#we6+ n h*`^,,j PʤG롯R]0VjP~3&ڳI_H-ú1[٦9F' tx0a;vn zqu|et$v*c6F &~i@ldu uvKEr@Dl[̺tT/'':U"6ePV!$Du1qܑw[md1[ZC85-ey՛.\εwhR d2ׯ71E,rq3 ȓkX|ԝX._ÄXJj ` 61H:h8]P66.{"Qծ1Fq`#y"и'HАJB_kUrh;oHRpfHo_Jj7<ݥeHX؃ 0TN'OYP/PKؒ$>=q% u%+sh!{Yލ%]Ҧx>c⥌ܦHP'-mG2;?U " {fy1&(:B?pLς1Jc4F"פn8KߑΙ @ s ga-wN(F*nF-fk3~Oer :'cb6$ϰI? @VO$%!udYYS%b,#3I( md gR 9lYnSair䱭u}\sxAOS2k%iֵ&Š[z"i`\7 0}u)K^Ld-M&0I&%Hw3K}bLC**-ifmd4o& eVX`e}t mU;jN厓JDܐ0:l̖&vO?zU+-&Z}&8<+$eusyiL7Ӹ.WRg-!8;Z+]粩te&fM9F[mo=HyCo#.}*ev0Sor ?}&X;˒2*nX&["K <%h(^G`E9'Q#pɄ.YS&`d2v9- H,W07M*oRxӢ@aڭȸ  سh7́Xd$EyyĔ#hڰgh(% @@ki.7}(`e݆1qw 7I47@+A[t>"ΈLy Rf@7<9ʴRa]b|Qg(Pz`h[fMͦgt?H_sCuflkzjH%->|y"zQÏ^B mJR:q$PGq)}G!˥L5yZ+AĩM3u<"tOā*"^1N٤QrFFɝ\*eG ;2uV6 V{ I-[8mJ}p &ڂc<GJX`-K72M'DŽ}]T |!G93ڈD 222I-8(0ڤl\4۬#.[hz|%yJVCV,"mEuyutE[!)-1 6mZx Qe*[Na_lጎɌ[b?"Vx$!jIIG$BETM-.08ARd5?VՓ%TqX!Ķ$K GfI ֜ɪӰ1)fGoʌKl[4D>6MDM遝r۩( iҨr_1[o@vsEDUw gԭJV.N-n ,-Aa; ;.^8.ҺR4 1\fNZPVeڔ&WtA)X0u#YyOK=_mX/8#~:3D~06(r0R +=][؀u_o*㰬_*Ń5WdÄٳ,loIXHɧQR—` M>Zb 0!k-X*X_ PV>(V$5. fi3w4IG&p %'Fp㝬%;VR\-bFw6P Q#S/o&8:꯾X_<~|ۻ||A|k׿$<T<<ZG/[k 9 OM k#c f hۖJ3i#7Dk w@6¡6K7Fq џԆB B XX;[}Q(nf @gC((y)x(CܦQ/r^f$``jjI]FW@aR!s0Mx,}6(AJԨƮm Z;iBFEHQ֛XQc]De"(rg8G&Yau0X/J,T¹0?ŝK& %,p}[S/Yݜ(bTef@#,[6qUEDr$>oEGp"j 3% gWLj)H$/z4xXkkxJ rM{=Ġ2+R!bIr=L퉣 *U0F1SpL)tB,b*, Lٔz#%b( jiz|!~6)t?y3SU8M޵ 4tD5CŦ3EqojQQ?bY96ש13aRy[OkzPڽCypie:6*"0PGa,t%Y՘SYqrC)QPwPIq(= .-WAKΒ;|`HXgґGDn~J&N1'ҷSAd g@hѩEA˒MHW+$2eoĕ~/@Wr+Ilklv"YA˂Ab4KBn!~Y1c "Wkp՗2F t@vnPU۝5Ond7"܎-%԰>q/c4^XŹIJ؈qQļ[*¼VKɨ: HȢ;DrS ]t˟a$"VGjӁz+he ڬ=m.Ey =ivc?eZ$Y%XZ*(WV7 ӭ]2;bMF׈FE«HŊ#6>Լ*ZľMO6բZBKU-$`V,Y,"VgEIza9Iܴ旍Vt|U}``zirutqdТ\D[Um@OH VM4" @]jNƵCT بGwCÞgjFԛ0k aEF+'hJsCµ6%UC2<ΰ꓃J m~ bl;HĶqvovK1^]\,bHy.WInv"QȘwNށBSZ^HߐeoxoӲQWȘTNpEK^asY5žϮ װ n:!Zo"|40`%kǗV6Fm$>Y;pQ PU`7S &g7&ըYkdr&AIa@ajYKK& wVg>] <8ܟƗO߈[?bM|q|S߲?M~AaAg+m ZÒxIB^?|/0{a 'B=i`^M2m$?y7dG`~7NR*]  be8#Нdb7`k&[-VMt{O".$NgPK?)f1`ߴԀY`xh{O]Wq=@LȒI횿kY5hnF)Q~2Ƚy_P&ĭnLmEw;_[IH5{yv]v+O{L終Lh<tyRe+Z_l+Yק%mG4FJ&YW ^cDD+esJb;/?)k9[&Rαw ]e}7B\[/mjE'ҋԅe1#]N:Om^+ƶ" #*yhڔX9 oG57jvp١ezeu:- eֱ I Dj J7J.\zԥ^F6.!ADr6-W 8[*`i0mnUo[>]2bLWc3SfXʊMޔ$jv z$)p-+ҰL6Bd/ǞۭFIY!hZ[L.,PD_b\ȃɣ rHJ_@PfҤ WD3NMR C(ܒ F51WJ +%?ǔ V]7) 8MohYǐ/у 3ׯmv[˿R*[9_O{7 jƯY +$ HZ5bRXJ_mX;.]6aJe`/8ӂ*e>j] L0ғ1UĊqf$sKY֩K{h\`;,PȍWe;_>;ytϵ] b^8?G|$v9ek+)$|Qb_bzs~弨Jh fdv3p( M\Bk5-6r447^KnhF1Z& 7}A #iQEJPj+FhqQ1k,Ibd.:}pxYj'1v gFޅU꼦=B$,6Rӄ)ERB4$ s6Lx/YVCJ8ifɠe}3}\!x U]l.'/=-!>2_X"/X+KQ҉OGm݅POB #hdL_b\dK":{atd{Uc{=?ȟ~}ȿs#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=Rxqa#_M(^!qQO3}2tqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#߃ i5Z PmKs58*VX-1xf4zhj _~_~?/?I,B= JZBfy[Iw# e8,5zw,9h,NȄCcUir)4Y:%8]1a wT?Ð?ĵlתCyU;k^O2oiqN":1G6 y>B}l#4fN.lubH{s9$Qiga՘].flڱ v+(Cjydl5lTb3ᫌhZg*CIBi0-~0>RL͔2Jv>hĐB J9ڦ&V4LDvVs9I.XgqxF̎ 仪|i jum۹@3msbhY=UZN尟LYxD$쯻L.8 nX7̗望J:_ݵ$Mp$ ɽo +9aJ~ёE/Qnޚqi :tMszlYQg cqե\Z.,L2>VIK^ZCp8?,+k̼ TJyzC;i~t[wMT@w&!^@+rIߨK mkVc#f4>^ :<~hg7׻WBx?K2`ĸx5:񻌿39eQC>\jDq:[:Iyi090.FJ{/S4[raQ'+DXиG|߫wЋ5Qz7GFba",pVJvLR콬QBщ/*榝qS3*z&,޿.sQێb)䗎L/.@xbw$2/^_) EZ: 0y->ygMI=,RiJLGgjr>[uk`y6RFJ\{tzZ֠д"Kvw,'4tOG&`7 ӢbXDo5NT ifnت-_u]6G~1/)5Q~WW'B#?8-kv2(=C HG O6Y9$ 1ZτzkOg%&TGy@* 릃~nMk9d́>f {1a^oЈʾ{Qku\L?Wm *|ʏOjD奎ʱH%ov% Rwtzm$LLb([H3{IʶĆ*^LeZj7 =^Q*cQ>s *S늷~-3Iv)Q 0 9Ԏ_Xک3Prf'ŕH[Z)ZrTsi/ Y(/^f=Yp&Tr7*yZw*it.Lz}֤-==iqi_hH.zBx(/MZl%\t)s- pTꐤYyB: ",+=C >(xmÂD=1jha߉6m+mVX;8jGEXSaF*أ - MNX)K%n+qK'ӯauFZcRMV-6uH- OOM[>ɃU|5boWzvuIScW6\)bM#sfEa6ln=:@<4Xb, |N|'_PHUh[[< !8L:AVpd^v lQ(R-K{l4!QV/u%@K9\]|Q( rO%xϠ,v6K…&&&MG?ԏBj5 -\QdXsWjr=]IUz+%4k;M1hH)Q@"WE99Qg1} g16Z,m^3Uf\=vFNt6'ٟaӉBtm@_~.̂}w^074rq!WnU6u%|DC6mRYP[˶m{)32E/)x3=Ɗ9wW$U; {V:ʜC02[7wa@qh4EGZ>0<:r>-ܻ䂴ܹ`ѫDs=<3t9G=ۥTZ[r+0g|T-7i Y\)_)[!Na ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_4/000077500000000000000000000000001410636150300204515ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_4/expected.txt000066400000000000000000000001061410636150300230100ustar00rootroot00000000000000m54026_160803_070612/28836180/20388_33105 0 13/73677590_73687657 1 51 ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_4/read.fa.gz000066400000000000000000000076471410636150300223310ustar00rootroot00000000000000~rXread.famI DMŕ°[U=, Irp8?~_?׏_ۏ3=:}NOw}٩sܹW瓙\sG9loy{sy9?q+~\y?{{S ~ﭹseObWv%.s0c]p>ѾK?ugj-Ofy.Ij?TkJ loXkVm_k93oM1ϵx‹'ø[O^WcqqNi܃/JW?aDsk{VIvi >jg]auvU. \d&`1Ig66ivp0<8ɞǣ$hj/ u8sc`cg£9k`,|oL,T"~Sf!A a=y;rY^Md@@Mb䳸~0[(. ]K+/׎b|PZgUl-7Ksl|kuZLy$~}4[ M5񃝞=Y†[!km8Y2ʲYÞLcP!9rf& 躎w9[y-GGblR)# *jJǜ P IW{{<73C wC; 5(GXQI%5 ҭS:K7@Kuo:qN}o[3]vzJ{Q7͌찉kJm>U)|*N}UIzbUUoHE; ;e'SX먵ƑXd9u^Kޠ6#V7̳M.풼6os4XtzS-€L"C %Mɬ;drc۬_Mak6GpܰpL5|aWPUiޭvFu)OX߂?iim}K@߀̱f %Z9ځPO|'F CVlgִ4x5ih/$V&?l*|rUZI8dyAxBca-T36,+7-FI1Z|^Ҋ-9;H,]J\0dN iedSn @I3 2IE*\"UP|˨S!x e}j9^dR'Ǻn` T*وS`])M#}˨8"{Hu8?|/1gG٧ՇG;WPC$sVߑل Zڢ.EH#I3#QЄ4 \ i T>PT`<LUF6X6櫥 D.^dl'`ìGŘi UkQ?ὯOQAG`"lWF{6cN25żC72qQ6ro ~ξ_"xA,5tJ[֝ =H5^{+-׍VAJ<=g)i;rN i3]ΤohX$;*Tֶ԰2e2n!_dktSR0I?k dgBi氡WCEG*EctK;TyJ0 GG.5uһo%gFQ$]_QPOl頮+h9E>pF` xm'ܕEQ#y G \c줬ftˉ*= =$MN};/mF&u:WQ.aTJނ\UP:Zv\ߤlE00$J#3ƭ5X.Hm" ^{2 ߦ;`ř*;&ۥ}@dxWwCDcjTԃ7;Xeu]BIͶ^9=蜉UGJP|raOi i[8@&I+#pF(~BWУ(R[3qlPqjtҍo}wB5w7|OSOK=C(e-k2o9z,AFV.2"Q]/25bt:qdަ9KZ(;vL;[˚ʖ^ö!0siltGi{)U[JOk*uS\%)oi^ 31)~5BĶt19NU3[gl7'PdwƿoWYoLt'{یs$T33# @ޮx @6<сft+I:dCtH()܉u9ÌA kkUܝ,F$Je7^j%t2R۶dtd#|a"Co2SqaAUтY52sf3xllX HкF0_ecyٯ,RcG9Nm@z7C}@g$ 2e**ͦ?Z( ^Fe'@1SjfETdg'>D_l:͝NQ>M[j;/ggp:P_.,\f9lݚ 'qr:f4/Y*wmJ@h֣nGbJTfck}뿟w6ߜl{=DVBIݪ]N W i[FH? ;J1RŔ@=scv$s[*'08WU6ιzuwl)}ܲz {N/̼[ ͞Wdv,)eʶ_$AYSmw۹ f*s܅Y*]nw]g+ц61[Of%&{aYFP΁V| 2:wo^H; }zѰw#V:ǒ?Noq1ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_4/reference.fasta.gz000066400000000000000000001112511410636150300240470ustar00rootroot00000000000000qrXreference.faK,tH$Jh-,405YJmCdV~%%p oǟ?ϓ]_CFd?^gǿ#j~:k~)_{_?oq^oѯ{W}}'^zro[_u|qկD_wzݣÔ>&}yX_;^^?:1_gɛ!{ӯs_^r/__|~)~@>+߸W!ǽ-Ag~uOf릺W%܋:o3{/iFxUQ^81wOuͭ4G0䜀w=/g>&NG:ϋsz.\{p{}=Wu ^:3q KsW};zL}{*܃ >Vc~PdQg:o{ޕEvi>9/>{}}ZNbn;s{ {5H=^kXM}?܍o*߼~53Oܯ?v/=1fΒ +ν#DqY"gI}]nn׽=KבOHcV> ,9G==m]g~=:ٽfe׫㹋k-c.K_/pf5߫Y#ZO~RA:.I*?I'OR)G~=yׁäOs,=Gs#FkyV?Yߞ)3x=n3p]I]:s q[;tϷ&p?Tާj -ǙMϙnxxX2x}ΏKEP>{guj%3Z_gޗ,ZYS,ڮgГz{,  ]o%$c~\'11oV֘=;CV^ p)h<{ۭ̓:۾8G=nS1_?jPsyW|ާ|^2?1[g6Ӹ}zjgXi۳ai7fGPz[v^z+Dkj`g9?;]{$* 3pn{^R=.= ^1T P}Rze{FuK/n'7nPsm^'F$x~B^d<[#@ޛDuo G0αA{?v'>Ti.u(9C 5긗 8>֭+s)n%p+=%N :Pl|(YT=؝ E"r]LUOءӻ+^9La:msM6aqʸA7n`*[)5g|V k8 ({!Z>VGǯ5}%u|QA 8wpί~O}etթ? ׎y˷tNۆtϛWҫl?nHsed+mH7Ƥ3'\koќwTaC68@@q?4!Y$=8ϒnny[_x!ܷ6)Y=ɘW߸p$uS~f>jn4M025,jM+F%p9滙qSC;7X͎7)զIg[}vdr?Lkr.ʼR}Q*>M1ڃ!ۜ"ciJAY\p[cS"LS`(޻](⧲磿ȷsZqYZTCǷ1ѩyjTg۴>FjQ@C) ?0wo3"aTr<jF5{/b!;:>[vE'[ʷx2~ C"uלTWxey_'6`nCZ EEN݋X}~}fՑtDz֞W, lY\fy>oךj!Ւהn(= KBzW㒘33~ PLӽaN wKvV{k ;yOё:WSckcqٯ>bI{ut<^:}.zuWyuzsܹc-URl>}s!EHF>RƄTHHd=a@zF6٤kkHw p(1'nu _gKjx[Q\Y4E^~aM/T.ʰMCLIFϞK^y\/nRks^.yj !PmL \Gǽ@Zg Lئ_"&i )RttAőʙN)#18xU~w-xjۡq~*6V&Xm Њ4ci,sUAΔR%)CA:\۝%4 3lTO7 ךgSdaI2wKΓ7U#)5F,̓iro1T_FlS{OӊjF>rqc`*x=s 3%xJVSGD:9Z&5 [,46ce OED-Hp^VnQX1]c#/`4OCǡGjDtN[iBJm./={3ol>n3wx[|vxanԳ:g^se H-|$#tqȽ[dN,ݡW/6<2m(a9z}EsD#!̂zv$2H"~]mU[,fR*ߠ -,lOL*6"Q/yvi"Sl=7 )\bnADj5%)vyz;3=8yU R|4hZVżgοȼst< Lq0w Jf{p <iRh# =oU8J~J1 !9R] 㮟ȵ*>zޠ֖QYt4)\275qʂ䌊Yz[S[񎀾R=jBE&'g,'S'}Lw|P뾨?+!,=Hs|p9H2į:kd'ii.iRϞ=ҡޒV?TI1 nQn9 17=4)zw1 կy93vZ=bS>iHZ/4阹׺~۟0ԚJ[|)Rȥ!֎`. Cutc1mk#~d7$1iBEi~a]´r,\М5'L 4z;hCC$@3t0*"xIt'K+0 @bKM-"kSwkI\bd\MQj~fgyj]$DZ J0ï4z- *IRܡ5E6W@pq]|(1K|TJC5`Ż>ρS"_CDPc/Ϧ:<)EI;RY)cPk?G-M% "Z `NTg>FCjs8j<:"u*dʵ+ } ( U/)8J1̟V"$&܊R'Ml.)%Z LH j Zm1)%5`@]gg*ײ;l湩yDgZ`Ō&OYȔ~-Flfh, T0# JlwR=:]e͋E )"4Wpm8! EWJwb.-Ӭ8(۟fPKSiT4s{?k&KH& Tʳv|h%U~$wdG$W⨡ KFIJ.0gPdV? pR괈yG^++@"F0Y[nnQ:bUx̩ePBͳP¿^l)^u[0]+9јwG{O+ DӇT,o8]{ҽ?J h)sMSDy#RlϼǷn |PDDq"hA Pf[>ژ?ih(FsQDC(J6N}36~C)|ǘ [> #IɜG]uVKicTziprSQT/BVұ@ndh1*2Y/>.LT*SR9gvD3{'dlCI؀nmXK@u4GO8 /E?ܪYm &ih5XTzRK\ 6bCXۙ rY"OSjZN#h/ھek}6,4FWQ.Wy:%.EP&1-b$=/$ cB5Gǘt%~@BHS>Utrbrzu7g,\7G-w50Ռ%#9Z֗; 4˭T##9VU(!Μ')e:uf '"tź2NG78t hK9Rj_G2]A! jɆ)@Z&R^hmUqb-GlfJW_ `+s԰UT^5G")FF|*@1LvL |L@}R!f˽eGu?-"><[$S]v؜_2qr˂*ܛhI Jg4 WXv(*2X aAVVfrnz^  &0<VmWV9 Tу^CB|@\G+"_B'$-kV^@]tD"!5ϖd5LJN\IOɮXNg3f3fJoBhr_~RLiY+WKju像$e!yaFgj3ѪAJ@#>U휴 ;1`IQYl.!O:cpe\AmRƠ^{tUlВ6lgUɤۼV_frkL!:/~5}Db |z_@*yhbKG c<|IKKe`!iIP4="4J|y r)S3<񢊉gUƼ43(ykM(g9:b/oKkW"@E.,bB{p(mZco>:h)MzˡNtHh MiÎ L}>T/\^í]ru0LvCJAΔ@Dm WH`%)wocr cA\M' #=Yְ.6Gx-^<F¾3j~Xu J3+iD"qĢgSJ(iP-om2dMԍ1#ּ.qFBԨm<⇚)jpM/3/Ep]5 *v1:PwC-VJLfk1Oc,b"{2`6 Usǽ!εR{-SE A%g]ZR] QD!jIMidvFQ!oëCVպzsR+@AvIA;UIGGuݒ3Bsf2: h2=.Fv#̽A,m^`H6^s tǵm1}:LT]8MPiw 9<:#EyִDyHF#rۈeUS_'{!s;+菉gid0DW.z]0K "VMbyRX4(U o\70p DoIr;Pץ(J;ڙGfWOpl ]8!s`_.; ]BQl'MIR()jg X𽆵k @1 7-[|vtA"딚,raƪVźգm+%kL}ڢ[S=ܺ͑-F8L~#IOo"'q9ŧp>r9+"z7lʧ%ϩ2h=7@#O$ 鉔3n gk&M-+lP.WC:ʮh#Kq54s: Oml*NK]h mZĉe&h}1{|pFi>zHYik {~H|ϸJ>$zΧMG|w\t~֨9w'F8|6c砽|a`P3l1"TCf҃aD$\dՉ¹oM++ ߖJY]hdSx|v7{X+_jB_Oy4_Xu}z%r3aZ[J!gW١2+~Ȩkx+0~?ǟ1?C0Q;e5 hXGwI }ZΑDRxvGfMWͱ(vGho ةZGt\oA=g}~{<co^C^⥘w.Z\ۇ.i^ Ve6@dPˎK!T,RV=qlyk,\Al`Mn{P-qk[n .DZlm͚NH4[T:z 0,c%%dZu!k`¯zr2;(:b:zAeφʇpħ2Lajk,0-\zN#泥Ϋm }uGWAPzHިa5b_ jYmt{]~\һ(XdkL`yO3DKQGR> Q#0|}2G3 P6:բ1?5:~#~˳8oMeےӎ쎋TD:m2V ; c nX*:pGތ&ܸf3M657.Rfz)j^JvO!*m y19b=5!0AJ'һqDMt(byJv7P`kvOOu?R[xauC8e@gOu^!yFO*J *r0ŚJhT8v+ỉ`EIsLDkr֤UOJtZfzL҂sѫ*qX`i$b!@.ך, ģCyqKft x4e2*i&el+;KGUnP …0FBR _L]8lTܻFmQ<Ia(eMxnl'[Ya(ɔuYJ5$ߨqYYb;q/)(-KЮzp0 ɜ,6;,m8S$IZ[}<D%0vaiܫl m06- vs|,@D)ݩ'AEyEݫF'PIRpa6?{TCV&ڪu?!7&,$Ϧ`Eu\tr!i~蚄= @: {uF[YV@ ]g~9JOnɽHc=@9q}]=omk_qP V' pA@Ip夽Su<E+a͏<9pPCm GZsഎ tԌIl?b4*1QK)pm'ep|^KVED 2m$[hUhM'+T$frM%9jbaFV$5*B掀u,m{WBJYv+K.q:Wz?J&u `p$<`Is"ƌ-D8g~xO?zgoG&+/8(2^Dʸ7` ?(yl׏"}EŽc߁dнQ4t9-=z[cM)H#䌿GZ6.e%4u2{ (KyHrނ:lJ /Q_5 UD&pR 525QB ?SapJ5 i@{6ruk"Oka{5 uKg' /ӞtUiN!H%9@xa QƸ3BC5L&;亸uXXXwu~ߪ].x<Qm3\6P(D)~U= Vxjw.DWv(V+6W2擰D|y_,pDVE @i|T9vo8o⵲Xc F8c눏cMl.Ǵw;o*ArXh%R׬ʠ±6#Q4~%T(`QӐCU]=5Mρ-!#V7{*LMeO 0#hS4i1ߒ^mWܞ*.IÏӿ[YYs6T HI?N}łӪ+NiN\f{#iFh\"{P ~MڪQm15sę@: Wqd͒t饔 $\##!\TRAUGA3Br΀c믁Kf~aS,YM 7Ӣnf-J)TdQđng ]%j l*ޥơ?ggm/NE^'5d"7Y?Dw'<5҆X9U׹Iӡya9uMJY0a7T]rQeX&|ΆlIpCŎDCҦ' -ӟx%ewT1M@cν:(Ul'epB2ír=\/0VGb;g`diM(=lWʛ&ūU]$fR2>ٙ)L`mfgW(p*CS?jd!'}rCN읖8 e؟&:~Z"DVsa7ؐw I%) rslUORKKuJzd0I_t$Rr941g25t| S*c͍ed's4cI$fWM/%xwDݠRY8cmgs~zo4DŽ&lpU1pⅹR5HmK9lȔ;2:-a)v /ܨTNT4C>V$#Uu8[`cd8bi) kʽp>}v^bP'3J?%Eq]N>(e{a,Uxpց'NC:#iPͼG\!XJҔ1h`y0(COWaٌ@y ̇ۿ~㟿߿H/h3lj3v9h ۥ^$v$f< #6 AGԬP?$=P>^%K4EenAmeɬ#C 5puz6aH$bڽ3ƥ_oDCvposzesjZhzX9m.s* b:Rwi'o2m>{)-OƵrN glp$tځW&fc" CRݑ:B0W<*o3=>UY9#T&&[ɀMy^y# 4)K.V=xS:8~?O6SÓ>3ؑtfTE_UM-OyE2IJiֵ}7r)B&ThxOVñ)PaѺȋ[s:bM)J͵/p5IteM+Kҁb&Q'5%Olðo@нCƁB:a] s6H!P J܌cOiz dB$0$I0A<1>Vj9plǨF8$ "{L}P !D8oA=[;H~i^CC܂ƺqwpEPRt G8bS^?BSHXH~Jpm%T)O#>jl S%4G"Gέ2 y5!uU(/"5k5;S|ɿ\w@B2MQjc3LC"wqeʅ{Q,+TC\4tke 6k̕TlOh<mdVsUjO i A@Г0kc%jӔC2&Ο]oiyKڈ[(2UYjRxt^Ve>D2o0c0ps j#iЎ?nN{{Z*ʠXW+"AD*|K.Wt 1(Vr E. r&YMԺMIYQ]Fm^cyr-ٽ:Mxه<3e%f$`9ٵNd=Tex-N?gZ6`ЌqiT|2IfJ)X陒"XӖW7$BȋbUQwX)FG L 3.[G*4h޼g%s_A,$=-q\{lis@5ΗLpQaDMτ]XZe2MdN?^A n{}Ɓe?~*h݈b׌N?;U(3 NsW躭eGvr TsFTnZէN^T+.ʗJx3`JB$* sspkjci}'1h31p<)G ے+SptcXmxv2VygB^u l<퉿,,~(suܚ\aѴIr= _XT7IדQTAOo26ay̨& _9жtŶ`抭4T:VD.\$1Hh 0ͿӯehHЇ&%8K(S뼳wBUqAB`t9yRWߕDq%C-(<^1M4AOOߏo\b185Vy"j(.0Qw(v"') XDƀ6qTd/},PRtBg/kO҃vj[U8F.b}VӘQ",oS}˓K"|ci?Ԓs|͠EӚ_ak'lA+ŒԄÀ8 @[A{fDC/O`1IJn WӦ߄<Ň&41oN51D+K"b9GSD2v!U# Cg"+<Yb+tD_ߡr܆((^Bms p8Q/q H hQQeaPDRޖs+r!3!ee(ɤtўD $TyKklY{*-KyaKv83zagQ)Ov4(a#@y[0ϯEw#ڢf -=wQ8jsweDh όPdT?U턋\r= 0S}6fĦ_I7spb3df c sQBͭ5eUTU2^uGHe*p+C<Ў o{=^'zhDW\\SD./ZBHPWdzM[O0 U2.7BP~|`cTz%jesF6PL@`?̍b#Z4{}tFA^yӔ06z!&) Ĥp`L5fI:bC k?m.s  ,;V8|]D6}$T2iG62AGJo6U/vK@FABeP`CV͑G +69mΥåA*ԑ]VX w3U9a HIxVALZ)BBӨpnp=ِ#uuj,tYX_cy$uq6LOAFU&aVlDԞE@kԒO%-9kstgV柌7A=#0ޱ6:'Ďl=ب=OnSulCXlJF&EZ܅᥂ 1 dT |l̽ Ϧ n4\n3!Ơ2Ӱ`m,pe6(pf5 PèN>kgQr3N +=3m"U^| >ZkartCGܙ3LPj:*8̦y5UDT}cH.ȣP$6.{Chj|^;3dgQDwgf;Xzԩ:W!x͕('jKB5r t)KBD̨Q yᾄ)!hJSװI)z5gH!$M+KB|Se̡.>gĦOT+\hsqԸuqp?X-^i vfT3,%=?Gm#V))Y.$ ֞SP{65Ṷ)E"LWz?S<ܽ#Rs !I$Q'S!},tYw;瓸5JE8(TYBeעIcDaSp0P!kJY@֦X/_JWNoXNg "UxX&y^kUT8jS;t҇O/{!& g DƝm%[!>2^Xd8A|,?zjRG``;\Pq;eo;a>$,,ǹSCl+;h%ډwsd’ KeNbs76]\ib e0+%iz3(#Վy53d RD_dG?鯤wuh+dQJ~^"=O!ʘ`u4m&܎;xDt:M>,HksaL4@mBbF!~0m]6ك}mN6lֿ#ٌO/)s{>m> QgG=^BViOs8XyH+Qo~㨼MH h+Ԏ .:i,p}LbtUlrMcn$K()D')39)4g[uvb]K]4cI#O5kÖ8bL,V+xBb8M~vK)f^d*򂚎/u1 fvR"nH1,,\kZQr0Tp8%OGrr^C+g]uCqJ֓Է5#BC{ ̜L勢߰Y@'ln棰")bNֈipH lv r "E Wv_)"/rUc sp#@1F fi[<: D־<9ԼOfai8:!溿ÑA+5`8JZqʹoz.gp[T>95mTv`yoGN(Ъ欚m.e'mW c7|z\u^aiQ1f{Zw"\Xw{3f8񵅔LɋPEi޵Dw4F ]4r,ݽ !#,BԲ/Jg.xal-٭HG7S0Xvx -AP@?I2B<+gbCk lʤsϩkaNw癪9yvd9$.^i6 rϦ $q"|(rUmCՏS*z&Τ6 υM:KI`Ő?%"v#>v5i$zN "GS ߣu )blt WN#h0 ͥ;z)˲10k)- %"Wh׶ee6rjR>i6j=@))O'P)¯(7iq"e! fإtvU񷝠)AB1a*?] r4482o 8BFߤXhcZe׆rAUcPrZ|+LTI(;CL?RXjEATV|*{ if%IqB'R<۾Rm I(8V9@ T\ |EzOGNXCӨYGVLGsJP"m#3ŽpD'BjH:>A4hՔ#cPz6c獜BkZ3X;.wa(!l eͅim"2(ՆJºUQqc"\)Cq!sN11A 7v/IΒ%yAZ⾤vafqo]qqъZE7P:0!-4.uw6P\g rEi U\*VގΏ!ao~k_zw;i OLSpi 2xZyC5gr`Y$-oH%|FTJ2.sNI:6"(Wn%t*$ڿk !nb0"3ÞUv[ MB?.'&: WL܉1gMIjر\o F=#s2}-*Hi9}U h4fyyhQ{eh)N2T2+&EzF@&sZ$aRJZz B,Z%\g8Ԭ`|X\;|Y}Kwzű#}a[Oߕk~hDOf|r0 HTXQYd"s0HNgo\aCj.;LÔ }fJ1ɸ9#&.,5 OF)y4fwaSLE+BPi-qGvr+K\jtlp𽸧3G2o,>X@ MWK{? M7 ikF05$FZ$4|@&:AK%g>]RAfo?ZsG:dk=M;I,1 S1m֠+wH&n2&6c%T>˄ooNtAd.]G߶IFg*@A@2 iQ V@<5d3Qna⹏IGԩ##D34 2kR촧U#v<goݔ> P^Cཋ|jcQFH$)@v`}6[,ׅՠlf><#˾"LItݹQ zXƁyC+;i)6.`l׬>ʫ'ёN(,@ VxҩwhKC$~9X)2 p]qџR0G|nZU%Cpף0]tEnR[-?ۚ,2 Zb!৾;a=*m`YfB:{=%k X0@ee@VKIK ;m'w r\N-6^&GF8,0oW.cjLJ< -:4SN6FQ i f̱)UVYDJm,-f-}Cɍ°q\UIr5DSEǤ.t3=f?l 9ZM%6ЀC!` ;n-).<;%hy!fwRvlL;c?$rb[ocYp~Fr5>lެIqzy?X;|5ԓ6 I2Υr&H!0qwTv e#we6+ n h*`^,,j PʤG롯R]0VjP~3&ڳI_H-ú1[٦9F' tx0a;vn zqu|et$v*c6F &~i@ldu uvKEr@Dl[̺tT/'':U"6ePV!$Du1qܑw[md1[ZC85-ey՛.\εwhR d2ׯ71E,rq3 ȓkX|ԝX._ÄXJj ` 61H:h8]P66.{"Qծ1Fq`#y"и'HАJB_kUrh;oHRpfHo_Jj7<ݥeHX؃ 0TN'OYP/PKؒ$>=q% u%+sh!{Yލ%]Ҧx>c⥌ܦHP'-mG2;?U " {fy1&(:B?pLς1Jc4F"פn8KߑΙ @ s ga-wN(F*nF-fk3~Oer :'cb6$ϰI? @VO$%!udYYS%b,#3I( md gR 9lYnSair䱭u}\sxAOS2k%iֵ&Š[z"i`\7 0}u)K^Ld-M&0I&%Hw3K}bLC**-ifmd4o& eVX`e}t mU;jN厓JDܐ0:l̖&vO?zU+-&Z}&8<+$eusyiL7Ӹ.WRg-!8;Z+]粩te&fM9F[mo=HyCo#.}*ev0Sor ?}&X;˒2*nX&["K <%h(^G`E9'Q#pɄ.YS&`d2v9- H,W07M*oRxӢ@aڭȸ  سh7́Xd$EyyĔ#hڰgh(% @@ki.7}(`e݆1qw 7I47@+A[t>"ΈLy Rf@7<9ʴRa]b|Qg(Pz`h[fMͦgt?H_sCuflkzjH%->|y"zQÏ^B mJR:q$PGq)}G!˥L5yZ+AĩM3u<"tOā*"^1N٤QrFFɝ\*eG ;2uV6 V{ I-[8mJ}p &ڂc<GJX`-K72M'DŽ}]T |!G93ڈD 222I-8(0ڤl\4۬#.[hz|%yJVCV,"mEuyutE[!)-1 6mZx Qe*[Na_lጎɌ[b?"Vx$!jIIG$BETM-.08ARd5?VՓ%TqX!Ķ$K GfI ֜ɪӰ1)fGoʌKl[4D>6MDM遝r۩( iҨr_1[o@vsEDUw gԭJV.N-n ,-Aa; ;.^8.ҺR4 1\fNZPVeڔ&WtA)X0u#YyOK=_mX/8#~:3D~06(r0R +=][؀u_o*㰬_*Ń5WdÄٳ,loIXHɧQR—` M>Zb 0!k-X*X_ PV>(V$5. fi3w4IG&p %'Fp㝬%;VR\-bFw6P Q#S/o&8:꯾X_<~|ۻ||A|k׿$<T<<ZG/[k 9 OM k#c f hۖJ3i#7Dk w@6¡6K7Fq џԆB B XX;[}Q(nf @gC((y)x(CܦQ/r^f$``jjI]FW@aR!s0Mx,}6(AJԨƮm Z;iBFEHQ֛XQc]De"(rg8G&Yau0X/J,T¹0?ŝK& %,p}[S/Yݜ(bTef@#,[6qUEDr$>oEGp"j 3% gWLj)H$/z4xXkkxJ rM{=Ġ2+R!bIr=L퉣 *U0F1SpL)tB,b*, Lٔz#%b( jiz|!~6)t?y3SU8M޵ 4tD5CŦ3EqojQQ?bY96ש13aRy[OkzPڽCypie:6*"0PGa,t%Y՘SYqrC)QPwPIq(= .-WAKΒ;|`HXgґGDn~J&N1'ҷSAd g@hѩEA˒MHW+$2eoĕ~/@Wr+Ilklv"YA˂Ab4KBn!~Y1c "Wkp՗2F t@vnPU۝5Ond7"܎-%԰>q/c4^XŹIJ؈qQļ[*¼VKɨ: HȢ;DrS ]t˟a$"VGjӁz+he ڬ=m.Ey =ivc?eZ$Y%XZ*(WV7 ӭ]2;bMF׈FE«HŊ#6>Լ*ZľMO6բZBKU-$`V,Y,"VgEIza9Iܴ旍Vt|U}``zirutqdТ\D[Um@OH VM4" @]jNƵCT بGwCÞgjFԛ0k aEF+'hJsCµ6%UC2<ΰ꓃J m~ bl;HĶqvovK1^]\,bHy.WInv"QȘwNށBSZ^HߐeoxoӲQWȘTNpEK^asY5žϮ װ n:!Zo"|40`%kǗV6Fm$>Y;pQ PU`7S &g7&ըYkdr&AIa@ajYKK& wVg>] <8ܟƗO߈[?bM|q|S߲?M~AaAg+m ZÒxIB^?|/0{a 'B=i`^M2m$?y7dG`~7NR*]  be8#Нdb7`k&[-VMt{O".$NgPK?)f1`ߴԀY`xh{O]Wq=@LȒI횿kY5hnF)Q~2Ƚy_P&ĭnLmEw;_[IH5{yv]v+O{L終Lh<tyRe+Z_l+Yק%mG4FJ&YW ^cDD+esJb;/?)k9[&Rαw ]e}7B\[/mjE'ҋԅe1#]N:Om^+ƶ" #*yhڔX9 oG57jvp١ezeu:- eֱ I Dj J7J.\zԥ^F6.!ADr6-W 8[*`i0mnUo[>]2bLWc3SfXʊMޔ$jv z$)p-+ҰL6Bd/ǞۭFIY!hZ[L.,PD_b\ȃɣ rHJ_@PfҤ WD3NMR C(ܒ F51WJ +%?ǔ V]7) 8MohYǐ/у 3ׯmv[˿R*[9_O{7 jƯY +$ HZ5bRXJ_mX;.]6aJe`/8ӂ*e>j] L0ғ1UĊqf$sKY֩K{h\`;,PȍWe;_>;ytϵ] b^8?G|$v9ek+)$|Qb_bzs~弨Jh fdv3p( M\Bk5-6r447^KnhF1Z& 7}A #iQEJPj+FhqQ1k,Ibd.:}pxYj'1v gFޅU꼦=B$,6Rӄ)ERB4$ s6Lx/YVCJ8ifɠe}3}\!x U]l.'/=-!>2_X"/X+KQ҉OGm݅POB #hdL_b\dK":{atd{Uc{=?ȟ~}ȿs#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=Rxqa#_M(^!qQO3}2tqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#'QHI=RxqDa#߃ i5Z PmKs58*VX-1xf4zhj _~_~?/?I,B= JZBfy[Iw# e8,5zw,9h,NȄCcUir)4Y:%8]1a wT?Ð?ĵlתCyU;k^O2oiqN":1G6 y>B}l#4fN.lubH{s9$Qiga՘].flڱ v+(Cjydl5lTb3ᫌhZg*CIBi0-~0>RL͔2Jv>hĐB J9ڦ&V4LDvVs9I.XgqxF̎ 仪|i jum۹@3msbhY=UZN尟LYxD$쯻L.8 nX7̗望J:_ݵ$Mp$ ɽo +9aJ~ёE/Qnޚqi :tMszlYQg cqե\Z.,L2>VIK^ZCp8?,+k̼ TJyzC;i~t[wMT@w&!^@+rIߨK mkVc#f4>^ :<~hg7׻WBx?K2`ĸx5:񻌿39eQC>\jDq:[:Iyi090.FJ{/S4[raQ'+DXиG|߫wЋ5Qz7GFba",pVJvLR콬QBщ/*榝qS3*z&,޿.sQێb)䗎L/.@xbw$2/^_) EZ: 0y->ygMI=,RiJLGgjr>[uk`y6RFJ\{tzZ֠д"Kvw,'4tOG&`7 ӢbXDo5NT ifnت-_u]6G~1/)5Q~WW'B#?8-kv2(=C HG O6Y9$ 1ZτzkOg%&TGy@* 릃~nMk9d́>f {1a^oЈʾ{Qku\L?Wm *|ʏOjD奎ʱH%ov% Rwtzm$LLb([H3{IʶĆ*^LeZj7 =^Q*cQ>s *S늷~-3Iv)Q 0 9Ԏ_Xک3Prf'ŕH[Z)ZrTsi/ Y(/^f=Yp&Tr7*yZw*it.Lz}֤-==iqi_hH.zBx(/MZl%\t)s- pTꐤYyB: ",+=C >(xmÂD=1jha߉6m+mVX;8jGEXSaF*أ - MNX)K%n+qK'ӯauFZcRMV-6uH- OOM[>ɃU|5boWzvuIScW6\)bM#sfEa6ln=:@<4Xb, |N|'_PHUh[[< !8L:AVpd^v lQ(R-K{l4!QV/u%@K9\]|Q( rO%xϠ,v6K…&&&MG?ԏBj5 -\QdXsWjr=]IUz+%4k;M1hH)Q@"WE99Qg1} g16Z,m^3Uf\=vFNt6'ٟaӉBtm@_~.̂}w^074rq!WnU6u%|DC6mRYP[˶m{)32E/)x3=Ɗ9wW$U; {V:ʜC02[7wa@qh4EGZ>0<:r>-ܻ䂴ܹ`ѫDs=<3t9G=ۥTZ[r+0g|T-7i Y\)_)[!Na ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_5/000077500000000000000000000000001410636150300204525ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_5/read.fa.gz000066400000000000000000000076221410636150300223230ustar00rootroot00000000000000Xread.fan%;s̵=Nr_X`Xڳ>j?b돏ϯ?˯Ϸ}sׯϿg~׏_?o<=}K_ߌ?_~%󳇨{:gǷX+w zWzw^8ouq /Hxuh&AtD}d9G>h-8Sw, }}w.JZ Yq5Ylsfi9tnX},F̫Y'>SȳU)3lU2l&;Q2vUc:#7󪐥u.ٟ́[SwmBe\|u:X[1Ԃ乼c`x> u,Xb̫S5f*?}faÑ'gKf+)2 "#HYfёvyC&43V,av2؝|g8>q@˦,3i÷Նbzabx>Qr3\'3jĉW+qrd*R(\~O˶WSt7X8\jbXi`rE=(eszUrW!8اQ%O̩X vM, l0<]S$&X. MW Aߔw7v4&_d|XJC&1%W8F ` |EiBIR^ii&T;%IG\x^_W1ԉV> WCm uaPKK@)1=ķg7es`uU6pᴤTYac*cDPB? kZ3{?jb|=!hXNDZf\jW}Bø,d*zDF2"ʢ;gV-qkdRmTIRy7cS1Y7}BL89,Y2@ATNwԊBQ`Ȧe(`wursJFH1&C% /hdJ4)HTZ%d,<kWMO@*4Vբnpi$ѠΩ#pI9Q[/@M؏3B+LM kqxnK1M3'#X?8SЌr*V Z7w( OD Ӥ,ԳܺҲtHR "Eyюsgp Rťp0R9˺I`Xn8oĮ*-rv1dIɔ}eOi*n1X\5ABӒ!aGP:P坌 f)vԄ"@ {QŰ0:;t_D>H 7\ni8KF NU-宵.o2lːJdKcH&6GdRX+TWXF\p^d `Yx%ܥEc1pP0[RX'iS؅%6T?x&vxtNӼr#r tbq ;ai\TtfMw~庚MJ8܀jDbD{ ^ [yTHy&d٥afhkMX+qC`24((SvG2Zf|pIl).ݨEFQ0ՔS*(Bl|OS7񸘺&{ۑ!Jppe7o4pM| φO%!4N䖥.4lzLc zeD6焬r2J3%b62vE)8R~pY䪭nG: X8QʻG=$%XƁ;u}Uhc'"گ njVNT&7,)^f>Jxf"{˃UlO.gUQ*xkGƻr(Z; lΪ.%*. 5=!UƚzZ-ZR.j2"\-RZ5 1~L~$ *iVXNDikwѨk' |҅6aiQL5pFL nف ?Pk65ItcBy~pwM>-Bk*V_ﴛնj̓ͮyN^S!$ZeaLaQVF׬e͕6(t]k ӕz!3 1-x:*I' ;{t#d) 75He4Qjf+Bf2.][& NHzoĒu:4$.3N0L ?3݅>9:3yĪLf ~C?1{yo܋t',3+N|fx=SOjh yդs||'yCP6=90M0Ys\oiQFm1=~$Sǹ1x{ĞכuSdž|Mڀ֖sggP~~>Qx8l67v sҟOXϠPLRq=k)b"ka>+Ôuv!>yfyDlnoh6Kf?ש6,XO~<ܢc~ w/nlj"(Fd%oxVuDv&ƼnV-feSpf,xN[6N\Wȹ!bl!8&P(@%glyeși?Nð3hYxǞ|=H#>ĻȀQ{xC]Cyv\dS/,j00Yx\y_ԱGn[EOֵ$&)Yt|"%r!I!@GiXV१\:߮Wk.g=&Ma4@셠<@ }1d7iMAP(/ 8rI'&?!V;%2bT=9Tٖ8Y<֞\,#vY[N.`gj#yyH$ ^_+oQ jn Nt%VmǙN*f+~UvɕY=#^ܓa[3M?73!\sY97]lHaNh37bmɮHp OWK{Ӿ oԱt!p:Wqɵ7vn06KW$0r^&6ds5Dakӫ4's]2q%1wWDA^ph"0t72lӍ9b2Q}WM=;]gR ʈ &\Ư <`"h"T])5Fba;5!|W R89G ^E<4~yOu˂\ڃ'bCf.U?^u+s&R]Qű&q/bCq>T,q- I 9u[=f+=BnzOC+QMкM:H9h[;aV ^. kv fHr_߱8!"GۂOE @_)شUΉ[ .2(=, }`+C⨸'k߿5f=g1vcDcrÚga7c'EVhKmXtp;'旰 &:cѼepCt%,SX\Pr88U$, 4iJo]D!тM!^[_\@)' qQSS]H2%,ZO@Y{X Yh CskDsB. ҏ8,sC`Y?Ts(xUt*+EJ?NtʉB_FW01 `׿ibY1%_VCйNJ{_FNC_pCBMm'5g5-'n21u1H!+4*d6٦ Q/Sʒ-݆$;x)e[HS͇FDs^u ,B Z&-vdJM8Yms0_Tj}{"v  `GB9:19aFu6*Hnmt,(&NuL.OSEqÄK ̎~==ơh[ASЬ[V(!?N\w{ {?&EOKLVsXb5/Fk͸s}hwL Q"/ Xn7N,s?vGh6r,_)l7]%lŎ̎BwUs7"^MZ!{1l} }wg9vB*W$0B9tԈrOTS.銩D*1]{:}OOnRU~tǀ+Qv! 6rQD[7†NЉvosK"x;Wl/HE2{a6v4l`h(0 l|UMzL/,dKBA@d1]Zz7owWtq,5aue/ȓ\(cСk;l> ʮcٻ+PYM;W[8˶cb >+zhRw/~q$~OZNI%, & |dyJڃ?,J YxYAm{8. Db7D p{:(.N=a\+ǂ5@rs~ 8f軳}+Zu c덁*R/VFhG*=~5ܔӏ(>͍siA[oʎaK̔)PE^HAk|\S;Wq͑~ 7oN K)4!btgIi7к+֪ź)!v-"L<* UoNQsڲ_CS6 j4X8L D8qPˊ f}S7>g1".A哾ҶÞ|9pc>==Bkz:wūafaϫn8I-kCH4D-{ UMHnaJGhp=2W~ILps[B$==ܢNXyX ̉;F"v"um{E>=܂=˱ U"1ד- ᖰ] 0$*{=zn|;{wOUȁ]1¿[ ?=|sז}D<Ƨ*Q[89-vvengmlr-0.2.7+git20210816.a2a31fb/test/data/test_6/000077500000000000000000000000001410636150300204535ustar00rootroot00000000000000ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_6/read.fa.gz000066400000000000000000000007021410636150300223140ustar00rootroot00000000000000Xtest.fa픻AD~I?UZ]C|ů2G* 9Bg9Hn;BS:׼w`%HIkiCR|d,EinRDyM0g2\M(+.O xR_PX؏B1d2[%5IBXpWS 2kQRԄĥ$1Riy4QM| 6YN3x솀OG" dfRe0/HK#QOdT@jdCNB˫UZ/N s׌Y{vuV'I *k, ,?;hZ)NЪ7 xq~.;,;,;,;eeeee~ޱ˞ngmlr-0.2.7+git20210816.a2a31fb/test/data/test_6/reference.fasta.gz000066400000000000000000000057521410636150300240610ustar00rootroot00000000000000Xreference.fastaZK6 .,^xD*ʲ󒞙n,QdQ_~Oo t7|&1V Ɩkf ~n1n(;-bŴƥtA$2N@Pl8`FJT?U5D%,^&ЉKY%`-9fkH|C%tCӋ!MKne^^.ި,FGL  _ DQXӕp 4h ^2S%h,h"kitYJx/! >W ʦ1 [&M\,pzGnQ]0!9<km3b_B 2#1dmΐAMoil{hr}IO<(te%Dp 6ad3$+=9aĭl(8VbCSD d ڙr $TÒ~.0haV7e1QfK"`J4)54V3ar$ΜztT1#TJQqW1:uc =8('MA)z Y2igd#'Y{(G: \%QӇ]("Ҟw6w0' ۿ$48ą@k qrB˷Q7wEY˝) D<ؔY#З.$!]]{’Tju@U]ꚑ{]31VD]]3 {LמOYt}n#Sjяԅ0Ҋ/cB٘êROgep⁑8FZ224+gHl~"# q*T2B@@h܁Z",Ok$ / {mm`,IF#q`y˔AP{)8X!v5S[*f*[0KT ίj[8ԡZt1*;0К;ڸe(s1 XXc$pU7+'jzpa H9M^f8`p;n1tۛc3|@%>Iu dUdWLzBi :duDY~Bh &h v<ح:xE<ԀSaeĽR&ޙkavW Z֝?(J)*a'S[f2Xbd?mWSa:J*]l2fc1)F<۪#_ScQI0Ǽ!]w{Q^vMj$ sk™&|y򎥧A?JccޘcK"c`rcB*ߙBzY ZBt͞ IFsyVf5>͖Iglk|f8M꺉eflm et4J@d31IrJ3sSKXI;4,"l*c~uK3< ɃikorIs%Ԃ^fWCl"x=;^׫X')5}߭[5 `(MC07Uݮ~c 0ݺ-}Isb2h^ /dev/null | grep -v "^@" | cut -f 1 > test/data/test_1/found.txt diff test/data/test_1/expected.txt test/data/test_1/found.txt && echo "Success" rm test/data/test_1/found.txtngmlr-0.2.7+git20210816.a2a31fb/test/test_2.sh000077500000000000000000000012441410636150300200760ustar00rootroot00000000000000#!/bin/bash NAME="simple read length test" BIN="ngmlr-"`grep -o "set( NGM_VERSION_MAJOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_MINOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_BUILD [^ ]* )" CMakeLists.txt | grep -v debug | cut -d " " -f 3` PARAMETER=" --skip-write " echo "Test: $NAME ($BIN)" bin/${BIN}/ngmlr $PARAMETER -r test/data/test_2/ref_chr21_20kb.fa -q test/data/test_2/reads_100_2200bp.fa 2> /dev/null | samtools view -Sb - 2> /dev/null | bedtools bamtobed > test/data/test_2/found.bed diff test/data/test_2/expected.bed test/data/test_2/found.bed && echo "Success" rm test/data/test_2/found.bedngmlr-0.2.7+git20210816.a2a31fb/test/test_3.sh000077500000000000000000000017471410636150300201070ustar00rootroot00000000000000#!/bin/bash #set -x NAME="deterministic mapping quality" BIN="ngmlr-"`grep -o "set( NGM_VERSION_MAJOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_MINOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_BUILD [^ ]* )" CMakeLists.txt | grep -v debug | cut -d " " -f 3` PARAMETER=" --skip-write -x pacbio --no-progress -t 4 -R 0.01 " echo "Test: $NAME ($BIN)" bin/${BIN}/ngmlr $PARAMETER -r test/data/test_3/reference.fasta.gz -q test/data/test_3/read.fa.gz 2> /dev/null | samtools view -Sb - 2> /dev/null | bedtools bamtobed | sort > test/data/test_3/expected.bed for i in {1..5} do bin/${BIN}/ngmlr $PARAMETER -r test/data/test_3/reference.fasta.gz -q test/data/test_3/read.fa.gz 2> /dev/null | samtools view -Sb - 2> /dev/null | bedtools bamtobed | sort > test/data/test_3/found.bed diff test/data/test_3/expected.bed test/data/test_3/found.bed || exit 1 rm test/data/test_3/found.bed done rm test/data/test_3/expected.bed echo "Success" ngmlr-0.2.7+git20210816.a2a31fb/test/test_4.sh000077500000000000000000000013071410636150300201000ustar00rootroot00000000000000#!/bin/bash #set -x NAME="primary alignment test" BIN="ngmlr-"`grep -o "set( NGM_VERSION_MAJOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_MINOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_BUILD [^ ]* )" CMakeLists.txt | grep -v debug | cut -d " " -f 3` PARAMETER=" --skip-write -x pacbio --no-progress -t 4 " echo "Test: $NAME" bin/${BIN}/ngmlr $PARAMETER -r test/data/test_4/reference.fasta.gz -q test/data/test_4/read.fa.gz 2> /dev/null | samtools view -S - 2> /dev/null | sort | cut -f 1,2,3,4,5 > test/data/test_4/found.txt diff test/data/test_4/expected.txt test/data/test_4/found.txt || exit 1 rm test/data/test_4/found.txt echo "Success" ngmlr-0.2.7+git20210816.a2a31fb/test/test_5.sh000077500000000000000000000011421410636150300200760ustar00rootroot00000000000000#!/bin/bash #set -x NAME="max query name length test" BIN="ngmlr-"`grep -o "set( NGM_VERSION_MAJOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_MINOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_BUILD [^ ]* )" CMakeLists.txt | grep -v debug | cut -d " " -f 3` PARAMETER=" --skip-write -x pacbio --no-progress -t 4 " echo "Test: $NAME ($BIN)" LEN=`bin/${BIN}/ngmlr $PARAMETER -r test/data/test_5/reference.fasta.gz -q test/data/test_5/read.fa.gz 2> /dev/null | grep -v "^@" | cut -f 1 | wc -c` if [ "$LEN" -gt 254 ] then exit 1 fi echo "Success" ngmlr-0.2.7+git20210816.a2a31fb/test/test_6.sh000077500000000000000000000011531410636150300201010ustar00rootroot00000000000000#!/bin/bash #set -x NAME="reads from stdin" BIN="ngmlr-"`grep -o "set( NGM_VERSION_MAJOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_MINOR [0-9]* )" CMakeLists.txt | cut -d " " -f 3`"."`grep -o "set( NGM_VERSION_BUILD [^ ]* )" CMakeLists.txt | grep -v debug | cut -d " " -f 3` PARAMETER=" --skip-write -x pacbio --no-progress -t 4 " echo "Test: $NAME ($BIN)" LEN=`cat test/data/test_6/read.fa.gz | gunzip | bin/${BIN}/ngmlr $PARAMETER -r test/data/test_6/reference.fasta.gz 2> /dev/null | samtools view -Sc - 2> /dev/null` if [ "$LEN" -eq "5" ] then echo "Success" else exit 1 fi ngmlr-0.2.7+git20210816.a2a31fb/test/test_travis.sh000077500000000000000000000003061410636150300212430ustar00rootroot00000000000000#!/bin/bash # Read name length test removed: max. name length in BAM is 254, replaced with test_5.sh #bash test/test_1.sh test/test_2.sh test/test_3.sh test/test_4.sh test/test_5.sh test/test_6.sh