pax_global_header00006660000000000000000000000064141164517610014520gustar00rootroot0000000000000052 comment=63a91c21c13999b8bac080227b31b9d455aaa569 q2-quality-control-2021.8.0/000077500000000000000000000000001411645176100154405ustar00rootroot00000000000000q2-quality-control-2021.8.0/.coveragerc000066400000000000000000000003241411645176100175600ustar00rootroot00000000000000[run] branch = True omit = */tests* */__init__.py q2_quality_control/_version.py versioneer.py [report] omit = */tests* */__init__.py q2_quality_control/_version.py versioneer.py q2-quality-control-2021.8.0/.gitattributes000066400000000000000000000000541411645176100203320ustar00rootroot00000000000000q2_quality_control/_version.py export-subst q2-quality-control-2021.8.0/.github/000077500000000000000000000000001411645176100170005ustar00rootroot00000000000000q2-quality-control-2021.8.0/.github/CONTRIBUTING.md000066400000000000000000000015131411645176100212310ustar00rootroot00000000000000# Contributing to this project Thanks for thinking of us :heart: :tada: - we would love a helping hand! ## I just have a question > Note: Please don't file an issue to ask a question. You'll get faster results > by using the resources below. ### QIIME 2 Users Check out the [User Docs](https://docs.qiime2.org) - there are many tutorials, walkthroughs, and guides available. If you still need help, please visit us at the [QIIME 2 Forum](https://forum.qiime2.org/c/user-support). ### QIIME 2 Developers Check out the [Developer Docs](https://dev.qiime2.org) - there are many tutorials, walkthroughs, and guides available. If you still need help, please visit us at the [QIIME 2 Forum](https://forum.qiime2.org/c/dev-discussion). This document is based heavily on the following: https://github.com/atom/atom/blob/master/CONTRIBUTING.md q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001411645176100211635ustar00rootroot00000000000000q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/1-user-need-help.md000066400000000000000000000006111411645176100244560ustar00rootroot00000000000000--- name: I am a user and I need help with QIIME 2... about: I am using QIIME 2 and have a question or am experiencing a problem --- Have you had a chance to check out the docs? https://docs.qiime2.org There are many tutorials, walkthroughs, and guides available. If you still need help, please visit: https://forum.qiime2.org/c/user-support Help requests filed here will not be answered. q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/2-dev-need-help.md000066400000000000000000000005641411645176100242660ustar00rootroot00000000000000--- name: I am a developer and I need help with QIIME 2... about: I am developing a QIIME 2 plugin or interface and have a question or a problem --- Have you had a chance to check out the developer docs? https://dev.qiime2.org There are many tutorials, walkthroughs, and guides available. If you still need help, please visit: https://forum.qiime2.org/c/dev-discussion q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/3-found-bug.md000066400000000000000000000017421411645176100235370ustar00rootroot00000000000000--- name: I am a developer and I found a bug... about: I am a developer and I found a bug that I can describe --- **Bug Description** A clear and concise description of what the bug is. **Steps to reproduce the behavior** 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Computation Environment** - OS: [e.g. macOS High Sierra] - QIIME 2 Release [e.g. 2018.6] **Questions** 1. An enumerated list with any questions about the problem here. 2. If not applicable, please delete this section. **Comments** 1. An enumerated list with any other context or comments about the problem here. 2. If not applicable, please delete this section. **References** 1. An enumerated list of links to relevant references, including forum posts, stack overflow, etc. 2. If not applicable, please delete this section. q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/4-make-better.md000066400000000000000000000015321411645176100240470ustar00rootroot00000000000000--- name: I am a developer and I have an idea for an improvement... about: I am a developer and I have an idea for an improvement to existing functionality --- **Improvement Description** A clear and concise description of what the improvement is. **Current Behavior** Please provide a brief description of the current behavior. **Proposed Behavior** Please provide a brief description of the proposed behavior. **Questions** 1. An enumerated list of questions related to the proposal. 2. If not applicable, please delete this section. **Comments** 1. An enumerated list of comments related to the proposal that don't fit anywhere else. 2. If not applicable, please delete this section. **References** 1. An enumerated list of links to relevant references, including forum posts, stack overflow, etc. 2. If not applicable, please delete this section. q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/5-make-new.md000066400000000000000000000015131411645176100233530ustar00rootroot00000000000000--- name: I am a developer and I have an idea for a new feature... about: I am a developer and I have an idea for new functionality --- **Addition Description** A clear and concise description of what the addition is. **Current Behavior** Please provide a brief description of the current behavior, if applicable. **Proposed Behavior** Please provide a brief description of the proposed behavior. **Questions** 1. An enumerated list of questions related to the proposal. 2. If not applicable, please delete this section. **Comments** 1. An enumerated list of comments related to the proposal that don't fit anywhere else. 2. If not applicable, please delete this section. **References** 1. An enumerated list of links to relevant references, including forum posts, stack overflow, etc. 2. If not applicable, please delete this section. q2-quality-control-2021.8.0/.github/ISSUE_TEMPLATE/6-where-to-go.md000066400000000000000000000100111411645176100237760ustar00rootroot00000000000000--- name: I don't know where to file my issue... about: I am a developer and I don't know which repo to file this in --- The repos within the QIIME 2 GitHub Organization are listed below, with a brief description about the repo. Sorted alphabetically by repo name. - The CI automation engine that builds and distributes QIIME 2 https://github.com/qiime2/busywork/issues - A Concourse resource for working with conda https://github.com/qiime2/conda-channel-resource/issues - Web app for vanity URLs for QIIME 2 data assets https://github.com/qiime2/data.qiime2.org/issues - The Developer Documentation https://github.com/qiime2/dev-docs/issues - A discourse plugin for handling queued/unqueued topics https://github.com/qiime2/discourse-unhandled-tagger/issues - The User Documentation https://github.com/qiime2/docs/issues - Rendered QIIME 2 environment files for conda https://github.com/qiime2/environment-files/issues - Google Sheets Add-On for validating tabular data https://github.com/qiime2/Keemei/issues - A docker image for linux-based busywork workers https://github.com/qiime2/linux-worker-docker/issues - Official project logos https://github.com/qiime2/logos/issues - The q2-alignment plugin https://github.com/qiime2/q2-alignment/issues - The q2-composition plugin https://github.com/qiime2/q2-composition/issues - The q2-cutadapt plugin https://github.com/qiime2/q2-cutadapt/issues - The q2-dada2 plugin https://github.com/qiime2/q2-dada2/issues - The q2-deblur plugin https://github.com/qiime2/q2-deblur/issues - The q2-demux plugin https://github.com/qiime2/q2-demux/issues - The q2-diversity plugin https://github.com/qiime2/q2-diversity/issues - The q2-diversity-lib plugin https://github.com/qiime2/q2-diversity-lib/issues - The q2-emperor plugin https://github.com/qiime2/q2-emperor/issues - The q2-feature-classifier plugin https://github.com/qiime2/q2-feature-classifier/issues - The q2-feature-table plugin https://github.com/qiime2/q2-feature-table/issues - The q2-fragment-insertion plugin https://github.com/qiime2/q2-fragment-insertion/issues - The q2-gneiss plugin https://github.com/qiime2/q2-gneiss/issues - The q2-longitudinal plugin https://github.com/qiime2/q2-longitudinal/issues - The q2-metadata plugin https://github.com/qiime2/q2-metadata/issues - The q2-phylogeny plugin https://github.com/qiime2/q2-phylogeny/issues - The q2-quality-control plugin https://github.com/qiime2/q2-quality-control/issues - The q2-quality-filter plugin https://github.com/qiime2/q2-quality-filter/issues - The q2-sample-classifier plugin https://github.com/qiime2/q2-sample-classifier/issues - The q2-shogun plugin https://github.com/qiime2/q2-shogun/issues - The q2-taxa plugin https://github.com/qiime2/q2-taxa/issues - The q2-types plugin https://github.com/qiime2/q2-types/issues - The q2-vsearch plugin https://github.com/qiime2/q2-vsearch/issues - The CLI interface https://github.com/qiime2/q2cli/issues - The prototype CWL interface https://github.com/qiime2/q2cwl/issues - The prototype Galaxy interface https://github.com/qiime2/q2galaxy/issues - An internal tool for ensuring header text and copyrights are present https://github.com/qiime2/q2lint/issues - The prototype GUI interface https://github.com/qiime2/q2studio/issues - A base template for use in official QIIME 2 plugins https://github.com/qiime2/q2templates/issues - The read-only web interface at view.qiime2.org https://github.com/qiime2/q2view/issues - The QIIME 2 homepage at qiime2.org https://github.com/qiime2/qiime2.github.io/issues - The QIIME 2 framework https://github.com/qiime2/qiime2/issues - Centralized templates for repo assets https://github.com/qiime2/template-repo/issues - Scripts for building QIIME 2 VMs https://github.com/qiime2/vm-playbooks/issues - Scripts for building QIIME 2 workshop clusters https://github.com/qiime2/workshop-playbooks/issues - The web app that runs workshops.qiime2.org https://github.com/qiime2/workshops.qiime2.org/issues q2-quality-control-2021.8.0/.github/SUPPORT.md000066400000000000000000000122421411645176100204770ustar00rootroot00000000000000# QIIME 2 Users Check out the [User Docs](https://docs.qiime2.org) - there are many tutorials, walkthroughs, and guides available. If you still need help, please visit us at the [QIIME 2 Forum](https://forum.qiime2.org/c/user-support). # QIIME 2 Developers Check out the [Developer Docs](https://dev.qiime2.org) - there are many tutorials, walkthroughs, and guides available. If you still need help, please visit us at the [QIIME 2 Forum](https://forum.qiime2.org/c/dev-discussion). # General Bug/Issue Triage Discussion ![rubric](./rubric.png?raw=true) # Projects/Repositories in the QIIME 2 GitHub Organization Sorted alphabetically by repo name. - [busywork](https://github.com/qiime2/busywork/issues) | The CI automation engine that builds and distributes QIIME 2 - [conda-channel-resource](https://github.com/qiime2/conda-channel-resource/issues) | A Concourse resource for working with conda - [data.qiime2.org](https://github.com/qiime2/data.qiime2.org/issues) | Web app for vanity URLs for QIIME 2 data assets - [dev-docs](https://github.com/qiime2/dev-docs/issues) | The Developer Documentation - [discourse-unhandled-tagger](https://github.com/qiime2/discourse-unhandled-tagger/issues) | A discourse plugin for handling queued/unqueued topics - [docs](https://github.com/qiime2/docs/issues) | The User Documentation - [environment-files](https://github.com/qiime2/environment-files/issues) | Rendered QIIME 2 environment files for conda - [Keemei](https://github.com/qiime2/Keemei/issues) | Google Sheets Add-On for validating tabular data - [linux-worker-docker](https://github.com/qiime2/linux-worker-docker/issues) | A docker image for linux-based busywork workers - [logos](https://github.com/qiime2/logos/issues) | Official project logos - [q2-alignment](https://github.com/qiime2/q2-alignment/issues) | The q2-alignment plugin - [q2-composition](https://github.com/qiime2/q2-composition/issues) | The q2-composition plugin - [q2-cutadapt](https://github.com/qiime2/q2-cutadapt/issues) | The q2-cutadapt plugin - [q2-dada2](https://github.com/qiime2/q2-dada2/issues) | The q2-dada2 plugin - [q2-deblur](https://github.com/qiime2/q2-deblur/issues) | The q2-deblur plugin - [q2-demux](https://github.com/qiime2/q2-demux/issues) | The q2-demux plugin - [q2-diversity](https://github.com/qiime2/q2-diversity/issues) | The q2-diversity plugin - [q2-diversity-lib](https://github.com/qiime2/q2-diversity-lib/issues) | The q2-diversity-lib plugin - [q2-emperor](https://github.com/qiime2/q2-emperor/issues) | The q2-emperor plugin - [q2-feature-classifier](https://github.com/qiime2/q2-feature-classifier/issues) | The q2-feature-classifier plugin - [q2-feature-table](https://github.com/qiime2/q2-feature-table/issues) | The q2-feature-table plugin - [q2-fragment-insertion](https://github.com/qiime2/q2-fragment-insertion/issues) | The q2-fragment-insertion plugin - [q2-gneiss](https://github.com/qiime2/q2-gneiss/issues) | The q2-gneiss plugin - [q2-longitudinal](https://github.com/qiime2/q2-longitudinal/issues) | The q2-longitudinal plugin - [q2-metadata](https://github.com/qiime2/q2-metadata/issues) | The q2-metadata plugin - [q2-phylogeny](https://github.com/qiime2/q2-phylogeny/issues) | The q2-phylogeny plugin - [q2-quality-control](https://github.com/qiime2/q2-quality-control/issues) | The q2-quality-control plugin - [q2-quality-filter](https://github.com/qiime2/q2-quality-filter/issues) | The q2-quality-filter plugin - [q2-sample-classifier](https://github.com/qiime2/q2-sample-classifier/issues) | The q2-sample-classifier plugin - [q2-shogun](https://github.com/qiime2/q2-shogun/issues) | The q2-shogun plugin - [q2-taxa](https://github.com/qiime2/q2-taxa/issues) | The q2-taxa plugin - [q2-types](https://github.com/qiime2/q2-types/issues) | The q2-types plugin - [q2-vsearch](https://github.com/qiime2/q2-vsearch/issues) | The q2-vsearch plugin - [q2cli](https://github.com/qiime2/q2cli/issues) | The CLI interface - [q2cwl](https://github.com/qiime2/q2cwl/issues) | The prototype CWL interface - [q2galaxy](https://github.com/qiime2/q2galaxy/issues) | The prototype Galaxy interface - [q2lint](https://github.com/qiime2/q2lint/issues) | An internal tool for ensuring header text and copyrights are present - [q2studio](https://github.com/qiime2/q2studio/issues) | The prototype GUI interface - [q2templates](https://github.com/qiime2/q2templates/issues) | A base template for use in official QIIME 2 plugins - [q2view](https://github.com/qiime2/q2view/issues) | The read-only web interface at view.qiime2.org - [qiime2.github.io](https://github.com/qiime2/qiime2.github.io/issues) | The QIIME 2 homepage at qiime2.org - [qiime2](https://github.com/qiime2/qiime2/issues) | The QIIME 2 framework - [template-repo](https://github.com/qiime2/template-repo/issues) | Centralized templates for repo assets - [vm-playbooks](https://github.com/qiime2/vm-playbooks/issues) | Scripts for building QIIME 2 VMs - [workshop-playbooks](https://github.com/qiime2/workshop-playbooks/issues) | Scripts for building QIIME 2 workshop clusters - [workshops.qiime2.org](https://github.com/qiime2/workshops.qiime2.org/issues) | The web app that runs workshops.qiime2.org q2-quality-control-2021.8.0/.github/pull_request_template.md000066400000000000000000000006121411645176100237400ustar00rootroot00000000000000Brief summary of the Pull Request, including any issues it may fix using the GitHub closing syntax: https://help.github.com/articles/closing-issues-using-keywords/ Also, include any co-authors or contributors using the GitHub coauthor tag: https://help.github.com/articles/creating-a-commit-with-multiple-authors/ --- Include any questions for reviewers, screenshots, sample outputs, etc. q2-quality-control-2021.8.0/.github/rubric.png000066400000000000000000007014131411645176100210020ustar00rootroot00000000000000PNG  IHDR,4\sBIT|d pHYs.#.#x?vtEXtSoftwarewww.inkscape.org< IDATxw|g3AޫEEQvgmKhQRD.#g$ G)9IIr~vkxr\7ޯ\b0 R1NE/zQ@G E/z'w:~9 .VhhD?^Kg7o78s7HG^{5]~]v ӧOլYD ^-ZٳgW_TB iٲeںufR)//_lRl߾ݤIs8#8ѣGرcٰakQ ___۷Of (p&I8p@sIO5ydXTRZ~ҦMk7oZpDO<1ӧO(8!?0c2dȠs,fݺu_6 8 2?sI @C ޽{uСfIZj& ilϟ߬EILR^DԬYq]]]`I&Ѿ6vUV5o\TD$&~<н{%6p^DGGk֭˓'O/Sڵkhh#^QF &:t\]/TՕ={ve˖M/[l8cǎ%.aÆI ᅲWڴi#F)+)<<\&MҡC8$^dN>mR7n$Y*Toh?^@\UTщ'4tP.]Z3gͫ-[jӦMZf0=ŋMw!;֭ۗ`^q 7|iĚ3gNrN/p6mq$=iӦD Klc׮]K4(z1P ><Ȟ=j֬`gϞ%Y|֋رc; IMMd4k,$ zSLÇ; Id̘Ѭ#GԈ#e\~)z)׉''$w(z6{_uѣ6ͥ\rʔ)SIQh`7ne˖zyr8bŊY4\:t蠀UN/ N%ɝJ,iXQVR 4l0ruw*g͚k׮m+][-Zӧ;8\ !OddgϮGd|k׮ڵ-j9<{Q۶mu=O,XP+VN4ӧOu1*((Haaazː! (E\rJ>}2g`>}ZgΜӧ+W`0_q\\\%K+WN5kT9$ϘԩS:}N:]qSM0A3fPtt(z{xCpBmڴy`0hڿ6mhTMݻw~zmذAғ'OL%Jyj۶*Tę:K.i͚5ڼy;(ƹB jٲڵkB %q҃b[Ew/FGFFjŚ]t<$???EEEI8>vzRѢEuʕ$Uzu |ڷooҽfS5jO?5ڶdXª6m'o׮]2ev!k_?aÆ=zj׮m\֋}I' @;vɓ'M#Oҷ~kl9z:viӦiѢE*W\#""gIh@s(^x큁:tlbUѶm۴m65o\S\̚/oݺufIү_O>5y̍7ԡCi[bV\_:tf͚e.]d$I|'Ol; Kwv=zƍ?~ϯݻ믿Klٲ7oM ^v1UZU~m̟,[L˗iU7oVٲegƭ^Z~~~6/xܹS-Z0~;w֭[Z˗/5-Q'EӮq#""d/_^=z͛7,֊+;tD[ʕf]|Yyn*___b={L}_|amک`ѣյkW=~8...j֬vء7n(22RW^UlYݻwO5?l-v%kNϞ=x_ՆY'{R7'ojΜ9ѣcך5k4zh3Ʀw~-\P}1.q,W\ʕ+5j%KW^&7ne˦}iҘ1c#Gɓ13G*TP`N:PhhN:G***ʤ8UVUժUU^8m CK.Uv^z/_>uI۷ט1c4mڴD犈PvcլYӤչsgX5ٳgmV ,ŋSddU󹹹QF*U1c(,,L>ԑ#Gt9֑iӪv*VMs1X{, ՛0a&N9TREWV맟~RVL*R :T|MK}G&O&L~I/_N:%`0M6Z~IsΝ['OTk׮ԩSڸq:dϟ_|>C3fnܸϟ'8WZo߾ߵh"]~\,Y]&`0رcF>cmݺլ 2) *\Kn߾QF~0+͛7Ox͛75x߿&M$oooQHFi3gNmٲE+Vx /_^>LouIK.ѾϞ=Sum(UN8!wY~ʖ-4ᅰ-[V'N0{ܫݻ9rmsuuՎ;۷QF&iժɅ/dɒ&رمM6K.hLƌg2eѣչs؝D HtTsxչsg?WZJH.]|rLlx.]TىbJKX6mژK@@/^hyjȐ!&oݳhܫ*, 6,ނ׃ԭ[7 ^4j(s*VTbr+Wȑ#&-Zhҥfy!,,쥂Wٵ~7L+O< {zzjŊ*UE:ɓ't5egbΓ1cd%  ֐!C}xﻱQFrcWX=c^UNO6ͤЀ>}z9v- qx^^^ 矛DZYyy v*lRժU3{ܿjFRIt)=<<4vXs4iEc9~Fڷoϑ /W/{6m(**1ϟ?7-IPʫxfpݛhٳ[nf-o6m2|ʚ5Ѷ˗/kܹ&LjoXBׯ_o1͛77{̿ 2DF֭X///w6k,~&SM74{ܬYnU g}j^`['%@dɢ ?P͚5%Çk&_j]frs{!wfaÆYtҥKM>јH\2sOOO?qӧOWddqyGFFj֭fDZ3w߿uY9r䈷=W\:zƌ*Upz7ճgO=zTY Zn%K=nڴi={y޻woI QuujnGh ѣG͚;gΜfcUvwĈf/IgVLLEc|_~{}c,aB.]#G}'Oj…*S,͑ZtY``֭[gQUVɓ'/=K>:vh| PbŊZ~4qD(Q"c.[,>7n4{^KW6{LttM[Z5ըQ_wEڵ+u&xwRJ/]dq\YfUjK:t`1-wy֮];eɒŢ@ҡ0[5n8;wN>e˖-Ib>}Z.\Hρ̞7$$侏?̙3GYw9Ң(`0y>dȐ%} :Tk׮5;γgt]YAVe5zh;vL~~~f9y݃m@D `*Uh֬Yy6mڤVZæ1lH޽{+cƌʚ5kx{{+s2d={fQ?6ofTxqcڵK&ҥKokv<<<4j(|_xxVXy>}̎ 샢fͪ:wFiAAA]ry ҥrav˗| <˔)zหW*Zhrz^{qv8EoOOOu>(zYlYY'!%JД)SѣG9֤g3f4hvOj…;}{v,Y$8?oKy{{%hWh?cGnݚ`Mj]t)ޝ@I;K,<./WWW 4(-=~pڴi]Ec͕?~ġf_њ:u͛og- ۢ<}P't>K5jΝ;o|_Bw4Yzz-Cյk_sm޼YZ2-_>>۷Oϟ~}%޽;N>}X^DrUw1 ()+V̤~E`NME#F=&""],>ԏ?_>}ڽU@sRiԨQfwzuX" `0ԧH"]MrI8$XQ$)yxx\rȑCٳg7;v@@@GJѼys/^q͋?ĹW]7k7x<9>%gΜ޽LEFFjɒ%qk yQ'ц/㏊C6x"""WNx\\\TJcĉfK6l_ 6H2~a˖-޹UP!̙\8p3fҦMk֘gj˖-駟tΝҦM]2E(z0eWӭ[n:;d;w9JU V%c`ھ}Ec}zMڵ|||7sLi5h rUcu%… ?~!e3(o|SNfꫯwyޢE ȑ;Nä#ƍ_tСDt)Ѽ}YƦŒuQƍS*UtY驁=?,I:y*U}ltګ;ِ!C,Sox IDAT̙?ƍho^ϟ$O*[n޼ia_~~~5c խ[Ws-ZTڵ3{ܫ"E^z쏢8tҙO>QPPPrƍDRرwNYr$M8Ѥ3{l}W/=ԛoi/[nVkYTx!cƌyYӧOe+W.Oy瞽kƍ/=H>HֽիIc@A IBCCѣGIxӧOO>Znŋ>Sg}f~ &˪_5l0_OV>}z͞=[7o8gԮ];-^8N۔)S,*R<~آ<ý{C㚲KU&LPDDDי3gV…͎oJR˖--&M}Q''O?~\M4I̙3-O>QM]|EL4ɢbbb4h E2eʨ哐bŊyO6guyѣg0ԵkW8q챏?{ァiرj֬i,޽{q}9sqձ-AD]6qM6+s?;6m9sZ/^DrmVztMhʔ)EذaC97n?աCM4)ν>|ԩٳgiK.VXaSXټЮ];UL=|P5kԆ Lk׮]q (`)-.&&&G5cҤIo~z#o޼f9poΝ;3k˗Wƍ-ۧO싢8K^\\r5k?nqgϪaÆC_ʕ+-1|+Vq111?~jժk*,,,N(:tHzoN)SXT 2UUzu2fyKNk֬QƌnZmڴѮ]ӧOm65iDjR```>iҤ-:F޽{jժ._lXI5j(G4Gdd>3M>ݢϟ?׻ᆱ 6\}Uƍ4 jٲ[]rEu6lؠ GqܹTbQƌ71 R l:-R^,?~ 8P)h[nСCocǎD_,YRwz'R``jժ[nY< .ܹsMWPPP=6L_qMqFjʬ15jЁl4ib=W*^rȡhݿ_/^LpNWWW-]T:u2)u9׆ lr|g,YԨQ#UREEU TLeϞݢBBBt1ݹsGGѺut59Sҥ?~e͚U+V4il g<)R;̙3t!SjĈ6E/p"ǎ3wb˧ҥK+_|򒋋BBB#ԩSq5lP+WT֬Ym_@@{=]r&{Zh#&&F%KŋMfi&Iٲe!\\\4sL}&?~&MYϢEԣGƮ]Vm۶qF*Tn'O[oeՎhǎ*W޳g֭kRߌ3ڵk=OR&MGɽ^z_~w5>I>>3 6LnnnVBR}ڽ{5EǏg}f.Ç&ϗ/Zld4iDP۶mu…$#IZxڷoqe/.B iKj:uFOon(xq8wz+WNuQ5k,rI&wﮀ9Ҧrȡ]vi5kV^Z ^/tU>>>&8pݓw_˖-'NhĈJ6m(VG+ >\SLnnn۷>dƏhWWW <8II8ƍy/_>-YDGUʕ%S0ڼynݪ5j,~|4~x]pA/Vm61...8p._qY|ϒy{'ّԀ>}zԩSuyS6?שSTR% ˌ9RwVٲe-.]:mV-[6go4n8ɋo iq8ǏB 9pĈرc;sN::qݻgRӫ|]5kʕ+5~ٳgڸq6oެ;vfԭ[7KEM,Mw=(P@ӧ,X`Ǭ'$$D?l٢={$1%JP޽եKw>秥K/5!W\Y4h6m$6mJϝ;w~vE/p2A&LPcwuYƍp߿P`0(}ʘ1ͫH"I~bbbt=zT/^իWu-EEE)44Tʚ5gϮrʩjժz7hgѣw^˗OSb=_|ʙ3gr(IzN>G*((Hׯ_۷0e͚UYfUΜ9UR%UZU JaWҥKzٳ+w)⿣`Pٲeuԩ8mK_e#JmQSXhzw}g9H]R֯IСCq̙S;vLlQû{VX~(OOdE/8s*""gL[`G111u넇kĉX ,jժiƌ<5jҧO;rOĉuM͝;W>bbbԬY3>r~wkq|׺sKϊ-$y~\ j]矪Y"##վ}{-[LiҤIRu֩M6F۲e˦k׮tGŋUB>sqqy$N`>T)IZj5jR1ۼysm_c U6m|ݻw`SPPKvڥƍÇɔUsۗ/_.XÆ uɗ .)S$Y~ p!@[dwo{ ce˖͎YNJҙ3gmwqqQJt%dɒI&HP``*TG%د\rڹsgnRիСCfK6~Wխ[7 )$(u1т$8qB׽{Y[o=&C ڰa/E/$2~x$WWWm۶rww7ɓzwt{ 8P&/^8{/ )E/$pYM2ETL:tH۶mիyx 7OVݺuum{j+VLVR,YQFѣ*Wɉ;,mذ!NfjѢ"""-^vޭܹs#TΝ;Z|ۧ =}T3fT…UNuA>>>ɝ&#^I(*** nݪVZٳgFK,ݻw+gΜI"C`6lM6)]tF/\u͛v u(|X@ аaCmܸ(z,D `^) / Cr')**Jо}}/Yvޭ9s1K@25k,]zլA }xŋkʝ; 3H](z$VZ:w$)cƌݻ7nB Ç:~֭[;v(&&&޹E/dzi޽jժiʕ+ǏרQk׮xkr'؂W͚5{x ^T|yܹSӧOWڴi9w֭۷o'I);,88X ֣GSN)O<&?ԤIݿh;;3b-\P=$kά$UREW 8#^vq,dɒڻwrmEڵkP0;v,kk ,Xmۦ,Ym?wUݻwi;6l`ql=p&VdddVojUDDD7n^zzw+>|X+W*U1 E/; ygϪVZVYvm-_\ڵSLLLv۷k/=WkUl ՝],պuk >>>>Zl\]y=#77޶m}R{Fe5?QƌU\=}T]tQTT󻹹r2 Zn*VV`ACO8v֩S8:~d4iHO>Qn:e͚&1R^v֡Cyh"9RFqEIO?TAAA/p4,gΜٳѶiӦGu{n={V={9rh>`lSjf͚Zzrm>T*Uty)88XYdU);&NoTB-]T111SmVϟ$կ_p*ŋu]zUTP!URE 0kݻkɒ% TF-[*M4qڏ?={T^=rH(z`0hݺu:u8...jԨ&LU4j޽}TfM.]ZO߿_~ӦMYo P0{Ծ}{ouww_A4whhZn]vY^uRHDppj׮mRK4x` 6Lmۦݻ[g2e}v ^)QH@dd7ogϚ=v&ҤIŋk̙ʐ!ٱZh!˗]t)S8z5ydy.]:Ϙ1—$ 4H޽I1J(~I7nTLL83G^8+QR?XK/ܩ@&L5iҤدկ_?_zbbbt1} 2U@-^XoҥKզM+WN^^^ʕ+*W~~S@@6mj 8G^8+˸L0a&N(I{%sVWCՌ3$sڵkU~}}o߾^z%rjȐ!o$W0 ϮKvz'cFQ6mZmڴ)ނ$̙S?&NoQ_l+:d/'C ڲeԩ|II>l٢u&cVwJ>#ծ];1...7n;C /gX8+QRǿto /)y.\[ 7rHٳ{ _@2s a ^@ @ @j/d>s[ `PLL$z3۹sg _@2r ca^@27n\/B @/dΜ9oF4| 0@E$eΜy--|EGGkŊ86yXXl=ٸq_~eʽ1`OB`0h/ϟϟ+M4 jΝ;Kw83fPttO.777]rE|l٢;w*>lyXXlz Y|G/cΐ!nݪ~;?[2M/^TB|x _THɓGRddҤIիWe˖VWUҠ$W ^3gUjd r2*Yܹ`>}hVK/|^pWI;; p2ǏO%I}~7%vǗD 3WUb`GcǎɓcΒ%~W ^Rgx!sQUR%vוeUX1c/^X={`>gX8֫N/N(xH-̠A7xCTHHN8%J=5lP׮]:v=TJQ,ԏ>(zI`0hСq ^i %r2WztAUVMTT)޽[%K4:&((HuֵI+[lN 03WR7+xC   6L3f̈}o@rs2A...qߺuKΝ;gt\"E{n˗ϢoV3 ^q:^;$b/1V\riϞ=*U@ժUK1cbbԷo_ ^u^;$5sgT_Rھ}|}})x`Z^%vz6_kǎ8B&22R-[ԡC,#W\+00;6l/`&G^8֫N/  Yf>[o%cfׯ,X 2h֭z-Ν;W(P@{Q- ~^pWɋ^P8 I&i'OiӦVz״sxw|]rE7+::ZsUxxgz(z6`04x8;vP8 Q&Lx٣Gk\ݻjѢ֭[w8zq^ oXEkٱ^*W@\B_WDD̙3_Uj,q-;:wlٲ}z֬YO*M4+*X_\|YժUݻwg;`>G_8֫`!AiΜ9(xHLppW .HgG`Ǐǎ/` G_8֫; Wڹs'/)yZj .H"ڼy>|7naÆF򎯂 m+*e`0>x;wRJɘ /dÕ9sfըQC5k&Iʔ)6mڔ䅯>s ^aXR.75wgڱc/)31 TڴiEDDEھ}ѱ80} D 3WR7֫^(xHM테т$KN?4ibѣGjРgQSNQlԋ* GHx!Wڴivx:|䉚6mjQ111;v$ ^%XW0 8p͛EbŊɘ ϫB p IDAT @jzz HC @/d?A)$$ĪyҥKM6ŻѣG5yW%?k͚538z^.a04`͟??vڥ2e$cf#1 ֭-[J*iǎjNKw|iܹܹreUr caJ}A @j/d&Me˖I9w}n;c8p@+WѣhrWUN/&BfժUС^}}a_͛7׎;MV5kThh;&IU\9b+*KLLz%K> r2V:uS˗Ν;-[6ܺuK VDDI/^ݻ[p6^pW_LLzR+GHB&((HM4%IǏGʕK:t0o~(xfr `J(z_kҥ(xHLhh4iwJjԩS}z-M>ݪ8q `r *x.]:3LLLڴi3gΨxڲe"##u1-Z[jwTTb b-֨K"1D{KJWc^(*-5(bIٝ.lly>9-3lg&puu)S&[VhQر...zAdk^` Ȧ) ^Dd1laB#F@׮];j֬cǎ-rvv\rXr|988`ӦM(S^m"[WDdXB Bf~zi/"2Wyɓ'hѢݻvz OOOۮS.^B ˗زe ɓ'cҤIf^`> &i =UȈㄌ*c_B)R^wޅ/d;c""Kze!BA^ŋgEDf2ٕ*U*ץ۴i8 ǫWKWPXR^Y/^DDDDdS2?SVxq9rNhMպuk|RfΜ)ܢE 9HdSXR^Y7^DDDDd3x%Lr Ο?-Zٳg9`H,8eÇzDy^DDDDd  6H24RJ(;kQ(p9($$$ ##e˖76mSm_ؾ};jժ]3gbƌȜi߾=߯#1^Iݻw{F+<<ڵBÇQHIdnXlC/""""z ȒXݻw-[HҤzLj#k۹_...ѿ,X׮] pIB ҥK(Sn/FYs2%KoŜ9s0i$x~}͛g`EDDDDVYkIKKԩSpBtfϞ.cs r㣏>\"[dT_#%%|e .xxx9c-Y-B?Yky5ksx@TT={")))cK*'NF:쌍72"Ғ+SIMMxɓ1k,Y9<:tׯ_Fl^DDDDd27JJ(#G0""c2hܸ1nݺ]6??? 22ك\۫]6qqqq֭?kΝ;ѦM^zeJǏǂ 9s&LbpϟG6m >D% nR^&^DDDDdu4^GEʕpdDDYLFFڷoÇsرcao}љ]xYVR'N@…sԩ;w.Jcjժ 6jժڿ0"fʔ?VZiK׻|XbmY+ЋBi&i/"2WH=[W#G 888 ڵkɓ'# @cعs'n݊'*jsD"KzEY1"""""P(,Ld\\\qF#>Rݻwzejl|խ[zRK?QYte^\̍-M-[W6mxUɓ1k,sqq6*V,c$2'WC/""""8۷D'/"2W6! sIKw .>^2G}5k4^5u*3lc$2W C/""""( Ȓ̛7o_|)XU ))I>l-+seR 6u|DyrЋ,Fzz:2ZlY^DdluBt*̙ :t(TEFF>-ze2eԫW~)f̘-[HHH{|J3gDttmr~X"""""3}bҶ'GFD-OȔ+W'N_räIdi  P+Mdl^;P(?3/2 +ҖB 4IKKC>}_Ix 999aƌ8qʱQQQ(S Jv777=zT{\t kݻIdk^Y 6h Kɾ|+WQ`h(ezE=li ;̎NǣYf*>&MU{yyI&INNF6mj#}Gdk^Y3lڴI㒃'OƬYo޼'O2777ٳ銡?GFD5OȌ5 nҸĉ}ʶoF ԩ6l`И""";udP[Dƚ땵ӧ֬YNիW/.]=>cxyy4www۷Z2"m^>xO/""""2;iiiݻ7#mFXX/"2;|||b ѪU+$$$}ؿn/FBd?q8::GڵkmذAc Ϟ=CuٳgѰaC ȴXPҋBZZzꅽ{Jۼq1+W.FDN!`gg'=OHH~^l5j @ضm5j|u~g}FDDuԩL뫌!s\6lÑ???lڴWKd^Y[nr労mٳ'6lWWW@WFt OɁWzQcEDZ'dJ%tI&q@3xA0Jv{,X@˔)mۢt(Rw^\v PdIbŊ:XkѨ[.?~vnݺ\튯9s`ҤIZ+>>-Zݻwxɰ^\zQRx+Waaa XҥK1bxxxhܸ1mۆ}ʲի1|p{f͚ؽ{7} ҂5+k7xÇZU˗s5j9Db2o7֮]gHHH@ٲeQ^= 4ڵQЋLZZz`i/"2W!_ܿh߾=;whDEʕq-Z.XQZ5uۗL撆퓶1""se2BtAkĉhڴGFDze 6m!C`С? "##agg'{_x)^}b۶ms{{{m 63]իW1Oz%"""",-LȬ^Z x 6 ϟG|82뒒!D/#җ-+Kh"ٳCJ˕+g x{/9_ ȔXۥK}vy5aT^]帤$,YfBRRRvѱc< t[H)))ԩJ̒-L( ̜9P^=^QlYݼyǏ70رcѪUM/[W޽{6m@T/ĪUPreٳgF?} ȔXߒ%K{ 6mNxok? .vj ;f! ȨRRRХK>|XږxyyyȈ 3g`޽9s&D 0vxôhCΝ!@jpAGzehٲ%?+VƍqIDGGh@Uw^dJWOE˗(]4.^"Ez^bb"zPbC^DDDDd4 ȒpB ׫ ;v4,Ǔ'OPfM|RP^YKbĈjի1x`|򈈈L|) 888=zooou0`IKKC߾}{nM|qyC""""2d^Dd18!t?w) |L<2ˠT*g^-ZΝ;y42W!""?JvI1Riܺu <L|=|e˖=../_>[m6tM~S/uЋd.X"/"2KQk׮Mׯ_m۶ٖ"`ܹ Sh޼9]fQ5` JC AbbV_x֭3XRSS1h !xI^QF!** ;wFHH<<<>˧s{NNN_ B>5aEDDDD 9"mX"='dryŗ+)) ;vdſӧxGիY+o|Ep^dRWm޽سg͛7޽;n޼ ͛7zoumTV 6mһxO/""""Mrr2:wGJxℌrǗ;ۇ?#3/[,XBz<2tWnݺpv튱cǢ\ry&~/e˖8x d/3"`2oɨZ*>|C\\>}ŋGzz:=̙za߾}ߐUŋ@^DDDD$ MWXXJ,##"Κ'dӱc8q(VڵkΝ;\M&BbÆ jϟ!!!hܸT1ժUѣ 0'CK.Etts .CN:*YkWӧ_|]ٳgcԩ6l/_n!Gؼy_l%Ɲ;wвeKDEE_@:t 40Xk"U ^Y-[O>ԯ_͛7j*( 7nA}yu͛7UkbEDZ'dbbbЬY3/ B޽WXv-s<ܖG۶mqỶ+nXh}B|7M<*"^t IDATY+&O3g`ԨQXlv'''lٲCR4oWWWtIe1zΒ^#kIMMEqm@ձg %%h۶cpfhB~^1Xk"F ݗ|ZJJRUDzeY.]={`ٰw ۶m|YFƍ,7$""""d^ǎe^%JȻV?={ETT--Z`(]t^Hv7 'OָsرcKe˖ԡze*AAAׯ,QN}ڷo/;Q_:u¦M?~iìފDrbr/uk$''v/HDDDD6%)) ;vT j֬HW~p<ӦMS{M9D"„̉'hӦ|+h ݋^z!--M6.]K~~~ h۶-Μ9c⑑1B2w v͛KW˖-~z>}ºu0x`xzzVpp04i'Oh1c`aEzeN9m4QdIqѤI:yHLLB$ڵk% 3xbѧOQn]QH1gϞa l^[% 3,ׯ/vZǦUV2ea͚5EBB6l4}pttosZѣG (O^O|A___[շo_# 1g)J*#4cEDDDDdle3gtؿt% dpTzEʕ1tP}_3fDNٍ7_{Z2MW… z}aoo/ &|-}HcZ!xQ`2_GŊ3Y:tqqqZ[bŊ"**ȿzx|hU/ &J,)֭[p'd&NvB BTf;~RPls V*Ν+>Si[۶mMRΝ;wT&|}}ʕ+T~A*Tze ^w;v^~WϞ=u8>gggq֭\9y$/WkYzojԨ!F!ƌ#>QV-é*UkկW^^B0"""",^111y=4Rpp}gy=" cǎihx IIIK?6=z$˧$… 2NrrZ;OT{׫WĸqT`el^|nݺ&b ,UO< ѣAc}h۶ƿ~x~rr]6/29+u.ŋ`ݾ}[L4Ixxxdɒ޽{Z[eB؃@||<>cKjժÇpy82둔+WbܹqQ ~0JD`ʔ)={ hٲeJ>7n͛7k֬4hm{QHm6l@TT\\\W_iL29rVc+V ձ?3f={ƍ/_>,XÇ8mΝ3ʘI^LׯQZ5߸w_ܹsuԑźut#88B@R o>L۷#::Z۷oŋ`h i|EGGk׮HJJBҥqitQ~~~3g߿ѣGAcO>\Э[7̟?_+",, %KS^nDDDDxݺuK$e'Xzu'2y s!~(^(QEDD___wPD qΝlU^]]tɵgϞ GG ȫ )\\\J{hdzY&@bB>o߾SNjUT~ʕ:ѣG2nR)zowʕ9?ɰ^Ç /^ܰ0Qt?uMJ(Sʹ*U2+21""""qqqqaÆ (>>^TPA\ZJ־21˜~왬gn4ɫ 5kGGG}vxÇxzjtR5;`?߃+K.W=M2E=3F6D|YN /==]dddhe-[S 4ڵÕ$%%:udСl}ʼݽ{WmƍӫѸq͛7kVr6ٴxkgΜծ]K,00wUoųgd+%%E9##6lLk֬A?6QNjɝ9Ocs j ϟ?'f͚믿ƍ7p1,_v۷/ .m oÓ'O>ɋKctըQ~< iiiZ pٖvssCPP<<7d_6.oooO*۞>}S(G$7+'dooʕ+V|sN|jغuk0""""Ih۶-2 渿XbUzu瑑Xpl@ѢE%11Qֶ 9s* UTGrr2\"=vZ!pYxzzt ˗WhQh|޼yq_|ƍ>۷ԩSqq9.\ƍ 55Us˔)|̙]CUU*^O +åcҤI(\0+ٳg/K.!22Πl2:UN_l@׮]:zٜٳҶЫ H ͚5Syf͚ٶ͜9ϟKDEE.:y9!w/OePQQQBH7lؐMvޞry7n0vuoVXj.\(}O?xصkW3FNdd$V\y*ϯ\y4駟l+Plip ]tO?W^!::SLA׮]e n޼)پt8o-\0s6mڔc? ӪU"V^VT\Y(JYٷo_{-KۙN8idmzY1M׫Wzhg ѫW/#GLprrZ}%"tQNiB)S|~Me'k8{ptt*zիWe闲k߾}߹l_@ӧ UOIIReNʒxϟ!V%DRRRgddڵkkvvvbΜ9zqd' |j8wl}sݵkΩSd5ee\xe}x{{˗~e.+@̝;WsF֭[G ł ֭[O$c2_|)ѣG*V/6x\%KD6m n+1""""" ,BM4qRE+%%Eߋ!;;;Փ- 9A bذaFkDD8w]ׯE``С(Z...aÆok7oVJ*%o#Qxqf9z״ >ʕ+'VXq)fmIm-ZT$$$zR'NzE}cƌ믿eʔWPA<~ؠA+u}QN_X&N}Ϟ=+a0' īWDݺuU>6nܘdZM|)J1}t'2NNNbFzdmBwxTV^ĤIĺuDxx,KӮYFyvlBH"Kooox 9QFiGEEGx$^}wïUV~mVj履~ WWW@|z_I-+T*G}$J*|ĈbŊXg+JѲeK@ԨQhK4C/""""+"ZO| !ĕ+WDÆ uV8{^5*k1$ʜl(Zhڴ2d;wصkyf~oV]t%ۄǏM<ݶm[G.X s .,&N(>| i&i"핸Ν3ůXk2w h]n_^ZܹsN;{ݻ<^/>{dtWmժU*>ׁ}5G?Zy5 e%^DDDDu>|.Oծ];ѽ{weKTcǎ 777m;99͛?4$+k7V^WtA3F͛7?CL4IZNIa^*J.;tO uB ݻwgkwذaZogg'|}}E^D߾}EN >FgT^z%\u֕~"44To^ ty?CB={ژ={ίĉ?9֪UK y V+ ~>?_IMMGΙ2e/l !"EGGuָr労q Apd/_bȑ9s&ʗ/HOOǢE0i$( 7o^fdd͛|2ooo4jzW IDAT"uLٳgK-[7m4̜9S>_~%JFn݊ݻ}kƍptt1bIs׮]Xx1bbb4SN~6RcѢE?bp[?RL%,, ֭òemױpBlܸ:]|yЍ7PF ( *T}4*UO>U{%K z;t+9y6mV{Q\9|r>}y3g4+#2+cǎ\>W|m޼{ 4^戡be>v-M,k|ݹsG*UJ\zU~__dluBF%K޽{ ???0^˺tڵks=^PVZxe:~ GGG1a.?kZׯs]YӣB b9} jѦMƪo={L5uT̚5K>GGGT\Yk֬slѣGz*\˗/̙3x𡴟2޽{ѥK̙31e[j o%J+W;w ""BzгgOAcGPP5j ,,̠ϧ)))(_<>} [n_+VĔ)SЯ_?888H۟={___$%%@xNɈ 4hlق~=z@jj*vڅ@=G{|esv܉K.ݻx9 .bŊN:h߾=6m '''C_yԍlWx5mڔWx7oވRJ\a_K.1u[м,~YTC &ӧ+Whu^NKf>˧['O^28qܽ{VxB.]Z+'22Rl޼Y㣣EZ|C/""""3)~2GIl޼Y+SnWnDRRtR-~ M(uB&...-M>]vr u׳gDɒ%xOzO~7u W.ǐIOZL-keoo/n޼)k .ޣ}b̙p:_UT[lf͒M>|(ǰIG\L)k@GRR(^ *v؄/HWȺXELL쯁W$ʖ-u NiK~ ̔Yf ذa4JŊe2|`E`2^...m͘1C6H>*U '''lxerttϚ)xFY"pR9{+%%E,YDx{{~e>&L zw-[=zQ@s_^z뒟x䉡/f؃΋/ЪU+\vM֬Y3߿^rq_DDŒoݺu zln:888e,dLٳgK-[T{ァoXbZ9sLL2E |'رcG}=z4NhҚ+S B~=..}d﫯jl`` bbb#Fݻ?s_K,AttA%U8pʿ7n1B(PBÆ u!!!UwG}Oܶ-bEDDDdf?VZ6^^tAAAFnݺcx1„ݻwq!̘1CcȐ!:MfiۥKЮ];ڵ+uꏴӠA7nĖ-[x@BB3Gӱze LG/z˗/ҧ;Əx5͛NNN4hnܸ͛7zZ4^"C^=l[p|FxB Ç5_nBV_7oD&Md//5#"""y}͛sIC 7dQ︤!.P(TϚ5Kz֭BT*ŋEƍȑ#ׯ/Qzu:dkE_ӧOӦMS=z4{*&M$J*eВ^*=~xC^iZ땩[0G֭ٳg ;11Q+VLZT*Ş={|՘ 3>Xٳgֈ-[,ix_b߾}"==ٻ(m. ҤXbcbA-F5j~1jbѠhL4jƆX5*"X( /ceβpkKvfΜqq3gիW/7o\~X2^f"!!kԨ˂UVMx=c˘ӧxA(2r;uǏ^ߘݝrQ)Be?<ժUXme2msJ*x13ZJhoɒ%z > ^hj̙3ܹsgE ze^d2/^\e;ʡ)Rxyyq||}D LixVZaJC r!$S FEE̘Sfdd()  ;;:ttB'N "eI$WT9lllhǎԣGJHH ???ɳ.22wP;Rک*{ה9իhVU~46;F7vŋjcܸq³V^Z-ZЁٳԹsgu}ʕW?ze~R)yyy\߹sg4TET'NP2eDE2uPة+--] R~}~32pذa񕝝k׮~M/0|r\\+VL܎?׭[}3f ِ!C4^믿* vssSAw[N}5djLP ׫$˹m۶LD'_~ .ӧ?u痿??^B#F0\=z`T&M2}m^=zeƬIII S\+[pW^LHYծ];NOO7u@sb_r7oŊ㤤$u۷oGFUd:uwޞ;5j`GGG4jRRRH222^{~{ T .ԹΞ9sF! Pv\GAW---gϞͯ_γ.==ׯ_իW+СGDDhݗa1o߾ `+++&"H$uVQPʼ bccgv!B/yBB&E /&"6mGFFSd6lؠw^xBhhK$?B \J<ﱲgiӦj4h/_֪/ׯE ZYYիW>e_̕L&{rƍ ڵkgΜX .8p>|8 yd\D j1c"B/xYa۷o3g"b32׬Y DWd 0 lZCuKxxQ~~~ Sk֭k.Gy۶m,նyMgiZӓZ6M6FPꕥq]~v޼y¶}dz0eh߾x]x?ܹm+99SSS0`/ G,ÇyŊܫW/c___8p XoܸUb_ׯ__lTa y r*% qF^ ĉ`n͛\|y([j֬ϟ?+ ʒEGG44JNNf777&k׮tze9BCCUr|EGG+wy]|Yx+/ '?^ӧ]u1!777̏(D0 r93F޽{MMqx(ɸUVJߣ!CQ͛ӧD;6+;ްaƻk-u;w9sL}JJ^L_Zjyꌳ3CСCLD\t<{Πs,lzQ\\0uVұcG^`ҤI{VlY^x1;w\5J+wڥ8ASeWBd "E0OMѺ}MСC˜m۶֗-[T* ںu+)SFaM2^J: ̬YhFr;w\.71ݻGVNJ'N`ڻw/xB$ /4rH322[ntĉ<233iȐ!`RUXʖ-r}Rn$Hhȑ#JOOOF>r)11Qi^x{{ƍ)22ƏOvvvz*۷/zd_PJJ uЁvMŋga^۠A?T~[HHy{{իiŊԠA:~~Ȑ!deeفԩ@A Wq/ r 8p徒S;#GUxϞ=+Qa+O<7ݻw`ݺu7j(YveFv` 5k0ŋ!x֬Y\hQرcZKSED666gQl߾]!⠠ j>}`@^JNN`.S[P^,Ⴈ޽{1mۦԬ666||WA  3Çr45a@WquѨQH.4a6mɉ^|w_e)wN:ENDDTH}мyݻw:M)SL&ӸD"UVѨQTnFDDdccC;v=zܷ?7nз~KǏsu҅ǎkhf)wrOiԨQvM63.\rи8>}z~([ڴiu=dr:!?~hipЌ^eo>^hX>M2%ߏs6m{yy+7i҄.]ʩޗbbb^,?֯_14bf`"bz d^DĥJ2I&1D"ᐐy)_c5h qu^"ҥ ;88xe4_C Q|effWD fz-+ˑ^n]#:%___zZ@@޽SZF)|UZxS>ʕ+GL};w׸8;w(]?yd RM6tY^ ͛7yޞ8@mڴ8/y3ԸqcQL]zer.^+V=xJ,)qH[l ҥKDkt;K[FU1B:////vLaP[z@… BUBڱcy^|I'OTѣG~F9pVTɠVPΜ9C͛7W~͚5 $[v-/>|XiEDN]t'Nr͛ÇNoq^h rY[[S͚5^KIII&z;>|(j^P֭)&&FxW^ mR:u>mڴISRR`kݺmb25jԠ:uPfҥKԷo_a֭[Ӊ'TR-"]'!9tEg777:zhgQxx} FݻwGeT=zmөk׮Muؼys #;;;۸ѣGx9+m^Y ym˖-"1%SuU>0bŊQxx88q><===iƍϗ/_0.h߾}T\<٣r?[[[ڻw//̜9SeVZѲe˔sqqpjذ(ER4A*W_ѱc n?%%_""*Qzjٲ/EL=hтn߾U{_Ν;Ӂ $6 D*wЁ+tυ?_pAN*QLڳgY[[+~eюiժUDDTjU $__tA1%J/_/czUqF/+RЀtn7>>իGDDD'O6?^"___a:"^ٳ4m4w}8::җ_~Is%777{ 5nܘ5nDM4%J==xnܸA YYYѾ}sڝ> 3j(Zf խ[]tzяըQ޽+ܱcG:|hz /_^b())/.1@ 6lm۶Mz1K. Be\^ :\.UԮ];:~m+ R222ϏΝ;GD.2eʈgB/\T^۶mS9 ЬY4NVT)ڰauQv߿OC !Hhʕ4f 2ӧL2TjUx UZ޽{GDDw咽={jߟ9ږ-[zcC?S9==]3Ә1chJӁM6:[jܸ1LԨQ#C J^f۷oM6њ5k0+󖖖FG7o5ժUNۃnݺj^:OԥKm=~zAW^^4hmذA``fﳻ;Ӈ߿oꮁ'NTx4-ּf7o\c|aĿ(l;c|ĉ|;ɓ'ޞ9&&Ơ&O,G:uX.kg̙y~ҥK%k m.N&СCUX>u:uE; ӱcG&"vssM6;&ze޽{sŋ+Vl e+++5jīVDyߋp%[n^!D"˗k},^x1;88|J*qDD1LNEDܬY30/^p>vҸו.]>|hPr?~\h~YXi;;w"2"S+Ntt4(Wݻw甔Sw ߠ^ԩ{W˖-9))I6WXwŋW+믿o H^*11;WWWyvvv_111~1^zrw 6T;͏?6uW|;vL^9KjѣGZRT- j0>^PEFFrٲe>1c{7l0~6AAA*\\\'?ޠ ,c"b[[[>tmr۷o9<<>fW^||} $+󕚚*\$HxʕJ;u+WNK.ƍAZ^[ .x ^P *Oe7n bUч>|X^ZhK+ggϞq`I&ZߙveЮ]zJΝ;^}]H|yNj3 4ҥ0 SwdPӅf޼yj}1רQC+ǵkxܹܽ{wd\2wܙgQ ƃ eLfkkw g},ZHЍd^VZ֯,RM4#˹o߾immͣGXmm߾͛7War%w˸L]@Ç3ч;`/^h yKJJ>GtA;MVZ_`$PDFFR6m(>>^x?͛7 {X|9M8ʗ/Oqqq:Mj۶-|2:DB˖- &U̚5ϟ/looOaaa/?uPzz?@>>>{˖-4p@"";w}222hgK$_>k׎ʖ-Kŋ8ڳg]tʔ)CN"OOOΥMҋ/ʊjԨAo߾*֖KW.S>}T...N 648hm۶t j۶-;v0 +O?7|C\BjDPٵbŊt)OE-%Sn޽{\L;,޽{XbzTz@Y;T-[Gd2]ކ oƌz;gU?|PVԼysu3{*mmmŋ}<˸L]@;Ϟ=UlM޽2u:uJx~wKHHEqժU5!Cpff@W!==L20MXbLDsiҤƟӾp-T-%K1cf|5mW>1u9rDxڷoq/H":hze9UI$yѢEݠޙӣGa5k_߫WK.S{ëWbJC#2ud2nѢ^uƆ |Ҷo޼Ç?W+++:Ŀ;?^6˖-SZo߮L&#0a޺uK &M$i CY5tP^… ɓLN:53g/0:SȜg󌯬,ްa(Q5k 3'TV899Ys.LBzeTQvmNMMU^&oƁrJ~}6A7of"RJqݺuu/9 wMa 8p 駜>aaaloorcǎZcӦM}U 9q{SfM~(&&& w{yyy ak׸W^.t"^n^x[r>v3vݻwÇowѻSLa"L|dz}G͔֩sV\|Y(ȑ#9X^`^Æ Ce޽Ea'''>{,337nܘ_s{gΜ-t=2/"Zj~J#Gd[[[ïF ?+WN;9Aw.\`;;;Xw|5J?g^z|H!!!yi„ Z33]tIɓ'vZq:JPn(##R)U\Yu}xٿt֍Onq@5S+PѣGԨQ#Zv-ry=m޼ᆪwމ/LFÇ,>|8& IDATى~ ^Yw n޼9]pY`N?~n̴f""j׮ e @W˲mݺUt9T߿mkחٵknZ|W |ǵSgٳgA܍s1c+VL;˖- $;;LJo߾̏?z펯L.@//<Z*yFӄ^z?r\+?^>3~hdHNN2eʨ 4/ggg:t(Ϙ1[h!ߋt2ܿӧOϟv܉' /[L}^~sŋ4xsA{gϞI&qff^2jUjU!lۿ|988[ =-P f͚xh ::Z-Z͛7CiWrr2Khwb:@Wƍx stt4O2Expl"( F/v&Mh0buN>^`,5Ǐ7xz m:6lP|U,]Ԡ#S'''u Rh&˅; ?]Ɲ;wV[?۷opG3sBB0p{)^8תUkԨ666 ٹsN@ze-Z_9uHGuq?.\PyCfdܴiSsssS|yatyf^L= cH{#G'OG||^ܼ,ްapdɒWi&+X; ֹ?S+ΥKՕܹ۷oW;u쓒~~~*f͚+P!_^H.ZhZ1a^z5;%\.ZjiCW *24 c&".R/Z߽{!!!,JU~94iׯ/7dDvvv#G>}^ᗝw~}B;s1ܶouQ%K~aֻwo&, }ꢦjժ+3e}Ndz[|ڀJ=իp@Y蝙_|} ʼd2g%ݛ% iF޺uK=<==իWB/0[׮]CU@s=رcy֭_^m5yd}^/e@ɓ'x ;88Dʦ#[`(m 2_^K.rJ *U(A@fe{X933SvmVVV*$M8Qf͚ܷo_LAə2PyڌU107ol1$z x;wN[ ׯ_k|+WD9VVV{zz L *ltٳ':t(Ϻkr"ETֲƍszzAP^͛ YZh/^й=1JJJ^ 0 sU TB+[R)Ӈ###=zB}u ._a!WFFK㸻+YsWŬY41B mרQCzN8VVV:}z1o۶M<(\l۷/Q SxM8-KWL*U׵kpWUa}6 S~ݻw?sů >NNNLN;ooon֬׮][PӐK.+zu҅E>k`.|ʒ|+ʊo޼)1NhB ԫ5g/(ʊ7oެq4_&L~B/0+W PS,ڵks]!*^^SVi a%K5Eadz^ݻwyȑ 2) ۷ogkkkJ77o֧۹uF cccWZŅ;v4A\,ь35koߊrܦM )SF6tz޾}*T:Zp~Zc! Lʕ+'7yd='NL&S&%%9ƍzqTT^|9::rxk : |s9sf -ZPΝ;>ɓ\H*\ڷo) rdeezeY?Ύleeŝ;w_~DcΝE]0`fE8ݠ^ի.zj9;; t>֑#G>S KtVX! XrLMWdJMM`.WNWo߾>˗D[li_`}JDD^^^t *S}Gj@p9^$ˉtRA3gΤ&MUX*WLTzu߅UH$ԴiSx1`@0-Zеk(00PٳgCxx8YYYx͝;f͚t]vv6ߟve10WC@@޽lmm?py{{ɓ'5{:txUPA9P̏T*%///;w,zEDԩS'ڳgʚk:u/ B/0sΑB5e^ѣGŸ_x>IIIxb-Z… ŋݽ{hԣGW8g^` g}F7n{Ul=zN:+nܸADBwܹsiJ!2-+ˑMoߦӱc… 3|=}h*xk׎oNDرt;!^RJ\e )ʁ tf`'''9LbnfϞ-Vyذalggӳ} ۷^`TxƄq_y~}||Lݽ#w=y(md2ݻ7eFP_jj*]u癶988++Kv5=+͛ѣm6ꫯC%F[@2wm۶͘޶mzyyq||ю B/0^ˮ]` zjnٲAˎ;ah0 ^xsJNDdnR(T_r!2W...:}}iu m/uK͚5F@2w2K(U0f D#af&EDD? M:,Yb^!222t TVR*VHO퐐6lVVVqF߿(ǃPӧOo߾t9Сmٲ/vR^4N [boɓ'};vk׎iܸq?|IhҥcxbgLi@CUp-\fΜiPգ!CPvjժLvoVnݢڵke0 Mf8rHEi;++J,pǬi֭ԧOQ ʼEGGS6m(..>L-[$gggJHHzVmUR8@^^^j&j߾=թS7oN;vEjRzB :tprvvpjԨmذ*z𕒒BRٳ'ݻxLz8gϞ3iL-ɻwQF:O#J[n?l;::˔)#v|<3(0DӦMS2M~~~3T}Lu(>+^:[YYo߾ͳyʔ)󓛛ߺuK5MuئMNJJ2i(ze9BCCՕ/^Kxuhvuu3gYw ^ 3g *={ժU*첷篾JgF>|XwٲeF>(0 Uhhhz\xqnݺ1qǎy֬YydܱcG&"P<'Lj?K-[N߾})--~'51cU^ShL/0‡Y(={FDTlYjԨf:uSN2P,X<תUTuy{{Q`` mܸfϞMS5P``N*U ^L򢘘jٲ%>}Z6޼yC{Ǐ&((HeM'ORҥu':WX:|0uԉJ.MO>U233UB9{,SZZ/:z(=z"""(%%ҨhѢ駟P׮]>pXl_ҥK%$$A : Ȁ%bfTJIIUR DժUW^Y駟ÇK~d2SNъ+믿֫ Jcǎ%kkkڲe QժU֭[J.P,ßIC%"-[Pj'++ wxT;!{GAJP@~"x$(Cӣ ( M"R DE@z( ded$3ILk3$3뙽s/_>j@ٺ"h?CpXpñc̋/hrֹ"""L.]̱co߾Fҥ_sL 8p Xb)r%̓O>i-[f\n?mڴTzv$+8 5GMu%44̟?듕QG-N;vj$o73p@J_+Wvy5k֘ Cz\}P2כVZ.TPtl޼٭=W^}hzKhxSy=)y%wf&!!繾;bo1!@ozmܪ5k46lp9Vddd۶i޽;</^4mڴqڮk׮>ޝ QǕ+W@tA;d7UThw_1& :Ԅ`3uT<dmԫ믿2O<۟7on>ӧOOk2ӧMBc M/` 9szj֬Mu_Ǐ7qqqng[nɟ?d:ug Uz\CBB;c_4ޙ3gLJ6G'4 ,0Ν3$?ȑ#ft)9ӧ / W%&&k>s^V5+fLٲe$^p*Zvˣӻ(P|g鎟^3_x4jqR%J^#^ݱ~o̜9ѸtٱcyL*UPTZ5sٿLɒ%Ͱa$%%':oJ2Ok SD kMdd4+W6AAAu .8~Sxq'r̙"_|sIJJ2< /PϪU&O쳱] ?k|ݸWעEK.mZje5jhnwܹsK'ߐ^RJf„ fԨQ)|ӿ z5]n[v- 5{ldiӦMͥK|%KL@TfG|=zԩqaڷooNj~Ws1ᅴ)Sڵk;WJ- Ä 8*,,|)0 IDAT=xy]gϞ)Lrn|vd꣏>&U`3gӿ?OgϞ_ݻk|W?;/Z;wnՖ-[ZG|/^<ŗs_B+p;vΝH2 4pZj"-?Lwr]v)={y衇'Oӯ_?CÄ IRRcٟPߦ.[t]wǏɓE]G?UZzӿ]PP>z.wwQ2;*Qٿ={ qf͚W_O_aaaf͚5>x@hzt]4qcw,c…fӦM~_4Lܹ=+[lI3fʕ+e˖nS^=3asY_}o= ɬZ^jz)+U涇r,ub 7T7/SسgO9uꔹ;-\b"##9++{?qTcPPPG|}w&44HKD;vf͚}QHH>}Okٰa/znw9s[l߾ݱ7GxGzV\-[*..q5`SeMpyeTF Ƿz6nhy{W4c ܽ{~T۵vZ͛7O=Os!{d[lq|ڵti5nX{ŋ>*"""|rrze+::ZdI 6UV~WJr͛PB)nOHHPΝΝ$+V̫#8[Wׯ_O111jԨ.]^1cMm\B2+WUVN A6ʚΟ?SNzѣGzox>}ڣ% թS'͛W۷Wxx׹H3|7&gΜNKX 4XYʱc;c~#GḺt$$$x-[8ѤI>M6x;w>!)),Y4iZ?n6l^yǘ毿rSNի[^2|U^XCvXƌ3+VL\֭͹s<Xb1-ez彸83ydSf4Bxxy_ݺuOJJr۷"EX^0<88ٳǧW_uGÆ }:>&d۷o76{nN;)mcq#<3oK>Ku2]7ovٳ 8]nvn:\| 1oS=X?ܣzSܾg;wN ҪUTD ƽƍ+I*Yqo;wN6mryŋh߾}}Scƌh̛jJ?xKk׮Z~J*e9wΜ9G}T;wtVxq :T111ѣGuEm߾]/rʕK,ѯQ2eʨI&)nߺu_O ,PXXGlʕy/Lx:tݱ]:^:uK.ٖˎozɓ'W'LW^1Ԁ3 _KHH0:tpjݺuGSƚ-[ '|>,\дnڄ{dD…ڵkFdFHJJ2_|T[Gxlذ^yܹsVZ/88ؼ[?Zjiւ?<_~e5m$%%Y}իNuǀB l-\-[֜:uHo߾~ 53fjI{QboLג?4I5rHOLL4Zu|rꫩYvms K.Zi[^yo߾}{==EC GiӦ~m|ݰuVӧOӨQ#SlYd (`*UdZnm>cs H;/^4<˗/YrG?>MRRW^c>&>>q1_~q"""LllqB ld4Ne䃏??ޔ,Y2 {ҷ9&f͚Θ?+ߩ3{lHLL4QQQ.kjb,:w)^x\rYɓ1F5,eCW=z sy5m۶5|Yz_̆ ̒%Kȑ#MTT)RbfΜ~ndƎk1f~k|%&&Zw\b~aWpauVǹpႹ]֝R_~%#%z]vy4q$]Zd$^d^ݱ!C8^H8Yti_nkTHeRĄ o*sZҥKxx\p NsSNNX]~|G&$$ir6zk׮.]8^9s7|Ӝ>}:m_n-Zd6mꘔ NsO?ԩu_'O47h;W޹vѡ 6r)MZ[/9s47'OLsXK/}ٿl@F@6|C[W^u:o;R Æ K$SD 駟:iذdrՇ=VLF{勣Sunݺ^9ttkuPPyG͈#?~s1vZ˧橧"%n>j%,jG5.?ݗ$SNS@sY +$%%g}͛'{W^<^bbi۶m%SO=e&Ol~W~sQb ӷo_> d^dq˖-Kz펕̝;(P\vH.<{5'N4Ǐw>11,_y睎 onń aڴiNGPEEEl *8>^ٽ{wj5k/f+7-[>|1=ܗ'Io߾^eENRRٳ_DzGy?ޫ1\b4h<; dY˗/WTT^*I ȑ#էOe= .t|})4448qmۦnݺtҪP|A5lPe˖?={(88XcǎO<ɑ 0@v\ϕ+.] ژ nz畔nsޤI?~  Ǫ^/_Ʉd+:tbcc%It42_5nԞ'Ojǎ>zc^u92}s~n~/q|^?\C Qxx1[oiܹ :Qhz-[^4c޽:zlLRbbt[ǎguU9rp{P ڱc6mȦ?Ç_~.\gU޼y}2$mV;wT.]<:zPB8q/^,WrUM:UTdI6'Jm۶9~>t/^yF#nXd>cϒz"%DGG+&&F5hۊ+jŊ<d v|oҥNܼy;ݻݑ6mdSP!s ٿ2d^CBBL {g=Y瘀?z. z_7Ιl۷ה,Y2ZÇ .-GvF/:8izDVk֬֨Wqu/WP`o (`$%Kx=6nh^x7o^'w&22̜93ӞpGϺgv˖-S6m5jTlVr1'N)IJKÇkҤI)sw(::ZѺtݫC)w*Qʕ+R2!#n5h IJh>|X֭$uE+V4;*TCjС:|bbb_)_|*RjժE#o}k֬i_7 0@o={ŋׯ}%IaaaV^yˤsͮ_zJgVTT-[qKvڪ]&N{*&&FW\Q|TD ժU˯2J1xo…zꩧtuI42R5d5kj˖-6&r֬Y3-[L!!!ڽ{#L/f̘{έZ,-۷ٳU`AܹSԦM{nJLLtL$vmZ|A̙}?VHHO)SFeʔQڵUV-=>} FG(#l= Ă LhhR+G;Vѷo_e!S]J7/اO,>}Ӓ{y'LZ]H:;wcbŊEB }sι8Stifk奁WQ^=k_tDxbir̙cDDݻKaj9Ps뒆7xoӦ?ᗥ{ؾ\r&wnՕ˛cǺݻMHHM\\(4pO3fݱ[?`J2'O;ŋMXX`'&d_|UZ5qFSP!5~t'ӻ.\،1\z5;F޽P'22'c? >q=qfӦMn|z7|5ouϟߜ9sXv2=z0yo1""|WnƗz@ZWtRnMbb̛7'e˖;'Zjŋz뭷$Ӻuk^'  @͛7/Ekرvʖ/^GPPٺu ȶtR bBvرT'nuaKGs)S1b9y>]fڴixܥK|5M05n׮[G*ܐdkӤI䳿Ðl22?>IP3tP/6o>׏?u>Kٳgwm$'c@@?:tׯK4f IDATNpoÇ\r)noٲ/^\X`ڶm+I;v,+PTոqc>}: 0@t\?r6lHʕ+zK 6T"EtI=zT?,Y;vXʗ#GYrȡUViΝϞ= Z^e WwѣG+$$$Ξ=Yfi̘1ڽ{_͛W?Vco߮h}~ռys_իWK>}ϟ+!!!DŽjيrܶn:EFFҥKڵk_W:u?SGʕ+tR=zRիWOժUӕ+Wxb#7o27W_57˗/OEXvZӮ];}qiذaFOy!b޼yСc ;V=z9'|}O?> N=#I7n7;A pwׯիW+44}?^|F+Wx}uV/_m6}{9M6o?ׯ4i 1O?+xy|-)UR7{W5zhK:xy}JJJxUjƍ PW׬YTϱkر?,Y$A^VZ"EI&YjxIMCjϞ=z#G-R^~@ׄ Tn]۸qcYq^R.]hN/^̙3} z9mVfJ|7.\XÆ kƌںu{1ZVXA M/2shxqN;zϞ=` Llݺu`կ_߶A ҥKkҤIQ-O?v^ΨW˙3-Z뱂ԼysmذA~~aoذ{=y UnZd^VXUVVZ>ETT) 7 ;w~ ݻۜ nݺD>ѻwo}ᇎ7nHK؆zxh|_)&&F.\PrTF ^dB^ǏWnlN?~\w}Ο?cBBB4i$uyhʕ+>kw1!$&&F5Jջwo͠TUwY͘1C˖-Ν;ui\rUV-EEEf͚~I/:ZJ5˾Pׂ Ծ}TW9rh̙j߾}&^d2s3}Ժu4 ƒ%K4h IRկ_?2ȪUիW{d|>}dP*xzw:uzѢEmJz5iFfRhhhILLTǎ5k֬ Ld}4$nmxkԩ1'((HSLQ }ŋu_~iQڵSbb$i*]O du4ğ_|Qw}FӧOMBBf͚jժw4J*e˖)^=&d]UVMVroz\\:tu:"nA1FT^=5nDWC6m_($$$$&&SNZ`A9vZhG#&%7j֬YرAqڜ {nh<ȑ#իzHUTQbŔ+W.]pA֭[W_8z7ߨbŊ|Ƙ۷q~!7|࿿gcuQ۶mS2eo>;rDK.U%IaaaڴiWns*duԫgj߾㋯j)kuEǏ?e˖;.hz`iӦK.JJJD+UΝh"N:ZhJ, `BU]vʙ3֭[%K(11Q ʕ+ugPz}c||Tn]ǗƎ_~'c^e_4$qƊT\\kOʕ+ ^dS^pjxM:U;v92̙3̙3>788X={￯0  5jȭ%ho?~}7Seoԫ#))I/ .>׶mԺuk:tHԳgO9GIרWX`ڷoׯ{ݝwީ5k֨TR~J>^d ^̙3:tƏxǫUƍD*|  u6hx*{9scG}TSLQٲe=#!!A'Oo+WHz1c8-M  7xO?U׮]ix5i$M<~z7լY3-HLpE˿Wُ1FСC%Iѣw *d :Tv풔w;ިW/^hz\5Mgyd,1ڲe/_M6i:~PrTV-=j޼J.mcjdULۼy4h8s/^eocƌkx-I˗Wu=@ʟ?N8C)&&F?rB4uThŽlzL>];wN~x~F V%%%… ו?~!;`B\5dȐ/$iѢEСEUhQ?Q{L+WLq; /s,R 7U`A,X225M6Mq /^֭[kɒ%ʛ7o͑#W~[>c^;ѬY ;YՔ)S/y)ZQpƍkݺujӦۗ:2ed`2dw+eZ%^78 ?p>}: /2wVXQjժi֭j۶˖-K zO|׎ixޡM4ydKN 3f)1!xիzuy^~FԳgO\RŋwިQ#S!;^Ǐ׳>+c /Ghz#5:t`s2H {}~^~F?nݪzH9sOd1v M4Iݺu 0!Δ)STZ5^~B_UV)22(WAk׮4\5fΜۜ RbB@^+IhxȔ(W 2O>Dݺus4BCC5gnd2 @^@đ^x@„ @A(Wy1 / z PP scyC{N sUV6'(W 2? 'Ntjxi1! PP ^cȑѣSkΜ94dJL+z Hȑ#;8«e˖6ט(W  Gz ^ 2 @^@ #F `0! PP &7#FP^4oHo: /2 @^@cyC5|5oT2 @^@d1vNÇכoN @fƄ @AiKqqvM q7劈ɓհn X)1%RN)dk4& Le ]5@璴T @6`4p)2%ȶ F @`@^4 Ȗ zq=<<\ , Sb@^4 kbyCɓ5qDc@Ν;8B ʗ/3gСCXc_(pz-gΜ;FTItI%\`*z?-[ܖ{ܒݻwEY>}_||d*ϟܹs۶mB ٘\ٳףTHk+}[J7;!i=q~9ή]t]w9o߾]ժU1~p\߼yjժec"pz S4HzmSpNT!r BCN+]Μ;@ʙS x?$M[%&J $/#Vi`Ś5Сv[b/_T2v?d*2-7WƌΟ; hPFΞ; h@HM/HҔ)!<ew g۶I&%/{Le i,SݓLV>kWGNhz@zfϖ.;OS87O+S}jN[$$HӦI7ڝV'7);S~; W*U M/pDž ر޽v'ŋ'7)3ѴK҄ Ү]v'EHRXIenN ${:LN; T)Lxi(Y N!ii^}M/ܶmҔ)R|I`ETvpҤIҕ+v'-ZHO=ewlXrvU]J ڝwI}fw XեԸ)5^`ܹW_ٝVEGKUڝ…vU}H5j؝"ۢV%&JSJ?dwX-*ew#͘!I`UtT)%^K ]N+InRٝo/K'JfwXQԯ+I^୓'>; T)񕙜:%!>lwXQԷ)^ J#GJg؝V<+vpvpr)u=N_>Dr$eK驧Nߒ:|$Y3gNm_;Nt7;~O; IjM/ Nj԰;E NxC~Sdy4׌fL>Bo_lYS89SZo_\9Sdi4.]J>۝V,ܤ;߮\I>gܯڝV+EGKy؝$ˢrGv'+&7)2ӧ#CN+ʗ|SYM/ÇNٝVԭ+iw gGJÆI'OڝV9s4~Mcefͤg;ݻ DiDzYSd94 #]+͜)cwXѩcvpOҴiRRI`EǎRӦvRhz@FY RZvpܹvU&թcw,d35kNʕ;?*:ZPYM/HWH|"I`E޼M~G 2? N; YSz-S8OiYM/VƏbcN+ONl>i8~C U6;iӤNl&i5~A $פڵNliSKzS8ki,S~A nf͒_?;Nli2S>G nȝ;?Iv4yeI`ExxTBv'ԩYM/'7)21cN+JN>+3pA;Vڻ$[լ));& .?nwXQ۝Ұaɿ[@@ \y1Nls.\; hHzS8;p@=Z:w$hz@j:t7;M)SkN+ڵZ;[wI_؝_KfٝV!կow g+WJ_|aw +4 =Iwiw gs$7*W;s%KNXF ܤ(X$~=yMN+BCEڝo ԩ?۝L):.\Ǝ; (Q"w*($xQ?^ڽ$hzȺ|L^:~\6L:v$JL}[ IDAT=yR#QhHzS8;p@3F:w$ᇥnNihYnjNjζl&O^; h&l&}gw-4=;+/;-djNX-Ulw gsJK؝VEG'+3;WZ@hz1ֶ mo$$HSJ?lwX*Q$3F1CZ$@hz7JHnRٝo/JK{؝V-*T,.]&Lv; *^*Uɓ؝V}wߩ#GND |aC饗Ncᆪ(o"Ev.^'`4 0j4E}6ł 7XPUTDu0 3{g]a{ hIHcNJN(4XxZtl""""""""""J@~S(u XHJѧ0h֮E'!RQt Eg۷NA5 Et Ex{NAM/""""""""""yxR'{NAʚ1h@t ENA^DDDDDDDDDDRkkIdf[.NB*V"L&': 6TJ>K__t,5@`$ ss5ed$:ID^wNBĦ˛$2XQ|Ɨ:-BCE'!-Ǧ*k+:Py"*JtRFV€%KׯE'!-Ʀ $:;wuQg_N񢓐bӋ(t,:"__[t RȑΟnd2IH EDDDDDDDDDTT݁ DP?oS&MDPtgE """"""""͕gϞ˗x)}HOOG\\tuuaff055ER`eeXYY|򰵵EEXD L<.:L&eat(: ) "RHHΞ=gBd2 $$wT^ݺuÀбcG HD3~~~I7_bĉ]hD@^@Ts$Y<֬/X4 =VNLLD! Ʀi\7n@ODZ%>>'OqYQAAA oJ*aȐ!6lg/_ .#\ll,~7]]t+#:i#:%:I `?H /7czzӐbӋ\D={#G-֯IO>1|k3f'|Ԑ;}={`ݸqd2H;<Ο?F҇Djdxjhժ;;;ёH[˗|Tt,۶ɛ;NBbv\9It@lzQS+ IIIGgϞEffHE֭[4h4hիWM6#ѣʙTʔ<=卯Di䒒uM E!Ml 64 ^DDDTddd 00 ."*RSSqQ8q222DGh׮+,X#(99'Nđ#GeTXQt$6ի̙dy~VMto+VȯE! µ%XYz50b,_/^dË1ydTT ñcǴ/LM6N:سg8DDy:s 6lcǎBڨE `D)=} ,^ z%: i˗aӋHBÇGzdDFF1h ?)))͛7ݻ7VX!: iO? BÇ5@\$)?VbcE'! DG(6VZ֭[όZFF\]]51>Ct E/7NRzw -Mtlz0h޼9\": Q/_d2QHL 8:NaKouN?]D  nݺGt">>+ұIDE[Nc윩S33ibnbVQdʛg}ӵڸQ\ /7i FR{lzSzzzGӦMѬY34k 4@ɒ% U755wޅ/O?iiiΟ'O`С8~8ttttl"ʝڷoVZyhܸqflZn֭[c֬YǦMn:DDDI???]cǎ-:xP0^6oƎ D)0=]]I԰/B:tHt,=&LAFlz)IWWcSw'''tA%6I&hҤ &Ol߾ׯ-x9y$֯_o$"Eԩ:t耎;^mѕ+Wٳݻwc RsСCϢ%*2nn&ŕ+d9z(WNޔgx5u$YN,,#D'bBWt"""6l-[cݺucGݱvZXlzYd+ʔ)q֭[E6md\2e BCCl<"m-Z`Μ9z*^z={`ܸqW6>!CBҥU:ׯ1|A+wwzu) ?.:)][t Ev׬FRkEDDDY&6my0r A6m_`齎;… 8r&L0ѣG*H*U | >sCc300+sΩle˖ *(GJI@L4r%,,GGi 卯ɓ峾Az:ijRtRsEDDDZ xܻw[nڶmED ;w.BCCqy7N^p3F3?|||p)Amʔ)`˖-xۇCjLCvvv8{,O1i&'SJ&:V<ac~ԻwUǢL/"""EDTڴi7774^;v U6'uV,V#*\]]ZOOG C&I>1m4s%5Ҹ10}:`$Y""ŋ~7Qx__I| ,Z$lmE!5U|~""""*\022`llƍCZD)FpvvƋ/T2ƍ7pK%6f K^;88>>>prr6Qt ~-_ZP]ѭ[7zhӦ '''8:: M6/ּ~:.\X鉈T'66VZ""vijk׮գ"&N>zBt Ek 2CEP!f|MlzI0`U777亱L&C@@<==QJi?:t͛o޼QADDDD/^@jjdT"Y-"nޒjҤ %G$_/ۛ j{w)]l dfNBaӋ0sL4hCFFF322q㉉XbjԨ~z Dff&tu9IdJx7"* S=\N*Y-"SId-F%㴿?nɏիQ1e дZ'#3>8o길'-DPt({T@lz'p|(]k׮&_|,"""""UȀ5{S.3CDp=nZ####޽&&&%*6<=n!̓ _Fas6qwDPs'pTlzٳgVFbӋ ((HҚÆ i(L:M6ŵőҲeД3]HțmAyĉxXt16<<33I6P>ETwc*dɒEFFl<"""""dddয়~%$ID'883f̀-Zǘ9s&;;vv& w}036l@jqއJbbˁ'OD'|`ӋBBB Gjjtqqw7ũl,"""""lذ!Ǜ c000&i/_bÆ ޽;j֬  &`޼y*MT,5oL$:Hݻl=I m_,/56 ݻwَ%$$Oec`ĈWjDDDDDRzfϞ-iM##l vJKKãGc+Vѣq)dfflYfa*OTl} 0|;!!hߎEyNNȑS(zX /:Qq t~Sͦ^ *V(iM"NZZ<(Io(DEE!22AAA Ez/edd+V`E:.Q2l p$ 5=cp0zz#ܗ__GN5`F`xPt^D`lllϜ9׫o6m`aa(.HDDDDTXXb5 0m4Ik0p@1Trؽ{7Zl): 8QޤvMtǺc%̌E)8WW * |Yt,ǏE@rr=7~xڵK%a„ ڵ+Zj1 +)) CEZZujժIZctttlx`g':}?}=^e<=ZDP{7g5)6 N:KMMŐ!C0m4ƚ5kN>H^H x5MLLO?IZc4h???o033x167wG Ai':Jɯ)ssI6qVbӋ5jLCƍq"JEDDDD$ޅ C+9sFDD97n޼ۋCT|U"oRZKL*VEP \ <~,: }{ziElٲAQKݦ}s}f͚ݿ=z@1c :::Ep"""#z 000@2ePZ5Ԯ]%K,,wA|۷oqMDFFݻwjԨQp-<޽9,--ѰaC)SP#44111044D2e`cc"Co޼!C)i]{{{L0AҚDD9iڴ)\]]1x`2"I4iL,Z$:I.YVeLX!J$")%)iixHzgw503gį8Ө0c0$Y^_fs$ ɘ>}_4֭ NY5jܽ{7_?wΝ;ZjaԨQ1bT2233ݻwxi544D6mзo_ :TOpp0Ο? ϟǓ'OD(QBqqq߱eܺu 2,[=;;;`ѰWDlٲ;vKrF__-[ķ~CWWfm6ܹΝCzzzCݺu쌾}QC"<<\K,uB /0l04nXt"Խ;|85gʕѤfMԩT ml_*T)jfdfś7OVP?|̹;w0vrl:UhtDE6N%8X\ސ+[VtǦx‡IIIhso߾zΣG0m4̜9{ѣѥK7LrM6axI ___bƌ3f O 2>##wݻw1|o˗/GÆ %FDDD9sĉꫯ>:럈ׯO>={D۶ms=$4xIq$ #:6nu~j 3 [KKZZ©iǃ""p v MΪ)upן|RcڠAfd 7\]{0lzi͛7+|Xf->s*sSSSw^ݻvvv * inݺ#G͛Y[[e˖R J,x}dP;)) 111Ri6sss:u UT)tt?o߾Ir}CD$x{{c~EM"68[9~l\Lѥqc\X '~U+1DDL(6 TKKItItŦW1cƍh׮I:+W˗x +,, fBժU1rHɚ_7oƔ)S5eT>7Osmw^|7y>nݺ8y$^6lXYb> @GqF 85BʕQ^= 0Gݻsl̙3ػw/NwJ.͛7# nnnhѢ*W5kC_Ct5׺W\ӧY={fhXh?q0z͞=7nP:ѿ2220x`ܹsG7ou>&66֭zD$[[C%@*牱ʕ*ɥ͚j1F*o|TDk?+ ^ <|(:VґiؚW׮]ѣGDEE!::Hgf\\\(Ww)))r.]0˖-|icccL<ӦMR5ЪU+*PݻJ]kkŘ4iRk.\񜁁_`۶mZo}ݺuos=_n]<|(]4N86m|nbb"Zl<~)=:9ꫯecy& wPZ5DGGg;׼ys\r%2(00u} LD֭[1bݻwգ/((5jx7$Hƍի%kllW^.C{fffcHFGGO?T H 30s7x0)*gKR)5TBvvY@Ŋ0 7T:N&MpzR~~NSWm>#?s*MiL`̛7Wƞ={ .x"""bU5TbHp/^[n?saÆ4T :4[ 7ixҥKx+P z.-- Xvm7ooPX"_ /(UT!---_>tĉl /Xpa^`jj1cxڵk? o\ /^^ / +*d2ۇcƌHIIHt%IJ~A!^ X`°RW/G֭U:O@;1TcGDP ,_ps:5j֬):Z Akԯ_gAAAAСe SRR ]%ǏÇ6 ^JKK ШQ#.yH$A>}DPlYۤT)3 R8o/'R'nd9MqMZjV*zM6Ç9sJ*MNNƀpԩ|=>11K BWԩS.WXP/ ={~g5kRs=?9rAAAَ4l0}|}}T]"""^.\!y-Z`Œ%"R`` Zj 6v,жNv",5 ? 1n㔿モR'g۷N54ebbkkk1FN|hTT gFpp0N<#Fz}t 4O֭[͛u666_bEz¢355Efr=oggΝ;+~i/%s`zz:NoF^ z~c׮]^ҙԏ.$EٲenL8GVMDZSGt E{GN#F`7QY"88Nh)PV-zJt d(QBt '''899!99'v؁cǎ!99bbb0~x:t(mڴ)s-[,^z~ÇB~_SN\|9s7Vzjժzm} ٳgs}:6oތk׮۷8w~GmV%qA8;;+u3+|yyBU".XxHtltttqd8桵GnMUuYpK"bK pCdjjÇ㈈ҥK tZ*s~~~n:inn^ହ =F^ )L(/Jӧs=sN<o߾Wtt4nݺ///9.DDD1֭$kע&"bddva֬Y8<ñl24iҤH?s ʥ oRWŋgD'ɦtɒ7kJ`/"]^_Sᢓh,6@ ;j'ND`` vؑMǏϵuʕ\'eӫVZ[ =FaLR5Ke?猫S*W7n'"...ϱT'iX>TI 믿VIm"n+V gggڿ?\]]U:V [)^^@q/ +U_J^7*6|ڵƎBQh(t,a4Up4^Ň.Kܻw={^£\W?~8,YP?TD TT) U5w DlHD8;;͛*)S6ч:v#GhSV^͛7t "ҿ?Яn֭#13u+Ws$)L>AS({X+FBD5LQ255EݺuQNQ4£Gϴ͛jٽ133Çѷo_>|8Lkv<444礤H=KK\NjtbF|Ϧm۶ׯJSfff$""/99}.\~-~'&"M&Mp9l߾&L@LLJ7n6m뫤>;Ot,gQ(0#G9=p"ָAKTQ(⯿{bN#^%KDŊW\Y`!!! tuuQF TR+WFʕadd333D7@}- !!HMMEXXr!R~}CݺuQY~mqF,\|*U);vAΘʭٔ "^y}}|)5mۆ*UQ"""v6lΞ=ǪU$"\::::t(ڵk!Cŋ!C'J&ݻdٻWsI|޺5V}x>>>>IyL~Oazzz]4Y!QQo>۷/vD$\Vf IDAT*UWWWYFwE.ym"&^N# l"o|A0|I^wO^)?DN&Tǎh ]n3ϟ//[2 C 6kԨ<0̟?|dKm۶?>BBB0{lY0fIƢ,;=֫W/T\|0yF\*QD猍y7o.>lῳ=T)33#GΝ;UR[nرcgիO?y!$$DDZJ>KKk(Ա#ML$y}Iss5{ӬbLc^5kvUVlcǎիَO0ׯ_G޽U~7!̙ooo7k֭ڵkU:pW@@@>,s+f?pɒʫUB4ʕ|ddd%!"""m%0vXlݺU%۴i(&"RX @ʏ?(y]"fo/oRH`b <\t y6ּFZ_$* X(4V57o.99>|8/_^w2<_±)S܇3N>"1㖖9^P/^(td\UVMq4ǚ^EL&Uv\˖-qq>N^۶mÇ%KڵƎBQh(lY&I<^PD^JZSmjN(<tItbO^ c咍QPnnn C(ʖ-_zӧOVVV9xݺu(Wyܸqc4˗ϳ9~d2b*߰aC;v,ŢEХKIkfdd`…$"}N`:tjSÆ(%,OJZO|嗢S(a+%*mze@Y_N:혋dv)![dxP˖-+sjiӦ9>e˖y֓ȫպuk4Jʳ)xE$%%a""""3fʕ+URv8ydDDJWW[lukΝUD5 Yt E}}gaHIt 6 -Vtid;֭[7+VZ gffbhgz'pȑ";ԩ 0''<7}d^|RJSNڶmwaϞ=EfԨQgϞu5""uUbE_sNIk?݁ DP?o p5u*Ф$mz͛7kܸq vc(fڵ+}(r?E0}ڵkَuc^[[[j*>>>Iq#ڷoy̔IDDD̙3믿vJpiب>}W֭[%GD*V"L&': ׮-i=/@ >ߧ覗 ʖ-HLrؠB WVjjjc/^t'meccCCCc.lpAjՒ$:7ce$]p._>mO YIڟzuSKmC]JHHݻws=M:Cq\RN:3f8֦~<<~i3 b۶m9reN'ka?>OH2e/FD$>3Yk9rDzD6m)4I/A3=-QNz))2-['NAEr۫?$ڵk|.gw$kZ;&N( W⣏>QECСCѣG\i8:u*5jTZO&Bg3gyOdddmjժ3kvލQFiZh T:0 ?ghFӦMOD$'|"kK.ZBݻ% h>4 +gJ%JϞNAZbKKr(?߇Jķ~y+++)?ر#4͛ѶmM%kkk]PK,#?,twoqm۶^:'11NΝ;y>)) ˖-+t]غukB9s&ի5k׮Ev |oz ƍ_lDDDdVX.]4:͛+RH$WWWT\Yz˗/eG uKtֈ@׮Sh:}Xg]VlzgݻNAZ`KKիWqٳg֭[@C'''&* 93gP^=;6rsMt 14ΙbÆ / {Aٲes դ{w76שSww7/ލG}׍ĠA: ;w,p]Z%K`:t( \ ;v쀃Cם;w5ȑ#qͬ{!Ν WWW,Yq[[[ܹeUV/|o>lRDDcǎ͛7eG {(s3SMNi.`6+kӫ-oo?epR<~^~Z֭[s} -/_~@ƍڴs#֒m3'==K.Eѯ_?Z QQQ9Sոw,YmۢaÆ8tPlll}vO܍7ƩSPj碢Ю];;vuΞ==8ުU+5vZL6 uƍz1b-Z `ٲe5jj׮ׯnJJ 6ms4ܹL6 4q/+v,kƱcP||KJJB@@:uKKKTV m۶EfP|yKncc}zI"""2iժBCCeG [ 06ǏtH+^YYH+^(3a&ĉQN <|7o^%j5޽3gɓػw/>7k(y{ԩ׿>={`Ϟ=RJrʰϟ;fӦMvڷ.6Ǖ+WcvSTT:w.] ͚5Cr吙\r;v5T*xxxyrܽ{y?WիoL/>rƎ[^K.۷c֬YZ]f ֬Y{{{ywq% <gϞ}iiixQ&UZ{AÆ Ϻu0rHE>|gnn۷C&"75jԐ^xxHaҥ=Pg1$@24CUIN/)=IIKJScc pZZneڛ/_(UlmmaffkkkXZZK|111ǣG\M4qI$#'''XZZ}/QFARaݺuӧѣ9Kܽ{@cUX>>>=z4LLOlٲرc///zc#Gȑ#ռys,X 0^J%K`9u+(###1sy벉DDDd6mڄ#F(ڳg>Ck飚5kZ/""Bzy@ =SԤ>]tltO`rBKZCRV U&5SM M/-o߾Oӧ ]Νu>fqRPZ5_uZl#GΝ;عs'?أ+7NNNh߾=^zxTa =zl2>|laa={bM4Kzsilٳgjiidd?>|8zj\v@ﵶ<<<иqcmٱcLkb֭lxQRreYfgR6²_g"el L,X :IpOJΦMɓ__I-*c%J޽EG(VV\ :֭ubDxx8BBB/^~(QL899Ut民>} !!Nµk8 Y&5km۾~4mT"#Ch PB Ə#""sBCC4XYY5j@˖-{FH^"""ҽ]vaСSacӧ쵉 ,,,r-mV!=qԡ'P!$@Ϟ@LX4 (UJaz%[-+>o>P v$6yԩ;&:J6mFQh1Ujz:%uSʕADDDz:t(eeMDdlll"I`ر#_NY7P`K DVRZ°arNBy0~Y'Odv! 0622š5k0tPk 333j)ұ]mD mMȰ%nUgϐ)>ӄ @VSP* b̙cI&pssdtORd 6LDD$11QZE&Ć Sgg)4m>,{ِ'OdWM 7P 6dnݺ VӧO5/^ѣG^Dr2bp$ I>Z Z\*kًZϹ|yYP$vDd`ll۷kדR|}}Q1rCRpB;VDD&)) ճ 6U$.NBBd+ymj@56VL%¦Lq!CtL4 cLO^RܹsGDDѣGLb&<D'!m4o.O"#{"RqBeLhk)_ ooo||Jo:q9t /_T?S*RZtҲ#=p>d IaݺÇN)(XHH(R !^IU;#GNA`Kf&&&pi4o\g:99?3t6&)իѣb ^`r7eGzY` 3Stưa@^Sh:^ӵ. /]M2Wt ^ypylٲE旅L[nCDDDDDu5tԟ9s&OHm""CvyYըQCzGm5aЪlYj5uݺPT,־ hFtM/T*… 믿W_rʲԮS[,uHׯsΈS'fϞHm""CVq)YkUm9":i ^]t M7m.\XY[Wz%7P%%EVЪU+미}6.\/ÇǓ'OrgҥQreTT CƍѮ];N'""""*ݻ?2?'ODD͛xlJ*'''JIVƍE²||OOsi$ii@@tOb&{lz4 DbKT*ׯcĈ9gdd˗DDDDD$ѡCDEE)RS6QqEe*k=Sqq?0s&": V*RbTI=,Z̘`7p-Y#9g,ibEDzvvvlx0AAAر#>}H#F`ٲeܗ(X~5۷o/k=c/Ia_-:Ǐ??|d}NB%FRtM/""""""ѡC<~C m}Xb^DD.k_z炂ŋ/D'!mt 2P….?۲=dYtNQEDDDDD$PXXtHE껹aʕ02_򒕕ٳgZڵ&sի IHC}N%`*i7Dcʕifb[^Drs Dz |PE47n"M6ʕ+lԨʔ)#kM2&:ihFt M7kFW׵Y3^;r:c":@I{ի Ǐ/^ôiD$"""""@CE6m GD8xyy^w޲$y3`ot.: i$oIT^WKjh-||X@(I ZGbƍطoaÆnzaΜ9 ?mقWɺcG]7c!矕ѯ)o+:EŦLn߾ኍadd'Ncǎ9ΥsQl|"""""ѽ{wܼyS[Ea~ `۶m^z!55USLc%`*i/*L[.~7n3]4܀'zZq*98s@G HɎM/<}~!bcclٲ8tƍ IDATZ7f͚x"""""*t/_V~Vp*UJDT|ܹsnnnxqJ>>?iii4iFtEprrM͢S f  _ -ر !C:kر(ee5wwC)6HVcĈ٘&&&Xx1<==s=waӦM:CDDDDDKHH@׮]q%E7j;J.H}"*ѵkWɺZ"L7nUV7ox{{Z1m(5JImh=aLe#KeU ] #FNBqqx':mmqQQt"E饥t[1fM4:j믡Ve:{&<<c(NRaʕh׮(T\l 88}NBŘ- W&: bҍ7r=ާO[WT2e .][ʚJ*bbb xDDDDDDDD%J?>Q8֬_[NC^ EG!R*eK7o۷nݺɞL2Wոw$&&&Xb<<|Xڵkc֭8r^leAx{ˋNMfN"J%:^za'M'N(H$6:55syW^}ƖUTQ""""""""'ǴiPF Q,Y[nᣏ>Drt||76+`RIٲ%[ơs&031I68 Kaߜ$wܱcKKspB,áCЬY3ܻw/ʖ- *(̙3AAAuf͚:uꈎ5je˖Ç3f LJCt4KDGN"K п?mߎm3f^Pret<OHЩ(bb ɍM/-n:1ZQFaҤIHIIQl@ݻwG\\[oҤ TKDDDDDDTիW| ܹcҥ EGSSS 8NիW1zhXZZEm[૯DԤD/Z[cPX:a^MvT|޵kjYw4xX<{&WE"-iHMM8V1o}O>>}'OĹsp5EWQBʕѮ];t{F2eDG"C4j ܱcd;u ppNy/]=[Dϖ-_\7>Dpd$?WdT]4>Ϟq#.GM">|xMKHH別ٙ򂗗DDDDNٲeѷo_[nҥKtnܸ;w AOfMvhݺ5ڶmvڡjժcQq1m \&:I;&ŠAJ-ZhNH@pd$B|8/^˗/äI`oo/:@6662T|Ԭ)5)f$[L 0>0cP4TX..R3GtlqqtONCTh\n:+&O,:Q{Sh gD'!mh!'/$DƦ ֭ŋCR@ڼuڵxc)4ݻ5E{wD$S,GKd(ٳgXt)Zh!:QNY`:@@ϞSh/`j #CtcKF3f?(lƗJ_Ę<hDt Mv[NAښ8QZPl":Q%3///lڴ Kذa&NqJ,oojU)4m;&:ipqBCS^ 2d];d&MŋX&""""""""*lm&$ْˁkD'!mX[K$RS+˗E'!z+6cǎahР"cTT ˖-ŋQNE """"""""|HM }!!6Vտ{s`BIŦׯСC8p T۷իѣGȈDDDDDDDDD´hxzN)"D'!m4i"O"#{Id":@IRеkWt8qΟ?/ CJJJ-_<ѤIj ;wFuQwE')@RPa}! ^-:I `"`TZlz阥%z=zhGRRRSSK ,,,D$""""""""3 &8p@tl%5MƍL8|tO':I UD!rzvvvcQQxzJs.\$۾}='6Ə_%:I{jpI4p3(4o<4m /GDDDDDDDDDT*ݏ ~l >,:iUKt M[׬F"e6l؀+W`׮]:u*W/ҧ=RS+˗E'!m^^>.-sOcKK8zhs):nhh(^#˚5kаaC?~\񉈈V$>Xx@tFR3U$$AA`Kk5jt5fE KS###ѥKlٲE DDDDDDDDDTM'N)2<Ѩ0m<|}{H06K.B|_/FFYYY>|8g|?Bt MAA위IH:FN)$DE/: plzA۶m" NBr4Υb^cwo)4]H2<_t M/KƥNB%^E,:ڶm@-[VxLL f͚%(i?hJt Mq3ru0iTUڵkcٲe9/]Q@͚Shڼ8p@t Җ7*:[}DM"AA222vZAHԤ$[z:j!SSpt$[Fz5矢P ĦW1ңG6lZ- P' @P${J$˗ߢP æW1RjBCCqi(WӦNcO O{*"Bt*A*Fs=~'!""""""""|u):_E'!mt|BB .Nt*!*FnݺӧO8 Ր!@߾Sh|XHM1h0p]/E'Mbڵkؾ}{ݻ4DDDDDDDDDT _}m+:ÇMD m|=E:a":>HJJB\xycPݻy.o>@zShںؽ[t ҖShڱؾ]t *&ʃ &L˗/iӦhppp D'ɖ] 9#: iTItlj4II`-ԩgb;1H[I/Iz,] ܻ': ilY27$[Rۢcӫͱe|駢ܹsQfM1(֕$* E'!mԪ%-uOyPIȀU@&&&@.]DG)3gDDDDDDDDD$v퀱cE ̟ĈNBhBSX ^`bb-[raΝ={(DDDDDDDDD$77)4ݼ)-K$: iO`P)4ݽ ,Y"-ITHlz6m=YCժUCݱvZc݁Et~#]Et4nVNBF?:7Yf]ŋѲeK={ȀU.5)IL 0>*: iZ5Kt Mqq?": 6dpelwcǎa޼yE/88qqq9ǣG|r """""""""ֲ%0a__ *JtF_$2R>^E޽{#11@CVi̺uڵkhڴis/^@=\1 &:%K/E'!mt .: `" !AtlzٻضMt ք @VShڿ7)H06`ZQ KƦM`nn?0""""""""""T&:#GD myyիNif)H 6c>|sqq;#k =t̛7Oֱ*x{66dKIV^aeeʈN-- .^aKK@f!לUT;w"y&MJʕ+ Yj|铸8 QSϟlziܹsV}ԬYfff{G)Zjh֬Y㉉8t"ci\KDFӧ67Zt M~~үT饥+W8ɓ￑O˗?ѽ{wE3c]qȀt .: `b IH;#FN)8XPE%^Zxmoo~ FFJMLL dF'ODDDDDDDDDd zBӹs@F$C>}Dtjlzi)..N!C`ii)(&M(l"""""""""-Eд?oS<<6mDt y#lzɤu֢# 111joq"""""""""{@Shڼ8p@t Җ7PlT饥7guUTIPl>ܳgt )#:I4 |Yt҆rp$[z:f p$06dmm:))IPlgϞ7$""""""""\U"5)6*VDД,ZNB bKK*Tx}5AI$7n+W<4DDDDDDDDDdP7LBǀ+wտӧ/!: )M/-U\Y둕%$ZɓJGi u !:``Biww)4@\$6TF wŏ?($95:JCDDDDDDDDDkPO)4]Z%E 0@t M׮ITj$$3 Uƍs9s&2220k,T*3cԩX`[ZyIIF )ӘSDSF%KASaH<}[n… Z7ڴiHDDDDDDDDD%TJ0i$Ef\͚Pa99I/OO +KtɫW%RPj.V/Ec޽{ѻwovZXBgVrr2\uF`mm-0QRRRpׯ6l}Qaac樃;9)4YXUff6^Edn{htΘ| gzAѸq/3(B2eйsgJDڵk#EG "zDD21RR )8IM~O5:z=hԩ#c5.EDd8ӫO?,+++L0Ah:aÆׯ rs_!CQ`""l.^ΝH6jBuE.NV-ww5_!bIQD-ҢjPE[ZFդZrί۴k,.:Lcߗ !BBV ?>SK}q]^N~{|ŏ M/.y ѡCIX>}:>⺞DD C&Mxꩧ,<<5'NE .xADHWW#+/7x]_KJƏ.!g+q~k_}=]vxw3,d2Ig=qtL&Z5<`*djՒ0+(V.B:OqIO)(_<֯_eJQIWt+,. T 89I؟ҥkɞaÜ5!;'"#u\{uؼՁW~t,\wlX C]S@Nt ,^ڸ|K'شiv튓'Ovlܸ͚5k """"""g@`0 ۴k0ctY^zMd{~s дi@rʸ(_L*s__5S8 0POթ#]CC`,uMխ+]Crسg:t r~|7իHGݻÇKWX ;wKH]Q+,ED%ENر^nݒ.!-ڷ&Lt0{q襳+bCaÆؿ?Sl$"""""""+{5h?rXΖ.!- tlZ֓l/HWX:sXHO.!-^z P9-JjZt >P,!=׿uk6T%f9^=.oHDDDDDDDdKvF̛$'K:cJWXzU]SII%E "#Ր"!Ah8Qj@/]B4O҉e@Vt iNRKeI3*^RUFrjy:=}&]a),L-ɚ*]BЋ0]+H1cS_FuըQT#ٷX8Q !]a)4X ϗ.!pEDDDDDDDdL&۷KWV&H[+HS~FeEidOҶml0mPtYn.r%pt i_5jH's.!L&SҚ5޽մi@z֭SO(AVV~G|ӧ|}}888L2TG$j8a2aQ=N.^.!-VU7KRS^Laa%E@@PtYzΝ.!-*TPהtYFڇ)C/+:y$Fjժ^ϟGRR2~ۄ3''o~>EDDDDDDT tSrOxC6_?` KΩeӥKH>}^dMM.!-zxCRxRRKJt4g+HNNv빹>}:z4lر/#g`: j(kW KWV9Á=+,eCᗑ<\ J(zdѢE?|TRXp!K8=`#ѝ;wsθuLj/#ټ[ jTys K|l"]AZM l)]aiV 8XWM% ^: |o~GTPᾯ=z{Ffff88W%fW_"]BZkKWk{JV&PtuөdL&K҆ ?JWzQJJ f'sغu+ڡC0hQZU )KRSE9d{TQ7p?JLz9ҢbEuMJed}O.!-\]5UtYVlptIWEݵkW]KkW0||?#ץKHFiӤ+,%&g%ާyҢn]]SoWH=ݻ3ghÀM2{t:KWXTCҢ];`D KׯfUmڨ$*J KH-վqFrㆺbbK^EvZJg`ĉѣ}ߺu P ttZlO>kIWXpA-iuAϞС.],RRKH=å+,AA;%vC"XftsARW_ݻUDDDDDDDd(F]HWXڳ0`p{w Kz5PP ]BZ~ʕ@nt ikjHo$G˗%vC/nܸÇKgnݺzjj*6n(PDDDDDDDDƌWWW4|oMԮ-]aVPڻW2u+,[tie2^^6lv풮 M5a~8ȑ#ڐ!CpY\z7nħ~)S`„ Xx1;777ݛy~Q Q,]b,Y"SAoM22ԞqOKԊK̲eˀǥKH gguMU,]b9|Ĭ C/.]tkXj֬Y__߇7&L{SjzRRu?٨Fԧލ$!=.!- e#u ;zUWxTr20>pt iFrn8ڵk6~x 6~Ez'lٲZTT#"""""""֮_fR0=<L$]a)* 9.!-ɓ+,ݸ11%Eԩbbԍ%vC/-~_LL+'ʗ/w$GDDDDDDD6o_W+,],ZJzCJWXt XHI.!-zιsG5JRDz03SqQFF[n5k (/^|5#""""""l{w Kz5=mo={JWX:xX ˓.!-^{ Gґ#j_&=/$]aq4ӛPٞ={ҥKc ٔZu+ytii#]a;+Hm+,qti5aоt˗ l^+Wgdd 88_s/n] Kk!!U@Ptۥ (L&aC K6;vHWV&-]A:K?uYxG!>>_\r1ͩTI )\\K22%KӧKH K̲ (ʕSהu˗89ӦUJN8ҨN:x"BCCEZ6oތ/^"""""""4hn(ɭ[ܹի%Ez2^<=>u`U5jkAtF 4{ڱd :O\;V]S{JziTT) ,x\r ZJPt@LJJB%ٳ."""""""0]nub ^Q@%ɤ%f6)GMOIUFz<&П;']B `رp(}6nݺƻ9 IDATd^ХKxzzv<""""""B,N.!-ʗW7*T.1/Wˈ)WN]S+KeT#=>'' @ "7XXO5spPoЫ|}}M:Ǝ+@DDDDDD ;.!-M̟DDHꆲܾ /Kj{W]S.Iժ#̳%z_|ҥKKg>ƻ8*͛㭷ޒx?Jb""""""2Eaä+,')ܑ.!-uFt 0o,]BZt #]a)"B=휔$]BZt/]A̚5 ͚5ΰ0dK:~U@^t i1dлtÇ~L:Nh`ॗ+,?,b嗥+,:,] dfJJWcKe˖Epp0ݥS 6ļy3` wm+,iti5aоt;+Hc+, [']AZ t"]AC/x{{ᅦh;;T\Y/_ti4l(]ai` * hXƍKWVӦMJWX V zJC/m9͚5oooJf&lpt inU$]b;zT(S0\`J!ҢT)uMU.]b|/%մi@zGA݋:t#GDDDDDDdKsҢNuCHn˗KHZwMݽKKHj5(]b ,^ IUkYC/+Y&v܉%K?EP|y| {ŒHnfbcKH-)S+,ݼ7KHf͌7hǸTTt iѨzڙ Ǯ^غu+^{5VZ?OX=z4.]O>5j0a0e8 DDDDDDDsG 9Rҕ+/=;GKWXPO&%I:IWXfKH~[n^IIIԩ 6󈉉1g4ogΜzMHcqk'''t .ĵk0|ڡDDDDDDd/VR{<Wұcj/=KWX:u XTIHu]ٳ%@zt iѷ/vxPNNz#G<{1p@;wXrvv+W^y ñcpDFF"&&YYYHKK*UWWWԫW^^^hѢZjrYH!%on%f;wa%Ÿq)KvVהўn3zBBKQ#]BZ۵K`Cs>r/D^ʬTR񁏏O&lؠn)]BZL?ptƍ[6MP>ȇr!]#Rq PbX mTjN.)nyÂ,X౿V!""""""BV.!-ʔQ/\tC%ERꚪ^]Ch|૯T#N@PtYAzj ԑ(nuEDFF>)Sz1DDDDDDD@Ppt iQRɝ;@xt iQ\@3SSE0COpZx.O5Jԓ..%%ǩS |+WÈAAυуܼ iL )$69.!-6U7$.NOEEIo@̚2 wM0v7JLL|X"v\?ڶmZjlٲ_>|M#""""""?|?_=EK`h Kܹ@Rt iѱ#0ntH`lٞ~[j ]BZ< 0itEewC&M}ݺuyfT\Yو,fz_dɒ{'CDDDDDDTdǎ˗ /]a)`R 3S_]WFrӥKH}W_tZ!z (=֮] ???$&&"//uRJE>V\+V# `Nʰa%Ÿq)KvVF.!-FVTHtYHt i1bzjn55n ]C5lzڹSD'\I\rТE ./Ct~զM+]AZ=$8; * @g$_ |ti5e }dغؼYz]uk^\1*&&F::rr+ÇKH GG5VM,/O]S%Ԫ%]aVP^mpL&N KkF* __İWݺu{-77_rrrEu"""""""s åKHͿR% ,ZIzȖ'"^LK*ӦXQLLF3YҢ|y>UtI`ЇIp9]äDEE!::Z:Ⱥbc365mn(I\DEIF̞ \&]BZ4h`k*1Q]S%Ezig:zUR^^^v>Cff.2ړ^[lN """"""*@Rt iѱ#0ntH`- +,] %3#]a)*J}#.NhZEVewC/h۶_OMMdBÆ  K!i蕒YfIg'ˁ,Ң` KgK%K/KWX:^-u&]BZ "]aE$kJt i av.^}yףQFhԨFe˖!44IXDD}\v }E'"""""f.`: jsg K!!ڵȑ@n ((.!- S # VKH!C@Q:zr!##/7<<X|*U ʕ+J*sn{="">>>p)o߾k׮!77XGDDDDDƖdܾ}?Ґ;wX| *|UUe i xx}J&ګYVT%Ŕ)jʓ'K̶nU%ŻkQV5ӍxyGwtݱˡ^u,[L1n߾۷ok .h>/ѣ$&&~]v FLL nMJPfMԩS>>>A&M*Ur"+Wj_=&|tRPY;Jא&@2uԐhO7ڸ\DǾi#F11@t֮Jڷ/֨R.Vާ\.+v9wy+V@~~t ٰL\xaaa77n >>YYYsp]F*VRJB ]6WOO{lڴ)P]8MDE3gܹs8{,Ξ=ֲ?xڵk^^^ر#yt^^^DHjqc*,";[FIMU{1yx>>5TX* AgB=6`4gp~v;[anܸGȑ#8upڵBœv~+|||O駟FN_lҝ;wp19rGѣGmOIDD"""j*@ݺuѯ_?+h׮d䊋Ӂ:uk7VC?|0@15YZ6TӥKٳ>Փ!"iuߗ.v;O>۶mCbbt L~~>N>ȑ#qFwݻ5kk׮֭^xT^ػȺo>ݻ{ůڵk3g̙:u`=z44i"F%ի9t V @Pc}VZHOՐjUkֶ;g\(`L5Qj//. vN5zj~ʐ.]‚ 0`TV -[ɓuV`ڵx7QvmX~=ӥӈH޽SNEVPF +X`Ο?o?ٳcvG6M/ vYF SKIO{CHWXxQ-ɚjȖt"'gϞOa2Sؾ};mۆK.I'Z^^v؁;vB 8p }% -//۷o޽{g;wD7}iӦ裏п$*IBBԓ^o%]BZ۽_0@Nq6߯3mϰaڹS,4T5~<}~W-HnSJgQ11l0T^;vČ3lrg)))X|95k[,HDr]sř3gJΟ?_~m۶Łs$k`V jy~3NjFٲE"ݶ  "xW"^gaɒ%(St ,//?F5jo߾Xz5nݺ%fغu+ڴi=zIDDh߾=|Mܾ}[:J`j& x) dj5k={$ (Ǝ.ߺuO?IWم3ѣGh۶t ĉxQV-t+V@rrtVڵkZh{l@AA+ Tii-[Ԑbz 0mJG۶M]SK&}.1{2DȦ'E`OUZDDDd0YYY8p VFoѳgOdaoL&SҚ5= H%)ׯ~Y2 +,mtMˎ⋨\tL^^FkJ= )ʕ rKӁ%K>_dXvǥ3OFT#=> @=jYYeJHNNFʕv0͛c?FDDD#Ff͚ڵtlٲ_>֭ڵkzpww2e"%%HLLDBBbccK.!<<Vɓ'{a >.1KLfOՓ?y,]*Q8IIܹ򒮡ª[W L.1}7O]SO>)]CM"WBB>3lٲׯ_zV_K.ui"T*Uʕ+lٲpss  ::QQQst2rrr0p@8p7!BV|}}Ѵi{lРjԨ p|?TpIIIݻ7?77b??=777M6hӦ Zn:u98vZ QPP#F… (sR1G=a~tYXp!0y2Pt X{78 ]x8`lO[%f/kq-[eFzz5* ?:U-CLd'r蕘^z=p<[v믿_]:&9997k~~~ *UN:SNbؼy3֮][O]|XlY ;v?N:E(]t=hݺ5Zn>| f̘ŰHbb">c̝;b4|%f0~"Ttim~!>$l߾'OFV 53''' 4GŦMkѢEyM IWXڶ ؼYuo Urfv`& ղFcati5~<Сt]u+tcwCl^?""B*WcǎYfIDDDWfM;8t"""`兖3rqq|ח_~iyG۷~."RT!C`M6r=3g`ĉpppڹrrr`㓠n] K?,]Qbm޿[??X4]XKm`pM5iJWV&#]a)8XO5 N>]7^#DDDd˗ȑ#h̙3 BllUAT… ѭ[7899IgYUq!-wFnIR0w.Pa&.Xd?zu`6:m`|eҢvmėܹ,Xp_TzH7MI..^.!*JɅ K.믿ij>ڵkh@xWc„ XtV 0WΑ?V;>QIv~Ȯƍc޽V{Zbrrrrl֦ /]a): KJ>!!ye˔Q/ ݸ̚<>d@O=L*]a)&9S][d{|}Hԟ}QQ%Dz>}0zh4nO>$^u޽e~! tGAAaҥ8p_-!""*Ne˖Ÿqp%sVc8,صkW8ܹSA tKԓ))%vNZΝ[c~Eti\"+ S:d{vF̛)Iԩ0vtW9s[K4Wr d!<<k׮Oµk_FIVSfMWZ%:ٗcذaw׮]o?ہM+RȩSXYaFe+; +H+,_/]AZt,]a)$$z=fWZZZz\X^\×Jebɸr OnXC GGGݏ}%8p@Q3<<W^d@&%]aiO*-3g*ozmXU6mR/M&#]a)8X 6}$8غUPnUn^+((… u?,\xQ:j1rHcƌpwwN*v;wɓruYDTrժU ?t?u?&\tYVZqҥn..X;:uM9"]BZ8:!Eժ%fj9V~698?IAz5t cW ?k׮\Fz;w*OAӦMqY,[ 9qƺwݺhر(UJ߿z~%Dݺꆲ$'WHؼcqH[m͝;@P.]BZԨ%f))…MUӦF ,^ t c |hNN^z… hC\c옏3 lٲ1c u?.lGgЫf7n@P*ҳ/²5_ԱJPL 0sũ(xTB0{6pt _Z?|}}ѹsgZ c˗1| """*&}A6mt?}t?&Q^t=^%L9wHؤV!g'',4 Fz""yӄd{:uƎtKH +,EFs AAAz~~>݋{3ϠI&Fj *B \.1336mXYGľ}0yd9} 0@c۷CDD]vxQzk@b"PtuڏiLq8, sHǘ>dqLn(<(]bcy,Y99|hV>8P*ٵ 0ӍxƌQS}~Y]SFIFk知KSԘ1ώ7vb"""")Sus%]GDx'u;^vv6u;ِaC K6֬H?__NcWT#ɤ2``V jTys K[_DdC/?~<ʗ//ADDDdU=zxH^Ddz>Ub+n(W,]b9mTdc""s$ҢC`x KjH ]BZkL(]au5L.!`C/~ ggg""""{蕚 ##Cc)SF!٨A^t8l%]"./?nn;V*td (~{;KO.!-^{MRXZ$t 6lt jI6^Dd )))vpppxd&Lڷk~t͛q{R?*UҩȆ3nti5jz:H֬ KHÁ=+,W"q%bQ^=""""]UPA4u\Sc09F l.]!Rt4ߚ5E:Fz.:ف͛o NUɖ-٦ɓ-+,mݪ#Tb^s'st\2!<<\c=䓺섓0mPtYn.jptI/(YQ%]ߟOuQ~>W/HV@fi{KH+ [WҺuT"!%jBfŋ1f.yHDDD6/33SQvv6"""t;^K}F uCHKKoΞ-1>>^5kTdGRSE9d{TQC ggt׹s%EŊE!|_~%ƍg}+VDFPPLq`ܸqhذ!ʗ/&MUVxgO =6o\,=Dd|z-$$DcUPC/zΝ1c+,EDs窛vo͞"X44 Kȑ"#Ր"!Ah8QYlU6t(`Lb(`$KFVЪU~O^^ݻwcҤI}Ϸ~;Z3բwTTW.BT+VPĮwE &` {Î{DEPDqH&Rso-ֻ8{q'55U9&&&r?6)) J^bŊPb#=zÇx%իWLܸq7nIn:%$HU$/LBÇղ>zDC+\$ÇrONN}wɓ8TMXZۛwO7mߡ~zLN aZA88cjnIr~ [͕̚DEUH:::J.kӫL2jF(]vhݺ5tJ]vaܸq#55U/nnnXjhY\]]dtaL8?|/_^dׯw.R:B:(Y^XLB۷o㉒{[nݘ"n * |w~~f 1[*U aHct%Lz|F^Ν$ǵk90q"; )aÄ>N$͛I.#$6W(JWW˗/'I5Fe˖}8p N>;w`ڵȵv%' ---iSBSj_~"Bp(M\1 ?_KK `h`0\\y :;QԬY@ƼS:rDx"itaC)9~\Z3eF֪iڴ)*TPQ `ڴiƓ'O7600@ƍaccSSS܎;"++ @``{T+WZBrT' 7ƤIG{>DVV,\/^f͚z{ӧOEHgϞ!%%Y5j0E!w!b @yR8ڀpP*{de;w 3)lmyabs8vR5v F%0x'dg ˙NC ̘{;I{1eg;$ 8<?ǏARj*SSՅ!uuaT `Z*. +33T(]&&k6?}oވS_ ;w杄h8jzizQK"7o"::woB2001qD*GѣǷ?~V¦M iԨ/_{{{ޜEԲeKl۟CCCkILW\uf;k^ ;B4\fdS:u#]4i7ZCKK SNeR1K\PF cnԪ;R>}7*UƌaHLMs.(wv$% {ƙuNC dɜ1M=́ x&":^ (a_0 +ssԫRMQLFFӁx뱐 l",ڤ 4DtҼ#<`ԩx)b)ccc\znnn 7rSF _Ǐ/FݻwǍ7ЩS'lxB صkFsfffbʔ)6VZm_CBBrՄ>(RA`B#+ݻǬ^^Р_t#JSG,%?߸:y|U)S`bl(Ԩ!H`J[I"VR^ q=BefeƳgpݶ Əe>oڅn1kx@ZFB>}±7p.?Vu<"cc?A{֬y'!^>>>~&N;KKK:uJeYV^-3c]]ZZZb޽(Vhyx5kε\%lԨZjsGo1GQ>}M%7---k׎Y=BHѵo>{`ѢE"M`$)d}+4)^DU%˗qujto?i(j8:N!{` FO3BCww,+DXc~<4৯_s ',CKGGw/YRI`L!&#$DCQK4nӴiSޑH.Z|6lyƏɓ'k 37 NNNS*W}" !Eff&zk׆%zĉ1b% Z!yߟw YO%%NR(QqqpZ^%u_gO` )dx!,; QDn/N!k`:,' |QffqK߱5F@Iu$ j.ȑTD` v- D3PK ZZZ011GWJ#ݻwԩJƓ> |۰accc$ȑ#ҒX9sϞ=cZsR&8̜97ofZWWW?.!pq|wз/$:q_Ta\nIY˜wGқH3}֝;8vLS11c~9z{ˠA(idN>uK5!q065a= //o?W\AGG>DEi&n~/{yիWs=-C) U-[2I|8r֭˼;Znͼ.!77ʊw=@"61X]^zz쬒6TTw Y{/NAT;{sx /!9˽a=|8V9f⹺֪ 'ӧy ^&88wRWQϥ,۹f͚*NBQW݃ӚCռ Odgg̙3hٲ%~'2?ѣ1{lu T,:ƍ,M۰"#1oԮXQ" )UJSŋN#9Y3#I"&f<[h2q"@CCaLF[JkV#Qk yD_"***c˗WqB:ƴiӘ/!D߿amm D>}i&jլ)\H`J[Iv(9ã^*=`DTTTz5; QDT)֬{y-Z8:b-y*_^zSu@P$DPK!%%w BH>򛍩, !ׯ_gZwިVӚgbhԨ*Us犺 A֭GG)d{X!4$"1%VDvv5 |3BCww "w&M3yxx>NB##3˽S6Um Sye&DN)hٷowTR*LBQGɘ+5 ! HIIA\\|/_ << ‹/š6mݡMgEWD*^:6MX⌳6ǏJ՘ڧgc(u&̰ڽw_63fHk<".]FΝ ֮fJ䝆G@` ZLC CÆ?NS[>\^OO`i-H 54D@@:;!oY$}@$`ɒ%xӚ?#6mʴ&!D.\@Nx!֮]QFBQ&1u*`fLp\Gt5' IDATR5*.#F . .(9;IaLMЌZ3t:u$9nmLx!5>΅ɘأ8PU./¾qS5DiB 1z#'X|9R[˝R4o"0kШvT]BYkalh(1h֌w Yǎ>>SE99-[N!))H2231sl|Vs@QKb̙W޼y;!D#BPRR6"VP>}ЦM5 !D^FFFXbnܸڵkCHWWB)d\n۶'١.ҫ+P ֬FR85N杂OooL۰!@Z Tij$j^j&-- DNPfMxxxEtB{%(bܹxӚ`ZB䡧qט6mthy-"5Jnn@⼓HNGTz[/^`ѣJ0+Q+&L`HM VjσE cJJ{ ޽; #G }\lܺ; Q3R_ܹsQ|y.\P҄6xG cڵΞ=Uv1!DaҤIx6mڄrDHުU.(KITz5>,c2rD.UQ*5VL_1E&kAA.L${`YnQ+'8aL~; Q#/JMMűc???jr"#88!!!D||D (N7$9rT>xhlm6E кn|gm&hbm AC׮aۙ3rŒP`߾˜Ui|=|l,.Vw"a˗رclق(qQ{aĈxYǍaaaDFF"#/\o޼֭['Y.pB͛7}%-7AHo>lذy*U`ŊB?|ӧc]6u놾}y4ۃ3&ݻ8v 07 bZ{@xլ ~bHC99 EIaNBS)Sשy'q:5|8:hW>zn^_3x)el1aq7eh(ƭ\}5a \,rpASGNB$Lw(%%DNPvm,_^Hٿ?ڶm+*Q&Lg"11x glٲVVVԩSqEUAi }0## cǎe^W[[;wD%&ܼxhٲ%*U}w,B T;}癕{?W69;CG.9BӼSE5kN!nW a~{TTijvgeK8Wc QIGNA$fzϱk.l޼_~9sٳhӦ 4hҥKT 111Ell,"""p-ݻQѻwo$%%1=k,iӆy]BGhh(-[?]vŌ3о}{ޱ)cc@B4`w%Ah)9`vhTR5sTL 44aI:ssY3iHa 3Rl.-E?!uꄱ]ajO U,-mLL c<<08XsN߸͛jk cjt -;T*+K坆H5DǏK%Hݻwcݼ0; <ϊ+lx8Fa@@.]uVZUVywpp<Xd :v(V4Bǣk׮M4E%‰'p nK,Avx"*KVV"\m(^~V,VURQ0oj9*ilIrkT?4)".NS@ {ˆΝQHsZkkY.\ aQZq^~N鎩2"^ M4AӦMhޱl߾kiiDž?y߿!7ggg;vy]---l߾UHVQUA4ށPvmlٲwBS ֭bc lYɩJ~\bHraSp0ft^$ӡ ^JyFx]hkv.٘;v6mE;B޾VrDhyC}!A*za``-Ze˖UahhTTÇxΞ=0Fs~ |!6_nܸqG!Z k֬[cegg@JDGGcر8y$v؁"LCQQu ر<Е#R45r]\WG7C)=`VQ/שÇy'!y3w(K㲇:ϝ;/_rׯ#(<˕?$)Qί'O//Y+yRP\\87 5~x,]'33!9KBpt.(Ki3g}s6gDaիpASRݨJܲe52k~ر˜xv7~<$DUHڻw/y!M67a/͛zkkkhiizǺYj,dgB|}}1rHdee1]re8p $D4ocR+>>HMMEdd$m% 39Waz 8uQhUWW`ta)8ؿ_C1nJ$$'+un-Z6mA1$9TE gx'q0zD42©%Kld(c~=Æ<..B㫐[f"^r7֯_/ׯ|rܿB˫"Hڅ 0ddff2maaӧOܜymB_%J@&MTrt~o˗q^%(ѣSy QHӥQZm0Y\IP4%F''j\ 3OMFtТ4s23;1պ54jǬD Y:IJ_I:u @u*< %m; Hw) aeeSË%ڵ /FFPBm[nů;!̭[ЧO<(QΜ9CKB5 v»wS*{IHH@Ϟ=q T \P`Z (Ca_eVO|XPErS˜SBB[B t VŦiD}ҥdn.NIiD`Fij$*'W9iʕ+QN4m^^^_ưvڰ`޼y>޿+W`ԨQЖ.BǏѵkW$$$0mhhǏqkB`…x]>}9.)) z+)-EH^5fBVx8]cWDGZթqݺ)U^=I!%>E3S$"Bx D- CV}YSz H` [I't:֗/_Ɛ!C`eeӧŋcFXh^|ϟŋR X&==dž 0rH$%%D!.] ::ymٳmi BxBKUƗ/_гgOʼnzB5w YAA5ߖ^~,N߹TI==l>ZZ,t;7oի_y'!h8w Yo+WJg9O5fǡW{`ր#+{`*F"􊎎ׯ:`߾},5Ċ ƍk׮˗X`j֬ @X~;m&J4Hvv6h"ڢdɒhҤ &M;v ##wDB[hh(:uO"l2͛7'ڬ5qU4h@~cƌ>!L ;{['ظQr AJ#rg͛I"~IWR0&BX4 Ay^W`왰ԡWq#Wvv60`XZZbx)Xy244qqDDD`ӦMV.wSuԉCBBŋ1vXXYYiӦXp!;!(ӧOûwD鉑#GRBզMܹs3f F Q GGw)9s]]䲆u+Wl.L(Б }x ;VI(%/{N{FI##5 03FfPիΝ@v6$DL+""˗/G5`oo+mmmn6m§O~tzzz>v*JH[QQQXbjժ;;;lٲ?~v;vļyo>ܾ}䘘B.] P;-[)SRB K__8y$J,)9̙0Qjœ׉DpD=slBqqBpDQ..qRrp0j&0{œ9Rrp D4镕sΡo߾PΝ ޱTNx=_qơDr?r6d,]+Wƌ3oʔ)ggg\xŋ1h 4oBHbccǏR3g( !DG ׎3󺄈B__lj; `/DZwoƆA%]]Z4$923I\]rxȑ %!ػ7t^/t Ɣg0 Zt)W.]#x f͚+++jrl"cǎvpssC¿([,֬Y\:t.EHQ3qqqܹ3޽+J}''',ZHڄ‚ _.Cʕ+" ++͍w LYK#!J)SF¶R /y'!07Ɣ>$9=D55E ּHӫT)ὯxqY, $D$NDD;.\mXU !ѧOݻ7?~)SАSBBQNbb"z;wRԨQXr( !+(-ŒjR0㋓Yt(D3UFD(&fM%%ʕH{#k3 (ɩbj\r0޾坄L#^R[PWW;vɓs=^zufqQӋHYFF뇹s"++KѣqasJG!KJJBqU8~l޼ZZZ'֪W___3/]Dz;V姍0A;G˖ *fڶ&oU(I"Z_wB"2wѧukh36[ea"4pwDcid+88w’BCC燥Kf͚1;ݻgj,GGG~{{{{lܸ.BZrr2w˗/R~¶mۘ 'U3֮]˼&!' @5JJ5Wয়}y1$%NBѫ0p =:LLD-(KUAԽ;0t(0,z%,; Fns1 c~ }-[e˖eVVΞ=7~{---xzzҾ]}ҥKҥ G5o<!.<<|'B6,Gs]|ADt 0ǎ~Æ qIRBxpuueZ͛+ӚD2e A#F($˜$GB缓E*%4) y'ɑ$ $V7|aS))}MIlY'kzEGG#::y]o^x9šyH%)xDdg+8FH>gff֭[A!ddd`4g IDAT8z(4h???RBx5z8Owuec#\Pf%_ְaŊڧ8DjeL)%2XxwkkI!%_+WoN"Yf%JD%$'3*U7~V޼ᝄ0qM@jԨݬ.OXx}M-9?/_xzzzͫy-{ܹSR_O !D2331b:tHjٳgajj*J}BIKK #F`Z֭[LR&N!CVBak L;w&Ed$$D-[NNS {Mi(+ssfSR 5cۚ  W֤I;v Shf>zqΎ\DV:|0.] }'HMMŁ |7\kTRyx"222[Qzz: l?zQQQf$%%Ȩu-eбcGBĕ#Gb޽ԯQ.^2eʈRBk׮psscV/ Y-BgaH7)eԩ,ޑݡ/Vy.U kՓѫ02Ϟ KN(pн;;IW 3\D70`V+95Yo~Qxҍ큁uYth\KGG=z@=c_{Abb51c hBĤ(t/_^BBB憿K,prrkײeгgOUTXhh(֯_S[#%%ƕ+W.ϣzGӧѷoBG`` ߿qOOO :NA'I&aݢԯ^:.]_'_>ŤÇmF"DeƏ.(_; >8? ?LUdZ;G /\C cIq+-`v`dD4ՠ~ظq#ñi&/ԟ:u -[D&MU!T9pwwСC!Ǐk׮شi\CvsB-צM|Ϙ1K,ZBBQnoMÇysqq͛R4DNA4ɜ9@ÆS~z1h҄w Y N!9Ɔjed =#Y=΀&8!ЊDD7nƍׯGAFX߿c֬Y8p Qn]&͛7G\\q}8rw^8ph޼9V%KbrC>>hݺ\GQR%̝;"'%D34jǏG~6qy4nݺزeKc6!$/...Xz(˔)sΡjժ')c"V-2!X[KoL}\)BD~UHoL} xzoN" ,^ S lg)TP$L200@~Я_? {w6 |˗/;;;;hF7m8}t :T,rl۱cG|>>>8r߿oǵQR%ԫWvvvݻ7*VoaÆVZXx1.^߮)ڴicǢ[n=?ٳ ]nmLMMq=&,HQyaٲeԶj׮-J}B%K2W7BԎ-0e v-$DSl 89"ХP?_MAKf̜+x',XqJ%0YX1fո10k_9'33'N'PvmL4 K_ω'sssM [###9#Gh7v7oǏ~!=BWWMh3!jk577lllDO!ؘid,EKz ah݁H`>Ir| _̜ 0~o * N;I@`:yR4\dggC^й3%,-(AA59@R9 caas"88GEN 8::|0a=z$s<22ٌ7/???\pϿ"DLLLd211)E!߰xbQj*U gΜA=ڻR1GM/Fx dHK)d;vYYE ;\ݺlʬ*^0hгjY{[Q+:::իΝ;/^`ԩr-ÑM6aÆŁ\Ϫ{{{tۏڄBHQ_U%KĹsh(!@R1U_!D6䝂h3}&oLJw (ggE )d8QdgʾiLhZϙ3S9PKN5kիlذA;1h o߾>&&&I#BHZ 3g?f͚RBMBBzg"9@SMT;}??)\]jxup,*z r2LQϹ <;)5 &LǏqezzz>/11_|ؓ'Od!OOOL6Mŋɓ'ѦMQB:bbG!cb"\P64䝄h~Ɣ^?//CI"r2-@@$*uS-˴ )SS>Mztۼ|PK ڵ޾} /{y"""A!5[l( q kN>}Ĵ"EpAVTޘXxwJ&@P$*üeiɴ^XY 3S$6Xc+#5(W-Zw;++ ]v'>p{)\B!(ڶmƏlǡCСC !D1DM/RdjL;$͛ӧN!`|QƍYxxxB##myԯ/Oԇ\PӋ!=== 0W^ŋ/0uT|}NNN([,6m ˗:'M!I;vرcż>|}}ѵkW !D23ʊi=B$G``)&qp BV` n; QDQS Tl,$|i===Ԑž;cN!`jzVZXz5>|+WZeee! -BڵQ~},XyoƵkXD'B47ƌ#JKOODݙ&Mj_T^i=B$oHK)&[7)dݺddNB1hг'nx' WckkgZSa}N!}a߸TIȿJ*ggg899ܹsXnN<)E'Oɓ'Xx1*V޽{W^hӦ ?ƀDYB4СCɼvލRrG!ʛTJ*3g_T=D++RX^Jl!_ׇ.h&&j1 DF 8~03 ᝄ(QS7oNiaL ; sBCqk5[֮ʹ&M49aLImvcFM/B.]ХK`ƍغu+{xzzƨX"222$ʝB!ݢ:::صk 6!hW2fy"1xۯ7_ xחY Փ,WWa7ox'ɱ?`nNՕ07c-)nTka^Si{缓+ !UTnݺ5s~^B9AƎ;0 ދ^H+YR'~* xyNBad$%y'ɑ*,p0Q!aLIiVvz:};p6$|ĮוL/TҼcqwjzqe``~wƍCCCޱ!si 4kkiiaÆ :t(ڄiôf-#DT*\_ի5[ȯR%鍩` (w++aƗ01ӦreX3L2lgm 7Wx')$4*&M`ӦMǪUPreޑ!pYOHacY---[ƍc^B4ôf#D-5o.,&%>@D$DfN!+, Xwsy#.-5g@vdn]%%{_h($E5$TRprrBpp0Ο?ݻCKKw,B!D-?{FJJ ZZZĉ&M?iM333Hq Bxpp BLxI":wFBV` v0K;;`)dyxzѼ($+;==)7ڶe^ xZDENRdQKaooǏիW3gL-!"q׮]C>}Dix)SRB4ю;35۷om)-kCo"4MaU%*0x0Уnx'!0Ӈw Y Ɖ:ؖۇ/_2[JԮXy]Q3з/?LJ❤Hoj˖-ûwaԖBk׮HLL%K0gQjB&… ׵g^7}ܡ?x{NA5u*ЪN睂(j$M)d;;Es)Jm/m_:N!ES^j&LӧOq!TZw$B!Drnܸ$$$R~6&|>J^B5gy rsjB"Sw Y>>B^ CYkϗGNQPK ikkӧO1vXq!ɸu~Gċo̙31|QjBڷoünϞ=annμ.!H\$$9RS%x'!00.(KitaLݹ; Q0,,x'ɑ!,z$z.s"Z=GvK)[gi;Il`.UIjz1CCCxyy~Bڵh iӦ᯿6!h7obܸq1b(u * $:X杄(|y鍩X`Z 0wKKI%Ã7_L y#N uIoa!L$GBq#9$E541l01!n>|{{{DGGR +V6!D3#U 7?Ç e˖E.]%$EJQ&̙S <<y'!h;w Y?"n]%l MD:*Y uvϟE;GvP\9DZr)V޿睤HXz5LLLx BTǰׯ_E?f\Rڄ kkkxyy!33wѹsgƊR6!K`H)d sDz "ƌB֛70 zh&]j XBB1%r4:̜"żERcêA@4+h%c5ֱ^{0&$73KL,b&F{FEQ"Hc%9٣&(>x+/p8;ך,]a_%^Dr0lADD.^Ν;#>>>_裏wQ6DFFbxk.X`q{CͧW\ya~6t(гtѱcK%C S.P @S59zduSVt 3/G!C0wÅ yѠZ51@_S۹X1Ν.)t8""""p k]vŖ-[xl޼'Zn_8~8233{_s=QFѣÿ{=Bqcݓ̟ܺҭ` ?|Ԙ` *Jtԭy  8wW˝;ԍZ(+ ?ݸak4<>qo+U ;z \\ EԮf,\ugLDDDvڵkuyT IDATp7ʔ)#ALxBBBpqqAӦMѢE h͚5CժUP?G_{ 6lg QAyum*WŋsmHӮZS}$]bቛt T6Iꮽ|`pz)jAmuN'}=8E==Q %]\0=iiILDt|@|?Qti899YYYHKKjݻw8TDo݁QKHDŽ jM}tjM+]B:ƎUCK잃Mɽ{K5Jkuw\5 D$&&Jg䙿xץ3  0szY!EϞ%bQC 3mmZS/$]B:]S[V_^SN1ٳΧNIp\+"@DDDDDD[>>>x3΀!]b ] 9"]B:9Z^^%6YYuj MOK-'GG,<eUJW9#]`8"""""""SpttIJeA:奆frt)pt Tk*gNd 0Pt.-]`˖ä^ŞlY5*YR&#CqEDDDDDD+͛7cҤI)DϮ ?3KHG[SDEoo_ _|Q:żj0)HTݺuc)DԾ=0~tQx8$$H6m@988`R^> *T1ٖT(pEDDDDDDb'NE<0 VRSKHG>AOtQ]2?X6e 9;K؏n݀å+(pEDDDDDDbŊ/~z49 DLk']a l,]AƎ:tx_H b8r%7n,cFP/kzQqqq.^9T\. ]@FAAgIW.__Q# O> V cuÅիֈ($dfTЋ(jժwww S+RF˗/G2e99"]A:,LdeK.??+lV`oKT6Eoo888H+^(&+c̙<+/Y,@C/"""""\۷/nݺ}aN2bŊ^éSn:T\Y: ZZt)pt Tt@r2|9pt psSkX1` yk z5 ۶Eg4U<<7t(m؀%'tRS3tiQprrBǎ"::ĬYP^=4+Vo7n`͚5xHRL 0>%]B:WC 3sGHQLbc /77C~=>.Ŋa@۶;q#5 ^nnY[j=E¡QsttDv . <<˖-CQct2doߎ̛7wMx8$$H6m+""Ԑ".Nt20etjFvFŊ'#htF-v놭b?Ag˖p,KiS`l !ݛNDDDDDT8U^&M¤ISNСCow!))I:Q+zs(^tYh(r%0mbだ gնtӧ%JHPNꥆ%6?Ϝ9(UJr{w8ǣ h Q}P 2d*S5*VDڵѡqcҤ jV$EХo& 7o͛cFHH>'ODJJpUX[FVкuk4iEcʉ`3FtH</޽%qFV.;{jDArj{j_p?\p M1q[ҨX<+_ WG5РZ509wd4tZS.]B^Kg`0dHnS֧GHЋL>>>DDF>} ߻w_ܼy񈏏GBBC$''###Vwޅ+dɒ(Z(QT)B 򂇇<==QbExyy,._YYur5O]TySDZOOm[TdtƍTX2_ԵkZ?5M7mRΝYX,Y@Xt H2eаaC4lP:(w?T֕rs]PNOQWժa$$5.]B:*WVC 3{XrEtTd?Qzح[ ǏܹsdN$""""""7nٟ-9f 11%iSuƗܼ%IG(:ZhѰ!_&$@pfϞYYYO}\%зo_L6 /RV3g%KJPNڸQ%`r5<1vy=]qqu%6aa9sek(:vTkjjWŋ@L[0Ro#g^P\xBTT>| $''۷oGƍ|>|Mk`ƍظq#zTZ5oC@ĉt ȑ=%6!!jMM8:JPN .(tѣ<ɓ>d_Vv.9yR)SEk(Wkjvg^-Z :u iiiے?O;wXf DDDDDDDc:~@1kR?.]bkZSCHi#GKl PC9?'SK٣~O)]B:&LP[4:$]^Ξ=~!G߳n:/߿`ٲeyDDDDDDDd6HW.^]hf`> Ԭ)]a-]A|}:u+l1]3~~@4h"Ϟ˘"""""""SHIVΞ.!J ʥJI<|Zt (QB]P.W.G?-tW#e_Ѣj@.]b Yc)QkBg ^ŋg˗ׯ|||~=+/XV3W\ɳ$"""""",\DDH?3IHpQJה5R~u.t)rR%wO˗KHZSNlٲǍ7L2bg>)SѬ:LnTkmѤ #]aTtt h|`| *JtԯvW.hѢO~q%̚5 %Jxc/^ 5))]4u놑#GSN(Vcٳg~-DDDDDDT\,_ܿ/]B:vF0 -KHGǎ1FWK;o']aLMH.!m'JW<8ʅ={ ==;::bѢEضm*~III k:::Ý;wW_aڵػw/_nݺ=BHn%]B: z0:rXVCg`W/ 'իY_d0 U[>|(]B:U^뱯988`Ŋ6m͛ __P>S4im۶>FDDDDDDΝ@LJ&2mТt_[HW)SV++Hĉ3 6m ]:HWjzitN>x =:[ϱrȑ#1bĈ~x !""""""6IW.YS(0ؽ[tY,@:F[*'??A mۀ> ]@F^Ǿֺuk̛7/[?…%K:w 777ٓ!""""""+V<>(.(+']b|1pt (ZT ݥKl23֙GJ"EԚcl ܣGjߐ T$]Q(qرc`8::fԩSQt?|#7onZhhh^Ȯ$$@xt RE]P6wK+WKHGJ[SIIjMIOO5(bŋ%]*ZT1J˙3g /AfͲ9z*U z_V-wet͛?pt h3G(:?_OÆjHa&oSQQ%AugĨS%N 4>իW655r9ͿlٲcbbDDDDDDDv+, X wOtt ds dOqFԄѶ-0qtQDp!?׫NjL"]Qp̽{"555ۏݺuQ\py͚5sDDDDDDDv-- X 8yRt-.(ϛEed3.!NNjZtͣGjMH.TIj֯.!]f+q襩J*lܺuڵk>|g/9 wŋ+WKHs~~FIIҥ@6L&S0atQr2|9pt pwWEKl<>8^t/.]`8Ժuk{{~g"""in/m׮*Tk>vW/KDDDDDDTP?4j2۷ *Jtx{K<.&X.!u ׯK84i{hѢy!333ۯ1x53|3w*WK;t']aN5`" >^tjL,]at|J(45n~݋M6eK,~e2d"!>>>pvvJ'N K}+NRƥIPaq b"]B:zrxC;^mut QK#FeZFFzEܹs'՚7n\]]H/} _Z*N$""""""*v+Hĉ#n^ or&z%+Hט1@ǎF96Md8ʅ3gTRaƌpwwG:uPJHJJ:;;cƌ4EFpȑǾ'Ndu򜛛t֭_JW.__((صKt4l(]a'JW.I ;ۥ+ ^PBO^ZZ._(CM'L?OԮ]q){geeg_(ϼ_5ѣ%I <=Kl=Rk*$DtY,@J6V+aCT"]aaptQ+N>}UV c_駟ZBZ[oƍ|{EtttHҀtQRt)&]B:*TPVr2|9pt pw|}EKlYL.HrԚrq.IIQgƝ=+]BLo6mB޽s\KƶmPlYGcܹst6XVV>6"""""""mfr6ܼ)]B:40ߚ"#KHGݺ[S%[ $.X.!7z|s+WKO8|mڴ֯_@--; A<<" O:ZI~+ΜQ[H޽+ΟW[>x ]B:z 0tImɚ,]B8cq!|5kիyzzwزe N>&M[Mn@DDDDDDf1i7滽{M+H@F7JW1c+6lrp ȑ@׮F!!ڵ@Vt Qr(ڶmmŝ;wPD =UBԨQ㱯)SbŊ|~TT 5jԅ IDAT@͚5DDDDDDDb,`,mgOajΞ.vw#eZS%6۷滻g,MٹS)H z'''TX+V˗q ''59sGF֬ʗg% _T۶5SQQ%665e){Ԛ.ٴINK7$""""""WR88Hܿ|:쏇,]bb2]}j"]bΌ3]}K5UtÇl.!z?I]3`| 2Rtԭk5 ,X\.]B:ͷEue_[S @xt QqGۘ?>KܻwO:ȼڵ&L0vM]P.!['KW]Tlt h6M 573͚m$* 7D8ʥ˗/{R 9s7ٳѣGxyyҩDDDDDDDԯпtљ3ʕ@jt &550iҤ,#""""""3ǫd~`& 5f +F~ _X%c(K `Z +Kt t.]atf )]BC/M5o̜)]aoK_̑0VKC/M9z|-жm|!""""""* 0:w#=ٟ=C+.^>@mI[7` 0`2=ѹ30ztѕ+jM%%I!4UP![srr€! cW^0[`zj.!F]HWkYY%cp{w #GԚ̔.!C!;^ K.45lߛ}+NRƥI+Oxxxoȑ#޾}PfM=gϞͷՊ{/ߞtQۈɎ@Pt9Smwh&l*]ANU۲@`t4 hFh^`f "z];w{iiiXf 5joooL>}ѣ\vzz:M\?]XU+6m ] PtQ` ][hV5"dKW!=0'{??~uؾ};Oʕ+@@@XbX"ʕ+WWW\rpr5qqq8|0\""""""z-.͜ P:uk 58;;ÛGF?#]B:6fϖ0y?uKt4nlA*֒Z[d'52{*2RQzijРtVF/˖w5J(,Lݝc)g^y;V(<\ݙ(]B:ڵ&L0vM)lI47ADDDDDDDt&]a꜓L1t(гtѱcyp 4G)`*u~ٟ~ԇ+Vs. ;(_<|_ ݃oމKD4-::{8gdLuֱcO瀇0dt :SL+|w7RLKݫ֔n0A7%65ePK^DDDD/_756I(wd^5\oش (_Yt¤KleHc!ŋ%6AAjMFE ϝ. RF*&ooo+VL:T)5(]Z&-Mmvt pqQ]]%#X\w5R9;~~.PT۱~t ppPKlV`z!zFp DDDDDDD4ժ f,Y\*]B:*WV$) X\wQyy5%uWܿ|pt P9;K$'}dРA3ӭ&n:\R:RՑ#GdɒB5DDFEF;Qa/Ξx9Mنߺy1C P!+QQ6nmTQxqߨ\QyrM///s;wٳ]bc ksC\^Ov Hge[hhtѯ:H80TޙCyC) WyqMQ^KKM no z>t=3xW.pd͛7ǔ)S3*117n!C]Ȧ#DDyvx~} #G۷+Ud+Փ0dyQlY'8~\[7kIsmujtԽt ' ơW.ԬYŊCZZSSrei?<ʕ+<<2==111ؿ?..]K.DDOuEkܹhԨ`o^DTxq ѣ95f^U:ODfp*Х гtܼy08p jժ%XVZSI\ t t 30W/]b.7rKz傓ԩ3g<=777,_G"jŲe0m4deek5bQk ㏁ͥk(??bckL`ZhRrUk*&FF֭֭݁kH/k,wZ jMk']C^ԠAdž^%J L<ׯ_& +ZQtҀ #''Uה3P3.=##"~UQ//{*WV9sKl-ԖOd_l=`RjזTfRCL3HN/WC njlo TJ GjMqC#^.=\3fl5k,,\=*&"""6p 0rtK`" Ly kH_fz_Fx Ĥѣ#5j,ʆƍ.Vk7@KÆ{I?*W__ߖ.sǶ^rvmugoH 5Ut 31b@ 3i.!}JW=KI.!zCHW>39Ytt .]at2lpt  jűcǰh"khӦ jժ*U ^^^miӀ-+زEtM j%]ag(]A&Nڶ0 6m ]:HW<l ]AF:w0;`zj.!#FݺIWzsڣG%d8Gʕ+E1c֭[ÇիBbb"bbbpl?ӧ /`ǎXODDDDT|}5+ݻ+Hԩ#]ae}40 >LtIWm|t3xE ;mۤ+H̙@Fv?^ ..'ND:uyxxqJJ 3gΠo߾hݺ5.\gODDDDTJP˕.IOW[?.]B:U/wwL`QZS*Hde!!%x9 ظ8tHtUHWm8 ]A|}ե+6m +QFg̚50 K/>V2LDDDDJuAL.\.!*oMݻΣ .!jM99I$'ss.^.!nnrѢ%6~?/]B:ʕS%KlRSՙqOKRԟ}KKؤV'OJq蕇֭[nݺ֭[YYY{c_OMM믿!C $=j0W$Ӱl&o@Tt _|k*&F.!uo@ ,XDDH5ͷ぀5QIb"d pt ^yd=zt"E`xQmݺݺu󭁈(tc7+W_3:IW %m[`D `B .NtjL"]at|J-ӥ+"#Հ>&Ft4m ̞-]atZSoK q9^{ YYYZQxǾ7_oDDDDDfW/ 'իY_d0 V>.!}ue&gϪ-RRKHG^?3'%{w`p KԖ|}9R(,LmG$]B&áW.bذa(}WGGǾ3fhQ2EL+Hĉ3 V}7NIh&7JWѣΝ+֭x}1U($XxHt !]at(@_'s+-ZBXbҥKuV*""""<`NdV/+HРtѶm]Wg&||t3Gqi&;vUdf50ڵ  ]Ӧ-[JW}et^? G[o͘1+ """"P|Kddw'=*]B:QC OOG5k;>Y,@J6V+~CT"]aq#ptXե+6m ] -]ae {t^&8mڴyn;#PDDDDD*URC 3IJRgI ԅ"&pr:ETѢ%6Ο.!ʩ;SK.IMUgƝ>-]B:JRJ.IKSt pqQkU&=]msxt M_^:%K)]B:Q$6X.!5koM\SZ5TBZS%re󭩻w՛Ӯ\.!aziAx 3'%%a^&""""{֡0ntQxP ]B:ڶ&N0-KHGV)Fׯ5+]B:ZPgIdzGLt hLe&7o5ut h0Vk*:ZqoţG~1ԩ&L[0`Ӷ={|׷oߞ/GDDDDT`0 U[I}պ23g+az0:^mut 6L%%%kW`H 0uwNRt 3FU`b 1Q8Iثcǎ={_VZ?~ڵm[lį9r$O_?{wU{! IDAT`n(\TMKrռ.2d{ݺR.i*Z{(\Pr Qm:̙~xs>z^gf<߇DV:$ln|y`p$ȑj́IWsNBzS{J'1;tHͩ1cGl@7tSvI'1 VsjX׽ R*wNbvڏi8H4dy*(H:YhSkM\Sc63g{m/h޼9ƎkL+W~㉉f\""""r>>@)mۤS^&%Bk&`哑l p5ejMg$۶?O'y^?6H ƍS~d. @: `K؇?I&͚5u$/^FDDDDUbE$f+W;>L@ժ)rrի,c2իK7֪FԪ%Bk:`)B+ عS:e2uJZX)_S:;;?K.mHH~Bۛ`EJKu!}IMU{<#SFjsڋY$G2/Pt4`R)$*RH'1wX8qB: Q:O)#,#C;zT: Q<*,+Kݜ }K/wެY3ԨQC(ؿ}DDDDH4Pj$!=NBzԭ.(IbS4Bvxsu``SZꂲܼ ̛p[ TTRp!%Zxsm5""P>aKt/駟7'nVKDDDDm[`hZ.s i0XUxى-9F̚ d7W{|jNK'!=7V{ɕ+'//ԜtI: tzpW~巌 lxf%RVNuj!&x5ZgΨVwH'!=w Nujɚ":T:Vd$hZQAC`ZQQjٟv퀑#ShEG襓=ϟ?/D˗CFR_d~`Z׈:|-#:T*$8Xͩl$ǠAj$!!j,$G@Ϟ)VP{}[:VXlړ^:i~?{,;&e׮]9sSz|JCDDDD$dRTd&`V哑l l,2hT:VP(8Nc~t kxukZv)H1cTKr#ٻNAyE/<<<zlƌY6n܈}O|#""""S&<(rrի O>>7<[8p@: Ԭ)BسG:e2);S^&Pt UA쓯/Рt mۤSPaK&M<ؾ}0|pdÒ۔L:o&<;ʔ)癈D"E"IRS^LgJ'!=ʖUYTZ3)$GRjN=e{ˁ'%J F| ptңhQuruNbZ>,(THͩJݿڱK'^.]NBz4hVIB:O=p^:9;;W^O|Nhh(|}}Ѻuk.]...Dݺu1}ts]oDʕϢL2h֬???>}ZW֮]zz5Zg_ӑ4H:Vx8xSO.!)"#En%;ѩ0|t (`ϫ#GJЊS+Tm #B+&Fݜvt0j(DGG#""… FBBRRRlM6UM"""""+#FFzO@.ڔ  t,B+8Xs> <M:VH$+K: 1`гt cǀ+^_dzN,[$$ӻWFrꔚS9!eM⥗^DG@DDDD$g Q#Z7OSF79( NAzMx{KڱX^:5~<кt ]ט1j ['9hN:ڵ)X_|'''Tvm3Z՜(Lt 5kS^@͚)={S^&)BkzS^&Pt ᅲNAzK mNAzLt M-[SXRV0h}駟H"1ʮ-T/.,- XTR!SS..I/W-(.()#,=]ͩP$GѢjN+',3S<|X: *VNbvSIH/ ZU:YNjE~t^6`գG1vmH_UgUK]P67yh$TR0>%VML5d`B 2R: Q'YYIH=Sh;| !K:j߸t$G@߾)NT{I'!=^{ _:֙3;I,z٘7BBB흯}_|1_KDDDDdN6Nl(4 Ocat kxU+Z;w)Hc^N{7/5 hN:ڵ)H#Sh:|-;m򀧧'~g|xgXE;#ԩS'OEDDDDP|}5ShI ||Z?J |}}߰{ԯ/B+0ضM:e2^^)6mlNAzM֭)(X#Θ>}:"""0yd1p@:u _|+f񉈈^RHQtwU[0$Gɒ_IUP$3Ϩ9UtL:a$S+J'1_ͩ`$T*,'XF!d2իKZ8p@:^yRJŋ_s(Z5jO>QQQ."""""kxx/Fr&0o-pw7ޜJJժ_F ,ZDFJ'!=*URB, ,Y;'puU7YqRS^LgJ'!=ʔQsxq$fiiSSͱ.]?k.ܺu 1g7ݻwGfаaCxxxM6K/!CGPPp ]?1hL,B%`, >^: Ѥ 0mt +WٳW?.իfT+gpҋV/#WIVtcGZG+VIH7zNu*ĥK'!=Nuj!&x5ZgΨ;IH݁ASh;ZJ'G`ы&OVdv`ׄ @V)vS^c/$Bkn_:5jЮt uS^#F:H:tXɑNBz  t,B+8X ΖNB`ыL&C:V@)H/__NZ6/2ShmܨdL&K:V` ut ktQ#Z7OSMJ R*2#9%?#yڇJ'!=yFͩr夓ef֙GH'!=bE$fYYjNt\Y:YNk!$IZ8p@: Ԭ)BسG:^i5j@b gggxzz^ /񸻫 5F,X?/VM]P6d`B 2R: QSNNIRRŋ^'d*TPNbb:{V: Q%%ǏG #88qqqHcC#::۶mÄ PF <GDDDDTp4iڨˀptңQ#` ZWfEaCy*.N: QTb"0{6+]xsu`\ &F: Q͛@tt^eddØ?>z-4m+VDQV-4l͚5CVбcGtCr 6m ";effbڵhذ!}dee?:w NV$'K'!=ڷ~[:VtPstWѣSh].(?_26mqShƪ9(h8Q:ŋ@tңys`dZ.ؙM^:-[ĉn:?~V޼y:txbQI233GsHJJҝ0p Уt #G+ $ǛozI:~\ٙ>}}Sh< ,[ܽ+x5u2ӧVt>SIxjɚ*2D:Vd$hptE/իgrrr0|pV~t )))6HFDDDDD VSh l ;x%ZwI FRd>_:juz5#6L7``* ]`uN\ #tڵů)Z(J,+WDPP-b=#lSG:V@*~}QI` }t dR|I` ut k lެ~>M 4m*B+(H>Mx{Kڱ7 bK_~ sAL2 [FF># 7|cq gQEeef6GH'!=Q eeE: _+K'1Q+sNBzLt 5kS^@͚)֭SS>)NQ SB0gΜ'>p5j"##gjժ=g͚5͓.ُv?#IN.T{\Y)''$f))js礓* EH'1KMU{1=+([VNb,]"S*R<#w՜ NBz,TI~I gyR ۇ 믿KƴiӰsNbǎ:t( ڵk-Q#H^f._NBz4lhbjB0{6ptң^=ͩk׀9sk FrS11IH㝧nƛSII@TtE/+?yJ#44/_GZtF!<<ХK4iݺuêUyf.\Xٳg[4>BoKЊ,nݒNBz 0zt huM$G6ر)bbT"1Q: Ѫ0at ??UT%Ӣ0yt KԍDIH&MiӤSh]SWH')0X޽{XtCתU {A*U:Ʋe,:fcT~Lo_ƍd oVO?W99IHaÀΝSh9-<M:VHj%0@` #C:cK}=،3ЬY\H+_jԨ hۻwoCDDDDD29Fl.2>_Fl*1CGh$[7K N6Nu+qt k$Ho6lNAzMڲΝ@@t ,^8qB{r0eʔ\x3,( OXEDDD@ZZ._W"..vp-ܺu IIIAJJ rʔ)pqqAQbETT UTAŊQZ5ԩS'W+ĉ|}՞F٧&+Kݝ\;Zt YKܑNܽ!,_xJTsj>J^^eJORdkV-yg穛7(ʕ󔷷tĢN&l׮]_{- dɒ߯_l*nDDTp%''ѣ8vN<ӧO#<<믿_g}mڴA۶m^^^ (6T?L:YBM{%pvvf l'K'!GѢZE1{tK| IDATTJӐ4M ?s$fWfTji +!:-[V%6mڔ>WYv5o< *T@ƍ1qD]Νף?5j+W"/m`N=ݽkoĔʣPkzo)Bi`2՞O]ekW``Zj%EJtңS'`0Hڷ~[:Vt -$E/,zvߏ˗/ù>N.],Wh=Rb=MNNN> O>X"^xL4 }nWw0|p?Dbbt$"zѣW^NonE/ׂɋb8Y#6L]T&!CTH~Uc2"=H/IaK IN6mdѝ]u|X4?ADDdTgFJ &`˖-qt|>pD||>_F|]l<D1C1͛ Lo)ȑL )H T[V"[;V6ݻ-9E/^x{yk؂>+VD֭-kk֬Ecӧ/RRRz߮89BTH{dg~ {%sׯP;3o\&ʽVS=^Ӧ7˗oNAz5j$ WLMMN`X„ zl—_~7nDorQeNOO: 99YjժA_]"-ʈW/_?ZNKt&.^)iSDTu &B+&F:Y}{S#y`hdC,zY7@z<22w~aֆs={9/^<ޥIDDT۷mڴAllt"#W_Nuf ?{H!K t$a۷99)zNA7DDҧ!j*/^ܦΙ3Ώ:''GĉQZ5 8-.\ȂgΜa;'^:͛1㏑"}6 hD:@`t "2 T[V"[;`k=Z"Ǣׯu=HLj#гgOc?3F777x{{cHLLx/^DhhMt:vk׮IG![9yg/Pt??Lt -U""MkKxXptdՓNAdR|]c^u|(SUt .|ٳgcҥr劮qCBBEDDD!22=z@*/l; ૯p$GrK3H'AKCJVKNbv3ߤ/ʖNw#)H"EԍDI'!GS+K'!+e#:uBHHZh{͛QX1'Ξ=k1 2eʠvhڴ)6m:h~ZlM...qr;V:JBI'!=QE AiF`SC.ɍySZQfTj*p!)\Y# T1H$mznݺ ֭[駟O}Mjbȑ(\p|rKDDhQvmXL 0g*,պ50~<`MDLy4 ;W:Y\0k{@JiHZFK'1zUH{@ժiRFlI^=usGI'!X1'''{F\\~={ q-eˢAhժڶmBlp¨^:<<#""rdKFӦMѢE _>իE8Ŋ'<==ѥK?}6b۶mضmmzܧ;v,ZjOO|=.ST IڌrgOu _uS+֬Nb,YL*%@3Gi'ٗD` $fӧ# lrFx祗cŋXCիWǨQgF…>… t(_?*TE;"""{Vn]+xѢE ԩS'On<ɭg}ݺuCnݰd۷/eXJJ a׮]y~,'6IWEݻpFYoJbULݹS:Yp:O Q*`7mQ<$,4X0n S7M#ҫat^vW^쎇:v숗_~ T" *;cǎᅬk";;;O?bԩSͪ}IHiſ\Io0ySG}mۦZ ?95xtc8uA知ޭ԰aIQۧoK'!=~[}ڷO: DDDD6TX1tsŹspy|W0` ^Y&[;Ϗ7mڴVNBzի!NmA}6 "5 UK:j" X2&?HۥS#ٸ;׌U%n/_?7n`׮]8q"ԩ#j^^^駟9 s+$G2o͖0ӊ1kZ(9uAHhaIQdf6FZHWzPA:YVj"Ev6ZHUNAE>6A;vĴiӤ# TR׿w^cʕٳ'JbI0Lعs'fK,ɳIHb"0{6#TE< J/ʕ,9c*嗚5e#u XNB") XNBzT.(jNEDH'!G ,YK'!=ʕSѹߟ9lɓػw?DDDD6駟b…h߾}2:_~AʕdCϓI''یs"0w*&M'1f*JCiS`Z/fIQ\ԕ+IH/:T:VdZI,j5!ٟvQShEG7oJ'!GÛYV ) Lڵk8t """"ݼ~z*dp[ldrrCBp̊ח }N8ӠA@)V1eZ_}ӥ}}H -ݓNB)5Ҥ=zH(0E/Xft""""tS=ŋq9Ku+qt kys/?#+#|l\n$fDeKZ?_/"@kn){6z4+)S#9pj5|8Щt zUZh3ٹO>6w6 dZ`~Ԫe˲ _0Q`Kf2kKZعS:U Pt ;S^>>@)モNAdf`&״i@&)uu7nܐBDDD[ѢE|}|L2wU S..HQE/ g+ El+F&qŋ eH'1PmNBz89󔫫t,`J $D: QS*I'1Vmݕ/rrj^&.@_EfͰzjddX3z 6`}IGt:0g $fW{" //uϤ%$̙tTjN}d6t횚Sァn Vb"0{:Oլ),nN{]$Z;w`5(W5j&Mm۶h߾=J(! `РA6-zegg#22^^^6 9u)#E>e V R_Aͩ+?,XAOv_K'1S%˕NCz%`(bb z$uUt70i0wt777o1k,˗G>}phDDD$5m|`[UIHAfX9pLkI:vLŭ S߾@)I'!=zNujK&→n5ILn) <̽{ehѢ~WHDDD$]v6͛6 n6`Fĉ@˖=< @V';6nкt ]ט1@۶)S^#G*B`H_`j 'G: 1dеtE/;vQncǎEzzt"""РA; `e\f2uJZرC: モNAz?/Bkf`&Hnild/``ɒ%hӦ \"Y:ul:^J5C.ݻ,_8!(QB]P.SWLrxȎ-ji+$GBjNU$,;[,UNa] :$Q`׮NAzL@Z) $gѥKԩS(^H,֭[HII۷qҥKرch׮<*Uqb"""25jt<*n{NC^0w-+yWDjUufd$fokK!KUԔ)ijߜzӐʕS+&O6ξw_}V7R,5mw=ʗ^xA: Yy7YT0p@899Iyׯصklق>7"":uBHHJ,)HM3g#C/fWiBnV+7CK]Pǫ̙tTjN}tOUԭ.(tD`w5Ӑ OW us̙\5djT+Sg̐NRlfޫR ~'[vqQ:uٳ 4k?}4Ǝ HRRl:w2Hm$d%K%ѶCW#ShEG7oJ'!=ڶƌNׯK'!=ZƏN ̞ `dIShũ}BtңiS`Ml25ڦTP!G+>yWFPPP>#""" 6D6PH;(`%%~}Q+PR-B+, XLIHwo5)B(-2={Hw$Gn)ΝS-Y&>u *(PkڵknݺIǰcǎ1{.L:FiLDDDy{pU2&$g`z CBOVaP6qQV޽t kHH֮NAz t$B!o$ǐ!@.)UԾcd wNQ `UTvm:tUV}oQQQXb@*"""Om܆Zj6X@st zT7Ϫ1+@)6nmNAzd&`״i@)nU*OS͛Kڶ  NAzMl)W#\jհi&*y!w9WF Gv,# 4T: =ŋqي=h X%"V*RT(}Վ58X: e2WLNzZCdWNv-t djՒN-2ڵS8S*[^iժFΝnZDD*Qc['S̟DEI'CΗcڵ &MBdddF ,$"ul=z d6lPnݤ83/y+V0vΞQ** e2 5NI'1۴IzNBzL.(8!lV5xm>/F IDATMѣI̶mSsj$ĉ/$D:?*ou#θqjNK'qްx] 9Ei,^lY;..ΝV,xݘ3gMYu9L`JuG)_Ϟ"+lרv颊+(K=3ڜVV+t.ZR^Eի4jnUC57֪FԪ%Bk:`w\Eg`<"ْԭ+!pqss.@\nP"@izjcGAXX5j0p@#66ϟ1zꅚ5k"11NB {lA%$$/xh߾ƣ 9YPPt~~ȶag?899*/Փ'Fiߜ8)_WO: Y5 c$fw\]xYY8㑑r\? \IO$\ @ypP㏟xƃiij8WW+F⢊'s=`r57NCOq?;/xT"/_V籜wr\|F+ uuus<:nv͛[;巢Eg1c?Xr0...=vU$h֬Y۷o?ҥKx>>(T BY̙t6s*~Uc|8d}Gam8nU+7-UiS7}$$rT/͛#FHк|Yͩx$^Xxڧ당[࿧NYUʍ;,0 jk}8 ˒\?T$`>)NNNxwj[o "ʭcԩ6?)b19~\IONp20/u1 ƊSQ1M>=~8yRc[3gTC K0ib=~Y]> lsTKVķOmJ'xXd$h;RS1j\lWZZHGs(usZRR#2.Z=F[-zߗ-[OIVN.lu'zt|"XnlӵkW6 ݻj)}]5 hΪڵ)-[J':t[]P kBh`)jNeoD!!ʕpј) r-4Z8v XBET`Ο?ݻIQ\rAAAO|Çqĉ|JUpnn)֬NA`AHسVHB ;S }azUP%* f̘1ϟpAHLb|%CFFF[]w#&_SA8xwЫW/KdIuA>ҧNH/6l@hdUc 4EjNiTٳIHeU1xq$fiijϸSAAz@S{[ u?!>(SF:YF7\D _+9LιG+??}o\YmRIl,L gN"Q+W`4pg,ǁF 0猋3!"\ 6}*>fφӧu'n,)x_;S9sUG6]fϞ}ߋ+… ̞ B!,,)SШQ#T´iӸqSԩ-) M47ԝڙ30}:\ۯ-^2[9x0r a2YI;Gݺ0lΟW/N"LĂ*uX 0y2\dx.O? GNa-*Jݧt'nfP o\S.>.e6""" a&}+F63n!441p@ZlIrxBᖢٽ{73gΤ[n+W+2j(Թիv>ުG\(V?wy{WXG}DΜ9]U!0c 9;+ƚ5khԨ(UƍS ǎN!$ vt'1t>M}د% JcfN_6)vQdΨQjA!I2|vQb gM_~tȜCϾ}t'ɰmO;pC[Q= 74nY1%K(Zj̙3ڧz'Yd I!ױcG>,^Yj^$,Xv%˘i?8^reA %J8gl{XaS6C2SX[ Vw aR;P 6X\mR%)] 7N!>p/TR^,X@w DGGLժU&~i'bp»Q 4zM~9ƢEM!ըQ;vB``8B BLΗÉ٘-Y,9l*?ZwHJR=՝D#wnuMN-X\stQd:A_$RSŨu'n"_ᙿp玺tQdM/aÆl21lre֮]K=(S ~!l`O:uPx[rԩ~PIжm9?#vJ>!OrJ~W^xqn+e3iYILb0`tnsFUgP|ԕ+0}:DFN"QZP681""t'&uh aL8}SzL`l ӝD?ɓB a, 55}pB:vH 7񤦦ùsx"'OѣX,lԨ9!9s{|ڵ^Kݙ6mCYt)3fpJF!4hah߾=ٳgGIÆ0dZ1HINeqKm_~qhJ%K2U}օR fqL&@B[ծ #Fԩdp&Ow1WX7V@ G ʗy!/~~w_w#);wHLNr|<^\vԴ4k?oLDEeܧ-ȓO ?ԝ$åK>5a{y)ZAy޽C{]o޺EJj*))s>6Wx SS5 6vbb dIل0Bˁ8pNצM g۶mwܷo_r׾Z|9~!9s4<BduJk׮ӇJf5 ̥m[ujZI2; ,9!U޾=yyx\Y >sݜs$̝ F\Ȝ-5|$`=ѝ-xyyQhQjV@ X|bV Hsp<'HsǠ 2@i5 ƌ|L8GӦ>eV;V!(U=K{JX8}"ᄆaniz_g)3g2N+XP[.!e7^{517oe}mʕ[C7ٳS !DVӰaC^z%ZlI5rVy^]-ܩ;I~@0?'7W.^mԈW5b|w/Kmcv@&P5oغUy S{NavuM;[KkJfMivX l\y=p+wߩk7\Bc#pˋQF!g}F\\?<ҥ s~DZc 'Y˗2d+WZj{?~\w4.a {)\JB#sxoSfƞVT͸qPV6שF ʛڵcϴiD]ˢ#h] 5/v8B;~8V>, .$99Yw,afeI2$%^Y!3g]]cdULEʥT^.oaN2~>>ڨ_>׬aƠA4VnP: pp,T9> tN5VBt'p玺!v! @r1cnJ*VT_fr L8Ńs3}@y81""t'(]Z-I|<̜ ONTE `L΄/_Cz1cԮ\gda3!!́0'%NUOi#81̓?НDrVv^|kMgt_?`  2`_HL .LtwF3f63gwޙ~o_ޑxB!2ҥK > *duGfTjxn&)p$Nsuޘ6q&@ax.pIG[xᰚ5ah)EEԩ;fxέZ_x`HZqx*_ީs%M>u Z|ĨSNryrd?Iڵ42 dʕGGӧCXlwgXaWNٞk)յkWl{c/ZȮlB!s^u5j$=ܑW^g?/k~g8yUOzssCc4Q͛(  Sԍ{4o}Na-, fVt#$3/;}`r6LhO?rNcшxevST(>'ii{t6䧟`HIѝD W?N~îF{p# :NaRZMmK}ǹ qi/UÛ78ƑM/˺u뤬IZZ .g}ZjU'Z`ƾ~:QQQ>}'NoqQӝ6ӰaCmF5\:0yB͈)Y,O=;ݾ eɶm=;KF^;.s*I<;_},SSU̠ ][wa^Hco€ 1-M]S B.0nO];b Bƺ{…}M$~v?ۓ&NzþN3өF!#^n(00sw^ʖ-;pSs"̤I(R(P Q^%fϞ=k !ȟ??/2ӧOٳ۷iٲ%NKڵՓfr>ٌ_[țcb}VTlbcaTsWC)o3 <鄙plzҥKf"kq+Vxoݺŵk2Ojjj^ϊ!DE={6ϟgĉ-Zԩs^t_|8в%;S`s7nth ///~ Sst'xxu)ED׮N"lTlYFth|AK5lCNaYuM9gThR. o>p”7G>wNm_مp욘X@@jf׮]3n8sJ>S_mBc̘1>}w}0ӧѣׄSm~IZ$u;5~SW7{y~IJIѝDأsghNw k q­ӣePС^GEϥp?m۪{; tn o :aNT%Y0˲ݐk׮MX"r.???C)^8^^^# cX7oײgNF(S 6ȹs8piYz*ׯ[n6#YIΜ9yݻ7}[Flٲ>f+%1B=]OdشI56g-[94F`޼LߠD⡶nUWvQdΠAҞ=dؾOI rNcC]/vTהN7yuuڹSw ?@O>37X}9~6)#W SԠA UɄIdM/ooo.\H*]vq˗gTT׿Ŝ9s ʦBdR2eعs'3gd6ͬ &ТE z)n,8Xm~jysI觓'~2y H$kjPcӍ"sƍSNԝ$CH^~YwanM5)"PсBBCf;(2gXI;I}CI=FRY}y>S~%ȾJ]S]8rۯ3f̐ /ݿ!5c C6@={6iϞ=4/Bar^^^ 6ܹs>~ZZ$==˕K-(;ᚳ۪|}_e 8KkӹIcBKMUetQd6"-MceGl>ތtA#X`rؽۈфPV'U.0~<)/qT3>3שFeM5jo!6ϟg=M .L- gȑbaņ+y|qB߉h"nLK\fAx$Vr%"##wΜ>ܘ@"`l ӝDأHl2]7n';Af1tL/?Nb$}ʉzm >_έNeOkSe>)3jYV߿?٤ϟos}dϞy֭KʕO>[n>Bx5ksNoIf~<ʨŋ0e DGN&8<·QL'Vhcǝ4iթ`!z50ۦO?ҥ/&^!z{dH<[Vuw$:Kh*$'‹>k`YcTä$G3'ה;Zb=M'dT|ɕ#齃b/cFɄ'a|yb`k"-[+t'p*=z4\.O8_@߸aX`lxmUS'M/!<ԁx <<*U,Kzxbz-J(a؉ͮP;|O:nqܩDtȜ_W;wNa.(X|{nz٣~ h"szT)3߿-S'f#Q\w q#]R^6{pO#FrfiNʊL1zbhիQ+%y&&MA\r塯/iԨ[ly))GƲ`d ݻw[fj#fذa|͛oɞ={25?~#uF||]s!jժexgϞ5t<||`8YНDxtSsj?ם"Ţʙ}$ƵNZeS6PVoѝBX:`kךT(r.Uw?fiժTX@=z4<Ξ=˷~Kxx8'Oȑ#9sŶgAÞ={ȕ+գqtޝeoq.^ݻoIOOx1114nܘuҴiS/NPP5H"VMMM믿ŋ9s/f^n۶mUV<*T"EТE Bᨲe˒={vN?ސqDRZ1S3UbEi'HLyN7+P >ec IJ 5U4H20 Uϸ@QCG\}jHHHНF}[ ;֌%ݺeX k`AnnO6'OdOq%''sn߾]^7ofvex7ocvA Bg" )o(BA?ׯ6b НZDZRQ"#atY!Oz0tΝS!6Vw,-3yz$~]1 .2vj*736 3N9s`hȝ[wa_T-ӝ$CX:ې74!n0l,"")1c ~g&(QK"CjYe5klH!7Չݻu'ɰcGѯ$SڥQtȜ}ՂdسGݧ//i11؛Q7jd @kj~&I2,] C};|fL6B!u'x);Vw k2a;w_z8 7'^B!"&&˛7ac qWЩ֎U%Ēt'aRьrvQdNp:sFw VAм$e-|߿~|B!WN7>u$BB (|=ܺݻ3 i׭SW^ѝDB!o6lz XIIѝFySm,U>%Krɒ.f> Ϗf5k3X2KdU`AQCwaYiݾʇ,<;G/4|zϸ(5U9 4Fx>>0~bcuQ`2uMtX,Lt©M<敞~)n# B!<ƍILL4l\w kÔ);3Ϩtfr"L .Nntǖ}i3y)^|}Ĩ}.NR^q_[?]S/k9IɦB! o5t{x6mkW)?J޼;GVнC=l2y6-Z@^SX S')t'q[o/ZD:eTfЯs;$<f4OEa矇tN;;3L^g>n瞃F` vHdz8IIɦB!׿Ezzc6iȔ}ޭX,{6*d>sGwaݡuk)<1Nv?-[ LԪT)s/ڶ5CU=SUlz !BÇb~~~ԕB1cT'3ٰ֭ӝBkHUKw k7nBÆ~NnN(b]GjԤ ^^^Ð!а9}\S7qc)N؜ʒoߦK6[׭K92д8d.XBw aB%B0`᧼Zlc a`(YRw k+WwN! eNaҴ…B)Y[NRrI}_gax80WYZw ajU)_N1M¯aaN /O:e>_;0B!pS&LlJD֓/ZəSw ɪ,ѣ{Mܹu'p** IDATo{ſ|t'ɐ$n0`t~8r)(W7T`앖˖{d˦…u'ɐFݫ;{orV唱T)Zթoŋ;e^X,N"LD6B!Ж-[4iK/>6+_^-(ɕ+0mj-O2滦` НDأdIl&0{6>;)Y,̚ŲoqctŊ~]]SNN"Qu'ɐɓIko'ӹ3V@uM9m~%%^ǏN"LB6B!́ԩe ^{5|}} Wԭz0y2N"Qe&/k%I=~Z"4(uMEEY}y70zB.k Wڝ;1m6mru*WI R6bb`pAwa*UwM]mz۶ԩDfa/gNdPKVhbc4qlz !´ܹC~8o/C楗^͛-[6x ![CSX{hf+NR$$N"Ѭ;p5K[nz`\Bەb'u #:*_ڴ]NKLԝDh$^B!0.\HJxwb,RSSywر#I6BY>>>{N[a󳺑#Ui:3ٸ֭ӝBk0xXv]֬ѝBk仙lW?[L *?ƌaӁX,t۷x1 㬓?;z{3{P>p 4nl옎ڱVҝBثx\:W۵ ~C.:u ݺѾaCc+_|ի4 ?#>&zDD!W^e͚5YlٲQfM{9֭K:u(i IIIرM6i&b`A *Ă \>h\Q", Q} ѝFتY3ضt$NYԆJ0iTݧ-ҝP 7ovO ŊQD *,I%XO+Fqh89oO[x8lݚ-Zvƍa@u,"#a4Ӡ ~֘Źsjk r7oÇ@%RrRwcE p4畄EFoO˩S8{ѿZթûF?Y ӧ;#ΟW&TpB!GKOO_~UX1ԩCթT+VbŊq"͛7 ѣi !Bx8___V\ɘ1ctG¹jքѣuS'ͷuL .N"QZPn!{lۣ&L 6UZP6X6 "#u'(_|ի0cNhՊ&Q8~=ʔ1穸8uMEDN"@6B!ooajR=E ѥKɦB!?Ahh(M6Eڴѝ/2*)){tNa-4T]SoN"Ѿ)kЀ gtGɼ6mK)?J޼;Gн.^ԝm<6>7%CЫTIdK!ȑ'm64tzLmիu85ҝpON!Q`AM7F5ӝ`N"ѫڨn#@ ɓ\8׽P5aRHM՝DD6B!ŋSXKHPt'(\X-4mb"̛'ON")__NB@~fnծ/gAYQS 9sN!) .Gu'PT@F ~7=5,=%Jd9g|t'ɐ$AY B}|g\|/ݻL5[.} 8ooyQzIPc&.Ґ]UjԘ:ΟםDأR%ܧr 4>^ټhRF&jf DQ36Z w L{-65 ,ΧKBLlߞ}\9rhN|*Ub֐!D]1cPH+YהxpӺȦB!B9h۶-+V 66~cO29s[nT;Ν2sf=M-ZT.?n`7lV ˔D\*lR%tv{mtoB_=NoL0>/穏>N̜cǢmӦh۴) Dzͱ쎏˗WBӢn*uUu$mjl$ӧKA3(ծ]O>$|I@||<֭[7_~ݻ;ŋGӦMѮ];t ]tA"0MQyz$V+ÂE-65X ^]h0P^V;Ú5ҦzJ; zNB&^xAV nFE, GSRp$) RRp"5Gqlz:^8 ,BBBPLX\9 CԊTAԎDuQҡmv/}Qof$˗E?rŊo-7ވ;;C'NDj*8~4RΝ/-U,W!*-+zDjV*V*Q0-g8\))~ *,zQWT)n[}ѣػw/<#G->>O?\jժjժVШQ#4n 6dHCh)FNN#9sNC&1cgΕοӐh9O=a^;ÂҦxr?O}?nviS.i'!X""""""d MS-^ ,]LhFieKv_~)* NF[k[XH;zYSح\ ,\L=4оv UxqZcыBBd!յ8XY^; jNa7ovv 25~Z;7Nax1lv rE/"""""\ҡ!=x`^$d""B:KN␑!kڥL//m\9$.fɔO|ʔp$/KڶM; (YRTJI23e͛PyZU;Cv5X""""""ZFGu IN&OMSIDzҡHRSSC:u]F~Q`PvI:sF; h>\;2i$\2^vsL t额nF` 'G; 0U;ݦMҦ~ݵS +ID>@Ϟ)~U֍|Y; [;Νf*/NSǢ;-Zh3Qp3hR;ݗ_Kh SF[k+OSgS;݊…)3i[ X@;6 Q;ݚ5)<<jNa7o)Tt4Pv  NA(v ~L4hONAbbƍS-^ ,[L͚iSϵSi,zy!%Kj'qȐvNB&åM-Egv$dlY NpLmv2QJ8df~lެLJZU;CvLǺqv2Ԩ뵓Y,zyA='IDTtT`T!$dNkSgӦh'!5k{_Z0s&LT&b-}<}ID*r!QXvtw{Itv!""""" pw .!88uJ; h =Z;ѣ ɓIcj;~4 8qB; h\:ɉr:vL; h$TR|JLNB&5 >$E^DDDDDD _;]l\ML<0pv 8୷w >;if̐Q:|2D;ݡC2$dC`pvSOk'!m#Fh;rDfeHNNREDDDDDA.]Sm̝+P0@_e휬,$d)-[ٳ+WGzNa믲nID^@)v-32=}S#^`ыĘ12X YXX;=Z; $_}|v 25rLHV.NAyhN;ݪU)԰a@ǎ)֬>X;<I;ݺuy8EDDDDDd*&SG;݂k S11@Tv oNAƏ4Na'_k S11@),"=hY3vD^xhB;gɍ^DDDDDDålY$/ʴ<۷k'!eJ NpLImv2QJ8dfԙ[h'!RN␕%m꧟iSիk'q,6zz$d*&UK;ݼyڵ) ="*J$i ;:uM9L)ISIDFצI#GMSI -A<]hۿ9S~ӥ 0hv 8L{/0dv Cdd3ID)6uv2Ѷ-0bv #GHLi.!A Ni')X""""""NaϲIVv2ѿ?Эv -[d+WGzNaY~^޽SmsIG9Wݻwߕ(t&IlLɚaыȟFW_|L yv +ئ3i[ cdj0HX@;2DFu뀹s9B4HF9s$ ^DDDDDDDEi[P:)8EG˺dB)~QpsR#|ŋKSqd=@gr4f вv /s ^DDDDD$$D;Cٲҡ\v˗em۴ҥC9"B;CfLsev2DFj'qʒXI;  TI,KF_Lji7djxn]v,S/X""""""uՁ`tA$dV- $ii#IDҦ邋e}Hy N␞.k1j'!r*]Z;CFݻⴲe8\GHyƢQ~iRQ $ǎ''Nh'!-ZtO SML=L4j$ʁ)yKHNB&6L k'!QQޗ L*QEDDDDDtI\0sҡs!)P^t !KMNB&ڵyF;]|)ئӝw#GjKHbSIDV)6nNX""""""oݺiۼYFdfj'!> 衝 ޽^Sm.=]L)@{7pv 2խ| $2%kzv2)NNX""""""*#Gmh`"djm[T . h SC@evʋAd} ٸ;,$dbkWG,zY",\XL9f:d*&F $K_|L'˘1k[XX;5J;BE/""""`tv2Qt(GDh'qf*, ?Nbliv 2"յ8}v2 Ԭ Nv T N11@Tv Ѷm)DZGu IKfNB&W$IDdP$o9|*U%\Sxe8\(n߮L-+m*<\; ^DDDDDy`D V-Z/q`OfR$IIr:zT; h8 NIJHNB&4f >^; Tj*0mpv2QN)^DDDDD*.NFRi'!:k;xP:jΜNB&:v Naw0utRixv@rv2qȑ)N&Mb VZGkKL}Rv2qn-ȺL|zNam0kpv2ѻ7Ыv e=GNa{7@Fv2ѭпv 3ӵ NaL}v2ѥ 0hv 2ĢQ`"djm[vVL t蠝٦ِ!=h[7O;4Y;݆ ܹei'!J+3@Vv2ѿ)EDDDDT,ZXLi[X\;4Nax1)Tt4мv >>T;;V $Kʹ2a +OS#eZV *,zW4[j'!aaҡ\v,:y&$dX1)V!'#ず5S8X$d*&SG;݂2:SL nBEOixA g35&;'mj~$djUiSIeݜX$dR%iS%Kj'q}W.mlY$/ʚq;vh'!eʅDI._RmNB&J6ĢQar80aKY+|%%'Gj'!^:uJTBv2Ѡ\HRRɓx$d"*J:ԩIDݺצΜONB&j S^DDDDDi5aôS:$IDv3hLb;}V;]B0iLn .1Q.$JJNB&ZƌNaw\qv2Ѣ0nv ^DDDDDѶmו+ID@^)o.]NB&zNak{2=݁~SLLt n~`Ly$dK` vqq2utZv2q!) +el NÇk[X@;:vki SO> tn`\NaYYID@n)l23GzNAnEDDDDT-Z,_L4inb/Shysv}|v 25v,p).,NAFZNaWlSlHMv|#)8m\`ы0ʒ7mNB&EUN␓|I@͚), ?X^; Na7>fv 2 ԫn`*d*&__;…)TL Шv rE/""""9Yb~$djU:4T;Cz:;@lv2Qt(,iS{h'!ҦʔNpcv2Q/e`,Y7OҦ""8dfgt|BH$t 'GƍC9$%IJLNB&6 6 Lk'!7$ʁi`Ta$dn]P$gӧj'!jy*-M.NNB&W6¢QQqtj'!O?.><HINB&xYv RJNNB&ZFNaL z >-[ch;vL.8yR; h7N;ҦNB&6 8ہ.]NB&~G;ݮ]2XFv2ѽ;Яv ~[Ѥӵ+0`v M?Lt ..1CFP^``vӦhB >;Æi?EDDDDTԬ^-Sp:vkk SO> tn`\Naq#0gLu( 衝n6Y7e$dwoW/%Ke˴Shysv~ |v 25v,pm).sC;ݲe)smh`"djm[vVL t蠝cы(>P| ԨddITL Pv 5kS^=v H2~}v +Vh S11@F)//NAbbd/RâQQ.kj'!U%Jh'qpx`$dbE`xL$/ʚq;vh'!y|y$/g4b|J6!3S9ܺU;  "#8dei6i'!!!ҦUNRdEDDDDT%%'IDÆHIx$d⦛M> L6֕bj IMONB&jՒ@r,0cpv2QF൩sM߯LT*BCI,zu@Jv2qjKHL֭QS%&&HO˖W 9vLɓIm/qiSǏk'!͚E=L4nxm`ы]22݁}S#S^Lt D;1hV;ʕE)@)V,NAG;E9X0wСԮn|IH)&WO;}LEGk[XB;6Nah|v 25~<Фv ŋ/NA͵S ,z݅ Ӟ=IDŊQSveZ]r夣\9$.fL)#mbE$WȔt[j'!%JHJ$YY6i'!ŊIVM;CNLI@͚) =z#IM7Ir II6Lԫ'$5:8tH; ];ٳIDצΝ6v2QP$rqZlv2Q%j,zsGH"9Y; hF $ @Rv2qW 9vLɓImZqiSǏk'!͚^+) 88zT; h8pTbv2ѠA]VȰEDDDDD#W^L< )~8^; ~'SH4$dS'``vӧ/ >;Æi;tHFj'!O?.>^.NKINB&xY^DDDDD~ei'!O{?nvY%$dᇁ>}SLt망P I!! [TuꤝLt$${j'qKKYrOkvҹpUwHk,_(<)z*mNr%PTO;=$-[l.ҦxByAR矵8]+mœQ8Pw#S4]DDT[nw؁͛+&""opw""""""r[;E@DDDDDDDDDDDDX""""""""""""ǢPDDD-44իWTZ'"r.$D;QPbыo'NЎADei' """""" Jސ^DDDDDDDDDDDDX""""""""""""5 7-[j "ΝSKRB$IJR67NoHDDDDDDDDDDDDAE/"""""""""""" z,zQcы^DDDDDDDDDDDDX""""""""""""Ǣ^7o)>K,K;  _nۖ-!+gΨ+RSg幱,re)ŕ+=Ϟul "BQٶͿiiunq"#|Y_v @T?k+W+u++^#) XXؽطھV2@˖@vw:xWKO5 ѯ?Qlsp"p̕+u/ɑ8Ko67J{` 23QH/"""""MHv%[nڷ:u:wJNEqHqh0kyR+? 4mz99ԩJ( ,\h(Wr aaw]}uj'*8? ,]jX"?EDDDDD ׵*TF4NC Y``tO;&M#ٷ+_8}Z:"^W g`X3?tcY"?EDDDDDG9y[!X1U+vmvp0p:x5o IDATY? ݻh`N !ǰiWΔ, 4kvLCZ<HIcceJ <42k>ٰh??]>*S8!]];[䟗_D}{X"?EDDDDDykx10c}AqOT/Zv]f,^mX:AתYS^cxbSѣc+~]P6ަ}{`{w <>/_u> GZcܱ,_›JdVW֝;v.Y-S0֮^yE.pE/"^DDDDD'O=$x㣏}?ŋ^\hb鄧).h,z…siS̏o H7z,1?&;Zx}xncl*⡡Cߖi l` `<۱ED`ы))I9}vŋKtic][oy6,Lցjx^y?]Ϣ˒TZ!!qK/I~x1瑩__:Kl,pW^8/J˛QO> ̚Udnp>n.<T vy)x@ٲ̙z̔<(x$rrd7p^*UJ}utv;AQ#GpljyXR.͏L*TDD^`ы˛Nnz xM۝<)W`STFaYRz}(!kp?ǏiIǎu]No_d "աwըcwra'11jQ^DDDDD_tJGy>)p +2m+|t钿BB=jDDժy]dת0a231]QƑE/""""" ~!!)9O/LZrrG 5k _|_ . ] 﨣75ڵM;.Qcы =od ڵe-ğJUOHԙoN-LŊs渞ȑCDx ~}sg`24G{Go" ¢y1`ϢeZ̞z 8w'e\\+Ӧ9/!`wOM bEg!" ,zQq}ޭysgѲzv Vs+Wukws:vG|".pjT"иRS?Q`ы  *v;w G?ŋ@Lm &;/pN.D$-.]NQ5hvǎo" .5jxަNx뵘ܙ:}i:@nǕΝ[o/5H… …AD$X"""""¥re$%v Fof@Xt!cؿ !*ʎZR!,̻ʔDDA">Q*mr`>Μq#Lo-k:YiӀ,Yn!s p,dfv F̘~Zf &7J:u,DEՉ]\PRRy?GA9yx,M&W]cы] ̙hHMPj D!?Qzm€{q.]> XP:*ϟin[ÆI?\$?myΝGVI+w$+%JNSAu4_+5S/Xz6+K1{G M@TTgrt8_IO8r.۾\ܖ-rۺU:rG*z9#=+T5FNuodek>7˖-As^JJ JZ*?Ęw_̝+M<)[nG9_;+Kn?&#Cs/K\?eɱ}ֻ K [F}<4\"9s:;W\tiM) bN`t/{ 4l(ˀ;//y1ŋK9/תLGӦKz^."B>O ~|oj7}j>劏f̐zGx޾V-,Яй}Je x!/""""""|5iZ:S'oӽtZHO^xG'P駁G:Wqm7gؿ_%xWm&#~ܭg<1w.0bw&LmsٹSK<)R^m2``yyZN0{LG'^xAFe)~7k4^"&HqWw|!Рdns}3s옌8{,[A[xۥ潘 yeK#}y5˒"ʸqލvL)sW(QkgJNƏs­+M ^DDDDD_ZE}dOW(%KQd;iBj'dR:p@?k^_xK:-ҀÇ_~qbŀ[Fuڑke4D^DUKggVANޭ6n4+R=[: MRjVF awm/ =k浝3gYѕ+tLH 7:A)Δ//={w7n, oք_)n~d輸8amwuL`,ٗՓ%nv:߬,ߝ[-,kڻײRS-%JL%K,kWϙg9'mzW^of<*]Fs\?vF˪]u-eYVޮWc,;ֲBB{+]ڲ~-dI?[6I%'= '"W{%>52ɓ}>㏖U/^ܲzʲv1YYzeOaY[z>f?#߹ӲV b,k,~w._ߗ28IӊLǸxѲOwzRŲ?~ͲjԸ!!5`eΖ`v3-kYk=_y?eI1hв>Pk;fY/hYJ׿ZVNY9;ҤerۻײRR8zԲ>̲zsmʲ\=ו+u]}Y֫ZVFefZ\g?WU5ye9sRS-k4\YZR2珩Yxa}з-[ukIU/qPd6~ݻ}˒k{]}V=lMk3ҥiI]u#""""BGz}ez>ܹ{diTCWs}fv} Ov\ j_{4+;[F\zZвbc-)JOxZJF+}`L=zh'7QZ}|+9YF-gYrpսee*Vt g9{VTɻ,'OZ։^եeedF42,|W-#W9ڴIzVFxx]27(Zs,kx uݏ??ƫmۑ^չe *Wߞx²yIJuA5kzR<Сd;2RF b@?K&y!#rr,ǝ}ƍېs}Ϝ9{7@?ܷL%yy__>~פIgDDDDDTT++˲|S:p=ϗBL}\9ٖլ۷Ѳ ;n׷"UFNߟ׸qdjt=xPڬvV%W_yy iۿ쏢eYV^cRc-Q|]w_uؤ,qqBɓyuӦ{sVʽU:ǹsuM?&,̲vkYRwVȽM>Ms;} y=X[r`AOvL|mbŤM9f맞p:[1nY#ITQQ_Sڦ,G^1c=Vdӕ_ΞmÇNYrն-`y&3G﫯d:WS? q6ՕOM\0v߯T 2lcIL&Mn?S4תV)BCB't/GM-ޠor(,Ybz03>ի;iiYP__=)932}'>,k&4i)#]ȜFɚt0aT̳Vd A2~}:wvMﳠuzu|MʮvZ[ 3xqۭ\iWA> \ߤW(Yz 1#UT)|;wWYl UL 5,/, h='<Ι3RU˅ bZ'(6yAX1+Ov\]弰4twYgʗ5\6ͻ  kʟGK|0j5k^ٱc=嗝׭pfyBBbW>77+HWNVΕΐ^ƍZÆղSG-H'?{YW UWۼY:]1MWm'O:=[Ώ?eey^\9onKM79&$}Kq͓P;2j܏<իck=ިRhy<47߷}^˛,K˨]w^}U.rhBFT.شIt9'-Za_~VZS&Vҙ yƁƛb Eߞ 7%seȫ]zՒ%}ɑ#z!!Wkp*bVb"z>P:_+;[7ɋs]o{HHp]ݹ}|hSi~iOvъGtFJ2{w}fΦM,zNoHDDDDD̳uaa@F2ާ IDAT2(Ym;'J{< g?|Y%11rPXT)44L]]OQp钌p_~\˛u_I_hq7/ zg)*deA/]ߗs}m?{>z)Nbaы{w]UuB0 DhQDD<%BE}P ڊRUh>dh@ & S@ 㷲2{>{o.|?kE=g}=So&""""ozHR?/~=0iRkX=5r^'6t/ |+0,z8S󟻟ͩnn ȟ?< E ffze`[#*۴q֭y-^l=VMys*37{:J8x]^,] eM3fWoT0xM`~%%˫KIo=~~TsmU+ ED{|f) """"""rRϤaazM7X)66nwo>s.eecD? n w)!rTO? wr$8tȷv68_)Ds?۷޽HII~ ̜_OwCwM/;ŨQ5./X4l(ϣJ;keב#%Á7h ? կo#ysguҸi"""""Ką _{Z`Qx<%818uU  M7l*+v}}sK7J|<^Z&N4TYlqK#o 2୷>}~gjIt.(ۓ'_m/^yyՊ =z7}€%A/""""""Skݻ?|ue믾,F"(Uun$^+&-=s)4iʕ{~%dh]N59mnE7OٳN=]i?iiP)`""""""frWׯaТ~ڽ)t=do.vr11@RRBצ~d׃M͛-$ave.F/~XV[O}ohܪUeǵʨcǀU$_O)I+)5g۶~eN~Ǡ'۷u߻v`B ,, X2GP<h@Ւ>ؿeK$j?ޔ;R#fH[zc_mlw2c}Lڴɝr;]J={ԅ- n헯;oRSݻj?,Yx׿ii/]hYlz".Ngsz_~EA/"""""ʬ.eb8[7e**>L}?bce R79*JJ,=cpz%'{o$ lR鮻̖o/h2CQ@ˬZ>UTX|y=x~ 11{RMYopu Qu;wOLtVny9' ;= ѯKLƏS܆ 2+ML3Ѩh|U =/rs<8z/%k֟GOGد~^ˁck"5U2S7Zq1oW)2X>*ll**wLxiϿrϿ7o| R_"k""""""w>_tA˭|iSzܹ2squIݒ7x1С~Sgw }AyMet}+4n Wӧݓ'ufffe[~(s)/`W1OF3 $(Q)2~u )S̶o*/ny'rUp<:{6;2fgJzݹ8rٺ_}߽;=.nn-[̚%cƸ[6A/"""""rI`;(/8wYQXhɓϽ{|{w;BgL 3|?.J|/ɜYƴ"i뫯Gå]xQW$b <^Aߪ*Х))k>)XLG:6Cgy=<ϗԹS<`um:wf㏁ɓ}o~|69{0GPʯP֭>utJIiǒ%fi`R_Z/oo۰C-W v>:TƴiiB8nz;/[w}Zcy}\Fpk^#@^[SSec}k7Xs..y X9=ON ^?l6z6o7}JtxCt|{ET9E (y(ݬ,z;=v?WU+|`ڝfd(5rdmiw^~AR͚YDRRe9u5ʺ^xAӧ}ի߉s;vҳR.jv6h_ɚ5J<}~{+ӓwߵu׉26.7R[ltR'O:K̚evlJ)j{~QmJ .ٳJmڤT||{}T?ryԼT5Y| w~*թپ&Vj,_nާ)zZ/>zYsaaJf{vmbb:|X^i|7&W+l^BNVYN+DDDDDt+?4kFV yzHiI2?f7JCmJK̔F+a?I Sj6TxCk\^uwoS)uRGJYO<9Ҧ,oQ_^zImZFDG+ηQdd(d}+u= +yR)ըcQ>?~&)r>ٸQ.zIIJkϢ:T3ZHG_;j¬Q/))JkgV3g~mJJPn uРnTZ:UWNfVo%Θ1_CO=ԁJ;'Ad lYs'pY-7WȈWdR?/:_9瘼:w~)rz@KV粊%v]u͛]iiխQ#V_~WJ=R_~=3x,d @V@orNth޼j>}:lu_Ujy̔g>}>U׏YڵfY盯x@y:atF=yR;tȑ=O_)TGQ9rD~> |_k TxfGeKIҽkնe(˵l)nV%)JL |Y#0c<1+}KWwe p-e?_Ni#scΫWۛsgסwoڵ.WR"s:%CIhOI ٱh| x%Igz5m*t5HZ¦M<8wNy9{VR</@k Tӧ (/\R(z2qK.#C-ɹn[Mw  cl_Uwꔜ{ii*jj{Y4Pʹز#T&%eDD5sgaCI{ x4ol&*}2OnY%ArjMΡv\ׯ7?6%`^rv*LJΪU6I:[O+rsÇ%\judnI4c=) *9v:t{gͫi壏$}'J5o3//<\ΙD筸XRR<#5yjX$%E1u4]V=O^ٺv~s_hB%Z3_NK1N,Zdw1C@Rܲo__:kӎG.…ԛ1c$WNI{@f̰==]RrIQܤ pr?={Acn8QӓޗWbb>MխR[,;/<]\e zik5{}lq{K~nsxIKsw;sQjR#FM7IJYVz{U/<謌6m2}{挳}6guIMkB?A +1^zM7ϓW^ 7FUƌ1HIV_,]V^w;ifYa];3iM_11CuG vR{Mlե9QQU2j>d85;&5ĩSJ wANGRp5"""""ڮx} kKH  ]vxL~D2g(r""BFpC}U);{/\6LFsmV5B;%ˁSZ[(C74i"rwF&_1!ٳx1{' ѣ@bp͚I:8`͒[} RXp! bH',L.=oAr ̽40V6zHR오$(kmyӯ0aBggqˈKlI%f\ٌF{XpKAo%ǖizN$7yr"I׶+_:ȿKG˗~jyL,X,] n]f͒FJ'Tge$%N4=& n5 /~$nHJ~|s瞓{ɹߠ/1unHNԽv]Tr;ް8sr[KZ8O6 Ν+iC:uuNk["#_wnZ<._.)jg I8{omD+_w3y ׫s;qUQR)r2~2曒NJttvy)q*3Sow3G""""""),Q[))ȟ/#;7?8JNbbeN '.\[ʨ'aQ#"!A:2DpKE|Ud\x )Kk~i^>҉íFWV=1 - seaborn - blast >=2.6.0 # There are issues with 2.8.2, and no OS X builds exist after 2.7.0 - vsearch <=2.7.0 - samtools >=1.7 - bowtie2 - qiime2 {{ qiime2_epoch }}.* - q2-types {{ qiime2_epoch }}.* - q2templates {{ qiime2_epoch }}.* - q2-taxa {{ qiime2_epoch }}.* # TODO: revert this pin # https://www.biostars.org/p/494922/ - tbb 2020.2 - biom-format >=2.1.5,<2.2.0 test: requires: - qiime2 >={{ qiime2 }} - q2-types >={{ q2_types }} - q2templates >={{ q2templates }} - q2-taxa >={{ q2_taxa }} - pytest imports: - q2_quality_control - qiime2.plugins.quality_control about: home: https://qiime2.org license: BSD-3-Clause license_family: BSD q2-quality-control-2021.8.0/q2_quality_control/000077500000000000000000000000001411645176100212725ustar00rootroot00000000000000q2-quality-control-2021.8.0/q2_quality_control/__init__.py000066400000000000000000000006741411645176100234120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- from ._version import get_versions __version__ = get_versions()['version'] del get_versions q2-quality-control-2021.8.0/q2_quality_control/_blast.py000066400000000000000000000107051411645176100231130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import tempfile from ._utilities import _run_command def _search_seqs(query_sequences, reference_sequences, evalue, perc_identity, threads, perc_query_aligned, method, left_justify): if method == 'blast': # blast uses float format but vsearch uses int for perc_identity perc_identity = perc_identity * 100 cmd = _blast( query_sequences, reference_sequences, evalue, perc_identity) elif method == 'blastn-short': # blast uses float format but vsearch uses int for perc_identity perc_identity = perc_identity * 100 cmd = _blastn_short( query_sequences, reference_sequences, evalue, perc_identity) elif method == 'vsearch': cmd = _vsearch( query_sequences, reference_sequences, perc_identity, threads, left_justify) return _generate_assignments(cmd, perc_query_aligned) def _blast(query_sequences, reference_sequences, evalue, perc_identity): seqs_fp = str(query_sequences) ref_fp = str(reference_sequences) cmd = ['blastn', '-query', seqs_fp, '-strand', 'both', '-outfmt', '6 qseqid sseqid qlen qstart qend', '-subject', ref_fp, '-perc_identity', str(perc_identity), '-max_target_seqs', '1'] if evalue is not None: cmd.extend(['-evalue', str(evalue)]) cmd.append('-out') return cmd def _blastn_short(query_sequences, reference_sequences, evalue, perc_identity): # Should have identical settings to blast, but adjust word size and filter cmd = _blast(query_sequences, reference_sequences, evalue, perc_identity) cmd = cmd[:-1] + ['-word_size', '7', '-dust', 'no', '-out'] return cmd def _vsearch(query_sequences, reference_sequences, perc_identity, threads, left_just): seqs_fp = str(query_sequences) ref_fp = str(reference_sequences) cmd = ['vsearch', '--usearch_global', seqs_fp, '--id', str(perc_identity), '--strand', 'both', '--maxaccepts', '1', '--maxrejects', '0', '--db', ref_fp, '--threads', str(threads), '--userfields', 'query+target+ql+qlo+qhi'] if left_just: cmd.append('--leftjust') cmd.append('--userout') return cmd def _generate_assignments(cmd, perc_query_aligned): '''Run command line subprocess and extract hits.''' with tempfile.NamedTemporaryFile() as output: cmd = cmd + [output.name] _run_command(cmd) hits = _extract_hits(output.name, perc_query_aligned) return hits def _extract_hits(blast_output, perc_query_aligned): '''import observed assignments in blast6 or blast7 format, return list of query IDs receiving hits. blast_output: path or list Taxonomy observation map in blast format 6 or 7. Each line consists of taxonomy assignments of a query sequence in tab-delimited format: <...other columns are ignored> ''' hits = set() with open(blast_output, "r") as inputfile: # grab query IDs from each line (only queries with hits are listed) for line in inputfile: # ignore comment lines and blank lines if not line.startswith('#') and line != "": query_id, subject_id, query_len, start, end = line.split('\t') # check how much of alignment covers query perc_coverage = _perc_coverage(end, start, query_len) # check for minimum perc_query_aligned # if vsearch fails to find assignment, it reports '*' as the # accession ID, so we will not count those IDs as hits. if perc_coverage >= perc_query_aligned and subject_id != '*': hits.add(query_id) return hits def _perc_coverage(end, start, query_len): # query start is one-based relative to start of sequence # and hence we add 1 to adjust for comparison vs. length. # E.g., alignment of two identical 10-nt seqs will yield: # start = 1, end = 15. Hence 15 - 1 + 1 = 15 nt full # length of alignment. return (float(end) - float(start) + 1) / float(query_len) q2-quality-control-2021.8.0/q2_quality_control/_evaluate_seqs.py000066400000000000000000000051561411645176100246530ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import tempfile import pandas as pd from ._utilities import _plot_histogram from ._blast import _blast, _perc_coverage, _run_command def _evaluate_seqs(query_sequences, reference_sequences, show_alignments): cmd = _blast(query_sequences, reference_sequences, None, 0) # modify command to output seq alignment information cmd[6] = '6 qseqid sseqid pident length mismatch gapopen qstart qend ' \ 'sstart send evalue bitscore qlen qseq sseq' # generate report of blast alignment results results, alignments = _generate_alignments(cmd, show_alignments) # plot histogram of mismatches between obs seqs and top hit in exp seqs g = _plot_histogram(pd.to_numeric(results['Mismatches'])) return results, alignments, g def _generate_alignments(cmd, show_alignments): '''Run command line subprocess and extract hits.''' with tempfile.NamedTemporaryFile() as output: cmd.append(output.name) _run_command(cmd) return _generate_alignment_results(output.name, show_alignments) def _generate_alignment_results(blast_results, show_alignments): '''blast_results: output of blastn in outfmt == 6''' results = pd.read_csv(blast_results, sep='\t', names=[ 'Query id', 'Subject id', 'Percent Identity', 'Alignment Length', 'Mismatches', 'Gaps', 'Alignment Start (query)', 'Alignment end (query)', 'Alignment Start (subject)', 'Alignment end (subject)', 'E Value', 'Bit Score', 'Query length', 'qseq', 'sseq']) # caluclate percent coverage based on qend, qstart, and qlen results['Percent Coverage'] = results.apply(lambda x: _perc_coverage( x['Alignment end (query)'], x['Alignment Start (query)'], x['Query length']), axis=1) if show_alignments: alignments = [] for i, d in results.iterrows(): alignments.append((d['Query id'], 'query', d['qseq'])) alignments.append((d['Query id'], d['Subject id'], d['sseq'])) alignments = pd.DataFrame( alignments, columns=['Query id', 'Subject id', 'seq']) # convert to multiindex alignments = alignments.set_index(['Query id', 'Subject id']) else: alignments = None results = results.drop(['qseq', 'sseq'], axis=1) return results, alignments q2-quality-control-2021.8.0/q2_quality_control/_evaluate_taxonomy.py000066400000000000000000000123471411645176100255560ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import pandas as pd def _evaluate_taxonomy(exp_taxa, obs_taxa, require_exp_ids=True, require_obs_ids=True, feature_table=None, sample_id=None, level_range=range(0, 7)): # validate inputs join_how = _validate_indices_and_set_joining_mode( exp_taxa, obs_taxa, require_exp_ids, require_obs_ids) # merge tables taxa = exp_taxa.join( obs_taxa, how=join_how, lsuffix='_exp', rsuffix='_obs') # extract class weights from feature table (if one is supplied) weights = _extract_frequencies_from_feature_table( taxa, feature_table, sample_id) # calculate precision/recall prf = _prf_to_dataframe(taxa['Taxon_exp'], taxa['Taxon_obs'], sample_weight=weights, level_range=level_range) if sample_id is not None: prf['SampleID'] = sample_id return prf # modified from tax-credit with permission of nbokulich def _compute_prf(exp, obs, l_range=range(0, 7), sample_weight=None): p, r, f = {}, {}, {} # iterate over multiple taxonomic levels for lvl in l_range: lvl = lvl + 1 _obs = _extract_taxa_names(obs, level=slice(0, lvl)) _exp = _extract_taxa_names(exp, level=slice(0, lvl)) p[lvl], r[lvl], f[lvl] = _precision_recall_fscore( _exp, _obs, sample_weight=sample_weight) return p, r, f # modified from tax-credit with permission of nbokulich def _extract_taxa_names(inlist, level=slice(6, 7), delim=';', stripchars=None): '''Extract taxon names at a given level from list of taxon names stripchars: str Default, None, will strip leading and trailing whitespace. Set to "" to turn off character stripping. ''' # Truncate taxonomies and pass to set name_list = [delim.join(line.split(delim)[level]).strip(stripchars) for line in inlist] return name_list # ported from tax-credit with permission of nbokulich def _precision_recall_fscore(exp, obs, sample_weight=None): # precision, recall, fscore, calculated using microaveraging if sample_weight is None: sample_weight = [1]*len(exp) tp, fp, fn = 0, 0, 0 for e, o, w in zip(exp, obs, sample_weight): if o == e: # tp for the true class, the rest are tn tp += w elif e.startswith(o) or o in ( 'Unclassified', 'Unassigned', 'No blast hit', 'other'): # fn for the true class fn += w # no fp for the predicted class, because it was right to some level # the rest are tn else: # fp the the predicted class fp += w # fn for the true class, the rest are tn fn += w # avoid divide by zero error. If no true positives, all scores = 0 if tp == 0: return 0, 0, 0 else: p = tp / (tp + fp) r = tp / (tp + fn) f = 2.*p*r / (p + r) return p, r, f def _index_is_subset(series1, series2, name): ix1 = series1.index ix2 = series2.index if set(ix1) < set(ix2): raise ValueError( 'Observed and expected ids do not match. Missing ' 'ids not found in {0} ids: {1}'.format( name, set(ix1) - (set(ix2)))) def _prf_to_dataframe(exp, obs, sample_weight=None, level_range=range(0, 7)): p, r, f = _compute_prf( exp, obs, l_range=level_range, sample_weight=sample_weight) prf = pd.DataFrame([p, r, f]).T prf = prf.reset_index() prf.columns = ['level', 'Precision', 'Recall', 'F-measure'] return prf def _validate_indices_and_set_joining_mode(exp_taxa, obs_taxa, require_exp_ids, require_obs_ids): if require_exp_ids: join_how = 'left' _index_is_subset(obs_taxa, exp_taxa, 'observed') if require_obs_ids: join_how = 'right' _index_is_subset(exp_taxa, obs_taxa, 'expected') if require_exp_ids == require_obs_ids: join_how = 'inner' return join_how def _extract_frequencies_from_feature_table(taxa, feature_table, sample_id): if feature_table is not None: taxa_ix = taxa.index diff = set(taxa_ix) - set(feature_table.ids(axis='observation')) if len(diff) != 0: raise ValueError('Feature ids not found in feature table: ' '{0}'.format(diff)) table = feature_table.filter(taxa_ix, axis='observation') table = table.sort_order(taxa_ix, axis='observation') if sample_id is not None: # confirm that sample_id is in table if sample_id not in table.ids(axis='sample'): raise ValueError('Sample id not found in feature table: ' '{0}'.format(sample_id)) weights = table.data(sample_id, axis='sample') else: weights = table.sum(axis='observation') else: weights = None return weights q2-quality-control-2021.8.0/q2_quality_control/_filter.py000066400000000000000000000130461411645176100232740ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import os import shutil import tempfile from q2_types.feature_data import DNAFASTAFormat from q2_types.bowtie2 import Bowtie2IndexDirFmt from q2_types.per_sample_sequences import ( CasavaOneEightSingleLanePerSampleDirFmt, ) from ._utilities import _run_command # samtools flags # -f 4 keeps only single alignments that are unmapped # -f 12 keeps only paired alignments with both reads unmapped # -F 256 removes reads that are not primary alignment # -F 260 removes reads that are not primary alignment or unmapped # -F 268 removes reads that are not primary alignment or unmapped # or pair is unmapped. KEEP_UNMAPPED_SINGLE = '4' KEEP_UNMAPPED_PAIRED = '12' REMOVE_SECONDARY_ALIGNMENTS = '256' REMOVE_SECONDARY_OR_UNMAPPED_SINGLE = '260' REMOVE_SECONDARY_OR_UNMAPPED_PAIRED = '268' _filter_defaults = { 'n_threads': 1, 'mode': 'local', 'sensitivity': 'sensitive', 'exclude_seqs': True, 'ref_gap_open_penalty': 5, 'ref_gap_ext_penalty': 3, } def bowtie2_build(sequences: DNAFASTAFormat, n_threads: str = 1) -> Bowtie2IndexDirFmt: database = Bowtie2IndexDirFmt() build_cmd = ['bowtie2-build', '--threads', str(n_threads), str(sequences), str(database.path / 'db')] _run_command(build_cmd) return database def filter_reads( demultiplexed_sequences: CasavaOneEightSingleLanePerSampleDirFmt, database: Bowtie2IndexDirFmt, n_threads: int = _filter_defaults['n_threads'], mode: str = _filter_defaults['mode'], sensitivity: str = _filter_defaults['sensitivity'], ref_gap_open_penalty: str = _filter_defaults['ref_gap_open_penalty'], ref_gap_ext_penalty: str = _filter_defaults['ref_gap_ext_penalty'], exclude_seqs: str = _filter_defaults['exclude_seqs']) \ -> CasavaOneEightSingleLanePerSampleDirFmt: filtered_seqs = CasavaOneEightSingleLanePerSampleDirFmt() df = demultiplexed_sequences.manifest fastq_paths = [record[1:] for record in df.itertuples()] for fwd, rev in fastq_paths: _bowtie2_filter(fwd, rev, filtered_seqs, database, n_threads, mode, sensitivity, ref_gap_open_penalty, ref_gap_ext_penalty, exclude_seqs) return filtered_seqs def _bowtie2_filter(f_read, r_read, outdir, database, n_threads, mode, sensitivity, ref_gap_open_penalty, ref_gap_ext_penalty, exclude_seqs): if mode == 'local': mode = '--{0}-{1}'.format(sensitivity, mode) else: mode = '--' + sensitivity rfg_setting = '{0},{1}'.format(ref_gap_open_penalty, ref_gap_ext_penalty) with tempfile.NamedTemporaryFile() as sam_f: samfile_output_path = sam_f.name with tempfile.NamedTemporaryFile() as bam_f: bamfile_output_path = bam_f.name # align to reference with bowtie bowtie_cmd = ['bowtie2', '-p', str(n_threads), mode, '--rfg', rfg_setting, '-x', str(database.path / database.get_basename())] if r_read is not None: bowtie_cmd += ['-1', f_read, '-2', r_read] else: bowtie_cmd += ['-U', f_read] bowtie_cmd += ['-S', samfile_output_path] _run_command(bowtie_cmd) # Filter alignment and convert to BAM with samtools if exclude_seqs: sam_flags = ['-F', REMOVE_SECONDARY_ALIGNMENTS, '-f', KEEP_UNMAPPED_SINGLE] if r_read is not None: sam_flags[-1] = KEEP_UNMAPPED_PAIRED else: sam_flags = ['-F', REMOVE_SECONDARY_OR_UNMAPPED_SINGLE] if r_read is not None: sam_flags[-1] = REMOVE_SECONDARY_OR_UNMAPPED_PAIRED samtools_command = ['samtools', 'view', '-b', samfile_output_path, '-o', bamfile_output_path, *sam_flags, '-@', str(n_threads - 1)] _run_command(samtools_command) # sort BAM file by read name so pairs are ordered if r_read is not None: with tempfile.NamedTemporaryFile() as sort_f: bamfile_sorted_output_path = sort_f.name sort_command = [ 'samtools', 'sort', '-n', '-@', str(n_threads - 1), '-o', bamfile_sorted_output_path, bamfile_output_path] _run_command(sort_command) shutil.copyfile( bamfile_sorted_output_path, bamfile_output_path) # Convert to FASTQ with samtools fwd = str(outdir.path / os.path.basename(f_read)) _reads = ['-1', fwd] if r_read is not None: rev = str(outdir.path / os.path.basename(r_read)) _reads += ['-2', rev] # -s /dev/null excludes singletons # -0 /dev/null excludes supplementary and secondary reads # -n keeps samtools from altering header IDs! convert_command = [ 'samtools', 'fastq', *_reads, '-0', '/dev/null', '-s', '/dev/null', '-n', bamfile_output_path] _run_command(convert_command) q2-quality-control-2021.8.0/q2_quality_control/_utilities.py000066400000000000000000000440611411645176100240230ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- from os.path import join import biom from scipy.stats import linregress from scipy.spatial.distance import braycurtis, jaccard import seaborn as sns from itertools import cycle import matplotlib.patches as mpatches import pandas as pd import numpy as np import matplotlib.pyplot as plt import q2_taxa import q2templates import pkg_resources import subprocess TEMPLATES = pkg_resources.resource_filename('q2_quality_control', 'assets') # Replace this function with QIIME2 API for wrapping commands/binaries, # pending https://github.com/qiime2/qiime2/issues/224 def _run_command(cmd, verbose=True, stdout=None, stdin=None, cwd=None): if verbose: print('Running external command line application. This may print ' 'messages to stdout and/or stderr.') print('The commands to be run are below. These commands cannot ' 'be manually re-run as they will depend on temporary files that ' 'no longer exist.') print('\nCommand:', end=' ') print(' '.join(cmd), end='\n\n') subprocess.run(cmd, check=True, stdout=stdout, stdin=stdin, cwd=cwd) def _validate_metadata_is_superset(metadata, table): metadata_ids = set(metadata.index) table_ids = set(table.index.tolist()) if not table_ids.issubset(metadata_ids): raise ValueError('Missing samples in metadata: %r' % table_ids.difference(metadata_ids)) def _validate_metadata_values_are_subset(metadata, table): # pull unique exp IDs (metadata vals) from metadata for comparison metadata_ids = set(metadata.unique()) table_ids = set(table.index.tolist()) if not metadata_ids.issubset(table_ids): raise ValueError('Missing samples in table: %r' % metadata_ids.difference(table_ids)) def _interpret_metric_selection(plot_tar, plot_tdr, plot_r_value, plot_r_squared, plot_bray_curtis, plot_jaccard, plot_observed_features, plot_observed_features_ratio): # convert metric boolean choices to list of column names yvals = [] for var, val in zip( (plot_tar, plot_tdr, plot_r_value, plot_r_squared, plot_bray_curtis, plot_jaccard, plot_observed_features, plot_observed_features_ratio), ('TAR', 'TDR', 'r-value', 'r-squared', 'Bray-Curtis', 'Jaccard', 'Observed Taxa', 'Observed / Expected Taxa')): if var: yvals.append(val) # at least one metric must be plotted if len(yvals) < 1: raise ValueError("At least one metric must be plotted.") return yvals def _validate_metadata_and_exp_table(metadata, exp, obs): # validate that metadata ids are superset of obs _validate_metadata_is_superset(metadata, obs) # filter metadata to contain only rows (sample IDs) found in obs metadata = metadata.reindex(obs.index).dropna() # validate that metadata values (exp ids) are subset of exp _validate_metadata_values_are_subset(metadata, exp) # filter exp to contain only rows (sample IDs) found in metadata values exp = exp.reindex(metadata.unique()).dropna() return metadata, exp def _evaluate_composition(exp, obs, depth, palette, metadata, plot_tar, plot_tdr, plot_r_value, plot_r_squared, plot_bray_curtis, plot_jaccard, plot_observed_features, plot_observed_features_ratio): yvals = _interpret_metric_selection( plot_tar, plot_tdr, plot_r_value, plot_r_squared, plot_bray_curtis, plot_jaccard, plot_observed_features, plot_observed_features_ratio) # If metadata are passed, validate and convert to series if metadata is not None: metadata = metadata.to_series() metadata, exp = _validate_metadata_and_exp_table(metadata, exp, obs) # if no metadata are passed, we assume that sample IDs correspond directly # between obs and exp tables else: # DROP MISSING SAMPLES exp, obs = _match_samples_by_index(exp, obs) # DROP NANS/ZERO ABUNDANCE FEATURES obs = _drop_nans_zeros(obs) exp = _drop_nans_zeros(exp) # TAR/TDR for obs vs. exp at each level results, vectors = _compute_per_level_accuracy(exp, obs, metadata, depth) # regplot of taxa at top level composition_regression = _regplot_from_dict( vectors, palette=palette, legend_title="Level") # pointplot on obs vs. exp at maximum level (coming off of the prior loop) score_plot = _pointplot_multiple_y( results, xval='level', yvals=yvals, palette=palette) # list taxa that are obs but not exp obs_collapsed = _collapse_table(obs, depth) exp_collapsed = _collapse_table(exp, depth) obs_features = set(obs_collapsed.columns) exp_features = set(exp_collapsed.columns) fp_features, fn_features = _identify_incorrect_classifications( obs_features, exp_features) misclassifications, underclassifications, mismatches = \ _tally_misclassifications(fp_features, exp_features) # PLOT depth of mismatch at maximum level as histogram mismatch_histogram = _plot_histogram(mismatches) # generate tables of false postive/negative taxa. Sort alphabetically. fn_features = exp_collapsed[list(fn_features)].T.sort_index() misclassifications = obs_collapsed[misclassifications].T.sort_index() underclassifications = obs_collapsed[underclassifications].T.sort_index() return (results, fn_features, misclassifications, underclassifications, composition_regression, score_plot, mismatch_histogram) def _match_samples_by_index(df_a, df_b): # find all rows (samples) in df_a that do not match df_b, and vice versa df_a_new = df_a.reindex(df_b.index) df_b_new = df_b.reindex(df_a.index) return df_a_new, df_b_new def _drop_nans_zeros(df): # replace nan with zero df = df.fillna(0) # drop rows / cols with all zero values df = df.loc[(df.sum(axis=1) != 0), (df.sum(axis=0) != 0)] # remove spaces from rownames (taxonomy classifiers are # inconsistent about adding/removing spaces so let's just be safe) replacements = {t: t.replace(" ", "") for t in df.columns} return df.rename(columns=replacements, inplace=False) def _compute_per_level_accuracy(exp, obs, metadata, depth): results = [] vectors = {} for level in range(1, depth + 1): vectors[level] = {'exp': [], 'obs': []} # collapse taxonomy strings to level exp_collapsed = _collapse_table(exp, level) obs_collapsed = _collapse_table(obs, level) # compute stats for each sample individually for sample in obs_collapsed.index: result = [sample, level] # if metadata are passed, map exp sample ID to value in metadata if metadata is not None: exp_id = metadata[sample] else: exp_id = sample # concatenate obs/exp observations to align features joined_table = pd.concat( [exp_collapsed.loc[exp_id], obs_collapsed.loc[sample]], axis=1, sort=True).fillna(0) # split joined table apart again for computing stats exp_vector = joined_table.iloc[:, 0] obs_vector = joined_table.iloc[:, 1] exp_features = exp_vector[exp_vector != 0] obs_features = obs_vector[obs_vector != 0] # Count observed taxa observed_feature_count = len(obs_features) observed_feature_ratio = ( observed_feature_count / len(exp_features)) result.extend([observed_feature_count, observed_feature_ratio]) # compute TAR/TDR result.extend(compute_taxon_accuracy(exp_features, obs_features)) # compute linear least-squares regression results if len(exp_vector) == len(obs_vector) == 1: # linear regression cannot compute if vector length < 2 reg_results = [np.nan] * 5 else: reg_results = linregress(exp_vector, obs_vector) result.extend(reg_results) # compute Bray-Curtis dissimilarity result.append(braycurtis(exp_vector, obs_vector)) # compute Jaccard distance, must convert to bool array result.append(jaccard(list(map(bool, exp_vector)), list(map(bool, obs_vector)))) results.append(result) # store vectors for constructing regplots vectors[level]['exp'].extend(exp_vector) vectors[level]['obs'].extend(obs_vector) results = pd.DataFrame( results, columns=['sample', 'level', 'Observed Taxa', 'Observed / Expected Taxa', 'TAR', 'TDR', 'Slope', 'Intercept', 'r-value', 'P value', 'Std Err', 'Bray-Curtis', 'Jaccard']) results['r-squared'] = results['r-value']**2 return results, vectors # ported and modified from tax-credit with permission of nbokulich def compute_taxon_accuracy(exp, obs): actual_obs_ids = set(obs.index) expected_obs_ids = set(exp.index) tp = len(actual_obs_ids & expected_obs_ids) fp = len(actual_obs_ids - expected_obs_ids) fn = len(expected_obs_ids - actual_obs_ids) if tp > 0: p = tp / (tp + fp) r = tp / (tp + fn) else: p, r = 0, 0 return p, r def _find_nearest_common_lineage(feature, exp_features): feature_depth = len(feature.split(';')) # slice off empty labels feature = feature.rstrip(';_ ').split(';') feature = [f.strip() for f in feature] for i in range(0, len(feature), 1): # start with None (i.e., don't remove any elements from list) # this will check for underclassifications first if i == 0: i = None else: i = -i for f in exp_features: if ';'.join(feature[:i]) in f: # underclassified features will be substring of exp feature(s) # after stripping if i is None: # return difference in length between obs feature and exp # match (negative for underclassification) return len(feature) - len(f.split(';')) # misclassified features only match after scraping tip lineages else: # return positive number: degree of misclassification # (includes overclassification) return -i # if no matches are found anywhere, return full length (no common lineages) return feature_depth def _pointplot_multiple_y(results, xval, yvals, palette): colors = cycle(sns.color_palette(palette, n_colors=len(yvals))) fig, axes = plt.subplots(1) handles = [] for score in yvals: color = next(colors) sns.pointplot(data=results, x=xval, y=score, ax=axes, color=color) handles.append(mpatches.Patch(color=color, label=score)) axes.set_ylabel('Score') axes.set_xlabel('Taxonomic level') axes.legend( handles=handles, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) return fig def _regplot_from_dict(vectors, palette, legend_title): yvals = vectors.keys() colors = cycle(sns.color_palette(palette, n_colors=len(yvals))) fig, axes = plt.subplots(1) handles = [] for level in yvals: color = next(colors) sns.regplot(x=np.array(vectors[level]['exp']), y=np.array(vectors[level]['obs']), ax=axes, color=color) handles.append(mpatches.Patch(color=color, label=level)) axes.legend( handles=handles, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0., title=legend_title) # Plot arbitrary line with slope of 1 (true ratio) x0, x1 = axes.axes.get_xlim() y0, y1 = axes.axes.get_ylim() lims = [min(x0, y0), max(x1, y1)] axes.plot(lims, lims, ':k') plt.xlabel('Expected abundance') plt.ylabel('Observed abundance') return fig def _plot_histogram(mismatches): fig, axes = plt.subplots(1) n, bins, patches = plt.hist(mismatches, align='left') plt.ylabel('Count') plt.xlabel('Distance to nearest expected feature') return fig def _collapse_table(table, level): biom_table = biom.Table(table.T.values, table.columns, table.index) collapsed = q2_taxa._method.collapse(biom_table, pd.Series( table.columns, index=table.columns, name='Taxon'), level) transposed = collapsed.transpose().to_dataframe(dense=True) transposed.columns.name = 'Taxon' return transposed def _identify_incorrect_classifications(obs_features, exp_features): fp_features = obs_features - exp_features fn_features = exp_features - obs_features return fp_features, fn_features def _tally_misclassifications(fp_features, exp_features): misclassifications = [] underclassifications = [] mismatches = [] if len(fp_features) > 0: # find and report underclassifications and over/misclassification for feature in fp_features: mismatch = _find_nearest_common_lineage(feature, exp_features) mismatches.append(mismatch) if mismatch > 0: misclassifications.append(feature) else: underclassifications.append(feature) return (sorted(misclassifications), sorted(underclassifications), sorted(mismatches)) def _plot_alignments_as_heatmap(alignments): # split sequences into 1 base per column alignments = alignments['seq'].apply(lambda x: pd.Series(list(x))) # generate numerical representation for plotting as heatmap numerical_rep = _represent_sequence_numerically(alignments) # we don't want to see nan values alignments = alignments.fillna('') return _plot_heatmap(alignments, numerical_rep) def _plot_heatmap(alignments, numerical_rep): # determine shape for sizing plot nrows, ncols = alignments.shape fig, axes = plt.subplots(1, figsize=(ncols / 3, nrows / 3)) # A: 'blue', C: 'red', G: 'orange', T: 'green', other: 'white' sns.heatmap(numerical_rep, annot=alignments.values, fmt='', cmap=['white', 'blue', 'red', 'orange', 'green'], cbar=False, ax=axes, vmin=0) axes.set_xlabel('Position') axes.xaxis.set_ticks_position("top") axes.xaxis.set_label_position("top") # plot horizontal lines separating pairs of aligned sequences axes.hlines([n for n in range(2, len(alignments), 2)], *axes.get_xlim(), linewidth=4.0) plt.yticks(rotation='horizontal') plt.xticks(rotation='vertical') return fig def _represent_sequence_numerically(alignments): # map standard bases to numbers alignments = alignments.replace({'A': 1, 'C': 2, 'G': 3, 'T': 4}) # convert all other strings to nan alignments = alignments.apply(pd.to_numeric, errors='coerce', axis=1) # convert nans to 0 and return return alignments.fillna(0) def _visualize(output_dir, title, running_title, results, false_negative_features=None, misclassifications=None, underclassifications=None, composition_regression=None, score_plot=None, mismatch_histogram=None, alignments=None): pd.set_option('display.max_colwidth', None) # save results results.to_csv(join(output_dir, 'results.tsv'), sep='\t') results = q2templates.df_to_html(results, index=False) if false_negative_features is not None: false_negative_features.to_csv(join( output_dir, 'false_negative_features.tsv'), sep='\t') false_negative_features = q2templates.df_to_html( false_negative_features, index=True) if misclassifications is not None: misclassifications.to_csv(join( output_dir, 'misclassifications.tsv'), sep='\t') misclassifications = q2templates.df_to_html( misclassifications, index=True) if underclassifications is not None: underclassifications.to_csv(join( output_dir, 'underclassifications.tsv'), sep='\t') underclassifications = q2templates.df_to_html( underclassifications, index=True) if composition_regression is not None: composition_regression.savefig(join( output_dir, 'composition_regression.png'), bbox_inches='tight') composition_regression.savefig(join( output_dir, 'composition_regression.pdf'), bbox_inches='tight') if score_plot is not None: score_plot.savefig(join( output_dir, 'score_plot.png'), bbox_inches='tight') score_plot.savefig(join( output_dir, 'score_plot.pdf'), bbox_inches='tight') if mismatch_histogram is not None: mismatch_histogram.savefig(join( output_dir, 'mismatch_histogram.png'), bbox_inches='tight') mismatch_histogram.savefig(join( output_dir, 'mismatch_histogram.pdf'), bbox_inches='tight') if alignments is not None: alignments.to_csv(join(output_dir, 'alignments.tsv'), sep='\t') alignments = _plot_alignments_as_heatmap(alignments) alignments.savefig(join( output_dir, 'alignments.png'), bbox_inches='tight') alignments.savefig(join( output_dir, 'alignments.pdf'), bbox_inches='tight') plt.close('all') index = join(TEMPLATES, 'index.html') q2templates.render(index, output_dir, context={ 'title': title, 'running_title': running_title, 'results': results, 'false_negative_features': false_negative_features, 'misclassifications': misclassifications, 'underclassifications': underclassifications, 'composition_regression': composition_regression, 'score_plot': score_plot, 'mismatch_histogram': mismatch_histogram, 'alignments': alignments, }) q2-quality-control-2021.8.0/q2_quality_control/_version.py000066400000000000000000000441311411645176100234730ustar00rootroot00000000000000 # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build # directories (produced by setup.py build) will contain a much shorter file # that just contains the computed version number. # This file is released into the public domain. Generated by # versioneer-0.18 (https://github.com/warner/python-versioneer) """Git implementation of _version.py.""" import errno import os import re import subprocess import sys def get_keywords(): """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = " (tag: 2021.8.0)" git_full = "63a91c21c13999b8bac080227b31b9d455aaa569" git_date = "2021-09-09 18:35:29 +0000" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_config(): """Create, populate and return the VersioneerConfig() object.""" # these strings are filled in when 'setup.py versioneer' creates # _version.py cfg = VersioneerConfig() cfg.VCS = "git" cfg.style = "pep440" cfg.tag_prefix = "" cfg.parentdir_prefix = "q2-quality-control-" cfg.versionfile_source = "q2_quality_control/_version.py" cfg.verbose = False return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" LONG_VERSION_PY = {} HANDLERS = {} def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None for c in commands: try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None)) break except EnvironmentError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %s" % dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %s" % (commands,)) return None, None stdout = p.communicate()[0].strip() if sys.version_info[0] >= 3: stdout = stdout.decode() if p.returncode != 0: if verbose: print("unable to run %s (error)" % dispcmd) print("stdout was %s" % stdout) return None, p.returncode return stdout, p.returncode def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: f = open(versionfile_abs, "r") for line in f.readlines(): if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) f.close() except EnvironmentError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if not keywords: raise NotThisMethod("no keywords at all, weird") date = keywords.get("date") if date is not None: # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = set([r.strip() for r in refnames.strip("()").split(",")]) # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%s*" % tag_prefix], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_pre(pieces): """TAG[.post.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post.devDISTANCE """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += ".post.dev%d" % pieces["distance"] else: # exception #1 rendered = "0.post.dev%d" % pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%s" % pieces["short"] return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Eexceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%s'" % style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} def get_versions(): """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. cfg = get_config() verbose = cfg.verbose try: return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass try: root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to find root of source tree", "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) return render(pieces, cfg.style) except NotThisMethod: pass try: if cfg.parentdir_prefix: return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) except NotThisMethod: pass return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} q2-quality-control-2021.8.0/q2_quality_control/assets/000077500000000000000000000000001411645176100225745ustar00rootroot00000000000000q2-quality-control-2021.8.0/q2_quality_control/assets/index.html000066400000000000000000000147731411645176100246050ustar00rootroot00000000000000{% extends 'base.html' %} {% block title %}q2-quality-control : {{ running_title }}{% endblock %} {% block content %}

{{ title }}

{% if score_plot %}

Per-Level Accuracy


Download as PDF

{% endif %}
{% if composition_regression %}

Linear regression between observed and expected abundances


Download as PDF

{% endif %} {% if mismatch_histogram %}

Mismatches between false positive and expected features


Download as PDF

{% endif %} {% if alignments %}

Pairwise alignments between each query sequence and its best database hit

{% endif %} {% if misclassifications and not misclassifications.empty %}

False positives: misclassifications

{% endif %} {% if underclassifications and not underclassifications.empty %}

False positives: underclassifications

{% endif %} {% if false_negative_features and not false_negative_features.empty %}

False negative features

Download as tsv

{{ false_negative_features }}
{% endif %}
{% endblock %} q2-quality-control-2021.8.0/q2_quality_control/citations.bib000066400000000000000000000032431411645176100237470ustar00rootroot00000000000000@article{bokulich2018optimizing, title={Optimizing taxonomic classification of marker-gene amplicon sequences with QIIME 2's q2-feature-classifier plugin}, author={Bokulich, Nicholas A and Kaehler, Benjamin D and Rideout, Jai Ram and Dillon, Matthew and Bolyen, Evan and Knight, Rob and Huttley, Gavin A and Caporaso, J Gregory}, journal={Microbiome}, volume={In Press}, year={2018} } @article{camacho2009blast+, title={BLAST+: architecture and applications}, author={Camacho, Christiam and Coulouris, George and Avagyan, Vahram and Ma, Ning and Papadopoulos, Jason and Bealer, Kevin and Madden, Thomas L}, journal={BMC bioinformatics}, volume={10}, number={1}, pages={421}, year={2009}, publisher={BioMed Central}, doi={10.1186/1471-2105-10-421} } @article{langmead2012fast, title={Fast gapped-read alignment with Bowtie 2}, author={Langmead, Ben and Salzberg, Steven L}, journal={Nature methods}, volume={9}, number={4}, pages={357}, year={2012}, publisher={Nature Publishing Group} } @article{heng2009samtools, author = {Li, Heng and Handsaker, Bob and Wysoker, Alec and Fennell, Tim and Ruan, Jue and Homer, Nils and Marth, Gabor and Abecasis, Goncalo and Durbin, Richard and 1000 Genome Project Data Processing Subgroup}, title = "{The Sequence Alignment/Map format and SAMtools}", journal = {Bioinformatics}, volume = {25}, number = {16}, pages = {2078-2079}, year = {2009}, month = {06}, issn = {1367-4803}, doi = {10.1093/bioinformatics/btp352}, url = {https://doi.org/10.1093/bioinformatics/btp352}, eprint = {https://academic.oup.com/bioinformatics/article-pdf/25/16/2078/531810/btp352.pdf}, } q2-quality-control-2021.8.0/q2_quality_control/plugin_setup.py000066400000000000000000000360351411645176100243710ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import q2_quality_control from qiime2.plugin import (Str, Plugin, Choices, Range, Float, Int, Bool, MetadataColumn, Categorical, Citations, TypeMap, Visualization, TypeMatch) from q2_types.feature_data import FeatureData, Sequence, Taxonomy from q2_types.sample_data import SampleData from q2_types.per_sample_sequences import ( SequencesWithQuality, PairedEndSequencesWithQuality) from q2_types.feature_table import FeatureTable, RelativeFrequency from q2_types.bowtie2 import Bowtie2Index from .quality_control import (exclude_seqs, evaluate_composition, evaluate_seqs, evaluate_taxonomy) from ._filter import bowtie2_build, filter_reads citations = Citations.load('citations.bib', package='q2_quality_control') plugin = Plugin( name='quality-control', version=q2_quality_control.__version__, website='https://github.com/qiime2/q2-quality-control', package='q2_quality_control', description=( 'This QIIME 2 plugin supports methods for assessing and controlling ' 'the quality of feature and sequence data.'), short_description=( 'Plugin for quality control of feature and sequence data.') ) seq_inputs = {'query_sequences': FeatureData[Sequence], 'reference_sequences': FeatureData[Sequence]} seq_inputs_descriptions = { 'query_sequences': 'Sequences to test for exclusion', 'reference_sequences': ('Reference sequences to align against feature ' 'sequences')} taxa_inputs = {'depth': Int, 'palette': Str % Choices([ 'Set1', 'Set2', 'Set3', 'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2', 'tab10', 'tab20', 'tab20b', 'tab20c', 'viridis', 'plasma', 'inferno', 'magma', 'terrain', 'rainbow'])} taxa_inputs_descriptions = { 'depth': 'Maximum depth of semicolon-delimited taxonomic ranks to ' 'test (e.g., 1 = root, 7 = species for the greengenes ' 'reference sequence database).', 'palette': 'Color palette to utilize for plotting.'} filter_input = {'demultiplexed_sequences': 'The sequences to be trimmed.', 'database': 'Bowtie2 indexed database.'} filter_output = {'filtered_sequences': 'The resulting filtered sequences.'} filter_parameters = { 'n_threads': Int % Range(1, None), 'mode': Str % Choices(['local', 'global']), 'sensitivity': Str % Choices([ 'very-fast', 'fast', 'sensitive', 'very-sensitive']), 'ref_gap_open_penalty': Int % Range(1, None), 'ref_gap_ext_penalty': Int % Range(1, None), 'exclude_seqs': Bool, } filter_parameter_descriptions = { 'n_threads': 'Number of alignment threads to launch.', 'mode': 'Bowtie2 alignment settings. See bowtie2 manual for more details.', 'sensitivity': 'Bowtie2 alignment sensitivity. See bowtie2 manual for ' 'details.', 'ref_gap_open_penalty': 'Reference gap open penalty.', 'ref_gap_ext_penalty': 'Reference gap extend penalty.', 'exclude_seqs': 'Exclude sequences that align to reference. Set this ' 'option to False to exclude sequences that do not align ' 'to the reference database.' } P_method, P_left_justify, _ = TypeMap({ (Str % Choices("blast", "blastn-short"), Bool % Choices(False)): Visualization, (Str % Choices("vsearch"), Bool): Visualization, }) plugin.methods.register_function( function=exclude_seqs, inputs=seq_inputs, parameters={'method': P_method, 'perc_identity': Float % Range(0.0, 1.0, inclusive_end=True), 'evalue': Float, 'perc_query_aligned': Float, 'threads': Int % Range(1, None), 'left_justify': P_left_justify, }, outputs=[('sequence_hits', FeatureData[Sequence]), ('sequence_misses', FeatureData[Sequence])], input_descriptions=seq_inputs_descriptions, parameter_descriptions={ 'method': ('Alignment method to use for matching feature sequences ' 'against reference sequences'), 'perc_identity': ('Reject match if percent identity to reference is ' 'lower. Must be in range [0.0, 1.0]'), 'evalue': ('BLAST expectation (E) value threshold for saving hits. ' 'Reject if E value is higher than threshold. This ' 'threshold is disabled by default.'), 'perc_query_aligned': ( 'Percent of query sequence that must align to reference in order ' 'to be accepted as a hit.'), 'threads': ( 'Number of jobs to execute. Only applies to vsearch method.'), 'left_justify': ('Reject match if the pairwise alignment begins with ' 'gaps'), }, output_descriptions={ 'sequence_hits': ( 'Subset of feature sequences that align to reference sequences'), 'sequence_misses': ( 'Subset of feature sequences that do not align to reference ' 'sequences') }, name='Exclude sequences by alignment', description=( 'This method aligns feature sequences to a set of reference sequences ' 'to identify sequences that hit/miss the reference within a specified ' 'perc_identity, evalue, and perc_query_aligned. This method could ' 'be used to define a positive filter, e.g., extract only feature ' 'sequences that align to a certain clade of bacteria; or to define a ' 'negative filter, e.g., identify sequences that align to contaminant ' 'or human DNA sequences that should be excluded from subsequent ' 'analyses. Note that filtering is performed based on the ' 'perc_identity, perc_query_aligned, and evalue thresholds (the ' 'latter only if method==BLAST and an evalue is set). Set ' 'perc_identity==0 and/or perc_query_aligned==0 to disable these ' 'filtering thresholds as necessary.'), citations=[citations['camacho2009blast+']] ) plugin.visualizers.register_function( function=evaluate_composition, inputs={'expected_features': FeatureTable[RelativeFrequency], 'observed_features': FeatureTable[RelativeFrequency]}, parameters={**taxa_inputs, 'plot_tar': Bool, 'plot_tdr': Bool, 'plot_r_value': Bool, 'plot_r_squared': Bool, 'plot_bray_curtis': Bool, 'plot_jaccard': Bool, 'plot_observed_features': Bool, 'plot_observed_features_ratio': Bool, 'metadata': MetadataColumn[Categorical]}, input_descriptions={ 'expected_features': 'Expected feature compositions', 'observed_features': 'Observed feature compositions'}, parameter_descriptions={ **taxa_inputs_descriptions, 'plot_tar': 'Plot taxon accuracy rate (TAR) on score plot. TAR is ' 'the number of true positive features divided by the ' 'total number of observed features (TAR = true positives ' '/ (true positives + false positives)).', 'plot_tdr': 'Plot taxon detection rate (TDR) on score plot. TDR is ' 'the number of true positive features divided by the ' 'total number of expected features (TDR = true positives ' '/ (true positives + false negatives)).', 'plot_r_value': 'Plot expected vs. observed linear regression r ' 'value on score plot.', 'plot_r_squared': 'Plot expected vs. observed linear regression r-' 'squared value on score plot.', 'plot_bray_curtis': 'Plot expected vs. observed Bray-Curtis ' 'dissimilarity scores on score plot.', 'plot_jaccard': 'Plot expected vs. observed Jaccard distances scores ' 'on score plot.', 'plot_observed_features': 'Plot observed features count on score plot.', 'plot_observed_features_ratio': 'Plot ratio of observed:expected features on score plot.', 'metadata': 'Optional sample metadata that maps observed_features ' 'sample IDs to expected_features sample IDs.'}, name='Evaluate expected vs. observed taxonomic composition of samples', description='This visualizer compares the feature composition of pairs of ' 'observed and expected samples containing the same sample ID in two ' 'separate feature tables. Typically, feature composition will consist ' 'of taxonomy classifications or other semicolon-delimited feature ' 'annotations. Taxon accuracy rate, taxon detection rate, and linear ' 'regression scores between expected and observed observations are ' 'calculated at each semicolon-delimited rank, and plots of per-level ' 'accuracy and observation correlations are plotted. A histogram of ' 'distance between false positive observations and the nearest ' 'expected feature is also generated, where distance equals the number ' 'of rank differences between the observed feature and the nearest ' 'common lineage in the expected feature. This visualizer is most ' 'suitable for testing per-run data quality on sequencing runs that ' 'contain mock communities or other samples with known composition. ' 'Also suitable for sanity checks of bioinformatics pipeline ' 'performance.', citations=[citations['bokulich2018optimizing']] ) plugin.visualizers.register_function( function=evaluate_seqs, inputs=seq_inputs, parameters={'show_alignments': Bool}, input_descriptions=seq_inputs_descriptions, parameter_descriptions={ 'show_alignments': 'Option to plot pairwise alignments of query ' 'sequences and their top hits.'}, name='Compare query (observed) vs. reference (expected) sequences.', description='This action aligns a set of query (e.g., observed) sequences ' 'against a set of reference (e.g., expected) sequences to evaluate ' 'the quality of alignment. The intended use is to align observed ' 'sequences against expected sequences (e.g., from a mock community) ' 'to determine the frequency of mismatches between observed sequences ' 'and the most similar expected sequences, e.g., as a measure of ' 'sequencing/method error. However, any sequences may be provided as ' 'input to generate a report on pairwise alignment quality against ' 'a set of reference sequences.', citations=[citations['camacho2009blast+']] ) plugin.visualizers.register_function( function=evaluate_taxonomy, inputs={'expected_taxa': FeatureData[Taxonomy], 'observed_taxa': FeatureData[Taxonomy], 'feature_table': FeatureTable[RelativeFrequency]}, parameters={**taxa_inputs, 'require_exp_ids': Bool, 'require_obs_ids': Bool, 'sample_id': Str}, input_descriptions={ 'expected_taxa': 'Expected taxonomic assignments', 'observed_taxa': 'Observed taxonomic assignments', 'feature_table': 'Optional feature table containing relative ' 'frequency of each feature, used to weight accuracy ' 'scores by frequency. Must contain all features ' 'found in expected and/or observed taxa. Features ' 'found in the table but not the expected/observed ' 'taxa will be dropped prior to analysis.'}, parameter_descriptions={ **taxa_inputs_descriptions, 'require_obs_ids': 'Require that all features found in expected taxa ' 'must be found in observed taxa or raise error.', 'require_exp_ids': 'Require that all features found in observed taxa ' 'must be found in expected taxa or raise error.', 'sample_id': 'Optional sample ID to use for extracting frequency data ' 'from feature table, and for labeling accuracy results. ' 'If no sample_id is provided, feature frequencies are ' 'derived from the sum of all samples present in the ' 'feature table.'}, name='Evaluate expected vs. observed taxonomic assignments', description='This visualizer compares a pair of observed and expected ' 'taxonomic assignments to calculate precision, recall, and F-measure ' 'at each taxonomic level, up to maximum level specified by the depth ' 'parameter. These metrics are calculated at each semicolon-delimited ' 'rank. This action is useful for comparing the accuracy of taxonomic ' 'assignment, e.g., between different taxonomy classifiers or other ' 'bioinformatics methods. Expected taxonomies should be derived from ' 'simulated or mock community sequences that have known taxonomic ' 'affiliations.', citations=[citations['bokulich2018optimizing']] ) T = TypeMatch([SequencesWithQuality, PairedEndSequencesWithQuality]) plugin.methods.register_function( function=filter_reads, inputs={'demultiplexed_sequences': SampleData[T], 'database': Bowtie2Index}, parameters=filter_parameters, outputs=[('filtered_sequences', SampleData[T])], input_descriptions=filter_input, parameter_descriptions=filter_parameter_descriptions, output_descriptions=filter_output, name='Filter demultiplexed sequences by alignment to reference database.', description=( 'Filter out (or keep) demultiplexed single- or paired-end sequences ' 'that align to a reference database, using bowtie2 and samtools. This ' 'method can be used to filter out human DNA sequences and other ' 'contaminants in any FASTQ sequence data (e.g., shotgun genome or ' 'amplicon sequence data), or alternatively (when exclude_seqs is ' 'False) to only keep sequences that do align to the reference.'), citations=[citations['langmead2012fast'], citations['heng2009samtools']] ) plugin.methods.register_function( function=bowtie2_build, inputs={'sequences': FeatureData[Sequence]}, parameters={'n_threads': Int % Range(1, None)}, outputs=[('database', Bowtie2Index)], input_descriptions={ 'sequences': 'Reference sequences used to build bowtie2 index.'}, parameter_descriptions={'n_threads': 'Number of threads to launch'}, output_descriptions={'database': 'Bowtie2 index.'}, name='Build bowtie2 index from reference sequences.', description='Build bowtie2 index from reference sequences.', citations=[citations['langmead2012fast']] ) q2-quality-control-2021.8.0/q2_quality_control/quality_control.py000066400000000000000000000125541411645176100251030ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import qiime2 import biom from q2_types.feature_data import DNAFASTAFormat import pandas as pd from ._blast import _search_seqs from ._utilities import ( _evaluate_composition, _visualize, _pointplot_multiple_y) from ._evaluate_seqs import _evaluate_seqs from ._evaluate_taxonomy import _evaluate_taxonomy left_justify_supported_methods = {'vsearch'} def exclude_seqs(query_sequences: DNAFASTAFormat, reference_sequences: DNAFASTAFormat, method: str = 'blast', perc_identity: float = 0.97, evalue: float = None, perc_query_aligned: float = 0.97, threads: str = 1, left_justify: bool = False, ) -> (pd.Series, pd.Series): if left_justify and (method not in left_justify_supported_methods): raise ValueError("Enabling left_justify is not compatible with " "method=%r, check the documentation for valid " "combinations" % (method, )) # BLAST query seqs vs. ref db of contaminants (or targets) hit_ids = _search_seqs( query_sequences, reference_sequences, evalue=evalue, perc_identity=perc_identity, threads=threads, perc_query_aligned=perc_query_aligned, method=method, left_justify=left_justify) # convert query_sequences to series for filtering query_series = query_sequences.view(pd.Series) # if no hits are in hit_ids, return empty hits and query_series as misses if len(hit_ids) < 1: hits_seqs = pd.Series(dtype='string') return hits_seqs, query_series # if all query seqs are hits, return query_series as hits and empty misses elif len(hit_ids) == len(query_series): misses_seqs = pd.Series(dtype='string') return query_series, misses_seqs # otherwise filter seqs from seq file else: hits_seqs = {} misses_seqs = {} for seq_id, seq in query_series.items(): seq = str(seq) if seq_id in hit_ids: hits_seqs[seq_id] = seq else: misses_seqs[seq_id] = seq return (pd.Series(hits_seqs, dtype='string'), pd.Series(misses_seqs, dtype='string')) def evaluate_composition( output_dir: str, expected_features: pd.DataFrame, observed_features: pd.DataFrame, depth: int = 7, palette: str = 'Set1', plot_tar: bool = True, plot_tdr: bool = True, plot_r_value: bool = False, plot_r_squared: bool = True, plot_bray_curtis: bool = False, plot_jaccard: bool = False, plot_observed_features: bool = False, plot_observed_features_ratio: bool = True, metadata: qiime2.CategoricalMetadataColumn = None) -> None: # results, fn_features, misclassifications, underclassifications, # composition_regression, score_plot, mismatch_histogram results = _evaluate_composition( expected_features, observed_features, depth=depth, palette=palette, metadata=metadata, plot_tar=plot_tar, plot_tdr=plot_tdr, plot_r_value=plot_r_value, plot_r_squared=plot_r_squared, plot_bray_curtis=plot_bray_curtis, plot_jaccard=plot_jaccard, plot_observed_features=plot_observed_features, plot_observed_features_ratio=plot_observed_features_ratio) _visualize(output_dir, 'Feature evaluation results', 'evaluate_composition', *results) def evaluate_seqs(output_dir: str, query_sequences: DNAFASTAFormat, reference_sequences: DNAFASTAFormat, show_alignments: bool = False) -> None: results, alignments, mismatch_histogram = _evaluate_seqs( query_sequences, reference_sequences, show_alignments) _visualize(output_dir, 'Sequence evaluation results', 'evaluate_seqs', results=results, false_negative_features=None, misclassifications=None, underclassifications=None, composition_regression=None, score_plot=None, mismatch_histogram=mismatch_histogram, alignments=alignments) def evaluate_taxonomy(output_dir: str, expected_taxa: pd.DataFrame, observed_taxa: pd.DataFrame, depth: int, palette: str = 'Set1', require_exp_ids: bool = True, require_obs_ids: bool = True, feature_table: biom.Table = None, sample_id: str = None ) -> None: prf = _evaluate_taxonomy(expected_taxa, observed_taxa, require_exp_ids, require_obs_ids, feature_table, sample_id, level_range=range(0, depth)) score_plot = _pointplot_multiple_y( prf, xval='level', yvals=['Precision', 'Recall', 'F-measure'], palette=palette) _visualize(output_dir, 'Taxonomic accuracy results', 'evaluate_taxonomy', results=prf, false_negative_features=None, misclassifications=None, underclassifications=None, composition_regression=None, score_plot=score_plot, mismatch_histogram=None, alignments=None) q2-quality-control-2021.8.0/q2_quality_control/tests/000077500000000000000000000000001411645176100224345ustar00rootroot00000000000000q2-quality-control-2021.8.0/q2_quality_control/tests/__init__.py000066400000000000000000000005351411645176100245500ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- q2-quality-control-2021.8.0/q2_quality_control/tests/data/000077500000000000000000000000001411645176100233455ustar00rootroot00000000000000q2-quality-control-2021.8.0/q2_quality_control/tests/data/bacterial-query-sequences.fasta000066400000000000000000000024241411645176100314510ustar00rootroot00000000000000>1111886 TACGGAGGGGGCTAGCGTTGTTCGGAATTACTGGGCGTAAAGCGCACGTAGGCGGCTTTGTAAGTTAGAGGTGAAAGCCCGGGGCTCAACTCCGGAATTGCCTTTAAGACTGCATCGCTAGAATTGTGGAGAGGTGAGTGGAATTCCGAGTGTAGAGGTGAAATTCGTAGATATTCGGAAGAACACCAGTGGCGAAGGCGACTCACTGGACACATATTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >1111867 TACAGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTGTCTAAGTCGGGTGTGAAAGCCCCGGGCTCAACCTGGGAACTGCATTCGATACTGGACGGCTAGAGTATGAGAGAGGGAGGTAGAATTCCACGTGTAGCGGTGAAATGCGTAGATATGTGGAGGAATACCGGTGGCGAAGGCGGCCTCCTGGCTTAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >1111783 TACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCAGGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTTAACCTGGGAACTGCATTCGAAACTGGCAGGCTGGAGTCTTGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGCAAAC >1111768 TACGGAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTACGTAAGTCGGATGTGAAAGCCCCGGGCTCAACCTGGGAATTGCATCCGAAACTGCGTGACTAGAGTATGTGAGAGGGAAGGGGAATTCCGGGTGTAGCGGTGAAATGCGTAGATATCCGGAGGAACACCAGTGGCGAAGGCGCCTTCCTGGCACAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCGAAC >1111750 TACGTAGGACCCAAGCGTTATCCGGAGTGACTGGGCGTAAAGAGTTGCGTAGGCGGCTTATTAAGTGGATAGTGAAACCTGGTGGCTCAACCATACAGACTATTATCCAAACTGATAAGCTTGAGAATGGTAGAGGTGATTGGAATTTCTAGTGTAGGGGTAATATCCGTAGATATTAGAAGGAACACCAATGGCGTAGGCAGATCACTGGACCATTTCTGACGCTGAGGCACGAAAGCGTGGGGAGCGA q2-quality-control-2021.8.0/q2_quality_control/tests/data/bacterial-ref-sequences.fasta000066400000000000000000000121201411645176100310520ustar00rootroot00000000000000>1111886 TACGGAGGGGGCTAGCGTTGTTCGGAATTACTGGGCGTAAAGCGCACGTAGGCGGCTTTGTAAGTTAGAGGTGAAAGCCCGGGGCTCAACTCCGGAATTGCCTTTAAGACTGCATCGCTAGAATTGTGGAGAGGTGAGTGGAATTCCGAGTGTAGAGGTGAAATTCGTAGATATTCGGAAGAACACCAGTGGCGAAGGCGACTCACTGGACACATATTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >1111883 TACGGAGGGTGCGAGCGTTGTCCGGAATCACTGGGCGTAAAGGGCGCGTAGGTGGCCCGTTAAGTGGCTGGTGAAATCCCGGGGCTCAACTCCGGGGCTGCCGGTCAGACTGGCGAGCTAGAGCACGGTAGGGGCAGATGGAATTCCCGGTGTAGCGGTGGAATGCGTAGATATCGGGAAGAATACCAGTGGCGAAGGCGTTCTGCTGGGCCGTTGCTGACACTGAGGCGCGACAGCGTGGGGAGCAAAC >1111882 TACGGAGGATCCAAGCGTTATCCGGAATCATTGGGTTTAAAGGGTCCGTAGGCGGTTTTATAAGTCAGTGGTGAAATCCGGCAGCTCAACTGTCGAACTGCCATTGATACTGTAGAACTTGAATTACTGTGAAGTAACTAGAATATGTAGTGTAGCGGTGAAATGCTTAGATATTACATGGAATACCAATTGCGAAGGCAGGTTACTAACAGTATATTGACGCTGATGGACGAAAGCGTGGGGAGCGAAC >1111879 GACAGAGGGGGCAAGCGTTGTCCGGAGTCACTGGGCGTAAAGCGCGCGCAGGCGGCTGCCTAAGTGTCGTGTGAAAGCCCCCGGCTCAACCGGGGGAGGCCATGGCAAACTGGGTGGCTCGAGCGGCGGAGAGGTCCCTCGAATTGCCGGTGTAGCGGTGAAATGCGTAGAGATCGGCAGGAAGACCAAGGGGGAAGCCAGGGGGCTGGCCGCCGGCTGACGCTGAGGCGCGACAGCGTGGGGAGCAAAC >1111874 TACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCACGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTCAACCTGGGAACTGCGTTCTAAACTGGGAGGCTAGAGTCTTGTANAGGGGGGTAGAATTCCNGGTGTATCGGTGAAATGCGTATAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGCAAAC >1111867 TACAGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTGTCTAAGTCGGGTGTGAAAGCCCCGGGCTCAACCTGGGAACTGCATTCGATACTGGACGGCTAGAGTATGAGAGAGGGAGGTAGAATTCCACGTGTAGCGGTGAAATGCGTAGATATGTGGAGGAATACCGGTGGCGAAGGCGGCCTCCTGGCTTAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >1111856 TACGAGGGGTGCTAGCGTTATTCGGAATTATTGGGCGTAAAGGGTGTGTAGACGGTTTGTTAAGTTTGTTGTTAAATTTCCTGGCCTAACTGGGAATCGGCAGTGAATACTGGCAGACTTGAGGATGGAAGAGAGAAGTGGAATTCTCGGAGTAGCGGTAAAATGCGTAGATCTCGAGAGGAACACCAATGGCGAAGGCAGCTTCTTGGTCCATTCCTGACGTTGAGACACGAAAGCGTGGGGAGCAAAC >1111848 TGCGTAGGAGGCGAGCGTTATCCGGATTCATTGGGCGTAAAGTGTGCGTAGGCTGTTTTGTAAGTCTATGCCTAAATCCTATGGCTTACCCATAGACTTGGCATAGATACTATATAAACTTGAGGATTGGTAGGGATGCTAGAACAGTTAGTGTAGCAGTGAAATGCGTTGATATTAACTGGAATACCAAAGGCGAAGGCAAGCATCTGGGCCCTTCCTGACGCTGAGGCACGAAAGCCAGGGTAGCGAA >1111847 TACTAAGGGTGCAAGCGTTACTCGGAATTACTGGGCGTAAAGCGTGCGTATGTGGTGGTTTAAGTCTGCTGTGAAAGCCCTGGGCTCAACCTGGGAATTGCAGTGGATACTGGATCACTAAAGTGTGGTAGAGGGATGCGGAATTTCTGGTGTAACATTGAAATGCGTAGAGATCAGAATGAACATCCGTGGCGAACGCGGCATCCTGGGCCAACACTGACACTGAGGCACGAAAGCGTGAGGAGCAAAC >1111845 TACGTAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGTGCGCAGGCGGTTGTGCAAGACAGGCGTGAAATCCCCGGGCTTAACCTGGGAATGGCGCTTGTGACTGCACGACTGGAGTGCGGCAGAGGGGGATGGAATTCCGCGTGTAGCAGTGAAATGCGTAGATATGCGGAGGAACACCGATGGCGAAGGCAGTCCCCTGGGCCTGCACTGACGCTCATGCACGAAAGCGTGGGGAGCAAAC >1111839 TACGGAGGTGGCAAGCGTTGTTCGGAATTACTGGGCGTAAAGGGCGCGTAGGCGGCTCGGCAAGTCAGGTGTGAAAGCCCCGGGCTTAACTCGGGAATTGCATCTGAAACTGCCTTGCTTGAGTCCTGGAGGGGGTAGTGGAATTCCCAGTGTAGCGGTGAAATGCGTAGATATTGGGAGGAACACCAGTGGCGAAGGCGGCTACCTGGACAGTGACTGACGCTGAGGCGCGAAAGCTAGGGGAGCGAAC >1111827 TACAGAGGGTGCAAGCGTTAATCGGATTTACTGGGCGTAAAGCGTGTGTAGGTGGTGGCGTAAGTCGATTGTGAAATCCCCGGGCTCAACCTGGGAACTGCTTTCGATACTGCGTCACTAGAGTACGGTAGAGGGTGGTGGAATTTCCGGTGTAGCGGTGAAATGCGTAGATATCGGAAGGAACATCAATGGCGAAGGCAACCACCTGGGCCTGTACTGACACTGAGACACGAAAGCGTGGGGATCAAAC >1111819 TACGGAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGTTTGTTAAGTCAGCTGTGAAAGCCCCGGGCTCAACCTGGGAATTGCAGTTGATACTGGCCGACTAGAGTACGAGAGAGGGAGGTAGAATTCCATGTGTAGCGGTGAAATGCGTAGATATATGGAGGAATACCAGTGGCGAAGGCGGCCTCCTGGCTCGATACTGACGCTGAGGTGCGAAAGCGTGGGGATCAAAC >1111807 TACGTAGGGGGCGAGCGTTATCCAGATTTACTGGGCGTAAAGCGCGTGTAGGCGGCTGGTTAGGTGTGATGTGAAATCCTCGGGCTCAACCCGAGAACTGCATTGCAAACCGGCCTGGCTAGAGTGCAGGAGAGGGAAGCGGAATTCCAGGTGTAGCGGTGAAATGCGTAGATATCTGGAGGAACACCAGTGGCGAAGGCGGCTTCCTGGCCTGTAACTGACGCTGAGACGCGAAAGCGTGGGGAGCGAA >1111783 TACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCAGGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTTAACCTGGGAACTGCATTCGAAACTGGCAGGCTGGAGTCTTGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGCAAAC >1111782 TACGTAGGGAGCGAGCGTTGTCCGGAATTACTGGGTGTAAAGGGTGCGCAGGCGGGAGTGCAAGTTGGATGTGAAATGCCGGGGCTCAACCCCGGAGCTGCATCCAAAACTGTACTTCTTGAGTGAAGTAGAGGCAGGCGGAATTCCGAGTGTAGCGGTGAAATGCGTAGATATTCGGAGGAACACCAGTGGCGAAGGCGGCCTGCTGGGCTTTAACTGACGCTGAGGCACGAAAGCATGGGGAGCAAAC >1111776 TACGTAGGGGGCGAGCGTTGTCCGGAATTATTGGGCGTAAAGGGTGCGTAGGCGGCTTCTTAAGTCAGATGTGAAAGACCACAGCTTAACTGTGGGGTTGCATTTGAAACTGGGGAGCTTGAGTTTCGGAGAGGGTAGTGGAATTCCCGGTGTAGCGGTGAAATGCGTAGATATCGGGAGGAACACCAGTGGCGAAGGCGACTACCTGGACGACAACTGACGCTGAGGCACGAAAGCTAGGGGAGCAAAC >1111772 TACGTAGGGCGCAAGCGTTGTCCGGAATTATTGGGCGTAAAGAGCTCGTAGGCGGCTTGTCGCGTCGGGTGTGAAAGCCCGGGGCTTAACCCCGGGTCTGCATTCGATACGGGCAGGCTAGAGTGTGGTAGGGGAGATCGGAATTCCTGGTGTAGCGGTGAAATGCGCAGATATCAGGAGGAACACCGGTGGCGAAGGCGGATCTCTGGGCCATTACTGACGCTGAGGAGCGAAAGCGTGGGGAGCGAAC >1111768 TACGGAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTACGTAAGTCGGATGTGAAAGCCCCGGGCTCAACCTGGGAATTGCATCCGAAACTGCGTGACTAGAGTATGTGAGAGGGAAGGGGAATTCCGGGTGTAGCGGTGAAATGCGTAGATATCCGGAGGAACACCAGTGGCGAAGGCGCCTTCCTGGCACAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCGAAC >1111750 TACGTAGGACCCAAGCGTTATCCGGAGTGACTGGGCGTAAAGAGTTGCGTAGGCGGCTTATTAAGTGGATAGTGAAACCTGGTGGCTCAACCATACAGACTATTATCCAAACTGATAAGCTTGAGAATGGTAGAGGTGATTGGAATTTCTAGTGTAGGGGTAATATCCGTAGATATTAGAAGGAACACCAATGGCGTAGGCAGATCACTGGACCATTTCTGACGCTGAGGCACGAAAGCGTGGGGAGCGA q2-quality-control-2021.8.0/q2_quality_control/tests/data/exp-results.tsv000066400000000000000000000045241411645176100264030ustar00rootroot00000000000000 sample level Observed Taxa Observed / Expected Taxa TAR TDR Slope Intercept r-value P value Std Err Bray-Curtis Jaccard r-squared 0 s1 1 7 1.166666667 0.857142857 1 0.471111111 0.075555556 0.742421444 0.055977102 0.190116274 0.13 0.142857 0.5511896 1 s2 1 7 1.166666667 0.857142857 1 0.735555556 0.037777778 0.898475147 0.005968234 0.160735962 0.09 0.142857 0.807257589 2 s3 1 6 1 1 1 1 0 0.930260509 0.002375359 0.176383421 0.05 0 0.865384615 3 s1 2 7 1.166666667 0.857142857 1 0.471111111 0.075555556 0.742421444 0.055977102 0.190116274 0.13 0.142857 0.5511896 4 s2 2 7 1.166666667 0.857142857 1 0.735555556 0.037777778 0.898475147 0.005968234 0.160735962 0.09 0.142857 0.807257589 5 s3 2 6 1 1 1 1 0 0.930260509 0.002375359 0.176383421 0.05 0 0.865384615 6 s1 3 7 1.166666667 0.857142857 1 0.471111111 0.075555556 0.742421444 0.055977102 0.190116274 0.13 0.142857 0.5511896 7 s2 3 7 1.166666667 0.857142857 1 0.735555556 0.037777778 0.898475147 0.005968234 0.160735962 0.09 0.142857 0.807257589 8 s3 3 6 1 1 1 1 0 0.930260509 0.002375359 0.176383421 0.05 0 0.865384615 9 s1 4 7 1.166666667 0.857142857 1 0.471111111 0.075555556 0.742421444 0.055977102 0.190116274 0.13 0.142857 0.5511896 10 s2 4 7 1.166666667 0.857142857 1 0.735555556 0.037777778 0.898475147 0.005968234 0.160735962 0.09 0.142857 0.807257589 11 s3 4 6 1 1 1 1 0 0.930260509 0.002375359 0.176383421 0.05 0 0.865384615 12 s1 5 7 1.166666667 0.857142857 1 0.471111111 0.075555556 0.742421444 0.055977102 0.190116274 0.13 0.142857 0.5511896 13 s2 5 7 1.166666667 0.857142857 1 0.735555556 0.037777778 0.898475147 0.005968234 0.160735962 0.09 0.142857 0.807257589 14 s3 5 6 1 1 1 1 0 0.930260509 0.002375359 0.176383421 0.05 0 0.865384615 15 s1 6 7 1.166666667 0.714285714 0.833333333 0.06 0.1175 0.076447079 0.857219209 0.319478742 0.28 0.375 0.005844156 16 s2 6 7 1.166666667 0.714285714 0.833333333 0.32 0.085 0.360484727 0.380364243 0.338033529 0.24 0.375 0.129949239 17 s3 6 6 1 0.833333333 0.833333333 0.55 0.05625 0.524404424 0.182133944 0.364577381 0.2 0.285714 0.275 18 s1 7 7 1.166666667 0.428571429 0.5 -0.533333333 0.153333333 -0.618318528 0.056717568 0.239675707 0.6 0.7 0.382317802 19 s2 7 7 1.166666667 0.428571429 0.5 -0.473333333 0.147333333 -0.510804586 0.131357175 0.281651873 0.6 0.7 0.260921325 20 s3 7 6 1 0.5 0.5 -0.433333333 0.143333333 -0.419573196 0.227406638 0.33145303 0.6 0.666667 0.176041667q2-quality-control-2021.8.0/q2_quality_control/tests/data/fungal-query-sequences.fasta000066400000000000000000000015331411645176100307770ustar00rootroot00000000000000>SH076366.07FU_FJ613078_reps TTACAGAGTTGTAAAACTCCCTAAACACTTGTGAACTTACCTGTATTGTTGCTTCGGCAGGCGGCCCCAGGGCGGGGCTGTAGCCTTTATAGGCGCCTGCCGGAGGATTTAAACGCTAAATTTACTTGTCTCTCTGAGCAACTTATCAATAAGTTAA >SH076370.07FU_U17329_refs TTACTGAGTTGAAAAACCCCAACCCCTGTGAACATAACCTCTGTCGTTGCTTCGGCGGGCACGCCCGCCGGAGGTTCAAAACTCTTATTTTTTCCAGTATCTCTGAGCCTGAAAGACAAATAATCAA >SH076371.07FU_DQ528766_reps TTACAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTTTACTGTTGCTTCGGCGGCGCCCGCCGCCGCCGGAGGTTCAAAACCCTGAATTTTAGTGTATCTCTGAGTACGAAAAGAACCTGAAAAATTAA >SH076385.07FU_KJ855505_reps TTAAAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTGCACGTTGCTTCGGCGGCSGGCGCCGCGCCCGGCCGGGCGTGGAGGACGCCGCCGGAGGTCTCAAACCCTGAATTCTAGTGTGTCTCTGAGTATGGAAAGAACCAATCAA >SH076388.07FU_AJ132542_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTTACCATTACTGTTGCTTCGGCGGACGAAGGCCCCCTTGGGGCTGGATGCCGCCGGAGGTTTCAAACTCTGAATCTTTGTGTATCTCTGAGGAAAAAAACAAATAATTAA q2-quality-control-2021.8.0/q2_quality_control/tests/data/fungal-ref-sequences.fasta000066400000000000000000000066161411645176100304150ustar00rootroot00000000000000>SH076366.07FU_FJ613078_reps TTACAGAGTTGTAAAACTCCCTAAACACTTGTGAACTTACCTGTATTGTTGCTTCGGCAGGCGGCCCCAGGGCGGGGCTGTAGCCTTTATAGGCGCCTGCCGGAGGATTTAAACGCTAAATTTACTTGTCTCTCTGAGCAACTTATCAATAAGTTAA >SH076370.07FU_U17329_refs TTACTGAGTTGAAAAACCCCAACCCCTGTGAACATAACCTCTGTCGTTGCTTCGGCGGGCACGCCCGCCGGAGGTTCAAAACTCTTATTTTTTCCAGTATCTCTGAGCCTGAAAGACAAATAATCAA >SH076371.07FU_DQ528766_reps TTACAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTTTACTGTTGCTTCGGCGGCGCCCGCCGCCGCCGGAGGTTCAAAACCCTGAATTTTAGTGTATCTCTGAGTACGAAAAGAACCTGAAAAATTAA >SH076372.07FU_AJ246151_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACATACCTTTACTGTTGCTTCGGCGGACGATGGCCCCCCCCGGGGGCCGGACGCCGCCGGAGGTTACAAACCCTGAATTTTAGTGTATCTCTGAGTATAAAACCAAATAATTAA >SH076386.07FU_AF422960_refs TTAAAGAGTTGAAAAAACTCCACCCCTGTGAACATTACCTTTGCTGTTGCTTCGGCGGACGAGGAGGGCGTCGTCTCGACGTCCCCGGAGGCCGCCGGAGGTTCCAAACTCTGAATCTTTGGTGTATCTCTGAGGAAAAAAACAAATAATTAA >SH076392.07FU_EU636699_reps TTAAAGAGTTGAAAAACTCCAACCCCTGTGAACCTTACCTTTACTGTTGCTTCGGCGGACGACGGCCCTTCGTGGCCCGAGGCCGCCGGAGGTTCCAAACTCTAAATCTTTAGTGTATCTCTGAGGAAAATAAACCAATAATTAA >SH076393.07FU_JX134600_reps TTACAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTTTACTGTTGATTCGGCGGCGCCCCGTCGCCGCCGGAGGTTCAAAACCCTAAATTTTAGTGTATCTCTGAGTACGAAAAGAACCTGAAAAATTAA >SH076377.07FU_AY428782_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTACCTTTACTGTTGCTTCGGCGGACGATGGCCCCCCGGGTCCGGACGCCGCCGGAGGTTACAAACCCTGAATCTTTGTGTATCTCTGAGTACAAAACCAAATAATTAA >SH076378.07FU_AY428786_reps TTAAAGAGTTGCAAAACTCCAACCCCTGTGAACGTTACCTTTTTGTTGCTTCGGCGGTCGACGCCGCCCGAGAGGGCGGGGGACGCCGCCGGAGGTCAAACCCCAAACCTGAATTTTTGTGTATCTCTGAGCAAAAAAAAAAAGACCAATTAA >SH076394.07FU_KJ855497_reps TTACAGAGTTGAAAAACTCCAACCCTTGTGTATCTTACCTTCGTCGTTGCTTCGGCGGCAAAGATGCCCCCCTCCGCGGGGGCTACGGCGCCGCCGGAGGTTCACAAACTCTTGATTTTTAGTGTATCTCTGAGTTTAAAAAATAATAATCAA >SH076395.07FU_JF710374_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTACCTTTACTGTTGCTTCGGCGGAAGATGGCCCCCCGGGCCGGGCGCCGCCGGAGGTCACAAACCCTGAACTTTAGTGTATCTCTGAGCACAAAACCAAATAATTAA >SH076374.07FU_FN555109_reps TTACCGAGTTGAAAAACTCCAACCCCTGTGAACATAACCTCTGTCGTTGCTTCGGCGGGCTCGCCCGCCGGAGGTTACAAACTCTTGTGTATTTTTTTAGCATCTCTGAGCCTAAAAGACAAATAATCAA >SH076379.07FU_JF414846_reps TTAAAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTTTACTGTTGCTTCGGCGGTTGGCGCCGGTGCCCAGATGGGCCTGGAGGTCGCCGCCGGAGGTTCGAAACCCTGAATTCTAGTGTGTCTCTGAGAAAAGAATAAAACAATCAA >SH076375.07FU_FJ541434_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTACCTTTACTGTTGCTTCGGCGGACGATGGCCCCCGGGCCGGACGCCGCCGGAGGTTACAAACCCTGAATTTTAGTGTATCTCTGAGTACGAAACCAAATAATTAA >SH076385.07FU_KJ855505_reps TTAAAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTGCACGTTGCTTCGGCGGCSGGCGCCGCGCCCGGCCGGGCGTGGAGGACGCCGCCGGAGGTCTCAAACCCTGAATTCTAGTGTGTCTCTGAGTATGGAAAGAACCAATCAA >SH076380.07FU_AB190407_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTACCTTTACTGTTGCTTCGGCGGATTATGGCCTCCGGGCCGGACGCCGCCGGAGGTTACAAACCCTGAATTTTGGTGCATCTCTGAGTACTAAACCAAATAATTAA >SH076387.07FU_KC871049_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTACCTTTGCTGTTGCTTCGGCGGAAGATGGCCCCCCGGGCCGGGCGCCGCCGGAGGTCACAAACCCTGAATTTTTAGTGTATCTCTGAGTACAAAACCAAATAATTAA >SH076376.07FU_KJ855489_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTACCTTTACTGTTGCTTCGGCGGACGATGGCCCCAGGGCCGGACGCCGCCGGAGGTTACAAACCCTGAATTTTTAGTGTATCTCTGAGCACAAAAACAAATAATTAA >SH076388.07FU_AJ132542_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTTACCATTACTGTTGCTTCGGCGGACGAAGGCCCCCTTGGGGCTGGATGCCGCCGGAGGTTTCAAACTCTGAATCTTTGTGTATCTCTGAGGAAAAAAACAAATAATTAA >SH076396.07FU_U17215_reps TTAAAGAGTTGCAAAACTCCAACCCCTGTGAACTTTACCTTTACTGTTGCTTCGGCGGTTGGCGCCGGTGCCCAGATGGGCCTGGAGGTCGCCGCCGGAGGTTCGAAACCCTGAATTCTAGTGTGTCTCTGAGAAAAGAATAAAACAATCAA q2-quality-control-2021.8.0/q2_quality_control/tests/data/mock-3-expected-taxonomy.tsv000066400000000000000000000067551411645176100306640ustar00rootroot00000000000000Feature ID Taxon 74c5523929f4d53f7928f15bc7751994 k__Bacteria; p__Firmicutes; c__Clostridia; o__Clostridiales; f__Clostridiaceae; g__Clostridium; s__ 29f6e97a2ed3b8abe26bb45acba8451f k__Bacteria; p__Firmicutes; c__Bacilli; o__Lactobacillales; f__Streptococcaceae; g__Streptococcus; s__ e25836661b81c9cc3aa99c8b2c7ca14d k__Bacteria; p__Proteobacteria; c__Alphaproteobacteria; o__Rhodobacterales; f__Rhodobacteraceae; g__Rhodobacter; s__sphaeroides 33b601a7a8295e7a6c8f413504129220 k__Bacteria; p__Actinobacteria; c__Actinobacteria; o__Actinomycetales; f__Propionibacteriaceae; g__Propionibacterium; s__acnes 47ad35356a9bfec68416d32e4f039021 k__Bacteria; p__Firmicutes; c__Bacilli; o__Bacillales; f__Staphylococcaceae; g__Staphylococcus; s__aureus b7269ca8dbd01fc77b163d64ff1caf90 other 04195686f2b70585790ec75320de0d6f k__Bacteria; p__Proteobacteria; c__Gammaproteobacteria; o__Enterobacteriales; f__Enterobacteriaceae; g__Escherichia; s__coli 4e9b3c8dd9808d6a78936ceaf96dc0d5 k__Bacteria; p__Proteobacteria; c__Epsilonproteobacteria; o__Campylobacterales; f__Helicobacteraceae; g__Helicobacter; s__pylori d9e724faff24eeeb7ac7fcc5cc7885b6 k__Archaea; p__Euryarchaeota; c__Methanobacteria; o__Methanobacteriales; f__Methanobacteriaceae; g__Methanobrevibacter; s__ 86adb6193435090318cf24df07770d07 k__Bacteria; p__[Thermi]; c__Deinococci; o__Deinococcales; f__Deinococcaceae; g__Deinococcus; s__ d8505780c03879a277eb71fe2c852192 k__Archaea; p__Euryarchaeota; c__Methanobacteria; o__Methanobacteriales; f__Methanobacteriaceae; g__Methanobrevibacter; s__ 92e3a73c9006d7a85d3112558daf2576 k__Bacteria; p__Proteobacteria; c__Gammaproteobacteria; o__Pseudomonadales; f__Moraxellaceae; g__Acinetobacter; s__ 075614efc7d3dd61cd64a4e5f17078ae k__Bacteria; p__Firmicutes; c__Bacilli; o__Bacillales; f__Bacillaceae; g__Bacillus; s__cereus 94b000e59b7ac160b0416c9ab45ff0bf k__Bacteria; p__Firmicutes; c__Bacilli; o__Lactobacillales; f__Enterococcaceae; g__Enterococcus; s__ 194be3a565245d51b6d1182d4d8c7e5b k__Bacteria; p__Bacteroidetes; c__Bacteroidia; o__Bacteroidales; f__Bacteroidaceae; g__Bacteroides; s__ ac5402de1ddf427ab8d2b0a8a0a44f19 k__Bacteria; p__Bacteroidetes; c__Bacteroidia; o__Bacteroidales; f__Bacteroidaceae; g__Bacteroides; s__ c4269a6e9bd66eca53e710c9f9d9ad4f k__Bacteria; p__Firmicutes; c__Bacilli; o__Lactobacillales; f__Streptococcaceae; g__Streptococcus; s__ 9ac5fec396208e598ab2e2d26985d0df k__Bacteria; p__Actinobacteria; c__Actinobacteria; o__Actinomycetales; f__Actinomycetaceae; g__Actinomyces; s__ 1c86153e1b13ab5322c96f2602b73513 k__Archaea; p__Euryarchaeota; c__Methanobacteria; o__Methanobacteriales; f__Methanobacteriaceae; g__Methanobrevibacter; s__ dcb7b288381ec22163253cc31ca4bb57 k__Bacteria; p__Proteobacteria; c__Betaproteobacteria; o__Neisseriales; f__Neisseriaceae; g__Neisseria; s__ 7a8d29c59b803baaed9cc1f04ce0dc33 k__Bacteria; p__Proteobacteria; c__Gammaproteobacteria; o__Pseudomonadales; f__Moraxellaceae; g__Acinetobacter; s__ 5642c43966bbd7f41c2f0cbe988205ff k__Bacteria; p__Firmicutes; c__Bacilli; o__Bacillales; f__Listeriaceae; g__Listeria; s__monocytogenes bc23d2ee539bf2f52faf789289af7879 k__Bacteria; p__Proteobacteria; c__Gammaproteobacteria; o__Pseudomonadales; f__Pseudomonadaceae; g__Pseudomonas; s__aeruginosa b3fef1e26b7b6ac20847ede4da68547a k__Bacteria; p__Firmicutes; c__Bacilli; o__Lactobacillales; f__Lactobacillaceae; g__Lactobacillus; s__ aebf2a74a3aa9e5876c479b1db88985f k__Bacteria; p__Firmicutes; c__Bacilli; o__Lactobacillales; f__Streptococcaceae; g__Streptococcus; s__agalactiae q2-quality-control-2021.8.0/q2_quality_control/tests/data/mock-3-obs-table.biom000066400000000000000000001020601411645176100271530ustar00rootroot00000000000000HDF  0`  TREEHEAPX observationsample8 @id ` @type` H format-url` P format-version@ H generated-by` Hcreation-date` H shape@ 0 nnz@G`TREE @HLhNGCOL No Table IDhttp://biom-format.orgBIOM-Format 2.1.52016-12-02T21:19:05.935051 dcb7b288381ec22163253cc31ca4bb57 9ac5fec396208e598ab2e2d26985d0df 94b000e59b7ac160b0416c9ab45ff0bf 1c86153e1b13ab5322c96f2602b73513 b3fef1e26b7b6ac20847ede4da68547a 4e9b3c8dd9808d6a78936ceaf96dc0d5 d9e724faff24eeeb7ac7fcc5cc7885b6 d8505780c03879a277eb71fe2c852192 ac5402de1ddf427ab8d2b0a8a0a44f19 194be3a565245d51b6d1182d4d8c7e5b 33b601a7a8295e7a6c8f413504129220 b7269ca8dbd01fc77b163d64ff1caf90 04195686f2b70585790ec75320de0d6f aebf2a74a3aa9e5876c479b1db88985f 5642c43966bbd7f41c2f0cbe988205ff 29f6e97a2ed3b8abe26bb45acba8451f 92e3a73c9006d7a85d3112558daf2576 075614efc7d3dd61cd64a4e5f17078ae bc23d2ee539bf2f52faf789289af7879 e25836661b81c9cc3aa99c8b2c7ca14d 74c5523929f4d53f7928f15bc7751994 7a8d29c59b803baaed9cc1f04ce0dc33 86adb6193435090318cf24df07770d07 c4269a6e9bd66eca53e710c9f9d9ad4f 47ad35356a9bfec68416d32e4f039021HMPMockV1.2.Staggered1 HMPMockV1.2.Staggered2!HMPMockV1.1.Even2"HMPMockV1.1.Even1 HEAPX8matrixidsmetadatagroup-metadata SNOD`QQSTREE@'HEAPX `dataindicesindptr8SNOD(NO(QC @(HLhNGG ?@4 4 deflateG9BXPTREE(GSNOD09x^U=KA[n#XZV 6,h EPR(cL ,!VdB, [{,\21xb |)3L.0{1~?c%7V !VKâaKa~ݱ}5? 'YŖqw>kmYRӎ9ZEЯaq6;8)ؐmo(˺\K2~PHx^c````b& ffbĩG0t9F7_x^ + @ 1 A #g`"" K+k[;{Ax^]I ѿRpTp GXyQD>%eo*V~ a laopp<^58 x^U=K`3) ]%*EࠤUEERNAjv J3:j fCbt9;ڽ<3c~ML/Њn۲#LJw_qk~K]ܿ!ОA S^PkTH3isPK{Px)',8a7db112-846d-4e7e-8cc0-b2d6b019edf1/VERSION uU0J,J,KR0J+JM-/ʶR02033PK{PR{=8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/metadata.yaml=˱0НPB2#8\{^V(ׁķ@VZEPG8W)[ck+}"\t!J}9CX= p9L[h<(w &J# PK{P=l =8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/citations.bib}Vv7+$ě^ E"edd[&Ɂh,(c X P%S4 Y/犿-,5hW)>x{|m]|;2jú#NH ҕˊMqIRIT`ՈQ{ >2k57fV:/zPp=II=g4v'gd;+Ⲭ Kj"-\MwZ N-94Iv$g NUR/W|:b[0="nIYJ\=5/di;6205~p}PHW5O6*G;&1:n_R26/%Hg V7H1nU*sleyQAбT[h*"isNGL^<Nv>biʌ3S%ԄAFޗ\IQLfFI&4aA~&.=3]H ΑdMQ9 /LQ Ã-FjY{ֵyL\MwKvx^dbRtˎB"Ue gGFuCUuuGџ(%[}]_C SV)`p*IYzQtdSGMa ̬U?5K%X4 # phdhcrybB(o$Lq"4!3=Kԯ<%yJ3 #*C5-%Be!&3JF%k'ti#C`[LkӬaXqz,*sr~etzV`quO=' Y;&x X%zib e-A{rV9{Ͽb@u)v*g,}vY\΢Jܣ:phV>n sUskf4,*t a"8Y>^\NA<$ġ~>=^h珝;;PK{Px)'78a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/VERSION uU0J,J,KR0J+JM-/ʶR02033PK{P,bO8B8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/action/action.yamlXo8_{.vRԷߊ\{EWԽbPHf-D%v?lQ@fp>*!͍_(CL$s40*4r qVkPWJ\4g ߣAH%9C[",.ƞ[g1q{9m10ltWPʾahVU X ߲==?E4% jROY?~{nlWSDlE% S98SΩGӀbS;6 ]Ie@3L+(@Ytk0ܳ-?ٿ?^a8ʂgh!NEvi _AQxR~] y'O 4J4,+H/'؏Ox\&EqVyQ4~  `O Γ`!s^0eJw<(?&eQƋdQ{}w-kB$ N/T{| ӻS6o<Tg.AaQ:@*8˾M79c%/K},^U2Ӓ{quP1lf'm6׹l(Bu1\VA"Ac0N߉\ J|YPЌXy=w]ב٩W8$j\04i_ap/۳ G"$).@w|nX:o?~8TL&뙀1Z![on>NuV%Y N# )cǐVZU:o@-z&h*ЀKrnf 'ǡMsU,p`:9˼@SFzd+.ֿ#c^ L@uQiWV~2،r[0Xӭ wp+Ϋ:^NnTOg`!d2>&   )Ame+R/#+uv~тKD`iOoMt5Bi14Rw6CݚJe O#piAxvrliXzBS]-Bz mYi[PSVK IX~M,6}u2yIF2V osguS| nٰUYjzB}Ȇyա֜I &8luOog>@{i| eef ’E j;Mo.]z֚(c3ՑN,pZ^q*(”N heyPRE!:ǵ8>CSO b}XVLiU:uͩd3y=x,.pKɪg^t|uiͻZ&Ml∬~Y|ylKTyZV} u(gw5t쒇1%{Mhw0`7\wtEpcsq SI)e ?F^~`COQgVvpyjzS<Ţtz}?PK{PAxsK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_c_S03_L001_R1_001.fastq.gzsn~^sample_c_S01_L001_R1_001.fastqAr0 EF]$l*,06Y?=LnZ-JHw>۱m_>ޗSU#2L#;og>GwNcV6;,ُS͌EL:ZL%0r+XG`ZOۆh<Oo2:;~'u9PRԌL<-0 g@[7"",w z:dW-y4 }-]]ڛk*u?,C [*5K X{Lf1퍞])^^c`WUY7{z6C 3ɐ؜v:9SP.΍{0h_Xj PK{PxsK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_b_S02_L001_R1_001.fastq.gzsn~^sample_b_S01_L001_R1_001.fastqAr0 EF]$l*,06Y?=LnZ-JHw>۱m_>ޗSU#2L#;og>GwNcV6;,ُS͌EL:ZL%0r+XG`ZOۆh<Oo2:;~'u9PRԌL<-0 g@[7"",w z:dW-y4 }-]]ڛk*u?,C [*5K X{Lf1퍞])^^c`WUY7{z6C 3ɐ؜v:9SP.΍{0h_Xj PKL{P7&28a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/MANIFEST0 ;O$Ia ۴}zBү[O{pO-)BmdzG]g=xI# BF Mi0-/O@h $pҌꐅjTsS>8u*yVӾUR)y&LDM)d=IaS"YNPK{PZAxsK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_a_S01_L001_R1_001.fastq.gzsn~^sample_a_S01_L001_R1_001.fastqAr0 EF]$l*,06Y?=LnZ-JHw>۱m_>ޗSU#2L#;og>GwNcV6;,ُS͌EL:ZL%0r+XG`ZOۆh<Oo2:;~'u9PRԌL<-0 g@[7"",w z:dW-y4 }-]]ڛk*u?,C [*5K X{Lf1퍞])^^c`WUY7{z6C 3ɐ؜v:9SP.΍{0h_Xj PKS{N({68a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/metadata.yml.(JMOK+N-R06PKH{PFrmK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_a_S01_L001_R2_001.fastq.gzm~^sample_a_S01_L001_R2_001.fastqKr@ DY%2(,PƸY2zە$"5ޯv-ח%#㓭#:jcƌѥƕƱHz4{ߚm33ot|}Jg,mTsqsq˷z}|]c]1'lW3V-hջ>POC޲D1D4.uC7iK,LGҐدE~dB!xb>1zHd@{Y o:mtX16 m30L@J0,sYl"B𫺍I]-=uFMv:|_?ET<"@ՎkD;꘼Ŵ{A%š 2pǤrвaGPMI٘طn&@KU; i$9'6:SIF-SO3]((BÅx`꾋sy$v<~n+UZY?d{<8yts Ypo9I<2T I>j PKE{PZ̤rmK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_c_S03_L001_R2_001.fastq.gzm~^sample_c_S03_L001_R2_001.fastqKr@ DY%2(,PƸY2zە$"5ޯv-ח%#㓭#:jcƌѥƕƱHz4{ߚm33ot|}Jg,mTsqsq˷z}|]c]1'lW3V-hջ>POC޲D1D4.uC7iK,LGҐدE~dB!xb>1zHd@{Y o:mtX16 m30L@J0,sYl"B𫺍I]-=uFMv:|_?ET<"@ՎkD;꘼Ŵ{A%š 2pǤrвaGPMI٘طn&@KU; i$9'6:SIF-SO3]((BÅx`꾋sy$v<~n+UZY?d{<8yts Ypo9I<2T I>j PKJ{P$" rmK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_b_S02_L001_R2_001.fastq.gzm~^sample_b_S02_L001_R2_001.fastqKr@ DY%2(,PƸY2zە$"5ޯv-ח%#㓭#:jcƌѥƕƱHz4{ߚm33ot|}Jg,mTsqsq˷z}|]c]1'lW3V-hջ>POC޲D1D4.uC7iK,LGҐدE~dB!xb>1zHd@{Y o:mtX16 m30L@J0,sYl"B𫺍I]-=uFMv:|_?ET<"@ՎkD;꘼Ŵ{A%š 2pǤrвaGPMI٘طn&@KU; i$9'6:SIF-SO3]((BÅx`꾋sy$v<~n+UZY?d{<8yts Ypo9I<2T I>j PK{PR{28a7db112-846d-4e7e-8cc0-b2d6b019edf1/metadata.yamlPK{P&=_28a7db112-846d-4e7e-8cc0-b2d6b019edf1/checksums.md5PK{Px)',8a7db112-846d-4e7e-8cc0-b2d6b019edf1/VERSIONPK{PR{=8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/metadata.yamlPK{P=l =8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/citations.bibPK{Px)'7 8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/VERSIONPK{P,bO8Bg 8a7db112-846d-4e7e-8cc0-b2d6b019edf1/provenance/action/action.yamlPK{PAxsK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_c_S03_L001_R1_001.fastq.gzPK{PxsK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_b_S02_L001_R1_001.fastq.gzPKL{P7&28a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/MANIFESTPK{PZAxsK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_a_S01_L001_R1_001.fastq.gzPKS{N({68a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/metadata.ymlPKH{PFrmK 8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_a_S01_L001_R2_001.fastq.gzPKE{PZ̤rmK8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_c_S03_L001_R2_001.fastq.gzPKJ{P$" rmK"8a7db112-846d-4e7e-8cc0-b2d6b019edf1/data/sample_b_S02_L001_R2_001.fastq.gzPK_%q2-quality-control-2021.8.0/q2_quality_control/tests/data/qc-mock-3-expected.qza000066400000000000000000000123321411645176100273540ustar00rootroot00000000000000PK%WMK̕jh2228722f8-3bc7-4c6a-9d9e-6a2f29e10851/metadata.yaml+-LR02072J5NJ65I6KԵLL5K4J3L5405*,HRpKM,)-J ILIJI,,Ku+J-,MKJ/M,Rp 324p,r-PK%WMK&',228722f8-3bc7-4c6a-9d9e-6a2f29e10851/VERSION uU0J,J,K2ӊsS󋲁Cs=K=.PK%WMKw 0<228722f8-3bc7-4c6a-9d9e-6a2f29e10851/data/feature-table.biom]}p_ ac1uJ&FrÀ?A66GX:Iޝ+8q !$OôӘv!t:8C҄ɤq v- t۽ӝ}61V^*u9@a4>IzD1Xpa#s1)joɷ-ͳ-:칎;-p8[hb4A!&nq)ZdxZf \X!he6媄|\D|&-f(fͫ! r0co_oVeH>hZMEJτ @ ωLhD6hQ |.d|,aTɬȕ<;2 "Qʰ^rs(YEJQ*$|ґ@_-+4ד8LiFTG*b[_ Ijh6s}G#a8gتSӰ\6,ć))ω5k5ё{0gZ($Ȏg5>e}QZbS@COcI]t:#q{ cN B% A1BǻQD C S)8U ڦI3,r812Fe!}^r&Qe jg%XRT13]mgKBd)&<.B͠DZtbJ| JYU(Rȯ>@m y8@zr6vDST" A23:'rZSiJ/W.x nzXŹw>;쐡^WǏ?kkrbW B_' ϳ#~8R{(^ sU*^G譫.5$y-d؜|(i]zNT[?,'dpr轌{e6aiH4(w^F)`>_@XZNW%u_qF}/zx Lm7\3~i2,dV*/eEh6R#Iɲ &IoV=L/f$79)2WU܎Qm6\)Mh"2ޙ: k*N9MVc8ǗKܶ{ ?;s9W?9vʬq'_S6۽ºom{}n ҟ μ6{^{{IړEo_= _\P8+x5 ֮,:{_ͬݭ "a[SSGǺlkpkCs:S֔nQdf9x/@Kc}OdɱW={߿?rryk-O,g+,ޓROY Z@^ϧW+on?m[}'yTfҁ͵TQOyܟdgzzwCmKno8߲7_׾N]2N\>Kԕ_xsSޛHk]~TfG!H9Љ?vxi=?=M^f}k=w8Sc"zNkCv^pMҋLW΅'AmkC@@@@pס,kdd>GaۡRޢ]+cu(uihk`xW1]܀A]ۉO'|xQJG9}P^~.~dI@@@@@@0Q Пt$`5! b|wӳmS⿓FpZ>k]Hr! NNz-X3 >#X^7S ŖwV_`]w?_qxδurܜ3 O#L &.Llq?cq9[b<9gB@@@@@0/~N0~*]c'N$~" ?8wIGrܜ3[?s&FI'I'7[ݭ} bPK%WMK̕jh=228722f8-3bc7-4c6a-9d9e-6a2f29e10851/provenance/metadata.yaml+-LR02072J5NJ65I6KԵLL5K4J3L5405*,HRpKM,)-J ILIJI,,Ku+J-,MKJ/M,Rp 324p,r-PK%WMK&'7228722f8-3bc7-4c6a-9d9e-6a2f29e10851/provenance/VERSION uU0J,J,K2ӊsS󋲁Cs=K=.PK%WMKrG: B228722f8-3bc7-4c6a-9d9e-6a2f29e10851/provenance/action/action.yamlWM6m4DYm݂=(4((j$3H-Im4Rkڭ{̛7Z8 7MLMMfq,{u4-ΙI>TQmLҘl~#iUl+B]$ӢJӋ=62u3)r>ʿ|1_o"ɣoHّvD4FOM-z.z?uIwQJTx{qQd 0"8~ I 2͒4)6orZE"q)\OLSDžtt`d@hW Fx A0pѡ{ ~u ߛC"~e=(I=7('Ir IvE1 K R H+.B1h%tmPyΨуl.HKgDF#u)1~hz8#7qtyAEYsiUELsc &,rKf?LSdjYϯgĨҮu'z]-v5okfOx{m0Fod5D[&JP6-a:Rt+>1C.pa+Xnaq:<$~9?773X}䦯(tNbKY .iG5%!|%;je@UV;T bT˥bdOG`J(ɖu :Yxe4,IX! R-zk :)j{ĩK1m1EiC00>w a\I{i~>RuGڂ;morcpH؟ϓVj˝Esak`Vx/\|/Wp>̘)~HvNGPzrMxp]f W-/h'˖.ۭN-ՆvďÓd~pj%wjA3ڝHkQ4ߕV[wbQjK ^6S2)>6r([GV3{dbf&sږ;iP | $DR-px?@=O(T sE GҺ@*C|M$sYo;u踙|-h6MLk} D$OzG>dq>kv o| h@n^p_PK%WMK̕jh2228722f8-3bc7-4c6a-9d9e-6a2f29e10851/metadata.yamlPK%WMK&',228722f8-3bc7-4c6a-9d9e-6a2f29e10851/VERSIONPK%WMKw 0<*228722f8-3bc7-4c6a-9d9e-6a2f29e10851/data/feature-table.biomPK%WMK̕jh=y 228722f8-3bc7-4c6a-9d9e-6a2f29e10851/provenance/metadata.yamlPK%WMK&'7> 228722f8-3bc7-4c6a-9d9e-6a2f29e10851/provenance/VERSIONPK%WMKrG: B 228722f8-3bc7-4c6a-9d9e-6a2f29e10851/provenance/action/action.yamlPKd`q2-quality-control-2021.8.0/q2_quality_control/tests/data/qc-mock-3-observed.qza000066400000000000000000000132121411645176100273620ustar00rootroot00000000000000PK%WMK6Nih2d5d6a058-eba7-4a35-a5a0-60316d8ae3fc/metadata.yamlA 0}N RcbR$B7y@[53u9pἁ5.tӨd0DHcqSquD}<_/]gOEPK%WMK&',d5d6a058-eba7-4a35-a5a0-60316d8ae3fc/VERSION uU0J,J,K2ӊsS󋲁Cs=K=.PK%WMKqѨ 0<d5d6a058-eba7-4a35-a5a0-60316d8ae3fc/data/feature-table.biom\ TW(DtɱkUcE+dHd$ X@8=zr\SYTE[=u.;y7 <{{ܼ%ɉ۶ښ@ZPZ>\7V2V*\t- 1_$w 9/S=4Zeg>f9w6sUm(+AT'JCEޡ@F C&$$9wiGZ r9vG9 +G^ /kϿy% V kK]-l+ؙ'f,Y -d NFh / k)ܷ+&ۑl7kPv\v#azC-1lܾf4&f7d88uXsqř+qFxm4͙9634#\F#C[4# zg5D(+r;Y a$Rl"*[_s3)xOr2|r.gPK|h\,ɱƅ-P{wL`Xx`ǡ57z.W=< HfY9D9Yy7Ԟ1V@$^ FNs\\oYYsL)Hu1yi X90 πbߗ&H41:g^k\t;FvHXD=P+@"Y>3>aJK6o39O%~TXX$" vz2P_yVfJC^/;Mر59 '$ZIHTJ"$/_vSM|4|8<G]S8 RsXe*Tŧ%m36$)w˓;STP,.0\Z^Ad,@v2,/wa^SRS8kS1c͢zRT7|c||>ӻSrSu[X-R,8,Pg-'@n(c'爖7mD~ݏ?ONl$;ߦ }Ėb[X/#w * /G(Q8~sfTr5pZycэ/[Vr̬we\&H}oDl?ZJ#]%rv.B-go6/D( z,9k޲}(Ivn:tgGEBG훉nڜ|-"ݻi /6?,ڬ-F֦JC;BM[tӏPչOi"4xچvr}rl+phh1ud߻)]P{]+QgdMFM֨܉xu(G+!鄿^/u?糁u~F7අ PB}SIU-PO0N~" hT?9haPGE$J*?sWQ?8i$ h.ωPAPrespZ[<B>Irs3}1&]po[1Elo 9Eϙ:%b ]a?)].O.ϙLT6s3ܒssAz;~>/cOa/M eT5}I~}n>I@2ϰ~2$UM~ _`HD@@@@@|~:pΤ(_RdΙVOp? Ap/6(=} ?)5PK%WMK6Nih=d5d6a058-eba7-4a35-a5a0-60316d8ae3fc/provenance/metadata.yamlA 0}N RcbR$B7y@[53u9pἁ5.tӨd0DHcqSquD}<_/]gOEPK%WMK&'7d5d6a058-eba7-4a35-a5a0-60316d8ae3fc/provenance/VERSION uU0J,J,K2ӊsS󋲁Cs=K=.PK%WMKvF: Bd5d6a058-eba7-4a35-a5a0-60316d8ae3fc/provenance/action/action.yamlWM6m4Dɒm݂=(4((j$3H-Im4Rkڭ{7Z8 7M }Ŏ5񆕻2 qM7m$ `ykPeAJ1IcFҪV$4/veU^A47$IQk<Δhe3PE|2ww baSJ5T@'Ӯ,98K<)M-);#ԼiSoE."+]jC*R燇hd 0bMuqĿ>1*Se%iRorZE"qi\Oҗ ]E|J_~F_xӁѢ]?s{ A0pѡ{ ~u ߛC"~e=(I=s$X IvE1 [ mr5&Tއ5z ھ%`$P6\:8[ 4);5f캷_K=هeͥU35 @;Yt醕}RmX?iG$Ʃyܭ-"PDZ_E]iu.P,4JVcx!m}] )wgA ?8j@Gv .6`o2Cֶ՛` o9kx- }JRAND1 AGGAGGGAGAAAAATTTGTGATGATGTGCTATAAGAAAAAACGCGCGCCCCCCCCCGGGGGGGGTTTTTTTTTATGTATATTATTTTTCCCCCCAAAAAAGGGGGGTTTTTTTAAAAACCACATGCTACTAGCTAGCTGTGATCGTGATCGTGACGTGTGCATGCTAGCTAGTGCATGTGCATGGTAGCTGATCGTGACAACTCACTGGACACATATTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >RAND2 AAAAAAAAAACCCCCCCGGGGGTGTACGTAGCTACGTGTGTGCTGTGGTTTTTTTGGGGGGGGATGCTAGTGTGTAGCTGACTGATCGATGCTGTGGCATGTGATGCATGCTAGCTAGCTAGCTGACTGATCGATCGATCGAGCGATCACAAAAAAACCCCCCCCCGGGGGGGGTTTTGACTGACTGAGAAAAAACCCCCGCCTCCTGGCTTAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >YAYIMATCH TACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCAGGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTTAACCTGGGAACTGCATTCGAAACTGGCAGGCTGGAGTCTTGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGCAAAC q2-quality-control-2021.8.0/q2_quality_control/tests/data/query-sequences-left-justified.fasta000066400000000000000000000002671411645176100324440ustar00rootroot00000000000000>1111886-leftjustmatch TACGGAGGGGGCTAG >1111883-noleftjustmatch ACGGAGGGTGCGAGC >1111882-leftjustwithindel TACGGAGGACCAAGCGTTATCCGGAATCATTGGGTT >1111879-leftjustmatch GACAGAGGGGGCAAG q2-quality-control-2021.8.0/q2_quality_control/tests/data/query-sequences-short.fasta000066400000000000000000000001751411645176100306630ustar00rootroot00000000000000>1111886 CACATATTGACGCTG >1111867 AGTATGAGAGAGGGA >1111783 GTAGAGGGGGGTAGA >1111768 CCGAAACTGCGTGAC >1111750 TGAGAATGGTAGAGG q2-quality-control-2021.8.0/q2_quality_control/tests/data/query-sequences-with-mismatch.fasta000066400000000000000000000024131411645176100322770ustar00rootroot00000000000000>2MISA TACGGAGGGGGCTAGCGTTGTTCGGAATTACTGGGCGTTAAGCGCACGTAGGCGGCTTTGTAAGTTAGAGGTGAAAGCCCGGGGCTCAACTCCGGAATTGCCTTTAAGACTGCATCGCTAGAATTGTGCAGAGGTGAGTGGAATTCCGAGTGTAGAGGTGAAATTCGTAGATATTCGGAAGAACACCAGTGGCGAAGGCGACTCACTGGACACATATTGACGCTGAGGTGCGAATGCGTGGGGAGCAAAC >2MISB TACAGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTGTCTAAGTCGGGTGTGAAAGCCCCGGGCTCAACCTGGGAACTGCATTCGATACTGGACGGCTAAAGTATGAGAGAGGGAGGTAGAATTCCACGTGTAGCGGTGAAATGCGTAGATATGTGGAGGAATACCGGTGGCGAAGGCGGCCTCCTGGGTTAATACTGACGCTGTGGTGCGAAAGCGTGGGGAGCAAAC >8MISA TACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCAGGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTTAACCTGGGAACTGCCGGCGAAACTGGCAGAAAGGAGTCTTGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGAGCAGGTGCGAAAGCGTGGGGAGCAAAC >8MISB TACGGAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTACGTAAGTCGGATGTGAAAGCCCCGGGCTCAACCTGGGAATTGCATCCGAAACAAAATGACTAGAGTATGTGAGAGGGAAGGGGAATTCCGGGTGTAGCGGTGAAATGCGTAGATATCCGGAGGAACACCAGTGGCGAAGGCGCCTTCCTGGTTTTATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCGAAC >10MISA TACGTAGGACCCAAGCGTTATCCGGAGTGACTGGGCGTAAAGAGTTGCGTAGGCGGCTTATTAAGTGGATAGTGAAACCTGGTGGCTCAACCATACAGACTATTATCCAAAAAATTAAGCTTGAGAATGGTAGAGGTGATTGGAATTTCTAGTGTAGGGGTAATATCCGTAGATATTAGAAGGAACACCAATGGCGTAGGCAGATCAAAAAACCATTTCTGACGCTGAGGCACGAAAGCGTAAGGAGCGA q2-quality-control-2021.8.0/q2_quality_control/tests/data/query-sequences.fasta000066400000000000000000000041571411645176100275320ustar00rootroot00000000000000>1111886 TACGGAGGGGGCTAGCGTTGTTCGGAATTACTGGGCGTAAAGCGCACGTAGGCGGCTTTGTAAGTTAGAGGTGAAAGCCCGGGGCTCAACTCCGGAATTGCCTTTAAGACTGCATCGCTAGAATTGTGGAGAGGTGAGTGGAATTCCGAGTGTAGAGGTGAAATTCGTAGATATTCGGAAGAACACCAGTGGCGAAGGCGACTCACTGGACACATATTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >1111867 TACAGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTGTCTAAGTCGGGTGTGAAAGCCCCGGGCTCAACCTGGGAACTGCATTCGATACTGGACGGCTAGAGTATGAGAGAGGGAGGTAGAATTCCACGTGTAGCGGTGAAATGCGTAGATATGTGGAGGAATACCGGTGGCGAAGGCGGCCTCCTGGCTTAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCAAAC >1111783 TACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGCGTAAAGCGCACGCAGGCGGTCTGTCAAGTCGGATGTGAAATCCCCGGGCTTAACCTGGGAACTGCATTCGAAACTGGCAGGCTGGAGTCTTGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACAAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGCAAAC >1111768 TACGGAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGCGCGTAGGCGGCTACGTAAGTCGGATGTGAAAGCCCCGGGCTCAACCTGGGAATTGCATCCGAAACTGCGTGACTAGAGTATGTGAGAGGGAAGGGGAATTCCGGGTGTAGCGGTGAAATGCGTAGATATCCGGAGGAACACCAGTGGCGAAGGCGCCTTCCTGGCACAATACTGACGCTGAGGTGCGAAAGCGTGGGGAGCGAAC >1111750 TACGTAGGACCCAAGCGTTATCCGGAGTGACTGGGCGTAAAGAGTTGCGTAGGCGGCTTATTAAGTGGATAGTGAAACCTGGTGGCTCAACCATACAGACTATTATCCAAACTGATAAGCTTGAGAATGGTAGAGGTGATTGGAATTTCTAGTGTAGGGGTAATATCCGTAGATATTAGAAGGAACACCAATGGCGTAGGCAGATCACTGGACCATTTCTGACGCTGAGGCACGAAAGCGTGGGGAGCGA >SH076366.07FU_FJ613078_reps TTACAGAGTTGTAAAACTCCCTAAACACTTGTGAACTTACCTGTATTGTTGCTTCGGCAGGCGGCCCCAGGGCGGGGCTGTAGCCTTTATAGGCGCCTGCCGGAGGATTTAAACGCTAAATTTACTTGTCTCTCTGAGCAACTTATCAATAAGTTAA >SH076370.07FU_U17329_refs TTACTGAGTTGAAAAACCCCAACCCCTGTGAACATAACCTCTGTCGTTGCTTCGGCGGGCACGCCCGCCGGAGGTTCAAAACTCTTATTTTTTCCAGTATCTCTGAGCCTGAAAGACAAATAATCAA >SH076371.07FU_DQ528766_reps TTACAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTTTACTGTTGCTTCGGCGGCGCCCGCCGCCGCCGGAGGTTCAAAACCCTGAATTTTAGTGTATCTCTGAGTACGAAAAGAACCTGAAAAATTAA >SH076385.07FU_KJ855505_reps TTAAAGAGTTGCAAAACTCCAACCCCTGTGAACCTTACCTGCACGTTGCTTCGGCGGCSGGCGCCGCGCCCGGCCGGGCGTGGAGGACGCCGCCGGAGGTCTCAAACCCTGAATTCTAGTGTGTCTCTGAGTATGGAAAGAACCAATCAA >SH076388.07FU_AJ132542_reps TTACAGAGTTGAAAAACTCCAACCCCTGTGAACCTTACCATTACTGTTGCTTCGGCGGACGAAGGCCCCCTTGGGGCTGGATGCCGCCGGAGGTTTCAAACTCTGAATCTTTGTGTATCTCTGAGGAAAAAAACAAATAATTAA q2-quality-control-2021.8.0/q2_quality_control/tests/data/sars2-genome.qza000066400000000000000000000350361411645176100263730ustar00rootroot00000000000000PK{{Pdq bk2d11e38c2-e1a3-4e25-a08a-8c226a7890fd/metadata.yaml+-LRH14L5H6M5L45I52M4H %[XpTZ)&$$F%r&X)9]2RK*\PK{{P k;2d11e38c2-e1a3-4e25-a08a-8c226a7890fd/checksums.md5=N0F k{<9"D?"Y$nOVD*p𾣖[MVdQ{}x?2X*X>Eh@LAAy,(%M:d*!)3,f2vZVڟR/ʹ1?Pcm,y#4ꅣdn;Hx{|m]|;2jú#NH ҕˊMqIRIT`ՈQ{ >2k57fV:/zPp=II=g4v'gd;+Ⲭ Kj"-\MwZ N-94Iv$g NUR/W|:b[0="nIYJ\=5/di;6205~p}PHW5O6*G;&1:n_R26/%Hg V7H1nU*sleyQAбT[h*"isNGL^<Nv>biʌ3S%ԄAFޗ\IQLfFI&4aA~&.=3]H ΑdMQ9 /LQ Ã-FjY{ֵyL\MwKvx^dbRtˎB"Ue gGFuCUuuGџ(%[}]_C SV)`p*IYzQtdSGMa ̬U?5K%X4 # phdhcrybB(o$Lq"4!3=Kԯ<%yJ3 #*C5-%Be!&3JF%k'ti#C`[LkӬaXqz,*sr~etzV`quO=' Y;&x X%zib e-A{rV9{Ͽb@u)v*g,}vY\΢Jܣ:phV>n sUskf4,*t a"8Y>^\NA<$ġ~>=^h珝;;PK{{Px)'7d11e38c2-e1a3-4e25-a08a-8c226a7890fd/provenance/VERSION uU0J,J,KR0J+JM-/ʶR02033PK{{Ps3fJBd11e38c2-e1a3-4e25-a08a-8c226a7890fd/provenance/action/action.yamlW[o~ϯP])ْd]춋CQ Ɍ%R! Ώ-ʱ[yp87~ N@{=x{V,C~PYtѰede5ka};L u0|& }0_nIMy߼#3$>z5ߕP?zجh;lM}q>?{i,T4=7(Q&z˯__Lb4glĢ y Kgm `w(أ֝=>28/6i;,jv{A)xeƃ T̾fQ3PοA9Ƀ" J&8)C_TSoosO r"`]/5XEvp#̂d+kЊpLjű@c%I5%㵺蝢W}0(Ȯ w UeӰ"k'ߞ$z FPQB, áJy/g5΢4uAl<b9TBɴфSS]|Ӫ%4j y.b'^;*}0i{ľ$`NH n0RxdoIfRL \_4bSۭpiFA&h2=5@uS0>7ra77JQc6D)V13{ړX BK6pJcAVzFۇ[Ф$N*}iÉfQi mL5v@t/KZf/E]aA;ʒYwJQB۟w{}8-+ܭ 7u '9q" 0L&WK>WC`p~yH$7RJ !a3yy=lS@"t jjn3\o摘#sL/yV~#HլVi9!(xjΙS3??|ϯpeg뼿۽_v}_O#z; }߱x;]an;wn{w>W|vXkKo{KjE;wIny.X2+D\ϳ[7vmv w|.Ni"=5嚽="[yy͞ݻ=zG3]"YwD+T֮.fi7&Nv{fg47ȉ:pm:!?1پ| ߽zq{{/7.;߻[W{w.YW0mgs䓚ԆV$X1\(Ryfc s*791I.v"-o'b IUW d8f$ЦYmVcV@7jt.S~! te'};fFF؆c8@lD8쑕$Wy7q;&J#fM#礼- Qm-^Rq'8kcXMr̵Tvԟ"B=a:HC},o.oY\gx':XTI7Y;/z/M/fy^9l|ܜGeRȒ>#Z m7S@omC_$^";lfw^5b;>j}vM1‹:ŦRKXw>q2nW/MK|6*hy.@' %[NgAtjqooU%ZemHAa҂_:svS>?Dex,lpݤlmHI99ֆ_B%0kc_=ˋMZH_V1v79zJ{#Ε T,D)v&}-#E; #̋j(zx,0B>9|_lH|9 +([m3 :]]P[UXኇx[F"T.@$}ڵl`0A[#SA匴J2ssTU'%,$wN6 eXQ IcνDK|\FH5Sv{D ي,h@K|oMK@(Oĺ"ġ,/9-Fg)pRlT.3 hpe4$AN?ݱ>R)Xƾ[I{%EIeބI-5FqhԑP~B d2TpVI)V Nƅ_ 0oigDj%(qye6zS(8MJſ TCSd%X hw9 \³nL4*NZBD̥ܥz#օP-ݱCWTt.P ޛ-iwLԾqG$җ|vH^*%rSB8u]PF$ǶlHU;RgtKn|ɌSiOY0.Nyk$z?k ._1{TFEݼlcLÔJ.snm`\xp3]:0tX:eN 0Qp yK&db$ 5& H+A>e'ī$\/"{2ZYC>:N<@T58F\%PnBxW3tWJ?q[*參D.36vXÙ L^i q4JIzԾ"t hgDߪDh5eAuL< ѳ(Enn"x/^K]>qQ8@2HV" SrۭnKo!xA}2:<諔o)j)^؆7eᣲ!NHBQBp]I'M[(BJڮ$d^Z# mUdfv]k7s|UI xU!]ԋ^uKj$JdD=e!vPK5ƢJx!*\#*F$׫ !b?[1/ 5r1⬭*'ڬBu[DBDU[V GhḤaslEיLʜ39#m7dVO=6lc5@:HzOJPY4S{(X표N{SVlJ%+~[6!AtA ݢшwbIs;z Ѻ&4+40 tH{0P79x.!XX # hDRm2Ld F_@!1VtOkyM+q=)qK,ȹ}:!_UE:/<._n? eBFN]8h#t{ƥ5%.e􄲩q7>$ ERc(PRj74VN L/grVgDuoyT`=sW%+v?A|cב";Kό*->s3x*z#:))z{*Ӹk sؓ.Yi š0D+n ۩av୚y"$(#h. TVK/\]f렘V2b'L?='eOg8MȬE97jڎ]v$lFcWvdmB|DƩ Ϙ_QMz8BJa&zʽ(\F)bP}H<~Nj刂f"Qz ]x@܂5aʂDW>vqJO&Jyʃ#1Mج Կ"X~̬aN^]5gґ,Z>9 \<1 ѺCP#ƠA ?4QW!]ـ 5/l [nk?: H\ PRUJO&5jd+!Z!`b)ZpPi'4E_RWDxZ[JP)>ffK}O(EQJ;fymN^y}Gns0+O4na{~j ׎%ݎKLO ;D Hy={(1:+?x2j!d/`6i>2X^++w7SZ} CLwiZEp]`Z:Rmm'siFwPXd-)u>f->"}s=wWR)p8ד~wSh3H"v"n+Ebzj6ENZ5h紁"-O4 pMNjWgxϜIkrXwDSXf[ Ք:+ɥqjێص[J%{Gu"Mna\sŕ#Ι}MpBaT PزiwŎJqƮ1.?S?0M-ͶF.ڽZ"O!U7ƖC &1iIRDP6-g7Ah ^?zG悹۰<} $[.G;!U8%f+K8TBh$L/]t8m&FD6Y <  1?;L-lS@xM{R6^־!=dx2^rLxYQ62LψuزW݋C=1A)OrAHj9cSI=WmN$L8Vdқ]ur*փ鼧AN,U'}&VGca*qԡU`sy7IsƽH2HsG͔ LH>ɭ ! < \ u 5~ԲQG8ҿ^_zl*fqܩg`3dE&;i>:. 8K\#D]XKZXsԦQB7Q#eOLj_wȹ <Rߪ0U:dK ''.ZBBt- <179:iIRi̹ٕ:e1ޝ !mZ]7r'5^쮵6!ӓifH^*yrɼnOc&W)ʕt(NJ"!Jֶ]:-_uTGOpRЍ:Eu;ÉI& esE-&GkuϩB\X(6q >>(~G$)e/f<2B>V(= HX-#A\DeO\AdQ ftH6y},mI'*KYB]yfJ>|Vfqө=ApG E~ҍkbz Hq#co8Me 4jeۮNerinRiX;NvJs mNy$%P22y"ޞ:YꀜД=P>Lhg N;I?!(kKrd+^ԤNЙEgvUiabI@=lT>(rQ_t+ sa5 FR'y36u?}{ldT|"21AVd*%]x?ٖY0-?砘#݈%T7q"'TX~bVȠV5nalzWGv7ᇟDzLcsBE+Gdn1Q0}cG2WPlh^Sr'+( i2}e{o~2y8wa;A(᥀ N N!ѰIҗm@"؍=#=I)O2?m/cNm=KD8mCfݮ ݙIėIlzE= vsՁ9m!n?G~"W& y.U} iQ/Z兇hIwCӖ!W=5p:H}9U~awt@0c)KzWjkk"VL@bF~iVBdy M?ک.-as_6ߋmTRDHE= uWPwT}PfZĿ븰6KŅɈ6s;,9*g|80Κ ˍ\CP5Vs!qMNJd﫚y޻NK⧝0!laiDH+xwQ 8$7IMB;Gt VB^N\ɵ퍱 ^\D ,8U.*<9JYFyc%ּgC;r nJ .h1ԂҦH۽cPΉ1 ~)o{%˯;#|\*!J٥cELf,ӕZң2zS_'L,KY9[SnI@b']9bYּQpL\^EbGKiY=QT'6juz;i_P|G:jJ"ޅY'Eh~CFtyOuuo RV)%RYYUPfm /-#! /[~NHcTJ{1j*sT mG xpbvKFYPK{{Pdq bk2d11e38c2-e1a3-4e25-a08a-8c226a7890fd/metadata.yamlPK{{P k;2d11e38c2-e1a3-4e25-a08a-8c226a7890fd/checksums.md5PK{{Px)',d11e38c2-e1a3-4e25-a08a-8c226a7890fd/VERSIONPK{{Pdq bk=Hd11e38c2-e1a3-4e25-a08a-8c226a7890fd/provenance/metadata.yamlPK{{P=l =d11e38c2-e1a3-4e25-a08a-8c226a7890fd/provenance/citations.bibPK{{Px)'7d11e38c2-e1a3-4e25-a08a-8c226a7890fd/provenance/VERSIONPK{{Ps3fJBx d11e38c2-e1a3-4e25-a08a-8c226a7890fd/provenance/action/action.yamlPK{{PL[%v="d11e38c2-e1a3-4e25-a08a-8c226a7890fd/data/dna-sequences.fastaPK06q2-quality-control-2021.8.0/q2_quality_control/tests/data/sars2-indexed.qza000066400000000000000000005655311411645176100265510ustar00rootroot00000000000000PKI{P'OY232eb5e3e-f571-424d-bd94-2e56e0347c98/metadata.yaml+-LR06JM2M5NM357512IMJ45J55K5061O*,HRp//L5KIJ/M,At,r-PKI{PA232eb5e3e-f571-424d-bd94-2e56e0347c98/checksums.md51 yȒ%[C/-лdfKgo_gmC-{13f>EmGdCkf%,_} P %ȪҺR,U{ ? I¨QQf25E_Tj A#K J@#^XСHIk34 T~[?QagܛwV[O秃8f"Jޚ1yIHJycv|=nj4)u =$7O(Vˆ_P:1 >b ){6 Z׷dldŹUj @F&dn-I'B \R)"-܎ޒL?PKI{Px)',32eb5e3e-f571-424d-bd94-2e56e0347c98/VERSION uU0J,J,KR0J+JM-/ʶR02033PKI{P'OY=32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/metadata.yaml+-LR06JM2M5NM357512IMJ45J55K5061O*,HRp//L5KIJ/M,At,r-PKI{P=b0n =32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/citations.bibVKr79$ے]#ETXTӜ,&,r\,T*F"4ݯ'?/ fIwv^i4xVw6#-7TA*nEڻAqE6'BJ 9-#|^y3(⯖dp>#p}q9*<VyGBL920^~z2SQQQ jh(xhP  }l&SJi(lq8A '6].%w%2WFJT\uЯwC/ިc<{Y/Ƅb֤ 3} zid y;@匍:w jxDHl#)tRgL)]c9|R9^5_!!~*#L=* i ϶C:GvG(ǯA>~Ao$C-ysOW{&辉>~3AeF)Rkm6_ꪴOQ3;xn_<]6^_t^x5yU?j$dߒCoA8 bzP;JhPX4 ?`.`UbnL薋 ;\x&Ob7M87ϟ>%6g_=ZZ=u`Aþ}畣+{7/+aeZ73vwy!x{|m]|;2jú#NH ҕˊMqIRIT`ՈQ{ >2k57fV:/zPp=II=g4v'gd;+Ⲭ Kj"-\MwZ N-94Iv$g NUR/W|:b[0="nIYJ\=5/di;6205~p}PHW5O6*G;&1:n_R26/%Hg V7H1nU*sleyQAбT[h*"isNGL^<Nv>biʌ3S%ԄAFޗ\IQLfFI&4aA~&.=3]H ΑdMQ9 /LQ Ã-FjY{ֵyL\MwKvx^dbRtˎB"Ue gGFuCUuuGџ(%[}]_C SV)`p*IYzQtdSGMa ̬U?5K%X4 # phdhcrybB(o$Lq"4!3=Kԯ<%yJ3 #*C5-%Be!&3JF%k'ti#C`[LkӬaXqz,*sr~etzV`quO=' Y;&x X%zib e-A{rV9{Ͽb@u)v*g,}vY\΢Jܣ:phV>n sUskf4,*t a"8Y>^\NA<$ġ~>=^h珝;;PKI{Px)'f32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/artifacts/d11e38c2-e1a3-4e25-a08a-8c226a7890fd/VERSION uU0J,J,KR0J+JM-/ʶR02033PKI{Ps3fJq32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/artifacts/d11e38c2-e1a3-4e25-a08a-8c226a7890fd/action/action.yamlW[o~ϯP])ْd]춋CQ Ɍ%R! Ώ-ʱ[yp87~ N@{=x{V,C~PYtѰede5ka};L u0|& }0_nIMy߼#3$>z5ߕP?zجh;lM}q>?{i,T4=7(Q&z˯__Lb4glĢ y Kgm `w(أ֝=>28/6i;,jv{A)xeƃ T̾fQ3PοA9Ƀ" J&8)C_TSoosO r"`]/5XEvp#̂d+kЊpLjű@c%I5%㵺蝢W}0(Ȯ w UeӰ"k'ߞ$z FPQB, áJy/g5΢4uAl<b9TBɴфSS]|Ӫ%4j y.b'^;*}0i{ľ$`NH n0RxdoIfRL \_4bSۭpiFA&h2=5@uS0>7ra77JQc6D)V13{ړX BK6pJcAVzFۇ[Ф$N*}iÉfQi mL5v@t/KZf/E]aA;ʒYwJQB۟w{}8-+ܭ 7u '9q" 0L&WK>WC`p~yH$7RJ !a3yy=lS@"t jjn3\o摘#sL/yV~#HլVi9!(M֎-OCW4ۇpX6юm9GI47)QG#8B1(ƻ&02 6yRM tuNÜV0Iz:ZwO**Tad)Ygd:7YCW^?"-I.N ]n\BRbD=dA jK#蛡fxU ޵Щjddžq*d1b@>k9Pt,(mABHh.Boi".&!NY$F/DTќJ0)7(`a~1UҨ^曨dB 5^(A;Yqў]t"E%x?vp#|䊛>9j 57O] G4mi;_Q_aU׌H巍⨄6+ mULh}AcxTTl`]ӂc.]hj@ͷ%TthC1$K7ߝM2"QG,v5c&oˇqr[6بt?sq2 ߌ6ϐK1 J2}dH4$B{ d~+0]AkC}$y|>| Bqxa}G(9ˎ"9ce Jv9tԻh4n#xɺZ^>\U$\ȂsiX"Fdx7t 0bK ^ TdXiD-jx~6@* =eB%(1,LiM<;Ily \AK5s}|D䓠roK4p;W\~gS_x`*l $q96F# =D Q!7Iހݵ25[x$ ZMz^6MiѰ'DDJ}hb*c@ưbr JA*da O;x2{چwHC&bz`H un瀪ABdPs~e Sw(fx*wC\Q٫w879..NwԸ"oMTlbK]ܩK :R$S1+3#pږ^V>/zGLT`;5Y9Lя$K TN]vT!bЃ uoI=% e4%G kzjny^Wfz<-n0H6!㲉^_hzqQgMßr`?f6CrOWgK rrkP[aW/C>Fbj`s=',׳Z rHtiݼ_tx45:|h4[(Bõ˖ Oˑpy Dnr[lH=)+\8+m\PSVs X~M>}tqV$ Y7SEb-a&XϬb_e.!n=_i 8lu4o{8N3/XC?VvȜ`KݚpNW ۝RƮ=k .j79UTTd6)cϙ!`t:}t/6.kȬ%([٢ش;>%:- BSӚh:vCBԸs%[ӌ;Ko|x_9ilpk=e]rT)C },]bQfp凭)Eu.!^~5>wPKI{P,k 232eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.3.bt2cd```d%@6PKI{P*h8232eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.2.bt2yGYR ɖʞlIHvcd/%1;Cՙ2RHP44D)D(t2|?u_uoB8&ڱ!U>ABS"*9B^4>Ȳ!|,-B³ B813 8 PUMo!d qR_C(PcbqUyBiN7o뙵YC]!\3 Ca2Z֝SQ57(lSpҾpGu'._ޯEHGq;U !=(BL7o74q~ouv8_q9>hBoMj8 =7/Y}7T !g kI]<?埋tggzx/#бZBIz-ʈi_z0Wq axn~eptʄ?}]<_Ӽ((ԇ]?F7Q:*q4B7qn>vQS?mBi/5|5pGDڴ~~xv.CX Oo&|+y6ux;/`ިOafv<0g;ѳ'im3r^UkkhA~㩼p/R>zϺ>w-ie=>.1Hgڈs8mZ?yGI~퇫k*OOVqoq\Zb:ՆgoW<---YFE7y)ן|3j~*̻}ޅ.,.'w Y=-E ja]eeY[|0ݰ,=/˫gK}rX}&|~ ởw[ۢM|br?֯.mE@lᠣxj3q /x^OggsjnO]3h/??ϯKcL3<&ᮯ''[ 菖>O}9Um_/:ۢ* *.Q!\ynZO읁w*_] zaR-6g#: ̰#}?adY78*v_Ƙ-m]yj\_DYOx qg1ڡ|C_q6[O\x|<+2G͌]Uq[S#pTގz:ǜjWy7ސY]/I:fz ^̈fgo{VI}*yߏv}QC |^L%}^Nq?Z0'1n]E8ػ\96u'v0FЪS$sjx͙7}{{?e,@}Ol5_YߛNއ뛮Gr3#-e]'Z5_]:O9beޝrʯ+-fqbRC9xu%F[}WK̀} >Yھ 6郟XuNo\| s:_ "Ζ ޥ4Y{3 y<|84iִc/{Dq7ݽ=_5ci1ݽn>E!A7{-i~H_6WVE}[#.p6z-D_&ܣ!k"A~cf4Dsk4;<*ba,᦯}o6DqñW.j1YBd5K7~ E ܾc]H otÙ8w;^c|Uitzߞh~o aff$o F$~ꊧn\o|wC+:OPP[^6a7WxG59ϳj#لObqZ; >OO}zbORE蜍fݯx˯jв:k hxŚ)RŁ8zwc ͎Vմ}f"qBQY}'"?O˙l] 8 =`&o 0|h}pSGx)^6Q8cI5މ!9Gx9%OuW5Wu]q6t2ׁCx?0O`lr87`KEWUX{Xfr,/v;OZ_g4:49]ԵqwH=Ca0?,>Sx37{> )cfo,xtI۪8\ O6vePklJZ^ }}o%ga#Ms̏_zGM/xHi6O+"f}S^k3jطvW{ d“C=_yp?G9{d4|]{ߡtEsT}b]77+֞⛂~ gqۚ?p[N+0ꥂϯ^?[\^v2/X-y|"^Y[Ry _7\\`_w뾤{ZLg)ίUq^_'+ag,B5T5΄Jѿ!ך2bGe]C5oY۝1WאyKVY z^qK.ߝx~gMuW~[>y*(| z`5|wzOCCǚbطOo;P|'4_]s؇\idoa){y}υJtɟ FQa5 ̄iOVL:a1{"&>QFjMEn6?۾/iZۜτcfj??sնo+})LR<#}m?ɰ 7S]b\aKEY8h?!~ᄂUG4\\fDC"ގiUmhR ޽HNX>$F}#s oe]s-cA}%KU(഼^D(N uLӝt@9q-mmq~vĨyX*+M_tjK4Km臏vzkbq[xޗN/'냇镗WC4$m>O˷+̓+HNI[&zp>N囲t wlgFۋGǔChP:ksZʯc<2x6GL}t>%fo:{otkr塞?PKI{P*g/>(@232eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.1.bt2Tm%e)AEE;o[[$XBAV%>go.|5;sM p¨ t!gGǿ=¨A_Kde@I'>['QΧWOD9U}xҕUVu 3Jq@u"=.oٯ Ʊ74AS*jPt&avWFO}1)7;`Z>ƅUxD.w=/?joJZstƔ#=?^twW] dO֘`7.aa|4?4pHYޝD.UO6QaUcf/tOz}gv@4*Խ;pNP]p<<oRukum{цs;j?k9F<POX?μ>uy4RR9Uh;B.`g5`D&C:_s395ڀYviv6;q)~1>C~O^tߢk>93pIB a}OxӾL<2Vō?=>h{I~U~6XNJzЍcmʗ;Hĥ.OYpINÜ@N~Sw~~^;B rϘl~s# 6|?#˸ɥM\׬Dd^Uy,vmJ(6< E_.xRC¢:Oy7h:Y>un$ᰬÍ9h RR |ߏJ:41zdV^Gk7{euN|64na=gCtyT8aH~_#67&=+/]럣xx7h¼O|oNn G rDv(al{ΥClv,/=-8@j]C]qzET@O3+W۞vn|،tп!fܨ =ؿ{wT [lqicl][ۚyχn0fU^  u#9j݉;vtTq+QIy :Lpkۥg&wԠfޏԼ#&>q>ɱ䧣V%z|w@? >hγYOT}Ͳ\F[Zh EK= 9< agدh[ڏ!yͺNq-֥;3Z}[y4dpdEv9M(+mP+}w8,§{+-uZuLs5oٳޥzkX^ru"4ץ߻cFWI1E_Tu0`<7m ݊Z~:[1pkQCKC7p@ }4?r9>3{QPD~s|[ӥtVQ % t' 0_ÄP~5Lt^~uOEcǮ|Iѵ&_7s E݁ \;Wc#Zk9]f9M;ۘl FpПb`׻^MlVoݦ羸mc=I!67$fNU&D=> z-ПX<#N8k}ؼ Vk|/kojUd-~Ь^<юC42p>A5ggzUeWXN܅L.)an7R"Is9&=_7zSXA_fʌ56U  @3.]̒Sy<)蝡#=t&^+Jmo_0[C:-&jSۧC+yBA 0)UM7|@_qϕ=]xqK*my3KMᵡ`荺m8hZ[+ ~ r t([ :r܃pB7AЯH76cꘗۦִ[)03!V#Pϳq|NVbA튯^nzM-WD\?{I`HfstЊH9CGȿc"cl3pnA0zN=nW]0VVg Z{y::٥ܯ48>Aj_{ U}BCuX~[=R`SΥVMtzp?Oh~ B_<=of~~ּf+s$inB4+HRJzhE:1?O~u^}xW,:#4̏}j>JZ6Ӝ5n{V9w7{2'BzL{}-NǢOrބvsvwm[+nM,ks > -Y1yIݣN^`>ӄ6J+Ėv,>A}ewm<ըn/fQ{:PGGӵQ?:K6D5]#kXVp"PdNTH[3*׏سyYi miB"~B;n/j9$M^㴥Rj[desY=lm5KvX.*׳mǎ3 >[}މsCЊ~1[(6 q {ly{NfыvT>ڑlnQ 6M>y ohvʆױS y)|c8$.ub}[ۤ(k C}:%[:Ӻ *Sh#2*~%,3Mr&@sg8s݅A36 o3JP}m۴pn|oϲM_cC#}a"3K-{<*9$W,c#ef9DE[sߔA '}yB5b[y.6XG,&̘yD+ 72k7k̹ܻB;>}Bd@m%N6gHwYȄf9' qWkk_rnP>!nX8;gŽf)+<y--dVF$ |_@{ >,^(F EcAzmb -PV♝X*xթ hUf &e⎛%F:~,pIV+ "r Bh?=wñ/%~g‗X|ô7e|G_**Js+GP};Lo :persv8lH_+'鏵[^lO`vm+p:Ev eAf%ecAIKX³͙z{h382K|Ϸ9-?;<.0:?A:I(ͫr E+lj; $rEAyNi"SgIYxU'^ G?21w+<~q'ah^l(ciik^Y2 OT pvI.~=޹]\ƯY.* Z+2N:gD EށKfqik{u^ V"oBQj]޷J]Hh;]*rګnڙu>z٣k?}OgAwI{ 9F%Yҹ_2=">7#ۣ@%ͬοsW8pt+HZ[@t eqLT~Yhg㼦BO]^^:GoBGB_ RXf.VsD[ nyf2= 3AdN1/}`RSTwBYn-x:N ^2:,Ze\Oq< }ߡO>9| qy9&fv'zѷ&<{/{jōBu`[aڄo kb?۬ e}6pkøPQ' sYzuA]x [N2{gH$ CtR* DpA-Qx avR;+c&F^8eT-T(8&抲z9x&V[$5L=G׮kC=? )USK͏]Z)2K /MikŜQ{!,lt\;M7\g<ƚZGjYׁ9iwsЗ],sAdWahNZY%ՌJ|=n֩H{KOrGA ]{ɿMlQ8zO '9fyQ^Ʒt?mѤ\ |aDE|gY+_MRoe~>䕟^bI7 Dk ӡ~9k\ ng^_Qf#ݮ߇_P>,*&?<Щ^ π/QuOMC yt Yeyg-^'/|}){yWǠ )6HX,Wz٠3LҿxG϶߇-?тV]IЏGQc>O_ro>ƇGgy.qes$k,7M٬_i Jr{Ö\Vw[1N/ r֪pbMSRL?l0h;RZ[:̮ɔO^nܽ+B 8`o~<'dz_sdU  Wj٣_Acy >r"vi۟;{K%`Ҁo[X/v.ݮ˳ѯ c5rVo5kf?ǭ49cEEJ}0?? /YAx1h|%u}odU8av9>gxm^ E?ʸM^8^ͿS#B[x֠`ki6[f$ 6HYmҩtdE^ ec5 Mc#Yc}vx1y'Q\?uU?V~@_Z~(Y_gExnwpOdR]pwO':oF5[# MUx7wX7x9&\{wyQSt(u=ڏ:[׶t\(zπ~ Ӄev>)WNl~n:ns^H;wZ: ?ǡ?}\-Qjbr+b | :OӲE"ʺԫ_Lx_ } ϡ'z_| ҼDF`_dI![χ E-ASJ-$v{^Ǝ },P;?jTaQêlA{`ݷ@ҚI s0{e;oԕn2QSڟ'3rV_v/W^ya$=W?xΒzmLL!)AVt~ u3σQ ҝ:5^Xy>in}rkO^VnnP\^_@_>v _jlu,ϲʛS\sBϰffLmqH[Aoe=>57a㾪ObrV,7}b_oD}[c?m"} mxCw]:0`χg {.~[&4~-ZhQu_z~qyЧGo]k4g: X2kq_4 rskWmӱ9wBrNԼ~{Џ^H*/hۘ_6.J~㝳Ή vUJw; ?}$hw!Zk713G`yΆ%nF6>.n`oBz>qZcfxy8x# ~sn}׻׫BwC_8U5P-ݦ~п~^f[J r1(ZYW-n^,/k=QE~'z-X<“a?A'b.3ŋ1]UhlE#죠w>C1"ln ͮe_Rk9rѼwcwθGWLB? /ЧBcv쓙",:'Xzyo m\+v FJM \zu]`m}ؘ(} Z<֫ޞgڎ#o+ŭIW\z,r so}ަu[??#&ݐ ӿ6 X?m.r0C?M|V@ϢA>ۯ-\6YQ~cEߝSIX%{u 5蛴+y%~䠠agWr_vEY׼E2g'ُ;C]p0rs_n5-V92f7s.|v٨e?MZGOsx}}bLjc6?]Һsc'-﹓v bOk-6kG_w)$Nw,3ߗp [ɟ &O_ԙqͅɯ;Cz?OB՝ȳv=ی77hPgw~Zϴײ%C?ЇTq-{F8[M5ɷorٺkf3%v달5;}}XM;4p]RN[W}snźn9:ypW{}O} wg' ƊAMDlVNv$4aJ4IsZ{jb8%p3E.X$ 㴥Y;xƣ(#C:Йehn;AѤ'A/)[>Y?gX9<# A!` p1 F4FOLci0E1￑$k ͤ,f1G/,b -&i B@Y iXd+VQrZG2l#`p6Ig[ ;%nbh?pజNpJAYg:$\S$C.RpI(9\ƹ"U ! N DP mIJL4K"Q %2$ù/FҤHI_LH EOUB^+,^* %0IbY6>/8_ໂP ' ($2H~J&Š4CQ)R-e!A6 =1`9C#`L`B3X:gT@-LmS Dz0Iı 6R4C#4I95iN4jI=Zɡ5A.8aUEW`NB[ ڱ'ü0ƇRt` _:b:!Y.+A75םz(Sp z> +E?9`E4H `855RQ4-1q /$&K0EMcE d,3G1a%YHEJX%4 DR)Y#v˰BBhRVi U34z9lC6dlGD%vPFDFD-A(ۋ٧R` BCbGH:d(8NpB4; gq΁8ĈTs\‰2K]AUa4  @<1I;ܥ(Y 4JUPE,!#OT W4¼ƼS6NoA.&#xdT#g5|7 |*B& qSNP,AI%(A)TB G<-%Vˠ*,QUzjH_(!EF 3DEL1f2TcPu9Xb1uTW>%h 5I Hlf'FcD5aXS5# hI#{i *Z A 4rgi$n$ˡ P'Ƌox$ȡ=utTN8 NWΐ$i2_ADA?/ aL!h(P4L8#2RcGAcYjI㥘3a%*4 W"3*`f4GJj.a>E B b["E,%XF `9V0 Db¬[ ֩4 A&p6cU!vv^+1A!1tD :N FX 8˰s.F.*A沊]!᪆Fu "De% !-'FIںCpW*1~%*E: 2W@&x(#1'*g/RW2dk9![\"HxbhO4b_J0P>R H%%~RTD?U+[I0 SSQ8:R鐠+*bTHOUf 2BH1V!3j$U'SCjH- jezR'cӀ$k٨XCL#1ld'5)5#h.E ثVR8%ɑ'9E ƍeqʡ $y`+L+N7]~= zӗ~ 00 Ua . FR0FSMP`Mh *4Mg fcP3gIYh! ',A8! Y5 ['zP6J%Df-r؊" vN.[{T*Ȥd81Qps਒8'I1NQpg$8 ΑpE.(p F UxLY& wLR(R)H#) x(#<&O2/+9d1{CQ6r[1rU$Ow4xB((OWo2|c HN!(")V28ebc*$8- tKBLU5'>@*`1DNr2fդN# ԐSM9Ԣ6NDau+zJԗV24 Q4k$[! i,C4I͕NKKJZ@rd *rb!pmЎ 8jGA{1:P䫠 $,EEX7zT2~RGI"P40XM h(*4!4g #bS,73QIRL&a S!t0CN31pf1 c>0h!XJ PNK%XVaV V &HX/P6RFp5 lf J%3dvU> !qQ) bi!8'ysA4Ep 2174J*2)(F Q$$ER$W ܗ"&i, A|2+TC#" H%Şrx^(kC6 [ ;AhAb>|V_d!|PdS! B R~ V)LUB 8UB䢍%J%RU} f#)ՔLp) TZAhVQ:BR]5S!>"%V   XA4 h( -;95VP5E QZ$@kA5P­dY Q 8.2j6R!䮠Fk'r"ɛGN핤Q4ә&]I?Q/PopJO83HM Fcr#4AHFF1Ìbi2INIP6! fH0`f+`C0sFX ,&`q%%2 R3$, 1B0+JrZ1l=6(I(6&F8 0D mb+]م Hg+栒D;Ǝ+NRtF%8'y).HR\".+$]U5 + 7eEn)Vh/CR$C$K"=%OTb|d@Gjq%)x2d+Lk02[#;$|#E}NA>P(!'/1YfUJATI$NUiQD:$RTSU= (011„"SMI&Fu1jTSN$MQ%I`I 68 A# l`4Ěf4-1(r8* pQ!Wq-N;`' f>4i/2ё&:c(IW9uǯI^8$ }YaD` a ScåF2lF1cq1`2RS3LCXe: 3*bcs4F擴ERE%bTeLX DM*j%Yf"0W& jk+Cv9$E,`/}4د"0AC :9s18 DT攊F*329WD%"YH\*vPS7)!6N,Iq p Cj aǤ4K!_2 {jIY慂^"RPiAT AHުX@T|`,IK%&4w%@׏JA"E,fAf1JA(CAAT$"?]IIWMTaJG 3TB1LԘ)3)5@54`X jJPK$Qu IQ!rY11624*f'Cc4a@S5LJԂb+I+ZS pY  VC4<9C%+FG:!י.@W?ԝ=O D2,қ>4 见)3A4ADU2I#ŰbhJ2Nƫ ,1iBd%m*CiB I0 AFHF6c>I B,b-!`A,'a !$DdZaVWbkHXu8)ڀPBi&F86fmVD-lcva'v)`bEb"pHcHpTAq)N`N*)N8uA.Ip ,,+,pUɮ1AM9Bh-FF*X T %Hb%HQ=5u Ai4KY| "X!xTJHN/C~ШP+'2PLR5R&F9©P"8d&IGItI'}5bc`")0T:XPaLM$AJ]64h@`M`#FC 1) MehƠ$YK{ZaZpH 1\A9㴥J /V Ԟ+CG: "AW)Hwz(OCY/92Q?c13C3ņ0\A#0F1h4QsX1ƱJf&Lh2 J1L )f*`fa@ ̕<5& Yh%\ fTjJ$ ˆ,YfúJd6@(F A8&5YlQ, ];&H2{4^9c9Prp%*,wBMĜB%;M3b%<5IE5uI( .W2WskJv Q7sX9!#A Q4K&HQ{8N r< c$)sfirc9b9ð4:ɀ8(R2\QUp : T[RD#m%*xLI2$䎚+C2 )j T!R3 A|12%xqHK+Fw)18BiRDO/P ~QR(Q#r)!IW 1L_ F8&nj$sưJ`Tj5H j1u$ˀzRWh 5ClhHAJfGAc&8M\35Ǵ%^Hh-2̑&N q + ;N[ Ǔ/ox #èWЉ!IUIѬ =S@O^*S_c@ &1gCIb+ bdM?bUqbRLc(h LLcL%E8sh.I(OBE'`)2 ,rF!rX%jAk5:)dA(H&F8 p6lblan J_I"0qISgtVs\r.(psEk8ipF7tKh1b*"+Ia$ܡ]9$Hq t 1$= xaba% Y2㍜Q[UB{}`G}(+ 0)?eeEB~J Ӭ hP @9 G$XuF:JKATzJ,`$F$  0ȂF5jZr-E2>M,J5Ű `+I%k Q\15(*A㴕<IހS1|q:*Y'1:.8]I]M Y/>J?0A J0L F(`$F4ac?`,'x9LPbL0*4)4efYs \G8 X(8$A0+jXn5 Zu2c E4F尉`3آ[U`٩bHB{>AC%81DG uaS :-΂sW 5%5Ee]!*MIp]D#Ahs[XDx aD$!a*d)*v!, Mt12hWL)h$<"1 O) x^%IY5 oZ[)rƽCHH |SBPDO~P&)%r%H8&ia ttIz ї$c` S5b&9IՔ5ĨIP S[:8u ,eb@ 16rh9[a ;Lc`f9 -@K15D+ZIX 'sfDa hh.A[1I>'_:*A'9uY?M끰H zWr}TCX? @i Ba`x%4(8chc'x 8Ud ,4ML`?f,,1!ƛ$|9, "-c8KLX$$!%VdĚJl4zh#"0 W3L-[ l'g~p:XEHqHb!8*19g'qN$Q8GjN.jK2D "U%&,vCA7+[8 Qj Nx)@I;8wY YD{RHSC84Tx@bN||W}e?m@ ,@P & st0 ' D"I&(j`\l8kA<gDIT%"ؤ$&%5!>F J͠4uP: )(D(3. EY] !9LIA.0,Uy (+3YQ*H * J\PSslR|Tʨj.SCCMQ- ̨KI=ЀXDSdh!hI6c@{tNtU]Ttn݀)c #٠?0a ,b& 5`E)F2nF)c\21yx&8`&aSMU1Q0 LEh怭oc|[H"pb 0fEF+ Xi*ZfdI%6d3Cpb+g1`Mv`. Kh0c?d :KpINN+8#8+s%.tK*&.sSm.p 9=)g>^3^x+7փp=F|O:O `/Y_l 㾃`OD? A|"``Jp`F4)0  K"27E"XEGTDGD.#6@"#8(  3#1$9)@C*, OtJ# YiH`JVdd'C9ra{y6\S,+ȀB>QXG_)*NJ-J( `2+ *(oR-2EUtTnT0:F Ք@ImPJ44_h)%-jAYKV@]k%Ў) \%= Ɓ>cz٬7ج|?@Q6!*~PI gFQ0Z0Ӡq &0ѤI:&0ŀ &3 f0fY*f0f2l`>xl |` KlAt,h kX'Xb 6Ill1ah; إc{8Wbhqs 8L舏8&8N%'Mg=% .K .tE檆k t3D w]tO澂.xhG6ysO]F5M^ykνN=Pc>2E>􅂯`o|Wà:~&QA & nPJT%>AGD07"(>D-A(X6-+!((QX%IPrA RiHm4 HgȠ!L&2d1( 4)ܢ< *Y1SPIA)VQFCY((FEpL%*E1-a>Q;2(k̀&4i.--j@Qk6Ж3Y4tN&ufLMWu=XO ԛ>6Ǹ>5@41Q=j 6Q=`E#qFS25VON'0AbdLaT N/6`h&P7K0[U0s91 -`,f,`+D+ Z-X#֤u AlfV6 ᐝ&"ۤ=}6o!&pvpNNNN;GUq1E((sB*k]rà[r۠;>uW=`}zzz,%OmL ^^9 %o?q콊:> >YE BW QA??I_ * FAp B@kR8wQ W~HDhD L,b[<+( m@EBQ"SPR $Rr$ )Hc:҉SACFQ& Ȣ#(rP@.r# ȯ TH"TTTe%Q%eL(kr*3TTU fRu595Edj[PǤ.Ǹ.h j(HԘP4i)ʠ2meޤ2|D]E(n:zZKCoA_Q?$2dhC8b867#QT@PP!qPQQ1'P1%RJPZPPYAyJ**WfU=:E5,iR-BEuTW44FkL)e\A-%ZXVL{:P:DB]uttwY^@Eo`NJw C(*񇃆 !I(1O1`C&(H`0e2)@dA(/ LY2sd患 QZ`hhAkLXku*s`6Zɀ*hتbI)ءc.)c^ _E)8㰎#>rԀc SN蔂 ;cYs} K +AupS-v w5c}B xH#xJ/R8ୋމ޻샇|᳆/|Mw~: =$0"LHZ, +Π:"&$lRQ@tb L,Jbġ(.Y_"XD (HjA2&ԑJCjQKKY: LLeuI6&r('ePnNYUPCP‡JH\i22e)(g 620j5-ňQ_CAC44fLhf.jaRKA+ m jv@M{t$Љ΢. REez8 MQk@?7h A>6]f(5FHeh / 4a&&l z4d :fh 93Ss,t"XaIC3<+0A Ɉ@PULGpJBXCB1"Ȅ {@DA4D1)*]G ĴI," e]@& 6J D2$I)MJ2iVC:HOQE&2Hdd!)ˢ:PET7 2 STĀ3:Jj((Ǩ RQTɀʂ* TꜪs52z\=Q}5!%MjDs-<ϴ ڈh#:Qق.jn&`\O z z[Ї1}e p@ *w ` 1Fz( FXp8x&LLbd)L4ʦ134gCfKQ0C橘РEMX#K|d[ZcG6h#C6 6-ʨm)&]{u>!>r18N8):A3CιG\ qY\u5`u06n&Ϲy%]jxfs0%WK5o8Cl<G}+P ?- wp,D0 М CIX$"070,(2p- JTP Gbb{@Nĵ $%%R$2Ie9()4&eD:`QFL.L(e!\6 yM AE)*fBq>U <4p, UK*gU6EUV PCTSG-ڜ#z4XC4bHc4AS19%Dk6* ٨E]mMGw zج8ǤЏ `hwCEX06# ͈1UA|bwns3|W ;~a?_   @pPΠ&EQDF c"KDJ(E-!ɈX-C(8a P"CD&)JF(9RdT*K͘4b^CB=& LQV ,:r*#ky,!a4La0(PU U܇JP,)2e(+ Ԕc\y*HTO ₪ƠհYMԢ6%uC9>'8!F֘QM4A3N4iiB+ Z\;3t3 f\CzO%[Ar_  ET  !1 7\bj$F) >'84&Mdd) *1kK>36`lP5DŽǩ2 -,,--,rTʠ.XøuYbhMل-jm6΁&ұ[hE=AC>tsG@QPu%)9) vZ6;Lj\EBlt!WT\k]7膍n-6 6z`*ycSD}I/mA 1-ix/ I?>H|aWB8'bu B($0'DŽ(M 'P "[1Q9a1 T`XF%OA| 8PC".H¸6KfQrΥ0!L*QjAFe((IEYtd5 rӠ\͑< ,( QPG! PT\ % 2aD9 TT,Q@5Qu25E$j0.E( ihAM445Psδ В$Zÿpc\u::ؠ PՕnun7E}ׄ~ (d`! M sl'Fʌфl:&(h$&%SL4t[ fZ4e _c`-0`hC!K,,,7i`%E\Zfu2%6Qf 6Հm&m7aMv:d{4UOb?t!FQc N94g΀s<2C*nnZpˤۄPv=){ xHE x⢧: /]k(x+x|$g_}Q?D?Me\ SĤ3!8*Bj 4š΢c&@dE1)E18ӂX>GC\|AQB$EU$%Ց̤ RHH (Ae2XQI"AY$ͤ*r\*(+'/*`BANbXa)P Q.(ɘR&2&L9QUU,"s$jPSE-vAX} 4rXck)hA--jekCQ[iGA{J:0:.`zz!E},+)a1 1wP0ܤhケ?m6f `eESLjikKoN͐iY&̶hU0ς-[,-Xfr ZEj 8l:s`eulh-*:` dv+㒽}.Cpq q' :ũ gVgU3< .Rte\156mw=E}䁊>H1%O(zg /= ^3⍋ޚфO|6 s? # @6 ˂!! G k@8pExDPɇ"Scamf1H,-㐸 3 r,}"A8\A RR3 HSiSҁ&d[dL6̀,-,;r@N\.c#_ "b)`QUJEi1TtX%*KT1jؠjYTu  LhQ8ӘSM\f,j-V.jcR[ yD{AuH'J:tIWn.ѓ^ z[W6,3C\ECx0NhI#E5Z΍Oƍ*KLpDAES4LLctKfhiY f;hZ0[#jXK5,Ӱ܀"Ak2Mzl==ss%W.yͰ7.x˩w;O|0>3 Pc)n2q)s&` ΙB;ap (ZD~sY$DQ]P,Hq%@& kHJjA2%w@  HgA2 4e&dTv rX!46)"/S_PA)+DQaE׊Lq J0Js ZT=c*2GTPET1VP jpjhz.G5UDMh¹'5gL Wǵ6xX;@QG:Yل. mC'pz0/~ =dCY0aC(J@pDF(Ѡk XJqLM$j2pc X2'ytp_95Lf`h*1`>P@BN-bbRd92+(ZuZ6P6)ll6llG^F~JPvЂC#蘍 _p'.h%\fWmv!Mq7mvKp[tDŽ@=}==`@3}^+k7w=hO6 bW8݄IA@\ daPP`\C ! Sa( kB8J` h,E&(N br(b;,Gߢ6HDĢ$I=(Dr )T$&1imN&%=( 2$ 0/E(Ȯ!E95-C(/{)+d@a"+j@1%D%)+EAiIy *ilBi.!iR-&TGE]cD}55.hbPS)h.ӂ!-)hũ&/H{tтNu.un6.aBO z-〾#ԟ  "Pl3!94#eF9lhOq5L`IsS7[ 3 Őق9&U1ς-pB- Y"T2rέjVʤXC`:mlTIbhl"[F{]O~lpXpĀ;&8.qBO6gr!%.(h%eW-&s)emwvW{>2Ld6!l]"CrZyuQ> 3e]RHPXTăxP12%dJrDi23I(:&QA5 !Tעz* 42A,h6jeAkUN:t$I٠.]tugHzRK7>5 82 l C5!34„%cI8LLbdLqTMAߌIl1h͗X,ҰXR-Zᰕ&vZ֙lQ \![(٪`IMaN].٭bO~ࠋEGsL8S.;-8㰳 ;<%((q٤+ং[:螎*~x"x*̤{ `+xmo-xG{ DExgWJݠ.)߸@D"( ( ,edFe"DV@T<*D Ť ؂8 H#D"JlB QBEJƥ LZDA"L:2TjA6%r!T5! dH!Ea!TTG1Aq JRR W!eL(S((π h@%9Rŀ&T.QCT'jjcA]4@G#6jiAT40%cZZ{PZ!|N::JQ7SÄ2D?B%hÃ4\Hbhc'ZȄZBR l\ VjQր&mh4lv ئb2vlJ#_tqtEG$Rr\t%'M:%8!g$8\TqItEpUtMuJnPrS-m 8G<)c\ $^FoT)"fw&$1(0 2A- fPp!A(JBk  MG$L GDt0,Cb2(6⨈+O_; ( (D )mʠH#V"2(IAf,JY6Av 9\Ӣ܂<*wY PHEa"Iu(%eei(OAEUb@ePTETE5dj%Qø7RH1M6kf0VZSƀ YޤtVu5I-aQO^vA ~w OD` _nPa `R0Zc)  DdLʘi&L7of:l #K<͗X PHb%,%L XkuXc`Al`[Evvk>3怎2vc.;n pZ\rE]Uk[:n;G5鞃SGF\^7y+@{F|TɀDA`70? 颀|dEA)qA!u &asxD8Qx#  Q|&0"h)eآ8a%H(HĹD#4$7(DJf4u@:w@e2,3Cr"@MrJ6(/cB9TDEQQ150Adh(**h(ĐU\Pe\R5)eRmԱA]Nc@}5e4Thf4CZ8%#Zq5P%m)i'hoRu.ttသdz3>OA`4yp# I(a,?Mg & ,149E4ÄY6mͥ`C['`E -,dhh&bjN1i-E_]M&laVd'vZ%}`O_ %pآ#'qR)N8,Pu6` ᲎+2Wẗ́qq q] se]Hc XE/蝊O QEWo6NO HHE` 5(!u$ /4DL(D4At1bisqq ųY|$THGb$$K#4.H+H'J#LYA dcPQNb@ny, ɯE)(ĸ2ElPԄbQ&%,(-*CD9Qy$**dAeʪ*j .Q jI6u)ǑiDSSR̢ ZВ#T6m%1LQGtE]lUMCwzؠ^z3E,ȡA6,1Ġ)a6θ.iQM`S4Τ &qbS,j4[E3$f1Sss)oJ,"XR,hE+tYm JlFB\٠-6تcMvɐ]{L+O_t@EL:G8wluLq tS&v2yU\pjF MpDŽ2U<=XSBLx΁4镂x#; ($_?*wd[f?) HRD"(e!( IuQVG8W@D`oDQd 9,L B158&uQ<7(H!((%SiLHkR: 2Ȩ"̢,&eՐ@vY.BEy 'ϱ )BaHQPR J3 ʊʻLEJ{= &UιڔՕKRHXDԢf&5gD AK D %(ktQ:EEWC݁XTK[GZϤ>5 R04 !;C=ƨ# %1+ӄqL D`hIS)ft([fYcqh> WXBReshE+ ұZb-E X/AIe[dݢ)K{d~j8$qXRtLp\NtZt i8/ qQWDW &s ݒ 9E\ТG*<=<3Ṋz)zek(x `;y/ cg7O $̐  FIp! ) Qp,LDH2Q%)nbQۀ82qMg@|B T$I$HLI%uY2JB&%TQւtHd˨#e8 (Dv 94!>GWA>o@pY![EE(*n( Jq42&u@9ʋ**U,JY5AL-QmHԥ 4Q54As-(h)je@k1-E8^C:ttV#*订LOc@_JП(,3!d\0#T4`h 0ք?u``h"ISS% K傿]6Lf`Ed{ )ZX̑% Yf[AJVjF!Nzl&pfmVLnv.h^`I(9ua]pDQ@qN䔎ӌ9c*) sɢ˂+&]C7?n-߹C]N]8#%Syfs ^hxˡw>^GD >3 W/{`O$5/0xFQPq"(O %ڄ0 kp+=,"R EvHEh2M$b 0-, >HGARq"9(JaBJ HjHt@ #2yHfe`XVe$rru|*7y,+@~ )% qG1LqJؠAdJSVFP ʫ\hR%Ae UDU-f55rImب.zOQF4%U4YS4\G Zhem]%:Q :Kt!ԕP7*zH$KЛ}D}mOԟ@N R1اP l#D#%FmXq+ DhLU0M4,4Cb,l sdJ,аРE:+Xc)e V`%VX-Zcu>^fM25l1aES;!MÉ w :$qX∊;&q@愆 NYtZ9)@E.12ǮhFu㦍n ܻc] {H#<ੂg.{n ^:Pa |0#'Ùς/|e7?$~$sF 6 # \e!+$BSFc‰"(̈́H.,b@TQ41Dq( ēo@.HsIlTLR$%hJE(5g0"OCddeѐc!sL㢼:9  1O.+Jq2:ʔ3<*2@U\u5tZ6PPק6kLj& 2-D-}5XG ڋ:LG<.?])ƠAA/K2.``5;g+aq#,)1eH5hx6ı2&SiKE`f2n9s}bM`E 5,ńXʰehh+ujk) ($l|ovFv\e{qn?h:@A yaG(9 q 'WN2xiBgmrNyE|2W8rƸ27dnB-@ܣ྆=:z {F 6yw {/fEtÐ*0+p6 H_$SDGPL n2!%B B㰰* » DDTDⲨEcPtQ, W#8(yPb T" H-H#'$= ฌ %9ECVlnP2 DQ^E *((Ce8(b&4EeDe-*Ǡ*8UU% jhZ6-cP]ԃ6h(HAMDMejnR Z2Z;k H::M+O_@ic0?$1l86Al0Z4Ac*'3g&P2Q$&;`*'aE;lA3-elBs kS:Ե5&5&*h&ӜS-Tւ6`H[sI{ <.uY7WwCAO|T_Fn  "AC9 ΙI(Ƃt8ln"x$&Ld`:_6e3,)3 ͉9sL1ߠ-E Xl jX+9`u:Fױ'6l2h3&;\]Mh'*B!32}NJbip9e...SpSWMƩaMmMw yT=<2 #r^8^yk7&O{)ࠏ d?}fpW}?O HiL N]A?!|"D(QhBaL+@x"(oȂ(: s I1< 68"x:+H P")ILJ*H1-Jᢔ6HePjuP:@AFdґaYlUEv r,rۄ Hd@!"6)*Qf} %mT ) e,(ˑr:{TT@eU(ʨj԰IMՖuU#T߀4&ihN%CZ< B@;U,H3xB3݁i=(iR/㒾@f u@`2ԃ`h8F4E0c AL 5 5AS|b`G[A̠d&fl9>2A(ω-$HXR1b` V2`Ղ52k]S- ٤b`6n]=>ACuz1sN8eӂ3K.\\ ]fup Ő +xxdc=SLzn6x {ũq[; ǂ bW|'h HeL ĄXpAəP_IXpE8 ^G9PI"2xBjQ4Qtb(&Xˠؔű .e9@"D"]RLGrJR!AiDi WL2 " l5HN\ T L~ PRPA!Qax^QP\E ) J)(#(倚T*IT_AV5} եu4h(j%M|I R ZƀvԞ*:t3.ʐn讠'zQ諠2u 2a0ECNPa.a$FF[0F4` `*阮ob36 5Jl#hX Z(Z--Yfr+D+ 2a5(ZQUUlFlұ[>FCNإ`=e>8`A!8ʉcr'(9)q ~qΈ*8λ삊]pT]!pՀk:nh[6 tfw-㾊ͤ4)ؔפxoB%%2!Cp$ %RJiT*R{D0-Dz #2s.lf9TPnH~ATȂ‚" ڨ ()%QZGe]PNT &TT6UeD5UWPa5 %Q!u,+Q@}&544\  <RϴX;ƴj:!|tMGwIO"[ǀ*B955DPH p2#m2ʄ&8/`DM ĦHL%4͂ pNE4\t%.{]Ι18q8.Ps3t=G<㉂ @qwq$% JlRpERdJ.E) Aj8 0!E|.(̌\ʩle. $Q&0D!H* <8e% ( )%*-SRqTtQ%PT٢*`HUUj joGL+S!exDCQ#0CxXSQ>|P?REEV)ePEefDȎʈl +*d"3! );E~?}s}wxI$$)) !I$#$IO%cc I$IiOg" $I$I$1+g?#I?97|L/HΗta.RbKHzėd + W1(~uȿu\kIpIB#OtCor& LfEn!IVFv=ߞ;$kw#C;{Wbw'dɔ ~$#<C$I2_$ITQ133Ig&]<$I&gRRIt g#)< J?3s0s =$Ig306s$I$I=!I D,@?$I<$I$ILЂ$I$I^@%_b!&~ᘼ(EH$I'I$K$Ip)$#\Z2}@&xEb/IJReB̨F2LI˗Gf֢ +u(U׵yzi_#6h:x||codc$[Pޥ&w{|O kz+C>#}'%T,alV?E|k2FP趆^l?"BH;2|J.$U/i;$C+]b?_1}U(AiN3/i{!I$IHR]K$m.+&r&]^+I&:2sp~GA׻A)Mڟ_|RttC;+]L$=dH/3?LC.%>vx)3:~*Ct8kO#IJ<&.3Sa1',z6)s(d>7h|O<<OXB-,ɋ"X( _* /Lꊒ%L2/el^"V]azyV _XЫY{קkZA*:Ayx76f[ oM6oRwF. ywQLM>ÆDOR1[ؒRJ%FnG)I>g!_ю>v;kU/=$3a{Yca_R|W 6)r0}B$oPJubTmqoF-RK%#I' 'NLI)} X$ԏHLԏ}BN $ITtR3Hg$I&,g$H&Bϕ<$I>$I})/I P$IFti /#I$I$I$_M$u%c}$]\M$H~$kkv;C#IדLyCoLM sBB $-$ݪF׷+zG$I_MwI%IIw1J?|HC7>?1}I2&ΨiBGO` id̟HR%z̄A*4'CyI$S>sQڹ!|Tz~ $y8dbdb__(BfaHEHe#)$$I$I*$I2H$IRIJ∖!IzYJIWPtEJ$I^Bre y)Id/#I*$I$I**#]ʭN$$crIk $cW1X^MG$$Iא$#ym Lj#I@!$3n Mt$%}+m $IRw$KDwL{IO$I$Id cAC$0I$D2ҏLI>'ɦ$}od̶%؊"roC$oKdۑbSOT3$I #cv %I$I$IN$I"I$I$Y]Hߕ$ɘ})H*{`O&~r LJ j Fj$IHR) 2tp#IJuI*rdGGI*-2x861qǓN'wIOR䈾'iZ$@$$3?!9O1:$Δ,;Ls|< ./}^E$Ir /_<_r+I)&I$]ߑ5$ITZ$uL}\Ov&JgBFt$V1$w'+cqdnx3*tÿɔ |OA-?G<><39&O!4O,P?l%yFɴsH:ͳ$|1L3wBXC_)3̟f=b4/X8&/"%YbQ$]xHK䉥HR_Nj[ pY2!1vڮPVJV॒,ժ ڇ 6|GiB7-\nm%S6v6v\ğw/8Ѵ$_Ls@UR=B^1;>}i i2}]CClHJw1[i;8'ONHq:8ʜL%>~)P%T; ?O) 3ȳ=;A?ΉX<_8_ ,~iE/K~䗹~⿶"͕tuF ;k]\?pި&f-[v.W]--5gwA~$ڃC.[# ~X3*&mfOT ffi?0aHss xl9dsNܐx^ ,k ^a!m_fIbc]-iX/dx9+^)◐ le/ eV1J!Fxu `ʗ lM$=ER+y|ë\gX_h6 uMo|#)7ۼ%[-xڻRl"=G{oSL|0Ň\|XG|TOa3ms u>skm ^>$QcͮfN*==qob+iWx_o88ic'*y$cwTG 8&o2l; KKOD%IRId#M߷CG)N5$F~A : >oI9SV3cS_-o6c7}]??z|y(ſ a=g\"Lf6<%aOlRYi%M=bs0rAss4d̯/  Z@ pDhċX\R.Ћ%]YVL˛VYQJ^qe_jW hUVp /wfrW8|a]6r}:@ 6J%ySۼ9[Lo m!'ީ76q^~>?ч[|DG]~Lkd:L\ǖmIm`|3| ;X|<|>v`W_!)x/{e}_Iɾko8 ŁA ,~#CB>#=@oߒ> ?N?^d'N6}O=@;jIHSZM$>K2vsi.LsD4~-$^EHru*ZFz 4ק!7 MT fު&v _)]76ݓ{g)ALRp(#QL63{|OeFEfЧ4IF0g3}a3g1vϦaʹ($IR璤6м$I$I2I^HR瓊- hBB XɋEZ$II8["Œ^$I^2$Yd9\hH$KHJrH/HNl _bMJ"k E_u|ẒZk} ^#k%݀tag(o`17ӛ${o3=;qg@t4= {~?|!}G->F$CP6J-ԶS&v4Ngs}$/(E;KKwKrw{mWki8 =} ?a <\#\)(Gpo; q.|c]IdOv} ?2ji4 / $} t}QAX\%-$Y:/N2ڲ$\ d]K%|*dUIT|5Wa /WxM}-}I}euH*Ru1[6ZA0bz 7xcL$xcAooަ6]tIH=>}?C6?j~"Oj,E[Zle6mv6NUs?a_c|Ѱ»h*vŞ{)7ˊp?+j52!Kź1?t ġ :!AGp~ǐ 1VBMw|ks '8|WH:Hd'sCGO5~~vbg8最ύ"MhTB2bI/pv\ WDxeW MW~_#ڈK{I -nPdIͦ[,n5ݖSܑ;yT.[={x0#Qf\&~&fS#.& }9"3g9|6Cy\)榣*_k ņ^g `#o&Kiަ.e$yy//S|H> |\IY@°J66ۚӶO49[Rē.6nx/mo}/~_ѿh:Hѯ{Do{OďGcUg)=5H2E&pvg<9Mϊ p?Wy$7E4?) = L xiA%LKzXJ2,b9V0%KL_j)ZW06tW;XX6nu^yc7EqB߬[]-=3w?|wy eڏ>Ҧ.73lrl)h? i[};}{ ?3?$ B")Φ]Hj%ĻKB{ QiuIa_alJ42҃l4*a.舐tqTߴͷ|9'É~7I|O؜bC~.~'Rtzg؜i8Kf:ùyB;2Ņ/p%KLU_xJWMS;Iqq<|1c~CCSB/.nx I[C4wLWw7w;'{g{Hq?-C~/6<HౘͨJLlɞJRYBUbt9=g09gsLsN\rП?ߴ`_ x!#X yQIxB ْR,_b`X1x}2U\jZD\C5CZ+^R_'W \7W~^ˌچ!.mޤm,ٛ%x66pN>ߣ_>da#Oؔ67!o [ѷշŧ>s'l(`'_v6b/-.p6`_8k!:8˃ CSnsH(Ѧc\~÷||;uxbǻ81Ms~ ~d85!?4<, <'Ź3\_(pK/LE).xRr ~+ؕoViפ6R^?j[ ٍn"ޒրo4wN.tw{ݫɐQϨvLg6<Ь?/[,^hX/򸈶lזЗtDK#X\޴aE̴JZVִYڦWj^eXj9\70lhx`⍆7IqofxwDNӻlbx{MC~XяX|TǴ{Dț꛹<-B2a[%dkѶM]%tH>ϛv0|!Ŏ!dE;aW_w򞆽mŗM+k@1vp7<a.G |p"8^lN!$dߋvJ*#ũ$Nϰ9SҳExNs.//-.(-.҄^W/kHȕ \oՒVߙѮux1?&z7(~InoV9#͝]f=>M}!1}x(yc631MOITD3gC\vю6;_4aW}7ab/'/ٗWtyuC87\!HQ >Zc"&c-ۂ⸘/ )Nt]'G='}'NC }ȏ% ğO%:]3>pv3z 3g)\֞+`p>RZ$| $](z(h,Ne1[],CRe%[$ӕBz-^|"hUau&vÚEX;W~u"|u-^s=:ZyM6 u%x7&}cIlxǷJ6ޞ<靆w)n={MxP.>>>}"l!oIW[Y|Joз h;3g=~.`'vh*%,viO^>oi_5=@_`hHq92B8:#vlH1L'&IiNV{.S ~D;M g8SB<[Ÿ <ùRo@%S^(EbH|@.u@WtĿuxM@׹}?_os%S71M͊V=;TꯒޥH%G{CO?|߮;"~g )ݔ=Ҽ/d$Ɉ>D}$IGHJ}$8 2&$Cޔ4l1"-($IFm]@ۓ|gHg#@>`f`#iv!CڕĴyܝ q{z˰}|+}@Ls_W1}dF#(Hrˣ-a;$I8qd g'P%I ~ cC~©Gp8=iql?yNJr' ^L܅r;tr. 7i~w. Z: z톀nS7L-r+C#;|Ipw>~Z><K1E?y\!$c1y%|~>G=傂^@^ȴ 1V K"XT8ZB%,Eiņebc+&x_B ]%UiNZ$C_$ R{eB׉U%I_M2H$=5V u>&oIacof oIVw)bIV= 7|?ɌjJa.>O(IMoH6p 4mO ߆ؖmG*"&I )gs!~>.rǀwrňv6Bj%JI2A{E(e/__y O:=!iA&PØ1<#p$::c$fo8 DߍI.N{~Sx1]J_?v"i+pvf32sRK29_|:2&(]^B2K)2$^I *Ww ׹h .n O!$ςr[%.΄57!Xݛ>n<`#x/pᑘţi8f,)| &>_(pN"^bx̗4K܋2$)3,@]dxD+' YX5Q$I25Ҽ5y-kK _IJ¯n3פx6$=_7H7*&Ƥ昼%fooy;\3Żli{y_Wdt!&T#>||26+Ib[}J=lѶ$3ڑ'}$I28s}فvL/9]]==꞊a Tj'+6_ﯹ6pP_wx7$:4aW#hh-߉c`Ǔ >+I{iN >Ԅ8NL, ζ91=SB \Å,.4e LtkteWjMk^:?\h'6͒ViG|~'m]oq2w?)?dhhfNL!͜)b1çik16g ٦`͝f| , y ,H/x!"/ pEbx@Kd"\,-k#\A_JKU=pHr q+ 0vMHkZ xo0l["~A(4說$>1Hq'<~RMSlf9 omEߟruLmnmOK9 |_HNҮ.nqb{ '/Go|}-#>@ӯ;<8!oЄ&!HGEpc|~wxX\'<{)o?E?6D;Mi@xLt6#h:8S" _Z\hs\.hydNq+mrp;5T'CCԮwpm$f -CCS\M;{\Ctχi#kzTθ"|̬?J>5Y$$%x&m/%i4 a/LB.E$`Q sx—Ж^b˦X.˧XAmVrIVRA/s%^CG&#]+cUMc"3kbZxPEbQ7)-!5Iv AߩػH2ƛĻ-ޛ+Z~0&a?BFQ c$O2MHLV Z&Ͷv?3?K&s}^/b'`W_[{?{9F~!:<(;<8H P98<#\⨘c|3!ߊw">-N!$) ?GSKƴ?|3:+fgG3d0qy\_OtA #d'Re'(4Ws[Og$ϑ.?f@O;D$I2/FLĮ$HLn$I$bw*=ɘ%`o_&I ߗGWH&$_%:@tqIϯ&ITTi%a$I2$d$G<:c,i&}~'F|=^L']I<¿'@?PS%8<-pzppH$Hz:')/Ȅ XE]LåLe<+.kWĕ7vL5_k{Cc'7)gHr[\ޚt'_%+¿}d` $?@*O21"I$IR<$ɘ=B|4"3ꐤ<3 $c$I:z*I$)x$Ig=)l<1;IdϠtϴC$E!&I2F!I*1WsS$IdL!I%I$I6?I2.=4-H&>^B$I)\2F],AlIR[J)ŦeH$IJbˑ1Z>+H|%/aWV xU`5RYx5IעI$\'WXWuIk h|' n)ޤm[}} xwG{oH~S|8hu? 2M#܌6qLO :0mIN8\ϻA/QR|΂wvK!f]1ޓ+ |pG__ <5؟R@iutp 0HQGpLo Nwqx'Dpb¾+I>NOC8UNS 3 g >;<<_<_ R0tIYJ>~ JrU ~#j~k;51RW\ o$)O7B)nVEo#I$PN%)]-I={>23R<_>ä!)McθgRdfO9&il3$>c1g1gSP:wb^|,`<\_(`!^/BEMX,s)vb}.W"JK}PG||4Ǵ|'lf[DOvkmvm>3}yv;whwelb7{${ܛ'/ 7R|%WyA׵]P8B;R;J;Z;M[}wc,NDyR' S~~@ϧ!é6?~idq8gsy~NW;@/0EņKR\2W\ג^!W7^oN5uyߛixIş 73п&VGt"wzwI7ff>.$$<?L#1oG}/,>hvUc?i>q7Ki m)h+akŷ!-Up; ^OgBK ; a4_`g$hW&Kt7*;##!{ZEO{{Gx_~WbUx8tC$Pp$ DZu: $3&2Jt<<~?Dp>I,OHOKSg89ʞ-Ρ2q9CE 'K$ IŤӥ$h+ /WפvIaW$# T$$I%:$]$I$cG z 'o"I$3]BofnI%ܡdU.Juro063cP 1y$ ځ/ؑN<ńDb4FwxgO$Id")d!ɐLH$Id_$Il'ɐ cx 9M.ao884H W4G (G $IdbI[o;DKRq.xS(CG)4:1}pZ?A&Lf̢g+\ Σ /0]E.$K$UM Õ *o)|vP^ Lč? I?{nm11SFp7wkDtol!)HivyD=<cgԷ)Nj6SgLsx3gY< y.sk<"R| Py/(>^H"ɘ.YT ǥ$Yaed˙wIb+46ְm۶m۶mvmngϦMroryY|yk oP~[q{ Pǔ>>?}[tgW ? $ q0tarH CdhD47 h 390KF41(.Ug43CeL2M 7㪌Gi| dr2M&Aݿ{|RJ!R40GS3VΥӋ3p0#ę-ɬ 7;sH$)y p~- SXĢ.^\pIiie%\*+\W*YM:![Z64w&6T؈pcN76،Vpl\l']Ln]e쩱޲}U_<@8A=T<xxc$ .>Q$S,i{ ϴxsLky6/^ \$^u/ş1tWSZ:9⍲Pf[ ܊!v;; m3x?Z~@|С|X1 '>y:# ##F!UM6:'ccpl8kx&ЙDĒIĿ{pRMpJ,L-L3t.އ3p4#g34l:0hyt\<:i/, ,HVXĢ-f\R諥-.e]"^=z~eUoVs.YuBd6u(Ky=llXgt3h [Z܊֒m4uv؞*;Jvٙ]JC{xpO^:{ H%<@@ăѵ(j0Gi(cX8 OddS,J4tt`p& -9G\  mǗ(\ JZ ש\oF7i[Ljm/wNEx7*Ň4Fq th)?|᳈^~ ] WFu opdoDt]t=eREO%>WBK+_ |?~"/-j7CP"X28` mApF(Q\0:cxLD eal8uxH}BDDDD&ibTΰ'y2'g<ϧ$ U60i=63r6zf,6jq6t|v6d.mbԝLOyd BXE ,YKK2^å9\E.WphE+ٴ2*Ve VX5%k)u^We=G (oF7x75d6l'l/ 貝$;]?!r;=L쉆27fz`?8xKr`!.>ԣ<##)]t cQ8{̉I';tS]tB϶ :|K.BDN/x1Z}u)"2rW0,^^vÛނJ݆LnANJw)m>?H!Ə=n ΞSBD_=glxsw }+ ^ukuްmD;.x-!z#?|"T3>GD۾pKt+לo=D􏈈> ]kWt7DDDd;"D (~H60bDD9(!"2p ЈSFaX·38<:6#&FA6Fqt1<2&R ]96gl\Ji t&41ĒIl;zbRDNL\M0T4i:d6=(L蛙fxVDf>s sq00Wg>^`!.".XT\ Kpd)s.gryaWB+pU5V.YpMa-T].z7 ІLnlqMofqsmAa C;vlbaWvsdOx} ?(`C8?T0Å#D.1x'^ P"ĥ.WуW"\%Zr-uMlVá94x"zn{9E<Ѓ6?GeIw6ӦL=3>x>gyxQ+*{Mu7ߴ-o屮k='1XƧ ɾ`˾7  ?O? ѯ~w?<6H211`.HeHNRZ0&EPsx#H6Ń88:Rcekq< {lDD'Tч#I ¤d SxlJDDDa*d6ADRm 6l`ʳRM]c45'\s3ǁy5S_\Ă ,LE.FKpR:˸lY ,h(d`e0Z=5?kX: 6l(H& [PVUeszvGmEeWJvBD*{p.;Ã!8q8#!G?&.-|AW_3·w:?Pu?S F@ L0ƠlP.eCahy8'c#-#902Q8ǰ0Ccx|\38 U&b<1$>;IMLFarSTt/QtfDqfYYmM]2dN-#|'\@B k,(40R K۴e%,`NVÕexhUq5qu kظɵ^]z6THƦf67dK [Z*luvw줰dW݄e{i`/{#WO_e|!Ä##eG|ǏXdNj'HNNNNNu45Π|s-| d\s/Ur WPU_rµY^&Teh*69ĝ&b|g> >h!G8z1g?>%[gg\^Bd3|CxS-mɻޣJ>RX OLs_ƯT6 CA~FC_ 1e ?vpLapCXR6lhqaeùpx##jd`dQM2:Gc4& Bű ADnS0=1db 0;IMLFyr)8ᩐ4:C{tɌ 3xfYgŀlf'pNRpy Χ0d "\"up1,2²6,pyd+ +ܯ٪hu@Z &Xz>jn!mMm-}GF.vaD}GNvFDGvA])F{p€ވq>@@DDA;tuapT=#ģ}v ǚ$>B*Oѧг2owpM@E ᫔^c:ܐo ޷هG~lZw7M? ǁr+75>"T]Jj5µohMj6v wX.QWvx?tC F1Ǐ D O:OO!* >g49y / 9eW77ŷ-w8}W=h#Ogs|!W _SL~OGO~'q;?`` Mtil9:wE9DR9BJW^Mx ᵔc|ool[%fv;Ttp{4oŇL~-=_.zIe+W<77ަw`Ӈ>b'*~/oo)*?H= Z/_5~S]G[Hg`H51lpCZʁuj'σC(p O—WZ-w~ r𛍿3=3"?I4AppCxHTvThXq8Ë#0(0.K6q5&'48K&:)L.N2T&t6NOiqF 3 3S:YCaN¹̭200TX`qQJ-Iq)EW-GdqEZYgU)fquk4gk3ZGa]q=NpZፅM(njf6l[ڴ:PVN؞vŝ]wUM{}}'<@9CL4u55q\^rKKM\&*ղk-\'^F&-nCr0y''w1=:ROv?t݃,>><.<' Oq/N풧eʞzYU^#x o om;wx Ə)S?/ |)|\|ٷÀ6 ~rT~/&~E? Dg DePa0! MgU^60HQ &]1UƢ06l\x&'M1'wI)NCSSr6lji4%N2 >L̲YY-Fav.˃sͫ0L.BɢC-z~IDD,塥9[er˖WYmYw0^Wc:""""R[]ĵZ6n`#~cDvS6@[r5m8ۖvw4UvQŻ Sæ=(-죳#rz4yz`DzC-hDّ&€h+=9?I8S]r*"!"tD@$8Y;s}|<_vCZ]x Ku.3q9+SWyjpv-u&'AQ&7bV &GO~e<&y\ OR OSz],7K_U<:7ж75ޒMwx_j~(>T _h|I+_ 0V~"/_~o*P9   . >BaH"|44*#0QIgdFU2 hLcc|ٸx&W@eB H.mdSa*T4N+N' 3ZI2Y%q6s84\.[aJr8`Ņu,*.fqqpRXFXVX Y LqDq5.&8\:_Oa}ܐF6&܄pS )l.BRa+[8l{q;*$Y܅Үvyw&%ۛ>&5l: Y|AK4VFP{#O cb.o6 :ŁbӠ`C`HCɆ7u JyxlQI#h ǐip, c;4Oǵ8 &b8I(]2)&8")mԄ0LhY)͆\ΎdN]:7y}0/"n>Dt8_--]X\`Q-np Η,le).gbymDيWrheqp55\&gkٸl],o`6l#6&mja3Ul蓭}ڸW;;q3:]vawqϞ m탎~TD `$:񡈈aHp@DDDjG/hdzα.?Nx'|З'&;}}39:&8Wv/\(R |9GW#W:t)_ru o|~36C;5wket2{ =TEDGjO'eO1ʿ5O_4^6 _E"uD DW?f""w=wmbSF/ _(|)|[a{~@<?#hWo*Tlq jq0BeH)059:#s28GS]c 1u"ۆq30 g'Ҙ$&2)dLɔ:SQZi)O2 3r4EաtfG98\%0WOg~ "X"E).&..[B\Re,g`y+xh%+sʪ&VsH4u֑+Y}>" $yxc.L\c JZca[l^cvTIYgʻ|w`O{9y_쇖dz ]rp(M!Q<چccL@DNdJ2O/2zE/K^1^y[ oXx=‡?bS3SBK"ZU6Oѳo@v A s:C* 2FcX / #1(.ՃFWÇcd,c#"q8WOg|DD T&ԙHI,]eRNFyr<ԔaZΠ3Lf60¬gәԙˇs{h^'X 2XHaap(dq%lXRX yY ۼ+\Õ Ѫ k9Zp] Y\]*PTc3ld;mvwD՝|.]%)nb{Rƽ}d2  ;P ƒm<:GQ8Zɱ Ɏ}t)O5qpxx&峄=rp/`pE .%eWȮԸ}|µ @p&73!>❌R[G^C&6G qOOiS˿|o=s 7M${YUk*`w4EOgC|,DS3~ЗBqٷw,h'ѧ?K75A *!, 3eS°pWAcDH #:çc c1q<2xp>D>$ N8)8%(LMCqZ31=23RI6 g|8Йs0<:|6/,TX0RY#\%dK*,e.\Y^c]+XUX͆-5]-,/ڼK67Ao&@.4U.NvV؅nl {G~`xA<psx#ѕG<Ǣm!Z<M?ODՓL63()咳UεaIN/ɿUf g)?Gy!" fa CɆF0°$Ûˆhadp8GF.c+`<&'lB‰ Lp¿3\>CSp6lLgH4Ogtxf,Yfhs"չĹUa'lF76 M}9[8%[dm[Dy`{qvB;EL=]G쇞ܟ,($j0 nّhcX'OD'qp2Ss(+9M\`B]db%:ZLr9+Б+=v-^ɵ M&nQ6Q)%ޭr{΃ _.DD_db m ]}9z +Q*]ɵ\g ͍݄Er+܆툈D܉BԹ}{EއߏL@Dtу=0#ݣCDtq'.'e߈Hid "gѱ\<"""""""h%Dѵ/""o^CWn i-FDADTx%q>"R >BDDdO!? DD}D_}ߣ?`G$G-~3;?Pu@mDoD8KtPb0 AaHFCQ򰌇pH8ő-b`T)nb ɘeu&&ф蚉,LBLjdOAyJbD2?" 8" dq.aqIa),he/',or\UWE˫Xk0^p-ܬCq]G6!F6_6AM)nps%G[yhka-T7. M= a_a?ux ,CLja.9†#l:Zk8[8&N8ET9t:3,飳dgst׸":p \8+Ж+]truP:_Tn&›܂nŀ?Q64|@DD;m Qcx/}G(?1q I>пMig)>Ky_ |Q%^FW(j57\&06wz G>0>?6S}UR+1wG G?uJ~s>PG   !=0F[frN >AH(&F8818]77 zd\l_gDN&.=6 <:6Cɦ79fDOτ̌%zp6+hNNr<+.1͋qKRX`ie%XΡ%+ظge*U9_ͥkje:֥}Ά QH65 V[S؆Ҷyd{;PQa';vqxW>{Z܋&Wlp8GGr|6#9MGx'H$NF)OE4aLelJ8xK|E%h\pr +\sʵ I7x7jܤs3VC69Æ; m=6܋&y#j<&QgR~?&E/_-f  * @[::Cph2au39<2AeDF(t4.CS82O U&Ҙ$npRq2 SBaJT6M-N1t:3h4fb㬒dkapN21yL΋[X@gA…$ k,xQtdId˗ٲ<++DqeʫؼL.["X:*)/6m1MM6À:[ҥ[9m8؞؎d'Dd3..U ݁==}b5: o-~?d?_W~w8ޯ SDTa0CL mo Ȇ gpxQIad(Q38d,-#x/pB‰e0lR'89)(LԦljhLL5f L3kByVm6D-М̅Hynyl}3͏څ] AE9XG3Z%ť ,mpr-W@M䒕%ذ*~558YZu8\z6mhF66Ûr-)m%Zem S^geGDygj^hzod_9@Ds"j0)H4uш.:;=yx'I')©.? g3->}ys g| 9_T/apWW15ע3y=$Moxέh.æ;ewM{m&9c >O%{Zg%i`E䁗)bU_s&`[oSzѻ߳Dcʟ|?g/9{~@t r /?n hj Fyp Cj 3oÈÊ^gHFf4Fi400l,Jc3xJ&29d L.Na&BqUNAL3Y]8}>00dټ:1_\@\Pl1-.. p,X +\*: \Zu֕'[>F&¦lfas-9JdmUAcG;Q.*faw=,)屽#~ W8䁌`j0[8:GQ81KxNDON&8Nn $w~:[xĆG c||M&48lb&6N*N&)LhyMKq:2M3hhr&`guh6Nf`Nss+>O_e.Et5%lXRe)Qq (ly VtVDע6u(Y%lWMӛ6ClsЖ> -omٶ>mOa;ΜbqWv#g{0S>5 ]|C)FpGH(c}~p'|'1<)&NFt g8ˇg#s=w-R=woйC7qp÷ /oCfNw!ލc^>~0zP:)=){ O<+yyJ/K*/+d[|CMNޢCp{o>G2̣—k7w ?PO&b࿲_)N ;d`FTa0:a|6p:#z`F䃑 ܎Jq4NGA8&ñ<0qPw\gr| 8 LlpN)\>ǧMM8t@00e*.C2'R[2l^a>,.$.,,KXRZFgY9<\(LiqUQ^pMq-qmuY6p`CFXg l!nIa+ [ ۉۛAؑN>ޙ.]4v'CG>_ŃLpC &n#%G!rt c%'(“tN8R<:gge h+9| $..ָDe / tpxM@F&fJnoWCSr p>~<裇 f8 :0ّ9)%pFb@>)/ЂB A. ,KOg8Xǫj&ְ>ZGg] F6o,DcSƛ6Gl-o mms;jDigt.]Qq7NwqBmG?$㇠gEOHp G "ё傣-c g hINv<ŧ#r|rw 2HdvI\$)%H J) NGz$%#!:d9 0ɍQW|KVP# TTC1Q+%Ii+#Y9}HN(%TUQMCuB &RPCK@s M54ÚVXkNmv't:iL颣ͺ4ѓKބ> aA`a:42RQ&Ƙ`,a& uLbӱl B-BXa-Ӱ YIXl eAl l4&lmd+́n;8TKc^ &: pT17 N :4r9'yN].cW8]Upu7t[rw$C+xD=fOu<ܠ^jxB%y"o5>('g|w~"46S+(E,8p& ZGAaS"`EQTJ4Jt$Ӈv8"8GX(!DSZ(0Mr/) H)YX:H+%#L2(Y A9\&\Xn,$y-) IA Pi(n@ JI4 , KTRQA%*6*RݡjX&&.R@PC \d55QsZ hCq tQA':Suź)nX/MEa-60c02000܀tQF#hqƛdLtILM0Ui7]30K`y0_Y t,&,q_qZidD5>j- ڠ`6l1Vld;evJKno*t#r8 9ӌ0: Ip^ 6E.ɮ*຅n踩<~=6y&x*3 `҇F=2zt7h'}|1W \;H8/`u8&@OH@ء  fPpBxTHBBhkpD@"*$Ad QLUA4İIL,_x@<u$@:T",DI\$)d4( R HCIR4אACF,̔,)Ȯ!\:r+c:IV)6AJQ3Iq tR6( )+:**UUujPԒu +E# $k546?DESF|Ts--%iv65 ct :#]. FmևQ_J?9 𨁄Ad lF #u&58b$&1妚h>d6SY̱ͦ\ OY,PE,a[aJdMVKFZ<` 6a[([l3vv 91h/ABh8J9fNNSp(:cM}E\&\U5 캎-UܡE)=@J%y詎g&{NyAyIxF^ dόh}gE-/ů @H`$ .YIBrFKg@xD`#2(XT@b&G$0 !$ H%gCJr4:b4 L 23"(Ic9\HnNyEPCAB! HɊElP!J %]JKRơT+/ABEB%F*XUJ5A5UԲ@m`u PA#BcDX3 5RPj@mhˡ qtq])tzi^z#}X?Jl S0LpF#UBFCOMr.4ET4ӱ60c0X(hń%,2rdjk8㴞m6fq[%h;eKا`*R#GtpLq'S&8 s&:]`tQ%.W]Sp] 7[m wup{NO<乀+kot^.>3⫀ow'*ko HP)X!BB0:b,Q E4 . # bQbs#%>%I 1LArN)()2 5CrH'( XFudUC6 ȉQ>R)Ĩ0VAQ Ő:Jb e(e)\ H%2R`LV]GMR[@4`kġ1Oi5Z -XD]GGB'I:CtEQ#=bЛǠg.7F8 0p#tQ*F42dIdS(S%Ll&e62G\!B Yl1DKe+L Y kuuO h#`fBcYdaNA6h R C :dp'v3YQ *.%2劋]EfMpHq"v; Ox=K&{fs#^1x H3ཉ>HDLb|c]_:~/ h@CXQ(V˄cfE4 ",A JL,D8**! J $֑I$R0J)Q*VKG@hL&ʬ" l:+aPN$ rSPr`uPR+J)'QRRQJY *a5TA9\u5(5)$ձ@]i h_PJSFT4B@KP[trX tź9@wJ= )/`eD2DP 0BFFdc`&hdL4UitfH2SY64<G`1%,Lrdoe5FZ: ؀mD6q,Vlvm;ndgt!K +8$ Ncg$9✂ E %]bprAnM -4v;.{p_{RhHa}A7A'[X(R !.R@(BKz@8 mCD"i0Q8DU N!&Xb#q5(!C%0 $H,( TG2,9% Ra4 qJ"!L 23Ȣ#+!A%(\rQyC򛬀H! v" "Ő⒔`PAi)TF hJ> TPUC5IjhiZ&ͨCQOC}׀ACB#&&h4ip- zT;\=0E#NYGtun&ΨD=Ua"} a\`0nCa>nF0Hda4164LdGLB&Sdͦ{  2ly: Z` Xa e,Ö[`$jGZC&%ۀm$lұY[%a;Nl {~lpؠ#&:jcqN 'Sig*ιyA$t\\nM`-mwaZr_!c͞" zK{ൂ75;{>(pO\⋍J NE~ox_h5XEJPi@Bb&QSDEYCQ$:b) GG\NtHA"u$$%$PңRRH #\*#ICf, 98K&L p*’ɊJ %6Yd:*(Y%5TՠjjkC+Q=ISP"56iAMu`RE+kMi#MA.t%tCzm>.׃a5 4`!bð F0R$m1X yxMdSi6tYlde 3`>aHb,2rYT"`MQ66& )[ "4lwiW>r9D9,*c'$q9K8$3 U7|B?~;ï`@fAY0ZBB" !,%" %dPdFQlr-CGL#Aqs*JHGbH`@R$ J i9Ӑހ X": Y&]E9\S ˇPQCaE͊ (tJbLTA !=*TCj 먡&R!j6>6idƜ JDMVK$QVv>.IAguqX>>61FA`C8 BI0F`Q1Z1&@|x&pM kML c:1Nns1!WYhEc)2d$++UjZg)XallP8V6v)vnIh/}B) 9a Eb<8'T@iFgg;O]tK.;]v 8u7Ena%.{A ,ДQ"MI%Hf$%M*],d_2qʌdaՠl*! '\6 GP^$ۤpQȀ„"HQH %PVP9ByJJ:*KRE @jZ6zX}4*hĠ+hBhkZ6:"$jtEP7Auaza>*'H2P fealA #Xc &!)Tlf 3Yf똣c.a.РE XBXhCVVrXFZ'll԰d+vl6إbCGgp@A8:8. I86 psvQ%.#W\t an >>!HX)慊"}[tw2%$~HW6/1 !`c!r@Q amS"HxPdBQE bh#!x*H+!0E"lX$'$Ր̇%6I(CH#QZ3(dQF,XJVL9(9] S^V@CAXEUcT\G IJ(2QB$(U*TEqpji$uu3A}F j4Oibf3hA8(h+3 YGJ'uVʨҝ҃QOEz#}B?e"`(eK `0 b`c91^I&b,0afxL2efdsUsBȇ-DI"+$Z)* 5Q֫t 5t555 5' JGkBI^G`.:s]tRt2}(}~&  rP`MF0`h1A5L@&J4I(ӱ f*0a) *QkXb aˑ* q:ldltMmv-Id;.lCᴗ> 吂:*8qNtN38c*a *.b\p&[nnw$k{:5h(/|EwA?%EW_{m$ h@ ć5I0 s !! 0r(QA$DQtD5(%KPlIP\cK BIt$%$$B@J,6KCHktXze22Ȥ! U@6$99Ґۀ,?RH!H1UPRG)Ji e (g** -PICeJU Td5MVP۠: bLVd  F> sjBh1-ЂCK$)m jkHJGB'Jg ]PӀ^XoBB_J? W0`!aFi(A%!c}8l&`ILl 2Mt`4V00 -BZ k,GV0ZIYe:X+`M֫`f [ Pl*vn{E8qGmpLqN'Ipƀ 8.1]!\Ů)N$nKp"U< lp@!;cqv",t(:cp^ E\1઎k&n MbppK )<'jxṍ^HR+576z+>'3_U|`OFX䯅:THE` `+!$ڠ0HXLdH:"3"(ѐ&!&ˀ xT\FאG$)H!$$ 9%%\,58WAE&dRe1AVxِ.crzD.$7 PFр+E6 !XI(DlepJ* X ))Ԕ4ҩH(I2 ʌd(+l:3r99r,: 1*L(¨(VLX %%*\"TPȩVPRUG5Ujũ:uzH} !4HSN,ЂiEhCiǩt$t23J&zX/Joh˨ ` EaÑH80KGh &b8LV1Ł:4A)3L6S,b5`2_ XDX`Yf@ bYc:Q֫؀mamQU6.d']vثb b,rX䘎.rANU8#,߿B qH$z?Ȍ@Cˏ|O#>s,24?~whЩm;voӸCжM.;t?c۶j:7k&Mi2FZPKI{P4232eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.4.bt2-[q*((֘cu*TKtii.h4D=K6mc3L\ٕD'Ċ4=>}/&Lo6wu/7gСj%N'kHT;B/s]zos.%*RRY^7B!+S2o@'"G<'7~8v;$8HH&-d֘xMUKDzRh;b( !x13K)+yJB)/fPlkq3)t_'[@KvaOV&%I~raی,9Nq=e|Rx3:sVa NKB |«OD&y%ڎnpz)b8V9;=;ϖ=2-b4EٵO{q:Q; ЁM%c<ң.XWrjxkbl Ez}z`bA{S {Wi7Aڦp0*@7`"z ĤE}+ %Z:\.+&&ñRM0KP[Ĉz!]u5iU[ʩI#:bR:|@ vzum)oz+w]I|: ?udj'b V̍VG;{SNxUc6&삭Obm'=/rD5pMPꔀKKc'<"G4 wо WB?)MքZw╴\ёMn+j 0FԺгWpHS*,ч8 N vZ|!Nt_hX4{8ozNS U!w;h؎1@7bJM +_9FA|c _ S@Pc>A7**&;* 9~ Ima:LQM<`E+R`a}["|YK6Ua}ڧ43 |4 MOS4Z V긱# "NeCDlt!yVH8$Ni}XU6Ż:{bY,4hLK4|w]6|z{.w,oSn>E̔_ 8+H$9>@i;2p؀/&D;a> B -dky>S.ҵ{5L-1mc>r8t3ПhcA)5}ڦ,Hs[yP=茔}7Zz["M2;u{ȀMPn5hbd p-DB.Hh"3dD]Kܕ B@B==j2%#(%L\<>Z.ˉ_Di l\Ǜ"_ =9vܨ/6a}hG<%礌"RP_؋70gv}p"] =Ńio4;VFDKŚ3Z&lVhߛ;3{pRIPhT E@9"{n7Ʃn:DhEpPҼx+$LU z.8yo- Zn-vI*l95GY:A5zŬQ⋇sVaFFC#SBUq([.0$ho=A=&`\I5<|b-fQ{2m ,ք](26fIf뽢s9HN8N~ UoSZZ,f#Pn ݍCR=|4ܧɿ G~Y8A=Dzd~ĔcчldGCNX|SfUVPp0ZZ7Ւmb`(?* ݴprSY{CWjAR~Q(S!imG4GZXч\"䓉!x@k-OPt0\Ug9}ܳY #`DyD6JQ>S%*`O_hG%IB$~_UC!hIખ }  ╏ 2[4{8t-+@}Z>\MZnp 7%~,$_}pdR [>CS;RG}xX$w-}1vl3<)Dl mJk'Mܞt$c)5nXuӊ /|"^P (hZHhtFl=W3tWx Jh-fzUhjipÖZX?<+Θ}! @:[\ =ļL:K׷N**{5O+_vK/`U!! wM-| E0n\1Ci,C9O: 7E?cLՅ|7 ,i/aV!^E4xiWB,a%UC/U#SK~Ihğ7OF{U=qۧzY-g1HA ~B쯵#^Y=SFk43X$>SqFt]M[5cg\ÈM9fLgu>n*Éj'Ƭer}=_{E4%D%a'<<[qKKHpo!P&#]jHo8;2#Pe9-䫞F삐2J}NR>MZ%sui3:0µZ-w|[ ݓ`T:ٕ)=vVa;0CtNM7QeR|dyvU[97ugQ 6LCbg̐+%S (dÏ2򣙜^hؼv}e9%g+ׁ١jJXx@%*U-+<`3M zhD`p8p5Ī7f\Dy|$8Ssl"UHyN&:zY)EЍ>T^e ;}(”>hs .Il[dyLFb14VgA+r8IhlUArop-}P - V5QRyr$^(FÜsa 4݊h0SaS Toс ʄu/f( !ؔ$WY[D 3Ǔ)eKS [YˊًzO,d^~b)\4Ėg )ew<,޷uF c$~|荨 b*rYzԌE]yƪؿNUðnqЙtwLط'BRΪyИȣi߆v>2C9F\ʹJ`#fx{Fv"F;X̛l)\a%+׌]U 9(Ϡ@ 5ڶOry2iK1G\6^(jjbzkeeTm۵šL}P՞@kA^SjDc Ttlw!rg{Ns;*8χ33 :oJ[UP[2h+ 9]ab"aMIʡx4pĪh?CU &v3Z]90!|J$螭Ӈ`x;3X<"{{Uڨ# j$ Rʹ k=G% 4@~sj -( vZc0h4p~ O{0:ڦ&cjU֦}E]lrh[nkm F՞䑡T~ѣ-'tKP.+uƞc 2c8c8UY!?(- 7GpPi* RkCyJ1m;فg=ٴtmXؖh?0rbŵj2̛-pv԰% 40iZ(\";5 -N*ڱb@y oCDR ;0sG `ڎ&C-@T\8ׂ:$eѓK'6y[-cX}P(M<֯Ȇ&xjEmhКle״}Awmk;j<.BH@ڭF\f9ΫZw~\0^f>"}O)j #Oj%i+5y?}JkCdI,P.if'1bhEyu#nK们w]̈́BǓKfpɶCTŰٕ32VERqM\1|Qܠ)Nmb(nKngsD9Rlmi= : &?9`l?~~]Si%.լvh+v*wo֕N;uMӎpu5;iDo>=Ri4v4Bd?;r Bz;pE{ԉVpw%Kd̸21`v}PUvKf^:4ڇ_}Iؾ&ؽ}D3BZLz_̺[K-'!yskϻ{ m`Vdt}k-.>#VtLm3`׎:d.!/٦Q}SKC X9ّ'[>|184FpOg yCϜ 8-\޻/lMƵ$[tK*b&hÏcc|۶g( )Qت^LtpŕFVm 4"`]67anIKҗړy ^JjK{!1/c1Ŀ@SM',(l6{~;h1O8D0L|R,؉Fefk*~7o^F˚?:k/@||zwꄲR9.ӧZpHL ;иƈ IsR[-8.DAK⾾ {듺g`؆s]W}dVT Wd`s?m4%Rw0$`39^*4l>TvD\1 =eM_|o5l_7LEm5ui%;$G?Mߊh; >Ğb?oo71\>ܹVEC]_irKt/+ ֫۷٘ h٭C]RG-%׎p9޼j6*S; H Z$ I& PKI{Pu$8632eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.rev.2.bt2% Ou/aƒedTvFcId a,cdi!]CZ RD QWE Ⱦ^[w]9}sd /"!mBCh(Zl!—B OwF !WR%u>j#Cm'P۷I. aAWF|?%BX5B c{h%#CX_6B(sQN>B 9?w-ou!Ts:a!S¸=/db!ܯ&Just9՘eHr!@-_ a!,N k^L{Wٳr7«[wۺxU¼!ܗ78Q8-Bxi5ۅPG̱EO$of^-O}hɸ˰S׼6CȩN1yjuaﭺQ!}*;bGGivs }Z"zZWKzRsOCCO'ĝwS=rv=ң:طOc*{XkMZN}49,x'p_)z| )!Ϗz4kVVcB[s|ߏhݫL+y?6Lȵ8>)O#qku]Cq8Dci[D]x_vUpwu]X) vg{vxpoxU4J?C;^V?cq }pu]dr'n =NsNJ:Foqv&g59)މdX5=,¼յ ubk铆9^_h|ֱ7}8V*I/MП3zo9N&/Z}š(KUt}V_Lz1㭏WkF$Ӷq}v*җ_zu8.OuKI{ۅV*N1)UV3bߨB//ܛDk4"NK5yL2?חh[[uX[V)^Wwu1kKg'Gfu;_|1ыfxJ]^Q^Up3]#qgzUS٧ONx i'~N*X_ӵKgU䭇若8KcMQ~LiMsu"ϾBv t/)급<[/^!_v<_ge,)E {.Úϯ7EWw3ͱ3\cM忷gՅ2ս[+*g}-gJsg評ngYҎ{L񼈇8{;Oh8zaYͳhTypuß OʓOjf^D5ƈu/jWo ҃߮WMPoA6Gx]s,VeM83 ռhe_g5uI<Cy=~=(oN Y>h N'ˮA cwkskf/EEo~#Cx|w4(jxSްc^>k3_ZI|07Yã.z_1ij{#;7E̟XJVAh^irO$ni4{Z=fw?v(ӽ l0d{܏ylmx%%4VKak8ӑskhw {ڵO͂24Fe=)@4óqg/m> Tgy16R!zi%۳rEˋz2Uxx)rox|>%_,KzLw]B-&^$z8γ.^S=y_X`fM'=~?ֿ͜f>Bz&q2ߪ-ψK'D~=$/^( #j 1?㫻b'#]EB1>Zul_|SUh϶8l؆z<^СZnkΣ[|Y]7ũ3: }?GfSqЮ~|n=KglL,suj)$JRy}iK`\?\^y~}j.ͩtNMW?^zA?|83=-B ;ވgU)g8^?Ó~xGuy`ˇ( tx65GӢ?ѻ $/kv͝OU/,e$_!+CC]_g z5f6n8Ny;ۚLңpU<&9O\b~=^$<wn_i; \5T+hݟ⭃(9֊ypZJ^|ׯ7F<~nX~/|Ļ}|\o=PS^4O2uqsN1t^g#\3-u՟xgVs7~8Wk;<'Ut]]n#}C,t .@~˥tc0>B@6rNu#l},GhLdSPKI{Pd"C>(@632eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.rev.1.bt2PP((vQb޻^{AQQA@`H JUT,(v>}/e7$pL|vOvCQcXKY4A]Pհ(cރdmleafuv rȯms9^nɏh^R4Y;~Ԫ$Vַcӛ?gzۢ,h:n޷<&io4"۝~ɀwKw AFLV{B3E[5׼5AV!>˧fwkxhύUa֞FAg#A`֫KV|fa/Bs;>yi꓆JujUOyS7QpD۱փUc6Vy˴m46<#Z˺G0{ӱ֬mg~7jqC>v]kԿ/ $=z:NgCYL/^+F#'6 1`FEp3>yL1(0E}И&`:կ[iC[v9ym_e7\0DV]"wϪo=~k]VwǁAkCkڻ:}5-)ܢM[m#&ȿk?#+}[4{zstS@pS#ƾN~\s[E|gJ~coo;}sf tgH{͎/?> Tu2 s};j?"nE'ߛ8YBvF0tpZmǣҔ*mIKu=X{ӻϵ ;Y@4U; SnbRrJJ#Cj5zKWOkdj=mQPj ]m LcbẮ4_Q nd:9iiE5P߽¯?;е`: [XoWjYC}O:~ݚa 1.0 ~5&kiﲟ5 q赥N !b;nߚ롛xpϏ7kǍK/36"uG{{8r \v\֫8KݜZteh1[sv{VO o=bŶFk߭c* v\+|ڕ蔩zHY@{~ jt.8]K#8o#Ca_&՞rfZ=}꜁t/[S#6 p>V?;mۚ-7<~mvYO>0?zK 7Xb4zciKkZ2uU;2ǽsոrۄͦ^I-k2t6@)6< 1Mk/{qSps:`9[p+lA[5x\壳jۡz/gi Lh0-d_,55zZ,( =ڍ`QE/_3Ģ SnjyفόVwa8EmyC 6CQ*}xq׬{ލ} á Ѓmtf67gVzKzZ:4d?)C*VY~Á m6(knuj/Kl~zĶzr}@%6sĦu vΪ3fl4SΉsNԶܺjHƼqju} `Z5 hOk?]r-H{mؙZ(qf!n?}8aځWC܃~}ؙ4Z{t>*&< 7oaug2o^z3@W  E+g6quYŊbWhN쥑95w,Pu f WEKj_ ,]mvZe7F8)ky_^!tqS/ tӿq ЋX0I~#ci$4? %p]Ӛ JFjSuָmnL!SMl}l,)=`EŎoll֦4&0Mfc-6y{6=pgJUp̨83g5t$ \o:W_YЛA yb+דj0׼zc;Sfe.=21+tc׼B?ohb~3X|t]9kfP0 K,62bJ}V2}<{Kp}ڗzクmo8~];62I:W?i2ۻ$cúw]ӟMNw26}e_W<]WlsKl܋xN4n8v(K\K_7gx:隶 ءe5Pky{I-97 - }gxݿ@ܲWkuYA{Txqd١[㢨LX >?[i tĔ.]͆Xe7ʦM%8糪kǞC}_CZYi6s}}\XZ0\8$6W܄Mu؅> 7ҝ76=nN1?9{%&_56`{rL5RQ}2!7tqbPoknƃ^٭L\W.ǗKhYg4wV<:}sxݷЏ>6URl:Oےla+bwD 5KM]+.qZ~/~zc> Ւ~L(Im[VYZp;ٻ`dv';Muz>Ϡ.j䨻IJr Mlz%VZwҡ܈e{M`.\xS;XoˆQs֙_kk~6+kvm^pcdBo譯nf8gwQ2ܩV\C;5C3֝BàV&fh uWڢEF8QO&ߋ5dY*.K/Y}9.wk^LJz$-Gv֙YXRbFF5f'yCr7} .e~pPXgh\:qrl8&|2ߊb˶o06q։s5Ѩs%fTG-U } sMūqI״)?mvmX$buǫ;ch}Ҋwbp-סifzT&f[jnt8)mi=q/k*2NlJZЛC_ }-CJ"2bv*:2!ݻ;o}=@ӍykU]uӳ}㡷tZS:6[{\BOn|^U~[vY211$N=k:p ECo3DAu†)|cO6.,ׂR3-װ&>v6.w~' ׃՞iqooF:Fe\NJD6ςkaӤl  c}d͍(V *-[hjO[[FWs#SY*@we$UR.46ت/(e̫-9A;:%.6.w}UϡIX;sݐ|cQ)i.X'n)x|/'nZK (Ma.Șmy_ӝ-ܪٽB7=ΩJ3ܪwg:&pN~Fs| JS5JrKBR;su 4&T}oyzѧzϵZrDz/MB*x誇zl4 a@;ۂ댂~ k`_88ͮ<[rF&$^q_.`gM&>g:ֲ_ iCo1ڿ_Vڝ6V^πXd[fm71} peBem<'n=,:g%ljɨHq}W2ٶ!l÷WJRsau1-'gVF..oA}K8|{+MNmq^濖k{>pmFXZO-U.sb蝡o sYUk䯕St*};]*}WwϦSZW/~C#xXT}#8̈́ u:MZ紵{|.{keܙ[ip Y,;C}Xzo2yٓSbYl+B*VC- 8c5^5/MXӡ}ދٻ'4J1X7Xꯥ3mzUU.s,k|br'A_>d+G\51yDˣRW:y9]~a-;U+s?'G@(ıqЅ+m {^6*nQm,S{>Y,.m'Y;9wVF,c5<?/[7h17߾]9 UWm*\bxg[wqC3lAOr:o_-נK'ʨ]_J s7~;\'riҬ?8Y5;a_;ǖd<_\Gu NЗHꧯBs r+mGs .ckY3N~ˠO{J:cuEje fF㐊W+%{fֵ55 wC0~=J=~M2h~e.v:ҢVʢU&] Ա1\7?jc&$jl:آϣ3os-.N17qVj@>swCgK1QnvW+ wu+XqI~7V9?|">W6VaX]ugYgemK6_Bm8vҾb{0iK] `'C7ޡ<- vH{1ÂO^}%%l߼\VlCvlbU>X|,eUȠ絓vI2n?vnw~֫uYf"gۺ߁ г/*Ͻ=XuG'Kȍ~3u9J*[\ӦE٪L힓̒ x8\צå%gsw4otzCnA_޼C]וz  =T*%y^"UڙaE>g>;}NՏm_Co }]8OA>4r^Wv|+*-Yɩg[6Q嗫Џ92?~yS*޷QwBwnnk.nhyf޷π|oSGAsCKv^Ŀ-wW9mOK{s5YC_m/G;K KoY^sz~*/;qM7uC]88˹EQi#>ީ_Q̱K[0G۷NϺP^V=sB Qc;|1_l|ۦb_kCt>ۺ5zC㘛ɦ[dѢ)+VV.jXto47d\?C/44xɇߜmt.|*k7&O+O*ܭ6}zOg7Y}!`|nh Y3Mc_D8_oϻd/Y~{ggxihAov,9?&f (|n81İNX8gusϏ}k1dsya<SapRp;sB€:x]TM:Umޑof|X"àg5gJN`rE:X漯oxyce:Ym>hK>4`S #295>%R &+kS1{.|nc5/N_8'a''hAރ0.JcOaaTO2N{ݫ:Wm}sz|XV.=\>sgYxJ;ެdQlEͫ:uⷠjݲ{޾xōj<ߕ=fg[Žゾ;.jotHY@`|ߝڮ}Kag#?\gwcY%%l3?mܮMgVP;:g͟Uw%-=R.8Ư>*񕩛s[@֭9t[XɃc,_< :]Pڝ9͆YY*^p/u_>OH{|5OCAcO3N;+zK w֪yEϫ}5 u; Xhs9Q]0}UzP%;lτyԽy`JN3䄐 VW֍feW/>m+ܑvNKW56tv|O_YcUmUf])ywEs̉ߖtiG: z7gޣ-\laπwfdA_ga?_wTV?-S1 ͩ. >^“Ɖ+۪*諵knmOp z>^حw߃]S{שx";K?]U۹+NwܢGmtcPY/}۳=ʹsgܿ(9Qc]Lhu<6 i;Ey919igo6|Ե _}&&$;k ^З`rcWZzUl-C>n5<_:ſl> 7n,߰uuXQ׮#o43󧞕[yGr1_V]4Z=Am#yek|Kꔷ]ږ3c"6n_S952_-rayT߷Sװur۫wt|˨e!I)<\w׌v!Ҷ<7r6 z{hwس\@֎o9UM.6i2 K)ojG-6؝hЏ#8*鹎ESM[g8OoKO.hu.WVǛaΖCV@b'۝28 qLIFquO,@ ?D /->Q֭#S5]+MB :/_wʝ'mn};Iʆnڎ3 ݱuxwzfY6'Ft{~0xVS٢ e'Az6p/^coc+R.z;Fsgߒא#3"濯|\)wWB?uEN+GE&;*9sccoʦ=ܶ jylfS[iA.B|ߕcZ=yX+b=Z7,ouҭH+C?Я1q<"}ӱ#]5, cwiUU7շ:ztڱίvR;@e[z(Ծmgb^|hs;OLI<`;YI)RJ( D`x"S,{N y%lx rȥ(O[|;^|G }ೌ|Q*7*AI(J;E?0$ٟ[J O*eu4dHZR-F[H.FG ]z>8 pbI?D$4  dcZZSQ[ ў$ttq,Hı&Aw[)1==ppIr")gP*nr }@_ @Hb܅$`!b #i8(h)b,M጗ BL$ߨc N  3fsq 0_-,xg Mgr%᭄V+kU #c4ZM4@Z*@!Jm@h ٢ FQBlN)RA?{h/Cf?"%pa:"#GʎI8 1B8s4 gqd\$Dp D0e,R W%p!MnVRwhE]1 IA8x CH#MtAGJ1d<O)x&Y a^"rJdk r( O㝜> a8_@"|`J  CF*%o*i T+F@HM:]#AM0I0YLC1&2T5#h F BJ-1jBL Cv5D{%A:RI t]0]I0XHRBV2fM` A`v d !'Js!'Q="'  RQK}dR @%NA@b !F`F*($aqR`b,T%7Mba6fsŘ@lT1X"!/-`K"aWOB@ g- p6b6ll* &C&;E%nGI/TB8,tTJ8N4 "8#Y9:s$L]P.p"sY WIUQps&&Jh!bd,8'KR (OD1 ,)RFPOSgYb<ýa^@6k9y7oI%􁢏4,UJhVHADRL.9I/~#5RUQM3>K@GheDKJR uQzrÖEhV"Ci@ iMdk0^s1RrR*DVBV0Sk"Ri'#E:d&#]hUsYRAhfl@7ˀ- vBQƜD 8U n@~8 Epb3 aa H1%13`e`Ř"Ti 0]f&E(ps03OF拱@RS-`^2`1B X Va-N#X/ I$)"VH&B04ANv WBcpCQ!cN*I1Np Eg8'ypD5* Np$61bĊ'GqEH G}$ )i 'GA =aY \ ˦k), [9{!>||3"C_1bJJROTIZ /uJhɉ%AF$  >"kDAc!Ѵj&DsaZQK!DR1)2Ŵ-I= ItVf*uȜA,H$"V6uYw- v=Q'Dnz)p A7/8el;f`<4Ta '!Œ bƑ4^ R($,bLS*b % 2K26b'X G e`9 $pGqIดNJI)N䌔Rps!eIU5B7irKۘ;QݥQ KAN j4@OrY}J+M!*d"AF%#"C! ]~PPODi7 BUA(xj @hPKjEm! VWB:EHS0}Da50!4!4Bj8M0MЌ3?ZJ̘hZL)jCbSb%ԡd: t43Q 4BƱ;#;` "@d΁AҜ'(YQ@n$Bw ԇ"H QJk DN+1 "'Celf!HFFD)ci2k C$)M&i T)LcRKfJh`\#@,S+%Bx!*c)XFxd%Z`$FR P5`-M1+ XCl`3E[IۤLvvSpvWJdd?!pG8qNR:##gE . 5E!. .cI p Q(EhPS$("$$@ &J"CbdRDTT/xI+)e K<ިb#>2'(/ QBL JTBe+w%C %$F4P%jLj.5$4$IPB% J@fRГ} [I(zȿjHQ#9i,D$5F-@KeDVT64h+B; EA'%Y3*,D$ b#B7莈e+'vAq8!J', R&D/ЛK?C $]BP Ì$aI1*8Lb0Ř3UBt 3KBeds<|B!QI%20KfIZAG_Vck`a= F6BIa FhB`;Eߘ="%G~$9LpfGN`BI8N1i;# r \"\Q8A\ A$U&unV t[(9+D É Gp_D$y$*dJQ*(J#F EO% !%{.2RWdL.&OoxK|xG{> H>_T_FBLQBP)P DDEQ*r#j%W,RCHSW"5hc JⰅ0z' hDИ!Дf cDJ"@+ Z ` ` ю&UX]Ak D*RB!AT@7F.8v  f P=( g agA r7  *(C? "CcI`0IJhECehIÕYÍX! 0 D 4 P4A4Dbӑ1 L9f 20AA!5|F[ ' A Hë[@DΖ[VJVC+2B) 2D f%AM f[@DF&v HحF(#5>Op@B8BQs %ᤔN!8[IDp!eH(b\C^ e$Q*Xq$+. J" ($PdRpRIH#d`J.'B<39^`^b^I(Kଡ଼ü >I_ba e9(e$+~ *'`~)o%Vc*P×|Ɂ:i $ԒBm9В6ꀺDWJz  d@z5D}2dP e4FB%Tfr\Ό0-c@+m%WT\G)uBY3AWȿ,k +1 N7U;qz #81DOM ƕ7 zޘ> W 0%0@Ax`P0 `8IQF(#gcl(D0L`*4%0]B3K%lD<XY<)XHe^Jh)"w˔rBbU C_ V#SJ ` NN# `,9J 6)K)l%SJH-{f/~Abb48&JEI8d"Ω@a)"% !J.RE]UrהuݐBBw$JʊVD!bICxAEHODJx20i4H z$cL'8O3(xN {I AhZ < 㭌㼣{|裂}3WM RT$F1ÔY\}g8 K~c*1 H Q0iEDJ (I2@$o9S%g b .cRĩEP%gژ:ԕ1t'`S``0"4rЈFԄ L@ Zb%d j#D[!aڃudNt K%`EkЍ d D'# 'Ig\pS1pzcW~ 3ܥ4H 8CJJ`d)QJn4ch0&$0a R(h2S0i f@$il04'J` XD)bh)XFr y RUJ̗`5#Q1kA gHa $ma3 [( d` fD%m;iK %7!+>O5A8@e ecRCBI%u sZg(8+s t^0 ]P,B \H90פpP7I@)CUCEjhS"8KR #>II !&THTcds)K)Rly!ȣoi/wGdG>/ V W!ѤP(aJI* '7A%SEj ғ$iMD©Z5ADbt>`ˁd> DjAAAD 4QAM%L!A "V+50Aj0 :tQ'c&. U s,(XXt#.[1$d/G=$@H'zp㬄\A/!z3H'F%6@ 122H#x! 0KiH)h0 2g Gq&)d%0`EIa͢h6f+<1hO!,^8K21- YIJ>2j9c0[(:[/#(0`[1A$mS!4 l(]C̞`/SpTC v!( D8N"*49%i (Y;Gy 1. \x !e)"\:AwGJQbܭ114U8?kIIHPDxH$Y )2Zt!GrXLD Oe Yϥ􂤗 Jza\1([)K GTC|*PB_7L!NN1P pINT`~*_TNA5|%'O$ & j4ђ6AP 刭 004@GCL#!4)0AK`BQ+ZSh#gmA;tY'93#+ %`A`I+ ] ;iCpBd88.ʑ%Bo/0x0DN0Fi2RF+`x&Ii0Ei`:f0 g6 s)GB,YD' EX"c^$,d$JY#/X-C(H&16ႤM` b;fG S]FrA#5A"ᰊ;먊8FqBpB Qg8FpQK(]#A$pA躔nM!n pE!w*ZIK8 ū.% vOJHDAGx CkHQN:AM)LjLe*'H|$WQ"?-@O 5XP>ҠPfMapޢ %( ǢKL6܋ H%[%HlAr"Ɂ9)RJ)Ǥ + Dz"g2 2%9Ygr/_P|)E=XV@b>Ws%Ur@inr6*OAJ:TMU8PUC5Uשj¿jyPm uPQϤDihB#h!MM}XҜhVZkh1m%ڹALNf]lԕn"=DO^".}9O ph#sl0k(C1fN#L 1>4#yxlI.TFLtͰLfl6pm%s\6s bʖa:de.Z+ʂ&qZ[ 6:`>\UmAb 8#{}9sA);"qT/ TEN褆SiUp&]`E%]\qUk&]q\I7[;:#!*q?pa C84fp( Fƍ0΂M &4Id) JLh͠`&̲l pbOc|X@B Y1K7Ö*XƉ kJ>F֛AMmlhC1h;Xà:풱3{Dj!50 䰊#&17oNty U\˔]*c9M7p[ݵ= x@<-x& %9vEG<s4Puag-:o &\%)BU\M7<nRv͐;:Uq%<)l+Ed|WCOQlPAP".!iB((AaEYހ "ʈCd xLTQQ1[E5(, )H #1$"I=&)|& ii-HǨTW%-$#Dy\v9 )#[<SIסQC i(LN,(nA JZT>RFEY(OAJUVPEU9SAQMjۤz./f )kdiⰦ6h&Ҝh)NmNAD:ڠEmЅ]m du=ҡ}D߇R2H0!C\4Tb͆{(F0, a<&DMrd S?lL7api̢`\3a HXbN갔Xr 4`kIkd`I%6`M:mi #6 vpdvqf7Ǡ. q0cPpSO"9e_] .ᰟ&D@@U` >ԃ/ ᠐a( `.(6JY4! 2bۂ8 kA<$РD6I̩$J `d"m<+ RgV&imN"=E(LlAjlɮ"rR ͹<>ϤDA)u((e4gL JJ:xRieL* L+gAy*PPQ*ITBTjcjW#u$ZT,ϰਆD#G41)CqMZsZGem8fm d@g]n&uWC'z z} ˈ~"5 P0PA*;hPI 'F4%m Y4^0AbIdSt*ctf0b&%( Qs?X XȉE:-a?U,,dA+DVXaNk8֤u aD6[ت`6i.ۭ`^|lE :(e@18X7vt9ɱS6; 81<0p ..\]@u0.ű>qG=Cأ8 8S/|%57.y w[aM}O;8) :!As$%@QBP( @>1{`H`HdsQ?Eg@ b0& \kxOY D$ 1uJᲔRci(H!$;,2r,8*3eY$R!(\ 8!#9Ac 0E$VX֠vt_::#:xDMWNut>. @db x _ dᔌHFFpXn0d%4 l5fS{S 513SfJ2h`\.)Z u,Ẕ%:邥`2A h V[Ƥ",Xϐ :lt&6l+a {tˈ}"9w)8a∆A47o Tp%p,cι,h%2H\%p]nm;@]FS=H&<<yn 4kzé=xP'>}Wg~)1Ƞ&1( !)!23,DDH99ŠD3):E1\ ۂ8 +ǐ6K@$4! Idy9BAJRHj i(KS:FQz2XQ$ "lAQNDn䑑| #D rDaTTHqJHdL)26) Tt:T22Ȫ‪4TWPCPӂZ2j;H=HHAU 4ӡ9тhIQ+ ZFE[Ё(h̘..n== z{DeD?Э?X6 ;dACuF w(F pj,9`N (dS"D[4À&̒bCjb>E )Z`?-XJ2*VҠUj5keS!$6RIǶVmcv0mhکbvKalv@8B☃wf S ;Mg 8'8/rA6$r+"WEɸ!qwLKܳA<#c Og&E_L*)႟@:ćz@0"I!<&O$,V8 D"r*Ȃ( ZM":11E+#M[JCb$$I2JΨ`X*0$5&҂e8Gz-2r, NY$myLv\s<%¿)ϸ*hB!0QE9P̠%d(Ũ҂2(gBy *PTfs*UU6SujPSF-j%uDTϠe\XFpTS e-&"ZKVvK{:xLGurHg",fjz zsz!}Џ)ఁDbi855e9cw҄S& %gsK)W-funnaw{.o*2O(zj3 䅂yE6CxG>2g_=%?% &dX(B a]N$M"LDH,E$h NI dT,bs$W";,N AS"Ab0$)GA)(K q42ҊsoH d4)2ȢCVe3)N9 iQ.&ȯNE i("&(ơD AIJ J{@)xNENA%FTfH0*VM jTSPEP.k(HĠ2Qւhւ6".hP'Utt%]CCOJzۣؠMQߤ6&%H 1L*FHd(eq.ϙ MlEM"j4LG0hY0ss(kyͧl"Ke-WB|`5GP#(l&HlhvҰ[bW>pEG%q |㸇a'>vJ gtVs68o":]!pC?"79s @6c.qA-z`C<>>e/U6y=C>!=2(fwFiQS@)$*B0&6 GQxE! "aQt*#N a&"bh e@HEbAH*#DrITK2&~cPz d(p-ʦ!2rI֐G6'#?QQeAaHQ+Ƹ&MJ)(- ʚPs).N=D5U EvQzש U42M|)㚁:4.jCItE<3آ M; zxTOEVu\w΀ qQK6 ]1*# "ȸi[5wM|䓆"_tj7 C@>H`1!D0iQ(`Rh0 2 E@Q"D$";,DDb(II,)ĕ"%0)D"Ą6IfArI LH 5FCZ17A"erPf" Y dwXPfgq(# XPT؂" *18V%L*1@PF,VCUTQQ6$ReU<*E(nQ &fUQOA}â ibASZp%JFkڸ-jgAAG褠3ECWuSН!=(Ɉ^6͐>}O$$1sC$2`` FFR6&m4"tOLpDp$"S iAL90'~YZ c ?e5PeT1`XlYll!fv씱AmǢ u]r@A!0EG\v'7'8wRS9'8/qANWDnqAwrS >⁇<.{⒧=A/?^^3;{|G|O|1K~qA`X` DHBYFVF8DD4!HdEE+ᐘ -Cq]&e$0)!H"I(HC2e RHŀH7k@IFLuˆd!DN"rKcL~ LA QRXF8J$J٨2.)+EM3uݣ**jA5`^uj5TE}H]E=W?,j T4HS`V3N-<%xF+6 R[3=C:8N.,Zԍ +OCD`la 0i$Fn87&cWLi.⢩.3=be3UrlQ0y"mE,f,&J*FYCa٨a͜BV݄:.ڭb^qc-( Ui'|$I,8M1Nϸq@K>tYʹk\SnG6%ms}x$؄'=CSB z׌xC[QA'|W7%~1"Mʨ`&!RA(u ÀpD"1eDI49CS$ b;,Aq=&D|"H"I8T"\"#R$42zP:Ʊ@IFeQȦCvɡ"\>syD _P@AA(d*E]Pe_% (6)CIYyDy*s~WP*PE f{5Q3]PEuV9@\XE4cDs-(hiV6km)jǸ((C:t+#] !)㒾 0P0H0X!a23b2҂Q&X4֤"tHLlbӈ&i&2ˠق9`\b, ,RsKYƈ+|nU:&XdhN%6um"*v.m&\f\vPpe-:ⲣ2 E'u:ň8YF\EW=cK?6ɑ[c]=ܷN=#J; p) pK+Ao8L{G{ >ıϜbW}3;E?4U)̑ 2:(Hp0$!=&B[\#=,Cd.H4%N1(C,Ķ(L|aW⛏}OA@/&8lBCH " 3"IdDDATE3 ?bzD, _qD(J$%IF(KM) Jű*RE1(=dRfA2, r@@NDF$(hP!E%T!%8Q4(cQY+G@TTQQ!U)&D 52:D]9MPPF#0 4)h!RF+ژV^FNtI ݂d\/Ao Ϡ"!: h1R0Jh c4U0N&L`NTLbLaL(mU1O| EĀ?e,,3hI+tZ)J*(X|`6HlTIbhتadSnbg~pE%XtԤlrLqI 8Mqւs9o .$.pEpe,n Jn n-#+:UOF2 81\t(b4c5'OLDI6,2ń ftfX4ӀY-cGZ4ObdNeI,Y&XΘ.XStZ-#:d+|g 0`+0ml:.v#c*p(:lr/t\ߌ;I9eip9u`E.i Wt.?75ܒq[]{ /%c=1)E(yy){y2>"羀:}w ~A`ÂM P B[F ^C":$EJDIĒ-GF\5$! $QHSrH%H ZN6`ɢeQA$K\*rL $ApEA($NE]Paʼn J%)ce%i(/p~`H%*@ :8:VCAM jyDmC]JxH}5QCAYc M$hfBsZ-}ZKiAѢN.t%9N=d$z z3}%P4Pb P 2#DF  ƛ4f)$1ETb Ṵ`&1sy>2߄" ȢP&-#+LZmZbN (ɢb6 v4i v{,ڧ~⠊CÌ8B%9mDT\".˸bUEmvCM-n˸+rO}HO=)y!NlZ޺M >PO. bWt`H@bL`qYP50($xZ(`Is@x"EE"D"Aщ bX:vY!A %)Hl$"IU$$,:rAj4>H7һ$p/ %UM:ȥ D^SR@EA Tؠ":eeHI)#RրdTJ:UVQE*Q*jTc&ԳD$i:YKZhMjz@; ڃadt΂. 2@U饠W`A 0eC-&1\0#u%c2Q4ޤ &JLR1BL#3,,͖1ǀ2 sjE"Ke:,YAd* VkX#A6H&6dVb UTKbZ/r@E]tĠtTm )N gta %eW$ n4薊ۂ;*'/x 㡂GOtxI9ൌ7 R %>130ϟ?o6姊$t! &3!DAH" 8 AdD 2eQ) N1,)EĶQ\JyP|%0(!%\X$DR"䂔W6 6H 22ĨdH6"9()<y (ϑDA D P+jP1L Jz@)pTiʘTP^GTwUYTgT QQWE=3HCA#СMf:4'ZhC+&mm?:R ԙBYW1;e=$z ,m@5D "*0bÆp0ZJ4Cu1Yd GʘFLaf4My" e,RSK Xj2-W+UՌZZuzM 6+bmٮ`Sb`7ٯlpXG(;oN$ӌ8#q֠s: .tIe *î9 〛rmw$9쾌Ex s^RʢoE)'g|%|aOA@RuA`" !B(40! N( S F=& Uİ(&+Gl$tϡ2 K$$$Ӑ<)*%RvIi7E2ha|,3UFvr$\:!*'~)`)$RXE*jP1N)aBI QNFy KT\epU:9WD-N]UPq%PP?e4!*h -"m8VΤ:uɀ:u1=dHo>˙~]0y` aPpFl Fg_Cq6OLL&LM0`bf00g0c tX/K'K9LX.B2h yz emEböxv;ӂ]*vk ˸}?p@A AaG<(f7 N*8eigtVs"E.p%.3U5][ݐ%7[mw3e&eUIg| 9lL  L_B0&$PʀД!RNAx"xXDDXd(:Dh&Es@Ql Px`I%@" p$N)J!҂T*RkH##ޢ hL,ŤD6e"4vPyO(&ҡ0*¨`J1Y JHRPZMj(*q2D5Js mBS}:4ԩDchjf"-"4Ơ6hgPNҙ.tJw"}]Џb"."1a>2\dA#85ڠ1*:dG`A0Ib2Lu46!)elF͡h.< X,2a14h2f9CV*ՔQuh6jؤa[.fv;} ϩ8H!FvQcNPt҂S&%tH%.Srŀ&r,#rӠ[m]s_,y x̘'S'</WfRx>dg8䫊o?2_. b@Pq"8BEHZEDr@dBQTNDDP!SqWsH|J ZIl@2$I*R:,RKaPZƥj2ge4! 2$HV^6pUvrp& r8()K;mP)("RTP̤pYIJ5q@Y(P@ TTҩ2PQEPբjΐ )e= JԳ>% s.Dh&4Y3hZ҄V h3m,kC{:ȉNiDxPWt`D/AoLˡ~.T G  2`G P4C#( (-c ecU3hAtaLbT4NM"Dfkス`-Yh"-%ӂ"tXΩตJjY'XoHlҰ&[.fv0`ObnKdXrTra G\rTm:i)9Sg(8˨sLᒌ`+.J5"7_@MCn{ܗ,{ sS zaKp+ν5M+`G}23o} ~Ha@&TC0"8!dU0)3&HD "1Q|,ED{T 1&McR\x2RI\e HΠ6KiT)HcRZo*2HdbPf Y,*αDNrq(MH䕑c * /E@SQ@4J3Kj(VlVtLA RPA=5P#jKԑQ1>gjDDc hCBAKZQڀ6N>LS':]4tI7uATЋs9Ǣ1M 1Ї.EP0Ln0d$2 CH|hX$.`&&`Lh0aM DDICd6&]q(MđWx.H X" cR6J T@UjqPZZ:o A$#I&Y@UVec9LʩC.-*Ǡ0 خNaYQӡ8FIƕ PVA9[P1\R!U|A=57jP[ T%]@CCFCCcM\Ԣf5U-$ZT+ZmD: :HtHg]DRMFw zRҋ!>:G `@I  1h(1ιI( Fd 0&8h"&9lOMTp4[4CLY>7R0*XФE kNK c,w Vl@ZPTW6:d -.ڪ`S4s{=`9` 00G$Z8% )&p9w\re+ʡk6aMஂ{v\P#=qS<F7# T֡czD16+iQ)f@TN5CL,fy kMl!E>؄% ̄:$VX-XcZցֻdF6 6S6 KPA81hd'PrPpXZlr[ '!N9v!gM:GyF]pEK\\I7 A7En͠;wv/xCuzD<6 *xF0\3L4 h32ˢ:̡l` 9A SK@2`r EVSFuL;j_ 9Fq ;S;MY9y.p"E<2eW|\u7cMEm;w}0>NtzhOtz xFsWkJxkw`h'} iS}*6 FAp BhA|&DžQD "DT$E‰ S"8?wVORTB{V4B454mR(* + eTv߹x:+€dR4bI+;ۣR.6H͠\}(S *ڨd*Wͧ0̠DT/h 1hS4؅.554".N5Ϡ`-h%pGm%qi@lqY .t sLxt@]X\ @:=%5µ1N1%TA b0qfPde82Br#%q$F9`c c!8kFdM& "5 s3 S65ᦥqKtkTtf,f=`ؘy5i-E @ Bxv?Ee1 zE= [2a A`Z!G/In%b {'ƓS H{=W6(h' yQ/#6)Ux >mlKmhlћ[>-wlOw=v*|}]؍Y''S }>? } |m̾ P1G(m? OYa(w!$a#:PS6ZP H!: NErpq2)r[ VN(-f@+*?W$FA @s gF謈\ҊyPA AJ (H4R&*\ʅ WLHbbt `!Y {hb =lxD!1z43 H'$f@Hhhg =z@ ۘ`Cj/@R/+ @  _pm_ވțb6 t`;bv32@BJdvk#>$>gsHc `񥤾5@ߺ ߇@b# u@q⧐ ~ ~ ad$7w$EYY !c8V3fLJd\Nrp \ˍ95<:M R9F~dT f:ÅB3:˧€OEBTTA>lltt@*ecv.r1:/Dk* PR%Uƪ*DHfjEvL J HCiq5AJ.V%9E@-x$:Hµv6 tY@ǤC:Pu) +Cգn]% #C5KFW|b `]!> `XFdLb0:dcb00΃܍!2h1 f@1HaKS-ܚ 9=!̝ 3Sܝ=%ls<@/!xRx)bxfx%7BxR{41{` W8$@b|}b> P0}ek&&; ٗƏb 9k?rpȟ_i#>dKdPqlȎK#G#"rb r twN wN,p$J" ?f Jq&qVL C"bUQLBUB#%!cV @iAD,p$epOC @** V9"U"Vʪ0TL-VAu#R/i4̠14dt6.%!hEDZI5HA`m4viP]騈N.tq+KW$^7B\R\-XOS/]:D&TO1A:^QCl B4,G# ݠQ 5ZrcRh@c2!D7&JnK7;LQT5 ["v+n]e f3#r7=YP  CA>-"- zXe#@L+hG#Ȭ U)V=Ğ@ͭZR{Z1򬦞66h#0xE% @m*W^6? m@o-go4#dIl'(} D>.n$q >Ad>$B9|ۣ/ _+Jk7.|{Y>A~ ӯ> !@Rɟ!Kq[)BP1qɉH$ 6NX.Nrd(;!N 4(#/@dNQApDbSW$SBH@ɜWJ VƢ,!;P@LPPEU)Dh*TZ V;u ~a)1C8()\i EhiI5&By Υ(2 @ZɥȠK+%U"R\%Xwzik\֥QoD/ϣc0,"P4p#%uQ18 |!dYɒT5M[VnCbݎ܁b: ]>4-=̲1ۥ9_'̂4} #rO\XҒxClF>cYUj5l=.'x੄X1xZu<g%\ֻ8y^E^2+M5! i[o x״#di L]>|}B {Pȗ_7b_÷oѷOo:駘l=?:J/"U1ZِVvK1;t8>Ӊ KsG(*T(4 uO=RItpFB.)2(HĊ(&@q PIgǬCiMUV!">3)*T1$bPY*6yPA jJOHu>s~ 4J!hbqaM \$m4"&-# AkDmKC΅rS:ƤS5rE@]Bpk@$sULjTT]k z@i}K6@!]$\z0,`2 Q -11qKF d&&hR7Kh)4d"[wwh:"5]bGw 0+c407y40 ߇E6@x Դ̧- ha @+=Zj;xdOx6Ԟ `f6FOȋK rH^IcD^5>m` 67box x7&;\z/b;% *bc}>Ug#ľt髐7!փ@?mOqӯ%G8ҟ1ˇH*˖Fvrt X$\Nd$s"r ss2q ۅSi8*G,N(R8#bl頰E4P,C9%4Wp"JJQBpyt%w`A%*TET3Tj:Ojꤨ+z0j,X Y .NqIBV!hB). A;O .4A!mt2tqO]qeȺ)uW 3^ƥkcp S_Ũ(d`@| 7DQCad #Ō J1:c2kvc@I3ӘdqiS4nqkn]Rwtg̦KfFe13dwtODf!rqX{#r MHQ]z %xҐ,<`+"3bKpIܚ.KgxV>b S}`݆ >uG;ce_`o_gƾ;7}.p~ Ϛ%Dzw>Ba$֟˥-xUQɖp%#c28փ \ɒ;EAm*XkO'T~ tB qg9( BR4$$R*m(P@I}* pdO @eEUAbT'lT7p&ajP#@]ՋAhF4N&FSj!%k@i ZhE[A.E{e]6:jSΆ+Rt1\tP =jz+u>'E_30d0X]"P4\L01XM1Hc4!\$!,)T6 H[v+]3wCy3 3mܭ{,f٘ Gs\+<_ֽO3 Z<,G,.X<ÓV'! }ƞ||Ru@ 3!d|~vid9_4$~ "C; /I-*2 G Ď 7É$dlNq y<:-"y:]cf pGLY)@4iBJ$@INQ9JǤEY\SH LSTXECTI1GFi@]C H2t4pb.'A C2vm.M@Zm\&):Qb Lg]bpG]5vUu WGfzt-q3P_$JG pa`inp K1H7hfFP G$ucL&D$d4xvK nEmHvHΘM @Bwe0t{Y.V0Av)vk#(cRi}gP{  6_^_7j; \sBo>?bv(6_-EvF+J8r:A'zKlSn@1(O(ot$FAHQƙ: Qا" **X1GJ s$rG%RRR;W18p><G*"*PPŃ!%RF%@m:PFݐT4@$I& P ,$Ns%FY[K#ÑPB': vEtqp%ꪁn*WdzHqĮX4D/O#2 !x25̃)FpCDF 04FAc#4C 7"krS&Bz$us1Ep n 6 J3-f . wwHĬ̆+s>K1X ȽO! !h!{Y{0Dia GZB&cXV@V 8 yy +kEӀ`뀐<YM<Dha"6Jy /R/ ` P5D6@ [*6 dXo;H]j޳5 Ї %>Ii}&n|iʃ|÷|]b_~`Ob5$AC?R`F/ HIJ9&XvC#ȱ63M't)W'NtjVN)/#s: qTȇ3-E5S XqJ*l:'(ؕ$vpt~B] P*P)ʆ* T5E5K`)P-S L} 5g hF B&D\$1ĥ.LK AkdVKc."tY.OmtJitH4*8zqM*:蓢Y@ 4b4<.(68'č,nJ!%39"S|ęf n5)Н! wfZ-{$1Ka9>h@Xӽ ϴ[dXLK!R ,3=,G,6VxTQ 2*ZQ)f 4a]sa=68C/^2 @i\jxz6G`[M|z#75Vx'4v;5Ӈ] G >3@b{G3_d𥄾rio_ƣR|GAKφ_k~wI!aӟ.%.I#[heDrű q![É.䂔NJ=8"wJ&O9kʇX1+!8F! YNQ$(@5R">R>@( sMl@+CVRT2TE2UCV HQ]C5,j*Fj PG"u](~ƠQ=h" =h*X]=DA3h\m Tv.Ortt@H]f##Wzz+56 }_`@17 qid%pF (hgt18n@K69AT$´bVnsv)tfL=!@#6Hc.b74 Žˆܟ"b4x`,aXax4cZ*qh kOX鈭 ӳz.f hz> iM lݘ{>410]GI Y>O=6pKWk:$ qM]wCEǘrP=Ń_]-3#C!:?CBjO6]4 vBN\' pr@œANS@ސCN O\*( L HEcT,bJζQ (ʤ(kqn%y:ߣ \(/P TrHhP]$S[Bu$QA=|ihQ5ć m4uY.rb%j.@ C Zh@m]4E;Oq ;萢G΂].>]AWSWCbW+GFlΠO}g_!@9,i aaH`eX8xӍ"40ɇd05iťҸ];"pglw4SMDdVfx47"RaބϰЃ%ȴ@Ȗ$̃`iaE=r<* +m`ux҃[c:3gS<li/xK+>lUk`ڌ"քؖ [v {}>pC˴[b$>3K2Mow{hd_?Fl=Ia?ky; BpXCJ4H j«laqLȎ8Σ )rtRMD O:A^Cnߥ!Bi%Q$bET WL 9)mQAYΕH9#G\`|**PɧT\4Ǥ@5SʠGuLu=.4pF5Y0. \c-"2Vi6ɠd.Υ!::IsH.ҢI*.PՒ)X Mq SICFf@LJ`P5 @!#h7F 4ZAc$4VӍ>LMiLLIMT4rn6ܮ; 1]3 wE`wKf 4ۥ9.=%51[ӂsó!-^xR-6^k{=ilq5dLoZNL[+ɽ'Nga]!m#ǦOl|#|i*B{|o j;|}>h?b<:i~!?CO ZzfnZ8FJ8$JN:u "pNS&wDNM<)NK#t򇤀B:tEa(A1+D% gQ✘\ \t^ pA@%P!"%VɃ"@\n5=`=#P]C=h4JqM"t).b%iZZ"ZAmcr`psytȠ#"I"I]QW\JQCCqWCi=%+FׄZu rƬ_kd@B+lާ!1P b64> s/֗JS{C7|+w64O?`b O9#Ca4epDAY'@M9$wLǥ)Cpbw $ N)NSɓ`YM:ݣXA!*LSa"͠+.H SgQʃs6QT٘kQ. .*D`<,PTPTYnL ihh414HȅM8hR Zʥ6d΅\f\a  "f]|R &LjSOtg}F_R'6x40$|4$DC#2,#42F(b|ĸ1Z Mlt33iM Tb0-B( nC.LhFLn,FFsk)͗xvKioX$\YD{lpLr@"+$ V&*VKq詐0k!P:Y$s46h`cB="`x yQ_6 -lMm7x+#Ng ;iO Ňn$G 'O5K'%+^ `j; |o)G~I`?~ï\#C 8?5G;8":/!a@< 줘 miةcq y|n#`"Pi2H I1%uJqN5S&de͝ri' @"=b*IrUU5TO5$W3ZpvH@u5UOA jFB5P4f\@ vIB5Y4Z·V1Ҁڥh0Iu0ttN+ƕu覈"ݣ q5bF/qpKM}=AA i\!i ui`O70*aF+l l1·7f0A17 61&pOTi6nQԭ t{ҝ.LG(fJS,fG`N|d-H|Z(Z`HIdiĖ)ar(eJ1J,VGqIg6>71|!/W oR|=`>#$vO9_I R :lD[#dK6Cv()cR  'l281"usrDNI!8գc|"ȧ>}`lO̾|i}U׊&j;+?d/F?ȁL'?~ Di0?=KCt$YȖAv9"vc5t\ r t'tL'pG["QH4pT^ϥ%0(34P(Bgj଀ L1Sq F%dNte[Yӹy@򒨐-*%He@YUWTڪM- !:!kgQ_# j(P50MpOMC,$tq$L Zh XkDKm5N#̥1@ Xg].A7W!O=Ҹꥩkkp}|苣΀ 0bfO! Ѱ a1R|1#X 4>`n6MNc 0ͧ[vNM3]n=J10'3͏xroE`ahx@%.=(bT"p1-BG}z̰b1z<'R<)d6#M,֛6਍C^t饀^+M!zkcY-mжzMmމi| ؇iraw>]$!>u᳐|./5_{ }Ǐ؟`~Jg_,~~C0DO cp$bdK.1iqG'(D;)M jʓPE !N7F J4 YiqEaEhbmAIAJ98GuPNTTjȪTC.rP;u$R7!P^j"F@5FVA. OBvKtI-Z Qm@1mqO2Hru@bt::#2W( P\)) tb@pgLz!HZsw@}kOb`i  pFH`Hklui"6n&nDffnF&` ě*i- 5f#vGw· 2K3;f@yF$ؘ| d ^h![Z P,A<@;)Be y Gr@C+ GD1$Ja5=.@B< B k!x YH9 롌 Q{eh&M"zlh ekYz3foimޱ"#{1 G@`i7G!}O$g>}(lX_@ Z0(~@ Iq?;ٯPo ;8$ X G)AFvH# rJ8@# N q q $$i霎GpP3\*% ,E"@iEV J*PBIHke2( \4< \򊪀T@%ʩ &T5@ KMʨ qjC+u\ @ p@L@MB/M$ b(G51iPk K v#VR:3wH Rb]5 ʺ ;#6DTܵBw @}/i $ paih8@Œ4n1 RFg0ƣ"3.D%v#m7MhK7)hd*i!(V\ZڻHb"qWHf{5 (i6PIi̓|E,Ƚ,4 !{K3xYe@NG2X=jx aS<=@ΧgyzbJـ/ 1^ Kzx46ݫ{M!_6{ES[% F7@coC)8؎Dy$^vj}||v!(";@F"9)Q@doB|P}'5}~ !O9$xGO >Abd5 &!K9 XrR9Y1(7'$Wbtz{PTt L$Б#GˠxQ%#tJi*LDsU.$%p+$**TUKIuj$DMj TGaBP?f УF!k&).t05ikDZ%X٥vk2.X@St򨳆Q]u%B- ÅmkS\g> Dx0У)aa()Fd02li 08 Oq&(&&lLДLlZnUq!؝.M7%̀=Rlh1 {E܇Z/E6,$`LHg)Lc\c+GS `v#2c>Ad>r>>e@ X| l}ppPA?g8Z;$a)_@V߲t  [᨜ $D.PId $XnT$i?)tX"Vt"ΒTa"R4f$V<%Upp6P  $%R(ҹry@LΗ(PhbBUʠJT @hۨa)Z B;BCCidA]  .I]KG-i SQ@[] @D!h2@a!muLN1 W  @) &WitJjJ/һʹI]mH~^$5 +zZ0x2l@FF46@rc 7. @܄&P$dMAd"i r&n-n1HondH`RO@zt -!6=xB,A$PK!vC+d9Xǀ>">1||u}*}hx0(~D~~o1=d@)8,ȟK]8$DV&@vAr c"SQLJ䄈PB,Nd"@4Niu/B$G 8ˣK %2( J).IQV3 RN$u Tr$ب )USPuĦG52NQ'1goh`PFDrL\lj@ ZZ AkH Ũ=2 @:Š®T\WMuUH3^>]ҵuAe_"`z&0Fh$@,FA hLD0.)nhB741$7d Sbjtv`iw٘=Jc9Ѽ4h^MݏP-J1x%<`FxiPȣi%4\CҸMC,FA\bhHEp 1jch K5΃.]f< hdpE+CA\Fw=R\m5u.o`-)fK[ AdeFx0274J1!Ɔl\ƛnЄnJcbIbS- tKnMp[H4fn=l\,X`q/rK CrO|Zlz BK2x0D9X*2<,G6Vx(Vz*$%xO񤃧\ZO{Ng z lhc ^e^a"`^7maKlgېF½xۣwnv }h˰[1y:L{' %Hd_ [}e|/яiAEDWe!aG.O6 d7168ΐ3" pNL\: l:ť:Ր'B(Gln#K%tF$pJHE+@q>(@eQ9K|.( 6*ڨdr*.U͠ 5bT3d\Nugo Ms]>\jb:f]3]2 8fdP3/}bE Eb@m &XnbJsS2vO@#'&K*oG &>+͆J?b\A"lPZ! 'a G)BE)ȂPThXtߐXbSc H)$f I5$c,9I%6QI#d` L 9j"ˡ˥cC^, PPC! FTqVJ2TJ[TFGYDʻVB%*k|J5:@Z5oR-:+z.Ҁ.j$:8)1kA%C<6h |ڃu𘎌u3a]=E XOzmQ} 30A: C- PSH*c,k8MLi"IlbT R5pYCau4єR3k@K$J[jmHG/tn..*SG/B%}G?gL l 1Ă6 #4܆SaQF{ 50xIM&!)L51AhM`y2! X,VY"ZaJ2ZI̭U6 jnv`;gb`$ۏp_;aG|(p1oR9tN: u8 #\$t e] n8&vE9|Ca@=q39KJL6{+w: |A.O  dct'BCH40p I`(M<(GEUC450eˆ] 4$,H J %&˒K* i9H^p2RD2aeH6T_ɡ!'C\xX^ِc (T(;RXC(>UJGi*QR&ꂩ&RjeJ}5PiHGc i&*-8jiA+ϵuP;ګtembn z*2D}oM i U gd?Q*a8)M``"'|dOL0բi L8 \5Gay6hXSY e-Yᒕ cVX〵6c=U$Q&lvl`d[#v:lۃ)A|`?AIM3tT$w Ntig9pNRM\pE\0rU5A馎[6V㮇xGcH=4K{t썎9=GO/}EqO$u  P 2@H8›YD t"OhHtb`1 #f(6P"$.J@rRTH4tk,2il > grK(i/D q;& E=8*PJR]PƂ+ >UJU fCuC5P@m1Q'*,jM8h4@sVj-6hgJhBn %уzKGo 41Ha06D"CmfpOɍ0Jh`q WSuLrd)6L4 :f02Ӄfli'-PXH`X"e>HmJFVX 0Hg-fG=bGmt&la VevO)]v>;a)t CfxQFyqNZtʦ>wegs.9 >qe \6qņ:irXrS2pu=JX{cA<T2 yn +kz >K>C<곀8쫎o*?~" XP BnBS !MEF`Q!â6F $+$a B2BH(#}"BZ(=AGF̌d1D6 G@.<.|&S(  (LBQƊ1RB J(EEe**PBeUPU2l0Q#u'ЀRCk4E!5ieJԎ@@:93c]Ywz >H_YN0ЂA&cC 31HiJdS2$l)*S9a*3-ae`-h۴KZZ)U@XF k]hZ/ m [Q.vұO~/UpX:p ';eiYsy.XpQL\pUfuI*wLq*4H'*O)=s!B/9x%Jomz'>xG(}V⠯:)|G ({@L0΂ QHI2D,,^!D((XT$#a1~3Pl8ĵ!H&!>C[DR1D ((R)JPz $Q%BfbAVl.>e(b(/*E8)J>T)X)JU( !uT TQ Ta*R! PSB]@M5vXh*f 5L Z:Eh^PsutTg aQOJ V# A %1PÐF #)X4Vac&X4QaU*i:[4CeYfkc`.GlЂE* ,RKa7Ga:o`!i;ⲣ:&Q'Si:y.Xpe4\Ʈ$n w|=MlzH鑁ǜ<S)$ {r΢g䫉o; ? A$T!\%DB+1A%EYGh B,MQ# IHb I $X RjHe"4:*,= H&,+MGvB9(DraUpP>BHAR@%TLJrPJrUʨeKʛP2CU(TETwA H- X]깠&jlQkfAs$Z"6@[!m d3.tЍz^DX?`@ va iHQh &Ʃgh&d` 02U4LWddCfs4Ge.6O|(,ԱȆŀ%RZ\ +=lY#Ql6uvrn+}&:.9p؆#j8FdNP:C8k9<E<#]r!Wku7l ni-;*wwς&`5|T㳉/aO$P9cA e(@B*(4#a&1@)H"[h:c1Tb)Q!H$qK#)d ɑ TRci,Jk 'mȀe4,.*l& X. XWC>,+X! V)@Q,*H:qTBUrQeU&ՠTSjsTK hĦkF9ւHk VG;N3A#I3.nSaI } C`@lcFh FJ`c9Ch(70$hM1fic\a -pBE:Xer+:Vl5Z (gh#M [6d ;vrˢأcKWG gtHr99r1k8᠓q!g: t'\p]U:rMlEw=pCI=2g_,7J]@ vAF ! (f C3@DDV"11 T@,b#&Gx@B &1IL$ŒI"L*JCiKtқYFLȊdC[DNb,< y|H~ T !+V(Ⲣ&(RB$R&J#eʪP^R)TATM:RPMMRGC] ,@GcMTr@s @+(ҎP{:8#N:[ԅBWuú#=?SHB}oB`daJjhc(Uxd&lb SUa3,fKlD暘|,0E `1 Xt9rا0t%TS8a)43Ysu^E\Af:g7L$pK0qG0w 3pF:{ Ǣyi+^kxc[ɼ3g>` }R/|w  @PN!B2!ByLh au(<HDER <-â+Đ\LTb߉sqH< H$I J J)TR@) xTZL:PiU2H,+R6Ʋ C9KxF^a䷨  q; RaE8)3P* 6P+3Q 6UTs-"*VR jPm<.zHzH#B&*MLZ0R@Fm=XuY ]8*n.nCz #kS?00Pr3ECTjFiڟQ2ڢ1 aEc&)&`Კf1G`>XD`%Zfr+R*[Z[G`= FMflEaۑ*0>rE1pptԆc 'pB'uN8rV . ꒤. Wkq7Pnt 6; wpO}B"#y#OysFq ^W^kxEx}'O}WL}'CG@EmkB!` PP  eLA!"H6D(*'<(:1&~c(D<p%@*It$e( )lJBR#it2`5dҐbCVl&c98I c"|sPDAT~@a*JJq %,*PJ4R++r+O*qV* UL5X jjPD=u4@#65QiGjtY+ m,hiu QJgJ],jAw =$ӇzDoWG?5Pa`BC 50pFFpFRE`41i &26dM:dt!.a69| P" -qRNY܂JV[Vs[:6pM.L`VN!5Nv)VCi}ۏDZ`sGc* 0pRYλEu\B.3rJ隉nPnp} ={=vOxF9'ǽd^1ڣ;L}'>#_,|sw~/`cA 3B$Bha B8) ,(D(:C!1%]W08@9 )%ĄJjA2%$D*Lj,KHgAzIe@2X&AeDeLe@`9rِ[y$e<$?#$U`~7QX EPP1'TB@%(%XP9ʃ $@HUTJ`:$T  U (ԧЀqkQSA4Ch|%VXkɵ@G[@.ণM<3.?\wKX4ЦA 02 HiFOB th51X6^`,LRliN`L q\'-pBiXK|j,`JYej`j :J]FJ\Y[\vd?8``CX6pH0]vD"Gv NH$SN8Ys.9@%벆+ \vp-MQk2>z<7c/@^xe(u;N_>r H3.bી ⻎*@`$BPDHPXh cCX@,DžwA"E9DD4 -#d~3PlUgQ|ؔeTs$B!%T:R[Fbi #^R="d2d(+'eW!r!%G!/|@ bLIaX1X Pi63P^1-"@Ց 5]V XeEU!c<&HS9:Z:6 u0I ]fQwzPziHo }0h  ⢡>4pF`R(Fccx 4Ir@ST7cf)c\lKI,h_QZ08j6DrWࢍ6mRlbVdvdvO-=հ~Le -:#>w Hǜӄ,;  ,rx|*@X@unxM m'ܡtWz㡆G@8xj<@^kJoRykL}H# ׾S ৤H@]DP@,G8$pLhAD8B᱈" .2GQ<"d;,MC,mS*D$D$J@r$RZʦԒHC!-%pEz2H 2+d˦]%BN\FXWC> PE} XQaJP+2HYr* HE#UpTR]BM 񙺀J=(է@!G,hL Trlj R0FVG; D'uVG]n6u7Â^C}-}9ࠁ` C \E.[a2 бReYZZN62Ɇ͜m6{i`@vڃedߧ`ߜÌ!pT`L)9ᬉs* . 2#WT*\#tᲛn ]qr*8yL艆Qx^!MV;>p_=@'\XA4% @ !)Xha gQx6E(*! Đ@L7Al,cq]x@BK"%$?2L!RRr K X!(2 , J6rtX. .C) ?W G,! Q) <CHIJIϕPY rg*UBY jYm!Tׂz6g '44Є5Z --jVhc(t\G$Μuan{XzG/gԟz B) 11Ta)#h,05{`D[(L&4ET)L0cffh sMs,a1CKt,%Le9pJd5Z i!U6 f [/pC7r; TxD᱀ O}M)c /Jkzwޫ|@>*|.bWF*?- D`, & C!5b 40!9 H$(>aLDbx@L~X, Gq/.%&$K" %),G (KRِG I Q! dqAV d(ˢ>yQX!S* )@1J=J2Rac*PASPETbUlj>QjeSm ,4hXGBM54\ -H+֒kҖR;:JB7c=?lKCoL_h 4Hr! ,fpl6i\3цI& hMS L`6l9*s90YP"N[T0˰*+4iXk milU&i.Ǣ1_ ;Hov Gc:#'4qʢOPTAD#16D\H /Rb%GRpRG* ҘHkQ:sAP9ʄd*l АR.$7<*Sɏ@aƊbŐJTDi(5PYE *[PECUITS#Y]KCm:yH} 44Th$*ML4Śy@sJ-Za q@[ (N uVbQWn;?*4XW0T_a`C h `$0(1>6Va )MPdbSML0LYfk0W< ,`!E_Zf`&V"(&Fa֙Xࢍf l1؎аS"v؃U~a-#Q GN(R9pV#.bJ 7%tK6Cwp}z JMJꙀ+#^x%ׄqޣ>h'F>*o}W5@6@A`&!) #a 0BDIE2Q / S0B"loSJ M$b(1I$.'LQI+tS` L2&.B6{P$ra<ڐxB~Jl(h6P*TJ"(6PRYTPETTYcjP-%S+4pXCjИ& M=?ZzP+kH[J4WD'.at@7z->::Ao V"* GF6BFS0c9d& h*Sljbf(lA%0|Y |d!G(-%:`X dhb5j)'6Ib3C[T*lch v"m`$R؇7q_:"c\pXGp1 N)촉38' pI \J]grnYt䞆xC,xdc 'xS`s^xK 4v"|,/|u7PԔS `K`, 1e!P&BcQX <.BD):H"EtDb`1U~S%6P\$pXB4$6DILCrRؐTJmS!^Gd4 H'3,6esAv 9tX.RO (dwA(⌕M+PP *R*S T稆KjTK6Cu(H=էЀ@CFYИ&44WhaB+ZskKMU:XБN&:c] <;P)^P'6 cG 21! %4̦ #FaCFXY0LR,)::`M1,9\9d, Pe1GK\2d9[)U 5Ѱ:w =nۢTc;4h݂CiKA1v9j1:Nh8i g8; :g\qdⲉ+긦ẉ*tV.{*X%)g ]B%W*5Ax`>|2}o!j (u@0BpR%Aa \HXdQJ ID~#@Jq<* $H# )%@R ɐ䌤АT VI#t d\FJ8,e(#S9@@N\-0eLl2STd:c31|)|~|'@X`Ƃ (#<*Bz@(Iv@  DLD,`&MQT!&\K!6 P<(> YXCI$ՐLGr|&(%H*]RHmPFBlA,OdXv 94K@9˧! TB>.)QQf($V@iA1P)GH?l 't  0JUF Jh(FZ4΂M1S0X0ͦAi&cٜad.yO`"KlZ2B `%UZaku.[\Q, Glle`g=d;% {,sA𥃂9dⰄ ;pܦN*b4GgTb \2qU$pt-]sU=\S g>ga׀ywWG (|_}G}wtI@=w2`K$Ԣ`&B 0XX̄"mD `"J T%pW8X_QJ!I\GyHr`$@R,561tclAf ea,+p\6UrPI!`r[P~)@ g]PPQ (cJ4Q&H1RAVB%T RUG5.cj3P+zD}<ZC46NS fh@icQ[ShuPH%օ@WFzÆzQkA? 06ІA a( 62h qX0^L"4Y Si bLfV\ -P"%[c9*Y:װAe ̈́ [ulCSځ4 Ha7c{, >S:rpGUI8rBN rVᜤ+\"ve ]Qp 7mEᶆ;*wMS<0P {<yA{ra8SGm:1-8INag9r9o₤.j\&pE@WUtMlAw<.>sC3_6}@?S +EA5 #!UBHa¹$<'"\$E! QU!-7X*8H\ .G$TB$ kHA!B*K#J# XFd2BYIv rH.J. m#ȏ;‚+B(RRR)FTVrwIU@C%ʂBUBՀ@ `&Vˢ u\PW`8`4Vi⠦(4c -m- @ܵXN uta+n>]=t䠗XjQaÆ&z0UFhGFZ4JeHjq2$%0Ee*5tA`&2  8obB-"YcK=h,7†.[EhXYzl0&@l3c[[BئaPi.dHn/}.WH/A; 'LϜ1qV4'pG]+\p ]ܴ v[w,KG>#zl:C0A\{e`=*@ l\e?- h(@6FXPl#!P ,F8MDpXDF"i DM%b(☈kA|$ .[D0I]̦ HJ)Jz,`CFerQf l.nC$'Dnhȋc,tH!w *RTJPB)T+kC HE*!*ZP J ԤPK:zi4TcM$\39G-ZZʂ֌!GihBGF:sŢtT_ LNPAl ! 1LedFX'3 xhRKhMpDIM&s20iu903 08bCsS <`!EY 8d-Yn [i* VsF0kMhmpFI|l+hpvہvq' >/:p߀!;J@8pIS gz9 tg. G]U k tn:n3r ҹ=pC&DXb J2,9B*ƂSHoC>3@de$` &g9)Rȭ!#@ wP@ E9*fQq%T(eCi+C1Pޣ*8*a} U)TgETjcQ] zDW5Fh5wQ ZqZ0me H',.Ӄ?/=/p|Vj7wA◂߀̯_Fu3 "(!8! %Ih,Eb|Px8DX$Dh#1 iP,-z@ x@U:*jRjs.H!&YSi9BCKBZOj@m9NHg8]4tP7'^6!U 0h pA6 0Ð.2 eh,6xA&LM3t3Yf0Fs%'| -4"-f&|r ԰Y#%؄lEvavl 5>䀠sppr9 gs."v ]î7]6=}C!<1S)/4dJ[ u|>S`_]݀i/)(M&% @&$`& .(I( M ) MA"IYPJTNlab9X,@6H!$%,X BJ,H2J XFL!p (r# H~(=01YQB1 JPIJPY+KTPIR5Z*jcutuzH}dC`&i96hAm$icހ:!.&誣]GF=2d}8 H4cC-0 cQv1?*'` 2ѠI&cS468L,`sy*J[` [FYbU6h u6(BllaMv;Tv)؍ᴗ>FC:KrT1uPpҥN3qy] \4]t]qMu n66gHa&y"S = /%xǼ@곃|1W9ߐax/lN]̯ i$0  J f!Z0B-AHK$*\4 1 b,6GP\A%I@H `Id R )MCjArH' QE&l@,+MAvN9rk|6/AI L!aEPP\P `HI9XJY( pJXW&-Td5RPDuTUPOA}JJC 9Dc㯠 5uf&jǵ2Ik 3=XGJ'tA2f@wF=%a_2Gp 1a60 R0h1FX4&Xh"$l)TII6hf:,Fp9.7ץ9|[,TbKlfT,J[2\n $p@ [ $r;r {} #R1: 6 8O .1\1*k:n&ےpW=N< <4#=v'> 1xNyaW:^#o4E!M'ه|W }7?_~c_S?(Iq") TQ D@"20mEETJ4Nѱ&#&".K%$$2AbB$dHr)TR#ilVt7ANd,3jlep2uq|w Tؠ"6+*Jؠ$TPZ2 "w :*jdQCU&ڄ:X] Ϩi_GM43ZX%֊QkXhϠ&tхMAwA=^6_A 0FCC Fӌ4h7+8lAMd (MS1݁fX`&a2Apb,THb K8-%,S[+]dZX09ml4`( @C=zn+F7RI#-&w~p㗅~#LP@X@Tp!<$$!MB("E$Idɢ(bRGE\FU$Ra%KBI S*Jj iEY,QA&].  ʎАKEnJ y53( (hB”"5Q18J2("2:D9 TTQCUj3TQKAmJz*;@T46_A 5U kH+ M҆C[#tD:1uun&r=. -Y~1@t Q00 W0BHl2Zc $/`6",6ـ)R4`es0," XbT, dRZl-ae= 6HDجc &Fَ@vr%n{};:18L9Ɏ)8nqN9)gLpրs#(vWk7}-ntk=}Hc`'S{f { Ρ`_> mo᧊_o_sm4(!0 :Y$BB aa8(fD2Y KpH,1 .$@jHDI)H20(TH1\ e2#YYd( rJKEn$y].RRH@aAELR)F(A%(%R*J3(C)P HEUVPŠqPPVPhF*cK4%4Ԝi)I+6Qm` :ԙ몡zOR[>5ҟ0jb0aņ0m22hc8U1NxFl0D,e:f2M4 / M%:X [a@U8Yh *6la6hr;Bv#`/&i 8Atfp&GUq '243 Scp^Ed]\7 -@HtסQ[pcO੅久^pz^xou3{>A}E7߱Or8_ ?@X@ D@Pl\ARE($4!,>" p.1 v! ҌT1ʃF#cf,3-2AD1 6ɦ:4N%$ͦ1h.e6_BN Xa &[bV Zb 8FulA:6 ;;Ұ[H9 ࠋqG(G)7$*Ψ8b<Ke䊍r\n`7%wxrLؠ'yj3 s{aK4f;{`}r*7wO/oA Y@$ #dAU!P6 p `DB"{XD&U@b:H,03H$IXEKf RJCj X -KO`2!,XVdwHF Zž(J#)(ΨA%)8QY8G*\ET UHMVˡ7Ii(A#HFM),i%ҊҚku:q̨tc"=b @Q[lC9 0#dAc5#7F-0 LBjif20Bs0_ MHbd z2[h [ lJ`Flƶ [l]4.Ivhg9 rB%8%3Nv9C8kspvppIeW@&:vM,rKmrf4<{)ᙎ@+A)olV;F9|>}C{?-oI00~@1"A4,Bp %Åa]5DHDDQUG4,:CL$ +Q<$$`PG"$$&H*(\C BJ,!#C$+!D-SNB. HFLX 2*d EbXqA%PPڅʘǔP^@THe U4T@5 d$͠IڠISPJG5v41fH ( m j kK>:b:"]9tS]z ePo} KB%` !h 3h8 F4058lI&9dLlL0ӠY fGH3ϥn ,Yd&Zb2dd+d-FgF6Q6Bيmh; 2'~:`ApÄ#'$ tFry$b']ft긦:vCMe[x]NWx x |y♎{%k䍋> >pd*$߰ ~P~6#/5H@(0DEP,BpiPXh ap[ DH"K!JM@tIbrF q 9$Б#K$CJF*Ai$JAPFJ&F9e(+!GvȁDr(7<P+ȩ%(bbVA %]ҌTQ9'TPPQE%H UMR j:L-Ep shF6il?ăf6ib-LԒS+<5 @ȡbH7=4KEos 0A&u 4T0=f$@1B,2#&l2)SL5hE; 3]f.50O` ,,hɖR+tlBkOZ g &i͔-Vle;avvW>d?v9(rXGq '('BN+8C9K9w &H\q5s&[ n莆=><{LyBx</4+{ w+}4EW }c%~X~qbU1"ESBBbVրpACDBd QD saba qĕ > I!)%R ) HdudL*2s0Y-M@vr(ȩ"<&+(HBYb*4TF@Y+D$LbUTC@-W[GzRc(h4R  MLԔC3͑ZV5ktЉY@B7 tKO`X/m>8X_ \ @ b4BCL6Ԁa {dD4lcm6F 6hI:&#S+oQ;>ap\@eT`fA` KBGHB(uš(ADXDB$ (X.#.%H%tD*sH DXrJ A)]&)i6J'(=eRQY= K.'0]. `* ؠBW)b>8) \Ҝ0*Cy@yX%A=U)8UGjHTŠ6RWE} \d(_PM 5wZZ;X[J;7d4tɺyDw=,e@ 0a1LbPN hFr`ƘldL2GLP0`ɦZl ff2Muyd a,,ue?3Zi%U:V+XCXCcl԰ ۬` m8NN\n7^N8GPp8aNG\(vp\ 'UBNS(8#WpAEA$WaW\#\n0I%m]= tjD˰"+U.YCX#װ&ul6v;"1`/rAAG]r\ ӂp:qf\qIeWku[n#w&=< K{Jx=7 T;IK(C|7U@~~m~T )c aQX$6 "H:"#Q.h>&1$8舋ē, t$$ sHbdSRD*HMH"$(dbYAY Fy=$$%)Q)(VRJHPRA) eyDyTpJHe .W h j9Xmꚬ;P F[ߡH$447V*Z jàd9uPb b]\A(9$RAk~ i0!Z`K g4"1rL*&Q&0ET$hd3 ̖daK3|Yj i\gD m!l5h&فh ګc8 A38͎! 8Lvr9+9 `*..B\3ຍni[ wp_CT<ƞH#/^x㍊N{>|v/@7nOF(& AL@؁! 4(Q$˄cC"2"2MG 19E⩈$PE"$ aRRzL* R(HCehL>"3EAV";y9lɥ"<*gP~) pB@HaE4TLCqRJcer*o >"`R9U(U]:0H-V[Cu9Q_XC58TS-(-$)mEhu tT lP]ut]A=UBz3Џ_ `AC8 0̀ᒍP0#F9h0; -2IdMji2H7f3-40Ӱ"#K$[`ܠViXcuzN$ڈmⴙm ێT Mc^>d?b4tpT1p) g<欆sqr.v 5tt]`{}4VSV+8Rʨ(4G*P*z\%mVS5$5Ej!UԡUPϨk WЄ"(%h%VZsj!::$Yg]9t3Aw 4A/N> D!!0a62hlc9d &"8M&L1h*efxL,d6e /h"Xbt,gBJ XcYl l4&M۪` v`;]n{8>~(Cv#1:aSi*8G8.q1WLrգIrpp[;rg}z!G xᩂg=G^KRZoU3 >phO:ી~)_įqTt `A9\A,AHapXx$E@D5A4Jt#Œ(6i MB$&Ib*sJ!(%AZ,HF%ˤ ,lr 9Mk| UbPXPbJbLRZ2 JUArFB5}X-uԓ>w&*hFhn*ZQ0hkP;=#NXrfSEo}T5_@` "P02 aL`IL04Sf0I0]`s-6OY(`;IVl5A֪XGXbe#al1h+mb;]Fd}~dtppqsNN"\ഇ1Y_[%_U[H?H~~͐ ~ sATWI/R_RPdɐ1mwߠQN;wl׼CNm;t߱{ڶߨmmtiޡs7ضUTֹY6iwN!5jnA~PKI{P'OY232eb5e3e-f571-424d-bd94-2e56e0347c98/metadata.yamlPKI{PA232eb5e3e-f571-424d-bd94-2e56e0347c98/checksums.md5PKI{Px)',32eb5e3e-f571-424d-bd94-2e56e0347c98/VERSIONPKI{P'OY= 32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/metadata.yamlPKI{P=b0n =32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/citations.bibPKI{Px)'7} 32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/VERSIONPKI{Pdq bkl 32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/artifacts/d11e38c2-e1a3-4e25-a08a-8c226a7890fd/metadata.yamlPKI{P=l l 32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/artifacts/d11e38c2-e1a3-4e25-a08a-8c226a7890fd/citations.bibPKI{Px)'f 32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/artifacts/d11e38c2-e1a3-4e25-a08a-8c226a7890fd/VERSIONPKI{Ps3fJq32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/artifacts/d11e38c2-e1a3-4e25-a08a-8c226a7890fd/action/action.yamlPKI{PF.B32eb5e3e-f571-424d-bd94-2e56e0347c98/provenance/action/action.yamlPKI{P,k 2"32eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.3.bt2PKI{P*h82(#32eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.2.bt2PKI{P*g/>(@2632eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.1.bt2PKI{P42u32eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.4.bt2PKI{Pu$8632eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.rev.2.bt2PKI{Pd"C>(@6e32eb5e3e-f571-424d-bd94-2e56e0347c98/data/db.rev.1.bt2PKtq2-quality-control-2021.8.0/q2_quality_control/tests/data/single-end.qza000066400000000000000000000205421411645176100261120ustar00rootroot00000000000000PKf{P!Irx29f53ceb0-752c-482e-ae92-cf2670049957/metadata.yaml%˱ ᝧ ,"k'MpC/l15kk\0/%^'i>ZZ5#9b z'*D)·$?xW,sXy PKf{PU͓L29f53ceb0-752c-482e-ae92-cf2670049957/checksums.md5nA Fy R_%"UEjc{HMڒ  lukbRQpex}yr⥗Q\1˲tEa,X3 ȑjO)Jv1TtY^wnݼ|XZ``fFlPϒ n.T-JA.~u[n`>c=xzY?|]y(V[1@ D:r D&Υ(d?<z=X\pĎF>|K .!۝{:}C/Lϓr {4u d."7v7PKf{Px)',9f53ceb0-752c-482e-ae92-cf2670049957/VERSION uU0J,J,KR0J+JM-/ʶR02033PKf{P!Irx=9f53ceb0-752c-482e-ae92-cf2670049957/provenance/metadata.yaml%˱ ᝧ ,"k'MpC/l15kk\0/%^'i>ZZ5#9b z'*D)·$?xW,sXy PKf{P=l =9f53ceb0-752c-482e-ae92-cf2670049957/provenance/citations.bib}Vv7+$ě^ E"edd[&Ɂh,(c X P%S4 Y/犿-,5hW)>x{|m]|;2jú#NH ҕˊMqIRIT`ՈQ{ >2k57fV:/zPp=II=g4v'gd;+Ⲭ Kj"-\MwZ N-94Iv$g NUR/W|:b[0="nIYJ\=5/di;6205~p}PHW5O6*G;&1:n_R26/%Hg V7H1nU*sleyQAбT[h*"isNGL^<Nv>biʌ3S%ԄAFޗ\IQLfFI&4aA~&.=3]H ΑdMQ9 /LQ Ã-FjY{ֵyL\MwKvx^dbRtˎB"Ue gGFuCUuuGџ(%[}]_C SV)`p*IYzQtdSGMa ̬U?5K%X4 # phdhcrybB(o$Lq"4!3=Kԯ<%yJ3 #*C5-%Be!&3JF%k'ti#C`[LkӬaXqz,*sr~etzV`quO=' Y;&x X%zib e-A{rV9{Ͽb@u)v*g,}vY\΢Jܣ:phV>n sUskf4,*t a"8Y>^\NA<$ġ~>=^h珝;;PKf{Px)'79f53ceb0-752c-482e-ae92-cf2670049957/provenance/VERSION uU0J,J,KR0J+JM-/ʶR02033PKf{PW^nB9f53ceb0-752c-482e-ae92-cf2670049957/provenance/action/action.yamlXKo8WhOd} blA%5Ӓ(SmoRv{7k 1RUw}U ns8rqʂedn[䐸eNS*ߏˆ˱Sj~~נ&A=%`PJtu>_~,vT4*, "Z Yǐ&!˂0%zZPEcۼҕeiUEaG~SePBӌ$5P>חyʫ_^'Q쓀iT1ZV4*dnDH1>D~Y%#QH`~Tu D?h "qQZfCJ bK%04ǟjo"5A3./IAWBh8l-n$NJVHhM?jhMs6@a`33K.&g쏡ma\4=xT h@'2| `mx77W'̈LΙߥ ^qݕm}Iѭx, &BI\p ط+؈ǧ}ۈbd0Kz]Z/ ! Z%`JK]&r%+9,?HqT0h[Ҋތ.\Wy3/Xzڴoв =ꅙWA4X})bq ZTS36Y#`dnyl}^.{&*4A#KR%L$RǞ h柸[]txbՐ vjf ǥMsU.pJAa0pڜa]e_p+W#^}ϙD О&!u4yWV~2،J[70숄=zJ󪀸['U&vL L*Lb"1=pksBv*P`{ Lt 6-@`z"4]t5fF05B6ۡaMxxyg]d`:$i)%%RET>>-L(!jj)?s\OzHŧowC_$\jͫ>t{, %:,v4\w XOoxx"3߰:ɚ3}dƟ..[=S{4Z̗=km;P/%c- Kz1Wi{+ujԻ$Ftf vEX2y7Xޜi2XbPp\8;"QZպN;{ݢs4LG. i(ƥD- Wg]/l]Fzo3("+5"KW>ӱ`E99?fb:/ YJ݄vK#VycuOp>J^*\\D\%N2_\PE_q ;b}'zaZbP:}PK{PAxsK9f53ceb0-752c-482e-ae92-cf2670049957/data/sample_c_S03_L001_R1_001.fastq.gzsn~^sample_c_S01_L001_R1_001.fastqAr0 EF]$l*,06Y?=LnZ-JHw>۱m_>ޗSU#2L#;og>GwNcV6;,ُS͌EL:ZL%0r+XG`ZOۆh<Oo2:;~'u9PRԌL<-0 g@[7"",w z:dW-y4 }-]]ڛk*u?,C [*5K X{Lf1퍞])^^c`WUY7{z6C 3ɐ؜v:9SP.΍{0h_Xj PK{PxsK9f53ceb0-752c-482e-ae92-cf2670049957/data/sample_b_S02_L001_R1_001.fastq.gzsn~^sample_b_S01_L001_R1_001.fastqAr0 EF]$l*,06Y?=LnZ-JHw>۱m_>ޗSU#2L#;og>GwNcV6;,ُS͌EL:ZL%0r+XG`ZOۆh<Oo2:;~'u9PRԌL<-0 g@[7"",w z:dW-y4 }-]]ڛk*u?,C [*5K X{Lf1퍞])^^c`WUY7{z6C 3ɐ؜v:9SP.΍{0h_Xj PKZ{P~*29f53ceb0-752c-482e-ae92-cf2670049957/data/MANIFEST;0 н* `Dn&'qaD,rphx(b Xh(bo !0rmPN:^ `ֆ2- Bgr%I(΀L@PpNuG]n!~YM\4{JA7yPK{PZAxsK9f53ceb0-752c-482e-ae92-cf2670049957/data/sample_a_S01_L001_R1_001.fastq.gzsn~^sample_a_S01_L001_R1_001.fastqAr0 EF]$l*,06Y?=LnZ-JHw>۱m_>ޗSU#2L#;og>GwNcV6;,ُS͌EL:ZL%0r+XG`ZOۆh<Oo2:;~'u9PRԌL<-0 g@[7"",w z:dW-y4 }-]]ڛk*u?,C [*5K X{Lf1퍞])^^c`WUY7{z6C 3ɐ؜v:9SP.΍{0h_Xj PKS{N({69f53ceb0-752c-482e-ae92-cf2670049957/data/metadata.yml.(JMOK+N-R06PKf{P!Irx29f53ceb0-752c-482e-ae92-cf2670049957/metadata.yamlPKf{PU͓L29f53ceb0-752c-482e-ae92-cf2670049957/checksums.md5PKf{Px)',d9f53ceb0-752c-482e-ae92-cf2670049957/VERSIONPKf{P!Irx=9f53ceb0-752c-482e-ae92-cf2670049957/provenance/metadata.yamlPKf{P=l =9f53ceb0-752c-482e-ae92-cf2670049957/provenance/citations.bibPKf{Px)'7 9f53ceb0-752c-482e-ae92-cf2670049957/provenance/VERSIONPKf{PW^nB 9f53ceb0-752c-482e-ae92-cf2670049957/provenance/action/action.yamlPK{PAxsK]9f53ceb0-752c-482e-ae92-cf2670049957/data/sample_c_S03_L001_R1_001.fastq.gzPK{PxsK>9f53ceb0-752c-482e-ae92-cf2670049957/data/sample_b_S02_L001_R1_001.fastq.gzPKZ{P~*29f53ceb0-752c-482e-ae92-cf2670049957/data/MANIFESTPK{PZAxsK9f53ceb0-752c-482e-ae92-cf2670049957/data/sample_a_S01_L001_R1_001.fastq.gzPKS{N({69f53ceb0-752c-482e-ae92-cf2670049957/data/metadata.ymlPK Xq2-quality-control-2021.8.0/q2_quality_control/tests/data/test_evaluate_seqs_identical.tsv000066400000000000000000000030611411645176100320170ustar00rootroot00000000000000 Query id Subject id Percent Identity Alignment Length Mismatches Gaps Alignment Start (query) Alignment end (query) Alignment Start (subject) Alignment end (subject) E Value Bit Score Query length Percent Coverage 0 1111886 1111886 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 1 1111883 1111883 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 2 1111882 1111882 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 3 1111879 1111879 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 4 1111874 1111874 100.000 250 0 0 1 250 1 250 9.18e-132 455 250 1.0 5 1111867 1111867 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 6 1111856 1111856 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 7 1111848 1111848 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 8 1111847 1111847 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 9 1111845 1111845 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 10 1111839 1111839 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 11 1111827 1111827 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 12 1111819 1111819 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 13 1111807 1111807 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 14 1111783 1111783 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 15 1111782 1111782 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 16 1111776 1111776 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 17 1111772 1111772 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 18 1111768 1111768 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 19 1111750 1111750 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 q2-quality-control-2021.8.0/q2_quality_control/tests/data/test_evaluate_seqs_mismatches.tsv000066400000000000000000000010361411645176100322200ustar00rootroot00000000000000 Query id Subject id Percent Identity Alignment Length Mismatches Gaps Alignment Start (query) Alignment end (query) Alignment Start (subject) Alignment end (subject) E Value Bit Score Query length Percent Coverage 0 2MISA 1111886 98.800 250 3 0 1 250 1 250 5.52e-129 446 250 1.0 1 2MISB 1111867 98.800 250 3 0 1 250 1 250 5.52e-129 446 250 1.0 2 8MISA 1111783 96.800 250 8 0 1 250 1 250 1.20e-120 418 250 1.0 3 8MISB 1111768 96.800 250 8 0 1 250 1 250 1.20e-120 418 250 1.0 4 10MISA 1111750 96.000 250 10 0 1 250 1 250 2.61e-117 407 250 1.0 q2-quality-control-2021.8.0/q2_quality_control/tests/data/test_evaluate_seqs_part_rand.tsv000066400000000000000000000006471411645176100320440ustar00rootroot00000000000000 Query id Subject id Percent Identity Alignment Length Mismatches Gaps Alignment Start (query) Alignment end (query) Alignment Start (subject) Alignment end (subject) E Value Bit Score Query length Percent Coverage 0 RAND1 1111886 100.000 50 0 0 201 250 201 250 8.29e-23 93.5 250 0.2 1 RAND2 1111867 100.000 50 0 0 201 250 201 250 8.29e-23 93.5 250 0.2 2 YAYIMATCH 1111783 100.000 250 0 0 1 250 1 250 5.48e-134 462 250 1.0 q2-quality-control-2021.8.0/q2_quality_control/tests/test_filter.py000066400000000000000000000121731411645176100253360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import gzip import itertools import unittest from q2_types.per_sample_sequences import ( SingleLanePerSampleSingleEndFastqDirFmt, SingleLanePerSamplePairedEndFastqDirFmt, FastqGzFormat, ) from qiime2 import Artifact from .test_quality_control import QualityControlTestsBase class TestBowtie2Build(QualityControlTestsBase): # This test just makes sure this runs without error, which will include # validating the contents. def test_build(self): genome = Artifact.load(self.get_data_path('sars2-genome.qza')) self.plugin.methods['bowtie2_build'](genome) seq_ids_that_map = ['SARS2:6:73:941:1973#', 'SARS2:6:73:231:3321#', 'SARS2:6:73:233:3421#', 'SARS2:6:73:552:2457#', 'SARS2:6:73:567:7631#'] seq_id_that_does_not_map = 'SARS2:6:73:356:9806#' class TestFilterSingle(QualityControlTestsBase): def setUp(self): super().setUp() self.demuxed_art = Artifact.load(self.get_data_path('single-end.qza')) self.indexed_genome = Artifact.load( self.get_data_path('sars2-indexed.qza')) def test_filter_single_exclude_seqs(self): obs_art, = self.plugin.methods['filter_reads']( self.demuxed_art, self.indexed_genome, exclude_seqs=True) obs = obs_art.view(SingleLanePerSampleSingleEndFastqDirFmt) obs_seqs = obs.sequences.iter_views(FastqGzFormat) for _, obs_fp in obs_seqs: with gzip.open(str(obs_fp), 'rt') as obs_fh: # Iterate over expected and observed reads, side-by-side for records in itertools.zip_longest(*[obs_fh] * 4): (obs_seq_h, obs_seq, _, obs_qual) = records # Make sure seqs that map to genome were removed obs_id = obs_seq_h.strip('@/012\n') self.assertTrue(obs_id not in seq_ids_that_map) self.assertTrue(obs_id in seq_id_that_does_not_map) def test_filter_single_keep_seqs(self): obs_art, = self.plugin.methods['filter_reads']( self.demuxed_art, self.indexed_genome, exclude_seqs=False) obs = obs_art.view(SingleLanePerSampleSingleEndFastqDirFmt) obs_seqs = obs.sequences.iter_views(FastqGzFormat) for _, obs_fp in obs_seqs: with gzip.open(str(obs_fp), 'rt') as obs_fh: # Iterate over expected and observed reads, side-by-side for records in itertools.zip_longest(*[obs_fh] * 4): (obs_seq_h, obs_seq, _, obs_qual) = records # Make sure seqs that do not map to genome were removed obs_id = obs_seq_h.strip('@/012\n') self.assertTrue(obs_id in seq_ids_that_map) self.assertTrue(obs_id not in seq_id_that_does_not_map) class TestFilterPaired(QualityControlTestsBase): def setUp(self): super().setUp() self.demuxed_art = Artifact.load(self.get_data_path('paired-end.qza')) self.indexed_genome = Artifact.load( self.get_data_path('sars2-indexed.qza')) def test_filter_paired_exclude_seqs(self): obs_art, = self.plugin.methods['filter_reads']( self.demuxed_art, self.indexed_genome, exclude_seqs=True) obs = obs_art.view(SingleLanePerSamplePairedEndFastqDirFmt) obs_seqs = obs.sequences.iter_views(FastqGzFormat) for _, obs_fp in obs_seqs: with gzip.open(str(obs_fp), 'rt') as obs_fh: # Iterate over expected and observed reads, side-by-side for records in itertools.zip_longest(*[obs_fh] * 4): (obs_seq_h, obs_seq, _, obs_qual) = records # Make sure seqs that map to genome were removed obs_id = obs_seq_h.strip('@/012\n') self.assertTrue(obs_id not in seq_ids_that_map) self.assertTrue(obs_id in seq_id_that_does_not_map) def test_filter_paired_keep_seqs(self): obs_art, = self.plugin.methods['filter_reads']( self.demuxed_art, self.indexed_genome, exclude_seqs=False) obs = obs_art.view(SingleLanePerSamplePairedEndFastqDirFmt) obs_seqs = obs.sequences.iter_views(FastqGzFormat) for _, obs_fp in obs_seqs: with gzip.open(str(obs_fp), 'rt') as obs_fh: # Iterate over expected and observed reads, side-by-side for records in itertools.zip_longest(*[obs_fh] * 4): (obs_seq_h, obs_seq, _, obs_qual) = records # Make sure seqs that do not map to genome were removed obs_id = obs_seq_h.strip('@/012\n') self.assertTrue(obs_id in seq_ids_that_map) self.assertTrue(obs_id not in seq_id_that_does_not_map) if __name__ == '__main__': unittest.main() q2-quality-control-2021.8.0/q2_quality_control/tests/test_quality_control.py000066400000000000000000001322301411645176100272760ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import numpy.testing as npt import pandas as pd import qiime2 import biom from warnings import filterwarnings from qiime2.plugin.testing import TestPluginBase from q2_types.feature_data import DNAFASTAFormat import pandas.testing as pdt from q2_quality_control.quality_control import ( exclude_seqs, evaluate_composition, evaluate_seqs, evaluate_taxonomy) from q2_quality_control._utilities import ( _evaluate_composition, _collapse_table, _drop_nans_zeros, _compute_per_level_accuracy, compute_taxon_accuracy, _tally_misclassifications, _identify_incorrect_classifications, _find_nearest_common_lineage, _interpret_metric_selection, _match_samples_by_index, _validate_metadata_and_exp_table) from q2_quality_control._evaluate_seqs import _evaluate_seqs from q2_quality_control._evaluate_taxonomy import ( _evaluate_taxonomy, _extract_taxa_names, _index_is_subset, _validate_indices_and_set_joining_mode) filterwarnings("ignore", category=UserWarning) def _dnafastaformats_to_series(fasta): fasta = qiime2.Artifact.import_data("FeatureData[Sequence]", fasta) return fasta.view(pd.Series) # test template for EvaluateSeqsTests def load_evaluate_seqs(query_sequences, reference_sequences, exp_fp): results, alignments, g = _evaluate_seqs( query_sequences, reference_sequences, show_alignments=False) # need to cast to numeric to match dtypes that are interpreted in exp # as it is read in by read_csv results = results.apply(lambda x: pd.to_numeric(x, errors='ignore')) exp = pd.read_csv(exp_fp, sep='\t', index_col=0) pdt.assert_frame_equal(results, exp) class QualityControlTestsBase(TestPluginBase): package = 'q2_quality_control.tests' def setUp(self): super().setUp() class SequenceQualityControlBase(QualityControlTestsBase): def setUp(self): super().setUp() def _load_DNAFASTAFormat(reads_fn): reads_fp = self.get_data_path(reads_fn) return DNAFASTAFormat(reads_fp, mode='r') self.query_seqs = _load_DNAFASTAFormat('query-sequences.fasta') self.bacterial_ref = _load_DNAFASTAFormat( 'bacterial-ref-sequences.fasta') self.bacterial_exp = _dnafastaformats_to_series( _load_DNAFASTAFormat('bacterial-query-sequences.fasta')) self.fungal_ref = _load_DNAFASTAFormat('fungal-ref-sequences.fasta') self.fungal_exp = _dnafastaformats_to_series( _load_DNAFASTAFormat('fungal-query-sequences.fasta')) self.query_seqs_with_mismatch = _load_DNAFASTAFormat( 'query-sequences-with-mismatch.fasta') self.query_seqs_short = _load_DNAFASTAFormat( 'query-sequences-short.fasta') self.query_seqs_part_rand = _load_DNAFASTAFormat( 'query-partially-random.fasta') self.query_seqs_left_justify = _load_DNAFASTAFormat( 'query-sequences-left-justified.fasta') class ExcludeSeqsBase(object): method = None def test_exclude_seqs_bacterial_hit_fungal_miss(self): obs, missed = exclude_seqs( self.query_seqs, self.bacterial_ref, method=self.method) self.assertEqual( sorted(obs.index), sorted(self.bacterial_exp.index)) self.assertEqual( sorted(missed.index), sorted(self.fungal_exp.index)) def test_exclude_seqs_fungal_hit_bacterial_miss(self): obs, missed = exclude_seqs( self.query_seqs, self.fungal_ref, method=self.method) self.assertEqual(sorted(obs.index), sorted(self.fungal_exp.index)) self.assertEqual( sorted(missed.index), sorted(self.bacterial_exp.index)) def test_exclude_seqs_all_hit(self): obs, missed = exclude_seqs( self.query_seqs, self.query_seqs, method=self.method) self.assertEqual(sorted(obs.index), sorted( _dnafastaformats_to_series(self.query_seqs).index)) self.assertEqual(sorted(missed.index), []) def test_exclude_seqs_all_miss(self): obs, missed = exclude_seqs( self.query_seqs_with_mismatch, self.fungal_ref, method=self.method) self.assertEqual(sorted(missed.index), sorted( _dnafastaformats_to_series( self.query_seqs_with_mismatch).index)) self.assertEqual(sorted(obs.index), []) def test_exclude_seqs_97_perc_identity(self): obs, missed = exclude_seqs( self.query_seqs_with_mismatch, self.bacterial_ref, method=self.method) self.assertEqual( sorted(obs.index), ['2MISA', '2MISB']) self.assertEqual( sorted(missed.index), ['10MISA', '8MISA', '8MISB']) def test_exclude_seqs_96_perc_identity(self): obs, missed = exclude_seqs( self.query_seqs_with_mismatch, self.bacterial_ref, method=self.method, perc_identity=0.965) self.assertEqual( sorted(obs.index), ['2MISA', '2MISB', '8MISA', '8MISB']) self.assertEqual( sorted(missed.index), ['10MISA']) def test_exclude_seqs_99_perc_identity(self): obs, missed = exclude_seqs( self.query_seqs_with_mismatch, self.bacterial_ref, method=self.method, perc_identity=0.99) self.assertEqual(sorted(missed.index), sorted( _dnafastaformats_to_series( self.query_seqs_with_mismatch).index)) self.assertEqual(sorted(obs.index), []) class BlastTests(ExcludeSeqsBase, SequenceQualityControlBase): method = 'blast' def test_exclude_seqs_left_justify_value_error(self): with self.assertRaisesRegex(ValueError, "left_justify is not " "compatible with " "method='blast'"): exclude_seqs( self.query_seqs_left_justify, self.bacterial_ref, method=self.method, left_justify=True) class VsearchTests(ExcludeSeqsBase, SequenceQualityControlBase): method = 'vsearch' def test_exclude_seqs_left_justify_hits(self): obs, missed = exclude_seqs( self.query_seqs_left_justify, self.bacterial_ref, method=self.method, left_justify=True) self.assertCountEqual( sorted(obs.index), ['1111886-leftjustmatch', '1111882-leftjustwithindel', '1111879-leftjustmatch'] ) def test_exclude_seqs_left_justify_missed(self): obs, missed = exclude_seqs( self.query_seqs_left_justify, self.bacterial_ref, method=self.method, left_justify=True) self.assertEqual(sorted(missed.index), ['1111883-noleftjustmatch']) class SequenceQualityControlTests(SequenceQualityControlBase): def setUp(self): super().setUp() def test_exclude_seqs_high_evalue_low_perc_query_aligned_permissive(self): obs, missed = exclude_seqs( self.query_seqs_part_rand, self.bacterial_ref, method='blast', perc_identity=0.97, evalue=10000000000000000, perc_query_aligned=0.1) self.assertEqual(sorted(obs.index), sorted( _dnafastaformats_to_series(self.query_seqs_part_rand).index)) self.assertEqual(sorted(missed.index), []) def test_exclude_seqs_blast_low_evalue_discards_weak_matches(self): obs, missed = exclude_seqs( self.query_seqs_part_rand, self.bacterial_ref, method='blast', perc_identity=0.97, evalue=10**-30, perc_query_aligned=0.1) self.assertEqual( sorted(obs.index), ['YAYIMATCH']) self.assertEqual( sorted(missed.index), ['RAND1', 'RAND2']) def test_exclude_seqs_short_seqs_miss_with_default_blast(self): obs, missed = exclude_seqs( self.query_seqs_short, self.bacterial_ref, method='blast') self.assertEqual(sorted(missed.index), sorted( _dnafastaformats_to_series(self.query_seqs_short).index)) self.assertEqual(sorted(obs.index), []) def test_exclude_seqs_short_seqs_hit_with_default_vsearch(self): obs, missed = exclude_seqs( self.query_seqs_short, self.bacterial_ref, method='vsearch') self.assertEqual(sorted(obs.index), sorted( _dnafastaformats_to_series(self.query_seqs_short).index)) self.assertEqual(sorted(missed.index), []) def test_exclude_seqs_short_seqs_hit_with_blastn_short(self): obs, missed = obs, missed = exclude_seqs( self.query_seqs_short, self.bacterial_ref, method='blastn-short', evalue=10000) self.assertEqual(sorted(obs.index), sorted( _dnafastaformats_to_series(self.query_seqs_short).index)) self.assertEqual(sorted(missed.index), []) def test_exclude_seqs_short_seqs_miss_with_blastn_short_low_eval(self): obs, missed = obs, missed = exclude_seqs( self.query_seqs_short, self.bacterial_ref, method='blastn-short', perc_identity=0.01, evalue=10**-30) self.assertEqual(sorted(missed.index), sorted( _dnafastaformats_to_series(self.query_seqs_short).index)) self.assertEqual(sorted(obs.index), []) class UtilitiesTests(QualityControlTestsBase): def test_drop_nans_zeros(self): test_df1 = pd.DataFrame({'a; b': [0., 0., 0.], 'b; c': [1., 0., 0.], 'c; d': [1., np.nan, 1.]}) filtered_df = pd.DataFrame( {'b;c': [1., 0.], 'c;d': [1., 1.]}, index=[0, 2]) new_df = _drop_nans_zeros(test_df1) pdt.assert_frame_equal(filtered_df, new_df) def test_compute_taxon_accuracy(self): res = compute_taxon_accuracy( pd.Series({'a;b': 1, 'b;c': 1, 'c;d': 1}), pd.Series({'a;b': 1, 'b;c': 1, 'c;e': 1, 'd;e': 1})) self.assertEqual(res, (0.5, 0.6666666666666666)) def test_compute_taxon_accuracy_no_matches(self): res = compute_taxon_accuracy( pd.Series({'a': 1, 'b': 1, 'c': 1}), pd.Series({'a;b': 1, 'b;c': 1, 'c;e': 1, 'd;e': 1})) self.assertEqual(res, (0., 0.)) def test_compute_taxon_accuracy_all_match(self): res = compute_taxon_accuracy( pd.Series({'a;b': 1, 'b;c': 1, 'c;d': 1}), pd.Series({'a;b': 1, 'b;c': 1, 'c;d': 1})) self.assertEqual(res, (1., 1.)) def test_collapse_table(self): old_table = pd.DataFrame( {'a;b;c;d;e': [1, 1, 1], 'a;b;f;g;h': [1, 1, 1], 'a;b': [1, 1, 1]}) new_table = _collapse_table(old_table, 2) self.assertEqual(set(new_table.columns), set(['a;b'])) npt.assert_array_equal(new_table.values, np.array([[3], [3], [3]])) new_table = _collapse_table(old_table, 3) self.assertEqual(set(new_table.columns), set(('a;b;__', 'a;b;c', 'a;b;f'))) npt.assert_array_equal( new_table.values, np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])) def test_identify_incorrect_classifications(self): res = _identify_incorrect_classifications( set(('a', 'c', 'd', 'e', 'f')), set(('a', 'b', 'c', 'd'))) self.assertEqual(res, (set(('e', 'f')), set(('b')))) # matches should never reach this function, so expect underclassification def test_tally_misclassifications(self): res = _tally_misclassifications( set(('a;b;c', 'd;e;f;m', 'g;h', 'j', 'm;n;o')), set(('a;b;c', 'd;e;f', 'g;h;i', 'j;k;l'))) self.assertEqual( res, (['d;e;f;m', 'm;n;o'], ['a;b;c', 'g;h', 'j'], [-2, -1, 0, 1, 3])) def test_tally_misclassifications_no_match(self): res = _tally_misclassifications( set(('m;n;o', 'p;q;r', 'q;r;s', 'r;s;t;u')), set(('a;b;c', 'd;e;f', 'g;h;i', 'j;k;l'))) self.assertEqual(res, (['m;n;o', 'p;q;r', 'q;r;s', 'r;s;t;u'], [], [3, 3, 3, 4])) # matches should never reach this function, so expect underclassification def test_tally_misclassifications_all_match(self): res = _tally_misclassifications( set(('a;b;c', 'd;e;f', 'g;h;i', 'j;k;l')), set(('a;b;c', 'd;e;f', 'g;h;i', 'j;k;l'))) self.assertEqual( res, ([], ['a;b;c', 'd;e;f', 'g;h;i', 'j;k;l'], [0, 0, 0, 0])) def test_interpret_metric_selection_valid(self): yvals = _interpret_metric_selection( True, True, False, True, False, False, False, False) self.assertEqual(yvals, ['TAR', 'TDR', 'r-squared']) def test_interpret_metric_selection_invalid(self): with self.assertRaisesRegex(ValueError, "At least one metric"): _interpret_metric_selection( False, False, False, False, False, False, False, False) def test_match_samples_by_index(self): df_a = pd.DataFrame({'a': (1., 2., 3.)}, index=['1', '2', '3']) df_b = pd.DataFrame({'a': (2., 3., 7.)}, index=['2', '3', '7']) df_c = pd.DataFrame({'a': (2., 3.)}, index=['2', '3']) df_a, df_b = _match_samples_by_index(df_a, df_b) pdt.assert_frame_equal(df_a.dropna(), df_c) pdt.assert_frame_equal(df_b.dropna(), df_c) def test_validate_metadata_and_exp_table_metadata_not_superset(self): incomplete_md = pd.Series(['there_can_only_be_one'], name='mock_id', index=pd.Index(['s3'], name='id')) with self.assertRaisesRegex(ValueError, "Missing samples in metadata"): _validate_metadata_and_exp_table( incomplete_md, exp_one_sample, obs) def test_validate_metadata_and_exp_table_metadata_values_not_subset(self): underrepresented_md = pd.Series( ['there_can_only_be_one', 'what_is_this?', 'i_am_not_really_here'], name='mock_id', index=pd.Index(['s3', 's1', 's2'], name='id')) with self.assertRaisesRegex(ValueError, "Missing samples in table"): _validate_metadata_and_exp_table( underrepresented_md, exp_one_sample, obs) # test for issue-25: metadata is superset, but values are subset of exp # should output new metadata that fits the table def test_validate_metadata_and_exp_table_md_superset_vals_subset(self): overabundant_md = pd.Series( ['s1', 's1', 's1', 's2', 's2'], name='mock_id', index=pd.Index(['s3', 's1', 's2', 'fake1', 'fake2'], name='id')) corrected_md = pd.Series( ['s1', 's1', 's1'], name='mock_id', index=pd.Index(['s1', 's2', 's3'])) new_md, junk = _validate_metadata_and_exp_table( overabundant_md, exp, obs) pdt.assert_series_equal(new_md, corrected_md) class EvaluateSeqsTests(SequenceQualityControlBase): # check that visualizer runs without fail. Following tests actually test # the nuts/bolts for expected values. def test_evaluate_seqs_plugin(self): evaluate_seqs(output_dir=self.temp_dir.name, query_sequences=self.bacterial_ref, reference_sequences=self.bacterial_ref, show_alignments=True) def test_evaluate_seqs_identical(self): load_evaluate_seqs( self.bacterial_ref, self.bacterial_ref, self.get_data_path('test_evaluate_seqs_identical.tsv')) def test_evaluate_seqs_mismatches(self): load_evaluate_seqs( self.query_seqs_with_mismatch, self.bacterial_ref, self.get_data_path('test_evaluate_seqs_mismatches.tsv')) def test_evaluate_seqs_part_rand(self): load_evaluate_seqs( self.query_seqs_part_rand, self.bacterial_ref, self.get_data_path('test_evaluate_seqs_part_rand.tsv')) class NCLUtilitiesTests(QualityControlTestsBase): def setUp(self): super().setUp() self.taxa = ['Aa;Bb;Cc;Dd;Ee;Ff;Gg', 'Aa;Bb;Cc;Dd;Ee;Ff;Hh', 'Aa;Bb;Cc;Dd;Ee;Ii;Jj', 'Aa;Bb;Cc;Dd;Kk;Ll;Mm'] def test_find_nearest_common_lineage_match(self): res = _find_nearest_common_lineage('Aa;Bb;Cc;Dd;Ee;Ff;Gg', self.taxa) self.assertEqual(res, 0) def test_find_nearest_common_lineage_no_match(self): res = _find_nearest_common_lineage('Ab;Bb;Cb;Db;Eb;b;Gb', self.taxa) self.assertEqual(res, 7) def test_find_nearest_common_lineage_misclassification(self): res = _find_nearest_common_lineage('Aa;Bb;Cc;Dd;Kk;Ll;Mn', self.taxa) self.assertEqual(res, 1) def test_find_nearest_common_lineage_underclassification(self): res = _find_nearest_common_lineage('Aa;Bb;Cc;Dd;Ee;Ff', self.taxa) self.assertEqual(res, -1) def test_find_nearest_common_lineage_overclassification(self): res = _find_nearest_common_lineage('Aa;Bb;Cc;Dd;Ee;Ff;Gg;O', self.taxa) self.assertEqual(res, 1) class EvaluateCompositionTests(QualityControlTestsBase): def setUp(self): super().setUp() self.exp_results = pd.read_csv( self.get_data_path('exp-results.tsv'), sep='\t', index_col=0) self.exp = exp self.obs = obs self.false_neg = pd.DataFrame( {'s1': [0.15, 0.15, 0.25], 's2': [0.15, 0.15, 0.25], 's3': [0.15, 0.15, 0.25]}, index=['k__Ac;p__Bc;c__Cc;o__Dc;f__Ec;g__Fc;s__Gc', 'k__Ae;p__Be;c__Ce;o__De;f__Ee;g__Fe;s__Ge', 'k__Af;p__Bf;c__Cf;o__Df;f__Ef;g__Ff;__']) self.false_neg.index.name = 'Taxon' self.misclassified = pd.DataFrame( {'s1': [0.20, 0.08], 's2': [0.21, 0.03], 's3': [0.25, 0.0]}, index=['k__Af;p__Bf;c__Cf;o__Df;f__Ef;g__Ff;s__Gf', 'k__Ag;p__Bg;c__Cg;o__Dg;f__Eg;g__Fg;s__Gg']) self.misclassified.index.name = 'Taxon' self.underclassified = pd.DataFrame( {'s1': [0.20, 0.12], 's2': [0.17, 0.16], 's3': [0.15, 0.15]}, index=['k__Ac;p__Bc;c__Cc;o__Dc;f__Ec;__;__', 'k__Ae;p__Be;c__Ce;o__De;f__Ee;g__Fe;__']) self.underclassified.index.name = 'Taxon' self.exp_one_sample = exp_one_sample self.metadata_one_sample = qiime2.CategoricalMetadataColumn( pd.Series(['there_can_only_be_one', 'there_can_only_be_one', 'there_can_only_be_one'], name='mock_id', index=pd.Index(['s3', 's1', 's2'], name='id'))) # test that visualizer runs without fail; internal functions are all tested # with various utility tests, this just makes sure the plugin works. def test_plugin_evaluate_composition(self): evaluate_composition( output_dir=self.temp_dir.name, expected_features=self.exp, observed_features=self.obs, depth=7) def test_compute_per_level_accuracy(self): metadata = {_id: _id for _id in self.obs.index} res = _compute_per_level_accuracy(self.exp, self.obs, metadata, 7) pdt.assert_frame_equal(res[0], self.exp_results) self.assertEqual(res[1], exp_v) # confirm accurate behavior when exp/obs vector lengths are equal to # one. See https://github.com/qiime2/q2-quality-control/issues/44 def test_compute_per_level_accuracy_vector_length_one(self): res = _compute_per_level_accuracy( exp_one_kingdom, obs_one_kingdom, None, depth=1) # assert that all r2 values are nan (if r2 is nan, r will be also) self.assertTrue(np.isnan(res[0]['r-squared']).all()) def test_evaluate_composition(self): res = _evaluate_composition( self.exp, self.obs, depth=7, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features=True, plot_observed_features_ratio=True, metadata=None) pdt.assert_frame_equal(res[0], self.exp_results) pdt.assert_frame_equal(res[1], self.false_neg) pdt.assert_frame_equal(res[2], self.misclassified) pdt.assert_frame_equal(res[3], self.underclassified) def test_evaluate_composition_metadata_map_to_mock_sample(self): res = _evaluate_composition( self.exp_one_sample, self.obs, depth=7, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features=True, plot_observed_features_ratio=True, metadata=self.metadata_one_sample) pdt.assert_frame_equal(res[0], self.exp_results) # false_neg should contain only one column header since the map # contains one sample (rename to match column name in exp_one_sample) false_neg = self.false_neg[['s1']] false_neg.columns = ['there_can_only_be_one'] false_neg.index.name = 'Taxon' pdt.assert_frame_equal(res[1], false_neg) pdt.assert_frame_equal(res[2], self.misclassified) pdt.assert_frame_equal(res[3], self.underclassified) def test_evaluate_composition_dont_test_all_levels(self): empty_expectations = pd.DataFrame( columns=['s1', 's2', 's3']).astype(float) empty_expectations.index.name = 'Taxon' mc = self.misclassified.loc[[ 'k__Ag;p__Bg;c__Cg;o__Dg;f__Eg;g__Fg;s__Gg']] mc.index = ['k__Ag;p__Bg;c__Cg;o__Dg;f__Eg'] mc.index.name = 'Taxon' res = _evaluate_composition( self.exp, self.obs, depth=5, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_observed_features=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features_ratio=True, metadata=None) pdt.assert_frame_equal( res[0], self.exp_results[self.exp_results['level'] < 6]) pdt.assert_frame_equal(res[1], empty_expectations) pdt.assert_frame_equal(res[2], mc) pdt.assert_frame_equal(res[3], empty_expectations) def test_evaluate_composition_metadata_not_superset(self): incomplete_md = qiime2.CategoricalMetadataColumn( pd.Series(['there_can_only_be_one'], name='mock_id', index=pd.Index(['s3'], name='id'))) with self.assertRaisesRegex(ValueError, "Missing samples in metadata"): _evaluate_composition( self.exp_one_sample, self.obs, depth=7, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features=True, plot_observed_features_ratio=True, metadata=incomplete_md) def test_evaluate_composition_metadata_values_not_subset(self): underrepresented_md = qiime2.CategoricalMetadataColumn( pd.Series(['there_can_only_be_one', 'what_is_this?', 'i_am_not_really_here'], name='mock_id', index=pd.Index(['s3', 's1', 's2'], name='id'))) with self.assertRaisesRegex(ValueError, "Missing samples in table"): _evaluate_composition( self.exp_one_sample, self.obs, depth=7, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features=True, plot_observed_features_ratio=True, metadata=underrepresented_md) def test_evaluate_composition_depth_too_high(self): with self.assertRaisesRegex(ValueError, "8 is larger than the max"): _evaluate_composition( self.exp, self.obs, depth=8, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features=True, plot_observed_features_ratio=True, metadata=None) class EvaluateCompositionMockrobiotaDataTests(QualityControlTestsBase): def setUp(self): super().setUp() self.exp_results = pd.read_csv( self.get_data_path('mock-3-results.tsv'), sep='\t', index_col=0) self.exp = qiime2.Artifact.load( self.get_data_path('qc-mock-3-expected.qza')).view(pd.DataFrame) self.obs = qiime2.Artifact.load( self.get_data_path('qc-mock-3-observed.qza')).view(pd.DataFrame) self.false_neg = pd.DataFrame( {'HMPMockV1.1.Even1': [0.047619, 0.047619, 0.047619], 'HMPMockV1.1.Even2': [0.047619, 0.047619, 0.047619], 'HMPMockV1.2.Staggered1': [0.2143622714, 0.0214362274, 0.0002143626], 'HMPMockV1.2.Staggered2': [0.2143622714, 0.0214362274, 0.0002143626]}, index=['k__Bacteria;p__Firmicutes;c__Bacilli;o__Bacillales;' 'f__Staphylococcaceae;g__Staphylococcus;s__aureus', 'k__Bacteria;p__Firmicutes;c__Bacilli;o__Bacillales;' 'f__Staphylococcaceae;g__Staphylococcus;s__epidermidis', 'k__Bacteria;p__Thermi;c__Deinococci;o__Deinococcales;' 'f__Deinococcaceae;g__Deinococcus;s__']) self.false_neg.index.name = 'Taxon' self.misclassified = pd.DataFrame( {'HMPMockV1.1.Even1': [0.08634], 'HMPMockV1.1.Even2': [0.0533176566813], 'HMPMockV1.2.Staggered1': [0.], 'HMPMockV1.2.Staggered2': [0.]}, index=['k__Bacteria;p__[Thermi];c__Deinococci;o__Deinococcales;' 'f__Deinococcaceae;g__Deinococcus;s__']) self.misclassified.index.name = 'Taxon' self.underclassified = pd.DataFrame( {'HMPMockV1.1.Even1': [0.536876], 'HMPMockV1.1.Even2': [0.577293], 'HMPMockV1.2.Staggered1': [0.639295], 'HMPMockV1.2.Staggered2': [0.666156]}, index=['k__Bacteria;p__Firmicutes;c__Bacilli;o__Bacillales;' 'f__Staphylococcaceae;g__Staphylococcus;__']) self.underclassified.index.name = 'Taxon' self.metadata = qiime2.CategoricalMetadataColumn( pd.Series(['HMPMockV1.1.Even1', 'HMPMockV1.1.Even1', 'HMPMockV1.2.Staggered1', 'HMPMockV1.2.Staggered1'], name='mock_id', index=pd.Index(['HMPMockV1.1.Even1', 'HMPMockV1.1.Even2', 'HMPMockV1.2.Staggered1', 'HMPMockV1.2.Staggered2'], name='id'))) def test_evaluate_composition_mockrobiota(self): res = _evaluate_composition( self.exp, self.obs, depth=7, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=True, plot_jaccard=True, plot_observed_features=True, plot_observed_features_ratio=True, metadata=None) pdt.assert_frame_equal(res[0], self.exp_results) pdt.assert_frame_equal(res[1], self.false_neg) pdt.assert_frame_equal(res[2], self.misclassified) pdt.assert_frame_equal(res[3], self.underclassified) def test_evaluate_composition_mockrobiota_metadata_map(self): res = _evaluate_composition( self.exp, self.obs, depth=7, palette='Set1', plot_tar=True, plot_tdr=True, plot_r_value=True, plot_r_squared=True, plot_bray_curtis=False, plot_jaccard=False, plot_observed_features=True, plot_observed_features_ratio=True, metadata=self.metadata) false_neg = self.false_neg[['HMPMockV1.1.Even1', 'HMPMockV1.2.Staggered1']] pdt.assert_frame_equal(res[0], self.exp_results) pdt.assert_frame_equal(res[1], false_neg) pdt.assert_frame_equal(res[2], self.misclassified) pdt.assert_frame_equal(res[3], self.underclassified) class EvaluateTaxonomyTests(QualityControlTestsBase): def setUp(self): super().setUp() self.exp_taxa = pd.read_csv( self.get_data_path('mock-3-expected-taxonomy.tsv'), sep='\t', index_col=0) self.obs_taxa = pd.read_csv( self.get_data_path('mock-3-observed-taxonomy.tsv'), sep='\t', index_col=0) self.obs_table = biom.load_table( self.get_data_path('mock-3-obs-table.biom')) self.prf_res_unw = pd.DataFrame.from_dict({ 'level': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7}, 'Precision': {0: 0.96, 1: 0.96, 2: 0.96, 3: 0.96, 4: 0.96, 5: 0.9583333333333334, 6: 0.7368421052631579}, 'Recall': {0: 0.96, 1: 0.96, 2: 0.96, 3: 0.96, 4: 0.96, 5: 0.92, 6: 0.56}, 'F-measure': {0: 0.96, 1: 0.96, 2: 0.96, 3: 0.96, 4: 0.96, 5: 0.9387755102040817, 6: 0.6363636363636364}})[[ 'level', 'Precision', 'Recall', 'F-measure']] # just check that visualizer works. Other tests check nuts/bolts def test_evaluate_taxonomy(self): evaluate_taxonomy( self.temp_dir.name, self.exp_taxa, self.obs_taxa, depth=7) def test_evaluate_taxonomy_basic(self): prf = _evaluate_taxonomy( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False, feature_table=None, sample_id=None, level_range=range(0, 7)) pdt.assert_frame_equal(prf, self.prf_res_unw) def test_evaluate_taxonomy_sample_id_no_table(self): prf = _evaluate_taxonomy( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False, feature_table=None, sample_id='HMPMockV1.1.Even1', level_range=range(0, 7)) prf_res_unw = self.prf_res_unw prf_res_unw['SampleID'] = 'HMPMockV1.1.Even1' pdt.assert_frame_equal(prf, prf_res_unw) def test_evaluate_taxonomy_sample_id_not_found_FAIL(self): with self.assertRaisesRegex( ValueError, 'Sample id not found in feature table: Peanut'): _evaluate_taxonomy( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False, feature_table=self.obs_table, sample_id='Peanut') def test_evaluate_taxonomy_plus_table_no_sample_id(self): prf = _evaluate_taxonomy( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False, feature_table=self.obs_table, sample_id=None, level_range=range(6, 7)) pdt.assert_frame_equal(prf, pd.DataFrame.from_dict( {'level': {0: 7}, 'Precision': {0: 0.6377837950426994}, 'Recall': {0: 0.19487462344605203}, 'F-measure': {0: 0.2985326855267221}})[[ 'level', 'Precision', 'Recall', 'F-measure']]) def test_evaluate_taxonomy_sample_id_plus_table(self): prf = _evaluate_taxonomy( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False, feature_table=self.obs_table, sample_id='HMPMockV1.1.Even1', level_range=range(6, 7)) pdt.assert_frame_equal(prf, pd.DataFrame.from_dict( {'level': {0: 7}, 'Precision': {0: 0.5523983315954119}, 'Recall': {0: 0.19757575757575757}, 'F-measure': {0: 0.2910514387748094}, 'SampleID': {0: 'HMPMockV1.1.Even1'}})[[ 'level', 'Precision', 'Recall', 'F-measure', 'SampleID']]) def test_evaluate_taxonomy_plus_table_missing_features_in_table_FAIL(self): obs_table = self.obs_table.filter( ['47ad35356a9bfec68416d32e4f039021', 'c4269a6e9bd66eca53e710c9f9d9ad4f', '7a8d29c59b803baaed9cc1f04ce0dc33', '86adb6193435090318cf24df07770d07'], axis='observation') with self.assertRaisesRegex( ValueError, "Feature ids not found in feature table"): _evaluate_taxonomy( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False, feature_table=obs_table, sample_id=None, level_range=range(6, 7)) def _test_extract_taxa_names_species(self): names = _extract_taxa_names(self.self.exp_taxa.iloc['Taxon']) self.assertEqual(names, ['s__', 's__', 's__sphaeroides', 's__acnes', 's__aureus', '', 's__coli', 's__pylori', 's__', 's__', 's__', 's__', 's__cereus', 's__', 's__', 's__', 's__', 's__', 's__', 's__', 's__', 's__monocytogenes', 's__aeruginosa', 's__', 's__agalactiae']) def _test_extract_taxa_names_phylum(self): names = _extract_taxa_names( self.self.exp_taxa.iloc['Taxon'], level=slice(0, 1)) self.assertEqual(names, ['k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'other', 'k__Bacteria', 'k__Bacteria', 'k__Archaea', 'k__Bacteria', 'k__Archaea', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Archaea', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria', 'k__Bacteria']) def _test_extract_taxa_names_all_levels(self): names = _extract_taxa_names( self.self.exp_taxa['Taxon'], level=slice(0, 7)) self.assertEqual(names, list(self.self.exp_taxa.iloc['Taxon'])) def test_index_is_subset_equal_series(self): # if series1 is superset of or == series2, no problem _index_is_subset(self.exp_taxa, self.obs_taxa, 'observed') def test_index_is_subset_TRUE(self): _index_is_subset(self.exp_taxa, self.obs_taxa[:-5], 'observed') def test_index_is_subset_FALSE(self): # if series1 is subset of series2, raise error with self.assertRaisesRegex( ValueError, 'ids not found in observed ids'): _index_is_subset(self.exp_taxa[:-5], self.obs_taxa, 'observed') def test_validate_indices_and_set_joining_mode_equal(self): # series1 == series2 indices, no prob bob join_how = _validate_indices_and_set_joining_mode( self.exp_taxa, self.obs_taxa, require_exp_ids=True, require_obs_ids=True) self.assertEqual(join_how, 'inner') def test_validate_indices_and_set_joining_mode_inner(self): # any time require_exp_id == require_obs_ids, join_how = 'inner' join_how = _validate_indices_and_set_joining_mode( self.exp_taxa, self.obs_taxa, require_exp_ids=False, require_obs_ids=False) self.assertEqual(join_how, 'inner') def test_validate_indices_and_set_joining_mode_right(self): # exp < obs indices but require_obs_ids=False, pass join_how = _validate_indices_and_set_joining_mode( self.exp_taxa[-5:], self.obs_taxa, require_exp_ids=True, require_obs_ids=False) self.assertEqual(join_how, 'left') def test_validate_indices_and_set_joining_mode_left(self): # exp > obs indices but require_exp_ids=False, pass join_how = _validate_indices_and_set_joining_mode( self.exp_taxa, self.obs_taxa[-5:], require_exp_ids=False, require_obs_ids=True) self.assertEqual(join_how, 'right') def test_validate_indices_and_set_joining_mode_require_obs_id_FAIL(self): # series1 < series2 indices but require_obs_id=True, FAIL with self.assertRaisesRegex( ValueError, 'ids not found in expected ids'): _validate_indices_and_set_joining_mode( self.exp_taxa[-5:], self.obs_taxa, require_exp_ids=False, require_obs_ids=True) def test_validate_indices_and_set_joining_mode_require_exp_id_FAIL(self): # series1 > series2 indices but require_exp_ids=True, FAIL with self.assertRaisesRegex( ValueError, 'ids not found in observed ids'): _validate_indices_and_set_joining_mode( self.exp_taxa, self.obs_taxa[-5:], require_exp_ids=True, require_obs_ids=False) exp = pd.DataFrame( {'k__Aa;p__Ba;c__Ca;o__Da;f__Ea;g__Fa;s__Ga': [0.15, 0.15, 0.15], 'k__Ab;p__Bb;c__Cb;o__Db;f__Eb;g__Fb;s__Gb': [0.15, 0.15, 0.15], 'k__Ac;p__Bc;c__Cc;o__Dc;f__Ec;g__Fc;s__Gc': [0.15, 0.15, 0.15], 'k__Ad;p__Bd;c__Cd;o__Dd;f__Ed;g__Fd;s__Gd': [0.15, 0.15, 0.15], 'k__Ae;p__Be;c__Ce;o__De;f__Ee;g__Fe;s__Ge': [0.15, 0.15, 0.15], 'k__Af;p__Bf;c__Cf;o__Df;f__Ef;g__Ff': [0.25, 0.25, 0.25]}, index=['s1', 's2', 's3']) exp_one_sample = pd.DataFrame( {'k__Aa;p__Ba;c__Ca;o__Da;f__Ea;g__Fa;s__Ga': [0.15], 'k__Ab;p__Bb;c__Cb;o__Db;f__Eb;g__Fb;s__Gb': [0.15], 'k__Ac;p__Bc;c__Cc;o__Dc;f__Ec;g__Fc;s__Gc': [0.15], 'k__Ad;p__Bd;c__Cd;o__Dd;f__Ed;g__Fd;s__Gd': [0.15], 'k__Ae;p__Be;c__Ce;o__De;f__Ee;g__Fe;s__Ge': [0.15], 'k__Af;p__Bf;c__Cf;o__Df;f__Ef;g__Ff': [0.25]}, index=['there_can_only_be_one']) obs = pd.DataFrame( {'k__Aa;p__Ba;c__Ca;o__Da;f__Ea;g__Fa;s__Ga': [0.10, 0.15, 0.15], 'k__Ab;p__Bb;c__Cb;o__Db;f__Eb;g__Fb;s__Gb': [0.15, 0.10, 0.10], 'k__Ac;p__Bc;c__Cc;o__Dc;f__Ec': [0.20, 0.17, 0.15], 'k__Ad;p__Bd;c__Cd;o__Dd;f__Ed;g__Fd;s__Gd': [0.15, 0.18, 0.20], 'k__Ae;p__Be;c__Ce;o__De;f__Ee;g__Fe': [0.12, 0.16, 0.15], 'k__Af;p__Bf;c__Cf;o__Df;f__Ef;g__Ff;s__Gf': [0.20, 0.21, 0.25], 'k__Ag;p__Bg;c__Cg;o__Dg;f__Eg;g__Fg;s__Gg': [0.08, 0.03, 0.0]}, index=['s1', 's2', 's3']) exp_one_kingdom = pd.DataFrame( {'k__A;p__B;c__C;o__Da;f__Ea;g__Fa;s__Ga': [0.15, 0.15, 0.15], 'k__A;p__B;c__C;o__Db;f__Eb;g__Fb;s__Gb': [0.15, 0.15, 0.15], 'k__A;p__B;c__Cc;o__Dc;f__Ec;g__Fc;s__Gc': [0.15, 0.15, 0.15], 'k__A;p__Bd;c__Cd;o__Dd;f__Ed;g__Fd;s__Gd': [0.15, 0.15, 0.15], 'k__A;p__Be;c__Ce;o__De;f__Ee;g__Fe;s__Ge': [0.15, 0.15, 0.15], 'k__A;p__Bf;c__Cf;o__Df;f__Ef;g__Ff': [0.25, 0.25, 0.25]}, index=['s1', 's2', 's3']) obs_one_kingdom = pd.DataFrame( {'k__A;p__B;c__C;o__Da;f__Ea;g__Fa;s__Ga': [0.10, 0.15, 0.15], 'k__A;p__B;c__C;o__Db;f__Eb;g__Fb;s__Gb': [0.15, 0.10, 0.10], 'k__A;p__B;c__Cc;o__Dc;f__Ec': [0.20, 0.17, 0.15], 'k__A;p__Bd;c__Cd;o__Dd;f__Ed;g__Fd;s__Gd': [0.15, 0.18, 0.20], 'k__A;p__Be;c__Ce;o__De;f__Ee;g__Fe': [0.12, 0.16, 0.15], 'k__A;p__Bf;c__Cf;o__Df;f__Ef;g__Ff;s__Gf': [0.20, 0.21, 0.25], 'k__A;p__Bg;c__Cg;o__Dg;f__Eg;g__Fg;s__Gg': [0.08, 0.03, 0.0]}, index=['s1', 's2', 's3']) exp_v = { 1: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.12, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.17999999999999999, 0.16, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.25, 0.0]}, 2: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.12, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.17999999999999999, 0.16, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.25, 0.0]}, 3: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.12, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.17999999999999999, 0.16, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.25, 0.0]}, 4: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.12, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.17999999999999999, 0.16, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.25, 0.0]}, 5: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.12, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.17999999999999999, 0.16, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.14999999999999999, 0.25, 0.0]}, 6: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.14999999999999999, 0.14999999999999999, 0.25, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.0, 0.14999999999999999, 0.12, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.0, 0.17999999999999999, 0.16, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.0, 0.20000000000000001, 0.14999999999999999, 0.25, 0.0]}, 7: {'exp': [ 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.25, 0.0, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.25, 0.0, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.14999999999999999, 0.0, 0.14999999999999999, 0.25, 0.0, 0.0], 'obs': [ 0.10000000000000001, 0.14999999999999999, 0.20000000000000001, 0.0, 0.14999999999999999, 0.12, 0.0, 0.0, 0.20000000000000001, 0.080000000000000002, 0.14999999999999999, 0.10000000000000001, 0.17000000000000001, 0.0, 0.17999999999999999, 0.16, 0.0, 0.0, 0.20999999999999999, 0.029999999999999999, 0.14999999999999999, 0.10000000000000001, 0.14999999999999999, 0.0, 0.20000000000000001, 0.14999999999999999, 0.0, 0.0, 0.25, 0.0]}} q2-quality-control-2021.8.0/setup.cfg000066400000000000000000000002751411645176100172650ustar00rootroot00000000000000[versioneer] VCS=git style=pep440 versionfile_source = q2_quality_control/_version.py versionfile_build = q2_quality_control/_version.py tag_prefix = parentdir_prefix = q2-quality-control- q2-quality-control-2021.8.0/setup.py000066400000000000000000000020561411645176100171550ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2017-2021, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- from setuptools import find_packages, setup import versioneer setup( name='q2-quality-control', version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), license='BSD-3-Clause', packages=find_packages(), author="Nicholas Bokulich", author_email="nbokulich@gmail.com", description="Quality control methods for feature and sequence data.", url="https://github.com/qiime2/q2-quality-control", entry_points={ 'qiime2.plugins': ['q2-quality-control=q2_quality_control.plugin_setup:plugin'] }, package_data={ 'q2_quality_control': ['citations.bib', 'assets/*'], 'q2_quality_control.tests': ['data/*'], }, zip_safe=False, ) q2-quality-control-2021.8.0/versioneer.py000066400000000000000000002060221411645176100201750ustar00rootroot00000000000000 # Version: 0.18 # flake8: noqa """The Versioneer - like a rocketeer, but for versions. The Versioneer ============== * like a rocketeer, but for versions! * https://github.com/warner/python-versioneer * Brian Warner * License: Public Domain * Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy * [![Latest Version] (https://pypip.in/version/versioneer/badge.svg?style=flat) ](https://pypi.python.org/pypi/versioneer/) * [![Build Status] (https://travis-ci.org/warner/python-versioneer.png?branch=master) ](https://travis-ci.org/warner/python-versioneer) This is a tool for managing a recorded version number in distutils-based python projects. The goal is to remove the tedious and error-prone "update the embedded version string" step from your release process. Making a new release should be as easy as recording a new tag in your version-control system, and maybe making new tarballs. ## Quick Install * `pip install versioneer` to somewhere to your $PATH * add a `[versioneer]` section to your setup.cfg (see below) * run `versioneer install` in your source tree, commit the results ## Version Identifiers Source trees come from a variety of places: * a version-control system checkout (mostly used by developers) * a nightly tarball, produced by build automation * a snapshot tarball, produced by a web-based VCS browser, like github's "tarball from tag" feature * a release tarball, produced by "setup.py sdist", distributed through PyPI Within each source tree, the version identifier (either a string or a number, this tool is format-agnostic) can come from a variety of places: * ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows about recent "tags" and an absolute revision-id * the name of the directory into which the tarball was unpacked * an expanded VCS keyword ($Id$, etc) * a `_version.py` created by some earlier build step For released software, the version identifier is closely related to a VCS tag. Some projects use tag names that include more than just the version string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool needs to strip the tag prefix to extract the version identifier. For unreleased software (between tags), the version identifier should provide enough information to help developers recreate the same tree, while also giving them an idea of roughly how old the tree is (after version 1.2, before version 1.3). Many VCS systems can report a description that captures this, for example `git describe --tags --dirty --always` reports things like "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has uncommitted changes. The version identifier is used for multiple purposes: * to allow the module to self-identify its version: `myproject.__version__` * to choose a name and prefix for a 'setup.py sdist' tarball ## Theory of Operation Versioneer works by adding a special `_version.py` file into your source tree, where your `__init__.py` can import it. This `_version.py` knows how to dynamically ask the VCS tool for version information at import time. `_version.py` also contains `$Revision$` markers, and the installation process marks `_version.py` to have this marker rewritten with a tag name during the `git archive` command. As a result, generated tarballs will contain enough information to get the proper version. To allow `setup.py` to compute a version too, a `versioneer.py` is added to the top level of your source tree, next to `setup.py` and the `setup.cfg` that configures it. This overrides several distutils/setuptools commands to compute the version when invoked, and changes `setup.py build` and `setup.py sdist` to replace `_version.py` with a small static file that contains just the generated version data. ## Installation See [INSTALL.md](./INSTALL.md) for detailed installation instructions. ## Version-String Flavors Code which uses Versioneer can learn about its version string at runtime by importing `_version` from your main `__init__.py` file and running the `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can import the top-level `versioneer.py` and run `get_versions()`. Both functions return a dictionary with different flavors of version information: * `['version']`: A condensed version string, rendered using the selected style. This is the most commonly used value for the project's version string. The default "pep440" style yields strings like `0.11`, `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section below for alternative styles. * `['full-revisionid']`: detailed revision identifier. For Git, this is the full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". * `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the commit date in ISO 8601 format. This will be None if the date is not available. * `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that this is only accurate if run in a VCS checkout, otherwise it is likely to be False or None * `['error']`: if the version string could not be computed, this will be set to a string describing the problem, otherwise it will be None. It may be useful to throw an exception in setup.py if this is set, to avoid e.g. creating tarballs with a version string of "unknown". Some variants are more useful than others. Including `full-revisionid` in a bug report should allow developers to reconstruct the exact code being tested (or indicate the presence of local changes that should be shared with the developers). `version` is suitable for display in an "about" box or a CLI `--version` output: it can be easily compared against release notes and lists of bugs fixed in various releases. The installer adds the following text to your `__init__.py` to place a basic version in `YOURPROJECT.__version__`: from ._version import get_versions __version__ = get_versions()['version'] del get_versions ## Styles The setup.cfg `style=` configuration controls how the VCS information is rendered into a version string. The default style, "pep440", produces a PEP440-compliant string, equal to the un-prefixed tag name for actual releases, and containing an additional "local version" section with more detail for in-between builds. For Git, this is TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and that this commit is two revisions ("+2") beyond the "0.11" tag. For released software (exactly equal to a known tag), the identifier will only contain the stripped tag, e.g. "0.11". Other styles are available. See [details.md](details.md) in the Versioneer source tree for descriptions. ## Debugging Versioneer tries to avoid fatal errors: if something goes wrong, it will tend to return a version of "0+unknown". To investigate the problem, run `setup.py version`, which will run the version-lookup code in a verbose mode, and will display the full contents of `get_versions()` (including the `error` string, which may help identify what went wrong). ## Known Limitations Some situations are known to cause problems for Versioneer. This details the most significant ones. More can be found on Github [issues page](https://github.com/warner/python-versioneer/issues). ### Subprojects Versioneer has limited support for source trees in which `setup.py` is not in the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are two common reasons why `setup.py` might not be in the root: * Source trees which contain multiple subprojects, such as [Buildbot](https://github.com/buildbot/buildbot), which contains both "master" and "slave" subprojects, each with their own `setup.py`, `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI distributions (and upload multiple independently-installable tarballs). * Source trees whose main purpose is to contain a C library, but which also provide bindings to Python (and perhaps other langauges) in subdirectories. Versioneer will look for `.git` in parent directories, and most operations should get the right version string. However `pip` and `setuptools` have bugs and implementation details which frequently cause `pip install .` from a subproject directory to fail to find a correct version string (so it usually defaults to `0+unknown`). `pip install --editable .` should work correctly. `setup.py install` might work too. Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in some later version. [Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking this issue. The discussion in [PR #61](https://github.com/warner/python-versioneer/pull/61) describes the issue from the Versioneer side in more detail. [pip PR#3176](https://github.com/pypa/pip/pull/3176) and [pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve pip to let Versioneer work correctly. Versioneer-0.16 and earlier only looked for a `.git` directory next to the `setup.cfg`, so subprojects were completely unsupported with those releases. ### Editable installs with setuptools <= 18.5 `setup.py develop` and `pip install --editable .` allow you to install a project into a virtualenv once, then continue editing the source code (and test) without re-installing after every change. "Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a convenient way to specify executable scripts that should be installed along with the python package. These both work as expected when using modern setuptools. When using setuptools-18.5 or earlier, however, certain operations will cause `pkg_resources.DistributionNotFound` errors when running the entrypoint script, which must be resolved by re-installing the package. This happens when the install happens with one version, then the egg_info data is regenerated while a different version is checked out. Many setup.py commands cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into a different virtualenv), so this can be surprising. [Bug #83](https://github.com/warner/python-versioneer/issues/83) describes this one, but upgrading to a newer version of setuptools should probably resolve it. ### Unicode version strings While Versioneer works (and is continually tested) with both Python 2 and Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. Newer releases probably generate unicode version strings on py2. It's not clear that this is wrong, but it may be surprising for applications when then write these strings to a network connection or include them in bytes-oriented APIs like cryptographic checksums. [Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates this question. ## Updating Versioneer To upgrade your project to a new release of Versioneer, do the following: * install the new Versioneer (`pip install -U versioneer` or equivalent) * edit `setup.cfg`, if necessary, to include any new configuration settings indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. * re-run `versioneer install` in your source tree, to replace `SRC/_version.py` * commit any changed files ## Future Directions This tool is designed to make it easily extended to other version-control systems: all VCS-specific components are in separate directories like src/git/ . The top-level `versioneer.py` script is assembled from these components by running make-versioneer.py . In the future, make-versioneer.py will take a VCS name as an argument, and will construct a version of `versioneer.py` that is specific to the given VCS. It might also take the configuration arguments that are currently provided manually during installation by editing setup.py . Alternatively, it might go the other direction and include code from all supported VCS systems, reducing the number of intermediate scripts. ## License To make Versioneer easier to embed, all its code is dedicated to the public domain. The `_version.py` that it creates is also in the public domain. Specifically, both are released under the Creative Commons "Public Domain Dedication" license (CC0-1.0), as described in https://creativecommons.org/publicdomain/zero/1.0/ . """ from __future__ import print_function try: import configparser except ImportError: import ConfigParser as configparser import errno import json import os import re import subprocess import sys class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_root(): """Get the project root directory. We require that all commands are run from the project root, i.e. the directory that contains setup.py, setup.cfg, and versioneer.py . """ root = os.path.realpath(os.path.abspath(os.getcwd())) setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): # allow 'python path/to/setup.py COMMAND' root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): err = ("Versioneer was unable to run the project root directory. " "Versioneer requires setup.py to be executed from " "its immediate directory (like 'python setup.py COMMAND'), " "or in a way that lets it use sys.argv[0] to find the root " "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools # tree) execute all dependencies in a single python process, so # "versioneer" may be imported multiple times, and python's shared # module-import table will cache the first one. So we can't use # os.path.dirname(__file__), as that will find whichever # versioneer.py was first imported, even in later projects. me = os.path.realpath(os.path.abspath(__file__)) me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(me), versioneer_py)) except NameError: pass return root def get_config_from_root(root): """Read the project setup.cfg file to determine Versioneer config.""" # This might raise EnvironmentError (if setup.cfg is missing), or # configparser.NoSectionError (if it lacks a [versioneer] section), or # configparser.NoOptionError (if it lacks "VCS="). See the docstring at # the top of versioneer.py for instructions on writing your setup.cfg . setup_cfg = os.path.join(root, "setup.cfg") parser = configparser.SafeConfigParser() with open(setup_cfg, "r") as f: parser.readfp(f) VCS = parser.get("versioneer", "VCS") # mandatory def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" cfg.versionfile_source = get(parser, "versionfile_source") cfg.versionfile_build = get(parser, "versionfile_build") cfg.tag_prefix = get(parser, "tag_prefix") if cfg.tag_prefix in ("''", '""'): cfg.tag_prefix = "" cfg.parentdir_prefix = get(parser, "parentdir_prefix") cfg.verbose = get(parser, "verbose") return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" # these dictionaries contain VCS-specific tools LONG_VERSION_PY = {} HANDLERS = {} def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None for c in commands: try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None)) break except EnvironmentError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %s" % dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %s" % (commands,)) return None, None stdout = p.communicate()[0].strip() if sys.version_info[0] >= 3: stdout = stdout.decode() if p.returncode != 0: if verbose: print("unable to run %s (error)" % dispcmd) print("stdout was %s" % stdout) return None, p.returncode return stdout, p.returncode LONG_VERSION_PY['git'] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build # directories (produced by setup.py build) will contain a much shorter file # that just contains the computed version number. # This file is released into the public domain. Generated by # versioneer-0.18 (https://github.com/warner/python-versioneer) """Git implementation of _version.py.""" import errno import os import re import subprocess import sys def get_keywords(): """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_config(): """Create, populate and return the VersioneerConfig() object.""" # these strings are filled in when 'setup.py versioneer' creates # _version.py cfg = VersioneerConfig() cfg.VCS = "git" cfg.style = "%(STYLE)s" cfg.tag_prefix = "%(TAG_PREFIX)s" cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" cfg.verbose = False return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" LONG_VERSION_PY = {} HANDLERS = {} def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None for c in commands: try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None)) break except EnvironmentError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %%s" %% dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %%s" %% (commands,)) return None, None stdout = p.communicate()[0].strip() if sys.version_info[0] >= 3: stdout = stdout.decode() if p.returncode != 0: if verbose: print("unable to run %%s (error)" %% dispcmd) print("stdout was %%s" %% stdout) return None, p.returncode return stdout, p.returncode def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %%s but none started with prefix %%s" %% (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: f = open(versionfile_abs, "r") for line in f.readlines(): if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) f.close() except EnvironmentError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if not keywords: raise NotThisMethod("no keywords at all, weird") date = keywords.get("date") if date is not None: # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = set([r.strip() for r in refnames.strip("()").split(",")]) # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %%d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%%s', no digits" %% ",".join(refs - tags)) if verbose: print("likely tags: %%s" %% ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] if verbose: print("picking %%s" %% r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %%s not under git control" %% root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%%s*" %% tag_prefix], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%%s'" %% describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%%s' doesn't start with prefix '%%s'" print(fmt %% (full_tag, tag_prefix)) pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" %% (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_pre(pieces): """TAG[.post.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post.devDISTANCE """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += ".post.dev%%d" %% pieces["distance"] else: # exception #1 rendered = "0.post.dev%%d" %% pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%%s" %% pieces["short"] else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%%s" %% pieces["short"] return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Eexceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%%s'" %% style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} def get_versions(): """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. cfg = get_config() verbose = cfg.verbose try: return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass try: root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to find root of source tree", "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) return render(pieces, cfg.style) except NotThisMethod: pass try: if cfg.parentdir_prefix: return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) except NotThisMethod: pass return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} ''' @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: f = open(versionfile_abs, "r") for line in f.readlines(): if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) f.close() except EnvironmentError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if not keywords: raise NotThisMethod("no keywords at all, weird") date = keywords.get("date") if date is not None: # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = set([r.strip() for r in refnames.strip("()").split(",")]) # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%s*" % tag_prefix], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def do_vcs_install(manifest_in, versionfile_source, ipy): """Git-specific installation logic for Versioneer. For Git, this means creating/changing .gitattributes to mark _version.py for export-subst keyword substitution. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] files = [manifest_in, versionfile_source] if ipy: files.append(ipy) try: me = __file__ if me.endswith(".pyc") or me.endswith(".pyo"): me = os.path.splitext(me)[0] + ".py" versioneer_file = os.path.relpath(me) except NameError: versioneer_file = "versioneer.py" files.append(versioneer_file) present = False try: f = open(".gitattributes", "r") for line in f.readlines(): if line.strip().startswith(versionfile_source): if "export-subst" in line.strip().split()[1:]: present = True f.close() except EnvironmentError: pass if not present: f = open(".gitattributes", "a+") f.write("%s export-subst\n" % versionfile_source) f.close() files.append(".gitattributes") run_command(GITS, ["add", "--"] + files) def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") SHORT_VERSION_PY = """ # This file was generated by 'versioneer.py' (0.18) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' %s ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) """ def versions_from_file(filename): """Try to determine the version from _version.py if present.""" try: with open(filename) as f: contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) print("set %s to '%s'" % (filename, versions["version"])) def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_pre(pieces): """TAG[.post.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post.devDISTANCE """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += ".post.dev%d" % pieces["distance"] else: # exception #1 rendered = "0.post.dev%d" % pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%s" % pieces["short"] return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Eexceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%s'" % style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} class VersioneerBadRootError(Exception): """The project root directory is unknown or missing key files.""" def get_versions(verbose=False): """Get the project version from whatever source is available. Returns dict with two keys: 'version' and 'full'. """ if "versioneer" in sys.modules: # see the discussion in cmdclass.py:get_cmdclass() del sys.modules["versioneer"] root = get_root() cfg = get_config_from_root(root) assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose assert cfg.versionfile_source is not None, \ "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) # extract version from first of: _version.py, VCS command (e.g. 'git # describe'), parentdir. This is meant to work for developers using a # source checkout, for users of a tarball created by 'setup.py sdist', # and for users of a tarball/zipball created by 'git archive' or github's # download-from-tag feature or the equivalent in other VCSes. get_keywords_f = handlers.get("get_keywords") from_keywords_f = handlers.get("keywords") if get_keywords_f and from_keywords_f: try: keywords = get_keywords_f(versionfile_abs) ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) if verbose: print("got version from expanded keyword %s" % ver) return ver except NotThisMethod: pass try: ver = versions_from_file(versionfile_abs) if verbose: print("got version from file %s %s" % (versionfile_abs, ver)) return ver except NotThisMethod: pass from_vcs_f = handlers.get("pieces_from_vcs") if from_vcs_f: try: pieces = from_vcs_f(cfg.tag_prefix, root, verbose) ver = render(pieces, cfg.style) if verbose: print("got version from VCS %s" % ver) return ver except NotThisMethod: pass try: if cfg.parentdir_prefix: ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) if verbose: print("got version from parentdir %s" % ver) return ver except NotThisMethod: pass if verbose: print("unable to compute version") return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} def get_version(): """Get the short version string for this project.""" return get_versions()["version"] def get_cmdclass(): """Get the custom setuptools/distutils subclasses used by Versioneer.""" if "versioneer" in sys.modules: del sys.modules["versioneer"] # this fixes the "python setup.py develop" case (also 'install' and # 'easy_install .'), in which subdependencies of the main project are # built (using setup.py bdist_egg) in the same python process. Assume # a main project A and a dependency B, which use different versions # of Versioneer. A's setup.py imports A's Versioneer, leaving it in # sys.modules by the time B's setup.py is executed, causing B to run # with the wrong versioneer. Setuptools wraps the sub-dep builds in a # sandbox that restores sys.modules to it's pre-build state, so the # parent is protected against the child's "import versioneer". By # removing ourselves from sys.modules here, before the child build # happens, we protect the child from the parent's versioneer too. # Also see https://github.com/warner/python-versioneer/issues/52 cmds = {} # we add "version" to both distutils and setuptools from distutils.core import Command class cmd_version(Command): description = "report generated version string" user_options = [] boolean_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): vers = get_versions(verbose=True) print("Version: %s" % vers["version"]) print(" full-revisionid: %s" % vers.get("full-revisionid")) print(" dirty: %s" % vers.get("dirty")) print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools # # most invocation pathways end up running build_py: # distutils/build -> build_py # distutils/install -> distutils/build ->.. # setuptools/bdist_wheel -> distutils/install ->.. # setuptools/bdist_egg -> distutils/install_lib -> build_py # setuptools/install -> bdist_egg ->.. # setuptools/develop -> ? # pip install: # copies source tree to a tempdir before running egg_info/etc # if .git isn't copied too, 'git describe' will fail # then does setup.py bdist_wheel, or sometimes setup.py install # setup.py egg_info -> ? # we override different "build_py" commands for both environments if "setuptools" in sys.modules: from setuptools.command.build_py import build_py as _build_py else: from distutils.command.build_py import build_py as _build_py class cmd_build_py(_build_py): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() _build_py.run(self) # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION # "product_version": versioneer.get_version(), # ... class cmd_build_exe(_build_exe): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _build_exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: from py2exe.build_exe import py2exe as _py2exe # py2 class cmd_py2exe(_py2exe): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _py2exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments if "setuptools" in sys.modules: from setuptools.command.sdist import sdist as _sdist else: from distutils.command.sdist import sdist as _sdist class cmd_sdist(_sdist): def run(self): versions = get_versions() self._versioneer_generated_versions = versions # unless we update this, the command will keep using the old # version self.distribution.metadata.version = versions["version"] return _sdist.run(self) def make_release_tree(self, base_dir, files): root = get_root() cfg = get_config_from_root(root) _sdist.make_release_tree(self, base_dir, files) # now locate _version.py in the new base_dir directory # (remembering that it may be a hardlink) and replace it with an # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds CONFIG_ERROR = """ setup.cfg is missing the necessary Versioneer configuration. You need a section like: [versioneer] VCS = git style = pep440 versionfile_source = src/myproject/_version.py versionfile_build = myproject/_version.py tag_prefix = parentdir_prefix = myproject- You will also need to edit your setup.py to use the results: import versioneer setup(version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), ...) Please read the docstring in ./versioneer.py for configuration instructions, edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. """ SAMPLE_CONFIG = """ # See the docstring in versioneer.py for instructions. Note that you must # re-run 'versioneer.py setup' after changing this section, and commit the # resulting files. [versioneer] #VCS = git #style = pep440 #versionfile_source = #versionfile_build = #tag_prefix = #parentdir_prefix = """ INIT_PY_SNIPPET = """ from ._version import get_versions __version__ = get_versions()['version'] del get_versions """ def do_setup(): """Main VCS-independent setup function for installing Versioneer.""" root = get_root() try: cfg = get_config_from_root(root) except (EnvironmentError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) return 1 print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: old = f.read() except EnvironmentError: old = "" if INIT_PY_SNIPPET not in old: print(" appending to %s" % ipy) with open(ipy, "a") as f: f.write(INIT_PY_SNIPPET) else: print(" %s unmodified" % ipy) else: print(" %s doesn't exist, ok" % ipy) ipy = None # Make sure both the top-level "versioneer.py" and versionfile_source # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so # they'll be copied into source distributions. Pip won't be able to # install the package without this. manifest_in = os.path.join(root, "MANIFEST.in") simple_includes = set() try: with open(manifest_in, "r") as f: for line in f: if line.startswith("include "): for include in line.split()[1:]: simple_includes.add(include) except EnvironmentError: pass # That doesn't cover everything MANIFEST.in can do # (http://docs.python.org/2/distutils/sourcedist.html#commands), so # it might give some false negatives. Appending redundant 'include' # lines is safe, though. if "versioneer.py" not in simple_includes: print(" appending 'versioneer.py' to MANIFEST.in") with open(manifest_in, "a") as f: f.write("include versioneer.py\n") else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: print(" appending versionfile_source ('%s') to MANIFEST.in" % cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: print(" versionfile_source already in MANIFEST.in") # Make VCS-specific changes. For git, this means creating/changing # .gitattributes to mark _version.py for export-subst keyword # substitution. do_vcs_install(manifest_in, cfg.versionfile_source, ipy) return 0 def scan_setup_py(): """Validate the contents of setup.py against Versioneer's expectations.""" found = set() setters = False errors = 0 with open("setup.py", "r") as f: for line in f.readlines(): if "import versioneer" in line: found.add("import") if "versioneer.get_cmdclass()" in line: found.add("cmdclass") if "versioneer.get_version()" in line: found.add("get_version") if "versioneer.VCS" in line: setters = True if "versioneer.versionfile_source" in line: setters = True if len(found) != 3: print("") print("Your setup.py appears to be missing some important items") print("(but I might be wrong). Please make sure it has something") print("roughly like the following:") print("") print(" import versioneer") print(" setup( version=versioneer.get_version(),") print(" cmdclass=versioneer.get_cmdclass(), ...)") print("") errors += 1 if setters: print("You should remove lines like 'versioneer.VCS = ' and") print("'versioneer.versionfile_source = ' . This configuration") print("now lives in setup.cfg, and should be removed from setup.py") print("") errors += 1 return errors if __name__ == "__main__": cmd = sys.argv[1] if cmd == "setup": errors = do_setup() errors += scan_setup_py() if errors: sys.exit(1)