GenomicRanges/DESCRIPTION0000644000175400017540000000530513175727645016053 0ustar00biocbuildbiocbuildPackage: GenomicRanges Title: Representation and manipulation of genomic intervals and variables defined along a genome Description: The ability to efficiently represent and manipulate genomic annotations and alignments is playing a central role when it comes to analyzing high-throughput sequencing data (a.k.a. NGS data). The GenomicRanges package defines general purpose containers for storing and manipulating genomic intervals and variables defined along a genome. More specialized containers for representing and manipulating short alignments against a reference genome, or a matrix-like summarization of an experiment, are defined in the GenomicAlignments and SummarizedExperiment packages respectively. Both packages build on top of the GenomicRanges infrastructure. Version: 1.30.0 Encoding: UTF-8 Author: P. Aboyoun, H. Pagès, and M. Lawrence Maintainer: Bioconductor Package Maintainer biocViews: Genetics, Infrastructure, Sequencing, Annotation, Coverage, GenomeAnnotation Depends: R (>= 2.10), methods, stats4, BiocGenerics (>= 0.21.2), S4Vectors (>= 0.9.47), IRanges (>= 2.11.16), GenomeInfoDb (>= 1.13.1) Imports: utils, stats, XVector LinkingTo: S4Vectors, IRanges Suggests: Biobase, AnnotationDbi (>= 1.21.1), annotate, Biostrings (>= 2.25.3), Rsamtools (>= 1.13.53), SummarizedExperiment (>= 0.1.5), Matrix, GenomicAlignments, rtracklayer, BSgenome, GenomicFeatures, Gviz, VariantAnnotation, AnnotationHub, DESeq2, DEXSeq, edgeR, KEGGgraph, BiocStyle, digest, RUnit, BSgenome.Hsapiens.UCSC.hg19, BSgenome.Scerevisiae.UCSC.sacCer2, KEGG.db, hgu95av2.db, org.Hs.eg.db, org.Mm.eg.db, org.Sc.sgd.db, pasilla, pasillaBamSubset, TxDb.Athaliana.BioMart.plantsmart22, TxDb.Dmelanogaster.UCSC.dm3.ensGene, TxDb.Hsapiens.UCSC.hg19.knownGene, BSgenome.Mmusculus.UCSC.mm10, TxDb.Mmusculus.UCSC.mm10.knownGene, RNAseqData.HNRNPC.bam.chr14, hgu95av2probe License: Artistic-2.0 Collate: utils.R phicoef.R transcript-utils.R constraint.R strand-utils.R genomic-range-squeezers.R GenomicRanges-class.R GenomicRanges-comparison.R GRanges-class.R GPos-class.R DelegatingGenomicRanges-class.R GNCList-class.R GenomicRangesList-class.R GRangesList-class.R makeGRangesFromDataFrame.R makeGRangesListFromDataFrame.R RangedData-methods.R findOverlaps-methods.R intra-range-methods.R inter-range-methods.R coverage-methods.R setops-methods.R nearest-methods.R absoluteRanges.R tileGenome.R tile-methods.R genomicvars.R zzz.R RoxygenNote: 5.0.1.9000 NeedsCompilation: yes Packaged: 2017-10-30 23:03:01 UTC; biocbuild GenomicRanges/NAMESPACE0000644000175400017540000000707213175713746015564 0ustar00biocbuildbiocbuilduseDynLib(GenomicRanges) import(methods) importFrom(utils, as.roman, .DollarNames) importFrom(stats, setNames) importFrom(stats4, summary) import(BiocGenerics) import(S4Vectors) import(IRanges) import(GenomeInfoDb) import(XVector) # only for the "Views" method for integer vectors, the # XIntegerViews class, and the "viewMins", "viewMaxs", and # "viewSums" methods for XIntegerViews objects ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S4 classes ### exportClasses( Constraint, Constraint_OR_NULL, GenomicRanges, GenomicRanges_OR_missing, IRanges_OR_IPos, GRanges, GPos, DelegatingGenomicRanges, GNCList, GRangesList, GenomicRanges_OR_GRangesList, GenomicRangesList, SimpleGenomicRangesList ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S3 methods ### S3method(.DollarNames, GenomicRanges) S3method(.DollarNames, GRanges) S3method(duplicated, GenomicRanges) S3method(sort, GenomicRanges) S3method(summary, GenomicRanges) ### We also export them thru the export() directive so that (a) they can be ### called directly, (b) tab-completion on the name of the generic shows them, ### and (c) methods() doesn't asterisk them. export( duplicated.GenomicRanges, sort.GenomicRanges, summary.GenomicRanges ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S4 methods for generics not defined in GenomicRanges ### exportMethods( length, names, "names<-", "[", "[<-", "[[", "[[<-", "$", "$<-", as.character, as.factor, as.data.frame, coerce, c, show, split, unlist, range, Ops, merge, ## Generics defined in the stats4 package: summary, ## Generics defined in the BiocGenerics package: duplicated, match, is.unsorted, order, sort, rank, union, intersect, setdiff, start, "start<-", end, "end<-", width, "width<-", strand, "strand<-", invertStrand, score, "score<-", updateObject, ## Generics defined in S4Vectors: elementMetadata, "elementMetadata<-", mcols, "mcols<-", values, "values<-", selfmatch, relistToClass, pcompare, ## Generics defined in IRanges: ranges, "ranges<-", rglist, pos, findOverlaps, countOverlaps, shift, narrow, resize, flank, promoters, restrict, trim, reduce, gaps, disjoin, isDisjoint, disjointBins, coverage, punion, pintersect, psetdiff, pgap, precede, follow, nearest, distance, distanceToNearest, tile, slidingWindows, ## Generics defined in GenomeInfoDb: seqinfo, "seqinfo<-", seqnames, "seqnames<-" ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export non-generic functions ### export( phicoef, GRanges, .DollarNames.GenomicRanges, .DollarNames.GRanges, GPos, GNCList, GenomicRangesList, GRangesList, makeGRangesFromDataFrame, makeGRangesListFromDataFrame, makeGRangesListFromFeatureFragments, isSmallGenome, absoluteRanges, relativeRanges, tileGenome, bindAsGRanges, mcolAsRleList, binnedAverage ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S4 generics defined in GenomicRanges + export corresponding ### methods ### export( ## constraint.R: #constraint, "constraint<-", checkConstraint, ## genomic-range-squeezers.R: granges, grglist ) ### Exactly the same list as above. exportMethods( #constraint, "constraint<-", checkConstraint, granges, grglist ) GenomicRanges/NEWS0000644000175400017540000011346713175713746015052 0ustar00biocbuildbiocbuildCHANGES IN VERSION 1.30.0 ------------------------- NEW FEATURES o Support GPos-based GRangesList objects. o Add 'na.rm' argument to binnedAverage(). SIGNIFICANT USER-LEVEL CHANGES o Change 'maxgap' and 'minoverlap' defaults for findOverlaps() and family (i.e. countOverlaps(), overlapsAny(), and subsetByOverlaps()). This change addresses 2 long-standing issues: (1) by default zero-width ranges are not excluded anymore, and (2) control of zero-width ranges and adjacent ranges is finally decoupled (only partially though). New default for 'minoverlap' is 0 instead of 1. New default for 'maxgap' is -1 instead of 0. See ?findOverlaps for more information about 'maxgap' and the meaning of -1. For example, if 'type' is "any", you need to set 'maxgap' to 0 if you want adjacent ranges to be considered as overlapping. o GPos now extends GRanges but with a ranges slot that must be an IPos object. Update "old" GPos objects with updateObject(). o Move pos() generic to IRanges package. o Move rglist() generic to IRanges package. o Rename GenomicRangesORmissing and GenomicRangesORGRangesList classes -> GenomicRanges_OR_missing and GenomicRanges_OR_GRangesList, respectively. o Remove "seqinfo" method for RangesList objects. o Remove "stack" method for GenomicRangesList objects. DEPRECATED AND DEFUNCT o Remove 'force' argument from seqinfo() and seqlevels() setters (the argument got deprecated in BioC 3.5 in favor of new and more flexible 'pruning.mode' argument). BUG FIXES o nearest() and distanceToNearest() now call findOverlaps() internally with maxgap=0 and minoverlap=0. This fixes incorrect results obtained in some situations e.g. in the situation reported here: https://support.bioconductor.org/p/99369/ (zero-width ranges) but also in this situation: nearest(GRanges("chr1", IRanges(5, 10)), GRanges("chr1", IRanges(1, 4:5)), select="all") where the 2 ranges in the subject are *both* nearest to the 5-10 range. o '$' completion on GenomicRanges works in RStudio. o Minor tweaks to conversion from character to GRanges and reverse conversion. CHANGES IN VERSION 1.28.0 ------------------------- NEW FEATURES o Add coercion from ordinary list to GRangesList. Also the GRangesList() constructor function now accepts a list of GRanges as input (and just calls new coercion from list to GRangesList on it internally). o seqlevels() setter now supports "fine" and "tidy" pruning modes on GRangesList objects (in addition to "coarse" mode, which is the default). o "range" methods now have a 'with.revmap' argument (like "reduce" and "disjoin" methods). o Add a bunch of range-oriented methods for GenomicRangesList objects. SIGNIFICANT USER-LEVEL CHANGES o Some changes/improvements to "precede" and "follow" methods for GenomicRanges objects motivated by discussion on support site: https://support.bioconductor.org/p/90664/ o Some changes/improvements to "rank" method for GenomicRanges objects: - now supports the same ties methods as base::rank() (was only supporting ties methods "first" and "min" until now) - default ties method now is "average", like base::rank() - now supports additional argument 'ignore.strand'. DEPRECATED AND DEFUNCT o Argument 'force' of seqinfo() and seqlevels() setters is deprecated in favor of new and more flexible 'pruning.mode' argument. BUG FIXES o Fix severe performance regression introduced in Bioconductor 3.3 in "intersect" and "setdiff" methods for GRangesList objects. Thanks to Jens Reeder for catching and reporting this. CHANGES IN VERSION 1.26.0 ------------------------- NEW FEATURES o Add 'with.revmap' argument to "reduce" method for GRangesList objects. o Add 'with.revmap' argument to various "disjoin" methods. o makeGRangesFromDataFrame() now tries to turn the "start" and "end" columns of the input data frame into numeric vectors if they are not already. o Add makeGRangesListFromDataFrame() function. o Add "summary" method for GenomicRanges objects. o Add 'use.names' argument to the granges(), grglist(), and rglist() generics and methods, as well as to a bunch of "ranges" methods (for GRanges, GPos, GNCList, GRangesList, and DelegatingGenomicRanges). Default is TRUE to preserve existing behavior. o Add 'use.mcols' arguments to the "ranges" methods for GPos objects. SIGNIFICANT USER-LEVEL CHANGES DEPRECATED AND DEFUNCT BUG FIXES o Fix bug in distanceToNearest() related to ranges starting at zero. o Fix GRanges(Seqinfo()). CHANGES IN VERSION 1.24.0 ------------------------- NEW FEATURES o Add the GPos class, a container for storing a set of "genomic positions" (i.e. genomic ranges of width 1). Even though a GRanges object can be used for that, using a GPos object can be much more memory-efficient, especially when the object contains long runs of adjacent positions. o Add a bunch of "invertStrand" methods to support strand inversion of any "stranded" object (i.e. any object with a strand() getter and setter). E.g. invertStrand() works on GRanges, GRangesList, GAlignments, GAlignmentPairs, GAlignmentsList, and RangedSummarizedExperiment objects. o Add "is.unsorted" method for GenomicRanges objects (contributed by Pete Hickey). o base::rank() gained a new 'ties.method="last"' option and base::order() a new argument ('method') in R 3.3. Thus so do the "rank" and "order" methods for GenomicRanges objects. o Add "selfmatch" method for GenomicRanges objects. o Add "union" method for GRangesList objects. SIGNIFICANT USER-LEVEL CHANGES o Remove old SummarizedExperiment class from the GenomicRanges package (this class is now defined in the SummarizedExperiment package). o Move the following generic functions from the GenomicRanges package to the SummarizedExperiment package: - SummarizedExperiment - exptData, "exptData<-" - rowRanges, "rowRanges<-" - colData, "colData<-" - assayNames, "assayNames<-" - assays, "assays<-" - assay, "assay<-" o Rename "pintersect" and "psetdiff" methods for GRangesList objects -> "intersect" and "setdiff" without changing their behavior (they still do mendoapply(intersect, x, y) and mendoapply(setdiff, x, y), respectively). The old names were misnomers (see svn commit message for commit 113793 for more information). o Remove the ellipsis (...) from all the setops methods, except from: - "punion" method for signature GRanges#GRangesList; - "pintersect" and "psetdiff" methods for signature GRangesList#GRangesList; - "pgap" method for GRanges objects. o Use DESeq2 instead of DESeq in the vignettes (better late than never). DEPRECATED AND DEFUNCT o Remove GIntervalTree class and methods (were defunct in BioC 3.2). o Remove mapCoords() and pmapCoords() (were defunct in BioC 3.2). CHANGES IN VERSION 1.22.0 ------------------------- NEW FEATURES o Support coercions back and forth between a GRanges object and a character vector (or factor) with elements in the format 'chr1:2501-2800' or 'chr1:2501-2800:+'. o Add facilities for manipulating "genomic variables": bindAsGRanges(), mcolAsRleList(), and binnedAverage(). See ?genomicvars for more information. o Add "narrow" method for GRangesList objects. o Enhancement to the GRanges() constructor. If the 'ranges' argument is not supplied then the constructor proceeds in 2 steps: 1. An initial GRanges object is created with 'as(seqnames, "GRanges")'. 2. Then this GRanges object is updated according to whatever other arguments were supplied to the call to GRanges(). Because of this enhancement, GRanges(x) is now equivalent to 'as(x, "GRanges")' e.g. GRanges() can be called directly on a character vector representing ranges, or on a data.frame, or on any object for which coercion to GRanges is supported. o Add 'ignore.strand' argument to "range" and "reduce" methods for GRangesList objects. o Add coercion from SummarizedExperiment to RangedSummarizedExperiment (also available via updateObject()). See 1st item in DEPRECATED AND DEFUNCT section below for more information about this. o GNCList objects are now subsettable. o "coverage" methods now accept 'shift' and 'weight' supplied as an Rle. SIGNIFICANT USER-LEVEL CHANGES o Modify behavior of "*" strand in precede() / follow() to mimic 'ignore.strand=TRUE'. o Revisit "pintersect" methods for GRanges#GRanges, GRangesList#GRanges, and GRanges#GRangesList: - Sanitize their semantic. - Add 'drop.nohit.ranges' argument (FALSE by default). - If 'drop.nohit.ranges' is FALSE, the returned object now has a "hit" metadata column added to it to indicate the elements in 'x' that intersect with the corresponding element in 'y'. o binnedAverage() now treats 'numvar' as if it was set to zero on genomic positions where it's not set (typically happens when 'numvar' doesn't span the entire chromosomes because it's missing the trailing zeros). o GRanges() constructor no more mangles the names of the supplied metadata columns (e.g. if the column is "_tx_id"). o makeGRangesFromDataFrame() now accepts "." in strand column (treated as "*"). o GNCList() constructor now propagates the metadata columns. o Remove "seqnames" method for RangesList objects. DEPRECATED AND DEFUNCT o The SummarizedExperiment class defined in GenomicRanges is deprecated and replaced by 2 new classes defined in the new SummarizedExperiment package: SummarizedExperiment0 and RangedSummarizedExperiment. In BioC 2.3, the SummarizedExperiment class will be removed from the GenomicRanges package and the SummarizedExperiment0 class will be renamed SummarizedExperiment. To facilitate this transition, a coercion method was added to coerce from old SummarizedExperiment to new RangedSummarizedExperiment (this coercion is performed when calling updateObject() on an old SummarizedExperiment object). o makeSummarizedExperimentFromExpressionSet() and related stuff was moved to the new SummarizedExperiment package. o After being deprecated in BioC 3.1, the rowData accessor is now defunct (replaced with the rowRanges accessor). o After being deprecated in BioC 3.1, GIntervalTree objects and the "intervaltree" algorithm in findOverlaps() are now defunct. o After being deprecated in BioC 3.1, mapCoords() and pmapCoords() are now defunct. BUG FIXES o 2 tweaks to subsetting *by* an GenomicRanges: - Improve speed when the object to subset is a SimpleList (e.g. SimpleRleList). - Fix issue when the GenomicRanges subscript is empty. CHANGES IN VERSION 1.20.0 ------------------------- NEW FEATURES o Add coercion methods to go back and forth between ExpressionSet and SummarizedExperiment. o Add 'assayNames', 'assayNames<-' for SummarizedExperiment o assays() supports arrays of up to 4 dimensions. o Add GNCList() for preprocessing a GenomicRanges object into a GNCList object that can be used for fast overlap seach with findOverlaps(). GNCList() is a replacement for GIntervalTree() that uses Nested Containment Lists instead of interval trees. Unlike GIntervalTree(), GNCList() supports preprocessing of a GenomicRanges object with ranges located on a circular sequence. For a one time use, it's not advised to explicitely preprocess the input. This is because findOverlaps() or countOverlaps() will take care of it and do a better job at it (that is, they preprocess only what's needed when it's needed and release memory as they go). o All "findOverlaps" methods now support 'select' equal "last" or "arbitrary" (in addition to "all" and "first"). o Add absoluteRanges() and relativeRanges() to transform back and forth between absolute and relative genomic ranges. SIGNIFICANT USER-LEVEL CHANGES o Renamed 'rowData' and 'rowData<-' -> 'rowRanges', 'rowRanges<-'. Old names still work but are deprecated. o Some improvements to makeGRangesFromDataFrame(): - Improve internal logic used for finding the GRanges columns in the input. - If 'seqinfo' is not supplied, the seqlevels are now ordered according to the output of GenomeInfoDb::rankSeqlevels(). - Now an attempt is made to turn 'df' into a data frame (with 'as.data.frame(df)') if it's not a data frame or a DataFrame object. o The GRanges() constructor now propagates the metadata cols that are on 'ranges' if no metadata cols are explicitly passed to the constructor. DEPRECATED AND DEFUNCT o Deprecated 'rowData' and 'rowData<-' in favor of 'rowRanges' and 'rowRanges<-'. o Deprecated mapCoords() and pmapCoords(). They're replaced by mapToTranscripts() and pmapToTranscripts() from the GenomicFeatures package and mapToAlignments() and pmapToAlignments() from the GenomicAlignments package. o Deprecated GIntervalTree objects. o Removed "map" and "splitAsListReturnedClass" methods (were defunct in GenomicRanges 1.18.0). o Removed makeSeqnameIds() (was defunct in GenomicRanges 1.18.0). o Removed 'with.mapping' argunment from "reduce" methods (was defunct in GenomicRanges 1.18.0). BUG FIXES o Fix 'findOverlaps(..., type="start")' on GRangesList objects which has been broken for years. o Fix self overlap search on a GRanges object when 'ignore.strand=TRUE' (i.e. 'findOverlaps(gr, ignore.strand=TRUE)'). CHANGES IN VERSION 1.18.0 ------------------------- NEW FEATURES o Add 'use.mcols' arg to "ranges" method for GRangesList objects. o "assays<-" methods may be invoked with 'withDimnames' arg. o Add mapCoords() generic and methods (replacing map()). o Add granges,GenomicRanges method. o Add strand<-,GRangesList,character method for global replacement (i.e., all strands become 'value'). o Add resize,GRangesList-method. o Add DelegatingGenomicRanges class and vignette on how to extend GenomicRanges. o Document subsetting a named list-like object by a GRanges subscript. SIGNIFICANT USER-LEVEL CHANGES o Modify "show" methods for GRanges and GRangesList objects so they print a 1-line summary of the seqinfo component. o Remove as.data.frame,GRangesList-method; use as.data.frame,List. o "trim" method for GenomicRanges only trims out-of-bound ranges on non-circular sequences whose length is not NA. This behavior is consistent with the GenomicRanges validity method. o Changes to flank(), resize() and start/end/width setters: - no longer trim the result ranges when called on a GRanges - warning is issued by GenomicRanges validity method when out-of-bound ranges are on non-circular sequences whose length is not NA Note this behavior is now consistent with that of shift(). o Speed up validation of GenomicRanges objects by 1.2x. o Speed up trim() on GenomicRanges objects by 1.2x. o Improve warning when GenomicRanges object contains out-of-bound ranges. o Work on vignette HOWTOs: - split 'How to read BAM files into R' into 3 HOWTOs - split 'How to prepare a table of read counts for RNA-Seq differential gene expression' into 3 HOWTOs - split 'How to extract DNA sequences of gene regions' into 2 HOWTOs - make individual HOWTOs subsections of single HOWTO section o Follow renaming of TranscriptDb class to TxDb. o Replace references to plantsmart21 with plantsmart22. DEPRECATED AND DEFUNCT o Defunct map() (skip deprecation). Replace with mapCoords(). BUG FIXES o [cr]bind,SummarizedExperiment methods respect derived classes. o assays(se, withDimnames=TRUE) <- value no longer tries to access a slot 'withDimnames'. o cbind and rbind,SummarizedExperiment-methods respect derived classes o "ranges" method for GRangesList objects should not propagate inner metadata columns by default. o GRanges() constructor now preserves the seqlevels in the order supplied by the user. o Ensure tileGenome() breakpoints do not extend past end of genome. o Fix "show" method for GenomicRanges objects when 'showHeadLines' global option is set to Inf. o [rc]bind,SummarizeExperiment-methods now compare all elements. o Remove "==" and "<=" methods for GenomicRanges objects (not needed). CHANGES IN VERSION 1.16.0 ------------------------- NEW FEATURES o Add "subset" method for SummarizedExperiment objects. o Allow DataFrame in SummarizedExperiment assays. o Add 'use.mcols' arg (FALSE by default) to the granges(), grglist(), and rglist() generics (a.k.a. the range-squeezer generics). o Add coercion method from GRangesList to RangesList. o Add score() setter for GRangesList objects. o findOverlaps(..., type="within") now works on circular chromosomes. o Add 'ignore.strand' arg to "sort" method for GRanges objects. o Support subsetting of a named list-like object *by* a GenomicRanges subscript. o Support sort(granges, by = ~ score), i.e., a formula-based interface for sorting by the mcols. SIGNIFICANT USER-LEVEL CHANGES o Move many functionalities to the new GenomicAlignments package: - The GAlignments, GAlignmentPairs, and GAlignmentsList classes. - The qnarrow() generic and methods. - The "narrow" and "pintersect" methods for GAlignments and GAlignmentsList objects. - The low-level CIGAR utilities. - The "findOverlaps" methods for GAlignment* objects. - The summarizeOverlaps() generic and methods, and the "Counting reads with summarizeOverlaps" vignette. - findCompatibleOverlaps() and countCompatibleOverlaps(). - The findSpliceOverlaps() generic and methods. - The "overlap encodings" stuff i.e. the "encodeOverlaps" method for GRangesList objects, flipQuery(), selectEncodingWithCompatibleStrand(), isCompatibleWithSplicing(), isCompatibleWithSkippedExons(), extractSteppedExonRanks(), extractSpannedExonRanks(), extractSkippedExonRanks(), and extractQueryStartInTranscript(), and the "OverlapEncodings" vignette. o Rename 'with.mapping' arg -> 'with.revmap' in "reduce" methods. The old arg name is still working but deprecated. o Move makeSeqnameIds() function to the new GenomeInfoDb package and rename it rankSeqlevels(). The old name is still working but deprecated. o The "strand" methods now perform stricter checking and are guaranteed to always return a factor (or factor-Rle) with the "standard strand levels" and no NAs. Or to fail. BUG FIXES o Tweaks and fixes to various "strand" methods: - Methods for character vectors and factors do not accept NAs anymore (they raise an error). - Methods for integer and logical vectors map NAs to * (instead of NA). - Method for Rle objects now also works on character-, factor-, and integer-Rle objects (in addition to logical-Rle objects). CHANGES IN VERSION 1.14.0 ------------------------- NEW FEATURES o Add coercion from GenomicRangesList to RangedDataList. o Add "c" method for GAlignmentPairs objects. o Add coercion from GAlignmentPairs to GAlignmentsList. o Add 'inter.feature' and 'fragment' arguments to summarizeOverlaps(). o Add seqselect,GAlignments-method. o Add CIGAR utilities: explodeCigarOps(), explodeCigarOpLengths() cigarRangesAlongReferenceSpace(), cigarRangesAlongQuerySpace() cigarRangesAlongPairwiseSpace(), extractAlignmentRangesOnReference() cigarWidthAlongReferenceSpace(), cigarWidthAlongQuerySpace() cigarWidthAlongPairwiseSpace(). o Add seqlevels0() and restoreSeqlevels(). o Add seqlevelsInUse() getter for GRanges, GRangesList, GAlignments GAlignmentPairs, GAlignmentsList and SummarizedExperiment objects. o Add update,GAlignments method. o Add GIntervalTree class. o Add coercion from GAlignmentPairs to GAlignments. o Add sortSeqlevels(). o Add tileGenome(). o Add makeGRangesFromDataFrame() and coercion from data.frame or DataFrame to GRanges. SIGNIFICANT USER-LEVEL CHANGES o Renaming (with aliases from old to new names): - classes GappedAlignments -> GAlignments GappedAlignmentPairs -> GAlignmentPairs - functions GappedAlignments() -> GAlignments() GappedAlignmentPairs() -> GAlignmentPairs() readGappedAlignments() -> readGAlignments() readGappedAlignmentPairs() -> readGAlignmentPairs() o Remove 'asProperPairs' argument to readGAlignmentsList(). o Modify "show" method for Seqinfo object to honor showHeadLines and showTailLines global options. o 50x speedup or more when merging 2 Seqinfo objects, 1 very small and 1 very big. o Add dependency on new XVector package. o Enhanced examples for renaming seqlevels in seqlevels-utils.Rd. o More efficient reference class constructor for 'assays' slot of SummarizedExperiment objects. o 'colData' slot of SummarizedExperiment produced from call to summarizedOverlaps() now holds the class type and length of 'reads'. o 4x speedup to cigarToRleList(). o Relax SummarizedExperiment class validity. o Renaming (with aliases from old to new names): cigarToWidth() -> cigarWidthOnReferenceSpace(), and cigarToQWidth() -> cigarWidthOnQuerySpace(). o Improvements to summarizeOverlaps(): - mode 'Union': 1.5x to 2x speedup - mode 'IntersectionNotEmpty': 2x to 8x speedup + memory footprint reduced by ~ half o Change default 'use.names' to FALSE for readGAlignmentsList(). o Implement 'type="equal"' for findOverlaps,SummarizedExperiment methods. o Modify summarizeOverlaps() examples to use 'asMates=TRUE' instead of 'obeyQname=TRUE'. o Remove unneeded "window" method for GenomicRanges objects. o Speed up seqinfo() getter and setter on SummarizedExperiment objects and derivatives (e.g. VCF) by using direct access to 'rowData' slot. o coverage,GenomicRanges method now uses .Ranges.coverage() when using the defaults for 'shift' and 'width'. o Remove restriction that metadata column names must be different on a GRangesList and the unlisted GRanges. o GenomicRangesUseCases vignette has been redone and renamed to GenomicRangesHOWTOs DEPRECATED AND DEFUNCT o Defunct all "match" and "%in%" methods in the package except for those with the GenomicRanges,GenomicRanges signature. o Deprecate GappedAlignment*: - GappedAlignments and GappedAlignmentPairs classes - GappedAlignments() and GappedAlignmentPairs() constructors - readGappedAlignments() and readGappedAlignmentPairs() functions o Deprecate cigar util functions: cigarToWidth(), cigarToQWidth(), cigarToIRanges() splitCigar(), cigarToIRanges(), cigarToIRangesListByAlignment() cigarToIRangesListByRName(), cigarToWidth(), cigarToQWidth() cigarToCigarTable(), summarizeCigarTable() o Deprecate seqselect(). BUG FIXES o Fix bug in c,GAlignments for case when objects were unnamed. o Fix bug in flank,GenomicRanges (when 'ignore.strand=TRUE' 'start' was being set to TRUE). o Fix bug in behavior of summarizeOverlaps() count mode 'IntersectionNotEmpty' when 'inter.features=FALSE'. Shared regions are now removed before counting. o Fix bug in cigarToIRangesListByAlignment() when 'flag' is supplied and indicates some reads are unmapped. o Fix bug in summarizeOverlaps(..., mode='IntersectionNotEmpty') when 'features' has '-' and '+' elements and 'ignore.strand=TRUE'. o match,GenomicRanges,GenomicRanges method now handles properly objects with seqlevels not in the same order. CHANGES IN VERSION 1.12.0 ------------------------- NEW FEATURES o Implement "seqnameStyle" replacement method for Seqinfo object. 'seqnameStyle(x) <- style' works on any object with a "seqinfo" replacement method. o Add trim,GenomicRanges-method to trim out of bound ranges. o Add promoters,GenomicRanges and promoters,GRangesList methods. o Add "overlapsAny" methods as a replacement for the deprecated "%in%" methods. o Add 'ignore.strand' argument to match,GenomicRanges-method. o Add 'with.mapping' argument to "reduce" method for GenomicRanges objects. o Add "unname" method to remove dimnames from SummarizedExperiment. o Add "cbind" and "rbind" methods for SummarizedExperiment. o Add "seqselect", "seqselect<-" and "split" methods for SummarizedExperiment. o Add GAlignmentsList class. o Add readGAlignmentsList generic and methods. SIGNIFICANT USER-LEVEL CHANGES o resize,GenomicRanges method no longer checks that 'fix' is length-compatible with 'x' when 'x' is length zero. This allows for resize(x, w, fix = "end") without worrying about 'x' being zero-length. o Change the behavior of "distance". Previously adjacent ranges had a distance of 1 and overlapping had a distance of 0. Now both adjacent AND overlapping have a distance of 0. o shift,GenomicRanges-method no longer trims out of bound ranges. o "distanceToNearest" no longer drops ranges that have no hit but returns 'NA' for 'subjectHits' and 'distance'. o "genome" is no longer an invalid metadata colname for GenomicRanges objects. o 4x-8x speedup for doing coverage() on a GRanges or GRangesList with many seqlevels. o Remove ">=", "<", and ">" methods for GenomicRanges objects. o Speedup "seqinfo" setters for GenomicRanges and GappedAlignments by avoiding validation when not necessary. o readGappedAlignments can now pass a BamFile to readBamGappedAlignments. o Remove unneeded "unique" and "sort" methods for GenomicRanges objects. o Change behavior of "match" and "%in%" on GenomicRanges objects to use equality instead of overlap for comparing elements between GenomicRanges objects 'x' and 'table'. o match,GenomicRanges-method gets the same 'method' argumnet as the "duplicated" method for these objects. o Remove unneeded "countOverlaps" methods. o "classNameForDisplay" shortens the name of data type when displayed. o Add global options 'showHeadLines' and 'showTailLines' to control the number of head/tails lines displayed in show,GRanges and show,GappedAlignments methods. o "distanceToNearest" now returns a Hits object instead of DataFrame. DEPRECATED AND DEFUNCT o Remove defunct countGenomicOverlaps(), grg(), and globalToQuery() o Defunct previously deprecated '.ignoreElementMetadata' argmuent of c,GenomicRanges-method. o Deprecate all "match" and "%in%" methods in the package except for those with the GenomicRanges,GenomicRanges signature. o Deprecate "resolveHits" methods. BUG FIXES o Several bug fixes to "nearest". o Output of "findSpliceOverlaps" now displays 'NA' for ranges with no hits. CHANGES IN VERSION 1.10.0 ------------------------- NEW FEATURES o SummarizedExperiment gains direct GRanges / GRangesList interface to rowData. o Add "distanceToNearest" method for GenomicRanges objects. o SummarizedExperiment class can now be subset by row when there are no 'columns', and by column when there are no 'rows'. o Add 'drop.D.ranges' argument to coverage,GappedAlignments and coverage,GappedAlignmentPairs methods. o findOverlaps() now supports 'select="last"' and 'select="arbitrary"' (in addition to 'select="all"' and 'select="first"') on GenomicRanges objects. o summarizeOverlaps(..., mode="IntersectionStrict") now handles circular chromosomes. A warning is issued and circular chromosomes in 'reads' are omitted from counting. o Add disjoin,GRangesList method. o Add findSpliceOverlaps() for identifyng ranges (reads) that are compatible with a specific transcript isoform (the non-compatible ranges are analyzed for the presence of novel splice events). o Add ngap,GappedAlignmentPairs method. o Add introns() generic with methods for GappedAlignments and GappedAlignmentPairs objects. o No more arbitrary max of 3 gaps per read in isCompatibleWithSplicing() and isCompatibleWithSkippedExons(). o Add findCompatibleOverlaps() and countCompatibleOverlaps(). o Passing '...' down through as.data.frame(GRanges, ...) so user can tweak stringsAsFactors default for metadata columns. o Add extractSteppedExonRanks(), extractSpannedExonRanks() and extractQueryStartInTranscript() utilities (work with single- and paired-end reads). o Add 'flip.query.if.wrong.strand' arg (FALSE by default) to "encodeOverlaps" method for GRangesList objects. o Add makeSeqnameIds() low-level utility. SIGNIFICANT USER-LEVEL CHANGES o SummarizedExperiment rowData and assays operations have significant performance improvements. o mcols() is now the preferred way (over elementMetadata() or values()) to access the metadata columns of a GenomicRanges, GRangesList, GappedAlignments, GappedAlignmentPairs, SummarizedExperiment object, or any Vector object. elementMetadata() and values() might go away at some point in the (not so close) future. o Add "$" and "$<-" methods for GenomicRanges *only*. Provided as a convenience and as the result of strong popular demand. Note that those methods are not consistent with the other "$" and "$<-" methods in the IRanges/GenomicRanges infrastructure, and might confuse some users by making them believe that a GenomicRanges object can be manipulated as a data.frame-like object. It is therefore recommended to use them only interactively, and their use in scripts or packages is discouraged. For the latter, use 'mcols(x)$name' instead of 'x$name'. o No more warning when doing as(x, "GRanges") on a RangedData object with no "strand" column. o Refactor "[" method for GenomicRanges objects. The new implementation always preserves the names of the selected elements instead of trying to return a GenomicRanges object with unique names. This new behavior is consistent with subsetting of ordinary vectors and other Vector objects defined in IRanges/GenomicRanges. Also modify "seqselect" method for GenomicRanges objects so it also preserves the names of the selected elements (and thus remains consistent with new behavior of "[" method for GenomicRanges objects). o No more names on the integer vector returned by "ngap" method for GappedAlignments objects. o Many improvements to the "Overlap encodings" vignette. o Remove 'param' argument from summarizeOverlaps() generic. DEPRECATED AND DEFUNCT o Defunct previously deprecated grg() function. o Defunct previously deprecated countGenomicOverlaps() generic and methods. BUG FIXES o Fix several issues with "precede", "follow", "nearest", and "distance" methods for GenomicRanges objects. o Fix bug in summarizeOverlaps(..., ignore.strand=TRUE). o 6x speedup (and a 6x memory footprint reduction) or more when using encodeOverlaps() on big GRangesList objects. o Fix bug in renameSeqlevels() wrt order of rename vector. o Fix bug in selectEncodingWithCompatibleStrand(). CHANGES IN VERSION 1.8.0 ------------------------ NEW FEATURES o Add GappedAlignmentPairs class (with accessors first(), last(), left(), right(), seqnames(), strand(), isProperPair()), and readGappedAlignmentPairs() for dealing with paired-end reads. Most of the GappedAlignments functionalities (e.g. coercion to GRangesList, "findOverlaps" and related methods, "coverage", etc...) work on a GappedAlignmentPairs object. o Add encodeOverlaps,GRangesList,GRangesList,missing and related utilities flipQuery(), selectEncodingWithCompatibleStrand(), isCompatibleWithSplicing(), isCompatibleWithSkippedExons() and extractSkippedExonRanks(). o Add 'order.as.in.query' arg to grglist() and rglist(). o SummarizedExperiment gains direct access to colData columns with $, $<-, [[, and [[<- methods o Add map,GenomicRanges,GRangesList and map,GenomicRanges,GappedAlignments methods. These allow mapping from genome space to transcript space, and genome space to read space, respectively. o Add seqinfo methods (and friends) for RangedData, RangesList, and other IRanges data structures. These use metadata(x)$seqinfo. o Add disjointBins,GenomicRanges. o Add score,GRangesList and score,GenomicRanges (gets the score column like for RangedData). o Add RangedDataList -> GenomicRangesList coercion. o Add RleViewsList -> GRanges coercion. o Add pintersect,GRangesList,GRangesList o Add stack,GenomicRangesList o ignore.strand argument now more uniformly supported on set operations. o Add Ops,GenomicRanges (from rtracklayer). o Add strand,Rle (only logical-Rle is supported). o Add compare,GenomicRanges o Add 'drop.empty.ranges' arg (FALSE by default) to low-level cigar utilities cigarToIRanges(), cigarToIRangesListByAlignment(), and cigarToIRangesListByRName(). o Add 'reduce.ranges' arg to cigarToIRangesListByAlignment(). SIGNIFICANT USER-LEVEL CHANGES o grglist,GappedAlignments now carries over metadata columns. o Names are no longer forced to be unique when unlisting a GRangesList with use.names=TRUE. o seqnames() is now preferred over rname() on a GappedAlignments object. o cigarToIRangesListByAlignment() now returns a CompressedIRangesList instead of CompressedNormalIRangesList. o Low-level CIGAR utilities now ignore CIGAR operation P (instead of trowing an error). o The 'weight' arg in "coverage" method for GenomicRanges objects now can also be a single string naming a column in elementMetadata(x). o Ranges outside the sequences bounds of the underlying sequences are now accepted (with a warning) in GenomicRanges/GRangesList/GappedAlignments objects. o When called with 'ignore.strand=TRUE', the "range" and "disjoin" methods for GenomicRanges objects now behave like if they set the strand of the input to "*" before they do any computation. o When called with 'ignore.strand=TRUE', "reduce" method for GenomicRanges objects, and "union", "intersect" and "setdiff" methods for GRanges objects now set the strand of their arguments to "*" prior to any computation. o No more mangling of the names when combining GRanges objects ("c" method for GRanges objects was trying to return unique names). o Remove isCircularWithKnownLength() generic and methods (nobody knows, uses, or needs this). BUG FIXES o flank,GRangesList no longer forces 'use.names' to TRUE and 'both' to FALSE. o range,GenomicRanges was broken when object had no ranges o Fix integer overflow issue that can occur in cigarQNarrow() or cigarQNarrow() when the cigar vector is very long. CHANGES IN VERSION 1.6.0 ------------------------ NEW FEATURES o seqlevels() and seqinfo() setters have a new arg ('force', default is FALSE) to force dropping sequence levels currently in use. o Seqinfo objects now have a genome column that can be accessed with genome() getter/setter. o "pgap" method for c(x="GRanges", y="GRanges"). o Add comparison (==, <=, duplicated, unique, etc...) and ordering (order, sort, rank) methods for GenomicRanges objects. o Add "flank" method for GRangesList objects. o Add "isDisjoint" and "restrict" methods for GRanges and GRangesList objects. o Add GRangesList constructor makeGRangesListFromFeatureFragments(). o Add "names" and "names<-" methods for GappedAlignments objects. o Add 'ignore.strand' arg to a number of methods: - findOverlaps,GRangesList,RangesList - findOverlaps,GappedAlignments,ANY - findOverlaps,ANY,GappedAlignments o 'shift' and 'weight' arguments of "coverage" method for GenomicRanges objects now can be numeric vectors in addition to lists. o Add "c" method for GappedAlignments objects. SIGNIFICANT USER-VISIBLE CHANGES o readGappedAlignments() supports 2 new arguments: (1) 'use.names' (default is FALSE) for using the query template names (QNAME field in a SAM/BAM file) to set the names of the returned object, and (2) 'param' (default is NULL, otherwise a ScanBamParam object) for controlling what fields and which records are imported. readGappedAlignments() doesn't support the 'which' arg anymore. o The names of a GRanges/GRangesList/GappedAlignments object are not required to be unique anymore. o By default, the rownames are not set anymore on the DataFrame returned by elementMetadata() on a GRanges/GRangesList/GappedAlignments object. o 'width' arg of "coverage" method for GenomicRanges objects now must be NULL or numeric vector (instead of NULL or list). DEPRECATED AND DEFUNCT o Deprecate countGenomicOverlaps() in favor of summarizeOverlaps(). o Deprecate grg() in favor of granges(). BUG FIXES o Fix bug in "pintersect" methods operating on GappedAlignments objects. GenomicRanges/R/0000755000175400017540000000000013175713746014540 5ustar00biocbuildbiocbuildGenomicRanges/R/DelegatingGenomicRanges-class.R0000644000175400017540000000201013175713746022464 0ustar00biocbuildbiocbuild### ========================================================================= ### DelegatingGenomicRanges objects ### ------------------------------------------------------------------------- ### ### Virtual class that delegates GenomicRanges data access to a ### GenomicRanges delegate. ### setClass("DelegatingGenomicRanges", representation(delegate="GenomicRanges"), contains=c("GenomicRanges", "VIRTUAL")) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Slot getters and setters. ### setMethod("seqnames", "DelegatingGenomicRanges", function(x) seqnames(x@delegate)) setMethod("ranges", "DelegatingGenomicRanges", function(x, ...) ranges(x@delegate, ...)) setMethod("strand", "DelegatingGenomicRanges", function(x) strand(x@delegate)) setMethod("seqinfo", "DelegatingGenomicRanges", function(x) seqinfo(x@delegate)) setMethod("update", "DelegatingGenomicRanges", function (object, ...) { object@delegate <- update(object@delegate, ...) object }) GenomicRanges/R/GNCList-class.R0000644000175400017540000001240713175713746017235 0ustar00biocbuildbiocbuild### ========================================================================= ### GNCList objects ### ------------------------------------------------------------------------- ### ### GNCList is a container for storing a preprocessed GenomicRanges object ### that can be used for fast findOverlaps(). ### setClass("GNCList", contains="GenomicRanges", representation( nclists="list", granges="GRanges" ) ) .get_circle_length <- function(x) { circle_length <- seqlengths(x) circle_length[!(isCircular(x) %in% TRUE)] <- NA_integer_ circle_length } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Accessors ### setMethod("granges", "GNCList", function(x, use.names=TRUE, use.mcols=FALSE) { if (!isTRUEorFALSE(use.names)) stop("'use.names' must be TRUE or FALSE") if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") ans <- x@granges if (!use.names) names(ans) <- NULL if (use.mcols) mcols(ans) <- mcols(x) ans } ) setMethod("length", "GNCList", function(x) length(granges(x))) setMethod("names", "GNCList", function(x) names(granges(x))) setMethod("seqnames", "GNCList", function(x) seqnames(granges(x))) setMethod("start", "GNCList", function(x, ...) start(granges(x))) setMethod("end", "GNCList", function(x, ...) end(granges(x))) setMethod("width", "GNCList", function(x) width(granges(x))) setMethod("ranges", "GNCList", function(x, use.names=TRUE, use.mcols=FALSE) ranges(granges(x, use.names=use.names, use.mcols=use.mcols), use.names=TRUE, use.mcols=use.mcols) ) setMethod("strand", "GNCList", function(x) strand(granges(x))) setMethod("seqinfo", "GNCList", function(x) seqinfo(granges(x))) setAs("GNCList", "GRanges", function(from) granges(from, use.mcols=TRUE)) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Constructor ### .extract_groups_from_GenomicRanges <- function(x) splitAsList(seq_along(x) - 1L, seqnames(x)) GNCList <- function(x) { if (!is(x, "GenomicRanges")) stop("'x' must be a GenomicRanges object") if (!is(x, "GRanges")) x <- as(x, "GRanges") ans_mcols <- mcols(x) mcols(x) <- NULL x_groups <- .extract_groups_from_GenomicRanges(x) x_ranges <- IRanges:::.shift_ranges_in_groups_to_first_circle(ranges(x), x_groups, .get_circle_length(x)) ranges(x) <- x_ranges x_nclists <- IRanges:::.nclists(x_ranges, x_groups) new2("GNCList", nclists=x_nclists, granges=x, elementMetadata=ans_mcols, check=FALSE) } setAs("GenomicRanges", "GNCList", function(from) GNCList(from)) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Subsetting ### setMethod("extractROWS", "GNCList", function(x, i) as(callGeneric(as(x, "GRanges"), i), class(x)) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### findOverlaps_GNCList() ### ### NOT exported. findOverlaps_GNCList <- function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "extend", "equal"), select=c("all", "first", "last", "arbitrary", "count"), ignore.strand=FALSE) { if (!(is(query, "GenomicRanges") && is(subject, "GenomicRanges"))) stop("'query' and 'subject' must be GenomicRanges objects") type <- match.arg(type) select <- match.arg(select) if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") si <- merge(seqinfo(query), seqinfo(subject)) q_seqlevels <- seqlevels(query) s_seqlevels <- seqlevels(subject) common_seqlevels <- intersect(q_seqlevels, s_seqlevels) NG <- length(common_seqlevels) q_group_idx <- match(common_seqlevels, q_seqlevels) # of length NG s_group_idx <- match(common_seqlevels, s_seqlevels) # of length NG ## Extract 'q_groups' and 's_groups' (both of length NG). q_groups <- .extract_groups_from_GenomicRanges(query)[q_group_idx] s_groups <- .extract_groups_from_GenomicRanges(subject)[s_group_idx] ## Extract 'nclists' and 'nclist_is_q' (both of length NG). if (is(subject, "GNCList")) { nclists <- subject@nclists[s_group_idx] nclist_is_q <- rep.int(FALSE, NG) } else if (is(query, "GNCList")) { nclists <- query@nclists[q_group_idx] nclist_is_q <- rep.int(TRUE, NG) } else { ## We'll do "on-the-fly preprocessing". nclists <- vector(mode="list", length=NG) nclist_is_q <- rep.int(NA, NG) } ## Extract 'circle_length' (of length NG). circle_length <- .get_circle_length(si)[q_group_idx] ## Extract 'q_space' and 's_space'. if (ignore.strand) { q_space <- s_space <- NULL } else { q_space <- as.integer(strand(query)) - 3L s_space <- as.integer(strand(subject)) - 3L } ## GO! IRanges:::NCList_find_overlaps_in_groups( ranges(query), q_space, q_groups, ranges(subject), s_space, s_groups, nclists, nclist_is_q, maxgap, minoverlap, type, select, circle_length) } GenomicRanges/R/GPos-class.R0000644000175400017540000002575313175713746016652 0ustar00biocbuildbiocbuild### ========================================================================= ### GPos objects ### ------------------------------------------------------------------------- ### setClass("GPos", contains="GRanges", representation( ranges="IPos" ) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Getters ### setMethod("names", "GPos", function(x) NULL) setReplaceMethod("names", "GPos", function(x, value) { if (!is.null(value)) stop(class(x), " objects don't accept names") x } ) setMethod("pos", "GPos", function(x) pos(ranges(x))) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Collapse runs of "stitchable genomic ranges" ### ### 2 genomic ranges are "stitchable" if, in addition to be stitchable from ### an integer ranges point-of-view (see stitch_Ranges() in ### IRanges/R/IPos-class.R for what that means), they are also on the same ### chromosome and strand. ### stitch_GenomicRanges() below takes any GenomicRanges derivative and ### returns a GRanges object (so is NOT an endomorphism). ### Note that this transformation preserves 'sum(width(x))'. ### Also note that this is an "inter range transformation". However unlike ### range(), reduce(), gaps(), or disjoin(), its result depends on the order ### of the elements in the input vector. It's also idempotent like range(), ### reduce(), and disjoin() (gaps() is not). ### TODO: Define and export stitch() generic and method for Ranges objects ### in the IRanges package (in inter-range-methods.R). Then make ### stitch_GenomicRanges() and stitch_GPos() the "stitch" methods for ### GenomicRanges and GPos objects, respectively, and support the ### 'ignore.strand' argument. ### To be as fast as possible, we don't use internal low-level constructor ### new_GRanges() and we don't check the new object. .new_stitched_GRanges <- function(seqnames, ranges, strand, seqinfo) { mcols <- S4Vectors:::make_zero_col_DataFrame(length(ranges)) new2("GRanges", seqnames=seqnames, ranges=ranges, strand=strand, elementMetadata=mcols, seqinfo=seqinfo, check=FALSE) } stitch_GenomicRanges <- function(x) { if (length(x) == 0L) return(granges(x, use.names=FALSE)) # returning GRanges() would loose # the seqinfo x_seqnames <- seqnames(x) x_strand <- strand(x) x_start <- start(x) x_end <- end(x) ## Find runs of stitchable elements along 'x'. ## Each run is described by the indices of its first ('run_from') and ## last ('run_to') elements in 'x'. ## The runs form a partitioning of 'x'. is_new_run <- x_seqnames[-1L] != x_seqnames[-length(x)] | x_strand[-1L] != x_strand[-length(x)] | Rle(x_start[-1L] != x_end[-length(x)] + 1L) new_run_idx <- which(is_new_run) run_from <- c(1L, new_run_idx + 1L) run_to <- c(new_run_idx, length(x)) ans_ranges <- IRanges(x_start[run_from], x_end[run_to]) ans_seqnames <- x_seqnames[run_from] # same as x_seqnames[run_to] ans_strand <- x_strand[run_from] # same as x_strand[run_to] .new_stitched_GRanges(ans_seqnames, ans_ranges, ans_strand, seqinfo(x)) } stitch_GPos <- function(x) { if (length(x) == 0L) return(granges(x, use.names=FALSE)) # returning GRanges() would loose # the seqinfo x_seqnames <- seqnames(x) x_strand <- strand(x) ## Find runs of identical (seqnames, strand) pairs along 'x'. ## The runs are described by IRanges object 'runs'. ## They form a partitioning of 'x'. is_new_run <- x_seqnames[-1L] != x_seqnames[-length(x)] | x_strand[-1L] != x_strand[-length(x)] new_run_idx <- which(is_new_run) run_from <- c(1L, new_run_idx + 1L) run_to <- c(new_run_idx, length(x)) runs <- IRanges(run_from, run_to) ans_ranges <- IRanges:::extract_pos_runs_by_ranges(x@ranges@pos_runs, runs) breakpoints <- cumsum(width(ans_ranges)) ans_seqnames <- x_seqnames[breakpoints] ans_strand <- x_strand[breakpoints] .new_stitched_GRanges(ans_seqnames, ans_ranges, ans_strand, seqinfo(x)) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Validity ### ### TODO ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Constructor ### ### Note that if 'pos_runs' is a GPos instance with no metadata or metadata ### columns, then 'identical(GPos(pos_runs), pos_runs)' is TRUE. GPos <- function(pos_runs=GRanges()) { if (!is(pos_runs, "GenomicRanges")) pos_runs <- as(pos_runs, "GenomicRanges", strict=FALSE) suppressWarnings(ans_len <- sum(width(pos_runs))) if (is.na(ans_len)) stop("too many genomic positions in 'pos_runs'") ans_seqnames <- rep.int(seqnames(pos_runs), width(pos_runs)) ans_ranges <- IPos(ranges(pos_runs)) ans_strand <- rep.int(strand(pos_runs), width(pos_runs)) ans_mcols <- S4Vectors:::make_zero_col_DataFrame(ans_len) new2("GPos", seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, seqinfo=seqinfo(pos_runs), check=FALSE) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion ### .from_GRanges_to_GPos <- function(from) { if (!all(width(from) == 1L)) stop(wmsg("all the ranges in the object to coerce to GPos ", "must have a width of 1")) if (!is.null(names(from))) { names(from) <- NULL warning(wmsg("because a GPos object cannot hold them, the names ", "on the object to coerce to GPos couldn't be ", "propagated by the coercion")) } class(from) <- "GPos" # temporarily broken GRanges instance! from@ranges <- as(from@ranges, "IPos") # now fixed :-) from } setAs("GRanges", "GPos", .from_GRanges_to_GPos) setAs("ANY", "GPos", function(from) .from_GRanges_to_GPos(as(from, "GRanges"))) ### Because we implemented the 'strict' argument we cannot use setAs(). ### 'to' is ignored but we must have it in the signature otherwise the call ### to setMethod("coerce") below will complain. .from_GPos_to_GRanges <- function(from, to="GRanges", strict=TRUE) { if (!isTRUEorFALSE(strict)) stop("'strict' must be TRUE or FALSE") if (!strict) return(from) class(from) <- "GRanges" # temporarily broken GRanges instance! from@ranges <- as(from@ranges, "IRanges") # now fixed :-) from } #setAs("GPos", "GRanges", .from_GPos_to_GRanges) setMethod("coerce", c("GPos", "GRanges"), .from_GPos_to_GRanges) ### The "as.data.frame" method for GenomicRanges objects works on a GPos ### object but returns a data.frame with identical "start" and "end" columns, ### and a "width" column filled with 1. We overwrite it to return a data.frame ### with a "pos" column instead of the "start" and "end" columns, and no ### "width" column. ### TODO: Turn this into an S3/S4 combo for as.data.frame.GPos setMethod("as.data.frame", "GPos", function(x, row.names=NULL, optional=FALSE, ...) { mcols_df <- as.data.frame(mcols(x), ...) data.frame(seqnames=as.factor(seqnames(x)), pos=pos(x), strand=as.factor(strand(x)), mcols_df, stringsAsFactors=FALSE) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### updateObject() ### ### Internal representation of GPos objects has changed in GenomicRanges ### 1.29.10 (Bioc 3.6). ### .get_GPos_version <- function(object) { if (.hasSlot(object, "pos_runs")) "< 1.29.10" else "current" } setMethod("updateObject", "GPos", function(object, ..., verbose=FALSE) { version <- .get_GPos_version(object) if (version == "current") { if (verbose) message("[updateObject] Internal representation of ", class(object), " object is current.\n", "[updateObject] Nothing to update.") return(object) } if (verbose) message("[updateObject] ", class(object), " object uses ", "internal representation from GenomicRanges\n", "[updateObject] ", version, ". Updating it ...") object <- GPos(object@pos_runs) metadata(object) <- metadata(object) object } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Show ### .make_naked_matrix_from_GPos <- function(x) { x_len <- length(x) x_mcols <- mcols(x) x_nmc <- if (is.null(x_mcols)) 0L else ncol(x_mcols) ans <- cbind(seqnames=as.character(seqnames(x)), pos=as.character(pos(x)), strand=as.character(strand(x))) if (x_nmc > 0L) { tmp <- do.call(data.frame, c(lapply(x_mcols, showAsCell), list(check.names=FALSE))) ans <- cbind(ans, `|`=rep.int("|", x_len), as.matrix(tmp)) } ans } show_GPos <- function(x, margin="", print.classinfo=FALSE, print.seqinfo=FALSE) { version <- .get_GPos_version(x) if (version != "current") stop(class(x), " object uses internal representation from ", "GenomicRanges ", version, "\n and cannot be displayed or ", "used. Please update it with:\n", " x <- updateObject(x, verbose=TRUE)") x_class <- class(x) x_len <- length(x) x_mcols <- mcols(x) x_nmc <- if (is.null(x_mcols)) 0L else ncol(x_mcols) cat(x_class, " object with ", x_len, " ", ifelse(x_len == 1L, "position", "positions"), " and ", x_nmc, " metadata ", ifelse(x_nmc == 1L, "column", "columns"), ":\n", sep="") ## S4Vectors:::makePrettyMatrixForCompactPrinting() assumes that head() ## and tail() work on 'xx'. xx <- as(x, "GPos") out <- S4Vectors:::makePrettyMatrixForCompactPrinting(xx, .make_naked_matrix_from_GPos) if (print.classinfo) { .COL2CLASS <- c( seqnames="Rle", pos="integer", strand="Rle" ) classinfo <- S4Vectors:::makeClassinfoRowForCompactPrinting(x, .COL2CLASS) ## A sanity check, but this should never happen! stopifnot(identical(colnames(classinfo), colnames(out))) out <- rbind(classinfo, out) } if (nrow(out) != 0L) rownames(out) <- paste0(margin, rownames(out)) ## We set 'max' to 'length(out)' to avoid the getOption("max.print") ## limit that would typically be reached when 'showHeadLines' global ## option is set to Inf. print(out, quote=FALSE, right=TRUE, max=length(out)) if (print.seqinfo) { cat(margin, "-------\n", sep="") cat(margin, "seqinfo: ", summary(seqinfo(x)), "\n", sep="") } } setMethod("show", "GPos", function(object) show_GPos(object, margin=" ", print.classinfo=TRUE, print.seqinfo=TRUE) ) GenomicRanges/R/GRanges-class.R0000644000175400017540000003727213175713746017327 0ustar00biocbuildbiocbuild### ========================================================================= ### GRanges objects ### ------------------------------------------------------------------------- ### setClassUnion("IRanges_OR_IPos", c("IRanges", "IPos")) setClass("GRanges", contains="GenomicRanges", representation( seqnames="Rle", ranges="IRanges_OR_IPos", # an IPos only for GPos strand="Rle", elementMetadata="DataFrame", seqinfo="Seqinfo" ), prototype( seqnames=Rle(factor()), strand=Rle(strand()) ) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### "update" method ### ### Having update() redirect to BiocGenerics:::replaceSlots() on GRanges ### objects makes all the methods for GenomicRanges objects defined in ### R/GenomicRanges-class.R work on GRanges objects. setMethod("update", "GRanges", function(object, ...) BiocGenerics:::replaceSlots(object, ...) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Validity ### .valid.GRanges.ranges <- function(x) { if (!is.null(x@ranges@elementMetadata)) return("slot 'ranges' cannot have metadata columns") NULL } .valid.GRanges.mcols <- function(x) { x_mcols <- x@elementMetadata if (!is.null(rownames(x_mcols))) return("'mcols(x)' cannot have row names") NULL } .valid.GRanges <- function(x) { c(.valid.GRanges.ranges(x), .valid.GRanges.mcols(x)) } setValidity2("GRanges", .valid.GRanges) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Constructor ### .set_strand_mcols_seqinfo <- function(x, strand=NULL, mcols=NULL, seqlengths=NULL, seqinfo=NULL) { if (is.null(strand)) { x_strand <- strand(x) } else { x_strand <- strand } if (length(mcols) == 0L) { x_mcols <- mcols(x) } else { x_mcols <- mcols } if (is.null(seqlengths)) { x_seqlengths <- seqlengths(x) } else { x_seqlengths <- seqlengths } if (is.null(seqinfo)) { x_seqinfo <- seqinfo(x) } else { x_seqinfo <- seqinfo } new_GRanges(class(x), seqnames(x), ranges(x), x_strand, x_mcols, x_seqlengths, x_seqinfo) } ### Internal low-level constructor. Shared with other GRanges-like objects. new_GRanges <- function(Class, seqnames=NULL, ranges=NULL, strand=NULL, mcols=NULL, seqlengths=NULL, seqinfo=NULL) { if (is.null(ranges)) { if (!is.null(seqnames)) { x <- as(seqnames, Class) return(.set_strand_mcols_seqinfo(x, strand, mcols, seqlengths, seqinfo)) } ranges <- IRanges() } else { ranges <- as(ranges, "IRanges") } if (is.null(seqnames)) { seqnames <- Rle() } else { if (!is(seqnames, "Rle")) seqnames <- Rle(seqnames) if (!is.factor(runValue(seqnames))) runValue(seqnames) <- factor(runValue(seqnames), levels=unique(runValue(seqnames))) } if (is.null(strand)) { strand <- Rle(strand("*"), length(seqnames)) } else { if (!is(strand, "Rle")) strand <- Rle(strand) if (!is.factor(runValue(strand)) || !identical(levels(runValue(strand)), levels(strand()))) runValue(strand) <- strand(runValue(strand)) if (S4Vectors:::anyMissing(runValue(strand))) { warning("missing values in strand converted to \"*\"") runValue(strand)[is.na(runValue(strand))] <- "*" } } lx <- max(length(seqnames), length(ranges), length(strand)) if (lx > 1) { if (length(seqnames) == 1) seqnames <- rep(seqnames, lx) if (length(ranges) == 1) ranges <- rep(ranges, lx) if (length(strand) == 1) strand <- rep(strand, lx) } if (is.null(seqlengths)) seqlengths <- setNames(rep(NA_integer_, length(levels(seqnames))), levels(seqnames)) if (is.null(seqinfo)) seqinfo <- Seqinfo(names(seqlengths), seqlengths) ## in case we have seqlengths for unrepresented sequences runValue(seqnames) <- factor(runValue(seqnames), levels=seqnames(seqinfo)) ranges_mcols <- mcols(ranges) if (!is.null(ranges_mcols)) mcols(ranges) <- NULL ## Normalize 'mcols'. if (length(mcols) == 0L) { mcols <- ranges_mcols if (is.null(mcols)) mcols <- DataFrame() } else if (!is(mcols, "DataFrame")) { stop("'mcols' must be a DataFrame object") } if (nrow(mcols) == 0L && ncol(mcols) == 0L) { mcols <- S4Vectors:::make_zero_col_DataFrame(length(ranges)) } else if (!is.null(rownames(mcols))) { if (is.null(names(ranges))) names(ranges) <- rownames(mcols) rownames(mcols) <- NULL } new(Class, seqnames=seqnames, ranges=ranges, strand=strand, elementMetadata=mcols, seqinfo=seqinfo) } GRanges <- function(seqnames=NULL, ranges=NULL, strand=NULL, ..., seqlengths=NULL, seqinfo=NULL) { mcols <- DataFrame(..., check.names=FALSE) new_GRanges("GRanges", seqnames=seqnames, ranges=ranges, strand=strand, mcols=mcols, seqlengths=seqlengths, seqinfo=seqinfo) } setMethod("updateObject", "GRanges", function(object, ..., verbose=FALSE) { if (verbose) message("updateObject(object = 'GRanges')") if (is(try(object@seqinfo, silent=TRUE), "try-error")) { object <- new(class(object), seqnames = object@seqnames, ranges = object@ranges, strand = object@strand, elementMetadata = object@elementMetadata, metadata = object@metadata, seqinfo = Seqinfo(seqnames = names(object@seqlengths), seqlengths = object@seqlengths)) return(object) } if (is(try(validObject(object@seqinfo, complete=TRUE), silent=TRUE), "try-error")) { object@seqinfo <- updateObject(object@seqinfo) return(object) } object } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Accessors ### setMethod("seqnames", "GRanges", function(x) x@seqnames) setMethod("strand", "GRanges", function(x) x@strand) setMethod("seqinfo", "GRanges", function(x) x@seqinfo) ### Range squeezer. setMethod("ranges", "GRanges", function(x, use.names=TRUE, use.mcols=FALSE) { if (!isTRUEorFALSE(use.names)) stop("'use.names' must be TRUE or FALSE") if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") ans <- x@ranges if (!use.names) names(ans) <- NULL if (use.mcols) mcols(ans) <- mcols(x) ans } ) ### Genomic range squeezer. setMethod("granges", "GenomicRanges", function(x, use.names=TRUE, use.mcols=FALSE) { if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") ans <- GRanges(seqnames(x), ranges(x, use.names=use.names), strand(x), seqinfo=seqinfo(x)) if (use.mcols) mcols(ans) <- cbind(extraColumnSlotsAsDF(x), mcols(x)) ans } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion ### setAs("GenomicRanges", "GRanges", function(from) granges(from, use.mcols=TRUE) ) .from_character_to_GRanges <- function(from) { stopifnot(is.character(from)) if (anyNA(from)) stop(wmsg("converting a character vector to a GRanges object ", "does not support NAs")) error_msg <- wmsg( "The character vector to convert to a GRanges object must contain ", "strings of the form \"chr:start-end\" or \"chr:start-end:strand\", ", "with end >= start - 1, or \"chr:pos\" or \"chr:pos:strand\". ", "For example: \"chr1:2501-2900\", \"chr1:2501-2900:+\", or ", "\"chr1:740\". Note that \"..\" is a valid alternate start/end ", "separator. Strand can be \"+\", \"-\", \"*\", or missing." ) split0 <- CharacterList(strsplit(from, ":", fixed=TRUE)) split0_eltNROWS <- elementNROWS(split0) if (S4Vectors:::anyMissingOrOutside(split0_eltNROWS, 2L, 3L)) stop(error_msg) ans_strand <- as.character(ptail(split0, n=-2L)) ans_strand[is.na(ans_strand)] <- "*" split1 <- phead(split0, n=2L) ans_seqnames <- as.character(phead(split1, n=1L)) ranges <- ptail(split1, n=-1L) ranges <- setNames(as.character(ranges), names(ranges)) ans_ranges <- try(as(ranges, "IRanges"), silent=TRUE) if (is(ans_ranges, "try-error")) stop(error_msg) GRanges(ans_seqnames, ans_ranges, ans_strand) } setAs("character", "GRanges", .from_character_to_GRanges) .from_factor_to_GRanges <- function(from) { from <- setNames(as.character(from), names(from)) .from_character_to_GRanges(from) } setAs("factor", "GRanges", .from_factor_to_GRanges) ### Does NOT propagate the ranges names and metadata columns i.e. always ### returns an unnamed GRanges object with no metadata columns. setAs("RangesList", "GRanges", function(from) { if (!length(from)) return(GRanges()) from <- as(from, "CompressedIRangesList") ranges <- unlist(from, use.names=FALSE) ranges <- IRanges(start=start(ranges), width=width(ranges)) ## From now, ranges is guaranteed to be an IRanges *instance*. if (is.null(space(from))) { stop("Cannot create GRanges when 'space(from)' is NULL") } gr <- GRanges(seqnames = space(from), ranges = ranges, strand = Rle("*", length(ranges))) seqinfo(gr) <- seqinfo(from) metadata(gr) <- metadata(from) gr }) setAs("RangedData", "GRanges", function(from) { ans_ranges <- unlist(ranges(from), use.names=FALSE) ans_mcols <- unlist(values(from), use.names=FALSE) rownames(ans_mcols) <- NULL whichStrand <- match("strand", colnames(ans_mcols)) if (is.na(whichStrand)) { ans_strand <- Rle(strand("*"), length(ans_ranges)) } else { ans_strand <- Rle(strand(from)) ans_mcols <- ans_mcols[-whichStrand] } ans <- GRanges(seqnames=space(from), ranges=ans_ranges, strand=ans_strand, ans_mcols, seqinfo=seqinfo(from)) metadata(ans) <- metadata(from) ans } ) .from_Seqinfo_to_GRanges <- function(from) { if (anyNA(seqlengths(from))) stop(wmsg("cannot create a GRanges object ", "from a Seqinfo object with NA seqlengths")) GRanges(seqnames(from), IRanges(rep.int(1L, length(from)), width=seqlengths(from), names=seqnames(from)), seqinfo=from) } setAs("Seqinfo", "GRanges", .from_Seqinfo_to_GRanges) setAs("Seqinfo", "RangesList", function(from) as(as(from, "GRanges"), "RangesList") ) setAs("ANY", "GenomicRanges", function(from) as(from, "GRanges")) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Subsetting ### .DollarNames.GRanges <- .DollarNames.GenomicRanges setMethod("extractROWS", "GRanges", function(x, i) { if (missing(i) || !is(i, "Ranges")) i <- normalizeSingleBracketSubscript(i, x) ans_seqnames <- extractROWS(seqnames(x), i) ans_ranges <- extractROWS(ranges(x), i) ans_strand <- extractROWS(strand(x), i) ans_mcols <- extractROWS(mcols(x), i) ans_ecs <- lapply(extraColumnSlots(x), extractROWS, i) BiocGenerics:::replaceSlots(x, seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, .slotList=ans_ecs, check=FALSE) } ) setMethod("replaceROWS", "GRanges", function(x, i, value) { if (missing(i) || !is(i, "Ranges")) i <- normalizeSingleBracketSubscript(i, x) seqinfo(x) <- merge(seqinfo(x), seqinfo(value)) ans_seqnames <- replaceROWS(seqnames(x), i, seqnames(value)) ans_ranges <- replaceROWS(ranges(x), i, ranges(value)) ans_strand <- replaceROWS(strand(x), i, strand(value)) ans_mcols <- replaceROWS(mcols(x), i, mcols(value)) ans_ecs_names <- extraColumnSlotNames(x) ans_necs <- length(ans_ecs_names) if (ans_necs == 0L) { ans_ecs <- NULL } else { value_ecs_names <- extraColumnSlotNames(value) if (!identical(value_ecs_names[seq_len(ans_necs)], ans_ecs_names)) stop("'value' can have more extra column slots but not less") ans_ecs <- extraColumnSlotsAsDF(x) value_ecs <- extraColumnSlotsAsDF(value) ans_ecs <- replaceROWS(ans_ecs, i, value_ecs[seq_len(ans_necs)]) } BiocGenerics:::replaceSlots(x, seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, .slotList=as.list(ans_ecs)) } ) ### TODO: Refactor to use replaceROWS(). This will make the code much simpler ### and avoid a lot of duplication with the above "replaceROWS" method. setReplaceMethod("[", "GRanges", function(x, i, j, ..., value) { if (!is(value, "GenomicRanges")) stop("replacement value must be a GenomicRanges object") seqinfo(x) <- merge(seqinfo(x), seqinfo(value)) seqnames <- seqnames(x) ranges <- ranges(x) strand <- strand(x) ans_mcols <- mcols(x, FALSE) value_ecs <- extraColumnSlotsAsDF(value) x_ecs <- extraColumnSlotsAsDF(x) new_ecs <- value_ecs[!names(value_ecs) %in% names(x_ecs)] ecs_to_replace <- intersect(names(value_ecs), names(x_ecs)) if (missing(i)) { seqnames[] <- seqnames(value) ranges[] <- ranges(value) strand[] <- strand(value) if (missing(j)) ans_mcols[ , ] <- mcols(value, FALSE) else ans_mcols[ , j] <- mcols(value, FALSE) if (length(new_ecs) > 0L) ans_mcols[names(new_ecs)] <- new_ecs x_ecs[ecs_to_replace] <- value_ecs[ecs_to_replace] } else { i <- extractROWS(setNames(seq_along(x), names(x)), i) seqnames[i] <- seqnames(value) ranges[i] <- ranges(value) strand[i] <- strand(value) if (missing(j)) ans_mcols[i, ] <- mcols(value, FALSE) else ans_mcols[i, j] <- mcols(value, FALSE) if (length(new_ecs) > 0L) ans_mcols[i, names(new_ecs)] <- DataFrame(new_ecs) if (length(ecs_to_replace) > 0L) { x_ecs[i, ecs_to_replace] <- value_ecs[ecs_to_replace] } } BiocGenerics:::replaceSlots(x, seqnames=seqnames, ranges=ranges, strand=strand, elementMetadata=ans_mcols, .slotList=as.list(x_ecs)) } ) GenomicRanges/R/GRangesList-class.R0000644000175400017540000004616513175713746020164 0ustar00biocbuildbiocbuild### ========================================================================= ### GRangesList objects ### ------------------------------------------------------------------------- ### setClass("GRangesList", contains=c("CompressedList", "GenomicRangesList"), representation( unlistData="GRanges", elementMetadata="DataFrame" ), prototype( elementType="GRanges" ) ) ### Note that rtracklayer also defines GenomicRanges_OR_GenomicRangesList. ### Do we need the 2 union classes? setClassUnion("GenomicRanges_OR_GRangesList", c("GenomicRanges", "GRangesList")) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Validity. ### .valid.GRangesList.mcols <- function(x) { msg <- NULL x_mcols <- x@elementMetadata if (nrow(x_mcols) != length(x)) msg <- "'mcols(x)' has an incorrect number of rows" if (any(c("seqnames", "ranges", "strand", "start", "end", "width", "element") %in% colnames(x_mcols))) msg <- c(msg, paste("'mcols(x)' cannot have columns named \"seqnames\", ", "\"ranges\", \"strand\", \"start\", \"end\", \"width\", ", "or \"element\"")) if (!is.null(rownames(x_mcols))) msg <- c(msg, "'mcols(x)' cannot have row names") msg } .valid.GRangesList <- function(x) { c(.valid.GRangesList.mcols(x)) } setValidity2("GRangesList", .valid.GRangesList) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Constructors. ### GRangesList <- function(...) { listData <- list(...) if (length(listData) == 1L && !is(listData[[1L]], "GRanges")) return(as(listData[[1L]], "GRangesList")) if (length(listData) == 0L) { unlistData <- GRanges() } else { if (!all(sapply(listData, is, "GRanges"))) stop("all elements in '...' must be GRanges objects") unlistData <- suppressWarnings(do.call("c", unname(listData))) } relist(unlistData, listData) } ### Typically, the field values will come from a file that needs to be loaded ### into a data.frame first. makeGRangesListFromFeatureFragments <- function(seqnames=Rle(factor()), fragmentStarts=list(), fragmentEnds=list(), fragmentWidths=list(), strand=character(0), sep=",") { fragmentStarts <- normargListOfIntegers(fragmentStarts, sep, "fragmentStarts") nfrag_per_feature <- elementNROWS(fragmentStarts) start <- unlist(fragmentStarts, recursive=FALSE, use.names=FALSE) fragmentEnds <- normargListOfIntegers(fragmentEnds, sep, "fragmentEnds") nend_per_elt <- elementNROWS(fragmentEnds) if (length(nend_per_elt) != 0L) { if (length(nfrag_per_feature) == 0L) nfrag_per_feature <- nend_per_elt else if (!identical(nend_per_elt, nfrag_per_feature)) stop("'fragmentStarts' and 'fragmentEnds' have ", "incompatible \"shapes\"") } end <- unlist(fragmentEnds, recursive=FALSE, use.names=FALSE) fragmentWidths <- normargListOfIntegers(fragmentWidths, sep, "fragmentWidths") nwidth_per_elt <- elementNROWS(fragmentWidths) if (length(nwidth_per_elt) != 0L) { if (length(nfrag_per_feature) == 0L) nfrag_per_feature <- nwidth_per_elt else if (!identical(nwidth_per_elt, nfrag_per_feature)) stop("\"shape\" of 'fragmentWidths' is incompatible ", "with \"shape\" of 'fragmentStarts' or 'fragmentEnds'") } width <- unlist(fragmentWidths, recursive=FALSE, use.names=FALSE) ranges <- IRanges(start=start, end=end, width=width) nfrag <- sum(nfrag_per_feature) if (nfrag != length(ranges)) stop("GenomicRanges internal error in makeGRangesListFromFields(): ", "nfrag != length(ranges). This should never happen. ", "Please report.") if (nfrag == 0L) { ## Cannot blindly subset by FALSE because it doesn't work on a ## zero-length Rle. if (length(seqnames) != 0L) seqnames <- seqnames[FALSE] if (length(strand) != 0L) strand <- strand[FALSE] } else { if (length(seqnames) != length(nfrag_per_feature) || length(strand) != length(nfrag_per_feature)) stop("length of 'seqnames' and/or 'strand' is incompatible ", "with fragmentStarts/Ends/Widths") seqnames <- rep.int(seqnames, nfrag_per_feature) strand <- rep.int(strand, nfrag_per_feature) } unlistData <- GRanges(seqnames=seqnames, ranges=ranges, strand=strand) partitioning <- PartitioningByEnd(cumsum(nfrag_per_feature), names=NULL) relist(unlistData, partitioning) } setMethod("updateObject", "GRangesList", function(object, ..., verbose=FALSE) { if (verbose) message("updateObject(object = 'GRangesList')") if (is(try(validObject(object@unlistData, complete=TRUE), silent=TRUE), "try-error")) { object@unlistData <- updateObject(object@unlistData) return(object) } object } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Accessors. ### setMethod("seqnames", "GRangesList", function(x) { unlisted_x <- unlist(x, use.names=FALSE) relist(seqnames(unlisted_x), x) } ) ### NOT exported but used in GenomicAlignments package. set_GRangesList_seqnames <- function(x, value) { if (!is(value, "AtomicList") || !identical(elementNROWS(x), elementNROWS(value))) stop("replacement 'value' is not an AtomicList with the same ", "elementNROWS as 'x'") value <- unlist(value, use.names = FALSE) if (!is(value, "Rle")) value <- Rle(factor(value)) else if (!is.factor(runValue(value))) runValue(value) <- factor(runValue(value)) seqnames(x@unlistData) <- value x } setReplaceMethod("seqnames", "GRangesList", set_GRangesList_seqnames) setMethod("ranges", "GRangesList", function(x, use.names=TRUE, use.mcols=FALSE) { if (!isTRUEorFALSE(use.names)) stop("'use.names' must be TRUE or FALSE") if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") unlisted_x <- unlist(x, use.names=FALSE) unlisted_ans <- unlisted_x@ranges if (use.mcols) mcols(unlisted_ans) <- mcols(unlisted_x) ans <- relist(unlisted_ans, x) if (!use.names) names(ans) <- NULL if (use.mcols) mcols(ans) <- mcols(x) ans } ) setReplaceMethod("ranges", "GRangesList", function(x, value) { if (!is(value, "RangesList") || !identical(elementNROWS(x), elementNROWS(value))) stop("replacement 'value' is not a RangesList with the same ", "elementNROWS as 'x'") ranges(x@unlistData) <- as(unlist(value, use.names = FALSE), "IRanges") x } ) ### Same as for CompressedIRangesList. setMethod("start", "GRangesList", function(x, ...) { unlisted_x <- unlist(x, use.names=FALSE) relist(start(unlisted_x), x) } ) setReplaceMethod("start", "GRangesList", function(x, ..., value) { if (!is(value, "IntegerList") || !identical(elementNROWS(x), elementNROWS(value))) stop("replacement 'value' is not an IntegerList with the same ", "elementNROWS as 'x'") value <- unlist(value, use.names = FALSE) start(x@unlistData, ...) <- value x } ) ### Same as for CompressedIRangesList. setMethod("end", "GRangesList", function(x, ...) { unlisted_x <- unlist(x, use.names=FALSE) relist(end(unlisted_x), x) } ) setReplaceMethod("end", "GRangesList", function(x, ..., value) { if (!is(value, "IntegerList") || !identical(elementNROWS(x), elementNROWS(value))) stop("replacement 'value' is not an IntegerList with the same ", "elementNROWS as 'x'") value <- unlist(value, use.names = FALSE) end(x@unlistData, ...) <- value x } ) ### Same as for CompressedIRangesList. setMethod("width", "GRangesList", function(x) { unlisted_x <- unlist(x, use.names=FALSE) relist(width(unlisted_x), x) } ) setReplaceMethod("width", "GRangesList", function(x, ..., value) { if (!is(value, "IntegerList") || !identical(elementNROWS(x), elementNROWS(value))) stop("replacement 'value' is not an IntegerList with the same ", "elementNROWS as 'x'") value <- unlist(value, use.names = FALSE) width(x@unlistData, ...) <- value x } ) setMethod("strand", "GRangesList", function(x) { unlisted_x <- unlist(x, use.names=FALSE) relist(strand(unlisted_x), x) } ) ### NOT exported but used in GenomicAlignments package. set_GRangesList_strand <- function(x, value) { if (!is(value, "AtomicList") || !identical(elementNROWS(x), elementNROWS(value))) stop("replacement 'value' is not an AtomicList with the same ", "elementNROWS as 'x'") value <- unlist(value, use.names = FALSE) if (!is(value, "Rle")) value <- Rle(strand(value)) else if (!is.factor(runValue(value)) || !identical(levels(runValue(value)), levels(strand()))) runValue(value) <- strand(runValue(value)) strand(x@unlistData) <- value x } setReplaceMethod("strand", c("GRangesList", "ANY"), set_GRangesList_strand) setReplaceMethod("strand", c("GRangesList", "character"), function(x, ..., value) { if (length(value) > 1L) stop("length(value) must be 1") strand(x@unlistData) <- value x } ) ### NOT exported but used in GenomicAlignments package. get_GRangesList_mcols <- function(x, use.names=FALSE, level = c("between", "within"), ...) { if (!isTRUEorFALSE(use.names)) stop("'use.names' must be TRUE or FALSE") level <- match.arg(level) if (level == "between") { ans <- x@elementMetadata if (use.names) rownames(ans) <- names(x) return(ans) } unlisted_x <- unlist(x, use.names=FALSE) unlisted_ans <- unlisted_x@elementMetadata if (use.names) rownames(unlisted_ans) <- names(unlisted_x) relist(unlisted_ans, x) } setMethod("elementMetadata", "GRangesList", get_GRangesList_mcols) ### NOT exported but used in GenomicAlignments package. set_GRangesList_mcols <- function(x, level = c("between", "within"), ..., value) { level <- match.arg(level) if (level == "between") { if (is.null(value)) value <- S4Vectors:::make_zero_col_DataFrame(length(x)) else if (!is(value, "DataFrame")) value <- DataFrame(value) if (!is.null(rownames(value))) rownames(value) <- NULL n <- length(x) k <- nrow(value) if (k != n) { if ((k == 0) || (k > n) || (n %% k != 0)) stop(k, " rows in value to replace ", n, "rows") value <- value[rep(seq_len(k), length.out = n), , drop=FALSE] } x@elementMetadata <- value } else { if (is.null(value)) { value <- S4Vectors:::make_zero_col_DataFrame(length(x@unlistData)) } else { if (!is(value, "SplitDataFrameList") || !identical(elementNROWS(x), elementNROWS(value))) { stop("replacement 'value' is not a SplitDataFrameList with ", "the same elementNROWS as 'x'") } value <- unlist(value, use.names = FALSE) } elementMetadata(x@unlistData) <- value } x } setReplaceMethod("elementMetadata", "GRangesList", set_GRangesList_mcols) setMethod("seqinfo", "GRangesList", function(x) seqinfo(x@unlistData)) ### NOT exported but used in GenomicAlignments package. set_GRangesList_seqinfo <- function(x, new2old=NULL, pruning.mode=c("error", "coarse", "fine", "tidy"), value) { pruning.mode <- match.arg(pruning.mode) if (!is(value, "Seqinfo")) stop("the supplied 'seqinfo' must be a Seqinfo object") dangling_seqlevels <- GenomeInfoDb:::getDanglingSeqlevels(x, new2old=new2old, pruning.mode=pruning.mode, seqlevels(value)) if (length(dangling_seqlevels) != 0L) { ## Prune 'x'. non_dangling_range <- !(seqnames(x) %in% dangling_seqlevels) if (pruning.mode == "coarse") { x <- x[all(non_dangling_range)] } else { x <- x[non_dangling_range] # "fine" pruning if (pruning.mode == "tidy") { ## Remove list elements that became empty because of "fine" ## pruning. x <- x[any(non_dangling_range) | elementNROWS(non_dangling_range) == 0L] } } } seqinfo(x@unlistData, new2old=new2old) <- value x } setReplaceMethod("seqinfo", "GRangesList", set_GRangesList_seqinfo) setMethod("score", "GRangesList", function(x) { mcols(x)$score }) setReplaceMethod("score", "GRangesList", function(x, value) { mcols(x)$score <- value x }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion. ### setAs("GRangesList", "CompressedIRangesList", function(from) ranges(from, use.mcols=TRUE) ) setAs("GRangesList", "IRangesList", function(from) ranges(from, use.mcols=TRUE) ) setAs("GRangesList", "RangesList", function(from) ranges(from, use.mcols=TRUE) ) setAs("GRanges", "GRangesList", function(from) as(from, "List")) setAs("list", "GRangesList", function(from) do.call(GRangesList, from)) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Subsetting. ### .sBracketSubsetGRList <- function(x, i, j, ..., drop) { if (!missing(i)) { x <- callNextMethod(x = x, i = i) } if (!missing(j)) { if (!is.character(j)) stop("'j' must be a character vector") withinLevel <- (j %in% colnames(x@unlistData@elementMetadata)) if (any(withinLevel) && !all(withinLevel)) stop("'j' cannot mix between and within metadata column names") if (any(withinLevel)) { mcols(x, level="within") <- mcols(x, level="within")[, j, drop=FALSE] } else { mcols(x) <- mcols(x)[, j, drop=FALSE] } } x } setMethod("[", "GRangesList", .sBracketSubsetGRList) .sBracketReplaceGRList <- function(x, i, j, ..., value) { if (!is(value, class(x)[1])) stop(paste0("replacement value must be a ", class(x)[1], " object")) if (!missing(i)) i <- extractROWS(setNames(seq_along(x), names(x)), i) if (!missing(j)) { if (!is.character(j)) stop("'j' must be a character vector") withinLevel <- (j %in% colnames(x@unlistData@elementMetadata)) if (any(withinLevel) && !all(withinLevel)) stop("'j' cannot mix between and within metadata column names") if (missing(i)) { if (any(withinLevel)) { mcols(x, level="within")[, j] <- mcols(x, level="within") } else { mcols(x)[, j] <- mcols(x) } } else { if (any(withinLevel)) { mcols(x, level="within")[i, j] <- mcols(x, level="within") } else { mcols(x)[i, j] <- mcols(x) } } } callNextMethod(x = x, i = i, value = value) } setReplaceMethod("[", "GRangesList", .sBracketReplaceGRList) .dBracketReplaceGRList <- function(x, i, j, ..., value) { nameValue <- if (is.character(i)) i else "" i <- S4Vectors:::normargSubset2_iOnly(x, i, j, ..., .conditionPrefix=paste0("[[<-,", class(x)[1], "-method: ")) len <- length(x) if (i > len) { value <- list(value) if (nzchar(nameValue)) names(value) <- nameValue x <- c(x, do.call(getFunction(class(x)), value)) } else { x <- callNextMethod(x, i, ..., value=value) } validObject(x) x } setReplaceMethod("[[", "GRangesList", .dBracketReplaceGRList) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Going from GRanges to GRangesList with extractList() and family. ### setMethod("relistToClass", "GRanges", function(x) "GRangesList") ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### show method. ### ### NOT exported but used in GenomicAlignments package. ### FIXME: This seems to repeat most of the code in IRanges:::showRangesList! showList <- function(object, showFunction, print.classinfo) { k <- length(object) cumsumN <- cumsum(elementNROWS(object)) N <- tail(cumsumN, 1) cat(class(object), " object of length ", k, ":\n", sep = "") if (k == 0L) { cat("<0 elements>\n\n") } else if ((k == 1L) || ((k <= 3L) && (N <= 20L))) { nms <- names(object) defnms <- paste0("[[", seq_len(k), "]]") if (is.null(nms)) { nms <- defnms } else { empty <- nchar(nms) == 0L nms[empty] <- defnms[empty] nms[!empty] <- paste0("$", nms[!empty]) } for (i in seq_len(k)) { cat(nms[i], "\n") showFunction(object[[i]], margin=" ", print.classinfo=print.classinfo) if (print.classinfo) print.classinfo <- FALSE cat("\n") } } else { sketch <- function(x) c(head(x, 3), "...", tail(x, 3)) if (k >= 3 && cumsumN[3L] <= 20) showK <- 3 else if (k >= 2 && cumsumN[2L] <= 20) showK <- 2 else showK <- 1 diffK <- k - showK nms <- names(object)[seq_len(showK)] defnms <- paste0("[[", seq_len(showK), "]]") if (is.null(nms)) { nms <- defnms } else { empty <- nchar(nms) == 0L nms[empty] <- defnms[empty] nms[!empty] <- paste0("$", nms[!empty]) } for (i in seq_len(showK)) { cat(nms[i], "\n") showFunction(object[[i]], margin=" ", print.classinfo=print.classinfo) if (print.classinfo) print.classinfo <- FALSE cat("\n") } if (diffK > 0) { cat("...\n<", k - showK, ifelse(diffK == 1, " more element>\n", " more elements>\n"), sep="") } } cat("-------\n") cat("seqinfo: ", summary(seqinfo(object)), "\n", sep="") } setMethod("show", "GRangesList", function(object) { if (is(object@unlistData, "GPos")) showFunction <- show_GPos else showFunction <- show_GenomicRanges showList(object, showFunction, print.classinfo=TRUE) } ) GenomicRanges/R/GenomicRanges-class.R0000644000175400017540000006304313175713746020515 0ustar00biocbuildbiocbuild### ========================================================================= ### The GenomicRanges interface ### ------------------------------------------------------------------------- ### ### TODO: The 'constraint' slot could be moved to the Vector class (or to the ### Annotated class) so any Vector object could be constrained. setClass("GenomicRanges", contains="Vector", representation( "VIRTUAL"#, #No more constraint slot for now... #constraint="Constraint_OR_NULL" ) ) setClassUnion("GenomicRanges_OR_missing", c("GenomicRanges", "missing")) ### The code in this file will work out-of-the-box on 'x' as long as ### seqnames(x), ranges(x), strand(x), seqlengths(x), seqinfo(), ### and update(x) are defined. ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Getters. ### setMethod("length", "GenomicRanges", function(x) length(seqnames(x))) setMethod("names", "GenomicRanges", function(x) names(ranges(x))) #setMethod("constraint", "GenomicRanges", function(x) x@constraint) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Extra column slots (implemented by subclasses) ### extraColumnSlots <- function(x) { sapply(extraColumnSlotNames(x), slot, object = x, simplify = FALSE) } extraColumnSlotsAsDF <- function(x) { ## low-level fast path; otherwise, would need to wrap some things with I() new("DataFrame", listData = extraColumnSlots(x), nrows = length(x)) } setGeneric("extraColumnSlotNames", function(x) standardGeneric("extraColumnSlotNames")) setMethod("extraColumnSlotNames", "ANY", function(x) character()) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 2 low-level helper functions to deal with out-of-bound ranges. ### ### Returns index of out-of-bound ranges located on non-circular sequences ### whose length is not NA. Works on a GenomicRanges or GAlignments object. get_out_of_bound_index <- function(x) { if (length(x) == 0L) return(integer(0)) x_seqnames_id <- as.integer(seqnames(x)) x_seqlengths <- unname(seqlengths(x)) seqlevel_is_circ <- unname(isCircular(x)) %in% TRUE seqlength_is_na <- is.na(x_seqlengths) seqlevel_has_bounds <- !(seqlevel_is_circ | seqlength_is_na) which(seqlevel_has_bounds[x_seqnames_id] & (start(x) < 1L | end(x) > x_seqlengths[x_seqnames_id])) } ### Also works on a GenomicRanges or GAlignments object. Note that GAlignments ### objects are not trimmable so use 'suggest.trim=FALSE' on them. make_out_of_bound_warning_msg <- function(x, idx, suggest.trim) { where <- seqlevels(x)[unique(as.integer(seqnames(x))[idx])] if (length(where) == 1L) { on_what <- paste0("sequence ", where) } else if (length(where) == 2L) { on_what <- paste0("sequences ", where[1L], " and ", where[2L]) } else { seqlevels_in1string <- paste0(head(where, n=-1L), collapse=", ") on_what <- paste0("sequences ", seqlevels_in1string, ", and ", tail(where, n=1L)) } msg <- c(class(x), " object contains ", length(idx), " out-of-bound ", "range", if (length(idx) >= 2L) "s" else "", " located on ", on_what, ". ", "Note that only ranges located on a non-circular ", "sequence whose length is not NA can be considered ", "out-of-bound (use seqlengths() and isCircular() to ", "get the lengths and circularity flags of the underlying ", "sequences).") if (suggest.trim) msg <- c(msg, " You can use trim() to trim these ranges. ", "See ?`trim,GenomicRanges-method` for more information.") msg } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Validity. ### ### TODO: Should we enforce ranges(x) to be an IRanges *instance* (i.e. ### class(ranges(x) == "IRanges")) instead of just an IRanges *object* (i.e. ### is(ranges(x), "IRanges"))? Right now I can create a GRanges object where ### the ranges are a Views object on a very long DNAString subject with ### something like 'GRanges("chr1", Views(subject, start=1:2, end=5))'. ### Sounds cool but there are also some potential complications with this... .valid.GenomicRanges.length <- function(x) { x_len <- length(x) checkCoreGetterReturnedLength <- function(getter) { if (NROW(get(getter)(x)) != x_len) paste0("NROW(", getter, "(x)) != length(x)") } pbs1 <- unlist(lapply(c("seqnames", "ranges", "strand", "mcols"), checkCoreGetterReturnedLength)) checkExtraColumnLength <- function(slotname) { if (NROW(slot(x, slotname)) != x_len) paste0("NROW(x@", slotname, ") != length(x)") } pbs2 <- unlist(lapply(extraColumnSlotNames(x), checkExtraColumnLength)) c(pbs1, pbs2) } ### Used in GenomicAlignments. .valid.GenomicRanges.seqnames <- function(x) { x_seqnames <- seqnames(x) if (!is(x_seqnames, "Rle") || !is.factor(runValue(x_seqnames))) return("'seqnames(x)' must be a 'factor' Rle") if (!is.null(names(x_seqnames))) return("'seqnames(x)' must be a 'factor' Rle with no names") if (S4Vectors:::anyMissing(runValue(x_seqnames))) return("'seqnames(x)' contains missing values") NULL } .valid.GenomicRanges.ranges <- function(x) { if (!(class(ranges(x)) %in% c("IRanges", "IPos"))) return("'ranges(x)' must be an IRanges or IPos instance") NULL } .valid.GenomicRanges.strand <- function(x) { if (!is.factor(runValue(strand(x))) || !identical(levels(runValue(strand(x))), levels(strand()))) { msg <- c("'strand' should be a 'factor' Rle with levels c(", paste0('"', levels(strand()), '"', collapse=", "), ")") return(paste(msg, collapse="")) } if (S4Vectors:::anyMissing(runValue(strand(x)))) return("'strand' contains missing values") NULL } ### NOTE: This list is also included in the man page for GRanges objects. ### Keep the 2 lists in sync! ### We don't put "genome" in that list in order to facilitate import of GFF3 ### files as GRanges objects (see ?import.gff3 in rtracklayer). INVALID.GR.COLNAMES <- c("seqnames", "ranges", "strand", "seqlevels", "seqlengths", "isCircular", #"genome", "start", "end", "width", "element") .valid.GenomicRanges.mcols <- function(x) { if (any(INVALID.GR.COLNAMES %in% colnames(mcols(x)))) { msg <- c("names of metadata columns cannot be one of ", paste0("\"", INVALID.GR.COLNAMES, "\"", collapse=", ")) return(paste(msg, collapse=" ")) } NULL } ### Also used by the validity method for GAlignments objects. valid.GenomicRanges.seqinfo <- function(x, suggest.trim=FALSE) { x_seqinfo <- seqinfo(x) if (!identical(seqlevels(x_seqinfo), levels(seqnames(x)))) { msg <- c("'seqlevels(seqinfo(x))' and 'levels(seqnames(x))'", "are not identical") return(paste(msg, collapse=" ")) } idx <- get_out_of_bound_index(x) if (length(idx) != 0L) { msg <- make_out_of_bound_warning_msg(x, idx, suggest.trim) warning(wmsg(msg)) } NULL } ## For convenience, validate the extra column slots that are virtual ## classes. Since they are not directly constructed, any validity ## checks specific to the virtual class have probably not been called. .valid.GenomicRanges.ecs <- function(x) { virtuals <- Filter(isVirtualClass, getSlots(class(x))[extraColumnSlotNames(x)]) unlist(lapply(names(virtuals), function(nm) validObject(slot(x, nm)))) } .valid.GenomicRanges <- function(x) { c(.valid.GenomicRanges.length(x), .valid.GenomicRanges.seqnames(x), .valid.GenomicRanges.ranges(x), .valid.GenomicRanges.strand(x), .valid.GenomicRanges.mcols(x), valid.GenomicRanges.seqinfo(x, suggest.trim=TRUE), .valid.GenomicRanges.ecs(x)) #checkConstraint(x, constraint(x))) } setValidity2("GenomicRanges", .valid.GenomicRanges) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion. ### ### Propagate the names. setMethod("as.character", "GenomicRanges", function(x, ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop(wmsg("'ignore.strand' must be TRUE or FALSE")) if (length(x) == 0L) return(setNames(character(0), names(x))) ans <- paste0(seqnames(x), ":", as.character(ranges(x))) names(ans) <- names(x) if (ignore.strand) return(ans) x_strand <- strand(x) if (all(x_strand == "*")) return(ans) setNames(paste0(ans, ":", x_strand), names(x)) } ) ### The as.factor() generic doesn't have the ... argument so this method ### cannot support the 'ignore.strand' argument. setMethod("as.factor", "GenomicRanges", function(x) factor(as.character(x), levels=as.character(sort(unique(x)))) ) setAs("GenomicRanges", "Grouping", function(from) { to <- as(grouping(seqnames(from), strand(from), start(from), end(from)), "ManyToOneGrouping") mcols(to)$granges <- granges(from)[end(PartitioningByEnd(to))] to }) setMethod("as.data.frame", "GenomicRanges", function(x, row.names=NULL, optional=FALSE, ...) { ranges <- ranges(x) if (missing(row.names)) row.names <- names(x) if (!is.null(names(x))) names(x) <- NULL mcols_df <- as.data.frame(mcols(x), ...) if (length(extraColumnSlotNames(x)) > 0L) mcols_df <- cbind(as.data.frame(extraColumnSlotsAsDF(x), ...), mcols_df) data.frame(seqnames=as.factor(seqnames(x)), start=start(x), end=end(x), width=width(x), strand=as.factor(strand(x)), mcols_df, row.names=row.names, stringsAsFactors=FALSE) } ) setAs("GenomicRanges", "RangesList", function(from) { strand_mcols <- DataFrame(strand=strand(from), mcols(from)) ecs <- extraColumnSlotsAsDF(from) if (length(ecs)) strand_mcols <- cbind(strand_mcols, ecs) rngs <- ranges(from) mcols(rngs) <- strand_mcols rl <- split(rngs, seqnames(from)) mcols(rl) <- DataFrame(seqlengths=seqlengths(from), isCircular=isCircular(from), genome=genome(from)) metadata(rl) <- metadata(from) metadata(rl)$seqinfo <- seqinfo(from) rl } ) setAs("GenomicRanges", "RangedData", function(from) { mcols <- mcols(from) ecs <- extraColumnSlotsAsDF(from) if (length(ecs)) mcols <- cbind(mcols, ecs) rd <- RangedData(ranges(from), strand=strand(from), mcols, space=seqnames(from)) mcols(ranges(rd)) <- DataFrame(seqlengths=seqlengths(from), isCircular=isCircular(from), genome=genome(from)) metadata(ranges(rd)) <- metadata(from) metadata(ranges(rd))$seqinfo <- seqinfo(from) rd } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Setters. ### setReplaceMethod("names", "GenomicRanges", function(x, value) { names(ranges(x)) <- value x } ) ### Used in GenomicAlignments. .normalize_seqnames_replacement_value <- function(value, x) { if (!is(value, "Rle")) value <- Rle(value) if (!is.factor(runValue(value))) runValue(value) <- factor(runValue(value)) if (!identical(levels(value), seqlevels(x))) stop("levels of supplied 'seqnames' must be ", "identical to 'seqlevels(x)'") S4Vectors:::V_recycle(value, x, x_what="value", skeleton_what="x") } setReplaceMethod("seqnames", "GenomicRanges", function(x, value) { value <- .normalize_seqnames_replacement_value(value, x) update(x, seqnames=value) } ) setReplaceMethod("ranges", "GenomicRanges", function(x, value) { if (class(value) != "IRanges") value <- as(value, "IRanges") mcols(value) <- NULL value <- S4Vectors:::V_recycle(value, x, x_what="value", skeleton_what="x") update(x, ranges=value) } ) setReplaceMethod("strand", "GenomicRanges", function(x, value) { value <- normalize_strand_replacement_value(value, x) x <- update(x, strand=value, check=FALSE) msg <- .valid.GenomicRanges.strand(x) if (!is.null(msg)) stop(msg) x } ) ### Does NOT suppoprt pruning mode "fine". Pruning modes "coarse" and "tidy" ### are equivalent on a GenomicRanges object. set_GenomicRanges_seqinfo <- function(x, new2old=NULL, pruning.mode=c("error", "coarse", "fine", "tidy"), value) { pruning.mode <- match.arg(pruning.mode) if (pruning.mode == "fine") stop(wmsg("\"fine\" pruning mode not supported on ", class(x), " objects")) if (!is(value, "Seqinfo")) stop("the supplied 'seqinfo' must be a Seqinfo object") dangling_seqlevels <- GenomeInfoDb:::getDanglingSeqlevels(x, new2old=new2old, pruning.mode=pruning.mode, seqlevels(value)) if (length(dangling_seqlevels) != 0L) { ## Prune 'x'. non_dangling_range <- !(seqnames(x) %in% dangling_seqlevels) x <- x[non_dangling_range] } old_seqinfo <- seqinfo(x) new_seqnames <- GenomeInfoDb:::makeNewSeqnames(x, new2old=new2old, seqlevels(value)) x <- update(x, seqnames=new_seqnames, seqinfo=value, check=FALSE) geom_has_changed <- GenomeInfoDb:::sequenceGeometryHasChanged( seqinfo(x), old_seqinfo, new2old=new2old) if (any(geom_has_changed, na.rm=TRUE)) { msg <- valid.GenomicRanges.seqinfo(x, suggest.trim=TRUE) if (!is.null(msg)) stop(msg) } x } setReplaceMethod("seqinfo", "GenomicRanges", set_GenomicRanges_seqinfo) setMethod("score", "GenomicRanges", function(x) mcols(x)$score) setReplaceMethod("score", "GenomicRanges", function(x, value) { mcols(x)$score <- value x }) #setReplaceMethod("constraint", "GenomicRanges", # function(x, value) # { # if (isSingleString(value)) # value <- new(value) # if (!is(value, "Constraint_OR_NULL")) # stop("the supplied 'constraint' must be a ", # "Constraint object, a single string, or NULL") # x@constraint <- value # validObject(x) # x # } #) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Updating and cloning. ### ### An object is either 'update'd in place (usually with a replacement ### method) or 'clone'd (copied), with specified slots/fields overridden. ### For an object with a pure S4 slot representation, these both map to ### initialize. Reference classes will want to override 'update'. Other ### external representations need further customization. setGeneric("clone", function(x, ...) standardGeneric("clone")) # not exported setMethod("clone", "ANY", # not exported function(x, ...) { if (nargs() > 1L) update(x, ...) else x } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Ranges methods. ### setMethod("start", "GenomicRanges", function(x, ...) start(ranges(x))) setMethod("end", "GenomicRanges", function(x, ...) end(ranges(x))) setMethod("width", "GenomicRanges", function(x) width(ranges(x))) setReplaceMethod("start", "GenomicRanges", function(x, ..., value) { new_ranges <- `start<-`(ranges(x), ..., value=value) update(x, ranges=new_ranges, ...) } ) setReplaceMethod("end", "GenomicRanges", function(x, ..., value) { new_ranges <- `end<-`(ranges(x), ..., value=value) update(x, ranges=new_ranges, ...) } ) setReplaceMethod("width", "GenomicRanges", function(x, ..., value) { new_ranges <- `width<-`(ranges(x), ..., value=value) update(x, ranges=new_ranges, ...) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Subsetting. ### ### Needed only because we want to support x[i, j] subsetting. setMethod("[", "GenomicRanges", function(x, i, j, ..., drop) { if (length(list(...)) > 0L) stop("invalid subsetting") if (!missing(i)) x <- extractROWS(x, i) if (missing(j)) return(x) new_mcols <- mcols(x)[ , j, drop=FALSE] clone(x, elementMetadata=new_mcols, check=FALSE) } ) ### Subset a named list-like object *by* a GenomicRanges subscript. ### The returned object 'ans' is as follow: ### (a) 'ans' is parallel to 'gr'. ### (b) 'names(ans)' is identical to 'as.character(seqnames(gr))'. ### (c) 'elementNROWS(ans)' is the same as 'width(gr)'. ### (d) 'class(ans)' is 'relistToClass(x[[1]])' e.g. CompressedRleList if ### 'x' is an RleList object, or DNAStringSet is 'x' is a DNAStringSet ### object. .subset_by_GenomicRanges <- function(x, gr) { if (!(is.list(x) || is(x, "List"))) stop(wmsg("'x' must be a list-like object when subsetting ", "by a GenomicRanges subscript")) x_names <- names(x) if (is.null(x_names)) stop(wmsg("'x' must have names when subsetting ", "by a GenomicRanges subscript")) if (anyDuplicated(x_names)) stop(wmsg("'x' must have unique names when subsetting ", "by a GenomicRanges subscript")) irl <- split(ranges(gr), seqnames(gr), drop=TRUE) seqlevels_in_use <- names(irl) seqlevels2names <- match(seqlevels_in_use, x_names) if (any(is.na(seqlevels2names))) stop(wmsg("when subsetting by a GenomicRanges subscript, the names ", "of the object to subset must contain the seqnames of the ", "subscript")) ## Handle empty case. if (length(gr) == 0L) { if (length(x) != 0L) { x1 <- x[[1L]] } else if (is(x, "CompressedList")) { x1 <- unlist(x, use.names=FALSE) } else { x1 <- new(elementType(x)) } unlisted_ans <- x1[0] ans_partitioning <- PartitioningByEnd(names=character(0)) return(relist(unlisted_ans, ans_partitioning)) } tmp <- lapply(seq_along(seqlevels_in_use), function(i) { seqlevel <- seqlevels_in_use[i] name <- x_names[seqlevels2names[i]] extractList(x[[name]], irl[[seqlevel]]) }) ## Unsplit 'tmp'. ans <- do.call(c, tmp) ans_len <- length(gr) idx <- unlist(split(seq_len(ans_len), seqnames(gr), drop=TRUE)) revidx <- integer(ans_len) revidx[idx] <- seq_len(ans_len) names(ans) <- names(idx) ans <- ans[revidx] ans } setMethod("[", c("List", "GenomicRanges"), function(x, i, j, ..., drop=TRUE) { if (!missing(j) || length(list(...)) > 0L) stop("invalid subsetting") .subset_by_GenomicRanges(x, i) } ) setMethod("[", c("list", "GenomicRanges"), function(x, i, j, ..., drop=TRUE) { if (!missing(j) || length(list(...)) > 0L) stop("invalid subsetting") .subset_by_GenomicRanges(x, i) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### $ and $<- methods ### ### Provided as a convenience, for GenomicRanges *only*, and as the result ### of strong popular demand. ### Note that those methods are not consistent with the other $ and $<- ### methods in the IRanges/GenomicRanges infrastructure, and might confuse ### some users by making them believe that a GenomicRanges object can be ### manipulated as a data.frame-like object. ### Therefore we recommend using them only interactively, and we discourage ### their use in scripts or packages. For the latter, use 'mcols(x)$name' ### instead of 'x$name'. ### .DollarNames.GenomicRanges <- function(x, pattern = "") grep(pattern, names(mcols(x)), value=TRUE) setMethod("$", "GenomicRanges", function(x, name) mcols(x)[[name]] ) setReplaceMethod("$", "GenomicRanges", function(x, name, value) {mcols(x)[[name]] <- value; x} ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Combining. ### ### Not exported. 'x' *must* be an unnamed list of length >= 1 (not checked). .unlist_list_of_GenomicRanges <- function(x, ignore.mcols=FALSE) { if (!isTRUEorFALSE(ignore.mcols)) stop("'ignore.mcols' must be TRUE or FALSE") ans_class <- class(x[[1L]]) ans_seqinfo <- do.call(merge, lapply(x, seqinfo)) ans_seqnames <- do.call(c, lapply(x, seqnames)) ans_ranges <- do.call(c, lapply(x, ranges)) ans_strand <- do.call(c, lapply(x, strand)) if (ignore.mcols) { ans_mcols <- S4Vectors:::make_zero_col_DataFrame(length(ans_ranges)) } else { ans_mcols <- do.call(rbind, lapply(x, mcols, FALSE)) } if (length(extraColumnSlotNames(x[[1L]])) > 0L) { ans_ecs <- do.call(rbind, lapply(x, extraColumnSlotsAsDF)) do.call(new, c(list(ans_class, seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, seqinfo=ans_seqinfo), as.list(ans_ecs))) } else { new(ans_class, seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, seqinfo=ans_seqinfo) } } setMethod("c", "GenomicRanges", function(x, ..., ignore.mcols=FALSE, recursive=FALSE) { if (!identical(recursive, FALSE)) stop("'recursive' argument not supported") if (missing(x)) args <- unname(list(...)) else args <- unname(list(x, ...)) .unlist_list_of_GenomicRanges(args, ignore.mcols=ignore.mcols) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Displaying ### .GenomicRanges_summary <- function(object) { object_class <- class(object) object_len <- length(object) object_mcols <- mcols(object) object_nmc <- if (is.null(object_mcols)) 0L else ncol(object_mcols) paste0(object_class, " object with ", object_len, " ", ifelse(object_len == 1L, "range", "ranges"), " and ", object_nmc, " metadata ", ifelse(object_nmc == 1L, "column", "columns")) } ### S3/S4 combo for summary.GenomicRanges summary.GenomicRanges <- function(object, ...) .GenomicRanges_summary(object, ...) setMethod("summary", "GenomicRanges", summary.GenomicRanges) .make_naked_matrix_from_GenomicRanges <- function(x) { x_len <- length(x) x_mcols <- mcols(x) x_nmc <- if (is.null(x_mcols)) 0L else ncol(x_mcols) ans <- cbind(seqnames=as.character(seqnames(x)), ranges=showAsCell(ranges(x)), strand=as.character(strand(x))) extraColumnNames <- extraColumnSlotNames(x) if (length(extraColumnNames) > 0L) { ans <- do.call(cbind, c(list(ans), lapply(extraColumnSlots(x), showAsCell))) } if (x_nmc > 0L) { tmp <- do.call(data.frame, c(lapply(x_mcols, showAsCell), list(check.names=FALSE))) ans <- cbind(ans, `|`=rep.int("|", x_len), as.matrix(tmp)) } ans } ### If 'x' is a GRanges object, 'coerce.internally.to.GRanges' has no effect. ### If it's a GenomicRanges object that is not a GRanges object, then ### show_GenomicRanges() will coerce it to a GRanges object unless ### 'coerce.internally.to.GRanges' is set to FALSE. Use this if coercing 'x' ### to GRanges is not supported or is too expensive but only if 'x' supports ### head() and tail(). show_GenomicRanges <- function(x, margin="", print.classinfo=FALSE, print.seqinfo=FALSE, coerce.internally.to.GRanges=TRUE) { cat(.GenomicRanges_summary(x), ":\n", sep="") ## S4Vectors:::makePrettyMatrixForCompactPrinting() assumes that head() ## and tail() work on 'xx'. if (coerce.internally.to.GRanges) { xx <- as(x, "GRanges", strict=FALSE) } else { xx <- x } out <- S4Vectors:::makePrettyMatrixForCompactPrinting(xx, .make_naked_matrix_from_GenomicRanges) if (print.classinfo) { .COL2CLASS <- c( seqnames="Rle", ranges="IRanges", strand="Rle" ) extraColumnNames <- extraColumnSlotNames(x) .COL2CLASS <- c(.COL2CLASS, getSlots(class(x))[extraColumnNames]) classinfo <- S4Vectors:::makeClassinfoRowForCompactPrinting(x, .COL2CLASS) ## A sanity check, but this should never happen! stopifnot(identical(colnames(classinfo), colnames(out))) out <- rbind(classinfo, out) } if (nrow(out) != 0L) rownames(out) <- paste0(margin, rownames(out)) ## We set 'max' to 'length(out)' to avoid the getOption("max.print") ## limit that would typically be reached when 'showHeadLines' global ## option is set to Inf. print(out, quote=FALSE, right=TRUE, max=length(out)) if (print.seqinfo) { cat(margin, "-------\n", sep="") cat(margin, "seqinfo: ", summary(seqinfo(x)), "\n", sep="") } } setMethod("show", "GenomicRanges", function(object) show_GenomicRanges(object, margin=" ", print.classinfo=TRUE, print.seqinfo=TRUE) ) setMethod("showAsCell", "GenomicRanges", function(object) as.character(object)) GenomicRanges/R/GenomicRanges-comparison.R0000644000175400017540000003177413175713746021570 0ustar00biocbuildbiocbuild### ========================================================================= ### Comparing and ordering genomic ranges ### ------------------------------------------------------------------------- ### ### I. UNIQUE AND DUPLICATED ELEMENTS WITHIN A GenomicRanges OBJECT ### --------------------------------------------------------------- ### Two elements of a GenomicRanges object (i.e. two genomic ranges) are ### considered equal iff they are on the same underlying sequence and strand, ### and have the same start and width. duplicated() and unique() on a ### GenomicRanges object are conforming to this. ### ### II. ORDERING THE ELEMENTS OF A GenomicRanges OBJECT ### --------------------------------------------------- ### The "natural order" for the elements of a GenomicRanges object is to order ### them (a) first by sequence level, (b) then by strand, (c) then by start, ### (d) and finally by width. ### This way, the space of genomic ranges is totally ordered. ### Note that the "reduce" method for GenomicRanges uses this "natural order" ### implicitly. Also, note that, because we already do (c) and (d) for regular ### ranges, genomic ranges that belong to the same underlying sequence ### and strand are ordered like regular ranges. ### is.unsorted(), order(), sort(), and rank() on a GenomicRanges object ### adhere to this "natural order". ### ### III. ELEMENT-WISE (AKA "PARALLEL") COMPARISON OF 2 GenomicRanges OBJECTS ### ------------------------------------------------------------------------ ### We want the "==", "!=", "<=", ">=", "<" and ">" operators between 2 ### GenomicRanges objects to be compatible with the "natural order" defined ### previously. Defining those operators when the 2 objects have *identical* ### seqlevels() is straighforward but we can in fact extend this comparison ### to the following situation: ### (A) 'e1' and 'e2' have compatible sets of underlying sequences, that is, ### 'seqinfo(e1)' and 'seqinfo(e2)' can be merged. ### (B) 'seqlevels(e1)' and 'seqlevels(e2)' are in the same order. Note that ### (A) guarantees that the seqlevels of one is a subset of the seqlevels ### of the other. (B) is saying that this subset should be a subsequence. ### Pre-comparison step: if (A) and (B) are satisfied, then the 2 seqinfo() are ### merged and the seqlevels() of the result is assigned back to each object ### to compare. This is a way to have 2 objects with identical seqlevels() ### before the comparison can actually be performed and meaningful. ### The reason (B) is required for the pre-comparison step is because we want ### this step to preserve the original order of the seqlevels() in *both* ### objects. Without this precaution, the expected anti-symetric property of ### some operators would not be satisfied e.g. 'any(e1 < e2 & e2 < e1)' could ### be TRUE. ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### pcompare() ### ### Doing 'pcompare(x, y)' on 2 vector-like objects 'x' and 'y' of length 1 ### must return an integer less than, equal to, or greater than zero if the ### single element in 'x' is considered to be respectively less than, equal ### to, or greater than the single element in 'y'. ### ### On 2 GenomicRanges objects, it returns one of the 13 predefined codes ### (>= -6 and <= 6) used by the method for Ranges objects when 'x[i]' and ### 'y[i]' are on the same space (i.e. on the same underlying sequence and ### strand). Otherwise, it returns a code that is < -6 if 'x[i] < y[i]', ### and > 6 if 'x[i] > y[i]'. ### See '?pcompare' (in IRanges) for the 13 predefined codes. .pcompare_GenomicRanges <- function(x, y) { ## Pre-comparison step (see above for details). ## merge() will fail if 'x' and 'y' don't have compatible underlying ## sequences. seqinfo <- merge(seqinfo(x), seqinfo(y)) seqlevels <- seqlevels(seqinfo) if (any(diff(match(seqlevels(y), seqlevels)) < 0L)) stop("the 2 objects to compare have seqlevels in incompatible orders") ## This should only insert new seqlevels in the existing ones i.e. it ## should NEVER drop or reorder existing levels seqlevels(x) <- seqlevels(y) <- seqlevels a <- pcompare(ranges(x), ranges(y)) b <- as.integer(strand(x)) - as.integer(strand(y)) c <- as.integer(seqnames(x)) - as.integer(seqnames(y)) ## Note that sign() always returns a numeric vector, even on an integer ## vector. a + 13L * as.integer(sign(b) + 3L * sign(c)) } ### The "pcompare" method. setMethod("pcompare", c("GenomicRanges", "GenomicRanges"), function(x, y) .pcompare_GenomicRanges(x, y) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### duplicated() ### ### unique() will work out-of-the-box on a GenomicRanges object thanks to the ### method for Vector objects. ### .duplicated.GenomicRanges <- function(x, incomparables=FALSE, fromLast=FALSE, nmax = NA, method=c("auto", "quick", "hash")) { if (!identical(incomparables, FALSE)) stop("\"duplicated\" method for GenomicRanges objects ", "only accepts 'incomparables=FALSE'") duplicatedIntegerQuads(as.factor(seqnames(x)), as.factor(strand(x)), start(x), width(x), fromLast=fromLast, method=method) } ### S3/S4 combo for duplicated.GenomicRanges duplicated.GenomicRanges <- function(x, incomparables=FALSE, ...) .duplicated.GenomicRanges(x, incomparables=incomparables, ...) setMethod("duplicated", "GenomicRanges", .duplicated.GenomicRanges) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### match() ### ### %in% will work out-of-the-box on GenomicRanges objects thanks to the ### method for Vector objects. ### setMethod("match", c("GenomicRanges", "GenomicRanges"), function(x, table, nomatch=NA_integer_, incomparables=NULL, method=c("auto", "quick", "hash"), ignore.strand=FALSE) { if (!isSingleNumberOrNA(nomatch)) stop("'nomatch' must be a single number or NA") if (!is.integer(nomatch)) nomatch <- as.integer(nomatch) if (!is.null(incomparables)) stop("\"match\" method for GenomicRanges objects ", "only accepts 'incomparables=NULL'") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") ## Calling merge() is the way to check that 'x' and 'table' are based ## on the same reference genome. merge(seqinfo(x), seqinfo(table)) x_seqnames <- relevelSeqnamesForMatch(x, table) if (ignore.strand) { x_strand <- integer(length(x)) table_strand <- integer(length(table)) } else { x_strand <- as.factor(strand(x)) table_strand <- as.factor(strand(table)) } ## Equivalent to (but faster than): ## findOverlaps(x, table, type="equal", select="first") ## except when 'x' and 'table' both contain empty ranges. matchIntegerQuads(x_seqnames, x_strand, start(x), width(x), as.factor(seqnames(table)), table_strand, start(table), width(table), nomatch=nomatch, method=method) } ) relevelSeqnamesForMatch <- function(x, table) { x_seqnames <- as.factor(seqnames(x)) if (!hasHead(seqlevels(x), seqlevels(table)) && !hasHead(seqlevels(table), seqlevels(x))) { x_seqnames <- factor(x_seqnames, union(seqlevels(table), seqlevels(x))) } x_seqnames } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### selfmatch() ### setMethod("selfmatch", "GenomicRanges", function(x, method=c("auto", "quick", "hash"), ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") x_seqnames <- as.factor(seqnames(x)) if (ignore.strand) { x_strand <- integer(length(x)) } else { x_strand <- as.factor(strand(x)) } selfmatchIntegerQuads(x_seqnames, x_strand, start(x), width(x), method=method) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### order() and related methods. ### ### is.unsorted(), order(), sort(), rank() on GenomicRanges derivatives are ### consistent with the order implied by pcompare(). ### is.unsorted() is a quick/cheap way of checking whether a GenomicRanges ### derivative is already sorted, e.g., called prior to a costly sort. ### .GenomicRanges_as_IntegerQuads <- function(x, ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE of FALSE") a <- S4Vectors:::decodeRle(seqnames(x)) if (ignore.strand) { b <- integer(length(x)) } else { b <- S4Vectors:::decodeRle(strand(x)) } c <- start(x) d <- width(x) list(a, b, c, d) } setMethod("is.unsorted", "GenomicRanges", function(x, na.rm=FALSE, strictly=FALSE, ignore.strand=FALSE) { if (!identical(na.rm, FALSE)) warning("\"is.unsorted\" method for GenomicRanges objects ", "ignores the 'na.rm' argument") if (!isTRUEorFALSE(strictly)) stop("'strictly' must be TRUE of FALSE") ## It seems that creating the integer quads below is faster when ## 'x' is already sorted (TODO: Investigate why). Therefore, and ## somewhat counterintuitively, is.unsorted() can be faster when 'x' ## is already sorted (which, in theory, is the worst-case scenario ## because S4Vectors:::sortedIntegerQuads() will then need to take a ## full walk on 'x') than when it is unsorted (in which case ## S4Vectors:::sortedIntegerQuads() might stop walking on 'x' after ## checking its first 2 elements only -- the best-case scenario). quads <- .GenomicRanges_as_IntegerQuads(x, ignore.strand) !S4Vectors:::sortedIntegerQuads(quads[[1L]], quads[[2L]], quads[[3L]], quads[[4L]], strictly=strictly) } ) ### NOT exported but used in GenomicAlignments package. order_GenomicRanges <- function(x, decreasing=FALSE, ignore.strand=FALSE) { if (!isTRUEorFALSE(decreasing)) stop("'decreasing' must be TRUE or FALSE") quads <- .GenomicRanges_as_IntegerQuads(x, ignore.strand) orderIntegerQuads(quads[[1L]], quads[[2L]], quads[[3L]], quads[[4L]], decreasing=decreasing) } ### TODO: Support the 'ignore.strand' argument (the signature of the order() ### generic doesn't make this as straightforward as it could be). ### 'na.last' is pointless (GenomicRanges objects don't contain NAs) so is ### ignored. ### 'method' is also ignored at the moment. setMethod("order", "GenomicRanges", function(..., na.last=TRUE, decreasing=FALSE, method=c("auto", "shell", "radix")) { ## Turn off this warning for now since it triggers spurious warnings ## when calling sort() on a GRangesList object. The root of the ## problem is inconsistent defaults for 'na.last' between order() and ## sort(), as reported here: ## https://stat.ethz.ch/pipermail/r-devel/2015-November/072012.html #if (!identical(na.last, TRUE)) # warning("\"order\" method for GenomicRanges objects ", # "ignores the 'na.last' argument") if (!isTRUEorFALSE(decreasing)) stop("'decreasing' must be TRUE or FALSE") ## All arguments in '...' are guaranteed to be GenomicRanges objects. args <- list(...) if (length(args) == 1L) return(order_GenomicRanges(args[[1L]], decreasing)) order_args <- c(unlist(lapply(args, .GenomicRanges_as_IntegerQuads), recursive=FALSE, use.names=FALSE), list(na.last=na.last, decreasing=decreasing)) do.call(order, order_args) } ) ### S3/S4 combo for sort.GenomicRanges .sort.GenomicRanges <- function(x, decreasing=FALSE, ignore.strand=FALSE, by) { if (missing(by)) { oo <- order_GenomicRanges(x, decreasing, ignore.strand) } else { if (!identical(ignore.strand, FALSE)) warning("'ignore.strand' ignored when 'by' is specified") oo <- S4Vectors:::orderBy(by, x, decreasing=decreasing) } extractROWS(x, oo) } sort.GenomicRanges <- function(x, decreasing=FALSE, ...) .sort.GenomicRanges(x, decreasing=decreasing, ...) setMethod("sort", "GenomicRanges", .sort.GenomicRanges) setMethod("rank", "GenomicRanges", function(x, na.last=TRUE, ties.method=c("average", "first", "last", "random", "max", "min"), ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE of FALSE") if (ignore.strand) x <- unstrand(x) callNextMethod(x, na.last=na.last, ties.method=ties.method) } ) GenomicRanges/R/GenomicRangesList-class.R0000644000175400017540000000147713175713746021354 0ustar00biocbuildbiocbuild### ========================================================================= ### GenomicRangesList objects ### ------------------------------------------------------------------------- ### ### A List of GenomicRanges objects. Subclasses not necessarily have the same ### "compound" semantics as GRangesList. ### setClass("GenomicRangesList", prototype = prototype(elementType = "GenomicRanges"), contains = "List") setClass("SimpleGenomicRangesList", contains = c("GenomicRangesList", "SimpleList")) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Constructor. ### GenomicRangesList <- function(...) { args <- list(...) if (length(args) == 1 && is.list(args[[1]])) args <- args[[1]] S4Vectors:::new_SimpleList_from_list("SimpleGenomicRangesList", args) } GenomicRanges/R/RangedData-methods.R0000644000175400017540000000215213175713746020316 0ustar00biocbuildbiocbuild### ========================================================================= ### RangedData/RangesList implementation of the GenomicRanges API ### ------------------------------------------------------------------------- ### ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### seqinfo ### setMethod("seqinfo", "List", function(x) { si <- metadata(x)$seqinfo if (is.null(si)) { sn <- names(x) if (is.null(sn)) sn <- as.character(seq_len(length(x))) si <- Seqinfo(unique(sn)) } si }) ### FIXME: needs sanity checks setReplaceMethod("seqinfo", "List", function(x, value) { metadata(x)$seqinfo <- value x }) setMethod("seqinfo", "RangedData", function(x) seqinfo(ranges(x))) setReplaceMethod("seqinfo", "RangedData", function(x, value) { seqinfo(ranges(x)) <- value x }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### seqnames ### setMethod("seqnames", "RangedData", function(x) space(x)) GenomicRanges/R/absoluteRanges.R0000644000175400017540000001210713175713746017642 0ustar00biocbuildbiocbuild### ========================================================================= ### absoluteRanges() & related ### ------------------------------------------------------------------------- ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### isSmallGenome() ### ### TODO: Maybe this could be re-used in tileGenome(). normarg_seqlengths <- function(seqlengths) { if (!is.numeric(seqlengths)) stop(wmsg("'seqlengths' must be a non-empty numeric vector")) if (length(seqlengths) == 0L) return(setNames(integer(0), character(0))) seqlengths_names <- names(seqlengths) if (is.null(seqlengths_names)) stop(wmsg("'seqlengths' must be named")) if (any(seqlengths_names %in% c(NA_character_, ""))) stop(wmsg("'seqlengths' has names that are NA or the empty string")) if (any(duplicated(seqlengths_names))) stop(wmsg("'seqlengths' has duplicated names")) if (!is.integer(seqlengths)) seqlengths <- setNames(as.integer(seqlengths), seqlengths_names) if (any(seqlengths < 0L, na.rm=TRUE)) stop(wmsg("'seqlengths' contains negative values")) seqlengths } ### 'seqlengths' can be an integer or numeric vector, or any object from which ### the sequence lengths can be extracted with seqlengths(). ### Returns TRUE if the total length of the underlying sequences is <= ### '.Machine$integer.max' (e.g. Fly genome), FALSE if not (e.g. Human genome), ### or NA if it cannot be computed (because some sequence lengths are NA). isSmallGenome <- function(seqlengths) { if (is.numeric(seqlengths)) { seqlengths <- normarg_seqlengths(seqlengths) } else { seqlengths <- seqlengths(seqlengths) } if (any(is.na(seqlengths))) return(NA) ## sum() will emit a "integer overflow" warning and return NA if the sum ## is > .Machine$integer.max total_length <- suppressWarnings(sum(seqlengths)) !is.na(total_length) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### absoluteRanges() ### ### Transform the genomic ranges in 'x' into "absolute" ranges i.e. into ### ranges counted from the beginning of the virtual sequence obtained by ### concatenating all the sequences in the genome (in the order reported by ### 'seqlevels(x)'). Ignore the strand. ### ONLY WORK ON A SMALL GENOME! (see isSmallGenome() above) absoluteRanges <- function(x) { if (!is(x, "GenomicRanges")) stop(wmsg("'x' must be a GenomicRanges object")) x_seqlengths <- seqlengths(x) if (!isTRUE(isSmallGenome(x_seqlengths))) stop(wmsg("the total length of the underlying sequences is too big ", "or couldn't be computed (because some lengths are NA)")) x_seqids <- as.integer(seqnames(x)) idx <- which(start(x) < 1L | end(x) > x_seqlengths[x_seqids]) if (length(idx) != 0L) stop(wmsg("Some ranges in 'x' are not within the bounds of ", "the sequence that they belong to. Cannot convert ", "them into absolute ranges.")) offsets <- c(0L, cumsum(unname(x_seqlengths)[-length(x_seqlengths)])) x_ranges <- ranges(x) shift(x_ranges, shift=offsets[x_seqids]) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### relativeRanges() ### ### The reverse of absoluteRanges(). ### ONLY WORK ON A SMALL GENOME! (see isSmallGenome() above) relativeRanges <- function(x, seqlengths) { if (!is(x, "Ranges")) stop(wmsg("'x' must be a Ranges object")) if (is.numeric(seqlengths)) { ans_seqlengths <- normarg_seqlengths(seqlengths) ans_seqinfo <- Seqinfo(seqnames=names(ans_seqlengths), seqlengths=ans_seqlengths) } else { if (is(seqlengths, "Seqinfo")) { ans_seqinfo <- seqlengths } else { ans_seqinfo <- seqinfo(seqlengths) } ans_seqlengths <- seqlengths(ans_seqinfo) } if (!isTRUE(isSmallGenome(ans_seqlengths))) stop(wmsg("the total length of the sequences specified ", "thru 'seqlengths' is too big or couldn't be ", "computed (because some lengths are NA)")) offsets <- c(0L, cumsum(unname(ans_seqlengths))) ## Map each range in 'x' to a sequence in the genome. ticks <- offsets + 1L start2seqid <- findInterval(start(x), ticks) end2seqid <- findInterval(end(x), ticks) if (!identical(start2seqid, end2seqid)) stop(wmsg("Some ranges in 'x' cannot be mapped to a sequence in the ", "genome because they cross sequence boundaries. ", "Cannot convert them into relative ranges.")) if (any(start2seqid < 1L) || any(start2seqid > length(ans_seqlengths))) stop(wmsg("Some ranges in 'x' cannot be mapped to a sequence in the ", "genome because they are outside the boundaries of the ", "genome. Cannot convert them into relative ranges.")) ans_ranges <- shift(x, shift=-offsets[start2seqid]) ans_seqnames <- names(ans_seqlengths)[start2seqid] GRanges(ans_seqnames, ans_ranges, seqinfo=ans_seqinfo) } GenomicRanges/R/constraint.R0000644000175400017540000001212313175713746017046 0ustar00biocbuildbiocbuild### ========================================================================= ### Enforcing constraints thru Constraint objects ### ------------------------------------------------------------------------- ### ### Attaching a Constraint object to an object of class A (the "constrained" ### object) is meant to be a convenient/reusable/extensible way to enforce ### a particular set of constraints on particular instances of A. It's an ### alternative to the more traditional approach that consists in creating ### subclasses of A and implementing specific validity methods for each of ### them. However, using constraints offers the following advantages over the ### traditional approach: ### (a) The traditional approach often tends to lead to a proliferation ### of subclasses of A. ### (b) Constraints can easily be re-used across different classes without ### the need to create any new class. ### (c) Constraints can easily be combined. ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Constraint objects. ### ### Virtual class with no slots. setClass("Constraint", representation("VIRTUAL")) ### Like the Constraint virtual class itself, concrete constraint subclasses ### cannot have slots. A Constraint object doesn't need to contain anything ### anyway so by enforcing this we make sure that "combining" constraints ### (i.e. creating a Constraint subclass that extends more than one concrete ### Constraint subclass) always work smoothly (no slot clashes). setValidity2("Constraint", function(x) { if (length(slotNames(x)) != 0L) return("Constraint objects cannot have slots") NULL } ) ### Constrained objects can store a Constraint object (or NULL if no ### constraints) in their 'constraint' slot. setClassUnion("Constraint_OR_NULL", c("Constraint", "NULL")) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### constraint() accessor. ### ### Get or set the Constraint object stored in the constrained object. ### Classes that want to support constraints need to implement methods for ### those 2 generics. setGeneric("constraint", function(x) standardGeneric("constraint")) setGeneric("constraint<-", signature="x", function(x, value) standardGeneric("constraint<-") ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### The checkConstraint() generic. ### ### Returns a matrix with 1 signature per row. Less specific signatures are ### guaranteed to be *before* (i.e. lower row index) the more specific ones. .nextCheckConstraintSignatures <- function(xClass, constraintClass) { ## Loosely inspired by validObject(). xClassDef <- getClassDef(xClass) xAncestors <- sapply(xClassDef@contains, slot, "superClass") xAncestors <- c("ANY", rev(xAncestors), xClass) constraintClassDef <- getClassDef(constraintClass) constraintAncestors <- sapply(constraintClassDef@contains, slot, "superClass") constraintAncestors <- c("ANY", rev(constraintAncestors), constraintClass) signatures <- NULL for (class1 in xAncestors) { for (class2 in constraintAncestors) { methodDef <- selectMethod("checkConstraint", c(class1, class2), optional=TRUE, doCache=TRUE) if (!is.null(methodDef)) signatures <- rbind(signatures, methodDef@defined) } } unique(signatures) } ### The checkConstraint() generic function implements its own dispatch ### algorithm. Like validity methods, "checkConstraint" methods must return ### NULL or a character vector describing the problems found. suppressWarnings( setGeneric("checkConstraint", signature=c("x", "constraint"), function(x, constraint, verbose=FALSE) { errors <- NULL signatures <- .nextCheckConstraintSignatures(class(x), class(constraint)) if (is.null(signatures)) return(errors) ## We check from less specific to more specific constraints. for (i in seq_len(nrow(signatures))) { sig <- signatures[i, ] sigString <- paste(names(sig), paste0('"', sig, '"'), sep="=", collapse=", ") if (verbose) message("Calling \"checkConstraint\" method for\n", " ", sigString) method <- getMethod("checkConstraint", sig) errors <- method(x, constraint) if (length(errors) != 0L) { errors <- paste0("from \"checkConstraint\" method for c(", sigString, "): ", errors) ## If a constraint is not satisfied, we don't check the ## remaining constraints (so when implementing a constraint ## a developer can assume that the less specific constraints ## are satisfied). break } } errors } ) ) GenomicRanges/R/coverage-methods.R0000644000175400017540000000617513175713746020130 0ustar00biocbuildbiocbuild### ========================================================================= ### "coverage" methods ### ------------------------------------------------------------------------- ### ### TODO: Merge with Biostrings:::.V_recycle() and put in IRanges. .recycle <- function(x, skeleton_len, x.label, skeleton.label) { x_len <- length(x) if (x_len == skeleton_len) return(x) if (x_len < skeleton_len) { if (x_len == 0L) stop("cannot recycle zero-length '", x.label, "' ", "to the length of '", skeleton.label, "'") } else { if (x_len >= 2L) stop("'", x.label, "' is longer than '", skeleton.label, "'") } if (skeleton_len %% x_len != 0L) warning("'", x.label, "' length is not a divisor ", "of '", skeleton.label, "' length") rep(x, length.out=skeleton_len) } ### Returns a list-like object. .normarg_shift_or_weight <- function(arg, arg.label, x) { if (is.list(arg) || is(arg, "List")) { if (!identical(names(arg), seqlevels(x))) stop("when '", arg.label, "' is a list-like object, it must ", "have 1 list element per seqlevel in 'x', and its names ", "must be exactly 'seqlevels(x)'") return(arg) } if (isSingleString(arg)) { x_mcols <- mcols(x) if (!is(x_mcols, "DataTable") || sum(colnames(x_mcols) == arg) != 1L) stop("'mcols(x)' has 0 or more than 1 \"", arg, "\" columns") arg <- x_mcols[ , arg] } if (!(is.numeric(arg) || is(arg, "Rle") && is.numeric(runValue(arg)))) stop("'", arg.label, "' must be a numeric vector, a single string, ", "or a list-like object") split(.recycle(arg, length(x), arg.label, "x"), seqnames(x)) } setMethod("coverage", "GenomicRanges", function(x, shift=0L, width=NULL, weight=1L, method=c("auto", "sort", "hash")) { ## Normalize 'shift'. shift <- .normarg_shift_or_weight(shift, "shift", x) ## Just handle the default 'width' here. Non default will be checked ## in IRanges:::.CompressedIRangesList.coverage(). if (is.null(width)) width <- seqlengths(x) ## Normalize 'weight'. weight <- .normarg_shift_or_weight(weight, "weight", x) x_ranges_list <- split(ranges(x), seqnames(x)) circle.length <- seqlengths(x) circle.length[!(isCircular(x) %in% TRUE)] <- NA_integer_ IRanges:::.CompressedIRangesList.coverage(x_ranges_list, shift=shift, width=width, weight=weight, circle.length=circle.length, method=method, x_names.label="'seqlevels(x)'") } ) setMethod("coverage", "GRangesList", function(x, shift=0L, width=NULL, weight=1L, method=c("auto", "sort", "hash")) { coverage(x@unlistData, shift=shift, width=width, weight=weight, method=method) } ) GenomicRanges/R/findOverlaps-methods.R0000644000175400017540000002405013175713746020761 0ustar00biocbuildbiocbuild### ========================================================================= ### findOverlaps methods ### ------------------------------------------------------------------------- ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### "findOverlaps" methods for GenomicRanges objects ### findOverlaps_GenomicRanges <- function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) { type <- match.arg(type) select <- match.arg(select) findOverlaps_GNCList(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type, select=select, ignore.strand=ignore.strand) } setMethod("findOverlaps", c("GenomicRanges", "GenomicRanges"), findOverlaps_GenomicRanges ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### "findOverlaps" methods for GRangesList objects ### .overlapwidth <- function(hits, query, subject) { q_ranges <- ranges(query)[queryHits(hits)] s_ranges <- ranges(subject)[subjectHits(hits)] ## TODO: Replace the code below by a call to ## poverlapWidth(q_ranges, s_ranges) when it's available. score <- pmin.int(end(q_ranges), end(s_ranges)) - pmax.int(start(q_ranges), start(s_ranges)) + 1L pmax.int(score, 0L) } .aggregated_sum <- function(x, f1, f2) { sm <- selfmatchIntegerPairs(f1, f2) S4Vectors:::tabulate2(sm, length(sm), weight=x)[sm] } setMethod("findOverlaps", c("GRangesList", "GRangesList"), function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) { if (!isSingleNumber(minoverlap) || minoverlap < 0L) stop("'minoverlap' must be a single non-negative integer") type <- match.arg(type) select <- match.arg(select) unlisted_query <- unlist(query, use.names=FALSE) query_groups <- togroup(PartitioningByWidth(query)) unlisted_subject <- unlist(subject, use.names=FALSE) subject_groups <- togroup(PartitioningByWidth(subject)) if (type == "start") { keep <- which(S4Vectors:::diffWithInitialZero(subject_groups) != 0L) unlisted_subject <- unlisted_subject[keep] subject_groups <- subject_groups[keep] } else if (type == "end") { keep <- end(subject@partitioning)[elementNROWS(subject) > 0L] unlisted_subject <- unlisted_subject[keep] subject_groups <- subject_groups[keep] } ans00 <- findOverlaps(unlisted_query, unlisted_subject, maxgap=maxgap, type=type, select="all", ignore.strand=ignore.strand) if (minoverlap > 0L) { owidth <- .overlapwidth(ans00, unlisted_query, unlisted_subject) owidth <- .aggregated_sum(owidth, query_groups[queryHits(ans00)], subject_groups[subjectHits(ans00)]) mcols(ans00) <- DataFrame(owidth=owidth) } if (type == "within") { ans01 <- remapHits(ans00, Rnodes.remapping=subject_groups, new.nRnode=length(subject)) ans11 <- remapHits(ans01, Lnodes.remapping=query_groups, new.nLnode=length(query), with.counts=TRUE) keep_idx <- which(mcols(ans11)[ , "counts"] == elementNROWS(query)[queryHits(ans11)]) mcols(ans11) <- NULL ans <- ans11[keep_idx] } else { ans <- remapHits(ans00, Lnodes.remapping=query_groups, new.nLnode=length(query), Rnodes.remapping=subject_groups, new.nRnode=length(subject)) } if (minoverlap > 0L) { keep_idx <- which(mcols(ans)[ , "owidth"] >= minoverlap) mcols(ans) <- NULL ans <- ans[keep_idx] } selectHits(ans, select=select) } ) setMethod("findOverlaps", c("GRangesList", "GenomicRanges"), function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) { if (!isSingleNumber(minoverlap) || minoverlap < 0L) stop("'minoverlap' must be a single non-negative integer") type <- match.arg(type) select <- match.arg(select) unlisted_query <- unlist(query, use.names=FALSE) query_groups <- togroup(PartitioningByWidth(query)) ans00 <- findOverlaps(unlisted_query, subject, maxgap=maxgap, type=type, select="all", ignore.strand=ignore.strand) if (minoverlap > 0L) { owidth <- .overlapwidth(ans00, unlisted_query, subject) owidth <- .aggregated_sum(owidth, query_groups[queryHits(ans00)], subjectHits(ans00)) mcols(ans00) <- DataFrame(owidth=owidth) } if (type == "within") { ans10 <- remapHits(ans00, Lnodes.remapping=query_groups, new.nLnode=length(query), with.counts=TRUE) keep_idx <- which(mcols(ans10)[ , "counts"] == elementNROWS(query)[queryHits(ans10)]) mcols(ans10) <- NULL ans <- ans10[keep_idx] } else { ans <- remapHits(ans00, Lnodes.remapping=query_groups, new.nLnode=length(query)) } if (minoverlap > 0L) { keep_idx <- which(mcols(ans)[ , "owidth"] >= minoverlap) mcols(ans) <- NULL ans <- ans[keep_idx] } selectHits(ans, select=select) } ) setMethod("findOverlaps", c("GenomicRanges", "GRangesList"), function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) { if (!isSingleNumber(minoverlap) || minoverlap < 0L) stop("'minoverlap' must be a single non-negative integer") type <- match.arg(type) select <- match.arg(select) unlisted_subject <- unlist(subject, use.names=FALSE) subject_groups <- togroup(PartitioningByWidth(subject)) if (type == "start") { keep <- which(S4Vectors:::diffWithInitialZero(subject_groups) != 0L) unlisted_subject <- unlisted_subject[keep] subject_groups <- subject_groups[keep] } else if (type == "end") { keep <- end(subject@partitioning)[elementNROWS(subject) > 0L] unlisted_subject <- unlisted_subject[keep] subject_groups <- subject_groups[keep] } ans00 <- findOverlaps(query, unlisted_subject, maxgap=maxgap, type=type, select="all", ignore.strand=ignore.strand) if(minoverlap > 0L) { owidth <- .overlapwidth(ans00, query, unlisted_subject) owidth <- .aggregated_sum(owidth, queryHits(ans00), subject_groups[subjectHits(ans00)]) mcols(ans00) <- DataFrame(owidth=owidth) } ans <- remapHits(ans00, Rnodes.remapping=subject_groups, new.nRnode=length(subject)) if (minoverlap > 0L) { keep_idx <- which(mcols(ans)[ , "owidth"] >= minoverlap) mcols(ans) <- NULL ans <- ans[keep_idx] } selectHits(ans, select=select) } ) ### Needed by chipseq package. setMethod("findOverlaps", c("RangedData", "GenomicRanges"), function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) { ## Calls "findOverlaps" method for c("GenomicRanges", "GenomicRanges") ## defined above. findOverlaps(as(query, "GRanges"), subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), ignore.strand=ignore.strand) } ) ### ========================================================================= ### findOverlaps-based methods ### ------------------------------------------------------------------------- countOverlaps_GenomicRanges <- function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "equal"), ignore.strand=FALSE) { type <- match.arg(type) ans <- findOverlaps_GNCList(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type, select="count", ignore.strand=ignore.strand) names(ans) <- names(query) ans } setMethod("countOverlaps", c("GenomicRanges", "GenomicRanges"), countOverlaps_GenomicRanges ) compatibleStrand <- function(a, b) { a == "*" | b == "*" | a == b } setMethod("poverlaps", c("GenomicRanges", "GenomicRanges"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), ignore.strand=FALSE) { seqnames(query) == seqnames(subject) & (if (ignore.strand) TRUE else compatibleStrand(strand(query), strand(subject))) & poverlaps(ranges(query), ranges(subject), maxgap, minoverlaps, type) }) GenomicRanges/R/genomic-range-squeezers.R0000644000175400017540000000165313175713746021427 0ustar00biocbuildbiocbuild### ========================================================================= ### Generic functions for squeezing the genomic ranges out of a range-based ### object ### ------------------------------------------------------------------------- ### Extract the genomic ranges as a GRanges object. setGeneric("granges", signature="x", function(x, use.names=TRUE, use.mcols=FALSE, ...) standardGeneric("granges") ) ### Extract the genomic ranges as a GRangesList object. setGeneric("grglist", signature="x", function(x, use.names=TRUE, use.mcols=FALSE, ...) standardGeneric("grglist") ) ### Pairs method. setMethod("grglist", "Pairs", function(x, use.names=TRUE, use.mcols=FALSE) { stopifnot(isTRUEorFALSE(use.mcols)) grl <- zipup(granges(first(x)), granges(second(x))) if (!use.mcols) { mcols(grl) <- NULL } grl }) GenomicRanges/R/genomicvars.R0000644000175400017540000001365713175713746017214 0ustar00biocbuildbiocbuild### ========================================================================= ### Manipulate genomic variables i.e. data/variable defined along a genome ### ------------------------------------------------------------------------- ### ### The concept of genomic variables could be formalized via a dedicated ### container. This container could be a simple extension of GRanges with no ### additional slots and the following constraints: ### - The ranges are unstranded (i.e. strand is set to * for all ranges). ### - The ranges are disjoint and ordered. ### Then the metadata columns are the genomic variables. ### For now, we just use a GRanges object. We make sure it's disjoint and we ### ignore its strand. We don't mind if it's not ordered and make sure that ### the code that operates on it works properly even if it's not ordered. ### setAs("RleList", "GRanges", function(from) { score <- unlist(runValue(from), use.names=FALSE) lens <- runLength(from) ir <- unlist(RangesList(lapply(lens, successiveIRanges)), use.names=FALSE) nrun <- lengths(lens) gr <- GRanges(rep(names(from), nrun), ir, score=score) seqlengths(gr) <- lengths(from) gr }) setAs("RleViewsList", "GRanges", function(from) { as(as(from, "RangedData"), "GRanges") }) ### Represent a collection of named RleList objects as a GRanges with 1 ### metadata column per RleList object. bindAsGRanges <- function(...) { args <- list(...) if (length(args) == 0L) stop("nothing to bind") ## TODO: Implement (in C) fast 'elementIs(objects, class)' in S4Vectors ## that does 'sapply(objects, is, class, USE.NAMES=FALSE)', and use it ## here. if (!all(sapply(args, is, "RleList", USE.NAMES=FALSE))) stop("the objects to bind must be RleList objects") ans_seqlevels <- names(args[[1L]]) if (is.null(ans_seqlevels)) stop("the RleList objects to combine must have names") if (any(ans_seqlevels %in% c(NA_character_, "")) || anyDuplicated(ans_seqlevels)) stop(wmsg("the names on the RleList objects cannot contain NAs, ", "empty strings, or duplicates")) if (!all(sapply(args[-1L], function(arg) identical(names(arg), ans_seqlevels)))) stop(wmsg("the RleList objects to combine must have the same length ", "and the same names in the same order")) DFL <- cbind(...) # named CompressedSplitDataFrameList unlisted_DFL <- unlist(DFL, use.names=FALSE) # DataFrame DFL_partitioning <- PartitioningByEnd(DFL) ## Prepare 'ans_seqnames'. ans_seqnames <- Rle(factor(ans_seqlevels, levels=ans_seqlevels), width(DFL_partitioning)) ## Prepare 'ans_ranges'. ans_width <- unlisted_DFL[ , "runLength"] width_list <- relist(ans_width, DFL) ans_end <- unlist(lapply(width_list, cumsum), use.names=FALSE) ans_ranges <- IRanges(end=ans_end, width=ans_width) ## Prepare 'ans_seqlengths'. ans_seqlengths <- setNames(ans_end[end(DFL_partitioning)], names(DFL)) ## First column is "runLength". Get rid of it. ans_mcols <- unlisted_DFL[-1L] ans <- new_GRanges("GRanges", ans_seqnames, ans_ranges, mcols=ans_mcols, seqlengths=ans_seqlengths) ## Keep only ranges for which at least one variable is not NA. keep_idx <- which(rowSums(!is.na(mcols(ans))) != 0L) ans[keep_idx] } ### Return a named RleList with 1 list element per seqlevel in 'x'. ### Works on any metadata column that can be put in Rle form (i.e. any atomic ### vector or factor). mcolAsRleList <- function(x, varname) { if (!is(x, "GenomicRanges")) stop("'x' must be a GRanges object") var <- mcols(x)[ , varname] ## If 'var' is numeric, then we can use coverage(). #if (is.numeric(var)) # return(coverage(x, weight=var)) ## Otherwise 'x' must be disjoint and we compute the RleList in a loop. ## This would also work on a numeric metadata column but would be slower ## than using coverage(), especially if 'x' has many seqlevels. if (!isDisjoint(x, ignore.strand=TRUE)) stop(wmsg("cannot turn non-numeric metadata column into a ", "named RleList object when 'x' is not disjoint ", "(ignoring the strand)")) rg_per_chrom <- split(ranges(x), seqnames(x)) var_per_chrom <- split(var, seqnames(x)) rle_list <- mapply( function(seqlen, ir, v) { if (is.na(seqlen)) seqlen <- max(end(ir)) rle <- Rle(v[NA_integer_], seqlen) rle[ir] <- Rle(v, width(ir)) rle }, seqlengths(x), rg_per_chrom, var_per_chrom, SIMPLIFY=FALSE ) as(rle_list, "SimpleRleList") } binnedAverage <- function(bins, numvar, varname, na.rm=FALSE) { if (!is(bins, "GRanges")) stop("'x' must be a GRanges object") if (!is(numvar, "RleList")) stop("'numvar' must be an RleList object") if (!identical(seqlevels(bins), names(numvar))) stop("'seqlevels(bin)' and 'names(numvar)' must be identical") ## A version of viewMeans() that pads "out of limits" views with zeros. viewMeans2 <- function(v, na.rm=FALSE) { if (!isTRUEorFALSE(na.rm)) stop("'na.rm' must be TRUE or FALSE") means <- viewMeans(v, na.rm=na.rm) w0 <- width(v) v1 <- trim(v) w1 <- width(v1) if (na.rm) { na_count <- sum(is.na(v1)) w0 <- w0 - na_count w1 <- w1 - na_count } means <- means * w1 / w0 means[w0 != 0L & w1 == 0L] <- 0 means } bins_per_chrom <- split(ranges(bins), seqnames(bins)) means_list <- lapply(names(numvar), function(seqname) { v <- Views(numvar[[seqname]], bins_per_chrom[[seqname]]) viewMeans2(v, na.rm=na.rm) }) new_mcol <- unsplit(means_list, as.factor(seqnames(bins))) mcols(bins)[[varname]] <- new_mcol bins } GenomicRanges/R/inter-range-methods.R0000644000175400017540000003544013175713746020545 0ustar00biocbuildbiocbuild### ========================================================================= ### Inter-range methods ### ------------------------------------------------------------------------- ### ### 'revmap_unlisted' and 'revmap_partitioning': IntegerList and Partitioning ### objects representing the "revmap object", which is *conceptually* an ### IntegerListList object (of the same length as 'revmap_partitioning'). ### *Conceptually* because, well, we don't actually have such container... ### 'old2new': IntegerList of the same length as the "revmap object". .translate_revmap <- function(revmap_unlisted, revmap_partitioning, old2new) { ## 'times' has the length of the "revmap object". times <- sum(relist(width(PartitioningByEnd(revmap_unlisted)), revmap_partitioning)) ## 'offset' has the length of 'revmap_unlisted@unlistData'. offset <- rep.int(start(PartitioningByEnd(old2new)) - 1L, times) revmap_flat <- revmap_unlisted@unlistData revmap_unlisted@unlistData <- old2new@unlistData[revmap_flat + offset] revmap_unlisted } ### 'rgl2' and 'rgl' must be List objects (typically RangesList or GRangesList) ### of the same length, both with a "revmap" inner metadata column. .fix_inner_revmap_mcol <- function(rgl2, rgl) { unlisted_rgl2 <- unlist(rgl2, use.names=FALSE) unlisted_revmap2 <- mcols(unlisted_rgl2)$revmap revmap <- relist(mcols(unlist(rgl, use.names=FALSE))$revmap, rgl) mcols(unlisted_rgl2)$revmap <- .translate_revmap(unlisted_revmap2, rgl2, revmap) rgl2 <- relist(unlisted_rgl2, rgl2) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Deconstruction/reconstruction of a GenomicRanges object into/from an ### IRangesList object. ### ### For internal use only (not exported). ### .make_spaceid <- function(x, ignore.strand=FALSE, drop=FALSE) { spaceid <- seqnames(x) runValue(spaceid) <- 3L * as.integer(runValue(spaceid)) if (!ignore.strand) { strandid <- strand(x) runValue(strandid) <- as.integer(runValue(strandid)) - 3L spaceid <- spaceid + strandid } if (!drop) { levels <- as.character(seq_len(3L * length(seqlevels(x)))) runValue(spaceid) <- structure(runValue(spaceid), levels=levels, class="factor") } spaceid } ### Work on any GenomicRanges derivative and return a CompressedIRangesList ### instance. deconstructGRintoRGL <- function(x, with.revmap=FALSE, ignore.strand=FALSE, drop=FALSE) { if (!isTRUEorFALSE(with.revmap)) stop("'with.revmap' must be TRUE or FALSE") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") x_ranges <- unname(ranges(x)) if (with.revmap) mcols(x_ranges) <- DataFrame(revmap=seq_along(x_ranges)) x_spaceid <- .make_spaceid(x, ignore.strand=ignore.strand, drop=drop) split(x_ranges, x_spaceid) } ### Return a GRanges instance. reconstructGRfromRGL <- function(rgl, x) { ## Prepare 'ans_ranges'. ans_ranges <- unlist(rgl, use.names=FALSE) ## Prepare 'ans_seqnames' and 'ans_strand'. rgl_eltNROWS <- elementNROWS(rgl) spaceid <- as.integer(names(rgl)) - 1L ans_seqnames <- Rle(structure(spaceid %/% 3L + 1L, levels=seqlevels(x), class="factor"), rgl_eltNROWS) ans_strand <- Rle(structure(spaceid %% 3L + 1L, levels=levels(strand()), class="factor"), rgl_eltNROWS) ## Prepare 'ans_mcols'. ans_mcols <- mcols(ans_ranges) if (is.null(ans_mcols)) { ans_mcols <- S4Vectors:::make_zero_col_DataFrame(length(ans_ranges)) } else { mcols(ans_ranges) <- NULL } ## Prepare 'ans_seqinfo'. ans_seqinfo <- seqinfo(x) ## To be as fast as possible, we don't use internal low-level constructor ## new_GRanges() and we don't check the new object. new2("GRanges", seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, seqinfo=ans_seqinfo, check=FALSE) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Deconstruction/reconstruction of a GRangesList object into/from a GRanges ### object. ### ### For internal use only (not exported). ### ### Unlist GRangesList object 'x' into a GRanges object but the differences ### with the "unlist" method for GRangesList objects are: ### - The sequence names of the returned GRanges object are modified by ### embedding the "grouping by top-level element" information in them. ### - The seqinfo is modified accordingly. deconstructGRLintoGR <- function(x, expand.levels=FALSE) { ans <- x@unlistData f1 <- rep.int(seq_len(length(x)), elementNROWS(x)) f2 <- as.integer(seqnames(ans)) f12 <- paste(f1, f2, sep="|") ## Compute 'ans_seqinfo'. if (expand.levels) { x_nlev <- length(seqlevels(x)) i1 <- rep(seq_len(length(x)), each=x_nlev) i2 <- rep.int(seq_len(x_nlev), length(x)) } else { oo <- orderIntegerPairs(f1, f2) of1 <- f1[oo] of2 <- f2[oo] ## TODO: Support 'method="presorted"' in duplicatedIntegerPairs() for ## when the 2 input vectors are already sorted. notdups <- !duplicatedIntegerPairs(of1, of2) i1 <- of1[notdups] i2 <- of2[notdups] } x_seqinfo <- seqinfo(x) ans_seqlevels <- paste(i1, i2, sep="|") ans_seqlengths <- unname(seqlengths(x_seqinfo))[i2] ans_isCircular <- unname(isCircular(x_seqinfo))[i2] ans_seqinfo <- Seqinfo(ans_seqlevels, ans_seqlengths, ans_isCircular) ## The 2 following modifications must be seen as a single atomic ## operation since doing the 1st without doing the 2nd would leave 'ans' ## in a broken state. ans@seqnames <- Rle(factor(f12, ans_seqlevels)) ans@seqinfo <- ans_seqinfo ans } ### The "inverse" transform of deconstructGRLintoGR(). ### More precisely, reconstructGRLfromGR() transforms GRanges object 'gr' ### with sequence names in the "f1|f2" format (as produced by ### deconstructGRLintoGR() above) back into a GRangesList object with the ### same length & names & metadata columns & seqinfo as 'x'. ### The fundamental property of this deconstruction/reconstruction mechanism ### is that, for any GRangesList object 'x': ### ### reconstructGRLfromGR(deconstructGRLintoGR(x), x) is identical to x ### reconstructGRLfromGR <- function(gr, x, with.revmap=FALSE) { snames <- strsplit(as.character(seqnames(gr)), "|", fixed=TRUE) m12 <- matrix(as.integer(unlist(snames)), ncol=2, byrow=TRUE) ## Restore the real sequence names. f2 <- m12[ , 2L] x_seqlevels <- seqlevels(x) ## The 2 following modifications must be seen as a single atomic ## operation since doing the 1st without doing the 2nd would leave 'ans' ## in a broken state. gr@seqnames <- Rle(factor(x_seqlevels[f2], x_seqlevels)) gr@seqinfo <- seqinfo(x) ## Split. f1 <- m12[ , 1L] ans <- split(gr, factor(f1, levels=seq_len(length(x)))) ## Decorate 'ans'. metadata(ans) <- metadata(x) names(ans) <- names(x) if (with.revmap) { unlisted_ans <- unlist(ans, use.names=FALSE) mcols(unlisted_ans)$revmap <- IRanges:::global2local_revmap(mcols(unlisted_ans)$revmap, ans, x) ans <- relist(unlisted_ans, ans) } mcols(ans) <- mcols(x) ans } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### range() ### ### Always return a GRanges *instance* whatever GenomicRanges derivative the ### input is, so does NOT act like an endomorphism in general. setMethod("range", "GenomicRanges", function(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) { if (!identical(na.rm, FALSE)) warning("'na.rm' argument is ignored") args <- unname(list(x, ...)) args <- lapply(args, granges) gr <- do.call(c, args) rgl <- deconstructGRintoRGL(gr, with.revmap=with.revmap, ignore.strand=ignore.strand, drop=TRUE) rgl2 <- callGeneric(rgl, with.revmap=with.revmap) if (with.revmap) rgl2 <- .fix_inner_revmap_mcol(rgl2, rgl) reconstructGRfromRGL(rgl2, gr) } ) ### Overwrite above method with optimized method for GPos objects. ### Like the above method, return a GRanges instance. setMethod("range", "GPos", function(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) callGeneric(stitch_GPos(x), ..., with.revmap=with.revmap, ignore.strand=ignore.strand, na.rm=na.rm) ) setMethod("range", "GRangesList", function(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) { gr <- deconstructGRLintoGR(x) ## "range" method for GRanges objects is fast. gr2 <- callGeneric(gr, ..., with.revmap=with.revmap, ignore.strand=ignore.strand, na.rm=na.rm) reconstructGRLfromGR(gr2, x, with.revmap=with.revmap) } ) setMethod("range", "GenomicRangesList", function(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) { endoapply(x, range, ..., with.revmap=with.revmap, ignore.strand=ignore.strand, na.rm=na.rm) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### reduce() ### ### Always return a GRanges *instance* whatever GenomicRanges derivative the ### input is, so does NOT act like an endomorphism in general. setMethod("reduce", "GenomicRanges", function(x, drop.empty.ranges=FALSE, min.gapwidth=1L, with.revmap=FALSE, with.inframe.attrib=FALSE, ignore.strand=FALSE) { if (!identical(with.inframe.attrib, FALSE)) stop("'with.inframe.attrib' argument not supported ", "when reducing a GenomicRanges object") rgl <- deconstructGRintoRGL(x, with.revmap=with.revmap, ignore.strand=ignore.strand, drop=TRUE) rgl2 <- callGeneric(rgl, drop.empty.ranges=drop.empty.ranges, min.gapwidth=min.gapwidth, with.revmap=with.revmap) if (with.revmap) rgl2 <- .fix_inner_revmap_mcol(rgl2, rgl) reconstructGRfromRGL(rgl2, x) } ) setMethod("reduce", "GRangesList", function(x, drop.empty.ranges=FALSE, min.gapwidth=1L, with.revmap=FALSE, with.inframe.attrib=FALSE, ignore.strand=FALSE) { if (!identical(with.inframe.attrib, FALSE)) stop("'with.inframe.attrib' argument is not supported ", "when reducing a GRangesList object") gr <- deconstructGRLintoGR(x) gr2 <- callGeneric(gr, drop.empty.ranges=drop.empty.ranges, min.gapwidth=min.gapwidth, with.revmap=with.revmap, ignore.strand=ignore.strand) reconstructGRLfromGR(gr2, x, with.revmap=with.revmap) } ) setMethod("reduce", "GenomicRangesList", function(x, drop.empty.ranges = FALSE, ...) { endoapply(x, reduce, drop.empty.ranges=drop.empty.ranges, ...) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### gaps() ### ### Always return a GRanges *instance* whatever GenomicRanges derivative the ### input is, so does NOT act like an endomorphism in general. setMethod("gaps", "GenomicRanges", function(x, start=1L, end=seqlengths(x)) { seqlevels <- seqlevels(x) if (!is.null(names(start))) start <- start[seqlevels] if (!is.null(names(end))) end <- end[seqlevels] start <- S4Vectors:::recycleVector(start, length(seqlevels)) start <- rep(start, each=3L) end <- S4Vectors:::recycleVector(end, length(seqlevels)) end <- rep(end, each=3L) rgl <- deconstructGRintoRGL(x) rgl2 <- callGeneric(rgl, start=start, end=end) reconstructGRfromRGL(rgl2, x) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### disjoin() ### ### Always return a GRanges *instance* whatever GenomicRanges derivative the ### input is, so does NOT act like an endomorphism in general. setMethod("disjoin", "GenomicRanges", function(x, with.revmap=FALSE, ignore.strand=FALSE) { rgl <- deconstructGRintoRGL(x, with.revmap=with.revmap, ignore.strand=ignore.strand, drop=TRUE) rgl2 <- callGeneric(rgl, with.revmap=with.revmap) if (with.revmap) rgl2 <- .fix_inner_revmap_mcol(rgl2, rgl) reconstructGRfromRGL(rgl2, x) } ) setMethod("disjoin", "GRangesList", function(x, with.revmap=FALSE, ignore.strand=FALSE) { gr <- deconstructGRLintoGR(x) gr2 <- callGeneric(gr, with.revmap=with.revmap, ignore.strand=ignore.strand) reconstructGRLfromGR(gr2, x, with.revmap=with.revmap) } ) setMethod("disjoin", "GenomicRangesList", function(x, with.revmap=FALSE, ignore.strand=FALSE) { endoapply(x, disjoin, with.revmap=with.revmap, ignore.strand=ignore.strand) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### isDisjoint() ### setMethod("isDisjoint", "GenomicRanges", function(x, ignore.strand=FALSE) { rgl <- deconstructGRintoRGL(x, ignore.strand=ignore.strand, drop=TRUE) all(callGeneric(rgl)) } ) ### Overwrite above method with optimized method for GPos objects. setMethod("isDisjoint", "GPos", function(x, ignore.strand=FALSE) callGeneric(stitch_GPos(x), ignore.strand) ) setMethod("isDisjoint", "GRangesList", function(x, ignore.strand=FALSE) { gr <- deconstructGRLintoGR(x, expand.levels=TRUE) rgl <- deconstructGRintoRGL(gr, ignore.strand=ignore.strand) ans <- callGeneric(rgl) ans <- colSums(matrix(!ans, ncol=length(x))) == 0L names(ans) <- names(x) ans } ) setMethod("isDisjoint", "GenomicRangesList", function(x, ignore.strand=FALSE) { endoapply(x, isDisjoint, ignore.strand=ignore.strand) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### disjointBins() ### setMethod("disjointBins", "GenomicRanges", function(x, ignore.strand=FALSE) { x_spaceid <- .make_spaceid(x, ignore.strand=ignore.strand, drop=TRUE) rgl <- split(unname(ranges(x)), x_spaceid) ans <- callGeneric(rgl) unsplit(ans, x_spaceid) } ) GenomicRanges/R/intra-range-methods.R0000644000175400017540000002614413175713746020542 0ustar00biocbuildbiocbuild### ========================================================================= ### Intra-range methods ### ------------------------------------------------------------------------- ### ### The methods implemented in this file should behave consistently with ### those defined in IRanges intra-range-methods.R ### ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### shift() ### setMethod("shift", "GenomicRanges", function(x, shift=0L, use.names=TRUE) { new_ranges <- shift(ranges(x), shift=shift, use.names=use.names) update(x, ranges=new_ranges) } ) setMethod("shift", "GRangesList", function(x, shift=0L, use.names=TRUE) { ## Unlist 'x'. unlisted_x <- unlist(x, use.names=FALSE) ## Recycle and unlist 'shift'. if (!is(shift, "List")) shift <- as(shift, "List") shift <- S4Vectors:::VH_recycle(shift, x, "shift", "x") unlisted_shift <- unlist(shift, use.names=FALSE) ## Compute unlisted 'ans'. unlisted_ans <- shift(unlisted_x, shift=unlisted_shift, use.names=use.names) ## Relist and return. relist(unlisted_ans, x) } ) setMethod("shift", "GenomicRangesList", function(x, shift=0L, use.names=TRUE) { endoapply(x, IRanges::shift, shift, use.names) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### narrow() ### setMethod("narrow", "GenomicRanges", function(x, start=NA, end=NA, width=NA, use.names=TRUE) { new_ranges <- narrow(ranges(x), start=start, end=end, width=width, use.names=use.names) ranges(x) <- new_ranges x } ) setMethod("narrow", "GRangesList", function(x, start=NA, end=NA, width=NA, use.names=TRUE) { gr <- narrow(x@unlistData, start=start, end=end, width=width, use.names=use.names) relist(gr, x@partitioning) } ) setMethod("narrow", "GenomicRangesList", function(x, start=NA, end=NA, width=NA, use.names=TRUE) { endoapply(x, narrow, start, end, width, use.names) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### resize() ### setMethod("resize", "GenomicRanges", function(x, width, fix="start", use.names=TRUE, ignore.strand=FALSE) { if (!missing(fix) && length(x) > 0L && (length(fix) > length(x) || length(x) %% length(fix) > 0L)) stop("'x' is not a multiple of 'fix' length") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) { fix <- Rle(rep.int(fix, length(x))) } else { revFix <- c(start="end", end="start", center="center") if (length(x) == 0L) fix <- character() else fix <- ifelse(strand(x) == "-", revFix[fix], fix) } new_ranges <- resize(ranges(x), width=width, fix=fix, use.names=use.names) ranges(x) <- new_ranges x } ) setMethod("resize", "GRangesList", function(x, width, fix="start", use.names=TRUE, ignore.strand=FALSE) { ## Unlist 'x'. unlisted_x <- unlist(x, use.names=FALSE) ## Recycle and unlist 'width'. if (!is(width, "List")) width <- as(width, "List") width <- S4Vectors:::VH_recycle(width, x, "width", "x") unlisted_width <- unlist(width, use.names=FALSE) ## Compute unlisted 'ans'. unlisted_ans <- resize(unlisted_x, unlisted_width, fix=fix, use.names=use.names, ignore.strand=ignore.strand) ## Relist and return. relist(unlisted_ans, x) } ) setMethod("resize", "GenomicRangesList", function(x, width, fix="start", use.names=TRUE, ignore.strand=FALSE) { endoapply(x, resize, width, fix, use.names, ignore.strand) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### flank() ### setMethod("flank", "GenomicRanges", function(x, width, start=TRUE, both=FALSE, use.names=TRUE, ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) start <- rep.int(start, length(x)) else start <- as.vector(start == (strand(x) != "-")) new_ranges <- flank(ranges(x), width=width, start=start, both=both, use.names=use.names) ranges(x) <- new_ranges x } ) setMethod("flank", "GRangesList", function(x, width, start=TRUE, both=FALSE, use.names=TRUE, ignore.strand=FALSE) { ## Unlist 'x'. unlisted_x <- unlist(x, use.names=FALSE) ## Recycle and unlist 'width'. if (!is(width, "List")) width <- as(width, "List") width <- S4Vectors:::VH_recycle(width, x, "width", "x") unlisted_width <- unlist(width, use.names=FALSE) ## Compute unlisted 'ans'. unlisted_ans <- flank(unlisted_x, unlisted_width, start=start, both=both, use.names=use.names, ignore.strand=ignore.strand) ## Relist and return. relist(unlisted_ans, x) } ) setMethod("flank", "GenomicRangesList", function(x, width, start=TRUE, both=FALSE, use.names=TRUE, ignore.strand=FALSE) { endoapply(x, flank, width, start, both, use.names, ignore.strand) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### promoters() ### setMethod("promoters", "GenomicRanges", function(x, upstream=2000, downstream=200) { if (!isSingleNumber(upstream)) stop("'upstream' must be a single integer") if (!is.integer(upstream)) upstream <- as.numeric(upstream) if (!isSingleNumber(downstream)) stop("'downstream' must be a single integer") if (!is.integer(downstream)) downstream <- as.numeric(downstream) if (upstream < 0 | downstream < 0) stop("'upstream' and 'downstream' must be integers >= 0") if (any(strand(x) == "*")) warning("'*' ranges were treated as '+'") on_plus <- which(strand(x) == "+" | strand(x) == "*") on_plus_TSS <- start(x)[on_plus] start(x)[on_plus] <- on_plus_TSS - upstream end(x)[on_plus] <- on_plus_TSS + downstream - 1L on_minus <- which(strand(x) == "-") on_minus_TSS <- end(x)[on_minus] end(x)[on_minus] <- on_minus_TSS + upstream start(x)[on_minus] <- on_minus_TSS - downstream + 1L x } ) setMethod("promoters", "GRangesList", function(x, upstream=2000, downstream=200) { x@unlistData <- promoters(x@unlistData, upstream=upstream, downstream=downstream) x } ) setMethod("promoters", "GenomicRangesList", function(x, upstream=2000, downstream=200) { endoapply(x, promoters, upstream, downstream) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### reflect() ### ### TODO: Add "reflect" method for GenomicRanges objects. ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### restrict() ### .checkParms <- function(x, parm) { if (!all(is.na(parm))) { if (!all(names(parm) %in% levels(seqnames(x)))) stop("start should be a named numeric vector ", "corresponding to seqnames") } temp <- structure(rep(NA_integer_, length(levels(seqnames(x)))), names=levels(seqnames(x))) temp[names(parm)] <- parm temp } .restrictRngs <- function(x, start, end, keep.all.ranges, use.names) { tmp <- names(x) names(x) <- seq_len(length(x)) rng <- ranges(x) res <- restrict(ranges(x), start, end, keep.all.ranges, use.names=TRUE) x <- x[as.numeric(names(res))] ranges(x) <- res if (!use.names) names(x) <- NULL else names(x) <- tmp[as.numeric(names(res))] x } setMethod("restrict", "GenomicRanges", function(x, start=NA, end=NA, keep.all.ranges=FALSE, use.names=TRUE) { if (is.null(names(start)) && is.null(names(end))) return(.restrictRngs(x, start, end,keep.all.ranges, use.names)) nms <- names(mcols(x)) mcols(x) <- cbind(mcols(x), DataFrame(posIndx=seq_len(length(x)))) splt <- split(x, seqnames(x)) start <- .checkParms(x, start) end <- .checkParms(x, end) res <- lapply(names(splt), function(i) { .restrictRngs(splt[[i]], start=start[i], end=end[i], keep.all.ranges, use.names) }) names(res) <- names(splt) ord <- unlist(GRangesList(res), use.names=FALSE) df <- data.frame(orig=mcols(ord)[["posIndx"]], final=seq_len(length(ord))) indx <- order(df[["orig"]], df[["final"]]) ord <- ord[indx, ] mcols(ord) <- subset(mcols(ord), select=nms) ord } ) setMethod("restrict", "GenomicRangesList", function(x, start = NA, end = NA, keep.all.ranges = FALSE, use.names = TRUE) { endoapply(x, restrict, start=start, end=end, keep.all.ranges=keep.all.ranges, use.names=use.names) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### trim() ### setMethod("trim", "GenomicRanges", function(x, use.names=TRUE) { ## We trim only out-of-bound ranges located on non-circular sequences ## whose length is not NA. ## See get_out_of_bound_index() in GenomicRanges-class.R idx <- get_out_of_bound_index(x) if (length(idx) == 0L) return(x) new_ranges <- ranges(x) seqnames_id <- as.integer(seqnames(x))[idx] new_end <- unname(seqlengths(x))[seqnames_id] new_ranges[idx] <- restrict(new_ranges[idx], start=1L, end=new_end, keep.all.ranges=TRUE) ranges(x) <- new_ranges x } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Zooming (symmetrically scales the width). ### setMethod("Ops", c("GenomicRanges", "numeric"), function(e1, e2) { if (S4Vectors:::anyMissing(e2)) stop("NA not allowed as zoom factor") e2 <- recycleNumericArg(e2, "e2", length(e1)) if (.Generic == "*") { e2 <- ifelse(e2 < 0, abs(1/e2), e2) resize(e1, width(e1) / e2, fix="center") } else { if (.Generic == "-") { e2 <- -e2 .Generic <- "+" } if (.Generic == "+") { if (any(-e2*2 > width(e1))) stop("adjustment would result in ranges ", "with negative widths") resize(e1, width(e1) + e2*2, fix="center") } } } ) GenomicRanges/R/makeGRangesFromDataFrame.R0000644000175400017540000002357713175713746021456 0ustar00biocbuildbiocbuild### ========================================================================= ### makeGRangesFromDataFrame() ### ------------------------------------------------------------------------- ### Must return NULL or a Seqinfo object. .normarg_seqinfo <- function(seqinfo) { if (is.null(seqinfo) || is(seqinfo, "Seqinfo")) return(seqinfo) if (is.character(seqinfo)) return(Seqinfo(seqinfo)) if (is.numeric(seqinfo)) { seqlevels <- names(seqinfo) if (is.null(seqlevels)) stop("when a numeric vector, 'seqinfo' must have names") return(Seqinfo(seqlevels, seqlengths=seqinfo)) } stop("'seqinfo' must be NULL, or a Seqinfo object, or a character vector ", "of seqlevels, or a named numeric vector of sequence lengths") } .normarg_field <- function(field, what) { if (!is.character(field) || any(is.na(field))) stop("'", what, ".field' must be a character vector with no NAs") tolower(field) } .collect_prefixes <- function(df_colnames, field) { df_colnames_nc <- nchar(df_colnames) prefixes <- lapply(field, function(suf) { pref_nc <- df_colnames_nc - nchar(suf) idx <- which(substr(df_colnames, pref_nc + 1L, df_colnames_nc) == suf) substr(df_colnames[idx], 1L, pref_nc[idx]) }) unique(unlist(prefixes)) } .find_start_end_cols <- function(df_colnames, start.field, end.field) { idx1 <- which(df_colnames %in% start.field) idx2 <- which(df_colnames %in% end.field) if (length(idx1) == 1L && length(idx2) == 1L) return(list(c(start=idx1, end=idx2), "")) if (length(idx1) == 0L && length(idx2) == 0L) { prefixes1 <- .collect_prefixes(df_colnames, start.field) prefixes2 <- .collect_prefixes(df_colnames, end.field) if (length(prefixes1) == 1L && length(prefixes2) == 1L && prefixes1 == prefixes2) { prefix <- prefixes1 idx1 <- which(df_colnames %in% paste0(prefix, start.field)) idx2 <- which(df_colnames %in% paste0(prefix, end.field)) if (length(idx1) == 1L && length(idx2) == 1L) return(list(c(start=idx1, end=idx2), prefix)) } } stop("cannnot determine start/end columns") } .find_width_col <- function(df_colnames, width.field, prefix) { idx <- which(df_colnames %in% paste0(prefix, width.field)) if (length(idx) == 0L) idx <- which(df_colnames %in% width.field) if (length(idx) == 0L) return(NA_integer_) if (length(idx) >= 2L) { warning("cannnot determine width column unambiguously") return(idx[[1L]]) } idx } .find_seqnames_col <- function(df_colnames, seqnames.field, prefix) { idx <- which(df_colnames %in% paste0(prefix, seqnames.field)) if (length(idx) == 0L) idx <- which(df_colnames %in% seqnames.field) if (length(idx) == 0L) stop("cannnot find seqnames column") if (length(idx) >= 2L) stop("cannnot determine seqnames column unambiguously") idx } .find_strand_col <- function(df_colnames, strand.field, prefix) { idx <- which(df_colnames %in% paste0(prefix, strand.field)) if (length(idx) == 0L) idx <- which(df_colnames %in% strand.field) if (length(idx) == 0L) return(NA_integer_) if (length(idx) >= 2L) stop("Cannnot determine strand column unambiguously. ", "(You can use\n 'ignore.strand=TRUE' to ignore ", "strand information.)") idx } ### Returns a named integer vector of length 5. Names are: seqnames, start, ### end, width, and strand. The values must be valid column numbers, except ### for the width and strand elements that can also be NAs. .find_GRanges_cols <- function(df_colnames, seqnames.field=c("seqnames", "seqname", "chromosome", "chrom", "chr", "chromosome_name", "seqid"), start.field="start", end.field=c("end", "stop"), strand.field="strand", ignore.strand=FALSE) { ## Automatic detection of seqnames/start/end/strand columns is case ## insensitive. df_colnames0 <- tolower(df_colnames) seqnames.field0 <- .normarg_field(seqnames.field, "seqnames") start.field0 <- .normarg_field(start.field, "start") end.field0 <- .normarg_field(end.field, "end") start_end_cols <- .find_start_end_cols(df_colnames0, start.field0, end.field0) prefix <- start_end_cols[[2L]] ## Name of "width" field is not under user control for now (until we need ## need that). width_col <- .find_width_col(df_colnames0, "width", prefix) seqnames_col <- .find_seqnames_col(df_colnames0, seqnames.field0, prefix) if (ignore.strand) { strand_col <- NA_integer_ } else { strand.field0 <- .normarg_field(strand.field, "strand") strand_col <- .find_strand_col(df_colnames0, strand.field0, prefix) } c(seqnames=seqnames_col, start_end_cols[[1L]], width=width_col, strand=strand_col) } .get_data_frame_col_as_numeric <- function(df, col) { ans <- df[[col]] if (is(ans, "Rle")) ans <- S4Vectors:::decodeRle(ans) if (!is.numeric(ans)) { if (is.factor(ans)) ans <- as.character(ans) ans <- suppressWarnings(as.numeric(ans)) if (anyNA(ans)) stop(wmsg("some values in the ", "\"", names(df)[[col]], "\" ", "column cannot be turned into numeric values")) } ans } ### 'df' must be a data.frame or DataFrame object. makeGRangesFromDataFrame <- function(df, keep.extra.columns=FALSE, ignore.strand=FALSE, seqinfo=NULL, seqnames.field=c("seqnames", "seqname", "chromosome", "chrom", "chr", "chromosome_name", "seqid"), start.field="start", end.field=c("end", "stop"), strand.field="strand", starts.in.df.are.0based=FALSE) { ## Check args. if (is.character(df)) # for people that provide the path to a file stop("'df' must be a data.frame or DataFrame object") if (!(is.data.frame(df) || is(df, "DataFrame"))) df <- as.data.frame(df) if (!isTRUEorFALSE(keep.extra.columns)) stop("'keep.extra.columns' must be TRUE or FALSE") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") ans_seqinfo <- .normarg_seqinfo(seqinfo) if (!isTRUEorFALSE(starts.in.df.are.0based)) stop("'starts.in.df.are.0based' must be TRUE or FALSE") granges_cols <- .find_GRanges_cols(names(df), seqnames.field=seqnames.field, start.field=start.field, end.field=end.field, strand.field=strand.field, ignore.strand=ignore.strand) ## Prepare 'ans_seqnames'. ans_seqnames <- df[[granges_cols[["seqnames"]]]] ## Prepare 'ans_ranges'. ans_start <- .get_data_frame_col_as_numeric(df, granges_cols[["start"]]) ans_end <- .get_data_frame_col_as_numeric(df, granges_cols[["end"]]) if (starts.in.df.are.0based) ans_start <- ans_start + 1L ans_names <- rownames(df) if (identical(ans_names, as.character(seq_len(nrow(df))))) ans_names <- NULL ans_ranges <- IRanges(ans_start, ans_end, names=ans_names) ## Prepare 'ans_strand'. if (is.na(granges_cols[["strand"]]) || ignore.strand) { ans_strand <- "*" } else { ans_strand <- as.character(df[[granges_cols[["strand"]]]]) ans_strand[ans_strand %in% "."] <- "*" } ## Prepare 'ans_mcols'. if (keep.extra.columns) { drop_idx <- c(granges_cols[["seqnames"]], granges_cols[["start"]], granges_cols[["end"]]) if (!is.na(granges_cols[["width"]])) drop_idx <- c(drop_idx, granges_cols[["width"]]) if (!is.na(granges_cols[["strand"]])) drop_idx <- c(drop_idx, granges_cols[["strand"]]) ans_mcols <- df[-drop_idx] } else { ans_mcols <- NULL } ## Prepare 'ans_seqinfo'. if (is.null(ans_seqinfo)) { ## Only if 'ans_seqnames' is a factor-Rle, we preserve the seqlevels ## in the order they are in 'levels(ans_seqnames)'. Otherwise, we ## order them according to rankSeqlevels(). seqlevels <- levels(ans_seqnames) if (is.null(seqlevels)) { seqlevels <- unique(ans_seqnames) if (!is.character(seqlevels)) seqlevels <- as.character(seqlevels) } if (!(is(ans_seqnames, "Rle") && is.factor(runValue(ans_seqnames)))) seqlevels[rankSeqlevels(seqlevels)] <- seqlevels ans_seqinfo <- Seqinfo(seqlevels) } ## Make and return the GRanges object. GRanges(ans_seqnames, ans_ranges, strand=ans_strand, ans_mcols, seqinfo=ans_seqinfo) } setAs("data.frame", "GRanges", function(from) makeGRangesFromDataFrame(from, keep.extra.columns=TRUE) ) setAs("DataFrame", "GRanges", function(from) makeGRangesFromDataFrame(from, keep.extra.columns=TRUE) ) GenomicRanges/R/makeGRangesListFromDataFrame.R0000644000175400017540000000276613175713746022307 0ustar00biocbuildbiocbuild### ========================================================================= ### makeGRangesListFromDataFrame() ### ------------------------------------------------------------------------- ### 'df' must be a data.frame or DataFrame object. makeGRangesListFromDataFrame <- function(df, split.field = NULL, names.field = NULL, ...) { splitIdx <- namesIdx <- integer() if (!is.null(split.field)) { if (!isSingleString(split.field)) stop("'split.field' must be a single string") splitIdx <- which(names(df) %in% split.field) if (!length(splitIdx)) stop("'split.field' is not in 'names(df)'") if (length(splitIdx) > 1L) stop("'split.field' matched more than one 'names(df)'") splitField <- df[[split.field]] } else splitField <- seq_len(nrow(df)) if (!is.null(names.field)) { if (!isSingleString(names.field)) stop("'names.field' must be a single string") namesIdx <- which(names(df) %in% names.field) if (!length(namesIdx)) stop("'names.field' is not found in 'names(df)'") if (length(namesIdx) > 1L) stop("'names.field' matched more than one 'names(df)'") namesField <- df[[names.field]] } else namesField <- NULL if (length(c(splitIdx, namesIdx))) df <- df[, -c(splitIdx, namesIdx)] gr <- makeGRangesFromDataFrame(df, ...) names(gr) <- namesField S4Vectors::split(gr, splitField) } GenomicRanges/R/nearest-methods.R0000644000175400017540000003777113175713746020004 0ustar00biocbuildbiocbuild### ========================================================================= ### nearest (and related) methods ### ------------------------------------------------------------------------- ### ### Dependencies : ### ### distanceToNearest ### | | ### nearest distance ### | | ### precede follow .orderNumeric <- function(x) # unstable order sort.list(x, na.last=NA, method="quick") .GenomicRanges_findNearest0 <- function (query, subject, sentinel, leftOf=TRUE) ## query 'leftOf' subject { zeroInSubject <- subject %in% 0L if (any(zeroInSubject)) subject <- unique(c(subject, sentinel)) else subject <- c(subject, sentinel) ord <- .orderNumeric(subject) subject <- subject[ord] rle <- Rle(subject) subject <- runValue(rle) ## zero in query i <- findInterval(query - !leftOf, subject) + leftOf zeroInQuery <- i %in% 0L if (any(zeroInQuery)) { if (leftOf) i[zeroInQuery] <- 2L else i[zeroInQuery] <- 1L } ## zero in subject if (any(zeroInSubject)) i[subject[i] %in% sentinel & subject[i] != 0L] <- NA_integer_ else i[subject[i] %in% sentinel] <- NA_integer_ IRanges:::vectorToHits(i, rle, ord) } .findNearest_distance <- function(hit, query, subject, leftOf=TRUE) ## query 'leftOf' of subject { if (leftOf) start(subject)[subjectHits(hit)] - end(query)[queryHits(hit)] else start(query)[queryHits(hit)] - end(subject)[subjectHits(hit)] } .Hits <- function(queryHits, subjectHits, queryLength=as.integer(max(c(0, queryHits))), subjectLength=as.integer(max(c(0, subjectHits)))) { o <- orderIntegerPairs(queryHits, subjectHits) Hits(queryHits[o], subjectHits[o], queryLength, subjectLength, sort.by.query=TRUE) } .findPrecedeFollow_pmin <- function(hit0, dist0, hit1, dist1) ## hit0, hit1 are (possibly multiple) hits on same query; repeated ## hits are equidistant within hit0 or hit1, but not necessarily ## between { stopifnot(queryLength(hit0) == queryLength(hit1)) stopifnot(subjectLength(hit0) == subjectLength(hit1)) stopifnot(length(hit0) == length(dist0) || length(hit1) == length(dist1)) n <- queryLength(hit0) d0 <- d1 <- integer() d0[n] <- d1[n] <- NA_integer_ i0 <- queryHits(hit0) i1 <- queryHits(hit1) d0[i0] <- dist0 d1[i1] <- dist1 dMin <- pmin.int(d0, d1, na.rm=TRUE) i0 <- dist0 == dMin[i0] i1 <- dist1 == dMin[i1] .Hits(c(queryHits(hit0)[i0], queryHits(hit1)[i1]), c(subjectHits(hit0)[i0], subjectHits(hit1)[i1]), queryLength(hit0), subjectLength(hit0)) } .GenomicRanges_findPrecedeFollow <- function(query, subject, select, ignore.strand, where=c("precede", "follow")) { if (!length(query) || !length(subject)) return(Hits(nLnode=length(query), nRnode=length(subject), sort.by.query=TRUE)) leftOf <- "precede" == match.arg(where) if (ignore.strand) strand(query) <- strand(subject) <- "+" if (leftOf) { plusfun <- function(xstart, xend, ystart, yend, sentinel) .GenomicRanges_findNearest0(xend, ystart, sentinel, leftOf) minusfun <- function(xstart, xend, ystart, yend, sentinel) .GenomicRanges_findNearest0(xstart, yend, sentinel, !leftOf) } else { plusfun <- function(xstart, xend, ystart, yend, sentinel) .GenomicRanges_findNearest0(xstart, yend, sentinel, leftOf) minusfun <- function(xstart, xend, ystart, yend, sentinel) .GenomicRanges_findNearest0(xend, ystart, sentinel, !leftOf) } ## sentinels marking seqlevels ends endq <- start(query) + width(query) # end(query) incorrect for 0-width ends <- start(subject) + width(subject) maxend <- max(max(endq), max(ends)) + 1 lvls <- union(seqlevels(query), seqlevels(subject)) offset <- setNames((seq_along(lvls) - 1) * maxend, lvls) stopifnot(typeof(offset) == "double") # avoid integer overflow sentinel <- c(0, seq_along(lvls) * maxend) ## offset for sentinels queryOff <- unname(offset[as.character(seqnames(query))]) queryStart <- start(query) + queryOff queryEnd <- end(query) + queryOff # true end + offset qid <- seq_along(query) subjectOff <- unname(offset[as.character(seqnames(subject))]) subjectStart <- start(subject) + subjectOff subjectEnd <- end(subject) + subjectOff # true end + offset spid <- which(strand(subject) != "-") smid <- which(strand(subject) != "+") ## '+' or '*' query idx <- which(strand(query) != "-") phit <- plusfun(queryStart[idx], queryEnd[idx], subjectStart[spid], subjectEnd[spid], sentinel) phit <- .Hits(qid[idx][queryHits(phit)], spid[subjectHits(phit)]) ## '-' or '*' query idx <- which(strand(query) != "+") mhit <- minusfun(queryStart[idx], queryEnd[idx], subjectStart[smid], subjectEnd[smid], sentinel) mhit <- .Hits(qid[idx][queryHits(mhit)], smid[subjectHits(mhit)]) ## When both query and subject are '*', treat as if on '+' strand. ## This combo was tested in 'phit' and should be removed from 'mhit'. sstar <- which(strand(subject) == "*") qstar <- which(strand(query) == "*") remove <- queryHits(mhit) %in% qstar & subjectHits(mhit) %in% sstar mhit <- mhit[!remove] ## clean up qryHits <- c(queryHits(phit), queryHits(mhit)) subjHits <- c(subjectHits(phit), subjectHits(mhit)) hits <- .Hits(qryHits, subjHits, length(query), length(subject)) if (select == "all") { hits } else if (select == "first") { first <- rep(NA_integer_, length(query)) idx <- which(!duplicated(queryHits(hits))) first[queryHits(hits)[idx]] <- subjectHits(hits)[idx] first } else if ("last" == select) { last <- rep(NA_integer_, length(query)) rev_query <- rev(queryHits(hits)) ## can't call rev() on Hits idx <- which(!duplicated(rev_query)) last[rev_query[idx]] <- rev(subjectHits(hits))[idx] last } else stop("'select' must be one of c('first', 'last', 'all')") } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### precede() and follow() ### setMethod("precede", c("GenomicRanges", "GenomicRanges"), function(x, subject, select=c("first", "all"), ignore.strand=FALSE) { select <- match.arg(select) .GenomicRanges_findPrecedeFollow(x, subject, select, ignore.strand, "precede") } ) setMethod("precede", c("GenomicRanges", "missing"), function(x, subject, select=c("first", "all"), ignore.strand=FALSE) { select <- match.arg(select) .GenomicRanges_findPrecedeFollow(x, subject, select, ignore.strand, "precede") } ) setMethod("follow", c("GenomicRanges", "GenomicRanges"), function(x, subject, select=c("last", "all"), ignore.strand=FALSE) { select <- match.arg(select) .GenomicRanges_findPrecedeFollow(x, subject, select, ignore.strand, "follow") } ) setMethod("follow", c("GenomicRanges", "missing"), function(x, subject, select=c("last", "all"), ignore.strand=FALSE) { select <- match.arg(select) .GenomicRanges_findPrecedeFollow(x, subject, select, ignore.strand, "follow") } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### nearest() ### .filterHits <- function(hits, i, map) { m <- as.matrix(hits[as(hits, "IRanges")[i]]) m[, 1L] <- map[m[, 1L]] m } .nearest <- function(x, subject, select, ignore.strand, drop.self=FALSE) { ## overlapping ranges if (drop.self) { ol <- findOverlaps(x, maxgap=0L, select=select, ignore.strand=ignore.strand, drop.self=TRUE) } else { ol <- findOverlaps(x, subject, maxgap=0L, select=select, ignore.strand=ignore.strand) } if (select == "all") { olv <- selectHits(ol, select="first") } else { olv <- ol } ## non-overlapping ranges if (length(x <- x[is.na(olv)]) != 0) { ## precede() and follow() do not support select="arbitrary" if (select == "arbitrary") { p <- precede(x, subject, select="first", ignore.strand) f <- follow(x, subject, select="last", ignore.strand) } else { p <- precede(x, subject, select, ignore.strand) f <- follow(x, subject, select, ignore.strand) } ## terminate if no results if (!length(p) && !length(f)) { if (is(olv, "Hits") && !length(olv) || all(is.na(olv))) { if (select == "all") return(Hits(nLnode=length(x), nRnode=length(subject), sort.by.query=TRUE)) else if (select == "arbitrary") return (rep(NA, length(x))) } } if (select == "all") { p0 <- p p <- selectHits(p, select="first") f0 <- f f <- selectHits(f, select="last") } ## choose nearest or not missing pdist <- .nearestDistance(x, subject, p) fdist <- .nearestDistance(x, subject, f) pnearest <- ifelse(pdist == fdist, p < f, pdist < fdist) isNA <- is.na(pnearest) pnearest[isNA] <- is.na(f[isNA]) if (select == "all") { map <- which(is.na(olv)) pnearest[pdist == fdist] <- TRUE m <- rbind(as.matrix(ol), .filterHits(p0, pnearest, map), .filterHits(f0, !pnearest, map)) m <- m[orderIntegerPairs(m[, 1L], m[, 2L]),, drop=FALSE] ol@from <- unname(m[, 1L]) ol@to <- unname(m[, 2L]) } else { olv[is.na(olv)] <- ifelse(pnearest, p, f) ol <- olv } } ol } .nearestDistance <- function(x, subject, index) { if (length(index)) { maxStart <- pmax.int(start(x), start(subject)[index]) minEnd <- pmin.int(end(x), end(subject)[index]) pmax.int(maxStart - minEnd - 1L, 0L) } else NA } setMethod("nearest", c("GenomicRanges", "GenomicRanges"), function(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) { select <- match.arg(select) .nearest(x, subject, select=select, ignore.strand=ignore.strand) } ) setMethod("nearest", c("GenomicRanges", "missing"), function(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) { select <- match.arg(select) .nearest(x, x, select=select, ignore.strand=ignore.strand, drop.self=TRUE) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### distance() ### setMethod("distance", c("GenomicRanges", "GenomicRanges"), function(x, y, ignore.strand=FALSE, ...) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") d <- distance(ranges(x), ranges(y)) mismtch <- as.character(seqnames(x)) != as.character(seqnames(y)) if (any(mismtch)) d[mismtch] <- NA if (!ignore.strand) { idx <- as.numeric(strand(x)) + as.numeric(strand(y)) if (any(idx == 3)) d[idx == 3] <- NA } d } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### distanceToNearest() ### setMethod("distanceToNearest", c("GenomicRanges", "GenomicRanges"), function(x, subject, ignore.strand=FALSE, ...) { x_nearest <- nearest(x, subject, ignore.strand=ignore.strand, ...) .distanceToNearest(x_nearest, x, subject, ignore.strand=ignore.strand) } ) setMethod("distanceToNearest", c("GenomicRanges", "missing"), function(x, subject, ignore.strand=FALSE, ...) { x_nearest <- nearest(x, ignore.strand=ignore.strand, ...) .distanceToNearest(x_nearest, x, x, ignore.strand=ignore.strand) } ) .distanceToNearest <- function(x_nearest, x, subject, ignore.strand) { ## 'x_nearest' is Hits when select = all if (is(x_nearest, "Hits")) { queryHits <- queryHits(x_nearest) subjectHits <- subjectHits(x_nearest) } else { ## 'x_nearest' is Integer vector when select = arbitrary queryHits <- seq_along(x)[!is.na(x_nearest)] subjectHits <- x_nearest[!is.na(x_nearest)] } if (!length(subjectHits) || all(is.na(subjectHits))) { Hits(nLnode=length(x), nRnode=length(subject), distance=integer(0), sort.by.query=TRUE) } else { distance <- distance(x[queryHits], subject[subjectHits], ignore.strand=ignore.strand) Hits(queryHits, subjectHits, length(x), length(subject), distance, sort.by.query=TRUE) } } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### precedes() and follows() ### .normBounds <- function(x) { if (is(x, "GRangesList")) { x <- range(x) if (all(lengths(x) == 1L)) { x <- unlist(x) } else { stop("operation undefined when ranges cross seqnames and strands") } } x } precedes <- function(x, y) { x <- .normBounds(x) y <- .normBounds(y) seqnames(x) == seqnames(y) & ifelse(strand(y) == "-", start(x) > end(y), end(x) < start(y)) } follows <- function(x, y) { x <- .normBounds(x) y <- .normBounds(y) seqnames(x) == seqnames(y) & ifelse(strand(y) == "-", end(x) < start(y), start(x) > end(y)) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Find 'k' nearest neighbors ### ### FIXME: Largely untested code; unexported for now ### findKNN <- function(query, subject, k=5L, ignore.overlaps = FALSE, ignore.strand = FALSE) { seqlevels(subject) <- seqlevels(query) starts <- with(subject, GRanges(seqnames, IRanges(start, width=1L), strand)) ends <- with(subject, GRanges(seqnames, IRanges(end, width=1L), strand)) if (ignore.strand) { starts <- unstrand(starts) ends <- unstrand(ends) } start_ord <- order(starts) end_ord <- order(ends) starts <- starts[start_ord] ends <- ends[end_ord] phits <- precede(query, starts, ignore.strand=ignore.strand) fhits <- follow(query, ends, ignore.strand=ignore.strand) if (!ignore.strand) { exchange <- decode(strand(query) == "-") tmp <- phits[exchange] phits[exchange] <- fhits[exchange] fhits[exchange] <- tmp } findPart <- function(x, w) { S4Vectors:::findIntervalAndStartFromWidth(x, w)[["interval"]] } if (!ignore.strand) { b <- width(disjoin(c(ranges(seqnames(starts)), ranges(strand(starts))))) } else { b <- runLength(seqnames(starts)) } seqends <- end(seqnames(starts))[findPart(phits, b)] phits[is.na(phits)] <- 1L seqends[is.na(seqends)] <- 0L pwindows <- restrict(IRanges(phits, width = k), end=seqends) seqstarts <- start(seqnames(ends))[findPart(fhits, b)] seqstarts[is.na(seqstarts)] <- 1L fhits[is.na(fhits)] <- 0L fwindows <- restrict(IRanges(end=fhits, width = k), seqstarts) dist <- pc(extractList(start(starts), pwindows) - end(query), end(query) - extractList(end(ends), fwindows)) ans <- pc(extractList(start_ord, pwindows), extractList(end_ord, fwindows)) if (!ignore.overlaps) { hits <- findOverlaps(query, subject, ignore.strand=ignore.strand) hitsList <- as(hits, "List") dist <- pc(dist, relist(rep(0L, length(hits)), hitsList)) ans <- pc(ans, hitsList) } ans[phead(order(dist), k)] } GenomicRanges/R/phicoef.R0000644000175400017540000000153113175713746016300 0ustar00biocbuildbiocbuild### Based on http://en.wikipedia.org/wiki/Phi_coefficient phicoef <- function(x, y=NULL) { if (is.null(y)) { if (!is.integer(x) || length(x) != 4L) stop("when 'y' is not supplied, 'x' must be ", "a 2x2 integer matrix or an integer vector of length 4") a <- x[1L] c <- x[2L] b <- x[3L] d <- x[4L] } else { if (!is.logical(x) || !is.logical(y) || length(x) != length(y)) stop("when 'y' is supplied, 'x' and 'y' must be ", "2 logical vectors of the same length") a <- sum(x & y) b <- sum(x & !y) c <- sum(!x & y) d <- sum(!x & !y) } a <- as.double(a) b <- as.double(b) c <- as.double(c) d <- as.double(d) div <- sqrt((a + b) * (c + d) * (a + c) * (b + d)) (a * d - b * c) / div } GenomicRanges/R/setops-methods.R0000644000175400017540000004562713175713746017657 0ustar00biocbuildbiocbuild### ========================================================================= ### Set operations ### ------------------------------------------------------------------------- ### TODO: What's the impact of circularity on the set operations? ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 3 low-level helper functions. ### ### A fast implementation of 'mendoapply(FUN, x, y)' for GRangesList objects. ### Assume 'x' and 'y' are 2 GRangesList objects (not checked) of the same ### length (checked). .fast_binary_mendoapply <- function(FUN, x, y, ...) { FUN <- match.fun(FUN) if (length(x) != length(y)) stop("'x' and 'y' must have the same length") seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) seqlevels(y) <- seqlevels(x) xgr <- deconstructGRLintoGR(x) ygr <- deconstructGRLintoGR(y) seqinfo(xgr) <- suppressWarnings(merge(seqinfo(xgr), seqinfo(ygr))) seqlevels(ygr) <- seqlevels(xgr) gr <- FUN(xgr, ygr, ...) reconstructGRLfromGR(gr, x) } ### Both return a named integer vector where the names are guaranteed to be ### 'seqlevels(x)'. ### .minStartPerGRangesSequence <- function(x) { cil <- splitAsList(start(x), seqnames(x)) # CompressedIntegerList object ## The 4 lines below are equivalent to: ## ans <- min(cil) ## ans[elementNROWS(v) == 0L] <- NA_integer_ ## but much faster! ## TODO: Replace with the above, but only when the "min" method for ## CompressedIntegerList objects (implemented in the IRanges package) ## is as fast as the "viewMins" method for XIntegerViews objects ## (implemented in C in the XVector package). Ideally, the 2 methods ## should share the same underlying code. v <- Views(cil@unlistData, cil@partitioning) # XIntegerViews object ans <- viewMins(v) ans[width(v) == 0L] <- NA_integer_ names(ans) <- names(v) ans } .maxEndPerGRangesSequence <- function(x) { cil <- splitAsList(end(x), seqnames(x)) # CompressedIntegerList object ## The 4 lines below are equivalent to: ## ans <- max(cil) ## ans[elementNROWS(v) == 0L] <- NA_integer_ ## but much faster! ## TODO: Replace with the above, but only when the "max" method for ## CompressedIntegerList objects (implemented in the IRanges package) ## is as fast as the "viewMaxs" method for XIntegerViews objects ## (implemented in C in the XVector package). Ideally, the 2 methods ## should share the same underlying code. v <- Views(cil@unlistData, cil@partitioning) # XIntegerViews object ans <- viewMaxs(v) ans[width(v) == 0L] <- NA_integer_ names(ans) <- names(v) ans } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### union(), intersect(), setdiff() ### ### Always return a GRanges *instance* whatever GenomicRanges derivatives are ### passed to it (e.g. GPos or GNCList), so does NOT act like an endomorphism ### in general. setMethod("union", c("GenomicRanges", "GenomicRanges"), function(x, y, ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") x <- granges(x) y <- granges(y) if (ignore.strand) strand(x) <- strand(y) <- "*" reduce(c(x, y), drop.empty.ranges=TRUE) } ) .unsupported_union <- function(x, y) stop("union() between a ", class(x), " and a ", class(y), " object ", "is not supported") setMethod("union", c("GenomicRanges", "Vector"), .unsupported_union) setMethod("union", c("Vector", "GenomicRanges"), .unsupported_union) setMethod("union", c("GRangesList", "GRangesList"), function(x, y, ...) .fast_binary_mendoapply("union", x, y, ...) ) ### Always return a GRanges *instance* whatever GenomicRanges derivatives are ### passed to it (e.g. GPos or GNCList), so does NOT act like an endomorphism ### in general. setMethod("intersect", c("GenomicRanges", "GenomicRanges"), function(x, y, ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") x <- granges(x) y <- granges(y) if (ignore.strand) strand(x) <- strand(y) <- "*" seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) ## If merge() is going to issue a warning, we don't want to get ## it twice. seqinfo(y) <- suppressWarnings(merge(seqinfo(y), seqinfo(x))) seqlengths <- seqlengths(x) ## If the length of a sequence is unknown (NA), then we use ## the max end value found on that sequence in 'x' or 'y'. seqlengths[is.na(seqlengths)] <- .maxEndPerGRangesSequence(c(x, y))[is.na(seqlengths)] setdiff(x, gaps(y, end=seqlengths)) } ) .unsupported_intersect <- function(x, y) stop("intersect() between a ", class(x), " and a ", class(y), " object ", "is not supported") setMethod("intersect", c("GenomicRanges", "Vector"), .unsupported_intersect) setMethod("intersect", c("Vector", "GenomicRanges"), .unsupported_intersect) setMethod("intersect", c("GRangesList", "GRangesList"), function(x, y, ...) .fast_binary_mendoapply("intersect", x, y, ...) ) ### Always return a GRanges *instance* whatever GenomicRanges derivatives are ### passed to it (e.g. GPos or GNCList), so does NOT act like an endomorphism ### in general. setMethod("setdiff", c("GenomicRanges", "GenomicRanges"), function(x, y, ignore.strand=FALSE) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") x <- granges(x) y <- granges(y) if (ignore.strand) strand(x) <- strand(y) <- "*" seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) ## If merge() is going to issue a warning, we don't want to get ## it twice. seqinfo(y) <- suppressWarnings(merge(seqinfo(y), seqinfo(x))) seqlengths <- seqlengths(x) ## If the length of a sequence is unknown (NA), then we use ## the max end value found on that sequence in 'x' or 'y'. seqlengths[is.na(seqlengths)] <- .maxEndPerGRangesSequence(c(x, y))[is.na(seqlengths)] gaps(union(gaps(x, end=seqlengths), y), end=seqlengths) } ) .unsupported_setdiff <- function(x, y) stop("setdiff() between a ", class(x), " and a ", class(y), " object ", "is not supported") setMethod("setdiff", c("GenomicRanges", "Vector"), .unsupported_setdiff) setMethod("setdiff", c("Vector", "GenomicRanges"), .unsupported_setdiff) setMethod("setdiff", c("GRangesList", "GRangesList"), function(x, y, ...) .fast_binary_mendoapply("setdiff", x, y, ...) ) ### ========================================================================= ### Parallel set operations ### ------------------------------------------------------------------------- ## check for equality without requiring identical level sets ## instead, one level set must be subset of the other, like merge,Seqinfo compatibleSeqnames <- function(x, y) { if (length(x) != length(y)) stop("'x' and 'y' must be of equal length") if (!is(x, "Rle") || !is(y, "Rle")) stop("'x' and 'y' must be Rle objects") xLevels <- levels(x) yLevels <- levels(y) if (length(xLevels) > length(yLevels)) diffLevels <- setdiff(yLevels, xLevels) else diffLevels <- setdiff(xLevels, yLevels) if (length(diffLevels)) stop("Level set of 'x' must be subset of that of 'y', or vice versa") runValue(x) <- as.character(runValue(x)) runValue(y) <- as.character(runValue(y)) x == y } allCompatibleSeqnamesAndStrand <- function(x, y) { all(compatibleSeqnames(seqnames(x), seqnames(y)) & compatibleStrand(strand(x), strand(y))) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### punion() ### setMethod("punion", c("GRanges", "GRanges"), function(x, y, fill.gap=FALSE, ignore.strand=FALSE) { if (length(x) != length(y)) stop("'x' and 'y' must have the same length") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(y) <- strand(x) mcols(x) <- NULL seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) if (!allCompatibleSeqnamesAndStrand(x, y)) stop("'x' and 'y' elements must have compatible 'seqnames' ", "and 'strand' values") ranges(x) <- punion(ranges(x), ranges(y), fill.gap=fill.gap) x } ) ### FIXME: This is currently not doing a "punion" at all. It just appends ### the ranges in 'y' to their corresponding element in 'x'. ### 2 proposals for a more punion-like semantic: ### (a) for (i in seq_len(length(x))) ### x[[i]] <- punion(x[[i]], y[rep.int(i, length(x[[i]]))]) ### (b) for (i in seq_len(length(x))) ### x[[i]] <- union(x[[i]], y[i]) ### Note that behaviour (b) could also be considered a valid candidate for ### a union,GRangesList,GRanges method (which we don't have at the moment). setMethod("punion", c("GRangesList", "GRanges"), function(x, y, fill.gap=FALSE) { n <- length(x) if (n != length(y)) stop("'x' and 'y' must have the same length") mcols(x@unlistData) <- NULL mcols(y) <- NULL ans <- split(c(x@unlistData, y), c(Rle(seq_len(n), elementNROWS(x)), Rle(seq_len(n)))) names(ans) <- names(x) ans } ) setMethod("punion", c("GRanges", "GRangesList"), function(x, y, ...) callGeneric(y, x, ...) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### pintersect() ### ### 'x' and 'y' must have the same length. An 'y' of length 1 is accepted and ### is recycled to the length of 'x'. ### Return a GRanges object. If 'drop.nohit.ranges' is FALSE (the default) the ### returned object is parallel to 'x' with the original ranges modified ### (seqnames, names, and metadata are untouched), so this can be seen as an ### "intra-range transformation". The original metadata columns are propagated ### and a new "hit" column added to them to indicate elements in 'x' that ### intersect with the corresponding element in 'y'. For these elements the ### range in the returned object is guaranteed to be a subrange of the ### original ranges. If 'ignore.strand' or 'strict.strand' is TRUE, then the ### returned GRanges has the same strand as 'x'. Otherwise, for elements in 'x' ### that are on the "*" strand and hit the corresponding element in 'y', it ### has the strand of 'y'. ### If 'drop.nohit.ranges' is TRUE everything is the same except that elements ### in 'x' that don't intersect with the corresponding element in 'y' are ### removed from the result (so the result is no more parallel to the input) ### and no "hit" metadata column is added to it. .pintersect_GRanges_GRanges <- function(x, y, drop.nohit.ranges=FALSE, ignore.strand=FALSE, strict.strand=FALSE) { stopifnot(is(x, "GRanges"), is(y, "GRanges")) if (length(y) != length(x)) { if (length(y) != 1L) stop(wmsg("'y' must have the length of 'x' or length 1")) y <- rep.int(y, length(x)) } if (!isTRUEorFALSE(drop.nohit.ranges)) stop(wmsg("'drop.nohit.ranges' must be TRUE or FALSE")) if (!isTRUEorFALSE(ignore.strand)) stop(wmsg("'ignore.strand' must be TRUE or FALSE")) if (!isTRUEorFALSE(strict.strand)) stop(wmsg("'strict.strand' must be TRUE or FALSE")) if (ignore.strand) { if (strict.strand) warning(wmsg("'strict.strand' is ignored ", "when 'ignore.strand' is TRUE")) strand(y) <- strand(x) } else if (!strict.strand) { x_strand <- strand(x) idx <- strand(x) == "*" & strand(y) != "*" strand(x)[idx] <- strand(y)[idx] idx <- strand(y) == "*" & strand(x) != "*" strand(y)[idx] <- strand(x)[idx] } x_seqlevels <- seqlevels(x) ## Check compatibility of underlying genomes. seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) ## Align the seqlevels of 'y' to those of 'x' so that comparing the ## seqnames of the 2 objects thru as.integer(seqnames()) is meaningful). seqlevels(y) <- seqlevels(x) ## Restore original seqlevels on 'x' (this preserves their order). seqlevels(x) <- x_seqlevels new_start <- pmax.int(start(x), start(y)) new_end <- pmin.int(end(x), end(y)) is_hit <- as.integer(seqnames(x)) == as.integer(seqnames(y)) & strand(x) == strand(y) & new_end >= new_start - 1L if (drop.nohit.ranges) { x <- extractROWS(x, is_hit) new_start <- extractROWS(new_start, is_hit) new_end <- extractROWS(new_end, is_hit) new_names <- names(x) } else { ## For elements in 'x' and 'y' that don't hit each other, we return ## an artificial zero-width intersection that starts on 'start(x)'. nohit_idx <- which(!is_hit) nohit_start <- start(x)[nohit_idx] new_start[nohit_idx] <- nohit_start new_end[nohit_idx] <- nohit_start - 1L new_names <- names(x) mcols(x)$hit <- as.logical(is_hit) if (!(ignore.strand || strict.strand)) strand(x)[nohit_idx] <- x_strand[nohit_idx] } ranges(x) <- IRanges(new_start, new_end, names=new_names) x } setMethod("pintersect", c("GRanges", "GRanges"), function(x, y, drop.nohit.ranges=FALSE, ignore.strand=FALSE, strict.strand=FALSE) .pintersect_GRanges_GRanges(x, y, drop.nohit.ranges=drop.nohit.ranges, ignore.strand=ignore.strand, strict.strand=strict.strand) ) ### This is equivalent to 'mendoapply(pintersect, x, y)'. Therefore the ### returned GRangesList object has the same shape as 'x'. ### To get the 'mendoapply(intersect, x, y)' behavior, the user should use ### 'strict.strand=TRUE' and call 'reduce( , drop.empty.ranges=TRUE)' on ### the returned object. .pintersect_GRangesList_GRanges <- function(x, y, drop.nohit.ranges=FALSE, ignore.strand=FALSE, strict.strand=FALSE) { stopifnot(is(x, "GRangesList"), is(y, "GRanges")) if (length(y) != length(x)) { if (length(y) != 1L) stop(wmsg("'y' must have the length of 'x' or length 1")) y <- rep.int(y, length(x)) } if (!isTRUEorFALSE(drop.nohit.ranges)) stop(wmsg("'drop.nohit.ranges' must be TRUE or FALSE")) unlisted_x <- unlist(x, use.names=FALSE) y2 <- rep.int(y, elementNROWS(x)) ## 'unlisted_ans' parallel to 'x'. unlisted_ans <- .pintersect_GRanges_GRanges(unlisted_x, y2, drop.nohit.ranges=FALSE, ignore.strand=ignore.strand, strict.strand=strict.strand) if (drop.nohit.ranges) { is_hit <- relist(mcols(unlisted_ans)$hit, x) mcols(unlisted_ans)$hit <- NULL ans <- relist(unlisted_ans, x)[is_hit] } else { ans <- relist(unlisted_ans, x) } ans } setMethod("pintersect", c("GRangesList", "GRanges"), function(x, y, drop.nohit.ranges=FALSE, ignore.strand=FALSE, strict.strand=FALSE) .pintersect_GRangesList_GRanges(x, y, drop.nohit.ranges=drop.nohit.ranges, ignore.strand=ignore.strand, strict.strand=strict.strand) ) setMethod("pintersect", c("GRanges", "GRangesList"), function(x, y, drop.nohit.ranges=FALSE, ignore.strand=FALSE, strict.strand=FALSE) .pintersect_GRangesList_GRanges(y, x, drop.nohit.ranges=drop.nohit.ranges, ignore.strand=ignore.strand, strict.strand=strict.strand) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### psetdiff() ### setMethod("psetdiff", c("GRanges", "GRanges"), function(x, y, ignore.strand=FALSE) { if (length(x) != length(y)) stop("'x' and 'y' must have the same length") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(y) <- strand(x) mcols(x) <- NULL seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) ok <- compatibleSeqnames(seqnames(x), seqnames(y)) & compatibleStrand(strand(x), strand(y)) ## Update the ranges. ansRanges <- ranges(x) ansRanges <- replaceROWS(ansRanges, ok, callGeneric(extractROWS(ranges(x), ok), extractROWS(ranges(y), ok))) ranges(x) <- ansRanges ## Update the strand. ansStrand <- strand(x) resolveStrand <- as(ansStrand == "*", "IRanges") if (length(resolveStrand) > 0L) ansStrand[as.integer(resolveStrand)] <- extractROWS(strand(y), resolveStrand) strand(x) <- ansStrand x } ) ### TODO: Review the semantic of this method (see previous TODO's for ### "punion" and "pintersect" methods for GRanges,GRangesList). setMethod("psetdiff", c("GRanges", "GRangesList"), function(x, y, ignore.strand=FALSE) { ansSeqinfo <- merge(seqinfo(x), seqinfo(y)) if (length(x) != length(y)) stop("'x' and 'y' must have the same length") ok <- compatibleSeqnames(rep(seqnames(x), elementNROWS(y)), seqnames(y@unlistData)) if (!ignore.strand) ok <- ok & compatibleStrand(rep(strand(x), elementNROWS(y)), strand(y@unlistData)) if (!all(ok)) { ok <- new2("CompressedLogicalList", unlistData=as.vector(ok), partitioning=y@partitioning) y <- y[ok] } ansRanges <- gaps(ranges(y), start=start(x), end=end(x)) ansSeqnames <- rep(seqnames(x), elementNROWS(ansRanges)) ansStrand <- rep(strand(x), elementNROWS(ansRanges)) ansGRanges <- GRanges(ansSeqnames, unlist(ansRanges, use.names=FALSE), ansStrand) seqinfo(ansGRanges) <- ansSeqinfo relist(ansGRanges, PartitioningByEnd(ansRanges)) } ) setMethod("pgap", c("GRanges", "GRanges"), function(x, y, ignore.strand=FALSE, ...) { if (length(x) != length(y)) stop("'x' and 'y' must have the same length") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(y) <- strand(x) mcols(x) <- NULL seqinfo(x) <- merge(seqinfo(x), seqinfo(y)) if (!allCompatibleSeqnamesAndStrand(x, y)) stop("'x' and 'y' elements must have compatible 'seqnames' ", "and 'strand' values") ranges(x) <- callGeneric(ranges(x), ranges(y), ...) x } ) GenomicRanges/R/strand-utils.R0000644000175400017540000001373213175713746017322 0ustar00biocbuildbiocbuild### ========================================================================= ### Strand utilities ### ------------------------------------------------------------------------- ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Some "strand" methods ### setMethod("strand", "missing", function(x) factor(levels=c("+","-","*"))) setMethod("strand", "NULL", function(x) strand()) setMethod("strand", "character", function(x) { lvls <- levels(strand()) if (!all(x %in% lvls)) stop("strand values must be in '", paste(lvls, collapse="' '"), "'") factor(x, levels=lvls) } ) setMethod("strand", "factor", function(x) { if (any(is.na(x))) stop("NA not a valid strand value, use \"*\" instead") lvls <- levels(strand()) x_levels <- levels(x) if (identical(x_levels, lvls)) return(x) invalid_levels <- setdiff(x_levels, lvls) if (length(invalid_levels) != 0L) stop("invalid strand levels in 'x': ", paste(invalid_levels, collapse=", ")) factor(x, levels=lvls) } ) setMethod("strand", "integer", function(x) { lvls <- c(1L, -1L, NA) if (!all(x %in% lvls)) stop("strand values must be in '", paste(lvls, collapse="' '"), "'") ans <- rep.int(strand("*"), length(x)) ans[x == 1L] <- "+" ans[x == -1L] <- "-" ans } ) setMethod("strand", "logical", function(x) { ans <- rep.int(strand("*"), length(x)) ans[!x] <- "+" ans[ x] <- "-" ans } ) setMethod("strand", "Rle", function(x) { x_runValue <- runValue(x) if (!(is.character(x_runValue) || is.factor(x_runValue) || is.integer(x_runValue) || is.logical(x_runValue))) stop("\"strand\" method for Rle objects only works on a ", "character-, factor-, integer-, or logical-Rle object") runValue(x) <- strand(x_runValue) x } ) setMethod("strand", "RleList", function(x) relist(strand(unlist(x, use.names=FALSE)), x) ) setMethod("strand", "DataTable", function(x) { ans <- x[["strand"]] if (is.null(ans)) { ans <- rep.int(strand("*"), nrow(x)) } else { ans <- strand(ans) } ans } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Some "strand<-" methods ### normalize_strand_replacement_value <- function(value, x) { if (!is(value, "Rle")) value <- Rle(value) if (!is.factor(runValue(value)) || !identical(levels(runValue(value)), levels(strand()))) runValue(value) <- strand(runValue(value)) S4Vectors:::V_recycle(value, x, x_what="value", skeleton_what="x") } setReplaceMethod("strand", "DataTable", function(x, value) { x$strand <- normalize_strand_replacement_value(value, seq_len(nrow(x))) x } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Some "invertStrand" methods ### .invert_strand_factor <- function(x) { x_codes <- as.integer(x) switch_idx <- which(x_codes <= 2L) x[switch_idx] <- structure(3L - x_codes[switch_idx], levels=levels(x), class=class(x)) x } ### One method for each of the "strand" methods defined above that return a ### factor (except for the method for "missing"). setMethods("invertStrand", list("NULL", "character", "factor", "integer", "logical"), function(x) .invert_strand_factor(strand(x)) ) setMethod("invertStrand", "Rle", function(x) { ans <- strand(x) runValue(ans) <- invertStrand(runValue(ans)) ans } ) setMethod("invertStrand", "RleList", function(x) relist(invertStrand(unlist(x, use.names=FALSE)), x) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### compatibleStrand() generic and methods ### setGeneric("compatibleStrand", signature=c("x","y"), # not exported function(x, y) standardGeneric("compatibleStrand") ) setMethod("compatibleStrand", c("factor", "factor"), # not exported function(x, y) { lvls <- levels(strand()) if (length(x) != length(y)) stop("'x' and 'y' must be of equal length") if (!identical(levels(x), lvls) || !identical(levels(y), lvls)) stop("strand values must be in '", paste(lvls, collapse="' '"), "'") levels(x) <- c("1", "-1", "0") x <- as.integer(as.character(x)) levels(y) <- c("1", "-1", "0") y <- as.integer(as.character(y)) ans <- x * y != -1L if (S4Vectors:::anyMissing(ans)) { fix <- which(is.na(ans)) ans[fix] <- (x[fix] == 0L) | (y[fix] == 0L) if (S4Vectors:::anyMissing(ans)) ans[is.na(ans)] <- FALSE } ans } ) setMethod("compatibleStrand", c("Rle", "Rle"), # not exported function(x, y) { lvls <- levels(strand()) if (length(x) != length(y)) stop("'x' and 'y' must be of equal length") if (!identical(levels(runValue(x)), lvls) || !identical(levels(runValue(y)), lvls)) stop("strand values must be in '", paste(lvls, collapse="' '"), "'") levels(x) <- c("1", "-1", "0") runValue(x) <- as.integer(as.character(runValue(x))) levels(y) <- c("1", "-1", "0") runValue(y) <- as.integer(as.character(runValue(y))) ans <- x * y != -1L if (S4Vectors:::anyMissing(runValue(ans))) { fix <- which(is.na(runValue(ans))) runValue(ans)[fix] <- (runValue(x) == 0L)[fix] | (runValue(y)[fix] == 0L) if (S4Vectors:::anyMissing(runValue(ans))) runValue(ans)[is.na(runValue(ans))] <- FALSE } ans } ) GenomicRanges/R/tile-methods.R0000644000175400017540000000131313175713746017257 0ustar00biocbuildbiocbuild### ========================================================================= ### "tile" and "slidingWindows" methods ### ------------------------------------------------------------------------- ### setMethod("tile", "GenomicRanges", function(x, n, width) { sn <- seqnames(x) strand <- strand(x) x <- ranges(x) tiles <- callGeneric() gr <- GRanges(rep(sn, elementNROWS(tiles)), unlist(tiles), rep(strand, elementNROWS(tiles))) relist(gr, tiles) }) setMethod("slidingWindows", "GenomicRanges", function(x, width, step = 1L) { windows <- slidingWindows(ranges(x), width, step) gr <- rep(granges(x), lengths(windows)) ranges(gr) <- unlist(windows) relist(gr, windows) }) GenomicRanges/R/tileGenome.R0000644000175400017540000001456513175713746016766 0ustar00biocbuildbiocbuild### ========================================================================= ### tileGenome() ### ------------------------------------------------------------------------- .make_breakpoints_for_cut_last_tile_in_chrom <- function(seqlengths, tilewidth) { tile_relative_breakpoints <- lapply(seqlengths, function(seqlength) { nfulltile <- seqlength %/% tilewidth if (nfulltile == 0L) return(seqlength) relative_breakpoints <- ceiling(tilewidth * seq_len(nfulltile)) if (relative_breakpoints[[nfulltile]] >= seqlength) return(relative_breakpoints) c(relative_breakpoints, seqlength) }) chrom_breakpoints <- cumsum(as.numeric(seqlengths)) chrom_offsets <- c(0, head(chrom_breakpoints, n=-1L)) ntile_per_chrom <- elementNROWS(tile_relative_breakpoints) unlist(tile_relative_breakpoints, use.names=FALSE) + rep.int(chrom_offsets, ntile_per_chrom) } ### 'old_breakpoints' and 'new_breakpoints' must be non-negative non-decreasing ### numeric or integer vectors of length >= 1 with no NAs. In addition, ### 'old_breakpoints' must be named. None of this is checked (we trust the ### caller). ### Returns a NumericList (or IntegerList) object with one list element per ### unique new breakpoint. .superimpose_breakpoints <- function(old_breakpoints, new_breakpoints) { ## Set names on 'new_breakpoints'. new_breakpoints <- pmin.int(new_breakpoints, tail(old_breakpoints, 1)) new2old <- 1L + findInterval(new_breakpoints - 1L, old_breakpoints) names(new_breakpoints) <- names(old_breakpoints)[new2old] ## Compute 'all_breakpoints'. all_breakpoints <- c(old_breakpoints, new_breakpoints) unique_idx <- !duplicated(all_breakpoints) all_breakpoints <- all_breakpoints[unique_idx] ## Compute 'all2new' mapping. old2new <- 1L + findInterval(old_breakpoints - 1L, new_breakpoints) all2new <- c(old2new, seq_along(new_breakpoints)) all2new <- all2new[unique_idx] ## Compute and return final result. unname(splitAsList(all_breakpoints, all2new)) } .get_relative_ends <- function(absolute_ends, chrom_breakpoints) { chrom_offsets <- c(0, head(chrom_breakpoints, n=-1L)) names(chrom_offsets) <- names(chrom_breakpoints) absolute_ends <- unlist(absolute_ends, use.names=FALSE) absolute_ends - chrom_offsets[names(absolute_ends)] } .get_relative_starts <- function(relative_ends, seqnames) { relative_starts <- rep.int(1L, length(relative_ends)) run_lens <- runLength(seqnames) run_starts <- c(1L, cumsum(head(run_lens, n=-1L)) + 1L) idx <- S4Vectors:::fancy_mseq(run_lens - 1L, offset=run_starts) relative_starts[idx] <- relative_ends[idx - 1L] + 1L relative_starts } ### 'seqlengths' must be a non-negative numeric or integer vector of length ### >= 1 with no NAs and with unique names. ### Only one of 'ntile' and 'tilewidth' can be specified. tileGenome <- function(seqlengths, ntile, tilewidth, cut.last.tile.in.chrom=FALSE) { if (!isTRUEorFALSE(cut.last.tile.in.chrom)) stop("'cut.last.tile.in.chrom' must be TRUE or FALSE") if (is(seqlengths, "Seqinfo")) { gr_seqinfo <- seqlengths seqlengths <- seqlengths(seqlengths) } else { gr_seqinfo <- NULL } ## Check 'seqlengths'. if (!is.numeric(seqlengths) || length(seqlengths) == 0L) stop("'seqlengths' must be a non-empty numeric vector") seqlengths_names <- names(seqlengths) if (is.null(seqlengths_names)) stop("'seqlengths' must be named") if (any(seqlengths_names %in% c(NA_character_, ""))) stop("'seqlengths' has names that are NA or the empty string") if (any(duplicated(seqlengths_names))) stop("'seqlengths' has duplicated names") if (!is.integer(seqlengths)) seqlengths <- setNames(as.integer(seqlengths), seqlengths_names) if (S4Vectors:::anyMissingOrOutside(seqlengths, lower=0L)) stop("'seqlengths' contains NAs or negative values") chrom_breakpoints <- setNames(cumsum(as.numeric(seqlengths)), seqlengths_names) genome_size <- chrom_breakpoints[[length(chrom_breakpoints)]] if (!missing(ntile)) { if (!missing(tilewidth)) stop("only one of 'ntile' and 'tilewidth' can be specified") if (cut.last.tile.in.chrom) stop("'cut.last.tile.in.chrom' must be FALSE ", "when 'ntile' is supplied") ## Check 'ntile'. if (!isSingleNumber(ntile)) stop("'ntile' must be a single number") if (ntile < 1 || ntile > genome_size) stop("'ntile' must be >= 1 and <= genome size") if (!is.integer(ntile)) { if (ntile > .Machine$integer.max) stop("'ntile' must be <= .Machine$integer.max") ntile <- as.integer(ntile) } } else { if (missing(tilewidth)) stop("one of 'ntile' and 'tilewidth' must be specified") ## Check 'tilewidth'. if (!isSingleNumber(tilewidth)) stop("'tilewidth' must be a single number") if (tilewidth < 1 || tilewidth > genome_size) stop("'tilewidth' must be >= 1 and <= genome size") if (cut.last.tile.in.chrom) { tile_breakpoints <- .make_breakpoints_for_cut_last_tile_in_chrom(seqlengths, tilewidth) } else { ntile <- ceiling(genome_size / tilewidth) if (ntile > .Machine$integer.max) stop("this 'tilewidth' is too small") ntile <- as.integer(ntile) } } if (!cut.last.tile.in.chrom) { tilewidth <- genome_size / ntile tile_breakpoints <- ceiling(tilewidth * seq_len(ntile)) } absolute_ends <- .superimpose_breakpoints(chrom_breakpoints, tile_breakpoints) gr_end <- .get_relative_ends(absolute_ends, chrom_breakpoints) gr_seqnames <- Rle(factor(names(gr_end), levels=names(seqlengths))) gr_start <- .get_relative_starts(gr_end, gr_seqnames) if (is.null(gr_seqinfo)) gr_seqinfo <- Seqinfo(seqnames=names(seqlengths), seqlengths=seqlengths) gr <- GRanges(gr_seqnames, IRanges(gr_start, gr_end), seqinfo=gr_seqinfo) if (cut.last.tile.in.chrom) return(gr) relist(gr, absolute_ends) } GenomicRanges/R/transcript-utils.R0000644000175400017540000000342413175713746020215 0ustar00biocbuildbiocbuild### ------------------------------------------------------------------------- ### Some low-level (non exported) utility functions to operate on transcripts ### represented as groups of exon ranges. ### ### These functions are implemented in C. This file only contains R wrappers ### for the .Call2 entry points. Those wrappers are not doing any argument ### checking and therefore are considered "unsafe". They are in turn called ### by "safe" and user-friendly higher level wrappers defined in ### GenomicFeatures. The reason why the "unsafe" wrappers are here and not in ### the GenomicFeatures package was to keep GenomicFeatures free of native ### code. ### ### For all the functions below: ### o 'exonStarts', 'exonEnds' are assumed to be lists of integer vectors. ### The two lists are assumed to have the "same shape" i.e. ### elementNROWS() returns identical vectors on them; ### o 'strand' is assumed to be a character vector with allowed values ### "+" and "-" only; ### o 'decreasing.rank.on.minus.strand' is assumed to be TRUE or FALSE. ### o 'error.if.out.of.bounds' is assumed to be TRUE or FALSE. unsafe.transcriptWidths <- function(exonStarts, exonEnds) { .Call2("transcript_widths", exonStarts, exonEnds, PACKAGE="GenomicRanges") } ### 'tlocs' is assumed to be a list of integer vectors of the same length (but ### not necessarily the "same shape") as 'exonStarts' and 'exonEnds'. unsafe.transcriptLocs2refLocs <- function(tlocs, exonStarts, exonEnds, strand, decreasing.rank.on.minus.strand, error.if.out.of.bounds) { .Call2("tlocs2rlocs", tlocs, exonStarts, exonEnds, strand, decreasing.rank.on.minus.strand, error.if.out.of.bounds, PACKAGE="GenomicRanges") } GenomicRanges/R/utils.R0000644000175400017540000000156613175713746016033 0ustar00biocbuildbiocbuild### ========================================================================= ### Some low-level (non exported) utility functions. ### ------------------------------------------------------------------------- hasHead <- function(x, h) { identical(head(x, length(h)), h) } ### TODO: Use this in GenomicFeatures::transcriptLocs2refLocs() and remove ### GenomicFeatures:::.normargExonStartsOrEnds(). ### Used in GenomicAlignments package. normargListOfIntegers <- function(arg, sep, argname) { if (is.list(arg)) return(arg) if (is(arg, "IntegerList")) return(as.list(arg)) if (is.character(arg)) return(strsplitAsListOfIntegerVectors(arg, sep=sep)) stop("'", argname, "' must be a list of integer vectors, ", "an IntegerList object,\n or a character vector where ", "each element is a comma-separated list of\n integers") } GenomicRanges/R/zzz.R0000644000175400017540000000023013175713746015513 0ustar00biocbuildbiocbuild.onUnload <- function(libpath) { library.dynam.unload("GenomicRanges", libpath) } .test <- function() BiocGenerics:::testPackage("GenomicRanges") GenomicRanges/build/0000755000175400017540000000000013175727644015440 5ustar00biocbuildbiocbuildGenomicRanges/build/vignette.rds0000644000175400017540000000127213175727644020001 0ustar00biocbuildbiocbuildU]O0 -6mm/1BAl멺MLv({4;MB(<4}Ͻ\ߓGqS_9^cIV,:MbJQ !uODS657hg*H+ Jï CbWQrCFj S67ƽRv][0ѱ:y*!T>ƻ$>HIQֆBH*emή åހ\XHx>S|}S@BD5g*`osǦ}*=Dk݁@IEU;٣~{V^3DK*)KDی)YrT%#KhLxg.ۑcRrUmII.b\[eZ=U˼܌M-ʹ4%sO[1*Ozf`#YnrESlVoYaL|KbGenomicRanges/inst/0000755000175400017540000000000013175727644015316 5ustar00biocbuildbiocbuildGenomicRanges/inst/CITATION0000644000175400017540000000165413175713746016457 0ustar00biocbuildbiocbuildcitEntry(entry="article", title = "Software for Computing and Annotating Genomic Ranges", author = personList( as.person("Michael Lawrence" ), as.person("Wolfgang Huber" ), as.person("Herv\\'e Pag\\`es" ), as.person("Patrick Aboyoun" ), as.person("Marc Carlson" ), as.person("Robert Gentleman" ), as.person("Martin Morgan" ), as.person("Vincent Carey" )), year = 2013, journal = "{PLoS} Computational Biology", volume = "9", issue = "8", doi = "10.1371/journal.pcbi.1003118", url = "http://www.ploscompbiol.org/article/info%3Adoi%2F10.1371%2Fjournal.pcbi.1003118", textVersion = "Lawrence M, Huber W, Pag\\`es H, Aboyoun P, Carlson M, et al. (2013) Software for Computing and Annotating Genomic Ranges. PLoS Comput Biol 9(8): e1003118. doi:10.1371/journal.pcbi.1003118" ) GenomicRanges/inst/doc/0000755000175400017540000000000013175727644016063 5ustar00biocbuildbiocbuildGenomicRanges/inst/doc/ExtendingGenomicRanges.R0000644000175400017540000000234613175727436022601 0ustar00biocbuildbiocbuild### R code from vignette source 'ExtendingGenomicRanges.Rnw' ### Encoding: UTF-8 ################################################### ### code chunk number 1: style ################################################### BiocStyle::latex(use.unsrturl=FALSE) ################################################### ### code chunk number 2: options ################################################### options(width=72) options(showHeadLines=3) options(showTailLines=3) ################################################### ### code chunk number 3: granges-ranges ################################################### library(GenomicRanges) selectMethod(ranges, "GRanges") ################################################### ### code chunk number 4: delegating-granges-ranges ################################################### selectMethod(ranges, "DelegatingGenomicRanges") ################################################### ### code chunk number 5: gnclist-granges ################################################### getSlots("GNCList")["granges"] ################################################### ### code chunk number 6: vranges ################################################### GenomicRanges:::extraColumnSlotNames(VariantAnnotation:::VRanges()) GenomicRanges/inst/doc/ExtendingGenomicRanges.Rnw0000644000175400017540000001114213175713746023137 0ustar00biocbuildbiocbuild% \VignetteIndexEntry{5. Extending GenomicRanges} % \VignetteDepends{GenomicRanges, VariantAnnotation} % \VignetteKeywords{ranges} % \VignettePackage{GenomicRanges} \documentclass{article} \usepackage[authoryear,round]{natbib} <>= BiocStyle::latex(use.unsrturl=FALSE) @ \title{Extending \Biocpkg{GenomicRanges}} \author{Michael Lawrence, Bioconductor Team} \date{Edited: Oct 2014; Compiled: \today} \begin{document} \maketitle \tableofcontents <>= options(width=72) options(showHeadLines=3) options(showTailLines=3) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} The goal of \Biocpkg{GenomicRanges} is to provide general containers for genomic data. The central class, at least from the user perspective, is \Rclass{GRanges}, which formalizes the notion of ranges, while allowing for arbitrary ``metadata columns'' to be attached to it. These columns offer the same flexibility as the venerable \Rclass{data.frame} and permit users to adapt \Rclass{GRanges} to a wide variety of \textit{adhoc} use-cases. The more we encounter a particular problem, the better we understand it. We eventually develop a systematic approach for solving the most frequently encountered problems, and every systematic approach deserves a systematic implementation. For example, we might want to formally store genetic variants, with information on alleles and read depths. The metadata columns, which were so useful during prototyping, are inappropriate for extending the formal semantics of our data structure: for the sake of data integrity, we need to ensure that the columns are always present and that they meet certain constraints. We might also find that our prototype does not scale well to the increased data volume that often occurs when we advance past the prototype stage. \Rclass{GRanges} is meant mostly for prototyping and stores its data in memory as simple R data structures. We may require something more specialized when the data are large; for example, we might store the data as a Tabix-indexed file, or in a database. The \Biocpkg{GenomicRanges} package does not directly solve either of these problems, because there are no general solutions. However, it is adaptible to specialized use cases. \section{The \Rclass{GenomicRanges} abstraction} Unbeknownst to many, most of the \Rclass{GRanges} implementation is provided by methods on the \Rclass{GenomicRanges} class, the virtual parent class of \Rclass{GRanges}. \Rclass{GenomicRanges} methods provide everything except for the actual data storage and retrieval, which \Rclass{GRanges} implements directly using slots. For example, the ranges are retrieved like this: <>= library(GenomicRanges) selectMethod(ranges, "GRanges") @ An alternative implementation is \Rclass{DelegatingGenomicRanges}, which stores all of its data in a delegate \Rclass{GenomicRanges} object: <>= selectMethod(ranges, "DelegatingGenomicRanges") @ This abstraction enables us to pursue more efficient implementations for particular tasks. One example is \Rclass{GNCList}, which is indexed for fast range queries, we expose here: <>= getSlots("GNCList")["granges"] @ The \Biocpkg{MutableRanges} package in svn provides other, untested examples. \section{Formalizing \texttt{mcols}: Extra column slots} An orthogonal problem to data storage is adding semantics by the formalization of metadata columns, and we solve it using the ``extra column slot'' mechanism. Whenever \Rclass{GenomicRanges} needs to operate on its metadata columns, it also delegates to the internal \Rfunction{extraColumnSlotNames} generic, methods of which should return a character vector, naming the slots in the \Rclass{GenomicRanges} subclass that correspond to columns (i.e., they have one value per range). It extracts the slot values and manipulates them as it would a metadata column -- except they are now formal slots, with formal types. An example is the \Rclass{VRanges} class in \Biocpkg{VariantAnnotation}. It stores information on the variants by adding these column slots: <>= GenomicRanges:::extraColumnSlotNames(VariantAnnotation:::VRanges()) @ Mostly for historical reasons, \Rclass{VRanges} extends \Rclass{GRanges}. However, since the data storage mechanism and the set of extra column slots are orthogonal, it is probably best practice to take a composition approach by extending \Rclass{DelegatingGenomicRanges}. \end{document} GenomicRanges/inst/doc/ExtendingGenomicRanges.pdf0000644000175400017540000042137713175727436023162 0ustar00biocbuildbiocbuild%PDF-1.5 % 26 0 obj << /Length 2182 /Filter /FlateDecode >> stream xYK ϯQ l˪^&F #rXP#L ֣-_RK3`NU*R$GVwq*(.A%qgX4β` O/}o>4q2 o$\i^DL*lWRdk="N bVv}[ Ef|A@HT}"^H~˃n,)> +;>awթv"w*^ ZӒPBDE8uqWP؋U=o΋GHrd,in,Sm2cN^%<Y$E|-E`j_nצr6"Inz YwLKR<*H#i] ,ʤ|#߈_EġR^RGBpWVZ]"#%2Jbf774T_I7,|#*wU*ʔ&ySTB~iDŽ&5M2'$.PV'2>;B޺L[ﯯ~W74J:#e{ExqXF9WJݵAW+7CeJݶeWM %Eo t7alCSzsj;ޏM?ډ87%YJW.᪘K%µEb7< ;sT}wq%(hVhy# RЯ4˨Hǐ HR=)i$ ܓ4o_4bӖP 6EVlԳǝávفOׅ8wgN*3hOXPfN`\cuƔw~y2lv[MN$6ݑ4eC̹^V=k-FjƏ9u0FRT/Po;uU;>3]=iz~($[G@zC,4MYPw;a;=?2nd(|]gA. ܰ˼i2V[zhbhv#b x52Ѵ~>7uSOdW~#+{}7@GJ90.nR,*sMW+C wF)5{*s.Yޚ/?I ę,5 Hhq=FYE6 `F){Ҍv، ()2[r'N+S7QAOuyjZw@ж()|IO,aISW!>HiRf"uRJV 7=¯gR4ilk&0w|6tu8x!ش=c'*-bXy@O%ka,U59ic"/ÕGgÁ+TpOpDon/B=JL3i>b%cD;L1|"MV8*s]m.qR9jf:0iu^sO8'pSTLq:=E6+ j<R'8 9ǞWT}u\saAR zyxn> stream xXYoF~ׯ^4H@m%d6oY$i|L"A"#^$P"\]+5A_MBˢe *\JYMBD0 k1Ջ< +~Bt҈ gr+Էgv>x#p~.pKOYE~Q@m} f+A }NSH0H-Z g8k3e#ֻn.giJr')!wNԉeKS-maN;p@3ђ2,XUOk.,pr&21'Ssܖښ6[a|. Cx8򼃉,Z,k HuZ583XA s=?4cƣHOGfh+JW"p*YIͅ#ײonU2ߛ\6f?yV2u H{L퓸ͮn qhɊ0VRstwn"x >{Rr/|5{c\IJΚLΪsJs)B8gʌ#qs`=X OmJ*{iN"v13|uyBB}BURm␲<䨒h Pv˛GQр)o$$`&@ǮO8jZ#wTGjjAxUo!Q&4'M7/G/n{bX?yZ5UaZUz7V媖sgL.?wY >^\CFׇ4NgL=N%kA lZ)VbQ‡lRTNtx`+n*w]YuLsvZo\o>T P0z?hGKA@&)iybXvs'/ryAdQ <'豇dGYuji%x&O{@JEܬ*i!faװݰ{elj!!(#bW`&dH]a+kG|,Xgt-Ùsh8 ϶?>AXOZxA19fjiG-̎zN;!)I&,LX@WF943%ێO}OT N 暐gyst`O%Yj+ЦqW^ UC:^ U_F~ @ CO endstream endobj 50 0 obj << /Length 1996 /Filter /FlateDecode >> stream xYKoW>m._$k 2d֘1I2=.]ekcJa7b.c1ͳhjBeZk:[D遒[_Ӊ I( 2&Qw9P׾.%wpܖ65 Xbk$ ܸ݁9u$Kb*L$ˡ5*4G@%}G98( V4=|?/3B|fYb^I#X23K_J# K/Hg+i$33;1R{u0ݴcS!Gͦ=6pۣؼ~XIP~KP+z-PB݅Um($x,J5ԏT'?JqY&ሗdSCA!R&>uxف endstream endobj 64 0 obj << /Length1 1649 /Length2 5235 /Length3 0 /Length 6193 /Filter /FlateDecode >> stream xڍWu\liD:FtJHm ƀ""*R*tJH4HIRx|_y?usιa`,Eԑ H(P`.4B PDrq``4Pa2'/6." IɈHʈD@1'@ $~@4G gB8  <6o |ln( Hh8UANh/<( G{Z@`t 0yP0п#{ݰ158WாO-4QB8SA hMP = A@L !ts=$ 0ߕcna 5#]c;! H(Q(/)vX$؂0ہ{H%Jo$ V@Ra $ V$a k\ {1 )_ 1iIcc/*zFl ?$jC`0%Z?sv/-,?Ht.1s\ C/AlJE3 ^Ua]n`sz^KvNjX{-LNN0%,]T%m|/X%.:\ }O鰾H[{!11N@ n1"/4Dàt _z_m-s &u begV0^p06uܜ1낱ۆXw|o\n<H _P ("*@ZD*/VG/9/vcu00("<-]Gղ(=i-ZV'56&y{9 EUrI ]V܉=kyCkU*UOpJ;jܐ?Slf_3afFeX~݊ (0ljS}_Q6EżAI0[ͷJx\ˋWOK F>;qȢ#t_|@II` f[浚6T9Ȧב()i;|@.{ϧ\\ *MB msnfǷ+ytKܽ[z,GLN_6&n}3D~O޽V~Q5nT~-lK>pߧpF9<0U_ յR7i hRxp݋#sCiqddʐN Q ^cJw:\g,(vڬՆ:fֵX|ƃc+O m@x51?vȐRɗ)p{̘_q"G!94\ZE\Ӂ{3uCq~5ydwruW\d2ãS),PϔKyS_e{ ĔAG$5I6Go]"m}7Un7|UegH5 0}AÔ6bI[rDOِDbzwV^AgTVq7#w$;VU '3Q}3$O-GJ#ceteq}qc'Q2t%+xjΦE!eҸ!rzȄS9Z> YjZyDFKWfk:/h{=Z] fǘLF)/*s=~R_[]8F3 ]^ IGc1M9=s!֍fb94gGomhwE3BΎvD`)q<Sesl T)(T_ּP_xk*: jQ(g~7+iYuaq /sj{5ЍӀݷ\Olm7D@웕eY)|v |FHIUܝ/%ds[Y}e.%̡>oN;c74asuy n.7l<{M UMVoeRNݷ7b8W9[K=j+jwNAMIR;T,HSw?ma_addz_<'itءO@q{wQ$%S73&0k]7GϒBfw!~5tp]8ERVXo9UZ.f Elm2J>Q/wKKz!c,8_ǽ*U8rqhi\E  =u eO0cMC3h+PO;;XS5:̼RG)ID4ㅔ ֥n"]YO47!Y8d(BluVJ\<=^?MV+wɢ&h7 ՛lƌTJ-]~{*s? gq!0!_"X5W_[ΆԂr$Ω)$1ٯ ̵ [)tC萫y/[* +^i4.ԉe6yMu#R +|$oUkϜo-*t/,M"mE*~ѷ԰` ͏tq4CC ط"Dd_&mq7qC DT&G2sǕ)[ZҜ!IՓtɚK{/q9byH_PIЎrTjںdUzX X8\ ч- y>_QM! ЪMlzP.4M {ӽB~JpAS`MɌPޕ1xK?~ حxhT}ʼ]\+(T:Ηm6vj͏46+~ĆA% %ןf[u0̜)n^q,iVOɘ0(nh mUs bfrGFwhRKɛ$͙Fխă2TuEOԒ،n}?*30##pnTpl%1tڊPLOKn 8t?BpeN DбRurnU=v y/|r:JN&ڊ/$okbd0gi>k~rNvb2(hf/W5O܉csPu44=FcԆ(q;'fpmmimO_= |ӏU e=Y"Z]Wr@i _]op@:D:f֌=5n1%kR$J_.r/&3+Hm7vR6'*ǀTG5{M8y d :ò(6m`*j [4kXJOTNQr[ưEJ8SUKW҄/k KL!ek"[`2Ʒ'.,` !8sSnoW^ȄY}x`e[[nJIK h ཧ19$gc 3JsyjG5IHI2Pt,D^&ѓFU~TkOARәCX7v2x{flnQ|UT)9\ET"I&eo znb$ftu5ϥ+qUz 6IBZk>$PE8.ddB JK)1SPlȴi9!}17rgҴmή=^2d`WS@lD9اA"p󤧃*? ] ST6h-(ҪT\$ix/3v[yrz/*_Y+Hx0G['\ݍ ߬^h5ޮX*ij*~G?y!!4NS&[*5krZT$rZ$ObOu1xǧ&g%&׎Ӹf[e}Y#ID/+1 9Ϊn,5R٠ ]Őߏכ:O7R;fz NꑪvzM[kC3m7rB7ʩ&1tRn|ce$Uݳtg/dt=}npc[<{m>T2-CYdD#ɓWECHg kR!-)Έ*lVFSXEP[_Zt(?nS~h ؒgyx|RMKӲH_h[aS; (һJ`̨*(Qb>Xl$s1ys۴rQn[|X1gU,B&k^%#w1f}4;yϑY;ˉV?:tk Ŏ_TP *X2(i"dT wa+4G+4]袚W~`Kt; *iM< {z%GAB~lMO6~]OZӜwy>hKCۙh;R91[L7=BKU+%0_yEЊ?X< endstream endobj 66 0 obj << /Length1 1281 /Length2 4357 /Length3 0 /Length 5130 /Filter /FlateDecode >> stream xmy<ɒ5=˜ È.a,3%)k"ٕlEƒ-a]So~cy93bB0Km412`Y95@C@X"pP</ca99. b8=XQ*je5S&^"\9`j@N+b4EW,KvC*g. PxgƸPk<=^///\|3U;Ei\=1/ǿX_, a(7HvwCcX BN_kVnX (d3fx_08S9nflcr^T} \ ,SIX%!Qۏ ,"e{@*HoR R@DoR$,˥I 
 $ P'ƅx;NToRn{R_/A0ق UR\zC=HR{<@ASq U` `p8?\OĠQ'U0՛HH PI U77X*r3E{@:Zo1 ::x(C}2y%TUJ?3Q~j/W#_vR!aP,#(igYm]zAy!齗j\^G5QmlB2;O)_Ot*~ PؿyF8N~ʫj/v`y[S ?4Fq_'9LGo> (6ݵYyJ,{2WIk9e~+yDoDdTpiUHт ZrWŋ8V.סO,,% *!\k%`!T 8"|matvMd =sbm', ).;ǔ-;=?o]_Ư|NWj~yZAMq\˯Ƿ79ܿ\!zWď.NF>FoH E^ j"`~Lnc!ÜH~?>-- 6V֘2"zy$+Opm\Mv15\_ø').X [ 33 07N4:T7D5f=K}}e}sFTeJZd"V־BkJm5>FOTkp+^ _ON,y}Vk3fT44[pgs}rzW93 LN& E^ H5e],ke5יt8\f ꉘK{Ga+gS0r1G`gQ)-3ڬ`i?"%~>dVb?>UwNKiɢ @/ulAgKnBYw^$ }Qd]1=G[/~D%} 6)ۖ\ϠtEp327K]%)!3JuI:8uzR{o/*ZqܳibpI3Dn U4D$ pw;+O.=߾DPn749SZ=:QRyማoZn i@rp +➫JBW d g ؍ JuihЙ S^YOhUq&dWtœwQ${.3޾b?z_x.fX;]*wAon)HVQ߾W ī4v+Iy[I{ʢ5ELeN7G؞ύyDlgېEo|ׇYAF\o-pc+,AJS -\>G9߬HMtsO%#4fGh(LvG*Hҫ9;c362k٣b:LoK^>dvR_tb۶dQDhX̵{Mr 9K=Yp|HpO}%j3UqTJBfE@Tr$`5N8)ikeLk>Fc{~mbp?<&u.eW6٢DOx]g㼣* \xjلD4^r!̪`*}4{UUaO]4{{׻f<ncxV&~Z:3*NQi4!o*w;2*ݲnj<܆I"Yx(]F񊐾7nɊyy)H9w%kbg=OmYBr>w|tc[cjǽG{O%^Y;<,hXMT8&v4>厖:z9Oi[tDݙu[,saͪ8I3"07y,Rdx^PihY FS~֟Zk+ oemljp_zuqh(K0Vg9G➌ӗ~]xU}ҍ/fן1Ykm8uw n|X)$TԨN E(Ka d'ѓM 3eXL#.CΑyZ?t9ځU 8ǸXK#7i|y$ҹCGV])w[*‘gl!2y; ԥ#P\f_M2Jac$}ܔn~s5gpF~ &ey-nhcAnٞq;ӕ8)T_í "G䔯.L`\;$S6f*4Z{Tw6^ cAtfOK& >!!)GU`z58SzL;'vM+V)X>ХaQ5 }p#ҁ#x|PD)mxг9̴l1_%{4d9 rctH.-ϋ5 n) ] pAֿ[sc>,*u&l u qNH.4\Ml=01$Rmpn&ޚBbb?pwH{yA7j^/:%D:M?=0'獜QImMxQK7N Ԍ撒쪬b˲W*iU"G9ApOIh@`xMAKƙ L-N[fuƋu it0{qRծ7(hP`hǵy9I'zLaH[jd)3Uq,jl0Ą$-tQ3=3rRoྈ"Q%ٚ{ϰdx":-_\/6vqd6 2J"o|ϽxWI:'|˹1-!SNie Pi[ϬcW8?w]z%e M9YLt&Raͼ9%^rD%@qn=$5n?-%P&Wo*A̘me#~W$62G""f(s/vE+W h^:%9VzěҘ%Ȃݭ3{'OR`> ܬv>m:}8u{}~_hvїuܷVۧfoCK:S/$E͛gaci+}&7WF fʻR`cRuH]4%=?JJnw;8oDNi ck x}7]~.'œ[%̮qo2<[vLP)}T%!v l endstream endobj 68 0 obj << /Length1 2394 /Length2 19633 /Length3 0 /Length 21050 /Filter /FlateDecode >> stream xڴeT\۶5 $H S;Np]#s>~_AGcεH^Vlh2J {FZETh`8f9#7NxR8{[4dʮ6@F_@l@kh` o!`W;sS3?9iid-D20;[ @)::,h@3+ T(**T(+9؀8 @DPVYT() 7*'\FTYPYC^OFOF 7P;_f6\tt`;S:)vO;/aAor:Ϧ͍ { 1ߤ| z;/7!;2fJK A@hL/@ݟ2^2.~Lwhmm#0_s+MFPVRLTIVm@27u@t.y'("``0rކTd, ~cmG>7vg-A`gM(ohC2uJ o).Ff5-̌o2xۀm&V@Os`t"xFv۠KLߘ{F⯃JvJ +W1^6%he%k` oI?e/`EE2d|?(@=h!!;-eZ}fdafE6J h0 6H*/&;*Sy2ނI$kȟ',,- *P' zYi+2V4CTSK)n#ܗ(dLmi" sG0~H .nZΆvΟflBsGmśotxLj 7\ lG߂ c>փƊlOz!=:ni(QV@ڳ_v&>H`ŷ 'ŎT:νK!ygjYQ5QZFOUyWiv8sޏ:'jkȏy*q 0xP]Ls.@9\.9r\x>1P(=PS Cu+(13Ceo$Ĺh\ާsݳk}iUt9F1nHd5NIȽ1%Jc=t K&!{K{atg ̮Bԧ 0; HqMy(ۀDji=#\oZ7Hy\/\JkXNNУLϺ8sEx[ &]Sfm:}xg8eZzI\q&խT 3b-&2/XƑD (TDrɿc|jsj~ _a£; 8ͺǢ?Em۔Wa(g- <~cSa[gx@Eb^>tֹÔbk< gy^yLc}tC'+d&S&Zp\ g^bvX @ǂً^ܽCuϡ2Wtus6l\\2&}Rln0 z<&{47ҿ,eD (I3Խ_q~"xT1T}/ʹwH]̭ZNWS2N݊Oiz6֘ ۃ M@#mdDyL<4W%d;-5~Hq1ϟԁBiM5.WNR… uL5SKzs;&Sqi9';o;iUAO:ݒ"@Iq .0@8-GX>'tg^z04y_OsF"F'D:WLS^ciшe0{}4PXlW&RV  vNy+{*ZƴfVgypZhY)?=\m6]nHV;w±M:x.~w|YEd,8 r ٿ3wM|Tغ0H:28[.Ur ʱv$TgoIkJݧ$-8KwpYuI7݂E9ՂIB t*<"n@a;uO֦ƒw%JՐ*un"K,El͜;]Ӧ<# AXG Uf; V<$]\Z/=怆ډU%LwR e.(l]yL;"c1B/ Ta?d7xHݧS&}ӕi[ m-\LYydĤmͦGdCsW?0)֪gll;A1q*΅t^͙޿<nwo&D!4 6mtoBB  M*G.Kޟ,xbZՅX(M"S$5lkVP4r~m2n]X%/-k !].tBgEw= # >|;=/.,5htA 5Id*[%w&3ܙ''ow=7r3f4{Vy#@Âsk#̯\Vkij j21+i$5 ju]'r3GCJ a/<=\..P!b2s7ȐnD2FX OVI{|g $5V˫XP/(ǧg.?GU&UnhV0aI? ?2Ҋ '"Nw1rwJD&i>e,e PK?\n_t=!t?y;N +Vv~fF_2%pc..h=_˯,iDډQmpmX\dJS&!~-Ẋ\Bar^$(k&˂;ƊW&DSrQ4SuN$*2/ -YF&Io9[HYMs+w Esw"3{ykFlV=GtM f"O䩁'ΜpD%G^{{iWs2$j+?_ tĮ[F #>,Hk~HtEha15z\Β@XAgʞD`h!-i0J=2NM >f U'+*Bu^,\>X{6i2 {{ iے\&+ׯ勑f,jr($XV[:!袤%vWQW$# ) A3㽥D(O.t(<64+"( å!k&l@n`Ț^bz*5Pmņv ٓ,T*8}G^AʆUY }Ccڮ6ɑy>w1L|MM~C qRe[ev-;&U' _umn~Rܯ2 hң/ Q+y 㟪4g~Ƭt$q c b@x_?;zCK6k%#W >p@=k_ /P%͓09JbVdSFsm#y9+{,:Zjyxmf4{TQSX)? 󯜉Qx1Π(^3ub1҅ẒѐYDm%GY$ OIƕ?>%+.,]}P4Q+WtwgQɏY-@,#Au,nsunVѺ =;lD/:e4+t8ɼMXuplɃcFmMtG&KԖmAdS~snɆ^hwl2!~%+!1^B_lL* a{ en8^Ե*}yG)rgM)ɳ]sZ0!'Ш/)}C8^":ˮyo_$:Zh'({vRJOZq^{0"$k$YPd\K4z&2s]Z dEYO/y)~ZL56f㕴Qh&Qϛh;;QnSRuՙڹ(^’1f4cTve&2oq1APp1T}1\LyE4dkb~+_,Aܽވ2xr4&x8W* ݔY)i"̌&ΆMs^vǤgtvM֏'P豣Bqx0%~P7iᤖt *}3mVڪ`f*}}ս4CUƅ!\x]Jbl.;X]k,&CE˅ך$.ÍV*f 5}8k5`Ի&ڡ%)V]ODTZ Z1!F:bi|K=?^%Z~~b;PM[o0є6!kY^5|t<S!Q7R^Ffq nxtȵ0;­(V)q(WЖU3RRz“&&kT m7UHh{[=CU7Py7SQmlkN<:`XQN'/e 5%O]hM3YX3K 74r1,Ӕ`ˤ@')7Pp9v6zF,p!@55g_}Xj6uSҁbR[c:F'%TчI`{˙Ft7YVˮ-˜a:ϡʑHSKLQ>c["GZHtԊ 9O2&g19 >+ i~0Mn_iL =͵;z}Qb5D)OQ kLWNAf<*>'~V}U HauQ̲bayE2|[5V_X3PYhobFO\ !qF{H4o{/2Puo=ָ R83k-PP $GFmbdډ*7ek6VTfW U0Gp]KȂcz.?FVc8R|ِz~vD׳L78K1_^>\BыBt_mdhkG-Nkg1RD6sh_e{= 9 td?4]7no?tb nY}棏=MA|MFT:R+4G oY!3# u1X_)wh61hR>?>@wlZu4Tqh{l?UӳN<읟=H$WIѲ{Ӿ*8ڬhvjN"*{4Yw-JBa/- 2 p;uTΰZ%93OL8 a1ׂhSeqOM|Pf׈#rIMXg=A!(Dk9s mӻjH{r|Ίz?ALVbkL3h)f?U٢|!F@q*MI(BmdmWsdA:@],ʞ'Ym$Mvإ6 "7!,i@LGS.}=52L9wsNx-{D -"F"P$R&"E]6ʸby'АbJRɕH0a1U˺' J2qR+zFTDj=ol|C [@bR5ˉKc7< U>Za ЧhxDïppI'&0 )ܞX.GbhژD9c0q82Yo~y/ilIdL7IZ\jR  MUo?%`naO%8PW!퐪yxQ9& :|cu`P¬IhzגɏӨb<#L^Y/dfaϑ zXLJ*ٙ-$]`7 *LM0rԶ\CR%q ͧSeF:@|ꠤ7!t).qV~Df/ M_1Jtx8y.oVLAE;ds4|.݈aܴ9鲮Mڏ, bI#T[~!(o(5 WbmBiɽ{قV/ Clv &H_/\H)S?@IΏxS Z%!oᮊql,j;xhlcA?2XBACooYV?HB1P;a1dC+p =S03֟KsUpDnI`սNUpo!JYUzy2( @Ħ$$}R =*D ^<},\;a}z7_n7NBm-hc4nFLwi ),;,Y ?QNaǜOYݤJNP*yG"U݃dp_M7gm{H[BZz(wm"2l)^aƓZW+s97˖S@n/O.lFҘ|Q+#g~L1ςG5r5yVgď<%8 ЁLDΨ$]3SFI3Gv~ʑ3R$)Ow҆1bQZǒcj[!<`qt!'ZNnPqQijB˄]Ӎ֫&0JYpԦ`F_6LӲz[ny N^g7N爦mG"YËɨyLS< MP+\&aвOS6$#L.JbWb!m[. ,9;[y2bXtwd:qq_+~55^ :HCf;} 1{Dk'n# 7'0?GфiZ\%3\t8|EfO8/\4Fpi^[jd0kWŲow5{c%o lBI/iUtϔlBMיǝHwI%k}Q . ijY~DWo @M-'!t^Q[5&*ND "ȿ2@9ۨjo $ަɽc>~4r'@^) eZ@IǟJ.3" -p""~"wEq9GT1(z47}my&~އBVx(@ Kk4ŴꬎFUgtmў4mb]6/pO AK:^+VȡcVc .L pSZVI&JkKqBFn1H`sWG>Lk0PAJ&FZFj7 3zZV\چ^"7ٜ.J\Ϗ5x}R_ڱw%(BjVx7 iF5Y&fY.-K5:})U0mZ`ؿ+)Q"Xr}ͷޢ)m2h,dA|8X7($c/ .".X^Al6Ȏ=Z5<{De!̠IG 7;<B ֎-"irr,osJ#xJ8i7 aŏMnciZignؘs" xW~E[tiSY5lё.܄dq?t$"X,R.cgrH_Y1ܶVo 5as[|?ˠPpEExv˄@hBɿ%"|ĸ*w1saɎBXFm?v]!XJK6?[taSI@ ^K3dgmбM:ߛC6)*Z?; M)|ET#~LsYb6쇸\c0 /U 'okH' J;tY|?Ra4В*Cc7=^KA[LmGfw!3Jpw.;7p Mz/ H,\=rm9{w=y+#Zi#򨩐jlUۯ]#'K2{$˯yDMɆ9!%c7`cvwgAU3&msd{ ךXΟ`4N4PkU稤`wһ"{Ê՛#4J0viP9 Ybp,31@ $rTm}S*@ۥ۵Ꭽ*FD!9Sv|_pA j:6܌N +>9 >bCl+ɐ~ v㢒~6ybUV*efΫ IKPA5Ŭמx[t)1Շb#ZNGKCxN"uO愈[`{;aˋg@؏%GjggRᆝ˸IߣRKΛK5G*뷪?UK5\׈7YyD yhόi-cXWIL3ͻw0C"!f4cm3ۚSyǞ5[0z&Ш۱~ sɋWb;M|٥Te]‹e&4aHBFHXfh !$]?)9n/uK,rRTw9ZQ. MqN`GZ:s̎w8YI~bw6>h`Iy0{GS 2.R@L -k3~Z9|v3/$-->ERikd #@x:v[)[seƾa _41&zM9R!ݵgO"CqfS,ww7_z_ 0|!X@wEFl]WFAP94oΌ1MV]6 +bAyJoYM #?qVuV$ACT3t{ Jl~,,yn7jd/~Zǯ *ijzSRud$ce fw+A`_q|GWn37hLlhcwկ5D?min5ñlo%u|VA9y+2.{[mE(H}BļB1FW?fe!ybСlVpbId4l[UP]  3$tktm5/Eq^[q#$oe1xOĈ66&}\3I )+ xI۱?CjН,tydS^]eZ,3u5kOJ?;xwqdǎZr@ubχ=: 7_d㔻ާ`>psc40ʦ-W&á m!!/K&jڈ6ravi>r]< D 6% 4@!1bF_a̟a1v!s폑j]#48j)>,Q37aL ek" B[Y= rɸAܚN֓m8_ݞEm.z 7=.hebYxBxM'ǬӏQNݧ!BөͺջPq<4e$qwNbI>2B^Iڜ)MdJOt5MpteW9SyhaHOt^aeLfs]I7~/5Zr\WT˅>U^+(;YOFGN6l}Ӭ:# ɘ5q Dk|}B|2a˴ESL v>)1I`42ޟ~Ax: _r0$Yoamj*hD&r{LU:d7#lHq{-|#%T҇(zNΉHqρ5Z_HU6TCqK\}jm ? pUnCxb^:'3q%lA'>aEjyVW[%=tOib_F#dx"X3tHp\'.F?$Υ8؝&9/o_@cP t!u ΋(+JW^@.gbĝar:`IJygxoNk݀nsI R; La;A1Oȍwz/'Jd)%;(Ifs'I"d@w"y(X)ݹ3?u*d=2oot/" i C\\ͨ~zlnP+l,I4>z̈.8fP,BmnEM~Z'}CHPr{ r'~k'EvXbb'f&@8V4 / ܙ3XR߯CPvB]>~# tG㊂w HEYQyS$lGlζZuJ k2IeERmiG56FkDBN\e D9&)a?J/Mҵ3'E[k?)GAY+|tu>+wQUEVaIU*&\|:pu*b9]Q,xgƠi>#׈qS|1o6hs佃QB1]pEÈ o٠K~_~S| 03SLt؁+V!+N) IoJ[WD1y fOėτ0~ LM8'bRh=*(v1i]!IM*5e>Y̖㹺r[W2{R3wfdJgy>6xMwѲ0kfUK*2;F+0wR&*5M32w0fϭ~bh u 31%ww _4Uͣ ?R-Rb0P\{C~9id|ʲd7_!>ЌE@bi>q5d[[/ISJMuXjo%NTӛ]E>ÐO|ӧʰHԆc4Dy]U7?n7A=`z}+3\1 cvSQݣdJү@(f%EN9'-?N*zq$Htt3)EԚG'|v\$(]m]Πpn2#֣xIjFŋ%DG,ŵ5n ȞMF6B ^Nv#)>u(&#Lt'BkHf}DJROu6s29 xEM8_O0~O&3% xգ'# >S[{wWGe&'kw\S3hmӭQ^$0M>NQ`di5xϝ\t\j't* #BkKDA}uJ$w#.S>Tv~D;KLkmd5,31MWͨXKG䀈>Q A _xFZmW{hC.>X z++gJt ox v*6HYRe~A-ɗ N҇ { u5z5%߭3jJD zd:H%B|7=)SOBÉ"dKsZrrh J+5JE(+&aֈ|UVti[ooq Lj]43" ü_;tD~' %YZV[ǡчYqR8y;T~ó1Ë7긝"*ˏmBb"RSL8=F4J!e}єׅq "-vjՃƒ Lϣ$e!o`LF0THПG*6bT͏+X|D%(>T4[6}e4<:Zki,ԱitCD]1>QKj>}B\J#Dg[SF*} dG>תb\,j,EZÝ#b!IrLwRoZhf!)Yec m1: <)xRm=#jKsq ߌvRK@F(R훂yI/4y(+HRsķYWu#GaQVe23F3F՜hh86%k}̠P:PpB,~`ʈ81!H+w'[ 㧝N~4Ҿ^t3╗I!XnNvM8`Os5ƧKi;0w߭ql" =k(V!L9Sj͌+ECaDMmI:27Ǥ8j^pf|z kg9BYEG~'ǀD(K&{vW:|>޾ͳԃ}\aD-zT?>I L 9')C[=LRFb6E=-T/z["yLEG.*Ab}%@1#B@W#Q=9y8kZ'sr8i.^f rƮL81!榭&&:\9&4 "n@J6h"X)r%/s"W)ѓa> *'B $b yeQP&2lQu!,tN0#g$b[FS BAuɄh߳/bzv`eƥh0jYި+?=ƄȜ peM0R( g,WBRLҌ0:hyM@.KZ;EjUUh(6-k +PϚuQx[sfM,lF[Sṽvzq t;uAx^,qz b~'XI8y;cZh4|HF?7nb^W4D鐜ԤFr}ꙞֱY_S269@zmOn-v;}-Tp&*#$bm?qy+ZcT썣,=ςZ#%'="v~.Hwxw"YպPF%%I1,O+5|W[At(ɵ8WF {aD}Lg䛿{ lmqVU5"ЍQ"8r-o{L;YoD? R %[ZJdvlbлTل|C=Oʉ,goV>#(vh&ϰ"D!-;1fF^P( B'vhug߰ TH[pezM[{Ďvz1\ $hUMl1VKuAFp7dqvsQnh:%r[##ݙA!UIMs x夗&FVv \6ޯ`tif|Ew쿫MWe $oN2̐&5ԖjK1Z[RAd|z1iq3i5O"ҾH| Lu2!B &8l䏟]"4ҋziT1&0_.xӐ3s-p`ϋgyT`ƽQAH\OajĈ S 'D=u{wg!՘=wvdВE# SlnLNIS Z =RBtʙ\؎+l_B'c֚,3zTj/e?q;xWһw^9[Y;x6 %N8Uz3D^ R rkڧƽ oaVVX# `'72@0[#`*|‚< CzOInQ!N"J=] t AR=OwAmmr»zDd$R|m|f _QW(ANODqƤ=&cUh5D1b3"IsQ]KhId}QHܕ42t#I8qǫux:Oܒumˇ8sǕTaDP;IDÿgRPB=xZ1[$3;g}.̠ǥdKs8)5ˈyb7庅e[jFy 噲䝍-ݕ+3,(2ѧg,`=ߑXڎ<\whj0+nsϪ%C W.Tpu (2_Ԙx?^׳]_=F| S(v=SϲorڜoWS-hgD !8z(Ӛ_m+_ĮOcaY}pdn׈(_|!hZ ?THX7ߨixR0 Zw+q ㆢ畳9Ŋa[6{C+ E){WJ΢4lG`ufMԛ)1!F ]x.[Y(XMIyvd?XR(Gp䚡&̷xd:Kpg7h7[>|='$}긚prRf=m3װ..3=30 N|-,4;\{a#s+:t̟*$9!C .^~3UgHYXtnUҥ:*0D˱8V.`)` ފZ=鴘 !;DoZzR%G2m +ު>|Q8ePXU~3'0P-vK3QwZLca -uWfN`Hg׿齙I&OB/?U4XTl63N'(Vp_kfo 'x,kS̋%(̱)eE-ٜVdoaO2~[k: nOWJ 6*P vAU (†H-)B>m4I%-)Uh ,3Yb%v|̡ƶRe5v r( 8&-~JHuօ|&efWS{q$, Ӕ2[*5vl@CZ? tTU2<[(H5槾1J?GGJq0[ፖ8Qh-҂}]?ֹ53WQRG*lz50@It뺂!pWGL0)7c|\ރ$(ml`aM_VG2T 6wx]1ZbnMef$`ZgK!"=K_0עo"Dn@A^R'wn{Cj1\ endstream endobj 70 0 obj << /Length1 1923 /Length2 26843 /Length3 0 /Length 27959 /Filter /FlateDecode >> stream xڴeT\[6Sw- !!Hpw ' 9vw=הרTՙ,@f@i3+?@QIѕIdobfo3r"PQIMl@n@~5@]ʇ@:]ޙ3oT 5 \ݘL]@G+G ݻ &?h3M@v6SG <3@NЂf@kS{KhK}P|PTUc~7rX$54ebR#@FS]U#@Yϻu%) 1 ]U)6?k<.6Wlڻ /Zk77'~OOOf+wW7f_iX۸N{J9ZHޣvE>I<\Ygo9<}7O,ܝX4$O㝄o :^,5lu9,M]~6;?߇/r ?@ҽO`D`Q7?_M+-k`c% /űqZڸ[#˹O=Ѳ}6/{{9]]'\5;J9,l\SSo`믎0;UNn~K ŸrsXB?e=y2q'=>'u@/9"\ 6%_xW|rL'!d69P$k`6u HQScU(F[j莩?!xfpҏ.r#"2ιv_gC4rBh lX.^?k'L?oR3.ۍ Y䑪qnߩnA'L <.<) I`Otq^/|0$;YncDTU3bYd`oG&l°d*9t%K%a;gX %fJ7`,]}9%GxҌ}t/`P}xN3Q!M`"#)j=76Rm]Cs O`-qHցfCJmdw2f Plksؾ]q6$OLFJ%wyc3Qa:4mAgI֠VǮ,&"6=/JAkmWhC={1J[V' V'kX?2%h3¦DL@ )80$nw3EnQ}u,ַl77,(N PT`޴Z FOi %NMH-.y} ,.J/ӳhhd:!C3˂gy^(6諫X(9jfO+u]\}(99e?̴z uUa+v;MTZTRoe =A`T7( cp@!ML^4H XQ/.H'M\k N xH=*)QmjfB B͗nv2qqjq"3yK}HaVO2IR3hF"Gum}w 0 /A<-~[G #[0IV S嫵eF<_y鞃ʱPp8ϟߎdw˝})I bst_0o:AŲ0?V4M3m7]4VAdO/a$p9_ ̘DPuN@DӁ =6 U|AUTEG)dDWX@8dqDtLtr>ٟqdR;hw qi=祁R"Rݎ9坨XWPy~ӶKЃQ@)*QC$2t/o>5CzP eڛ w3YT&uc ZLP1&:bȅom67粱@u6v. "fJ<Q }͗,#c$`"zfx%[u>)AJ\̬ivɰxԸH"S]OC>'w$Wr*PfLnb@V7RL6+]a"[> -f:9¬$VNM@.mR NN$'%O(Zdu`RZ*P](@H (8 xdy'74C6-ڛv2- 5Ijh|S-]gUli{q(Wo2hXV=UCK)Q0ԵO-.v 瓫V,"%NJ&+s4.ۨ`rԷj2"АC ^U.ۗ\ }qI[]ZYe3"xʭ5m5˼ )1' 8NK/:*"]cR=>C<>T95+@ n}|ɔQJ>= GO2P;;`3d3KUC* kK lbȏZ$[Il^>]QJ t9034&\aPHd++(E'~N0뭁6aa SHBVS{RʉZ:"}]/nrU ٖ!JcJzc` mM R'M)%Y4Y#9+zs7U\*܆kMv{~T؅=lro({i htnƧZ aanU7B2ֆ=u[ȫ-1m#SIy,QqUk*k2ܦ4ޞc25whwݑh92t$)qSv{:S:Q{!p}7|3B.RG_r\/GI2d0Ek.~fT]|ߚ[<"9Kn}UEER~KTxG@8tc ZlO eqF܅q fo^""a,J*nbR Fj9w¼IP"]pL*-ٖ` f1)gICRF \Ǚ;C.l: -n13~G! xA XDlLbctrQ 8Lmg8@dN fwM F0ޯ=kmqz60EM7I\ ;'>4GЋj>@Ki \z3E⏽ԶYauf/U6U 4\H:#1k JOBf5*^caZ21vQ$S"1\Dc{1yA?`aGJm-k?38ԮsW$fFbk)I0[4TsA coxYkR d%2p6X*NOC@;%|9ѳ8O#aO2z|yu>9<$PK\keU 4~OEׯ3|{psA3}> WE O\$~x tHF,rv WuGNݷ\F6.J׃gθ?s*=EK VEWnOrrfnD4ijXfw+t^Ն2&\B|鼎a̿Ht8} w12X,"S0,h$'cAo~ls80 PntJ ~\"[U4aR@W#2fXKM芌&%ԂuZlU3brJ͓&24 n74Tq<?U: tz]>a9_0YY{(hAlVYW^^1^o/۲&phJ:Eϸ;2 5u9\]2D3кS!9>5 syHq&5h%% '/NbL,*- o?Px4<) vտfL,\R$s3NFK 0#U?S~}( =w_nI(!@MXKBqa9L}26G6txV $ ~chԷH(m}&83?2R~[r&M1rL:vOL[0BB =F)s8#s ߬h@3C*s5fcZ9xz "eg6{t]WKnNjיRp]DtzBc~'n_eu OtwIG=4XoU'ѝIpcA]c:lCw_-D6< lqO%'9 o-wԮ҃M.|~MI$>"č$o(26LǦuBơ @D<ӃjF)r WlH] c9uZ,|/Y/Eↇ*Q!&*DWtd,LX_{W^8_ -z /U\$K+z#&]t_ɛ d6Ycg٨vOUdɋSw- NJhv"oϩOzQb󌒕qV6aqPrq_o~?n0}uGujǁCDkJ{v9ZJX(:;uAt:tF3ғ ۦvΜ#+|Nzi5(/ø'=tG%\9i\Sib!!qn< :h% s_T%/$>P٧6 l_T@E/P3T"_6qG%:Z֢hQ'L7z JTBY͒U &82%UEr|{kF=k7 ]-I0-<5|p4=YiUx@\H9![PRPnݯM6oޫ-Z%^ѡ) 4iP7 ޲aǻ[[Z}Op$T){S?0KWeOKj+Sg[9OPOBBPụxX7t^"5U!&gD_]Ocj͏4F=Wm<!*H<)*0h:VhFcά^f}4yğqZWrI3qX =c7^oOYPKg:9g  s($[㏹=SDt[1غE,ڸh4q?[iS &*Ump8˽Uo)ΈٔjR>4ΣҦJTM70e`p`#샟\0gEw>6_&eG,<8ov4#柾MXlpUfC+u;xi~ Me[QFp8!fHflf,ҹ[7 ez1}| ^36Q792mRc0SM?ɞgIZ*u}e6 -d ء+ wSu1 (){j,вe}dޠsZtW16=jPZϮbVmZ07PЌ~( phUJLT;*D,YFIKhR`\ /!M9q0KFs#ۯoe[m /goXawʿՆJw6U1^;̆M\e564] l!GQ &E+$G z #']6LUu")ڐN /أT-Y?}HÖ+* Jcȭ|} ƪG 5ӳw o`(Xy&{mQ{#ؿK}iFŋZ8(%NV]nTº> bNLO^iAsG!Rڙ. x.DVBP5)/FQ*B͊.$Z* a^手 v?khuP} BEw/~ tߴ0+u2|OE2f=z!cАQPTpebj)܉\2AdH_smF|@Imަ>yݪ̉E DhWI`9wrٚ<@1o%51 J))KBT6R:J½MP fW=[@[x<\,ϦH۪<)-\h-X#c\ t=)G/uG>1+` ``D/-wAU͙G<o/,r;.?ߓP&dsҌ3"`U]y E] 9dW 9;c ʋd`!0 K=z HB<);]:yR<R{;I fXd>_lq]C"KHT< <m-$T bl o6v3E!&WQ^R=\Lkcau\(H DRfcNie ZG:},{6RC<Ⱦ]>ytǺx){Xfep%,toZ3/k?}mgWʱ-K*]d"i]N ?`DN?4.%nj|=0Ty"= KZtrws?^@%HԹU)x[3F`֢+rBSaP oȉr 7k/irᫌV6E RM0nUXSM=&–LF&^qŲcq_e\2ϥO}VZ#UhYG ƽ [Ne\ ]6扡u- P^*fs\浡Dix )kb ( ( jՕ4ZoO.1VeÜmH/ẔR#p3ƌojobTLa<&u삳//GψVR|糹$O1=UAJI[_hMDxWw܇VkSrueζHt<7Zld9weZmLao`aABNjZǯD.0?ܸuUO& 7dYDp}QbP)ŞD~S3bQt36IN<K3vVnOQ[}lbrv6xHl?}ϐxkPJ|fM|*!'w!.o6dpPS|,OvbNIsFza'Mz )d,BO\b@N.#&lbBOʓy#j䔓^ ;)ĝ}o!_p*Uq#רojzjPf?CцPׂv(t>ٰX,|h U& cuBҫOb":fPT #3洧a%61J|LokD(<^RyuSS>9k-(bV_VCV`zCiZnŒyAv@a`Gcug^v]c O&4 ֘9QW.Tc5woӍq"3YQƝq}hL1_18r&R,kd; [ ^q[~ L1)]!S U!~ 6S8888Ugx zKDsG*ѥn`':TE6H$e"{.byL+ԛeʂx*$\I:Q.4wG7`~~ZcMY$l"u!œIQ 0xH$#je QiV*+H!kdmF-Z2h-cB rqХ( C;I(lb_wiUtv?C`JtC[/aR-f_ImiV|`z6~ L +vƅ kRBͿA?#L,51/>Z-T?._R5f~yc-%2`.Րf 9m%5TݭʳV~ÝR~g2xe(/7BhPw̫acF$A89i w&2eJp ^,q)!5 Ew %HM64Rov6A 7JWiu.^5OtNA{&#OӖtE 7 T` ,u]~gmN()\>؛..C}-+tǸCM{ookץ" nE /rˉb6\TʿͤSy3kǻ&Y.J(xLgW;sk%ʣ{A5I=4O]G}ѺU[m^T |.ЇtA$m!_SG2K36CxЊ_k=sA i-U2.w$hBG"=+Rx4Ö<.L@>d.䆍XvÇAlds S[[V '6M[3$ar?|t !$C=&5^{޲>•@WKtbsׁSY;X{OU8|1 6`4mJIs[eCIAM+%1?QO;zw+ b!C/Bj9uDØ[(cI4>S|n,t=WjBm?Cn vCN@!D򌻲(v~ 9L vg/?+| Jv٠7!s:UbT^VߞQd>#a-EdxtoFUjg)&n,Zb]-^qmY,>̒f=8|Y wb82\5OзPL:1+so/]zRZTWbD$5X_Ng`Ǯ yvn٦Mt,RfbzW<"̪i2.CM=닇Y1$?VTJT?Z=ؐZL|F9KY%D-gq׺;YzM lx/aPc')5"(ܧ?{ }K&A_9"ԵՃ\xυIk1&-0KIi6:mzt sPe\/I1/zP0Ѐh˨l'a{zIUOK8qBsg_[E*[ӂ>' }᢫1)-?<:6q=!5U >I2#LZIY_a󤆪E(VP8o`"OˏtLncB~=FTѩ?pk M$nTq"A Ο le!%>v  1zP,0yrAVhױ>K[1-< @/1TWrJaD\xIyU~4#?t]3 ^ FYIZHp20B쇞 J45ZlT#v9'?(H$K1{!#w;6=˪>!|n<CM0S7ݳ*5rg; u:f;u>̄n$)g,Nu"ET:r̹&da!te0`٥3iX"L䲗DorO B7GZ!0!X, r({%L L?~=^(VDm!|/_T:GK@ZxˮZ^pc5Ajz~Jy70`g?}WI/WaWw.E6W)[*-.]:U%Cc+ HT17O7'>e:DO0ḑtrZ`c~qTW3GߟJז]?^hOnXlˡoE E|9] $Ǩtq e-?D2$0bN5hzZX N6fG<$=o٣V2^t3>b2;>udgƝ3[' 9!)w2_rN'Ua+gٮLwn%xhDe*)-%g !"HzKJ.Noq[C9̰!,r +^;T" 5B<[4 d)CN Xu84r~@\F8;3d/9EO]N>hTFk k!8\]A_L=zMr\-쥙c,rKqnYU-5Vi. Έ+x~y=,Qո 8zFܚqa '>} p Vo$ F=bX/Ro)58pd-5) R*R/& A;/)!}#l= 5O]sDBDOڙEtycp*[nȠ[wŸGy0q[8Frf1 dwCO ee,榔lo͎T oԹjTje@6J 0_9zs`hàk{GXf"m9xҘdհ晣wƜR^vp;S4HGj_WKòyeqiOgVK؊˝w,5nwg :FlN65y)JwyAk86m-H<% "[pt8H R3=xhbL9쫨琤sbO.LC''y ȟ(6'lO >‚؟P~-눠Th1mgG<jNLA%{zVZEGy.ȌSy쐅S'>Z`BK\mcs%c۶m6nl۶m'3m{bؙU[u/ƺ_B0i-/줠ngr`$f׹'y.7!WE ր!9}jƇ()$㳸5,e^XZy_me̙<t("Y ;?d#n6oF 3d80uEvdIzL1¿MrkP%4>1Db+h\fI"$?{ 8zW18_(45x1[mٿ~X3=c`դ,3_ksdMw@ jL/| K03? X ZX`G0QnJL;3܎}9vHS؞sL{DZ -L6~&C'`ui4E+~]68\KP]ot,K=NKEFeb" hl"Ag ``^]BSaLS"t/q$_.Wr/#%ݬeyFzt?E߼ ]o:xReNuJB\* D hX T2)k/;#BZ~iN:>,-'C'm<*Rs x{W!7dadRclE#!LM?-lנ 9|zL|?qXf1!dZ?K^rcnX{v;݄<yV-Shk(_Ւ0OTN<5 qۻ]Ge=יLIoCggΩ*ؠX݂0Ρw@9EF)(缫\k6m]Y5hw L &[krST S$(WB̓˃@` nQ9b{{(ΏKzSZ/U30A Ez [#O6rU ]ԾE%+%ܡ .v'C+rШ7w?}eJl y9XQȨ})?h\@ECbUqgZgh\7"Z*}1cMdN5,fAժp)~sŖ>[ScUi:[xqH\p&dHBnns^z[K z~٠Ϫ{w.P ;ZbN29|'t?l&; mh(Hu1-wV=]KUz2Zy,o"=|<+s @۟%槔8DfQ`9yxܟ_;lmA6E{V(P640Z ᦈ֠+&b*or1sُO U9#LA <,ZF'M |n۽QSvEMJI6!;FŃ}xA.! ;x')qcd5ql[SZKUi?yAco;u6-:,WH<e-H7nHb(3CHA|1"ZZuhHPq?"S1uM|9V.ŃS$E^«.j&Ęrt"xEdL4'|ޑ%dMsbᠰi,FHRqixE 4 ~Ն :kܚ$.n0ᅳRS7Fqn*E:&m-6f XVP*|ɻ@J( @wXҭuIaAǻ"$ B//lC{9e8كx9Y KZ3Fv%vH* ڲ[Ani~}&Ged7J%Q"]} ҼT,uoL62d9xMJ6 t?h'WXIql(^ʟT6d1 ++L8Ѯ!G?*mw'gϠL8&gz-\V#:8?1vM`HCHZ5!SeddP}:q}+ `Ez*BPgۿ}}zvt3lI7p.4|+ip ﶸO AƶOmk& Uv:X4k5 8T)f["nw칣S#n-zjD"ǥbȧE~4Mp^>6%DgoGt` 2YXφ `%Z#ZnXG<8w/`EeuAs((  `+Btuqd qyu^(lu$I5G cWz!R9>?UgƷpR}&o{I%9 <+a`vEk&7)t}<s˜!SύUԣ6-#"a'\Й([[7y?C` [hr_$#pjӲ5N jH`|xL3wl.LMje.eA䤿~Ck)ܫlM*=q6êd6/?o.7=nR$L73q]EŸ@2i.W2TP`fHݒ[M)˓gUE~oO7G,z Jĕ- `A͝[(xw/F?юG@Wrm&#mc5 vXG FrXX5 辵P|\ }#qux !i\ehuPdg2#u= r@E:zQw~Eh\ ?le4o9(ǶY!V)0 c `OYk.*0\2jat=Y(dzx}wE8^*o(]%uhn5auA@n9klO8`7-'Q8DGk.+7~(w9䍺5ҤdXQ Z}SAC@Vdb&,j}]A=jOIgD.u9mGEh5azs5wB)p3yACVsnQ4!(ٵuy.GDah}{ޓzOS|hUQ8>흌֯!GkUeUΕ-tLgr%\lF2A"0`G>iS]\ a|X.&)K҅Xș)%l%;gՇUe\eEv'{2~ Hv~>L9CXC_ RcmXm7Jh_!ɠ={?PEPx_z*Χ--6%yAk详gE#t%6 bevRĎ Es;wnA}'4z⃳ ?7CDa7Om>c+ VєKg |^5kNDS(~_L #cZBNcCm>Â4 #D9*p%o<ضa5$7=vs9\g8\#|EUy룣,z3]U j!7K\_*n=E>! R"{&VePv):&Ӓ^>ӁVi}{gZZ߆L ,f}kaj΢W1sל݇.j"Yk~BiJ.m Nou(XZc ӶMd->8=| \*"]R>7կDHڿ*||=@>otbBFM1Mbg~aˏ͙%&;3ww7J{iB\;iX j,l`aW~AgHCvMM7_D/_ ~VXF7֧4m# +hzuUR-vt"ީMib/V |/s9}z3\l*/,k+c6ͦa*]%;u77òEvon&"[?d 95ゴIu|޵DlʯnbO-le H]*ޣIuݿ s>%E{X}آRZM5qn<Ȓչ+)_4J*"ݮ0)"p{"< Szwl\krVj00pN0v " 5`ty:i+ ERB#Hɏn|kQ4Ɲ6֠#jKEG͡_'tEDሠ,:?ݥvץ$Ip^YLj"KrdNPW!W~hv̙d-#h8^/p/׉@\mmߢҸryyDK7c7 Q͚_$T6I8c4 p08_ ` cPиt|nuNjFE5}W$Pa'$WihI#DG/'iN D?C?`-wMO6WAAz&ER򩫨rŒ؞#E}^M^RL `ht^dRKھ fu3m89XeU'̓9:W6 wBVR̗bB +H7:oJRp B4!_ ^&ˉx¹ʼZ90%-,ήx5d%Mޠc'S GxT@@  ,`hQp1G7y -=  ./4ʳׁjނq?4S50VUYLygr)FДbcmň*cީC!Ir y*8`^ &ɻgq=qϹPt}`Os?dIgTA6WoyF)*EO^g12eR*#q!֨L;2~_BZ"UfDoS^%ah<(;$+*B'nh&'ܾY񄤳2<d&_8NO}'Ht Am@As>@hBoP)˔6%9£( 2T?đUԜ; ߏW*3}?wj1pFNrdC:+',^<1.%ƀ26pCwO'$ܞgw,K Y[RDѰU6G7eU/gnM|DĂa900CQCM/w[|Qﳅ?-kY( PWuÛȩ)8=li]ڴeAѩ:piUi.9:5fxC]; VwǨ^&`t:rt|]Ըzطࡇ9>5:`pIkƠ S)Znbv*Wh IZ˰Vp$vgM4^3/i݃=wzިG4o,4k)tWma틔4{rlgSC!-!vJb`끇S<1Z~n C($vzҨb\Π,O)Czpi\T-GQ@)8{j϶ ًVVt^OBr@7B a:*J۵J+sc>7aV%"7Ɓ4MſM͉I V,a|J8 ~% V@֡%\Ȳ .ԍ0qryLopE<( I~1[G^83 5%\Mw(d~vp 셶HdN2OJVf>S&r"NFyoP%V4:mz/FEJ91tlGYPsA3>QO?aEK3`4)6u/&eJx%`b!)HקOVe:+抻)sUQ SWx.umZ)2R@4K}\8v#^4S?lݫp'])g6$y@lLDЂ YsL*ȃw$56:іyh@g9:RΉzb-61?e]"ӳZF4aD i{*Y}(FX-URdd::\JY:SRu>v$UEf^o0GtfN{|x9Rh4Mt:ƛus6:y91Hҙ# ieq/C8.#.ꋭZ+'5GB@ܝKȹ8`),cE܈/E*1!Hhc-v6Ȣ:*'GTƛ anU&$;p6M@A6@ xAU(*cq4;qB>5E,zH:m8>77__5[Tg]ҵga"*6SҢS-UAc.'N@XY0 GzbbCMg lZT&PU3&vE{reuy.~2g p9-^[ vqL5 BsdVGt-{ۇQk5\w ň6/DD4GWE{| +7t{+U$E- WnTyzh^Q}%ڕcDQU{žG䝳II}bKR6b }~!mk\BB';uavܪ\ ?L*JuZwn)c=iAFIT5oaC;]C;Fcai"]vJ4Sxo4吡!ic~g"&]qc^"h Ŋ[n:gIvJ%IL XiR||9-3xYP]OUŨy| Hp/: ~IKXaU*ș4B֢'JT`|D؈Dݔby=@lυA&#Cocr@f82ROǀurW~jt&]d zr&W)=iEQUצ">Χ2BkU8_d,SWk{Dodb7kf$?# q7ڲ R$S.o Wuҗc.<W+V.RvO]FfE[xQ#b1+396fp.O! d̊'%q*DSPtBف<J S%cF?lHw 4̀qLf`Wua$-UͬL)M򸃐h$]͸A3j3pByH=KOw:EE; ihſ؊>V5YEDz 7%-j! O<1p@fbd;y8܀H;R*0ˀ9wW7m &;cW{ E\H jQŀd&*L@*Edq. mZfa }Asr3n?e+XǢn@f^MoEì[^A7Sr/ )BJ \!#2($bO(W4avN!E G'{<]WT*gA~s6*o&'SH8]S?L endstream endobj 72 0 obj << /Length1 1969 /Length2 21961 /Length3 0 /Length 23221 /Filter /FlateDecode >> stream xڴeTk6[[4wwww'8CqwS-^{s3sf]Y/v[TYA(302L@., vVFffv$JJ1g $nV%33 ߔSOldИ%(;LM\@5H"lmiO?ޢY3[w[k  ˨Ptp4 )`Pj4$TRJjo\G Szo ӟ3Xn@g?i3Z8;@c;213Z-nepwp=v 2+' w?[A.?N+JM?16/_yeey5  &`W_hN7A @O_ENok3x6}l3 @{?=)(HJ3ȿ A: F/?Dy̜vېJX )[ΞL=Զ w s?57wudY;e Bf @'̊O~+#km|{ y`gW?-!p̭o#&HEY8xߘKͧkEid 0Z 1):F \vv&@[yXhZHZ{͕fVo\l6" K;[?4۰]8+ ;tqpU辕Y"_6 3sk%`l6o)6z5!&F X88#"'I`&)[0Gzә[xә9ؽ_; 33" & W9LRC|o-)@ߢ;C|#Lo.@{>[P7 n& R8F 7ߝUsij`g[o?LLzo򆿽P7;'3 v*6v5kf_z͐mRCK?IOR0T j&,eL" 4gR8K|JiSڽ5'UN^o|RD&!2ɨ_AF{(U}&%1z$y:yB_3ֽp;"~;T;$'.ڤGdnk(ި,cw'dteFs9_plC(x) ӫ$ ;Oich6)F|QE֬'(o/D9P!>춰~'G.nsnCe{BF]M$4m@ZfvF>ZW[PMix~U?rcS8͗#4Eiq"?+Lrxmj}3Z>9 o/]u:HC7ᳪMYj&q(OA%½JeA\Lmsfͫ*6KV;#TU r5N8FodI ‘Ic6RDwC@ XH8Lu"ZlFz%B߁ ϋw,}\&WMjdFe'625 9֢1ETY%JXK(o/ 7TU{4@ݚ/vl0D`./WkxvR& [IݶRAJR7k,ޭYrl^}NVujz5h(v6&1AÂa5iyH(Yr|0Ŕ' f08W#HZ&[JnA j7ػUL`1Kdޑc@wM|F]?:&k|ؐ?agYWB"u2t. 3JV"X`JA>KQ1d[8|g(BMU.[#`,*YjsփVi lEڝZ _sU_!"\B>b}:Ai1 ZUQ b~v9%qj'VLq7B"FڿU"UE+ejUД O' )z?dS vRY 8EҾebۤ#>,-RAo O #Jb5BZs,pqeh ,'gBEYr%_!m2)kz4kӖbh !v=]wNJy›2#Soa>A:Q,.Mx:*BEQ1B`gϏgh,~Q1P,% #Xi" 9p>)Zݬ;=`V ,D[ /Ku{ |[X T:/g2Yx WWɚpɷu_r5# &]Vp7{/yH/l/>1+jY0/MQJBʃWf6҆judW4Kb!\B9k5:e lʣ(U~LE6F !vDSU~fU KoT̊sP'%Rȱ܉CƁy>8(JίAL$Kì/0P sք]c[8a俾rDkUF䭬m%Vp?EzȚLzj i8j@K 0f':0֕pEؾ>I-g"QOhbP&5ؔ< ; G񬬬ͱ?`#\N,T-"a: g]fL+lUq1,ʞH^$ӥ~Sղ/[^X:bJ45|1R,aK_emHC +!"OAΪR )kG&-)Bdh.67^ ֖x//êQdz}VdCx&7,8[k#J`IFZWЍ,myI͢ ~̐PYwY"4ՠմX8-3y6RZ)Jy>lNؗ:2|2g6A{kJy6t!+ P.axTm_8+3-U0kxÛh?goI2_PX0K<(ہ 'sǪ: 4[W4ɺlid'9(Fsi] z߇-omwk`؍c"Nuhh0;ŎwPWrbKЪt-"Bg-^u#/ LnP>Z"pP򽩗I`xe/)x^݃JO#Cu Qs9HЎDGrݲRVV?V/t!u&m]YՋà~~-%nRyTTna-n`hU?#WDS5RhW\޹N뺜@:Ɖ@{,&r#@DHG [pʾd=2+ckrusC6E!Tppf|.*0Ȕ7}IrfN!#fHm+t:ƛuR߈\ɛKo )rxi2D&{)M߶)TNBE([^|'7'Zb)>9M^ښ)Qfi5N%kbjO?UDw5pC|>Q$Ul+Y,ƯB@*zHmYFm!請8: Ѝ-GTT# )K4R#j"X:?t_zIgYGmҠ֭ҩ︝ ?h^'| HapRl4ɃrFV:#9oѴې5NԦ0I|˶2H[}Ĝ{JEƃpl\#z! wQ{c@B+hyCm+7YN#7vb#2֞Ɛ3K,wCNє˚Xnzs,f n!K, 9G?z63hG<[.z<TXYZދ ňUϧH?y'?BOݝtȫ@Kad(x&2̿@~05{457hBQ?Kh <(0@ #z-W[i2iB4*{{,@J;7#(áԞPYAc}o֣G:k~V܋Z3`)Wr,O=bԍdpMIs%DFϤӎ A0aer_=GLJ T;Tϵ `*47 xD\UӢ)CZ!se znByrN^LZxŶ3k#SݬX )ma.sVBKXVGK|ꪁyp/+*GVx}BnMe(٨ SyƇcº Lf.(`39YmUok/"/\7d9חz_lq*3;-^sN8Gq6rA;,gvTS^/&h,*GB&$d‘Շ x,@|VPtK6Ys~M[cKkN(`qΝlZ|f)7íC:ۋMSVұs %=U08tTެ(ӄ$@xkFG 7d0Tn# l۾%ռkz^_xA.֩hR^k5kVTSԹvx+j;m\S^Q$f5c*L6Eb|"ZD1,g<@wBNKYsʹ :ܽ64>1SEk: f'{r}~yFQωuCzn3қ-ciVQM1n 3ȻH-epQdLȌN#)SWRwB#dZ>\t;ߪ ;Q@֥c@3To/VlQ;X=0q,rk!9;5H⪯VA"~Q".{jv| 1%wr?DEGO( npR!ֱ 1Fy8q1S`> ȻtAYS;' n+%eW,vcN$NFn3as)쌨6Fb,1mϵ23]OaUo#s@MnhqJF\p (nl6 )hcl2tiЭ8zd~6> Ġ³EN?*bM`4!QE]G2%LO`aꘕ˔?ej9C<i/z z~yc{WY"Zh\봐KPyޫZ^ԼoXf> RD ;].jPCM~NxHCg i8TcA+H|21ʭ]O1@]AΈCx4M+,jL5'<χD٥ퟓQCbi^^@PVkЂמPT՘o8%F%65ӨuwdzgEm)|Lr<wɸF˱^jÀ1ݚ}ĦC&|҅,)k}iGG^4\T#-C0Mvy_%W~n'L!רJrL)Rw~QDƬ!1#K8˶ vSPU0mUp]awj* 7\!ӄRذ^.dzC~T,o_<2־MmD eηccOMzsAtaњ1ka-Z^,:9!ɍOcG4=S˿xټ#fp Ř+Gʰ$P''1@(:r;']j\8sFe-A3Q˘ {8E_xhF@Y\.?aGb4]&`*s ). _Y#d9[6W$"eً_ET7 G"2żOkB-AvG3nv?V4U[ytE?-jkחGEyI"Vd 6;L=u=SM>‘B|ֆ;`yc$|5>2' nvʭ2I_b<񡬴\Ğ,LB]oǬ:ʌHtQԎsdKA݁a(cX(+yڪwsԑ'b1C4,Ifjn$nP.PdVT րfNE\- $}mh~nF0SsJmc =9eڷ_q-ƺ5tej%4a;+O{F2ͫy*#*#l DDV(SHҵ[gc&"]}8UE?dR\<6 YzOfdq Tb : Sk%NT2m\ȏ[LHV|a.qXAgߡ^0"ߵX݅C9_ΏҡJ쓮@$sr9u!Sm]a =HPB]wp5A+/^]@௢qwe ! \ ڣb[ἳtbwC|4u!Rw1C X3I9Y&f>6E 9~p";I$a si 2 GA5Җr'Y^^Hx7ԹE4Xŋ(RS0vwcVq(jFiA,84J$H.6v_(_Z#>z-ۭ7WfRmzHꕆ/MUB(bl\\hlFkyy]5~2jʫy9 U6i@Z=q lֻ@9m } MzUnGKˍ4s2M;tE~ 4/vB8d`XWTt#c2DOd 8 gFyPz*{[`$iװ\u;KAnm"<чR 0OQD:i(8/.,d2j=w,! +!jQ~YޭU7Og旮嘲os##@K`ehCݔخZK"Vs]PP7҃n$YKkx4c'yT,}cTEi$&wJK™Ea]pÎcyDux6U gW"@B5 v; ^brdKjNg򃐨%R; IbO!@UvHtl')qAȨPe$:}]@~_!ǩG#IsFǏA31"bgTÙt !A\Ŭhs#N(t@\.,~59gcSя~KyeYk-NIOjubZm<,p;Sk!iZQZ>aC. !iR0R/ N822mJE7g S[|cXHYy39Z2${A)aCsb h貵6 Oڇ!GHG0ٿ]#).L:!]&Rq(o{&ZS:B A<^Y>TC `pK Y+1C לCli]T~؅p|}Oqe}U 0+Gԫ Mq Vm7IB"1cvnT}"92f$W/Oڄu&Ty>IF1W/?uFeeA]BO--[}^3:ԛ g4nyVH}N~m\+"^NjhL-PuxڏYqP[ZgY^QJ:wH?yh`p0I*|UxwTZzOmCRbf{ 쁆A83zYi^͗RDOZiZb3,o~&/|DU2 v/$b>EJ0&4 40]K-j:GSMF'{Փ`Њ>3a>(6mל֙aw˪v6d' cpiTkH{"ԣW;ay ]ďjdqVX}vp*ir ]8aUfTiS+VX4:!2o6ef}-ɮeGu_{lRvwb4TZ]z+V*+Ix Mx@C@~-Sq|Qk}L#+J.}l%D=c5,2x:&>uƴНDkZssP5ז݈p6>R׌,qp~ܺΤβ \c6_a/h}IISq\M}:i#sn^xce fsHÏV*3^eki q834+ zѳSvZNjǍBm)mԵyGJ>N""J]@{nNO2(g/ҕj7K_5䗤uNg01P<OM'5r?o`3*vD5٧-}AvEp[i gݘމ?9GBJαI[< 2ULO`*<"uTg!vƯy3_ PIfnI"I:*\DMBo6ʫЬmYaI׆(Giԇ7m4(6JMLzdxȦ ߠ]AEܢvEN[i/dDYݪ ;!sNಌokr]0 Elg7|j~Rg`{_twœr>V|=Z]MlsGW|{@ G8_-NiCM?e˶p;\В =DpFb&e" Sc}ߩ"C=t kIHP3TH..P=:6-فeNbD^V)'u]D6/:ʉK"! ~"J~f'gz7L‘U?'u]χBuy#?z޷Д"R^Ź׊uw|{|X;A=XsQG3DWixWxW+'_mZϳ|NUA'x'bsz?$fBY~iyk$]ТVRszcy$()ޟ{0sGf lO36ҵiRy~K¤ '`Z7YTȔ0sFޓcdAfNAA"|\]bc9u05g+~Xzmғ*][s 6B*i+e컕5X` ΍H{`B:#Ii໲ TS?1vW*.0bE0G;_ZrԵ~X^xbEZøDQs;=-:RT{-8 d"6f#ˈx&nߛ q+̻ipT}cmhE2!It<&! >k8g2dB,NeiDLO4(%,^"r,OzP$wI (+~ Ȝ+"YNR:gjC8JRl .B+P\IbDA3wl0E)UA`  AՌp2<nC'YżqXې5/Ͷf nD_`r0&:m6βH!Įtf`Ǚ?bhbF]!V)نPH-U~RP5TlN í:JjCȴ|.6d#(ek#nf^g9c2 'M C>sj|TU-/Ǻί+B6pH"QVIULrl!6d)=|_e;?BTH 8riH ?s̎ה<av!fs70^sAkW/LҔFȦ@v0~1DwXFAٛaJ]|ZW q69CR <\lHH=D1Gl&"p|M5L@yf֘ᇙ973}̉*4WE CVҫ,;^/0.<؝ j‰wOL`S*OՇCu읦 2?EV$oBnX}1A1 u?ods>W[ QG}EKC4F5+nNv+RSO_8j[CFܐj Kq/^  ~j4~iRaXUΔl>;EWw($L)]9p"'Bn(*Y@wucP46:5HXuFiKQ+a{X"׉:mZr OY[5Y6=]SB:>bH+qofQ3aⶽe8חa3J8P4KHZBu ./L 2*% RUtyPx) }) mx4ٲq#Sw"F,xry?phm]g W"nG7 8Lߙt$^Ii6(>p DhfQ`'"h4YI${|irC =Xv1Œ!>wgm8poyLA, \l!GF!1ZFh4@L`ڀey''vOL<Z 15,_:ku pW~ /EQ7zڇB +d4G[W_[֋LN$wAJߦZ$UGmRrxt\BѪ~q٥V?w^Wp2-y})-"b* ΠX8f'at򄺛A0sQuH[=E%b)2Jq[pRlpx;ī ֺRGעV:$Whl./|mu^2қX"m6Qhn>SPhme=ө?Lm9Y\ൢm1W]wkFtUZ=4;?7^Nn7KK?dԇ{IpUT -IfZ B3,FH;^5V0|]FY@ !G#䪭 8t1ɕV߯ #plGK E1u c"s%d!?}K4$w&ˁ#.Y siTWn5qyj :~@E|6F~r*=Y6 `K$_OX(/(^0F/ Na+J6`'_c}~aWԧ $M4^uQ9y /Vv_<x儶e*섇ӯW>Tu>DO|.@ػԥM{&~PA1];M:5Tb?/T>w@#ՑBBôM &Yp ;7GĂ~~[]q9d:(Fr  91l*jc'(jM50@2Xun4W?a-vޔe7b=,2=pdM.opO D|n 9 3YCHϴj&6 ijP,kt ]jm.&tjy@{-N-+XH JLP6$[6.ʖF, (I6o٫5|kC`ΌlhRL} ѣ㥽5ʙ :!qZ>XxWv1:VR'aV$Áo9R1YX#p}7 CS0 sФR3H.#O1Kz9A/*˰RN> NfΤnn'ʌjz}b?C}0 w}mwÉW(LOݻ&L:/koNĐ] RS \;>)e&4Y\qCy- FU[M>$H.~Ѹf6{_-ȷcML}a^mcBV3/K#\4CDw OVR5ZBbF{ 3Gͼ kw퇞8._z~' 1egԁޓ.)cމtdGde?7 4AsZRZlW~sNȋNoO%p%0PBn034ˁ"\yƟ$Ӝ锣c0Zɦ'T Y6l>)u,“7ixA f{)g[f[YݠP暯k|;CgU,aBYѣ192<>F:@tq7CD޸ȉh[Wa *G2d>I/J* b6}rU- B g/uG`՟EɶOi17()C|L)$b\ӽ_+7;䥳 H| r ⢈똃%ɕѠ;Ȅ>0 m W'TW-ӾQPWcJYqs0DG;'˘.%Qy y4ПCbx A*`m3sn 3rmĢfjKz9^ w}>"bq&2O}Ct0#QQ "[?2YWiM O/'6 4uY2],5o<٩tᨅNJraȋ6DIZ& $"%°oז^,ܷ|zN(iYӣfP MVaft˒3QC|{w6Ws}w Ӧ7WI0zdCzAkԑ>N2O |Vs)W5些V5 qkΈgKk+V_3} =qʩ T08_|1;Odnd\oc^n  ):2!Ф>@mV- :|_uߘ!@ $i1Uރ&p“>Gy#*^t(<+q.cRgV ֨,; f>yZXWxA*:"H|۲C E CtJ0R慖Ez)7*MZv/4w'xAF$;wGӰjJ #?OK N6=[[eʶe~Hl=8}ct h-G~s[ԂߡR]`T: vIL[S NlplC$}躻#jF&34ޟx}(xL䏬'O0rQƜ`t݊Q+~ hhAqd's1r&牭ϊ?lQn\x+)Z x( _qn=i2PՎ9":3GP.j;)پ?5]A4Z-w5,{ f8A*@l!yAQ 0Ѡf3LU:LdO^$; ~5jE:5x1[:Eߴ]!$t #|4P4MVOݎم/Qz,;G>-[ jd Hz7g֤ 2YOqӨ8`~x~gm#~rTʈxij|}iz SJ#!h6F 3yn_ﮜJd`7~bs-Qr'IM3z o=1ߎ5p.|B3Ƀcmv~8S6iW CĐ׻f3HsZW؝PǦ -v&r(jT϶ C~!uX , hЭc-l`Skwa> stream xڴeX˶5JpHp-qq@p'w'k}^kO?-cJQFFNB/lbg330dT m-&&6xrrQG!!A祈&&nxr4 CUw{ 3/h72tzwm,l)vf?cO@`hkfc۹-Tv#) )$UVqs.*jtb:@BMEϣ*@^{t91UaU-E1f?s0\N7wf:U@e0229;jnps?;5佝 s(Y cOݿ6|OzM?cZ+GsCree6 { 0~P  ]ؽLWi:Y85"`ja ϚYeSQ}-{wl@n'Y`f0TD杵}xѝѵk751yg{F5?6nf@؜OoO{;{dޞt'gXޅY]/;uڨ`4g }_ĝ mT3vJ%ohch_> 'q 7_] d}a[3k _F?]紐ş_wQ[lL/C(%.M01[c; [3 ;] ,OwU wyL';Q_(70~7d0J8<{ Qoog7z3q&lELYflF9[|k7d~k^}]큎v`^?{\|?_;o5u/rjX_"grpazߖ(sg`г]&::e݀y,BJ|&Kȹ14c!Na$ 7QJ$jaX5'TL\( m! d3-vPHgjMĶFE:"YP.HtK[Vr\ fQq'?У# {`HCwwm(|Zg:ՙJ~LW2HLU5 aj`ŕ0>$[ +ID*t"K[>uSiuA/+F֙8nrCg60GoMpZib7==[:iSh=mQ]47,ޖh s]VO#` z(- Zt|N<du9$˩7I1~'K ͽ1dv I:?L=ӟ'ynw3)MFn !S9ņV)ߏT9ZF55fuS凬ͫg}>=]$l>{}[Qw6p<(>$@F ^pT0 )521-}u)ak|(u(mg%dpVТM/Al=[٪Ia?m/g.$5D wBK{ ,p#)"V!Gs ~"0Ȕؠ{jT?fG@FB q\n6^ ̴Zt5}`e4$أT݄R`d LUrqBnm]zFzʈA4 贳+5pi3lXչ⵻EaEg0 '(laX̙jjgڵM9 }P6K'x D>^W\䈢i%C ^OH/ܯ877LՏrWE;1Ƿx]P9 T“ri0JJ9 jw5QcU#j~ %7 6inÛT hOeSNy_א;:HU@6'fZ:(Wi`P)Y_Q\N܌wP6HBZ~DUb9xg4Z^慷 3'k6gsdIߍt2YV k_q?EoUOE|Mv86fيYWp^"˨_5 삾@08#TlFuG~~g&ֈCl(ιNY ξxBR(V#~葼{g$"`'۹iQЪ`7!,o,2ȡ9%UDž\MS7*$O-'1NRCcG͝_0e ͞BsR1L~1~֛ʖأ#WXhsU$|B!$PT B CeKذ-J3}6VҜ@kU|,YY:A:e|m>Ri~A꿕.Tr+ :0rTi4I 62LW 5Yi=O="GOwT|ӭ"J#L|!h\PHmYlL>3[s[cLd|EbGúĮvda#XN 00ۯԠd. .9 KQ4ez Ěe6~RBit=q>ni26Y"5`<7%8݀̓LMXM)[4kv5jy|!p {uCεSgU vJ6Bu\}㰄!nI!7_8-C٩$Uâw4nAu`!Gqz٨Dsp_e `2kyAL87wM1p%!^MKbG6O4(\q+uY))ѮS$0C-,Bsv.щP.ǠJJ4 L0=,r^} 6qt(*$g͂P>Zi&O6??BM gVqQV DH4lrLz|}XV\2J8 IFK + $sނ)"lwEɠh4U1 пaBjUTꆿO!](PMEwSq)-kb;|ka/4|e,C`uJ139a"(U ~2gzmo$¡ԑ>% ~;l2I{jV Tg{rI;xj1?%ٞxJ/ktcK4H~zpQtdo2RūNfL&c,Ə):88*08˞vk4F $d grz};_t5g yyf p{I'8/rѤ+>x⺒$M)J7?JgvpC@?]In!\PT~;zx'%x  -nKvο0X)ȯRܛ@Ny‘x0CXj)lB=K ?U5m)Gg1&6D('@1qwiLlO5PC*!ꅇOV\MQk"QL .EzB(1hǩJRdo.;̰FM q+Ꙃp$ǒ, 1(*ۙvKVgz}D :__ϳ9s")ۡ>SL? ijtiM>, uZj5׆tJ*QMxsb7>/U^hQ+g-tMsQPU8RX9 dԼ6u"V 'g}@ )yeNWUuBrA'DUF*MO7]Rg!Ӏxڨv}`oMqyXORUkӪ NL+SnZVd$%Yؐk&) >bSj^놮H%x,9hm@_ id&I> Q XlZ{z!.̷o UyCg1cF ɭ~'ʿ-׌XõY`q@h`5*8%ԤJ{<9S(U3ԚN(븀xoOɿX6jzQIFx2r˜[< VwoDķ7;5e0q" Blߜ_PI q76yf m2*Wpz`p"K#'3IO\6,e2Ib'~?b N0;'JJf*j˩((G OTv9:)2zSGػ/ mX&E!Jo^FTutI`yTCƧ0"Q_0$ +RA/Oey &3߃Yq49V3nB?2 |ix:p!Nj,Ch¨"zujoA咎&&7ZG 'z!t*Cpwe X tL^|_)+>xsH~!b显kP8QÐ+Aj96a{OjEL'6r r*&l9'l MϢy`|>יuz_%us!U_%yIb1D7Ea2X4!Kqْ`8Atx V T@T[#uTnm}H]Iz񝭪c8?T{턋CArL8 .;}ܡ`sܛ'8,(% }2Tl=_;?mQVFMzoxܤD..azI G $oI2)i,8oN( tZ"U ;{+t~ gϟt?B7%{"*.w%& o*X U&{V)p4޲e}@_O!&u!56,C.kb;:sVp4bԵ;UXpmݩ/N!fI <Ǐ]AqPE}<>qBxm%1:' >mRߎ 捼pV$D 5Dgj̞,ͱ~ 1:쯇ƷQCqpܼI嘴핊< z^Չ-cifz*dEj#wɠe!GIXbF|kEZ<m mglPlTyNji O1Iy)]k2o^h`*(a6U#Km*-_Ps4g|#\+ܖF2,1E'C%^O6^Zi?X <9 t+EcaKd'_ewύ$8S.jHx@܆6QLr}OֹN!5o]]TM8h-OLaY ^\/=r@:槠Ş@-#T$[yt#ts/tX^\MkEO:r(*Bp1J3}QO7ʬXy:8=4P-xnh>^ 5\p>3  _T?a?Tonaǽ3ž߅/]Shi"wͱWͣE(TM1="s>|!@ sʎFj9pT^:GMyD9)j ϴ8ҝ/XFjuGT %)e + SbIN>X[dLqTpf+]oq#W_ÌIs.R V3~~ 渡TR\bB#jdʈS<֋5{͓# !h{tPr愍PZr=ҝ)RL%"ofd੮ !S$?7}SE4b랬b'emzn_O tMٮPm2Uy7s+gä R+HivCy mz VA@>tR\V͂',%d`3=x$/(gfUTmt;N.#3I;%2_Oy뛼~@a7BڟfMywlR)|׎ksͶPl6%}̬EE *a ^ 0W+47U?q+'H$"%/mxp lbW軨ot#hq @'XmP]z?!f:Ux5?Js p*̨\{[YBN=/bGЭBaneA GVH]>Siobk7/%A ز]A:?QU7և/uR>TH4݊Ocb⚰UAXG 7pP9ב-q?*L>Kdnn?iʾWr#!Hޥ<:ҿO7yMO_zOa%k-rղ Q|%es0}LRÎ- +G9NkBaz^'`cׯ#&qPp (+v}8J}ZlRc]}L8nKmEc\(95^tלZT.wZhLofK30rl^v Bqk qZyŇO}v6m5TU4fy~yt0n7Œ VY~XI^!Ǵ{V@a-L&@YSp*ЕM=O DE3.\ܾfD»},ZK_ʱGn7i?imeJHJLMt@z%NmSA]QIcDh3%ts@]7挜I =m"yAM$s-':DY耱r!" bAT[Y~;z#H)cԫJVQ!3v%x".ljn,'aƘD|A֪iHZ_a?6yQA/ˀ岖[IGչJgxb> oԲU\$d00s*-/^jBߐ,^7l|E:IAȍ~Wt⌎>=+ Y{[ya~lYḱ<PH*z y(Q:u2R5 8fE801 iX5n4m\$ѣN^03n O~>Fe7Oayl9SAqA}R}Xv_(pm/.QؤbMQLC>̣T(sqv+ aY6Kes'VQ6D: *S\ lcoNނ0z=W(.7H nE/X(9vVtxtV]}Cs>هi+Bf u]͢zhC'Yҽz]nxEE5lA >0`gKJ1]8p*$:.u_q8QFtEQ%';=0^p  VDtcՄqmQ YSKêF+# In$5 me*Wt$HRAxoCJ.m%u:h#82>BxOg~$U+f0-0sua.4Oݬ7o5p)"^,yoHG>wK9ZU)JОy%Ob*/.AmЀ:n<Dlw0IVЪC{ܽL͈ʃ;!i(V 0ߩ1C0pj4; BT٦{$jϰ t8+k0MzoYoW\rL^WWǜ %LmV s0.bdLv:s)ToI4!SֺQ4941]oQG$34넊Uvٷщ<戤eb'pzk7șUۢ\% `,A4߻kVص1'﨏!c%lVa*]K|O6(ߜ!f4 Z.krgaFTˮ83Ց'tKr_n7)zG%ɚ c#gi62^$@r nKT V -5yJ@}5 7_Rۧ'[95\ֶT9:Q6H~a}Rɥ/)~\bn4v'HB™2H˥O {+v|  K-i\ Aqa> ȗwP 8'vfoۿ6s9wFBߝ!Z>]>S`v;I\nۆtA.7uO>nkBVau 05bBʢZoEy/;p``b)Yx(8QXD+m- Q)hBxKY뻫\ǷokD燫%+CD:O[n{9BS)ĨUsVC9nuSF80Dd6=P23EQS2RI c_g~&D]./Ff<E\9wuVBsQyk}9g5Kn,dEQ۽tġޔs|oRmjvkG_>E3(o8F?tph'~!NI $վ'Hϼy)GQmP[m~03(™:h*R >5|#gxKd͓I0Cib)sŧ;3U Sh-tlS@Kr uk:STxŭ#m%/T\@HDk6"Ta^|xb9Jrw_4?H3R26 WƁ.4m.Q}^EHlY$5pE9b 7!. d50OYd'Y>D+_c{/K[DLCSDQ!?/S7}`bGEQI;B qrt{2-k&JpaewUm;;D/&`"Dί3umwQ#|PEԴ_0+o?ݹ/z~Ɂ9h#}e#S&im]*Ju_)(0aARdJ(YJ:G z<Y/S/n ۼOɉ.]J0 }.,9m%řw7̑)9!Uo|uivԙ%[G$￾Kn_jd!а#X$뼳aŷۮ*Iѭ6׀ jL'6=?+[|#͠LLj# \w9kE53M~m5P_7Nн'.zIu}MS v.G:tԢGwh|I2Te'6'ϧϩή9pJY** #Nj߭ԞIfn.S҆F>-u4iZlE9,Y]-(w+"BTL| p&َkJ|).Al-KHt YztK<6s ~"»F/Y_]wqSPi6| oد",-tT|1^*&=&;ӵ ;vq#k&0Qj跢֎%e "MTMuu:Q}0z߇ȀxA㕔Z2,Qb"ZMpL`jrOpf(18NG~z0TxwY>g ͗)FL3% Fe[cڮI\u`a=naO^n^7~B+ĸ6S(Rq}Ua->"5-rG=DB<\>B\IUMa9JZhh1RM pdD6q`a1\C7xȍʏA }kDk66WIr9}l'W&;pg][NP|VP\L.5:`pg KٜjgD(s5bZ$$U&).w{5!5?=mkFVcK0!tR,mA4SAߍ.ͻN w CTDˍF>jT:i\+g\16$n">{%SvW֮$KoYHkƸK zʼwɜʚ04:ʙ}mQI|D'2"ϢQ"e9:\"_fhQjnNABb(aSz(.a>_GuZlR߶1g0jY[6ͪdZAMm-dZ M]*#tB6(lE!NʫIO}z]# hŧ/*^Z ,K6QÇd1,ls[rH>NsN8vP@wEӍH5} EnCDc%SOf+e])l }"2ǝhՍ{i]NVU3nɻ*'^z+tF)`RTCZܷ(t yZFLdDTu˨C?`$-M_ٗD)mB5U~}t1™|7TҁUa| %9u'IږV2N,z-[; u۞?*|{z,;EӤ -AZ#qvRYY qן;Y9!'z]6O,l4=bxI< [T.6׊j!}e\u6:'D&0`7#0'Cjo2iTw0q\o09g 8+ W6T6nq^@48GKLXARx_(} P(97Yod9zYkU5*`;Hǜњ!& vD;Ttz$U2cbIH\#~dh0"urnX&yԋ0?.49%~M=- 7-rpQeB1G ,]A-|7c`F}mRRR =9+^ܖ7>n\?mbBS .hZorUwMGڴG^}V꘎meuzy9∷y~W &?Q_eoὨFZZ[䔭Y0RXo[_R=1|6잞˨3o7ł2M}=i 1O^<;CA~qnh' FJeghQ5ӂS{7V]߲9sV}"W\9fE+hLrWj?Щؕ:逎fvgqqɛt>꠿G"- *gh)n2#uQW^яq|qآ|zSY9+CۀkVx77|K[0x{֟B)+9|ޓ0?̆ٽxMͺ̕f#_I",\.QOK>&7=]oh*{?Һ_Y[qIuG$3 ğM10#PUA=#%z%TifcPuhkSOՎ\et|)U;ѩRB&g{LT(OP Ղk#cuxwPm`\W ݈;Xm 0B~*=*si}U&PkװCd2E^X@Es%~ xgLۊ#3gI7{Z S6W'3 H$I>qrXb.+`uo?Z'H_Pa"!ZJ$oqXП`"|㑁Ot~g{8fy4>#lM//~tѳ1%'WSX6unl&2||g_sk`*wY@wvt}-h81`$I|̕g۱jiAu;!=T1ך^_|QW8`+jNILO=O U#Aq]BTT*o# _:3EA&REIؗ+M k?;{}&,Q.sҳt{#_ef.Hng FXFxγh@2Q悖[D9X&n9o e*Nmlt׊Znخq_g "g|߆4Z Eڮ\;gb(LBw5Fs[64a23%?6b%>Rn,T*l~s-fYxhj'x,T^u)##([3FAu,t- 9_6֧j8-8| VX(9ՠƺk1/Cknkz4>0Pimג| *6%&YC7ӋX![Syw^1unboOMٺ'Ia/m2v^3\:\D8x$D#- Y!l/ę:_s_+Iu6A,S'LdxSC e-tl.8goT`"u oW"m%IIe_ȁČjT*K@7_Mfp 3.kdx+|ZѺ͞1 Kv6U IۊH }p6wZR`T7ɂey)}VH3 ?}˟\Sb }ۗ'l|6⤆#umPfH9^FG/C#] mqzR!I=qTQH+KDc=iL,oO~M(vʕZo&k-+f/ͭѓ,QMUT$4i!]ߏFY%XWtgte~ofB7d\ߛȏ*~ ue5_q?QW\"g1]*Q- ^ސ+yZ0 Ln`<93MKS$3C\n۾"?8Ï Nw a |,ܑfD\^gWc(zkܛ=s=]-БZ"!zJ~Rє'[6߰m/ZNff^YSf$&/> k'^/jypnCWnHBp~1ZV|Ȥ_kϚ0ʱUsUVUaS.& AJ% \=V f\7Zs"Si>Dnn~E tضzR=sX:/@ QZD!!-m(kk;Z1=ṋg)S~[*/1(`Oתd=/ 5950 ʩ*o(qTD2Go弬SVd- W~n޶WV4vgȪ}%A>NQ5^1lq`_OrVx1~Gn< o-@@Q%̲7E2/oӆhZ/;آ~9를 vviG)yE6wоw7=ea_-3ߏCwf1Xł\ptA;|Ul3Zc.a l +A([*8u+L.A} endstream endobj 76 0 obj << /Length1 1608 /Length2 5456 /Length3 0 /Length 6269 /Filter /FlateDecode >> stream xڭVgT[֦WQAz!T)қtQ:! $&M(K AM#AE.MP蝙;~kxz<U((XLB`pwކx0(Ci` p@HJ4  A8f"Z~}!"=/8v{p88!pM#@@OG$ 0@@X  X(WiX1`p( Dh8,zCP' "D|0bhDS8Wn,0WI}Ax`87W.G8BnMpw``H8K!`Οuz;_8,$F$4妇 Dn$PH D#nR;>y7qѿ<Z4 @a;BH@  M5gbXm7fA]N$Gf08F(XF/;.ǯv=`eN7oqSMm[MGTAC__(o(XN *%!G8lRyi7ϵ!AxlEKϕ_`<(د9x//7!(Jp( 暖aִKW:"?W8U5*|vcEOhy#+ؕOENx5Tn ]EE2kY ե[w(F[0TG^|苁ԺX D 5kGz^%ZΎ)BXׁI8̷zU Y#@hw?I5m'٪*˖] E<]_$Gj<4 4 >6޿V1Z(}Z(*8JRip?lqP*=:R.:?x9e'JKrzQ;YVв5m4ޑAYV$vbxkK[,a&=&:_ѤJU}O&$ssbI+wX%jS;Y|rgL84Hhfr5ngV۳ֿؙ->zERLc')IioMTev$o8 IoG BEEY]υ0l!PɍwxV2'oyj.vd`HƛS.̢Qwжp8LQFfC3jqD6xa+}#٠f\JEW3YNuqmvQզ2IbٜIq'=y^ZFH R ܀xj/ϖ׭D7eu $=h?"}Z~:xրD̓)(؟A9>;yy|cEdrB]"+|h'=ZW=euu[hs0lBCtGIRݽD+fCG4"u|F6-ɂWlvkuU{Qsay8NÀy V)Y+!2ؓ`;@$GXej;]b.xPf{-.cZ^( BQȲ֨.9|\*9+ٗcWx[Nק;Y.-&,Ej;l'.}n_v0/q>QKf2oQYbx؁T & \$Lyi|EyZKS<*P?sHUZޮɺ[|T[!3;bOx zg Ɗ[NW`-6|/5Bl9Zkz })}3KE׳6,u[೫UjucNR.,~;'[f})Y }WT辋U&G]Nj[P}}٬鬹,Y_CfNG~9fJ">,ǽ*n#A3t@?Ј<&-mRh}ѩy˱7B ΢8?axG [$doTzms0GQӥu)̀x\>y dP>~&[=k gɥ$d屴( вT Q H:Ko`oX= Yǁ.t^=53vPǐP2q ~$-%/ #t$څxD2(F =Mx@P35_Sv?q md3IZSy^S|1?in+&.$>L& ͈Qɇry a0ʗA W;fM滆Vdo38sM0JΨ4nT9OvJ3SxE~}FK1~ iЮW!d KQ-'7o{m0W.<72}ۺY5OnTwO\)S5BeB ,4>LJ6oH/?(_Ҷ=t7ӣ0}?<8`Xͼ%cX2줛YacҹBSlsX@%df ٨^uQ[앆g#%`sw.4fc"ooE;R_yg1}w鮛Y +l-eK}5icyCӻcdm| CUH]բ#w[ҕ[醸 np ?&}(fŶ]'G hpCSH^q(.BH_& CV|h6Ɨc?nY :"*tg%2)wUKeL~ ?Q)~by^CV8(~/S 1FvNk^wh[!b BkNq0!b+>q(yfZٹJTH敷d)O@wmpVoD%N:K7#^u""ҝ^*Non9W2tزq؊,y zqsޥChR;iFwLeŻ 6Of0f!ow38CnPΈЦa4,'#eWoNF0 VV+>ɍ:g\Q~u>bq 8b9~ϋi̒c)/cO!X\nctc$cҔ q+:$[]d*.o}9Q|rnS㣏D-eF5^+!Wsw2kX܍x !]vuSܬBkZk%O ;eMbCqSgڡRM4n t pYBGe`vIe2{! +y02mGTOE9&#תʞk)垵2%YNgX\5tQwu UmV3UƖ!TV3iםBs5UVX/fQg3lȟ+\j˓GNmc{N۲`WF*=|CGH CTBw$^EGd'ckTW%?0Cd]̧usm̵߿:\5(Py}wCduɄ3S1X':p)hV}X_6fu1 ݙ^|z邝ʁ1(MsC zԜvsyn♡Im׻x;7/V1.acR2. U,\cz@ Q1ԲenOA"/7u6)Y$"2~- <_i9]8~Mža*U, xI=jjFPRqR9x={ǭefίT$6,.[/1Q~37}T`:S *G~yu {ز跚U$Y-Ku.jq]pAibbϻwVDg9xcU^j$xc8)/X^r+p震_*@xbtӥo[ӒdqшOd]J,J#秌B_9WfOD\d N;v={Ehw ٖq*kskE wh[o#-b5.^ =/3<گP6{RKJxgBg|NnNU/I`pPΨjZwj-k ٬\0Sφg|'88`Aw#+Zw3([g59f9 դ)D:LpPє}d.#"xf˭ @tƵY;mDBu j6D*s]kJ*oi2ۻYm4,ŘYuHDuZ=Zl# endstream endobj 78 0 obj << /Length1 1625 /Length2 6423 /Length3 0 /Length 7230 /Filter /FlateDecode >> stream xڭVeXQ@s莡C@Ca`!nDP@JiiPA:3>^^ee5Ump/O@ s0o; aQw! {f8A p'_jï G ]8o]5?H#5={N rF_K2'{{ s7FW4ocQ+!; K P@!0` rBuw@MSO7vt]}Q?ؑ}9[4u#0u;4-8䟇ZVo8.Qi}6aBW- .r',K@fbU610ger$=a.*`eLOYDKfR W pv]2w%_./;1h J(23g޼5!,,], 4tOsd>ǁv5'jz4E4 6- F|5?PT4<4 &PX* #Gx9#o}0qbbkNɱ,}2k٢@Oqdi``tzZ=OH-aſ%Li?\#b[bg)A^L1~ArHCu:Zi%n԰K&K[bWhᗂ#MXl*+P(-v#GOIPn]͚*\,n >,A$_C]nrM!3B45^_n׎6?~*qLM.}mj98*UZѢ=c͟0xTig Y>s(1VjE~Ӣo)y0V5>*PfbqYpyd*h$~#*&Duf?. X٭u > 5c[0IBNXɦW I*ȶV'F7smNS0'J:X܎ n #Iӓz%o/K*nN;8xu*nX֗#!0X'Me5ɋcALc)>S=tI_Kôm!{4eZ&r: !H[\n~տ2hFR(zu;p؏jG/rMM1-Wzi<_A3\k4:|VVV.rmJG "(1%PI'Ч,>qm:Mv M9X⃮ލ[)Th#"F#ԊmI+!sIl(u~l?7ͩ{KuwǫִI^V@m"7MZ"OEAH+xP=FjQ^!a_xJQRɯ pĜk9)sA3'ZBѤI7Q<묑<`ߗP]ɏ) FinH/!R6r=p_k kִrcS?=@կHEb5,HGkE _KGfl D5̴jG9mWi> -W5[3_88?ne@. GD:s2Qp q \v1;<5]N$bڢ|4Zau>~,/Yo6$Ib;-kHݤ+\&mv_dFY ]5s"#~51L,O C{cr3CAqw+0"ZN.qy8}J1f]/]#vLL}c:<2# .y$Y!6CJJ~g}?*ԒJBiRzAyo' % i3wR{yOp7$?-j`w &\ޛ2_?n@e7]Edɰ~qPhm}1EĘ轕z[<ʄ p `粽dP~6 C$UtQ=fK=ecMuvy͢4xiPFk13Ɍæc Q}u:: 0+fu*YǍM$u [ykS Oli@Mk9 \W%KƖ<;O` %9!> ؠC͖>$_?H4':>7RPxSL\8,̔Pec-tӴ] `.${iX<${My dYjC=#En@TSK B5b6=:ƢuX-saJ ֏2 9] QׄJ2J)5,Yxyəsߤ9)o?^ܻGUrH _]36k>vA*: 3tIlhNs^/ Ⱥ+Kݩ)@@.~#"!ɩXs &Ȑ+y^fnI"q7 6HU?!B!sc_LGE tuGk4'}ur4 D5a]J/ߩinU8-m i(w(2L/Wxx& !@&M *اF:i8+5h2u.,yqɛ@y1\2&BmZ{7Ξ)F7e? h+8 ]^ W&t[gʛ~=0% 1z+X=FD$PP'AXDs TFN0o3uӔdÐYV=%G7>]ELf7F7qJ)U;C O:OҎkE0ld1 } ~  :&/T<{}"Xw.B3g̈Ek4zϭJpOC+"*,M '.&4F x|{?ѻ/m$C Qu{09i ǡqFaEh<9:uϚm.O<)lpR‚GBe= 4[L{xr>'ʷAA]- ̤ќĔc<3,.rgdb!YHF mcbE%Y ugHJ`҂pk+VFf0X65lUxK+vO]D|r! tfm/7؂!*hODž{x2(/*rڹ~4U{y4\.̌| %S5r-,% )UE3Nm7dv+&Fy7;12W˶2/u꽕Gd\yH9'_/6v!Rs[s;"[G>p1 Ͱ=hYRiX\tiz+ א,mQ'[C2ZTש̹I {4vΥߏm^zQrG[0}"=(RiA䛜r,3MGE3;G1h6'm]+8Tӷi\o0/ok@j4\6PZ9s` |Ҫ^dOO=1@[w&Ջ]G%_?}ƛ ?EhxMu]9g8} 1968 ,/X|(OW!i/F7ND`dDl na֟zQy}KzJ&^Pae!jl@1<4r1Ftzzgf?DžQLwmDh #* ؓJ׵ZϗeO9}3}g5^H^~yDjQ S4WUsLg W-Qk$UXvn`+Gc(K*Q92_ʈvُGMrС#&v ;g~ڼub.as N,Ttyn^[i9=Ggyv*y/Gx4E~Gө> |G'ɝeg+ C|5fa,m-Yb0CiIx J@ ge!PڅH 6'2V_uUJYPg}v:^;YKi@Gģ򂚅<\yܸ*,x|2} 7d(&Fp>iUQ)%Nm0G}]h[l~| j%W\8|{Ū Xe5Rʯo:,gV*ɣ7)sk\t>YBHJyiZOW6q 6S FZIZx^144AhI*")4ճYKޤ@e3}+HUHwio 9+q|>?zDe=IHn^"7UM}EbKDs cEŗ2WMS7-ضhuQuAq&7KO XE]GszfKt$f^sz'DPal2@+.Kf4rjh@NXj)ob࣯m+5oUyBNMe=ZKVD7opvh#pdя1)sg6hkl ]ZY L$'q))'[#&O9 ^a.=OU~RY95Gr-`T,u{q)AOd>Svޕ|+%Plx9$>\~Se? ڽt6(Ix2_4+~hɓT, 5ȁSIK;RGI~P[7: 5C]\'#הP>u>|UBNJz A&sr8raZ@H~[$kQ_\J-yoQqS9G̜c訾S $#6GxY93miI]L$^cG+^ҋSۡM@<>mN&#by 3Ƹoau K+]F}f?3rjh `CpBN%_Z9&L_l t3[h endstream endobj 80 0 obj << /Length1 1144 /Length2 4913 /Length3 0 /Length 5670 /Filter /FlateDecode >> stream xuWe\T[AB:DbIiZ%TN)n%TBDs{{^yzah"A:BՑH( Їy8zM]!c7 rs0p+Bc`H*sśz((e%@Wk؟H,@ ( C\QH'o(c A!P4E*wV sq̌߾-78Th s‘2]Ih@PUѐ_`5 ]+)+" ^ahga#U%&53U tՔ?@";-A=E0/o_Ac.P @( ^ȯ$ F@z"=`8 z>P }ܑ@ p\]W0@ P;\Xj3QRVF^I BWNR!>pFd(jbE\mX~*#10'(o%Wzyguo8w|4 F+  9)!\ VA!07C@~qPC$$@L]aN(}GJ5CL0W h'oj{MCLU~Wrk|=|܈ějR24h47ewI>;1XW(9VT1@Xyd+yYv`m_G趁&,xo*-42LnWۊn󘶬abKB"h9O-]&!.G$UĬŒ;-O=?\xCep? e&y>7$W]'=!e*`m@y~>[59Z1tg"5s~_UD&,tyd.CnYmp>!IqN!`y=i<#I~?QևbqnQrbQV~^9bipڏV7 *szBʥ̛5\^Rc,c!M9Q_"<#7֜j_UǮ=Ey)9^$uDGQ=4!8g +q<.ea|_mX#`f[.}TfB~[h6vxDLdþ -\`e㉦EڍK;B7b|$׾47 jcVR$i ΢Se6{LƦSN^f1٪Ngi}N;b`,&s,nsJ/V]nP}kɪ!E{o<ݹO߈]5 :^`RjoÎX~XMKv X“gw&2Lp cxei QШh/d `y{U^2[**?1 D⌕a^g<)3fhxk]}n17!l / tnɔyV`,y!==4r_Oa2Oq&ƨ ?)՞スRෲ/Bc8XjA׻WBn.>.M`}ܬF512:b`E'iN 7+N_&;,^o\%S AЗ@tR%QXӖ~&RLN6YRYS:8I gwGw|=&npɚƓO1 _ý붂%[407/42._Qc;i! cj8B%+Y% 1\SjieO/GyY 6h*<ӪIҦʽdtKH{Zz"HLkL#3!{yZ"%TkY:%r^ؚe9 =Nbi_W?ft@7lF5&%Me_٨La͂G$fPoyx|%olWyNc39=1w;8Uo.֟>;`>a%<֣,>¤c>G BTvKb?l}nBmq jg丘wYTq2mD#f9O#\Vg(x X~2 e>>dgKm էj=9V(aTV_>nؔ<fw&1n F7/N,ҵ|x5M+(&-2e+<9z\`5SFkGի*d 5 ?{-6@pzՀZ7N7P^EwEqa|yf[ 艔֩R.h=]hΥ4,z 4n=L8҅;+DdwF|i IaisԨ\CJs6Ƃu}[|Ƃ1噞 (i 6`o>Okad^n֤Ot`r^tYf~oT?^)!.^(PF˟X"\GaMJTwLs2[}_DΆ0N{0W'X(³S_W, ^CBxT >TApn/q Z,`b)m 'c9!&iZ,9OWU-"Ɨ4:XJ+GA^|џQ]z!p|pj<5E˖{rdߊuk^*nh7t76O[k$W匯64w4̨*J>( n~y.=;b2wyҵ٪ H_H9.rjR4ala&uL^~eZ$8!-P;Nx%ʓ};`8ɍHdB"hZ-Dd,D/mr.pisto_oj ._(‘ߟny?:ijY :P7 +.t…D`qP|{WWaWk=Y m|S";ߩ~s4}$!s{ES3(; n-3%8B5- Nll|V\~Mد,D9W,6>i5y!u:_SdG?ƪĤ7ҟ Vʥr!>f"h#8B(ڙ19FQ\~5ړ>6*) ɐ*ZaG|P3cʼnN$Y+ڐ F i#(({%6|JܶJ4p=D=q\Z// Usi{B&N,/sS3I2ti\:t_gQ9‡_Gs+ny^L8eB}NܚuUGaxSa*1du }~3?o`%{+2/GL05_*hn(#Kٷ")uȴ!VOvl{u}4飶YJЗ85kx?)M\4/z(.Nk uUۜTqSm7%1l*dTt/})냜OҍمXC ]c.xʜ+0us`o<ꤵY[5ڤ}pJB LmW7Կ_,F)wVi!f^AgL\x2`c\^-nJG: O8>@}m. H'B K[kK'8qЋ&qeqTgǡ=2e6`0#*E>!B}h Ϯ:#醘PR YT=KkY|z30-gf"d%m=]l^<UFODx|ďOJrLU_pTPvK +;='*[H3ѨNnP@hT<,ת]D[ >\mLoXfAܠN.d=4 ٔͯ,lS:h+3e)0`07Frx⻋9R|dp}.q&rѼ!g8:X _:V|fQ2!p@$zv1-"x%bꉢGߟ%RlD2 k)|W--?a(`YTgոkx>V:(\J\F8G1ښ]1VTONM0m endstream endobj 82 0 obj << /Length1 1177 /Length2 3641 /Length3 0 /Length 4399 /Filter /FlateDecode >> stream xmSy ћJ@ŀW2% 6\N N=C/E7` Q B{@8?7/R_ ] %pkb0S<LwIM6-$2ɰkSX¾8O._9]cSef "ݙQ ^CDL@7EI.ZR"rw,V|L7|̠DMI[!&Z-1EB}-ccxU޼렓\{c{qU:qT֔,Qy|Czݬа~61O1o.xjص*IZ.dHKX}uTz N No< tKCq4NG[ FG:k$^ql"p\l+o ۠KF7>~>\za:W·qd>Q,*]w]Ō /gi Mp"CZILaco;sKIgI 7/mZ )s!)0k#`Gr|li-Y,P%L?9|dVJHk~  9D^n#01:<^-jo2V/Lau[Q O%V{E&<KOT*-|„nO_<&.bP"mkd:ed %iӮ;М0='PX;Q4t$0A.m̖MTzqO0P@_%UjqiGXmL”NRLMz^{cBPmSmw&,o^D6aGeP5pi>lNj5[Q4+\\~Гe.-1Lw:#AZ#t!C6 C<1Bx54pe4oIV5**("5/fKVe񇏟VYc>;ȴ>9gq lZF 䘰6rg߀ kmKDփ4U_}{= G]ҏAѪ\mkF>CX}Fc$|Z$C<{mxtTCɴN|$F|42,nJ+HUޥ0]pGVY |Inj`>ccGء4avV*ڶB:-/"u*Rj$j*!36//$Z qI1yNag0,\|u[e&aW !):!&cjVr|^+B*cUcݫJ5EGF:igT*Fr֠z ˎڏHʼni;zl:%0ޅ 6#Hk.D7-p{iQvҌT^OGesF}].Pwm\ LX}.a=f1K}!l&*ƣrh}Bmly:ΧItp?T7 jץvhTo. o2dʙ ƵlӘrk,+0Ja^@m')߿ꎷ]ڕ{oxB N40ZlēT6ڊEsP(rA&Џ'} #64n+o y$Y%D=lX\g!rr4GY1 }E.̡ޚ<\S'`J%x]5>X(F-qy!.nJֲFDw:Й^7^/=`ןUCsP_\ l~: -&-/`1>Ϲ :c<2Ӽ'}bHc/I Tn+AХ(qX1WP |/60VĪ\6{yt*xUՄ`#$hK}\ 5o){\ X@fWE&2Xe䴼}eyoL!4?g$5ci+j>6AqEs<~Zkݐփ:bx sI"Xsj6.~ԜƳJ)*\gzADc,ar+DHT1 eC-?+AiG.8^rYsTvv/c*QQzL9Un->Eſ.Ԑ0[4qXʤ&I9iI v5"E gJVSlI'\1?WXQliH .i2FA\7ZoG(I0\kAMdjzvr5݆ vqH@I+GOP5vVC^X~x; `Ȉ۵<"""ZzaYҝ@QX2^q>z['vLx3El|^رks2.a,ؚbJbrI*l9Ʊ}''X.N \%'#b(%:(Ⱦg.2|/Dp5j., E7O^Y|]tms&Kqg{KVFu|ZaӋfvsTg/QE2o7fdY!NjPs]HUWsi .}#uGFeݨ}XE ^c?MXDOG"Dj$ILf:&,Ge4eܛNу_BڽǃfGOe 5xU7k47{x҈2fJ' bsy>ݙ&ϷZMN$'-#FҊzc L/鵯 @I V'iyOƫSJ9,՝V8$]#d4+k}hљıO4)p5ɚ|WK||fdS:+[{e%"猾׻[ۢ } xM)ųy[ɴIM'Bի5kqt(D'ȕ_͠/s 7h;0qkƗ'KS}еcЩ[r od.aC endstream endobj 90 0 obj << /Author()/Title(Extending GenomicRanges)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.16)/Keywords() /CreationDate (D:20171030190045-04'00') /ModDate (D:20171030190045-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian) kpathsea version 6.2.1) >> endobj 2 0 obj << /Type /ObjStm /N 72 /First 571 /Length 3199 /Filter /FlateDecode >> stream x[ks۶_tL NR9e֍,:&,@Il)r⦷w:c L0˴`)3e9&R24x&=)\ը3̡Ŗ)S0㉮tG'"eԟxd)tfe4DmOgxf4S]++Z(^!^2Au`@Sf%SDcz(0=bvX=FS2f1G})jke9R$ڥ(iK-KSLǜц9ɜN3/kHBH aQ(Y& )2#l]e)ŐY!\ !G!a&8 0_AĕФA)!OfiEY#bZړ><-dTB@ H1h< 0Sz 9R){1~Ad|=zXSd*ϧ!*VWeqy5E1a٤/ױfeujP&?ǟО!=ɨ'7y `3?OGzE.*xj90)?)u:񃪜^fU>\U1|fcd8AQ&cH#1e҈:>Lx:=NYUP'M 4AMXb%^&+D+h dLjtˏ|ѣ0'Uu}#grP*) ~ (!Mf0Ft J$*@*6QhktbC28~gJXx:cM& 7 Gx J&Vn}pc0}+HWZ4iZ>rM<ybS_t ɪHzoZ|yoZfo#{웩Y#sd2m¹cFnd_6U]|i_iV098kU!CpTk=|}A]>UJ;?L=4vDπ9{X1mjZψ|Bn߅"2 u@ҐzHSE"u{ƴ .DIkZl|҇¦Da2Bk_#c^/׎wd00$oW]ZC-RZG"k,sZWX !P#g٥}H%j4Q0Zfg 1omN[{iEA5Ɩ6*W(};Eq9.U>FQ~1a& ],Rm"6| #sw'*.e[?p=L`C^Whk>.6{1gK<?A1*1UQ'!Hǂ#lUy|ċOQ~w*%|}YL_u) RqkPӲ.F11Ҕy'|R|D5ÈxaZeliWeFv9h-뵦:mI:{ E3m-[1M]=9z~rt1+VvXlKIC,ņlx#+V]_9@e&z]%Y4 9iˢ/`]osCKj%iс~y`rtּM`I/H%Lz ۪ ZM `.+fft [f?Bӕs#?Ff,YcF~eUUAHo~_ DRMoZ-ٚR 8آr';φWg @9Zc4iƒ:꒵|~ۓOn͘GЪԇkD/AK%VM5 1ꯝp")@DqQѓtĉ?kO<ӪM;UٝNUЭoSe:؇WzEQm#|6 's :KO86}-x<(7bw#ZCJu敱ՙn" fBq8YD#17V÷]D!!rd>Lnflǀ,ӝ0[$I'D yNXc@mN7UkbdPa"M!3>x_MZx^I `<@̼7¸}X8 No.A&"?rMYt2o}XMjZL"8g/ĵo儎~3%љ[i`\kcǮlN.F>|!沥d[- TJ܃P% :$79S}X2.ebv![L]% :Tr!VKʼ!Cڒh7u)L=2zoXvb jD#fQ Ś٨:<6%|ZcjDaqI,{x:k8D(@aG !՜M/#ˡa6kn֤ѱnacGhN`lyU?N*OVү%!"4n1?^ [Nj rVa+=#G]t ZaMaE/bh9x?SEq\դXbmѯ^  endstream endobj 91 0 obj << /Type /XRef /Index [0 92] /Size 92 /W [1 3 1] /Root 89 0 R /Info 90 0 R /ID [<49864C1BC7986B12126CBFF02555C4A1> <49864C1BC7986B12126CBFF02555C4A1>] /Length 230 /Filter /FlateDecode >> stream x%7NCAE{ &Ƒlcr4ɘZhX ۠AB,xtiFR79E(%dz!+iUR CJ qo Ёc؃}8S8]83@ V3p0c0 V&a &,’UebuV7]3QC.j~jٯQSԖp];'u0I| endstream endobj startxref 139550 %%EOF GenomicRanges/inst/doc/GRanges_and_GRangesList_slides.R0000644000175400017540000002742013175727455024170 0ustar00biocbuildbiocbuild### R code from vignette source 'GRanges_and_GRangesList_slides.Rnw' ### Encoding: UTF-8 ################################################### ### code chunk number 1: setup ################################################### options(width=84) plotRanges <- function(x, xlim = x, main = deparse(substitute(x)), col = "black", sep = 0.5, ...) { height <- 1 if (is(xlim, "Ranges")) xlim <- c(min(start(xlim)), max(end(xlim))) bins <- disjointBins(IRanges(start(x), end(x) + 1)) plot.new() par(mai=c(0.5, 0.2, 1.2, 0.2)) plot.window(xlim, c(0, max(bins)*(height + sep))) ybottom <- bins * (sep + height) - height rect(start(x)-0.5, ybottom, end(x)+0.5, ybottom + height, col = col, ...) title(main, cex.main=2.8, font.main=1) axis(1) } ################################################### ### code chunk number 2: GRanges_constructor ################################################### library(GenomicRanges) gr1 <- GRanges(seqnames=Rle(c("ch1", "chMT"), c(2, 4)), ranges=IRanges(16:21, 20), strand=rep(c("+", "-", "*"), 2)) gr1 ################################################### ### code chunk number 3: GRanges_accessors1 ################################################### length(gr1) seqnames(gr1) ranges(gr1) ################################################### ### code chunk number 4: GRanges_accessors2 ################################################### start(gr1) end(gr1) width(gr1) strand(gr1) strand(gr1) <- c("-", "-", "+") strand(gr1) ################################################### ### code chunk number 5: GRanges_accessors3 ################################################### names(gr1) <- LETTERS[1:6] gr1 names(gr1) ################################################### ### code chunk number 6: GRanges_accessors4 ################################################### mcols(gr1) <- DataFrame(score=11:16, GC=seq(1, 0, length=6)) gr1 mcols(gr1) ################################################### ### code chunk number 7: GRanges_accessors5 ################################################### seqinfo(gr1) seqlevels(gr1) seqlengths(gr1) seqlengths(gr1) <- c(50000, 800) seqlengths(gr1) ################################################### ### code chunk number 8: GRanges_Vector_ops1 ################################################### gr1[c("F", "A")] gr1[strand(gr1) == "+"] ################################################### ### code chunk number 9: GRanges_Vector_ops2 ################################################### gr1 <- gr1[-5] gr1 ################################################### ### code chunk number 10: GRanges_Vector_ops3 ################################################### gr2 <- GRanges(seqnames="ch2", ranges=IRanges(start=c(2:1,2), width=6), score=15:13, GC=seq(0, 0.4, length=3)) gr12 <- c(gr1, gr2) gr12 ################################################### ### code chunk number 11: GRanges_Vector_ops4 ################################################### gr12[length(gr12)] == gr12 duplicated(gr12) unique(gr12) ################################################### ### code chunk number 12: GRanges_sort ################################################### sort(gr12) ################################################### ### code chunk number 13: GRanges_split ################################################### split(gr12, seqnames(gr12)) ################################################### ### code chunk number 14: ranges-ir0-plot ################################################### library(IRanges) ir0 <- IRanges(start=c(7, 9, 12, 14, 22:24), end=c(15, 11, 12, 18, 26, 27, 28)) png("ranges-ir0-plot.png", width=800, height=170) plotRanges(ir0, xlim=c(5, 35), main="ir0", col="blue") dev.off() ################################################### ### code chunk number 15: ranges-shift-ir0-plot ################################################### png("ranges-shift-ir0-plot.png", width=800, height=170) plotRanges(shift(ir0, 5), xlim=c(5, 35), main="shift(ir0, 5)", col="blue") dev.off() ################################################### ### code chunk number 16: ranges-reduce-ir0-plot ################################################### png("ranges-reduce-ir0-plot.png", width=800, height=170) plotRanges(reduce(ir0), xlim=c(5, 35), main="reduce(ir0)", col="blue") dev.off() ################################################### ### code chunk number 17: ranges-disjoin-ir0-plot ################################################### png("ranges-disjoin-ir0-plot.png", width=800, height=170) plotRanges(disjoin(ir0), xlim=c(5, 35), main="disjoin(ir0)", col="blue") dev.off() ################################################### ### code chunk number 18: GRanges_Ranges_ops1 ################################################### gr2 shift(gr2, 50) ################################################### ### code chunk number 19: GRanges_Ranges_ops2 ################################################### gr1 resize(gr1, 12) ################################################### ### code chunk number 20: GRanges_Ranges_ops3 ################################################### gr1 flank(gr1, 3) ################################################### ### code chunk number 21: GRanges_range ################################################### gr3 <- shift(gr1, c(35000, rep(0, 3), 100)) width(gr3)[c(3,5)] <- 117 gr3 range(gr3) ################################################### ### code chunk number 22: GRanges_reduce ################################################### gr3 reduce(gr3) ################################################### ### code chunk number 23: GRanges_gaps ################################################### gr3 gaps(gr3) ################################################### ### code chunk number 24: GRanges_disjoin ################################################### gr3 disjoin(gr3) ################################################### ### code chunk number 25: GRanges_coverage1 ################################################### cvg12 <- coverage(gr12) cvg12 ################################################### ### code chunk number 26: GRanges_coverage2 ################################################### mean(cvg12) max(cvg12) ################################################### ### code chunk number 27: slice_coverage ################################################### sl12 <- slice(cvg12, lower=1) sl12 elementNROWS(sl12) sl12$chMT mean(sl12$chMT) max(sl12$chMT) ################################################### ### code chunk number 28: findOverlaps1 ################################################### library(pasillaBamSubset) untreated1_chr4() library(GenomicAlignments) reads <- readGAlignments(untreated1_chr4()) ################################################### ### code chunk number 29: findOverlaps2 ################################################### reads <- as(reads, "GRanges") reads[1:4] ################################################### ### code chunk number 30: findOverlaps3 ################################################### library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) txdb <- TxDb.Dmelanogaster.UCSC.dm3.ensGene dm3_genes <- genes(txdb) ################################################### ### code chunk number 31: findOverlaps4 ################################################### hits <- findOverlaps(reads, dm3_genes) head(hits) ################################################### ### code chunk number 32: GRangesList_constructor ################################################### grl <- GRangesList(gr3, gr2) grl ################################################### ### code chunk number 33: GRangesList_accessors1 ################################################### length(grl) ################################################### ### code chunk number 34: GRangesList_accessors2 ################################################### seqnames(grl) ################################################### ### code chunk number 35: GRangesList_accessors3 ################################################### strand(grl) ################################################### ### code chunk number 36: GRangesList_accessors4 ################################################### ranges(grl) ################################################### ### code chunk number 37: GRangesList_accessors5 ################################################### start(grl) end(grl) width(grl) ################################################### ### code chunk number 38: GRangesList_accessors6 ################################################### names(grl) <- c("TX1", "TX2") grl ################################################### ### code chunk number 39: GRangesList_accessors7 ################################################### mcols(grl)$geneid <- c("GENE1", "GENE2") mcols(grl) grl ################################################### ### code chunk number 40: GRangesList_accessors8 ################################################### seqinfo(grl) ################################################### ### code chunk number 41: GRangesList_Vector_ops1 ################################################### grl[c("TX2", "TX1")] ################################################### ### code chunk number 42: GRangesList_Vector_ops2 ################################################### c(grl, GRangesList(gr3)) ################################################### ### code chunk number 43: GRangesList_List_ops1 ################################################### grl[[2]] elementNROWS(grl) unlisted <- unlist(grl, use.names=FALSE) # same as c(grl[[1]], grl[[2]]) unlisted ################################################### ### code chunk number 44: GRangesList_List_ops2 ################################################### grl100 <- relist(shift(unlisted, 100), grl) grl100 ################################################### ### code chunk number 45: GRangesList_List_ops3 ################################################### grl100b <- endoapply(grl, shift, 100) grl100b mcols(grl100) mcols(grl100b) ################################################### ### code chunk number 46: GRangesList_Ranges_ops1 ################################################### grl ################################################### ### code chunk number 47: GRangesList_Ranges_ops2 ################################################### shift(grl, 100) ################################################### ### code chunk number 48: GRangesList_Ranges_ops3 ################################################### grl ################################################### ### code chunk number 49: GRangesList_Ranges_ops4 ################################################### flank(grl, 10) ################################################### ### code chunk number 50: GRangesList_Ranges_ops5 ################################################### grl ################################################### ### code chunk number 51: GRangesList_Ranges_ops6 ################################################### range(grl) ################################################### ### code chunk number 52: GRangesList_Ranges_ops7 ################################################### grl ################################################### ### code chunk number 53: GRangesList_Ranges_ops8 ################################################### reduce(grl) ################################################### ### code chunk number 54: GRangesList_Ranges_ops9 ################################################### grl2 <- grl grl2[[1]] <- grl2[[1]][3]; grl2[[2]] <- grl2[[2]][1] grl3 <- unname(grl2) grl3[[1]] <- narrow(unname(grl3[[1]]), start=5, end=-5) ################################################### ### code chunk number 55: GRangesList_Ranges_ops10 ################################################### grl2 grl3 ################################################### ### code chunk number 56: GRangesList_Ranges_ops11 ################################################### setdiff(grl2, grl3) GenomicRanges/inst/doc/GRanges_and_GRangesList_slides.Rnw0000644000175400017540000006607613175713746024545 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{3. A quick introduction to GRanges and GRangesList objects (slides)} %\VignetteDepends{IRanges, GenomicRanges, pasillaBamSubset, GenomicAlignments, TxDb.Dmelanogaster.UCSC.dm3.ensGene} \SweaveOpts{keep.source=TRUE, eps=FALSE, width=9, height=3} \documentclass[8pt]{beamer} \usepackage{slides} \renewcommand\Rclass[1]{{\texttt{#1}\index{#1 (class)}}} % A Beamer Quickstart: % http://www.math.umbc.edu/~rouben/beamer/ \newcommand\DefaultBackground{\setbeamertemplate{background canvas}[vertical shading][bottom=black!10,top=black!10]\setbeamertemplate{background canvas}[vertical shading][bottom=blue!40,top=blue!15]} \DefaultBackground \setbeamercolor{block body example}{bg=white} \definecolor{YESgreen}{RGB}{0, 160, 80} \newcommand\YES{\textcolor{YESgreen}{\textbf{YES}}} \newcommand\PartiallySupported{\textcolor{YESgreen}{\textbf{partially supported}}} \definecolor{NOgray}{RGB}{144, 144, 144} \newcommand\NO{\textcolor{NOgray}{\textbf{NO}}} %\AtBeginSection[] %{ % \setbeamertemplate{background canvas}[vertical shading][bottom=black!47,top=black!47] % \begin{frame}{} % \tableofcontents[currentsection,currentsubsection] % \end{frame} % \DefaultBackground %} %\AtBeginSubsection[] %{ % \setbeamertemplate{background canvas}[vertical shading][bottom=black!47,top=black!47] % \begin{frame}{} % \tableofcontents[currentsection,currentsubsection] % \end{frame} % \DefaultBackground %} \title{A quick introduction to GRanges and GRangesList objects} \author{Herv\'e Pag\`es\\ \href{mailto:hpages@fredhutch.org}{hpages@fredhutch.org}\\ \---\\ Michael Lawrence\\ \href{mailto:lawrence.michael@gene.com}{lawrence.michael@gene.com}} %\institute[FHCRC]{Fred Hutchinson Cancer Research Center\\ % Seattle, WA} \date{July 2015} \begin{document} <>= options(width=84) plotRanges <- function(x, xlim = x, main = deparse(substitute(x)), col = "black", sep = 0.5, ...) { height <- 1 if (is(xlim, "Ranges")) xlim <- c(min(start(xlim)), max(end(xlim))) bins <- disjointBins(IRanges(start(x), end(x) + 1)) plot.new() par(mai=c(0.5, 0.2, 1.2, 0.2)) plot.window(xlim, c(0, max(bins)*(height + sep))) ybottom <- bins * (sep + height) - height rect(start(x)-0.5, ybottom, end(x)+0.5, ybottom + height, col = col, ...) title(main, cex.main=2.8, font.main=1) axis(1) } @ \maketitle \frame{\tableofcontents} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRanges} objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{The \Rclass{GRanges} class is a container for...} ... storing a set of {\em genomic ranges} (a.k.a. {\em genomic regions} or {\em genomic intervals}). \begin{block}{} \begin{itemize} \item Each genomic range is described by a chromosome name, a {\em start}, an {\em end}, and a strand. \item {\em start} and {\em end} are both {\bf 1-based} positions relative to the 5' end of the plus strand of the chromosome, even when the range is on the minus strand. \item {\em start} and {\em end} are both considered to be included in the interval (except when the range is empty). \item The {\em width} of the range is the number of genomic positions included in it. So {\em width} = {\em end} - {\em start} + 1. \item {\em end} is always >= {\em start}, except for empty ranges (a.k.a. zero-width ranges) where {\em end} = {\em start} - 1. \end{itemize} Note that the {\em start} is always the leftmost position and the {\em end} the rightmost, even when the range is on the minus strand. Gotcha: A TSS is at the {\em end} of the range associated with a transcript located on the minus strand. \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{The \Rcode{GRanges()} constructor} \begin{frame}[fragile] \frametitle{The \Rcode{GRanges()} constructor} \begin{exampleblock}{} {\small <>= library(GenomicRanges) gr1 <- GRanges(seqnames=Rle(c("ch1", "chMT"), c(2, 4)), ranges=IRanges(16:21, 20), strand=rep(c("+", "-", "*"), 2)) gr1 @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{\Rclass{GRanges} accessors} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{length()}, \Rcode{seqnames()}, \Rcode{ranges()}} \begin{exampleblock}{} {\small <>= length(gr1) seqnames(gr1) ranges(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{start()}, \Rcode{end()}, \Rcode{width()}, \Rcode{strand()}} \begin{exampleblock}{} {\small <>= start(gr1) end(gr1) width(gr1) strand(gr1) strand(gr1) <- c("-", "-", "+") strand(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{names()}} \begin{exampleblock}{} {\small <>= names(gr1) <- LETTERS[1:6] gr1 names(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{mcols()}} Like with most \Bioconductor{} vector-like objects, {\em metadata columns} can be added to a \Rclass{GRanges} object: \begin{exampleblock}{} {\small <>= mcols(gr1) <- DataFrame(score=11:16, GC=seq(1, 0, length=6)) gr1 mcols(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{seqinfo()}, \Rcode{seqlevels()}, \Rcode{seqlengths()}} \begin{exampleblock}{} <>= seqinfo(gr1) seqlevels(gr1) seqlengths(gr1) seqlengths(gr1) <- c(50000, 800) seqlengths(gr1) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Vector operations on \Rclass{GRanges} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects} \begin{block}{} What we call {\em vector operations} are operations that work on any ordinary vector: \begin{itemize} \item \Rcode{length()}, \Rcode{names()} \item Single-bracket subsetting: \Rcode{[} \item Combining: \Rcode{c()} \item \Rcode{split()}, \Rcode{relist()} \item Comparing: \Rcode{==}, \Rcode{!=}, \Rcode{match()}, \Rcode{\%in\%}, \Rcode{duplicated()}, \Rcode{unique()} \item Ordering: \Rcode{<=}, \Rcode{>=}, \Rcode{<}, \Rcode{>}, \Rcode{order()}, \Rcode{sort()}, \Rcode{rank()} \end{itemize} \Rclass{GRanges} objects support all these {\em vector operations} $==>$ They're considered {\em vector-like} objects. \end{block} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Single-bracket subsetting} \begin{exampleblock}{} {\small <>= gr1[c("F", "A")] gr1[strand(gr1) == "+"] @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Single-bracket subsetting} \begin{exampleblock}{} {\small <>= gr1 <- gr1[-5] gr1 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Combining} \begin{exampleblock}{} {\small <>= gr2 <- GRanges(seqnames="ch2", ranges=IRanges(start=c(2:1,2), width=6), score=15:13, GC=seq(0, 0.4, length=3)) gr12 <- c(gr1, gr2) gr12 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Comparing} \begin{exampleblock}{} {\small <>= gr12[length(gr12)] == gr12 duplicated(gr12) unique(gr12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Ordering} \begin{exampleblock}{} {\small <>= sort(gr12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Splitting a \Rclass{GRanges} object} \begin{exampleblock}{} {\small <>= split(gr12, seqnames(gr12)) @ } \end{exampleblock} \end{frame} \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 1} \setbeamertemplate{enumerate items}{\alph{enumi}.} \begin{enumerate} \item Load the \Rpackage{GenomicRanges} package. \item Open the man page for the \Rclass{GRanges} class and run the examples in it. \item Extract from \Rclass{GRanges} object \Rcode{gr} the elements (i.e. ranges) with a score between 4 and 8. \item Split \Rcode{gr} by strand. \end{enumerate} \end{frame} \DefaultBackground %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Range-based operations on \Rclass{GRanges} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{An overview of {\em range-based} operations} \begin{columns}[t] \begin{column}{0.44\textwidth} \begin{block}{} {\bf Intra range transformations} \Rcode{shift()}, \Rcode{narrow()}, \Rcode{resize()}, \Rcode{flank()} \end{block} \begin{block}{} {\bf Inter range transformations} \Rcode{range()}, \Rcode{reduce()}, \Rcode{gaps()}, \Rcode{disjoin()} \end{block} \begin{block}{} {\bf Range-based set operations} \Rcode{union()}, \Rcode{intersect()}, \Rcode{setdiff()}, \Rcode{punion()}, \Rcode{pintersect()}, \Rcode{psetdiff()}, \Rcode{pgap()} \end{block} \end{column} \begin{column}{0.44\textwidth} \begin{block}{} {\bf Coverage and slicing} \Rcode{coverage()}, \Rcode{slice()} \end{block} \begin{block}{} {\bf Finding/counting overlapping ranges} \Rcode{findOverlaps()}, \Rcode{countOverlaps()} \end{block} \begin{block}{} {\bf Finding the nearest range neighbor} \Rcode{nearest()}, \Rcode{precede()}, \Rcode{follow()} \end{block} \begin{block}{} and more... \end{block} \end{column} \end{columns} \end{frame} \begin{frame}[fragile] \frametitle{Examples of some common {\em range-based} operations} \begin{exampleblock}{} <>= library(IRanges) ir0 <- IRanges(start=c(7, 9, 12, 14, 22:24), end=c(15, 11, 12, 18, 26, 27, 28)) png("ranges-ir0-plot.png", width=800, height=170) plotRanges(ir0, xlim=c(5, 35), main="ir0", col="blue") dev.off() @ <>= png("ranges-shift-ir0-plot.png", width=800, height=170) plotRanges(shift(ir0, 5), xlim=c(5, 35), main="shift(ir0, 5)", col="blue") dev.off() @ <>= png("ranges-reduce-ir0-plot.png", width=800, height=170) plotRanges(reduce(ir0), xlim=c(5, 35), main="reduce(ir0)", col="blue") dev.off() @ <>= png("ranges-disjoin-ir0-plot.png", width=800, height=170) plotRanges(disjoin(ir0), xlim=c(5, 35), main="disjoin(ir0)", col="blue") dev.off() @ \begin{figure} \centering \includegraphics[width=0.8\textwidth,height=!]{ranges-ir0-plot}\\ \includegraphics[width=0.8\textwidth,height=!]{ranges-shift-ir0-plot}\\ \includegraphics[width=0.8\textwidth,height=!]{ranges-reduce-ir0-plot}\\ \includegraphics[width=0.8\textwidth,height=!]{ranges-disjoin-ir0-plot} %\caption{Range-based operations} \end{figure} \end{exampleblock} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects} \begin{exampleblock}{} {\small <>= gr2 shift(gr2, 50) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr1 resize(gr1, 12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr1 flank(gr1, 3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr3 <- shift(gr1, c(35000, rep(0, 3), 100)) width(gr3)[c(3,5)] <- 117 gr3 range(gr3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr3 reduce(gr3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\scriptsize <>= gr3 gaps(gr3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\scriptsize <>= gr3 disjoin(gr3) @ } \end{exampleblock} \end{frame} \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 2} \setbeamertemplate{enumerate items}{\alph{enumi}.} Using \Rclass{GRanges} object \Rcode{gr} created at Exercise 1: \begin{enumerate} \item Shift the ranges in \Rcode{gr} by 1000 positions to the right. \item What method is called when doing \Rcode{shift()} on a \Rclass{GRanges} object? Find the man page for this method. \end{enumerate} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Coverage} \begin{exampleblock}{} {\small <>= cvg12 <- coverage(gr12) cvg12 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Coverage (continued)} \begin{exampleblock}{} {\small <>= mean(cvg12) max(cvg12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Slicing the coverage} \begin{exampleblock}{} {\small <>= sl12 <- slice(cvg12, lower=1) sl12 elementNROWS(sl12) sl12$chMT mean(sl12$chMT) max(sl12$chMT) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{findOverlaps()} \begin{block}{} Load aligned reads from a BAM file: \end{block} \begin{exampleblock}{} {\small <>= library(pasillaBamSubset) untreated1_chr4() library(GenomicAlignments) reads <- readGAlignments(untreated1_chr4()) @ } \end{exampleblock} \begin{block}{} and store them in a \Rclass{GRanges} object: \end{block} \begin{exampleblock}{} {\small <>= reads <- as(reads, "GRanges") reads[1:4] @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{findOverlaps() (continued)} \begin{block}{} Load the gene ranges from a {\em TxDb} package: \end{block} \begin{exampleblock}{} {\small <>= library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) txdb <- TxDb.Dmelanogaster.UCSC.dm3.ensGene dm3_genes <- genes(txdb) @ } \end{exampleblock} \begin{block}{} and find the overlaps between the reads and the genes: \end{block} \begin{exampleblock}{} {\small <>= hits <- findOverlaps(reads, dm3_genes) head(hits) @ } \end{exampleblock} \end{frame} \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 3} \setbeamertemplate{enumerate items}{\alph{enumi}.} \begin{enumerate} \item Recreate \Rclass{GRanges} objects \Rcode{reads} and \Rcode{dm3\_genes} from previous slides. \item What method is called when calling \Rcode{findOverlaps()} on them? Open the man page for this method. \item Find the overlaps between the 2 objects but this time the strand should be ignored. \end{enumerate} \end{frame} \DefaultBackground \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 4} \setbeamertemplate{enumerate items}{\alph{enumi}.} In this exercise we want to get the exon sequences for the dm3 genome. \begin{enumerate} \item Extract the exon ranges from \Rcode{txdb}. \item Load the \Rpackage{BSgenome.Dmelanogaster.UCSC.dm3} package. \item Use \Rcode{getSeq()} to extract the exon sequences from the \Rcode{BSgenome} object in \Rpackage{BSgenome.Dmelanogaster.UCSC.dm3}. \end{enumerate} \end{frame} \DefaultBackground %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRangesList} objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{The \Rclass{GRangesList} class is a container for...} storing a list of {\em compatible} \Rclass{GRanges} objects. \begin{block}{} {\em compatible} means: \begin{itemize} \item they are relative to the same genome, \item AND they have the same metadata columns (accessible with the \Rcode{mcols()} accessor). \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{The \Rcode{GRangesList()} constructor} \begin{frame}[fragile] \frametitle{The \Rcode{GRangesList()} constructor} \begin{exampleblock}{} {\small <>= grl <- GRangesList(gr3, gr2) grl @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{\Rclass{GRangesList} accessors} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors} \begin{exampleblock}{} <>= length(grl) @ \end{exampleblock} \begin{columns}[t] \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= seqnames(grl) @ } \end{exampleblock} \end{column} \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= strand(grl) @ } \end{exampleblock} \end{column} \end{columns} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{columns}[t] \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= ranges(grl) @ } \end{exampleblock} \end{column} \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= start(grl) end(grl) width(grl) @ } \end{exampleblock} \end{column} \end{columns} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{exampleblock}{} {\small <>= names(grl) <- c("TX1", "TX2") grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{exampleblock}{} {\scriptsize <>= mcols(grl)$geneid <- c("GENE1", "GENE2") mcols(grl) grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{exampleblock}{} <>= seqinfo(grl) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Vector operations on \Rclass{GRangesList} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRangesList} objects} \begin{block}{} Only the following {\em vector operations} are supported on \Rclass{GRangesList} objects: \begin{itemize} \item \Rcode{length()}, \Rcode{names()} \item Single-bracket subsetting: \Rcode{[} \item Combining: \Rcode{c()} \end{itemize} \end{block} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRangesList} objects} \begin{exampleblock}{} {\small <>= grl[c("TX2", "TX1")] @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRangesList} objects (continued)} \begin{exampleblock}{} {\scriptsize <>= c(grl, GRangesList(gr3)) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{List operations on \Rclass{GRangesList} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{List operations on \Rclass{GRangesList} objects} \begin{block}{} What we call {\em list operations} are operations that work on an ordinary list: \begin{itemize} \item Double-bracket subsetting: \Rcode{[[} \item \Rcode{elementNROWS()}, \Rcode{unlist()} \item \Rcode{lapply()}, \Rcode{sapply()}, \Rcode{endoapply()} \item \Rcode{mendoapply()} (not covered in this presentation) \end{itemize} \Rclass{GRangesList} objects support all these {\em list operations} $==>$ They're considered {\em list-like} objects. \end{block} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{elementNROWS() and unlist()} \begin{exampleblock}{} {\scriptsize <>= grl[[2]] elementNROWS(grl) unlisted <- unlist(grl, use.names=FALSE) # same as c(grl[[1]], grl[[2]]) unlisted @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{relist()} \begin{exampleblock}{} {\small <>= grl100 <- relist(shift(unlisted, 100), grl) grl100 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{endoapply()} \begin{exampleblock}{} {\scriptsize <>= grl100b <- endoapply(grl, shift, 100) grl100b mcols(grl100) mcols(grl100b) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Range-based operations on \Rclass{GRangesList} objects} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= shift(grl, 100) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{shift(grl, 100)} is equivalent to \Rcode{endoapply(grl, shift, 100)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= flank(grl, 10) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{flank(grl, 10)} is equivalent to \Rcode{endoapply(grl, flank, 10)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= range(grl) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{range(grl)} is equivalent to \Rcode{endoapply(grl, range)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= reduce(grl) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{reduce(grl)} is equivalent to \Rcode{endoapply(grl, reduce)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} <>= grl2 <- grl grl2[[1]] <- grl2[[1]][3]; grl2[[2]] <- grl2[[2]][1] grl3 <- unname(grl2) grl3[[1]] <- narrow(unname(grl3[[1]]), start=5, end=-5) @ \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl2 grl3 @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= setdiff(grl2, grl3) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{setdiff(grl2, grl)} is equivalent to \Rcode{mendoapply(setdiff, grl2, grl)} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Other resources} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Other resources} \begin{itemize} \item Great slides from Michael on ranges sequences and alignments: \url{http://bioconductor.org/help/course-materials/2014/CSAMA2014/2_Tuesday/lectures/Ranges_Sequences_and_Alignments-Lawrence.pdf} \item Vignettes in the \Rpackage{GenomicRanges} package (\Rcode{browseVignettes("GenomicRanges")}). \item \Rclass{GRanges} and \Rclass{GRangesList} man pages in the \Rpackage{GenomicRanges} package. \item Vignettes and \Rclass{GAlignments} man page in the \Rpackage{GenomicAlignments} package. \item \Bioconductor{} support site: \url{http://support.bioconductor.org/} \item The {\em genomic ranges} paper: Michael Lawrence, Wolfgang Huber, Herv\'e Pag\`es, Patrick Aboyoun, Marc Carlson, Robert Gentleman, Martin T. Morgan, Vincent J. Carey. Software for Computing and Annotating Genomic Ranges. {\em PLOS Computational Biology}, 4(3), 2013. \end{itemize} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document} GenomicRanges/inst/doc/GRanges_and_GRangesList_slides.pdf0000644000175400017540000075207413175727455024552 0ustar00biocbuildbiocbuild%PDF-1.5 % 10 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 11 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 13 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 14 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 88 0 obj << /Length 932 /Filter /FlateDecode >> stream xWn0+xf(mR)$=⤵ՠw)EAj8ܝ%؊ ?b" U3k{3-k/* 1" m/Lܖ$سQbق2r`+xJ!Am5S0%y%`ҵ.\Gse Q]' )OZȞc4;\['e%ڄUQ w1AKn I-DJj BX rmr#&Q[{ݐ$8Ht_g=ueiw>W E;+I=/yl[Z$ohr돤8 }v " FoO~&\y/~p[FD/lK 8B% R夝F)ԯ.O3!c*![-rsTeU"")Hq%h~w4QV)56Mq2^ö@ ^ÃJǺ6TwZHr )JW%(擼c‘+Id!8O#8JJV_ b O=a/ exuL琼,p ^]8%bbٺo^LgZf*s/ חl3UfKTvC:ކv1 r\ո^,k2"U}7k0~N\M?I5Rr$= 5iT(MMyj}O <{Gb0#VA =[3|]twќ1kҌv\F+ϥ WxXx}=݄1% endstream endobj 132 0 obj << /Length 1073 /Filter /FlateDecode >> stream xWKo7Whq-^ԍbZnѿo%Zq {kA?'ˁ)oqʂ9!p I$#Ts) 3NuL0VJ e]"yȪHQeW/ YT gWUO %rdjMRGmZKJAdb^ӹl@U4LUWenyΐIR&ҧxO.-$鉷QSuLO#DJ\rH`Lo=i 4_^KA kc.qo[v#z7Aƶ}Ct*pm޼_ʳfYѨx;aL@abu͒+_mNW@*b1p/ [KTߑ7O*2*?r4h=Y4w4&k&D2~;m%{!mkfUD_TV>YZ} Wrӑ5!@3r"!r0)qg.r5x⹷" %3;|8W#("TmLAFR]S j&> stream xXKoFWV 7$w @&As(ط-HwfߤhY&*";;;oKZ\xqFg p/~ݜ#)U1z=Ji[6uAm.FH]g#(cFeo MxeԔSk! d mq^*^ʊS Iw## / /1Xg~iQp0rYٴi;²(_d=ΦkK-ˈCcZS 0%t̠5 !I`8"0 Jq9oTԺQ@-[#C I&i >̚XY HHWзeޤ+DI i \5qn2v+sI69 mws$TP:Fk(Z$C%j*`\*]qJJV"7`MPq$t3Cx4q-d=Z={#QbOXD>Is,QPlhF 0Ls~G@3;=ὁ@8 㽉 snn! ;[ʾ2/>%m0Z\HrE3ưqAO h4jfCBk$@W$pEe żcr1eE;Ή!'(XN { 5\Wpp>b͵_MK!d3ISuDKϽ:Kz%.! 9 &LҕR5jd$LKYsЇMTvU-VZ!A᳘l.Lƾik-*kyހ= UM,dFF6H" WKkj؀ ͐և7[`&(؎Q35T4$! &\&lVx99 @El _f۠f D6$oQlT,(+ڹY8Laxt뜵sXhndf OڹyOL@5.!:Ol a;r}`"Vi0BU vĂ\gʋL󔙎w&a bq#M6AYf=lAȤ) Fi+- Y doftVut֍cìei-%;[tpm4swjHet7ޥlq5wa,Y'Ld 0@DC܂8έBIIzUmQ Y}pvsCcmxzP4yfm[wvr[僧Rꨰ+78{BRADzMH{cOsFAƯyZa9[8֘zBqvȕw֧K #za4H;gcg6 !zn?8?T;3G* XGZ"t\3LwY8Jᇳ4DCRl%+;#-''+SLB퇐6# Ӑ k*GSذ>eE>Id~YkEFB [CrB.;/4) R~Wݛ1[u\b6&ūK"oݱu\a|WrG5 O  ,{BX}yYs*Ehm!g;۽ZלmCks(j?xfVȦ*:CRiJsO,̧5q9 t&e endstream endobj 12 0 obj << /Type /ObjStm /N 100 /First 831 /Length 2054 /Filter /FlateDecode >> stream xZ]S}ׯCZ}SkupR]6ayYP4.iu}Νn6x-!`E(>ӟ2̤“8י87! K>b"YM!ّex:>4jd3%\C)39K٠("aXyFyGZ1;&`22:0!1h( E)2nD 2{oq=\LbM0i28BL Z)1\Ύ "kpTo ؁ȀugO@C}>.NBNP]C pH>o÷UUz?Zyꠙ hW;k6OOirwo忴L&bͿm*֥?[A݇vވ=54fўlgߤx )o o(Z*g+CNڱɭry.7Y;y.Z#š0Y̩a&msڎ0g| <8,d=6/Ú=ը xy2m9PYGr:!"EԥRRR8 E(EA%TPRAI%TPRAI%Z(:ZcQ|_FX>uz4vTb0aM^l`Cjn~,`_#5M=ae5phO$Dd44pAY"㝲rtDlE[_ ZEnIJK"^~Pl#XXKsI0&InC,>H2J;E\`I$*mn@+ EtId(`I$6rZm*b5ZUWX 0lkCgw1D,CA%^d]&glVaEĻ[?ĐM//QӪiqldx:;ެǪ\"m(fwߚML#&^fY"8I*' j] :oyp|gw?ۓ~rY,I(H$u`e}17V]L'gM{i;kդgqΏ7D+ .ϏT5"R"D@}gTq:웾JHi8! aԏo@c H>[ &sWJDZQ5NyYîvm:h 0[]ޏQ 9C^7 %E,8ox9abu.1b?גnu\dԲjx]dT_xOaXS4yf:U^y”^K% ^ƒsf`f7g*Z,8{yJٮr/EoܐYjΤuT=L=/xJNl}F{!q~mgo`>sD-kg\Er5j.ܖ-_s[|mW<_|/TPB &LD<(ty 90Pr`CɁ[u endstream endobj 198 0 obj << /Length 1316 /Filter /FlateDecode >> stream xWKo7W=ɉwǒKE#rdzԒ>3K6m TEr8͓l8;N7sFrRփ=/fOK6s%4-kICTTN3UVܱA?rV -qzj.TZ)&Mppa.\XUdkU+eK@FL"RC2c”~SD&rhb)TPU}KPMjA% h]Z0eRG}$PS"liOq/#!}@f iTҒêksmu`!YI5\K+oD$Qp"pZ/^`~VLē t?3: FWG!Ix%qI K$Ya5RJbbytLDIQZ+seM"Rbϕ$ֽKlatɭ[3km1Mg}^ݾY@ĊޤǃLkc_}-]*S&D$hpo]5t$i2WKX FC)`аt|cq@K1| PP䂍gPWLj bkv52Up$hv>j>n * (լWȿ=f>p |$|EiUrke{p<  4b0Xz ruY8,gYŻ`]3ubT}vT@† -O0 94L$&g mDh k%Qo0:A) a2 E_"ЂX o͏I8,{wW%[j%>**$Z vLȌ) Ҏ F~}ҫN/|x[VT6MOe7(qMcN)FirK -!zqڞx,[_+_/yhO&hE8<22S_3s D8CC#bcrW&W= a>"H;08 wPP=b'0)5T[|8qMޗ,iav;/=zZiXxfKrݾ?s_p_p endstream endobj 223 0 obj << /Length 1238 /Filter /FlateDecode >> stream xWKo7W(f& MР=zqspײBߙK֍ m Tp἗ Fx?HAv5ynw#}lݟUVloĐt6iCH qlu16b2/F#Q`gAr"APB!4a!ũ)@~&:BG}Yit1BDQe\X5Rt 8"+`fYtųڥzS]F'@cM@u V"%M#ᱴnĽʄ[g#$IɥEGwבu!tQ)Ϥ޴Й(s3ϯlZߟ%!B^͌<$mN `-|:l#|E2m"SYđ)-rz@UʴsBA˘by_ñElee zoA2@ J?3tt|lOYR֧YxoSJ)21RUKֆ'R Sg_<-Ns2R\5&#XF̯s|N>?zk %BmywwtK \aKqKoXG"LF}7"5ݬ/Wd!7eo=7lkb7FK2ū`5]zVg\L78jT2ޙ(  цwB\u%fyV.U钣ߞ̬e9#9WR8#QɃzV%k9u@.ujl:U( V@53*? F5MKv?"_ܦJ[5*~7鐟:ò)&)0j_I}2@-R~3|6~柋e.չu>`lG35 Ǣ;v\~:d+u8V m/;{q~Y.PöxM$Va]WIv;^*Rs_^۷I7H-<"/ (OgS{>F!b$.tCAU#칰9 rW#:-` tuoIS:$l endstream endobj 249 0 obj << /Length 1180 /Filter /FlateDecode >> stream xWKo7W=IM>46^l 9kI ٰ3ڱc% Xqqf8q8[1`&0h&[`L޼HxO\ivņɘ߹6P/-v-p&#l0;n]1ǥq-4\(&CXSv&Ǥi%Hio9{6huQ`Y2ay-zDTIVL>Ӌ \))Z[$1B[]"le*RH]=-қ$nQ>^@#iWG}ZG_x^%4ׇo(s dNɯ2Z_IPBb`҆0x̖Qܛ"e'~:qߛt"cđւtz &RbjrCNhe2n3BIh-)4Gwًd7P:vNվ2[X5`i]F0Ж|v롾$[pw rۆ,\BiRa^цxrLON'%$ђlAr6u5Ux!q É*x5F*c1{ۿ}$"$FXǖ72@ѰB-K-LEq>!_{;n'bEϾS梅詄}F=;ޢSPJ><^ VUI.Cỹ$ņjz]\F֡tDLL~?5MsI i bMV1Tcd jK/ؼM\" kƽg&ģ;wY,΄])}G^PZ]s#y$N$AӯlD䡒exKs;^$f֩ endstream endobj 274 0 obj << /Length 1246 /Filter /FlateDecode >> stream xW[O#7~ϯxJԝYǦiY`U@$P = Pm<|n>v81> x_ zⷞ%;\N6X5# [XtMu.hKfKJ Sv9`[V`w}a$bsW\TJ)&&8L3v'$i%K{uB_?_{(2Geʄ-j+'\`b &]_EΞR6f8ՖRp/6V$aLQl Bn#a[r̕Ey"$߂? Zo! b.M o:XUe1AW yDz[mMsi |NCO}Ļ(4mx\L<,}g~O2'^丷8zI7R:(ek-.Aϭ'DRx.qo &YgjOdJz$4Oԙ"Jמ'+i^g-% 6Lui;?wʔ܉p49 [:y_g , 25d=VB:?d_Zkڐk!׃v6LEWTэwAgq'sGip^}"040P^E endstream endobj 174 0 obj << /Type /ObjStm /N 100 /First 909 /Length 1609 /Filter /FlateDecode >> stream xZMo6W̱HpQ6 b>lE& ֛6}#.Ѣ@HPG!G>F!&,k{(^)I 36pjE >7>iC wFCy7"ëhΙ0s!J*Wb` qbQ: . %̃j>K )B,PȬ]BIQ,I|re@D$h8JR6DR4@E0B`XxE(-bvcʔ4 YPFj#R!Af*^=#eF$sD' B9e}R5\t .4P"*qg-)hZr $Dk8bފt"PEtq!(&M= ެS"(&-yƼ46^A9iA&0 r "Z`˂['*Z t։תc-SdTP|Ȩ'0ZNġꕕ*&Kȃ慌{ ^电x-fx O\N~j6˦\.7g+֝w?wgm,/t%umE%r֡k%y KGGԝPp}hՋj ?ҝ; C!;"L""&Z00<=҆3\#~!r`ݵX;"H"Dr0&\ڬ;&D8>7x;57{p6N_;6~"ݣ{x˛;Ժ|1r||ۈ%`Mxky:H'=};6 '=HVW2Xd,uׯ֛7%NjvY?><.K}CW۾WvѪPî[Wv=yэ3px,]7닓%;] }xl0v^pUqbyݟ_W{wֶeybu[@Fa.!D_> H'Cd8:Xob65bxUëg}_ xzұ]Z\3|6wPG.ӵV!x22x?{ؓJ m8"b+(rv>")cG9xdBeȷR"p;)DnD{o撱q[ILEŶg> stream xXKs7 W(OM]4qi=AY˲R=jI/RҺMf- A䚳 ̀7#gO/{X HVK:2a%Rj Sp=1a q;61{N%ҍ^5?ԯlHyeUP5vrEL>. ΑR6d֍S^󾀺ڃHc晢j_#Zrqki<RlV2&%?ozaq¼![]Oo+k>92˯-$$/Qp!𰘤9-ʶI1˜xTݟ: DJGG!Yx!p s")."AHJ NjbV&Sm&!yRfZd82H6[(Jˮ3N;ۢpLͽ䌪[,v(0[mxyHX a|yyZwۆn PiT),MɓNY&%{t28w. %7ۍ@AdU#>c)`Bg@;/K9| i) I.$Ic5;d7bxo O VDDQmyT@Edd< ;O79ځ6oP IbSE%um,Des=dP55k;κW;<O0E E1v} Nt,Gv Iw58)ѢwU1EMI_+䦆vtPhۘ3v(Xݘy"D8\ DZlxF1ֺPK?DlA{FKILl^EuEɻYdL)pɏ8@@+̪t~7' }yZ%b2:L,@MB%]yTK4'9~^E4jMZ.)ͪT0Z(5)YA)k}$lxQ02@JJ>]lpa2^uˇssi TGh([ʩku]gl ɣrv${cank}Wf9'|1>0&hw 7*Omovu_KH|S}{#c:FUa}աnWqc܎q 5ćW%5P0RmNQcM`I} -,hds&jo5ljGG>C] (ԮgR=ow+;7|*<5m0,D#O9(F~"'Գ*xUS%oOה=5c ^[pU޹yqC]&~g yh endstream endobj 325 0 obj << /Length 1234 /Filter /FlateDecode >> stream xWYo7~ׯ $Y#Ԁmyp7BG% bHJ\@.-k"rؒ?T D&mxaz8(JIq!%9's4K齊ߠ_Q?@3RDGR ʜpCj.Px%jaYN4JQ6u@R [e sr1D8e(λEU"$l?^82GHBZs|!벒Oo u%+*W?)/v&h`q1Ix(L>Y_.}d$Hp$1=3Isy.bgTF-`☒:Sk&iHdNdg py2H6{(ͤPZr.վDi[km)m@dC_.~߂g J͏c_yNIn”܆xˤON'%$nPuO#\E0iL/>6p#m5 җSRK \3Eְ#oƯ&||  ~vKW@#(Ҷy;YWnx GRۣ70`7"K>mPrXbvrJurDjq{?^Q RHvUN7=1p3ݰrCϫ~[ a7CpA=`YO2$ޏ(5Ux4O @'39}:i}W[h7]ΡmvE* 2Y 0GQݗu ׬6R>9Htq7CvnuCG-jߠwqq7+$IM~0`BJt]k܅/z<7_vEj;fcTFY€k/^R}:iV3DI Ә hC̽~Ϊd}p]pƀN'[E rLFZ%$#~LAs5q^ ړ*RW ,P ڌ_ ~WB﬽Za#i9Aeub endstream endobj 327 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 328 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 351 0 obj << /Length 1457 /Filter /FlateDecode >> stream xWKo#7 WEm=b>t/EhcoƏ< KR#x2'l̈")~$EQ2wD}#-X|VӝݽfwKU].O:uBKI\47DWl7Q $ew Ep>BBK6)1;bl%"7]"XI C&t"E$hnᭁIi(%ڂ^gZCۺP}.,98Ix ޚf %~JGPG;ADH>~\I"steZ!h_e#0u2Q!8^CPO1KeIK yRBެ4x[  "N&iAGH動Y^k_IAYx ȜHZ27R8tW/:!"UH02k,X04U"QI=(;zxGA\xI{R0)w|)(}W DLOr;r\sc?J9KJGCIʒAX&%{t28)o yJ.8YGL@T*s6cy.2fxn6mBpti#u?MBJBKv ÔJÎGq5|ZB&Np *}awϔmsxkO?M]6eՂ׹_J8n,%@lP jĢE/:<3)ZP KN&pF$?g5N>! -M&p)W`qցuq2 ԒiNٵƓGFCj]ܨuH83$@(IEd7g#GHQDhKt/ەz(,|)_Hިg|KZ{b) endstream endobj 355 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 356 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 357 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 358 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 381 0 obj << /Length 1333 /Filter /FlateDecode >> stream xWYo7~ׯ B % @AYKRF^;3q0dk EJx&=ZrUN__ :ד@|A,-h䁥^1lM)pp~}); )뜐 \@Lp]!A*s)Ng.bѶPm&#yV^ # {:-VdJ13Crewbzw(˅ԚQmZsBψbi 7-U6T[(AT^ِ?e++lOg% oO)Oލ@&WjUCG| '6ͷRi57p ~=!J\))k ;=goWv,bj5øV` g𷘯qUgύ"+8Nsx.7 3дD=25kcLuvp;lD!_6у5Ph@r`~ʿ~ok0S)ý(.m-&p-u`Q;kX-8>pi8 4u6ƘpNJսsT@/iJ<2XnTJSv178xV >o&Ua OCR@.<%ee%SB1RXk](J:xiP R /A֏tOJDX[CXO&"jk`m1q3tt|M 10U]y6>`[ QS/`ʾH`Fyz-}w ٩9̞$LlMFx?^n2dl*v&~Xv9n%o7<}/0 endstream endobj 278 0 obj << /Type /ObjStm /N 100 /First 915 /Length 1741 /Filter /FlateDecode >> stream xZMoFW̱; vm>5|Pl6qH,r,hYeᒻo~W./ԓG@/rzۅM!fr8z&NxbK &9 -BΎRH)wu"J/umRQ. 2$̖rtbz[doSM A$ dBBd{(p1"j$|aSSs h&G\'(5^Zd\Y [{}> -'{`$X#D7Py%ZSиbdu^B^sQc2Y$5˄rݨbJY9QfD7V_P@ ΥP쪝9mKͣ|u-`ޚIVͳlE'A.IbMEGC55ݓٟ/gܚiwHLb HQyo6z݃},1 Xj4<ݠ.5YKljsr}wãlՒnTbr@6 RJ6,'-84uxmOGOjw+:mU;_]ahI̯˳;t~n/f{wԍ:vr6Iw0[bэ&/<8[֩e^mP&Y+A\o(^Qx;o/cWsYpAC1nQ2p/$-ϱdȤQ2X29(e܃E:/U$WvI djB$z$${I6uθ'-,Y,xg,F&0u"1sC3 ILe(߂@a=(C~Sdrq}"J\[)_6jڬ|U[֩U> stream xWKoFWBCf0$u=z |phVjJȥ?3%MI$m Tٙo͒qvj$`,^f1rt0i EL\l TR0Ui0+6ڣPogf++i@wJ1 jCSv -ҍAG__C5ǻ*Ɍ [jg',CV%gvɓn,JdpBu;I>|24Q~TYK1÷4KnzҐhg&}   6 LM䚽/K_L(˱tz\*q)m1].\lpUrv}+ [o?&>tLCXkzQnz4.•{#b6 A m) nۤ;&}MɁ4Na 0Ҹп-{r-t9"`qìѬ $i!\P@E_3 N:] 8dLXVI8*d\X p[WDĢ0rXf\}xX ~?b?FVGg,6N X_:˨`:*.!Ay(Zt6HtF#XOR{jq'[DoABJߡ$픲1/ v.'^o_ф[EtGK1D1E$"Ms!! ^DvA)'\+]הf>Sxh э_[B:s?/wOKHmy ]bkuw9z-Rl5S\#y1[#qPc[ڶ ,|tRgvHPB[lF endstream endobj 432 0 obj << /Length 1456 /Filter /FlateDecode >> stream xWKo7W=%@6AYˏbɆ/>I7Or9;erKYf[O_ un_;aX3Ұ)6IM RNyT]d[F` * a(v\'{sJ1 l Sc[PJ,e:غ8P;6d<^dPN9"*T &[9qȊN);+s4ǀ2Eu2:"ND(.uS,RlVo d!MJ ?>d yJx"=\t-ϰr8UN/z(,$0>C<ȜW.xې嶐FR^ѓ?yQeR'K'xqI[(dq7^ګ%jG\RӇU{_MU/5BIB nf8Ě揉ttj1}JfiJLq𷘯pWdr+uZe5E9GdVljh p136`~-_hqiz_OYmEoG<!p1qZ"`xYavh֊Zhn(ÏMc Xܣ0&|8L@d>i؝F*J az{E'7(7p8fyDHBTAa.lJusL(lQ/g*OV9>K~-4rYkf5PL JbI7`Λ :@Jvv^M)˲a!}y>ޚxTol8":`c@bHPv[P/nE Sÿ0>@XhƓZEu.ʡiapw A<\S*!4r } 01мTluաжmppxJE6Fy=Ž!Aޜ,v k:ٟ5NΧip81z~IhH(3P endstream endobj 458 0 obj << /Length 1442 /Filter /FlateDecode >> stream xWKSG+Jy?(L9\H Iփ%?>e2P؉V3=M3\Jwh]0h) tT󝓍z[1E,HWtg[:2Kas!* XYE4[[qq2A8LcB!9!;'h9)MdGz|YQ9gQs{JA+@2!LW^1%e& tggfY%9$Њj* ZIMDT<v8hV$H|x#b89PiDA_tA0vWҘx,zl -OqPsOuQp РL+?Y7ģ{t?1'GHHZS%v89\(`\"wj!Hy\'J$fBE,aT=Q5Ҹ^$Iv3AlRӄ7?&JU24)j<_g D%ʷ˼`hBs m7\$~xY,?:9$ѭF`0*ގ*b@l { ) iPCtK!hލkb- 6pK2$gşnq=`z>XJ!D12(.KP\j9ti;[Ic083xó ph,?8^wPJ)ta _a|EᆎQ͊}vIwUǩH%y7fO=:g g~K]"R2~nǾ| YO9T K~&#_.C1&ҧ"t~{fEdUp1¨3">gXc]UXr KAX˵o߽",aE~^cO²Q!-wS/o}r BԴ~ Y fq-Y(y7~m/a &>̩&-n ~m|ԏ#בy꡹\q<~> stream xWKo7Wj 0ФEa[YKIr kIIlmcV\gy\F ##5FFF׏^5y9:aG5IZh&ۤ}R:. BJ*&*g1+2OQz'b+0yX2Y)6)9#'dtF0`W=t7+ޑ"x[x$0J74V93P0.w,RXUTCFپZ\$0`}H*#+H y9jXH_3!C=$1YI%هUozg ou%2xBgЁUOF! N+Yų,ݏkA{ޅo?|"c!Exa!ȜIK$p0v!IeeALSRJd'- cLg|ޜs/?U؆ˌ<$)Mya#p M=!&@yp5 5> :e=b߶ڦ]ͱXAmªZ[556ZǏ?`vk戚Z:,9~ p[0΁ Q endstream endobj 384 0 obj << /Type /ObjStm /N 100 /First 916 /Length 1547 /Filter /FlateDecode >> stream xZMoG ౽ΐ/:=i6AqM"Ҧ+ZMX8 " jx$7 $%P 2iBIR6QeԲ+C"I Yh䂯EӐ) (V@rS qTJڈ5e )I' 2>1qe oBܲh h[l@O#@3Ix񱯹vFr #EU54944`*^9#cR8.qjFdЈD&h(1Q*kA&A"r(6Rfel(+R@ϙSfp2Wa Up*  @R@J6@DRRST ՐB2U)$jf8TiTKFڐQH-eEP(1hO0ՊZiV% ѐ0$6ѲjByMiRF &B3`A C_Vي4t0@yS{W@Zr`ff#jȨ6}md(rE?[[\UF,.8qXTfwr jv՛nx޼Zn^,p1|?<lyBPloX ڷj):ݧhx>_yb{^-ݻ@LrokD2rãbS=HvC$"!*aD$ #)}"p&\j=,pi-)<OͿy-M}_d dr2 Ox`q5!̓^^mg{;;-#׏W3 .0\Lo^ܢ/ oכKݐvY}|]lp^m9űܼ)8޳Nu|O/p|l܁ƣSΗt?]^v.WkpKry=ZW?._]-?8M [".: nzw p)0#Olq[FVܪ[k9^'np;npp?zƝ|F?c`\/M\1kC4l8l'G)'cl$%Ϟ19ɩ\p.7DJs_IZ)HIS&mʙT>:K[ԕ)$LʁTf2+YʸLT*S"RJEw?R*?QDW Ctmrխ+vQ*5~ ]1dW CvŐ]dW Hvٱ_J+W8^qx/CTV1RcQ*hJ:g2+Y$ t endstream endobj 509 0 obj << /Length 1392 /Filter /FlateDecode >> stream xWMo7Wênd`h&hbl$ۅ%ղ\\rH&@̼~,g猳>j'-g[LZr5yFiEGf8F2KaK Sv-p&{^`w}d4횹FZ=[rPZaƎ[6yK3PZ{7GޱI"s{uTc*HL& QLLJ8]̬h>TV}"͉EFAB,u9M}5EE$nx{D# ]gm->!ﳒO!4ׇT9cadUe .1E4zڸ} ݣFѭKx~!ĊD v2G4X:+]l|Z+黓7O_D1xUF>sgj&Nv@cqz?Iې}Lxdؿ\EG†K[ {_] ZLZ8"Њ.0k41h@aX}(:=]RM `1/$טuD-E @4gkGx 3(/}R);gC,RoCjȾpB,CFl`]jTY2W$_o.+,v C*bw`䖭.$E#Y(4)-ŌX=@C8D["nypP>a—$7PDU7Mk- E4$ 5;sR VVÇ5$\nf0|@.HMgcag&٪KuJcDw$tLUg!"ʫm=}~'rd$OxXDapEeA~%*J}UYEABT~E`E(@S%fS=4,PHA#h]@]W{x60*[&eҪfdg;WIo3dwwQ%:,IE3ș\.y˵_zzuk5IXOu))* C}Q/ yXa[m/Oc endstream endobj 511 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 512 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 535 0 obj << /Length 1091 /Filter /FlateDecode >> stream xWKs6 W(|vNg:I|!(޴Q Q8lA CJfj[%fG'?gTVi'6+1MY@_R X \#MtHjN̦ Ĵodx'>kTA6FhT0Zq.N,%=q#NĮ",ѡg#%WL$=CV7Xm/4z^D"FMZˀE6yH݃OS"$̡UJaX~ rBiIѿPoh=c7bLaEoZ衱Gj=< Pw [4xLxy.E.S )=y?%|>A2JE]x:Yd'hKF[oJAV oyH@,xFoJ,)aGP#VI J0%2oS$,I\j}6h}}oUBp5eWHgiJ i^&+"Xs|5= m" (/@S=l%0~KGBXX WXNYX^vզ5>v0T0|(W::2z`hʊb.dbW|X8Oku}NKG'>ޖ<#Gۜ[|m6~ʹ6l:VdޓpE?:z~F/U{*~۪'y oznTZ;G}]ʌH{[ ioyDerRJv]M;\r\q6O1A3m(͎V yL y WX{Mtq*v~C+5:]m&ABm,fKm:]Ze}8YBO_fK;šj}yT;{z(Ue)^d7n<t~0Ux銑s 9UM5AsdYPvKǿr' endstream endobj 537 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 538 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 539 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 540 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 541 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 542 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 565 0 obj << /Length 1499 /Filter /FlateDecode >> stream xYKs"7+tUAc:Tm; ]_ni0ʚIu22!c['#g#{φrEF E-5Kiä ̉* )tHYߓ޳d$<rO,10)a rM.Igj`66lq[e͜s%"=I<%HƄk{yz oL.XɖJՌ:#Z2`$fA1,I$+D`]d8W_jFϢ {{v8Ԣ77p{t3V!8ދAklT!KgIͥymh^`z?k:l;#~-ZY+UN~81Hsa֌k<GR9.2ZP0ә;{XI$";.' V'8Ȝ5wv%i*9M8z`OXC'),1Ɉv=z>OK35c3!8&,0}x|)dƇA~)kb$VY3K1{x  ~^EZrR d Ell2F?@#u"3Jr9 Q-.T`5+Qw>+R.яѰ˱4cR^ :׷GΗdC'!Cp1.Vm &H0徱!G/-pmn- (D(bQ6)­}*0B-Pz:;1o¶8_R\x\1x);VimxzVd4==#_) e(p՛$YL~ ]H?\lɁ l~wuqF3&GH41C֡Ӽcy ׼I`ݍ [)(L|<5L·fU|4 |:GjuEpgq.saY"S9{sp޼<գGe[AЬH7xY]nXCMwu#ց8krWFי)KV]uٿxB>>M^oH+2TS)qD> stream xWn1W89)n!sC$:C|>SNg H4^UUI)RW/V5գgCQOvk^kԾ6/gj)zu*Dƌ"6uN>'BiBemc%9efoՉ:VcB:{ϣK!^~/d5%՟Tdgr( ˛YpP͒)$rE>#H0pwBqP# G\2 ~*v$C 8l#ZXXYDO*z-h-G=]hyeIΎiJ2Hq-^}h8Sx'l"M=IbKkMȪ$zuB;]amdl`5dNv4 QyTM#w̸aϤ?}uӨly bEJ"ɍڜ"yeCxy^~{dg^ukl7lN_;Go6/=KWk÷ ߞ8v(D[G㫾vq_Q|1%[D؂ާy$^ڇ$&R7a:[|bg͙#3LG;{!`oQ)8եP_iG fBƏw!dzO.?s喀 rwa]6K(z"eV endstream endobj 569 0 obj << /Type /XObject /Subtype /Image /Width 800 /Height 170 /BitsPerComponent 8 /ColorSpace [/Indexed /DeviceRGB 232 598 0 R] /Length 1544 /Filter /FlateDecode >> stream xuwREJVn)Bw %DJfK(u ˒„{\4]r 3}=yz>=9?9֜M?~ypk+tc'GOqCgWQ["m5 J7"PͻfRcLtK9Yp 'Kst% Np(~\|}]>$'}8}!Q5"/Ud'}6AE.҃>/ѹUy!{8cU|(2dH'}8_U?'=o!"SODzCdo~8(҉>/~. '}>_Ds"GMk~>>j0Ov}_#rDڗr"G@y13:B>uܻԓq}r=vj>ja*Tg+]m;i;Uqp״YqchiZGi1q֣8=}}}}}}}}>A>ӳGؾn81ޟ^$M+5lת^sVxJ -z=r}K 5W٪ռCMGOZ!*[E\>>>>>>>>>>>卂{"HcC{;*[51ib;ȟyP ҝ -kc[\AAAAAAAAAAqq am*WhLlVCƇ;.Iۺcmo{m9޶;6ۖT5vucl|Xl6uGgl`믭;6ryjLAX5fSmݱTz%LںcΚ0PDoRl{+RضjmӤQmƆfSǴ~~hk ^¶c^߂>olݺ =HXQio뎵w)2ۺcΛ>T埯*,7NsQi{[wmWt+_[wlkǸ|>̶Xf卧qZ֛ԥl믭λտ# endstream endobj 598 0 obj << /Length 710 /Filter /FlateDecode >> stream xD&,08>?@DEHNQWZpw{  !!!"""###%%%'''((()))***+++,,,---...///000111222333444555777888999:::;;;<<<===@@@AAACCCDDDEEEFFFGGGKKKLLLMMMNNNOOOPPPQQQRRRTTTVVVWWWXXX[[[\\\]]]^^^___```aaacccdddeeeggghhhjjjkkklllnnnpppqqqtttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~rA endstream endobj 570 0 obj << /Type /XObject /Subtype /Image /Width 800 /Height 170 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 6408 /Filter/FlateDecode /DecodeParms<> >> stream xyPgg(G*jqED$Uj6ZkuW]F<*ՍwbV @׈ƨL <@G/]3 ctwL>>tIQy.hX$#`HF  @2d,X$#`HF  @2d,X$#`HF  @2d,X$#`HF  xN&d2]vB;\2<<<<<رc+տoo ̚5Umذd2-Y䩧{vnڰaCXX￿bŊork͚5&)""BBTs魷R+lVw\hQׯ/2vXK.]4** GNOOwssSO,>|:8d6m?^ѣ=ƍ}k6Kѣ-Z\~]n1t 9F޽&Nlٲe˖EGG(ӟ,Y^z?~|xǎR*PTLqqFժ6|||*EYrbڴiO=S%''<طo_uz#F燇Qtz^zӧO?ʕ+'Nh2@w,Prrr㓓ڶmۭ[7''g7))ĉYYY^^^۷իKu:ysN%vW%..… -Z BDFFT۷BlٲeծUDW}ϞTaaaW\6lX+P[ ,olڴicZ/=Q}u 쾺`;vbO=]M6U%33300P}O޽E)))i۶e߾}vk׮vUn/--M=ڸq*믿.1bD+PK0nݺ]K)))'N\vmy|7BW222BCCwUM5knݺgA:uƌׯ !\\\ bw7|Sm|؆SN]_^ ڀI:tؼy˗SSS9!,,,!!!!!AAAG~~~~LLzM1c m}]Ç?pv{`׮]8pE !LrM64H}uʔ):7`~ٳg׫W_~&M>}"11Q}5 +zR[ZرcaaaLL̚5kfϞm֭7o|Wc.` PݸqٳBVZx`ۍj _hР(...**ĩ5VU]SW_mܸW^M6:tƍcccɹ 6=ӫR Zyݻwמr&M9?,Oe0uJR͛n啷C*2Eϝ;o۾aĈ.oQ[v֭ `udڶm ?w܀ooS:tH)<==kR;% l\cҖ^V x­_˗srrlߠK` ,5kvѣGׯ__~޽-[=Z}-}E :gGGGۍZXyv-{L{Զݧ64lPm؍_`&)88xwٳg_={j۷oʔ)OҋKǞ@{ם;w{Ovvx´DZRҴ`4ofDD?peٛB -T~?6%+ݻOx‚(jeMWn?چy7oԥK??xuO,|||:w,X,GXQo<9sx{{{{{ܹ} X1:/&&f… .ܿ7hکH#kڅ3[  4z0aOUV#FGP:O{Udd{W^yF+avکXΝx{Ym۶ϗ~dΜ9j{֬Ye~ѣG9s̳kȐ!-NZxmTeãk׮rR F6N>=|{^~=33ҥK֭ӧg]tѥBgN:?֮ЙLCK\;ozhouZOG+V 8믿tqƩm:uJ1x`\ Ǟ:Gs΍B|w}{nZӕI&=z駟V-[ ,raþ⋜d[lŋcbbrssCBBC4hw=֌3.]NS;vرc={|`w7npfc 0UV}ڂҼ>|a7mϯBaÆ˒=*fy׮]~6A]pA?)L&Ӻuovk׮_NilJ/S-|.)..tRZZZzzǏ;w=7n\TTkfw,K\\\jjÇ5k֯__|ɻ6nx͚5sέйEzjJJJjjbiڴi```47x#66_/6u !RRRZnw9"--? seffhjL`}\,Bppȑ#ׯ_c۷OKK۹s'ʵ}H55Xj^z)%%Eedd|Ǐ۵ksmV$fWYz^58::nݺf֭[.##?$] d`HF  @2d,X$#`HF  @2d,X$#`HF  @2d,X$w*&###33qwwo׮]Տŋ4iҲeK!&EQ@;6:xݿ駟uyyy=w!VIӻ P("R!-ޅ๵"+۝#Gޅćt?$#`HF  @2d,x'UzwB8]]4l6jU;'gUU...`xۯP}ze6zw ףGժw+]EL[p@2d,X$#`HF n+((oFWF(J>}-?c=<=='O\PPcmaɌjӱc  4(!!AHn'3ںuk֭ƌnd$euɊNZjuȑ40)S!-EEE͛7ߴiӍ7] FTnrssŋt0e #Yk׮կ_ٳC yFlv;Y{$ t9^z֬Y/N:GkN ¶rڵjd22ɌdmۦuΝ;6#Y.HaZZKppp۶m'LKF5o޼uyzzj[_޵kWݥK_~D ¶r 2$**Jm>}Ã,Nf$zђdv#Yum3g:99?^2wussSd> stream xy|mmk$`"P9ꁈR 2<eq|FǗw1FJjO:jN>ږU3]8 B`ѸYœ2r?0Vf|;y顰VJbT,w"%ZĞ~ơR'k0 k 䵰FnZ棃î68'Gz򈻠%B@YvV7qz8]%k}X'%>nk rp*9s~ko͌vêu{JnґK禚GTbnuӚV|Lٲ`dL *éHӝsts&ew>t}5u2ǒ>%;oY7UF0(%P)nW9ߗZ9W~C8`^:I{UJ eF4QQ)n_sp6{A);~967I7isĐ.̇yx2B/?F(~U9.l{+Kz-F3ib7E%%%f2RvD>OJ=HܟL.A;[h_jzઘh$0gL7iˇSytcT\S~IÕ:2󑬸3挜0Gc{.:Φdyj'_tr z#2=| [Ę)é4?{͵s T|G𳕾LngF&;wJݡ]h3E_8?x|Zp%+hInBKv%p[( ·N$*c:SׯF;iAyܷb͔B5&[댾. ;J;족\j,߲e?|).0n>hmmk*;xHq_Rz/!փ68tZɞh+SM3GajYa T2QmQt`ª\)=q{Ga;!{vNJRgx봭Hן>S_*W gm6;آU-|;[^^b:v.]GIg7  Úl1SW.MCoIZ&P}ahӭ6گ7|#'Z k#1g:.У(Uz||/g1v_٪Y+||U)l3]g\4׷ 5/w>8A yPcnRozQKPQs~p鵚StIs~5JaSW%+F/@,!U$0-$Ҿmrqy{_|!tC~\ҫj^\~gā|A> |A> |A> |A>@> |A> |A> |A> ||A> |A> |A> _! rѣU$?zх<~qKqO#/ |A> 㫙4C_~ٗ6Rvp/e?IbbbEݜܯ^w<n^w;=>[lwri~>$]Z]Toё7xޭSnw\f=yޭS=X9kuuv[z; tuz4l[lw#{ =OHs@~0*;d xݭSnJ˶|:eە.ٗ|d0e80|zm[D:|ZgtcV}AX0VL}NY+qD^w딭n%.\_4WsM^w۹  uʞn_lZXscJbzp}unY h\m[?G3O'# endstream endobj 599 0 obj << /Length 767 /Filter /FlateDecode >> stream x @ABDnprw  !!!"""###%%%&&&'''((()))***+++,,,---...///000111222333444555777888999;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXX[[[\\\]]]^^^___```aaacccdddeeefffggghhhiiijjjkkklllmmmnnnpppqqqrrrtttuuuvvvwwwxxxyyyzzz{{{|||~~~7p endstream endobj 572 0 obj << /Type /XObject /Subtype /Image /Width 800 /Height 170 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 6961 /Filter/FlateDecode /DecodeParms<> >> stream xyTW۴DEܢFw]o1`2qddqɢDahb83n9j3=1hFD" &"Bw=_AV}TROn2)" d,X$#`HF  @2d,X$#`HF  @2d,X$#`HF  @2d,X$#`Hf^p=xJ6lhѢqi-[vѣGZ-Z??/44s&V^^^bbbjjjnnn-Znݹsgwwh,'''666++QF=zСlqգGfffk.44ã~ !Zlߥ(JLLLBBB@@@xx^bbƌׯp|jj?/UVnnM6Z?ðaN `dZ[nm֬Y?]v=yde_~eujj7nYUV7oX,:\|yĉ۷ok.jNoooEQ &O\!5kl˖-' ! H_רQ#EQn޼ٻwo={guݻw;N:ر_|Q1bĈ+,u(2)SdddT(!!wޱկܹs+W>xGiiiӦM[re5K >>ӧ~e;衷333=͛7˳=j9RtŊUQE\| >?S^ZZj#S?={lS4}t!j?U|z244²U_}#&L/:uzL˖-дiS!ĤI*׈+Xؼy۷ 6\fM5l?mҤի_->>^=ztm?2Lfl69s:7oܶmfoo .\Nc׎///0^zIݾpGQ+Rf۷jvAAQ>wx:呺Xصk;cǎլVRRndee^^^^^^nݺ|ꭺ`6~ Bu̚5~vԍr7nB8l"""(..V7XZwux@݅Ν{8' E9~=uTǘL)ST`Ս;wΟ?Ӯ?cN8QW~ĵkԍƍW[4_XZZnTXV:uԍria?׋{wj֬q*tM[iٲe~~~#GO:UPմ̫x}͚5YYY#Cդ^6I&MwjܹSjͭ}[U ԍh s"`@}%h޼b{,h26nܨe} 6|W8Tca*;- U]9GgS:MƲMt8K |,W҈*ƍ߿?**jرk߾}{aaacǎUqBuBWc:Q] :g[Z6l^h1Ή?׮]a4WWd2M0aΝ999NHHݻ_y啪#rDE&HUBӮx=|2{kp999nh+ykr pkV' 9|O˅{zz3f'O>ȑ#K,ӧϕ+Wׯ_Yk׮˗/߼yٳVիU]*22R߭[/ĉ6m=zŋþ*d2 :Tlcu4mtܹBC~%%%V… 'Nܹs޼yU8vb''WG*L6-11qҥBSNiVGEEkU,ڤ ~w/_.8|Ç ܰaCK޽{Ĉwܹtқoi… wB?9Æ ۴iS^^^jj~-:s̞={Å5kVLSή]*[4++K}R[r k :L&ŋnjּN: 8>쳯JnA|ӧXV~N:5vXū:t{ cm--] 4(!!A}۠C?1|p-0IrNjŝ;w.//׷k׮=zxS^^~k׮eddܿ?00000cǎ'=eʔB6mp֭1++ϯgϞ;v| J3iҤ;&SIIILLLzzݻw7nܷo_'֨Q/V0_)i ?OֲeKcyf@@bٿXX[q ((Ha$$+d.]Tv!C #Y6'Y1z$$$ĉFt'#YܥKvEa$?1'ٖ!#٘+XǏUfs͚5 ѪU+@77V萌Q-WiiiXXX?d$$3׿zj!ٳϜ9SZZHI6|$odG-,,cH'ψEGG,_|Fwrܹb̜93###=====b0rxr5h`)))ׯ__dIHHHZr9<Əy7n5vج,pa^wwƌ71WR$3%7o^rrrFTdFDVoԨgXXXJJ,Qe'ؑlRie9g7}$#`HF  @2d,X$8 endstream endobj 486 0 obj << /Type /ObjStm /N 100 /First 916 /Length 1784 /Filter /FlateDecode >> stream xMo6+^$r`G4sHkM ֛6}IͺI-#J+%jf8e ȺL䭅$'CAb<%>R LbYdS" g|(]2Yɸ73,`-31P=1ØBmE9õ>'LG!gG%Ǿ\q8rb< BAL Bޔ> (B A/v|/wI[EVY B$>ˁMNْ$R)(؈)8;X(x_H!Y ' I` a=ZE,\'.:(t)'PB4buzV%ƭ0e;J1C31 e[GRH%2J"2<[ ('83B0X J5Jw/VIi5I*R-P.1q%e|qFa}ŪQ N[K6EcS,̦Nce!AZX$`` ,]Hb06)g2$VJZXƬV?tn}f{m 9imsjt;:v6kXAΦ k:ܥj}y}h|;Yg"GbT &brGybuL#.7%!!oe[fa CԬO]IH{=j_wgpso}}h\^|cPk><ϮoVAUa{޾gi ~ {SQAbo_:F_jo^mGo֧ݮy{x[:Ī=#(YYUpu~xkO{jCƃCjvvta_t+~w-Aؼݞvuת6N $T\q绺B/0ϲrmiUJҫA˪/DWAJҫ{>7 ydv(Vvryy)y1aV:*i5rcX2o6{Ift^i ޑhg$ZI6z:yZGyoC ۱+L B[0g391(= MNcpؓx_θƍt}5x,OO>\8nbGBx7?1 ,ʗO*K2E*GC~3}v~=yx=)0u^@.9OK?cxS2:ea%!bwP aןW''FT 9w TVdR *ʤR)X)XcǪU>V}N9xFT*9TBeq6TgCei*[lKTd3F0%ցrl@Q,̍l-[\uThYEle;\Ep+"WD^+"{EdQDEdQ'OT>ڥ2HT_P}aNm rǹ w r w rO&7`4n s/̽0m2w}Imytx` cUX@{w=U7Gcĉ$Q$*DEHI"IR$I$ny}/RwKE-}TRsB Nf68y68Sɂ8 OJpi endstream endobj 602 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 603 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 604 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 605 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 628 0 obj << /Length 1308 /Filter /FlateDecode >> stream xWKs6WHwJ7S}$984e+cYÓK|wHɲ6V3"oTJ(vvpT"=՛9u19N;}R.m3$CC6F #m {hgAbKjp?4A@ 8brL^+d&[^ƷRۦi#2Qto G/yw f`i1eYTV M0%վ܈$(`B1R>"qWQzKLȱE~ZĜB !/:ۄqݰ Zg Z]sŕ3W?d$r@Pi3K+zI7ebLJdJBPאYG^ŊL)ff{ bߍ夊wԦe z2[m2nKpۆn <ಳ^(:#CGΊ"لEPyn.}$L{67%{\ΥoH!Px>EvpNV)'2)4}:Sp ]K%(R6iahPXBz!.4׉cmk"mnNdZjhbvyKrs׀>\jOdTXu6rŠ0):$od'F"(C"=4}v8ar7.GN6x0T2ǾV5'չŏ ,$WPtS$pBS)V0G-nns7cuMXdFў.^ B_ݒr^%ڔ'>,]&Oq̺q.~Jk\7r\Vk_[ַ&PaPOԵ)~pxS3{4Gy(x}L}_Hv_=·y|O(_{ xx endstream endobj 653 0 obj << /Length 1364 /Filter /FlateDecode >> stream xWOH_AW; !]ۣJずp$Jofֻ6Ih^Ajx3R\ ) :Rk ^6lp%X^bq)VIǛlrlk@ eDz^\k ʑ\9]}%hNOBB> m;Ó'bŚ*pϻp~{t~t@)=:6e9 A@̉uIGPbS 485KmII)Pz- d|2H:[(J-2N }(Q5஑4ߧי1=We$u~yP9{ ս-yegH%8녊ɛNY&%{t28w.AE%:P&WU悾#>c'6)P_mv]YI_G9bIbM4BYMlB`x>/.bZ g U 85^f$$Mg/Mʕhky c`V`DkEgdGboѦg3ؠ] xg@_JuЗ+4#hO'XT ۺhѣ+<#r1mz뼇Y:kpQ4u ƩoSb_I|տ,zWB6~x@ iy8+Ҝ!f?f:1) 6鱶8ט9pqMyϔ۫H,XEWWy<"]CWdŢBM\)5}Z7rIs0\bWe> stream xWOH_AW; !㨮Rqc'6)P_mu]YI_oF9bIbM4BYMlLw`x:/'.lZ g_v U 8%^f$$M'/Mʕhky c`V`DkEgdgbѦg3ؠM xg@ߊJuЗ+4#hO'XT ۺhѣ+<#r1mz뼇Y:kpQ4u ƩoSb_I|տ,zWB6~x@ iy)Ҝ!f?f:1) 6鱶8ט9pqMy닸H,XYW_Wi<"MCWdŢBM\)5}Z6rIs0\bSe>D(׆^^4qK*Us*1ձpJn[ BMm9ltx3>n[ 1>n͋ Aov~w$Fu<=\8\iG.!p]oBV.ΖOq&<;SByg!- endstream endobj 703 0 obj << /Length 1506 /Filter /FlateDecode >> stream xW[o7~ϯǍ >(B*PP+0\P6!Dc{;IH-H]koR՛-5zzATz *9I5mrXdژW=pUmm62]UmP]1)0UoLjq6}m~,߆|ga>pL0@+j9 ŒTf]Χ=xcژVԶ T69k<Y[ d/IoA,oSUȀ[ߠ1rti2i hRTg4L9J2g̯lfZ?ɜ@^rALGޜ*܉ow?|#c"-pVQ˗`Pm` 2x.2eߵFֶfWָ_3Cg!eik/YF2YWѼwEq\2rsuS9{QCM pF!Nb }c ^C`<{r8A:4J.~1ѺXLZf*櫂g:Ise^̪2,&Oc|f}#h]]'\RC8<߮6%]Nq́HD`8 ULa4b&B TH'9!`~k>'}:B8VI'k^dvW@wT߇c$@{wMXR>(gPX8|fnNPQ\눱3<]03)(\)vܸYR g=N[/eDƟ5CvKΐF(V|.|9ﲞ ogYz{/B/"R0 D?b9':$6$勍jrAϨMHXȚFLQ7S 6~Cν(\df3L0"vݐW Q0&VlO7#NcżK 'q(e=8M1Q2k9?$:|5)WZs>c!}"ηR_tϳt0DJwXP"szn;`Qj;Z7}mG\Ur> stream xZo7 ~_N$JMdh-ȃxm.w}vK]hC(ϩ9J%Y)zTq/VHOѮL}2wMġ^H\"qKR#eb`C)EL\5q)}'BRL!PP+,ΎBuc2#T9QL E: $C\O2ʼn+e iF%h :}*Ћ NP);}dV)Gu5)㕲d(#9+`@NNp"l1y%jQ4ؒ ¹R4,:LGBC2&F#GD$QHdMIZ*WRBt1Qp1.)Vf@ VD2uw]Դ;=yH_GMd5E:b葨DMf SRzjy@+#s={+P犹#D RV`9 _Rf7iO~5|XMړOW]I{X^Ζg ם?gM|>],8i pwt=xq{8tu=OOokGJ8t$mّ`e=dy Lo&+bS!˾l6`fcitصti'%Ӌ7]Nq̃ ]/oo6qƬJ/ hk|!%,UG}o8%"4X4}}}~ ]j/˓WӋGjެOVՌ|wa-.GTS;†j_Q^Ȏ탗uݺQY2o-'3Q{:{R}h˫>.ux{8b՜0\07szə* ^/tMP?Fqh5݊ӏ^^yS~^̨w>/J;|fEwa=>wB|)9V7(&즫K?.7ȴ4k ~tr>r:Yo|p%pI [MWIjVj!bj"{M`2L& 7{:n fh^ۮ#`:p#OJ$ݤ l;=G{O 8yV%t|ٲ'IXc\wAG"&z'R֋88PvA+^YG:rqVt(gE@Qѣ_ŏY⧙p* 3 8 Nq`$ Aqp/ /^4hxEKnw'*opm*~g#WUF2r|U\%p2P**WIqd!g bDq1"A쵤ʣg/9mvWD% q3\ W*3\%\e*#WUFUq?ޫo罊 pbg(qb)Aqbg1_hUëW x{ʜpv*q*#WUUX* endstream endobj 729 0 obj << /Length 1432 /Filter /FlateDecode >> stream xW[o8~c*[lT!-Ey::m ?~cNzPiGoq8RޒbJbނHZnkCVX)&.6/ntB7Ʒ ^l ފ/.o 2 $վZ( sN십}tJdXIn(4?oB^, 1gF7HkG>bhĘƌe6)j6Ѫ>婲b7Q648k wuˋDrbJ>!/yž!P{: 4ب&TE-\uz6AvLndxngɶCWɀ`O&^A[WV%!)/N[ɾ1c5}}Kq({ÀnsLu_'x\?NEt|,P}/|֥Fъ}wyZc}wNwGKTh7 1qsN0s"~1wѣTg􌍼1z~`B&3s@jNMcoN:PߒIȥFb,lMu:OMSӌwj-̝¦yu__kW[2-N]e~')l [ endstream endobj 754 0 obj << /Length 1522 /Filter /FlateDecode >> stream xnHdߍ"He9䱊'$ U{']vq'B;r^Rg|6ho| <=!K1F(k8Xś]XqG .wn0WG>1l@W^?ʵhky +V`Y/Ȥ$VfA,p{@B?I8fah5WjH,V*9ڌ̈́FtD*2& \a^d@9GцƩo‘Sz ԿAXDžbi\2PB 1xp6Viu~ l4ژjs d&GJi,- -&GeV W$xx:s~yLQE _>u}&T˼Տ_l:2jLgŷO =r|bq ҩ59*gko yțQgpNmb!9~H09BXMBr;Y- بQ$c:-a#{oD/ a4`fEO߫%&-Ao؊Wq/o53޼KP.C%tn=MC7`aL#{Csw:>7r <)x 5yVJP%t Dd.aٲ&L T6*3Ƅ /C˭z [fٽ{dP<N vAq`(Ač?7n݌2~&)_1K6+ endstream endobj 780 0 obj << /Length 1462 /Filter /FlateDecode >> stream xNHWqwG(&Di bV.ʈ>z (TPH]}+6v)$Mu|SK~c EɄQe,4jĜ p5|L4d̶~]LL]" .շk T@}܀(#)`mZu+)%P;tP%6#rlVOSH{pd[#Z(g oZ\[ɕW? ɒ}(^L[/'=?OLG$H0"sQH$#(Cs)Ng.p1 h[06%d8+i ꠥ"H^fnS"\iyӻ10;JenM)k6-9Mgxm7 ޔ˃*{en-yegH%8g ++lOgKǔSdDJ *T0t$`o=i>{l77p [|_s}Œ"qpnZlb#Nlof |Q}$pI'jviR~Fc|^DËw5r56Z#=k?+e0歹;uWdD.MI+ f3ؠ]'>Q~?ga5W:ɲPKe}6m?GHHEtCWFTTm"QB7Ч)~f]5p Ҹ4e @<ڬҜ9$iKz-5fj,|%3a>Sn`iXh <^mv~KOVCUyIU./6(De'גp}+[rg_1eC̑I:ZBҲCn_1^1 bA:5ۡ${^EbA͹!o2eEljUoqH!RƸim'GTˣJ/@8ㆢbzRK6xԡEum+1ڃ0yo?IA@v4&5rE"܄'oƠ7+;g`7HS oݧ(!@й.3rBOU .:zPIEں^;JM,[,?Q6Ծ݁A\2ψт:'rBg4+.aAi3x40_N4*_݇ }'k5_u\W֡O%JҖ:j(wL36a;Hۚ2<$M:4Xce>Dt6IJtz뺷SU۾+Iy?# endstream endobj 783 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 784 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 807 0 obj << /Length 1051 /Filter /FlateDecode >> stream xWKs6 W(|d/4ٙ%qm^v҉@vt QP%h|J{]lAG(@o^)n,DK\#MtH 2|A&= xj0bvI8 wB'|+qAl$EHAZ@#jo!I``JCC~a1Mn#ћHĨ)R hPd¶H]2zJT9t J,`~Q?q 9!Rδ^/ZyLFRu)uQܧ|KݣR=3 #=ʋl/},^w_P'龍O!آn(hUIEQ*6$m&4Zc)Y W$|aH@,F% 0Q*-8}zR9/i(, f$.}S&"x5}JIWP&RVzUтa"!1>m4|~ӫVy "$[b 9ōxWZ͡:x븚ƘJ]}*QgX0/:CբY~:^rpvGB+T[6x_ n'۰=F@xH9L!OZViۉAZ> stream xZMo7W̱o0ǵ{h !bo5*6}C [Uc;Cro>ıD2K"l&N+1,s<i[X2s}[$ )d}kȆаdËpD4<@H٠CȓdA-\c.ْɱ#({r [LRHvbjynw0;O^“\ %&./ ,B`\(%8xNR =S&ՕԅOd`v}lL |AUh_mƸ׸Ö{X5[~sj_nq RtqX]t֯-nh><|\\vxQ{ֽ_ x6{M@_uez_/nu5|vxOu\U`t嬿$R- @1~_ܨS.Ե]/WӵjYSQYųNJNJNJNJNJNJk ;n\?BG@n._\xd[Q2,Z9Fm *Iv܍ .-{yK$FH2MLd=+ ! 0iQP&/vdх9xtl2m.a.!Lܖ &r(ؔ<- |{9θ & 5 T8-S"|$q! D#V} ZeGUBVI!~UjAU?#U T8 N5W Ux+Wv%>;'_Yl,-tYV=UeWYUV}UT_Wk(^QxE/k-uj8겞貸+,.K;F]6QQ* endstream endobj 811 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 812 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 813 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 814 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 837 0 obj << /Length 1080 /Filter /FlateDecode >> stream xWKo7WЃ} %>R H^$>7+5 X3,W ! 9oQ?nlȈo';ؓ*+b:ݧer>x+y+{н#p+{^`(XV^ և0HQIgD,NX) 6bGѾ%~߄2sTUF\j#94Q,BSa^G,ZTV_à>@#\ ئrtr"D<%LJVLɸ}IzS[Gp8i`_c5 bʼ+zY|NpX9J$X ͂LE[ųlgk ^vO/ʫcO UIr .,  cS IgL4VN .NʡkiZk/pGE0TFqY΀ɹ㍲HǴ"Ʊ 7bX^Tݿ.|PPA,;.E_b>h*SKxKm|y7N4*ED|c~I4~Ծyj96z/B(I99 J#8F,~8-?\_},Y?-[#6Zş%è+a:7 u~7Z $Hvbwֈ\'xAeԌE | ?cўlIvdk-3Yf*}4 2£[L&qVxd7ie&HdDWHzϐ4ОҒ=yWlIyo垘X~v?]8m$N {xֹz뻉ǝ"Bg-@K@X?$:eZU>r@d5!#BBC!P+&6hN KDm)ӪwxԳA3T hclc 1 t I6Hfg*wd˿: endstream endobj 862 0 obj << /Length 953 /Filter /FlateDecode >> stream xWˎ6 ߯ 6Yݵ]< `6P$sd45`ˢH琒eR׊w;ڴ;FK>ً#;go5{<͵ڊ^u' 8G0SȢD%AlpR0 ]p N9뻤fo]:Yr=೗eE0Pfu xjIei*,޲?w /o'yخL_9mqZA);'Sr(].r,xzgLE-nn$;$}>l2kT]@R%c{ꩋ)irǺ}5u>jZɧ-ey]hyޯ|22+,vVU8֯cٌ mJ*I2L_I? K:n+%Jp3nJóQӲ9Mq7|S&H5P<4Y5$a,%J?/c"C<磄LQ 2-=D+HGHأN:N`8#>NaҀKkVnQ$ǠOX_nhtu endstream endobj 887 0 obj << /Length 1193 /Filter /FlateDecode >> stream xWKo7WЃ t>\2h{(גH-7\? Hg3 \L&b_M$zz5rr\eIGL\E ro50kWlU ΰ;FbWqeXo|#$jhؤ C69$IXJh: k.kc+h&̣AA9gZ 9LLCd0]ZۘVApІ;@U4j Tg[W V!IbM ?>V}X}BG%#H/ ]KW9"dNɯR:4A|EIZ'aroN< 8t>7 FJWC,x%ĜH%- ;Rpy'jm2%f4O"ӢY=O^=ҼV$J63qeˬ7oep2M©i跙ń\㾅@ҕ4{*/6Ty-zҮ- SM'Of़$-\|q5'Ы%)hԚXt+]`s"%ϑFLC\;EKhA`hm)CF\q^JFZ24m.ipخJj#C$z9:55GтFQU7R?GeWE嬨{!GaHP5A q2JO7}8$o0W)N/ {aD?da9:J%]/qmiIU1\uoT:"72#ٟ/67Ф[7Hѻ)VݦwNuh2l@'jq d=~k #_~G)pѼA&'RX ˯FU TqBJ\bU(ރAq\GNe-:nC*]lOnoRwgP|[uXFwx P8NgqpwqSvŎݓ 85PqNIjJ>i>`4aFI $ZG'gOڧm0*}[=_<,~ endstream endobj 912 0 obj << /Length 1568 /Filter /FlateDecode >> stream xXmoF _q'{]Qh5XaomQ(&vߏHqFm-@>#H*3G|k 9 M7f?FGx# :gۤ]&,ӯsa %RR dl` * p%s{X|URI`Lh1;b#i%~:躃|]rޱ$#EqyTi`T@1aKZ G1ؘ钸3TʆPm+ *뀤9e*e4D|r )"\i9/pw~ A MߴaW']=hȣW2mۛiIx)rJ's$>^i7ޘ$=}m@REJc"y/Z˅"ȜH %-ԈuVJ0R[mU7ZLIL&SD"KtF7YDj&LiEӛw ;t)t59[-^d XFCc_̷z>$a7yioې}#sEEIX&%}pޛ$*)9dxJ\bh `lw=|/ *~:}h5]Bi2^ ! A. pͤ1p5;9coGb|W0,? 7Fģ'tˮ_NJF.%צsS1[<)K }-O+DY&~[ՄU׋9L6F,H"q=HD}0=A?)+pa,簿/2!4+*(tyjìp6V--3t%hbl={Ta\ȩwx?D:.ҥE;xṎg3Ϡp~|ܰWqSmLw4\D>O^·no4=OF)oP%B)ڴjP9u6u`(m ϟLwX54!tքˢ&8: I_4ޠak2 ݴd; m*O ΃` /&TZ/?Vߘ٭*84[] w{fA΃5qyfOb:'1O}޼TNoJDwms&TNȆG(a XkWLRBXF.T9QyC%Tu("B@)5ƀ0^M%ʭ$MHzFb/=| VCB?n|L[8Aa !1p]Z}YWwԽ%vHJRqpGRUo/1lf'Al/%hq .UnB|-Hmf<4 xNV]g;V}{' endstream endobj 810 0 obj << /Type /ObjStm /N 100 /First 917 /Length 1697 /Filter /FlateDecode >> stream xZMoFW̱; r>5|Pl6QP,r,S0R.ɳK3 lz#') uPSmY'ldI*IJ c3Kr'1T"oאPn I(8>%{%%=L@Ԓӄ,[Nl>:@pu얣9Tiq%kIO@n,U71-[+on61_CV`c9@woِ= x~$a !#lS9}3"Tcå+I8"ֹ/s` )|J>'}BO+MJ4+J;+J; /(^PxAⅲC$e3$ =);COʮГmHOFz2ғd'LONOғۓUޞD QiBT&DIiGRڑv$IiGRxI%ˊ/+S7COHOZ;COʎГm7'[dszbGz2ғd'#=yT$ۓߞYoѓbX Ei.7gTQvEiGiGQ[{TJ2*ʬrޞDOܮГ٘؝'vgHOFz2ғQГݒ>u endstream endobj 939 0 obj << /Length 1456 /Filter /FlateDecode >> stream xN[G_F]塥$*.}"Q6il0}gα)F mt3s]F&7/FF;l͸" >RIB Q d=%T:M$UA \|1$ 㘃5Si)4@28@J#ѩ 8++%3GR Bǭ0!ՄIl:ٲJiBX}Q u#0ĵR 6IETsr!9+K سH|o7z #r0i:?kîkkeu !^Oeޢ%3#W?1/$N@^seff~;sl1w༸z=ARGJc pa`t8DN % Ph;c2ȼn&)3$fN©LڞC-if)$XҒiS;)ܧ&#>k46C@3~,ͼ?@X}H~ ^ mCB>ɍ_r.o>yQˠ$ON'E% ny8JZe,^+b14Fï ,M < h]!$!99>L5$"ǧdq5S~.a ]gI)·/a@kӄC* q)DJ5Zy|AЍQp'PUxBd6ԿIf O/ަ#p9E\ ',.؈7 U7@=FnA)'rV(?څtMqpIu'xKYI ݈F|;X[q}2\F8X.B7պ (?P2 zW0}_贊vu%7qih<'~~-m}56OI:QWO_`/]vҗ=)D \ǟpe[344 oÕCЪ[NDMnej#:B7S}:6+t|#:B'60v4YNwB*Jr;AO>e&}F+y{0T]} endstream endobj 942 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 943 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 966 0 obj << /Length 1118 /Filter /FlateDecode >> stream xWKo6W(8-Pt^$zWVM~gH (jm ЃDq8qCm`fb$wNN[i#Iʲ Χ\//n,K\iuLsnkbx ,B\%TW{PvTx.ueWOSaCu{Iق xOQaTEK (/I=?7JKx -|wKIX$%[^B[a[ir>Uk沺u ϡ/֕gyה"D`%V<{1eVm;|ulP.=8wɕvTOMw&4Qjs䈵xq5KC՗1Hcf8p {D]h)l; !zٹ%i^ھ_~noE endstream endobj 968 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 969 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 970 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 971 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 972 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 973 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 996 0 obj << /Length 1082 /Filter /FlateDecode >> stream xWIs6W(c'pN38RNI Mi#Z2)K.li"n"1 z=9XK^m''̥e`eގq9OC%og\iuLs+Mظl`u}eĸc+D$ H WZ32)FM.! (p"` hn1k`tcqD]ɵv/J  j=8=P&JXuFJZJ5B .[s'b :#r|AcAI"NaJ:ԿPϾh R)QϨ5ߺzDƲYhNO; "mfn7?).ţCʿ?xH/S /hѕ DQ(!2=Rp8tkD mMᬤ.ɽF YGbE3WjvSt7TY.7`wRCY"ƹڇs ,+Kv}]/uOz{PNXxTJA*SNYAe{ w68 \vr3 nm}//O|LJ= 7"Ys$}W\e}3рtj ټr og Dk׋9V4¸CZ-Ǝ; /%AmGV1S,'K^{+] *˃/a>9b+YZ)G~(횊}ɭQI֟\'ۦ=d7Ҟ-Lf O f*~lP-|:=Z .zb'8 endstream endobj 998 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 999 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1000 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1001 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1024 0 obj << /Length 1147 /Filter /FlateDecode >> stream xW[5~ϯc"/c7Pي !nހte6 T|ۓ6mD$s|/`/&b?N$zN[%Ұ(k6$ݎI8bRJkaW&d*Q{gFbqe}-$jWkؤ@+vn$`)#tW\G+c-4E~y475(LZft"{/|8Lw;#+6j5@\ZswH L\uHIR`e7r܊|M-nz$9BOz1b샯nU2-.!sJ~^N "N&i&ᄇGp?t"cđ, ^ktza=1'uIxK*:leu7ĉJLI!&S$wZT2k)d#Ed7wBiCS»/{uG ep2`j2iLAdbB_a@֋ J˃en~Ү"҆ veɃb,?Y:9dM7cASTU@\cxE_ :n_exTs]#[9XHrHp#*AWl<]a5u꺪 E{[%mB;OQչ]ka0jq6ZM7]NOLi鬭㞦f8bA8UƁwsq8=<)?=t३\=bP9} )S6$*(䵖. ~gk+IWxs}({V5eJAsLM[Ήy>\Ectg'dgUW P-gPB%Y̞ F2/pW#{kE?8 ĸSE9}Sl9bzX4\mlNz:\e&}ە7]ljԷ?=6Q$web}~F,&TPl;eoh%,ޅ,8$J]aڒ>ҏ&GRoE$D_&C (#KKԗޯI˥_  endstream endobj 916 0 obj << /Type /ObjStm /N 100 /First 937 /Length 1749 /Filter /FlateDecode >> stream xZQsܶ~cBbxƎ+u3jpXG}9S[rĎ2)f< 7wT]%v1W nv) Հ'RBK|eQ`XlHD8%Ȏ7>.03C #2#|qt<ɱ:X=I c>"P"{8GTi.fDYwO. )aK#)4D]$d Ia9NՉWJ@LzU8×'Q+DW"neNM #D' %T v9\p@. 0HvJl Wjj.$LHzEW!Wj:^@TG-:yZ*ct(o%7U+zGɑ T=,8?W:y-@_2C ,q9oHˁj)&V}75j<0Y[XQBVB[չoX.408ij(#}t9Y]L Ũ.0j'i0xXBKjNN;p }`A [Pr۷__4ڱjz?as;zs8 cOCFȦ;mu:6T'NQ{f"8۷/ rr~wy9h<=u??U߀o7p؋{/a_]o޹s%ڂRk". 7ۛʙf\(qx|c[6xk`-[M֊ /%Sw>H~{~tOv~?_tw_ Cy2طFZ{ =lrPnxp2Q1&sMC'eK_g~-!Iw=߼鯀L.>NI2,#b{Լ$'p'&[Œ6tf͉vv]nfDo%gbRZ}=ML>OGI qeR|둅In}t rȤ"'j5;L*rc"1IGf"-Ƅ=FihZ+֊idZ+Jidx%K O O O OxA-ǻ{hƋhWjUmhF4mh[׎F5{ʽ"ך!ڢ)> 7:>Φl8.Φb..bx+W ^5<7j]Ug`|Kq1:;.FgUg:{٫^u(]ήK}1]p_E*?!Dɇ%?0Rt o3dɐȓQ&A~2h2&diB &diB 9LeӸ-bi\> stream xWKo7Wn MR ҃m\ܵ$Jl#𵫕1P+y~3r6gx8rn~'894KZh1h߹(6\[HHl5϶*FN/Įk*JC4#K?z}BG~p}wCDe*<8J&ri(}}]FJ{@5A m됤8lD  ,-9CZeBns4IA_tq[kp탯=)+LzYZVQP9}}A ŇZhkq3KyI[e~bFʯ-Y5s&I.qoBv!0Hee"&+ %fFBIhמ(nR*6BiEӇw%J7AhMBpCmZ9m`dؿcoYW0\D_/tm Eo?E:;!%ޞRc|0@\c|M_ =6_T8_'9bIb̰5WLhM䜝T].OofnxH(#-Sn>_\sQ~ݘZEZ>rWjE!0InF*$%E]v0u 3 ș488`lV8C!VX^ar]gbt TyJEmRR֘j8Wq:Np28CjeB$>AEl J#n/7DBNCY^}1%ۡ3Q Κ5cm!P(Q?T:YPU8c#ݐjMbt⼀Si*N7q\S:s:I~@#ݓY_ZxUkPnJV#m:k:iVT,]*EBr,T8KҚ4 4GF/{n%]<~$-O [ endstream endobj 1074 0 obj << /Length 1272 /Filter /FlateDecode >> stream xXKO#9Wf_msjwF aՓHۏi; UϮ*.`'bN{o~39 4 I'cR&N_؀roW0ŵk [6g3;#[渴^xo}+**$@1IZ)^G[GhoЯ?Z_{[f_e ) ".PLL`u;LwFR6jo uH҂[fw>ApY ~a"2pCGH@ҴH!wg}Z`G E+DzY\ZR#)+Vu&аhq2I0ymN;$]I0޻|yy\ mCBiZlBXO2)ٓIyq Z-|a6BO^ګ#.1ĠK@U'fS7J#Эm!ґClnf bf_LO9#l_]ZTDU@ӻ r\Ǭ$& UBןݲ䴦7A Ȗtrk4k &P&18g |&sEUt)3_'RjzoTڴ5Kl #zIE` ƙֽ3@sT`* xxansjz}zs@bұ +m T'0ѱZWu7 yh U/}PZVnSܔ5D;od"($u bz5ѹU$N12EHk<_c"8tϷ됉15uB!5hA#Cثog|E VN;^sdG+]4eၢ8 2`S0P`5CaC0~K첗*ǰQx> stream xXIS\7ϯq8C])8F87$ [;8Hjuqi `Y헓흥dwh~ꔭƤtE5eN9Kd~6 Df.Jgdـ vd$R[#t7૎W{ǖLQ#;D Ӆ*.PL`q1]Y41Ty+1cCs- Ev"9@]c$TKCNF3<,_^fB-򇸡#$ ҬիZclh!OR"I+5\K2W?6W= [V'4/loģ~r??p?: "1bHE^c8*O̙$Ľ!E3N*,c⸒Pm&#qV tNr˞'/<RWzvVp{;w&gapC۴m-m7{_._mz[(AH;E*!`?ePRHg3xu ,VJ9| i2W ZG\ 'nͿ(hx|CyϤ@[p!e)%1Ɂ`k7bsv8=[wkgl|5x Ŗӫ ;RN4~%e_IpHCXܯsDgĻ!aDžz^? {ybxoa\m"B^6ъit&a p,/^.' S_3!D)yu|9Jn &&2Xj|"79/ <4DB7Jb^b$vI,R!EuxptN(IERܒ򛄯ӫByȱ\UĩL?$럂9EO6]+T.-p41 O^|GvnьwadqJCbx0-AJddJXS*k=d8%MjKv XAD~l"1x ;16fIn:N'>\> [tiu0X,(rK  B)5~Qu]ƉA]ž {SS*G>(V$0@Ʊ8.0> stream xW[o7~ϯ>l 3>6 -} C%C:Mf7~|s|6H[>~=R )|u0K+-/vhUN?؜)xKBbWƴ&:aZ:8C/ ;AlW"GN*53Fh) x!^$mu|JH1d:_T:P݁Oƨc!3[?.kU1>շ3l往vm(+)`1Ύ(EK@I*CӗWQb zރRDBZ _ulk2gFZʑ\9C}Б" c)d,ܒ7_~aZpO'OHcHRy $'ҖbNZopi) \`UUH^S,"v\y31>;JkePܚRpHOmZ%}38|:r(ik׆^ <ಳRyUSAYE{*w1\RzTokFqzKQB>:l6YJjݜJ8%ꢤ5i`1~P[:o‡Mb,| \\k-WB KL ¯Ϯ 3plL-۬v7nn`;$^\Ҳ96*LWijA prJ['i-gMv hM[j͉$TfaQmOl6p?IN8VtD_,(^ssUE4qwf>_Mxt{9(*qp*? U|ɛ~T*Gh_ >ޫQ.@+β]\T7-[AO8.eK:L: 0lq z<]%?ܪ$&%7BUf_@]5ON , +q79)%sdԐ.uCɴ!{Ў>S^5C.0[ź)T.'C85󷈳 >> stream xMo7sl/~ I:=iAqM"Ҧ; '6]ðfww!,vޑ#vJ>zȗLA(v) #VJJjk8,Q/]ee'j%UɳרB!S끸BёO!GdU4E h1QM/hb끡E=ȅԚ%h1(#9(3(SDjAv)RIݧD04;I(fKb:0$9n*H"!*”TD{H@HS%\ .ħ֮U#|dG"Q{ [!H JR1Iȗ65|3s6\)'V d!KR),pi˕5tdh`E*\4)%Q ^U0d* (9Ac=X{TIQ=U_UeUC$]F"!Z[|iH+]m5csX[ j˚%̘gujvCo7(n B?9ےNyY9n}i .4!>:j} Vk׬mu=:8;8rGDww?p/g:t:]LbĮ0<4:jA?_361x]>]W\?L-/|0,|wNoqzZ1?[|Y//yzoƬ?\-7tp@!ԡ!.Fy^^aHb X}X-H#)lCNg\ϗ-# k(n*Mbj玆ΝK#83 oF0#3L9r4hє)GS/O? 2Vǟ^]]>.`;\>.Ne+%xE(<3ߜ!}O{/HPX/BqEZ>z$`Su6M)옄$I C$ب_9ERۜHv @$u@._#۵L[_H {eRܕ/8~f 'xuNߦ#93D"]-~E\®[ $8 ۽{)qC$İ[$)n$m Hq []wrtf˷MWgd8#PŻkl˻ȣ#09 Tqdsr95@DnpN2HFH#i$#d a1È1r6-92q2psh8'sh8GF9y,y,9L3qsgw9szp5a7ֻllQ-QK1j)F-ŨbRZ)WS\Mr5jՔ)2",C @O @Og z&虠go zظ`ٵ71^np x'_m_ 1#QD.:l7#alllllޔ){S8), ǔpL Աpm1L3q1wu endstream endobj 1152 0 obj << /Length 1560 /Filter /FlateDecode >> stream xWYo6~Q^OC)4%w ^|03'> ;q'ˁ'R<:& I{kA'#HҸ. g UE*'+[Y-0iDMLQI(ldcϑQGɊHIfF7\i$w501; )E#4EU#,izo1^'7(+J{.*/m]E*dfҤWHў;.ɚx{Jj>IƸa#Ы%4R }Z\ @/K CUM)$l7ʔ1(*do}Y9ų w}v!ȳ`E"ږ7o.UyoF2Ֆ䒲+Rv?,KR!,F=)5UԚO+b)W ňGPO^Hr0^dTB B:vķj>+qx khD$*=cx0J]yh |*'^^ r~C0@๧XT` ODic e~M>nD$_\oh"ĿHز9W݊ G'#oSFp#Qx@IӼX{fSfGZėfKRlѼƠƊeíb\'9n=Lҿ3 eфf`mʷ];4ަb7!"dħF/zTx3?FoC/W#fl]s{ * !p}SRN&}@lL~P~p3rwLzr'Vlo}ŔY 'JNXM&I-4N岆4S xrG|}QbLxי7+ѹl|I]?rE" Evm=SZMo0+:T粊ހ&9M僤XMt:"#ǕCTplp*׬ʛ2ʠkh _ju՚ʒQ<59,=O9'BM  1<˳wȫ<]M$ب2}ae|'B_BՂ`<҂W_rgn.!Z|s]#ʏvE|߰6 endstream endobj 1176 0 obj << /Length 1080 /Filter /FlateDecode >> stream xWMo7W(Ea p5`[w-.RerI.j#i@q9y3r0Ĥ$zNz%3Ҳ*6l*Mdy+in|K >; ޲soC+$@of jR blvAN >9 ȿ !x$EGs^Cf8[92JcqڅYɵviY}V1B["/Ր(1PF;˗,B?򆨏$)'J*жc P U)g뢷2xO+GĕSW?~2(4"Mfk'rO"u/r>q4!_G)uNHG/ \ ,Ҹ.H !wJ!Ie܁/Eo3!H$ZY e]"KJY*-85+pnP /,h\HYח`2twJ\ mCB93R8ѯlc>ePQX3xMI[%)6R㬊'[O4_KH֦/?67p n-wK|$d5)k [ް_or~vE۠h? ϏߖN9!E]jѶZV4nH쉜Ӓ| s?. 湦d!!2"rlƏ]_Of$o&:4hQ0(^;kXI@!Qm,k >/l<ͮBܚQrH<~"*Ge$TļN *Ձ@UDe\G'XuqD{rx:1?(YvCv}z&mZßzG(;rx&7zדKg,FgSVe7enb\=1@?_?$iA"aŔ7r ĪY4m͢69ۑEt>G0?ǠW5Dc :X7>|5D M endstream endobj 1178 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1179 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1202 0 obj << /Length 1125 /Filter /FlateDecode >> stream xWn7}WQ*K{IР@a[KڇdvZRl5=C.ɕ5bvΜ^$LW3Vֳg/Jﷳ[riʲ v,:.]6:Ĭ:Z b[l"e7LXEi usBmA72;R#XM.pM^\M rͅ>?u #H~5rOJ*? dH/$({NɢK4o7Cynhef? #dI`jC5&e0!P"8oz:p[ߦIwRimRQR9ȵׇuT#=ϵthAj`4v_T?!O$p' ip KX._xDL ?Me!#_φວ6pFϋVgCEH%J-dh"e/J'GtͿU ͽw^)Jꦼ.0w@GI˹SOlnr<5pD endstream endobj 1206 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1207 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1208 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1209 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1232 0 obj << /Length 1438 /Filter /FlateDecode >> stream xWKoFW,6d M Cl(В’bIF.}h'i6*`ٙo%gg=>̜vB*|z_aX3ҰƤLܦ؀roTaa? ް Ůo < U)$ .1{^X9h%|p~BlHe,<10+̙ vrE3S_0y1]wh& NAxz i[jdrD|rjqQ\o,EE&? ! d!J:} YX5= !cC]ਦLj#3~ p1; ֏TK-Ǔ\sV tV:"YRyl06[UPnxQ˳9.y%&v("OFݍ*o>X^T*jYJBTڧYFlا3o.ȽvBzxz6mП%-_ .֏إFWX&S=E>:9;LVVػტ'_,3 ºǰ\/hH+nϩt3]~@ڝ"~( , ΅(Eh԰儫xC;T}PM pՆڽQ R7; F vHtީ(,:Eg",1$ב1I0AV#}:!G$٭"I$ho.3j@F" k#{tOcGjzBCPӹ Tuv o^ܦ(0" nsǦyB]|w w6_=IEjnv X q~Mb/5̢E}A)8|K(_zq LK endstream endobj 1129 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 1769 /Filter /FlateDecode >> stream xZKsFcrfYr9$@a`v>*xmް/zJ1Y+6\#8sV-x\\̂,b_@&J hd'#x`dOY2C2l}ò%D&&!DhžXe-ߣ%4q_@AN1:Y*9H 7ou𲄹D*( %Cj-`0#s.^y sdǦ!{x IWEȩKsI1FcD7# 8#XFDޘ(ˣ g54%%ڒEЖ:YŠ][d!mʎYVeA:@dme(K%8Jt&#e.e.kEOY}{z;֛fsj(0gq}ԖƬ~Ԝoi^ofom .63|mV+IW<ޜ7WU~m.k(U"9Qq6cbuUC0uhAJԯبrLTTp*x QBN";Ev)SdȮE~{]w%oOCi$ϋ6љB~ԋG5p"px|.+?›ZBJI,:ܢܳN֒.P\(]E6stNxXk 1Q;c7KRK|7/֐@:!TB$}S+]"/&۰:K?EOa-IZ+=KOHϘ'N'|RKBUnP,- 3Z*{A !c+!PjgؒPq%]">x>7Kg cc0! ;lV}UwH{=+ة廈.r8bw9<bwCo?o>$2 L+$r%(G QrA"E9*rTȑc>rKx }iߝ;xc&3|k<&~m?[\,WO}+]%:~ͫyr%\ƞ$Ua6nYMWص=R3U}}>'6 8sqy@{&#8{\=r8ٱp6 gp6 g:MvlCG͍Mmlg8|ٛar&mNOwO[ptWna~fL_3+)7;QWmLWi3q]\ɽu $N@HW!UH*t\WEFEFEFEFEFEFEFE1q];p] ץp] uםu';q݉um{0 endstream endobj 1258 0 obj << /Length 1526 /Filter /FlateDecode >> stream xWKoFW }o`h&hElK6rɏ̾Hь'j@ᒳSً>/G<| ɞ^8 hlsƤS\:n"ۈ|o!e#fQR.y6);3bds[(T:+%x 8`o+v8xN _5_yP2QD/h%R Lv{>p|hȘmYh4V_Tx+1SCsu"))%'vH+OwcC Ҭ']ozg oKe!g{=Yвfa7;VL|V7pOH1aHųp0x:IK"P;2Ȳn1&+ %fJBIHמ'/nR"nҲ"w (QBir*2o = e>[|xȲq J^ۆo )R &,!)^Y!e{ w68 ]Kg{Ji>EƸ!'Ыr '(hؾO@[%dC+BAlDkX {[6Z33aͬRVwZjc<ǿjK'ˇϕJQ-_ Ľ>[|~<ͯ]CA x/bnpi^eVI  T`Gii޷CHM(l!epNۮ^pxlIӁ# ˁhґ(&+>ƝK%~f{\{_x^bj-dEPIѧ@.yw??7H<XRog5aDhTlZ!9&[/SR)i"}Qws<; w܄^URMQIq-ȦPlqB \wm4n-)\_G•nl{ I*?PmkUm[2}@&\Ӡ6_Cb@0 !%?DqQDWv7i lF Ǡ؄AdK  :Kk~ב!yH؂"_DڟLjA{QE"Q> stream xP( endstream endobj 1284 0 obj << /Length 1342 /Filter /FlateDecode >> stream xWMo7WV~/ =iE rp{PVFlK7䒻v:F Tjw3yoC`'Lغ_$z1xn {>K˚?,:aۢ>+0<*6$ɘ\47"lz\B솑%\ JH8ԾҚ)IgY:/"7SBD=.#&>I}^t4kH>1xm1J],G¥ZTDP@ > +bkQ$(Uҫ sټyDLX^dA/\Hr2OҊ5/2nX1D&<ڂ |AU"bg<̻^ `q;I Z*'Vķ$#1y3 B9!mkA@Yq@*C9@^m$H'Dr6`h#%,)af;PjvZZ$Y.kRRs|]$@%6y^6}ek.UK%ghJ⫌*)/dE)9켅$+m%6P.%@|"cӟ4ԴFi+|yO`EI%B[a[ixʎzo./F gWM4 A`ڪCDAklNe i +pɾZ–itcTlkU,vGbGq )Dp ncMΈ}GRYaSE fͤʙ܏T\Y"[6^C%4Κ;Y\P'Hzaq@h>⶷ZawowdRH"ilB$4A;.Kiބ"M =@!>z}GEn$p-˜A!&NP,ӔƸ ÁzkgCST >I=K:>Q{#DE endstream endobj 1288 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1289 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1290 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1291 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1314 0 obj << /Length 1522 /Filter /FlateDecode >> stream xW[o6~ϯ eT^D,m+M t@Oq.C,v;IV7Af&yx7R3v`9 |۹4p?-5[!pJcom @JUi63F#f+iw8o\*($ 3v>Di$J7::]qH~휳ly8Ҙ gLʟvtz&>aa>]xYQ)eBZ=ũrxTZjNgd4DZ 9Xr"qg+}<oG@K>N]AC=@_{;l4-1Sp9]~%Ӟ }.8p?<(l̉9Np?qCҍE2-p%q@ % w)admjO,ΐI> i3DTVZdYd}Hfbqϔ]d>yG^QtŭənL:EX!e>[:$^ðx9~{ kCv|$R^h=y ˠON 'I!O1Fqd[D1|9FW=i*RptH_&HI$`3$5Zk69ejW39-n]iGX5R )mUqcuKJL}δ#Ld+U#E|T\kfe^p8(`2qSD`dz2D}֤(琅>=оY磥f\֋RKU8$ƉpXqVRxqQhoE"lMXN)灈i8a?SJi8jL/VI7|84Rè HbaZ"KQ_@DPUK/ge-k[`z(AdEwPp#}+rh",ϖ>ygyz8 ׸"֌l/|ȸ8p IX]|yCP4M y5cQ#Ws\s=R iGD4$]?1R1nFgmʿ%~0-xXI1j).g]z/z+CmKͷ8" _b&nJSG\_*~-S Y!Spc̸׮ E@/7cQ"*RO{.1b)MmFAS/qMR3f6.B|q[~ǵPEۍMn}ֻQ$nU+/`]r|{ $ˏW"K؏fv endstream endobj 1339 0 obj << /Length 1398 /Filter /FlateDecode >> stream xWIo7WЃf&܇ MR ڃm >cIvaɕd#~یGmcF$Ǎ`@Yo;Ҳ;z[ ҟflH:&etw. hqKj Sv !d;[V * Hl\-oRaŽ!9$I+9X: u#{"K{UxTm*PL:vr f`q.wAVJXV_}6@]ؼPT-S BPWm$!'qF)_7 [~٭$yn)rR!M QW$M gF{d V; -!"l9 .@'6U:{ vmBDU(:a_E1T?/)@!BV &ֶ0e T5ŽpmF~GѓX\BF>MPVTb7|xЊ/` yR bEoZٿϊ$E(b)+ǒTϽ$7VpI%IV"Q> stream xMs}L.3YRd!QTNXiDCcF5\ıʽs{pĵeȁbifD%GhD1kr&bUSL&dQYT0NTTGaJK)URk\2e)U(KXrtڮQN:"=,=\*| i347#ɭ靀eq_)ct(nk0] U2Te RU5JgyNbyj2v/iы_fVDULcZ Qej s R5m18)Tv)qQE؍Um듘U EW&.%L\UL> `R 曬3KAfM$IݢRNn;Y N*.ثyվ,eslV"{x)W''~lvw5w?:z{:Gw!X#_:?ڜnoכ''YtzГv~c:ǨE9_X/ay]Svwr <[nCa~h\͞NN?٩Tynt1V/(R:͘.{n{y6 )/{8/"F@Koov͸G齿WG۷9tӊ DqnhΨX,GĪdT3dDg7#fD3M9r4dɔ)'SNF_eoIK%ҟۚ:ƾ13qneŖPyzD++\KHq/^l\~);$M"I nN>-\db?S$oJAJ$90ER$EIu ktz;(pHg:P' 9i"ɝ>Gwtq@)@#G#n#%rN=$tvǙSAyr|J56>tavnu9;#cnqqE/c;ms ǧכ=6Ǥs`/c~X_]o^5Go?~?ysz}wdI#մͥ;NW&+ʵ)H8lB[f0[6FH)}elW1*F_Ŕ)S.\Lr1bՔŅ61φ\-͆l-φl-͆l-̶0l }IV#8aOc{ǟb'_OZ`0Pv_2[;BYW>> stream xWKoFW}p<4h ֡BK S%A~3 ENܤiTٝ73;K)΄/`SMN<{"YmL IGc\6,] |omLa({#Ũ`x'Jԅv^zW BM]#4) X{i-`{_xb4,rv|f1M}daYUBZ} cVE skJIb Q^#A-M%8 '9|aw [g`IiRґǪ*g[=,1*D\kIxK#9sJ'=;=IRhIa1qK^<}/L̉N}p:p6 #1bH^rt6'uIzGKNk8Yҙ xjJ]Y/'3|W$\ ne)(RNdWSsg[MsS#C|t>C%^+Ll!?ȵex`ϮtG#}7ÆRډV li='Ө?4?\RCa3?g`І_%eUCe5':4dz&&OYKUxA30ӜYG㬈ȿy2a6>U"m; 'x7FQL5%}!>B΁OU!H; Rnf6)o_f$b:!-|Q!1&L\_Y&Z&e]ee_Y9]492CWwxbd 2CmFQ9ktz5շLiS\JƮJe5t똸|XJfNEg!#P TYM`&z$M'4 \綒b:GTHGЈ4)k ;0&ެ6! wwP겥H؁ nƻXOAX!QI<S@Z.m'lMbn_oojTߢ 1]soO|IӼN~?zT> stream xZo7_}vk" (as\K.|g_{%W@ GDqTXy>Etы4ΛKY.MK],UۡUOZlRZ9]-E/#Q9-;+l-[ @ʶJ@ ]yC+Ȓ^9g)J&LϓģjOqټ,S02F[osBi5A5kAb(mm\FPjWC$TKCA!lmoFB-siTIaok[cǶ:P]I ES+z$\ޗB,AɸZl7ڜQnwoOxt "1 NG̑. gkD'ĊFDh&J㨤K $ x92.Y)(+]qda_6J(j2MqDAϘgk#(+JX./e0@hCf]C*X/OdeIQxv Z͔|nky%^%.;b}0VQ/)Pj}÷Tn5/9bJbC?ע)XMX/By0oGn,移lK,v1ۜhھ&Ƃ@XKgMx2F,xMl1hd_8'_s׳BDVbfpk!u4w̪G *jzskoG\ !zϳ覨`k 4TM_3O~ukX%\2954gAqy&p |n<٭T] N|6JtL-Bb|<ixB8 y)czB1 E)&E<@Pd ^"TjXtߥ瘎.H!ꁟ"OS>b]klF$i[KFr.Z`s/; bdcܟvx#OFU .~ vTF{/8O"z}2#GGEޣ|rtL'1&bQ9=+-')h!.>$@ lA-h'KhQLTdk/]QB[v q+Q%X>~8СSџQ+MC IÓ}}wO%< [Ǔ hXoF1c0X>|X&e.D:m.T]o.7ǖP7We l b 苽d ׀,V=ۄ"Jn39º%v|\< ]N߈X`m8"#ƨ1:[ 6xQ1w ^U;9CspIƪ(?b=ato5?7n  endstream endobj 1414 0 obj << /Length 1784 /Filter /FlateDecode >> stream xZs6_>8da@a:Cy]rm\2wq. $@h9ZIMD_XmEl4֫3k]XC櫵~ ERrPuc[Q5dD.>4N8o]+**UH\MoW+i%eM-os!gt?LkT2)gAq"E z]i8;9.1 뫄%' 2QX >dcL!'4|HF]gv@hsJaGR R{9Paܞ~l|Bw1]h]튶oF$$/ |yܑsc'M jkn2pR`u[p7 0ܡN~э98/tƽl1W+‚ {ӀI ZHwaG]) <(d -ʐ*oyCU-q` ;_{v^*"~5Mޚd,yQRКAm M̀5ΓC@uκpd ,Ј0kS^Kmk^ɜSqyF$XK>4/F;bJYzN9W=\CL@lxUd'jD+PUu@;Y<\:Ϙ: QN g!~!@(}&Ӏh| y;]G-];$ŏk0 0uo}_?_Kzi`I +XRd%Ս`I>Fm@˸2C$$F|=$2>D>G`a." yKzGO Gy7cQĈ!0bXC8W60a:sAg@p; 6qdOVo e44 )H5+Mml;S>;f>7n1* endstream endobj 1439 0 obj << /Length 1825 /Filter /FlateDecode >> stream xn7=_1}EH *>Tq-mnO+$UT:gq,A/ ]TC*B6:;ԉ6!.C@8-y2H.s ̈́bM:xxoQ/{qG2B:ДG=Y!RWza5޻`k$XӅɓB,?tb8!/"AK{ $'c5ORTyqA]Oۿ)׆UoZM< *5nOxBY%ɡT W7Pq8Mu{G 1>t6hz?~y)yc*/p?S߄q@ !J+6y\rS]+l^AR_iɫ|qO 04an?>,).Rc|px)iX̒-CC#>Kآ`#E7͎6x x{df\$.$bG4>oڳWDc$r^O>;3&Yx8û ;s½bJ㖸p:sSߴ#z}&9}1볎98N OP+<ݾ$Mz NiUKY83qr8Y]Ŕsqp>,v, #Lv'4NTQP($@  jhtTq mnp|h:"Н4!i$ǃ94HHR*>PAi'KJ54I#ioCdHDIuUg2cSJl[^lM:Xcs0:.炋fЈwGۑYtV,KY?'Mp%|PK5|8_ NsF#jsl1`hgS<Z%d}l80 ##98-r1qCRoZX;o Kn"Joq덡B4x3ZU%^2J CcJެy4(ŗ5W'ak7sԉpр^j[e\hާ$v"ߒ흾 W{q_f$@09'{ﱗD q%XRMh/zn,-1FXh_aU[!_xІSw.sӀ喝=l(zCJka)H2]dA׶YHôFYtˆºQO(|> stream x[MoG W^vg0Nm>5rPl!pH/9^*hkYFta>!9yX91"IϸA0&K!H 9Y (* DѓadSd=H0d{"{BȐsLfP5:cIͯ(4<@DPoDg!5VkvF $gm)HCFPJբBH $ \иh.,@N-z#gi!Lj8!pLW ^M$ ^ 1!#sՈ \ZYAaB5,ʢ.QlZ! Z= *B ACEBVlPBlEKA(T`V ٨ 㧏 Ԫ $ bQfEN3(fch&UR=9,fY@lfj#菵2RpBmk'_-)VYt:?Yh4cO6uڟ_-fJvY,7W4tK|qu&k?...VG/wUKm/f/"6iRRm7mFv(nT7d0rp#ّ#gGΎ9;rvdvdF[ZswgHtݿBז&ǫh}drL[7>HsvL蝒MLN]lvb+]VJ.nLjW6'}QKIC'RBǺ2LΕ)eDcW.Y㘤2 LJp{f9!FFќVKhNb2Nj2}m8Ru4Mt떈. R'`K="#]P˾ҥtC.{ޓByS:IILe.w,]jtݹx:^ ϋXwFBw(Rݍg$.82RF\ʈKLRAn$7Fqё!I-s<$"](Nh@$& hM3+4$j*wiחbp1]L t.Se LA)2p4ͿGEΚ&ip44ͤi&M3iM_iF9  endstream endobj 1465 0 obj << /Length 1844 /Filter /FlateDecode >> stream xZKoGW!_B P9>D"xxmEǧ5;; Lwuw:DlKOߢ ~uLb݂CK]-uҫU: ӹlRVy]sq;po5O;$HQ$Ź0tza>;( 41Ez1DWⰞ}2_+`І,h!D.\lOaɫ‰y1 ,-\|2jk&(j}~ig@uc)p>K ߔy@DZ}xjm +-ς -j(`ǀ^=yF*4N* w%ɳyãR[?lRWtNP7EyjpTq16.|}:U H!xT@k>K[EI)1y1L"Rq .wbUcj7d G sd0.Fc G|@F]\`. #vDhbLaR&Z9˘q~h0c6='{a.N.f4,h.nE[ sZ7# <^~_qQx̂lCƟLq8]E wfA"LNexr1Zv37+Ă {7V\ilŽm\FD/?Ҁ2$`[PxOxG[;n$un.Q58nY%;١XAAfĒ'CkdKer(69Q6ަ Ga1`ڛanMuù9HKr.7NɹC3YajDITUvv%i: ~PO UbZD+4sDl1ʮMOLi;!%UY yx_)|#A~04ktxqd-q `kl. =^.y.F2&!؏׌>iQݕG|-D >8 (񧫡>|$, S|4،\Vafa3.D00R]o! pێ-9D;#uWcsKȃGb>DxQtM)68c{=*{QKfԌظāOĢi]kr&]c1Tm+_6?]r%q3_AJ88q}ӱ ,9a/aqR^S?j_]Vu9uƨ.2)h?'E0t0hiVjT*qG7;t endstream endobj 1489 0 obj << /Length 1796 /Filter /FlateDecode >> stream xZIoFWF,C&hP$Dž$DzҠ@|f!xKv@Λ[-2mIvTӭ7k{|)(S̏UަS&,plsInuS4pVlm_lD n)>t𕲍h'$j.IFMNZ%:~] #u43AT'y F ȸ iS`z:YYim[}Rm8 %JlR<Ղ6](*&TqgvO YozHD}?hcqb0 8*Y ۉh %l ޘKgJ11FC;kkkJNſp8<)9 >FCIBzWl~}!2ue!G%qMvquЃ. 8L>~\4!fAqHBQƳNhƠFx%q⪆ʕQ1Fί&c TWI>o(5^jvİIat.=0Jূど xчUa="w%;8N>;^(3D È}CnXY"q ua'b& tR3'0% ã_MoxJ+q6SbKIs&_gH_ls1k=džLG틿COFAsܡZth l1b5̻#I˔N%!3$E}?p =Ou!)SX;iKTAJ.evW}cusڝhy s\f` oogvToTm;B9ei7kM:P W-wB > td|tF>36)T6͊Iْu'췳S8Msaҗ녨h쑇4F]($zYD'!2НQ)2t]"&1>fҰC0IrwA Qk%݆8WQ$zz:+_eDwoW{)ЄYwޣ#}u/ rbZQj_rZP?Rc:0)CPBSywyBA]^#/~e%CΒJ$QKsV endstream endobj 1515 0 obj << /Length 1669 /Filter /FlateDecode >> stream xXo7 _q :}I-m{X9;Q$ H.ΥIv[tH䏔lwˎg~`!U|fP"[O]qTi֋@.-bbeiZQ9[d]fq.@FL$;g(YJ,촷~8sf ЌyQY,%ZNX`dj F[%q TjA0 Z i[$b28"~ FcqQ\e%'<"blV2CjҿO>:cJX;Ձ<"I?Wxklp-*_`pʜ:Qi ěZpYk~3Js<|5';qp"ŧŐ$ eECHR.qW"AH+m)%8K] &kU$JfT"U\=^3JVDJ23J'={'׍C ƭU /LwDJ(c;W xzR ~qnېuJ;GID$hpT^$ ֔t$8J6J\z||_ 4oU/ڍWm ^  ) I.$xu&Xgqg'u{ ? _tV(RPcR0'{#v"яt  /uH`؂n3X[@ݳj9*XdYVȉ[iC/1f%-ЉqՎ氘M[TGAxe'Αo{\$>lefҤO)ٯ)+> U<;$8mUgC(S*03_VA ^e]FG&Es _S"ٶ֎)Ђd|\ִz0yJhjI>yoLpY8l*{A$+m.Y v4P;V, ݪm@+} [2)m~ FZ3qrF/὏:Bؒ}PckSpq*,(=< =LyˣtՊ^՚шp{DSp <5WЀB6y*Wj0i|A^_Q\(<ۿ?p c;Ǿi[!ޫ_05>B+zDJnT nH~4{/ iS7ʫem˛UUO)'=LU> stream xڍt4ֶ%?F3Ѣ]m(3{%Do!Ak=JDx'}k{?{yƬ'kB(QX>?XP`!~0XMuDu"\1H4J]0,Χph@88 b];T(M労s1Y'+C0 #H%8%Xgq~j+ x v.puGX4aN?vHsE8#@apn(k+SQ?`?^~ȿU N0e :? Pֿ0G s!aV8a w< cFUwʊ(kyŐO銀K:( emkk7g sgP]!Q! J },0PXx,sZTidnߤ)r57\}KҚK>G ,dor1vi3F7K[v豑rTM&z,Q֠\YN fuQ֪K#{).d)Qf:d  =]3-A+Xñ] D3y?7)}4ruiIКg>K$٤%{z"m Me򱖜U l|;3Ls4E8߳xy3kd/WV/>n 1NN_;z I(Kk 7D霉yY2y0\#wSqXunuՋYGh0\5f񽔒8Ǹ,gqtOfTQL7`HϲftZDirE'*^;{V?GIiN=[{b'4ݯgģ~eաлܴ7MM)~7td ^?<",Dh3ʨ³tCEDJ7rrw2-548=7qv2Vc֖tFYZN@TJ%۝}ܥ2+7gJ)tkE;4!gyk|8DB&8V+Zbuk"IDy5T42-~Vغ(rtP#ɹtuvCws;On.Jž=Ϩ9wq, DdA,@T)U3 y1b"WW7~ztF9KWC*ӟLZLW*6,nviSzt.unRp0k<[|kL'cUZڐCy+o ?KEP\v9Rz:EٚhF~Re?C X\I_"XUje(YI檆zm5惬X@bnO{ 1a/7juBiWu6bt^_aFX3{!9;5ǞY hGq OvIykr5v6[%P9XᨏJof -JP ]&!\.YG0^ɉ;)írSU)9uoG!yϻ:63z.}vC* ɛȐp<{Q\=vѨujɓw>>\'0vJQ<,;\f[RM9cɆzIӰʌb?ˊoKv4髬q;(9$l-ŝΚ@qщ3-Q<\>)@DHF9UA7[k?m)Mm?PW<OmmvU{5*xx4/?pNv)mL y&=s0Q Jg/5n6 z"?*%*Z:{12pNWQؾx?iBu}.-Qz/Nu@E{2Qyh{p&߯EYA#my-1P1 5{NlޭV/~ 1'/3en9m/h>z-&U˩|jpXЬH7 /L(1ÌɓX:=ɾ=1Ԙ"QOpܫ{E#OK1>A yGjL0A巪̳YG Hi8}t*=bo\֝q۝$kMLOrٮ3:6tKv0 gNʠ{hVgї4zdAig|q'~:a|v/nF|&ؚ<B%.21Kg! Li0}֍Ȧ(m?36u\||ǵYy̳X2׹wZ)M=FSIXv@+p^}1ʰྜyf?,2!*!UᜈaW=Wyy_SS^(4,̧1 N?h54%VY_Uùj㚃/Jvt=ЪK.]Fr*B\_ϼg9)DEr=^Ѽc1ϊui l P\P֭Psn'Q"<S@y~^mRz 0}ObնiswF3pVw0Ҭ*ɽS'UNu,kF$_>Of};0{͊KW?&L=A;?8jD v@gnq muϛ= $lfsfm(gWĮ*/HJHkL!<,Ë$)h%:S7?.ֹ~O6jZu{)+?ViuۡҒŹwWkdtӓC^k+*VD>f's +C+iO5tt=5R*OL-r_Ͱ}E>R A^mD*a-}omH,#S-no^tkluE^xT`Og:p6Ӏ0f"d>IpSGI^A h.v/^$g q &£ψ QR?0~q/5/b򭟘2^<#'Kc^\`Mnʚ=sU]$%=ܙTʨK8x{: i0(Q{Oa)┄p,Kvo ܝh~v%r0v闽ӥEK6mT6#V!@[)tz֜y]g2 `+ԾGP!&7c_tݽ>wE(iV~*E{t_;bT endstream endobj 1530 0 obj << /Length1 2514 /Length2 16497 /Length3 0 /Length 17960 /Filter /FlateDecode >> stream xڌveTغ%)!K; .]}_1֪s(IEMnL,|15yuuV ; <%Rj/1&nUptȺX\||,,6ttxX@WxJ1G'okK+7 1r3X8Lܬ f&v5G3kyodbb)Hv].@s&c[YRsp4q@;k3+H -OyLoC)9;8x[;X,%Iy&7/7oA;WG)HM"*P͕w̿̀ -`.hotps TyoZl[X;[N݉Y(#) daa5 zY1v `Jomxn.@3̭@Kk?Ad4.^=X~g3sG;?5YKZMYZa:z|Xl.Vn/ )X'8X8xT?@=-EG4] =y1I%A?"d@#ZGR8oQ-[4v\7Z8XFo\1{ʎֿ#+ vt/JUαqrL\\LY@C e-9y0398T .[ `MqE n`x n `2ȃ<(A J 6q PFȃLA &[)AL]Lls?d|r 0A2w3q(  9wvPnT@ZX{o}D,X-_tb VNV@IhHmAշO\*?|P)@I;ȓ_]f?1L.Ay9aL:nG-Yv3;fO8@5ssW̠ Asvwt5 꿪 r]AP nV.@uw3 \]]P;<AA b`yOY@|.G_g n]3_ h0hC}'.7w;-&E\b,q+ =HHxnO[^v&t0tHc|4,?qӾyKP ;b;+A)b?*IA u؄|LCl|Eh8(oG7E w97%)d{jb(ʡ޻b([L pVn$;ekQ2p7ng|Th%}]|45-Ms}z1WOse(>kE[H47ݾ%Hr%<&#j޹@*wO˙OdmaHH6x%oQ/NywVx׎+L'kO{㽶R$L̃?^L;IQ#7!MK7vn@0K+}2_27_y<@M1g&(^dEXt^;b"N8Y/<.EBg};}GZU楟_GHWHZOMWʋڍ<?9 ĸ#1Ӛ*Np3R" \S_@?ڕɭY? 9d_;رv΍/qiAm'U`B6U1Y@3H}Qj!'ZG#m.!o- +]((G5#eoˇI$t6Ay5xLnG ^8PL Yz_>|_ֿ㫤y 1s%u;1юSѵ*LqEjg 6'EoWm_^K9aED0[7:mgUMm:K^0Ye t7@]&#Iɳj]AܲDi:V;/x_6ҕ[32P0/rŽL1bBB?{i=(kjĎ3{u힕Ĭ(]([-|\8ӄrGg4~Ј$?o |X/=SY]yĐm.chw5O͉ʴ`Ej㶃p5K`쳻"ieӺW '7SEn'ey9E4%S}{ deyf7faV3+S Oƪݭ:fanO~=Q2C9"3ઑ'vB 2QC\Bo 5 77 Ng_2]wzHl< Bzh5FzG(]fvk @Z9vd[6Psc0_L6!ki9|f%}@T6A1 ΡZޖY=_2;?ȂI|t㌉LxrBpN_z՗Fr{=&'GtR뇐sC84-{c}`kaeսvlߟr5?FO5-.Z*tQn ?jek<9@g+С}#lpZ7&}f =nTPT 4b[_ ? ]Oջ6D1BFK|\F>{ :/oll1vQ6پ=cV^$$vc " f+J&d' jL,9o1Wj>8\pm./Ն5O$=[vװ 8ku@]jOjtlw^߯lf^:s$|N\HnW8ki5yL~B!麔Q|bz3}=a1OO赁k.fO%){:;<+?͘ˤudv ̡8~4C"E~3Sg:&V/B (98ti ıOԪj;h-E߀m,.Y/nkj-ExP;侾$ ެr|qm "f&q2x'.V>Ge>,Crg_D_G+ r5E[ 8M|ky(a1\jks-gб$ys)av$/ ;ό%1V{d#_$(Bx ]عg%WǸ8(t 6ݦ~}cUa Ud Cbt9pWh:ڴO r1tsަڸ?t7;ujv_S?7M2F}AWv0#@ɕ3{臛姇}EaQy ~UsE+0װ}?Au.þ.:j\;|}_y6ծdН4\#G߹c NQӿ&a]~8 Z1o( >gjЉPT, jF{S]vXmRR;k͂G Yf"&!g)!٫  0s_esn5A[]" Xe/MW[m1e/gO.a'䃍]U!I7*`~Lk7Uғ4gg\Q&Xz̐n< c~nPsu7EN=Es&Wfg'552"|(}8nw/n<'13i,pcމ%@G P'W4&¸SxL|ٵEF ?vk7UsaƻuE˳nš*sjG BOxmOF>_chCxī CU+b'@jz"VBkOfL],#طMi8)o3, U"\[qaCP,-44eGFl XWF@@xc|$n轋t;m4_y+aK҄XlV9I!]2m\Z`rr v=ή ]m$FBѳת$rYVBĕ]0Oݕ-^N@B*>, h I.*.V<;sU$x<38llq䝼g?O޶X8Q3v]UغMYýزÄJq ykL\)CPZEJ֯+hw:ˋi7I!M6s*K$%f:2iZ Y0! ˚F<#R`WHEZju'j5,Vʌ23>TAxfH¬ `&r@źb /#1?4F Em"}1d'#Xң>WpPr8@e$KS&(l6i;5)j:^/XڑCD'93^0ra 觉ċ ivMSr>y@Z UX2ԆAG']Ӎ;9PK>`ex,^ʺqt? CL\F1c=3$"P[i:UQt#gnʧ}c)G0}ouM>1u|N$Ҿ5z]~lcosۅ֟UiBCxGwkǼg@K\G6'j$X¥RCh.N;ni'j<9'_(G3ɐn̹O&thiȁE m8Fz*Ӕi2h&/;.Pu>/OBA}H1Tɬy?x3bWU: t4N+! ID !ᵖ,ƪQa~l\UpUz]MH$B Y첗 lú'}/3va3Ė{i%IX5f9h&ӺL'+`u ysWyQ7Bqˌ$ !TԤ:f?pFj;!cbkHzʖ-IH_WpbwbF|5rA(ez98'6<hyEy K/ /-o%t_MaQ{2uDacb]*'Ï.KTS24'}P(t{Bg} E+Cɝ3 U?Qf!!5SXC0'`:RqTA랓|S~\-Bi Yd1МxeӶ_/K^2Z s/ C!'mcYGW)7=R]ddTU|x^fGb I+8RT7q߹/Η^ހ>?ǓյSuu{'JޝΦgR~iS}gw.} פ3gxw Gjw s#'_Coqq- QƚBr~/lm7w&975ʞ-𤜲ťU"/U?6D~ iu-nĊK AВFоЋzezah#7! c%"K/ !ϫ<pK]: YzqM#N|%.6F>o``ݙ5q>&Vi~.x)jVd{4T45ĭ|3&H-rdc4rhwp KxgrkO_R>1cܧbsM8b.V>Bi_C4XI & `Hyf&ט,݄]hݎn+2~R1 ѬL"GbFωfĿ0X%>w#pz  ݓ)Ǣx-АyC˧nTJ;* )IhoG0qرHBU|6>&DX7{f}if~Bh}Q"qOlH|䓥o⊯#ͭhgc5kl`OeDL˿!+ MtcJ,9쬗2@[7 rH(aO%l緣ڗr&}gi!in;kQ5[K< RzEnÀ[qv31Eg=LQǸX(VO]cii%ᅇ\DBKLI{ p jOlH^y!=zu;|cD]1EὫOzBJ5@"VuޒsfBKG-I {9H|rȝD9=0Gӱw*]Y]ךСUGw!4$G(θo;H"tJα?ĭqNHQĕд5^[u\%%@)=p"HHDz \ 1Q+UAy({F>c/|{jǸ nϠ)zEE=H恁< 핈8:G4&=9u05f#ϵ'^ᘩɚc]F28(2B'&n2Ѿj: =b"F殜M!Q*Z}CHy(oE9OԲicvZLb0%ϊ;Υ0`QPK5w .\wo{ݶ/ :n|7][14 m UiGJJ*m¹ v85o?&7vdb%׋Y4|.ﺼBwm&7JbyR"]0[?яT6d+bG})պg©eUNۚf>^kE$ M-}5>%)Uō9mS'_,gF5*'/I^|&(VPk }0QW_p5uGuٿ<Դ>8ꇟ u]oE _Ie-s +jf3}6m&pC^sf҈$A…|/V az,HQWv ˄@:@⭃!n:X*uh< Igԇ%>+>,Ο/hz [%tg%VYKMA'MmJ*l5;4Ɵlie_8V:h~;`/m,]ʩ HF 'zEUoq :$xUr]m*xmE*{ޛK%gdI?X@DA_mR O)M]>jh 8g]Znerk5Vh?-b#|19W0*@=ၫ|mڠ(;4|O^zfZX3}C6K+]we"VJ cxn>ȗ߸]isZS0F]{ 2 }wנ3f#-xӰTŖ3X}o(pFxjW@ڜU^CZ_DCf$:m`[Fh/ZOИ]'5H^9y״h1XuiK|^Dх{>])ܶ@1 leQ\6[|D\.7]g6)muȑڰM!:W7rܷWB ̘ӊΈFt#Vhn͆Y@T(g `Ћ$#aN/Mgz] hW>>X2b>4ЅhTXz7âjJn-El(?sVƾ[YKKߴtaWez|I4UY=5YI!rgi;u%J |p ?heߓNc&;* UN}hĐ#wjT|emOhq"x,v 'nZNccq"s pC}Et|wxJt2+ͽֱ 2'c$wFSz{(RXr#Rx}/:/(pD٪[|}!S,6Ȅ< u\菟.G?XH36I~,o>:QD sl9;m;UR'xaf1i= gW 46(W@f2(!gi=0l9ϭm775c9>9xn!GRr2*"i)mMzPx/79rUH^(\{?͐r* BDXrm噁Ռ\N)tK'ףgGgB4g2¥jeufi;_o>^pz?9ؐQF;yÜ͌Up27XX2:%_Kh0_~8{#O`(f](5z:ݷɽnj1/޴1^ȴ ؍,󢊢@}w!ū̮x7/Va^-v =X'RB@OXYI߆_ Ρy]|nލIs T6/ץѴqOErbJi #pmfYJtJTtn*7:P Y\6n].SBX3EImD6m-_-Fρ7/C{PثqKzDè^ܚd}bg'_^H ߃{ }%4| h9We (t5-`;LHVJ,ajJ*k<ϼ]5 _V%ubE(b:8d9 B׋mCT:'d}`}uܮj[L7#; XD^7s5ڪnem{m_1W.ޚ$$̱{ґKN\V#'͈/0NB( ~ԝG'{7tV;$UZ):~tti}:T:c1|sC=ĻօIj}9RE)2\+1._dX>wNQȈ K&y }4Ah'+Gu_uiG_rAImDjmsy|0Q>gf<9|30݀I9q_\TmtGl46T4F%ATdܕ9zSKkr "َn)ă9ĦVtC:7}E-s rSUվi?VYپ aĮyMiJ3Gog7=%wJ,ϏNF:D:aAy6v0i-Tv2&q Y?A($EljOJ# _Į~ b_b[&Ƽ-,~}Q CI}#w]U@xqe`5[ x? 7r8 ΈGgsy#&9~0bo(x uv6w&=K}ޮqlN 5HzhHɹJ lu+̲o\pWI_ szrL{Whr3鐲{ʹ6T')(?fQ\Thp0p-F)@#.^wG0:3J\vU<U`4j_q!WZeE֍cjrE) Z.26^g4F8L_jR$,lN1xJ94Y2?".:Z?.*wDF#zr+2% >luBHuVS4F ]&gatf%OSĜDc\ب/EuԨń=nƼ#>1KPuLبo\QS|BfXGFaP+ٯo}es5Wߙ66݀=%I]-@WE 3gpNL6rbx=`{;ZN+2.o$U7%p 0N|IiA-PD©_b9aK ŷDД}eIq'V5Up\43Xl [QvsˁN^Ҥo::6!rVdy.j9dUJi ~8^٪LɭqHaՌ;žQNcͦ Dݾ &lf3O,CSM;MgIN7ł/V+6upՠx^xϨidOJ*UW[mqLUM0ϳz% chHk>-uwɟԄFUAƐNpeqL(L|JipoUu![͆_J610ָ&{$0_Tف+zWq.NkDb,=upDOʴ!`F+*Uqco"wğ!~)Xx7`e,,kKEc1=ž _,O|˱}UIjpI IZgW 0#=q]SjG,o wGȪQQ~{~%y~Gk O_ӤY?,2JX]pǽ8eX,Un^g# ?j-i DeVJG :IsL}o(= di( @ASԃ⪀1F4^4&:SrMIu*}vBmWImL[M +L3`wN4D#<4;nYpj fC:cxy6\֪!A粢Rw$,Oxhy(*9ap(7}"\r|O#Ot駾p/1R*M:WGzFn.-W'J'L IqL" L4C>zM(R L[j+xMŰ>DHWmDzIrfo7?W%Fk;:it[zۼY]Sע+>dܮ/%rʫV0PHɿׄ*P9=m#,=.2qӑY.-3HS CeHGDL9poW搳 4m}nxh@Ƭ QL}o#HMWgt˥.N`K RIVMքXXFO JWfm(=V)0g^,Ae-5\}0:"F;G)XB3 xA)oLy5G&`ER|Bxub8>IaPBz$"Ƽ"4h7膠DZ~2d@ X5Bha3!E EX\;A)k󷹤a鳟z>E &i+bwn*eĠh[D lh yGX 0qaY931  Iwn*2œ̈́ȿXg]8z e@.:U1?ɗyR M |T|+"!?dTE~tJF3JL&PA08]‰drj x-[? /Zto.V5f3{^kO`|5وCۄ zlT=y"[sZ>QAƜ;i^klBcOɆRG@pITa?~ QIsMPʋk9KD^K&1}>V5xW:3toHv>xb{?ZIo$b?f2S˄(QӘ˪*o[ JA]_5[x.bu?#K OYGP%' #6|$Cv }KtTao!̰FRn!#` r<{칗Xgz݅:K B+*4h 4}DzJڙLJR`BT}zDtFnX(~,ܾ)%`/*fV!/Axͻq7$m+;~ *t2lܷiY5m[T% HBO!e-]+ UO fL8ʤBQ1ǵ`J\ B:BǥjLNrZ@`cs~(drq.^Nv}Nw'-[8i_ST/65/_-(N xBRD30*> stream xڍP.ݵE[w ZX)P\Jqwww)zӽ9?sd&zz &%( vtcbH)kjrq89y99Q@nQt. R.@37L b v(x\\œnNN]f K2;@tE;ym y``p p,fn6@HF 3{&t6nnNf`kq&V'tx-(TPcGhـ\Vh<\dtt;Z]My%oc X4o9lfavp2s9Z@@+򗡙+oa73U@VB`a?W ++G_a mq;8\Q~' rZ@9=}@VhX;qh;݁@D(e@7'' ' zYpJKK vXAhAV@S ` pA(C@1]@^CNq8}}2L%_G!`//? $$w53?e*h]-M`g?K \ qqZ@/!:[_zƿ ?z3?uw,2 k {s wʻAAF\eA^@K5\צكj`WЯ?:zYAWPBS8Z-7?2K||_.>Zc# X]P~)?Co$H!/pJ C7C7phF:F|$ſC //o_B~_;/vwIg;96N6@?, 2jB:U#2r ~PCjw:A@+RbHN6 !G[ ,]A7  ? @7? ׶X@uAV?7@[քVKzm !F%D(!fw4 HU>6G||;eԑ"%ӳ!yʖHa &H>IT'453dHҝ~٩.zlu1:8RH$rZ`bh~akk<Āo$[bzoƧXZۓs^U_K@3?1K+$ߵ$.h]٩Q_-`It)cHLbOpsM5)؃"] E8~ѱ708V;p[|ԕ2˩~k>Xm ?vHR )hCS*CtwwtdB{ |Ю 0z3+Db4hddm&e/`}Pɹ-n}HLrG{T|2:`9xxmzEr:ͬ%ΐiz @)،0Tc6d ~,Iv=sz??KP52ݙ[-JeWΞΛHxcd&:S@.OL=oJTBJGp!IK,N6FRJ}mU瞻l]Y[ؾʀ0E~N؛ Hc43|RaM3LOP`}&zs}n~׽Ґ5HQgRaPTq=Tsȧ/ uvG?X j׻"!:_=zXY$M|qRxIFD!ĭ.,p͏WgkE bfL`_bCqXg>&'n#zA7 ć?\OkvuBQ`^9N>syfi"]=ls`%E/IꝊHB8UU (g>0ҎH1͙h۔l"dYNhE]SD|~OBFlω,llN߂k<&F{aOɯK2٩? s= [k%e@16Ux;JxkR "֓Hf_ra""K,JStHJ>~D=ҬHݮ:^eĖyS"Ck> sИMElO 2\~'lVT &?|YScf8Q,׊_;uIyC d ^]_  /ZJ$o?1>pF C$]\dI [{QuưV #9Pc3l3 MKb1;o%P#ymYǿ z(rR\~<Yw)o"Cb0ϔOۍ?)#Z>sA+D~!L55[Ż9o&!g."tw]%u.Iu4\  !z廌' z'j9 ,7t`8^ I_4^?|Jj nBzoGl4zAs-[xSkݾ﫪 2 mV*YFI<Otiu$Vz̙Z.^BTNpH03bq0:荙*_l{wcd2V0)itsA!uU1H&U_x^^8y.Y> Y /Nl+ҜawC3+b8Y'P% \@NvKkV`'5[abjN1Lފ`JbpXtxѿGs!G5teP@~~d*h·-zrs'Xo `^ԋ(Ȣ^ݸ |\4pݢVQ k1]m00.$,u|ʄ^{ߝұWr}}r[_chP|-.U5I޾y=V\S..jl9뵄i F?;FѭV,67hzKT7s2T6M+[puEޓGС^W4-}V9G!/_>uЮXWΆt9$ozNQ/0f(6]hlL"f':ig$%]DE݊X#,@2ҏCsn;XwF i.J`3&" ^u6 "q0qijcAYT0 tsxTUvׄ'-!{?оj [=O4SH;4IT6cLߎq瘚PP>ѮqtO Kv diX?:]V8ݕ;j%ݶNR;B4LmMƉ?Ώvr lSܤ'L< ŝ5]+Nwv:+ţT-pAX|8Ya/Y[1EҨOV``™S6@d (ߎ# H|[!]N$LjUz+[FrD:;lBjbl07*~'g^~@ kȒX( 2LtV2.Jzl\'_83,fcg=T*WNฝͽ’zG,s^, 4kjٽ.ƻ4H[}D{Hf/#.)=e@(3{Yɺ6u<.}8c Nܑ8eR~Ëc}lZãxbxV oc6'M젮x]De GSkodr`%6o1o Lkfajw# hE.͟-><.)J);3$ KlÁ(ܑqG*hF&bŃN4xmQg8lN0u|$%I4m6. $:Uėjʻb|AHlUcmT?_ljZE߳..wN5gYg˳=|5ZڒڤxBRNIUԸzVpWmD?>8[?;/ad\xǩ,&Zy~#y7c^'JhzؑߑX h|7 _Zo "Y,K ؓsAUȎ^W1r w~A;aNBʀ'e"]5sk$e."]@aFжaW7#+ j>1 5=U{>'N#엟!~0vb{EeY:M9^|fh1344s#H#,r- dS o(4q_-h4xrm nW&QrܡW'w$J?UzЬg;֛6w;.-.OyDJEoޡkHmݮy_;8޳J!"{&}`Ƶ0Dʋ4a<`gi/9euozN܌bWt&;8m|2 3蘜ݽ3x ڋk佈^5pkRv:Z)*%H@Y  ΕB!] ԲDQmδQ sWOҋ;ŒMs8si% z 8T|&<,Ad=Jҵo(o)[;n[fi0"<7F_7$V//IYfX8 #Qmav)9w}Q#j81&*\ygRX8-}e͊cƮYf%|h \NFdNkwJ lؑNqOa?br;mdpw E_*n| q:4npF_@`M g*1-R'nʳ>0nJ0&wys!3 7R.p1[Y-FZi׏+'đ2k_VG].>mE0y\"(G ;!E!kIކɸxu4цkd"0oǀS5JSs.r9QkO+ގCy٦`0bBDت$ I(~8v>+YȥHWQAqپSZZ%_< e2f^uJ΋W^)`e*o=;gkf{9}{jkև?(&"WV9ޒR0~t(g'> Gi QtTB-+hhpM/D+UnsPʊ nkx|Y9l.xhrǵ ƙս8^)C|jрeq)7ܪ.Z,Uhj^B.+Rz=D,|SGH8d^|o}#~hN:?j=oDJZ 5HZ@Or$C :(m(cT瀤#yml SZ"g6|-uڰC">u2v7 *[J.u=hIےFkG7NhxHg\7L!΍>w-ϾƆQE=i,=*HWeu=MORҋ1WMsU rk ͎N(=u)4omr>#h⻌ݶv^hnR F֥]Q__:>]&j?ҬpiE7c既,wk%<&T:0D$2- nr5~@wn[e-JQ >}QW3=&,tB%KA5"}cZb2+ySrYQ;:cپo+ NDΖ{;K-ܸc7O{YTLf3qY2$(uVӦB7tR r'HfDl6Lh[^e4ҜԪITMxueϫ8J-rś6VfCxʫ JSkˣuʔKy:ي%L7%~eMX50XlNцC!&<vx5Wo{dgF<W0,^ˑ6 =[?c)ف8kst9vd5.>ns=ȭԸ@nȑUΪֆJxP(Ɓhg#7L+\ԺiE7d) a"-M*;n([X~`^yP6[SLyL^ W@xOMwݓz};Ir;^JXȰ6m]Iؔ>C/N#ir} UĜ|Yɬb4v\/mMJ/F W2qCѲP+kװ-JN͝ R(}Tax]T44PlzFSUН)>_ZŊǬ bQ %\ﱝ8,&q_̝W1 df)w$'>a3J%W\]TEmi_̔qP rG">Ļ2d]Ɲ\\S lA] g" XH~2@A;{ n(GfTP U!UnM4*FK]6vwͩ۹h>"q4-.;K74u!*<,.a ȠKޥ-aFw)Nva۬dvu8Cz6sF5 ⚒nMy'c䣾2i]T*>7I6Gz7OʹUG+`HƦ)gJ&/ޟ2TMܯcs Ū={MXl jb^^ /Z~PU7<]] ܙɆI_TH nF5=&1|9YM>jfFc,fb0?zlgPMgc$K  T%Р.'wuKoUӪf^ iU |HoviRVPÑ/"4zn$c[u =>GGm Ifˮ45].SŎu 9gay(;2f&}$I^s8/YFwXVvat9mi;L(C(NU= gR&8'o%#瘰%DbZd>I/x 'n#BGF=%h4B{&ӔS!µށ+9XVS"]yGCgڲ-Wiao;$E:ޮ}JRi$@ py# @;&8U Gt!0~61ȷZQ#n2qq@Sj$'Ahez˺Iө%c,Xg[v/`#4 n/Q/Beio@ts/iPr$ ? pOx\R xDTIEڙT Β68st/׌]EVq `|5rH[P!a4Ris^,2#IYiA5 3<ֺ7Щ;Pg+[>V?]n I0)ATF:u #yɧ[ߺby_6_<_3sΨXNE٪S'mp' ƻ"='Exڰm!'0[TG[jծћgswny Nx$ؼmNvKK)YZY/.{˰y"C&6=B\X3!n {~ւ,./?K&Z'3o(o"/S}A۞QYN z#^6PlDv=2B۫9 9a֢t4E o5{cvs0z4YFGq嫶b1;<RO763.]/? hTD x6Pƾl8H| Q& :גL(@/G@9heUbؿzn>&ռӉpsNҼ j^]S'K-BSa*zp+}X@9t[x+[^y} ]wsA9 nE#mhx\(#[҆`̷z;t[SG-ά.d}o&bwp=G}vE(ުw02scn~4~l_Y/1=%RS<-cjOfw )omkQׄp#.H%z|X,0(ؠ?i 셿O,, gAB9t&z{>> stream xڍP -.ݥ,K)R܋KnSŵH)vL\uu? 5MqK9H.TsshAQht@.`. T&t)C .  ;;]?Al Pf(@A(4'o4 >  t9@3Z 0B ۸9 yzz\Y!." O @ rYjt+ @\b t{h r@4N 1` +og vXAU%V7/7f/C+P+d@hjvrseu"_a,K;ZJB@n('vY@ifd!+_MX;i;AR@E(e 7;;;?; yYذ^ o1_' l=@7wE(Kd vD*YCgO8{6|T5%Ԙ: `r7o} =T Щ;o6 w{@Сuw.2T*,W+.iʀ@j`7 _[fvA\]+vp*ts7]\(C"/t-A^1u@XA\P:QX%$~#>o`lE|6߈&q~#.o `Sٕ~#hv]7fW/fW4~#h>O7AFEP/fZ@7и@b#Tg$IH6? ɠ׀%t46KP@ r=H?76bà x;ـ@h+@(v@h?ˇr@9#2Re sPCq:A{ 4rs+uvE:Ao*2dG|7!w{!_Bn〲P zٸ8&h+n?$$zEx1Po? 4J說|@.Kʚ߯ @(K ۺ5Ğ,HKP'43D0Kҝګ^g pp|H!v8ҧt7Šq1Lsגמ|JEyoƦ e r]+VV"QM$KRhv๑,/ZBXp10` w=MuSzO\ Re<ңlMf|Uq,5(7U"m1*O( )UԨ tRΖY,cwRtea%0T13=1$[RCfφ,c+Z? wu6S2t0x!Tj<.=O<+^*n`ndK]V… +͋|Q٢k;1X\_ż[$rZ9VJOkk> YYt>qySf{Mj j.Uܛ@»hSC՗ C,~ +t]Ny{/wiV>=s$먖Nێ /Z SbpgD3!(륭U߸1d3,iy T#wboh$pGMKAaeku$jʝ2o0lZ#WY:U|d+ VHԧG>k'!"_Y$frBm džLc|Ca֣V¤"[ʢ}yΛp>0*R!3 <wسl.:osvų +V+ 2DxpUv w5F OOy_ȆZ^{ӵ< QuwQq^ݢ%7!I8kTY6>@,t%,E|`s!NX{hMqIdKQH.l„c}?q"~a.~SSk@՚ ̰|IVׯyKHV_WY_3O`.ڬT8ʘ6M"|ox./)e1AF wfCe#O ~$RҪ;rdBI<3%U] 9DIEd8{KDxU' !h\Muv6|gzܚih?'S1p3}dXahpY +‚٠:U5CԞDG|c5F&lG,)M@oi jU/(r34ޟVxMAv̩kz ,s4!@!ж75 2*j3PkΪͼjHT)a$z ex1d˱ܣX~1[HV; ڑ (拂^ZYys>rʸ<tk{a:/Dd=eG3nLfV;:`=&mכh-:wX@􎚌 G j\o4.=B],Ȕ BNb-^=YKt$%NFM@c SԲX09ˣ}y :bۓQb0x9`KY[%ۢ)Ja1:*KGzUflnnXs 礃w!Bg;<6Zy*!"=17Cg}!M(u{+}_\i'|ŴY͑, a5j*bR+Ce~Z0LSclp$zi="Gn2 q7r8銌aA(^R?^MHȷ Y` Bf]Rl&+V,X)S6rI"x+oOӣyT^hRt/\S}ɼ @ Z;yhopbrjPbJ"'`Xl\WYxbp:1/cmn[ExE1dS雠JCm{^k]Qwܥ9ҝqչ}]G7_U(|c,5N xk2zZ4]\։ vuAЭGCkWBK3ltV͵ǟ&N $rJcTpպ|6A>!ҁ,4gICJZ|2<է bbbAU1xK %C[B3鍻Z!:N_b'VSk'ffۡT m!iїIvbhJk_ES tHz!KW5;~`6EFssUf+ |  J_rlPV֓qu[>GD/b`&#v|vfÉFCG-"u ([FYp|98AIX?!stǒ]dLX" 3*,V橿ۡDb^i|2QK:m7o^?L/|HRAQ-4K@ICv M^Z-}i 2G {tyfnOĵ)l@ɦF c'6D#Jlmu> w42@|+wYSy:#۱BR}<\,=1%0[NTsMXpsl-OG[>>U}Yĕјpt`ũ.=4DP_cSW"Ccِ*5l\֛$SDЙAOw{Q%xtE )+7{susdeQweyrQBxXIJf+)X#|6n1Z?a1MHDp /.jDߕ kl2|d}2♫˅:E؋ pitB/KC hř c29Emn5Zi3h26:y^Xo*ǖb཈qd1m`*LK*^o*H~Cz4/#);cq^6/u"%NjSbܨp[/3W݅cTF+ġn8X*2y [XqZ*,)x&5KIi&'.e[پ@L>/or54<'ZANK?@fVnC~~R/oa\U@zFbŊ[{ =b.Y%D}%=|.@֢ɵ찆-#}5+b狁sե'FA DB_XVqvd3”>X~`{lZan6YU lbY{C|yj uQhml(6. kv0r^q69F#\$səпfQ%)+}":ۧ$0d4AS8VL8o>NJ]8L_Bb<"W"{m@4O(b/#a$X1Be=Vnr bj,e-b,&U=b{"(:UN8ҶL@v. :jE*y堫̢%k%8n;>ÓĸwڱŜ-^^n6cCx)ZvXÌ5 P0Hv HI*U=i X˙Lxg.RIww~ mح̻=)C0)"=W *]Ǚd#ٓFŢa^QHxn_h沄@(< )Y)R['[.99i<.0ߦ`>JAFZb V/EYq6͞#[[r K<5n3H뤯 =ߺ%}yn(fc/,Qnܫ2!`n%$L8dx?f=bD$0g+fcn7G%|1M"N.`pj,WZ %\œFIԱBīVfFU\z$"9΂D!C~Zf$zV/:'enSOuf}sd^Sb6o 8 HMY"XzTO*Կ {U(yȝٚ{JZZ $0K4QK[dEPWLAD}U:r^89Y]8#u$λ^JWK7r} vTj/{⫍T5VkЂ(es{8u?İ K9 } I1讏Y.sݹ]#˵# g2wkENyƞk80ݜٖVΗۂtދ,(+9x!`GFP D+Iׄ~5"@NHKxqgw~_eq2Fx|(gnƦ/a.kЗVؾ5#6Q۝j9H,/%P#2 0FE_W@ kn #Qʮ oHّg٩ QqDSaΪm~1E5op{4;J\CvaFB݁]d*&maї1:ytL8ܨs8~mٶl*[-U7; OvB}Xz$8~|-xDmz3G+Lݥ}jR]Cn; ²ʗB捷S$k*Nכ">a>xC* }L0X/P{aA})?cYK [K_.dW_D=C-t9aH.=!jA{S /Dz=(?lDyqtaء8he؅ݹ[8Ra15 N( Wr1S#ۻ6Wz.!8" ;[Ft:ǧ'c'VFO/]iȷP8q;EK0bȽ^n$֎ݐ{}d+ypofkeAFx--B>a>+I$U0k3/5PIfDxF v/ qlOc}pK;Zn|(x5r/gZiI"+rX^Z;tr l 5^Ԃ( ~bliHX'[1s!˄ރf,i]3 luk|grE#gxcӪ ӆ[G=Ǚ/i"k@KGòfuђ!\?%e>znz]AقYu(қ#qZXFMרa<:8t#Fz1p%3<:!,_>8?jMQfʾ#8,UxDğոӌqdu@V4Nspx|tE.TwΛ>'b~W+DyJR+rfFMrܪc2dE]&#b ݾ_")\9w/|6ͰA@5)D/~* \+b"&IXod2ϓ/eXN|rfOy~s2ߗ?W}u[IQ GeF{Ͷ=Y흔:Fb E#3f"nl]xUx z_sAVAԾZJ"o.+I|0( ڮY'LS%ky /Lg}}뒉{aNo)!k4=̫' B͓yIN!&'"Rdq@v|  cer)B墉oS:5f D, Io(<Br_=sạsa4/2oӇ˟+~,N~sTbMJG}fXv]cmXQј~ݪBP+WgՌl$q* У-dsW wclq}l/rO7iߪj؍-'bd.E <K{1ydq9[kAXBKdK'ǗB@"dmo-ryhI }% =UNe*Ɋ {ߚ vg. ?ab%J|udـST$-\ x'+0I~#"1w~U9S|aH9j^#U)f:,_ vVv9r sO1%-o܊ eZ߿yN7}у{kͪh{6*N;$=zP8-ZqFqé:TQvaNMzgɕ*GND++!zZЧM>Qm(;~uk7PQ0&vѪ3[i w=Br4V]WM!F jxn+s,=y"3$i0|CӨw]\Fd h |f۠3fc=Qf\Kԩ=DioT[%HMnaO?Ϻ%>]31LloCs#L8,EN5|mϢc", F|%twhCPZDF_a/B9N9sFfaaBu _& 1LeUikoe|rm~~Eq]O)_Q[ODEScXozk*""tRޠ&idDz(8"!j^cgzO0;eklEڀu^&ZwXw؏H= ToʘzOu5:` &ԃmOJh8_zRX*m2'@?yUYJ@lP_RãB#aBȎ^}\4#2-EnAVRi!ۑ0/^OMsd_7q,.Itc(=7,*C9(¥VZh5Q9erNÊm 2Els7>/ jہWh j4ɠ%ä$9E*>5?$}х<"<@8_Ci7xc޵Z=ZoO׵R MxtshYx΁Y8* JPYo&MwŘ(VCef|c1iW+"94>?G+`ME>F ZAښAi@څ^K=rC_g?fkVaκlۄ~_7 :IEƜ+5Фt'Q;<-~Xsr2`2\aަ<fK` %5zHÜ+PΎުwo=vn{;{sO`OY57m.qf._i~2]a֏x-JQ $ Ozcu <8]I}`263ԴeX$h#U}byM@dl/Uau#u|YƳ>)WʄsE$|̽J 0^b62?)f^rfq.].BCk=/'˲80{&o;5FCTz?.$x;[JF|>[l6S~F _ˎtd,ygg2F\];d2!ZVoIr8Z\34="y '~NOtM In!{wj+'*(m;(IQo%~5i+:< &֜┊ AnU^41nɂi Ƶ@`| `q6CRp8rx}ˠtQVT4Dvlj˺Mˠzv>5(qPr)ef<ÄB>/P: 'mDㄩk%Γ7ߍz]`Xh 븒s4Nb4 D~:Q+{Rim<NJO5ך{6.ScQ>@Z읩Fd#*%@ C jw/0c`U~I:$l"2vis3&tRXn{9$8+A:J'pLEloݮ%9js%IZ_pg'J‡LSk#:m5V'+Z?dZsp;ș4]'NdFoJf~^cCy΢h m;##[`+\-galaAF'D,tSԤjH5,+mR3qCtVHHH}bQCnǼ4x)EJI90 [Y3*( &5>,bg W\NBJ;b#w\xsN3ÍZgr/!f\%tEֳf2>9@h2y+;5z%r"n&(+è1 1}=將o^[aMuzP:HAOfT.zv!p$ZTqj)l)@\u3kn|vhoo5_\ ugnqw^A1ǣox+NUEN [`'O%j 74|XmBJ1!*kO+syvc+n"#/K2> D1g[턢]”GhS?̯Vk%m^'&v`=DNcRl8=Cb /A[egʪ@ gu!$}y FWҞֶd@gG9{ s>?N90c7zMM$шH;XÌkIj39c^F]q-b1 YjPD!epJ#7I\+p/tVk~h]:?" A2-xe)# J(B3A!a'c,l'\'ªoUƋz0D%!x D,O-;z0Ki2e&EuTҶ0Y9w%[?_6M>"yXuЁp[!,͌j<|dx6rv [6(XrR\f0r؅*oFu5Ɣ,#p8R{ 5kWpj N?R2!?zimg\B^*X``-󥖛pcs0D<|X7lqqޯ׃T `p7;SYoDJ]f=nF]XTU%l3/!wc\E2q endstream endobj 1536 0 obj << /Length1 1762 /Length2 9331 /Length3 0 /Length 10434 /Filter /FlateDecode >> stream xڍteX. ݂t!  50 -)ݝJtHRH H\tﳷ><3~ ZV0 ,  T$A@ rc30hC= +$G #m`=UPtsx ~a0C`w@sb3HP[}0[@BB8P#l!--%lga..N+' n#"lWb56@g8Nl-/C%> h)(Ԝ!N">O%:[ZN^P'5PUDx"`'_D+>:- d%4uFrB~M+A8YI!NW_IC`N>bkQܜt.nY&m6 ҖWm/go'~_g3~/r vp7ϟF  jX@lNf7C[zK}grgV0'/KPYVퟡqKJ<> 7 Τ N0_ ߟv{ s7`wፁ|@/m, =ɺ98f01P9;솸׃ ^NKՃ%cI{UH88sPWY'Jki szf |:J\7 r/.)d 7n>~{a_=i.N'>p?/u._HA.}_$ ,A\?}Z?}M? /wm6?}+{mp{G.ؿ֜] ?W~xp7}Zo_XbN,E[/HPxpl>C;H-6DL$jd)UdMU%].r4xqnXOߝ!N9&hF*K."SEv`[j1`I`|JV@1UͫlǔBW5,7N0:ƽ\6HSͤSzvph`aUgT{PCJi^׺ 7yeD>rwz+ggzeiwja&ptv\+R+2lypi}F&:#Jxn]4~mk[zy( E|1oٵ3S%4#C=7GP5o' dԙ_jS3.8ZXIE4僦WkkṂ;pۦv T Q(|U~ As7Ԝfދ(;9y^`iO`& r!:7ډ7p[},qwW,}~{.z,qA/Jmٲ[ifxq1ϽBz4_f‹|xNcib{~~'6L>|u-ǡzen͏2I*Be.jJ+.38q=(Qs]n߈]rX9Αt &/u&RD݉n$4@"_:OB٬UBUQ(ckIU9uF!)pݥ)L<<7eϜ3=[2m -}ʮTu& ?Bp"./0Ta\dT3eNwY#i1YY ])&M?0/p]fؗ6p9y)UHjCz@F:Y O?bD\5.9?+kTK܍ Rs(Rgh h#ܹ<6bإ"D!4mPmUK )Wts7VW8c ,%nG6N'Q2`*fύNCsC߅u5xӌ x!Q[Kk:˿MMx}2oepgg͍~׸O!dsUuy?ѩkUx\KR3Q'dU򺪫X }OT)aqfȩtK^a\VgԢ$_K5' =&Q3p63PKe}%r[v &$ިRZ7 ϲn?T[G-t|_l%{}IzMC_t˔҆<{cYoЅAXpjMSIvf\v/Cx#"̋r_#V"xmU<@+ l~epz.]&uwX'VAaPk*,[A~8&U]irU\EPNUJSܡcωݫBhӆ-*vDN+(83ig FYiɲe}Jg[>U]ܒqN+LD$AǼW-L;&oe;TTJ*DOo%}}m=ɝםӧѣ]vk54vG1T>nx.ت(M zd " 6Z*3I2pofV,mH&,M }7{Taؐ[rMLX▏-m*'L$,iOkj 'LI{6ؠ&\UGH@=s[[= ˟j5d,c4 !=\AX7BKb<5'gOP8)Xe"́.CMRM@-~9 1r#$@yBs*ЋΓ>HN4{s{!şx]9t3e6!ic(^+㏨y3#CVsgW{fz!,)tI^ȵ=4d<ݿM]eR|YL35XJU&y-+2FVQJ3T=R,_u}@T.Kк| ՠ()< Hi2BJ_$-[݇1G-s7U'#.RO)GϸG}Ԑvǀ8wI|cp&2^{Aj.XÒbѭoޅrUӾS 'qn6_elLJyh;|*,C4{[Yj'. J{8JH +5U$*ԺkzS{|ButRMWK!K{gfag"6|ke/>^6sl?)O1|o!eb۲T\v-Q .~U rܠ=5ÿeq4`% \r.ΊMɞ<_n9OʭhMx|+l@g,V߻ S0̈́Īo..2 T&-ìU8-/]^NKԶnj#-lFyN*98kDzo3fI%q(~B۔3Kрpqk:sWI\JE#[OS Od#lkx%ؗ9ǚlv19Kз 9$2NsZsA ¦DI J#2I 집*;ķ,ڼ2ǀ,==S5y'IBώSʇS1 >f;KFE:bfh]ћ"PefJ˳I#4UrW#6^s݁#]-|j@0e菍iǽTY&;'jYbc(ON(h^iAҌezloɌZ+D C& on<{Lf2 |kO|Ήlߨcq$X0vR\&A;3&?igd g=\cofyKU-PE_%Nf 6nqu;Իωo*@)BS1 ՍB"g]2~j7 ^^a8ø)1l9;[6c۷15MK9׶|n-ޟ?'>$lmf [ 'מLzRk YIËfU^)~F5l: UMؾ[Xu^ #m?|[Ϩdz$6*l=qj|?C#xBg,^l0L{trJͯL5HxZgxWOxq{L^ v`q|Ҭ7-4*w׮( ./d sXxsoS?f-\V/ Y.>O]tV;,(_ݰK=@f ԉ0׈֭v&y짒7sDF{Iz{4Hd(wV&0Tʅ/ԝ"az+6DUƔGŦ$p9;wX|"I2*uQ( anrҙݓ-H)ӠajpQN)٘Jc&4Ef6h pz$?%LJC4z/n̴y2$l0)%2A@@ A$wOzv%l’#*12`NB-imfAyiwwQ$T; zE J! fQO.%aJG!ƆNp>8|tӞ1ϳ vVlu,3zjFVvWz,I˖U`"AXHd9z])o80ڥ{ˈYoo3-[ޓ nmzzCp2Z9mJ9gu{ڷASFY4^?q{[98%A5=^4~!>d9~*nng]n: Z#7K`;wGK0m8xi| C̠jF;";r?>Q6xH `PyAq΁u 2z AF_f=݊:[RR #sq>Jx⮅zi+K*y8 ^51^K39͎v}JxNMu8T<\?M*%prhQ!x܇ڔ)Mr@6Wu߃vJ׵YZDǛÐ2(1W9oѻrf}}tƤXg_IkC*R^3K!IG,HܘxwE9,wvU_ៃ3ߔjqJ|_FP mx蝊{xJTX-NTWFLYUL:ynHթ7oύK Qx>di4|*nm}fBI&nU{n߹@& {wsrtކo:ş1"%{;xUp>@ux8Ui5 v#+gdZanLձc+Fv^YVfa㓙hRy KUN[vZ+g{aSylSK0ט:p)\86OkT[5E˰OCfUsw 5#tsEbFU GLf0̈8$XGdj)%͘h^$] r1o6\bZ4ћR7PID?J4$ <&XB8?cYN3Vem #*kIJB92yvZ(L7DMyM-0qq;%3cU2sG|f2TP _Ax{0vE VLbtmw?$ hg~_bH4n+6j՛Eq&O3vSbSʮ;ڇLYXm(D=Rl ww טLß(O(S08̛ǚF!q~JUJ(b)7>;%gԬnL^=YE|4P1rpn0 pMq`eͷ6L` o\v+¼ѡ]BIhi_BDD{_ꈛb Eu^)4AwMlL\U/lr$A*kgg7"^"UuYZi ҏr^ɾݎz}ODs((b=>6$Q}[/=Zdr¹߱c*3( %tpSKWz3L\ !Rg Bv#] 32>$Xf/bϘQxrγ&qr;tw0F%($3ԗ&sV]y'7/Z[?=OùW{4A&)5zݹ7q\eA}\*@dC'o%֠R㹩%L瓾8x`'qI7*0NCOkBAzg`\?.IЌeja (A=?jײavc(Akl$'Bqf AK@BXيOi\G+G6k쩊3A]ص>=x'QsvzYOK%T.Ψchm0R -,)?Ó)u.7!٫<칕pNz1ne AV9x 5WDŽ*&^M0a'bu^1Hޝ'v"{"}<|}nʷ\gH+,}! 6 uTJZ ZA:T/呍gXi_VyG[+|Q~3wnF}H*l /[p+Vx~!e+uLIj?mg3VJd酷 =oѐlwx@X BYWE40) No.ֆk`qX<n0{@s]ɯ=mnSmPVӖ`˙c,Tc9~5]7`AX1R{ @{'۶bءgyqqB@]27]0X?Q*"C^ɥelZ.C+XafUGl_[Jss,.:^ iƜ UN˞ | endstream endobj 1538 0 obj << /Length1 1504 /Length2 7197 /Length3 0 /Length 8202 /Filter /FlateDecode >> stream xڍw8ڢ6UUػjŪ JBĪ=jVYF)j+5jڛ֮]ssj4z[@^8"_/Hk7U? ( y7 y @to nH$z+_mzB!qD"ġ*Rփ{u@G!?@9>Kab1^'3cZ<6whUu96qRP%xްc95>8q=FA,x C.n] kUdCbfmO(,iuWYb_F3J~8{T]=KI E }_^B62};ZMWˢW|XyF#EPĮIϡZpK8vSk.ȴo,n,MEK";>d]jW+M͡0;g}Zq3De=S.Y\񁩶PCj΄z SZxd֛SKQT}%. U֖s fL̫O!K x(A'ag=.#ܥWнEyFAr`6Q7+ ү=,kUOOe % 9"kOsH"Įv Ir`A4X'D;M1p$yGU 9qID<4=U9͑VG!Y,8AZ5*;Ȇw'&r:8 z֮o${es IT ҘO26,so֏ʁڡ4)CP fb鴍Dt66-!-i?zQPCC>1X=>Uw{YZw9AU/ert:GiVZ?twXI]i;e]PsR|,^鵠J\x\1"n(t}lJ.T_[R?BfH[2OE@5ycA{Qj\4US,ԶVDdz/Y^"S+cR4힅ܞ&D /wh2zrj~)ڸn~,$܀a9dF$eE}Ul%4~s=<ˌZygfsC8xdISdEQ鶮ձ L:A?%Mu ƛ22 5˦ǗZ+Cj Cδۨ~nLxXÄNZtZ1NrH^Q֋!qOjD*sRZ2y`tX R dV3^)vg:LuGA2^eSύC87]nn ɿ52;e ğz;,( L[ }1}W(@ZsmE;6 >FQYkV8@ +NdbM&Z h8ЏqUKj?|_6:S)c+ Q?TN2*$UNj=иS(ԳõZyе/vYa.Ok\qSShLAkR/G~;_e"2N˓LU(/w-hs=QRZ\ Wrc6pËCoc* (䥙 []7y^<#c1nǍ 7Ͷ(-yBDK칇䏤f:B A{Dz-0kǭEW4mYߕ.r\®M,;\SQCw;٭ ߷Vͥb28`5ˢ߶U۔ҥo(֚"!( xHx0Y8b88, hwiX+6JDF_Pvl~EE\9" R _"?|j?= a [ʁ*(&$YѤo;{(lI?2R$0lgfYlplZذiGTp[2I‰gZJ*F==%㔫 (nrq~T"uM\EKc“Lod "b=+gO6h4<cB4#itvJr;ͧ8iа\SxfY=_CМDf*/pz.33v^]nf lˁFU=5/{o.ܯ_?>.ZhѢi>a4nڞ#4[տBq񧪚%l ȵxMl9Khy:>ܟ@0b6ܼ X|WOT9?unלd.^%>,7eK_[}Qs6=,[Pg'9l1A?&]6X䞎ҧTE]IqPMstL鳟t#ި#Uml}uW|/뾦+} P_A]!@'ϩv (NKo#m"+ꗩ|q,ݛژ$[D4S*@ '\UxW3MgŇ#j S 6yTwRHLqGz'#NI%tF(5(VT}|0 n-: Je=Rz ژI]0)wX!^̖8~Bi)H uSB1k1~a@jdKPdU.Q_Սa?By#c1A2۞ 1-y@/^if* ]]x\\|!^j)K+u?IsA@VcOgE.~ܾwwq[a5s3t O=*!JM 47SjD%7J\Y%^ν+|o:sH8UDV`p 5aJu3Bo'BP\NpRiJ`gu._@*z uBrz&vL鴼 w3R9~kDTsK:_nn12M]> Ifͥ\]8d֤?|c.p ?JJVGhG _QQ󪧁؆N'S3[iHY(>nt_ONvO=Z1o QhymDxK?M:}Rkh $Sz ߽ >D&<op،=wsF. \tk/O?X>7Dϴ/~оR{si1k_fҽoY~=h?dq&|^on57, {{ehYsc_퉼jq^ByjŌu_Khz5ɂrVJg7/2kq^tHIГx"l,-KY*܏N?907:Y `wjJBb}x8Qz I&C:_ 5V>-92~jd xrP?1{w?ύ F=l:r\o3Z#fS-5M|5ck@geku9?;lS Q)pe6krSWzw]H 6/DC0ehsXC:C\VL en>UcʫvZH8nNT&}D\/=(),!qEJf8/)d|zd1i#8˲<"]2=޽%%=KVo$GhVm;9[XIT6:9x_H RQsLw?F@^v%,F0JqPyFs}5Lz\)Yٟ6 PnKc88}4cCT#mf9xpCT5I"5IAB1 Qv<5K3{a=7ҐRq+񕩽lȑ֟QZhuÌPʏ>If&l wdY~bzb3r{WPCSbWnOo7'JൿMַٟݵ=.Lol8NY9ӃɹWct ̕"bbB?ڬg}q">< KDR߽#&V~ =O{9)qLG2:Mzl+Ww.,-Q:.Ɉ6?˥GU'u ͤ {.ҵߢ;S{d1Lr(qb?Mh W1N(oj?fX,$xf5˙`He«[ ӵ+[+ 3T+T4JBwbɎdh4 VOu mAd1wwG0`}P%QCkHC,J[LБ/87&U/A nbFF vr+ӯexM2#ћ(S{]0ȓgȳQO&j>ɘ‡D:2jQrd^,f?91߻3"#ՑqOH xX8I2S[<P%)cZL<{eV@O&:M WmVeBcàc]*rzfv.s3r0qtbHa⑱i6QZC+smr;,yʪG.15t&e=mg֫uVdޫAPep)7Ƕw :uqy@D,HlFƳx cigyB[cZP)(KUߛ ع-4ޚ51(|o~A8_3C}3H=W^O1ZZ+Ck@8f1iM!xpTm ٍ}`QȜEoF3'DOZ"%Lù)ɕf*ia-6s+wo|&4( LőWrUn2m "wc.Q`/,kM\o8̠m8CYLS*q؛F@}r5[pJ c啊LQHS[)񖤼jlrM^l{_rsl죉B!SzGط&Y* ߊݕPL釜,g./PV? M+ M[ƗoN2Q-~Y^)'{#+QjoÐcھ&O!Մ,IuCp(afTVƳK)Y-!b絑2ͭyHzoEezJ#LVX׃k'T2=Y('螞|R;x4.%dv{ފek>LNZnS¢჉#-1-ңC,I> *;+j4+eCC"2s"nIԏ/Pc} v5Ч \:9'ZI9[l- dۣ^l,4ɃX7=Ù^XKmy2|W;N&aθUaxtuqTȒg;篅yYfkļ #ܥ cw# e tdkffkwJz䈓|p*O֧j˗0a۱mҡRAšW: endstream endobj 1540 0 obj << /Length1 1911 /Length2 10119 /Length3 0 /Length 11289 /Filter /FlateDecode >> stream xڍvTZ.!!0t)H30 1Cw7tK H"Jwt9;uy|޽w/tp+ Ȫ*@~n Iu69;"Px8xBbb@ O U 8 $ wqڹ#'՚ +**W:@  w;5 B};wwg1///n7Vu@ 0 ѸzvPpw/+08B!07D q tjp9/7U +dm wr|0[ TPvv`_ G78" :Q Ąf uvwv:W1p'' ?9+q><\ 6{8à.eb&6[;@EڎW=g_N_f ~pg b HsyB?xy`; b a0ClƈwzL>2C( 9yu4Tt9_ ŋ( /w!-"08@ogDφ!]M@ko*OoF Y? '?z#@X50{Au"$vkoms Zp7=b7 !̿\wSy5k WWHNjI0/)xapwD 1`V<ҿL#!o$ DJ?CO;oE*4L+sCz$ضO ߟt3IJDF׻52QUVz',N akq1YO.j ?@#'^c0_w_=JXLW"=Sv2:rk~]#Q`8犓7/jL0eH;-M4_>S$:ϝe{\S8Ӆ=:2n ZJ5w;g֚8nB"U^o &QuwM=m^WlIa`_P%& akE%dR~768hR~`vO^Uܒ\EIn(G894TR+Qj_lU"mYxF?>lGgfAH=Qd _K ~i8==0-V/? F>u)5̔RȘYP4otDbڠ)tTR787 _YL[o):dK{_1N^5h/CfӼ/4M(%V}W"& xKHio_1GH64T&Fdˇa G`]j1q"Cw93X] JqW2cit& s]2apIOGzQ>9C. Mp{N>gRɛZT]jՖwe<\("E}-@wlzdT",#z85% (ֿV>H=fJyXt:y$RA%x l |pqt'Z|9ӉkO`1 `mTv~ = NqoGXC&jk/KJL̆jfָ+ TCA7޿ݗ?A\ԍfWw5mFxk攇ԳM-*1bY-bƝ¾ 9.L]ITȗ%tf'iEM?yҝK>d@gjK. )[oY4m;L,}yŇSqRXf]I.Agl .q(̊i 3suXS G+P] hm^L6!>Kީi̝USv'<[FصA[!6kM!@1&ݢk:Q hA򚙥OJy$8t\)$hq仉xQ_NibJQX<^Dx nJPENy*~)<87Hf[M8A/2t$B`r[^0e&I*OAVn1sb A#h-/!U8kfD/}Jn_zl)g-1c2e&5mPST ]M7dv8ψCM﨤K}K[eJCͺ”|6D Vr Qj[SfOa WW1*hZ Ǟf"p*3xhӬB?[$},k"qT-pKxOveע!3Pu~kqx/`O2#.>)B_} w.eǭ[~`㓌#S7,~ 0;i>ԏ gke%210lMu)tr[|>}vmׅ4C/%F-&9ӤyĸH~N⾖aJUtATikI[Qo%>"-fU{|p] s_EHOe/MT@Wqem{,nB2ŒW!? DA%NUE*w+GYFZCħvBh\=p ı}B? sEZDZòqяڟR$ ~#NOh{H&[udCڃɉJ&мL;.V+o@9KR1(2 p-=O5m{މ#to|򌡂9nu:>X'`TFG_xc43źPFoz*ʹBK{ܛL*~y.'92UdW+5.b)߼bFݬprnht'sx$;ku4 $kY-!o;@)}SzfGHLUp(\f6/}nE$£ؒO *' ^t5^a[jQa /m2 uNI/-2%Hm4}`9W5aeaJj➓@@wѓjB"_vec1p,bn7YSJ<G%]$LfXQ;~G`;QťQd#ЂDt1mQ^ȃoǮ5[ys CuutR8MoX=R}쟘dǚKNˋ/8 H~joAMhHPȟh9( ,QB. Uqb-xoU~HZ[{`j#z^.)pfn0`f@)ZAѬ^gFmT D Iv@^9jǽZV,Ś!_.:4,u% f<=& re܁mT t*=[KF;6ڏpx))'otaK6 7CsJ(D*DN\+0}O8֭cJ^jefL:>{c+.a[)[zՃ^OFl+E.*%T;>0*&wmLWX.ޟ~'ZDQ;A[nR݊\ Rf9& Å&Ks&6>zꪼEs?s>l9pspD!phڸmM0ޞHuߏ9$ͣ_U.KgaN<jOS^*&9i}_+p5>[֚#6;SX|! Sv__,jSl%əq~iX4|M򉈝rݻmW܉0"O?RxgS'vzaN(vlH}luzFʝinIgK) yWmj # v;Bka|IRl 03_0"(1w=7UOU/I@V ʕ7Z׊R_K(>>8o9q%`'MS8u?vQ5raF O=ư 2ƈㅞbc)vZKk$Hʲ(bO߯?xc|d c-Xj;ͅa^.]^/b]icrӹu&d+'D'θfٸTies]v(\mxhTvafP|<X x3q+<|G҉oB*U;74u9)No-Ռ ^_Q/p=g3ݑqy%sTB⫌4d  ڎ,>WW;02~c 34ֺbjϸ^QT4Ƞ0̭nyt9YK{@ۢ(")C_B]]l:0 ʑ̎t,q#kHԁ;bC[i&q~^W:A: ~`xD"rvo[.Z>uKzW+ŘP2"bR&icU<ȭOh]˽.>շ~]VrS"jf2}0!]DZ}JMyvhAC ^ÜNB_ab(&"=N4+ŬT΋V orP_OH5))Φ/[Ԙٙ,WmU.\ƻ*.v֠{y7h\EȷL\K&Z? Iw`iE'4N$x9=^in.4ޱ7uV VlQ۷۾ 9wҲMFD=ȈQGmQea )ԉ?v&@" TD~6/TU& qv`.ݯYZ9p8i Ob1;TFu#n eI|tHrob9BjҚ3Q붴Ң{ҹ6G?Ad=<ПdiLS:\ΘV͎orR9„ 2UO(ud\}ҷϟMGkxl'c W$)U/sQ'N>H"5@>9jM8JjܛLc6"0-ۗ JOd-:`Ӄ)?X{tBP,l*$ÞSqf&}(mwGsixK ?>m=yV_Ld}n~ݣC5O&l E?rf@C.TCRT]zcAejɳAsiڒFk2Ukϗ@ y}})]㖀ތ-#tV &B-!9(Q`g~a_:k}yMXd~N/wʯLtcbv׃7;cҖɁq0]oؗ{ے8H=5?**rr<}tgbC\\3QbCn->osj@ `e5j,=~mwS3Q"Sh&N}R2m#n3^K|oc G#BNs\۝z-\+ң;en~doȄ_/4eGoO]@k8pb[O>h2Xe Aƃ-T2_ ;#vV$6hILW‚1sYBVW[bC,zs3J+7tE'lN.I. yD^oqG[D̢X+?|Vŵ̶e`Q>,7)T[ G f2MȠ}8Ce-&1>IOb$F>$3ΟQz3{݋3` `"f[?\jٜOW7Gy2H{A{YEk}1S0RJZDC[nL6L P,À"ΘΓ|_:Sّ`VcHt6V#%׬o O>GQlc0{bpvX)&䓍6pq405봦l=y%Hү-)_Cj̬!'=jQns.*[g ]3`&0COǓVq:N|EQhy;yM)fLڃd[C9aOqf#磂 ښS$Y=}M]}nR .nl>ʐk0]BDm2zG+h" KTbhf干o^ˢ)U ɇ: }z*q6G΅MWnuթz*`˅k#xq`,x^DJ]EJ4b_;:hR,<,NEY uW~@3P!; |W#Js7sv`↑CUʶ*BfP-h?cAC:]TXO"36#rԞa4.7ۓxp1V;-IZ,2 Xf4ZĠAO/<Vδ]oC ؟8Jej<3YNiM?Sy<7I 'z]hkG]%BLlYWDïrT23 ]UI ki䅧/0nz oS1D.FGuq4#5;%k+Ue&98BB%[dw}\ df<( !ǰKRq08&eh0n&\7R:֨O;D( -"TBteFYhˆ 9&RK0dr^w0*hۀ3PZs 9C-1QE)3v1C-!&{Ӊ+=mLEY?lX{Qc80) ,Xk]GsV(`MxeƊOW\3!XuQ6c0SF&E{bB7ƢĖ>Gڶ2$M}bMnn\]Yx;T3OHaSMϱg.Wbth)= /SݜٶW;܍S;x!+2(ъP=x~Y:I7)MF{)c o )|Ar1Bi//Mfq/Nʌ7vr"EEaK8'3/=`ȓAKMU=X PКVj^@K hӖV7OEb(Ŭ\X訣_ҡC c؋K|>Sƥ9nV. |x|yĕ4Bo@A,5^ӓנwTゆ%~Nϣʤ''?(~F ą_sR(|@Xoew"H3XS6sj^B;^t?g k"n(ϕT$ktosR4r$Uȫ=\~OBK|-e 8eI;NCb܈WP$jo{lڭC܉sX(A=K@f/u%, I TBGa;UqZk|~ǃo Y` 2ԧp~KLIȋ-M)[̀LytIZՖ >uWy>뼆V<~I3L pW2A};9Āwn4ن_99xdc)$O^J6YBEg!˪^c4l.fK6e *$+AxP.d;>ȉ% v&m{~s0D%$@]9avh1Aqg<t2$5KB|]2^:a\XR]| 1NGP4WhؖՓD`4 rd˖%v OTPmy~XI©r,J)t~~tt,vkUdAwUMzjoy趀3xwdJ:RU<;K§[L}Sqԫg,rlf1^4L[\[fx^pLaNGM|6dHI9|%ȱ^b1g1H4ak`f~?zڀZ;0 ѳj4=Ɍ!_  gQY~"JI&^x{2t .G 5{=zu۫VGGy)d\(羇U_'-*K,f޹i7ƴY52zW݆JIEa[';!Sq%F/L|$H RaC4]Y'Bru<;\)g; ͗Z_h*kP}hE JNUt%?`tšjfa(y"=O.6F2@.g+s7=jzͿyc)v9gԳ@r%GE$^`2;vaĸNLVٍOTBm] BD۬0S1$+t4+܇ki!SǬϊt^Htj,sJz3@[{ŧ #H1zo8yuu ˀeԪ}8D@c{d4ΫnKJ.NPM̖%Q[3k_ϳ[lFo@Ae4RliFt8s4T0$إ;3>^!\3=}uZA,&u5+Bk.F t>#5t|(q Ӻ[D.#D?n5<&;@vO(?Y*~*)`w3$ܾ7w n/hGx1O3=Zz)? endstream endobj 1542 0 obj << /Length1 1500 /Length2 8989 /Length3 0 /Length 9993 /Filter /FlateDecode >> stream xڍP\-$whh݃Cp@pNp'AGsUUWc1m17:9$ wabcfH(ihXY9YYّ4.HTZ 'g0Ğ_ '& ty!*A67??++o"ĉ t{3 liRWp l(]@v/̀u_)h\\YXݙv'Ka:F; r9G(@ƌDа;PX@- djorT)T@$0:3?lG0 b[, " #hou݀`[ ցiw˄lvpqfvwc7ف]~' v'_kcqY-~aivtIy1!f rpr@?l/3z;@/c|?$og l0Y ܿ"?6?o/ 3zȨ)25?Nqqpq|;*Wln/tΥ y-@rmշFDYm_| wV#SlUNYo=u09T)u抆_8#Hu=b-_)A/Wf˽_z ^͞S%r\-df z8U0hQIz5omI&RƎeYk*>(.L%?6I+yp{ .Ƣ%BY: WqdVOR-C0r"^P}N5}mqeú~zsz_YEevŪwf;0R0km{cJٛNzp$)he!c#^ZO7(ت҃*Z@Z|(8L>W!.{zPWZjɵsxq(ucy>ûXNV3hٌ WTw}ّԕlQ[I`(̇>DQTCQB"P_ŕhΜXĒl.v{3oW/T5ßc5O/1X9 wkz&bLj1PsuZ6[TlZ(LaAQH*SNJU_#nQ6C =>{O'KI~^+GhAW !]d fh) ]#i3!{.E3xw6ǻ<9^oGIG%e'TK2RZ chAY4ϗc3DۍS={ eضS,Wigz%yp4)ah*3,)bU;a|QѢ,3\p|# 4J),ersa#R&ڔ98{dt9T0h&GCP4-0l1%C˖VQӕ]W9y0=eig~mlDQT{nAT}~{uI׊P`;!uқ?ٓXv 0Uޥ&pO-Ps}_L5rK8?Ny$颼-4>)'yv쌧. R-,r5BV! W"۴_:ԉj]R _\XR㰈Xߤ&㵱F4_iQad۠i}`op?Qvqփ劻n ׮.}IhwG&Xkp~hP5i+ M1bX$+')fT&Ƨ7.oI7qE>ܦXDw2@P +{XkPnk/xQ`ADGКWLj}bT4#8W> c KyjBWW}=3: ;N pZZF"4W6w29f&0ѡ㊷QℙS67%uzlƪ EE`q;А'%gkxD 5[Ȣc% @nЗ:'}4}Žs!n҇ . /} {4ɼy%1&tԎM0P["C uCHT:I6Lw׾kz)!yW$eTޣ1wixN3ڳ>NYsOCy ”ɚ~EO]edMxd2w@ *'ߘY YmR)ߡ#$&tlaFo( kA}_]Ʉю\5yFpkZҠq@jt8ƌϏJ'i_V7%&A_ ub(%ӷx {jILImعMr?H1k6a,|0*l:#ȇk"T;xO[0|tZ O䣭G3hZVqDt/|\ho4Q;: pEPZGFJO$8Gymͧ,g:}+ja )7ERy^ZK{^rq\ OIYTwDY8I V:l4eӯJhϿr x'Ȍl+5(IunNZ*_q -R*7,Y2< gN4E,%ΰVbu@ՕW95w+~:NjրM*G<6pTHTʴMo<~yw|]pIlWd Ib(_P+ly|;^ה3%E0,-Cfא!X.6ubtC:glRSn A<5OD(rw}jbau`h ̣~pe!~'FN(pQrJ0!;Out+*V}>2N.QR HzBg4C D $W > j]$"4{E-E X} f0⚢_\ŵe4ʼJT Rn1HQ!s[I\)]8F;!Py9&QqP~,c/4=Nr  Dy9j<my~3 v$f~ x7nÍb"|B9ao{7Ծ{9%8io20QTƳ1YD7}BjuZ3dSFݛӠ2VΔlUܔR}u뼄oCTǑ6|IlAzsqS悛X$J&WbHTk>H/ 1,X3 ,L8D yϡHś)/`۫B#K`ZjgrS6ўkϱ9<( =ض7 'Й׽ btWh{m3.#ON>ٽGC(3đds ʑx fFЉ}|:\aK +e@-9>VQΉp7=ҹN85^9'A ]fh\(Z\B2l*۶umq*:4*U 2^~w'H-°ufIQY|y@%oKN I{ٲb֘͜-OInX+YD@rrjflɛu/@DC\J| 壝uwJ9"lEȪC %>A a.$ԗx"oݵ7FǚT&ՙtR\byDZ< B?VTSۓ޻E+S[tBm烍 o܏zfw ĦpG4Dp.}N*$W>IĬJGBʭFxfGF377;l~w+gj0N{#H`@rU36LtwR#}*l_ _^*;SΤp9M $-SR_12Bsצ EX9aɷ[e@;*롼aՅ`iΧ`pX!]wPbL+'&3NP>a269CiLwqVS\:tQ q348.Z[ F5gE(˹ 1#Hg?'nGPH^*yt*3hhQoz*".b=÷ }*l=ls*B*^R nrÌoxzd ٕlI"6 =; Gl$Cj-'r9Ɂa0~}&n b ɤ\sOx,oN[QFU53;d KBP3%߼:>9px>(hPpW 9@J= 'C xW|ysΥAV Ell{WM}bQ]b ]hnk][}8N\G9*Z,:J緟 'Z$慇+5~ ^q S=4PtC|TX*b˘uD3qNELQ !p]1*B -;&9ycqBq}qpnaKdl)_YRvN/oQ?UjhF1V%z%;>@BWI)4! I\A[Nn[n9ʘZ}f6$ s׉]UekBR7HlU>ħgEO>dM}D^!m~ Hq7)%gVyI0dK6yr~4rLV}OHo(K+ 8uڭ]NJgJ2vUSnyF:-?Zaܴո&: *C3&!ܶ\rh#Z&Y-XW#Y֐QQI'ީ.TuI>w Z0IlԨ-l:{rBdtcFTkK}e2ڳB:&S4Y06?XQՐE-"1<5Wju8Mdo&8]͒ 2 r|Pod$Di3zL竉FOќ Ax &˗~20hRmg⪯uPSV S O k4Eld!0ÙM;C/FV2mI>e5jPc3-_iD]ܥJ戞!?4ts/3VM, k3ũQ%R?fVb1HN1y,8 7W"0)F,/ $'> stream xڍTk6t4Cw7-=CCҍ)ݭt y[3v?#. 8yxzz"~.>LFF=0 B0uapSB*N^~G nb9'PB@P7= ~XYH;@@9=ZPk0 07ٝ f': w';awf\={r]- N`k~brt. jp _N&C: :!>`h*qa ! ?Vp"@xnvs~^ey,cO݇:B^-bc; n}, \ <<<"<+mm^ ` O0}݁ `@v`;\ Ûg/3x@!N>[K]C؀@N>~> @HT_- xN*Clѿc,+\P̂,#n#c <,)x89fKQN>Gu(| ʪl[ @bo `ofm`-bN`H Lp/| w<!P'(}0yc'(/ psA0<;?- wCҿE#!p> py Jܟx@p"8s>  ܟ3u>`w/ܯA Tlarƿ x"A85 >![ó:9/ z [Tvx,p [P?MvoDП&t.;r0NA \ ¹ }C !:a\p2 Oxp_. 7]_20 8y5^>W( dc \Gy|`grwۀ<( ~ bG[[8.'[6(T-Gk]doXOZ_Xi#^Rq GԬFWOLϋBsTO^(f7u8/jEw=2$h)̎QRhe!ǎ37GRWذEpjj2IrV6 'oչ c)m>x OC[W(:9_.u_U ;}'r~d֠f_*8] T i`#dı|j5{eTYfv۞WE76xrӍ5F)0xcRDI8k5:7U;N^t lov.hУ|/Ӝ*/>XW\~F0Dk@I㑍Ril 5vfðzٷ"*5pd`,.Mg'GK 34=t`θm~ю2)y vuwLxD 4 &>Ƶr /KΣYF7<~LKԩ .$oy].i`4}#Blg+ u▰0'Z/ɋh`[xi:_&(x`>VC1nLxY sxtA~֍~_/Ky-^!jJ|Y2DdiaI>cﮫT-RGC ݂j$oMH^X*RzD6  jt~=RGR;EOP)h$c5TNƑH΂"!)*Λ-Y!Okyw!N \6InίK.qBR3>Fb[_}7mz[GEKsv@zҍD4H%1V|9KSjDn|g: Z:eX5<ڼPFԊ2IS}9bcl<e0w`Oc&;Ҕߐ x;zd?~t5(3N(ŀ^^U|,Rb~%UB)z} }o*6<*XiX+}%u Wo )u9>2N]sRI̬RfP?͠G<raG̘9?Em6fl t9͔ӔzqXۺCImU(C vc Ig|CQq(r˩DMH7~\7D9<0e5+b0gr#N"_8@(oWx˘N#Pdc仕idE%v~Q E>MB~!cc_FX)4pTR_ǩ90 3J}T&tC8M{B0kcP'n(בZ$ռvM^]>ʋ~teLT|ׄ3 %"7r } ?ߐ3V-;u`{ lI-љY: wFU6zÐV' =lTi?>y8=/ UC̰qzLbK!.,KHSA;3l)7Dr5WrZ tžsXg뙍Ըf,eSOHt["{Ip$PkǿrcFxss9O"sRP|fz qWKz``XQf`T]33?)X=>uy8MtL iY&\zOF7%Dk2*PsdY1{HiCNJ1~I%>L|+UY] I{bze7OUVQ @+^gFee\q"O"Q} M'^`J*bG#&8o/i(F,P epՏ!5y|RXUP2/LfÐ/yD0v.ƒrB쉯8/~}Y XIVV7V9y}EDayg- v+[*Ͻ-N9ȉ0c!VcbLw(:ylĢ[Ԇc ̆4؇Zry[ѪJ[=4taW iKV}ZH,f^ãO<ϰdžipۄ l?,DZ͉lE'7kA<>gja! k90W2yp0N (eך&2G}z4K;Ă f΁f~t7b6t^%- v yT> ^u@I!JsVp)Ca˩!>:ta6~Kky.Z̑\yա d5˕w|,IvR>Ayz(R_ DBRYx]oǥ|PyT*gc'@ cq4ͫ|F\ȐVW~`;c<3tjpMr6z?jyPPW[g`=gT/>Ryn1 :dDbHe ^^:~ afϊiKfG!(Өifa7J=}2l!2,L*vemM R?B+kXT$/I6(R*ͬ;{0HAcY'bA!-gCt!% Ā~Ҥ H֐sW16~ɈƮd4 txmFwz(Gd!R~η8|oWIl/?7<o"f{TCNdӱ(m@$%]`r9&kj^сVVi?3ڸhiDИǞLQR z; dI \l=ذ#7ym)!../6O;:jWBѸg ƒaoI^XO2׬:jmC汰e2@d$y_eSzKp2%c 6NB_C-J|WTi{~Pd-bv(Yv]̥@<1AT3I`c1Ȋ)fi\ YuVLc+R:#EKygR&*LqOjPc$ȲlE'ʖLEk , L?Hb?.I267޸]!|KfmQV?*.V M"m@vă;jؒ@]`7]ɄVva_JzQ99h6FI]: 'ۧӣbx[(jȆ0[X&v8yfQZ^rfoŷQP 4 LGs f'ԞL],kQ ֚R3RֹjoSjuI2߸K6u0DCq"Dd %Q*kva<Į|A9{w i은QL$sמF%)%I9f,S_/\cJBmI*d3[n#;iyw4@˒=z7eaLv5# R9JU`^GJU-ә~SȽ]s! BI ^i^%ͩ;VfTmP㣆~~j^Y%Ү7eN=*L;iDy잖\ K߸qorUlyQaŬ.P}4V6g;ʕLq\~{;{b{ 822D݀ЗޗR -SN9)lw p='lfש^wXPQ†}-fU¤9|y\VYuъh dړenL GX/xr)#8χ4mAo*7<*ymj$)So*iĒB@d<*ȽYRr65;ȁ8nkY-:6@X0qq! s?E;u,\j"_*( f9r#\|v+һ7u64*4n!> ?mN~N\%):8eQ&ȴ,X%Ocru$fd37̻j6بxHl7"ĊLoRW1Y xl>3??1ǡ1ӻ"RtIl킗zhezQ:F4#j`9h 78hkcfC_e sk|=6.jDnZK:vjCQԷ5BVɆUA} W5Q$Lq*ȡWyoǞqu*/K"[ք8rS^$@ E"9NDG@ߌZF`G:La{fvjsnt핫3S؄Ѡ u;ncyluvijKVoyR'8 :St ͏i,i1>$ o7y;eP&0~L2W@\2ܺa%c|(UZ- ]ØgG'edIY=C*msFo]k1_]s}z[AۭI2NMN&آ{]~Cva(ڬHgqvP1!-Y4o-faM}q "V&ɬ#k5JB$*p}9&gˠΝm/;UΓu9V5fj] e5xu?k/1|TfL8b$a8Y^Ud-.à7zc*6u!Z,Ud-=J՝`eKg؁lpD+'i_0nU/ٵ15?;9/}&#%rp}a닎p^7ϸf!ޞ oξ2&7)4xpfGUJ"Vkj2Bj<L5δ*<#W!];Q4M>s$ c62(\Iۨ 79l̈֬>nEW1L1JA$mRre;1Fj%BTBOFssߨ_pk׊Y50I pV +arYs6*CC#AӯLbfC =DafY$ݔ9uçnI=h_wjS1J>[ Z\?WCUS܇ʳT`W4=+d/2Q܍9l;-܊Um!dqK%)Q<`~u-o1lc} k#VƯ??ɽ'=7̶`CF- 97} Lcli92c%?< 5IIq0Lf3v#'Ք'mYii&W/'@ <юcp[~+1^Z>zѡJ_%̒:|z)zyhB.ai#r rC2D^3GҝET5aI]\>l($51k-o/g6ʴ }?f`Q1B7&zRusMSdN{d5E-woJIA{ *WOiEjpS L^` ůhV 3咵"+v$ڒv*GK:&-jC:( =_w:QRr :~FHuό)R!敭ޜy_Ɓ"'7%+~? eA<2t i$֏X=ɷ~="51Wo$P!+.{]^\YXW&Oth<&.ֈbs,qCm޲uPh(<=ɰ`X.)2AJ!FdNq,ŲӂLZjX# {rrueZv,S0O\Z[%I?`.\ty%v8N1@XxO:q ^G.;j Xz85#<ם̈Z7XqW`h'#eeW-h6zc*ҫ/,IJ ÉBy2)ipp}M7 -nZ8?|I<۞kYݹkcV**4uMSX7` 3j(M~^,s"|#ҔĭxLAP/)O3[i 7l>.[<.5P4!uW–OZ  TEp⺇>;2X+HTuK<+]نrѨ^q5hؤqRfW0߇#>Txnj cEgޱY|~/V ]vPz\+ue_Ra*?wx%m$TRdJ)1ָ͡] łV&v/@48: / 6ƕ2_ xXFgGNXGd5.nCýRt I4KJ"Oݧx|"(9''B9@UY?5{[J7m;,?4DgK9kjf}9OۆIp=)7TQ϶< 2SV`C}$!p+%dxCGWw|PobElO'2Z'Nƅ |F06nCO@1`nh;V֘Hu>%qgߋV}|ךǫubF% ykA0&̳t˽ 40a:N!$=tͰJ!3}<&CԟC*,39wjw#> n>^H>;TSV]l1}#B:hݮfb'R_zPW2>3啓fm3]7r})R *$'F/ _5x6BXҘs)x/b2:E)J"ΎB#rn7;34})9kҡ47J0G)zPW;G4W4&wDb'! $(J2d[`쯖'*d6-1])6U\@5oŽ?ka&^Etq"y̧qE%]Ґ8Nkjt:GEҒEZ9NLLF|in 7OJ%tqMVFT`]r-5\eUySyA;oM憧PZq4:&78Xn2WyOT!ULHVDXnF\(mjz')qQf b'3+G|.9*\,{&u4œ6/SCs< \"Ar[r",^4v_W35cBT&*Dd3~y}A)jY2ǂl4+UC?HdQV nqx ק*b}$Y^LzuUxEB#DBF`XH6/m& ^ܴWze"w,`pѱr,CH`DЋOI6\)\jgeףh1sf)ĆuC%5czǠJ: 3u\T/ɩ=Z4sU֙uT:T Tzƕ16TȮ޽XܯoFDV xRև7e*!iVź\$xe0,|Ѫ U9'n: gR6qBȏ2!-ñðoߡ6OHbA7K_ӠuG+/8 M Ō {AYƂM qq0y.lv vN;ճEg]> stream xڍvPk-H)Ioґ.  DBIUi"E.A&R7]EzUG=9w2}^{==rsCTlQ0M+$&,*CTR QQ aQQq7ep8 )jh{eSbPH+$&%'&-'* C 0Haj(gO4+gRq6P$ :n"@ ,'". uJ w8dn0[ЯAN? AFp;eua+nCb"\04rD[ C HLXo66('g(00+"m *#WߙCA* UAÝa D_4W]@ڪ`H,+?u8fsvO?uDܑH[_Eغ:#.0m W&?6{$%*!.*&`6"CwPM;Td?ި 5*pp0>@ޟRJ"dscI;UEszǣ`'dt`]CBO|δNa$ ܤrx4Lɮ#݌6:)443`2gd?V]}0束;>Qy\O>Q ʞHr+Z LLp7ڦa B {n=>۩3?t7c;3<oG-*;275x Xͯ}mWd*(H̯g z=7gR# Sx=fh/HBA~BMDNq]]hc!kNi7drm E.fo+J|vOL=7\׉i, H֤>;oN)X,HtR?gպPv|!MQ1+YόX@Wyxsl&ƱR>v!34JrٷD%>5?3-+kh PA|z?%%$!rynVDG-kId~Q5q#3 ɷu/m"GCg Q@Ɨĉ #%M{kZU~l ~ڧ7K~KuJ$ 4 Rҟ+:@5gMy08z*:"YE-ZԄ&P!@ 3~K?XˤUg_X9(6ʈPYJj H"n1'~(?TMt>B1B!ݪ{(c~ƔmAT8,e~ὦ Y>O6~zP!trjK,M8[S홯x@zRi؀3N#YL-ۘ{La"9 X ǎa v{(bTA)qJcMp>Y֪X/Ɍo#QuFk2|3o,Zs7vX!hs<Ext'n0J?iJLt?p6Ҿv#"cEUgH3w}M ~;szA'Z :C^gv&un:M`0%l0$rLyOr|BxMS`, +@ڗ3.OZmn)uZ̋B53X|MMZ/=G)qpHCnڣU$noI`ϤwֆbU?qy.lKK /7Uuڛ/9r=u-[7 7ٶk>6nᯬ o0/elϝԪm''?b-l k}8ny^Sj/@7Y-YfVM`jم;Z>Szq+. v!ƏE +IU(H7F|TmEJ86\Vۈm/Frjq^ DD+7*∧OKa*MKVe@ZndspIwUR7zon NjU{ǎe1e~x25k"vWNd!{\ 1<(3t0wdb eEJfN',S$isTʨG ew*ѝ_cw$pch{Y$\JS"KlL4_ZL,7hp :U xMCT/SnKXpsQ'ǚ$KzO^KjFckS;(/V'Y1w1y+@#6FqPoos8ϒQΧWvy8K8^'N75O^dfBrUfœjW1Ѣǿqs0q|fqvyicC<$}C5Fi_ٶ7k}IqlzWJdrw?*JF0&G1jr>36~)~g$`J-x\'=ތyG0ňA-o$0-)۲횤@>og?w΍dq =_ՋS6b&m4 4$€{i֎n326֐O9gi|@/qGB0fTkw Ä_p?WteHzhiG1agPSyb 7{~ P9u?zK;q*?HZ,)=‚&$ KE- {PL|so{Ӎ͝ s; RꉡO%8amwO.oc QlPS)vkV/,)4)( q+O[RV-;쨕c/oZQ1d߹'Un+z̈nsUӖy χ:Paq,p΀q;SQ5=?vRPc]ϡfzC/9<T[CP%qzPUlX݌bDqռ+b&˗ $j=a*׀x5 ;\RLdf٥S8iHyM~JINq&W\(:@ L8'uxAvZ"<$6y<[k jp.H Hm9f;!<}ssQK4Uf@y8p٠AtPpR@@?F]ٺ<`qLUJ~q[s&ڸ? CS~Y1'4;_ PT0ԓ1M׽7韣9MlW\"Abô])hR9JM ];kR(*uc1հQ{qѐsT l2WfCS9B`Cner}.q]sI1)_qUIdʹ&l۪|RFz]I&=VlrTo|Rǰ$Bƃp\r9UD,B R'4K6+*Z 9;fu9g\BLaV!RN1F9 ," ;Va4bRk vhPKx8tR m07WFK3$^[*Cf9+aH}FjWžK9#jhFg10oM>V g75jfMcSyA ^>ՙyՠ/ []u^'3VϙJocC<kr}Wu&&Ir>lʢ҇O_lF+2^s4~XW{[wrϗD48ĂX)ѽ5[m w{T-–*MgVq>Ek`-Bf>k;ސs ]Uz&U^jw+"i(5Zq/?uUZOoVykӷ20X˒KaO1%U{nFuE31ݻ+s 𞡹G3|UqdTtw2Nqc=!Aƌr32cM]i:g@d<WZh*v=Z%E5X͏\ieBn_#;_4nf&Y. +) X28TwRӋo4+EsLr*o@lQǃWPoéٛ q&lVԕಆ0{z#e;UuCl<[KR}M7 C~ᝇ?m<@JSWDsq9]TOl:[N`<;S҂K_mǠ*|IၡkKb#)ԣKm6vn+"Kc$ w"dG~ߘsEQkF%'AOy Z{+ЬΧUYwO\jNdqR` ̠wvS Kf䴩;E>=\^}Aa%qy+bzngɱq]QL]MbnqIviy}z)3H'2Nx1BM"eaR{t g l:sܺ.i9~% op ]QDŽ).Sv嗟 g>rHq} Yْ7 !P=@y4!#m+;(TD\V˥K~,i,%zG,Ž4yëú8151%;-U=l"ڻtSӖ{MV*AtIeg>jS fKzEyLMًPm$#U՛bX"Z cwhS#e24Q78 h<)9Sfb‚QǬ6ϩ\ѥSsIid/]A NH<28GgϓZ2)H 7TV_Oel|^B endstream endobj 1442 0 obj << /Type /ObjStm /N 100 /First 1008 /Length 3246 /Filter /FlateDecode >> stream x\O_7Ze,!br" 13s_}k0Qip,R)j'M&=M4~~~~~g>ssȜC299dݡFmz[/Bi]iii̦4flzMO4!\YqX{|]z{{{t'Aq6ʄ΄Ʉ̈́˄DD,3g9革`w޴;ww1w1v{۝dvlڝ\߼ݹ~vlڝMiwl-{uӭ)~N ֶeU|FI^<?p~Τ=Š>UoLݲ7%<>&J;TN@I]V޵Ȼy/W\byom)/"+/* ~QR h;eSS]=s a "0lWI+Ҩ%d1T #tyOm8:\z,1 h5o^Bf^6P3y GTьpK?r mfԜ^8Y+ 񘧵HE Kw|N&tl׌7?PPRX'hF,EA=E(xTGVO>)'n>2hye:i K4WTNn*SB:354*TUi[M[r7TzO4's-`GQmg#f҄zg|_v_J)0Q[|Wݳ1J|ݗu^wFk\]Ї^Ye&e/{I.,VѫOKjuTj=9:bVl$89\P /J).)N..i]#?)Ɵ?/+LeC5UǙ1o7xqQ z}yqR{e@9?:<xш_>O.Nz=+>C|O6x&# Uk>pu1Uǟ|'pn}}w_߼BY.]V\,w :3K0i vll-EX#at%\up}9zxH.I6@88Zҫp op}?s8 tٞ+^ ~Eȥ )D5X)6Ҍ:̵ 퓽dBl3 ֶnh6m?9/bJv#0pePD~p_ gY>{Ikl?=t\P4輎|X`YL sǒ,f@zp@Z~t/V8ġ tV> endstream endobj 1581 0 obj << /Author(Herv\351 Pag\350s hpages@fredhutch.org \205 Michael Lawrence lawrence.michael@gene.com)/Title(A quick introduction to GRanges and GRangesList objects)/Subject()/Creator(LaTeX with Beamer class version 3.36)/Producer(pdfTeX-1.40.16)/Keywords() /CreationDate (D:20171030190059-04'00') /ModDate (D:20171030190059-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian) kpathsea version 6.2.1) >> endobj 1548 0 obj << /Type /ObjStm /N 63 /First 577 /Length 2326 /Filter /FlateDecode >> stream xڥY]o}c> @޴vq|y&@Gjv]'0r$#HFѠO& D4!&Fl/xƔ (b] &MP`ety8sa`Zq]" g!$#˖]֕D(h":=& AleYĵݿ|hym(N8Z>ZlY>zyr89;)я77o/?o9 s߸ٞlËw?od-c<''s3 ZvkȚ~N^^^ hĻxzU!0o?|ק?G/%o)@j))~ѓ_ [  e0 V} ӧ'L`s20Q  W+fʐh"k~y쇳g~S=j~ss<`j}atn(ǭ^s瞇zu|[ի.sҫAܐ%em+)׌ g t㶦 !g!W*Wmb נre T^^` kZaX5ap@k0A q(>Rj (90v5OKíG,,l)Z*'ٲnHRN* !z7kTjg/df<[e;3a2qÆ5SVkí/CӓH8O_fzƙf}7o#`kφm6.a@h¸<fl4 I"@(G]YAZG;`4lq&Ax`f+7ȍH´rϱQnȳat0 Va$TxU~^=zz<]_o/>¤97عy0 u#Sw,O/?^nwLuJq2ɳ;؝QػΝ$ԹWSN`rGY`;*#>R?ECYH] }W%:@ֺYdRC9Qr8/'9nI*/}NfBXzi^j*/%: ](Գݲ 1 GxtRSPrjű|@̹يޮOMtt¡$Dp)Dq%Qj ˖*!.v&Ş+XWn.2Zt'Jg8L{,u>ch;?wO0u7ܱt0nB8@.]ҵlw9wAp8 _VؕIK?i<MA!O>[z&Ia>x@#v|nc9!b*0I"#miDGGW2-߷LKۏ1$}2F=Y^:h-`i ZOݮSi4H'm~GUvjcgHv2>b,O'#}K׼䫯o w7:8Ol>ܿ ] /Length 3462 /Filter /FlateDecode >> stream x%Y%YB8y2k5k-k+k+k/a AG>:Ì0*>t"43؄(4pω=q|723(irSnE1>2"3dW hMf>͜bxt́Lo}mNaNٷ*ٜ)}=ڜ-CŴ4؜#s[cjd}[es,[is,D'br}m.N5f~q~{d#ȇ9)elͲEʸlCv.r0i'%!,:ϳܐrKnyG=/rL rJN9+\rI.K>Xb=9fU3 ]"ޱCJXիqu˫0%O<R^kyd6-MƊhmz'5`Ȱ̔L *羙/86 f,yX)f? \ \ \ \ \ \ \ ʍrH`h`h`h`h`h`h~3oɱhX:"""""""""b|ֈmmmmmmmmməPl$C%{"l4l4l4l4l4l4l4l4oX!Ad d ˈLCFBq2OY(d,L Y)d2&dl98yʍEʸlCv.ݲG>/rD ?=3QrF99/\rE5.7ܒrGޑld(>,B̿Ia(lͣGD/ACCCCCCCCCCC{ 2$&yaq/7~?Gߩ~~7g4f+d,HY*dJVY+cN6h(<9*elq&e]2!e}_A9$MɏrJN9+\rI.*ܐrKn]9Su^6F$elq&e]2!e}_Kxyރ)#p)rB&夜rF99/\rEܡ\rK_"_ܑ|ܓ@#y,OdJ3y./䥼ׂ@ir`v_Nt/\׿7˰pPrPrPrPrPrPrPrPrP:%eAAAAAA]9-/\r`Q % % % % % % % % % % % % % % % % %eexy_ȣ|RJJJJJJJJJJJJJJJJ̬w$KD__fIQRQQQQQQQQQQQQQQQQQQL({_z7'&DD""HD$"DD""HD|DD""HoI+Cx9\ E"aHX$, E"aHX$, EOK$F&}ByDI$I$@ H$I$@ H$[ٙ EB ?zH3`HX$, E"aHX$, E"aHoQgfW{Ma2Sfg2G= 0.2 * length(ids)]) ################################################### ### code chunk number 79: cseq_13 ################################################### tmp <- unlist(qseq_on_ref_id2, use.names=FALSE) qseq_on_ref2 <- relist(unlist(qseq_on_ref, use.names=FALSE)[tmp], qseq_on_ref_id2) ################################################### ### code chunk number 80: cseq_14 ################################################### split_factor <- rep.int(seqnames(gr), elementNROWS(qseq_on_ref2)) qseq_on_ref2 <- unlist(qseq_on_ref2, use.names=FALSE) qseq_on_ref2_by_chrom <- splitAsList(qseq_on_ref2, split_factor) qseq_pos_by_chrom <- splitAsList(start(gr), split_factor) cm_by_chrom <- lapply(names(qseq_pos_by_chrom), function(seqname) consensusMatrix(qseq_on_ref2_by_chrom[[seqname]], as.prob=TRUE, shift=qseq_pos_by_chrom[[seqname]]-1, width=seqlengths(gr)[[seqname]])) names(cm_by_chrom) <- names(qseq_pos_by_chrom) ################################################### ### code chunk number 81: cseq_15 ################################################### lapply(cm_by_chrom, dim) ################################################### ### code chunk number 82: cseq_16 ################################################### cs_by_chrom <- lapply(cm_by_chrom, function(cm) { ## need to "fix" 'cm' because consensusString() ## doesn't like consensus matrices with columns ## that contain only zeroes (e.g., chromosome ## positions with no coverage) idx <- colSums(cm) == 0L cm["+", idx] <- 1 DNAString(consensusString(cm, ambiguityMap="N")) }) ################################################### ### code chunk number 83: cseq_17 ################################################### cs_by_chrom ################################################### ### code chunk number 84: bin_1 ################################################### library(BSgenome.Scerevisiae.UCSC.sacCer2) set.seed(55) my_var <- RleList( lapply(seqlengths(Scerevisiae), function(seqlen) { tmp <- sample(50L, seqlen, replace=TRUE) %/% 50L Rle(cumsum(tmp - rev(tmp))) } ), compress=FALSE) my_var ################################################### ### code chunk number 85: bin_2 ################################################### bins <- tileGenome(seqinfo(Scerevisiae), tilewidth=100, cut.last.tile.in.chrom=TRUE) ################################################### ### code chunk number 86: bin_3 ################################################### binnedAverage(bins, my_var, "binned_var") ################################################### ### code chunk number 87: SessionInfo ################################################### sessionInfo() GenomicRanges/inst/doc/GenomicRangesHOWTOs.Rnw0000644000175400017540000011362713175713746022310 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{2. GenomicRanges HOWTOs} %\VignetteDepends{GenomicRanges, Rsamtools, GenomicAlignments, pasillaBamSubset, TxDb.Dmelanogaster.UCSC.dm3.ensGene, TxDb.Athaliana.BioMart.plantsmart22, AnnotationHub, DESeq2, edgeR, TxDb.Hsapiens.UCSC.hg19.knownGene, GenomicFeatures, Biostrings, BSgenome.Hsapiens.UCSC.hg19, KEGG.db, KEGGgraph, BSgenome.Scerevisiae.UCSC.sacCer2} %\VignetteKeywords{sequence, sequencing, alignments} %\VignettePackage{GenomicRanges} \documentclass{article} \usepackage[authoryear,round]{natbib} <>= BiocStyle::latex(use.unsrturl=FALSE) @ \title{\Biocpkg{GenomicRanges} HOWTOs} \author{Bioconductor Team} \date{Edited: July 2014; Compiled: \today} \begin{document} \maketitle \tableofcontents <>= options(width=72) options(showHeadLines=3) options(showTailLines=3) .precomputed_results_path <- "precomputed_results" @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} \subsection{Purpose of this document} This document is a collection of {\it HOWTOs}. Each {\it HOWTO} is a short section that demonstrates how to use the containers and operations implemented in the \Biocpkg{GenomicRanges} and related packages (\Biocpkg{IRanges}, \Biocpkg{Biostrings}, \Biocpkg{Rsamtools}, \Biocpkg{GenomicAlignments}, \Biocpkg{BSgenome}, and \Biocpkg{GenomicFeatures}) to perform a task typically found in the context of a high throughput sequence analysis. Unless stated otherwise, the {\it HOWTOs} are self contained, independent of each other, and can be studied and reproduced in any order. \subsection{Prerequisites and additional recommended reading} We assume the reader has some previous experience with \R{} and with basic manipulation of \Rcode{GRanges}, \Rcode{GRangesList}, \Rcode{Rle}, \Rcode{RleList}, and \Rcode{DataFrame} objects. See the ``An Introduction to Genomic Ranges Classes'' vignette located in the \Biocpkg{GenomicRanges} package (in the same folder as this document) for an introduction to these containers. Additional recommended readings after this document are the ``Software for Computing and Annotating Genomic Ranges'' paper[\citet{Lawrence2013ranges}] and the ``Counting reads with \Rfunction{summarizeOverlaps}'' vignette located in the \Biocpkg{GenomicAlignments} package. To display the list of vignettes available in the \Biocpkg{GenomicRanges} package, use \Rcode{browseVignettes("GenomicRanges")}. \subsection{Input data and terminology used across the HOWTOs} In order to avoid repetition, input data, concepts and terms used in more than one {\it HOWTO} are described here: \begin{itemize} \item {\bf The \Biocpkg{pasillaBamSubset} data package}: contains both a BAM file with single-end reads (untreated1\_chr4) and a BAM file with paired-end reads (untreated3\_chr4). Each file is a subset of chr4 from the "Pasilla" experiment. <>= library(pasillaBamSubset) untreated1_chr4() untreated3_chr4() @ See \Rcode{?pasillaBamSubset} for more information. <>= ?pasillaBamSubset @ \item {\bf Gene models and \Rclass{TxDb} objects}: A \textit{gene model} is essentially a set of annotations that describes the genomic locations of the known genes, transcripts, exons, and CDS, for a given organism. In \Bioconductor{} it is typically represented as a \Rclass{TxDb} object but also sometimes as a \Rclass{GRanges} or \Rclass{GRangesList} object. The \Biocpkg{GenomicFeatures} package contains tools for making and manipulating \Rclass{TxDb} objects. \end{itemize} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{HOWTOs} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to read single-end reads from a BAM file} As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads @ Several functions are available for reading BAM files into \R{}: \begin{verbatim} readGAlignments() readGAlignmentPairs() readGAlignmentsList() scanBam() \end{verbatim} \Rfunction{scanBam} is a low-level function that returns a list of lists and is not discussed further here. See \Rcode{?scanBam} in the \Biocpkg{Rsamtools} package for more information. Single-end reads can be loaded with the \Rfunction{readGAlignments} function from the \Biocpkg{GenomicAlignments} package. <>= library(GenomicAlignments) gal <- readGAlignments(un1) @ Data subsets can be specified by genomic position, field names, or flag criteria in the \Rcode{ScanBamParam}. Here we input records that overlap position 1 to 5000 on the negative strand with \Rcode{flag} and \Rcode{cigar} as metadata columns. <>= what <- c("flag", "cigar") which <- GRanges("chr4", IRanges(1, 5000)) flag <- scanBamFlag(isMinusStrand = TRUE) param <- ScanBamParam(which=which, what=what, flag=flag) neg <- readGAlignments(un1, param=param) neg @ Another approach to subsetting the data is to use \Rfunction{filterBam}. This function creates a new BAM file of records passing user-defined criteria. See \Rcode{?filterBam} in the \Biocpkg{Rsamtools} package for more information. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to read paired-end reads from a BAM file} As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un3 <- untreated3_chr4() # paired-end reads @ Paired-end reads can be loaded with the \Rfunction{readGAlignmentPairs} or \Rfunction{readGAlignmentsList} function from the \Biocpkg{GenomicAlignments} package. These functions use the same mate paring algorithm but output different objects. Let's start with \Rfunction{readGAlignmentPairs}: <>= un3 <- untreated3_chr4() gapairs <- readGAlignmentPairs(un3) @ The \Robject{GAlignmentPairs} class holds only pairs; reads with no mate or with ambiguous pairing are discarded. Each list element holds exactly 2 records (a mated pair). Records can be accessed as the \Rcode{first} and\Rcode{last} segments in a template or as \Rcode{left} and \Rcode{right} alignments. See \Rcode{?GAlignmentPairs} in the \Biocpkg{GenomicAlignments} package for more information. <>= gapairs @ For \Rcode{readGAlignmentsList}, mate pairing is performed when \Rcode{asMates} is set to \Rcode{TRUE} on the \Rcode{BamFile} object, otherwise records are treated as single-end. <>= galist <- readGAlignmentsList(BamFile(un3, asMates=TRUE)) @ \Robject{GAlignmentsList} is a more general `list-like' structure that holds mate pairs as well as non-mates (i.e., singletons, records with unmapped mates etc.) A \Rcode{mates\_status} metadata column (accessed with \Rfunction{mcols}) indicates which records were paired. <>= galist @ Non-mated reads are returned as groups by QNAME and contain any number of records. Here the non-mate groups range in size from 1 to 9. <>= non_mates <- galist[unlist(mcols(galist)$mate_status) == "unmated"] table(elementNROWS(non_mates)) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to read and process a big BAM file by chunks in order to reduce memory usage} A large BAM file can be iterated through in chunks by setting a \Rcode{yieldSize} on the \Rclass{BamFile} object. As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() bf <- BamFile(un1, yieldSize=100000) @ Iteration through a BAM file requires that the file be opened, repeatedly queried inside a loop, then closed. Repeated calls to \Rfunction{readGAlignments} without opening the file first result in the same 100000 records returned each time. <>= open(bf) cvg <- NULL repeat { chunk <- readGAlignments(bf) if (length(chunk) == 0L) break chunk_cvg <- coverage(chunk) if (is.null(cvg)) { cvg <- chunk_cvg } else { cvg <- cvg + chunk_cvg } } close(bf) cvg @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to compute read coverage} The ``read coverage'' is the number of reads that cover a given genomic position. Computing the read coverage generally consists in computing the coverage at each position in the genome. This can be done with the \Rcode{coverage()} function. As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads library(GenomicAlignments) reads1 <- readGAlignments(un1) cvg1 <- coverage(reads1) cvg1 @ Coverage on chr4: <>= cvg1$chr4 @ Average and max coverage: <>= mean(cvg1$chr4) max(cvg1$chr4) @ Note that \Rcode{coverage()} is a generic function with methods for different types of objects. See \Rcode{?coverage} for more information. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to find peaks in read coverage} ChIP-Seq analysis usually involves finding peaks in read coverage. This process is sometimes called ``peak calling'' or ``peak detection''. Here we're only showing a naive way to find peaks in the object returned by the \Rcode{coverage()} function. \Bioconductor{} packages \Biocpkg{BayesPeak}, \Biocpkg{bumphunter}, \Biocpkg{Starr}, \Biocpkg{CexoR}, \Biocpkg{exomePeak}, \Biocpkg{RIPSeeker}, and others, provide sophisticated peak calling tools for ChIP-Seq, RIP-Seq, and other kind of high throughput sequencing data. Let's assume \Rcode{cvg1} is the object returned by \Rcode{coverage()} (see previous {\it HOWTO} for how to compute it). We can use the \Rcode{slice()} function to find the genomic regions where the coverage is greater or equal to a given threshold. <>= chr4_peaks <- slice(cvg1$chr4, lower=500) chr4_peaks length(chr4_peaks) # nb of peaks @ The weight of a given peak can be defined as the number of aligned nucleotides that belong to the peak (a.k.a. the area under the peak in mathematics). It can be obtained with \Rcode{sum()}: <>= sum(chr4_peaks) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to retrieve a gene model from the UCSC genome browser} See introduction for a quick description of what \textit{gene models} and \Rclass{TxDb} objects are. We can use the \Rcode{make\-Transcript\-Db\-From\-UCSC()} function from the \Biocpkg{GenomicFeatures} package to import a UCSC genome browser track as a \Rclass{TxDb} object. <>= library(GenomicFeatures) ### Internet connection required! Can take several minutes... txdb <- makeTxDbFromUCSC(genome="sacCer2", tablename="ensGene") @ See \Rcode{?makeTxDbFromUCSC} in the \Biocpkg{GenomicFeatures} package for more information. Note that some of the most frequently used gene models are available as TxDb packages. A TxDb package consists of a pre-made \Rclass{TxDb} object wrapped into an annotation data package. Go to \url{http://bioconductor.org/packages/release/BiocViews.html#\_\_\_TxDb} to browse the list of available TxDb packages. <>= library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene txdb @ Extract the transcript coordinates from this gene model: <>= transcripts(txdb) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to retrieve a gene model from Ensembl} See introduction for a quick description of what \textit{gene models} and \Rclass{TxDb} objects are. We can use the \Rcode{make\-Transcript\-Db\-From\-Biomart()} function from the \Biocpkg{GenomicFeatures} package to retrieve a gene model from the Ensembl Mart. <>= library(GenomicFeatures) ### Internet connection required! Can take several minutes... txdb <- makeTxDbFromBiomart(biomart="ensembl", dataset="hsapiens_gene_ensembl") @ See \Rcode{?makeTxDbFromBiomart} in the \Biocpkg{GenomicFeatures} package for more information. Note that some of the most frequently used gene models are available as TxDb packages. A TxDb package consists of a pre-made \Rclass{TxDb} object wrapped into an annotation data package. Go to \url{http://bioconductor.org/packages/release/BiocViews.html#\_\_\_TxDb} to browse the list of available TxDb packages. <>= library(TxDb.Athaliana.BioMart.plantsmart22) txdb <- TxDb.Athaliana.BioMart.plantsmart22 txdb @ Extract the exon coordinates from this gene model: <>= exons(txdb) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to load a gene model from a GFF or GTF file} See introduction for a quick description of what \textit{gene models} and \Rclass{TxDb} objects are. We can use the \Rcode{make\-Transcript\-Db\-From\-GFF()} function from the \Biocpkg{GenomicFeatures} package to import a GFF or GTF file as a \Rclass{TxDb} object. <>= library(GenomicFeatures) gff_file <- system.file("extdata", "GFF3_files", "a.gff3", package="GenomicFeatures") txdb <- makeTxDbFromGFF(gff_file, format="gff3") txdb @ See \Rcode{?makeTxDbFromGFF} in the \Biocpkg{GenomicFeatures} package for more information. Extract the exon coordinates grouped by gene from this gene model: <>= exonsBy(txdb, by="gene") @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to retrieve a gene model from \Biocpkg{AnnotationHub}} When a gene model is not available as a \Rclass{GRanges} or \Rclass{GRangesList} object or as a \Bioconductor{} data package, it may be available on \Biocpkg{AnnotationHub}. In this {\it HOWTO}, will look for a gene model for Drosophila melanogaster on \Biocpkg{AnnotationHub}. Create a `hub' and then filter on Drosophila melanogaster: <>= library(AnnotationHub) ### Internet connection required! hub <- AnnotationHub() hub <- subset(hub, hub$species=='Drosophila melanogaster') @ There are 87 files that match Drosophila melanogaster. If you look at the metadata in hub, you can see that the 7th record representes a GRanges object from UCSC <>= length(hub) head(names(hub)) head(hub$title, n=10) ## then look at a specific slice of the hub object. hub[7] @ So you can retrieve that dm3 file as a \Rcode{GRanges} like this: <>= gr <- hub[[names(hub)[7]]] summary(gr) @ The metadata fields contain the details of file origin and content. <>= metadata(gr) @ Split the \Rclass{GRanges} object by gene name to get a \Rclass{GRangesList} object of transcript ranges grouped by gene. <>= txbygn <- split(gr, gr$name) @ You can now use \Rcode{txbygn} with the \Rcode{summarizeOverlaps} function to prepare a table of read counts for RNA-Seq differential gene expression. Note that before passing \Rcode{txbygn} to \Rcode{summarizeOverlaps}, you should confirm that the seqlevels (chromosome names) in it match those in the BAM file. See \Rcode{?renameSeqlevels}, \Rcode{?keepSeqlevels} and \Rcode{?seqlevels} for examples of renaming seqlevels. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to annotate peaks in read coverage} [coming soon...] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to prepare a table of read counts for RNA-Seq differential gene expression} Methods for RNA-Seq gene expression analysis generally require a table of counts that summarize the number of reads that overlap or `hit' a particular gene. In this {\it HOWTO} we count with the \Rcode{summarizeOverlaps} function from the \Biocpkg{GenomicAlignments} package and create a count table from the results. Other packages that provide read counting are \Biocpkg{Rsubread} and \Biocpkg{easyRNASeq}. The \Biocpkg{parathyroidSE} package vignette contains a workflow on counting and other common operations required for differential expression analysis. As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) reads <- c(untrt1=untreated1_chr4(), # single-end reads untrt3=untreated3_chr4()) # paired-end reads @ \Rcode{summarizeOverlaps} requires the name of a BAM file(s) and a {\textit gene model} to count against. See introduction for a quick description of what a \textit{gene models} is. The gene model must match the genome build the reads in the BAM file were aligned to. For the pasilla data this is dm3 Dmelanogaster which is available as a \Bioconductor{} package. Load the package and extract the exon ranges grouped by gene: <>= library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) exbygene <- exonsBy(TxDb.Dmelanogaster.UCSC.dm3.ensGene, "gene") @ \Rcode{exbygene} is a \Rclass{GRangesList} object with one list element per gene in the gene model. \Rcode{summarizeOverlaps} automatically sets a \Rcode{yieldSize} on large BAM files and iterates over them in chunks. When reading paired-end data set the \Rcode{singleEnd} argument to FALSE. See ?\Rfunction{summarizeOverlaps} for details reguarding the count \Rcode{modes} and additional arguments. <>= library(GenomicAlignments) se <- summarizeOverlaps(exbygene, reads, mode="IntersectionNotEmpty") @ The return object is a \Rcode{SummarizedExperiment} with counts accessible with the \Rcode{assays} accessor: <>= class(se) head(table(assays(se)$counts)) @ The count vector is the same length as \Rcode{exbygene}: <>= identical(length(exbygene), length(assays(se)$counts)) @ A copy of \Rcode{exbygene} is stored in the \Rcode{se} object and accessible with \Rcode{rowRanges} accessor: <>= rowRanges(se) @ Two popular packages for RNA-Seq differential gene expression are \Biocpkg{DESeq2} and \Biocpkg{edgeR}. Tables of counts per gene are required for both and can be easily created with a vector of counts. Here we use the counts from our \Rclass{SummarizedExperiment} object: <>= colData(se)$trt <- factor(c("untrt", "untrt"), levels=c("trt", "untrt")) colData(se) library(DESeq2) deseq <- DESeqDataSet(se, design= ~ 1) library(edgeR) edger <- DGEList(assays(se)$counts, group=rownames(colData(se))) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to summarize junctions from a BAM file containing RNA-Seq reads} As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads library(GenomicAlignments) reads1 <- readGAlignments(un1) reads1 @ For each alignment, the aligner generated a CIGAR string that describes its "geometry", that is, the locations of insertions, deletions and junctions in the alignment. See the SAM Spec available on the SAMtools website for the details (\url{http://samtools.sourceforge.net/}). The \Rcode{summarizeJunctions()} function from the \Biocpkg{GenomicAlignments} package can be used to summarize the junctions in \Rcode{reads1}. <>= junc_summary <- summarizeJunctions(reads1) junc_summary @ See \Rcode{?summarizeJunctions} in the \Biocpkg{GenomicAlignments} package for more information. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to get the exon and intron sequences of a given gene} The exon and intron sequences of a gene are essentially the DNA sequences of the introns and exons of all known transcripts of the gene. The first task is to identify all transcripts associated with the gene of interest. Our sample gene is the human TRAK2 which is involved in regulation of endosome-to-lysosome trafficking of membrane cargo. The Entrez gene id is `66008'. <>= trak2 <- "66008" @ The \Biocpkg{TxDb.Hsapiens.UCSC.hg19.knownGene} data package contains the gene model corresponding to the UCSC `Known Genes' track. <>= library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene @ The transcript ranges for all the genes in the gene model can be extracted with the \Rfunction{transcriptsBy} function from the \Biocpkg{GenomicFeatures} package. They will be returned in a named \Rclass{GRangesList} object containing all the transcripts grouped by gene. In order to keep only the transcripts of the TRAK2 gene we will subset the \Rclass{GRangesList} object using the \Rcode{[[} operator. <>= library(GenomicFeatures) trak2_txs <- transcriptsBy(txdb, by="gene")[[trak2]] trak2_txs @ \Rcode{trak2\_txs} is a \Rclass{GRanges} object with one range per transcript in the TRAK2 gene. The transcript names are stored in the \Rcode{tx\_name} metadata column. We will need them to subset the extracted intron and exon regions: <>= trak2_tx_names <- mcols(trak2_txs)$tx_name trak2_tx_names @ The exon and intron genomic ranges for all the transcripts in the gene model can be extracted with the \Rfunction{exonsBy} and \Rfunction{intronsByTranscript} functions, respectively. Both functions return a \Rclass{GRangesList} object. Then we keep only the exon and intron for the transcripts of the TRAK2 gene by subsetting each \Rclass{GRangesList} object by the TRAK2 transcript names. Extract the exon regions: <>= trak2_exbytx <- exonsBy(txdb, "tx", use.names=TRUE)[trak2_tx_names] elementNROWS(trak2_exbytx) @ ... and the intron regions: <>= trak2_inbytx <- intronsByTranscript(txdb, use.names=TRUE)[trak2_tx_names] elementNROWS(trak2_inbytx) @ Next we want the DNA sequences for these exons and introns. The \Rfunction{getSeq} function from the \Biocpkg{Biostrings} package can be used to query a \Biocpkg{BSgenome} object with a set of genomic ranges and retrieve the corresponding DNA sequences. <>= library(BSgenome.Hsapiens.UCSC.hg19) @ Extract the exon sequences: <>= trak2_ex_seqs <- getSeq(Hsapiens, trak2_exbytx) trak2_ex_seqs trak2_ex_seqs[["uc002uyb.4"]] trak2_ex_seqs[["uc002uyc.2"]] @ ... and the intron sequences: <>= trak2_in_seqs <- getSeq(Hsapiens, trak2_inbytx) trak2_in_seqs trak2_in_seqs[["uc002uyb.4"]] trak2_in_seqs[["uc002uyc.2"]] @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to get the CDS and UTR sequences of genes associated with colorectal cancer} In this {\it HOWTO} we extract the CDS and UTR sequences of genes involved in colorectal cancer. The workflow extends the ideas presented in the previous {\it HOWTO} and suggests an approach for identifying disease-related genes. \subsubsection{Build a gene list} We start with a list of gene or transcript ids. If you do not have pre-defined list one can be created with the \Biocpkg{KEGG.db} and \Biocpkg{KEGGgraph} packages. Updates to the data in the \Biocpkg{KEGG.db} package are no longer available, however, the resource is still useful for identifying pathway names and ids. Create a table of KEGG pathways and ids and search on the term `cancer'. <>= library(KEGG.db) pathways <- toTable(KEGGPATHNAME2ID) pathways[grepl("cancer", pathways$path_name, fixed=TRUE),] @ Use the "05210" id to query the KEGG web resource (accesses the currently maintained data). <>= library(KEGGgraph) dest <- tempfile() retrieveKGML("05200", "hsa", dest, "internal") @ The suffix of the KEGG id is the Entrez gene id. The \Rfunction{translateKEGGID2GeneID} simply removes the prefix leaving just the Entrez gene ids. <>= crids <- as.character(parseKGML2DataFrame(dest)[,1]) crgenes <- unique(translateKEGGID2GeneID(crids)) head(crgenes) @ \subsubsection{Identify genomic coordinates} The list of gene ids is used to extract genomic positions of the regions of interest. The Known Gene table from UCSC will be the annotation and is available as a \Bioconductor{} package. <>= library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene @ If an annotation is not available as a \Bioconductor{} annotation package it may be available in \Biocpkg{AnnotationHub}. Additionally, there are functions in \Biocpkg{GenomicFeatures} which can retrieve data from UCSC and Ensembl to create a \Robject{TxDb}. See \Rcode{?makeTxDbFromUCSC} for more information. As in the previous {\it HOWTO} we need to identify the transcripts corresponding to each gene. The transcript id (or name) is used to isolate the UTR and coding regions of interest. This grouping of transcript by gene is also used to re-group the final sequence results. The \Rcode{transcriptsBy} function outputs both the gene and transcript identifiers which we use to create a map between the two. The \Rcode{map} is a \Robject{CharacterList} with gene ids as names and transcript ids as the list elements. <>= txbygene <- transcriptsBy(txdb, "gene")[crgenes] ## subset on colorectal genes map <- relist(unlist(txbygene, use.names=FALSE)$tx_id, txbygene) map @ Extract the UTR and coding regions. <>= cds <- cdsBy(txdb, "tx") threeUTR <- threeUTRsByTranscript(txdb) fiveUTR <- fiveUTRsByTranscript(txdb) @ Coding and UTR regions may not be present for all transcripts specified in \Rcode{map}. Consequently, the subset results will not be the same length. This length discrepancy must be taken into account when re-listing the final results by gene. <>= txid <- unlist(map, use.names=FALSE) cds <- cds[names(cds) %in% txid] threeUTR <- threeUTR[names(threeUTR) %in% txid] fiveUTR <- fiveUTR[names(fiveUTR) %in% txid] @ Note the different lengths of the subset regions. <>= length(txid) ## all possible transcripts length(cds) length(threeUTR) length(fiveUTR) @ These objects are \Robject{GRangesList}s with the transcript id as the outer list element. <>= cds @ \subsubsection{Extract sequences from BSgenome} The \Rcode{BSgenome} packages contain complete genome sequences for a given organism. Load the \Rcode{BSgenome} package for homo sapiens. <>= library(BSgenome.Hsapiens.UCSC.hg19) genome <- BSgenome.Hsapiens.UCSC.hg19 @ Use \Rfunction{extractTranscriptSeqs} to extract the UTR and coding regions from the \Rcode{BSgenome}. This function retrieves the sequences for an any \Robject{GRanges} or \Robject{GRangesList} (i.e., not just transcripts like the name implies). <>= threeUTR_seqs <- extractTranscriptSeqs(genome, threeUTR) fiveUTR_seqs <- extractTranscriptSeqs(genome, fiveUTR) cds_seqs <- extractTranscriptSeqs(genome, cds) @ The return values are \Robject{DNAStringSet} objects. <>= cds_seqs @ Our final step is to collect the coding and UTR regions (currently organzied by transcript) into groups by gene id. The \Rfunction{relist} function groups the sequences of a \Robject{DNAStringSet} object into a \Robject{DNAStringSetList} object, based on the specified \Rcode{skeleton} argument. The \Rcode{skeleton} must be a list-like object and only its shape (i.e. its element lengths) matters (its exact content is ignored). A simple form of \Rcode{skeleton} is to use a partitioning object that we make by specifying the size of each partition. The partitioning objects are different for each type of region because not all transcripts had a coding or 3' or 5' UTR region defined. <>= lst3 <- relist(threeUTR_seqs, PartitioningByWidth(sum(map %in% names(threeUTR)))) lst5 <- relist(fiveUTR_seqs, PartitioningByWidth(sum(map %in% names(fiveUTR)))) lstc <- relist(cds_seqs, PartitioningByWidth(sum(map %in% names(cds)))) @ There are 239 genes in \Rcode{map} each of which have 1 or more transcripts. The table of element lengths shows how many genes have each number of transcripts. For example, 47 genes have 1 transcript, 48 genes have 2 etc. <>= length(map) table(elementNROWS(map)) @ The lists of DNA sequences all have the same length as \Rcode{map} but one or more of the element lengths may be zero. This would indicate that data were not available for that gene. The tables below show that there was at least 1 coding region available for all genes (i.e., none of the element lengths are 0). However, both the 3' and 5' UTR results have element lengths of 0 which indicates no UTR data were available for that gene. <>= table(elementNROWS(lstc)) table(elementNROWS(lst3)) names(lst3)[elementNROWS(lst3) == 0L] ## genes with no 3' UTR data table(elementNROWS(lst5)) names(lst5)[elementNROWS(lst5) == 0L] ## genes with no 5' UTR data @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to create DNA consensus sequences for read group `families'} The motivation for this {\it HOWTO} comes from a study which explored the dynamics of point mutations. The mutations of interest exist with a range of frequencies in the control group (e.g., 0.1\% - 50\%). PCR and sequencing error rates make it difficult to identify low frequency events (e.g., < 20\%). When a library is prepared with Nextera, random fragments are generated followed by a few rounds of PCR. When the genome is large enough, reads aligning to the same start position are likely descendant from the same template fragment and should have identical sequences. The goal is to elimininate noise by grouping the reads by common start position and discarding those that do not exceed a certain threshold within each family. A new consensus sequence will be created for each read group family. \subsubsection{Sort reads into groups by start position} Load the BAM file into a GAlignments object. <>= library(Rsamtools) bamfile <- system.file("extdata", "ex1.bam", package="Rsamtools") param <- ScanBamParam(what=c("seq", "qual")) library(GenomicAlignments) gal <- readGAlignments(bamfile, use.names=TRUE, param=param) @ Use the \Rfunction{sequenceLayer} function to {\it lay} the query sequences and quality strings on the reference. <>= qseq <- setNames(mcols(gal)$seq, names(gal)) qual <- setNames(mcols(gal)$qual, names(gal)) qseq_on_ref <- sequenceLayer(qseq, cigar(gal), from="query", to="reference") qual_on_ref <- sequenceLayer(qual, cigar(gal), from="query", to="reference") @ Split by chromosome. <>= qseq_on_ref_by_chrom <- splitAsList(qseq_on_ref, seqnames(gal)) qual_on_ref_by_chrom <- splitAsList(qual_on_ref, seqnames(gal)) pos_by_chrom <- splitAsList(start(gal), seqnames(gal)) @ For each chromosome generate one GRanges object that contains unique alignment start positions and attach 3 metadata columns to it: the number of reads, the query sequences, and the quality strings. <>= gr_by_chrom <- lapply(seqlevels(gal), function(seqname) { qseq_on_ref2 <- qseq_on_ref_by_chrom[[seqname]] qual_on_ref2 <- qual_on_ref_by_chrom[[seqname]] pos2 <- pos_by_chrom[[seqname]] qseq_on_ref_per_pos <- split(qseq_on_ref2, pos2) qual_on_ref_per_pos <- split(qual_on_ref2, pos2) nread <- elementNROWS(qseq_on_ref_per_pos) gr_mcols <- DataFrame(nread=unname(nread), qseq_on_ref=unname(qseq_on_ref_per_pos), qual_on_ref=unname(qual_on_ref_per_pos)) gr <- GRanges(Rle(seqname, nrow(gr_mcols)), IRanges(as.integer(names(nread)), width=1)) mcols(gr) <- gr_mcols seqlevels(gr) <- seqlevels(gal) gr }) @ Combine all the GRanges objects obtained in (4) in 1 big GRanges object: <>= gr <- do.call(c, gr_by_chrom) seqinfo(gr) <- seqinfo(gal) @ `gr' is a GRanges object that contains unique alignment start positions: <>= gr[1:6] @ Look at qseq\_on\_ref and qual\_on\_ref. <>= qseq_on_ref qual_on_ref @ 2 reads align to start position 13. Let's have a close look at their sequences: <>= mcols(gr)$qseq_on_ref[[6]] @ and their qualities: <>= mcols(gr)$qual_on_ref[[6]] @ Note that the sequence and quality strings are those projected to the reference so the first letter in those strings are on top of start position 13, the 2nd letter on top of position 14, etc... \subsubsection{Remove low frequency reads} For each start position, remove reads with and under-represented sequence (e.g. threshold = 20\% for the data used here which is low coverage). A unique number is assigned to each unique sequence. This will make future calculations easier and a little bit faster. <>= qseq_on_ref <- mcols(gr)$qseq_on_ref tmp <- unlist(qseq_on_ref, use.names=FALSE) qseq_on_ref_id <- relist(match(tmp, tmp), qseq_on_ref) @ Quick look at `qseq\_on\_ref\_id': It's an IntegerList object with the same length and "shape" as `qseq\_on\_ref'. <>= qseq_on_ref_id @ Remove the under represented ids from each list element of `qseq\_on\_ref\_id': <>= qseq_on_ref_id2 <- endoapply(qseq_on_ref_id, function(ids) ids[countMatches(ids, ids) >= 0.2 * length(ids)]) @ Remove corresponding sequences from `qseq\_on\_ref': <>= tmp <- unlist(qseq_on_ref_id2, use.names=FALSE) qseq_on_ref2 <- relist(unlist(qseq_on_ref, use.names=FALSE)[tmp], qseq_on_ref_id2) @ \subsubsection{Create a consensus sequence for each read group family} Compute 1 consensus matrix per chromosome: <>= split_factor <- rep.int(seqnames(gr), elementNROWS(qseq_on_ref2)) qseq_on_ref2 <- unlist(qseq_on_ref2, use.names=FALSE) qseq_on_ref2_by_chrom <- splitAsList(qseq_on_ref2, split_factor) qseq_pos_by_chrom <- splitAsList(start(gr), split_factor) cm_by_chrom <- lapply(names(qseq_pos_by_chrom), function(seqname) consensusMatrix(qseq_on_ref2_by_chrom[[seqname]], as.prob=TRUE, shift=qseq_pos_by_chrom[[seqname]]-1, width=seqlengths(gr)[[seqname]])) names(cm_by_chrom) <- names(qseq_pos_by_chrom) @ 'cm\_by\_chrom' is a list of consensus matrices. Each matrix has 17 rows (1 per letter in the DNA alphabet) and 1 column per chromosome position. <>= lapply(cm_by_chrom, dim) @ Compute the consensus string from each consensus matrix. We'll put "+" in the strings wherever there is no coverage for that position, and "N" where there is coverage but no consensus. <>= cs_by_chrom <- lapply(cm_by_chrom, function(cm) { ## need to "fix" 'cm' because consensusString() ## doesn't like consensus matrices with columns ## that contain only zeroes (e.g., chromosome ## positions with no coverage) idx <- colSums(cm) == 0L cm["+", idx] <- 1 DNAString(consensusString(cm, ambiguityMap="N")) }) @ The new consensus strings. <>= cs_by_chrom @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to compute binned averages along a genome} In some applications (e.g. visualization), there is the need to compute the average of a variable defined along a genome (a.k.a. genomic variable) for a set of predefined fixed-width regions (sometimes called "bins"). The genomic variable is typically represented as a named \Robject{RleList} object with one list element per chromosome. One such example is coverage. Here we create an artificial genomic variable: <>= library(BSgenome.Scerevisiae.UCSC.sacCer2) set.seed(55) my_var <- RleList( lapply(seqlengths(Scerevisiae), function(seqlen) { tmp <- sample(50L, seqlen, replace=TRUE) %/% 50L Rle(cumsum(tmp - rev(tmp))) } ), compress=FALSE) my_var @ Use the \Rfunction{tileGenome} function to create a set of bins along the genome. <>= bins <- tileGenome(seqinfo(Scerevisiae), tilewidth=100, cut.last.tile.in.chrom=TRUE) @ Compute the binned average for \Rcode{my\_var}: <>= binnedAverage(bins, my_var, "binned_var") @ The bin size can be modified with the \Rcode{tilewidth} argument to \Rfunction{tileGenome}. See \Rcode{?binnedAverage} for additional examples. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Session Information} <>= sessionInfo() @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \bibliography{GenomicRanges} \bibliographystyle{plainnat} \end{document} GenomicRanges/inst/doc/GenomicRangesHOWTOs.pdf0000644000175400017540000071122713175727606022313 0ustar00biocbuildbiocbuild%PDF-1.5 % 175 0 obj << /Length 1800 /Filter /FlateDecode >> stream x\Is6WVjB\ړI:Ӥc+Cڙ, Ka,vȘbQ|[{ {/pa1#F!"_Ϟ=?cܣ!18Al_Ryvɔ`_ԓ?gy !pZma!(W"{. 'ur99xr]kȭqUXg6QPy)rqcmA.*Yםױn(G (@HkAdAl!V#D"tʧjl4~(|;dcl' mDfJ5fK1FfU% MWSc:P#ޙw7a"%1Wi^!;'ěbotIZNo˫JfB'=HjdpCh'ȳPy^:ςT6rBhM QH3NŀT .vu !U@х+~ᵎ! C؇Ƴx<<3v{p)mq5sf ׅ(sMr׫ N.Nֿ^V9'QnьmʎF;e- -ؠ "q00 ϴmŁ"}ٙ݅TYGٻC-nl6gOy@6M9磲Mvj/A&"sѴam̳CR ~bt%Q[>)FcJA`(pUUZ #L.5qpR&[uE ґܜ9^J+E%&כ9Z3|S]zDa7N&DE46>m$THuۢHm #-QܚDq%rUU9eھ;y$ڣfp3h Ew)rx޶ eC^ ,XO;1ruF keNuIʍ92Dm Zcj< X].AJTB-@c $'/. $fF%k,XƊҺY6>J&YӝQRx+]QI秝"}(oj5%Qa=+A6_>Ĵ>OC<̜{0V[F3'=\[^lmɳnu@VLQK&fC 2.RHq1aYsov[n '@xj"zś(붾%%M%ەK?2=tOC;8%P`s\3/sSX&zJy>>5Up1`K\z.)V uU{t^̡`8#}'^;_}iv7~cI endstream endobj 206 0 obj << /Length 3002 /Filter /FlateDecode >> stream x[ݓ۶B'j_vl7$Ծ6'CIЉ E^H׿H|Qv&H~b *\N˳FP6VXIӟz .'%DDk6QFb9yEor:qd釋@VH:+hJ*Wo2~8za,5աmd&$0,=QFhI=DG)tƔ]yVv))g5r?Q[m& l@z b;fx<#%sʴ 2A(tU NuV޻^)[m-Μרo'qCf73Dh)Gb8nZۋ(,Oh3&IL'd S+ɍ{p35'ɻ$>WAHXH#&hWD"3諲8\fXҢ]1 .- Ea7L[o\7 L1P Р)9y(7>&UM#r݈eM'Rs.*HXAe[nbk$2mҲ_VᚈE䗼7Ḍ bJئYafZ,Eyo+{l-Z.Y_QfXf T$-`Sm,8uD9Cyu%~y`ZGW׀u~e<0 hmRpN cp}1Yqy'/ะyy[W@OOpyvYd2*[o}B9ܼɌ2{=P~igӄADrJ|Ȧ]u'1Ij-H2ra)jHsiroE~rU0,,<@X@~%r]Wr eo;[,?0ߓ>-j@C;EN ; 4JdF 5Q6SS$ߝ$+96`g`rO9+6D8]W-FwWCj)7Σ7e8(ȩna\V4 H"cui:j WDbW:۶i,&4] Zf K] Bu 쐂^u x#܅9ٲ(n&CR Ix/Ͼ#AJc`n"m$M4#T@יEa{԰| Pȱ' @sdܗƒ0c}/4"4T&_Le2}Zg#4QC;v"/Y}g Q! ^`Hqper!Ie6a35HMKsϹ0̸ `|A-"Չ6)4^=ݦ/3E@Bn.51 YZ5⧅v2:2ȝ\ Cpʹ2MoB`ts@Zn rr;n#AޏC n]x9](-e*sVo!]] j>ܕ-U5 fL5_Ouԋsyw$gIM&kN m}ow兛lXF}Z%PII nWiJ?*q~SylKۭ'}x ǔVv@וLqKAm?w4g'(މAP& "djj iw}ga( O*uFr"4!Eڤ"|($Od!$DU"Xra\(I. ӫ;0T ?$!v"R,Vk&D웆!0'1t1̙IFeV_)[?›d,M+lFoߦiQ/8<.ĠF?ĠL;Wpd6'I* JUy3֞4DHbHEe_ֲ(IEٞ@FH% =P8ӿ69D/)X꧐Z~4C&t1CCt|:H+i9! Mׅ?P]݂_eE~mV_Te]7_0O^oЎ~^ct&o]u-e e֕cxVDgP$7Ca",Bn˜ Ǧ=8,/q>8̚g`myxdiE3pγfw.FJ`@1,鿫#v1:Yyveˆ5qhoD{`w<&nS DOxZઆr23?33N=9ls!(Ƿj7'鮊 e&s=j)v2MM­IQ4d~ifǤ )v73`SrJhVڗ>@@P( X F_Ez-6@Z;I<)&I</ƒ]yazS$QmOwR|w^&h]{l ߏ?p=^ endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 816 /Length 2499 /Filter /FlateDecode >> stream xZnH}W&Cc`g&%D;ܑII%~jRw bӧ/$A GSH RR=)@*IZR%/HT$cCZ񜬁!ړs"$ymfxE# pmoD"d5Ũr07RI60SKŃSgqE  WIiS|R$ԁI] tx3]Ur4F-\aTFPY۶zGw4먪ie;BtS4-[\l֞3bylw5]\U̽, [cZmU~(uY{͢\ sڼ9:? di]p.?]ys֐a l8_tr|Ԉk8A]7}-_.w b ] ?9ymm[-se*Q#1L /?ӢB 5']fX͸V77E[dŨ/%a" ]6Unu٧l,?5u:ղ#bՇNc32yyr>>Tt]3}A !뼀#tt^V]? Cma(:]ppZA 4oy@ P v黩YrS>/]YwnɚmVϫZVe 햞LMۏS ;.]_Eh a>]o0h I%irKMsY5/ d^6=u|XxMUZXUx1/nK_,?Be(BI,gY5W髟EU6Gn$)FmQw\9 ) ^eg'\ v*MuʋtUbjhF;=~ףhoF{chgF;;څ]vvķ=Vލ΍nw'2Ӛ'.-,0;_]@Rտ/^$Aʨ<svj0 xu޴Y^7Nd(hgE5ʣ3J&R^dgJ_gv阈% DȔT!K;Q;MT%3挱Mv؆G3i$v>3 LK@\崍B]0d"L'u {% i75ŽHYlhaNJ@2c~CKt~`p#a| t~`2i@OfБ r(pw {"CND'sTkg,0ADt&d0!6Znʶ. ~ ­0"l4A%;:RkuL|GELgOpށwG 3’MY̳2Ț)|>%vÄX8~w:2"]s9J 2x6(IYyl5^k8#TRj? T-c2TR{n2~lPXM*Fv?"IWkLi}e|ܔol^zԤ7N G$2s*{ɴ}RQ1m@j|LQmO\u*[㩢wqAoWrm'i8 Km3?/!_S~Q~=8Ĭ;U[n}&8hć8 0gq8 Trn> stream xZKs6WNV֕=Ȯ-Cp$NJvSK#; ~~ 'GX2P M *xW'G/Ϗ{-TXs_(⁑p&UpdvI^, z#z!b(ŭQb1LNG  "& " %2,_џЪWXQa,"FRSK(lYg֣$r^K9qbD䊨;rFV-Ce&lKUVԎ+d;G0֮>_<ե7܅DsN^/Kcf0O/J'PDTVlEVl35j[0`a`aIQ|Bz&5Z>o!)m4ҙ!G`ޤ:uT(uZ :s `Pl34prޔ-;Z";WlO<&R,&[I_GD;Wr8 f1p&k56N, ωe'γhI??S"ce9xKsKP#$aAgInܝzuM%rl&m6F7aϱrņ%n_@«[j']HœG&5$tTiS>apd1g!C8J Vqؙ@Bc1""8C,pS:E|+VPvTx rNk0%+7lMWvFy] >Pd+$MnlغIhXB/Ш9ttHc]}QY8/Ue\PcwHi $d9S!A9Q\UR}zK hlj˖ЀsC5wb 2<#[=" {zz]Ino0x!1cV%=2mV]%H./SQ[PޮNoEV 9v~:Szp7 J `J.oPȓE.73O=ɫ/n]4)Sv"DN Jc;_&^!fdX)(кW@d4ZDDv 0eGDv7$H9n L|Wx@a,\ , : M7wo[ %!^ݸAڑZ 0:*}]ۊ{_A_Ww8C<Ď~gY[aV͌A2FZ 8v?D93s6g},mUGGwI(BH9}{%p0 ޮtNw!H"Mi x/U;,W&@ וAC8D7CM:T7997*\cnC׭tԡ7'>I-5 e`i==T Sizpᖊf] N.)_mOWЍ&|X/+ t? (I5zA#Eo"†&C(d}؜̀\h`f` :$^F}@9ScNT7/v:p"+VnB RjuwhSڍn*r:xF`*-<܃SqX(SbCֳ &ix[&eߕ}E+8H׀Y>!hCYc=)ΣTwG. *_l{! :Q 7\eg,n?fU5[7]QJ`?c>knR!`uV-ը.ZoMg"Yi[Nd!4R֞4$`K#:ÀkXɚ*N~S <s8-844l֤^d0E) gώ噵³{u^Y! ̓06L(_ or_ 3tv6؟965#{q e4z<΋q_{/< .:nU'q{"cHLfw7A.s AwgV əFᇛ|e}ʰ$U'e.;O{jߟ[%נlK&[躺C\w^4tmo%~lgQh5bF^(~k=,nGs .F3ZɎ,K;>7:YMNJC"K V $0 endstream endobj 233 0 obj << /Length 2485 /Filter /FlateDecode >> stream x[o6_!*,? ZlpPdQϖ\^!)ےd7ˋ)R 7$CYBP'O(QTYFScpoJqj(J剑p&Ir~(zQY5Mvts YC2bp ~HW#IӟQb:)|W\]v-MX'8+|q+œI94E2Sge V"NrT8#-] u3  Mx:d65XZs&65 ƌ_Lni4t[ӔPP@r_U>k?y'9i^β3G@MYYѼ }eMcp':K7D}?;z8S%$P[VVu ht*(M ]y9-Ia-B{V8[fvBex2ȥS~Wի1,͖iSg9z#-VC:>7IBWơɺ T JmA TA:m$VandYZ% Fg,e_"ƦŋJ1D&zQ2'l1(=ǁ\(It hUU)U! oTŧ2D?l~B΋Ю)zMLб6!N֌'~Xa)a 3_z:2l"&g6k숖|O5 %j1=HLH2KX_cB)%zaaXV15<(X\Sz>45lfEz!rϵ "xDEq 'h|"$,iÌ 9=cr=fzT 4h 1rZˬlɸ&ۑ64TV~|GJxp1xuLߵAKeL'#'y\D/ Ѻ,;vҖyVXd41y\;[p goO=Y|j/F:Y;Vv*[XE~-OG,N r"s*f^؛M*:\*;XI`Xyh0 u 0bMoX;mv xcƩLH:>9An4(~FgaA]lXHghw^g"[}Jk)PmQiP(gf8Bvn^Ϊ "ƞ\ױIɵ($JL%'H X)g0ĺ.RDbs%MC9ƥĨ}8`RFP&pHz@@ jW;;~b ,I8(E])T[̻a'U b`+5ςAX@s^SWSB,Ío-UK6IPCW\YD>/W[÷{_e*5,ԜY9I5 ΒHv̔9}n()S ۗ$;?~{AW+y c[*Yku>4VHfؑ<.Ƨ}xuw]C9pHl#IK ,IT :V(tZ:fa: GI3h~|ϳ#sXZWCwȿauU-v_an`{⶜uA;, @,Df\F67#/e E,9R! ,Yh<Ĺb/AP*oNRqh;$m(*pop{, P)8m^nQv\*`ٝ6 .܏ɪy)%Nռ6p߇)wboy-1bXνcg 7zIU#Kad_U}vjs)^ҭ%w}ln7jTR=-d@& e@q"!9T #C/ǧj(IVT:*324I e2}Nm8;\Rɭ!C3){wT>T'.9ӄå-f`HAx 5Q=j_{vϏ;{ݰbߢXez^TPCnU٢ȏRHlNk/3ߋd͡7mkGo [^޹v:p-i5)ܰ9ÐU{EQnN *9ǡ濇> stream xYmoF~ª*է˾ @UD)j&gzgۧξr8)VE ݙgfy FpBZA$V*i`ɳɃ&29>KFZDq(a,9ImU/(Χm(V+h)oa"2.LJɇ 8!0XN\7װM&oxB^)`4aaNؼf vyá* Muk,ӇLbƍ-;B1OlcfYzTFlFY76euVG:йUͳ^Z^rU(J; :6T e E & [>R& l^nED2إkiyu= l% >ç O&47~ :V]Sv[qhOq3.BbJҼlJ\l dC2'*~a@lXGN>P~ ML(5?qt"zx6(Q W(#]t]]X^ÅA+Dj7b]Ej0Dk:@8@SG{ c',,_,Hc!NG<8JOtP.pK{[tci h.ֆfcgi[qksQ58fK&6$Ɛ]M>3D<,_ExEX`@3*Ye<wA@hU@͎%H%:^4!zpOj.y2 Ų^;mEhP-? ]lfUtnw6tv$Kb1*dJrΫsr:O)E*Tj]0pFOW2p T.QS qmڮ@d& "0`u}1RP1r{g0H鳍˻խa܃gy+bw 'MuaSaW #~M$Fd\&Pe'P~I7!gB*OO^ٵ *xn?̈#X &/<"2}ӱ47Gs!1Ru߰f.w59.v:&*E 2%pz:{ endstream endobj 244 0 obj << /Length 1507 /Filter /FlateDecode >> stream xn6_=*: tCbn= ˌURIn CRe;I#~iht:xD*Ӱjp|t|s"CL"Rd3/񩭛uYz9Mm7 BE!cD+q_*q>4~9ƣG\u$26 |IFΉxD)-͔4"Ưkm ua/rg'?{ c>4jS eצ]5?G Ĉ& $Yl ]7-:q[Q4DOd:)ʀ>BVaȧ,=<nY޶yo_f G~A_5J,YJ,sኚ,]_F:|X?OMXF,(I$g`KJ6@]^*wu,N4;窴"xL) I%BJKEwzUsgrA8z*Uo |ID i:&0X1/flefnS~孮fՐ,ݥd@.'+6KB!ok%Z^$j. Q˸.g;slg  !35c'G )Xɾ ngyY,'DoLNOrY?Vivxx$̀%fk[ݝMSCCPf@iBn8C&mHM:!ǵd|I@Xqc7m"l^<ԗkh ؑ%hQ0+F5V=x_~;;>2{ x gʘM[NZ ޮlW9>}WzG.&$9~P']#{h;K;եl~]ˎԛr/F 4Z#F#Tܩlcd} O$PQ"}zWRmm6xW~`;LrQYge a`im249X_X=Jm!3ޝ9*ݷ;t{^mpZ{p]fBalt}6 eNaLf:@@~>H%Rh}:϶BG8H%Vh9 foRb7P\R-2  endstream endobj 250 0 obj << /Length 1187 /Filter /FlateDecode >> stream xXK6WhA,ߤ @R !- ̵V7ȿ!%+Ivz0șAW3I&(CK"50٫쇟DShq$0ÌrXɕ<$/3U:@0k Zo$sA7uYT&OOݜў3Qq$F&Ú3Xt7T##E#3I۝c-QLdb5&a;MzSyKwAV^uЦ\R#u|(ÌEC~ᔤfC}'ˈHLk!*a1 B|q\Ns:QEѐ̦ͫYTNQ(yȽ% ΂4840&{΃Ͷa+u׾n}BP#*0{Y +Z~0҈ާTjΩL>jt ~ilݷs&!+;$TdHRxCh;a$"C>` Իͭ3é.t(04 V僭c3йam[v$?z%C?RB~c`7z8C>u[]&:bw#ib! m,<):4n= -3s!@$Acmz2!f Q>ċާSlo˪_vDY+=eF6>m[4e0V. eMod{ܺ$pA"KփPuf2X䕷M|t9>CwK\c<:m: 20 D? T҃qWC"xʦ^_UǔeUj_Eq.#Znj@Wz$'0=J)$}|6A~ +w3=ɯHkJ!C@P5UN9$-I |$g"j̇q>B .'kO~>8 AH~6"Nמzl.pY`Q*?vk0 endstream endobj 262 0 obj << /Length 2422 /Filter /FlateDecode >> stream xZݏ۸߿BNbI+\qh jli#ɻ%ۻf=qHp>~# g g/0'4H`Jbٳa"+P!.24S"JXv1.n켬)&/ykXAV)\ܗ&o/&0v['G:g{Bl> D 0&YkaNe S!,¢:M|ݴSfe֦%Ï58M)G͍ieMٲOx tD4?g DzfAbcsY={0|ԋ~iBm)Œxo GyꞂ[Rs]),I9ֹF >B(L'Xg*<#!Q8qpEzQ~/W 9- - - - $98qt<_,ПaH=Q~qbR@KF6e <:a$Ę2LwO ?OHEݢ֢8evTBgcwq0dt(C8u"|Iвk ,=B- %{[$N#6dڣGZ(,S} K Y׊uS.[DXuK,Lmj;WzWu,6Xy}Xμz3-@Ek7Ä6ݺͬ pE7|_wPiA,iHOr!8sߎmjH1[:GxKGt7JdSFDJŽ{ җTͶ8e Tux.*[ GU?DdSk/ҘգXfS"_6"[u;f6ΓU֔;Pa  uP ~(ZK6ݦ\NU4A5`D/֋j+mb2X| mӇ.ׂ3)k|0 /o>BifևfַG,|TCig!(8z|!y\·zhmEȥ'J" &wjDs9eI kz}6% -N__C}s!qz`S&H8!Aj0M57i\/fe0cQ>4'|?;4>Viʷj mY,736<ax>/? +ni@Ԗ(,K x7$Gջ6A&&VM-i6S)䘍|DT$,| pT6t<awBDL i }׬i1}d57U'ރo/^LZ/ljьi ⤱w$"z1[A֥`VڢKU/p$0ƈT Y|%+U5*{`]46QN G[Y.]+]$R&ZxqE%/($P:R$EJ :2R.II_AhƱrJL/ SdpT09 >Ac> stream xZ[s۸~`jqdznI4QYO`Dj)*N}nINƖ\ p}qp #l8F T+5Oߜ0;xDfTfL`5u9_Tɔn'$ȞM%}n"plqn8#0l\zzYzF@-HQ(8|}9*P4klv}Z} ,X1 L0a>2y9JLsgB7Runp(H JR%TLTIPt;O KE2K]-ѽ,jY8Q 2URtGoLa.',Udg=MOfI'(BFzNBhOXB%1i/zzX3|0JrF4dI>4KYpxd9#"j% ^j4{# (~)-AȾc-S a@`ODրrdL5jDws[.ovpʗg[ l -nCs^~p<[_0]D)PI]5!n}D5#rͬv0ru[.l'h:A9mj1n t 4r -°]6> Bk .r# rAe\.Nڢ >CloSK?97@<`"AYb@N5DO=Cs*$vv{05epzRB)d iQ`$?3_Ņ+HLpr pG+Hj^DQs8?x""7ApaP]7G_}Gf1B<}{Fz)4tP"Yo6M WI\h-WCNu{D(MQ'L؁ēj#I4ѩSf9s,S$] ͆HZL0Iٷ' AK_ AR*BDIS""Pfll l0Px}*BUX ^GA7_}xͨױ Z@zn\6c|4aԞ!mYWu=kBݕ?o~O s!h#)%ޮb5]pgfhDs3h0n2 k69gc/.ȈanBUi&@`11Xg dN%cTjPIŠ[ ލ|Ny&@%WbӬ)'Pح@z&@#crX8&pb$l1JУ/Y}q`/LfƤɛb~[,֡,V{|nC:@H q +] b<_mSx> ]1.B1;Akr9k4*:EM3Ny +ׅzFˇH&vJ>B]# V*ZZwh@~CPy`Dܗw8.@oŦBFA.,U}W9>D|Sⷤ>ݎ~ XĘ ׍}7vMݴkX8y=jdջf$gv=i[4kEUnqWK ,(H,.a>8i'z)k+fEh endstream endobj 278 0 obj << /Length 2290 /Filter /FlateDecode >> stream xZs۸_&/\'NI:˜< %tH*v: HɎk!~a](4hzJ#JUԘN^ $\G瑢$Ixd$'tůmQIV\ ƶ|: ^0bp{߼(<Hb:ۧNt4bJ "=\ D~AGg`%"CRE9')#THOCMy|brQ~ˁoM`Ÿ;Y1ɐ1 :N_*٣6o{|k5Ym@wvCX;E>$y}r*LPhU~ٸE)xHn}v㒘DxQWISMݲFNj- 1pN=!6&7$d!³2ncjXU6kl0FܢsKv*u㲘,MYr/Qm+0e PcH䀱O|Tяv͊,aȰUore͚YI3ɇ~{?ŷ7G^qt_!13k( pI( >|t W -- յ`M\jI^s~{ߟ׾u`[sܚ;;x2;!J:] 2_WEh'{}z[g/G텹ʛ:f8+.Ӷ׃żqEFezHSۯE6GbJCFmPkG%hzU B^\"S)??Y0ЌzAq*۹ 9~Ec/lF،&A3 VkfVo 6o> ۾Eaǫ ˼w}Hofcihlݖ7Y@FCq 5͟XOm 3R%OuvLj;=T:'ue>Ve.[ZVw\B]z ^l"a%XA(ڻa 8cppۺ,1OvBb B/X!bdB G/xx/{tN :pBv-[ƧklXȺ;~. :,:GH Ba[!L dKA-ghvoo\/h]m൬\u^c=d{γVvAܥR$L]U./@8%i[ @EQ6o^FݜBcWֱkL$ <5BpB8[oe3 c0 UM|gG喾5A#_M 33PޓRޙ`d͉礅iG (*O 5NwAQA)P@^;@Qr9ˊF@Iffr?UJ u.n cpU endstream endobj 284 0 obj << /Length 1935 /Filter /FlateDecode >> stream xYYsF~ׯ@)/`m8{0*'UR" l4$@JʏOHUYƜ}M#<kNh"RU+0gjbtÀ@#- F@`E4P"JX074/Y2YOpV?G`(- AJջ>@,"׊{j]'4:rƐdqb9hPzi0=Bz} ScaFw{}iX&1[[Ѭkw\ˢ3sxOvts\ǮU2i\dś[ekrYxMeU^<axמ-g@E9;"3mqhy'#T@P"HQhD8?f vOC{ߴ"R_|su޿>;vmbWl.Ui9ŭC"#13;P4Oa!w*)e1~=ðXkt~5$xӧ>}7n HgeFNjwȆkO5~ߞ]qlk #3D*W_]D#PQ$8SQkYp5w,\tM{w]gZS%E>Y%uQ8 #p1`٢7p.nJ9Lpc8F@s?|sջkQ|DLa'? ʪ/% 7򽼃똀15Łק*,z_9r +7*ײkgn$=EgK(w4b4B3O4#Ȟ}*sQɸ 4ϸ XAܹ . LVlm[ d%|]((\J?ҒM2iy}y\&>^GIb8Ol<"2|q}B1o<yu:K˟ ӓ{0 xb0gk҂(܉Y7!5Ʃ{] {@hMMb%BȯȵBN . ـ1q.k9w0:FZBiB;E\\DC~lmADCٮ껟]ldxuI?<L2YBA'p>j&4kҀ 3 J9b\Z` w X,(jOb@jxޚ`u"V>..֢ξ[^yyhEVN!(:54E'_603SZ]'6~^e'7Ub꾷 H7BPԤy5G.zmk.8D2p4ZS"1*!fRU Pk 0=/_A;TR8_k.{y l@}M@.&xz K K8d)\R*1Jn4jϢ6PQH/`$ϡ)JgXjE n>Nr@):3NBֹP&7y>PQrրt7XNp(ۂGmUa>عyl'fYbi˭"n`X(`8v5]fp?`7b#@Q>.H!_TڸBاo[S&ޓVM9e\O<{ng=cM7ys꾪2izWק6.&BQrbb2C`R*" 7i_0)zPk6bPϣDc-Mh>NǴ(qUf8ϒwCX5 ыBn7'} endstream endobj 293 0 obj << /Length 1479 /Filter /FlateDecode >> stream xXr6}Wp>H'NOdMf:lD!ƞwA$\ݳ=]=p 0XhO%RAKѤ7:a"Q( &@`5 LfEdy([ M9x7=4h4AJ}q6dql[#0`Yܾ4~GFRDqڳ DBP":(L0}k ( L{B8ɐ , ~u=Zې͓S?mԛY\ZwKJl*GF3Dժp4BȽ<5iUrȐڙxLET܌vpF溚 AYHHz#%Xt;?O!BYbeIz{<'uv޸2rK&MGQiܠۈ_>;"ʸHzP3"a&݊c&0D TzƐ{D*Ct{??:ߏ/ެ|QQ1v5F)^@<_BXB^t=FW6 h HF-&'~;-Utn 6c_]6|H]݀ 1N>0odG8ϭx?ud~1\!! +5dc{4_Y>hSbdр+{$WW3797NdueRyef_rJZEX@}1c78VeQjM&v4g^שmM*)ͿsiEu ܏&x]f-'.ǤOݣeTlݮrf3iDN/͇,J2\ڮ+ h~-[:Vd *`Ry{@$Ƅbެy0*02GA_A˦h_ə"*[@۸rA;cDn";-!- ݴ=GnuP;A&H}#4QK)!wc)?w䑚qRwN֤uTwN@v-dtoHV))ݟ;20{U@;IpMy7-OU_CBJ; U'd+/ (p1&RwBVH~$R(vBcjkҼ94ɪI[צ n;n>L߹OGb+'󤹝/?B~v,_kqUnr?7un?## endstream endobj 298 0 obj << /Length 1724 /Filter /FlateDecode >> stream xioFW `fd[`19HjdJ4N6͛yǼ, F8F ,R LQ ~>}D,I4}FiJ#)E"u,Ucݍ~wh 8IR۱6~ UF#jN (I(" 7͘xBe[[ݷ`zpaLEݑrLh ]9mNϴ'C+D )iy]7˦Y?C̣zB)CTP@l0q"?1Vþ Zz}.0t SHSMxђe(!Z3>v%ˮPp$Sx_{='udE̒7ufT"NH4!e›P=ؙq/U1O ",av{+Kތ󸩟GR.J< !MeǞ DI29ӷAʕy~,ADBf` A%%rY6&8Utr&wT jLa$z~Q_$ J3|_H0eU{d]8X3^< "{&NF H2yM&ĝ՚daEc8$SPH&#!ߟm̂Gme%P3*k' qU޷]a< b Cԓxoj0m{*TCAnVea50?&n?tNN7^vK{"JC\9B錝݉L5% ZM**]Cc~z^>;v˭g'x]] m L!ޠ}DY%>Mr2X+KNk O`A e?wZrWV/VwbsHmq؎D˿D̐Q)/`JvTs!́ ȍ[aK~vbRHBwqO;"G72m`2fƦXe_i_<ڌscirJ"R/X<ⷒE*F lg-:ҍYV~J4 \Oa.L1A&m_Fi[,yL:oǝ|Kuzq_Gm]_ J[3Zt)@qq~o@jwl=$fHJpZ_N5ݧ0Wז4i)?eŎ3ewU{Æ΄Z%:>L>?,Ҵr0 t=#Z-y_7A^#w9!xBMg$2Ͷ-fY͇0roqiR]`4( Cg*th6Bwy[.OwĎݘe.ZcYsW&LCNM63{$9$x^ː;v`~2/ކ;ϵG DYjDl8WM,e7I˙7Z`GSYKj> stream xZ[6~_!L 5;bAlI(\?2FIdHٖL+C$ܿse,ǜ#E$V*(g{u%AbIep}SD 4|eb&t M5]|=iAPqk_ ~=8|]Edп6,~u}YVF\T $ J\P&~ V;1CF2&jex<ϋZi_ڂmƄr{Wb.SskYR 7+73Ukz:|Z(]gGI6yIԁсKPc݈Fa&:wwYҵ-̽ MnvWʇ랾@6٢0"a:[(|7q.S v~&¯(VQ߯)-$dlu_~$z;QpK"o&/g)s~"[tw;γm|ve]}LdZ.yVJ*I N,Qot@Xue&̴R”SǫO \<֝岿EYTffgbڔѵT@v/u("ڊ`iM7n.cEQr]o_NQ^v*8ƍ,ۑ }VQ ﴪO"$/UR܉Qq"VYv3۴!nn΍X1H(20Q@W-n9 94!1XSB*_NX7죛l+5->T\%<1~HQI$}u-v(*PmXp 9Po$]Bu:jPE PݎDDk}6DوEHECHҸg2y{Js0G*Fa$EԳT76P6Olqplt34yfܰɬĞyϣ#nۼōk\+#fJh!RsOf*`튨jMQTpaGs=Uxa|ĀC@hU?H`A-E>Ty|%OEy iΊ/&G" ] #  3AlI4(COHWy`]7dEjUl'Enwu;#m!3&k{%*.;odUk蒛&=#njek]'+w^9|8C(+&XF4'J +foRl"6n{" @۸=)]g) #VKQ؞P Mh+|h`à'Un4΀P=xޘ@A#:n0`0Fxؼ2 ,8޳s"4 ОM _v6 ]kΆL0PqϪ,"M1| Mf'tzmf+PO% ,θlD[ ŀdcPĕw=h0Lu1"R5)fWnh6{mQҬQB Np>[ԤP^JD(E@ECp!Mh- endstream endobj 214 0 obj << /Type /ObjStm /N 100 /First 904 /Length 2290 /Filter /FlateDecode >> stream x[]o}ׯ З.93q8Arm PEbĖ IM=Z9Q[KV wggΐt삋U\̊29V;W89q]%~!Au88 ͅp]L# g5GNr1Lh=q"8%Iu*aՄ7Z(DRp`l ˂Qb5q9SBxURWH .HAeeWTaJ7$d{RͮÇj &W%tjD|ZbH-f6-8(!Ytw MLA20f1pG|,kZVGZh F61.`nv[qd&vd+:<tkx? FZD/qF;2rjDgd 5f12i 3X \#H GxɨrӺt:[};0:ÛeϮ{3jҽoLB^ A>%\Qm~~jt/iLis~\i]&r6f<4.z9]-#/1br)ި/r.w]j[ZC np}03?oy;$`|HN0ё(>c$KE9VQ~6ԉ,QAGRf{NN\sk_&>cN'-:Wqq,>íc0ed2#)$x]+k:^ěaI&|sQ9#Sū ",qOu3^\^]Ox]~>9Qpg׿:D.1LWWo~X.Š *aH]NJڇ1"ZYp%v(9OfndT2h˂|Grt_!A-ZKRd^%m E)ӑB?4HD@ GU1&u*uHUS s~^67q4np7 /DM>u'0( [G R#{)KXh#V/]B؜b"8^+,6-h-%e=ᮗݩ*|C^ukn2MO;)[ }c y!tH^Ȫgj$\YeΤxr)Amaě 8m#1%"qDYv_W,1Q: `߼QuGqo:;ᕶᐄOdX⾔L}'Cho7؄S<;p>Ռ^XwUتopEhX5PHQX1ZyET-%/uU;^)jc?.ۋ}zK^ݖΔTwt=fS-ד'&S_7#\^lQMd*-%IIaὔ,}6["mk*NK8TFOnTl;mRXtA^W<9Uoؤ&-{$0w"?:@!De}l@_ş endstream endobj 315 0 obj << /Length 3220 /Filter /FlateDecode >> stream x\ms۸_I;Sjx9];%fC Iv}wP")IJ~"HXb_]@ :& %hj̤zɟ^ 5IH\\M%q'Fr™\,&?GlQ.۴l=H3B̈Q@훩OSI7M DH͑,НICb2t.~ismڇIdIy'6byBg.g뼩&t.4MwcVΡ*U.2㍛EKQ֜r^_z@9KA\hG3b<GsژbLT[rBJYbtנgM\ĹWmiݼ,4+j ʻ_Py9un?tF^eۻ\Tׁ7?>k.-Q-Xf00ѣA|4 sZNu\ycMo6:kZ%ZψHЎKaRK)J$F1>5D11>P14"Oc1H 1XA!A>> 9bClwᗶ0FE -Wg,zq/s~Nu*mb30Y{ -,*d0_7]#`jHZCsMtop :'>vQ0xzc-u+lTO'6XALk`#EEYq:d2 ֲzü`]u/]V,ϽV}ZXim-D%E2PP A {kY؞b)o6O:7m,o848ۧ|5gb&D5{.Ӆ'fȈVJ))XwMĵQ]@eNSj{]?t9Ͽ  h`MXS\?5/$="kzGlQ~~ڻ{ ~$8ZzMİ9RX: ty?ᄣ%$#h`[B?|Ưpg֯3jOndyo:)ncxǕ[yg"6>_mc*yڍV$J3|P 9:xchd1rGAt'l4t[R^7%lwh6oOk\'|P\,8ÃIjlKK8x 1I*=`7?YM|:^>=Z8,p`kapL6{ b nȐHo;L JF?!WhǾއTa=zo: @z$8d|-KXIY1\Y L% 鴸unϊGw'lw  PXD!9;#V-B*|" ¸I_W#cTLq̉A $yqBR>G#,~3G=s4u^ 7|RRlݦW;[I<g*{!DnIgs #$D~H$$'l`>.scy.Vo5Xr7P#O^T&M|s8#UzP?L[GƅwںBes\5cջGU lb;8f]2>q°ދ >ʩOE*M#DcXm(C8/ D%:h $urHcv5Bx$`/V!2:h5H,hY@R9'&I,! .9t.q{ 0";g]3s<~KƠ6&cid1$Az: ocO )5ayD֛ 2 N~ njq" >D6M? ¾[>`p0 aNcXr{M6vRGF#<\EpU`b;DCX> #%,m;a=ȦpIF- ɍy=ٮ:VxI1s$VGe H*!<}l> stream xXYo6~_!yТYH6b;) YKj%[Bᡵ$P?Xr83|\01'4H`$|e *Xްt|4?=?d"Q(8FJ@r(a,8 tQ.8) Na$D )@X1>,ï5y}wG‴g#gL#3ϩ@$U .FJF`bqOQ#_ƓӰ*?= q[~I)?_oysDD0(p^`֭{U|VI & ,t̒&qTZEQ;sBY"YR M$QqdDe8踙f͜!,]҄rR}ǹvsЄbY3֛4+=וI*C&zȇ1*L/+vvш+J3yQ"BßWJluǛ7K6=y͵)Q@ &`M$ W@VK("0^(Jy~kSS}3\i86J %kC$ew7x1Ҳh̯?60Ľx9mzc %z[uHb3{u}k! /MxDaX4GPc鑋g[.L5G[-Oo endstream endobj 331 0 obj << /Length 1665 /Filter /FlateDecode >> stream xYYoF~ׯ Dz# E&@17(hj%1(ȏAI(EZ?7#L\ 0†`$ Jb  ]^ ~f"1H*I"0Қ&SD Kuza/r:zGAnq)R_Nr`~=ˇjp7 'Ց8/SQ  ɒ&oEu蝧c;G䮏'&_D,_ʖy&rц]͋IacH{׆;QknABA O R.?s Im7!k٭[U8~,pe^,k„󪸁ry+:LnjM廵hXc LрIΗBy˲}Iem+W퐤s*µCFҭ #kQkd ~"}tΊyv3wKeF5K~9Cgg.h+:4\!Y#5˳:[4ЀU(jQiN ]֪o"WөF'_iBB"L')M !.mN!NǜH$S1x8]B=`o3i]ٓ)d{dEI#U?t.z"$]tItR=cqx.ҵC!l0a}N ninC&HU[#hDJvmM}gɱwUqz TJC1;;pN]vݽv> f\kX#j0ڴE g1'Q0'\ZǬi>]T#Ed Z ^.f)3=HIg|2X2!HavMKV:}3أuŤx 튋+٣Cb)ښ.oY Y;ۚ|Yu;_$# |O_o "{ 3jcŒ#y NP._[׏ "c$ Lᩴ,NE ,Kx m`!`-1a-cvJEFҭ8@|v3XwUs< \[J0b> stream xZoF(TAM$MC?ƕhrI)ofgI8Ā}<~K<`󊋄eigfmRC ]/|Bg%eΉ* .ir,墜l4,-Lo3aHףb<Y$ۿ]e oy4g'6+3md,W$g/ ^-y 3yyƴ'{NFccH9&9IoWWSQVg˧04jgrAu\,0#.x>^pSϴ FB3߰?Au5(i>48w83d4XGߛ3D>I3w'hĒn;di!`=VN!Cug7ˬx\-һj7[vNBeJ:%7iU.4Dš K%8B)e:oO>"n! j~?/gբVRLo^w ϖ#+*]P%vEg[,ل+`aqK8h@q96MVpZN?ºtY pVP$K/jJZmc/buy%#Ӣjw*n;C˜e1!9Қ`),H*ޢmhOlP2ϯa?un  DtID[R]tCE:I]^o'ІV2D@oLY%5qS B{ 1/xyL/<^5EYjs?d3@3sX/?X9f9WrTeKV XZ# J9PA]yjJV`A!"o/=uE Zհ%uX.ݖEHM-BT,b^y}쨧BM6PTA;ָ.Ccu6S^:Tga90fSQH ć=<= q|q LBL*vš0 P Pî&3$z~{t m#zj<}Ay:>a:_#? '{sx?7䂙rXL"dyh|T{_݊ Ħ.>AAeb K{ ^j]frVv+̥FqE~(ƅRgX X*T+#!U@/ ܢx=XCo0ÜZg tt(j#H|\CCfrqԦxh "RsEME\ҬwAETwyz2Tfc=jtDm. c[ q1όxڬOb]؂.Y.e(`/t#@t2cAB~''d]sw@ls]Mʁ9^bb^W^ߢX`mU4P'\PWg2 0?C JE!MXf"at(L+p^86gԹ`틔kYQgӯrįA@!37biKԥ ~GWQ/A+L)G y@LL! '<lɓa 's)%z_5bj8rB-Zrw[ª]vӢ[#={N{N,tW&Dh+v ( sR/뉟XJ}k+7.yp$ro~(OnÏ=1[m~ T V曃SoES0p>a/Ȏ^OI-ZC 1o.B 񀣣=Yk۪I!Cbs G~hЄM||_̯˕H/j'Ku;_ S^T6O-.c|mwkm=K1EE}ЛK#\A&.=B@@Ǫ{/y获Zk[;wyM _].#~>w)`WY F endstream endobj 346 0 obj << /Length 1653 /Filter /FlateDecode >> stream xYmo6_! I"Ul0 -,Gq6r*)wwqR'MDxtx0x82Lsm /NiEp|[=Xdg8Iwn=Dvj=9pI{\KXdo܊"LdڛpB}wVܳh7B]TG(NJY DẾ0{=~W1wKͦ%%dC: Ex-1׊r^k>h;>SyO5ei /? =NPE>C89*okܨV6^uu7q^nOvX|]vj_x„R>ayJevp `_(÷Pɨ[eD kH.'pwT_/MQӋΥ6t'B]OXsPq7+EMe%QЄ:jBs3GfG+)RvAs4 'i' r81UHB$WBz))B:#.ɑ8MO^pYț>{(1Q2ܫ4E Pӌ\QBp[X;2ɁxHHe9{!]b{%~ڗ=/G Q"R@vKLVa@h)E&M3TJl uh!L)eH> stream xXo6BLbD=mfJhDE?،-ԑ\IN~w<*$ut'ܙ;FLqІC{ы|Orb2psGqE }ɤ|朸rzTTDpWC0 *B{ߌwco6qjnw/=vA>8 ; B&bL/F8KX0X8\]S|"Ё!`Qɟfg2/+3D-I~B\w{a[J]n]w0NH Ko,<)~-ێϩ]j-OZMNNS{DI%YieY$8MFY'?L {ؗ$ٟ9̥`%!ILg|r;yCS̈́fʪjP6M__ \1abC(5;/op.ar {m耢1iS=B^"$7;cZ'Ȥ.ΘLL$b72diG[ o}f=A񨔁Y{,ŒA [83R2c)rex< [(,?*7A˨RH'oO!l ׇp8*ܥBXxy<`{7 bx1ژ`X. 3%SA_J9s9ENDqP0x&$@o(ykKF':41 H_,j|!G!?B৻ 'SC k YC2[6OCDa=ʽO r9V 3I_SfyQZCUiiexTTѶP#LdYi) MeiW,VuQYW,yU}1XP+֊JFpzClA_qCxtO|,@߸ )c\pֺ euY//ȪF7P"MNbW Ұ=t﹧ +Z#t5ki;ʙ.܊Ķ2A2,]2] ȊR \UOX6u1] 瞓peUW_xYقzea-(lvx\m Q oq"; Cź\ZXԠY %^USBE c|)XBAaoz@KL vڔ+K]ZLވkkjj/Kue[Of2Yr]z&9CoQw|d @A9OG!Ԡ_9;LT"lI8 t7j6pU1P̵oo=\ u LMyn 1= Yi 4PPAZGvYWs9khW,Ζz?0ŗifjGeKmە%\x𶠩pĪFܮ tzvpH ,15FеP̆`>Ҿ\ו2:\_}v, Sm)8g=!|Xo0tY5Es6oo&\fWI~:@z#yWKܿG1$;Z ;=bZ>'=!?z{> ~]3 󭵒oH,R endstream endobj 362 0 obj << /Length 2488 /Filter /FlateDecode >> stream xZs6~_=$N6D>-^$R%);vP"eJAX`~ 9$8IH ʢIeTgĶ=4I r ASRX},M_g"ߎ%Eet[=^LO~?l^ǔ*",%4S)JDN]S)RFR!#Qt3MD3B(J~Ad_pZJ6I4ٕYX74aL9RcꇹJPz"$e 9"V5wm%b@ OSyS.w.ʶ׫ί/SMaMz~3oUҁ, m&*~?ȡrZ׍ͻ^߇ &4̓ ^TE]S~(#Al0͑}v{BfgsS0c1/̼W l1S j>Zd6-m۪k6G\agf.y.qh+|B*B~xI 'f?긛ƩSNFk}{֜7/..| ^ƶGPdd[iB3MU `jnL9߬a'4dgeVXSH4gsmh8іSp4udJhfO<$Z,m@܀%[ y"`&*r ,I!U, mTi^Y3 "~ow5"EGe,g&|+!Ju]F7\R/0C.p @:ZԾ l iAcb\Pw/ VJI)U#(+:}#^Y`f\eUv&ȣuSžs4`U݁,k'p` q&V`)^d/+_U럞O;9u?R= +wAҽjá96Z®v MZ7y%ݽ;A5 -űڅ/lz5º ~W . pI=3e;`6IpcKmCB>{D R|\u˕{x$f{Jz.P]Ђ.j -"I#Nar >@#: wumG@c=VX0{" ěSFׁ Nr=,) R:CD j&J{wgXI{;&̠PmdiƏw1HT6Ӈq0[ @rhHH?- i*܁sNzA:wUE`}RMScj0&> stream xXo6BH[@joCW`PXa`e&fK$HcYcEx/GM0ša$P |$`xd|-FZR"R4J8EhNw(yv'س r"(ŭ}q*p|qq#hۊ''t{Z#([Ol?D30*M~~h8 +t&1)k*-/',ps\uOoYԦq,7+Wee&]vΞ H<#$Pʬ򺱢lu{6AE6o+eBB*1(Q$P3N;wFCR s@lKvob^?97k}W8o.L zeK ,WL)Y9WsΓ ##: ,î%zʄ EdE2$1 :ЌR [ϙ$A % OWA'3BCװ`,Iab7Xj cROo >Y)g/ޒd+w&qs*bͅqK>~hsf 1Oy [Ym)0vؖVFejrwcdɁc/K(e%yƷPW}]nB]ߎ<ˋgA{G@yx8[ њ8i)3(AxG8K7Pf~S x;Ha2 Ee8fF .˺+sR e̅ǧߐsqFt|u]ilx0P&yZe.6@_+"5"p_!H%1~DzcҺ'v9>uohRQN)QI=Tr[)j+E|2i` seL띉1ǎU"~Z).{TH"I7ꎯF%o[b An_]b!֌2s!d* jIDP endstream endobj 372 0 obj << /Length 875 /Filter /FlateDecode >> stream xWMo@W쁃#2[EH AU$Bq@N*8Y{֎qVm.1;fw=g P*AZ@kR8stzeIf&tuuGfvň.Au,`No3&Jgk OA|APmJlWp z/23)㬛*{3`&|@4:,M6ϊzv^&Enʉ sZN 1We A;k-n5t$DZ0ɗ jzg,ù⼅ù8*pVpv1C8"q,pQ0#C8V)aQ,8r m:`U6AG5Q8[\w_胬\ 4n5f̃PE+쥆jooTZkݗ]랊qYSP 4{ʝԎT)roSjRqn?yhppG endstream endobj 377 0 obj << /Length 2826 /Filter /FlateDecode >> stream xko8{~,jp@%.8hk˩!G8mb>Dpy,g'e6\d3edRlrrQNOjv8|TԇO} 5@^0gKCG&g-LvLxM.Lmk~Y'is8Ώuq(F{.VE>!ӄ0 d%'4IÃφe\OH l6,͟`֏O3̕ːYǙtq3q#?߸(|Fe=BX%IU>p#RjjyE;=CG44JY^ⲱLz.e~6{P`}59^dCA2gngbbgSrX:*foaL`[ki2%"aպꠘUyñr4/?--˙YD) QGhه2> ӲVAF0!}OҎiMpLtr7}z$$O$ *c7FUf6u[4i~H`hhz4MVy5,jT?&&HIj{/OQ>̒d0=j8IfcmGzb%zr==h4=nY\e!){һ)D@@XbdXG@9| g]-hgt$= z3@֫_mv,,Jư p6yjMq58)ur>/0N1o'D:O ^VEoRϲ8O]&Muv$di?*.Sli@.€:8EQcL\2iOR $]S "r"y+!S  쪘?(Uk:T@g7KMT=st~4 6mF!I;KJmM'Fʙkto%aW޾ dЃ; PVԊc tLPy-Q R_ETLK4q0lb/}L?b{5ɼCe׸,Bu+@)N]/Ww%K@.P8L}9@_)1H.bxCF 1/d(tcg..ʦN2Blsc">iR;)-)VuHJ_P){,gUrk1Ə5&TW&nwN.鼈ɄHyJ>.$X"ߞYݨ=GQ{.FF<C~o;U"z~H"G&*U6I>TuD/EQjAMj@>ڔu--~6)t5$c7^K6Ӷڠ!UH̪թZV{Ӄd‡L 8P BJz|$4`_P~,S]-hL ,F4чOyG˪iσe^9hd8jR V7!kωD쫮)V`2~BىPaKC,WCdZ 3RgPÖϜ.+ŎMp泥tjUxxTzhhH`=}ԭ*t%TTj* JGnJBSIfQpTeS{( VaMS5MR{@ijPA[> stream xk cu*ɖM:{a?P$I}INlf_3a$>DRHoIB J{Ri`8ZX~`O 4ґXyF$^jU-;MU7Y͕m7} ɢC4(B?]B>SnB7 6D<Љ_]ѰY4s;S>oʒ3N]V ؖw o>dEݖ<:pfmkTH],=tjK `g9px216xD~e'Z.ɎApw 4,7id!xfJp97ιpѿ?Hv:bu>FqHI40h Mە=KLCM4;3AK) Z7IpawtȂ=P )(!}KjyA!;DɐBmJcO>oҒ p@0%4X#&a\_ݼ~s &CӝPIq }0`24 #1ÄaJ)P1 Ca0f $%Aх yaV!Ut9:h,:vZ |Qktt%3I:eR哓C<>3S3ewP uc{oꊠw|A~5pxW`v6o2`ø$~r;r.6ǐOd!i.eM8 IC8 CH~mПI+y($cC<]HC^X}(AgclP- %DzCT r kVouE8]&u9FW@MK/iA6;׭x|( =TO#t/}!]T6(R 3# -W_ yxM['bCvME$iFjr%rO R mɍrPM*rfKlo]{CB4Tޝ\*©|,e`YcewOFw 2mV혅Ã]5YMݷMI t2XcP(2sjv}8"ܶoFUnjSĊಀTЊ/!=avz3?hA{T}KP{.@S@ԙi`[m6!蕽mxAQ=h%A農5,vhwbM K'J׆)h s|?$T.\C QXmg.o #ngdXÛ3,q]S%y(6 N,L`X+܇P;Of;<~];(ٽc{gi/kbZ3<> stream xZOF*۲ӹA!RVQ|5Y\`F76 DUD|ͻ88a'4H`Gp$5C{F߼b"PHI*@`48E$8 ҼXd$'i5>:eiAv Pkz;8|08|_Gֺ S(p]['Ѱ>Kb Bp(+++֪{U?.F#1TR t48,,j@4E@Q"b HՇbp $EW4>PR"j#NいBʮTIiν^:+r$ ̊p`^(`i^y GQyl\\IWJ-%'~V2jXY>s,oJ2=Mˉf"n@W@8ЄR("WN"* "_wbҝU R ;)#Ds/i8{bbUZIi;x1-fBvZ!gNwtD@GOߔ.0`kfK KAB"ubXfb4%em<"5Kbw ,.ue\rHr   =mO0HeݹBbXx8#Nπ*ŧ0)F)B2+q z &+FrOǵ:|[Ϊe($Hz @OË\N#^yEe!@UIYwm2=g‘Wr<ᜇi2=wKY8KLԎӅN%t9c}iIiyAn ),_(nU|pMfγҺd|~el8U 8^X5B|/g /CM BCSDP838:rk5XX{3!L;&Ilb/Oh~w< zI Cn8,PS{"k봧r:OufwݪL0P ҷXq6($@ DĄ}֦EHL_6\א/|CJӐ(ߐ33u .jZpCcaԫ jgȗUm T#uc_ҫIِQ;i/ek"f/g;;o/pǝl6[ N.:#>.btYCeL"nC\SLlNGJyU[ /8CoHt9 3O A',> stream xXnF}WMF\B%QQMcMBm2PES؍ Y``ң:x@xM нͤ4흼*pit(J偑p&28 'Y^,.Ly?b4VTݐ`1 _^ HvQrwכ<}1PKYpgo\\Y Y0ZK+mv\b~C1~8s:s#h&d2Nǣ4%M' 20/E𰀴S%?wJ2veQ@[U8v }3sǠ*-4n{1f_{ڶ\iYCnAmxp$uM{S_s(_gkՇb1[d0#CM)3 zAW_`vBJ""9/}Ezga6#߂ S[tFCGC:#t "&%XMi'u1߶(V$,&*;BP$-|k[1uWX zߋ0܈a>A 1t_Y(4=*GR>ŀ! RXVR2v:NĊ*-H CdWL/ g<UAp*61S<R!ӂpE1d}12 +aΔ5^ }{!\Zӎ2xv-LV0VV4f|kdˉ06C5ÉH4t ɉؑКvc 5Mظ Z+55a)~._%ImO<23 PnrjZ2!R1GC3[>1)b> uRN<//'{@ϡS S _ɩ/iic_m|ޕCuwg~RBMh^ endstream endobj 398 0 obj << /Length 1748 /Filter /FlateDecode >> stream xYmo6_! *o1KR|6Эkj`ҠSmVkK$7ȿߑG9iX;*4E4:ڣIԊjUu|hDF)IWhIJpDIt٢\㬘ƶ~ۣA46V0h Rp{zϻ(^ݬ/x~XvJ9D# . K5< hKu ;II*)wa)TRFLF{}m"[>K  8鄝HAMH;F~{4Aptx4:<<>{}_JKEĈ ~hB@  !ך.b꓊ bG~w1&j~kh@xIPn鍀sI`W$M9 ͊ $q3yl77\q p)SqT0 rQ*e;kyjE$yT_@/ Ha74|P @WFx|N;7y`w'ZBgM $xp=:*/fuB]CMʷ=qcZ*n-̶Zo_DTumH.[ئHA{ M-M-Sp~DS´$ze կ’}hU͔v)[uP v/)w6u\5I»n$4:kc,{Lz\`0]x9vĜ b|fm( >Du8u`S(g9v6jxޛ.o[ X[+{Uc􁞫^H/ScbA+cNp O[IL$}x"6>v>~HCC cg u$DZ8X-87Ķ\ Ybf1P ].⅊x4o; ޹ UB{-ƫE<f٬Νw+K(T"Mބ2|%1.?0{NQ"_޻\hsp}W>1J|8QW`VF])wnc4˳b׍Suc*$~AjmR |ltgjBqOt^i3#tY֞ˬ]l~lgn(Z6Ā |J6Swjx 'is 5Qy 0 آ,@!{G yvNA1XI7lcIi0tJkkSrǽ"{oU7D&b8i+Nuyh~|/[W-?n5u;^ƴt7?]'^t=rEKjY]% 67e_aÃdakx0$2%,"v\9n;UJ~凥k]~\\qa 7 w-&evv耬~n8ٟ-S> =ld\wyl쯹C='Żxĥ!Bxm?uvR"o>+\}50ƻ+${ge*%qջ#"*=BZg $?V1p endstream endobj 403 0 obj << /Length 1656 /Filter /FlateDecode >> stream xY[o6~ϯјUe@ץ^CҠPlfI$/Ɇ-N%Q'R\xH؛x{s9F %a7?̈́07{#'9E0o07:͒xx^`_o؉ )@]뇞AcC{F Ry}W =R{T J3a4*L+'Q(05 aw!A8p0dn;?mHgqQ~);/HR %s#xv>!1"#gQ%8~ (L5}88KB֍M\[B9Lv:8r=P9W+N E灠  2ëVAOI̼>'HPjD y_JuT^JG_X BC7mcr`Mzy7GI- h}{XK)eW[PDžm##%`_dc6~x.P9O"d9pm&ng=*+ f,~To _޿F4OKMiz 3f$\ifEl8= 18HQ(+*:.`8V)قtخrQD %A$&vɾosr\pe7[3)C!Y@AG2*73i<CWyk?wk-l2lf0;šP[i6']Mu2(㜛ݸmvhFU,WEP %7mj%eEcK?= LȬĠ@T 8mŷ]36Ґn|3h=r3C4;2i/0Zڹϳ F$:tmKMc}ۧ]Z#]F?CnlogcFq1!iaC4xtݎ:0l||l[*9t]Q9t2,]4?2+;nO\e;SSUjgdw< U;7c%FP7-S*u[>eoEɠu^2xiQFOY̡X٨.af6 endstream endobj 408 0 obj << /Length 1622 /Filter /FlateDecode >> stream xڵko6V,"%k%jEamZrlH4H;T7?'!F8 E;H[ƽ% /=8FqL('_VEf|z{aj Zb"Zw0P2> stream xZ[o:~ EEp\ ݢMR֖~shpcY8F3pdgHLP6z"Tpk8ˊ]FK*x=$eMiQѨgX0bl":I ӘdQYfʂ(' x!-9#M Ip7A8 Q'eS9,7Xt(Θ"Z .$KԊ8CG?qL -&t> &ft`I@Ƣ dlL q>36MbF+ "9G,I*(2xU6c`T2@n&\{' dxSr'/.: ԝ"Z qѠ#SƠ2^D9t֝h&˂K -î,l@&"R} $cʒY"i irt4)>|/Uq\Uu3)NMhSxW~Q&e9kG:ain4GZ]7xcy8>:j_Ϛy]Wϗ>7z^f5kꅮtez[.g W v.USeҲ?-ݧgE]+J6d{jё*ΡWh; I\yx6clm3~ٹ*>+c&)U%y.Z֫Ŭ\ky3TZEos9jy?]*ީf,xrVg>+//NZh"р ݭ,TZ [ԵE Wصk':kq, t3VG8jp31ob;X#0Ƚ\f'FZL-n9]~U31bpi\ s˽EiI{tnuw LȖH#!TӆyPdo\͓faĚqIy^Q襱kƌ52, CՄ4!kH'IY#HtLoF4i`˛rj~c X;"[:}$xXƏgsSڡXg̒GeQp~^1qF촕3n2:ØӯM]-ZRWeS &aR'9k+@:4R*->`]^{^^:rkkk;"H'0lGuLhӄxkQL:W3C>|;oyY-ϧWKURaQn$5Sn˰G=iZZ.mc|pCV 냜8؇y)p:ܝ"^lNu*.h f|2b^ȒX0N:xWe?X"_nL?]Eӹ*U~m@)iy^d7 B\lZ>ym'j njcl{cr!"[dÐ/%@= fTِNɧ A{ւʨkQHŬcS?휚Iˏ[ᩱ~LO |ОٚA R]>+QY9uܞbr>ǝ;z;z #|sm{}ڣ')>mLA簝,9󮕅glh!u1+÷3%Ah%S3 8ns|xNGu|N!:,x1/46=B`3&!9xB`CcSϚ?*3}Q$^{hWIq0 endstream endobj 414 0 obj << /Length 2147 /Filter /FlateDecode >> stream xZoBOJ{fn:\8BD,e%9=C-Iv@4_7Ν= u0Xx Jb4;8f/tG`yQ"J3;7If8~`7*oaKvK;x)Tڟ/v5ؽl"i+W7]}#@;Qr;tOs*#$(.r&{ؔI+b_|;' (A2v$!𥘻R7h`uћ ^˴ q8(#ӡ p7CB 0CxiEI4Ҳd]j<8&j€8.$c-1| okmǰ̑,ce@mz + (2m"J;t)$!>bRܑD@xS$bPԊ; IR, 8KadQPVtQi|GqZI^mYUbǦl/@#[_|x|8$azt>7ӭ-~ї8d95eӇY4Fck=>q$ۧ[Ψ紿gc9+ 6nJx۟7?k`BIĘ\/y@wͫY <0«]99&i;'dBvBxs`HAyP'QkF ~vԖ҇t2p'})' KE(7|iv+mT ̯0KfO҆ jTGe>e-m*0ܙ7IG\rN>Yf,+M<?-CZo-% P|7v}!A8` Y Xߺ#@#-tuktciK*tNO_ \q&@ Vuu 9fMs\â7rDТT0=a<ڔ yg8`KT_ 1V qy6ND_fQaC_jO$ȫPXLUAxv&xT`C3`fE 5\;ͪ_7̸=IacH;ľԅ 2  r1D &LVsm!%i[;s0mLBg-.\MRTS. G0Ǻ$} ຟ>$QZM#)VГRqgAkzAC|@(r!U{Nv3 wT L(G bX ْ֥\wx>y·'?y: gGo'7/P]x4qD6&}uگdofIU|&wNot @zo,Mc]h֋f8-ףYZml8ŨfyP73!Ƴ,Vh̒r?uv=@QYFÐ螃A_*UuGvI]p) jo$÷V#G0?FFhUcTAT:ˮzxljMZ^Q]1*FB O2dŇZ&8:<;{/$: _kln *\yXro0l8Z Q*{믰ܵ徲{J;>{n@jðwֻ,e: i%y~w1UoC/^ߚN?ӣ≄7@PAxْ(([U1{D> stream xڥYr6}WQ~;Ⱦŗ8iR/3iS̚"N|}@QdCL2Drw{Y GGp 0X ^JE\>rzr(A2ZE8Q¢286E]fOM}i;`A,)^oޟ Og3t],Şkܗ].3PBeso*nޛ}^!T,!pns{>_6h|L:0,YDPώqk:|.gNܛZo2S6k+ؔ1NM`|O{$]}gy׾t PޭSk$j 7r\k!xqƹB{P<[ɶ?dc)q/{["}RB`gUQnxhK 9EN4؋oŷ[y γukf~✄#␛HD;CkCb3F*<##lrmJ׍!fsoxpceghX_[GbBB//@HUahHEdu-p՘Z̭a\ԟȁ hbUFvt@Ɏx6eu"]oе1ƫfymc-tkF}!qSO WU, 2x;*G>lkѮIhs!]4F0:]|r IbKU!;v<|{9f]0c>omx4?,GPc7ߟoW-4m2x}Y<i;c(x @zj;>a=&B7i" @-ULoh8%t?'S' &}rWg=G׽pL&WF6ytB!!^7|os3V/B=ige|Z:wek!H@1ȓ,o\-~ъݩL-r@ 6{~DMo2ž#FL&l^kq}9a %ErS+vt<ҲV.0I@~}0a0$†-WƋlj?,A 60xcxq(: endstream endobj 425 0 obj << /Length 1422 /Filter /FlateDecode >> stream xڥXn8}WQ,{ A[hhȊPYtޯߡH:&rH,"3s" NN0š`$\J%ͫɋ&2YQDq(a2-v]sӔiX|5HG2]w_SӏaLO]z1{B`[xF(b&z9hPdo[MЉ@TK$;:/'@X. pצ*k zIKͪ}|eU qޮA`#޴zWB o6P0e<=7~y X`Z‡ 盍Vb$)",*tkENC?N GEX<2i hjIM7\ D'ӷHj쓞83n}Hd =08sy!IAbț˺] 4U^ha(1U˂S@SqdYb|x,&~BL\5@nͽ\*?*D>wt"ˢ)6ukmHD*$H1I=Jk͇(e PemDsJWd4T03x#jB!Fצc#Es{~v!a5)HhbC;5cUPv=X2((\3O3f-:k=]7%!e$PY:'&lgukպkpTT(Udί(n}9ᔸu89'qD6䎊ܱ "(m-xXFNL8*R&wN?@h&uc/L3M̄Ts۞ z:?;'5Ч7(NԵ{b5YtE~N![A@Yhlϫ@ 6cgfJ^~딪Wei-|@访3A''”0L>Kh&;7n.O/{@]mywaΝnu6"Ag1%)=<5ͥR}@iƜYzѮl=x_+/߯f(ʛ m:L+Ё-rWm]R:>^}j,u[[B( RRw,0 0A0ǥ3Zz1Sy endstream endobj 441 0 obj << /Length1 2291 /Length2 8469 /Length3 0 /Length 9725 /Filter /FlateDecode >> stream xڍweXZJwICwwHww0 0%ҝ4%%%tH#!- gOO:* m6I+%XgbHa@m*ʦu:899991a` u[WB-psr" T]]6.& ,6GL?Y.޿VNѹa.L@䶂:{֘jP80JC7 { *`w.'W/ 3B~>_KCRwH!}2wH!FC ] .8rw ! wxxJwS!(!E;vA.wE!h!;s\tBpѿC.w$5@3? W݀xQNCD@8qK0ōS#:` p{5NQ^<'?>D>T.ĝqǛQ-.Nz{ ?zgW=;D{1s Ll C䰁ys T}'D5w!x!܃/AADjGrGr! qulsfޑFĄ3E;5"vBrC)_2j"Zdz0.?Ol?B(ley"@"͉ ъt|/ߛvox| .Nj(b{/0Zm >;"ݚ!ry3\@P}Ep3D{77"=gD$/0o~b4G?ޟ7/uU#0p"^?G{MKJ fq#3?b酸}mr!w l A 0g oSU݃2#><<ܫ׭'B֝qaH= q˱eyϺ6QOLUǷ:֥[,c+ںF|͖s u4,Jj~1x({2Sh[y sdt =`r ","lH@Ǧ pвokm36\YL--oGY>ᣍ® L̲dA?£S.*vv 45Xr #[xanf? ТNT繺i1&Mt j6PNqTŞ KY] apI[w]4kew͸"j;| ! 7ێl>ٜ<#:f4EBw}:TqAUC鯝!1d⭌$?ǎQ7B/&=u 劒LH-5QӄG hg'γ/J n@=%{WQ>n\; 5蘷ڻ)ݫiO<pE`$h*_)Dama|q%8t$ҏx)i^_՞tUX` ąNbVG noztY2V`{iQVY2 c뙿~/y87(+_vp);xl^9k+0W4"1qA㳻ScWv)EҦ$?߬6XFܡaXdBg2~%{pISd}AZ4Zu2QXz}}!Ͳ|kmL{hPCWn;;`^"ZAJ\aduVcފ8<cZik]##Ht٬kQr1Vyrz{E0TSGb_(~gxAczyëUj]eډI$IBflQI-,iSyr:5ZHIaupcsիiV6ߊ sHvhPʚ3WhgT閽藣\o/\)>eNw f~e c{t(ިיtRdy7a ?) <4P-P^oe)̱>|NtHTp*"ˈoŦyEX"5䔑ݼz8\QQAk/ŗUZ~l4&;Vơyi5FaES~ &fa Ӳ!2%o ٘r X)Jܨ2vԄGgHq o}XOW} r$E|D4ZrJ>RUkU2(E+jC(F64+ɶF]QutOA[ F^W閴:i^x|2]o_V^IP|22VIbpCXu4SvG|o@D6⚜(XxӜ=1}%Ҩm݁Yqg-/JOqNb3O ӧUzK4mcsru |h%c"+ڀ胷hߍT`C6WF!m?E%aӉB-b!ņտm齾ѻRluc>@jvzo"ZZElS₳8^)Yk'4EBBQ'4LAXt xdW|: ůe³(n58Ob;M! XQ BsKlk?3;I z8¥_ψ>ݶRz&QB@w#p  Je LS+Zs>ЭrR^o:%Lu}dP:rQ1O_ o*` ֞v(ֳ!QA >SKe;! ƾvak9gl>7eƢX.վ%7} P⺕ <7!דs ԉ)#cmEqZF#l|ҟL&3*x|V/WVn p:\>O൬'J䷝o#JT'*1&Io}4 }p4)jIoWj?Ơ:7Sn]ʯ|yg,,@:'R"/)i:;Q?ƍRvOrc5" o|eWG]古W"R2_>S_d+ihd൨ȰéQeQSFy> ul{\:f쫉-R[kuZN@djV<~rUEƀM9E`;wpwPMՐPЯ0FzNTѤ>}Ud&v0!IRVRZՋNJn)D Q~D}(?:ٯ2 hUek "&ȿMˌdHФx)^k39WČA%DZkKϻj5d>sӜmCp湸3&1i)^)jnKġxǛkr(  "Q$lk ~u$g9c @LZfsSƞr.q34q3~Quk|'qQ>0ZHyJ`4= a3=8i(C1zxWVtc/!s|ع#Y:t qfLv =:!sTŧ~g=.yW73z2D#1$'e%ϙ=O*ⶽ3T^>xTe*d`6 Ů{hq6#8&nKB>]F&H*8ٽ'3r&!O#]`ѰA}XC,zme%f֟Ttɏ2,hu/[F_qZJz8o(@x{p,aln#ϔp9dsQúQJ 3FXQE᱒Z&?$3bVwò@"-j[ލV%D\ շ,\/<_yq26T~yШ?8_O>-4pn+Izh/l>8BǍ:&d ?칼RꠠynDV PgRhJiJM1rygVP5yʵmfn&W&~/Vrn&[} =3Q@ݫRSQj>)m2zF S j~UOh`>ȯwAѾH_ 6;2gZ}Zn<̓S kpy~1-gWuW|hd~Sg5£T\Kn^f6ĶK%CG {Omne]>txHI=7>+BA-7u *TeڧB8pЈU)!Hȇ.W7 @wYczqfցoLyk29Z .j Dc1館+ o'SK 7J$|m>KG9yUg 0mХ%5< 2o1n5YkC hA=M<9E\vA8 |VO݋QBp- ļA+=VQ"r쉹<:+I9ȃq3)qZ L>G-cANO<%'u8RN]q!݅Tx+?<TGR0=R{3:w= WVmmŋv M׈_|iGm y/HPҼ >:O*U# qG=)jDkVVSkeݬڸ!!/u' ?3+M-0.`Whq =xa˾{5\I7yŃ'BVz_iKׇz}2K)NjV~]hEXA4C"Pɳ&7q;JV朣ҿ(7n2@P?tm+HU  dEӌ.Fott%nl.,YAW!biala|=w:w8!k>ܥV_λS 璚,ʳuM1xs1*V7zUO砭6NwߒěT%ЄH!l:1kZJ5A? ɀ+=$qFzYz\ZcFo2 r0|>Di6өۗt|pPS2w%[(zAui4T3!-R+ߢ;rZ{b%'+"xG:L0"p1$#SELM'0^Ơ[M8|xXW+ZF/:me`{Laq#vf;1ȐC:BWכ2vpĤy~I/'ܕު^Vi5GlISdX[{FՉEfS?:6+ V)tY>6Ruqo#?I`fͧ5jL^{nݨdb/ROĪ#v_'}֏v#-&zۉq-=9"t{}A`T5>m\n^ ZQ୲N>\rMdGҵ/g }ۥu6a}_jcl?A> stream xmwu\k64JH,]]! KK7*R)HtHH74<y5\|?QiJX@@PC rj!PUpppqpp`I900" Z. %pqpu]VpN''l ? P'v ;s99Ùag-;bgh ?l" h6Xف1e 50sw/6dԠ?Gpי5rv } [Y*P'{ A,[;O)gWSTSccUbC\|}8xqpI;v68|P'?K1.uH.#N=#n{`WGp-E(#{עkQGpv{g׼Gpv{g׾Gp> Akt6/;3 vK5{ W`4ف,a̼1;uO l _[asC<,?Vv 74 \}k)ߟsG}>?}%A?Pp{՟mz/8x=Apys}/?qx 85^z aء989:9N ȿ뿧 r2AeCgo˃8 _<Pct=½̉ފ{:?`LpwgBx!v@g)uW o s>ppN?P(| z4wq__\%>1d13 5~k!5VAUp[M+/1!7zz^~_ƘDs`WY' K=xN(q0ر(=COYoᶉ3P ׁ;w>F~7Fq3/Q)'ɇy[uw _,bLXSrPPL=tyi1Z3O'֊ny6_{Уz]יɊ+@[ن!:CG\ 'Tc[r($:Zkn`5Dɤ;rϨe͊tKtx82c #=!tݨ\_Hd|Jγ흋M)vD%_,8&QDƥ5}^3̢9;r*ZOy7"0QɃ j)X@ii[*re7a Z$| 1/՛jU;1jϨ i._؂p.P,T}z3[`H je"a̧4g{=5ߏy,=Η-G8S&HE)d!wk)+V<.lYFĽdlݱ/61Ȓ0_<=xM!+0<+6uCdmQûw^\@Wqp1 ^Bp֓".С^W&LsEKՌ{a!/D,% a25DpO@x\K(%S>hiQz zGk\imwR7p=^n8 [D2"m$cZLܜӧr[%Ќ.7* . M/sjTwXX4mx]hu.d?4OYd33o3MC%'^g"Ԯw[ٯ,|J'yeg,bug=ʟgIſOz`X-o}UQ+HMl!Q_]qO<;M&׮^QX͏r?1v_:+p5{I\mpVm#8lU/sbMHh4dO23MC8!Pkz֬VvݗAIEHe9Q1Z9dt S^VjYnM|SOCu3ULݺ2h\{@BS^[)w^Z>IlѰR9Dh=BXD`OQe` 7oY o"|'/z?Ίו:'_&):]ܽI@ErE8 U<ɞ+UeEn$[Pp 3ke$M; "+qTp%ou.ƽSm $#*"uþXձ%^k?콼 C^M^5o-cRmYK+nԀ- 0>iĉԣDD1>uUʕ˓J{O2̙22{,Hȋ0sxrn +k[Ef> 2F+!{; =yl#6\siM%JuF~48 L(^ ̴$<;[ΌI`Y/5ہhي>#&ڛFQן";d.<%xőd7ŏYFT{n2DKy:I ٺ[JBb[H-j;sk 8ia܍V/48j_H30v`D #k>^ w`Z 366 X~O">bYHl3ino$p10SP P''sAA5n̷)M #'8a;e)mGtTB׎HwчmS sh@<9{W6DxIr$%?7ʎFtr9;LV`" b3,|&tNmJ?cvEFY=a6;־j]H]iڥF '+@6eFmFӾ֙_^ zUSL,˷B 萝$m NƦct=$ W.K"HmIKޜ熭⬼[FƗ쏦74Mx{d1lY0K\~[̀dbʰvFQ5R$#ܪ -K//4sS<LHFwruOt-yn쇦j }2j>n @t,Qg8i+k֨gb:ۯb\&\jm[Y@۪R{,CJ@ xxsah 1I-Ȣ++ 9Cd8&4ˆ]~-e"Nڧ-KٞAvx߆@JP &wxJFХJgɢ~=0Rԯdtzu[#_L\oR8,2 _D2s,Ȏ7dN=4>*g"+vLʜ촲3״Ɗ"$ F4jc8 xӎ5\hĻNX 2"mr) /NrӂryO?~\.&ۦz_P$1?ƂҦzai„tEWG5|DQv17,ZJ:{ܶgG'FyH4J|kj^rj.~8KV;tՄЁ jg ?ٛMxG1Iz7%̹߃ЪVJj9w-fXڂ7ؽh< $r_+!n<gk&Wh\+tĬ'dƬ4UF->K?Pk%8y6fc+er A'mCMwgURCB{sv9W~늆` fnCi٤&](^poP1Zb΀[3# lbvn7{3ŀ:`›#{3K_'_N49?<bui9YIߠ~G<>L}H駍hz\t".=hFvaz\u2w-?q*]q~!"yޕw ^sWLm+Ә4v\۹ {/8uV<+iqG/ "ZW#k֓r|.-fT&9FsnGr3ꢬ|έ;\}S$Xdq -5--DSS;Wկ/S4_-XiK" I&e뚵#qjKP@w?.H56fk:걏>Izv9mj,il* ۾^㲘WZ@D+p^^ .$x8AH OB Ib}Aqi/^WCVjl]$LH "U˦^DgCڧfM|_/7҇9Gdߔ7C9>GW|{cZ)C}'m#;Qe&am{ bDdO!OP8՜4N28˽%>(c HZB";Hǿ>NbVԃ ̆fxU;..xj~*NK՛mćQYngYׅi_ӲKwv9&3,&*v__zXE\Qb*>h>._1gfj\*}LCiynヱgΨ>F+@3^|-̹+P/l7ꩬH X*wS'Tفo+0$焰 nw kL kqOγ|a] F1ZYy^K-_-;O[EUll+S\g4n4 /$xٍC[/=ˑqoFmiMk~\>NJFA< yu vsȻ Z ff/4#R P'|ɖÄPzxt/&BL 3ً /\!x }h*ߪl-#>NR]`]ڋV{/wW\ζU2X^1oxNlh "L&5ɨ0L:C}1K@,i7C3~}DO JFq7Ÿx:J1UGa).]SؼC^n/ky\ƴ*ef3C@{j-{<#28 #9r=m?T GíU'l8W$_:]qxNG͒<)kПЭzƹw1X._N9:)he%q6YG.BR 0b=Yoٴb$lۗVɘ/Dlğ g86~R"bRȭ2H \҄ȬM}J+NH#GTb ?%7l܄? +hFjcC\|"Y}c_B$o~/Y=2E2.r:戓 jk@VCQ%u[%ѯhD|M.܅:M {(.@s$oWd'?_o!Ph}!ԼU~׳ VH-~G++f&J ,=zkaW~h<>+ILŲKs/6} -l#QάA{ց$~5,iΖJYnqYR5q:ړAq WMMR}];%rRgDȓT*͵=:7kkE?K-f\kP;yhh hSu̼S[+Ay~87Qo7Ǵw^8StQ U|q 2}*3*f)|L݅&UԗTLqLn^]82LcB"G;ƀҗEq55C.Rj/4}y6F%1?Z!.j.$G$eԒ98*atrjK*o4IVr1LW_As<|>h*oژADf5Lcw4:X%oXTѶwbD>%qTeht;m"m/"gvH۔M*[xeh&CͳFn2UvTq;fɓ/*G A|Pz MAGsg\(POѾw<xkcstNa( V@ Kds}tQN$uF^G&s@L1w)8$%CTG/ϞT(JQ[-nZ*[Ͽ-}MIu0X$97yٶ2huL'#7FQښ',W[shOe9T+ѪmIA#b e#F 1˹>M۬N \_a,=B qԸb'?#K=tZ̥sa߱jikaPpf,@۝kOX6;ԯR>Loꊆ}=z}ǬE%k$pd<3uȎOgGKO^~7Ak46,591EG j vѾos< #4˩PWDɿ9Ώժ#1dxOJ1g=3dwf*ȍ$d0Gm7^lz-E:"9 m *{Po|}QM X]nXC026r\Qf}+zV5ݽ6N!}8a+ߢcBŠgI> !lƧjޜ YdEq]\p\u'93$=N=\ 3ϙ7"Y)&@m^ =a&Ggnk!ӂH1LGZ܆Ec&jI5Cb["fWa \^.:kW ]9S>VșQ[}cvWIl\w;4G#g_}\vm,a̢O]bi< A(Cr7ӆN d'1ѥgKYO^>oexD -YhT4q: 8pr;Q$G'9q zfDhr_b_s9}7=jg~jdHE ,g<_#JW ɀy&:--|!Lf%@yeO+1VLeD|.5'GNvLGReD*MS]kV_ +4a[Vhᝨ o!= e=M ; 7U4_Y{%9e $Ooׇ![*J ӥe>f͇|&'}Le|q7@tf\G bmiy=%~6/-ErSp; bʲ8_#f\xnI+T3w 2w)ƣ:g2I1cUNn: Y^E3Ûik* #N}@޷RlDew]JL22 :J '4 h%ڏ$r=w:Ǫx-_O%7ccy8qMcOy繋;$hLx]Y+~ZTxz5Hl/Xwb4HXt^5E "\ 黝tHGF_<=_Qx8{nEf֒z9zոo\v gG<|>5H4A,7/NVgh [r$MG5y[)þď~ҹ^_4*HUz7Le߼qQ?~9|JNWn# U/dͶFݝ*[htfu#- @>1ːy7?S!Q%5ޤ6֭C驦޺kj>MG'R,!ĥsޓLD))KZ0K?$ endstream endobj 445 0 obj << /Length1 3074 /Length2 24505 /Length3 0 /Length 26221 /Filter /FlateDecode >> stream xڴwuX5͐(04 "!ݍ4"4HtxνG=<0XPQg@n,lEuSGWv6f5 Fhfr0u xݬn`W? @tZ̼@7S o' ;/ruc63ul`qۯ̿"cșہ<]l9EL@3%d 4%jʚ*,NN hWДfH*iHZLiMu_5`VL% <`_*쬿`x]\m~m`e. ܜXY===Y]X@.V,NӰqx\O=¸;Zf ;E(ؘ]@:K vnWL@X嫠p0qt:: L]&q_ū..r(w4.W{ GWW7׿#6_]_A8ye+`78W$lurxsy:_W-ܝX5m݁SH9+ ṱY[~hp}@NKS{W%j}7BbXؘY.h Mw?-@FR 7hĪr7}?Lt[3uXhiS8ϘB˺{_^(_ܷ`f1pK9]]\e `Uf?=󗙤9 0uq1Fb777@:r _ `Exb/8o` ^6o`82'U7F`-Xo֢(F`- >E7kQZ#E7kZ#pv?x74Z\MtZ9.`678c0e'0ك /v6pE,` '8;O\'˯#LWgwS?B,CVK!8?bsYrw# 既UcWwv_[8Xo6!8~VHb [48&/vv~s8/u'X+S8܁VE Bv.#cG K`eA\m~,rKfK Fjrs={%A@p/ t[/_}߷^au7PbD|x鳁/mv0J@񇷘˗ <fN`d>\5׃|z=@/9<\06)"@h, ?G5ДS>$\Qh 9~EbdezifӴF$ .Uw'Xo9Z$P>K[-)OR.Ԑ~pY6 UaVpR銤918"k~ {_t.nWgZ"YDQHUL4%A;c|'@KU]T퇳TuF89TFfNO.}6 kfnG&9 4TNsɱ`+ZK.eWaDďę:UQ)X?/pil=``ql^l.,}{<)zN ڙr2 1uVk7j-7r5L=SޖD82ڇϭ9|Yէ{eV6.،Ĥ3zxIj+Rk 3승,w7E we %{o?Gʕ!_ETqCZpXs2rW[ؒ~@t+?lkfVL[1=+ȴأaGj\w“(eNSYҝLL|8o.ޡ #fs~sSS,&eV>^zj d/8I=&YAl^tɈbKH.[+a貉eqn=`EjW(Ӵ`e9 ܱQt=|#]zYlg*M8) >͑'-+MNtBvjh7יUٰosW-l]y_u$H   ońh I]]*;\l5>3jZli}>RJ| Y!WU0V(4BJ|z&+v8涯֎cez;zL B6)U.M (IaJ1O$Zͬ&ŠZ 9<Ηy2?b^+n?JWewР.{Gta8g.ú}P 7Lʳ'`Vba+(7,GK-b]4= D``) U;/ INOnUcQЍp; ٠wF5M8'j^tLGe 7uĚ"S0! ~cpQ,h #c- sr\i[(o$D2AӹMt&nGoܤߤ5ٵ:lQP^bEbFn'8(@ 2>UkRF[+Jm)[ڳvU(IFM?!2RRT^N SCG@bb&FDPVTΙ쑧 \SRySM?4|$3^z3n]b~K&Zr9=m>wi5U2AnŃ.SFQ.i/|7}#K2 UHD:~R>ouOkDC mQTF| ɒtDŽ܆&Ql vu?]3k 1JPQzs~5b1ZcM7QA B$tU2@:uTr\(mWt?jM+ծsU!n6PL 7IdLOunJ^Aќ$f/[S}-[mMPu  *U-B[Zot!>/@}S\NG> 5bT{IZ6]+w=@_Lvaotq1f!}͢JǬ>3>?2]xP}1Bf8Q^ԩh{̀ /PRICMqғnnaζ=Z&jO2mG3h3-z}&jȡ8LRc9Q6_ajsYҁL>zU[C}ͺW\p| sO\v\4!ӆIOMeT֗\m;Lϱ [GNy徃<6e04L:"_t)UoaQ$ ņܽbI`{N `D`Uӑt&mJn{~FQs]lʶ3īj|תp؈ncpchzf1//7{%miT+I \C" 4 οΡf | 3lZꎅg Duzi5n(ȇ l,U@0lʬ_>2[HH*Sd`^{k=JsiT~yx}]K7"Q$B#8&.TM3dSKu2{NHPNH@`,}miJ׶|I6ik, ;E#-H_%E5[RpC-J}WHsؙ6c$l~sgcLm.~G?~ >,^齹_bhcMR0nGۓ4H]O]1ohhDž(+.%&'<LSTYRa92-)s\7ayZ>2&Vy_gUTjc coDSmWFi.8De@PBk.>g6W +xф22Xp;KP$b7>"Tc+]BC|o7Joh @9HF fD|EB:jVtP`b/6Jm6?0~.rI?{ԑ%eSZ Am$%w諶 'MtMNI7xvP^w>)77^EyXTSMC>2:k#A؟sx4.GGPmèm?xSWybL*(f: =qjcX^_tQFO{s`M5j&\rI8WSyBPa f 7سQhrF K9,B2Ҍ}\!≢Y+f-k/Ly{-je7*Iz`LD9rZ%veŇc%$B\#?{Zv 7>W;>.ɯbG3,<=h2j1 e&~M$6SN7 O-6S4VY&YHj7_XX=+?^` <ɏю/m,g0m;S,J.#opj|H!=H/BG/iG%2 lWUxNȡ]'ԽX;7Jiaz˲sӁuc 5t bX,7z 5aRmaf,]xߏBH5j>."/ȋ|lWpjzD> {lʭtC+EW hV; cv-υýa(#N^,Yjܝ-+vF\i Y]s7%e!"-0. \dSjn䶙9٥2yu2zQn$0532NVfW_%॑Rק1INЃMO} ʸ*PUMYˤd6#UﵚR=_(>< g< VfLn&o’<|cHVh~YgVtm<(o!Qe<C[ZϷXF92F4 n=اZrܾp RF6E3c90:9|z-eVE`^zoS)r<YʸvEUAT*[}[B=HTsT߰bFCG qOm̔D,,9 IeƧEIX*G Q#t^eƕW7ɗ*#quO"x5>ۆrvm{W, HԶ刨o}0K+eO q>Sq$:1佼^r7焉3YXD}uMJxSײ[CXߖ¸ht9rԇF)+-Q`6 EEND |i(=Nn PKTBXw&!HCq(-{16ru>P(FjV!Cw5";07Z~Ch~~F*, (H19YV-bPdIJL^ ڌ`O39ٌW|@V?aQ÷ L^сe$$P|owO|`U!FEyCB\ +bt&x#:qWk"*uHnN{0^~tي^`xueYľ~'Q[y@o;"sV&k襞tVu!4$v\ gUHirDA1aG *$!֪Ѷձw^B.m (1僧w|6k{B>J=>[$ɢoY w"`=p^6[?V6øjo*h_iGHMűwS Kf `x?wf>P&]AIH [O?c qASs~Ѐz'1]F8KL&1f@&N|s_C}$nGVG.9Or2xߡJ6!Wos(,?d_``:$(}-%a3?%IbzJpSM@*U(5+i|.q`I\.N--AC녘:.;^X9~(ԱMi"fBe7R:Y]vm_``܍ ӵ#W}65 - 8h c`x䙻A#|りyȽnMn獮)\'9M#6ZznUc;!^EY?rj ]SWLCz0Y|X쥼300sv_z86JQ=ߣLx Q-ݠ+YH`vϿ蹺d8&6id)ש+[ʧ><`2!>h ڧ 1>özr kž#LP`4˫N:O )u3@~;{(l)W}1ao=Pil1c5^K Axt[d TqE^--Pl/qː\irn5z-yuQDvH{< cLxUM! >zp.N.D+r7B ,9U::q,ޘ~Ըe4ftß|y{Fh ۇ%բ[睒†Ab2V HM 0g rI{5L&T Qo%%9v(k2n5Ui1N{MqjFt*&zS OBj %`a|A֏L3U&a)C9LL9}oC`<(X)% qX!dDjto/Q~Mx(z=py&E'hK,BvSSbQyDk7 B`\V( MRp$msy 6(t%΁͓ulq;q /U)!ǭY}[`|{ -0+'3S&1[İ=7(KhlKBp)jN/ŒuUE-8aTY:sZ9[g+$0-lR ȭ%5Y8ٺpvU?{ 8G8P^h }}?6`i<"*Kϔvy}г#*[wFzo 0A9ŗF,m'_6Xx#.unD0 TQ9JwX1}_ۧ5U^oy/"T+v;|Fg;_1Y:cy[;k<9- >a,2W<2#~mvӣ5TtxVį Xl *縕K\{EA@6fGV'0@~ܓY&\EsJO?PWwGDo1@n Z |Sځ ìNFFEF&(葩ٙCixD' ncuu="GWv~%9? ǸlWz.͜XV5g~4Fü7qL4y$/Ph/ڴv6`wZ7h.}Yn(U뚢A G;E7͓޽!a뜐e&V\ڬANGasͧnW Fŕ{Q7ʾ ηKެsRK󭞞|)`VIS : =w^%sxySi Y:`CNtZ~ z?XKOl>7&Co×wC8Eh )˓X_QiX:njۥ襁+E>3"Q\-|f׬e1'u~/#&o@G<4 G(LO/15(.pbX AĹNæ-)Ԫf]X;AK5-kni( Liɕ1UkGsn4@ oyHjZ6VQ>L1s?ULְ5V%tMԽtHX,.S,Nm%S9ilGD▦5Ju)Rt`I4UpSj[Dfhv&̉s),{ q;I0;7NWςbyj>˫Q3m~3?|¾tپn=.¥(`6-e);6RrJCz;?W,Ws9{EuMorIKB 0@xNl|F0fZllZM>j;6;WnNTJ8rM֧CTQ ] 'WNĞP2m,VFZgOC"Ƹ'Qۖcb/;[וQB'vq#!Zr]trNhg#w(3K5S+/Z"%uMFTwX}-ˁͺcJVj4MIVКumn )de;uH\ wU:AϬLԷmqVnp?PKBCbz|/&I/; d?VUqG?$1腋+"l6fh-Xh1x!]ˇм4{\r<(WbVֺۅj=o ⚾fy>Ύ8+c2-V2otCh=D\ f-F-}{/C*b KYꞇ!utG T!p5c/dJ?{7/uvA24t8׹!V(NrW TѾ⑉;9Eg9@xJ:`2B\2V5%GF~"?#7vߥz":9.U '`8uX;}޻\7X+_ʻ73ؿy%|@ a ?;uLhyze7uW{p:gYmlp_ƻ!,ֆXLS]Dx`u`ar6=&u ̡Dq ={lqdVs@kRѰkK0QU(Im8 R>!ם6"Ib|' C E؃9CEzy__7lJL7*z.Tz2˩n{_mS0a!1̀ ?! qCw[MȎ|>* ag ~p;H拏ha>^۫fw@ oճ>?:Hozԓb\C%Ք2*~p|D]\\Q٬SCUpHiDDͰW'ȗM/Tww \iA;,tvpOOx>1 >_qu9٣KF^C]g<ہ ajV\Iyw"32~fhJrLJ|#5O̍t)~4m{&XrmeP2FeU'ܸuYCjpB$۴V6BqgWE 44Hݣ'^"1bBla_єl>U( ޥ&ZnRoh:&ѷ"%A62g%S ̟eQ1:H .i{6eQ2B(ޣ-af P-ЦxE@Tַ?J%P@)Yփ $λ {"r;.7.GuUȼ)ss`8lN8hѤ]4l~ H6Y\`n.պPb!f@/Gf~C)yĒfqK9~fS=1 58}2A1уM0mWqÁrcG "|s}C^խJm f;j̘..Tecoj;%ʶ֒~CHOxͷ&ozwro;xrH; zrЅ%+]DC4Nu?u9F$~;XQ(NqQ {RF2s _r=xϊ(cO6J/9M]dش<ֹ; KD\D;r0e,U-u>Hh;#6"NyڋNRUe*r;fIMX@w"|+˭9{X:ٮrW8j]Ue"ɍrPh[ahGۧ:4 3 9 k6,1Eѽ iq•IɤsZb Wȴ'f̵VtbDN\?F^x,QPľZ~X\}ciS@\AG)kw5#PrÝ9;w Wv/h6P"7~s4`#!4q|ml4 2ݟwSy`r+1)W]W!](Nnw8TyQ)߯]}wo8O w} `k"@,]T7͔'pY][`#ӛFU@k-Hsf+ y^C !*/?b$8Y&cQL HΊo1%klխ6>?.j*ófFik,YtW>}'6lUR` q1xU/ p4?ؖ2QElWh /@&*32b3~y#t"r\m<  Q3lҗMR77Qw*풧m)\Qz/Pȯ[E^G\ę>Z8hbHk狯λ-j>|Y"J}57̅%y\M<ۑ!尞$k鷫gLe.^X_'V%n11C +,j٫x 4'~9qaǁg(K@u4ٝVqxד| @XfB.1X]P&7D7V*~x7L\q)#o׆@[/-b{`KcӅC{_@X)Ni~˼,;^u|t"Gs,ֲуP! _>j'֮ȊX[Kk\D!߅a"g.CTrפi(Z F)Iy%[8*LU)f~^R/rZ1k4@vӛn4ǿq4:JdjIy\ \2\x ίJC5T^}E9y'MVLtFGೞY4y1NI˾Q7j{x]Δs1HzQ-\::,/]6إJ;}p|g;|#7r6c}JfhyFe 6b !P^={eX߄pUC.M>'V_N4RP99//=_%y!JAqXtzKE\acM 2Ky[:DRI.5s9Y4]Æ9즯kVKX BK HDHd(ν$hFp tt R.Vй,K#;ELګrq'[Yl>~]}Qjr.W+YD]<Ϙ7mnN}}j3?-($УD2^CTxa~6Tɟ9W9*x7S7f#/l9ۭ(ocݜ:3 Qʿ?oVh.ϴU:yc R?}k6Yʋ*\&I-p%%zmyz!= hrS!{S8z+Շo#a͕9yA)Nɻ0e+ .#Ms})Oeew؝'EC?"oQ3쓂Lg'rDq}+2SLROүᖟJ,ca{t)LExJq[vxA]. DdS"l[0g0>FԔ n'fmd7WK{?3mH$3GPꖤZ3Zr}Rk4F),(盇3`5II]!1O,t Tw<߶ny6b_Di~1ĉ+%v03:`+(o EeS(>jC{8̸ k_}5ߵzk"dVR4{]ҬA%,[^!{5h|\L02::?UxbŢv5%}]UEiʿƵ~fE#NBGNٌ*i5g"%P eM5u R'ƹAKhA@U5BasMuemwȲuA6n(:&r>7KwEcdq{u=!.uӫe8~>l8l>o/gdOtY ~XQ. R+MkAL72VPمdk,{ŗKy{amh# iqidC eru9Z c- (rZ}d}D{JUL꤃INۺtA":}Cvt'4Pv3hݭE2W6#)NsKT_ם}x }yiɰהGkɗqظ:g~9yNa"!LD6۾YB&ErTVVAt)Ig* C90 6D!iL|x&widōR5K<<u-<}GERSscBfpY4?=CIhC(%I_[Pv <Av0fP5&) 'P a@yvW+w%N;)~h|~ _=w*-dA׀O2%g0Y#k|23cuh;Q3E=ݟ]FPEd!\M6!..i#%ښ<}醴ڡe>)2ct嘠xNf2DgF{ܗͭ뜧jWѸC#s~=RIh ͋SXL`õy)y]c5qƇįM[7BCfU2$"2I \h[*:YVig/m -sm1+_fj;WcOcwQclfɜB}* /Y$xW¸YQ]zP㷈U=)`.ܜr40v7kM|Oˤ4'JNӫu*d zr\:!aMG8SP6YZe1 YL`M|Q{k9H!qR~>=g0%ͽ`33E|+~,AsahhsӬOo ׹j x }DtFq1 ~%x&Xcy-y4 "<ys:_11:m dx`ߜTm&)S?k8$oe-4AN/#n3)Cdc䓇 >*^< /f(dNVWՕUwsr7U͢B_} OI^K??o|\&kn= CG: ՆHť7I+EarW{s0j𩓒}uËAiR2Sһi_?u[M]? kgաS U0RUUKc%.}&n=Fp#-LdZ˫"/?:[f"ӎ>BTGZϒ*We{ۡR5ɁQ ^ (“sNuseK0p dpVqL琀5Ae].Mߪ5Gf/8k4,;ĚgYw2pZ]jZG0 fRf}?4Rkx ^C BVf.01Bh0c3Y1@t>w&jq-Z]ޙ5?̛?4 ǞqDŽNo̹w]7"QXX֗HDpY}p$f+2]f` J1rOרap)wv ag9~.0vBAW@3Ǐ4"bV.YmR[䆬||J+R@)ѷXixWh7!/n>[_~SSh(CU`--^1$Dzoң2x~-MBXӀeЍSRngw”X =u8al͒z"dM|=cK%fC;ĈquGi/6\>zzC""6-C8$S",٨,# [ΰBKybj}~ܴ:6ƀ|!ـNITD qÄ;MLYkI =IKz"$0c[tʈS;t]ǯ.!* sX 5]{6+W-L(LHxoNQtJ,`)3#T}: J><I* AY]#sBnγH~ku%6]BR.Z)sC0XwubʔPijA7/*ɕXDrgy@PEz~IC/-6,JvUO \1>@HϿͭkupuhnp-`ޣvuCjm#B3~֊ȑM H!ܸឺ]CY> }y:!Eѵ6زSx~IS!2!/^(7T{c_Zyynrwl'zt`7.5=F9 l>G"Nlᯩ}]C(%3cxPX(3C6DYhHщ@lx;J,4~"Q]6V|B*U@L›7 &@2fx6-ljLd9fu6S?f2J=N)Z(t)v#rJ]nL@%e  6_TH>o~C6oó…w}WWf Kq1ب;MX4Bt!Pdv(솳}faBXY oqkFN;_w8a1ҔË!'gsh $bD`0olm[%\($8.J͎*pLSŦ %S4XR(?<j>aɃiD/r~Z3;-7#@_O k5v*ٲ*v oֻVy>]-L 8%,-<ь|ėH',MlmI?R)8I rb+cݾ؛2-<UKw~ aVVM.QHԀK_= ۅ Dk?OF1+e.X3z,YE?]lE (}+t֏ 'ؐ'Eݑ.?Trͷ6BGu\\)݀H{ =rY .#!0%,>$tHǧa(祝MWiJz3ZSLQY!Qvf$#2Ʋl!Z9LZwc;֞?!hCĠv.u6bث;-"\ڡz=(wI1y(A&dWo@18'oQE*됫OK;)^2ɞ*Sw˰n4oJ?&DM W=`YBVh9"y]cz`4Zo{ Kjk!D n|"ÐMI6[Iq{EMv\62 LMԶDx4FnFB'"XiY %\fR&.9GBk,ɺj^Nf jk{FA;9goH ȧmqae>9+~__j=8τ|fE;J v n'Vpj.H `+N"Mvւ^#*R֨ geVzJ쀾Oa[%ıe0~i1T1ı^:}<F!K1llw֑PDlszwQh~AV};Ѡ xA{@wD2.\bٛɶ-넓g/[ DFTBYAo`'ºt2mF۞wK`MSR |aLsFIJV8C\xk oKo -NMĆǫ/};lP5yI|)/x*=~HKrTwm[6BHRľiƯp0?bN?]Um8FSlä+[{׈9V8@ˆׁ>Z@'ҵC ^s_ԽVЁLz|i=0GUZKRZ7D֦qWk*JZD-mAb$SBeg;]3 UI~|۹f7h]C-CvxP k [2 x~WY>9+ƴ3A`F#oM_e;@A3EsFh[ܐ]~k1džmn5> VZ%t9 "G &nOPԝܡe1pP]Ɩ$M[ !' SBϘh󞸬|if] C I=WA*1طt.,p`nA넌d ;Q6`΃wұ-d*6;2ks=zlUD)yrDNZ$z$q_tB[-6>j2h {m1­FO|1%6d piԶW!J}VvkkX$E!bhL먷ir<^; ngLd~/n+MS-)1{VVծzD~ia:znc nٟə-nࢍ $ -+ / V!0zCFMMV)ȇ5/̉ѩC4ٌd->AhFz"`eɶ{كyQѮwH-|[~i;m;wҸ1#N"/`J7y^ރwqUFЏcSq<@g'%Y{JzފXLwDo1d%o)'Ş' ȳJzwBS,}l /R)+BW`OI;-aD:rxPmeJ~ok̬*v6 ,? ] 4ݮ{8jk cGd6313/ohV p5PnkR[ AT8X1MI9e&$BX*i1<=bY~c yTqnQIڶs9\kR>&'8D nV=CYK)p:iPNC ixwYv%#&L{(hjmeVbC,70zBSiwf/X:}Wj3UI,Pvm/Nsm2ej~NFsh̽PO8y߹̩ %h}ge`?"'=^} INhj{>7QFиi(Zؖ>eqX֪@ٜ\^K..m"~5qDDv#?!gC"?2X?'-@2 j(U21&؄+ Id̮P5n[x hiS__Img '%&=uK2e,cJDBzwAFji\Jnl ]3Ih^`MU& @ loE@ H·ӭ+oχ\WF#N#u-XȷjNJ`tõiICEU I9˻PEvJʮCc=m5]Hf5)YqY7*mӋ&~T'k ,Ѐ&?EkbV&'`XT僺R޸حO΢%Z6yIJeS$Uze+B#(Ki`Fu(fUBuP?fX5YocΝG Aj]j"" 3g+ΧmK:7X(%ƐZ"c4pF]ޛ_ҫhch;z1-)'bE [ ^,֋g`-Ѐ4Άt)(zd4WU3:Ũ±,,toI𿮟ŦFCe-2 ׂk쮾63 lR%Z[.g>~ endstream endobj 447 0 obj << /Length1 1934 /Length2 27144 /Length3 0 /Length 28326 /Filter /FlateDecode >> stream xڴzeT\[5)݃NAp-=[pw4G}5Jҹ^kשQTEQ(radeb((YY̕M?lL,,N@k bP6syww"P ӻ` P{:Y4&gFSw5di Ҿ;8z:Y[Z'o1&5dcRd(9 4 )`Pj4$??*k2Vsuttp.j Q%uIP UzoPRn]QR]T]GE7_]-Jrqqcfvwwgtuvarpdr3UW{9]1k3 Io{)ߝ.G.bmp-_ ** {k d2{7t1qqu%{ͩ&:9ɡ*KWok;fruGm}f gkg#v?5/:{ޫbrpO ޤ sq{w'a^''O۶ wYX-쀹#LVpAc!Uw7 `s.h3<7Ôkc<3MIu6*֦CvUUJA9Gez2/@pW߾&75*֌G&9s؃ԩT*j%ZEU׸fQIc)9N6t pbݰ/G?bt*kq hV[Rp.CiDQLwK@Zh],g]@U&#N JpR̓Hxᓀ U*ycä;R[GN&g`to4j4:%2R;q>esY)RzUSFtgdN^5 TB2Z=xOڼVE[e&pL*MIwҐ`~ e?n;( uAs85 <,ڴ3.0#b_(jN,9pD6!u)5$՚DW~Hhw9鳉$V ߎiVUbۥ]Az 5KQތ'N0p.t)0x@inc-H.{w@@?KP?C>8.]-6l98׹e&?`w2{q7K0>XY=d0*ٱB odI<IvvkǞ^7"dxH ;ǣV.!oftCc] S3)A;YV Z; Egioa{@[nټj]yh[O|$ iV_a ?`|/巛59`JM?nP;K` ϐ^UwrmNCr[X1ǼnΉUjy,o.4jQUz}C9<>Q)jA`ޫ=Y鿡n jX%om`҅96UL( jEqw_҄zg]{L}I'T+(C+*)4̠m >2B-[ny.XFXEйMawe`MBꞘEO#Ɯydj-~^Rc񋤸"Iw]|Z.t,ȍ!"dqsx5b]bY"sr;=ٞ7SlpfHU2;9rfUlJbEJf#۵ĨjX8ԯ!iy-!?[g0#[n.I}UOaH"J ]x!!I" cHȧ"R Ms-yJd#'9My}gU2w/<]|bk;fvzrLZx?hk`, е"ںj>)!1EPC(+^򍭰n@hXW7ǵ4Z`bNxd>Gl( p)C[ r\Ɩe%=)3ё >A6hI4FKK7Zd}&I[ڢZ COyM~Rr-؅:v Nٝ23tdH'ߎ$T˳J䬕18j5N "!eQj=oVk%F?a',TV -zEEᡙKC&Mt›iR|F 4FC':P&HݧX\5>EԿ: T:3C l~|NVL<; 9!Kd+uC.A8S@Ļ8Ѭt8 ճPmlh(SP(hxP~"xOedqĩ'LaUgJX{Oଁ SaY}2f#gvRKn*+c;w0-QΖ dQ輻  Hv۽, NOhNYqv+YQQ#^}/&Lyko Ȱg`;18'οҌ^"ܳL&ztȃέ|iZ#j !qspf(d7E+4ll :g6A'/JJ(1]fOrajV*S#}7 PMoPat $%CdXFDdd 47.tjalr:^_Uܐ'v(U&(9vxcaq)Euq[qt6O/vt@[7+xQ+&-b3(]܋Ior~vւiPL {||DӞUJ2}u}J;IQ9Uh,ݹ"۷4b!9ݛf֨JtN h>4P"+~Đ]R A] i)`[r͞dK{^/<ȷla'jP %̶[oݜr|tv$ [1Ts *f EDV=5Sa\%oK2 } |UvtȾI/VH@lS6!= {dP998&ѹpSRQڮJXn_4rq#G]et-ZX%zIŒ?.i9#xM_FqY5FJݦ,?7bO&HOm呪EE { N8{9,e30EϳPZz pzČi/{ 7(JI`,\E.觺GDlH*TfHM]~K( ED>ZC/I_ x"1WW KDm ݉DAؐ YSMԬ",]o  }yRgMHL-;|l]wŴ.2_^2Гh=v_kbI~-gvm23rY?;.մ\zTpG\mSF#Px"@  ˔6U句/MY[̶jSRF{V;=fl QL6WcR-v-:ȁM1гM"CF릿cN|?[OR[qnbGt)}1H ?UU=NjϪXVXK ӓ% N'0P Gy o իFIwHvKAԙ8?2R9|"s#hM=$Nr Wo"5hD! M\#(ٗѼ٫Z81KZhJhoȘ(]EDm5hV"nBtueS<#l]vP)]qjbH% nz%~hH)LJYkHI0ޏ TPL&뙋SF~ wҔ^9K/[Fک /2i]`:E1ɋf C(E V,TG@$ɖ48L%g8!ӕթdNLX}o p+sPU'jaƸxڟ N`^@fD! =:YygJ<&5m\O *':VWЛh~z֦ll./r"̙éʷJ4S]lq( ȅTX8vqk̇_( dKY]J?!6]'n.E]T~n.^}+ ؞CELLt0j[! l/3=iZ3Ke'RqlpJhj_>vj^ut/XõhLSKON(Kp=$]HV}\؋cU ɈxUj#qk|#\6*""`B<|*ަh8Pz g'XhiK|)6(bV|we.j'˂>Org9JNe\ǐ0v3V@0kZnYt9Ӓ${Ic4kʨ>Fy//P|<0mhh7: ;&)gnHK0RM~G9N ,}秔E!Fd7>>BX` sլ>G2!Nz4#[dzYmLql"5BN {=1j$B㩏rg4~h.-MQTx(~DS!OV _E !Q%pBVF/L,ū{â蒈dK@OK~hbIi'liuKڳ\RX|dQMB`44 ^A?6`GlG4D- S>/pH{P|l+YN(i7;,N ]GcE23ﺨ[ 槆S >>D5daH4q=AOX 9(N T;1Iժ;S|EGj&)T4[a zREyZT.JeD|b'Ъ Ɣ;Y}үAf_e'*ؽ?rD9htFь I ֻ'3eof 9׉D$u3{MNWn'VU7]u תq؈pЩ1R7g'Uf^J$ A/5ƾlo$/օG{?AMv, ,|:Fa$R7#O% <_jp\=o`nh~Nvkyd%7Ƴw-2)FbWJo-\ Jg%wr6Cÿ}Q(F1p%!ՉSI ._256d.xT{NC~ogt :vCލ}MD4N#ҥג1G631SEC-M_Q>:" h(LwFޖi̼,QzHހ˃!pYD ֫h

0W]˲i/i@Ɉ6Qm@?V!P|Jt4zJ G|j4 VTƷ[ؿWP0ڮ?c1~=DC+ww8XXr=M2,2τMS#B R(*^o>8)?i?~5==o'=^$%r Dz_h=#8>_tj)m/!Fa`-ȓ꘵KhIeWd9UrZ=cϗʔC\,Q|fOULBa&=]+f\97[_Hi"hs9UkC~󸛞k$-vHrOru-Sq$ɈUz{Kmf~ FVi_<,kKK#"TFit7~Ӭ-Z6U͗ŢaP̡Ij l.9mX+x W2IҶ8XT`^JU7W[_x #OP,+dʁheF8 RF^p& <#7pDc'eJLj8fթ&+)2#K>57Zbhm7Lr8[V՝$n뮲N ̂PcIXtlաRZUs]ѝK`R!0 څgN TKwVQ<}PAZ[^ f\u,8Z 'oO'n`NQX?A駆O v:)aË6LҖ.ui/GjHrBUϫUo=υu$c*qHuGmEDɪ`ΒI7Id72 ưZ>G0FEw5HWL=د:ǘ1HxLuH2 7꽲Fg&iLds}ٓN]B()݊u|>\vIƅy|<ma|hܫĸծ;Df־epkSCҨ90ÈE8DZ*c[oȽ3?d~G|S%àa//ؘCfۊK,ndl/[h~hGcv1i,ϻX{Z&!Phd*R;"J2B#vHv_[ RFGLb*[F/_C}cl lf4 Ig=3wt_ oNhб#yed 6^D81 !z.EӦ t{nlaq0$q;۠zB- hZ&D UibhBh Ş/oO"RX"`aPaupmKk`-_;WY-ixY\\TgQ6cƂp$5m^O |4"aC!ԑbS+=55:# 濼a!NHX(9j){!cPw( ImI1~|}|c1@+tF|@\[0j$OnhhhޮEğVx1;ޡڪqxi&AH3"X5ZI*JawBlx>ҡq15'1I[T8o}*4F{6]J|HN] ϱ,F^UE " zaUwK VS5=\XMW`QHL~ s tq߳=>xvV~IJ0m:t60k9S38xfى_]|mR!NEԑ։0.-r@HzPxZm643226k&IxMR˜v+d , Iʂ= #Scg<hχh{|aOMc T\|i{Ng,rޞ,3->ۇe<GߘTZrBU'Ѡ|hkr6x(s0WPE(tN@gOOF!vR$_V vT'!``$<Md6e 5OjR;_@YQy[XJ-0$EܑlxF5Jؒ#ީ~ 4{ q[:*kTd2i'[ M 3SEyd8"ǕpAY=38?7`q6ʤz{޺;B2:$6 Vi>[fx՟jQ9M Grӿ |Z#DƬᷲ5YFa=װ%rl0a0*#WVm[u!#_Q(e9n [ {la?ywbHtZkcP7Ђ.WgRÊm*ŴkиfxsMԼ4~OhE%yGF׬=WPÀm} n!5 "KlU}vW6wQbޱ-:: ?xL [K%:؟,]+tZj>;&ZG;7BYIC-y lхt&\9x@ݿo*qKf8R3O„xf兀Itr}}$ԗ;`!24F-`1JVH1ysٕckT!%Y3*?bi5۞+D0uɆ!i,f\S/zuY)oNq" cYʹ`q^7ODR 4\Eҟ]ψ33e`Hn%P] |nW;,68mZH[ȬiS?Ohmd_/m^`E-mLEF9C YmDJ.xZOObb.',ynSC ǡ'ET f|ṚJUZđzu0 ݀O m?>ĸkzӁYrU=,\g{p #;-7|Bh2ӫz"CKAJ _ـf=,0Z'f&}S"oװِ`aC墔 fB\ySXDc([ƹś&FX֮!90W2lpyC ;Ói-Se$UYsl8 ܯ"XwQrѕyg>e{\ŝq ORL<CUjr aBc_eZkF kON3okt6mEx|V9%lC=6+xꏏ7:Ǭ'|hG b#D&l \opU{Evtj9 KxB7F)0 qS U~mhm~ ƙg :GsfvDatK7\9BHq{N@J޾p5ċ)QJ-VSfTd#~5)ZcBFG~ҏ eE:\Θ7>B_mC~á9KD}Gm [=Nb|"ǜRzfW7#ߦRTrb(Xj?BWzI-W5ܛ c QC(pKn Vg$˰P34e2 8;!(ݰ01! NkFHIbO(b+Y.4Kd%L*-Έ'6VZC1$RSڢ 6-ߔ lh%Q5:\~$đ. yF?0y3.<&gj! ੜ/ZAk7ѭA9ý@4-nby.P 9'X #յlLfOoR:US}HYh#2kudH*R2 9#u Cj(o۳:("+acnj=h S&587&C<6\N(X gE5ƶH,. K摀B4ꗆZ4̀v @EgD0A1sTrcpqL!-1}.o!j \@~ٻN5Z>jީv?p "r7]H{$9]`o[?jOJ^hwRtl2`z%r LMwTчMn ^\0,=m&RkcPCCحzk r[#BM"z+xfu_#s?X=P0nh9w.AO3%D)u]h{BVodMB 4fY|ѻp;ꊣ"‰267H vr7 rዜR`> + 7`Κ]#WYH(rm(4߁E*I P5@֊%WLKn H Ȧa_?%L5o8*v ,4R5$F?`63(8ǷJפ8ٶmLl>m۶d۶kɮ~?쵟 _s;5dZw_ \YpPoF.h>ٓ3a~OCb=@[z:{8UjGYIpT>VuoƬ]j7>.i>ƺ q=9ԭwa!XA)+;k'O[h<_Ty2Yv…J{QTA>ږ'^[}>EWaӡUVeHIg4\ie&Q!ț!l0Fec1IorJ^nbx<ϥ!5k[PSm;8)Ut2݈ia}ĒÇ+ M f L'ַQv]x@[ZV ;=FR*;B|VuY6@M;HO4_j'%F{jf?\يGaa^~+o~eXEU-~zy x/V`7f}W# -hiYPNtcdoUvgcP-JRwG^`eV~.K%_<+! ~1Vx@ k ( ,O[9ᣕ֘^P\O*IYzLJVV.֤%Fڜr-\r]Gմ 0iEE@Wo̘M>9`DBebySܑ᷆?P'zբ'G:d + CQsa)Mrg|4>rwƲ>zsS}8OQt9ݠRYQoUge@r UKBIo-'ɪWr*lsO 1+bR ]TdVm''ꭀN^!Y oL,29ߓZB0:C`̥vJ~{>pAN.IF~GSW@<EY~];^)SA;AbD{2gc+[Vâh \001Hˉw4Tvr/8gVgIb=R/*ṆmFO'+`CiyISc iYb"Ao;0xXC+I_[bp/MeTx:jp]JoJ<^ &gߊ_[vrc>s Xz/9]#?˜2ej;MMqQC$O׾VR5bݨy#p+:dUyُy z 6>ۦv1$'ốP9J"m1œnĉ ˣ=!Ot J=c+~d܅Ldj`tgͱ+S7S*X_J^i$IUn{42q'&4l; ѝo<[';a_Ihl3H+}nߧ?W$G:+0<< $jRoIUJ|8Ӻ`3T_- CI6u/knƉ$NGA1;N?Ru,E[uQ\iU=_K>#Bˢ=Th; ﶻ$ Pr}>ej""潞K,I#˵S'P.-]ʰA ɷG߱+iygq/ !!o\'2'76MQ lsx6#w]hsi~ A֘~X #a4`w L"6 "2l"5f a TEU63Q -KֲcfbiN*镡Ɋ5Ҹ%pqCcŲZ(;1ru//RkV?KNֳ${7B a9`[=7z%0z.*3>So@Fև3o#%Mp9ZVb Z5&pk뀭.SVY(UXeBPh | \a.g NkfLڗx0kW?EԏL`-Ѻ,)Bbӯޟ2ߦtg/`lp;R%0SRםPeU]9vꟳLʺuG"w0SI;&iëcsuXEkbx0沵Jґ+~n)p99,[$Qc^vh.| 7r7&In?YˋVp ,u8@a92 ]c?ZESVeԞ s QLtsƫ";fuÌ WN]r}tm E.v!cꗯq//f:%WY;6>cZ%V_aP PgJMSB I°)$4A٥omO ?v|!\Yo2OX3y/yqh\0puDRH@: ʬO.iڌn6ܥ?Щɳ!뗗>d3] >tvuu: /)c  W!jЕohcy'SÊT/.F=gKx2PӂQr'QF^xoOt^S(X89aF9Gt|8z\~lM}^!T S$X}lTf8ny58y!P~ 5\>(o,$[>=4O)w2jDsb UFLt2WkX=fk3̆1 UeX+m:.#YƣG+{0&h>Q!0Dqv4ɝIX-&^#~3Pьe\CKa$f=O8fPO<` fSPBWc=Utzk 1 `kؓ?nNEM4[ ͅe>67T{!2ZL K0&1aT3Q΅/PQ-S;BOg,6}wfF̏PH)@OGZJm ~cUb țº#U9"!5:g/\?a8Mi / 7KH8%PU#Sഋ,r0)jrdžfCd.XlKVb:$O{%L5ˡIy_(=>fr~̫>!"{$L]jL]tF{cxǨ4=hj:aưG2狑{uI =}\E3[e|%C +\AJe~0&I!yeod,5Dv'ݳzO[CPwZ_nXM}8v*T1;:s*!&!?b, Rͨ$rMXEƖё$j35 td{#1]I`juV Dws!OD&^xۇ5V$5q݄ i Tj>3Ηػ܊(uʫZςmrFQl#~NLD)˦~U?>vUH= W7 xHłWogXTT5rKjo._(աfz< -%j:[CRr WgHA|ʿ!rWe풂 O~szܧ-N[٪[K랼cM) ˆ]c~~&/;iAEX50j hut7kH(uQy@RJ:bIIJVA@GvtlM"6!/*On.ʍkZG.WiorN+S YuII ],XH>8`(ҏ3f?`/ZG͖q&QރF ?04n:5n ōt4P. ņQqarUbEҬHߝ5*n@)r~--Ѭ}q-7Nxh4#If?'ֶ}g{J>'eȒoWUՕLMJ ?Rk)<Ř ( 9+az<ܙ= 3Sim 8Q`oUE=_.<ÏN`ɊV|:I'Q)1^|"D$NLY,uh"'\D Ӟ& fli\Dpc\5៝^KSe^zvwpjUFxr ֢>ENffk%}-fS}+,_5iz$iaVhSw>ۉ\f'dF~ 6ԤF<\Dž{;~YːE0!s|p!g79p ~̰v?j:/ %VËFQګsL$0")X7IX8RgzKaR ]ó׊ 2^"mnPbG϶{Dِi;$Sw"J~ !GdTjԣ}'dt+pS)놬ް0ێ-}nSMIaHabEa;m7ރ+)6z/pgT$lH*,*gZe2VIwh=!'iLTKxd>c*{GHC:} ZũQ^ٳ`37Pn." %hAsoCЦlG<»7oõS~7ݾ܆ ~^fV%ħI2EW9$Hqӳ 2A#:Qytk6M̤r2o;%6BQ&ΐ#Ze]GlM>lcyߡɸ;ud{j"j]/YQUz 1S-NJ[A[Ǵ7HWߢb\MGv,|l?-cnQ NHɘU|oo꾨Eena~LDRyȾ>}N{<67Y.2Xg60"8N1j(ve9?aE${'RXN ;NPZ叡q%RAQV`?͕ñٚںtL[׷c4]4j6$'mw̍ G%P\K^oѱ1dx<[+_zY^H:2:!?M$C>0YbyܮߑVsZ j݄kiӻpU I]3Gd6kX(-æ$pr-o!!_ѧ5sq75\_cz< RLN!%b*jЃY|VppmJ`S9DO .iߒ~ɪR̅z 0x3*Gx="6?=79]ZF uxdBj s_iOjᄒF׌V @,D/]|a <0ƻOK'-'8^C|iin'Xއ磆T|쨀 Ht2?] 0 [gZ-, &؄BxJfw좔hISWWLZf"v5 I;UAlIa=1GsI\4gA,Es}0jK}Refa,y aDK ܔNFcnG?ۈwTY(mW9Hʁ_gߺm*gW:oFukeK4?!=,mojGݏ1@83yW"&']" 9FWk/3=on&C's]K<3][oYC(1_dRn/I[pMۿ$Lݖ^S$Gߺ8D#Bt55iȤj 29â-^ DΞ`+HZ".c!".u&&k]C?w;KY`<>\=ݼGesE<(8sbI>I7Y@IlW>BJtCWNFbX/ wi< 4)IGΥk |opVKEE1koY dfΖ/㖋tiE1pޞ^\ץjkjrq~"sNdOy]`mTC7X$U#A\߷cQt8#VɕKBղQNTȴ)$׸JɈ7 ]ΰ˱HYE ZYLvbB[y@b3VO=|Qw?8V+C$x0 CQOc ! ʵk<_A_rGUZ29l0hɮi$F\5L؇adYR! v?*dǏ\2}[~E f,Is{kBKjH@N o:;h&dA 5= %5},S4N8? ;F0Ly40s0BS:)Cgb؊ecQNl_>\HX8m&U˩\m*U"TPbN4qzq`h2^r=݈lrG[< bSLm:r}zǥA{1U̹ !RWa325h.MEZgpϤO)|J"If~˯Y}{%C}2JPCę)}U}ǀbg?4ڲ%S+zc3+\wy +hR{Ӵ3S>ߜ_C >QU?TLCpE7:axoixćFQB]T;y]-}OFҝD+adRE x2\I2،QR=֤::(w[cJY(KXGE|+3YwPOtAJ_`7W27491-!: : ǘDXhV[k} `VlXHXjIDa|,-4~t}淤H¡y" frO|@oo+ &4oqd3nfOtg/Ьy@Yg{rH|X?&Fb0"! XBxCޕ睚F+M!N{ 5/-yUT}`pL S#]#QC\v1":"Lw>'Y<;SjܕVNG rbgk5kSp.ZlG*I^fjmۅۏ/Abhbpr0>Ўz0#O]/|Y}% kCy]Z&{xdES.h-,W-bScy #gUܺ5 ^jN)nJi{EK>5"Sv endstream endobj 449 0 obj << /Length1 2145 /Length2 24017 /Length3 0 /Length 25319 /Filter /FlateDecode >> stream xڴeT[5C.{pwwIƝ N; %ޙ|}W/USV7*P 'jh bgm`edffu,l AO.9@s23S$@w  YԆ%;'ӻhkfa yٻ;Z`c`[ chlede0503\ߍj;[`g PjUUT*J4UO$=@LXAMԠHyWھ7(yCWVVga dh|W[;js+ь/}jNW;G+#WcmM 2+YmHvrڼnG{#@rZ+WsCrJJrC [=drve{PK  ])o"v+ӳ6t3uvGo{vNN eL-;3 ۿl j rg o[F?>9,<!5yW}b}93P[ڹzOMm-bnf@؜O䏙ޞvSCk')9:=o001+_w%vSuDiϧ;h Ϥ`zNԒpV0RW?7'BG(k$a4QK ^!a}p,Wvϡ- ށ?bLZZt=+ňۙXؚX98dyb_`bS o#]01 XL#v=R?ݧo `28}v o> 33] &S;gLf 9L&wVߵ Yu{v߅hwYN/pY]>w sG?.j 5/D?_ ߣϥ* iaLG!Mr`y*@';'3}X8Yޗ_\="пy,B}La<)ВZLh" 7QI}o[Ei_6~m,m#,.<&P&+W}*)>|$:zHi%5mai%H;m5,cَ/HQ=k_n5#[tv6 EaJ8A[(j=jvbOTPW5Y~lzEb1y Sq#3¹mwexz: 00 k0%Ap牋ۄ B_&[6 9``;|Ua9#%0ٲ8w?2EחF)FC _̎1288:V7BϘF{Gx"aFܾc)XTq𬼰xECXƃaZ "_`4h`LP)U˄CM}2 # "B9Ncx#Xꂨcnn\, A"j|z"QCk7ؖU׶)NCAf7 6(}9ڗmE7eV UF֝L:[Ur9wI"5`J Kmߴ@ d.y~s)vypŻwcI"۬5NwQ\GY~Mfb'趃>9"ilǻ2O_0يE]{;YcGs2lv2*:UUR*>~5P!N͔a5ai@(Ab?Ո+ _N[Qa.p2Պe[E ~*HL?$;t?3Pq6_]Wr|Wwo6 2ρ -sB^M~-~pВo/R0LP^S/[B ZՔz*BSޗNZ\)W_{`9Q#[hա[,Xx^Y => ٪u Y` yPT7Lz׶)@y+A@iٿxb,u5f[cM۠ D́>v0T^2)^ڃB3v | u2n\+ fG B >?gjxiN66 e:!_z+!4=e: *ρcc~lZȑLbں9H ͮy %IA/`s|V uԀ6wFww[&4(ƼI>SIchɽk6mҩCu)G.H?&HGÙ&B8h~xxhXCͥF-&t|e˱ t#0ޒ :. !ϧ 92~bE+xT{i)FVz|B9 I}ũɍm Klt9DdeN$.h*h^4b z`+̙O2Ia뫈LSq p[ u_sQ>f\F4Ӛ4()o#xѡjA-y0?_ʎ-I5S(\^yKeUѨk)4~H7i5)^pk$eI0r!+6G8LֵĒB=^ILjl{~ksbI&d(!w@IG~FpZZ6_CTS~9VvcV)iQ;W6D "wEV?w'ǷÓؙcmY27-e :5lɞJ{Oi>w$w0@N,mm|F39FEPC  =>^7RgQb:wmWa/RMY\"I=bFKIXS ?<7/QCmh+|ł+#ӓ"]h=rFAj[  r\.U/)&njouCSYiph3UW~ m2S*+[˪avvKM*>ѐgfm/,ZWlF+o>>.8/G#1"{y8`!@tsLAYwȼEz,ߥu8aŮ A$lO@ޑÑ sk#s")Շ2ɾZߡKH1{*z}XU~0ۥx'qíLI:$%8pcX@g8儶ː5.fL)fq37m5g+:$,1p$zFdThӺ0s~t-v I( Bj|"A_,x's_`KO@ނ~vE3+z3 U}x᷻0soO>ϬLb_bER~/5Ic'a}w$+b)"/Ylwϓ}m~{R*Z8JkY4GYa\rR݃Q(Ql.H~\ã?J3 )]?:FUQ'kW#‘4ɭlʆ 8 ٣Eݫ[8KWe7J$ݺA9hȔŢL9rG 3(p37n\;,Td=r -Ur`^ SZrǹ"!$kl޿*mX>3_ϲ\:3DDx)j?'Y6H10I ˄DrNp ݥdZ7.r8tW,iB@nyVLF:qf#X Q $|]WΨvтy"QR}[l!3(Eoޘ^#k[4P.2%H(_6s`qU"Dsv !VPVX{&xvlEV[%n ђQ <TJ9>܈ei<ݚzᦺ{C(QfaSVErrGW!rn\!YZOiA.{ qV"j⎊ ǀ-2w^S6OzlE"aB_HU$ɕQsL}T%ܵ<.ɉz{C?YlB ~&(e K?°ZAQaΏDڹw3br.QEG.wggM80z. ΫN3IUP%_\UU!cP="dŦT<_8(--HlX*(idy3 yy#~ĀIIvvȵQ~Q-g>mv{zŢʲrٛw$4 N}4=r@. -R(mFmShlo3N,s;9bvk;E@8l 9BUZ\$28Azw_:x򅞎gۣP& "HV?ԱT㑙y]jd:IInʺK@ZƄ&Iqҳ jCg+\vp=m-Fytt]6WtoYY ^4B\qPy%jjGlUnZ[nx>s8y*_Tt^( œ K(EO痣jw=9frQ! iLחk+S֜0%~B[|a(ïWoʀUӔ)3~ Q%r%7f[F`v2F~mq0]2qPhLݖ %?vGHNŌ1niGc7ByX;'yו|p/.r7Gp>{ j ެrj7؟ş]"m"Y?2%-Gd|r8,0RJzNjKk:TpC/]NV/zC!\(auҺ.W}E̡lX0fe3\5@;8jTu'f J\daS*r6_9įt_KnWTOHlk'nR_䅭5(;7WYrN>jIqڲ\+?+Zʭs0D:9>}&퀿(jJr7}+C;Q=BJ"{G(;\aSiEAgTdfz Q+)YFe;{W+4~ɪK甓G,<"s<#1*,xyhΠEiXzˆO#'>żO7;dǷs b7>&i6":WtT(2Z z+*Cچ~2 5D"6vҕ[k]QR|=scr>`ݡnf$^zYCԃf{͓g, 5Rkd =VQuL5?ANxx1B BXjQYu6u7O7"Jx8B>6%L4>RᲮʕ/z(BJkrb*: Kq3F ح%pn5!r` Pǣ*cLrsd 9Rvu QAl!Z 6t5~R x=RKPDhU%jE15-j oa"2 m?xԨb㎂l/L|vdC= v3dpWyo5N7 _ ;4ۏs\![7ݥ_ .9?#sC-BᠧlVà)VNU9'4[PMSlEL`=Dʹ,+j)u^`/m&r2 䯎_˨es] [ȱEVɎVɇ˓YONg͖LSeJ ѫ4~'Ѣ 5WG,NX+̷dT6Vsi,soTo0#%:\趧*VZ`LW4n{u1vu0.$+'Vϟ8_^ƴ崍pv`{N~`-,xH#_ᖷFPϻ5FuYhaY{xml:Sz例+[PӈOrk2$v%GC%¼bv"[ WJ5Y:'_I2SkY _8L>2gpC{NZײ鈌u$I1ޓtS np3T?SjRcVԤQIpV^q8(ٞbo^[ _&kpwԣם'G拲2H/CI=sHINM+c" hG?dO"Q 0XSUcd8^ئ{fh]2 OВdeò˘$s47D ͘rB\N ;;aFj9V1X0\) <c1\VhƗ*#@#EDĝ̓ˉޝ-̵zFHG=Z_ױ{j#>{ ҹ9 mv^o>wI]'+:M3 3c Mُutsj=brڕoo:-,Ĥm+\u$OH!-?lk9 6i{$cZH`+idpdTO-{@<0ù2?7s9 vĥ.%oeJ:g|MF9lI40P9QOX+-?c:< y``t{R y2Q~5r( }+ ?BO<= \(zw\:eY1@] {]^%űgaHOv~y J]>`CP-i(̧{rК2qMi@S->v0QSckI wIBbm( <_J!7dc*+jxeOlNImg2H>R2aR/o:Y%hU}ZxJ󙮜0X|>pݓ((IgM/g fD͉\h-AZ8} Uλ; )jcܚ?ȵ@!;z=){dß>GǠ0˟6~Kɒ ւK#&?ft{;3}غp ΜdRb UXh LO`6XaDG,uHDGt!/Ѹ#OO0sJm`Kt+⅋39t8\CUM)VvƚK҂U7P\WU-FK(pm+Z*X{y>HdS(SD}yYupnՅ%l=VikCuC\nN2wDGAۡa1 Lor6k v{l,ú5]I{@!fFiƼ.*#N.삁K mNJRSv8v_Ptm_?@EvTۿ7-d^e|jL60$>HQ6|:JHKt*Gs Xa r%S̚kN.H<vd{K:@pN52'PaY7aӬo1eWv3ꡈ0n^SGy5;gV ,)<8BTqdNL@&Ih5ͺ+(;mHV,Ks{-)x /"v-q:+2(KORO* w#ncU,ϋ'?ч<]Vc##Poy| ԇQ:R5,>0d10(=|On6r8WtBHEjFWxU-\UAgZ+w`F>ҌK 5Cب⽐ؙ8#)Uy5di?/4YL;pw`LSa|W$z,1GCGδUOUm!h-g`iL>rZy_6QYfRranQhH 5 $\iTZi[si;g$8 *t#=WCM-Td1DeϼI]4Se*SE9C:Pv_g# F&6&/)C:TPǘ eS4y0+o% XK2-D?Fz+ AlJhԐ3V_ / ۓx1mudXmB(;:`4:j@i ;>s }nc(`P7ϑd\i:vkZrG^U!A[@KplrTOqzLqOI@`&iuyIF$n{ƖMCJl_j2? 3iOpK {J$Hl/W`G#Z`=Yn+8uHYk p.˛f{9|YT5@CSamlv^8uyXZ-mmev:Dea_n֏X .=EQ~V${֝뉳+YQ 1nNAT^aőEбצwENجKґ2 /+&NcW4%ඣ(X D5<~a;Ä%,^mޮ E(KF㹼!*J=se4YXJz`ƒ9#iy 346:a-gsī52*]ؗ%@7 ~5$_3&gC<HM5E!4^|? :qaAR@‡3ҌFߋ1! 9ާ A*FdN(~{ٖR-7ssP5Wf&dE31{wp3dfvr@0X9l|㇃l+\Zl.7WʠSu %tO^[=~1gㄜ5k%/(LaR:]%Q0A~?DQX4j@DD5'|EXRDR>Ѹ_1Ca)I(3H%Q,ҁRے ~j[umu[=i< g/)Y1jdd?{4*a R Iv!juw(d*B'hZ3c7"*b䘵txu8pRRG$m|ږ!$s8-[ ŽN]/w49H<5z>ib*;Es8b9١m0D+mmc &i(}~݅# N_Su3t2[)YaQ9 I {&MrA~MZ1#;(GUPvU«PhXjɾאPCOwY߿\ҲxIL;~9)"=,cRȺL 7]/k7BwFL}xQ<"}KT&,d6B0MeQ-({dUzvKĩqlp]L(rz֛d\N}B"2[nhdit|a ?Aq]xѶTK˨ #0ᖢs]krXyKHEw&O1P!IҲscςO^P~bAm Ձ]\%5S4"XKIE&2ҭV" lj#2؊ Nejv$kcBz(qK fޙ˭|ucA\?\ K盎=Jlz Ysc yqe$*41DzYfņ~]Rq} Գƨ^~>7S/"KW3BTF]_ӧgB۳M:#f+^Y0h\vG39~9{[ l^8V5tE;%)=x(_@k?J8߱O4uwE %R Az#- 5) lpoHsVcJ |L#e/g( 9~~A}GyTnV3LO7>q/ݨXC:F?So:=qE`| Z \wxyͽMú.+Yyy+qa'y۵nUMYǍuݣ GzgO"`|Tp1- em98kS*BxQ-R$NL  X0<(lc[V᪃9se.[7.`B_7 ^iR* fӖڏ0F焣wY kDՊ]5{He2jGj0ݑVK^ !7Ao'_ (NT',m1CeJ`z9Kg d= ܇Q372r?}$|9nE^t6O5dtGZQwx< R[fZ!R%]LJDnb\䅴!NހMN% ePkVI$|Mm#]+Kەm_1m`qk#9GvIpMl2ʖYbVQ" rnAZi/ϡmd O 4&N_qTYOV) W4+!zLAF6@̪,FO߶Xu#Y_L>3sߵ`j|8.GWcOy"鷞?: hްxV)D[&٫\Dc0 D9L>de@$Ә Bb5AμY W:DtIhSط%\kD%6>e\u='~<2/xt~u9Ry+%mY#):>: Ȁ3QyLR=INHJ/e45קLJY[p}DSnơy]#@pYK^8)ijdF;᭚q&TĈxHeWh--%BZ2Pczo!\mQ , khFwWe$lTդo RAs y;Jjv(qCTȏ}MQeSfCoсᕤT? PLlVA3:!eUSY\8"Zevbuo RK^(&ԈsԴ[66. pawe /1|l`>DI,r̆E"4 EfybPEc'AcڌԀ5BWo09@I-¯3ّ)+KȘcBJ??WR{SY;6  y1_59r3LJWm&+Ul )Vs4>E@ h_9*HClfz 5ӖoOJG];ֶ*D0gڌfAO*z<S~) h1"7ך]f7]у}QkؚÞ^%!3̕]jFXSm`ā<#A&(J7,ET*WA+ok5tgkܐGYJHXb>lqƿwW2[ @{LS Du,pSIJ2;Ki$[lFX{eS @s$&P\GB2ַm{讄-۶m۶m۬W*m۶SmZ/EO2M+i-7eZ.]ر3j>8θ{zFr'uᷠdihxPEHɖ ˣ_X׆SuA_ɦn.W$yx]X*"iS3?ݡt%5t6aoDܵ`?`XHrgo02õbU#Z*zWuǟUs/֤]R,rLm+\2Eޑ 7[2mۻqOlڳLK*O]]C޲/dN LvO v6 8w,lG=l^Wk+L<(nS#f?yX2uriXMn5v MΣܷ$\(E'݈dm^~p`S1g?FȒ/$Y{Kp-=@F’"I91Q7 uTx!EcnO@ s/\K}B!R2R* ! JD!2qD~@p+6/mQyɺn?d~\"~I=T 'Tr#]N: ;Gٿ(nYaxnG@zVNrtm-|iLlN^6~i:f6"Ȯ8ss]PT~!q2{C][GsHNH~ 9=eݑ9a_,OS^5D{Vrp#gjfD8܏/s{Ȱ(〖Pߣ!6M>Qa wl8PJ6+3V@C[ﬠn6w0Iv&:zԞ YǮ.Ǽr&' T-< >oqٗ1N"T] C~ICE9MmQ'D)< n'q1An:,M8a2o"[[:2HQG1NY<$BNJpNgm!tr%vi6Pf|{GiU H#ZOW}9->\ N`3~F,0f/gU l0 h\=asUMg0CQ{KzIJGY;DnHtۦ ]Y6 dd^=O`km_9һw150waYL%4]9rmO%A9p/Š# 2~0KfEѶK&5V=tӷnEx>CxpfU'~cx :!,D!7~@F)p{ *] Q,⓯h.=;fɟďh4_Fna8$ NqJC8ED_ɑ_ڿx˴L^tZ)hВ{q=țj\B2{8 4]b9w|ɺdc ;kq9E7SFT{l=˻CWfQ E('D ã?0+4tV+p](Bv/A/aJx">Xw.gΛՃٍMrV8Q_e͹9nEInT_kU팆r KS|pB:HIy"4Y5XMi[e#sJ){ݯA{r:D'.S5YgUT|˲<}ʾ){?"j"k1&14z_Gi 7Ѳöj2Z*#W5X_`96_'u:E6R(ݱD;*jOxq tBKD0.5ުj'0!b 4lqcL y%ַw``xe#[t#ɀ4RPs ũp9ws&;Ȉb巜hd3"P4kFmX 9 RqC6ԵMw7&4S"G4!Av2Ѭ>vXr-vj&&%* 2$~T">cN 26W ;ݠi_:.չ޹-ۂD1dOsd69דYDmѷO二Ǎe^ewH&ɦt}L>ႻtuKM0HNels{qky$ ~W'Mjz",)~m:5Cd{iO sɣa)Oa6LzJT `1mX {t'x6Gگ^}@]@Ƴ]J*CM}|g@t3TqAK x} Ls;"I$_hL[Z2 xhc P|i)=N1avrKDb?|<-GDPP`,~-1I V-n3 U/>:m Yӓ|3ؒxǺu_.1h-OL_q8@`apd"nG,s1G܏+j$&5*=1ۦ@wf9R 0M#>^7BG= ZჍPE$ Mg*$^HNX GVIo&b.2evT%EA{i9I 7eu M)4I?.!g("`0QjnĞH1onm(rLhb] dž ȥmgTD"'j9E?> Ďds^5f-ѯ_tdD-sR=bq kRAQ*{I \|npuboك rf"Uqx~kxw׫p3}w^u>p 9n'#ad̒VkUcCZK {O;n@)g'nbUswA:LB hsvNۍs~ D=~ RƊZ[fYX&, Q=&h,44 _!P]Êh1-ȏT_bhDٚl0\4 ׇ />^5WA{DZ&Xv 4 nmsi߃$_*" 0⏘ CM!iW ŜwtA0:!AKU殓Ifz'L #2L<0RoHFv:ϜbNq ƱV%#Iֽs,՘:M ?[ q@悛й5d )@0e(eP̞f0M@MHɖcKlcVs):a[rSZP%j+qS~,5[ۼ o}؅2t;hWSvh(M0fO+!QлM4&<m}J߅aO=tc9R^60IC렉!p_;r)I!k;`Q-*W7[W *1Q#$ 9Oo部hZ8aiC38&> 7XFe[+}iHU^ w<\ftϴ*p,].' '׾vW#DmieGysAM\pF#J9Xh]B"c)Fy( 5Xa&\4 w$[~l]c`W񐵖XӇre<,̈c}L@~Oɟ.` : XgbBsdU!uvZ6U?3;"&27C7+Z<#Ē4݌{Ft;c^m~>Tlo!ۼ!{٧-5ϵU' RINs(+h!8!ZEM^{J_0YPqen <ޤG:97A= Wn1X[}'\1M'XskELkr-R>$1pm<^(E"K.u<ⴳ+ׅǕ⥌%xwK'pxURǫ'nP2? yv}+IPI ([%}vTޒhsV)o<8_RרXc ظxVifobSKBE6Uס#]pWwxJ"WpY! SxS6$Iʠrv(WQ$M<7pZ /v:*{fJPf4K 4W%LȑfU{瀽5﬚Hɖ쏀-oTW֚{ÌqʤW^?Ǥ1lX[5ԝrDd2=$NP }>Z&[~rQ2Ӭqg/=#)ottk8CiP/d1 p&0AZn~4AJOzY= (jx廕J:,WvJG_FlަXJlU9,B}xg-L@lV/.,RÁMnpЅ9^Q5\@hà/A֓!#4#}p_'wdR Ggyӧ\t3A ꜒H?OԢd;$zE<~ȱ =(n5%|҂O{nPY%uv@CH&7;+ k]<5\fy7|iݍ7+M,Y~i8Rb \̜d賝V1~Fk($jj2c7c{\!y3ŋy7X.Cc5 hDI +9+j&zz=Mʳ>Zq?~q1W[p3{4UǔPVZ]&eT5Sv>sd(UeReNɥ4E\tL6/'1=2 F>t=fUs].+7I& _6;$Wyhal"-ti_- c.J@OB&ݶM+d P.Ew2U瓛ze0Jfh9QXb`\ 7!D]KO4G|L2{ο䗻[)Na[!:b@i5 D!sEV[AY^kMc[ j\8{LS5d/uŦa$lOY^݌~@ۗ xz:lqU$i֛\kV"&3El|7aT'_;” P}sU#dGj2٩?{֕_ޖr}G۶JGDd\_~NC8p(pjnoo%evb=qV+Ϗ2@Ӌ" {C?+ "q*@,T hIEp͈KwYkqSE5)O7G,$M!- tAg2;gF<{gPv_WoB)d[LwFDna % _8tV'Tiue (\jOhOfĢ endstream endobj 451 0 obj << /Length1 2318 /Length2 24164 /Length3 0 /Length 25526 /Filter /FlateDecode >> stream xڴeX\[qw wV8=K$]/}N}~߇ws̵TIA dٻ002UYMl]VFffvJJQ'^ r(:Xy(@{ӻ ` y:Yم Ҽ<,,]g?"cS (P { 2*IEu%UU]@NETUM] &&j$UTڿ뷠(y./&$gOF Ts'_Ԗ..LL. ' FۿYZ9AN6O'-Ƹڛ @h $Iv {o˟5mp_rJJr;c+{{3/7NNjeW}gz޾}b^ndls+[/3ȃ޻cWx̜vۛU;#i{\@NLgmAnneoffLlbnBft0%ӟrM3{|@sc[g9 pqrz02uy˂ ϿJ?#@Eyf {[OI>ՒpU0RwK;?"+BG+|VV@3%+S5_viXXeTsl'cb/P/#(,B0q{S`d> o6z5+&F{{ `rBs&?'Io0M&$ob0IM,&ɿ$7{u齞^O^Ooz7WPLj{=}&w2ޫMMM,XXXz:Xn +KYޥ{x wd[NVl}78ߥ;p[ͻ6w?\jFprR?ҟ_@AbU' P8Yy2?X_l7;'3D/8ϟfG^f=H3KKFJ8yiX-3@WRnV90~;;DZ*Tp䂳r S fҒ~ !ls_9#N`RC]5Wbi^<{rɐ5~Nҡ o/!}њ;yjšCu,%$ I.={P?)y@*~ȉU쨤|J@q%'nHkخl*VB[BqtzDS~_dn.oAqdKۄ޺\ҽ`iҶ"g!(2d6q@q4־1)>] =wMj5*pr7jv$=ػgM! Zoj<GPe[qo*y(7UQ(ŻҀ{-PⁱkT=Zq i}e󩂇ӴB#S^7M\F-9UO!*ӓ1.Oj'ϐ`=7vk8]J\FvLG h|c~i/rFLT}DWʌ~ KYFT0) F1f415XLbqzP(_NƟ'bOك|Pv&Ry֯xb> 0#ص!¢nM8iMP8O(z .c| Ǵ%|0_52WA{eIo y.?d| c CrL&<ؾgׄPކF .-h*6H{UѮ6v:e0IMh zUb s[֎FB#dJׅB2(T5ND\KUp(9*LgAw0#"\Є5hj=ZMJ)5lg {=%aFL[>\ɡ?և%\qև:7Z|Xd-Yb,ƒP9{ ݃EIvxv[[{ʨGx~<ʑ3y=mVwwp<?И9SN4M` Ń}EpΥjL|~ÞڈOMԵQ;ϊEqG^({; +>d19r(]>@U+D 4)- C鋢wYewi|+"&عÑϸniL$r,mdn^3y[6\; >~jN.s.“qJ~KD1rFG) WY2n`$R'zc;X4orXq윊;Iɶ閚xˋ9EfKȯt7&\B괼; i!AsSC{aX?C,sPqdW߷_Ncx9-лR2N(vKؓskcwS8oyeFysK]=oQ~ua*DnҬT|i !փȎҗ<⌫ %Զ#rb%X?:֥?>=,zw)T_4h5%nG$]9QW/4)fŸ %l7h|?(fo0)@)6N+ZҸg{Z3EyYղ"۾Oֶj~rwkKUbL*7r tYCOז&|G ]N>* }4K9&$iAL_JTpǫ+z9)CZ>RjЅדSEv_0pySeo1ad C1I9БR#NcUi/ U.Q 5khm=\!;qjUGeEGp;dԒq'F˘>by"oH$kgZ t*"y/N|<2c9O9<ٽ:Ȯm~;7VcTޱNNn1*ºīK-?M&wp>x61%DNO>ɕuY@:lc<̧kO}Qdu6=!ݻ'Vx1{!0{5`ɫg,ojuॵBGvhsfi"Tx4Qj4Na(!`q( V4^Ez_a Ll{> Uw}3mzʥ:3~K@8pd]@ , Id)sʁ:m\Y8PqMnòO.ԏ*a!m>ե]I\`y >Q&|rK?J-xc_ETVlU+SJ28u˵|R^H)S%Bx|ʏ='KBaI$rSrMejW,G J!{8YF鶊~EYnYa\7G3LHF7uij>UO;xU*.]NX*)ەUGR&my T닻f*DVAfry2җ+ˆYX3n4א\L(Ņ _%1ꦝ3uNv=t4v">tSuڲÁ+tzr屐~Q֛Q3EX DhmZ) y=?;H%'cɶ"lg 5irR4 |{ ­w7hXJW Uh>NT}YD'@/&E6,~&5mKǫUbGFdbMO,"`>Os >'t zW6 ۆS0Yl12oZ7Skij@-<Q( {0TzjEGVI*JL6wE*HՅ֖V(8)#'8;桯/ְ{Ŕ =FE 37(!=.FEvisP@t[.E%OY'q5ҦXi1P~IU8\|Ejt(m'!9ٸ{CZ5縎6a摟8C2H]3*HvrP&-RY*f̉:=7 '>M䖽/\M]6o1x%Jr_X ]- 9dz`X3hx1zĤ~V|޶u`?`UuQr.7+D7N'qXx/4DjZヘk5=K,w9"jjZT;˅p?LAPyҗHjb#BXyMG8 $.X!)Jl?46e&Ie1꓅UQ$OJ: lo ,Cܔ G&9LB/@|\zr?>3QosmdiaIBVkl5)K rŪ/p[jn> {0 zD44mqhz_@g<Աf2u ]abK0^j_.!)@pN>ঢTI rd 슔1XKJG3TsUu(d4h,:vKuݎlV KfEd$ T~r9lL1?lFkyaxi5vѿRa.E/tݵuf䤔֗&: X]|\)j9`| G:&C5,MJ_߱Yl#ݿ:~&%YbNs}YZ%Nh߿!WMvtǃ琞S&p"Eq 7*$ _՗>E;2G\:cIf-RF6RpwGGMH0ѹ\"#< jP;+)]ui$уX ۬o1<{E"AR,5gCQo4[0cf[Hm`)Oɼ+dd|mM&rPMB9hyұˏgM ^yۦͩM(3G@n=>Kt\-[3\4~ۿ>O6=}b趃֣RzE.TA$nV Ė`(iҩ~SLH? CE‰J[R]窿ؓ'-ƻ?ZvCu;;0!ź \=J+St(N0g|G r;h/VrO1Lp{hlo?HMN+嫚 E}uNfW"{?O1>uruz"Jr-a,8I޸l9{Dq!HytsưtEC\KLZ-ns\<ks`؋{+q^,VqtCLh\Qfέ Å2ɇ5 p%-] C j K e /a6Xj4?'bK6$qת$#i/fl~ε=}YVGf%푏DF7Ro'}W1DSAyt:ռ7&E;=Ԝ $Ϊvad`Dҝ]iq{?A¸ԺJ޽^?zG¥ފ6}45a] a ZcR#gΙ`cygN؃k[|ﮱE%+"bo`)t%3>ha7۴! ^6ӵdqD#eMJXkJd p;.Iʷ_-V)}z8tc;^R\@Y,;orET*DJDm! QxF&cLxܖv/3f9aǃ2hy~Sm1m߯ſ]Vym-PK=NR=_W //_ky!knΒuA[*d9XUI번~Bt+J}j`|n"RVOTie9H'۞iZ Nr*4լ*`l; wpzm-b20~>gא-2NNFGv082N~ϮhQbe$FyAn얷ȯ֕J6P}: qN!Z?CZ! )=GW-`P&{]TE ׉ڬy>$vɸC*E^Q/xjEh "A}Rȭ0[/x>|nlώX: (>2:(c`7(j;Ѳfǥޢbw^[6@@[5 #Y%lfu%sKXń.+qlݸiBKFNZְ@>NJYynY-JK#Y"\/ @i\=CxԁOp&+jjcnQ\RTTjKv0+`ņ ??!"cȶ. B(}{2=?cv4Y[-^ffHXudvO2.sļ~?F[ ƌnlҐd$" Zh]򄴟؎SUBqʺfA$_Rhg&+.[O{XAIZtbflAx|8&$xc>Ëގ^W*1X{C[,?akAFߜ3[z] ~[ )Bw~QYJ,D#d˰k7 Ͽ),#գUnWL"91d)uYckQǟWe7lxO#,пT~S$gH6@ԝq{kP#k!e63H}=1ֳ"dtLW ,`80 Y׼Ct Id ",/% *}34׶E`%jAFv6,ӂuzM'3XLa B2%E@o~G9VBS;.߉W" -/7σ(Eh^FQIۿCޞd(*,-Gk4hmKXJ;֮?6͠5$(~A!0 Gs?^_O.@7e Z8M#!k[GyEx[; ǡ2O`>M 1ngQ@ ,ȫ, xN7ɤq݈D|_$ ?b-={+r40*k;!V(W;۸67)~|[~8cf x vs*^\\ |mWzPt,a>GtETkǷVN=K'B?2J#=~E ]k&7e]Tİ[4Hz/dt+vlաZ]ǴN❁kaRؒ9ɕfJ^8L5GOOVqѱk Tdlj'(7t860j FE;06*ȜNi񠼌,V=!qCo Ζv*K|Q+]{ 5Ԩ'n^건tfBvvsf pKr j#k0q+~f0x| ObUTsK;o|e˟E\א]^w Y(@}A?jWEXa:&t6S cL.AU Td'BwEu#I-^V^ߒkFf]d$9uS1~ 2kC[u@W?gx*]v# 9cMh;{~~׏+sX`lLsLi AԞBo$L!}J7޳1/UoE?w^druBSi KȘcQ@G'ʛJ>Ⱥ@]NB)x/F.3^!#25&qڙY{L>(6P"2̦*&g!KJQ"u – K5lyv ]8!+!]8D-ڸ(+=},A^xe|s-T,Pvf[%g4E#O`zX 2H- 'ڞCvp1HK:P,ݱ1 {0`N*4&_OFp1'koeBLJ5qq6TNj=,1Mٟ#f)a5M'LB.\TBH!i:HtDŐK>Ha3 σ }u NIY7G*fON>OB Y>*:U9o=Y Fg й粒|zڕZȞ4 s=7ވ 44|h#D4Vo,VQfSϰ{}&ShS}n^bWgC^KC9œTWªCs䧧X̒GwNxj ,KB$?D t2j"oS4bPj"?xՀ)J>쩹5?-%![z, WpUxX725ۊv_jf z@K痥4r}YeY<-w[ɍah}:KQiEnb;[O%::=ЊF5'VCU 9u˭$_bЌ|ceI,}wtz4 =ߣ.'; C~virl,3cځ')\jXbg, {8Pf٠ lNp@A(_B˜%3΍"T?Nk@df"uL[a-~kwՀh*BqWa/*EM^ _PY.nm}(9vlߙ̛~jsK}uH@eoW$?x%@ڙKF4ۂ:S)RW/wDPrޚ2w~~%d޵ZJdu`UedM I2vy֜iS(W l;5墩zIj0o\^4=NՉVy.=m_p#Jn&{4eV)v{fFeD=,6'5Uhk{;P&cSšۀ^~景毫co_YxYjPoLB͏u| %@h,C>Xzxm$ODŽ̈\)*J>pR7Sd"OȪĮyS5Pރ>tP 6j@:rt8J?jl\7#{;{D-C#v-& )vY花 .S*e޾LF"2T" )!)ש&)öNr{T]تJw*,nSM#ѩxē)%~/H1gFIvCW}usCҶHңMV6͞Tkv4nU{s.)fZH9zK8C4ئIrAݧkr5s J) kCبo7r[u)4ٳ\QU0>>"TI|rh/S"#-W*vhj%.)n1I*KM.#'wHM\P}[H?3:CKھz클fNZ?%'#<.ܢ7/ Un!%?PFmkTɺ;f_] %$۶m;IضmvlcĶmc<ìu~]kUg!m L}\+MXԲ?vhO v{-\=D}t[حݙ 劈0>m%Y8FF.Ojc/fD)*Bqz<몢 G1DᢋAijz4 2 7g2WKއ-fӃ݄ >v+đ/*=;CDC\rh&Z䘔-/4f\Oۯ+:!!@ ,aaFsb#` gPٚgaHuJ>϶S0ÃZS&my ~1߹_E"HX!cc@ʬSYyt\JN9q]Y!;֠{y kn"adAF&j9v6q(UJ8Nk4z6=$YU8hdFoApgzI( EilAQ,A!0( bS5?G ;q,YWu8|`"lŽ ~Aש=>A %v|vXGvc?9&:%#C 5Jb\($e=uvFMSϮ m7Œb?>):.!LbxB>iTVT^laQ)c+ͼM"@a4lE qeZd'P#!lFfV֢:6#hhm*n1TEVB{A1XWXT%yfq_u ' joμ1fLRog"@ǜAںS =0: 7 X^EAc jV]f7>['. Ir3uP#" |W\kXuL\"VLmsA 1*Wq1GotkwF(]_O7m k#oK{rQc*wˋ \֖N!\pYWJ-SfS|6}F?_xݕCb[qĎ"}X~h *)d_1WK٩ Ȇ~Wd#R&=fu Lʑjeg*.Gn(dנ9MѻuiI/uFΥ9| CGou +Y9n2G1v@TNz:= 2TUKr6N@Ź.O9@d^7)_-g_ AN#V]͚H` 걋q\z203vVb@דtUy\~(8gnQёCT|Ec>e/R;b]$NQ;V9ʏ2K},GB0cr4 `Ӑ| /'=̄ҢKT%X;ncPű L6Qiu@lA$9`c&EZi=D(Ud #07'9gAnibjay>$( y~Uz^ѸUw֤/i,69S\/XBc_6Ã&S?EIM[K zRM`bn,@<2!fU!~t<ên,{X aXБ,2jRh{S5RJuL[o~c{^gU0?.`Y3E~LV;S MU rZLFTbi* 8guO2R4ir9`Sypw䙡~m d$I 7|{ 7Mx:e L@]|!()Q,țo}{Hϵ~G' qVp~mT`Xd2c};C3*%usL< ~#~T2dyC2cі#/9,*JͮlGlA2mKdS[DsOwʫ ر2*tc7db!*Q j8Ƈb&$ qo-* SH D#b]RS"5D(Ҽ%tHXR`X?zcy/Ts=RAJ0h6 m #h)Tz9رw;=BôOG0nSƲD|lIb=[J|=V;IA-~,b'^×|d`xԥWԆBE>1 {:wy1Rͅ4)r#s"v#ʹ O.dr j yW{:e q:h2&_Up(~ʐ%@s1H]Br0:8iq&(noi$d;Phu\D_"r{-C}*0#§l)  G3cEC8!WgOu'\M 4׺ gQ9 esv0b<ҫ+B|.9DЎn3,2 nVIgu8wI_tQxqfSn ssOU8 o1(˴ nϟg3g? TZT㓍]Cv9& N!%G0 9ak9 +ݝtݚQJa@% ,q'>݄mj@R.O6? hAڹ@L%0, 7b.f $MY v]j }MRjf]@zTsrIUQ.E룛2ya`biQ"m0ԟ{>n @(WBH7,<?=zDݭjw++9^vgך:kmQU*%թ^8Pv "W) @t!"dUd0ens)< ũ yg*O/>B.Fo/ 94kfm/8e;`Gy[!K&nJHg5\f5O#pHf[&fa~{#[ƣd<s`EwjrBFeg@, #iuZ Nnӳ~#i]z7{.wlD*݅p 6~d1_EnrIN&kH7Z]Ѵ  y@zt-C{sB: !( shئ :% QP\@x*, ! ˯S!ү \E1dK(Լ܄ұg&):!+'?g`y^1q7`8#9Vrwt|tQyTb۵'ͽxڶSD: ]9G;a4BHER=[W;3P6VD\a鉥XM)P^ 3sQN*ֿCn .^o/) Nq!nBt0n'R2\w2t%])E-oF ST#*4ۍ(z_7mfZͬv~6M_6bϫ1s$m0(?4ꛬ 1?L^*n|1éKZPǝ0*%=8{v(9[y/U-mאRc(z7}˜I~"lkuq3DZW !f>#k;xЌK$W5Ua <^)-%ʡy͟ec6i]ph㐈>tfO}d8bIlqbM^l<$ݵL*6+l[JG^hz9/U&\hP2"[/+,Kci55Qil耻€wQq/k[gtwZ{ngPԵ"1|胊[v\I[# k/s֒ۓCQ .o0?jb8-RQ; By8/}$&D (ʲ7С6g|p4ck/ع'MJp>`8/.ÿK.!u >`5m!l{jw)Uа;Kmfouag+v`{-~ROPRc\B^0KJXm[f, ܠI;EF)[r_1[:`$Y`FdjC3N./i2ObM'a*R ‘@+c; [,-gg2<=YZKꓻ& <q4q 2ř>z-O^4SV!RPM!\OV,h2K# ƮBܟerze9_gbhUfNnwQ; *p cW!U:~"mLQklz"+xN\{uh|= ˚{`*Tpsfjw|~LycV!Mh#ۖS\?≮AaH0?jhrS2MTy3DF|] U=;/ ¶Wޕfdix{Mp+hvjnHyGȽpBY]̚? OB\|eu:=e6?]LXαR^S]a!:;@FBskYC1^ɏj(Q4@KQɯ>#C9xQ/;n9JmP%?a4Ób>|xB^bE9CScgݜvԺ@QJXa_~Y# $+@bin@cH9+]8!zP[nMG#x4 ܳoqj/71*Қwa1jl9Sq6~jTס  Wk,Wy"^&K|Rzn,b6~0ưIRzhd%/[eU.~^0Fp*uT,bwan;]!9Q¢g<5kq#TzRq7bӝFਛF|n#Ӧp-03= |Y񉌪ܑi %!ʂ \Ҿ+XYƇJ)rfԩ`/DQC1㣶Cr~TtSnx:< xT& UZj؁5Nc:N,a^K-v-=A93mG6ߕG՞iGI и}`Ң~`{Irɡ >,̱ IhUdWM&V,L17P`{v/;R I3p# s iKOٌnݏK % pGwoܑQ&1QGR.@=eK%)BӰ2eE9c6k{]*A<(:ݼy\oV&ױq9N4g͎ [(:'}cej"7k9H !N$[yyX(TI4uʀNp C#MUm{VbDx3+\ iǣaOHb)iJ)&v][E"R|z]s@yJ]t)nDGͅp]_P?}41v#uDkIID [@Q-T_ C$1[pBZtdIqTyכc$zg B55y~yɵiZ<|0aHr&b@ %cXS"[2K O*}a4?瑥=e5B{("5Lr%r⎂htҔR:{qz>B3t+JK:NHYDz8,Ǜs^USpKz @A|,itMOv~1Ϭ3IT 2<<ْ5"~#ݳ9W'逤+%ls2 ~jy[Ɔ+awI&6l|nv۳vK-8 su\]oJEN"1 @*Ĭt{]B(8@;P7Z{"ӽqcj+c#LE endstream endobj 453 0 obj << /Length1 1608 /Length2 6311 /Length3 0 /Length 7123 /Filter /FlateDecode >> stream xڭUgX۲FJUj& HHN "!ޛ һ{EtHG}:|kf;;k΢'AZA4$P`F<! ( `gW@AhFC%PPj  IHH؁ HG |܀/˯?<0[ #4߾vP *hij*(k( jXa0k(A?@k$U3?K:;BakPwk//r9;c0g- @czFak # p0`Hg5 bj+*mF øHL$i> Ƌ@4+9;0G7 g/@ U'Tvt{O03nFcr_AC\s~7Ch"ј= Ww#Oߡ\pMf\0@̆q>1/{@d@T`L)4œ`P6 mm1=mC@(8 h@>!Qѿt`_M" g7o=c*<ߦ1u=1 $䟇_ OH\'"(yl"@"o `4 4-(u25kNt`3Z4r[PEvL8r(j DZKHIKEWf *t 9V!?J ]xoyU_3,yyv8d^67+WGΝfquBmȗO />{n^p8,"?eub;q$~]CB^EQ͑yzc'#6'i%aQmӍL2=!hź#>y9Q;<ݞYȗpY tԄ+\([xkun:{^Y 9M;װӋ+wIG /GplP>/SEX7\o)ݻjzipq 43%#SLCyoYUB ٬7E-_( ! C%t=n)bSPNr<,WpIڄ_8q[b!n^{;vO|c&4r7vcFɥԫ^\>Icy$WwaalE *N{I2+tW'aK [7G$zi|@&}nY[.k.1iu?}E˚Yx6 J4YrE0^#sȟ쁠Wɍ@^֋pȦcbF;>6Qa (с2piod^$ƞը;uiH?~ _Fj91et]K&hjbm)jR'}BEԯb @0yO꼁YxɚԕL蔐hɥهG]D}(}za:'erK Gs?q+h%9၂sw|f׀7KhpO;AؤW~f@B>4ɜV>s8 +ε~od,EzqvIRN9k5"q" {d7&bn}5gMs\zʣ)wgRBj-5 r*}'Q6LJ2ټ ^Ǐþc(m+MxuqP^FFLJ@ FGǜ5P[EݪυgJD Kj# 肅$@OP&{Io_>z$PP6&_௱*lֈmM'2F'Z+&Lw̓&gUc$>ɷE3^p5tɐITq^GiwlO,z(@V'Ouyɝқz;RxN"0-y^v رi݉GHvUwtJ-Kevǝу a~!>؁r}w?qz8|Сڌ@u$Z06AҶZ-H[@חD+wfmKm,=t+0BX8[ 4qGFH&DZvps=56M~7(5)19yy{>B 9ěp$(A6Aϼ3t;m &M׹)VVԭ1>z @a2L>K_^˽1A7g2=WޔV~STIM*ÁuǪdozb&Z62ѧG^-$J_b{h8o۴)?e'w3Y@'#}u(k!zG7OntV*HܑV)IwOK7rL04B|A|:F|6y?X@H۶8VD (}[Och֫gL2IdD뛓_4rd02*W2_e>tPz*`>o [e+4Sv8W*jIJr[d"VrO9GJ4j#,j"T.nܗ-[x}2Fi+vƁ6>᜔6lȟTxHA~mfh6zϓ'%[[>ɏ76ba?v }}97nw.<Ҍ#\(BC^qa.QOeA51A`maY*<%д)& ,w@aTBM!qV?g !;Z̙fBrjC`ǮaV|Q} |6zK,?Jy66B~r;\<Iv@6Yƣ!Y?Gɧ; QI ucj \Z'4T5 rdPb0y67K*0'UqoQS&;)Dŗ;|PRpFҲXA7 2nBq_1C!yuF+~"<ņ uxV;MEg|pYk{;}jtk!w^6PlF»&h]p՝;x,CZ_MDR o fْ{lO,D~2Tٛ|}4OC,ftVSZsJa﨤eRb"'(!9*aZ-Ie{} |Vk pU,ȿ%!9c)x t}^Ȗ$t.OP]@},EuW |IqZ%8MD}' L2CH k,4M $z/|g=&>u=Sb?-h>YZ:5^Xoybf7~_=V);|זFuYٖZ4q!1)a,q}.Z ‰ I~w*:zC0J݉hMld͟&V0(*h;]u8|*!ZLbƒNJu^z# Vc,Cn0>SYNB,PwyɦX~Mg鑃lK@&_ab=L"\=JuU7X EB1n=";-J(&;|VC oACn45yq,tH !oo2\EKI*a=tӱY;[ 86JGl?)XF5wI&gP4C&q('$&;o~pdUhy~A$'ĔjLP- Z}O)4w{9RcNIaЊ'fd5j.BӐQMgꂙ*em͛~&t_XK2%3-p*|:;.9M3a/`;fihcCLFn؛Z0V}eg{/6%C-G(8n,OϛpM升 +<Iҽd>Jer/T-^N/T>)I}`O8 ]loZXuve Lkt{*JU2֟z.qE[K32wG +(d}Ttըt<7a`&;"qXϩN󣃓;Nގ*Oq@ 2]{(Hbx{-Z~ư_>tKyӍ@FkxDZr;p |8 kn(ľL#MohE*a Y X&D\KRk(i{7t_^=ڹx{W;oHOxr$P#V2P)ᐶl,L_`RYF3yzUV{n"M\Jg\._l1sme={#c>zxC&j!}USC, o MVtfSᕊ!]]da͜e n7_Y|w)iXCơ(P^nl'j{yr7^`ƅ$vclIiѓE=I:G{ݯ;212Wlc݊'O 2FW>hRzg~mru ,Q]I|j]K^Zq^⊝wǧ6#O93qVj*_+B^Y5XOrJewy3{")ָ,h\p-Luƒ/]gB%,fgn\O悚"G|FiI6W%tEu c[ђN\U{e?}K %~Z$woքξ{F6-n%l)ܟAfD=Y8%w1>mwEͦ?(Q=L,GEj (u;Js!sKr|~:nRl}/|5 %d~gmE廗z4|)JcJ'Z%vw/`*3|vT$821ݾ@FwiTq+/؜!YOw3G([> stream xڭVeXQ@s莡C@Ca`!nDP@JiiPA:3>^^ee5Ump/O@ s0o; aQw! {f8A p'_jï G ]8o]5?H#5={N rF_K2'{{ s7FW4ocQ+!; K P@!0` rBuw@MSO7vt]}Q?ؑ}9[4u#0u;4-8䟇ZVo8.Qi}6aBW- .r',K@fbU610ger$=a.*`eLOYDKfR W pv]2w%_./;1h J(23g޼5!,,], 4tOsd>ǁv5'jz4E4 6- F|5?PT4<4 &PX* #Gx9#o}0qbbkNɱ,}2k٢@Oqdi``tzZ=OH-aſ%Li?\#b[bg)A^L1~ArHCu:Zi%n԰K&K[bWhᗂ#MXl*+P(-v#GOIPn]͚*\,n >,A$_C]nrM!3B45^_n׎6?~*qLM.}mj98*UZѢ=c͟0xTig Y>s(1VjE~Ӣo)y0V5>*PfbqYpyd*h$~#*&Duf?. X٭u > 5c[0IBNXɦW I*ȶV'F7smNS0'J:X܎ n #Iӓz%o/K*nN;8xu*nX֗#!0X'Me5ɋcALc)>S=tI_Kôm!{4eZ&r: !H[\n~տ2hFR(zu;p؏jG/rMM1-Wzi<_A3\k4:|VVV.rmJG "(1%PI'Ч,>qm:Mv M9X⃮ލ[)Th#"F#ԊmI+!sIl(u~l?7ͩ{KuwǫִI^V@m"7MZ"OEAH+xP=FjQ^!a_xJQRɯ pĜk9)sA3'ZBѤI7Q<묑<`ߗP]ɏ) FinH/!R6r=p_k kִrcS?=@կHEb5,HGkE _KGfl D5̴jG9mWi> -W5[3_88?ne@. GD:s2Qp q \v1;<5]N$bڢ|4Zau>~,/Yo6$Ib;-kHݤ+\&mv_dFY ]5s"#~51L,O C{cr3CAqw+0"ZN.qy8}J1f]/]#vLL}c:<2# .y$Y!6CJJ~g}?*ԒJBiRzAyo' % i3wR{yOp7$?-j`w &\ޛ2_?n@e7]Edɰ~qPhm}1EĘ轕z[<ʄ p `粽dP~6 C$UtQ=fK=ecMuvy͢4xiPFk13Ɍæc Q}u:: 0+fu*YǍM$u [ykS Oli@Mk9 \W%KƖ<;O` %9!> ؠC͖>$_?H4':>7RPxSL\8,̔Pec-tӴ] `.${iX<${My dYjC=#En@TSK B5b6=:ƢuX-saJ ֏2 9] QׄJ2J)5,Yxyəsߤ9)o?^ܻGUrH _]36k>vA*: 3tIlhNs^/ Ⱥ+Kݩ)@@.~#"!ɩXs &Ȑ+y^fnI"q7 6HU?!B!sc_LGE tuGk4'}ur4 D5a]J/ߩinU8-m i(w(2L/Wxx& !@&M *اF:i8+5h2u.,yqɛ@y1\2&BmZ{7Ξ)F7e? h+8 ]^ W&t[gʛ~=0% 1z+X=FD$PP'AXDs TFN0o3uӔdÐYV=%G7>]ELf7F7qJ)U;C O:OҎkE0ld1 } ~  :&/T<{}"Xw.B3g̈Ek4zϭJpOC+"*,M '.&4F x|{?ѻ/m$C Qu{09i ǡqFaEh<9:uϚm.O<)lpR‚GBe= 4[L{xr>'ʷAA]- ̤ќĔc<3,.rgdb!YHF mcbE%Y ugHJ`҂pk+VFf0X65lUxK+vO]D|r! tfm/7؂!*hODž{x2(/*rڹ~4U{y4\.̌| %S5r-,% )UE3Nm7dv+&Fy7;12W˶2/u꽕Gd\yH9'_/6v!Rs[s;"[G>p1 Ͱ=hYRiX\tiz+ א,mQ'[C2ZTש̹I {4vΥߏm^zQrG[0}"=(RiA䛜r,3MGE3;G1h6'm]+8Tӷi\o0/ok@j4\6PZ9s` |Ҫ^dOO=1@[w&Ջ]G%_?}ƛ ?EhxMu]9g8} 1968 ,/X|(OW!i/F7ND`dDl na֟zQy}KzJ&^Pae!jl@1<4r1Ftzzgf?DžQLwmDh #* ؓJ׵ZϗeO9}3}g5^H^~yDjQ S4WUsLg W-Qk$UXvn`+Gc(K*Q92_ʈvُGMrС#&v ;g~ڼub.as N,Ttyn^[i9=Ggyv*y/Gx4E~Gө> |G'ɝeg+ C|5fa,m-Yb0CiIx J@ ge!PڅH 6'2V_uUJYPg}v:^;YKi@Gģ򂚅<\yܸ*,x|2} 7d(&Fp>iUQ)%Nm0G}]h[l~| j%W\8|{Ū Xe5Rʯo:,gV*ɣ7)sk\t>YBHJyiZOW6q 6S FZIZx^144AhI*")4ճYKޤ@e3}+HUHwio 9+q|>?zDe=IHn^"7UM}EbKDs cEŗ2WMS7-ضhuQuAq&7KO XE]GszfKt$f^sz'DPal2@+.Kf4rjh@NXj)ob࣯m+5oUyBNMe=ZKVD7opvh#pdя1)sg6hkl ]ZY L$'q))'[#&O9 ^a.=OU~RY95Gr-`T,u{q)AOd>Svޕ|+%Plx9$>\~Se? ڽt6(Ix2_4+~hɓT, 5ȁSIK;RGI~P[7: 5C]\'#הP>u>|UBNJz A&sr8raZ@H~[$kQ_\J-yoQqS9G̜c訾S $#6GxY93miI]L$^cG+^ҋSۡM@<>mN&#by 3Ƹoau K+]F}f?3rjh `CpBN%_Z9&L_l t3[h endstream endobj 457 0 obj << /Length1 1144 /Length2 8457 /Length3 0 /Length 9223 /Filter /FlateDecode >> stream xuveX\[-@{[p.@yӯ{1S. U  K9Pe`e(]]4Yԁ֮W FJHAfPQ kڸ Nv ; 뚝럁` @r{TP JI-\P W''{RvX]VwVup=. kG hv+ӫy-XU+3Kv6P cubuB^ q;%̤AkSl97;GV G˿[tubr9?HWߘ5 ad`@ Rjz:&9-}N+3{/ @v1sWK*d_0{%3(0`gegB-W6sؔ5tՔEIJ_%Y8,8Wu4xw{39=?:f Gk " Z60?p-G˿8*; `Ndatqyu?R8Z-A -\!}Agz-PB!u!w5,\}Z7/ܨpvܹ)YҪ6Uo% Hv"aabG + =G`#J!Hs@FFTjK# OzY<EC/y{?5AĹNiv۠h ]Mt hM'ؕX .❰̅Q9tlch[Ìso IbL(:-[ gwL_bp4i^NUCEઈ$z<9ر6 io^p_1=p;SkHFNr7|0O畋o(>k0wV%d%!gNj6E`V-^$}+o-*;.4T("W%Yȕ<[Dz]95:nB{Qo H]JhBʄ KBh-(I6%E^CeؓXFY͑;߉YpV"Bvd=SUyD,Lr0)y;PqXEt6߭-)D!қVqZT起FTFKlKO\ȁ)bثR1i?T"sPlh*Op`;oVG (l ̢+k\C\IXMeD [Ho2=Ƿ5- &W GRM_/c6nt6+\!cIwuR;M~Z=ѮT02hUY7rr0ǎeݚٖKuhX=fR>~OLZh$rRh)* _Ii)պh}0o'EpНd%Dy֒?~]O ⱇRu+O`nNe)nLK:\5-WJ w JN i](9)=oCRF[xTFz_O󎐿XW 3b__t. ;w_l k{[ ̼yamCF M_3@.g؁mVF'XM4S>¾&T"tݨPI.Mj<ǽTU9=!5R \5V)W8E]EKV>bncwJzOX=9鵢2w58soO}d8WTn'~ӂo-*~سP9?Ǐڲք}7afzAmciNmoTYƭ5ݑI]"t\BTN4*8YEC:0ꪇ ZW|l*rsdo 8qvB([e@[F,J<8CV}i]qJevbù[^U h/G 1࠽NPYuDH^΋Pe_|:A-f]v@BB#f2m҈a">' o:1/#m5l$=اs[#p|]=9>ԂhbI/8 e?mzO>UmZA5Ҝݿ?on}Q0>knܹ@lV^*K" VwZ7d#`vItkLb\*WaHQ&Ky1RGbi+b/=7c(&o33Xש~]|7NaC]ģ>!a \^C:Up5t9ހ] M]6` @X";\R7fYkAQԕA"S6{66eHU [f򗧶B,"6ՋoHj.E\;qΎQyfȧ7Zq:,WaB_"0:tD ɮB4\.Oҵ}mƂmZ]&ucLmuVγ@J,rBǕAQk鞛7QWAF{ÓL懜q($Q|)RᒶJ>D5nD#&3 WR8K*q՛|JuQ$evBx4|~N.t`hHL 8}w}9i-:1{?ZWyާ_T`EKe|']6A}`)U"-hk)FH -w¶i@Kͻ8A 1 !0]`p0zM֎}&hDР%6 @z 1\"фg' pk0)h'Wncr|Gƣ[4BC$yOς34"45RAu1'הeaO!z5ZҞ hoVWYٸ|5y[BG 3̈ y?Y"(c#yV(!?y+äuUGFmղ_̖"}q/IjkAe$)b]䏖o@n #`~n?Yp=_z y|v?tvCW3@ͫO p|LɣTRJܩ7S#}jjXs Oћ܅ x$OLq6·rl2 :꬇f/yeQÏ$^n,N% $޵P, /8dQZ!:9xPlge&Gq?E``aگtJT sJEp0]X$R5t) 4o\$2,b;$rA|)f[`4HR*]Ѻqh31eRe\zFoUCEܖ{ʟֈ=QMgLi4@s.mUtbs;7A9_'s o48K&Kt_^tvI~_n(?ؠJ%$4)PDGhD{ 7NU]kL1D^Vజ4 PbYl ͏ۥ Dbj$`^/V0 0FݫOh|u-UN ,N\N:V ^y`rH CeA$ƋO<(>A*>;$z/vrsC" 4nm&ŶwFW|sܠ޷!SOEPks1}ToOuubk5@zU=X?OBxwԱ7(Ȕ,r~آasd`WF' գM_,v6r v-:k&X P-\y23yyLB&=Ga[5$R|f {|QO^~9cKju:c]{.Nmuy)dK?RGzl{ZLL%tڷZ>Qۄˊt!I^Mjqp5On}l*l+煡8r^Iq|}ߦ2.;w&KDwZ Ϭd:lO-۵EfXCEKv89c"jSC^AeOU$ k%L#au#)]c:dzt9O+ 7=GԒ&[F3kk5w'H3f{R"½K8f~~p)Ho>=o_8ЅΔ !Z$f2vV^ݞ!.*|aR78s_[OơdX<w|f*<`7Qƞ)1 Noz iH/HRJKkD^B5!޾9toj ) `Jƣ2{GDT~m\* =aV endstream endobj 459 0 obj << /Length1 1177 /Length2 2801 /Length3 0 /Length 3547 /Filter /FlateDecode >> stream xmSy<6dMn3Kcley3b %IȄ&%5#JCHPl%H}GNӯ_Pk엞t_?Msq+Z~Pù&0s ݯ!R&q B|JԄ|)̂ MU尙\ h9"?QSڱ6yy5Eܞ716475}ħeX[_tތΚ&2uVWn|e_HIC]~}r< L$&$XY(]TvU~|-u[Fb^Nɖi](5sW&8cEnDL>% \`>!AnTt(&ҋV͠DZR/L-(>x^R{ZRć>_ZDWPxyσ94DIkjw0>;3s=QM{: X^,kҞ K!/2 c#arsNaU#m@߸ ~/ӄgiw߼c1ŹkyKL<̋1s\+)0ҽ}ٻS#ިu 4Til.FBƭNT&~/}!5ŒWOm9 w{w1~7չb\G'УyTe"Bms\WEK+y /mpw \ΏYoL apzY9(XPΜN;U3tRJS\VuKMvO.z`ܾ=씯o]MEߛ8­48zg$ E%l^jU|b 2msVyArTUG] }s̯-/7Au/]ڲc@([JtA/P0&+Vi\4Ss;8zT-]7N;diTtGCw~QA/Ry?~ȍחB(Mtz[F!gGNhsȰWSKx+}<ڕbWS p<4$B7nNtq ^s`S,ynS hĵ%2}tqWB`#1m Wz\DŹq0};~'F.F]ˏ5V3-Z bU^޿h]z ==LY;޵/ZףDzPX0D_+D76cR<Þ-(- 6m )}dR[Zzo߸<q.\OQqErnN[揉N0Y㥅]YFQ\~mĉrPt?ꤘn/3i>L[^͜i#=x˩k[?s=“M~IB97O"ơ8qS{Z,KaڽO9,B-Ev7S>Egd_r*0˫'G3bEA#ܼ6jOe;TX|B\2Ҵgoq&ܽ; 9mzM'd×LC%7wcs*щ_%KRIM_=Ω_E"ZBZZ+`~!X 0}KOߞ|dՏ0%X/}Ga'J endstream endobj 410 0 obj << /Type /ObjStm /N 100 /First 929 /Length 4289 /Filter /FlateDecode >> stream x\is>BCE&ɴw!,dfgYOyRd ,!`@K $(̈́v6P0PК Pz(In!IR9&L) 5c{ciOI.3`j3cs|GJ0̬PBqŵ͜5tK1Ffpmt 찱YZ%8א[:IC_99t_boG"%H@Vrr\L`^)-8E9#qMHd6< yRҘ0eE a;;\9(D}Ų^Xcf(rK 8!Pʰ%PȰ`W caf V5٢0^LP 3{`;I90Eh#@,#H̬ ;n|}4Ly-Z`\[s aOX , bmc>T2 !9AxuhIMjS 3 | =Ay,k ?'2{8cO!I_,)%ER)^`c6M:×olXfo3v|$cOlI7$. th,>`'bzV\٧-6ـgKhc>.nFb:|CA'{ s,ITt:ߒB0)}fbN3}]Fz!ŁQ3`Qg$ Y^ΗP#;*T?/ٔd?|WW;/gb5^݌;,r|2#@/0t=t5ufUU6Y#]h|[#Ոk$Fh{[lYT?ҢR-*G}yfΡ N\|Y$o-Ӯ[П-_jAJ!EG巾Bpw[wXkaiܕT;T}%֐kH5Z@]A30Mp\nb[|zB<(.#0vΈ% +HRyM5Ks)V'-PR|ǻ8Tuv=) @2DW{ 5ܱh 'Y`l96 7<LL'ʘ94mCA@yciϾtCJ<-p1 |5ϥ1W,MwloaѼ޹đKylTW7U fv1y'ޓBQ aԸb)( T4JO p&0FH2,CTZ8A!Jֹ]-5M)zmMM$Dn*9G Ɔ4g\Z#R'pQ:cZu$GD>,òb17<=]C/ONz^gldv=Br{9wL#@6˥?-?yZW*1m}MrRd|^.3ɡi,d:Fs<|e9(g[EY̋E`O!u~~`G{^c#;a/+f ѸW&']hzFe1/9;|4~_,'Że#.6f|6eل#v.f *gŇhޱwǂ]Gr9/FbWo)+{6ab`lʦ`9+/lfqИP(*>*t`a5[X7[e('WlɖW`_glV 1 >7[1= BxRStp||ًI eDszuDv* kb\A~@/E"XOP_Ri<]o)/PvO~z3ԏ;' 8kW#܎ !^ kZ6Wly&WI- Dp[Ep&H&N }@W/ z[LJ?2wQ/NjڛM.z~4# O߈DQ6שvIߚ.IVjmjktA͌I%X 8c!KSwN_|M[;_ףJ(}P0^+u^۴Tw雓5uұ3d퉬UYTd]Cq$6X4wZӯ0y#Aq# JCnW?>OzW_5/6*};Rg='d= wêgEp`=p|ٖ $ + +=xJD5]mNdz XBw~sS,L qqg,ka]UMJ+j=C&k]A{Z;), #?yА p5 $EK#BɨߪVxaaXZfyrV\5`tizdkoi$q}񢢯m+3Mթ@&M7gȢ{IG ")Wi#SDiG!J*L*Yuܷq uo2o(ek]ޓrX2`G"jA_S ,}'R6Mx6'$Oױe&.\&D=&44zh}r6'6Iwwpt&<*еn 6mA&ܴi0L~L{QM" Ahyޙc2H{a<6nÎ͙-?4.O3"0:!vV?Ż endstream endobj 480 0 obj << /Author()/Title(GenomicRanges HOWTOs)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.16)/Keywords() /CreationDate (D:20171030190229-04'00') /ModDate (D:20171030190229-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian) kpathsea version 6.2.1) >> endobj 478 0 obj << /Type /ObjStm /N 2 /First 13 /Length 114 /Filter /FlateDecode >> stream x317W0P01T02䲱wI-.) ! Ή%9\@5f`5%9y`#_b. 6;7?%U?8 51$3?Of0& endstream endobj 481 0 obj << /Type /XRef /Index [0 482] /Size 482 /W [1 3 1] /Root 479 0 R /Info 480 0 R /ID [<6A3C7FF2C6897A1B6B2A801B95AF90E8> <6A3C7FF2C6897A1B6B2A801B95AF90E8>] /Length 1183 /Filter /FlateDecode >> stream xIlUwo((ti(oD':q;.lQC 1hQh0Ab4hbᐸ py.]Wy{Ϲ{ss&K8s/?g/H-Q&A^."e:[J),Rwe{o2ċf)!pooÛ,xKxg)K@)yI2P(7AY*xUo黍Ruxxg(1x# u S6&!fЂ77H Pxx퀏.QFoL=A=ιWHA] UJ `PoH pPoIuMj4RcAݐ=nJMӀ[*uSr:fHj.RAݑSŠJ-rPVRj5RkA}%R[A9 \Kb/HN4:}gNzgZe53_`ދڼ6CpM Jr&" ]s?Pifi pD){"( 8DļFi5m)U@hjDV>MQ3L԰$ m mQz:Q$*kQk&!#-: aGKkZCF?0`/{Z*΂Y0s~X`ZʊVU/]군 *Ԏ%Pu~ PLfj52[ ˬ|N Ai4HLΉ霘.ui>qUV_gRef/I%UaFJKܿ.Ueɜo-ٔwR|KJ3']<ؘ'okl̓u_m48K[?1KS endstream endobj startxref 232696 %%EOF GenomicRanges/inst/doc/GenomicRangesIntroduction.R0000644000175400017540000002542113175727613023331 0ustar00biocbuildbiocbuild### R code from vignette source 'GenomicRangesIntroduction.Rnw' ### Encoding: UTF-8 ################################################### ### code chunk number 1: style ################################################### BiocStyle::latex() ################################################### ### code chunk number 2: biocLite (eval = FALSE) ################################################### ## source("https://bioconductor.org/biocLite.R") ## biocLite("GenomicRanges") ################################################### ### code chunk number 3: initialize ################################################### library(GenomicRanges) ################################################### ### code chunk number 4: example-GRanges ################################################### gr <- GRanges( seqnames = Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges = IRanges(101:110, end = 111:120, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score = 1:10, GC = seq(1, 0, length=10)) gr options(warn=2) ################################################### ### code chunk number 5: GRanges-location-accessors ################################################### seqnames(gr) ranges(gr) strand(gr) ################################################### ### code chunk number 6: granges-accessor ################################################### granges(gr) ################################################### ### code chunk number 7: metadataAccess ################################################### mcols(gr) mcols(gr)$score ################################################### ### code chunk number 8: setSeqLengths ################################################### seqlengths(gr) <- c(249250621, 243199373, 198022430) ################################################### ### code chunk number 9: setSeqLengths2 ################################################### seqlengths(gr) ################################################### ### code chunk number 10: names ################################################### names(gr) length(gr) ################################################### ### code chunk number 11: splitAppendGRanges ################################################### sp <- split(gr, rep(1:2, each=5)) sp ################################################### ### code chunk number 12: combine ################################################### c(sp[[1]], sp[[2]]) ################################################### ### code chunk number 13: subset1 ################################################### gr[2:3] ################################################### ### code chunk number 14: subset2 ################################################### gr[2:3, "GC"] ################################################### ### code chunk number 15: assign1 ################################################### singles <- split(gr, names(gr)) grMod <- gr grMod[2] <- singles[[1]] head(grMod, n=3) ################################################### ### code chunk number 16: assign2 ################################################### grMod[2,1] <- singles[[3]][,1] head(grMod, n=3) ################################################### ### code chunk number 17: other ################################################### rep(singles[[2]], times = 3) rev(gr) head(gr,n=2) tail(gr,n=2) window(gr, start=2,end=4) gr[IRanges(start=c(2,7), end=c(3,9))] ################################################### ### code chunk number 18: IRangesStuff ################################################### g <- gr[1:3] g <- append(g, singles[[10]]) start(g) end(g) width(g) range(g) ################################################### ### code chunk number 19: flank ################################################### flank(g, 10) ################################################### ### code chunk number 20: flank2 ################################################### flank(g, 10, start=FALSE) ################################################### ### code chunk number 21: shiftAndResize ################################################### shift(g, 5) resize(g, 30) ################################################### ### code chunk number 22: reduce ################################################### reduce(g) ################################################### ### code chunk number 23: gaps ################################################### gaps(g) ################################################### ### code chunk number 24: disjoin ################################################### disjoin(g) ################################################### ### code chunk number 25: coverage ################################################### coverage(g) ################################################### ### code chunk number 26: intervals1 ################################################### g2 <- head(gr, n=2) union(g, g2) intersect(g, g2) setdiff(g, g2) ################################################### ### code chunk number 27: intervals2 ################################################### g3 <- g[1:2] ranges(g3[1]) <- IRanges(start=105, end=112) punion(g2, g3) pintersect(g2, g3) psetdiff(g2, g3) ################################################### ### code chunk number 28: manPage (eval = FALSE) ################################################### ## ?GRanges ################################################### ### code chunk number 29: granges-methods (eval = FALSE) ################################################### ## methods(class="GRanges") ################################################### ### code chunk number 30: example-GRangesList ################################################### gr1 <- GRanges( seqnames = "chr2", ranges = IRanges(103, 106), strand = "+", score = 5L, GC = 0.45) gr2 <- GRanges( seqnames = c("chr1", "chr1"), ranges = IRanges(c(107, 113), width = 3), strand = c("+", "-"), score = 3:4, GC = c(0.3, 0.5)) grl <- GRangesList("txA" = gr1, "txB" = gr2) grl ################################################### ### code chunk number 31: basicGRLAccessors ################################################### seqnames(grl) ranges(grl) strand(grl) ################################################### ### code chunk number 32: exceptions ################################################### length(grl) names(grl) seqlengths(grl) ################################################### ### code chunk number 33: elementNROWS ################################################### elementNROWS(grl) ################################################### ### code chunk number 34: isEmpty ################################################### isEmpty(grl) ################################################### ### code chunk number 35: mcolsGRL ################################################### mcols(grl) <- c("Transcript A","Transcript B") mcols(grl) ################################################### ### code chunk number 36: mcolsGRL-unlist ################################################### mcols(unlist(grl)) ################################################### ### code chunk number 37: unlistGRL ################################################### ul <- unlist(grl) ul ################################################### ### code chunk number 38: pc-grl ################################################### grl1 <- GRangesList( gr1 = GRanges("chr2", IRanges(3, 6)), gr2 = GRanges("chr1", IRanges(c(7,13), width = 3))) grl2 <- GRangesList( gr1 = GRanges("chr2", IRanges(9, 12)), gr2 = GRanges("chr1", IRanges(c(25,38), width = 3))) pc(grl1, grl2) grl3 <- c(grl1, grl2) regroup(grl3, names(grl3)) ################################################### ### code chunk number 39: intOpsGRL ################################################### start(grl) end(grl) width(grl) ################################################### ### code chunk number 40: List-ops ################################################### sum(width(grl)) # sum of widths of each grl element ################################################### ### code chunk number 41: coverageGRL ################################################### shift(grl, 20) coverage(grl) ################################################### ### code chunk number 42: subsetGRL (eval = FALSE) ################################################### ## grl[1] ## grl[[1]] ## grl["txA"] ## grl$txB ################################################### ### code chunk number 43: subsetGRL2 ################################################### grl[1, "score"] grl["txB", "GC"] ################################################### ### code chunk number 44: otherSubsetGRL ################################################### rep(grl[[1]], times = 3) rev(grl) head(grl, n=1) tail(grl, n=1) window(grl, start=1, end=1) grl[IRanges(start=2, end=2)] ################################################### ### code chunk number 45: lapply ################################################### lapply(grl, length) sapply(grl, length) ################################################### ### code chunk number 46: mapply ################################################### grl2 <- shift(grl, 10) names(grl2) <- c("shiftTxA", "shiftTxB") mapply(c, grl, grl2) Map(c, grl, grl2) ################################################### ### code chunk number 47: endoapply ################################################### endoapply(grl, rev) mendoapply(c, grl, grl2) ################################################### ### code chunk number 48: ReduceGRL ################################################### Reduce(c, grl) ################################################### ### code chunk number 49: unlist-relist ################################################### gr <- unlist(grl) gr$log_score <- log(gr$score) grl <- relist(gr, grl) grl ################################################### ### code chunk number 50: manPage2 (eval = FALSE) ################################################### ## ?GRangesList ## methods(class="GRangesList") # _partial_ list ################################################### ### code chunk number 51: findOverlaps ################################################### mtch <- findOverlaps(gr, grl) as.matrix(mtch) ################################################### ### code chunk number 52: countOL ################################################### countOverlaps(gr, grl) ################################################### ### code chunk number 53: subsetByOverlaps ################################################### subsetByOverlaps(gr,grl) ################################################### ### code chunk number 54: select-first ################################################### findOverlaps(gr, grl, select="first") findOverlaps(grl, gr, select="first") ################################################### ### code chunk number 55: SessionInfo ################################################### sessionInfo() GenomicRanges/inst/doc/GenomicRangesIntroduction.Rnw0000644000175400017540000005041713175713746023703 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{1. An Introduction to the GenomicRanges Package} %\VignetteKeywords{sequence, sequencing} %\VignettePackage{GenomicRanges} \documentclass{article} <>= BiocStyle::latex() @ \newcommand{\GenomicRanges}{\Biocpkg{GenomicRanges}} \title{An Introduction to the GenomicRanges Package} \author{Marc Carlson, Patrick Aboyoun, Herv\'{e} Pag\`{e}s, and Martin Morgan} \date{\today; updated 16 November, 2016} \begin{document} \maketitle \tableofcontents %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} The \Biocpkg{GenomicRanges} package serves as the foundation for representing genomic locations within the \software{Bioconductor} project. In the \software{Bioconductor} package hierarchy, it builds upon the \Biocpkg{IRanges} (infrastructure) package and provides support for the \Biocpkg{BSgenome} (infrastructure), \Biocpkg{Rsamtools} (I/O), \Biocpkg{ShortRead} (I/O \& QA), \Biocpkg{rtracklayer} (I/O), \Biocpkg{GenomicFeatures} (infrastructure), \Biocpkg{GenomicAlignments} (sequence reads), \Biocpkg{VariantAnnotation} (called variants), and many other \software{Bioconductor} packages. This package lays a foundation for genomic analysis by introducing three classes (\Rclass{GRanges}, \Rclass{GPos}, and \Rclass{GRangesList}), which are used to represent genomic ranges, genomic positions, and groups of genomic ranges. This vignette focuses on the \Rclass{GRanges} and \Rclass{GRangesList} classes and their associated methods. The \Biocpkg{GenomicRanges} package is available at \href{https://bioconductor.org}{https://bioconductor.org} and can be installed via \Rfunction{biocLite}: %% <>= source("https://bioconductor.org/biocLite.R") biocLite("GenomicRanges") @ %% A package only needs to be installed once. Load the package into an \R{} session with %% <>= library(GenomicRanges) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRanges}: Genomic Ranges} The \Rclass{GRanges} class represents a collection of genomic ranges that each have a single start and end location on the genome. It can be used to store the location of genomic features such as contiguous binding sites, transcripts, and exons. These objects can be created by using the \Rfunction{GRanges} constructor function. For example, <>= gr <- GRanges( seqnames = Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges = IRanges(101:110, end = 111:120, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score = 1:10, GC = seq(1, 0, length=10)) gr options(warn=2) @ %% creates a \Rclass{GRanges} object with 10 genomic ranges. The output of the \Rclass{GRanges} \Rcode{show} method separates the information into a left and right hand region that are separated by \Rcode{|} symbols. The genomic coordinates (seqnames, ranges, and strand) are located on the left-hand side and the metadata columns (annotation) are located on the right. For this example, the metadata is comprised of \Rcode{score} and \Rcode{GC} information, but almost anything can be stored in the metadata portion of a \Rclass{GRanges} object. The components of the genomic coordinates within a \Rclass{GRanges} object can be extracted using the \Rcode{seqnames}, \Rcode{ranges}, and \Rcode{strand} accessor functions. %% <>= seqnames(gr) ranges(gr) strand(gr) @ The genomic ranges can be extracted without corresponding metadata with \Rcode{granges} %% <>= granges(gr) @ %% Annotations for these coordinates can be extracted as a \Rclass{DataFrame} object using the \Rcode{mcols} accessor. %% <>= mcols(gr) mcols(gr)$score @ Information about the lengths of the various sequences that the ranges are aligned to can also be stored in the \Rclass{GRanges} object. So if this is data from \textit{Homo sapiens}, we can set the values as: %% <>= seqlengths(gr) <- c(249250621, 243199373, 198022430) @ %% And then retrieves as: <>= seqlengths(gr) @ %% Methods for accessing the \Rcode{length} and \Rcode{names} have also been defined. %% <>= names(gr) length(gr) @ \subsection{Splitting and combining \Rclass{GRanges} objects} \Rclass{GRanges} objects can be devided into groups using the \Rcode{split} method. This produces a \Rclass{GRangesList} object, a class that will be discussed in detail in the next section. %% <>= sp <- split(gr, rep(1:2, each=5)) sp @ %% Separate \Rclass{GRanges} instances can be concatenated by using the \Rcode{c} and \Rcode{append} methods. %% <>= c(sp[[1]], sp[[2]]) @ \subsection{Subsetting \Rclass{GRanges} objects} \Rclass{GRanges} objects act like vectors of ranges, with the expected vector-like subsetting operations available %% <>= gr[2:3] @ %% A second argument to the \Rcode{[} subset operator can be used to specify which metadata columns to extract from the \Rclass{GRanges} object. For example, %% <>= gr[2:3, "GC"] @ Elements can also be assigned to the \Rclass{GRanges} object. Here is an example where the second row of a \Rclass{GRanges} object is replaced with the first row of \Robject{gr}. %% <>= singles <- split(gr, names(gr)) grMod <- gr grMod[2] <- singles[[1]] head(grMod, n=3) @ %% Here is a second example where the metadata for score from the third element is replaced with the score from the second row etc. %% <>= grMod[2,1] <- singles[[3]][,1] head(grMod, n=3) @ There are methods to repeat, reverse, or select specific portions of \Rclass{GRanges} objects. %% <>= rep(singles[[2]], times = 3) rev(gr) head(gr,n=2) tail(gr,n=2) window(gr, start=2,end=4) gr[IRanges(start=c(2,7), end=c(3,9))] @ \subsection{Basic interval operations for \Rclass{GRanges} objects} Basic interval characteristics of \Rclass{GRanges} objects can be extracted using the \Rcode{start}, \Rcode{end}, \Rcode{width}, and \Rcode{range} methods. %% <>= g <- gr[1:3] g <- append(g, singles[[10]]) start(g) end(g) width(g) range(g) @ The \Rclass{GRanges} class also has many methods for manipulating the ranges. The methods can be classified as \emph{intra-range methods}, \emph{inter-range methods}, and \emph{between-range methods}. \emph{Intra-range methods} operate on each element of a \Rclass{GRanges} object independent of the other ranges in the object. For example, the \Rcode{flank} method can be used to recover regions flanking the set of ranges represented by the \Rclass{GRanges} object. So to get a \Rclass{GRanges} object containing the ranges that include the 10 bases upstream of the ranges: %% <>= flank(g, 10) @ %% And to include the downstream bases: %% <>= flank(g, 10, start=FALSE) @ %% Other examples of intra-range methods include \Rcode{resize} and \Rcode{shift}. The \Rcode{shift} method will move the ranges by a specific number of base pairs, and the \Rcode{resize} method will extend the ranges by a specified width. %% <>= shift(g, 5) resize(g, 30) @ %% The \Biocpkg{GenomicRanges} help page \Rcode{?"intra-range-methods"} summarizes these methods. \emph{Inter-range methods} involve comparisons between ranges in a single \Rclass{GRanges} object. For instance, the \Rcode{reduce} method will align the ranges and merge overlapping ranges to produce a simplified set. %% <>= reduce(g) @ %% Sometimes one is interested in the gaps or the qualities of the gaps between the ranges represented by your \Rclass{GRanges} object. The \Rcode{gaps} method provides this information: reduced version of your ranges: %% <>= gaps(g) @ %% The \Rcode{disjoin} method represents a \Rclass{GRanges} object as a collection of non-overlapping ranges: %% <>= disjoin(g) @ %% The \Rcode{coverage} method quantifies the degree of overlap for all the ranges in a \Rclass{GRanges} object. %% <>= coverage(g) @ %% See the \Biocpkg{GenomicRanges} help page \Rcode{?"inter-range-methods"} for additional help. \emph{Between-range methods} involve operations between two \Rclass{GRanges} objects; some of these are summarized in the next section. \subsection{Interval set operations for \Rclass{GRanges} objects} \emph{Between-range methods} calculate relationships between different \Rclass{GRanges} objects. Of central importance are \Rcode{findOverlaps} and related operations; these are discussed below. Additional operations treat \Rclass{GRanges} as mathematical sets of coordinates; \Rcode{union(g, g2)} is the union of the coordinates in \Rcode{g} and \Rcode{g2}. Here are examples for calculating the \Rcode{union}, the \Rcode{intersect} and the asymmetric difference (using \Rcode{setdiff}). %% <>= g2 <- head(gr, n=2) union(g, g2) intersect(g, g2) setdiff(g, g2) @ Related methods are available when the structure of the \Rclass{GRanges} objects are 'parallel' to one another, i.e., element 1 of object 1 is related to element 1 of object 2, and so on. These operations all begin with a \Rcode{p}, which is short for parallel. The methods then perform element-wise, e.g., the union of element 1 of object 1 with element 1 of object 2, etc. A requirement for these operations is that the number of elements in each \Rclass{GRanges} object is the same, and that both of the objects have the same seqnames and strand assignments throughout. %% <>= g3 <- g[1:2] ranges(g3[1]) <- IRanges(start=105, end=112) punion(g2, g3) pintersect(g2, g3) psetdiff(g2, g3) @ For more information on the \Rcode{GRanges} classes be sure to consult the manual page. %% <>= ?GRanges @ %% A relatively comprehensive list of available methods is discovered with %% <>= methods(class="GRanges") @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRangesList}: Groups of Genomic Ranges} Some important genomic features, such as spliced transcripts that are are comprised of exons, are inherently compound structures. Such a feature makes much more sense when expressed as a compound object such as a \Rclass{GRangesList}. Whenever genomic features consist of multiple ranges that are grouped by a parent feature, they can be represented as a \Rclass{GRangesList} object. Consider the simple example of the two transcript \Rfunction{GRangesList} below created using the \Rfunction{GRangesList} constructor. %% <>= gr1 <- GRanges( seqnames = "chr2", ranges = IRanges(103, 106), strand = "+", score = 5L, GC = 0.45) gr2 <- GRanges( seqnames = c("chr1", "chr1"), ranges = IRanges(c(107, 113), width = 3), strand = c("+", "-"), score = 3:4, GC = c(0.3, 0.5)) grl <- GRangesList("txA" = gr1, "txB" = gr2) grl @ The \Rcode{show} method for a \Rclass{GRangesList} object displays it as a named list of \Rclass{GRanges} objects, where the names of this list are considered to be the names of the grouping feature. In the example above, the groups of individual exon ranges are represented as separate \Rclass{GRanges} objects which are further organized into a list structure where each element name is a transcript name. Many other combinations of grouped and labeled \Rclass{GRanges} objects are possible of course, but this example is expected to be a common arrangement. \subsection{Basic \Rclass{GRangesList} accessors} Just as with \Rclass{GRanges} object, the components of the genomic coordinates within a \Rclass{GRangesList} object can be extracted using simple accessor methods. Not surprisingly, the \Rclass{GRangesList} objects have many of the same accessors as \Rclass{GRanges} objects. The difference is that many of these methods return a list since the input is now essentially a list of \Rclass{GRanges} objects. Here are a few examples: %% <>= seqnames(grl) ranges(grl) strand(grl) @ %% The \Rcode{length} and \Rcode{names} methods will return the length or names of the list and the \Rcode{seqlengths} method will return the set of sequence lengths. %% <>= length(grl) names(grl) seqlengths(grl) @ The \Rcode{elementNROWS} method returns a list of integers corresponding to the result of calling \Rcode{NROW} on each individual \Rclass{GRanges} object contained by the \Rclass{GRangesList}. This is a faster alternative to calling \Rcode{lapply} on the \Rclass{GRangesList}. %% <>= elementNROWS(grl) @ %% \Rcode{isEmpty} tests if a \Rclass{GRangesList} object contains anything. %% <>= isEmpty(grl) @ In the context of a \Rclass{GRangesList} object, the \Rcode{mcols} method performs a similar operation to what it does on a \Rclass{GRanges} object. However, this metadata now refers to information at the list level instead of the level of the individual \Rclass{GRanges} objects. %% <>= mcols(grl) <- c("Transcript A","Transcript B") mcols(grl) @ %% Element-level metadata can be retrieved by unlisting the \Robject{GRangesList}, and extracting the metadata %% <>= mcols(unlist(grl)) @ \subsection{Combining \Rclass{GRangesList} objects} \Rclass{GRangesList} objects can be unlisted to combine the separate \Rclass{GRanges} objects that they contain as an expanded \Rclass{GRanges}. <>= ul <- unlist(grl) ul @ Append lists using \Rcode{append} or \Rcode{c}. A \href{https://support.bioconductor.org/p/89339/}{support site user} had two \Rclass{GRangesList} objects with 'parallel' elements, and wanted to combined these element-wise into a single \Rclass{GRangesList}. One solution is to use \Rcode{pc()} -- parallel (element-wise) \Rcode{c()}. A more general solution is to concatenate the lists and then re-group by some factor, in this case the names of the elements. <>= grl1 <- GRangesList( gr1 = GRanges("chr2", IRanges(3, 6)), gr2 = GRanges("chr1", IRanges(c(7,13), width = 3))) grl2 <- GRangesList( gr1 = GRanges("chr2", IRanges(9, 12)), gr2 = GRanges("chr1", IRanges(c(25,38), width = 3))) pc(grl1, grl2) grl3 <- c(grl1, grl2) regroup(grl3, names(grl3)) @ \subsection{Basic interval operations for \Rclass{GRangesList} objects} For interval operations, many of the same methods exist for \Rclass{GRangesList} objects that exist for \Rclass{GRanges} objects. %% <>= start(grl) end(grl) width(grl) @ %% These operations return a data structure representing, e.g., \Rclass{IntegerList}, a list where all elements are integers; it can be convenient to use mathematical and other operations on \Rclass{*List} objects that work on each element, e.g., %% <>= sum(width(grl)) # sum of widths of each grl element @ %% Most of the intra-, inter- and between-range methods operate on \Rclass{GRangesList} objects, e.g., to shift all the \Rclass{GRanges} objects in a \Rclass{GRangesList} object, or calculate the coverage. Both of these operations are also carried out across each \Rclass{GRanges} list member. %% <>= shift(grl, 20) coverage(grl) @ \subsection{Subsetting \Rclass{GRangesList} objects} A \Rclass{GRangesList} object is behaves like a \Rcode{list}: \Rcode{[} returns a \Rclass{GRangesList} containing a subset of the original object; \Rcode{[[} or \Rcode{\$} returns the \Rclass{GRanges} object at that location in the list. %% <>= grl[1] grl[[1]] grl["txA"] grl$txB @ %% In addition, subsetting a \Rclass{GRangesList} also accepts a second parameter to specify which of the metadata columns you wish to select. %% <>= grl[1, "score"] grl["txB", "GC"] @ The \Rcode{head}, \Rcode{tail}, \Rcode{rep}, \Rcode{rev}, and \Rcode{window} methods all behave as you would expect them to for a list object. For example, the elements referred to by \Rcode{window} are now list elements instead of \Rclass{GRanges} elements. %% <>= rep(grl[[1]], times = 3) rev(grl) head(grl, n=1) tail(grl, n=1) window(grl, start=1, end=1) grl[IRanges(start=2, end=2)] @ \subsection{Looping over \Rclass{GRangesList} objects} For \Rclass{GRangesList} objects there is also a family of \Rcode{apply} methods. These include \Rcode{lapply}, \Rcode{sapply}, \Rcode{mapply}, \Rcode{endoapply}, \Rcode{mendoapply}, \Rcode{Map}, and \Rcode{Reduce}. The different looping methods defined for \Rclass{GRangesList} objects are useful for returning different kinds of results. The standard \Rcode{lapply} and \Rcode{sapply} behave according to convention, with the \Rcode{lapply} method returning a list and \Rcode{sapply} returning a more simplified output. %% <>= lapply(grl, length) sapply(grl, length) @ %% As with \Rclass{IRanges} objects, there is also a multivariate version of \Rcode{sapply}, called \Rcode{mapply}, defined for \Rclass{GRangesList} objects. And, if you don't want the results simplified, you can call the \Rcode{Map} method, which does the same things as \Rcode{mapply} but without simplifying the output. %% <>= grl2 <- shift(grl, 10) names(grl2) <- c("shiftTxA", "shiftTxB") mapply(c, grl, grl2) Map(c, grl, grl2) @ Sometimes you will want to get back a modified version of the \Rclass{GRangesList} that you originally passed in. An endomorphism is a transformation of an object to another instance of the same class . This is achieved using the \Rcode{endoapply} method, which will return the results as a \Rclass{GRangesList} object. %% <>= endoapply(grl, rev) mendoapply(c, grl, grl2) @ %% The \Rcode{Reduce} method will allow the \Rclass{GRanges} objects to be collapsed across the whole of the \Rclass{GRangesList} object. % Again, this seems like a sub-optimal example to me. <>= Reduce(c, grl) @ Explicit element-wise operations (\Rcode{lapply()} and friends) on \Rclass{GRangesList} objects with many elements can be slow. It is therefore beneficial to explore operations that work on \Rcode{*List} objects directly (e.g., many of the `group generic' operators, see \Rcode{?S4groupGeneric}, and the set and parallel set operators (e.g., \Rcode{union}, \Rcode{punion}). A useful and fast strategy is to \Rcode{unlist} the \Rclass{GRangesList} to a \Rclass{GRanges} object, operate on the \Rclass{GRanges} object, then \Rcode{relist} the result, e.g., %% <>= gr <- unlist(grl) gr$log_score <- log(gr$score) grl <- relist(gr, grl) grl @ %% See also \Rcode{?extractList}. For more information on the \Rcode{GRangesList} classes be sure to consult the manual page and available methods %% <>= ?GRangesList methods(class="GRangesList") # _partial_ list @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Interval overlaps involving \Rclass{GRanges} and \Rclass{GRangesList} objects} Interval overlapping is the process of comparing the ranges in two objects to determine if and when they overlap. As such, it is perhaps the most common operation performed on \Rclass{GRanges} and \Rclass{GRangesList} objects. To this end, the \Biocpkg{GenomicRanges} package provides a family of interval overlap functions. The most general of these functions is \Rfunction{findOverlaps}, which takes a query and a subject as inputs and returns a \Rclass{Hits} object containing the index pairings for the overlapping elements. <>= mtch <- findOverlaps(gr, grl) as.matrix(mtch) @ \noindent As suggested in the sections discussing the nature of the \Rclass{GRanges} and \Rclass{GRangesList} classes, the index in the above matrix of hits for a \Rclass{GRanges} object is a single range while for a \Rclass{GRangesList} object it is the set of ranges that define a "feature". Another function in the overlaps family is \Rfunction{countOverlaps}, which tabulates the number of overlaps for each element in the query. <>= countOverlaps(gr, grl) @ A third function in this family is \Rfunction{subsetByOverlaps}, which extracts the elements in the query that overlap at least one element in the subject. <>= subsetByOverlaps(gr,grl) @ Finally, you can use the \Rcode{select} argument to get the index of the first overlapping element in the subject for each element in the query. <>= findOverlaps(gr, grl, select="first") findOverlaps(grl, gr, select="first") @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Session Information} All of the output in this vignette was produced under the following conditions: \begin{small} <>= sessionInfo() @ \end{small} \end{document} GenomicRanges/inst/doc/GenomicRangesIntroduction.pdf0000644000175400017540000056203413175727612023706 0ustar00biocbuildbiocbuild%PDF-1.5 % 100 0 obj << /Length 2073 /Filter /FlateDecode >> stream x[KsFWVy?vOkU*$j/N9"&ҿߞA@En γ{4N Nޟa M0XhO%RI_pl7Wg1P"IFZDj<)%4(jBqZ7&/ciS҆(CV,&SS[& ̍)@Ez]w%#%up t$Sf:C6a$f(%oU+W<$͚*} Mί d]e me/[ C:s8pSa,Tz*&DB2Bx&1c踞?ΚґDR[Cʔa7T)D#nn=PBdhoXveo1 ƽ",[4u#-v5wi5|qJ4^[~pSү0F{w(RcXJ(ŽR irDH?=:tǧƭZyL8ۆ05V:} HDp<ŷv0SG#)O/oWy"eV•=b!mvּ @ ^ɒOY4[!ಹmc\h8=X c%ŭcMVoѼh|0w*l[(%8qe7.SV0 ~rgH(>4"Y b? = \1Hh_,DP D({y (#Uh*oKp1X򢈠't*2cP"/Hl(B[I@C鵥lfzA#F*;Ïi;A"o4GȧU|=M#dz̷E8d XēL8q[V $am B>qk#ey~-'DScYÐ' b3/?O(tH R!s tE",Gʶqp}]D7C!٢3OlfC5l6PI SNeHʥp:ଥe/}԰c_3Pצ@Lp$!5?~;sZ'dC=ȓ8CwЇ+ٷ\'51.Ka\ӂ껠ØK1x3*Kt2l =GHfON՝EiRs,q2lwZqpz| i8ҙ|)S2}۵v,s[ely?,u I\y7j^o. Z} "eMV/GL!FZo,p^TYT"B %#c]ҝt+&T&s/uPRon JWՄҝA ҋ=70;wLAMrupHХH ar].n5l6.!d7PS*4bj*̕G ϴKu;O[fs}9 1zRK%|Qe>>`BˮrwL-fNo2&&S XqTsyQMxH'̳lY@nH/ NE>N!=v Nnz'.%5G*{Wܛ"4'fuoW:C0Nҿs<3(\fYYVY]8[=I7зeQ.ȫ=#>?wOrߐt+gh'dѷA/,F$?/U\lj'[ xVy6^יּRēGD?ν'i@,512v$ d rw+l&5סK_p`?xsP <*u"3-Ȩ֡ iPd^]^Wc&;mH?D endstream endobj 113 0 obj << /Length 2523 /Filter /FlateDecode >> stream xZKs6W|OکZaP3LfHQh5ڒ\n4_ãMģg<{J(cY":2Y+TK&.ѻJ6~Sq>}־嶤nU67+㲣+R-?}3%zJ3q@ #6 !i.~2pcS(ӄi;"}g%gH$O4n|WKj_|s;Gc7WESN4Po@l7d$ETrwrsUHP,3^2*J!H. `VX¬_}8:OD[P7Q?sY8_)D)Kc䨭q]UW$3u"Vኊ J@Jo߰{ЙNNQ٠3- Y)KydL{bjI2a~8_%\]sh'3\ݸT5{ jzk:rQ#F~,`S06OMQqGUA5.8Tg%2,- " r%zѕ]N)$ ==]1]έmW]y-{2:Du<0n2^/#v:p\j2ɕz@~0׉dS$Lm{ S>x~A JDVL%2\ I Aøbw@l-eWֽkqN]E1ģLn{3('re^lm,SztBr{B=]pUqI<:p:rkĸg^驑Kh=)Xo{..] 9"HLk3ӏ˼?'LJMw@-iR#͡9t~U 1<~tp uϠ.E܃޻n) u'Ơt%57WfzNʭ[dpg,}H)TX<3 ~7`d% 򺻎w0+G6*5R®y9gTγZX恏P+*_'(_2᧠SoW~=/; m+<G9hCRR@|B!${3Jpq!]p z{{2_#]eq/ ) zIe3)o5XsM'uhZ8'u-QV( s^OR ;+M}9)D& PR* =nEx;7ʹ9'ؗ}0&}6þ.h2&sk[:Cmf&GU3elH,V/:GTܔ--l>˶*~9{qo;1n8{OW#GX H,DTDHTDDX l%jd`igX0O1<}H&5TCJ M Wm'(wleĢZb,;2Xoů ,x FyS _-CU_7>nqPBm Sy{޿ߌd( 8VWJXd$K]n?5.d= $⏳a(G~a9v!]Cksob},;%.zCRx\:-wrR2H ;^ߢ-24ʷͧW$ -{b\H4ѥ\~Ԡ_sAwN .̈́l}vj,7]h%\?kJq*  u=&JIh,~j-x}S:^',1xztcMs>@zJ>G>2PVdz+Ej].}ڍʄc1@nzg$G(l gݬ/+<+nt ,4ZQ<Ύw)k2s |e$)cK`)IxjW,D9>d 5& XKNMMw耍~J0f6rb+ j/HJS`]m> stream xXr6+p$TekR9$.U.9$ӑi%J5* xhx0A+D5Ha͗H eaF9/z:cY|vH,e_5kx{]Fͦ*oz5Q}mIRf)4/gDж+t/ n a3PILUXF0-'?wQ)ʰ+RE1E}Y}n֔Y:weJ}L;WY14|I7vvE.)[KlFg^wI8@ܲAD}֌i[ {evgQ/\mt_,snM q69fy>\~-D8X- U 1]UuWk=Y=;5Pyw"#2"xDa<^G'ytuREuPbd8HzHSy vgP:9saF;Led"`mb(ԑ2k;a;yrr*8p (0+byH W5[l{W))tl[}^TFGMێ^/IrthRǛ^G2&,5dRae;|EҸR++M!*";Bpa`.7o.c/u(Ȏ=R`. HV ,+n,VHݭ#H~~9`»E0`cZyqN0mIGdon3_gUc`lF0#g3 KU/ˁdǭː8˶لt.e}Z߹Javo'^U7}aU&e, <:튥}o%К%-Ck*@a'8Psx1g0k;^yt+ Q-7X$ŹR1 f%33H$~3.&p01p>s_p*)G G2,xc nbx}ټ9}J՚CMc;+V{Nq!?FUS⅝-X~fO/}3Gu;H xMP80FA IK| endstream endobj 123 0 obj << /Length 1673 /Filter /FlateDecode >> stream xYKs6Wp29Pm 0z&4N:L@T"rz%tIyba"яG_1(T&D`5MWEeTM3t3ӶZC݆֡ ĩiU]b޷>c8-Jb{vyasBd_v䮮8!qrDHՑmT DiI:̏F2Q(Z qdN7eRRJLS ZZ dtalM%x N#h?;S;ٹPcNU.wXEi_ wőr\¦SSJJJJJJJʰV|ю<EȂ yNoy;:Vw}IZ\g]%Y ׽Q/Mo ǩnaDo>MS>,vpb:ehLۣhˢbU64,GVIu㻬| GkS 37#LjkǵWM9 Pmͣ/uZDC+]M(BFLn4yݮ6͔N8 $8ZGKMCE1"Ennc,-_eBH2#! 'y8[=Ǚ/KAyN<3LP' JD_6USvs-fj^M}xIP(; & $ݒ8e6>2{8a[Upmd(FsF|HW:s(y¥1CtCaXGXNJdHlQFupCu '"ء~$ÁH +e7'v.nMD X@ƃnwq*7k &pMQdȸƹ? lIL+𵳟Oq2U$L$XD:u$?ܳ]H>|moS=Xh8۰X.]gֿL a XqREӷ7zxtb#vuU7Gz$H5,H1GG{f\xE+p \&2ur ]@k7a_fvW3 WE?d+R0"Yz'dWې#-Ez!k;޵Oȅ0L 0 %F#ج6~KOmHTu_T~| E6A+0{S6#Ǟ7L#_9Cf'9:yAC)[ޟvMSN:a;:QQ ܬ*상K$z&PN|1Ls?t~ĕ'[1㳥9 To6uL5 ӝf2]]9ᕡ 8^\)O}26a-SaJ7Lid)χzS")|;D(B>=%7"4PkUZsM&֨*ѧᬊ&fjFqOMDD>4)Ly!!xJ5et>eif endstream endobj 127 0 obj << /Length 1432 /Filter /FlateDecode >> stream xYMoFW9QhZ7U$&T!%Q֖jpFFW_o/94,RX##9LD7h*#nlCNrIlz벹/2l\eE뤘GY { И%N2zg~~|0k#Z(]|0g"Lj/f?:K>r⌌4P0A!>b-#MyŬ@ 0tn";?[IMQ4;4GQf1rg.[%CnuR08top) ? х5qtW ,N"}"l\coYZߴ5s=K Wd! 0PhShl)@n%Ā;0@QM;|x,h1+GcuTKV8?9N ђiE`VYjDjeV/py LE%?{LC[O(f/AwQ&/fӿjKklE4뽑dI3n, /8՘"Y~﹪[hViuZ5zDw.2-.lƫ]Eͳ5*xeYf<}Rt';=f[g[gzV{EvoS~#lr}iB{ D a: B%- HhyOęG!i}o[yӷq-0};2]Caʂx/k Kk8 RDyk ,C,~@(3:}}6Uּ >VPHg:({5Ts) 3j^zYRoKgN Y?Y';!'0jgW$v"BN'BgS3}VdI&4$Ps#$]uN?Q7 endstream endobj 131 0 obj << /Length 1257 /Filter /FlateDecode >> stream xXKoFWHv_\NH():Jb*I9wAi7q-L<.f?.f@!% HJ$"JXXrDoʶSV뛬+?Vi׹eUeZnns43Lů3%HqBDpྥǞz`]\(0 bf9QI@Rq:x_váH2b"aK,z ]xu}S I@v6M-mj+e?\,х2n1V]Y8Eڱ/iq뷻~.itVk0Hcx՜v3Vrp*,A`O ;]Qu4:ۼݹ-NnŌM~3i+5N A"V F('#uZ.jt %!":n9ޡ׿ \Iq0h$pt ts3eZbl@aIZI:K=IWGR8іKZ=pxӵ tdGndhq S]GcߎmNԍjS +31ǂ7'D2t6ܴuO/d4% /~rT9bS=kP oܽ[T[]l̉ ˛By$e1ԋjh, &^Q&&eS@I:)Qف(퉲(~7& Q2ܑy^&otufUѹkoZg&[&_ZӠ9TybW1]S< g!#KY9ml^؎40:e^#&ŷcjsdP> 04)v m42ʾҎ3C¿v lZgAٟgL^B*=` T2\jhhM۳Fl {_^/MYI7g˒ڔͰ69hD>xjKHL:a|e(R1QyjC͋q_z~F$=E;̒OB|{= :.χCA@`O zdo>:");$ϽT=UQ7b7B,= ;t)px~t1EACv^z11 `E endstream endobj 135 0 obj << /Length 784 /Filter /FlateDecode >> stream xX]o0}ϯ#ق6mQUy@VBԗi쫖"_sA"h6z7RX4@%!ESLyνا2NS6y(y|5lD*jakC{m=c_p=f/ A\ A-Dkj":h!>QƵ1Էm(IbYt ܦElTm.UVT~[lq:2S˝jLbNU%_ Y5)kU^\qm훼^Y˱]I/N(^v]lz@aGE6ɚͼ.o fmVYgWf(>Wwmc.yQYZuZIߧLsJ VX(z볉5t:]=bU߆s9!Ds$i ZߠVSM^$kQUIZ$wn_> stream xYIs6WHM-;A{u|S|)Hb"*IeFfLu0@o2ˣggLD)J%")ESD .,~QN4Q벭'|EGʷ+:纬6E~ɔX7n q LG{Ե#JM$N[.M02"1.GS "E) _fMd q~Pgk7\maB jA?uR0 7I/buNm3Iz;\ tR q>.82Wلr-Zrt n[yV:䰣Sk}]S23&l hK8>ua{WGpG$4AHJQ92#NlHGݣ\F[lWݘ  86ۻ*e P(Af+!h`2{r~df `2D-ϑP3ȱgc1oWH)c,? ;JϘT ѫME=ق6]U| _A X $!iQAL{>>)H"2V<'S9zFNؕy@Bx^su3|udL ٢kË{Y`yg LBdDc[': INnւ'EOnmjGȈv#XO. ͳ6sOym& x%6F@ 4*Sf yz)O_;߻g;g$"@Ԣl L7x:Mf'N;qډ Ƙ8 w5n݋Ool ,Eu2X,2.jVεXگN[u ' Zu>M.Y2^Yc/ܝ5I\2?I?ޢd{p%1TL ry&SN3\ݦOru}3nRfA;*RgSwdZx)0}+SǨgH\nfώiG54.a7Upuvш9ŧW^#$@nBXvjjj4,_ZotƒxTAYO ڢk{v]GW6\1PiVӆ0LBsX3^aۘY)l,??IC m$"L}bKCcTa b$x!}{7ve<G&u^}uxX)>jf{Ǫh]9m_oR,6C]LB5ȷ7eslO)Lh/9R56+4E'd 4p*3: ws}HmƉxң%Cpzp!lo{͡D,l,OwRj{齼 M^Րd4> 8qj/x|_1*>-w]g3ŀf#thscB~^ɴkN3&7z 1;vXgb;a[0|WDrPGI'i8-X ?GT&8_ Bm a)z7/O/_7[d/E`p 1%jd_o endstream endobj 145 0 obj << /Length 1698 /Filter /FlateDecode >> stream xZKs6Wpz!#I4MQSTHN;]DҴؒ/q]|888;;&2#i8Eb\?瓈*rBqXL7I~.H,͋U|[sp'V6O`8ྭ>ɧjq@Z%eHR$Ω@Ĩ@ 4CveZLQ< ,z<$L"ixC^ $ #e NtHg)0ֈ&d%ZB ߵ~1ɘ UQZT|ܩ` 1w]5J'5rc Sϊ7N 4OlۏXYqW4fY:u s>G hA Cݑ,}x^s2ebV3H8*!USJE5˓f lt0o';!$Ә6= F+ͧnNR#z(,z0̑=INcU*_AE0;$ӗ %bF9TmRH2p"!Z!nN"f4MyT=<ז$N]Ѻ͖˦@G1A|[̘tNgSpzj݈23|v˥[hj&q:Q8+Wn4yoq0!PA :d,zɍ\&rYN.LpZ"c܅.n:uٴ^`j@M%GR}"jyy8̄dH<#6[}>`+ AXgAgMgiRmV/܌|^`xױ*4@h1gonWrȭWI9hxʁe kyv8P2KmBl9{c-Xm*sX%FY8>kdZK;LmÏ}\\s%KPFpNIa?+ F `TWVֹUpGfJ8O[˵3x *(Y(Z $0Cv>,0cG0&FL${H$@FjlעhoXОC2v ̱f}\p_Fi %i %8jeo{#pIsTJyߦbZٖ[]mV@']&$ 9ڻ" X{@de"ۯ+'w*m=UdRUWvђzmOk~;4w_og~-vF21bv vW`1aۋAmC=QaOT6joc5 ˷0Ŷ@c/ޘX3F"petl*ӳhIk} i}q/y}\v?&-zߔvm1mMjyȍՠ e;)sF(9pƺ:oC{ceT#}#:SUYs{^6dNˋ1xIڤ{jWX}] jD7qv+V`8 endstream endobj 150 0 obj << /Length 1396 /Filter /FlateDecode >> stream xYKs6WՖof2igO:9'FdiS3Y '4 H.%V^Wn(rġOiPq'1F r{!ā~Z2ͤUz$͑A,cSgH j| ~Lա $LsQMe82'~<'J04j46YL>J4n9en7\K( 17O c$B {=:,-.^H{U^Y-B w`sp<@oH~9ǹp`|4VϣG`"7yA$\'Љ;'KT%3sNtLظLQ]Jb i e{zB,y`h-׬^mUP{S>)ņ7m;JK3|qh0 8Ck TKxC1ή.#) )*`Oc뒝$`ҎI6ʄ0`4eBӾgcAQGO0X1lEvZV>844 Jfo F1Q:nm5r.C6vV.JOa}HRYNP"sT щІ= bЩO`Na(#g^nC1qhb20M0ć&}f; (&TV0VUQ}UUTs &ű؍mUWY*KW{-# k7ЧpНZ 㢸|3C4c 3A> stream xZKFdtƪP/{8LI]' !2nU˲--Tq>꾋[yͷ7|'$wtXxLp.;M9(,z&Z쳶h[:7e-iyy&?h3Lo E|ǣ9 C o4і#4 ( Ņ085 (jHDR1h`p X' [盝m:1Olzӫ:>޼ &'4(,gL`%P-o~LЋXA R( YLUQ:I<'@xR,xJcڼ>KddOXBc q4??1#S 1F>b&=S27L70j%.I2@trM@(6ogILyURErSh:1?ͲدmHjgp2fhI 7G@mr\ 덨⁄z<8jg:%;x1 3\”!B4ݽWgmWTێ%]#7ۇ")RǶ oʾ(MCeGkd;lt ]~##+@Џ1'a-'5 >d vT;L#ƖUdH9?cC2G1ljLT["ВtE>B$jRm°'5K7~7ukqզEk e^e{LC{qՖ |*6+EG[EGcE.;Cu"mZfZm2Pc1|0CH;N#\1G/yEpK?=/ R0&K(yjŧjQ_Ou a$cᝯ͘ BPs8:c+V!{]0&> 08eAu, Rkur]dPf ʇ ="<%J_ ,i$nڳ=e-~`Ds8) fE3r6C~de 8ɪ8"f_i+*bOI6>.Ri4:m6GM錹:O8_؁ucqK *f1`ܰ*_da@nԃMO7MSVm۲yi-y8itk.VnںsNFnrҵW?Zg3g]dĮ -5x87!g*;1=er.;pt"8}nǦ ̢\V/G=E'e]mY,r+:pϝ wn8+MB'䚧y'j8y_ /?/ϡ8ᗢ8s>Gi|$]wIۮQ Fġ-`~FtE&!l>k 5~BӉ~3g\Nr}L7|}܉kRUJ2~*)< 3wo-a7 mNmnִ=]yx0]|i2t;W2o^_$ʇh?UX3MX7A33WZ6*=Q8WCc:L|!c(2'fN@> U줠scCXmkmѹ;B`cFVJ[ݢ=jaJtImfoD}QuAcR>|pҼ*[fi'|A=4[h\}g$]Lka_oHGiW%uXf*ұ2wN_OK1߳z4vuҫ6λnNSNZaM~uZW˨s xi˙х\? 1r]HP>\dIG+dhڴn_mrI|~tBtOs&ְ1o|mC endstream endobj 158 0 obj << /Length 1715 /Filter /FlateDecode >> stream xYKoFW>Qp{i"1CC$6T]R"e9{ggo),\N~<}eDb*^Dq-X(E91˶2Vmm+_\ZUZ.3JBӸߧi;|L0"%R2m꾫~|PK)uIl=~dDp&"6b}O9:Q" C'<PS Vi:Sm HdO\גC`5؆3 -w+@&k]&oW\Q&U+֦MiVVuKq"&7G=?p8r鑧ٽ1"5ZBDq@fT \f`MӄߏK82bod91"ae]m70<]@hMHp{sq7v溇 -o?w0ktZ$;fSZ#>]W*9-] e!7A~;y ?A>SUw) ;~Np~xwB@*ŲØ*R<Ȱlo@п5` endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 798 /Length 2005 /Filter /FlateDecode >> stream xZnH}cT{ ;]J[[2Բ19;}.n,!EäɓE#?Olnq đaܒpgRC b LQr"kg!FAcPh'PQ \c)@^S*(f!ЌKNYI<T{6`C1r@"kE+&E~cӍ@8$6HIxщX'p3Yó&21 tVe ^ O2=lM. \(5n$6 P1 ʽypb.b+ZF@"m6_'y0a@ FbPpF^MH1!8*:q7Jp@ob=w #Ob#;㋃b7B#bT% X܀UCxW\00& d 2pXCPf$C.2b55Q xe?98⌊熊n^MYS+~eӳf7񴬯ٔ'F}6x9nzu͗Y-O |/pG:tإKGjkjn9ִkuKNJ0rħټmswѿtn6?PJtZMTb!~3l,kvKXC_inEIs_EP Du aʢXK3/0 8)\N8u2`R|z[QkyUM 0\8]d޿{u9+?\DŤC3~nz~[U=J u&y/ٴ:x1+$:$lu`s"?\pHD 8A$ "iIv2Hf=\Hem Ñr1yD_|R ںӬcR5e|xr6r,iE }w6ӳ Sc4՟ݏl<73^Gi)eԈ7=MBd٦mO~Tx,:Dv~.Jc/A+1Ϋw9L~v 0)>2Ҭ%j#eGn?.M\0BC/]˫t}m&i`Lf Q(Wr Qa4V^.핺I_msu Nr𦕔@-ferC*֊G7/:q{]2.eVf #n0LPCFD9yhtvHt'mMZ x!Jf& g endstream endobj 162 0 obj << /Length 1896 /Filter /FlateDecode >> stream x]6~E+NB)T U{:!&KKrpڮdlό:ɳUd,3 ,MehɤP2֋H&i޷ f}Ǎ%Ͷ,zmG_y0o_p/gcn:]?=b8)ZLdI  O_?Wʱu$,DgiL&7^O2\X۽1GHӶHqPkgu]M+= }Z<zq-#+xi *d$n 3?mMki9S~ÑiYӼ*v u;h;Y3\ _ʻH\n^Xz=E>c >o*2l]yk2^MoĐ)K Z&<]/審u*  TN>>,(VHޙ4:ޮm뱏~k۲xGJ1 //? np9Zaќg,NT,EqzDƄSIg7疫!\rsd,"FSn3JD9z<AW-Ui XZQ72U/Md1ƙco|f2Yש`(&bhnj(?FK'u6+0eZ 4WHkR$i=R.ѳp,dSJW|܄Ѓa8^qR%!1M%wU92ү;?PB%}U u㦔"[H5gBe"bgNb9tF]%, 8boJNS4uW.p= ؓv L瘌XM+E L3&4}UXK ; )G+MpqF8|W.on4h:dZ#%tjү+;#{;cS!TiFAmQEX#AOvJ z/[->РJ4.g-w[n7ZXeOy^uw!. y 8S:;SƕA* rHlNQ%qU"I+/+KEnZJCďPBg̅;uxSnћ&q>cGB2tYq Ɏ%ezLSgq6.GpL1݉!M9}"qgyW޶XT8=OMSzf⼀FkcIAbNw=Ə(>'v=`M]+ ,ja՚ -ˎ-k*wu V'a~K5PySq\Mgk}Ӈ{H';W&J ,NGΠcn<޹H.`a, qwm :>J@ce^UhUNk³͗5_nG<+{5t-ߟR$j'4\˯vn*3J@v>tsVѳS?yYAFj謲#︓IWGxξWWpW^27+VNW le|r/> 2>y:aܘ tUjR!  endstream endobj 168 0 obj << /Length 1385 /Filter /FlateDecode >> stream xYo6_!{W[0 ֠CmY=t}Pm&ȉ$I3'` Oyx#M&'7\&)ISy")1%Z0€'g6÷E]ΧI=Ƿ<6'_&Yq1*u08 d#?>h# ~,ئ(mx &-w 7[3'F.cq&L$Zi7Elǩ$5EMΝj}W35-r5 Ӧ)=8डˣϋDMQ`Z[]>Ԙ"6,7JFI&FA\yz`[GIPSQ1*MLDl, ܍BIAdןݹ0I'QJvE3|wi< -[(a(/֬ ,[UxBJ$aO۱$PV^ۼ܅\ihZ=u,݈Vc|Ӱt&S.W~&8a=+T f0ÅMY -=Xa&N==(yӯ"b)u/lViE G3"g_pZ@9ƂY=xU-"g62\ptEDpA>K_^({'f5]>toM]BK)u/CQEKFʯXE3^oܺ+փ趻'}|5)1YD'WB endstream endobj 173 0 obj << /Length 1741 /Filter /FlateDecode >> stream xYKs6Wpr'ةCPV"U.H=4 . \ߜd"Q(#h 9Ef܆ghL ?u98,& [kpbI> u1&O2?yqH,+1q>'2% G>{ob:R<Q9DѱEO&_ȗeN]mkrOI>q~jb8}KkjOyR&i@B'yM;{~KL⋅^w¼I:s/ >4c0׹ 8SExNGV:X#bnA$ ,|mIE[Mk R7ew>qȀ49  @NR?I3.!I $qtd atסR)KKYViQP$ >ztj%PK0z, #!iP@]brX;y<qLoh` %T#exڄI/Y{ǻ|zs&Qe8_6E:d^yhe:ԩ(j aT2;Z?vH62uNa1[#Bդ:.}jIm%Mu1QXI& lr}t endstream endobj 177 0 obj << /Length 1240 /Filter /FlateDecode >> stream xXnF}WA[#E?Jf+-Pm:G3gΒ*ًWLD9%2e]D'Tek5 q}+][;ԛ(*I u& Ei=Y$_g8 z!hrhD@#sB#VITԀKhrNvZLqKli#U-n.Y|gv@ pKFBUm7HbﭯeSo {XSz܃kѦk0y\*L{b̲\WnwӥwU?Yli+Z(@gߋ4lh@γul^6`*/C땱xY:/tʢLa^^P`c8/0)\{9AHt $!ң@\Г! BcJLU&wvu.ix\٬ ?Lٳ~a)il?@&pyn!< O}P1g#$GeHڬ1LI/}fC/b c9M3vo6+nrcZfH9A(*8vun-R}gkbzCB1K`,* l2,-4g-#s0EpI8oc~#&{t遞t Z#2x1JS)|@}JI#鈇_FaCh(D+{&hJX  , N9S9G*O)@*_ &wڔ}ږM۝iTY7GzLDKM;^OO\.vHO#e?7TjʞVMŗ+PILW#S?|9~C7-5A_M[ endstream endobj 181 0 obj << /Length 1535 /Filter /FlateDecode >> stream xXKs6WpDx2wO:L H:$e'3@YԣUh.>]FFWBE4eM”EޕW{N~U<*Ղ5hEy@l[jThNK~.>阦[7آFJ>}̖SS E`WSb?_q=*_ƶ!U^s?IWaV~ٸӳS{MJ+I2)`M5B(﷯Q"%Z(ad*,`livE9 lG 0.]^S?^OM4bC>KC2* %e&b)>Vm0&2`SB3p)HIRoDS>oߩvz4$//P.lBqeEsLǞyҿaTu˄ A8s\g_K'}N٠:Yr/V0|BFJe{bp艭mfyf]B\v{7);[e@L5AdA!'r P { ʃ/ XܮlagW_D-0`Ds{om]u؈m.0r&,\_j`}Wz}Bs%þ֏5E[OGKIgzapW Ht*`˔/\$`Ea]!"Cq*o6tcw΀O / aB@K(dJ燞$\CY(4.qۂ ^'.B1031^0^>tiwixcb=C xAڧme`ȩ3}<#0ck;|: g򤶍#-pzKW=7\@WWA+w}!L w`M iF;6 % qi'Kk> stream xZKoFWAmpI)rhS#ZYl$%;$R㧜O~89Kprt&29&#i8Exoј*~,zDqZMy[Tb9rdjQ䟳l4&8M}pNlqx5pBd2,䪡w,m\hcI8p DJaHr6qW-7Q2QL!5iԟ糚:l1!0Wl홭ǟ4򬝅:2T.^kP/v2L.=KwnacIen~[2jɶ[osǶɎ%`0E`JbC Y&#ƥgXP xp8 7{-P6+JgQ/oΝݥNuV&(њ^=Q WR}SsnE5kϚPa$6F `{D aGuGe @Em#z6>8K5[WN~t#4B캊r8ψ5pjlr([ї]z!;%z9*n Z0A  Kʰdc)>"8ȍ 4moHya.kHC_B!y1lfcQ+^M0Ɛ'g'ԍKB_V':۩t8=P:%йea2E{(!>y1-l̽WQV+1zѴ#=Xz~}wG 6(DGra")AɊjEPMPN O!" %OD'oÞ{3{%[.HK0ܸ,0oiR]\SW12*PN\ $P9 y{O#qw![OB^nE`t.¨!_B@^Sܓ Q^B`\@^ Falq>$f [\&v 5r:Jv ?Q0`(0 "= ܒ@Z(SHVTwtb/JOH V(6HB8 h Y2voX/}U endstream endobj 189 0 obj << /Length 750 /Filter /FlateDecode >> stream xWMs0WvI;2):$Dnmr#Ge}o5"hw篙@ N$h0F8(S`h0BPwC6e-2k o J<;I TﺌiV#|Nv/wOo:GDp$ڴ]trt;`%V&,AټS9Ip,Bt! )0H&I?膒РTg r635j=wٯΤkcBbگkʌ_fkzԙ2(5el1^;1qCtV\ˀ_GLـUVJ<_.Qc&b*jdlݹ[ڨ*sU>d jti>| z] 6; q `.d0'ZKk:Jg"b" ],~R Mt̔i剽0"mv75s((QY?޶,=1_w;͉G9Es08j\`۴8n̮\ 2@p6.op0V 'Дe/]!$8IUv+υ6meK[F{tۊ?އݺ7ni睾#r4i>)߻+Oh2iiϔ]+Bb," $}~\U endstream endobj 194 0 obj << /Length 2146 /Filter /FlateDecode >> stream x[oF_!J~np zw>0b+.I9 ?fKYeDZe*Ƀ%gvf;;3; =y}q&8b1QX'Fr™\'y1qcrMem.}xxrgj:c4uT$͐8#JdLOmu5oSɟ' R$[`0ɕ%ڸI'=uZzbS֝ c*_4IwuϋЮ|q,35 fe|u?KC% _ i1<4kߤIï\mE-1 vg,52VڙAT[:++`,-T$BHUgV'299"UlWgf<%?f}~ʖUQqD5kƓl9)lb7%R(Թ o bQ~8tn|uj[T[ng"QWGQnhvЈ_"nju+UnҪG%b#nPUw8`~"/ꅑ mmv [9lo .>lctayv8Z1!'n"u@eDwMP <)#_:SrTr3*UN>;>Z»Wæ{|7 $J~ښ7S?݌7`ΧG_ig&F7ݺ]&IWuz,upEhcж?tFPK`)&Xˍ95O]g9 +,@ؠ/#/$^幆} &Km2tfH.`Td&^SR9p@ A*tJ|Trz\@ F ch,F>BC|ţX؈!G}M`e1cj N*[ Ɣ=2-bh m^g`Z`0!8%!/м< #Q  7_/9\28afp͹&q`/kazEڨc`1ʀ?M9<`x'2tfEx1It?GHHq g/k%Gy+Wh%Rw))xe7=|$ L CGgI!ôeb GMULYζ͢*#J~~\( >bכU)EPv 0#o4.`Q)ThbcX)a _w7DRQSG!zt1ӋjDBjIA9)t7\ ls[;M4i(+eVv {v[,0AyYwPNS}sǍb){Jr8'Ŝ&/d Ŕ+)4$0w&ج`ҿzT-#KZ>F^CE}*nd |}BIr\oKڃ1a-k̞:`z``xZY`Ƨ 7+%jBPݹS*Pxo3o? veaTY=smwֻ Q;mmD[-G! 9 1HF&x_-ؓf C~„83Br<#Wvt7N(lT}>+xi"*71 z1e_[<}I = $x0<-Ugp^拦3y8!Ri 7mxdCZTׯ>A} oxJx}F*vcO 88M6 endstream endobj 198 0 obj << /Length 1166 /Filter /FlateDecode >> stream xXo6aY~dh5h[[ڃ*ӖVKr%9Y{)ŊKҠ 6f// 61:k"%fGUtS*zVͫ@mfolYyzdOu JR>#og$HD͵D3 ג30&J &15*ZbTTh=RZ]đFn8 Do?;_QgΰΦ1azM[_ꃃI &MSZmEٜt1<ʤp` &ji~P\1> `DW^[N[i/l: Y?[JbǏ)C7IA5LS>`Stw^ \dF mXUۯ4_6hjrf7R-džb$U(('Ѩh4 4H'Q1pO*ob ;UvuPLbxh!b~Ivo$iP{Sow 84 --""_wm-BwZDEXF8CJ۽ƇlnFPR۪cwZj1y|b e8%`vf_KXvSsWlWyf5j:bzft-KUb~(CO)P$x9|ɃeD K"Cv#۟n=riHOPG$]z0+ģ.wYD322kKP'_J6'$Į<\$ō6,a[ m\6&u]"@ G ƋƝ%HrŢz4K15X(Q> stream xZYs~@zVp*'2U ڝEc`I*?>3pL3_ N~:?PQJRut%I##9LD"~Q-$k:vux9U]Y],m4VH]0xs '%3Gǁc(-(vP*Ϊ5x-{`ĶҴ~TQ {Ȗ#hDgnz}RɘOk~ v|~i"4D:URH01QcɿyFf#CRE9YIPR$0V?Ќ BK),ac?-_cd. Ck7bioWwݝ~y1@I ! D G Qh1En×_Hia/-#XG7*rZ "Z2oD ӣgmk`0 g1,עoJ UΉH %e~_Nl"]0PJ Lj%dEIN}0-CPo &ۉAA#(*kl{(PB582@9r)s(i "M+RSo|CZTdi}V[@$E3ZܚqI x; D> WyO+B2(m.Vuq(#D־ ostk Ag2a:>;g{scJ-Ǫw:!%S=]XP T_y \8S|^Aa0:W?]NhwcTjpOQè~/g%Y0LTa-4¤K!|-ApXb tO # _nc)a0`@HJSA)fPJzS)ny%W X~I:yfl@S=嘙 6,@yZz4uޮMnXڿU=(8)*<Zt}Z Jp&Y( P+)@[h?,bƞ;"{[axW;OQt@BʬI!(k)؆e?N*[s'u)S߾9AT:"L?#gMg\|bxcWGjx$rhgXHe~5Z?LIvʐҋ%([i*GVe%K!~6g_.N8$F)?^dO\]\6tP `F7)9VjPP;Tƒr\0-v,{s@a;xC5́Qʭ,Qzlx# KC֊S%jL"Kۀ[|:?+.zgR+e~̫@ ^0iyگ^[8fWPs.d$ƙ{[EGj68o_`N-lF(˺ m Ha>[sQO0{m8{[=藌 MV~H5>Jܨ9T# K4}@HDʰw N~@=%q4O=Pߗ)Eĩuw&y9L8&&]ǪMq WwP.w pV_NJHwrqۄ* ,]U.{vv&Fcn,l˫k' LMOF$?n CE:v]W.8NEouN,za3"QEi_j 4Hz䒂 j7n7/~ZRf]}H_?YZFʷ'H/W9Ϯ:qʖɿ!W黜\ ; endstream endobj 211 0 obj << /Length 2277 /Filter /FlateDecode >> stream xZo8B'W1ST] w ˴[YJ$7|H'N$5of {ʽło2x$^"zwD?/jDBin)xÙ*eb1 pORMd nyeItGkx w9J_5?vڈa֕˳NۺδLmEҴ#Wg9_\p:8J0j$9*vfP}I1B KD!n1*iԵ_^@9A^1;$eG;k #O{4U6sui^HWm !t0vRNĺ#om Wij:%* T _6'lS>Ju*ʜD܊XfNLRV\A8M[WIŴiU -\_Ʋ;ʓmNY~6P0X<aYU,#u:9z&G"(=)‚x,H06ȫ7?3e4Ƅ'CbXr)%GlxN1CLMB:ˈNG0XC,C?!@ `} ^ΘF:|LD vi*^~B>ČULGGJ47=rTEE.࿶Il<1L{y,BQ$\/0Xfт32 DHLH֧{Eڮ,~c  7ՃixDP~Pa8;mEY.8VxefzO;z\v8! :Ato% ,#j`M65 AR  9~o ^pPg%A!J2:bZ%R$uTI)7msaiNdh-%'f U.󺢹97WIݭw^9r/Q(J7r/&νG1Hp8>3/v{X2۬OF-U̒& ]$D\ "˯E4mV\#_^n?;qyp 0v͂w5oXύ!zqX1 Lۮ96+P}[KUe/NoS 0] X2W]C&zn;3˜(ƄQf oL=`wb{vQ.~5]*vDJ!$nW[0znF 6cx,-+K3LH;Wl;E}l) };neO&WŢ_.8v>+I4SL{}S>F #mFKAN c1LXO4ad> [HPӦB[~4"!E!@\`fwѺL`=.TrxG=g.Vk7aUp)r)q_*εj#ۢ[tֵ'i)teB s0cʴ;{5v+p%Q^Eѹ!1UϹ` xMeXG&%_CVfX>~UcH/>\)!_ ʀxm}w+#K` 34һ5;}L^]hX9& nc|xqcI67njVcbo 옯bM*x73Umyno-TZ|zSD~Ъp7aAPlWnX`߈2Naؾ at!51tI@ǖȧ2skGjI7۔?8t=fe:m|v8E"3<4OjTۈ]}::緑tO?딗i7GC~=_vp*&&;eS?_ϓt]cQD؅?Oޝ L6UjraS1CvykM'ݚv:E<:;܅#^b?tvd=]6Dp endstream endobj 215 0 obj << /Length 1814 /Filter /FlateDecode >> stream xڥYo6~_G6[; ȊG,y6w2IYXv$xd<=;_r|/D[{>FRR/Q¼һrpA|8W~>hNuT\8dx£ {{earBWKf?tq#nG^>.s#  ٧ t.ߧU8DH1I G*AD"$dhVÁ7j\886cr$#N wn(TF7Јpn)|vm;O&|G!"!( Y wnvy~0z:M7 za. <@Lv}5WWՇR RU*zKN|ۨQtYN*WI-|P,8ciCv*qT@e婌rJdʚmo& (7ro.}w>_Uܥ<9\J TBԔ"t*\88mHP۷۬m>u΃}-zV1c7vj0Y{XФ1., do4 3΁MoVXyC$jf![șH(vJ H`8v9C8/&k8w > v]:/G`k~ HwOdSA $ t/Oи|PIRZ%$*-5|hnp\ b7HЦC42uH#TP+eMד}f+U:7k >9?oV^jU>p >m?A M%qnIJ:},8֍I 0DMFQŬP2˒,N 0`8/nF36O@yyC/7:1w;ڙ-o>&jqRʖkG}VS16;ZRGͲkXIztZ@ĀS_Cc5wZby:UzMz{{Nܯh}3q`sžt!^*:I^4tBIN#Uk]c_*k!p 2msHT7$ xXvpjqe?Ȓ,?7TV#:&VАav-KPyWJS!r<,7 j|^`:gq喪 8=ԪhT3 2(@дv3U J.iPޭ":yߡ w暓DL"d=eCV ǣ|] ([oĒuOm-^xJ/v!r uPw"be|PD* G [pG(o#@IiϢy'Z/uTд21XW0WWrF؞1b$G"%̾_ M}~͢"Y ϷT4]so endstream endobj 220 0 obj << /Length 1187 /Filter /FlateDecode >> stream xڥXMoFWHc\;H(Ŋe+7ϐ(bIҒ}|3ͬpIpnqZ #LVwHk(N%,Y&_72J׵k>weV]> ]Q72f_d8y.Bc" 'D&vkZ-Y'$8g ̓|9PiV4in(Y2QA{ CD KijLbmWH^yT"1b aòJuHƖa7]%#C AZFfK am+4U7&C2c[n H`Sp$b87c"l. a5HDX g:}銙@gTwQ6u9[UE;<l1ia>N~n4q!'\SI$q̵0̏QV%CM/6qBRbgO&f)}:<'ӶݛnLk#%4 @$uմFdSF m-#!z+Lz-r}i )Rʐr 6*mnA*Fhk Sֵ`ISCC!cQN7n74d\N3O"}Uմ(bF)u@A)4jHzOL4$cUB7jPD W5~\h?ST1-F/#L3t)8]Wznc3_DRYʼa(Θun.H/J!IJ*Q"6EfI5Ǯ#T2xQ>nTL󦨋]8Z+OMuX}zilʹEd4#LꪽS03Q.ţ'r}7~ E}͵p1,8}FudS"%MFFBCή+Vr$><A޹q.FSRQ>BLiMb|]W[Nqp"g(6L's{Ͷs{Ty(Uηא]=ݾ},N7Q)$ AvW`#>LŶ)@"50Hҹ椕wd0岆Ne >]yGMR~&4C>>|vOQώ <~ ap 3p V7?eqZ|L 7 endstream endobj 233 0 obj << /Length1 2065 /Length2 7345 /Length3 0 /Length 8485 /Filter /FlateDecode >> stream xڍWe\ )]PXC.eYrمeF.I锖FA$CzνgfyycaWbCd0$;0@ i`N*p]n899899q_ & BBE[%(- E8;P1\(''\..  0XpY`pv g@N(&Pp`‘6`ace0Y~R6H'$j=@HBQNMόP*w݅" Xf868ڸA,m`k ۬ 60:w\Ӷ NN~]z+W#A,S9*I**>?W Y 䎋! <6(An  D-88#pM#~P /n (}@'({@[ "Pؕn]Un]A(v[b׸E(v[b׺E-BiѹE(-E"*Emj?u#@`; Dy}qA|`8-bo+ ú@Tp(\(ۤȿHA?]kiGnی(K gJm%Y;XC`Dl6@R? jv@Tsn}FoVB.T-* uUZ Uí5U^{2P~;%^TBYo!N]IX1)\ަC&q|$N6nPqH&>THk-j Tۍt}:?%JDQ3ՌA:vw9}#n u/wwZ<ܨǏڱB܂;#P{Kz[ڠ' Ɲ&CSftH^n=Rxڎ1pݣ/oó+9ΓfQ96Q>}5_ 7KD*uOM27 i ^k]}#FĩvZ#ҟ"l>=Vl^QN8q%SЇ(i;zU|[g{,H01>=1l@?be04N8юjz+>+)0foWg~Yɝ IP5ԺWRz״(d#evaJGb]HVi{\+s}|M(L>d"o\K"5/nM1XJ/ tˌ)T,uRһ&< =IqILQb+8b,֞ 5hΊؼW}GJɝ b)OFa;5ڍ7AVgOpnK ^pnq?S3.0x2ͱl蠡?[ђ8F Sn  M;+Z3xSbWg24lt'H1LSrrW+HF{2.ƥaWSwPpOhe/u=H!jfۇR܅%*.-[܆ S' thkQ߸L6^ISu90Q*y􌷕T ȸNow1xݩͲͷD8= Ê+[rejiR?񎘒-ϬiT7FYƟωL9Tmywې5B˹;L$$L>سU!g>[D`"eMI]Ozi]S/#3Rz/̨UbOz{lAY@kW'XF6nIf/Z`L?cWBi@<]n GMp˳'o@WwYW~Y>[i Y/=-">OҜfcDX$1H{sf@={@͏jw~sœ wMgS6-s ]=Z!R)/}yC `),~`:59>9ACIA,4ýn%ϭ,C&+GEKJ~;Aۇӭ c4^,rFzH 8ybﱨ[f>DjE2LF:6"SϦ5f*n1tz՜kHoDoVp1z\D]ۄ%4f:Ĝ#BQ3p4.5l ~}rߟX Zq:= ( =sc%<i9AQff+%khkZ(~l,9k wbdר)~w, %s9NDoiJo_*=[O>˾O;@H]o$vHW9\91Q:%pgđ15yW'>;\~L5@/Tj^9`T.pǍceaK"]ngf ]$٥bf)wUWbaC!Lj"tRHdDpsOty3ﰙ-VlXq&.Qg?Tjv:18$T;l͍w;'$jk^LED%)85g_4z[^Y5{DMleKugde5,XT y#[݉cVxO(5G9;r耩"钯.BJ)z UƓ+Ӟ"GNf6[{Rd}lsղ-Cr#j*FBѕJZ$?L,"Y7R6d2Z_6rF WтL ^ƉԘgkpM1&C'^-j)qhs~` gq9B9֙:p#EyN:qyq 4wf=IJ*Cر-cy;O܎G<ɻh٣?.\5XQɎ@ٶYc?WpA5M~~4wr\sj2z<|Aq1 RmU ء>MX'꺗  &V0N5`Ѐ锿9yqIf)$v7&HD>XioIjH@5V[Ƹ徵iaWE5TVi-~o3";K"$K^F՘h6ϲeJP9Ҿ';1mc~~tcCry+Pݣd&w`[۔&NNh_&P\LRmsm)`>keyg$4 >Mx/v\$(}2QAUK^8RJ^\?}[IԒgkf"Y]k4+u=6CUK>R'xAT ;\FA3\ߝfnW~5#.\Hp}]dMkS[oʂba,Ÿi7?*2's^tsէ<-bF0\B=>29h|m&8ܾہy`2wpLeq@Gdd()=p)Xp B(+rNqBGρ3hcv#S;6_}g95="GHLbSwɝ>&͜Z&J%(=ՂmKِ=*cvno_r?}wB_HO lF!|t<2,UGTOe%bǬCƾ֞pC9 5`&ﵦX9f/9eMԼv ºL'ފQ-Я=ͼ($ԝo|QX&/5)ˠK'-'DUkj\'îf=)BU㥌%%"_B}-?lh~p$CXUmD_gytt(&FYʰVUIjpzfOo -%+r qMUIxdBqܸ}#1E/!)?'_[|-[;>""ٚ8gj$׺,[7$| i,*o!b}+-{Uг-ݾӛ/8˟]s*6|%`GZqlT}kJD罼'6E?״' W̯ȄtIf0vwٸz#S}҉ZHKӛ ~*WsF2߷=5P8C=wDT!>tצ3yjBɎvl@zw] ,+їJ}]hMA s4l) W)c*Ͼ̄9ߘK ꆳZ Ge1, {%jc3Bo-"N,ɷD/¯WY(E'˓?j N@\w^$Z}6`P4gݰgsՄTrWg%ʉ_r5d2^+Q /i[%c**#ZMXH|Ϛ>yjStOBFR}Weha|/Hb wzCET/!386y د'~ kQa? ӈpv3ȅHk2`N?Eq` CM[:2T=)0c1`=3hn2ҺjZS/ڮRݩwipWѢ)EmS?|*'Ӥ/ i|ANGu???gĎa$JpOGm/_"g߫~pYLGedi{AddHq_x?-t/Q+AdɒÏ1Efu"t}z{ H@IreO_IŗIF/6G,헤߬*Ga#M̦Ӊɺ EEá>o1v Ҭ'G4Q UjK㕊, }l1(O{{}r60"&`di)_}T"@EoQ> ߋm^P7(( a\!~KϲCن=W7˭q|Z?8!g{Ei1/_ T?\"ѿBb>]7eXKfj~-GDɏ#R`ʏ(;2r1&7Xڠs%#s|Ok#};#$ t ?~唕3r;qg\*k7ou|b4}JScQY$ O4D{|% C%ޭO&d=k|Qu4'B,&Kje^#EyA;/e{o,Md @x?Ѫ74hU`LҊYGk# % IDldI񊐨Gȶc&s[s梚c7df54c 8X‹ @@q͎tAԡYo|u7aj>mϠ}"f %N梙GYSb WŰ B^X4ĤA-߭ N~f"Htl .t5`i  U_W'DpIN[s?|Mـ|kj%q ]q]+@<Q|?ZYQ^~QRM{#Nj滖e5*sKjK$$j5"xN;w+ k֠7ӾUNyU?ֲK NV`ubbd($`-89[e B'<]>"_>R Dz/OMPx}gqwζf;wSEjي½&+ʗ~ +݄ݞ{REj!}uMh~dt^݆_:%/嫀x dE$۸]5r!QF0я%-F޿I[<4!s}K2U"yF"Ikx{GM>"Ut~TV1n;OP8, k?<%3Spb~d[T'0Js~$E٥MV]egccoˍZq,7+Զ'LWn::I?Kd.H.%D' R9lPZg.;=]\[*iz5ۤ?0Un_/`YIq{񾦶~qq=,cxkbsy WA n0V/9+ ۧ߆wxiA^Չ-fꌂ/, T β՗\(s"a8z^Z [wѦS pvRxC udiheaVo{g_iLEׄ\ xZ%} N[P3oiǥft/z7_dYE!ii h@HKWye-+h6Ir:[?9885:*.aY(R[t\QݑvKKF, aJuG8:*a`]|U1c4]hLؠ]-VTa8E6f~if_&GRXqg㹯o\_Zw?_iB`L .@V#'?{Ow c;c4Y㰂ge1%> _{%"ؽp^ 3u7v; ᪐U#~êdȅpCcSLo ?ό`EӱmiWp0'h^$&y"!*Yݡϒ> U/ 7O`;f%/?VVF2tٳ Rj%9* zz>uħ)_^0~"\Uȃ-+dK[ Jfn{/DI Y endstream endobj 235 0 obj << /Length1 1856 /Length2 7526 /Length3 0 /Length 8571 /Filter /FlateDecode >> stream xmuu\6-t#,"K7Jt҂t(% HI7Hww!Ļ>s嚙{gt4*l/͡ (dHMM NJP-bĤtP $аr(@\F89@?@ l,Lu!P_vsg6Bl Yg[[e;7goҀ߬fś؁m׉؂^B,mAߌN2`7 ff9UǬ 19ڂ! 2<Ӱ@@NN>@`K+Qhgb_@rZX5* 1!.^>;&\}8x`8%7 ; ;üPG8^6 8$?C 8 ~N8d7Cs*> xN$P~@ .T@<ϩ ‘b9lBeM f =ع?8O? j  j='Kb5q+|&fpNWn5!~ ;rAA8S \} \|plŃ.JsA4|f99?5MAl࿭y<py7r&\p~xοo+IA<@bKO iÿ?[ |J&at8߈c_U*!ux|/%fΎYo`WraMC̈́?%HһFފpspqݶ ? iG^|vۣ-gYnqyJd!@ֽU%O>zPi7|7}S2()Dz9e1cGGR vYr@Ftrt#W;}5mGn>,]d-/%{1p@+9ڥ? ]C'6#,i~#7L~55Og|+nL&os Y⢍&ڒJeR}! ]a!S)> os>̝t3fA] (ƀ}Ig5 gǕ-+-'2'$UF_";>-]؟X9ZrjJo;ATҗQehmjJƦߑ K੅*%$[_M!7FOU4FCua =0Z;X+ؕEɀu-2Le"ȾS|FMitA/\ !M;"r :htoZR o-yӟݺh.y+jfqA"k|dm<|+2T/աu*;^UY{9a1})/{#W\Olcs  /B y3fB>j̩ ^j~U*"FRX~"cʙ5 Џw"uXPѯ #$~ :f碱LV G܊(O9T喇 CqOfm1&sQJ 'F(~}`tUD6tךac5y]mGbyX1aHmnܧ/ܴύrҋʎLs]h dGvdG;|P}팒$gJפG\3/#uPeir >lr +NA=OwTk})72y)hU c{*g+yDlŀ>JETJmM-KTY=iYshAĖ !Q)EҨHOS޾S͸ĥ*y7 ^#kٶmTHDm<@ #5[=ieZZU2 Zt{%6y|\6̮-(0Le,j%%|Fbt^pL"+QV ET[6ơkUt jK<0R;,(O 2_(ED8DПOH ApZc_ ,#;tsG(_UXNƁ_D>o츒l0ˠYEL@@pmRK_$C>&/HXIr)=LN Ln3s{|^u?d]Tio#1U4'/ٲQ;- %@ 89^2GBFICߐ4͝>>l2ᔑ zy}K&vUQ[zeT6l3gZ׃]]0]`/LEZvu)QwС s] S n\l 2"/__y,"f#wxzcC8hSt\>czҭRJoɌb9zlA LO?ަE SI{Hcm~e@: y4'3pz1׹?ȁA"@D)(UyIu׉4G, >TO|v:}| $W%B/ӽ>谝hࣤ&]G_ =={js'R\*cSA<2\H1UQaB hoHcKK]ۻGSLmkhKQ,beF[QEqkov6YJ=4Ḧ́.fFOS7K sݚ-y Ki\pAį*Q/d # m>rYMc~T f[oK+9/XLzf0It½;g-hq6ۧ1T=) @M[m;ڙQ'`\X^#;3þbL/{e'McRfq&&Ӵt@+>0}P(ndg"d-_U+ [/&I K`bFXW5xlLٱOt+'dHOoyjӇfQrZ?#hBGZųC\)=1Cˍ ̘ [aj #L'ؓ* m{A%\Dxl._uJ!5 F73`pnN}=e{@V<_ڒm#fϢv@9KIcY&jnrj , v.% o'drefHfkMdz{c\{/-3uRqlb~Oz]zi| o}-(ӏ~ϝxf#~w'͹C0Q$S&J.nEG+sD6܄M>T%h}= AAfJ$RTA6ZPgAn ۘyAXtmĐŗLek2E9 La|LD 3@v-ݮ` ;ꄒ/?5z]TXcmpSӄ_gIST "Z%`vH_Ƹ1oX]s 7_e(qxo9)UR@rhCmߠef,#^oESCAV)2bӕ$:Hs9o۩1~6u zR$ BHayhZ٘!co{.+#%4Y;Ѻ.?}\G'BT\9/G3 suN{WqYBY?( lj*?_ٽ܊?&[K *VoS ](fB[9kTӂv J+'s׋WC^ :]}l"O풕M5 o@QpY6pm$N.זX--~kƨi*}|Gz4Y^ڐu64tv= 3աM G {LJ!o 0IЎ-^2zoƏ;x$zʇnj/??;1?dFgY+P[ =!dUcQm{2[#E{Q4rw=*K'ꍻOd 0 BK8Y?9qQ]N:(TP6%;-[j6F|v(~Vj#Y8_mZ?M}XHX ~GσQG z{~)q9JYnt0n\c1ͳ$z8 ,G*~ K H-<'3P9H+,'J3/̖%F' \"T">bL\ް >Yd."b^8Z?!!WT|x[1p:ݧD:\,o1#Oй;[v-K`+>vw˻ 2z7NoKDž;ޭgJ#'-P=^F͜^,Qrs>ʡ}Dv*#fFc3Ҽ;g$Ȓ7Փ|+Ov'`ƌVOw0;TEG5(|[5B8Nn&(=Lym~\KIڗL`}Ip$Sc,^JXQ삓;xA=qyVq{z1)=Gڟ;O=m\s\jTz8"|ٷxp!8T]!枇w{> `q2@[b3ʉ&s[w&i L ^ʦu>bzu>ܛA5y~kVHP.^Qc>/ZnO }'Xd1$Y֧_{  iXό ٹp[{{[A&u@?4`JOv UѢ 4wnSn̓;yLH\F=A3qOvuXi") B2S(.ӔN" җo(Pll/y.4`2b,A^|(iC*m+יسGN=΍jr&jB/B/o>b5&|co}J٥}K)r!^IDnD@prMj<&"!$_5ҧ#k32S% ᰛl9An̬!vA} y eOޑ-8V 7sa(~_4纊q]_ȓ9ܱ$A*^otHRNm| yepLZ4ngv3fEC̀]槡R B;ʳ>yn§@e A/DJt(}#Nx=FLJn7SR_z%PX[q >el#(ݺ8yOUg"$]x^Yjʇ<.INYP@n#kiR 9 JڭẂ89_D}K뒙1 W1G-fՎ5g) ÏI)(li\5?r0f}cu¤i}{fzą8ŧ: C2Hކ[Y)$=YIBb4aaIݤҬ%x5|!+Z%JlYݍc 4PkO"/|U ]T! H8d<ͲyΓ2b1'z"qB|'e˔ƃr σT̡ 0i.:~60*kPJ/"gLqRi'laҏG+nXl)溝3"MK61SFԇwU3\~e]n\k趋^&l+ˌ?ŗ7|B|9x(x;__?^|;أ},=Λo}e8Rj\R h#yaG,~%y1F6sţ3XP dK\2f?$ƽ㎨H])5A^w]+|e(Mx孞̀!]E8 U 7žŋPGITE'X,V~ )xSM'~-0%bh!H7o6+{o m _E$w ٍ˯!fv 1rHuBtfڬ[eD"m`diz +dؕ':F)gٜ퀺hqeU]MzI<췼"tNƮYXtq崍I1jXoeX%juP0>q#8$+|mŔA\<ͷ7MM\loJ+fP2VILzh??8)2hus`g?qa0osw%%3K;w<s".!}Ra=kI?LGh~lB M# %dDy;NFf *Jo'ŗLvPߐ{Kw?V&?y=~R -zniGѕ[{bE5]}~a@꣐Ld~ÀҠz@# Nɒu)V l,νꊡAglD_[,+coR cm y&\mKP_}E,vd|U^u=Ԏ.s׿:T0\gbY~?z ._)>4L@֚(\20d]R;ߣ\KY]o{lDO,ueZgƫ}fn ncNV RUO[U ?+@ZpuHRP({Osc8Nc$A|v.PlOAuzÛ u $ vKx1M'X|Rk I" jwP=Cs*]{R[~ }@,r#GX_Q-F igWF؍cњYLݿ%O *a ]y:OZio Z21D8͋`%5V鏄Y縡]Dseib@r8lʞZrSC-j5?~EulKE dvkbjexiY9_^V6ŖTix݄BH9)ŊY5h{/%eEWZn_ H %&L6BV G7iнզp,cywx? 6%j\O:,C#)x*=@%9fht` 0yn!*,R.2Syz$N<\Fj yYƞd endstream endobj 237 0 obj << /Length1 2596 /Length2 21476 /Length3 0 /Length 22922 /Filter /FlateDecode >> stream xڴxeX\[-!@ h݂5;wUι9}cژ">P DHQԳgdU;XX?}L@@.; g-8?ĀV@;\l k{=X 26R]m\LM@c0[ g`ndon г2HdBS@hga6(ʊ" 19/t66v @X@VIT)+*oLU ˈ( (a]7M_3I jdgmᢧwrr3vYX=Zj! ~ mjv[i n% ,;1p#@cZmD/_/_zV r% Nr!/ݿi5nzN=1=+{?6702LJ(*JϊV+:3/ lFNxIE --Y#n)O k;VNVn[ndjeh6V@ Ȍ h :k[~mpY=LD7{=G dp?"#;^taA+5o18g(:Sjhme0!Z A%[vz.a_߹RZYY^hd`wcK/`el/d[c2V@{{n@p+ap WRU_;󗙈1 gg^&VV#x m v8<Fv - v 7bgЋALz?@/% 0f8O߈@/ 0S F`o ӳ/% X07b -3OTFpk @V ¿ h4omgXP);Y WM2f)eG8kȗ;,ZZK3U'?L򉟆z2("#*t>2%Ĕ9,ө#!֎pW%ٰͫN vQ?.NA^0"ftsF$l:w ~-bbEts|: 8Pc|`>D|WɊo{F%)=|{7B*;ڗԫb!U_ڑ -o":ԛ-TQGDnpCj*,}d3y#$P Sw)ՔPx]eW2gGr<;rTwgMUz0K> G|݄$A(vBHIvCNAp$`0;ށsϒg@*ܼQ^ AY§{ ԔIo@֧ev-JqIy,݂|9H'vA4a7=IF3Wɟ@/G}cYMc%T K*Ei"''Lfc]`p͞SI1VW:]Dr嚜zi\1&TV%2"2_HA2ĿW`F@ +VY 򑇆c;PGqD&*.l8}MVǿeRk/{u CwԀ&\dL}͙R9sxW14Δ+bC2!~g?N%x -κis`DNήME5i֊tP*rWmNedqsG<SrAx%#3bI h'Q8-ZGTpm9aɑ2H:Ƶ9ä8&+k;!pV5k4AsMqkdFxVh]P~|=bS:-Ī5wYq#pcYV;PpT usH~i >Q&-)dգQز!"YCq/Q!G57([Q;<^[<dЉ 7V}mɥ4s$T/MtLeQgaF޽Ӣ%ɅnVETRm7HCNuG_D N@am ]~Z2^H~5+beܡY }1̧]%zBFMP2qߝzpm~-#EvMZ%-M*@"ohR&b!eY79NyRGŚ52:j2uSњj0cPl8Dd2!1hUS 5<OsI43؞( "NyNS_$*X*uudqQ}4ΜϺ e4 )'F(195lcS*WLd[팖la!_JDRaX7ᾷ^A~r-a?a^89xEsEiQֿ0J6TW 84tzZe܆HQ#wPjK;eˮ pG`-dm(h b%KLƧm5:>x?f2Qv 3U\fk%a+!YkHy@L =-m;8o* 9e5"I͓CEvI2̃*"?Hc!0S@0#/ l?ϧ@Kw+׻0+">0=k0-n\r$J8'`,D|r""k+qlVCw}>)$c X,(;M!B:KaǙ-~z6ɗ;wN}$ɶ8ǞOV8O;ĥ#ɔ^ɩJzR ; fbQͣTO֠ОgHhs׈$DLmΆ({.1 1ah9_jI"anр5ɟHJd[LO~?]֒ۢ`unIp@Fm_ o޶>y-eL>7 {CBxCDtJ,+Ȓ!PP6}d6[A)ܻ.=\AG_n#;\.lw(9HtoA ᅢT9*0Mxyhۭx+۷O=ɘq&9Z q95f~Gؤ@Wrquӫ^z8sz.P9?Y(iV&j;I?>>+mZ*DH ScsNY9aLē&EB?|LJxgԛ?@,FD$ w$8"^pSHTS3 ޹HyXf8]wMh/|Z}':7#LN ӕ`cTM('HPEYn)!EHqWC|cW@/ J#J'nPoP_U)rFaؑSWA,Y\Qӂ=sXDA}_Vmsϩp׬AqJҩFE16$imYC0J ~7@{xhxLHZ|3LtbR-)U"wn#2*Fa&QЪ׵jb|!JҊa|NyB=Byv{$<Û Gj(f{]֓Cl ' {.7m_qZʷs&l#6ZUK |sRwGDylyxk!ȕ"ڵIq"%bCxJ _E\_fAaeSYFXCĶnmxU.,z+9)DR {E7BNG(ÕNCf }|~Lu<ڒR~T ߖSԼ8#f%C~͉+JVȍAsl-0'K|HVWr$;˴PIhq >&V f/@h$deAX][?Ҧ0 LH; CսN5 6v Ҙ,b7FLiˌ:ud.Q tƊ݅g$C1ãh1x@9xL-U*nʝ?7(Noyhdm0+ŻC*h"j{.mrb5{$K>WdLDX 4vIr^\C}f[zAKw܁3x\ᠦ:ΰq_pBB`拳Nc#EZKYB|eucGr<$q*ap~m\75J= CRU'1@}vXzߘǎEa c֕c*1tk$A""8FK]#x'by ̇dJ)؅ȞQ>weHHJ^k~1POvŧs˅Nd, bq+1ŨEs+8Yx˶[(/tdB8}w! #!yͽ9k@NX2W{ YٶKo4qq6D^cl/ $E ⁅$r8*8&|F >GU8i* S`ha9c3ve$X&J-73>5gtn{"_]4~ o\D!%3LK]ZmZZ{~QTvqبأ'ڋkT+8,aȄ{!c(s7 ` lZ`9bŀ>_гN<}+7;TTTɐ L׎®5 O–ЮLOpϨHϙD \= AeimoHDv( B'O cny=ٔ'cgj1 jώo m8{ rr_=qƽe&(Ʌ‹s86٬+`AuW)Nu?1}wqu1.m]['dQmX#Ö)]!sxQP~>ao\0v‚t5ʠcm:.4j hD*tʗ+9e= b(_/|5.)y7t6&{(rG :fihZeB[7 Y4>eg-RNU6pQ/_ qتWrpH+Tr_}8V&J]Ft".[%y`@b a^20ڷOt%­~KY/z.ny9r8d^2&; V]]YAL'Я^x[R߻$ۖj 8J=8nQThQQqueOٮ .0Z!ɬf{g+[.5̏7Hwq+J_J,HC4ӡHʆ)Wr|3^fIuvT?of4~=j(8]O /.q]yW["xj3̀i*R=s|"|;尝O@zX|iBwqt{5JsLWB΂~WsP;b8LV+Qݗ4A`?|Z2Mo # _應"E0akaxuk_Lh(;x=c4FNbk ~Q 6I'O"ҍH`At%Bf {p|)_1(\;+߾!ByEfBSE6eWjcSȇ&̱{s KI \MI;,_?8'4;EsmÝn}ר^$ÏGgx~#Y#o4z1Cr24$i '`'iA[{k>; b/ojn4bK,} |b-7BM FuA΍!V0Ɲw9၁V+9%6֥^Sr^飥o$͒jTנ8I9XSoV&F}#n na|!eUWq ,)[EHƀ&<`V0&7FT4I]V(5[>:{ڷO5WErH:+$O6 ̍ccooƒ#qYԞX=|#2yuu/czŌ!0*4qV#A[l~BP%j>~̐,6~sg5 snOWO6IPL^5&s4K&(N)1WOC Jfo_5yO1˒ԖFJ#GBk G~ϋ Y)@7UYP )f@zʭ9. dMKԘ,\ Cw|n?c cpֶ{HU}-Ob.?fS{ Ltbh &\0pjmUEAټޢP6Nm̀.Ʊ+X'g۵vQkvysЬ∘KaxY&OJ)4Br)n[=v%p֭fd)k!R}n`:n0DZ}1Ҩ?: ; ~Bd1l.& oJEGȳ,~C c})-tSS-$ I37&u}7[HQԐ24*חYF#DA |=38V5lD/B!o.|۟Wh(kNތ4r%IH_^EJՃ 5]}@uꟊ ILU[yEMDKS%韇3o2|oؔ~h4wۺLZR>EAN} YRqsy1]9+Ls3)IN_ |kH[czGQ0*ڠz/1~t/,{u^;gRX>f֛mٰ A_ҥQ:u6cְ'Gap7sg)cQPW%< /{pE{wF|*'--80oy>ȭL"ׅĪՐ9)L^}5ìv!Z͉ɛ,_-^)/jX\_Ws ^e׭RM eU2U'P`XyEO­L>7]KKc$M*{lQ:DF\cQV"rr%9iS*`3 M]Ls'ồއP2UNIf L[d:M{ >VΧկ:dMqk!LYݓ2 f}R͖`3m"/.M/y9߸"b's.u1U7!%ϩskE|UAy >?ת!r0&χ0׎w?P>z+M6WP#q` ʕlylvO@$LM4OLgLn(47=EHX-tW=xƇ7VE#X%e)>H}s #8->9]]o6F]ʳ/2Fl_toaXZi]QsV7+JWrL8CPc?=m-JiٛM$Ə敔Z!#SM*lM!OfpPíA2z/fYLw=r{fZuVNIT%aU?DMdS3@1A6烳!i% 嘎,Kp?-Mʵ8I }Y)R{&r@ʧΏ%8ThdA -awiٵqȊ!jۡkK`@GjYaC?HWi! tɚ]L[Fqgd+`1N):֖ѧZWeb9d, .Pv]# y&u?+ B~LmBxeVUb?ku=tBaW#|`K2X.-vU5JF[vZk IC~o "|.}@L$/~@ҟ圮BER086 3+-BاW:t~6!E`I=u{ |2T{k'b۴8P [M[:ϕ\OYFZd?ns"P%D؋- 1,q.x2)X,LmK].>6PxYRx]U5 Q6|cpC,u9bNZ aQ$^*6s?LemD@~!@E[D݂4t<*ױ{wah sD=D5b "CduG O"хme$xxu[t|(/XeoW ~rs,[ES!7juБՂf| Lm&5- B{<=)Rm$foo ЩXl׻Ǐ&dt_Ojlyϳ'7#jAA%&:*ONYQ4Вp8^1 cF#@wQV>8q@nhcYTLvF։O(q*aE\/?=_/υ7d:eXiŰ7x8  ?ɚ:`4+]ߎ[+z c+pZ;G& /kJg!1괥ޒxdA[li^CUx?P^p5c0-cJL7H8kZ3YG`|._%DW2 "lfXO&zIU{Jk\"ZPMkcn)˲f&vTX.%>"e12׫ I}CXNYP .Aj˜vNU'a]⣁]`x >\KXhQ~8IPe+ -t4r&ݵ!ʽa҂ BE}@{pvϽ崱78|n53 h rќ{Ol3dԛ? h[l5];RFLvvY\ځJX)Ȋo:L&<1 \2gC=~0J>Gf{eAcQRo.YV61r?G<4}ʹV}TsjIvO 8 c?ZwO,HFa_!  mcr/)j1S`ax_u rL/88 W7naI8>cUY7y>t͉N|--+J۾M>ti]ËoVU"`oEO=9Rd^@7j /=1(Ve0c;Lju0iNvV@\_g_?p|5~:/ˀN"ȗB *oKL `8pho=lC>@\O\=EA)w7aՄ7)60os9/JDI ^Ud9S*s ŶhV0ڑnd

?k3-S$^jP`ir`2upBh(s~F,($VQ*Gts=d /^gKٖW͚@h P{ Eo;Q'-ՉP\CK1wV<eUVBcS(uO(ݭ6ZEA%%?R>:̸]TdV܀=x|9)`;:>!cs]ua*+{4{&!U褣:a> 뗊RreSr,"W/$G^!a3AI&\=}%uG!&CNg* (7ĝ>xFT:[GiKx ṆoaxFax*Rtӛt:aCd&h}n{I$>M3; \l-eޙLw64AWerBb=t^$/πy:zW6H١cnIiZ49u;z\^53bkMLI̊wjΦ]hӬAKm/6e۸grcpbu/!ؾ|m֧k-s/<#xd]XlG :S`4U7ăj $@P `(`⥳@ٹU>Hg7Ew.Tho5Y] [F55h"1-+iU CFY'͢f׽iP(k@~;#br7䑩H{a>񌿨:ټx˛rmCל|î+Iq~d?Z)mdRpDee/PM,) ?8p w\n]!~+N7ﲤa:"D/ {Lw4=q%4h4M#h=&zEyv QCPw_gC6jL?+iY}dF5`%7G|1'cH(TeXzkS,0}RQԙv ݊UlJa!FCBGCA=Tfr$ڹsH߻,inpܔ9uGSvKN.Z=#)B4'g}&U 9SH%$`&xʤFnrBk<rUn|&6WG~!:9FשjޙyxcR}/v6UCD (oQ4oF%44Gi&5eTs#y†Z̲KA+qFιS?-Ex3vWZ>!:Ƹx<(OosMZW4+GUn-j?E)o>Ʒ[n[e[rnkoCg_yK] r⥟S&d[/[GI0*a-mrkIنşE,{6'2l1yYy6J/D1ʬQ#=x9PO:$7ܨQ2\i](!W,<9*W "% I>9@XQ[aB4qK3}jcOrF :wFgp!%:|Ghҥ~z6WN-5/(kZG9LkzakFufi<}V_MXdD-bf|Up )}|[eMEGD[Q3qֶM$ Rrd뻓8voQJ<7ܥ&xTje$Bc4_4ZN&P{fzYyC ľZ yrZ%rWFj{'ك-2q+JoK~pXY*E4o˿r+(WRf*f!yQh^qGB zAsr8e0Ny%eQ9M QXsq(u1C/;1OvwtT!^$ui@8G>+\iP8 G:͔NU[3چN} ~:,z`H+&H?ˎD <(yH[ȦƂz צX8^_[:g^rhx@r*RC2@sZDum\&}, i'']S۸TĿ6 517|P=4KdPBv#'7=~ FDWGGSkܒ/`%NzGxuuEdYkmiT8|-ea];1Q}Lr1[FJ=3iBn8X>+:6ڌމu:VֹO:(['@ r cDA d/*}ǂGٶW?{fX\ /bW13uŐuKeEѤEt/jrϝѸܞ#u!);bҜ})mOm:M|b]6j]d*/ZٵvܙL+_q3+,8*Nt4xĸ6ZFmn@E0Ѣ[Dդ嶲!b1Ҷ%0T ~*e>1S0Pu.[>a 9ݏ%*!h#+SFB WAYQ[{䚊ʍ<{;]Y]?H xA,Ԅvf^E8tXuU].( }Ex\.]uė:d4^J`qoQʺot{;ì.d(gGQr3P}2M,0kE ;P5jZb&~@|a6ʞf+wLynh'!d.|iQnr\FiDȽuK-c660|983s~T9nsDo|Z{JP`x)!8-Fs [}}*<)zyYv>MW h+pTh[$zzq`7xqVMҳa0 )EUy!%b&`=}ZyGT23װr}P#-gs! TF8Q>KpD?pX ż/ tf x [ޛ Nڡv;\~X<9$}?}0^b.&SLEJtwDŽ3C7aiH"ЬK5GH-uvS:w{"nNPҌ[uib.7Q`gQ-pҁG)I31vXiz xZ D  }&A A[%cbʣ6s.x0 &y@cK#! V' JT7-; y**7C^(9^Q/A'ҏ^ W,5CË7J*D ݝ2m2' q&L% :D^84jږ$:%+9~uN3I!H0N[FPhkiEK+QCIUG+xGG@1b- O[O]W csT5VpjL۞+.;*;]N&]Y?z5\v*Bя0MGHY%R}mǓkJX:Ya\ﮦ1>bɾV 8I\#sS o}?9ɥG~od _Ҽ$uHOZLDg2ZE}߅/허l1 "Y߭Y)`ÌKw͸+ݮЖWHyV!X]&cBV`+Z aW-k`t ;c=͋oLgfO;O$Wh&ϡ<5Y57{~X"Z'SXL@`ӃӀc["`Gdl9gaV.9Y/ 1 ):/qY8=p>*%!˘ɱ5)n+)6 ԰( cU$9>>c"g^+: ?R&VʁTWl30_iㆅ4lāUbZ(,RszΦ[厷^rzk%PW/znB@I]7gÁFD5eKTMF*~I ?*ƷǏ mkN9#Wd$Dwg ;qR/N\#0ٻ 1]t(QQ1cT=U7)8rs_iK{+Atgv zju$\}lqA͜.rRZ,doj_?tP&sE~3hT)Y|Wkn I҈kA 2,*F$iT@_Pv Y.O9{ei^7 sޏOtRl3c}T|$Q<$|ɽ9dHhB44wW {}wZMuO YS?vd34T/g-btޛBuS1h5S':DmMA99cBMfV *+}H0'9I,plWxA]aqoA ;FtA2˟s[D @s5_$'ZGPXh ՗P0ĭdufY.vLЖ{E!(|giOR)8 wj] bP=}+'lBK0",K3TJ7U[}K^he\{%PȫF a߇0ԗ1_`+W',uJ-|r>qCS3 яhu8mS"3Nۉ. $hH憅\aZRI`Fa Ya^e5{ux+g并bKp5 3*E;ĵ+62d‚V36fJw VS%;vȣ澖7m.ˮ&p:l[L :0D?2y;ADvKhT R]J@ߎ%q^<#unbE:Z@.ZNL.Fr`"&|K1u"?Ezk[.ftr61BnmA,xQa0guպ9Ba,< pH- 8Ǒ/S;_&$NxBu^fhɅLv垉 }){v'tG.zI%% M9̘ BWq h㔆*~c8L8;*ЁL{]B&ض%_3+Jlg73WR1o2TSKon8ug#hG1BnefUCpK+ь_.a69>7Rab2.C06-eJ+Mi.I.v"lgz9<]).X%9u7m K IG{ze\`cCBNOESnuƗE;@"HN(.+{8˙LyiRbҺa_TQdMNWJMA+gL[+XR/)yWxŜi^̳t2Ⱥ8TW5މrtGxR/.:!R/({`'xsLBW~ lkk *I{6 3U '7QLt c;wyH+) @77nS,8a=vwagTLsJyu(|Gb)R͹&~Bv7qq#7:z>nCa1j4iF 00b(QʶG5aZ&R}gJRƌD | HgrE+9(Gv |F^}JgϿ^`Z +Ռ ŁJ= |Y1,~˱ 5 ڭdHkpu2 L3kj̊%sERW,llQа:]D۳?^sW ŗ|$F7=R0P4'֭{$"UdX<TM&]Z QşT/@43NT)}꩝~@1bOFwTꈇ)zD QrnyTl0r yy"whPxFc]1\Ci4ǒSl_3&Z]BdL-KoDܲGUBdMeEKSL, YQ$Ɗ姪E$`Δ=:K5&%')b6&z@8aݰ ӄKK#ZhyNac%Q3J 0+ J4ɱ %ېJf8"Xd|g,j6YPꇣ avgfߍ2䲯W~p8 ~ XM/Mi }d|A +M0!YScVW9]'c*M )FGTED; M}(*/) e򘏋\ۦWR`w'0nAd}KYPfa*CH^0{ 4*,KenyqYA\V4#Y0J2w j.6 Jձ°_DSYd'z$Z/1)xy%&&mx}xq~EA endstream endobj 239 0 obj << /Length1 2021 /Length2 27858 /Length3 0 /Length 28984 /Filter /FlateDecode >> stream xڴweT\k5]www C!w  Hp G3sgVӻtzCI(j2J\YX j&.,b ;s%S;k'7 Rhj r0q]Jf6^xJ44z&^@V_@hj:XZ;i]A^֖Vb32[ gbf p8 w50ZY@u6@CMRU FX\5&@ZCMϯ:᝿%@Q]'ϻwIuQueIV?`]/nTj +ՑÃŕ lh?u+k~u*{9]`f@')?|wz{!\Ĵ94V&.++M\&f&n.d_9?nr(S4.z3};?>17?o b@{?gfLATQVJRMQ@q`rtO ޤ {w.'a^'Wm[YX;[9s7Gf ?2Yx[f tNu1{9|A ;b:|O 06s}o+;hXi59ý̊ Ơ3oKNH߶&v^a_Z?|i/'\\} D,FV5{!?k]_4uxRK_.YCFVZJ_f skK' !89>=ncL w T8̢D@f!n6̿ѻN_/37088ۚ= +/M\.{'tv{|/w Y8 3 Sv|7`v|O7ߐ=_?[kYP :lZĿ(:[{걼"kobb OFcd{ayweee_{Y h2Im+,.e:ҖZɘ$A. j ̤*'9hS`ٽn%UMݘ+ Kj2i|TX,&=-1N ? *L}=ڣxs`y 3I ݜqAc7= ? mE{BK/`Gq(ҫ%%?&xao !pmΰ#;YDRkH3 $*TֆFxPb0W;AUx"qsy( ̅ `t: =>JH$ӸBS9'DE2hC;|] vؕQâ"NEEpYՅe5ARG y:r.2#)}Ľ炢Bo4]B5,ōdX;{mч+ExemUMǺ7-0ە&?Huj]ˀ_<n0~&7j簕$L9czr?ScU7I ̬s}F!Q8Y|qǚ%VʕL㠅׬@s:֏D-38LK"l[.Fv3. ,T ٕTӃe[} v|NEE_CC<܊I*eDȱqٙ#U$X:5YJHF}g3<4Rޯ7"ps8'`m\L Y=mtFwZ/(OMQ[űA%$:k{}-H p=xX4i D٬x~' Oɐ^>qEQyeN٪]2]Dv`S=O 9~ dJJb s*z8%'em: /IgU~ԅXs{e09cT# SWԐJ`  xio´;S !zn8:2,ݛJS{0PS+^a.hB2cbwB&;ǒl鲂 xd %…/=6~Ou8fQg+CasjnP{56Pxjk#l]NQ >{eS7Wjͧ'1@nKι`mH#$^?F $7!iאla_vKɚLm/L1\)D-pڈrvf"Ɍ:5IIWG-<yx٭^]DKۤ?]PIoIjwl6X .ojj4cYTH1"IgqwˑOŗzD$m ! EnMPy#v{=7j!5g<u_&TQ:Sz% 1-%N@e%7AK?O1G—3jYQ Ka9#goRM\ZL Sxk.@%iwv㾸%tPJՓE&9%'W N;6LiěupS)o A:."_&dFyMt_N.(a9Uf|5hiZQHb|^h$ iq\ d+( R4N veS;MiӺ0u:bozAeCЖ4lw_݃ ZX l3[l,kGgUS_w&I2uTV$?7~}wgʼnRJY`Κڵeh p[9lV*Ćr[Gw!S<l8ݎS5}ؾL7nO&P">GHqZ85`v9"W.LgNS -۵ՕzfcY/18H {~@*Dmi} U8F6Ub fd#Q( Kx4,rUhgt=EM9tEnO4"˺ƭ,;"y֫uXyA}0ʈ cހ{˯Jy[uQŊ` bqFczS;Ӑl#cKjF!EC\\F6pl-r(?&2xG5US"„VU1Vmltf0)i'nR!Ys\ۜ#ΜN B~*s%%| r3*αd2N?:tQ;Y1c-)^!0B "M b MS$O~#ŲxGS3noYdcMX2FR퇰LkP1>]CnK"rפ\FZ8pE9I Dt ]^!탮& $!98:#"0J嘵x$[jX %lw̐a&YZ[4\l6i_o ;FhܝrgJRS(Rܐ$dzӂ,n4ɧkI#O~ Eu%'DlysN1 +xjSQ婆Rq=ּ&j>`ӗv>{ܿ%y ^ǣ4ulg .H"F߫+%sF"\7@UB6vCKS{t3<kFMn" "=푭"MG+*&ӑSA7Th~X_r2 QLOD]VX`hGjΖ ⵃ?ׇ@M\+ڒ&1&H 7p>k&X=xP3mP w x˖'-t=Sx;\MKM"i,a WLܬ%0F!IOSueqw]is078)jp+L!mO٩2[.3v<Q H'UHGhNe+u,Pb 'دp5h.Ε+'S;9L[a(:#9w"hhyy{ъ>)r'^M.3fqqe#>EFұDhsB}z^/c~pn#d,ܸT0L-,&YtP8Hc }YrFA2KMZ\'cdJyIцs, +_ ~CW#"rNs3*x uB7A\<]{vJBU$ nvL6?`3wv;1וӆLE,mI: 2%dgg:Sz{@CR yΰr9}(TOGؐ6W%ZPa+>~x_ )aw? ^j#t휾 AၟI:l^ihA4L l1F kN^[9!̘6exaTӕ<͈6%c5`R MAV"+f%A3-* Md˓hVgNu. sX2dmۚ3-u=3cM3ar8>(-9Dx${1|#t@x~R8eVC+Nw,c@zeACV1dN-'/m>[Y"T3_m_|vt:t.RYt(>Bl'Jtqw6}οe.OȹNB!ӧ%rЮgBi( ;f׸\YzMr?bX_=-R7y>}bRU*y 1qA@8#1 fwvͨDd㠅R( >=-&C|Y Fw1>+Ysx%Fs64$"I)ht>\»b,\Lpn(C:R[#].p }NS"[f83 /dUT st]8^,qlDBY!- F%8c!wm@>"-nj]H|wHX^[EXHd"MQKe7R hmYOF,rFμciP 4W[OHu*l*Rq3.{D:T߄pœ#8_qMq`kK#&3Fs@ uϦk$4Q|G\h)0t$6f0lcd*GTuuW{^xzy䗣{NV㯺.![Ʉ\W~i8 VHXNIrqKKyw4| Z$:@a]~GۃEp? a枚eMM3͞#¼Q3&!$.n%Gzӓ5<~_^*(kIN4E ÜZȳ{Mv20w=m&+{I۴t}KQGdu~ec}:?T=S.w{VYWq}Ӷus% 8b~muϦ #q>3ȗƍtj|qC:==~m&'G ћxouۧZf~Z[0mi?,:~$}CȆ='#(^*G)zr O<9#gؙf`H@;:ב*К r^E`1sƺmշ=jf/YU]mCyմz߅m(V GjjnF6QHœ>J1B_w`|Uy{"RoDZxV]9j18rfvuŵ~E3sI:Eo64_$:7[f?)lN;sc$F34Ƶa5o`=B' ΅BM1VLq屖g{ R0g4I#(뮨@.jG qOU5dNbP^`go[>R/v'&_!ɓ?E&Umؠ+\yG5l;lٗl{+PIԖC;ZnPc~v1P[ cʎ6&j/,+3*MHXGN4th[ Ab2 8T&@8#c#``$Ɔ OGz:5ZeC,G-rqSڙƦa3ٌL91 5rFy t^uvD^{c" w}W~oIĹ}Ueӧ Ņ>*1Օ>VGof`@iBg/LsN774aupT-O&ilu#丩6xHC`}A6Ǵr:-c)2t u0 -/NI``9ZQd KVm8* =m*'Һ&vo bX0DL[rnHn^G.S\2ю]dݣUd K1`Ԭ4Ǒ~&W5+w%jNȁ̊:z #x+>ᛔsF&]Qɛ0/$G$yQ"LDy=M,Om݀-?Z꧃ '',SԽu3)>~ՠ#V&h(1+'p ,Ѣ7\@Bf<`acx? =PN *DQCVf#0W=؜vF9Rrsxj=l9(Z@AL&z/(C2paㄆ8_NrׁU;(6i!ib^>((پ_k=3֛Uȶ T6osàn^y4JQ,9Ns52):e $KG.:k~L:Q8 5(o]I+j' !3X89a+΢HG .>s/hN[ӊK c*rg9fI5)bP6 sQIU^iO,fZuMNm5tBT1&z/'ۮE)ƹNcV`bT\YY)ߋ'C#K{e-o|%Y%oVɔ8-|]<>v_W1,Cu~¹w|L}u19B4ц>цf5:-SXw<=S@E `GYlբA... ]"W0Є-ua]Q1Begp~ sR#]c\ 1*ߤ7'z5/יbX1%u2+q },!&?#ĦM{->XꧾOI@{jCyXc<%1'½-;6cpi[d_QUM x! `o3y ׅb#'Rsfô!iɻ.Ǘ-m 4k'yE!\O3'~1>=M} Ņsz̗'zv[8t6GD$?.7->7ŊM}ľn7ߚ|*_U6F" ;{O~[gui?H!h?kT[\O3J3?AkV 5?)N˵Gv=b˥;ޥtRzXtPQƁ9"g38t]CNƗ3{)|^qFdW'vu#&Uض\`ͯ;.`덜AvdeJ~WbZu A-0[a?gM޽#4hDJ^W>Nm{r^J=i?B'SX,!)a :t(w*^A$';dYB gyQr/إ(cfy~ȺruU_ 3GT -0fAh 8M"b/獈|yW'f+c+(F6ŭg?ፆN>۵9[Hg;۔v7@)C6 Z-"ix5N=8 jzB1qY{ݙn $8lQ&~7ϯOD"0  q=8"Z2#5MsJ+!7) H :C׏R{_dVw6K$NT -;5ET"Zid ,䑰}9+ &[=R' r@V)ݣL`BR $]X][~eXln}.5e/f`% z!X PIe'&?=08&LSVɇlp.Z!c5J/%\r}ℝ& }pc15}L:C=~&Vvм S;55cqƌڝڢGaew/FSB|T+A[ꕾȨSTX; &V E%|R"Tڌ8YaZr7n 74St3t᠁ߙDޫsEq(J#8W_p?H @{J05~rW8|4F m}\Q3LBMNf2EYewþӐ~=Ժ|7sjL8 /^S2|f,^hCJ54H@fJpa5 se&N@15 uO ;V:!\l?'uW 6a]9 E缯dWER5yWcPu~O&Ji)jS@a;^1z4'x};!c\W4 qƭl1Z-uzm#b{#9E2߆ub,s/*n5?ǹԉକ"k ןʢȡqGN͚E|$_ ivrGݰ '#VxMS2%~c3cV<կ)'W,4WFR ZFǺͅ MV18uPjEhZUш vnȀKp'ך&w) .]leH&zX} ~}R1T2bQN`OTWLA/yTԝ!jc"Q)L(ABKwzb>q |B;\ UloKdy%ם(d19 ̒rg%*d8uW̍ݓϡCzȔe.[]#fk1JF"{,? KBI01\UT> kŌC5W}?C1\19(}狵9EfAQ{!wkǫ_L-Vp\-+Ĭ\HE"DGY$Pnj5 ?nWU* Tlm}JLyÞ,}SBk%ah-©DVԭS> A9LïJ/zۙ1|b>NXT1T:ybT}G)3{lZԧ5w%H?9NNn\Xc%B 0lA-mФ;fopZÍ JڥKbHhB,ʔo1+^h(҇ d|5/E昂#n{%ۋ~Fj"RɠEc Ixp@IGTӸ"Etϯ‘SMd0vp>#YͭүA<0~Oʥ=o~ osD>j Ӧ|C΋{UoztcGZNuSt*cwH:9b(>Z !l,u+$8>cmDenVCjT|IІK>ɧF/n^6(_4ݦs_BՃD.͸b1,:k砀>⎐GV]P 6fؔHx 󳊱W uȐ!&qrv7JZP= ÊU7XG4Fc*~NEįeB݊^c \|/"2OH0fۋ6GP"Ŷ DsͧdM{Ɖd"[(_Xb(wFq3{9O^'x_#k ;vY>JqK)^!k})+QQnE~Q&(?+kYJBh9'M;Y᲼.ͦ2LT/`M\iMڀ_8ncrxN~1FX*Ad#"@f&9k黀X)in­[,SXξϪm#~aNhVWVY= œ2Jʯ/*xNI%#@w nvq0>ynضfboblZ3blX"xH3B>oj tK1%HriF"<-pQĀb.HMTܣ$Lv-l&0 _Ip'-ܲpaG9,i ASiO vOiZ9^caYQe\8TJm~r}MRI^q)ugPŦ G~=4]@4jkI#22}^zZdP``*}Vaw<#4s(&+_5exio˦yMVS6@3,aǀϣ??CûG6ӭ/GPo%%pkmZ;._ ow]7 IH[F.;|[W!6yai6hchA I)w,ο-Se!@_=oo2q?azT.')3NX-Lh@$uEEHTDXSƩ- L/ХJ,7$JVx77iulBacmCA|<btݮ䦽RG\˸j׶?6# fTZB5!c=g2G2l+_Y.i}`4U7 S;R)`0H祉}oQ ͐khpv>Z\Db7X!msi{|c1`uRv`Uڽ{KUDx:C1Fˢ uE4uC+-nZR >_Yn)HfOJ'?W3M ᗙ:y{ +vgcAH , zCUgAl}f^TJyui۫,nX|ϗCROLf'3d( c˔wJT^<E=G>{0rU'M}8qbek\Ӿ {RgjfJf [6~7w xȧ?SIn.xpoUT3WtB.vE8CYWq*PolKMtZ>Q!5S$@t'gT?(P#vʲxF OԒR$zr9j^,3[!nTӳzh me =){H%G'|!~`Bp۰* j5ͷX=qZqѰS4-i &op/CtN1ĥP~cȰ180RcKg/=ٶ5/Q"x;LȻ'=͚$yr>x.#dU󎓛44_ɜK,Yfy@pYGVjc欔qCUNP.Z몧XS@M'xi q%~"21q~ag8OW9|Pۑ&ubJB*|Lݏm4 fDc6.HoZFqvU&{)f[ ŠPf5+x\ghS:,]~O.y- FU^_Tƒsc욕o7 +Sk*Azv-;enm^j wE9hVЪd`K޵_}2Vz,lψq;)EOEO~;3 a( %nwZ%1١qFC+ ,`p(+bspJQECOmsY5c-5GM/8~6$(x!5YHzl?{טnP ?@?!9rUeq!x:!Xxg~*r6[\bDt84̾?C13蜡cxbnbk)T[`wLQ#2Xz>SB}p}1 h$!9n4T{<@Fy67Λ86fj*f cfF>K֓9\ ͉6)X&ݍC*$!?4BJhI(b2Htw31֌j/d>!J{4؇Xk@ E;/;4e]4ZXbhk< q |>Kj,BR:Ci;I'>D#x-B0%Lv,jf6ˣT+298¤9eaQcl_-N<9!/YIiK5VUH::8Y^`pmFD `޺i7^e֋~9.,h-3jeVN.脫 p/klۡ"E 蚛th1+O#r-h;Wx}dW#ٯFأ84q3&s2rpu ^4v JáYr /܂SN)xͪo 4wқ̱K>ϬYlL5.q G/c=f˹D?q,:?ɎC*z56x͙9BuwWvY=4&}^gj8B"Gh a qY剐9-:@qv]ʺF KtyӳȩM #549?c+H%N|!ՊI3ݞi>ZGk㭺ɿYhozl$OU5pSgdRƢѭuO=|Ho@AV3' anNQ :_訠c ̟ۙ2%P8^/JEojdz`Qh_ jϧj|%oSA+H>'{H`sdJW@ck! jyaS%j+Jea;{&G>CwV![jtӅ֣)!/cRF61PW`i; P31HII0~Wsf9S!5c2}  |PY.K$]f۵~;nCFr;GjEyIr'7<)ᖺ@ uDпؖM1"ڙ`&="7WƜk5PH-H! +HHz*IǾRY33n|qSLs㽫Db"[k9J9"p+W@be 0X%'pshBQTޝ\2eKVlt,K %%M z蟩6zxl99ӌ UΔB|Cw-. tq&˶)Ip߇3Q V*CsCP?:ͷO̻bvNX ^Pa'{P[m݀Fn 0 T|Xڢꨕf0}J ثjUrڇrӎ*Lu™aSyT*.;8s/p,ӚdՌp& 5tàWZ&oOY &Ч䯒D֞e<#DA($QbgMcvZ[!7t򦬕;֮À[ LEj՞ȡp1(߭5 /@ǯߘCB7u >mT׷?KӡŦ5L`0bҖBk~%rEF8a2Q@Ie~yRT5X1 4Mz^LWT՟7/;j=0rFKȢ]&@О#-ʍ0TA%&f^b#/$Nj`퇘L)DcҞAȽF囑s~.o!eJIC[m r~o6'i >ݧRDQڮ \4QƌKP&kƋ'('rE4V')>~׶c"Aq.H<8 LӾ0cSr:(h<` .+x#5Ӣz7=AOFQ=L[&JgHy4{KCF vJPg|` *< I*JL+sUF>)=!>s#M=yp?:ۢ,O7oX%U}fMCΌCۆ< H䌄6E+yFU 5+$ŔJorPB['LYMw)[8c5FQ 3^|4ڟ0;jP0Xטn=Na;7`V;62vMZՏRjy*?Љצ$LFa{͵dcA.beS~3)IřqsF~*_܋;'?7> D'߹ I"wy}85d^Z=1b(({ص^jp*ncbki![ĪiSH2S=]?ΈuXv<+-Zu:ɪp& *C,MɖQ`F%zAmTQ)nrz^%gGE/&O]5N¾,8kh0Au a'#?Я*dqYs]St9?J÷ k@@v @M=I1f>L2i(Dž_o Tq/eWC0"C={+"Ӟ:z \GZ翡%Mֵ!lf:0-'d҉!BG|-릮̴R:Ϥ P6C>(3\_'^*)CcD'v]H)YOߩt9$DjT9!An'(.xU5sBɑwF\vFvtĺmmtA4AyӱẁɑMd|fh-l/r#p+qd SP:̪`"3hyj-}z,4^`2+wQ`?UHn?LTu.O$ -{4z}(@pQš .&3xEP7%D S]H,;$ȫS!AaeE*QV99d*ץ\=kј“pS.N<匞[ >6A¢]{7Uo$C5gK10mQrӌmPU`̴ ;WvED\cMUg1P`ג-st jFܰK 4%ƹ+‘YzҎΐ5-[b NRcRHT|i{[@mopѢwN[Z:;uHv>LI32C~?!(Ê_&Qٓavc0앮QWqyqډ;Yf=briEn?]=FH|&R8\g rC$@Ǵ/,#yPS_ٔm5#qP0b.]b٤OH|toG="e Ać)Z#{>.APſE8< #ݙ(H fWzxlN|E_R kT;l`)dt%Fl+L! 4Z,Fʊ LV"amcl˩C4ӧO6%D= @3iZȊƎYi:(|K-L A@"pپyb画)ԪKYE90_Ob9D}0T#ɜ"J$8!`34L~MБUS58d9嚞-*).X1-vF߹xE:׶T\S (fvl>5[BfuEnI "}. ɏzE-\H@4k5a:8Sxb:QP#%MхBs@ Ժw.c#X>G(e[0~,NX܄Ȕ|跔r~ Pu$_*P rRo|rn?:=dwOL-Ք̬!+!J{lʏMf# Ft7zٮͅ&Fi.2O~?H,Rb.i+ ׯ_'ۧQ=LeklˣL]H1b rڴ:CE;ciƤc%Yn0r]nh(# |<5SCu=ꩫaާ? eZo*&&4۳Em*xUHlaK=؊17U7nĵc`'ѾWT,F,ۏ;teE!t=,k>GsFiYZ9 7`LTwʧ.~ Yss8{/ȳGX9H<v '̶IC#fq#C%םVnLgTmۅT3 66nT #Ug{ GG$apÞe|bJE>91sEx t"*OUү;T ؋dUi8{SWAmO)Xi峾of9A hAAZlu!:=E-K'`fO-/O n @ʦRς^A}bdxZO7i]4KƆ8[bp52TXȼ g)u}aek""SZڿXne&5ܴ!+,˻Sb[+7ݪ×j0L| \N"9N_R'xX8@h+sLh58~1]d̂Gg[.}'^.qB~N)E~dj#S_2SP4<;gJڌL#@'+ZL5ڀ Ak@nPn6$"vz7NqEEʘORkWJq56ȁ~! R P0~t}Vk mCb V>fjR>S#X)_O)]' 1cB xSXF g2 QpCM⟰B Q?!B#bxnX;8HGsxEq \yѣ?*L6tx7+<(`Ǵ>MQ*E>;X{umpnQwtxLGסi*2/`V@Gz#1KݨLphz䄏ʭk5B ҸA${&+-Ook9b!k~+Ygv*ĀQL V8,| =? rƘd.FF*%?O^yO{R "X!=q%#(_9!ĀC-Du10wω:710,s __<۴t<Nj-i&xfNE+ul!F{J8ʫP?%"Y6X/n"䭤ܾ.&V)Eek|X朏h(8{+`@UtM7CYC[cPJuvTMZSŅHcS_ &kY9Dž8G$T-kk|iK+)Zg⭝^%L(qlpB-OIp@LF ]yn{W;|AYPNBem ePF"Y񉝠otmp2/9􅄥`hSq\jZXQB`f-?Dio/<wp>5?Cs K%:]W_IkdN sY :I8}k{AIsqB?S' _AHءlGb9ibs.p^TO ]~NFFꈢۤ"*}@7Р7Hsgoݤ-U2=5pOEW5I7 ҉%pcPRi@=.yD4ֶ;<}Gkvĸ6 >om5j/~[gvRM@x䤬h[TzJ8ʄ~{,5ȟ1A0RR 58 ()OZ|0◄'ס:4)}#V 2&Qjf)M %dLQ"Wp, qHog3*S]fV }ÉR_e`,nˡ!^2~!t1X_ٖV4Y9SG3%D+8l!!V?]+E C!^0`;X$Nf?7AM&fۆĩ%mp5t0Iz8{EO|encHNP`)LW&_3;D +W2jY g)aL")1H{"CF쯛#eh,ſ(h0*؎29zy]!|(79I%U@OFG/E=nWRE]dQ_M%8XQ{KOf1 Uv`> ymq<('iziԄ5σg;Bo|DwFᏜK7Ymډ#ԲbQ,Qq-X H|h!TȬ3bLˁ endstream endobj 241 0 obj << /Length1 1950 /Length2 21950 /Length3 0 /Length 23190 /Filter /FlateDecode >> stream xڴeT[5Cp'xS-GNtFQ5gw!PƉ '@ZFƑN􅁁Lhdnk#l;䌜>L d1 i 0t 퀌JhcjnHsw075sSO?ق_Fc/Y[9`432ؚ%E%՗JvvEHIYE , ,TW|7*.#,!/HÍoj&5P99qӻ~1uvtb`/~fW[Kǻ 06r:UDF@G$Q9?H;؇NjZ+W3ǿr6N@@''gG_И_!g?=drOSx2m+Oo?6q4wtrWE 㟙eQRX<:ul894'+"6Ba'l;/MmMhnlGbcn 6S݌4kO?X9Mo.@3Fcs#8&U1p߮>_G|X&N@ ^VV@ ͭ+"ԀR;͝N /`cj_&?gcY?.?|{hditt|eP~,^\EXRNw#[csS+cXY[l tkC_ll>RvN[?Sd cq FH G320t!jN[D32?9~D;͍l>G?ʰvPp2sݖ \m? .@@]N_Xfn's7-a'j@lAA[7O:6$?83xWѿ׿N@veֈ+")G$ i&dJt;gmb __y8OM:Yʩc\Dl/*2~eTGy,qc!(wer!] Pݖq:p;@c P`IBt~+{"ƶk½*9b(OD3YU[+>s= 'NS({IAT7[Rʉwuھ6U+f25qNH·_`7.B{g_u4[`zv}Ç;i/Q1.aQizؾ$Poǎ䷲¶f(O߂ cչR4Ej^W ܭ.#U"-aYJ1(/O~N+x9( '! Dp+p f;D**>dj/ OYG$ A䠉̶̣꧓mdvPaUб ]5["۴,?cDxă } )'(H%ѡ]%UJ.iI$bFVEӓ<w1@cR@`J.t5 v2;=Q:5F$զ>EsY#P.9u͉y89&urp\3g>2tU)2*~GU ykq)^\(vb5:7 ƺw7GI1I0&n.6S ZqP؛!7bo-*%~ trB[<| jP1e750SsP_|EYR%ydϵӽu߬t@v.ozʣܡ ǽi`֙ȥ7Qlsr VKW!1b&=]ič:W!Cr]n3̶Pn_rџ>>ĕ|=5R XjnؿgT+( \̥ff͓{ -#ֳ1#z- wQfB"OӠDZ@_UӼhZ7F| x*OOIo_ hJ^Q?=pdADZ18 ݭ=1nXB?jH4T-R^Vs ;cS)($3[W(\k<ՅF݋Yw/{sJ%%o6{ gX6v_Lu$9m6hx+)2m7t܀#vŪ# ƹμxI8u7͵dYP"YL(9է>8bt}lD+! \ms5U厍) \dz+ FF~bcȀ162O1oiEJ!BKX;y9Y2 =KwmhbbR|l8 cPN-2{ݲTUuJ2彚elQ9t}t|z7[0%MqhUWcNr2gx=#FoucX2{@ C((J^ږ\m{d&PS&. Pŏk:V\ps b3idˡCל=a3<4JYП;œ5~(.4vDQnҍro2I9Փ8b i6G5ajL܅RdUу7Bߟ =LNJ&Hb&n5$S 4OHK;NZq]}Dǃox,EZD#kQN[C21]JkWyД W7-df+e,j!]Dm^ڎEO9!7d5K#KdcBm"ӳ1^Yy6K>3aӐ#(H1 EFvW̛S!"A&Ub*آ'dMo{ǧZ=hRE! "&Y!|P?hFhwpGJڶ_SJ>W[[a}u`Ī5Z+~P,*MVjҩͅvᇓ&7+͐;dN40⩋ oW|"sg^9(E;fDŸh# &怅9/v}ι]ב%D[2[;9Qʕ x!4]UdYsXu"!b.#$ 0}q1؂'fra35*/hJKqt" BA6Ȩtū@ܴzB ދ~ߔSyt<}IKřF2xKECXۺǨre+8\|FyI-I<+|]Y m_=/r)+hgw+2i(yQƽJrCjL 5KsysaU:`A?6gœdib.<G n284DnpXrY,taOWaHE 55ڟV:-[F紻#MlhLWθ;I9S#QON,r sQ0x>_$y(nsu_k2{~Vԛ:Vs^ CigrT1Uӌ^"!&P-%zD3v)LqO eRy#V vڝ .u q*TY6u8V:S̀fIx݆Ppdj)r,3^(KdP=Ú#V"6tS!;$]1A!wP 4%MUEeޥϵw| 5E_)ڡQC$_9B4ckUyYXF{י|?{&6tN%JG;4rV0J(}K26~%Hl/:D!4y ̈́ܵ 7nm X u%H*+uc׻[}WhC#j P2G} DA]tlCtMxf0vNn50N̍Y$O j5}e@އ ]!Ia)ze_~{ *ą] -4_MO `g-G#=PvH\Cj MhsȊp *biFv7kk0Ş8 ,Yw7twH `P<2#yBKĿ:sl$--a`9b }jߦ>)F%*+mH8/]>#YoFO$%=B1Ib"& "d3*rBDŃϙq۰wڐldtȩmO2A>v˙He4R.%A\V#bX&%f~1yJt*PO`ٹ}f WK藞^}}15G9ܺlD.EMu&ʱNּxS<0 4n-.$SqL~S3+)kp_<@{qd߯`JV)( :g`Fb!4{= i{4_rjE&n(D|06e~7~=wROS2T5:&P]EY@uƵ. 543͙H%,.#tLT7B] ҷxD7V&g2kWaYSqNf ;y6v˭3a&5Q]D; Ckj YK[s_LGf,WJo#q^(vR2'(vԃJ]W`dr}phxniNDvWBie@z4o ~Eץw'rjùiC30T2_D֤?Z Z %DT2?R im8j]z _,*+b߂S625d_r-4vR Y!::).xpdr(XoƀT1_N"}s}+ M[KBuᅷp,$iYN]07mY%~ش@#l7☌X[cvwtGi3'Θ}WXL*"6̼]_,3Sl?܃I^S7aaP@5zN|t|fkayp)7X8;{LQ|(!Yn7HSS5lFvoZ~,2lVj-n5C2:7>2 0)0Ҝih݁91S"DL)CUP 0+5ޤ*{ޭm:a7l](J lS&|eB]Ú`f?  +CŢ0{J8Sg/9a2ŧзH{luTh|mF+d2&!31z#p a`vڻ*Ǜ)} hY^fŴ">HV]t>_]X05ʟĖOq$[ Mv1j4t;MƙL ӭm@7 r6Ӄ"% Wj`NzGTH:kԺl!KQ"LS(ݟ bASe@nMĈ@Yځ˜QR3oTq5lൊƵpJ6u򕶐Bͳi6ĪYjĖZu2%'m/T{[+~-Q@:) dabA"-g^n n,*FYWB ]6>]@@I#&nI"t]^'zۑwI8=4ۺ(d7|p>b'Oz (+ll*~0Ҿ82yv /!=qYx*!2>s%&̎&Z0 8vc-jVT\){^i̔B 0\ngu-tNeN0ǍLu[k @]7S jaaXl՜N.Ԧl~tUrWF=K쮇 @.܋<˿'x)C޵M gUR3V5jO( @CPؚjn$ 2ӭ>d"FwXLb!>LMqjɠ;v 9t^HaZ`|@$eS"NH`X<yxWU{6ImQ'XlsU聮;)ɸ|6h GRuVHPnw|ڮ gȒ/BM辡yqV%dwOtoUtĤq]%"~]vFs7x4 Ũ)uT (nS6)Zy2r _Y/-_Y'nt5tѝ_x:L0[X6qrP)vkLdV3,3k9w?<92WF6 =݊L-u~5^%hnӅq[-!a;-ZC)I_Po&wkLϯ,pռVۥ `Rb p{!udz"}YC-n/VʭIlD7 Y Rk"`P'wH9Hض /(Qrx\:ھ Y_ߕ~5#lPNEb^X76qT'K^t4Ӆzg%)EK2q/]PʺNpK>(w}gtـa϶$T>;mji EP֋O.A>V# JP!@uJj ikZ,`3x?:9zb ޠڍoqߙhR[@~^*s`A`G 8=ӆXGQQKh|J,ΆL?$U-9CE5Da] /jٸXE]+Ϋ^b ui{f#$;p`Ki5)%O4z%֯˝(R5JTes ^1N1פ%oNff(]:-c?5*w"nJRާA!wF/hLe_#m%V}4:=h%q ],Vv~JQV†`d pɞi7ȦV\[o^BAD*_ @q@bR7e،?K j JJ~#<:x:ԯ@ ~i13AOteqYe>WʽP|6QZ`5l.{D܆7PzM7¹R$ kd`uʐ{'-VêcJ3 !zki,wtɘ0N&C{{`Ҧg1Z<t(J&H,4 X"z4dN.Eg r N+#Z(Xuvk=M ׅO.J(D~!dYeNŭ\ׯz2vDApMzx)Φ@fV ?}ZCx?dپVy>龑%7Z7Y%tfvܼYҺ^R ]- ˎL}VH'BWoϦkg5cxܙTP&טܽ7AТDfN&΢3[sB{—jz5!͆QUpl6+ɐuդo%VcٯP%:!ڢtN ! @, _uXfI9-eHhmQ1ntͦI0˃ s4*Qjh(Ȏ@Fn C%G]UDdcJw2%|/9~HTHg *ӕ7O2g)E.#dA|fpj-@. w)A0 # >'ǧ]>>J>+(2{nIVMexQ=tpz B 8phuuf^ۖn^6WE4qg ?RR#4>b%PlH;Z[*9c,Yy$݆*ZYvGfUPe,(ZT”ʎJBD)N YAsF!oNR9hBؤra]oy8ZtFD7Zzׅ=' >Bdj#64uI<6V S2Ք:3tD P'afaECe]"RS;k+Dܰ_䩨\چNsȑ7t>3ȗ%KcF2kU7!OF1YHgǃiQjFR'(pU%6Ljxv9@źDgўs2Q[]KG2%]4cI7ҀxLj 1tL#Q41j+Yf;ՅƔݗXVbMeSs `ƫ¤B!s2(/eKl$pPȡ˜΅R ʍ'!J#u3G**PȐv+i @ڕgo^l,g "5a:WmJ'O!4Y? FJrW릍uK됭"b0P-AXA'uts̩vun<_:Jxo=BZE.=)H[~V8x}nC -d2b)twA&G+hRn>BJUua0Q(׎Î$/1= ^z\ӧ<`׷f{,DSNK f<1Xtg\6K,]":Jn@۩h ͎NT-_:Vthܚŵmyn(ôƞ3#R5!=ࡒ'N$4NyH- J T ;!Lf+nn. Ԓl/Hњ!h9 c9Bi{id0z?AS^3)&#:0aE$|~u y*͊[뽊2msbH1BeA؂ɐY:/JsA8ߍdߌ}] iARfVd'/e kvHij 0f0'`1+WljSMx\y= zŐ4 &ȷd?^ET`0@/`[3ͲWf)ӄXXPS k ޻klsBt;lCZ56\K1_dw$]vc*Rz +ȻK-/K .xQvh;SJC\=C:I€%Ҍ7F""<` >GPlB!6㹮L'fU7ІsiqZ|F2 RLk wTi*L*̢N 6|ZΰF>"áQBܑF ޕ Aaݖո+ڐƬݹ ."ѶtxΈջsyVJc T}3h{ݜafEjOw\+8r-ƗZIs*aAebfd7'(J0{$d ,y`E@Oi!f~Ve)_b2gݛG(bJV`WfsAYUH\)&ph#b7\`;Sڥ4wGf&h]s0w6zG"6y֛lʎǽLeX^4wqlIoSQS/(胵ޡyTS'iLAD¢t]/ɲj :Q ,iJT"3⃈$sr拈P%1UR4U̱qC~.d)Y8!Ҭ~kH!%pF(_+XLGjQ֣h0 InFSbaS7aE5Wb\DD{Kms KpRm-.y!-&zVoOGU裀1Z_:=&~i5 uRz& Ԃܳ Pb; h_ { ޭT@"=V7_~> 9vmݩ^ZƥY&aEk]w`wC}'YGh5Â[Ldhi,5S?B_JDSi|qk9> MEΔ dtfY(AGė{p(S䵾|E25 ܒ0qXtp=`A`ؠ8%4<0g|9#] 5SOt^}& n3TqNp\`v@M |U_ o"gO#;gF/`2᷀R{fRb-J@6yVOO!+Oha@u>{o)I>93Tǃ£Kڔ/8' { FUjId U2R³ }uiczfwhD˥H]CzS TT62 `+G2N&w>1߼ " kcSL3 HgqvSlIuqFSW }H2wבq kp}&$8"0♼$/o)VI}ө׼@Eٙ8AO|6N F89I 5:P T3 LER4n&~1Z[jHFܗ'oHGr~Iǫu y 3=^oW.Kq\:_&xqbB͋`-/`"ө-+/U-gh:@h6hGD/( j@F}fuaZ&P8*o=f p"CH obѕkGIe#g+w XhB1^8UX\Ty-I{ j/XWq&ߣ-&G ĹӟWݸqhrw˄! {uU0uDݧ *ȥ՗/p8OĬǐCm5*Ѱ>aJjUHv9_Rx@cjc;kHax y&Z5,6`ݽbC-`s~AGhE9|X0+niм#U+ńFS'SٴYa&Eݽfs?Ju߿4N":9ۼū&>ڄIz%ԛ{{A=zD  #Pt\QJZ J4_kbͣ Y7³$Dtr˄m" hyDb!A +;Zu]}&9; ~"|5OHWC`- vEg=m,c8yP9 D!>Vg,*?Om|W7Lρh/qK/Zk{(4z%;]:҄ҋ(v] P0Q2qyWUPD{ɢI@7zoЅMvw̃VE6 U$etfI:ك{e3P7/ _&r7[",4nMĠh'K{sm_/,(1zCs:-iwvR/ץW7} @='&5nU m j+~`{wppDeGT mdJj75cK* =D! V ,$x2J{ YJ+"b9NmsX٦c{ W%)͢\5N6,| T@Vw|. #hҶ&n@L57IGQ#@Pq>BeUa|<a/sW1Eџ]>z 2wMT Xm NG skS!]%;7$o[)}1%_:$ 6c+:H*f`?Q> qOv<&;BOa˖o/j\Y4x);>5>BD)j ^K!Q'vNiJ:KS (FwKbf#J2Z T"TgiY -n5tyӛcVLXS}rKШ PFVʧy;J?3T;أxE4o٢niADQ<*Kec(r^V/Y 0 [~OܞIjM30Pq!EMgR`Ѓ)y2t&~5K[{A=]y㦞.rZ`zR2}ry߀,PND 4ASkd Qj peJ_^Iϛ[ܮCjbK*xǝYŔ|AOW2`4Cm=۠ܨ{; ?͔{O׽X M?wA5\Mh~~mDa8Ē a=-f6YlkMj7K‰c߀y ~NCu짞Z"Ӊ1Ů?daxnQqƫ `G+GTB".@PGwU78FkUG9뺷4 ptW̙wp6r7lk"y>SPI\"cZ?)ĩgl8arrCBnJyD Ab4^`8I%:Uf)L-SG{8|ΟD[l0oWX:n9:,K9rR6T - @Al[IXPSK"Y 3 Ev4+x:>m?GjAk%ݸЉoa^ѦP޴}lR?z{djrRTlmdwQL>e_ u{ad@]o:Ukzx2{rnC`N.Ez㬃's7e$^w¬jox AZ)1>::*$WEFK) 7'?+jK$W2>$/,Yzj mQ lCsy"vE`7u8򋺼c2aD3,`쬿ŨYvL ͨ$fm|Bq%[XOxX^Qv'qHDIHY Sǘ\[y;Z1{&N#^ vR@!zDNL8W^·&>Si6[f؇"]P-caƕ@ NBDVI:s)ˆs0JEoi/Xי_˾4< D_l34MHD\CK}7zg |*GYbu滱~슓ٶ2&i y0¿߶tgN|x &r^ \=[dW5E1s(6}8 }]Bzgl$VL1dJtu&nzoEs>T1iT%C<٦2{OM @Q>6,؇R1)pgys,U"E Er OINi*U*/(w^"SIwC L3*/ m.z /2~<VWXeC2,.l<BmA&H?y-i˕^fN3p ]+Y4j 4mz= k,?w.1LCHSü |7NߜKhlߥ/} ?)0G/.d+&W##-k]zVh@˭U4ZWkj}p+'~E+ARptXO(ԌhSPy m {?OǸ\Si - ze=-_9gNpc?W鰫F<h שgie]v __%/76.6 Ӯ¡HѽԐ7L v7xbj9"~=FX'Ya(Uf}/dzkt&$@(WS!A/ ?Xw=,0ϭqz{_ӜR:!5Ms[4khxR%g:2zA)mw+eG[VN DsY\A{#[J mMr@љ-.1TA? 7U`kR]v,Ed&=$Z\MwB6[Ӕ&f(WS\wjJ)5u"V=DѨorp8<3:&qx: D=55VQK`瑞 V'*_(&qrWj I+Z&6憡BV>1RC:3 TYrԌ\UԊc&s4X,dp/r+>})̐/sYq4 obTO؄aЃMO0hd#y#VB}5+΅#k-pmOn%C?3{&gLuV>K~d1Z 88RGʰ%8&,@`hA]u][ܒv)e) {3g 4Q_dejQJ]KvyJ7kTRh ۟m ^Gø.0itsw`bDzn C2@=Y`~EoNldGv=ufqJܢc.CK7)"WLq6[Uf!2ҦqGe'̍4aŽwNY`.ʹ-HY>-!f3_TRWj`~К~A|QS\L{{o!7A]܄H1)1ަbQTXS=#lItw zOC z?] wmTL޷F#j`ʅ5̘kuQkZaX9q+|U [,,b_Fղz BO\5PO4CvSN)πKF$̩,~Y2,2ޭ> stream xڴuT۶>; Z[ݽP(ݥ8ww(>Ͻgs~od$oϚkd$J ¦ {;Ff^*ΙA`edffGu],Ā. ^@ ̃@ فޕcO<bPJ. @w5D"jdin'ßHE2@k{wgkK (PwZ  $UՕTi:8;QU5uIz8ATWU{oNPP{n]^\MXM[I,7埴ōojfN%P[8213:0;3:Ond x:l@.3)9K3菓|wz{!\Ĵ94@|唔@K; 0K~A@OU9;R/g hM-]0ag, +HK1Ƚ7{u]<\OXL `a07;kg?|'vvOM]Ȥ]`  ??b?2z;;̀6 _K38|O04qyołWti;3{ϿLW?-@By_v6S{CP+D%o;X&Wj{'[,%,=@J.&*.3XX%Tl;}y9Kޔ&v gg;_*{!{0ijk?]󗙸9trz"0+彫MA  0wB3&?!N߈$o `$F&IoS߈=Oo7z70ow#ɿ {^w&dw?;;w&6Tl,T坊?ߩ8u|?; CDl4?[_ߝ?g_Xii~DdN?P{[DÛ^%gxk}/@  Ҽ _UZchxT4%iLRTw$U芾6C0x"/#N$'huG̋X@iXoeS46 N Vcn~,rf魂$ln:8 ` 9!o,wjV0n/%&Rj'J`?$Bk Z*F2ڶ1.gC~=T<~h#2χvFn=HHgc ߒY )L ~]rV1(71`&. `~w+e Llz .s&0c(^T4hxS^<6{%ݮw,Jsj'O-爨`A%Z "DƸp } iJ4{?]LJLvT8֓bV0A$RH*l-fS>_F*T @ЕHBӍ,~lkwKم!4ZPilZ)|;SFKM峘K96XpleE1_J7Ei]qT6`Hyr?\+5t-jUnN`*5BT3w}cXǶ oN=1٥9fE8/V=͡dZK*1d9@jo {ڜ~6иVt>FT7 /"yp2k9^Cpzԇ/ qȖeGrh LF 0a|cc^_4}iYPhVsR/vBA'2>Q%E['npkl V|[ڦBiTՇ:DO,4(?v8Hg]rނ"bX)ɷ 3Ǽu{ioҥmDh/BTAdj1l`d0 P >] =wuJ hb7r v>Q*꧛cB<$ZCs pV z? mWAEX.W%F%o&RJշ_4/^&QHk˛O<&wYof2jq_<]:<y',6>M *ycX=cJI4Ukad'd29݄(Y0)~43`r\]++3WQ(W` /ng?g,Q@EG1Wa]ӓ~ֈDpj&1ǜ0uւl7c^OŢ|`ԇSbpX4d7@@<臡0@jE{3B;w)cWwW\chj험')9jLdoK?ᣇMF&EOH*xgW I /X_U.UIR$:>׭+V1͂Ko.[3W;݆`c(] PBv<*C^g 7 "X{ֺR/skW3 !%9>˪.e_g%,hy&YbMsٰzs>_}V u.zxdX!007^B哳VQ\Q1i>Mqk /2ϑS_L*Ws:rSrJ/ |SNtق;ߪZ @+R (fGq[MbxXVE8ߚW7eB~b?٢]:K3 ^s#6yXtc[ע"VT³Oڋyv CRp[93d zgQ"ar8}{OWsa!=,3 BaPW&c)ZУ9o qFTm;z/7-uQhpUXۆ*e*w^sDd 1qҍӻ x/^N"o5CB5-&F*"(:52j!`ǯ{_`>+A~[ vd{abLy`![/Ɗ+~> ^yS-U53'hg֊.*Aظ$H/Gy߄&Jjh]{9K Zu()4A` 8/?-'% 99Nty}6b)>R[*x| ƕxF{TYi3^&ݑ4&ch&10&"2;m#uܶ" wz 㪚~f (.Kfӥѓ'?BAX-.P%o0>CZ-rVKu|5+2T&/]eIzz{DZ) PO+ I姝kc*Ƨ.>"YskE;O0ZB d÷}1glRp[ž#ߦ49ݧs/.jVeUtC$78Tj0{bTFj5bW m_ j=dra wV7JEҾH(}GU$#xns1j)JB'}2O41Lk Dq]ͱ`a7] Jj$,?^0׶~ {y`ߎt0$No%k|4o#mݡpڨ6rFZ +Z @.ȹ-p'P[qKŰ7vbo(`BP;,C@NFQ$2B&rևyeU0Gۋڔ̊ IɠDbq:V}GGW(JO.x!H z8ݹͣi }5R%CJZ_BW^t5_ٛ㉿$#@M[>$Aa`{'Ii8!uv)9WGO9b jYD^g~q_)NI az}@Lů!f ;Jmp!kh8%ǟqk"bO߯j,v=kV3n@̾='ML.)wΐHjo!HH,:.>p%)~0QM(!`ȻXá(7۠F-}o-q/D@7tze5ljTS?0}+f|,N_{aǍ'鵙s'k^&+&&J<J3ѮBcJm П"鹆s>6f2 )IpDO+HB ʙē,2bTw_ sT"Q0֮>JphO3AH .b,,D6(9ac-dAȈ{UZ />,HܧaЍ~H(1.f>&]ԦXliTʗfoH3$ߓPHϪSVY Uf? c!%m:8 'cy3YSOGpd<0܉[@K'/6E|rnjbχf6Vg٨"!TG/X\!a FCV8oipW\X+Cͪ.DRGWvl/}[76.3t!Ip ;_R|zaw}Ui +bڱ!g F>U.辂vp?g_<{%;V}5̈́?a5ǣ 8PWޖxY3R8ᇋL *))NpxZp$w ij!٠ !Ur~ _8g>pWqD,km&ttDb?"2%Bq{5G\bf&ڋ !WGxF > ԰BL=!f[f<¸iz&](HA/XG8& VYW]8FOJ8-ҮpUx,n! Xzì qs=ax_}HѰ4@ 1=0]TT4}HۅIV0wyh2p <1V*H.%gX氁o*Pm_C<ƱZǴg6Ffdj?V. jXo` h0~M( fq)=OIYcq`>uHfӣffT(܎[:(<2  ^66C7l*qbt6_ ly}ZCJx(Lߡ ?pWCʇo噄vhۃ Bí ŏ$q~]j̡Sr_rJEg`_>#t*2/ӆ4<.^luPUsW8Ty.@|)jg4sd0_-xM9)ŒqD?%fi%], 8 .r|ҙcAo_O;c7Dѧָ9JsQY&"[G_vfZv='ߜd'4ٮJ&fJgܦ҆|fxC C2(:P'n[VqGAТ*r$tZP qz8W[zwp7ꊕ % "#:pSY)⃁M| 1p'̉͠bsksgwLF4TB:U6F̺ cՎw]{M?川_4_#8@Gh/Rˬ6kDNBG+]%'VxjB c"(k,Е;)g7(W ᅷCTo7*IVQ7~){@_Ju\P>u\~_EyZ! ym'R' M9q7XH/@5J|o1%F9-ϗS_Q`!#`ehJ*#H١י"~E*]I-F&)5:lEĸr.wlrIfű3j羗^WC2%t9>9ݗhY2ˢBw%C\4njv,gs.SFӢI}=+Y=3""KVF^鰆zx*nV4h;'XG7kRW F/d{9.r6'2 oW(NHzﳘQ*?svZ%Wy\2QtI_2XT(-EP=%=DFuV$1HQ{D >*KP.ڨ|DE^@*z\toPe`riZr- Lf[ DaY!=/V 7|Vr $;b2񴚿- ~5bǣJgmi$zF+T؎qv;`:q9<(xGyĠAs HċXn7Sy i *0kK/`T537xJ0.4_߿r+jC Jj5A1ԂS~MArj}?hP 6`JbĞ1]p!4-'z[^4ͰאEbSyŒPwڕᮚmj|7D fʠ,VCТ=s7MϢF~p}PpQfp8 PLcBE۩O1tӅ\0ɓPM!'dzT;>cjN9,1ޙP8}'= ߰E:Ak8;E2<9tֹ owa5nbX*{"[01 ;:ү8g\($I緹[gK^;OJ1;a,׽y3ŢMWR+3jyWz:aHY63%'=zAPL?H~ה0T=n{eVKX¥t"MGz3:ԞB_R2C>B{d۩ B qu>R~1G!7'Qc{kc\A[l,B ØySRhҚJlT f4'[}ͭOsZr}u"3س%Fn/ 9ݐZd,qWwBFk?-zqweUlXʏG5g@[׳nae|ګpȥ3C^n_^~i{d-VsJw؜U j<;y[Y՗S/.ֽi_<τv,ϿaGjˑ:Z4+B-[yG *OD.ΠF:wS7ѺT3͕Pf6LB`εo3,%5y۰k]FAxh{<_^z!0Oɉ_ܾzAKz ${[6WreC,+@d,{9ݸ<,|)·NڜQx^B\:y} KH2dAa|sg0-}>'}.wQSH)##N̚3GLH8"34rIC936\QW:Tf89}GPs\R*) hm/5eֲ<'t-1٤щ\Ux!̫o_rӄ׭JNC:qs) ]9 1Z| ?!_ \ >ֱZ+@Yh׋,SA0g!Bqw_sLD^ny8zjn)0\ /Z`~B2AУV,#Ǭ!n\K+PP5RGNX훕,dvԋ^zۖ UhJiI 7Rn>* g1sB%ShG>&,tCb/10|kѪCv ߼ΈedS)xnjȼ7"ʇܸ,D8z08uT¿b?to~]S+3d̐-F2}b1!QR'_stά=tzAt_+y+KA)SB5`6] ϳ6|d xqTlMQ =OW xydPL<)s>}G@Tp2{3q,-3 G9XBk$,;U2kZFԿ_te}POo>~7u?>.R:ajJѰD%w1&mDS{Tld@g}O20`Cnh/+ kLqr9^zJ; uf2-I%SάgSeȓZ/4-L ݑ.RZ_}=ȕbPSa1,fۣ 6NNʈЕDZ-VVЊHlnM ~!rb g[m\yc}THzeN=[We\-:<G zsTN`Ɂ~IB"@㒹r;x߳pP_jywD>nr<ݥ?KzhAxA%}UPP~i˜b9pA]m{ؓ L&~$ا惬Bq - IEpa+ml~uX jgzzY^5ah_|ߡh0:6!N|,=ڽ8`_ .1xH E.ˇ븏+;0lm|Ö́V>.@qcVa5WC 1ha &—vV/ʰwb/;_EH,XتS~ׇ@_󸞲s=)Nmd&i \psslwXd}~>*Gc1V%P-aU ,aׅRhkbjRZR /|2D.L^H1;'=]ae^s6Lj/R !K?B -7o3܌eMmU=DbJ]"~|W K1(u(W6ӁRPKC~pϗ-ʸ}s?z8KdS"Eȁ oG,2Q]7jf%b9Yaz9}|0 E hn?ӺJ9oyEY_ˁ~uS,6m|[A/U#?^|{c s~^/I5-|X(WHIQ]k@pX˨DwnXgpuL!D{Fqg`d@X = t{m)-ŠγT'uJyeǒ2<8t ~b{'(034cRmG6b`S/®bYb!sL']y]+J s&cMU}=L.yx-#^afRw"|U fb~Q 19+sʽֺR[~gž*@S!/ HR|ԥ#&E.߭X/O?uxc2VUBB:3Orؗ3+NbC9tso.v\˘;5fto_*+4$v~A-"%R =uoKtLNYב,q a8Bh+ "r[Sct R <ڧ͔{AY!C(N5]αTRhM}ndT%J֑$H6-VH/;N e`O(o߉Ij}zFnL?K +B}C8Rj6@X]tVWa%u%1wx~la=hY&/-OqxjaG4R")rWXt('e 4dƮV'8z%F/. {ʄ0ykN'2~rKp6oq%^Mm!&K 68>4 @Q"(ߕM}!S!'rҁ;Vڹ7s dg:4?/ؐ@lj L?>}56:ۜpeO߾&`HW-:ؖ+M%{MrʻH -g* _ Jxj=WZyruKY#H8՗U/0П"qS>Θ!FE[un0npS [JV;˜¦RabS!Cڛs>T "=ϗX(k;G! [׊"fK6x`*< %ϕz5q#]2x _xysE/r/U8G#ЫAАeyY !R$=㩖!>tCt .ge@ܜ5v"9BܧQ=x! 'BQXKK"2kSƔPՕݫ=h$?G#cF@rx?LGگpD©gKe4cb |.na${8x9Nyp\ja#Yp?{K{=Xa_ '*آvգ4RNMyʜ# 9}s3ڼZ &FV~ɃM#*!bE I y: ͱvMMiQ6(n2 u>'KwS2q,qYԉC>ܡattSMPޭwd cez4y>;o rm,K֊!Ea F@jѰYNa3ayly![@`#G~ݗ+EXTN&h&ɭ^Bu,gsdj~rN+kOcA U|&򵕷jx1K,in1 JxN"E(-B*Phm "*+MK h S/t­Ep;ĿLFfޤ&+0_dZT3ӕfG(9~?~hyo1l`iE8Z>d4,TWwp:;/T3m8EՊPM< MB=rqnq;<OeW/5P"[Uf:p9Ų^"I͗Neho=.J<;<ͽOsEzBc?(;xXYgb.jeoS=-zY?Pp?[1p/5~K/^T'Ā-OknjCa:$}}ԗT4yz\[LFi=ׁf/TN7L-9&K8M6 z*v&+m8CWBa ^ crI(jY3R~w'FvAϠ鳹OE/yl%b2Ng)rfm|lg@1x!kVēMC/ )8iNIS"x%B]mv`!gN4E[`GqSF:ϺM`}>·*JjgH:w-wⶤ"$~Hf Cb /  a܎}в3+>F^ :Z_;USIsױc!4m4E q|og4SoDbb䞎MXeeǷay E1rz' Q3#I;%E⩜1=r殷s׫ٳzzx/σԊ-ً*Br6}HL噛=Ez}O0T [SS=E~Vy#>&R|bX,*q f= ]]|h‚4]PV6S* { ?4ʾD?jl(hVU dFy(%%8ʻNS5xɒz6V{(^a Ha[Aw2ExB,148n-|N)˟}/ °FkgW&6hhQ%IoW|(({dMJ`fٺ%sUǙ-د%%eD#MACoڊ@!;cyG rtxEw0rʹo5[ZɼQm b^s,5& 6ewQW.8dYX&Y?;vb 23ėGw8B$\n*nk(^B '#j;oml -Ǘf} )sbrRgla9Mgq(aY~MjֻΞL Mɬٙh{8#vwCGTB2}[Q\2\ٍ}5=W,ur}l),u<Y[p41Z<22-=` x3L| kn&Mi+X>@xZoO˖ -֪>vH{$]&W\SF#wɳF|SJz$#!G 3[PgsuKch߲֔c|7Y^fo' b_4u].v r{j&8-#[*QlVu5 Z#gVZ1JCI2ƈ:ۤ뮵`@⨈Y)j |lpYv`+.qu{P?D< 6qڇDXSRۏ>T#?PTo@4]۽|sH@mcjf2˓^XSz*F܃c+>)<7: r2yg`xTE!}%Dh/5V⦰D&vI3GbsW% O(Ip kyӅp \oCZu]V-W ts:bo58к?O6ʍ;&y79.KcW ;)K-JT> BUhn煈OmKbϒu5(?x\13dUX:og.$#F{QC;>CLtM)Wи:ˎƉnXӠ!]1' #9YvyI\jGȚVD⾑cMkL) m ~!()S)%6jZH YGrwIɇf+zMD1auuww4g5=&`Fyp~z)/ҒGE5>.5v )I yb\ힻ33~Z) :_#y`V$Aegچ؀{ -1%WnȥG `1|Vr>!hH'HQj1  K.fQC qq[z`Ŭ?-fW-2 XG<v맋jV|#̰5XB\qǚD3i *4K NaImO#gz6sY,U >Gu^́kwӇ*ٶnmmht&k&:gQ QmubP(=-kHsB1ϖ5ڟO!(`9gźjr E_p͝?!#]T,Rk)L,{2J u˻?ܗb!z ڕH4V X8Hf{5vmflm[[k}?s=>K3JPyRݰstOW ot.{<olyY(K1?זиkAd$ɱB4AlE#vZ|i\nH_j:<.ϗyX5z7^4&/4yuy*f%vx=cm73dES7;nTؒbn JEvZG8Μ}g֚L'U½2FxcrG`[7k 1oyϺ#% ᮎ9l̀a:'DfJs" ыu^y|zaqDJ[Ѭ:>_W)*cE}[c.sn*~w=CsVr.,N6h{ V dph 0J~ 4&CHif:L/&x&hE4  r78(o!(2Ƚ抺olswک/E**U᷃*.:QS 8IJgyov-qQ֎9&Hv%:řضh~hSc) |{B*R=(Qs]H@fb}*X6Gw2\fr7E`~{"-w` ){z׆]kW2Q[b?JEgi:HF>m6CVy0w4ċ'D`] QdVr1uLXs?LL&Y]CBH^l`&Aaj=]xml2 w-Z;[ݧ:SƓk4٧-U|a@(p4%FIN]"ng[OP?3ny^z;`mM=l|lAG?b˷1o5_[ ܊IrAԤ Ϳ+/)gޤfDW :O"ol1g9ߘy2~jvi&t,X/Osޕ/TTYZe 9.dٶNn\nϊ0% -=&ϒ">CaUY(HIք㎬_;Yn[SVO(&Oi) +O'ddnt30C@ -Nk'cjD Q7^kÇ=HBպy)MpVPn ?fVgk852zk\?(]a,۸KO'`h<)=Fo(轅ToEY>y[m\3'5pj16xS+ 5H\gui#\V!|W#UΒ/`W =ҺP1ˢ쐅)~q]IeOD̈́~csMb.u^MޭX>j r~yD:Q.Zm>7$Yv* VXmO;QP rlz;DWlJ?*am,td.1rvK6FƩrECʓ)BHtPê^;FQZqn%MAKD$Iq7y[W_;w\)i MPhKnQx'pg1Y.kHJ@f3>A{ahI#WYEAlM)ZkCc㜧|z8؄%v1syp{Ie$rR)SEsʜ2y.mՐ,oiFQ<\=#rqyջvId\WG铜 3~U~|6{>@JWc>]8ӒoIbC{  fحן)Vjx/\vAf{{eNɶ',m+q]jzֹ'-4ʊ1N7ԧ$u WrxDjyRU, t` 31a?p߇mIXTxs>KF1,$ߐ["C<^)jdeuղmxIނi>$4"CZR%L"`D1 mNEEI`D(݄H^l;{ $LE:uv lYVʩQ~qX}i㕝d(Q,h\LL:QsF/#X4B+'rCSɻHӬPc!h9g{Ų@NQ]͆5JWRXZu^)T]OC%jCla qLc6 ^0 ،%蛭g .#6F:d}=O2('ȐL&K-'X8EOI<LjNyN_1&dhaxSNVq)dۢ;nQ3Ɨڇ=qGiv~Msy 2QҢ :~Y}-:! ~J?¾Β(¡tkw|hIiSm4inL||rUˮ\GD32  owU> XI T $xvMٳO#cNhIFۤJE;ˢḠD>4GIsSWw/1WLf33tJY6u UߢA<,Yf[ko` k%8/џ9CS4,h>AZ$aw#'4I >B6#kzjwܽ5CЭ_3 %Pv Z]+hfs&_# N!QF!Ut~g"&X__a> $G6H٤cy# }^5,x/5'9l3SzY\m6X~JR|pqLENˍS'yAL8 :-/GswjnY.kG:Ŧ%Ãuq8 dTic) CuPey:Oe-N.QKF8|5>Mv# Ѩ$%\ka,),]«5\X$|3. uc:lе}*nuAG٢E7Mb'$}&'Fhȑ>h#臧ԋbrAP'yW;QL9eE|Lnw QEh,0wB:atl^m%.$7k庁ò]/)|H2Y|]+|-zWչn9*^ 1)/C 9B\ #W)8}dmS4e4eDO;Be}"+΄e֤M#چDk־1R9`(lC)AU[ `ǹ~cBy&S![}zrnH7GJdLa/u!lNЋI;L^Z6S!1hۣY)x3'Π{Z#j2u!> --wBtdN+sZkl`IDѦ @VveɀaϕdG;X3c-d9=p>3C8bL^Omc. ]7n't+:O±®2?C# Ro*DPͅ``"Nlu 9]Ւ|-Q# lc{uB豋=ilAΟtk<0Uݸ fnܴ8Lo ,7} %H#)m@` VjJ(E%"!M#޴UYR*ls1YfX^j_7699n-g$œ$nY$Qs+*+ײoTk a56A۟#1b?\ɏGvycBQ#n;z P {Dc[Er׹]9b c?BZT .)5H o5|9-87 .όj[2/wMsj:R,Q.5brVJH.4~cSʜ=mm'}Ap ]2ώr/~s#<b 5p dHrd &94k~:B> Q.&ZTb5L~2S/Ld$&MsЦtaMhAOaQIkj 6j%e zA$z䄏0y-;(2xi Nb4HsVV'O2_/#iE}?]B$uz_~U2Q-,Mcm+6\v`TiJ𒼼䲃~5PT=U3ɠM곓R*I%I7QƑt0OC*PA(J?:`si@SP^PbC":ގU;KaTX;NUAf~ϣZ)+OSϽ+wF-G/X[N`satY _/9]Cܱ=C&x e0ip<-%_0ՇB@Nc'/N\gN|ZWQ]Ndi 9Č߫H$.2dJ*?? r)!Br rƒE=ujc}~ L(i3JdYM7@ծm"~Xo'$_J"D%ǪZ =Rl w9Y,Er]ʩ]5r")0  35 7Gr\Y**svV?B—qb׵mWd0kcA?9 VãL^va6fa]pg0kK,O4b.2L?QzG~k"7r@ |p[p iu}o%Fv(9vr=C|:>76^B[J!py'K]1> stream xڭxeT\۲5 ܃i ] Npt4ݸn n58A[>s_{j͚Uco:jU V )!Pۚ:4L Jv6@N 2 &p@H\\NAAAt:+la 0hk323;`ON|qۂ GF 6 ,AVY &6UGS@ l@s;(. %` 36`ڂaw@=3Govs?vG0U;fYUni~t#vfK{yMre 0{܏`P00 XP hawuG&6v01gCzimy/;>'O~ # +Sw*D/H_"Mܿk?<uo@ bMl6!ڠ'yc$ Rpqeހ]@@U0`nbأ?v-C@Zi#o>MK5w@ߙ?7;ߦTUk?GoZƐsrsX97@G?[8,Ox2 {N4&hm>*?!\@f vfVI aivN@jͼ26蘿5R_l5B_\g۟ۼjKe{2v73ob%hp?VZEx>nT bч)LJ=YbU$Q3n ~E}իޞS䎭ht&^qpWcEٝ3kPzlYg? MKH/), DW)pRT:F 6 5$IKGxnLٛSj,Llj^vD\K!ZxG@&y2⼬iwa;Yhbjt7>a{6P{\ G:ťi%!򡨳y_8Os ͣ\D'7-”4 `*U\AItr$\ɚ+; Dh)] GbTLD .q4( 'P?"a$uJJH}TޅlsGgyÕ؏C͂Bt1q-iߴ-"TaƵbeO-lJ*HL ~$T їjD0p84*UL-ꊕv7/K!@"zb3.ꦴ VG {xUOAzھA|0ĺ Qy3k=P6{̀|"Rw$D6NR_7 jȓLKC7b2(W*?&y}Zk] 薌#m>V #MJ҈sɑ|rtt~ܼ-todl

ȳދQcRLsݪ?AA3gen׋iftB DP<+<D,yf6i[-pxPb@YO@([7?wIѧk@->ea.B^߰c[Ҥt\qN,.v*#_/ŭ{-zk{rAQ(CZ_w ."3.d] 5}VtG-8/hF"+Ʌ6]ŸqR+2/!x^kkV\^vNA`~`ڲ1@c#WD'PC_ cR;:rC.KI 9%mL~PD|W9(C_$%U6`r{8:qaV8/rx}g F^/ݰ(cesQ}O`M}9戓~ 66CAQVvKکYgnOҏk&>  E_re0L\է%2^(z"W~{4/qUChՁ5S[/]gʰ[K،h5{O8Cdɸ1W)>P˜z9"Cr5-bȳa3ȕ H1vt\9 n'h\0:"kΩRgg 'Dǖ`$)%ȱuNvX@@//EX7W#(6} @T?B$XƚGKlkᑯP7##-^{}ÆƠ+AG ӡrvܤ%s mؠu)r5u~O:vҬy^Uӹsqk`i4sybP|^R$hڶXmUA'@e)WmQ^.яst~K=)"'dsk4'b՘IȩY&7 CSͨ`r(w9q2_(}8\Xjυa43;KDgVu?L%pB7"W*Ѯ??F# ZyelQ]1D !{ֆFQ'o_N WSz*.C}PJYyiH[wn ؁qm.KN)8bm5‚k(5T DVób}2Xφ)Umq0KgibwzF=w/#jn\gre L,AY(GZ|A'SQs2 6ԞeQ2ژ #f:۽ #8Ԣc6by fmrU׎'!W=t gZ  0c萕di60ʼۼ_+4q GOE2$RdM@HuFme:˲9ќ/o2pflh 1 bٛ#7}1kG!};O(P=ϔV[1pA}~/Lo ZhuX55*"uKӺo{z٠z9uDݱ{4İ`?uqy}Zw<P8CͶRX)/xťuwŇ+>/U\o~%{=1Iuӥ:tz_x`&mC2եVr,)&dN#[BBB: [iqD!{B傓܊j*7CJ{Ȓ75 Z00B(7_kl2ۦ]EU߂٢=M d)y iuv0W[#Y  6P#kvCÜALm@.dK3]zm힗ѥlҟa]YxzG}Ĕilm#^Sf`pvuPN҃AՖt钛A6E~W[`5%$YQ[k7> fzLeBi?U9 LW#Ud>;UK^H2I!z]D]x9޷+sXd3ޚLUⳗ}7 PWDk M+C]Tjۨ$`É3*sφ\:ٜs'Ƭ͂ D[#H)~!EIٕ;!?;4ϞsVtn2̝rd*<*` :%5μtb|x{]J[ U'GQ?1!BϝEԣ;).Y(&E;$eĒ yksirmErЇFew/vM\Ɯz4}T??D1O7_;"= 33}:y, p@?)|c=ϷP):Rr 4LG G͡7?It8ss2,͕)4hZhioLQ)>AWZ8qEsvX8N^)ė>,eVçSMH5&>nOۯEw ~7CqETGc[ `(Cl7>>sȧ}l50]lg^"˃}ݩnbaNrni}cZGð3l6g* \v`d\OO"ɧR]E|uُGYXfDŽ<ԽTW!Nrݖ?74B<}ЋVB⩎ I_ND.YMˊwxvaɞw# WlN8U7GpVnXC&[܎rr-V*3dikV=;.tzM9se(%7MœBl‘Ҋ8>J~5WH@ƒiapnc@FV-[zo ?+#Ai}[g &Gb{K0Gg%N0q1–|MX6Su9NfDqj!;>c><]r}+ ^]N}nY1:~h#0gEnYT4j̻ oMfRtR=}pG#Ø5|[i^@թ@2d̚*rx& ċzD . kYI]mb`>ޖpuۗ5s=+z)ÛE[%nD'}eϞÐZMB1wQ;Mm6!ڳ@z^umBJ~b"+o`.܉-i]D\˙vFSY69Y,1e}s.;5~)h4'rH6ؑlN㮗ׄlDޑBӼ!i)YKֺ5,oF`7YX"8c,rHcYs*ʭ^$!?)hZ[G߼;$$)zKVz4_־2AzhYvr!rJȼJ)L?@$OCjyXp])_Ϥ V +}$9H&1Q%0iVyϤt)80Ix|ǹѵ:8=<&\$9_G΄=pVz6Z,Qezj_1~ A383yHM GO%&ergQ-Xў@E;z["rبcUP<fi7VI~rJx݌Zs &)` F"qP\:f}+P$i+I͗m]x>ڟ*qmutFIZ )Rx)-:%*u O/+$[:m p2pևPV\!02ǽ`!̐aD~yFUAwzi\MLCgDK* 6fz&὎(<y ]>Ƭ 48_·J[Ȩk 9pӫݳ,jY%&A1H 5.ww9 Vn:껍'~XIF"ʨ4MXȆ ,۳0MEI#iuYԁC7&g. )K5 &b߸_s[Ni𪉷 2@")?_C7x;l7r380WQ pj7OB(CܨњN]J^]-+i?}QB9YH=RFX]4döS'F9&V8Z(#'ZD-3S\CR?yF$ br @U!v@([(%רM g~bB,LP vTԓY/u}I45~U#r+G9`[_ctK |Z DO7upKa?2pr"N?d=OWC!otk3&KWS ~f ҷ B!8X΀gz >!Nj.|x)V6Pï.h`k+穞ȶʍmC(VQGV]0X4™17u}$(R#vXOnԦ՚ \W̾,؆֠(_C닩$a @5Hdy~\3y_m-(ހT!FIsSF7?&Cc꺼62.KUm( Qg$*PY}>e zqw,z ըGQ w5<[0ŌdzLV'5g3zX7!Ԥ\~UO~~#e׋yAӞN-[V Ql`PwM^Qd\BC%HP6v:2&v"hƴ&eha}Y7a_Y3D#JDȼ:\T)ASo&u\˙)c)awz !a'hd5Oѫ6r[18s{c,V"*qў!J˾`WkCbdA8Z>?1!g~1Š{<#nWEd1ğtFBߔYL[\- cpF/nUsB8)'r<2W,5d49V}#6YыD*kqLbƉv!oSu;BF]'Ƭ~.)i?Xz-i&`RX>#IZG-G+!AS)\2sJ$?pg endstream endobj 247 0 obj << /Length1 1144 /Length2 6135 /Length3 0 /Length 6899 /Filter /FlateDecode >> stream xuUu\ۺ$fTRraQB@P)A.}s[yq+!m*H,jÜm\ P7 (jMiCáAJ(5D([oxCG75 (A qIQ$W % E@](72@aP;}+ e uTYJH/ 6s>XBBhT@;tFBnko.vt`(Z;%oW3S7My snOH0-ٹ!`ܠ7"s !H}z: Niv}\.@{k+9z"qv(7sK l@5~CkYQ0OHA,n.{m  +(gRTDHDB7NQ5+}! U;zB 6 69Ht㏛jPqƁ75{[#/hk8Vט`*0O. m1čv|qP]+7 :l"7"iC8 7F MۺP7nzBmI> mj0U { Fgn"$QpunmbFIʺÎfZ!!Z"#$1/QcRmӦsz'?+ l*=×34 UW1M#Bóퟐ'A4mMif'-ܕ;4VGY 2Ȇ]߇]՘' <:+j_GElF<n&'\|g> !Hͼ%jڈ2MX\"?VW3f$ mpq.~/,qfSmU"m6x_ew}ziHQ + r]XT|ZgRha?;2,6V^e@dB/}KҟQf7,_:VԝJJwM6{nβ\z gD5]̎%@sز$Tf:+= hB/'+_)08e_vV`o+~UpT4Ttѧka;77ɉ{@K^u͍2ꓷ\i/Ty|tRCIo4]w)_) T奓`. 6''gEdk=7flWYG)sґ^qmJA)nh aV~u/rTbCFQGg_t%)Ϙc`HE?gI[ltNXv2Z\./'s ΌpW aL$?˺gvDzЂw&$kaBԚbEKR xvAM*pm'~*-R3aêNI B!~A݆n1kϹgM 2ݏ4n~`d# | -Ri_ hm峘yUy+T~D_ԈJF0Z* vzRdt¸8XRtx"v幞?gHb0w=ݺ)ӥ{f83]8C8t]CPˣ׵65;nBd pjoUGlIyL:l|8Hy&'"2Kp"{B`|1_FGXΤ бG+1q(:"33A@4P=o;gfJGjץvF0y/,_.#y5\|GXĴ) v{}*Һݖ4 &vjl~-YQ×#G1<T`qz;w@pԘ#(Gi%Ȍ|-@)uGfgX@CMhK긖 KVL/6z~];Gu)a5|NS*ǻv{Jn }VC[q:(oN|>&{a;/رX1{MRU6C*$)feZk)ȃ }1/hXb}|dnoX nɿ7H:-f?1+lx҇Y=q*)S KƓjunߪ>)b-<~L`Ilf!':$_3XB4oJ:PUZ{,~p {#aeyG8;HeUUU="i¢f{*-Vy>.˫Sԅdxwԇ-=C2zg,p1̖"?|JXmmlo ҢjYj 62Oە1W](ڛm~]ytBOiYG&:& $*#z{ư뼴Sc3FLkgسmdT%_hea)Qsl쯽FǑR߳ǖ^Eݝལv/a7!Uh\o) Y} Z(L\H?(a'ԑ;ƇdX$!iWZ7;6Wz1,>Yrkhn1"21"mP|fV4*>#@[Ys31}4C'VWKS9F;GbYoY]ylO{(%̈5S NƥbS?եd|.. NW1$F40L}a=WԱ9@INR'+;0r󌘯4W~q&V xţ@~SuV(hF&w;Qr"&ACD +h>%(2Qp$;dzaieeoAy>ӍOqUzhiI*j|ӹ౛Zh m$"M Mե3:tr쑼I1bzA`7<]:>K_=-y[b TL@e|pMiKV&%P/ řм Y+/@zmM#*+#_^_vR-uZd~}8BIkȩRd V7l[EɡLlf@ݤCY=8"+^ 2/ ]:C%MJB^R.݃^eD}- 1x#^ s#kV5rgCQbC2 U_Di5 M1~EyVҟhNtzhR6}ˡSP5%x L~L :91:L'83¼pF*]qRslt#wRGi.Q^ImAo15PƇLxaZfɫ8[O8$ g,C,.eVxA*Ea&؋eyZ%͘cJy/*ּTi-!Z&c3,]ekC/WN=L9>-IP#!K84/͹"XCq8룞dqS#D份OѯqxJ?m^+le՘}WB(LӍDl65 \Fs`}&(ܼiъB4{$E-Kr),Q4ǫ{?|yٴ =keZ$/1C F"D&]0P)r4IP@~\@f0gD-cGӲgm].wWDwy}*}w gef٫íNK9ZEWYfW6?(0"_=D=}/MB` .*¼B}{4@/\a;kA>\FYۚ T]+4Yu`)}R=d&B5EZ9MC(C,s4Ckjh?}rb+*,Pd*({3Ad9YI90?XҜْ=OT[_+Vn\+GB`kfoxZp$5TK`%1wYL^n_v A A"9;߰{ ݛ|0v aJd$q8ʻ*r-?K! hReFKmTcPp͙@^wio=(欉&0Ȓ)XJC$xT*Yft/c$C.>Uo$+0? *Ņr.y؜Sj+UԷUYSPʣpISV R$c?QB"G)S_]A U`]eԘf rޚ*Q%'UĆP֭?Si8RRbcx+-9jMsβ'[%9^,Ar%˧n?XQ{)EF~ e*5YzA2بpxj˥Di@pGh#[yxnlvGN3'&B8`x"4W9NpzjeQ8 $u 9PL1B/+Zl=`]P ]%i%(_伃B}QZxw:/\j gr}݅.'ӹMዃX0" 3jq]:)W}Y/ u<&݇t>Oei$z)n9nr4v"t6}di\;ypC  i3@͂o AF_) di1EM(+H?%]xp@ K6+}m7Fؖsaޥb $NQdBWLLsN(t'˱.Ѭ9wÞ&76'e[qxrͬ4:X" TצWo)8Kqu3ATSHsCw@T)9Nt|?>V58U_s3hzXeq)FW!/X,;$D**o'Z 4 U孋_߿wܛU|Sź20Y,*nMV} 8U3} غσg,[wiɶTFd &O>X}s@eنP~3)ʹo q^եfFgCK$37_ulۘm;WM7H3fY:$d4ܶ'*57z)>;Xavٶ1hsOT@V 7Jv f:gȵZLgG{e_,@ F)ggm!oF6(Ty}*&O endstream endobj 249 0 obj << /Length1 1177 /Length2 3385 /Length3 0 /Length 4140 /Filter /FlateDecode >> stream xmSyJDLkks3⩻)O*G]A08'TiZD>{cw~x2 R ?R8<CGMG NA0 (#(` SacA> g|H>΍@C88Cq* =8HPwЃv%`soF%G@ߕ3r$"!W7(Y-eH==20A5 WgFALb\lRݟMIA&EEpb ,aF`eB8kq:"&qUϦg:oI=T_hcjŲ;̾HUWz3'rq9+ /8wƟr@SG@/Õͽ51l̾\jSqE9bP?sVɷ5/;p+m|A>rI0WoUe%3 j;*+vc^ g !wNNi2{yŊrBg.V$YhvSNVu(b Kv陫8W/Y|֞۫>ι t>WfhE(lTn9]iF#Qdf= ҜDX7 •1w[^xѤl ]AZDq ] P?1 0'/Y18O| knb{m\r _n4m|kv Ve/f+Ck_`kAegkg|{ $NQ;a!7<҃x'qIԄKNؿWJhAHy-<ejɾZ.ygoname,Z ~AuY/9aa2F*Eolm#hZcq2oL@ ,;2:vY&/uy~t2I<"1Iq0&f]F:v)QE̒HAz;rxX VݛeZdz_ }Ӫ_frEx2}Y(OGRvM"ƤYt.cؾȕU#+TUq1X|fлUh?^)k_u~ ɹpab6o!l_ug?uRFL gG>_voStb=T;MdSsJ}c6_|olh೬/""p1&\1X͵3=Q!ʊ)#E|_I:?1-;6PpQP*⚬og7?,-Z RJ,/^{ C$+bg݅ʂ$".pɋqZ#=u 4[,[jN`>'1ϐIp-N Jj1³x!FIM"*.+4\4-?,gb@RB &]S\TG_*b-9}c15ΐxbέ}^3?FV_w!fLijiIGXgNFiɪQ*K4|k?EWٮ2!閫!t! =1;}HHK{kzm̿X\}%3}uS:gՃ|VXM͇F[:KY{ߊ^reUJ"6Åp v )gq~ǧ 3FFi[qBeB#vMӼbHoAη[7a[kSo+K|;԰G5>rZJ-:; sK@zNyR;[GVEXLA 4r])7?yVzoӚ͵.&_o7A}lX[$+j+ 56]jH ƣ t u&;ۖ}>k\(b19owƘg#3 FbSr5 ls|مlciKؔ,-$:t062ewm)« SA.Pd_5#}v h{'!Ũ/d*{Ygs5{rBkRh ya<n]<.l#FI`J ( d4}!?QvGÌGqC쫵臗OCO<99;UkMsӵ,p{ʊB8/OګZˏbk-pV_miVh͂}!7ӥKi]J9Lo;!&[ mP}{FG~.04^wSӪ* 8n].S.%2b3\'4ߨגm"5lc~oԤNFZ5KYc"g#[/I:'i9?.*>[IZ%xDrcC0ة`pGh(hGbkBz'L%IBF Rz7RwZ %&lH%kt Qk>oBɞDl݊I2@^8H?0, CyD^~ZE琣'LEU=/s u89( : ZæCf ťg"M 4_܂l=Huq \CykH(=ƓXQ$: 2Ί{Ƌ$+B [ϲOs̪\Wnθڤk7O2]jfj?Iln,C_p}p4|Xnk endstream endobj 164 0 obj << /Type /ObjStm /N 100 /First 904 /Length 3587 /Filter /FlateDecode >> stream x[[s۶~ׯc; w8/uĹΥLjd4?HʗxNdƄX,o]P 8agpe;,2"PF,QrN&V7Xg:#,KIq862Jh˭ZzF͈`2#Jm!ÅDl Z Ű@Fa u 4cL{Au0sD2A ;)% d,@3h,@LÓ 36(qfaPóhBp,W=-d4@'@PD C7^K@dp dXYv JpvUeB@Č "\T=x7]x\6pHQ %)" .XMFd9%)4 ʱh9AN)4^oj> : #`I9x O9X1B^汱.+  C l N 4v Pm'Ozכ7eѣxZt0AzdPT~z0)@qGN ycBNquO+d:(pg<GOw~BG eCGN_!?}V LƳteSJ A> _N. NJG]S36c13@Y1?jw=,>ժY4K3 ,[MYj~!'wu6n;p{9>:p8p8/`uxgGx{px@9P _C30B \kị>ò}M.0像[Ez88PjGgm<3u+w=lc[M#dU4܂w:|WJZ`]" uE[Ce["| {y%*#cNA+xW;i:56D N] N YײB^i_~F2|jvKX&B"jei5'ѭd#kHK 5{[TgYjGׇO#Y:0%KR*9vK'kC9?l n4Z'BG/Mpio߲G|bP;XB[cCخ~#k%R1*&\Q(Qɣ8"(8-@ԲВՆ_67boZYV(sԯHiMg@񮯗Y%d~ͳX:4-ioChBH3HjX`F@\a"NTLeX_+|oaò гiRuPPLe H Ho@DA2Šz/+@B&@ҀD . i7$/j#YrzeJ9in!NS 3EC?$!V/^Aja:= /$Nͩ}Z2=ϫcFķ?|+ֺ^}I~|WTfZNKW5y?8W/quT^ch4/+B~dK-<'ȃnW|߁vn~^^AQۣ|4l/Ga=z<-Ѳ-vʀ|/6~t= ݧOkJ1}KNsWb2>3zO$|,bZ'8A9*ǐ^_/׃f^Ћ^ "^}*tH鈎tLqAKZBzC{"?υao@ތfD?͊ʿ14+وNhEz0L5BQ^])^MN*Ť~/+]L]CYH'S8<|Ë)> A`x[a!XAc >,̏ggrFPvwhO/xζv%ْx2QI0Q͙]lʼ/6s,-]!הk"QZYz1V;l"iNf>-L?:mz9];|LUă[;SEMٰm]%,ya#̦r$~zqٻج%cƎVBFucsK{ڍw~9cff><N^ޛƄZ0!u+Gůojx}65FG?%Uah/.DYeC*R1B߇Ru1YInmV]xwwGzUh)xtX Zo%Weu)X7B'!:WV9|<#o|jw<|UZo``:'Jz0 7I~%+/Ay>_Ë7-*r"܁&1S`6+ Olx搞@֓*ObOzŭ^Յ8 d)!Fߗx8 I$h4T4ы8lqG ;+nD1$dI&!Uܬ[1 /Rn 7M\DewRHQ&!P9ZU_HA?{?TSpD<8:U?bmk>3: ):F=YՓ![-%ŹMbiQ5QM C͢u-܄JS[6aQKg|Vxv4Sep&18 5 *[5{+ [evv@W'fqy1<)+EqaFwz!xL8eZcį/꯶oqOMGw#DZxqbxmQ,2>|L>Y[z6ADWE#qCïX}!UsAѿnCHrfR|&ml5]k 2-919S˱b=uSS&udLLN1K R#R1lVɖ= E#)ݼkl0Th#>Xtەy X5ojeiΖIS(a#|L endstream endobj 266 0 obj << /Author()/Title(An Introduction to the GenomicRanges Package)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.16)/Keywords() /CreationDate (D:20171030190234-04'00') /ModDate (D:20171030190234-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian) kpathsea version 6.2.1) >> endobj 253 0 obj << /Type /ObjStm /N 13 /First 105 /Length 525 /Filter /FlateDecode >> stream xڥMo0 <6a ( m[;lk@ lJJ1`'))K<-P#+i%xoi Po@+Ekк4AX m]I@G,]G)f%~zuB/.sslW[EٱϚ@q31IL$@!˿uH;=,,_0)$I)IAS2"A-MY0.UKiAAjG:HbHHѤt=,ǧeH qOP -F)6'40RJE ;D4{~fNbNؼ"rU>Q9n^ON'8ۻC=siʰ*Tؚ'7᥂Iy8_a-5|4(N2$eH&cvUl(a7ۿv--0o^]86~? <302F4DFC73B0BE16EC779B0F2CDB27A4>] /Length 674 /Filter /FlateDecode >> stream x%;LTQgTTTA'>y "-,‚helldžD;[,434_{ݝ3̒1DL q[V~zwU`575il-XnѻQrxܤ6QKܠ,uJr F;eFLRn;(Հ3U[A+^Y]nds5V5vQ'aYSn#ɚs6!kd<_ppӠt1p:4`hn@npm͜6dHyU,΂^wHnO㌤ niґCn-oSb[[7ka(*[G[aI=Lv+R(E/ӗ2 r+f]=JB(uP= &PX+<Ψr{)Qv=)hFu{.ݞSo7AۋZh+Z^Vhs[lP8 kq/| 1\(p\2q3:>kNTtՐ}\쌧EYYdHLx-r˸_2qe /cW2Yf\UzO?ϯc endstream endobj startxref 188538 %%EOF GenomicRanges/inst/doc/Ten_things_slides.R0000644000175400017540000001645613175727644021667 0ustar00biocbuildbiocbuild### R code from vignette source 'Ten_things_slides.Rnw' ### Encoding: UTF-8 ################################################### ### code chunk number 1: setup ################################################### options(width=80) library(GenomicRanges) library(Biostrings) library(Rsamtools) library(BSgenome) library(hgu95av2probe) example(GRangesList) gr <- GRanges(Rle(c("chr2", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(1:10, width=10:1, names=head(letters, 10)), Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10)) ir <- IRanges(c(11:13, 2, 7:6), width=3) mcols(ir) <- DataFrame(id=letters[1:6], score=3:-2) x <- GRanges(c("chr1:1-1000", "chr2:2000-3000"), score=c(0.45, 0.1), a1=c(5L, 7L), a2=c(6, 8)) mcols(x)$score[2] <- NA y <- GRanges(c("chr2:150-151", "chr1:1-10", "chr2:2000-3000"), score=c(0.7, 0.82, 0.1), b1=c(0L, 5L, 1L), b2=c(1, -2, 1)) ################################################### ### code chunk number 2: inner_outer_mcols ################################################### mcols(grl)$id <- paste0("ID", seq_along(grl)) grl ################################################### ### code chunk number 3: inner_outer_mcols ################################################### mcols(grl) # outer mcols mcols(unlist(grl, use.names=FALSE)) # inner mcols ################################################### ### code chunk number 4: Ten_things_slides.Rnw:84-85 ################################################### gr ################################################### ### code chunk number 5: Ten_things_slides.Rnw:95-96 ################################################### invertStrand(gr) ################################################### ### code chunk number 6: Ten_things_slides.Rnw:106-107 ################################################### grl ################################################### ### code chunk number 7: Ten_things_slides.Rnw:117-118 ################################################### invertStrand(grl) ################################################### ### code chunk number 8: Ten_things_slides.Rnw:131-135 ################################################### cvg <- Rle(c(0L, 2L, 5L, 1L, 0L), c(10, 6, 3, 4, 15)) cvg i <- IRanges(c(16, 19, 9), width=5, names=letters[1:3]) i ################################################### ### code chunk number 9: Ten_things_slides.Rnw:143-144 ################################################### extractList(cvg, i) ################################################### ### code chunk number 10: Ten_things_slides.Rnw:154-157 ################################################### i <- IntegerList(c(25:20), NULL, seq(from=2, to=length(cvg), by=2)) i extractList(cvg, i) ################################################### ### code chunk number 11: Ten_things_slides.Rnw:168-171 ################################################### ir ir2 <- reduce(ir, with.revmap=TRUE) ir2 ################################################### ### code chunk number 12: Ten_things_slides.Rnw:180-186 ################################################### revmap <- mcols(ir2)$revmap extractList(mcols(ir)$id, revmap) extractList(mcols(ir)$score, revmap) mcols(ir2) <- DataFrame(id=extractList(mcols(ir)$id, revmap), score=extractList(mcols(ir)$score, revmap)) ir2 ################################################### ### code chunk number 13: Ten_things_slides.Rnw:199-202 ################################################### sliding_query <- IRanges(1:6, width=0) sliding_query countOverlaps(sliding_query, IRanges(3, 4)) ################################################### ### code chunk number 14: Ten_things_slides.Rnw:209-210 ################################################### countOverlaps(sliding_query, IRanges(3, 4), minoverlap=0) ################################################### ### code chunk number 15: Ten_things_slides.Rnw:223-227 ################################################### library(Biostrings) library(hgu95av2probe) probes <- DNAStringSet(hgu95av2probe) probes ################################################### ### code chunk number 16: Ten_things_slides.Rnw:236-237 ################################################### replaceAt(probes, at=IRanges(3, 4), value="-++-") ################################################### ### code chunk number 17: Ten_things_slides.Rnw:246-247 ################################################### replaceAt(probes, at=IRanges(3, 4), value="") ################################################### ### code chunk number 18: Ten_things_slides.Rnw:256-257 ################################################### replaceAt(probes, at=IRanges(4, 3), value="-++-") ################################################### ### code chunk number 19: Ten_things_slides.Rnw:267-269 ################################################### midx <- vmatchPattern("VCGTT", probes, fixed=FALSE) replaceAt(probes, at=midx, value="-++-") ################################################### ### code chunk number 20: GRanges_as_a_subscript_1 ################################################### cvg <- RleList(chr1=101:120, chr2=2:-8, chr3=31:40) gr ################################################### ### code chunk number 21: GRanges_as_a_subscript_2 ################################################### cvg[gr] ################################################### ### code chunk number 22: Ten_things_slides.Rnw:304-310 ################################################### library(BSgenome.Mmusculus.UCSC.mm10) genome <- BSgenome.Mmusculus.UCSC.mm10 library(TxDb.Mmusculus.UCSC.mm10.knownGene) txdb <- TxDb.Mmusculus.UCSC.mm10.knownGene ex <- exons(txdb, columns=c("exon_id", "tx_name", "gene_id")) v <- Views(genome, ex) ################################################### ### code chunk number 23: Ten_things_slides.Rnw:319-320 ################################################### v ################################################### ### code chunk number 24: Ten_things_slides.Rnw:329-331 ################################################### af <- alphabetFrequency(v, baseOnly=TRUE) head(af) ################################################### ### code chunk number 25: Ten_things_slides.Rnw:341-351 ################################################### library(Rsamtools) library(RNAseqData.HNRNPC.bam.chr14) fl <- RNAseqData.HNRNPC.bam.chr14_BAMFILES[1] sbp <- ScanBamParam(which=GRanges("chr14", IRanges(1, 53674770))) pp <- PileupParam(distinguish_nucleotides=FALSE, distinguish_strands=FALSE, min_mapq=13, min_base_quality=10, min_nucleotide_depth=4) res <- pileup(fl, scanBamParam=sbp, pileupParam=pp) ################################################### ### code chunk number 26: Ten_things_slides.Rnw:359-361 ################################################### dim(res) head(res) ################################################### ### code chunk number 27: Ten_things_slides.Rnw:372-374 ################################################### x y ################################################### ### code chunk number 28: Ten_things_slides.Rnw:384-385 ################################################### merge(x, y) ################################################### ### code chunk number 29: Ten_things_slides.Rnw:395-396 ################################################### merge(x, y, all=TRUE) GenomicRanges/inst/doc/Ten_things_slides.Rnw0000644000175400017540000002153213175713746022221 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{4. Ten Things You Didn't Know (slides from BioC 2016)} %\VignetteDepends{GenomicRanges, Biostrings, Rsamtools, BSgenome, hgu95av2probe} \SweaveOpts{keep.source=TRUE, eps=FALSE, width=9, height=3} \documentclass[9pt]{beamer} \usepackage{slides} \renewcommand\Rclass[1]{{\texttt{#1}\index{#1 (class)}}} \title{10 things (maybe) you didn't know about GenomicRanges, Biostrings, and Rsamtools} \author{Herv\'e Pag\`es\\ \href{mailto:hpages@fredhutch.org}{hpages@fredhutch.org}} \date{June 2016} \begin{document} <>= options(width=80) library(GenomicRanges) library(Biostrings) library(Rsamtools) library(BSgenome) library(hgu95av2probe) example(GRangesList) gr <- GRanges(Rle(c("chr2", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(1:10, width=10:1, names=head(letters, 10)), Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10)) ir <- IRanges(c(11:13, 2, 7:6), width=3) mcols(ir) <- DataFrame(id=letters[1:6], score=3:-2) x <- GRanges(c("chr1:1-1000", "chr2:2000-3000"), score=c(0.45, 0.1), a1=c(5L, 7L), a2=c(6, 8)) mcols(x)$score[2] <- NA y <- GRanges(c("chr2:150-151", "chr1:1-10", "chr2:2000-3000"), score=c(0.7, 0.82, 0.1), b1=c(0L, 5L, 1L), b2=c(1, -2, 1)) @ \maketitle %\frame{\tableofcontents} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{1. {\it Inner} vs {\it outer} metadata columns} \begin{exampleblock}{} {\small <>= mcols(grl)$id <- paste0("ID", seq_along(grl)) grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{1. {\it Inner} vs {\it outer} metadata columns} \begin{exampleblock}{} {\small <>= mcols(grl) # outer mcols mcols(unlist(grl, use.names=FALSE)) # inner mcols @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{2. invertStrand()} Works out-of-the-box on any object that has a strand() getter and setter ==> no need to implement specific methods. \begin{exampleblock}{} {\small <<>>= gr @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{2. invertStrand()} \begin{exampleblock}{} {\small <<>>= invertStrand(gr) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{2. invertStrand()} \begin{exampleblock}{} {\small <<>>= grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{2. invertStrand()} \begin{exampleblock}{} {\small <<>>= invertStrand(grl) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{3. extractList()} Extract groups of elements from a vector-like object and return them in a list-like object. \begin{exampleblock}{} <<>>= cvg <- Rle(c(0L, 2L, 5L, 1L, 0L), c(10, 6, 3, 4, 15)) cvg i <- IRanges(c(16, 19, 9), width=5, names=letters[1:3]) i @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{3. extractList()} \begin{exampleblock}{} <<>>= extractList(cvg, i) @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{3. extractList()} \begin{exampleblock}{} \Rcode{i} can be an IntegerList object: {\small <<>>= i <- IntegerList(c(25:20), NULL, seq(from=2, to=length(cvg), by=2)) i extractList(cvg, i) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{4. 'with.revmap' arg for reduce() and (now) disjoin()} \begin{exampleblock}{} <<>>= ir ir2 <- reduce(ir, with.revmap=TRUE) ir2 @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{4. 'with.revmap' arg for reduce() and disjoin()} \begin{exampleblock}{} {\small <<>>= revmap <- mcols(ir2)$revmap extractList(mcols(ir)$id, revmap) extractList(mcols(ir)$score, revmap) mcols(ir2) <- DataFrame(id=extractList(mcols(ir)$id, revmap), score=extractList(mcols(ir)$score, revmap)) ir2 @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{5. Zero-width ranges} \Rcode{findOverlaps}/\Rcode{countOverlaps} support zero-width ranges. \begin{exampleblock}{} {\small <<>>= sliding_query <- IRanges(1:6, width=0) sliding_query countOverlaps(sliding_query, IRanges(3, 4)) @ } \end{exampleblock} But you have to specify \Rcode{minoverlap=0} for this to work (default is 1). \begin{exampleblock}{} {\small <<>>= countOverlaps(sliding_query, IRanges(3, 4), minoverlap=0) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} Perform multiple substitutions at arbitrary positions in a set of sequences. \begin{exampleblock}{} <<>>= library(Biostrings) library(hgu95av2probe) probes <- DNAStringSet(hgu95av2probe) probes @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} Replace 3rd and 4th nucleotides by pattern \Rcode{-++-}. \begin{exampleblock}{} <<>>= replaceAt(probes, at=IRanges(3, 4), value="-++-") @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} If supplied pattern is empty, then performs deletions. \begin{exampleblock}{} <<>>= replaceAt(probes, at=IRanges(3, 4), value="") @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} If \Rcode{at} is a zero-with range, then performs insertions. \begin{exampleblock}{} <<>>= replaceAt(probes, at=IRanges(4, 3), value="-++-") @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} Use it in combination with \Rcode{vmatchPattern} to replace all the occurences of a given pattern with another pattern: \begin{exampleblock}{} <<>>= midx <- vmatchPattern("VCGTT", probes, fixed=FALSE) replaceAt(probes, at=midx, value="-++-") @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{7. GRanges as a subscript} \begin{exampleblock}{} {\small <>= cvg <- RleList(chr1=101:120, chr2=2:-8, chr3=31:40) gr @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{7. GRanges as a subscript} \begin{exampleblock}{} {\scriptsize <>= cvg[gr] @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{8. BSgenomeViews objects} \begin{exampleblock}{} <<>>= library(BSgenome.Mmusculus.UCSC.mm10) genome <- BSgenome.Mmusculus.UCSC.mm10 library(TxDb.Mmusculus.UCSC.mm10.knownGene) txdb <- TxDb.Mmusculus.UCSC.mm10.knownGene ex <- exons(txdb, columns=c("exon_id", "tx_name", "gene_id")) v <- Views(genome, ex) @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{8. BSgenomeViews objects} \begin{exampleblock}{} {\scriptsize <<>>= v @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{8. BSgenomeViews objects} \begin{exampleblock}{} <<>>= af <- alphabetFrequency(v, baseOnly=TRUE) head(af) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{9. Pile-up statistics on a BAM file with Rsamtools::pileup()} \begin{exampleblock}{} <<>>= library(Rsamtools) library(RNAseqData.HNRNPC.bam.chr14) fl <- RNAseqData.HNRNPC.bam.chr14_BAMFILES[1] sbp <- ScanBamParam(which=GRanges("chr14", IRanges(1, 53674770))) pp <- PileupParam(distinguish_nucleotides=FALSE, distinguish_strands=FALSE, min_mapq=13, min_base_quality=10, min_nucleotide_depth=4) res <- pileup(fl, scanBamParam=sbp, pileupParam=pp) @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{9. Pile-up statistics on a BAM file with Rsamtools::pileup()} \begin{exampleblock}{} <<>>= dim(res) head(res) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{10. Merging 2 GRanges objects (added this week)} \begin{exampleblock}{} {\small <<>>= x y @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{10. Merging 2 GRanges objects} \begin{exampleblock}{} {\small <<>>= merge(x, y) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{10. Merging 2 GRanges objects} \begin{exampleblock}{} {\small <<>>= merge(x, y, all=TRUE) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document} GenomicRanges/inst/doc/Ten_things_slides.pdf0000644000175400017540000041612113175727644022230 0ustar00biocbuildbiocbuild%PDF-1.5 % 35 0 obj << /Length 912 /Filter /FlateDecode >> stream xWKO1W̭1} =U ;cKZPU(R#zNDC/,d,2u#C(.~9"MCdkoQNoIڒsbQt10o.8@Un )7%H[4X=б-%ZbYY\+/>5$+dtKH+E:^|[,!6aٶd/5_+}aη՟uHSpHtI} } |uI8KBϺ=R7cs"UaUU L%/3>ц(>}w:S''Mw)/%$x3~: Dkݬ|bq͈j>J+I^*41wߎo.gaΖs:_Yd ̲2f$e=,eׯǟVÄ6Z9zdx%3"GZ_Ry)=wa^fYmSȘs\Hd)=6DZؼgsX0{ԫ%"I[so9]y-XZ-ֱ~k;}#=An۾~6 endstream endobj 66 0 obj << /Length 1414 /Filter /FlateDecode >> stream xXKo7WEk{ic$ŲojPBcIn.>v%c;uS.<>d挳kp2LֲҲuf[BY_ HsOIYǹ C# `RJyT]͚蚍nq@R5s{X}(TVI` 섍NPi?^v(?T{[6/2 (3&lEpD=Lݏߊ83Rh+_+!ʁHz1%d @ 9D8(.US2OxA 2(rMf6k sO>z dtCمb8I+SetbNJ{1wv&ki$iQX|6+S¿ FQ?D^kxyn=2''  Bj:+%*qLGҐH)z\-od#͛Ed7[4";&T 9-na"(aI?M伆{԰ެ w{C(]mY' VmP1nDG]lzY.c^ <1Do/Nj20,-R[B f| JשvCX\:II^~Fkt!#kpLKc&K-ܧ1E{<>|@ n%Uؘp>ʆC mޮC!:Z/͡wOރU%I1bbZ |J8S|u nfl9gw䓔-ML𰌹OG;k?Lk t+`W%ܑ^%A!NT)TÁ-87^ka/t[)-yeg;dyETJqbRDwe/eW^l%&kvj'Goךl-9 ׇB]UtC (@Zuٳ EĹ"?OvyNZF endstream endobj 94 0 obj << /Length 1147 /Filter /FlateDecode >> stream xWYo7~ׯ  2I b[om%k\ڕ4q $C]2>MNHLYɽ2L:AZ>g=s0,4l}vI'c\ֳ>1mQN( >0W0ŵw&lf#"7-\ @RL" Ȟc69&NYۢ}Q!x֡4_W{ ՞|žw58<8(b,x{4#IcS(.49FB4y1U B)cFH@ʢ'PL Yhc@D@n!PNQeX}ЁϽ" هRhKipxJREx2)`?^LorĈʋXkXĂI#%HMqJjVRˣH(󢤭P% Zty[(jfJˮ޽S^$.<;XSY%mgbb_ƻ}A o"Hme_Y/sz-g@,9M*)D?u+bO.KSSe@+9`O} _4j.Zղy1࠼'o"67B3i479>{͑C Ku$3P;:J˵ݨHYݣ0%JBvt8"fRrڮqFR:2-j|.;a8>ϕƂI+X\Hpv FЁ(2&OzIɌf`GLr(< IRgja$Zl+l1*0KeL]"# f $U[J#R^,s9}HI:"!.kÒd_Jٳz.nbwP-Ӗ#Ym-Jp}4\: bFև 0NX΅X Ė09T{9"/f<&aE㙛eFyl>+e/Syʸ֭QͧRdo% !.IaRspHZck-W_=3"R)H]M".2i!MFʊ|@T_8|MRGU endstream endobj 119 0 obj << /Length 1440 /Filter /FlateDecode >> stream xَG}mn<$ (w<f|zMH||bBHY]uwR,B;mv.gGLނyʊR&\y !1a&rҺ ݚE>gGHD VV(#%@B!HK8y&ٷAXi%&FZ 0hX?~QVk@F#E@ oep`ttu j  Tz]%Hd;"N,Jzzop6FL-?;!S)3$gF?"tsHB{ 2]nɗ_~R,>+`^_`RZ #*/:'E".(42:B27Rq w S<%]~IUhТ]`Eđ+rz.0/Fd[g\)Qisyb3Xa|wpYEawu~i_{! @=\.'SNq؁'WjU#!%ϧՃnK6`Cb3e(%1A\.04BYZr&^T;nѣFpoq]hr+ie`}&8PE Y3;3pnl6N?]l$V5u?eZcP374& RQYRe=RC p ao:X$֘O(w6yJ1Bo.0V)z e:ZΙQY:t>qNUwsMP}Դ"QY#͔+@Szm/g ':kFwUv>nn&8NO8&< "A:5ziUDWe{^#_l޳Uh!IMW[بF/Ak_vTͬ7JFM.9-Sn_JJB^\ i>h}^;Ԙֲ@;0|0[LH_"@jB Ce&o+=ެ>7ޗ @ ߞ 4$jbe> stream xWKo7WB,o-ZYAȲKew]IۨAj@$g8ϏZ%l"fp~@`JaIҲLay0ҰfcZֳ}:>Sfx3Sr.F9~%TZ! fqga[}{joQ^G(kKX6pa)&ܬRbj*!^he*|y .N|@Bw5©atӻ@ jp!JJwEs1|baƻz~ekA}ir 6TwVY%].lϩ @(+9̪J0jI 4Դzrvlo4 .$^r`7xL xv]5O[UB'|[aD`z}X{ |7ϕƣv&PuBn7vod`r6O^hqD +52"fsy`-/lFV6xD {\袛H<&p-r/);OĵLӚiNI5EIg#i>lɚle o?P]T>;ac7QGq C7 ZD8pۢ+AJ0۝^rJrԢދj98Ws):h<'Otz?I=ϖ8`O.WR|:z:Sy;96CYhvIX8q*ocQE֢3ZX-xBQ8Eq) + + + +GXzWetEs}۽잝L6^ҩcJ`7-GI1 &Iju$rm0s$ɮ#C{ʏȰV~$F‘ $! $E`ʑZ#"Mk#5.DDGu "ihhzRZTOb[rޑ':zEC;GXXk?0GGbaXN]OlwHj_0㛝̭"LdžK#K1$T?h t4~a,7nfNrC&̌iuhs/'6mYXA`PX۞/0OZXtM/޼7WvxƹϿuseO{U}$J (xB^X.'Uo/NttG4}a:R `^@OP#^M-m!y6^Wnx6^7A4A%(JP(AQDE%hA 5 hF5@jƔbC{)U=Q\?/D5M5I2$bRʐ2$ef[dEɊ%+JV(YQE)v p{B5x_ @51Pj|9TTcCհCauCh'/ﴴt[L/f1Swe=cيg+^7{jjZ݁1 >xO؇}} c`>a6Om( \v!#S(CIl=IbQ[ϒz$'<Jl=QbGJ*W> stream xWKo7W>4hXM]d\Krs un5`rf`s&؛#q-")+WI'9H6-b=úH6svMƤg]}C&DL*U0LqkVGj6!a2ϥ " N*T)$.asvƎHk5A'/\ECP!˲FqBd8ˁ `qqeaR?1 sܣ!=`LQ\v'1P8t#ϭJWȜ8QgWiܸ9} 2P˧wd+ +sV:5P { "Mfi'_Hj?I}}Ej?^/7J>G(Z. lRRo[)1@mUe ^he _YCg#MAzBCрV0hM"#ͬ^( .zΑﷃFI2\xw`qK[|7"bb_Ƈ}A o+k8Me_/sz-/g@,9M&!Db$pGʁSt@((*9a >qjI_DthcyJ#G~xqRSIba4M+ɏkU8j6KM:8~w1?d> stream xWr7+paT GC\*._DS\E%nl3F(\Uq4XȌ0r>bG-C #& ʅ!ۖLG}rMG M3r,2sqсd0`)H%r!{d$w| dC3[tVJ"@3^ 2N*w MEa{DvQt$JL 74v [ s| EN4Ra:)h9%bHnqp9O#G TEedLA?6 N:d6؇=D,zPv鸔N6`29g;?,[agɼB'aQطW$S FQ?DY 0nxT" O PqFHPed7cJ"/l!H8\[^CG7%,)afRimӥw x5$ISx ;ܚo2 2>nXY϶=ޔ_\wkAt}9B)tMېOtΊ(SV瀳.%nQ8>`ǬD?%n#hf步N~t5$9BkЊj TJj~«_i_F |~cņzXG |2J+Ktf)~YvTݓG: `RwFK+\wCWk:ozi.Pa(Q"_347&Z.f8lBAa'Vm1YB_DeG>`[.*4"dcL;LjK Jp`b{# Fjl!0%a&x{_g1_BΌNa08Gؠ|YKiq[j7Akᩁ]Ota=^Vonq!gUM$ f ItU(I 0(E&ED疀8,]^G&XF7H>׋;dvޯ3\xR `] a{<=D&'`ߧ*OW2zq7L\su^CFٖ}lvYd0m4v:dQξ5w ɚ_pk7x68d[oUl, [*Ehnf{`'n=^O} ۵$ endstream endobj 222 0 obj << /Length 1293 /Filter /FlateDecode >> stream xWKoG WQy?$q ?K%/9q8Tp8$Hά$2c;#xFIM C)g#嚤 du2eI/҈s0`)H%zvGf{d$w|$rG3[tVJ"@3Ȟc2;FMHzyq`SQ?TyY52I58Vw,*fo$ Ji VzDMg7bIE s$b8eQB:32 b`qPM*;44=xR N6`2j䘳&OV ,.fmOHj_n-7J>'( k /1όG̒IüA q3*,pLI]8#[I_8\[^y<S&BUS;_5IҔ9`FB0Yp a؃g me =ޗ_zׂ}9B)ܒ0a_nCfP҅ib*)+u5[e7{! P5s]'.8xQzɌ&iͪÐ:opWq@'7u}Xa RpLjћM:n/x a2M440c#AG+_&Up(13. _~2 vS-%M|lmSCZ\9ᚼ~yOZeܳaX7a/r2/uTͺT1"HK)!R0O -v a|DkE,82ѥ>WgElKeoB>{, S={JVsr endstream endobj 248 0 obj << /Length 966 /Filter /FlateDecode >> stream xWKoT; ϯ.Z !6m $NLO)Y#$q(q"xP;5` XD 㵌 ő8^\2e'i'.NĮh9g壨іdI4P 1$'1q8KbE&E'> 29QjT41#4r8VO%- Ɨ1TLmJ)5D6(9ev&45Ml,4c25G^Ì(X#uMD薺̡*OU^9E.rtOrqӝ5Ӭ9`)A .iN=&QVzUӂi"j)4*Zn7`,6`H[ZAq;evV:bJg`;؇XSbyyV|Xw2{K✛ u_A.is\iȇEgjQ0wH%aG$'yo&UYܸtpiB2>a`i|~c+w4 ;tBGFNF/rD3,G3[l&k(eȐBA'G?3pZA6֔t\>rX Y{Pa.뼝UG!Wtj> stream x[Mo6W̱H!9$#@>ACzӦoNtaX!`Ey|3-K@,8DX)6;.#I%-6ި@-5L*EILjөٜL#F]0+IH46. WȘ$DcAG9JRSDAMM"7ɁbkL1eHXPΉbU8g)4ͅbS)Q ! OjkbJUBa"VI94DYbX33T)gSt1&tAiC[& ƹ$X䂑,l 5.GJ*BT"rU$c` _K*"l&$AQdbdZWm *"f%R B2jh(P I@eI@FPFpy+6 $DY*dn +PX+N["Q@1Ց0b@j zU&zq G V/b&EPHbBȈlq'aKX!`E; hv''KVm7};tz ֛͋6?O/Ly7<[^lDQz&J1>pF5 '?/_-U/ECGT>,Ga}%B''d%ūWBH}Ldr!W5v"2ꭒq3"/|ТwC#"=z-|"Wʞk%8*}!Dnh'R z"P 'Ҡ?Իe ^{&ڷZDo ^c^8Dt|9 %:Bj"C|MH:җˆQMl- 6 )yx}n|xrFl7AO/W/o6ɸLFݵ-tk(#zxzF/⸁{swoޜ`. o֛%%Or"~l.ǁn8]cF&rv C}9ca) ϗtoQmفj\mP`by5ZqŃ{MI[ybu/br1 ̕M>oz[:::::::::usۑg۱*Sy"Cb;t*̶cml;f d;;Y3ҭm(////'~'xUǫW9^sx-Nw;Vu*C';T|G勉};f1w|C}ǁs;DSa)ݽﰯ}Եkm6{oW\MwwT|GSu*;c};fġйw;yI ~z!V&$LHÄq nMEtSTD7MEtSTDNjEL%KW&cBlBVBDݗ endstream endobj 274 0 obj << /Length 1252 /Filter /FlateDecode >> stream xWo#5_Dk]HS4K,i5I3cfA9z6{~3B'r0-RVNZUbl1ʈͥcZ q.*QBi]ko׊n=i1bI;# W+G~[ hPVkP !dOʼnk&ƷGͦG6{'h(*YFG ^\@JɌ"Z[m[ 9^[; !0Dѵh jni)Ixj+C:(f! G(jEV7o[kb dtC٧8d|M!CgrNF{?Vh[e`~~ontuQZ .1/'DTCYgXdMGI)o=@ז7h]"QrA*vNw^"Z:waHK[3SLńc^7x, x/xeN -אKa /!eR'k>%hI'@)+UfLE0a5OC_Ο[n NҋPKbX\`eڀ_T׳itag1~F/= j` P| R֗nݟLUA2`x:.YaTE'AARӊ6$ldt wKďjK43҅o%\EU^1|3kB*N߆I}㗋|.yO~#玀hg[=ynn{[\5d|70Y~+V"@u{kضX5cqzBqzv|8?' 9U&JR O5ײT e\n,@AM #o#ȸזhE^FKP/ũ,͢EiAYn|O-*A(w~μ\W j4iv-+FN*{x"\ endstream endobj 299 0 obj << /Length 1256 /Filter /FlateDecode >> stream xWKo7W n8|h{( zl'ZvK~|gv]Ù gnj&|R@zΤ +zh4K-4[Mq,}J8r^3+gٰɖ4DN+F*xqzR2b5Ei:ǫh50UG*c+D#(KF*sa hP=~ADz) v@{+=EtRH}ًuApYrR4r!UQz9(⅛m$C'wi7Vd2봐!> stream xWIo[7WP O})\p؁%7ncI]e83f8YF~CϡFIM C6sg=嚤F M6KM:2ƹ(tr0)H%jvɀJ I4HP=qT<[oY)64"{L%"*w2{ !EH@YnhX ^ fZ00~YPTJPoGx:0IALT$8!C$ y9jXU^eB^l$ʼIOzX50Fn&|({w\r'+_af}d~ k-85YX<~!}>Y77J.FY5qg#s&Ix0oB܌3B(#˼<SRJ~yd y7 [)^45X)̬bǕ\={ǀa4e;pRY9]gC_}7x֕5l\/9DۗRN܄)r)~BlpV޻-Rp 2W׎%/GhӣVmA~x2P䜜, 5SDhE5wdFNEǭRy5Khn/hBq+hc\Z\6뱰@Ad͇G1͠gaެgql;hqN<uQ J QV m}=V} l+zðGC#hF[""-_!HRJ#?nM|+B 8+4BDdTyM"Qo3OL$:MmbaSe0&r W\%eOM0l^FZ-1!Tz ,rj[q̱;S%342ǮK>}z@T9 };_M0&& +Կ^"üDvJ+ I?:4O9m_W]%+]xR~Hs,k7Vߎ+`b=4}P,HG|rOw/KMirq3 %* A)9W0:\K@h> stream xWIo[7W(}4prP%SݠPe)vŖpyd;F,EqC f -PN-S^q[O\ZVY~dž}(X~@=)՗LiuLs<,nn%t 1ܲ"wP5SM =coD#$_OPSc lܐ<{40k̘t8"; ,=n%V\k`@ǣ- b %T(*>KpW;AJPl ^l{H7'SCZwiH轃u$#H&u 7eN AOѹ0ܞS8->g߈kdQ~\7Q:J){X뜐X.Bp!A*vs) g #mGPIH #+h[т匲T) YX2aWOU'I  F"f}/T hFKsیQt;xU8 s|R+fvZ( )-%+=SaT"paު$=m)T ZVu*106FSj}-h^ʍщ2䒝 0LYí ],?lѣ_C9Z5wq:lV#$x7$wt#JBQ ˒3-|_7E!c r@74GCG-Ĩ(%;2 i-&Gy[k(Z=ˢ'9.:YЛ%vW?SBq}Ǧ*pm _& =?lҤܼDLIs͆$k`h^Od1ۯ $a8?$]Lg0DBI7hؐ?QRå)KIo y1xD(I@(٤xy^DڵjK4vhq5G 55PK7"k9r"RUHHd$C `;KD- 84ojDc^UhoJ\Pr3|&5]̓5K=6 E7Y ~%q㟉#{:g5筪lsGɍb_g1V{15|5"SVH;l'HiqD,-OG' endstream endobj 251 0 obj << /Type /ObjStm /N 100 /First 915 /Length 1562 /Filter /FlateDecode >> stream xZM6W̱H$"@> {pw` NN-Rq`!‹$̐ؑ< l)z)HJ*Ag yW3 dd]@ʡhFD1*8vdaw~rV)e(*rIre2Oh"{ >JArB #OË";meDJ~fA+E1 |HCD<u!Ca"3QLZSsvtYRp7MwpU=7 {=~&~WMzC/Pm][jjEFΨiSybsۯAqxsȮOCuA@R؏weA0&%NĽHqCDr난"`D*"`/"IEHlH[K9iN`-S <ҲN`,>XOmv$ ׻pmE>9";p6cJ uݳ =-_8+'3vusۄqLb3;{ޯ\?pKLs~_~IbB__З~}fq$oylwfI~8tj39&vECsh ٶukz?u}DD䜺 ]3/ ج6d5wn؋~\.h>ַ`~zVQX SF!w`K2el2+fbvz''''''gSU2x(-ݖ*a}ĽΖnkY\1X t.g >&*qw%TVrõљ.>,>f1Y|c_ȼس1G%7wDwOCjCj:$Ȧbz(/b(/+W ^5jxU>+"a*BÕQ"aV"ȬDf%2+/H[Ȟ}'ý M~> stream xW[o6~`w0@ɖ}Xoi\NI+wER"'͖e)0s΅3rE9QϡiRQʅ! g=嚄Șt1%e, k;Às"i"w[2M&TI:W"Ras^qP(m!%ƙȮ9U$| (T=U9Kv )"z -^[O`d#w9S9PWH`S+H z>E"89"Y2afa>U.bL mđ e4ғ^(?da㺢00wd,d E7^({wlp'*ae0_}DNX_\>)}o#(d ^b̑$IÜA fTF52%uėGH(zL-huB) fTqϕ|LzzV7^$i,w0#~0[3cDur!}4t|z/#ϏN9KgBx`lf!|[|hצ#~эۦ;@tϺnC(x̷nb) /ښ)i4Nx>vSWnMPÉԇ*eU™+;tZCiR&taeF_x) Ëıeė, Ky$ByXj!}4!-XKjK8X Q XjlٕS-} 0lBGNuK?p Jh.R<^?:U:K+ ZF2ysj6ː t> stream xWIo7W=IHhEPJ wFӦT$بsoˆ4:ra9(g=嚤^1i=eIea@9RR5T9KvɄI I4HP8*g[tVJ"@3=!dvN*ۢ`SQ?Tyـ5_I5(U@bj3>H(r*?J`SL$=2ER\L`Y2Tia!UQz 9 6A(C/2Ӱq>`􀌥 feu%w V Q'6>u%PoZ`Y`<~R,b{ FQ?肬1<33I“y.8#82cJB/l!"Cpx1ŋy< L)0WrUTN ޯIҔ9`FNaf}7x-P.Qy2ׂ}9B)\0a]n?eR+hgxu[rtʄzdw 0k{¦z5ڪp-`॥绱O}j endstream endobj 426 0 obj << /Length 1231 /Filter /FlateDecode >> stream xWKo7W=I@Q6C˺9k ٱ6 ZIS.Ç"LؠPs@ˆ4:ra%YONg5嚤_h9feIсd4`)H%nrG&ɈKI4H8*gƭC鬔Dg=#drN*;SQ?Tyف7Roj 5ᆆj]0+"Rh~z+=2ȳL"5DR\`Z24aa. 2dqTTI+7Ұq>`􀌥(f˧R83̨cN<^[=8Y<{!KI\#¾$i^77J>G@[5qgƣrIx0oPBތ3B@(#K>SRI~yd'鋄[)^<5s~_PdI]< 'O ~5\$Mf$fpkv^H ѡֳϾ/zkA۾!NM0/!ҩQS3켆-VI9p 6mTEH7̗#iXlW .?g |&t+ zPbD~tq_zcƒqJNyj!7&w(RnF9B_"؛(<edGΜYԸɮ:aK.?m0 jAq8mcW (Y5n-75cgkԐ^8*M?:-d\z"Oy4?K*TWy(-Zjrv2.GJ7qzs 鸦(O`K, wGM&HNPA"ֱ-yuĀ1< )u7cBuq! kCwi0+h@zJy` ѰWb}r-?oe`yiyG,VH$P|J'{ "6c8gcx.7ߓY1Oq9iqIL'w{SF/w$/X K+Ph endstream endobj 451 0 obj << /Length 1278 /Filter /FlateDecode >> stream xWKo7W=Ih{-qk#94w,; ZcIS.9Ù7>9axF=C FJMD+(l>SIh朌Y)-cIX8K ωJʶdXn40 ,&wUn8`u-`PVJ"@3=%'dvVq*>oSQ?T9,Y5_eI58+ E[bw%s93hkL ,=GR\L`Y$HYjOU^'F)xAM8 PE +4l\׶h1:@brt凲c;+(|NF+:V,XLO>+j{ FQ?"났13K“9 .X#8222%u椗GȐ9zLl-hZ#CF8f2qϕ\d;ŽSja4e;S)Cg}_.q?c l% =>_rkA>.ɍ'_ޟL2+ p2^\-N>p :WY׎%l/ǠakáUci6RA[ b’"_AkЊjnIhW >w5|η?>|n!|; (]1_Fqܗ =V (G[(= I[ts`4Hľ)NLoNCowajsw=|1@_Ff!|k\6C&D.Q/А H3f](upX#Ha R8\NM"+HUXR`OϋF JdUm* "?6-E韠l5U4e*+"?.SؚK|pt巃ʐkj] ߢ?Ӹ.\V尫\ "U^ P"L b] )~o.zo$Wl8l|xEϜ뺠8q8OѸkZߛC,w\-9W&(ݽ*zb|_Zc 'pռn͕ |Kؠ[^ӈ@/p.{韐d7G֍2=)nsmw='`.꟱9g^E@Y;.^f~%Yy##v* endstream endobj 353 0 obj << /Type /ObjStm /N 100 /First 915 /Length 1533 /Filter /FlateDecode >> stream xZMoG ౽ 9_ Uzh mj tJ>RB rIװCrfb9 )YH%GB1""pb B!%8+b\ࡓyQ4Ƣ>.55ZPLˎÅ9a*$S8 5Qt\Έ+rO1VL/bfSbQXmr ?FR LJ1SJUS&T8@;,2WsX;fiB3~0(hBAG\@Y+~XPȌ8I@Tj U}#HLcFZG-BupNmxb FH,y'8z\l$\Fi+@0{t#DYPZ(\X @Ymޫ.5@9xԐ ]DBXw(2҇X}l.C.^)Y]~E_om=YoW]v?v/HeӽZ]mu(uIV::݇Ψ;bM3ϛ7ͺӣG ~Hl#5 帞T$yZ0'rܰ(;?JII G@'I;pGrgyJ?InB}n);"_쇋Yry_RZήdXH;^,X] KDg3dxq_lɸ;& .֛OL?U t_~ RXz<]AwՊxrݮ6=vE~tujd}cdgc>Q& g .Vt\Y5p߮-z5Ж ~^],?ҐumV9J/ nͅ(?b Gڲڱ2&q=ڬқ &٤%K /Ň-~ڡwyV[@{nN" ivq-qֺ8# sCx!r"rt<>&)ׅב0wdצOI^I )vz6E4`f"3Df&d"9D="2Pq3*RCPl%(F Qb(F1Qb(W ^5jxUëW˄Ti2TDBEdH I3LEf*2S|;TDq(9T'/HLKgoH$<e2M!&I6ixy /^0`xaJoHLKz'CKThI -I%y%3-iLKfZ2Ӓoߐu!!y7$UglQ 6F1(`L IHdH ɓ"y2TTd"_ endstream endobj 477 0 obj << /Length 1391 /Filter /FlateDecode >> stream xWYo7~ׯ $՚ǒKM}IlXVΐC뵝n%9~sg zP8SFVVi&Y izN&wGK֧lH:2 E9D7I*4SUm֯&WlrrV["WV8`q PF)&Mp=blrfquE|^g]qsβhCL2JCr„jSD!Jq]xEQ)e`h*(ck* 0-j)d8r┣ ܫH>~/H@ʸI&}XuMc`wjpta_쯺Ξ1%!N 5uevjټLL/Y>?᳄v㬝I;5tb{-w֥3Fx[K6S"Q-f`"`/@CDs mq{:`DC/#ނ!ȝ=\W s3lxBMo(Y/XCX%7aؽEt 7gr c@ N 7$H q=rq] tG#K'L]) g'|R ԍ+*_;>pP 3cIS1/*PM4i+U7Mൟfs-tEڧ@0D;(X>K &y/?BۇQCAG OO'-!ė~vuQ +פ"sҠjq?*Z<}Xnh%e_xwDwj][5dL 2#.S/Kӟ*YpLc/I4Kc$m|NZQ7 endstream endobj 502 0 obj << /Length 1332 /Filter /FlateDecode >> stream xWKo7WB[LZA^lֲKewfؕ4MidtDe7Rq: R^EC#}hbET7PzqQ@Oj6v2RpHGYeJȘb/þG(7xU4x_/U9x3SΐIp< 㩓X%tq(CO#8U 2RӨ*L WK*O'ˇVK ⠼8;ge(%1Ac[iݢ5F7,Wl[VkS=^a{;Ξ?A?gOy_Wp :aϭvBox$HEr_єh'~0㫚 G!tZK'8lp+~͸2n&Ď/#Xs/s8*6b*yVYDɚ!DPE\\F\dOB^mjh)u=͔E`yL\)|*uZ[!;w+ɦ&7}r*ErK7[2!`\UM}λf@Fg f>m0q,ቁ [ri/ 4Y^i5D/!zإe}=yc@WM;CFռG!XNd-Rf/ rHu#Ti/ ʐ۽ qb?oQ?dQބ 8;V谇_'-N^b@n" ؋CC2) EJ4TJvo¥lCvC]OM 9F](<_e'FYP8TT׏S:WpCg@k}*wٜ﨨7aNwCO0A\ wNBI_]Ɨ_^{% o/I>eT[ endstream endobj 528 0 obj << /Length 1131 /Filter /FlateDecode >> stream xWKo7WЃtX7"m F/AV~]Kr;fvV$? g>,LZAD0e%0$ifNgG{J߭`X1ҰC)-Y>)}, T`;֯g7l'&L"7쎑 \ λARLC#6;"MY :E Hu5Z#D(nU2<6=b**JV+e Z Ā"qnz41Dq.) u#ϭJNQ>6 '*" z\ƍ8ǀn^?-)T"VFs1:S, &ǯ$q?HO$(pꢬ,]bA@RRo[)1@mUu#^he*R^BEj`ѲFՋT7Pzv^FI2\xw`qK[K`d1mQ7 ^l =_vkA۾4- 6! .Sm vqo!#ن@(*9J0Z҆y> stream xWo7Nb_kK $/l.Wh6Q3^׷p $NόkēԀ5`}%2't%h/Whw8_h"B6$DB#MtHZ31-DKA&g"H8V:45FhT'f{dȟh|ė|ZGc=z#.q1amPr$4:AH Y6d|;IExl~^Db@m#aYcb:@MD8-uCUJՠݳ9E.-" JdRLƍmƈT@aEw1a= VƸ~8fvZ<ÞмBуZ;گ"~E3O2F b+tE#)FEOЖxkZo)W$`I"|) ^[!P]A]\ ?cxjQTD),m|W$YT6g_aǻr?/sz-/g@Zr6S:dEx5fcHВ()N1=&RThAHȘZ sy"J;Zcw(oX$uҒEby )+ACr䢱-`~^~Sb>PKbztI/ǣ&Hc[L<lAƥҮucDGZ&7cO‘H3-2cuQzc~]4Nqs,os/W)X֙,XܗXX.>dq5L  x;4м]ף~X>a-4$2TԬv1> stream xZKoG W^vg<#@uzh j T dM}?(5MBUHM͙5c8ڔ"J)J⢐RdH%M 2SP W1\)SP&NJ IakXÛj# 9shDbi@LR&)÷\L'h:Jz$LB,hTXʍ$5*$ HR Ï&`@(zt0R"<ֈ^ŀ_S|Bʆ\ iZ"KV3j1k%t ir4-R3Ғ}};槽":{?`-Kv).KuxEccccsf/h#s<N}?8'8}cd#>>v=YؼNuX!Y8 gBU qV!%K/9^rxe`p>qoafdG<#>F?& endstream endobj 579 0 obj << /Length 1619 /Filter /FlateDecode >> stream xWYo7~ny@Qm@l5/n`(kɲaɰ$'~̐]ɪ#G%s|go}||o™0d%e ~ }+aX4lyIǻgi> mP x|R J{ǚ-;xv ް En < PSI`ܠgOkv%fi:۠>ҩ+xRBlڐ"uˣ*_)NNx`f f| ֋RhT@]sHΔ)BT]$0K"|e9*r3!_l;H+b]F 78gacdKdq ߬WoG/:/JiH*% l4.ͼkSe^npl@`xO)({8iAIQe`HeIN{~X`=vJhu1Yx3G߽}jj,.$̍0Z)1*(΋D%,OV%*FBJ!E7 Snh=:s ǤhTk4K,`L@NJ -&k*Z;b)_Na=15=wH$!@0·H*qNc X7p*`7y]FlD("zPǁ!no<ǔaRQԝr0ǁH2"/9, t鈆HcSD :@RoS}0\o #58؀6y)No[QiM!)<3ic/eR$^فt8d.1H͓'{HF:R4FFeao Uzñ{lŋ3\Z(ϰ׍9z ;y' f];f9Q}~jY9?[ ' endstream endobj 604 0 obj << /Length 1010 /Filter /FlateDecode >> stream xW[o\5~_]u=[$J}A,>\@ل$7>PQJ*3ąPLԄPBZFZLώZwbW:(G-͊iIhcINicfv+f{$T&E' vQjTBHAM  3R=bv̞ъIvoK2 ?Ԧ5WH@s.(f MԱ8ٲHe &1yAF 9U$@"C* MTZQzjTE/,*b:HW},g7N9ƄTnU=}*{:S72T^}Ԝ+$>NEA[Γ'2ŃS¿IFQ [yĒ򉍫Igi˼F[oZ{QY㚦<*BmA!k+9ZǨEQ5- .NO|5$'U|+w5\g~hd5.2ޭ&5+VECu/s~-~۷3 /9CMRFj<ͻ\{Jضkځ0vO $JOjV4M$dZ _L0Zznޥ :8|={v-/I,rs,pJGQߊ(Kk'g^l=YxX7pexwx~X;iX&Jcwm=`\*BæSˉ~cSաzi c9#fJ[QbAfҾ^,6(~ qٵW(\p0宴oQ~+53ʏ)T|1b]*_QV(ߣQ' .Uebط}1Ⱥm>(zr2oam_z=sS嘘}JہF/iftEwQmhO I1úRREv$vK|e%0cn?Ls0%> A'HjA8 3#O Co?: endstream endobj 629 0 obj << /Length 1189 /Filter /FlateDecode >> stream xWO7~Ow*T m&j-,O;w;5$D*Ҝ<3%oja0j/ F6 SMpyK?~H,iFOtJ78[V腕E;\-i$llr!iBTX+ mS[+ iٱMlnp dI16b֐cxe0Z dt8PdR{$Qo0Xۈeղ0`95+ %5NYTiȠR: 3SOxA-aid'=jCVnb dti(6>P3hs-zimJgRڕkKdg_uA6>bQ̲Ib@6q M0t-(g}[5;i3G÷r:[g+z}Q0'&nҊlOo x+K+N x4+fd8>c8U-x\?sZ0kr]ꐖ:u'/zgdm)e{Npt"feʬ.i:0Z4C|x+Ä76[\Chp0I/> UǑTW;U֚l 9o;6pn[/wJdFqd~>L=+`Al{p_m\#SQ6!AwR_rN˱*Ղk0n--uaTETVt]íR6 Dhhƿ;1mM{sSc#~[9/t ֩^R+֖%bˢpC`dTS-W2'O">:siؑZckŞ'e.bNCCZO*g{0#k;Ĵ;Z_|NVV^Uxz endstream endobj 654 0 obj << /Length 1046 /Filter /FlateDecode >> stream xW[oS9~ϯcpw $X im7@N[Դ sFtmKc{<3ߢW_UրJ0^hAK^\-_VKp~vwY('b! >m4 #m _N䖶E&E'n\(O*xHA:41#4r8CVO߆eV*Q6D6(9e f Yil"k6A?2 #Œ(X#u wpZ*2ڋҫds/\l;D@ʅJd=QLM!x짌1!2U3er'pV+cX?3;<Þ|셺UZg{q'~E'O Q٢ <]bID,2Qɓ%|Zc[oZG>5 <yIzBVr~PdBY3w|5J*B;Eyښ͙#2ޮ{Mj|/v?.sz-og@^r煐ia&b<͚!$;Hځ|l@h(*=i8X~ y"J(Н5ʛ3bx--I\ B;+D8I:kLa9rYg֟U2pyA~.8fGEgelNr}9t^?y r k`q.}(el$Y*B7p8v#yC-S]0SэpTI[TU%S/gfz\ ZNL58[FpX>KÝ\8`YEA=FWX.esTJ,}d]n}V9kS]`Ku{NDX)` kו=[&f+Pۮ=$V,zjwTPC-*S#A,<2ivh񑡹'Xj~hpVlN^ endstream endobj 556 0 obj << /Type /ObjStm /N 100 /First 914 /Length 1537 /Filter /FlateDecode >> stream xZMo7ﯘc{%g! Q6j>I@QvMrml~o  ʩRۈsI]oNx)W/JP!!:(˹Qde(&뫑btӨ%B((Haj&Jlm bH@\ ؔH"|& bx-zQ3.#R1@ WPsZr͔rU@"S(Uxe&DKzƄl4t`4,6s̟ f%7%1)c̟ (dṯSdV518GbZ1z6@MNC"$FE1h 3>`1T^c*jF*[BTZ@-pHM:4dBr( LcjB(ԚPcCdK0 R:WqRgX} 5(P#X1"r+_0/( Ph:1P;Kx͘'@Z;@͂)D E =pSc\PŚl4ĥgQEY%&κKVm7\mf7ϗg6\ OLniygd:!fBղ'hshrM#⏛z[wD>9nnQnSd#2?;.'ߗρx`qxIy8>0fx{L+=,=׏Y'~W,q=D^]іWdt.7+rm_l%݃n8_9ǼČ5;tb$9 w[w".^,;Xm7뷛=*ohoQmMUbf_Na.4b پdd ֙`E(i:1}9\yu)=4L*|Εd>Mw5cdR)&JjxoZoi #J!#r࠻g}DLOa?%H/c#!.`W> moN$"!v ?HDJ-dӉۃ/c$c3+(pq`/8pOG˄ԇ * ꪢ*檢h9^sxV48!Xq੨ɨ4Y}cVף>{ж_H}`Xӝ>c~~ay~u2 -mvn/:^t~,?V'#?d*#MF~ȏ<ˏY~cW$?ҿ[iG_!~?OJB\I+ r$%K/9^rx)}HXNFq(<ő'8tVǬ8f1+@q ׄ endstream endobj 681 0 obj << /Length 1321 /Filter /FlateDecode >> stream xWO#7㦺z!R{IDJJwfnz-\A*k{<)87HB[UymreŪ{#QF.i:&e>G-ʔ`A(+Uh{7bQ$wDn 2 N*i-48{$k}Bۢ$Qu9j#uѕQ#Rx&`q̙QJkӁcʣI51%TMA,-%C򕕜=O)3^Xl#$ e2ғP_eqsׁ} 2MeIT+sR:4P -{ 2n&iɛG/$Ń["?_tĉ,Jti1'' jzXn/km2%peEQe.#0O'C_NM[v'?J%P xq|!N ܝu~4ZBIguws0IH#?^D.fDT`rz1(v?|k?[(V ?`+ i3r@/wx$iEt؏Ǥ)Q4hrYHJU)cb&QP@0`W1+4%? H#s^(d:F!*.DGyQ7gF׷/}KaD`;֔ʛɀv` RQ"R>MJeM]`b!sA+6w#Mhrpn8.\HiU5IYosoZ{5S$s&͚T_CNN9,S4T+N#To"o4ޟiB-[{FU2g#3y!O;#[6-l6@Y;S,v| sj-5/WTȁu[.چr9kLab &Hrh-\ɳj؆.^յm 3 ﷡{]m;tPPrO8p؇ZAv#H>Ntl{d{^ ^ծ(Xh||vMD~x)htxK?~& endstream endobj 706 0 obj << /Length 1190 /Filter /FlateDecode >> stream xWYo7~ׯȲTC6h>X֛{#-ߙᒻAj@Kpo[0ތI+L;ŃLyťrl߲ɢҲce;VOi#d4`)ingzc'Jt }`dW.>z!A^k@L ^K6ĕMNa&!J*2[h5 s&~ ,4\{ I%Ax:"yp3dSF4W]RbWsš*I39y $Q8QWiظ{H>FLt(fSهp5V'ǜbdM|&jAW/$_ob{$#(?DY Eΐ' S 48] Ѷ 5q6D[OY4-8mqSHq3xJ>+`a,A,pk~|SKm bxg]YoJ\kA}9 JOAo@ٟ:;!I=R5Rèa>kIßOV?>77o -t"l60e 2`v\XV%|6ZJZ=$t{ kanPNa>k%PaYV=H#]wz)Pw>}so:œI]ktFGv_WIJ tǁnjIm{Cle昐}HlD ݥM͑2JS ^=`kjg|:`P ^SKWuNУZ9kكcF@W-1ld{|Z`[I rS#R8UM`0]!tQlck˦P[ `?15A"6Y"zl)% rV;aCO%mc*>T(|ūh25Q W }< ]h2[8E~С.p6-L]@}nX)D|:בphwGsMQXf7 |`16Uv%EYl)%mVdaqӊ:'?۹|]' endstream endobj 730 0 obj << /Length 1350 /Filter /FlateDecode >> stream xWn7}WqUx_R@ AԀm̓^$d^v-MS]̙3Cr%Z-H8SV6^&llݱmaeaK+:[e=K/{cL*ը`jw]Nn61 "a.e6.8.N)&AMp̞#69•^ :'|dS7~!xk(]hHL؆fu“D fŒiVYXR@2sDZ1ejd @ 9&8\o,TEedNAb TTf'+4lq n=*p| '_bep~r OˇVp[q24yLRY\m?oHOW &FGt% E >ix(R#o[)!@mUeke$yd yE"[kQ, >-(&Ҳb~3k$p/v 5K?g-$2m[X϶=ޖ_2ǯ RX +S"x 8Cu{I9pJ*Zbd~ 4|\mGr nI 2mG9YZŽt*@-m c)4AVb:BMJx[}|LCŢ20×42V; !? Q"@4L,vBةzA]r' NH\ q1``q"*IĆAʉR ɏK4ƺն1Fc\>Z(PJR*H?ZS[j9ƶd034EJ8Y:G CELc{bεXXF 8KHxG]t~&iB~uC{(Bs7C pnG'm엻l ,R endstream endobj 739 0 obj << /Length1 1391 /Length2 5943 /Length3 0 /Length 6895 /Filter /FlateDecode >> stream xڍtTo7-! 8R7FIHw0ƀlAZSANF$! Htg<={}usseV0%$򚚪b0X sr1jrNC G"< t  O:E`,/G$Jq[4A5$&G:{v\PY'   W q!p)%0gq>>www Blx;#rY~ Ђ8L"zH;p( E"a(8@OU Cqpn +;"!O8`w4@}aF!n# s@IV w<4wƠAh~ݲ"ZC`S`Pܵ{٬+6vu3@]\a ]p*la0XTDPTscVRf8,f*uMģJ};9=:.ҭ< 92q&CtC9eLCrͥϥhᴷD\=AŭFzlx|z\<ṟ8"Iw#AG#Ϫ؆d">6^bd)5:ۚ CԌ/K?>ݕe$0oCu9nVV,~P; ]pf!*<6y6'_gѮtocHz4COQ&bw܊EN/ NZxCc[9=C/HkzLY0jz!:M_+w3YsdV5?tkA(BMk)gs Uj:4CRFCj)pr + eGE1 ,8rF /E ; 5,k=üTfttYDrئsQ1^Wԥ8h{2h([7b-@}%\hz}u,>|s~X[HˡU)bOPr@.TuػJ{(z NZR]#Pߌ*Ŀ% +djvzn8Jiy#:[rF|) r@jG@][NmPװ;ă=qKq[煺*PG2'~^'9ywC@̃ (JOCàAyWzAr3șW@4ռȚ#q^ ΛYWė1ꒅc+d,u̧%6 T7[.&{_M-KG.X`,nj\V6xJ _uhb3 S3_ǧtuƋ@qK:yXgjqJ߸x:>?OK-*l\d| ApR'usqe0b[T;o}ԂH>#Uˋ:1%x妟Yn{_Ycl.mO` rD7A6AK>o=˟#(GK{\w8|ZZoxe i]ԣNL;6iTLG 5#db/cwfZXM^=Y?q2#G̫g]^}䃅&n{dRg-6(u+M%mtѥA!Sy'n̸3K$(au7trSqg~&6'3ՉWU"<YQ06iH"gnͫWf&P2Fá#9aVuuzM]ke,}nA?M=8Gѵ˵W>biyUdDo6*;X N[DÐ_c6I)Zx3=eqU G?-" 0%eXn791AyNPaJvRI X)8J`56GJ5N-Y,rJ_S.F:!-ݝ(7=|rD ֲ9gVCNu2Ct{vsNm&J,GIc;->\G-Š$dsx>rZ_`xZhnp;' :ya2=Mxg楯  g::{$S|e̽rIX'ZS%J4h(:ÐЉ@c}ô U Y t|BzM*2}.sۓ &V2勩) Qln:<6-̆DD0+6%tOe$U lH.'IC UD {WJR˘eL'H`ΏP^nK ;5cFJ16垖x1DC3dN=skx[N DyAUg5;Nrv)7W,y~t8&~u Z,0j 0eH0Q.\%òVgA0!/=Ku74 Y%r8ij)W."o}u?OWT<&ϩn?6VYmՈɡvQ~ؓDm-=NbhF߅ I6l'rJ÷F:F/vH̷;D,]ۤn>~%[!s)aq3 >ַIv,厊O~ /HFh",pޑf,&| ⪐VK)ëʾ):pf\_<ɘXH難f&D;M7M)F餦GCtGE e9QFoPt <GDS=3uFƔI̻RL,?ESН~w80W]IyJusTR_p~<8j`x:%$d=8\^%'Nጒ:Qר/+GNn?'h(x/u(yڞcA*M\)&ώۢ-,WKW.%j .KU;U.pbo1r%Zgr|hMJq1ݹ?3c2,U!ȍ^Eʞ{Qzr7 16JMɎ_9JDQu"יEi4sYպ-563ݨ k>D#-A3F8Z$R"uPHw @o܍\Ҩ.{u G1f|4|+lAUbzţO.at)P5/6RRcގhJ5c?y[|mK!gދ`mvxBRPhXph^LmMS $UUT}kvW Q"u$+, =yfؓ<2?э ,rmޠF.x==#N|l+&oc+ZN.oɥhֲQ3Q 0;S:pw땁sޏ'VJknz8(Q7%fW>`NӘ–P,Ȭ~$FzϑDuN1NI6|[h%oS`2m&&1G&>%qȻlƧ?]ޢ?`!|J1v9tJЏdžLi,|TCP+g5!m^^>§Hc+zyONJ d['*h;033vVxqf(A%$&+[^"fVN3%zOlJo?&Ppnw[L}3l0$O%&T+H\k^vr"&X\=}G]NNFR`ؕk24-цMÎxSd^lYe[ݾTL; i6#Z|^X >x(Y){/$ThJ7.F<|q?,G*ʞM(SM;IC#e\mPXrc0䓥ƳAZ%Kʼl [Ma!)ҳhEi՗Ғ7,|ZG. >u`MeAG׳N*ZkpWޠ+^H!waICη9K,C TU[{yuxBH҇Fv> stream xڌeT Xpw84=;IpM Xpwwwۙ9g2]ff&{& - t:() neJ da vf@9mO{L@9M,v@<+ onbmgb 6+y \*t1svtuar]%0FK8.v;:<|` ksߥ92k8X;ec!Y],,,<:fV̿IԽ)Yu|q9,?X[}\L܁Wg7+!̭\@Kk?b<֞=X~xAv^:hf5)5G-* 0\.^. lbD*`/Q?@=o,Ex?b{rQI/ ,Lca7W:(KMoje\Mk!` mF^&.֞@sekW3oﵳv*\_5FV-:qO_* xU d{8&&^,b<@` 30̢7Y0Af7 Yb0KAlf?, 0S|J 0fP jYW5A`v?n+2u61 ?r? pf Np03+-CAvv&glRz'72q 8] klb'"Xo՟J-r:,w_܍?)r˶=;OlNp,fid-3Oy+ss8F9]Hl@N5G;T`v$eNn W,W_YVN }NOZKWynfbrwk/n~OO@)2ss7'|zg@f!6u!mw5"#?4n^H9?Al2A~Wij-%ȽIW҃RL(ÖW 3R:"<9h/b^?Ootņ1@w{NJ$J{38A'Jv~*|S,6A)H ԲH G3=(SaRug:|ÝlVr] Q9Ի P~*8QE3l-2 =GBfSm,< ObK&iN`LtZO2؆=NX e؜VԨtHsͫ]ܶ$WW|>5TuY]c 3x^>ѱ/MО Okg&|4YτYwNWX8+}\WQv JVJx49]~DRkXѼTF18 $ui\3LN3S1OٹSvtsrF\1bly[bs[r8k:0N-Cj*9b]K~^7ѣ>^r]|α("K1h1ٯ;=]eFy~) ^IO/Z?pɰ3 +ixr uWQR*  Șo78Ut/ mUrf2u}7mhqfA1$_ʳde :ZK\pJ=m˿M88`:.<3+,m߯܆% j=ӰQ(7'^_G(*}40I]-ϜfxWo<dG`3-V𽩜)%A<_!; d!{ z:V/Zӂqn=Q'DV>lBO MT_O0tO7rt@<{mwoa~htIlV)itE~@DoA/tfu!C#I<6G*ӂQϪ( X09E6r@bm.6zII^rd=df>\PWaɧc Cp)H'<=wi$[֟eU^+dݵR#~EO^bvmCY>1/n2w}^rA.ki9xj![kS6{_mG> \cy| }-쐩]4cQ*sϋ@6_(nڍA] .ozּϤBvLH0>YӝIHC[P㥍8ۡ<%Lp^?Y;Qt&7K&^-~. 'E\UfZvUݔEA=5ƌgs[>abNEL)%J(ΒQ=2r{p"|R@¨*Xsrn'"]ґ:L f;@ӛbW($䞺`P|e8GKD[6?Bs}[- OL&0p&cOE~um&o0_ {CdGofF?LC%IGQM  90_{+ 2ߋkܢQZg6R"OB@Q@eG4wV`h`;ͥ-#IE3,(IIWOq.QH\}Q2V; N<֐3Xt\}M;#}`KaE՝v#L/a~qtƯhMsAj}hݟmHnhHZG׏ي~t􊈚WzDpus E,!݇*JZAR}<sz8dǂW[(ٞ@$rd g 9a|;TfR~'J^sJ׊_/1 #b 1l6SLul⎷ $9ns3Ȗh 7ݖalb?zRg>j.JOׄ6,o" >Y#:c /_6_kܹY/U7bqgOsE4@ldz`zH֬ ~q-7$ϜCG3]3곙On{r º-3>4pc{d_]>foaYgd='Wc9G/f(d_rpڽvu(+2]=s4ZZ noŢܮߐn.#Y+(@]寶ZM m$7 C4g/!?͸piW;yAѧ>u W8p%Ϝƶ~!7=drxɉP scZ_k4-YƋK ˥#hm~Glj$YQ=gǯYB2֘Kӕ~-j8ijT“:=I~E(|) v\ c@P/ݹ,/5B"ovX|M0jPyܠ yruT9YWx_M#m#\CYgV>~q)~Pp؜+ =1GTvz@P3>q&=s_'~H(({ޔ_-m~3 G bϕ {B&Ź|%\v|%| X-H!ٴ}D:#4WZ/fp!j -4Q"FL憀pWރu[\>I]e99i*`nTk'Y҃<{{T $(Y;bH7τ18ӯVN=Ic*']]˓͚ B._Z,ͤX5f܅$})p*e#al+^ pyψv||n~YO\ l":34鋴cqb.xhy:M0Pp/T1:\ J#@t%(ߍݻmV6g"4BVQb8(MjX2v́ݑI; ><9zbY8 "n;i] dy@V1vbEus}~wDɅkC"LnTNL&n\-S{EBb;E 'ir' xzPtw//o _ɪl@p1 ƞ O=`n"OUNeV}e8:'*YWu3}1&a<5ëFQuO =eoSvcw1B "zenZ™UόAEy_Zk ~}&Z`ŠWy3:4;[5;S@sH!T/(qQdIJؼ!+B~5me$IyHFs6ة<[qa2mm`,-†!to%秄F F{he6LG(jBѻtm}4G_yDhYk27}jI!]0 =#]X`qr" xv!<^FTB䉏2i_xBU6~+VΥNOxs[,RG,aMCA'yZumJrE ^^}kƥ;.3Q.ش×{Dp4LĴ\D!]-^T8H~ K|z1IإCɵ,q}Ln4^NFHڶVŶJL5 rD}G-v76W7hsc\)~4YD!쾔a> (5c$m/\ mƪ],slN8Łc|,`]Ow2&[25l#4^R!ыEQ{ga YU ōH8V-h8nj@&,Bz7]lBR V3``1ߍwhˇݗ0z?3-߲[VHPe]̏/,;ӊGAG$DBvla5kn;-/vDo7RV%  ζP^F#G~8!3sg0{]f?V ѡ~/?b/eB/ڳ?k&I7`xÉO/F :5^A ?ʹT˫;~P):,B: c[Ar(_зAj8̣GK#e!oqg[_:ƍ36)3`x+='p^SXWOl stYdaxV e!r-d %KyJI]_{)ᩉ͎TFf[_vcpRET?4bԝ苩dë"7w@Sǣ)̅%;'H&&qvz@+;K'p;x\\ BJHaW\qm*vu:JM8(ZO m~`K%sf F:g938= 6̲M*K@Q0+2D)$ʶ;ёt4֑hW3Ni*;sK;ƅ\qѹqp{[M-M<%' TtģXmtݢA\ERh2t)LzI%MXzfXUŇ3ط djB6<{ڱyCßF;rF ^'7ׇ\.IYTl4qg?Ɉjtcz F*I} 8L5ǜ}K jv b>DC/0R, FyEc4{Hg*m0}As.zSxd׸ք_O˗/g4%|IT5If:~=Q1|c8JNmHt{IӟjYb;)%:o\8l6rŧ7dE6󜂃EE#nֺ9 ;}˒}4Z"_xR?c[1MZ`!7kၩ9/+&>[䠰@30%i^߲lMh~,@6KZGَJp2k-XϬEc2߽R=0Jhi*(!%+kԮ)$)֋ G:V*-NYSE.'K+AԷ$lԹY]HN-ݪaӄ.5?]tme`-7Thxc GK @}]?1%׷xv2vhd`|L ',cՈXM\`\<_Iz=~qڀ}}s|.>_myb6XLL:— iF 52'YB1p |Af@cx9;2uO%>UO;_r,!S6j`f-[Q)bu(b]+aDcxuÚ$B`P[TNP#o2秋}m!h8vNRJ}^X"$<"gR4_?e,$y|V>HP`7|F@x!HɔlRRi9L&ZKX8͂@R%;jGgLB a<ŲpDY/}t| zv%Bf&`t9e,f &dT`iz>јS'gbzE}onaG{ |ŻOJn:3MO1aGRO8XFN> vE%Q6$Sn/`3ǷT60iCx5/ǜl?<`]ծ$A4A?;JPZPiB+5rb΍!RR[.Yz꫺_c."ĩ=_DPahW3]}3Oo_Ђe7a)3h :edy^>tw{TO xHH5NT}ԅyF˃6"ȏĞ7-j&!ػ+o=CٴRPJQ;#u{dMp6C<[DNB'$ddDӌZ"+ >(!OX*Cĭc}g(dw撁uihS`dMNC,g֭L}&jniD;oB?}m\t+KOq}:6D15GI`K"]>"".}h/Zl;=ˁȫ)(m#xM](3&oHT lv(knKK{5#IX.^Y qA nIs.$֎i{Py"HSƑaKh2º#£M~/z@8-+~V1y˦˸ge TC ԍli 4U].{wT $~u+aiqDǟ$ ET)#CKͫ>Pzы7qD[q>>z<_ad PԂUlpVT|#aYv#2Y_B'Z,""`*+Ֆ:;C{[CldXGQZa[PDm|7f+h>r([.Mw<:W tt6ث8bˈTHKl f&,IL^NIm_|g?%c,L{p<!S^I-//%] @l9s먭'Jw_ZM66qwpC/?u,x 0T|sT +$"\~V2tyB,g]qmVrm!e`wф)7bMI8B%X S'aGPniF!EٌMx2ݓ)h)JG5hL^Af9E"Mgn9K܎얈^<'Nȡ?RBƧ^](yD_L$gNfu(\kp Ȋ\K٪+VBFJaUsɯk}Ģl.w֮+ƁwG?XI7J#x$%ts!xSa>l)oC;+=OZ CM{}[HJr^[MFIWj,MUW4C}6uu&]og_nO IIə~׏6|§'oh\<;ˏ{ V8b }Lsqy/mas aFT #*eւ6ޢS䥑$akG DLج}ͼR$UU8z53x\|xˤ G~uw_Ȫ("E^f7[+gJSO T|0E!$P4pR\z'<{b>s]{^x\W{bdl'a%^µ]*,f[ݬYm}LLXH2~HH6M!6n_Kp!;(i5nda oWwIVhadv`']!f᫬x$lа1$ԷɖMw!"GP]6fUu6ͼ62Ěk .d}FIǐ{ϳ|82 P6 L%'>>0F۷,oC`gI)$ 됤#7GOR_{OOr+sXb˾릈E&1+ix"D4~I1u~m"!rvCb|˻9=,_dzQ,%pKrw%Kz#0PC3W>R>O\mpՈye1!~ٿP)TPLЯĈ(V폻v'<'3m.v:<7EٜX|?!gd>7^uK_~_zh9;KT2KRḤFk{;)QDn϶#'EߠnyȾFP~VLRWᶉY>u4-2j/BLgN#IQ~$'߱X+&FR[P)NO'"=L 0(|t( r,YNM B<ɞxD~hbD>Za8_74}OtRp=%aR2; bU4Y*ZcՎBK$֠阮a8ql]g|7-waҘln]2 _6#HR`UenƎ*,ɹX! F͝An]*^ݤB[Gn q'N$_Pl2Rt]{xy+".#8ޒd9p4NϗJ?/tjH>_1/yɻ{MoStWPEÔ%DT{74g @<84F{ՒXy,%&B>EUV E)_B׉!LՋ>ҟqX;%3mJj %ˑ%r"[?=ݗ W* ?pes%/. 49b1]B;Z'A "<B 6Xn\JkλI>djDg):7_Zy}\XSD'$ĸ8nvW"4CܞT[BnR^v!&͗Y8EWԧ~~@o΢ϒN:O•Յ2#uBqOC#G֚c ʲWgd/ P־sgM4Sp h/}>S̢5tznƩ T R~7zȚI(A彜5s6T`8͢Т3rR]ǡ8,[<NNc:=o 9拈zاۀ"j3距kj/s 8^ܒ$18dW{0λAivK-6_чg,\ endstream endobj 743 0 obj << /Length1 2180 /Length2 11494 /Length3 0 /Length 12790 /Filter /FlateDecode >> stream xڍT6 Ht C ݍtC !% (%]!tt7xιWo̳y~޽YQi[BA2G76Nv@RYSف@.T::-=?vT:m+(G j2s*C Nn''qHy-#NqF & ?_q lfrhafЄXAn`qssd7speX24w}Pml@D@m? $? T ? e? Tymh2_nh3NP2'7=>G&n6.?Z'@@h74ø޿\Z@5q둄n__z u~b!j[~[#Nɶqu#*Q?׍~6F )KvYԲh8]m<|bƏv˰mJ\t)ۻnk%z?=j$Iހ!Yg1{Nя@5U[xn\=Cx w-Wc?b7wޛ_?O>/P %Q~3HV^Z ndoYᅨj *_9y9Ӱ`kE*X~=t,Dg$鉩*SŒՐґ*Z i&PRi>6H.,9Z;5"-Ӈfld3XFOM?iIYx< 1^oi@|v|.. S)V~=se}d JI= cE`R/2{Kz䶙>bW@K:7´%xР',t'.uqPgk>z<+1H5|> =KPQdm"%[k#aS4!)L#,KPxBI\Y= |Z%TыGX &:AVkh~}J՞wm@zqh|OeTP-jHNUꤽMIi0ol./mřŅ"r@!*9D ]EC=@:WMű텘p[!\s@_L܈IBQ`^Nϊp+VͲ$gm]O/S!ˊMQ N%$!Bb% "12b8<"K)i"ɖ%ow\ԥzϩJEĥ5?la" :|XSڷ Ě 8I,H%%x_'bRNNK˺xZ=ydW[,*--x#?WsMG.^Ʀ=B#OvKW.%iէd%88 |g.#ёxhKPT-(#ײzCİ],돢u8qn5ǣ{۫MoJD=X͟7B4fSg;3 "E2֊QW# ~\p`kQ !N+ux%ΝްYæ>u*'Fw_/6ȻjO 㥯QBHKTLpaUx/ jQD=4j=,P _v AHYrL>fM8Z~Kdh)f%_pґ;8 >w}SR1" w8X!*S,0$l/O8* >#դe4; _y[ ^FyC_k M7aBNnCĹ\py7w37\ p}&HdP Cn\y ,{8[mS䨨ڔ  fݫ6gK+=G;{yjGOTZheS=~`Uޞt0iu?d eJd;ې'Ŷ5"W`kFz֎Ä 9om |/k$wo_?W)iD4YҶ@-!PP{S窻EGI3 ir _7`[,nc~Ku2`HW|K"~ e M6`.ܤrB~KSٴ"vm#kdayOz!\ ķZ魅4{7콡]ɬ2Ɂr>Z&kY?$KA56Sp4o=ձ(n]r;F15.>!}:GtIaHzO![C3 >.M++n;iakw$J#po<LꊙyF^_;k4vVBtW2YGSx|7(Ear0E<.f\'g MZI;!`sq Lʘ4^3.ې z<&] ̹˩HQ.Rq3S@ unT^ʙ3Cl4noC8QD+SX:z۷+mbɅĘbhtۦ8='Kv++3cخJWr+؝>ose%\FO`ɫ &Mó!\/josOS (Xo{5Ig:\wooHSs~3.L1$-*!5m$6t ̵d]n|>qHX;H2F]ر@&ѡ*/|{%4)s#:U&_ ,̝/?eճF06.kC_ςW2j<J4WtEi+ty evZ6={p k0^E̽Q|Pv.x ZSĔ@>GGeuBZnP`1rFǂq\龤!M=uHbwͼ==ma#%iH 5vkE_/ ٻN1.K fxD1+gKM-+XSL1ǥKbsƵ8ż4I5VSc,Iq&Ӟ+cV3qEbN7iIwL'rA3IcC2}5[Do)tv.\g%崘xY]%b ڛBpO6i )i_L'eDjmQyv7$-bWm1o->0dF*.( (h)\=!u@^o:?]Su hY}ڎ`8)?}]==F\օliJ/u GKd(oGG5JSs>"DY:ɕMf|})Ə |,Eem} >HS ] 41|U˵E$n)MJ~cgK|jφ z%J%iƕ ieg^njr&9<셝kn$2wI/ZոUԐy=ۥn_KmH\2(0G 0tCCh96(咇/G^66v%2ʰWEv)I\a($er)/d]՟Z$Ehn%24X&Uh7=>Z(ר&Pvq XŰhok5uT0]<:߿[Q\}v~0\>=Lb4[ eC^d$]r]Wo/3cyA rs$k\>RN oY G7)g0Q fD]"lOZxʥ Tz?4eɋVE6o= $ꨋ(F^Ze[EtL>?kMd^~q4޻F9OBC/v &V}c0{u/$\bܵMDPrE^{-͵N}@hf7+.׃"Z(`. ') NY9OD _Kd"[Md_TFdxOkzv^o= I߼{,3}$#!u-wf3TYeec()Q\ ze8f+-y5:~DѮ{>WWiЌ1Sֿ^ ,NRO--J -*}Kgzxi{Qg]Yl!4HMoq"7w@ "uGPk)KaCy/F͛VZ`y?e-yg{ز|_u+-y.# aMNK Eu)@督bj{@IdK,>l:x8/}f7XI}3~q)e_=)zh)3Vܣl\y6rDy51u,0!b\, C{@ze"8LVC.s؉EO4 d{&@ƤLVOnliv=` ع4sť }9K|ˆ6eؗ+5vk|nܭ?L yMC]w^OeNܔ^lV6uI5W0rDoc(Qo)^Eo\Ew U [w ʢnoF?չ~ZyjOuʮyG^[.O^S(Q6O~w5&GgR ~,0m'-U}噳Jj 'zk|t8[ɖ+Qp-_ h'v vUO./C` eH !sgY_$\TI!i GDm C{PS.>!)k~vIUJrm:KXN{[V!jQ\NQkNJ9y° /-]s2 #LIJkD\!b}Q累HR+eU38H^ͭEm$3B yTxU#~Lw[};f&21xȭxHW9HaK+. ~b %JWL44RqA>,VAI X>U}+g% TCpüFsTiD~ D [gBhRAn6"_!ߴߗ=>jD@J|IJ4,"-dP,S'tDvcQFFӠZ {u"oOc+3׫;`È$jWj)=ET@г)J8- 6˷oLuwC9tZt|-zNCٝCr_vw?WJ̭ب֧¢\|Uf \'/Y$Yuo*}p*2+Eg4E dXggK< ͊gd(,[1Nd0(I\&CCKjϬ';qg^Oƣ}e̻t?qBi a5Tv ɣr=uN=R}1>qIW0z5aYV1x$|"}%IE{ά8j`xHv'L⎀ͦ 1pC'5{FL<\рO3o^lfԈlo0p _X/ EU&Bͩ|nQxJ,|d[4w16-7`DQZ!duiRiby 1.!q`ڠ ۵\BBxI7);xho&=iH[ƔwMt*,rtsVL^%FC:LY٩k1-יZjuGBJ8*1{(|AJf;^H>$5O}QЧұN_yqi?#\m\r܌',-Ut T,4R&[Ň=HoUt=]yHDL!k;q5>'e'erM3}؋g甥cm[n . :m_ʓ^;;?啢آAr7eM#_܋Qj .'#?1(v4#oå *>n.59:&rRC#ECQo9t3#?YQbx,.mQ$Pi4]~d|' hK|KoD]b5ٞ/bm8ʋ/9To\sv)Z <8)h~YrS#QBW)l5BNu_q&$!bQ'b{,l[\H9]5{pnK5-1dHAU oD>;a_A?zo]!)h6e&<}F?wഩ1 H=y]7~$? beGwƻVحw YLT9nM̱CI2Z(ꚿm}IM&H&)߼gEDN҄|Z Gf'u>uJAel̉G3-~J++{G'.JjI'VI@* 4Osgwݢ\}B]XaON􉕙W!-+z>[=(7D//(%_AGg^n$(b9 #C<^kR82Axt-~ǂ 4we\adܕX35|7 =f/6^Gԍny[] 3|ylK? "׉G%{98Z_lT͛ɜ/eI? endstream endobj 745 0 obj << /Length1 2197 /Length2 11357 /Length3 0 /Length 12655 /Filter /FlateDecode >> stream xڍT6Lww)C7C"%9PC7-ݍtHH#%!! %xιGoZ3ϻQjY@@W6Nv! NjGF rvC0pBeP;%@ pqp,4u[ le MFs& ?_1{3dj f47h@ W (b(zxxڻC^2<u d0@wghtMkr 3؁A.P7 3!Pq9m+nW _Φ{GS/lH+zL,~ڹ@`;S3_i"W(R{{ گ$ s(^O;XXjvrIcY\\in ^ځ#` mA|\LAWg7ϟFh + dv@*Y p@g?#xY@~u@5qE%u;W'.qظx9\~>Q5So_9K@j4b`w,etjACna\&WېoAnvvԦ`; C ]%t T*,ns5.ݿ4] U\זف@k?:jBHA7SJ9C,~/ zP ! P=?%׉D#AP_FoF("P7FQx@߈ B鿈Z9(~Wi\4"^be?_{?@Z9?BNnЁm737?̡YЊ %Y.ʌ5 lefZ(!!'?"C wn-C }&@G+]lBIDqBtM$Th |]= 8@cL{qPo? 4ʌ⠑A4wsR Bdmb.b!V܃mkie32^?ו~.Z9SfIĢK|YĬ/9혧awvrl+T)ۻn+s 8ZI3l$ٟ=;E.;{@5U*kXn\밞!N,A\48F-׆Al`40|Roy/ ]`y%ʒO{a #Mb\5`kz)&HPI}Q*m Cۛ~y"8W2?L&w/h%yǾŬB_/SjW:󺽠0}ϦMYEb@7Nq[R.4eʺ ͦ:FO,)-",ni?͛1~ 9Kmk,fi E3o$Xh>H78XG6 IS'Omcn̎X}gD)h.>/fS Ia\.KȺ+qۋxNo]8wBJ-(MTaDzA_J1h-v+Ѽ(TS5o5zwp3$*f.K9O=k/<92LiZd ܹQS"nuzU#SB |ߨ͡s9RKsݸ+a iipr %lǟig%⇈Q9Pt|a,n;`/<#ܦi.kFtUWn7 2)'J1F-sya &m!VP#TX(6u\ vpS0{.m~^8Sl'5,ՀX=cpaDDE?z'+u2SLFS|ϛ}Ktհ sJ%n8=VBA`(\Gl>Dg҂3f$eD{17GεKO[^[3 j)ǵJlN鱋CUs@*<jweg gPkmpe>Yt]#}:HGSuR_O:;+ _sоGNGVTռʹՇŝuHT"xOp);ofK?!@xUWÏZHZ޾繿Z3j+q xZ„;w> IWњ}KC,,hsOeľ,uC-ZJLGhr J;FbK4,#o ?B)A>oᙢo,|xUpOމ@ a٠qŔH^.]<଍|7$Zܠ4 ;7^ھ[T(~9}q*=uq$B>FM4&RSo9X<SMqv0φ0UӽHT$*slV2eD`aS<ůWؗ58I)n(}sp%T?FkRۼJ h٭tKd-ř {00 6;r0QN[go0`-,I{y\NqJ<,*N?=C\`F=^/"LzoPϓK*+:߻H:i1{%(Xh&gP]qҲ{$/c]z,HA>=Q* P̺s"~T뭤uw4[$'šmlrv(򋑕6g_ ~H,A0S3Db+b $ydìyT)?d*6 5.tʼn,32{` _EZ;_T1L@wbtۺ[&}}C{书HI;eg̴ Y̬W'JU"5UIqNZUK_0IfX_onvO\L;7OGf{fԪMp)D1y+L {%R0'e]I>ngо9aXE6Wyj7=tezTbLgqMLo<">NV[@\|/@nF J{RϾY+5S}V@Zbaۛ\ k"'n57X$v !5qL}|ewg*M!\)^n5l6~Ac7: 5H[kE\DI`-OGj0|V&~FKe}T_'kybfj̉@aܷF5ܫBuj[ZE .(-AAIWZIѓފؕsP~ss]umrKL~ i-Pcp1".ϴe__m[x ߉3,B.x~tt%Y"sJ/exߠy\$*a {Z7^1茂0h]h(Dފ79hH$%'hvL iKamDޅecϹU-r̅ UXc Ch-OOk<0|{e)}Z:Ѹ''ƯKSz WC#* 9@yVM"X+%r) V/Sίl|z9f">KzOO΀^0Q(ٺa,dTET1{mM)Hk+dեޱyN9Vũg"+"#*W[z[#؝Ɏ'%dfFNQ_8)`Vf)Q)`nP3fa1VL)`' 8 rb!<e%NOLnj)"F<,5}7J0_ΥVhb~05qv-ߒ]|ȶthko9AUy0(j0%\+ueTq WWg9 ]䴉ɒd$R0?^ S _3`,</'Dh=:OP/6?F64]ZC2Vd(Km3uFW dwq$5~Ck +5*?qfy- M }ϾHkCRQ̣Y0T0wc)kʤW4:9/.[n[&]6{ac7 fxf/de}=".4)Fsu}D|^u*CN|hdh\"2.$lupzau3SyG՗]ȴcLEw-APWU޽ˋxN’UoPKlY;(Gg5#"-`~XU{a|py3M.MvdڴGH\XEI5x=v[lb"YNҹCM0$Hww=s;wHVcE Ka@~1A L,Qd/_$ j;uMj쥏Ӝ zۢ:eCJ~ɱ<F[⧌jI".~/RHMvWlA{*\`Fź,yK=͜$ UG5d?Bi.BF; V\4ok~oWJ8C+9 M -GUE|9JL7 8-rT\^HDbb9nEg-_qd=bT:R\$ڄ>ln1f0IӉ\+nxŽzORKN%e(i5Q ~zca>oas;z{&ZМY"?7?|]Kxg#_-n-@>*Eɘup,kt lZ̽wM`H}[HWXgo&/,ɋ*Q#SvߗO$/S[%`t n!, JQwyMAsUw^Rrmj?_$a5lRĪL\kHc3WN_WAS~UJNV4^XfW%a~')/ׂ6-,)]_L#UHIn |\q|;L5L`=W{|r%aS?/3M>"asG8!:m{&PX{ȁIp R}v=QnG_ du|$^c[)}v8jb41duD 9Π=srⷋX.a/?p *\qxf.sk$а]Kn**L4XM'7@rM Xˮ$ PN;t&f&gz QS{SW\栉1ye-c[ޤ,X=ivV(w^ uia_,W*ŧOy# B;S۟jS7Agk AEͶ3{'SwZ ~X:_j:.>]<]|~Oրl[ė%4@'U%܌q@͜Eπ8VrH$Ǫ'zexXx~t\X1DLaliqLPB3\ļXq>DI smС_;a+ kĕʳΠqQjX6CmEs&AѬ#ie$wo 訃~du{M-싢}0LקQ%{$^Y? x#%G {04訠KUOxoSF_ArK'DK Z ZHoTA|f8J25CnhlRŕ$_^Vxpi/ֆ\ p,ޗM,sYWiLVTŢ`j<,;%3S pQCS%pq/ 5lDm =lA/lrD]mniiPަ/a [TflqwA_FcqMg(ÛR\_E%gRm<8(5aJdj0Q۽oUõroQ/X6˺G0Mfd>n7FJgQm5Vf 悐d>x3\W~`:MdXJ;)+_H]HÜ|$9;"䕲CТ͹,[PW#V3q8u>߭v/Ti_ d7bKb'֢8k־ď5_y iqR4ϵûNB}#9d"n|喷=Xe#qPVY:loܛSqasZ5Ϡ#}Ӷ<1`fuZf54XT2l`_zi=JIM( tH'.m~M3<|za~&4AHG-eQ[q C#ɂ[=,}MBys*V5;16H_ٮ8+O 8<ƎI<܂#:% ~C$>Sș ]^LGZ$#e݂>yW\"8*P5I=LzȒ5÷R}W>k@\ҬmzWQA7V%︬2ZIYH7rLmZ4&m# zԉ-Ț^)uyd=vD ~Qkd6cۿEIwk%BLG'7r_%/hJFWۣBqlQp(c?֎𸅘u;t!U!38M/-8 .←kuG<&Lzօƽ:fEf1 xlV- t6Q1Fsm:,镺*xl%\ˆ"'3ys2\=y U9(ҁ+ H7yIh~ 3כ~q9O ҸAغt9 RDJd6mE/NоYՆv4?PU;lfL4N;[d 21>cE7.CxPP0r-L畸e5&vJ,g& (rD.-X>*wśݙf򒄣ƾ+ٟ|<|* cf.|LSvkg90TQ,kke ihο1Cv$9.5p Y'o _*Fó>$=dx>w !q>-PT_0Rԯ68ׄ aƮxm!B[ס} &ŧK#PuVNѓ9^*?[y6ֻ(뼶y+;YoqOD^Ow31/\I'xF'*HvѶ!6Sߘ^OfR䰒~IDk~bN5H yɢI򕫴*_^1Ia~nSĔ-hK)eC#f C^U  6/яf/i葇]92`*‚P AyJ Z;xIEk.^.=Pײճi[9]nMkm4B$ʧ]p6QD;Vgr𯉽NjQ+fDe&KQ"wVn}˯u* Reyi~^YXcw~S%Y1 ij*ퟹ ;ܲzTIs]!촓 w' u]QhA.65hϩ+ 2J6[Y-dy١6ډ ?@̮MRm˷}H m$>H݋.R f}lmjMT7WsvuX ׷(F TP)9WSopb})~po-]ز$sNY^  zٵ׿)8-Նx*|mp. 4]ME,:{g7fD1Sj0ҡ"=SAG{;"z=s"eZxB|wũ"-GWWF+#zXPD/bǸZajcޅX?܌ErLֹG}zΛ|0*_P4MY8Ml V%&>{Il~EHڷGOVqY#uLLr]EVy?JWH yWaGONNT,cg38tj[ӾU7Wk<*:upgB~-Ojbmy& ls c3Yza)ᶻ_Hn) d]'zVewƞ6` _iC cgn~3S{|t ﬎>_1ܸ. ն&37 1T1Z~c@(E{kϥJ2 ?*n䖼>Q-bN\4$Ym+.͒W|LZ#A7O!IJ|33FQx#-! U8E'Jb60q3W;?nD};3pycCW竢ϫAbN*a n> stream xڍwX>!5"HnHKJ1`Q҈HH" R!]]ss4D`\h?(  )°8&Tsu{`1 (EDc$075PSF!\ h'O [G 7.,..;( 0PC8VP4z+$!(.st@cleݑX;qCX5 Ԃ9"M ԷCၢm0 38  .eq@m'> NgDH`vt<([ Ԇh`=|@`Hv" ZA8upA:jRW>+Ў>E$m_vGy m(k_X: ήU?I8?6[( @NNN/3 /'i}\`n p, aDgFq =A8_p"Fybʑo(Q"I Kaf&s$駪sՎ.sߌOa]5c7t"ЌT;|KO%sUo_!+*WWZ3(⽸0Dw  zQ|>~Ƹ()73Y~j98hd#٘5#Vk\*Q&̍uzġɻ'x6sD%?NrƸ%Җ[,,1,>xܬ`idyJOÌmYP,Iz!q2lqkܤ`v>()X!:,kGǞƌw([4֒ Ylwu s6++){wY:Et.T%Ѿl+$+ R;ى4R\dÒ􎫐w/VoJw,%q% .f0'"%H>uwύKMqf Kڴ()е {,ɥmCC|Gf"IbkTcS~'ul7@jtkp'-:jeDf>Qjɭvk~v>F3j>USW8b<2 Deޕk襇xSBޅaM5%9ե[݄NL"^Dy-0@D?<4;x@:ޝ^t=S>~V]Xa|,46*QYӔװI @mɕ4{/1Z;#ae١/9D/1=93(;e#EMM N ts!wTL = hTIbw/?kU2+8-tg+Jol_Ǒح-L2-c; (=dv}#Ʌ-+RCL1ԜoX0gy`u '/8ސcVC((~Y^T\٣*gxCl4] ]h$|Z)]j3aA܂Olع#e)r{gv(y,BSɨ\؍uGnwmmF32FY/w7WrDu onEiŗ18b,M'qKh?R HN'̥4@#935Dxa)H`~dqW zβ*~ڹgNwK;P(<.)Q>oD%$֗0.FyG|rrFdK(qs{\#iгaۺg ;Hܚm=O]<$ E):Pbl%lD'Ez3) v| RC姙RGGɤZrC͝_$o}*/Sy6I~YODCu%Oz&wgm.rFh8` $0K Ow-1|B)TgZ/2"oCmb0ҽ>G@wLPyYO2}u@/kjgi=Zg;u)Re R啿#%[uK,~ت {!1,{Z/7c[**acSMf<|" _[V2?W4aLzPt@5*k;s_R@_m)"JڇS<㕅ٳM~+XGqΎ&z/1tA#/z3k7PGK+^3|h}HƆ ͌o^QYJ%D/m}!H'&r9"x`jjkM n!aN;i-Xwf7Ś|P}G/pYvM^=BbzxGyӕ9E"wy loj .L~WchX,XRI nhʡ3A/"SLH_ ./;bO9*ΥIދxHr%۶W^یSSb]?H_ odLeI5R'Do"fTDPpOBCA#S,XIDOvxTeJRpcI>K`HA~AXۛl.IM>Ii/ ? KLg:gҤ7zBmY#~Zkc``)Tc/p$7LcUjJ͑>N`0Ԁ@8O駧q]xD7 +Fyw|'?WzljH=PNZv~_Nu_DW&gy4GZelJ|jO-nד~&Nq{.ItZxӥeUlгB0 |@} l Ck4D-[gm(O QK_K 7v==#@><{+o>k7|fI͙ WStm{DdYD{ńvW(riG&tv@m[++{vD9+zwsdu#?{hD:Q0 X[[H:&KO\W͟?II9ִȟ$TK"d,ɔٗ}Dԧ"Yk1GF|mb`4 PfLZ|!ndۨUKRn{7mvE~?5z'釀,OG\Q>{޽bOV'S<U;"Oxv E(4SGh^lU"΅Z4qM*-uNm]n=:%ѾWB Kʛ:2 bw=ԨUwZ\h4mTկVjy,=>h"Ig]hJASdWWd-5iWVY*74QFۃzgdzSg"[>aʂd_b榣TrOD<-j+5}$k!Ӊsr׊jI:B1\3{߻i[뷗#u~,Y<,=VMqFr%ljw}̓i*_M(mN#nB*K:EV6g t-m މ%hVL,l5rRП [ \gO;Qil{TY 7N(dZ:WEs; ߒ{ㆢ̊#=Pxtk`t6g̕.3{ҭ3;=pE3|:M5"nZYwSD.Լ'%沺U\].=6,{ʩ1PZo6&7UaS1 > stream xڍTZ6LI -2t ݝ 33"  JHttHx}/Z<{ae(A@pC>^8@A@ @031>a#Q2E0e<|>aq>q!]A5Ϫpu; Qa+Ö'&&q f 4H *-Aq!D޼`^4'tA=^Pw- xY0;7 @ aP'ui]56S/߿9 a- v0g(@[Y߆`g< s۠ b(I9N Jp Gzsڢ Np7`C~'tanGD2{( D@cA+`J>=^P"6P{;J Pj _h)s:yy!?@HP ,&0ۓv\QE^ח5P툛@|σב6_j5jd=DM&tGH0j  Bt`H[os:;_:^: <  P5 /D !7TX- HTEH*">PH|t@[qPn/EӹEzA""T~_$/D{p5AQ|ۀoըmNPa +{U "Qo-C P@C] @S?A~@zD?q?MPn3A %QLjRF{oڹB>o!T/ᨍCqKu5*[5ʙ+|HDAoWԜ n"*lQ? n@TqB(rPgA  xބ[7(&P+ވ?y;=?kE%@9 ?W;tȿԽ?Pf a+XZ aS\5%M0iɍ%]_MN& 'ŀXqʙ;v6<RW]]p=Aހ'mIʋ =^XjQQ̎JG,Dz#^+o_ ϖÖvv]O3wS Ӫ[&X)Q_sGrx $b\ [1Uo'f0`+"ڨ4 ; 0|=fV1lw b8N;yrJ¼-ʏ 3 Vj*m5[,I$ -O;]JosRu!6OjG}$^fᤇ=m]MΟǃ>KtEuGӀ6o>РY\IlN*D޵Ln1Ja4G00%4j97: 78ss^u_ hvG] q]~} </L1C8`j>{@ixf`Q7dm s^oҠ9-!a=ʰUhzonGwc9%Vlv42jUa,fng*WnX5JAqNSBqa{f< @{;diK|~ۅi8":ͯ> ynC Y&>p!9J릉p)Tamu!V3q'HGֶ[K^GxB'ヨ0ȶoVA;z/8d vnx6)MIEr /|V`oH8e;_Qx[%|٢9?a OM`5e_N&f07}~ʭoZRO6wm]TInΰKx9_堐[CCDF]bV0v ؜#aaO5w ы !Ih̅aJzo*1E~-86i5(?PMRm,a;Srg'qh)eH&e/ D - d{r&.v2kz'e&^ wb":}>oA0L0Y8/z[0&9T"Kc޼u `r[)s $>!gU^LOoN0юY/=de`?;M?y-ɋWwh,"c`&RX]XK“㕔dtH-ƄiPVMEa=90ya3+p2ꃠ,'b?-GB!~zᔕ7@W.]x8eM~{À,fXY^~l}cԫJtQMLFfJU,KYIpZOK=KwŴeĘ_??{?{S`vBOk(^mפ}sqB}fC] 2&v/,=^lY( ]r\~a^r f\~8blZW97AT/߷gtJpfmVjU:j''Z݆GQLaw L}a"C h?id=3L܈.:EdBA}4xܒF'M/7̞ kK>RCBh`H bM5UNUzyx]OЌrS}|5tyL @m!L m a!ԇv4?d +e.CWRa\?":H j$x@1E~d?99㇤0׈]r/νESGBc6srS'uhOEuce ڲ Z6hJXlVJZgZwXYiX圴~.9K:\/~&7> C> bv[mZjl ^.ѥ%ܹv/S4:jk0j_͚8G6K„Ʊ;)iқHu)`⡌uv8S&ǃkl^6㾕Սi4] $|"K"jSIx'pmL:LM }]7\4hۆ7eݎf7Xs) Jd&镖ݫg6^P^* ѥkc˾"Ġ< / PNv)M-DCFX6? {ȂY?V+Kd[T>AraЛwƕ],9n&u{Ɛd{W]ΎZS+8σ#?n$>x<$,;g!V $iJl-xE $QŅa  Og$m{MwZh?}#-!)_JXJ@dFpe9Z-/̤cɁfT_9%;7Dڶ-iYj-N}<"]pϕPT~mDb}Yl[7d3h HP*Jcd^`'!NcN߆"o9Hh]3WY`m-jowc;ν=jN&a+̈́h7CAmҼyx5WVިj23,XfCBHbXI\X'JF?'Y;ؒC>rV0~w#86רᬖؽR 30dՇIEP|/UiΨ*yfy};Dq}y,aTstr dSs sZN\d3S9^T\o) &8+XLjTޫ-SrGUZ61^j)y9*m߹^0i!y_4lH6b+meC<'eemgCn 6ium\ChsÆQdM&f3hiNߦ&*G4lcFbcsKݾ `@ܐu >-,®^ߟDQi 6ē2̃&K_&z"e:okLXҜ*t~q \[{N9s^B㦪y*|"0QͥV/g@' ;N)S!wu2wRXVNtajDByiOOK㇖QM=N_Ⱦt?f| ~18/.\hZ2zдgj~wLi . a&»E*'O4;t1wҖѡZ'YDfgt=l|oe:؎0qg4jLu,fY6 w9JnRE-woɝ>VHDZ}GN?נsH'\$fj8kô2s>?!lz\~C lC9:3<}zܼmЇz=o؜sFzv7mu:<s$wﰺZEҕ4=#VY{-#A579ጨhK+YnώJoa3ڬ|Oz-Uw @[Nx[APF V%-:_6g5ƠB9t"d  Zuډ}I{WcC{,6G*ɍf]ٲzҖ7\MX24Sc<]jj?gU!߸qEC:&Wf&*0Φ*YvA~#ܓt4%*EP/*+O&R0?GiZ yo.SttP$իDd])\"GRmO_/_ћYy<)fH,ph{[8nz0=]A>B*d[4 %)|i^w$V!P茾L#qڂفlb׆!FxH$ܒ$~rÅbr #G,7E=4e쨣'HW;DcjEKu}3ҁ4UF9cM'/_cw[E3ޕ^\=^D $ x7N'ei<7\tݝ]EQjDyU2H8AU4 \ym3_}:|N4iۅtEkۙ0Μ|"* -~Ewe xtZr2-f.Bp}Ho\kohp#vl̾k%$b좳i7e#(/R Oe̾FZ)WƝzBor% ť,x8^v1,_+d"$C&HL0MPRM_B 1 RUH} {+u__g_Х6hI ;;{3"e?V۞őy{}y_a̕žͥ@KַbW9? ;=%574aP lYEHY$e}a!KRٝ3Ք@OBjT+m:&<3jg饐`X#Cg׬ԋg1[jڏ@kpejʔ>v|6VtyjxBbh Il'"!xH6<sZ!ϒ N|~!KۡoΕ~%4s%QY[QVO?,rH͐ c6\m|awMS Kh&x-4Tt]R;ZItxijT/oԢ0 *xä'D3I}>fɒ֠J: $v>l>y"qa]0EƽFFBށ(Wl^-Vv|d|#;^IC*X \ $OunSQ1i=S{kh/}H LYRQP3]ϹKa3mkz \"NRO~fѣaǵ[?OLWBY[G| *zz 0`M::(uxG|݌6v^Z'zƅs\\LKS1`)*E|v;p42֮BS^sh?~C"2櫓XBKL%.ywZ14]aH uGg8Y#,r Jc.Y4DE:'d.Tp~!RSV䐃&{ asn:.'^^8Oѹ(A>Z bAc{t?RS6a1U-Msٸ]F)rg |I79mzcl^fkڵŔz~.9cB;IRoNtQII` \z3+)mv%v=Ӈ?)ʊǒXZE<xn\ ߰}aN( 5Lׅ,|wcv-3*ѕj~0l)8j0)TQsTC@`T1q 6tێ- 0GޤG:6( qE&-Y %kMSZʕ-G(.Tr~X0^~]q٠'ޚ|-{WflR< d2!Ü?)A&gFPLɖ2ؙgb0Y&Mu+,N!S]24oNABѓ|˭&,@dQa!Cw1>LMx\V#-fCo7aƱ.HTj*ŝrm├ETc)ѷ\~dNJeݹ.m-:IE(]+ȵ~XsxKJ/rhJߑ)+siBw:*p9⃎;ɍ vK b:Ѐhlߨ̼pvJ)b#:4 v]jCY[?T) y'|ڌ- jMVs6*I TcUjSA3e7| v#7+­5Y>52|HGFyͳџ-PEBH$"QF7'|ߺ^%ja&渧"A܄x>2%~-#-+2?nURtݾq -Fp J͟ldPzdbh&wK%5NOaf?r)%ȝq_7(y ꝅ;d*&"asi=t4 \<4@>2r{/<.XǣtƱh$)TfL ‹ >uia81wg]Fc K|}^QT4) c?ױtA+rvjvNJHYr{;>t9eQR2䫤ԟ+R.r->ݡ `?P!MŽ_;gecnRcVzpG %:jYKCxt€t+X'n%y-$ͮ_%z8hh K|5]7+?XWN\"tMuŏ&rd<{W>$In` f Q/%Ͷp)9mrډqִ&RG:tX GZJځ< _u`%%Uй(wO gj t~l@S4@?%'[9]€qܚqm=} |Vjsbo`BqT)Z Ñ\@N+:S7&gRG2bޣ<NoO3i_fVБ2{(1fRW1'uv N:|w#dX)07BRe?\ -,KF>56cخggZgu5c2_k9g[H!a|@ǰHWQ̻x,}yC$Hj"?GUҳ7GؔW"WDRYXHxv?mzj-$3 ptM'鈫-34NUzG6u67o_zuJOkz ev%Le0 xЄBt<\Z//fN231As6Vۛ] 7C9pz̜&[ կ[x)(4da29~{g=G}7o(Y$i)ʒ;"?5*]_E.W1۫KIj -~b?gp۲)Hyۏ;frP1iC|o%Ƶʎ6" ߼*6K/<޾K}Wib-~zHYPnqqR;$S굞O|gٓ(΁];{\l?[Z4B ii|v(LyL6|s}Gφ8;߆`PxQ:$x|LW#JأL|dWB(uPKd bt1{Kk44gubq=vo! cJ,G ]k ewhqix x减M0nuxZ"$_̪jf"A; guǧ6w!|sӞ; KVW{M2AObvj_/3F}NӉdߨu4&H1l=<0fF:9zy@%}x ("GsٝbMq|.?:K_uSNx?NK䫱nZ~B9ǫpod,q#1㵐=X9β5pn+ endstream endobj 751 0 obj << /Length1 2233 /Length2 13419 /Length3 0 /Length 14755 /Filter /FlateDecode >> stream xڍPڶ-!hpwFww w%Xܝ}UUWu昲 PHSU01201 QP#Q@6` _evr6``abC{3 (DllAf掯_1 /w5dl:_O46nіŅځLr4(@oyCk( *6.@ d ;z8M*R[ ocٿ pLAV@,#ldehjWq!%+s0::08~Sdb`kk w~ {k%` &ad˨9Dc*B#3:ؙX@;؜wxU7[_ʿį R-_,EQ#=‡73o&~H"yGxhoDs_+Weq'#y;:E!#Qw0b!bܝ{.lwX@B/@}Yh4Y x1pIޤao:go~Q1>U:g†ݯU6kQ0;9'}4_w}jl\͢MyXPPa;F0_ft\"mKڻi`\,C`]=FoC EV f/IZ){ބM-o{v})jaRQ[>N-4:@zyډf{.,w0]QRhaW2G/pU9k.BKY :bQ>tbp6-m{O[+ڃp,C|R+ TpOR8y L4 5agxntn4v<̳w&6&yB:=!; 5mu=2^5gkwm>pۀ(%`P6Yhgb¯"`QZEpaX^"2wK k,,0 ޠo%?C)PjSVܪEKaOp1u))%{)*q35l Ci棻 !$f9 +u 6(zO; Ԉ"tP)}qE ,@NDju8'2tj#I l@O+ϦЮ*pik_^x3xwz}妤l" dH߾E]J% c+xv:1mMc;]Oq G0B;g:Rx>Dd{3xI ;DbҀI'F$Â?j%|qs9 m3~0+1feB֐V)4I\ ֚`:$TTeqHW-DՃ h_E 7#n9A}mGZPaltl\AWgO⳾b6IoҜ|i=eX"5C{~^N?z<3z1 qR1x8@^_o ӼY5p!a&2םu&xl6=ޤ&BjK^~NBQ$XgbaKnYgY)SV,KBB%❛_ a|0XqʌN#xPRЗџyW< RY0w%S]d_N0wn LqI\a|tRv&|5rD63l%<i9؃G^w ]u3,lgO779GIAуG@va^-pvujNl[& ųT;&R~YhL[Ȼ f68!Hwhv)j=kiE{Sm1(etk3ѱX垟f,9d+HcqѼJaŬ%ξdD+v*f&*nϒN6Ƽ=0(TXW&.c_Wu##Py%h0q}+'&֧Vo ݝl/~[^EIN$xd A}IrAk*UZSnajP +WCA(:pb#N 7AWnפptOLܡ8x q Y,ӥ cKz񌄌ӷzIkX;RyيUޘXs-{247HCL6'}]VpNrS%bMĢd?gt )Qn,8w0h xͮ1R{SHb\激.>GN NT f&q:QsgU~D[jIJ2}RZ| o60 fiubznYoW21몏#GfljI3e̚xAM2D%B2.Z,7 h*#flv  CU=bz!rK:*0p֋[1O7U> b\s$gBS^I2}VcfMJl)\XT;DM:GծZVY UEO\[ 3']=K@?Q',tԧ$K}p A%S^nʳî;&%L!p%Kc *>?S,eHV|]?S~W%HBD`HoھMt~ !4 уn_}GRG{^ԐOw +4$A`?UmjXCX9MEMau_2a1s;SL3$،7ƣƲtr{1 <%Tiz|)qRS뒾C%әkͨةH !3{iȽQ)(3/s.e%ڣ4A@QfTƏ=떡;DAhos]kq?*UhLR[oMy),ы'O2$TPŎ盭}TmN쑅%aMB9}3pSQo01$`?, ~Sjkm*ӧN6[ kulv9xЇ,A^0`+rg˧D`<3AwHRU;+ SJr#aĨ,JZ^OC=9LqC=TM_@u2VS§qj>(*9;v/攜NWe0?gY~nmz9A1BAIP >.$xMߛo8o4]} xcA$_HE *6Q:UM6b G Y8EO;B|xIpe AGH}7V=X{/OCG\ħH>-^fXbe#(X݌bǜ fi9{TfaBsXbsŁMRiW4*K$ADNk>}y6ǧY$&_H2vH[?W'"V~*iw?zWKaTclJ)@HU6%u{@A0$y?b `*?T3ۼ9I'HȬr-/rAnxO>uCNSH#>!OPtKЏDpMGMX&?y} <RjۨS-;jI?) YE@(9i[C@KoFHИ;NK]~Ng4y6M`Ϧ~_7>\CmɆ.A)9]\ŒU u5:›]D+PU#~ǂH[?](SakD}{`Im  V|Պ8سDQŕ^̴<&ƈKՅeEwbzKA&?84fA^:=; ]=9^' SjaOQIfҵɁ/eq7/ưU%; s.s!ybFˀ1:)4DFV-I~8\|G|Q9&k`e ~s*\0$ᤥIt8ȁejuCd{=$=M\Z4(¾z0 TjgŻ=g{Lx t7CL6Wi E0p.$CCIRjxV) ;}ؼuJAI}B5YeQ5MJ=fCUNtd_JȎ擱9,8iܐ"΍>k ˆay:7BkҽG8eԓ&'%v[g& 9lBM58zL?RԚ5tcLڇ:Ƭ ҷU χ GEt 6'Q~nb–En֝Ҷ<"TihbF ^;SK$=m&r 3*CCk\.FcLN2_&<{]E/ü9hCPsz,Sf9WAUMrw;YgԓY{fzyψ}#'5&nj9㫭vT.§yEI~>f k 5Ƴ-q(e>\1&a<ֿlFHi7R˭}#tM!ß䳣koKBh7ώ0Oobt 3 kJ- .Z^z*(P'=Wʪ ~?g vOp"S|to1 Q];#İ ;r9BDB.s\ #2Gb4EEa(D$<^Ybz|At,DGmˁO^#ٌJ>++z)+aGY4'ґg'ƲSboR-,t5fMnuj>k%X(eFs p]M 2v01ζѻNk(izVYzqoqVT~ǝH6SBfdȠgA 08,]Jүj+._\~Xӥn==f`/i-(j!+'z$2h6˞#^:mQ~~|[M_v`MBdv;JsBhڢe7gӃ9H26 oMZ5&hb腪'Ph O[ÛƲGf=Y!Tcy&[g<2J?C8}orsͤZ@0O&e|?[hsCI {޾DJ/( |ix%"b\^g}+(cxI]YMbğ_T&?Pyn_}Moi{=Tz6zX9@Iℨp[9CJVX|؝Ԥի4?gyB!|i⊍N.|(iQk>λ D1S7Gܬ1+02Mw(Ea!YJ~֗.l(QjJǧ>t#aiZbY!Rt=;ehk|$ [,ow VQ/6lΔˇN6I.J"#(S^L9XŃ ߰0; &:[ @rv6*L),OH {h>ogg&,}%(-:8tRrJ=Fv}. K)3GfaBLTj!Qֶ*lIxȨ0S{ԉpLa TaźxOV VEqJc oGD3&\18$~^`m7"ޥTU Z/Zd!Mw[lrcrsFߡ4N4bwݱ[%S!vxC̟ FcayKR_& ܏&w[d[qOc- q,DaqrU\ ,m~d$]ѹzO@6Vϴ⹊ FW{jdC3&& ʿa\Y|0m;s@-ݡt$y"ܒÌ$U٣z;Ei閈tq,-3+mBb25U*1 f8= ~_`'gFPF%#L~YP\xM;\h'uxW(һzk~ǣp -^bc0@)`Q\/?K20 {%}nBlpMtߚ63 U!&~򵌻wtX7䫲QcVY(BtJx :]<Πhyo>#M# $uvI\ͰhYd'9\֟)>jkK<$v`$\k4bC1`tM_vdPpA< ϡxw$t#/["X+vp뤑c5uG3ęB6}!2Ucqş"M."J 8Lk ͲZJN #9}L*ؿ:.[BtZ)v]&T tZW5PՍ5U,G٧8ԛH&P~-#ʇLuow*':L>D3p؏xl)wO_9('G8g9 c `&ik)αö_c>Ir&jYgetqՔ\P HwqG?/]>3DnJzz Y7Er( F!wyw>Srk Fia:w"5<( zLF~[rzs*\6tOKH 427v)RZެlKLRXZ/?cV*kcIEFn2ie~K//JPJ?._ :qޭ=slE0 ڲ63?_1pld~fndgk}LZ`;mZ@VKL {߹9ٞqޏsr 7־o\2SpX$s 1טS 1TP\$_XJQ6%zҮM ށ>碮s3U?*7^51`;Obf͠£xwN{!t>P"W(!Hai5b Q>#\=zQ}I*2I n?bG!`Kgx,Q|O1X(ݦީ1vJ($OwJqsW7{k%Igu&rFo)A 1' ~ߑ+辰|y8{΅إEa Gm\ޔ|3Be4DUmg,qPJ%j.xDD]7"EfhFb;KK< naQ  <fz|nI!htiEM#ꖟN N8bn>YCBBiho-6>$MA9`@ eNjxqI8ү6* +"̎nhZS }9.,[hf P(|u Epp@#(MxgA5Bl;"';"J6\kf+@ jhzyS> '.UQ*ɗKjur9-cJ?3F0i%d&9锱D| A׹=ޥ%&=^ph!^ViX0Un;bd$ڵF!)64[`IOn٥?`cΚyיkz֗Ph d,&I@<NRK5yn(帡Z_C{scN>՘GAMU^+[cdzDhMBWXB27P70vT‚*@1Q>CAվ+B'%Ŏ'|,L݂ [zbauKӧO.8^'b( 8Hg˴ŚX'=NUbC&Du֡󨻮:+evE"c+(A|[x(RӍ:pT.xf͎Z輜<ݜycF2_(u?:]6GmfB7XѣOy[*4aVXnĜ̡}ܳÑ<+wǎHNNU/:ZYWk9 6%}fb| ^ ;/k}?:f(.#E^Uŝ>6fZ۴V*77e;7@!~[|$*1/ C d+|B8$QZ'wSFdLyư]X7բdE 4[ň"n቞P˫0{X-;G{0N<2UOՊYX'~3E~̎lj%ZSƗqz2ۙأGmS6$&$+į24VG<Nx4Δ[&;B8LF5bB7g%x$0Sq[ x-xeӵlUC S2H&MR &/(r\Xv;-8Ka6󹜕(r&YZ%k.< C2W:Um y OY= }l {EŔHRB#|.+~J}8mw`jn^]d:I !s;|d[p\J#QvHHiSd V p)rEWҪճG5'*_) >rShA(l rύ) :m?:i.ExKM+랏Ś%h^ͻQUi 9 rYB.0! fKx)AH>e-%k.Λwf _[Rp&<O֧4[uEzB9&rE5q`}WS{ZagLdž]73V ޣy^~eCQYhUQqi7S.B0-6ͭt z9^-v[%B$MMltؒ7͜9MpXC#Xmx_$bzf}zؒ=UZ(}Y q0x{Ǡ_?*1n^ȼ KaFj{ł"Ϥ0D^OhzuR V7ݟ :^1( Ɩp~{>"Pml}2U۽h[o20/M/C##c4 2!I ,hO١"41-:j Z>ӣG%;ը!a-uywr.+6x4NZE17>^?J%h,u w" EآU2㈅:yy _ޏ3>:[*H$>x@F,syaXHt7̘_ rOAwmVN#/T: /Š", 0KjˣY<p&8/#탩}v"LutR3l;m*D]:5_Zt$yOxlujukLV.WWtNk:̮Kvr]2ߺW'x(4VOj,F{,xXȋ.7ϣTl]Ros뽚 qmG1c,e}(o CuWLчBBO3#7ğSԴ^3ŞI<^I7ԉŏH[G{īMcԱ(IGBpR,<ONl'm$_(R۞kqFnHN'vJ_ IPs+rL"cv /dW1 LeQ1GsƮ TLoyA xПS6ty$Q*b(2)\5H3SM~~6g&{C`faf$Qd3a외 :$;cU_΅6kr3Zɐ@XKd>nHa X=[k%%CT}A6+2[Ou5EenaV 1p$V3> p6%6^= "ڷ Moj٬ػ#c6l` s1MbT{lD:!RFt}: M mcw٭BjlU>h}4Z{0S1)GjjhA͚rJvPFt4 Ɍu9 ~/NumonMW*irsCz1A˻b+ =+1>L3[G0mrqҙ";y/=xnpAiތc(5_6+pj--<*FNjxD͂Uٷ␶F:EKKϢ< :a۴!sCۖ d޴j=xf(j^{(GB~ >$diV B]@nu[C^%.<2VPet}wюq% wԆR=*:5drAJ6;Ѩݫyܟ_N6N89Y_ =xڕ X85"LpM!!j(506. endstream endobj 658 0 obj << /Type /ObjStm /N 100 /First 896 /Length 2819 /Filter /FlateDecode >> stream x[kS_~tHi4 2|ؘ 16]l00g V~{is2c)sA0%#.#N{^(5zͤä eR+Ǥqtg Lz .2b^Xq0L{ cf=茔P>0Ȍ. fQ2C$+jf" eVI5b`pIC`t tȞ%^E I # Ӆk=La7|wu0&z|w<ӧBWؔvH7 oq!?eܱ7$AQ׌ f2fjzgv(0"#z֣IpB݂/XQSDQtqD[3 I㑲ߒ:2]\ &\\Ŕd zYs N ѷrqi1e4zN+p+M"M5$TTgjp_W+"^TzFPzS4K?D@5 Q 8ar<(y֋MDǣ&!<&2bqtxh!!9@waqi{+H8 p+(@E/F HQDʹ;{!$Hyn"]]?^0S8b-*LjhA?֤'A0Q}x{@PP@((  UĂ*bAXPE,b X/f~BeU#Bn>= } ؠ ؠ ؠA?έ>֥}C+C{@t˧dAYЀԥ7w/d ?UO~7"/} xL? AAAqCǚ>.ɇ=;5:YQXVrMiڣ*3^U FVÕd>knϢ!.y\Z$pqB,Cd%aű$ɳ*/έN"vI)SYA6FSZKM/.$M#KyiEޣ WhB ItfU2-4> !!-04O]Yu̧pNfY3*o'P,c*5 D^Êb!Iޒz*cgI+zn_PzAtYj̉;ӀZE8|zi`UűK (y& tYϭf:W,($Yǥ1%ZjC΅Bҧ^-/JK (BJ0 ӗOpmA>H&{N}}389H&D҇/z8oN f05gz.%-'mt~UFQeܴڢoâR0J(j=Q`l˹MJ%$WŷƟ]l~o[ =6ݰ-q}=;1?ui=O[~2s$?6#>Ʉ F M7dp2c>9?Vi7`|χ 5w!oOO`>|Nۦc>?n?v|)F(?Uau2j6թJSU5,D՘H(H1\,FKZ̟)4<(v_z\J8=Zwv=ReOi>r>j v8|2'~M;_J%H5wX&˖X?aA.K% mKZvZgj}'&PsJA%lYD_M_z tUȻ5tZ wBH){i}]X6;.Q&@kJP]s{;I_]>] az;8=F;h'_  Iz ¯Ȗe,ȗJ.(`oaYY/J6/ݿH_+[Ȳ,E/w7T藤+%͂ts /פeU8˄sR?=x3G5^,Oɜ}L8/ endstream endobj 770 0 obj << /Author(Herv\351 Pag\350s hpages@fredhutch.org)/Title(10 things \(maybe\) you didn't know about GenomicRanges, Biostrings, and Rsamtools)/Subject()/Creator(LaTeX with Beamer class version 3.36)/Producer(pdfTeX-1.40.16)/Keywords() /CreationDate (D:20171030190259-04'00') /ModDate (D:20171030190259-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian) kpathsea version 6.2.1) >> endobj 754 0 obj << /Type /ObjStm /N 20 /First 170 /Length 888 /Filter /FlateDecode >> stream xڝVn0 +tl[LJe(0lumml3mS4HQI(IH=|Oi: t.8):/;Xr!:t.y=Tw&,QSr%%R q>#$t)B4&9zqNw:GrH#qKcj Z$14G.ME8D7pPd˧t :yi}sć5ר5\GG5eDm̪3F!նeFӄ:Hi4Dv3۾BD{~8}/+O :Hk^y,(F{F1iuu@TN: ڥ*m+@;h6h$mV{vbuĥllNg1?#@~%{6 oL+41)zӰ_nb7eoe_ԧ_p_<  gg= x(^Kԅ%(((((!#(%'()+(-/*//*/ /*//*//*//*//*//*ixS?91}I endstream endobj 771 0 obj << /Type /XRef /Index [0 772] /Size 772 /W [1 3 1] /Root 769 0 R /Info 770 0 R /ID [<95FAF192BCDD557F91C07A470E858AB9> <95FAF192BCDD557F91C07A470E858AB9>] /Length 1639 /Filter /FlateDecode >> stream x%׹I}o}g@BvHH %  A"{e"sӟSJA;r74̑2OKyrZrh*jȘ̒2G#" w!`''21%e̕y2_B^4yڑү-e\VJY%e Y'elMYV&e4N9+{d2rPa9"G䄜SrZȤ9Y7?'O\rE5.7ܒ2%wܓ@#y,BNgl\:J^y+|BSFn؈hD4"FDsoѶd,q`h04 C`h04 CC-}K,Ac C`h04 C`h04~}̠ H D4"FD#шhD4"FD#шhɜI36>(ZH"FD#шhD4"ɋ&21Ogˆ~s?'e,E1\"TrY!+e5V;dl9}߾F9.[dlCv.-{d2rPsxT ٜ/; 凧rN(\1.7ܒG/HwHy*dZ y)8= 퇎CgCP:9,X(k`k2G BD!Q(D" BD!Q(D" e,~ӷI Cl" BD!Q(D" BD!Q(D P`(0 CP`(0 C Pf~k|E/_L~yП4Mճ'.tS9z˜OѬ<0юvd#hGF;2Q?hGF;#ȃ3)V+V. endstream endobj startxref 136426 %%EOF GenomicRanges/inst/extdata/0000755000175400017540000000000013175713746016746 5ustar00biocbuildbiocbuildGenomicRanges/inst/extdata/feature_frags.txt0000644000175400017540000000043313175713746022324 0ustar00biocbuildbiocbuildRefSeqID targetName strand blockSizes queryStart targetStart XM_001065892.1 chr4 + 127,986, 0,127, 124513961,124514706, XM_578205.2 chr2 - 535,137,148, 0,535,672, 155875533,155879894,155895543, NM_012543.2 chr1 + 506,411,212,494, 0,506,917,1129, 96173572,96174920,96176574,96177991, GenomicRanges/inst/scripts/0000755000175400017540000000000013175713746017003 5ustar00biocbuildbiocbuildGenomicRanges/inst/scripts/timing_overlaps.R0000644000175400017540000000744613175713746022343 0ustar00biocbuildbiocbuild### ========================================================================= ### Timing findOverlaps() and summarizeOverlaps() ### ------------------------------------------------------------------------- library(RNAseqData.HNRNPC.bam.chr14) bamfile <- RNAseqData.HNRNPC.bam.chr14_BAMFILES[1] library(GenomicAlignments) reads <- readGAlignments(bamfile) reads_grl <- grglist(reads) library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene exbygene <- exonsBy(txdb, by="gene") ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Timing findOverlaps,GRangesList,GRangesList method ### system.time(hits1 <- findOverlaps(exbygene, reads_grl)) #digest(hits1) # "42f770fcf1a2f27f2ceeb18249244677" # With BioC 3.0 / R 3.1 # --------------------- # First time: # user system elapsed # 1.999 0.020 2.022 # Subsequent times: # user system elapsed # 0.852 0.000 0.854 # With BioC 3.1/ R 3.2 # -------------------- # First time: # user system elapsed # 0.797 0.008 0.806 # Subsequent times: # user system elapsed # 0.141 0.000 0.141 system.time(hits2 <- findOverlaps(exbygene, reads_grl, ignore.strand=TRUE)) #digest(hits2) # "3f1a62b338d431ef2705602ce6dfbf9a" # With BioC 3.0 / R 3.1 # --------------------- # First time: # user system elapsed # 3.605 0.020 3.629 # Subsequent times: # user system elapsed # 1.152 0.000 1.154 # With BioC 3.1/ R 3.2 # -------------------- # First time: # user system elapsed # 1.244 0.008 1.254 # Subsequent times: # user system elapsed # 0.170 0.000 0.171 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Timing findOverlaps,GRangesList,GAlignments method ### system.time(hits3 <- findOverlaps(exbygene, reads)) #digest(hits3) # "42f770fcf1a2f27f2ceeb18249244677" # With BioC 3.0 / R 3.1 # --------------------- # First time: # user system elapsed # 3.844 0.016 3.864 # Subsequent times: # user system elapsed # 1.093 0.000 1.095 # With BioC 3.1/ R 3.2 # -------------------- # First time: # user system elapsed # 1.792 0.008 1.802 # Subsequent times: # user system elapsed # 0.366 0.000 0.367 system.time(hits4 <- findOverlaps(exbygene, reads, ignore.strand=TRUE)) #digest(hits4) # "3f1a62b338d431ef2705602ce6dfbf9a" # With BioC 3.0 / R 3.1 # --------------------- # First time: # user system elapsed # 5.075 0.004 5.084 # Subsequent times: # user system elapsed # 2.642 0.012 2.658 # With BioC 3.1/ R 3.2 # -------------------- # First time: # user system elapsed # 1.766 0.004 1.771 # Subsequent times: # user system elapsed # 0.396 0.000 0.397 ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Timing summarizeOverlaps,GRangesList,GAlignments method ### system.time(se1 <- summarizeOverlaps(exbygene, reads)) #digest(assay(se1)) # "7e58dc4eb0c56fbf75ff86c09dbafb90" # With BioC 3.0 / R 3.1 # --------------------- # First time: # user system elapsed # 3.815 0.012 3.831 # Subsequent times: # user system elapsed # 1.361 0.000 1.363 # With BioC 3.1/ R 3.2 # -------------------- # First time: # user system elapsed # 1.783 0.004 1.789 # Subsequent times: # user system elapsed # 0.436 0.004 0.441 system.time(se2 <- summarizeOverlaps(exbygene, reads, ignore.strand=TRUE)) #digest(assay(se2)) # "7d473582932ee5704acbddd1ffc5c146" # With BioC 3.0 / R 3.1 # --------------------- # First time: # user system elapsed # 5.545 0.020 5.570 # Subsequent times: # user system elapsed # 2.614 0.000 2.617 # With BioC 3.1/ R 3.2 # -------------------- # First time: # user system elapsed # 2.489 0.004 2.495 # Subsequent times: # user system elapsed # 0.490 0.008 0.498 GenomicRanges/inst/unitTests/0000755000175400017540000000000013175713746017316 5ustar00biocbuildbiocbuildGenomicRanges/inst/unitTests/test_GNCList-class.R0000644000175400017540000001366313175713746023057 0ustar00biocbuildbiocbuild### findOverlaps_GNCList <- GenomicRanges:::findOverlaps_GNCList ### We need some of the helper functions defined for the NCList unit tests ### in IRanges. source(system.file("unitTests", "test_NCList-class.R", package="IRanges")) .get_query_overlaps2 <- function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "extend", "equal"), ignore.strand=FALSE) { ok <- .get_query_overlaps(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type) ok <- ok & seqnames(query) == seqnames(subject) if (ignore.strand || as.logical(strand(query) == "*")) return(ok) ok & (strand(subject) == "*" | strand(query) == strand(subject)) } ### Redefine the .findOverlaps_naive() function we got from sourcing ### test_NCList-class.R above. .findOverlaps_naive <- function(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "extend", "equal"), select=c("all", "first", "last", "arbitrary", "count"), ignore.strand=FALSE) { type <- match.arg(type) select <- match.arg(select) hits_per_query <- lapply(seq_along(query), function(i) which(.get_query_overlaps2(query[i], subject, maxgap=maxgap, minoverlap=minoverlap, type=type, ignore.strand=ignore.strand))) hits <- .make_Hits_from_q2s(hits_per_query, length(subject)) selectHits(hits, select=select) } test_GNCList <- function() { x <- GRanges(Rle(c("chrM", "chr1", "chrM", "chr1"), 4:1), IRanges(1:10, width=5, names=LETTERS[1:10]), strand=rep(c("+", "-"), 5), score=seq(0.7, by=0.045, length.out=10)) gnclist <- GNCList(x) checkTrue(is(gnclist, "GNCList")) checkTrue(validObject(gnclist, complete=TRUE)) checkIdentical(granges(x), granges(gnclist)) checkIdentical(x, granges(gnclist, use.mcols=TRUE)) checkIdentical(length(x), length(gnclist)) checkIdentical(names(x), names(gnclist)) checkIdentical(seqnames(x), seqnames(gnclist)) checkIdentical(start(x), start(gnclist)) checkIdentical(end(x), end(gnclist)) checkIdentical(width(x), width(gnclist)) checkIdentical(ranges(x), ranges(gnclist)) checkIdentical(ranges(x, use.names=FALSE), ranges(gnclist, use.names=FALSE)) checkIdentical(ranges(x, use.mcols=TRUE), ranges(gnclist, use.mcols=TRUE)) checkIdentical(strand(x), strand(gnclist)) checkIdentical(seqinfo(x), seqinfo(gnclist)) checkIdentical(x, as(gnclist, "GRanges")) checkIdentical(x[-6], as(gnclist[-6], "GRanges")) } test_findOverlaps_GNCList <- function() { q_ranges <- IRanges(-3:7, width=3) s_ranges <- IRanges(rep.int(1:6, 6:1), c(0:5, 1:5, 2:5, 3:5, 4:5, 5)) query <- GRanges( Rle(c("chr1", "chr2", "chrM"), rep(length(q_ranges), 3)), rep(q_ranges, 3), strand=Rle(c("+", "+", "-"), rep(length(q_ranges), 3))) subject <- GRanges( Rle(c("chr1", "chr2", "chrM"), rep(length(s_ranges), 3)), rep(s_ranges, 3), strand=Rle(c("+", "-", "*"), rep(length(s_ranges), 3))) for (ignore.strand in c(FALSE, TRUE)) { target0 <- .findOverlaps_naive(query, subject, ignore.strand=ignore.strand) current <- findOverlaps_GNCList(query, GNCList(subject), ignore.strand=ignore.strand) checkTrue(.compare_hits(target0, current)) current <- findOverlaps_GNCList(GNCList(query), subject, ignore.strand=ignore.strand) checkTrue(.compare_hits(target0, current)) current <- findOverlaps_GNCList(query, subject, ignore.strand=ignore.strand) checkTrue(.compare_hits(target0, current)) ## Shuffle query and/or subject elements. permute_input <- function(q_perm, s_perm) { q_revperm <- integer(length(q_perm)) q_revperm[q_perm] <- seq_along(q_perm) s_revperm <- integer(length(s_perm)) s_revperm[s_perm] <- seq_along(s_perm) target <- remapHits(target0, Lnodes.remapping=q_revperm, new.nLnode=length(q_perm), Rnodes.remapping=s_revperm, new.nRnode=length(s_perm)) current <- findOverlaps_GNCList(query[q_perm], GNCList(subject[s_perm]), ignore.strand=ignore.strand) checkTrue(.compare_hits(target, current)) current <- findOverlaps_GNCList(GNCList(query[q_perm]), subject[s_perm], ignore.strand=ignore.strand) checkTrue(.compare_hits(target, current)) current <- findOverlaps_GNCList(query[q_perm], subject[s_perm], ignore.strand=ignore.strand) checkTrue(.compare_hits(target, current)) } q_perm <- rev(seq_along(query)) s_perm <- rev(seq_along(subject)) permute_input(q_perm, seq_along(subject)) # reverse query permute_input(seq_along(query), s_perm) # reverse subject permute_input(q_perm, s_perm) # reverse both set.seed(97) for (i in 1:17) { ## random permutations q_perm <- sample(length(query)) s_perm <- sample(length(subject)) permute_input(q_perm, seq_along(subject)) permute_input(seq_along(query), s_perm) permute_input(q_perm, s_perm) } } } GenomicRanges/inst/unitTests/test_GRanges-class.R0000644000175400017540000004462313175713746023142 0ustar00biocbuildbiocbuild### .TARGET_names <- letters[1:10] .TARGET_seqlevels <- c("chr1", "chr2", "chr3", "chrX") .TARGET_seqnames <- Rle(factor(c("chr1", "chr2", "chr1", "chr3"), levels=.TARGET_seqlevels), c(1, 3, 2, 4)) .TARGET_start <- 1:10 .TARGET_end <- rep(10L, 10) .TARGET_ranges <- IRanges(.TARGET_start, .TARGET_end, names=.TARGET_names) .TARGET_strand <- Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)) .TARGET_mcols <- DataFrame(score=1:10, GC=seq(1, 0, length=10)) .TARGET_seqlengths <- c(120L, NA, 80L, 50L) names(.TARGET_seqlengths) <- .TARGET_seqlevels .TARGET_seqinfo <- Seqinfo(seqnames=.TARGET_seqlevels, seqlengths=.TARGET_seqlengths) .make_TARGET_GRanges <- function() { new("GRanges", seqnames=.TARGET_seqnames, ranges=.TARGET_ranges, strand= .TARGET_strand, elementMetadata=.TARGET_mcols, seqinfo=.TARGET_seqinfo) } test_GRanges_construction <- function() { checkException(GRanges(letters), silent = TRUE) checkException(GRanges(ranges = IRanges(1:10, 1:10)), silent = TRUE) checkException(GRanges(letters, IRanges(1:10, 1:10)), silent = TRUE) checkException(GRanges(letters, IRanges(1:26, 1:26), strand = letters), silent = TRUE) checkException(GRanges(letters, IRanges(1:26, 1:26), score = 1:10), silent = TRUE) checkException(GRanges(letters, IRanges(1:26, 1:26), start = 1:26), silent = TRUE) checkException(GRanges(letters, IRanges(1:26, 1:26), end = 1:26), silent = TRUE) checkException(GRanges(letters, IRanges(1:26, 1:26), width = 1:26), silent = TRUE) checkException(GRanges(letters, IRanges(1:26, 1:26), element = letters), silent = TRUE) checkException(GRanges(c(letters, NA), IRanges(1:27, 1:27)), silent = TRUE) checkTrue(validObject(new("GRanges"))) checkTrue(validObject(GRanges())) checkTrue(validObject(GRanges(letters, IRanges(1:26, 1:26)))) checkTrue(validObject(GRanges(letters, IRanges(1:26, 1:26), score = 1:26))) checkTrue(validObject(GRanges(factor(letters), IRanges(1:26, 1:26)))) checkTrue(validObject(GRanges(1:10, IRanges(1:10, 1:10)))) current_seqnames <- S4Vectors:::decodeRle(.TARGET_seqnames) current_strand <- Rle(c("-", "+", "*", "+", "-"), c(1, 2, 2, 3, 2)) current <- GRanges(seqnames=current_seqnames, ranges=.TARGET_ranges, strand=current_strand, seqlengths=.TARGET_seqlengths, score=1:10, GC=seq(1, 0, length=10)) checkIdentical(.make_TARGET_GRanges(), current) ## Call with unnamed 'seqnames', 'ranges', and 'strand' args. current <- GRanges(current_seqnames, .TARGET_ranges, current_strand, seqlengths=.TARGET_seqlengths, score=1:10, GC=seq(1, 0, length=10)) checkIdentical(.make_TARGET_GRanges(), current) ## Call with unnamed metadata cols. score <- 1:10 GC <- seq(1, 0, length=10) current <- GRanges(.TARGET_seqnames, .TARGET_ranges, .TARGET_strand, seqlengths=.TARGET_seqlengths, score, GC) checkIdentical(.make_TARGET_GRanges(), current) ## Call with 'c' metadata col. current <- GRanges(seqnames=.TARGET_seqnames, ranges=.TARGET_ranges, strand=.TARGET_strand, c=LETTERS[1:10]) checkIdentical(DataFrame(c=LETTERS[1:10]), mcols(current)) seqinfo <- Seqinfo(letters, rep(1000L, length(letters))) checkIdentical(seqinfo(GRanges(seqinfo=seqinfo)), seqinfo) checkIdentical(seqinfo(GRanges(seqlengths = seqlengths(seqinfo))), seqinfo) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Accessors. ### test_GRanges_length <- function() { checkIdentical(length(.TARGET_ranges), length(.make_TARGET_GRanges())) } test_GRanges_names <- function() { ## names() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(NULL, names(gr0)) checkIdentical(.TARGET_names, names(gr1)) ## names() setter names(gr0) <- names(gr0) # no-op checkIdentical(GRanges(), gr0) names(gr1) <- names(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) checkException(names(gr1) <- letters, silent = TRUE) names(gr1) <- NULL checkIdentical(NULL, names(gr1)) } test_GRanges_seqnames <- function() { ## seqnames() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(Rle(factor()), seqnames(gr0)) checkIdentical(.TARGET_seqnames, seqnames(gr1)) ## seqnames() setter seqnames(gr0) <- seqnames(gr0) # no-op checkIdentical(GRanges(), gr0) seqnames(gr1) <- seqnames(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) checkException(seqnames(gr0) <- NULL, silent=TRUE) checkException(seqnames(gr1) <- NULL, silent=TRUE) checkException(seqnames(gr1) <- letters, silent=TRUE) } test_GRanges_ranges <- function() { ## ranges() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(IRanges(), ranges(gr0)) checkIdentical(.TARGET_ranges, ranges(gr1)) ## ranges() setter ranges(gr0) <- ranges(gr0) # no-op checkIdentical(GRanges(), gr0) ranges(gr1) <- ranges(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) checkException(ranges(gr0) <- NULL, silent=TRUE) checkException(ranges(gr1) <- NULL, silent=TRUE) checkException(ranges(gr1) <- IRanges(1:26, 1:26), silent=TRUE) val <- IRanges(1:length(gr1), width=10) ranges(gr1) <- val checkIdentical(ranges(gr1), val) } test_GRanges_start <- function() { ## start() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(integer(), start(gr0)) checkIdentical(.TARGET_start, start(gr1)) ## start() setter start(gr0) <- start(gr0) # no-op checkIdentical(GRanges(), gr0) start(gr1) <- start(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) #checkException(start(gr0) <- NULL, silent=TRUE) this actually works! checkException(suppressWarnings(start(gr1) <- letters), silent=TRUE) #checkException(start(gr1) <- 1:26, silent=TRUE) this actually works! start(gr1) <- as.numeric(seq_len(length(gr1))) checkIdentical(seq_len(length(gr1)), start(gr1)) } test_GRanges_end <- function() { ## end() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(integer(), end(gr0)) checkIdentical(.TARGET_end, end(gr1)) ## end() setter end(gr0) <- end(gr0) # no-op checkIdentical(GRanges(), gr0) end(gr1) <- end(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) #checkException(end(gr0) <- NULL, silent=TRUE) this actually works! checkException(suppressWarnings(end(gr1) <- letters), silent=TRUE) #checkException(end(gr1) <- 1:26, silent=TRUE) this actually works! end(gr1) <- as.numeric(10L + seq_len(length(gr1))) checkIdentical(10L + seq_len(length(gr1)), end(gr1)) } test_GRanges_width <- function() { ## width() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(integer(), width(gr0)) checkIdentical(.TARGET_end - .TARGET_start + 1L, width(gr1)) ## width() setter width(gr0) <- width(gr0) # no-op checkIdentical(GRanges(), gr0) width(gr1) <- width(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) #checkException(width(gr0) <- NULL, silent=TRUE) this actually works! checkException(suppressWarnings(width(gr1) <- letters), silent=TRUE) #checkException(width(gr1) <- 1:26, silent=TRUE) this actually works! width(gr1) <- as.numeric(10L + seq_len(length(gr1))) checkIdentical(10L + seq_len(length(gr1)), width(gr1)) } test_GRanges_strand <- function() { ## strand() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(Rle(strand()), strand(gr0)) checkIdentical(.TARGET_strand, strand(gr1)) ## strand() setter strand(gr0) <- strand(gr0) # no-op checkIdentical(GRanges(), gr0) strand(gr1) <- strand(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) checkException(strand(gr0) <- NULL, silent=TRUE) checkException(strand(gr1) <- NULL, silent=TRUE) checkException(strand(gr1) <- letters, silent=TRUE) val <- Rle(strand("+"), length(gr1)) strand(gr1) <- val checkIdentical(val, strand(gr1)) strand(gr1) <- "*" checkIdentical(Rle(strand("*"), length(gr1)), strand(gr1)) } test_GRanges_mcols <- function() { ## mcols() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(DataFrame(), mcols(gr0)) checkIdentical(.TARGET_mcols, mcols(gr1)) ## mcols() setter mcols(gr0) <- mcols(gr0) # no-op checkIdentical(GRanges(), gr0) mcols(gr1) <- mcols(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) checkException(mcols(gr1) <- DataFrame(score=letters), silent=TRUE) mcols(gr1) <- NULL checkIdentical(S4Vectors:::make_zero_col_DataFrame(length(gr1)), mcols(gr1)) val <- DataFrame(x=1:length(gr1), y = head(letters, length(gr1))) mcols(gr1) <- val checkTrue(validObject(gr1)) checkIdentical(val, mcols(gr1)) rownames(val) <- names(gr1) checkIdentical(val, mcols(gr1, use.names=TRUE)) mcols(gr1) <- val checkTrue(validObject(gr1)) checkIdentical(val, mcols(gr1, use.names=TRUE)) rownames(val) <- NULL checkIdentical(val, mcols(gr1)) } test_GRanges_seqlevels <- function() { ## seqlevels() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(character(), seqlevels(gr0)) checkIdentical(.TARGET_seqlevels, seqlevels(gr1)) ## seqlevels() setter seqlevels(gr0) <- seqlevels(gr0) # no-op checkIdentical(GRanges(), gr0) seqlevels(gr1) <- seqlevels(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) val <- seqlevels(gr1) val <- sub("^chr", "Chr", val) seqlevels(gr1) <- val checkIdentical(val, seqlevels(gr1)) } test_GRanges_seqlengths <- function() { ## seqlengths() getter gr0 <- GRanges() gr1 <- .make_TARGET_GRanges() checkIdentical(setNames(integer(), character()), seqlengths(gr0)) checkIdentical(.TARGET_seqlengths, seqlengths(gr1)) ## seqlengths() setter seqlengths(gr0) <- seqlengths(gr0) # no-op checkIdentical(GRanges(), gr0) seqlengths(gr1) <- seqlengths(gr1) # no-op checkIdentical(.make_TARGET_GRanges(), gr1) checkException(seqlengths(gr0) <- NULL, silent=TRUE) checkException(seqlengths(gr1) <- NULL, silent=TRUE) checkException(seqlengths(gr1) <- 1:10, silent=TRUE) val <- seqlengths(gr1) val[] <- c(10L, 20L, 30L, 10L) seqlengths(gr1) <- val checkIdentical(val, seqlengths(gr1)) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion. ### test_GRanges_coercion <- function() { ## -- From GRanges to character/factor/data.frame -- ## ## no strand, no score gr <- GRanges(seqnames = factor(c("chr2", "chr11", "chr1"), levels=c("chr1", "chr2", "chr11")), ranges = IRanges(1:-1, c(4:5, -2), names=head(letters, 3))) target1 <- c(a="chr2:1-4", b="chr11:0-5", c="chr1:-1--2") checkIdentical(target1, as.character(gr)) target2 <- factor(target1, levels=target1[c(3, 1, 2)]) checkIdentical(target2, as.factor(gr)) target3 <- data.frame(seqnames = factor(c("chr2", "chr11", "chr1"), levels=c("chr1", "chr2", "chr11")), start = 1:-1, end = c(4:5, -2L), width = c(4L, 6L, 0L), strand = strand(rep("*", 3)), row.names = head(letters, 3), stringsAsFactors = FALSE) checkIdentical(target3, as.data.frame(gr)) ## strand, no score strand(gr) <- strand(c("+", "-", "*")) target1s <- c(a="chr2:1-4:+", b="chr11:0-5:-", c="chr1:-1--2:*") checkIdentical(target1s, as.character(gr)) checkIdentical(target1, as.character(gr, ignore.strand=TRUE)) target2s <- factor(target1s, levels=target1s[c(3, 1, 2)]) checkIdentical(target2s, as.factor(gr)) target3$strand <- strand(c("+", "-", "*")) checkIdentical(target3, as.data.frame(gr)) ## strand, score mcols(gr)$score <- c(10L, 2L, NA) checkIdentical(target1s, as.character(gr)) checkIdentical(target2s, as.factor(gr)) target3$score <- c(10L, 2L, NA) checkIdentical(target3, as.data.frame(gr)) ## no strand, score gr <- unstrand(gr) checkIdentical(target1, as.character(gr)) checkIdentical(target2, as.factor(gr)) target3$strand <- strand("*") checkIdentical(target3, as.data.frame(gr)) ## -- From GRanges to character/factor (continued) -- ## checkIdentical(as.character(gr), as(gr, "character")) checkIdentical(as.factor(gr), as(gr, "factor")) set.seed(555) gr2 <- sample(gr, 100, replace=TRUE) current <- as.factor(gr2) checkTrue(all(as.factor(as.character(gr2)) == current)) checkIdentical(unname(as.character(sort(unique(gr2)))), levels(current)) strand(gr2) <- c("*", "-", "+", "-") current <- as.factor(gr2) checkTrue(all(as.factor(as.character(gr2)) == current)) checkIdentical(unname(as.character(sort(unique(gr2)))), levels(current)) ## -- table() -- ## current <- table(gr2) # same as table(as.factor(gr2)) but much faster target <- table(as.factor(gr2)) dimnames(current) <- unname(dimnames(current)) dimnames(target) <- unname(dimnames(target)) checkIdentical(target, current) ## -- From character/factor to GRanges -- ## x <- c(a="chrX:21-3.5e+03", b="chr1: +21 \t-+30.5:-", c="1:-15--3:*", d="chr..Y:-21..-3:", e="chr1-X: \t 21 .. \t+30 \t\t:+") current <- as(x, "GRanges") target <- GRanges(c("chrX", "chr1", "1", "chr..Y", "chr1-X"), IRanges(c( 21, 21, -15, -21, 21), c(3500, 30, -3, -3, 30), names=letters[1:5]), c("*", "-", "*", "*", "+")) checkIdentical(target, current) checkIdentical(target, as(x, "GenomicRanges")) checkIdentical(unname(target), as(unname(x), "GRanges")) f <- as.factor(x) checkIdentical(target, as(f, "GRanges")) checkIdentical(target, as(f, "GenomicRanges")) checkIdentical(unname(target), as(unname(f), "GRanges")) ## -- Going back and forth between character/factor and GRanges -- ## ## this looses the metadata(), mcols(), and seqinfo() current <- as(as.character(gr2), "GRanges") target <- gr2 mcols(target) <- NULL seqlevels(target) <- seqlevels(current) checkIdentical(target, current) checkIdentical(target, as(as.factor(gr2), "GRanges")) current <- as(as.character(gr2, ignore.strand=TRUE), "GRanges") checkIdentical(unstrand(target), current) ## x <- as.character(gr2) checkIdentical(x, as.character(as(x, "GRanges"))) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Subsetting. ### test_GRanges_subsetting <- function() { ## [ gr <- .make_TARGET_GRanges() checkException(gr[1000], silent = TRUE) checkException(gr["bad"], silent = TRUE) checkIdentical(gr, gr[]) checkIdentical(as.data.frame(gr)[c(1,3,5),], as.data.frame(gr[c(1,3,5)])) checkIdentical(as.data.frame(gr)[c(1,3,5),-7], as.data.frame(gr[c(1,3,5),"score"])) checkIdentical(as.data.frame(gr)[c(1,3,5),-7], as.data.frame(gr[c(1,3,5),1])) checkIdentical(gr, gr[Rle(TRUE)]) ## [<- gr <- .make_TARGET_GRanges() gr[] <- rev(gr) revgr <- rev(.make_TARGET_GRanges()) names(revgr) <- rev(names(revgr)) checkIdentical(gr, revgr) ## window gr <- .make_TARGET_GRanges() checkIdentical(gr[1:3], window(gr, 1, 3)) ## [ by IRanges gr <- .make_TARGET_GRanges() checkIdentical(gr[1:3], gr[IRanges(1, 3)]) checkIdentical(gr[c(1:3, 1:3)], gr[IRanges(c(1,1), c(3,3))]) ## [<- by IRanges gr1 <- .make_TARGET_GRanges() gr1[1:3] <- .make_TARGET_GRanges()[4:6] gr2 <- .make_TARGET_GRanges() gr2[IRanges(1, 3)] <- .make_TARGET_GRanges()[4:6] checkIdentical(gr1, gr2) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Combine and split. ### test_GRanges_combine <- function() { gr1 <- .make_TARGET_GRanges() gr2 <- .make_TARGET_GRanges() ######################################################################### ## An unremarkable combination gc1 <- c(gr1, gr2) checkEquals(start(gc1), c(start(gr1), start(gr2))) checkEquals(end(gc1), c(end(gr1), end(gr2))) ## Check the combined data frames -- the rownaming is different when ## combining using these two strategies, so ignore them for now. vc1 <- as.data.frame(mcols(gc1)) rownames(vc1) <- NULL vc.orig <- as.data.frame(rbind(mcols(gr1), mcols(gr2))) rownames(vc.orig) <- NULL checkIdentical(vc1, vc.orig) ######################################################################### ## Combining GRanges objects with differing metadata columns colnames(mcols(gr1))[1] <- 'illegal' checkException(c(gr1, gr2), silent=TRUE) ## Ignore mcols gc2 <- c(gr1, gr2, ignore.mcols=TRUE) em2 <- mcols(gc2) checkIdentical(nrow(em2), length(gc2)) checkIdentical(ncol(em2), 0L) ######################################################################### ## More testing gr <- .make_TARGET_GRanges() gr2 <- gr names(gr2) <- NULL checkException(c(GRanges(), RangedData()), silent = TRUE) checkException(c(gr, gr[,-1]), silent = TRUE) checkIdentical(as.data.frame(c(gr, gr2), row.names=NULL), rbind(as.data.frame(gr, row.names=NULL), as.data.frame(gr2, row.names=NULL))) checkIdentical(as.data.frame(c(gr2, gr), row.names=NULL), rbind(as.data.frame(gr2, row.names=NULL), as.data.frame(gr, row.names=NULL))) } test_GRanges_split <- function() { gr <- .make_TARGET_GRanges() checkException(split(gr, NULL), silent = TRUE) checkIdentical(split(gr, rep(c("a", "b"), each=5)), GRangesList(a = head(gr, 5), b = tail(gr, 5))) } GenomicRanges/inst/unitTests/test_GRangesList-class.R0000644000175400017540000001614713175713746023776 0ustar00biocbuildbiocbuildmake_test_GRangesList <- function() { GRangesList( a = GRanges( seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), score = 1:10, GC = seq(1, 0, length=10)), b = GRanges( seqnames = Rle(factor(c("chr2", "chr4", "chr5")), c(3, 6, 4)), ranges = IRanges(1:13, width = 13:1, names = tail(letters, 13)), strand = Rle(strand(c("-", "+", "-")), c(4, 5, 4)), seqinfo = Seqinfo(seqnames = paste("chr", c(2L, 4:5), sep="")), score = 1:13, GC = seq(0, 1, length=13)) ) } test_GRangesList_construction <- function() { checkException(GRangesList(IRangesList()), silent = TRUE) checkTrue(validObject(new("GRangesList"))) checkTrue(validObject(GRangesList())) checkTrue(validObject(GRangesList(GRanges()))) checkTrue(validObject(GRangesList(GRanges(), GRanges()))) checkTrue(validObject(GRangesList(list(GRanges(), GRanges())))) checkTrue(validObject(GRangesList(a = GRanges()))) checkTrue(validObject(make_test_GRangesList())) } test_GRangesList_getters <- function() { grl <- make_test_GRangesList() checkIdentical(seqnames(grl), RleList(lapply(grl, seqnames), compress=TRUE)) checkIdentical(ranges(grl), IRangesList(lapply(grl, ranges))) checkIdentical(strand(grl), RleList(lapply(grl, strand), compress=TRUE)) checkIdentical(seqlengths(grl), seqlengths(grl@unlistData)) checkIdentical(mcols(grl, level="within"), SplitDataFrameList(lapply(grl, mcols))) } test_GRangesList_setters <- function() { grl0 <- GRangesList(A=GRanges("chr2", IRanges(3:2, 5)), B=GRanges(c("chr2", "chrMT"), IRanges(7:6, 15)), C=GRanges(c("chrY", "chrMT"), IRanges(17:16, 25)), D=GRanges()) current <- grl0 seqlevels(current, pruning.mode="coarse") <- c("chr2", "chr5") target <- GRangesList(A=GRanges("chr2", IRanges(3:2, 5), seqinfo=Seqinfo(c("chr2", "chr5"))), D=GRanges()) checkIdentical(target, current) current <- grl0 seqlevels(current, pruning.mode="fine") <- c("chr2", "chr5") target <- GRangesList(A=GRanges("chr2", IRanges(3:2, 5), seqinfo=Seqinfo(c("chr2", "chr5"))), B=GRanges("chr2", IRanges(7, 15)), C=GRanges(), D=GRanges()) checkIdentical(target, current) current <- grl0 seqlevels(current, pruning.mode="tidy") <- c("chr2", "chr5") target <- GRangesList(A=GRanges("chr2", IRanges(3:2, 5), seqinfo=Seqinfo(c("chr2", "chr5"))), B=GRanges("chr2", IRanges(7, 15)), D=GRanges()) checkIdentical(target, current) } test_GRangesList_coercion <- function() { ## as.data.frame gr1 <- GRanges(seqnames = c(1,1,2), ranges = IRanges(1:3,4:6, names = head(letters,3)), strand = strand(c("+", "-", "*")), score = c(10L,2L,NA)) gr2 <- GRanges(seqnames = c("chr1", "chr2"), ranges = IRanges(1:2,1:2, names = tail(letters,2)), strand = strand(c("*", "*")), score = 12:13) grl <- GRangesList(a = gr1, b = gr2) df <- data.frame(group = togroup(PartitioningByWidth(grl)), group_name = rep(c("a","b"), c(3, 2)), seqnames = factor(c(1,1,2,"chr1","chr2")), start = c(1:3,1:2), end = c(4:6,1:2), width = c(4L, 4L, 4L, 1L, 1L), strand = strand(c("+", "-", "*", "*", "*")), score = c(10L,2L,NA,12:13), stringsAsFactors = FALSE) checkIdentical(as.data.frame(grl), df) } test_GRangesList_RangesList <- function() { grl <- make_test_GRangesList() checkIdentical(start(grl), IntegerList(lapply(grl, start))) checkIdentical(end(grl), IntegerList(lapply(grl, end))) checkIdentical(width(grl), IntegerList(lapply(grl, width))) ## start checkException(start(GRangesList()) <- NULL, silent = TRUE) checkException(start(make_test_GRangesList()) <- 1:26, silent = TRUE) grl <- make_test_GRangesList() orig <- start(grl) start(grl) <- orig + 1L checkIdentical(start(grl), orig + 1L) ## end checkException(end(GRangesList()) <- NULL, silent = TRUE) checkException(end(make_test_GRangesList()) <- 1:26, silent = TRUE) grl <- make_test_GRangesList() orig <- end(grl) end(grl) <- orig + 1L checkIdentical(end(grl), orig + 1L) ## width checkException(width(GRangesList()) <- NULL, silent = TRUE) checkException(width(make_test_GRangesList()) <- 1:26, silent = TRUE) grl <- make_test_GRangesList() orig <- width(grl) width(grl) <- orig + 1L checkIdentical(width(grl), orig + 1L) } test_GRangesList_Vector <- function() { grl <- make_test_GRangesList() checkIdentical(grl, grl[]) checkIdentical(grl[,"score"], GRangesList(lapply(grl, function(x) x[,"score"]))) checkIdentical(grl[seqnames(grl) == "chr2",], GRangesList(lapply(grl, function(x) x[seqnames(x) == "chr2",]))) checkIdentical(grl[seqnames(grl) == "chr2", "score"], GRangesList(lapply(grl, function(x) x[seqnames(x) == "chr2", "score"]))) checkIdentical(GRangesList(), c(GRangesList(), GRangesList())) checkIdentical(grl, c(grl, GRangesList())) checkIdentical(grl, c(GRangesList(), grl)) GRL <- local({ x <- grl names(x) <- toupper(names(grl)) for (i in seq_len(length(x))) names(x[[i]]) <- toupper(names(grl[[i]])) x }) res <- c(grl, GRL) checkTrue(validObject(res)) ## [ checkIdentical(grl, grl[Rle(TRUE)]) checkIdentical(grl, res[seq_len(length(grl))]) checkIdentical(GRL, res[-seq_len(length(grl))]) ## checkException(c(grl, grl), "c() check for duplicated names", TRUE) checkIdentical(grl, local({ x <- grl x[IRanges(1, 1)] <- grl[IRanges(1, 1)] x }), "[ by IRanges") checkIdentical(grl, local({ x <- grl; x[1] <- grl[1]; x }), "[<- 1") checkIdentical(grl, local({ x <- grl; x[1:2] <- grl[1:2]; x }), "[<- 2") checkIdentical(grl, local({ x <- grl; x[[1]] <- grl[[1]] names(x) <- names(grl) x }), "[[<-, replace") checkIdentical(grl, local({ x <- grl; x[["b"]] <- grl[[2]] names(x) <- names(grl) x }), "[[<-, replace char") checkIdentical(grl, local({ x <- grl[1]; x[[2]] <- grl[[2]] names(x) <- names(grl) x }), "[[<-, extend-by-1") checkIdentical(grl, local({ x <- grl[1]; x[["b"]] <- grl[[2]] names(x) <- names(grl) x }), "[[<-, extend-by-1 char") } GenomicRanges/inst/unitTests/test_GenomicRanges-comparison.R0000644000175400017540000000714613175713746025401 0ustar00biocbuildbiocbuild### make_test_GRanges <- function() GRanges("chr1", IRanges(c(11:13, 13:10, 11:12), width=5, names=LETTERS[1:9]), Rle(strand(c("+", "-", "+", "-")), c(4, 3, 1, 1))) test_is.unsorted_GenomicRanges <- function() { gr <- make_test_GRanges() ## Warning expected checkException(S4Vectors:::errorIfWarning(is.unsorted(gr, na.rm=TRUE)), silent=TRUE) checkTrue(is.unsorted(gr)) checkTrue(is.unsorted(gr, strictly=TRUE)) sorted_gr <- sort(gr) checkTrue(!is.unsorted(sorted_gr)) checkTrue(is.unsorted(sorted_gr, strictly=TRUE)) checkTrue(!is.unsorted(unique(sorted_gr), strictly=TRUE)) ## Ignore the strand checkTrue(is.unsorted(gr, ignore.strand=TRUE)) checkTrue(is.unsorted(gr, strictly=TRUE, ignore.strand=TRUE)) sorted_gr <- sort(gr, ignore.strand=TRUE) checkTrue(is.unsorted(sorted_gr)) checkTrue(!is.unsorted(sorted_gr, ignore.strand=TRUE)) checkTrue(is.unsorted(sorted_gr, strictly=TRUE, ignore.strand=TRUE)) gr2 <- sorted_gr[c(1:2, 7:8)] checkTrue(!is.unsorted(gr2, strictly=TRUE, ignore.strand=TRUE)) checkTrue(is.unsorted(gr2, strictly=TRUE)) } test_order_GenomicRanges <- function() { gr <- make_test_GRanges() target <- c(1L, 8L, 2L, 3L, 4L, 7L, 6L, 5L, 9L) checkTrue(!is.unsorted(gr[target])) checkIdentical(target, order(gr)) target <- c(5L, 9L, 6L, 7L, 3L, 4L, 2L, 1L, 8L) checkTrue(!is.unsorted(gr[rev(target)])) checkIdentical(target, order(gr, decreasing=TRUE)) } test_sort_GenomicRanges <- function() { gr <- make_test_GRanges() sorted_names <- c("A", "H", "B", "C", "D", "G", "F", "E", "I") checkIdentical(gr[sorted_names], sort(gr)) sorted_names <- c("E", "I", "F", "G", "C", "D", "B", "A", "H") checkIdentical(gr[sorted_names], sort(gr, decreasing=TRUE)) ## Ignore the strand sorted_names <- names(sort(unstrand(gr))) checkIdentical(gr[sorted_names], sort(gr, ignore.strand=TRUE)) sorted_names <- names(sort(unstrand(gr), decreasing=TRUE)) checkIdentical(gr[sorted_names], sort(gr, decreasing=TRUE, ignore.strand=TRUE)) } test_rank_GenomicRanges <- function() { gr <- make_test_GRanges() target <- c(1L, 3L, 4L, 4L, 8L, 7L, 6L, 1L, 8L) checkIdentical(target, rank(gr, ties.method="min")) checkIdentical(rank(target), rank(gr)) checkIdentical(rank(target, ties.method="average"), rank(gr, ties.method="average")) checkIdentical(rank(target, ties.method="first"), rank(gr, ties.method="first")) checkIdentical(rank(target, ties.method="last"), rank(gr, ties.method="last")) checkIdentical(rank(target, ties.method="max"), rank(gr, ties.method="max")) checkIdentical(rank(target, ties.method="min"), rank(gr, ties.method="min")) ## Ignore the strand checkIdentical(rank(unstrand(gr)), rank(gr, ignore.strand=TRUE)) checkIdentical(rank(unstrand(gr), ties.method="average"), rank(gr, ties.method="average", ignore.strand=TRUE)) checkIdentical(rank(unstrand(gr), ties.method="first"), rank(gr, ties.method="first", ignore.strand=TRUE)) checkIdentical(rank(unstrand(gr), ties.method="last"), rank(gr, ties.method="last", ignore.strand=TRUE)) checkIdentical(rank(unstrand(gr), ties.method="max"), rank(gr, ties.method="max", ignore.strand=TRUE)) checkIdentical(rank(unstrand(gr), ties.method="min"), rank(gr, ties.method="min", ignore.strand=TRUE)) } GenomicRanges/inst/unitTests/test_coverage-methods.R0000644000175400017540000001144213175713746023736 0ustar00biocbuildbiocbuildmake_test_GRanges <- function() { new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))) } make_test_GRangesList <- function() { GRangesList( a = new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))), b = new("GRanges", seqnames = Rle(factor(c("chr2", "chr4", "chr5")), c(3, 6, 4)), ranges = IRanges(1:13, width = 13:1, names = tail(letters, 13)), strand = Rle(strand(c("-", "+", "-")), c(4, 5, 4)), seqinfo = Seqinfo(seqnames = paste("chr", c(2L, 4:5), sep="")), elementMetadata = DataFrame(score = 1:13, GC = seq(0, 1, length=13)))) } test_coverage_GRanges <- function() { gr <- make_test_GRanges() target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(0:3, c(1, 1, 1, 7)), chr3=Rle(0:4, c(6, 1, 1, 1, 1)), compress=FALSE) checkIdentical(target, coverage(gr)) width <- c(chr1=10, chr2=20, chr3=30) target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(c(0:3, 0L), c(1, 1, 1, 7, 10)), chr3=Rle(c(0:4, 0L), c(6, 1, 1, 1, 1, 20)), compress=FALSE) checkIdentical(target, coverage(gr, width=width)) weight <- list(chr1=1L, chr2=10L, chr3=100L) target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(10L * 0:3, c(1, 1, 1, 7)), chr3=Rle(100L * 0:4, c(6, 1, 1, 1, 1)), compress=FALSE) checkIdentical(target, coverage(gr, weight=weight)) shift <- list(chr1=0, chr2=1, chr3=2) target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(0:3, c(2, 1, 1, 7)), chr3=Rle(0:4, c(8, 1, 1, 1, 1)), compress=FALSE) checkIdentical(target, coverage(gr, shift=shift)) ## with circular sequences gr <- GRanges(seqnames=c("A", "B"), ranges=IRanges(start=5:6, width=7)) gr@seqinfo <- Seqinfo(seqnames=c("A", "B"), seqlengths=c(10, NA), isCircular=c(TRUE, FALSE)) target <- RleList(A=Rle(c(1L, 0L, 1L), c(1, 3, 6)), B=Rle(c(0L, 1L), c(5, 7)), compress=FALSE) checkIdentical(target, coverage(gr)) } test_coverage_GRangesList <- function() { grl <- make_test_GRangesList() target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(c(1L, 3L, 5L, 6L, 3L), c(1, 1, 1, 7, 3)), chr3=Rle(0:4, c(6, 1, 1, 1, 1)), chr4=Rle(0:6, c(3, 1, 1, 1, 1, 1, 5)), chr5=Rle(0:4, c(9, 1, 1, 1, 1)), compress=FALSE) checkIdentical(target, coverage(grl)) width <- c(chr1=10, chr2=20, chr3=30, chr4=40, chr5=50) target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(c(1L, 3L, 5L, 6L, 3L, 0L), c(1, 1, 1, 7, 3, 7)), chr3=Rle(c(0:4, 0L), c(6, 1, 1, 1, 1, 20)), chr4=Rle(c(0:6, 0L), c(3, 1, 1, 1, 1, 1, 5, 27)), chr5=Rle(c(0:4, 0L), c(9, 1, 1, 1, 1, 37)), compress=FALSE) checkIdentical(target, coverage(grl, width=width)) weight <- list(chr1=1L, chr2=10L, chr3=100L, chr4=1000L, chr5=10000L) target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(10L * c(1L, 3L, 5L, 6L, 3L), c(1, 1, 1, 7, 3)), chr3=Rle(100L * 0:4, c(6, 1, 1, 1, 1)), chr4=Rle(1000L * 0:6, c(3, 1, 1, 1, 1, 1, 5)), chr5=Rle(10000L * 0:4, c(9, 1, 1, 1, 1)), compress=FALSE) checkIdentical(target, coverage(grl, weight=weight)) shift <- list(chr1=0, chr2=1, chr3=2, chr4=3, chr5=4) target <- RleList(chr1=Rle(1:3, c(4, 1, 5)), chr2=Rle(c(0L, 1L, 3L, 5L, 6L, 3L), c(1, 1, 1, 1, 7, 3)), chr3=Rle(0:4, c(8, 1, 1, 1, 1)), chr4=Rle(0:6, c(6, 1, 1, 1, 1, 1, 5)), chr5=Rle(0:4, c(13, 1, 1, 1, 1)), compress=FALSE) checkIdentical(target, coverage(grl, shift=shift)) } GenomicRanges/inst/unitTests/test_findOverlaps-methods.R0000644000175400017540000003210513175713746024576 0ustar00biocbuildbiocbuildmake_subject <- function() { new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1), strand = Rle(strand(c("-", "+", "+", "-", "-", "-")), c(1, 2, 1, 1, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))) } make_query <- function() { GRangesList(nomatch = GRanges(seqnames = "chr1", ranges = IRanges(start=5, end=10), strand = "+"), onematch = GRanges(seqnames = "chr3", ranges = IRanges(start=2, end=7), strand = "-"), twomatch = GRanges(seqnames = "chr1", ranges = IRanges(start=1, end=5), strand = "-")) } .checkHits <- function(q_hits, s_hits, q_len, s_len, current, select) { target <- Hits(q_hits, s_hits, q_len, s_len, sort.by.query=TRUE) checkIdentical(t(selectHits(target, select=select)), t(unname(current))) } test_findOverlaps_no_overlaps_returns_empty_matches <- function() { query <- make_query() subject <- make_subject() ranges(subject) <- shift(ranges(subject), 1000L) ## select = "all" for (type in c("any", "start", "end")) { current <- findOverlaps(query, subject, type = type, select = "all") .checkHits(integer(0), integer(0), 3, 10, current, select="all") ans <- countOverlaps(query, subject, type = type) checkIdentical(structure(c(0L, 0L, 0L), names=c("nomatch", "onematch", "twomatch")), ans) ans <- subsetByOverlaps(query, subject, type = type) checkIdentical(query[integer(0)], ans) } ## select = "first" expect <- rep(NA_integer_, length(query)) for (type in c("any", "start", "end")) { ans <- findOverlaps(query, subject, type = type, select = "first") checkIdentical(expect, ans) } } test_findOverlaps_empty_query <- function() { query <- new("GRangesList") subject <- make_subject() ## select = "all" for (type in c("any", "start", "end")) { current <- findOverlaps(query, subject, type = type, select = "all") .checkHits(integer(0), integer(0), 0, 10, current, select="all") ans <- countOverlaps(query, subject, type = type) checkIdentical(integer(0), ans) ans <- subsetByOverlaps(query, subject, type = type) checkIdentical(query, ans) } ## select = "first" expect <- integer() for (type in c("any", "start", "end")) { ans <- findOverlaps(query, subject, type = type, select = "first") checkIdentical(expect, ans) } } test_findOverlaps_empty_subject <- function() { query <- make_query() subject <- new("GRanges") ## select = "all" for (type in c("any", "start", "end")) { current <- findOverlaps(query, subject, type = type, select = "all") .checkHits(integer(0), integer(0), 3, 0, current, select="all") ans <- countOverlaps(query, subject, type = type) checkIdentical(structure(c(0L, 0L, 0L), names=c("nomatch", "onematch", "twomatch")), ans) ans <- subsetByOverlaps(query, subject, type = type) checkIdentical(query[integer(0)], ans) } ## select = "first" expect <- rep(NA_integer_, length(query)) for (type in c("any", "start", "end")) { ans <- findOverlaps(query, subject, type = type, select = "first") checkIdentical(expect, ans) } } test_findOverlaps_zero_one_two_matches <- function() { query <- make_query() subject <- make_subject() ## select = "all" ansAny <- findOverlaps(query, subject, type="any", select="all") ansStart <- findOverlaps(query, subject, type="start", select="all") ansEnd <- findOverlaps(query, subject, type="end", select="all") .checkHits(c(2, 3, 3), c(7, 1, 5), 3, 10, ansAny, select="all") .checkHits(3, 1, 3, 10, ansStart, select="all") .checkHits(integer(0), integer(0), 3, 10, ansEnd, select="all") countsAny <- countOverlaps(query, subject, type="any") countsStart <- countOverlaps(query, subject, type="start") countsEnd <- countOverlaps(query, subject, type="end") .checkHits(c(2, 3, 3), c(7, 1, 5), 3, 10, countsAny, select="count") .checkHits(3, 1, 3, 10, countsStart, select="count") .checkHits(integer(0), integer(0), 3, 10, countsEnd, select="count") subsetAny <- subsetByOverlaps(query, subject, type="any") subsetStart <- subsetByOverlaps(query, subject, type="start") subsetEnd <- subsetByOverlaps(query, subject, type="end") checkIdentical(query[countsAny > 0], subsetAny) checkIdentical(query[countsStart > 0], subsetStart) checkIdentical(query[countsEnd > 0], subsetEnd) ## select = "first" ansAny <- findOverlaps(query, subject, type="any", select="first") ansStart <- findOverlaps(query, subject, type="start", select="first") ansEnd <- findOverlaps(query, subject, type="end", select="first") .checkHits(c(2, 3, 3), c(7, 1, 5), 3, 10, ansAny, select="first") .checkHits(3, 1, 3, 10, ansStart, select="first") .checkHits(integer(0), integer(0), 3, 10, ansEnd, select="first") } test_findOverlaps_multimatch_within_one_query <- function() { query <- make_query() query[[3L]] <- c(query[[3L]], query[[3L]]) subject <- make_subject() ## select = "all" ansAny <- findOverlaps(query, subject, type="any", select="all") ansStart <- findOverlaps(query, subject, type="start", select="all") ansEnd <- findOverlaps(query, subject, type="end", select="all") .checkHits(c(2, 3, 3), c(7, 1, 5), 3, 10, ansAny, select="all") .checkHits(3, 1, 3, 10, ansStart, select="all") .checkHits(integer(0), integer(0), 3, 10, ansEnd, select="all") countsAny <- countOverlaps(query, subject, type="any") countsStart <- countOverlaps(query, subject, type="start") countsEnd <- countOverlaps(query, subject, type="end") .checkHits(c(2, 3, 3), c(7, 1, 5), 3, 10, countsAny, select="count") .checkHits(3, 1, 3, 10, countsStart, select="count") .checkHits(integer(0), integer(0), 3, 10, countsEnd, select="count") subsetAny <- subsetByOverlaps(query, subject, type="any") subsetStart <- subsetByOverlaps(query, subject, type="start") subsetEnd <- subsetByOverlaps(query, subject, type="end") checkIdentical(query[countsAny > 0], subsetAny) checkIdentical(query[countsStart > 0], subsetStart) checkIdentical(query[countsEnd > 0], subsetEnd) ## select = "first" ansAny <- findOverlaps(query, subject, type="any", select="first") ansStart <- findOverlaps(query, subject, type="start", select="first") ansEnd <- findOverlaps(query, subject, type="end", select="first") .checkHits(c(2, 3, 3), c(7, 1, 5), 3, 10, ansAny, select="first") .checkHits(3, 1, 3, 10, ansStart, select="first") .checkHits(integer(0), integer(0), 3, 10, ansEnd, select="first") } test_findOverlaps_either_strand <- function() { query <- make_query() subject <- make_subject() query@unlistData@strand <- Rle(strand(c("*", "*", "-"))) ## select = "all" ansAny <- findOverlaps(query, subject, type="any", select="all") ansStart <- findOverlaps(query, subject, type="start", select="all") ansEnd <- findOverlaps(query, subject, type="end", select="all") .checkHits(c(1, 1, 1, 2, 3, 3), c(1, 5, 6, 7, 1, 5), 3, 10, ansAny, select="all") .checkHits(c(1, 3), c(5, 1), 3, 10, ansStart, select="all") .checkHits(c(1, 1, 1), c(1, 5, 6), 3, 10, ansEnd, select="all") countsAny <- countOverlaps(query, subject, type = "any") countsStart <- countOverlaps(query, subject, type = "start") countsEnd <- countOverlaps(query, subject, type = "end") .checkHits(c(1, 1, 1, 2, 3, 3), c(1, 5, 6, 7, 1, 5), 3, 10, countsAny, select="count") .checkHits(c(1, 3), c(5, 1), 3, 10, countsStart, select="count") .checkHits(c(1, 1, 1), c(1, 5, 6), 3, 10, countsEnd, select="count") subsetAny <- subsetByOverlaps(query, subject, type = "any") subsetStart <- subsetByOverlaps(query, subject, type = "start") subsetEnd <- subsetByOverlaps(query, subject, type = "end") checkIdentical(query[countsAny > 0], subsetAny) checkIdentical(query[countsStart > 0], subsetStart) checkIdentical(query[countsEnd > 0], subsetEnd) # select = "first" ansAny <- findOverlaps(query, subject, type="any", select="first") ansStart <- findOverlaps(query, subject, type="start", select="first") ansEnd <- findOverlaps(query, subject, type="end", select="first") .checkHits(c(1, 1, 1, 2, 3, 3), c(1, 5, 6, 7, 1, 5), 3, 10, ansAny, select="first") .checkHits(c(1, 3), c(5, 1), 3, 10, ansStart, select="first") .checkHits(c(1, 1, 1), c(1, 5, 6), 3, 10, ansEnd, select="first") } test_findOverlaps_minoverlap_GRanges_GRangesList <- function() { query <- make_subject() subject <- make_query() current <- findOverlaps(query, subject, minoverlap = 5) .checkHits(1, 3, 10, 3, current, select="all") current <- findOverlaps(query, subject, minoverlap = 6) .checkHits(integer(0), integer(0), 10, 3, current, select="all") } test_findOverlaps_minoverlap_GRangesList_GRanges <- function() { subject <- make_subject() query <- make_query() current <- findOverlaps(query, subject, minoverlap = 5) .checkHits(3, 1, 3, 10, current, select="all") current <- findOverlaps(query, subject, minoverlap = 6) .checkHits(integer(0), integer(0), 3, 10, current, select="all") } test_findOverlaps_minoverlap_GRangesList_GRangesList <- function() { query <- make_query() subject <- GRangesList("g1" = make_subject()) current <- findOverlaps(query, subject, minoverlap = 1) .checkHits(c(2, 3), c(1, 1), 3, 1, current, select="all") query <- make_query() subject <- GRangesList("g1" = make_subject()) current <- findOverlaps(query, subject, minoverlap = 6) .checkHits(3, 1, 3, 1, current, select="all") query <- make_query() subject <- GRangesList("g1" = make_subject()) current <- findOverlaps(query, subject, minoverlap = 7) .checkHits(integer(0), integer(0), 3, 1, current, select="all") current <- findOverlaps(subject, query, minoverlap = 6) .checkHits(1, 3, 1, 3, current, select="all") } test_findOverlaps_with_circular_sequences <- function() { gr <- GRanges(seqnames=rep.int("A", 4), ranges=IRanges(start=c(2, 4, 6, 8), width=3)) ## With A of length 9 --> no overlap between last and first ranges. gr@seqinfo <- Seqinfo(seqnames="A", seqlengths=9, isCircular=TRUE) current0 <- findOverlaps(gr, gr) target0_q_hits <- c(1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L) target0_s_hits <- c(1L, 2L, 1L, 2L, 3L, 2L, 3L, 4L, 3L, 4L) .checkHits(target0_q_hits, target0_s_hits, 4, 4, current0, select="all") ## With A of length 8 --> last and first ranges do overlap. gr@seqinfo <- Seqinfo(seqnames="A", seqlengths=8, isCircular=TRUE) current1 <- findOverlaps(gr, gr) .checkHits(c(1, target0_q_hits, 4), c(4, target0_s_hits, 1), 4, 4, current1, select="all") ## With A of length 8 and minoverlap=2 --> no overlap between last ## and first ranges. current2 <- findOverlaps(gr, gr, minoverlap=2) .checkHits(1:4, 1:4, 4, 4, current2, select="all") ## With A of length 7 and minoverlap=2 --> last and first ranges ## do overlap. gr@seqinfo <- Seqinfo(seqnames="A", seqlengths=7, isCircular=TRUE) current3 <- findOverlaps(gr, gr, minoverlap=2) .checkHits(c(1, 1:4, 4), c(4, 1:4, 1), 4, 4, current3, select="all") ## type = "within" q0 <- GRanges("A", IRanges(c(11, 5, 4, 11, 11, 4), c(30, 30, 30, 50, 51, 51))) s0 <- GRanges("A", IRanges(5, width=46)) s0@seqinfo <- Seqinfo(seqnames="A", seqlengths=100, isCircular=TRUE) ## sanity check with linear shift fo0 <- findOverlaps(q0, s0, type="within") expected <- c(1L, 2L, 4L) checkIdentical(queryHits(fo0), expected) A=90 q1 <- shift(q0, A) s1 <- shift(s0, A) fo1 <- findOverlaps(q1, s1, type="within") checkIdentical(queryHits(fo1), expected) ## circular shift n1=-1; n2=0 q2 <- shift(q0, A + 100 * n1) s2 <- shift(s0, A + 100 * n2) fo1 <- findOverlaps(q1, s1, type="within") checkIdentical(queryHits(fo1), expected) ## With A of length 8 --> range 3 is within range 2 gr <- GRanges(seqnames=rep.int("A", 4), ranges=IRanges(start=c(2, 4, 6, 8), width=c(3, 3, 3, 5))) gr@seqinfo <- Seqinfo(seqnames="A", seqlengths=8, isCircular=TRUE) current4 <- findOverlaps(gr, gr, type="within") .checkHits(c(1, 1:4), c(1, 4, 2, 3, 4), 4, 4, current4, select="all") ## With A of length 9 --> range 3 is not within range 2 gr@seqinfo <- Seqinfo(seqnames="A", seqlengths=9, isCircular=TRUE) current5 <- findOverlaps(gr, gr, type="within") .checkHits(1:4, 1:4, 4, 4, current5, select="all") } GenomicRanges/inst/unitTests/test_inter-range-methods.R0000644000175400017540000001303213175713746024353 0ustar00biocbuildbiocbuildmake_test_GRanges <- function() GRanges(Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), IRanges(1:10, width=10:1, names=head(letters, 10)), Rle(c("-", "+", "*", "+", "-"), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10), seqinfo=Seqinfo(paste("chr", 1:3, sep=""))) test_range_GenomicRanges <- function() { gr <- make_test_GRanges() current <- range(gr) target <- GRanges(Rle(c("chr1", "chr2", "chr3"), c(3, 2, 2)), IRanges(start=c(6, 1, 5, 2, 4, 7, 9), end=10), c("+", "-", "*", "+", "*", "+", "-")) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) current <- range(gr, ignore.strand=TRUE) target <- GRanges(c("chr1", "chr2", "chr3"), IRanges(start=c(1, 2, 7), end=10), c("*", "*", "*")) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) # test with.revmap current <- range(gr, with.revmap=TRUE, ignore.strand=TRUE) mcols(target)$revmap <- IntegerList(c(1,5,6), c(2,3,4), c(7:10)) checkIdentical(target, current) } test_range_GRangesList <- function() { gr <- make_test_GRanges() grl <- GRangesList(gr, shift(rev(gr), 5 * seq_along(gr))) for (ignore.strand in c(FALSE, TRUE)) { current <- range(grl, ignore.strand=TRUE) target <- endoapply(grl, range, ignore.strand=TRUE) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) } # test with.revmap obj <- range(grl, with.revmap=TRUE, ignore.strand=TRUE) revmap1 <- mcols(obj[[1]])$revmap revmap2 <- mcols(obj[[2]])$revmap ans1 <- IntegerList(c(1,5,6), c(2,3,4), c(7:10)) ans2 <- IntegerList(c(5,6,10), c(7:9), c(1:4)) checkIdentical(revmap1, ans1) checkIdentical(revmap2, ans2) } test_reduce_GenomicRanges <- function() { gr <- make_test_GRanges() current <- reduce(gr) target <- GRanges(Rle(c("chr1", "chr2", "chr3"), c(3, 2, 2)), IRanges(start=c(6, 1, 5, 2, 4, 7, 9), end=10), c("+", "-", "*", "+", "*", "+", "-")) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) current <- reduce(gr, with.revmap=TRUE) mcols(target)$revmap <- IntegerList(6, 1, 5, 2:3, 4, 7:8, 9:10) checkIdentical(target, current) } test_reduce_GRangesList <- function() { gr <- make_test_GRanges() grl <- GRangesList(gr, shift(rev(gr), 5 * seq_along(gr))) for (with.revmap in c(FALSE, TRUE)) { for (ignore.strand in c(FALSE, TRUE)) { current <- reduce(grl, with.revmap=with.revmap, ignore.strand=ignore.strand) target <- endoapply(grl, reduce, with.revmap=with.revmap, ignore.strand=ignore.strand) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) } } } test_gaps_GenomicRanges <- function() { gr <- make_test_GRanges() current <- gaps(gr, start=1, end=10) target <- GRanges(Rle(c("chr1", "chr2", "chr3"), c(2, 3, 3)), IRanges(start=1, end=c(5, 4, 1, 10, 3, 6, 8, 10)), c("+", "*", "+", "-", "*", "+", "-", "*")) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) } test_disjoin_GenomicRanges <- function() { gr <- make_test_GRanges() current <- disjoin(gr) target <- GRanges(Rle(c("chr1", "chr2", "chr3"), c(3, 3, 4)), IRanges(start=c(6, 1, 5, 2, 3, 4, 7, 8, 9, 10), end=c(10, 10, 10, 2, 10, 10, 7, 10, 9, 10)), c("+", "-", "*", "+", "+", "*", "+", "+", "-", "-")) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) gr <- GRanges(Rle(c("chr1", "chr3"), c(2, 2)), IRanges(c(8, 6, 8, 6), c(11, 15, 11, 15), names=c("k", "l", "m", "n")), c("-", "-", "+", "*"), score=11:14, GC=c(.2, .3, .3, .1)) current <- disjoin(gr) target <- GRanges(Rle(c("chr1", "chr3"), c(3, 2)), IRanges(c(6, 8, 12, 8, 6), c(7, 11, 15, 11, 15)), Rle(c("-", "+", "*"), c(3, 1, 1))) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) current <- disjoin(gr, with.revmap=TRUE) mcols(target)$revmap <- IntegerList(2, 1:2, 2, 3, 4) checkIdentical(target, current) } test_disjoin_GRangesList <- function() { grl <- GRangesList(make_test_GRanges(), GRanges("1", IRanges(1, 10), score=21, GC=.21), GRanges(), GRanges(Rle(c("chr1", "chr3"), c(2, 2)), IRanges(c(8, 6, 8, 6), c(11, 15, 11, 15), names=c("k", "l", "m", "n")), strand(c("-", "-","+","*")), score=41:44, GC=c(.41, .42, .43, .44))) for (with.revmap in c(FALSE, TRUE)) { for (ignore.strand in c(FALSE, TRUE)) { current <- disjoin(grl, with.revmap=with.revmap, ignore.strand=ignore.strand) target <- endoapply(grl, disjoin, with.revmap=with.revmap, ignore.strand=ignore.strand) checkTrue(validObject(current, complete=TRUE)) checkIdentical(target, current) } } } GenomicRanges/inst/unitTests/test_intra-range-methods.R0000644000175400017540000002457113175713746024361 0ustar00biocbuildbiocbuildmake_test_GRanges <- function() { new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))) } make_test_GRangesList <- function() { GRangesList( a = new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))), b = new("GRanges", seqnames = Rle(factor(c("chr2", "chr4", "chr5")), c(3, 6, 4)), ranges = IRanges(1:13, width = 13:1, names = tail(letters, 13)), strand = Rle(strand(c("-", "+", "-")), c(4, 5, 4)), seqinfo = Seqinfo(seqnames = paste("chr", c(2L, 4:5), sep="")), elementMetadata = DataFrame(score = 1:13, GC = seq(0, 1, length=13)))) } test_shift_GenomicRanges <- function() { ## empty, reversibility, recycling 'x' gr <- make_test_GRanges() checkIdentical(shift(GRanges(), 10), GRanges()) checkIdentical(gr, shift(shift(gr, 10), -10)) x <- 1:2 checkIdentical(start(shift(gr[1:4], x)), start(gr[1:4]) + x) ## no seqlength or circularity checkIdentical(start(gr) + 10L, start(shift(gr, 10))) checkIdentical(width(gr), width(shift(gr, 10))) gr <- GRanges("chrA", IRanges(20, 30)) checkIdentical(IRanges(8, 18), ranges(shift(gr, -12))) checkIdentical(IRanges(98, 108), ranges(shift(gr, 78))) ## seqlength and circularity combos gr <- GRanges("chr1", IRanges(5, width=6)) isCircular(gr) <- TRUE checkIdentical(start(shift(gr, -10)), -5L) seqlengths(gr) <- 20 isCircular(gr) <- NA warn <- FALSE res <- withCallingHandlers({ shift(gr, -10) }, warning=function(w) { warn <<- TRUE invokeRestart("muffleWarning") }) checkTrue(warn == TRUE) checkIdentical(start(res), -5L) isCircular(gr) <- FALSE warn <- FALSE res <- withCallingHandlers({ shift(gr, -10) }, warning=function(w) { warn <<- TRUE invokeRestart("muffleWarning") }) checkTrue(warn == TRUE) checkIdentical(start(res), -5L) } test_shift_GRangesList <- function() { grl <- make_test_GRangesList() shifted <- shift(grl, 10) checkIdentical(start(grl) + 10L, start(shifted)) } test_resize_GenomicRanges <- function() { gr <- make_test_GRanges() checkException(resize(gr, 10, fix = "middle"), silent = TRUE) checkException(resize(gr, 10, fix = rep("end", 3)), silent = TRUE) resized <- resize(gr, 10) checkIdentical(rep(10L, length(gr)), width(resized)) checkIdentical(c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 1L, 1L), start(resized)) checkIdentical(ranges(resize(gr, 10, fix = "center")), IRanges(rep(1:5, each=2), width = 10, names = head(letters, 10))) checkIdentical(ranges(resize(gr, 10, fix = c("start", "end"))), IRanges(c(1L, 1L, 3L, 1L, 5L, 1L, 7L, 1L, 1L, 10L), width = 10, names = head(letters, 10))) ## No-ops. checkIdentical(gr, resize(gr, width=width(gr))) checkIdentical(gr, resize(gr, width=width(gr), fix="end")) checkIdentical(gr, resize(gr, width=width(gr), fix="center")) } test_resize_GRangesList <- function() { grl <- make_test_GRangesList() target <- endoapply(grl, resize, width=5) current <- resize(grl, width=5) checkIdentical(target, current) ## No-ops. checkIdentical(grl, resize(grl, width=width(grl))) checkIdentical(grl, resize(grl, width=width(grl), fix="end")) checkIdentical(grl, resize(grl, width=width(grl), fix="center")) } test_flank_GenomicRanges <- function() { checkIdentical(flank(GRanges(), 10), GRanges()) gr_seqnames <- c("chr1", "chr2", "chr1", "chrM") gr_ranges <- IRanges(21:24, width=10) gr_strand <- strand(c("+", "-", "*", "-")) gr <- GRanges(gr_seqnames, gr_ranges, gr_strand) ## NO warning expected. S4Vectors:::errorIfWarning(current <- flank(gr, 10)) checkTrue(S4Vectors:::errorIfWarning(validObject(current))) target_ranges <- IRanges(c(11, 32, 13, 34), width=10) target <- GRanges(gr_seqnames, target_ranges, gr_strand) checkIdentical(target, current) ## NO warning expected. S4Vectors:::errorIfWarning(current <- flank(gr, 10, start=FALSE)) checkTrue(S4Vectors:::errorIfWarning(validObject(current))) target_ranges <- IRanges(c(31, 12, 33, 14), width=10) target <- GRanges(gr_seqnames, target_ranges, gr_strand) checkIdentical(target, current) ## NO warning expected. S4Vectors:::errorIfWarning(current <- flank(gr, 30)) checkTrue(S4Vectors:::errorIfWarning(validObject(current))) target_ranges <- IRanges(c(-9, 32, -7, 34), width=30) target <- GRanges(gr_seqnames, target_ranges, gr_strand) checkIdentical(target, current) ## NO warning expected. S4Vectors:::errorIfWarning(current <- flank(gr, 30, start=FALSE)) checkTrue(S4Vectors:::errorIfWarning(validObject(current))) target_ranges <- IRanges(c(31, -8, 33, -6), width=30) target <- GRanges(gr_seqnames, target_ranges, gr_strand) checkIdentical(target, current) seqlengths(gr) <- c(chr1=60, chr2=50, chrM=35) ## Warning expected. checkException(S4Vectors:::errorIfWarning( current <- flank(gr, 10) ), silent=TRUE) suppressWarnings(current <- flank(gr, 10)) checkException(S4Vectors:::errorIfWarning( validObject(current) ), silent=TRUE) checkTrue(suppressWarnings(validObject(current))) target_ranges <- IRanges(c(11, 32, 13, 34), width=10) checkIdentical(target_ranges, ranges(current)) isCircular(gr) <- c(chr1=NA, chr2=FALSE, chrM=TRUE) ## NO warning expected. S4Vectors:::errorIfWarning(current <- flank(gr, 10)) checkTrue(S4Vectors:::errorIfWarning(validObject(current))) target_ranges <- IRanges(c(11, 32, 13, 34), width=10) checkIdentical(target_ranges, ranges(current)) ## Warning expected. checkException(S4Vectors:::errorIfWarning( current <- flank(gr, 20) ), silent=TRUE) suppressWarnings(current <- flank(gr, 20)) checkException(S4Vectors:::errorIfWarning( validObject(current) ), silent=TRUE) checkTrue(suppressWarnings(validObject(current))) target_ranges <- IRanges(c(1, 32, 3, 34), width=20) checkIdentical(target_ranges, ranges(current)) } test_promoters_GenomicRanges <- function() { checkTrue(length(promoters(GRanges())) == 0) ## upstream / downstream gr <- GRanges("chr1", IRanges(c(5, 10), width=1), "+") target <- GRanges("chr1", IRanges(c(5, 10), width=0), "+") current <- promoters(gr, 0, 0) checkIdentical(target, current) strand(gr) <- c("+", "-") target <- IRanges(c(3, 11), width=2) current <- ranges(promoters(gr, 2, 0)) checkIdentical(target, current) target <- IRanges(c(5, 9), width=2) current <- ranges(promoters(gr, 0, 2)) checkIdentical(target, current) gr <- GRanges("chr1", IRanges(0, width=6), "+") target <- GRanges("chr1", IRanges(-3, 2), "+") current <- promoters(gr, 3, 3) checkIdentical(target, current) checkTrue(validObject(current) == TRUE) gr <- GRanges("chr1", IRanges(rep(10, 3), width=6), c("+", "-", "*")) target <- GRanges("chr1", IRanges(c(7, 13, 7), c(12, 18, 12)), c("+", "-", "*")) current <- suppressWarnings(promoters(gr, 3, 3)) checkIdentical(target, current) ## treat "*" as "+" gr <- GRanges("chr1", IRanges(5, width=6), "+") target <- GRanges("chr1", IRanges(2, 7), "+") current <- promoters(gr, 3, 3) checkIdentical(target, current) strand(gr) <- "*" strand(target) <- "*" current <- suppressWarnings(promoters(gr, 3, 3)) checkIdentical(target, current) ## metadata gr <- GRanges("chr1", IRanges(0, width=6), names="A", strand="+", score=99) current <- promoters(gr, 3, 3) checkIdentical(mcols(gr), mcols(current)) checkIdentical(names(gr), names(current)) checkIdentical(seqinfo(gr), seqinfo(current)) } test_restrict_GenomicRanges <- function() { gr <- make_test_GRanges() st <- structure(c(4,5), names = c("chr1", "chr2")) en <- structure(c(8,9), names = c("chr2", "chr3")) res <- restrict(gr, start = st, end = en) checkIdentical(mcols(gr), mcols(res)) checkIdentical(seqnames(gr), seqnames(res)) checkIdentical(seqinfo(gr), seqinfo(res)) target <- IRanges(start=c(4, 5, 5, 5, 5, 6, 7, 8, 9, 10), end = c(10, 8, 8, 8, 10, 10, 9, 9, 9, 9), names=letters[1:10]) checkIdentical(ranges(res), target) } test_trim_GenomicRanges <- function() { checkIdentical(trim(GRanges()), GRanges()) gr_seqnames <- c("chr1", "chr2", "chr1", "chrM") gr_ranges <- IRanges(0:3, width=30) ## NO warning expected. S4Vectors:::errorIfWarning(gr <- GRanges(gr_seqnames, gr_ranges)) checkTrue(S4Vectors:::errorIfWarning(validObject(gr))) checkIdentical(trim(gr), gr) gr_seqlengths <- c(chr1=50, chr2=NA, chrM=NA) ## Warning expected. checkException(S4Vectors:::errorIfWarning( seqlengths(gr) <- gr_seqlengths ), silent=TRUE) suppressWarnings(seqlengths(gr) <- gr_seqlengths) checkException(S4Vectors:::errorIfWarning( validObject(gr) ), silent=TRUE) checkTrue(suppressWarnings(validObject(gr))) gr <- trim(gr) checkTrue(S4Vectors:::errorIfWarning(validObject(gr))) target_ranges <- IRanges(c(1, 1, 2, 3), width=c(29, 30, 30, 30)) checkIdentical(target_ranges, ranges(gr)) isCircular(gr) <- c(chr1=FALSE, chr2=FALSE, chrM=TRUE) ## NO warning expected. gr_seqlengths <- c(chr1=50, chr2=NA, chrM=15) S4Vectors:::errorIfWarning(seqlengths(gr) <- gr_seqlengths) checkTrue(S4Vectors:::errorIfWarning(validObject(gr))) checkIdentical(trim(gr), gr) } GenomicRanges/inst/unitTests/test_makeGRangesFromDataFrame.R0000644000175400017540000001424713175713746025265 0ustar00biocbuildbiocbuild### test_find_GRanges_cols <- function() { find_GRanges_cols <- GenomicRanges:::.find_GRanges_cols df_colnames <- c("chrom", "start", "end") target <- c(seqnames=1L, start=2L, end=3L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("stop", "start", "Chr") target <- c(seqnames=3L, start=2L, end=1L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("stop", "width", "start", "Chr") target <- c(seqnames=4L, start=3L, end=1L, width=2L, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("strand", "STOP", "START", "chromosome_name") target <- c(seqnames=4L, start=3L, end=2L, width=NA_integer_, strand=1L) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("Seqnames", "strand", "start", "end") target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=2L) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("Seqnames", "strand", "start", "end") target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames, ignore.strand=TRUE) checkIdentical(target, current) df_colnames <- c("seqname", "start", "end") target <- c(seqnames=1L, start=2L, end=3L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("chrom", "strand", "txStart", "txEnd") target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=2L) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("chrom", "strand", "txStart", "txEnd", "txChrom") target <- c(seqnames=5L, start=3L, end=4L, width=NA_integer_, strand=2L) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("strand", "txStart", "txEnd", "txChrom", "txStrand") target <- c(seqnames=4L, start=2L, end=3L, width=NA_integer_, strand=5L) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("chrom", "txStrand", "start", "end") target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("stop", "txEnd", "txStart", "CHR", "start") target <- c(seqnames=4L, start=5L, end=1L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("txEnd", "txStart", "chromosome_name") target <- c(seqnames=3L, start=2L, end=1L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("tx_end", "tx_start", "chrom", "tx_chrom") target <- c(seqnames=4L, start=2L, end=1L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("chrom", "strand", "exon_chrom_start", "exon_chrom_end") target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=2L) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("chrom", "start", "end", "end") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "start", "End", "end") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "start", "end", "stop") checkException(find_GRanges_cols(df_colnames), silent=TRUE) target <- c(seqnames=1L, start=2L, end=4L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames, end.field="stop") checkIdentical(target, current) checkException(find_GRanges_cols(df_colnames, end.field=4), silent=TRUE) df_colnames <- c("chrom", "start", "start", "stop") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "start", "end", "CHR") checkException(find_GRanges_cols(df_colnames), silent=TRUE) target <- c(seqnames=4L, start=2L, end=3L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames, seqnames.field="chr") checkIdentical(target, current) df_colnames <- c("chrom", "start", "end", "chromosome_name") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "tx_start", "tx_end", "exon_start") checkException(find_GRanges_cols(df_colnames), silent=TRUE) target <- c(seqnames=1L, start=2L, end=3L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames, start.field="tx_start", end.field="tx_end") checkIdentical(target, current) df_colnames <- c("chrom", "tx_start", "tx_end", "exon_stop") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "tx_start", "tx_end", "tx_end") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "tx_start", "tx_end", "tx_stop") checkException(find_GRanges_cols(df_colnames), silent=TRUE) df_colnames <- c("chrom", "tx_start", "start", "end") target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames) checkIdentical(target, current) df_colnames <- c("chrom", "strand", "start", "end", "STRAND") checkException(find_GRanges_cols(df_colnames), silent=TRUE) target <- c(seqnames=1L, start=3L, end=4L, width=NA_integer_, strand=NA_integer_) current <- find_GRanges_cols(df_colnames, ignore.strand=TRUE) checkIdentical(target, current) } GenomicRanges/inst/unitTests/test_makeGRangesListFromDataFrame.R0000644000175400017540000001275413175713746026122 0ustar00biocbuildbiocbuild## .TARGET_names <- paste0(letters[1:10], 1L:10L) .TARGET_seqlevels <- c("chr1", "chr2", "chr3", "chrX") .TARGET_seqnames <- Rle(factor(c("chr1", "chr3", "chr1", "chrX"), levels = .TARGET_seqlevels), c(2, 4, 2, 2)) .TARGET_start <- 11:20 .TARGET_end <- 12:21 .TARGET_ranges <- IRanges(.TARGET_start, .TARGET_end, names = .TARGET_names) .TARGET_strand <- Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 3, 2, 2)) .TARGET_mcols <- DataFrame(score = 10:19, GC = seq(1, 0, length = 10)) .TARGET_classifier <- c("a", "a", "b", "b", "c", "c", "d", "d", "a", "b") .TARGET_classifierF <- factor(c("a", "a", "b", "b", "c", "c", "d", "d", "a", "b")) dfr <- data.frame(seqnames = .TARGET_seqnames, .TARGET_ranges, strand = .TARGET_strand, .TARGET_mcols, .TARGET_classifier) dfac <- data.frame(seqnames = .TARGET_seqnames, .TARGET_ranges, strand = .TARGET_strand, .TARGET_mcols, .TARGET_classifierF) DF <- DataFrame(seqnames = .TARGET_seqnames, start = .TARGET_start, end = .TARGET_end, width = width(.TARGET_ranges), names = .TARGET_names, strand = .TARGET_strand, .TARGET_mcols, .TARGET_classifier) DFac <- DataFrame(seqnames = .TARGET_seqnames, start = .TARGET_start, end = .TARGET_end, width = width(.TARGET_ranges), names = .TARGET_names, strand = .TARGET_strand, .TARGET_mcols, .TARGET_classifierF) .make_TARGET_GRangesList_from_dataframe <- function() { makeGRangesListFromDataFrame(dfr, split.field = ".TARGET_classifier", names.field = "names", keep.extra.columns = TRUE) } .make_TARGET_GRangesList_from_DataFrame <- function() { makeGRangesListFromDataFrame(DF, split.field = ".TARGET_classifier", names.field = "names", keep.extra.columns = TRUE) } test_makeGRangesListFromDataFrame <- function() { checkException( makeGRangesListFromDataFrame(dfr, split.field = ".TARGET_classifier", names.field = "Bad_Field"), silent = TRUE) checkException( makeGRangesListFromDataFrame(dfr, split.field = "Bad_Field"), silent = TRUE) checkTrue(validObject( makeGRangesListFromDataFrame(dfr, split.field = ".TARGET_classifier") )) checkTrue(validObject( makeGRangesListFromDataFrame(DF, split.field = ".TARGET_classifier") )) checkTrue(validObject( .make_TARGET_GRangesList_from_dataframe() )) checkTrue(validObject( .make_TARGET_GRangesList_from_DataFrame() )) # Test with factor in data.frame checkTrue(validObject( makeGRangesListFromDataFrame( dfac, split.field = ".TARGET_classifierF", names.field = "names", keep.extra.columns = TRUE) )) # Test with factor in DataFrame checkTrue(validObject( makeGRangesListFromDataFrame( DFac, split.field = ".TARGET_classifierF", names.field = "names", keep.extra.columns = TRUE) )) # Test GRangesList length to split.field unique/level length checkTrue(identical(length(unique(.TARGET_classifier)), length(.make_TARGET_GRangesList_from_dataframe()))) checkTrue(identical(length(levels(.TARGET_classifierF)), length(.make_TARGET_GRangesList_from_dataframe()))) checkTrue(identical(length(unique(.TARGET_classifier)), length(.make_TARGET_GRangesList_from_DataFrame()))) checkTrue(identical(length(levels(.TARGET_classifierF)), length(.make_TARGET_GRangesList_from_DataFrame()))) # Names check with and without keep.extra.columns checkTrue(identical( Reduce(intersect, lapply(.make_TARGET_GRangesList_from_dataframe(), function(x) names(mcols(x)) )), c("score", "GC") )) checkTrue(identical( Reduce(intersect, lapply(.make_TARGET_GRangesList_from_DataFrame(), function(x) names(mcols(x)) )), c("score", "GC") )) checkTrue(identical( Reduce(intersect, lapply( makeGRangesListFromDataFrame(dfr, split.field = ".TARGET_classifier", names.field = "names"), function(x) names(mcols(x)) )), character(0L) )) checkTrue(identical( Reduce(intersect, lapply( makeGRangesListFromDataFrame(DF, split.field = ".TARGET_classifier", names.field = "names"), function(x) names(mcols(x)) )), character(0L) )) } GenomicRanges/inst/unitTests/test_nearest-methods.R0000644000175400017540000002153613175713746023611 0ustar00biocbuildbiocbuildquiet <- suppressWarnings test_GenomicRanges_findNearest0 <- function() { .findNearest <- GenomicRanges:::.GenomicRanges_findNearest0 sentinel <- c(0, 20) subject <- c(5, 15) hits <- .findNearest(10, subject, sentinel, TRUE) checkIdentical(2L, subjectHits(hits)) hits <- .findNearest(10, subject, sentinel, FALSE) checkIdentical(1L, subjectHits(hits)) hits <- .findNearest(5, subject, sentinel, TRUE) checkIdentical(2L, subjectHits(hits)) hits <- .findNearest(15, subject, sentinel, FALSE) checkIdentical(1L, subjectHits(hits)) hits <- .findNearest(5, subject, sentinel, FALSE) checkIdentical(integer(), subjectHits(hits)) hits <- .findNearest(15, subject, sentinel, TRUE) checkIdentical(integer(), subjectHits(hits)) subject <- c(15, 5) hits <- .findNearest(10, subject, sentinel, TRUE) checkIdentical(1L, subjectHits(hits)) hits <- .findNearest(10, subject, sentinel, FALSE) checkIdentical(2L, subjectHits(hits)) } test_GenomicRanges_nearest <- function() { ## adjacent r <- IRanges(c(1,6), c(5,10)) g <- GRanges("chr1", r, "+") checkEquals(follow(r), follow(g)) checkEquals(precede(r), precede(g)) checkEquals(nearest(r), nearest(g)) checkEquals(follow(r,r), follow(g,g)) checkEquals(precede(r,r), precede(g,g)) checkEquals(nearest(r,r), nearest(g,g)) g <- GRanges("chr1", r, "-") checkEquals(follow(r), precede(g)) checkEquals(precede(r), follow(g)) checkEquals(nearest(r), nearest(g)) checkEquals(follow(r,r), precede(g,g)) checkEquals(precede(r,r), follow(g,g)) checkEquals(nearest(r,r), nearest(g,g)) g <- GRanges("chr1", r, "*") checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r,r), nearest(g,g)) ## separated by 1 r <- IRanges(c(1,7), c(5,11)) g <- GRanges("chr1", r, "+") checkEquals(follow(r), follow(g)) checkEquals(precede(r), precede(g)) checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r,r), nearest(g,g)) g <- GRanges("chr1", r, "-") checkEquals(follow(r), precede(g)) checkEquals(precede(r), follow(g)) checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r,r), nearest(g,g)) g <- GRanges("chr1", r, "*") checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r,r), nearest(g,g)) ## separated by > 1 r <- IRanges(c(1,5,10), c(2,7,12)) g <- GRanges("chr1", r, "+") checkEquals(precede(r), precede(g)) checkEquals(follow(r), follow(g)) checkEquals(nearest(r), nearest(g)) g <- GRanges("chr1", r, "-") checkEquals(follow(r), precede(g)) checkEquals(precede(r), follow(g)) checkEquals(nearest(r), nearest(g)) ## overlapping r <- IRanges(c(1,4,8), c(6,10,12)) g <- GRanges("chr1", r, "+") checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r, r), nearest(g, g)) checkEquals(nearest(r, rev(r)), nearest(g, rev(g))) g <- GRanges("chr1", r, "-") checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r, r), nearest(g, g)) checkEquals(nearest(r, rev(r)), nearest(g, rev(g))) g <- GRanges("chr1", r, "*") checkEquals(nearest(r), nearest(g)) checkEquals(nearest(r, r), nearest(g, g)) checkEquals(nearest(r, rev(r)), nearest(g, rev(g))) q <- GRanges("chr1", IRanges(1, 15), "+") s <- GRanges("chr1", IRanges(c(1, 1, 10), c(5, 15, 15)), "+") target <- nearest(q, s, select="arbitrary") checkEquals(3, target) strand(q) <- "-" strand(s) <- "-" target <- nearest(q, s, select="arbitrary") checkEquals(3, target) target1 <- nearest(ranges(q), ranges(s), select="all") target2 <- nearest(q, s, select="all") checkEquals(target1, target2) ## select = 'all' q <- GRanges("chr1", IRanges(1, 1)) s <- GRanges("chr1", IRanges(5, 5), strand="-") target1 <- nearest(ranges(q), ranges(s), select="all") target2 <- nearest(q, s, select="all") checkEquals(target1, target2) ## ignore.strand q <- GRanges("chr1", IRanges(5, width=1), "+") s <- GRanges("chr1", IRanges(c(10, 8), width=1), "-") res <- nearest(q, s, ignore.strand=FALSE) checkEquals(res, NA_integer_) res <- nearest(q, s, ignore.strand=TRUE) checkEquals(res, 2L) q <- GRanges("chr1", IRanges(5, 5)) s <- GRanges("chr1", IRanges(c(6,7), c(6,7)), c("+", "-")) checkEquals(nearest(q, s), 1L) q <- GRanges("chr1", IRanges(105, 105), "-") s <- GRanges("chr1", IRanges(c(1,120), c(100, 125)), c("-", "-")) pos <- nearest(q, s, ignore.strand=TRUE) neg <- nearest(q, s, ignore.strand=FALSE) checkEquals(pos, neg) } test_GenomicRanges_distance <- function() { ## empty checkException(quiet(distance(GRanges())), silent=TRUE) checkIdentical(quiet(distance(GRanges(), GRanges())), integer()) g1 <- GRanges(seqnames = c(rep("chr1", 3), rep("chr2", 2)), ranges = IRanges(rep(1, 5), width=3), strand = c("+", "-", "*", "*", "*")) g2 <- GRanges(seqnames = c(rep("chr1", 3), rep("chr2", 2)), ranges = IRanges(rep(5, 5), width=3), strand = c("+", "-", "*", "-", "+")) current <- quiet(distance(g1, g2)) target <- rep(1L, length(current)) checkIdentical(current, target) strand(g2[1]) <- "-" current <- quiet(distance(g1[1], g2[1])) checkTrue(is.na(current)) seqnames(g2[4]) <- factor("chr1", levels=c("chr1", "chr2")) current <- quiet(distance(g1[4], g2[4])) checkTrue(is.na(current)) ## adjacent, overlap, separated by 1 query <- GRanges("A", IRanges(c(1, 3, 9), c(2, 7, 10))) subject <- GRanges("A", IRanges(c(3, 5, 12), c(3, 6, 12))) checkIdentical(quiet(distance(query, subject)), c(0L, 0L, 1L)) ## recycling checkIdentical(quiet(distance(query[1:2], subject)), c(0L, 0L, 9L)) ## zero-width target <- abs(-3:3) current <- sapply(-3:3, function(i) quiet(distance(shift(IRanges(4,3), i), IRanges(4,3)))) checkIdentical(current, target) query <- GRanges("A", IRanges(4,3)) subject <- GRanges("A", IRanges(3,4)) current <- quiet(distance(query, subject)) checkIdentical(current, 0L) } test_GenomicRanges_distanceToNearest <- function() { target <- Hits(distance=integer(0), sort.by.query=TRUE) current <- quiet(distanceToNearest(GRanges())) checkIdentical(current, target) x <- GRanges("chr1", IRanges(c(1, 5, 10), width=1)) subject <- GRanges("chr1", IRanges(c(3, 12), width=1)) current <- quiet(distanceToNearest(x, subject)) target <- c(1L, 1L, 2L) checkIdentical(target, subjectHits(current)) ## strand strand(x) <- "+" strand(subject) <- c("+", "-") current <- quiet(distanceToNearest(x, subject)) target <- c(1L, 1L, 1L) checkIdentical(target, subjectHits(current)) current <- quiet(distanceToNearest(x, subject, ignore.strand=TRUE)) target <- c(1L, 1L, 2L) checkIdentical(target, subjectHits(current)) ## no self-hits / self-hits current <- quiet(distanceToNearest(x)) target <- c(2L, 1L, 2L) checkIdentical(target, subjectHits(current)) current <- quiet(distanceToNearest(x, x)) target <- c(1L, 2L, 3L) checkIdentical(target, subjectHits(current)) ## ranges start at 0 x <- GRanges("chr1", IRanges(0, width=1)) subject <- GRanges("chr1", IRanges(1, width=1)) current <- distanceToNearest(x, subject) iranges <- distanceToNearest(ranges(x), ranges(subject)) checkIdentical(subjectHits(iranges), subjectHits(current)) checkIdentical(mcols(iranges)$distance, mcols(current)$distance) current <- distanceToNearest(x, x) checkIdentical(1L, subjectHits(current)) checkIdentical(0L, mcols(current)$distance) current <- distanceToNearest(subject, x) iranges <- distanceToNearest(ranges(subject), ranges(x)) checkIdentical(subjectHits(iranges), subjectHits(current)) checkIdentical(mcols(iranges)$distance, mcols(current)$distance) x <- GRanges("chr1", IRanges(c(0, 10, 99), width=1)) subject <- GRanges("chr1", IRanges(15, width=1)) current <- distanceToNearest(x, subject) iranges <- distanceToNearest(ranges(x), ranges(subject)) checkIdentical(subjectHits(iranges), subjectHits(current)) checkIdentical(mcols(iranges)$distance, mcols(current)$distance) ## NA handling x <- GRanges(c("chr1", "chr2"), IRanges(c(1, 5), width=1)) current <- quiet(distanceToNearest(x, x[1])) checkIdentical(1L, queryHits(current)) checkIdentical(1L, subjectHits(current)) checkIdentical(0L, mcols(current)$distance) ## select = 'all' vs 'arbitrary' x <- GRanges("chr1", IRanges(2, width=1)) subject <- GRanges("chr1", IRanges(c(8, 10, 8), width=1)) current <- distanceToNearest(x, subject, select="all") checkTrue(is(current, "Hits")) checkIdentical(length(current), 2L) current <- distanceToNearest(x, GRanges(), select="all") checkIdentical(length(current), 0L) checkIdentical(queryLength(current), 1L) } GenomicRanges/inst/unitTests/test_precede_follow.R0000644000175400017540000003231413175713746023474 0ustar00biocbuildbiocbuildtest_precede_follow_multiple_ranges <- function() { ## query on "+" query <- GRanges("A", IRanges(c(1, 5, 10, 15, 20), width=1), "+") subject <- GRanges("A", IRanges(c(5, 15), width=1), "+") hits <- precede(query, subject) checkIdentical(c(1L, 2L, 2L, NA_integer_, NA_integer_), hits) hits <- follow(query, subject) checkIdentical(c(NA_integer_, NA_integer_, 1L, 1L, 2L), hits) subject <- GRanges("A", IRanges(c(5, 15), width=1), "-") hits <- precede(query, subject) checkIdentical(rep(NA_integer_, length(query)), hits) hits <- follow(query, subject) checkIdentical(rep(NA_integer_, length(query)), hits) subject <- GRanges("A", IRanges(c(5, 15), width=1), "*") hits <- precede(query, subject) checkIdentical(c(1L, 2L, 2L, NA_integer_, NA_integer_), hits) hits <- follow(query, subject) checkIdentical(c(NA_integer_, NA_integer_, 1L, 1L, 2L), hits) ## query on "-" query <- GRanges("A", IRanges(c(1, 5, 10, 15, 20), width=1), "-") subject <- GRanges("A", IRanges(c(5, 15), width=1), "-") hits <- precede(query, subject) checkIdentical(c(NA_integer_, NA_integer_, 1L, 1L, 2L), hits) hits <- follow(query, subject) checkIdentical(c(1L, 2L, 2L, NA_integer_, NA_integer_), hits) subject <- GRanges("A", IRanges(c(5, 15), width=1), "+") hits <- precede(query, subject) checkIdentical(rep(NA_integer_, length(query)), hits) hits <- follow(query, subject) checkIdentical(rep(NA_integer_, length(query)), hits) subject <- GRanges("A", IRanges(c(5, 15), width=1), "*") hits <- precede(query, subject) checkIdentical(c(NA_integer_, NA_integer_, 1L, 1L, 2L), hits) hits <- follow(query, subject) checkIdentical(c(1L, 2L, 2L, NA_integer_, NA_integer_), hits) } test_precede_follow_strand <- function() { subject <- GRanges("chr1", IRanges(rep(1:10, 3), width=1), strand=Rle(strand(c("+", "*", "-")), c(10, 10, 10))) ## 'x' on + strand x <- GRanges("chr1:4-7:+") current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(8L, 18L, 28L), sort(subjectHits(current))) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(3L, 13L, 23L), sort(subjectHits(current))) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(c(8L, 18L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(c(3L, 13L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(c(13L, 23L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(c(18L, 28L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) x <- GRanges("chr1:15-20:+") current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(0L, length(current)) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(10L, 20L, 30L), sort(subjectHits(current))) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(c(10L, 20L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(c(11L, 21L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) ## 'x' on - strand x <- GRanges("chr1:4-7:-") current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(8L, 18L, 28L), sort(subjectHits(current))) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(3L, 13L, 23L), sort(subjectHits(current))) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(c(13L, 23L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(c(18L, 28L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(c(8L, 18L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(c(3L, 13L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) x <- GRanges("chr1:15-20:-") current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(0L, length(current)) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(10L, 20L, 30L), sort(subjectHits(current))) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(c(20L, 30L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(c(1L, 11L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) ## 'x' on * strand (i.e. on *both* strands) x <- GRanges("chr1:4-7") current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(8L, 18L, 28L), sort(subjectHits(current))) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(3L, 13L, 23L), sort(subjectHits(current))) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(c(8L, 18L, 23L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(c(3L, 13L, 28L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(c(8L, 13L, 23L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(c(3L, 18L, 28L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) x <- GRanges("chr1:15-20") current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(0L, length(current)) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(10L, 20L, 30L), sort(subjectHits(current))) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(30L, subjectHits(current)) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(c(10L, 20L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(1L, subjectHits(current)) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(c(11L, 21L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) } test_precede_follow_zero_width_range <- function() { subject <- GRanges("chr1", IRanges(rep(1:10, 3), width=1), strand=Rle(strand(c("+", "*", "-")), c(10, 10, 10))) x <- GRanges("chr1:1-0:-") # zero-width range current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(1L, 11L, 21L), sort(subjectHits(current))) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(0L, length(current)) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(c(11L, 21L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(c(10L, 20L), sort(subjectHits(current))) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) x <- GRanges("chr1:1-0:+") # zero-width range current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(1L, 11L, 21L), sort(subjectHits(current))) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(0L, length(current)) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(c(1L, 11L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(c(20L, 30L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(0L, length(current)) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) x <- GRanges("chr1:1-0") # zero-width range current <- precede(x, subject, select="all", ignore.strand=TRUE) checkIdentical(c(1L, 11L, 21L), sort(subjectHits(current))) target <- precede(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "first"), target) current <- follow(x, subject, select="all", ignore.strand=TRUE) checkIdentical(0L, length(current)) target <- follow(x, subject, ignore.strand=TRUE) checkIdentical(selectHits(current, "last"), target) current <- precede(x, subject, select="all") checkIdentical(c(1L, 11L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, subject)) current <- follow(x, subject, select="all") checkIdentical(21L, subjectHits(current)) checkIdentical(selectHits(current, "last"), follow(x, subject)) current <- precede(x, rev(subject), select="all") checkIdentical(c(20L, 30L), sort(subjectHits(current))) checkIdentical(selectHits(current, "first"), precede(x, rev(subject))) current <- follow(x, rev(subject), select="all") checkIdentical(10L, subjectHits(current)) checkIdentical(selectHits(current, "last"), follow(x, rev(subject))) } GenomicRanges/inst/unitTests/test_setops-methods.R0000644000175400017540000002530113175713746023457 0ustar00biocbuildbiocbuild### make_test_GRanges <- function() { new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3"), levels = paste("chr", 1:5, sep = "")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:5, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))) } make_test_GRangesList <- function() { suppressWarnings(GRangesList( a = new("GRanges", seqnames = Rle(factor(c("chr1", "chr2", "chr1", "chr3")), c(1, 3, 2, 4)), ranges = IRanges(1:10, width = 10:1, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqinfo = Seqinfo(seqnames = paste("chr", 1:3, sep="")), elementMetadata = DataFrame(score = 1:10, GC = seq(1, 0, length=10))), b = new("GRanges", seqnames = Rle(factor(c("chr2", "chr4", "chr5")), c(3, 6, 4)), ranges = IRanges(1:13, width = 13:1, names = tail(letters, 13)), strand = Rle(strand(c("-", "+", "-")), c(4, 5, 4)), seqinfo = Seqinfo(seqnames = paste("chr", c(2L, 4:5), sep="")), elementMetadata = DataFrame(score = 1:13, GC = seq(0, 1, length=13))))) } test_union <- function() { gr <- make_test_GRanges() grlist <- make_test_GRangesList() checkException(union(gr, grlist), silent = TRUE) checkException(union(grlist, gr), silent = TRUE) expect <- gr mcols(expect) <- NULL expect <- reduce(gr) checkIdentical(union(gr, gr), expect) checkIdentical(union(grlist[[1]], grlist[[2]]), reduce(unlist(grlist))) } test_intersect <- function() { gr <- make_test_GRanges() grlist <- make_test_GRangesList() checkException(intersect(gr, grlist), silent = TRUE) checkException(intersect(grlist, gr), silent = TRUE) expect <- gr mcols(expect) <- NULL expect <- reduce(gr) checkIdentical(intersect(gr, gr), expect) checkIdentical(union(grlist[[1]], grlist[[2]]), reduce(unlist(grlist))) gr1 <- GRanges(seqnames = c("chr1", "chr2", "chr3", "chr4"), ranges = IRanges(1:4, width = 10), strand = c("-", "+", "+", "+")) gr2 <- GRanges(seqnames = c("chr1", "chr2", "chr5", "chr6"), ranges = IRanges(1:4, width = 10), strand = c("-", "+", "+", "+")) expect <- GRanges(seqnames = factor(c("chr1", "chr2"), levels = paste("chr", 1:6, sep = "")), ranges = IRanges(1:2, width = 10), strand = c("-", "+")) checkIdentical(suppressWarnings(intersect(gr1, gr2)), expect) ## intersect,GRangesList,GRangesList gr <- make_test_GRanges() grlist <- make_test_GRangesList() expect <- reduce(grlist) mcols(expect) <- NULL checkIdentical(intersect(grlist, grlist), expect) } test_setdiff <- function() { gr <- make_test_GRanges() grlist <- make_test_GRangesList() checkException(setdiff(gr, grlist), silent = TRUE) checkException(setdiff(grlist, gr), silent = TRUE) expect <- GRanges(seqlengths=seqlengths(gr)) checkIdentical(setdiff(gr, gr), expect) checkIdentical(setdiff(grlist[[1]], grlist[[2]]), reduce(grlist[[1]])) gr1 <- GRanges(seqnames = c("chr1", "chr2", "chr3", "chr4"), ranges = IRanges(1:4, width = 10), strand = c("-", "+", "+", "+")) gr2 <- GRanges(seqnames = c("chr1", "chr2", "chr5", "chr6"), ranges = IRanges(1:4, width = 10), strand = c("-", "+", "+", "+")) expect <- GRanges(seqnames = factor(c("chr3", "chr4"), levels = paste("chr", 1:6, sep = "")), ranges = IRanges(3:4, width = 10), strand = c("+", "+")) checkIdentical(suppressWarnings(setdiff(gr1, gr2)), expect) } test_punion <- function() { gr <- make_test_GRanges() grlist <- make_test_GRangesList() expect <- gr mcols(expect) <- NULL checkIdentical(punion(gr, gr), expect) } test_pintersect <- function() { ## pintersect,GRanges,GRanges gr0 <- GRanges() current <- pintersect(gr0, gr0, drop.nohit.ranges=TRUE) target <- gr0 checkIdentical(target, current) current <- pintersect(gr0, gr0) mcols(target)$hit <- logical(0) checkIdentical(target, current) x <- GRanges("chr1", IRanges(c( 4, 13, 2, 9, 16, 9), width=1, names=letters[1:6])) current <- pintersect(x, x) target <- x mcols(target)$hit <- TRUE checkIdentical(target, current) checkIdentical(target, pintersect(x, unname(x))) checkIdentical(unname(target), pintersect(unname(x), x)) current <- suppressWarnings(pintersect(x, GRanges("chrX", ranges(x)))) target <- x mcols(target)$hit <- FALSE width(target) <- 0 checkIdentical(target, current) current <- suppressWarnings(pintersect(x, GRanges("chrX", ranges(x)), drop.nohit.ranges=TRUE)) checkIdentical(x[0], current) y <- x strand(y) <- Rle(strand(c("*", "-", "+")), c(2, 2, 2)) target <- y mcols(target)$hit <- TRUE checkIdentical(target, pintersect(y, y)) checkIdentical(target, pintersect(y, x)) checkIdentical(target, pintersect(x, y)) current <- pintersect(x, y, strict.strand=TRUE) target <- x mcols(target)$hit <- as.logical(strand(x) == strand(y)) width(target)[!mcols(target)$hit] <- 0 checkIdentical(target, current) current <- pintersect(y, x, strict.strand=TRUE) strand(target) <- strand(y) checkIdentical(target, current) strand(x) <- rep(Rle(strand(c("*", "+", "-"))), 2) current <- pintersect(x, y) target <- x mcols(target)$hit <- as.logical(strand(x) == strand(y) | strand(x) == "*" | strand(y) == "*") width(target)[!mcols(target)$hit] <- 0 disambig_strand_idx <- strand(target) == "*" & mcols(target)$hit strand(target)[disambig_strand_idx] <- strand(y)[disambig_strand_idx] checkIdentical(target, current) current <- pintersect(x, y, ignore.strand=TRUE) target <- x mcols(target)$hit <- TRUE checkIdentical(target, current) current <- pintersect(y, x, ignore.strand=TRUE) target <- y mcols(target)$hit <- TRUE checkIdentical(target, current) x <- GRanges("chr1", IRanges( c( 2, 7, 7, 4, 13, 2, 9, 12, 9, 4, 8, 7, 5, 20), c( 6, 8, 12, 10, 12, 2, 12, 18, 8, 12, 11, 11, 11, 20))) y <- GRanges("chr1", IRanges(1, 20)) current <- pintersect(x, y) target <- x mcols(target)$hit <- TRUE checkIdentical(target, current) y <- GRanges("chr1", IRanges(7, 11), strand="+") current <- pintersect(x, y) target <- x ranges(target) <- IRanges( c( 7, 7, 7, 7, 13, 2, 9, 12, 9, 7, 8, 7, 7, 20), c( 6, 8, 11, 10, 12, 1, 11, 11, 8, 11, 11, 11, 11, 19)) mcols(target)$hit <- TRUE nohit_idx <- c(5, 6, 14) mcols(target)$hit <- !(1:14 %in% nohit_idx) strand(target)[mcols(target)$hit] <- strand(y) checkIdentical(target, current) current <- pintersect(x, y, drop.nohit.ranges=TRUE) target <- target[mcols(target)$hit] mcols(target)$hit <- NULL checkIdentical(target, current) ## pintersect,GRangesList,GRanges and pintersect,GRanges,GRangesList x <- GRangesList(x, rev(x)) current <- pintersect(x, y) target <- mendoapply(pintersect, x, as(y, "GRangesList")) checkIdentical(target, current) current <- pintersect(x, y, drop.nohit.ranges=TRUE) target <- mendoapply(pintersect, x, as(y, "GRangesList"), MoreArgs=list(drop.nohit.ranges=TRUE)) checkIdentical(target, current) y <- GRanges("chr1", IRanges(c(1, 7), c(20, 11))) strand(y) <- c("+", "-") current <- pintersect(x, y) target <- mendoapply(pintersect, x, as(y, "GRangesList")) checkIdentical(target, current) checkIdentical(target, pintersect(y, x)) current <- pintersect(x, y, drop.nohit.ranges=TRUE) target <- mendoapply(pintersect, x, as(y, "GRangesList"), MoreArgs=list(drop.nohit.ranges=TRUE)) checkIdentical(target, current) strand(x[[1]]) <- c("+", "-") current <- pintersect(x, y) target <- mendoapply(pintersect, x, as(y, "GRangesList")) checkIdentical(target, current) checkIdentical(target, pintersect(y, x)) current <- pintersect(x, y, drop.nohit.ranges=TRUE) target <- mendoapply(pintersect, x, as(y, "GRangesList"), MoreArgs=list(drop.nohit.ranges=TRUE)) checkIdentical(target, current) checkIdentical(target, pintersect(y, x, drop.nohit.ranges=TRUE)) current <- pintersect(x, y, strict.strand=TRUE) target <- mendoapply(pintersect, x, as(y, "GRangesList"), MoreArgs=list(strict.strand=TRUE)) checkIdentical(target, current) checkIdentical(target, pintersect(y, x, strict.strand=TRUE)) current <- pintersect(x, y, drop.nohit.ranges=TRUE, strict.strand=TRUE) target <- mendoapply(pintersect, x, as(y, "GRangesList"), MoreArgs=list(drop.nohit.ranges=TRUE, strict.strand=TRUE)) checkIdentical(target, current) checkIdentical(target, pintersect(y, x, drop.nohit.ranges=TRUE, strict.strand=TRUE)) current <- reduce(pintersect(x, y, strict.strand=TRUE), drop.empty.ranges=TRUE) target <- mendoapply(intersect, x, as(y, "GRangesList")) checkIdentical(target, current) current <- reduce(pintersect(x, y, ignore.strand=TRUE), drop.empty.ranges=TRUE, ignore.strand=TRUE) target <- mendoapply(intersect, x, as(y, "GRangesList"), MoreArgs=list(ignore.strand=TRUE)) checkIdentical(target, current) } test_psetdiff <- function() { gr <- make_test_GRanges() grlist <- make_test_GRangesList() checkException(psetdiff(grlist, gr), silent = TRUE) expect <- gr width(expect) <- 0L mcols(expect) <- NULL checkIdentical(psetdiff(gr, gr), expect) expect <- gr mcols(expect) <- NULL strand(expect) <- Rle(c("-", "+", "-"), c(1, 7, 2)) end(expect)[5:6] <- c(5, 5) checkIdentical(psetdiff(gr, rev(gr)), expect) expect <- GRangesList(a = GRanges(), b = GRanges(factor("chr2", levels = paste("chr", 1:5, sep = "")), IRanges(2, 10), "+")) checkIdentical(psetdiff(gr[1:2], grlist[1:2]), expect) } GenomicRanges/man/0000755000175400017540000000000013175713746015112 5ustar00biocbuildbiocbuildGenomicRanges/man/DelegatingGenomicRanges-class.Rd0000644000175400017540000000154513175713746023216 0ustar00biocbuildbiocbuild\name{DelegatingGenomicRanges-class} \docType{class} % Class: \alias{class:DelegatingGenomicRanges} \alias{DelegatingGenomicRanges-class} \alias{class:DelegatingGenomicRanges} \alias{DelegatingGenomicRanges-class} % Accessors: \alias{seqnames,DelegatingGenomicRanges-method} \alias{ranges,DelegatingGenomicRanges-method} \alias{strand,DelegatingGenomicRanges-method} \alias{seqinfo,DelegatingGenomicRanges-method} % Coercion: \title{DelegatingGenomicRanges objects} \description{ The \code{DelegatingGenomicRanges} class implements the virtual \code{GenomicRanges} class using a delegate \code{GenomicRanges}. This enables developers to create \code{GenomicRanges} subclasses that add specialized columns or other structure, while remaining agnostic to how the data are actually stored. See the Extending GenomicRanges vignette. } \author{M. Lawrence} GenomicRanges/man/GNCList-class.Rd0000644000175400017540000001161713175713746017755 0ustar00biocbuildbiocbuild\name{GNCList-class} \docType{class} % GNCList objects: \alias{class:GNCList} \alias{GNCList-class} \alias{GNCList} \alias{granges,GNCList-method} \alias{length,GNCList-method} \alias{names,GNCList-method} \alias{seqnames,GNCList-method} \alias{start,GNCList-method} \alias{end,GNCList-method} \alias{width,GNCList-method} \alias{ranges,GNCList-method} \alias{strand,GNCList-method} \alias{seqinfo,GNCList-method} \alias{coerce,GNCList,GRanges-method} \alias{coerce,GenomicRanges,GNCList-method} \title{GNCList objects} \description{ The GNCList class is a container for storing the Nested Containment List representation of a vector of genomic ranges (typically represented as a \link{GRanges} object). To preprocess a \link{GRanges} object, simply call the \code{GNCList} constructor function on it. The resulting GNCList object can then be used for efficient overlap-based operations on the genomic ranges. } \usage{ GNCList(x) } \arguments{ \item{x}{ The \link{GRanges} (or more generally \link{GenomicRanges}) object to preprocess. } } \details{ The \pkg{IRanges} package also defines the \code{\link[IRanges]{NCList}} and \code{\link[IRanges]{NCLists}} constructors and classes for preprocessing and representing a \link[IRanges]{Ranges} or \link[IRanges]{RangesList} object as a data structure based on Nested Containment Lists. Note that GNCList objects (introduced in BioC 3.1) are replacements for GIntervalTree objects (BioC < 3.1). See \code{?\link[IRanges]{NCList}} in the \pkg{IRanges} package for some important differences between the new algorithm based on Nested Containment Lists and the old algorithm based on interval trees. In particular, the new algorithm supports preprocessing of a \link{GenomicRanges} object with ranges defined on circular sequences (e.g. on the mitochnodrial chromosome). See below for some examples. } \value{ A GNCList object. } \author{H. Pagès} \references{ Alexander V. Alekseyenko and Christopher J. Lee -- Nested Containment List (NCList): a new algorithm for accelerating interval query of genome alignment and interval databases. Bioinformatics (2007) 23 (11): 1386-1393. doi: 10.1093/bioinformatics/btl647 } \seealso{ \itemize{ \item The \code{\link[IRanges]{NCList}} and \code{\link[IRanges]{NCLists}} constructors and classs defined in the \pkg{IRanges} package. \item \code{\link{findOverlaps}} for finding/counting interval overlaps between two \emph{range-based} objects. \item \link{GRanges} objects. } } \examples{ ## The examples below are for illustration purpose only and do NOT ## reflect typical usage. This is because, for a one time use, it is ## NOT advised to explicitely preprocess the input for findOverlaps() ## or countOverlaps(). These functions will take care of it and do a ## better job at it (by preprocessing only what's needed when it's ## needed, and release memory as they go). ## --------------------------------------------------------------------- ## PREPROCESS QUERY OR SUBJECT ## --------------------------------------------------------------------- query <- GRanges(Rle(c("chrM", "chr1", "chrM", "chr1"), 4:1), IRanges(1:10, width=5), strand=rep(c("+", "-"), 5)) subject <- GRanges(Rle(c("chr1", "chr2", "chrM"), 3:1), IRanges(6:1, width=5), strand="+") ## Either the query or the subject of findOverlaps() can be preprocessed: ppsubject <- GNCList(subject) hits1a <- findOverlaps(query, ppsubject) hits1a hits1b <- findOverlaps(query, ppsubject, ignore.strand=TRUE) hits1b ppquery <- GNCList(query) hits2a <- findOverlaps(ppquery, subject) hits2a hits2b <- findOverlaps(ppquery, subject, ignore.strand=TRUE) hits2b ## Note that 'hits1a' and 'hits2a' contain the same hits but not ## necessarily in the same order. stopifnot(identical(sort(hits1a), sort(hits2a))) ## Same for 'hits1b' and 'hits2b'. stopifnot(identical(sort(hits1b), sort(hits2b))) ## --------------------------------------------------------------------- ## WITH CIRCULAR SEQUENCES ## --------------------------------------------------------------------- seqinfo <- Seqinfo(c("chr1", "chr2", "chrM"), seqlengths=c(100, 50, 10), isCircular=c(FALSE, FALSE, TRUE)) seqinfo(query) <- seqinfo[seqlevels(query)] seqinfo(subject) <- seqinfo[seqlevels(subject)] ppsubject <- GNCList(subject) hits3 <- findOverlaps(query, ppsubject) hits3 ## Circularity introduces more hits: stopifnot(all(hits1a \%in\% hits3)) new_hits <- setdiff(hits3, hits1a) new_hits # 1 new hit query[queryHits(new_hits)] subject[subjectHits(new_hits)] # positions 11:13 on chrM are the same # as positions 1:3 ## Sanity checks: stopifnot(identical(new_hits, Hits(9, 6, 10, 6, sort.by.query=TRUE))) ppquery <- GNCList(query) hits4 <- findOverlaps(ppquery, subject) stopifnot(identical(sort(hits3), sort(hits4))) } \keyword{classes} \keyword{methods} GenomicRanges/man/GPos-class.Rd0000644000175400017540000002701113175713746017355 0ustar00biocbuildbiocbuild\name{GPos-class} \docType{class} \alias{class:GPos} \alias{GPos-class} \alias{GPos} \alias{names,GPos-method} \alias{names<-,GPos-method} \alias{pos,GPos-method} \alias{coerce,GRanges,GPos-method} \alias{coerce,ANY,GPos-method} \alias{coerce,GPos,GRanges-method} \alias{as.data.frame,GPos-method} \alias{updateObject,GPos-method} \alias{show,GPos-method} \title{Memory-efficient representation of genomic positions} \description{ The GPos class is a container for storing a set of \emph{genomic positions} where most of the positions are typically (but not necessarily) adjacent. Because genomic positions can be seen as genomic ranges of width 1, the GPos class extends the \link{GenomicRanges} virtual class. Note that even though a \link{GRanges} instance can be used for storing genomic positions, using a GPos object will be much more memory-efficient, especially when the object contains long runs of adjacent positions in \emph{ascending order}. } \usage{ GPos(pos_runs) # constructor function } \arguments{ \item{pos_runs}{ A \link{GRanges} object (or any other \link{GenomicRanges} derivative) where each range is interpreted as a run of adjacent ascending genomic positions on the same strand. If \code{pos_runs} is not a \link{GenomicRanges} derivative, \code{GPos()} first tries to coerce it to one with \code{as(pos_runs, "GenomicRanges", strict=FALSE)}. } } \value{ A GPos object. } \section{Accessors}{ \subsection{Getters}{ GPos objects support the same set of getters as other \link{GenomicRanges} derivatives (i.e. \code{seqnames()}, \code{ranges()}, \code{start()}, \code{end()}, \code{strand()}, \code{mcols()}, \code{seqinfo()}, etc...), plus the \code{pos()} getter which is equivalent to \code{start()} or \code{end()}. See \code{?\link{GenomicRanges}} for the list of getters supported by \link{GenomicRanges} derivatives. IMPORTANT NOTES: \enumerate{ \item \code{ranges()} returns an \link[IRanges]{IPos} object instead of the \link[IRanges]{IRanges} object that one gets with other \link{GenomicRanges} derivatives. To get an \link[IRanges]{IRanges} object, you need to call \code{ranges()} again on the \link[IRanges]{IPos} object i.e. do \code{ranges(ranges(x))}) on GPos object \code{x}. \item Note that a GPos object cannot hold names i.e. \code{names()} always returns \code{NULL} on it. } } \subsection{Setters}{ Like \link{GRanges} objects, GPos objects support the following setters: \itemize{ \item The \code{seqnames()} and \code{strand()} setters. \item The \code{mcols()} and \code{metadata()} setters. \item The family of setters that operate on the seqinfo component of an object: \code{\link[GenomeInfoDb]{seqlevels}()}, \code{\link[GenomeInfoDb]{seqlevelsStyle}()}, \code{\link[GenomeInfoDb]{seqlengths}()}, \code{\link[GenomeInfoDb]{isCircular}()}, \code{\link[GenomeInfoDb]{genome}()}, and \code{\link[GenomeInfoDb]{seqinfo}()}. These setters are defined and documented in the \pkg{GenomeInfoDb} package. } However, there is no \code{pos()} setter for GPos objects at the moment (although one might be added in the future). } } \section{Coercion}{ From GenomicRanges to GPos: A \link{GenomicRanges} derivative \code{x} in which all the ranges have a width of 1 can be coerced to a GPos object with \code{as(x, "GPos")}. The names on \code{x} are not propagated (a warning is issued if \code{x} has names on it). From GPos to GRanges: A GPos object \code{x} can be coerced to a \link{GRanges} object with \code{as(x, "GRanges")}. However be aware that the resulting object can use thousands times (or more) memory than \code{x}! See "MEMORY USAGE" in the Examples section below. From GPos to ordinary R objects: Like with any other \link{GenomicRanges} derivative, \code{as.character()}, \code{as.factor()}, and \code{as.data.frame()} work on a GPos object \code{x}. Note however that \code{as.data.frame(x)} returns a data frame with a \code{pos} column (containing \code{pos(x)}) instead of the \code{start}, \code{end}, and \code{width} columns that one gets with other \link{GenomicRanges} derivatives. } \section{Subsetting}{ A GPos object can be subsetted exactly like a \link{GRanges} object. } \section{Combining}{ GPos objects can be combined (a.k.a. appended) with \code{c()} or \code{append()}. } \section{Splitting and Relisting}{ Like with any other \link{GRanges} object, \code{split()} and \code{relist()} work on a GPos object. } \note{ Like for any \link[S4Vectors]{Vector} derivative, the length of a GPos object cannot exceed \code{.Machine$integer.max} (i.e. 2^31 on most platforms). \code{GPos()} will return an error if \code{pos_runs} contains too many genomic positions. Internal representation of GPos objects has changed in \pkg{GenomicRanges} 1.29.10 (Bioc 3.6). Update any old object \code{x} with: \code{x <- updateObject(x, verbose=TRUE)}. } \author{ Hervé Pagès; based on ideas borrowed from Georg Stricker \email{georg.stricker@in.tum.de} and Julien Gagneur \email{gagneur@in.tum.de} } \seealso{ \itemize{ \item The \link[IRanges]{IPos} class in the \pkg{IRanges} package for a memory-efficient representation of \emph{integer positions} (i.e. integer ranges of width 1). \item \link{GenomicRanges} and \link{GRanges} objects. \item The \code{\link[GenomeInfoDb]{seqinfo}} accessor and family in the \pkg{GenomeInfoDb} package for accessing/modifying the seqinfo component of an object. \item \link{GenomicRanges-comparison} for comparing and ordering genomic positions. \item \link[GenomicRanges]{findOverlaps-methods} for finding overlapping genomic ranges and/or positions. \item \link[GenomicRanges]{nearest-methods} for finding the nearest genomic range/position neighbor. \item The \code{\link[BSgenome]{snpsBySeqname}}, \code{\link[BSgenome]{snpsByOverlaps}}, and \code{\link[BSgenome]{snpsById}} methods for \link[BSgenome]{SNPlocs} objects defined in the \pkg{BSgenome} package for extractors that return a GPos object. \item \link[SummarizedExperiment]{SummarizedExperiment} objects in the \pkg{SummarizedExperiment} package. } } \examples{ ## --------------------------------------------------------------------- ## BASIC EXAMPLES ## --------------------------------------------------------------------- ## Example 1: gpos1 <- GPos(c("chr1:44-53", "chr1:5-10", "chr2:2-5")) gpos1 length(gpos1) seqnames(gpos1) pos(gpos1) # same as 'start(gpos1)' and 'end(gpos1)' strand(gpos1) as.character(gpos1) as.data.frame(gpos1) as(gpos1, "GRanges") as.data.frame(as(gpos1, "GRanges")) gpos1[9:17] ## Example 2: pos_runs <- GRanges("chrI", IRanges(c(1, 6, 12, 17), c(5, 10, 16, 20)), strand=c("+", "-", "-", "+")) gpos2 <- GPos(pos_runs) gpos2 strand(gpos2) ## Example 3: gpos3A <- gpos3B <- GPos(c("chrI:1-1000", "chrI:1005-2000")) npos <- length(gpos3A) mcols(gpos3A)$sample <- Rle("sA") sA_counts <- sample(10, npos, replace=TRUE) mcols(gpos3A)$counts <- sA_counts mcols(gpos3B)$sample <- Rle("sB") sB_counts <- sample(10, npos, replace=TRUE) mcols(gpos3B)$counts <- sB_counts gpos3 <- c(gpos3A, gpos3B) gpos3 ## Example 4: library(BSgenome.Scerevisiae.UCSC.sacCer2) genome <- BSgenome.Scerevisiae.UCSC.sacCer2 gpos4 <- GPos(seqinfo(genome)) gpos4 # all the positions along the genome are represented mcols(gpos4)$dna <- do.call("c", unname(as.list(genome))) gpos4 ## Note however that, like for any Vector derivative, the length of a ## GPos object cannot exceed '.Machine$integer.max' (i.e. 2^31 on most ## platforms) so the above only works with a "small" genome. ## For example it doesn't work with the Human genome: library(TxDb.Hsapiens.UCSC.hg19.knownGene) \dontrun{ GPos(seqinfo(TxDb.Hsapiens.UCSC.hg19.knownGene)) # error! } ## You can use isSmallGenome() to check upfront whether the genome is ## "small" or not. isSmallGenome(genome) isSmallGenome(TxDb.Hsapiens.UCSC.hg19.knownGene) ## --------------------------------------------------------------------- ## MEMORY USAGE ## --------------------------------------------------------------------- ## Coercion to GRanges works... gr4 <- as(gpos4, "GRanges") gr4 ## ... but is generally not a good idea: object.size(gpos4) object.size(gr4) # 8 times bigger than the GPos object! ## Shuffling the order of the positions impacts memory usage: gpos4r <- rev(gpos4) object.size(gpos4r) # significantly gpos4s <- sample(gpos4) object.size(gpos4s) # even worse! ## AN IMPORTANT NOTE: In the worst situations, GPos still performs as ## good as a GRanges object. object.size(as(gpos4r, "GRanges")) # same size as 'gpos4r' object.size(as(gpos4s, "GRanges")) # same size as 'gpos4s' ## Best case scenario is when the object is strictly sorted (i.e. ## positions are in strict ascending order). ## This can be checked with: is.unsorted(gpos4, strict=TRUE) # 'gpos4' is strictly sorted ## --------------------------------------------------------------------- ## USING MEMORY-EFFICIENT METADATA COLUMNS ## --------------------------------------------------------------------- ## In order to keep memory usage as low as possible, it is recommended ## to use a memory-efficient representation of the metadata columns that ## we want to set on the object. Rle's are particularly well suited for ## this, especially if the metadata columns contain long runs of ## identical values. This is the case for example if we want to use a ## GPos object to represent the coverage of sequencing reads along a ## genome. ## Example 5: library(pasillaBamSubset) library(Rsamtools) # for the BamFile() constructor function bamfile1 <- BamFile(untreated1_chr4()) bamfile2 <- BamFile(untreated3_chr4()) gpos5 <- GPos(seqinfo(bamfile1)) library(GenomicAlignments) # for "coverage" method for BamFile objects cov1 <- unlist(coverage(bamfile1), use.names=FALSE) cov2 <- unlist(coverage(bamfile2), use.names=FALSE) mcols(gpos5) <- DataFrame(cov1, cov2) gpos5 object.size(gpos5) # lightweight ## Keep only the positions where coverage is at least 10 in one of the ## 2 samples: gpos5[mcols(gpos5)$cov1 >= 10 | mcols(gpos5)$cov2 >= 10] ## --------------------------------------------------------------------- ## USING A GPos OBJECT IN A SummarizedExperiment OBJECT ## --------------------------------------------------------------------- ## Because the GPos class extends the GenomicRanges virtual class, a GPos ## object can be used as the rowRanges component of a SummarizedExperiment ## object. ## As a 1st example, we show how the counts for samples sA and sB in ## 'gpos3' can be stored in a SummarizedExperiment object where the rows ## correspond to unique genomic positions and the columns to samples: library(SummarizedExperiment) counts <- cbind(sA=sA_counts, sB=sB_counts) mcols(gpos3A) <- NULL rse3 <- SummarizedExperiment(list(counts=counts), rowRanges=gpos3A) rse3 rowRanges(rse3) head(assay(rse3)) ## Finally we show how the coverage data from Example 5 can be easily ## stored in a lightweight SummarizedExperiment object: cov <- mcols(gpos5) mcols(gpos5) <- NULL rse5 <- SummarizedExperiment(list(cov=cov), rowRanges=gpos5) rse5 rowRanges(rse5) assay(rse5) ## Keep only the positions where coverage is at least 10 in one of the ## 2 samples: rse5[assay(rse5)$cov1 >= 10 | assay(rse5)$cov2 >= 10] } \keyword{methods} \keyword{classes} GenomicRanges/man/GRanges-class.Rd0000644000175400017540000006531613175713746020045 0ustar00biocbuildbiocbuild\name{GRanges-class} \docType{class} \alias{class:IRanges_OR_IPos} \alias{IRanges_OR_IPos-class} \alias{IRanges_OR_IPos} \alias{class:GenomicRanges} \alias{GenomicRanges-class} \alias{GenomicRanges} \alias{GenomicRanges_OR_missing-class} \alias{class:GRanges} \alias{GRanges-class} \alias{GRanges} % Constructors: \alias{GRanges} \alias{updateObject,GRanges-method} % Accessors: \alias{length,GenomicRanges-method} \alias{seqnames,GRanges-method} \alias{seqnames,RangedData-method} \alias{seqnames<-,GenomicRanges-method} \alias{ranges,GRanges-method} \alias{ranges<-,GenomicRanges-method} \alias{start,GenomicRanges-method} \alias{start<-,GenomicRanges-method} \alias{end,GenomicRanges-method} \alias{end<-,GenomicRanges-method} \alias{width,GenomicRanges-method} \alias{width<-,GenomicRanges-method} \alias{strand,GRanges-method} \alias{strand<-,GenomicRanges,ANY-method} \alias{names,GenomicRanges-method} \alias{names<-,GenomicRanges-method} \alias{$,GenomicRanges-method} \alias{$<-,GenomicRanges-method} \alias{seqinfo,GRanges-method} \alias{seqinfo,List-method} \alias{seqinfo,RangedData-method} \alias{seqinfo<-,GenomicRanges-method} \alias{seqinfo<-,List-method} \alias{seqinfo<-,RangedData-method} \alias{score,GenomicRanges-method} \alias{score<-,GenomicRanges-method} \alias{granges,GenomicRanges-method} % Coercion: \alias{coerce,GenomicRanges,GRanges-method} \alias{as.character,GenomicRanges-method} \alias{as.factor,GenomicRanges-method} \alias{as.data.frame,GenomicRanges-method} \alias{coerce,GenomicRanges,RangesList-method} \alias{coerce,GenomicRanges,RangedData-method} \alias{coerce,character,GRanges-method} \alias{coerce,factor,GRanges-method} \alias{coerce,RangesList,GRanges-method} \alias{coerce,RangedData,GRanges-method} \alias{coerce,Seqinfo,GRanges-method} \alias{coerce,Seqinfo,RangesList-method} \alias{coerce,GenomicRanges,Grouping-method} \alias{coerce,ANY,GenomicRanges-method} % Subsetting: \alias{[<-,GRanges-method} \alias{[,GenomicRanges,ANY-method} \alias{[<-,GenomicRanges,ANY,ANY,ANY-method} \alias{[,List,GenomicRanges-method} \alias{[,list,GenomicRanges-method} \alias{window,GenomicRanges-method} % Combining: \alias{c,GenomicRanges-method} % Displaying: \alias{summary.GenomicRanges} \alias{summary,GenomicRanges-method} \alias{show,GenomicRanges-method} \title{GRanges objects} \description{ The GRanges class is a container for the genomic locations and their associated annotations. } \details{ GRanges is a vector of genomic locations and associated annotations. Each element in the vector is comprised of a sequence name, an interval, a \link{strand}, and optional metadata columns (e.g. score, GC content, etc.). This information is stored in four components: \describe{ \item{\code{seqnames}}{a 'factor' \link[S4Vectors]{Rle} object containing the sequence names.} \item{\code{ranges}}{an \link[IRanges]{IRanges} object containing the ranges.} \item{\code{strand}}{a 'factor' \link[S4Vectors]{Rle} object containing the \link{strand} information.} \item{\code{mcols}}{a \link[S4Vectors]{DataFrame} object containing the metadata columns. Columns cannot be named \code{"seqnames"}, \code{"ranges"}, \code{"strand"}, \code{"seqlevels"}, \code{"seqlengths"}, \code{"isCircular"}, \code{"start"}, \code{"end"}, \code{"width"}, or \code{"element"}.} \item{\code{seqinfo}}{a \link{Seqinfo} object containing information about the set of genomic sequences present in the GRanges object.} } } \section{Constructor}{ \describe{ \item{}{ \code{GRanges(seqnames=NULL, ranges=NULL, strand=NULL, ..., seqlengths=NULL, seqinfo=NULL)}: Creates a GRanges object. \describe{ \item{\code{seqnames}}{ \code{NULL}, or an \link[S4Vectors]{Rle} object, character vector, or factor containing the sequence names. } \item{\code{ranges}}{ \code{NULL}, or an \link[IRanges]{IRanges} object containing the ranges. } \item{\code{strand}}{ \code{NULL}, or an \link[S4Vectors]{Rle} object, character vector, or factor containing the strand information. } \item{\code{...}}{ Optional metadata columns. These columns cannot be named \code{"start"}, \code{"end"}, \code{"width"}, or \code{"element"}. } \item{\code{seqlengths}}{ \code{NULL}, or an integer vector named with \code{levels(seqnames)} and containing the lengths (or NA) for each level in \code{levels(seqnames)}. } \item{\code{seqinfo}}{ \code{NULL}, or a \link[GenomeInfoDb]{Seqinfo} object containing allowed sequence names, lengths (or NA), and circularity flag, for each level in \code{levels(seqnames)}. } } If \code{ranges} is not supplied and/or NULL then the constructor proceeds in 2 steps: \enumerate{ \item An initial GRanges object is created with \code{as(seqnames, "GRanges")}. \item Then this GRanges object is updated according to whatever non-NULL remaining arguments were passed to the call to \code{GRanges()}. } As a consequence of this behavior, \code{GRanges(x)} is equivalent to \code{as(x, "GRanges")}. } } } \section{Accessors}{ In the following code snippets, \code{x} is a GRanges object. \describe{ \item{}{ \code{length(x)}: Get the number of elements. } \item{}{ \code{seqnames(x)}, \code{seqnames(x) <- value}: Get or set the sequence names. \code{value} can be an \link[S4Vectors]{Rle} object, a character vector, or a factor. } \item{}{ \code{ranges(x)}, \code{ranges(x) <- value}: Get or set the ranges. \code{value} can be a Ranges object. } \item{}{ \code{start(x)}, \code{start(x) <- value}: Get or set \code{start(ranges(x))}. } \item{}{ \code{end(x)}, \code{end(x) <- value}: Get or set \code{end(ranges(x))}. } \item{}{ \code{width(x)}, \code{width(x) <- value}: Get or set \code{width(ranges(x))}. } \item{}{ \code{strand(x)}, \code{strand(x) <- value}: Get or set the strand. \code{value} can be an Rle object, character vector, or factor. } \item{}{ \code{names(x)}, \code{names(x) <- value}: Get or set the names of the elements. } \item{}{ \code{mcols(x, use.names=FALSE)}, \code{mcols(x) <- value}: Get or set the metadata columns. If \code{use.names=TRUE} and the metadata columns are not \code{NULL}, then the names of \code{x} are propagated as the row names of the returned \link{DataFrame} object. When setting the metadata columns, the supplied value must be \code{NULL} or a data.frame-like object (i.e. \link{DataTable} or data.frame) object holding element-wise metadata. } \item{}{ \code{elementMetadata(x)}, \code{elementMetadata(x) <- value}, \code{values(x)}, \code{values(x) <- value}: Alternatives to \code{mcols} functions. Their use is discouraged. } \item{}{ \code{seqinfo(x)}, \code{seqinfo(x) <- value}: Get or set the information about the underlying sequences. \code{value} must be a \link{Seqinfo} object. } \item{}{ \code{seqlevels(x)}, \code{seqlevels(x, pruning.mode=c("error", "coarse", "fine", "tidy")) <- value}: Get or set the sequence levels. \code{seqlevels(x)} is equivalent to \code{seqlevels(seqinfo(x))} or to \code{levels(seqnames(x))}, those 2 expressions being guaranteed to return identical character vectors on a GRanges object. \code{value} must be a character vector with no NAs. See \code{?\link{seqlevels}} for more information. } \item{}{ \code{seqlengths(x)}, \code{seqlengths(x) <- value}: Get or set the sequence lengths. \code{seqlengths(x)} is equivalent to \code{seqlengths(seqinfo(x))}. \code{value} can be a named non-negative integer or numeric vector eventually with NAs. } \item{}{ \code{isCircular(x)}, \code{isCircular(x) <- value}: Get or set the circularity flags. \code{isCircular(x)} is equivalent to \code{isCircular(seqinfo(x))}. \code{value} must be a named logical vector eventually with NAs. } \item{}{ \code{genome(x)}, \code{genome(x) <- value}: Get or set the genome identifier or assembly name for each sequence. \code{genome(x)} is equivalent to \code{genome(seqinfo(x))}. \code{value} must be a named character vector eventually with NAs. } \item{}{ \code{seqlevelsStyle(x)}, \code{seqlevelsStyle(x) <- value}: Get or set the seqname style for \code{x}. See the \link[GenomeInfoDb]{seqlevelsStyle} generic getter and setter in the \pkg{GenomeInfoDb} package for more information. } \item{}{ \code{score(x), score(x) <- value}: Get or set the \dQuote{score} column from the element metadata. } \item{}{ \code{granges(x, use.names=FALSE, use.mcols=FALSE)}: Squeeze the genomic ranges out of \link{GenomicRanges} object \code{x} and return them in a GRanges object \emph{parallel} to \code{x} (i.e. same length as \code{x}). If \code{use.mcols} is \code{TRUE}, the metadata columns are propagated. If \code{x} is a \link{GenomicRanges} derivative with \emph{extra column slots}, these will be propagated as metadata columns on the returned GRanges object. } } } \section{Coercion}{ In the code snippets below, \code{x} is a GRanges object. \describe{ \item{}{ \code{as(from, "GRanges")}: Creates a GRanges object from a character vector, a factor, or a RangedData, or RangesList object. When \code{from} is a character vector (or a factor), each element in it must represent a genomic range in format \code{chr1:2501-2800} (unstranded range) or \code{chr1:2501-2800:+} (stranded range). \code{..} is also supported as a separator between the start and end positions. Strand can be \code{+}, \code{-}, \code{*}, or missing. The names on \code{from} are propagated to the returned GRanges object. See \code{as.character()} and \code{as.factor()} below for the reverse transformations. Coercing a data.frame or DataFrame into a GRanges object is also supported. See \code{\link{makeGRangesFromDataFrame}} for the details. } \item{}{ \code{as(from, "RangedData")}: Creates a RangedData object from a GRanges object. The \code{strand} and metadata columns become columns in the result. The \code{seqlengths(from)}, \code{isCircular(from)}, and \code{genome(from)} vectors are stored in the metadata columns of \code{ranges(rd)}. } \item{}{ \code{as(from, "RangesList")}: Creates a RangesList object from a GRanges object. The \code{strand} and metadata columns become \emph{inner} metadata columns (i.e. metadata columns on the ranges). The \code{seqlengths(from)}, \code{isCircular(from)}, and \code{genome(from)} vectors become the metadata columns. } \item{}{ \code{as.character(x, ignore.strand=FALSE)}: Turn GRanges object \code{x} into a character vector where each range in \code{x} is represented by a string in format \code{chr1:2501-2800:+}. If \code{ignore.strand} is TRUE or if \emph{all} the ranges in \code{x} are unstranded (i.e. their strand is set to \code{*}), then all the strings in the output are in format \code{chr1:2501-2800}. The names on \code{x} are propagated to the returned character vector. Its metadata (\code{metadata(x)}) and metadata columns (\code{mcols(x)}) are ignored. See \code{as(from, "GRanges")} above for the reverse transformation. } \item{}{ \code{as.factor(x)}: Equivalent to \preformatted{ factor(as.character(x), levels=as.character(sort(unique(x)))) } See \code{as(from, "GRanges")} above for the reverse transformation. Note that \code{table(x)} is supported on a GRanges object. It is equivalent to, but much faster than, \code{table(as.factor(x))}. } \item{}{ \code{as.data.frame(x, row.names = NULL, optional = FALSE, ...)}: Creates a data.frame with columns \code{seqnames} (factor), \code{start} (integer), \code{end} (integer), \code{width} (integer), \code{strand} (factor), as well as the additional metadata columns stored in \code{mcols(x)}. Pass an explicit \code{stringsAsFactors=TRUE/FALSE} argument via \code{\ldots} to override the default conversions for the metadata columns in \code{mcols(x)}. } \item{}{ \code{as(from, "Grouping")}: Creates a \code{\link[IRanges]{ManyToOneGrouping}} object that groups \code{from} by seqname, strand, start and end (same as the default sort order). This makes it convenient, for example, to aggregate a GenomicRanges object by range. } } In the code snippets below, \code{x} is a \link[GenomeInfoDb]{Seqinfo} object. \describe{ \item{}{ \code{as(x, "GRanges")}, \code{as(x, "GenomicRanges")}, \code{as(x, "RangesList")}: Turns \link[GenomeInfoDb]{Seqinfo} object \code{x} (with no \code{NA} lengths) into a GRanges or RangesList. } } } \section{Subsetting}{ In the code snippets below, \code{x} is a GRanges object. \describe{ \item{}{ \code{x[i, j]}, \code{x[i, j] <- value}: Get or set elements \code{i} with optional metadata columns \code{mcols(x)[,j]}, where \code{i} can be missing; an NA-free logical, numeric, or character vector; or a 'logical' Rle object. } \item{}{ \code{x[i, j] <- value}: Replaces elements \code{i} and optional metadata columns \code{j} with \code{value}. } \item{}{ \code{head(x, n = 6L)}: If \code{n} is non-negative, returns the first n elements of the GRanges object. If \code{n} is negative, returns all but the last \code{abs(n)} elements of the GRanges object. } \item{}{ \code{rep(x, times, length.out, each)}: Repeats the values in \code{x} through one of the following conventions: \describe{ \item{\code{times}}{Vector giving the number of times to repeat each element if of length \code{length(x)}, or to repeat the whole vector if of length 1.} \item{\code{length.out}}{Non-negative integer. The desired length of the output vector.} \item{\code{each}}{Non-negative integer. Each element of \code{x} is repeated \code{each} times.} } } \item{}{ \code{subset(x, subset)}: Returns a new object of the same class as \code{x} made of the subset using logical vector \code{subset}, where missing values are taken as \code{FALSE}. } \item{}{ \code{tail(x, n = 6L)}: If \code{n} is non-negative, returns the last n elements of the GRanges object. If \code{n} is negative, returns all but the first \code{abs(n)} elements of the GRanges object. } \item{}{ \code{window(x, start = NA, end = NA, width = NA, frequency = NULL, delta = NULL, ...)}: Extracts the subsequence window from the GRanges object using: \describe{ \item{\code{start}, \code{end}, \code{width}}{The start, end, or width of the window. Two of the three are required.} \item{\code{frequency}, \code{delta}}{Optional arguments that specify the sampling frequency and increment within the window.} } In general, this is more efficient than using \code{"["} operator. } \item{}{ \code{window(x, start = NA, end = NA, width = NA, keepLength = TRUE) <- value}: Replaces the subsequence window specified on the left (i.e. the subsequence in \code{x} specified by \code{start}, \code{end} and \code{width}) by \code{value}. \code{value} must either be of class \code{class(x)}, belong to a subclass of \code{class(x)}, be coercible to \code{class(x)}, or be \code{NULL}. If \code{keepLength} is \code{TRUE}, the elements of \code{value} are repeated to create a GRanges object with the same number of elements as the width of the subsequence window it is replacing. If \code{keepLength} is \code{FALSE}, this replacement method can modify the length of \code{x}, depending on how the length of the left subsequence window compares to the length of \code{value}. } \item{}{ \code{x$name}, \code{x$name <- value}: Shortcuts for \code{mcols(x)$name} and \code{mcols(x)$name <- value}, respectively. Provided as a convenience, for GRanges objects *only*, and as the result of strong popular demand. Note that those methods are not consistent with the other \code{$} and \code{$<-} methods in the IRanges/GenomicRanges infrastructure, and might confuse some users by making them believe that a GRanges object can be manipulated as a data.frame-like object. Therefore we recommend using them only interactively, and we discourage their use in scripts or packages. For the latter, use \code{mcols(x)$name} and \code{mcols(x)$name <- value}, instead of \code{x$name} and \code{x$name <- value}, respectively. } } Note that a GRanges object can be used to as a subscript to subset a list-like object that has names on it. In that case, the names on the list-like object are interpreted as sequence names. In the code snippets below, \code{x} is a list or \link{List} object with names on it, and the subscript \code{gr} is a GRanges object with all its seqnames being valid \code{x} names. \describe{ \item{}{ \code{x[gr]}: Return an object of the same class as \code{x} and \emph{parallel} to \code{gr}. More precisely, it's conceptually doing: \preformatted{ lapply(gr, function(gr1) x[[seqnames(gr1)]][ranges(gr1)]) } } } } \section{Combining and splitting}{ In the code snippets below, \code{x} is a GRanges object. \describe{ \item{}{ \code{c(x, ..., ignore.mcols=FALSE)}: Combines \code{x} and the GRanges objects in \code{...} together. Any object in \code{...} must belong to the same class as \code{x}, or to one of its subclasses, or must be \code{NULL}. The result is an object of the same class as \code{x}. If the \code{GRanges} objects have metadata columns (represented as one \link{DataFrame} per object), each such \link{DataFrame} must have the same columns in order to combine successfully. In order to circumvent this restraint, you can pass in an \code{ignore.mcols=TRUE} argument which will combine all the objects into one and drop all of their metadata columns. } \item{}{ \code{append(x, values, after = length(x))}: Inserts the \code{values} into \code{x} at the position given by \code{after}, where \code{x} and \code{values} are of the same class. } \item{}{ \code{split(x, f, drop=FALSE)}: Splits \code{x} according to \code{f} to create a \link{GRangesList} object. If \code{f} is a list-like object then \code{drop} is ignored and \code{f} is treated as if it was \code{rep(seq_len(length(f)), sapply(f, length))}, so the returned object has the same shape as \code{f} (it also receives the names of \code{f}). Otherwise, if \code{f} is not a list-like object, empty list elements are removed from the returned object if \code{drop} is \code{TRUE}. } } } \section{Displaying}{ In the code snippets below, \code{x} is a GRanges object. \describe{ \item{}{ \code{show(x)}: By default the \code{show} method displays 5 head and 5 tail elements. This can be changed by setting the global options \code{showHeadLines} and \code{showTailLines}. If the object length is less than (or equal to) the sum of these 2 options plus 1, then the full object is displayed. Note that these options also affect the display of \link[GenomicAlignments]{GAlignments} and \link[GenomicAlignments]{GAlignmentPairs} objects (defined in the \pkg{GenomicAlignments} package), as well as other objects defined in the \pkg{IRanges} and \pkg{Biostrings} packages (e.g. \link[IRanges]{IRanges} and \link[Biostrings]{DNAStringSet} objects). } } } \author{P. Aboyoun and H. Pagès} \seealso{ \itemize{ \item \code{\link{makeGRangesFromDataFrame}} for making a GRanges object from a data.frame or \link[S4Vectors]{DataFrame} object. \item \code{\link[GenomeInfoDb]{seqinfo}} for accessing/modifying information about the underlying sequences of a GRanges object. \item The \link{GPos} class, a memory-efficient \link{GenomicRanges} derivative for representing \emph{genomic positions} (i.e. genomic ranges of width 1). \item \link{GenomicRanges-comparison} for comparing and ordering genomic ranges. \item \link[GenomicRanges]{findOverlaps-methods} for finding/counting overlapping genomic ranges. \item \link[GenomicRanges]{intra-range-methods} and \link[GenomicRanges]{inter-range-methods} for intra range and inter range transformations of a GRanges object. \item \link[GenomicRanges]{coverage-methods} for computing the coverage of a GRanges object. \item \link[GenomicRanges]{setops-methods} for set operations on GRanges objects. \item \link[GenomicRanges]{nearest-methods} for finding the nearest genomic range neighbor. \item \code{\link{absoluteRanges}} for transforming genomic ranges into \emph{absolute} ranges (i.e. into ranges on the sequence obtained by virtually concatenating all the sequences in a genome). \item \code{\link{tileGenome}} for putting tiles on a genome. \item \link{genomicvars} for manipulating genomic variables. \item \link{GRangesList} objects. \item \link[IRanges]{Ranges} objects in the \pkg{IRanges} package. \item \link[S4Vectors]{Vector}, \link[S4Vectors]{Rle}, and \link[S4Vectors]{DataFrame} objects in the \pkg{S4Vectors} package. } } \examples{ ## --------------------------------------------------------------------- ## CONSTRUCTION ## --------------------------------------------------------------------- ## Specifying the bare minimum i.e. seqnames and ranges only. The ## GRanges object will have no names, no strand information, and no ## metadata columns: gr0 <- GRanges(Rle(c("chr2", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(1:10, width=10:1)) gr0 ## Specifying names, strand, metadata columns. They can be set on an ## existing object: names(gr0) <- head(letters, 10) strand(gr0) <- Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)) mcols(gr0)$score <- 1:10 mcols(gr0)$GC <- seq(1, 0, length=10) gr0 ## ... or specified at construction time: gr <- GRanges(Rle(c("chr2", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(1:10, width=10:1, names=head(letters, 10)), Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10)) stopifnot(identical(gr0, gr)) ## Specifying the seqinfo. It can be set on an existing object: seqinfo <- Seqinfo(paste0("chr", 1:3), c(1000, 2000, 1500), NA, "mock1") seqinfo(gr0) <- merge(seqinfo(gr0), seqinfo) seqlevels(gr0) <- seqlevels(seqinfo) ## ... or specified at construction time: gr <- GRanges(Rle(c("chr2", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(1:10, width=10:1, names=head(letters, 10)), Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10), seqinfo=seqinfo) stopifnot(identical(gr0, gr)) ## --------------------------------------------------------------------- ## COERCION ## --------------------------------------------------------------------- ## From GRanges: as.character(gr) as.factor(gr) as.data.frame(gr) ## From character to GRanges: x1 <- "chr2:56-125" as(x1, "GRanges") as(rep(x1, 4), "GRanges") x2 <- c(A=x1, B="chr1:25-30:-") as(x2, "GRanges") ## From data.frame to GRanges: df <- data.frame(chrom="chr2", start=11:15, end=20:24) gr3 <- as(df, "GRanges") ## Alternatively, coercion to GRanges can be done by just calling the ## GRanges() constructor on the object to coerce: gr1 <- GRanges(x1) # same as as(x1, "GRanges") gr2 <- GRanges(x2) # same as as(x2, "GRanges") gr3 <- GRanges(df) # same as as(df, "GRanges") ## Sanity checks: stopifnot(identical(as(x1, "GRanges"), gr1)) stopifnot(identical(as(x2, "GRanges"), gr2)) stopifnot(identical(as(df, "GRanges"), gr3)) ## --------------------------------------------------------------------- ## SUMMARIZING ELEMENTS ## --------------------------------------------------------------------- table(seqnames(gr)) table(strand(gr)) sum(width(gr)) table(gr) summary(mcols(gr)[,"score"]) ## The number of lines displayed in the 'show' method are controlled ## with two global options: longGR <- sample(gr, 25, replace=TRUE) longGR options(showHeadLines=7) options(showTailLines=2) longGR ## Revert to default values options(showHeadLines=NULL) options(showTailLines=NULL) ## --------------------------------------------------------------------- ## INVERTING THE STRAND ## --------------------------------------------------------------------- invertStrand(gr) ## --------------------------------------------------------------------- ## RENAMING THE UNDERLYING SEQUENCES ## --------------------------------------------------------------------- seqlevels(gr) seqlevels(gr) <- sub("chr", "Chrom", seqlevels(gr)) gr seqlevels(gr) <- sub("Chrom", "chr", seqlevels(gr)) # revert ## --------------------------------------------------------------------- ## COMBINING OBJECTS ## --------------------------------------------------------------------- gr2 <- GRanges(seqnames=Rle(c('chr1', 'chr2', 'chr3'), c(3, 3, 4)), IRanges(1:10, width=5), strand='-', score=101:110, GC=runif(10), seqinfo=seqinfo) gr3 <- GRanges(seqnames=Rle(c('chr1', 'chr2', 'chr3'), c(3, 4, 3)), IRanges(101:110, width=10), strand='-', score=21:30, seqinfo=seqinfo) some.gr <- c(gr, gr2) ## all.gr <- c(gr, gr2, gr3) ## (This would fail) all.gr <- c(gr, gr2, gr3, ignore.mcols=TRUE) ## --------------------------------------------------------------------- ## USING A GRANGES OBJECT AS A SUBSCRIPT TO SUBSET ANOTHER OBJECT ## --------------------------------------------------------------------- ## Subsetting *by* a GRanges subscript is supported only if the object ## to subset is a named list-like object: x <- RleList(chr1=101:120, chr2=2:-8, chr3=31:40) x[gr] } GenomicRanges/man/GRangesList-class.Rd0000644000175400017540000003420713175713746020674 0ustar00biocbuildbiocbuild\name{GRangesList-class} \docType{class} % Class \alias{class:GRangesList} \alias{GRangesList-class} \alias{GRangesList} \alias{GenomicRanges_OR_GRangesList-class} % Constructors: \alias{GRangesList} \alias{makeGRangesListFromFeatureFragments} \alias{updateObject,GRangesList-method} % Accessor methods: \alias{seqnames,GRangesList-method} \alias{seqnames<-,GRangesList-method} \alias{ranges,GRangesList-method} \alias{ranges<-,GRangesList-method} \alias{start,GRangesList-method} \alias{start<-,GRangesList-method} \alias{end,GRangesList-method} \alias{end<-,GRangesList-method} \alias{width,GRangesList-method} \alias{width<-,GRangesList-method} \alias{strand,GRangesList-method} \alias{strand<-,GRangesList,ANY-method} \alias{strand<-,GRangesList,character-method} \alias{elementMetadata,GRangesList-method} \alias{elementMetadata<-,GRangesList-method} \alias{seqinfo,GRangesList-method} \alias{seqinfo<-,GRangesList-method} \alias{score,GRangesList-method} \alias{score<-,GRangesList-method} % Coercion: \alias{coerce,GRangesList,CompressedIRangesList-method} \alias{coerce,GRangesList,IRangesList-method} \alias{coerce,GRangesList,RangesList-method} \alias{coerce,GRanges,GRangesList-method} \alias{coerce,list,GRangesList-method} % Subsetting: \alias{[,GRangesList,ANY-method} \alias{[<-,GRangesList-method} \alias{[<-,GRangesList,ANY-method} \alias{[<-,GRangesList,ANY,ANY,ANY-method} \alias{[[<-,GRangesList-method} \alias{[[<-,GRangesList,ANY-method} \alias{[[<-,GRangesList,ANY,ANY-method} % extractList() and family: \alias{relistToClass,GRanges-method} % show method: \alias{show,GRangesList-method} \title{GRangesList objects} \description{ The GRangesList class is a container for storing a collection of GRanges objects. It is derived from GenomicRangesList. } \section{Constructors}{ \describe{ \item{}{ \code{GRangesList(...)}: Creates a GRangesList object using GRanges objects supplied in \code{\ldots}, either consecutively or in a list. } \item{}{ \code{makeGRangesListFromFeatureFragments(seqnames=Rle(factor()), fragmentStarts=list(), fragmentEnds=list(), fragmentWidths=list(), strand=character(0), sep=",")}: Constructs a GRangesList object from a list of fragmented features. See the Examples section below. } } } \section{Accessors}{ In the following code snippets, \code{x} is a GRanges object. \describe{ \item{}{ \code{length(x)}: Get the number of list elements. } \item{}{ \code{names(x)}, \code{names(x) <- value}: Get or set the names on \code{x}. } \item{}{ \code{elementNROWS(x)}: Get a vector of the \code{length} of each of the list element. } \item{}{ \code{isEmpty(x)}: Returns a logical indicating either if the GRangesList has no elements or if all its elements are empty. } \item{}{ \code{seqnames(x)}, \code{seqnames(x) <- value}: Get or set the sequence names in the form of an RleList. \code{value} can be an RleList or CharacterList object. } \item{}{ \code{ranges(x, use.mcols=FALSE)}, \code{ranges(x) <- value}: Get or set the ranges in the form of a CompressedIRangesList. \code{value} can be a RangesList object. } \item{}{ \code{start(x)}, \code{start(x) <- value}: Get or set \code{start(ranges(x))}. } \item{}{ \code{end(x)}, \code{end(x) <- value}: Get or set \code{end(ranges(x))}. } \item{}{ \code{width(x)}, \code{width(x) <- value}: Get or set \code{width(ranges(x))}. } \item{}{ \code{strand(x)}, \code{strand(x) <- value}: Get or set the strand in the form of an RleList. \code{value} can be an RleList, CharacterList or single character. \code{value} as a single character converts all ranges in \code{x} to the same \code{value}; for selective strand conversion (i.e., mixed \dQuote{+} and \dQuote{-}) use RleList or CharacterList. } \item{}{ \code{mcols(x, use.names=FALSE)}, \code{mcols(x) <- value}: Get or set the metadata columns. \code{value} can be \code{NULL}, or a data.frame-like object (i.e. \link{DataFrame} or data.frame) holding element-wise metadata. } \item{}{ \code{elementMetadata(x)}, \code{elementMetadata(x) <- value}, \code{values(x)}, \code{values(x) <- value}: Alternatives to \code{mcols} functions. Their use is discouraged. } \item{}{ \code{seqinfo(x)}, \code{seqinfo(x) <- value}: Get or set the information about the underlying sequences. \code{value} must be a \link{Seqinfo} object. } \item{}{ \code{seqlevels(x)}, \code{seqlevels(x, pruning.mode=c("error", "coarse", "fine", "tidy")) <- value}: Get or set the sequence levels. \code{seqlevels(x)} is equivalent to \code{seqlevels(seqinfo(x))} or to \code{levels(seqnames(x))}, those 2 expressions being guaranteed to return identical character vectors on a GRangesList object. \code{value} must be a character vector with no NAs. See \code{?\link{seqlevels}} for more information. } \item{}{ \code{seqlengths(x)}, \code{seqlengths(x) <- value}: Get or set the sequence lengths. \code{seqlengths(x)} is equivalent to \code{seqlengths(seqinfo(x))}. \code{value} can be a named non-negative integer or numeric vector eventually with NAs. } \item{}{ \code{isCircular(x)}, \code{isCircular(x) <- value}: Get or set the circularity flags. \code{isCircular(x)} is equivalent to \code{isCircular(seqinfo(x))}. \code{value} must be a named logical vector eventually with NAs. } \item{}{ \code{genome(x)}, \code{genome(x) <- value}: Get or set the genome identifier or assembly name for each sequence. \code{genome(x)} is equivalent to \code{genome(seqinfo(x))}. \code{value} must be a named character vector eventually with NAs. } \item{}{ \code{seqlevelsStyle(x)}, \code{seqlevelsStyle(x) <- value}: Get or set the seqname style for \code{x}. See the \link[GenomeInfoDb]{seqlevelsStyle} generic getter and setter in the \pkg{GenomeInfoDb} package for more information. } \item{}{ \code{score(x), score(x) <- value}: Get or set the \dQuote{score} metadata column. } } } \section{Coercion}{ In the code snippets below, \code{x} is a GRangesList object. \describe{ \item{}{ \code{as.data.frame(x, row.names = NULL, optional = FALSE, ..., value.name = "value", use.outer.mcols = FALSE, group_name.as.factor = FALSE)}: Coerces \code{x} to a \code{data.frame}. See as.data.frame on the \code{List} man page for details (?\code{List}). } \item{}{\code{as.list(x, use.names = TRUE)}: Creates a list containing the elements of \code{x}. } \item{}{\code{as(x, "IRangesList")}: Turns \code{x} into an \link[IRanges]{IRangesList} object. } } When \code{x} is a \code{list} of \code{GRanges}, it can be coerced to a \code{GRangesList}. \describe{ \item{}{ \code{as(x, "GRangesList")}: Turns \code{x} into a \code{GRangesList}. } } } \section{Subsetting}{ In the following code snippets, \code{x} is a GRangesList object. \describe{ \item{}{ \code{x[i, j]}, \code{x[i, j] <- value}: Get or set elements \code{i} with optional metadata columns \code{mcols(x)[,j]}, where \code{i} can be missing; an NA-free logical, numeric, or character vector; a 'logical' Rle object, or an AtomicList object. } \item{}{ \code{x[[i]]}, \code{x[[i]] <- value}: Get or set element \code{i}, where \code{i} is a numeric or character vector of length 1. } \item{}{ \code{x$name}, \code{x$name <- value}: Get or set element \code{name}, where \code{name} is a name or character vector of length 1. } \item{}{ \code{head(x, n = 6L)}: If \code{n} is non-negative, returns the first n elements of the GRangesList object. If \code{n} is negative, returns all but the last \code{abs(n)} elements of the GRangesList object. } \item{}{ \code{rep(x, times, length.out, each)}: Repeats the values in \code{x} through one of the following conventions: \describe{ \item{\code{times}}{Vector giving the number of times to repeat each element if of length \code{length(x)}, or to repeat the whole vector if of length 1.} \item{\code{length.out}}{Non-negative integer. The desired length of the output vector.} \item{\code{each}}{Non-negative integer. Each element of \code{x} is repeated \code{each} times.} } } \item{}{ \code{subset(x, subset)}: Returns a new object of the same class as \code{x} made of the subset using logical vector \code{subset}, where missing values are taken as \code{FALSE}. } \item{}{ \code{tail(x, n = 6L)}: If \code{n} is non-negative, returns the last n elements of the GRanges object. If \code{n} is negative, returns all but the first \code{abs(n)} elements of the GRanges object. } } } \section{Combining}{ In the code snippets below, \code{x} is a GRangesList object. \describe{ \item{}{ \code{c(x, ...)}: Combines \code{x} and the GRangesList objects in \code{...} together. Any object in \code{...} must belong to the same class as \code{x}, or to one of its subclasses, or must be \code{NULL}. The result is an object of the same class as \code{x}. } \item{}{ \code{append(x, values, after = length(x))}: Inserts the \code{values} into \code{x} at the position given by \code{after}, where \code{x} and \code{values} are of the same class. } \item{}{\code{unlist(x, recursive = TRUE, use.names = TRUE)}: Concatenates the elements of \code{x} into a single GRanges object. } } } \section{Looping}{ In the code snippets below, \code{x} is a GRangesList object. \describe{ \item{}{ \code{endoapply(X, FUN, ...)}: Similar to \code{\link[base]{lapply}}, but performs an endomorphism, i.e. returns an object of \code{class(X)}. } \item{}{ \code{lapply(X, FUN, ...)}: Like the standard \code{\link[base]{lapply}} function defined in the base package, the \code{lapply} method for GRangesList objects returns a list of the same length as \code{X}, with each element being the result of applying \code{FUN} to the corresponding element of \code{X}. } \item{}{ \code{Map(f, ...)}: Applies a function to the corresponding elements of given GRangesList objects. } \item{}{ \code{mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)}: Like the standard \code{\link[base]{mapply}} function defined in the base package, the \code{mapply} method for GRangesList objects is a multivariate version of \code{sapply}. } \item{}{ \code{mendoapply(FUN, ..., MoreArgs = NULL)}: Similar to \code{\link[base]{mapply}}, but performs an endomorphism across multiple objects, i.e. returns an object of \code{class(list(...)[[1]])}. } \item{}{ \code{Reduce(f, x, init, right = FALSE, accumulate = FALSE)}: Uses a binary function to successively combine the elements of \code{x} and a possibly given initial value. \describe{ \item{f}{A binary argument function.} \item{init}{An R object of the same kind as the elements of \code{x}.} \item{right}{A logical indicating whether to proceed from left to right (default) or from right to left.} \item{nomatch}{The value to be returned in the case when "no match" (no element satisfying the predicate) is found.} } } \item{}{ \code{sapply(X, FUN, ..., simplify=TRUE, USE.NAMES=TRUE)}: Like the standard \code{\link[base:lapply]{sapply}} function defined in the base package, the \code{sapply} method for GRangesList objects is a user-friendly version of \code{lapply} by default returning a vector or matrix if appropriate. } } } \author{P. Aboyoun & H. Pagès} \seealso{ \link{GRanges-class}, \code{\link[GenomeInfoDb]{seqinfo}}, \link[S4Vectors]{Vector-class}, \link[IRanges]{RangesList-class}, \link[IRanges]{RleList-class}, \link[IRanges]{DataFrameList-class}, \link[GenomicRanges]{intra-range-methods}, \link[GenomicRanges]{inter-range-methods}, \link{coverage-methods}, \link{setops-methods}, \link{findOverlaps-methods} } \examples{ ## Construction with GRangesList(): gr1 <- GRanges(seqnames = "chr2", ranges = IRanges(3, 6), strand = "+", score = 5L, GC = 0.45) gr2 <- GRanges(seqnames = c("chr1", "chr1"), ranges = IRanges(c(7,13), width = 3), strand = c("+", "-"), score = 3:4, GC = c(0.3, 0.5)) gr3 <- GRanges(seqnames = c("chr1", "chr2"), ranges = IRanges(c(1, 4), c(3, 9)), strand = c("-", "-"), score = c(6L, 2L), GC = c(0.4, 0.1)) grl <- GRangesList("gr1" = gr1, "gr2" = gr2, "gr3" = gr3) grl ## Summarizing elements: elementNROWS(grl) table(seqnames(grl)) ## Extracting subsets: grl[seqnames(grl) == "chr1", ] grl[seqnames(grl) == "chr1" & strand(grl) == "+", ] ## Renaming the underlying sequences: seqlevels(grl) seqlevels(grl) <- sub("chr", "Chrom", seqlevels(grl)) grl ## Coerce to IRangesList (seqnames and strand information is lost): as(grl, "IRangesList") ## isDisjoint(): isDisjoint(grl) ## disjoin(): disjoin(grl) # metadata columns and order NOT preserved ## Construction with makeGRangesListFromFeatureFragments(): filepath <- system.file("extdata", "feature_frags.txt", package="GenomicRanges") featfrags <- read.table(filepath, header=TRUE, stringsAsFactors=FALSE) grl2 <- with(featfrags, makeGRangesListFromFeatureFragments(seqnames=targetName, fragmentStarts=targetStart, fragmentWidths=blockSizes, strand=strand)) names(grl2) <- featfrags$RefSeqID grl2 } GenomicRanges/man/GenomicRanges-comparison.Rd0000644000175400017540000001563713175713746022306 0ustar00biocbuildbiocbuild\name{GenomicRanges-comparison} \alias{GenomicRanges-comparison} \alias{pcompare} \alias{pcompare,GenomicRanges,GenomicRanges-method} \alias{duplicated,GenomicRanges-method} \alias{duplicated.GenomicRanges} \alias{match,GenomicRanges,GenomicRanges-method} \alias{selfmatch,GenomicRanges-method} \alias{is.unsorted,GenomicRanges-method} \alias{order,GenomicRanges-method} \alias{sort,GenomicRanges-method} \alias{sort.GenomicRanges} \alias{rank,GenomicRanges-method} \title{Comparing and ordering genomic ranges} \description{ Methods for comparing and/or ordering \link{GenomicRanges} objects. } \usage{ ## duplicated() ## ------------ \S4method{duplicated}{GenomicRanges}(x, incomparables=FALSE, fromLast=FALSE, nmax=NA, method=c("auto", "quick", "hash")) ## match() & selfmatch() ## --------------------- \S4method{match}{GenomicRanges,GenomicRanges}(x, table, nomatch=NA_integer_, incomparables=NULL, method=c("auto", "quick", "hash"), ignore.strand=FALSE) \S4method{selfmatch}{GenomicRanges}(x, method=c("auto", "quick", "hash"), ignore.strand=FALSE) ## order() and related methods ## ---------------------------- \S4method{is.unsorted}{GenomicRanges}(x, na.rm=FALSE, strictly=FALSE, ignore.strand=FALSE) \S4method{order}{GenomicRanges}(..., na.last=TRUE, decreasing=FALSE, method=c("auto", "shell", "radix")) \S4method{sort}{GenomicRanges}(x, decreasing=FALSE, ignore.strand=FALSE, by) \S4method{rank}{GenomicRanges}(x, na.last=TRUE, ties.method=c("average", "first", "last", "random", "max", "min"), ignore.strand=FALSE) ## Generalized parallel comparison of 2 GenomicRanges objects ## ---------------------------------------------------------- \S4method{pcompare}{GenomicRanges,GenomicRanges}(x, y) } \arguments{ \item{x, table, y}{ \link{GenomicRanges} objects. } \item{incomparables}{ Not supported. } \item{fromLast, method, nomatch, nmax, na.rm, strictly, na.last, decreasing}{ See \code{?`\link[IRanges]{Ranges-comparison}`} in the \pkg{IRanges} package for a description of these arguments. } \item{ignore.strand}{ Whether or not the strand should be ignored when comparing 2 genomic ranges. } \item{...}{ One or more \link{GenomicRanges} objects. The \link{GenomicRanges} objects after the first one are used to break ties. } \item{ties.method}{ A character string specifying how ties are treated. Only \code{"first"} is supported for now. } \item{by}{ An optional formula that is resolved against \code{as.env(x)}; the resulting variables are passed to \code{order} to generate the ordering permutation. } } \details{ Two elements of a \link{GenomicRanges} derivative (i.e. two genomic ranges) are considered equal iff they are on the same underlying sequence and strand, and share the same start and width. \code{duplicated()} and \code{unique()} on a \link{GenomicRanges} derivative are conforming to this. The "natural order" for the elements of a \link{GenomicRanges} derivative is to order them (a) first by sequence level, (b) then by strand, (c) then by start, (d) and finally by width. This way, the space of genomic ranges is totally ordered. Note that, because we already do (c) and (d) for regular ranges (see \code{?`\link[IRanges]{Ranges-comparison}`}), genomic ranges that belong to the same underlying sequence and strand are ordered like regular ranges. \code{pcompare()}, \code{==}, \code{!=}, \code{<=}, \code{>=}, \code{<} and \code{>} on \link{GenomicRanges} derivatives behave accordingly to this "natural order". \code{is.unsorted()}, \code{order()}, \code{sort()}, \code{rank()} on \link{GenomicRanges} derivatives also behave accordingly to this "natural order". Finally, note that some \emph{inter range transformations} like \code{\link[GenomicRanges]{reduce}} or \code{\link[GenomicRanges]{disjoin}} also use this "natural order" implicitly when operating on \link{GenomicRanges} derivatives. } \author{H. Pagès, \code{is.unsorted} contributed by Pete Hickey} \seealso{ \itemize{ \item The \link{GenomicRanges} class. \item \link[IRanges]{Ranges-comparison} in the \pkg{IRanges} package for comparing and ordering genomic ranges. \item \link[GenomicRanges]{findOverlaps-methods} for finding overlapping genomic ranges. \item \link[GenomicRanges]{intra-range-methods} and \link[GenomicRanges]{inter-range-methods} for intra range and inter range transformations of a \link{GRanges} object. \item \link[GenomicRanges]{setops-methods} for set operations on \link{GenomicRanges} objects. } } \examples{ gr0 <- GRanges( Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(c(1:9,7L), end=10), strand=Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqlengths=c(chr1=11, chr2=12, chr3=13) ) gr <- c(gr0, gr0[7:3]) names(gr) <- LETTERS[seq_along(gr)] ## --------------------------------------------------------------------- ## A. ELEMENT-WISE (AKA "PARALLEL") COMPARISON OF 2 GenomicRanges OBJECTS ## --------------------------------------------------------------------- gr[2] == gr[2] # TRUE gr[2] == gr[5] # FALSE gr == gr[4] gr >= gr[3] ## --------------------------------------------------------------------- ## B. match(), selfmatch(), %in%, duplicated(), unique() ## --------------------------------------------------------------------- table <- gr[1:7] match(gr, table) match(gr, table, ignore.strand=TRUE) gr \%in\% table duplicated(gr) unique(gr) ## --------------------------------------------------------------------- ## C. findMatches(), countMatches() ## --------------------------------------------------------------------- findMatches(gr, table) countMatches(gr, table) findMatches(gr, table, ignore.strand=TRUE) countMatches(gr, table, ignore.strand=TRUE) gr_levels <- unique(gr) countMatches(gr_levels, gr) ## --------------------------------------------------------------------- ## D. order() AND RELATED METHODS ## --------------------------------------------------------------------- is.unsorted(gr) order(gr) sort(gr) is.unsorted(sort(gr)) is.unsorted(gr, ignore.strand=TRUE) gr2 <- sort(gr, ignore.strand=TRUE) is.unsorted(gr2) # TRUE is.unsorted(gr2, ignore.strand=TRUE) # FALSE ## TODO: Broken. Please fix! #sort(gr, by = ~ seqnames + start + end) # equivalent to (but slower than) above score(gr) <- rev(seq_len(length(gr))) ## TODO: Broken. Please fix! #sort(gr, by = ~ score) rank(gr, ties.method="first") rank(gr, ties.method="first", ignore.strand=TRUE) ## --------------------------------------------------------------------- ## E. GENERALIZED ELEMENT-WISE COMPARISON OF 2 GenomicRanges OBJECTS ## --------------------------------------------------------------------- gr3 <- GRanges(c(rep("chr1", 12), "chr2"), IRanges(c(1:11, 6:7), width=3)) strand(gr3)[12] <- "+" gr4 <- GRanges("chr1", IRanges(5, 9)) pcompare(gr3, gr4) rangeComparisonCodeToLetter(pcompare(gr3, gr4)) } \keyword{methods} GenomicRanges/man/GenomicRangesList-class.Rd0000644000175400017540000000235213175713746022063 0ustar00biocbuildbiocbuild\name{GenomicRangesList-class} \docType{class} % Class: \alias{class:GenomicRangesList} \alias{class:SimpleGenomicRangesList} \alias{GenomicRangesList-class} \alias{SimpleGenomicRangesList-class} % Constructors: \alias{GenomicRangesList} \title{GenomicRangesList objects} \description{ A \code{GenomicRangesList} is a \code{\link[S4Vectors]{List}} of \code{\linkS4class{GenomicRanges}}. It is a virtual class; \code{SimpleGenomicRangesList} is the basic implementation. The subclass \code{\linkS4class{GRangesList}} provides special behavior and is particularly efficient for storing a large number of elements. } \section{Constructor}{ \describe{ \item{}{ \code{GenomicRangesList(\dots)}: Constructs a \code{SimpleGenomicRangesList} with elements taken from the arguments in \dots. If the only argument is a list, the elements are taken from that list. } } } \author{Michael Lawrence} \seealso{ \code{\linkS4class{GRangesList}}, which differs from \code{SimpleGenomicRangesList} in that the \code{GRangesList} treats its elements as single, compound ranges, particularly in overlap operations. \code{SimpleGenomicRangesList} is just a barebones list for now, without that compound semantic. } GenomicRanges/man/absoluteRanges.Rd0000644000175400017540000001142713175713746020364 0ustar00biocbuildbiocbuild\name{absoluteRanges} \alias{absoluteRanges} \alias{relativeRanges} \alias{isSmallGenome} \title{Transform genomic ranges into "absolute" ranges} \description{ \code{absoluteRanges} transforms the genomic ranges in \code{x} into \emph{absolute} ranges i.e. into ranges counted from the beginning of the virtual sequence obtained by concatenating all the sequences in the underlying genome (in the order reported by \code{seqlevels(x)}). \code{relativeRanges} performs the reverse transformation. NOTE: These functions only work on \emph{small} genomes. See Details section below. } \usage{ absoluteRanges(x) relativeRanges(x, seqlengths) ## Related utility: isSmallGenome(seqlengths) } \arguments{ \item{x}{ For \code{absoluteRanges}: a \link{GenomicRanges} object with ranges defined on a \emph{small} genome (see Details section below). For \code{relativeRanges}: a \link{Ranges} object. } \item{seqlengths}{ An object holding sequence lengths. This can be a named integer (or numeric) vector with no duplicated names as returned by \code{\link[GenomeInfoDb]{seqlengths}()}, or any object from which sequence lengths can be extracted with \code{\link[GenomeInfoDb]{seqlengths}()}. For \code{relativeRanges}, \code{seqlengths} must describe a \emph{small} genome (see Details section below). } } \details{ Because \code{absoluteRanges} returns the \emph{absolute} ranges in an \link[IRanges]{IRanges} object, and because an \link[IRanges]{IRanges} object cannot hold ranges with an end > \code{.Machine$integer.max} (i.e. >= 2^31 on most platforms), \code{absoluteRanges} cannot be used if the size of the underlying genome (i.e. the total length of the sequences in it) is > \code{.Machine$integer.max}. Utility function \code{isSmallGenome} is provided as a mean for the user to check upfront whether the genome is \emph{small} (i.e. its size is <= \code{.Machine$integer.max}) or not, and thus compatible with \code{absoluteRanges} or not. \code{relativeRanges} applies the same restriction by looking at the \code{seqlengths} argument. } \value{ An \link[IRanges]{IRanges} object for \code{absoluteRanges}. A \link{GRanges} object for \code{relativeRanges}. \code{absoluteRanges} and \code{relativeRanges} both return an object that is \emph{parallel} to the input object (i.e. same length and names). \code{isSmallGenome} returns TRUE if the total length of the underlying sequences is <= \code{.Machine$integer.max} (e.g. Fly genome), FALSE if not (e.g. Human genome), or NA if it cannot be computed (because some sequence lengths are NA). } \author{ H. Pagès } \seealso{ \itemize{ \item \link{GRanges} objects. \item \link[IRanges]{IRanges} objects in the \pkg{IRanges} package. \item \link{Seqinfo} objects and the \code{\link{seqlengths}} getter in the \pkg{GenomeInfoDb} package. \item \link{genomicvars} for manipulating genomic variables. \item The \code{\link{tileGenome}} function for putting tiles on a genome. } } \examples{ ## --------------------------------------------------------------------- ## TOY EXAMPLE ## --------------------------------------------------------------------- gr <- GRanges(Rle(c("chr2", "chr1", "chr3", "chr1"), 4:1), IRanges(1:10, width=5), seqinfo=Seqinfo(c("chr1", "chr2", "chr3"), c(100, 50, 20))) ar <- absoluteRanges(gr) ar gr2 <- relativeRanges(ar, seqlengths(gr)) gr2 ## Sanity check: stopifnot(all(gr == gr2)) ## --------------------------------------------------------------------- ## ON REAL DATA ## --------------------------------------------------------------------- ## With a "small" genome library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) txdb <- TxDb.Dmelanogaster.UCSC.dm3.ensGene ex <- exons(txdb) ex isSmallGenome(ex) ## Note that because isSmallGenome() can return NA (see Value section ## above), its result should always be wrapped inside isTRUE() when ## used in an if statement: if (isTRUE(isSmallGenome(ex))) { ar <- absoluteRanges(ex) ar ex2 <- relativeRanges(ar, seqlengths(ex)) ex2 # original strand is not restored ## Sanity check: strand(ex2) <- strand(ex) # restore the strand stopifnot(all(ex == ex2)) } ## With a "big" genome (but we can reduce it) library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene ex <- exons(txdb) isSmallGenome(ex) \dontrun{ absoluteRanges(ex) # error! } ## However, if we are only interested in some chromosomes, we might ## still be able to use absoluteRanges(): seqlevels(ex, pruning.mode="coarse") <- paste0("chr", 1:10) isSmallGenome(ex) # TRUE! ar <- absoluteRanges(ex) ex2 <- relativeRanges(ar, seqlengths(ex)) ## Sanity check: strand(ex2) <- strand(ex) stopifnot(all(ex == ex2)) } \keyword{manip} GenomicRanges/man/constraint.Rd0000644000175400017540000003357213175713746017577 0ustar00biocbuildbiocbuild\name{Constraints} \alias{Constraints} \alias{class:Constraint} \alias{Constraint-class} \alias{Constraint} \alias{class:Constraint_OR_NULL} \alias{Constraint_OR_NULL-class} \alias{Constraint_OR_NULL} \alias{constraint} \alias{constraint<-} \alias{checkConstraint} \title{Enforcing constraints thru Constraint objects} \description{ Attaching a Constraint object to an object of class A (the "constrained" object) is meant to be a convenient/reusable/extensible way to enforce a particular set of constraints on particular instances of A. THIS IS AN EXPERIMENTAL FEATURE AND STILL VERY MUCH A WORK-IN-PROGRESS! } \details{ For the developer, using constraints is an alternative to the more traditional approach that consists in creating subclasses of A and implementing specific validity methods for each of them. However, using constraints offers the following advantages over the traditional approach: \itemize{ \item The traditional approach often tends to lead to a proliferation of subclasses of A. \item Constraints can easily be re-used across different classes without the need to create any new class. \item Constraints can easily be combined. } All constraints are implemented as concrete subclasses of the Constraint class, which is a virtual class with no slots. Like the Constraint virtual class itself, concrete Constraint subclasses cannot have slots. Here are the 7 steps typically involved in the process of putting constraints on objects of class A: \enumerate{ \item Add a slot named \code{constraint} to the definition of class A. The type of this slot must be Constraint_OR_NULL. Note that any subclass of A will inherit this slot. \item Implements the \code{constraint()} accessors (getter and setter) for objects of class A. This is done by implementing the \code{"constraint"} method (getter) and replacement method (setter) for objects of class A (see the examples below). As a convenience to the user, the setter should also accept the name of a constraint (i.e. the name of its class) in addition to an instance of that class. Note that those accessors will work on instances of any subclass of A. \item Modify the validity method for class A so it also returns the result of \code{checkConstraint(x, constraint(x))} (append this result to the result returned by the validity method). \item Testing: Create \code{x}, an instance of class A (or subclass of A). By default there is no constraint on it (\code{constraint(x)} is \code{NULL}). \code{validObject(x)} should return \code{TRUE}. \item Create a new constraint (MyConstraint) by extending the Constraint class, typically with \code{setClass("MyConstraint", contains="Constraint")}. This constraint is not enforcing anything yet so you could put it on \code{x} (with \code{constraint(x) <- "MyConstraint"}), but not much would happen. In order to actually enforce something, a \code{"checkConstraint"} method for signature \code{c(x="A", constraint="MyConstraint")} needs to be implemented. \item Implement a \code{"checkConstraint"} method for signature \code{c(x="A", constraint="MyConstraint")}. Like validity methods, \code{"checkConstraint"} methods must return \code{NULL} or a character vector describing the problems found. Like validity methods, they should never fail (i.e. they should never raise an error). Note that, alternatively, an existing constraint (e.g. SomeConstraint) can be adapted to work on objects of class A by just defining a new \code{"checkConstraint"} method for signature \code{c(x="A", constraint="SomeConstraint")}. Also, stricter constraints can be built on top of existing constraints by extending one or more existing constraints (see the examples below). \item Testing: Try \code{constraint(x) <- "MyConstraint"}. It will or will not work depending on whether \code{x} satisfies the constraint or not. In the former case, trying to modify \code{x} in a way that breaks the constraint on it will also raise an error. } } \note{ WARNING: This note is not true anymore as the \code{constraint} slot has been temporarily removed from \link{GenomicRanges} objects (starting with package GenomicRanges >= 1.7.9). Currently, only \link{GenomicRanges} objects can be constrained, that is: \itemize{ \item they have a \code{constraint} slot; \item they have \code{constraint()} accessors (getter and setter) for this slot; \item their validity method has been modified so it also returns the result of \code{checkConstraint(x, constraint(x))}. } More classes in the GenomicRanges and IRanges packages will support constraints in the near future. } \author{H. Pagès} \seealso{ \code{\link{setClass}}, \code{\link{is}}, \code{\link{setMethod}}, \code{\link{showMethods}}, \code{\link{validObject}}, \link{GenomicRanges-class} } \examples{ ## The examples below show how to define and set constraints on ## GenomicRanges objects. Note that this is how the constraint() ## setter is defined for GenomicRanges objects: #setReplaceMethod("constraint", "GenomicRanges", # function(x, value) # { # if (isSingleString(value)) # value <- new(value) # if (!is(value, "Constraint_OR_NULL")) # stop("the supplied 'constraint' must be a ", # "Constraint object, a single string, or NULL") # x@constraint <- value # validObject(x) # x # } #) #selectMethod("constraint", "GenomicRanges") # the getter #selectMethod("constraint<-", "GenomicRanges") # the setter ## We'll use the GRanges instance 'gr' created in the GRanges examples ## to test our constraints: example(GRanges, echo=FALSE) gr #constraint(gr) ## --------------------------------------------------------------------- ## EXAMPLE 1: The HasRangeTypeCol constraint. ## --------------------------------------------------------------------- ## The HasRangeTypeCol constraint checks that the constrained object ## has a unique "rangeType" metadata column and that this column ## is a 'factor' Rle with no NAs and with the following levels ## (in this order): gene, transcript, exon, cds, 5utr, 3utr. setClass("HasRangeTypeCol", contains="Constraint") ## Like validity methods, "checkConstraint" methods must return NULL or ## a character vector describing the problems found. They should never ## fail i.e. they should never raise an error. setMethod("checkConstraint", c("GenomicRanges", "HasRangeTypeCol"), function(x, constraint, verbose=FALSE) { x_mcols <- mcols(x) idx <- match("rangeType", colnames(x_mcols)) if (length(idx) != 1L || is.na(idx)) { msg <- c("'mcols(x)' must have exactly 1 column ", "named \"rangeType\"") return(paste(msg, collapse="")) } rangeType <- x_mcols[[idx]] .LEVELS <- c("gene", "transcript", "exon", "cds", "5utr", "3utr") if (!is(rangeType, "Rle") || S4Vectors:::anyMissing(runValue(rangeType)) || !identical(levels(rangeType), .LEVELS)) { msg <- c("'mcols(x)$rangeType' must be a ", "'factor' Rle with no NAs and with levels: ", paste(.LEVELS, collapse=", ")) return(paste(msg, collapse="")) } NULL } ) #\dontrun{ #constraint(gr) <- "HasRangeTypeCol" # will fail #} checkConstraint(gr, new("HasRangeTypeCol")) # with GenomicRanges >= 1.7.9 levels <- c("gene", "transcript", "exon", "cds", "5utr", "3utr") rangeType <- Rle(factor(c("cds", "gene"), levels=levels), c(8, 2)) mcols(gr)$rangeType <- rangeType #constraint(gr) <- "HasRangeTypeCol" # OK checkConstraint(gr, new("HasRangeTypeCol")) # with GenomicRanges >= 1.7.9 ## Use is() to check whether the object has a given constraint or not: #is(constraint(gr), "HasRangeTypeCol") # TRUE #\dontrun{ #mcols(gr)$rangeType[3] <- NA # will fail #} mcols(gr)$rangeType[3] <- NA checkConstraint(gr, new("HasRangeTypeCol")) # with GenomicRanges >= 1.7.9 ## --------------------------------------------------------------------- ## EXAMPLE 2: The GeneRanges constraint. ## --------------------------------------------------------------------- ## The GeneRanges constraint is defined on top of the HasRangeTypeCol ## constraint. It checks that all the ranges in the object are of type ## "gene". setClass("GeneRanges", contains="HasRangeTypeCol") ## The checkConstraint() generic will check the HasRangeTypeCol constraint ## first, and, only if it's statisfied, it will then check the GeneRanges ## constraint. setMethod("checkConstraint", c("GenomicRanges", "GeneRanges"), function(x, constraint, verbose=FALSE) { rangeType <- mcols(x)$rangeType if (!all(rangeType == "gene")) { msg <- c("all elements in 'mcols(x)$rangeType' ", "must be equal to \"gene\"") return(paste(msg, collapse="")) } NULL } ) #\dontrun{ #constraint(gr) <- "GeneRanges" # will fail #} checkConstraint(gr, new("GeneRanges")) # with GenomicRanges >= 1.7.9 mcols(gr)$rangeType[] <- "gene" ## This replace the previous constraint (HasRangeTypeCol): #constraint(gr) <- "GeneRanges" # OK checkConstraint(gr, new("GeneRanges")) # with GenomicRanges >= 1.7.9 #is(constraint(gr), "GeneRanges") # TRUE ## However, 'gr' still indirectly has the HasRangeTypeCol constraint ## (because the GeneRanges constraint extends the HasRangeTypeCol ## constraint): #is(constraint(gr), "HasRangeTypeCol") # TRUE #\dontrun{ #mcols(gr)$rangeType[] <- "exon" # will fail #} mcols(gr)$rangeType[] <- "exon" checkConstraint(gr, new("GeneRanges")) # with GenomicRanges >= 1.7.9 ## --------------------------------------------------------------------- ## EXAMPLE 3: The HasGCCol constraint. ## --------------------------------------------------------------------- ## The HasGCCol constraint checks that the constrained object has a ## unique "GC" metadata column, that this column is of type numeric, ## with no NAs, and that all the values in that column are >= 0 and <= 1. setClass("HasGCCol", contains="Constraint") setMethod("checkConstraint", c("GenomicRanges", "HasGCCol"), function(x, constraint, verbose=FALSE) { x_mcols <- mcols(x) idx <- match("GC", colnames(x_mcols)) if (length(idx) != 1L || is.na(idx)) { msg <- c("'mcols(x)' must have exactly ", "one column named \"GC\"") return(paste(msg, collapse="")) } GC <- x_mcols[[idx]] if (!is.numeric(GC) || S4Vectors:::anyMissing(GC) || any(GC < 0) || any(GC > 1)) { msg <- c("'mcols(x)$GC' must be a numeric vector ", "with no NAs and with values between 0 and 1") return(paste(msg, collapse="")) } NULL } ) ## This replace the previous constraint (GeneRanges): #constraint(gr) <- "HasGCCol" # OK checkConstraint(gr, new("HasGCCol")) # with GenomicRanges >= 1.7.9 #is(constraint(gr), "HasGCCol") # TRUE #is(constraint(gr), "GeneRanges") # FALSE #is(constraint(gr), "HasRangeTypeCol") # FALSE ## --------------------------------------------------------------------- ## EXAMPLE 4: The HighGCRanges constraint. ## --------------------------------------------------------------------- ## The HighGCRanges constraint is defined on top of the HasGCCol ## constraint. It checks that all the ranges in the object have a GC ## content >= 0.5. setClass("HighGCRanges", contains="HasGCCol") ## The checkConstraint() generic will check the HasGCCol constraint ## first, and, if it's statisfied, it will then check the HighGCRanges ## constraint. setMethod("checkConstraint", c("GenomicRanges", "HighGCRanges"), function(x, constraint, verbose=FALSE) { GC <- mcols(x)$GC if (!all(GC >= 0.5)) { msg <- c("all elements in 'mcols(x)$GC' ", "must be >= 0.5") return(paste(msg, collapse="")) } NULL } ) #\dontrun{ #constraint(gr) <- "HighGCRanges" # will fail #} checkConstraint(gr, new("HighGCRanges")) # with GenomicRanges >= 1.7.9 mcols(gr)$GC[6:10] <- 0.5 #constraint(gr) <- "HighGCRanges" # OK checkConstraint(gr, new("HighGCRanges")) # with GenomicRanges >= 1.7.9 #is(constraint(gr), "HighGCRanges") # TRUE #is(constraint(gr), "HasGCCol") # TRUE ## --------------------------------------------------------------------- ## EXAMPLE 5: The HighGCGeneRanges constraint. ## --------------------------------------------------------------------- ## The HighGCGeneRanges constraint is the combination (AND) of the ## GeneRanges and HighGCRanges constraints. setClass("HighGCGeneRanges", contains=c("GeneRanges", "HighGCRanges")) ## No need to define a method for this constraint: the checkConstraint() ## generic will automatically check the GeneRanges and HighGCRanges ## constraints. #constraint(gr) <- "HighGCGeneRanges" # OK checkConstraint(gr, new("HighGCGeneRanges")) # with GenomicRanges >= 1.7.9 #is(constraint(gr), "HighGCGeneRanges") # TRUE #is(constraint(gr), "HighGCRanges") # TRUE #is(constraint(gr), "HasGCCol") # TRUE #is(constraint(gr), "GeneRanges") # TRUE #is(constraint(gr), "HasRangeTypeCol") # TRUE ## See how all the individual constraints are checked (from less ## specific to more specific constraints): #checkConstraint(gr, constraint(gr), verbose=TRUE) checkConstraint(gr, new("HighGCGeneRanges"), verbose=TRUE) # with # GenomicRanges # >= 1.7.9 ## See all the "checkConstraint" methods: showMethods("checkConstraint") } \keyword{methods} \keyword{classes} GenomicRanges/man/coverage-methods.Rd0000644000175400017540000001034513175713746020640 0ustar00biocbuildbiocbuild\name{coverage-methods} \alias{coverage-methods} \alias{coverage} \alias{coverage,GenomicRanges-method} \alias{coverage,GRangesList-method} \title{Coverage of a GRanges or GRangesList object} \description{ \code{\link[IRanges]{coverage}} methods for \link{GRanges} and \link{GRangesList} objects. NOTE: The \code{\link[IRanges]{coverage}} generic function and methods for \link[IRanges]{Ranges} and \link[IRanges]{RangesList} objects are defined and documented in the \pkg{IRanges} package. Methods for \link[GenomicAlignments]{GAlignments} and \link[GenomicAlignments]{GAlignmentPairs} objects are defined and documented in the \pkg{GenomicAlignments} package. } \usage{ \S4method{coverage}{GenomicRanges}(x, shift=0L, width=NULL, weight=1L, method=c("auto", "sort", "hash")) \S4method{coverage}{GRangesList}(x, shift=0L, width=NULL, weight=1L, method=c("auto", "sort", "hash")) } \arguments{ \item{x}{ A \link{GRanges} or \link{GRangesList} object. } \item{shift}{ A numeric vector or a list-like object. If numeric, it must be parallel to \code{x} (recycled if necessary). If a list-like object, it must have 1 list element per seqlevel in \code{x}, and its names must be exactly \code{seqlevels(x)}. Alternatively, \code{shift} can also be specified as a single string naming a metadata column in \code{x} (i.e. a column in \code{mcols(x)}) to be used as the \code{shift} vector. See \code{?\link[IRanges]{coverage}} in the \pkg{IRanges} package for more information about this argument. } \item{width}{ Either \code{NULL} (the default), or an integer vector. If \code{NULL}, it is replaced with \code{seqlengths(x)}. Otherwise, the vector must have the length and names of \code{seqlengths(x)} and contain NAs or non-negative integers. See \code{?\link[IRanges]{coverage}} in the \pkg{IRanges} package for more information about this argument. } \item{weight}{ A numeric vector or a list-like object. If numeric, it must be parallel to \code{x} (recycled if necessary). If a list-like object, it must have 1 list element per seqlevel in \code{x}, and its names must be exactly \code{seqlevels(x)}. Alternatively, \code{weight} can also be specified as a single string naming a metadata column in \code{x} (i.e. a column in \code{mcols(x)}) to be used as the \code{weight} vector. See \code{?\link[IRanges]{coverage}} in the \pkg{IRanges} package for more information about this argument. } \item{method}{ See \code{?\link[IRanges]{coverage}} in the \pkg{IRanges} package for a description of this argument. } } \details{ When \code{x} is a \link{GRangesList} object, \code{coverage(x, ...)} is equivalent to \code{coverage(unlist(x), ...)}. } \value{ A named \link[IRanges]{RleList} object with one coverage vector per seqlevel in \code{x}. } \author{H. Pagès and P. Aboyoun} \seealso{ \itemize{ \item \code{\link[IRanges]{coverage}} in the \pkg{IRanges} package. \item \link[GenomicAlignments]{coverage-methods} in the \pkg{GenomicAlignments} package. \item \link[IRanges]{RleList} objects in the \pkg{IRanges} package. \item \link{GRanges} and \link{GRangesList} objects. } } \examples{ ## Coverage of a GRanges object: gr <- GRanges( seqnames=Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges=IRanges(1:10, end=10), strand=Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqlengths=c(chr1=11, chr2=12, chr3=13)) cvg <- coverage(gr) pcvg <- coverage(gr[strand(gr) == "+"]) mcvg <- coverage(gr[strand(gr) == "-"]) scvg <- coverage(gr[strand(gr) == "*"]) stopifnot(identical(pcvg + mcvg + scvg, cvg)) ## Coverage of a GRangesList object: gr1 <- GRanges(seqnames="chr2", ranges=IRanges(3, 6), strand = "+") gr2 <- GRanges(seqnames=c("chr1", "chr1"), ranges=IRanges(c(7,13), width=3), strand=c("+", "-")) gr3 <- GRanges(seqnames=c("chr1", "chr2"), ranges=IRanges(c(1, 4), c(3, 9)), strand=c("-", "-")) grl <- GRangesList(gr1=gr1, gr2=gr2, gr3=gr3) stopifnot(identical(coverage(grl), coverage(unlist(grl)))) } \keyword{methods} \keyword{utilities} GenomicRanges/man/findOverlaps-methods.Rd0000644000175400017540000001603213175713746021500 0ustar00biocbuildbiocbuild\name{findOverlaps-methods} \alias{findOverlaps-methods} \alias{findOverlaps} \alias{findOverlaps,GenomicRanges,GenomicRanges-method} \alias{findOverlaps,GRangesList,GenomicRanges-method} \alias{findOverlaps,GenomicRanges,GRangesList-method} \alias{findOverlaps,GRangesList,GRangesList-method} \alias{findOverlaps,RangedData,GenomicRanges-method} \alias{countOverlaps} \alias{countOverlaps,GenomicRanges,GenomicRanges-method} \alias{overlapsAny} \alias{subsetByOverlaps} \title{Finding overlapping genomic ranges} \description{ Various methods for finding/counting overlaps between objects containing genomic ranges. This man page describes the methods that operate on \link{GenomicRanges} and \link{GRangesList} objects. NOTE: The \code{\link[IRanges]{findOverlaps}} generic function and methods for \link[IRanges]{Ranges} and \link[IRanges]{RangesList} objects are defined and documented in the \pkg{IRanges} package. The methods for \link[GenomicAlignments]{GAlignments}, \link[GenomicAlignments]{GAlignmentPairs}, and \link[GenomicAlignments]{GAlignmentsList} objects are defined and documented in the \pkg{GenomicAlignments} package. \link{GenomicRanges} and \link{GRangesList} objects also support \code{countOverlaps}, \code{overlapsAny}, and \code{subsetByOverlaps} thanks to the default methods defined in the \pkg{IRanges} package and to the \code{findOverlaps} and \code{countOverlaps} methods defined in this package and documented below. } \usage{ \S4method{findOverlaps}{GenomicRanges,GenomicRanges}(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) \S4method{countOverlaps}{GenomicRanges,GenomicRanges}(query, subject, maxgap=-1L, minoverlap=0L, type=c("any", "start", "end", "within", "equal"), ignore.strand=FALSE) } \arguments{ \item{query, subject}{ A \link{GRanges} or \link{GRangesList} object. } \item{maxgap, minoverlap, type}{ See \code{?\link[IRanges]{findOverlaps}} in the \pkg{IRanges} package for a description of these arguments. } \item{select}{ When \code{select} is \code{"all"} (the default), the results are returned as a \link{Hits} object. Otherwise the returned value is an integer vector parallel to \code{query} (i.e. same length) containing the first, last, or arbitrary overlapping interval in \code{subject}, with \code{NA} indicating intervals that did not overlap any intervals in \code{subject}. } \item{ignore.strand}{ When set to \code{TRUE}, the strand information is ignored in the overlap calculations. } } \details{ When the query and the subject are \link{GRanges} or \link{GRangesList} objects, \code{findOverlaps} uses the triplet (sequence name, range, strand) to determine which features (see paragraph below for the definition of feature) from the \code{query} overlap which features in the \code{subject}, where a strand value of \code{"*"} is treated as occurring on both the \code{"+"} and \code{"-"} strand. An overlap is recorded when a feature in the \code{query} and a feature in the \code{subject} have the same sequence name, have a compatible pairing of strands (e.g. \code{"+"}/\code{"+"}, \code{"-"}/\code{"-"}, \code{"*"}/\code{"+"}, \code{"*"}/\code{"-"}, etc.), and satisfy the interval overlap requirements. In the context of \code{findOverlaps}, a feature is a collection of ranges that are treated as a single entity. For \link{GRanges} objects, a feature is a single range; while for \link{GRangesList} objects, a feature is a list element containing a set of ranges. In the results, the features are referred to by number, which run from 1 to \code{length(query)}/\code{length(subject)}. } \value{ For \code{findOverlaps} either a \link[S4Vectors]{Hits} object when \code{select="all"} or an integer vector otherwise. For \code{countOverlaps} an integer vector containing the tabulated query overlap hits. } \author{P. Aboyoun, S. Falcon, M. Lawrence, and H. Pagès} \seealso{ \itemize{ \item The \link{Hits} class for representing a set of hits between 2 vector-like objects. \item The \code{\link[IRanges]{findOverlaps}} generic function defined in the \pkg{IRanges} package. \item The \link{GNCList} constructor and class for preprocessing and representing a \link{GenomicRanges} or object as a data structure based on Nested Containment Lists. \item The \link{GRanges} and \link{GRangesList} classes. } } \examples{ ## --------------------------------------------------------------------- ## BASIC EXAMPLES ## --------------------------------------------------------------------- ## GRanges object: gr <- GRanges( seqnames=Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges=IRanges(1:10, width=10:1, names=head(letters,10)), strand=Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10) ) gr ## GRangesList object: gr1 <- GRanges(seqnames="chr2", ranges=IRanges(4:3, 6), strand="+", score=5:4, GC=0.45) gr2 <- GRanges(seqnames=c("chr1", "chr1"), ranges=IRanges(c(7,13), width=3), strand=c("+", "-"), score=3:4, GC=c(0.3, 0.5)) gr3 <- GRanges(seqnames=c("chr1", "chr2"), ranges=IRanges(c(1, 4), c(3, 9)), strand=c("-", "-"), score=c(6L, 2L), GC=c(0.4, 0.1)) grl <- GRangesList("gr1"=gr1, "gr2"=gr2, "gr3"=gr3) ## Overlapping two GRanges objects: table(!is.na(findOverlaps(gr, gr1, select="arbitrary"))) countOverlaps(gr, gr1) findOverlaps(gr, gr1) subsetByOverlaps(gr, gr1) countOverlaps(gr, gr1, type="start") findOverlaps(gr, gr1, type="start") subsetByOverlaps(gr, gr1, type="start") findOverlaps(gr, gr1, select="first") findOverlaps(gr, gr1, select="last") findOverlaps(gr1, gr) findOverlaps(gr1, gr, type="start") findOverlaps(gr1, gr, type="within") findOverlaps(gr1, gr, type="equal") ## --------------------------------------------------------------------- ## MORE EXAMPLES ## --------------------------------------------------------------------- table(!is.na(findOverlaps(gr, gr1, select="arbitrary"))) countOverlaps(gr, gr1) findOverlaps(gr, gr1) subsetByOverlaps(gr, gr1) ## Overlaps between a GRanges and a GRangesList object: table(!is.na(findOverlaps(grl, gr, select="first"))) countOverlaps(grl, gr) findOverlaps(grl, gr) subsetByOverlaps(grl, gr) countOverlaps(grl, gr, type="start") findOverlaps(grl, gr, type="start") subsetByOverlaps(grl, gr, type="start") findOverlaps(grl, gr, select="first") table(!is.na(findOverlaps(grl, gr1, select="first"))) countOverlaps(grl, gr1) findOverlaps(grl, gr1) subsetByOverlaps(grl, gr1) countOverlaps(grl, gr1, type="start") findOverlaps(grl, gr1, type="start") subsetByOverlaps(grl, gr1, type="start") findOverlaps(grl, gr1, select="first") ## Overlaps between two GRangesList objects: countOverlaps(grl, rev(grl)) findOverlaps(grl, rev(grl)) subsetByOverlaps(grl, rev(grl)) } \keyword{methods} \keyword{utilities} GenomicRanges/man/genomic-range-squeezers.Rd0000644000175400017540000000573713175713746022154 0ustar00biocbuildbiocbuild\name{genomic-range-squeezers} \alias{genomic-range-squeezers} \alias{granges} \alias{grglist} \alias{grglist,Pairs-method} \title{Squeeze the genomic ranges out of a range-based object} \description{ S4 generic functions for squeezing the genomic ranges out of a range-based object. These are analog to range squeezers \code{\link[IRanges]{ranges}} and \code{\link[IRanges]{rglist}} defined in the \pkg{IRanges} package, except that \code{granges} returns the ranges in a \link{GRanges} object (instead of an \link[IRanges]{IRanges} object for \code{\link[IRanges]{ranges}}), and \code{grglist} returns them in a \link{GRangesList} object (instead of an \link[IRanges]{IRangesList} object for \code{\link[IRanges]{rglist}}). } \usage{ granges(x, use.names=TRUE, use.mcols=FALSE, ...) grglist(x, use.names=TRUE, use.mcols=FALSE, ...) } \arguments{ \item{x}{ An object containing genomic ranges e.g. a \link[GenomicRanges]{GenomicRanges}, \link[SummarizedExperiment]{RangedSummarizedExperiment}, \link[GenomicAlignments]{GAlignments}, \link[GenomicAlignments]{GAlignmentPairs}, or \link[GenomicAlignments]{GAlignmentsList} object, or a \link[S4Vectors]{Pairs} object containing genomic ranges. } \item{use.names, use.mcols, ...}{ See \code{\link[IRanges]{ranges}} in the \pkg{IRanges} package for a description of these arguments. } } \details{ See \code{\link[IRanges]{ranges}} in the \pkg{IRanges} package for some details. For some objects (e.g. \link[GenomicAlignments]{GAlignments} and \link[GenomicAlignments]{GAlignmentPairs} objects defined in the \pkg{GenomicAlignments} package), \code{as(x, "GRanges")} and \code{as(x, "GRangesList")}, are equivalent to \code{granges(x, use.names=TRUE, use.mcols=TRUE)} and \code{grglist(x, use.names=TRUE, use.mcols=TRUE)}, respectively. } \value{ A \link{GRanges} object for \code{granges}. A \link{GRangesList} object for \code{grglist}. If \code{x} is a vector-like object (e.g. \link[GenomicAlignments]{GAlignments}), the returned object is expected to be \emph{parallel} to \code{x}, that is, the i-th element in the output corresponds to the i-th element in the input. If \code{use.names} is TRUE, then the names on \code{x} (if any) are propagated to the returned object. If \code{use.mcols} is TRUE, then the metadata columns on \code{x} (if any) are propagated to the returned object. } \author{H. Pagès} \seealso{ \itemize{ \item \link{GRanges} and \link{GRangesList} objects. \item \link[SummarizedExperiment]{RangedSummarizedExperiment} objects in the \pkg{SummarizedExperiment} packages. \item \link[GenomicAlignments]{GAlignments}, \link[GenomicAlignments]{GAlignmentPairs}, and \link[GenomicAlignments]{GAlignmentsList} objects in the \pkg{GenomicAlignments} package. } } \examples{ ## See ?GAlignments in the GenomicAlignments package for examples of ## "ranges" and "rglist" methods. } \keyword{methods} GenomicRanges/man/genomicvars.Rd0000644000175400017540000002200113175713746017711 0ustar00biocbuildbiocbuild\name{genomicvars} \alias{genomicvars} \alias{genomicvariables} \alias{coerce,RleList,GRanges-method} \alias{coerce,RleViewsList,GRanges-method} \alias{bindAsGRanges} \alias{mcolAsRleList} \alias{binnedAverage} \title{Manipulating genomic variables} \description{ A \emph{genomic variable} is a variable defined along a genome. Here are 2 ways a genomic variable is generally represented in Bioconductor: \enumerate{ \item as a named \link[IRanges]{RleList} object with one list element per chromosome; \item as a metadata column on a \emph{disjoint} GRanges object. } This man page documents tools for switching from one form to the other. } \usage{ bindAsGRanges(...) mcolAsRleList(x, varname) binnedAverage(bins, numvar, varname, na.rm=FALSE) } \arguments{ \item{...}{ One or more genomic variables in the form of named RleList objects. } \item{x}{ A \emph{disjoint} \link{GRanges} object with metadata columns on it. A \link{GRanges} object is said to be \emph{disjoint} if it contains ranges that do not overlap with each other. This can be tested with \code{isDisjoint}. See \code{?`\link{isDisjoint,GenomicRanges-method}`} for more information about the \code{isDisjoint} method for \link{GRanges} objects. } \item{varname}{ The name of the genomic variable. For \code{mcolAsRleList} this must be the name of the metadata column on \code{x} to be turned into an \link[IRanges]{RleList} object. For \code{binnedAverage} this will be the name of the metadata column that contains the binned average in the returned object. } \item{bins}{ A \link{GRanges} object representing the genomic bins. Typically obtained by calling \code{\link{tileGenome}} with \code{cut.last.tile.in.chrom=TRUE}. } \item{numvar}{ A named \link[IRanges]{RleList} object representing a numerical variable defined along the genome covered by \code{bins} (which is the genome described by \code{seqinfo(bins)}). } \item{na.rm}{ A logical value indicating whether \code{NA} values should be stripped before the average is computed. } } \details{ \code{bindAsGRanges} allows to switch the representation of one or more genomic variables from the \emph{named RleList} form to the \emph{metadata column on a disjoint GRanges object} form by binding the supplied named RleList objects together and putting them on the same \link{GRanges} object. This transformation is lossless. \code{mcolAsRleList} performs the opposite transformation and is also lossless (however the circularity flags and genome information in \code{seqinfo(x)} won't propagate). It works for any metadata column on \code{x} that can be put in \link[S4Vectors]{Rle} form i.e. that is an atomic vector or a factor. \code{binnedAverage} computes the binned average of a numerical variable defined along a genome. } \value{ For \code{bindAsGRanges}: a \link{GRanges} object with 1 metadata column per supplied genomic variable. For \code{mcolAsRleList}: a named \link[IRanges]{RleList} object with 1 list element per seqlevel in \code{x}. For \code{binnedAverage}: input \link{GRanges} object \code{bins} with an additional metadata column named \code{varname} containing the binned average. } \author{ H. Pagès } \seealso{ \itemize{ \item \link[IRanges]{RleList} objects in the \pkg{IRanges} package. \item \link{coverage,GenomicRanges-method} for computing the coverage of a \link{GRanges} object. \item The \code{\link{tileGenome}} function for putting tiles on a genome. \item \link{GRanges} objects and \link{isDisjoint,GenomicRanges-method} for the \code{isDisjoint} method for \link{GenomicRanges} objects. } } \examples{ ## --------------------------------------------------------------------- ## A. TWO WAYS TO REPRESENT A GENOMIC VARIABLE ## ----------------------------------------------------------------- ## 1) As a named RleList object ## ---------------------------- ## Let's create a genomic variable in the "named RleList" form: library(BSgenome.Scerevisiae.UCSC.sacCer2) set.seed(55) my_var <- RleList( lapply(seqlengths(Scerevisiae), function(seqlen) { tmp <- sample(50L, seqlen, replace=TRUE) %/% 50L Rle(cumsum(tmp - rev(tmp))) } ), compress=FALSE) my_var ## 2) As a metadata column on a disjoint GRanges object ## ---------------------------------------------------- gr1 <- bindAsGRanges(my_var=my_var) gr1 gr2 <- GRanges(c("chrI:1-150", "chrI:211-285", "chrI:291-377", "chrV:51-60"), score=c(0.4, 8, -10, 2.2), id=letters[1:4], seqinfo=seqinfo(Scerevisiae)) gr2 ## Going back to the "named RleList" form: mcolAsRleList(gr1, "my_var") score <- mcolAsRleList(gr2, "score") score id <- mcolAsRleList(gr2, "id") id bindAsGRanges(score=score, id=id) ## Bind 'my_var', 'score', and 'id' together: gr3 <- bindAsGRanges(my_var=my_var, score=score, id=id) ## Sanity checks: stopifnot(identical(my_var, mcolAsRleList(gr3, "my_var"))) stopifnot(identical(score, mcolAsRleList(gr3, "score"))) stopifnot(identical(id, mcolAsRleList(gr3, "id"))) gr2b <- bindAsGRanges(score=score, id=id) seqinfo(gr2b) <- seqinfo(gr2) stopifnot(identical(gr2, gr2b)) ## --------------------------------------------------------------------- ## B. BIND TOGETHER THE COVERAGES OF SEVERAL BAM FILES ## --------------------------------------------------------------------- library(pasillaBamSubset) library(GenomicAlignments) untreated1_cvg <- coverage(BamFile(untreated1_chr4())) untreated3_cvg <- coverage(BamFile(untreated3_chr4())) all_cvg <- bindAsGRanges(untreated1=untreated1_cvg, untreated3=untreated3_cvg) ## Keep regions with coverage: all_cvg[with(mcols(all_cvg), untreated1 + untreated3 >= 1)] ## Plot the coverage profiles with the Gviz package: library(Gviz) plotNumvars <- function(numvars, region, name="numvars", ...) { stopifnot(is(numvars, "GRanges")) stopifnot(is(region, "GRanges"), length(region) == 1L) gtrack <- GenomeAxisTrack() dtrack <- DataTrack(numvars, chromosome=as.character(seqnames(region)), name=name, groups=colnames(mcols(numvars)), type="l", ...) plotTracks(list(gtrack, dtrack), from=start(region), to=end(region)) } plotNumvars(all_cvg, GRanges("chr4:1-25000"), "coverage", col=c("red", "blue")) plotNumvars(all_cvg, GRanges("chr4:1.03e6-1.08e6"), "coverage", col=c("red", "blue")) ## Sanity checks: stopifnot(identical(untreated1_cvg, mcolAsRleList(all_cvg, "untreated1"))) stopifnot(identical(untreated3_cvg, mcolAsRleList(all_cvg, "untreated3"))) ## --------------------------------------------------------------------- ## C. COMPUTE THE BINNED AVERAGE OF A NUMERICAL VARIABLE DEFINED ALONG A ## GENOME ## --------------------------------------------------------------------- ## In some applications (e.g. visualization), there is the need to compute ## the average of a genomic variable for a set of predefined fixed-width ## regions (sometimes called "bins"). ## Let's use tileGenome() to create such a set of bins: bins1 <- tileGenome(seqinfo(Scerevisiae), tilewidth=100, cut.last.tile.in.chrom=TRUE) ## Compute the binned average for 'my_var' and 'score': bins1 <- binnedAverage(bins1, my_var, "binned_var") bins1 bins1 <- binnedAverage(bins1, score, "binned_score") bins1 ## Binned average in "named RleList" form: binned_var1 <- mcolAsRleList(bins1, "binned_var") binned_var1 stopifnot(all.equal(mean(my_var), mean(binned_var1))) # sanity check mcolAsRleList(bins1, "binned_score") ## With bigger bins: bins2 <- tileGenome(seqinfo(Scerevisiae), tilewidth=50000, cut.last.tile.in.chrom=TRUE) bins2 <- binnedAverage(bins2, my_var, "binned_var") bins2 <- binnedAverage(bins2, score, "binned_score") bins2 binned_var2 <- mcolAsRleList(bins2, "binned_var") binned_var2 stopifnot(all.equal(mean(my_var), mean(binned_var2))) # sanity check mcolAsRleList(bins2, "binned_score") ## Not surprisingly, the "binned" variables are much more compact in ## memory than the original variables (they contain much less runs): object.size(my_var) object.size(binned_var1) object.size(binned_var2) ## --------------------------------------------------------------------- ## D. SANITY CHECKS ## --------------------------------------------------------------------- bins3 <- tileGenome(c(chr1=10, chr2=8), tilewidth=5, cut.last.tile.in.chrom=TRUE) my_var3 <- RleList(chr1=Rle(c(1:3, NA, 5:7)), chr2=Rle(c(-3, NA, -3, NaN))) bins3 <- binnedAverage(bins3, my_var3, "binned_var3", na.rm=TRUE) binned_var3 <- mcols(bins3)$binned_var3 stopifnot( identical(mean(my_var3$chr1[1:5], na.rm=TRUE), binned_var3[1]), identical(mean(c(my_var3$chr1, 0, 0, 0)[6:10], na.rm=TRUE), binned_var3[2]), identical(mean(c(my_var3$chr2, 0), na.rm=TRUE), binned_var3[3]), identical(0, binned_var3[4]) ) } \keyword{manip} GenomicRanges/man/inter-range-methods.Rd0000644000175400017540000002415413175713746021263 0ustar00biocbuildbiocbuild\name{inter-range-methods} \alias{inter-range-methods} \alias{range} \alias{range,GenomicRanges-method} \alias{range,GPos-method} \alias{range,GRangesList-method} \alias{range,GenomicRangesList-method} \alias{reduce} \alias{reduce,GenomicRanges-method} \alias{reduce,GRangesList-method} \alias{reduce,GenomicRangesList-method} \alias{gaps} \alias{gaps,GenomicRanges-method} \alias{disjoin} \alias{disjoin,GenomicRanges-method} \alias{disjoin,GRangesList-method} \alias{disjoin,GenomicRangesList-method} \alias{isDisjoint} \alias{isDisjoint,GenomicRanges-method} \alias{isDisjoint,GPos-method} \alias{isDisjoint,GRangesList-method} \alias{isDisjoint,GenomicRangesList-method} \alias{disjointBins} \alias{disjointBins,GenomicRanges-method} \title{Inter range transformations of a GRanges or GRangesList object} \description{ This man page documents \emph{inter range transformations} of a \link{GenomicRanges} object (i.e. of an object that belongs to the \link{GenomicRanges} class or one of its subclasses, this includes for example \link{GRanges} objects), or a \link{GRangesList} object. See \code{?`\link[IRanges]{intra-range-methods}`} and \code{?`\link[IRanges]{inter-range-methods}`} in the \pkg{IRanges} package for a quick introduction to \emph{intra range} and \emph{inter range transformations}. See \code{?`\link[GenomicRanges]{intra-range-methods}`} for \emph{intra range transformations} of a \link{GenomicRanges} object or \link{GRangesList} object. } \usage{ \S4method{range}{GenomicRanges}(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) \S4method{range}{GRangesList}(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) \S4method{range}{GenomicRangesList}(x, ..., with.revmap=FALSE, ignore.strand=FALSE, na.rm=FALSE) \S4method{reduce}{GenomicRanges}(x, drop.empty.ranges=FALSE, min.gapwidth=1L, with.revmap=FALSE, with.inframe.attrib=FALSE, ignore.strand=FALSE) \S4method{reduce}{GRangesList}(x, drop.empty.ranges=FALSE, min.gapwidth=1L, with.revmap=FALSE, with.inframe.attrib=FALSE, ignore.strand=FALSE) \S4method{reduce}{GenomicRangesList}(x, drop.empty.ranges=FALSE, min.gapwidth=1L, with.inframe.attrib=FALSE, ignore.strand=FALSE) \S4method{gaps}{GenomicRanges}(x, start=1L, end=seqlengths(x)) \S4method{disjoin}{GenomicRanges}(x, with.revmap=FALSE, ignore.strand=FALSE) \S4method{disjoin}{GRangesList}(x, with.revmap=FALSE, ignore.strand=FALSE) \S4method{disjoin}{GenomicRangesList}(x, with.revmap=FALSE, ignore.strand=FALSE) \S4method{isDisjoint}{GenomicRanges}(x, ignore.strand=FALSE) \S4method{isDisjoint}{GRangesList}(x, ignore.strand=FALSE) \S4method{isDisjoint}{GenomicRangesList}(x, ignore.strand=FALSE) \S4method{disjointBins}{GenomicRanges}(x, ignore.strand=FALSE) } \arguments{ \item{x}{A \link{GenomicRanges} or \link{GenomicRangesList} object.} \item{drop.empty.ranges, min.gapwidth, with.revmap, with.inframe.attrib, start, end}{ See \code{?`\link[IRanges]{inter-range-methods}`} in the \pkg{IRanges} package. } \item{ignore.strand}{ \code{TRUE} or \code{FALSE}. Whether the strand of the input ranges should be ignored or not. See details below. } \item{...}{ For \code{range}, additional \code{GenomicRanges} objects to consider. Ignored otherwise. } \item{na.rm}{Ignored.} } \details{ \subsection{On a GRanges object}{ \code{range} returns an object of the same type as \code{x} containing range bounds for each distinct (seqname, strand) pairing. The names (\code{names(x)}) and the metadata columns in \code{x} are dropped. \code{reduce} returns an object of the same type as \code{x} containing reduced ranges for each distinct (seqname, strand) pairing. The names (\code{names(x)}) and the metadata columns in \code{x} are dropped. See \code{?\link[IRanges]{reduce}} for more information about range reduction and for a description of the optional arguments. \code{gaps} returns an object of the same type as \code{x} containing complemented ranges for each distinct (seqname, strand) pairing. The names (\code{names(x)}) and the columns in \code{x} are dropped. For the start and end arguments of this gaps method, it is expected that the user will supply a named integer vector (where the names correspond to the appropriate seqlevels). See \code{?\link[IRanges]{gaps}} for more information about range complements and for a description of the optional arguments. \code{disjoin} returns an object of the same type as \code{x} containing disjoint ranges for each distinct (seqname, strand) pairing. The names (\code{names(x)}) and the metadata columns in \code{x} are dropped. If \code{with.revmap=TRUE}, a metadata column that maps the ouput ranges to the input ranges is added to the returned object. See \code{?\link[IRanges]{disjoin}} for more information. \code{isDisjoint} returns a logical value indicating whether the ranges in \code{x} are disjoint (i.e. non-overlapping). \code{disjointBins} returns bin indexes for the ranges in \code{x}, such that ranges in the same bin do not overlap. If \code{ignore.strand=FALSE}, the two features cannot overlap if they are on different strands. } \subsection{On a GRangesList/GenomicRangesList object}{ When they are supported on GRangesList object \code{x}, the above inter range transformations will apply the transformation to each of the list elements in \code{x} and return a list-like object \emph{parallel} to \code{x} (i.e. with 1 list element per list element in \code{x}). If \code{x} has names on it, they're propagated to the returned object. } } \author{H. Pagès and P. Aboyoun} \seealso{ \itemize{ \item The \link{GenomicRanges} and \link{GRanges} classes. \item The \link[IRanges]{Ranges} class in the \pkg{IRanges} package. \item The \link[IRanges]{inter-range-methods} man page in the \pkg{IRanges} package. \item \link{GenomicRanges-comparison} for comparing and ordering genomic ranges. \item \code{\link[S4Vectors]{endoapply}} in the \pkg{S4Vectors} package. } } \examples{ gr <- GRanges( seqnames=Rle(paste("chr", c(1, 2, 1, 3), sep=""), c(1, 3, 2, 4)), ranges=IRanges(1:10, width=10:1, names=letters[1:10]), strand=Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10) ) gr gr1 <- GRanges(seqnames="chr2", ranges=IRanges(3, 6), strand="+", score=5L, GC=0.45) gr2 <- GRanges(seqnames="chr1", ranges=IRanges(c(10, 7, 19), width=5), strand=c("+", "-", "+"), score=3:5, GC=c(0.3, 0.5, 0.66)) gr3 <- GRanges(seqnames=c("chr1", "chr2"), ranges=IRanges(c(1, 4), c(3, 9)), strand=c("-", "-"), score=c(6L, 2L), GC=c(0.4, 0.1)) grl <- GRangesList(gr1=gr1, gr2=gr2, gr3=gr3) grl ## --------------------------------------------------------------------- ## range() ## --------------------------------------------------------------------- ## On a GRanges object: range(gr) range(gr, with.revmap=TRUE) ## On a GRangesList object: range(grl) range(grl, ignore.strand=TRUE) range(grl, with.revmap=TRUE, ignore.strand=TRUE) # --------------------------------------------------------------------- ## reduce() ## --------------------------------------------------------------------- reduce(gr) gr2 <- reduce(gr, with.revmap=TRUE) revmap <- mcols(gr2)$revmap # an IntegerList ## Use the mapping from reduced to original ranges to group the original ## ranges by reduced range: relist(gr[unlist(revmap)], revmap) ## Or use it to split the DataFrame of original metadata columns by ## reduced range: relist(mcols(gr)[unlist(revmap), ], revmap) # a SplitDataFrameList ## [For advanced users] Use this reverse mapping to compare the reduced ## ranges with the ranges they originate from: expanded_gr2 <- rep(gr2, elementNROWS(revmap)) reordered_gr <- gr[unlist(revmap)] codes <- pcompare(expanded_gr2, reordered_gr) ## All the codes should translate to "d", "e", "g", or "h" (the 4 letters ## indicating that the range on the left contains the range on the right): alphacodes <- rangeComparisonCodeToLetter(pcompare(expanded_gr2, reordered_gr)) stopifnot(all(alphacodes \%in\% c("d", "e", "g", "h"))) ## On a big GRanges object with a lot of seqlevels: mcols(gr) <- NULL biggr <- c(gr, GRanges("chr1", IRanges(c(4, 1), c(5, 2)), strand="+")) seqlevels(biggr) <- paste0("chr", 1:2000) biggr <- rep(biggr, 25000) set.seed(33) seqnames(biggr) <- sample(factor(seqlevels(biggr), levels=seqlevels(biggr)), length(biggr), replace=TRUE) biggr2 <- reduce(biggr, with.revmap=TRUE) revmap <- mcols(biggr2)$revmap expanded_biggr2 <- rep(biggr2, elementNROWS(revmap)) reordered_biggr <- biggr[unlist(revmap)] codes <- pcompare(expanded_biggr2, reordered_biggr) alphacodes <- rangeComparisonCodeToLetter(pcompare(expanded_biggr2, reordered_biggr)) stopifnot(all(alphacodes \%in\% c("d", "e", "g", "h"))) table(alphacodes) ## On a GRangesList object: reduce(grl) # Doesn't really reduce anything but note the reordering # of the inner elements in the 2nd and 3rd list elements: # the ranges are reordered by sequence name first (which # should appear in the same order as in 'seqlevels(grl)'), # and then by strand. reduce(grl, ignore.strand=TRUE) # 2nd list element got reduced ## --------------------------------------------------------------------- ## gaps() ## --------------------------------------------------------------------- gaps(gr, start=1, end=10) ## --------------------------------------------------------------------- ## disjoin(), isDisjoint(), disjointBins() ## --------------------------------------------------------------------- disjoin(gr) disjoin(gr, with.revmap=TRUE) disjoin(gr, with.revmap=TRUE, ignore.strand=TRUE) isDisjoint(gr) stopifnot(isDisjoint(disjoin(gr))) disjointBins(gr) stopifnot(all(sapply(split(gr, disjointBins(gr)), isDisjoint))) ## On a GRangesList object: disjoin(grl) # doesn't really disjoin anything but note the reordering disjoin(grl, with.revmap=TRUE) } \keyword{utilities} GenomicRanges/man/intra-range-methods.Rd0000644000175400017540000002216513175713746021257 0ustar00biocbuildbiocbuild\name{intra-range-methods} \alias{intra-range-methods} \alias{shift} \alias{shift,GenomicRanges-method} \alias{shift,GRangesList-method} \alias{shift,GenomicRangesList-method} \alias{narrow} \alias{narrow,GenomicRanges-method} \alias{narrow,GRangesList-method} \alias{narrow,GenomicRangesList-method} \alias{resize} \alias{resize,GenomicRanges-method} \alias{resize,GRangesList-method} \alias{resize,GenomicRangesList-method} \alias{flank} \alias{flank,GenomicRanges-method} \alias{flank,GRangesList-method} \alias{flank,GenomicRangesList-method} \alias{promoters} \alias{promoters,GenomicRanges-method} \alias{promoters,GRangesList-method} \alias{promoters,GenomicRangesList-method} \alias{restrict} \alias{restrict,GenomicRanges-method} \alias{restrict,GRangesList-method} \alias{restrict,GenomicRangesList-method} \alias{trim,GenomicRanges-method} \alias{Ops,GenomicRanges,numeric-method} \title{Intra range transformations of a GRanges or GRangesList object} \description{ This man page documents \emph{intra range transformations} of a \link{GenomicRanges} object (i.e. of an object that belongs to the \link{GenomicRanges} class or one of its subclasses, this includes for example \link{GRanges} objects), or a \link{GRangesList} object. See \code{?`\link[IRanges]{intra-range-methods}`} and \code{?`\link[IRanges]{inter-range-methods}`} in the \pkg{IRanges} package for a quick introduction to \emph{intra range} and \emph{inter range transformations}. \emph{Intra range} methods for \link[GenomicAlignments]{GAlignments} and \link[GenomicAlignments]{GAlignmentsList} objects are defined and documented in the \pkg{GenomicAlignments} package. See \code{?`\link[GenomicRanges]{inter-range-methods}`} for \emph{inter range transformations} of a \link{GenomicRanges} or \link{GRangesList} object. } \usage{ \S4method{shift}{GenomicRanges}(x, shift=0L, use.names=TRUE) \S4method{shift}{GRangesList}(x, shift=0L, use.names=TRUE) \S4method{shift}{GenomicRangesList}(x, shift=0L, use.names=TRUE) \S4method{narrow}{GenomicRanges}(x, start=NA, end=NA, width=NA, use.names=TRUE) \S4method{narrow}{GRangesList}(x, start=NA, end=NA, width=NA, use.names=TRUE) \S4method{narrow}{GenomicRangesList}(x, start=NA, end=NA, width=NA, use.names=TRUE) \S4method{resize}{GenomicRanges}(x, width, fix="start", use.names=TRUE, ignore.strand=FALSE) \S4method{resize}{GRangesList}(x, width, fix="start", use.names=TRUE, ignore.strand=FALSE) \S4method{resize}{GenomicRangesList}(x, width, fix="start", use.names=TRUE, ignore.strand=FALSE) \S4method{flank}{GenomicRanges}(x, width, start=TRUE, both=FALSE, use.names=TRUE, ignore.strand=FALSE) \S4method{flank}{GRangesList}(x, width, start=TRUE, both=FALSE, use.names=TRUE, ignore.strand=FALSE) \S4method{flank}{GenomicRangesList}(x, width, start=TRUE, both=FALSE, use.names=TRUE, ignore.strand=FALSE) \S4method{promoters}{GenomicRanges}(x, upstream=2000, downstream=200) \S4method{promoters}{GRangesList}(x, upstream=2000, downstream=200) \S4method{promoters}{GenomicRangesList}(x, upstream=2000, downstream=200) \S4method{restrict}{GenomicRanges}(x, start=NA, end=NA, keep.all.ranges=FALSE, use.names=TRUE) \S4method{restrict}{GRangesList}(x, start=NA, end=NA, keep.all.ranges=FALSE, use.names=TRUE) \S4method{restrict}{GenomicRangesList}(x, start=NA, end=NA, keep.all.ranges=FALSE, use.names=TRUE) \S4method{trim}{GenomicRanges}(x, use.names=TRUE) } \arguments{ \item{x}{A \link{GenomicRanges} or \link{GRangesList} object.} \item{shift, use.names, start, end, width, both, fix, keep.all.ranges, upstream, downstream}{ See \code{?`\link[IRanges]{intra-range-methods}`}. } \item{ignore.strand}{ \code{TRUE} or \code{FALSE}. Whether the strand of the input ranges should be ignored or not. See details below. } \item{\dots}{ Additional arguments to methods. } } \details{ \itemize{ \item{}{\code{shift} behaves like the \code{shift} method for \link[IRanges]{Ranges} objects. See \code{?`\link[IRanges]{intra-range-methods}`} for the details. } \item(){\code{narrow} on a \link{GenomicRanges} object behaves like on a \link[IRanges]{Ranges} object. See \code{?`\link[IRanges]{intra-range-methods}`} for the details. A major difference though is that it returns a \link{GenomicRanges} object instead of a \link[IRanges]{Ranges} object. The returned object is \emph{parallel} (i.e. same length and names) to the original object \code{x}. } \item{}{\code{resize} returns an object of the same type and length as \code{x} containing intervals that have been resized to width \code{width} based on the \code{strand(x)} values. Elements where \code{strand(x) == "+"} or \code{strand(x) == "*"} are anchored at \code{start(x)} and elements where \code{strand(x) == "-"} are anchored at the \code{end(x)}. The \code{use.names} argument determines whether or not to keep the names on the ranges. } \item{}{\code{flank} returns an object of the same type and length as \code{x} containing intervals of width \code{width} that flank the intervals in \code{x}. The \code{start} argument takes a logical indicating whether \code{x} should be flanked at the "start" (\code{TRUE}) or the "end" (\code{FALSE}), which for \code{strand(x) != "-"} is \code{start(x)} and \code{end(x)} respectively and for \code{strand(x) == "-"} is \code{end(x)} and \code{start(x)} respectively. The \code{both} argument takes a single logical value indicating whether the flanking region \code{width} positions extends \emph{into} the range. If \code{both=TRUE}, the resulting range thus straddles the end point, with \code{width} positions on either side. } \item{}{ \code{promoters} returns an object of the same type and length as \code{x} containing promoter ranges. Promoter ranges extend around the transcription start site (TSS) which is defined as \code{start(x)}. The \code{upsteam} and \code{downstream} arguments define the number of nucleotides in the 5' and 3' direction, respectively. The full range is defined as, (start(x) - upstream) to (start(x) + downstream - 1). Ranges on the \code{*} strand are treated the same as those on the \code{+} strand. When no seqlengths are present in \code{x}, it is possible to have non-positive start values in the promoter ranges. This occurs when (TSS - \code{upstream}) < 1. In the equal but opposite case, the \code{end} values of the ranges may extend beyond the chromosome end when (TSS + \code{downstream} + 1) > 'chromosome end'. When \code{seqlengths} are not \code{NA} the promoter ranges are kept within the bounds of the defined \code{seqlengths}. } \item{}{\code{restrict} returns an object of the same type and length as \code{x} containing restricted ranges for distinct seqnames. The \code{start} and \code{end} arguments can be a named numeric vector of seqnames for the ranges to be resticted or a numeric vector or length 1 if the restriction operation is to be applied to all the sequences in \code{x}. See \code{?`\link[IRanges]{intra-range-methods}`} for more information about range restriction and for a description of the optional arguments. } \item{}{\code{trim} trims out-of-bound ranges located on non-circular sequences whose length is not NA. } } } \author{P. Aboyoun and V. Obenchain } \seealso{ \itemize{ \item \link{GenomicRanges}, \link{GRanges}, and \link{GRangesList} objects. \item The \link[IRanges]{intra-range-methods} man page in the \pkg{IRanges} package. \item The \link[IRanges]{Ranges} class in the \pkg{IRanges} package. \item \code{\link[S4Vectors]{endoapply}} in the \pkg{S4Vectors} package. } } \examples{ ## --------------------------------------------------------------------- ## A. ON A GRanges OBJECT ## --------------------------------------------------------------------- gr <- GRanges( seqnames=Rle(paste("chr", c(1, 2, 1, 3), sep=""), c(1, 3, 2, 4)), ranges=IRanges(1:10, width=10:1, names=letters[1:10]), strand=Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10) ) gr shift(gr, 1) narrow(gr[-10], start=2, end=-2) resize(gr, width=10) flank(gr, width=10) restrict(gr, start=3, end=7) gr <- GRanges("chr1", IRanges(rep(10, 3), width=6), c("+", "-", "*")) promoters(gr, 2, 2) ## --------------------------------------------------------------------- ## B. ON A GRangesList OBJECT ## --------------------------------------------------------------------- gr1 <- GRanges("chr2", IRanges(3, 6)) gr2 <- GRanges(c("chr1", "chr1"), IRanges(c(7,13), width=3), strand=c("+", "-")) gr3 <- GRanges(c("chr1", "chr2"), IRanges(c(1, 4), c(3, 9)), strand="-") grl <- GRangesList(gr1= gr1, gr2=gr2, gr3=gr3) grl resize(grl, width=20) flank(grl, width=20) restrict(grl, start=3) } \keyword{methods} \keyword{utilities} GenomicRanges/man/makeGRangesFromDataFrame.Rd0000644000175400017540000002143013175713746022156 0ustar00biocbuildbiocbuild\name{makeGRangesFromDataFrame} \alias{makeGRangesFromDataFrame} \alias{coerce,data.frame,GRanges-method} \alias{coerce,DataFrame,GRanges-method} \title{Make a GRanges object from a data.frame or DataFrame} \description{ \code{makeGRangesFromDataFrame} takes a data-frame-like object as input and tries to automatically find the columns that describe genomic ranges. It returns them as a \link{GRanges} object. \code{makeGRangesFromDataFrame} is also the workhorse behind the coercion method from data.frame (or \link[S4Vectors]{DataFrame}) to \link{GRanges}. } \usage{ makeGRangesFromDataFrame(df, keep.extra.columns=FALSE, ignore.strand=FALSE, seqinfo=NULL, seqnames.field=c("seqnames", "seqname", "chromosome", "chrom", "chr", "chromosome_name", "seqid"), start.field="start", end.field=c("end", "stop"), strand.field="strand", starts.in.df.are.0based=FALSE) } \arguments{ \item{df}{ A data.frame or \link[S4Vectors]{DataFrame} object. If not, then the function first tries to turn \code{df} into a data frame with \code{as.data.frame(df)}. } \item{keep.extra.columns}{ \code{TRUE} or \code{FALSE} (the default). If \code{TRUE}, the columns in \code{df} that are not used to form the genomic ranges of the returned \link{GRanges} object are then returned as metadata columns on the object. Otherwise, they are ignored. If \code{df} has a \code{width} column, then it's always ignored. } \item{ignore.strand}{ \code{TRUE} or \code{FALSE} (the default). If \code{TRUE}, then the strand of the returned \link{GRanges} object is set to \code{"*"}. } \item{seqinfo}{ Either \code{NULL}, or a \link{Seqinfo} object, or a character vector of seqlevels, or a named numeric vector of sequence lengths. When not \code{NULL}, it must be compatible with the genomic ranges in \code{df} i.e. it must include at least the sequence levels represented in \code{df}. } \item{seqnames.field}{ A character vector of recognized names for the column in \code{df} that contains the chromosome name (a.k.a. sequence name) associated with each genomic range. Only the first name in \code{seqnames.field} that is found in \code{colnames(df)} is used. If no one is found, then an error is raised. } \item{start.field}{ A character vector of recognized names for the column in \code{df} that contains the start positions of the genomic ranges. Only the first name in \code{start.field} that is found in \code{colnames(df)} is used. If no one is found, then an error is raised. } \item{end.field}{ A character vector of recognized names for the column in \code{df} that contains the end positions of the genomic ranges. Only the first name in \code{start.field} that is found in \code{colnames(df)} is used. If no one is found, then an error is raised. } \item{strand.field}{ A character vector of recognized names for the column in \code{df} that contains the strand associated with each genomic range. Only the first name in \code{strand.field} that is found in \code{colnames(df)} is used. If no one is found or if \code{ignore.strand} is \code{TRUE}, then the strand of the returned \link{GRanges} object is set to \code{"*"}. } \item{starts.in.df.are.0based}{ \code{TRUE} or \code{FALSE} (the default). If \code{TRUE}, then the start positions of the genomic ranges in \code{df} are considered to be \emph{0-based} and are converted to \emph{1-based} in the returned \link{GRanges} object. This feature is intended to make it more convenient to handle input that contains data obtained from resources using the "0-based start" convention. A notorious example of such resource is the UCSC Table Browser (\url{http://genome.ucsc.edu/cgi-bin/hgTables}). } } \value{ A \link{GRanges} object with one element per row in the input. If the \code{seqinfo} argument was supplied, the returned object will have exactly the seqlevels specified in \code{seqinfo} and in the same order. Otherwise, the seqlevels are ordered according to the output of the \code{\link[GenomeInfoDb]{rankSeqlevels}} function (except if \code{df} contains the seqnames in the form of a factor-Rle, in which case the levels of the factor-Rle become the seqlevels of the returned object and with no re-ordering). If \code{df} has non-automatic row names (i.e. \code{rownames(df)} is not \code{NULL} and is not \code{seq_len(nrow(df))}), then they will be used to set names on the returned \link{GRanges} object. } \note{ Coercing data.frame or \link[S4Vectors]{DataFrame} \code{df} into a \link{GRanges} object (with \code{as(df, "GRanges")}), or calling \code{GRanges(df)}, are both equivalent to calling \code{makeGRangesFromDataFrame(df, keep.extra.columns=TRUE)}. } \author{ H. Pagès, based on a proposal by Kasper Daniel Hansen } \seealso{ \itemize{ \item \link{GRanges} objects. \item \link[GenomeInfoDb]{Seqinfo} objects and the \code{\link[GenomeInfoDb]{rankSeqlevels}} function in the \pkg{GenomeInfoDb} package. \item The \code{\link{makeGRangesListFromFeatureFragments}} function for making a \link{GRangesList} object from a list of fragmented features. \item The \code{\link[rtracklayer]{getTable}} function in the \pkg{rtracklayer} package for an R interface to the UCSC Table Browser. \item \link[S4Vectors]{DataFrame} objects in the \pkg{S4Vectors} package. } } \examples{ ## --------------------------------------------------------------------- ## BASIC EXAMPLES ## --------------------------------------------------------------------- df <- data.frame(chr="chr1", start=11:15, end=12:16, strand=c("+","-","+","*","."), score=1:5) df makeGRangesFromDataFrame(df) # strand value "." is replaced with "*" ## The strand column is optional: df <- data.frame(chr="chr1", start=11:15, end=12:16, score=1:5) makeGRangesFromDataFrame(df) gr <- makeGRangesFromDataFrame(df, keep.extra.columns=TRUE) gr2 <- as(df, "GRanges") # equivalent to the above stopifnot(identical(gr, gr2)) gr2 <- GRanges(df) # equivalent to the above stopifnot(identical(gr, gr2)) makeGRangesFromDataFrame(df, ignore.strand=TRUE) makeGRangesFromDataFrame(df, keep.extra.columns=TRUE, ignore.strand=TRUE) makeGRangesFromDataFrame(df, seqinfo=paste0("chr", 4:1)) makeGRangesFromDataFrame(df, seqinfo=c(chrM=NA, chr1=500, chrX=100)) makeGRangesFromDataFrame(df, seqinfo=Seqinfo(paste0("chr", 4:1))) ## --------------------------------------------------------------------- ## ABOUT AUTOMATIC DETECTION OF THE seqnames/start/end/strand COLUMNS ## --------------------------------------------------------------------- ## Automatic detection of the seqnames/start/end/strand columns is ## case insensitive: df <- data.frame(ChRoM="chr1", StarT=11:15, stoP=12:16, STRAND=c("+","-","+","*","."), score=1:5) makeGRangesFromDataFrame(df) ## It also ignores a common prefix between the start and end columns: df <- data.frame(seqnames="chr1", tx_start=11:15, tx_end=12:16, strand=c("+","-","+","*","."), score=1:5) makeGRangesFromDataFrame(df) ## The common prefix between the start and end columns is used to ## disambiguate between more than one seqnames column: df <- data.frame(chrom="chr1", tx_start=11:15, tx_end=12:16, tx_chr="chr2", score=1:5) makeGRangesFromDataFrame(df) ## --------------------------------------------------------------------- ## 0-BASED VS 1-BASED START POSITIONS ## --------------------------------------------------------------------- if (require(rtracklayer)) { session <- browserSession() genome(session) <- "sacCer2" query <- ucscTableQuery(session, "Assembly") df <- getTable(query) head(df) ## A common pitfall is to forget that the UCSC Table Browser uses the ## "0-based start" convention: gr0 <- makeGRangesFromDataFrame(df, keep.extra.columns=TRUE, start.field="chromStart", end.field="chromEnd") head(gr0) ## The start positions need to be converted into 1-based positions, ## to adhere to the convention used in Bioconductor: gr1 <- makeGRangesFromDataFrame(df, keep.extra.columns=TRUE, start.field="chromStart", end.field="chromEnd", starts.in.df.are.0based=TRUE) head(gr1) } } \keyword{manip} GenomicRanges/man/makeGRangesListFromDataFrame.Rd0000644000175400017540000000602113175713746023011 0ustar00biocbuildbiocbuild\name{makeGRangesListFromDataFrame} \alias{makeGRangesListFromDataFrame} \title{Make a GRangesList object from a data.frame or DataFrame} \description{ \code{makeGRangesListFromDataFrame} extends the \link[GenomicRanges]{makeGRangesFromDataFrame} functionality from \code{GenomicRanges}. It can take a data-frame-like object as input and tries to automatically find the columns that describe the genomic ranges. It returns a \link{GRangesList} object. This is different from the \code{makeGRangesFromDataFrame} function by requiring a \code{split.field}. The \code{split.field} acts like the "f" argument in the \code{\link[S4Vectors]{split}} function. This factor must be of the same length as the number of rows in the \code{DataFrame} argument. The \code{split.field} may also be a character vector. } \usage{ makeGRangesListFromDataFrame(df, split.field = NULL, names.field = NULL, ...) } \arguments{ \item{df}{ A \code{DataFrame} or \code{data.frame} class object } \item{split.field}{ A character string of a recognized column name in \code{df} that contains the grouping. This column defines how the rows of \code{df} are split and is typically a \code{factor} or \code{character} vector. When \code{split.field} is not provided the \code{df} will be split by the number of rows. } \item{names.field}{ An optional single \code{character} string indicating the name of the column in \code{df} that designates the names for the ranges in the elements of the \link{GRangesList}. } \item{...}{ Additional arguments passed on to \link{makeGRangesFromDataFrame} } } \value{ A \linkS4class{GRangesList} of the same length as the number of levels or unique character strings in the \code{df} column indicated by \code{split.field}. When \code{split.field} is not provided the \code{df} is split by row and the resulting \linkS4class{GRangesList} has the same length as nrow(df). Names on the individual ranges are taken from the \code{names.field} argument. Names on the outer list elements of the \linkS4class{GRangesList} are propagated from \code{split.field}. } \author{ M. Ramos } \seealso{ \itemize{ \item \link{makeGRangesFromDataFrame} } } \examples{ ## --------------------------------------------------------------------- ## BASIC EXAMPLES ## --------------------------------------------------------------------- df <- data.frame(chr="chr1", start=11:15, end=12:16, strand=c("+","-","+","*","."), score=1:5, specimen = c("a", "a", "b", "b", "c"), gene_symbols = paste0("GENE", letters[1:5])) df grl <- makeGRangesListFromDataFrame(df, split.field = "specimen", names.field = "gene_symbols") grl names(grl) ## Keep metadata columns makeGRangesListFromDataFrame(df, split.field = "specimen", keep.extra.columns = TRUE) } GenomicRanges/man/nearest-methods.Rd0000644000175400017540000002125413175713746020507 0ustar00biocbuildbiocbuild\name{nearest-methods} \alias{nearest-methods} \alias{precede} \alias{precede,GenomicRanges,GenomicRanges-method} \alias{precede,GenomicRanges,missing-method} \alias{follow} \alias{follow,GenomicRanges,GenomicRanges-method} \alias{follow,GenomicRanges,missing-method} \alias{nearest} \alias{nearest,GenomicRanges,GenomicRanges-method} \alias{nearest,GenomicRanges,missing-method} \alias{distance} \alias{distance,GenomicRanges,GenomicRanges-method} \alias{distanceToNearest} \alias{distanceToNearest,GenomicRanges,GenomicRanges-method} \alias{distanceToNearest,GenomicRanges,missing-method} \title{Finding the nearest genomic range neighbor} \description{ The \code{nearest}, \code{precede}, \code{follow}, \code{distance} and \code{distanceToNearest} methods for \code{\linkS4class{GenomicRanges}} objects and subclasses. } \usage{ \S4method{precede}{GenomicRanges,GenomicRanges}(x, subject, select=c("first", "all"), ignore.strand=FALSE) \S4method{precede}{GenomicRanges,missing}(x, subject, select=c("first", "all"), ignore.strand=FALSE) \S4method{follow}{GenomicRanges,GenomicRanges}(x, subject, select=c("last", "all"), ignore.strand=FALSE) \S4method{follow}{GenomicRanges,missing}(x, subject, select=c("last", "all"), ignore.strand=FALSE) \S4method{nearest}{GenomicRanges,GenomicRanges}(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) \S4method{nearest}{GenomicRanges,missing}(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) \S4method{distanceToNearest}{GenomicRanges,GenomicRanges}(x, subject, ignore.strand=FALSE, ...) \S4method{distanceToNearest}{GenomicRanges,missing}(x, subject, ignore.strand=FALSE, ...) \S4method{distance}{GenomicRanges,GenomicRanges}(x, y, ignore.strand=FALSE, ...) } \arguments{ \item{x}{The query \link{GenomicRanges} instance. } \item{subject}{The subject \link{GenomicRanges} instance within which the nearest neighbors are found. Can be missing, in which case \code{x} is also the subject. } \item{y}{For the \code{distance} method, a \code{GRanges} instance. Cannot be missing. If \code{x} and \code{y} are not the same length, the shortest will be recycled to match the length of the longest. } \item{select}{Logic for handling ties. By default, all methods select a single interval (arbitrary for \code{nearest}, the first by order in \code{subject} for \code{precede}, and the last for \code{follow}). When \code{select="all"} a \link[S4Vectors]{Hits} object is returned with all matches for \code{x}. } \item{ignore.strand}{ A \code{logical} indicating if the strand of the input ranges should be ignored. When \code{TRUE}, strand is set to \code{'+'}. } \item{...}{Additional arguments for methods.} } \details{ \itemize{ \item{nearest: }{ Performs conventional nearest neighbor finding. Returns an integer vector containing the index of the nearest neighbor range in \code{subject} for each range in \code{x}. If there is no nearest neighbor \code{NA} is returned. For details of the algorithm see the man page in IRanges, ?\code{nearest}. } \item{precede: }{ For each range in \code{x}, \code{precede} returns the index of the range in \code{subject} that is directly preceded by the range in \code{x}. Overlapping ranges are excluded. \code{NA} is returned when there are no qualifying ranges in \code{subject}. } \item{follow: }{ The opposite of \code{precede}, \code{follow} returns the index of the range in \code{subject} that is directly followed by the range in \code{x}. Overlapping ranges are excluded. \code{NA} is returned when there are no qualifying ranges in \code{subject}. } \item{Orientation and strand for \code{precede} and \code{follow}: }{ Orientation is 5' to 3', consistent with the direction of translation. Because positional numbering along a chromosome is from left to right and transcription takes place from 5' to 3', \code{precede} and \code{follow} can appear to have `opposite' behavior on the \code{+} and \code{-} strand. Using positions 5 and 6 as an example, 5 precedes 6 on the \code{+} strand but follows 6 on the \code{-} strand. The table below outlines the orientation when ranges on different strands are compared. In general, a feature on \code{*} is considered to belong to both strands. The single exception is when both \code{x} and \code{subject} are \code{*} in which case both are treated as \code{+}. \preformatted{ x | subject | orientation -----+-----------+---------------- a) + | + | ---> b) + | - | NA c) + | * | ---> d) - | + | NA e) - | - | <--- f) - | * | <--- g) * | + | ---> h) * | - | <--- i) * | * | ---> (the only situation where * arbitrarily means +) } } \item{distanceToNearest: }{Returns the distance for each range in \code{x} to its nearest neighbor in the \code{subject}. } \item{distance: }{ Returns the distance for each range in \code{x} to the range in \code{y}. The behavior of \code{distance} has changed in Bioconductor 2.12. See the man page \code{?distance} in IRanges for details. } } } \value{ For \code{nearest}, \code{precede} and \code{follow}, an integer vector of indices in \code{subject}, or a \link[S4Vectors]{Hits} if \code{select="all"}. For \code{distanceToNearest}, a \link[S4Vectors]{Hits} object with a column for the \code{query} index (queryHits), \code{subject} index (subjectHits) and the \code{distance} between the pair. For \code{distance}, an integer vector of distances between the ranges in \code{x} and \code{y}. } \author{P. Aboyoun and V. Obenchain } \seealso{ \itemize{ \item The \link{GenomicRanges} and \link{GRanges} classes. \item The \link[IRanges]{Ranges} class in the \pkg{IRanges} package. \item The \link[S4Vectors]{Hits} class in the \pkg{S4Vectors} package. \item The \link[IRanges]{nearest-methods} man page in the \pkg{IRanges} package. \item \link[GenomicRanges]{findOverlaps-methods} for finding just the overlapping ranges. \item The \link[GenomicFeatures]{nearest-methods} man page in the \pkg{GenomicFeatures} package. } } \examples{ ## ----------------------------------------------------------- ## precede() and follow() ## ----------------------------------------------------------- query <- GRanges("A", IRanges(c(5, 20), width=1), strand="+") subject <- GRanges("A", IRanges(rep(c(10, 15), 2), width=1), strand=c("+", "+", "-", "-")) precede(query, subject) follow(query, subject) strand(query) <- "-" precede(query, subject) follow(query, subject) ## ties choose first in order query <- GRanges("A", IRanges(10, width=1), c("+", "-", "*")) subject <- GRanges("A", IRanges(c(5, 5, 5, 15, 15, 15), width=1), rep(c("+", "-", "*"), 2)) precede(query, subject) precede(query, rev(subject)) ## ignore.strand=TRUE treats all ranges as '+' precede(query[1], subject[4:6], select="all", ignore.strand=FALSE) precede(query[1], subject[4:6], select="all", ignore.strand=TRUE) ## ----------------------------------------------------------- ## nearest() ## ----------------------------------------------------------- ## When multiple ranges overlap an "arbitrary" range is chosen query <- GRanges("A", IRanges(5, 15)) subject <- GRanges("A", IRanges(c(1, 15), c(5, 19))) nearest(query, subject) ## select="all" returns all hits nearest(query, subject, select="all") ## Ranges in 'x' will self-select when 'subject' is present query <- GRanges("A", IRanges(c(1, 10), width=5)) nearest(query, query) ## Ranges in 'x' will not self-select when 'subject' is missing nearest(query) ## ----------------------------------------------------------- ## distance(), distanceToNearest() ## ----------------------------------------------------------- ## Adjacent, overlap, separated by 1 query <- GRanges("A", IRanges(c(1, 2, 10), c(5, 8, 11))) subject <- GRanges("A", IRanges(c(6, 5, 13), c(10, 10, 15))) distance(query, subject) ## recycling distance(query[1], subject) ## zero-width ranges zw <- GRanges("A", IRanges(4,3)) stopifnot(distance(zw, GRanges("A", IRanges(3,4))) == 0L) sapply(-3:3, function(i) distance(shift(zw, i), GRanges("A", IRanges(4,3)))) query <- GRanges(c("A", "B"), IRanges(c(1, 5), width=1)) distanceToNearest(query, subject) ## distance() with GRanges and TxDb see the ## ?'distance,GenomicRanges,TxDb-method' man ## page in the GenomicFeatures package. } \keyword{utilities} GenomicRanges/man/phicoef.Rd0000644000175400017540000000205613175713746017021 0ustar00biocbuildbiocbuild\name{phicoef} \alias{phicoef} \title{Calculate the "phi coefficient" between two binary variables} \description{ The \code{phicoef} function calculates the "phi coefficient" between two binary variables. } \usage{ phicoef(x, y=NULL) } \arguments{ \item{x, y}{ Two logical vectors of the same length. If \code{y} is not supplied, \code{x} must be a 2x2 integer matrix (or an integer vector of length 4) representing the contingency table of two binary variables. } } \value{ The "phi coefficient" between the two binary variables. This is a single numeric value ranging from -1 to +1. } \references{ \url{http://en.wikipedia.org/wiki/Phi_coefficient} } \author{ H. Pagès } \examples{ set.seed(33) x <- sample(c(TRUE, FALSE), 100, replace=TRUE) y <- sample(c(TRUE, FALSE), 100, replace=TRUE) phicoef(x, y) phicoef(rep(x, 10), c(rep(x, 9), y)) stopifnot(phicoef(table(x, y)) == phicoef(x, y)) stopifnot(phicoef(y, x) == phicoef(x, y)) stopifnot(phicoef(x, !y) == - phicoef(x, y)) stopifnot(phicoef(x, x) == 1) } \keyword{manip} GenomicRanges/man/setops-methods.Rd0000644000175400017540000002104613175713746020362 0ustar00biocbuildbiocbuild\name{setops-methods} \alias{setops-methods} \alias{union} \alias{union,GenomicRanges,GenomicRanges-method} \alias{union,GRangesList,GRangesList-method} \alias{union,GenomicRanges,Vector-method} \alias{union,Vector,GenomicRanges-method} \alias{intersect} \alias{intersect,GenomicRanges,GenomicRanges-method} \alias{intersect,GRangesList,GRangesList-method} \alias{intersect,GenomicRanges,Vector-method} \alias{intersect,Vector,GenomicRanges-method} \alias{setdiff} \alias{setdiff,GenomicRanges,GenomicRanges-method} \alias{setdiff,GRangesList,GRangesList-method} \alias{setdiff,GenomicRanges,Vector-method} \alias{setdiff,Vector,GenomicRanges-method} \alias{punion} \alias{punion,GRanges,GRanges-method} \alias{punion,GRanges,GRangesList-method} \alias{punion,GRangesList,GRanges-method} \alias{pintersect} \alias{pintersect,GRanges,GRanges-method} \alias{pintersect,GRanges,GRangesList-method} \alias{pintersect,GRangesList,GRanges-method} \alias{psetdiff} \alias{psetdiff,GRanges,GRanges-method} \alias{psetdiff,GRanges,GRangesList-method} \alias{pgap} \alias{pgap,GRanges,GRanges-method} \title{Set operations on genomic ranges} \description{ Performs set operations on \link{GRanges} and \link{GRangesList} objects. NOTE: The \code{\link[IRanges]{punion}}, \code{\link[IRanges]{pintersect}}, \code{\link[IRanges]{psetdiff}}, and \code{\link[IRanges]{pgap}} generic functions and methods for \link[IRanges]{Ranges} objects are defined and documented in the \pkg{IRanges} package. } \usage{ ## Vector-wise set operations ## -------------------------- \S4method{union}{GenomicRanges,GenomicRanges}(x, y, ignore.strand=FALSE) \S4method{intersect}{GenomicRanges,GenomicRanges}(x, y, ignore.strand=FALSE) \S4method{setdiff}{GenomicRanges,GenomicRanges}(x, y, ignore.strand=FALSE) ## Element-wise (aka "parallel") set operations ## -------------------------------------------- \S4method{punion}{GRanges,GRanges}(x, y, fill.gap=FALSE, ignore.strand=FALSE) \S4method{pintersect}{GRanges,GRanges}(x, y, drop.nohit.ranges=FALSE, ignore.strand=FALSE, strict.strand=FALSE) \S4method{psetdiff}{GRanges,GRanges}(x, y, ignore.strand=FALSE) } \arguments{ \item{x, y}{ For \code{union}, \code{intersect}, and \code{setdiff}: 2 \link{GenomicRanges} objects or 2 \link{GRangesList} objects. For \code{punion} and \code{pintersect}: 2 \link{GRanges} objects, or 1 \link{GRanges} object and 1 \link{GRangesList} object. For \code{psetdiff}: \code{x} must be a \link{GRanges} object and \code{y} can be a \link{GRanges} or \link{GRangesList} object. For \code{pgap}: 2 \link{GRanges} objects. In addition, for the \emph{parallel} operations, \code{x} and \code{y} must be of equal length (i.e. \code{length(x) == length(y)}). } \item{fill.gap}{ Logical indicating whether or not to force a union by using the rule \code{start = min(start(x), start(y)), end = max(end(x), end(y))}. } \item{ignore.strand}{ For set operations: If set to TRUE, then the strand of \code{x} and \code{y} is set to \code{"*"} prior to any computation. For parallel set operations: If set to TRUE, the strand information is ignored in the computation and the result has the strand information of \code{x}. } \item{drop.nohit.ranges}{ If TRUE then elements in \code{x} that don't intersect with their corresponding element in \code{y} are removed from the result (so the returned object is no more parallel to the input). If FALSE (the default) then nothing is removed and a \code{hit} metadata column is added to the returned object to indicate elements in \code{x} that intersect with the corresponding element in \code{y}. For those that don't, the reported intersection is a zero-width range that has the same start as \code{x}. } \item{strict.strand}{ If set to FALSE (the default), features on the \code{"*"} strand are treated as occurring on both the \code{"+"} and \code{"-"} strand. If set to TRUE, the strand of intersecting elements must be strictly the same. } } \details{ The \code{pintersect} methods involving \link{GRanges} and/or \link{GRangesList} objects use the triplet (sequence name, range, strand) to determine the element by element intersection of features, where a strand value of \code{"*"} is treated as occurring on both the \code{"+"} and \code{"-"} strand (unless \code{strict.strand} is set to TRUE, in which case the strand of intersecting elements must be strictly the same). The \code{psetdiff} methods involving \link{GRanges} and/or \link{GRangesList} objects use the triplet (sequence name, range, strand) to determine the element by element set difference of features, where a strand value of \code{"*"} is treated as occurring on both the \code{"+"} and \code{"-"} strand. } \value{ For \code{union}, \code{intersect}, and \code{setdiff}: a \link{GRanges} object if \code{x} and \code{y} are \link{GenomicRanges} objects, and a \link{GRangesList} object if they are \link{GRangesList} objects. For \code{punion} and \code{pintersect}: when \code{x} or \code{y} is not a \link{GRanges} object, an object of the same class as this non-\link{GRanges} object. Otherwise, a \link{GRanges} object. For \code{psetdiff}: either a \link{GRanges} object when both \code{x} and \code{y} are \link{GRanges} objects, or a \link{GRangesList} object when \code{y} is a \link{GRangesList} object. For \code{pgap}: a \link{GRanges} object. } \author{P. Aboyoun and H. Pagès} \seealso{ \itemize{ \item \link[IRanges]{setops-methods} in the \pkg{IRanges} package for set operations on \link[IRanges]{Ranges} and \link[IRanges]{RangesList} objects. \item \link[GenomicRanges]{findOverlaps-methods} for finding/counting overlapping genomic ranges. \item \link[GenomicRanges]{intra-range-methods} and \link[GenomicRanges]{inter-range-methods} for \emph{intra range} and \emph{inter range} transformations of a \link{GRanges} object. \item \link{GRanges} and \link{GRangesList} objects. \item \code{\link[S4Vectors]{mendoapply}} in the \pkg{S4Vectors} package. } } \examples{ ## --------------------------------------------------------------------- ## A. SET OPERATIONS ## --------------------------------------------------------------------- x <- GRanges("chr1", IRanges(c(2, 9) , c(7, 19)), strand=c("+", "-")) y <- GRanges("chr1", IRanges(5, 10), strand="-") union(x, y) union(x, y, ignore.strand=TRUE) intersect(x, y) intersect(x, y, ignore.strand=TRUE) setdiff(x, y) setdiff(x, y, ignore.strand=TRUE) ## With 2 GRangesList objects: gr1 <- GRanges(seqnames="chr2", ranges=IRanges(3, 6)) gr2 <- GRanges(seqnames=c("chr1", "chr1"), ranges=IRanges(c(7,13), width = 3), strand=c("+", "-")) gr3 <- GRanges(seqnames=c("chr1", "chr2"), ranges=IRanges(c(1, 4), c(3, 9)), strand=c("-", "-")) grlist <- GRangesList(gr1=gr1, gr2=gr2, gr3=gr3) union(grlist, shift(grlist, 3)) intersect(grlist, shift(grlist, 3)) setdiff(grlist, shift(grlist, 3)) ## Sanity checks: grlist2 <- shift(grlist, 3) stopifnot(identical( union(grlist, grlist2), mendoapply(union, grlist, grlist2) )) stopifnot(identical( intersect(grlist, grlist2), mendoapply(intersect, grlist, grlist2) )) stopifnot(identical( setdiff(grlist, grlist2), mendoapply(setdiff, grlist, grlist2) )) ## --------------------------------------------------------------------- ## B. PARALLEL SET OPERATIONS ## --------------------------------------------------------------------- punion(x, shift(x, 6)) \dontrun{ punion(x, shift(x, 7)) # will fail } punion(x, shift(x, 7), fill.gap=TRUE) pintersect(x, shift(x, 6)) pintersect(x, shift(x, 7)) psetdiff(x, shift(x, 7)) ## --------------------------------------------------------------------- ## C. MORE EXAMPLES ## --------------------------------------------------------------------- ## GRanges object: gr <- GRanges(seqnames=c("chr2", "chr1", "chr1"), ranges=IRanges(1:3, width = 12), strand=Rle(strand(c("-", "*", "-")))) ## Parallel intersection of a GRanges and a GRangesList object pintersect(gr, grlist) pintersect(grlist, gr) ## For a fast 'mendoapply(intersect, grlist, as(gr, "GRangesList"))' ## call pintersect() with 'strict.strand=TRUE' and call reduce() on ## the result with 'drop.empty.ranges=TRUE': reduce(pintersect(grlist, gr, strict.strand=TRUE), drop.empty.ranges=TRUE) ## Parallel set difference of a GRanges and a GRangesList object psetdiff(gr, grlist) } \keyword{methods} \keyword{utilities} GenomicRanges/man/strand-utils.Rd0000644000175400017540000001217713175713746020042 0ustar00biocbuildbiocbuild\name{strand-utils} \alias{strand-utils} \alias{strand,missing-method} \alias{strand,NULL-method} \alias{strand,character-method} \alias{strand,factor-method} \alias{strand,integer-method} \alias{strand,logical-method} \alias{strand,Rle-method} \alias{strand,RleList-method} \alias{strand,DataTable-method} \alias{strand<-,DataTable,ANY-method} \alias{invertStrand,NULL-method} \alias{invertStrand,character-method} \alias{invertStrand,factor-method} \alias{invertStrand,integer-method} \alias{invertStrand,logical-method} \alias{invertStrand,Rle-method} \alias{invertStrand,RleList-method} \title{Strand utilities} \description{ A bunch of useful \code{strand} and \code{invertStrand} methods. } \usage{ \S4method{strand}{missing}(x) \S4method{strand}{character}(x) \S4method{strand}{factor}(x) \S4method{strand}{integer}(x) \S4method{strand}{logical}(x) \S4method{strand}{Rle}(x) \S4method{strand}{RleList}(x) \S4method{strand}{DataTable}(x) \S4method{strand}{DataTable,ANY}(x) <- value \S4method{invertStrand}{character}(x) \S4method{invertStrand}{factor}(x) \S4method{invertStrand}{integer}(x) \S4method{invertStrand}{logical}(x) \S4method{invertStrand}{Rle}(x) \S4method{invertStrand}{RleList}(x) } \arguments{ \item{x}{ The object from which to obtain a \emph{strand factor}, \emph{strand factor \link[S4Vectors]{Rle}}, or \emph{strand factor \link{RleList}} object. Can be missing. See Details and Value sections below for more information. } \item{value}{ Replacement value for the strand. } } \details{ All the \code{strand} and \code{invertStrand} methods documented here return either a \emph{strand factor}, \emph{strand factor \link[S4Vectors]{Rle}}, or \emph{strand factor \link{RleList}} object. These are factor, factor-\link[S4Vectors]{Rle}, or factor-\link{RleList} objects containing the "standard strand levels" (i.e. \code{+}, \code{-}, and \code{*}) and no NAs. } \value{ All the \code{strand} and \code{invertStrand} methods documented here return an object that is \emph{parallel} to input object \code{x} when \code{x} is a character, factor, integer, logical, \link[S4Vectors]{Rle}, or \link{RleList} object. For the \code{strand} methods: \itemize{ \item If \code{x} is missing, returns an empty factor with the "standard strand levels" i.e. \code{+}, \code{-}, and \code{*}. \item If \code{x} is a character vector or factor, it is coerced to a factor with the levels listed above. \code{NA} values in \code{x} are not accepted. \item If \code{x} is an integer vector, it is coerced to a factor with the levels listed above. \code{1}, \code{-1}, and \code{NA} values in \code{x} are mapped to the \code{+}, \code{-}, and \code{*} levels respectively. \item If \code{x} is a logical vector, it is coerced to a factor with the levels listed above. \code{FALSE}, \code{TRUE}, and \code{NA} values in \code{x} are mapped to the \code{+}, \code{-}, and \code{*} levels respectively. \item If \code{x} is a character-, factor-, integer-, or logical-\link[S4Vectors]{Rle}, it is transformed with \code{runValue(x) <- strand(runValue(x))} and returned. \item If \code{x} is an \link{RleList} object, each list element in \code{x} is transformed by calling \code{strand()} on it and the resulting \link{RleList} object is returned. More precisely the returned object is \code{endoapply(x, strand)}. Note that in addition to being \emph{parallel} to \code{x}, this object also has the same \emph{shape} as \code{x} (i.e. its list elements have the same lengths as in \code{x}). \item If \code{x} inherits from \code{DataTable}, the \code{"strand"} column is passed thru \code{strand()} and returned. If \code{x} has no \code{"strand"} column, this return value is populated with \code{*}s. } Each \code{invertStrand} method returns the same object as its corresponding \code{strand} method but with \code{"+"} and \code{"-"} switched. } \author{M. Lawrence and H. Pagès} \seealso{ \code{\link[BiocGenerics]{strand}} } \examples{ strand() x1 <- c("-", "*", "*", "+", "-", "*") x2 <- factor(c("-", "-", "+", "-")) x3 <- c(-1L, NA, NA, 1L, -1L, NA) x4 <- c(TRUE, NA, NA, FALSE, TRUE, NA) strand(x1) invertStrand(x1) strand(x2) invertStrand(x2) strand(x3) invertStrand(x3) strand(x4) invertStrand(x4) strand(Rle(x1)) invertStrand(Rle(x1)) strand(Rle(x2)) invertStrand(Rle(x2)) strand(Rle(x3)) invertStrand(Rle(x3)) strand(Rle(x4)) invertStrand(Rle(x4)) x5 <- RleList(x1, character(0), as.character(x2)) strand(x5) invertStrand(x5) strand(DataFrame(score=2:-3)) strand(DataFrame(score=2:-3, strand=x3)) strand(DataFrame(score=2:-3, strand=Rle(x3))) ## Sanity checks: target <- strand(x1) stopifnot(identical(target, strand(x3))) stopifnot(identical(target, strand(x4))) stopifnot(identical(Rle(strand(x1)), strand(Rle(x1)))) stopifnot(identical(Rle(strand(x2)), strand(Rle(x2)))) stopifnot(identical(Rle(strand(x3)), strand(Rle(x3)))) stopifnot(identical(Rle(strand(x4)), strand(Rle(x4)))) } \keyword{methods} GenomicRanges/man/tile-methods.Rd0000644000175400017540000000524713175713746020007 0ustar00biocbuildbiocbuild\name{tile-methods} \alias{tile-methods} \alias{tile} \alias{tile,GenomicRanges-method} \alias{slidingWindows} \alias{slidingWindows,GenomicRanges-method} \title{Generate windows for a GenomicRanges} \description{ \code{\link[IRanges]{tile}} and \code{\link[IRanges]{slidingWindows}} methods for \link{GenomicRanges}. \code{tile} partitions each range into a set of tiles, which are defined in terms of their number or width. \code{slidingWindows} generates sliding windows of a specified width and frequency. } \usage{ \S4method{tile}{GenomicRanges}(x, n, width) \S4method{slidingWindows}{GenomicRanges}(x, width, step=1L) } \arguments{ \item{x}{ A \link{GenomicRanges} object, like a \code{GRanges}. } \item{n}{ The number of tiles to generate. See \code{?\link[IRanges]{tile}} in the \pkg{IRanges} package for more information about this argument. } \item{width}{ The (maximum) width of each tile. See \code{?\link[IRanges]{tile}} in the \pkg{IRanges} package for more information about this argument. } \item{step}{ The distance between the start positions of the sliding windows. } } \details{ The \code{tile} function splits \code{x} into a \code{GRangesList}, each element of which corresponds to a tile, or partition, of \code{x}. Specify the tile geometry with either \code{n} or \code{width} (not both). Passing \code{n} creates \code{n} tiles of approximately equal width, truncated by sequence end, while passing \code{width} tiles the region with ranges of the given width, again truncated by sequence end. The \code{slidingWindows} function generates sliding windows within each range of \code{x}, according to \code{width} and \code{step}, returning a \code{GRangesList}. If the sliding windows do not exactly cover a range in \code{x}, the last window is partial. } \value{ A \code{GRangesList} object, each element of which corresponds to a window. } \author{M. Lawrence} \seealso{ \code{\link[IRanges]{tile}} in the \pkg{IRanges} package. } \examples{ gr <- GRanges( seqnames=Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges=IRanges(1:10, end=11), strand=Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), seqlengths=c(chr1=11, chr2=12, chr3=13)) # split every range in half tiles <- tile(gr, n = 2L) stopifnot(all(elementNROWS(tiles) == 2L)) # split ranges into subranges of width 2 # odd width ranges must contain one subrange of width 1 tiles <- tile(gr, width = 2L) stopifnot(all(all(width(tiles) \%in\% c(1L, 2L)))) windows <- slidingWindows(gr, width=3L, step=2L) width(windows[[1L]]) # last range is truncated } \keyword{methods} \keyword{utilities} GenomicRanges/man/tileGenome.Rd0000644000175400017540000001111213175713746017465 0ustar00biocbuildbiocbuild\name{tileGenome} \alias{tileGenome} \title{Put (virtual) tiles on a given genome} \description{ \code{tileGenome} returns a set of genomic regions that form a partitioning of the specified genome. Each region is called a "tile". } \usage{ tileGenome(seqlengths, ntile, tilewidth, cut.last.tile.in.chrom=FALSE) } \arguments{ \item{seqlengths}{ Either a named numeric vector of chromosome lengths or a \link{Seqinfo} object. More precisely, if a named numeric vector, it must have a length >= 1, cannot contain NAs or negative values, and cannot have duplicated names. If a \link{Seqinfo} object, then it's first replaced with the vector of sequence lengths stored in the object (extracted from the object with the \code{\link{seqlengths}} getter), then the restrictions described previously apply to this vector. } \item{ntile}{ The number of tiles to generate. } \item{tilewidth}{ The desired tile width. The effective tile width might be slightly different but is guaranteed to never be more than the desired width. } \item{cut.last.tile.in.chrom}{ Whether or not to cut the last tile in each chromosome. This is set to \code{FALSE} by default. Can be set to \code{TRUE} only when \code{tilewidth} is specified. In that case, a tile will never overlap with more than 1 chromosome and a \link{GRanges} object is returned with one element (i.e. one genomic range) per tile. } } \value{ If \code{cut.last.tile.in.chrom} is \code{FALSE} (the default), a \link{GRangesList} object with one list element per tile, each of them containing a number of genomic ranges equal to the number of chromosomes it overlaps with. Note that when the tiles are small (i.e. much smaller than the chromosomes), most of them only overlap with a single chromosome. If \code{cut.last.tile.in.chrom} is \code{TRUE}, a \link{GRanges} object with one element (i.e. one genomic range) per tile. } \author{ H. Pagès, based on a proposal by M. Morgan } \seealso{ \itemize{ \item \link{genomicvars} for an example of how to compute the binned average of a numerical variable defined along a genome. \item \link{GRangesList} and \link{GRanges} objects. \item \link{Seqinfo} objects and the \code{\link{seqlengths}} getter. \item \link[IRanges]{IntegerList} objects. \item \link[IRanges]{Views} objects. } } \examples{ ## --------------------------------------------------------------------- ## A. WITH A TOY GENOME ## --------------------------------------------------------------------- seqlengths <- c(chr1=60, chr2=20, chr3=25) ## Create 5 tiles: tiles <- tileGenome(seqlengths, ntile=5) tiles elementNROWS(tiles) # tiles 3 and 4 contain 2 ranges width(tiles) ## Use sum() on this IntegerList object to get the effective tile ## widths: sum(width(tiles)) # each tile covers exactly 21 genomic positions ## Create 9 tiles: tiles <- tileGenome(seqlengths, ntile=9) elementNROWS(tiles) # tiles 6 and 7 contain 2 ranges table(sum(width(tiles))) # some tiles cover 12 genomic positions, # others 11 ## Specify the tile width: tiles <- tileGenome(seqlengths, tilewidth=20) length(tiles) # 6 tiles table(sum(width(tiles))) # effective tile width is <= specified ## Specify the tile width and cut the last tile in each chromosome: tiles <- tileGenome(seqlengths, tilewidth=24, cut.last.tile.in.chrom=TRUE) tiles width(tiles) # each tile covers exactly 24 genomic positions, except # the last tile in each chromosome ## Partition a genome by chromosome ("natural partitioning"): tiles <- tileGenome(seqlengths, tilewidth=max(seqlengths), cut.last.tile.in.chrom=TRUE) tiles # one tile per chromosome ## sanity check stopifnot(all.equal(setNames(end(tiles), seqnames(tiles)), seqlengths)) ## --------------------------------------------------------------------- ## B. WITH A REAL GENOME ## --------------------------------------------------------------------- library(BSgenome.Scerevisiae.UCSC.sacCer2) tiles <- tileGenome(seqinfo(Scerevisiae), ntile=20) tiles tiles <- tileGenome(seqinfo(Scerevisiae), tilewidth=50000, cut.last.tile.in.chrom=TRUE) tiles ## --------------------------------------------------------------------- ## C. AN APPLICATION: COMPUTE THE BINNED AVERAGE OF A NUMERICAL VARIABLE ## DEFINED ALONG A GENOME ## --------------------------------------------------------------------- ## See '?genomicvars' for an example of how to compute the binned ## average of a numerical variable defined along a genome. } \keyword{manip} GenomicRanges/src/0000755000175400017540000000000013175727644015130 5ustar00biocbuildbiocbuildGenomicRanges/src/GenomicRanges.h0000644000175400017540000000040713175727645020024 0ustar00biocbuildbiocbuild#include /* transcript_utils.c */ SEXP transcript_widths( SEXP exonStarts, SEXP exonEnds ); SEXP tlocs2rlocs( SEXP tlocs, SEXP exonStarts, SEXP exonEnds, SEXP strand, SEXP decreasing_rank_on_minus_strand, SEXP error_if_out_of_bounds ); GenomicRanges/src/IRanges_stubs.c0000644000175400017540000000003413175727645020042 0ustar00biocbuildbiocbuild#include "_IRanges_stubs.c" GenomicRanges/src/R_init_GenomicRanges.c0000644000175400017540000000062613175727645021326 0ustar00biocbuildbiocbuild#include "GenomicRanges.h" #include #define CALLMETHOD_DEF(fun, numArgs) {#fun, (DL_FUNC) &fun, numArgs} static const R_CallMethodDef callMethods[] = { /* transcript_utils.c */ CALLMETHOD_DEF(transcript_widths, 2), CALLMETHOD_DEF(tlocs2rlocs, 6), {NULL, NULL, 0} }; void R_init_GenomicRanges(DllInfo *info) { R_registerRoutines(info, NULL, callMethods, NULL, NULL); return; } GenomicRanges/src/S4Vectors_stubs.c0000644000175400017540000000003613175727645020350 0ustar00biocbuildbiocbuild#include "_S4Vectors_stubs.c" GenomicRanges/src/transcript_utils.c0000644000175400017540000001320313175727645020705 0ustar00biocbuildbiocbuild#include "GenomicRanges.h" #include "IRanges_interface.h" #include "S4Vectors_interface.h" static char errmsg_buf[200]; static int get_nexons(SEXP starts, SEXP ends) { int nstarts, nends; if (starts == R_NilValue) { nstarts = 0; } else if (IS_INTEGER(starts)) { nstarts = LENGTH(starts); } else { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonStarts' has invalid elements"); return -1; } if (ends == R_NilValue) { nends = 0; } else if (IS_INTEGER(ends)) { nends = LENGTH(ends); } else { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonEnds' has invalid elements"); return -1; } if (nstarts != nends) { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonStarts' and 'exonEnds' have different shapes"); return -1; } return nstarts; } static int get_transcript_width(SEXP starts, SEXP ends, int ref_length) { int nexons, transcript_width, j, start, end, width; if ((nexons = get_nexons(starts, ends)) == -1) return -1; transcript_width = 0; for (j = 0; j < nexons; j++) { start = INTEGER(starts)[j]; end = INTEGER(ends)[j]; if (start == NA_INTEGER || end == NA_INTEGER) { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonStarts' and/or 'exonEnds' contain NAs'"); return -1; } if (ref_length != -1) { if (start < 1 || start > ref_length + 1) { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonStarts' contains \"out of limits\" " "values"); return -1; } if (end < 0 || end > ref_length) { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonEnds' contains \"out of limits\" " "values"); return -1; } } width = end - start + 1; if (width < 0) { snprintf(errmsg_buf, sizeof(errmsg_buf), "'exonStarts/exonEnds' define exons " "of negative length"); return -1; } transcript_width += width; } return transcript_width; } static SEXP mk_transcript_widths(SEXP exonStarts, SEXP exonEnds, int ref_length) { int ntranscripts, i, transcript_width; SEXP ans, starts, ends; ntranscripts = LENGTH(exonStarts); PROTECT(ans = NEW_INTEGER(ntranscripts)); for (i = 0; i < ntranscripts; i++) { starts = VECTOR_ELT(exonStarts, i); ends = VECTOR_ELT(exonEnds, i); transcript_width = get_transcript_width(starts, ends, ref_length); if (transcript_width == -1) { UNPROTECT(1); error("%s", errmsg_buf); } INTEGER(ans)[i] = transcript_width; } UNPROTECT(1); return ans; } static int strand_is_minus(SEXP strand, int i) { SEXP strand_elt; strand_elt = STRING_ELT(strand, i); if (strand_elt != NA_STRING && LENGTH(strand_elt) == 1) { switch (CHAR(strand_elt)[0]) { case '+': return 0; case '-': return 1; } } snprintf(errmsg_buf, sizeof(errmsg_buf), "'strand' elements must be \"+\" or \"-\""); return -1; } static int tloc2rloc(int tloc, SEXP starts, SEXP ends, int on_minus_strand, int decreasing_rank_on_minus_strand) { int nexons, j, start, end, width; nexons = LENGTH(starts); if (on_minus_strand && decreasing_rank_on_minus_strand) { for (j = nexons - 1; j >= 0; j--) { start = INTEGER(starts)[j]; end = INTEGER(ends)[j]; width = end - start + 1; if (tloc <= width) break; tloc -= width; } } else { for (j = 0; j < nexons; j++) { start = INTEGER(starts)[j]; end = INTEGER(ends)[j]; width = end - start + 1; if (tloc <= width) break; tloc -= width; } } tloc--; return on_minus_strand ? end - tloc : start + tloc; } /**************************************************************************** * --- .Call ENTRY POINTS --- * ****************************************************************************/ SEXP transcript_widths(SEXP exonStarts, SEXP exonEnds) { return mk_transcript_widths(exonStarts, exonEnds, -1); } SEXP tlocs2rlocs(SEXP tlocs, SEXP exonStarts, SEXP exonEnds, SEXP strand, SEXP decreasing_rank_on_minus_strand, SEXP error_if_out_of_bounds) { SEXP ans, starts, ends, ans_elt; int decreasing_rank_on_minus_strand0, oob_error, ans_length, i, transcript_width, on_minus_strand, nlocs, j, tloc; decreasing_rank_on_minus_strand0 = LOGICAL(decreasing_rank_on_minus_strand)[0]; oob_error = LOGICAL(error_if_out_of_bounds)[0]; ans_length = LENGTH(tlocs); PROTECT(ans = duplicate(tlocs)); for (i = 0; i < ans_length; i++) { starts = VECTOR_ELT(exonStarts, i); ends = VECTOR_ELT(exonEnds, i); transcript_width = get_transcript_width(starts, ends, -1); if (transcript_width == -1) { UNPROTECT(1); error("%s", errmsg_buf); } on_minus_strand = strand_is_minus(strand, i); if (on_minus_strand == -1) { UNPROTECT(1); error("%s", errmsg_buf); } ans_elt = VECTOR_ELT(ans, i); if (ans_elt == R_NilValue) { nlocs = 0; } else if (IS_INTEGER(ans_elt)) { nlocs = LENGTH(ans_elt); } else { UNPROTECT(1); error("'tlocs' has invalid elements"); } for (j = 0; j < nlocs; j++) { tloc = INTEGER(ans_elt)[j]; if (tloc == NA_INTEGER) continue; if (tloc < 1 || tloc > transcript_width) { if (oob_error) { UNPROTECT(1); error("'tlocs[[%d]]' contains " "\"out of limits\" transcript " "locations (length of " "transcript is %d)", j + 1, transcript_width); } else { INTEGER(ans_elt)[j] = NA_INTEGER; break; } } INTEGER(ans_elt)[j] = tloc2rloc(tloc, starts, ends, on_minus_strand, decreasing_rank_on_minus_strand0); } } UNPROTECT(1); return ans; } GenomicRanges/tests/0000755000175400017540000000000013175713746015501 5ustar00biocbuildbiocbuildGenomicRanges/tests/run_unitTests.R0000644000175400017540000000014113175713746020506 0ustar00biocbuildbiocbuildrequire("GenomicRanges") || stop("unable to load GenomicRanges package") GenomicRanges:::.test() GenomicRanges/vignettes/0000755000175400017540000000000013175727644016351 5ustar00biocbuildbiocbuildGenomicRanges/vignettes/ExtendingGenomicRanges.Rnw0000644000175400017540000001114213175713746023425 0ustar00biocbuildbiocbuild% \VignetteIndexEntry{5. Extending GenomicRanges} % \VignetteDepends{GenomicRanges, VariantAnnotation} % \VignetteKeywords{ranges} % \VignettePackage{GenomicRanges} \documentclass{article} \usepackage[authoryear,round]{natbib} <>= BiocStyle::latex(use.unsrturl=FALSE) @ \title{Extending \Biocpkg{GenomicRanges}} \author{Michael Lawrence, Bioconductor Team} \date{Edited: Oct 2014; Compiled: \today} \begin{document} \maketitle \tableofcontents <>= options(width=72) options(showHeadLines=3) options(showTailLines=3) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} The goal of \Biocpkg{GenomicRanges} is to provide general containers for genomic data. The central class, at least from the user perspective, is \Rclass{GRanges}, which formalizes the notion of ranges, while allowing for arbitrary ``metadata columns'' to be attached to it. These columns offer the same flexibility as the venerable \Rclass{data.frame} and permit users to adapt \Rclass{GRanges} to a wide variety of \textit{adhoc} use-cases. The more we encounter a particular problem, the better we understand it. We eventually develop a systematic approach for solving the most frequently encountered problems, and every systematic approach deserves a systematic implementation. For example, we might want to formally store genetic variants, with information on alleles and read depths. The metadata columns, which were so useful during prototyping, are inappropriate for extending the formal semantics of our data structure: for the sake of data integrity, we need to ensure that the columns are always present and that they meet certain constraints. We might also find that our prototype does not scale well to the increased data volume that often occurs when we advance past the prototype stage. \Rclass{GRanges} is meant mostly for prototyping and stores its data in memory as simple R data structures. We may require something more specialized when the data are large; for example, we might store the data as a Tabix-indexed file, or in a database. The \Biocpkg{GenomicRanges} package does not directly solve either of these problems, because there are no general solutions. However, it is adaptible to specialized use cases. \section{The \Rclass{GenomicRanges} abstraction} Unbeknownst to many, most of the \Rclass{GRanges} implementation is provided by methods on the \Rclass{GenomicRanges} class, the virtual parent class of \Rclass{GRanges}. \Rclass{GenomicRanges} methods provide everything except for the actual data storage and retrieval, which \Rclass{GRanges} implements directly using slots. For example, the ranges are retrieved like this: <>= library(GenomicRanges) selectMethod(ranges, "GRanges") @ An alternative implementation is \Rclass{DelegatingGenomicRanges}, which stores all of its data in a delegate \Rclass{GenomicRanges} object: <>= selectMethod(ranges, "DelegatingGenomicRanges") @ This abstraction enables us to pursue more efficient implementations for particular tasks. One example is \Rclass{GNCList}, which is indexed for fast range queries, we expose here: <>= getSlots("GNCList")["granges"] @ The \Biocpkg{MutableRanges} package in svn provides other, untested examples. \section{Formalizing \texttt{mcols}: Extra column slots} An orthogonal problem to data storage is adding semantics by the formalization of metadata columns, and we solve it using the ``extra column slot'' mechanism. Whenever \Rclass{GenomicRanges} needs to operate on its metadata columns, it also delegates to the internal \Rfunction{extraColumnSlotNames} generic, methods of which should return a character vector, naming the slots in the \Rclass{GenomicRanges} subclass that correspond to columns (i.e., they have one value per range). It extracts the slot values and manipulates them as it would a metadata column -- except they are now formal slots, with formal types. An example is the \Rclass{VRanges} class in \Biocpkg{VariantAnnotation}. It stores information on the variants by adding these column slots: <>= GenomicRanges:::extraColumnSlotNames(VariantAnnotation:::VRanges()) @ Mostly for historical reasons, \Rclass{VRanges} extends \Rclass{GRanges}. However, since the data storage mechanism and the set of extra column slots are orthogonal, it is probably best practice to take a composition approach by extending \Rclass{DelegatingGenomicRanges}. \end{document} GenomicRanges/vignettes/GRanges_and_GRangesList_slides.Rnw0000644000175400017540000006607613175713746025033 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{3. A quick introduction to GRanges and GRangesList objects (slides)} %\VignetteDepends{IRanges, GenomicRanges, pasillaBamSubset, GenomicAlignments, TxDb.Dmelanogaster.UCSC.dm3.ensGene} \SweaveOpts{keep.source=TRUE, eps=FALSE, width=9, height=3} \documentclass[8pt]{beamer} \usepackage{slides} \renewcommand\Rclass[1]{{\texttt{#1}\index{#1 (class)}}} % A Beamer Quickstart: % http://www.math.umbc.edu/~rouben/beamer/ \newcommand\DefaultBackground{\setbeamertemplate{background canvas}[vertical shading][bottom=black!10,top=black!10]\setbeamertemplate{background canvas}[vertical shading][bottom=blue!40,top=blue!15]} \DefaultBackground \setbeamercolor{block body example}{bg=white} \definecolor{YESgreen}{RGB}{0, 160, 80} \newcommand\YES{\textcolor{YESgreen}{\textbf{YES}}} \newcommand\PartiallySupported{\textcolor{YESgreen}{\textbf{partially supported}}} \definecolor{NOgray}{RGB}{144, 144, 144} \newcommand\NO{\textcolor{NOgray}{\textbf{NO}}} %\AtBeginSection[] %{ % \setbeamertemplate{background canvas}[vertical shading][bottom=black!47,top=black!47] % \begin{frame}{} % \tableofcontents[currentsection,currentsubsection] % \end{frame} % \DefaultBackground %} %\AtBeginSubsection[] %{ % \setbeamertemplate{background canvas}[vertical shading][bottom=black!47,top=black!47] % \begin{frame}{} % \tableofcontents[currentsection,currentsubsection] % \end{frame} % \DefaultBackground %} \title{A quick introduction to GRanges and GRangesList objects} \author{Herv\'e Pag\`es\\ \href{mailto:hpages@fredhutch.org}{hpages@fredhutch.org}\\ \---\\ Michael Lawrence\\ \href{mailto:lawrence.michael@gene.com}{lawrence.michael@gene.com}} %\institute[FHCRC]{Fred Hutchinson Cancer Research Center\\ % Seattle, WA} \date{July 2015} \begin{document} <>= options(width=84) plotRanges <- function(x, xlim = x, main = deparse(substitute(x)), col = "black", sep = 0.5, ...) { height <- 1 if (is(xlim, "Ranges")) xlim <- c(min(start(xlim)), max(end(xlim))) bins <- disjointBins(IRanges(start(x), end(x) + 1)) plot.new() par(mai=c(0.5, 0.2, 1.2, 0.2)) plot.window(xlim, c(0, max(bins)*(height + sep))) ybottom <- bins * (sep + height) - height rect(start(x)-0.5, ybottom, end(x)+0.5, ybottom + height, col = col, ...) title(main, cex.main=2.8, font.main=1) axis(1) } @ \maketitle \frame{\tableofcontents} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRanges} objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{The \Rclass{GRanges} class is a container for...} ... storing a set of {\em genomic ranges} (a.k.a. {\em genomic regions} or {\em genomic intervals}). \begin{block}{} \begin{itemize} \item Each genomic range is described by a chromosome name, a {\em start}, an {\em end}, and a strand. \item {\em start} and {\em end} are both {\bf 1-based} positions relative to the 5' end of the plus strand of the chromosome, even when the range is on the minus strand. \item {\em start} and {\em end} are both considered to be included in the interval (except when the range is empty). \item The {\em width} of the range is the number of genomic positions included in it. So {\em width} = {\em end} - {\em start} + 1. \item {\em end} is always >= {\em start}, except for empty ranges (a.k.a. zero-width ranges) where {\em end} = {\em start} - 1. \end{itemize} Note that the {\em start} is always the leftmost position and the {\em end} the rightmost, even when the range is on the minus strand. Gotcha: A TSS is at the {\em end} of the range associated with a transcript located on the minus strand. \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{The \Rcode{GRanges()} constructor} \begin{frame}[fragile] \frametitle{The \Rcode{GRanges()} constructor} \begin{exampleblock}{} {\small <>= library(GenomicRanges) gr1 <- GRanges(seqnames=Rle(c("ch1", "chMT"), c(2, 4)), ranges=IRanges(16:21, 20), strand=rep(c("+", "-", "*"), 2)) gr1 @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{\Rclass{GRanges} accessors} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{length()}, \Rcode{seqnames()}, \Rcode{ranges()}} \begin{exampleblock}{} {\small <>= length(gr1) seqnames(gr1) ranges(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{start()}, \Rcode{end()}, \Rcode{width()}, \Rcode{strand()}} \begin{exampleblock}{} {\small <>= start(gr1) end(gr1) width(gr1) strand(gr1) strand(gr1) <- c("-", "-", "+") strand(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{names()}} \begin{exampleblock}{} {\small <>= names(gr1) <- LETTERS[1:6] gr1 names(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{mcols()}} Like with most \Bioconductor{} vector-like objects, {\em metadata columns} can be added to a \Rclass{GRanges} object: \begin{exampleblock}{} {\small <>= mcols(gr1) <- DataFrame(score=11:16, GC=seq(1, 0, length=6)) gr1 mcols(gr1) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRanges} accessors: \Rcode{seqinfo()}, \Rcode{seqlevels()}, \Rcode{seqlengths()}} \begin{exampleblock}{} <>= seqinfo(gr1) seqlevels(gr1) seqlengths(gr1) seqlengths(gr1) <- c(50000, 800) seqlengths(gr1) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Vector operations on \Rclass{GRanges} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects} \begin{block}{} What we call {\em vector operations} are operations that work on any ordinary vector: \begin{itemize} \item \Rcode{length()}, \Rcode{names()} \item Single-bracket subsetting: \Rcode{[} \item Combining: \Rcode{c()} \item \Rcode{split()}, \Rcode{relist()} \item Comparing: \Rcode{==}, \Rcode{!=}, \Rcode{match()}, \Rcode{\%in\%}, \Rcode{duplicated()}, \Rcode{unique()} \item Ordering: \Rcode{<=}, \Rcode{>=}, \Rcode{<}, \Rcode{>}, \Rcode{order()}, \Rcode{sort()}, \Rcode{rank()} \end{itemize} \Rclass{GRanges} objects support all these {\em vector operations} $==>$ They're considered {\em vector-like} objects. \end{block} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Single-bracket subsetting} \begin{exampleblock}{} {\small <>= gr1[c("F", "A")] gr1[strand(gr1) == "+"] @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Single-bracket subsetting} \begin{exampleblock}{} {\small <>= gr1 <- gr1[-5] gr1 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Combining} \begin{exampleblock}{} {\small <>= gr2 <- GRanges(seqnames="ch2", ranges=IRanges(start=c(2:1,2), width=6), score=15:13, GC=seq(0, 0.4, length=3)) gr12 <- c(gr1, gr2) gr12 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Comparing} \begin{exampleblock}{} {\small <>= gr12[length(gr12)] == gr12 duplicated(gr12) unique(gr12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRanges} objects: Ordering} \begin{exampleblock}{} {\small <>= sort(gr12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Splitting a \Rclass{GRanges} object} \begin{exampleblock}{} {\small <>= split(gr12, seqnames(gr12)) @ } \end{exampleblock} \end{frame} \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 1} \setbeamertemplate{enumerate items}{\alph{enumi}.} \begin{enumerate} \item Load the \Rpackage{GenomicRanges} package. \item Open the man page for the \Rclass{GRanges} class and run the examples in it. \item Extract from \Rclass{GRanges} object \Rcode{gr} the elements (i.e. ranges) with a score between 4 and 8. \item Split \Rcode{gr} by strand. \end{enumerate} \end{frame} \DefaultBackground %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Range-based operations on \Rclass{GRanges} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{An overview of {\em range-based} operations} \begin{columns}[t] \begin{column}{0.44\textwidth} \begin{block}{} {\bf Intra range transformations} \Rcode{shift()}, \Rcode{narrow()}, \Rcode{resize()}, \Rcode{flank()} \end{block} \begin{block}{} {\bf Inter range transformations} \Rcode{range()}, \Rcode{reduce()}, \Rcode{gaps()}, \Rcode{disjoin()} \end{block} \begin{block}{} {\bf Range-based set operations} \Rcode{union()}, \Rcode{intersect()}, \Rcode{setdiff()}, \Rcode{punion()}, \Rcode{pintersect()}, \Rcode{psetdiff()}, \Rcode{pgap()} \end{block} \end{column} \begin{column}{0.44\textwidth} \begin{block}{} {\bf Coverage and slicing} \Rcode{coverage()}, \Rcode{slice()} \end{block} \begin{block}{} {\bf Finding/counting overlapping ranges} \Rcode{findOverlaps()}, \Rcode{countOverlaps()} \end{block} \begin{block}{} {\bf Finding the nearest range neighbor} \Rcode{nearest()}, \Rcode{precede()}, \Rcode{follow()} \end{block} \begin{block}{} and more... \end{block} \end{column} \end{columns} \end{frame} \begin{frame}[fragile] \frametitle{Examples of some common {\em range-based} operations} \begin{exampleblock}{} <>= library(IRanges) ir0 <- IRanges(start=c(7, 9, 12, 14, 22:24), end=c(15, 11, 12, 18, 26, 27, 28)) png("ranges-ir0-plot.png", width=800, height=170) plotRanges(ir0, xlim=c(5, 35), main="ir0", col="blue") dev.off() @ <>= png("ranges-shift-ir0-plot.png", width=800, height=170) plotRanges(shift(ir0, 5), xlim=c(5, 35), main="shift(ir0, 5)", col="blue") dev.off() @ <>= png("ranges-reduce-ir0-plot.png", width=800, height=170) plotRanges(reduce(ir0), xlim=c(5, 35), main="reduce(ir0)", col="blue") dev.off() @ <>= png("ranges-disjoin-ir0-plot.png", width=800, height=170) plotRanges(disjoin(ir0), xlim=c(5, 35), main="disjoin(ir0)", col="blue") dev.off() @ \begin{figure} \centering \includegraphics[width=0.8\textwidth,height=!]{ranges-ir0-plot}\\ \includegraphics[width=0.8\textwidth,height=!]{ranges-shift-ir0-plot}\\ \includegraphics[width=0.8\textwidth,height=!]{ranges-reduce-ir0-plot}\\ \includegraphics[width=0.8\textwidth,height=!]{ranges-disjoin-ir0-plot} %\caption{Range-based operations} \end{figure} \end{exampleblock} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects} \begin{exampleblock}{} {\small <>= gr2 shift(gr2, 50) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr1 resize(gr1, 12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr1 flank(gr1, 3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr3 <- shift(gr1, c(35000, rep(0, 3), 100)) width(gr3)[c(3,5)] <- 117 gr3 range(gr3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\small <>= gr3 reduce(gr3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\scriptsize <>= gr3 gaps(gr3) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRanges} objects (continued)} \begin{exampleblock}{} {\scriptsize <>= gr3 disjoin(gr3) @ } \end{exampleblock} \end{frame} \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 2} \setbeamertemplate{enumerate items}{\alph{enumi}.} Using \Rclass{GRanges} object \Rcode{gr} created at Exercise 1: \begin{enumerate} \item Shift the ranges in \Rcode{gr} by 1000 positions to the right. \item What method is called when doing \Rcode{shift()} on a \Rclass{GRanges} object? Find the man page for this method. \end{enumerate} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Coverage} \begin{exampleblock}{} {\small <>= cvg12 <- coverage(gr12) cvg12 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Coverage (continued)} \begin{exampleblock}{} {\small <>= mean(cvg12) max(cvg12) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Slicing the coverage} \begin{exampleblock}{} {\small <>= sl12 <- slice(cvg12, lower=1) sl12 elementNROWS(sl12) sl12$chMT mean(sl12$chMT) max(sl12$chMT) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{findOverlaps()} \begin{block}{} Load aligned reads from a BAM file: \end{block} \begin{exampleblock}{} {\small <>= library(pasillaBamSubset) untreated1_chr4() library(GenomicAlignments) reads <- readGAlignments(untreated1_chr4()) @ } \end{exampleblock} \begin{block}{} and store them in a \Rclass{GRanges} object: \end{block} \begin{exampleblock}{} {\small <>= reads <- as(reads, "GRanges") reads[1:4] @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{findOverlaps() (continued)} \begin{block}{} Load the gene ranges from a {\em TxDb} package: \end{block} \begin{exampleblock}{} {\small <>= library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) txdb <- TxDb.Dmelanogaster.UCSC.dm3.ensGene dm3_genes <- genes(txdb) @ } \end{exampleblock} \begin{block}{} and find the overlaps between the reads and the genes: \end{block} \begin{exampleblock}{} {\small <>= hits <- findOverlaps(reads, dm3_genes) head(hits) @ } \end{exampleblock} \end{frame} \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 3} \setbeamertemplate{enumerate items}{\alph{enumi}.} \begin{enumerate} \item Recreate \Rclass{GRanges} objects \Rcode{reads} and \Rcode{dm3\_genes} from previous slides. \item What method is called when calling \Rcode{findOverlaps()} on them? Open the man page for this method. \item Find the overlaps between the 2 objects but this time the strand should be ignored. \end{enumerate} \end{frame} \DefaultBackground \setbeamertemplate{background canvas}[vertical shading][bottom=orange!40,top=orange!20] \begin{frame}[fragile] \frametitle{Exercise 4} \setbeamertemplate{enumerate items}{\alph{enumi}.} In this exercise we want to get the exon sequences for the dm3 genome. \begin{enumerate} \item Extract the exon ranges from \Rcode{txdb}. \item Load the \Rpackage{BSgenome.Dmelanogaster.UCSC.dm3} package. \item Use \Rcode{getSeq()} to extract the exon sequences from the \Rcode{BSgenome} object in \Rpackage{BSgenome.Dmelanogaster.UCSC.dm3}. \end{enumerate} \end{frame} \DefaultBackground %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRangesList} objects} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{The \Rclass{GRangesList} class is a container for...} storing a list of {\em compatible} \Rclass{GRanges} objects. \begin{block}{} {\em compatible} means: \begin{itemize} \item they are relative to the same genome, \item AND they have the same metadata columns (accessible with the \Rcode{mcols()} accessor). \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{The \Rcode{GRangesList()} constructor} \begin{frame}[fragile] \frametitle{The \Rcode{GRangesList()} constructor} \begin{exampleblock}{} {\small <>= grl <- GRangesList(gr3, gr2) grl @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{\Rclass{GRangesList} accessors} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors} \begin{exampleblock}{} <>= length(grl) @ \end{exampleblock} \begin{columns}[t] \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= seqnames(grl) @ } \end{exampleblock} \end{column} \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= strand(grl) @ } \end{exampleblock} \end{column} \end{columns} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{columns}[t] \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= ranges(grl) @ } \end{exampleblock} \end{column} \begin{column}{0.44\textwidth} \begin{exampleblock}{} {\small <>= start(grl) end(grl) width(grl) @ } \end{exampleblock} \end{column} \end{columns} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{exampleblock}{} {\small <>= names(grl) <- c("TX1", "TX2") grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{exampleblock}{} {\scriptsize <>= mcols(grl)$geneid <- c("GENE1", "GENE2") mcols(grl) grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{\Rclass{GRangesList} accessors (continued)} \begin{exampleblock}{} <>= seqinfo(grl) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Vector operations on \Rclass{GRangesList} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRangesList} objects} \begin{block}{} Only the following {\em vector operations} are supported on \Rclass{GRangesList} objects: \begin{itemize} \item \Rcode{length()}, \Rcode{names()} \item Single-bracket subsetting: \Rcode{[} \item Combining: \Rcode{c()} \end{itemize} \end{block} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRangesList} objects} \begin{exampleblock}{} {\small <>= grl[c("TX2", "TX1")] @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{Vector operations on \Rclass{GRangesList} objects (continued)} \begin{exampleblock}{} {\scriptsize <>= c(grl, GRangesList(gr3)) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{List operations on \Rclass{GRangesList} objects} \setbeamertemplate{background canvas}[vertical shading][bottom=green!20,top=green!20] \begin{frame}[fragile] \frametitle{List operations on \Rclass{GRangesList} objects} \begin{block}{} What we call {\em list operations} are operations that work on an ordinary list: \begin{itemize} \item Double-bracket subsetting: \Rcode{[[} \item \Rcode{elementNROWS()}, \Rcode{unlist()} \item \Rcode{lapply()}, \Rcode{sapply()}, \Rcode{endoapply()} \item \Rcode{mendoapply()} (not covered in this presentation) \end{itemize} \Rclass{GRangesList} objects support all these {\em list operations} $==>$ They're considered {\em list-like} objects. \end{block} \end{frame} \DefaultBackground \begin{frame}[fragile] \frametitle{elementNROWS() and unlist()} \begin{exampleblock}{} {\scriptsize <>= grl[[2]] elementNROWS(grl) unlisted <- unlist(grl, use.names=FALSE) # same as c(grl[[1]], grl[[2]]) unlisted @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{relist()} \begin{exampleblock}{} {\small <>= grl100 <- relist(shift(unlisted, 100), grl) grl100 @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{endoapply()} \begin{exampleblock}{} {\scriptsize <>= grl100b <- endoapply(grl, shift, 100) grl100b mcols(grl100) mcols(grl100b) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Range-based operations on \Rclass{GRangesList} objects} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= shift(grl, 100) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{shift(grl, 100)} is equivalent to \Rcode{endoapply(grl, shift, 100)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= flank(grl, 10) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{flank(grl, 10)} is equivalent to \Rcode{endoapply(grl, flank, 10)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= range(grl) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{range(grl)} is equivalent to \Rcode{endoapply(grl, range)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= reduce(grl) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{reduce(grl)} is equivalent to \Rcode{endoapply(grl, reduce)} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Range-based operations on \Rclass{GRangesList} objects (continued)} <>= grl2 <- grl grl2[[1]] <- grl2[[1]][3]; grl2[[2]] <- grl2[[2]][1] grl3 <- unname(grl2) grl3[[1]] <- narrow(unname(grl3[[1]]), start=5, end=-5) @ \begin{columns}[t] \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= grl2 grl3 @ } \end{exampleblock} \end{column} \begin{column}{0.49\textwidth} \begin{exampleblock}{} {\scriptsize <>= setdiff(grl2, grl3) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{setdiff(grl2, grl)} is equivalent to \Rcode{mendoapply(setdiff, grl2, grl)} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Other resources} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Other resources} \begin{itemize} \item Great slides from Michael on ranges sequences and alignments: \url{http://bioconductor.org/help/course-materials/2014/CSAMA2014/2_Tuesday/lectures/Ranges_Sequences_and_Alignments-Lawrence.pdf} \item Vignettes in the \Rpackage{GenomicRanges} package (\Rcode{browseVignettes("GenomicRanges")}). \item \Rclass{GRanges} and \Rclass{GRangesList} man pages in the \Rpackage{GenomicRanges} package. \item Vignettes and \Rclass{GAlignments} man page in the \Rpackage{GenomicAlignments} package. \item \Bioconductor{} support site: \url{http://support.bioconductor.org/} \item The {\em genomic ranges} paper: Michael Lawrence, Wolfgang Huber, Herv\'e Pag\`es, Patrick Aboyoun, Marc Carlson, Robert Gentleman, Martin T. Morgan, Vincent J. Carey. Software for Computing and Annotating Genomic Ranges. {\em PLOS Computational Biology}, 4(3), 2013. \end{itemize} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document} GenomicRanges/vignettes/GenomicRanges.bib0000644000175400017540000000055613175713746021554 0ustar00biocbuildbiocbuild@article{Lawrence2013ranges, author={Michael Lawrence and Wolfgang Huber and Herv\'e Pag\`es and Patrick Aboyoun and Marc Carlson and Robert Gentleman and Martin T. Morgan and Vincent J. Carey}, title={Software for Computing and Annotating Genomic Ranges}, journal={PLOS Computational Biology}, volume={4}, number={3}, year={2013} } GenomicRanges/vignettes/GenomicRangesHOWTOs.Rnw0000644000175400017540000011362713175713746022576 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{2. GenomicRanges HOWTOs} %\VignetteDepends{GenomicRanges, Rsamtools, GenomicAlignments, pasillaBamSubset, TxDb.Dmelanogaster.UCSC.dm3.ensGene, TxDb.Athaliana.BioMart.plantsmart22, AnnotationHub, DESeq2, edgeR, TxDb.Hsapiens.UCSC.hg19.knownGene, GenomicFeatures, Biostrings, BSgenome.Hsapiens.UCSC.hg19, KEGG.db, KEGGgraph, BSgenome.Scerevisiae.UCSC.sacCer2} %\VignetteKeywords{sequence, sequencing, alignments} %\VignettePackage{GenomicRanges} \documentclass{article} \usepackage[authoryear,round]{natbib} <>= BiocStyle::latex(use.unsrturl=FALSE) @ \title{\Biocpkg{GenomicRanges} HOWTOs} \author{Bioconductor Team} \date{Edited: July 2014; Compiled: \today} \begin{document} \maketitle \tableofcontents <>= options(width=72) options(showHeadLines=3) options(showTailLines=3) .precomputed_results_path <- "precomputed_results" @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} \subsection{Purpose of this document} This document is a collection of {\it HOWTOs}. Each {\it HOWTO} is a short section that demonstrates how to use the containers and operations implemented in the \Biocpkg{GenomicRanges} and related packages (\Biocpkg{IRanges}, \Biocpkg{Biostrings}, \Biocpkg{Rsamtools}, \Biocpkg{GenomicAlignments}, \Biocpkg{BSgenome}, and \Biocpkg{GenomicFeatures}) to perform a task typically found in the context of a high throughput sequence analysis. Unless stated otherwise, the {\it HOWTOs} are self contained, independent of each other, and can be studied and reproduced in any order. \subsection{Prerequisites and additional recommended reading} We assume the reader has some previous experience with \R{} and with basic manipulation of \Rcode{GRanges}, \Rcode{GRangesList}, \Rcode{Rle}, \Rcode{RleList}, and \Rcode{DataFrame} objects. See the ``An Introduction to Genomic Ranges Classes'' vignette located in the \Biocpkg{GenomicRanges} package (in the same folder as this document) for an introduction to these containers. Additional recommended readings after this document are the ``Software for Computing and Annotating Genomic Ranges'' paper[\citet{Lawrence2013ranges}] and the ``Counting reads with \Rfunction{summarizeOverlaps}'' vignette located in the \Biocpkg{GenomicAlignments} package. To display the list of vignettes available in the \Biocpkg{GenomicRanges} package, use \Rcode{browseVignettes("GenomicRanges")}. \subsection{Input data and terminology used across the HOWTOs} In order to avoid repetition, input data, concepts and terms used in more than one {\it HOWTO} are described here: \begin{itemize} \item {\bf The \Biocpkg{pasillaBamSubset} data package}: contains both a BAM file with single-end reads (untreated1\_chr4) and a BAM file with paired-end reads (untreated3\_chr4). Each file is a subset of chr4 from the "Pasilla" experiment. <>= library(pasillaBamSubset) untreated1_chr4() untreated3_chr4() @ See \Rcode{?pasillaBamSubset} for more information. <>= ?pasillaBamSubset @ \item {\bf Gene models and \Rclass{TxDb} objects}: A \textit{gene model} is essentially a set of annotations that describes the genomic locations of the known genes, transcripts, exons, and CDS, for a given organism. In \Bioconductor{} it is typically represented as a \Rclass{TxDb} object but also sometimes as a \Rclass{GRanges} or \Rclass{GRangesList} object. The \Biocpkg{GenomicFeatures} package contains tools for making and manipulating \Rclass{TxDb} objects. \end{itemize} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{HOWTOs} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to read single-end reads from a BAM file} As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads @ Several functions are available for reading BAM files into \R{}: \begin{verbatim} readGAlignments() readGAlignmentPairs() readGAlignmentsList() scanBam() \end{verbatim} \Rfunction{scanBam} is a low-level function that returns a list of lists and is not discussed further here. See \Rcode{?scanBam} in the \Biocpkg{Rsamtools} package for more information. Single-end reads can be loaded with the \Rfunction{readGAlignments} function from the \Biocpkg{GenomicAlignments} package. <>= library(GenomicAlignments) gal <- readGAlignments(un1) @ Data subsets can be specified by genomic position, field names, or flag criteria in the \Rcode{ScanBamParam}. Here we input records that overlap position 1 to 5000 on the negative strand with \Rcode{flag} and \Rcode{cigar} as metadata columns. <>= what <- c("flag", "cigar") which <- GRanges("chr4", IRanges(1, 5000)) flag <- scanBamFlag(isMinusStrand = TRUE) param <- ScanBamParam(which=which, what=what, flag=flag) neg <- readGAlignments(un1, param=param) neg @ Another approach to subsetting the data is to use \Rfunction{filterBam}. This function creates a new BAM file of records passing user-defined criteria. See \Rcode{?filterBam} in the \Biocpkg{Rsamtools} package for more information. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to read paired-end reads from a BAM file} As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un3 <- untreated3_chr4() # paired-end reads @ Paired-end reads can be loaded with the \Rfunction{readGAlignmentPairs} or \Rfunction{readGAlignmentsList} function from the \Biocpkg{GenomicAlignments} package. These functions use the same mate paring algorithm but output different objects. Let's start with \Rfunction{readGAlignmentPairs}: <>= un3 <- untreated3_chr4() gapairs <- readGAlignmentPairs(un3) @ The \Robject{GAlignmentPairs} class holds only pairs; reads with no mate or with ambiguous pairing are discarded. Each list element holds exactly 2 records (a mated pair). Records can be accessed as the \Rcode{first} and\Rcode{last} segments in a template or as \Rcode{left} and \Rcode{right} alignments. See \Rcode{?GAlignmentPairs} in the \Biocpkg{GenomicAlignments} package for more information. <>= gapairs @ For \Rcode{readGAlignmentsList}, mate pairing is performed when \Rcode{asMates} is set to \Rcode{TRUE} on the \Rcode{BamFile} object, otherwise records are treated as single-end. <>= galist <- readGAlignmentsList(BamFile(un3, asMates=TRUE)) @ \Robject{GAlignmentsList} is a more general `list-like' structure that holds mate pairs as well as non-mates (i.e., singletons, records with unmapped mates etc.) A \Rcode{mates\_status} metadata column (accessed with \Rfunction{mcols}) indicates which records were paired. <>= galist @ Non-mated reads are returned as groups by QNAME and contain any number of records. Here the non-mate groups range in size from 1 to 9. <>= non_mates <- galist[unlist(mcols(galist)$mate_status) == "unmated"] table(elementNROWS(non_mates)) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to read and process a big BAM file by chunks in order to reduce memory usage} A large BAM file can be iterated through in chunks by setting a \Rcode{yieldSize} on the \Rclass{BamFile} object. As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() bf <- BamFile(un1, yieldSize=100000) @ Iteration through a BAM file requires that the file be opened, repeatedly queried inside a loop, then closed. Repeated calls to \Rfunction{readGAlignments} without opening the file first result in the same 100000 records returned each time. <>= open(bf) cvg <- NULL repeat { chunk <- readGAlignments(bf) if (length(chunk) == 0L) break chunk_cvg <- coverage(chunk) if (is.null(cvg)) { cvg <- chunk_cvg } else { cvg <- cvg + chunk_cvg } } close(bf) cvg @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to compute read coverage} The ``read coverage'' is the number of reads that cover a given genomic position. Computing the read coverage generally consists in computing the coverage at each position in the genome. This can be done with the \Rcode{coverage()} function. As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads library(GenomicAlignments) reads1 <- readGAlignments(un1) cvg1 <- coverage(reads1) cvg1 @ Coverage on chr4: <>= cvg1$chr4 @ Average and max coverage: <>= mean(cvg1$chr4) max(cvg1$chr4) @ Note that \Rcode{coverage()} is a generic function with methods for different types of objects. See \Rcode{?coverage} for more information. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to find peaks in read coverage} ChIP-Seq analysis usually involves finding peaks in read coverage. This process is sometimes called ``peak calling'' or ``peak detection''. Here we're only showing a naive way to find peaks in the object returned by the \Rcode{coverage()} function. \Bioconductor{} packages \Biocpkg{BayesPeak}, \Biocpkg{bumphunter}, \Biocpkg{Starr}, \Biocpkg{CexoR}, \Biocpkg{exomePeak}, \Biocpkg{RIPSeeker}, and others, provide sophisticated peak calling tools for ChIP-Seq, RIP-Seq, and other kind of high throughput sequencing data. Let's assume \Rcode{cvg1} is the object returned by \Rcode{coverage()} (see previous {\it HOWTO} for how to compute it). We can use the \Rcode{slice()} function to find the genomic regions where the coverage is greater or equal to a given threshold. <>= chr4_peaks <- slice(cvg1$chr4, lower=500) chr4_peaks length(chr4_peaks) # nb of peaks @ The weight of a given peak can be defined as the number of aligned nucleotides that belong to the peak (a.k.a. the area under the peak in mathematics). It can be obtained with \Rcode{sum()}: <>= sum(chr4_peaks) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to retrieve a gene model from the UCSC genome browser} See introduction for a quick description of what \textit{gene models} and \Rclass{TxDb} objects are. We can use the \Rcode{make\-Transcript\-Db\-From\-UCSC()} function from the \Biocpkg{GenomicFeatures} package to import a UCSC genome browser track as a \Rclass{TxDb} object. <>= library(GenomicFeatures) ### Internet connection required! Can take several minutes... txdb <- makeTxDbFromUCSC(genome="sacCer2", tablename="ensGene") @ See \Rcode{?makeTxDbFromUCSC} in the \Biocpkg{GenomicFeatures} package for more information. Note that some of the most frequently used gene models are available as TxDb packages. A TxDb package consists of a pre-made \Rclass{TxDb} object wrapped into an annotation data package. Go to \url{http://bioconductor.org/packages/release/BiocViews.html#\_\_\_TxDb} to browse the list of available TxDb packages. <>= library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene txdb @ Extract the transcript coordinates from this gene model: <>= transcripts(txdb) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to retrieve a gene model from Ensembl} See introduction for a quick description of what \textit{gene models} and \Rclass{TxDb} objects are. We can use the \Rcode{make\-Transcript\-Db\-From\-Biomart()} function from the \Biocpkg{GenomicFeatures} package to retrieve a gene model from the Ensembl Mart. <>= library(GenomicFeatures) ### Internet connection required! Can take several minutes... txdb <- makeTxDbFromBiomart(biomart="ensembl", dataset="hsapiens_gene_ensembl") @ See \Rcode{?makeTxDbFromBiomart} in the \Biocpkg{GenomicFeatures} package for more information. Note that some of the most frequently used gene models are available as TxDb packages. A TxDb package consists of a pre-made \Rclass{TxDb} object wrapped into an annotation data package. Go to \url{http://bioconductor.org/packages/release/BiocViews.html#\_\_\_TxDb} to browse the list of available TxDb packages. <>= library(TxDb.Athaliana.BioMart.plantsmart22) txdb <- TxDb.Athaliana.BioMart.plantsmart22 txdb @ Extract the exon coordinates from this gene model: <>= exons(txdb) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to load a gene model from a GFF or GTF file} See introduction for a quick description of what \textit{gene models} and \Rclass{TxDb} objects are. We can use the \Rcode{make\-Transcript\-Db\-From\-GFF()} function from the \Biocpkg{GenomicFeatures} package to import a GFF or GTF file as a \Rclass{TxDb} object. <>= library(GenomicFeatures) gff_file <- system.file("extdata", "GFF3_files", "a.gff3", package="GenomicFeatures") txdb <- makeTxDbFromGFF(gff_file, format="gff3") txdb @ See \Rcode{?makeTxDbFromGFF} in the \Biocpkg{GenomicFeatures} package for more information. Extract the exon coordinates grouped by gene from this gene model: <>= exonsBy(txdb, by="gene") @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to retrieve a gene model from \Biocpkg{AnnotationHub}} When a gene model is not available as a \Rclass{GRanges} or \Rclass{GRangesList} object or as a \Bioconductor{} data package, it may be available on \Biocpkg{AnnotationHub}. In this {\it HOWTO}, will look for a gene model for Drosophila melanogaster on \Biocpkg{AnnotationHub}. Create a `hub' and then filter on Drosophila melanogaster: <>= library(AnnotationHub) ### Internet connection required! hub <- AnnotationHub() hub <- subset(hub, hub$species=='Drosophila melanogaster') @ There are 87 files that match Drosophila melanogaster. If you look at the metadata in hub, you can see that the 7th record representes a GRanges object from UCSC <>= length(hub) head(names(hub)) head(hub$title, n=10) ## then look at a specific slice of the hub object. hub[7] @ So you can retrieve that dm3 file as a \Rcode{GRanges} like this: <>= gr <- hub[[names(hub)[7]]] summary(gr) @ The metadata fields contain the details of file origin and content. <>= metadata(gr) @ Split the \Rclass{GRanges} object by gene name to get a \Rclass{GRangesList} object of transcript ranges grouped by gene. <>= txbygn <- split(gr, gr$name) @ You can now use \Rcode{txbygn} with the \Rcode{summarizeOverlaps} function to prepare a table of read counts for RNA-Seq differential gene expression. Note that before passing \Rcode{txbygn} to \Rcode{summarizeOverlaps}, you should confirm that the seqlevels (chromosome names) in it match those in the BAM file. See \Rcode{?renameSeqlevels}, \Rcode{?keepSeqlevels} and \Rcode{?seqlevels} for examples of renaming seqlevels. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to annotate peaks in read coverage} [coming soon...] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to prepare a table of read counts for RNA-Seq differential gene expression} Methods for RNA-Seq gene expression analysis generally require a table of counts that summarize the number of reads that overlap or `hit' a particular gene. In this {\it HOWTO} we count with the \Rcode{summarizeOverlaps} function from the \Biocpkg{GenomicAlignments} package and create a count table from the results. Other packages that provide read counting are \Biocpkg{Rsubread} and \Biocpkg{easyRNASeq}. The \Biocpkg{parathyroidSE} package vignette contains a workflow on counting and other common operations required for differential expression analysis. As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) reads <- c(untrt1=untreated1_chr4(), # single-end reads untrt3=untreated3_chr4()) # paired-end reads @ \Rcode{summarizeOverlaps} requires the name of a BAM file(s) and a {\textit gene model} to count against. See introduction for a quick description of what a \textit{gene models} is. The gene model must match the genome build the reads in the BAM file were aligned to. For the pasilla data this is dm3 Dmelanogaster which is available as a \Bioconductor{} package. Load the package and extract the exon ranges grouped by gene: <>= library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) exbygene <- exonsBy(TxDb.Dmelanogaster.UCSC.dm3.ensGene, "gene") @ \Rcode{exbygene} is a \Rclass{GRangesList} object with one list element per gene in the gene model. \Rcode{summarizeOverlaps} automatically sets a \Rcode{yieldSize} on large BAM files and iterates over them in chunks. When reading paired-end data set the \Rcode{singleEnd} argument to FALSE. See ?\Rfunction{summarizeOverlaps} for details reguarding the count \Rcode{modes} and additional arguments. <>= library(GenomicAlignments) se <- summarizeOverlaps(exbygene, reads, mode="IntersectionNotEmpty") @ The return object is a \Rcode{SummarizedExperiment} with counts accessible with the \Rcode{assays} accessor: <>= class(se) head(table(assays(se)$counts)) @ The count vector is the same length as \Rcode{exbygene}: <>= identical(length(exbygene), length(assays(se)$counts)) @ A copy of \Rcode{exbygene} is stored in the \Rcode{se} object and accessible with \Rcode{rowRanges} accessor: <>= rowRanges(se) @ Two popular packages for RNA-Seq differential gene expression are \Biocpkg{DESeq2} and \Biocpkg{edgeR}. Tables of counts per gene are required for both and can be easily created with a vector of counts. Here we use the counts from our \Rclass{SummarizedExperiment} object: <>= colData(se)$trt <- factor(c("untrt", "untrt"), levels=c("trt", "untrt")) colData(se) library(DESeq2) deseq <- DESeqDataSet(se, design= ~ 1) library(edgeR) edger <- DGEList(assays(se)$counts, group=rownames(colData(se))) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to summarize junctions from a BAM file containing RNA-Seq reads} As sample data we use the \Biocpkg{pasillaBamSubset} data package described in the introduction. <>= library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads library(GenomicAlignments) reads1 <- readGAlignments(un1) reads1 @ For each alignment, the aligner generated a CIGAR string that describes its "geometry", that is, the locations of insertions, deletions and junctions in the alignment. See the SAM Spec available on the SAMtools website for the details (\url{http://samtools.sourceforge.net/}). The \Rcode{summarizeJunctions()} function from the \Biocpkg{GenomicAlignments} package can be used to summarize the junctions in \Rcode{reads1}. <>= junc_summary <- summarizeJunctions(reads1) junc_summary @ See \Rcode{?summarizeJunctions} in the \Biocpkg{GenomicAlignments} package for more information. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to get the exon and intron sequences of a given gene} The exon and intron sequences of a gene are essentially the DNA sequences of the introns and exons of all known transcripts of the gene. The first task is to identify all transcripts associated with the gene of interest. Our sample gene is the human TRAK2 which is involved in regulation of endosome-to-lysosome trafficking of membrane cargo. The Entrez gene id is `66008'. <>= trak2 <- "66008" @ The \Biocpkg{TxDb.Hsapiens.UCSC.hg19.knownGene} data package contains the gene model corresponding to the UCSC `Known Genes' track. <>= library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene @ The transcript ranges for all the genes in the gene model can be extracted with the \Rfunction{transcriptsBy} function from the \Biocpkg{GenomicFeatures} package. They will be returned in a named \Rclass{GRangesList} object containing all the transcripts grouped by gene. In order to keep only the transcripts of the TRAK2 gene we will subset the \Rclass{GRangesList} object using the \Rcode{[[} operator. <>= library(GenomicFeatures) trak2_txs <- transcriptsBy(txdb, by="gene")[[trak2]] trak2_txs @ \Rcode{trak2\_txs} is a \Rclass{GRanges} object with one range per transcript in the TRAK2 gene. The transcript names are stored in the \Rcode{tx\_name} metadata column. We will need them to subset the extracted intron and exon regions: <>= trak2_tx_names <- mcols(trak2_txs)$tx_name trak2_tx_names @ The exon and intron genomic ranges for all the transcripts in the gene model can be extracted with the \Rfunction{exonsBy} and \Rfunction{intronsByTranscript} functions, respectively. Both functions return a \Rclass{GRangesList} object. Then we keep only the exon and intron for the transcripts of the TRAK2 gene by subsetting each \Rclass{GRangesList} object by the TRAK2 transcript names. Extract the exon regions: <>= trak2_exbytx <- exonsBy(txdb, "tx", use.names=TRUE)[trak2_tx_names] elementNROWS(trak2_exbytx) @ ... and the intron regions: <>= trak2_inbytx <- intronsByTranscript(txdb, use.names=TRUE)[trak2_tx_names] elementNROWS(trak2_inbytx) @ Next we want the DNA sequences for these exons and introns. The \Rfunction{getSeq} function from the \Biocpkg{Biostrings} package can be used to query a \Biocpkg{BSgenome} object with a set of genomic ranges and retrieve the corresponding DNA sequences. <>= library(BSgenome.Hsapiens.UCSC.hg19) @ Extract the exon sequences: <>= trak2_ex_seqs <- getSeq(Hsapiens, trak2_exbytx) trak2_ex_seqs trak2_ex_seqs[["uc002uyb.4"]] trak2_ex_seqs[["uc002uyc.2"]] @ ... and the intron sequences: <>= trak2_in_seqs <- getSeq(Hsapiens, trak2_inbytx) trak2_in_seqs trak2_in_seqs[["uc002uyb.4"]] trak2_in_seqs[["uc002uyc.2"]] @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to get the CDS and UTR sequences of genes associated with colorectal cancer} In this {\it HOWTO} we extract the CDS and UTR sequences of genes involved in colorectal cancer. The workflow extends the ideas presented in the previous {\it HOWTO} and suggests an approach for identifying disease-related genes. \subsubsection{Build a gene list} We start with a list of gene or transcript ids. If you do not have pre-defined list one can be created with the \Biocpkg{KEGG.db} and \Biocpkg{KEGGgraph} packages. Updates to the data in the \Biocpkg{KEGG.db} package are no longer available, however, the resource is still useful for identifying pathway names and ids. Create a table of KEGG pathways and ids and search on the term `cancer'. <>= library(KEGG.db) pathways <- toTable(KEGGPATHNAME2ID) pathways[grepl("cancer", pathways$path_name, fixed=TRUE),] @ Use the "05210" id to query the KEGG web resource (accesses the currently maintained data). <>= library(KEGGgraph) dest <- tempfile() retrieveKGML("05200", "hsa", dest, "internal") @ The suffix of the KEGG id is the Entrez gene id. The \Rfunction{translateKEGGID2GeneID} simply removes the prefix leaving just the Entrez gene ids. <>= crids <- as.character(parseKGML2DataFrame(dest)[,1]) crgenes <- unique(translateKEGGID2GeneID(crids)) head(crgenes) @ \subsubsection{Identify genomic coordinates} The list of gene ids is used to extract genomic positions of the regions of interest. The Known Gene table from UCSC will be the annotation and is available as a \Bioconductor{} package. <>= library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene @ If an annotation is not available as a \Bioconductor{} annotation package it may be available in \Biocpkg{AnnotationHub}. Additionally, there are functions in \Biocpkg{GenomicFeatures} which can retrieve data from UCSC and Ensembl to create a \Robject{TxDb}. See \Rcode{?makeTxDbFromUCSC} for more information. As in the previous {\it HOWTO} we need to identify the transcripts corresponding to each gene. The transcript id (or name) is used to isolate the UTR and coding regions of interest. This grouping of transcript by gene is also used to re-group the final sequence results. The \Rcode{transcriptsBy} function outputs both the gene and transcript identifiers which we use to create a map between the two. The \Rcode{map} is a \Robject{CharacterList} with gene ids as names and transcript ids as the list elements. <>= txbygene <- transcriptsBy(txdb, "gene")[crgenes] ## subset on colorectal genes map <- relist(unlist(txbygene, use.names=FALSE)$tx_id, txbygene) map @ Extract the UTR and coding regions. <>= cds <- cdsBy(txdb, "tx") threeUTR <- threeUTRsByTranscript(txdb) fiveUTR <- fiveUTRsByTranscript(txdb) @ Coding and UTR regions may not be present for all transcripts specified in \Rcode{map}. Consequently, the subset results will not be the same length. This length discrepancy must be taken into account when re-listing the final results by gene. <>= txid <- unlist(map, use.names=FALSE) cds <- cds[names(cds) %in% txid] threeUTR <- threeUTR[names(threeUTR) %in% txid] fiveUTR <- fiveUTR[names(fiveUTR) %in% txid] @ Note the different lengths of the subset regions. <>= length(txid) ## all possible transcripts length(cds) length(threeUTR) length(fiveUTR) @ These objects are \Robject{GRangesList}s with the transcript id as the outer list element. <>= cds @ \subsubsection{Extract sequences from BSgenome} The \Rcode{BSgenome} packages contain complete genome sequences for a given organism. Load the \Rcode{BSgenome} package for homo sapiens. <>= library(BSgenome.Hsapiens.UCSC.hg19) genome <- BSgenome.Hsapiens.UCSC.hg19 @ Use \Rfunction{extractTranscriptSeqs} to extract the UTR and coding regions from the \Rcode{BSgenome}. This function retrieves the sequences for an any \Robject{GRanges} or \Robject{GRangesList} (i.e., not just transcripts like the name implies). <>= threeUTR_seqs <- extractTranscriptSeqs(genome, threeUTR) fiveUTR_seqs <- extractTranscriptSeqs(genome, fiveUTR) cds_seqs <- extractTranscriptSeqs(genome, cds) @ The return values are \Robject{DNAStringSet} objects. <>= cds_seqs @ Our final step is to collect the coding and UTR regions (currently organzied by transcript) into groups by gene id. The \Rfunction{relist} function groups the sequences of a \Robject{DNAStringSet} object into a \Robject{DNAStringSetList} object, based on the specified \Rcode{skeleton} argument. The \Rcode{skeleton} must be a list-like object and only its shape (i.e. its element lengths) matters (its exact content is ignored). A simple form of \Rcode{skeleton} is to use a partitioning object that we make by specifying the size of each partition. The partitioning objects are different for each type of region because not all transcripts had a coding or 3' or 5' UTR region defined. <>= lst3 <- relist(threeUTR_seqs, PartitioningByWidth(sum(map %in% names(threeUTR)))) lst5 <- relist(fiveUTR_seqs, PartitioningByWidth(sum(map %in% names(fiveUTR)))) lstc <- relist(cds_seqs, PartitioningByWidth(sum(map %in% names(cds)))) @ There are 239 genes in \Rcode{map} each of which have 1 or more transcripts. The table of element lengths shows how many genes have each number of transcripts. For example, 47 genes have 1 transcript, 48 genes have 2 etc. <>= length(map) table(elementNROWS(map)) @ The lists of DNA sequences all have the same length as \Rcode{map} but one or more of the element lengths may be zero. This would indicate that data were not available for that gene. The tables below show that there was at least 1 coding region available for all genes (i.e., none of the element lengths are 0). However, both the 3' and 5' UTR results have element lengths of 0 which indicates no UTR data were available for that gene. <>= table(elementNROWS(lstc)) table(elementNROWS(lst3)) names(lst3)[elementNROWS(lst3) == 0L] ## genes with no 3' UTR data table(elementNROWS(lst5)) names(lst5)[elementNROWS(lst5) == 0L] ## genes with no 5' UTR data @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to create DNA consensus sequences for read group `families'} The motivation for this {\it HOWTO} comes from a study which explored the dynamics of point mutations. The mutations of interest exist with a range of frequencies in the control group (e.g., 0.1\% - 50\%). PCR and sequencing error rates make it difficult to identify low frequency events (e.g., < 20\%). When a library is prepared with Nextera, random fragments are generated followed by a few rounds of PCR. When the genome is large enough, reads aligning to the same start position are likely descendant from the same template fragment and should have identical sequences. The goal is to elimininate noise by grouping the reads by common start position and discarding those that do not exceed a certain threshold within each family. A new consensus sequence will be created for each read group family. \subsubsection{Sort reads into groups by start position} Load the BAM file into a GAlignments object. <>= library(Rsamtools) bamfile <- system.file("extdata", "ex1.bam", package="Rsamtools") param <- ScanBamParam(what=c("seq", "qual")) library(GenomicAlignments) gal <- readGAlignments(bamfile, use.names=TRUE, param=param) @ Use the \Rfunction{sequenceLayer} function to {\it lay} the query sequences and quality strings on the reference. <>= qseq <- setNames(mcols(gal)$seq, names(gal)) qual <- setNames(mcols(gal)$qual, names(gal)) qseq_on_ref <- sequenceLayer(qseq, cigar(gal), from="query", to="reference") qual_on_ref <- sequenceLayer(qual, cigar(gal), from="query", to="reference") @ Split by chromosome. <>= qseq_on_ref_by_chrom <- splitAsList(qseq_on_ref, seqnames(gal)) qual_on_ref_by_chrom <- splitAsList(qual_on_ref, seqnames(gal)) pos_by_chrom <- splitAsList(start(gal), seqnames(gal)) @ For each chromosome generate one GRanges object that contains unique alignment start positions and attach 3 metadata columns to it: the number of reads, the query sequences, and the quality strings. <>= gr_by_chrom <- lapply(seqlevels(gal), function(seqname) { qseq_on_ref2 <- qseq_on_ref_by_chrom[[seqname]] qual_on_ref2 <- qual_on_ref_by_chrom[[seqname]] pos2 <- pos_by_chrom[[seqname]] qseq_on_ref_per_pos <- split(qseq_on_ref2, pos2) qual_on_ref_per_pos <- split(qual_on_ref2, pos2) nread <- elementNROWS(qseq_on_ref_per_pos) gr_mcols <- DataFrame(nread=unname(nread), qseq_on_ref=unname(qseq_on_ref_per_pos), qual_on_ref=unname(qual_on_ref_per_pos)) gr <- GRanges(Rle(seqname, nrow(gr_mcols)), IRanges(as.integer(names(nread)), width=1)) mcols(gr) <- gr_mcols seqlevels(gr) <- seqlevels(gal) gr }) @ Combine all the GRanges objects obtained in (4) in 1 big GRanges object: <>= gr <- do.call(c, gr_by_chrom) seqinfo(gr) <- seqinfo(gal) @ `gr' is a GRanges object that contains unique alignment start positions: <>= gr[1:6] @ Look at qseq\_on\_ref and qual\_on\_ref. <>= qseq_on_ref qual_on_ref @ 2 reads align to start position 13. Let's have a close look at their sequences: <>= mcols(gr)$qseq_on_ref[[6]] @ and their qualities: <>= mcols(gr)$qual_on_ref[[6]] @ Note that the sequence and quality strings are those projected to the reference so the first letter in those strings are on top of start position 13, the 2nd letter on top of position 14, etc... \subsubsection{Remove low frequency reads} For each start position, remove reads with and under-represented sequence (e.g. threshold = 20\% for the data used here which is low coverage). A unique number is assigned to each unique sequence. This will make future calculations easier and a little bit faster. <>= qseq_on_ref <- mcols(gr)$qseq_on_ref tmp <- unlist(qseq_on_ref, use.names=FALSE) qseq_on_ref_id <- relist(match(tmp, tmp), qseq_on_ref) @ Quick look at `qseq\_on\_ref\_id': It's an IntegerList object with the same length and "shape" as `qseq\_on\_ref'. <>= qseq_on_ref_id @ Remove the under represented ids from each list element of `qseq\_on\_ref\_id': <>= qseq_on_ref_id2 <- endoapply(qseq_on_ref_id, function(ids) ids[countMatches(ids, ids) >= 0.2 * length(ids)]) @ Remove corresponding sequences from `qseq\_on\_ref': <>= tmp <- unlist(qseq_on_ref_id2, use.names=FALSE) qseq_on_ref2 <- relist(unlist(qseq_on_ref, use.names=FALSE)[tmp], qseq_on_ref_id2) @ \subsubsection{Create a consensus sequence for each read group family} Compute 1 consensus matrix per chromosome: <>= split_factor <- rep.int(seqnames(gr), elementNROWS(qseq_on_ref2)) qseq_on_ref2 <- unlist(qseq_on_ref2, use.names=FALSE) qseq_on_ref2_by_chrom <- splitAsList(qseq_on_ref2, split_factor) qseq_pos_by_chrom <- splitAsList(start(gr), split_factor) cm_by_chrom <- lapply(names(qseq_pos_by_chrom), function(seqname) consensusMatrix(qseq_on_ref2_by_chrom[[seqname]], as.prob=TRUE, shift=qseq_pos_by_chrom[[seqname]]-1, width=seqlengths(gr)[[seqname]])) names(cm_by_chrom) <- names(qseq_pos_by_chrom) @ 'cm\_by\_chrom' is a list of consensus matrices. Each matrix has 17 rows (1 per letter in the DNA alphabet) and 1 column per chromosome position. <>= lapply(cm_by_chrom, dim) @ Compute the consensus string from each consensus matrix. We'll put "+" in the strings wherever there is no coverage for that position, and "N" where there is coverage but no consensus. <>= cs_by_chrom <- lapply(cm_by_chrom, function(cm) { ## need to "fix" 'cm' because consensusString() ## doesn't like consensus matrices with columns ## that contain only zeroes (e.g., chromosome ## positions with no coverage) idx <- colSums(cm) == 0L cm["+", idx] <- 1 DNAString(consensusString(cm, ambiguityMap="N")) }) @ The new consensus strings. <>= cs_by_chrom @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{How to compute binned averages along a genome} In some applications (e.g. visualization), there is the need to compute the average of a variable defined along a genome (a.k.a. genomic variable) for a set of predefined fixed-width regions (sometimes called "bins"). The genomic variable is typically represented as a named \Robject{RleList} object with one list element per chromosome. One such example is coverage. Here we create an artificial genomic variable: <>= library(BSgenome.Scerevisiae.UCSC.sacCer2) set.seed(55) my_var <- RleList( lapply(seqlengths(Scerevisiae), function(seqlen) { tmp <- sample(50L, seqlen, replace=TRUE) %/% 50L Rle(cumsum(tmp - rev(tmp))) } ), compress=FALSE) my_var @ Use the \Rfunction{tileGenome} function to create a set of bins along the genome. <>= bins <- tileGenome(seqinfo(Scerevisiae), tilewidth=100, cut.last.tile.in.chrom=TRUE) @ Compute the binned average for \Rcode{my\_var}: <>= binnedAverage(bins, my_var, "binned_var") @ The bin size can be modified with the \Rcode{tilewidth} argument to \Rfunction{tileGenome}. See \Rcode{?binnedAverage} for additional examples. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Session Information} <>= sessionInfo() @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \bibliography{GenomicRanges} \bibliographystyle{plainnat} \end{document} GenomicRanges/vignettes/GenomicRangesIntroduction.Rnw0000644000175400017540000005041713175713746024171 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{1. An Introduction to the GenomicRanges Package} %\VignetteKeywords{sequence, sequencing} %\VignettePackage{GenomicRanges} \documentclass{article} <>= BiocStyle::latex() @ \newcommand{\GenomicRanges}{\Biocpkg{GenomicRanges}} \title{An Introduction to the GenomicRanges Package} \author{Marc Carlson, Patrick Aboyoun, Herv\'{e} Pag\`{e}s, and Martin Morgan} \date{\today; updated 16 November, 2016} \begin{document} \maketitle \tableofcontents %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} The \Biocpkg{GenomicRanges} package serves as the foundation for representing genomic locations within the \software{Bioconductor} project. In the \software{Bioconductor} package hierarchy, it builds upon the \Biocpkg{IRanges} (infrastructure) package and provides support for the \Biocpkg{BSgenome} (infrastructure), \Biocpkg{Rsamtools} (I/O), \Biocpkg{ShortRead} (I/O \& QA), \Biocpkg{rtracklayer} (I/O), \Biocpkg{GenomicFeatures} (infrastructure), \Biocpkg{GenomicAlignments} (sequence reads), \Biocpkg{VariantAnnotation} (called variants), and many other \software{Bioconductor} packages. This package lays a foundation for genomic analysis by introducing three classes (\Rclass{GRanges}, \Rclass{GPos}, and \Rclass{GRangesList}), which are used to represent genomic ranges, genomic positions, and groups of genomic ranges. This vignette focuses on the \Rclass{GRanges} and \Rclass{GRangesList} classes and their associated methods. The \Biocpkg{GenomicRanges} package is available at \href{https://bioconductor.org}{https://bioconductor.org} and can be installed via \Rfunction{biocLite}: %% <>= source("https://bioconductor.org/biocLite.R") biocLite("GenomicRanges") @ %% A package only needs to be installed once. Load the package into an \R{} session with %% <>= library(GenomicRanges) @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRanges}: Genomic Ranges} The \Rclass{GRanges} class represents a collection of genomic ranges that each have a single start and end location on the genome. It can be used to store the location of genomic features such as contiguous binding sites, transcripts, and exons. These objects can be created by using the \Rfunction{GRanges} constructor function. For example, <>= gr <- GRanges( seqnames = Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges = IRanges(101:110, end = 111:120, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score = 1:10, GC = seq(1, 0, length=10)) gr options(warn=2) @ %% creates a \Rclass{GRanges} object with 10 genomic ranges. The output of the \Rclass{GRanges} \Rcode{show} method separates the information into a left and right hand region that are separated by \Rcode{|} symbols. The genomic coordinates (seqnames, ranges, and strand) are located on the left-hand side and the metadata columns (annotation) are located on the right. For this example, the metadata is comprised of \Rcode{score} and \Rcode{GC} information, but almost anything can be stored in the metadata portion of a \Rclass{GRanges} object. The components of the genomic coordinates within a \Rclass{GRanges} object can be extracted using the \Rcode{seqnames}, \Rcode{ranges}, and \Rcode{strand} accessor functions. %% <>= seqnames(gr) ranges(gr) strand(gr) @ The genomic ranges can be extracted without corresponding metadata with \Rcode{granges} %% <>= granges(gr) @ %% Annotations for these coordinates can be extracted as a \Rclass{DataFrame} object using the \Rcode{mcols} accessor. %% <>= mcols(gr) mcols(gr)$score @ Information about the lengths of the various sequences that the ranges are aligned to can also be stored in the \Rclass{GRanges} object. So if this is data from \textit{Homo sapiens}, we can set the values as: %% <>= seqlengths(gr) <- c(249250621, 243199373, 198022430) @ %% And then retrieves as: <>= seqlengths(gr) @ %% Methods for accessing the \Rcode{length} and \Rcode{names} have also been defined. %% <>= names(gr) length(gr) @ \subsection{Splitting and combining \Rclass{GRanges} objects} \Rclass{GRanges} objects can be devided into groups using the \Rcode{split} method. This produces a \Rclass{GRangesList} object, a class that will be discussed in detail in the next section. %% <>= sp <- split(gr, rep(1:2, each=5)) sp @ %% Separate \Rclass{GRanges} instances can be concatenated by using the \Rcode{c} and \Rcode{append} methods. %% <>= c(sp[[1]], sp[[2]]) @ \subsection{Subsetting \Rclass{GRanges} objects} \Rclass{GRanges} objects act like vectors of ranges, with the expected vector-like subsetting operations available %% <>= gr[2:3] @ %% A second argument to the \Rcode{[} subset operator can be used to specify which metadata columns to extract from the \Rclass{GRanges} object. For example, %% <>= gr[2:3, "GC"] @ Elements can also be assigned to the \Rclass{GRanges} object. Here is an example where the second row of a \Rclass{GRanges} object is replaced with the first row of \Robject{gr}. %% <>= singles <- split(gr, names(gr)) grMod <- gr grMod[2] <- singles[[1]] head(grMod, n=3) @ %% Here is a second example where the metadata for score from the third element is replaced with the score from the second row etc. %% <>= grMod[2,1] <- singles[[3]][,1] head(grMod, n=3) @ There are methods to repeat, reverse, or select specific portions of \Rclass{GRanges} objects. %% <>= rep(singles[[2]], times = 3) rev(gr) head(gr,n=2) tail(gr,n=2) window(gr, start=2,end=4) gr[IRanges(start=c(2,7), end=c(3,9))] @ \subsection{Basic interval operations for \Rclass{GRanges} objects} Basic interval characteristics of \Rclass{GRanges} objects can be extracted using the \Rcode{start}, \Rcode{end}, \Rcode{width}, and \Rcode{range} methods. %% <>= g <- gr[1:3] g <- append(g, singles[[10]]) start(g) end(g) width(g) range(g) @ The \Rclass{GRanges} class also has many methods for manipulating the ranges. The methods can be classified as \emph{intra-range methods}, \emph{inter-range methods}, and \emph{between-range methods}. \emph{Intra-range methods} operate on each element of a \Rclass{GRanges} object independent of the other ranges in the object. For example, the \Rcode{flank} method can be used to recover regions flanking the set of ranges represented by the \Rclass{GRanges} object. So to get a \Rclass{GRanges} object containing the ranges that include the 10 bases upstream of the ranges: %% <>= flank(g, 10) @ %% And to include the downstream bases: %% <>= flank(g, 10, start=FALSE) @ %% Other examples of intra-range methods include \Rcode{resize} and \Rcode{shift}. The \Rcode{shift} method will move the ranges by a specific number of base pairs, and the \Rcode{resize} method will extend the ranges by a specified width. %% <>= shift(g, 5) resize(g, 30) @ %% The \Biocpkg{GenomicRanges} help page \Rcode{?"intra-range-methods"} summarizes these methods. \emph{Inter-range methods} involve comparisons between ranges in a single \Rclass{GRanges} object. For instance, the \Rcode{reduce} method will align the ranges and merge overlapping ranges to produce a simplified set. %% <>= reduce(g) @ %% Sometimes one is interested in the gaps or the qualities of the gaps between the ranges represented by your \Rclass{GRanges} object. The \Rcode{gaps} method provides this information: reduced version of your ranges: %% <>= gaps(g) @ %% The \Rcode{disjoin} method represents a \Rclass{GRanges} object as a collection of non-overlapping ranges: %% <>= disjoin(g) @ %% The \Rcode{coverage} method quantifies the degree of overlap for all the ranges in a \Rclass{GRanges} object. %% <>= coverage(g) @ %% See the \Biocpkg{GenomicRanges} help page \Rcode{?"inter-range-methods"} for additional help. \emph{Between-range methods} involve operations between two \Rclass{GRanges} objects; some of these are summarized in the next section. \subsection{Interval set operations for \Rclass{GRanges} objects} \emph{Between-range methods} calculate relationships between different \Rclass{GRanges} objects. Of central importance are \Rcode{findOverlaps} and related operations; these are discussed below. Additional operations treat \Rclass{GRanges} as mathematical sets of coordinates; \Rcode{union(g, g2)} is the union of the coordinates in \Rcode{g} and \Rcode{g2}. Here are examples for calculating the \Rcode{union}, the \Rcode{intersect} and the asymmetric difference (using \Rcode{setdiff}). %% <>= g2 <- head(gr, n=2) union(g, g2) intersect(g, g2) setdiff(g, g2) @ Related methods are available when the structure of the \Rclass{GRanges} objects are 'parallel' to one another, i.e., element 1 of object 1 is related to element 1 of object 2, and so on. These operations all begin with a \Rcode{p}, which is short for parallel. The methods then perform element-wise, e.g., the union of element 1 of object 1 with element 1 of object 2, etc. A requirement for these operations is that the number of elements in each \Rclass{GRanges} object is the same, and that both of the objects have the same seqnames and strand assignments throughout. %% <>= g3 <- g[1:2] ranges(g3[1]) <- IRanges(start=105, end=112) punion(g2, g3) pintersect(g2, g3) psetdiff(g2, g3) @ For more information on the \Rcode{GRanges} classes be sure to consult the manual page. %% <>= ?GRanges @ %% A relatively comprehensive list of available methods is discovered with %% <>= methods(class="GRanges") @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{\Rclass{GRangesList}: Groups of Genomic Ranges} Some important genomic features, such as spliced transcripts that are are comprised of exons, are inherently compound structures. Such a feature makes much more sense when expressed as a compound object such as a \Rclass{GRangesList}. Whenever genomic features consist of multiple ranges that are grouped by a parent feature, they can be represented as a \Rclass{GRangesList} object. Consider the simple example of the two transcript \Rfunction{GRangesList} below created using the \Rfunction{GRangesList} constructor. %% <>= gr1 <- GRanges( seqnames = "chr2", ranges = IRanges(103, 106), strand = "+", score = 5L, GC = 0.45) gr2 <- GRanges( seqnames = c("chr1", "chr1"), ranges = IRanges(c(107, 113), width = 3), strand = c("+", "-"), score = 3:4, GC = c(0.3, 0.5)) grl <- GRangesList("txA" = gr1, "txB" = gr2) grl @ The \Rcode{show} method for a \Rclass{GRangesList} object displays it as a named list of \Rclass{GRanges} objects, where the names of this list are considered to be the names of the grouping feature. In the example above, the groups of individual exon ranges are represented as separate \Rclass{GRanges} objects which are further organized into a list structure where each element name is a transcript name. Many other combinations of grouped and labeled \Rclass{GRanges} objects are possible of course, but this example is expected to be a common arrangement. \subsection{Basic \Rclass{GRangesList} accessors} Just as with \Rclass{GRanges} object, the components of the genomic coordinates within a \Rclass{GRangesList} object can be extracted using simple accessor methods. Not surprisingly, the \Rclass{GRangesList} objects have many of the same accessors as \Rclass{GRanges} objects. The difference is that many of these methods return a list since the input is now essentially a list of \Rclass{GRanges} objects. Here are a few examples: %% <>= seqnames(grl) ranges(grl) strand(grl) @ %% The \Rcode{length} and \Rcode{names} methods will return the length or names of the list and the \Rcode{seqlengths} method will return the set of sequence lengths. %% <>= length(grl) names(grl) seqlengths(grl) @ The \Rcode{elementNROWS} method returns a list of integers corresponding to the result of calling \Rcode{NROW} on each individual \Rclass{GRanges} object contained by the \Rclass{GRangesList}. This is a faster alternative to calling \Rcode{lapply} on the \Rclass{GRangesList}. %% <>= elementNROWS(grl) @ %% \Rcode{isEmpty} tests if a \Rclass{GRangesList} object contains anything. %% <>= isEmpty(grl) @ In the context of a \Rclass{GRangesList} object, the \Rcode{mcols} method performs a similar operation to what it does on a \Rclass{GRanges} object. However, this metadata now refers to information at the list level instead of the level of the individual \Rclass{GRanges} objects. %% <>= mcols(grl) <- c("Transcript A","Transcript B") mcols(grl) @ %% Element-level metadata can be retrieved by unlisting the \Robject{GRangesList}, and extracting the metadata %% <>= mcols(unlist(grl)) @ \subsection{Combining \Rclass{GRangesList} objects} \Rclass{GRangesList} objects can be unlisted to combine the separate \Rclass{GRanges} objects that they contain as an expanded \Rclass{GRanges}. <>= ul <- unlist(grl) ul @ Append lists using \Rcode{append} or \Rcode{c}. A \href{https://support.bioconductor.org/p/89339/}{support site user} had two \Rclass{GRangesList} objects with 'parallel' elements, and wanted to combined these element-wise into a single \Rclass{GRangesList}. One solution is to use \Rcode{pc()} -- parallel (element-wise) \Rcode{c()}. A more general solution is to concatenate the lists and then re-group by some factor, in this case the names of the elements. <>= grl1 <- GRangesList( gr1 = GRanges("chr2", IRanges(3, 6)), gr2 = GRanges("chr1", IRanges(c(7,13), width = 3))) grl2 <- GRangesList( gr1 = GRanges("chr2", IRanges(9, 12)), gr2 = GRanges("chr1", IRanges(c(25,38), width = 3))) pc(grl1, grl2) grl3 <- c(grl1, grl2) regroup(grl3, names(grl3)) @ \subsection{Basic interval operations for \Rclass{GRangesList} objects} For interval operations, many of the same methods exist for \Rclass{GRangesList} objects that exist for \Rclass{GRanges} objects. %% <>= start(grl) end(grl) width(grl) @ %% These operations return a data structure representing, e.g., \Rclass{IntegerList}, a list where all elements are integers; it can be convenient to use mathematical and other operations on \Rclass{*List} objects that work on each element, e.g., %% <>= sum(width(grl)) # sum of widths of each grl element @ %% Most of the intra-, inter- and between-range methods operate on \Rclass{GRangesList} objects, e.g., to shift all the \Rclass{GRanges} objects in a \Rclass{GRangesList} object, or calculate the coverage. Both of these operations are also carried out across each \Rclass{GRanges} list member. %% <>= shift(grl, 20) coverage(grl) @ \subsection{Subsetting \Rclass{GRangesList} objects} A \Rclass{GRangesList} object is behaves like a \Rcode{list}: \Rcode{[} returns a \Rclass{GRangesList} containing a subset of the original object; \Rcode{[[} or \Rcode{\$} returns the \Rclass{GRanges} object at that location in the list. %% <>= grl[1] grl[[1]] grl["txA"] grl$txB @ %% In addition, subsetting a \Rclass{GRangesList} also accepts a second parameter to specify which of the metadata columns you wish to select. %% <>= grl[1, "score"] grl["txB", "GC"] @ The \Rcode{head}, \Rcode{tail}, \Rcode{rep}, \Rcode{rev}, and \Rcode{window} methods all behave as you would expect them to for a list object. For example, the elements referred to by \Rcode{window} are now list elements instead of \Rclass{GRanges} elements. %% <>= rep(grl[[1]], times = 3) rev(grl) head(grl, n=1) tail(grl, n=1) window(grl, start=1, end=1) grl[IRanges(start=2, end=2)] @ \subsection{Looping over \Rclass{GRangesList} objects} For \Rclass{GRangesList} objects there is also a family of \Rcode{apply} methods. These include \Rcode{lapply}, \Rcode{sapply}, \Rcode{mapply}, \Rcode{endoapply}, \Rcode{mendoapply}, \Rcode{Map}, and \Rcode{Reduce}. The different looping methods defined for \Rclass{GRangesList} objects are useful for returning different kinds of results. The standard \Rcode{lapply} and \Rcode{sapply} behave according to convention, with the \Rcode{lapply} method returning a list and \Rcode{sapply} returning a more simplified output. %% <>= lapply(grl, length) sapply(grl, length) @ %% As with \Rclass{IRanges} objects, there is also a multivariate version of \Rcode{sapply}, called \Rcode{mapply}, defined for \Rclass{GRangesList} objects. And, if you don't want the results simplified, you can call the \Rcode{Map} method, which does the same things as \Rcode{mapply} but without simplifying the output. %% <>= grl2 <- shift(grl, 10) names(grl2) <- c("shiftTxA", "shiftTxB") mapply(c, grl, grl2) Map(c, grl, grl2) @ Sometimes you will want to get back a modified version of the \Rclass{GRangesList} that you originally passed in. An endomorphism is a transformation of an object to another instance of the same class . This is achieved using the \Rcode{endoapply} method, which will return the results as a \Rclass{GRangesList} object. %% <>= endoapply(grl, rev) mendoapply(c, grl, grl2) @ %% The \Rcode{Reduce} method will allow the \Rclass{GRanges} objects to be collapsed across the whole of the \Rclass{GRangesList} object. % Again, this seems like a sub-optimal example to me. <>= Reduce(c, grl) @ Explicit element-wise operations (\Rcode{lapply()} and friends) on \Rclass{GRangesList} objects with many elements can be slow. It is therefore beneficial to explore operations that work on \Rcode{*List} objects directly (e.g., many of the `group generic' operators, see \Rcode{?S4groupGeneric}, and the set and parallel set operators (e.g., \Rcode{union}, \Rcode{punion}). A useful and fast strategy is to \Rcode{unlist} the \Rclass{GRangesList} to a \Rclass{GRanges} object, operate on the \Rclass{GRanges} object, then \Rcode{relist} the result, e.g., %% <>= gr <- unlist(grl) gr$log_score <- log(gr$score) grl <- relist(gr, grl) grl @ %% See also \Rcode{?extractList}. For more information on the \Rcode{GRangesList} classes be sure to consult the manual page and available methods %% <>= ?GRangesList methods(class="GRangesList") # _partial_ list @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Interval overlaps involving \Rclass{GRanges} and \Rclass{GRangesList} objects} Interval overlapping is the process of comparing the ranges in two objects to determine if and when they overlap. As such, it is perhaps the most common operation performed on \Rclass{GRanges} and \Rclass{GRangesList} objects. To this end, the \Biocpkg{GenomicRanges} package provides a family of interval overlap functions. The most general of these functions is \Rfunction{findOverlaps}, which takes a query and a subject as inputs and returns a \Rclass{Hits} object containing the index pairings for the overlapping elements. <>= mtch <- findOverlaps(gr, grl) as.matrix(mtch) @ \noindent As suggested in the sections discussing the nature of the \Rclass{GRanges} and \Rclass{GRangesList} classes, the index in the above matrix of hits for a \Rclass{GRanges} object is a single range while for a \Rclass{GRangesList} object it is the set of ranges that define a "feature". Another function in the overlaps family is \Rfunction{countOverlaps}, which tabulates the number of overlaps for each element in the query. <>= countOverlaps(gr, grl) @ A third function in this family is \Rfunction{subsetByOverlaps}, which extracts the elements in the query that overlap at least one element in the subject. <>= subsetByOverlaps(gr,grl) @ Finally, you can use the \Rcode{select} argument to get the index of the first overlapping element in the subject for each element in the query. <>= findOverlaps(gr, grl, select="first") findOverlaps(grl, gr, select="first") @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Session Information} All of the output in this vignette was produced under the following conditions: \begin{small} <>= sessionInfo() @ \end{small} \end{document} GenomicRanges/vignettes/Ten_things_slides.Rnw0000644000175400017540000002153213175713746022507 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{4. Ten Things You Didn't Know (slides from BioC 2016)} %\VignetteDepends{GenomicRanges, Biostrings, Rsamtools, BSgenome, hgu95av2probe} \SweaveOpts{keep.source=TRUE, eps=FALSE, width=9, height=3} \documentclass[9pt]{beamer} \usepackage{slides} \renewcommand\Rclass[1]{{\texttt{#1}\index{#1 (class)}}} \title{10 things (maybe) you didn't know about GenomicRanges, Biostrings, and Rsamtools} \author{Herv\'e Pag\`es\\ \href{mailto:hpages@fredhutch.org}{hpages@fredhutch.org}} \date{June 2016} \begin{document} <>= options(width=80) library(GenomicRanges) library(Biostrings) library(Rsamtools) library(BSgenome) library(hgu95av2probe) example(GRangesList) gr <- GRanges(Rle(c("chr2", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), IRanges(1:10, width=10:1, names=head(letters, 10)), Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score=1:10, GC=seq(1, 0, length=10)) ir <- IRanges(c(11:13, 2, 7:6), width=3) mcols(ir) <- DataFrame(id=letters[1:6], score=3:-2) x <- GRanges(c("chr1:1-1000", "chr2:2000-3000"), score=c(0.45, 0.1), a1=c(5L, 7L), a2=c(6, 8)) mcols(x)$score[2] <- NA y <- GRanges(c("chr2:150-151", "chr1:1-10", "chr2:2000-3000"), score=c(0.7, 0.82, 0.1), b1=c(0L, 5L, 1L), b2=c(1, -2, 1)) @ \maketitle %\frame{\tableofcontents} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{1. {\it Inner} vs {\it outer} metadata columns} \begin{exampleblock}{} {\small <>= mcols(grl)$id <- paste0("ID", seq_along(grl)) grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{1. {\it Inner} vs {\it outer} metadata columns} \begin{exampleblock}{} {\small <>= mcols(grl) # outer mcols mcols(unlist(grl, use.names=FALSE)) # inner mcols @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{2. invertStrand()} Works out-of-the-box on any object that has a strand() getter and setter ==> no need to implement specific methods. \begin{exampleblock}{} {\small <<>>= gr @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{2. invertStrand()} \begin{exampleblock}{} {\small <<>>= invertStrand(gr) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{2. invertStrand()} \begin{exampleblock}{} {\small <<>>= grl @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{2. invertStrand()} \begin{exampleblock}{} {\small <<>>= invertStrand(grl) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{3. extractList()} Extract groups of elements from a vector-like object and return them in a list-like object. \begin{exampleblock}{} <<>>= cvg <- Rle(c(0L, 2L, 5L, 1L, 0L), c(10, 6, 3, 4, 15)) cvg i <- IRanges(c(16, 19, 9), width=5, names=letters[1:3]) i @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{3. extractList()} \begin{exampleblock}{} <<>>= extractList(cvg, i) @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{3. extractList()} \begin{exampleblock}{} \Rcode{i} can be an IntegerList object: {\small <<>>= i <- IntegerList(c(25:20), NULL, seq(from=2, to=length(cvg), by=2)) i extractList(cvg, i) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{4. 'with.revmap' arg for reduce() and (now) disjoin()} \begin{exampleblock}{} <<>>= ir ir2 <- reduce(ir, with.revmap=TRUE) ir2 @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{4. 'with.revmap' arg for reduce() and disjoin()} \begin{exampleblock}{} {\small <<>>= revmap <- mcols(ir2)$revmap extractList(mcols(ir)$id, revmap) extractList(mcols(ir)$score, revmap) mcols(ir2) <- DataFrame(id=extractList(mcols(ir)$id, revmap), score=extractList(mcols(ir)$score, revmap)) ir2 @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{5. Zero-width ranges} \Rcode{findOverlaps}/\Rcode{countOverlaps} support zero-width ranges. \begin{exampleblock}{} {\small <<>>= sliding_query <- IRanges(1:6, width=0) sliding_query countOverlaps(sliding_query, IRanges(3, 4)) @ } \end{exampleblock} But you have to specify \Rcode{minoverlap=0} for this to work (default is 1). \begin{exampleblock}{} {\small <<>>= countOverlaps(sliding_query, IRanges(3, 4), minoverlap=0) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} Perform multiple substitutions at arbitrary positions in a set of sequences. \begin{exampleblock}{} <<>>= library(Biostrings) library(hgu95av2probe) probes <- DNAStringSet(hgu95av2probe) probes @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} Replace 3rd and 4th nucleotides by pattern \Rcode{-++-}. \begin{exampleblock}{} <<>>= replaceAt(probes, at=IRanges(3, 4), value="-++-") @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} If supplied pattern is empty, then performs deletions. \begin{exampleblock}{} <<>>= replaceAt(probes, at=IRanges(3, 4), value="") @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} If \Rcode{at} is a zero-with range, then performs insertions. \begin{exampleblock}{} <<>>= replaceAt(probes, at=IRanges(4, 3), value="-++-") @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{6. Biostrings::replaceAt()} Use it in combination with \Rcode{vmatchPattern} to replace all the occurences of a given pattern with another pattern: \begin{exampleblock}{} <<>>= midx <- vmatchPattern("VCGTT", probes, fixed=FALSE) replaceAt(probes, at=midx, value="-++-") @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{7. GRanges as a subscript} \begin{exampleblock}{} {\small <>= cvg <- RleList(chr1=101:120, chr2=2:-8, chr3=31:40) gr @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{7. GRanges as a subscript} \begin{exampleblock}{} {\scriptsize <>= cvg[gr] @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{8. BSgenomeViews objects} \begin{exampleblock}{} <<>>= library(BSgenome.Mmusculus.UCSC.mm10) genome <- BSgenome.Mmusculus.UCSC.mm10 library(TxDb.Mmusculus.UCSC.mm10.knownGene) txdb <- TxDb.Mmusculus.UCSC.mm10.knownGene ex <- exons(txdb, columns=c("exon_id", "tx_name", "gene_id")) v <- Views(genome, ex) @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{8. BSgenomeViews objects} \begin{exampleblock}{} {\scriptsize <<>>= v @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{8. BSgenomeViews objects} \begin{exampleblock}{} <<>>= af <- alphabetFrequency(v, baseOnly=TRUE) head(af) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{9. Pile-up statistics on a BAM file with Rsamtools::pileup()} \begin{exampleblock}{} <<>>= library(Rsamtools) library(RNAseqData.HNRNPC.bam.chr14) fl <- RNAseqData.HNRNPC.bam.chr14_BAMFILES[1] sbp <- ScanBamParam(which=GRanges("chr14", IRanges(1, 53674770))) pp <- PileupParam(distinguish_nucleotides=FALSE, distinguish_strands=FALSE, min_mapq=13, min_base_quality=10, min_nucleotide_depth=4) res <- pileup(fl, scanBamParam=sbp, pileupParam=pp) @ \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{9. Pile-up statistics on a BAM file with Rsamtools::pileup()} \begin{exampleblock}{} <<>>= dim(res) head(res) @ \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{10. Merging 2 GRanges objects (added this week)} \begin{exampleblock}{} {\small <<>>= x y @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{10. Merging 2 GRanges objects} \begin{exampleblock}{} {\small <<>>= merge(x, y) @ } \end{exampleblock} \end{frame} \begin{frame}[fragile] \frametitle{10. Merging 2 GRanges objects} \begin{exampleblock}{} {\small <<>>= merge(x, y, all=TRUE) @ } \end{exampleblock} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document} GenomicRanges/vignettes/slides.sty0000644000175400017540000000211313175713746020370 0ustar00biocbuildbiocbuild\usepackage{Sweave} \usepackage{color, graphics} \usepackage{latexsym, amsmath, amssymb} %% simple macros \newcommand{\software}[1]{\textsl{#1}} \newcommand\R{\textsl{R}} \newcommand\Bioconductor{\textsl{Bioconductor}} \newcommand\Rpackage[1]{{\textsl{#1}\index{#1 (package)}}} \newcommand\Biocpkg[1]{% {\href{http://bioconductor.org/packages/release/bioc/html/#1.html}% {\textsl{#1}}}% \index{#1 (package)}} \newcommand\Rpkg[1]{% {\href{http://cran.fhcrc.org/web/packages/#1/index.html}% {\textsl{#1}}}% \index{#1 (package)}} \newcommand\Biocdatapkg[1]{% {\href{http://bioconductor.org/packages/release/data/experiment/html/#1.html}% {\textsl{#1}}}% \index{#1 (package)}} \newcommand\Robject[1]{{\small\texttt{#1}}} \newcommand\Rclass[1]{{\textit{#1}\index{#1 (class)}}} \newcommand\Rfunction[1]{{{\small\texttt{#1}}\index{#1 (function)}}} \newcommand\Rmethod[1]{{\texttt{#1}}} \newcommand\Rfunarg[1]{{\small\texttt{#1}}} \newcommand\Rcode[1]{{\small\texttt{#1}}} %% \AtBeginSection[] %% { %% \begin{frame}{Outline} %% \tableofcontents %% \end{frame} %% }