GenomicRanges/DESCRIPTION0000644000175100017510000000523112607330121016015 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.22.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, BiocGenerics (>= 0.15.3), S4Vectors (>= 0.7.18), IRanges (>= 2.3.24), GenomeInfoDb (>= 1.1.20) 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), GenomicAlignments, rtracklayer, BSgenome, GenomicFeatures, Gviz, VariantAnnotation, AnnotationHub, DESeq, 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 License: Artistic-2.0 Collate: utils.R phicoef.R transcript-utils.R constraint.R strand-utils.R range-squeezers.R GenomicRanges-class.R GRanges-class.R DelegatingGenomicRanges-class.R GNCList-class.R GIntervalTree-class.R GenomicRanges-comparison.R GenomicRangesList-class.R GRangesList-class.R makeGRangesFromDataFrame.R SummarizedExperiment-class.R SummarizedExperiment-rowData-methods.R RangedData-methods.R intra-range-methods.R inter-range-methods.R coverage-methods.R setops-methods.R findOverlaps-methods.R findOverlaps-GIntervalTree-methods.R nearest-methods.R mapCoords-methods.R absoluteRanges.R tileGenome.R tile-methods.R genomicvars.R test_GenomicRanges_package.R zzz.R NeedsCompilation: yes Packaged: 2015-10-14 01:30:57 UTC; biocbuild GenomicRanges/NAMESPACE0000644000175100017510000000744212607265136015551 0ustar00biocbuildbiocbuilduseDynLib(GenomicRanges) import(methods) import(utils) # for as.roman() importFrom(stats, setNames) 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, ConstraintORNULL, GenomicRanges, GenomicRangesORmissing, GRanges, DelegatingGenomicRanges, GNCList, GIntervalTree, GenomicRangesORGRangesList, GRangesList, SummarizedExperiment, Assays, ShallowData, ShallowSimpleListAssays, GenomicRangesList, SimpleGenomicRangesList ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S3 methods ### S3method(duplicated, GenomicRanges) S3method(sort, 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 ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S4 methods for generics not defined in GenomicRanges ### exportMethods( length, names, "names<-", "dimnames<-", "[", "[<-", "[[", "[[<-", "$", "$<-", as.character, as.factor, as.data.frame, coerce, c, cbind, rbind, show, duplicated, match, order, sort, rank, union, intersect, setdiff, start, "start<-", end, "end<-", width, "width<-", split, unlist, range, Ops, merge, updateObject, strand, "strand<-", ## Generics defined in IRanges: elementMetadata, "elementMetadata<-", mcols, "mcols<-", values, "values<-", relistToClass, compare, ranges, "ranges<-", ngap, score, "score<-", shift, narrow, resize, flank, promoters, restrict, trim, reduce, gaps, disjoin, isDisjoint, disjointBins, coverage, punion, pintersect, psetdiff, pgap, findOverlaps, countOverlaps, overlapsAny, subsetByOverlaps, precede, follow, nearest, distance, distanceToNearest, mapCoords, pmapCoords, tile, subset, subjectHits, queryHits, ## Generics defined in GenomeInfoDb: seqinfo, "seqinfo<-", seqnames, "seqnames<-" ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export non-generic functions ### export( phicoef, GRanges, .DollarNames.GenomicRanges, GNCList, GIntervalTree, GenomicRangesList, GRangesList, makeGRangesFromDataFrame, makeGRangesListFromFeatureFragments, isSmallGenome, absoluteRanges, relativeRanges, tileGenome, bindAsGRanges, mcolAsRleList, binnedAverage, rowData, "rowData<-", .DollarNames.SummarizedExperiment ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Export S4 generics defined in GenomicRanges + export corresponding ### methods ### export( ## constraint.R: #constraint, "constraint<-", checkConstraint, ## range-squeezers.R: granges, grglist, rglist, ## SummarizedExperiment-class.R: SummarizedExperiment, exptData, "exptData<-", rowRanges, "rowRanges<-", colData, "colData<-", assays, "assays<-", assay, "assay<-", assayNames, "assayNames<-" ) ### Exactly the same list as above. exportMethods( #constraint, "constraint<-", checkConstraint, granges, grglist, rglist, SummarizedExperiment, exptData, "exptData<-", rowRanges, "rowRanges<-", colData, "colData<-", assays, "assays<-", assay, "assay<-", assayNames, "assayNames<-" ) GenomicRanges/NEWS0000644000175100017510000007522712607265136015037 0ustar00biocbuildbiocbuildCHANGES 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/0000755000175100017510000000000012607265137014525 5ustar00biocbuildbiocbuildGenomicRanges/R/DelegatingGenomicRanges-class.R0000644000175100017510000000201012607265136022450 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/GIntervalTree-class.R0000644000175100017510000001140212607265136020463 0ustar00biocbuildbiocbuild#' GIntervalTree class #' #' Defines persistent interval trees for GRanges objects. #' #' #' @name GIntervalTree-class #' @family GIntervalTree #' #' @exportClass GIntervalTree #' @import GenomicRanges #' @import BiocGenerics setClass("GIntervalTree", contains="GenomicRanges", representation( ranges="IntervalForest", rngidx="IRanges", strand="Rle", elementMetadata="DataFrame", seqinfo="Seqinfo"), prototype( strand=Rle(strand())) ) .valid.GIntervalTree.rngidx <- function(x) { x_len <- length(x) if (sum(width(x@rngidx)) != x_len) return("ivalid 'rngidx' slot") NULL } .valid.GIntervalTree.ranges <- function(x) { if (class(x@ranges) != "IntervalForest") return("'x@ranges' must be an IntervalForest instance") if (nobj(x@ranges@partitioning) != length(x)) return("'nobj(x@ranges@partitioning)' must equal 'length(x)'") NULL } .valid.GIntervalTree <- function(x) { c(.valid.GIntervalTree.ranges(x), .valid.GIntervalTree.rngidx(x)) } setValidity2("GIntervalTree", .valid.GIntervalTree) .GT_getIndex <- function(from) { fvals <- as.integer(runValue(seqnames(from))) if (S4Vectors:::isNotSorted(fvals)) { flens <- runLength(seqnames(from)) idx <- S4Vectors:::orderInteger(fvals) rngidx <- successiveIRanges(flens)[idx] idx <- S4Vectors:::orderInteger(start(rngidx)) return(IRanges(end=cumsum(width(rngidx))[idx], width=width(rngidx)[idx])) } IRanges() } .GT_reorderValue <- function(obj, val, rngidx=NULL) { if (!is(obj, "GIntervalTree") && is.null(rngidx)) stop("obj must be 'GIntervalTree' object") if (is.null(rngidx)) rngidx <- obj@rngidx if (length(rngidx)) val <- extractROWS(val, rngidx) val } #' seqnames accessor #' #' #' @rdname GIntervalTree-class #' @family GIntervalTree #' @export #' @importMethodsFrom GenomicRanges seqnames setMethod("seqnames", "GIntervalTree", function(x) Rle(.GT_reorderValue(x, space(x@ranges)))) #' ranges accessor #' #' @rdname GIntervalTree-class #' @family GIntervalTree #' @export #' @importMethodsFrom GenomicRanges ranges setMethod("ranges", "GIntervalTree", function(x) .GT_reorderValue(x, as(x@ranges, "IRanges"))) #' strand accessor #' #' @rdname GIntervalTree-class #' @family GIntervalTree #' @export #' @importMethodsFrom GenomicRanges strand setMethod("strand", "GIntervalTree", function(x) x@strand) #' seqinfo accessor #' #' @rdname GIntervalTree-class #' @family GIntervalTree #' @export #' @importMethodsFrom GenomicRanges seqinfo setMethod("seqinfo", "GIntervalTree", function(x) x@seqinfo) setMethod("start", "GIntervalTree", function(x, ...) .GT_reorderValue(x,start(x@ranges, ...)@unlistData)) setMethod("end", "GIntervalTree", function(x, ...) .GT_reorderValue(x, end(x@ranges, ...)@unlistData)) setMethod("width", "GIntervalTree", function(x) .GT_reorderValue(x, width(x@ranges)@unlistData)) #' construct from GRanges object via coercion #' #' @name as #' @family GIntervalTree #' @importClassesFrom GenomicRanges GRanges setAs("GRanges", "GIntervalTree", function(from) { msg <- c("GIntervalTree objects and the \"intervaltree\" algorithm ", "used in findOverlaps() and family are defunct. Please ", "use GNCList objects or the \"nclist\" algorithm instead. ", "See ?GNCList and the 'algorithm' argument in ?findOverlaps ", "for more information.") .Defunct(msg=wmsg(msg)) if (any(isCircular(from), na.rm=TRUE)) stop("'GIntervalTree' objects not supported for circular sequences") rl <- split(unname(ranges(from)), seqnames(from)) new2("GIntervalTree", strand=strand(from), elementMetadata=mcols(from), seqinfo=seqinfo(from), ranges=IntervalForest(rl), rngidx=.GT_getIndex(from), check=FALSE) } ) #' constructor function using GRanges object #' #' @family GIntervalTree #' @export GIntervalTree <- function(x) { as(x, "GIntervalTree") } #' coercion from GIntervalTree to GRanges object #' #' @family GIntervalTree #' @name as #' @importClassesFrom GenomicRanges GRanges setAs("GIntervalTree", "GRanges", function(from) { out=new("GRanges", seqnames=seqnames(from), strand=strand(from), elementMetadata=mcols(from), seqinfo=seqinfo(from), ranges=ranges(from)) out } ) #' subsetting #' #' @family GIntervalTree #' @rdname GIntervalTree-class #' @export setMethod("[", "GIntervalTree", function(x, i, j, ...) { gr <- callGeneric(as(x, "GRanges"),i=i, ...) as(gr, "GIntervalTree") }) GenomicRanges/R/GNCList-class.R0000644000175100017510000001216612607265137017224 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.mcols=FALSE) { if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") ans <- x@granges 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.mcols=FALSE) ranges(granges(x))) 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, min.score=1L, 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") if (!isSingleNumber(min.score)) stop("'min.score' must be a single integer") if (!is.integer(min.score)) min.score <- as.integer(min.score) 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, min.score, type, select, circle_length) } GenomicRanges/R/GRanges-class.R0000644000175100017510000002371512607265137017311 0ustar00biocbuildbiocbuild### ========================================================================= ### GRanges objects ### ------------------------------------------------------------------------- ### setClass("GRanges", contains="GenomicRanges", representation( seqnames="Rle", ranges="IRanges", strand="Rle", elementMetadata="DataFrame", seqinfo="Seqinfo" ), prototype( seqnames=Rle(factor()), strand=Rle(strand()) ) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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. ### ### Hidden constructor shared with other GRanges-like objects. newGRanges <- function(class, seqnames=Rle(), ranges=NULL, strand=NULL, mcols=DataFrame(), seqlengths=NULL, seqinfo=NULL) { if (is.null(ranges)) { if (length(seqnames) != 0L) { ans <- as(seqnames, class) ans_seqnames <- seqnames(ans) ans_ranges <- ranges(ans) if (is.null(strand)) { ans_strand <- strand(ans) } else { ans_strand <- strand } if (ncol(mcols) == 0L) { ans_mcols <- mcols(ans) } else { ans_mcols <- mcols } if (is.null(seqlengths)) { ans_seqlengths <- seqlengths(ans) } else { ans_seqlengths <- seqlengths } if (is.null(seqinfo)) { ans_seqinfo <- seqinfo(ans) } else { ans_seqinfo <- seqinfo } ans <- newGRanges(class, ans_seqnames, ans_ranges, ans_strand, ans_mcols, ans_seqlengths, ans_seqinfo) return(ans) } ranges <- IRanges() } else if (class(ranges) != "IRanges") { ranges <- as(ranges, "IRanges") } 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)) if (!is(mcols, "DataFrame")) # should never happen when calling GRanges() stop("'mcols' must be a DataFrame object") if (ncol(mcols) == 0L) { mcols <- mcols(ranges) if (is.null(mcols)) mcols <- new("DataFrame", nrows=length(seqnames)) } if (!is.null(mcols(ranges))) mcols(ranges) <- NULL 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, seqinfo = seqinfo, elementMetadata = mcols) } GRanges <- function(seqnames=Rle(), ranges=NULL, strand=NULL, ..., seqlengths=NULL, seqinfo=NULL) { newGRanges("GRanges", seqnames=seqnames, ranges=ranges, strand=strand, mcols=DataFrame(..., check.names=FALSE), 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 } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion. ### .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 \"chr1:2501-2800\" or \"chr1:2501-2800:+\" ", "(\"..\" being also supported as a separator between the start and ", "end positions). Strand can be \"+\", \"-\", \"*\", or missing." ) split0 <- CharacterList(strsplit(from, ":", fixed=TRUE)) split0_eltlens <- elementLengths(split0) if (S4Vectors:::anyMissingOrOutside(split0_eltlens, 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 <- as.character(ptail(split1, n=-1L)) ## We want to split on the first occurence of "-" that is preceeded by ## a digit (ignoring and removing the spaces in between if any). ranges <- sub("([[:digit:]])[[:space:]]*-", "\\1..", ranges) split2 <- CharacterList(strsplit(ranges, "..", fixed=TRUE)) split2_eltlens <- elementLengths(split2) if (!all(split2_eltlens == 2L)) stop(error_msg) ans_start <- as.integer(phead(split2, n=1L)) ans_end <- as.integer(ptail(split2, n=1L)) ans_ranges <- IRanges(ans_start, ans_end, names=names(from)) GRanges(ans_seqnames, ans_ranges, ans_strand) } setAs("character", "GRanges", .from_character_to_GRanges) setAs("character", "GenomicRanges", .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) setAs("factor", "GenomicRanges", .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 } ) setAs("Seqinfo", "GRanges", .fromSeqinfoToGRanges) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Slot getters and setters. ### setMethod("seqnames", "GRanges", function(x) x@seqnames) setMethod("ranges", "GRanges", function(x, use.mcols=FALSE) { if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") ans <- x@ranges if (use.mcols) mcols(ans) <- mcols(x) ans } ) setMethod("strand", "GRanges", function(x) x@strand) setMethod("seqinfo", "GRanges", function(x) x@seqinfo) GenomicRanges/R/GRangesList-class.R0000644000175100017510000005216612607265136020146 0ustar00biocbuildbiocbuild### ========================================================================= ### GRangesList objects ### ------------------------------------------------------------------------- ### setClass("GRangesList", contains=c("CompressedList", "GenomicRangesList"), representation( unlistData="GRanges", elementMetadata="DataFrame" ), prototype( elementType="GRanges" ) ) setClassUnion("GenomicRangesORGRangesList", 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.list(listData[[1L]])) listData <- listData[[1L]] 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, PartitioningByEnd(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 <- elementLengths(fragmentStarts) start <- unlist(fragmentStarts, recursive=FALSE, use.names=FALSE) fragmentEnds <- normargListOfIntegers(fragmentEnds, sep, "fragmentEnds") nend_per_elt <- elementLengths(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 <- elementLengths(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. replaceSeqnamesList <- function(x, value) { if (!is(value, "AtomicList") || !identical(elementLengths(x), elementLengths(value))) stop("replacement 'value' is not an AtomicList with the same ", "elementLengths 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", replaceSeqnamesList) setMethod("ranges", "GRangesList", function(x, use.mcols=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.mcols) mcols(ans) <- mcols(x) ans } ) setReplaceMethod("ranges", "GRangesList", function(x, value) { if (!is(value, "RangesList") || !identical(elementLengths(x), elementLengths(value))) stop("replacement 'value' is not a RangesList with the same ", "elementLengths 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(elementLengths(x), elementLengths(value))) stop("replacement 'value' is not an IntegerList with the same ", "elementLengths 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(elementLengths(x), elementLengths(value))) stop("replacement 'value' is not an IntegerList with the same ", "elementLengths 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(elementLengths(x), elementLengths(value))) stop("replacement 'value' is not an IntegerList with the same ", "elementLengths 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. replaceStrandList <- function(x, value) { if (!is(value, "AtomicList") || !identical(elementLengths(x), elementLengths(value))) stop("replacement 'value' is not an AtomicList with the same ", "elementLengths 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"), replaceStrandList) 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. getElementMetadataList <- 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", getElementMetadataList) ### NOT exported but used in GenomicAlignments package. replaceElementMetadataList <- function(x, level = c("between", "within"), ..., value) { level <- match.arg(level) if (level == "between") { if (is.null(value)) value <- new("DataFrame", nrows = 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 <- new("DataFrame", nrows = length(x@unlistData)) } else { if (!is(value, "SplitDataFrameList") || !identical(elementLengths(x), elementLengths(value))) { stop("replacement 'value' is not a SplitDataFrameList with ", "the same elementLengths as 'x'") } value <- unlist(value, use.names = FALSE) } elementMetadata(x@unlistData) <- value } x } setReplaceMethod("elementMetadata", "GRangesList", replaceElementMetadataList) setMethod("seqinfo", "GRangesList", function(x) seqinfo(x@unlistData)) ### NOT exported but used in GenomicAlignments package. replaceSeqinfoList <- function(x, new2old=NULL, force=FALSE, value) { if (!is(value, "Seqinfo")) stop("the supplied 'seqinfo' must be a Seqinfo object") dangling_seqlevels <- GenomeInfoDb:::getDanglingSeqlevels(x, new2old=new2old, force=force, seqlevels(value)) if (length(dangling_seqlevels) != 0L) { dropme <- which(seqnames(x@unlistData) %in% dangling_seqlevels) x <- x[-unique(togroup(x, j=dropme))] } seqinfo(x@unlistData, new2old=new2old) <- value x } setReplaceMethod("seqinfo", "GRangesList", replaceSeqinfoList) 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("RangedDataList", "GRangesList", function(from) GRangesList(lapply(from, as, "GRanges"))) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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. showList <- function(object, showFunction, print.classinfo) { k <- length(object) cumsumN <- cumsum(elementLengths(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) showList(object, showGenomicRanges, TRUE) ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Deconstruction/reconstruction of a GRangesList 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)), elementLengths(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 <- S4Vectors:::orderIntegerPairs(f1, f2) of1 <- f1[oo] of2 <- f2[oo] ## TODO: Add "presorted" method to S4Vectors:::duplicatedIntegerPairs() ## for when the 2 input vectors are already sorted. notdups <- !S4Vectors:::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) { 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)))) names(ans) <- names(x) metadata(ans) <- metadata(x) mcols(ans) <- mcols(x) ans } GenomicRanges/R/GenomicRanges-class.R0000644000175100017510000007425612607265136020511 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="ConstraintORNULL" ) ) setClassUnion("GenomicRangesORmissing", 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(), ### update(x) and clone(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()) setMethod("parallelVectorNames", "GenomicRanges", function(x) { colnames(as.data.frame(new(class(x)))) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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) } .valid.GenomicRanges.seqnames <- function(x) { if (!is.factor(runValue(seqnames(x)))) return("'seqnames' should be a 'factor' Rle") if (S4Vectors:::anyMissing(runValue(seqnames(x)))) return("'seqnames' contains missing values") NULL } .valid.GenomicRanges.ranges <- function(x) { if (class(ranges(x)) != "IRanges") return("'ranges(x)' must be an IRanges 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), ":", start(x), "-", end(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)))) ) ### TODO: Turn this into an S3/S4 combo for as.data.frame.GenomicRanges 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 } ) .fromSeqinfoToGRanges <- function(from) { if (any(is.na(seqlengths(from)))) stop("cannot create a GenomicRanges from a Seqinfo ", "with NA seqlengths") GRanges(seqnames(from), IRanges(rep(1L, length(from)), width=seqlengths(from), names=seqnames(from)), seqinfo=from) } setAs("Seqinfo", "GenomicRanges", .fromSeqinfoToGRanges) setAs("Seqinfo", "RangesList", function(from) as(as(from, "GenomicRanges"), "RangesList") ) setMethod("granges", "GenomicRanges", function(x, use.mcols=FALSE) { if (!isTRUEorFALSE(use.mcols)) stop("'use.mcols' must be TRUE or FALSE") ans <- GRanges(seqnames(x), ranges(x), strand(x), seqinfo=seqinfo(x)) if (use.mcols) mcols(ans) <- cbind(extraColumnSlotsAsDF(x), mcols(x)) ans } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Setters. ### setReplaceMethod("names", "GenomicRanges", function(x, value) { names(ranges(x)) <- value x } ) setReplaceMethod("seqnames", "GenomicRanges", function(x, value) { 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)'") n <- length(x) k <- length(value) if (k != n) { if ((k == 0L) || (k > n) || (n %% k != 0L)) stop(k, " elements in value to replace ", n, " elements") value <- rep(value, length.out=n) } update(x, seqnames=value) } ) setReplaceMethod("ranges", "GenomicRanges", function(x, value) { if (!is(value, "IRanges")) value <- as(value, "IRanges") n <- length(x) k <- length(value) if (k != n) { if ((k == 0L) || (k > n) || (n %% k != 0L)) stop(k, " elements in value to replace ", n, " elements") value <- rep(value, length.out=n) } update(x, ranges=value, check=FALSE) } ) normargGenomicRangesStrand <- function(strand, n) { if (!is(strand, "Rle")) strand <- Rle(strand) if (!is.factor(runValue(strand)) || !identical(levels(runValue(strand)), levels(strand()))) runValue(strand) <- strand(runValue(strand)) k <- length(strand) if (k != n) { if (k != 1L && (k == 0L || k > n || n %% k != 0L)) stop("supplied 'strand' has ", k, " elements (", n, " expected)") strand <- rep(strand, length.out=n) } strand } setReplaceMethod("strand", "GenomicRanges", function(x, value) { value <- normargGenomicRangesStrand(value, length(x)) x <- update(x, strand=value, check=FALSE) msg <- .valid.GenomicRanges.strand(x) if (!is.null(msg)) stop(msg) x } ) setReplaceMethod("elementMetadata", "GenomicRanges", function(x, ..., value) { value <- normalizeMetadataColumnsReplacementValue(value, x) x <- update(x, elementMetadata=value, check=FALSE) msg <- .valid.GenomicRanges.mcols(x) if (!is.null(msg)) stop(msg) x } ) setReplaceMethod("seqinfo", "GenomicRanges", function(x, new2old=NULL, force=FALSE, value) { if (!is(value, "Seqinfo")) stop("the supplied 'seqinfo' must be a Seqinfo object") dangling_seqlevels <- GenomeInfoDb:::getDanglingSeqlevels(x, new2old=new2old, force=force, seqlevels(value)) if (length(dangling_seqlevels) != 0L) x <- x[!(seqnames(x) %in% dangling_seqlevels)] 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 } ) 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, "ConstraintORNULL")) # 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 } ) setMethod("update", "GenomicRanges", function(object, ...) { BiocGenerics:::replaceSlots(object, ...) }) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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. ### setMethod("extractROWS", "GenomicRanges", 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) clone(x, seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols, .slotList=ans_ecs, check=FALSE) } ) ### 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) } ) setMethod("replaceROWS", "GenomicRanges", 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)]) } update(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("[", "GenomicRanges", 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] } } update(x, seqnames=seqnames, ranges=ranges, strand=strand, elementMetadata=ans_mcols, .slotList=as.list(x_ecs)) } ) ### 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) 'elementLengths(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 <- new("DataFrame", nrows=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) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### "show" method. ### .makeNakedMatFromGenomicRanges <- 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 } showGenomicRanges <- function(x, margin="", print.classinfo=FALSE, print.seqinfo=FALSE) { 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, "range", "ranges"), " and ", x_nmc, " metadata ", ifelse(x_nmc == 1L, "column", "columns"), ":\n", sep="") ## S4Vectors:::makePrettyMatrixForCompactPrinting() assumes that 'x' is ## subsettable but not all GenomicRanges objects are (and if they are, ## subsetting them could be costly). However GRanges objects are assumed ## to be subsettable so if 'x' is not one then we turn it into one (this ## coercion is expected to work on any GenomicRanges object). if (!is(x, "GRanges")) x <- as(x, "GRanges") out <- S4Vectors:::makePrettyMatrixForCompactPrinting(x, .makeNakedMatFromGenomicRanges) 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) showGenomicRanges(object, margin=" ", print.classinfo=TRUE, print.seqinfo=TRUE) ) setMethod("showAsCell", "GenomicRanges", function(object) { if (length(object) > 0L) { paste0(seqnames(object), ":", strand(object), ":", showAsCell(ranges(object))) } else character(0) }) GenomicRanges/R/GenomicRanges-comparison.R0000644000175100017510000002365612607265136021554 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. ### order(), sort(), and rank() on a GenomicRanges object are using 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. ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### compare() ### ### Doing 'compare(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 '?compare' (in IRanges) for the 13 predefined codes. .GenomicRanges.compare <- 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 <- compare(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 "compare" method. setMethod("compare", c("GenomicRanges", "GenomicRanges"), function(x, y) .GenomicRanges.compare(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, method=c("auto", "quick", "hash")) { if (!identical(incomparables, FALSE)) stop("\"duplicated\" method for GenomicRanges objects ", "only accepts 'incomparables=FALSE'") S4Vectors:::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. S4Vectors:::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 } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### order() and related methods. ### ### The "order" and "rank" methods for GenomicRanges objects are consistent ### with the order implied by compare(). ### sort() will work out-of-the-box on a GenomicRanges object thanks to the ### method for Vector objects. ### setMethod("order", "GenomicRanges", function(..., na.last=TRUE, decreasing=FALSE) { 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) { x <- args[[1L]] return(S4Vectors:::orderIntegerQuads(as.factor(seqnames(x)), as.factor(strand(x)), start(x), width(x), decreasing=decreasing)) } order_args <- vector("list", 4L*length(args)) idx <- 4L*seq_len(length(args)) order_args[idx - 3L] <- lapply(args, function(x) as.factor(seqnames(x))) order_args[idx - 2L] <- lapply(args, function(x) as.factor(strand(x))) order_args[idx - 1L] <- lapply(args, start) order_args[idx] <- lapply(args, width) do.call(order, c(order_args, list(na.last=na.last, decreasing=decreasing))) } ) ### S3/S4 combo for sort.GenomicRanges .sort.GenomicRanges <- function(x, decreasing=FALSE, ignore.strand=FALSE, by) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) { x2 <- unstrand(x) i <- order(x2, decreasing=decreasing) } else { if (!missing(by)) { if (!missing(ignore.strand)) { warning("'ignore.strand' ignored when 'by' is specified") } i <- S4Vectors:::orderBy(by, x, decreasing=decreasing) } else { i <- order(x, decreasing=decreasing) } } extractROWS(x, i) } sort.GenomicRanges <- function(x, decreasing=FALSE, ...) .sort.GenomicRanges(x, decreasing=decreasing, ...) setMethod("sort", "GenomicRanges", .sort.GenomicRanges) GenomicRanges/R/GenomicRangesList-class.R0000644000175100017510000000266212607265137021336 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) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Coercion. ### setAs("RangedDataList", "GenomicRangesList", function(from) GenomicRangesList(lapply(from, as, "GRanges"))) setAs("GenomicRangesList", "RangedDataList", function(from) RangedDataList(lapply(from, as, "RangedData"))) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Utilities. ### setMethod("stack", "GenomicRangesList", function(x, indName = "sample") { x_flat <- unlist(x, use.names = FALSE) mcols(x_flat) <- cbind(IRanges:::.stack.ind(x, indName), mcols(x_flat)) x_flat }) GenomicRanges/R/RangedData-methods.R0000644000175100017510000000237012607265136020304 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 }) setMethod("seqinfo", "RangesList", function(x) { si <- callNextMethod() if (!is.null(universe(x))) genome(si) <- universe(x) 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/SummarizedExperiment-class.R0000644000175100017510000006656012607265137022151 0ustar00biocbuildbiocbuild## ## Helper classes: Assays, ShallowData, ShallowSimpleListAssays setClass("Assays") .ShallowData <- setRefClass("ShallowData", fields = list( data = "ANY" )) setMethod("clone", "ShallowData", # not exported function(x, ...) { args <- list(...) x <- x$copy() for (nm in names(args)) x$field(nm, args[[nm]]) x }) .ShallowSimpleListAssays0 <- setRefClass("ShallowSimpleListAssays", fields = list( data = "SimpleList" ), contains = c("ShallowData", "Assays")) .ShallowSimpleListAssays <- function(..., data = SimpleList()) ## this two-step constructor is much faster, 16 May, 2013 { xx <- .ShallowSimpleListAssays0(...) xx$data <- data xx } ## ## SummarizedExperiment ## displayed by validity, show, and SummarizedExperiment-to-ExpressionSet ## coercion methods .SummarizedExperiment_deprecation_msg <- wmsg( "The SummarizedExperiment class defined in the GenomicRanges package ", "is deprecated and being replaced with the RangedSummarizedExperiment ", "class defined in the new SummarizedExperiment package. ", "You can use updateObject() on any SummarizedExperiment object ", "to turn it into a RangedSummarizedExperiment." ) ## displayed by SummarizedExperiment() constructor if SummarizedExperiment ## package cannot be loaded .cannot_load_SummarizedExperiment_msg <- wmsg( "The SummarizedExperiment class defined in the GenomicRanges package ", "is deprecated and being replaced with the RangedSummarizedExperiment ", "class defined in the new SummarizedExperiment package. ", "Please make sure to install the SummarizedExperiment package before ", "you attempt to call the SummarizedExperiment() constructor function. ", "Note that this will return a RangedSummarizedExperiment instance ", "instead of a SummarizedExperiment instance." ) setClass("SummarizedExperiment", representation( exptData="SimpleList", # overall description rowData="GenomicRangesORGRangesList", # rows and their annotations colData="DataFrame", # columns and their annotations assays="Assays"), # Data -- e.g., list of matricies prototype( rowData=new("GRanges"), assays=.ShallowSimpleListAssays(data=SimpleList()))) ## validity .valid.SummarizedExperiment.assays_current <- function(x) { if (!is(slot(x, "assays"), "Assays")) return("'assays' is out-of-date; use updateObject()") NULL } .valid.SummarizedExperiment.assays_class <- function(x) { ok <- sapply(assays(x, withDimnames=FALSE), function(cl) { (!is.null(dim(cl))) && (length(dim(cl)) >= 2L) }) if (!all(ok)) return("'assays' must be matrix-like with 2 (or more?) dimensions") NULL } .valid.SummarizedExperiment.rowRanges_dims <- function(x) { if (!all(sapply(assays(x, withDimnames=FALSE), nrow) == length(rowRanges(x)))) return("'rowRanges' length differs from 'assays' nrow") NULL } .valid.SummarizedExperiment.colData_dims <- function(x) { if (!all(sapply(assays(x, withDimnames=FALSE), ncol) == nrow(colData(x)))) return("'colData' nrow differs from 'assays' ncol") NULL } .valid.SummarizedExperiment.assays_dims <- function(x) { c(.valid.SummarizedExperiment.rowRanges_dims(x), .valid.SummarizedExperiment.colData_dims(x)) } .valid.SummarizedExperiment <- function(x) { .Deprecated(msg=.SummarizedExperiment_deprecation_msg) c(.valid.SummarizedExperiment.assays_current(x), msg <- .valid.SummarizedExperiment.assays_class(x), if (is.null(msg)) { .valid.SummarizedExperiment.assays_dims(x) } else NULL) } setValidity2("SummarizedExperiment", .valid.SummarizedExperiment) setGeneric("SummarizedExperiment", function(assays, ...) standardGeneric("SummarizedExperiment")) .GRangesList_assays <- function(assays) { m <- assays[[1]] n <- nrow(m) names <- rownames(m) relist(GRanges(), PartitioningByEnd(integer(n), names=names)) } setMethod(SummarizedExperiment, "SimpleList", function(assays, ...) { if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(.cannot_load_SummarizedExperiment_msg) SummarizedExperiment::SummarizedExperiment(assays, ...) }) setMethod(SummarizedExperiment, "missing", function(assays, ...) { if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(.cannot_load_SummarizedExperiment_msg) SummarizedExperiment::SummarizedExperiment(assays, ...) }) setMethod(SummarizedExperiment, "list", function(assays, ...) { if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(.cannot_load_SummarizedExperiment_msg) SummarizedExperiment::SummarizedExperiment(assays, ...) }) setMethod(SummarizedExperiment, "matrix", function(assays, ...) { if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(.cannot_load_SummarizedExperiment_msg) SummarizedExperiment::SummarizedExperiment(assays, ...) }) ## update / clone setMethod("clone", "SummarizedExperiment", # not exported function(x, ...) { ## S4Vectors:::extraArgsAsList would prevent using clone on ## subclasses args <- list(...) firstTime <- TRUE for (nm in names(args)) { s <- slot(x, nm) v <- args[[nm]] if (is(s, "ShallowData")) v <- clone(s, data=v) if (firstTime) { slot(x, nm, FALSE) <- v firstTime <- FALSE } else { `slot<-`(x, nm, FALSE, v) } } x }) setGeneric("value", # not exported function(x, name, ...) standardGeneric("value"), signature = "x") setMethod("value", "SummarizedExperiment", # not exported function(x, name, ...) { s <- slot(x, name) if (is(s, "ShallowData")) s <- s$data s }) ## getter / setter generics setGeneric("exptData", function(x, ...) standardGeneric("exptData")) setGeneric("exptData<-", function(x, ..., value) standardGeneric("exptData<-")) ## rowRanges, colData seem too vague, but from eSet derived classes wanted to ## call the rows / cols something different from 'features' or 'samples', so ## might as well avoid the issue setGeneric("rowRanges", function(x, ...) standardGeneric("rowRanges")) setGeneric("rowRanges<-", function(x, ..., value) standardGeneric("rowRanges<-")) rowData <- function(...) { .Defunct("rowRanges") rowRanges(...) } `rowData<-` <- function(x, ..., value) { .Defunct("rowRanges<-") rowRanges(x, ...) <- value } setGeneric("colData", function(x, ...) standardGeneric("colData")) setGeneric("colData<-", function(x, ..., value) standardGeneric("colData<-")) setGeneric("assayNames", function(x, ...) standardGeneric("assayNames")) setGeneric("assayNames<-", function(x, ..., value) standardGeneric("assayNames<-")) setGeneric("assays", function(x, ..., withDimnames=TRUE) standardGeneric("assays"), signature="x") setGeneric("assays<-", function(x, ..., withDimnames=TRUE, value) standardGeneric("assays<-"), signature=c("x", "value")) setGeneric("assay", function(x, i, ...) standardGeneric("assay")) setGeneric("assay<-", function(x, i, ..., value) standardGeneric("assay<-")) ## Simple 'getters' / 'setters' setMethod(exptData, "SummarizedExperiment", function(x, ...) value(x, "exptData")) setReplaceMethod("exptData", c("SummarizedExperiment", "SimpleList"), function(x, ..., value) { clone(x, ..., exptData=value) }) setReplaceMethod("exptData", c("SummarizedExperiment", "list"), function(x, ..., value) { clone(x, ..., exptData=SimpleList(value)) }) setMethod(rowRanges, "SummarizedExperiment", function(x, ...) value(x, "rowData")) .SummarizedExperiment.rowRanges.replace <- function(x, ..., value) { x <- clone(x, ..., rowData=value) msg <- .valid.SummarizedExperiment.rowRanges_dims(x) if (!is.null(msg)) stop(msg) x } setReplaceMethod("rowRanges", c("SummarizedExperiment", "GenomicRanges"), .SummarizedExperiment.rowRanges.replace) setReplaceMethod("rowRanges", c("SummarizedExperiment", "GRangesList"), .SummarizedExperiment.rowRanges.replace) setMethod(colData, "SummarizedExperiment", function(x, ...) value(x, "colData")) setReplaceMethod("colData", c("SummarizedExperiment", "DataFrame"), function(x, ..., value) { x <- clone(x, ..., colData=value) msg <- .valid.SummarizedExperiment.colData_dims(x) if (!is.null(msg)) stop(msg) x }) setMethod("assayNames", "SummarizedExperiment", function(x, ...) { names(assays(x, withDimnames=FALSE)) }) setMethod("assayNames<-", c("SummarizedExperiment", "character"), function(x, ..., value) { names(assays(x, withDimnames=FALSE)) <- value x }) setMethod(assays, "SummarizedExperiment", function(x, ..., withDimnames=TRUE) { if (withDimnames) endoapply(value(x, "assays"), "dimnames<-", dimnames(x)) else value(x, "assays") }) .SummarizedExperiment.assays.replace <- function(x, ..., withDimnames=TRUE, value) { ## withDimnames arg allows names(assays(se, withDimnames=FALSE)) <- value ok <- vapply(value, function(elt, xdimnames) { e <- dimnames(elt) (is.null(e[[1]]) || identical(e[[1]], xdimnames[[1]])) && (is.null(e[[2]]) || identical(e[[2]], xdimnames[[2]])) }, logical(1), xdimnames=dimnames(x)) if (!all(ok)) stop("current and replacement dimnames() differ") x <- clone(x, ..., assays=value) msg <- .valid.SummarizedExperiment(x) if (!is.null(msg)) stop(msg) x } setReplaceMethod("assays", c("SummarizedExperiment", "SimpleList"), .SummarizedExperiment.assays.replace) setReplaceMethod("assays", c("SummarizedExperiment", "list"), .SummarizedExperiment.assays.replace) ## convenience for common use case setMethod(assay, c("SummarizedExperiment", "missing"), function(x, i, ...) { assays <- assays(x, ...) if (0L == length(assays)) stop("'assay(<", class(x), ">, i=\"missing\", ...) ", "length(assays(<", class(x), ">)) is 0'") assays[[1]] }) setMethod(assay, c("SummarizedExperiment", "numeric"), function(x, i, ...) { tryCatch({ assays(x, ...)[[i]] }, error=function(err) { stop("'assay(<", class(x), ">, i=\"numeric\", ...)' ", "invalid subscript 'i'\n", conditionMessage(err)) }) }) setMethod(assay, c("SummarizedExperiment", "character"), function(x, i = names(x)[1], ...) { msg <- paste0("'assay(<", class(x), ">, i=\"character\", ...)' ", "invalid subscript 'i'") res <- tryCatch({ assays(x, ...)[[i]] }, error=function(err) { stop(msg, "\n", conditionMessage(err)) }) if (is.null(res)) stop(msg, "\n'i' not in names(assays(<", class(x), ">))") res }) setReplaceMethod("assay", c("SummarizedExperiment", "missing", "matrix"), function(x, i, ..., value) { if (0L == length(assays(x))) stop("'assay(<", class(x), ">) <- value' ", "length(assays(<", class(x), ">)) is 0") assays(x)[[1]] <- value x }) setReplaceMethod("assay", c("SummarizedExperiment", "numeric", "matrix"), function(x, i = 1, ..., value) { assays(x, ...)[[i]] <- value x }) setReplaceMethod("assay", c("SummarizedExperiment", "character", "matrix"), function(x, i = names(x)[1], ..., value) { assays(x, ...)[[i]] <- value x }) ## cannonical location for dim, dimnames; dimnames should be checked ## for consistency (if non-null) and stripped from assays on ## construction, or added from assays if row/col names are NULL in ## but not assays. dimnames need to be added on ## to assays when assays() invoked setMethod(dim, "SummarizedExperiment", function(x) { c(length(rowRanges(x)), nrow(colData(x))) }) setMethod(dimnames, "SummarizedExperiment", function(x) { list(names(rowRanges(x)), rownames(colData(x))) }) setReplaceMethod("dimnames", c("SummarizedExperiment", "list"), function(x, value) { rowRanges <- rowRanges(x) names(rowRanges) <- value[[1]] colData <- colData(x) rownames(colData) <- value[[2]] clone(x, rowData=rowRanges, colData=colData) }) setReplaceMethod("dimnames", c("SummarizedExperiment", "NULL"), function(x, value) { dimnames(x) <- list(NULL, NULL) x }) ## Subset -- array-like .SummarizedExperiment.charbound <- function(idx, txt, fmt) { orig <- idx idx <- match(idx, txt) if (any(bad <- is.na(idx))) { msg <- paste(S4Vectors:::selectSome(orig[bad]), collapse=" ") stop(sprintf(fmt, msg)) } idx } .SummarizedExperiment.assays.subset <- function(x, i, j, ...) { ## need to expand Rle's for subsetting standard matrix if (!missing(i) && !missing(j)) { fun <- function(x) { switch(length(dim(x)), stop("'[' on assays() with 1 dimension not supported"), x[i, j, drop=FALSE], x[i, j, , drop=FALSE], x[i, j, , , drop=FALSE], stop("'[' on assays() with >4 dimensions not supported")) } } else if (!missing(i)) { fun <- function(x) { switch(length(dim(x)), stop("'[' on assays() with 1 dimension not supported"), x[i, , drop=FALSE], x[i, , , drop=FALSE], x[i, , , , drop=FALSE], stop("'[' on assays() with >4 dimensions not supported")) } } else if (!missing(j)) { fun <- function(x) { switch(length(dim(x)), stop("'[' on assays() with 1 dimension not supported"), x[, j, drop=FALSE], x[, j, , drop=FALSE], x[, j, , , drop=FALSE], stop("'[' on assays() with >4 dimensions not supported")) } } endoapply(assays(x, withDimnames=FALSE), fun) } setMethod("[", c("SummarizedExperiment", "ANY", "ANY"), function(x, i, j, ..., drop=TRUE) { if (1L != length(drop) || (!missing(drop) && drop)) warning("'drop' ignored '[,", class(x), ",ANY,ANY-method'") if (missing(i) && missing(j)) return(x) if (!missing(i) && is.character(i)) { fmt <- paste0("<", class(x), ">[i,] index out of bounds: %s") i <- .SummarizedExperiment.charbound(i, rownames(x), fmt) } if (!missing(j) && is.character(j)) { fmt <- paste0("<", class(x), ">[,j] index out of bounds: %s") j <- .SummarizedExperiment.charbound(j, colnames(x), fmt) } if (!missing(i) && !missing(j)) { ii <- as.vector(i) jj <- as.vector(j) x <- clone(x, ..., rowData=rowRanges(x)[i], colData=colData(x)[j, , drop=FALSE], assays=.SummarizedExperiment.assays.subset(x, ii, jj)) } else if (missing(i)) { jj <- as.vector(j) x <- clone(x, ..., colData=colData(x)[j, , drop=FALSE], assays=.SummarizedExperiment.assays.subset(x, j=jj)) } else { # missing(j) ii <- as.vector(i) x <- clone(x, ..., rowData=rowRanges(x)[i], assays=.SummarizedExperiment.assays.subset(x, ii)) } x }) .SummarizedExperiment.assays.subsetgets <- function(x, i, j, ..., value) { ## need to expand Rle's for subsetting standard matrix if (!missing(i) && !missing(j)) { fun <- function(x, value) { switch(length(dim(x)), stop("'[<-' on assays() with 1 dimension not supported"), x[i, j] <- value, x[i, j, ] <- value, x[i, j, , ] <- value, stop("'[<-' on assays() with >4 dimensions not supported")) x } } else if (!missing(i)) { fun <- function(x, value) { switch(length(dim(x)), stop("'[<-' on assays() with 1 dimension not supported"), x[i, ] <- value, x[i, , ] <- value, x[i, , , ] <- value, stop("'[<-' on assays() with >4 dimensions not supported")) x } } else if (!missing(j)) { fun <- function(x, value) { switch(length(dim(x)), stop("'[<-' on assays() with 1 dimension not supported"), x[, j] <- value, x[, j, ] <- value, x[, j, , ] <- value, stop("'[<-' on assays() with >4 dimensions not supported")) x } } a <- assays(x, withDimnames=FALSE) v <- assays(value, withDimnames=FALSE) mendoapply(fun, x=a, value=v) } setReplaceMethod("[", c("SummarizedExperiment", "ANY", "ANY", "SummarizedExperiment"), function(x, i, j, ..., value) { if (missing(i) && missing(j)) return(value) if (!missing(i) && is.character(i)) { fmt <- paste0("<", class(x), ">[i,] index out of bounds: %s") i <- .SummarizedExperiment.charbound(i, rownames(x), fmt) } if (!missing(j) && is.character(j)) { fmt <- paste0("<", class(x), ">[,j] index out of bounds: %s") j <- .SummarizedExperiment.charbound(j, colnames(x), fmt) } if (!missing(i) && !missing(j)) { ii <- as.vector(i) jj <- as.vector(j) x <- clone(x, ..., exptData=c(exptData(x), exptData(value)), rowData=local({ r <- rowRanges(x) r[i] <- rowRanges(value) names(r)[ii] <- names(rowRanges(value)) r }), colData=local({ c <- colData(x) c[j,] <- colData(value) rownames(c)[jj] <- rownames(colData(value)) c }), assays=.SummarizedExperiment.assays.subsetgets(x, ii, jj, ..., value=value)) msg <- .valid.SummarizedExperiment.assays_dims(x) } else if (missing(i)) { jj <- as.vector(j) x <- clone(x, ..., exptData=c(exptData(x), exptData(value)), colData=local({ c <- colData(x) c[j,] <- colData(value) rownames(c)[jj] <- rownames(colData(value)) c }), assays=.SummarizedExperiment.assays.subsetgets(x, j=jj, ..., value=value)) msg <- .valid.SummarizedExperiment.colData_dims(x) } else { # missing(j) ii <- as.vector(i) x <- clone(x, ..., exptData=c(exptData(x), exptData(value)), rowData=local({ r <- rowRanges(x) r[i] <- rowRanges(value) names(r)[ii] <- names(rowRanges(value)) r }), assays=.SummarizedExperiment.assays.subsetgets(x, ii, ..., value=value)) msg <- .valid.SummarizedExperiment.rowRanges_dims(x) } if (!is.null(msg)) stop(msg) x }) ## rbind, cbind ## Appropriate for objects with different ranges and same samples. setMethod("rbind", "SummarizedExperiment", function(..., deparse.level=1) { args <- unname(list(...)) .rbind.SummarizedExperiment(args) }) .rbind.SummarizedExperiment <- function(args) { if (!.compare(lapply(args, colnames))) stop("'...' objects must have the same colnames") if (!.compare(lapply(args, ncol))) stop("'...' objects must have the same number of samples") rowRanges <- do.call(c, lapply(args, rowRanges)) colData <- .cbind.DataFrame(args, colData, "colData") assays <- .bind.arrays(args, rbind, "assays") exptData <- do.call(c, lapply(args, exptData)) initialize(args[[1]], assays=assays, rowData=rowRanges, colData=colData, exptData=exptData) } ## Appropriate for objects with same ranges and different samples. setMethod("cbind", "SummarizedExperiment", function(..., deparse.level=1) { args <- unname(list(...)) .cbind.SummarizedExperiment(args) }) .cbind.SummarizedExperiment <- function(args) { if (!.compare(lapply(args, rowRanges), TRUE)) stop("'...' object ranges (rows) are not compatible") rowRanges <- rowRanges(args[[1]]) mcols(rowRanges) <- .cbind.DataFrame(args, mcols, "mcols") colData <- do.call(rbind, lapply(args, colData)) assays <- .bind.arrays(args, cbind, "assays") exptData <- do.call(c, lapply(args, exptData)) initialize(args[[1]], assays=assays, rowData=rowRanges, colData=colData, exptData=exptData) } .compare <- function(x, GenomicRanges=FALSE) { x1 <- x[[1]] if (GenomicRanges) { if (is(x1, "GRangesList")) { x <- lapply(x, unlist) x1 <- x[[1]] } for (i in seq_along(x)[-1]) { if (length(x1) != length(x[[i]])) return(FALSE) ok <- x1 == x[[i]] if (!all(ok)) return(FALSE) } return(TRUE) } else { all(sapply(x[-1], function(xelt) all(identical(xelt, x[[1]])))) } } .cbind.DataFrame <- function(args, accessor, accessorName) { lst <- lapply(args, accessor) if (!.compare(lst)) { nms <- lapply(lst, names) nmsv <- unlist(nms, use.names=FALSE) names(nmsv) <- rep(seq_along(nms), elementLengths(nms)) dups <- duplicated(nmsv) ## no duplicates if (!any(dups)) return(do.call(cbind, lst)) ## confirm duplicates are the same lapply(nmsv[duplicated(nmsv)], function(d) { if (!.compare(lapply(lst, "[", d))) stop("column(s) '", unname(d), "' in ", sQuote(accessorName), " are duplicated and the data do not match")}) ## remove duplicates do.call(cbind, lst)[,!dups] } else { lst[[1]] } } .bind.array.elements <- function(index, lst, bind) { e1 <- lapply(lst, "[[", index) dim <- .get.assay.dimension(e1, bind) if (is.na(dim[3])) { do.call(bind, e1) } else { e2 <- lapply(1:dim[3], function(i) { do.call(bind, lapply(e1, "[", ,,i)) }) array(do.call(c, e2), dim=dim) } } .bind.arrays <- function(args, bind, accessor) { lst <- lapply(args, accessor) if (!length(elts <- unique(elementLengths(lst))) == 1L) stop("elements in ", sQuote(accessor), " must have the same length") if (elts == 0L) return(.ShallowSimpleListAssays(data=SimpleList())) var <- lapply(lst, names) if (is.null(uvar <- unique(unlist(var)))) { ## no names, match by position res <- lapply(seq_along(elts), .bind.array.elements, lst=lst, bind=bind) } else { ## match by name if (!.compare(var)) stop("elements in ", sQuote(accessor), " must have the same names") res <- lapply(uvar, .bind.array.elements, lst=lst, bind=bind) names(res) <- uvar } .ShallowSimpleListAssays(data=SimpleList(res)) } .get.assay.dimension <- function(lst, bind) { dim <- lapply(lst, dim) if (!.compare(lapply(dim, "[", 3))) stop("elements in assays must have the same dimension") if (identical(bind, cbind)) c(dim[[1]][1], do.call(sum, lapply(dim, "[", 2)), dim[[1]][3]) else c(do.call(sum, lapply(dim, "[", 1)), dim[[1]][2], dim[[1]][3]) } ## $, $<-, [[, [[<- for colData access setMethod("[[", c("SummarizedExperiment", "ANY", "missing"), function(x, i, j, ...) { colData(x)[[i, ...]] }) setReplaceMethod("[[", c("SummarizedExperiment", "ANY", "missing", "ANY"), function(x, i, j, ..., value) { colData(x)[[i, ...]] <- value x }) .DollarNames.SummarizedExperiment <- function(x, pattern) grep(pattern, names(colData(x)), value=TRUE) setMethod("$", "SummarizedExperiment", function(x, name) { colData(x)[[name]] }) setReplaceMethod("$", c("SummarizedExperiment", "ANY"), function(x, name, value) { colData(x)[[name]] <- value x }) ## show setMethod(show, "SummarizedExperiment", function(object) { .Deprecated(msg=.SummarizedExperiment_deprecation_msg) selectSome <- S4Vectors:::selectSome scat <- function(fmt, vals=character(), exdent=2, ...) { vals <- ifelse(nzchar(vals), vals, "''") lbls <- paste(S4Vectors:::selectSome(vals), collapse=" ") txt <- sprintf(fmt, length(vals), lbls) cat(strwrap(txt, exdent=exdent, ...), sep="\n") } cat("class:", class(object), "\n") cat("dim:", dim(object), "\n") expt <- names(exptData(object)) if (is.null(expt)) expt <- character(length(exptData(object))) scat("exptData(%d): %s\n", expt) nms <- names(assays(object, withDimnames=FALSE)) if (is.null(nms)) nms <- character(length(assays(object, withDimnames=FALSE))) scat("assays(%d): %s\n", nms) dimnames <- dimnames(object) dlen <- sapply(dimnames, length) if (dlen[[1]]) scat("rownames(%d): %s\n", dimnames[[1]]) else scat("rownames: NULL\n") scat("rowRanges metadata column names(%d): %s\n", names(mcols(rowRanges(object)))) if (dlen[[2]]) scat("colnames(%d): %s\n", dimnames[[2]]) else cat("colnames: NULL\n") scat("colData names(%d): %s\n", names(colData(object))) }) ## transition to RangedSummarizedExperiment suppressMessages( setAs("SummarizedExperiment", "RangedSummarizedExperiment", function(from) { if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(wmsg("Couldn't load the SummarizedExperiment package! ", "Please make sure to install the SummarizedExperiment ", "package before you attempt to coerce a ", "SummarizedExperiment object to a ", "RangedSummarizedExperiment object.")) SummarizedExperiment:::.from_SummarizedExperiment_to_RangedSummarizedExperiment(from) } ) ) setMethod(updateObject, "SummarizedExperiment", function(object, ..., verbose=FALSE) { if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(wmsg("Couldn't load the SummarizedExperiment package! ", "Please make sure to install the SummarizedExperiment ", "package before you attempt to update a ", "SummarizedExperiment object.")) s <- slot(object, "assays") if (is(s, "SimpleList")) slot(object, "assays") <- .ShallowSimpleListAssays(data=s) as(object, "RangedSummarizedExperiment") }) suppressMessages( setAs("SummarizedExperiment", "ExpressionSet", function(from) { .Deprecated(msg=.SummarizedExperiment_deprecation_msg) as(as(from, "RangedSummarizedExperiment"), "ExpressionSet") }) ) suppressMessages( setAs("ExpressionSet", "SummarizedExperiment", function(from) { warning(wmsg( "The SummarizedExperiment class defined in the GenomicRanges package ", "is deprecated and being replaced with the RangedSummarizedExperiment ", "class defined in the new SummarizedExperiment package. ", "The coercion method from ExpressionSet to SummarizedExperiment ", "has been modified to return a RangedSummarizedExperiment object." )) if (!requireNamespace("SummarizedExperiment", quietly=TRUE)) stop(wmsg("Couldn't load the SummarizedExperiment package! ", "Please make sure to install the SummarizedExperiment ", "package before you attempt to coerce an ", "ExpressionSet object to a ", "RangedSummarizedExperiment object.")) SummarizedExperiment::makeSummarizedExperimentFromExpressionSet(from) }) ) GenomicRanges/R/SummarizedExperiment-rowData-methods.R0000644000175100017510000002175612607265136024103 0ustar00biocbuildbiocbuild## colData-as-GRanges compatibility: allow direct access to GRanges / ## GRangesList colData for select functions ## Not supported: ## ## Not consistent SummarizedExperiment structure: length, names, ## as.data.frame, c. ## Length-changing endomorphisms: disjoin, gaps, reduce, unique. ## 'legacy' data types / functions: as "RangedData", as "RangesList", ## renameSeqlevels, keepSeqlevels. ## Possile to implement, but not yet: Ops, map, window, window<- ## mcols setMethod(mcols, "SummarizedExperiment", function(x, use.names=FALSE, ...) { mcols(rowRanges(x), use.names=use.names, ...) }) setReplaceMethod("mcols", "SummarizedExperiment", function(x, ..., value) { clone(x, rowData=local({ r <- rowRanges(x) mcols(r) <- value r })) }) ### mcols() is the recommended way for accessing the metadata columns. ### Use of values() or elementMetadata() is discouraged. setMethod(elementMetadata, "SummarizedExperiment", function(x, use.names=FALSE, ...) { elementMetadata(rowRanges(x), use.names=use.names, ...) }) setReplaceMethod("elementMetadata", "SummarizedExperiment", function(x, ..., value) { elementMetadata(rowRanges(x), ...) <- value x }) setMethod(values, "SummarizedExperiment", function(x, ...) { values(rowRanges(x), ...) }) setReplaceMethod("values", "SummarizedExperiment", function(x, ..., value) { values(rowRanges(x), ...) <- value x }) ## Single dispatch, generic signature fun(x, ...) local({ .funs <- c("coverage", "disjointBins", "duplicated", "end", "end<-", "flank", "isDisjoint", "narrow", "ranges", "resize", "restrict", "seqinfo", "seqnames", "shift", "start", "start<-", "strand", "width", "width<-") endomorphisms <- c(.funs[grepl("<-$", .funs)], "flank", "narrow", "resize", "restrict", "shift") tmpl <- function() {} environment(tmpl) <- parent.frame(2) for (.fun in .funs) { generic <- getGeneric(.fun) formals(tmpl) <- formals(generic) fmls <- as.list(formals(tmpl)) fmls[] <- sapply(names(fmls), as.symbol) fmls[[generic@signature]] <- quote(rowRanges(x)) if (.fun %in% endomorphisms) body(tmpl) <- substitute({ rowRanges(x) <- do.call(FUN, ARGS) x }, list(FUN=.fun, ARGS=fmls)) else body(tmpl) <- substitute(do.call(FUN, ARGS), list(FUN=as.symbol(.fun), ARGS=fmls)) setMethod(.fun, "SummarizedExperiment", tmpl) } }) setMethod("granges", "SummarizedExperiment", function(x, use.mcols=FALSE, ...) { if (!identical(use.mcols, FALSE)) stop("\"granges\" method for SummarizedExperiment objects ", "does not support the 'use.mcols' argument") rowRanges(x) }) ## 2-argument dispatch: ## compare / Compare ## precede, follow, nearest, distance, distanceToNearest ## ## findOverlaps / countOverlaps, match, subsetByOverlaps: see ## findOverlaps-method.R .SummarizedExperiment.compare <- function(x, y) { if (is(x, "SummarizedExperiment")) x <- rowRanges(x) if (is(y, "SummarizedExperiment")) y <- rowRanges(y) compare(x, y) } .SummarizedExperiment.Compare <- function(e1, e2) { if (is(e1, "SummarizedExperiment")) e1 <- rowRanges(e1) if (is(e2, "SummarizedExperiment")) e2 <- rowRanges(e2) callGeneric(e1=e1, e2=e2) } .SummarizedExperiment.nearest.missing <- function(x, subject, select = c("arbitrary", "all"), algorithm = c("nclist", "intervaltree"), ignore.strand = FALSE) { select <- match.arg(select) x <- rowRanges(x) nearest(x=x, select=select, algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } .SummarizedExperiment.distance <- function(x, y, ignore.strand = FALSE, ...) { if (is(x, "SummarizedExperiment")) x <- rowRanges(x) if (is(y, "SummarizedExperiment")) y <- rowRanges(y) distance(x, y, ignore.strand=ignore.strand, ...) } .SummarizedExperiment.distanceToNearest <- function(x, subject, algorithm = c("nclist", "intervaltree"), ignore.strand = FALSE, ...) { if (is(x, "SummarizedExperiment")) x <- rowRanges(x) if (is(subject, "SummarizedExperiment")) subject <- rowRanges(subject) distanceToNearest(x, subject, algorithm=match.arg(algorithm), ignore.strand=ignore.strand, ...) } local({ .signatures <- list( c("SummarizedExperiment", "ANY"), c("ANY", "SummarizedExperiment"), c("SummarizedExperiment", "SummarizedExperiment")) for (.sig in .signatures) { .funs <- c("precede", "follow") tmpl <- function(x, subject, select = c("arbitrary", "all"), ignore.strand = FALSE) {} environment(tmpl) <- parent.frame(2) for (.fun in .funs) { body(tmpl) <- substitute({ select <- match.arg(select) if (is(x, "SummarizedExperiment")) x <- rowRanges(x) if (is(subject, "SummarizedExperiment")) subject <- rowRanges(subject) FUN(x=x, subject=subject, select=select, ignore.strand=ignore.strand) }, list(FUN=as.symbol(.fun))) setMethod(.fun, .sig, tmpl) } .funs <- "nearest" tmpl <- function(x, subject, select = c("arbitrary", "all"), algorithm=c("nclist", "intervaltree"), ignore.strand = FALSE) {} environment(tmpl) <- parent.frame(2) for (.fun in .funs) { body(tmpl) <- substitute({ select <- match.arg(select) if (is(x, "SummarizedExperiment")) x <- rowRanges(x) if (is(subject, "SummarizedExperiment")) subject <- rowRanges(subject) FUN(x=x, subject=subject, select=select, ignore.strand=ignore.strand) }, list(FUN=as.symbol(.fun))) setMethod(.fun, .sig, tmpl) } setMethod("nearest", c("SummarizedExperiment", "missing"), .SummarizedExperiment.nearest.missing) setMethod("compare", .sig, .SummarizedExperiment.compare) setMethod("Compare", .sig, .SummarizedExperiment.Compare) setMethod("distance", .sig, .SummarizedExperiment.distance) setMethod("distanceToNearest", .sig, .SummarizedExperiment.distanceToNearest) } }) ## additional getters / setters setReplaceMethod("strand", "SummarizedExperiment", function(x, ..., value) { strand(rowRanges(x)) <- value x }) setReplaceMethod("ranges", "SummarizedExperiment", function(x, ..., value) { ranges(rowRanges(x)) <- value x }) ## order, rank, sort setMethod("order", "SummarizedExperiment", function(..., na.last = TRUE, decreasing = FALSE) { args <- lapply(list(...), rowRanges) do.call("order", c(args, list(na.last=na.last, decreasing=decreasing))) }) setMethod("rank", "SummarizedExperiment", function (x, na.last = TRUE, ties.method = c("average", "first", "random", "max", "min")) { ties.method <- match.arg(ties.method) rank(rowRanges(x), na.last=na.last, ties.method=ties.method) }) setMethod("sort", "SummarizedExperiment", function(x, decreasing = FALSE, ...) { x[order(rowRanges(x), decreasing=decreasing),] }) ## subset setMethod("subset", "SummarizedExperiment", function(x, subset, select, ...) { i <- S4Vectors:::evalqForSubset(subset, rowRanges(x), ...) j <- S4Vectors:::evalqForSubset(select, colData(x), ...) x[i, j] }) ## seqinfo (also seqlevels, genome, seqlevels<-, genome<-), seqinfo<- setMethod(seqinfo, "SummarizedExperiment", function(x) { seqinfo(x@rowData) }) setReplaceMethod("seqinfo", "SummarizedExperiment", function (x, new2old = NULL, force = FALSE, value) { if (!is(value, "Seqinfo")) stop("the supplied 'seqinfo' must be a Seqinfo object") dangling_seqlevels <- GenomeInfoDb:::getDanglingSeqlevels(x@rowData, new2old = new2old, force = force, seqlevels(value)) if (length(dangling_seqlevels) != 0L) x <- x[!(seqnames(x) %in% dangling_seqlevels)] x@rowData <- update(x@rowData, seqnames = GenomeInfoDb:::makeNewSeqnames(x, new2old, seqlevels(value)), seqinfo = value) if (is.character(msg <- .valid.SummarizedExperiment(x))) stop(msg) x }) ## extractROWS, replaceROWS setMethod("extractROWS", "SummarizedExperiment", function(x, i) { ridx <- extractROWS(seq_len(nrow(x)), i) x[ridx,] }) setMethod("replaceROWS", "SummarizedExperiment", function (x, i, value) { ridx <- extractROWS(seq_len(nrow(x)), i) x[ridx,] <- value x }) setMethod(split, "SummarizedExperiment", function(x, f, drop=FALSE, ...) { splitAsList(x, f, drop=drop) }) GenomicRanges/R/absoluteRanges.R0000644000175100017510000001210712607265137017627 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.R0000644000175100017510000001212112607265136017030 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("ConstraintORNULL", 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.R0000644000175100017510000000617512607265136020114 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-GIntervalTree-methods.R0000644000175100017510000000577412607265137023473 0ustar00biocbuildbiocbuildsetMethod("findOverlaps", c("GenomicRanges", "GIntervalTree"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any","start","end","within","equal"), select=c("all","first","last","arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { if (any(isCircular(query), na.rm=TRUE)) stop("'GIntervalTree' not supported for circular sequences") if (!isSingleNumber(maxgap) || maxgap < 0L) stop("'maxgap' must be a non-negative integer") type <- match.arg(type) select <- match.arg(select) algorithm <- match.arg(algorithm) if (algorithm != "nclist") warning("'algorithm' is ignored when 'subject' ", "is a GIntervalTree object") ## merge() also checks that 'query' and 'subject' are based on the ## same reference genome. seqinfo <- merge(seqinfo(query), seqinfo(subject)) qidx <- .GT_getIndex(query) qlist <- split(unname(ranges(query)), seqnames(query)) hits <- findOverlaps(qlist, subject@ranges, maxgap=maxgap,minoverlap=minoverlap, type=type,select="all") hits <- hits@unlistData if (is(hits, "Hits")) { .GT_reorderHits <- function(rngidx, hits) { if (length(rngidx)) { idx <- findOverlaps(hits, rngidx, select="first") starts <- as.integer(1+c(0,cumsum(width(rngidx))[-length(rngidx)])) hits <- starts[idx] + hits - start(rngidx)[idx] } hits } new_queryHits <- .GT_reorderHits(qidx, queryHits(hits)) new_subjectHits <- .GT_reorderHits(subject@rngidx, subjectHits(hits)) oo <- S4Vectors:::orderIntegerPairs(new_queryHits, new_subjectHits) hits@queryHits <- new_queryHits[oo] hits@subjectHits <- new_subjectHits[oo] } else { hits <- .GT_reorderValue(qlist, hits, qidx) } if (!ignore.strand) { q_strand <- .strandAsSignedNumber(strand(query)) s_strand <- .strandAsSignedNumber(strand(subject)) compatible_strand <- q_strand[queryHits(hits)] * s_strand[subjectHits(hits)] != -1L hits <- hits[compatible_strand] } q_hits <- queryHits(hits) s_hits <- subjectHits(hits) q_len <- length(query) s_len <- length(subject) if (select == "arbitrary") { ans <- rep.int(NA_integer_, q_len) ans[q_hits] <- s_hits return(ans) } if (select == "first") { ans <- rep.int(NA_integer_, q_len) oo <- S4Vectors:::orderIntegerPairs(q_hits, s_hits, decreasing=TRUE) ans[q_hits[oo]] <- s_hits[oo] return(ans) } oo <- S4Vectors:::orderIntegerPairs(q_hits, s_hits) q_hits <- q_hits[oo] s_hits <- s_hits[oo] if (select == "last") { ans <- rep.int(NA_integer_, q_len) ans[q_hits] <- s_hits return(ans) } Hits(q_hits, s_hits, q_len, s_len) }) setMethod("countOverlaps", c("GenomicRanges", "GIntervalTree"), countOverlaps.definition ) GenomicRanges/R/findOverlaps-methods.R0000644000175100017510000007066712607265136020764 0ustar00biocbuildbiocbuild### ========================================================================= ### findOverlaps methods ### ------------------------------------------------------------------------- ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### findOverlaps_GenomicRanges_old() ### .putRangesOnFirstCircle <- function(x, circle.length) { x_start0 <- start(x) - 1L # 0-based start x_shift0 <- x_start0 %% circle.length - x_start0 shift(x, x_shift0) } ### 'circle.length' must be NA (if the underlying sequence is linear) or the ### length of the underlying circular sequence (integer vector of length 1 ### with the name of the sequence). ### 'query' and 'subject' must be IRanges objects. .findOverlaps.circle <- function(circle.length, query, subject, maxgap, minoverlap, type) { if (is.na(circle.length)) return(findOverlaps(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type, select="all", algorithm="intervaltree")) q_len <- length(query) s_len <- length(subject) if (q_len == 0L || s_len == 0L) return(Hits(queryLength=q_len, subjectLength=s_len)) query0 <- .putRangesOnFirstCircle(query, circle.length) subject0 <- .putRangesOnFirstCircle(subject, circle.length) pp_subject <- IntervalTree(subject0) hits00 <- findOverlaps(query0, pp_subject, maxgap=maxgap, minoverlap=minoverlap, type=type, select="all", algorithm="intervaltree") query1 <- shift(query0, circle.length) hits10 <- findOverlaps(query1, pp_subject, maxgap=maxgap, minoverlap=minoverlap, type=type, select="all", algorithm="intervaltree") subject1 <- shift(subject0, circle.length) hits01 <- findOverlaps(query0, subject1, maxgap=maxgap, minoverlap=minoverlap, type=type, select="all", algorithm="intervaltree") ## Merge 'hits00', 'hits10' and 'hits01'. union(union(hits00, hits10), hits01) } ### 'x' must be 'strand(query)' or 'strand(subject)'. .strandAsSignedNumber <- function(x) { tmp <- as.integer(runValue(x)) idx <- tmp >= 2L tmp[idx] <- tmp[idx] - 3L runValue(x) <- tmp as.vector(x) } findOverlaps_GenomicRanges_old <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), ignore.strand=FALSE) { if (!isSingleNumber(maxgap) || maxgap < 0L) stop("'maxgap' must be a non-negative integer") type <- match.arg(type) select <- match.arg(select) ## merge() also checks that 'query' and 'subject' are based on the ## same reference genome. seqinfo <- merge(seqinfo(query), seqinfo(subject)) q_len <- length(query) s_len <- length(subject) q_seqnames <- seqnames(query) s_seqnames <- seqnames(subject) q_splitranges <- splitRanges(q_seqnames) s_splitranges <- splitRanges(s_seqnames) q_seqlevels_nonempty <- names(q_splitranges)[sapply(q_splitranges, length) > 0] s_seqlevels_nonempty <- names(s_splitranges)[sapply(s_splitranges, length) > 0] q_ranges <- unname(ranges(query)) s_ranges <- unname(ranges(subject)) if (ignore.strand) { q_strand <- rep.int(1L, q_len) s_strand <- rep.int(1L, s_len) } else { q_strand <- .strandAsSignedNumber(strand(query)) s_strand <- .strandAsSignedNumber(strand(subject)) } common_seqlevels <- intersect(q_seqlevels_nonempty, s_seqlevels_nonempty) results <- lapply(common_seqlevels, function(seqlevel) { if (isCircular(seqinfo)[seqlevel] %in% TRUE) { circle.length <- seqlengths(seqinfo)[seqlevel] } else { circle.length <- NA } q_idx <- q_splitranges[[seqlevel]] s_idx <- s_splitranges[[seqlevel]] hits <- .findOverlaps.circle(circle.length, extractROWS(q_ranges, q_idx), extractROWS(s_ranges, s_idx), maxgap, minoverlap, type) q_hits <- queryHits(hits) s_hits <- subjectHits(hits) compatible_strand <- extractROWS(q_strand, q_idx)[q_hits] * extractROWS(s_strand, s_idx)[s_hits] != -1L hits <- hits[compatible_strand] remapHits(hits, query.map=as.integer(q_idx), new.queryLength=q_len, subject.map=as.integer(s_idx), new.subjectLength=s_len) }) ## Combine the results. q_hits <- unlist(lapply(results, queryHits)) if (is.null(q_hits)) q_hits <- integer(0) s_hits <- unlist(lapply(results, subjectHits)) if (is.null(s_hits)) s_hits <- integer(0) selectHits(Hits(q_hits, s_hits, q_len, s_len), select=select) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### "findOverlaps" methods for GenomicRanges objects ### findOverlaps_GenomicRanges <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { type <- match.arg(type) min.score <- IRanges:::min_overlap_score(maxgap, minoverlap, type) select <- match.arg(select) algorithm <- match.arg(algorithm) if (algorithm != "nclist") warning("'algorithm' is ignored when 'query' or 'subject' ", "is a GNCList object") findOverlaps_GNCList(query, subject, min.score=min.score, type=type, select=select, ignore.strand=ignore.strand) } setMethod("findOverlaps", c("GNCList", "GenomicRanges"), findOverlaps_GenomicRanges ) setMethod("findOverlaps", c("GenomicRanges", "GNCList"), findOverlaps_GenomicRanges ) setMethod("findOverlaps", c("GenomicRanges", "GenomicRanges"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { type <- match.arg(type) select <- match.arg(select) algorithm <- match.arg(algorithm) if (algorithm == "nclist") FUN <- findOverlaps_GenomicRanges else FUN <- findOverlaps_GenomicRanges_old FUN(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type, select=select, ignore.strand=ignore.strand) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### "findOverlaps" methods for GRangesList objects ### .overlap_score <- function(hits, query, subject) { q_ranges <- ranges(query)[queryHits(hits)] s_ranges <- ranges(subject)[subjectHits(hits)] 1L + pmin.int(end(q_ranges), end(s_ranges)) - pmax.int(start(q_ranges), start(s_ranges)) } .aggregated_sum <- function(x, f1, f2) { sm <- S4Vectors:::selfmatchIntegerPairs(f1, f2) S4Vectors:::tabulate2(sm, length(sm), weight=x)[sm] } setMethod("findOverlaps", c("GRangesList", "GRangesList"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { if (!isSingleNumber(maxgap) || maxgap < 0) stop("'maxgap' must be a non-negative integer") type <- match.arg(type) select <- match.arg(select) algorithm <- match.arg(algorithm) unlisted_query <- unlist(query, use.names=FALSE) query_groups <- togroup(query) unlisted_subject <- unlist(subject, use.names=FALSE) subject_groups <- togroup(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)[elementLengths(subject) > 0L] unlisted_subject <- unlisted_subject[keep] subject_groups <- subject_groups[keep] } ans00 <- findOverlaps(unlisted_query, unlisted_subject, maxgap=maxgap, type=type, select="all", algorithm=algorithm, ignore.strand=ignore.strand) if (minoverlap > 1L) { score <- .overlap_score(ans00, unlisted_query, unlisted_subject) score <- .aggregated_sum(score, query_groups[queryHits(ans00)], subject_groups[subjectHits(ans00)]) mcols(ans00) <- DataFrame(score=score) } if (type == "within") { ans01 <- remapHits(ans00, subject.map=subject_groups, new.subjectLength=length(subject)) ans11 <- remapHits(ans01, query.map=query_groups, new.queryLength=length(query), with.counts=TRUE) keep_idx <- which(mcols(ans11)[ , "counts"] == elementLengths(query)[queryHits(ans11)]) mcols(ans11) <- NULL ans <- ans11[keep_idx] } else { ans <- remapHits(ans00, query.map=query_groups, new.queryLength=length(query), subject.map=subject_groups, new.subjectLength=length(subject)) } if (minoverlap > 1L) { keep_idx <- which(mcols(ans)[ , "score"] >= minoverlap) mcols(ans) <- NULL ans <- ans[keep_idx] } selectHits(ans, select=select) } ) setMethod("findOverlaps", c("GRangesList", "GenomicRanges"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { if (!isSingleNumber(maxgap) || maxgap < 0) stop("'maxgap' must be a non-negative integer") type <- match.arg(type) select <- match.arg(select) algorithm <- match.arg(algorithm) unlisted_query <- unlist(query, use.names=FALSE) query_groups <- togroup(query) ans00 <- findOverlaps(unlisted_query, subject, maxgap=maxgap, type=type, select="all", algorithm=algorithm, ignore.strand=ignore.strand) if (minoverlap > 1L) { score <- .overlap_score(ans00, unlisted_query, subject) score <- .aggregated_sum(score, query_groups[queryHits(ans00)], subjectHits(ans00)) mcols(ans00) <- DataFrame(score=score) } if (type == "within") { ans10 <- remapHits(ans00, query.map=query_groups, new.queryLength=length(query), with.counts=TRUE) keep_idx <- which(mcols(ans10)[ , "counts"] == elementLengths(query)[queryHits(ans10)]) mcols(ans10) <- NULL ans <- ans10[keep_idx] } else { ans <- remapHits(ans00, query.map=query_groups, new.queryLength=length(query)) } if (minoverlap > 1L) { keep_idx <- which(mcols(ans)[ , "score"] >= minoverlap) mcols(ans) <- NULL ans <- ans[keep_idx] } selectHits(ans, select=select) } ) setMethod("findOverlaps", c("GenomicRanges", "GRangesList"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { if (!isSingleNumber(maxgap) || maxgap < 0) stop("'maxgap' must be a non-negative integer") type <- match.arg(type) select <- match.arg(select) algorithm <- match.arg(algorithm) unlisted_subject <- unlist(subject, use.names=FALSE) subject_groups <- togroup(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)[elementLengths(subject) > 0L] unlisted_subject <- unlisted_subject[keep] subject_groups <- subject_groups[keep] } ans00 <- findOverlaps(query, unlisted_subject, maxgap=maxgap, type=type, select="all", algorithm=algorithm, ignore.strand=ignore.strand) if(minoverlap > 1L) { score <- .overlap_score(ans00, query, unlisted_subject) score <- .aggregated_sum(score, queryHits(ans00), subject_groups[subjectHits(ans00)]) mcols(ans00) <- DataFrame(score=score) } ans <- remapHits(ans00, subject.map=subject_groups, new.subjectLength=length(subject)) if (minoverlap > 1L) { keep_idx <- which(mcols(ans)[ , "score"] >= minoverlap) mcols(ans) <- NULL ans <- ans[keep_idx] } selectHits(ans, select=select) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Other "findOverlaps" methods ### ### WARNING: Unlike most findOverlaps() methods, this method returns a Hits ### object 'ans' that is *not* consistent with 'query', in the sense that ### 'queryHits(ans)' is not a valid index into 'query'. ### Seems that the only use case for this method was to support the method ### for c("RangedData", "GenomicRanges"). ### TODO: Deprecate after RangedData is gone. setMethod("findOverlaps", c("RangesList", "GenomicRanges"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(as(query, "GRanges"), subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) ### WARNING: Unlike most findOverlaps() methods, this method returns a Hits ### object 'ans' that is *not* consistent with 'query', in the sense that ### 'queryHits(ans)' is not a valid index into 'query'. ### Seems that the only use case for this method was to support the method ### for c("RangedData", "GRangesList"). ### TODO: Deprecate after RangedData is gone. setMethod("findOverlaps", c("RangesList", "GRangesList"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(as(query, "GRanges"), subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) ### WARNING: Unlike most findOverlaps() methods, this method returns a Hits ### object 'ans' that is *not* consistent with 'subject', in the sense that ### 'subjectHits(ans)' is not a valid index into 'subject'. ### Seems that the only use case for this method was to support the method ### for c("GenomicRanges", "RangedData"). ### TODO: Deprecate after RangedData is gone. setMethod("findOverlaps", c("GenomicRanges", "RangesList"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(query, as(subject, "GRanges"), maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) ### WARNING: Unlike most findOverlaps() methods, this method returns a Hits ### object 'ans' that is *not* consistent with 'subject', in the sense that ### 'subjectHits(ans)' is not a valid index into 'subject'. ### Seems that the only use case for this method was to support the method ### for c("GRangesList", "RangedData"). ### TODO: Deprecate after RangedData is gone. setMethod("findOverlaps", c("GRangesList", "RangesList"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(query, as(subject, "GRanges"), maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("findOverlaps", c("RangedData", "GenomicRanges"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { ## Calls "findOverlaps" method for c("RangesList", "GenomicRanges") ## defined above. findOverlaps(ranges(query), subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("findOverlaps", c("RangedData", "GRangesList"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { ## Calls "findOverlaps" method for c("RangesList", "GRangesList") ## defined above. findOverlaps(ranges(query), subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("findOverlaps", c("GenomicRanges", "RangedData"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { ## Calls "findOverlaps" method for c("GenomicRanges", "RangesList") ## defined above. findOverlaps(query, ranges(subject), maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("findOverlaps", c("GRangesList", "RangedData"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { ## Calls "findOverlaps" method for c("GRangesList", "RangesList") ## defined above. findOverlaps(query, ranges(subject), maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) ### WARNING: Unlike most findOverlaps() methods, the methods for ### SummarizedExperiment below return a Hits object 'ans' that is *not* ### consistent with 'query' (or 'subject'), in the sense that 'queryHits(ans)' ### (or 'subjectHits(ans)') is not a valid index into 'query' (or 'subject') ### when 'query' (or 'subject') is a SummarizedExperiment object. setMethod("findOverlaps", c("SummarizedExperiment", "Vector"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(rowRanges(query), subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("findOverlaps", c("Vector", "SummarizedExperiment"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(query, rowRanges(subject), maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("findOverlaps", c("SummarizedExperiment", "SummarizedExperiment"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { findOverlaps(rowRanges(query), rowRanges(subject), maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select=match.arg(select), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) ### ========================================================================= ### findOverlaps-based methods ### ------------------------------------------------------------------------- countOverlaps_GenomicRanges <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { type <- match.arg(type) min.score <- IRanges:::min_overlap_score(maxgap, minoverlap, type) algorithm <- match.arg(algorithm) if (algorithm != "nclist") warning("'algorithm' is ignored when 'query' or 'subject' ", "is a GNCList object") ans <- findOverlaps_GNCList(query, subject, min.score=min.score, type=type, select="count", ignore.strand=ignore.strand) names(ans) <- names(query) ans } setMethod("countOverlaps", c("GNCList", "GenomicRanges"), countOverlaps_GenomicRanges ) setMethod("countOverlaps", c("GenomicRanges", "GNCList"), countOverlaps_GenomicRanges ) countOverlaps.definition <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { counts <- queryHits(findOverlaps(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), algorithm=algorithm, ignore.strand=ignore.strand)) structure(tabulate(counts, NROW(query)), names=names(query)) } setMethod("countOverlaps", c("GenomicRanges", "GenomicRanges"), function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { type <- match.arg(type) algorithm <- match.arg(algorithm) if (algorithm == "nclist") { countOverlaps_GenomicRanges(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type, ignore.strand=ignore.strand) } else { countOverlaps.definition(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=type, algorithm=algorithm, ignore.strand=ignore.strand) } } ) .signatures1 <- list( c("GenomicRanges", "Vector"), c("Vector", "GenomicRanges"), c("GRangesList", "Vector"), c("Vector", "GRangesList"), c("GRangesList", "GRangesList"), c("GRanges", "GRangesList"), c("GRangesList", "GRanges"), c("SummarizedExperiment", "Vector"), c("Vector", "SummarizedExperiment"), c("SummarizedExperiment", "SummarizedExperiment") ) setMethods("countOverlaps", .signatures1, countOverlaps.definition) overlapsAny.definition <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { !is.na(findOverlaps(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), select="arbitrary", algorithm=match.arg(algorithm), ignore.strand=ignore.strand)) } subsetByOverlaps.definition1 <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { i <- overlapsAny(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) extractROWS(query, i) } .subsetByOverlaps.definition2 <- function(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { i <- overlapsAny(query, subject, maxgap=maxgap, minoverlap=minoverlap, type=match.arg(type), algorithm=match.arg(algorithm), ignore.strand=ignore.strand) query[splitAsList(i, space(query), drop=FALSE)] } .signatures2 <- list( c("GenomicRanges", "GenomicRanges"), c("GRangesList", "GenomicRanges"), c("GenomicRanges", "GRangesList"), c("GRangesList", "GRangesList"), c("RangesList", "GenomicRanges"), c("RangesList", "GRangesList"), c("GenomicRanges", "RangesList"), c("GRangesList", "RangesList"), c("RangedData", "GenomicRanges"), c("RangedData", "GRangesList"), c("GenomicRanges", "RangedData"), c("GRangesList", "RangedData"), c("SummarizedExperiment", "Vector"), c("Vector", "SummarizedExperiment"), c("SummarizedExperiment", "SummarizedExperiment") ) for (sig in .signatures2) { setMethod("overlapsAny", sig, overlapsAny.definition) if (sig[1L] == "RangesList") setMethod("subsetByOverlaps", sig, .subsetByOverlaps.definition2) else setMethod("subsetByOverlaps", sig, subsetByOverlaps.definition1) } GenomicRanges/R/genomicvars.R0000644000175100017510000001271312607265136017170 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) { rd <- as(from, "RangedData") rd$strand <- "*" gr <- as(rd, "GRanges") seqlengths(gr) <- elementLengths(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 <- newGRanges("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) { 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) { means <- viewMeans(v) w0 <- width(v) w1 <- width(trim(v)) 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) }) new_mcol <- unsplit(means_list, as.factor(seqnames(bins))) mcols(bins)[[varname]] <- new_mcol bins } GenomicRanges/R/inter-range-methods.R0000644000175100017510000002270312607265136020527 0ustar00biocbuildbiocbuild### ========================================================================= ### Inter-range methods ### ------------------------------------------------------------------------- ### ### The methods documented in this page on this page are consistent with ### those in IRanges inter-range-methods.R ### range() ### reduce() ### gaps() ### disjoin() ### isDisjoint() ### disjointBins() .interIntervalSplitVariable <- function(x, ignore.strand=FALSE) { f1 <- seqnames(x) runValue(f1) <- 3L * (as.integer(runValue(f1)) - 1L) if (ignore.strand) return(f1) f2 <- strand(x) runValue(f2) <- as.integer(runValue(f2)) - 1L f1 + f2 } ### '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". .translateRevmap <- 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 } .interIntervalGenomicRanges2 <- function(x, FUN, with.revmap=FALSE, ignore.strand=FALSE, ...) { x <- clone(x) mcols(x) <- NULL f <- .interIntervalSplitVariable(x, ignore.strand=ignore.strand) xIRangesList <- split(unname(ranges(x)), f) if (with.revmap) { ansIRangesList <- FUN(xIRangesList, with.revmap=with.revmap, ...) } else { ansIRangesList <- FUN(xIRangesList, ...) } k <- elementLengths(ansIRangesList) x_seqlevels <- seqlevels(x) strand_levels <- levels(strand()) ansIRangesList_names <- as.integer(names(ansIRangesList)) i1 <- ansIRangesList_names %/% 3L + 1L ans_seqnames <- Rle(factor(x_seqlevels[i1], levels=x_seqlevels), k) if (ignore.strand) { ans_strand <- Rle(strand("*"), sum(k)) } else { i2 <- ansIRangesList_names %% 3L + 1L ans_strand <- Rle(factor(strand_levels[i2], levels=strand_levels), k) } ans_ranges <- unlist(ansIRangesList, use.names=FALSE) ans_mcols <- mcols(ans_ranges) if (is.null(ans_mcols)) { ans_mcols <- new("DataFrame", nrows=length(ans_seqnames)) } else { mcols(ans_ranges) <- NULL if (with.revmap) { revmap_unlisted <- ans_mcols[["revmap"]] revmap_partitioning <- PartitioningByEnd(ansIRangesList) old2new <- splitAsList(seq_along(x), f) revmap_unlisted2 <- .translateRevmap(revmap_unlisted, revmap_partitioning, old2new) ans_mcols[["revmap"]] <- revmap_unlisted2 } } if (length(extraColumnSlotNames(x)) > 0L) x <- granges(x) update(x, seqnames=ans_seqnames, ranges=ans_ranges, strand=ans_strand, elementMetadata=ans_mcols) } .interIntervalGenomicRanges <- function(x, FUN, ignore.strand=FALSE, ...) { x <- clone(x) mcols(x) <- NULL if (ignore.strand) f <- paste(seqnames(x), Rle(factor("*"), length(x)), sep="\r") else f <- paste(seqnames(x), strand(x), sep="\r") xIRangesList <- split(unname(ranges(x)), f) ansIRangesList <- FUN(xIRangesList, ...) k <- elementLengths(ansIRangesList) splitListNames <- strsplit(names(ansIRangesList), split="\r", fixed=TRUE) listNameMatrix <- matrix(as.character(unlist(splitListNames)), nrow=2L) ansSeqnames <- Rle(factor(listNameMatrix[1L, ], levels=seqlevels(x)), k) ansStrand <- Rle(strand(listNameMatrix[2L, ]), k) if (length(extraColumnSlotNames(x)) > 0L) x <- granges(x) update(x, seqnames=ansSeqnames, ranges=unlist(ansIRangesList, use.names=FALSE), strand=ansStrand, elementMetadata=new("DataFrame", nrows=length(ansSeqnames))) } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### range() ### setMethod("range", "GenomicRanges", function(x, ..., ignore.strand=FALSE, na.rm=FALSE) .interIntervalGenomicRanges2(unname(c(x, ...)), range, ignore.strand=ignore.strand) ) setMethod("range", "GRangesList", function(x, ..., ignore.strand=FALSE, na.rm=FALSE) { gr <- deconstructGRLintoGR(x) ## "range" method for GRanges objects is fast. gr <- range(gr, ..., ignore.strand=ignore.strand, na.rm=na.rm) reconstructGRLfromGR(gr, x) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### reduce() ### 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") if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(x) <- "*" .interIntervalGenomicRanges2(x, reduce, drop.empty.ranges=drop.empty.ranges, min.gapwidth=min.gapwidth, with.revmap=with.revmap) } ) ### TODO: Support the 'with.revmap' argument. setMethod("reduce", "GRangesList", function(x, drop.empty.ranges=FALSE, min.gapwidth=1L, 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) ## "reduce" method for GRanges objects is fast. gr <- reduce(gr, drop.empty.ranges=drop.empty.ranges, min.gapwidth=min.gapwidth, ignore.strand=ignore.strand) reconstructGRLfromGR(gr, x) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### gaps() ### 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) .interIntervalGenomicRanges(x, gaps, start=start, end=end) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### disjoin() ### setMethod("disjoin", "GenomicRanges", function(x, ignore.strand=FALSE) .interIntervalGenomicRanges2(x, disjoin, ignore.strand=ignore.strand) ) setMethod("disjoin", "GRangesList", function(x, ignore.strand=FALSE) { gr <- deconstructGRLintoGR(x) d <- disjoin(gr, ignore.strand=ignore.strand) reconstructGRLfromGR(d, x) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### isDisjoint() ### .applyOnRangesBySpace <- function(x, FUN, ..., ignore.strand = FALSE) { if (ignore.strand) f <- seqnames(x) else f <- paste(seqnames(x), strand(x), sep = "\r") xIRangesList <- split(unname(ranges(x)), f) ans <- FUN(xIRangesList, ...) if (is(ans, "List")) # values per range, otherwise assumed to be per-space ans <- unsplit(ans, f) ans } setMethod("isDisjoint", "GenomicRanges", function(x, ignore.strand=FALSE) { all(.applyOnRangesBySpace(x, isDisjoint, ignore.strand = ignore.strand)) } ) setMethod("isDisjoint", "GRangesList", function(x, ignore.strand = FALSE) { gr <- deconstructGRLintoGR(x) if (ignore.strand) xIRangesList <- split(unname(ranges(gr)), paste(seqnames(gr), Rle(factor(rep("+", length(gr)))), sep = "\r")) else xIRangesList <- split(unname(ranges(gr)), paste(seqnames(gr), strand(gr), sep = "\r")) ansIRanges <- isDisjoint(xIRangesList) splitListNames <- strsplit(names(ansIRanges), split="\r") snames <- strsplit(unlist(lapply(splitListNames, "[[", 1L)), "|", fixed=TRUE) m12 <- matrix(as.integer(unlist(snames)), ncol=2, byrow=TRUE) ansIRangesList <- split(ansIRanges, factor(m12[, 1L], levels=seq_len(length(x)))) ans <- unlist(lapply(ansIRangesList, all)) names(ans) <- names(x) ans } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### disjointBins() ### setMethod("disjointBins", "GenomicRanges", function(x, ignore.strand = FALSE) { .applyOnRangesBySpace(x, disjointBins, ignore.strand = ignore.strand) }) GenomicRanges/R/intra-range-methods.R0000644000175100017510000002415512607265136020526 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) clone(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) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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) clone(x, ranges=new_ranges) } ) 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) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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) clone(x, ranges=new_ranges) } ) 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) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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) clone(x, ranges=new_ranges) } ) 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) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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 } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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", "GRangesList", 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) clone(x, ranges=new_ranges) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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.R0000644000175100017510000002266012607265136021432 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=FALSE' 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) } ### '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.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 <- df[[granges_cols[["start"]]]] ans_end <- df[[granges_cols[["end"]]]] if (!is.numeric(ans_start) || !is.numeric(ans_end)) stop("\"", names(df)[granges_cols[["start"]]], "\" and ", "\"", names(df)[granges_cols[["end"]]], "\" columns ", "must be numeric") 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/mapCoords-methods.R0000644000175100017510000001001212607265136020231 0ustar00biocbuildbiocbuild### ========================================================================= ### 'mapCoords' and 'pmapCoords' methods ### ------------------------------------------------------------------------- ### ### Generics are in IRanges. ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Helpers ### ### 'x' is a GRangesList ### Returns a GRangesList with sorted elements. This method differs from ### sort() in that "-" strand elements are returned highest value to lowest. .orderElementsByTranscription <- function(x, ignore.strand) { original <- unlist(sapply(elementLengths(x), function(xx) 1:xx), use.names=FALSE) ## order by position gr <- unlist(x, use.names = FALSE) idx <- order(togroup(x), start(gr)) gr <- gr[idx] part <- PartitioningByWidth(x) ## handle zero-width ranges pstart <- start(part)[width(part) != 0L] pend <- end(part)[width(part) != 0L] if (ignore.strand) { ord <- S4Vectors:::mseq(pstart, pend) } else { neg <- strand(gr)[pstart] == "-" ord <- S4Vectors:::mseq(ifelse(neg, pend, pstart), ifelse(neg, pstart, pend)) } res <- relist(gr[ord], x) res@unlistData$unordered <- original[idx[ord]] res } ### 'x' is an IntegerList or NumericList ### Returns a numeric vector of cumulative sums within list elements. .listCumsumShifted <- function(x) { cs <- unlist(cumsum(x), use.names=FALSE) shifted <- c(0L, head(cs, -1)) shifted[start(PartitioningByWidth(elementLengths(x)))] <- 0L shifted } .mapCoords <- function(from, to, ..., ignore.strand, elt.hits, p=FALSE) { if (ignore.strand) strand(to) <- "*" ## sort elements of 'to' by chrom, position and strand to <- .orderElementsByTranscription(to, ignore.strand=ignore.strand) gr <- unlist(to, use.names = FALSE) ## overlaps ol <- findOverlaps(from, gr, type="within", ignore.strand=ignore.strand) if (p) { ith_hits <- queryHits(ol) == togroup(to)[subjectHits(ol)] ol <- ol[ith_hits] } sHits <- subjectHits(ol) qHits <- queryHits(ol) eltPosition <- ranges(from)[qHits] bounds <- ranges(gr)[sHits] ## location wrt start of individual list elements if (ignore.strand) { eltPosition <- shift(eltPosition, - start(bounds)) } else { neg <- as.vector(strand(gr)[sHits] == "-") eltPosition[!neg] <- shift(eltPosition[!neg], - start(bounds)[!neg]) eltPosition[neg] <- IRanges(end(bounds)[neg] - end(eltPosition)[neg], width=width(eltPosition)[neg]) } ## location wrt start of combined list elements (e.g., transcript-level) shifted <- .listCumsumShifted(width(to)) cumPosition <- shift(eltPosition, 1L + shifted[sHits]) toInd <- togroup(to)[sHits] if (elt.hits) mcols <- DataFrame(fromHits=qHits, toHits=toInd, eltHits=mcols(gr)$unordered[subjectHits(ol)]) else mcols <- DataFrame(fromHits=qHits, toHits=toInd) GRanges(seqnames(gr)[sHits], cumPosition, strand = strand(gr[sHits]), mcols) } ### mapCoords: .msg <- c("'mapCoords' is defunct. ", "Use 'mapToTranscripts' from the GenomicFeatures package ", "or 'mapToAlignments' from the GenomicAlignments package ", "instead.") setMethod("mapCoords", c("GenomicRanges", "GRangesList"), function(from, to, ..., ignore.strand=TRUE, elt.hits=FALSE) .Defunct(msg=wmsg(.msg)) ) setMethod("mapCoords", c("GenomicRanges", "GenomicRanges"), function(from, to, ..., ignore.strand=TRUE, elt.hits=FALSE) .Defunct(msg=wmsg(.msg)) ) ### pmapCoords: setMethod("pmapCoords", c("GenomicRanges", "GRangesList"), function(from, to, ..., ignore.strand=TRUE, elt.hits=FALSE) { msg <- c("'pmapCoords' is defunct. ", "Use 'pmapToTranscripts' from the GenomicFeatures package ", "or 'pmapToAlignments' from the GenomicAlignments package ", "instead.") .Defunct(msg=wmsg(msg)) }) GenomicRanges/R/nearest-methods.R0000644000175100017510000003053712607265136017761 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 { sentinelidx <- length(subject) + seq_along(sentinel) subject <- c(subject, sentinel) ord <- .orderNumeric(subject) subject <- subject[ord] rle <- Rle(subject) subject <- runValue(rle) i <- findInterval(query - !leftOf, subject) + leftOf 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 <- S4Vectors:::orderIntegerPairs(queryHits, subjectHits) Hits(queryHits[o], subjectHits[o], queryLength, subjectLength) } .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(queryLength=length(query), subjectLength=length(subject))) 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) != "+") ## '+' 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)]) ## '-' 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)]) ### '*' query equivalent to ignore.strand = TRUE idx <- which(strand(query) == "*") bhit <- local({ qid <- qid[idx] phit <- plusfun(queryStart[idx], queryEnd[idx], subjectStart, subjectEnd, sentinel) .Hits(qid[queryHits(phit)], subjectHits(phit), length(query), length(subject)) }) ## clean up qryHits <- c(queryHits(phit), queryHits(mhit), queryHits(bhit)) subjHits <- c(subjectHits(phit), subjectHits(mhit), subjectHits(bhit)) if ("arbitrary" == select) { hits <- integer() hits[length(query)] <- NA_integer_ idx <- !duplicated(qryHits) ## ties hits[qryHits[idx]] <- subjHits[idx] } else { hits <- .Hits(qryHits, subjHits, length(query), length(subject)) } hits } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### precede() and follow() ### setMethod("precede", c("GenomicRanges", "GenomicRanges"), function(x, subject, select=c("arbitrary", "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("arbitrary", "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("arbitrary", "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("arbitrary", "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, algorithm, ignore.strand, ignoreSelf=FALSE) { ## overlapping ranges if (ignoreSelf) { ol <- findOverlaps(x, select=select, algorithm=algorithm, ignore.strand=ignore.strand, ignoreSelf=TRUE) } else { ol <- findOverlaps(x, subject, select=select, algorithm=algorithm, 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) { 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(queryLength=length(x), subjectLength=length(subject))) 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="first") } ## 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[S4Vectors:::orderIntegerPairs(m[, 1L], m[, 2L]),, drop=FALSE] ol@queryHits <- unname(m[, 1L]) ol@subjectHits <- 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"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { select <- match.arg(select) .nearest(x, subject, select=select, algorithm=match.arg(algorithm), ignore.strand=ignore.strand) } ) setMethod("nearest", c("GenomicRanges", "missing"), function(x, subject, select=c("arbitrary", "all"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) { select <- match.arg(select) .nearest(x, x, select=select, algorithm=match.arg(algorithm), ignore.strand=ignore.strand, ignoreSelf=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, algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE, ...) { x_nearest <- nearest(x, subject, algorithm=match.arg(algorithm), ignore.strand=ignore.strand, ...) .distanceToNearest(x_nearest, x, subject, ignore.strand=ignore.strand) } ) setMethod("distanceToNearest", c("GenomicRanges", "missing"), function(x, subject, algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE, ...) { x_nearest <- nearest(x, algorithm=match.arg(algorithm), 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(queryLength=length(x), subjectLength=length(subject), distance=integer(0)) } else { distance <- distance(x[queryHits], subject[subjectHits], ignore.strand=ignore.strand) Hits(queryHits, subjectHits, length(x), length(subject), distance) } } GenomicRanges/R/phicoef.R0000644000175100017510000000153112607265136016264 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/range-squeezers.R0000644000175100017510000000161012607265136017765 0ustar00biocbuildbiocbuild### ========================================================================= ### Generic functions for squeezing the ranges out of a range-based object ### ------------------------------------------------------------------------- ### Extract the ranges as a GRanges object. setGeneric("granges", signature="x", function(x, use.mcols=FALSE, ...) standardGeneric("granges") ) ### Extract the ranges as a GRangesList object. setGeneric("grglist", signature="x", function(x, use.mcols=FALSE, ...) standardGeneric("grglist") ) ### Extract the ranges as a RangesList object. ### TODO: This one should probably be in IRanges together with ranges(), which ### is another range-squeezer. ### TODO: For consistency the ranges() generic should also get the 'use.mcols' ### arg with default to FALSE. setGeneric("rglist", signature="x", function(x, use.mcols=FALSE, ...) standardGeneric("rglist") ) GenomicRanges/R/setops-methods.R0000644000175100017510000004275712607265136017644 0ustar00biocbuildbiocbuild### ========================================================================= ### Set operations ### ------------------------------------------------------------------------- ### TODO: What's the impact of circularity on the set operations? ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 2 low-level helper functions. ### ### 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[elementLengths(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[elementLengths(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() ### setMethod("union", c("GRanges", "GRanges"), function(x, y, ignore.strand=FALSE, ...) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(x) <- strand(y) <- "*" mcols(x) <- mcols(y) <- NULL # so we can do 'c(x, y)' below reduce(c(x, y), drop.empty.ranges=TRUE) } ) setMethod("intersect", c("GRanges", "GRanges"), function(x, y, ignore.strand=FALSE, ...) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(x) <- strand(y) <- "*" mcols(x) <- mcols(y) <- NULL 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)) } ) setMethod("setdiff", c("GRanges", "GRanges"), function(x, y, ignore.strand=FALSE, ...) { if (!isTRUEorFALSE(ignore.strand)) stop("'ignore.strand' must be TRUE or FALSE") if (ignore.strand) strand(x) <- strand(y) <- "*" mcols(x) <- mcols(y) <- NULL 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) } ) ### ========================================================================= ### 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), elementLengths(x)), Rle(seq_len(n)))) names(ans) <- names(x) ans } ) setMethod("punion", c("GRanges", "GRangesList"), function(x, y, fill.gap=FALSE, ...) { 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, elementLengths(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) ) ### Equivalent to 'mendoapply(intersect, x, y)'. setMethod("pintersect", c("GRangesList", "GRangesList"), function(x, y, ...) { 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) gr <- intersect(xgr, ygr, ...) reconstructGRLfromGR(gr, x) } ) ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### 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), elementLengths(y)), seqnames(y@unlistData)) if (!ignore.strand) ok <- ok & compatibleStrand(rep(strand(x), elementLengths(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), elementLengths(ansRanges)) ansStrand <- rep(strand(x), elementLengths(ansRanges)) ansGRanges <- GRanges(ansSeqnames, unlist(ansRanges, use.names=FALSE), ansStrand) seqinfo(ansGRanges) <- ansSeqinfo relist(ansGRanges, PartitioningByEnd(ansRanges)) } ) ### Equivalent to 'mendoapply(setdiff, x, y)'. setMethod("psetdiff", c("GRangesList", "GRangesList"), function(x, y, ...) { 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) gr <- setdiff(xgr, ygr, ...) reconstructGRLfromGR(gr, x) } ) 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) <- pgap(ranges(x), ranges(y)) x } ) GenomicRanges/R/strand-utils.R0000644000175100017510000001065512607265136017307 0ustar00biocbuildbiocbuild### ========================================================================= ### Strand utilities ### ------------------------------------------------------------------------- ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Some "strand" and "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", "DataTable", function(x) { ans <- x[["strand"]] if (is.null(ans)) { ans <- rep.int(strand("*"), nrow(x)) } else { ans <- strand(ans) } ans } ) setReplaceMethod("strand", "DataTable", function(x, value) { x$strand <- normargGenomicRangesStrand(value, nrow(x)) 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/test_GenomicRanges_package.R0000644000175100017510000000010012607265136022071 0ustar00biocbuildbiocbuild.test <- function() BiocGenerics:::testPackage("GenomicRanges") GenomicRanges/R/tile-methods.R0000644000175100017510000000071512607265136017250 0ustar00biocbuildbiocbuild### ========================================================================= ### "tile" methods ### ------------------------------------------------------------------------- ### setMethod("tile", "GenomicRanges", function(x, n, width) { sn <- seqnames(x) strand <- strand(x) x <- ranges(x) tiles <- callGeneric() gr <- GRanges(rep(sn, elementLengths(tiles)), unlist(tiles), rep(strand, elementLengths(tiles))) relist(gr, tiles) }) GenomicRanges/R/tileGenome.R0000644000175100017510000001456712607265136016754 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 <- elementLengths(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.R0000644000175100017510000000342612607265137020204 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. ### elementLengths() 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.R0000644000175100017510000000330112607265136016004 0ustar00biocbuildbiocbuild### ========================================================================= ### Some low-level (non exported) utility functions. ### ------------------------------------------------------------------------- ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Used by "elementMetadata<-" methods. ### ### Try to turn 'value' into a DataFrame compatible with 'x'. ### Used in GenomicAlignments package. normalizeMetadataColumnsReplacementValue <- function(value, x) { if (is.null(value)) return(new("DataFrame", nrows=length(x))) if (!is(value, "DataFrame")) value <- DataFrame(value) if (!is.null(rownames(value))) rownames(value) <- NULL n <- length(x) k <- nrow(value) if (k == n) return(value) if ((k == 0L) || (k > n) || (n %% k != 0L)) stop(k, " rows in value to replace ", n, " rows") value[rep(seq_len(k), length.out=n), , drop=FALSE] } ### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ### Other stuff... ### 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.R0000644000175100017510000000013312607265137015502 0ustar00biocbuildbiocbuild### .onUnload <- function(libpath) { library.dynam.unload("GenomicRanges", libpath) } GenomicRanges/build/0000755000175100017510000000000012607330121015405 5ustar00biocbuildbiocbuildGenomicRanges/build/vignette.rds0000644000175100017510000000112112607330121017737 0ustar00biocbuildbiocbuildSo0NS7uZ5)#=L{7:&vѽ !a"MQwwﳿU,˲m[vA- sުz)Dtx w@vc@9ED:~ OHpoW֟$dGenomicRanges/inst/0000755000175100017510000000000012607330121015263 5ustar00biocbuildbiocbuildGenomicRanges/inst/CITATION0000644000175100017510000000165412607265137016444 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/0000755000175100017510000000000012607330121016030 5ustar00biocbuildbiocbuildGenomicRanges/inst/doc/ExtendingGenomicRanges.R0000644000175100017510000000234612607330121022547 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.Rnw0000644000175100017510000001113712607330121023112 0ustar00biocbuildbiocbuild% \VignetteIndexEntry{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.pdf0000644000175100017510000031120612607330121023115 0ustar00biocbuildbiocbuild%PDF-1.5 % 23 0 obj << /Length 2780 /Filter /FlateDecode >> stream xZIϯhDb ;#FedzȞ!!nb93y[UW)aw-^{ Geި2]F.ό.suVMnM.z;>+y~~UT^*UUe8慩wohgң+[[ct[Nm9|޵`t гySͪ*׶fu0_t̚bvj#y'~3SM;Fa+otHt,e3Z)*'R$nz:sNQᏃϟxGyCb}3mϖ 7MTQa[qnu03%et\B;(IBAw)g.kw4e^r`_Z5qz} w"%n|23[Ov- ^R: p>ģ"~{c}ZI #;\M-A"#i鷴;c,py'8 Z8{hЋ-kD.dB3h48 qc!4rywo+mI5ư3L3Bq)r/a@(Oi9N#F 9e%\F*;q)yF8g#)gΫ! @w+RC AM[#I鋖h+#f>xS5hu@$tXeDk#mf Y1>̄Fn~Sڲ0尣TE^`]zZx3jK2cݱ/M*h6saҶ\z}-vQ=Mc! 9j0 Y/`(<Ǧ3fcEahNt6v=㪶yc\*rHI0e꼮X3C2\CXc: ƖMtYRI(hf8=oUa8\hSp3s u cocBKh=O)T3O/:Kv(瞸!4 p/qiJ 5Ɩӓ ry=?ݓ`#Jn!ډT$d b^ b: _>mQ)RPh(U))+obtmҫ6Hߠ#7VG[rltd< Ec07h4}A8"猞NB"`_ <CJEHԦɌ)ʄNN9!I\J-qR H*CaԃCw t+^|a>1]^҆|wRݨ#"Y4a F3FSy39*P ep x$՘eXq5jL}exHrDd[41`P`'Fxh"qNPس,zGi>to5u|B20Ӈ\|?$<,=еr3"1w0~Ώh" k'h>zNjcccxӐjQ !?Buζ>$8`jz^+"@:l\3S"/(>IfQ]~-kt%KNHbk9ӹA:T xXC83Wj [B_ ņp;I2*Wx IC^C0ٚ-+KT ?0~iJ ј&*BU`ޤ[Sw+Z(a3rP_BlU @@=gY/|j[6{OX S>}">? d ;uw Ÿ߬dTnjRt@*2֩T9J֓bڔKymqHaFߺP.C)7cCNwiLCmD. vQ ]5ni~]ZW./}_]e;q3|!2{YL&l0:.,@N/-zIVB7z)_/AfvU+&}a)K;9 45p"}:FcW;NMW`*{l$?\~>\^J^2e{EMG1(J\0M2\h,am> stream xYK`J`P9.+r*V*&9H:`IxA Kٕ~`drGwO?&I4yu񗫋?}&BrZex%VEj1y;}y'zgՓWTT$L"Fiof,l_!GpLeSX^ 945cV-DO\v8X;KX8D-K`fȹhhlx.J#:Gf53ULW4s3]YM~`Euplne?sxx^>8z8B-ADEIКS$[xN!blYVz|#|#*6!(+BI1[q * $u @k8P4Ċ=iP[& lhHs_DF #SߎyCxQOE͉ Q q,^%zixǦQYF}%jE!z[)Xns݈L7$I)VTsz퍬yz!k'UY7o%Kg'⺽hozC5X1)A' 6:J2rWgSB,E|/XyyTC @9'5j*+^jW2; ] křuEh: ̑N8'ARNcMoyQе<(U(ppjQ~8:,cAL̻g);mo\ _W>7h>YlO_Q^!~J8hc>9H#~l\ܡ0L;ـ7bSڭ~돧/̟LBN3DSPۑ :$[D2]O22Lc5̴ziYvr-s&s4]nY` i? ӿoDrP{q* f<ԁ L=݈bf 3(oP{űrCQC洁 }o~&ly%ޣ+~G @lpz|ZMgath5<˾c{+3U ߟh=,8mo `7c]Bcv=>pʍo"\f ݣtn`Txd/w.oyy4%QI7 JЬƉ5L%~Ņ F CGq JdlVlStڰS(c:*rgxO`Zn1owFZ3[x]r{7k3oGAyREa'$E˃ɛx㟼i ̸luӬM}"ǙXnQ$<=AvH{G+-H3]ӀD!i|'\/$*FLvm=:tn|-x=-0f:3;'Ձk5Nx *#"Fj&l g$PeZw>PlĩZtI>mXrtbOww ä6:ӷ\ZEQ<-!k3;͹;x,oGkOUtA6a $ڌX[=rt,R,,{`:2kiZ $d9t͕>1rj޷h>d:V]!H7R[/KJnƚ{ (~¿[Dc!1A\CHbqiyZzE%p2>0R2~4^M{ 1oqE~|Χs@rv99Ub׊K$ ­E]jqk msJ <,Gi5_MI{M3U^Ig[m筂ݝƍ G"'LFH'SAU_iόGJ!3wýq!Ju[;=7M308*-BSב/GV WSMzpc{ŮkBߵ,рH_?8kBfZơp6i endstream endobj 48 0 obj << /Length 708 /Filter /FlateDecode >> stream xڅUMs0Whr23AHHCg&q3! ƞchzKb!&ww -d*|M2Ie2Ay޾uL[j/M<:a"I rL)r gƣ < Ae kAc֝sGԅi'mU`S9,ܖQq@d2]>{Ah^@~":h _im J\kG4 ]’ IAE ȢXg+j WQ8ϬĨ767G6B,;ljJmTi ջUr05yN5sַ«3Qu?Q*a=(Uc7Ŷw&6Ӧektt2apgFxDToCs+-xIS8p:b<_>h.m5-}7R;HXiY8`LV֧v~y•G>z޽[q;pJqM86y-}g)lOs =ucKZ$phm3kk;ܽKve~- c`|L̪T_4? "jK-;̞ݮ1r \Jh*SU!pu2)otSzm\M]-ΓZ(q'پ2z; endstream endobj 51 0 obj << /Length 104 /Filter /FlateDecode >> stream x313T0P04W0#S#CB.)T&9ɓK?\K(̥PRTʥ`ȥm``P73`v(PՓ+ L5* endstream endobj 63 0 obj << /Length1 1975 /Length2 11369 /Length3 0 /Length 12575 /Filter /FlateDecode >> stream xڍuT.L7HH# ]RC7CwwwwIttwtJ\>k֚y_;Jƶ [0#+ @T^UNM†DIf Qjmm%#_ib@𫨼 @ `ccaWց t673dlm@HvnfWO}XyyR[̍6y dhP52{30؎Ņ hd`*Hp1T@ g1w5䘐(jfTmM.@`enq|Ur19^Tv `<V&G!sFFv@7sS(!v36ƿV@gU ae5dh`nvdr4%o31ـ~'f2z?-uMmM~bdǬncn+ p6d1vf5  @^f/Bbe Ss?_ 8tX^ϓXZR$[D`dcgprx^k7J@/6&޿x-3qxg{hAuA?[b o+[$deE?@ks+ȼuIm_W cs'+ .32qpM6w0w+Ճ H0)^786/u׫MdnH, `}]Yc_S`f^3: n-'Y7o `xb nV`^W=Yb0AV4AVЫ?ջzMf1#[*bm3  z2S׬L^ȫMښ `/6mʴ{=6;9kN`ܱR*kl v|,̮~3FNs_r!-Z0`Ryq"@bgYFȑw͓%4l&X- K(b+ %FpT^ f ./%@)i(j-ϻ;}{E8BJDYZ^RV|pӃb,!)2]2ȍǷX3">H3CB2n._s.o)qN$fOFZ\ǦfQR-M\̤~Fgs rMIќ`NvO(D Γ 3= ni:ƿyۑQq&4&Qqb@uV2xҏӤn̾Pigm&nQ/N:iuWV׏OǕ}t?C<Ʈ/\F!.7>?Op>%C "EC6mQc=:9E雒jx,mmje=Qy6\̔"ŌLn;ώ4hpĴLhzw*Z,\0oM+b;o840>9!导#SSՎ|zI{\L3qRƵQaxuAF 򛼂/w2^= ƽOAKŰ"L1%i~'%e/ -DBϟ9C#S uM:G"tFWlߌb]Qc e; "!Qڝ ,#A9R~d39H=Q,&mb:߳P!ȆwfK;d>պڮ &1rXM~6rpIAZewTPBH]M Mw#̅v"٧|8VC7B踑 bNŏ}kw߿l*.eR0,r" Oh1 ̼ʃ0lq?^ SC=zYMui5(%Sŧ3 /0^(G)Y "M|s\'5s=ʋ|?>:.AwʣC}R|L-#巟VvDxn KIbhF$tui::Ժ~ciX1) FŒkEɜ?(c^ ,RIŸS5`(VH$1}V90hG7S34 !qg*Η iS@Q+H ,7餤Qp7DJsx܊xG1€_@;NNAS;wCMQ G>O;apJ]4` =MX6%#jl+L]jo>P b^BnS w~U' a4SօS#kY/N ''uDk \2:I3#/)|eJ鞡o:{pne:hpQx6kAÆ5IMouU8lzEIasevJʬFrE1[)$}#'}뽟Xwe8Wzk^0™ņ^seݏ yx$}t٣YїdkRbUl] ~_T?.c5\:Jz갬='3; Ԇ-o4CQ;L`V~@>-ɕ>4*DPc#( AO ?3zܘ jKU7<[N1 ֆ DҌ/uNBtc:_Hn<: @)T8k4_OYf{֬2/m멂;cDc3eLMֽ5d򫎱47LJxMUlcNylQ^y2@KwnH- #`j10}"bF^ʒJRAG>:g̺Fh>D-c0#vD}׵6,/JnHZ!Ő$E]t(.WJ3,Sa?*n΢G ^ Y` fƳ-WyC_09H -gJ΍b3Wrzwf<% _&8O @e@)?S',ֈyh8Ĺ*Iߦ5uEθ};ɜܤ݅@Wx,cu-+Th%.$JGx(rR{tZ$nl7(HbY$mo'iAdƫDVtF5zCw#Pi)^RbmR! GoKk?Ph\8Oa(3H0{e2pl U<rFC{rP0Kv}J=8LA#pMFUItwnPlI#LǗku2 [?uvH '$ !^p;m RIo-oKzSN/!dA?KH9‘m3`uEG?zH ޱnr8K%`Jon 矻?u]$ș}1uTPR 1c$R\UF@{;:5@Qf̱/8#lo: /bs;a3\-|SB1(KH.fa¢RP lEW%PW|\ފ T.Iybad+42unQ|>;Fe%BR/oCaC!aYl`,Nv "ĹN~&Uaƣ>C 7ݦl~Ebzh,I6lB1GW. /l[rgupkl܉ggvb#q4&=2d*ge38,qI]@s[ `|Qnv;i c]ēqb_Sf<-h?KR?9OW{ŝbCl_4+ ]'ܹr`#UH`&}b^EFsh5{&(skfkIZAo-'s֗KPQ4k]~Ts[ty/C]fλb[W͒uk0҃Z 9tb<o!;(abºq)u?^_е? ʨ]ͳv@O(,ug-t)ly-!F^b- C cV*EO5!_ѿiy# HeXRHS'zi\X{#5K+n;>b $hD$<Si8dș=NlDq?נRRp|dY\6[\A mxDp Eʻ0 Wu !ݴ[k?j{WNq/Sb ՊDP;o؃DST=?tpY>> Y{ζΦX{d(J|;=T?X_s(A!mEe%:%zpgyk]-<ik [Ek >k)j̳T̓:3LSmrߋ^Nc3ai|~y3J^FAswSR 95EBk0J3:,@̧46'h"ެ8<-ecAnU0 Pw w~9ţT/6쏛 U-' -y20͟ lj&&wf ;%@b1 ˎR  P5Z[4̕f:*3kËX[i̡W`U8YM $(5gBciD.HPS%" {?fο2Z\YZ}[} ryt5)~aI!<^}1+ܔ(Ümثd,P"r9S]b p7x>Qsr 闿#s^f0Z&b!~/ar',/ld#DXtw//'SɪGp1;jaMya ^`0 OUHv܁W3G#?6`I D(t3w(ES],b{T 6T1Alj? 6AHhi *bbf6P\Hqz}Γ/: Di"^>$ աXz;Ra| QPi4"wD0zPeh1HV%FGR_2j *>x ~:%u^*6[ğ/Un[I$OO5nߚ';_)xHDx,_g/ P{xg6ߝӅr0,&0-?:yE8@UHpOʌt#[hyg;aVv/֪~J{i`m/7Cˈm[ggcGU,4$yf;]"BpΌPIZ{++xTՠ: lab? vp( {%2dwMI/"$٪꽯h}<Gf,O{]v9b4?@Y6-hؚYg1ܭVvܥi 'A-閯4.fR` eüM.F!T4NYu&foDҢS)4_\m:^?@FSgŴ8N8v&V+9Z+MH0 D4^p/lbɒQA"0)እV[f8H13'hu"~EqǤV@h-]ɵRQM γfh3)X0=}1 <ԞH!P);&1gedWUQb٧eT P/8n&&۷S99Ӧx3W  4cF0-C.a:Vli`!3Ym~4/> 5a H3~qUzj39{轢lE7N&SipϩQ>a0(&؛毶|?k ŰPOPw' jRvgdT)Xځ8ǾsW,8pM# x,kbpݽ⿢mܣfVJQ2.x:G:eP:SWoύu:Zgs`a :V /+USXsˍÙLrQ xa^]D.הp :D>QJ6{ VT*lN T٢ب"yڞ{e}ASB[. ,XBYwfExd!17 '/ iiyh yZQs:ٝ]CD4Xfc('ȳw\RgrCC$+LބĪ1Q,HiEݠMvuc hPSI3^? z醢Ŗ1֮)c%6'.lBqnT3'EndIo[ۃHzFW iDyR{AT bUJ ^TOvFnokُ$PM,U !/K҉\Ɋ!vӂv]I}3}ܠA@g㤋'͸vy5;ɀ'8"Da,T9]C̆v3]2:^Es ^\\OO>PjexJr}T³7$R3侒GHMZy5\>Cv˧v; T6.مD((M@G{4| 1D_({? IBUpFdXH/?,+ ۉ+>G5G$<+l%g+}-1-#iej=#į̲iIx)?M`x'}Z:}!3PEDhh=庵!:'ޫF:,fx^(埈wmK[/\bHͣ+ʩHg#\-!|gVˏӠ" ͋?+.6z`9Yb^KW{H1pCWc]-zćm<\oň[Uml70-~ XÎih,aKc[w9gڥK]z)`z?^>CEDJJΛwg V@'M,E$ote4L-8Pd誠Ja_A6>`kvi4<3N\GvPk~ 7\&46 tJ-rwb /AحX,0j\if"o0. _ʱr[W:@ "bD5L+5C)'5xӔDfҜNDkwxﮂu&/e{ R~=: "p!mx/>ןhS9-??phŕqw %%/]e ,H|_edvY6;w}h"6y󢴀?w٩*O.wJgD3-<PBJ~37x:n5 G\U]I!"C@#,w:.ֳ6>REêúJ3<^%bf;ɠ.y1ZH6g2;nz.85圭.畝d3ڹMɪaNoZ;2ApSLF߼M~ka^L(QQ3yl$VQ%2宷=ԧlY^aᩃ(/gs0fjJz:% FV@~*񦉴̓o916m 1-f{kӟAG@B&ăVb!XDL=?v>JxV4&؛.;cLe7L@% iߍXx?W?1~FH5('ն`Ә=4HuExpIr~EW@Ee%?P9'Hx0ASGƸvw[a_xPmon9nRɝis^KO(8usQ`mNk3PT`m9f"Dy8|1+;ҡ!>Q|gw\ dд/w9,)ZTh|aݦnH M<uYsPeA^{ߜȱe1/oAz*mbm>Q+O8L( O>xfdྈ//ov >l&A,#~lPYQqa>X:Jfʭ#(޾X^a 6r7T*G*rW(*;Ʉ Ҍm9/zyG˜k(鋋6U CKUQy ^ٙR_k:9`':kɃcO c뜘aEeI 9dUk=Z(+UZD E|+aGҽ.ܾa*ʓB!&kij}4 À-sy>A=oe?[{(>.1e>vB'Sm`g43G[r%UykXQ݈E=.V6>_y+""0J]pvl~CҸ WRkMe$w!:bVeKޥLR.4MzO5t'mwK%W*iPKd%?(+?yGd'B15^wZ?`oXS}?y^[ (h4oh&6ƑA>3m@8;BcAȆ͸3Pտur,}w-DnEV#GvBFݏFW-0)Pujgқk20g @m(]s;gk'&MK>U)qQoPT;5n}ތ'P9 ,{O8Htڭ_=n;eBbFȟI֋ qVYfl?f>s'+)0aK. Htۏ r|!(G/FLć?4>vrV @ٳsE6*`%$ ޴Up\( rSћ @z<,ʀO5 AD$(0bIlDmjXV;P:P=$PEK5 t3`~2;& \В1~fNޗT w8S+(~ Ͻ'yzDb!tSC3_ӯK6 4Wn􇟿bgK~Vy,0Vjκ"vhRX@?6RY[Znlə^ik-YAfQ.5\"/xK/ QQ> stream xڍTk6 Hw5ttJw 0Ct twH+- ~9=Ykǵk{?ςF]] b8Aٹ8i--. _u@n`Ү s(&c@.00qȘ{*E ^ 'ɒ%$$W:@ 4wCmA-%/ &Q[(Yӓэj#Cm 7 K2@44zK[-5 '7XRP9V; Os\\W%d;jrP/(Woav0uts}n`gF_46:YICANP7_,a}r N>A`'+_2ܝ9. b`&6< eiKog_N_f_g3& |=@;O#4.. ـ~ 1]^C l_& ;+ЕTVcGN))  Mo#/9Ad ּg0fWP`=F@>%7X'swpwov'6Pj@` Ydvw_"N66&YOFvC8v. |=U` ۩.)d ||sWWso4 l¸>\-y5N'XC\~)?So$ r7S7p*FNƢ/iFΗoc o$`,E|0%XxyY- ar`5w#vp`0g aٿ+º`l r#fzc5b8qp? pÄ8vra'5vHgRCF7; p/Fߎ&i? 1nv|7# v'[%l8?` uUa^@_0_Sؤ@hsK*IrOQ䕵x>(Lӌ.RfV$é%a__ߎyue.Bd6N ~QYAlR#7pO4(  uByv* E84)Xɜh}gk!}#8g+TR~;@J w-]s27<9@sYyٲUYI֝`@ wQUAsӍiPmB挗/ l_-[5+i3m}7w{Ukר jfȖ꾆W1? =[ܴoux{ijcVk0|,Lo$剭Ҹp`bL3(|lJ^byjwM=4Vl6y{kkv˻%&Y0vhӧiqP4#:,'5]fmZe,<0G6Y=wk i|W5Tξ'&ƻ 6D) ղwsE-C%w D1 ǰ/HiS⪵`{xI%NYD|H!̭!"pOPkkM:/!՛nPcq8HbEXyuy7IqƇIt#KU8b :ily(hc_eCGy{ŽTtzF o˙DJE:I"-aj8K*W'zfGL |iO&WY\i'=i|| 1 ZRjH|Y\Ay-(,,QTr`> W[oNKAM*z+![L_Ǥ >')qi"t %1΄IF~2QidLR{anNwhfʉ#";i}7&u`(=$%fR{K!I"yJ.TiB6?*P%zAMl> p{bJl8q15{r(]<u2~_$[% ,/$$x 5iHǍ:CIr:*'H?J +g̰(3[C!]u:#~0Mf_|,`{ZBmK(gyU=H(a?l#N%lL\#~IP# P+1l*OrC*:8 E)fDЕ Mw4k[%2c >(Ö?ӟ(d|81o&N=0vsifCHuYrxq'4DWL^+?;J^Ihrx8j ޕC缙$TO切o^L }u0NJgh*J\Gk$BGCrzQz/Hϓz^v%TxϙY-^WV~3bdaɼԧbVYbKû;klqψN;D(' پKQ&WUW%GXAWh ߶?Н³+9K|SkÑ-}CcNv׋kQd$${9SnjӀ(F`MU)9G<&>#mrf4rWsXMq2O-G?҃2J侷9󆮋Mn^]|PI7wL7Č鵦e;Gdu"rh"!W7n|,ZxX nQej۵- l}[ʲd+2vMp{yr[_stDr-<ݴUJdb7&[+fV'%@5d 4:I@lIpח\u<,.}re]{ DPrMY-Bek,ˮP=ERAcm:xzbk&hXR}ZXUf cNJ;4`A2<[M0͆t9$3Z oP8n4.]h֙Гo=y4pK1KndδNk0F>dXX*Mt˱(KxG;8wFZi.VgAhS4Ue?5H:$ m[ !Ȉ~j)2Tǖb>x?n /ܢG-"!!ɽOh[;L2UH;69IT "c `%B<{CH=: 2m+yR Ht\O#M Nȳ0w8l~B3(hH3'/Fbf# 8hΥRZD ^uk D+| LpPp0lsBQ!2dHڭojɎ_͎Э[ Om"y+oQv@ y]ěQ/eP&l\DȳѽNpPQyl;,]xP z7 #I,imDp:9V|TTkLv$t|筋 I+e} #[nr\:m _fqG,o9,r^y: /ÝK'mc)=14^M&9`9yqg{jHl(Z7?eNOZMmH, n@ɼ-f[;HgÔi5WE8i>mqg$\FN[^}A$O!riQ6((~Y], hϾ젷O *"4p0a"ѭ: Xk0J2< ^VI5\sc$Չ=V~(qKC|0!,+PRLƧǩNDH4;+^/Y96bBº-V!fغTȧ%Tz'}| N7kIz8%;2(Qgb&U:NLMqyP/J!.5QcLRR]eWL: GwP >Um]{eԲ,lN@#Ԗ&赂,#JJR] Ͼyu([] P qܡLςDF4_n{ٻ]I X׼Tdahٶ'iK3zOto)D['$ʼWrFc `j.a&]uL޳`P#gMTBQLo 8jI1nKwD{gxXnf=i琜?^tW}oN"J%#,a0 [\o $]*MqYN\kkީH%=nߞ+bvx]*ڌ0Fa/ˋ odv.B,̎L7nl4uo*hdд厓rwo=lo޳bZTRsdrP4!"yzN5wNȔ%zEm=e2!U[9ON oHFܭQ/o+g@f`_X]-2/^Hnq-JsT W~ a*ǾAuxPu3O)yFeE%4} l~ܩJsa,/NȂ  >265g(Rl!ٍ,`Ӳ0e͉5DZ9ٲh8O"3+n cBͣdqO/ZI.:>r#Eys׽4Wv|5)3JJ8IjcfL,7c g(zJqT[S(cE UQTM>oeIetye j@:I{CZ))GSĵڻњnm9٫8i{7lHO=' )[wu_ +t;#f֔;=3; d)3$4Sfh o- Ҹ{@7ST_%4b۹D􄊷9TzdwUnI]$CWx ӭBPg[h6wʺh.~Z ] kP~+ޱ>fUzvm=;d (J܊ 帚T%=J^PlňlFB>񦛦=·(c߻MϩZۛ/徝~#e}-Zƕ]w& X/p"y/֞YQA;q=wz  Y'6_Tƥl_ ដ]ӡհF~ٜ9\殐0u=$spÈG&~5&(XU*2&Ih=Jem`4o)[;vWLq$<,iaQ;w٪e%i+ `GJ o?@w<"RCkv"[>e?@x'^~d*Uřt^kyQ+6YI<ǁדz?QZOjv 퐽e08POO< s$,`rH(m!69N5`&P~ A6XÛJHЉݤ쪋/]b ƭ7E]`Pk~q|oȹjt }}DC R|N4t y-'ҙlp_.Σb *!% qXL掴]/[ E!5R t$lcwFk+U jW/ErΘw;lj<7%139)}r;ɋixN=/4[EwޣٸسsDLwPۑ쎸*5rۿi _ GQ<ӋiuYf()uK;ey\~ ߕcƎ:T>zCTD2 EYSޞڈy0/ [ | )/erIgDC%B;sTz..G'lН7]Ed׳I=/<*1"zG8mེ2vȸ-.S]Y\Л$v<[2;}Kr{YEcf!͊z "Mb8O uf.h4鱢\Y9UJwbv HXj$x}5HqN'b%C߈jg,ۓS2Q(.ɸbN4ظhß6kc2Ds |~JꨓlАa XaВ.tF۔L[1faTn a2ј[zKTmaӅ}m;r mT]SP?Z ^2ڧ%<} NH귎),$x![MYF @Gi3EZU }\k6_{l(G@f/ Bn8ɛ#/rC) m)Eq=ѫcR8Ŷ[i| ]߻_ˍOKp lUw{}}v \3mhٽiA#k]oH|3 KUʎL_e|Qb-syiIL)|ES=[36jHm=Q(wv-zeӸ,ky[-}. *D[[{YV±@Q2t\M!i7)Ŷb&$hyHr,cRFq.<>Qxr=2gMI+ {xHpג).w6;>xڅvS-QV<%7[c3tCx=m;0LCω,K`7L#fuXtY@k ˵si"$|Fo 2ұo뇢IVho4q_smRʫ} s-[t\hK4ifKƑXڕ2~' ?Krm*G|lBX9őc(}/ Vc%_?^hќm찀 Kh3Pe/۝74qSQ34 2W9̬"k7% eXtiRQ9bxg-f(/{Jo[/u'"VUN, mslT!Nk,fT+v2;p\u>R@\hc5#n|$>4J85ķ^ֳs3LSQ)\^MyLI4dv\k CvZןDO HP8bxj8`":VGr܀OaeOIgQOB?vLǍF+IF_GBsI1h\ƦVP[s{y^ͪTt."kG|:Nc%I 4 HA uw h\Mkx=1vxArr4 Z'b"CݔJM>=uM;j2IJ;eۭW`7dВPRW<9 !ť*G(M,̓Kma*-RCM478g^u׸|^i'V%BN8$a[~I'ߛf GiqL16:kKlԇI,vͦUB֣ o 5UyͷSdSXrU ԭu,7^t⦒鱇_KuZk*:CENP(=L5.il&>) e:\f]C=b5JЏRnuě| FC/# __qԅ?H Oޚ."`J~GQk-+#w;נ-0z}<:٘8Gx=MzfC̮:D+ժͲ?,(?9Ug},Tpw5-`>]%Y &(w]9*dQR9…mJL04M>| !ky`p`D8a_0oߢ7~I ՏHϮ@-c}н~ԇǼFJcçx(b!ͮ`~ѳR;srŞtw|. t8aDWӤ,s8M/I4z 3n/n}flzI:oB"{mDHw3:r,.m|IvO2^R 2C3\$كR3+ӛ1exjz'5r#BQ+4VW.7Od;9{Mx#_˺b[{\*vlP!*T]@vVRՆ`|UՔfOT +axrV4a}J{щgQ*QtCè4Qx=^U!miFZdf4,;L K6?6 (~vX3uҵ^,ؽh Uūh %i`ʾ}RV+X`lpӣ2ؗUd /qQ .g@bU<D5C/RYrayy;i窮tKyfdZbj#G(|ڲIy/׺j~W稯կ2w3 A41l9T1i|oV{K*|h ]AXAٻ?s3"nDwLe┮RLyf()*u//c.e&y3(yd?h \.ڇ7ِ%?R!l֣h-ŦvODiӿ&L&0XS{qy!\c\t#\yo3c]*]sw:E?Λїc/Ѱ6<"syqK2#FsjkH|wN"@F9yk儻 "R3~y3SZ5@1auTRe:Io )'VwAZ[IfoGbOpk3e+lI7;bY{Z* .>zFL!V`FPeF]Ijm9f)q莵,0EF%2t|懞YQ=hU@~9TxH>`s8qma+7H%׈ ʩv*#g 6d6%YK;gA=~|AΈ4z^!:*oC1fʙKJnrfNwWGe/A%#>wRvXMEF ,qQ}`pKɮLfsdhNXZM"W kAENQ? tޓƕVGhՠA1Jڢ^-zyU`|3.3> stream xڍTk6 H C  1"!%" ҩ ݝ" 75k<{Yʨ+k +^>@^S__@ 3o9.!A%Őw[!2+ <B Q  MK \}!d6qqQ?.`wip #X9a60?.8W ~~///>+8!' p`wO-W-+_  ?0;;8ClP8j v U5ڮ`d? <_ֿA[\\>= h+i!<+/38[Y# nPX!+>;C ͊P[y OA݇u¼~#;W7_@Pvm0q%F s!C\?'p[_+ `{wl'F;` Dϓ9rlaPg?@^^YNQ~"^A@\T ? ?:Vv ټk08N#h p~3 hށ?LFoFJ9$V.gq@ WC\RgM-+Bi$@6Nt u`pȯ+t6N[63g^[Lŏm>P=3KbbyW޴]aX-=Hx Υަ@ZSAw{ulk[~>f%/]+LJ&s-6xtԼFx;S^NLk>Iv^eT98'K z&(O8n'*,}L}#Zi~ϡV2؎b#KZ0tN#7<gJ֓.SmWR3s@a][w Len˓cM}@#ֈݲ*]w`(]daFry6%.xwzܖ 吥P3|R5Lܲ)M~~%M4QG?_Ƿn+" {3%dz/tc4'M@||8s M셤Wm'1X'?z?̾.pp^hqgcӶ{3>v w ?!ƿUxdT{|,_>Ήbdբ7a;`6%{ /RR-^С'WGF {O  D;(ns?? v}ڶW%c}C:nA~ _Fe/9ȗ0{u0 ʕ)Fb-Vԕ~7۞65S,l&G6{fz_0  (.574Ah9Ռeχ%j6rV]_DY8>7+2Ɉql6/Ӑu@ށR:ut.6A y\ܢ^OTWjmk-0 Ç+".nҘZV~ ,K+yj指T \Jkon=݀l9+8 7y+gG7m!rDZ KNL ,?<UGwxtb JӨ9N_Qix`pO@\zrCo fkNKL(LhJb"Ȟ3 W8߼qexIL ZR4VD5| aK;f*Qa:AVNr]eeDDH,>sҙo,/J@Bdr:^)ثm`F,dnh$3>'jvMʨt_jζo+̀"&ߋ5gmzSVpG2B&@}o F0egNEP؇Sz`.;iWؾ/%LYrޕ. LH^/l?{ty[7ؓD)iLU<'9|!yO^g|9ѫ8i^Z8|U).4?D)>;1=jIg̀PMS)/͞oRY㣥s2_ʮ++ P y#=BKk!R4qkؗeQ`;y#dlQSqEbܶI%."e.C JIVWOQvYR'Zq{wvˣqR+Ig[zyԷ>#§c|l,sJ'SGLZT;oUYF__ci{9Irq{MB=.hKX)!P 7$7.D#n$h(Xqa!\pgӳSa-Z4)G@kqf(r.47{ǵdmD 82Zt&a`eK+{k񶴉S&hSS[p}!Rl=W7} R_vյ,]-D> ٪zTn GDqN4,/M*~VA5b|QMr4ĕ2)P)5~!R/P.*m ${1vk*~Ȝ 4҂h4Xjzy_Y+-[be~eX`?@H z#iEJk OzsvƧ+d.>C sKxyHm/c~]dE:`\)#yVvTI!İ| F1nxON!W} zФ?ۼ ^m'P2v]ʂRv/woxmR3`yVwm2VhdE4o^y.ҫMMN_L5NÝkHo"^hŬ85^L*F`Zk" {v@10>L6ӌP̴ђ6f7Fs<2t1*dž_ b6 h4242YNݫ$9wOVKmGh?Y&&ve`Nt: lc)ǛZ4O8}-d~Ϳ+˧k$5J0SձGO|Tg(Tjf=Z8$)}'2 2 Фy e6ȭoR"!4/<ߑ(9$*5ȬseE9#1fF3n!S\09sѨ9[BRIFkwJ > O( /y_=L!{WJ ;F tӏ8E#bBtu}Q<٤]MQDU#r8ZR4改 2t rVžkgy <" Ӯɶ,#ـhIs I1QwV NW hT ~8  c] -ڞVďn[%~xS[+aBR\Jynbֵ͔3`.weNg凾& v *I]W6à y2OcGf'쮓kyYP?vZFǁEVfj85dף|cli03iT&ПK/0`C,A)ʝ=M} |)ۇݖRZA~gpג×vV}ʃ6x@rD5/tɘ]9Py.IGb>s3y:0c1dUh?}]99T:;X@9(Fti<l֍ѥ7&~eL[8 H|J :'bO7.es}E pjU=5AH< /9qzBOznˡ>߻F | .7ro.u|C)z<ʓ VԮVK(ђH /{Yv0F[nڴ)VP|F'T ltvM\̒'Y^l:YmIL7m[Ay'nԸD?PuNXPzURkPR"cCv-IP:~D^/j/ad)v2e;s,![.̋lѭ,m/>QqS%JҰH=p{Ks?c_VN f"-CLJ<ƶ!O:8g,=BᬛDP$6Nkr `46H9.8񈪜X7t@ӨUsE @ y=5Y0r1 AwI"2.^yqcg'{O6>28נpiLΏ!4UMnwIFrH7 bIku "fdg8jE=c%*˓TbH;yaBX`ܷ J?=$lt/~ce\x[>~ r.dz8(!ch3.r#"Cޓ+98Wf풡|ʫc3dt򞆇B rWIO(sITꄎHz* =L_،<mwKX:~ؓtbXEi+|(WlfH9>JQ鈏舠d8sQY /)AR [JIB+J$urqGS HHE/ ;φ=7 ?}7*ed^6qI̼ )j{\mdNjnJG;<<w7N[-RG#?Nbdx󶿁x#^Fwf5'M3Dw_F=8?Ƶǝhv«.^Nnjj+Lj-#uKB21MW? |҉=g;j6qL[ƍ+Rwt];$N| mneW 2N(&Wz3uH"k\PT1XcB]xJ9UGkQƳW7"7Dzq9~֮4(0'b{K ڌC u;ヨ#w8*yӰt^ƠՔE$[y<KJ |'s?ngVRLr7o/:/5Hػ !{|?'@UU4ڱOV<8Pi9/KRRP)F ;ԛƐJ;5gp.i1 ]a+#M.^#z,1;|R'\TT~W`Oi?A.r\2(¾ehM^p;:V\ʰ=a ͝$47Ӛ 3!t:]6smgD3H{} |8R8~d4^WjPj~꒺,.C=}r~|P/ezBɂhH۽/:PJ2V87 ]ƶjkgQ%ߩ|9z BG(hphS(œbL(1y^3烀{Bivl]4Mwr) sY$E6&j.Mg6 S}7aau?waUaiھaIIΣ%Xn}#gKיPtI5ZO5}Pwڃ6NO%0AB_ۅ6q:MTmrJIĞ^0Q|n'{ɤv p2IjUp w?7a)šBojwt|I zr_ϝpf{Ҭܳb%M&"C_Zr9G7o2s'?Z{C4=_ːUQ8&g:da]C˿yP f+rGK m,:%)``e`Aݔhw윏7UdB2Ifn`&`l4ݺ5o7ܪ/ءr -ob*4UFY_j/c%t:-| of6On+FH~(}.MϜQOuG>di# YyY^{ğcbvɼ^?EWdŲ߭t[% AbS3$TEY.XRzjI40s~%7x[ni0Еmkm˸أ2H̬z;#f Hn˳ +PT'ۡRrMt ͼyY+ ;0K#Jp/X-ݗ#bRFIv;Rv1 SX!_ͽϼD|[z3EWlO7l%ZYIۙ§ԫwu.eZ,dby&W+}A:vsgLu-تJa4jQ ,2O}#[;3lÏC~eL!`/#cVЦ{QJ2w1zPjuyX0Oæhg$[!|ɫ&ul\@?hM]ࡪigI,R".mKw30u^[&%S\$ SYگqEVA*eo>if/֮$G.-?nWcߊ` ʮ堍~=Vjs{_ecW0NTw_{*x;`RPqʶ&g,-(ԣy4%4(b~Mm`wBoi~B7}BS) t݌@oV>ZJپs:r N0EWQߨ=T>8sG@6Ĝܖ5UD #2S=lY|rzG6a%'gvOA}1gy~lC:xz7E3o{4%?3x1bP:B%>Pm!@ٖ_vАZa8=h{ cGmb*Gd:;wJ) B>6ǣ{QbV 821-`vy_ endstream endobj 69 0 obj << /Length1 1497 /Length2 7020 /Length3 0 /Length 8009 /Filter /FlateDecode >> stream xڍtTT tKÐ0Ht0 08 "   tI+"]J(psw{׬g?o?olvG| v[* JbAA!~AxP4 r"PBA@2}c4`(* <(B Ǯ@z<8\ow3m| `(Ҏh4RR@ݝʏ@9rܡhGz  9CƏ0pGأA(F!p7W"!?0pz vg$ ;0@WUv A0Wč?) .PUx 0+E]]_~i N ]~է EA7}sOw_ E )`Aԕ-s"" v pF"_=@ T;( 8@xGC7GA=7fpG,cd'(o>qA@;G PnHyxbpy5\gAܬ3[o v(wEn0o= yiqnFM!ܳ6Zu4D4 =l_s !__PPt7G~rUqoRF:" ٰ""o͕A<~/7@@߸n(_3F* B@o7Z_Pc7¿$y zTBΝo}rk Ӯ04tN1ERꁤGNq {X \HT@RZU<;?nw0!hFĒWI3ۘcO0"!l#69޺};ҔmojAC2Ov3P7 9Ul9\5y??+I([\99 s@| e:["ߕM,OM I߼g3*=FX4TђZ2TE9j mu9|qpU/4,? a.3aN5Brx C֨Q̳k>/?-ݿzOҁgeB}ͨgů@7\Br!:ӷjsu#{IUq m[N5)`ta֒h!3I\ᔧgڕ>k(-U2:}&VUqRu=%UYߎD4/qɞ:T}z•~@B̜OO_oNhjWZt<}o 3߯V s20߳$fj& I+:$g%0='YɓNn{gH.h<6k^R'b33=b%ݣeئRifɢa i?яŇ/Sh{w]ņ3=W|bzQ'{RTв}^#h)3\/)&(>bvAV9Ta{Ϥ<#Ⱦ{͢2}AxAV~G.&~[_[[G/ODŽҹ1"K`qD$K' 涺1%s܍u5,4*|t*sfp I^0idq[Q՜iQ/p`m,x\.x:gT#R/C |VvHʷËF_ r/?+m+\*+/tEL1Lh҉M{oJ|mqGS,T'[W~%S0#S#Y>MX&PɫB)3Ky27IQ< M[9 @Ri(tS)㣫I*p!d8MP2Bj'?ek@̖6|}w!aI]ȶD]ԻVk|vgF]Tx [a\;v%{a =!מrXԂq0l* ͜!q 5LfwqJ=Tj[}嵌[S7;{RH9?k/1TCT'Il?@|}dMH+`4#BF* }KM1aaz?>S 3ʝTϧ4}CNܩV+ ס 7/PXp: VH&t1k*'.^=.FuOT~Y^Fn͉Jk,g &32bLqmT* ,cuk=Ȧfy@0]ɽMOH6A"{쇮*ϜKR~ Ad}L\*Ί2+n.O}Uf̓[9s޼T`@oUFD*?D[$9٢*Ҿ7l'\iu`K- t瞤P\n;DR_xB?Jt7!]$}ãgzF5߱p} B,x؞B;jUs12 RQ_fm;,o,{wa `+g )|6r 1;5H,=u|%&QfLxd45,(d^@Cg#K/'SegnRDWҹlg.Xpԅc9SqйF8^sZ0/aShl̟ΜJW6ᝬJ^X[$t6/ E=A%*n먮XlUSeRL؀nׁOחDy?;G׭$ZtxDž y[nz}QW,Y\UA\gCQG \-f>Lq!Ҕ|Oc ] Vum̚+N%y|!H `2SZ)Acot /i+DuWϕ:S$p}n7ע,ׁ1s[T^x͈LeҨi3+\RV/-x`3b̯i}\ܽ8|{VCpH g9%Bagঌ]ۣEPEvZO ;̧O8TkdnOab:ܚZvyJ7O}oRnt}C& ~>ⲏ.-rθBˊ%,'l`\`3;ob'S.1JV u/V2gRU:ZysfSxGi FPqJ#na~w&2Gu9\/jn4WI ƲRgX|yq_!u>LRRHWKe, JCv; k霞!_)-h4c G".5;Ƙc&8y8V^ue kL]\WK 1s")uނ2-I͖9R ny;$v{6vQ>%eWMM/|@xj $eL&{;ծ*nbM|$nLOޮP{nLe4~bV<}{߷ωoʚ5΅4ܲ˾}s"-YYX鲇]u ܗ; o`HXDHEldb 0?kzHbK>:VW2,;Ŝ2{ѯ_vq/.[?N}FMtn΃bZEG`Ohˆ qF߄IhE0ʄ~ԙτ ؖ6H{dW)0s~-B^ rٷY*UI}mjN?4O[F Rvl"15wMFh2lV|ZSc6Hn+m{~r1dc_Ð76 8?GCsS|PԻ*~'v3$RsjZ,lm+kt x1pQP{UCb"աgM۲<)גWu$_D8G%7T RR@:hE+qiOƯqe#jow✎(Bø3gh祆 %8JX|# 3* 9Q#>CF1|+;bL-sHZ`A}/p,%4)K[n8ODΘj^a MpzH: \ГZEuSRgƇ<邰YB|n3 آZvDy.O]W_ |fIA:D|YWɛZI&10je1EjXuw_*4ècmG|f+m~t6&:ڔo.P,"G}?0Xkb}G̢gM:; =HK {gml]ٯ[o?k,73I?/۔~ Ӊs {Vl)(!ǫ@"؜"/_B.~n[dGTr+OxoGj49t2>}[H"j&lF>>{j#u r/uԾ6^<-u*tvq"] Q ^n?p6|<럈r1h[/GQ+vY@,fֳL梎S&tJjD )ӝ+틊LTzm,WTI| <؋:\vsS37jЋa¢&B-O 㦱 &B}䌝Ѣ}+K;i%V:Ùޡѡ3:`A8p1*jsw+Y\x^sPzK'*:mkl=)Q+s2K~*b:jtH qN7 rgNW̸fujʕc*1d\eۤP NLQ$Q*Y"] XKzq;iqs%+33w;iD?ZY3=iQ.*ِC;'9ݖ_O +6:9Hީ=?lgt0r=!xL!BM&l^`bN>V9-/Ϯ`Q}i|ĺ{u _LDNMÛ}cpC쏝x Fd^5Iߘ|[?n K sZ FEp"Gx*f ⣊>[ KOZx+E:OŊ65Y9K #_I)WGv]sT,|h`s}=}R3UCd@{. h 8e׿U'%6.Ps캝N3[d'cj)FKn\MijfÅqEt`u1\7`s.-xpV\: z]s6A=\K0_͡ ]lS^b3Z4x.G*rq!qٔliT3:8۽WbB=9_ Q&5^8t=prZpU{'?-DvQirlGs..M<=DϪcꜯ:jLO8~m_01Q[LkKy v=[Y_ܨ OOcteB|(iSfH*t~^;&9\ڥ|r`Es]ofU?TL޾v4{W> endstream endobj 71 0 obj << /Length1 1826 /Length2 9932 /Length3 0 /Length 11067 /Filter /FlateDecode >> stream xڍveT.ܭxqkݡ)šHiKG9s{?Z$73{fϷ 4ZR0sѕ% x%pqprqqc20C`2@.P8/MHU9 _$ ȀݡNZ۸>VO $$$G8@Z*`WcE =@ fzW fQWW'a à [<6M n v'& O  P c%xRT9A$+I`5w': 98+=&;Z&]``w0lH`_XN..P]y dp佀_#lu݊PQhf qqqq r wW^N?>|`NV ~P+ pA|o ,s5f՟q PO!\?2~3K??.hwa r;3OXпV0Пm.?o1,23ɹ`b^q7Q%*G8/U򧸥aSt?jEQB]䠞Ku͟xLnu\|곰{|`\Q\]Rf[|0|G=dž0cs~+ /~DBH @75A૿c?H4=ֳ=,`Dg >_Ϳ |n/X%>>r++ t'.<|n |ZC  ̅YHRc'i?9ƊL0\{eL_-LlU]lS7x^qPYSBsMA;ی"M%\ EPx"aiݫŀ{>у蝜RXj[G,gB:G^m}Δ6d3(2U5h fG Z2~egT{)}+ /zr}nar]wt,[uεHbe Qi+ oRg~bz{̔F*͈Pm Ay`ES.TvRTsGTiHR}r1͓yY >$c%$y;{nv*`@ůw\hǑuEY߿KuZFmI+uFQ 5 /ֵWDCϵfaU7sculiYAe;y[3k_K7›7*PJ3YΏE15(1هkQZS}UٲNU;nyB{T I; kr%(J *B[oː,L5 HmoNf0yr1#kZ%JE2>N􉮚tֈdzVlJN#Fb F@svRy#*X?]nK| ^@3ked;JbYd| a~h_0s3K:T@r}=k b۟?Obdq%{~Wb몥ȓ PQ_p [ cts%[ *BnklE'!y`ts7^W$ِ3ҥg |Ol4N]'Ra*/C+)CGBTW]"#dN𲝙)qOz},D/^KX1;jIrpUigezE<~OyXxV뢮b%>UqX£5ELѤXU|k~SX#(Wm$\*)L=KIdD>x^E2EJWW~$i,1!dwB9Z(J6p /IW?^ K2Ə)/Ě,k3 k,8%غANDݫYWQ9Bې0oio߾qMb^I+Eګ 9A-il UAܝPA]1( SG.!,Zj "gzcf/aάZ*SReW&w|{sWWICedS71pA[(8#qXd3HU-rE}rggoG>]yEo֭ͩ/xCn[w1>u,GW,<#A"ZcnL6/$ۉM(3G;0Û.?Rgltd!cuRޞGt,hu}}OQ^> !+%qK9zx~~9gO;ri-v(ˣ /&Nqby<5#VI$K7v'wPqT%d,:/׶,6Ȑ34UV&kOSp6I(1&fz{|]H!;hQ[ԫ)o F΢ c1f63 nC2tQR :}N뎧Q 5.z>̨fR0>Hx^9m99͢E(jnVS*xP\|Jo6]}{\PMdQ@+}YKمz2Y5^}vi\ cuVJT+(|yoĉ,sݡKZڮ|3'Rk~gjFW݃8 $V L's @^x1hBIum~`?~u\d}N BaX|-x-Ywl,ah xR91 >euDwco &,>EPR"'DsCx`ݤ+8 5CkׂɈt{~ \8z/VΓXʵ[98}h4TV;=91*9Ys=YB=&\Kj,5;X@81Pe,$jOԡ&u#[vukuvyHqDs)E {/(]Rgwtї.!<tD9]4gjG8y2Έz$_Rk{qNo(I:6 cI&ҡ'o{f9da8ES2-MK? ^ҳw~i&,%w*Ӽ|+QcH%N{MFy|w3 u8>&o)Pj =!ar\*|/Xܖ[CݘȖy٪ WPͥg<&>ZA!5 b@v9ˍO iB 7L Rbjn񳱝 !V$xꬸ(oH{5$5IA6lcfkjAɢy-5x($Ƅhg.$Iף 6a++}c]Oj0zX/ŭ*%_V&v8xL[il"OoDM#D6K}Fo/DJ >˸{Dشlt1"D\G{>ey )7Awc_2QO?^ *wWGg2cSO? _'- Z*@4hڇ =i[p&>j;6-.9%.PUi}?NzW5Ap#b=",4cOWݞ pO_xa68S_qxL\3 mABRK諏Pa-k3}TCS,_ 68<.h+䃯 0CZYX̽"Ql^#7# rDCF`m9o A /99*Yko:jYc״ț 9d])ɤ-=kݔj՜l;3~\n-g_bߴ43Z }lڜ&],]M5ʘt_o(R˴f&Vz$3VóOY7m8¾=LdCk"q|&3$U x+/ Fb"6>=H `H z_, CҍMPg!$Ff_E1Wt/lJSԞCd3ڧa2_ $zKS&(=g&OmQ#ͽ.վ`mO^yu,32rsQQJ#|K^鐱q,ԁLL_ќHbw i,@2&C扗vB0-t ,?0{4 ʪkiN^+yD8Z% V V;o}k)ckr S ;sJOJ0(~೗amLdz+ؿoP*yKaW$vr3Ⱦ6ec,1|[&Nڿi*&I.c)eA,?K,h[A\YHL\ Ze*%u s,NzpE~ў /1O7H3"P;x?_8Sas'OOAN͵2}Fɣ|W4<&!z>GwXB5t1bE3~+{J'a{.O yjt$Ƶrԅ(hr֒y6%?<BRnb綖wkh"W~a!LwC,80foz s%LyA6J<G(qj?'֪YX{R6NMfIr@φsjw64yNiw^Z FC*#gӴjVV{_ {V|ɤ86Kɮ{z\RU~Ip{ƥUZ-vU@l Oc,̢@h$y{Hg\/qw+ gOp D#z{EfO[>~"ێN(=T&keH(>\06i~/I6WGAҧ7~;酷Wɝu; gH+R iue"5/n\ӡIaO8#$!m)/:A/VbR(ɼ 1hLɸLDF靮!rn*p}/ ND*UԯxPB0י?ge 7t῔],~]޻:kG pP.78?l@bv4Xl_YrLϠ_õßZO t3>!k׮nm]~+";腈.Ŵ1%™NٌzNz~q2O4xF^?z5(usu^T@oY)8-=kG>[agKrl$PZ/ҡϡ/3%>6Q6}erf܉8PkQ1{!IHqi ZI{**wfE+[-O;]iKd ‘/?m}QTX6\04m:VfH=LLQ_IE8#aD>*8;r% e C~:#;K&5ͫ`8&2Y|y z2Kt)oW@NQg<-aǕp\^HKAN svf! ~,>fq+qx&iy~IEěM2,V79/ YLoM#Y#冻])?rvGΙzP`fL\ܤ4t|i~$U/MT$ } UtYADL1u);6J}2-&ւ٫Áz])ꥷ۬MUݴoOGdQ#]Jt-'>gHP3\.|at7= 2J@ vVai&ø1CPD!yQOy ~O0 ]#Miu *0 َ,h1āZO!<}c(O[dS31ҴyT&y~3,Q1uK!s*l23adڧjʋNKeNpm!Q@Yͭ )) DȸQPtB!ǢgKm^U{$DqKok;P:')JuTcU=/ɒrI} wG0.ߌ(B&W1.EsZ$]W"#< 8L9 '`IPǃ+7`5EB%  _ Xm1OCMz~( c{??%7r' DiF_ۆ_; վ" ATvFAUNLVH#b-)惽~@,ΘVo.pmF8 hdxE"JjF5̧nK*(+Ť{!։tfTCw%ի\Q܋/P"jSu i}{fwȘ98PZt|+E] yLdX葁PGKT$HghPKS ·ܷLr ^u;G:jy|%87d lhTR)tNYاLi.c+F_)uyf6&\32y;:I ipU&xH.sHq9 =l8{),K#Mw<.O.ܜ}tu:m m֎BDBW4H9FQF:+Tr$a֢O㒭W 9X*Ӑ0}Ә[Xq}nZ8 HBo L\b E\%-F 4HkwjK?k>dWo uH՟ ]n*K o=t^@*`L+~Ҙ+!f:d;)R-Z1}!yFGaIHeEF\9kT&CGl'GӟϢFvhu?κ<) ij>r b9Sck.(F OKkhCjgB7\V%Tۆ'ŏR2op,H9Kj+ Q~z4AEHdxE,KD.h6UUMO7=R/sR\V_2t&طbxw_n;P#̣@zZ=cUqRƅ֎kwjyC#d`]SNu CR{Ipe!{Y\u#zo WDJOOjXvؔ20Z2rҭWN˓=҈9 &![L a>Jc3de/]+mVwtFU=]_WH vü7Sa&y xB7!yQ9I Ow]N(1oOe",fX=,VF\猒a)?DthP4^<XڈrF A+ogC7 o#9XM*7 j`8֦lޛ߱2__dNـ,\<^E>C@[oaJέ5lotͲB&qc;щCw4jwj4/TF<}Joc{lD89'k%jBЂo߰0֠" 5 %YZZbA>⩨;enk}pb,.۶7|J ˽?LQ)T?%luN1 ]DZt:/߱8U 9^:\m 0^V[ۅfnxf .rv_\kqť,v!]UXklX<+?BdRDGƏB_YY&ԋwۣ'S!pvWJ/Oi8ymM:.6\E 5!:ʸ#ZO3=*$_q&j2 6+>D:Re-+8O="nʔBğQc̖>7fc,=u)7ip"J]mDzbK|S6}}YqU:~|fcqJz5D52Vhޚ/W z rE䙫~7% ǵDd>"J5>k7U+Nqlk.$k2z\6n3M-~Wfemy "]-\q]-&y4r$5py"49?V6g%[Xa Cc6!9#Īz6nP| -/m2G+53%ْojN;Yo ~tN31Wd+V:e?jaR|7T endstream endobj 73 0 obj << /Length1 1805 /Length2 9030 /Length3 0 /Length 10153 /Filter /FlateDecode >> stream xڍT?"HI7att0-t ") ҭ4ҍ4u}1jhsHY,0(( QV@^N Qd;@`PQdpL` eW{7/[@[PBaY 7@ ]0e`[8"_  )3dZm {6 =Ywrwwpp9ۈ!p[*f6NLF-O6n  ꂰqZmuG0O? 쀿_ֿA[@0G 'j؃9pvp[X"nX J@3U$/7>Ad``(W~g0xO%ZCVֿ ru҅B\J"20!NȖWOGJ_bD>ގ0G5vpή`+0V` @1{Gb8C<@r^|3A  j)sI))]?ZiiCHpB:TWzѾ+qk8Z#3 0^@~ //ߔ] 0, QC G,* &\kUJp ĢHAm"[i@ ?g@@0ȯa|qboP9(fk y@ ~77b[8 #L}0g_*% d~g. 7K7p=vN!Av .AD6ADA^Ϳ ȇ(qf dAD&T~Cp\:"d\ADO\9h36c!S7= )H$خ*Bҝc}X €c8-7f>R,?-ojצ&tm{ƓF e9D'tS H9I…HTxV6ڌ:gݟ *nQ^Q䉐ѲOg)k!&h͋dT:OqxK} ]Tn !p|9'|rqn vR -%w?(Dm~tF}Ǐ;mnl2Tv:?Q zoe0>N%A idH _zmnezwLh(QZqRflt] wjx}>=mGΦj3=vtٚ`S' 4[&tȦIhFw˾0*$ū_i<m}-pmYVϥѲJSvCe(\UҰKF ;ɠ09K#hRQ &3zD 52):OS8&&M-xVi=8(hY`k}x9BXgA꺻ع8K\61j0%M^*yVz 3X(^?ѹd8q%Ib3LKiT ׍N3 m g9=YDiq`>${ioq1kIX_ց",+J1Bz]*_2gv9G iT홣?u[OYe7k_s\t&ؤ0YOgX-~EudD&PW*aЀs ?;)?9,T\RDݝ(6,8EC2RPKWnKč[I1rꔡ6^D~ڵit<46i%vu`{gS=m\z*mf"(#E7q~.3ձrtځ,I"b_ cvԌ3C6|b—%/'Y )R)%Thu܁qrghL˜KUm>C QVj_8엱2~3*g㣣=G٧}sQ,_+[lNbݏ4?I֊.~d> +2ԭh9|= ٍ6jzPZO_<7k)}v('h m.[ oddDKh^F?'p~deyONje#vqzusi"ss*P LύVLoJCA !aOHK=o(N=~v~_Rno`@3\ja>c+aPHsd!Kp p|1~;܏'Q_ӹgl`ɱ)\$Qx4makWrk?caծČV#7,4/ܱéqXmGA^HQa{Rd;/&(9!~JmBE[PFla!)kw?ڂ o۟05$UB ]\0$2An+ v 7RYYm@i2BR!أs%QGo;C*튩bPK(881J0C 1A=F֯Vտw[*H2DD^? u$zw]SO'Yc̷K`p9IG}ᴈēB !w#m)RC zƥNY 4o1WFVIXpvt+E8ȫ[Ĩ%ԒYϺn/j /4Sߴ6-DR =Уdj|Χ*m\N%Po"eZ 4pnV4k9I̟6gjںg% |8W .=?*gU~M&'۴ՌxFIIQ+p̊}5+04%_ z5ҁGn]6ތ^beQBq,ނhhQUXԵV^-jѬfi1M0bZoͽSl[wnRȉU&_GqOFCOiVt;.Lm(-:WK!r ek0Z _ʆu]IMt >L:ϩ}&&YYpdrɆ'1 XVMsFmb; ?􅾬!f]yRTLCRoZ1eZ1Pf͟LɋTrs߻EJ4 +;2}boOD3)3i"C=MLWa7_SRǾxx0ڕD_d9X:8ruP+`Ђ,:-h{gSlqc4U ?>gM(̵O[*KE305ow%MGӻ'E21-G.KDx:9Us@"!mR˱s#ZZ)'tbjLq4;O>1J0?lj:ߖVIuՓ1N&y[s笡]jJp$Kw@WO8o3ٯL"L~+@0FeVN|صc+,j 9Ӈf(F8DE&ZG`{.>KwsyR:2s d<1y$PS.܁3 GF!%O>3(z\.ZWuNܺFqݫsSZKībJ :ʫW WϢNbZi/I䏏cmL/ͺop[{~7GUlӀ?1a*{m`~uH?OZBtj$/U _~>5)ۜ-Yk_0DyFpqܕA6iJ'qt|}#Ol$mbgzѳ.O |9|Ш[5SlߟkyЕ܂M%E8Jgx;fՌVp3E75lE@l5*)̀n{:Kµ/b[whlsTIwKX ?S)kH*uS9r5TlDUbiwhpSҹ_&;#vJk~_ 7(N49!rP;e a/x~~\~28tMb+<()[Glӵݮ[-SQțOHꂏ8dxwՉN *Iv71{=F\oB<`6B8OբޥzX.1]vF0O؟)r,QOvM] hwpݲ@^H oh,kl=qP,GJ|p@rx0g!W@R As?5}w֛+W _lrWl4dUOe<UXb<~B4C hMAџǣc!~Ƒ9l| I&p`Ԕcأ[E4a6z?f*%[L[:ԂPJC!#-WMGSTеbt!!wYBќ}:"u0ks+rsdwƚWAôB$ QPcK]֧Io|zJyyEWF*}'ƀoUR4[ϯI:{}{:_I3H$`2VedpC6Q[JaC;NV4;iNȻ䇱Y+I |:JZ#-"Hgz`v}I?>ͫ/F 0g3-+.3qutV^ݣ\ƇK}k0=u =CeL=LtCqYmtx8G>"<2}^ r,Jā/}f1 x6FG,TT1_V>hAah.+SpˀmoNXfx۰Cr HsKO4|S!L՛jlPHϥݳ&&WISsǗBSz:eq:'֨]`}pT[, X N DQB}"_fx1vD r{Lñ"_|ˀqdLK5,'A¦3&6c(i9Шܝzm#+/L~584[)+u`ʇmGuR{p g<2q߹zK&aÈtϚQq;RqF+^.s-~yPh@80I' \VAyfD5Mr0(`AάNL'4pOtDϭH@`]<t&Z/~*oCo[^d_͈8Dl2m) *$JLNIV\մA|FLtlCd]DQ)/HEګ4q) {ڞj|B%5N l@Y0gXTCճ8$a*7A/1j;QZX cp^fUK<bLJ|/.Xs=]-`@QP!%sMր&u /!$l6nj,'ڝ*@ ׊m"_xi䩩o7 eRڠ+#N|Y=) ; "2͔^1x.fֹxWen0J-rX^0вm+l=zqxxvUKFN~tMD}2s%!qGsB }7 mɸT=zo9sTl)N *޲~$;Ȑ'`M<!~2Ӵ>Ix[i}DMh,GIձ$(jD U#oy=lR$\7j~io~o8oe:J2Zͱ㏑2(TǒE>v/Dž )FvSXO L0 )z'H⣷_ɿ/A#?N }yL-3يs0 G F#Z[j S5(:EFB-E8ݮ^U D 5k+2QZ˖j~jX0Aͳ}hE:: ڻUrs w2I| $^ɾTE:[\njC`\LR%-T^qSXe)wyIђjEx#i)o#`S%K]uLkSm~̹|W1˵ㄍ.( J]?(q\2. 3PQ msa.,$ѯyZ52^5)e Gt1Pfn %>lmƁ"-p_f G>,J!jٞӒ|L\U蔩w ς*ت_&ueiNXj;9{jDg'RIKiBd&  Q>'m~VpȲFIُSmә5V _i1fat.VAL3d?Q, ư $q*=UJV.?~h~9gtO+4ELg)~/H"lq- {b k)(S<5P%.H9:NONOeb3λBo:xYo-6y97j9^Lp TOFNhz=wmμ  !V7Jhyڇ^~=WUPhy*ң҈AdVm2 >Na˱ccc!CÌV4;qyY;"y>鲿N/^%#9uGא@զñ32zml3Ówqdxnq^Z᭻VCi<Ҷ:bo<;]^և!F" =8*Ů֚.IleKnQL32Սz; HwExĆ1_ꜯFB_:†8)//e4(P'&T0[X$-IR E_g5/=zS$'(OB*@%32nus֕u7ÒAc$Q.>9]W,Aҝ*^~N4M~̺la }Q&Q ¼W$F4-tN='LaG7!&j|9*hY‚k(-9rv.4AO>P< 嬈JrW sv4i,zvޗU⇟bFr%lsL۹@ҍ/^2T,tTD ]3-*'ZeݓcܾHrOYb茈Z{r9*γVv"s [xaw endstream endobj 75 0 obj << /Length1 1550 /Length2 7282 /Length3 0 /Length 8290 /Filter /FlateDecode >> stream xڍT6Lw#]K.]R!KR% -!]҂(ݍ4/g}kfk{YxdmE8̍ fATZ.d?܀?NgDP`+0bP'@KQˍ`Err[yXA (@W0 u%W>+lÝ!07W_'E@|apO %݅}Qtofq@Q? *2߫ql@W+ @nkO{3|?x? '!Ü>e>Y#Y4핓{|x[,&dS+S);k=;ϝ:Yed9iTf&dNg%=t1A,n 򂘕? =3I|@V0$RӉvUW-i$?Vo8x MMأxd@"NLy-OV$I;ĝn;al?֘^+V[j!_Cqls(2xJGQd-RĨѕ+ !hDI.>Z<$ rvM~#(֣*x-"teG\p- xĶvCSTi-Z{^$K6K/B5+x ix\4M/^}9U翝ZYzEAX!QnF;գ|?2뙳?} cQj)k-,>pm5 ꩙>CqmK_3v?L?a=u2_c!RqvS=#u.SCuDieO2'AtMmlԣа]<|Wq.VA/ݤ:IsPb纒{lgUǏ^ottMY~s>qc0E\xyhOdWqP&o ٵ+};IBQ#88~:s4!\7{(}kJ胄i'b''bkx5 YiuKw \Ν.?2|*yVew^@]QY: 3i. {2"vT,I@C+7uJY:.}4Z[];aig[I'GZ)dt}0b|X]"w5Vj ro۾sf!Lp]0TI[+*TY]a6atpqR=\ՠj- {lH%Y6iTŶdG6(PRg}=Zֹՙfɓ+t;mu;d-|ddOKkH aצ{M^`CJU|Kow^]ȎQ/GĈ7Ԕ=hR[n$]li9l';6@R-ޜ;DOP.fdM/Z}d}ј@yc" mt* ˬ`1.:꬝k!Tݙl!zA:V;Ѷ0?<\w.MkM4=fJqѢJ2`Z B讼D)_rg=wDmZEa+E? ޟ}^i(V4~a=l^I:TE1܁i|pAjp6= QS)Jd #%~۪*t`i2',*#&:(MLX:Ibgj ;؀['o{a3DX>fs/~z㘛̧rk86[>gж|v-)s3IZ"olg,`\xk()sU`'z 6TrZ*/bEMlxgl1[$}&;BK3nzîuw{u `X}n̲ m~ ٳl\7.qvG~SFx8ŠHwE_%"9);;720unpߎ>kop /O/h凲ORa T|2 a]8۷슚wC^gO)lSRFtycѾ,ǪD0DsܥIf:h) xy$8 Cy!iHxҠu޾}=`؈ Zy,Bá)5]Xlndiv=ZW&.E5oRY@cK>stz=dLcj~#;@~F2wv }6 sʛq|=ʅMcP-$qu]LL[6<>sO~Ş(s+g|5ץX62!d^<: C^$w%`VE^`EMMH6C= n1>&SJV{*w撱}oJlB;SunNiLM4V'ΉqHeKma %*jc[|#L$lx exbڐPRGjAS ݕ&>^QzݡFR>: Hi.-N0uhPRu¶x $?qđkV2r-OΪW9$y+Q>}G]Ee{5&hԊCo''[mt5OC{dRD>Thx)ۿNJrb [.vbjZ0(>Uo,-7Ӄv^Eu1Ζ2u;{QC+R= R$keۣ&;xZ7Oc/v9+w~t +tFN_Zj|!)OD"%O:\S,0[_5rz-¢Pf DWYYR_y B:r t3gո[f. ] \ecY66PdMՑ6)v՘ exSS;m9=N@E!$_~TP9Zϗԝ`j8;=YfeH2 gҥF:(*א4{h:0 Ԑ ߌ"4PDbۓq[PBTD fYUZIE"s +qʩH.i jo+h,o]zSn0> Un2S[*CV6vJISxD8LefY=,lE),ٟ:=2 m>q 2S^ٛf~85/:bGp%%}u6A޻+שֽyeδt0e"XS>z#_ m!ktK<ě.Abo[b҅ZF%9?dz\3MnR*bNǎhEz&DX6DW(]Q4Tΰ@?]- }(|3GLiA͖2xΝ&_WuF_JN]9Wu 6=, :af-`S*9S{e~?A׏ُMy#YZZ5E'6胎9X; Yρ97SG\(* ywc[Jk4(\E^G'3EZ$h!cصv[<=2vNѲ֌oR(; QwE7`ԝf̬l1kT n̮'H,~R4Ia+1[Gca?TaBt8ɥaw8KOe"MoFwm4:RO}$jis0ihg}09ar0PeL*B{dwEФ> tjmQrNDFPq`Ηx**|+S:TrGܼc1A< yF kAKx+jd#O$ckPUg6߰+~# @ v/ \c֚@ޢ~>"TN6Ub9%!$m PN/Dv$ҝ7iLLCO$9g~X e+π|A :TU:ř%CJUIٸ< /#;Ϳu|8#U($y2S4Wz}lFSD/5L6G8;VX@QĢd /C]/OO,dHR'9L'k=Mw?]ž05esHplwyr8ORHz,8I O=B60|4',>g~im.>ӟӞI}B$3Hh yD cfݜOkEcR~Ep R +v $I@ clBZ wihLeӴ&-F,\ܯ \"H\ ܐ-t0U/`BAs.8yIAzYz^ROޥF0sua w֠Qƞ8Cv> J=ł'%@zeO`\Z߭"25*=B1)*!@Cv/e ;B-[Qf)eﶇ]!Fۅ -Rc(ԡ^]MA0F"5!\wyЅhNmg/.'[ Kq6o1UW;<pdA l$ i` endstream endobj 77 0 obj << /Length1 2231 /Length2 14683 /Length3 0 /Length 16010 /Filter /FlateDecode >> stream xڍP\ ݝNиw] w A/3g2ޢ z}>ٻ!'QR6%@v L<Qy55f&+ 9 r@G'KϿ,DFo21#7Cy@ `aab01q3r43d@v@'rQ[~PP9r-MF@۷&F6U%BPY8;021:1nh M`d 9@? U#&49ؙorE{c@9f;_F&& [{#;K;s (!L03mhdz7r512~3t#2L-흝,m~sdv [[,&o}`{v 7;"3K;S4L],\bۼ́v&&&.Vt7`@=`Fci|d 8;}_ 04q-Dhaz[?f>m)_#fTUP?J; @ `gpps|7?/ߵ+ o/ ׿o6T_" T1Zxm.o!zk9M-]lVBmi;T⯍ޢX@N7zf&{;9g۰R.3ۙL ;mX^o7j tk v 7;H9¿EAF? (qALF?(q[L Qb}? թ~i7K#?ʷ fƎF&@83Gl t{n-& & iW[bkcf4|K C7rpyJNm6Fykٟ_7?1Vf̷vXx[e&|*767*`oBFПtoo/J~{_ ؘm?=e}r+Ǜ_ `~|oo1oK/[OǷz_I h2 z_#F;?KFM 6:+pV8yee[Fh븵6-Q ^ezdp}?!<ОkVN<.${>Ic {fգtqHa h.ܑnngr'_ei|NYxio\Pcq%!A9H^*)Z_af['$9ёFfq\#ig }jhOSgCk&!YRԧ7Hk* ᵷuu|#{|Z79c,*!Cs˻*֫j~}]@ lar:2 zaF'pM-:.|5w1n70˽14.GO77F"ivcfb+Sm D…2ZB2?L%N MQ?=7G@ig4jD(`DHk1.oi 'cዏȋ~v0wcaomSE%4|:;{n 'GWbggim[R1NVw+ͼĺ9sy;,'Uֆkd mlnW(4V#W .m%V R;ӇY$d}Bp aq ?**!E0ƬEIZj%`Ykiވ/>n#NDkf~*4^[4 T<ۅ ַޔl:S3#)˟-~Ggm,B#|1 (BwYJS>}>Pze ]e48"3}-~Sg7k**5.t#ؔC8ʔa]\+sdLjt?63n: }쫞"`X,(fs}|6ƢN-NFGԟ6/"(ۆ%L:X,`Ĺ1~;`7Ε ˊhA4[/]9L=,z,13?!䳼$V$*Er+QSfRr^NoճLNtIT̗fOSϴra/R&U"+zMK}5 xe_*T8:9!8 ǐU_ !Wf"^NE%L(~53§"d+GB ucF~S_LXXq0@[{Aa)lnᆅ>L{5Xr;O@o W1wyh i"u$*~r-ֽOy%'j'^T8< 'R[OslDựyKmO}t?sMl)GWRn5\ vw}Wа.D̓ I?L!!`A4}R6:G:gu> dYs/a)'mBCAQ\o,40beN\ypͧVq$(2O,ܮCGKpC]E#PkчA[2$]/> g9ҦN*<1 H_*hMAR38KX8/0A9W +`np"s+:7zG_;2A^|yF &kʩaF␩[b0̫'csցe6Y%\х1(c1p|^rkw6GVXO@Ov>lگC5^گe sU.l \qMC$X,3n .K!w3Ic'7 ǐt]<9kkF/Xn38s':pCr38HCF4n?v~Xi8T?19m-lkQ@J`/X(-Yz4Mu5Cje}$+sd c]aB)R$Ԭ/LkC3=eX0n_t3uV+,kӡZH R4đL )^ϻe y] %\krO^_67Pm31$vV0Q3}Ċ p=" 3mK% M.tH03;1vX$wrbi{d.o{Mjwb JO'I}2\C*?6uF ]V_u0v>p;*7DN^?ITZWԽPLWGěr*I]vrݽ[&sr4ᤋ3 |Ð :iqr7yGIlc÷w|6ZղzǦBRN7+GW[mc V]w#P|(lv~Uw(JrfN2zCyzЛ:##~@Y^^kP.ݦm=6n2kbd ;)h[z$Q-%Rl Q` cށXVx Ww}<] [> ˢ0-Vw=-h4پm]+m|k{SBZCsFm]C'8}qԌQ[}3P X#>44೩bM5]l"!!BeRc4):1[5~MI Mp*~ vЈ 5­^q&u%!!J8\ܲVօN`_EM#GdJKŒĽ6Vr"͟0WJ!UOrLd祼)n/r@曤:{fz B13OloJkSFEdQcQVA(xL~n`Eк9c{{~:r@9{-iXY_twi*JcİJ֖|wj້qdž J6cj^4LjƉȇDw B3%㾞]4$i6".K2R0 @sʶ8/˴,;iߵ-'fBl¯d TC3%cn6?xeQ^wjbOMmX3P'lg(aC~MWr>Mm]U*֯ `Yw' +?9J2LZQDx`xn$fynQ˅fss> zIbM^|yhiʮ) )XctR o.Ő8L8_ :m{!/ֻ*@W*hFw*LF9ΘiF&r,j/堐J^utCEv%ķFUn.P[t/6ݽ"6HzߒD!hIښ9:g}ʢܢU zssKt$,$1\Ӓ,,Qq B],MwdL1Dt,#AfH6:xX=%6n5`HlRbgt* ^b檸W$睯8H҄58ɇ% KY OVs#Ӓ%JB-Ӂ=؛!屋X'$ 7"## %!7Ά6pK.(ipI1yCɣ,Aj딌WMw$\"#blVCn&]]dUǙ^!6Γ4M$H|L ḊE N"jQsWhK|bxvkW2J˻&o`ӎmtW `%[a.M#e&q,|vH]QџnfH32'TE {fH P 7Yo2iA-\а3 TrI7Vlt740fV1vJrfB!}O%{枾7Um[As7 B~74 W`4)Fޟ:da,ypb-Z3r؞׼A h*uI䓖aɾHE!:{aANN9LΤ"yYT#/clݴz0mޜ5{>;^ÁPy\a$Q傚PdvU(A$J.7dprXZq(`ȖٲRD"w,I1j'W祤Nt}xv#%{=Q1/AE_d'*_s_V*s)!dxLXXyXEExQF\I;Œfq0G#n)|\p3AP`b|TB|[|308m2TSǗzrҲ538eU01G5,@42é'=9ϫL97~J" 4ڢ9GLFm ]m0w>3i[EbZC#ֵw`p$٥qlc|-f_7F{V#&tADߥC"M>p06sl-E@A7*[2UR',"T˽B '#0֒ y45'PAv 5א/mZs4jV2smw wJ{U4xl 6kL J2GL=N`u[H919m9Dz[&R𮯯fpg-l@N+<4e$EP}|:rOyvqNm<^c\ӫ"|5~&M*?O?5K IqY"@? ?ީՠ[Y> W.ATr Q?knE!~Mn^`#*[ٓ.xЮkn͞?/K4S_`y䨄Jp 3\'Nlz|oclKaYp۾;8%F[KPce%e_yWxčuL..4u'/i^QŞWf9!ގ?nKr9qk n>řp%a0: R| 7Hᅩа '6A&-R˹}~b}B k<,$RqZP@g/`XSπm59_I؉pTF' +[¶t] RCz4:G`:uk cCJ Ҕr bt ;eC|k#׉d?~~NpvJ5,'(Gu|ZBc$y(Yd7%Y1%CRbT0Ƹ%ǴцL![팂iyiڥ-3^VL{֊34RYI~XOLs,!zd2jK(Q3ğ7ZCƒkA$2a7u/saR~xܐl)BߤΞW>U tGlF3ļvJ5E5wHd,DS)XC_性 Fm;:ӠL>X{2\ ba˿$JoJ%צv+ܶ;c7}p.OęȯK1;[E0M>A,~qwҹvv!, 28Ko]l|aznF/꼷x<7BCi7SK( ##ڗp᲎|%`|S0[&)ǵctM_o' Kst;SX>ɫ.I"O(γ0>N8wU;͞x{Zڏ x% {mE5&6b*v=KL6J%hͭƊۍ+}px "򙘩A<#u=]z~HěQ=oŵ\TyW"(R+FXl9-GOۤB"#6zW8&'Z'V6>)s%:wzCIY@d ]DV[|CZiB~]gVM8x@Uq).;"{5)%槖̬`l–9s]Q`txf^T"Јn[tw_(^$ʌr`UB5yi(FOJn.>R-? YYgtgZfE~Vj cS).g[Ѻđԉ%JX]57/`s̸YP ?A|*L0֧[oLb˂X{œ>O"^$V|n^mP^,ZR+ɤ-JR:588y C2R/WY|WH5_ڠ:o'K}?"+%P n#T0w`D'_ͪ-ǣrI.`l`,Jj }̯>ToyF7/Jծ`Ŗ32[1$BrVz1J4W*hQD cEK 'Q F?&ݮD7Vt%iTFArf0(wn&8p >?գw%Ukiu 53¨ &bߟH~WnSQ.8ZFä%_v߄ZJE&_p;zn9n#*zyJg#x/χotD 9fɠOvэŚl(Qrv3>`6(C*e'ƕ ry v{FF//fd{_'Nq}Uhk~Eٸ(t8xURmۘi{ί9 Cj4V5Z?֌ִgdU<, X?{A8u@:)z~׼S7u ŽLwVWBSժ @+} n !AzdR>-1K^KXS,LfJW~NӻH8xԲ+jbU 04&k&AxżjZ~62 ȕWf=jjՂn;mH|SY͗UJK&CZc֣πd[šM+q4/|~,CpRz+ |S4:@vti5+ Z8 y9H0˺8K1-^sA5Ij3] 3Ѳ9;`)~/;|^TL%#KpCyhL'T˩+TЩgN]QK^jJlz3!+x[[,6h|=[r /j!&!_KH/`(&2vu*jyP޻)BfmP}kwmF@Xq~N\C/BrKF Ou+||߫H90^`s6ya27z/^ğgvjn琗|=.%?[6Zl}|wqS(`1vaЁY&83yH@m Ѥ2akT@qكH(A0RgDp:_)ZF3At\6N In[-**ф^nZDx_ЪJ/ [ .3 _g;CJeULpSiuOs̔k-+q4Os@="Ox79_L&·&4B-k.yP|`#9-Bo{6,K;5RIVt GH*o-:Ȥ].#hN&Yy6`GH%WNČτ@H\ :VᦾVjrB^˜\a@ˁIiR= p~|W sQEHe{ ?gr]N+b\^&vF\d=ȜJ(A1-BY'`JPK9TUͅNvUE3lX~rNfa0N-wkI<\Μ0Ggr<xjvݖDnTs@P)쒬.aږ>Th v6ͮ2G^;J{,W~XhV˱hEKhcJu6?/D#5g&` #)w2b7c}s%g"Ի[^S## {⿴ExX.:fAmoMj9Gj (kR:k͋$xqͦW'5Bp+oܙ}-)}n=K~ٍ #s_ǖt8<dNIVb9 q,z@N hzCbbUŤCg1c3gIXPJ``?vؒ0V*̇⡯x.h-n'{µd2D6 WG)eYn[{P {^@Η8M%S5r7h =ЌWu&rey- wRzc%iͥ_}51d(|/]CVU$D*2+L~ԠI|#>CaI/k|CbO sVx Oqqq<㋊uunKD GG-U=Z.K yJclUj* Hy҅u.@RL\ 7I XP"sQ=x}]ykH/<Jq 3,jEu@YnC!t=sW`ovAc"ʌzM?HA2Vc:_Gi3ܕZhdy[Xy8UJnD휝@wl LB,T[8[ vS ?ǐ'qѭ|[{Tuُ~*Emۚ!|lZ--ZX5 PEDmMzCTh 9Շ֦z+H,n1{1_jQF{mV[|{X9 A:= OVASsყGɂQ/n P(zd8ˣ"{ƴ+&3Ds'f[֤Kṙ:k[-OqX4}z!ج75/Incɒl/[NTPdVp(V Rs˕4ìmOci;VĊ}$#ә*vjZ)(D)fdgmDP'$x2EAp,G"|#v6F8LoLWjZZA]s!kf<"Cz! &iq-0 !#).;놎֓ie`ڿm\&'j>Y*FyOQ 4[7j5;`ԁRN*GtLߠ"]8sH }!Z}2:^eLp{[iH dd* Xaeys\fa0޿X9œZ:N!D SӪC4RO#rM 6aURURo]ਐP{ܴkU影.RXNzbZ;/>%/`;펄䮺$o;?@ j,[&R-'W.ٻ(B".wxxoLHrAo,Y Pq8[|#,!x! a&" gaݮSkUz9μҩKGI?GtWD:3~}Db<8ٯbe@nZ!o^Kg`L1WQ6 bYRy!r+"6e'.(?kEؽ g (ȃZlXZ1~<8܆ g{B#rZw=jk PMrV %NXY7f?|,+χz1@s\R1dbO:}9 ~eJ%5%)sI}ٵ #yдn`lוkX_ZDVruwDKK6p+n8\rM~fT krȴ֥rT:y°( 4z~դA)yE/\=lWEOh/»kk9zLT*"9tPA7LX:S!{*;_ѩ)RhǠqp>c/ q{h^#FO"ռ'[L% Vx}Oj'>EFHT͇n1ޡ%~M81RcA! E#JΥUhb:ZT4G2{ yȪ7cX/u㢵6p-Wi- (9ŹWde%\4|8gK5 )"VYoL6nJIOLeg{8ws>Z,3CD&=hӌs:2R96Tr!ip\z4q RZ?Sf[u&7!Xc6 J5ǬdԂ6Y(<%<v.cW^Vl<)56^z?~Kq9LKkWͥXT/C gBSp?'dZ*6uYƗhFҍP*:EH*lφreZՎ 0aHL]&0n%񣅈vˤʰ#O> stream xڍT 8Ty>#[RS}ָqT;fΘ9̌qݥT҅mW$\[֥hYR馵"ƨ(}}<ϙ{Y1h"+*.>TP$ F06%hO0^abE!\0-}l A%*Pm (i 1+;BHL0vAEɗ}_) PWX*Sa0 Rԁ/dL&#bE22Xb!.PPl!4ED0|X.$26!9"SyBށY`pD}_n*[QFlHW8Ǔ.7AeHŃ.OA+C8F yNap/ bG(@q>Y 8^)T琜(BEӀaXH0)qS@.̑(Fn: .?*(~ 㢈 \y䵬0)hH+Ь H{ܕ^6<5C=Ow𳛦; ө1vEq5C)6+LoWT|"w@G-S\R >(owqa󨧄o?HXA\X+3} xu@V|oB,'R |>pPbh6ax$RBqJi2 A%x %WjoKiQ)v,ģ&.g2ibH)۪T >ﴭ4@P!ܼrVEO{YԗY^YkdտyU죀M.ƿvwi?::t!%z}; oSEX&k;N<>o7rpM9ܩle̳k=5/~295H=tgܹwr?.q<ͦQKU>-<`Una,MTEk=^HQZ*VWzZ8"ja]P ܸ|%O<()פo(*1{SU%G-i͔ {saM.*|G>#}MK`cwzXץJL5Vfd5lTDDP):dF.5Il{΍9h[xbe\Lk؄W<_ ȢkxhtaAx_yU}(5l/%=,⪖5*{6{]:Ѵ΋>==KtQGob:҃.G, I|T=i[Rl:|A.MWT@/md'V?QW}oB~\DQսw(㛱5^fs2Yܚ`ml ~ )EÂ<Iԡ 뻫_uޥeuyedI ' '|ARɂuH|~[s&Iz:XVX9Ue/5]T7Qg`Dj9WqAt`gt_IaUX7;(Â-}>Nqƪ-]OW}h콕ڴ CPϺ4!7[NneۅE"7IKӱgv .qqa _l~ |p*b#}QاcYMM"a/Ϭ(XaQ~ڗ+!i*G_RjLT1"tfZ1V;~㲯_896y3_[2{Nmϙې*Lw"6:ݜ@3] ~ /7H?'̗>OkGyvγݛlmy9ǘŭhxCqW.3W^ū深Iŝk`v,ef['UN"Ǐs.Y %o~Ug54xo[RY*_n'<y~'2Vqug  m$'v8&iU~7:j%&TeGn6GzOPi⤂vUA!Uk3 endstream endobj 87 0 obj << /Author(Michael Lawrence, Bioconductor Team)/Title(Extending GenomicRanges)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.14)/Keywords() /CreationDate (D:20151013212829-04'00') /ModDate (D:20151013212829-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) kpathsea version 6.1.1) >> endobj 2 0 obj << /Type /ObjStm /N 72 /First 565 /Length 3099 /Filter /FlateDecode >> stream xZ[s6~ׯc;!v2qk'$m<~`dV]N@IlRݴݝ-s9AL ,g3)Iͤ0PL'эx]B.8<1@Qaъ) 3sP"$#' S W}(bځ=j!BDcAj 1@ar p%i$3Ai(SY+[r$[4 nHx;h2 Wp3(@j|1 s4yB+x3Ι,W˻2Iw gqd·)1uOMs Fհ TuV T.e1-c~\y5=wkjfmrc#2ILݶD  .$`0?+dB0k?+^)Zs2bɌ@>63$kCl-U ytQ3 < }tڏ?e(`Z;6VuupNW4v.aJ9ﺋXr ܔ)WIuJrV7Wۺ=]@\W6F"x]~lcR0r9C:,7H!4IK2ZxxljxB 4 X*m )ލ?K%eVa!)#{`&lv~]ԣbDQnG#֎8yf^1WN_@U$˓ܸn;-z[t̿pϛJ9˳H?/IâGTX*AJoQ?K@Z˪_N,n{eQ#i Aѹy3:o.D2:ɰ:]mwDԑhOiM-v]mg`%Mvs^|nۂrN*ڭ}Tk!zK/HyfuYlKOԘX^S{*MOsYZ ؟ ޶=vJucI~خX̶ts,m_$R,Q,jLD"$Ե nت<*7^jbw*uLv$Sl]llQTA-]^wY'iLZ$!r5L=g,jgQ?=GwG< ؞mUpr5=ZXw~32CilM%n)|.y~}۵s:QlG诩O[vzZRi!OcYdV+aI&PT ت"*IBb9J"001\ħ҄lÑ.30®D+L>%Q4&Sclagr !kzقA{C|JzĖ'H^R$c΀dJ@=Qk51CPQZ%t[jW$le}1O֤<6FzO(9drBQb j pq9Q9qKu'VE[hWCQz \'D{uwVȀ@ЩћwݎH )߶xcsm=ZEĂN,;WT"*4S-M/oΞa=6짧=ɉx4..twb`t|rG/ԧC#fbT\?+G-g̀7x4ܚ\K㦼z "c;¦mm-ß=~s~Mk^w]xٌͬ^x>j*9/ˢ)k~G|̯W8xq<<&b j;q&a&-@Ry)uM?Ϟ_Ggxxf\B$τ~݂B?w+mQz֫^^n (?i;)Q;~x &s' R.SttSMILKt 涟H 9˄-, vf:/ip$}O@_ Oe endstream endobj 88 0 obj << /Type /XRef /Index [0 89] /Size 89 /W [1 3 1] /Root 86 0 R /Info 87 0 R /ID [<6868A2AB788F39BBF5F88595C448D94B> <6868A2AB788F39BBF5F88595C448D94B>] /Length 226 /Filter /FlateDecode >> stream x%[.QKwVgu>+EP;1S< ADb pwyd.$$R""N@N -0 YhCd5.6AR!xy*p#0V=FFa*q&a afa h͸d]]Q+V&jzFY_Qva^6۷-h\•}[ }c endstream endobj startxref 102569 %%EOF GenomicRanges/inst/doc/GRanges_and_GRangesList_slides.R0000644000175100017510000002742512607330121024142 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 elementLengths(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]] elementLengths(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 ################################################### psetdiff(grl2, grl3) GenomicRanges/inst/doc/GRanges_and_GRangesList_slides.Rnw0000644000175100017510000006607412607330121024512 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{A quick introduction to GRanges and GRangesList objects} %\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 elementLengths(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{elementLengths()}, \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{elementLengths() and unlist()} \begin{exampleblock}{} {\scriptsize <>= grl[[2]] elementLengths(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 <>= psetdiff(grl2, grl3) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{psetdiff(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.pdf0000644000175100017510000074324712607330121024521 0ustar00biocbuildbiocbuild%PDF-1.5 % 86 0 obj << /Length 928 /Filter /FlateDecode >> stream xWMo01{X_q[AТH 8,t[Ec'FQJ73vl|$ jRftt[.KJUۆyq8ܝn[RJk}47"h ޕ솑z1ZJHPjWi@ ;f#Jky܆ (;+!*Kl4/j 'LZF;?"{ɨ󼟖`\kWӯi4\ YqT #HUF4WmRңTCRWl{[-Zt} 9@)H=?Yǘ*yzd'J'ڕڲV[SDګgn `aӵp/ў?ϊ:0DBZya='H $%@*CYgBsN]f$TC uF$wZiTcu"!9Dqfc(~FTrdؐ",mf* HO\a{O' ՝{ ,9C! ]*ԓ;] |wJ8w%Ɋl;$t2[>RO6q $-]U|uI J<)f,M,vɦ'8S,Zo¦ٻx*ίDz8U=q]]OTUt]F5j}`oqq~0و%g|:Ms90=#VHT%I,wbYX=f~\ U4P E;P&X%nNeEsBTޜFH3z⛱ .\UL(ϵu4KJS3`ufY6rFcJmM5|Es]$כՠ-#'X`ηPKܾEICۗv' endstream endobj 11 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 93 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 131 0 obj << /Length 1069 /Filter /FlateDecode >> stream xWKo7W(q ^ԍbDnѿo%׎:N T.y~3CR]2^e&1 fFٻ>riʲ%;&y9CbG4ȕ\G47_lM*Q`?W.UPך)0IޑS m&9Am,c`h%㟬hn1jP>2xZmr2$ `~XnwETr]tO$1g8Fz?٬c-z0Đt!=X[Xa(PT-JE(fhX MH?POZhO`O i}[0ʩS '$xA\H!2 N)hq{ѶRMh(bɃFV 8"Xly_(fQq#]U=- ~$Y.L )X9w|_),Qlہ}XY}W#-+Bb5sr"!Wx`RT<jIsgoW4ؔp^vTP72kO5JIͧL,6u'[?C'繋W2gu ]5 `\rxĹ; 1)= :%`OxK\ơyBS'uU;?-u!7I#i9/Q endstream endobj 166 0 obj << /Length 1851 /Filter /FlateDecode >> stream xXYoF~[e4--C~kP%ԒIM\M HͱuEgtpsN+.Ϟ>_=~'LUOqUmЫUOcjs!DxSWaPX K-j)h!*D]uQU @Vz9GAV- ,ZW~SEA\U!n6cƍba$*z9Q'2"DlԧRML#clfHC<2D<2Đ؛3n>߿ZÜպ7  HC_YZ&/-ԡ%c*}"'X^ŕɸɋ/' 2 |?h0"DZ MCY"qQ֘sPP6{*J#S{ܤM#A%KY1$EIbF{<]r`p6fnD{.{ k--|9 M OscGsG򀃜-Y^ۗiOzɛ(OZ̳JL#mII'f!XcQ+^jXw6>`> Mi+zl6o-$Y+xOpMqV]^W XV9̻?/}\ӽWpMZu W/#!YXބuy-,}71iaj!"p6 ιl< {d?}8ĝV@Z*"Si^FBy-5}d>tY$UknHYLWp`xDRZu`Jn?h> yCyC^`z, Xª,Tl;F6Covl 2Sɼw]d$q\ af 2 J]V4y/|]HRb 4PQ=ƒxF%POjlghv]3Gwcy梹Es}k o\dov qש{≧ce,ߺCc$J%o"l'c=sVHS*jW Srf: " x610#8FiTr!N$xQ_hXp[2.f5nW[zYgW\wYCmzUczw]AwmՋW32u $fD4(*E= Q%\7^5c8/uhL>7]Oj!fϬ\K- X[ |5VJ=vݻow%Nwy@!oޘsmԀxƩnu5O8@+,frGsRXh2N NބCWe)vA^^q$Xm `5wfLzܹ@uz,BO4=`Apd4#| *8 sxV#-;)&{Tx,LYsYd~k21glw''?#-vONW8bj[\4[LC~>?Go鞏aP뇀Z %J"$U_移^+2J_"> ɽ):<w0YHiǜ݃IU%${/kcR-t,|W%i^jVG~%'@:)4%H_̻vagbOi ˲/7/01^4ruݫ?~Y;6xJ&gܬ]l{;T*eϑ4GOlP "~/_SP Q endstream endobj 13 0 obj << /Type /ObjStm /N 100 /First 820 /Length 2035 /Filter /FlateDecode >> stream xZr7} wTʻU*zSH%-DOw֭!- / &VhT muB㛵h4|C   %,|Ya#jN8ZN uO"`W"(<СEd <8A1&8|"_Hk-A)Dm `hPbZ` -t~ ` z:+$=ae * <>mXJtxUq %td}a'-Z8r[y+"X7*Q. hD0 N$~^ s<w@j]12l7<! 0$8T'E/p"eh+zL`*BkL BGRJpHK<1YV"9+Rt<-ВxX†!;2`U'gr:kGϏy;a cW({c1f󡿞 ]E-݇Rɤϻr$e{0TmTb}󺙷gq: ɣoaL>E1RZڢk+d-CMkhML^m/v]0GN<ࠪ_M+ꟛfC;>Z`8ԞM[q`f kZoB|R{Fx2uq§>!1i,"66%dQBF %fQbF%fk>Nbl:;\bllvo s:i?Jtu|d.^;^&w1/j 8 $4g7[^ͅ<'7V!}79n;m\կ_c쏪~ ~:^8N> stream xWKo7W=ɱwǒKE#rdzԒ>3>֫li%9ɇ83. ѷY^YJza,|l3g]ҨOJӲZKbERr5 zY/0}f(fKiwZ TVI`K6RFr`Ƚ: Uᇚ+eK@ELEUjPfLүf9a=E#S[|Z,W;ETJLSZ}K Z UCLU8JqQ\- i#e$ĸCLJ2;f\]9oxFt$flp+/Z\S=H FiF_x'i~Fm`['^=F$I5 !s$)xqg dq3H V2*҉_*!Σ&QDiDB͡QG7ɊHIfF=Wvp{w,7L.~Crw 798fISu}GMz Ȕ/||Q"H/ U 'MD$hp.y3%: { Cd۫%ڎX × moCc+OG[ \kcBAB 6Ayk^15lp|$7ӣwӿG-qA&\shP`T^!n{hn}$sx$T;W dR׮=l+Z`.4& [EkaFW ϠA@*+ nF+ZLjN1 *>?* a'hI& " Qyے7Y`C  /C0D]`"/bhAßƛ@^zm;%3|}/GUVPwD>D7N -pʟdZiG]MW#xb7 e~x 8-8h?wS>cnhb8 @\ӘrQ\nBK^c᭶)K)lۋӕPė|<4'a" -3_ss D8CC=J!uj\a?JX3lIد2Od;O͕<S=0`њ`ޏ#brW&W= a>"H;08 wPJn^gh->m踦^QK0}`DDZ 4,<|wKs}uY n //7N endstream endobj 222 0 obj << /Length 1164 /Filter /FlateDecode >> stream xWKo7W( _KC&hb 9kK ɰ3զ4 HΓX og0fH=oglv-1i~-Ƥ)߹̖JZ:vMIDT Zi=xZ|H"Ȁkq!fe%C齎zNIW[﬽NlI*Sd7"Ph۰Zp+`bQrGUlδ-L9kꈤ]D"Ѧ<0sȽMW>#'HѝiBqQ5uf>I;=H/ǭ,7o9[ dKɩd{Z^I^Kiq1!,^|Ga~?1崗0 a~[g[']Jd$Z h`=3'xf V[=ÁV&SK%IHI):<ۘH>k(Y$Ĕ^d9ż ;QꍃdZp D\y"g Y(&=a=Է|$ʅ/ Y^)yKaa_=yR6ˤOF'bv[(2Ƨa<[%k2ֆM,.cLϿQO '$8Ŋۀ*`-Wb9{sjvԮ>,޽zC*$B2Lv=_G cFan}O7j8tAaBm {ܲLV] -{ܳ*)vH(kDR!+Pʵ Ma-'uSћL\0A*/(U4 O}3'ؾ",ZTt4]tgj0edȕNHlxBgQY?psُtIxaPnP` B2ݮoՇ싛8qiij 5MG{M~ʲH&`6qa !%ügi=E7{uI") ν]5YI`*}]ǫM!h)@kܜFg)kD7FLsj#B?F x1sik!сT[;@')O}I F8C endstream endobj 248 0 obj << /Length 1176 /Filter /FlateDecode >> stream xWKo7W=IM>46^b 9kI ٰ3|KZ;v6P+.? g>\`+ˉX6W7y1yw [. KF]}xL\TP/-v=p&#l0;n9.AIzD!;ҲP^G?Gpmkޱ Z%DvͲ[Ȓ h. QBb~\¨J٘MNW>p#]ui 6Q\ W! @"-Jo2yE< tI*ٮ:OAZt5,7-T=mbdKZnq0kC̅{|e~2/i?|aĉւty3" &ެRbjJ@>he o*BIhQ,) |fo_F}; -BT%aW3Oz.a1zW4ߖɤ^rĬ, O2 g2x}nෟO~- ryێ+$W*ύe4o_M]w{2@uș8"M{ 9Ͻq (<4nRf_Y}?j,F5u g 8}0:6) #KCm~ яhXO}rV"5Yq;[;/N<&OšnTxzZcylb*xmwq ;Etb}[Z6z11Mɳr -~k<λ猓`hŚSa`iޓ/ؼ]ڀ" ƽw&ģJj,UPmgסؾ@/D:64HId|xꤕmי|d98e8> stream xWO7 kSDڇQrT]97w9i'ymg~/}R\)>J3Ro;=i}zZ9}vby!VIG/o,B\6[S脩mh7b_Ab>ʈ&6R҄$ c1DR^K0}:t%~11*QtE1Co@ ˩(j |9Oţ6s6}3}e-9T YIugR4Tz Tf2g 3輆ݙ7I96XM1IdLz=n Y|F"S9mϠ}2ć(4$/fi0 rM0[ȷN(Q$T.(}$L2x艠%െ[oʼ?J~d<ϛ`UW[$y-2!Ҋ˂ӛw y ZHOsBeR_ث} (|-] ^:RҖʧJ&S&f)Y ޛ)*HVUK />0Ze=oe,8 o9D+1"B;l\l~RGhghs Cxj oq(YD61.t6 ޶!ɡrsMn]:H)?x`WPkT0m,^VZjᰝUЫI\L7(ЫA3RޢXA m=?}=[W KunIE!U9mRTKd])hIv0x+htrv nyS "ThuO~~\ .S.SBڨ9i1/y⩓˳Y(9%s&w}NKwgD9g.Kt`-ydmlZWzvM0 E(avȴ.kKgi Jz\tM݄R8-3yU|RRur) Ckyx ${7s,8#T B˔ OC`G0֨q"=Kt߇˜7Wv.]&7~Z9$7E:s?R^j `1#L/wN w]9W3ϟ>QFRoxo0~zoAnRw= ܷ~$>. ; endstream endobj 173 0 obj << /Type /ObjStm /N 100 /First 909 /Length 1618 /Filter /FlateDecode >> stream xZKoF W* 9oG4}HkdXo]4@fF9$g,q>C&!3B1J`LrTD *8 Lxkm8#D1"8}=!ৢ5A-gVE>g\ᢐ-$iJ$1 DI/XSyVȇJ&v򙵫/|E3WƤE S<̤ꢐtGCJY+&c!`K8GQ1E bH)ƪ-bEdJӮL SPCFa&Xq!| Z /)K({,gʑB9y\)é " Cw"7Bl0ǢaIT$LIPɢ-JANwTT#ê#94{d4E=5!qUM49X<E4gcv:-hB&Z@\Viҹ DlƽwC+Y҃E'IAdN6bxN4mK1łzI^{MiRfx 9:jӿ~_RwwZomE[o.3λG6RwtO[:f|VU]S'kCb KGGԝPp}}hj ҝ; dHjy0˱#퐃CsQZo[# 6$AupHc 9lh<%qo6z#~<4Z(&SJt鵙u'ݣū%-.^\qH{:QV7WAaZ MxsyK:C'=WXOZH͖V_qHnÎqqvEuhq%v=Fvv#Z+ *`[g{=w=ެ/Nl}pL͖ eɭ%Mozzs Ɔl(zl̄8>iajց&aZMIo24bxl^oW ^w$zi}2(`3O:TOiw\vk͊Cy555ȭImޟھmGRl&Ł 9ȮMoǐe("Pt )8B)ZJqn%4~.P[a79q93͙iLsSx9v@a-gwq}syp΢uL};H1Md2MW4<6<6<6<6<6<6<6<,a,4&YT8K gIS,a*%Nԩpv3iILZfb,iygIˈaIZ-1P>`04`cb#Hl xc$y /^0`xB3Y08`TL`f33 a0!b%?`%ÇgJ$iI4zDA4nDF4n$K /}'b_߉}x'$hIiɪLВ<ZBKLKfZ2 P endstream endobj 300 0 obj << /Length 1657 /Filter /FlateDecode >> stream xXKsGWQ˼g8 S7A#H2ǧ)ilB(c{f%ňFF³%;^^~Ň..tHʄezzvh ܖJ3L; 6g@T7얡oxs\N)&Ipp`^+C;[Yw]P"8cGF &lKENxJ01ՂrA9Uʆl`ڶs - k=ꁤ9j) !U!()Gqg-p!)f`I sgRRH_y߿]9 :w#G:|t+1[8eKɩ{|/z(8-<,&iNm~P<17al ta, ra9\xg ƸYoVy\+)馒<)3E^q-2mtyHlfsgW"zM2- 3n8{>S3ˁ; OX a|AyZ9F!ˍ J9* ‘?yReR'K'xqI8-t2nWKԎM(/!ß mLO?Q 3R\ Ho5@kvvތ_)&[~Sޞ||5T "}Ot> p'9hFEnrp Tvõ *'[o$kܠkǁF=Wa>G;MʺB$&ozzM (8 :Y(–I:6oP0V -Dw ѣ,l9ȏ4jBoLy#TҀ߁>s#A4NvW{!5tC H}/&eJ-CF|ls(Fr{ QLlϧl˥q]9Tf\~J=_I*8"\Qp(kh _tWY~73Z)Q1SՔxInZ8n)hG=hBՍ'ICz[&'Q`shZ֕U\)b ڳ0ZJbBf,ȇ( '/ȘS(bq,6U[!)~7' Cy%b2N*L,@MB%]yTK4'9}^E4jMZ.)ͪV0Z(5)YA)k}$xQ0:@JJ~tUqnH_]GSO꟡o)D7> Hx ekPLksx މ pc?0cc`>fPpc>vf_z075?_3>6,ca4 Wb$u,)v)bF*x?0ºFXc14̈rs&jo5lj''>Cm $ԮgR=ow+;7~,<5m0,D#HX|?YUM]wLkjށyy*HҼ!R.HCn^ endstream endobj 324 0 obj << /Length 1231 /Filter /FlateDecode >> stream xWYo7~ׯ $Y#@lyp7B+UΐCuB TEr87cYFOؠM8<~ vSI&7+2$IbȥTzM$U";2'(=A1GêqP)` X 2yRF0`(W: eC{HZ"r&GR ʒpCj.Px%ja QN4LC>l HKꀤBesr1F8e(E.0GH#H!?جÚ?=xldZr}XIyBJ'UN ,.&i/~4Gk@{Hׂ}HNFȒk /:όGDb gQFy x8ΔRI<i3S'Y\mcL6Ҽ^$Jv3 \e=% @) )skN3DI Ә hC̽~Ϊ/kd}p]pƀNFG[E rLFZ%$F8'0k-GUǠ0#X$M{8}{Y{/-|gr?kN endstream endobj 349 0 obj << /Length 1455 /Filter /FlateDecode >> stream xWKo7WХ^2HzAs)b !Y)k=cwf$ˊpf8p8 'VW= oⳚ2}o.-VYv}VIG]R(]ZL:X%b{ܬC%t1\ ΆRHP}5S$>fǬ 7yD.HM)C K<[xk|fqm'l &`pfę}(.ns<: v庒{ihjOHW s'(P{ɟOD IdnL4g3̇&X X%jg&Kpd׀)fh'NJ[u&okaA$-h6[9%}]ΑT; Ȓ뜐 \@DĈ A9p_xa͔m$ i2ErYVi4L*AY;ogY.(;E@FK^}W DNս]#_A5g|n֕%ɃfLJddpR@%6\h2Q6%@|tr7wtXѦٴq mͥԡ4 l ÔJÆ#@b>PezPhA\| '8yg| ?84e[{h,*~G &.f`˂Zt AjA\_MA\b%7ܒg \([g5maѢ+<3)ZP KN7"pF$?g5N>! -M&p)W`qցuq2 ԒiNٵƓGFCj]ܨuH83$@(IEdYEl{E{U"hɼT[޾WT1 Fk˭N%{H+YB~] \߈ԵMCYfo?>=/thj)F!0R!{|c`t*߾Qw{P%'Fy!ƲUV2.rdsiEKqw %3rTwuHG.5!4;:F`_eLSvaћ"GeH>7g#GHQDhKt+ەz(,|)_Hި=^G%- 5 endstream endobj 326 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 351 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 378 0 obj << /Length 1330 /Filter /FlateDecode >> stream xWKo7W=,p i4@^d+J$#𹒕n"`Er8͛e0jĶƫg&-FonH&O MdtKJ\ۢ\v[HIDR,v@i򉠘xaz8@Jg$8&䘌ޠ UsllEP;*RD/IT(2%а[ >LChb9%Jib5`eiSP"HNpS.v@).r԰gB+;Hc8J?ڬÞ;=XR6J3񄵺[jaZjMe3'#,JZUoLco|=0H1<33I‹ \(qFpPedYwǔԅT2B^g%]p$S Ǭ#bE33 W:rQp{פ&ISxhHFB0Y9]gX/Yφ|}ޕQꅏos B܄%z EUVHٞ" %nRʡS0O!zUf`تˣom0[ |倧PP✜L5SDh y5tcެca帕R6VfSܜb]{G"+8Jsx)hYK ƭR9,]"\6_у5Ph@+[J0SE (ʄ~8zzD.%Mvp``RiO@A;hCȁ)|fm*V΅ҚoiJ:99b: c]"zYw4p6P}! eeSB1,ܙIQ^نX!$yr뇛S"n! 2"ji[`hM1q3tt|M0.bY3]bTA8^3DMI> oFC\N Փh,=5d@y'׾dglw/Mrwqw&@6CzM:ƽ{\sjw]_BK 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 380 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 277 0 obj << /Type /ObjStm /N 100 /First 915 /Length 1750 /Filter /FlateDecode >> stream xZKoFW̱='`*=n`6ADM"ܦߐ#5ΓuDi %c$ȐL#'22R2Q2SvP Y09T.y 2İp&eh33F. p\g?ɥ( P(^FB5 hGꅉ*q1ru6D3px11 3>M6|I2)X0M  V&' BS(dh"El[Ga`=Mf ۈɢ('Ꙓ ^(Ip %d-\eN7@Hıb$4 9X,6bb,L,  XΜXD̄d9UI )JD Cd#k` cKm9A(%F]Q}RyΣLrr4R>2/oPuժ3d5F>ԤMh)R#e(o HqW*/BX<Ey[9dem2b-$"/RMupP5zRsk\mѦ;q|Z5GE~hpߚ渹}Ϊ=CrKɵb-:8攚+j7?j龥 Q}SK~KGxdG"L# Jh#~\O,Rv #t$H(:;;#.nmr[ #{ifv;0dҮ6}MAԮF:8hNHwWG77cm.ƹAgWaV?WLAIu8/w麆WϞi^=[O_[~fӮ߿=7-DVMW3ݼZn`̓.Y#vwzu~"aΌ ]O㶂M\IO$ӗy{mS?%ukWn7j<+* m 5p1)_#Dd6*JUzAeTT*^VxE+W(^Fk ]e>)^ˎmkG\%WR#6FF.3h2jNCH&b<.#1C"GZG2uL8azw$$$/R"0mu$Yk_%tEuvbdG>pIk/4:޽֌DK&Z2ђ|:ZR Zi`/[oh`+g+οW8*~o*ʨ2*ȏ**U> stream xW[o6~ϯ࣌U*車 . 졉"b'"e?~!EJ5ٺf"yxw#gٴ/OZެ~u# [_1t} ܖJU6LU; -;joFb5v]N)&$83v𞤬`ZG;a+u#ͺkZE%U 9 "i(|\,;GTTJXM<*S=HSLQB#A)-9n+C"w)1{Hc8l9Uaﲑ#H'[s+T-DefaJ=߂?OH taYra颫9^xm YojA<&id+% v\iu;C߱(I^,t Ԝy2d <  dk>VBy_d_/|zA>BiR)lXWO^2)ٓ wI8)S25y%^e.1t` (dwꗧ_M[*0;Iz5WS> stream xXKoGWr ݃@)*ȻwmOUӳk A lwWW}sv8{G厀;wrw;aX1Ұ)IM RNN{d;[V` vPw];.Ry$880coC{B[[wP޳9"E%PN9"*T ;q爊N)i)pw|[ ]T$1TLQNS!@).9唶=OW৘[HC8Byi{sV=كu K{兏7 YnPiT),-ɋ,=Y:K!o䦓1]dzJ^e.Q;C0nl_2|\h[eytx[!$M+<lzmf8MaDf6LDsH׬&RY~6l9,kܕ0~BV`Y~ Qz)<3xAa,E{~LZuMn#y/q?Nv)Hǥq}=kpieQTeYY+4qm P5,K'][Ga  L !B'e rmޝb S$]FdWlO ) ](:01hzUC#BEWeOER͉F!a [aI;g֜wzфYF1SV?u]HQ EB/hذ`TbkuTwU %;T.72JʨB YXxx:P$!0c>9~x(XҋrBN _{,_ kuH*U*LO؂n >5A?py4`ޫ<#D\ i(B^( Ot aTO7x7oQQ!f{$G<K$i&%͖Rxv'4$P9o?HPXXY[ \#TBSfCx}m ?BqIWB Hn qu\6DQunSը:y3m(nG.''vT<3l3±jIoaO|F<%%^w>.?Col7 endstream endobj 456 0 obj << /Length 1463 /Filter /FlateDecode >> stream xXKo7Wj ߏ 1v =V{qsp#XK|g]iH%9|3 9KY3&؋^HhKnpno˝׷~K*Vgl[t0e4CHj[2+a+inGz6 Be\f}B^k`ר唀}MsDв16T^Fs )l'I@,*&?VWF%ڥtC`%&r$HK*Hb?mQ  l^T_?xPrMJGCIvx7VEş].}H^RNخB1*5@B"cfS-h:l r Rؐ%0e-`æ'kB3&^NoVVk,OZ &q^gt&o/?D %p3gT73pd,.ºw^Ѥ54х9,9+tlq"ri_`^icH^sn7f;[kJX WLaX%:J} PL)-`)v kBPPuJSi ˜͒kx[XECcM|'cش3PtY<:*(Z6OpGFaw oId3=sL%6r*t7yw^ٕ:Ew#sЯ@ܗ+0LK~AdA5d<]BT>O[-JTNR_&ttyyf~1\L>1_I~$VU*d5`aYwjM@9YC.J2&~@gTMwscDno]hXy#17s.]2·/5OsaAG76mobxJ2~v'4$P{an?'mc 0~@5H]a5w7Z744q ShrkU9ꡍ[&ǣP^QLHBϧ;OLf hHcr>kU{Cm m~ GiC|,gTf8ץ*y.R5[cIuX^N/R3Xg{\bP_#|_v endstream endobj 481 0 obj << /Length 1332 /Filter /FlateDecode >> stream xXKo7Wj o&m(B/nZXR,9ȥ?3\KJbn5r8͛ZK&Hl7#Q-F_- y5zG?Fdۤ}R&-_ R)ak(7lF ްO<6.8SIdL)!)+21d:ڊؚ #:Q"x2Gj)0LCdb%y0-N}tܣIZPWHġynEL[^dB+ǘ{H@)YI%}?٬Zp,D;Z'lHg kuneURk*AW= Ň(4"-fiO4?(_{i~@m`S'{(kK]6s&)`RSܬRjʼxx)|Syt+ Ǭ#ϻbE33Ď+*8սSkVdR-RsPгH1qءlS>ce>AzӍBAbiR 6N!)=E:KRʦS0w! zU`O{I _2z\ڶky[1KῘWz%l26B3i 6f v1vchnWcUJ5VfƅsZjU/㷓_i7Dk%c8饗\3gDe]Cn`ju}A0dռ"b_&u\fIY Bݢn%_0oZPYh-(OcKɝqi0o,_K޵bY◇Lq sRp4nT EEaOaDK">2!?_*@7p1=q,e,,$*M< YDgXQ]&Ŕ;ztuqAܛ2a$x:41ٴ*Y܂%FRnY+;n6] TjkeԄ> stream xZMoGϯcrLwud!CB+h$Uo"Xh5MGϫWU,B*(J>d I<2ERIBHqkJBN=g't.|-xCE$_">Up}RlBĢ*(E]8L\5XpWnXqF `\ J @%W}MkncI/Eo qH񤦈OE$"4^$P Ť|3>b:&SrQ)Jq ({JN)ead]X(;}瘡:`5uLP_@pUNI9HC? JKJ#PUsS蜊8*E}4%„0FٯJ\&őL4B6(IF(1qP /DK Wzz(ZȑE D5fPho I@I狦S ٳW ,oUUĄ6'x5+ nmВAc/kqI7fIj톳Ϸn\-7] ? H,/,8k3^CAs="ŠtrB kw^Xl׫=ݹ@DRhD|胄DLSl%߄µxJCxo֗gKd 4p|xbفj\mo57뷛M۪ۣ_W׋{w&__|qX(,6m&<l2ug3ͲYëW ^5ѿ'#> #}Oϑ;=`:N< fl4f de2OdI>Yd'>ɬOIpO>=IL(_CA0}LobzCLoEË / 0듕'a*D&Od2$d'>ɬOf}rLN'v I_CD tB2L'$tG2ݑLwXv$H /^6lxeó'LHȬOV>MFTI>'i'>ɬOQ endstream endobj 507 0 obj << /Length 1389 /Filter /FlateDecode >> stream xWKO$7+|ȡI{n{l@Y%ndl3DL%?>_mY@H=n_U}U~4g猳-^o nvb؇֧5goaXgas*:4\"üTQ0hlk> ΰFZ=F[rHZ`Ď'e%Bi~nW`Gޱ PI"s{Œj Zɘ ۄ2O Ii810.A;3*lOm|>o&"UD$KT# W!7`Cڢ$  "Aʑd96mkOxtZKX+OZxRS):IH>DnAq0aQ||D-4/i-I'LZ˅sI9.B[7묔P[mUwqLJBHd8ŵ8<Řl~HfX cw?(INYX-)] 1-jaS>a%u Kc,7dRhCvM'MUh ǾH9蘪ΆCD"WW2N!HjE[oqmZ,STzUYEABT-R4Ub&L>C(LOf@]fh ^hZxme29*^LmUқ"Y_v˅6qcY 7ș\.y˵_zzun5IXOu)), C}Q݌/ ya['l% /O/ w endstream endobj 532 0 obj << /Length 1088 /Filter /FlateDecode >> stream xWKs6WHc"pL&3غ=845DR.%qgz A,v}xPPLo3VnY/?DrډJESV>hWl7%H0҆(&fSb7JM N 2 RBQ]Q hŅ}$`I b:!hѷQ`z%.`#%L$=CV7q>ϻ_Xi5BD"lHOS"̡UJ]Xܢ~ pB)IO<ֵ^LFP)lP; =,vQŨT1C]1vv}=Tdk/c~'Ó{EogaK^c/*IEG*zĜ^khd$(k\݅=p'id0B]t(D&x_rN Nm%ҚQ7)D$.=njg_aڛr]%<6t,M >u! uS:dEk&ARcM$TzUт} !qxKeyFy.Ek|D%by9T~oPm|m cLߖE"\'gZ M{\WQ,B֙ۥQO gzx/0^g촤~rsk-k[{z9תfムna㯤1ױL&+,B#(u:TTUOު͝ܨjv8p CY#c[nȫ<?$n ۶wp#=dV6)A3m(͎V5 yH yWX{Mtq*v~C+5:]m&ABm,fKmW:]Ze}8YBO_fK;šj}yT;{z(Ue)^dm<t޹~0Uxsyӫc 悪69hzL(U%r?t9, endstream endobj 509 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 534 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 560 0 obj << /Length 1496 /Filter /FlateDecode >> stream xYKs6W(T0ؗ;%۷dH=_])Y&DԮ2c\. #SoglÓ˹#,>=O%YMɮj,W[h$0',)"if *=M@H:#) ^g8iD `&gp 0j3mvC@(i朳dx(yGI<%H&k{yz oLWɆJw|:#P0 i$j+D`Wd8W_jFϣ {[8fԢW3;9lEoBR(ϑ3O:6׉H05 q6ǾeHc_! gxĄgi&՚qGc(P0QE6V e:2}` 2$V!~E$JSѸF.$m3B!>;&,0}x|)dćA~)kbUY3K1]Kx  ~YEZVrZ ŹdKEll2A?@#u"=1Jj Q-.T`=+ި;km)GAhXi)/ƆO£J+d2F!y|pV6@Adc4/Y76$sPbhQ[. ލW>B#&cQeEyؘ!/#dӂ 5dחAl٠ vȡl=KaZBn+Z$pt،} 0iw4vuWod9E-7we#p0&.8x۩߹[QQ[ϘX dTL =XVN;o!\N4v:lQ'=5A>1x|koͪ3itZܗ^rir]OÀn?D69{chAo^ѣ M~hV[.iUJ,&~n5p̔%*Ȯ/O Miwx|Avj}*%Hž[W4B`^QC)e6oe!YAfwK_JH 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 563 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 591 0 obj << /Length 900 /Filter /FlateDecode >> stream xWKo7W(kѤhnu+zH7[ kq\1\#*@| g>|>ԕ"ӆVƠ&5yf*u, Zޝ 1Hq6#lӮωQ{$D䠾(6BGK"8sB߫ 9g g<CzMqlpn\-di?wڙ>u՛tX7=|?C57vl|׷o> 6nO-"lE]?޲vi0ImɆTqG㰐+ẔpĠ6fc> stream xWe*M32r4i 21MZL 3I-,ʍԢ,1HrJ͍ewwr'~x·ϼp«.5m~v ǃK\GM~9KW7裾Eb1y< t*G$sg/I"}c%,IdoCOsl_e @qHrT5KZj6<;Q#I:Ȑ߼?'җ#}8Gk/H<.-2)NyX'k+9#Їf߅"3ODy8#ЇH‡_!ҝ#}߿&rG#;oEFrD><#}alp?RX}x#2A#W5c*U]_v򸧘}zwvt@0Ut {9B}NcVvs4Y*s"eq4Ɣ^JCD>\i٠xƘڏ>>>>>>>AEѺMxG6ZGqh|%=˹YAnuVilc}\'ǡRt}۠Qc^V-C{Tj{q18k}PyG]W*Zc@WDeg5y99Defv|zD: *0b=wGdtsVXv*(7}}}}}}}}}}}\}v{tSq)4ыMRaXbCpE/P46]ei*c愢y)_i2]el4S2v)BDzLO[kTƮX2vJW]26s}}}}}}}}4>t~u{Tܩ2v:X LtthSgW+쏵k{ەnj=a[wl7:6MFYшnh_Ea[X׷8mkm޹TAlo}+ή6uUƔHmݱvsl_T}U{]8sGmݱ];s⬿lqnE*}GXag Z֓3f믭 ?T endstream endobj 594 0 obj << /Length 704 /Filter /FlateDecode >> stream xJ&+8>?@DEHNQWZpw{  !!!"""###%%%'''((()))+++,,,---...///000111222333444777888999:::<<<===@@@AAACCCDDDEEEFFFGGGIIIKKKLLLMMMNNNOOOPPPQQQRRRTTTUUUVVVWWWXXXZZZ^^^___```aaacccdddfffggghhhjjjkkklllmmmnnnpppqqquuuvvvwwwxxxyyyzzz{{{|||}}}~~~C endstream endobj 566 0 obj << /Type /XObject /Subtype /Image /Width 800 /Height 170 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 6388 /Filter/FlateDecode /DecodeParms<> >> stream xyPgg@PPxcU0.7n0]J\lŊFɪZ*k]#11\ =+] (@C~3='O?mRE@ 0d,X$#`HF  @2d,X$#`HF  @2d,X$#`HF  @2d,X$#`HF^Rd2L7nܨю'N(]QAlrΜ9j&iɒ%=܋w?=zbZjdֻ@R4i#RfEo_n]ߖk/eee-]tҥ111|rzzǏ{ӏ>Ʀ$;w?ӪaÆޚ<{}͛7yb3X䈈P :uRvve˖-[sΪvWc^^ޒ%K^Oaa׭[W|խ[_^]7olٲYf)"ջFPPP*֭۩S*4z;wvqRJ;w3g!!! K.UN<ʕ+>>>R6ݫ8Ço߾=44TJ%)--Lmxzz"]))9ss\)))5;7|kV({~ ,:udR CʺvZJJJff_>}_dׯ}|W^uԩS :{!D{LK޽{vB vԩ322n޼)h޼í揄GָJ X=z߿۷^ ƀ4yL6ÇBnݺmڴ)11155ȑ#!!!{\bu)S>>C 3fL\\(իWݳ>kFݳg>}eeet޽wСC[nF{[nݺu2m׮]WUBiӦK.5>ܼys߾}wѭ[7m{Mmbyʴ#^tiND؄FEEmn/`M˗Ƙ1ct2LSL1fҥKVwwqq05788Xmk'ꃢ(BC(J6*FyK5-`\e>Ųm۶j\``՟/T&O~ΝʯN2tӦMVw5kKڨB /(%%BZ>}t ˟Nj6mڨOhK1ssݿСC3gT;' 0@Xz莀4yݻw=yF\ܡ\jK*(**RլвeKQZZZRRRCk9666}݆  1bĈ 6ũ'璓ׯ_oC^b4,ׯ~Rddd۶mG_^pEN>uܹ zJ;T#ڵQ؞WՎZ U(??ڵk*\Gjڜ{ե hL&֭[UTTyR~ԝkCUjQ#rgXiS~m@@@@@@`}j#111++|IcbbƎ۬Y3m{nn͛ƎPgтNlggWyVeɗ>>>-ZPVWmhժڰ49, L&SHHݻ=zgϞ>_{u߾}3f̨<^y5:V mGULQi'lll:v쨶)bi_`4nttO?t_J :TZ;m9~~,Yk999լ(JFFڶk7@cCM6EDDDDDTVkKc={B9r{FUyqsuwwwww߱cGUIOOWpssc `M^ll_|_߿['4*څ3G O9ŋ-[{}zŕ'Ĭ]VmkV~}޽{A4r,=z8s̨Q{\|yտ?C ,!:4bxs𽽽g#F ,իWǏ{n! *ٳ/~Ӫ݊+vxx!C_|9!!gHHȄ ԯx N>-6llЈg߿y󢣣Ǐ?~xnٲ+E۶m?ZJpB-9oU*Xw˖-tRlllvv)Svvvڢ-[ܻwoV7l֬Y/_VOS8qĉ';wܵ4u`ʕk֬&bŊ/LsΉ'zxx888=rHuZұc$l6ڵk3-] :ŋVS;&i[nj޽w_WuvJ dFU}8jiii酅={Ԗl&L[oY=VG񩩩O>z7^ywnӦͪU͛WcW!o߾ZPPصkWs}w~nS4h֭[:uһ#44ۗIX,o=z Õ}7B PHr4 !!!GNOO_nedggw5--mǎVWk۶mÆ kks4[[XIIIFFoO*,,ҥKVVVbb_}@C ;***+++**J:u0WV^|r`<3X$#`HF  @2d,X$#`HF  @2d,X$#`HF  @2d,l.@ͤ޸q٫W` O~U_NEѻ50~;;Ѭӯ?.//ٹ.Jy}.p hbEbuVJ0EQxU 12Is$#`HF  @2d,X hy?ɓ'RJ"EHk0b hP41IIIwܩ8;;kuE9zbѻٳU4d aXEEE˗//--ջ.]jk(-..^|yIIޅ܀ƏwԚ5kڶmg]E,փ<="\B<;;U2"33=gOƍzΝzHNU'rZF`޴_sѻ \ɍJ4jL`HF  @2d,X NBԻ2B[[[!N{{Okh|Kc{BKn߾}.!./Lk IMM=z;!<.ئ>{ 4HF  @2d,XL*Իc!؊.ELC qpwxu0IB|MeUdw/)(z`(  @2d:Ex3g8;;[eeef 1D'׫!ޅYnn(tr͵X,[ֻ#{q``AtAuL}0 .4k֬SNzbd trtszbdtrzjaaޅYRR_պuW^ywe[NN#\}[IQ}+0.HF  @2d,X$-`5Ř1c*?^pӧO/**ұ0#Ɍjӽ{-[:4))IHj'3ڲeKNƍnd$euɊN:vxȑ40?B$uKIIIv6nxΝ#F/ѷB Z{999>~xŽzRɲYd,Ս7ZjuܹQF} #Y6= X%%%𢢢̙ӢE =zPǎҥ~DNfT˵k׮A"ɔHj'3ںuرc;g$eu\"LKKk޼yHHɓ322t)èϟzjWWWm͛7{{umŢSuQr ><&&Fm9sŅ,Nf$(Jnnn|||``7Y6H'`ݿsqqq'NԥGNNvvv.--׷$aTԶm[EQ3eʔd21Ɍdlllf/WW׸ ~edNimll>|w!FӾ}{'NfsYY~GN.Q-Effqϟ?na$KWc$K_Ja$כ\.#Y3XgϞ=vڶ7vvvTܹvPrr +tHƨ(((GgϞ P72Ɍd6lذm6!D6mfϞ}ҥ"F\V;YhAAqN<%K 4EJ^C ڳgOAAAttthhZݻw}驩eeedv2#Y.77+V\~=??/wpp`$e yh///''c޹sG2 իsӧM6ӧO/,,Ա0#Ɍj,XPѣG #Y:,bYhcPPdd}GIQr/.HF  @2d,X$#`H= endstream endobj 567 0 obj << /Type /XObject /Subtype /Image /Width 800 /Height 170 /BitsPerComponent 8 /ColorSpace [/Indexed /DeviceRGB 250 595 0 R] /Length 2499 /Filter /FlateDecode >> stream xy|mmk$!VVX* C 4 P I g XPRnD@8 B`:3dw0zN<33_fY4 T ҳoYe73#g8xR +o>m$H#+u>-^WY?5m2we_lLltT|m1 ]|-Zj&'Zv&(~M`R')j{8J/c-]̛1,]5vpָˏ5DZrNx֚k{{JǾ'=ܦv|UbUf9V\΄"'qJjW=0H .1LkY83K0wn||Z}Ȟ?Ṫ]Ts4Z|~o;cf FyZSR۷Ll'IzdqR'cb>ˤ>J+6)vߕ5~+}뀹p&Yzh:L|+xcoyQcNb+a|[K[V;C3Qo3=}hԞFî+i8>4lk)+tLCR4:f>R<|>_ #Oʎȇ]үK%kqZj^9 s,;t3;f>ͼX=+$ s~]eu>[K}Uv"⚘h +gdOrAD>ʯ?Huuedge-QOhx>Fcd]*gdO1B]+n]6uy*祜]^V>RbaW^vozvH># o6;˙hgaiӴ7?Onci,5_zHvP>n%YxA85u{Ԟ~eW6ZKK2<5K3;U$*n\l/J=A_\)JO80''YKRRQ%?PUa&k=-pHq/9O҂ɞkේ"{ ?3U*"3&9y@g֠o}cկgc7tII`6^;rh_*fˌGNcӲOaiHϚup_5?9@3Sw*7$sJ?:0N J f86l2|ZL)4A}p3A7NpeMsΜ%v_隬׳֖*\XTwL͘0z\rѢ3U]6V-ezCKPW+^.`:@+^yjv+\­5wPd4IJ7TF.6F'RWXS9hܝ8Do zWF}õ0گ=A |A> |A> |A> |A> |A> |A> |A> |A> |A> |9/!+g#_w- [5! cyR6ӣQ Oʎ_u51&} l`OIi2cF>&zrʞI)3<);m'egLlON"|A> |A>3=<)e'en-h'eo4T׫v ܳpou{ .h^qGk޶R{Q>Zۣ]w]]G{)9k VAK˺=Ÿn.hw7܇\߷vn͟.t=!M5I8Qn1emiTa[lv]K|d>genuMy0`YGF<m{uOG|'{0ZDF[/mlv 37"ym cM ˺=^*1]qaTۣVhW$Ŏ\_/,eqn}Gku{ Z8;.{FFycwR_WqGuyz|) 1j endstream endobj 595 0 obj << /Length 764 /Filter /FlateDecode >> stream xABCDnprw  !!!"""###%%%&&&'''((()))***+++,,,---...///000111222333444555777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXX[[[\\\]]]^^^___```aaacccdddfffggghhhjjjkkklllmmmnnnpppqqqrrrtttuuuvvvwwwxxxyyyzzz{{{|||~~~I[nJ endstream endobj 568 0 obj << /Type /XObject /Subtype /Image /Width 800 /Height 170 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 6929 /Filter/FlateDecode /DecodeParms<> >> stream xyTgAQEYDEQI8 :scΜl9Y80xD3qf4q#15m\@#"&@ۧA}TQ?V=]ePE@'p4,X$#`HF  @2d,X$#`HF  @2d,X$#`HF  @2d,X$#`HFyz)IOOo׮]LL̍7&N_jՉ'N8a4;u4ilٲÇحZ~/X[[im߾_WBBBJJJMMMN _~e^zɦ_xnΝkYR_Vƨf*;;ãm۶wޕq_p=.]?~fff+`E({}G-[`ee#khvC ٿ~WWט_]Q{`oXYbʕ+W\w/uo`)z뭤$!_~{޽~iذaB8cƌ,;wnn~m۶Ii]1',;wMnG 8̙3111322kkk?nz̘1B 5%K;55R-.F/rbood:u qqqyܹsܪ*ۘ-N8ս{pWW׺N>yddd;w~R%11;v>}^fb޼y|/YfG:t`4QF=n3욞 f4wٱcG;{l]_{5uFF۷o曖YK.۶m5(9ee=zػw_jVZ)RRR2m4|ֱc۷5>SLB 2>GQ| R۷'G=aݖG_y!Ę1cj35XPeҥӧO6;tG6ZzzzHH_|CCׯ_5k{R?s-O0ac^M/**4hЮ]E1m3go-$//oBYf=g !ݻ7|tgNNNffuĈVp„ Ə?hyTDZiӦ?\ ۶m˗ϟ?zvUWWl`)EQ̙SPP ޽ƍ/\pƍ#GL>>::yo&***::Z}C=„}_{܅Zy3V~~~'NTqSfn$$$utA5',w|}}'_TTT9r9P7z p$,Ah'..';vAؿɖ'ƪƍk`{O@&w-A-fΟ?/pss+`i= Ns΂ V.ZBCCՍJ{ړ@ԯ_z>Z}…ړ9U,[ڵkBOOOU6[nEz#-ZYfB͛7%H[ooF]/+Tӧ苀8775k֨[nرcGzzŋ׭[׷oߴ6m4pѣGݻ7333???55uڵ B :wU>}:44tׯ_uÇ'Lb /u`09R5 ѡCuEZMMȑ#wQQQa4/]4eʔ={!|}},YRW_~E1|';נvx&̚5+WB={v̙G]\\ϟ_C4wǎ;v96mzd)}3޽{׮]7o9˗/ xFu֢ IIIٿqq:M6՞w޺n~R{,q +Vܹcǎf铔4tІW׭[ 7նmO?499糛ўaÆ?kvT?1zh-НArvh4&%%]p˫_~ xSSSz^zY} !222vjyBAA?[UU=p^z=h:uj||^QEEEbb7߿/[Sƍ;p+Rח <Xydɓ'###ׯ_ܹ:t(**Jf-BX}<]y饗Å[lѻm۶^z p<,r<|P{Nd{c0.]*ذa'ڿB{i$tѣV6loooKɓǎ_Ɩ-[ӇިO`7lؠ̙͛c?ӳgOׯk_{*++uVTTt…,ruuuqq 7n\bb+!Dbcc U@WvڥwvQ6<9;>>^BCdƌ;wJ_QR$4H,}("D?!>ӻ$Ev/s[QޖЋ$FQBԻ z`Zj%c&(ЍQE)  @2d,X$#`HF  @2d,Xg} ! TFl0d)18%5#`B$݈\v5ݻ2frC`S!lT,@6(zl֬Yuu.bccx-Zh'&&G֭~9AfV˵{Hu`03:d6onܹSpf\VY-›7oN<9((hƌ999/^v֭[k{233n_5:u ,Y-׈#@OOOf\V,ٳE)--MLL,A}&n߾`L6M6%%%v˖-kjjm0V%!!a̙_|``&eur9999;;ڵuXxd٬3YKgr''q4ݫO6M.**rvvկ5a:ȦRN4),,̙3ftl,Qaaʕ+0 e&sԩSGU]\\6mK'ω.]hJOO tr 1媪 >uTxx,Af&c˖-B// TUU1:Ⱥd}VTTL4ĉw裏"##===u91tТٳgݑbV˵gϞ7nܸqFmm-3Y.Lm۶~իWW^֬Y3f\VY4/ի fv!!!^^^ͫԱ1Gb6j,Yb՝;wfTu 23Y"GEE]zULAw&EyZYM_X$#`HF  @2d, 3i endstream endobj 484 0 obj << /Type /ObjStm /N 100 /First 916 /Length 1767 /Filter /FlateDecode >> stream xo6Wcp`HsK8m ?lm]k-֛^wY]jom!ɐ93I}l,(D2d&/P@9,ϋ' $k[,v!v1\bK&((Tb)buC[ef'k AD>Cs${QO!_F=|5qL8< ԲH!By3NqB0 x.!R:QF|JQ5L ;DCX[JPS#IbhMNhJ CĪJ^H)z(BIlsL/ JAa@NG j+8t:>Q2JxT(HtT|L#S Q) bbh"l%Uw:B5X"pMLfZ9U$%N&W"4rjSbM]fHZ"(kҹ}F1G, Әu%c,4 `<{W`Cwx5Gdk  ƠU\UaaohHcX3Fc2╛{O=uamwoWÏMd7םu_vϻ/N[^[:EZ`!6iۘ}u'=[ZS>{j{$~N5ȇ,X6 C0:k6q"㣣{z_@ӳ7SNfXb뼟erY-&9oWi,j%u|×B͛?׍/o֛V=voSNmO<64z؎q#;Snʺ{4'm}Ѩb\?{YxzLݫnGua+Q &_\Ӹ8!ٷg 4nV.ͅz)N7"_#O&Muՙdd0MjťRIIo2}09s*nlCݝ `[$g ,8|@E-ԙZ7L+8* 39"̳o^Hh3<]yrϓfIvv^:L#ٵI/OI뽒&M`o8;O yRHq7.Y_2.ٹ;$.^_?T$eϞ6.a#~~ǰ|pا'ّ4o# 1t$FHDAHns~Mƫcvs:_O?3dF@D 5'q'p4)&l4ϛ>oϛ>o|rrx=Mc@kѻϗgOP\]],>N1tz:&wù4vǑnV{:Ou=u ϑXјipA^iL| 1b{{zCa|0,b -,b X,,n{d1KexkIP, KI( }T4RP*JECh( T4}'OL>CW$z)ݬuQ,/(6p=ˇb`P CA}X 5,[XlabRYXFwf?Gn Ż.ĻAY-=d:&%-~,S?+>P{C Ŗ0,`3xw0`SlM=w,`6 ,`sl* endstream endobj 622 0 obj << /Length 1307 /Filter /FlateDecode >> stream xWKs6WHwJ7S}$bДeEL.] %ˎ]xZ͈߾APKQl->Jp8R쒎I i'1Pb_Fi_E} MP&cF&P@'N-IyaCG[J?lbDeHAT;Ad 3X0X0w(Hc|*L/`}%վ@Ԉ$(TB1RN>*"qWQziKLqE~ڼĜ™ gukBjS}6J3up+ne9Ujj*AGz2Qh9 o@i~T<i~D7_{(O/F3EH5-G5:h[GTָB7YI[( Q 1X) q˕V\1%IR 9ce>oAO7 =9%gI%x^Š=E: @)N=P!ثcGb &5̷?ckXm77om,98bAb8by;ev؊ qV@u~ZizqPŧZ(s|lfX ߟyʆ&^b;m5&2wVZ_DEdGbn7xDᄋ 6 !zQ4K]hv>^(:#CGΊ"քEPIn.}L;57%{\ ʈSj dr"B#qЧ3U g, صT"*es%JrHs8݆/.?ω{ZK QML6q.oHnNЧնk]jݒFX05#Euw=}HuuH~Mn6a5lRX>Ϲfk K#g 0U{"Gmuqs U? ;TU-p}'8 p[Bd.3TXD])?oo"Q)Ftv6|,K'Ҍ8fEn\~5Jukzr9nso5LF[(ZQS0)4umr;sidVxF}'> stream xP( endstream endobj 648 0 obj << /Length 1361 /Filter /FlateDecode >> stream xWKo7W( %@A[7g-?K% DJ"@pBwW)ⵝ ^N_kXeR6IxW JZ+tm|C b#0uV|$k xڄFBjh-2DX >SLsmElSKfBbDQyGW ")LL}hv2w(ZXNLWFMH2B5] Ji+IEI""? m@bLJ fB83uFt"=|VPHRSIH(GmA0IK><~Bi)_| gwH I FdIuN].s"i|9B3N}h)M%!}Rf ^Km|L:ҾV$J63AҊS;ƈ(I!n3ߧ̷1ZثkA +!y_T_:+|zP .9C*X/4Oe^\x %:P&WU悾#>c&6PıUG:M[ian,ޤ7#AO A.4BY l\ `x6/G.|Z g* 2?5^f$ M/Mhky c`e+ /u321whӟJڳl<3 oEu%F S$ C-mBZ \dLw3pzì5(EPB7p_I|տzqX+[SR -:^e1sRĤp\c--RP"bAvB\4^EϹ"n'ĽxE@41ĥ};% +@F.t72b*~WOߌwG"H7D:zh!nA} {=`/zT]q@uB9s/9J2VY1{4M"7 ctPָo861b|.U4C yj~oQf tuW~ bEW[*1bN<l{n -u Kaq/ 4H~X<鱦Wfx'1B(+9~ C L.5, Ø;;Lx)Q6sYװŘj1Oqά}} ?Mx׵?%x endstream endobj 673 0 obj << /Length 1343 /Filter /FlateDecode >> stream xWKOI+hIW;BHd6`Yl? e ŒzHq.#WUxm';&l_kXe\7IxW JZ+tm|C;F`$&H ԾZ(dđDRNId(k0 tM-GM EJ$][\5R\ͧEt}HlfXsw(JQl-=pCJ"5gOo3=c UjΌ_*脏<[~Z7}|LJ`[:u۫sw]?u}I2rѕfDgmq9ϩ']Mz˭Z_v:> stream xWKo9W8em!-]iܲBg@LqWe3I"v$r_vkuz'a*D5>TsƩ剚6Qx,G tncmmSn|R[Fצ : &V sNmeh shZǒW pesql0[@tBaF* _  ۘe}?h!Ś):潃Tcq\=IAj%բ[.a#X&'xaOA|9Lf_>/|~QE0IER+[ԉ=f6>uV83MqGt.VҪJC|t&`b{l7wXD?Fz;( QG`M W}5/+kveC9%\3?nRF9@7" Ca̅Юj٠~-^J:潨! ]&G8#fW'1}샾oF=9 jm\e{hU ,V&- E3Un]pe^JYuL SFfѺ0O9%"#]"tuە3V"İqIXbp<90)R0v"v?Z )FFh $'̯:XbQt]B'ݪ;I~+JJ1 ppkIuU,jX li84j7x":gldwYۅ^,­{!7ۊSN)RsFXIjw5z_DCF `fԁ!I]dM#m !^]~T. AXJqd3L̰"vݐW Qi`LUٞnFM68u.]b8@.;qm^QU\8&'峨I9?ԚY AώTq7{ O%2TJ" ^+-9]cێ~T16k;媒+m硦"epS`\b,PtXw[Б$ג+&w7wu.^.aO&Ϙkϥ{on{L\& endstream endobj 597 0 obj << /Type /ObjStm /N 100 /First 916 /Length 1732 /Filter /FlateDecode >> stream xZnF}WcPrg/ :-ЦATM&T!+m=C .[$gϜ]JEQ*3B>X" %3ž|@JB,~-B/𢑨q*l@,;tlb ^)*G)X0TX$U Ȕ B%WIrEW5lućF0a58G9l5>QS=eOdI0LH +r#HMq)/(\J@L:%fbdѹTd8*DeGy I1U.05YM EfőLhR֢+&_{A͐ `Euy jV0 C@Q!)IɅUu P87svU.8a; {tPu|ސl`QGBу_88thcؽ_Ⱥl i=dgƺC21OW5[>[5>AqrMo 1\^;=Sv{W4cl>+l9(-žFPo4[3c FkbmX[ǖ G]N~Y^\ư~f85$пV{^,/{MՐFiM׎_UOc)_8?c7>#T;4e_W gz-rUkeE$v[x-xzBl٣ϖ0XYv~q JW;\_+ Cd$=4LKw&ZLRhrH[&W.q=&ɼˉfj]x_"}0"+ix &ч-$)vȂ1)8L~_2?&..{f#ȉӘ_&91F4&iLn MHGp ϻc^&g"2#!t7Q$#x#5879wS ^z77T2q'I#DfQM&QEl[u0u{% Z$~}=zltz̛򦇼!o* ,hfllM_WLbckxEË /M*<?+>PPf2+Y eV(JBP(p0 % eV(BʬPfr+ɽ'` endstream endobj 724 0 obj << /Length 1431 /Filter /FlateDecode >> stream xW[o8~c*[lT!-EʼuytzA߱c'h[XvsfG!ū9Y/w-v\˝7?|mȊa1Eli;>OlJF+tc|;[V@,7ۆVDjj-Hx+v0SLs Bi$~لX@*cTYEэŪ9䚸;1f1cn%hR9`&Fn dx2C(ݨ "~%  Jf1mz91[P)YɀyeжPvX'lHgԯ-߻/ZdYAO 2mfn7DiWQ8A$].0qFi\dp e8n;qwFۂ7,!YIW0x-  8ud+VdL13pE[Dd)6[,9]qځ7)ee >AneĒ3\)6SAYAe{ w68 \iL:Et 'WjU#>cf8dovs ̭K?3 Q$f(o+P֢`x?0xůG֪Z~ڭU[1f30pX>;>G4y[#<$)(gdΛElų.Y{'HoQA9}i}Cn/,uB$#;hxUCM6ZGJmMݘLR[T<&ΒmI d/MQ7`-Rٝ"}Mcjy5=\Y ́{4 s"7}kss;I@5?Қ^AV+.E߅ik=> <8ֆ 1>TVyv&]c~9Ec[GQQ2zF,qB(\pFriT)߸uж(C5i4k\j$Fi&ݴ)Q4,15hMeSUR6^W&pWI}/ endstream endobj 749 0 obj << /Length 1520 /Filter /FlateDecode >> stream xnG_я ]}7$`fGYc-^TU3$vz{8Rݒ*Ezvֳ7=x}O_["?Xlvlgm|ou5S.H_V(#%HB!Ht`!rJ"F(۴Q*aT]DѭU#Hkyw11ca\2u(ZTN>^Sm@SP[WPS(TJ$vPh% J\c6OS8h{{Pd;#Z's6j up+dEr 5U|/BGz$dK!p fᖼ qg-<(h`O7:x0r"stQH"$#(Cqs)gph[1R$(*ڠ*H>S,"n҉*gpo#N FI )wtԜd1\;r|YEfwjpӍB 7:  ^OeU"|p <:t)Ouhf矷g<)>ΉaE?{&Pv@X[gMge_ ]`zN&M*`6 Z^gsz_T7r0CQ4O#E`1RYǯ]?fo6h$M"cFHf Lsdmh+H>ko7K5#P, @SJ$fË*͙ĿNϕMFsSmq1sVc̄B:IEb\%p9O*ϹVGUyFU/W6(Dc '/דp}T2/*bcgL\ 2km󂵄e>[`4;sĂtjC qFh![pC^2gilj]qHN PƸi=M"3y_@8ㆢbrRK6xԡEe65Nd@Ȟۤ~20)3}Z)SvԾG .yghAKT\B(S~81w(2?NSvy|܄WsRƏģsI|͟yA :`&Ȟ,Fܝύ\4OfJgCM, qJZfۄN!,~Q&,[҄i3A Fe`˜%cURpr#,ӱx,s{Y/(N9X,Jq ύ7ۯj?~7_Iʷ~L2! endstream endobj 775 0 obj << /Length 1460 /Filter /FlateDecode >> stream xNHWqwG(&Y71croU$iܮz-ř݆ٴ/v[jO_k{Xe͙lgmCҺ ])bc^L FςB\w}P^k$:0bq9%_IvNVmj?lbA(0"s*ռA` 3ѐ1u\0u(ZTNLWG}Y˩@:QFRڂѵWPS(TJ$vP;iKmF"= m@pf%='fvFNv(ΨޭйT-{:ד%!P 63_(OǃUA{|aˆ‰IptE"gƋ :hq #HmJᬤ)<"ud)VdL13XsEN>FdkR 9{|S0c,=^rxgYY¸ϛrAP%y?FA\rTcX/xlp޻h{L:Ex !O$ЫBCGB &5ߧՃ{歴0{/?sS,H,qXV6D6avGzYifW6+g9>aIޏ޿5~ 6YY,yW4ؿ(c"&vlKZI0-:'$rA?CQAH,Z*iZ ՈFD*2{`Ȭ5jH罡p8݀>Nk6%嬨{\(E )96fe_J&HL]Smq1sVc. w{KBKL$m[|xKv|IQE *_X>u} X<Տџ-2fL7 rrla ҩ5%( o ymw-.f#VcŎCr2Mn;9BXuUB<7ewדZ*QX-oxXLΓ7|ty LJ b30ٕ+9T& 87Ӭ΋nÇQ#f{xɧ [a> stream xWKo8W(){Y`Ѥ@oMCۃNnmP6 -6$y~3CRJ/'d4v39h#^&Qj/7^t9&UZx5J)NȍF/t! >ɘ ς4uT!6`X+ BKq%&I*81:B$&bwX bD1echAY ]˴(z LCc&ֹ~ZFDKBthMڌ7MndR2 -n(& )I8:45f12Rf+ta UJJvXćZhkPyUZI|-ST(p6|a1Fo]+]ӱUI#k"h: DWږy Dr ]XH[(Z.pEGS^()z+wKt:H=7-D(>}:jx.pm.?^_~PvTtL:MuO )0+C {d"EeQ.= $d0=M޻Cܾ3s?A(H+'k'Mue9վa9Yk+3}7g'q] ]L 03b*fkϚ ]KBW}y v򐹿oLf{} XTvHp̼ޏNfikב,Ui?eI\ -#Y@Y'f"ZQU[]] :fG"t^t3Kf4y?;+P6?Ng&VAsn׍7kw5&$؇(3]}2SE2blh|vqA?w <&фzZm;튠y£G6G/fW#݂}˪'t~\ n.aEm\@bf&jMZ̯;Վd?ВZ[+m endstream endobj 778 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 803 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 701 0 obj << /Type /ObjStm /N 100 /First 912 /Length 1690 /Filter /FlateDecode >> stream xKo6)*q0Q6 >ll5qh&M}#7:xa0LQg8r#K"GV M&)$>OyJQ%TD5ebW".{^rHw*qˎ8 f& =aqɳ:D>xxL>f A(U…J{GV{*6>B}A+8X(ĂPqr]]Mpi`%x1!( AG}.|Ȕ A(qTBɗ4E+QJ #S_*+Fʌ $j)D'GIX JNQ I!4GӸftI.f ӥ*HhkN L=x%*A`8Q"g*R14 U$⨆9Gu!=@C^'?;6_.>\ "{>nrR}iϺ7]9GGhu|íߺ[:to ËoG (r ] =h'Ʃ'FkZX;OOekMMMMMMMMϛ>J=xt3=_,;I_&u9mJS YW3EÃgG"k:H/kSfk˗ 4/RbwLM<1 IR$)4bd ߸W4CYZ$\q & _S$/ %_OC,׆Il7,\D"-G"ȉN$lN*r'EZ&n:.6qp SOs}s–HH R$ d4k6! ^wv^@Bmē$oxQGN.ko"5M֡2iru '1Njrk`L0' EL(H)x#`> stream xWKo6 ×Ƞ衏CE/m~^^7|*Z^n]@Kp#Js!ŏ+9oWQ?nWlɈoVd?ؓ*+vb:YҲi9{f<蕼ֽVyhL^ V0HII$bhc0)>bmKس !xU:^"{Qs&q鑏(b0,tEz]*àCHj[9W9 "Zb))Sw2n[F3ļ"Np':08P!̻Q.kK紊-Wj^Nro~%O0,ȴXe\h*SKxKmtyN4*ED|ӛM:03ȓṼŤ]3 Q$g(o+PCr1|0|sc!aݚ*0F]Tvm 𻙌)&O'FFt>< Ҡb,:n> stream xP( endstream endobj 856 0 obj << /Length 950 /Filter /FlateDecode >> stream xWɎ7 WshԮY@-!( =1'G$k q T'>Zԕ"ӎVݎђ{Np{qO_xJE/|.JXmjDN6&06'Vb 2FcĀ)Z @B 0쪟r l ?圓:U$cGk!TtvMiiXXQֆZN̠sOu "GSXmffKIKbs/@%mU-/1"6}?ڬc, hFt=ZiOR-TeT@< K͚W㽵QA{-H vaÉn tB&Q"`$n!c@lOG"g}JCh6%%G[m֟MlL zs5֛$kJ\$Z(-SYҎ{Nʹ<VCX_L_(̸})9.y9>3&On7AIt:zMVfɪkHxfS !'mkt_~h-ރush7(H8%ۓS{,`/x \]W ?K>s/ ٯ}m."qMǼNc:,䇕-e\hy-0uN21 )=y=n,KalkrR; n%ޫrOF?`]J*yNMuI!<,6 pTlMٛ >] GS(Fp`2FUCF<\YeLdG|לիw(}ObjuIT|c!M(k endstream endobj 881 0 obj << /Length 1186 /Filter /FlateDecode >> stream xWMo6ࡇ5P1)2h{(CE.,Ȯak )Z b H$3yoF$W%췙W3Vn׳Woֲf\~KQ]/Xt8eetx;F2%Jka׮!lBM:P{g#3Ǖcp]5SP:vf*:9!G]s\{[+ITn?A!9g0[ 90LJC̨ZXNL}_p1EdBuՂZg!%uaQ 2q+Bڢ: ! $HgZr_l1bCщ>$z9XZDRS {r:^I`>BAd-7'qo-<[0 iR[2ҩ %tAD!- 7RXƻl4>Jנ1 R$J\9ۈ)clqƎGr EK/Z%Ϗ%W 'hz'l{!v(lsjnC1ެDﯾ2[w1hЮdٮAH)FQ EEQ^F޷]b #~4op┃Vǫ©ӷz.'V(Xl 8 LnNk&B8Cl-bjꡋ_$&%[sǷ^^i-ns;wg17dUܓD < ^l8T'a5i_,)}?[0bM(<ѷֆwB_T<F=o<$ endstream endobj 906 0 obj << /Length 1566 /Filter /FlateDecode >> stream xXmo7 _!䓋dN*-+6 q-圸MۿIqzkhNE)Ι`#5^$ߦM^vҰW[_}dT%:gۤ]eX_¶-Kv+%ܸ dl` jJ6Ǖj+!AvL`@ˎwY% z px;ցT<.XѼQeƤ(r11 7=? %qgD%چp`Z+ .vYq: PuFHR"8]ƙVw W'@$tHO~fk,ywR8 Mt,{/zųBĠN1ЇЂp8}XIg-ymUV.^ar赑5bF. @z{xG 퓀i=3IX c!N?x9 q`XQA˃d Քj _cQplޢ؂0=7-zegRi}W1r8."tiycx(m 3(\`87,#UTy< <%5 AQ[8T%Pvr6zvMt]h*p2_)Ns&&ΚpYGG@FU:]T4SźEF L~W^b\}C# {=6xCZznM_J4nW)Ն:p؝W3/7s r8pĬ9˘5v1g>yuŠr5}P2&Gk018(rD6w8/O}FYK(tƺ\ӽbJqI``\RDZ*OE1bN1dT*rtg$zsn ' qCu%oc% [RעϢKTL/ $CW;@= 쭊{{9ua3[= B]f{-AkMpϮBwkFj(7cTYs=L;9 endstream endobj 932 0 obj << /Length 1449 /Filter /FlateDecode >> stream xN[G_F]塥$*}"Q6il0}g Ŵ! ֻ;;3;Ș0VN{Swg5Zhr5&MT:k BJ*&*۠.Io>YMY*cN0,m$8:rBzGHe2;Y ~xrY2yLf s [aB r汳E9҄p45gm2dC-jj!b.-Crw f G`tI}c?[Ùk;t ȖNc֢j%S棥T=1t/$N@^smaf;r񯱰ўonF{Zc!2%øFq@Bpn!@Aey߂=,SRgHz$i.i3S+6:;ҾR$H3XS%̧wGJ4edg 3yOP&te;-lP+8p *yY!.~Ifip>FH- ת?hqFx0ZtjN3EB1mC@k>e Pѯn/8~WHx+°#V\42_V#w.֑SH}K>xKiY ~Dq=F, s8Ww83%yɸ"/SҀ %]Q3/ ,5GVzMuec5z%>/iu_$+DU^y?-:nDv vyK_{rQ_ nM8X6 WAn95ފNq^[љ5: `i׏+ovbE0TQj7Ur>`/ w\o endstream endobj 831 0 obj << /Type /ObjStm /N 100 /First 918 /Length 1775 /Filter /FlateDecode >> stream x[rF}W!\TMY~ȮJ8Jl2EYi)rtessLD@"E-$QI PmVi&@1L.H1Z8K9gI B\#.J܊ӈEmP +E61PL& \"ņ%fRBbf+`!S6&tVl(ƔB3 cZ0DEhJjsQ')匘HK̔HCr9SaJ,6"~f"#%B`@5++%PQJa)*+D5 rP0c@-V oU#RZsR#`&jUPZ54j[d/Z L-UL4`5x N& *ģSI+5[v".N1I[jStl \팠+TRHȟJ)dC@CZqԢU(z  LfB:#PEQQ`f.Z"iPYj>7é!OKݼ\^-X|a6۫!t1æWfMhN@GَQÇyB_FN勛 ͐lC"v,!KpշoCx_']U%b]B-NQ1.U=]Axl/O?_?_ñ}f~/]Rvq޲ NN HfSrR%SrY5)AʞI ] Ƥnr]amOa&5'&۷s!$xRKv@.< LGDaϤu!N:|b3QĞS|X&sϙNe$NLj~4nrP)0,-ęL8'VQ$rK^j$qZq|X"mnvu❤X!S]n++n7΄UGqTv۷L?sQ=B֯^߆2W#jQn[Ѩ)и &ad#1R|b%nﭳg׻WKR?`% \$>ɥTr)\J%R٥Tv)]JeReˎ/;^qxJzWݫ(YS8Q""JhD(9t̢d%(E,JfQrϢIQE%AuqP]TFuQ]lTFuQ9^sx5kE:ш=QrE],JfQ2Y̢d%*Q"a(aPQ_J%:(@\w^Zu.6ņPSSSK+cFo藒Xx,Yш>QgQ2Y̢d%(3f3ALv@Q¶K>ʈ@I]3fwͨQ5kF}׌]3fwͨQ5kF}׌]3q;ё>_/> stream xWKo7W(D8%-(ZvK;Czk;p@\g|3|`k&ۉ'Z&'=_r@ҿf͆1+p4 !d "WZs-|f16:n\I!zPk(IAM>U0%c@Zm8tn`0DvHGs j'C#CR:686V%zG#R"<]I]h@OD@7v˾)uY#q 7(DL)MRE8/:8꽃^LX# }F $z9ְB9bDZW;9=C vZXIĽܢ?ߙ3tL" # 2Ȝ N)8t7HF" y>MA #84$&J.9pUi\NmҚ7),Ilj=l'_aڛr]P%4V_z?(A*:SJ2+}tdEDx5&5$QJS| ":h@B&='/_Ugk4{ t J\)k-Vͷv&7 ٷzg.=YqBr=O?M9XWCW¶/8ZNn{ C'p^1⮖Ev )ڻOwP }ف nr59[P\;%ImՁk(` /0:ȡ뙊Ibvw_R 0j |ͥ\h.RA9dp:d7U_s,ަMD%vXY #ۮ5p?IFl{hV#G6s]*ba9\Wr.ShIm9 6{`ֽn$zL{?>8uvok*S MDT89`-b\m{zO%{/#z_#h"K5%Ce ^b31 endstream endobj 936 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 961 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 987 0 obj << /Length 1080 /Filter /FlateDecode >> stream xWIs6W(c'pN3$RNi Mi#~ E5i2L޾`+&/1&`iד˫v\ZVY[!0TBHpfϕ\47ܱ ޲=W.H*@f DR-qyCT2#xX نgkH%*gi4507L:w;>#F3Q1xn"}ZTTPCD|(jRn܉DΈ[Ǹ GPSHs3OUhkHvF=vn֭,|M#btu}B{wz$Ii3s9R}VL'>3|bČ ZttgHG Ey\48]h[0%d8+ FrE.`ah֑X1,ĕ9{s 뺎d2ڂŞHes_ <5xYV0<T_z_}PNXtTJA*SNYAe{ w68 \vróom].@|L = 7"Ys }q. ~hjGhzw5l^^epdbU?M0?PVKC7KzIPu5:wL_T6˨̀x+a`%O}qAeyŰzxq 1ƕwԔ#N XwME֨Gj$}g$A)k"gK?f8-󦂨YZ-G!NOkK9^L7( endstream endobj 964 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 989 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1014 0 obj << /Length 1144 /Filter /FlateDecode >> stream xW[7~ϯc"5^_7ZEEU%v! lLR6i߱$LEHs|l{6gD/Xou{x\eÚnƤLZ'3rJka7d*QoFb+D NHi@+v&/H*ڇ&9BpYnBuJU-<;&-UNH4L~~]\k<8c@:UW(>)i( Fi*H\3ϭۖLȸ?bGHH%}},D?n3Z}XYyG"bԜʱgث C-4DZ".~C|ͅ&|6.h-ÈE i b$R5V)2o6_*YCg#mHhdр-PFŋL)nfҲw ğZoI /cA EX*2; "za-dYWp^my y^PEP΁r 6Ne+]LBpV^Cx+:E)@QaTK ӗM*/@Qsتӛ0;A~g"EB"%[!h2ܰ+t1 q |7hKmv@mӏIթ]kaja6ZM7}NO[,q魭-͔>pRAx5s+pǹ<0}ۭKL) "m#zJR^m1J_%ɝ."~H'k*x[sHvi2 ٹPƅ1g> stream xP( endstream endobj 1040 0 obj << /Length 1425 /Filter /FlateDecode >> stream xWKo7Wn M ClR܍$Jl#Z)NҺATDr8ofH%OO^ 냷;|@f%NI~b帅N9K\=lb$J4HuxqzUJgdcsvޒUs}Eݪ!{؀Z"x24)  U\H03_*pDr`[v]uHR Ev"@SHh!\gxH[2!3y 9™T7u\GxFA:~XkX.T-(lzY(>E{ں=[t}u7Mt;Wȧ zErWֺV`67=P.E4x8# jtsՑ ܈P;'g D\Q|Sϻ6}[5GvM4%J8K*3~HH+{MhX"Q7Tݡ[i6ÅۭwM6E{&.T$ cv׈F0b m@XSf^} P C i3n&so=h4ߨ)#CwNL;2!q؈qjQ7Z/X"8/ T2MũS6.[꠪3S7g}{2답 > stream xMo7sl%9 q\ b>(6qH,;\R/5^` []Q C$'mHQL#ZK&x,%96 mhZQ2Vh4ic,.zXtICQ^^(AJf+2NCgdRD BH N6©Ua&^! LV1ϒm-'k-F?ądƔl"ŅSdSBH,rFt*ΒTs众h1NR+}#\rd>jdcFdG J' FYC(JƒeS2qRH(*qC%&ąD1r :QS$JQ,BPEGG_+-*GQVÄKƵ JVd0Y}RR1[z)m6pj A5>$wD80e Y(D(kDa#QB$4ltt8%޴a#I voRv#Uu rXFejcˌ vz_0k$ kmAF}kl]l-aqx oO͇<|q G*ljF2Y-Ϗ;1P{ҽ])x20ź[-9fu]gɷ~..{˷g al|6j%_BKFY#5"ʓ8z ^Қrimi]i}i-z蹢犞+z蹢犞6i:~9\4VNU~ypr!g E~SHD}ڀxfq.[Xthd{lAG]e-.uGL@a ͦ9mZ߸z`3lӖR; x4df'2l"&2"3"w'24'Aw|_~*)@6~ BP)~ E/PB E/XbыE/ډxLw/  &k⯉&+n}LٻmKRT*JR|ENbjjp5l5\5|5B5b5Zp0믵\ =˃_Ùl~4pfgn4pFg~,p6t|9 =;w378#QtƂgGgNx6X, wxnw8mo@x(6}K9K|>ɿ%}7tx8*4UT2L%7STr3L%7STeS*sUU2We+ 7]FYX endstream endobj 1065 0 obj << /Length 1270 /Filter /FlateDecode >> stream xXKo9 Wt1H9P@=41a1q/)Lb{Mc("?&3>N`n9ya)zO9i9ǤL\E R)ak7l2F#QygwFbKַPrRL"t`N3IY)^G;Gh+\-Q+Qd/YQਐ``yX-r*T F;*pgD+eq`Z[ .ƀlCS Wc$ܔġ9nE[^&Bfh 9™6)gu\mkq惝}42҉|`-nޭ|IERT=)|/$M(^ki ba Nx(d:-)} I,=Y:%BE'V!䕬\P;"wo61a@ƲUǛVS6J#̭t?ҁ#lmfL`f_L+|lDg-*B[*RuAxu} mEM.cV }r*/``k,̀GP C.o*%Fj,;x$+й*BČ;~Bp)mAc^JA[sˆD_FEQ.XYu +V6%6OYUK>kd (%]JxGKDhQ^ ]HC[X}'_V}9CjYMyS!vȨ8dQ(> rs}!HrOSd+PNdOxT߿BЧqȟoWck7T"BjÃFqTSu߮ȮoU%@X9H~Ym7wNt`ҔjC1B[bOVew'E|_3!l&b_u\IuÃ14&ζ,=IVZfD^o6}O׾>Rܹ幻jG endstream endobj 1092 0 obj << /Length 1316 /Filter /FlateDecode >> stream xXIO\99\FLh\BQD7b+/,D k媯\r`'L31j/f`wmﬔ`g7xy˥e*.Oؘ;%et !hv+in'\?Q` #"bG/$ uZ3&)`fI)F9AZmi61V@%j<[c&O]ND4|/׉yTr]wk/rK AZ5!%u"A) 2 ܉m{U կO>Ú'H;Njws{QLX(<]IǭݬP̪+Tlz*ć(4"OVi&m~?9m~~3jթabM E"1WEHDG  48K#mԛJEd(-l(ml:xVQ)mbÔ%;m8ݼ/Gm"t KE8:_w~(,Qlj{KF1"]Tۿ: >(TV7[B 9S@"%;Fx[aذC?%[;w '|xn Ee:R~~dZWaM;__.)Ӓ狑+p cr\!j`rr3b@_|'+XQϏrXKQ'\QJ`N \졛r?,t=e3#}שrm#egkB 3|M֤ endstream endobj 1117 0 obj << /Length 1439 /Filter /FlateDecode >> stream xW[o7~ϯ>l 3>6 -} C%C:$TM ?9dzm@J^Hq.xv ',E.?\ءsN;>S>.?6iMt´6tkq^ wB}]줂H:cp`!^AMvVȶď4cKH%KQhL0`΄-V>Fh̘Xzjy0};e+kL @YIZRTz J Į2Z/9mzY%=(E)EIE}Y^:(ɜ![EErԚ*#߫" c)V 2mnɛ/4RS^5C.0[zw)T.'CqK-lB&4y)jiZSqv09k:hחK%J[N Ii:gW8]2oyKww|/g endstream endobj 1142 0 obj << /Length 1558 /Filter /FlateDecode >> stream xWYoF~ tS@eS*APuK^"A)Mma֔VpTuὅ:CAx֫%eפ XCXywpVSk? Pv׶;_1#A\dLx"1x5YZSa@ӫj-ht oи}_/{W *qHMшH?:0aaλ= &9 27ȃU)μ#g϶Q=0IIku7?+;qw'$ynKWgEŖ͹Vl8l}53 Rf#rbN-b31{Wײ 0 \et05'6V([n۝g_x0JKzɀGܛ)x6snP8[M3!KQj̈́p-)ZѾ֛n5|X(|AUj8\OYK]:HGAҲ1/C@*SFqRD[,NMX>1mnџXeH.BƻwSg&>x(9a "7O&8:Lux=1EI3)of@DO4&Ut͊,ىN-k7dP*z6=b!;4uMl6WmcPj۫ͪ_*o˸*|%Wk*KF(0U8@w 5lB4{d/!$Nw5 cIWl(  >|[1< yWۿ)f-"\B G|s]#/vE|?b, endstream endobj 1042 0 obj << /Type /ObjStm /N 100 /First 1008 /Length 1592 /Filter /FlateDecode >> stream xo7 Wq{؝DJ"ch-ȃE.wxߊgS_ROĀĀ" Ɍ9G32fd3jf:`R]b$B,9\MbˀQF0 &H0Ü*Iӏ PRlLRJWH M+  KIcTT)d֐9l3 9C*lʹ@`ʙ!da9HP%@W"6̶8IX(},V2K YBKNYP %Wedpdp6E]w00JSC\,u lD`IAch) h:O,A.< e' ,mD+54?] k 6f:ܪm Pu@fENuidW3 mɴtZ q ѴSsӗb7PlqYY5:cvYYs2[xl*ffio51Ѥ? b5O޽X&r<=!Og]s>.Vptj5ݥ>AGՓW/Ŝkwo?$SǺkl2)c[2{D:ۚܵ-eD~)Э7Cd"n3ђd ^>Go6xX^̀Ol9\_~~d5] 7&bjtgHۑyrs ?/V6Mk.'3-~t ?^ӗ:_k;goqx]ѧj` .ىQ亜\N~+l.UDx-ZZjh6hٍ!nԍ tÕ+gWή]9rvŕZ|?ŽBo{$Sz <^Q;]X p M `72) ܤ8I87#܌p|ops-ƾY_H{t*~J:5 ;P ; ; ; ;+++++++++KH:s! `HGC:u$tFIg$t4ox?{;PSCuj tHnd7솸ѕ+GWӀEFx0xK ԡ˾d^Fxe^/~_Oy xԀN ԀN <#<#<#4o^/{?^N endstream endobj 1167 0 obj << /Length 1076 /Filter /FlateDecode >> stream xWKo7W:,Ea }8@[ۃd^lrInd54 Hgy򱂭`g⠿I~ JOxxϥeUtqLʦ};A.:XE͎ -{HsXB'$ f LR%d$CIvV`.#&Ṭ߱EAY1x\rGf`b%kR9`:: qS=HFPB\NHIC8܉=dB+c`$άp_lֱa։1%ҙrZ[|jZjMe3'#A|Bӊ bq+JZ܂?H |E b$RN)8hq{ mJF/ɽF\m|:/VdJ13C> stream xWn7}WQ*K{IР@[KڇdVZRb5=C.ɕ5bvΜ^$ؚ |&NO3V6'6Jw7tҲeeWkv*:.]6:Ĭ:Z f7$D:ˮ\Fp:xpgl\P<ٽS!<?$hnjH.t<6;D 0{x;{ۤY9\ksW 2C/p'R O\&D3e&zL?[933z_H5 Q'SE×i_toCynh]f? #dI`jC56e0!P"8oz#:pWߥIwRimSQS9ȵuT#?͵thAj`4^T?8!O$p' ipKX._xDL C?Me!#_ϖধ6pFϋVCEH%oK-dh"e/JO'tU ͽw^6)J궼SD ɩ'67i9]bmsPz 8 endstream endobj 1169 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1194 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1221 0 obj << /Length 1435 /Filter /FlateDecode >> stream xWYG~_ъ0NV (y(ݍ6kOU5g#R,{꫻3#7_ 9TW;aX3Ұ'=2qb{4~K: S#pŎF(0Ug(;i wJ1 L3=C)+909hllqfBlHedGuf9*'Hy0Is բPT'B࣐c$PK"|g9-r/2!)f`I s gVRI_9ma/8gaL~Zɭ jT-t{Փ@|ˊfJgZ}?#6hm0['F(k-_tۀ̙"ăEfV[U=sLJF묤/yŵ(j c֑}"S SV d:5$g-bsP3 {A6[>ce>A7rPiT),-)=E:K!oC`B +9p#>cf0d8\ȱm ̫w D;!^;6/Dvk$zvͦGֳI{Qt_NOR,5(1.E 팂w /os*L7/evpo2 s,1@Q p H6J5klaz=(Hqin u ! ~_hAZTOc15 ԒE"BN%f&6?4 &f$G5$vw'59mm,H?4i+FX>q6?yH?QOzJr:wή:uZ0S ;P:wl0hH, ,^*Ts+> stream xP( endstream endobj 1247 0 obj << /Length 1523 /Filter /FlateDecode >> stream xWKoFW }o`h&hElK6rɏ̾Hь'j@ᒳSً>/G<| ɞ^84KZh9ec).ÿsmDC췐^3(g)`<DfF=Zo9H鬔L!aѫhmE٪#{XR"xh%R Lv{>p|hXQh4N_Lx+}@ơISBHN Ғ;k iLq!fh p gVғqmq[kp僝)%ҙtڻ[YxGh-=Y^OC)%𸙹y|N  |4m`N~=LQ81 <7gċ 8#:2[JB7,!Pq+(Ǭ#bE3{z$;Yn8uޖ ({ n> H%l,ze),w ,).<C):b0vo6`@!ƶ/_j7o-j9~栧H8᭹bBk,`'mLjΠZτ6ZJYja7i֫- ̎/>Wv(ݻFI, ~  S|l 4v 5-,J5z[]''$Sy ]#7%X CÅ~8mz=:és)%Mv0/2X:JGĎw.>=¢su]@nHH>Yx<A%ERJAߐ"# `CUՄ‚UP ·WhZ"nq NIYGdkF?0qJ{ ߓWI6mC<"G'q[u OB- pݭL_SrE| Wֺ&$$@Umr!wOx| >$/ NWÀTFTE D?_SݤC2 6Q'ĮbBr-&@̃(.Q:^G!a B|i2Eu@$^G#)-؊7pzDVb)Uʮ4rEE OݪG-Bop쐭@eoL&y1=\@vt3t&eGha! ^R*>rP/ʤkh`h Z2DEɉhfRHM%?N >y3S>/QdF^w4 tt'8}iS`(=:>{dL7/o%b\7¯QU*Q{t{jO޺c)܉XxN>G G  !'xھjxO7j݅ _}ܳ ^aI]?D7 endstream endobj 1144 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 1752 /Filter /FlateDecode >> stream x[MoFW̱=O0ǵ{h !b dM}gN\hX y3;Q:u,&6"H-!F h ;vF %3:0tfBg%X`c??uhR,8>gɲ瑬"$P$DȢs9_W2G:@9`0+ @̖Q,rGA!F >)EHԂ %l; 0@>*l !F.x;ܒTq3O1:Fi2AJ'FHʦBJ=GV#[HI*I)GFH%LCK1ș:C"d/e1r 4jY[2s@1;2)Ä,&E)PU:CW q0q3 RIl<3a"_s$/XT(a&>+=xXҟkN(&tKqW+W>8bA8^| 󌐺5\iLRq$\"j3ۛԧo~Ҷդ>~I}X^43C+?gUN \U\LU ͽ*jbk*-<=O>^.>֛aBHIя$SaB%bbeB Ua$xߏ adST&2ܨPMh[3)T0:jBSĪ70Xѓt VؓA:o cϩa`&b$FK%2T!B%q=pxpl9LO*+pz36X]lR 63ῸL$^}R?k.xq0;{>X<1xZ<]GaPbKh{, o>h//_by~vvgUlu?~Xf:I}hWG ~WyoWءQ寯;ދ|8?ih |vմ+ .zy\u}9Ks1,>UFQ9i0J[}Mb$dϮeH$* im$5emUéjx59(rPA"GE9vo*, 7o5-}i7A n!D"6>n#`6O4G K2qv/vgċF2Qe/xK Rܧ⥘/IUCRՐT5$U IHR=T$#IHR=9+rVY"gEΊ9b޾r}'V3ԇ_wySvzVLe]>@7#ǐUen*}}l 8cvyՀ|NB͎B3BPs;#56t_ =:[53B-BmjP$ʍok> stream xWo7 _9NIڇk/M !ۃ{vvƗGRw>ߚMNI?RNS&D O `YO^+^m&x}ҲgeWlH:VE d\47F?7Q $e7 E6sm%' x ).)kd@Nٶz<.6oqqs˸ͳצQ Q!p0<(y ϒ4n3xڨi@2Um?(ܴ[d ϺFDx D em]Qzjs?:ќg e`d]ɟٜ૴5ӛ-^zoZ&U MpÓ"Nzv,PT@tm0:$&7Y;&f/%ըE$By:TK,Gĸ%"Q9á'P"m*և/nm1;w4m2ψX#.c-Eksi۳HNt9JdI;❫{|E"u?^( \0x`o- kh"zs. \1ڑJ8|'h>#i=? endstream endobj 1250 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1275 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1302 0 obj << /Length 1528 /Filter /FlateDecode >> stream xn7 ˸L4 :p}PRXr-%hص@P$߾;f7yv.-j7aX3ҰƨL8tnTaѮE\|6;>1$s{8m}TUI@ CPf#px%kcsKpTc`V9e6tZ#&>an\vh!3m[9m9j!!p)#;XNa H~|<ܙ7:xFt=\4+1cpʖSĴg{8y n 5(\Ӟn{Nont=()Z.,^t[ !ĽEf V[qLJIH!qk9$#Ed5 S:vY7 iTQpř)]e14 {8w@yOaw sYE!ˋ J9" %{ˠON '$"n䦓y xJXo Xلy/t6=i*Zipsk`^&BBB 696\3i fvT.wE51ǿ.WpaIJjh'a}k 㦏~mjeM6hn&A6(I*xdѫ|gYWd; W;ߑSt{1nk,G%g?xoyçR&Rv* endstream endobj 1279 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 362.835 272.126] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 1304 0 R /Length 15 /Filter /FlateDecode >> stream xP( endstream endobj 1328 0 obj << /Length 1396 /Filter /FlateDecode >> stream xWIoFW̡ 96:p}piIvaɵ ~o6Ruj8o{9pH`,˃WkaX3Ұ՜ IGLdڀTV0Uk7lC4 ΰό\-7\rRLBHp$0elFc;u#{V"xŲ Fʌ [n'\b+82HDEo5dS;@ҜZeJBzr NiI]-eҋLȸB>`w G8loqzDS5 ҙ|`r)l|ACt=sF{w~%д#3k<(<|2?|aGEraz$Bj:+%V[U-p\+S(-yvZ 8<}y[Ȕf6J..c u덊djDX--+ 2 -t=V0\m R|QFPr\ "MȧL:g)9lKI4$QʦSl w!xJ*R`lly/&n[>n^Ҁ1x77| S4$Z\ mf,`&d.o;|/A&?MJ(piͥi|]t;QգWN( D`gFc 8퇀kj׀ѕ{o¬>̯3zaF <~Ws`LO`㵊6I*mOӋĚm>Y$kx^DTW H/-ӡe3Ζ=]LaoaP5&A=,^}9)W&Ul36\nj]u}ӂVm [*=?6r! Uh:a_D1?I/)A!BN&0mT5ŽqmۀN~DՓ\\BN>MP^Tb׋/`"yR Eo{9ˋE(r*> stream xWYoF~؇>m]r#@s8hiZr\r- كE_I$@P˝99vR)^x0JvaxvjgW eEڊƸlXlnmLa(Ju Kk]çn+IrOi%F jmF =uJ].Q[ 0,Զצ펤i>t a_{(7^dΖEkEY,(V{> =xwKke8a-JxjsG]X>4.cg#E}YjSnjiRX<<ħK(lL^W2ds FNEhzƐO.tG#0Æ?RډV\r`zN> L"0odBp9K j~g`І_%eUCe5':4dz&&OYKUx4>}@Ќ@Uiά#㬈Vqjt0i*T[(fŎ]^7x7F(m> !eXpj!pSUoe=F5hyAo&PuRCZL6zՌư 0q}eqnU3&LLʦʾrM4QI!'rnP(ۯQ=5jdVϰF)>Mwʔ7W)~DE :&.:V?vƐW TYN`&z$M>Jr .s[I1Rw#C$NGЈ+4)kr~v `LZmC.| yKm5A-v7S܌wݱzMCy)~N| ]!ٴv].w_b㚪;2!Su透9i7֏WO(ߟvU<^;V_]%)N endstream endobj 1249 0 obj << /Type /ObjStm /N 100 /First 1014 /Length 1754 /Filter /FlateDecode >> stream xZQo7 ~;I( 4͒=lY[7YSp#u۬6WHQ>>BI R *$R 8T 2U*r~$Qu>yՋC,r:#.rz=)U)TTYj?˽,6APH:)6 Jz2 .51`( ĆLuG :$8"Dr,." R|cT 3d1 TK“RRSY^D_+n@;J(E]6 "Ďd,3F:Hdc59!c( 9psL˞\.rq:C]%Focz*T {<椾\jHtmcHF gH3>{YLPDQ%1jޠP;/Ή(;DMGZq[vJej9 79MvkVy `i,:XC.3Tr%u!퓝=p79{#}T<1E)a-76ZD܃#p*Tx~$}ޘ^_^Pڧ쵟Mn>|8<^Lzc̦hQ(_~Z'}'Ub}?5.Z=}6w5qdړ7#lE7]\iY]x_ͮgU_{t{[$ea:i#OWK'&sAn \JD}d) фdM`R g!!!!!!!!!yד~p#ឈFЏUIRƳQ },}g3-ordq"5yհHPS˫uOnɗ,3kj! L+2²f8dC#V>lkɫ׷rh7*&$> stream xZKo7W졇up% M C 98kVaI4(ߙk%e+Up}p8g*Q!W;bywӝ//;o/]XwC滵~ ERrPuc[Y3_ FrV_ Zfkip8ۺVTUH omEM-insT<)"5>Rg:L_Y,g̝" RƧӷԮU辨P ڢIPME28@ HC6=W瘡$ fΨ$nyk[#v:NH nESْs*|z$\ޗB,AɸZh7\QnʊVKAs'D!3"H}S!`xZ' D(<-fJj:Ij5}>(dtmfcV0_"9)&$8cLo-BjŇ.3V}9VJr~[ɶ$oi91(z˦kij,B~ք+k2|$_xYV(jN&Isb.~+e?w<[+4[*Lc%)fiRMszJۗ{;v0^{dF7E_ dO`)oj/1~r[*Ig٬9 S3S snZu Ucji?N 0SȳLώ.i(J4lX/}3 gu5/dWzR"C.=ttAT |C풵\g3Z7%MZ7+tn|yQp#\'92­R`uk0ܣ~A~у8:-Ԥc:i11]iw09b}Dr)OOv|tFgDs Q !f6OʢI~9604+t aud=II "c0\ ~~W50p @Cjc ?5?D ھ?\[B[r_2x5)/FH%\67XDov(d}YL-!}Kap  <ulW1Fib_,OzJ9uiO'MҦ6VE1~8dc ~Lf)u+̽M[^ endstream endobj 1403 0 obj << /Length 1782 /Filter /FlateDecode >> stream xZs6_>8da@a:Cy]rm\2wq. MRBJ]l"B/h . f[^̤)/ޜY{t.Zb_~mk4JBՍmGb1\6[KֵRE ЀqzC ]Ȼ#ɍs3JE\jwIټ,S1.oz^Ηs^< RƧ;ԮUhŐ#ڢI WE2@ H(C_=W\>CH@;L٨k[#z:Nh$OGqk6"el9mL{g9nsa d-x7+cc.\iw7a|0[ݬ3%N\kCHR3Dِߌ5RiJaEtD9q% V<eqfdqƔ8H|y㯊\o$] \j3=w1E=:?#aλd_>! Ar C`в=i%R' G$himxw!*ٷ*!;c7rZ߶Ex+ՠ[?kZ )hESHbW/nC;/Gv,+ٖDYdm8?^=zѴ}I M债%Ꮕo<|ix>V6ՕՂT6w'^߅4fXis@L/ZL~hkIɮ$y6`rBYU^ Ie}z8 :p1<\xdz6)*0#[ xQTzyܿ-VI:LyM}YP~8oZ>lWZ*%}ΡK wL@B*=~zLV> ٘)xH E)$QY05AxR^2s5知_1=.]?EL3Z}5Eh-w9m-+uK-_wrSxƂ7~?cX]M ,w$At#tN&+4`zCQy F/@J@;YB2$`[{ސyosDU m)j؁4z^Ư#JH}dMxfbAKoAkphP[B5u3`͋P>94Pmt݃38 4":7ڔRkW2&m\Qs:I.M˗2lGUO'W1:+ 35@pFAÉJ6Tp?NW~<>3GB%uYHr?Q :J4`17_`c@v@pq?׎,%. Ddl{ 7C/.y2 aa~]%#FWp5W’^ڷ%XR T7%YcIu#XQe&Х2$%A$ }$ɾ$7W#It \-q$* q(M-aHx~:q?Ñᨼߙm-[^t{/g>a,F k& @z3hnb&NtS)}"ת:_t9:% fMybzʧÿbURtF֭pg] endstream endobj 1428 0 obj << /Length 1822 /Filter /FlateDecode >> stream xn7Cb8KF&i!(,)VJ~ b7\y*YܒK(&[^L϶ެSŇQUˠCLXs %B{SiѸ4pVm #P{gsBY/=(knw:e eMs"FHGォ& *UڣQ#+xLwgw2FClCVId* @@HC9a%-$@+g! AH}e[o[3|zNFkdM'QkE ydo)>dOH{: ci b:-y7dc/\KiafJoN*L䓸Z Io !YgBXF IJH! d X<ɘhyHfB"JWgFizN#U==RmM>>.N1AW^4m(+073%11ԯw/EEvUB5#yi$͙-fpz ҫd_J^tBpJkE+B*k7)9uԃ F$0އ~7%UEj=z85M59b5PZhSst~4[lrw&oZlsCDG Q^{h|@)G4zLA^\@+ш;~ǑL t1!Žpp@%B:;)n93M܄7m^IyL!h#xN53& E/. :FSip5*BAZURVa%?Ʉh ɔDeyr9\v1K2 ̄-k9Ӏ #>xbT% :HeƫZUE&{-[hk)p+]CN4M%94HH|#4 Je%$ ̀4/!2$qhۤVUg2cSIl;^ȬM:8_as0:.看fЈwۑYtV,KY?'Mp|P >`0t \ш B==^2Ϙֺ` Y)N#Lx&D}Ob/F3L`,ہ%?*x[’[<\alchjcK:% 㮁p>pU52Qݾ@ɛ5F=tS\y5> [C޾5 =V}~ؤNP-v-B!u',t'mUdnF4~'\^9`9rʥI`|A8g/A=uKl ;^5 \[ݷ[cNsRKx¢B:{ ѧp]k;Qm{Kf^GX?Jq3>eP4ɂ}mӐi,7cu(8St+; t[6|lhNv&Q~k endstream endobj 1453 0 obj << /Length 1842 /Filter /FlateDecode >> stream xZo7_}ؔk"B*QQ%)ߙ݆"t؞/ό^"JV/6t-O7^oL8VI;cLsa %B{SiѺS2~{Z/|8yʁOBD\K"rX.tlOaɫ‰y1 :[(dUxJ ʳ`h XF6!an@._V\5-3H.^sR H qv0l+e &p[WoMf8yO3jo6ZzaQ]M>Ώ1g4ASˇn( KyYX&W;kYkkQ]XIſhq~tSI}V]D8*/ɯ.:81ص" !OKMm9A@CE>L}Y ȍ9p!OaM[5`Fv@ ƣ* {*{b֯nM k\ļh0 ƛVǛQcps(!K8j^q#1 4O>;+)hM`gYɠ6YsD;bP<m$s뮳3qDt ion%7- e.MZXSs4;I.&!3m6*,.YON6qOH,~_HxlMԉa:=i c߃]?RXvB -@SG,F\fs,` hV?:ns{AD{ [%:׀!]&zM \gE;l|c?^3 nd!]vDWQz~|%pPVC}IX%h2rYy(HwWKX3n+h^ʏAUpd.Gˑ|蚜Slq#{Ub-ã6kA/q"Es*?LbvB:m~\Kg p?pfbXp^0! I[-_]u9 uƨ3)+]y| ɇ":dUj K5es*eYŭ endstream endobj 1354 0 obj << /Type /ObjStm /N 100 /First 1012 /Length 1621 /Filter /FlateDecode >> stream xZKoF =THG4}HkdU7mKy cMɣ9~28! 5d5bD)2@2л\bt az,qC}$PP} ' zz/3ɽT!Yy'MA]&޲WC@u2Ĩ(9@H\r`DG.]MI&XȒPRH\<Č5hX*^  !dHBN^GI/^fIb%CY'i4 }: fjrap KXR5e}88q#򯋗E=ܻqo'5cB8ALL5N`LJt1I#3H옰D+y KNd 0ԉͥg\h@"a2 7jP$$7zxIJ0./9I{"ȓKSm0,sg_/nő+$izwI pOoV{<{uu1yeA/WwdoR{X׏D~| v~u9syЏ~nW5`rmvmCiJta ]NG__ \;;ZIChWpd?]\-zZo/__vo7g˾~Y_,tΊ| ǂtŧ ,חV;ˍ + uz/TUʵ_;Af öfr6lِ!C.\ rO;6kn~ck{rx9\N&;~I`"&N`$8 &Nhѐ!GC 9r4hiBd'~CJ&LF((0++ endstream endobj 1478 0 obj << /Length 1790 /Filter /FlateDecode >> stream xZISF+tA$"!N9sH & 0JU~|zfFl6&@Q_w"#B6x!1"<_?n]{c%MFb~TvNOñ%֕nL;y1D n)>tW6k@ӺP$t* ԁ8xGi|1V<i F Ȥ iS`fQYim;}2m8 E%*V=@ UM3DW* !%J5Q :.WVi$b? <$mLD:=ZkslȚNǣN,Jȧ-${Bړ0x M; ",ӂ= 3JWx曙oa/UUF:)= 0ObBZJt mN BH4Rդ7RyB^dHT4OD עR[C2&if.$P2Nw뢻od$S /Bot9{|!!.a-6a@P~iKTQ"q]&T2]Xo(5^jvİIat.92J;OSQB®{=vDKvIx=!h񁦢T/6h"vw9D4OL Kӥf Oû ÔP.B,j2%O>N^耹r+3:<%:lu1Fؿ`sVslxɄ`~޾[$x;ȴPuV[[Xۙ ?-ƬyE}rD;nH")$KfהYT1Gޖ?dap'mz 0(@I¥lowpnU'`9e F|a3:}jS~91.KA]Emш\|\ 1)`r"PБ9̘ ('sR4+G;3%Lǝogp=6Kq*Q Q&{{#hW>FQH|OBdE;Rd",E&989'Lb|B!Lҥa`vw?!'!_"1DtqPGH!aujW>]ajˈޮR G#*)uG5}Ŗw.`h'&%ę€wGj '~at?L,A Y\l`L vyܿgՕ Dh8:K*HD.+s%a"eA16(mUqV]o>#/u_.WincڛG6+,o}+>.)nw3lWrB4<Ӹb6?=Iyh:O t$BJ}L_.CY8͉czp8;spFobk^A}1/q endstream endobj 1504 0 obj << /Length 1665 /Filter /FlateDecode >> stream xXo7 _!fY_wvK"E֡pΎc,?si-V`*("#%:͘`7H c d;n˂šP>M4:h VZs q#uZYb j vPqUzaz+$j0IL CR `go-tt.l-A+RT,h^rdi(!·rE9k]t`[ .iSP-3Es?j#(.Rl{)O1[HC8!5Ӣ{V`hH'-Jʗ-Ω{R>'i\DL҂6OC0?*_̅Ma~O FzubD޲ć΋#s"ih/ T 4)u^W'.2%u*ICZCLiadOGi]e+%TrbYO D A*p R0Qbq|)Q {@֋+t% u^Ae^cG r%-%+-a़vIZ):o!jzdq ` V؋($H?P!ker 5z:cJ>: #SOy1E2(D&aPVl>}H P/GjK-JEOL9xE/cvvnavr o)c`RnZtϵ5IhI2!M.kZݛ<%4V% ː> stream xڍt4[۶%Dhc F޻(A z BQ z N||Z}}6> Fa `q@ASSU`A66$ 񗙄AQ+@ l0,.NܝA0X@8@)]ݐvX\' 9#ܐp Єaθp#Xb]<==a~4/z a hH> sC8@ap(kj.ԟ`?_w@!)WBHdvv(;5^X^s q0 f }r, p!]~ D_epQ@;;#PX ɯ)"pܵ{ # kcDa"`B#T H!,zWHT@/.N/3 Ł@#m?_ `  XaDSgFq܃_qA =_yc}5%?㓗G{|  @ 0pw\[u`ȿ* x ο4GfP0+wRvwr?0g_8.cqDԁ?ZD ݝ۫!q"cGb^$nI B1_O. /NvpGܳM i{}%mKP&nm^ X\ آH~YD WqoN:-| 'C%^5U{-$N?2Thqۮ4d9Xi֔zdD¡IK({v|wNU; cF|XOg/qka!o&kg#xa"ɓf], j1o zط֝9 񡋱fӴ2X%I{V}hcl VYPdP&4'=)ȠVRc֣%TO~Mkv"2vzhDAK>?k=:(X*3ik#9v<{pp{Z@=gyn`@~Czܔ~.b*vV&^.nhJ鞊hz[1y2^'wWu\isӏCF2\5a"88ǘgIToVtb@L7`He0Z/Y4 !撔aA=P?GKk?]} f'4ݫgģqՁл7MMV/(0rbZK88&,B0ʪDE6Ns]|s343.748?79;[=1|D[YB6&ˊ%\r|=d1ԫ4eI+tؾkŠۢ}4S*|DB*0Z+Vj}k"$cмZY gFheN N]%m&XrS8C>4 oOu3kNeAxG4{Ӷ51/XKPf]$-Um5B䳌'EȔl~A?_?-cMRXϧfW-klw:t(@ݺX:wi8#9* }I|AXP=Ymh́}~|ef8˷=!(.tx+?pm$hMwr'Y;X.KZarzR!v*/M|Ufu0`Iz-u'X .ϻm/kMtBWu6b?aFXۘS()g\cWiLv&m4x@ѷECfl<5{!ԭze<,{pqC|f(%73* PfePKd.CxԔVI˼WuoG FϺ:67~&szC* 雨<Y]QPl=vuij҉w)+]>Su;@<^pnNmt)y=sB0a/ s*/ɵoF? QM->BY8"*)[?54x~p7w~ ٢5e2oTpZJ'$5{vcލe]zw%g;&0!UƋG{Cw,c6&癆$ͤNK9\7Q_%b#| }]n|,-A.[k7+I~J4A" &U>%iqU3!K{zW@"_nSlwZ-{XWҶ3ǿhV֒cɏה$+sVL'TG%[P{.JQ{J8Sx+љGsq݋6O v#麫5kY螇Wy0D;6x97ƆGeV#UFө,r:xnc&˃Pq=w>Е\{u\8lC}Ҩf+ʳmaLh~7{W6Rw&QtĻ1w'9Bm~76OEc%耳iwH:>S6^8?qI+KckZph+1.(V<+ׁ'LwǕOFhlx#mdJ|鄪;ޢ,&1_R5uGH"/:hdf$~9Gبh^ϳK7󛨙M-WGBbWRAOV~UL ^;A=]aϤ9.t7EqX: ~WM!x'"&%7{ {gEJƙ w޼ddذ0 8bG@(EA;[kVЇZNU@fF}QʎEdi>fT>pÝ$P$bޕ>m>}x ^)X̩=PdCX [Uc$h>[^HZB3Wse;|5ߊl{ٵNTeצeOw ұ+] Ri0ݳOuSOd=?ư0E 8 '?8Q +~u<¸@Om2G>Gf;ִh-0Tpme_[T?@/ k$mFs oD5Em{xqa 0V Og0O,V_Ej66uL%c}C&(oBzs瘍C7.xYn,sKTdj¹CnJ/U=/NUSKDE,rzH,fhp/GBv4a5k^mkxVOVM?/{rǍAQdS`0N&x^%?jxEVz{cԜ\Ϋtl݁^ujGb^2zٗClU3++9/Rm/R1X[=@ )v>뾍phs'W g TLƻ7)U \oj{pb\04+8ErbOPh^Z>W=Ά2-ƴ]Yp5ůꦣS~,>xA/R* qKp~vqc/Kjs9 )#ϲ5\HlPP nά{dž"<S@:y'~~mc2Yzs=/b S\)\B.e}/b=IngY3SA&!XAI !vd%+i&vQ9fqHM|sz(v``Ę@l<ޗxr{D9HͮP*'gׯ4+SU]xݞ'ۘ#m]!Q8M}F$,Pg&zAG{Gh.tװtGtht-/k.l9TxmL*-rc&tLc6Q}ٷxli33َxKqAaJ5o+PQMضg  CK,ƓozO-[8 cSdIQ!2{-3ો5-cncK6xLq,/6]cd K)v+>H׈%y0 Ȋ9]x(ֻTAڗ 5a&scH”(D&啑FxRof_?M7 R;:0֤Nـ#Q W*KĜ&rݳv'/|a}P*{LWZ(f7uj&QIpEgKvll=(۬fԛNNGHlZD(,ŝk~Jvx6Y !牊̸+æX+cqglӗvHY|ה"|A] *HZD>CJWX*IL 78K\)R;x,r=ު!&ie@7;YS Ĭ$ݥ-' , QעL(Pɵ8=Bk֑B GZFv[}zdh<P y+M BZgj'7Ʊeg(򪢊}ᗓ#uL?eV 26g͌R!г^΀!TGI:J:Ǽt?B׾YA[꫍YF~7E?xi>W6eG29|-2ڣɔOz̪{;KvMbeQ);%+5Ѳ2)uh*cN3K9EUa մ'{{I9C^iO=&bsN*ʸ,䃦Y?Ӈ [BܦcEE'\;Ҿ_3!: o{FMp`q W3fy3Wx;d{=>[1ck#M \%U/|(u$7;UB5i^RnUdѽ8FmIIt]:>S<7_X I^tfI*>@{̲^8}ԗqxso!uBGb9Ͻ"v([fFfv/dաWX5hd i.j6ʼns}^|3ٙu~ ʨھk b4 57cy`ָJ ߎ|+u:ޡ^l!s!afe5\䳽h6/1W:^P=-ML33Ȋ@GD 7*~8EaC*-?Ѯb⭿X@nپ> stream xڌuTZ.LwH7 =CI3twHwwJHIt# %!yq/ dԸxy|5v6g0D0`WkxR?]Avٿ?]Aܐ T ?AxP pص M?A2 6 F#MKH=(XAT-߂ 7 o'o$j/Ę#'rC tqtt$  8 ٢?*l@µ.c·SݟL uu9CBD@HqD_)9xrtHG×OKlH^[zv쮐Yq+H\=3'HH<] ?Z LX QT^ OXlGo!Y] xKR:?r#.W@HYb紲trQV\##z%IYto_=)xPw`>&)Hϗј` D"VP 'F!EDMac890X9e!$v ^0ٽᑛ: ymi= COu M!>LTJFw8KCR Q( +j~~^e>O,qE,cw+*)A4*d&oM]Ŧ"вmCO~&W+0b}އ+T{'UH-7m{)qJt꘼/ǗlfJl6@ Qҫ=:»ê [([00L)o/ pvYү. Yy] |jVdN6;m &6 'zH#Ftfhr^TO(mgPmx^:hF+oT:fsptƸ&7S$իX +n'lgߡ`ϋ1p}P6d~i ge*l'кFƘ P$a"痔47ʄ\o:i bq꼔w;q8\ux_y?(pMcIt~aP 1BחÃrOI^;sSŊg{CeC*B>b}|Cp΃*F?B^f9zn}qRC7NIbrFU6 -Cy:Mw jwx^=RCa;Xf%(L,t0{W,dbB :!V׫( $m~jҫ-.-m:R dpy#=58WKKEŷhٿD=?hw8~V!oEre/6ujxr k usKGB Y$yhj ! qjɭf-tKGX?m-D\?8Τ& 5ǵibSb=%^91m`W4$5LQ%mzGR*7-iu}E1ᮌ0U8QT! rR0C"gs;Z5&|ټҺ1҇(;tibOx&8òzl^:Ɵk5J.7J4l)WvxN[N25oդ:r=ϒ< < Ja!lMNIg4q]:eK7=蔱5w~3/?JGq,y]@zE-s`n׫ӢJwj'}ˋ1*cji?ʾd>uhLq-1eϜ̿)qk*|!BC^\MǞDGpⓧ,eUπ"/k1SU2*ELS ;RK{af!.:k:ODC.ܑP9D8/Eơlg%3BW6b:?:# 2іi\bկ*ڐl)c0*{=1=P EF0.lqmRo/zY}0b`//?Z*mSAFW.˲l('ZK3REъ+Jnc' (Ѧؕo B&KRmc[`⎩ rͪT@,pS ,TDG)5oظ[aI61%α,6Dž-;況Wƿu+PMޟ>A4rOJTuJ^_bd/ZO]XGjY}Ik^IT^J6 w ʄ0 vSL".p؛\r˟0t+T~ak 01|wdC݄'WXOz>p4Ú޽9EgvndGUmYF\گui$,%DyJUZlj-0ځ|fduc,(vBZ gLҝeMkU0jfx- ?7?>w2La)U,p^Tּ6['6m~/hNbh|:_]4,*NawC"1.&L{FQ?S΍(S:PJ0YW*PsesP ܏5=AP xwV9p|mQiyz0Fo>n^=::eQPLHs_aPE)3KFd>*GMe oaLPBVAs-fp5 ^`:_nq0#Б_9+>ٓ9-ݎ B];s$SgRKƽh>@u5oӫ|פ${Q{<>ߚ~"Bc$.մeQDcpcש{j9y%__%;jW:yu.jW> ]+;4/w֗0,;MvW6IJ\+8 8;<{Wq5M u4"$U:;sxdhڞf)lqh3:&ķdFD~,{}K /ײ8mp=T{f>"C2$k :|Y¯e3QyY5׻Sw9A[(}ߺzR\7g$&[a7!l eA^*l!= p2xiv6[:,@ w{{ؓ)t.G ܹ|q?ۡSACQ)[vxȃ\|iS*K0ֿ~ղp/w*yP)jl'!=i"ӗb^s":/E /SGґ8^ggOzC g[-V=1`k!,VyuٺpSp1g@Ζ"`~c%PܽgRqyp-{`ᐈ WނJA5mZMq%+(&-K^ַu7WOY)Wż:Vs૎L&mxz6AuVz1N8}\otnpI6EUsȎbbAMy)GIrPFM2j3֚V˚E~b5"*KiYe>!#O#AĒp7 )[v3MeR0V L5DF|yPتvx^>3o(uDE ]aNI*6L*\ 9^*y+6KnAi/s Xb?7bpy]v 'Gjx8s6_bQWbAiddKB =*&^ vX>t񶟩u+-Sv֜n vn_;n=!ɼHXHAZCjPR3E8apEF=P_6lxN ׿^=4r;/W7)Cu$C/MPdQʦ2;HQ*|Dx UǶ p2A[Bӱ󺇊 E֌/`7mb\Ӕt * ҨA,N4{|BaΌ LhA8UϷYЅLRSU եf_"|p=)Wt'ګȝ )njq`J},9,a/Z>. ܼSg6J;=69xU.HCG,L:.jչ[sU;k*=/ћ,N"m0ċh6 ~|-r~O hԗs+ b8-s*?'C'GQ&'Y_P2 殜rU{ˀy;]NyŒ~a!DVFqhNʯp|}L ,?5ԝV|DVbWIl&9rL=# ^*) H'* oq67Aȣ_1'm MքP> ^ "HB~[\GCH9gnL$jy_t"eAZnjVwQKݑ;5RO?>N>lM9M[rI G+si:Ғgl;1`bmQCX%\qW9݊wH1agg3tLJ&p5GxaCԠL@jUÒ834kCL Y۰5=s y(kJG]-:sSF_l9\DK#b|rZ:=FN&3#Y];Ih~κ[+޹/b3iӔR2 ˉ>}Lz4V4G)ï^5ߖb !6+Ҵ0B>hs7zk2V H!“B*L-OD?}՗7/f{0sA z\t@j!SYj3F|59ӱs_֯bH6W52Ho6rxF5&|}6wa?:+~"^ ܠgcO sF)NGE3TէF*ʏl)hv -iQ~IPIafcUz}릺߫ wT 7G2^~۱/I>+խvxuzC3$-Vq\&eU߹H0{;Qr"QG!(  )V=> uKRdjy=enP5@]܃ϸ*9LkgԴs*xU! #$[738\H?F:UutR# _^&K,%5d]ֲN%Q@;["C/umpނQ&Ox:mz_}E;k],.p /5A(zc]q*ge}N#3d?65 YV ?2omn%7pN)̒E>r ' =SpH ;Էͤp6 4l}F{"ִ9p{+gLٳx=.e#S &`j@kż8Df}%o:A3{bfCGd޳ѬЦ8+5&cl9.aڍ(ŝJU>BRnfBWڝ*4u *D`wl0wܔFs'eZ 0tu=#ʫ0*PˣrJfgLhӶɓۼU]MH!2TWgߚߠ]@CEJ8|D'yНsP`o 'b3o)aޕ9ِ\AXܤ‚T k.Z™;-R)\*qPt"5a `OnF' I!ը(VF2om$9AioGLoSibk<6=Ǐ5Kw2S8oV]EV vv@Y\5'[ha P>;ܫ|A-Ԩ#-!a=g1èUɍe=ѕq^lE}GY>_m`: }iHA/Dh)"۪Q*l #1]!)0L_)ǹ^iN(!X(<5~af5Si=׆``a9zBDڙgT /yRXMٽXxɴoNw^CyDߢ?ޕ}(#2qc^ pH9i K9\ fqY2Zm ՌSHSQ6ܡA^@ɍmt";5{Nep)B,7/g7K;p2 U_}HBKH)f?>/G 4, bЛl{-{sߏІO3 |tŒ~.dŻq=gfLewU)& N:7~YS #\Gi/\^'~bTH;^1]!_kmgݵK6a7p]Oz‚"d5'8P}d[_$eKW)Fu5f] .2mJ[f7~~ NK% ҏ_ OJ~+Ļ9Y)|x+vm&JLyEh!WQ{{ebe@7"V[ &oP~wYgrzgfz-]q[iN{CPMN DE/L?M͙ƿ/LВo c L.OR:sb뤛9m<,D|{eHWF6íS%kkǢ[ !uT%f<`KcѯTD/zGI8g(uL&f2BLU 04RjGBƙn탙۩N 8 $3V^4nvq"dp՜ }|z!6C9* Xn5pkK;ldyƟRF1'UR1C*O}b2y(V~>w57&(e5d=^.wٽׁT;$g4CzP*fIÑ>R:s_P% Dr>FG@CB|O[,OpHV:qK5r>xH7-dVCI Uq#FMWA ߖ"zU@]X-v46%eP sm&9{.lrFk{ZNroIVu[Xjn\\oCj!K/~Dϟu :>K Wk[X=yKa`V-._0htAaZxo1B,f[o w[? ꣟4L;eة ڵ~/2V'gVEQxg3Ll&M ']]g?eg,v!E19\z*/D܉ȑ>"oTRa"pCn6D:C`W=]9EC ]#ӇGAQר D(yZ3:ԪЦ3|d"~/}iKC% BLw#Lr߸-%OX,2q8F K1itMT"aWf0Ѭdx!W'6@kbRDy YK3âZˍH8ƻ%cDH[qlU;cAUk'ԇpR<[أo Fhg $g]HZ;69 W:TPsD=n8B7Gx2FcrS%) پp2H`D*fnwD^gBF8Dߌ”tP!;ATZ4?$ۘ,kơ?ԣk6V;sr=xLccE~)LdFCvaLKKo->Wy.#NB9dhT2xvdU$!x`jj,6AfY`^wINWJBJ_+e nyYw&6A1|_1:lϓqǕ#$|0Cv<38ѝTT1O 2ČH%;KTg]v~VzSWcŢ 5A_MS~ y~s0}dSX'Tx}vKœ'-M{*̼B ]`<ՒhbU'c`5uŏFbi#r8C~wSZ1E̸ pUt[nJmM2Vh*)WKT덛&FdpA2Xu:EwҺڝx}s7{1#Ob%o"B:g|O[A7*0M -鮜w-aɱ;3shuI]XOݕ?wRHm?1;5ko`a7 fEQ)Kh{9Ų7}c̐*ՑV&e;>*GFGِzbtnU0 5_z).Nn|Vwv`J(W8|L^2EUW&=0iYޏ5`ݏO$ bsJH10zVC73|1H|ݮR6]V *tz^/Ô44MȁKLۅpͱ<;u#rcp-O'76N8㱘7l:-㿹=Vȓ^-wi'E jJ=v6Ol.U:/-ĩ"~O&-86~l|I0=I;B/t)1Ϟ,ʐEFH￯Jai4^dҩ~`6z$La68 u8 }wE+i׷+pmj9 cq,S/A"|IvdXR͏!#TnTr]4oT?Zk' ]8k(R}\(Ib |%!lcN 7 5j177@f i\B:կ)^4| L>/'ԹߘYUtK~KuArFX+dE%x(caj=%Y鳅${4"IP5-"".#h":]=B| a!kN/7Im/{UKϡH_8Y.eZeJ$N-5e+r r0܀ޭJI^yĹfR"H_)9C=vMFDI{gAkc% òQ6ю4@Y L@Z1\'+jp⍪rOTLt(;9MZ+79Q3a%E7JE8: Gjk,_zKnpԳeu]d0! +_9v7*{_0Yp9͏yd o W#/Az]֯ t]{2hT]*=MN%fW9c+ׯ`{&#fVЅQ-`qFצfxk)3m*ϻV6?=A@>Cbgp$SP3׫O'~ޢ6S(K[O]n|ҴIOB|$$" jS+ڧqJ{.BG_Qj툛BRg=r&=r"*z$!|ʒmQٺ%󂣮lle,{X=:.%@o0%48 HZ@2["EҍE/1\Nߋ -jw&73rbt7-z"1 !Qr,^:"|95hx&d8bSx'g#B盥J(J(IwS$-bNſo!KꀠJ]HNAn( H2^G)NQ|nvW]23C"$&"偟P074PfM\6آda|D*EEZF0ܿʡ75%e7NҪ4&ˬ<?Jylԗ2x1>e`)Нj4r{+b3}ˁO^t%&ԍ$o?"huA=>$մ ӱ8Xж:n(r|ݗ$(hf/G,>03yT<:n />*isDWL8(ȆƄе[xZ,bp~$:GuU͓X ߷pG^CA۵;1̵k #*3WO7Pia=QIk=sDF̓ z< h1kK^)) iJ0m&xSD 7^:AՃܠ(רz ˦ sѷcWl`G0}/`/l)+ }϶R),HRZ*8Ÿ=*u#IE~5Gvk2wTⅷC\ 2_'u*E]Ji>FB')ȷ~[<̝|+Tg@{CSX.GI2? 3BeV?PNwTP&ݗ<B52X |ךr4PHC[okk5#t0Fz+F RyW5\%߷l˼* Ӭ_?mizn,۴5} p}&ٸ'f3@2 Ex)3\$j2}6wt:r;K^@tV(8 &2WӘNЪ~ :+ֶG#EwAX^KY@ };(U ~ڀTo &ս*|/W4.Mڙ3Mth:Kr^ VZ Vv l|KvC//(^hV ]vXE)S^Pm n+%|{ 2&m_|+3YqGfxr[g?6<Ó W\w]k id+#IwW8wT +`鉹xc$}w9mht*uSXg|Z0^/Q?aK?5hrn|g : \}(l3.ceJ<ݘW3/-}->kf2*nQߨ'ڳ/HmLFAm7=BI^*I)B&i!o@dk0 Lwp8s<(H_I}A;lQս;MZ vs@}$}ԧ k"tiՎQ蛴in0Y#֔R1?#ʲJR4Jc`\8uiJG!-TvV*#7kbZ ʌ8%}G o{ҍSw7Tݻ;750"$bՑ$$!|D̘U~+{7+6q8Ȏa_tCAQ{l/]f-T[O^=$ <δډYRpr~#%f%b_sFd9m7ߨb|iB糗DJS.>u"YkԕI(yH5.[L3 cYrRux |o_CˮUTd+j*%ViVHx]<{!.Hw$i' ^;~ݛUxmߣ`Zxn܃ˇ6-[;f(#uR3ʺ`Gst`g/ze*? g#:Bt"DwE3ʸf%9h!;>l徦!'橨aQx6hy(ps%* .{N> stream xڍTk6Lww CwwK4 5ݍ HJ"tJ#݈t7sޣk}ߚfkg =65(vsspdT\\\\Y wdrEÅST*B-B\\\B\+me+K_J_b(? JB-<0O#4nn5 ڂ~G6cF\pd0ko󿎘SVUIJO*?vn;?@XX / 06?jX)J6`韭aw50toeށ\FWoE6-@>X@] U0tAT>ANUX@WDFA@k )9@;`wЯ?:Y9@owiBwS9[- :a<?nZn'3u@lnhT)K7pFN 7S7pFPKS7pjF|Η4H7pZF V"~ m$||$NNuiBAP@h:ɡMq:aP@(U? J7.9 'wn-Zo5z;;m H"][ mWJpCY~;' 8sB8@A>+7(1_t]z7@+YhZ)r/Q$h~\ r”up|y?9͘qې4<\ߦ){ϋ.[ 5v\0=f$Yc}`7NvC PzCFIm?3ۀ|10Is3x3Jn'ieeem_:yዞH|R_eoadSxO{` MbXj\j{#7[Ó6S4ţ 噽-9ZZ?ᎈS2kYO_"q,$G"lTca}EBI^/XMaek I8Mfԩ4<4Guގ*îހ\L `!)^A BP?`wmLY+ bYo K?3UXd)ooyb,jm>E Z ]0Y@b`Ø]nӪ^h 껾5ad+H`jGZSg-x5AS?US|L(L-~ALcH-2{=Zuwޞnt4b˱T*39k P [i&sղ ʑ:zy.S/[(kNk {kVCެ|TOy.VDp^w=C4U~&y”ôU4F+}u8`)vpw C-E%wHx %$ϰl >KG[>WIw%=8meJx#}h ދpW+Oy6oYj|_u.%PDS#3ȋULlqMD4Mg2H\i'M*f] Y= vZFS|([%do'z}ȓ⣱)ٛmyWzkgΦ$A8vX:2b1G]'m5-$U݂˾ w*~s6/UT]wJD(io6^|&5F6_.ƥ%D[#/qVU~` D̏(tUEP O?UF\`.Ko||6$ZyݘRSRAy%$FDX'+S1$3j؇+I}ٶ%> M,źn\7Lw{RrZc#PD_qPڷ"ƙ .s]HЩH,22KIM:%4"H2r;jHVvȚc{(4݀%Yw>% `lއ Vz_b,`{VB)W틘GyCAT߰D̳Cv](W$. J];zd|`? f _.\\  p,2Yg-u҉qՁ+d%ejif鈵j7uwk%[ S0N ;(t|,%.p:Q =0nQsynSz5_xʙpR~/lX]<{-0iVp}zz2O͗sl=#(J|dP+wkԈ%nCҺX's7B#B~uGQMoIy-M^5&ʆre=#B`HDn$.@[F*K_x.>+֏y Cvþh _UޟӞ² sM6"ט# \r塟ߪaHHW3WenۈFhCU#@<&:#ͬy4;#Y`5bEz[i_%G+)}e+`:!fdVpDV/*,V(ڝaJh~2GMD1q׮PoZ޻s޳Z#|+M}  f(=W1Q4>iA*v{YYt -fU‘*Gu @(AuճH)'ab7o s7k^4k֮ĴYӾ]_3T9k+vM`,Qص!un!#|.> F1L6`{d,ގnV/,k>b6t@S0}CQXh›΄xίzjVbߔ$ʞiaɲ")}13. /[ k$5fYB-fL.k+5I: Cڊ%HeMi)2T2F~@ȘnPoG̸-"a/ {?Oڃ k 'ZH7d[vfo&9嚛cR 3?mpΤKŋgӻiD>84rt~\|A7M ["Qޞ<'x\ԕL{EH8k0\~Atu9/#d4 "%6IUHUj<41w <YO\s̿i|}3:(ƫ ğ@*0űxd ~cpG E!]Z9@V]p+8|AjX@Ҵ|K ǎx1e!wJt '!S4 #A1FX 29/ҤE /\I ŪLpPp0 8# (0 қ,Jv}D+:v#15u#VK- ΓE*[ݝH|QnjwYRGߞ-N.eAPdb;U+;VŃ/+bP&KhpSΛ_2kM<( 67#&E>$tg׮$n^{N^3u{!h~rw~.ZTgK*,=r mEؿG_99q;K3I8ES:·74]M神`9zs_xiJ|GQűx#WB!'+2ZpFmHIwbK68aGFQԣ"*ŪD`z7sf~L$zga ɍ& C!9 iɡPUۺtD<| H!!R݄# 8'c|{ȷjezEephSG$>%IUlI2󱺉Kf]aG\ %bعjƔ[\Iq7㨲F[{sҘu[_3NV댞xq(%ú ГWTۍr(j^.[]vZ,-e) $/bF(h׉ 0&gM eimFʐrxkDPn(n uTNV4^Bad>KYu푊`yAV_/w3X7-SfY5}>՘=,|HEۯ3VGA î[a%,%AWh& :KZJH'ʢ~/D L*> o;yگ<.ScۮIק'ZćAEW>\%QIfiS}2WIH>cBN?wB\Ǥh[B uf_!Pv_ɑ4+Lq$*2A,ָڻՀk`GZo?Ho<:FC{~*[!m?WMc fTc 0T*R2L&퍟Ei6y)|ǁ{dq'&2C {$Y TE|Sr:lNH'P,N(&N~ы-D#z<)F !0Y$ qh݄^]IE + ĸ5Fypy(X/1fE+;-稊ofUO6OF[9V n4uHXs l^y܊b<)~7{U;-V[g.By<Ɏ9:Cl ϐ[=-#B8/@eUn ; 1*w 8Fб)@:m,K0`B2 uH;f_ݴ $F+`8gxNMr/o6vUߍ2:ܯOh6w RqȢ~GVqvxK}(wTԜzieHNRN{;?R>7Xf`jU^jPP1_%Щ)]CrͼoҊJ:+spVMz;pΜan[;MUJ~-ƍ7#?Q7|\ءc1 bn19[>zOo ɫUīU(&W1z!=XAսV|RDjf;NNgM/Y}-#,`Tkz|WWUQbjEregVfgQx|c^W b\az*%F"XkoͻO =͏/?`m*N8MOd=8Ä׏ m:\[`8<"sDO;mUX,dV|@ƭJD.J׈IAIzms}+P$&N Y剬zIH[WtKW"pI!eof`L4yc88N*slnUƅ;KHyF? M]cNpXkPdZXCP6~?3e~ݣW湕i$ӄ^k l dJB>t/``$ \YP{KM̄ <tK9rL{#Ψٷz;3dAMx11;aKJRDd@Ym:ZN NGI M5U{WڞmS)TRT3l躗!Ng H z, +jm}}]I9{0}GGszDHHցx\AQ{1^ js;EcME']e?o 5wTqnOUNU7/SN4l~qKd1,Vd=hiUJ3й/ /J_ˉ&(#9bh$#y4 W8O͌^'odJIqT/~>&p|85;1 ǀC$[XӑlG[rLKMcig4 _2')V>#OѐQT{fIS}GEpo&Bq_j?2v͋qާs.wfc_F6lhŞD8ۍbq[dY:,c:DH_v쐧Ilľ5 iFync Is?nX(ObT}gAՄm 2Ʃ遙LQ`k."Q~||7(?W?z}v}"?l~[KPLibV⮗<+ v"gyqokgu8IJ>33ꕾbxU(gajR{g_1 XY6os;)xbAySY+&&]\ɪZ Ҍ,Ao=i+7eT ϶[,oQ@jjkڝicmUUL{-{9{@>2?k&eX"z@/* XjRݚoƑ+Vf-+Qo,.^ҥT]ELy,u- }gD!gF|w~aJN2/`ذx]ɥkk&-:>]xJ:%D%KG{H4Qڍ u^иr|H8nC$yIV9 #OUۃNP} vr5``K ɇGz8_o0!˼"ϩf2/˶PǶ?ŇHjٴ 6d%(.RD"(`Պ6jSĊ4L%%Zn_8)c)R}!\q)0]kA?{=A 紅:ve!RnC|N5)o2s#ݭSʨWXn +F#}:.cw= s2|)l7d呒,N'Y:`E2EdMPh^-2L \-54†IѹaZ[H #"׀~g i-K2dA Z- - ׈QV*~Dƺ֗D8JG9W[*Pv; Q&8QM}GuFUpjϻ/=+t !5~ z"T^GL$NOW 2QJȂ.O/ld'S^ W{m9t ]+WZIW(u85K-RĽo1k+w(C#:Aѱz[ (EdvBdQ0K/ -5_JprNBǾXN&wfvDԵ&>zJn! i31u(u33Rؒ@!CS4jL&JswW?\o#P{h̓uQ7k.Fe23cMOܽ%NV ψ̶q:5)9*` _/N Ϲ/ `t|TS!͕'e0^/) OJ"B&.m!\XM" ݈Y9*cV:4?i0׾3Eҡt -R;.%E*,Sp2Bj⤞ "}I>0XLǵqxK"݈Wv$} Rqn|VG;Ayi;xH2}~L#a_? 'Ax>+;Ϙ'vANA@7 5̃[Mi 2キ\=Q/j z, G+;>כ/}q3@VIa90%O0H^482l 2Ԃg- o3JgKѲq-4J+|BbNҒly ܣhwx"æfB\6Ȩ$c:UnIyd8,.B+o=2O%CnqjT8(vSR=fa#G{+B;)wB_͖Il S߭<$- Q̚ÑHaM7kô]#tԋ\]+r`Hi1$xC hlѤCUIveG|ZFA |U`dHN<|nxFg4E)~Mg,c4w p۳*Ai}bc}*{]gp+($jCa> stream xڍTn J4CwwHww 5tHHtHIwtw#tJԝ_[Z>s 5MqK9H.TsshAQht@.`. &t)C .  ;;]?Al Pf(@A(4'o?-|@.` #@fr2Z 0J ۸9 yzz\Y!." O @ rYjt+ @]b t{h r@JU'?J0rfUw2t;Z 3hW z@sh'd@hjvrseu"_e*K;ZJB@n(O 9B<}V`GKtwbv; P~۬Anvvv~vaofhN' ?  \A:pp,ns5wud^ `=__:^G{/?'!X8y켜>^ioWw*w,]2@ }#vv 7 wɸ: t-!pVYd vw^y7 t=+#UTY3Chy{#H pt,+vҎ˿tqz@x y=6VG4m`qAF& `l?M7Id~#o `l7M7+FPvʮAUjO7iFP>ڻoeEP/′-C[ h]pa#hg,Y *o2=3 v  #]eXEU凸 X`vPyml@D@m? ? Tf? Cut 9QԲA~sCc8vCs 2rskuutT7 UPoB ׿?F.U9Y;ٸ&h+n?""zc^@hy? T4MC+\G1O d4 iY#Nɲ;FFE쌳e%hbi1 /o)rn0,yw?Ad"IԈmuRL3CC$P{G,b#(} M}#X4w-yG(pD[4alP@*ebo5oe+B\AB,fWZ 𲮅(c FmpޓؔAQ{ Yg0GՀ. _;.=dgQ%R^#rS[5 q\,Җ"BREP,M'li>Ųm0L0z'EG]ky\V C9SC%;dl<%hp'.Yg:/+?I_,B]֞\c/OΓ`,*Ћ VVQLI\}EL[h5)\ذҼK[-zֿU+MpU}L"EstbJlBlKW/e~$~|u=H2oxwB."}`N 7Q/ǬнB5C- 5AxzҐaZ園C7k,dՓmn *_vB9C@IfXC]m񴸶)eNs7eW9Д<`뺫[eͽ?(ڍ^:5d]}0t"ᧀhڼI$`7RqGf3Njz(YUX?%-V qVPI4s^K^U+}C8Òp+ހ]ME9rw>|-6I_V]ߏF~ZO 'xԴV_Gfm)#æu:y[YŗN氒 oD}9 vx":EhF-'іLV47yo=Zoj%L*/,Z |ٗ ; s 2ٚ.{o<|`C~=+V96g\<˰bռ +#OMDg QeOijN 0[_cCw+)Xu]bk2pR>,5z {lXk=!7;9]s0qQwWz{^-j\"zČSF .mes BWR<үqG DZDF¦(L1v s/ҿ697%?T90 kɗdE[pgnkdu5TJk)+"8R&8`j4pgx=$]6bTG(U}O*J'G6!L3Sڌ_%P=[:߱N4a TIDI (WeqR`Tggw7Ci&bkSoG /+< wVSчOmTܙ ٬t_qMMл+mw_Eڪܧ : LpIVHvL#^"m{H:axzӕthw\ =(W. W  *~ s{]oPyCܽ).%"w WE|M(+T7ֺ<4ׯhE MQ.q=8z7`9KK #<0c}륔EbupbSxGэZ]Ōq)w~T0a/6r  #+°}l!Yv0{9~6|~]F _I}bvv}M"B֡2{ϹIefFu4T#N9#55_ER"pdz,׶u@,Eϛ abZ웏vhH/@R(uk%ΗɊVx.5W )b1"I.Kf"\\g9ݧ9 /lUSQ3[+XA}6hѺo:F sdw%umO?؈9I- 7u(>c_l-q fZNR3ϭVf|z"m;= ';w?O>aI&+[; ", >;+_u>Q1ˉ9DItG8V1;}>^ndB!v{\ϲڞd6Q|V"7C iOWt dWZk7=;YAD m|cPb.< p̫˼MaMBPj_GHC ^9|gڟDU.).Y?ծXNÆgCϰt6F@p$e k)(.|frx4diR +oڋMu $vo}3")#ۃJ~/w{\ y.0v%ǜOV`4RȁtL_XFK93qF%bTnC6a?ջ?F 9nN]4O: &%IeNݯ 2 }b.Gu򍊘V fk#+@0h%Nuq0U3?n+xgR nM=+#L;F;9;#J3J˱9=_Q3tI#>o%Oy-7Ϻu!xLKt">FGU\-v{91<1f7!jJ;*ݯQ^}rc/V9*Nsd~ b(~ J~aP>ɻ-*@vºNd IC[V=|1x8Fz kfU콣Omfq_~wD2{4 N3S. dłL "$f2eޣd MgJR~j~T ?ހ0J-|8q<ܗбQ#,=Y%JϏC N1? U-6CltWefkY8pN:HyGҾ!zCXkخ՘"sqz>tV4AJYGWE˕xQL;hҨ`VSKС6iҜ1a -&2T 45GM'fS9X-7{?z?* >|#Ny+[»%e\1g9{\e濒̧I{z?>%`xjeo=k^׿%sD - f;b7|kg8Mn4t"\Uo$zx윅 ǗuS?r0 +?+ǣ.Q>3P s9D5״;v9͝|S՗E\GVKCACP u;{!,O]*\16E~%24 I8B _c%oi)ʓۥ?pjݎgEe%ޚKRN~L2E}U"GAX0_x3O:W=gX;A,^v|W7./!gimy9b@g#FcjЄLx W{[B X@]ٰƖ-O's. \S8 FW ;V 2&QX6&c#seVrly{<( ދ7Lcb.D䎫b);G>R :7K ȉ/\jR'P9%ƍ ?s];~@omIBJ(&Z"g@ᾅp9ҜgR]f}Yۜ$]cA+x/Wc@{ookFlup6g'9!%&xj8/Ugľ.v]8yj0-FدZ\pUR|OYr^×`n-\k2W1(VMq(;W]:{`@+%e7zlG6c?.L)3]eNǦšf%Z ֞*0ćZzA\P6OƆbBf#u1gc=.E1 XѱklŬ\x,r_y^}@3KFê)z4K)slJy΄VjsE{$E,$k.<,y(MA:y-}Ks"v >Lx*Tf㾾a&7-R"bR#)?{|o+ͬ#Zk(md o`hv![ԉW,jY"=Vvh C3l.K£"ez-NYy%7'#mwetVB7_s]^ aDh:K>ѦSdk@\$=zgݺmtUca[Wĵ;/ l,S;e7ʍ{B&1-0;),GGVvEv樄?7~3&^VɅt Ne\Q>KӨ8:VxQjKD13ä#:1m: Vh ٖ'"6eHayq3:D?Lj%ႝ0OD ؔ#>՚Q\z~0ΟJm[RHhzWB}Uӕ!Y Dfcw!ᜧ V pK4\!QQm9Dn죉3 =J56uн@jy88JC . 1JH{ծ(W:"fa,dtS\Ioxzaw*bȆSg9.=VDÕ଼ZL{u07d2Pax&ihGpm2oP~|`MeI]2 +кxyi鴶>s~OņsOh"eU~rw6>gH-bJ TBAf\K㢌ݱC\K5i-ے|LrJ>t[C[#3Z_?|Їa %3[sXC]KX!$fzɷf"~)"sJi"HoJG '5+ rCdy׫B~0jFNOU3֎*V% xO|F*bZEl.{Ov`ǽQw =7A"o!)f:˅?W;;·|;{$wvdLn6@)smgfA2Jp[P^C{õ|e>O3Dl>Ө ^h%vo&X$W6 u c?N61O+,Nf(o9o T%wq  7Wfئ>'i_0bu]6{U֨Kh5a- t!t$9Jᘡ3A0;R,;w>;h*,=}Y/ms.w|ZBBk. 3HB;LŤ7̓r0u<2F~?nQ 'T55p7;-۶ۚ 2Xe %7R suGAnSP//ŷoTMs&h򡵻OTj+~m}X2oH%ᱏ j/=,/z3 zi !akB`˅\غ'Qx%?SB1')'RM=HzbjH\Tumޔ(/. ; ݴ;w|Sʡ4L" et|J4fa$Z{{&bjYX%cVXD{gT~ʈ? 'n'ñ(u܀|f6Z ߭ڑr/,z%VL{,hE g%) -4>|F=یhn%2m niG큢oe_nŻL+<n;yDljA(O_iQZj^(I\N[uCf+dӞW\4-|JݱL$T7_a6m;ZCHN1Gz.\7tn_0~"r20Empsɐ#^t|.*]lwII3o nkM+8/[X_w ᬚMD#!Rq4zt\xWJan-\8βe~z;YY mu[5_-D;_\?إDwi#1&/?#>ak =(K(`I} uRCd,"퍳E"-iB16Dǽʩ@E8Yy[qobea'QDN,0wVTd&O1UrTbC\c?!*0|o: o"I7Tbk$*LK7Ra.G7?aWӗpa`J,b\ >WVcs =W>g7t86\[ixEM/,a-<y TQZ Nx85^j#.٩I,R{Ccc%2QOb'*ҡ̀sۯn* .Zsyq+M0NGV 6+ ha1bTMc-be'0ѵ]dQo-YESND5hQaG?]$Ӄ3C]m| WI"fg sZٹHK[.2}QBJ0WAWM1;YIಎP@QBALJ+3|9*"l]n@iX1#CA<]`NԑA\8\{ACu;-ASm㴂&T^7|rT#Y!Sǁi!lcDXmr r_߭t1Fhr˻^J`_ jb,u-S{f<-G'֒&ZjDZqM;|Aw}G ,`Rb,2m4J ħR^9⇤Ϣ9|rU(!\ ?-҄)Qjl|W̡s{,]?&6t# jE$TٝFhEò((UA#U!S[s:YXݓ#-y@kGn˸wl*SYtP@ϯ=kF09A?S'ȘseF[T3B>j'~3ŏ_kNNӗZ+۔|2Bt?Ѭv _#tdQb}[uBnympuopN 9%:+MO+4 ^])BXI]ow5ɵUO16{ ˒pDʑO,6Ilԟe*}<4r$/ [™ٺx'eJcNu\ V7FTKF'K\,.إEHxhxg$~YyS=Xmt{hJׅUogK ҈gmfoЈ!gD$yšZR1#ȭʋU;4Yp Mݸ̕L4ahz@ _6׀yԙ.˜~ *ÊJ}fh֎MmYq<]ga%JN2T' -~:HڬgPu3_B ZGoh0umDy\#T<:c"L 5bWrC}fIlWz[O'jeO2 GXɿ&=Z3|ƥzߟ>~l>T3ՈLsD%$p~b՗"^\.:F~ @9)_g \D0n6apnn_@R 8m<g?:UGc8i h ە{$r9Gz3V+tkxLYacDiYijmDfܙ|Ru㇞l~WkNz'9ĩ#mTV̞kl1Y4 ?aM`;Xtļ}d lK 76,6l9H(n :tZFupEUֳs^|&n<sji s tC b혗/H))& a #66uFP&4ч%TVʝ ZH6SqGlcicQY묖9\%ČԽ.z7L'0k+NJ'\ 288ɌEu.1t32V_J#N:|oeh2c붗rPG~1xeȷHஜϢ9J?_Cp߱4Y)ZPA 8DfƵ@h(}K31cJIm-bJ!iE֊L$svw)CV*uZtvK~>ђݷƧ[CrB^--+v۹.wfmqӍwMV >2?(:<>xMu#x)Iza)~Dڢ恆9><cq S?QH@)f;D@eMi~e|"nl]ddceIgH;lP4߳K6my'j6b2ز>c_*GU_6zH V%hyվlSY(Ĕ_.9?^V5o!*X6ݛ ,8u#g4c`a~gݴ2Gf1Qi=ioGrx-^z6y˨+_坰WL0> K]MH1 @2 CQib>0~3jm› -1KY!"H,PbDSqyEh&r0$d9QBXU 45xV&$$wB_STT[HpioQ3f)͂Q,(Jv&+g8}㮤skfP~³QGD1:;|}+$Qm?㝇 RΎaKN[ CP ۨλޘb.SWjr&{-=*B7݁Cj[&!2_sQ5ҾuLKKE ̼erSvc{柈'K}"-!z f'tJ;MHɷˬبp㵪m"n@ [ endstream endobj 1525 0 obj << /Length1 1784 /Length2 9331 /Length3 0 /Length 10440 /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 gVu0Ȩd 5go*~!e` Z;_Y?d=ɺ98f01P9톸W ^+NKՃ%nI{H88sPWY'JksNu+Wz_]{qwI'K/rp8 t/W+ pq:!|08[pI2F@쿈pi"AſHe5Zky\@^{l{h˸A8[q+{r~Ͻp߷/oy:]m {Q ~?'{vf)lWzFƒccA>7h)&Wfl%Q+'{NBv$kj׮*rgFvˆ"~ s9%4A3R^$pI*KʦWS]LW!mo^e+?xg1w)o1ZqDj&ҳKDׄC {:݃6~Ї"ʈ PJb](Ŀ+s$#~k[9>[S/KS3ç[kZZa˃Ku32ѹP³w,AD$h[қF ܷP(9WTˮ*XA?!(G}+XF<)ΘwU s젗lδP:q J/D6y(4mGX[3l`Eށ6]pZ8"@kk 4^DGqvvޘN{@6IdŏсN2gcOesQNc鎫z %(Pj ȖzHw6{~"s.r7^wbTN#;yaik9+sVn~ėN*P*sTSZwv1qEV[nrFLE-B_yu Xp77|6Y"Nt#yf ͟F[KLQ-4 IpK.MaaG.m/{朞wْiKW(l$Sv p 7Y8g&M?qy. ":H/Cv`t NߌZ8κXL9`45hxXM0K7~Ǿ\́.KjGRԻ\6ҁFJ8~zpX7%o0qAY]Zn]F8,XGkT@fl.?̅ח'Ԩq-ojs:搰^gH5DlQ=nxg.v=q<s V!6}ntZĘK.DଫQěfLc]^^mjB HQ|-;;ln`| $ZhNe\ʤǛX–*Y04YzqZ/CK,۲+Ph59Kkj}|K_6ك<|. Ƃ#PlTݜH{u4 |%{»Hf^M"4IkZIeoc$]5"J3O-SzM9hRN+6x+kyN>갣]S?ߍ9RVeanCw\r[HQw3ӲM.#ғOX5iN*bP,53y“KS::ԁDѲ/աZY vËv dV lGiReh#K@a hRI x?0CbiF0aiHdeçj+ņogr|loW+O3 aIyKOBՐ5$gn*~`jo-;|˚PeRZu2˷hY1Rz䜹tAba"ǧ}r?,G"]wI_cDHYANR%)myؚ>49 lYY:pyx:N Rs!7Lo,nM|v.Đs*Z v8y4seƶJ-fcҵ,VRK-@#SfMʊW;qfxTE_MWBj^P^"QuX#՛2×jrX )\?c7;3^+{1jtfH~{} iw/hۖ XŰmOprk 7Fe-S[.a@tqVl$MpyRn휠֤d/Y*|߀nȡ0 ,'#uxֲHvʮn6%JJLPPIAd?T$E4g<d:;?OZ&xvΟ*U>I86CU&9X2*A3C:ބ/3SXwMrUd=C(LzmwS9(DldO;-/-]58q?TkխODyjtDyMGk L f,cSMf,Z9'&ooxP,t27ax+pKf"4iH\{sNdF=}|#Ic6ۙ1-I;P&۠>{6\u lᔀ(*q2KNwӏۡN'ňO6UJgn9igW)̧O ; tOM x6툉$`{n@ \ADK Фw~uG[Cf߾P E5CuX9bP7(6zr˟i㢰軛1i%kF g_5˺-dտP[WVMAM8\d<ԕO)Yw޲Lݾ1oXa5 tlVv9؏!4dF/f.0(gғ"^uP'5Nn'J^ 4*La&5g;֙L4:o2|or#H|}OiS۪U~FM$C#QaﱎS{a:eQb3a /F ;Tj~}ezA: O'|sx{`JGBnBf1]1*vh^j'Dlkgo^- 4)UP`?FUn.t:x7S^ɗ᾽;߿8uǐEOST /@/*7) 1̖YUa>av(oܿEð A<,G_dc%h#yש[UF^&UWܬ7 4ۗ8Di|C]C9>J3(sfm6 /ܾ mPɼg}vEi$vvy!ksnN㷵k|"1#mᒷzY؝rI9|ꢣh aA%_\D2k4m^נNFn3aϓg?\s 2c%LK{@j$C6!χR.x^I!2=*65l'3 ߹2I"Q3|ztGIXM mwlAH] Tr5fI^kEGfj $.aWJ{1OwcMn&!auτI9/;ݦ :b蔥&`~׳+q-`dWݏ9WvzjI3l3'uZ N zi ֳ/x_P (n4mH4xr) {V?B16puٴ囨ϥuyeb̭eS<7+jSe)TO=\h9@"Cm|Jyílh.^Fl"|{{iMmhzOHt#l##У%I/)m3-P,_]SK= ~'5IsTI/>DἠNۉ5#a|,Bjʘ[9{.Iky3A`&%Z#u#m|n5a|iqiz6ڃGT:ab/D%^ur%KNK&\) Qh}ɉ<筓Lw?Ӿ U=2rۋ"(9*A )I'sUuMܮ_w;eW`U@wo?0 tP0֢YZ޹+=>x]iqŃOS*gU3ّOGZЍ+ 5wFs;H#\P JO0e0둽Vْ:] ۏs=AWw-K[\SÙn8>jp_٭(ivc;6Pīujo1 T5H7ywxYmR)0.)M〖@>֦LiRߨ;dFPҪ%X8qENL@Uyޕ6s3&-=J\R̜\ I?bQV8D+(a T+S2Hаn\sFTܣHtSjq7j2*`bbbsCNuxkn_bJշ NTvk76O2qsE?v}/0Iؿ޻͝C-֠6|)䈑)݋=߉Oū W="l~3ƩHLgOC U4Y9#{ scM[52۔Oʲb0 DzlS=OTX*\p*wܲZ<۫ ʓ`3Z|7gIKُyZJv)ʟ&X?%}fȕo7{7c`vId;,S/5R8bB%6ueF?, :"P{~x5L!8,QnD"NL%~A'tJ"AU'I)~62Hh) w\9Ō,m7l[WQY$Bm!΃Ӛ@aT%jʳ lh)i/pX<|{?61oL"Nۃ6,nfKCfwlü3 I%-`8dFF+=Cu[`VC,3I}C@G4۟Rv-`>gϪjoC%JDg/GdU轳S\fDF=fެ84rSRDK) `qMYbhX_EJ|K^qM.mwi9Ԑ{`{: J+W;VVTו05<R)Mr >Ht}fÙq^^Bw*a@䥵WGO&s?~ EdPԽLڨQV1(A8 pfuctd*ӧQNsXĀhl+sn9fZy{T[ ,8o5JFCNzt'"-ͷUGLk_(uJM m"FFgc2Ej-f#R _;ycWwԁ ?Zm4a%93;X߬QF,foWPw gbU#G1Bu}딝Cl.q Q9ӧz㩔0=N ZZfYe8N?{}V[*HDHo Xgu]zM-Q`훽 ;R1t~V67Ĝbyqm{6Oc~g^*q^?&|&lp7@v[˗9^./F[)w¥hz|H,>ܵ VOUB.[JH67Ice%jFeAohҳ?,Zyj%svjG T|B~Qn6cC +wp=A<3.I@1gg._o+S[1)h! ydZO͡[]hGd+rD;?guXNysu9A#2*mM. <MH\yZ]j}&&4q; LBbZ[Q2((n_S.FU^uc>,cmS8;}gl)pNIl-Q|Geĥ٧4pUWn?H N Ĝg̊*MX~+tJ-v C}xD׽XW CD!u$X;z"S=nGq,vAy5w&iƔY[>IdPHlO ]R?S2ĴsX/!D F7۰}PdLo{ƼvX“s5Ɍۡ5(qF!]4۶ʋp< T}MZ.ޒyνڣy 2I٬%w9 l5O.~cRqʾ^':y()"M-aJ<ǫ6>KQq~ZC6ҋ?`j>PNphhOf,SC#T@ꉷU{ ˧(C%ИZmg#1уhjeya ,Ι$&/[eœݳ[=(> zS(mʝrн}FRRw5Z3vY-yǜ|4eHq&5m?ۭ^;5dcjD)ŃpVO+ \3ndf7߃_aMShܥ}}U+{gw6 /j z'L &D|9ZZQsJwd 2Zݒ)m|Bveγ]Ό=(£RI#&6mLY 5bB  V-n4Dm|O&礉䄵2 ~k^& vp丞9uAK`לr3iY4$w; 4 ]rxs^-tY/9^[MVAXZSFKnnICaunuZu8Mf+Sm}-eđ}#fblˎ4Rjվ[13իaEyYRT؃:Y ON oRw]|ɀ̼Of I4/ŵVPPXC:? 7ⶣt ՀR{qBϚ7pHI G`B_{Rws3+>GWaH xݪ+Xqw)[ e:OW!o;R"K/mAxpgÓš]:Ⱥzl.:ILVpԥ~s6\#p`EӴJ~-=oslhĄ_ά-cᄧsq^Rj:M{;ٶe==~l׵ (wRXB$O.-cתu\ѯzV~7è:$6d| WTRcq^WQ M8&O0,8Whrb]Y핎w`2 endstream endobj 1527 0 obj << /Length1 1526 /Length2 7197 /Length3 0 /Length 8209 /Filter /FlateDecode >> stream xڍwX>CI) 0EjtwC`IIiC nPZ~]9~kUݝ@~ ~Q (D % 0[:/PX.H G ;/..;( E p5v" 0(_%إP( >>OOO^kg7^!7r@ݠH-i3/nV폈.i' wCmH =PW1P 7]_` `NP&1/ Z;!0'k4ڭ`Ym5 H ʍ $߯2}V#p`H(|8i"b§CU](0CgA]P/߯z.A_n4 ? M?>nP gh 6P{h7-$ h B+-2[?ߧg"k(翣rr/(G@EŁ~.EWQQn}1S4hMC30~?UG࿗vwr `aNBТvGDC :Q5zPdh ᄹa^P[- : t'pz) y^';Eֿ*!_C( ,F"h-a?zZm^%#P :WdĀ|6[g)9x8h!a3~bqG"c[yhٿ( L# t<R?RNx-P]ÖjN~ci淉C*joF=M h{$u9Ir . -hVB[.]V_ʎw5[+S7YAt Ѱe-9dž,?7LHcVj>{.|%oR^ݻ"S쾧 _n0K|U豝FcDh۶dRea~lj+OzP8꽋T:Y|[d|`u&=a+ĜɥapzR%@[/]iz=Ԃޫ4Msf+LS<<&=^<Gu$o5toeQAAȭަ Eʇ Z_U:DgQ%9W;Ļ9 }xemtc 'o:}-~]ϦMO V̻mMdU,kPKīA˕5j'aVVbtׅF?mS˳5PFNa>2MN,U:i¯zDaisoTi#0IdL%@k:;Nf} CDOl3]TVAF>'T}+KllAJR*ƟTU:+E׎̧?#Y3o+JE5֯XlC1d){Tn]!;Soܬ]p*~! x*bH|ڝQс^.?P &\Sx6*xgxv#Ѹ%}%CImk/KrulyEJ{a4 ,yb8膃:ۏ&#_i,NjeKb *Â#$Py_a+hj@D[XYj/U*0z=.Gw)4ml&0-5[nCS&&&Tv-rPD+9C/7"na)(榚 \Z \46y > #s1nǍ,(yB ,`D[ԏFz"KADZ&yJT8nʵƋ㖐+{lI`nH7L&r%՚심;Y- 品 w֍%ⲁ\ʰ[CӚcm1oGjiW>7px%[^<{s䵼X_44me$cL.(:6"wR# H jHVE.͟Ze q{tٯrZ I{ִiJ[R. XXڈ}d])c֯HtVocxꎝӔì6eyǽ>ҁyI؅$+ vnc!N9k hO ԀRoR.{~T6.- W{β>,>&-yD= /CyI^~/$KbwLȟNa6.T-;^N2ԅ.sOsc 9%~_##θ::t9߈گii_K9Sy~W I0s,o-g;dyX/hКE K|͈L%1m7|?Hig~13 UL!G# sVOZt G  jB)7јk;lЇ= #%t"lljɭxdI3 :Hk3n>0L]68Q5A6`KN- +`@{SӁA*p\Sv^t4KWhƞxGSMn󭗲|A匤j{ێ X_ie٠1i/`{׆^ VrkuLt*HѾ5a>XKl'rљؾVly^thdx`{W.R1 O!cZ|N.P:L35]{ $5Uם?8'ӿ Ҥ\T_(\BuH3=}\r1ژi#f\P唇]lPeI++\u#<ԻdoNNɡ*X5?g0^A*dSpTuq_単Q?by#q!R 1-@K@9ٛ/ީ檌]z^\% !Yj%G'y/YKA{@cOYg׮<~x Mf./chȬG$OV٤Dž@ڛ)T-'Ams qq2wf1-|k䗭A>N"2yl|XR%b[\ɶ0 XYFj:!upLD7e4:>:)2*Bm?5 F'(3Mˢ)&P.hh1}w>1E-v%+ջ◇lc`ԼiЇqsa:s@f26uJϷ<Si]#RV,ZC<:as73j0$. ;Kd~7*DKHYsTCKY?Ni͸sGpWLʲ[ wzN5:K=qxE7t|𽦜R@|tphH5]Vq#`;?M<զ/~y3N㫥];!,{mX5"qGgֺeTήBv0(3 #)\K$,Rň,?Ê|ƕP*309e^8S" Sy񊤜ƒi`X{l(~%gjj]dՕ7|]y8Fz;zfd2,#.wE^V.lEaϛϢ1X5EyȪv4)UfZz/~2{Ѝ'WP8! jy65Ff΄SIζ#(jce;b]綈^75gMk̹p;qxᵏ6!oC-n œ`$b7'wqPV|CXB8Qxg/k\\ vKs&po]}nQւ&>1oH m@VΫordF yzCы<e};x<_m> RFZ9sDXXPD࿻22RN\DkpBjpMt8jy7쏳ˁWg7ӝq_vKI0 䭬Y=Nx>9&36}0:] `'pjIAP||0Qz I!K :W3Q>->6~([8A#~7B I$!y,B11~7=. 9nSs.Ӝ ߼h ’S˾Vg o/Jbj"}=snwBpwZWvd8%:!=A)FIA/#P힏LcBK'\F |ɽLӁL=%YgR[EIc *=TZ- f;VNR!Ҝn 4u[i $l:%D+a nʢ C]6lTKSZսOChY3[`vGExyřnemv^%UAn e5W7`kVėLhp;R!M-]=EXhDA@;A|{;Ծ%}gu6qrFO˨wOν&:DnhGkiRԙBB4, 0)~2OKscKH@z7G\^9Cpa+@.z<kS"M$uڴŋz' o_XY t0^R(4YGqA-m^SĢT liA*ל&) +D endstream endobj 1529 0 obj << /Length1 1933 /Length2 10119 /Length3 0 /Length 11300 /Filter /FlateDecode >> stream xڍTZD;ġ.if!f)AD@oZg>g`-!p'P $ @^LFF]?vLF}+CrCdAnG58 ^ P?pQ, q0+& jc+V_RPB@_!Xں9rs{zzr].6O-@ qJ!ƅеv@ sElq!.Dv*@ Yo?7? ;:`P hȫryq@0/G+:,I䥴 Djursr:W12pGG>Y q\= YCa`_eݝ`Pgw?>o 3ee+E_fD Np'5 ?uy@n.?0yx`ba0Cf@@D>2Etss+hk*Sp//'G9y> {)/&$n M|nMezB 7!X&D>)r@RHi"rNB@?!7  (p@Y8΍8C'P΃P"n"bl] ʃ"zD ߬]\_ sjn%fWvQ-Eɹ6u?9/`[$i2Oyk>L١ 4! \+;ٽ72yD.0ָzI\<{"V~[HNTDXӨ6rnJw3̥ZJs[2!|Zx)֦VXqZMeqM)K R<BaE&ڌ"BRΨaȹR-!r1UW:~r`)o_OLyUMIX̂z/L{W˚ė>&(H;А *^ wOW+׻z_Q"L gQ릊򊻤fpHK C1ьi?\A*I)Vy^,'Wͬ6j}CpO'’l8⛮dEa] 09V yW$*xM@ngW>at{6O* 3UţP:CL\&vW߈_>Qūﹲvb=P0ZFg8i'4;s\MY8/u $ aTQ_e 3N9^8D}'^SʙX"#W]jU=&Fe#O{drhX,(-r9! d)׾U>L9aBuJ_p8z,\Fݻq`}qx'RxzͻǎB3 Q1 iM6^trv1/j昧cj):aOhÎ55r$~'K"bE15__(okͦv/=wιWeu">ře)7*m8x}Vk=?o1$NZ̾, c\(v>|i$yeGVtոo܅i[;Srr+u;3eDu 0d` Iה8{˔=jz!X%:B$/[U;&ׁ>.Z(5@8W5dWcOUhGz $a.i`%"m5+t0R $ä#AQ9x)oQ6 xw1i l KͰ.ʗ[VŅ}95x&jYMo!V5F,`pPHJt7wri|o ڃvj#=ih4:< JCIݛKž׾bhcw2͒T]Cf7F/_60=D972=yϯsb8,'c]+V@t\CXldy[W$ybC f}Ȩ-A)2!lډ_4bf{,JA.@!RebD2ʻվ0'F/Y+=hLJ{ 穔 `wU`*̓bCvAV â- u 'W6s{V`uW ~3N2 &+=5wtU07缾֘;/b *HLTc&FjbkKI椷2^\@|q<~*_/!IF ć;f..[|grEyϗBJΣ3JI͚aR=\bgIg%isA%7#eVOcXf Ƹ{~;D nh-71wuQg 4ABzXJ`7n>V^XE:R'6}ړ&p]P9:ocl}zv;oU&Ϯm;$TX$X%6߾`7 ʭ =ՔD%\|=&`"hOm%.qo=񰕯#Hтs&C+]~R>9d}1Je2JX_%ELkk.I 𸸟- U>Ө]ǩ0iy|9n0#ax֡};Gmv6h1t`!γY0@()0Nc/Ѫ|3\~v-o:bJGܲҶpiw ͢X3:2UpV*`5(RH )Ȫ{4~9)& >/ڱ従lΜt\ї1ES@:N]نhO_7$/yjO}h27ݸCG5p5)b* ^o"YV FΞ˼\5+n@3o3X>z&!s+4咥@&vU WX|vrgXi˺Âx*]~MR 6IԒk _ЙOrUlY>-"e"c\Vj2;vy汊7̕AEFS,WhmDŽAG~xgؘxAHiD4 a6 r =ˣۑkf,@X Kdm v;I~{1fR|lٓrvsɎ}U8_P[U-s՛5 E(;^1?p| M/$p%#DҔ?O-'oVyk=;tӧQ)J`Zm'5:IሤDt/NDn5OrK fP||휠'x*몢8.o :wfg6 J:Ȯ$Fٿ]s_m;&`hvP4jZ< % 6uxK45M&rfiムU{)]%ǚOaZCր֥6/%pUڐ~2^,$sOS9V(IpM)t_\h )5Fvq F#{BM앙71#_ zu;UEF,zù/4r9Z\Ptڌ6gSbwڎՂ4 O~$szdqkNuGu\Qil_Y%*}0ѻ =C9w7J#q=2O>Z`48> _!ee}~,ٸE}_E<ʳ:wby  :N(f(!o?LjMg* K)6y kKIEA_{myta6yGpNJQo AAzW"_º2` Gs]IDQF!F}nO>m#5WId$~\‰b{<F4Z~cr Ew5\ ι|Zų$: c uke[KhwGcNaŢ~~2P x7v+4t4^TSJ %YTr}ւgyEamܬtv7l%# 0q*44e@k ;K_z7A"63<#b82FIȃUcËCUmɰuFOȼ.^R )*i꛽}>[_4t8(~-0?UF^R.Hsꞽ܏9t`ujtްv3}*}i-.Ljzsum* J0zD*>uhGIKk`J6IpD`(FSDd}A$x.rx6xCTYx VzKj%8rOiߖކ]'oA`4^?6[*~2ڢPϑ6I}tOh4x6ED?TG2Σ ɫKYBmyN#3TmۘìX-Og~BB TWJ9bV!1 j)E%8_=XUdVڻ ۓd+;J%9cYyZ\$#TtN^M;d9xĢ5>~;ΗG?L%X\pkq3}8C;|qPB>d k)4/n=Cn$d*OhHR@N⢐׺d}p<%/K1|6t7Tykٻ|7{N:@e'-5w'2(W㺌ǮR"-絶/A-FywcBwqaSH 3S6OW(YZUhx,ݭE!{)(Gh֫s+@ټ0#Upv7%*nh-*HZ\/*J&Je03 wΡEH9^Y^o~s2ہ6P7 'Ʊ7` 0&[ENF 4Tx xiȻڜB ?ݍW6>5O9.܅qqJ(T*7JErdjtr)d/t; 'su޽9pt9}:H.4ǰ2cSϲ?o3Gc`t웈P*K?1VZ?B߬;E@U=t"Ixt[e&~Iq!ҁt/S]pOS6I>,]қgp#_Zz_Cɚ7b3qB #جCP? k#LBeCV mW?:rP`_)x^EQ}5hT$cO0q&}O9}Vtjl{BHDCIA ;x5=BcHԳpTm^ß8s4PZ1_~bˊ/0(XIxuL䉣]$/743B#\ON:/-eMmػPu44RI=J}ۘ\J9a8-yCޅj&<1;Á*^56|"_9_Ч V&$woM0nOxZyc/xn=ʋP]Aσ与Q @wƃC//z5mFHh'1ȶ8.q$pZ/+E{wF[tj)Xih̫G]bh-$O8`P95[V.~. &;Sǧ1?QͦxOҩ!ͧ t|cV鵖!qO$Gv0dž >zH>HuXٞx+#ܥ=afhgИOQߎor<%NA)+ؙp"k"[Œg _O>i0[fr!AegFU^~puG\m.OH<`y\]ǯ)39/ݪ|"m3䎦3XlVgȿ QXAlר%4!YQOoNeg*T\ґ=К%N;&-5Fu܇`RDZ 0»Ne re6ly:2Eh&ޓu(̘fp̳$ƴ^C%o6)NH1ec8պ66z:N}$sk +D%4AdH8|X @NS?|꓈4-0í%kIBni\gi2u uz0SY u\ӲU= LmB#ψ8yQQ+_)aSu φVAL+ߵ!7.LTζo4@GV6*6X|yX'e!ugy@C,*v94KsZk)$z9v]JuqϖOZ ?AAiyƻj/7:pOŲc}(kj84 k[nZN8E{WfR=# p7#k`e"fM4,]+z~4ΫN .wOR_5A+ Bsfh7ɿzc e7\՛GD< ]x/џiѹ=uĎ,V~ufDɽFS;Ә T~=t2g$pF6N-*8RVQѢ#o >yj~SO%7gO%,0c<*jݤd|[Dq4r?%;+-uFTRP`S@DŰ7>L:nk;Jl6IB_H$:j0q*^Az0_$R$Xm$#LC֤ɸ5X3/9'w:sQ@qx&R+UԝcbUWU`>Ġfwq,:%odڍtȎAo|[2ĔEDk].)0՗}aRw Ƭ w0A1sa36},@"ځ6$c&4?Ӳ$nyw9>|yi`6xC% ^/6M50Ɯ;iS?_=֦p'buJvre_lQqOl[3CRrsMWQ nlHOyo*[kNxI*`Oq'39L󓷼581 +d̊MBY9i+5/6[hHfF.&R_o3T5#_VpH^*-\`=Ař l~hG%-HI%jjLK8Y4gAs7mx5TkN=QR~#SCt! >}5@gY߭(tu5 -`[vP"%4ؑ9FI7&惘xN5'{-')ʽG/5ؙT9f28.ķ}&K~:c:N"L&BѳGY.I _s5Ep=GSwU b! Q"0o7q똏 l@nI~G[r=v P{>qүkxMq->P9g.j S|<#קaHLΟUf熞cmq:5$#g'cE:dܒFoaa>egCk3JJcf;9OR!W*bJoJf5sjBx,۶FreX.B9"#O3*]ڨ*&"%)GP /Gv<>&Ak ]y3]{+4$c:RM:͚ue#h٥ !j,kb}E\+ d-`T"Pnmy3ࠒ؟43.9aLG *Aoy|\smېaI(X,$G}?Ҹ1@FM_c%4tB1&Xm.MVɗ-VƱ}E/XfnڸV +gUL&[ѸȘ CǬ(-ji8[V/_8/7*ha j| >&L`~q4Sy.^ν[͡RqۙSz-6W/;bgzo3C(o駌DuhxIG4Aͅe ~Liݿx8ADO#O%y · ;eV<>by^0XbcbI25C o矅 'ѾQ00}' i|Z8> Qa"^FsZ.[w]Wv^wj`4-XXz:8ϖl)3>ջ)P?NɤȾ@SxOl2DgiH vυEu3Sي #31J VUsh߬Z;o?0$ko §E6Lqy=CA> stream xڍP\-$whh݃Cp@pNp'AGsUUWckUՙ! i 3+?@BICʎDEvmG99!p]^l@@%=@`ggeqH%f<D%qt[Z@kF`a# frJ@+KG3-@bxW ZA+~wwwf33RvANn soe/jHT +u; x1؂@/) 'Kw"@dg.O 439= -"ڛ:C^n@-%bs6s;83;msd]嚥% vv {g;^ݓCF`{s4]X4 9ɿb^LHY\\#af򻁆'o _olzCv.N _;!f.S%?_ ?}Xy3|Q9?EFMQEU/8!o&N; *VU '_kiAf?7`b5{y?)]*=~??~5le?7T:+vsl? v{U.fV(1TۃT!+^V2?\Rf߫ :9=X_f{Qs0C\^R/|'#a{Qoӟex,ۋDY@A. ?E,/^.fO 2CZ^ X7tՉ3N Qj1y/;uޣfm8݈Yݑ]!{>ޖ8Amf4TX "1ϓV 'ny|GW^4B;aj+fb5c K Ls)\H1/xm\Z`w!$'?H[.+Zec$&?WcuZmod GAU7qop8F[gpw)Ti-0Gpb0Wr{齷ZZaJkTbigE|M)[ oOuV9ewԉÜǞzPԙ+|qJ̏K FȉxA9ՠ֞gU+lj }iM-0wEټ۶ @Gӷ+axhl42&Kּfktt7~dNeîuwO& {\di*›ULJ[r?0GgjTMH<]*j^goҖ‹';µJnxi?9ܰ<T~cKͼyZ_iPUV6g_m7OMJW/AbN^!/?ӤWAxHGֲUFFpM84АTݐ vz oԲ*$>H2z{CtA1g#RZm=Fp_2(LNa) W!69eo'+(\/ۗu7M΅1fLHhSh2IhPi06U9dD 6E.pubi\K2;Z%ʻz V/+h:LTWT⫇f-o9kN2<81 U-k4¯Hn*poO2y>(.Cgieׇ^^6dc!FDUm N`z!bVU.ۧ|2HT&'! ' nA&,myNc.҈mQ?rKͷmhLLSeo*Iu[z2W]'H[>/*%t|87gatbnuvƚ|! P'bJ;$&" 1_7>W٘PeF++lnyJ:_Ĭɵ^}:-8.+ sVyH_=4ޖW!5THH,ń!mr|PSmG˿H_3a E1aW)=+lY@[}@~2gMA!<|*.9|b/Xar /Fv:`gGIvҰ{2RKK,MeH2Tb͸Czo#⠋y6k1o訰0lFW9CN24 ŏ-zNuNxz|Ry25[ |+›&Ǯ -C4>|dKU"=:̮2RD66 |ж>DhJ@yʛHnOx4O'?WBѴ`۷*OgLdhU/[~ZE)OWvc{^AAZEQ5Q3N2E%^,ڢ FsSXH%2I~ =?^ċ<(o}˧$}$_+B`؇za*KodObe& oBWzbHc=L#?B@}3ոNr+/x#|;MFⓤjLٱ3P&4JOJXbo,4(,c(^n~R'u H}>F6,cW 8 ~r)bEK="|c|D|EIp0Vګm!P[pzýDYkj+2Mh;|_%ij+Q`eNꮍc[C6~}TnB=@stǃ69XdaS%^կ2Skm(HC[pfd:pl"8[Rwຼ%4sb M@F7%OP`CBNTBݮ\EMMfCk&N_1zQN0_d,ʦ~n.Y ]q_(ܳ C;5Lii ,kK\$sfZ~lbi4b¸UF^+FfNYܐOU.IOSKi@Cޟ؞-E'o!U4A_`h.΅Y^f3Kd&G$ĘQ;^4S@m aN|'. !yR$h2ݭ\V)z@{\Y_ǓdRyޥ95[xޣ&k8Ddͥ??qF 3Xp S'k>=u/]mSՀKź;fce ^D0\MWqwBRWr,餇 "RӰ`i^4Of-syNMȂ~i \ SB껗H\ ΛA׫8CG,Wm6Zk{ pڦL'6VC5o˓iՂsG~cf.diI=|&˛ӱi93US@/H}w%^D;rs!jsHNXġOx{3>?*!kfp}Y`l|}1euPLߒF&'1-[F'i6a6rH Ŭaڬ/Ø#J S= nqtj9$L>-N瓏ϐiYEѽIsG0`Aj5^.3)=8iҶ5!X5t&IMqzk-UixqF+khH~w²GiesU7Jk4_M:M+?%p@LΥQ]in\؍0Gm\ I 53!U0̳sW^_vv_k e}Փ[oK/HJwzڇ+lѮ~foˮBԹpF]z9u5,ߤ[(OFEUNXd[整)1fpIf+`[D(;1 ^O,R7VkNOo|)Hx96{`),>1>n~!X w?]-~l"]!**lr̠C;Μk`X ydکpZv:YoO?SwTWN> VZ 45z(lnJ%Qܵ&SbX𐦭dnb|J9x̦f\yIw%.&R]ӓ;VPH|.$|A`=oHfz>{_SJ ϐ@ȳP ]C>b ^[7_ԉeGJsKM1TD/p7>}* X>Iց10:Pٗ=; f5F F#ˑ+ԇ>QT740/μ ~N26hK^9hkƔq%O_lQ:S3yyG;lGWQ` פS nH -!"z$WJF)dTAs HfK"9Zצ'XOKV>& RÒSjdGugq9y+eAsZ-O5ԌdG]Dc~`(bIqPmzHM-~kst_ҮďȚkY L"Iu=YQy#Ar6:.u% 9&_ rgPlo1Ψ3ÆL Zm|4oǀf(Yֶ7SRu0Um v71T҃ @ְ5Zm ?~i>`{_ci3b#ŋ"bW?}-wCe(ـ2:q,\h2tHDGAAD;5)77$*wP*ٻ?\hjzTFrSvwd\cJA, qPEkP|Nṕ٦A.3F)=+ Nک}Ek;d-$z#CYQ*GǬ xmA=mp!\)LJvsj JTuq*otcY7\Sc}gƗrͰt׮P"p`xڮm]}Skʬy` =5fw~+CN>uװG[ '3N,葅"$"Xn’ enFChΐMuoNjZ9S*VqSJNic $gAB+JQֺcGQ$<1x + [.O}+ʊU랙6J֏]jC ]4oSBtI?YEO!SwɅQ|G:%<;#e 62=Cr'<>d"iyM nWc(9h\r!źSYWnD^|h"zǼc`00eH)=>46o#oxd~m AlW.Ei ˹ND{"^?Xw?l*w{?cސ$8Bg^2a^F1]7׷I[_̸?9yZd^Q{Ǵ(Gx0-C'q3s-6XlHX}G);'`KR;xݞ1uArzDV2@hq DqB$ ৪lD|ҪW؞?~zEO"(z'EgM-u8o&$t$]fˊYc26s"X<&ac 8gɽs_fmMov;'ob)My3rq+Q&vOY)Y:rLr! V-#;56}xX$S_Uxiv* kRΛTgIqj s$+X; hl_$F/*N5*m p܄Q2ޭѫYOl;2BNF"-jQWyn,2,JIC@~-Xrn ~IOx^{n$O8uN4s@F dOI}]6bBU~R$zo9uUڃGE;bewB1Hh8s>8B貆ɈHsy21RY%"Oq;F}/Ċy44SPhm>7}`ͣ,z(7tt 1`ȻYC!yzWj$Π MgK] [E:AVך8Ȱw橼uw]ӶҿVdEYd;>"_TrEUJ]w jfҜ ڱTTUiVKZx53؝iyF<"]ܩ<*݋g ޫ{S;5 Q?P7!u.):<5ukncZ 9NV"`-r&q,ʏv'i˿XWo@樻zqlHt|JqWs9gpǜ`W&Iq`m%ݜ+05+0,ftqT~fj-s1YxnE驤Qs *Hsγ$hC[̩ zIq`$<|Lc39(dW겹O'؀O8fhZ6 jG#']5?1&r?9‹Rd<7-;m"DU`>_[ϼJQ3/ E>@VΔw|XAuP_|)*i\6 -pXw_U>:x9J=[4–W!\5q{D vQ+t٣uumAg98qhh(~6H KkuO|1x}q7LtlBAQuc.c!i{̬91EiO/eOwǨ| -@覛X 9z` eƵ q[r/ 87 |eI=9x⛾Em@VAŤ[ (T{R )_%1І($s=n:m(cja񚕛۬0W,4]'<wU  J a$VFR=f5y%Z|l; `ܮ"E>,%[s'su. [:E1Y)?!.:,4@Hmjjv ;+=*̻/ڡV5N}~80zhqzwW.\,Ī ͘ p"[CgKs㣍hqLd`] XdYCFuFW_'zRSխ$xb='h$uQ8; !wӵߏmeR//h JxLd^`̾`EUC]XZ^7}}8Pt5K*$CBEᒁ}͠I2E2&=Es&qJjlT,_ːhY8K3uS}fCMZ6zOk$?I7p^A5Nbl gJ4y4U_DKlY=,_d=& ըs_C-:|vqWZ[*#z7;ϽX60ͰFҖpJY> ;hY,\= zZes'wîm^׾ŗ()k.{P)?>D&❞N!Eֻ%O=wPMj%"'EQhQ$+yI]r3 ߀F N7DzФZqUMEPpgv]yyˉ~?U {'>=?R )ի -^lwQx*c9| endstream endobj 1533 0 obj << /Length1 2611 /Length2 11602 /Length3 0 /Length 13095 /Filter /FlateDecode >> stream xڍT 04H Ht 13tKt !!R"Rx][}k ϳa撲`P'.^n(@FUGG>pu Nvĸ̺`8a 2YN(9xxEyD@(?C\ rXTJ0(,spCnf8@ U5dІCN`vrrquu#ap+qvN+F.` j {ߙq2t!0K'W @ `(yjڊ*u0oc 8/?A@Pw ` Tܜ8 oC<rA@fH"4 d0Cy~ j!C㓅ȲY[(@-,'a qt+cɬN (;nE% w/ ퟅa׃ 9`בSmo@rvvA; \ Ur5T"- WB.2Br7q_v(Xi\@!y KF.=>,~o qx"\x0'2;o% ߢ G xd0Gx; C|aCOGg"+x w~ۀ](| 1]{c"qrq|7H@D? 2`?6 IDzu"[q3 ;ܑpdOzĐ_?S`79iMy`g)jWC|]Gz)]5e~|Uub-6_m>d+5Bl;m3ߚrK~V8;9My1ڒb{;xhC(6I7HIO4+2!$vmJX-D,Rom;(ol R)ƙW۞S\ư7f3C hġXыPn$a*v%}g"i>ϒCO'`W6ׄx0G!ZgQQ<չ#% 2v#Okqvsr+v2ݫ8BE+#PVs1K*f\ʌ5И#鮐SZDhBM9ڥA)eDNvo,4Tå6)[3|9S:#.ps4Q?{0KKa'Qn @jd8nј&htRXs$'L4PY %Χ 2A_[эaZt*4Nkl}Z-g['=Sx=) ~46_ª`fgl?1:}>F`mshϙk*ly>-jJ'(Ib^5VyckeJGz $,W8րjseE8@D_A,`mfokq6BHT_𞳄cvSO1{a|`]Պ|`z*z".=Dן#~  ~!c݄·A{]hrTl}A,mLlrvnₚL{E;%*Ak馽ǯ_d^^=S$.ôYK@f4O&+yĆS+v^-difS3&U%k&'Gc|w((\Qh$J'' I-scKC45!ΐbD+xi~צy7ׄO-)&_p&}WnּĮ4ApHİ1** We;v5đ>8PId u`ulPsv UGWͷY!dk]CT1_Bg+qlM N1Y~ɛuI9O| ]|G?)QS%D$\=r㱺eڜ&Ǒ6鰼B$B7Bkt 9\{92fl9`F!M :kcE&1Mgpr㷃zd]T`hqy~ΰY˽O/t6.;5kٴ$L5T/t , 2FcIf&d켙T>ϭF1@#¹ ;F3>wLTڤtZb9\[dލT8SphVq!S^@W#>ta /~~}H0H 9E.U GܫbfUɾySXjԮ G?Дۮ|nD^ciVbư7{g{[4]OyU[P^|KB<-KIґ}OHچ!o>mdIkIobd{DLy P?dzf0+ B,DM^JUcTLcN-m2ƶȥM8G{'Q#19O[6i.g+#;? Yh=L=q4 3X +e%{yټ~ѼߥBqlg!ް]oTn檽Zy9}%T@O6FD\B!]E+F<2o?Ěz3 L))V(vXY#i|^$V=?h4Ӽ6jrMMs=bjL[?)Y̙L3x=Ϳ:0iUmC*wԳFdȜcŋFt?ѩ~R_v^myZ *gQ r{Չ=GK0%%8=yh0)~Bq!^C?bĸco֓u7{Jr[& \!vsɬ1վVBz,~cmT^%=F4<n"~{\b@1w77=]KGJh^$`̓ᤣgO$cG|Ћ7 EgA ލ]ASu,ॕ֚maq! CmO^kjr'&R>Z a\ )z)ao^$BEȰ tQih(GvnJQEΤzq=Ulw  s?4"}HsGI̠<&hGF=J&чl QYzhbښIw˴2B(U厲BWzc"scoCY9-"nk'+cPnC5 D|OyhfO[6hZ]GAvXA\*sG~~xV"/%RIT6fp7W> yu+6vGh5YVMq3S-JP%' eZT OM]`'v/ׄkyU''SAs U<|WqѤ[Y81ܠO!# ,/^Ф\̵K]vuL֑OnvSsĖ.΀ٜ>%aISsESl/oAh؈z 8#J·1,>U:TlQoGhu'Ʀ&j>C; Pg yK3[M~icq9.'QVԌkQm1>úm4jBOk`^MizN£_FFyiT_|ǚwwSS𕴁Z\j16/hIZT5yީkv}?v}o7@s>޼=Z wxDi;MWwy~O_Zo("qqxY3'NjIoTۆ-8ʋ$vlçB>f) _. 9a`NY!&=+_".̟GnXSNVXH#9ɇo)]Gp#(a;d4IO 1OČ)TBW\5Z r nn_2p T#򝭇eq/3Y\ؖG|`>x[T[{N: &}CJIAqӕ'!|^K2r$ bwT$ ?T96)Yhq:)@c=I*Vآ^aZw1)7`qœfpVx(ي2"\7STNꑾDg|0hG-ބ)Y9,d>*"Wo.xi~1C ,Y(&+1t=轏q: l>~+\/M1Mnޢ ̴ 0?p#4( ȫ ,}?s0T-WE3Ħt̓wֹ4wLf mo2i!h0|}OĘ~n7UKf|"e*N5X?Sb3&}JY\:-Mb*ϕZބ}1Hp:Cvyv&{ɇCdގl6͙vp:}{7K #GFCs\Q/2.CogȥE`>Pmy,۟-#^/^L`g@q e한f/= ʻ<3܎H2L: ZR>rDOذp .>$,ll_Rf8@z籓 I!꩛1&r ]w6\\ {m|6VnFjܴ7otBM!u>]Y ;aiN|M3'h1R#/br_vV^cV& 8;<;]sRGW 1L+v)IDF7ޜ-㷥*Ԏ/jn7m4ek&5W KMGDuCW=6st*b]~/ Kn]7|{Ah#NɐS/#:^|Aշ◝?E Vt q'&Qմ{W!{#: xo^|䊢z\M0|^pCPYZFYbsFƚP,{vIsBYp_ mK2w+I=Q/53PE]QD&iSv~Z*0>U(y,'6P LA93i/']LQ~񜞱&O$21#e{Xݤ)$Wy\Q?tdj]80L'iԃ» v ƺoY}rL!3<3$e~dhx+MGEG=Y"40Hʶ=&y~jQ2hLȖE/ +\rwmέۛU`_J>ru|u,m1n|'\q;U۝2,1ƍ0]f d$i=}+m;S̠\,ad7b[syQI7?ɷfjt .wo|f;,F8' OC#O7=5o2;MRG/&?y1T/r z*U߼j?T%6ZeI[*ޛA| }R_ Cξ3}Y1JMWekF=- Yn5ht#RaE!"㾨Vs_^k0Wsỉ A?'iqoQ (8܌˲ꞓꥪTyJMg}0AUL+spw8H[M'*(oǛnnc RXQ0pe&Jp d^gNT-A~@AbcU&1hD@Qx5"#9ia%rgow^3 ~Mb5<5旂z3랾uULD1CJAp9Ddo/A;!J?wHќϕh8Ux#Ul\a)tV}3;sؼkxeu2ea rC"{}hp)Gw͎";%v> -{]Xk'ݎAV/LaAg9b+77X1|$ _ 8&g'u3{+ETmtƷMg379`<~3C RJ;zma8 f>k 4s7%=mL5cLG \ɥt ODzLY.%8 1 O}^lߑiA5bE3.|k~٘MFGj¸iɦdl( JuKUY:zi<7E{-V`1ⱙOu"?n9':ۯ+;{vG aZMh`$6xThXzVs ںwZTMiws`Q!T3K˸8VpyrE \\dY{2=֥͗1KTigMNnġMHeM<?8Wӯ }90lԃXT6:ZYd,?| eM3PwLXN~mH-nEQMR#4ↀbj+9)RwJC桾R㼷q: ^嵔E՛v#ٝz*AFNA/`? n[Ń41ȏqV\T>"W$i3+ԉUx[۽{c~SwgK?wΈtsn쨡Ϣw mͥC16{!u, CD{rP'4N= uD/w u<)l-*$%x{ws9q.I1-1 ^ˇr6t..ў]v"fHQ!4Ƈ8 IR\+x"LHfSx^}-Zg(Z+SN}6ոcW1JqanNPCR pM꧊gWlXqX_-`_<\+fkQѝԥt/Jb:6S_KFj:Kٮ= cK=ke?+mUŹx4SڢbR+E qy5`CfaC#$F&|O-G.C'@YidHVP#wu-/P+{" !c\Re_lqҀ 8$<KGi)JȊ}jR*\cq߿UdY輘Q_;W:}fKlUܵKi;xXi4t0 s uͳ[nStS,%.u[)gM ן^L)П#~&r|ZU(mj쩝]wxCi:h)ӞbW wjgweBtmi*?5کme!5I&{fJ"˷i .W$g̭& URnJt9< xqK7#{OtKk y&wmw;D'etui?}?lxa$ei-_,K; JΫBclAX՚4jlhɷ{Ab pGE,m;x#IR L1V4~׎^4W:?YƠmz;7?X"C)3 O"Nz)_gekNV"p?0=G:Qrځ:H3OpM{@3)09'eilUH\I԰}IjnߺoQcMf 7k붲k1 (%ЬJOW_ײo7lnjz#Jٿ6"ecZ/RdծQBd/[WrT{ГKPPǹۣBiq- ģ9ZMƾYq~Iw 4ypkm_S%x|NKL}nY8t] 9ȼXHqJ(ȸ`WQ#rFSK/0GQU_3FmpLRQMT T 0ѫ7[WdE endstream endobj 1535 0 obj << /Length1 1335 /Length2 6500 /Length3 0 /Length 7416 /Filter /FlateDecode >> stream xڍvTk-H)Ioґ.  DBIUi"E.A&R7]EzUG=9]ޕ޼̞gYЇآa($VHLXT@¢nn#8 61pR0(ʦ¡ WHL$vKNLZNT$.** -RmA`a PΞhV+φ$&++-;CmHu9]U"@ W >,YND]FAp`_AN?̄ #8úC0Е!1WH[tU9Ðz;_ѿ66('g(00+"m *#W74U @+ؠX0EQW.k mPNN0$u?u8fsvO?uDܑH[_$l]EpW_+= \@0_ hK!d2vPSiy&}9kx})Sc&Y\[-9CK~o[ wm u"hZ:# l5) xN[u~ʩ$5,?x25/xZC'.&_T whkLk?}mho(C`ж&q"C#?shIӅZb?A->G[_x _RR:c,Mn\0}p!l)YԠ6һh.Vֆݳ-*!ђG&:KD%9̈ [t$M#$7@wH#9)HF,Nn #|g2B!o5,v7 `P;<rAA'uʥPYeS*`g6^΅HVdV15 C 0PC ($)V2mYt:V 29T,m%Gb8xD$RH[LIJ/U>l*']mnfzPBJ昃1~[?*˯ŀbY_xi Hօ+_hH)<ܶZoS(VT{+=T-6Hkg6SXHN?68HDZc3{aPg itj\fO*֋w2HTmu g/>5܍uV=OFQ^y;=p-  0Of5Ӱ4ݏ`;\qFOڥRo!JC_ۿLh<{8Y]jy.uioN#chƩc. 5R=v;\Doqmh'U}M엡׹/@fJ6m6;HbKS[>Yb_> UjX{vyc{eV^:laP,:wnD*So-kȒM"N㧣jRSgt s",JUz>u /: #R>D 3S1LF8!P (.*Bڳ{&(OeIvp+dtXʻ*qx?R\}ZU[ѬNC6b[ꋑZ\!W4ʍ8ik8ʹ/F>AP`3\m;iMޛZuDZ#kYL/vlfYWC O}" '* |;c=rY&CY6+ Ti,IZE-j{'2QqJt%I<*X.^ WҔ- "cFm;U˔[Ro*Cg >fRג$ ;>UIV] fފjQfγdFԳ镝~7p ӦM͓$Yc8ƻ0)dULo倄~(fGif"_Yܩ3uyޠ}v.I_c:O%YbxP$}"0lbu>eA& & }!ܸMtUx:j Tn J=$ZNPQW9p&)Yϝs#mlD):Bp,skM.0|@1( 0 \ivD-16usbA ?f-5$>~Y.=!dѮн'8՚z0'5]<=)i$<7=cLaY$Ϝc#I0S oqP-Mk{|a MB8&SA.|>߀+löޑ+WPL`| ;mWfH2=i~-X‡1z-y%#]ƪ}UG0{$J %kO^H,*7TxFNEݏ}$oj6#bJO$*/C() %`AQpn$~m/_t(Csg629Azbl NX](X4px4$T]ڠ %K8l B|} xn斻岔U ?}s7;j)< 6ijT5wnItۮnz 3;3D61G>eo2{aNw7TqxX (3sκ.(TTr dϏXs2 Ej&/P3TId/TUz3j-V7l\5oĊIe.e+ nfZOشd5`d/>8Žn1x{.YAYlovzNrZ;=Rp^ù_9RpRt.=#xG#|9+<+ )y9/^fֳHut2 DZn?>Kb5R R:lNf!f\aE(dޡ'\6(jG*y'ܨlЏDW`#'Xd~_f"=T٩y]"4&$cܪf} s;s֜I6"ZLI/ Zl<^ 2/槪$v]ndTfNUNVW{ZC OmK]s ZXkvziu}w/e"uOVLhb͡W- 7d {uo }lΟbem*G;WHjnc0mDk cڤԽGRBΚʼ zXL5jzg48d=F'̕9`*TFP3ؐ[k jba\\R EW\xU"+Yrƫa۶0Q^Wx gO[՛;*14P'6gqlD@gcfT"Mc|oD莙)s--~o!SfS QN@nԚB5ŰZ`YL՞3|Q:BnʡVVekV5],ېK<5w|ۏ%YkaӾkG| LktkoΤCDnPu~Gشg$a>&IR(Wۯ_7_yX&!Yji#HU/ /d;$Ns9T;4Az';M~13d̥3ǖPhf fuw$z? `w7ELXNwE|K&:x;{^;foPlvnV)U=u 'ɈM}ku\v@sSm M|Ŋ9y8fKXL#(̜/`ToZٗ THkSUM"R8Et:Fq&젂 K\^7߉Ƀ`x& UŲnVi/?,5X`xU-ÜGU~賰:dZ<êY ET^q'qECub^uFf5KVsIƌ;=s&OAZ'fU]6InI/w1vtEO.*' ߫2^*h=%& $F-0{DtEV[ 6ݞ#,UkxmL;Lo2Ų䵸stDSL.l8^Qkьkp;c.7ʜa(ȁ?ghL_Uau]Gp~pH1\ XoyWPF),q_?]q9}I8iQM4Vi{$壃3WZl[@?W/{V28BJ=bb &U@T G-?gu"|;S;;8P6[`jUupa&}GBu U$*u%aA5HNU0Fņ#cVTj`Mux!%O'R~Ar9Coߕ$\ef?`g'S$[ΖSe/}ΔW1! _@x`a7Ze{ Rn݆7p>ʥR' B]/7&\QlT-Z(g|SC $4g{i,'s=uS+/Yu8{T:3h]9mN{ Eq/;M;'y@{.~jYL ҂ E"l"oe)dJ endstream endobj 1455 0 obj << /Type /ObjStm /N 100 /First 990 /Length 3390 /Filter /FlateDecode >> stream xksG| bRG a E!KB+ȯ]i%Y Y 9W٣ٙ~wOj%L0idRS!ìXBDhg*!Ji,\jsZg VA{&=-)Lɀ$l`J j#SHP l@IV)3LKXeZycHᙶv] ̑,r%ـ+fu  3 9!=. rA[!poPjF9CжH-Xf=iai8Pk!0'L@``(9/Q|dh1^)c^9*z捠uyK^C|9$ia,xFDɂ/O*܇P$H4@, օ&ÏapɁ,xB }tp ѵаBY\+<"-~Z B(яk5b@_AbԞ|%"S0$TrP P"bD2*sh&X4; =^^N3 E#;pyI" ?Cz%΃;`|wxkr>7u)fq'|4v=f*L>D`Laa.{'OO݋|~en(29q9Z[e8qe\H)#!NɉeNЎ5'T;;eTDKy8O+NT ڭ4L2~R|y+12,@F>blp~Y}D>xDŽ^ST"TV@XNԀUL 11111:2䡌4^P[d҅+ mQ(3Qtߧ:MAwKs܌8T'fk-ׅNi_3EN=* /'N&fdrD0Vafx˜u2w]'su2N:u2VN~N&ԝC;PwIBݓ' uO$=I{Xc5Xc5Xc5Xcf|\50r(&G59?R&0Mkrܼɹml䘻&7ornߢ1wM]s6!-Sd SCJ &2DS:HϏx/ϻߙǃQ6]ˢ7mh&4Bn+l[ǻ7'y?EU}hDΛ^Ȇk^,[ >fҨ ,J@+~/r/l.}9q{8u4ƺ"_hXww\n?Bۮ] ✝NŇnxp QA#T곀wvQK 6`U0?BWxFý¢YaZ#nZd+"jz ;tJx1SB $ je&R#}Ь"~7/89[FM689ʲoZPdʊVvT#w jn <*#'ҼbC IӚjl`K6ڛ`)0(n b@p2h;'!MaG*YE*PfI4HA4**iS)JAf 5[ OQ<ozīր`i?uɢhXA'L eNw*4|v ZPc'afPS, 4ڄMAAJhZY&דuՊ4V4t0 ܐn?S,f>¾'Ey)T)D }u]M')%!J)=1XIxRN˶l稝W:q K46 JT*b7©pf!yl6L cy;+5UzZzfKqזm ^h?LYEuҧ@1jۯ?%3i}S|_Mb|jX;aPχ9NHKy4{nW L }襫]FK@ru_ |r/p؅Jwj^>xZONX! [;k%Px9J) TerqL|+?̏?-~x-9?wŸW6oz>WW9ΠGD'yo v0Z_~^}xWbTv/|'%C`oޤ`\t{|K^s||9* >8>ws{0*_b4XnĺG/GVhfj+uWcMf}&ydR[ehu=J:Ur>m<#HVI@88TW[4/. `~̳iм/1lړq*¢Ft,H764R\+-um(^~| jUxY m&k͆XG`}^6zh1*fAv]}*UD_mR},V:05pQKGydH{ɳZI?*im ѦAR,,g,u4cU)g@IO}}:g>AyFѓ'OÍB6ƭEnr5͋ʔʚS_m^t!|-.\\uJN^7wF?O>nk-,T<+m ۇ9[( Ն{帘W: bڍp0eA-vsJHWNr|08o\vƗe-;EX@Rͱ6ga]b@-2 t3P-7_o˥ nc,dAlRA ~sE2^nٹz9d@oD Si7_HK|7(dǗK|OiyV=V"NN%ի*uLE8 endstream endobj 1570 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.24)/Producer(pdfTeX-1.40.14)/Keywords() /CreationDate (D:20151013212839-04'00') /ModDate (D:20151013212839-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) kpathsea version 6.1.1) >> endobj 1538 0 obj << /Type /ObjStm /N 52 /First 479 /Length 1949 /Filter /FlateDecode >> stream xڥXɎ7W:L7 @`e41Сl$n3?0SbVXʨ`!B) DS(%p,!`Iv.z#~'[_kHc7k{tV²9)- _Ic6Dkt9ңSۦYIJWW!mB-[-q l;*7𕕣ܸ#7rC&rYNe7ܑ;r' Q4* ӒI?<<??B'śO!97:A<%7A5Mn-L=#<`>D[ۓ^cK_3 t+u-kɏ:CnA:!Q*SksNsN0[}x(O7Ve#|LM YNOC:oFh}kt^'n~C_9=ɪІrO7*Fk>1}6aOB6 mx]}O6˸+:kqU:7Rރilڻ@FRy#qm:ǴM%3+^Y(!l\^}r5lMڔ7`Ssdb`Tf+f!`F*}z6M l¦b{ f#;Gr>++a|8& E3KGb͡p(f#$xxnY>aACml.IZ7qb߾a|ul:^ž| gE 4ӎy{_ݻ|ӣ}et|ƿ ok&?0;ݿOK9_=|͗D1~~^%@,0 BH,2bX٬"V1Ujb55uG1I ))Tr`ђ%K 1)dr̤Q&Ņ^踠ภภภภภภศ踨踨ؕ5iڦ:.).9.).9.).9.).9.).9.+.;.+.;.+.;.+.;.+[>>~! ZaL endstream endobj 1571 0 obj << /Type /XRef /Index [0 1572] /Size 1572 /W [1 3 1] /Root 1569 0 R /Info 1570 0 R /ID [<1E71D2AF6756A76A80C6A228E134DDC7> <1E71D2AF6756A76A80C6A228E134DDC7>] /Length 3447 /Filter /FlateDecode >> stream x%G$A:}|'s3wLOsB,L ed #,[$ObYa@> =X $,oģWUu>uUUjZQ.媪}>t!3e%9jA9 yi*y`ϱաܔ[r[]'eJCy$东rJN9+礌6)\rE5.7 ?T'ނc՝w9xmS{\4yH>R+y-o䭔/XWcv+t)8vȳP}+o佼g77T{YgoCCstuuu&########C'ˮ9kaaaaaaaA;,GЙn{}S"G&<":":":":":b;b;b;b;b;b;b;b;b;b;bf2TZ˔(G$@d\I|.KPgX6uѧL y)䵼N hhhhhhhhfǡ,O,m/ue\!!!!!!!!!!!!!!!!!!!1͜P= QVEhhhhhhhhhhhhhhhhhhhNP=_^?(μ5g ͔ ePeii\#23X4X4X4X4X4X4X4X4X4X4X4Xd/E" B;ʣ5ߔJ#Dd"2LD&"Dd"2LD&"]eȵja0d2  C!Ða0d2  C!ÐaOːX qSlGJG&"Dd"2LD&"Dd"2LD&"ğo]/e0LkKGfQ'|IٵJF%QɨdT2*J./JF%QVISdh7˶}o{leL%e̕y2_BY$XRY&eUZP2Z!GdlMYV&e][^'CrXп){pTn )wJN9+L(\rM M#CG,ݓ2%?GcF%Ș4.3d̒2Gmȶ@6H\#ڑ[?*c, ᣳeiJVY+dlI6*d쐝Kɲo+CujwtCrD19.'䤜rF99/rA4qIjٍ+R M%ܕ{r_8|eDD""HD$"DD""HD$"DD""vDt H{qrc8EMʟ/ H$I$@ H$I$@ H$F$JҞeHJɔ%3Hl$6Fb#Hl$6Fb#Hl$6PO.DD"">8L' dLeL2Sflqa8WKPzw\^oAeiBKTm.RVjY#ke Q6f"[]ja)|^v+dXĝ9*东rJN9+ o='^\rMސܔ[r[]'eJCy$\ UA/ŭkqbF𝸑1/psssss;===}磯osط~,-H8999]7zzzzzzzzzzzz/ːD73v!p/`aaaaaaM|-y,zߛt/Lwo{ݛtwBrw`ge^ awei* > ~ea|VanS/KO3VfIs1GVJY%eu^6F$*v)N%V)~9 K!9b c?s5_ endstream endobj startxref 243755 %%EOF GenomicRanges/inst/doc/GenomicRangesHOWTOs.R0000644000175100017510000005252112607330121021705 0ustar00biocbuildbiocbuild### R code from vignette source 'GenomicRangesHOWTOs.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) .precomputed_results_path <- "precomputed_results" ################################################### ### code chunk number 3: pasillaBamSubset ################################################### library(pasillaBamSubset) untreated1_chr4() untreated3_chr4() ################################################### ### code chunk number 4: pasillaBamSubset_help (eval = FALSE) ################################################### ## ?pasillaBamSubset ################################################### ### code chunk number 5: readGAlignments_1 ################################################### library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads ################################################### ### code chunk number 6: readGAlignments_2 ################################################### library(GenomicAlignments) gal <- readGAlignments(un1) ################################################### ### code chunk number 7: readGAlignments_3 ################################################### 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 ################################################### ### code chunk number 8: readGAlignmentPairs_1 ################################################### library(pasillaBamSubset) un3 <- untreated3_chr4() # paired-end reads ################################################### ### code chunk number 9: readGAlignmentPairs_2 ################################################### un3 <- untreated3_chr4() gapairs <- readGAlignmentPairs(un3) ################################################### ### code chunk number 10: readGAlignmentPairs_3 ################################################### gapairs ################################################### ### code chunk number 11: readGAlignmentsList_1 ################################################### galist <- readGAlignmentsList(BamFile(un3, asMates=TRUE)) ################################################### ### code chunk number 12: readGAlignmentsList_2 ################################################### galist ################################################### ### code chunk number 13: readGAlignmentsList_3 ################################################### non_mates <- galist[unlist(mcols(galist)$mate_status) == "unmated"] table(elementLengths(non_mates)) ################################################### ### code chunk number 14: yieldSize ################################################### library(pasillaBamSubset) un1 <- untreated1_chr4() bf <- BamFile(un1, yieldSize=100000) ################################################### ### code chunk number 15: readGAlignments_by_chunk ################################################### 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 ################################################### ### code chunk number 16: coverage_1 ################################################### library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads library(GenomicAlignments) reads1 <- readGAlignments(un1) cvg1 <- coverage(reads1) cvg1 ################################################### ### code chunk number 17: coverage_2 ################################################### cvg1$chr4 ################################################### ### code chunk number 18: coverage_3 ################################################### mean(cvg1$chr4) max(cvg1$chr4) ################################################### ### code chunk number 19: peaks_1 ################################################### chr4_peaks <- slice(cvg1$chr4, lower=500) chr4_peaks length(chr4_peaks) # nb of peaks ################################################### ### code chunk number 20: peaks_2 ################################################### sum(chr4_peaks) ################################################### ### code chunk number 21: makeTxDbFromUCSC_1 (eval = FALSE) ################################################### ## library(GenomicFeatures) ## ### Internet connection required! Can take several minutes... ## txdb <- makeTxDbFromUCSC(genome="sacCer2", tablename="ensGene") ################################################### ### code chunk number 22: TxDb.Hsapiens.UCSC.hg19.knownGene_1 ################################################### library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene txdb ################################################### ### code chunk number 23: TxDb.Hsapiens.UCSC.hg19.knownGene_2 ################################################### transcripts(txdb) ################################################### ### code chunk number 24: makeTxDbFromBiomart_1 (eval = FALSE) ################################################### ## library(GenomicFeatures) ## ### Internet connection required! Can take several minutes... ## txdb <- makeTxDbFromBiomart(biomart="ensembl", ## dataset="hsapiens_gene_ensembl") ################################################### ### code chunk number 25: TxDb.Athaliana.BioMart.plantsmart22_1 ################################################### library(TxDb.Athaliana.BioMart.plantsmart22) txdb <- TxDb.Athaliana.BioMart.plantsmart22 txdb ################################################### ### code chunk number 26: TxDb.Athaliana.BioMart.plantsmart22_2 ################################################### exons(txdb) ################################################### ### code chunk number 27: makeTxDbFromGFF_1 ################################################### library(GenomicFeatures) gff_file <- system.file("extdata", "GFF3_files", "a.gff3", package="GenomicFeatures") txdb <- makeTxDbFromGFF(gff_file, format="gff3") txdb ################################################### ### code chunk number 28: makeTxDbFromGFF_2 ################################################### exonsBy(txdb, by="gene") ################################################### ### code chunk number 29: hub_1 ################################################### library(AnnotationHub) ### Internet connection required! hub <- AnnotationHub() hub <- subset(hub, hub$species=='Drosophila melanogaster') ################################################### ### code chunk number 30: hub_2 ################################################### length(hub) head(names(hub)) head(hub$title, n=10) ## then look at a specific slice of the hub object. hub[7] ################################################### ### code chunk number 31: hub_3 ################################################### gr <- hub[[names(hub)[7]]] summary(gr) ################################################### ### code chunk number 32: hub_4 ################################################### metadata(gr) ################################################### ### code chunk number 33: hub_5 ################################################### txbygn <- split(gr, gr$name) ################################################### ### code chunk number 34: count_1 ################################################### library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads ################################################### ### code chunk number 35: count_2 ################################################### library(TxDb.Dmelanogaster.UCSC.dm3.ensGene) exbygene <- exonsBy(TxDb.Dmelanogaster.UCSC.dm3.ensGene, "gene") ################################################### ### code chunk number 36: count_3 ################################################### library(GenomicAlignments) se <- summarizeOverlaps(exbygene, un1, mode="IntersectionNotEmpty") ################################################### ### code chunk number 37: count_4 ################################################### class(se) head(table(assays(se)$counts)) ################################################### ### code chunk number 38: count_5 ################################################### identical(length(exbygene), length(assays(se)$counts)) ################################################### ### code chunk number 39: count_6 ################################################### rowRanges(se) ################################################### ### code chunk number 40: count_table ################################################### library(DESeq) deseq <- newCountDataSet(assays(se)$counts, rownames(colData(se))) library(edgeR) edger <- DGEList(assays(se)$counts, group=rownames(colData(se))) ################################################### ### code chunk number 41: summarizeJunctions_1 ################################################### library(pasillaBamSubset) un1 <- untreated1_chr4() # single-end reads library(GenomicAlignments) reads1 <- readGAlignments(un1) reads1 ################################################### ### code chunk number 42: summarizeJunctions_2 ################################################### junc_summary <- summarizeJunctions(reads1) junc_summary ################################################### ### code chunk number 43: trak_1 ################################################### trak2 <- "66008" ################################################### ### code chunk number 44: trak_2 ################################################### library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene ################################################### ### code chunk number 45: trak_3 ################################################### library(GenomicFeatures) trak2_txs <- transcriptsBy(txdb, by="gene")[[trak2]] trak2_txs ################################################### ### code chunk number 46: trak_4 ################################################### trak2_tx_names <- mcols(trak2_txs)$tx_name trak2_tx_names ################################################### ### code chunk number 47: trak_5 ################################################### trak2_exbytx <- exonsBy(txdb, "tx", use.names=TRUE)[trak2_tx_names] elementLengths(trak2_exbytx) ################################################### ### code chunk number 48: trak_7 ################################################### trak2_inbytx <- intronsByTranscript(txdb, use.names=TRUE)[trak2_tx_names] elementLengths(trak2_inbytx) ################################################### ### code chunk number 49: trak_8 ################################################### library(BSgenome.Hsapiens.UCSC.hg19) ################################################### ### code chunk number 50: trak_9 ################################################### trak2_ex_seqs <- getSeq(Hsapiens, trak2_exbytx) trak2_ex_seqs trak2_ex_seqs[["uc002uyb.4"]] trak2_ex_seqs[["uc002uyc.2"]] ################################################### ### code chunk number 51: trak_10 ################################################### trak2_in_seqs <- getSeq(Hsapiens, trak2_inbytx) trak2_in_seqs trak2_in_seqs[["uc002uyb.4"]] trak2_in_seqs[["uc002uyc.2"]] ################################################### ### code chunk number 52: cancer_1 ################################################### library(KEGG.db) pathways <- toTable(KEGGPATHNAME2ID) pathways[grepl("cancer", pathways$path_name, fixed=TRUE),] ################################################### ### code chunk number 53: cancer_2 ################################################### library(KEGGgraph) dest <- tempfile() retrieveKGML("05200", "hsa", dest, "internal") ################################################### ### code chunk number 54: cancer_3 ################################################### crids <- as.character(parseKGML2DataFrame(dest)[,1]) crgenes <- unique(translateKEGGID2GeneID(crids)) head(crgenes) ################################################### ### code chunk number 55: cancer_4 ################################################### library(TxDb.Hsapiens.UCSC.hg19.knownGene) txdb <- TxDb.Hsapiens.UCSC.hg19.knownGene ################################################### ### code chunk number 56: cancer_5 ################################################### txbygene <- transcriptsBy(txdb, "gene")[crgenes] ## subset on colorectal genes map <- relist(unlist(txbygene, use.names=FALSE)$tx_id, txbygene) map ################################################### ### code chunk number 57: cancer_6 ################################################### cds <- cdsBy(txdb, "tx") threeUTR <- threeUTRsByTranscript(txdb) fiveUTR <- fiveUTRsByTranscript(txdb) ################################################### ### code chunk number 58: cancer_7 ################################################### txid <- unlist(map, use.names=FALSE) cds <- cds[names(cds) %in% txid] threeUTR <- threeUTR[names(threeUTR) %in% txid] fiveUTR <- fiveUTR[names(fiveUTR) %in% txid] ################################################### ### code chunk number 59: cancer_8 ################################################### length(txid) ## all possible transcripts length(cds) length(threeUTR) length(fiveUTR) ################################################### ### code chunk number 60: cancer_9 ################################################### cds ################################################### ### code chunk number 61: cancer_10 ################################################### library(BSgenome.Hsapiens.UCSC.hg19) genome <- BSgenome.Hsapiens.UCSC.hg19 ################################################### ### code chunk number 62: cancer_11 ################################################### threeUTR_seqs <- extractTranscriptSeqs(genome, threeUTR) fiveUTR_seqs <- extractTranscriptSeqs(genome, fiveUTR) cds_seqs <- extractTranscriptSeqs(genome, cds) ################################################### ### code chunk number 63: cancer_12 ################################################### cds_seqs ################################################### ### code chunk number 64: cancer_13 ################################################### 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)))) ################################################### ### code chunk number 65: cancer_14 ################################################### length(map) table(elementLengths(map)) ################################################### ### code chunk number 66: cancer_15 ################################################### table(elementLengths(lstc)) table(elementLengths(lst3)) names(lst3)[elementLengths(lst3) == 0L] ## genes with no 3' UTR data table(elementLengths(lst5)) names(lst5)[elementLengths(lst5) == 0L] ## genes with no 5' UTR data ################################################### ### code chunk number 67: cseq_1 ################################################### 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) ################################################### ### code chunk number 68: cseq_2 ################################################### 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") ################################################### ### code chunk number 69: cseq_3 ################################################### 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)) ################################################### ### code chunk number 70: cseq_4 ################################################### 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 <- elementLengths(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 }) ################################################### ### code chunk number 71: cseq_5 ################################################### gr <- do.call(c, gr_by_chrom) seqinfo(gr) <- seqinfo(gal) ################################################### ### code chunk number 72: cseq_6 ################################################### gr[1:6] ################################################### ### code chunk number 73: cseq_7 ################################################### qseq_on_ref qual_on_ref ################################################### ### code chunk number 74: cseq_8 ################################################### mcols(gr)$qseq_on_ref[[6]] ################################################### ### code chunk number 75: cseq_9 ################################################### mcols(gr)$qual_on_ref[[6]] ################################################### ### code chunk number 76: cseq_10 ################################################### 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) ################################################### ### code chunk number 77: cseq_11 ################################################### qseq_on_ref_id ################################################### ### code chunk number 78: cseq_12 ################################################### qseq_on_ref_id2 <- endoapply(qseq_on_ref_id, function(ids) ids[countMatches(ids, ids) >= 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), elementLengths(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.Rnw0000644000175100017510000011344512607330121022255 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{GenomicRanges HOWTOs} %\VignetteDepends{GenomicRanges, Rsamtools, GenomicAlignments, pasillaBamSubset, TxDb.Dmelanogaster.UCSC.dm3.ensGene, TxDb.Athaliana.BioMart.plantsmart22, AnnotationHub, DESeq, 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(elementLengths(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) un1 <- untreated1_chr4() # single-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, un1, 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{DESeq} 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: <>= library(DESeq) deseq <- newCountDataSet(assays(se)$counts, rownames(colData(se))) 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] elementLengths(trak2_exbytx) @ ... and the intron regions: <>= trak2_inbytx <- intronsByTranscript(txdb, use.names=TRUE)[trak2_tx_names] elementLengths(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(elementLengths(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(elementLengths(lstc)) table(elementLengths(lst3)) names(lst3)[elementLengths(lst3) == 0L] ## genes with no 3' UTR data table(elementLengths(lst5)) names(lst5)[elementLengths(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 <- elementLengths(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), elementLengths(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.pdf0000644000175100017510000057273712607330121022275 0ustar00biocbuildbiocbuild%PDF-1.5 % 154 0 obj << /Length 2340 /Filter /FlateDecode >> stream x[[s6~[ōݧ:df7N,MѲZItD:{@-'譝>H@9`c7dcaĢ4$fI-NO~:ǓPHyY8B)R|O&/᳂Ow4^=ywONJr.Tdp|j"wv. (%H`iRi鎇" _?4DzHT%NnzAQ&@Mq6$PR/DK矺qy_^U )MY>ь"O߄l q)Œ`g8USvy܋0ΤEz;MKxWGzp, czbg@_"ۉ(rfHO,b ĶYҒ$fNLQ\F6讛\4M&4/ ƀ3!H0k& $Q]+1#UD'RҲT_ӛ@1@^YDm7~#Oaޓ`6k6r fv 4Vĭvs95/k#ij˕QN5iK+; xZ2 ai&t7F"oq~SI*"5{u't2UֺWpC3h ʍJZ[OtfW[1Mzz( PNURﲧM/( ߊ4qT'jwAd - ,V9JC&6ofݖ%,hXX֔C[vkpSkvE'݀9p8(޾Χژ&_L<m있_'OHѐ05Z , Z:g٩(;-[qmV[n۴N4˒jzLl;9X:l؁6J6ӹI66aRWV=/: #PY}-LU1ʬKD`eFeN#*=kn[h_Lm)).o#S˰ 1U)OsؖJK$j:.R#{a^t %-3r(q}{,;U&Giڒ6 Z[068m}R57/]_Ȃ4 F׶aȗ 8MÖG` 15{f7p 6~ ܭ4֭lfJ=IA7rt·pL$}/m`ߘܯ S% n:{9jE w YpHX'm -aylG>3HD#]qѮ6*4?=q:Ұ2xy*9<+k[lM8`H毗Ľ$3Y ;x,wrvy<R;YouF~Z_Ӳ(5ʞ?h3 ,-'h|AYw, P2=ߔ" vF6U76s^i"FWS[lLl1p?1&<{bDugc X^B{tIrR endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 812 /Length 2451 /Filter /FlateDecode >> stream xZnH}W&C c;vf^KKmT.{E)N|wV.EyԩfdHdI; %P?I+O2 %DJRʐ+Hd m,C9n,(Gj &)=c ^"%4@`E!H :( 㙩!+:1 /xZXC!@Rh@d%# _5,pzb8s@eAxBR^QLbLj "tA$ŏz|"HDrB-[;ZLބKdVC2],|ץ"4?EGpxQ@%BMpaI2XSx*8Gzoɘ$ TpgD 9΁Ã@PbAt%x]ß`ۅv\8la !?oXCD7E  ";i&_P~\6g]USg9䙠o2}~jLЫe{tkU͚r~ \#Hz6٬~8m~ق .{}`.77iMׁw* |pk}^6ow~5麣YPIG?u5[P]۲j5 mi@%]U7 H#wwEI|ަ& sU5`7%=ub1Pxߢ|P7\tNIտ&H+ ;ɏ"g(-zN5˖˹t8ʣ)p" N$0e[@vC~F}(x"~cXN} ;ޤJrjІU+C+V Z3'<5O xjSԀ<5Oxz<=Oxz3]vn(D/e~reg"q* 2!?oG}ؓ˫_}~xpS3{oWUi{fM{ߖybꑿt3vب`3لYAJ.ftr{!x 3)>J4)v6~/l x+2لGٌ+?8J W~|uRc--2NZ_lbt/GBP*2,){YS@(U@GˬW#eQ7tBwDeEe]Q\uCI)}.,2@QI"O옓'',d]Sr.ƣeyt*B1ZD(P*Of`H2{ȨLjJICp$2{$"?p$ܗF̕c9'dȔr)K'-hJ)/ {]Ƅ^ UepOƖ^Mw5@ w}XYS ?2D"`mBZ/ =8ۙ}#&h~۪فi/k dE+}war-6FP}Yq8njcR؂o-{lOE'rT/R5.b2X>dUߓS>Qq ,Ư/$.B.%`}OVGBL/"J'_O endstream endobj 179 0 obj << /Length 3286 /Filter /FlateDecode >> stream xZYs~ׯ`)/P9\7Neg[)R$g؆Y, 0*YhqBzU/DU2ZQc.|QOڣMxVIɪT3 Z JqT~0AĐvI=Dw5mE-wطylY`ϳd~Ff\jMdKGnD3wņw=-O1*8檛zq;A+T^zdG(Lu;FgcEkv;/>32K0Iԟ{sZpʩ-kabo-Fȅ뻳๪\u򽬏vTY"{l*p̙*6z-Ǹ ^3׏_93Ux12 ‚_ Zy~+}|=*u94j2Ӭ*5Ֆ.l ou@;eJv5fg6bk H<0ys!޶Bފ<6N;' ci#_t$lm,@˞  Ɯa_рnj6]RX{/ȧٺ+Yu֟*Ő+]vE`"I pk(iӱ0^)E'֌bg:h2 bm)t$,/GBPP_eVayȪ豮t’"%xsa|@5(_n"d,gRl [#;k{;P'FM 7OJ7lg9ʑZ~%pz;gX O¤@'hYgVw _{pC&}MoDkĦcc>ZepJKR\adKI}jY`ݣRjtHl%'blSm_I?5.UUæV $7왝3p,bޯ߱0*7O~ .f :@dX+?}TdQ˙qKg')Lo1z] 61Oʣp) a^3LBXVB6>b枣*^5nlo~/ W6~Ւ0k>#Hٕ-ĝjFz] \ IuQybgSwv؅L1 r ̸MG,jzDzaf:7ctG)@^G'\`R ri YmaӷgoN\z4]>߶Ey+2p ^I/ۡ.ԙ %m1>}>B&Ζ@$F`qT|@9|CxóNY|C (%|q, yƃ0L!qcZۋe TO:f/(cw!C&:"yşG.0 ^> stream xڽ]۸=¸>MOs %e~ۋh" fлg">~ˉ KU!r2庰.kf65Gb3#(;y= 1,{/mm0@XƹCzGX $ ^&<ĭ;Zg;ǁrδ ڛUg5D5wE|*-@<#BxkXe{&i4qY_e2+@ ?橐׆{s /IbQAP4,8+%?U_= c⍰X֕E6m^ݵvv24vk͢"~In!Hyޭ*e_6-Z ))^@z d^~S:iq";; %vPW'n(vzwIw5=j>*dk1͵̧V؈̽=h#hIB55\҆Rog?&4I>$eF5 sZ{#3q;qK}G Y9ۜ1 kjTxJa`vBѡ1XvC"#?pb.HEcWGQp >$Ub0ޯN1 .$AsgHC{† J.k j. H;\?> )2/8//Ɣ2^.Ƙn҅s‹choy8Og!7?ܻ۪>c.`|߽[jh=_"f1ZZ]X:ns?s,YlkGj S5ם@ǜԆܼ Up̪8!ha>HAmW4MÊV=r$)㣪I[7 ,kpUvkeIGG3."~{ȶSv+iWZl}o@IV6C7D] 4 ҽ+wHJwADjS׭cljLOq}6uO{sczյl xx:i[_&,[%|Aě6u_! RmOh:L@پiR - SIv1I{ebdYe,xV}^{3g,˝I*5h¤[2!̦']3 JqW5ݖ]c~1ڷ-Kio^u :} ٘ppX{R)W8qE.%CE7RәSg`Cʷ0K8cdj}I:QuO?at}A(ްR mW@iq%asMk]bsNѰf h3) wVeu\9֩ a]u#]LQ@}!)lHATOI~k <L>~ATOOA;QvmLmHtN-Y., jby!OwT! P>k=}ˎ=p[jh#;ceBkZ6,>\ckmEߋö j ,[" ;" @tFvZ̋oaWExk)N6۟߳>yn!F9qʞFN :s6pFۘ.ؙqLe4v tp2-5i콷"l lzw5mQ^ [.zm!ѹ҆32)9sZ"=]o(6G= ź2lNc}CZT7ٻ Dj[#}{Gxx#< UݢFqdYŻQLV8\OY}Y_7ޯ}ZIXd?PvD guVc*0b\}?Q8?/{!ܝ#%g9|7?I^9 endstream endobj 202 0 obj << /Length 1802 /Filter /FlateDecode >> stream xZ6 ~Q X=a*+dž^+\K%-~I=89-E(Rɻ<&y,r-Oȋ4Re𑡷/Ξξ}^DgZq BeJ*e2'z/7Yz97#͏4l?p7BTf|e3mDriFS"bJ-2%D UJ'75,-kzZkaʓ6ߙiSni%ִXʵ^nΞt ӄi4a9mH,iV'Է>6i^s|8lLO|۱mXgܘGX7qC"aS(-TU96 Y.^jI: R 5ZR>!m a{9\-!dXPY!E;~Ӡm짂I&@%+e禛oJfY+4sj0`j2y`O% D(Ui2A*P+r kjCU53V΍-> ^{'}ntÈu$Eޑ:ɵ+;eXGW4A&Optp{ \FiO]**0.ZlNB EA¨y]VpF2twѵzsZvN!qnئsͤd繍jn X¯5-"-LU>4FľhNo1duce8cKz73W[Ĕ,t"&!`l`(%`,lE5*(.ٴg-`.]7>̟FQs+W09Yog2wUfBٌ:n ޷ЇFqnwLlx,Cpvzu~wߓ/Azb<45]Noųr)yoIlO?Xj~w``kـwdxob]{WCzXE5 D#9EQ U(Mܷg9ض.gEjV"ӬyH`?Cmj_'Bs_˩_NŗSqS!SOx*͂vK1fa7?~$&!r 'w/Sͅz _2NTFjWy )f˥e7zm3|AVۡf]rs}g AOU^ZTBͭ8ŀ Dm?|սwFU{Zt0ޯ'bx-9C[׆SU?t+zjv> stream xڽXnF}W$R2\.Ej>EAKZTmɥEIww̙CgIE"' 03giewL]]]2#n)F~ZbS;*1OM}"従gsУ) (ot0>V%/GJL\ytVGMqBAmL=il(kޣ`:M6kT[ցZV~\Y"!4;B@ber%̐2-Z[WfdWFtr% ,E:يFvs9`/!-9 #L,3 prչHjD˨4+~i7I`~hFUhr@uYv 9LM$-x=P ҨU{:rI@ .Akr%" F6tO:S5u#tB,Q}mo6RL3;aeSnPʶ2r`iQcʞ(>=ƚyCHM> LlN+y.bh:z߽mMCXyR%Ukʎ >RD?TFɕ[XK%\kꤌSpU|CoHŻ-0mo(AnJ L$htFGت'-㄂>ݻV7R!Xw}4w#f;: *%E{Y"a$~~**3QadJGa<~@1w  -+KnPw鄀=:<{$w- wWgi%hUQe xWܿ>YF endstream endobj 214 0 obj << /Length 1261 /Filter /FlateDecode >> stream xXKoFWmHA jE%ZAq;3;K$ʲV]cofA"*I*ae<j>u3SI,idr%i9E2ڬsS f6:m HSHR=SO6/e_d;^fյ1I@B'AM2 I%DB6c, V'dMeꪜzߪUO lL;Y /RE>Q*9P`cpAѐfslm8=;[z XBA&αayXږ~_;ރ,l$Qlt!.H=|.1| &e7Ϲ>$?I܉'̏@]I+ca](B /"VN8iV҈L0ؤ:1߀v>p:Kh2ߏ>t׶ꨤ{ I Y&Tn%#z%&my*sXJtB0k y̹NjV}K!UM5] D?m\)juv}=!λݕEk؇痽Ugx9D;g@Bmr;f.ZUn^͖WAГV V4ECtRl\mg#ڗË}A/dmp\OK}Eltc,OW}Nҋ%I{:bsko޾~:H {> stream xڵko~ ]ࢶ[((D)HEwvvyIIgvl;goNn%㳺Rj ]3ÛW'/_+9kVs=;)]V̌U-g͂ͻ|o{ +StlUqZy{dw7E.W"Mx?ZBV>Lnl$~o % vLɅ)S2`_ݔ>$>u_Ӧ$E%Ĕ\@iyB5oMb Z2&*0kWkb\!T 䁥''ɨB@fJK$sr3|p X 6>& .s$/)Jq|<f[0SPϣ);޸"怵P2Q`}rPI VT9- :vHuFTgCo(fd- תHo޽8?Js6pϻ%6C=ҏmac&шWdK>e$UjS*)UdiRՀz=$UIJ_Ӭ/ `i)eclCEH~%Ğ.q x;!Uܻ#VGgQc(1Jn|+ܺ;n)Q3+D_A\=* 哨xi uN5yڗ66㵏'g߷"xxmWr$Dг 5!ّHnAVX.Ĉ[.={\'4\mGG_:w.,r@{@sb#?&ZVm2oHBanKK܏t?@q7hXcU[w\>LTp#]7UM*ϥC+t:SD>eps`Mt>%ɸ ƭ<#5:Fa Xd4*֧;Y8Avm>lrTl99\0׭"1Xd89t`,V9G:ڋP=Cj}?0r.ԭ.rML2מʇ44IHa>DD2HE>>=s${AORII,I\lF'*O*?]>"VxГo&WIJa:X ,gB-MG*9Ac .s<6=Xsţ[S EdybrN9XhDX)uVuzQ*]O.˪<3/08lK߄$ endstream endobj 234 0 obj << /Length 2322 /Filter /FlateDecode >> stream xZms6_|% Hzz]3M/ӡ%ZV#YH[, '&]<`ˀx(LrNO`#Mo.&L*R:<D1Ep98l7+;Mtղ1H]kSm7櫾.@3S$AWzNtnKyǤʌo-K-JmŽ^1mYM ]vfpa?SSTzѵ՝HڌJ ZkAUDZoeK\[dt |Vo10XŶ }zq5 .JP V*(CKv&q RynoP ,Mr-PݒDsx3aq, ʍЮ 9q[x2V[˗J&/ 0Ϲl8Ӟߕ.c&,^9:XdּWu)q#]~'ĵ0s욹IVC1:1-Ydfq[k1#\n 7`n$ *0)ߵ{z #I-+t͚VrK[P.(hm440l7LXg ~ju;>s^+ y8U0]P#W[)qTHFYA9:p&sk63޺he`kE]#e*$d?>KӲ&s|| Z3(d١5)2huSS/&UylB!m?mp=T,1gᆄ=C_&'z y ,@1y0L.`Y]7AL3:x;,TOHY9j(;,F=:BKyvk. X OQ6AH1P{a&naUn-;w\۲"] Vtq%t4ˍS <Us>imݾLn6v gflq# Gpn-x]-;)~7LʟLF}0woAA$rx O"w+ d 2ߑmF\А#˂OҡV{[u?<7 *eRm$Fz/yq FGIり En}4zo$(}1⯦`(K#KRi ²LXR}vpI87,fJx X_D`ȒI-aֶ64PK1 OYZK%IK oa Z9>DMٱM ">MZ | 4`Xx;Pxd[2񣟸4.Cms endstream endobj 243 0 obj << /Length 2227 /Filter /FlateDecode >> stream xr6`ۋ<` a;iMf$qd&6C2Xp  _lօ~;V|sЀ7Y8ѴT\ZVZ9ZREZ11)@6zqo vV匴RY_חJQ hYm Z`$#؜$.ߑWi0`w]  ZIM*89U 0@$t-k.E&ʤ0;$dS %ˆb~<C?i# ' OV!|膻BJ8K;kOha-:5vȆ:eiّO hw[k8J#aH5"@"'6!8qڵa8PC V#~cTMO3펰## ݼK \Mdij~qqE$;vjvZz.#$S4 7v8D6GayaMfjFKvA7thSJ=ރݪ`!+WӅ-@L-9C?i@p{AV4o!MD<c3R֮gsGg{PSKhr}vd2dI!$З"&Fhxa(JQ0kVjerc _֕BhSذ_ C(J$ F #NoѾCFU ğ a9&jh)4sE2b'4UFKoYWm` 3CKrYd [娪PyG|2IFuOic\ 2ڂtl2hU()9AF2N}{^!ê =||xUX1UY]?U;d*nLE>YdhT`np?L(x:z?R*= e"M=E,ˬz{sSaaxZx!Ku_y/G(D| D| *H# DEc6):۹Q 溬[r wsHujU:,6o[32/mјDFpn{*YWQiJp0/EiݛV]{Ե+Eˏd׏%W&/4STeNF0k]U|5}`M, 3"e}5l@ًx樵<}t>pա;uĝ )i HBzލޡaMĹ_m̟& ksCҧsrտIU͛;z AŠA7 .n7[t3rfP R\V9)?sB>E1qC1qNL~A>`uKifnt]LtXVb)q5>: bVKz61{q]E >WN"뵨DwQ-},SFjX7TleF?oXS9U1-IN>%F> 'Wth?XpF8?-io?|2U^}$y@he:vX.xTOI'OM>4SҖz~.#Ꮠؤ;y{<3sE]JCP$D_ RZ.\}|7=.!< endstream endobj 251 0 obj << /Length 1982 /Filter /FlateDecode >> stream xY[6~_>d-LKvCL 8 l68]v_]>ٲ#gwN_ [s9NHL)IR RFk51hp&Qgh4RG21I$z;= -TyO7F1ՈA1մK13f1P'||q*Ҩϓx(2;G͑*QU+gQ|JzO7 L/Ь E& z4T  7s?P>$IdƌW$Nj:WШf({:wi,77|NmcB{nfF)}غFH[BZi%xV^Be}~EspW,VJTm-֤h;DkKXqg5/`fu3BcFynx6@ &*c`%:Nx/tLT8X}0Yn:H~soT:)+OOQ;l:j|lߏ ټJj$-d{4v7fI3Y-_ <&;5v5:s(RMRYc^ūSw/FO:(xnݫ~96y\%7We^!alʘP?zh]9ljٜ_q ر&t:jWk?CyP u.^"jάxLxA~;x'K5-8GpcNN̚ tuw ߢ{ׯA LuMe"WtHN !J]7L[)`41U};Ǜ^b]PIk'ҋt!v_z?Ut(\ TQ77+L7ua 1~9xwO3{tx ~^eK%ݯM3*,3Xn'&cNz|`p #w&n{L[݃Lms3t: sĝvuՕU>js 8Om}f Uֱ5*e)Uf_R3.c!<|ejES,?ލfWyyWqdHOUeY25Dߍۢvbi.P& sp=JGZ>b(aR $&mÜQFdxh|s83@LJu0Zuit} LD,3\'_Jw.e9P\.^؋ąFB+Rv:c= } fyHFI0 ml/ mtǐ%8g6me ?mL2jhVSaiVБN|ݾ:@̽zI,|Iu3wИߺ_^*]l<" O-xSNw_;_=ܺ5~([X03눦{1< |c"[ \-TQxDٰ%Ͻs8츙`ʋxjzŃxh}܉Ꝭ{=UBN| u^V:ýHx^RW^ykT?dt/`P endstream endobj 259 0 obj << /Length 1922 /Filter /FlateDecode >> stream xko6{~ŬЫk 4itТi9b{̖؏ߑw(r#=0apr0S\!(Ma ޟT,qп ř Ps|?lChFAHl6`3 ۮH:¶[1;3ƹk8_z*IAO*n9\ڧn/C4-$qCKi:m AJv~%0iЦЮfHm# 2jAsEQ-YVIKզEVYErgYcb#kB`.kYCX,(-%Pjj1o{hՍշ>#uoJ} ό86K+h3B<8.ٴ%!Vh6lvI=g5'yLAڕ+a%q_v `+Ǎ_91fB$'4G^w(E0Nop6uvESǯ PiBI:e(P j iѕ!KmoxE^._sgDԙa"rQv`:83X^hE̋rPjtuҖ"1BOJaDT9Po c5[>ZW3R0=ιZ@2'IfOͲ& H#Е‡3%df7g$*=* uPDe"[ݨ.vXfe3$[&$&+ȮH/](?O 4OULB h< 9P:M`;Ԧz8uB:ZI8BնzVu{p7hrL_zIFLmT!!f5: \Zу ZcmR{Bnqe2n иarJTT}l&U_# ۸kWŘ_ڝeܔtJa;v븸yO9?3 &<8t%}=jz~%_^5^!1gVk2BMDF:B4_1@O>Ǹq=̨h`T/L)Ћ2Z;b_G+ O%QVo'%ne2:VgId8.ssS暞$F{ aI%+R6G2*v'稜E eKc3}?oqr%ϭ ,vJvcđ=Fd᪝*> J&>x;Hd;HЎ[nimమ9H-gk9n.Ev_1ѻC҄ F)5FUN#\2H:G9?>eV_elfߕ%4VƑ) KK'19=VsBk"KGͬX=ƩWޑжF1(x ^;B9D'N:$n;*Ay]jMI)}pKۭ'adZMU6j&-7Kڼ ݾlS7աa+ <3/"zٿBz4N/mgbK$d4ķzWWw endstream endobj 265 0 obj << /Length 1982 /Filter /FlateDecode >> stream xY[o6~ϯIEi6 vc+NV[J-%i8i`dyngeDSCgh>F(s2XTD6'[Rr{\+z%'4}%^MS"e%[ `ѮR}}ﱝlfS5'3l;iW7yv6deIި~.nӱCK7riAcϨМEժƌY>FBP7lMp*WL N噥®Xw=,|f$n=*a}֨HC]*DOyW3i, YoӃNlU%Ki 4= xOҋ [q[ ].\ur,w9!̈%iA }cDTFbLیͼ}8 u}fE/m/iތ\+^6sO(BE,A1Q<rm𡷢P])="qV^ wgʔʊ.wbDQD'3?(&Z3\xpx ɇ)<}ϺfғlLR*=@RJa@k&i k5EnkXwݏ-V jkSt#FJf yrA2~]7(zHe*QdU66O(m+Hܥ#QiI}%*ZgBy8in[/.oJldw$(S;/;]ޕYb6IKtxe t7\pq=iy_g:- ;8wcfi;kyl'<4҄bI3oRT/{Fcm{J,7gR|xg(Fd+ȵc)ƣی;dudчnƛ8 0ݤiTv5T|qd~06_!YG^˯?/Э [ĆblQ [-& 7i`=zbʎ7;}{MȿND51*Q jXBFLh=ƒ%@Jcݭ<&DsvG:"fِ)g^݁HR?5SmԘöjjkk\c$YU*,GN'rT eDOΣEr$#S֘7JۜEYOL2=Sͳ0|6j:-|Z&|544fJMKR,$P0JSr~q endstream endobj 276 0 obj << /Length 2956 /Filter /FlateDecode >> stream xZBH TZ.ENlǁ~p'KY"|%Eɏ~Hsfvf~3CE$<D*<{FY6BO=:$HM:9$J ;TEl1y3}zԛKlZV/g?݋ XJl=ЏNL6'L;{?4sBimm{}[>֪H cJ=Xi[Dh}2:?'6ޞlN[y[]|dZʰ|--7mrO(zw6)$@ |C* (XAY@T5\KvrpwNv.]&H;I:N JjMIVkZs x#W^xEʱ1wCE*A"ᶒo4 >2_+H.u2u<}F[]::nX3fp *F,voqx#pK̬EK Ⴙ8UtGdәW>]vCjO|Zn:_̯~! VXez;tJ,6<^26\fsyGyB jNb>~{DYLo;_Z)b"xh1Fʤ-b^lű Q'A;oydiª>_GFg'\2E/pKl˵ryf4|nK-ka)c6Vo3 x.M糀C~D /ܸI(crr$>c[${c{XQ،"V&#d U0(mfJ ly{0/JS>Xl|sKc1̦2֌@;v6pxLF.{ĕ4QIGiWr)a(!u2#1_{VJy5iG. ΃aEBvnn=-HwL*(/9|ae*ȇ_σ;ӥ 5J&x OXF=G} `*yQu0l)CWg2;?nLdTNF}1m+;KhNM~^Oqm s3ܲҕƐr,L*Nš:Pi K/Ũ0 &2Xy0tԢ*";uq.1ѮHEEсˎa>ĉ/dcGe"*EbZܛrWbX`;sk]k=B btޯ"ő>%HN Sڟn|>A" 0Y $1/$MUۃјQT>>:7$z;X_=`t $.4R2Q_G*5jTW̋714#eyR|1^APu{X  endstream endobj 187 0 obj << /Type /ObjStm /N 100 /First 916 /Length 2288 /Filter /FlateDecode >> stream x[[o7~ׯ / <EYL&hxGJƻ(.3i{>!*9C>{'4CMpL B?v*&mS( -:F2ԐJIAIQ:r1앀 T()%NA8=_r+T?FvQ*@$9#GdЪxPD ">#cMo"2`.0@=$1NJ?ീ%p =Rz Lv]I6L1uə/3F802S^L̸`LZB#h电H{\k`(c\\T6͢op |C0ݨ*W>xi^;:0Pd]kmAC /et@61%AjhN\}AÜB*aZ.k5UFYxhR!TE3Tj994MI&͡LQy5ͫ<fh6Uv:Oӆ_adɼq(*4.z͋x~cLsnדhzӟgӼ4<Û={qO= 3h,>Mg'Pى.]*\sciij췶Z,Eu,|zxteMEʉeQE 32}l1l85Ϳ^?r8GxbǓM\6OۮFav}ռhGj~t Z#H5}#1gol0`p&bq%G[Kb| bN+9iZAm #K|EԪ&RؖL߈9n ɫ VM#u$uQxi__aᬵW" nj?-N nJ6RkM'j$E C#-PFAq3K`pH Q j ;7ҿvpj}Z^YfPZ*ŀ%l@T ~+rdnlڿWk,95^Lh~uuƮ.٤.Fu ʆua0JYz/.tCFyYMQa\^@OMƃ ;}~}iz%Aze B JlBR]-C7A=..>^sÈvz +^HAviɏd0`ʹ AUwMcu_n|N`ΡCV- %PcK(F ;vY dДMFDywC=bJ=H sa7&9a>fN @OB6>|^|#);U(LLcUv=ɱ<9mlW.,`"o}C~Ae>jЩ7/]|\V~ˊ@kYwDKEP!44t*"O s{[#gGgG6Ӵvfvrwd@afd\ίo>̡ m/oȠ mtmؕܒ<24>ԫ$$ļ7iv" ,N)'~8qy~\ l9 ^[w3P<z4hN0hB|rzKWuK;,BDʁ =oV`F"Ֆ"&$*/2VIyĜ۷?^n<$;ݿ$@h wpX3iryiZ+ojzYL2*,E9YknlJ YOEo81mr0M.GpZ\F12,d&#c\mJg X+~施jcpz#A,P' 3Fxp&6'e>=vʽR޴;pߘr}Q* ]>RwkAra_XWlh8i۸֫S+׊0[(aUP%%z^MIg|W?*Vr7 AVky0zjŰO;ysYO:/?&SZ?L;> stream xڵ]o6=B`&R$%Yvm $c+;J-i>(Ѷ$}ŏxw;8ӣ8s%dG:Yj4 KgG/.~~UG& L2QQwbfv6?05.Njߏb&b6G: "z/_v;;%HB(σ0QQfr}25ɶmZ& Xf[K[ߧmKړޓ~(t*zWm'uBD- ,YHy{ zYy{,htW̮,DvmƹJ?F1//3&pv#)E(Sf"LtсEa,qB޵wa<fgW6}ZPE)%P&Q.V5ԉ"4U ~ jT" ݭ~mدg5u}Gϐ}u|hȨ `uc 2K]8]LRVeҽKҼ ]h7dAP+;4hL/9NnpkOH$ire%)Z/܂2!S?\r}i]#BX m.nxꂱ/DF5/2F\I:$M!Ԙ?"ş \M kĦ09D8{ō"T:Ϛݣ$%Vs3zq.ּ\(пټ]~Z)J{?Q^FzuQS6:v뮬)0U 9YS%U=-Tn6v' O)YyCv):۫ QNjWjN{s_~Mg|pږY0SHz2(Qb,yXtL ~h (=@S+U8m,}DIy!|N5ZLsEQQN8,\ڣT(i&"y.sJٶo[\vˆVܽrmZ7ҦE I0mt resؒu0N 'vWiK6Q\q[ȰPV後Ӡ {zƅMY0.= endstream endobj 297 0 obj << /Length 2305 /Filter /FlateDecode >> stream xYs6=Bӗʝ HfI&1D;fD˪eё.DG% 2@%V"ܩ<z6IR7_ K\iy ƳV+;~ph^mNލ h4ĚfЫ'i>/l9thmmރHՃɒ• t^7t&SoBTu]Dq=piFsڡ Hticp􅋙g=x1DLſ#6(kVa#! @E3;*O2E @իQ$`gx v*)KD>=[ esFWQ*@?]A IZ ' >kjJsL S7xL&RsCBa*tDsӐ`X*lA3j0JAGSg@ktRZEBE'PD,aLyNF6twW9O?󖯡9#l?ɭ*B?A>U3od Y4jç!&LM}ҐK*a~x]ײ2 }Z2f.#=cEhz";#Wh} ۍ/̵p.iGEK[o"\7KomtZ|-Y >%pPrN,ʽ,`;`CF%6KJ6MI[x[&cg+% jrmEaE5X^\ .6\pIpO9p%1/ݏS"N? Q0E}'\ OʢUe{MDHiq;x>2I1 NGlA3kott(Z(ZwbpבUy%2wKn.Yp3--R\Ðˀ9v@ղcwPACQ,̅)RѺTr+mD7䰣ЁDB]ȘD:DAf+(y{RF I9/PfR5?j!ѽI!&t%NW ₓO\>YN8G\s )')@͉QNjZ+5|UQ0zAAs^52vYqMLV3n,j8]jE7(glȄ1f%|tX:آ4v0k?KIp?=j59Hsڟl/6,a&`X9eAM@1K },(Uy#u3wAq+Rdh cg*g~Q:CFv!g6WYH&u;4Xyg<.  KAS/]$Kg`{fA[b- ֛e K=l}ͪxK'r0(1E =AC; v# Zj%)j=3q[Y* q'x]-B쓮)7a>ёSY LKH'|@{c[!]_4 l0JvJ_z{S\٩II"NX;/EE1=^`=q.wC蟞c#y|@n|ذ*;~'12|` l_y.kC SAИj&p2\'ZAWKS7\ZL?!ADei`t'iw %+[Ufzu/myu\ 5*|ef(Ț@iG% v >Je+ٽ;I8w_~z/GF3M#)& ?Ry+|ۿ;] p˕pVx6"nc?hCt2C ~> q۶6aqj{l.SE˄GUlZ}9 ^E<}sCV/Jsc{Ţ@$A!T+-7EJ0e^S9g+3}/&1Ӟ7 fmၧył#,m5^}ڏ`ߜa+!REWkjuTNF~j\95KXUz1cX$/)Cϒ@{sL ۱Z)j:pEmNR?TyaBVp;XtG k2g}|sY-^ENeOU#a:z\Nqo]]OjNq1y>wR?љ.\Os}U[Rx)2Ypc3=9vc?0k endstream endobj 306 0 obj << /Length 2230 /Filter /FlateDecode >> stream xZo6_a{pZE}mE (n-M;)b_+Fy<A:`>QE,A$ag0zQTG?ă"((T$ B8 xPN+^. ڋ)Q]9~Uv-EFѓQ6UĢF7ci68ӂ ծ75[N j#û!K϶74zE=ot/v :X[N ҫN \f׾b%!_>aA u]OD,vv-d%F=4$)mlWSvp|*hd ʕn= ] +liPf_`h`V:8HXr#XnWcT Gmi],njַb[2ښfduv ᲭԻ+\ID3xXlݘ+eUKzȂ,,(J4ȋL5o\! V&EnUbPihnYufB]_䝼iOYƧ%Į(}MbX]IV4b$o0xoid"5qʼn Ew@tMw9m0hC9< LQgn~Y͉Ƥr Q[LjHKNEHI-:QU , rM`r$|k'4U<;MXط)?t Žo3v_3nß8Ԩ6_}uKb*ϧ.+Ffmr1aXY`pdI0[.@u8g$ [!R jcDYG>78Oߋ[:H&d\tRZm[-w=6.=FַQ7 'PŴ}8{on~aѵMvy1>{bQx MPz8Tr?*C픲hl'OFw|X> stream xZ[8~_QDB{VL-`f: >9N Kߎ?g;h> FYELQ'Ag?K,mx:{=KQi(IFYAAC/ <[ń$<ĪJ*#Q,gf=|#ָeyfa;IShTt81Of ̱ݖu%3Epk9o׺"'pJ$N!zcŵ%;Z txGQ0qJ;bS 57j U϶I{=+[#3foϹX̣͡KKÉ">YkJK'1w6QmR7orlΘWH}lζ)̾('O|S2~C̊?&FddiCFKѾUH<;Uٜ/bk[>`QNZQ$Q8nlEQ$Y#$;+f Zߩx,L#TAw!}"~YOf-]w@ p:n J89tF,{'~$`eԝTeێCakBN+r 4>:@Na/Q W@L$tU9H6C]^:ͬJG6]VVU/~?@}+lx'&@.aCi]6Ad?Ύm<=tNZ͈~0`5{T9W5HbOd=y`C-p">1ض)=s┎8ʐ8= x/CݚX9c=Sa(P !I`hw]W1.S>ۙr8qat} \I֪T.lnCjY b[:vpp&S ɾQŮc%8Pr]IdDIZ1;>,]m=*v鎏d2GFȵ..Ia}U2s=[X7zH8ֵ!=Ġ ViX;U斞$k+Oe'S`n_=ȣgq<0ED $ 84yShgԞςz5WBsO$tݬemr_[hx*XTkfV<.e+z R ׈] k9fAIK~EI&&8C|Y'{+6r?6Nwƨp})@R U¹|o\b-so5Y f{Ө>ħPrZzӺf6$lsq <ݚnV enE#Z>2Ej˟2܈k 8㆔ׇrXI 0Rqu'ܹpA.e fj- G<粷VYC u9ҒxgJ)D]|Oܯ{~'ʳ<[R-9QmXY@uGŀ /[&ZZL|766 z=VE@.D/\٠ZT[M#+xFQ Rd%YDbZ?mFې^yՄh[JQ>x*b3XbO7s ʾ$Er_s2 mNKsec^GWW3 v뾣A-gBv3Or?K\8pO[]Zɳ R>^z2CY|7: =o^pVi0/{Vb}r)~ 횯uF!DkRx)ͥtx^hx;CZQg|]Ѷu\ձk \XQ=|%I_Jv endstream endobj 321 0 obj << /Length 2569 /Filter /FlateDecode >> stream xksi&də>&NzL?\3Z%5芔}_ER~]A<}Cd9&'Q屐(L$K(M';pyۋ$a\L\MXQN/gbZn᧺]`ײg\$b4O܍Gx~f>JLA"'0$% s [X2VO@8 D+I- W"i[jbdi]yJsߚvQ1oy%hϒSxddydX1ZCQ]4q)յيe8g=`93wo{\sw<\@1j9C[04lD#n#/Tlr4knB`ӆo<_c!2OJLGYݮ [$L^M> HYTBl d.2K-rR6?$7}GtH~-Xlm cyFݰ#6V Aۧ3E(":EPVߔӦ2ͧ]-~f%Cle!59MKX7E$YƵJu &sr0|Mcx$ĵFǘ١dD6<c7?o}s? ΧLdD{C]:+֞bx|뙞SM>DieBS ]鴺1o'NЦ3#y5VޱYwc;DwtYJkv,cX9Ka3n:N/\6g"c" EzmejPAҁ}Y3<m̌Wܯ[GBe5GNe˸+v3wҲ>J`vlCWj^xiΛV*<~ၾjIQ/DOg[t;2OQ+/^ >b=>:.;d"R) D4q~t?f&s~|X- w SAEo/%C $ꂈCi?:EmnJhZYݶv)f TgXo`$3N}JrcmL/OZfmMc,:|7H.>)-eH]wN+2Dm70d"Aaiզ"|M%~f%$>l K !!nڎ"ݚo 08Jm6ho+^~ZTlpjX{*l|<Wt sbboqeP%y#o3M !'BluM>7<-Rg~k,YC43؄ !oU\^Gf(+hh#A e$ȤNDqf//h+`mRERP!f hK#19:l|;m~Vc^Ez7 ');v¼fR [,FnbjŒCIAY0tO4ga`2ꂒge˥[c[9yejִ%LIΫ•%|[zcf;vD@N¬k:w*';T[Ap2y٫q^x۞0ұ][0e;,ӖЈ9x'." h3[A%h{+?I28q"f;3q*H.IC݂ m8{g$У 0}s=F 8..!W]Zӹ2pIy pt5f&|wL:ssfڱLJ,aĠMTЊ?BkBV|I$MnJT HN%ܑ `裼k6k`[j[6DCEic/W>,3v+vǪQ\_ _fګ&r^<xj؊!veߺ[K䘹hFSe.83ۯ^M񛧈@G}~u endstream endobj 326 0 obj << /Length 1611 /Filter /FlateDecode >> stream xڵY_o6ϧpZI.:i:{HBqī>Q$J쁖t<w<$(%1Ox3IEkp~jrkF2hrq ɢ,qFbt~BF=,3BP"ݖG iԓ&dY=ZЛ'4&GR"cB!!Oiǂh8Ҍy` 5?d)-ƼΑG) w+1!xC#2'HMQ]chthg)r {͜)vIy$$AHM,lC%h?0id&garD[31o1. 83dL$!r: ić*7O*{ /PYdk0 YK藗Xl,:7$Ln:L tDQaҐTw-S%HDY,3}** M!3F;3zRJS&k9ՐƐUr0_h*],u$P4~ 1n+hߡ}Jx +h/̈cp&gY s|~k̩+ڡN 7A) b_ouQS)I>*C]'4!4t\p=>Vb6 Csv]?ioVfe٧pR^>:oFBمE X3>,5FӐʯt˙}bT]i%5y)0C,n(%5sm 5Qps Vs)MR6UN\@[뫾]w3hTl v|l/-LHԼ3.MuYoÝAyh|+?ep>[F\YW[)`hwlޡZ^mSlU!WYl6Q}@{ W< l8/:&E>O xn!èt/6h04ɴz,0M5[b7VPތ!UdY޴(vW:k}}L>ޙ|=3 s =&ƾ+pmvZPTp]7cP{| n 4gMvLVH^^%l6ǹLms O[bLmdBzyW.=xb=>|$IxlˌY-cb+< Lak{/0QAd%na, .%+t+͝eJ$:ú뚋 {̻K@;\ݿ0ӡA~4e@z&[/lӀp Du?ị4$sRW"s#gg4 endstream endobj 332 0 obj << /Length 1343 /Filter /FlateDecode >> stream xXo6_=X[bX6P@`]1Ŗk ߑ<ʴ-N-@S<wǻߑ4%HJUy}i%k<{>8{JNDiH2 `O/{,-S.;v5KU3j4Iӆ(Ìmgl~D2C=y:ח*#/$ɵkAV1.F}NI1JaAˌ)GLIDLIFLrIoTĤ$I{%R\|ks'j@)<@/"/+0ZlCxMPg^ |הV? 52nШ!Ҁ9'H)4Úؒe\N@JƯspD$(M_pCW>oNO- ?xŲmЃ\QM{`z Ljz'?*E*B!pʞe#S8Eܰ OuB|օ%tb*HqaAÍ(q[,MJ$ 3b𖼱rcmx;dkwa\.Joje}B{c*:\~ 7c&q<2F'VZkh/P &%fp \KX7up}>‡JwlET)d\(lx^pnJ]Ub iem#Hpݎ'&;OMѭ+iosw3+@u0 vH2;q$.j ŦF=m`!rJD~S>@(Gx!7G<> stream xko k "\A+=5(]y>Ks _֯|В"Ùp^tӣ4I+%ITEL}7?ZMʳ|2<+9)Tj2_NOOŴ~{ xj1C=yQd,W% g_l~pD*BZL27SeZLfR%e^њ3I$lx?6}3ꚙๆf<1\1?ߩNPxeϖ߿ +LI%%1hY73)jv4rksRJ =+ ,CU0;]ylv#t-9.:^Gg(tL3pȌHD,B4pep]p CsǼkÓgiRHTZwL2^J"K3CdqzE/`nWTsw{B..IC+0 fd]x'=];!Z<*`8XS=fUj@Vþ-rpڪh@(4zG?\%;wv{V mܕ8Aص~go[Ңw3/٬ ~g7lpc0\/Ű3| ^]MT 0b+ ׻0Vnsqn@%U6=5f7aja.H0NXhL K*ԚhX9. z,Q")U/"8"N`-T#?= R'TcA8i1=g5j#Q%iM!33YTIV80%~L V: e)_ڀ3 ADߚ[ A/55NۻbhfX'pgv-5ki-%߆)H#\ [gehmtwkCᒭ٪5c 8vVE| G@"l!e˖[5v%@lCjV /\;^f>Ȏʮز k" QV4dsBcj/;;7Nҹʋ+)ʊD:>Gc7ίx1[r#Yr\\W# VF2:5 9#v̮;jYB$+WHv }talݢ?R|QlFePH%֏ɩw&f:JFfȲaӼa ^lrPbCp`yh)Usrf4Ag;`qQrTC[62@% 掍H3r#OD}g+S|1$AUGE< wM3YQ&8ˌi+@rs!1Jf@4f -(q A|ݵ+]ljUk,s56:Aڵ%%,kzDaX&,cڷ쬂j85Hɵz.]jJM7?^oW6UAF`$ @T1)ai^pX2AQ$jSWm<]0۴pfd-֌[ɭVss[p[rt+S—V]W][n[HqaHyD#R~,&p|Ӵ'ku]<Ъ{6{w0N7a& Z,@P=h8 tv&Ӈn'LPW stGe:x,kcF+lj.iVrod^/O.ߴ8,xm8HK֭]C3yȴB_w5MRi9JjV]"Qv6lr1K2?c8Fb]5S*d*U1A׊ڗ?oBնCA&Qfo}eӌaB-ǴP/~mk):Uaܢf2{H3(5nIPIhkuc"oCaȷX$׻5F1x9k _ڋS3H:X7EHE$S?ÿ?N{* Qy Ƥ/> gȧL}6qW5IAiٓHv0h|LKfÃx`QDJ| oR7e\}/٫4 )kޞ(%2hՈ.%gd㗭|Wu`W~Ǧ>3#?#iDAf*GW!*>Of Fֶ0 endstream endobj 342 0 obj << /Length 2424 /Filter /FlateDecode >> stream xZ[o~.JwxMn& y[Z$)Tdsn!EɲE(}uR@ .ϔʍT4J;U 6@ٷopiǃln$]GsB;UiW;SL^ͷVS7 F8{3 ȍ#o0 Bw4^ϧaι.D_ =&/я'~:؅= o߄4Ұh(uH)X^] 8vj&ꜪWMWYT( V9r s Lrѳ M5C~F 3 VZ3|u̐5  K-G'Ş+AvޠS%WUouT?ihD4([3&DxS=Y o[Qcf`f0DQ2) cҕuMiFe%q@A%k*'3A91G$F7:;8!_-gɎH ޔ|Bb),04}X|GI |ƫiv`Ye2q0mD/ZJm[xyMhh:{c iʡȄЧLPjS O[Ij_YРĉ}6_;8%;m s~Ȭ',-6Lfc˨LLUZ;lI%#E¸A;0rSph;:Yrˌƴd"1'(hbMc(EҀ=ѩiQeda--? ܜ!{ҙ,a 6H„Ei;;Kx k`mRQNv^lkEQ-bb=;YUQΛInxT D.c:d1_ɭ2ud<cI8վ3[9: Қ$u-L+c+׺J?Nek24N2z] 7ՠ֕B+Hv)AD#>:43 EcO+6Ndf%z܇ـm@qkkkwd;]R+(YLC9WxD@'C=^զ !*yKz 2}D-tT_Ie^[7 g \,%$:A.y߂ZIWy_R6sC{ /&6U%cu%ZV,1kүa_mD+o'iJeΝ ܤ$&ѷck1[&*} ߉^I=PKHfr E$t45!DN%>Ibe <DqQfBBnC/%}2>י5oqߊ^-Y^g h[]X),,hv-ϐy/ݲ^q'sEcRi9"R77S?V"=(Ⱥq̉ ztʏFOk++xcש/'G9/ Κuشz ?no AS ?Q xSXV%NE>b<̌O]ƾȾ\_Y(9F\uq(и,/Q@dzH3'<`V\hf|'Ip̱Z;wB9,TW&=k}#'#>yȿ%xɟA:2?/4 endstream endobj 348 0 obj << /Length 1656 /Filter /FlateDecode >> stream xZo6_J")R]hPXk`Yeqf&vV h$ʖw'(okoFl.+-ngҒ쏓:hzh uvESipƪ[3Ub9/Vy'ؤs;?$}u/ O}jV@8oHP 3V7Wlgs`:4b]x h֪[] R]9 +~<EE t+ڪqID9|X(?R&nH8-xdKQRF#H O@bH$FA'F#1Y[x3VXD1\,Bum5'S^%(+rFJUt\bz1P\X;A%G14xQCԶ;lcm}߽5UIGGbNzxu.D BnzU7[toV$4g?S cpjݵz臨] }#c5V#6:>C 7n eFP#.Gʍ`) zUxe<Ȍ7#'|!8D|uXKlmmҖ:O8ƚtדȸb>q1.[U_]ÃڰNxQe9ljv^Mro];r"&ޛ3Cȹ!}^K/LkޢGh06Abo2gL8O AƽI^ldp=< 5JBJur:*VNu 9҂H- h, ")wt7s}]]*ߋJRmGA3ED)Oۉ9184ʗnYGr\g2H)s߼BsQOqᅪ aMUJH_8ss;dqEUa-^F(ZKDiX A{4ے# X Fv*`;   6X> stream xYms8_aѸzl7Lh}(.$ˑm^ʖ]mi%y+=ZuXp`,U\,Xkʼ^^4L(tSJLyp0Avf~~j~lqV 'm0&MIh ܃yFyGz#E׶p4a4"ּL9-ݢokrZBJrŭN\cݸ;Qi@h;{ MWoZq,1ݘJ/WzEO:V+5Kq!C(6:-a=/S) GRJ3{Y !ݲgQ(YӡH`@=fzV?D^n N2bZ~h B*i.'nE.ϥ#WP0xB8,TDa|G1wS2/3j>O]syA ~%RZ^r?񸙦sz} b 7ܜbVq?wYs gU@q)BRVqPpI^xP zJpT+K<@kD3sϏ`|, ]ɠSDAqS"$|W/zyc?4징Ъ:l`$V!0:wo=veFƀI$av6VӪ+( ,3 ņe#tt p2? ռAE=u2ˠPWEЬ豠BVjzd qgVCs] s9P[Jf%Vعʦ~ƬPa;GGI@m:,مxn6 9_7]/OP`/Ȭ8yNpάf$_:vS,6o =S|+vp܅)͸sBݯNh3l g 3 Q4 @u(Cg3~ÒXѼ%EIY%/ Vхr gQTX6,/vKIݑT^"p| ~F Пb@gvBDS.sya o>M;DίmCc4d[F7$$&/{t߿;[vǧ;Cm%;5K^Vlw~UXMۺdݺPJ0]vOu4m n\aƁБ! A>i\2aD>l?í8y߲1 6#"I6ͣZJnlrv] uS${ hDx;׵!=/ČzKSzt᱓XS4^@sFa'XcN@Q"Lb}ǨDi ;m$dnjt2جSF7,"gcu"% ?"3¹Z*38GV4eEl>YՔU]Q^ݔL87$}IS6M0Lv].pP&y̻ĝZW|H>Ӝ`J endstream endobj 358 0 obj << /Length 2005 /Filter /FlateDecode >> stream xko6ƬHY,Pt)x,GRb9Ia}GQd-6E{Rsqenqw(0pЙOǭ{WG,D Nޕs>vO6O}QKI9o` f`G#cGZ#7njsi`_t(bϝXI4Q,=$=%sW L՚hOVџj@ e%WD\iCj6D; 8!5V?j6D?aNSӂZdsH3N93] )8r5đ,|otl$RhL<䨥,m I&ķ@ qV1ȷ@6GJkEQ 7;]XJ|M GCʦ|.ސ !.Nct 20p}Dø g /;]XW.: b]^ȼzF2 B+ 5f{Kzoi=VjGrch}n*&ыEUA>օ̜"^#>;Ҏ"$GoNuDd'ǙFNH Rc|oJ|D]6pܰOP52fX^g(B>c|`xgY]371a.}ٖ&0Y]ACY'hԿa B &-Q*])wb&ϨЍ!$Ś"W )R'頄f>FRxpv=obEf%-<Cd!3s winW~_=᧤/baN@Ig,\mʈ7d&t}+seX-p[+=VdvM29dfdM)DIƏ-cĵK.dJMTdDV4kH5zTaxʩӅ/ʗD+RJs|J ,-B}j1sv_aX&yc)QǥҭEBRO]_rl9zC6,)2wUG42iFa:)|Җm7^bRd 9 ܘy\> }\c..;"*B5[5QjՃ∲Ͼ3`vL/DU1D0 >kJf ,WrOצ 2 ekU62,4\4ۓ#&:Q_F8C5 x!A6;>|UfenY+S\r:zNs~hc9hxq!E5a`׼hk`x0"j/l,/,[_=Jyŭ4RZi8jH?HX|Q}oR$5y:G-.|!(H :4P_\ n4 [7t:Mt׏(@*k4 nWY`5aY=fKqqUU?~`.] }QUyItj2Sj@K ڇ(b6q-E |pIL$~8UEi7)< @co)|0EQ f 2֬7_OPM:AyQy: Z!qxԇ)|צǥԯ3.+.MN+[tPJRug3uhVK9KiŚLKo2?XuKw| GqZG/ /DVRA%>A}^/EoDV8|zP-LsIׄɜWUNoY݋(z(1)W'[%.E۰^IzĶh$մ:&SbZBK)׈< 5?g3i۳9g{YY證wўyH]' endstream endobj 364 0 obj << /Length 1785 /Filter /FlateDecode >> stream xYmF~B }1H@ tT/BK|;;3ko;/f׻33̾D@'G"y"U T ̈, 03tzrlt8M<΍2 NB9,ড়w 崀5TᯣҔ'q0^ U6Fo9D汔(Ӓg|yQ2&0PwQ( O( K' PJiJFS(C( s2Rw#7PBy$K(3g(wuUL4FVK)_G$>4{W[߶.kaqdge#H'f&Mb | #m aztB]g}WeaAaT.'=mj7o) `eڜo:[ yщmTkC߭t?Oϸ_;@4 endstream endobj 369 0 obj << /Length 1796 /Filter /FlateDecode >> stream xڭYr6}Wp$[&IQmGVq2ٖ-HvN?XKԒL=ẉGgÞN͟{jhbOe & ZXe|ۓi3mq3#-r& cdZK,cI,,Kr?iK=1}WVӆx:L 9ba-K<'%0\473iv G{ţ,c/:{f@GVʈj ̠Ke17iACkK-eRm52Ϝpz7ewYt7*X2,};&NUJ0%eh6C1mװĆpjTcET4/ͤBS~)Y![,hb@_|u>x4eZ2RXc Ԝn) A6eLK]]/tU_p^QIcVbX8ׇJ4F"fx~፰DMIA8rE5VҐן:f,֪jc- bH)LUB%+gq]4cze$9䧦m|A4g@ލpW -&lv}5^ e k/[mcIIv)i⿵ۜwiR:M%ZUHMaQ޳2[:&UlP?5Wdgsy^)U Lƒo20aZFi)Gt'^y{iIf`W;}S:n:(Tk[6ł" ̺ %Yi`V6 -K&yINY]Q=m[.ʵ_C*4e(4!es;΂gW5\ĩd9ݑmVřzRɹOdߵ[ed$R0Ocܒ3乐P 2ڄ~aڽa6]-bEIyyG˕R푡jUݐ~)nr6r;mH!h/Znqَ!7_ O__Xc њbK"kU;>sOZ_.1G;$PLk\&d# Y6d8xIx Srpnϑm|؋ڍdXVNb.gVAQ-'nkx9ڤ!FM> stream xڥr6Q)\zR$ -Q&Rt\zHN )o_ Hp1"e$iIL$rt6zF l83$"fbBŝzl7+q*݈ C,ƛ{szR5n.:Mѓ{z3KÞo@{ ]rwx `=:؅7^+?@oq9.^h^ e{RL)#~ߑM+<8rsUq G {#2-rm9ҽh~kΟÆrq:^y4 s'(vJسA! X^&[sw CNܦ|bM'Mk{bE̷(֊9F9[\|"[NQw\f26ʓkҡr%b<{>oan V5?Q~yw Cggt~|_!;:@OG\/Cl5d4m ;Ny. flL$A^mfVQ5B-#ƺKԲDK]6Y3ԅ۟% ӠC\jVH]oiSr,>RJ!Jy+^k{結O(=TL¢t+;a:e!wU| #7Q(>:4d eSm=3K$7=Im봫zu՟ȽoQ7t;,|d o Q (ueEC[R=SI/bH.\u:|R%LR5).hx'ߢGUGW/* k/-eCewT?e&<߷ﯭq$v%P L34eHvzMȡqSb 3/@NV1}Ie+9݁aΧ#€x~zn]Mmv5> stream xZmoF_{_3z0 %vw,l!6哨k E2Y:B'$3<3(CkUhZRDQYcYFSw,8GBY&+2>"JUNDYaffGOlb5qUD{۔Y9c\rEWt5#ƅ Y@&07M'*hlxfd\()'Y dH VDi}P^ǽ<^{@\iF*CAsV蒇 b&*Q(bŌ(v$3uFfV Y!F U)b^gMbX-Lb䭬28Vcb f8$kcTFX$<d0 ' cohaP-/D$cIK1b@(*B9z`ņ$ȑwS-x18I}N3g- 1](O%v(@c 3fڲuftp0*}z(UqXUzTAu8~j.Gy9{u"u FG8pb˫ZOA3Fq8(~:#뇿t6UI=xO>oE1/l$8+trx7˪^hyސ:X8!U48b/Wr|@6G/(-<tEHA[5 x>o?gWۻbBZAZ7Dޱ+h|1e{oN{pQ?3Z]~Q6dj ^=U:8Pũ)دyTpĶB|QL^.x;M.J̤*ޞ]V 0*17r>)MonP^OGY7Y p6-/0|\-|RUϗONN'QcH(Jw,D엺dڶM{||4)K`q? +dWl_l\]σr~^qlms@ns@枹=%"OPrAY3Q(#C6Z&ۣJs۔dͭv952b9mq͝&)F˳;Ǔ+z1~Bt|qoo Zs,5 #0Rz9FdA݌hkxl3$׬2m[iq 0]j(vQNN]9|Ze90I:k9LdmB95)?rx&FuҐai10/³u;Y5JgV\WggzB6I>KhBd$- sn䛒 9 gVB uU@,'ɂt /l;d,elh~-.Y+O؊ʧsIiEcX^a6 쉼ֈkO&5vacy-vk`6r\2uV͠+x>,dۊP`CW CB>C&H_9u 6`e!=I;|eչ(ǥ.Xs~Am ;0vHx0tYmw6hq%o(wiFgi )8iK_n_!~!ڿ ilsl{B&3dIZhǾe8(}fqA5AHh)rLj endstream endobj 379 0 obj << /Length 104 /Filter /FlateDecode >> stream x313T0P04W0#S#CB.)T&9ɓK?\K(̥PRTʥ`ȥm``P73`v(PՓ+ L5* endstream endobj 380 0 obj << /Length 122 /Filter /FlateDecode >> stream x-ɱA($ \vTSHB $:@\#Q_TQUE&MG-nu8M [Yð,ΐV]'v=WN;S3uz3x:cE_ endstream endobj 384 0 obj << /Length 119 /Filter /FlateDecode >> stream x313T0P02Q02W06U05RH1*24PA#STr.'~PKW4K)YKE!P EoB@ a'W $o&| endstream endobj 389 0 obj << /Length 149 /Filter /FlateDecode >> stream x3135R0P0Bc3csCB.c46K$r9yr+p{E=}JJS ]  b<]00 @0?`d=0s@f d'n.WO@.sud endstream endobj 400 0 obj << /Length1 1418 /Length2 5940 /Length3 0 /Length 6901 /Filter /FlateDecode >> stream xڍwT6҄RD8tޫ@$!t7&]wTQ(H"EAE{oedgfwm"l!4(X$T 0$ 񮈿n3DdE@OQ@{@,)%EA 鿁h P ꁴ u(xcNxB@^8,-}KW8P E¡(>p#TC]&h8G ^9'<##") u |@O$ h!{O@5a7vP,H0"re Ձ&z@C  s9@0_DLD h7 D90 /84!EBaCF@(~88qHןE~!\:^@qSCbp½{i {D;a#bBChLxHꖘDxD~xcf_ t @#/p<pDN0#~ " @ϿV٣Qj\9UT^@_!1QKo/m(#6 Y' 4x % A#ֿH'|S+'YW4?~ {xp #o9D#۫DHX\$ێi xo1 B W$ qC|@fBx=ޟ{ayums&E%$P, H ky0 ' h,g%A@ן V?2aҿ$A(#^8`r q i=RfZ#J;#*4\hCQ]H0Κ}1 ְq0Pq?̙}TQ-/ġ8߿0{zcy L 6[4M'c 7_5]=yK5n鄶wVf1J}doC%v(x1*2 ㆮ\ foEtǃo\axZu~V5fW~xld4*mC4B(%C%j'y^~@o(Uy~97oeR a'6vYwpXrѶ׾>ذm~+RCvy0/${^t3yž7=WZUV;^!ڛtBڝbK`^xZo-y@Ij>t\Msb2i !O9]wBO&l=,>fk;(6XRe-?_J|9RQza_zJ9؛G\mb` |)T*WOz[#Sc׈`Yj'Y"Iڽk[rXC_8gGP--13hf\|L'`jvs388e Eԓ27ẏ'd|\x' z؜gԽ& >n֥ UD}w/ Y1.&Yn]7.ktE.PGi7o2ӣ"јAچZ>}+ ɖ^(?>جSP :TЏ4[g""۔-l/O6] ǯLnq+p2pI2W&EjbI\큦DtI\;HzQzj<his%$VF{mpL*1iK#C]Wl1[}~D. ͳdrHK}?c$OO 6IMӊC^+1L9:]->V~\=~}#L_DaX… ぼg-7Yd 2VnZbB7˗wiޕ.͵=淝٨570tƼ6(k{`oВe}A%cB `3Omc@OXM)v&{]y,]h~AeGe陛(?I^:z3qTċ*5 9 +ӗ4"c!fdP0:LtT\'ptg1TbZ|ϤT'dB'uŲ의ݩG 6of4s_U !jzZUyO!ED9I<޵{9,c%(H{a͖/nθ-F r)\k >/=iQ O{ Sf9z<BLMd}DN>}3$wk56ӱ0v}GIi㗽+A>m)ˏd\E*OE>40'fjIqvAdDjܹ޵o*5B.ϛszS\vOWE(*nX' 1m\͒<30[$DS)7eɽY7GJ1sךT5&ͭz=' Խ)Iө%^Ku{@ma|^NR&}ͩKaTxU!aAo }U4׬Mw0\@4:. ZnD|sg sLW. jLga.z#J<)m:Kef3R 6~y.FAhxq7zӹrQ2 t+c1![ XO>2GB}=-ZvzvAfx)c?#v -X/o+*ީ_#~2lN q!W᝴_bzOKMIC?gT>0u[oyR &𯳠A(̣6oN%XUh[3!MuqUk,vًJќih+%D($Oڧ/faB#ˡاƎmI ϾzuͿŗgŽ1*_QWlIi)!VnԎV|{8Ku݌uҴ]؇Kf4rnۘ]tϨZQ%ܣ#i(V1-xzPmqEB'n"%ZVQW[:#]tˉ(.? , KN>u9Y#_IBg] ydK&7m$fFowcK.IӄPrԧ)PΔ%5ʱR?ޮ;ڬW;~ˏ Q/*],o,7}㻕o&x2R\8ˋTSw5 [ϕp7yX&QŽc(=ڀYKlp9rC[fkHDz_il'Fз9 I_P UhHCv >Y,zaƋ5vTEu7Q An= w3mt5ǵ&'yαe~y?| |4Drmܪ{3k$*&߆2}ۤ?& !eN$Sz<2QݭEǧz 1ĺ3/+41z\#Z,Ҹ1{d %yy//0IO"7\KyL\":5^䰂70#5 By Eǔ_E%"ZWZ%3]p0T#5%kmJgCU#($4_k^ <{7p05G"9#jSۗ6ޠx7S֩t6pu)1 i1;VЫݼ%y(x y{69xA+l^97;X3|{5#ưpfL)Q4-Q(7Ez(bWi [cE֗t2-Q[^_Z1TZYI=$rp0zFa-ݯBScVT*ISlX0 \BO9QyB9".}V3@aW+|*'-x{x;W WDu̼- =\d%~zi[L3CĽ3iC\Gzw}MZY~&㢁ebP@n30Zu*CapZ+O97e⽆ܬQ%b1KYw:B>md g)Jg}>j^i{MfUIΗJ@> stream xڌeTs Cpw?XpwܝݝHpwwvrX xjW=e{dj@){WFV&>:+ R[@ tvvFh ILrnVv++7 | wks@@)lmi 4fV^^nDf&W+(-@?.h\]=<lbf`hbemo \=]&غ8ΛXۚ &oUrO.f֎.L.ֶeP%.v*o?;xbȬaoH[f tp t=ͬ [# b:|T/B`e[L@0h =z,!d93wmw%%$T5M_'bprѿ%oKMC￙g6Q2":m9#g?=yEf"_;ߤ.f!;&XX;Y'(_z'7в4\&vxUnR;db;HoS @EraYAm}; .PalڱzPut2 eEw3v`vMSDA1A?>;#0aw9@uu#1g Bn@o}s%tpq$ h'D ك^fW+gs*@>~/(3.fVZ? ȩo O@ϝk j#B/S!,;ԇv׊z0Ҹ}s#@fWPFȑÓ#n,ZA!&j0?[@x1#G !CAö>hz|zmFܯM\tƫJ,^xa|lQK|%M;$x|Ele6&ci/u xT yN%2J44&ב/Ym~`#iW#]1Y5Jo./Z e>ɁH1H4浘8ˆtW<Q l~򌘇'a(,%IhlejY#4^fLxjL泶.Cݙ(,d$#7%aޖn_nvӪaJ} 9[NR?+|N+RvΏ/wiG*J@Bbpנc8CeYqg4(~UTO̥t xk } >`5 ;]80k5=e˛I4d.AyxL^{=1~PL Yq_Xh}v WAU|@ȺR-.1ݠ2ԝdWtlsZZvI-Z W.Y9\ߢn،ڂ3hU}C:KL(/GRB9e@8<Jmä[˩[q}lGbc:;Q*dϱW沬іFKʢ*mB]UCIcJMd)5ĽQ.uQxͤY Ja`oY FIhv\.k}]lLWZ(Ȧ`,\栅ҹ;f#Âȇ|\t7>{PԈ`"qW;/ِU.X)Q$^~f%'qRߨ tr(—I2EԴrǫ Vd!$fcl[7 =dZZ)be;x+eL͠w:RbךM RP7{>#0`Ai؋ԱD=K"]{M9nxr3,{ 9.\FVP2շ@1 Ygfq5oSfɲ ϬfL> !֏WieHJ%lMpdT<$F&zJ nx*#Y斛/T &Iug^ 'HVj0,Jm*U^$bt~/ $siDzL"Xt$ٌ%p b-";bpWᗘS CH<<5rr !&Fj+Ÿ0"m-bB3z%~/q'/ݠoggDc9HrJ9wHQnᆌ-Uf׶ڵơ5WUm,rV~ZrEj_i`[f*vCgLP{^2@Hn, yk r05rR[ 2a#COb< ƜO2 ؅'qUtA3X-xJ}ҳ24w6(ImJ^#1.+M\SaZvSךCA5ƌgsWlJ_8mR8A="rwx2|FPҨ"C#2yf+H̙P ,eJar7iDf|{&ΟҤ:3\w̩-=tJ'r7нTLAf?^MoK]ۢCL>IW#utJk$-4i$l*9;E( ܙ={.Z?MVu&?;/6Zo%h;< 7C&M}_̸sLjKL*Hٰv_kLtBeB8tx1L;MKQb* -^0G"ϚM~wϗSs$=vȪAY^xMʟ023۽^]V\2@ Gp5,/&N, I!#MUH$L{ѽY.E1n)H(cٵwkVQ*,vΈ9 E gfcp[X3&$h1_f>0\pg.>(/{ޏTsEf] cl0šzy⠦=kb+J|7H=FRHaW< kgC4u>VG-[r3k37|U^{Sun~l' cb,ֱQ`adg׈8!3d2aϸe{YܫFNł4qSk ZZn/Qn7`ۤK4_,kStű?6vUcS[ETN.N:W b]pi{ V ж?i_:]+8z$@5mWF7Onܧ,Ml"4{/C!ύֈАo4-ťҝx4kv~pCƻ Ss(#ݲ @imnXˠ;mJO'W/F9s}h5a.AQuYEϙt_(K}_UWaLnY!`;M%eJgFvK <ÞpCy7C7OS!|#ߛA·%FsE<Ʈq+QY~_zBr32My¢`{PCZsz,&/͵(ImU'99i*`~\OwEƀlTݸ!D""w͟{)dq8x2}?䲦FBW~'vv3br; s42v?k+Qp.V@,a`% Jm '^/qP5vn}udq;ysĵ+ǟ"89-wS}H?jn WN9hey @8 H}7*tcx^ ՆW+B*AS+aN'@jz VkOfL[ m5n5G`Жh."DeoL0 xz5~&^$l1w' ;N.p\s6r br Q.ٺe"SİRiU_,vKR X H/Gm(/?M䉰jЉڗ$;jJ#<ѿqP((Squ;9SWbïj\Zc]Y8>lw;F꺙óSt&~3c9-W{YK?5F E-8mEMRVo2U} 9推*T$2w ;ee3*=%A-MIJ `⮘lwcCe#EJ\喍!'nvT..ґzuPasŪs##ŻXFxBd>L):Ρ5py"O>N`HFL|cd/pEXC?{Q֐vx#!T9-M| */D\'5ᑞ*/'!!V$h I).W?;qU'gi<E~oΊ8J^泛䧈w A*r?f*b)ͬVub:%&cjf\NWա"})C`ġzЖ'EJ {4r}_Reͼ0=JdF2ilVsDmҪ܈r-r{Rnd J#yZ/\ )ص!,DX]|>YbJ*\ZV:C)m+uQ}9_~ $ﷸv8؆+59O΋ސR94AjS( hxsFޱ* t=vGp>uk7ܤ/ً6픐ו 8S)wi&v\ DXcPWN0ҋZ[HgX%)xmB缝맳~oq UԚRحl߾v8S(͋V'2 /,Rכt&?l0\ TtiIgKs\iqIvX)6's7Q v{L* b%쓌':Mچ/_6QZv_MH<ѩ"K`=e'0J ٽ|1bS/o~Nyۑk/$-#ޚIzjrwvdஏb}r >HӺɝCO܂ N55^}Bb=;_w"2bw<ʼ$bT޾BM{~}vBF4dinj:]II.檍B;*~D UbylLM5sV ut @Aa]9#g A%gV8XQAXn9_cs^zjVL: E(Cw%*SoũXF5d-0 R<7ƚRytuzBmP*i2y,gTVNߩuǜCZ&e5n|wD E6$&pS|Kz m&j%;xrw+:YFyEy}ZstLAz2)Ho601Xn/R_QAފi1?& gtFBb(9YۿtLt~;eƚpbTtdKRƾɓgQ=ք5zD]$ٟy}bQf{Lx~yQc"Ě`vvNx0f>@ vl`i1 R" HdhצvzS e%H^و-J*E4ʰWhoyuL:svR|PKlAl6%;y Kla8*aSo;&ȥrt:%Nݖ-j}`QCk+yp$8QiǠ0Q=\6o8n.ou#rͱЭo $4z$/%jJGSuc:<YsLaDuY9ӱ1l|Ci/-}Z'?jB_vELͮt Po߹0>9^HckV;q7XţnQiLld$H hq:'8+(U=[fw\CgT $*w7YJh*/"D%R)%Af43ZdANFC_Zە'<ͨ)Vk>Sdԯ=䦂40A[vBk\RCJ &rvUr2b =T!D\jq_#ۺv[Odz&3CZsfjy?ٳnܥGMD5^1UzH_7\3&SӪ/a"͕W!/<St!%nw6.:|F`T }d]2.J~>f+ uhDžFVTp; kW Bj@5$@ֵ?PQ`Sa9tx~~G~/DL~JӺ,f|$C6 NrMm'}Abf3WB\GQm :?lU|1bx4Ս=dQ.b$1!nVR8FCu3JVg|O6TQ[/UsQIi RLKuK7%b).QlwB3cC%Dz60!([ =0fi--|zY9"G,LzN0Z$4xN.^ȅQ٢@˧eq>9C)_BS$%)axܝ!\4ޒMY9 3cɺƮƹ2^awRs(}C5]Mw4-jɭ Pg-Lgb;bd: w ;Б(wp?ufP˯rw wI==zZO -u$6Q[fg'he2s8 Zp3*.ofkEȟ_8U?*[f$??.uGV!YEA-Fӫn;~S$VKtٍKKZd'zR i`-^wl w'_nXӣƺc?v-pN] {6DNCu5p mi$}QNXa(uy1sf!S55='QhpW32!;k0f2`i}.kL~~I憽3`5D؀&$rYm/Ƃ}:^}`fyk9 1WR_Δ9OƖHA1 LeC'Kn) 9p0Ybd3kM0x6ItuTՉ4q\[M.΂ a|kmoIՋՁS{i_ݷ/Ctx#=[ewӌxAu\auq*c@?AO$mׅ;u'Gr6u 6)߉E+]2L$C<y&>iͷ7i Mɵ^ܵt@oMӯX{u4P9&8mRE:)3Ęh`bZfZ(qEx6^HHVT<9"İ/yI]*,Z*cAT3iw$ĨO1"̭po@k6gFyz(QMw3hCU "?`4V\-\)/Zť!O%S|9wxc=8M!$9 ]|9W.NC>ac1# +N-7.r Pj0yK =h&$j>Ҍ0$`pQT GޠX؃񨘓Łݺ$1na)S,YP2n$"Fo,t2B{־!wL^_82CPT,e;qTDNT<(\#w+j+: |q\: CFe&o$=] =ovZ~I,5c~<8T8fan]TĮp[C$ڦV1ôQsH9җ=eFR/*̢KZjŭNP撨) [͝z9Br&V)t)`{:A^sOzCۂb%6aG=SQKjxU" M1ŸKIYz9A/rΖLn啡ԇ򦢷O A6題'?܌Cg}AVemTBHRK9TDžKq줛R, Jbؖ603dm8>IF=v=D"/y4Z iqfXÄTۃӆW( N$g#D-ȴa$1Sc{4|Bٖ+ܺѝ6$A?fJ\cD 9j?/E:FvjD6W wmY!V(Vyd'xuW~<^{j"Ɉ[^\6>k٥ޕ4NoB+QV8`xU?T(AbyoF˅!:ɖ۴>6Yu;!Bzșw=!-lnwYWb#J: fՖl)pI7}457&YЈ\Bq3bn;0fے+92 M |r6st6ӛSyu5NY.,k fˡ) \1fv2uMX:\|hJ"]Ao28_`W-v5zHS eh+[\aBf.񞶗At7DA[9cvmF0qeD> NpA% nvGT ÉbCk'%01 |s'c30(?-Ԛ6Rhy&AB!q `rˮR[Q%j@.FF0I^9w؝y25ϱ"9䐝oX_԰ٯД j:T*Z)t.56Tjrc?HKJsXDd tGY+5-u F߼<+P&Y#*\ kK*6A섞SMC~8եhahe<:NZT$ݟ4tq Con#Ds{åLH 1l lD,H4gɏj-{|SPKsx(S爀5ק$ ma<`, -/Zcp![;>X|@ת ΪlC0މm735¼kDg_qQ>~T 4]\ԅ7Lљ>!?A͖${UҡuNpbI DpEdJ84tMI/(ij 2_TƁx[DLXi; NEg|kl'3fn+mm17yH-y6(#P#L|.'ݩ#N >w/cr]#Ғ4 =W@@52ͽl i*i4\\dUp;my0+C>*6ޤ/fؔSc=oSSPꭵ4obѩyŒCKK (9h46_D "ȧbc)l/T ɩP(Ӳ!J",06BD~kV%ר]t<0_)XW=@rڈ?>H]{hY(!Q5L7aRʵMմ~\-zl`77O'8_{ơ=®ֻVl4V7-1ʴB-3=GG]E F*d> Tݤ ~Tp`[v^b&y/3RrWXMnpĘlƏ(VX @Ǡ}Vj~$k! Qmq7tAr eO68e,!viUSHyڳEsǶ^2XB< I`ms®&XqfܬesOBe)j#D}@`_DuSX>DVLL)D †~L9Ɠ5*_HU"8{߃|PW[[7}ns@-yWĂ5!<㕶A.Db1&cw-6j|ؚh<^q}va>:?՝E<wOv-ڎݦHl5`UܱߡrθqX԰UY3eF=9{ vR"r܎l,w*<$?0(p<m(Lȟ ~ Ю+'j$ZOBgù>iN 1w ~:]$gJ45to &ʺ/s~Pj&ߙIeVZEHQ%H=O?~ύ5%SA@\Na"1N^3[B}А!0sGq0"ո'4+lnj v]`QdDZh騵,޳,p>F* q7Fo#L'1e/d!D>-Sǐj9jw$*Q2޷P(r{mS!fXӈF N*ɠr=ڰDygA5-ؓ$G?\xw IzLb|3Vt+&]x2v'ia1Wym1ZtA{OTw̄ ꏣѭ.u47^FF?$1%kZdm1_vڂ\h e:.N?jcFP~jM/ߔ4^G&)D63L5)L=82laro{7Miߍ61As=oD+45"~J l o]*IF5=95t9W!t֟_ 1shnwEfil% B Zn#ECl84PQ1nV! a !mP(Ϸ)'rk;Z-Ç7u˓`C)< %|4n][ZzNcp {h(䔱*X1YpO%j r PzgL/-8>+^KWgʂ nh~N^q~'}k㭩I XKC+ M w&ɀ LnX{B_װpDM4S> : \ӋV^&0+k]Zמ$Yg) pqў_ O ,×sΚ=K *wd]= ST` V:&铗aS[Xz vLl'9\F̑#S_h!)q,5jQ[2bov C X;zi @1Kcf,gv~wN\wyJqNpmOIYB+] LxqQnC(&YP X-#㵮!9tKkc1YƑ]8<>z)J^D~Rw>_6EUn 'SRDL.1ڟ4,IJdVAa/ۼPp%ev="YyiNv"qzXϽ]25[cME۹^nqZSK{pt 냺蛨p03#yŋtcʲD)Y?{fX,Y3ATb fnl V -?qpXTLkNO^SA4;7CwֈvAL$?' @̃6n#'s_'Z\_!V4 12W{G )+.ՄahVc%CnZd>bJ)gZA7n5<7}~ucd6y._?>G+3hlW4km#avC^uàGKc}7 w"p4:G90 l$_ζ閈r{)ݧV{iDU4yvRzT^C+B- %=MF@s۲0i=VW? QQY8JP}nk2.eC1:CDFD[7y*Afxk ' 4hsaĸɤ5OXz֠([2t [Eڠ[T|慐@⿦nVT1n~Jگ~A㪞jj,_OrRSJDO97DiJ@-aP/cp3wέb#U1WN> 5|GCת)x]s1U)EV=F1@N5 endstream endobj 404 0 obj << /Length1 2771 /Length2 14691 /Length3 0 /Length 16235 /Filter /FlateDecode >> stream xڍPX k݃w-kp .C 8!ϝ~_uoQt~aUԙ i+3; @BQ] ƁDMajZ b vBt$CE@ ```cp,[Yr` tfv~~^Af@" dhͬA^qA'd(wa;[3<]j ;+eOj,H +k` W3Y\ GAHt@L`ga?9v0 ltvXXہ ,L/C rB H ՅW@,`.9 'i 2݋:=|,-~aȪ`"B-8 '̊W /G_J_bH~>`G$ :|T!̭\ Kk!bgkO>dl~d0soZ̪&&O*fv37 !CY 0 _ ?[Co%0dAofy:oyH/=?z?qvs" T>+̭VY1K i"m 2Wv5{{;k ׍`fgc?:ҙBnHR ;ߐRf`_:;  al98]!G`g_=x/U7JFV/U7b82'U7F.oA(F.">E7pQ \#E7p \#Ht?DCt@38CFv@3[]p-W84qC ? / CjM23Dwr#Y? /h2 9A ~;evs#7h $!r9a "? $ŸB*lG 9HnD?*7GO>;gw8!AΐwSd}T变6Bn n 27Nߊ3V oM̫SUB'g}Nn< zVRdr]>o1]XHD㼩 $&0ڳ!;EO.z{@ y kXN!t.9պW]X,g47 Y'(фw^_yQ WSM-G3 !nB\ 8DY"tTW#?Sվ+T/[t^j5%)D# =MYzaJb?`r͓vbFFOXփ.bXMa榨F{@<$u>Bku{N(EbԾ880:h " ^~S| G.MblG:  W7ŜįpdL\`v tJ=#1P2h~g 91);s5NPk]͸tXN qͤ^@*G]^9CDc1 Q rhq#áf8ZVs@{ذ[@[M Py{gUR<6 T}1)NJ-t/BV*Vl1ޞ&n$㍍׋%d;% p<"v[~$E2Lx;H5XG%1~wɡ'5P+'DvoyAD[Ju/g37]q!\Sޕ bkRP72QӌŧD!ceK1 d2C!MK"*!i9]5S rsLOEo)ס8qnqnV^dp/8`N^ }!dk8"ˁf}{hm)B&`֑t^ ةO]oưwNg%쫅ӷWw~vE $ݵ䍲R7NH[A_ؖCVqQL5cp)J +LPeĨ?bŐpyZ:H./O9PVCM`NKF U,a=a)=L3?<(&`*y|$ #ņ9:;sygRCZH{g|Z#.|x_U:bC4q;ZƋ~SjHCJqӉnW1%1Sedjٌ#Dcg]#?&m}t9Oɸu,3#u,Oq[nZ;IC[Xư \oL"tG?8i+wy夑 p/~Z6uw2&VR gU>eɴ_9ca 2ԟҳ_r586:"YmA+owD2,΋ ^A"EQ jUíRO9/ z^j_#p\Tߐ4#70u$O&.fd4{c^i)ػ}wbzCD+Θ:pbkq*VLZ,xa {ŷfɨH3EJ䵕?T :Dp0o[RNYD||!/2FZzb?Fm޿{W\T9W:h$vQMS8hj)KLĊ=ɏ}Ż%B#=;jf"a}=FAh+oT=iy8&1Qaԗ$E4_]Eg<yɆG /IR;AZ֦ 90:Yc 79M XgGpe0;h+:ZG)HrEO_}?HyKg :j{I>&g[R,;Ae2t0Ef$z?Bm\$B.[>Eܠ[wAo҉M>MOh 8ߖ5 Ox[!YI iQ|`-']Lt @IS)-{^bK׷HKػ>.M3%}1e1->p l< @]H: &!)4r|M:wd@֓E /CqX<}x*JxVmj;hb!!z(/25F=fL7'6IPݱ i Q%+ق+Y92NEpgo:d'\usef`X 4֋ZdRWl.WD:y55mq}kσGPD[^n IKgr(X֧baۅ jE)؋*TDBH%}%0(GEŪKX⍽nÿ3~g}TnIz䆁S`弖Ħ0g*6mɵsfGP Vst޼±axt;郎8].X̎ .BD%]VakDZ5W*{ªd5]w[!(Dkږ]LK+,3"YٲLͬ Zsg2A=ՙm-jOYygŔh@g۪׽j@rnʝG0VvR Lu? z`TvV_?IK@ᢆ&%3 VxdDҌz[rѐ, @- 34dOv8b˙Aͤ!CDQȏ 1/bx2u!\Q;9wY?J"FsqSBEld@nKy|&AO3ȖȂZGbb{g~*_|{_2pf}gd@5\9,~SNo6H(I9 c[K1d47Epa"o|TXI.))}#qgg¨*ȩ03U O1 fkHc0"Uҿ{J23r(gJy"m(=u_gqS,^uiA;Eco KfU2v`Rrs){\"%[]`4g= |.ңz?Igdht28)x0gjc]h[[Up|^2>( 'GT8L,0U- !ƕ K jS0|+ ؃RHb5HEX1-HILwLW%?9k]FХdݼrkcȮĖ~yTb:jS2}rg8[<-!ş&9qjD#Kv n9G0֑%uƜA+CH-?MP2b&Lߐh-T)Ь\ʦ(;O!.n/+trp?Z߫)vx V"֘ 指^+ T@v4DD&ՆWnQ5x#w&܊9RUwڜ}X3QW_?eR)Lw56/LIEޫjPIFq>d V[@(G:OMa5:DF!?>^hSpnr wLYon3R cY GsO궰@X!w^Q.η+7l =K;O> GDeRWc`6y(qU*Jw5Ɗf*>:[0H!,cBZ Bp8 ؠ N=K~V _*%Ys{dT?CtR[Ty`I% }[PtF%g-tC֥$ɴ$A,xJɰ00qg|e2œ_L@IZV<-kcsy4T/[Ybv}}ғP_Orve.AJi>yO_Xa8VoCd"'v(p^c|?u 9Qi\+~v2=[#a_5= WIHXhw[_hkWKXx\"]S!Ҷ)9Ģنm)z4ڋuoL1WFFq%7>|3k<7?٨C$}}J8 Y(Sz9V8a0͛5Rҁ0lㇷKZWjлB\D+_?;MYԴݸD ΍9PE:3fD [th|KBW_$}Seح]bK H?L1}id~2_pQui!.F9ias螓YXqHdͅW럧.f'e8e@֧wɊD| _DZg獛,2kL(U3osvаbΔR/6g&M? x}sWt[輯µĩ:ݩU?W#t0~`ѣIJڰ`3mF!OwQr`vOKqxy@w弟K'5|q/[+Fi7n\X<ޣN` &cfi=kg YyS>^\!lbA7ud ow˸<}piU3/Ib=ʴVvϡTHK 1!j%-xGkYeVN[*iQ9"P~y :3i.=+cƋrT#M"![YX"-WTT*5;sAe.OA?%!޿D{=Pdb:?Z;E7{> ɡUiT6e۝uYɒz J|ZKBDT3;3t{naT/K:|k5R=.(\c6pƂȹIXI8[hJܣ6Ų!NHkBέԴY'ûdN zmFiZrZF KX]Mute5x;]!Odsޅ]]Q=4j! -"^ZT>:H5Ψ9>5Ӓ#wƉo',GlئtS@+,PFvs]kACNru^yϥo4oo0o}mq)htJl-FA(/޲[7W1U '\Et3#lvXjiU d)/F-:@|1jblu hɮR_vĈ|CjСYHvŭ+΅` ʐc i[W qi#Z\_1k!L XBUmx䁢?ї')͏3_Pv&S|+._R(wN C{ݜB< R=6=}ڜ^gܯ@& |++h>*ꘀ Ymof|)mes 55i+g6x5,3&SZtR9+Ǩ[Wpg UM%^0,}ZAYl>S2Y-5ą;t,om[^"@$6JWprWu;THBƳZ76 .ۢ:pWb]I)ꪂ BYy jFmqǗz1!=r Za=^ V:u'ӏV|Nt4O l(~=3 )] ʔBC/^}@te&? i;doZpj:E7Pss /z%"Y&_5oEskBrt; rDfhP?- nV=;bneR6]!*OzMwRmW]Nx'ɫc%,Xk C䣜yN%8/VRnjL3UהJ}mXhYc)6ec +#b.^%љt=Եt3mmct\y)EI/7SI#5%y;Zx&͡[=.FoA]f/,NzVZӴ.d*U(BFw])(Ļ ` pcIA@ʀ 8<֊M Z圦KՊꕷqF [4QN$,[ h'%#\or=~ƽ)"D[CWP*rw-mJwUDEC "iR<!/9Yס農npNM9HT "?[q3|HÕ\Ĩ'Jݪ!Udj097 ۾jP OܰTZ]aXVZ-pITWV g -1"})'Ek)\Pؕl1_ߨ Mx&7d]NP^xeF?l; )Kc}йr^e,.-V~Y|&|hZOWB%lhbX׾#w:-oRI6&Q=Ԕh; @U.!ͥd( &d9*fYAxS[Sjl*^91ՓM.-ME$VZ%#h5!A`R hf侷ND=s`C*rbaxgg}[?r|%JK>V`,kAQ/Wr"#5=h23/byhhSDK5oВq;JWjfF=sbJFkTY9>hd &, YgozolՖՑ-0GtNT,=te {r4axr4?0z&?ۘW NXӸA UaAzU]N_?[NF(ZJͯRK>RuF|8*U+SlJ>1(uJ:<0)m}]6icyCiaRy]=ayȘQSC~b _YO8(|/s=绪^.Dnެ?YC5 I$<͕Y'B#G{/0];v`o#ҧh3 >?"l\ʘKo ܲG:1خ`.3a {qjTglaݜ[͊Y|>1= W6p+!/|P>>QgWf0tC}Ĕ'0>qDZfю˭6hT/2uwODni^ް\`@K]Wu!#Ar˒n&vE`'8G7= +r3CЮ50׻&ݶK2R,Q^ `ծE@i*-Lt؊n׹ \8/v­,WluL?i;|AʙNM:W9@a!DAhLMn aɠ&M' kw0\pzz# }]'p2wk! 6K̽(9FxjfO531˜qxiZ!O/>G5~H֨4!5_/N|VӌSNY%o(`ײt'[VUgI%44:oCJ CB.AfJ?j۸ QvX>sNjw"ctle`KX9E >Q=dm;ojWOr8=*u=䷋ +d SlX顣6}Sٙx?a-bh`&=n'hf pkm- fd /H*G?X.wZ),S N#+yޤ;سғ/"mɃԿT5F+J>k;̚TQ𛎀Ge||?yqGUilc0~K,F7BVl =:6odƱaZ;MokBSN+HQ;dtt ]xS%2UD{)8d"9,AisAG% [ť͞ԇBHJ۸6p$B~F6T)A>ṭn:Gaمd=3ߓT-Eˈ&=x0xcgm8[R{ M0#V.EactIsow_-F^'*JOWwnr9!{`. ~p"eۜH9F_~w5+FNMf#*D px} E_}Ry-!^@Nϑ▩wsavtsE]ĉY[ ,tUY#lO,Ll9o3TIC[ mk `( o}Xqyq]c@_ Ѧw vWw:/S޲5T$MR59pʻimz[

!ڦ>辟My<7vi]n'kmq腔HQ%42 DtsW x>J0V8?ڙWNijǏ4*KyxG>޷ n-Gι~G93<~J_Ure8xs[Zv˄ُu #*[A3"/B Woq}wyhW)hI:VibDlAE ͺ?ޖՄJbr$YHr>%^QL2 غ)xY^1jarJ |u!q#CDc(mdĦ4;"\)jv'3$|XpmzDI;l%Ss6jcz1dBaC[RC1*Gmy w:-yH3s>FV /~1-L;L~U1I~̒q B&2-;i"/}ψWb>}F uuDqD%ОcrV1'y"I 5qi>Ob^8MAXsn}ٗy.tt0*!L}Eb<{DwYxIyxok9vU"h;Tt~cAH8'k8zS1-C\@NL1IјH8)$gp>P>銲dAQCirAr QXFt˽xY<EgoDSޓA^ 3k d "VaL$JIMnscֺZѼ~6, ;~֛N|] _ iܔgtgqC[7bc3.O.4&C?ѤQ6%w4DRp^$ԁ>.5M)<ul(T'=:tmԳN&JS4`'A'W5}k͔Kܮ(7jsw@_;'zoy,>c+%@ {A^Kmh@`~D2eojk/L2p-> stream xڍ4k6LDwщ{o F̌;!IE5z5 䴜Z߷fZ]]$sqR*ZZ\ Ƣ@˱uAP "/ )(I*N'/@ Bis7@襜=`[8"ߏ&Kf ? GlimA-'K0L"p';# j 4A0 dEj=@ Sd w7!\\!V ( PsA4VӀ Ws\\W 0gsKK'Ggs'b;jp8b7w3;[ ( +0G0 v8``_9AYb%aXCA{ru'w EՙSvq)Heaـ^ (|@h{:Pr#8x;;94@>`kf +V`K8d`Ĉ=F@q><#& #ԑS՗4`?JII'7;7 /7? Rus_TX;h<  Nq~OK /(ߊd]3iћ;<@+*N}VY]W7GFa`:ni}`H uع!q ةX:YZ>n^>9jDL7// V ?q#\z>k'(֯3pJR S!tj N$b 8-~#?1NK?%qt+V\N<Nkۿ+_N "ÿ ߐ /H8-_Qļk_\\!m@Tww!7wI6^ KW(qmqG@ K)'K ʠr rw!ՖX0^8t2zܸU @LA+rëamiKp$ucgm6gVNd6#I돏jP=4bכ o.68/-" V/@]tF~>l"n&q7+4[$K:} 4Z$TAlXȇPcMCò`Iovn8bz q+JST ys &YWm}JJlqoh$ㄘ*x -'ƽ-JR&P8w <-ӆr݉ihC?|A7pflJLaD\tQ@%WzCӳ(Un <}<^z8 ȑ}~òPV^᠁rM )5~ᘨxe]&8S1YC _qvYw98I]8ؐѻ@!kORp-mE% 7ɣJ4{;gPS$B=T47L`ۆpX|\R Ή_eʼnVjot3yw/vJyf=-*Wf~oz8?=mT*$}ۘ_^.6cM4YD=5q_d5펛e$Kjp yhrNJ[2̔7z炪ުPUx:7~qPX4YD+GUӉɊc rO1aG1 !ʏ׾߫*{TAfcHaa+VZUze+R΂Wn:+e%L.H S_8sHOʮS{})9Dv֚Iwt=Dp{|k lXXD7,a;*V:S)bݐem"e2헆w؜FܼdOk2=h5n .ErѴޔw,]ByFZ^nMwI5\pn=*Ҡ8 ʫwgh/2k6,TTh4>xyyJT"yѬ47g[LMJwf^i(cGpKR;oL^'};.(I©T=*]_ĕݗj?g)wdv?taS! <֋5k c6}E`u{ՀVB\@Mor>J!ZӀSJ`SIs*%} RBmK+3\!{Y7[g9 Q.i '5M/ #0:AhCn. G?Vz"ƅV;ٙWM8C|Mf'5Vćh)D>u>Δ}0͂:=?w'yI=N2Ԙ#&"4Ñlu^'7΍٧n'jN8q̝nɉUӺ+R͐ˋY@xuolsm`I:-ґW 'q&趋><X{5[=jk,Jc$JCoգV(Iſ/d'!ۗ+?=81;[>'TUre$@Y9W;`Y)Dwe¹1~gV"&#m `f.D]8N:kJٞ9OvX47BK͎<44 ,Bvx38Fohֆ@&IA븂X-FNY(x,)2.cҜ br&*X-X$]xZ]ROL fc$ݲCzĉc]׍Ұm|ƶ3=wBv' 9 ^*)Ts2\wU N)X=E*545g. :;d2+)>#\GyBcIۖ8\L2²U&E}3E6y gd=+?GWwq6YGG2 q~yyh1hXz, '0WvS3!Md G@mA0Fɏb>6(.X>ӉʰT)APDiQh_i;so_N"YIjT`h:s;~m]أb SR3s6?Rp-<:CnY{f3O{0k`+|xe)SBi' xJ%_劤vE [J`3th,.9^~YIR*N.j&pIX,)jM]aJPٸ^}-2HhnbLykMޤg5X\s8Ņo$/sSĽ1U6r|``:\=J'ylz%  UMҾB 퉈?FҫsT27n>?}ؒj*KAZ<".8.sHS}B?;_q\nxJç ~gH3.}B١9vTx!/VN]=~#i RwfhGFnFUEwi?1Fw(G- A{yxM?a|RёrkZ, +XTF 3 rBdXW&SAbᶊaլv~HyvMktE7g}?c1[7XTr0jCZ̰)Sa/rɉnJuaFe9?ŀijqc$g/߼}E%`L>%u0k@5-l>Rx:IcjFɍ o?FJrV"=R#IVExc Q^z0-Sbϣ.nl?MQ2h.5st&v)WLd޺e٫ w-.-6kmT?*H<` īxHH8̄r!JPFY|;.5V߽ٖ= Y@@ۙҹU_׼P# HYKjUEc*.jx2?4,t*z}v6QЗ{sBLqKj肚1T"k BM[} oƏ4O+rce_c[nĜy!J~sӷ >d(H-zOgOkzvZ|Xe /KԎe{ fO E/e`%SGKmm?ͬ)?CcE-Rhի8nmūɾU(]CvtG{]'z6G[bަnILz`ujN=)i: ]#Eq'Fm?ꪟ M"3' 4XIC橬~UdmDh6 " \ZW'B<\c>]FUn?5:V̎HU[R|)`NMLW f \oFH_q@_,tX"'X}-ڝ=4Kmkm;s.2D6+;66;IXbHюtXÃ).ώB}&dPݷ?|Rsee"j]v4{L1;g$h9&R: S_%?JSOfpfL`J Ǧ1'Ƹ[-ADO\T)o|v񫃲njڌ > %H͆=SϓT~'5lToVЦzP=s(fë0>N-(tR~wO=@]NC9_3 2t rvd/Pk۬q.fPC~™S;ӷ1&c&ak pjcæf>c4p+}*Tw BTSLn a-Ѫrޑf-ױ`1T,Ƨ򰅳u›7fEJ>K:h;TbKUp^s7ͧt˧ﷁZMLyCǘی]I oA'}].yObudsqj N?YU \ |\Pޏ ;h d,~-B'laSohڛ&HWOCg8)gH+k(g:s,yVJQ/&tGXTWD|>hя% NE=YIo7o+`ǫϧ¿+5}2 ~Ig⃇7kK(p$BUc?^Wŕi⁋S4~'q7 Iyw78V]FAXt}q؞G\۾١aoyVYH֪[ھ; 8ry0;t{I-O#c<֌]Dq%BSrmF.+;;gӿ1==e3&4py3/<;5O%2+*onS k!Beq!8L$eQH +/Ȃ6iȏFrJW|!F㓩*V2A=D$LոsZ]QoLJbWy ]x:Ѽp|3itBx?sv~r%X7#CFG5'WA})L7 5J)ƛtyƭ$i_P-F4E$&lw#9=r1ݼ.9`xm1DfQ2M4'>oGc8̥0rPbp]j&ZmxlZa=(8]jJۉògFeE# f <(_{ [/M,ҋߏR_? 2P\]5yGLN~eYRwG&̼%j8Aj&쟷# hOJZW@tc,xN_B`$!+ pU)vBrJ.*q(k7Ѿg,OsD"B# &|={=I)n>>xhjai/}?Kj 4y~[ ZǰV|Ox^Tc'uJ;K,&熼 mj,O"zb)tb~|bkgI4^;in5EC8Ƽ;HJf #87Ao/)UÅ:S_,-|NFbl|wdWC1wPWn.xװ {Nr=I+xK,qP+)9X G l^'K5{!ݺTFFgLJʴgrbxlyfUS0haxX嫉ϓzŐȦsvvDQbyY:Hd]Fyp`# I|M;qr |].@8sCn̵#rJr@ Za%œ컾p Ȑhm[WsS[#H%ȞCU 7-V"9a(*FK>;=P,oU=Ua}49溣\fIs&((֕̓KL91#є$Z`]Ќ8JOF$Zd+e#s`5nʖqf&Vz? '!|nq۟xX?/{F \1?=.<@]ڷzN/if7J Z&48H ^Ղo#U˓FnQWJP-#eLYlXH`G,*] v+S7}?Yʮa(udԹOu-NȗK>-g uʊ 0xh}&GysMf7cHB̴8 =Ά {*4YqASӪ)Y5ͳהau 1@s^8T;UepEtE5Pl2^9#;ZpvI価Cbu8qA;-[,JKTdCR”A RO2u^ڲW<ݝP3Gĸ vMA?0zcJ2)_r/:`OKG$|~&oe 0saԙTf=e=±W̠9'|otr\l\i |8\)]z˂OO5ivWq'5ڔd5q1 K endstream endobj 408 0 obj << /Length1 1449 /Length2 6404 /Length3 0 /Length 7383 /Filter /FlateDecode >> stream xڍt4\ v"Dt52{/c F̘!(A%DD'D/у%jDQ"|{Y}?{?p+8`(?X$ (HHKi @r0X8 )<00ǥNq騃B,E%b p!ᎀB°J(qYW%$~ n0  A:eE(pv@K zyy @ܰ(,p aX>Ѕ@ ]ؿ F('/\*p( D:0euHCCÐ9kODp`rCC>p3G=Umo>tA`Q8pu`@.bhQW1 Pnn0Wp z9w?˽Dy!HG_0=т&H'LCϥ_3@ . a_K ~hp ;.0 ߆``p$/0cހ~`ϛ%QHϿW,t(o_D+$$K!?3CP$p9qC ?Wg]%a QW'#UOⷝ/q#|x\4tPoW3_s{Ury" Hg?cU0G}/8}q~0_ˣ޻`/,]Q@|A +"/܀q\ P_; R%IzH€ h`.7g.[eaP© Tkգ />? sOQuWw,HXxdŸwhۺe|z%]0fGXRNxPܳ욥&&2xD)lDZr|跰&J40>ÉGPlzJwdnewW^Vgh[tq=tT/5WE-8_O\ ֓&Nm?*7Jc` Xќ|)̢e6>=J*6~jlݟmJӱFۯ20 2纗? qr/; l?72o(*XI({}&!K?Wn^hX3F(Zʵ>VqgKɘ5.w}eɄUGD|ms(B>)]oG{4yܼ\{7v'5xxoɔ Gz"Ek$qX}Xtմ'c?PuCĿ M1d>BM*q䜭r8CGSIoP- | \HԔHNjױQy6M+k}ry++rG9xtrF|qcLd$)I+L* YPo6]rbɸ n:1=n&$M`Ew\dSyM+~AB#Ytc/2t;F ˀ/³j,6{v( -z͏OLr^p(!43dWI OeC`>ȶ3ywuiXg+;R}US;TYOYo8q|rtVL|jU'>̤1ϙJw9+=C.~a߶ &פ`#SY;EK9]펻UԹK <ƶ~7?V;2nu*SJ>/&肐I:HNayL'ڮ.m3Vˁu|ge'|YB-16iTtزYEC77jy}gxu5F1DȰ+Klw4ٝ{:}>Va1,@,]/*hC2y\gUh0ZsQ/n.R8ƒ 3mM9]T0̗w8jC۩3veW (v 2Id잹ԅs҆r3x"|¹mVmt x o:2'Rƫ痗+uI!!|IbD\ыÎŴ7I[յkߵ<BysKK$V;se4|Sʄ#{DŞ<O3x EJ{1$ջPĖv y̚%yh40Ni]x/_HǵRC?Ntw2E DeKIl1g i/׺,5M`)2X6=E=x$Nay 36 sTw\?syŏD7;)s5ǙEu[*n>)_);dbrkCO`}Ϻ+XYM㝴p:;2D 3jOQ .Tx8'K4aoCGX>FN%{yU\'Ȅt˦!"/|Wa\؟+ E8m J8]^ PX?m{Ҙ%E͍vZNL;'WPʬ?'qQ٭ݕؿ?mc{]Nj~c>CcH筻y=7!߳x 72n+/ѳh Iz=u9Ztݝ 9Azrd *ӍX[%+W0z'9Y3iS]Cu Z[ټVʾbBːkp#=z\X~G1sðh'j𠂤Ѭi>F^G%*]3QהIŵo9DUo)/"LtNN]Z~/)]5;-x5f\fam t!Օ5Y7D2EODRmg0*PX~J))% yB,+\jDIm l|S5Q6YXp$.C3p'f.s᫉vUIȵџz NJxNF9v}@ ty$G kU>#N }Ǡw ; xwgY?Q991נcg,-ucf/H;lnZLS UЯ9pvqc-*Y>M{Bh+E.*Q}Σ#Lx$_ѶX:E ?QYű|fyuٹѤ ; [.w*+cjI K¸Cx2̖[ȼu'N7C_@Dbjt֫+ryet%5W!eBe% 00=poybo=_z8X*쏺15tK[걤jUpCc)m :kί{Hk5&τ}_Yֱ'b(S=AGB7aբ;FK2ON3f"~nJV eLeCբ :;tKO ceUR[,,N)YHs _%cxf/n1{!'?3Hh֮yT;18,]qUnӺrsqUC^Ƶn74_H>8OS%rSzyDrG: 4bu_\ڇKlz{Oxy3`%@J'#Y 3*CLa9OnGLGʯ'WuŸQyOBdw.o{k/P 9niRd[A"#X֤ G,5 3bcwxZ; )ߞ]A zR+h4VN%' fdHx-2[D9>8 PtHxT}"rx/Zׇ1Xb{Ĕ콗Lq3itjY ,WK:L)Ͽ A{zw3b🎪? l\MI+}MCK0SHoxlUQ>\fXyNk̢Gt>WAHSkuq3څ}NpAm8Lt¨spVLBvGg4|4R2%P /I *lo`| x3E19;1E'kk'6-ȂFo<1v! QmZK]O{j3SK(-﫛y{;TޫBڝ iI!4@,#ԙz( c8F+4E*yϻ겝^ɮȚ}=f|V5i6Fď‘ NJwDB S@%+ m~}J?!{ yG<+Vt9siL]~NXLt7G#J>*x|Բ>H`םba-®\3]ccA gל ֪_,VwE]<٣݂ORɁkK:dsB + ά(rPnsc9JETw嫂/uOX h1ǃ*Vb@ÊzJm&9fxAE?S m-mTx ` L9P _ӄ)I;Ƌ]lt eMlRڨq <#*BItTVgĺ^@p&A_gcdFkX2ꏩ_5lϱ4rW8]kC$ݴ}HL,P߂Hׄ2AXW l?鼠;3\5)~U^q&QidWn୚z'} \GnO;W`y0o8OpPRZzN_y9pxI%YqbzO4B-m:|Ė:ՠ/TB1y*3wW{y[vx#;a=8ĒRVjia *[!'P \%yUן6f 3uK1ryVs]Wr=CٝM+˻7{E],ÿ R{6!Rm(c_(ƅ2>koZSf⚚)8oNGT;o|0؈;7te iM#Zu mU?oݭ"$C,~+Od'V]u4^;yiq endstream endobj 410 0 obj << /Length1 2315 /Length2 14367 /Length3 0 /Length 15705 /Filter /FlateDecode >> stream xڍeT -Ŋ-;<݋.ݥw+9=߽?I\s7 W0710rdAFFfFF&$ eo ʒ![#Llb*ce t0 6.;##V\a# 4CvڿdW N;@bȀM,^2JV#{ Acjoo:991-lMhN{S!/Yѿ(ʦTJVN`[#b`di`ihd xPYYc,?@_ ; ,.K1 '*`lO[e6z;!`Dahg` cWFX YYXY!U0.76XEb q0Ջ09Jbm5hu0pS B F&K_F)8_`7934wmA$i%ZPF32@vFFT O}D4pC7\6#+2E&Qs-k[@]c2/["c+T27: {ˮXJ(Pbo`($^C, ]>z#ѽlcr^^SXXLl-_+ FO8`iex!0ETX@D 6P7b~#P7EEo~#&P7b%~ 2K%ܿeKL%o*F/T~|j"^F/ E _x?C@۝/GV{11P4P4u6}[  ?___[Q ߑY_\-_& 9ż8[oK!/oG3_@ߍq7272PfHmϠN' mߵ 당˥%p/W菣x!od ?K/e:q/$cz |μDr5'˃e~9 -Zpo p=IUgEۈQJO[& &+hs:w]MRrMO"oB5| =vCH6 HUh%OގohңDNU5DU]2Yk4!MEF~wT~[a!)dR;",9)nbo?/4q8˱*Vw(#Dӻuv?HX%|K6eF!鼗wX1g>z{]-:":P6ps2.p{Ryn&Ֆi8(p? V%OIY  E$N\0|e(#0Ɋ^Y6z镘9iB{F)/JF8EGMY꣐JqˏZfh[>KU'STf8)s+QD& @@MW7_?&Ql 4}U7' ',(7.A7b~)yPn,]E$ݧ?;4R>2q7t|{RMIFT1s^Mk~5`(Siҍ_XÈS)|mroMi)߮XsL.^Xg?6GTuy&^{$VQ(esN}ѫR=M\ |w֧3^o3B*ŠG] yRY{ytwZc1"lWuq%a90BPCn3NJNoK})^K;ZW%>h ruJa~S՟kGm( KL6Q )[M.!ي pm̑Կ [+L7̔1dƇT ȀLTlɈp2&:* ilqa ]t u&0Jg38xK85<'m_j'obVoeYMZ/& $~}YJ2Υ4 Eo &W~-ڝbx\%ۉ/G2s],cRe"qT튮==/=NYG6GCi1da7*R:A}Gkk]iw%,zD7:ZS_XY<#,^|v\ES=(SZ櫘G19̕Qzq8ٙ 8t=h(j}^,=q]-'F&8ʂ˽3O`%62gg@=wSu@*_F m)N4hCd[J9ZT$" J/$ m gIQ4n?oN7euڌ.?hm#T&' rMIkF÷:hUaL*QTfctà M?9?͘S%(][hGBޜjj%fQ|",iOJHC=>STܪ{{v!jFĠZ I̕= ӊ@eH}<Լ?RJ]PIp;LmVI"c$<ƒCYGd{;RόNraOy#q-:m<آcA P?I̟QIšX LŲqƧO_/@ZG7D۹oWt/6 dX:.uPѩlҭW %̴yJMX Gwsk6 ;hwɘ~A+Z : w59EolHq}ϟ?ԙֈefZB#rW.v<PT;n03B)xΙp>dٝyt*CU jfЧ7G9*a#g"g4ZqG#9gj@4cj!CJ74`NQvQxYLQAtaF П?>o?U`ϊGGk",wnsz:r:h@Jע̹+ v ̚h Afu^oD_Sp3Kmob:p^kg-#qGwױ³ĵo^U"Je8z[$ ڌir@Ot!v82g}+&KLڢ- k'#:$W, yQXOv8u%ZW =~ciH=?~ΩX'.-vZnQ|kj2rۆ[5,iGxGKL\QϜfQY IU :;an+3p>h%hpX~ќ?J#xɔv#]8 Af2 %G"qI~HOZZ;=gpz/' =1ZeS<,cW*fcG:{@Q2͜\! ,^Dxa.:w:DuǚbK$HP50l=m|<+΅`]ؗ TVF"ou :5f K3=6ܷ/Tn*A#߉G˶+4h!QQ>a?Rߙ%oq&SXn- fȾBgsX|TA/l$&1$ip!g@}IqQ<,[p?ejﭖ\Dx ݦf&BDpSbiZ㹓k9Rmdf[nQU^-6241@u"C3aR*%=a0PIUbzƪ "t~_C@FJ=:ߕH@m NUqk1R!;C]7ZG.r١2jWhLWƚ!-–6X$zs 3g+^]yz BqӢCtƔ.u1ᯌ]c J<kɦ&^1JA()5>KjLY34^_&K.<ɴ|,w ]oiMEÜY~̣͟yzH벻ZBH#M<Ӏ&-џ)hĴ0eMEC#Q+BmA yլBγN xl)Ȗ'B|_U[hmtkNq+h#ig1(LIX5 h'I@[In@p0wI|5յ")t9cvhis1V_TNz:>>qF} ӷ#CƛfCzm"]UAt/) 0? 'a1)7d,r$0%ne$V1=zp;"*ҟk^ɧ]hIte8&w| &*Rh.a] }J VǙd4wdi+^IP-) (n ;ELzkGHm 7!Y9h ysa'c9ZZQ*`Yd)ST p 9jwdFRIQ=)SRbH{W1Cr\8x:ӮP?"*L g-!P0 1M<@R~ZXnZ0\ 4_>aCkT8| [VmtK+*p3- )q$Z~07>а/G<~sYjOn8Shq ^T_󺾀rhtN%N$- 0s'f&<r%Fb OgY=+o[N =957w^H^f| w=L9^STͬ@I&gBۘ @@a{ G&yIҌriۇC5BUJC&%~2aayI |JOxk݄~DLCe:{⼊NQ.=/+o?@zh jn{i-SnjyW¾B:@ϸkJ)IMini+w8)e|"LX,ZC="'Um^da?pa՞+g(Y^ G_1^Ɋ#4'G~SP v; y|tzIW]p8} LDml M4[Bel{:vŵXtҩ'a0%w#)SRY{?ӯ&;Ǩo zE4Ű荎!Co <[ ;!$UCSuם)`5*G /T=$Y' y4+_yp|-v"VԡMyr@A+ex [,1$OI!.Ns+t#eK"[p:jn!a鴠 :طCZftCtSg'H_>'ė~YLc|#%-av ysrA-N"Åq*ҬW2Psx.!Q"8t <{5X H l~RvNZXd,(%HkbYD+h.0Ld_ S BzU-kěO֕P$Tr>UʇD2$yeT-Gt1!/xF|zVM&;@SVDHw!CTdgF&ڋ+$,ksRJNlU *ճ;Eњ%#H11,GJdԀAH5ۓ74^sJm VeÎ^kOQd^_+ɄG)vmINzʉ;؏! .|,"זtյEتw CJcz\P*=@l<.F9DBȣ4Ԍ yJA8gH{@&M@Pp=|O\ґkTSt)邬 ω jE~m%\|´K,y+vth8.³}pLj]#dO@mh?7l|a ` !?"qgulJmxF/.LDΏlm+c ZDn<vo++8i#~p(z#u,%+J vդt\JMB9xWfv2VYπIG3[}y*zk*iATrCCb*Jc#%xi!Kc/.Mޘ Nޓw!S3F̏F4;kUE?oZgA ,`x`t8oFޖݚOe1A d<#.v2ж1^$оqg3J6_\P |v.-J)124GݙyD#I,ccE\bԤ*Zw‹=sdkkD~dO(wDejs%߶QUw( @c4 !^^zh.w_\FM4b7`Mֿe &]5zo8r>O+=nN9<ǡ*[I⥼4 P\0tQ処P?qz V)o>x^4+JOR<g ͹K:~VD.2:)pbl+\5a/# p'~_ӡYZQMXb/PX>EZX,LmB{5-١'FA3#Xp$O$DIf3=`yc0h ..tڳ )z;9^ws[gU]@ŕgNfSYY{kMQ {j$HäO2o*F%~4$FkY/ɻM|nw_L3ih͸)8qEW/F/ArR#'Hr2 gMz*Jk]ٕ`ĸJ./5%~̚j`Q}cWIKm1tȿ""շ5<˰@%M,D%&{6YhDݱ_TT)%ZM k:UWYPW@iPR]2b#tWp$D(ތ" 3"%J=.{ʻGkiOᨁn@a&Eq KZN>GPS"2frBoD;g{#p_ A feܳ_,ȌTY]uӟ,+Ǭ/ +ILݯRBQ%' -ȫee+渋Z"j8f r]/͈QP^^_ ;,q` )=<|Ȩ<~ ؖ_P -n۹ 6w?3=gi3L姷|]Q\M#{V+h_R1o=$ew7;U `H+:G{Wew{ 7$;|Tm~ٝ5F+ 7ZaGKNdZ)6g'c.+X9H@-%l:gd) ͶFOox[vj,ěSpg.'||>"lԥJݯ1sd\A˰+M2>/`VGxsw1#aroP׷n&,`>ZCȌ .vE!Q"". P:gGͬu]7~}Ȕ*/›AÔPK3q0?I,RQ-$Icj?п H)[s;DX┄+y||U!8KQsQs sE6Y ،",T n,֎KRiSwVhNCCDGk1ҡ~ aˉ~ˌG)-_g!k٘rc0'0W[ès88N.ӈHb&8rTMos-m?H㽠Ir"Nc˧fSt]QvqKJtGtLE0[Bd#n/&k>UYA17S{"b-fc!H[9 ;hH`49<./'|goJ]bEk״ŎR|DLݣjNrNF+N3ȅ}yߐ}J.dF`gep S4 RḞ^|-6!u䠳.ú$Ha? PJfs vj9p9츷B5xXt_UQR'ZzVi ;9-lS ܃6O 5Nbj JIS\zsؔAŤ/dK*R`be#D^6>دk 3$Y+P2wشt%ހWNk<ח+G R蕴T wt:ZB;v`@(U~[RUw.RyjH) FP"C9]( _IdZǦ{=JiY wQHf$-02cT5*E+]DTa]xe&[2vlq3HFVJ  xכdU[vN.1=> 4Q"2p^d oլ;m!djD-ԥԯU-pv]w? ZA%;y *v#Vz\2w`H}y ء$\IѴl|ȗaÖ4cIb4$7wã/OuYxUȕ$B~M k~q- bǟE$'1s|\Lx}ǔ_lfzoz39Nze cP_e&y]XN powC1N̳'!.Ӯq'tƎ=\Qj%6JubeA>a6) n;DyGQ5#y˱9/lneO&;i&UИ@TOue$h VN^{ #R[Xҙ -/Lr)Mp H`i6Xkbj /SxjKఢZ\5 o:; TUNA7+vҾ{wIJ?7X,22ͩGsb]L\U~K #7%\dF4޾mm/ a̛Qsh2ӮwP?n2 ϲӼRɅqlBih =?y1ZjR^Mz't1Z jWeD]k尮]}b)yx3vGR^gd򙛚/^ܧA!!|-OْЪ)Ib5cb- 5 T?_ Cp[[ܓJxr(bS6?]mDEZSEoJt{06[:IM~j !҇aGk|Gۭ] >nyWlm]PfN1 $Tklڙ7XM*hu ӤME_k#qߎ䳺/Аtmo&g*ύ;','d4HIR؜Jzn),qE|.@ YA3i7+)ltlc.S-SnEnnr0ڻg$7؋c jM!~s py_@aފV=0nv Ɋ%=tS z_Q:f)=VGՕ`ww?׉0Wi€b@(*ya41![cIyRQ}:ɒ%;&Zi] ;}g>cM|Y@^ӉWuM; fFW?Oyh .߬[W,Cu$*+aI_\,c.ssme7ğJ m}M .FH'BZО"Iq@& ^ ;JX'DiqK%~f~rRQKy3<_KL Z}??>BRӴ`v ĝ3%XoLwP")kC [{,8{f-=8QB *֏ Ѹ"}$KV3\b$'|=3 L-"z!~@4NG:!8x߉/ tUO6ܿl?RDC4Ϗ\PҦ"0/}#>ci:@Zwə:xrU^#z m.%.>Z:fdo~?V'V*PR ϸ)$M~oWKI' bJ]Yq]8k7n{/iQQe?ښ^nȓPm0Lߏgk>hmQgc edU]XՉ'Z,SW#X|{>V>q_w $} RuE:LJD}!\PEMrH_%wM`OI+x7tӡ&aqhlBKSKš; <&mL/R{`K{k:<@W̕anV@lY5j2< endstream endobj 412 0 obj << /Length1 2068 /Length2 10942 /Length3 0 /Length 12165 /Filter /FlateDecode >> stream xڍP\4Hn!`ap3.A݃[p{s䞜{꽢 kﵺf(H @VL @n0H` ? $ U=ڊ_&Bv }LXb)cmt0ع8@3Ck;n #QY۸ځML @eH ` ` [dLA%kC0BP:8p32:;;3[3Xۙ|8L {GY}Kzc@((Y;8ہdeq2 J9_>?#Og}CCkK}+W lȉJ3880Է;- ֮PCZA{C;==&9g+#!kKK= @we[Y;[`+#?1raT:$6~L@6  @.PvdC ` i6A ;v +F`Cl;:D 2!#`vh!'mȐY[Y6e%i?ZAAk= `rp8ظ#OJV:q{8^jg4@{>ـ_Lϋ[şT[ -@ 2֐5_S5_k-2;ZVA(V&agbKl聸,9b?U nwR+Ck?ogܘ jrs VA`CQ7qQEQ71 Q7AK&Hv' !NH>ɠ ~+Q7A&Hjdy$od7'F!_пRɿR? mBJ,R,#dbZA_zHmֿCK 9:j@6_AށBH7vBHBH!!$od/T/TOy7t|.A?r"XU p;MUgAp]RJMY*f1kM[t۪&qe'3!6yvyO:*S-N;߮ l/^OXi :wUmd%ˏ;Tڨd*~JR5x £Όη/[Iefo*6ު-lvዚ B,an:-5V^ku q*aå@p6RE] Cr}s@D*/NINDvd`iht":nkTƂOh!"R{&,LM#ioĠJ=jl"T% |a="V;VQ62-WcJJokv{9)ћ5T3~46/~0vۥT3H$$\@\#P[8kSpKζU"+=S15aSiɡx:O"%T9C1b~>$b5qK]1ħ_G)q^Ƚ3sdy5PUXk!9z-S~0)ܩ?4~SLU3@` ]a9dQMj'I?bu 2]L3j[s&j2# ޼JL `Ӗa8*RPO]/,xn_w%\;n Dօ3NHQz jV&Oaonϟfdx//]8qG ,( (~=m֣LG1W+88‚tGIh9`׈Txߓ |(o6YU d;zh ffr=rb?~Qj*'=`svt|DJ TC@˫Afkm[>! 7DtkO:q;W:!{DT Xn0}l޼OUI\ů8TdXi¯$2gFj4nF_Qq˅4e ^Lu bu&8S*fU.g&K_&p9 60V4)/j8IS0uX(Y^WH)` Mj&piCEٝvCkG')gDVߧMZov6) O<CCE I [Տ4$"/R GSpk^V$ގJ̢aFmjysK0m9Z{LǖsO 1 7ĆoËxsAk6,ƂVkQfwI|nayf8Xa]zG,gaံY>X:yNAFxt&-)ɒWwx&;NϹ_#Z'}5^XոU tU[Zo/TDy*^Big&F"i_*+]ƕR.oUҊ=$ȳcںhlNK]WA++@;$"d)8?ѶX qВsOzR7+gSƽr࿝ͷIyoNMǴ@jl*A7 *.er۲{c$c.f#8'"^r747k]_@pQp]kޛxa Lǫi/j:д,o&n뫘Vǥc K2n%zbFXԙh; 㓤2S}4E}[K?56jXkB?i~,.֗0Rͻk7)B﹩HX(Ld)>rFidP|z4U;}rT} |g*G!rTۅ|\aIqP2hvz@N^Wþ7h)0R0g݇fW?e3aIag5A 7xmMhp+0I2e92gMx}`p.9|Ryr9oۙx+Ξc"xb sV+yUF[&E ԺFɚ* HXj ,c+&p䰷Xݡs6 ."/Qw_udOva}7y\=9wٲ`UY(YJ@{uUKd'Xk |;\©>B'aJKUxy0{w@k6zk$q{iA ^C\iIYkm+ߛp{.m==ЎZF53ˋJ=6y׊.WoKN:s7떁хtb9tr\<]4O,~>k$OT*_ᜋ/Ftj=^^PJ/~LEI]UeƖ9ERfn[hJYr~zB3&kBCBkÜ(H=1+c{BM.DaiBXyiCQk;Fͧ,/+ fvmm::8˞HXJHI&OHo]r/ '7`4s]g[Ew/!)5#\p\a ܃jw̖oO#yϲ #4o.]+U^T>ٹ[a[MamR.BId}pyusbnwm_R=*=ab,N4FfB>%M,PQHY lKmw|3A6-(C,CieN&@[QIUm:̶}1tޖ'16"} UYBq˫!I@sWV{U@:57칳44TeW/wс+ l}]ěy[0[(K fS0}Ú蒍{݀?0@:chWܝ5 =1kC[5Z:s/& E,ɮ spP%W睞yU:"Q*iרd+ 4߸D ;g[&4EO-.z":DUOK:\-?.k2S=r|Eu#E>Ձ~|Nd.ImY@G(d,=T_x)ő=ԴzfPJA%M0 HuO|-Cc9:SYGRE2A`FVBPfΌG(| nsIM> 9%W9k0x$TRcIޟ2|qB,篦#9h;a}b4ȅT[UA#DSwM\B !E zK/g"gz} /COyHVNVCycuPJg3L"4Y,gS~p?b"|qW$UcD^hH-prO ZrSUd b{ cWty,_ B(X&-ȯ9oŮ!lEo/b$fOQQ@E /0-Y r5=I'-44=|lEp6WBvÃ&Vh5"m \@ץO&?WT`WRrїNlhcΔsV~0Aq|_JrjB30gU Nq2Ew |ɿp(q N%Y{B%9)K1.Y5$옒Q? a /c,9l)ziBb6m)S㐒 XAstbJcx_bʤlH5M赐P2VxOvqjK0P߀?\l(s S)QrapSo=Q,ˌp8KY֎QyODOadGl.gx:we(R Wrjսaėez2LAs.dߊCbd,/j3%/Be < MzR4! Ll_rLJX', ./P~JQ&L_j;keZ scwȎyoSBf佥CS|L{zXqvq';.VJR!1!#|eozr3*L*1kX rSwk͓`-r:HXXܘ? 1e.@wûq-ATVIyJ^8ˍt*$fv`"l2VΡ W Gld,Nٕc&Z$<̚r(Ebג)l{KIq*iPM)cE?*qrU#8̵ LL{׷n2HmN1b̆\"A &z+YULe)39fb9ڊš]]|oJ/rթdp#h`w8BnҘ}b]b$B4rC34Q(;.GqьP6j(C!\ez Xx*j@9,?h{uMVm1e> éax˷fg431zH!BteZ$7Z`%QҚtIض*k[єjm7wckk$qw|\ʺѫE*-~׸bsM_ߞ%rUrpwTMDV'qs{.HH>YU s&ygp-}9 .Jߎ ^$U)>YgTc4mn~#dEʐ˛qi+e*_ qc] /;*{lJVׄEYꮥRr*bdsɥ{ ܿ̐b%-t}-r>^<%:NOX|sV/\E.8% ޲d,pzs#T!LKҭcBQXyOfÀpKJ^3YK+-VVr[&p)Ҫ\9Y@J%ne'-Rse_+2hSxK SB-7}o=/$| 3JZHXdÃkQ}a+7p%&_'pT.`cwI1T284 OڗjM39W쯨Xu'G -q夺ϓIMb-IR\v=dz%n!laZ~-+M-迱=߬J0T[ <-LKFxLJ^hnp+[[2&~_q%typ7{&B;!Zرct>ŜL5cIڒ})5:HVcԯ*Dddyo$x(¨5Ug#- ^}?B#ܦ'犏SvDyT^Lꬻx%A"Q"ᓣe?6wfS:{]^D2k$ sn>}A^(xY ^3%-b{· PhjYBn%vʐvc'RZ~~q^-aw'|=Bs"ʄ,k? L^Lgǜ( ?Ty覞v(s_ #&1t7~b~{&0^*у*`vXL ఽxwM-\&Gqh^ؘl1ݪyb~4q7DN0|ÈE։?Yށ-vڕ35A=3bW/70e}N#0aY߁*Ne%CY[7xhRBy[4i/WAt~AbA; ̝EmU-|Gݪe--)En,V#tzyEcl5ZC6ǯ]Ӵ{Js2`a$_p(j_{9es~\WV,>a+ gU|l+ڗ0|J&ԐG\we׻ul([a 8 x+I;qީ,Ow=V~TAk? ^(}ĊzV U8F(ue,^t#ZhB1`  lH.DŽ^/$ap9Mv\?[mj;}z,>AH!cRe/pKr4rZS9n}G7!C͝њ;7]TNy @L[r ?t/r]׏C*#]4J@eUy'yP]]:~ .b[(#v-HQV p.a UD /gY8Ͷ[b/nnn0}l(C&nhogR'(H'(K9=@Q6<݉ڭ-ϬɰX,]dNXW2%f5p7?s % P$€%>_rcÞ%H];O?TL;APℓ6dLҊEc)Zw *My5 =eP Md~!lR?I3QQad3(%R3$#_j+""/<HH ?h&F[>OwmAQݽ巽"|3鎈s|F?T)]?-!A͸jnNa5oO%|SB%W* YP:`urca,;(~, wDUjdH(DmtRQ $C̑HdYnj]"\!7n/_/UԂFhD+z_SaBT.k: WO{w($K|GKM^!b"8՚5Q~J%h1seC:#L ȣRlC@=PG6!N$d{1\꘷č]ps3l6R >fJuG˃R4-H*λZ#CjX :} y*_5OZ=ձXۊC/3t}M/#(EV(NAgUaWݻAK{#}H2.l Y_W9H i^0f?1_~oAƭ>ǁ/%>ݷ,'z!~oE-{>Iʣ9o":GZz){2D1 NN%s49He ]y.ǔ5b108z=$QFfKC?FO¿fn*NTp"h}O0d{pٯ @aSU|֩Pʠ.%g5.)9f QLG !)jKQƀEYx؉: C׻{8hۏP#{?lVsed@N;;'Z|-嬫M>HuޒM.wG49vrjۆm/R֗Tr͵0| ~`l+=Yd? H}5[( $ʷdd8A><'˅r"Kb8V endstream endobj 414 0 obj << /Length1 1550 /Length2 7282 /Length3 0 /Length 8290 /Filter /FlateDecode >> stream xڍT6Lw#]K.]R!KR% -!]҂(ݍ4/g}kfk{YxdmE8̍ fATZ.d?܀?NgDP`+0bP'@KQˍ`Err[yXA (@W0 u%W>+lÝ!07W_'E@|apO %݅}Qtofq@Q? *2߫ql@W+ @nkO{3|?x? '!Ü>e>Y#Y4핓{|x[,&dS+S);k=;ϝ:Yed9iTf&dNg%=t1A,n 򂘕? =3I|@V0$RӉvUW-i$?Vo8x MMأxd@"NLy-OV$I;ĝn;al?֘^+V[j!_Cqls(2xJGQd-RĨѕ+ !hDI.>Z<$ rvM~#(֣*x-"teG\p- xĶvCSTi-Z{^$K6K/B5+x ix\4M/^}9U翝ZYzEAX!QnF;գ|?2뙳?} cQj)k-,>pm5 ꩙>CqmK_3v?L?a=u2_c!RqvS=#u.SCuDieO2'AtMmlԣа]<|Wq.VA/ݤ:IsPb纒{lgUǏ^ottMY~s>qc0E\xyhOdWqP&o ٵ+};IBQ#88~:s4!\7{(}kJ胄i'b''bkx5 YiuKw \Ν.?2|*yVew^@]QY: 3i. {2"vT,I@C+7uJY:.}4Z[];aig[I'GZ)dt}0b|X]"w5Vj ro۾sf!Lp]0TI[+*TY]a6atpqR=\ՠj- {lH%Y6iTŶdG6(PRg}=Zֹՙfɓ+t;mu;d-|ddOKkH aצ{M^`CJU|Kow^]ȎQ/GĈ7Ԕ=hR[n$]li9l';6@R-ޜ;DOP.fdM/Z}d}ј@yc" mt* ˬ`1.:꬝k!Tݙl!zA:V;Ѷ0?<\w.MkM4=fJqѢJ2`Z B讼D)_rg=wDmZEa+E? ޟ}^i(V4~a=l^I:TE1܁i|pAjp6= QS)Jd #%~۪*t`i2',*#&:(MLX:Ibgj ;؀['o{a3DX>fs/~z㘛̧rk86[>gж|v-)s3IZ"olg,`\xk()sU`'z 6TrZ*/bEMlxgl1[$}&;BK3nzîuw{u `X}n̲ m~ ٳl\7.qvG~SFx8ŠHwE_%"9);;720unpߎ>kop /O/h凲ORa T|2 a]8۷슚wC^gO)lSRFtycѾ,ǪD0DsܥIf:h) xy$8 Cy!iHxҠu޾}=`؈ Zy,Bá)5]Xlndiv=ZW&.E5oRY@cK>stz=dLcj~#;@~F2wv }6 sʛq|=ʅMcP-$qu]LL[6<>sO~Ş(s+g|5ץX62!d^<: C^$w%`VE^`EMMH6C= n1>&SJV{*w撱}oJlB;SunNiLM4V'ΉqHeKma %*jc[|#L$lx exbڐPRGjAS ݕ&>^QzݡFR>: Hi.-N0uhPRu¶x $?qđkV2r-OΪW9$y+Q>}G]Ee{5&hԊCo''[mt5OC{dRD>Thx)ۿNJrb [.vbjZ0(>Uo,-7Ӄv^Eu1Ζ2u;{QC+R= R$keۣ&;xZ7Oc/v9+w~t +tFN_Zj|!)OD"%O:\S,0[_5rz-¢Pf DWYYR_y B:r t3gո[f. ] \ecY66PdMՑ6)v՘ exSS;m9=N@E!$_~TP9Zϗԝ`j8;=YfeH2 gҥF:(*א4{h:0 Ԑ ߌ"4PDbۓq[PBTD fYUZIE"s +qʩH.i jo+h,o]zSn0> Un2S[*CV6vJISxD8LefY=,lE),ٟ:=2 m>q 2S^ٛf~85/:bGp%%}u6A޻+שֽyeδt0e"XS>z#_ m!ktK<ě.Abo[b҅ZF%9?dz\3MnR*bNǎhEz&DX6DW(]Q4Tΰ@?]- }(|3GLiA͖2xΝ&_WuF_JN]9Wu 6=, :af-`S*9S{e~?A׏ُMy#YZZ5E'6胎9X; Yρ97SG\(* ywc[Jk4(\E^G'3EZ$h!cصv[<=2vNѲ֌oR(; QwE7`ԝf̬l1kT n̮'H,~R4Ia+1[Gca?TaBt8ɥaw8KOe"MoFwm4:RO}$jis0ihg}09ar0PeL*B{dwEФ> tjmQrNDFPq`Ηx**|+S:TrGܼc1A< yF kAKx+jd#O$ckPUg6߰+~# @ v/ \c֚@ޢ~>"TN6Ub9%!$m PN/Dv$ҝ7iLLCO$9g~X e+π|A :TU:ř%CJUIٸ< /#;Ϳu|8#U($y2S4Wz}lFSD/5L6G8;VX@QĢd /C]/OO,dHR'9L'k=Mw?]ž05esHplwyr8ORHz,8I O=B60|4',>g~im.>ӟӞI}B$3Hh yD cfݜOkEcR~Ep R +v $I@ clBZ wihLeӴ&-F,\ܯ \"H\ ܐ-t0U/`BAs.8yIAzYz^ROޥF0sua w֠Qƞ8Cv> J=ł'%@zeO`\Z߭"25*=B1)*!@Cv/e ;B-[Qf)eﶇ]!Fۅ -Rc(ԡ^]MA0F"5!\wyЅhNmg/.'[ Kq6o1UW;<pdA l$ i` endstream endobj 416 0 obj << /Length1 2856 /Length2 20405 /Length3 0 /Length 22035 /Filter /FlateDecode >> stream xڌT  [  nn>l=|ޚ')Pޕ `e`feeGR+G:we&`C{- `ge3?@dP`:]AVs'֌;@ 23(Z'@@W A+hlbl)DZT.@gw9௔&vRcF[\Psp0q[fotO1#ؘ _@;99{- [ @IJӕ`bodkb 6 @JT`\̜A.. ۿrd+ ̒vv@{WIf{\{{" _i9h؃܀2؀EHe@W+++/;zYu#o%_bp~> p@? puv_0L {b0 O+xxm~bIU MRW)& a0sp8x|oo nēp'p?sAE4_ u/#)7[ۿ1ћ؁lO+x3aMYg9je\M"joio!A.R O2omA@e_ +gfS\[o(io`sqLMXa90;]H "?"X#^o+E7b,ҿE7F`.ro(F`.J"^0E7sQ\~#0E7s\~#0E_4u&fW5s_W^`&&.f ?;? W(# rWpLSjp]LMl_V_ٿ\d3gW> '_;? p?Hc:]Ŀ5'i`kY6};__z'7\.,@K`z˿x&~+/G+`fjk7cnpmlZzp>gX+wGۻٙu9[A 8& 8Qj N;<?L~\XG[?L8N/t76_BWMeK8a@;\h8 8 [?bqr1=2z8{Wgubg w { ࠞ@^@psG:<fnFf_?̀@OҼ@umh}(Ļ]4:&%G4OtUYηYݖY&{9nhMRi{}6JPmCZ,:'A$fR}q n쒥srES.{Y_2>W-\)N#V?d*4{Ε}v3wL6$㳏9.$7c>b)x >űrX!|GOe0XmޏQձi f;:-3XxxH/Pj.3@tf0WpW\9;>ѳBDYm!䇭G|[dƧzqsSc\|ѧt7XEݾ"G,UVS%0krvYZx1?}H _dקv-ϥs| ##𤤌,XPvM_m}u[9Y{!`G1h5<G8NV3H9s7Tޔlv=ש#)˅YVͦYH(>GSP2P]|WclqC9DCYo%y*2Ư~ZPD^Sq0 #GY " 5Vk>%JNoQ :]F[X+e*”)[n(aS,=>{w>'Kq^n3GH~54!]TFUPgMPWY;{N9y3샏l(qc2Y=^͵vP-$]?ZXPu9? .ȔHii|ՎyRSfJ^NmձONtIU͕:ĵ&b„-΅C>^z2 RgZ*-d3Sk(~RGVCˆL3\|cCu4\ew$j힣;U20U\/|oEO7Ŏ)WDkKhh# ~/C!`rNS4 AcɆ.ݧ~0Q.IvѶLcИS ]#  *P.F䆲"#O{vU4n a9C\8)\f'^;'`R%ů%ƕ[ |5p;FزM=ȷRQ]FԿ'CTJtCk9=ڒ_~3ް2/Sn/i,Opכgv~;(-v1rL[myTFtE)ˉ#:1 O(-\?? h\S }Kyӈ4r7>o9::|˖tc-3@)QQN%,8i`ͼB2Tu9 43é?}_G fk'H~gz mʙ(ᔋ60%aԏ/e&fڧe.\HEQ0W!6\3uO@KW᣾xU1@m)Cc-Yx%_tY GKG_+QC}T7@O*Cl唰+:g`kM`~"Πb?Pz_ ko93+U⯧E^OZiN|VOk=|BQ˾z4eHtRF-A/*Lm|}3AgݧJq N sfd#$$]ݡYޏSIyڧGCO,w~MNe cqMC4ϭx0, > n f!1OZOa݈xml|,,-!m}˩ۉ) RFt]m:81; m/iŽoVDJ`/Z(_%M u#=:_먥Aߺ)*G%V"+ i %!bRL%2/D1 u^;g<^ԡzX- RƋԑl07e Şҋp (ɹ$NpG$g~R7ZTcɡ70x|Rb󲪴zLYq^:4 /ȕU# Xʢo,),c)`wKU;$ J aP.xpXLXܦ$㵲F6iR쏁f`[i{ \gmpPvr!_w'TZ\#i-VgeNFljDn\-PcWקO2ЌC™IAۦbC +'s~ J l™GWyiOa籑 olbu}Kڻ+L2}24Z 睑 [ѥ>J@[3=!(rx}1 AGy֛ 0v^v'FE99Ì'_n1@BeS;R3աfLWf6g' {UL))6֖9I̴H=[gY̱SPTEN]eBBޞ>fΙ[_Zn*\W_& x("Q}Yt7VPoBc0]] p3!2J,~kcHfˉ1! L]iw'MD҅8^ɒ_>V&IG@l67cMM<0?"举~S~>Iv)(Ļ04JɌ3bU'갅'29}p,Yѯ-Ǧ glM Xk{mT4ǨQ0~& .=a;(: LK|V@и:L]\cG t✮蛲[W[׼4ħDSu Ér% ZGܲ' $Mt1Z3085 qRēN5o~qMC݅⫥Kz4%-8,1c[7npIPZGNJO 8Gueͧ(6g5I?)aGtRɞgy+9l8ɯ06\@vxH vt"4PH Qu&NҜ6]Mla$UcnP &DdF > j#wgM܂pȏp)eV!,mՊӧ3—?Uʱ:"?G2v܉*+ۀ!w>nGN(E&*d؎ߪ볪#R -) ò&:?O֮A]^{H6Q2 tn\H!x0,KIw®:jIX24SAh'ʘ X?3ȒTKV]x{3Ur~?JR__6^fvSK + UF};" DQ| W㇫n6[> e9k[6\؈5-Ntgl,d:/[^eKڂ9=پ)b)pl(7h|bu|F]vYT., .hda ڶ.F>g24bNL9l}ᦖJ盷sqżz@q)Qp᷾:*OC8@Y G0$dJla&u?D},-0/ύ=Tg7M ^ x MՂ_T#I,9Ŧ*1PUXo* *3*YF<@ŏ=GE΃P^{-VJ=Ӊ+ԗ1QT/,(7(c~ًRVH ^XHʛ^gә%®]dl!t|f^Er!mstGk Ug,#iT0qڜ?KFԎ47ʡn42 unڽoqd* e;,>կNT4` ɨ7ͺ_b.Ulm)}+Aw'NH*ҏ*u!ȥ x1ӻVrM*sRo㸈m1 Q_oXS8gdN݃zʓӬ 9S1e5| /ܹdlo0e~RCL[~Xo4oÀd(YҲ7WTqK7Un t76TusC\["/o7ņH7yiۖ6PXMi&,Ǝp%[ GQDZ>m_ug9PfFvh%((}cY# RYC,^raA..yLӮb9TSL=iPf"9KKĞ8N'ar/{j2}+yuˡ8=up⯅Jiy="$cG(Bgξl&{ L|0C]}0u9 1ڏfr}N~Xtx*i<sxZw8g<1 Z5ɏ'*avw'YFkPKhtںnWgȄid|muS ŻZ2Ro!&L-3[¥ῆnllvڇCE۳Z?#(}45?XAy(43mP/cKzJ!6C[1RJfW5m/*86F@8ST gogsx+~up;) c)EձuNZ1p8Ӳ׻r҇Eʆ1%KxˌOH[՝UJ^bKG1Uu@ډV]_7zyڣmMXfNG?J/Yi7WC`t"ЅR'i4.f#!p+ s}3Lq# SAûeϐO癎eZ%-4ޅicj'9\Gb]UՑzڋ}$Ӿ$ Шbܴ)`'c5iUY2+g52.7|aQΙ!о !7*O(]/G78!yɑ<:ឫPME"5$kJ*`"{( ? *Id[1`nx8')'OKDᐔ]no`?g6Apo҄e]g:˻)rFkm#ް7HKch[ItmYBYٜ{q7t||dy@2#S`bI4^3ԙ|%RLDSSjo~*Ze Q_r$ 5dF==N3ٮv5?,b`X3+ &hX1_5X"7¯kyrjB Xf {J9z;7@{gG7k̳ ~Bz5]*s rYo]>s ,;ֲ=J5ƠLXȘD:5@O%.?,*xDf4)/`?"wM9F.JǾ^=!?{[S(0hWaGZ?7ENAHaY T[3Ɗ#K0^xc%ζ񚘙W*ゑʃš(eܜ̧c;LިG玤nZ0Cm=dW8^UiÚ9 )3gvgt*LuaCx FϭX^󻳵 %ߊ뚈sa0:J%b,/TD@zx;~)NO~)7m[QHRuY}qTjQ 꿂,ǰ6$=p]I&w۰|IKq(S/jsi~aSGRVA~m_S^H)À]v W*1 m*cV*TT{m kЊen QD\y#ny]e,W\7 ۃ)Sr+r:#Fרguk<;W/uq(tM<m5R|r_z{9hՕvr~F~WtF. D+Xor0LJ")Fh1T<1گt=X/#Ÿ/۽0n}P CX_ vbngilpҪ?i+x©*YrYn{-2|%9MWhԽYRD! +^cvG, 5PO4w{/O #sn4{Hݷ.qJ=dinxvoC6E7Aik.t=(C*wݵC3V nh9u4MnSYe5Nя9cRv\ pRD(Ra.bBIq~}sVxXEUK2?u;9:F N^Bl!O U\Fƛ2()&;3Gk$R0)i00QoB$M 'zW"'!a Iׯ\s&+óJ@@o~z8.ݭE0:2u+$;+D8P~]qATC fo.RQvp%=5Ji27a.[Ҭ)3nRh]d,CYhCTyr:\<ۦ834Yp8G}MU:<\;5ך.RԈ,MB@RlQzkvh`@#Ǥy. ώY,9[ߧ1lP|a"K&G&U!u%nr:+Gi]`o9jZ䉥[y:g k[ ZP]_i/H)왷Ċ֏E"AOvw>biVq0p%J!cp912v6ѡ9 E\TP{=?{`:jPH%#r$(;T}'UntW0W aZEr+Q~殫>gce=CT,w W ZX4FaX 6L|ޗh`hIxQq7m$0G:Ռ_EyrUt˧i<=ʧ5f!vKZʤFx.IÍ:c$H;\.BF3(>y@qh6F۫"/RҒΒʞu1J5g &gF 7VQ]|}BZ#FhưMUQnVv,wݷ!hv_Kψ¢˙aS 7ÏasQ{L`>RU&`sȡ|ײ dw@nFs&^O"h36g &fgH6#G~4l@ʩp (z(ǺQwDߣG# /mNaT{>NiZo|K'D2RYrjc#t2#I:꽶7 h0ylM'lsmxK?)B&h閗֠B9_LMɂ0=bX}*g)B]ϻ0u<Xqz1J*70P ]߷ʿݨ`忢)HudB3XOiPdfvp5\#TXO)ʯ_Ԓg.TZ.hآH/ϰ[5o4`ۘ^fj;>r>\I .bӘ⶛>%r*AcVL_+C;N/^)# ĩuY-8 Gf༕`&mGbfUYYxr†Z|5j)SGGj%><7 I 9jxw<q3fA(te0n66_a@tmY t ` VWl.GUbс{CysT:!O ?Fϓsu23ǖհf*^$/ɻ38I4}(*ITa ,ʊp5zg18ILn*qXYD˅s6׭Xr)O+4@iu%W\DRW"jdΞ&7v>JdLm)E) ža m#"1]Yl+څkI+In6vl¼"%e]i1q{E!zU5 눺*exNaN : "8J?P!vHP|Xٷ[vV(ýa[{:Bs#fJ^K@"o3ύ&'*'>W{}ެ<8M.8Z<]Nk,箫݇XYAI rԑD1G>hg]GoqfT^3;܇_];d1Kk~-ҰP߅}Θ.{pRNj9MjCĈQ1x. s75z?j4qx Y7"n\2(k؎̀~s0hM:%P/M54?3k9z2&E4!_28=_}N6gު LŧF3zUW|םK>ۖǹf;kiGe!G:âqW7m{= teBh~Kgt?7Q<. T|۠rrE܏X RL;:T([+3#k~ nwYqa;oa,['r]z^򋠝| z=ƒ|C꘦-9gьSDhٮd)t/. Yi6v k@k~uV0} ٗEtg;Q Ba0Zzk$BUP90:³f;z9Uoj~KH'؎G*sR<e$ DvAI(h/h.43ѓ5p_t>_reŒ2α)P2Ae!1z~fRRg76lws|1GtFS;1&͋ DGAsvIz92 "wnD=66ٹ"/2̚ s^CY1)#iN%A 8d"V|ՙ)<;b.?o/?s-=#[HNsQG/`MCN`} |ؤkrj"IzФ]e!R> (_F$P5n "8eA;y _},7{"+It+z 0sHBQ8{g. hU+:` V :`3 J Q)mڅ?A^/[;> W /cqE{pf0ͥ M-Wc m;0*_t+Y%'~6(#74S4ZF4:܁AudQzݵ^:. [:UQ uY(e|ߣ-rPeLщWtb3NCvd7|vG/zT|e!+yktf D=Oƒ$qQ̭E>@z8ܞZ's5 6!kyqf\N ~GH`voW.T-y/#G3vB˹\c15b 8@Fq1W$o#*YhOEh{ %,^RAeh仯IiMZu ZǤlҕxd!RU DI{4 CL''~Ϥ{B5ou56q RKпCb F\cm\ ^6`G?b䶿X| mYh.;YTX5`b,[<=ϫeڥ0pekzBԄHAI-,rI`Bv t| ZbX=BtJ8mXw ywP/1?ZUb$UjB/ꫝع~є>ѰrLTT'thxN1("9uɵErpzX) u:jU+">B#:ߖ+PMMLVi "j _c ^@73x~U+L!,_%ϚB&*?5xtŤs3Yht s[tU8 H :o?I7$u!cFG\̚*17EItO(xkIީVd2'bW{.E.ɯ9|ʾ`d|Ar]y=lxoʒ:x7^;=<ٿy\4 1Qp k5cE^Nֶ&X GŬ`2{cV6#ٲND @423c9U{Ш]IL2ȈPosTTo#GOYϜܙ/*k"vZ*Dc:z4yվvoDv;j_> & , GK=-E?9dw^@m?jN |5_>)b vG=fD )!rɪ[rEcFL3y P.u;"}@13~T-I;!oH~•%ށlvǑGvJX 3B/wBA=wעΣhQ ~bϵ<~ pNVT/<[$(<) Ç~D8Z+U!wD*1+zg=Iju|AÙ e@U`٬(;6ȋVףNAӮiazU 2:_$?*%Oguȵ_D;FmKQΰe&j(r}cZPF.w(JM;Zb@L5x3LZhw@}]X͐.CI\AXQdYZ8[5Yc0t7DzSm :DحQxH4B=l&ٲSiOkmH틻?SZb2^3/i#=f쓆j{,ie(9*8b|JPUr<0,`KTN:dOYΕog}4_m2^E!rYdC:o,CLgĐBYc8 Wی5AU%je͘p= C> EU/M2>V._4 RtYm/\#+x>ʡIJ@%`]P',ߍF IITWu<踫4# se?iz ]0r,u?DWnmܠi[5͘F3e;K8z5$Gr۰ u&/iGBϜt0◷SvD$w񂌺;٩u`JFS\Gf;nNs6A.N"BEm[mFm2z 5_`. -:r KPgσO&"ھ.zHӰU2nGmI'o2ana3Ŷ !H D8-TR/#jKb=v=wglLiYN31 $Xɺ(Csx8;v.dL8#HK2kwpѨF!! Eteͣ9c~` %4<9ꎅQ\5rGG)'Sfdv "}!Gå6ݼбs.x^-R1WWM#E/Qc9߁fc50ѕ[%IR<@ԦJvR$ VmuN^Xk1=Ž>[AS.:$v7?e-)h$L'bG ~If#Y>`Ȃ4,7k?E iQ(-!JF\"sTh6qI_ 6 3_N zfH4?(6mI{8]Y#dX9Vw_uk=c*c\t/^\HMxҟP /j6n<+ً>ɊY8: xģ}Y^. *ée +_ ;n"4-3e 迮lGLx:@9?Zf#.'}a%|o `X[Ǜ4F-Rm3!" I):q̾Nk=07۾$XI@.SHE% .C;  JeʨC*^y+ؠ_r G!AƫJZtL:8`ƕn/V;hB*[9]+vf"G;%b NL'?50~Lq%?5QToxd!C;XUVEy '7{_~EEŻ{)#k$DѡuQƩ:60b*IA\t 7O@2,dS~ʖQ%g&'w˟ m*y%P&K0 磯gcozxNLqBBx5B>~)T5o[]b)Whde#=>zpR55޿jr d\kbuUƆ#1x\aW'vNLu Lj,WHA%u#r 릢\ 9|ʬ~@ddq44,>Nm&v{j/kB#|~÷5WtjFMr twvj[,sG}ݢ4u< ۄT;U\}~ױ]P|Nz+a^E߆(Þ >*Htl(d#^Wm)I}.̢H#n1 ,IYQ+ asNzu,VxI&jMG&p 7 X )$$c@/!QUP7LL5ϯ8.yK(o싿^)Iq߁;@| X ގ+T1RAC/ tbj-J5DZ2d %bF'3 N%{3Q%f( kVA#!~GbIN7`m_p(:wgVx>QN%+ E7lR,HD׳gӅoeia֗N"6zv{WC-Z]ޙ{KbDOs8fN֝%+Y%qzԑeo'Lлbz'(Ę'e.C[bهj(hAڴXoVҽ|K3/0B,W$gGkBieVLECj?ԾIal:?8ws}/%75f {/k3w鳁#N]6e>lsE0o]_[$vJIҰJ4)#RC,8=EQu_`ZqGRK?h [PnOsg ȉ5qAQHO_CLo 9U5-5VjKE1E͸=F*oι#(1μrcJ؎wn.e)@y<[11Vi \i׎x? o8N_)k +<_,~"et IH^`XM. :I;^*GP~^^cf4| {!j 㛕M$ta+݌~r|I8/Q-|-^Ch0U\93#PpDfr̩ѩ5c4~tݚUsmZ<ͣ)zY7ad?El*h΋dS s=Y/fh>2x0g׾꘳8J ƒ@E]wT\ X]{W --e.>PL f1QW~Re6]"G}Oڈ*cLA3A`AY$ҭ26<"̀ru1XO3k< p7}eK&> endobj 378 0 obj << /Type /ObjStm /N 89 /First 798 /Length 3594 /Filter /FlateDecode >> stream x[Ys8~ׯx"WUj8LNJ偑;Ht&_HXNUni-aDK\@N%(#3VyBGEfBT:T4#'zw1[VPہSQ:9@;%o07Nqc*;itOˏ,-y#7J룋0@pI]7AheAě6z+f;kϩVϏRnmioTfI,oe,P,RB h6y $?9I)Ma[קp }eT3Vcjo5G-s-IW0!K +͔7b_i_) $+S9p 7^ 4G%Y_2TA " fvle )Ц!M~jZ#:[%mnP"ыcmmnQftfӳz;-6ϕ7 ZFG8h6 63NKBeL\>:LxA"^x蘺($E! >;,U0f26D#n1i4Хdkfuy6i7ҵ75!%Ey°w A x RL ll`7"HEvvle,R`(BQ\b2WL$Ge)OGRL a8b.5:@ XFOlE..:~Pz`X6x%=%̉K6} f*\0iw;oze\(p%5=mptzոL)1bm1fc+%+-ԲUP`-NRad!RTgMoeuv^..eqa]̫l^/5䄾M\J_?y^D*Rl ư?wO^9|b,5 =lڏ:ގ:k3e>͍אa~̮2%ǵyWs`IDpGbL*z;ave'K^跘%b$K’i"3%#w!3B&oʹJ!kBu$Hyvx'dA.{d9H_͵܄Gx:y~`|_5_M󍏵k~<}R_9 }17}X3z}W?[۾z\3 <!iVQGY XIAq ')G)0G%x@{߷5%M.RomrPTJww@oZ5bG\@r$19Q8RrKpIՙ#Yv Gs cr0c;#<6vx8ڲ 6 MˍD'@`  4Rm +t-bMe]vE-r QT9Dl;fTmOzmrGR|H:9 xS\Xj|CѼ>nB *VChC! P qyEl ҍBH(@(ȨF^dGG1ݙwaTtUjQb.]NvZu\CɁu1_MˊuCvN +<-uy7\#5 Gf endstream endobj 436 0 obj << /Type /XRef /Index [0 437] /Size 437 /W [1 3 1] /Root 434 0 R /Info 435 0 R /ID [ ] /Length 1046 /Filter /FlateDecode >> stream xKlEJKo+m)\Zn-[hii͘c&lذ``uaA,]B<|͘WVѺUn3`lDvrXO@vr k$UdMd')A Y7 ZDvԓ&;F 4";JNMR6sdG(h%H6AɮdSv2';D z({Q>Ls;H v ,$w "|RNP{Γ S #d d{(}d~5]㚑5hմZgmvF[&k|H2L̀8f.ep{)m77M&ط7o%N= y!q<:$5*TFp|QQ?Cf޼V-{|i< yZzK7ǣm'bbh 6ҭbF ΪU Am-- a{zvݦ5Ui777_#bmJ MFFJE̺<8| | iƭ'$"nnwtD,qCVؼ$nӒnqx^,dkS5p ϟk\Z@ pNeIO 8Y&Z:|哎@ s{0ҩ vCn?/:tIupM$dHno遲##"5/^ϙ{ս2ͨuWd_Ձ A2d<u֭kɽ=^TJO^M~VcŻweLf `T),v,q֚b Xrf.^zS^?j*< endstream endobj startxref 192713 %%EOF GenomicRanges/inst/doc/GenomicRangesIntroduction.R0000644000175100017510000002373512607330121023310 0ustar00biocbuildbiocbuild### R code from vignette source 'GenomicRangesIntroduction.Rnw' ### Encoding: UTF-8 ################################################### ### code chunk number 1: options ################################################### options(width=72) ################################################### ### code chunk number 2: biocLite (eval = FALSE) ################################################### ## source("http://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(1:10, end = 7:16, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score = 1:10, GC = seq(1, 0, length=10)) gr ################################################### ### code chunk number 5: GRanges-location-accessors ################################################### seqnames(gr) ranges(gr) strand(gr) ################################################### ### code chunk number 6: metadataAccess ################################################### mcols(gr) mcols(gr)$score ################################################### ### code chunk number 7: setSeqLengths ################################################### seqlengths(gr) <- c(249250621,243199373,198022430) ################################################### ### code chunk number 8: setSeqLengths2 ################################################### seqlengths(gr) ################################################### ### code chunk number 9: names ################################################### names(gr) length(gr) ################################################### ### code chunk number 10: splitAppendGRanges ################################################### sp <- split(gr, rep(1:2, each=5)) sp ################################################### ### code chunk number 11: combine ################################################### c(sp[[1]], sp[[2]]) ################################################### ### code chunk number 12: subset1 ################################################### gr[2:3] ################################################### ### code chunk number 13: subset2 ################################################### gr[2:3, "GC"] ################################################### ### code chunk number 14: assign1 ################################################### singles <- split(gr, names(gr)) grMod <- gr grMod[2] <- singles[[1]] head(grMod, n=3) ################################################### ### code chunk number 15: assign2 ################################################### grMod[2,1] <- singles[[3]][,1] head(grMod, n=3) ################################################### ### code chunk number 16: 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 17: IRangesStuff ################################################### g <- gr[1:3] g <- append(g, singles[[10]]) start(g) end(g) width(g) range(g) ################################################### ### code chunk number 18: flank ################################################### flank(g, 10) ################################################### ### code chunk number 19: flank2 ################################################### flank(g, 10, start=FALSE) ################################################### ### code chunk number 20: shiftAndResize ################################################### shift(g, 5) resize(g, 30) ################################################### ### code chunk number 21: reduce ################################################### reduce(g) ################################################### ### code chunk number 22: gaps ################################################### gaps(g) ################################################### ### code chunk number 23: disjoin ################################################### disjoin(g) ################################################### ### code chunk number 24: coverage ################################################### coverage(g) ################################################### ### code chunk number 25: intervals1 ################################################### g2 <- head(gr, n=2) union(g, g2) intersect(g, g2) setdiff(g, g2) ################################################### ### code chunk number 26: intervals2 ################################################### g3 <- g[1:2] ranges(g3[1]) <- IRanges(start=5, end=12) punion(g2, g3) pintersect(g2, g3) psetdiff(g2, g3) ################################################### ### code chunk number 27: manPage (eval = FALSE) ################################################### ## ?GRanges ################################################### ### code chunk number 28: example-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)) grl <- GRangesList("txA" = gr1, "txB" = gr2) grl ################################################### ### code chunk number 29: basicGRLAccessors ################################################### seqnames(grl) ranges(grl) strand(grl) ################################################### ### code chunk number 30: exceptions ################################################### length(grl) names(grl) seqlengths(grl) ################################################### ### code chunk number 31: elementLengths ################################################### elementLengths(grl) ################################################### ### code chunk number 32: isEmpty ################################################### isEmpty(grl) ################################################### ### code chunk number 33: mcolsGRL ################################################### mcols(grl) <- c("Transcript A","Transcript B") mcols(grl) ################################################### ### code chunk number 34: unlistGRL ################################################### ul <- unlist(grl) ################################################### ### code chunk number 35: intOpsGRL ################################################### start(grl) end(grl) width(grl) ################################################### ### code chunk number 36: coverageGRL ################################################### shift(grl, 20) coverage(grl) ################################################### ### code chunk number 37: subsetGRL (eval = FALSE) ################################################### ## grl[1] ## grl[[1]] ## grl["txA"] ## grl$txB ################################################### ### code chunk number 38: subsetGRL2 ################################################### grl[1, "score"] grl["txB", "GC"] ################################################### ### code chunk number 39: 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 40: lapply ################################################### lapply(grl, length) sapply(grl, length) ################################################### ### code chunk number 41: mapply ################################################### grl2 <- shift(grl, 10) names(grl2) <- c("shiftTxA", "shiftTxB") mapply(c, grl, grl2) Map(c, grl, grl2) ################################################### ### code chunk number 42: endoapply ################################################### endoapply(grl,rev) ################################################### ### code chunk number 43: mendoapply ################################################### mendoapply(c,grl,grl2) ################################################### ### code chunk number 44: ReduceGRL ################################################### Reduce(c,grl) ################################################### ### code chunk number 45: manPage2 (eval = FALSE) ################################################### ## ?GRangesList ################################################### ### code chunk number 46: findOverlaps ################################################### mtch <- findOverlaps(gr, grl) as.matrix(mtch) ################################################### ### code chunk number 47: countOL ################################################### countOverlaps(gr, grl) ################################################### ### code chunk number 48: subsetByOverlaps ################################################### subsetByOverlaps(gr,grl) ################################################### ### code chunk number 49: select-first ################################################### findOverlaps(gr, grl, select="first") findOverlaps(grl, gr, select="first") ################################################### ### code chunk number 50: readGAlignments ################################################### library(GenomicAlignments) aln1_file <- system.file("extdata", "ex1.bam", package="Rsamtools") aln1 <- readGAlignments(aln1_file) aln1 length(aln1) ################################################### ### code chunk number 51: accessors ################################################### head(seqnames(aln1)) seqlevels(aln1) head(strand(aln1)) head(cigar(aln1)) head(qwidth(aln1)) head(start(aln1)) head(end(aln1)) head(width(aln1)) head(njunc(aln1)) GenomicRanges/inst/doc/GenomicRangesIntroduction.Rnw0000644000175100017510000005063512607330121023654 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{An Introduction to GenomicRanges} %\VignetteDepends{Rsamtools} %\VignetteKeywords{sequence, sequencing, alignments} %\VignettePackage{GenomicRanges} \documentclass[10pt]{article} \usepackage{times} \usepackage{hyperref} \textwidth=6.5in \textheight=8.5in %\parskip=.3cm \oddsidemargin=-.1in \evensidemargin=-.1in \headheight=-.3in \newcommand{\Rfunction}[1]{{\texttt{#1}}} \newcommand{\Robject}[1]{{\texttt{#1}}} \newcommand{\Rpackage}[1]{{\textit{#1}}} \newcommand{\Rmethod}[1]{{\texttt{#1}}} \newcommand{\Rfunarg}[1]{{\texttt{#1}}} \newcommand{\Rclass}[1]{{\textit{#1}}} \newcommand{\Rcode}[1]{{\texttt{#1}}} \newcommand{\software}[1]{\textsf{#1}} \newcommand{\R}{\software{R}} \newcommand{\Bioconductor}{\software{Bioconductor}} \newcommand{\GenomicRanges}{\Rpackage{GenomicRanges}} \title{An Introduction to Genomic Ranges Classes} \author{Marc Carlson \and Patrick Aboyoun \and Herv\'{e} Pag\`{e}s} \date{\today} \begin{document} \maketitle <>= options(width=72) @ \tableofcontents \section{Introduction} The \Rpackage{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 \Rpackage{IRanges} (infrastructure) package and provides support for the \Rpackage{BSgenome} (infrastructure), \Rpackage{Rsamtools} (I/O), \Rpackage{ShortRead} (I/O \& QA), \Rpackage{rtracklayer} (I/O), and \Rpackage{GenomicFeatures} (infrastructure) packages. This package lays a foundation for genomic analysis by introducing three classes (\Rclass{GRanges}, \Rclass{GRangesList}, and \Rclass{GAlignments}), which are used to represent single interval range features, multiple interval range features, and genomic alignments respectively. This vignette focuses on these classes and their associated methods. The \Rpackage{GenomicRanges} package is available at bioconductor.org and can be downloaded via \Rfunction{biocLite}: <>= source("http://bioconductor.org/biocLite.R") biocLite("GenomicRanges") @ <>= library(GenomicRanges) @ \section{\Rclass{GRanges}: Single Interval Range Features} The \Rclass{GRanges} class represents a collection of genomic features that each have a single start and end location on the genome. This includes 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(1:10, end = 7:16, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score = 1:10, GC = seq(1, 0, length=10)) gr @ \noindent creates a \Rclass{GRanges} object with 10 single interval features. The output of the \Rclass{GRanges} \Rmethod{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 \Rmethod{seqnames}, \Rmethod{ranges}, and \Rmethod{strand} accessor functions. <>= seqnames(gr) ranges(gr) strand(gr) @ Stored annotations for these coordinates can be extracted as a \Rclass{DataFrame} object using the \Rmethod{mcols} accessor. <>= mcols(gr) mcols(gr)$score @ Finally, the total 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 \Rmethod{length} and \Rmethod{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 \Rmethod{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 @ If you then grab the components of this list, they can also be merged by using the \Rmethod{c} and \Rmethod{append} methods. <>= c(sp[[1]], sp[[2]]) @ \subsection{Subsetting \Rclass{GRanges} objects} The expected subsetting operations are also available for \Rclass{GRanges} objects. <>= gr[2:3] @ A second argument to the \Rmethod{[} subset operator can be used to specify which metadata columns to extract from the \Rclass{GRanges} object. For example, <>= gr[2:3, "GC"] @ You can also assign into elements of the \Rclass{GRanges} object. Here is an example where the 2nd row of a \Rclass{GRanges} object is replaced with the 1st 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 3rd element is replaced with the score from the 2nd row etc. <>= grMod[2,1] <- singles[[3]][,1] head(grMod, n=3) @ There are also 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 \Rmethod{start}, \Rmethod{end}, \Rmethod{width}, and \Rmethod{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 intervals. For example, the \Rmethod{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) @ Similar to \Rmethod{flank}, there are also operations to \Rmethod{resize} and \Rmethod{shift} our \Rclass{GRanges} object. The \Rmethod{shift} method will move the ranges by a specific number of base pairs, and the \Rmethod{resize} method will extend the ranges by a specified width. <>= shift(g, 5) resize(g, 30) @ The \Rmethod{reduce} will align the ranges and merge overlapping ranges to produce a simplified set. <>= reduce(g) @ Sometimes you may be interested in the spaces or the qualities of the spaces between the ranges represented by your \Rclass{GRanges} object. The \Rmethod{gaps} method will help you calculate the spaces between a reduced version of your ranges: <>= gaps(g) @ And sometimes you also may want to know how many quantitatively unique fragments your ranges could possibly represent. For this task there is the \Rmethod{disjoin} method. <>= disjoin(g) @ One of the most powerful methods for looking at \Rclass{GRanges} objects is the \Rmethod{coverage} method. The \Rmethod{coverage} method quantifies the degree of overlap for all the ranges in a \Rclass{GRanges} object. <>= coverage(g) @ \subsection{Interval set operations for \Rclass{GRanges} objects} There are also operations for calculating relationships between different \Rclass{GRanges} objects. Here are a some examples for how you can calculate the \Rmethod{union}, the \Rmethod{intersect} and the asymmetric difference (using \Rmethod{setdiff}). <>= g2 <- head(gr, n=2) union(g, g2) intersect(g, g2) setdiff(g, g2) @ In addition, there is similar set of operations that act at the level of the individual ranges within each \Rclass{GRanges}. These operations all begin with a ``p", which is short for parallel. A requirement for this set of operations is that the number of elements in each \Rclass{GRanges} object has to be the same, and that both of the objects have to have the same seqnames and strand assignments throughout. <>= g3 <- g[1:2] ranges(g3[1]) <- IRanges(start=5, end=12) punion(g2, g3) pintersect(g2, g3) psetdiff(g2, g3) @ For even more information on the \Rcode{GRanges} classes be sure to consult the manual page. <>= ?GRanges @ \section{\Rclass{GRangesList}: Multiple Interval Range Features} 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 \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(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)) grl <- GRangesList("txA" = gr1, "txB" = gr2) grl @ The \Rmethod{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 \Rmethod{length} and \Rmethod{names} methods will return the length or names of the list and the \Rmethod{seqlengths} method will return the set of sequence lengths. <>= length(grl) names(grl) seqlengths(grl) @ The \Rmethod{elementLengths} method returns a list of integers corresponding to the result of calling \Rmethod{length} on each individual \Rclass{GRanges} object contained by the \Rclass{GRangesList}. This is a faster alternative to calling \Rmethod{lapply} on the \Rclass{GRangesList}. <>= elementLengths(grl) @ You can also use \Rmethod{isEmpty} to test if a \Rclass{GRangesList} object contains anything. <>= isEmpty(grl) @ Finally, in the context of a \Rclass{GRangesList} object, the \Rmethod{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) @ \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) @ You can also append values together useing \Rmethod{append} or \Rmethod{c}. % <>= % grl2 <- shift(grl,10) % names(grl2) <- c("shiftTxA","shiftTxB") % append(grl, grl2) % c(grl, grl2) % @ \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) @ And as with \Rclass{GRanges} objects, you can also 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} As you might guess, the subsetting of a \Rclass{GRangesList} object is quite different from subsetting on a \Rclass{GRanges} object in that it acts as if you are subseting a list. If you try out the following you will notice that the standard conventions have been followed. <>= grl[1] grl[[1]] grl["txA"] grl$txB @ But in addition to this, when subsetting a \Rclass{GRangesList}, you can also pass in a second parameter (as with a \Rclass{GRanges} object) to again specify which of the metadata columns you wish to select. <>= grl[1, "score"] grl["txB", "GC"] @ The \Rmethod{head}, \Rmethod{tail}, \Rmethod{rep}, \Rmethod{rev}, and \Rmethod{window} methods all behave as you would expect them to for a list object. For example, the elements referred to by \Rmethod{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 \Rmethod{apply} methods. These include \Rmethod{lapply}, \Rmethod{sapply}, \Rmethod{mapply}, \Rmethod{endoapply}, \Rmethod{mendoapply}, \Rmethod{Map}, and \Rmethod{Reduce}. The different looping methods defined for \Rclass{GRangesList} objects are useful for returning different kinds of results. The standard \Rmethod{lapply} and \Rmethod{sapply} behave according to convention, with the \Rmethod{lapply} method returning a list and \Rmethod{sapply} returning a more simplified output. <>= lapply(grl, length) sapply(grl, length) @ As with \Rclass{IRanges} objects, there is also a multivariate version of \Rmethod{sapply}, called \Rmethod{mapply}, defined for \Rclass{GRangesList} objects. And, if you don't want the results simplified, you can call the \Rmethod{Map} method, which does the same things as \Rmethod{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 may not want to get back a simplified output or a list. Sometimes you will want to get back a modified version of the \Rclass{GRangesList} that you originally passed in. This is conceptually similar to the mathematical notion of an endomorphism. This is achieved using the \Rmethod{endoapply} method, which will return the results as a \Rclass{GRangesList} object. <>= endoapply(grl,rev) @ And, there is also a multivariate version of the \Rmethod{endoapply} method in the form of the \Rmethod{mendoapply} method. <>= mendoapply(c,grl,grl2) @ Finally, the \Rmethod{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) @ For even more information on the \Rcode{GRangesList} classes be sure to consult the manual page. <>= ?GRangesList @ \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 \Rpackage{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{Genomic Alignments} In addition to \Rclass{GRanges} and \Rclass{GRangesList} classes, the \GenomicRanges{} package defines the \Rclass{GAlignments} class, which is a more specialized container for storing a set of genomic alignments. The class is intended to support alignments in general, not only those coming from a 'Binary Alignment Map' or 'BAM' files. Also alignments with gaps in the reference sequence (a.k.a. \emph{gapped alignments}) are supported which, for example, makes the class suited for storing junction reads from an RNA-seq experiment. More precisely, a \Rclass{GAlignments} object is a vector-like object where each element describes an \emph{alignment}, that is, how a given sequence (called \emph{query} or \emph{read}, typically short) aligns to a reference sequence (typically long). As shown later in this document, a \Rclass{GAlignments} object can be created from a 'BAM' file. In that case, each element in the resulting object will correspond to a record in the file. One important thing to note though is that not all the information present in the BAM/SAM records is stored in the object. In particular, for now, we discard the query sequences (SEQ field), the query ids (QNAME field), the query qualities (QUAL), the mapping qualities (MAPQ) and any other information that is not needed in order to support the basic set of operations described in this document. This also means that multi-reads (i.e. reads with multiple hits in the reference) don't receive any special treatment i.e. the various SAM/BAM records corresponding to a multi-read will show up in the \Rclass{GAlignments} object as if they were coming from different/unrelated queries. Also paired-end reads will be treated as single-end reads and the pairing information will be lost. This might change in the future. \subsection{Load a `BAM' file into a \Rclass{GAlignments} object} First we use the \Rfunction{readGAlignments} function from the \Rpackage{GenomicAlignments} package to load a toy `BAM' file into a \Rclass{GAlignments} object: <>= library(GenomicAlignments) aln1_file <- system.file("extdata", "ex1.bam", package="Rsamtools") aln1 <- readGAlignments(aln1_file) aln1 length(aln1) @ 3271 `BAM' records were loaded into the object. Note that \Rfunction{readGAlignments} would have discarded any `BAM' record describing an unaligned query (see description of the field in the SAM Format Specification \footnote{\url{http://samtools.sourceforge.net/SAM1.pdf}} for more information). The reader interested in tracking down these events can always use the \Rfunction{scanBam} function but this goes beyond the scope of this document. \subsection{Simple accessor methods} There is one accessor per field displayed by the \Rmethod{show} method and it has the same name as the field. All of them return a vector or factor of the same length as the object: <>= head(seqnames(aln1)) seqlevels(aln1) head(strand(aln1)) head(cigar(aln1)) head(qwidth(aln1)) head(start(aln1)) head(end(aln1)) head(width(aln1)) head(njunc(aln1)) @ \subsection{More accessor methods} \end{document} GenomicRanges/inst/doc/GenomicRangesIntroduction.pdf0000644000175100017510000064224212607330121023660 0ustar00biocbuildbiocbuild%PDF-1.5 % 90 0 obj << /Length 2375 /Filter /FlateDecode >> stream xZYo~ 9=@66zdD(R TuUAhZ#U]W7Od)frq5Ɗ&xQ?O.Tf*ݦf=glC[kf /f[c 4[zWذ-/j"UH&W{_C ϭ\:ljpZeDi}x+%gy/8  鬡պi8 ZB i . \{Ѣ0yA+=+x.#-qX05r!U!R(}Ej"rTrJ,(N]6 (XP 0ŗy|;Wf4l~ΧbEhR"PD4>P^ 4(3Yѻ7 8_p@e #~@CD䤆7™!p˚T%tZkZ|Nh) je~RKQeǮ)ZNPŏ0PŬ~iNK21aOcHɟGt=E:WdtP6^&䤢PؗXR_*!S7FRlʺ4KUK`.-[G-XrmuvMGJm1߬9,J +@N".b;"B>ND!o I"AApG %A?54{.3A~a$|;#Pk ,LlfR0`w.X P;b%?WPelF$CvC _bRxrZ0pfɨUCC&pCE`8Y.ns@*2u,[ϨcA`g{q,OBJ TI-;*rL˯1|iէpT/3DBk!rp\3֓An71o^dю¸U:vr)%/XAQcMtUS| 2!|з9f9h$׎)N*!O>DН#EכxBwMgrl|heӗa*RvZ:X-|,l5*f?#A$rN4;޺S$HӲ&&Q`>atA^0`f,1֫?,FF$"{t>Hk;J^R10*UH}@ۗxzb!0:ptǚɕJ+\Qq1ϯCDqI=LHS0g@z=OW?7'iY2cXQiWlR9t[6.NE#Xju>n+~K/jOd'%|^P.5`5N|wD`g (lzxcN}V` S=Xw%q6 LWɲӟZamBIT0.ёCJK>6lY,O!X/(53r3;|ЉeCfG^FZ0ɺ; ڸ {/$*,ݏkqB؇ w#p/,)Ja9vB!eȐMύtWGm~.4zݚFU_z|{y0YH<:_4<$H+( ί\v0u|IquBEs ?\_ENbx`~i9^"|n:=xXs5C! ~ƛT%}W=LZ [2pnŋC_ endstream endobj 107 0 obj << /Length 2180 /Filter /FlateDecode >> stream xڝYKs7W4\1(Zo9a4>\"GKR*?~эRAwuI#)n5+gEen9_w012Br{|6ks?c[BZ/my ]7ϵNnܟ/Re >xs`ӁOgVRpRkV1ʅA)GN5nY5iUsD҅ B:;zC-2kA-L=UL`S+x#p&6n0F\U/ t^ƯFt FҏhiD;k&(J`lrpv- {Om5k1K%'W& ?civ/'7YUlh ʌ EVc5c(0Rpc F,)`yp^ݒI 1jjBȉRF-QRHLJ˙!1l'eZ=kCuvi^xد=rܐ*N{YjWp &`aF~.F};_ȢWٟyK$@/QT)  YN܍|/?[Ӳ;[HhV CvL~H6arno;vcɧW;kÉ솃ٗ'tdc2RG[lJ|iȼNzFvt,$_h]ܩGVP1~m T(6O\ΎJ$ȨMy>.rk@/LӾ+?6y {FĨ&+"걈+?̅1g' eYſQ7Hvt`pHs``՟DmԎ%-DK*_IH_oR/pLr(-O?+0[ۓ>v\Wg5+j*8|cԷt斡Q9}T ~*ݥF ؀qo5vZL! |)$!Ee>'MwR}Z7,s[ &L{6jPL]+kZ p/x2E73N 枸L "d=#"!qMV98CRa;ú@Bs^X~#w Nnh(u|NT`<ьXo ܊"XEku1X&tar:B|Or{AVP&~`o77h؂F`E_vzyZ4_#ee冘t%a!$ xI>5퇋H}iߟؽ>&XܩӥZKY e|8H,D&Ah" xNC8 IĤwѥ8JR,o`]$W#Y"QLyI-@aظ,P6 hm6Xkb^O@ &!27Íwq;#eK\kmJN&`g͍TY=T/(>XI^QWz#;(ʸ?d~Uj.|])aCkOrO8On7uW|UwBW *ygy <c$.E^ zNh#WTfB=HL)#aOӶ;$}zdf:,"F s}\@"Z]CΡpdhn^]zs ChIO eW4n!S껨ƾ{@:Wy2Q҇ ^ :F!g0?Gr:Yp,\ T1Vśm6ߧ.b"fM6u]G7m$| endstream endobj 111 0 obj << /Length 1275 /Filter /FlateDecode >> stream xڭWKo6W݈_XhE{زZ?wJE;>[?\|]af1)')Xef>)B$?C:)&9h_`q;%Ws^*㰦_MV| LV$ q/Dz*,MzXF+Tnala406002\0yB9?`an-Wn~>*8YsS*6oI&ܽg&MS I]s 2No#*wy(e}yMrMG/[4T؉+f,>{#m[g\"k~6]o>Z\u0WfVi]ﬣZ_O==ۋD|%J͔P`es=*"kH3Qi,Ss7Kd?8Uh]o{Q3if%8ћ+ L`)cɣ4_qD,%Ip2K[0*eŻ[GqóOƓ(X]8>x[-)%R:r_+zp1;@ZC8HA0ä0$a:1FPeYVgDI:@  a GUqfüp6xƎ;EQxۗz͒fE7-&QV2*>p5=iK[d{k\IwveA2]}j5>кpzg#otSt[*eͲTf)rCUu딅jֻaU8biq縂&MԬ0l>I;Nbd!%:U\|*h0?[itXmKRΊyޝ_kv L+y=Zt|k%dL_DSR T.#md:O)~o\XmvSSHj%b^[3a*RU Sp=fhx9Ik,߫ G-RU`^T} SmNŮLhwfXS8;(?etWHI*GKyjc8ǞSf~Y#+'yɊkMh$T*m$l5@ϻnS!FR=xׂ[bNOv+kc_g~Co.&g196&1\#?ܿ7])D"$g0 T͊}-?b? endstream endobj 115 0 obj << /Length 1509 /Filter /FlateDecode >> stream xYK6WƌHsh)zj} ]w8JM{ȁ6)g> G3g/(=Yd~51cKVY>/'s?o0gdM(덣^*+Ô xTۢ RPڲ鷋̈Я{ZēLs5ɚAi״k`BXV/ WdiCG0/*OGh8X TTԅcuϪzsOL] O ZDjx[pv [?ޘ)h wвLIUoF@ ah|y:\4 bPkp$6F_ hpƒfƢA4صh.Xizc l8t]}"eoƭnYWDZ(9S-I+⧱yWK#0 j )wdC&*GvK +xsF(S'`G3 !#XqBw?ԕl` S& Q FO!H p_x xpI~$-Fo~wĨw,JVg#uC+ (># 1 !HyǛղ_̘\Hwwe:%=Q.;O*n3̯iK}R }8<;t/.鼽 CLJ 뙋 :c*\ϑrLS>QFi2XluNG !":R*EiF*r?%?R(f)r-稿'o hс4P*831D&u5e:S&8!gcxʇ(mӓ~EbBv`sE5]3 בmq)E-D;^JR(Aa`e'>m~ {,AJ[⏫˓Ηq3Qg nH~㨻_ٗhn;]8ఊJh3 f{ zuo|lΔ5jۓ#-YKʊȻ\a8S*_na;u.Cڋn $"" E"něӽ%gRL¤V'PO[(FB)$Q@GJAxB( P擌X3B16gHН)K)X| }$~KC喟LJ#K/2|b+ 0_dOl@oOu(IryµaҚd}vK?oՆ}#]<>qm,2gf=|ov>āK>N ]rz;C2B2}DHӗ@ٴLX8x.- _+碯bi %dwR0R>V~?*\ endstream endobj 119 0 obj << /Length 1272 /Filter /FlateDecode >> stream xXo6_aI""%[mXeKAeElet@Gu@"#ŕFd>2 F&,h2]GE'J Z-7|7`EB8G؂(#YQ,˵v54_$]HB$yCPF(8:TЯ?!.1q#ߑK7mIzhn%ސvI*4ʭw%tL&ڻayu;4ToƱmq"Z} Jvd'#>Ȓ !c vNaw@.fkZ ?؛X>KR6 @OF* O4WP~tv~נ=_)Srl燪Ӫe9!Rf|:d,7[JrMIz{=QXʭp?[;~:'`/ci'Y pVPCU֍kj5o 5ݸ+V`"to8$+=. /dIz$z&op 쬫q8?*3-lvN )!2~\v1g梿7qi/ 'S @ѝ~b{vryGyr1}X*9nR ڦM'bߕ;dZj$2F?0ѯ%gdvM];-Iб.)sz]Y[v&H:j:`(KT]S)&!{b]44 J2 I'cG8l,IZBeC(E 2cE6.ƝkN.ƞ$ H;m)ȨR!^XcQs<3>'QT6œ+bIRXWg ߌgMG$Rlöm_PYSR{nො> stream xXMs0WSxeK2M4@|dZHK~|ei+ju n [jv$MZH3-HfLER',{M 6bD$15222620Un,pطtهm[Xεh~2!y3r]#3i $C? |w5{x'f8O׶* c. 7#0 y7EQF'ZlC;E T?U*U[ k_lLjdO++>f<:,a$] ڵw8',&yWK~Q̈(LN06ʅ*_Kg_ "91)>dbӓ} 4iG؇: Lؑ2/e!Eqwb T 5nS`)/A rʷP|AޗE p$) i+h+YR9t80]I *K w#U!,d bWҒZ*24mKӶ.mQϕФmk@wǾD* #W߭1xȽSDXA̷T`9]J!VB&5lͼ[oAUz)߹$?'q,wy=DO>S 96' kA<록Es!AXDH$'%,ؚ~vw@L D>/׊"7eHmM*Zzgg?M4 endstream endobj 127 0 obj << /Length 1437 /Filter /FlateDecode >> stream xXMs6WH&J|`ShIؖ+n2M25ig:=@bӳVrVRjPfVեp-f"/T%l iΡoU:-]䅖Fg/ya AB@l.8}V )Em-,`` oa` Oh7]A[C{C 5=RG9$v~ S}IAOW $J!̀R^ IGԩxUZ2{_ڒ;pG" w98?n#pIu7lO{%ɔ_'q3>$_F,~LkZ3U㎅ww6r%O{ُ4Y]HڸcȢ=mx^5-kѯ?#.iEU8azP'{ di/xv,lH <&N9`rO8&>IUS*`R|D@!>Dw`cW#usF(mL}6fʺ&(>ʺRFJOcgdP'<ϰ"T&;mxQ;v65'S^[[#>:u"L]o!m5)UJJ߻YIvnkQz>ov<ǧlAU` ܝ6}TMVYL4`(Dqi1ԼE][Rb[S RHڊ %* Z0 D5c!E/,?,dct,#DZ-7Đ4 Ps #:+2 tLjKMR-Z!Ѯp y0ڌ׮7"^8#lYm"!ϕ|b1ZZ+IXt,v%mV 2.AԐNq׹r\iNg/u+CZMz1aX :㥐8M:W^u41b 4t%8xλ(?nBFX\L\j0o;>GIo:c[)>D{<hMC<"UMU>5\ Aq>KLGIa=b^CyfF(QRL]'Fb(stk> stream xXKs#5W8.9j6'mكc;_x[iu<{vS,mkfZ_Kꗾ\vW)B ƽw}4ZM&@u?Jg+Ж>=p2W6czT`-O?=#KṔ,S^r)Ee-YWߘ{3**ښ1,vBmsuqI+W}Hhx A6Y2G!nSJ|d9tL! ^![?½i%^}IC ]?,E0WE A_tӡI4I%*|'=_a+CPs0:Sa$N`&\Ɋ ޼K]ΖR}5[KR<^M \NNی4ѳ9 '[h)JU]9jhW4DG1)tDqST="&}yXٗǩP.fI/-: t Gސ0ɘ,TќSпKHAg$$ Sşf csrYh7\3gg}~_ZEX9@#{'O]SQHFw!&kJtjC6eWiRYaZ7I w/6p>NR0E]d}v,pߑ˦lVM=O8ډpdMvgeΙe]cpMYĜxEˍ)g|Vk@qL0;r6ϰfDA4eēVQ(UHmlj 1c^+V~|)/'"$i.c+§ F"$DdjŚ]-F:EPtTEgyxHR Bu.ONµJ²IbIuMcN^¶%*pݝʺbEqwAc_b_.69umun^̇Iy;wH{eYlhL괂=.ix4%{`ӳ2W=ux^R'o׻5 a k? mN1N媂 j<oŪY endstream endobj 136 0 obj << /Length 1360 /Filter /FlateDecode >> stream xYKoFWV,InPhhQ@mQX2]QNǒKTl"Z7i~k+'.uV|9:-&eid\&3#UdgEM1};ͳl2"u ~x?WWԾyw< r477ɚT0nF?;&:RI@0(ew̨K0sD̄a3u+Y#9sNۆuI(Lz2*uH&2,A3eSK$O &X9kS0KdPNK*!o#|ec|_%2bty 86K)}4%[Qc`E!(Ha#*SGNNM/XsH>Neɓ]9- sKjd4k U^G=SW4XBxoUC2Z4š9Qиnţd+ЩkGkzEQ%8ӷ=퍉7']]  i\XS{3NaU)d¡эI V8 >xtw!kt4%Q5n*@{ta7vno+ JߣG%)siֽh _#%1Rp\q !G{Sy!WPF؍a/]YUχ"nI?j,CS>@f4?`!)f:vHm!DDz P_\^ aR))POdyqU%Mu(cL{_*GNQ@S-Pt`+T;tw5>0@5n%(64.S{ː'Mp_=ˬHF[Hxl5)|nӁYȅYzHOk%<ʹAC{왖9U롇˛L0ªYK!$DmT;Ek.\zGs<EO*isPQp~_PP{Tq`ImVHjpV]ʃT9 y~ 0 endstream endobj 140 0 obj << /Length 1532 /Filter /FlateDecode >> stream xXKo60d4护HmnS0zIc[e'P,;N Hh>D͌9?߼` ggb`]*r'*YeVAs6 -I  oyOy `As@KYKI; ?Td`$peɻ(˥I IH%Ç] %)1JōElYDsO< Aosڞm̓m\-_0>3u13 CfDH(D_.!ܧ Ip?/ܠ\֏mX: `YB44.)QUsiDZߛf8*0" #B9`,a[^MM/,ٖBe6X8Ɏ\ω =;wCm<[㔏^RS`ז FE1zނL e^dA@&ka(`3 ?.;t\_ڋ'.QW~Wl4-m!=؂C1pSB-.OW2a p$8 n( mm ^0%PRѴld"$ I?7Ԥ6e lVY"Ͱ+T엙:f~ű9AsQ2,̜]^9GB(_G@E̞؁Ҏ9GQ"4,| <)'Ud Ȫn>YyiR] 8w|9R3q0)S#l"H;^˓Zm2?Nшٹg|KLj/x)#Zf zfWctU躈wtuKdJ@QGGߎɌx.4"dRm8g hkӽ{G"Q3׋C  þb= ,ZjO8(?]o>//~^AzvOJ'Lz{tU$L;vEiqﲡ_=ex3nx0gWN/ŝ09[Wmh =Sv CDPʸ _J^)d&ai5 } 08(A9cupc2("r8Ľ쾖:f(!#C+uAG@ A7h=*rŃPa)~l UTm!T#K[b)+jjQ?y\4hZحM]HS$b1:(n[JVg1 <߮';'ፋ2!⨠MxB!zbE$.ʦBg5!J=rfZ |4ˆ uUoheQ/l0l)lS <% rKA^苂+ko~  endstream endobj 144 0 obj << /Length 1623 /Filter /FlateDecode >> stream xYKoFW=Qp$8ESFhY$@|gfgɥDJ@y|.sy[eWw"Ns9 ÑQ:e+x$1ItakKh5ܥ7nH/ OY4텓R ITN؎+3h?NV e8P"'"Y;_4ƠKœzg4id&lrde=r#O\df;숒h4cp8/%32_Q6`*θofS5q)0@&NN^ڰ5 1iw&͠T<2i )%C+F/eMӀU0;Iy^?>c4.كpN"E~|qjTҭMUo82eC~|;$Pv]'rvi98$yn+ c*y IaD`~\bo8xMb&K7^ fiDR\:8~YW 6uY;Hԙzhچ`qEnf^(C3ZӒr+X􌏉$ Vq A"11I8G%rh %"Ro:"BD? S՜QK PHtx? 4|IMq$U <1g"s!Z$<[1WlpB]$R6ht{'obrz?F6\y}k6`ʡ9,PzE_ݹ7=0ʆ6((Hrö>q@FcAIM0C4#Cpe?Yn )\,!h ŭ淇{dVCQ+:jQޜ `]lrq4 YK 'Gscѯ3G?2RA#5Z>#/"@"Z8@s=grA sLi:18E?zY^D@ŹLGN]bnv|~61*2{?bXP5s/`iDpelB2qK&{ TX5&r@ۋ. > m*Kߖ֍ "ɻA8pkv~``C.`o>E)m (٤{ *yp9D!l#ի^qLgڞk=NqP͙XRߋg/8gG֭^]濘C T{LH:uIkzM <@}{uW<p/IɷW'Bv endstream endobj 148 0 obj << /Length 1826 /Filter /FlateDecode >> stream xYK6WЃWZh&MPlsڲ\&A~|3Cu=hr8o?4'{e*c̈́Nj-V*eOt*.N;[œө,pmGrYHȗLD P 5Wwd|z;]xӦf!ckYxJb=c-Zرk2D /ǰE00\˜Xiofue/qg\g0spDpDGF@ (W =خn\J|yHqx /"#q V}9ߜwh? -9g9E<0m=|mklwO!'OERP " T"sRdqoJ_EA)eeDryn ʧ$7;D )fZ9 >pMl}BR`~)Ur{B* Aʳs;/ X..JS'W՝ S#e LP$G%уb iXV݂ұom<吊/5hSԶ{"ʧ->3-tbOemZfWI O09Sb9E S܅u;'&eyn'jEh-mE]a3i3j/qNOt}V֔^Il{ܬY-%f]( $#R@"HOPI yɇ܇b| i*d%ܗ`"JwwMxtɅ6:5l۾*?EULcN"ӳzLv]'.dߌ<7 3IJ\NiMgBDc9tTZW+6nj@}_YX-^,K0ɠ3Wt^᪜OP եm_a_ 4gujA,Ztq 9f]޺ٺ|W|ʵ5s/hH+B@] ]}Yb\W:>J;q攈nH퀴i,/.U_yg-&ф)U,RsrL{kdJ^/BU))AQܹ/ Z,keBّ!\6L!.9lLцVa*5P)d_ʩXTa]|ˉ:]kyaQ`I|>!}OvE}U0g9\t=qо +}c瑚>Ko~c;wrHYזVӾ7 ]0ٓY5sI,e[F~_xwg_.[ŀW2]eX{^yKT]˙_Gs#WTNi cP$"- #Q]~<< endstream endobj 152 0 obj << /Length 1371 /Filter /FlateDecode >> stream xڵXKoF WEr[jP6}`QAȉ J%'i}9 h##՛gY#lҙ1K,-og<qk?W)Z\ 7ٓBwyE"qy D42Ci jՏCYQP>Jp4|OMC`F'L{1gH6O1+1{Ih3OXh0kw74`n!^U[;%R}T=o;?(pLQ ۠#om %ltM XW%#,G~hlO>9;r5O n E pd@ mdw)I/d)/ҴPYsf/c e~<_$w9JJN)N?)̏UFgEMDw[qd#aRf}IX&d#&u_:ޠGcIHPT`\pg/S/&\hnp`!yK1ʜt1tԓ,eryPX,Kڐ҇f|O}jD+ZikYm)#hfK`IT>'j( ^}?@ g8!3nbH.4*=;&tshKww1SLKRqʨ̩c0#bI+km}1Į׬ ^f΅H@ 5%`%6eJ~v}C/s ˜],t]6w ?.a endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 796 /Length 1682 /Filter /FlateDecode >> stream xڵXn7}߯&/oK` `E*U+k I6ҿ])ZH R9gp ibryLh2&qdؒd2"Y$?C6Zr, +qd9b=q3 ҙ(8KB,hd&gJcM# (?g$ `:. `L6Z,|"E`2+ 9`E!/,- 5@]p"x[cj!K`.A-%&Ma@88\xL"K%>)bѲІ d$5!C D΋g@\EW !8 'AE} 0:> Xa,i >+<$b,)359@HR$I3I1U! RaEPChIPI#` ^Ž qOף'2?!m1Ȕ,Y17>48IGz3+j[zxi2Vuۭƶ1><ܔwt>܌Kr0SOp~?-g?j9x4kn&򶘄`.gנ75㏆|r:}{B6`pl[t4|tQ~aWWlVMw,$Dn/ےa n0NN' xx7χj4E%^8wRN[(w8LnRi5!utx }!}G;nt+-W׻YDz]Sg2|ﮤoÛ|8嬺VN笼 t!& SɤЅ2'MM&6Mjz&9Mq95(AI JjPRԠ\+jwy^&jz]Nk&rÅ̧/՜.SIKɢUG2gB^4SMTɦgy1JT6yd?bՕ=XJP>;9vTFM[QRZP geQ W4*-TgwQw'3Nل}=,I( [MK kp`l2ɻ]yFazԽʰ*lp]?@.e僨EjN={eT/XR[h½Ǭ8ㆈE̸٥uΩ W$ȵ+?qX({s$[X-A>xŽ ݮmk9%Pee? O˭WR?/NNCy}Z5{iy](ZOGv"ߏiuu4R~ke|Y>XUV QHֳJldt o㲍}gѸ}LX1|nnZƼ})n˙Dy"a97Lsf"y9G68Zӕq|~N3MѶmޠvS뛢{o m]UrvC%L/ "C&Gߙ#pzc1ús^ZE|z[*yU%ZbXןW/ʙ'cgҦJJJq}tݑ_t> stream xXK60d4fŗDȩȲׁ-o-{73 Xiv=͐/׉YffQ%6f|t]'Zh3Q5<<:M5aό3xJb ;x-yy)-1GΙ..riMTT֑׎4y`?yҠ򁸗L0kd{!Pr"9BtI/$]! Y  @l!GG)r@΀5BEuGrU.VmP'͟cm,6Hj?$& I"Γ"Un8ֹ0i(=OK Io3Jb!:A6* S&@"*T))gVU}f,RXN(ƕx(C=Y>q=dioyQG;ߖcapӮJ*zUf0 ->QeӷK)fIx*Fӆ鉑,1>h|J=umbV)m㉔. [WRzaF9NQS>ETTHs+lQ@ȹ(`Un X}A> Qw1GL3ʃD: vDp[ot[:?*ZWbX„v!zlobhᠣ.+{KSF0u6߷~x`숳 }l܄ O͖sډJlg99[5oSb~ڀ/-lŶnC8wju@S`XKvqHey2/,w[ qON{Ե4pٜƾŋ|mD}C=M_;Tb:MR?[_"no9H&=6(ԖEyP5F暳8?VcnU,‘< ęnyaݴ꾍3'{,˂AqRp R^Uүے:]|R?m(ّ]QsYdSs(A%}fS霼MϔHT7KJJ-1^<]B_Q|rEE#u'Æ>Y~>!x{с5}Nܰt ݲrhu3Α Z=tR ։MkC&!Ϳ㶾&kާ^CW7ΫHU/ ՑVY.{I&L+/wBrxZ'e\Rod:3_#%zv C7f_> v endstream endobj 162 0 obj << /Length 1368 /Filter /FlateDecode >> stream xXKo6W,ň[Hk ֫v@~|3CZI'Z聻f8׉"OT2^NXd$D|r: Z= A[hyxmGS-Sw4o;N ;yю7qelYCCgB5&Z $RƐv5W%&ǤY K]DPFqf U$ɕ\70-*9c(% Z YK92(HDg+4죮A0ܘqew"A}-Bn+Ky==7ϙKVB xh_Kf[0%L'ϟs aH2}9@?'WxoYߺ ̀a%!TN;c k|W90 կ *׿.ͺ,HY~ҁ9 ~r~qAFC5Kbt_'8͌ޑ[x±EO\Q2du9'6aA-wσ. TG!\}!1O~>* endstream endobj 166 0 obj << /Length 1040 /Filter /FlateDecode >> stream xXKo@W}KD-pH-JbH$~<3c{8m҂Do;u^%2E$N)H3$y,\I0 d hTDVi\~ϯ@ S&cncJqk9#@@'2D: rkɮ@_Jd3f|DZRX:䥜X4:|آ$ cx%4*Y]ҪS7#4sݣTF*-S˜ RZޏe?6KVA)P +5/AMy%(xf&'3)_ڄ৞ҋ3zM<.'be~%2# ϐ\Wy Dke"KL X9/MZڒmֳc+dwI[$y;l=,Zwtg0}ۄ{BƖyQRdqg7?vgQ] T{ rMU9s&X@ԋu.it7%Ea]mք_1+,d* ini 2LȜ̬^ќ!3 ~n{Պ1 wZ77A=lm)P ,xU[(]q 1SnE ;'f;m6l6J@[ܳCw<YV[2ۘђmDG@~w{ h'{w yuڢ c^'UiwVjq7Q5͒Υ71KDK>,s{u2I3kqb)% % Mc׽q^)I[G#K{B2pLbKV=Z~Cn{Ekm" nkWqnؿц o;bUk>e;/W^Lr[1=H! 醪jĕ26(/]NNF-2[zܜ\){Gmq{ؚcoN`y o{> stream xYKs6W55QIgNixtss`$VjI(L~|ʤe$S`Qb|>9#ǜv4f: 'F2y, +5o0Fl /a"iwi7na\㒀g_G| 1+{#`!=o#!c3/N:$3A`|v0i=W))7/h'!ܙ6!!oa.Dl;‰.at _I\C,h$M*f\^Gg},3Zu_²OiH.%Z)`ꔦnQB.L[[dD ՗ެ&<]J)KOG".Qa~64IR | Q'&ʔ /Sa)lyw3jSW%uB߮VF@FJ,XQHB ַ!8W00d7Tg‰.eUSwuۇL*7#VfBEz.bE %S%quė-P*yա=1g3n:#:LpCC8k7}Mg@\Lh8E*Jvұb25 E#p+u^M#Bzb1D3m:Qk['GhUǴXJkaR4Li\w*{ps&ǘ+Hj5Q) Ӫ5zђ2t\iˆmJN1stZAo:\,}WWo ׷p Ka5>Ol>1PH+d endstream endobj 174 0 obj << /Length 1114 /Filter /FlateDecode >> stream xYKo6WEhш]4ARaGZrWqǗJW؈si py#=<{exRLWQLLt\ O?li!ɻ ϙRI9F}>ɸ.x*@٫2X\1[mayg$SNoj&td3#dDt\>݈ eMޢWGPH.AY"-g&ݘ-}j"tgk\h;}f[~2]LSmNR/f!x~uVnM{`^"7`\=mK- st !E/0aCH_t OQaU#@.JUF~۠/d~?P~KQA#I qbP#АWC:B}$ܭn(،ND9/"_-.}Z GMPYţ:Z_Ҏ'%;v!T!_S6t>r0*aO?[K`AUq밊[lbgMM?]SDDi%cv6;Jœa@/;؉ Hd[Y\Ĺ"©nO]2G'cְ|AV+ϣ jhP~\Q+Ypl`zƪIix1mnX]Gtokv@?ԑ@@}YZr}=]LjZõ|wax|4;x<7y& Ozǿy$x<2oQF0^JP> stream xYnF+B Er"@RER,h=lR} 5(ۑcI=9|6öJLzgȞNg쳈%'K&~fBBl,HYlܝgAjN) ;u[7}#/!>Uo a E2(w%WRh5l&g2g{"m3;T,‘ڹt(b#ƯlX_0.iEq҉gxh'6^Lf8eo%NV]g˨a:yuȅ5Eb 2&𖓸~S &3ebeylJ '!>914_#:H4bnh_C!KBP!{dݏkkbx+/fztש>_=a} Xr-n'gcL76PU䧎MAt8=77blO>)"BplsZmulH׽>\m*+/ی㼭MC(ΐ.J5_C5=]Tsn[t8"iyטm9XpyzaO0FtžbݻS*h7fdaS3U7cuBƝo}uRDG&e.b "kπߵP{8wdǙ)t\ޫS;D1u3-LQywH(9zЯ|x Q >V@#6&L9^s&RKF2Y(w[gg"z@Do-j?`ҁٯQG endstream endobj 183 0 obj << /Length 2191 /Filter /FlateDecode >> stream xYY6~_a쓽;VSRdM mĖ:=Ū"ER`̫u~E}w7VLN!DVjb<+*1[NN/vVо͍Th4bl.[^}~CJM9AGnv\h51*c0,6K+*%(z](e]35ܝÔ fI۞!-RED'"V *Y x<%H!sn;V о$7z7Ch%E'^6{ &[MD+ vѪ |񦌜Mg&wZf(H"ofR,u=8'hoyg`E nL6r'?}g8xhPݪ#6 ]N+r$YE*:(!xnfQެ*2bl.rbfOXs㙵) 4`sg%3qD1(63kVTUiug3;uݏ3{"otL^ W/3SMk<Ūȳ*|H񳀯ÖC2XpLxk{f)HĒ?~2C |mRFK?-ܜN<= >MGvm/w'o{$xD1!0.i&6i(3їؙ[0U:lhJ0ownUF`SJ&M/ZNky~2Y$6]iӂ- yPp;:fEg>=`ǺF}tfxq!\̧wa#vGAv@uq/*qȡ̻ oaEDm/$6\Gŀ=qvzVA5 XcX l B{蹯GVibSV'qOӔS~r=aFOLjD9DMǥJ -gcр@ {98r&q,4j6@JDž9?)d`}|:Pա8w&M8V %(CrS#ՍSu4Eao֋co87*?]s!!RXsA rQ>や% :Rm^"|ꨧA~xj-.g# ơ`?48W%0N_sQSIXEg/d6#z.?LBiR =]Y+Ӵ3 P#_ V"f`X*-j(/.fxa+X\^aQ_˿_|Ջ/lKr)ƹ4)q¥M)mh?zlL > stream xڵZY6~Z&[TU+)ۻqfԆ8)@P; ht OEX:Ȋ0㋴¬P jxrbiu'l`]6rQ}Gx_y?f*[otہ Cx,N+KB x <3Z,Ug=_o]SU.|u*kݪKOB xadpf*U:^TM 5ɶ4YP+҉)0y$&'&(QZ-}NJ0,Ao يfx&L۔$UV)'8wd=kϛcOPϞ"wX].Aݘǜ19iȎHٗ(]4^9M-ntCשC}|:[[1#5j9%v_QPO<li_9<3Er%(ɌadiB`h ^qzKY|2ڪdi,JH2r?2c/ Cጋn;u+^39JCx/ ;5c%bq .Z(QPȬj 12wjJQY Ob:kWUs Ju G1t)& Y*Of(PEm:™r3%0fP-QKB[lZr=Jwʲg2pʴZJxswClI\yE&8?8FU|%qLuc&6*IPo ^qҬ-d g^7E#Gk INSJiW~ڀʣAS6 uⶉFq+H$b2! Q{M̤$j60c˯ǔ'meCVTPT2qKl8Yed:tLټhF J B.(A qLAqکd'NPWw,z oc`I }͹M ca}~V:8 'e 'x,##'ҕ'R%YqJ`,JƬ=9TޕLJ8JԅC$4Qq [չڒ,ma(ՐDZV#K;"UٜY Ҟ61DfsH]d&|wJ:z!r=01^/v4uPC[ ʰV eϛ+ʿ2JNМrh?ìǸzL=DFT2ճO"17 >wŘa-6dܹ-FR~/<#ih)j:<2ǻa?`"5a~'+aNfu<pCUB ۏ{-h.T߈vQ4ي뽴t?NCwo)㝗G7鳗^sW O6諼?]S3;iz0"v$Q4EE~R.=揞r0M.}x"!rV5)ŻFoiU6?&F FmGg~kk["y X{ۍކTK0W0GX)HT2ShBIQLV,3F6es^w`x}PP3^kA> stream xXYoF~ׯ R%@Qhm1PVCJ13D}XqəfvVW2&ncYL{w?Q˜'&֙0v0p^o&&Pij*EkQɳv<&?qN9P6viס^* 7b5(dfH|+OYw3}tY$|†zYY{1p˒@]j?jLs~/.:՛%b]58ԩMV257x `)Up!Dј_\A endstream endobj 202 0 obj << /Length 282 /Filter /FlateDecode >> stream xڽS=O0+<:}$ؼ(IUPKlMZUcxz/g.w;,bʎd-u+n5OBoޓ ^LXXVLQw-[ +bGc2?1Ng?i~ad–ifX X@> stream xڍPi. nKp]$x5Xp~ٝ{{Q3MA`W&6fV~+Jo9"3&y7;o"ؙ t6(1 D* [?hl||<Af@ d hPY\#? 3ޅl)Lv\@ s%JcFhXYKp:o;k3˛9.rY_F_1_8vhfw:xY;X,@Ҋ̮D LS*>3gkGWfk?jd[% W?v݋õu{8YX;[Q#HN/Λo% 9@fV,rdCV#`Vt\@~>T7Bdc[LA{,6~l?>y2|0s?E^FRGSᯒ{|L\66nNۃO]R_ã"޺B ڿֆo =\fo_lK:ݟz?z_yvs} %ۆ8/UۙN!bvi'\_CSxsngRXqXYGsfoYr0{otvz!-90;]Lo,Έ(7Eџ"7b8,r#/;EoT{cFӿ?Mg{kſ%t-#8avsZ@n?[|ov}~Kp|* sH1Pjb'&eWYل2'H"b8:X=NҜT7 ?[޸=ɍfG?=,K)pJF&Œ1l?)a<l[&w6} \ ~!y⪌?ǟo$p˓ӷO1bϬs&]q* Sj-PYbw;Ym~q =3tvR# x :"nLSP=uNϩy.@>ŬT5S(`<o3S뮰C2pOQl䓡jͿuvmb".˱NPF@O~?V,+1/"L^zmC~j'̎ IZE\{-T*vv̄0_kKo;R+}R(Q3j=B̎_U. $&z} sYqz^$%Q`,7' T8D8ڄ:'E\td[)Z~8oPFNi`(%N>p3$z`6m/ܱZy\vIWe !)ZĘP|#g>.%sN$  Q]u={Akc5MC9IjdH0n;|VSOmG,KE ARMQJiQ&j%6+7K 7D9h ' BٓV`#:`hI A%b |MFs|jrct os@6PG\ 6#U?-{TA>yu,O.J!)wԪLh©#RkxЛѿ=B8r%*6q~D$>^:OelUaH=hys9NskEtM_toc|>q\.V`ӹk ]pg+խkSYg $W;x-5.@Xa ^ơR K3!du[vXﵭuz[1gUԑi[a!cʙVKwWӎJ@+ r΀]Dlj"no]P+:YCvFm u桝axiZyd3ZM bhН[6cj3e+sJ%!Fj2CHEJnpd[nJaƖI<{yV8H8QShX0]Yi/\X(, gd->X w֠ŋG Vu=ޟ/;<0}z.G,;GEsAWZ.e;o}PRܞA0+oI޵,)GP<MM혘+ZG لeϤwKfߒ4$Q_Წ8wN&ը-EdqqSW/BVD?E7u6j ^/ΖOjC{A5#|'t |_7:6(9HFÀWL˻cRhO('TvAWhVBu9k͆3բ ڢv{,$He}yZR 6y:oz)1Cn\Z?qFLvKku @;} E :;4> ^QNM9(.8HKXlג Xߖ+mJ<@D)>bUvQ^?U$t`䞷4vBTKU6 )q\{c A(`v' o 2Œi 8P1}WkVAyŎW.ؘF lɏ^, g}EKͩȬ8P,(hCaoD]a(ݵ~-Fq#A^)OBf@ Ohgq U09 -·MJ=,Y4Sdwo/ R9W$Ń=\i G;gVeDnW7 AQun (ߞx%:VQ96\`\Y0'J4NP% %%XWrT_FU$4l (&DlP.NeHPHty _ZW!fRXDk4V5EpO^ͼCn9(-"\gUt.1J($)RG;h={ٽX8JF-hx[ϗEӸE[a[SϽϣ>WfhlQ؃:9>rK9C#E2i]arLZB9V2 2iy3M<( 3caW#,gVR?^ʪcM\ՀWS!h9/ޣb ,_B/K} >g`!ɰ(vLLojc;VF|z9Y0 Ә/?hfHCn3W~Fn1C֒FC^,0n2rO)ٶz}&T&-y+d0YJ̨}D0bK[8;)Ks߼OWYI]w"l< 9}&Q;dtzO%EY^im?:ŷ熸vTЍDi1E `k:s;uOwT$(佰y*y [~9{NVtMA1I惫ЁxeD \;|zX"XMb5%ՃKՃ6k^=αt91/$4E,M[fl e*`4-pۉYk7[0w(G!)?0ؾG4r@VGpQ  (J)daNpŌE^]#(zC苜ϗ}*s߾Nz.Sig@CZ]ĕJF>x[!fD߂/TĦEҩ9&˗.hw 9"FL"_KeyP cSqͭoZ,b?>ÁB(i$5l~˖t8b)fI;Q5V۱E|};τ1=,L$VeBX"̣H9蛐ҥk PT`!QO&CJV ;ZOɢEn 65_Wlpo^\Osd"]qg+I<6s,jQhٌZK ) "^-I0MuKȬ6&6mRgMOUG֫5q]D߹U &M[A>PKvmx *,;5B4F0ꍛ=UUXi?/?bܢeA**l}T)kˢͩ`?&H-8>[^H_cZ#l=X@K#+eCyRm%|ScJwbfC |XB"iv  Ќ$qKGZbI&L g_2]Ɯy?L5W (s{$O3oq͘B9G1D{)фل`oJd~1?me%Is¸N'#sV,E6#pӕY߈g}5SBny^cKJ"Zrnv%pPsdH/HHDpVCZFwKlD?nS.w+ش/=lucwaȘ쏅6SZq!+00^ r޻jHM}%6]-8D+ /"j>65"wh2 SQ k Ƹ@P BFfYɠM{5u(%vp\k!Do(ĴvK'!@Pbnx7E:;Hg+ ixd|EHDPPΫ QԓWU[*|0k l2_%^g`쎂(uIB)p}yd$xx 89c3Zwp=Fވ*~c50;纑~J(~CF3"m~v|0َe,$w'MMzF3  {r!5 10ceׁn}aQ$Ld :֮Y}-hp \OY&mAXAʼ|j<t᳡yPD;KԹb +0MaTA/%*uyv4 }_ZT5o</,;c n[EK&h|m#3DRI @76B#qeY# }2/_S UhM{?y&f=<"V uAm@C(Xo1ɯ|I`G|IHk=X%+mhSl 6^eG}C @Io-ۊuD+$V֐że]raL*&,DNs½pⲁOoZ{?2^23 sXWB9*9&sDU B!D \?Ԟ{ril\pG Ef%{04cĞ=_`m}%(0ނ]e{fM1.y;`Z?-ŶAz(('"?m:MoQ@&:F4OBs7Ɉ=v1?8ۊ{^Lֵ I%:Tf acIR!À(&r[ȀDCfY)/OkB5[Usu4,ӛE~ Yy53Uь*B!1bؐ'@1rd>:}| zRhUV`RbXtJI_G ˰%s3S'_6Z4{BV"-[ݨ+ȈY^P&U7!e^qET_Ou$v96c ~FxvƧ bд=M/@(9^_U<ݮXoG}LG1R}a6ruhlt@ӱ޽"WfO14pf޼ q(<0=y_]5xtbg4x-91`zhXU9@Gлʫ9|e.mŪpi<YNy7f}#嶴N -'* +gkOeش ) 3z=#La3 ^P{6- {f)B;t%) )[lC!8gMf;xOJkX:o:|cF|Ci6U>SupvѦ lu=##Za=T@ǪОo1߻k=x~`&mYp\d+Kҝ|6 c:]=]uؒǪn:#6 3ȵfa Nٻ"zw4 RJV ugFj&d2Nr2WUqȴd6[T-ML~oxQ>Bv iOؼ뙎UHѻ 9RYo;?`=ߣ}G)yAM*hXD;-!k]|Fp$hqcM䑰|W0 ߕ&cNZH"uA(JXFvCHH786WKPָgLMDW\PAq뷾PAA'arTsEF> *-yGAQrjGޚ`2:kTy4ۼn?WĒ G0m,/X; ErL-z(i,\c қ(mһj׊iĵs9$ngSZK`1.Onj w{:v6djjKVN:bIYQk.x`D=`nM%u7t|i!E !l46-dZ@EQz(=jj'EWIdZ*lH8NVQH?f-{79,ƚuxx+g:/ )ॄhNPTyTx0<:ڲ Z%k gN!P?~r5lCx_a,r(Z:pL՘~ ?`©'قa)X(nU5zXf`w_ڟ"x.-J T~8fV*rד#;s( P0j_E""i<:,ʮ wG(u(,{TIƴ< xp|үb2gWB!7b=U(#Y>W.N`4fĤSز̺i:bUvv*6N;)aS8VMMRD"(l-paas (Tq{B @ H8~3L duk`15oLgR~ǽ۷&kYwH%A Yb<7Eo옼 .EL2l.A˗wF&ZJ%^M0')̜cN߱ +`T2U.CR26( ߡ8EՖ%X]g|M{lfvLK2Dw|6Qw1% EH2԰ŷt jGAϷBək^7eqN F< c|,lnqkuP zp{Ϗ^K蜨}E"i({E =>Be#J$2ߵIy0QYmEd<=+9t(h CܹC,%eoG,@XI ='$ՈoKd"2$bA] W*+"4=9/qm\bs"XM@vQ_B tR̔hqŽ`n@G1Hi2=AH" Dw}U dl1:qB֭;A/F[z.uT֔L1[I2CLAؘNkV+;C cq&ϕ^^!'zdc,AA*wXN4FrNf_pmbZbE/hcR@h-3-DK[7lCx=hrGsz\S_(-1w[;Nz?WrcX3uZSO-f@ rkj}ד ~+y34t:~7q 2b,_#jе p&՜r [nEx` 3$Z@zgE"6<4hdYN{a^#qiYa\d#IC㯓,Cѐ$5ܷoKk^Pcד*,wDFo,k+tϲޙ)*\64}Pj7Y'~US_q\Z\r>#sVaelrƎ}\W=@6+zl#Lj 3gb=^ ޖ> WBW{"YI$5Zoj`qgT2&N[FI7`] R0q&E.qt /\!}>b#ۈ &QM yоҵC!jBjGXPՙb ס8s'H)IA$Rdž\^_Y tZv)aYq?_rPXz^sx%mey-65) Y.u*S8 JnIz{`U(4XS|{Yhs{|k \ *1wK0PK[_?gi`}=s }{5c2Q5Z`0 l7[BGY endstream endobj 220 0 obj << /Length1 1995 /Length2 12588 /Length3 0 /Length 13804 /Filter /FlateDecode >> stream xڍP-[pwww4 .IkpGɹaV޽zw$UVc53I:32ĴY,,L,,l֠(5ANv|b;o6 Q b `errXXxCsH]-L LY;[9 1r39Zm @gsۉ@kR;;131m̈́hnUdC2@h[%@/x3X[lB\lM@j2%{_d `eb'$3hllgc5ZXJRL D[<ha 4z#Y: %)[HfI[q;IX8ZڹzZؚ!ŞY$#7̈́frpps@9{؃ta~eog0}0CrΎ. ;!L,F 3 [ ӿ;ZtYƏ?&7+fQS[?N11;w#'; dw:ZW;/o׿'ﵡ vo =N%3oHO?_hca7m]vCmClkM' |Q[3h$e2Qp66ks oɭ-lAvN<8FV휱ۣvW@o+GJۙ{l\#m89^oKjrsLvo!7q>S;G?n,/` no `߆7z"eQU8~#^?glgִXɿ[}cM?l@t?v. rߚh/_X7%6![d09޸o?*rUfvfrpsYL=YtK%\olWJwvW w8:=>*oo2FX3 n%pcJeZrlwy@ML\wMA-Is-Lu\dYujaq"HQ]d[3 S2E9έWڽte4t~WeKt1Z#J/h2(c ƙuf#kD3=ϯh/ 9ru6.< <\"k)*/$w ^ŅDB@j%ґCRXc-JCk\ZgV<'goAVla)߿X_t$-p-NS}yftG>;ԽRp,> F8Df5'x5_j%NP=!g9Z.]18Hx@`^ bcA}%xѤT4j'm 5"AΦ[pԗ!f!+itS kbH YOaYP#. ^bvfVyPeyP=}Ƌ[6SE-M-E&iSŽ=&vtYQ kC4PRĎS5N y]co]i]Kb%ƗrZg# |pHfv=5V}o Uიm%AcJ6vo)sZO!#)2Z >C.ݞN<>ok8G $[Fs.z~7[9MU>ZG']pXu\PM"XmJcl<=gSy4GyĶW_ձ㘴o]4{$_M I$< ?cB.Mw>Q؟aƓN䭍Rr\ӧ?j 3vЭowmpbQ,%hJ0V&uWj-%W"65+ղb.' QqsCGel)Քzg^57cՇhƺ{_.n[x5/w6a[ǘƋq6ƂGpLRS^C!埕>pR%7߄1aw8ۈx)Bq3X^vM/@GJtE}27)? ^9l]4 %rz2-G<'g_gny[r;#(fQ{v Iz]_wD3O^!Z(@CxRu[CZcSƼ8 F-ѯv)x7F2zZdA Ddx3l{x^XޥIYyXR\MdlqIvdaFRe֌]Qvq~ز,, 8 ,#pf̼M/"tnKX@p'mUL`n.It/S~oߢl}ɣ B2,He,҇FmdrOtj(>7Қ\nFw65h:*s,?URoHW踇\|O Wee8 Ց<}\?&),vqgu B^섮x("..]?0I,%Q$ajRWgHkݘQ} /QGn5-c92CBO]Jt\t'gX"+nȇ:Z}:_o ڏ ǴLPW+64uquvG $ղf(u+kꍚ3HkS .].Xu&;M%Na8w0|O!{QZw t-U'򦗦REˆy` vh㣆1[b?=ߥA%28r(<'́-H 8c/tLjc +CԌ}襑?n٥} Ssbm b穳ӚHu)(UJ8&=ty?u4^Uh}PtZy@ Z6X \`ؼ ÿ;L>ce5T6.V1M-[MpJ46u͘UYf5n:[erH2XӈmZMF13o^o%Mw.3w7;}UJ $BYB=W.Q.,U)ު,y$8\38?+NXWˮ},E_qR4_?Io 6T8٫6 m񦕁Ee |յj` "kfcs>'C'9nRcΊt48')6*k$Iٍ@zB5xY 6t䳂#Oʺ_sOdLqH5D?O C 1ctms'stI/#?mb>>#%4mb_Ax|Whs{QvL87F SLwS6g6Xö HIMEjWtTl(+]ٶ^"uG ٢*2gq?Al 3rF4 ѧ9]F۽ Oa-5 'Rןc]9Xn֌0mEoqT0*.$QZFGti`B}ꖆ\#Lgr:6b^wbB©JCm_1$5Y5XL-^GL9 F˭xRm\4O1Ʈz5ux7wJWyq@t.>u|ib{2C+*XUY\)dϒ4b"~k,J`q`'e8blu6yGb1u{-5q%12)SVE/-"NJwh]YK. qYd_XYלz$|!mКJWbR@K75{~\Lb!@Q%>FTڧXD{Eb̡ 6o9yY1>⺍ ႒BV?[״J]{ ?8 '2Ní9)B.OBx^MG4rd/pFۆ#ߛz=BKリ&8QTELT}Ln|kI+!9Z[L;f QN WdžNçRZתLˆy"N9F5Dl[/^LrS6TT_ 4MBTOHL;>;))#K#˻E`͵{ .=Ls@Rq:XSB 5 Uxߟ;g#җzūn-%vhp sSK7]z/M͛"6 2H6ŪDP>T)+{͐C##-{(/qO tc%rj%wKj:GH wԑϳoCx^ L"8*s0u\XQ@y9gv1Me>+nQcacVk`.S `==^anJ$d_KzyH,iD$:Y[:8$djxemR caWEJ6}6IeuKgMmw5(W(\+Aj!y*XquwA"BrZ\{ ijۦ 8TkslX׸)i9|Ih J[]i9(w{R+úa(}ӠEI &Saz\vǕ]=<`shӘ(uE"ںHhఇ&Z\ŏײ̧D1u[>P r:|7xȟ?`VHEE7*-6?jYԂ.q&Ɍ~o+rA KU^j ;c<OT&O[++Ho0?,!"tBϼ:7M mٶOS" qOr*㙴H5, ۭ`|ґfZ;YƷJ>BŸFi@gQڤZXn~3C궭}7Ӱ4WE+Q6tA y >#g2[q$% Ml~&_X 9v:ynFmG8AO=Z6=Ý_%7XOq߹#G*̝p.Nܚgu֩lȫ7 |`d4Ä-doT߾~UGr^l6yĞ@CDĆX|pE{ə J+od`k?%;p&ׇyoE۽63Xx4"MB^EMpTQ_1dk!Y컾|6sy1X乭2ƶXauaAk좍 2{MyҏpPV,l362}p>RN0я:\]7|g",AG'U)1qKOr| 7cްJH>q+=<p( O6\?Ⱥ>/`Qe:Sfޤ:h԰tLy.L!60͒76GkΠb$ D fGBAiF2K+#] C v(D 1[ʲ@ڇ08] DND^P6"z1 wH^q%8 (4=mL QfhEGhkqbj`1O2En &'JE^!-j4S%um6Vx|V.?Q/*~u,ql4[y&m<Ւ EO";t )B.qsO6Mz‰ںS߳H7v}U))syy2j\52Et*VhײRƙ1 )c+;(iFXHҤ#Q ǀPߊzxȻpl\*dvȚۨ<9̔@}(Ft3>]mHal'ErbB rI O\0IM*M6ʐvh?) C x  +#$d֐,i3zZ='c5 A FI0 `xfMZ"NLkM IԼkmRuCE_Xw=%7y ) >-?=''xttxVVg+yzҒPeP>bh P\t?FeVA_[6\N=}3S?I4z;z`BZ) ƪ}> iX, I:!5.Fq2R6m[/Ry\Z岛G(qP3g>B]*hJA#to 1و{ pj.39t6m\s6d {3~DlFO]sH}f * u=:kN1eЄ2hIP˜˘I_Naj>hF"3yM"O&X-{$ux!Xa&u3/UB;tU.ڃB59GZ0 4fk;[xbQ~x '#-^۱a|b>$ypda{W;MOU`:N}U3(12;SpOI'>>f@e6y[["+ę{Z)͎+%Z:K",fy)Ä|SL BiO_|X;r%xUUEm?YVFj^ӻt rJk=3 N%Pi-{Lߋ`GJGXkr\pTTW$9bRs{& QD{ra,Swy\ +hRy& X_ 5@{H)GsAS#1pwU5Z iT&%:EZ;Y9OhK` 5nH.TH79b^36K &ʴs7M!c_%aոTMjxJ+jVwF-im;u]5rk'ϱUg;yxa3h-kgc0E]V>d]7$SZO94,hg<. fVR:%].x;DZOAhy)Z"AC SQ)i,@b֊oKZ,gG#O/KRqSPNg¨;ZֲmIkjJ'M_AfG4}#Eaf\) + $љ*6_]`}:C?^ WlD{"W.RUe${1&.A,wxg*>%zE :QJ2%GiF/-Y窋81FWF}E^D :G%hqd)=c}O8y#Yh;Yf-Rwܙ*^{ 4ؘavU3}$ {\(4@IJz/k;3j񕉋̚u҇d&=m~#Vu"#'Q nkțfj`ōչR£{+ q7[J8ڣ1<0\O<0 W8ѡftEc'YU^4`a'zX~HK>o}_1aøQdS i'[dWAEO=Ψm`}Lؔit~d%g++n__KS_}}o(3Gb.=}t^ L 2;7@@ex*<MHTk95THtGAq?X#d[q`Ac@'& f7H;%yL4dbv d4Y$=AQ$d,ً׸f3!һ,:؆9OA2Ԛqplڐ +:)޲\*%}g$eh3vVڸDh5Y\0t?G|tw= |q?XøAu V@<6ٸouj?+N`O-қiP.1E/KGuaR ݈CEsc8k<\e^8_n'q8p#Z/4ph(KdX3OUUw#$7=v7V+Lw[d_$>| =Ź,=i_ ,2I>!{[7+'ލ=L%t]v cf 8`Ϩ݇%f(GZ;dQ\OOeLj8&"hnoiC &*Ǿ:Չ),}Zg?Z>ϩ3;&"m)}@.Ɩ6@]:0;FY#O*cؕ3{bs[)̀yX9L#D_[VzdZ8WPw5JEAQ@Yl"X6[N5_}7pb:HO=cj>lgOr%P~W"mzi֨x|{iI_Sä=dTfac{{Я-TwQ DuH1 hۜo[,m1&H콆kr³aF'^ˢrzQ.>d29!9K%Y[QDP~: {-8]w S ɛZ!$fsUzfA !;dEФ1~:)1=OuV,3lDWLR=CSa2mkKl)gL3׊Em El<Ɖg{>i".u!>j*wKEِ02DN+#0ᬺ񿿗%@NQ5 55U"1gJ9Ch@x>ePi͜^`{v`Gt ~PHH!"ԡ8?eP,1]JgeXk?V;1+dYpr24EF6;=w^SL6acwt+աq? *(u;M.K7(e sōҶ;HE3V첎q|%0_1 5\up\7(?>Ӓ_ąM#Am:?~?YP}B*^6*Yl'TR8JSD?x ^Ns2zvo-u1Azq (1|-ɳ6x@{ ɔbeRhKŹo|I֊RF"KJCϔy`0N`Mb1֪P= E҂ŠMysҎ/Zw/Ƥ *7r²zBTJdt;)|{ ( J{NthТů{j!s6T65bZeL3N^uq˂߱" mpAY*ka'~}񛎔zzʮkLROK/ϥ3 jQ2ZW7,JzdÊ]:_싙h9&7M(q0+x]Ky/KSb($+jqK(wE-pkbE+F r!Ę1\i A9jig~'/gL ɑ!_{$"=5lpuOQ=ꧢE#Y4I}("z@2I$ 3 jta|˼ %ܼ endstream endobj 222 0 obj << /Length1 1588 /Length2 8710 /Length3 0 /Length 9744 /Filter /FlateDecode >> stream xڍwuT.]!5 "!Hw 503t#!tKw-)% \߽5kͼs};tU5$, f S $) aƢ@xAP /?^T%@psr E@.` ;@aIAݡ`+kCL.!! {lt( @; '5(CVbLW0. @{ͱc4?\K+ < C xАS8 +A`=.v+w0btp;X,v "; :X"`x l4{ ^< #>g0s(c~u+FK;XHAAp֯CA;:@\<` _X8;rh9Ard=Y>NNN. r3UDЇ#` l z]@8olXd0,*"pd3 ?!!!w%%!nO6n!7'[ o[U?rm<_?LJ ʐ]!'0,ckq`1`;?9v?LaVc%!v듃fEAl\으0B 7COC;H890 ~@ߺ_B@w < >'Z~?:XBXAYLу*8^#AnHHq=/|(p 8p| > g̝Їb/z@Xss@ 2W/ܼؽa:Ҥ.jR?xrg%'sq/{&iF4[g{qStRhk7q"Vz.>Dt9Z:Cc/$<[$Z$+%&&[ha_(dv[/bE'vT8OK`: &a 8og4 &*ξ~)$.bϥ-`ͫβ53B4쬤+DF,%2 f/5\D^i;3·ZwJ(D΍6$BFD5/ڗi{S1ۅWa)ov̏{zb#o7O+93o3i'"Hq%4[db6 4 \ۙBhR<$3rnqɟ5<ֳQx imt#=$),&vxJto;lU)q RճAFhG GY=\C:'x\ BfϬlA+lV G M_Y[i˵S 1աZL[wG#\]O՟vW)h#+xiIE0lsJ[5_~;hgJ^* k[ܺF~86Uנ1zc6{Ns0wf@^䆐CB֋ܓERIp#Zg|LԮ"!&b>;B  -[9RRӢǔ)vI]׎ڴcL KH%h\KQ{-Ţ'vd>~b)k^yFRۆ,"_o:ajH:n0U*wqKs)R( 7ʐSǔTqcK5=v E)vN* C8/brGmF>H)rziCgS'eO]C("%mTl,(m|6a;[M)%op}b$!KWbwpãXiLvd*C2|e Vl8O5Hx<&)5CRGOʃ!wE7/HF qWM5n&g8B:k"-T+m0cN=%n'ArL ŭOߺ,UœtfG$|$%y `)A>yxqёDQǼ^"ܫ7FcT{;5 h8YulggKc+Q58veDL epMfדevX=9(4D(Bax2;Ku1R@ we E?1P4.oƍ/x!xo\jǿ]"R%wR 2ݢ~$/9Y? c Dߎ׍7 z ENgF}<nY;fp԰'.}rcQ*_|U9%'1:Nӝ%iN1@XOZ)+No}$|tTAs$3Nٹ׍y\6ٳf9Q2%yO7H'$6F,A9ح>~ȅ3U'GS[2wYV$}{^,pPY[YrCL+&O׼c,ش[d!OT.Ο$zbuMq<p̤5A)g*Dcvw3׶4PDLqA$mIjUJ2Cų:TlEv>AfMK\DAbכ.)fx♬6^Ue&+m``@I` %=˗ޢ}Sn\}ܐ^9a&2I}ͤJ|BAcԪ(r$&HZeލ՗bhjh: N{3㶃7D!-w:44ɝg Sjj/c^Uʯ2(&aoѪ:ql@m,3zۡQoMovRK|di6*/EV+~33۲9UlAB.拸SjwZhS էwVwA߰$4n>YKͯKARI<9Jmlg eMqg$>ѵ /=gqo݊oԊ׽xOt1E-p MUCQ8"cqi Τij.짶H9/? i0KḎK{Ռ?{rJ;F9bͩL[y5RsY GYñnj(ع]QI|2FjDSx1#aKk<oμx<4v BB6\kH nܷ*v;C=BxIk}ov˿sV>OHN?ªBa]6T4TJw3O8j?\G>l\_刽9jʉ^׆oLg不MxшV}oJiMOVh6+L59TA#R r%MX?}dQEA*yV;bm^Ԕu+zcx"k `}\Z Xj5Fcgf2&9kI1^x4$LbᔦCoSwA0L2m3^wtj^lsl T[A_2 IusbD>xԅ.f3BK#ވKWM\:a(VUab49mP߬anwCTI4Zxi9s> _~":@h$?C%*0XCWTBSOajkV A㹧9O1_|Wguӽ*4ea1P9=Q~ՀK$N.e2=Z!z3@ 0"w]{v>ƚ2)eC٫\@:%ZۏFb| FzNWq!śE;v31( /FK,tezzPtO? nAk j9EX$z+\UҭICJH1V;rWGr6;O1=a[]E&t?S}ۮ}<Wth$D`"{~Dm;WWhW\&M>0>^i}̀D^ڏBRv׳74KܖOzp8% 1IRp{b޸L-۪8(/XkMƶ0%ߠ\ 6˰}|UA/y}ٍunGi/-,ԟ;hq "Ƅe!oY4] "LB!`ٵOɠY]ծV!ʥg2z L|n?}m ]Ff*b0匐vx^s޽"`_@b;]6'IZ:TqbJ`4+$ц؟#s00ř, jMt*/9<3TϦ\OtÿaeF)j xl)(٘ #6%wꃧmn@B4^F'RK!^xPwX xH.53G=4sDs"9K-۬5r+v8e|;e2=wp _gYBV_?pU)0^QY\.`E\P[c%@WrϚ˖,];C,?y3BIIYKZry?b)ʉ s S#55#0U$=(q|ج8vOcZm  -iQ7U0v1|ՓtgII)SLJ򁐧,JX=+< Sв"L] MCeHq#{2[;W؃-,K5oh3 Gd(̕™ T6lp Zڡ;5U򻲿B 9s썷PHU(7Œ>joϻn`UigiWJ7x"| яwj8r2<40Z2 !uQb T^kz"GPC4A ɺ+,+Eڒ0=ߖ, e{!?STl9X$hԉC"0ZPTW@8جVzR%4uCuV(i@1K̤g9AyMM2}!S@WV_~O,9=YD'/ͱJ95pW~_Ѝ O1NLGKFq%"TiؚAoEe[!,vNyuh63=]Z|_XDžT$@.0?S*K֊L> 0Cc[jc|j#z#70 xteYzItgrL2][S >L*TKr~\2W ,/*zͻN>-"49Hiw#U:wvӾ^& %Pch0D/-QhfLi3tco^ݐ725f(11T wd~^tko5u&xnQK?DOe*[&#)rٌ[PD}̌Sp nܝN a$ra@#w_3!_kC0Cwݗ٧eBS?za('Xq&c#P3a;sp[bKHŖ^Vu꤄ 9aG$:/{#ofCHD5e{X ڭxKOef*6jeA$w *(I&j3w@5Fq[i*C*=u[)&IeyD2MzጼRM5ao˅;+ԽqEb:iBsm91U^ڡ.TF;GH% sz +RܘsbjbZJ56r٘iN:<=C 9{Û2A#JhU/ZE{OT^D >snkoY`W^*}Z18{CDS?&A3ܫ3^R[1 T)j@OGn&{{ѡ3E=qX`/}1Aa92X'.dF%翡jx5VڏǧZe1#sPP0d`stf)7E!XMZN.rׂƘ'}-W1.QUjeh T圸(ٝРw3p)xbTrW#|<* >j#ʟyMbX+{>[p<^CzozUbg}XO8_yރB펝>Y^Y.x"#]5̆o>}67Ah!J"EyRܘ^F[1:RWh1V3h(܇gzCN X[$[όg+*ɢyKuFO4C`-~APaxf܅Ŏusei ~ BetS|w&vs69e:I}THՓN$R~ X˯PjBv2=Ke>/)32)D͆p+&6SH&5ۿjk6GԖpf#?}!P0OO2g~k?Q endstream endobj 224 0 obj << /Length1 1438 /Length2 6052 /Length3 0 /Length 7022 /Filter /FlateDecode >> stream xڍwT}?RPIf*p)c m#TRDBR@ABBExz?s?9{v|=q޼kįh!X~H A aHi Ǻ8Mah e4 T X.z  bR`q)(IDKU p{P aH7 %% *p(ԅ``nP+ ðH-Ţ=== n$Qu00xq&;1 FH' p( <@@|uPCvpp`HG @H7 G80 {A_8B\1H|<w~)!xah8 ]/0 ^*^C`1Thނ@z"|{ P& o# I Ka@I𢀱7 P1(|0~O?% C@;#wv[ ZA=YfDz׈U2_F%%Ї_X/$ A"@q?FK{dD8 %.Po$gox,7-A ( ނ_!?_d_=pue!npW?xB?C_~o.X~IxE@"p f:&p#`wŃˆ= rgk2 jCE_줐FCxJ%Q0_ X|D.-&tǀ7ցM\(Q Ʒ&V]0 @B[+=WdHͅ ɰݪ6 FYS&jmzJ9sv|kkE&/'ܚl$xb&U&EN.omIWuDO.5qʒ,zI/ Mv}+ ~r ZH˸-zHZb x#K*Ǣ"rt鵟4>v /yR7nr';&9DXQ3tJiH0v^ig:\\'VmΑS5-{&Ȟ.|JWe *}φC}q3! 4csjarku{/=imUrBDjf|3 oBӫqn^V:nB2\ׅԏR@gm1 ʦJ J^ҿA . 97=S)ָiz0h_>@^iq!夨ԝcPXޙ i>4.cr;pqӐ6WGm`i觯ye>:\~lɥourS˵y =3al-6yD+Kk~ya)Aͷݱ ~4#I<Fc7hd0B-ATWbMC|cJ+)!W@C~OP7?8ыED^T)3صE^Ph'C] KT*u7)NNzw*ӆr?4F68.%H7bTdbn`>>i܋!yEϑy+ӎ&wE+]{mݹ+ۅbYq_lT(}wfY7q4yU59wgJ&( ҇u.5 (ӟ!GqGEC 1hȯi-6!G.<8Ǹ&sU]y3ZrT#y`=X  :˩TT4n׉k?|oZ s=6`CygvLzzbBg"!CV Uf\S^9W2S{B]$t楍a5\GQkGAmB"b^ yހjOG5v.?Uy#;Kʯ6zFd]ǃ!ߜcH툔gAtH I;k(KKC/ǮWU .$au]/2V# r 47GXmxTa@EU^TzQyۦY[!P'kCת wʣAD^D4|&ȳhɖO9J"UgD _^ĢI(7F9 S F}jTN} Pg?Yal ɾ͉U"ߕO]Z^6.f+wU)PkCv;0rq 3nɽYzҷHGJZQ-Ջ$˭|5+ ԾM]q`vYJ؀3"Nc1fˏ;JS2+w9PDe=랝>x@xNq+{!~O*+>pXҕtR'̭ç|RaSeidxrSr>OPӈq#1W LR7\gr8\n*KH3k]/>nTd6%07C(7B3G}sXR3iywd+pT_-FV>$ \'Pۊ\zjN3F~e9]ћO'0Gb3JxyE{U&HQ;.Oة't?PSSYOr~-˲[bUdq=~ Eb_)~'t*Fc(B^ےhMpeWU*5Rܬr5{?< s3ZQ8br'O;1 t6AԜ%`J/R]E9Y]ڇId4ppmYVgԎm-(zqո|FM#{<3:ְ**Pje*yU-V[ Y>#[x{F??($o'8sr"3O>ʣ }CPB:5fAX15(`YfPr))*c%<|]{!f͵ިuT46pVhmtUb P#"BsgML㦴7RGJ{n2pd69)nJu T 1^HW+^$QM>;]̚};X]/g$*=ulӭqVͅ.M'UޠB+48j7G'_3fo_- #N? LO>8n21 tY ÿG0xb~wLWy>[1'f:1]dzHV fjE|' nwL=$rƢ>rEW@,|UeVW3t ١n qx_i'煐w9I;(|+:TԹp}ԄY:Le|r#6dx_H? 6Zz={uF'<1v+h;DM7ȵa-Fƴٓ> stream xڌPYB Ӹwwo$ .A%7VS]EϒgoCA bfguf`adɫ0Y((Ԭ(4NVv9A2qcg-@`eef23Α njeg(=,,Aa6p:Z䍝-6U;S+(-ym-inVΖhU0@wep5K+vnƎ@H`me uyؚUi9=oc /?޿lr6657[Yrc[_Nv cWc+kc_$DƠ)ىWLh@]~gk&fgcuv#v'`nekf3{&u[+?& o:L<)Y~AxAE}́/8/'cW `fe 0ZXfc̠c0Z/3;[k͗IRRMSTՉڹؙ _Kz/Ϳ _IIFi[s;5:\Y  @ P^}=ffS/{moB.m=13Xہ5}fV.6W+l :"Ihdljo zk+[կсЅ_* <7;[S;_`h=qX@' jmA.Py>s;G_08LI70q1$~#Vo`L2(o q~#P<7(o`R@U~#Pt]7UkFx"_.m@Ro/LAc7y3AU3:6jV~A|,ֿ\`XAZ9K{K ? XAݲP'~3s\mATd@vQكu@cgG Aj\윁f&adc/)?#1 9s̝@+u P@.#u4,? (q? {Aw\.a8n]k~݁pv|k[EG(5Sh[]?Te:ވ|BY|G}-@ucSrav38֏C j; P8p#)߹H-[Vީ┅*dV (5ɜ!rf E;sGB{%9f+Yct?EթWmxKt/IWIҏ9وK ({UV* 5m,[9T?зjJ0 I1 #ѝk> E[n4:',L~}L#j[7vz=9, ` Mnh,"pc}gțNyM&P~3[~s<ff'9|*֦QZq*'Z3MCW *c:[b/ ;#/dY9'DB9#_d(ad>_4(lo㦼\sN-LtӺWpnxvbH䛢͙nXc5QWdM5͑'72iq y^}sݸX w`(˟(2v! [4_DU<Nl Ml{YW48R!(I~n] PGEG4-ԤOCA1cI J2V 0^goxf ?4 T:ծ`\ uh <\។&UoeqS]|忰xħ|Mk-BB,xi-YɗM2];v*4sh v֚Bc'֘^0x3;&\N@"g6YowŢ/* \spLߩkyO~|?~OS>1鶾ΪoWֽ 4|Bv9gAK2) XXJ r^Q2NUWeIzޕSoQ?H?Y*4KV+ŧ*hXX}eJ{rwE8Za}W9UjJ׮A9pAx G?˄(#:k/<[l96'Ԫ'aur"ڲhy>{P>a؀ e6= ܖ)$DJEFŬ5+nYl=5aRY;\ǔ6O &${e3I3Cz,þr B@<'OHq0rYP# ʂ\"%xȥ^(D,m9=?H(_n*(~t M[ΣܭYG5? 0Dّ xLct5*f`q"RQ`/2ƨ˞:jHg p.-8QX.nqioH,sYKD#6\$Y~OM$`݀>qbxBw9Op)wF9P7Ag\Ϝ:ۏ">v2 xw_@$'I.wD$ K-at 'Ǵmcyq.3&-q:R8M+TdQ\6 _lJ I)ŌaBjt:R߾oz@O7:>O uZQ١WB-0Po.[~7'Ɲ)KZc6O sǵ--졪{&NtvK,qR+ ^CDb IUcݰ@;%wvLhͧ:EIY mtR6+˧u)=ҩr];cS;2{AV.fz'&oWH΂# N*<a64Vn4K"zTD UDݿ/\9Y8F\\W dw>g(PRlkVY;9j.tAE _ 6-fcՑR@ bӦ[9Dۤd+X!YX?bǏKdE?q{u.W5 &Y+DžMt~˼/`VťB0~ͻ )S^ýk;jfA&Ee7J?Q}?Bur pcIp%9q, ڊdS Wb%Qeg+I_ lM}>UOCPfW|Fxt/έGH%U|bwVi*PL %i>:'.ƕ3-|WxD. :?, r jBDU,fUu|0+iKΌ@FCN`kaEs/NPe gv5 K辔%0>[U;!r2w!Kc>%n )m &*E%j ƍ)HQS{i\!BѲ{>EeJ~6)dLe6|܇m5)poT4 b\izXKS馾Q>'>HEWOĆ">֎^m4"/C!/RY p<6Uw 'Td¦gH3ݷrk(&[49n~ш+aQuγZ vSRWbԻSQ{=9CF 'w.KI˗]}L8:=|Ig2:+ۜshvx.rCz+ m/PX_\z$y{rf-iGS6sUmT+/][Ghڎ(71 fD*ˀgTCXz &㲂&ˍ1bW]x`5Rc--7oAo#= ^[ޣpIwx[uyouź5kGӵ>=+`iv rD9W`)c,1Bj4hm]V~^#c"|\ 9`l4ջ>~;Bn~tlKTe-Syy-Rq؞An?TH`TWBew>T&:@)6sYypD_8 `cVfQ cA `EDBy=0h hI 䜮xjڨd8rɯ'B`cT7G~frtXN_$_ K!n-z} /uF`g ״4ڒo |7\;NnjB(s/ҿo&%?>QɇmThZN.t!<_*l @\'QeUy<*S߄ϝ1%0o{EFg8h&\ד BG.\wP-4ٝ֙vm(|( %TVz5 ʝR#WBjsػ ЪZ5_h-4gZͿK7X,2}U{Ccv(>LGU-6|[`g[ˤܷ9ul _t ,H*(zĩK7Oogxh}H0aN<lIdC \+ Ҽ F|R/xp<@t]3{OVj 3ڡ0p<,$W&i7;e O'@:UB^.Ә3UxܸYݯf s O2zK_*.Lp޳LHu|온|q% \¯ީK(dJwCV{м$z<,{'Ş~If/ "u--9  fDTfcEg!a(%c2SX{8ސsD,;H,eBmȑJ2INYƥ:4j%O &G?gWaiN?|TGeVd6Lf`u@l0e9é)dy^hQVW.TP-U+xT,c4^'L3yO{WrIyix6*]f'n#z.è(3=;OeD ɓ-W[fvwsb Rlʶp[HXbz_^.uΫAd daDUaeц'2 b{IQRONg'n#670Y+G)qkBF5ѩO @ⲳ)3AٺΕPM7~!N[&+ѠY&9iL?i0r`iޣ_$z<#Bc:%8 t8:^e K{sHV64ČBPٵp *1k[;a`IJ0$^^db]96iat>~ nw,jJ4NwV}6a&-*Z9OL* \]oy%c7*ZA<%!"cX)tTk^\[n|w+T8Ђ9DԖ+s~86\vST֖.Up ʴ .rؚ/o`Qn}v-kL\vׇr@eʵІZNvq0Q*joe9MZ=(YyoɄ;6 6&8`Wfn!*b660Y Zk!QX3*B"dvׄ##LݹjMq*?Ī^њuL⩽;4c(Jay\{|R/GPCZ3KWi(Ro"1"5uh nՐWjvFv#H}ӗDN@y~2 vlIw]$/ϹwOvoFMEC~EL5C=K˯1MjY+ t02՟ClRb&Pv4^ш}*Y)RM:t*xX*wN<vga߰Ij@3`1Nl~""SHۺ;Zʼj89^kG`9\\3lCI^ `-s2ȍeGPgPr([wT!"J `~63GCuZK?rPaQ.2]HR~J, NkDNJkZޝ)y}W2\7{Zcw়^)Z(zLYxsr:Uq{qN[YO<ĀZ{{( 9}TM,?m$5 ʈað 3>{!Mt6Y#ag)Kon|?˥'x!Wg#V_-Rə9.e'y;+u)=M (8'`T{xd@=T+iDŽaXqqJ,z4)7IJvF8\F~R)W@z;)z4U$#쉉i]]@@õ9xa!~c -FCЪmyiqf b~C^g/ķQdy(ngyus:%Ԉ&?,uNsਜ7ZX-t-HOD٨XW#跰rWǰCom\F=ikà0t%z$cT\҆Is}1-xXt?@{W|2Ol+ bX+B֡R>V]aC_{q-4-Qd6f()~7f 8F󏺾(~$U*.]#f_6.` DdefIpaP~x+ PN+rHE;lXfb=Lȹ 8  .O[ןPE_3INUAP&|2bd=6`rQkϯ))8Gz9bu2bmb4 :.Z1G { \ϟo^ &k F]3Q~M6&dOD>K֨D 3g>+HLi3 3Ձ6_rPs/F R+qĻô}sNCR#%YFDrWRۂ41w6ƃ_v#gt,q¤nEW$Y_aoJ$ٔ1F )R˼\#z94DGE7l9fkHG\|Zo/ݦRY[)Yo!o뻫 "#*;wVY\iDx^9c* <-1,JwnT=c3;8 BIVH\婁~z&dא$6±Q5`?"Xܭ'cWx~VQ5%..Et1;J?m`QΏ"_aGbS͞`uFV:^;q8:Mo9uڦb6S%q~Qoa E Z_J[2 `x9[jCJ1\=77_C}2>ia/nφ\M)8_"`P?u9"wTZ6s6PNÎ;BzҒh_@7s(,I"̡.ur,'wEmk$BY*&K{Ζ 43ћiweB3"ga[! -\wrVCU~B`EX̯D@oBCKbfJwE?吓x1ӹڜPe+A ʕMj^ ŵ"ֵZ,Lf>xq sx/!0V3ҬꗣI cHju*8^l՗ќp ǴzVϸ{mӊ`!TXsFY0++!]fvN'=WQ_5^@7BC]>\!bp." `"`;x(46sm$/q7E<꒬߳?GTr}Kr; u*wDamڹk֒|U~vy^Hy):yR?cA'_CvEEH]57d5}Yу@OCs0%U'RE .6 `: R]-6̏;߹<C΋;a܍xׄ>96{WE6 ~X92_ʷ-lSY01Z,4e,SŒ0;r1^6sriβcD` )* yU[^^}w:gB*)3D:$ivevXvЫNCB+GO >;~-, `J/ c{20fD}{#{GS} xh`Avn i1:<Ϫ@K"F̣C8Y}~;iߪ1K륦y`mhcҼ'jJ0wǗj/dϤqu+Ɋ“ƒ_!'vne )mر̂i>/&So,Ɋ}±&9rᨌ)c2 pZ(/ֹ;n5Wo;%n2C ː-V8n X,5dX}xhґz2h#^ث09o&SMǤ?D* ;j0:4~$P4HƇIJVEJ7xUm:հ0^;Rp"´C2yNvYp>b-i3dP{_`{dl INQ{q >GFI44Ż-v)j}SV< 9k*hÍHyFj6ۈ.jMJo> lfo6&sZߞx\l^/P?vq}Q|0šzя8<'1r_u5 F/n^uZJJK6ظĢdҨR%r79pVJ:xbb>8L@xXRI)u9wî,v1(..4uXu~<0}P5 5vuC뤑%I*-,q-p^тK,a.qmES^<@WxLiy wPs)D1l?hT#Y$6S)&aNh9edewGҞb>}W˺)34={SDU{ٵ]؊ܥC8Ur#]74`EwKSE$XdH˜ډ/h{ŽZaKWC,B2Y-.GE)$N_rյf2ܣ:WGDdZ: ~m`.vߎr t3yrt$n a 3]qݪsܺµD47vp}[⦞^uwu/2~E]hnJ|y=h{Fql&& `>ܘGhgڼ z{g JRv Xo[¾5 )e(KłD$=v7ٕ}vKaPrD|!#Yjtq*bϖسN/Y*>e&x/Ϝ FA{_O)UQg4Z0_ EQl 7$ԕ|6]#C0MUڻv}CK2 6LmY|t0#s*P%˔b+2h6fq7#Q"ڼT2ތ}vL=rYv3F+XW %x F†4EO è*iM |]e4AoxWINcWB(WaoGY^/f;᧮pִ#K6?Id-bTE$S:]΍ .]1oSWm rOCJz2ӟlg2> ؊,2UD[$M]f< x.Ɏ 6PP@ ^veRxoSІB~v~A|kl2Dƌ C?{CI9,n/x-؜&C Dξ7 D Uog ł@D 땆гx߉8BZŶ촧DSe2!|%N5 p $ U#3ӮWbW9F]{iOe7uf^+}r=>ʉF@ǹuiⱻ{(b/JPӏ1n ɏ|50%>q5|'ܞ*&nu{%+;{dޛȞ?Io2 ea{&=DX2xCV?^GtpOĺDU<,gK~Us}`1iMnӺ(xm3+V Ykm@LW9D.3 2\(bs$JWm{ls&ֈԽÝ]"$>I\!END5wqfYN*lr6mBpݗTgp^w@ЛTPy4ԼUqlĴl%!ƩqHsg"[EqI9F~jġ N oio+COv6J6|dz_+E^o\SwO+ kZ3}Fڴ4\?c뼈Kv;1?ŕwø'"Bmy_PxbHkemD;`vzQ V厌I/*L]9P@M,.>+eqJkRHYɲPG Z8 |XX@ AQK ܰei6[_n"ˏ^Z'BEڋL&≮ ְW5.%鏙:Cha$LrGj K ~" ːpY hq 奠8 `3k5p5$I;ߝK#{z-ٝo L"ٮCQ?~Qw?mJU:ݾ,RkqE ᛏBDXy8u\foo7.5d2 `yL%N `?S)/=FFiG9+<}Y*h>H8Eb؎K)l_hoҚIS`{d@2bL֠\qȫ(щ>+nFGQ6F5%G9aNhwtQ[?JܘW@ܱuj$N }7swkGzS:$}Su\4d]0q)x(vhg)ɓxu,iڔN6dZYmhB4>gي#2*lΌEpI}Ͳ8 ϖ_UBEo!0Y:IGJ:Z1ثR+'Wܪ1IU_M  UUhDD@AOxOb EFKdw~>!I= d>پ<,xtP܄8KoB}tP#k}mF'=lzڢ4Zgx:]) ^HBRL]9 ڊ\Se9 nğ_{G'[gw'u*L^JR$M ^"BNj|Z( ix!) ӈ>n 4EbP"m["]ǘFVRtV"FPKYΰ~XWS@"[2~"C)։(*Qo!6N(vbjGɗF\ hߜ/} +XIWqD t*$::̽:}uٴx+B7Ȗ-`Iwaڒni.Dc4A\"+rV {fI 5q-Fg ޷StQM; NgYP6 |j2(Xs'KFct@* ED1"~:֜M Dgb th b{$~`} Z mmŬYQ cTsBm9n ь ~>†%-ҥ븘My{Is1IuIVKW0DnB XxKx52_UˆLhӌBvL?$v9:$xTX,lܽ˛i>M{[? Y摪2ϸO[KbĴ 'u[M[Ԧ7kߍc#߾,.2FmŐފሁ:jZ3jC bx+Y+X ~+~zE25+ÿ~}h=%лX?£sC¾S.va$dn" rb9(Bbe_**!'WVB2r-Flg6ɋEkZk3slʏ[z[D\i#Km"M KGq__2"sy Ëkn@-9haA; M6Zf}.AK wL˶ AçǏaE* .,+ IX#?<7;O@ n2s5 >Ƴ>ՉJʢ1v4\YIg HLHdJa`mDg2$ڷi}bރKFp?^iyxkNT=_Y)̬/3dB+N4Q<1`a'j=qmȓ$( kBO`Eys.%ܙ*m7LV;ׅxG*(L?.5 )RGLRX(~vU2>`40 \&"JYQ:\O}6[ A4p\*;񥍕X?fT0zEfŎߟ:X vזSm1.q q6R 1<5<(UIޟYq} @,R|ھt5 +2`5nM@YiD&Vq'g)cDӊT{iVOȈ~]u黎X4h*Tڤm^̌^:㲱w:&٫_砨eו0̀E9h"~mo,I _G!Z+`4N^-,G"3M+[vV(s1=3s_E..._u@S @:xO(vy?OQZ \w՗u Jr%Œr,/"[8]H.i%\H%;/:JMptrlrYVy1Jڊz5`yZH«?b7MDDOZz8mGG_ׂ#(қTU3<(;Sdm̾4~ i!4bx_ȯxep(o6MI>'ê0sL Qaޔ|rT2ugoD#- *Xߥ$y_Ot-:>44Hr@I=R ;6(8zrƋ)?) U z|շ˫i;DPf |Ur3ޚxNК1HB89Xo:Ѥ(?4K !-{5P9'0+MWWYȊ·5w_dICBy$e Twl~dCg6v=JIk;(,R4o|PYD)Ev1U2v荎=Fu|h|}h f)#:+%5R]WvVpF9;=NVV)L8&r4̳hU=8H:fwdIZ87( W ato霭qqb4[ɨs?\i˂a{Qxa_l%_']:Ăv8ȚPӱiŀ:W$/EJ6D/l<VC)0j2;1DӁ`"3E>/۵;I*1d"]T?&tEpHŻaGڲUt v/dffS@`q팧$yX[2;sWaX3?P]DSnm/s{/e)s:`NxN2oOOq&@BEN `rX`0 $w>_QH3f+ka!- ыqZ_Ia6_P%g_0>Ԥ&FT0H#q/< fpa/rؿp[Cbр ڴֱ)6o^&]֒BY"ApsG:vMpy;n +|v3Mz?5JYdMK7T3R"fU`wJ kޢ$I# V FE1]nxvI+/Sj'Ǜb뾂޶q"k^[h8> t㬜4"pq*/%qu%$Ê ,ftF+^̔ ΃Hnjצ=?y6 BӓcrT=-3|ͣ|5~aᡉM kfi͢(o:1+N=R/ς\pGAlWkjAU*qOAKGF|[|3@P8|>L|LǀE=!&-ѷKIQVI1I;R`kLq9rLe DJWEr Ǩ=vpTάg: 9K> stream xڍP-(.] HZ]Kn-nŭ/P\_JXC_ / r=ˋ +4a n`|@9⼃pM]Hm$;θ ^:#"1:;hr-2܃%p%D}ڀޖ8Asjea``ád}?92Įϣn-l+E|'W B[>9Ѱj>%ԇihY9"jVr$&S٫gJfߣb\ws^i^NyK*~.-^tm's3xjB΍h'aG'ڗP%"䜮({(9%y5Qw5S)ytE;V1k#x-&䭝߭VW<f#N/ͳ9[A66״ɠ2'!wl%'yݨ:hlXsʘUrc \Y2_ ?_<{FeY։s9uupyi?Fvц=_m=.8Qpj@ }Z+7/b0~cJSᕚ7V5[f6.aI+=M-1# o&c@pVg*.0(ju3K =?IAGк30Wz5x`2=}`&\PG(4ءɆ(:iɼc1aj(u7.>hUbt"nh!J YޣMhwe䍯ބ_ˁ=U!}8D8%OC\ v4lm>x)HZwmK17^21w<"]2B'Lr^Gxϓ"+|pݬfߴu&;dɼx ʷn::}hu[0O۾Uu}"TuN1&/K̀_$ *kIJQ!A $ JJ#y7ŋ|(E{NAxÐH& 0Fi;mMiz#mL7N(<7 PZQS\cL^<]+ϙG&/"?3VLx4vRawIPmj,Q1']% d'ϰ+b+ЎX-R?(ϞT̓$Or&a~Gk21XOQ;DZh*qvi}niaĴ;'lk6 5o$TQͮz&$rVO-+v#c$\hI:W]|ӥӒѾ׼$s$W)*?1C& =5HC6T(`Hxc:W#,oAL|!&GqVnq[%I?,Zls8QB-edߗAڮBZi*)509~.Ҙ>p{ĖI0Ws]7l呤"q$k\r1dQ~*Wo5VNǗ.YG‡7 !LB1&*f!a .p#gifSLjȼ:īvn_IfGi2ɱGZTb:OTs,t16iΑWP%$C?Abb&*#I5nX\16v 0ʠ=WcEϾJo -Ōt pȾpaz%f(+gxIAROL!iN n_02bm@<#b)r1ۂBWUݎ cI.9]TƜ> HwZKҴĹ!BSBg2WCHY4 \)e@ed!TM+:Ӯ޳rGBB1Ը~"v[ejӢK]R2Y^a!vh\%DFA8tt`悺256#w&hDu^Tp @9/<:ΆfV 1B{7FqMR0&9=χMtRdeaś̱0oФ3XMi+U sGӧz䎽fXMsu)1=JvYm/G%DƄPWbyYBFy;^捠$۞LsW|PUc&)̇M{AWۨf L&\ropB?jC ΣZ9%$ĀL\xiHJtt2F|K1[o-BHF0FS)>#C<8?F1cSkzє@A4+iʥ]4ٯm^O~U yX1Z}å;A=K/VHаfoKFEI~ zR8f>-t%g~g9B/dYSLm]0BYʵ=}0'Ȅy2Y+o_cK1H5:@IBU"=/Ʋo{.kChR?FKV55SXkqH@mP!ߜSg#uY$}%򸉖A8Ziw GO 5WW 7uvB T+$K_ɑb2LjWۦJ%ec40w't|K[ui SUdž=^є"MS#08)F7 O7 Viaa3ƘCcb _\:g|GtT-֋BzGDҲ5yXݫvT0".R9t ?ŷ ,Cs5? _5X2BZu|f#s O(!r@;AU%-;D6q6+>+;-93+Ooݣv 9'@̚p8˘b|)S~dnu%gokV*-:2.V";xt$$\Ք\Q_ BbQӰZ|}#48]q$ﮪRGzT|L v_[ϱce_ANm>WK½"9tPt]*p[_3 $tO;J/R.)Vj帺ƾ+DvSΈ+WNDYgiH׺Edg!iGlx>/tҷI"xnBn_4\ 2/72CACs趐xƪR֎ocCOm(e,:.MCN!KE\Y>3.]LBf7yB䣒xF7NIE^H3 QLMF}"- 6ǹH`gzh6_Lh7DnT Zܼ;gpX|F "ɰ}S^z*QZ{5I`RUi۬$l ~L-dv3:7՛afT 5hloS Ś2MBLcklhիZ0QRa2r·O>^í&uGY^AuRHB`E Q1P/{j <KƂ #KcN m[j ..xD)w# fǁvt0s+???uY"+/ : ޙ=-چJ>H K M`/,ܬD*z9@fX ʡ]i;2_ir%uiRJ-i ʕ-{$„H,Yd7TU3 :^Ͼ+*g׳r: KE,5~"ayTSvq&_|fX93O>[ڏQ!pu6 Vfy89llSO#`ܙfj`d(T9u#ؑP1K5gyʩ;FqDž?5 j,c@ PcYi{h"x~~yΓxc5A-lVlz U.z(Fqh& 6̓v\dжsP\[M%|g!jy7PC$1PV8[FNM_ёjhjmbyNrV+yduTMGw͍a!]'E >k6L86|E1ogD&FXi,pa ~69NFdH r+`3}$#qH6%x-mwpϡ%,&X˪8̨͑`PDRl({O|#|i; e9FvP?k nBMgw8~DY[' ޏZݕS3'FA U bc:z-x\ZR詫Cb_i vԏ旓揨Úu-JgO$AP. TRD[)u˔4b-~Q]Y-37]~*4P=\+[Oap۫_s(^@8 orLhȸƻ湗.a)#=O_I'v)#IAHg],ygx jQ'{O7^=u֫NQbgh0!8g}@?- 爑 ]~X*^Bש;:3tjtl2׳'=<>&ipS #s)w1i/{:`[^лL<}t/hvEUL6Yna9%ѦɋYnOb^E†n {4kWy(<@KR}hu&Jami TZb{ cGs#+G#dU~^CJ>D}50YKpeÍ0|c,M_~dsn'ӏL2rquD5]pw\ &b|7Ntff>h. %hӻUni=`gF̜D;!(I>Ueό8 ]>6!݌?c?ˠ~ _Z&)~jG@ 7:'v!R$=`,x?p*Q0@2/gc*4v'vYP%HU>k9pqigibxƎ0!d@%\tpF K.۬lYvS}ym_>ZۗŲWT6i٩+DG?1ҙ VyU"8a<8ReI%>4D۰ܼn2 %\^HՕxLBWK 6A[1LqtSƆ*8W})s]BKvwR$Z u2ᅺw "=0hQX'LZat[a!wOmRWD2A^:v7/UP!Vπw_g4>|ްH'&y/dRxK_\ɣuUlcJNRlB_o81M;4v)薰eJ~Q}>#Pޑ B%YVo 19QcAw۳9ӟI@zZUi]+uGbqr¯գʘ#[h G青X[؛ 7u$TwBe~ =aҢ?ɅEx40(,[<Z|o O@ !V7ډλ˻!SY'iaz0rmRBX"W[#YvzPX\lAF42]Yg^x$W f5'O5$%Ƣ@5Ai} 9=^{\۞{j\_WFXX,t-~,cZ1/_:c r(SJ3sALv2~H z.rjphҵw3յeg c; $d2}>Hc_yPJsBX ..:ڭ?I<*|]1P{LMJXԊx ^MٌBzx#M]*\d#| .Ztȍp٢%~| N%!ruܗ? f⚵KCml’T2%V–M?~a;pIO@vJs+m:WF|Wa,z 6ly]lA.exj)>"QEb$[֏I.W)eu"GmpYqi[ |4?A6{ً$(u VVey 8SĞ!5 Pሧ/')-٥+*xJ '%P3Drs|.*6.0ʍg kwb0\lB"Ȍ[p:\t #pvOe~$Q8YQ3T)@ca}IډcA;TG|-вt?]\H-/Xl*O<+"# Sp`@Lir\X-=x qLoRSJl3 33 F 6Z\ZdGg,(wVrp`Ό h`o-=9hA4|s}\rƥ*e 3ҏ5(ե{Jmpΰߥ@.W&:XEs:s#tB;;D[1WRDFʅLvcڕ'9f= cG^WtM)Kq<-$cSqO[LM&zN-zsz8}qnUļ״(ZX|OP-m6o^j&F>U+G(FQ0&&^OEi>j&,/!Q;hZS2Z [L|(_ j|\ׄG@[]? RwЎC ]8۶tR)Ɏ8IFy!'B'ݝ6ԑ[IK+Za8S—FCLF.IS.ru){Я5ڟO-nФ HP(d`E8͑ F;N:BeԍE$.jzn+(6ELMp_c^~Hĸɼ-]vOO2&M_:]S_A+ѭ 9 |D.3;Lb!qOAWIѩx-f|aDr[bQ̲3Ul'83y/\e>&y?4 ̅)'J)4c4 RdלF|> stream xڍP- ]K 4H7] nC%X;3{UڲY}%( 21$x̬Ԛ W{_fdjm W3&il6n~6~VV;++!I3w%@ ]% ^ kחe0s:,%3Wˊf _6,,f.gka:Ft:-*cFhڀ\k@\=̜=vyp[/4*@0 o$YX@^ 5 dH+2z2] /ff {3?vnSK3Յd["o*K-% @ I/ebd_ -͑E rrIbBf tpqN ozM/GN~>GՋ b:|oÝ 0?/f՟A֗c~d^?/2ßC<>L&v.V',?f SK#kb2䥕:ߐHk, Iq9 xd7חPCuN^9W[]F4h rs / 0P}XY2ov/Y/)X;v.n2K{sq|^GgXח*V ~@f 3_/ `q|av (pWy-ܜ_?q@'yqb!jy['F3!4CAv6'xZݗ>̕RWKO>?"S:|Mԧv:},)qIStW; i >c0[Gًsɿ5 PE<ވ~ ݽ G ]/ R,#5[Fϙ M֥n~5w~4rZP hz+!׎+JAʕCN'F8%- 7)#daruǵ}v7\KG;ρ;EC!:9 ᚙU(Be^h΅o,2I*[FkJJ#gaHM87a8ꄎ6XL#>)]^/jIFeVЏ.Nz:t9ތd$|ӥ*↋qt3Sh17~k u}V(Qc;{] 6оo4 /ۆ{!7,kC_Bq8N⪪I _yXj cf* D'Ĉ퐔_[71@f_m1LpؗABXC bh^$emci(P[ز,1듇BSϫ ;v}8]L i`6 ?mq<\pS<V Pcl>W墩h#W@fd'UUBЯ<6 !uŬiZ9RS*afsż'=9Bx(*da{_7{ NM1V0j若0V!)Jz:Ebk!FyU9zxj:^O@:@6;-[LQ /a`sٞ38"=ziKd*G*~X-a 7#(ypM;vY@>ٚOuLWQL$c%F{h,{./vi5QOK)$Dit(d倫s*Ĥ3USۧjOFO7=Gzy3<`& ;*cB`"ۛ2ɧ"_&Y Vyg Ij7 =e.<84 66ep`gFUB-֬ Oedr+ U@1Xy, ^qB:ucn .XMkePWJ6-CX$rj)LEM{=t)B֪9%թ-g^tMH"֟,PDQ'kq2&\,Nw҅}U6>mKL(2`Vl6+2^DzȖsTY* ?K)-}ʹjvUz^"壋JLߗk倥L0A-""ڨqU2T=pMjӥ\kU=VwYc|r3E7,I7*"To!8M=N>VQ$G)byo%K zk,fM|;ᱧ%lW寰|ƂYî:r~$LKѳ\!TMm DrGp¥.f I34#ȴbiWD9^yR9B`CS`v\7dM/G~e j<Ͱjo " JlgoO>uhiqlZΜ5N"[);}U" ϧ40u\j4?m|h׭+⻣́w'nR4HTjihW qin<. 0wCtGtpdiyјu3 z؍5`XN-HP  ((<0($+!\BCj/t }N^7wxJHFEֲ%ICMPoKjsr!O+vz{4vؓPمW>M_m+oe}u;D$]7i6 V@^Y}<#>љo楰xM摆Tz21 ׯmIB8x[B#R/b-WGɞT&sm,CTRqѸz2PC?o2l(b>iP1TfCVM辷1™@H@ b^eJP }M&>q}QES7qk$XgՍ!Z^ںTOlS+&"\g,aIrK6HU9 S(( rz\,^ѯOetD&t 9BIV>@4,:4 Gg.`6CsEH uio%!ՊMc';rP,Bif%idOUI$`\6ly^!m=H`\zd~MYP$0puPv" \0Yтu;!PP%aas OIF'5rǴ.ֻJJZ8Q}BdoL莊TX ݣ.0l_?Jgk_pDIdN{ĈiPO j~Nj 6KG3i?3d~~"~m*rkY.Dl昹}L #^@H^ N{Gd*v|#M|B$2M|寡E#8^}SOGbYCys̉ƚ3MV_kzTWe]4lNJ#lT뙨=`|n"F>hfڃ|5 Ob,g%M"'=tg\Zkxzl|sUk w6k|7YM e|I?}2Ljuk8|M4⢈yrr_܉%Y9+Ĕmn"OϫuzՉ7X J~k6yy8\q2믜9ƐVBy ֚J)´W]0ZMjr2' 6/$$oqT(O@jjս.GSA8:jz+A'Ȩ#us۔oY\Qy"젽(M'StO$ 2Njd%' y'sTQʩoIüUq*aw|}­ 'tgL: R7 dqsԏFeVodE\'?K \",]Vx'5v%7Em~5B/*оZ4 F=l]vr-NU~ ?+߽3ڵb K9IKeHK~FH3W&߂bNxxr$Xrc@#O![PtR~KyOi@X'FlF2$H<=jp2Kbˮ!;YA '0(=\N[yYQ=0g3{=^dqMЙ?n}sZ¹ ]0GMRv yqȻ7[χ1p\$Q׹@|-6E (S<+ӗWr ݠFz~>P9{䬁98z5*d\1T$M<,t{gGe8HnȲ-Èzj'eLlI(>NL%(5-q6u_L5϶]SKH+Q%ԴFسN~ [=9u_s$΢Ive|BJ0qp9?S8 9p8F 4mqgQQ㤄>0C6hd<=7z':-JY|vgk.'ՀSkHk/@E OS$u?IbͅnzWVX+hD˄xb$%1IB0Pc\~EX Kh*hGەH!:A~/4xUXGHG5@ kwkg[z]A,8dB2}Ÿ^Y#ԉv^Eh:ⴛ-eo#̗=JofI<S~aP+a P遐 Lv4&|!=R3#T{{X);U@ND=<8"&?Eo8IyXNX1Eי8㡴d,EG%p•_Tb3Y ϔdhHxJdVy4d-z_sX"{`h':@u?c *^xKNKozȋDH9 .XOE*ˏWtRc&hƪy_0KgXdꛒ4?ҥ<,4cT`7c7/[k{`_nO|NV<8i8y,mȥȼ @mJcH㰆ibоb;CQEO%+H4>ixPJ!zG|}*jdC0G9ytQ, ӋsMͶiZ+"8Xh+|6g ['WG^{GEa0TosP JJ^]zV6wNLʸvO@ń~>Zc2 Qm8vEMA#>; xw~GR}r!|BUgj)V40lȤqy{h9Fė9m-"^v0~- 2`% IuQ :cn:ﳭ8gjiW3FiY|4 _',d.hW$}ePF9$Z*=_1\ͥ2RpZHiH@WO݃ItCl:0z^ 9YSRGI*:$r\݉lېr\Ι'f _ӿ{3<tvӻOMԭ/ hycGA`Y)YCGiN[RTk-1ENvȻ1L^B^tOa+><q< p bx4a\J^"]M1d>qR+l%|%DOEXA5LQQKYk flO[6rpihE*DúͷVgBMޟ2UaR8?_̵ljF5|i)R%6F!Zcs^S!!9$ %)az{ZwsOo;WI`dXϲ$u {m'd\ᇔ})gD (R%ee <<+8du CDi;׺T0އ3P ?.N?wza U 9FĦ4gXmiޞTNfqW9n{Xe`U_szK|xJ^b-iM6Llp=Ot?ܘʌwahg.)I22sLh*}#PXYQdgiby @$bvdjڐx=RfN,{.uMeS~ڤ-34'DxP k L@hh[YlB)g]Av_!"ىg}9ۿ+-..ZÚ\f@+p_Ytt~P3Oto-K\?RL|s;[[Z}ol]- a|0GpykPٺۍdҎiNKZ3!Y(gbfBc:kr` >4 N΃ʎvص@h?Gwx(у_U}ur`| \A#KǨCLT:%$cUz^~Bxt h~l:Gn+mߔ7}), 9ѥq HS:::Ě*kh1c>tmIqOӤv:YήސA+_Rgth!qJ4K\q)kcRC;V{τ==khK>؝tࡩ)0'ʪEjxIk?T666\E\%Rc<徳I vj 6#Bz4HRw4f=3'&ʐ:jʽ7g8\)w>CoI$ ڪ6m| T\3⦓7ȖeĴެ(ٻHw;TY;C?c_ipwBZ\ 3IPa֡]fh fC4Y% 4'paBEn4d 71ΙZ jE|1we?z JTط J 8#4HRN9DhW ^h[8| eL!d`@}ut"^mcm*EH??)cQ`]1LozO\h5g x3LczÆkQdԥ‡cQ0o|>3MO@bgo>`ouh u:IewL =H3@8$ endstream endobj 232 0 obj << /Length1 1379 /Length2 5945 /Length3 0 /Length 6881 /Filter /FlateDecode >> stream xڍWT컧S@QaF0 ƀnAB@B 4P@Ns=;g{ߧ{s06VqB:40X$P30@" hGR-a(o8!j(C83$Rr`i9 eD!p'@ySՐXee~T<`(8@Ю0\F(`ahB)ўr~~~"o$E_GLa0/ . L0w{!6C: ('pCao rtF0l ,;ܟ޿!P(.g; `/Ơ/C7!8߅C*&ߟ輡('[ 0&k Ԑ0ڛW}p :VXH?Dgg8'OQ NDH@ iY @]E7z~+ĸ<gXh,(+}Np(s#(Ü&c6 Я';w?濇+jc/*UU$ ,I`8@ww6?uHp s]` I_Qg=>|C cXm40'juf \n"[9P? p1Av {JqV)5Pӯ@P(7xM- Qs(__BPe=x\ֿ73H|ȶZ~˃ce3W>Ԥi5የ*i}};<`~#?MG_RL3vm<ws@07]` q!ݱ[-w'MVj(G,mJǁ9̜$hd04GǮ ]& Rm%X/%LWywpX3$eCcfQBzVR9E7Go!t=QX NJ#ƻ+# Jhy-xey}7FfiW ? )mZqX{-8}}e$~ dF*v'H>u2Ś샖ThzJZku;-FnZjZGYI2.OLH]] 4K/h&z$^d.{GX1{hW\5w~oͽvW59,=EkM4Dnǭۧa=[]<W*~eqy>/2{6Sr_6GJf )zu3` V"af~qnmYLgIBѫi{k}:}́k a$yy!!y^i1$xm4\zBSJ2 27ْ[Һ1лL FVne twS m+`'*& NL3>oh9+ )Min kfKD]ͧUczOG 0 ~eÇ(Њ/+Cr`) Ɏan]d|k ֙ΛGZN(V[g~Ay6ukFɎ j䬴C-ԥJD8yo0ί*Sbb"cQק~r{+MUYُ\k7.Α~L,d{!>܅*ak#e_΅ęk<2,#S; i1x}#&$by6W?>q ؠ#mVCڜ?VWl[D*#iXy;o Uzo#F}v{!IrFB -e: 6y$J!IxQaQAZީ0ѽ9AҗM#lsͭ3/ނKX,kilߞRTqu$Bs=I5PQ<4~ 6pqXy{-FM+~^T[bPRڐT]~E0qgb*Oa')7ɤ3z_C< LZw`VaFzmquzms8?+/RmS)-{nܩhSQT gSܙ .',uķlEOl}%ì(_x`sJPvKt>QI/OIq$$> ۾W5-*2m^Xo粎ꁪH,.]K2vS~7}jS >ן⥨ cJo4UG|Ч6 W\u;W4$ϖY^-A]ݑqɃU]u2ߨ2XQAwbd~э?y`ձàZ)[9|?CWKw-{-­̦Fv䩦݃8l:5'2&RaQ`NbUjxY @O?dHiƶޠWM:!$ՐJ)|rW#UZ}Bvuy#i!D=QwntHvu\Z3- /d AmrJǒ7~0͹>ʷ%-x b6/#=Q?XLNiavD^ V-4,2f?Ӿ;@ʥ8,s]ڒuxRoOm®-]R 0@XԡBf-7N!lcx\T𓗸 };toUP~*[<G. = )L)< ihˮߪ ݍ>$X"ՒȾP!NF[g7될[fbk׊_ċ#tJ]nXJEBzT^&tVQB ssX %=N$*(sPa[e)}lIAt/>%i,| /1ӱ)61фpL%g{3c^شbxOTҍ\weϙu*73|2h/4(FWnw8f|82;xckd|5}Y< ws K,fsTzUy^y:"5^4}ysvȌN8#92^ I`GwN%.iN7S֘Mm*2)6{;om?DwUEڡM fE6ff~B2#m }nb:m޳wuj$.㒉ğvM *GgŔggcP 4>$|Z! %V#}F'R2*;+K't<[B^cѥAXW]{!;]6_|":'%&_6XNOÚd1nzn׀cXKivWܸTloh'97G g'/dڏ)|ƅXӍ 4 ',rJ`m+|j}Tj_{ C}l)M*>"ٟc;V4T2 :LvZG E廒>&z+$c7SQP+p}w'4} S4\%=I%S| _j@{pЋI.rQ+p_ݼ!5{"` r v{BRL>J$b.G١>5^}l gc.}Cj69=Ssi* KT_@OJ1TlT!BkG(qcgws6#ԷK/\Xcއ)|ZliՎ r5(VTT!+sܸszv<pYiRг|P":eu?ʿ?L Y^IubKYvv1[s: m R:tLdNqMsr5zSM!Zw_!^ø\}jgu)MSzn[sMD<%ף.9WCԜ9HD*a{VTMQ#C韃* FYJM m^*Pj}}y;WۻU֞&Мj rt;_U,'J4$U>|:LjxZT C X-?zc@h^M;"p7N*)!A7`[ѢT*v>9}]aE^l$ T͋))) qYg3 #M9 0杦@[33s!V #P[/-LҞuU\Ajiq_!`zTbjpB\/at80n>BAyID A˗|1&&h.II]HB^BKrXșMLhg0/L|X1nam0.XSVz5* uG+[w{fo? endstream endobj 234 0 obj << /Length1 1379 /Length2 5946 /Length3 0 /Length 6883 /Filter /FlateDecode >> stream xڍVPݳI HG~R*(WMZ$j&*HSAtE҉H"ERyѯ{=gﹻ{'M-$0 ' ( "#H-8V5ĠEpD Gt3Ơ*@啠 J (*Z@`,`&7DTQQAw8B`p0<(bF8\ȿ(DxpJ`pPP /zJAH'`G`n/ -L $ Xz"0[`qA0, |pڟvC`bnB@lP)tF"Bp A=wc$ I0/G? !}`D:fOup,/xh7M @AΧ"[.7vGIp [~}?=&?6@  _! xp/p'J@#pD8ށP $;ьpcO< \ @~}^9{ wqF ih` )-Pii@7j Cy6?hw %#Ϟs\Dg097m  C!}Bĉ]#N18tA17d?Q}8h/鯃 F"qp?}h)$`Y{b~C(;6q5sr '<8n} 1 1XЯz*`c1<%=D0/zy^:ObQI)*MyV vW=ザȎ$1~UlCYaؑsb#h|U* Rر_ oz\K {AUw1cfK iKޱJtQ<"xS'G-Ʋ8;̒3po, _#S?驥+='˻ xtx$c4 WBɗ^v_B[׋ЍLt,Q~—Lni}i?WRR艂ޫg# s++\Lޞ WJ87a0~Ap!od G #XUG4n)Nշx($AxhWy{y] ZiFF}A"eY5ồ89nQM\hvJm~V~>";K i.wզvYӦUS^Q}N]!x`7GVtmC^D5W1"n4Ȋ%ֽ}iJgX>NsҚYݦ]n%ZmEa~m.ڴ2q=Yh 3-7qfԻ\!t+%E s3C&WNr<-8+/7{T_JҘ%e`:ػ=6zd*~@3rdL;J%$X`4p̿͘NڞGف>Igjܠ _?>~hUs׊6iU\O*H""Tnk~=:j˽ ]it|jLٌQ|}/ iĝԍWa{Otymkz~ؼyB}0<^ֲ*7Dy>(oK >xgx`dAjUyZ]*?_[z;;Uy%wؓd0*DٍC&RՑʹ7j y;@b5}QQṔѤW*Έ[i 'OV6_P(q_P?#4V!.S5*Gg#kK !/iepJ򊵓9O /12->wv6ky51,Nx}P1[Fh:K) q|L{aWocrs b,/'1yj4?1~r .S|&[ ۦ:݋xLhi|4)~^n" ܛ؅i{*e/PTa% DAE;hcG4Sٹ2A_=U@:QMydl4HJ/>$riWH퉆tܳS% `';&[˰'W֤C&_-Uhz ri?Nv:+›OLx 6eq썋,b_k.U?/[sYٕ%BڻqkRc(Y%6 z>SyKҜ6IWtBjzn= fQeD/>9gαT#y,hWijԵoz^SےMj6vȹ]WLbQQ4Vp'Ø~E:3jJ()_p wp`?`3N`#,Un}YL^ےxҦ\@5%~q]H:&La뫱P\85݁Ԕreu'MC\_C@car͇fkֶٛiRE:oñ5!v8'GvG55Qkڻ5Cyۈҷ.W3| Wʗ<;7iANIjJ 3Ϝt$ڴ+I^h|֋$"OKPk>/zHrY`ս" m}_ja#}G{YjL󒛵ZEsM1b_K3C؏ seTRdHT8٪ޖq"c OQDQ\|ݯ2 G u/TD5S@yRiV]"wPTo;N.rK̠Okʭ+Am=5?4@em;OḟrNZh#7mRw6 {&6Uo*ܼk"}F'Fut?Kj̺}olZ9ΧAL^Ä$𲄝Z>i3Ql*lmÒ]?J8;eTGyn!X} aYܖQh?_?TmKAy r#|6$F' ɜ7f #ɸ]}i hfK/OZX3LR݉3SpI,׎Df_@ʃ$⋌}/_C|P7EK]qV)d[.{w[FDš8B[gFԡH-,\Yfj6󭀭GNkcn=+-Zh7U]ܴzyGWdxE"+;g=Iۻ%+fv%",5˱)stdgP="em`1WZS:(7-8jLNs8TW`)IIKĤ*YsƕyrUë Pؑgb zKBT^TE|FU?]#ˢ8E4& *nu:(To[%\X'wQ:S*2pf ԣ}LM@:MἵƲ޹\[(8b1\a^h` `,Պؕ|&%!\x+_Bn9*d,Wn-0(3# <~'1oqg&}EeTO"NegHţivK,՟MSZvw92Vl3yTL铋p$F]RdTZq|{pFG¨$뛱KD., ݔcLCJM|_ױS|>SZ:S`y|S31X`%?%0/ÒǜW,5#]7_C.X3JX9d>2ܓR.űAjU6zzK2& Ltd\V1A+3CVzIF/6gfLwي-@T6+ѻ ux̧PZvv6vzDZ  =jGGbI.YگԎA޼NQE/5= ӊ$7;)Տ)G.iڃN Pi;)1s}j`[=I2,lbih짌)5_:矀-c062s5ʄ]DBd:_\ur^Qb6ĉk[.Yֽ5ȑ>N=oߦsZW<'1+U۞S78P=MnP]|+ZO"γ]("?w.]`Po"m+j۰`ԩrՐV L2X§C紐>͟ Zb>[}GM.Xql `B?-Dz ]u+XN}^(xL,]w |vwSUS}˵,ME(|a䰢r]8?_>w7Z,CЗ>1rkzclH$(?(jj=Fyvoney _iN^q}_:;#4tXG6%ie#F^)ESOF*GSV z²Sz丠uN`0(HOװc`x /^:# QsO٫hܳjȋP^Qѝ$0ʒgu&ۤk`%L͡I U ByMUv\{Ew<]a:K{7X{蜢p$4F(җ΃Y-/K2Skx{- ~D|+K'F<]p}oG86tTrD K^Ky{oz4p#Ϋ{LN֤Y@, i-T4绖&_c< ";1VLb8}ܩ:휌린P[͚%UۦomEv[JiC&1S}}$* jWCYaDqbiU|Vo](U e|Rs0pb};2rZ[7IrA#~n{Y2^S^zﰷ1}D^8Ėw>$z H1VLӳ.4M[B$L:?|HCH7mO='THW.9?K&<]xư} );V_p LKoLLIݭcX?ݧvj1 3; SkQz6,fKV3osݵk)B|@ɁH:P,]Nj.2IA>keotՎSs7ɝ`ȓsq TGp}) W/69P*+O^?(yꅠW *NDqltFNc`FLH~Z/`h~}^#_yxi¿xQArb/`ɧt_l*άknj¢褹"W5bL '1&a:4Еۮ) F.Dƚ1.~$9Z`ݶwL &8A\3Y>eaޖ'UWLqsA]XHo yniV3`W?&J _Tf +  c/#=PTc* {ˀlFh7 endstream endobj 236 0 obj << /Length1 2499 /Length2 15792 /Length3 0 /Length 17252 /Filter /FlateDecode >> stream xڌeT-;]! ݃k}N}̪Z|DQ^(ngLSUUef01201 Z8[hՁNv<q:d S9;[5`ab#@ :!{8Z;<_15!-@hhlh P3:{=#5 t:MIjnJ -NC.&@G?@EJ`Xo:`f`?Yu `ja (28; mM~Z;فZX  .0 -읝,gTh1[;D-Ơ{0b+[;7[?w*&.j.@)XDdf@g;@؜U{_JbP>^vSP*@ S +33`4EMƠ)pph3tAsfbgkF3*)kH?jaa;w=  /?%oI -޿lMg*3qxPg{A4@՟-abg2bޅo-cw˂& C k؀$rvUM?m9r6-h8[8[M-hd3)@hld@MK-z53,CGGC&ШA+ktk vΠ#P>S;G߭`0 8'Q083Qb0JA N?)8A\,!@,*Q b1:fdDŽ h4r44^S?rO? Pd v5Id-1YAiY[:)?N9~\@(7?G@Z>@&fAz&ds{s,@2AP[ 'bPO=6 be AEAQAt?)h#ASbKlj[+Z'ׂZB;gѿ: ̠e1;  NֆN'z%lWA;|;9~ *^FAWAP= b:\K.;⿾@w1Ҽ1oe]pCk/ݛ 1B5D[-WJ⨹@6$xhy 8K^hG"$w"*v~Z 0D XO?$}x`~ w2Y!Jw5M?RJk!6޿@7Ff*\waY9d!;]Qʃk%YD_JX".=Ţg,mR1 n?hy-MN%zr sJRF鲘3 ۃ,Ň'!LdSّdPk)ݛuž8G~.\& zRA{@P̛v*sPfkWL\U=yr`ǸoUW뢻b#~Rn6TtuU7PDT!ݩEDO.TL^U擳sYIpVn21*v(*D Z(J Em <#T4.I& e9%72,oʄ"jI 8dFhǪ$5:i A4E$+ {ܨ((Ê<xS}nh7"nƟfD<lq7Twg|tFG#1l;WoQtSP2b%Qa0a4(!3 |:8}o +y;=oZ"c]ݵ^ZL$;|U3D ꓒ /"(lN{2Q86!<"j9݇zeMY *{_?E1]w{Jzh;z. koi')הiOɯ&1p:\qC" @򻼂Ci^:Wq>D0@bhzd &˳ҷkvlײnvh'tG~)E{ƞΥMyVS~ 秷}'Ax"|Jow'ZJ(먱81 hjv N^S<3:Q˸hjG%L!t)&;}KFXe4% = RF2U#cvTUhX0Ϟ R:}unc`q"n}yWt|pVRиPgȄ5n!Ev(|#L!XB,x:Jٿ)Sb܀}&z˖F2OV -GȲ>biDžcbϭz,4S"5F8(]_Y0Pwm?2=؊!^yLowK.{t.@.y)ؼgC1 Zedr6iU1Ba:<,>XUMIc;m0L[x_Lnj2^(pdx"MT[BsJՋ>حF(\4™<6QxF?]NvWF"|Ǭ.ɿ`*[nsTh_TI'Ή Mސb:4V[ P|Gz}zĩM⋷63m*cmұVӻ?$EK%Ea~qdXD$J /dGedeNoyZO @\܃+ N~Q 5hnhM,#۟$8}ܵi3Jg nݑR+q!dCٮgtj%#1:)$(PVol:AՊa7EH55*Gڐy^Kڹ@6 t rF@vN`[,gbzk~&lLϫsŠ~F{b2WҐ u[gnHH ]/^䳴+G9\1 /Nvy:e^T#_ٙ\%^ ġaKm= _d44s=ƀN J*U&Ϣ.۪u]PoY>͝jQ=!˕A.&h_{2.6'se>Xւ h`O^"*|ƒ_^L\;X P0BJOx\>uѳŤt4?eHc秂b qf5FPିy,w _4- D_]MR#PMFjBYXEXDcHՄ7Ob,9^]7$^S4۵=X,OV7cpfmtqDjlKde@u'lkcp'O_Bh?F3ܔ반l]noR!$,?j+6qb^h%\0ͯH'n2|:/hH~p'`L:3§GHHw&NkVz_"UZ'O{./D"]nHOv6ľ"-lVohb]6|cS[>*^q.\@;aS%ntARx,|ҡѸvSt;&sZ ^Ǵ~';Vg zȈs}ku|3uS8@ׁPpL<\q1(BUurD/w*`#x-dQXNT@% 6tvYaUoG5VMC0N/81 1ƟF8~nRkYk+9K3n31l(,dX82]qۙ?xWމ=w٘E][& A_c+ISP|ќ=5ȵu+}nv].l5M7jD3}DŽh>674d"A F\}(OsL޹/M5(\,.E9 B|4Lػ3׹ߌ",} Cף>;Sb>oUv7ɷIC,$mL\?c uSE.[RWV% ;5g6( vy!Xo[.oHe7!+2+z=E5;V`S9^ո2H `#tv\PPIŒh-I>~'8(7po c~q[|Tnn'%;&N`Ql<FJ1s,ܛ УLd@d[BR_ߏxf"B# Gns+95""(LJ$˝svL4c}D2Y,=τ>(ƳKݭj'?*J` A\OXxLعeވ;_L:oQBM>b4oʛOw#-_n VL} pCpH/pa{^րpW)D,FU)QcL&@!VÐj$j0tvG/Wq{qy_[$Gbdpؖ5pP}])](oTtljt6lu~8%c@ 6"l%/'$u0YV%`"$7K{QF|1/NyxՕdV%~C!o$R.љ`T%-U֊~FA+ wGCgsj`k}geOe]MNѶv>ThAu:`b<踝DZSp$|6f:+U~YҢԙ'ڦ1$VVk2U~ : ,r(` >̝6ٌ $$.TY ?rq_Dk붩". AEotBc'߄J#TұjM@'4Q4OUɗ'z,SX'zGh?E?xKSdn˰LqYS2܉p'YI(0v @+X-2+SB vvxA!֐Uv# iYq͌j U/~W,_MAB?  ދ/W=pT%g=jnΊg;H^汙޾Th7U7qɌUEK-ǩYO')PIWc2 Oo:AR2)FtG&RLvaXAjB .v'^X+ЂDd$mkJ|j ϙ \ZUøF.FnK׊W3]$ЗyVၭ!V61dŒq9I9׮V^.5a Ρ厹c7T:[\YlJo'$xU@4e*nqǾQ2&&gvpq'NYo_c08m[z cEehf=,EgRq#ז}y:؅T~".*h5[mFk9G|k%qe Bp|8W:p獚K-=WljuqsTJܝD(_Z³z)>hS@N:PDn iʃNE۶#ďdozٗH.0E? ? @~7^Fi6yh~WgTT܅%"o I\o/[s[y X9u fCAM4A \/@D殳vIlƘP 'R5{IyiF)t걢@X͋3rᅲO8"B aWWP7E6R"hQX9t>X4^tWH7@M!$ |1+ 1=2%nuik# ]LJ5?;k9pܺ$Y>#--KnoEdj1}e1^rj\M"V/R8JcֱlJp`XB݌ h9_GuBGaVB8 c _(ƆbF c>Hĸ.*jic|Li~V^&_ك %-2A?is b@j~-`ytݞ_2=6yF[Ss; Fd20QA/lSm"opt H::@n"L},A̾_̳S$.OE9r FXġ(lŢĕ XD&}[9dE 5'Ty\ ͦwLhKeɩ"-`2 XULT!,鱭l1q Nm{|3&Tt1Y}BI=IUSH12Y'nFб$Rr g=uaEt2nϾ,P;V S2Tm:Xj`n=FXFJ['M/,i8X-6)HaSIM^嶉QfgA.uEЩ?G' p"dPb G!X5\&[qiLޞLf!H ,,ƺ<ĭ ϶}[aw1dJ~cL֌c4rD!w&ht%p _怫h~q֧<`nU2#HC- +8 ҤW Hw+сc GuI(RF)6c3XOcU_R)OA:/)ټPT5NM3trp7mؚ29'-HDUsH$麍l~\z^pS{|11qN[D9( ץ5eղnĵ`;;  6IˌCy ιDZ-LR"`İ_R7A}<)T="3*ug0V/NqqnpSF@`5I (N9trOa&I|Ne>SrH3==i?7hI©t@X&lE0QgFIX2e\bMueȉ.;ht5kV Z٭z%uǨAok"Bl`Fg !-jY RK #5^tC'Pa1ln0px-Iܫ>퓠OpK=]ԼvY^:*E5%:z- E!Θضۤ1xUBCY_^k{Y?yN}}0EohU{҈k9?+gSM>YS)pUcSU47~;A[K#+"ɧ4# ,iU'XӛJ k\,L^3=KNdOGTKY͐Yd>eLje80M3cJq1qR}H#nWX~Mf+9>Rj%oMgGz u@:1`K3XVȩW:se],5, 9H9KWV~^N+YXϥ{NE8i)WڦUbj.96y߼yʢRݵ)=׸K&u} [왆kIֱIgɹ|Nz롡v9M9C 1kVLA[vk)z_ٕ e4Sv7ujL&x?Cj.G4Tn"Cͩ-jTѧϳ2 YcR|`LbMڎ ^RNÈH=+oY||K椼px''Z¬dK_Q8pUkR^`\  dߎDSnkT w:}p]!Xl!,weZRس>{Y}K#f]督otlmw9 ުyV;+#>U<~X0 a.C!"/cMr/92Q$$=MtЍf܍WcB/иקb3\ !E}W ![K˩+ćN;dxTr;>O h_Lקe65$>?xJQN%#sKD 臃"jɝJ:<'gڸ$5vE`iWAN-P&ђTE] S.j?ٻ;F~)@{x:&yK?vġ[QP{P0ax\ɒe`qF%yI6m()ٴ[v}(r81d?e~]Vzp =oư^MopueO߽GxOxLg,drnXiHKVмW{*?@K1k~KewI>Z#-5AIO=|>dS#kê;"IyFTӁǯ׵Ai=9Y][ŁWy0!AÉb9Ӗ"2D 'bBE9i _7xm2k 7 U3g, `/2-Cs;sm!*%[bkp^Y+{U,^&IĠZy]1}sq{Ή_ipczon+[(<ޞNsFldtiՕg@Yn^7:dms8OK QJVD|2qҍMw7*7O>[%<ʗ$R Kj>e~A?/o FٗʷIE-z׻mǵ9_CVI| -Si]V0pv#;># w!x$W~fOLmwc/Vzn$鹺Lo0RًkP UݓYEЊ\5HՄuԼ"jLI[٬8` RYV>LF ϭ:%mռc;6*w),ѲHy6w%zq`J,cۏs`8&wULL-3V LN'[|"9a_^;R4-f7$*Qd$RJxZ8vDN{(AF>Qso]ʡ@D|`*NezoדKI.[7.L Vp:7xo/r[pZmCH~z9S:A|ȸjlsIg?nETWb~}\Ҝxm&lڸCr¬8| p”qsk~pogbע"*BzP) ҦtZ"&;큈P M w*mY6!X^,cͶ j1"U+5| :j»\uc:=BQ[idy"[׫fJo 5\ szt$ƍOdbbufNwbh%gtqS Ǘl<(B%$<})4cW#v|w(n|pI>)y4u/k54׸0Γǻ&~˫gXzfT'nY^+3vh~drTμ:5DʹRn:c۔RTAE_KURsHRwB _m:zOaSk< c"߂^(T0DZ*0xDXzoVO$sx")٤S":'DH{/3ކ} C-?sx[g_C浑ӻ~m+Ng7sZ##780 m7=#j jK8Wڍ b!D|* @Į\1%LyCGD3[|a|7GfN6Em;\!O[r+͉bWZCSSZ) y{!S&'Why#^%>9< x 6}Fkbe۸RCjQC^Q-FX+}p5;'u,a8a>2lN%a׸y3*C Tޝ7'_z57n'j7# u);˨u_/˥?Qedr9Gُ ~hLX0#qC;:Q,>Ig!F~/y!Sxy;ÛV gtp 1tU]Xq->vGp/ҋs^K a2tWE2Iq;5D^ ﷉`Z*{r ahRl,Otyp}=t-4>q'}ZNAm ܈sZONp6B;sTDαog#PCaW:ދmq&wa'B|3ϝNNlNC0 `ֿ'e%匡Ԕ7E.jk퓻A %8bmȀ 7-Jt̔f@Xq)=.8XKȡX0L3"Bhxjb[k0jSz;YG =Z.D^Gz%:v7P%|d~ Ӎw f ^>6,<=ɤȜɄ[e}0}ގ`w(ثL3x ^ϱ&*ֆ9ۮ!5/c/$Ik<@_ͤFwfpuyr m=V˳io[@PA`[jG y.*")1/ZN2`&ʼL¾~xKBVTJ=<bߑj`Lb(_:-RE( B# ,vex Ƶ[(;B'rǛC+O4A62V1 endstream endobj 238 0 obj << /Length1 1530 /Length2 7020 /Length3 0 /Length 8024 /Filter /FlateDecode >> stream xڍT6tw.ݰt Jw,.KI7H 4JI  HH}svf9g9X 58 ) ,(k @ (aEAq@P8L_e/򩀐(6v%d%e@(%P@ڂ 8 P{{A>=<aiiIEw AHg;#0Jp9#2BB w I E: 2@ #`wD o 0Tz@`@XPrf*Npw s8B ]5-A9pT>u٣)@(CH Я21|*P/5w?/e9Bah8x{àu?1(?>' 'v;(ˍ8h@^ !A8@H= : qFݿ` DO08+WW76|'心JJp?@0@@DHK[EWp*s_<|[o8J?/'_UysAP7?(9{#Q G-?Yvߨ:ZE߃"Ԡ~=(Ty7( G@q@PKvEUv-Ua`ï@x@D¨-u7@HGR(zAGޯ;)rPm:ߦ8@A1QrWBb!!P[(ٿ_57;FFQb+pֺC%PLyT =刟U׋yH4վ5#']N&8Өdfa>#%%WMdת툯һw@9 K=2Q1}=ޜ}܊$򙷑xh҅kIY^e~+쩖&x;=-e &ryDZ= {SL8-`3 ]f:)={[b`WfYlkRm鰬X Waq=Yㄉ~%,5 "2hL q*"k+KÜH$];?l|šV.PY^yV1D6疴{ոeIvcJ;FEtY$vx6Sm( ٮ 1gZ:XYxqoXрy+=pnA۵iؔ2.B\JJWBIﮕq,QISXO̐?0Ew5%O.͡Vj !Kܶub QK\5w$O ) RPSL-dL*#wr誝 Z=Z9llӰ }l΋uK3΅kz2=;v:)^#9#|itFR/ˋPa &"'ݴm[k+ј͸@8 u|&g+gٵ${F;j=)-E,סzuҐil芢++˳dskfl;?/vd@DZSR\'r6ijNqgԁ"T1n;X{7P'y/D2va_=O)J<;z`K>{[קC~:{~l}=$ u[TC$]Ow ,JZ@o'K0VWtc<佔*rs߷ȼo H"t'/ot3SIu?|˦1a" ;IF< $%`Gcw;/gR&á'R G0Lqm..} FS إh,SzMvC -y V"|V0K:P1EXYf{CLaRoڥ@k4[+\.):/vJ W(1J򍘵sX8 @6l#̧Dgg6f?%KZBgXjԤnMד$eVť\V)qȯ,LmV2/*iyMߊ"َI{Khy8(|I!k'Q,}O;6KosQl$ō,Tڸe:5a>cm2ssڨVQ nӾ{Ӷg[j>N۫x= `.jڇuok[ur[o?Ls_PsfV| ڧkP+<@Ͻ` `0i˹<퓺p ׈lI7Cϐ|ތo/&6 >eZ̈^Q8Ƙo{VU)IR—;_pNCذ$}@kѦ M8. rulo[6^STE36"K͞~Z>c¥X/Iyb :Eseցty}!Oΐ/c l0<-⪩c:x *̩ I9Fevt_e_V7^:?9E.2ć}gEP )#jmrV~wacVNڹus.fsb;~XgClIo;Dܷͻq`_v2ͪA[5ٟ˦hU7("NC1%KzMƱ4Feȷ/KrT Kz;i{5;HF bg_wI {SS| b4aoؘeiB:\۶2&;qݎ~%-)T>8'?hn[3ih9PqoMrˣIYUjcE4u9&%ΆIŠ3L}Ur2S.^[f[qYvYOi]>\U<  ~PB{YY\F*eݱd*V'@F;3b̶bgm=Ip3:}.3!gCƑ(DZn36ra?c }49zW4?>ß|I: /}Aކڹ_B|u$a*Ipsah;K?%rKT%ɿW]Ѱߏi˓>O>efBZ-q{$>IڛF;^fnߦ)w&j̈́DkA .Uzyzx+O9yvP]'~y.tILA|c2:6 Ͱ7K@%v6ק %n45af gJ* "KZNuId䄫n܃R&Z go~FakU& ק(V /c?2<-vúyW>!8{GNC> HJ-\zfpݛeG@֔~+G52o[w2{Q-tVsw3k;Uw'@Gѕ%t8{pЙTkҞiogs`E Nbl${x5`dnf u jMB&a"Ӑ[fY u?su [@gknKPHny1oή*Ty,:ޓk:<.}ЕJ4t.ƁDBVl2ٶ=o\1gOa98heɼ;NQfs1&<7c6z!3nFF;{ڇW \XmnDoǗ0(^}c}d%vjcLzPrׄC`}Cp] ߎ1(\[%ZQ iW)P{^$;Wf{N@7d&'(bCS:ym e1RgUXqB% jWâ*ybRwD+pzA3b1QqiS!Sd I'5}S(ȳ]잀Z%e`k]){(;5qc7J!iK310dBHjvថFUx1+eȻĮz'O%:l+||QfT8͵|gtZxkbzv`'f' &pV}i92@SEwuҦݾ aX+N 늂A$Ջ7q\t&oo4t)kPY3 ?6$D(uH'Ed5wo<>hB/͙8ٍaciM=?"[JD R2HN/xk;؏d0j 8Վy_a/8}#YKw:Z!IJn5S$z)7U J&MJLiL(X͠ EAhYqe0xł'ƶO_̐&. _7s%(U~1_~g􄋐 Pgc_œ!7W.dO+dԀ \H$w% 0,OX.^ q eP\}0%+<i}9%˧c~ϡ M{6sG[3YՄL~pjY>D~M ׵ (ޒߔ+3;jm)( j"v+-bފ9ƥ{\6z<ȗIDtlG-l.E &-0+n_^qgp2t_se7QuyX7WEHVF|=,*>b ^yƼyD endstream endobj 240 0 obj << /Length1 1826 /Length2 13283 /Length3 0 /Length 14424 /Filter /FlateDecode >> stream xڍPҀ |p 5 -Kp_ޢjx^{Qp4J;٘YrlVVfVVv$jj =?r$j-#_.@SLf|pqظxYY쬬|1ttHXA@W$j G'/+k[|l||9ٹXllOJULm_@x;4d6͠6@?ojy t7D[z 6^[ͳm76M-"jo;"zl̬m\m<*6`sf?Tqtybe?3{{[\߮Om7dz!Mq|vXA7[~KG?.mE"_aHCl"qX %7KR`1,?Ά_/| d/X9zr~{x R :˿B-;C[e·\oe /|dK'||@O9Ҽ@mmp] vNԁ+)= KoQbݳ7؋_tX6|Ӣa-Ͷ|\wup,NՆOe9\iFtx$y(ePd 0C#1.=#똺@ԅNU&t*f<&WO3ڟF ]ŭK)\=ee2B҈}ӿkb* O'idͤ0f`7_,M#F}ra Po`o4 oEE&G<$= '<M{dieiJd99!xqg2 GȮ1EqWp2V]^cmKԇ&dJw:$BJ+洍s6hkp T;栗6δS_CH4k,"&sc̙BDS|F{O7D"?wՖչ_S%]QP*G#奓}ZRM9XG`(+.uˇ,0êuVbgqEbxKf3m€6T;sg)ɾa-?|-Mʥ(1t3@pa`QM2hG,*u^4 MxtpA+y wil\=l!)XWT>ʁ0H84{Lb*wjg|[S{IJԬ&aa' LEV=j_Tt\shj'&2eĊ|4<#x'~!-F}$olK Tae ћBA$Ф6'.79 -edPf%ٰZhP % 4&֛:2bu{ 'm Z<ٴ-s} ; n\qIB# 2ǵRҪ2PWwJNR.bxy⻻'g"/MG~}*+r/jR֫Џm ro~6m]β‘PhjŔ'퓂UIp(mDdy(yT~%>%C68%{ˋo'|d1w),/u܃ݶC -q}auͲɬqnY;5SM+,&V\8#A_u]d:SZ|5s.֐Y Vޥ_D yʿ5J]\՟k[A,wxJc-vyR𥐐QpPZAt©6(ţ$1u3vȮ O5cB "3'}{ҡpݭ~69Yo1ڍ=ǩP4"'Iw#$p0䝫Ei2+w.5mI'nD2S܌gQ)d㮟f_%?V\4 q>XL)MhYmUB"0BVk|;? Z%v.¶fh)2iVc]Wcjkƀ J5ݞa̽DNgjskV/Tb\?t(QMY`̘S4̶%iHer )p1ozn[C$S83) sG㘍ihȺlE-D{+!B|J5z$Z)Ѐ0|`'Gi"+| qhWS2.AT_/vp:xlIl3%w͉x툙N쏫z}}11PJXVhU @35wH}OR3i}ϸysAG%ɀR˩hy)w}y\) ֒@ 8r *S##;Ԙd0 ? !hyѴ{{ŇX`~⸏VҌA.x% 8`<Y$KB8e*ô?Yh{ y ٹTUu<^J!cg>quⓟ[z?`.!fO5NǕ'{$x6zV]:><"."6ݒe*dn> wطvנØGq0 7tɨM,%LZ0ބ1Y?4;'14U~MY H<B{a, :왁xb솆i5Eէc*;Tx- ZE/+B, [{]]$1TKÑ 5 J\=B @Y8cyUfU~"̤MXX AQc3-`Ŝ .o  5G6{Fro se*EU5Əg,8gԲIX(![\|RS?5ǚ~Iԟ*aWܡ^ <ݬcW0+Anpt}yS(ydKPm>؊]3[ C^hO?*_)$"IȃRaTUU9:^j8@N'$w~ > 4.#U;מa&gb Hq?>I枽g|6d&_4Qc<Na&-QlcR߽ڽrx:3<aNiL.VddO&-^a^֓ ˀVG=Ǟwp2~T Q5RJޯҌƇD`uíW]1ĎC՛ mWSC?j*#Ȉd9@O+ -٫8T}l;])u1ys㍻A{*e4d|1e|@Bv{5>-xk ~ ,b1I. -eмd5aY()I^p%%6$>(^Wk(fQS*1jSx'%d]t|`སm4yBAG+b%+Ѷ3sLk W.zrP1XrU]Ia${ټД:\_c+Q5rS̈́Yl'iJ(SI { >mT2TLQYg,qje~U~&s+B?NCU#pQCP{C@b էh%wWaZ8/2B'|~kr92*P =Wi܇?a9Vu3Qq0̈́[$Bz:29ez/r(W7>#׶$8irSkTغn~֛ӝVXQ>/̿PDOܭ A%3nM+LZ 3EyBZ'҇NۥXa~IRaːŹOl[=gDjC8Q֯~*(>Ϳ{ًqI%kya {sZ(x\'.uƥ] oZY}@`Y|Ba0ߌuhfTuY'EaYRd%m Z)s1;o>gC%&YMfu\,X[ 1؟M$/Z_2 D$͋DAEVN]C3{@ca_ w7.^)Ɇֿx |yr8.ẙlӞ{4㔯YOTnx!'}S/!iD~0RPlpUr:IJ<|VJhDp[%œ2FSBu GBYbA:ctu7YM#LDNR&}q3k 8O%[iSyD{,v`f{^U{suߗ ?v*7M1 Jjzxi myD=Iht>}5MCd` Jw-+IJCِ&Mm7 NNS& u+㤓=sc,FF6Bn4J||bYAdf(kD>6,'s(<=.7G?hnDAuV +̀ms_j0W/R9hf!h>&m k7aC'#qODŻ~?ٵ=,hӀ bZ`|7{9y,nBX"EQǕZoRH:Q..)<=Ƃ컼$0V aa,XCOM*U-ކj\:LM!L cc*qT8nuy_'To]Ŕ+U`{͗M`D w/K9'  I9~$i,:ڠ{NB3v#PߕY4`&Y?]qhD_ | ߪ0P4`lRvuɊieΠ.\p|Z2Ji)/iK#UQ׶욿[coW>iz$DyBluvSVԆB0;$N)HRhY/C@4ՌpjĨ;C]q\:rB*eAǝt"xw;}RON^pYX' :[!\yJ*nmUs,^٥-s˖/gL#/5,UFn]HLG;KmiSx>beߢ uq3 ҦE}e$KR. =Ph촗 !؉4n)q=V1?Bj.;":>Ŋ YPdXrb$MW:(!F ~xh6kf0n5r:J-|2ZmQhpa.8Fq>٥YY!gƽ́x옹["$R1EbO&5`HYۄw>I?>[@yx7":Yܠᙵn ,qRԔN -[, wmHX.Z--! W >&^B5-+A8-#F-;wk_{)xl " 2B |?3?d?~~o(Ryi (PۏbÇ.xhcϸܘntdtg/pmÿY7~5hD@fe^W~lTM&_/^|xA2.u+2}NKKkOZnt~ bc^,e]h* 2|R=i"M?BZLAse+*;R&1S)-QSTWn%XTV2ɦ@\⾏D.1J  GׂFa>e)Oq2Ytuo.({E =H:ag;wQ6< xi; 5 Ĕ#.NDsH縄aOI3W6cwr)4b&+ cITV[ÏO\Pg\=G*lA6[g\W HRy~JMYZ⟞A!9𱵿rO%ApOb/ >O#Zۈb2fUGPp+OQ`A!Q+nԔHH x/51c?\h 2\6J4=IW^Gj!0ahא!!0en]~uQ񵝻f.0G}hG s-rMAe׃>gK:џ\k|,cK1Ŧ|V+?i+,@\O5~ M*‚VfG,xbن-B[ {&ATK*1;dntJ[I KHO᥽G` PlLއ5VN|zI67gR9K.p[Nr]2fVNH;zs//PΓq cON'&}#a_nƊ|&Tmf>`W={k.|h2S&Z/o!DYGӦ9ݘOG~5zܡ'4կb^p6ymcDA{p x,ه~tS AmWhg'|JtOm$.>xND CڬoWF`7#%{ۜY`=+uSA1&STy5Eޡ6xIV9K~cZiEm" F|;E"NhVǧ&%٠w)xch2ҥ[ԯWbLVձEĘtkI S7ga ,H%0.:<>,S.M93p5#{ ?q#cL r`TQ-yr94Ham1%@fq*ŋi%:R UɒjNO0%Տɒ>0__RS Mf?Z]\W1^{uWh/=#XߧNTp]<}f C޷pwqϮR9[2:';Γ:6>cTEYڀh`ii;a@Ei Kt49bfl"M|Ҙҏo'rć4~c])=EPA;efT,(Rg |:'.e"( z>/ =8JFgP|.7)4sv۹ll D̐'h| sפ 'HǙv6ù,"zNQ.1L5;]LUUY`SR9y9{u"tOsAx8yRXAb4Z0=o /ms_m`Bï<KʜOF$eS?'4d^-ⲣH *Dj1@Z$N)&WP~﹧ǔWA 2lE1sxe4؂Ă?q@JԠ2mJǖ($ubx)RߑT|vmr(C<қ@^x3#0 ~Gђ/71\K@Oz:C!6>Mh_XLTNN'دç~N6rYVCP>.lUzh]4\-!j 5[즗9Bp] ` ,NG0nP7?AD"Y.P~[zcF^A1)7\+ ˯klіWퟕji? eA~3QxyZ /ӆ!2F_EOZh# ?W2 B7YtDVe8ouWN%`5ѻRI [b6?':pZv,v/_6>>1)^ͫJgε},8ahx$/S8zQ#W1I/"=xGw0AK׃ '!'ɑ'=6exѕeK߯QKbJqwtWƸGjK$w)~0reǵ@W[HRHޞs)wyWj{^+.?:Q,% ;W qKys}%h&Α+d%?:ĪR*d灴ȍ^e6kptc>u-<4cb0CLC3EZޘ-)m1i>esI#$AeF(R 9glאq*nlFf8qJ+Y-9&)ʆ?ce>J8$Qw$%"5#NCF OhrVb[耚qOCRdX cPxNDjW>}!6.JzcM1q] 95<^GD&Q [E/_UWBQ`#~U(d{4,s<>B˯1hB. SEB\QA0(f*IoDUb)52e~]5\.Uz<lcZƺj7tpýN3snkս:qWe-ôFbjo@(' AG!UAҀך]'Yi.bq]9p>m)kaO;ZCiMuXia 䚿IbՖ%8ͧUx/p~b;OA)aOuoD]2i1 1P۪XRl;[lJqu9w!eޞhsEVOKXcJ/ZVU埌VR{`Ǎee֡y tf % @KxqMcmd^9.Sbn~ noo Af$i D,HF?G'm~]m6?P endstream endobj 242 0 obj << /Length1 2493 /Length2 17540 /Length3 0 /Length 18995 /Filter /FlateDecode >> stream xڌP N{pBp@w=kp \99*{=Pj0;ܘؘYJlVVfVVv$jjMk7;H WkGXHn`$ lwqظxYY쬬|5ttH=JyG+?hl||<:XJ@7+=أhf r ZA+77'~OOOf+0# rx Pڃ35@ G 7O Y\GA.w"@ oc0S3t9ÿ흀 k;@EZˍt0h>ZM S'?W3k'7WfWkrd\f)s G{{+_IZufOsm=|,-J݉E$'bee` /3+hz;dK `NomAuzn. *!̭ Kk?`1k/>+xxO;\U?U3\n)3wpY}[@fH fa6ua5bDL{B{:tL.S骳C6\R{1VwhoEW^|OZ?%?='O#-M N 3i8iBBvS:c?xxXSۯV@~.aՊ1.32O@D@u>w{73F&ȀQ諷{gBݵPkla1*z}({&NuN'h 2*-EFC#]̕<ᕽ}anuOnN&}F-qW$_>:(vdRL:z{i|,历_]𹉇z8ѠNpEZ'+Yޘ^“'q]d)V3YnZfc2ONpB-O*vSq=eyO昔 u'B͇'Q0sz_>[uoqdtYVv  >$CINύCs#AZ!@/GOGlUIE-Y n-!Fv:CW86n:qhw .Q{.qRj)97y/׽/nS3#i+bEn2ZL^I M(Y1(Br/KJKOb,~cK6=`̙ Udes_w25>}K¤#dr|:%}T{ʖ&52Ӽ/:FNH]$Kꗫ"g0xl(z6KfdES3^An)xU}_ NpF)rV\uSVtE ˩#&Sb0Z~fSq./&lm9N/c.Ƚ7_ͷhLGMלd*5[z2W?jR:oz,YamutpF~;)@ҦrU!1`|m'úƂ*1Y)}ZaQ$f@ sj%t<>K7Ԛt:bKDu*gGv=D:t[^g0G7)f:obn& )UA>8&~@q-x:f79b+HRzV\_AmAaʸ?8Ɇ7yTܚ9b/\X[^x7Ru2%w${-ȿ4gtQ}Z\R(-،,@VtZצ:Y ;t,xpn{smw{*YrO[4q$tg ) 8BN˶#[p>$e!c*#؍_(hk g`iiwW(hMiHmIj)֩Qx_|9M3Ge E:%oګ(p |o+<2ӽ%Q>#h*)~fz>zAbdk7E@^i{D" o翲?iY7`/iHWP`;"8MX,Nt'\FhAM'w*F=B%?*D T>Q}H Zȏo: mdY|tA^[I<;v[„FlD \Ur"1H‚8Ft}zgԏdvŠ~nK+:c,@ лdr6 7f%h>6pu7ly^:9kA5 R=F'fKHy}E>D;ra-eT!%,2x{3<+!zjgr/3foZ}5h-2:(%7 h#Ym\ڗHA#i6a%b_PYӴQs531Gv~/\"N#x-44R8]~:zÎdE?N} s։&^VVwŧ P#>ZܶS3䊵_Cg2HHj:Xm@Ë;^fwv[G;s0t_r;jT𫧋2A\W#nO3O1S> e5gS>zȘ--Nlw|,t&7G^m4]cQ}ϜN )fc)wwbhb B.>!hÍ@˛zw|K9DemalgL:ϳu _İ~LLorJ[wqúMJIpRƨ>K(Ha{}gSQ7\r4% GĢ4}?fk҇]lmpm@tgH2 i<#z O $)/lu|W>LϯJbH:jtEGsl,y_3)kqMf☐ %:J!D-lpvKrCg,r#7dz瞗O#s0r+2v,m xE3rL,&NpG%n,;~E@a:-PQ*xwN?隔WoZ9_a 3_M RTq~eڕR@5uTȒw sl!$HꙏKTt&(y,E߇x\p[6ihi9oh|jA\5F])A#)j" e4p+X'0gRor_;1:?/0uݴvf0BWű-\r|*Qn~i|]xΡޖ7)( `GRNj琐HP L%y|Tmj{ﯸ(g&sqq ]y1sjrA,Ֆ 1iCS \ )MCܚ2G2O:i 3svXb'5ГI fE|=Bhb~ID[!izAC>]݆hE19Edz˻& 7 @$T 6z ]?q; h2F".V/~"A}r_r O֌2]ۆsҕ|qxwWt(Ou\"r$bN*L =Iw۾MOq8DRϲ]E0$դ s['kwԨQ2|H/$cJq~g`Vڎ ,R-󨬨LJkrM-Ct(T<àuJ޺L# yQf~V{}\>p&bF9`[rz7d lfAw0 vh  SI*UfCIb^WIv35<"џ(C06>J-.#zɑ>D% ( )z=$;L'Mrw PrdC}MH%P×_[lIp*].7i+_hpf'U֔s! E-idQ ћl@'V{(Gu5DNZ9{BκPW},ɀa M-AcYUP<v ,Gg`.I*2-=s]eޫk=k!%)V!Y[8xdyeH٩HZ2{ f^nwv# ٻºm"}F2LLG8@^xoP}<"7jkjJ#&7Bg[6Ҝw?yh!>lv.F044k9zy{xbQdS-E4]f*'7q^045mY7JXvP E>%&ꕵ 2^vŧ^U ˚G1V_wp-8؈JaéR EKDPUs+o+aUp!q(Sm*$@OU‹S:*!pKEtԭJ-?M.(DwTۤl5X,Ko=u#\"]㣒cZ[{7~Yo{vjA퀳9{/$^)LJ-Wf ,\c-v统): (;+&aIjG!+H7 y(T |' R,|d8Pj_$ dBP^Gl;iyLy"4ȝ>yW0LyE_$ y䟶Hm rq!sdP&*w$s^Uae+& 5y1bC""W%d=\9\zP/./)n*6BT4u-Jɾop}u[˸_nb6Hv(s|)LY8v@1SqT&Ȧ;.ŝyLV(o#nt*gᙐNYapU.e rA](Uo/sܩB :n.seFP}:u}KŲ/h|@ A7o  Iu-βfv^ Bרl!CYt^0cRVm..t{5o(N{YXԔ#>/YTqce@L]^cE;Qm|Ҭ_717T:9ZH5mVi=IAr.Sѿ Cᚨ@EgfH5{foWc,Dζ(Ċ:;ZjyHn6y/,ٷr4ZOUXu໼dJkf\Vԟ~|2JF(EnqRo \b:0{ORPAwК#UiB#? u/BObW~%^'Y@@^qM OA߮eF/t"~zqwLn}bvz=,H7 SY.tu^-lƺS ؈UehVO-f .24כA}vV:YLnܽ:\bYu':vV*nTy(_~0\kOðVO_滣Yjw>LJA)>4 :9J'?I ATY)PR)Pj/w6B:pc6YOa;9m䞫 NED!g4̂ /)˿xu,@!s/bۢz8ϞFrr5i#<DZ=EN@3jҺot#Kŭlg[%&溨Q he4QWʚ݁{pIY0 7v6#f] ,3_sgBfP=(jvg+LT#m+.LIrh D︚ `TMٲ4"E*?%~EyK`3ZcU/CKp>ȱBPEfGЛ ϵUIpyW=:=Luw&<[J[l}GOC[{>o۝4_2Kj?i+ -/ =n?F Z3PcT"9>ܮoBVY\o6ƾrK Mp._tb_hwgK$I]Α{|نfOv*?\Z;ـ>AcA P5> cY?t0c)ϑS`.r :J]n>M=h_^l=YfDVѫІK.ŝS; N.'C/]8O" ϸ Ts\l+IgWŘ@5cNO^C.];fޕyMMMR3>6"s4{ y҂%z#WzfZ*3ArGzSr4eV>#W2y( I\azg̻On4WEԸUə'G?֣ΑNhcZh)wd|mCo9۾vy@h`]CF&·{>=.IXM"6ȇڏA&r8AA̸C/9,o,WaZzT:,!q2I@J }\E4L*c,%j~1kw^ #TQ1yJ %Q쉲E!yP6^\- !ugj9]Uш=2]5aĮI  nM}B"2aC 5~̏q|-7.HXB~| ^RK*q0PĶkBՅ׵E5?TNXF=)#c<vq<98}I%5 .D )LHW0B/ W"D(rWy&h?3w P&IEmm%B2wmax= %Q*r%-Ȍ!gϥ |ay h~=Rd#ēV@ܱ |1e wg~CLL4ӵ]_HKS9za_@/5UΦ ܫ5V|cYu3anNm:҅ $t)Rs7ܵk(h]1B?5l9x7k$?x;x:غgl;p?,z~o!".Lq`_pPU^ @gEE42Ds`9ÈٛB֊DžP%!. $ iuI"DlWL j:Ъ<$c#}w)LG}UOΩuTQ!Hmf7s_N@fgXP]}IJlP[ՍC9>Sc9ILϔ_e# *k}< qƾsCLDWbŲR2%6Z{S/łJu1yx.ҠEܯ9vs)$Uy>sO%X%%綟8[8#^I*g99HܵB?yq0 !1lyS߿+?Nn{,Ix&Q,lfJ,43ճX_# ߚgk~-tS$˜tvRZp&U6>x#g+Wk[ýj?Q %Dnggi1#/z B>T.c_ؚ+PBS-}a(yMwwz2|` r)N x$#P.!/&FQ#; [z!ci :7$"hF1^ M| f\`Q2b%ԡ%X_6]g;nT㠙 K.IJ-CWD~oSjW zFj]/)( ^=i>_. >-V %3酦g.Is_Qh3Vp%:0SCNzR[.0q`D[zl_^ !-A$0*f_|mq; !1{{YiѴ@GN{Soj(q~VNU \^݀-*S`v.EiP7dcM޹-E:1ϠBj3UC\Se@ v)q~{Y$*"Ó+mxǀde= {r9CS,d5N_5AvKVI-i;`ajKIM'12+NB=:ApNbk[clAA.]~i`[H #1A9K.BJ:?3)K>ˆr@#=;D~0>?Pbjg鏲IkԅCZ>xWd+Yz/e9AuOS ǑlF{ ⡊wɝ i҂6ߚD[wN%dQNt5/ yLmna5;f @~z܁rb$bƽq7>ɈM]'4ѼovQU< ZتtTU{]էmX{ w7Rԫ-rF场 cLӱr^BBٚ!ho"UjnOv4EznӲqWVPW:N"5)Oz}2vΝF,zbE/ez2ܛR"UIPh5 3}\B|1mK86!_KyܕJ%V (hFE. hmt%XWБKTёM}W A\~A6űzoϭd5d}\Gd֭/ږ5/v1S0 䯙eH5N_#ykŴ7O–Y_!E]oIjddH53<ž T76BO"rB㚕Zd{߉LOK~] ,(VS\Vls5m,nZF!Қ kh~{Q6ppPk ͯfQFfKxl=ɶAşE\hG|Ie}×㽪aM( NLƷ9qf ux {&+ d& 'T|IN,f֯w/†x}U#'F8 ]`WĜdߖ??|h6{$/Q?{=wp9 {~9`E'#JjQ?PA_[u CP_ n7%eDlOKTK E8׳ \Qz"ѐv!xC6—8X(s9_SqLP\{ևې`i7rNE{`|:#(hf[j jk'у5owXZp2^@+,&uiCeJ)I3k SBJ?H l!r퓝>G'R#ٵ 9wq8ԕy(d׾?!XOC7?tÝt 9x683ͩakAL^§7n_ڠNsߚ ru'~c y_{gu0:*^ϋLaNO$7kt:iwE[ysMnҬ*k'r?$K] e2u?3>AW&8IWM*((uSB <i_l1cem8&2ql)"g0'NLz ?>X;Rz}׊;>|.s4$l\@ jL_t< 2 UT[K !ǵZc#@s' NpgT,L"khJ(t"#vz;~lXط*ጅpb]R$`Th%Ob1i:Kƅo~Z=Q?M\7@Z[(f>HxOˡDZ ŃUװLG[M_[52g1:"1ssyS뺽Es`+9%~á}'b.&Gd0f. X"DZ'B>9AXC v[x|'\̼lzxBωktWG>CsSs![n$DfUtw &^]z|7:Шi7jƫ;~Q E,Tlk Om;l<,=_A\3q(fF?eqgb"" QT-غ -]]<7#JD`[z!,;˅xKñZ9⠠9BmH9 &"eUfP%5c%j̓_)p]byq}٭r~~ Stn3- 4|ءPMɞXic46sx@ޡj )\1kᝡܕd&LÌɐ ^a)0Tl FQE:?LJB E>بdǵ[ͫc ).Xl"~f~>I0o]Ѫ41vk轄Y~TߍdJF8o Ilו"EZΧ^jZ13~m̜'.C"dqᮚm4a~m+Kf;Y^LIu45rP 2/*+_]m奓Z}1U.rYv]/c_-*Qo#ioe4׷oM8:M<ķAUk#ēŜT*O+qy|>ח,Y4zUVHq~%i<!Zddlϸ[9&aOAs%m2Zي4KpuM_xkqpa=`J$.m^K5 ӪX1(:]GFsti xHWY x= 0oMqА]xL6cr:H+6R@%/\gt$ 0,1B g~/ճ_gUSܷI7 Ci''9{& 3ĕH,<Ui<ϗfTEy,OmέBooH9|td3_UF*] DՆc[@rȔr& !? (Ͷ߶U¢=*{q:hw6Zzk/@HkXB;A[4 WPCk ƪY%i +8v*Lhh\O$T{x)Sʰj/am8Y@>M\"m:%M Cq߀9P MH*=AiQQZ34~x& >i0ڟic?n6.AEC+T7g.V;5޹H2Ew1: H%}n30[B3>5yp+|5Q ˿௛كk9SJuQ=_ĻKq2{.o> M !Lve c]NJ0κE:YTv֬&Cnx:|/h@j.zL6HDtjO_LGxnݟ%aBߊIԨMp=dxLmI ǨD iX Ər (m!K~ܼ/ٴGaw7ZH(QDIQBmD>tJ~ds )r#)r KTs'?7wsS lԹWΘ<[En/= 7]|,i;cl G Ƴ4T^mNԣd\]={oQ,6v7̃vQF6FK(`mZ~PAT4h_IƢz)Hp ĐB?#dyW>yV8 (0AIܕAY D-v<&H"'\̃u-:EU_ݹvuq74XƅWak9Ft a [ m6nN>񀍹?iTXᴧ`iCYcj9B'#)n1Yq 5|NXjq /zٯ! =e,HWq;:}<زpFό:eTF'_NK;wJzIQfupZ-K endstream endobj 244 0 obj << /Length1 1719 /Length2 4422 /Length3 0 /Length 5484 /Filter /FlateDecode >> stream xڍt<(;#EV}:{7Eqgܝ22#+,#{ d )CGQq=_oƠ bqadi)R`$-d"x iAHA+aC$&@3 }o"@d `0 c)001h$P.Rp!"//+zy"q(8 HORF8QHB*X ___q'^sQ|QWG|0` D`&N ,]Qr 3C$ DIhz al@"a c<0? 8<8 ЈCCCP0'Q0@[ PX^8(qe-4BDipH8?&~g|HፕBz?MH"2$`9)0~pWXr(&1 b32$a>HF7@ N.(4$1& ݃ϯI=WBSTZ__:uu $$4IMaC;c Hϥy0B3cH/= ?rmam[ǑZHa(E&C: Mm?@y{WGC (60EGH=Ph):|i1OՑ I:gB1ë0O &-$ @H@5 !H.]T H, a IvwԲw[V c'fDN][zK]rB#\Xͻ| zm g/(7>)w]_':+''EOѢPJmpUڻ­Jx(j:si$Krg2} hD/Nd].a5mb [ 4;++b bw1%WKo,g֗!Y}˃t/alnPcUQ%BI\yܻ)m;K.' =msoD֡b0$V{#S.VM<_c`v{.p2 *_QڈY%T$ow\ VO{2,a#k_= K D+DG;7b?:u-7kA#g7uP|jD2^D=JU `ոXs!ch.>j0c ~9b r5Y&2\SD~㴣aAS4ڭ *6vd}#0|^L8LzOy浄'e]~CR~cȦUi`t] z o#Gv P\ߩ(֮^1uFLDէ>o%#%2.|Q>TfYK\j}aErx3ї'e[6i?56Kp/yӇL^hbw2 -T;Ɵ ׿zT+]4/ms} C}^~Iɋ{,b56;Ox<ifĩ\+)׼t~F4Eʓ7METݯ P˱%銋[`b};TJżvE9Z,R:^fk9\DY݇&F?Ӂ7nZS8~i((sUD9ilSOǮN$b <S%yޭ֗ʬ\ ,NsXבP 6>v;\2L"o2>nTtL2u]`M4^*ݿumcS.~w?7p;y>[:NǖRV^VrMCrCiASvҰKR!mkh2сŅJ"UJA~o/܂հY!23<_X")Ȉidotn!.ɢawvL9Wdc*3u ʨDN[&h~QC͉&xQ]BgusƻK|l~=21O8r+p3sE Kn(cy* N.`yL)2ށb&8;#g a.,#[0aQ5PF!Y&$l7<㨙ǾSXeąPS_Xn+~84&Ps[x ^0"g`KyKC#a~^;oX5vR )>#};|C*r_Lfvf=Ʀ>(tia"dpnLSSáK׮EX?FΓId3Wbm1U]B͹*WL:EoR0/rP i+3 vc`jyNn>s:Ēe΄ה>ڢ'MhͰsq`M`y:ƉV(K. }G>@_*v$jR6,,T HRzЇK{ϗ{΃}2'ڧ8*h'J0:^0~C -n]h+(Dɢ2^+Z><^u Qmļ_, _΅> ]QL<خG+z yB@=xh^|@Gt?YU *s>8:r{H.N$4 Y霐\xVwAB-neɅsޡ{a'Tt7(Em~%D]Oܟ_݌PwW5)q) k>-p7TU*g/؝rY6eN˻ƭ;aZ-aqϕ8NNI^zr(7rFp^2ZS3Ee}%1GAy>GUlCU47][ݟK޼K,es] Ҷ^u0s"RoVW鶺D[Ѓ&M5=VW;2AOGͤ6?S5rQ V'lrm=a-~I:6336I/F7,,`L7z %nbӒP[(۶r u) m}rl܉qPt$_#ufZy]ieu|?螢ԡ洅אc:U`ȫBTԗnrGK>1_[TVe{%ŗ&3"'~]s#OC 7t{ɣ$7iSa/SqN3uz/hVMmW|m ښm:w9(zd= :~qyKq_xA!J: ww^ev)Gh8iy𻐻QVVGЁn#]&!wXf3Wv CZwQqQ"]1.;~O]ЄƱWg_x <eWv蚆sЫrӼwW΍tϕm;G "X^>5 [Ԯ?exL6떜oTFkeSyjtR"MlVbi"F[36h3o {5c֊ ꓩ$'L[V^OdݔJo,eIw{@ivY3A endstream endobj 155 0 obj << /Type /ObjStm /N 100 /First 895 /Length 3879 /Filter /FlateDecode >> stream x[Ys8~ׯLmET'Nc;ȖG3nIxfA4H &E_LtdcZJ&dFy* |AW:=, < a"ydcsf`L I =pQNz=(}IW[ QcӆY hc!0%`T*R((|r)cwLYZy< -X%tL {Jh 4`Z $1Љ  )nJDfBOLR1 NriSԱ9r ld>rJFp \,E)͂Ge!" .PCtd1 тׂTXrL",i:@Je ~$B_.UB "- :>` 1)U)j-Q |Ht"ø@P(% Bk,\:ĤEj! A q G4L@@lA=7Ǐs4//Ⓔh ^KNŌ2~Iuz0O01,z|7)Ǐnr^L)i蠸_)pl>33Z 2]v{dH?0/lBn4:$4@hOiCp7kՑj`]p[p: g@v\](=l9%JoVMmbưqHHP>1Hf%6Eg$,Xb bFfu}S^1Mm jho6]!aM/d7Fɭ[@1+Pjwߏ I=ng\^񭛛1:>g}n&?8Û==\!SwNQqJ5˾ ahNp}mnj?᧧+g>E ](%p9xPV{{VBǏ?: 7>OW9ghOHO.M1[{繢Jq6Fj9e`~&Zlg=O7їC@*pNTBlX s%T ;4jهwCA9C8g Tጲ_1Z>>+c}OZZ-cߤ,_Uns}luGu6z*]2h`Y6SxƢs]b6Tb#L@{5 qWCZ4ƒF飈!~i9uj5Y@;ԉ/6l&>ֻ64 K[#*oQӁ0hmu }bS›g =n7KHHF$I\MiG'jWiv>V_&Hҫ S'#P7BCC 5<1,Բ?7lFQhK.ƈ73Az(:W/y+ Ds*CצFQPkJ94# D>FLd'sO SBPі,LiDácAE:Rb+ %Ct1eԦTѨ[d3@}_mx=bFWh]EE=aI^ L :Zmh&]~6"##+祫Nm=lj<~-O):s`FJx mp|j[L'x\̳'^ok`01\NIu3 1|,<=}p;ۧ .qs$N`xV\"8$ķ?|?s~>o/hw~ɇ?|į MoOϮ&Eg,&㟓9{CPBPB=x_mmLx4ƒ'}xD\6 `j uuVd8ߍgŨ4K ʼJ[)NbLccMA|U; XݴSc7`AZe+ ^ՌԲnKNvuz-ueY"YUiTJ_!gg/+~d8[<;n.jq>PsLZ sfSAyC7eN\8'\$΄_@tOGB!Muyx͎zgg1q]pv~7+M_B {H(+}=U?$p|8:z4p0qepl8Vmpc:Wqa^.?yƺ\5tg$KUz}u|BtMW7ej{{prsDh|WFʆ5xYYYkk*Z)VgHڏbF-Smkދh4Tn0#Rn\ ewjnJ_bBɽ|<)U_Vmqo&^*:OATW*SYY(*kUЭa&vr:vgo?Cǭ n;r 0#rk؝j&A=g p2^/BJz;]M镐ŷ[lGv}mt[<p5 o4xQ\KoevU.[/m 'dM@z%]פo|t&քE yn˶#q[Bit"@X.6(83UK7^nuCua/kSnX:|x1e>5Uw2=0LWBn~̖nQOSAl+BSAlԒu= b:i+YFT%1x endstream endobj 262 0 obj << /Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.14)/Keywords() /CreationDate (D:20151013213056-04'00') /ModDate (D:20151013213056-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) kpathsea version 6.1.1) >> endobj 248 0 obj << /Type /ObjStm /N 21 /First 165 /Length 694 /Filter /FlateDecode >> stream xڕV]k0|_I!=i%@H(iSɃrwNi}weYm]hdggG#u AZ0P*@G@GXЄk0HvDG@#bF%*)t I*]Ӄi4#Z3iY:Kq[Hx&&j"WKPbx%ݓ0*эXM+0_&oD}CyWIY/zᤗ:(cG eyM[:*%P( I_YmssN)fYmy~rݝ}} .􃓷?u-OD}l6p2 b 52Ŵm?kxsw EF咚#j©s&5s\ॊ<0䀬N8\&B}gV%1㸆Nk80YaReK)cAqN*nm{Β` )BL ZEg3kan|Eqӏ;YyJ|p2jޅԜ\@\)SB+J\Qc]/pn+ԷZyKK1ly 9$ߵnaq88ꗾMǶ 6熯J`iQȵ? JßG뫦o݆o E:^Gm xMݽ_;Le~w@n˿NX5 endstream endobj 263 0 obj << /Type /XRef /Index [0 264] /Size 264 /W [1 3 1] /Root 261 0 R /Info 262 0 R /ID [<6BFD20427E5A099BA19BF9B56F70EBD5> <6BFD20427E5A099BA19BF9B56F70EBD5>] /Length 658 /Filter /FlateDecode >> stream x%MSaϹD)*"** )գ JTB 3̘ƜxX 6[3>Oposs_5=dmn̨z6mr@?Y!UMTVGɴ sdz%2d:l7t2P`XU&v]MS I \Ji m-Ѳ\< }`?h8MHA+hGA'8 u~vS`L `̃Yp'׭6[}e` |T6 8(VƑҤ[㸲)p̸5Q.Pq4ֶty'.`S"dih2VݦBX\{ mrے(hn+]0;06־+␝n!pcT~Lj;3ʰ3CԫqWىWQ2WWHJh@E~zppppppppppf!$WoSz ޫsoV>Q*⫪_pAOկT yjoF= min.score ok2 <- rangeComparisonCodeToLetter(compare(query, subject)) %in% type_codes which(ok1 & ok2) } .findOverlaps_naive <- function(query, subject, min.score=1L, type=c("any", "start", "end", "within", "extend", "equal"), select=c("all", "first", "last", "arbitrary", "count"), ignore.strand=FALSE) { if (ignore.strand) strand(query) <- "*" type <- match.arg(type) select <- match.arg(select) type_codes <- switch(type, "any" = letters[1:13], "start" = c("f", "g", "h"), "end" = c("d", "g", "j"), "within" = c("f", "g", "i", "j"), "extend" = c("d", "e", "g", "h"), "equal" = "g" ) hits_per_query <- lapply(seq_along(query), function(i) .get_query_overlaps(query[i], subject, min.score, type_codes)) 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(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:5, 5:1), c(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, query.map=q_revperm, new.queryLength=length(q_perm), subject.map=s_revperm, new.subjectLength=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.R0000644000175100017510000004472412607265137023131 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(strand=1:length(gr)), silent=TRUE) checkException(mcols(gr1) <- DataFrame(score=letters), silent=TRUE) mcols(gr1) <- NULL checkIdentical(new("DataFrame", nrows=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.R0000644000175100017510000001432312607265136023754 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(a = GRanges()))) checkTrue(validObject(make_test_GRangesList())) } test_GRangesList_coercion <- function() { ## RangedDataList -> GRangesList rd <- RangedData(space = c(1,1,2), ranges = IRanges(1:3,4:6, names = head(letters,3)), strand = strand(c("+", "-", "*")), score = c(10L,2L,NA)) rdl <- RangedDataList(a = rd, b = rd) gr <- GRanges(seqnames = c(1,1,2), ranges = IRanges(1:3,4:6, names = head(letters,3)), strand = strand(c("+", "-", "*")), score = c(10L,2L,NA)) grl <- GRangesList(a = gr, b = gr) checkIdentical(as(rdl, "GRangesList"), grl) ## 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(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_accessors <- 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_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_SummarizedExperiment-rowData-methods.R0000644000175100017510000001117412607265136027711 0ustar00biocbuildbiocbuildlibrary(digest) .singleDispatch <- c("coverage", "disjointBins", "duplicated", "end", "end<-", "flank", "granges", "isDisjoint", "narrow", "ranges", "resize", "restrict", "seqinfo", "seqnames", "shift", "start", "start<-", "strand", "width", "width<-", "strand", "ranges", "seqinfo<-") .twoDispatch <- c("nearest", "precede", "follow", "distance", "distanceToNearest", ## FIXME: "findOverlaps", "countOverlaps", "subsetByOverlaps") .otherFuns <- c("order", "rank", "sort") m <- matrix(1, 5, 3, dimnames=list(NULL, NULL)) mlst <- matrix(1, 3, 3, dimnames=list(NULL, NULL)) mList <- list(m, mlst) assaysList <- list(gr=SimpleList(m=m), grl=SimpleList(m=mlst)) rowRangesList <- list(gr=GRanges("chr1", IRanges(1:5, 10)), grl=split(GRanges("chr1", IRanges(1:5, 10)), c(1,1,2,2,3))) names(rowRangesList[["grl"]]) <- NULL colData <- DataFrame(x=letters[1:3]) ## a list of one SE with GRanges and one with GRangesList ssetList <- list(SummarizedExperiment( assays=assaysList[["gr"]], rowRanges=rowRangesList[["gr"]], colData=colData), SummarizedExperiment( assays=assaysList[["grl"]], rowRanges=rowRangesList[["grl"]], colData=colData)) test_SummarizedExperiment_GRanges_API <- function() { ## are we targetting the correct API? signature for ## SummarizedExperiment method should match signature for ## GenomicRanges or similar, as in each test below for (.fun in .singleDispatch) { generic <- getGeneric(.fun) method <- getMethod(.fun, "SummarizedExperiment") checkIdentical("x", generic@signature) checkIdentical(formals(generic@.Data), formals(method@.Data)) } .sig <- c("SummarizedExperiment", "SummarizedExperiment") .targ <- c("GenomicRanges", "GenomicRanges") for (.fun in .twoDispatch) { .siglocal <- body(getMethod(.fun, .sig)@.Data)[[2]][[3]] .targlocal <- body(getMethod(.fun, .targ)@.Data)[[2]][[3]] checkIdentical(formals(.targlocal), formals(.siglocal)) } ## FIXME: compare, Compare .sig <- "SummarizedExperiment" for (.fun in .otherFuns) { generic <- getGeneric(.fun) method <- getMethod(.fun, "SummarizedExperiment") checkIdentical(formals(generic@.Data), formals(method@.Data)) } } test_SummarizedExperiment_GRanges_values <- function() { x <- ssetList[[1]] isAssign <- grep("<-$", .singleDispatch, value=TRUE) needArgs <- c("flank", "resize") isEndomorphism <- c("narrow", "restrict", "shift") .funs <- setdiff(.singleDispatch, c(isAssign, needArgs, isEndomorphism)) ## 'exp' created after manual inspection of results exp <- setNames(c("1f7c0", "35e2c", "02dde", "80339", "49a3f", "72f53", "86757", "77198", "ec53a", "35e2c", "625d9", "3c90a"), .funs) obs <- sapply(.funs, function(.fun) { substr(digest(getGeneric(.fun)(x)), 1, 5) }) checkIdentical(exp, obs) .funs <- isAssign .gets <- sub("<-$", "", isAssign) for (i in seq_along(isAssign)) { ## self-assignment isomorphism value <- getGeneric(.gets[[i]])(x) x1 <- do.call(isAssign[[i]], list(x, value=value)) checkIdentical(x, x1) } for (.fun in needArgs) { ## all needArgs operate on rowRanges generic <- getGeneric(.fun) x1 <- x; rowRanges(x1) <- generic(rowRanges(x1), 5) checkIdentical(x1, generic(x, 5)) } ## isEndomorphism for (.fun in isEndomorphism) { generic <- getGeneric(.fun) obs <- generic(x) checkIdentical(generic(rowRanges(x)), rowRanges(obs)) checkIdentical(assays(x), assays(obs)) } .funs <- c(.twoDispatch[.twoDispatch != "subsetByOverlaps"], "findOverlaps", "countOverlaps") x1 <- shift(x, seq_len(nrow(x)) * 5) for (.fun in .funs) { generic <- getGeneric(.fun) exp <- generic(rowRanges(x1), rowRanges(x1)) obs <- generic(x1, x1) checkIdentical(obs, exp) } # nearest,SummarizedExperiment,missing-method checkIdentical(nearest(rowRanges(x1)), nearest(x1)) checkIdentical(subsetByOverlaps(rowRanges(x1), rowRanges(x1)[3]), rowRanges(subsetByOverlaps(x1, x1[3]))) } test_SummarizedExperiment_split <- function() { gr <- GRanges(Rle(c("A", "B"), c(2, 3)), IRanges(1:5, 10)) se <- SummarizedExperiment(m, rowRanges=gr, colData=colData) ## FIXME: unname should not be necessary obs <- split(se, seqnames(se)) exp <- SimpleList(A=se[1:2], B=se[3:5]) checkEquals(obs, exp) } GenomicRanges/inst/unitTests/test_coverage-methods.R0000644000175100017510000001144212607265136023722 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.R0000644000175100017510000003206112607265136024563 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) 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.R0000644000175100017510000000473512607265136024351 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))) } test_GenomicRanges_inter_interval_ops <- function() { ## gaps gr <- unname(make_test_GRanges())[ , character(0)] checkIdentical(gaps(gr, start = 1, end = 10), GRanges(seqnames = Rle(c("chr1", "chr2", "chr3"), c(2, 3, 3)), ranges = IRanges(start=1, end=c(5, 4, 1, 10, 3, 6, 8, 10)), strand = strand(c("+", "*", "+", "-", "*", "+", "-", "*")))) ## range gr <- unname(make_test_GRanges())[ , character(0)] checkIdentical(range(gr), GRanges(seqnames = Rle(c("chr1", "chr2", "chr3"), c(3, 2, 2)), ranges = IRanges(start=c(6, 1, 5, 2, 4, 7, 9), end=10), strand = strand(c("+", "-", "*", "+", "*", "+", "-")))) checkTrue(validObject(range(gr))) ans <- range(gr, ignore.strand=TRUE) exp <- GRanges(c("chr1", "chr2", "chr3"), IRanges(start=c(1, 2, 7), end=10), strand = strand(c("*", "*", "*"))) checkIdentical(ans, exp) checkTrue(validObject(ans)) grl <- GRangesList(gr, gr) ans <- range(grl, ignore.strand=TRUE) checkIdentical(ans, GRangesList(exp, exp)) ## reduce gr <- unname(make_test_GRanges())[ , character(0)] checkIdentical(reduce(gr), GRanges(seqnames = Rle(c("chr1", "chr2", "chr3"), c(3, 2, 2)), ranges = IRanges(start=c(6, 1, 5, 2, 4, 7, 9), end=10), strand = strand(c("+", "-", "*", "+", "*", "+", "-")))) ## disjoin gr <- unname(make_test_GRanges())[ , character(0)] checkIdentical(disjoin(gr), GRanges(seqnames = Rle(c("chr1", "chr2", "chr3"), c(3, 3, 4)), ranges = 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)), strand = strand(c("+", "-", "*", "+", "+", "*", "+", "+", "-", "-")))) } GenomicRanges/inst/unitTests/test_intra-range-methods.R0000644000175100017510000002457112607265136024345 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.R0000644000175100017510000001424712607265137025252 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_nearest-methods.R0000644000175100017510000002711112607265137023571 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_precede_follow <- 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) ## query on "*" -> acts like ignore.strand=TRUE 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(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(c(1L, 2L, 2L, NA_integer_, NA_integer_), hits) hits <- follow(query, subject) checkIdentical(c(NA_integer_, NA_integer_, 1L, 1L, 2L), hits) } test_GenomicRanges_precede_follow_ties <- function() { query <- GRanges("A", IRanges(10, width=1), c("+", "-", "*")) subject <- GRanges("A", IRanges(c(5, 5, 5, 15, 15, 15), width=1), rep(c("+", "-", "*"), 2)) checkIdentical(c(4L, 2L, 4L), precede(query, subject)) checkIdentical(c(1L, 4L, 1L), precede(query, rev(subject))) } test_GenomicRanges_precede_follow_0width <- function() { a <- GRanges("A", IRanges(100, width=0), "*") b <- GRanges("A", IRanges(20, 25), "+") checkIdentical(NA_integer_, precede(a, b)) checkIdentical(1L, precede(b, a)) checkIdentical(1L, follow(a, b)) checkIdentical(NA_integer_, follow(b, a)) checkIdentical(1L, nearest(a, b)) checkIdentical(1L, nearest(b, a)) } test_GenomicRanges_ignore_strand <- function() { query <- GRanges("A", IRanges(10, width=1), c("+", "-", "*")) subject <- GRanges("A", IRanges(c(5, 5, 5, 15, 15, 15), width=1), rep(c("+", "-", "*"), 2)) checkIdentical(c(4L, 4L, 4L), precede(query, subject, ignore.strand=TRUE)) checkIdentical(c(1L, 1L, 1L), precede(query, rev(subject),ignore.strand=TRUE)) } 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)) 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(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)) ## 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_setops-methods.R0000644000175100017510000002571312607265136023452 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) checkException(union(grlist, grlist), 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) checkException(intersect(grlist, grlist), 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) } test_setdiff <- function() { gr <- make_test_GRanges() grlist <- make_test_GRangesList() checkException(setdiff(gr, grlist), silent = TRUE) checkException(setdiff(grlist, gr), silent = TRUE) checkException(setdiff(grlist, grlist), silent = TRUE) expect <- GRanges(seqnames(gr)[integer(0)], 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() checkException(punion(grlist, grlist), silent = TRUE) 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) ## pintersect,GRangesList,GRangesList gr <- make_test_GRanges() grlist <- make_test_GRangesList() expect <- reduce(grlist) mcols(expect) <- NULL checkIdentical(pintersect(grlist, grlist), expect) } 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/0000755000175100017510000000000012607265137015077 5ustar00biocbuildbiocbuildGenomicRanges/man/DelegatingGenomicRanges-class.Rd0000644000175100017510000000162312607265137023200 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} \alias{update,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/GIntervalTree-class.Rd0000644000175100017510000001660612607265137021215 0ustar00biocbuildbiocbuild\name{GIntervalTree-class} \docType{class} % Class: \alias{class:GIntervalTree} \alias{GIntervalTree-class} \alias{GIntervalTree} % Constructors: \alias{GIntervalTree} %\alias{updateObject,GRanges-method} % Coercion: \alias{coerce,GRanges,GIntervalTree-method} \alias{coerce,GIntervalTree,GRanges-method} % Accessors: \alias{seqnames,GIntervalTree-method} \alias{ranges,GIntervalTree-method} \alias{strand,GIntervalTree-method} \alias{elementMetadata,GIntervalTree-method} \alias{names,GIntervalTree-method} \alias{seqinfo,GIntervalTree-method} \alias{score,GIntervalTree-method} % Ranges methods: \alias{start,GIntervalTree-method} \alias{end,GIntervalTree-method} \alias{width,GIntervalTree-method} % Vector methods: \alias{[,GIntervalTree,ANY-method} \alias{show,GIntervalTree-method} \title{GIntervalTree objects} \description{ The GIntervalTree class is a container for the genomic locations and their associated annotations. WARNING: GIntervalTree objects are defunct. Please use \link{GNCList} objects instead. See \code{?\link{GNCList}} for more information. } \details{ A common type of query that arises when working with intervals is finding which intervals in one set overlap those in another. An efficient family of algorithms for answering such queries is known as the Interval Tree. The \code{GIntervalTree} class implements persistent Interval Trees for efficient querying of genomic intervals. It uses the \link[IRanges]{IntervalForest} class to store a set of trees, one for each \code{seqlevel} in a \code{\link{GRanges}} object. The simplest approach for finding overlaps is to call the \code{\link{findOverlaps}} function on a \link{Ranges} or other object with range information. See the man page of \code{\link{findOverlaps}} for how to use this and other related functions. A \code{GIntervalTree} object is a derivative of \link{GenomicRanges} and stores its genomic ranges as a set of trees (a forest, with one tree per \code{seqlevel}) that is optimized for overlap queries. Thus, for repeated queries against the same subject, it is more efficient to create a \code{GIntervalTree} once for the subject using the constructor described below and then perform the queries against the \code{GIntervalTree} instance. Like its \link{GenomicRanges} parent class, the GIntervalTree class stores the sequences of genomic locations and associated annotations. Each element in the sequence 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 as in \link{GenomicRanges}, but two of these components are treated in a specific way: \describe{ \item{\code{ranges}}{an \link[IRanges]{IntervalForest} object containing the ranges stored as a set of interval trees.} \item{\code{seqnames}}{these are not stored directly in this class, but are obtained from the \code{partitioning} component of the \link[IRanges]{IntervalForest} object stored in \code{ranges}.} } Note that \code{GIntervalTree} objects are not supported for \link{GRanges} objects with circular genomes. } \section{Constructor}{ \describe{ \item{}{ \code{GIntervalTree(x)}: Creates a \code{GIntervalTree} object from a \link{GRanges} object. \describe{ \item{\code{x}}{a \link{GRanges} object containing the genomic ranges.} } } } } \section{Coercion}{ \describe{ \item{}{ \code{as(from, "GIntervalTree")}: Creates a \code{GIntervalTree} object from a \link{GRanges} object. \code{as(from, "GRanges")}: Creates a \link{GRanges} object from an \code{GIntervalTree} object } } } \section{Accessors}{ In the following code snippets, \code{x} is a GIntervalTree object. \describe{ \item{}{ \code{length(x)}: Get the number of elements. } \item{}{ \code{seqnames(x)}: Get the sequence names. } \item{}{ \code{ranges(x)}: Get the ranges as an \link[IRanges]{IRanges} object. This is for consistency with the \code{ranges} accessor for \link{GRanges} objects. To access the underlying \link[IRanges]{IntervalForest} object use the \code{obj@ranges} form. } \item{}{ \code{strand(x)}: Get the strand. } \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)}: Get or set the information about the underlying sequences. \code{value} must be a \link{Seqinfo} object. } \item{}{ \code{seqlevels(x)}: Get the sequence levels. These are stored in the \code{partition} slot of the underlying \link[IRanges]{IntervalForest} object. } \item{}{ \code{seqlengths(x)}: Get the sequence lengths. } \item{}{ \code{isCircular(x)}: Get the circularity flags. Note that GIntervalTree objects are not supported for circular genomes. } \item{}{ \code{genome(x)}: Get or the genome identifier or assembly name for each sequence. } \item{}{ \code{seqlevelsStyle(x)}: Get the seqname style for \code{x}. See the \link[GenomeInfoDb]{seqlevelsStyle} generic getter in the \pkg{GenomeInfoDb} package for more information. } \item{}{ \code{score(x)}: Get the \dQuote{score} column from the element metadata, if any. } } } \section{Ranges methods}{ In the following code snippets, \code{x} is a GIntervalTree object. \describe{ \item{}{ \code{start(x)}: Get \code{start(ranges(x))}. } \item{}{ \code{end(x)}: Get \code{end(ranges(x))}. } \item{}{ \code{width(x)}: Get \code{width(ranges(x))}. } } } \section{Subsetting}{ In the code snippets below, \code{x} is a GIntervalTree object. \describe{ \item{}{ \code{x[i, j]}: Get 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. } } } \section{Other methods}{ \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. } } } \author{Hector Corrada Bravo, P. Aboyoun} \seealso{ \code{\link{seqinfo}}, \link[IRanges]{IntervalForest}, \link[IRanges]{IntervalTree}, \link[GenomicRanges]{findOverlaps-methods}, } \examples{ ## GIntervalTree objects are defunct. Please use GNCList objects ## instead. See ?GNCList for more information. } GenomicRanges/man/GNCList-class.Rd0000644000175100017510000001161312607265137017736 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 are replacements for \link{GIntervalTree} objects. The latter are defunct starting with BioC 3.2. 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))) ppquery <- GNCList(query) hits4 <- findOverlaps(ppquery, subject) stopifnot(identical(sort(hits3), sort(hits4))) } \keyword{classes} \keyword{methods} GenomicRanges/man/GRanges-class.Rd0000644000175100017510000006321012607265137020021 0ustar00biocbuildbiocbuild\name{GRanges-class} \docType{class} % Class: \alias{class:GenomicRanges} \alias{GenomicRanges-class} \alias{GenomicRanges} \alias{class:GRanges} \alias{GRanges-class} \alias{GRanges} \alias{GenomicRangesORGRangesList-class} \alias{GenomicRangesORmissing-class} % Constructors: \alias{GRanges} \alias{updateObject,GRanges-method} % Coercion: \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,Seqinfo,GenomicRanges-method} \alias{coerce,Seqinfo,RangesList-method} \alias{granges,GenomicRanges-method} \alias{coerce,character,GRanges-method} \alias{coerce,character,GenomicRanges-method} \alias{coerce,factor,GRanges-method} \alias{coerce,factor,GenomicRanges-method} \alias{coerce,RangesList,GRanges-method} \alias{coerce,RangedData,GRanges-method} \alias{coerce,Seqinfo,GRanges-method} % Accessors: \alias{seqnames,GRanges-method} \alias{seqnames<-,GenomicRanges-method} \alias{ranges,GRanges-method} \alias{ranges<-,GenomicRanges-method} \alias{strand,GRanges-method} \alias{strand<-,GenomicRanges,ANY-method} \alias{elementMetadata<-,GenomicRanges-method} \alias{names,GenomicRanges-method} \alias{names<-,GenomicRanges-method} \alias{seqinfo,GRanges-method} \alias{seqinfo<-,GenomicRanges-method} \alias{score,GenomicRanges-method} \alias{score<-,GenomicRanges-method} % Ranges methods: \alias{start,GenomicRanges-method} \alias{start<-,GenomicRanges-method} \alias{end,GenomicRanges-method} \alias{end<-,GenomicRanges-method} \alias{width,GenomicRanges-method} \alias{width<-,GenomicRanges-method} % Vector methods: \alias{length,GenomicRanges-method} \alias{[,GenomicRanges,ANY-method} \alias{[<-,GenomicRanges,ANY,ANY,ANY-method} \alias{[,List,GenomicRanges-method} \alias{[,list,GenomicRanges-method} \alias{c,GenomicRanges-method} \alias{window,GenomicRanges-method} % $ and $<- methods: \alias{$,GenomicRanges-method} \alias{$<-,GenomicRanges-method} % "show" 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=Rle(), ranges=NULL, strand=NULL, ..., seqlengths=NULL, seqinfo=NULL)}: Creates a GRanges object. \describe{ \item{\code{seqnames}}{ An \link[S4Vectors]{Rle} object, character vector, or factor containing the sequence names. } \item{\code{ranges}}{ An \link[IRanges]{IRanges} object containing the ranges. } \item{\code{strand}}{ \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}}{ An integer vector named with \code{levels(seqnames)} and containing the lengths (or NA) for each level in \code{levels(seqnames)}. } \item{\code{seqinfo}}{ 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()}. } Because of this behavior, \code{GRanges(x)} is equivalent to \code{as(x, "GRanges")}. } } } \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)}. } } 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{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{names(x)}, \code{names(x) <- value}: Get or set the names of the elements. } \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{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, force=FALSE) <- 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.mcols=FALSE)}: Gets a \code{GRanges} with only the range information from \code{x}, unless \code{use.mcols} is \code{TRUE}, in which case the metadata columns are also returned. Those columns will include any "extra column slots" if \code{x} is a specialized \code{GenomicRanges} derivative. } } } \section{Ranges methods}{ In the following code snippets, \code{x} is a GRanges object. \describe{ \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))}. } } } \section{Splitting and Combining}{ In the code snippets below, \code{x} is a GRanges object. \describe{ \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{c(x, ...)}: 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}. } \item{}{ \code{c(x, ..., ignore.mcols=FALSE)} 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{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{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{Other methods}{ \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 \link{GenomicRanges-comparison} for comparing and ordering 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]{findOverlaps-methods} for finding overlapping genomic ranges. \item \link[GenomicRanges]{nearest-methods} 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) ## --------------------------------------------------------------------- ## 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.Rd0000644000175100017510000003347612607265137020670 0ustar00biocbuildbiocbuild\name{GRangesList-class} \docType{class} % Class \alias{class:GRangesList} \alias{GRangesList-class} \alias{GRangesList} % 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,RangedDataList,GRangesList-method} % Subsetting: \alias{[,GRangesList,ANY-method} \alias{[<-,GRangesList,ANY,ANY,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}. } \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{elementLengths(x)}: Get the \code{length} of each of the list elements. } \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, force=FALSE) <- 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. } \item{}{\code{as(from, "GRangesList")}: Creates a GRangesList object from a \link[IRanges]{RangedDataList} object. } } } \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: elementLengths(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.Rd0000644000175100017510000001435112607265137022263 0ustar00biocbuildbiocbuild\name{GenomicRanges-comparison} \alias{GenomicRanges-comparison} \alias{compare} \alias{compare,GenomicRanges,GenomicRanges-method} \alias{duplicated,GenomicRanges-method} \alias{duplicated.GenomicRanges} \alias{match,GenomicRanges,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 ordering the elements in one or more \link{GenomicRanges} objects. } \usage{ ## duplicated() ## ------------ \S4method{duplicated}{GenomicRanges}(x, incomparables=FALSE, fromLast=FALSE, method=c("auto", "quick", "hash")) ## match() ## ------- \S4method{match}{GenomicRanges,GenomicRanges}(x, table, nomatch=NA_integer_, incomparables=NULL, method=c("auto", "quick", "hash"), ignore.strand=FALSE) ## order() and related methods ## ---------------------------- \S4method{order}{GenomicRanges}(..., na.last=TRUE, decreasing=FALSE) \S4method{sort}{GenomicRanges}(x, decreasing=FALSE, ignore.strand=FALSE, by) \S4method{rank}{GenomicRanges}(x, na.last=TRUE, ties.method=c("average", "first", "random", "max", "min")) ## Generalized element-wise (aka "parallel") comparison of 2 GenomicRanges ## objects ## ------------------------------------------------------------------------ \S4method{compare}{GenomicRanges,GenomicRanges}(x, y) } \arguments{ \item{x, table, y}{ \link{GenomicRanges} objects. } \item{incomparables}{ Not supported. } \item{fromLast, method, nomatch}{ See \code{?`\link[IRanges]{Ranges-comparison}`} in the 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{...}{ Additional \link{GenomicRanges} objects used for breaking ties. } \item{na.last}{ Ignored. } \item{decreasing}{ \code{TRUE} or \code{FALSE}. } \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} 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. \code{duplicated()} and \code{unique()} on a \link{GenomicRanges} object are conforming to this. The "natural order" for the elements of a \link{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 \code{reduce} method for \link{GenomicRanges} uses this "natural order" implicitly. Also, 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{order()}, \code{sort()}, and \code{rank()} on a \link{GenomicRanges} object are using this "natural order". Also \code{==}, \code{!=}, \code{<=}, \code{>=}, \code{<} and \code{>} on \link{GenomicRanges} objects are using this "natural order". } \author{H. Pagès} \seealso{ \itemize{ \item The \link{GenomicRanges} class. \item \link[IRanges]{Ranges-comparison} in the IRanges package for comparing and ordering genomic ranges. \item \link[GenomicRanges]{intra-range-methods} and \link[GenomicRanges]{inter-range-methods} for intra and inter range transformations. \item \link[GenomicRanges]{setops-methods} for set operations on \link{GenomicRanges} objects. \item \link[GenomicRanges]{findOverlaps-methods} for finding overlapping genomic ranges. } } \examples{ gr0 <- GRanges( seqnames=Rle(c("chr1", "chr2", "chr1", "chr3"), c(1, 3, 2, 4)), ranges=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. duplicated(), unique() ## --------------------------------------------------------------------- duplicated(gr) unique(gr) ## --------------------------------------------------------------------- ## C. match(), %in% ## --------------------------------------------------------------------- table <- gr[1:7] match(gr, table) match(gr, table, ignore.strand=TRUE) gr \%in\% table ## --------------------------------------------------------------------- ## D. 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) ## --------------------------------------------------------------------- ## E. order() AND RELATED METHODS ## --------------------------------------------------------------------- order(gr) sort(gr) sort(gr, ignore.strand=TRUE) ## 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) ## --------------------------------------------------------------------- ## F. GENERALIZED ELEMENT-WISE COMPARISON OF 2 GenomicRanges OBJECTS ## --------------------------------------------------------------------- gr2 <- GRanges(c(rep("chr1", 12), "chr2"), IRanges(c(1:11, 6:7), width=3)) strand(gr2)[12] <- "+" gr3 <- GRanges("chr1", IRanges(5, 9)) compare(gr2, gr3) rangeComparisonCodeToLetter(compare(gr2, gr3)) } \keyword{methods} GenomicRanges/man/GenomicRangesList-class.Rd0000644000175100017510000000354512607265137022055 0ustar00biocbuildbiocbuild\name{GenomicRangesList-class} \docType{class} % Class: \alias{class:GenomicRangesList} \alias{class:SimpleGenomicRangesList} \alias{GenomicRangesList-class} \alias{SimpleGenomicRangesList-class} % Constructors: \alias{GenomicRangesList} % Coercion \alias{coerce,RangedDataList,GenomicRangesList-method} \alias{coerce,GenomicRangesList,RangedDataList-method} \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. } } } \section{Coercion}{ \describe{ \item{}{ \code{as(from, "GenomicRangesList")}: Supported \code{from} types include: \describe{ \item{RangedDataList}{Each element of \code{from} is coerced to a \code{GenomicRanges}.} } } \item{}{ \code{as(from, "RangedDataList")}: Supported \code{from} types include: \describe{ \item{GenomicRangesList}{Each element of \code{from} is coerced to a \code{RangedData}.} } } } } \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/SummarizedExperiment-class.Rd0000644000175100017510000006352012607265137022660 0ustar00biocbuildbiocbuild\name{SummarizedExperiment-class} \docType{class} % Class \alias{SummarizedExperiment-class} \alias{SummarizedExperiment} \alias{Assays-class} \alias{ShallowData-class} \alias{ShallowSimpleListAssays-class} % Constructor-like function: \alias{SummarizedExperiment} \alias{SummarizedExperiment,missing-method} \alias{SummarizedExperiment,matrix-method} \alias{SummarizedExperiment,list-method} \alias{SummarizedExperiment,SimpleList-method} % Accessor methods: \alias{assays} \alias{assays,SummarizedExperiment-method} \alias{assays<-} \alias{assays<-,SummarizedExperiment,list-method} \alias{assays<-,SummarizedExperiment,SimpleList-method} \alias{assay} \alias{assay,SummarizedExperiment,ANY-method} \alias{assay,SummarizedExperiment,character-method} \alias{assay,SummarizedExperiment,numeric-method} \alias{assay,SummarizedExperiment,missing-method} \alias{assay<-} \alias{assay<-,SummarizedExperiment,character,matrix-method} \alias{assay<-,SummarizedExperiment,numeric,matrix-method} \alias{assay<-,SummarizedExperiment,missing,matrix-method} \alias{assayNames} \alias{assayNames,SummarizedExperiment-method} \alias{assayNames<-} \alias{assayNames<-,SummarizedExperiment,character-method} \alias{rowRanges} \alias{rowRanges,SummarizedExperiment-method} \alias{rowRanges<-} \alias{rowRanges<-,SummarizedExperiment,GenomicRanges-method} \alias{rowRanges<-,SummarizedExperiment,GRangesList-method} \alias{rowData} \alias{rowData<-} \alias{colData} \alias{colData,SummarizedExperiment-method} \alias{colData<-} \alias{colData<-,SummarizedExperiment,DataFrame-method} \alias{exptData} \alias{exptData,SummarizedExperiment-method} \alias{exptData<-} \alias{exptData<-,SummarizedExperiment,SimpleList-method} \alias{exptData<-,SummarizedExperiment,list-method} \alias{dim,SummarizedExperiment-method} \alias{dimnames,SummarizedExperiment-method} \alias{dimnames<-,SummarizedExperiment,NULL-method} \alias{dimnames<-,SummarizedExperiment,list-method} % Subset methods \alias{[,SummarizedExperiment-method} \alias{[,SummarizedExperiment,ANY-method} \alias{[<-,SummarizedExperiment,ANY,ANY,SummarizedExperiment-method} \alias{$,SummarizedExperiment-method} \alias{$<-,SummarizedExperiment,ANY-method} \alias{$<-,SummarizedExperiment-method} \alias{[[,SummarizedExperiment,ANY,missing-method} \alias{[[<-,SummarizedExperiment,ANY,missing,ANY-method} \alias{[[<-,SummarizedExperiment,ANY,missing-method} % Combine methods \alias{cbind,SummarizedExperiment-method} \alias{rbind,SummarizedExperiment-method} % GenomicRanges compatibility methods \alias{compare,ANY,SummarizedExperiment-method} \alias{compare,SummarizedExperiment,ANY-method} \alias{compare,SummarizedExperiment,SummarizedExperiment-method} \alias{countOverlaps,Vector,SummarizedExperiment-method} \alias{countOverlaps,SummarizedExperiment,Vector-method} \alias{countOverlaps,SummarizedExperiment,SummarizedExperiment-method} \alias{coverage,SummarizedExperiment-method} \alias{disjointBins,SummarizedExperiment-method} \alias{distance,ANY,SummarizedExperiment-method} \alias{distance,SummarizedExperiment,ANY-method} \alias{distance,SummarizedExperiment,SummarizedExperiment-method} \alias{distanceToNearest,ANY,SummarizedExperiment-method} \alias{distanceToNearest,SummarizedExperiment,ANY-method} \alias{distanceToNearest,SummarizedExperiment,SummarizedExperiment-method} \alias{duplicated,SummarizedExperiment-method} \alias{elementMetadata,SummarizedExperiment-method} \alias{elementMetadata<-,SummarizedExperiment-method} \alias{end,SummarizedExperiment-method} \alias{end<-,SummarizedExperiment-method} \alias{findOverlaps,Vector,SummarizedExperiment-method} \alias{findOverlaps,SummarizedExperiment,Vector-method} \alias{findOverlaps,SummarizedExperiment,SummarizedExperiment-method} \alias{flank,SummarizedExperiment-method} \alias{follow,ANY,SummarizedExperiment-method} \alias{follow,SummarizedExperiment,ANY-method} \alias{follow,SummarizedExperiment,SummarizedExperiment-method} \alias{granges,SummarizedExperiment-method} \alias{isDisjoint,SummarizedExperiment-method} \alias{mcols,SummarizedExperiment-method} \alias{mcols<-,SummarizedExperiment-method} \alias{narrow,SummarizedExperiment-method} \alias{nearest,ANY,SummarizedExperiment-method} \alias{nearest,SummarizedExperiment,ANY-method} \alias{nearest,SummarizedExperiment,SummarizedExperiment-method} \alias{nearest,SummarizedExperiment,missing-method} \alias{order,SummarizedExperiment-method} \alias{overlapsAny,SummarizedExperiment,SummarizedExperiment-method} \alias{overlapsAny,SummarizedExperiment,Vector-method} \alias{overlapsAny,Vector,SummarizedExperiment-method} \alias{precede,ANY,SummarizedExperiment-method} \alias{precede,SummarizedExperiment,ANY-method} \alias{precede,SummarizedExperiment,SummarizedExperiment-method} \alias{ranges,SummarizedExperiment-method} \alias{ranges<-,SummarizedExperiment-method} \alias{rank,SummarizedExperiment-method} \alias{resize,SummarizedExperiment-method} \alias{restrict,SummarizedExperiment-method} \alias{seqinfo,SummarizedExperiment-method} \alias{seqinfo<-,SummarizedExperiment-method} \alias{seqnames,SummarizedExperiment-method} \alias{shift,SummarizedExperiment-method} \alias{sort,SummarizedExperiment-method} \alias{split,SummarizedExperiment-method} \alias{split,SummarizedExperiment,ANY-method} \alias{start,SummarizedExperiment-method} \alias{start<-,SummarizedExperiment-method} \alias{strand,SummarizedExperiment-method} \alias{strand<-,SummarizedExperiment,ANY-method} \alias{subset,SummarizedExperiment-method} \alias{subsetByOverlaps,SummarizedExperiment,SummarizedExperiment-method} \alias{subsetByOverlaps,SummarizedExperiment,Vector-method} \alias{subsetByOverlaps,Vector,SummarizedExperiment-method} \alias{values,SummarizedExperiment-method} \alias{values<-,SummarizedExperiment-method} \alias{width,SummarizedExperiment-method} \alias{width<-,SummarizedExperiment-method} % show method: \alias{show,SummarizedExperiment-method} % transition to RangedSummarizedExperiment: \alias{coerce,SummarizedExperiment,RangedSummarizedExperiment-method} \alias{updateObject,SummarizedExperiment-method} \alias{coerce,SummarizedExperiment,ExpressionSet-method} \alias{coerce,ExpressionSet,SummarizedExperiment-method} \title{SummarizedExperiment instances} \description{ WARNING: The SummarizedExperiment class described here is deprecated and being replaced with the \link[SummarizedExperiment]{RangedSummarizedExperiment} class defined in the new \pkg{SummarizedExperiment} package. Please make sure to install the \pkg{SummarizedExperiment} package before you attempt to use the \code{SummarizedExperiment()} constructor function. Note that this will return a \link[SummarizedExperiment]{RangedSummarizedExperiment} instance instead of a SummarizedExperiment instance. The SummarizedExperiment class is a matrix-like container where rows represent ranges of interest (as a \code{\linkS4class{GRanges} or \linkS4class{GRangesList}-class}) and columns represent samples (with sample data summarized as a \code{\linkS4class{DataFrame}-class}). A \code{SummarizedExperiment} contains one or more assays, each represented by a matrix-like object of numeric or other mode. } \usage{ ## Constructors SummarizedExperiment(assays, ...) ## Accessors assayNames(x, ...) assayNames(x, ...) <- value assays(x, ..., withDimnames=TRUE) assays(x, ..., withDimnames=TRUE) <- value assay(x, i, ...) assay(x, i, ...) <- value rowRanges(x, ...) rowRanges(x, ...) <- value colData(x, ...) colData(x, ...) <- value exptData(x, ...) exptData(x, ...) <- value \S4method{dim}{SummarizedExperiment}(x) \S4method{dimnames}{SummarizedExperiment}(x) \S4method{dimnames}{SummarizedExperiment,NULL}(x) <- value \S4method{dimnames}{SummarizedExperiment,list}(x) <- value ## colData access \S4method{$}{SummarizedExperiment}(x, name) \S4method{$}{SummarizedExperiment,ANY}(x, name) <- value \S4method{[[}{SummarizedExperiment,ANY,missing}(x, i, j, ...) \S4method{[[}{SummarizedExperiment,ANY,missing,ANY}(x, i, j, ...) <- value ## rowRanges access ## see 'GRanges compatibility', below ## Subsetting \S4method{[}{SummarizedExperiment}(x, i, j, ..., drop=TRUE) \S4method{[}{SummarizedExperiment,ANY,ANY,SummarizedExperiment}(x, i, j) <- value \S4method{subset}{SummarizedExperiment}(x, subset, select, ...) ## Combining \S4method{cbind}{SummarizedExperiment}(..., deparse.level=1) \S4method{rbind}{SummarizedExperiment}(..., deparse.level=1) ## Coercion \S4method{updateObject}{SummarizedExperiment}(object, ..., verbose=FALSE) \S4method{coerce}{ExpressionSet,SummarizedExperiment}(from, to = "SummarizedExperiment", strict = TRUE) \S4method{coerce}{SummarizedExperiment,ExpressionSet}(from, to = "ExpressionSet", strict = TRUE) } \arguments{ \item{assays}{ See \code{?\link[SummarizedExperiment]{RangedSummarizedExperiment}} in the \pkg{SummarizedExperiment} package.} \item{...}{For \code{SummarizedExperiment}, see \code{?\link[SummarizedExperiment]{RangedSummarizedExperiment}} in the \pkg{SummarizedExperiment} package. For \code{assay}, \code{...} may contain \code{withDimnames}, which is forwarded to \code{assays}. For \code{cbind, rbind}, \code{...} contains \code{SummarizedExperiment} objects to be combined. For other accessors, ignored. } \item{verbose}{A \code{logical(1)} indicating whether messages about data coercion during construction should be printed.} \item{x, object}{An instance of \code{SummarizedExperiment}-class.} \item{i, j}{For \code{assay}, \code{assay<-}, \code{i} is a integer or numeric scalar; see \sQuote{Details} for additional constraints. For \code{[,SummarizedExperiment}, \code{[,SummarizedExperiment<-}, \code{i}, \code{j} are instances that can act to subset the underlying \code{rowRanges}, \code{colData}, and \code{matrix} elements of \code{assays}. For \code{[[,SummarizedExperiment}, \code{[[<-,SummarizedExperiment}, \code{i} is a scalar index (e.g., \code{character(1)} or \code{integer(1)}) into a column of \code{colData}. } \item{subset}{An expression which, when evaluated in the context of \code{rowRanges(x)}, is a logical vector indicating elements or rows to keep: missing values are taken as false.} \item{select}{An expression which, when evaluated in the context of \code{colData(x)}, is a logical vector indicating elements or rows to keep: missing values are taken as false.} \item{name}{A symbol representing the name of a column of \code{colData}.} \item{withDimnames}{A \code{logical(1)}, indicating whether dimnames should be applied to extracted assay elements. Setting \code{withDimnames=FALSE} increases the speed and memory efficiency with which assays are extracted. \code{withDimnames=TRUE} in the getter \code{assays<-} allows efficient complex assignments (e.g., updating names of assays, \code{names(assays(x, withDimnames=FALSE)) = ...} is more efficient than \code{names(assays(x)) = ...}); it does not influence actual assignment of dimnames to assays.} \item{drop}{A \code{logical(1)}, ignored by these methods.} \item{value}{An instance of a class specified in the S4 method signature or as outlined in \sQuote{Details}.} \item{deparse.level}{See \code{?base::\link[base]{cbind}} for a description of this argument.} \item{from}{the object to be coerced} \item{to}{the class to coerce to} \item{strict}{logical flag. If 'TRUE', the returned object must be strictly from the target class.} } \details{ The \code{SummarizedExperiment} class is meant for numeric and other data types derived from a sequencing experiment. The structure is rectangular like a \code{matrix}, but with additional annotations on the rows and columns, and with the possibility to manage several assays simultaneously. The rows of a \code{SummarizedExperiment} instance represent ranges (in genomic coordinates) of interest. The ranges of interest are described by a \code{\linkS4class{GRanges}-class} or a \code{\linkS4class{GRangesList}-class} instance, accessible using the \code{rowRanges} function, described below. The \code{GRanges} and \code{GRangesList} classes contains sequence (e.g., chromosome) name, genomic coordinates, and strand information. Each range can be annotated with additional data; this data might be used to describe the range or to summarize results (e.g., statistics of differential abundance) relevant to the range. Rows may or may not have row names; they often will not. Each column of a \code{SummarizedExperiment} instance represents a sample. Information about the samples are stored in a \code{\linkS4class{DataFrame}-class}, accessible using the function \code{colData}, described below. The \code{DataFrame} must have as many rows as there are columns in the \code{SummarizedExperiment}, with each row of the \code{DataFrame} providing information on the sample in the corresponding column of the \code{SummarizedExperiment}. Columns of the \code{DataFrame} represent different sample attributes, e.g., tissue of origin, etc. Columns of the \code{DataFrame} can themselves be annotated (via the \code{\link{mcols}} function). Column names typically provide a short identifier unique to each sample. A \code{SummarizedExperiment} can also contain information about the overall experiment, for instance the lab in which it was conducted, the publications with which it is associated, etc. This information is stored as a \code{\linkS4class{SimpleList}-class}, accessible using the \code{exptData} function. The form of the data associated with the experiment is left to the discretion of the user. The \code{SummarizedExperiment} is appropriate for matrix-like data. The data are accessed using the \code{assays} function, described below. This returns a \code{SimpleList}-class instance. Each element of the list must itself be a matrix (of any mode) and must have dimensions that are the same as the dimensions of the \code{SummarizedExperiment} in which they are stored. Row and column names of each matrix must either be \code{NULL} or match those of the \code{SummarizedExperiment} during construction. It is convenient for the elements of \code{SimpleList} of assays to be named. The \code{SummarizedExperiment} class has the following slots; this detail of class structure is not relevant to the user. \describe{ \item{\code{exptData}}{A \link{SimpleList}-class instance containing information about the overall experiment.} \item{\code{rowData}}{A \link{GRanges}-class instance defining the ranges of interest and associated metadata. WARNING: The accessor for this slot is \code{rowRanges}, not \code{rowData}!} \item{\code{colData}}{A \link{DataFrame}-class instance describing the samples and associated metadata.} \item{\code{assays}}{A \link{SimpleList}-class instance, each element of which is a matrix summarizing data associated with the corresponding range and sample.} } } \section{Constructor}{ Instances are constructed using the \code{SummarizedExperiment} function with arguments outlined above. } \section{Coercion}{ Package version 1.9.59 introduced a new way of representing \sQuote{assays}. If you have a serialized instance \code{x} of a \code{SummarizedExperiment} (e.g., from using the \code{save} function with a version of GenomicRanges prior to 1.9.59), it should be updated by invoking \code{x <- updateObject(x)}. \describe{ \item{ \code{as(from, "SummarizedExperiment")}:}{Creates a \code{SummarizedExperiment} object from a \code{ExpressionSet} object. } } \describe{ \item{ \code{as(from, "ExpressionSet")}:}{Creates a \code{ExpressionSet} object from a \code{SummarizedExperiment} object. } } The following data mappings are used for coercion between \code{ExpressionSet} and \code{SummarizedExperiment}. \describe{ \item{\code{assayData}}{\code{assays}} \item{\code{featureData}}{\code{rowData}} \item{\code{phenoData}}{\code{colData}} \item{\code{experimentData}, \code{annotation}, \code{protocolData}}{\code{colData}} } If the \code{SummarizedExperiment} being coerced uses \code{GRanges} to store it's range data that data will be included in the \code{featureData} of the \code{ExpressionSet}. Because \code{ExpressionSet} objects require an assay named \sQuote{exprs} if the \code{SummarizedExperiment} object being coerced does not have an assay named \sQuote{exprs} the first assay will be renamed and a warning will be issued. } \section{Accessors}{ In the following code snippets, \code{x} is a \code{SummarizedExperiment} instance. \describe{ \item{\code{assays(x)}, \code{assays(x) <- value}:}{Get or set the assays. \code{value} is a \code{list} or \code{SimpleList}, each element of which is a matrix with the same dimensions as \code{x}.} \item{\code{assay(x, i)}, \code{assay(x, i) <- value}:}{A convenient alternative (to \code{assays(x)[[i]]}, \code{assays(x)[[i]] <- value}) to get or set the \code{i}th (default first) assay element. \code{value} must be a matrix of the same dimension as \code{x}, and with dimension names \code{NULL} or consistent with those of \code{x}.} \item{\code{assayNames(x)}, \code{assayNames(x) <- value}:}{Get or set the names of \code{assay()} elements.} \item{\code{rowRanges(x)}, \code{rowRanges(x) <- value}:}{Get or set the row data. \code{value} is a \code{GenomicRanges} instance. Row names of \code{value} must be NULL or consistent with the existing row names of \code{x}.} \item{\code{colData(x)}, \code{colData(x) <- value}:}{Get or set the column data. \code{value} is a \code{DataFrame} instance. Row names of \code{value} must be NULL or consistent with the existing column names of \code{x}.} \item{\code{exptData(x)}, \code{exptData(x) <- value}:}{Get or set the experiment data. \code{value} is a \code{list} or \code{SimpleList} instance, with arbitrary content.} \item{\code{dim(x)}:}{Get the dimensions (ranges x samples) of the \code{SummarizedExperiment}.} \item{\code{dimnames(x)}, \code{dimnames(x) <- value}:}{Get or set the dimension names. \code{value} is usually a list of length 2, containing elements that are either \code{NULL} or vectors of appropriate length for the corresponding dimension. \code{value} can be \code{NULL}, which removes dimension names. This method implies that \code{rownames}, \code{rownames<-}, \code{colnames}, and \code{colnames<-} are all available.} } } \section{GRanges compatibility (rowRanges access)}{ Many \code{\linkS4class{GRanges}-class} and \code{\linkS4class{GRangesList}-class} operations are supported on \sQuote{SummarizedExperiment} and derived instances, using \code{rowRanges}. Supported operations include: \code{\link{compare}}, \code{\link{countOverlaps}}, \code{\link{coverage}}, \code{\link{disjointBins}}, \code{\link{distance}}, \code{\link{distanceToNearest}}, \code{\link{duplicated}}, \code{\link{end}}, \code{\link{end<-}}, \code{\link{findOverlaps}}, \code{\link{flank}}, \code{\link{follow}}, \code{\link{granges}}, \code{\link{isDisjoint}}, \code{\link{match}}, \code{\link{mcols}}, \code{\link{mcols<-}}, \code{\link{narrow}}, \code{\link{nearest}}, \code{\link{order}}, \code{\link{overlapsAny}}, \code{\link{precede}}, \code{\link{ranges}}, \code{\link{ranges<-}}, \code{\link{rank}}, \code{\link{resize}}, \code{\link{restrict}}, \code{\link{seqinfo}}, \code{\link{seqinfo<-}}, \code{\link{seqnames}}, \code{\link{shift}}, \code{\link{sort}}, \code{split}, \code{relistToClass}, \code{\link{start}}, \code{\link{start<-}}, \code{\link{strand}}, \code{\link{strand<-}}, \code{\link{subsetByOverlaps}}, \code{\link{width}}, \code{\link{width<-}}. Not all \code{\link{GRanges}-class} operations are supported, because they do not make sense for \sQuote{SummarizedExperiment} objects (e.g., length, name, as.data.frame, c, splitAsList), involve non-trivial combination or splitting of rows (e.g., disjoin, gaps, reduce, unique), or have not yet been implemented (Ops, map, window, window<-). } \section{Subsetting}{ In the code snippets below, \code{x} is a \code{SummarizedExperiment} instance. \describe{ \item{\code{x[i,j]}, \code{x[i,j] <- value}:}{Create or replace a subset of \code{x}. \code{i}, \code{j} can be \code{numeric}, \code{logical}, \code{character}, or \code{missing}. \code{value} must be a \code{SummarizedExperiment} instance with dimensions, dimension names, and assay elements consistent with the subset \code{x[i,j]} being replaced.} \item{\code{subset(x, subset, select)}:}{Create a subset of \code{x} using an expression \code{subset} referring to columns of \code{rowRanges(x)} (including \sQuote{seqnames}, \sQuote{start}, \sQuote{end}, \sQuote{width}, \sQuote{strand}, and \code{names(mcols(x))}) and / or \code{select} referring to column names of \code{colData(x)}.} } Additional subsetting accessors provide convenient access to \code{colData} columns \describe{ \item{\code{x$name}, \code{x$name <- value}}{Access or replace column \code{name} in \code{x}.} \item{\code{x[[i, ...]]}, \code{x[[i, ...]] <- value}}{Access or replace column \code{i} in \code{x}.} } } \section{Combining}{ In the code snippets below, \code{...} are \code{SummarizedExperiment} instances to be combined. \describe{ \item{\code{cbind(...)}, \code{rbind(...)}:}{ \code{cbind} combines objects with identical ranges (\code{rowRanges}) but different samples (columns in \code{assays}). The colnames in \code{colData} must match or an error is thrown. Duplicate columns of \code{mcols(rowRanges(SummarizedExperiment))} must contain the same data. Data in \code{assays} are combined by name matching; if all names are NULL matching is by position. A mixture of names and NULL throws an error. \code{rbind} combines objects with different ranges (\code{rowRanges}) and the same subjects (columns in \code{assays}). Duplicate columns of \code{colData} must contain the same data. \code{exptData} from all objects are combined into a \code{SimpleList} with no name checking. } } } \section{Implementation and Extension}{ This section contains advanced material meant for package developers. \code{SummarizedExperiment} is implemented as an S4 class, and can be extended in the usual way, using \code{contains="SummarizedExperiment"} in the new class definition. In addition, the representation of the \code{assays} slot of \code{SummarizedExperiment} is as a virtual class \code{Assays}. This allows derived classes (\code{contains="Assays"}) to easily implement alternative requirements for the assays, e.g., backed by file-based storage like NetCDF or the \code{ff} package, while re-using the existing \code{SummarizedExperiment} class without modification. The requirements on \code{Assays} are list-like semantics (e.g., \code{sapply}, \code{[[} subsetting, \code{names}) with elements having matrix- or array-like semantics (e.g., \code{dim}, \code{dimnames}). These requirements can be made more precise if developers express interest. The current \code{assays} slot is implemented as a reference class that has copy-on-change semantics. This means that modifying non-assay slots does not copy the (large) assay data, and at the same time the user is not surprised by reference-based semantics. Updates to non-assay slots are very fast; updating the assays slot itself can be 5x or more faster than with an S4 instance in the slot. One useful technique when working with \code{assay} or \code{assays} function is use of the \code{withDimnames=FALSE} argument, which benefits speed and memory use by not copying dimnames from the row- and colData elements to each assay. In a little more detail, a small reference class hierarchy (not exported from the GenomicRanges name space) defines a reference class \code{ShallowData} with a single field \code{data} of type \code{ANY}, and a derived class \code{ShallowSimpleListAssays} that specializes the type of \code{data} as \code{SimpleList}, and \code{contains=c("ShallowData", "Assays")}. The assays slot contains an instance of \code{ShallowSimpleListAssays}. Invoking \code{assays()} on a \code{SummarizedExperiment} re-dispatches from the \code{assays} slot to retrieve the \code{SimpleList} from the field of the reference class. This was achieved by implementing a generic (not exported) \code{value(x, name, ...)}, with a method implemented on \code{SummarizedExperiment} that retrieves a slot when \code{name} is a slot containing an S4 object in \code{x}, and a field when \code{name} is a slot containing a \code{ShallowData} instance in \code{x}. Copy-on-change semantics is maintained by implementing the \code{clone} method (\code{clone} methods are supposed to do a deep copy, \code{update} methods a shallow copy; the \code{clone} generic is introduced, and not exported, in the GenomicRanges package). The \sQuote{getter} and \sQuote{setter} code for methods implemented on \code{SummarizedExperiment} use \code{value} for slot access, and \code{clone} for replacement. This makes it easy to implement \code{ShallowData} instances for other slots if the need arises. } \author{Martin Morgan, \url{mtmorgan@fhcrc.org}} \seealso{ \link[SummarizedExperiment]{RangedSummarizedExperiment} in the new \pkg{SummarizedExperiment} package for the replacement of the SummarizedExperiment class. } \examples{ ## WARNING: The SummarizedExperiment class is deprecated and being ## replaced with the RangedSummarizedExperiment class defined in the ## new SummarizedExperiment package. See ?RangedSummarizedExperiment ## in the SummarizedExperiment package for examples of how to create ## and manipulate RangedSummarizedExperiment objects. } GenomicRanges/man/absoluteRanges.Rd0000644000175100017510000001116712607265137020352 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{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, force=TRUE) <- 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.Rd0000644000175100017510000003356012607265137017561 0ustar00biocbuildbiocbuild\name{Constraints} \alias{Constraints} \alias{class:Constraint} \alias{Constraint-class} \alias{Constraint} \alias{class:ConstraintORNULL} \alias{ConstraintORNULL-class} \alias{ConstraintORNULL} \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 ConstraintORNULL. 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, "ConstraintORNULL")) # 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.Rd0000644000175100017510000001034512607265137020625 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.Rd0000644000175100017510000002446212607265137021473 0ustar00biocbuildbiocbuild\name{findOverlaps-methods} \alias{findOverlaps-methods} \alias{findOverlaps} \alias{findOverlaps,GNCList,GenomicRanges-method} \alias{findOverlaps,GenomicRanges,GNCList-method} \alias{findOverlaps,GenomicRanges,GenomicRanges-method} \alias{findOverlaps,GenomicRanges,GIntervalTree-method} \alias{findOverlaps,GRangesList,GenomicRanges-method} \alias{findOverlaps,GenomicRanges,GRangesList-method} \alias{findOverlaps,GRangesList,GRangesList-method} \alias{findOverlaps,RangesList,GenomicRanges-method} \alias{findOverlaps,RangesList,GRangesList-method} \alias{findOverlaps,GenomicRanges,RangesList-method} \alias{findOverlaps,GRangesList,RangesList-method} \alias{findOverlaps,RangedData,GenomicRanges-method} \alias{findOverlaps,RangedData,GRangesList-method} \alias{findOverlaps,GenomicRanges,RangedData-method} \alias{findOverlaps,GRangesList,RangedData-method} \alias{countOverlaps} \alias{countOverlaps,GNCList,GenomicRanges-method} \alias{countOverlaps,GenomicRanges,GNCList-method} \alias{countOverlaps,GenomicRanges,Vector-method} \alias{countOverlaps,Vector,GenomicRanges-method} \alias{countOverlaps,GenomicRanges,GenomicRanges-method} \alias{countOverlaps,GenomicRanges,GIntervalTree-method} \alias{countOverlaps,GRangesList,Vector-method} \alias{countOverlaps,Vector,GRangesList-method} \alias{countOverlaps,GRangesList,GRangesList-method} \alias{countOverlaps,GRanges,GRangesList-method} \alias{countOverlaps,GRangesList,GRanges-method} \alias{overlapsAny} \alias{overlapsAny,GenomicRanges,GenomicRanges-method} \alias{overlapsAny,GRangesList,GenomicRanges-method} \alias{overlapsAny,GenomicRanges,GRangesList-method} \alias{overlapsAny,GRangesList,GRangesList-method} \alias{overlapsAny,RangesList,GenomicRanges-method} \alias{overlapsAny,RangesList,GRangesList-method} \alias{overlapsAny,GenomicRanges,RangesList-method} \alias{overlapsAny,GRangesList,RangesList-method} \alias{overlapsAny,RangedData,GenomicRanges-method} \alias{overlapsAny,RangedData,GRangesList-method} \alias{overlapsAny,GenomicRanges,RangedData-method} \alias{overlapsAny,GRangesList,RangedData-method} \alias{subsetByOverlaps} \alias{subsetByOverlaps,GenomicRanges,GenomicRanges-method} \alias{subsetByOverlaps,GRangesList,GenomicRanges-method} \alias{subsetByOverlaps,GenomicRanges,GRangesList-method} \alias{subsetByOverlaps,GRangesList,GRangesList-method} \alias{subsetByOverlaps,RangesList,GenomicRanges-method} \alias{subsetByOverlaps,RangesList,GRangesList-method} \alias{subsetByOverlaps,GenomicRanges,RangesList-method} \alias{subsetByOverlaps,GRangesList,RangesList-method} \alias{subsetByOverlaps,RangedData,GenomicRanges-method} \alias{subsetByOverlaps,RangedData,GRangesList-method} \alias{subsetByOverlaps,GenomicRanges,RangedData-method} \alias{subsetByOverlaps,GRangesList,RangedData-method} \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} or \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. } \usage{ \S4method{findOverlaps}{GenomicRanges,GenomicRanges}(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), select=c("all", "first", "last", "arbitrary"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) \S4method{countOverlaps}{GenomicRanges,GenomicRanges}(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) \S4method{overlapsAny}{GenomicRanges,GenomicRanges}(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) \S4method{subsetByOverlaps}{GenomicRanges,GenomicRanges}(query, subject, maxgap=0L, minoverlap=1L, type=c("any", "start", "end", "within", "equal"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) } \arguments{ \item{query, subject}{ A \link{GRanges} or \link{GRangesList} object. \link[IRanges]{RangesList} and \link[IRanges]{RangedData} are also accepted for one of \code{query} or \code{subject}. } \item{maxgap, minoverlap, type, algorithm}{ 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. Strand is taken as \code{"*"} for \code{RangedData} and \code{RangesList}. 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. For \code{overlapsAny} a logical vector of length equal to the number of ranges in \code{query} indicating those that overlap any of the ranges in \code{subject}. For \code{subsetByOverlaps} an object of the same class as \code{query} containing the subset that overlapped at least one entity in \code{subject}. For \code{RangedData} and \code{RangesList}, with the exception of \code{subsetByOverlaps}, the results align to the unlisted form of the object. This turns out to be fairly convenient for \code{RangedData} (not so much for \code{RangesList}, but something has to give). } \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/genomicvars.Rd0000644000175100017510000002020712607265137017704 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) } \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)}). } } \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}: the \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) } \keyword{manip} GenomicRanges/man/inter-range-methods.Rd0000644000175100017510000002133012607265137021241 0ustar00biocbuildbiocbuild\name{inter-range-methods} \alias{inter-range-methods} \alias{range} \alias{range,GenomicRanges-method} \alias{range,GRangesList-method} \alias{reduce} \alias{reduce,GenomicRanges-method} \alias{reduce,GRangesList-method} \alias{gaps} \alias{gaps,GenomicRanges-method} \alias{disjoin} \alias{disjoin,GenomicRanges-method} \alias{disjoin,GRangesList-method} \alias{isDisjoint} \alias{isDisjoint,GenomicRanges-method} \alias{isDisjoint,GRangesList-method} \alias{disjointBins} \alias{disjointBins,GenomicRanges-method} \title{Inter range transformations of a GenomicRanges or GRangesList object} \description{ See \code{?`\link[IRanges]{intra-range-methods}`} and \code{?`\link[IRanges]{inter-range-methods}`} in the IRanges package for a quick introduction to intra range and inter range transformations. This man page documents 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). See \code{?`\link[GenomicRanges]{intra-range-methods}`} for intra range transformations of a GenomicRanges object. } \usage{ \S4method{range}{GenomicRanges}(x, ..., ignore.strand=FALSE, na.rm=FALSE) \S4method{range}{GRangesList}(x, ..., 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.inframe.attrib=FALSE, ignore.strand=FALSE) \S4method{gaps}{GenomicRanges}(x, start=1L, end=seqlengths(x)) \S4method{disjoin}{GenomicRanges}(x, ignore.strand=FALSE) \S4method{disjoin}{GRangesList}(x, ignore.strand=FALSE) \S4method{isDisjoint}{GenomicRanges}(x, ignore.strand=FALSE) \S4method{isDisjoint}{GRangesList}(x, ignore.strand=FALSE) \S4method{disjointBins}{GenomicRanges}(x, ignore.strand=FALSE) } \arguments{ \item{x}{A \link{GenomicRanges} object.} \item{drop.empty.ranges, min.gapwidth, with.revmap, with.inframe.attrib, start, end}{ See \code{?`\link[IRanges]{inter-range-methods}`} in the 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. \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 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 IRanges package. \item The \link[IRanges]{inter-range-methods} man page in the IRanges package. \item \link{GenomicRanges-comparison} for comparing and ordering genomic ranges. } } \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) ## On a GRangesList object: range(grl) range(grl, 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, elementLengths(revmap)) reordered_gr <- gr[unlist(revmap)] codes <- compare(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(compare(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, elementLengths(revmap)) reordered_biggr <- biggr[unlist(revmap)] codes <- compare(expanded_biggr2, reordered_biggr) alphacodes <- rangeComparisonCodeToLetter(compare(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) isDisjoint(gr) stopifnot(isDisjoint(disjoin(gr))) disjointBins(gr) stopifnot(all(sapply(split(gr, disjointBins(gr)), isDisjoint))) } \keyword{utilities} GenomicRanges/man/intra-range-methods.Rd0000644000175100017510000002024312607265137021237 0ustar00biocbuildbiocbuild\name{intra-range-methods} \alias{intra-range-methods} \alias{shift} \alias{shift,GenomicRanges-method} \alias{shift,GRangesList-method} \alias{narrow} \alias{narrow,GenomicRanges-method} \alias{narrow,GRangesList-method} \alias{resize} \alias{resize,GenomicRanges-method} \alias{resize,GRangesList-method} \alias{flank} \alias{flank,GenomicRanges-method} \alias{flank,GRangesList-method} \alias{promoters} \alias{promoters,GenomicRanges-method} \alias{promoters,GRangesList-method} \alias{restrict} \alias{restrict,GenomicRanges-method} \alias{restrict,GRangesList-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 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 intra range and inter range transformations. 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 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{narrow}{GenomicRanges}(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{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{promoters}{GenomicRanges}(x, upstream=2000, downstream=200, ...) \S4method{promoters}{GRangesList}(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{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. } } \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.Rd0000644000175100017510000002104312607265137022143 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 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, "Most Conserved") df <- getTable(query) ## A common pitfall is to forget that the UCSC Table Browser uses the ## "0-based start" convention: gr0 <- makeGRangesFromDataFrame(df, keep.extra.columns=TRUE) head(gr0) min(start(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, starts.in.df.are.0based=TRUE) head(gr1) } } \keyword{manip} GenomicRanges/man/makeSummarizedExperimentFromExpressionSet.Rd0000644000175100017510000000133012607265137025762 0ustar00biocbuildbiocbuild\name{makeSummarizedExperimentFromExpressionSet} \alias{makeSummarizedExperimentFromExpressionSet} \title{Make a SummarizedExperiment object from an ExpressionSet} \description{ WARNING: The SummarizedExperiment class is deprecated and being replaced with the \link[SummarizedExperiment]{RangedSummarizedExperiment} class defined in the new \pkg{SummarizedExperiment} package. Please make sure to install and load the \pkg{SummarizedExperiment} package where the \code{makeSummarizedExperimentFromExpressionSet} function is now defined and documented. Note that the function now returns a \link[SummarizedExperiment]{RangedSummarizedExperiment} instance instead of a \link{SummarizedExperiment} instance. } GenomicRanges/man/mapCoords-methods.Rd0000644000175100017510000001141512607265137020760 0ustar00biocbuildbiocbuild\name{mapCoords-methods} \alias{mapCoords} \alias{mapCoords-methods} \alias{mapCoords,GenomicRanges,GRangesList-method} \alias{mapCoords,GenomicRanges,GenomicRanges-method} \alias{pmapCoords} \alias{pmapCoords,GenomicRanges,GRangesList-method} \title{Mapping ranges between sequences} \description{ These functions are defunct. Use \code{\link[GenomicFeatures]{mapToTranscripts}} from the \pkg{GenomicFeatures} package or \code{\link[GenomicAlignments]{mapToAlignments}} from the \pkg{GenomicAlignments} package instead. A method for translating a set of input ranges through a \link{GRangesList} object. Returns a \linkS4class{GenomicRanges} object. The generics for \code{mapCoords} and \code{pmapCoords} are defined in the \pkg{IRanges} package. A method for translating a set of input ranges through a \link[GenomicAlignments]{GAlignments} object is defined and in the \pkg{GenomicAlignments} package. } \usage{ \S4method{mapCoords}{GenomicRanges,GRangesList}(from, to, ..., ignore.strand = TRUE, elt.hits = FALSE) \S4method{pmapCoords}{GenomicRanges,GRangesList}(from, to, ..., ignore.strand = TRUE, elt.hits = FALSE) } \arguments{ \item{from}{The input ranges to map, usually a \code{\linkS4class{GRanges}}.} \item{to}{The alignment between the sequences in \code{from} and the sequences in the result, usually a \code{\linkS4class{GRangesList}}.} \item{ignore.strand}{\code{logical}; When TRUE strand is ignored in overlap operations.} \item{elt.hits}{\code{logical}; When TRUE, the output includes a metadata column, eltHits, with indices of the inner list elements of \code{to} hit by \code{from}. Useful for identifying elements of \code{to} hit by \code{from}. See examples.} \item{\dots}{Arguments passed to other methods. Currently not used.} } \value{ A \code{GRanges} object of mapped coordinates with matching data as metadata columns \code{fromHits} and \code{toHits}. The ranges in the output \code{GRanges} are position relative to the outer list element of \code{to}; all individual list elements are concatenated and counting starts at the 5' or 3' end depending on strand. Matching data are the result of calling \code{findOverlaps} with type `within` on ranges in \code{from} (the query) and the ranges in \code{to} (the subject). In the case of \code{mapCoords} matching can be many-to-one or one-to-many; one row is reported for each match. For \code{pmapCoords} matching is one-to-one as the i-th element in \code{from} is only mapped to the i-th element in \code{to}. When \code{elt.hits} is TRUE, the \code{eltHits} metadata column includes the index of inner list elements in \code{to} hit by \code{from}. In some applications it may be useful to identify the exact list element that was overlapped. These elements can be extracted with the combination of \code{toHits} (outer list index) and \code{eltHits} (inner list index). } \details{ DEFUNCT! Use \code{\link[GenomicFeatures]{mapToTranscripts}} from the \pkg{GenomicFeatures} package or \code{\link[GenomicAlignments]{mapToAlignments}} from the \pkg{GenomicAlignments} package instead. Each element in \code{to} is taken to represent an alignment of a sequence on a genome. The typical case is a set of transcript models, as might be obtained via \code{GenomicFeatures::exonsBy}. Each outer list element of the GRangesList represents a transcript while each each individual element is an exon in the transcript. \code{mapCoords} and \code{pmapCoords} translate the ranges in \code{from} relative to the transcript start (i.e., start of all ranges in \code{to}). The widths of the individual elements (exons in this example) are concatenated and counting starts at the 5' or 3' end depending on strand. Translated coordinates are only reported for ranges in \code{from} that fall completely `within` ranges in \code{to}. The transcript-centric coordinates are are useful, for example, when predicting coding consequences of changes to the genomic sequence. \code{mapCoords} maps the i-th element in \code{from} to each element in \code{to} returning in a many-to-many mapping. In contrast, \code{pmapCoords} treats the two inputs as parallel vectors and maps the i-th element of \code{from} to the i-th element of \code{to} returning a maximum of one result per input element. } \seealso{ \itemize{ \item{The generic \link[IRanges]{mapCoords-methods} in the IRanges package.} \item{Additional methods in the GenomicAlignments package \link[GenomicAlignments]{mapCoords-methods}.} } } \examples{ ## DEFUNCT! See ?mapToTranscripts in the GenomicFeatures package and ## ?mapToAlignments in the GenomicAlignments package. } \author{M. Lawrence and V. Obenchain \url{vobencha@fhcrc.org}} GenomicRanges/man/nearest-methods.Rd0000644000175100017510000002277212607265137020502 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("arbitrary", "all"), ignore.strand=FALSE) \S4method{precede}{GenomicRanges,missing}(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) \S4method{follow}{GenomicRanges,GenomicRanges}(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) \S4method{follow}{GenomicRanges,missing}(x, subject, select=c("arbitrary", "all"), ignore.strand=FALSE) \S4method{nearest}{GenomicRanges,GenomicRanges}(x, subject, select=c("arbitrary", "all"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) \S4method{nearest}{GenomicRanges,missing}(x, subject, select=c("arbitrary", "all"), algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE) \S4method{distanceToNearest}{GenomicRanges,GenomicRanges}(x, subject, algorithm=c("nclist", "intervaltree"), ignore.strand=FALSE, ...) \S4method{distanceToNearest}{GenomicRanges,missing}(x, subject, algorithm=c("nclist", "intervaltree"), 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}. If \code{x} does not have a match in \code{subject} the \code{x} is not included in the \link[S4Vectors]{Hits} object. } \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{algorithm}{ This argument is passed to \code{\link{findOverlaps}}, which \code{nearest} and \code{distanceToNearest} use internally. See \code{?\link{findOverlaps}} for more information. Note that it will be removed in BioC 3.3 so please don't use it unless you have a good reason to do so (e.g. troubleshooting). } \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: }{ The relevant orientation for \code{precede} and \code{follow} 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. A range with strand \code{*} can be compared to ranges on either the \code{+} or \code{-} strand. Below we outline the priority when ranges on multiple strands are compared. When \code{ignore.strand=TRUE} all ranges are treated as if on the \code{+} strand. \itemize{ \item{}{x on + strand can match to ranges on both + and * strands. In the case of a tie the first range by order is chosen. } \item{}{x on - strand can match to ranges on both - and * strands. In the case of a tie the first range by order is chosen. } \item{}{x on * strand can match to ranges on any of +, - or * strands. In the case of a tie the first range by order is chosen. } } } \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 IRanges package. \item \link[GenomicRanges]{findOverlaps-methods} for finding just the overlapping ranges. \item The \link[GenomicFeatures]{nearest-methods} man page in the 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.Rd0000644000175100017510000000205612607265137017006 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/range-squeezers.Rd0000644000175100017510000000573212607265137020515 0ustar00biocbuildbiocbuild\name{range-squeezers} \alias{range-squeezers} \alias{granges} \alias{grglist} \alias{rglist} \title{Squeeze the ranges out of a range-based object} \description{ S4 generic functions for squeezing the ranges out of a range-based object. \code{granges} returns them as a \link{GRanges} object, \code{grglist} as a \link{GRangesList} object, and \code{rglist} as a \link[IRanges]{RangesList} object. } \usage{ granges(x, use.mcols=FALSE, ...) grglist(x, use.mcols=FALSE, ...) rglist(x, use.mcols=FALSE, ...) } \arguments{ \item{x}{ A range-based object e.g. a \link{SummarizedExperiment}, \link[GenomicAlignments]{GAlignments}, \link[GenomicAlignments]{GAlignmentPairs}, or \link[GenomicAlignments]{GAlignmentsList} object. } \item{use.mcols}{ \code{TRUE} or \code{FALSE} (the default). Whether the metadata columns on \code{x} (accessible with \code{mcols(x)}) should be propagated to the returned object or not. } \item{...}{ Additional arguments, for use in specific methods. } } \details{ The \pkg{GenomicRanges} and \pkg{GenomicAlignments} packages define and document methods for various types of range-based objects (e.g. for \link{SummarizedExperiment}, \link[GenomicAlignments]{GAlignments}, \link[GenomicAlignments]{GAlignmentPairs}, and \link[GenomicAlignments]{GAlignmentsList} objects). Other Bioconductor packages might as well. Note that these functions can be seen as a specific kind of \emph{object getters} as well as functions performing coercion. For some objects (e.g. \link[GenomicAlignments]{GAlignments}), \code{as(x, "GRanges")}, \code{as(x, "GRangesList")}, and \code{as(x, "RangesList")}, are equivalent to \code{granges(x, use.mcols=TRUE)}, \code{grglist(x, use.mcols=TRUE)}, and \code{rglist(x, use.mcols=TRUE)}, respectively. } \value{ A \link{GRanges} object for \code{granges}. A \link{GRangesList} object for \code{grglist}. A \link[IRanges]{RangesList} object for \code{rglist}. 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{x} has names on it, they're propagated to the returned object. If \code{use.mcols} is TRUE and \code{x} has metadata columns on it (accessible with \code{mcols(x)}), they're propagated to the returned object. } \author{H. Pagès} \seealso{ \itemize{ \item \link{GRanges} and \link{GRangesList} objects. \item \link[IRanges]{RangesList} objects in the \pkg{IRanges} package. \item \link{SummarizedExperiment} objects. \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 some ## examples. } \keyword{methods} GenomicRanges/man/setops-methods.Rd0000644000175100017510000001647012607265137020354 0ustar00biocbuildbiocbuild\name{setops-methods} \alias{setops-methods} \alias{union,GRanges,GRanges-method} \alias{intersect,GRanges,GRanges-method} \alias{setdiff,GRanges,GRanges-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{pintersect,GRangesList,GRangesList-method} \alias{psetdiff} \alias{psetdiff,GRanges,GRanges-method} \alias{psetdiff,GRanges,GRangesList-method} \alias{psetdiff,GRangesList,GRangesList-method} \alias{pgap} \alias{pgap,GRanges,GRanges-method} \title{Set operations on GRanges and GRangesList objects} \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{ ## Set operations \S4method{union}{GRanges,GRanges}(x, y, ignore.strand=FALSE, ...) \S4method{intersect}{GRanges,GRanges}(x, y, ignore.strand=FALSE, ...) \S4method{setdiff}{GRanges,GRanges}(x, y, ignore.strand=FALSE, ...) ## 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}, \code{setdiff}, \code{pgap}: \code{x} and \code{y} must both be \link{GRanges} objects. For \code{punion}: one of \code{x} or \code{y} must be a \link{GRanges} object, the other one can be a \link{GRanges} or \link{GRangesList} object. For \code{pintersect}: \code{x} and \code{y} can be any combination of \link{GRanges} and/or \link{GRangesList} objects. For \code{psetdiff}: \code{x} and \code{y} can be any combination of \link{GRanges} and/or \link{GRangesList} objects, with the exception that if \code{x} is a \link{GRangesList} object then \code{y} must be a \link{GRangesList} too. In addition, for the "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. } \item{...}{ Further arguments to be passed to or from other methods. } } \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}, \code{setdiff}, and \code{pgap}: a \link{GRanges} object. 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. } \author{P. Aboyoun and H. Pagès} \seealso{ \link[IRanges]{setops-methods}, \link{GRanges-class}, \link{GRangesList-class}, \link{findOverlaps-methods} } \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) ## --------------------------------------------------------------------- ## 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("-", "*", "-")))) ## GRangesList object 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) ## 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) ## Parallel set difference of two GRangesList objects psetdiff(grlist, shift(grlist, 3)) } \keyword{methods} \keyword{utilities} GenomicRanges/man/strand-utils.Rd0000644000175100017510000000556212607265137020027 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,DataTable-method} \alias{strand<-,DataTable,ANY-method} \title{Strand utilities} \description{ Some useful \code{strand} 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}{DataTable}(x) \S4method{strand}{DataTable,ANY}(x) <- value } \arguments{ \item{x}{The object from which to obtain a strand factor, can be missing.} \item{value}{Replacement value for the strand.} } \details{ If \code{x} is missing, returns an empty factor with the "standard strand levels" i.e. \code{+}, \code{-}, and \code{*}. 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. 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. 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. 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. 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. } \value{ A factor (or factor-\link[S4Vectors]{Rle}) with the "standard strand levels" (i.e. \code{+}, \code{-}, and \code{*}) and no NAs. } \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) strand(x2) strand(x3) strand(x4) strand(Rle(x1)) strand(Rle(x2)) strand(Rle(x3)) strand(Rle(x4)) 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.Rd0000644000175100017510000000364212607265137017771 0ustar00biocbuildbiocbuild\name{tile-methods} \alias{tile-methods} \alias{tile,GenomicRanges-method} \title{Tile a GenomicRanges object} \description{ \code{\link[IRanges]{tile}} method for \link{GenomicRanges}. Partitions each range into a set of tiles. Tiles are defined in terms of their number or width. } \usage{ \S4method{tile}{GenomicRanges}(x, n, width) } \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. } } \details{ 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. } \value{ A \code{GRangesList} object, each element of which corresponds to a tile. } \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(elementLengths(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)))) } \keyword{methods} \keyword{utilities} GenomicRanges/man/tileGenome.Rd0000644000175100017510000001111612607265137017456 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 elementLengths(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) elementLengths(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/0000755000175100017510000000000012607330121015075 5ustar00biocbuildbiocbuildGenomicRanges/src/GenomicRanges.h0000644000175100017510000000040712607330121017770 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.c0000644000175100017510000000003412607330121020006 0ustar00biocbuildbiocbuild#include "_IRanges_stubs.c" GenomicRanges/src/R_init_GenomicRanges.c0000644000175100017510000000062612607330121021272 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.c0000644000175100017510000000003612607330121020314 0ustar00biocbuildbiocbuild#include "_S4Vectors_stubs.c" GenomicRanges/src/transcript_utils.c0000644000175100017510000001320312607330121020651 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/0000755000175100017510000000000012607265136015465 5ustar00biocbuildbiocbuildGenomicRanges/tests/GenomicRanges_unit_tests.R0000644000175100017510000000014112607265136022606 0ustar00biocbuildbiocbuildrequire("GenomicRanges") || stop("unable to load GenomicRanges package") GenomicRanges:::.test() GenomicRanges/vignettes/0000755000175100017510000000000012607330121016316 5ustar00biocbuildbiocbuildGenomicRanges/vignettes/ExtendingGenomicRanges.Rnw0000644000175100017510000001113712607265137023416 0ustar00biocbuildbiocbuild% \VignetteIndexEntry{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.Rnw0000644000175100017510000006607412607265137025016 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{A quick introduction to GRanges and GRangesList objects} %\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 elementLengths(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{elementLengths()}, \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{elementLengths() and unlist()} \begin{exampleblock}{} {\scriptsize <>= grl[[2]] elementLengths(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 <>= psetdiff(grl2, grl3) @ } \end{exampleblock} \end{column} \end{columns} \begin{block}{} \Rcode{psetdiff(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.bib0000644000175100017510000000055612607265137021541 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.Rnw0000644000175100017510000011344512607265137022561 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{GenomicRanges HOWTOs} %\VignetteDepends{GenomicRanges, Rsamtools, GenomicAlignments, pasillaBamSubset, TxDb.Dmelanogaster.UCSC.dm3.ensGene, TxDb.Athaliana.BioMart.plantsmart22, AnnotationHub, DESeq, 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(elementLengths(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) un1 <- untreated1_chr4() # single-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, un1, 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{DESeq} 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: <>= library(DESeq) deseq <- newCountDataSet(assays(se)$counts, rownames(colData(se))) 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] elementLengths(trak2_exbytx) @ ... and the intron regions: <>= trak2_inbytx <- intronsByTranscript(txdb, use.names=TRUE)[trak2_tx_names] elementLengths(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(elementLengths(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(elementLengths(lstc)) table(elementLengths(lst3)) names(lst3)[elementLengths(lst3) == 0L] ## genes with no 3' UTR data table(elementLengths(lst5)) names(lst5)[elementLengths(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 <- elementLengths(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), elementLengths(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.Rnw0000644000175100017510000005063512607265136024157 0ustar00biocbuildbiocbuild%\VignetteIndexEntry{An Introduction to GenomicRanges} %\VignetteDepends{Rsamtools} %\VignetteKeywords{sequence, sequencing, alignments} %\VignettePackage{GenomicRanges} \documentclass[10pt]{article} \usepackage{times} \usepackage{hyperref} \textwidth=6.5in \textheight=8.5in %\parskip=.3cm \oddsidemargin=-.1in \evensidemargin=-.1in \headheight=-.3in \newcommand{\Rfunction}[1]{{\texttt{#1}}} \newcommand{\Robject}[1]{{\texttt{#1}}} \newcommand{\Rpackage}[1]{{\textit{#1}}} \newcommand{\Rmethod}[1]{{\texttt{#1}}} \newcommand{\Rfunarg}[1]{{\texttt{#1}}} \newcommand{\Rclass}[1]{{\textit{#1}}} \newcommand{\Rcode}[1]{{\texttt{#1}}} \newcommand{\software}[1]{\textsf{#1}} \newcommand{\R}{\software{R}} \newcommand{\Bioconductor}{\software{Bioconductor}} \newcommand{\GenomicRanges}{\Rpackage{GenomicRanges}} \title{An Introduction to Genomic Ranges Classes} \author{Marc Carlson \and Patrick Aboyoun \and Herv\'{e} Pag\`{e}s} \date{\today} \begin{document} \maketitle <>= options(width=72) @ \tableofcontents \section{Introduction} The \Rpackage{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 \Rpackage{IRanges} (infrastructure) package and provides support for the \Rpackage{BSgenome} (infrastructure), \Rpackage{Rsamtools} (I/O), \Rpackage{ShortRead} (I/O \& QA), \Rpackage{rtracklayer} (I/O), and \Rpackage{GenomicFeatures} (infrastructure) packages. This package lays a foundation for genomic analysis by introducing three classes (\Rclass{GRanges}, \Rclass{GRangesList}, and \Rclass{GAlignments}), which are used to represent single interval range features, multiple interval range features, and genomic alignments respectively. This vignette focuses on these classes and their associated methods. The \Rpackage{GenomicRanges} package is available at bioconductor.org and can be downloaded via \Rfunction{biocLite}: <>= source("http://bioconductor.org/biocLite.R") biocLite("GenomicRanges") @ <>= library(GenomicRanges) @ \section{\Rclass{GRanges}: Single Interval Range Features} The \Rclass{GRanges} class represents a collection of genomic features that each have a single start and end location on the genome. This includes 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(1:10, end = 7:16, names = head(letters, 10)), strand = Rle(strand(c("-", "+", "*", "+", "-")), c(1, 2, 2, 3, 2)), score = 1:10, GC = seq(1, 0, length=10)) gr @ \noindent creates a \Rclass{GRanges} object with 10 single interval features. The output of the \Rclass{GRanges} \Rmethod{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 \Rmethod{seqnames}, \Rmethod{ranges}, and \Rmethod{strand} accessor functions. <>= seqnames(gr) ranges(gr) strand(gr) @ Stored annotations for these coordinates can be extracted as a \Rclass{DataFrame} object using the \Rmethod{mcols} accessor. <>= mcols(gr) mcols(gr)$score @ Finally, the total 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 \Rmethod{length} and \Rmethod{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 \Rmethod{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 @ If you then grab the components of this list, they can also be merged by using the \Rmethod{c} and \Rmethod{append} methods. <>= c(sp[[1]], sp[[2]]) @ \subsection{Subsetting \Rclass{GRanges} objects} The expected subsetting operations are also available for \Rclass{GRanges} objects. <>= gr[2:3] @ A second argument to the \Rmethod{[} subset operator can be used to specify which metadata columns to extract from the \Rclass{GRanges} object. For example, <>= gr[2:3, "GC"] @ You can also assign into elements of the \Rclass{GRanges} object. Here is an example where the 2nd row of a \Rclass{GRanges} object is replaced with the 1st 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 3rd element is replaced with the score from the 2nd row etc. <>= grMod[2,1] <- singles[[3]][,1] head(grMod, n=3) @ There are also 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 \Rmethod{start}, \Rmethod{end}, \Rmethod{width}, and \Rmethod{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 intervals. For example, the \Rmethod{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) @ Similar to \Rmethod{flank}, there are also operations to \Rmethod{resize} and \Rmethod{shift} our \Rclass{GRanges} object. The \Rmethod{shift} method will move the ranges by a specific number of base pairs, and the \Rmethod{resize} method will extend the ranges by a specified width. <>= shift(g, 5) resize(g, 30) @ The \Rmethod{reduce} will align the ranges and merge overlapping ranges to produce a simplified set. <>= reduce(g) @ Sometimes you may be interested in the spaces or the qualities of the spaces between the ranges represented by your \Rclass{GRanges} object. The \Rmethod{gaps} method will help you calculate the spaces between a reduced version of your ranges: <>= gaps(g) @ And sometimes you also may want to know how many quantitatively unique fragments your ranges could possibly represent. For this task there is the \Rmethod{disjoin} method. <>= disjoin(g) @ One of the most powerful methods for looking at \Rclass{GRanges} objects is the \Rmethod{coverage} method. The \Rmethod{coverage} method quantifies the degree of overlap for all the ranges in a \Rclass{GRanges} object. <>= coverage(g) @ \subsection{Interval set operations for \Rclass{GRanges} objects} There are also operations for calculating relationships between different \Rclass{GRanges} objects. Here are a some examples for how you can calculate the \Rmethod{union}, the \Rmethod{intersect} and the asymmetric difference (using \Rmethod{setdiff}). <>= g2 <- head(gr, n=2) union(g, g2) intersect(g, g2) setdiff(g, g2) @ In addition, there is similar set of operations that act at the level of the individual ranges within each \Rclass{GRanges}. These operations all begin with a ``p", which is short for parallel. A requirement for this set of operations is that the number of elements in each \Rclass{GRanges} object has to be the same, and that both of the objects have to have the same seqnames and strand assignments throughout. <>= g3 <- g[1:2] ranges(g3[1]) <- IRanges(start=5, end=12) punion(g2, g3) pintersect(g2, g3) psetdiff(g2, g3) @ For even more information on the \Rcode{GRanges} classes be sure to consult the manual page. <>= ?GRanges @ \section{\Rclass{GRangesList}: Multiple Interval Range Features} 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 \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(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)) grl <- GRangesList("txA" = gr1, "txB" = gr2) grl @ The \Rmethod{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 \Rmethod{length} and \Rmethod{names} methods will return the length or names of the list and the \Rmethod{seqlengths} method will return the set of sequence lengths. <>= length(grl) names(grl) seqlengths(grl) @ The \Rmethod{elementLengths} method returns a list of integers corresponding to the result of calling \Rmethod{length} on each individual \Rclass{GRanges} object contained by the \Rclass{GRangesList}. This is a faster alternative to calling \Rmethod{lapply} on the \Rclass{GRangesList}. <>= elementLengths(grl) @ You can also use \Rmethod{isEmpty} to test if a \Rclass{GRangesList} object contains anything. <>= isEmpty(grl) @ Finally, in the context of a \Rclass{GRangesList} object, the \Rmethod{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) @ \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) @ You can also append values together useing \Rmethod{append} or \Rmethod{c}. % <>= % grl2 <- shift(grl,10) % names(grl2) <- c("shiftTxA","shiftTxB") % append(grl, grl2) % c(grl, grl2) % @ \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) @ And as with \Rclass{GRanges} objects, you can also 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} As you might guess, the subsetting of a \Rclass{GRangesList} object is quite different from subsetting on a \Rclass{GRanges} object in that it acts as if you are subseting a list. If you try out the following you will notice that the standard conventions have been followed. <>= grl[1] grl[[1]] grl["txA"] grl$txB @ But in addition to this, when subsetting a \Rclass{GRangesList}, you can also pass in a second parameter (as with a \Rclass{GRanges} object) to again specify which of the metadata columns you wish to select. <>= grl[1, "score"] grl["txB", "GC"] @ The \Rmethod{head}, \Rmethod{tail}, \Rmethod{rep}, \Rmethod{rev}, and \Rmethod{window} methods all behave as you would expect them to for a list object. For example, the elements referred to by \Rmethod{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 \Rmethod{apply} methods. These include \Rmethod{lapply}, \Rmethod{sapply}, \Rmethod{mapply}, \Rmethod{endoapply}, \Rmethod{mendoapply}, \Rmethod{Map}, and \Rmethod{Reduce}. The different looping methods defined for \Rclass{GRangesList} objects are useful for returning different kinds of results. The standard \Rmethod{lapply} and \Rmethod{sapply} behave according to convention, with the \Rmethod{lapply} method returning a list and \Rmethod{sapply} returning a more simplified output. <>= lapply(grl, length) sapply(grl, length) @ As with \Rclass{IRanges} objects, there is also a multivariate version of \Rmethod{sapply}, called \Rmethod{mapply}, defined for \Rclass{GRangesList} objects. And, if you don't want the results simplified, you can call the \Rmethod{Map} method, which does the same things as \Rmethod{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 may not want to get back a simplified output or a list. Sometimes you will want to get back a modified version of the \Rclass{GRangesList} that you originally passed in. This is conceptually similar to the mathematical notion of an endomorphism. This is achieved using the \Rmethod{endoapply} method, which will return the results as a \Rclass{GRangesList} object. <>= endoapply(grl,rev) @ And, there is also a multivariate version of the \Rmethod{endoapply} method in the form of the \Rmethod{mendoapply} method. <>= mendoapply(c,grl,grl2) @ Finally, the \Rmethod{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) @ For even more information on the \Rcode{GRangesList} classes be sure to consult the manual page. <>= ?GRangesList @ \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 \Rpackage{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{Genomic Alignments} In addition to \Rclass{GRanges} and \Rclass{GRangesList} classes, the \GenomicRanges{} package defines the \Rclass{GAlignments} class, which is a more specialized container for storing a set of genomic alignments. The class is intended to support alignments in general, not only those coming from a 'Binary Alignment Map' or 'BAM' files. Also alignments with gaps in the reference sequence (a.k.a. \emph{gapped alignments}) are supported which, for example, makes the class suited for storing junction reads from an RNA-seq experiment. More precisely, a \Rclass{GAlignments} object is a vector-like object where each element describes an \emph{alignment}, that is, how a given sequence (called \emph{query} or \emph{read}, typically short) aligns to a reference sequence (typically long). As shown later in this document, a \Rclass{GAlignments} object can be created from a 'BAM' file. In that case, each element in the resulting object will correspond to a record in the file. One important thing to note though is that not all the information present in the BAM/SAM records is stored in the object. In particular, for now, we discard the query sequences (SEQ field), the query ids (QNAME field), the query qualities (QUAL), the mapping qualities (MAPQ) and any other information that is not needed in order to support the basic set of operations described in this document. This also means that multi-reads (i.e. reads with multiple hits in the reference) don't receive any special treatment i.e. the various SAM/BAM records corresponding to a multi-read will show up in the \Rclass{GAlignments} object as if they were coming from different/unrelated queries. Also paired-end reads will be treated as single-end reads and the pairing information will be lost. This might change in the future. \subsection{Load a `BAM' file into a \Rclass{GAlignments} object} First we use the \Rfunction{readGAlignments} function from the \Rpackage{GenomicAlignments} package to load a toy `BAM' file into a \Rclass{GAlignments} object: <>= library(GenomicAlignments) aln1_file <- system.file("extdata", "ex1.bam", package="Rsamtools") aln1 <- readGAlignments(aln1_file) aln1 length(aln1) @ 3271 `BAM' records were loaded into the object. Note that \Rfunction{readGAlignments} would have discarded any `BAM' record describing an unaligned query (see description of the field in the SAM Format Specification \footnote{\url{http://samtools.sourceforge.net/SAM1.pdf}} for more information). The reader interested in tracking down these events can always use the \Rfunction{scanBam} function but this goes beyond the scope of this document. \subsection{Simple accessor methods} There is one accessor per field displayed by the \Rmethod{show} method and it has the same name as the field. All of them return a vector or factor of the same length as the object: <>= head(seqnames(aln1)) seqlevels(aln1) head(strand(aln1)) head(cigar(aln1)) head(qwidth(aln1)) head(start(aln1)) head(end(aln1)) head(width(aln1)) head(njunc(aln1)) @ \subsection{More accessor methods} \end{document} GenomicRanges/vignettes/slides.sty0000644000175100017510000000211312607265136020354 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} %% }