pax_global_header00006660000000000000000000000064130663730710014520gustar00rootroot0000000000000052 comment=5827683a2733a78cc6cb8c68213a97b7a9cd37c3 sortedcollections-0.5.3/000077500000000000000000000000001306637307100152645ustar00rootroot00000000000000sortedcollections-0.5.3/.gitignore000066400000000000000000000003031306637307100172500ustar00rootroot00000000000000# Python byte-code *.py[co] # virutalenv directories /env*/ # coverage files .coverage # setup sdist, test and upload directories /.tox/ /build/ /dist/ /sortedcollections.egg-info/ .DS_Store sortedcollections-0.5.3/.travis.yml000066400000000000000000000002641306637307100173770ustar00rootroot00000000000000language: python python: - "2.6" - "2.7" - "3.2" - "3.3" - "3.4" - "3.5" - "3.6" - "pypy" - "pypy3" install: "pip install sortedcontainers" script: nosetests -v sortedcollections-0.5.3/LICENSE000066400000000000000000000010551306637307100162720ustar00rootroot00000000000000Copyright 2015-2016 Grant Jenks Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. sortedcollections-0.5.3/MANIFEST.in000066400000000000000000000000331306637307100170160ustar00rootroot00000000000000include README.rst LICENSE sortedcollections-0.5.3/README.rst000066400000000000000000000065521306637307100167630ustar00rootroot00000000000000Python SortedCollections ======================== .. image:: https://api.travis-ci.org/grantjenks/sortedcollections.svg :target: http://www.grantjenks.com/docs/sortedcollections/ `SortedCollections`_ is an Apache2 licensed Python sorted collections library. Features -------- - Pure-Python - Depends on the `SortedContainers `_ module. - ValueSortedDict - Dictionary with (key, value) item pairs sorted by value. - ItemSortedDict - Dictionary with key-function support for item pairs. - OrderedDict - Ordered dictionary with numeric indexing support. - OrderedSet - Ordered set with numeric indexing support. - IndexableDict - Dictionary with numeric indexing support. - IndexableSet - Set with numeric indexing support. - SegmentList - List with fast random access insertion and deletion. - 100% code coverage testing. - Tested on CPython 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, and 3.6. - Tested on PyPy and PyPy3. Quickstart ---------- Installing `SortedCollections`_ is simple with `pip `_:: $ pip install sortedcollections You can access documentation in the interpreter with Python's built-in help function: :: >>> from sortedcollections import ValueSortedDict >>> help(ValueSortedDict) .. _`SortedCollections`: http://www.grantjenks.com/docs/sortedcollections/ Recipes ------- - `Value Sorted Dictionary Recipe`_ - `Item Sorted Dictionary Recipe`_ - `Ordered Dictionary Recipe`_ - `Ordered Set Recipe`_ - `Indexable Dictionary Recipe`_ - `Indexable Set Recipe`_ - `Segment List Recipe`_ .. _`Value Sorted Dictionary Recipe`: http://www.grantjenks.com/docs/sortedcollections/valuesorteddict.html .. _`Item Sorted Dictionary Recipe`: http://www.grantjenks.com/docs/sortedcollections/itemsorteddict.html .. _`Ordered Dictionary Recipe`: http://www.grantjenks.com/docs/sortedcollections/ordereddict.html .. _`Ordered Set Recipe`: http://www.grantjenks.com/docs/sortedcollections/orderedset.html .. _`Indexable Dictionary Recipe`: http://www.grantjenks.com/docs/sortedcollections/indexabledict.html .. _`Indexable Set Recipe`: http://www.grantjenks.com/docs/sortedcollections/indexableset.html .. _`Segment List Recipe`: http://www.grantjenks.com/docs/sortedcollections/segmentlist.html Reference and Indices --------------------- - `SortedCollections Documentation`_ - `SortedCollections at PyPI`_ - `SortedCollections at Github`_ - `SortedCollections Issue Tracker`_ .. _`SortedCollections Documentation`: http://www.grantjenks.com/docs/sortedcollections/ .. _`SortedCollections at PyPI`: https://pypi.python.org/pypi/sortedcollections .. _`SortedCollections at Github`: https://github.com/grantjenks/sortedcollections .. _`SortedCollections Issue Tracker`: https://github.com/grantjenks/sortedcollections/issues SortedCollections License ------------------------- Copyright 2015-2016 Grant Jenks Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. sortedcollections-0.5.3/docs/000077500000000000000000000000001306637307100162145ustar00rootroot00000000000000sortedcollections-0.5.3/docs/Makefile000066400000000000000000000164351306637307100176650ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SortedCollections.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SortedCollections.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/SortedCollections" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SortedCollections" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." sortedcollections-0.5.3/docs/_static/000077500000000000000000000000001306637307100176425ustar00rootroot00000000000000sortedcollections-0.5.3/docs/_static/gj-logo.png000066400000000000000000002663751306637307100217310ustar00rootroot00000000000000PNG  IHDRqsRGBgAMA a pHYsodIDATx^-Q/_1~7ƫ9NRBY9|1Q XB1I#"XFMI6"(`[ !$9l0^j֬YghS'_ݯW~K_<]t{ڭ-:`^~>|~$^. /~gI  㙮 X?)ޢ]D=2= ^mSat%gii^mJm}:KA.Sm,| V6 .NI;~x^NeT\?ɓ_c}-.<_G-??MP7fO'WLpsv197O;ǖ/0g^kn2>j6o?+$3?UM>2<ξF@66˃hiO 3Hm;£"ku NFRM{6 L(RY`4~_ }0·yi.>I-}7//}򓟜oN23࢑Ix&\mb Y+g&hި "Y*7/Մ4l ^x$)G*YyJdϠbS7g8t,m]J!`.*쎄ٱg(w;"mDI$/{|w&I/4gϞ׽nZ֕47K2bPe۫*`$?AvBOV2H'(VAľ(%šJ7NS-f_SSaXmBye53NLKCğXm+G *؋dce˺x8[ni:iH @o,C'=O^dgXEeJu]qF5)Py^M$-N Fs#V\@1Ȁ!VXf )HJE<gIC9~f͘w$ ǥ!`$d/{qr|#<~K/5M<3gLyѺ0DB<8\4Mʦ5dt! }ٕ]sNq_C8cRy.!Eh}uzAls@IQւx eo\Ds^(üMݤ%%&k*&?҄9WZ-a? tNS'Ntj7pL%+Ns%'3@y-4=4lR) :YsƈSI1$*_K^sJ!zFbEjٺ&-c#"2v,Mh<!ViǛo~~*Q:q}j+^M9UFyVn7[w)Eȣ*Y~vw=݂k;ѓf |b\G-rLTKHZiUb*-̲.@FRAr\P># ] rs22 :#Jʇ? |a@c/d@.8J쫛. ۣYdLw@u]zx'hTYSpC-`& PX1`!az@Eq^>G!! N8&P\S*K3N2x$(;ݱQE4-+׆eo|Ctj^J @9$Ci=%ZQ EPTb!BZs-D+xR@Z&1QVATn*dEQAĹp%Vpsa.]QL#DU[gⓋ}f%Yz1^pWܟccc`a!U<_kO|{ .(n; &„.Q2LwcI HR*B^ZJ Y!Snjm*~K] 0mbك@c6hKyr ѵC)^N΃[9>&In(Chu?)i?8b @m1reH[L5p>`J5՘3J EhIVSz)cŸ6xHAYXzꎚ[|Jl51FkVR6Rt`ŤfA_Вu r[Av; s @%I<""nC^1"F'Y+LC%;foBLH$#WJsO+ }[nXǵl"Z]i~C1'X_Js.MI2e rX0h$FE`u7,/bNG2ܰ6;pNר}5'v "vgE\MJų)<<yQ ,؍ʨI#\lIr=gXb-52ӏhxt RZĸC٨A^.g^J0:t7a':*h!%#k\ȥ ?S[bV 7~ׯYUZH1 ՐDK_E> p0HnVmNJ3d 4OEmۄT.CA.zdp ;XgJ_ⲁtS'`Ճs{\"9N  :MgՄd,Rqɂf!~RfCt>*>We"ILOzVDPa"BF Xbabu2 3kI0!>AE%FsR bɼcBQ c%|i}M ?s"8] B"14 i5uR`YoGSankM9+ɦ:v0ie]t#=Lqg颌ٳgO )~3@ y r$n=4M]. r#1"g*(3D+K.Q,ŇI֑{$X| @S`f{QL n:HTn'A%LVNljPU6]jPK ^ Cyx^ `c42,(ɺI+3P:%rQTtJS|OL`KYF7)J{z<{l p:z1%[cBPhZ WRĩ,uq ?__I.%= hؼ!c-!"F!S(@vm*(޽r@=,Vw|)&c\W[bhe/a+ b"ߗcR4R2.YH@s^egOEtlN!/# = 893_%\ -t:izSz!YgKd:00\ Aa*v͆ p=\x9`Rq23e" fm7jfPN"ZYh'q[-g>T[p-?Zh"=9t)& . C'?%}WH,*/ZO`0 RךPffp]V$2  5Ipk:!^Sg8B<-m!=6^}9*^Ubr?`"bJtK|L¸dT-$%>;WaӴt#a6u6~t#bW mmF 7y@~m=) ԤCAkvx@#X$aPMB4e. zc,_7&tmsN3QXQDs/u'!ssBOy(#s%gHufR<0y!8#JTٕ;q*!ҪR2-&:k3a>_ߡc۸_ /DPg|pt~!E)Ȥ7M1=U4Ҝa{pɑq~$rLB%j9gs\ y Yo9Ƌ7bd/(6 X),05yh eAv)e2\2 gӈ٦hg%K &Ek~t}K/H{>3n{wB z?'I\h>E6Y%pTeဘ[DW@ڍ9KB.[x&ӄ#4k.PnQp-HR\GTmErUZNVPcd-x,0 !+F+wWM'Ҡ<$J˯n8 Rll>^*{B@G {9J @ X$wŪ&_2dF-@a2:&]+ TmU) #Qn .=ی-?N:`, ( $eR7C*G" xQQtd܊BA2s6iH]fYΧ${ʊVVܽOi΄2Gxj}di:^DA%%H# 3I%hy,ti-"wIa2FUs% Ԓm&L($ fVºdվšz Tb MZR f$"D͓>Yl!rA-ɀgl&Vsܻ~u3fB'i'hĠ{ =tAZM:z(U%Jvr4 d%ËOw Qb8)>"`KЇ`kd1f"/x:) >$Ӭ.#km1Х]넡A~}T^ iQĊJ\*:V tW*C!XGQJ) ٫.a϶K`#t W+Ql&xlQE%̐g8#ll$6 cR+{M82[_4h\"9] 0)(Dkp`x*rԎ2_U#w},%DY7k:G)6.z]ε5oKTr9v4)nI W9Z @ӢL}('D]_(PXƣ{vzy[8b2*,rR T|ɬGdwFw2rm0v[\jI@i颯ȹسqWNa:b+iяe Io5NKٛ Dqe+ce2 Y6.WnǩUgE>N=۵kj7{YӐ#qg@@*6H\E~Eo88/q90l68&^fH3'$%Ѱ| Pvb'x|@TT ʎ= b_ ސݬc%^o. SSGvo*&{Z9zWY]\l(3]U^?VN>}sswE^vW]zIw%_u/xeN_~x-]se\}٥Oߺ.pȅ\p|۷/p5 灁ۜ+DSݹ#c{}@sk1fD"wcc*0(K׀+aYZav[~G%4ʧ Bs\ Ibꀧ?Moo:m߼ʫ6`4w4Ǻ+Җ a"lc H lhc^nDg6aO(y_se7]sy#?pwn7?{|w=ߓ;<~l~|O]oo~у/?t '@v ={9b$ەqԌ9. ~XJ`}C;<9o3'qyEnrRhp}&[jX+ ZSR.ᥲe M1KJ1g+Uq)bb !z\v_5F :lGƙ7"1&?h"__l޻!tiS{0GR3H:VHJRM_4 n~}m_p蟜gzώ>$/IF}(f!e #D]IO2h6uz!t% &Ĺ#o:vo36M BlʱE֘ "]Qn>c gxhSDXO zfԇwM)'OO Ͻ֛zJ;\xn[2AрQ87{iMakZ8'f4N8L m"-elÂ1pSaw:,nh j7D q詘cyUVyjf/73L ggpS lY$ xVԱ%w*} O&s”;n'雟9#9黠`Ɯ,$ A] iVC׳m @IN9I5otN_']niJN>&kΆ"&dxcU2L#)[a M`F.%TJВB%^w5=hʾP(.C-_A6")lOwVw RI6yG>M}N}]"=FJ\ $1, /Gם,JW"1Ƨ^rGO]~vfy|ޞtT1y|-}2sAYl?e%bkD<{A`R4>}b/<ċIj.XuMu > b&`#GIeiB;vYxP_(H v"T!*ۤ, OO(~SO,@WKTqT3غ0"vȭ5M4Ղ~}*cs2قKgQ'VoZf$dxY~aMNrT*F{,jVq𐂘T>>q✟?}w=y詗|ݷvõ2U 4Gg m{zVp%+zV ;pCJ"aJ) B w@QXъ:@=(˯mп˿ ˜MO=-,fER߲(L&:81A ))L9"zUWНȑ:}&9UcGQ3F]ѐ~lz:^ha~(XI!SwĹmġnSJ()G/iX&Zߐo *ev&* PIaa^BS2y^13^|5 2H?JuYOE?C_wbT"؈#S0b)+D-O4j l`꿜G_z'o$Tf#iV(Aw/hKb"{uz;E8nWE]zSTPʺ% o I>;ܷO_UG^+/W}Ձ"tm=*:&{oFG{s+an[|P`!jVO5<:??;tࠦخ"0Z1")/k\$gtG1JQ~o[8}N;AnQ3&b!r޿3\{AFzj4(_[bGvy`'N:,*!HbQ2bV{ͤεRFtDWu@U[^\5ӃH\-gOV)o"GOo$Y1m>qVld `C'r5 K|.Ox2h {nyWypӊD-˘at 5^[=&hjMlvdt˹WkgB3$Ncq |=6XS0Wu=hФygyލi]R_$Z%M դ52jF Ih\kLMJT؊8t3gHwcAXI<&g6gjdvI )}xK{oGL)<8oJ@㣀$I2H  הE(R0֬bd(UlAy+@u&`?yb?|$)-yT2%|On/Э 0@GZ5+nue1+*Y2lP\ɚO8C+cøCdFlbee\u~LrW G?Ӛ^'-q?|t]}vR^L!)CGߠ6](Dݝ;B V2J@*).\.(6c㡭9!^yg!7j{=C~JUgNh˥]V'O a,XaR8Ϩ"=y)C%8U&G Ѳ: 5 I.У Itς"otT mF |ofk?i]-;c!8ˌ`G2)ECjM)a:"7lj*C=qs3Gy )]%&'^2H5+M\FUɳ |ڄ.r4(r9R*56EbXYlLMa% oyqY:kWdL!xq|w z#+

#" = Yy5vW-6ͱL*Es)5l5uP_b.\ RG͜B9ocr?q5 UMlF== v׆t*@ZfF'c|v:cPtpA:a|&`GHq)>sРv (GYW.ҽ tpF@0m7D(#bA\V`qvl!JH2B),02I2]a4s2q*fVJrE@\zVtߓތ sgu4+( ~@l^vMʉ:{?-~<B8vR񧋻Eo|=!:P 7*й֨C>/[QrHd 18R3[-xWP6 '(h8Ay.OEmʺQIÅp0φvͨ#j(ȂKK6h؇PJ{R_P "z5W)y^,!AzwI-WFqUP=0tr O'^YCmk| rR*R3hcZ_zS^ d&8rH8q<0UumC<+ּ%#}jw'FFxUjDs&|@ggq \FsQh7ȫwϿ>~FuN;٧gхuvS0bCRxEL9hC;Nj pI>X2C{tnW F31Kש4a3 \") s2d=ԾFAgNBpLBEݻ鲙XL#͐`7%)ov|9fl[iܢ&4s]ǯ|!C,f fK5k<6۽ѱ#TH8LBrB{ +4.pzA|iexsRbTPJ89NY䔫I gZ"Cc_xॸwS'L5sx#Ao <O0P-fKH@̐JP@[r>[స@ohBx VF^D̐a; hAӣ>6AjO:L'W^ J - Uc+׀~7G|MYcc=뤚587tnN 3jK}sЉSPC+v PTI@`rHJ Rl"!(9 # +}:йYvMJ0"{Bb*EgU)5zTEʨ]%M((~lpe1CqqMl']ރ*|vZd L!G"b y?\0wz h YFE"}1 F2T`$c74Y nK a};CaH™tf^hT'm }ΎgO߱yƱ́ ,WˊOv,FỄP;(M7m!TNMor{١C/ ޿d?y/W9=Om[>|3kCiB'ޟ_D}!vY@Lm4.,YK" Āy ig *qM$ņrq"aWIѢ?ZHI;;>cN IK (e{voT \\gYT(fc=ٷ ؗݧټٍƢr-ؐ%Vrk5`MH_x]־y&wzz92t:7MsV)l&sΙsˍrtϻK^yk<=O^ o?ݛc&ǎPÙ"z"1=&4SC+?)!+4ʥmz4wu, e=aj8bo52'BKs3; s5lj8[qÍQ(1dc2n9 jAewn/yO8'tοÿ zRŦt nq\o^ OS[n(d鄛S&SwMܿ.8g ,&rK?^7)/yoЏ7~36%&0ݴ(,),Z5-XJb[e^E2abNX\RQj/i޲l" S-rz>6`I0>'$Ei,24Gh'Ma()3Fh97b4,cۃtdSiB!`iwSl8V폌Ԯ馝N+.&P$^R%% EEn$L0>kw㖇_xtOszҩ 5l@$ \LJ%t V^dUj5^9ʈ($Ưin\~#aFgÉ8ht733чVg?O_~-4m$EC}cqRFJ‹U,6*NhQ:Pzy*={)MJq;Pwu - ֧ٯ̱%eJ_|2VD)*`?;.w9w)EwC8qtߦ?#]TnH h4ve q@IN;?/IhCrƘz)Dz0cT4@ 8@';TpVc53v}>Pb-kC!z @{ a,B0O%>jff}Oh&cn:n%lwڻ$7ՕS:59tSF+!teWaz_-T @?"ڕ*l]]yT^woZkTR!B:Smx Zlۂl ~&nzA(7ఘ/d 6ŗ>IW@ O3e i_ zxc6ڕhVjY܏Io8QKZ t4%1 G=60hZ ٷ0:Aɉse*P᩵ʸ ;ɜ~֜3/G_;vݹ/JO#Ӂ˹VHQ 7*ի΅!Y*0 +MW5AڲVA+CNR0P"B|eSaZ:+zn p WK3}E@)Z|Oـ !L$xaGM3|,$nChc߳bw{..yw6:-yH mbz޾}_yT{cG6Aoi#_';BgR-ZwM+<_MW)jhP4m ݠ$STh1c =sjrm BA}F(JkΡ E#5U) ?Ȑw*/~ 9jє (ՎnSN^4=}/π9c8,Kf)f0Mrc$_x\{zǴkvv:-'&5ګ 8Æި[KUy" XNvd,n$Kݐ`6_E@V$U1mM`|e+6PvS/mQxf6 THHn8}<ʖ Ng^pFj~4$<5UCw%Q!Ո>Irb4I;7E/*ݷk$Ox]fFR΁$S J$FHQ]wqB= enK{մU~jVsMhmSJ^*z,'3/-a+pk L-^J OidS[΢c΄;ΛziGO،u}82)HG1YJI{[蹊9q63F ]<АT=c[tDġ8o473'4g?HݠSt]=<*qRAo Йc:.…XUn\aʐutXYW5*_|Dwj˷%֡}&9iU7YIq%`WߏUq83-Lћ:ntKd:)Y9`i>L_}3vnƳt8Oby<}?aʩ0ZE]L Di8y1T~1\!9;&2ū;pQtNÆb`1eYmjh(qlOYfPҴai5{>d+iٺ0uC)Pz'q7GpjƩ1}|8ۄ=}eOIn a{S=HXOo$=;CSdڤJe 9w~DlfFm0^$1a4RD0[tc#> ;施 iI "Gл2.Q@Cj!|)Fz MDxzaj'#![ᆪʀ gWs scW ;{hV~ mb~vڗrHa;l.Cp%tq&%NϢB~]8utܨyB̶ 䯸56ujIx -n7XzW+g3eJfcD{NPItLAn*F!ˊt&G2lÄ{?+*?Φd̹VС1_PNA-6Ϋ^Ar[>ZWBX)LHss9 VA zט췌}=Ĝ$w*O P|!Ѧ1k +e8NGHD3\vceCle`s֧*&0t{].\@ '0R n2U>2:q}2N|֢%/"'I2TwK >+GBxbzͶ)a1B|n0⿞tsN]/Z-N u{>;7̋hC h{<Q!(5fñ$weTv`Yd5pܢCF ӸV$p⿭L.dDM&Hj70I؏Mnas̓, FRhEZ.leIҋUӶې*[IL 1ԅРqPDCKMWIŐPZK'G͜&MduD; bi@NrBӿ/*UXyD'Q2&Eh?Z3v2O<^x{-ON.7'VLg75(ĕ"+Y^96@>|Y [kP_/eeI؂'Wɢe$d ( LT旻룜Iʺ3P E38.Pp\k$kV$p4J T$RqژW~zM$^?\J 30uW^S՝ےB?SŦLLq让W K-P[ICSC)^%\7"#ZhS[rްp_8aj,&%6Egƅ,j z cӀz,.D"2ᵈy[wT/ CZY|u;U#e\OEӿ2OM]4 :flJ3*І?#.WMhJ]ѕ#U…)GbOE~-~ t`LvU*q6f0Jp1V9@jA s, (Cٕ^ d'l⬂i&ǢDpa"Q$qPI}Zqь#fˆ_džcxE~eӑqt2y7 =K̎ӋV/f OSú"mhdŒk!QAR}U>ɋx/Xh~;UЛDHJJ!d:%AQ."򻐎&$d4`.WJASq/ 5`rFMpfY1AY(r 0s$s=k .>;y~!8׃$!r[<ʩowoݟx|PIetѲ( c,2} f4[YxΠI4"1B t*[,j D* [ `*l,BӮ):30g5KxL)|Á8rɑsP BAOO.; St6 e)`f=}5빨:mn, b!/`ĩX%Je1$U~l> lcϨ1G"f(^@Mb?lqϢz4ȗm0EޑaMpŰsƔlዑsM_k\!On@RmSiZ[ `-ݥ֝wczUFhq$٣BS|||r{ܣcUYw3spOD@ h>hk 5+0IG2kR:cb2謵-#"wVBDޑ >z*]LG(_>.h J[4ݩY>ᢍ'eS,|$}ц64X~?=l4ۆθ(Ԏs>[̓雧7bH0ckֶ&; e2Gr4BTdx²E~1o.B|: ijgyhS< u֪$rxb pcJsk Tquy[ÿy{|n߻G6nߛM}׾|돾^pR:D[Ln<OӤ 92$?0c(ԭr** KLh٘NSjFD"!|0B?'D! k<'"T,+"1(tùHZMhfI;#gopQ֒ ]qs)y"KMi[zb%aOWUIp-.5̷Δ۴0X.x}jߛ;g4\9ΟG~oǛw)[Sl ǡ8Y`hbh}rJ3{-*n kE5,TQj<={4}r,9uSxT X2<@!]1/hф) 8nCxˆa;i˸X뜟 rXuJjmj(v n>ZyM}婿s hvM H߶Im{ck1ű!`.d*2XF3ܤ%1#>~F b?%B$C(A$q9LgD 1@.) [Le bjT PR`;CȣZf s >Khp_'^Iig6Vvu%Uw^:e8ձcLY01#lQ|Kn4wW OP(G޿Mq5RAU%ȷ.D|HV~I(1#X#caLC| R,J7D49z P2gl *}*]0TS0y>["BD}|Z9 v?uꮥ3g0j{/[:@=\SyZ+(IHāh;nӋH5S˷ǟrSu"tS1(S w:F++wm¦P!6pg- D,:켢F?*>R @and#,i,ޢz4,)Ʉ#̔$R^9i$ANOǎO?샶Gp"mդ'vy$Q$!r#="66*f+ S}T^7[b 9:_ҦS]w|?w" >CrRn_ԑمhߔ\cr6 1i^7䈟 Ee$S RTL'լj%vLtEM4(CX`3tB0Α|K.8ڇ^ yLDLXcY˸IO='#` Q "GodԼ?{(C bݞ-)﹔{I&@)_JW/yԇϞBnVɯFR W^T/'IXe >65Mtނ^4)[➞^t=®FUH<7ۊǟ]lDp| К`1nՒ!i==%g-;y"X8vО医-^'/%*TF#l]Zf|m^2v, jGD{[ng{dÔǠbRz_x,>$j~=݆ FrkR3Y 2*0J8SFDŘ};ٖi|:*'1z>=볿(ҷE^޴{𰥮X?utϏ0w; pfVLEÍBD;_g҆wݲLElc#_oϾP@@(%ddRpPsv8ĕ~9U̚NHl}o DU&ՑK'QΌM@6B%;ܻ1ߎjʐZgމ $٣ΏaZ@zн4|kf}޿ ]:u ͽ9Mzr\YJL#[K^F>M#˩+~ ) CA(zRF!y21 /ڡt=rd9x.NHA@Pș4[6VXPS.+qۀo }U9^W=o~^`p1VϲE n2erUj<JuUFq%q ?ڹz@h{I)kOeTT˽iPɜ%OTD| Mθz1:Kq [NS3 >bzt}kɴ~XF|ߝ[T-iVe)@'=D(B.͞is5ߛW/drU>]&1._*C !ȯ -Y#`JلE,Ry:Qم<>[ť&Cs&C`(^^PVDv(: .A؄")GH1yjyo| gG ߷{CK3S)xOq VmX rtҒ2­G}9ءdـm\7ҝv\ mDxS5ķV]{l>k7]Bc8Y0 KFVyJNZ@%9sTe7Q,0v)>2iV3짯Wzн|eY4OPN2L$?#?yc_͸k䪷y>~~ȱ=yVo37d$HICf3r߽ L8%Hct(3l;y䚷onMA+ &s;IfˏU]kfDDqݒzBrIZT'4fs%e@U6F 2kH#]ʁ>rvB) سOԡ3Og/Y9( nV3@K=dE~]|yhZPPmr8U/J_.ewzĩO]gJ^Cy=VD!.UO1,")j>:.L_T $0)l ttb5p"o#0&:U>5%Fė1LA6a{Jɤh~S wO8wS ^N5zo%O{''9 "\ȥʼRn+^{'vԣvp]qNًP+qC[@ϕѱA J1ה~#*{蟪Ѻ:zGʒIc7r6| 3CQ3wG9:c#0'4ﰭ?ݶT&LO>1î@1 e_[>ʹdjsr`: GUsQTBEj>iXD)!r@\UG홑xbS<]ozat5$!ƕfZFv9fYt- J?) LbX"$(A涺\(J9&5+x k-zǤ`r&@qIئ@?>Ͻg{#}:ajRL%v!3U79loCȋ?cɎ5ޔ>}|߿:uw7CE{IO>x&B @SSo=uE !̓jl~)}OD^d.@}UaP&E2?zP Wix-2 @q@z$4jk >_PN|i5l[8;%\=FUĪx)53q% oẟ>uG1~r%84[G28}=CG2JKr%}7*nQ/ҼM'O_-TDB:a$ z[<0*sgL , DMKc GKY.(RONpơfm,!YY&~ˊxTRyJ62 gM4I.ZiE$αUETc,:]>}tCd6!dO7L-_xР5⦫%ZzB`]3.%hZ=xNR9ީRA2t˿n-Y*Lە0lQ=~4.Mqc,@T"g'7 @m1s*}%l&]<U8#Կ92&4ZHv|>7[r''C{ɻ8sYԡoG!eZc+&9 }ȶ!a() xPSKVHߴo5>-tPKԵ f `0yi^6MXC1MpV C3DQr.~ee&K IrE.豑['A$",.8{5!RƛQ`qX zT/K\}O:P?@cԴg|ջ bG)L;yWw$S:}xUZ 3LHW1T2xJC탟v" `9n IIK(P+O?y{_ukJؘ%E5: H s*IryFy)S߽C"A"jCo)| C̚"o&mi^ʇGru(eD{p)&򤁩^wxݿ9}ǜ) O2=y-]RoWAtXMjٌ*}뾫"QNC3O"wzS݇^c4$>!rmh)%70XdTOm(4#B4W aF)hU,(%s4o",Вb*2B2׾?*R y2&e7¾dWKS>ޟBeK;@xw 8K}uWj)-xbP3@.&^*<{ XUHr,* ~;ӘX~Vza1Kbqh0dJ ^(ud&@A4ѣE Z2V|v!'Y+S%v@-Hs觰Hj-!iXbϜh.[svx١D-43@ͷsBۉ_!X x>IV mF\ l #E,MqTS-νGEB5ll:N/!Hao:oyϮfĉXՑ4Jʣ[z,| )6Ҭ0x5pU/sXyB55AjgT`䢍sb) [˷h%kRY; 4; "8zoWD_ LzȰ7#^ϞHfđ*tĠVbKERWfl+'QTO?߻z"ψY4Tm\|NKsb ٌg)eϤfP/yyOHiG*@Fk[=6Jo-Tm <>fcuX\nV_, GNt:4evi km y~PG_H.$jA@"YVp24"wUks2M[|4'ՎRgC!}81Vӻ ,Fx O U@~*СB1i]}-⊟[FyrAV'×_ ǯ3tg;Oǣ}$=i\U0ՑNl %Tt^׿CьEhn '6AJtozC__q5nOm©Rܺd"TkHTmuܾdP1hRkG=$Qh42-\Zhf٢ "h@l]4\Nj@"-(=*.'9I1̀c;rOZP+1"3$'O/ UHڱFaX38gnKsMoޏtͿZ x~`ߋOyUyvY:k $ISsN qn.{1B@LVhs{K[9Q"n .LF/M)ߢhzqJ+&3)"˫}#+|%f??%oʹ@} ؉nfqrDmJQ=. ޝclc[`A0P<7v=&Eî]ow]qF{6&i+0+AV'#EmYփ9>x6$8"aHW^'=H|v /?=zFWvRy,\tE_)<`r9ߺ=jm~淼?+/ZӒC;Hy3Jwn_M*m.K A@^YsN) 5a\0%1zI:-8Q몜A(ГxaERph/zSia`FHߝu>Dy~A] fdϞ>:6֣^*pHi+d̃ Ң/z~oN5M|l4;tNbsM9޴yoGZВL,(;4x|zCy.Ϗ0~(R\dG_4,0 {" -lpd=it%O>Uзozc7=+3,e"TKeא&&߶9i%h׉/$p.~TC&A21e#"^!IK-l}fOu]1~Ó_<{ܷbk-:x GiJ>7j5ϋH`ѓIt (DU6g܃9`>RY!&VU"(Sl9ɗ3)pHˠɨ$@oωq-ѶI+C…,\g~_i *ZYhRFD">Pc@Tr6D>:|@A:oo8;PʄZQ'Ι#u\譋 "bVB҈ l>> XA)IlIn#3>]!nTCb )$hwՔfU'6v.%|5 2?eX#Iq$AVG+(:AG$°Eclם{fE6<]qڣI]M].kJt󛏜p3<Пx ɾX3>;ZېC %(O![̳ 1,o]!8g`V.lJ0?O,c@Lg$G. 3[cZѱa88A莩ԓ |(Ϣ%ثdYB&bǵ*<{(L0 `':vcs ˦@r2:g 5AljNӷaH#/5ⰝUTcUo0eRϘbgg6`OqG=r"=vdKlupX\`hl /Pt[ W$NjD F~jpeRlUQAJ86j#?XЇ! kH~v3#5Zi_uOc.zjE 2-'7tE'˓&ir筷'SH6\Fz:9l;C7ZD%i}G`مY%.|R4-*}N!,t6k4KU; ;[uV?"p5Bx\k&3hƄ @X7&"A٨ , kctOcjE m+Q$Pԡݮg|oX{/#j7MMOx*MZ rΙ%QfY7J"Ht„UIdZQOԬާF蓖b6جߖGevEɣEOy X M7KswaABO3`fbIk%S~5_m7Usfz8n]bxZhoo{|>FdYTzHGdzuN^(X9馇dQPU1dJd (M$-.M_B 12 u`\X YU38>,-L^յ6~GB SW2SDe!YX_ȧ 7R &WleOzbM)R"9Ѥ>9,@\;b*_KsY/ԕgݭZ% ie?}&ZJ oW*i! G9'+?rI#97Tas' ]eHoL당f?O` qZm-@3}`^v6$?ӷEYN~eOtPI.HKz$#GrniG"^#u0t`>ŋ'N^kNfKt]E=|mӞò6JO IUPm*Pplǹ*We ؅ş֏0 >tN$]@c7+2hZ&z|2*Sqo=L_?sboUQBO} tR/Kd:<}` Y*%R2XD`RaG=$̣2XȜTԒفRFf˳D52q#i]E>;҄WB+@w&$¦gOgVNq)_P)ɐ}IAvȤ:ufk$AAJ<οOj)iՌ*ۍl(!@& Iv:) ''d3R}j|`KvKq- DL9mbծ*l>P33$;/d)%3~ V<>VZg=2 OJ*̴Rv.镶H&=jAOG;@%?S)v /:$ }l4^S4l. \qx.k1X"芫2fA`FV1t^P>]INo<3=چN$_'\hqDd_TKsk=rm~٩XzhGRGվ1i ,n2FZ[*ۜKsjc:1hX.p}3Ԩ"EF$\4n[A g։7 V,+5, e+޸d`-Lnc:F:Dw+jba-܄$ñ)”>xē:XX%9nӓ >>wFzR@J-9Ҥd&lucwt:N &*mN v|]%RIKt`$jU~QkHjT73yt`Vgr2k< Z̍׫٠5Y\&Sl[S:&s8A₸&OHI\&Xuf/^J6Jcz0WL$)<+f%7Z?S0Z_}[lbYԍt(P~=:qqޥԗ|>a2얕:pt|Z z2\!27(j 9X(5>c48(FE2Q0QR2~.N'-)3O%I尟g",FXDLG!{}Y'=KVUjm 燷y%(PN1y*4Wcpfo2A#cXOrVA87nI @y~qΙ! 䕸*CYc&y-02Coĩ^ț9Zj3`U]S,i5$)ru2_J nQ*gKrxp~H_yp$HBϿtR-Aw#0p!*=oUx)sM7K0Prpx/vnk.+.]o>?>9x |q/].o״1/ݿ{wXe葳)GA̟42v"> zJGSh}fb2U* Ú^TabCKfiqy_m5D_͡>JF>lhyICMr3 9"6+ l~~mSO7.9~ױ?-mWjיG~oØ?t:u]7PJWT[jϓb5&Lu0PHrdQ q=Yt4N49Raä1J {!tIpY2z X1>*\D@bzD;1)hMDXawëo ƴA1gV{S?]g=wѝg~'?/ obK|E2vm_prl`Sa1.1iP)-+zU2P$ ^\ ޱ‹n(Râ.!ĥ 13ճiLR/^1Pc."y\NmH@Ok,,:T1ў ;pg6^kf7I7a.(W7XK|}Wuk'gg.z3 6Iv=CD$ȵȐ%*'P]-f'@L }ƚh-T*efu_XH)us$y,ՋC{ }ʩ8QӪܛ07>9jKL-|]|GswWm 50A`\%g'iv'^_joͣOt-; fYiBJJ`a1b$lh"Ps]Kbfx9.mRtO}h:ήP7w*`);2f0%ۗvR36g&xI_܅ $,JR6Pg|HLnhX¨\2IY3;Uv챏-: ;Sяa2x&]'QG+. g;4'Ek8Ւ ɲ؉dR{^-DZ܋`o3F;C1bwڽSM*wnd.֕he4#8mҏ 0q|G46X:%r;s7~k-WslNZ 0% 8[HaHjvA_:v͆e1 bXXJs:`]NI?JDgKW0JJ !?4l=D"RLP7 RH6Z+%8{n|{ ScO[;&27ղbb@H\,`YB+lCH8p[)1-eP=zsAڌTTn|k“Aڮ?ز#2V `z+}/- bk:ȉ?|pr]UmE$E!*;`%/wJՠycYbn@(FMEh@gQK"UYm*fxK/V(Ɔ"K699y(%yj|d{ 0L/hTZʇ<[>z켳:bN-bO-Lja{~ a %FvJUN掞0_V foژ6@'<&-z$ւkLC}U:B{bhTDZtqeF-(Pԭɫ%"Cb.8e42;@ȗG6:G Fm6Y{p̰u7;=^eErf%s^w^HwIPҤ0% ҬBy{z9}^]b8 1^.s]l|NRfrlR>GY*+6(,Fzhҽ^s^kjie ijiJ{be ,B 3!9p"PNgu*zc +Nb*ƤDՀ5h0BӔ+KYQZ?K#|x%/Guo:ϡɱo)TBo[5ŕPjM}+8 $m\Hzږ>PDg Bf v濇B fZhJF(r US꾑W.ݍ! `9;4zJ Y=I[dL'菌5w(t"<esmhYw_i2;#B N S)V|~M<d-!b9۷rJ_r^ m0qK,n'a1EkSYJ @+ž&BF7^}O%oS#А9.~㻼Rɀo.XbpӘqv !wa ٖiPK4taP|u_dk]ȋ!2u%|܆n[H8 jcVr[tSm9R]21,h5V:o40s:L2}3Χ UX3ꊟ8qA^q87ĺGNu:5̭iޒdz9AC,hn9Pޔzcu+tᇐ$m -yR(ڶrNU$y&s`Ҋ~r3s^q'@-=ul"O|]!+(m 6 t|>c^^!6 &qvLHPL㭅VovOe75ңۣ)b az)_t$?^P_4:/`'5ݽgNd12KBL:rZ%Q 岉SgH/R.a|A2LqRGpԎ"/KF&T[vE.#CL@Ro;x1[ yJ&&`%HY$ ]] lݥ60: e3O+X5F: ft"5r=sjJSP(V*.?>q"[h^GWA( Ny^jZm)&L::qn֤^MGjkm/X6M4)0!H\0#tcP(ᵃ{" L!,t~54 =WB4t7鍌~t4|f_ܣt(EJ>Lti3gwM;{{q7=M1J˕?~WMG Ɂ-D6rxhDn1Qpn|n8i'3vȆzR8^[#>θ* }qvz$DTWR fӃ>jG%lQ(Ptt.cG5cY|$1$8^n[#}%s$\x{rIImqZz]tK eŝHvd邟r/W˫(r!7˟Y KyiFpT_LY9?yO'7PeEfQlXɫ$KZƹj*:=~ԡО~S? Kz$f;gfb"e(EnQrdSI\yܝmZ?"VfןLE'}>uJnI&߁B:}[A3C\>&D65lQvsQ =$y d ,xd"ɴiLhXz#u@ h{=Bs'SgdApԐ=F NKc~_T=YByQya`NSWhC*/uhHAmJ&!㖟UF:enߒipcmO􃻦W ?_ľ)u: 2:bӉ=:X!b\.U\)J-`YBĔ1y(l;J{Qp"#CM 䕈cu ]5b U$ɋ e=RHibn]U,Rz+{!>U05chSrWOߴg'FlfQ!]H 9q NпŷQϫZ^;[fVoNȌazr`QM82:XELʙ[S·CWs[S-M$M;4YSz5qTb/njmg|T^6!Xv˗Waix*u(u`Ya"]DJ1`XMc ҡ춧$UG9i\jGD7oS̻(I˖}^j_N'Sٰ4kd0)w}+9C~c!= q) UMEX}C''yj!ra2 g(e_9[YB{= o(3OTԘ   H>~_O}WIIa)F!k|-j:]xnxÎ-}EptU4jGyLވ`)DI O Em;.<ء3nҠϸ"2Ѽ0=>NñLR5tHimY&H ^%!bmQ$_S$zϼj@30yI[{ %$|m}5ۀ3Ak'6gOan@V6 M7cPuHN mK'ڥd'I3E-Bkjv"}aJ YL"zZ[DIɇ~Eи]ut ^O蘛.B RaH-ͤf}4XS*]WzRms^C#BYډhCTg>i+I(xqY5͢5L¸ 7iq $:r\&JVu9d{Cl8)tʖ%D1KlRt2;@J2MFgx %AĔrgnԻP+qk W{9{HtX4WZ=jљ4ڔ벦Mcd#E$[:[ ؅yP|xSk&[FǙNV^*KY^sOUӭ?膸440rڿg" saO)>vFBABi@|-z% :ClQKq9/]JaLۖA@8غ ]Sүq߮Q ="GHQ G6R bHKmxE?}GNwڙ@Wr2=߲h%Vge16vo؉QTKp0H*E7sUjDp1Ǡ-XK#d@r4 TF$Ä́Cm ʙ(EvﰨuCӚ_|yN$+3ii(0a7Ap150 -X0סDg*@je 8Fs 7ZȔ4OGYy>˓nI=3 Zβtg.ė" ˆTW8%s%%c3ΦnD(3R7[1 KGM &>, +yxIn4<1* ܽ Ez|'"]r㲓Ǚdg,O88$N CXrdlVMrk;z@kcK2&Rɥ5 ޙgVZ A҆\ψ 1%DFAEBG¯ ƻt:4KuP3"E;) $g1Rh2+E!6m+"/:pN_  P0l*cN|oAv,6RK$*s+VYj[M [lqcVeZc'#'hPŚ]k.<%}+4=ԩl4 %(bz`#%D (1N#c(dT]ǭ]S:N B'Ӯ=1!C>gWsU o' } 7PڲWi4jdh~V;.fFs_?r,nZ{)R[Ng)4\ߠʎrB(:ǃ_lؐDNi\VO3k5Zqvx?,afXZl1dl\tyt}O]+D/]3=D-m.64 v]M`*ٺdd܁gk$G@S {"ےKS2ۭMxWR7h;--* 2"CR8vB $iF+)f#tC ,8 e4q&utόܯgc1}{>rM3Lڀ`_y[{}4S?J;,pPKM#?~EcWID3J50_})PM* wS;tχ ߞ 1䬀LonI= bXt#CH?LObb3|$I wx;OѢx:H cpj$N0x]ykv 1y 8 "eh98@ Cўh suˇz&E'a.GrX-@ !@8,(-ԗl841Ӈw`~yĝm9@#W 2N0Ҷi$3c@aX:a",?{Jr!Ȣ{<.Zu G{(҄[QRt gN_wu׈05HQvVamb)c FJO/ BAx&[_ Xv d?ۖme!i)4pN*D`ywL=^}fd!lRH` oL؏@k۲n1&idF}IP457vt%$=MN]K=#.Fu@m!( #287@' zi<V[(: dl^SToa#l3Q (ÀX.p_~DBĀ3ֿUD'eL}Ɵř\ێ߻93xvϸgoTczbN_K.2g=6Yd,eS8Ф\XTvΤPP[f/H^Eeؗ\/CTH ˏI1$T!Ȯk@Xl<,4 Ȟf5z=`hC\!FI8魜y!,me{-jQ']0/M~#?.⣵.y8]u)!`X}r8}&\}utٸ7B2qIc"oJ) y{ew;l#!>XVFHK[x^ou)r"<0AA(<Qrqx8wC%U!mqؘ[/-~a|0T*V)v"-N&N)mv.ݚux%?о5.aDIūD5d 7vἵc{>~k.Q1GC"asi-*sOod@}8˴6 XKqvxe[2hu yI$Qu+þUŇ }X*(=K~^ c Po|4 ֶ1Әwqh|}=V*e19yTvz͠f,}PUQ1-c{>؞8vpNH'ױ԰F.P#::;D?}O}8MtM^(HdՑSQJ4EpF#  d#>^X\⩼d |۔ @} Ӊ]VNۉTw e JRZAzB`*/J`rs{eJ=p"cOS{㽠A˅]!BUN P\}8˚EC7ϰ3hzŶid{V*bjAX l9Cf3fVS:I]\= T#9HCP)~c,ț6&?k4,U\b9R L"gf -~͉ሠXnA}PRd7?cOǏ4v#HE 0!O]+Y~2V/k>~:Nt~ dBOiz Bm)O'BܖFKIP˿\|SƭIPfKHRf*smM+ U *KF!i8@) iRdO+c췃p9;3Cg9mLw jO+ rsªeQOOc˓W7Sq2y5HgAs)nc7S^X<?L]iFJE0.>iǕ8g8'}ҩmv*UVdiٺM'=F8JPv%hâu ";1 $q8"^P^ugF 跄S4f[n7}t4-th6yִ%L 1=?:yqSdvmeEKŸ'gn f~VE2FK:-GuCc5AW_+xXƲ TĦMT'ZW3RLׯ>CJ?L)'Hh.~RT/4c*%1Lx0Ⱦ8+-FtoU/qXNV3," rhv?~2(v,iEFVUr䁋p~ӱI/~jPFB&o15Ք=J fGk9_B^M4D~h—da/kRX>5wa+f9ɘITfS<56J9-+Ov]Dט]"aaߋAp yQfR/T@R% 6ډ5Nls'UНnpD&wǟ9o/t"cY#Hp^6Iݟ}bw=y.a'ۭf1d:{Jl -JˤvZ{Do jɓͬyB=^ pk2c4/(MQ<~Z1 " ζEċx[G?)psD &MFm/ީ/uz> K) %,>*} o\%^t o`ͩr_hW'UQ1LASa􄤷x9Thd QR5Dd]%&c:4GkM6MR,>T=QMqVC$>[2kH+L6' \acWo%F7-,Z-~BpZ?8u=x \34q+&tk^\׽CxyJmr@Gf+hlY>y|!eAR4} 4[;f1:YWD$mw%;׈GVr'#rsPry>L2*?+8O3ueO95I4LEsj;Qe^:?}/:pk2 }Љ\h](Qm8;+F9;ξq:ͧgGM lr ;%`("*Ň2 #X 举ztMLAH/˞U =<eDci%IF[h &RTՁgR.Z.DZVrar鮢{o闞mOlfPwӋ=Z<{'SNMGM/>xǕsbT7Q1"[z}E~qvQRCBAܗ2|G*1 Wq`+TEsQEH,GW"A@h(&n'* H*MTfAaLp uڄ׍P@ף|a aRBBU螲K@Nv0HN~s+WcUKx6 dB5)u۟= GW\r Z%á@h U;ΎJ[JOc9x~`L[ťZ㹑^+)m*oabyBbh'wdq'K22ӯSJVՏzl8ϰQM+13.Q) [$Qΐ%BQ,!~8Lc,(gNBcT0#>C9uc+< zk=I&B)uyvd^O}Ozőn³91HQ( H)0<@?XӃ, tjcj;y,cs@ZRgHeY|e5>fU?r[|-_C݄0^^B *W*U b…+\;- h,؇VV}DyTDRX:MR<5 @3(?8i4/?SJ[>dl_1vyUH#wa5PBR&K Pig̟Y$;w"E >g= 4҈%:;'l;- sJd>P9бy ;ҙK|-#wm:\`7gjvFf!<-xΰΊT֊fPI@V(`KHS1 b7.Rn@[r&넆YJ;}"k#,ߴd6TVfp ٓڬ́2.C8 S0e6GMῌa~cG>v)qeB{尙uDiA (H{6N_c#;o~Obny|+WR@E;?Q(a :U䖯!PYY РfZ~QdF8`4]kLūK y7J R GW^yVX Aid'hՕQm9ЀxYړXMCG3elOy =ݼS>`ݤ:{;`ҕW׹=] _,w9F>:'+Mz?y[Oxӿ9qw>y=mߟ80ϟ?L_y#S3\p.>ez-"\# aUpD]afjA455eR(~"$tHHdWPM|zѽ@D=*OseV 8Sݩ-̩S)'1 !S E4Hb#$;BNV2Xca@ "fŽw[>6A/zMs_1LJЧ#!3.%-"_&L7R۹7a\j|`^~s]ӿǦQ˿-;twz@GttY iއQ`,O|?[IEJpRA)֧[+5* +{(X&N OTt5 Ґ*J)5|/|AjL^|<'h Y])ٛX"M }k6Kv?;~szH:vƐx { z1r֒6LG3 B`zY ߧH@?m"Ҵi΁a3 T5INuDQSrhQH7ć ]+j.hF69!%V‚)+%Pɝu$L96 FE12lq!W&.ےw윒- jRRAϢ2-$!M8L& lpY ӓ0tT]|t~;Zmm~Ҿjxz\f*a77]jh cн.{md~(a6Ƙ`oA 0% ،јC`.EOgTWh,eZnR t(zQQ̔₾c3cHߕ:fN0yt^<1lgɇ87$:|#֩[A{ٱ`Q΄gjawO.x~(ucZkOjz΁e # Yj_Bri&^m* ;g Q$8OȧňV1ߚhٹ:5ƟȝMSP1E!% \,U}KքC0fQ! W>Sxd"ԛP;QB 5MӚK֗NHZLʈ1fgаX8M1 yH;_X$aYb{Ics~_J-1~%d~iB:lw<>Y-Z2+zL/htZX_B pC#%S7\"Ĩh#Y#1)Ȝ^T8Yf@RP)PBi@雑¤r޵եF n DMn9\|t"@,ˤɑoW6\_߇jK]"/uXeuSfa!e[|EHB5iOk/R2pqDQu&i O2BV43;ҲCZ =`$(\P:ϧ1Yg,( +6ͮakD*5~"fsQ xj p BA v<$U³m;NJ1%^Pq8:r6<Ri@EzpX@a#G)YlEBK[5'/9@vU:6%3Z8ۛ@ wxjF.}[1C5tԁ.<5 %Z bTBMw/{r4Hh2*ɌGY%^0qwwJ1P=?D2_=| 'BM R ?$z^/0TX"fwaprX !)/"bg:bm:P+vȌ9;}')zԅ̴EQEM9 xmt| S@7JVF ͘p [ҷIFvLreBaw@3eϓ,WhWzTfLS 9^tA+ 'SwK8HφxK+[G/Riz+ބSMF:Q "" fFrER_I䪧.2sqHFV;^#rfYI<2᱁(.9RIBQiCWW4lϙ(9ن 21>W%h9 yrP=cJًctt |,#OD0g?>Ͻgk+6`o:_~ͺ <5BPbJM8h~E<AYW^pO3f)Ƿ^*gc-{Wa2y`l!ik`O%x@x=x<]8iLD,z1uǣ~1HZ<2*SI \#}`:u$8?W(ՖSb8)rpЬ(X O'Ke "k/ԄoFwO'YKo?>tD&FrAB}$1@-Gu3DTsrIX+7 F,ޭO<5̙JNIPu@Xbj f8B=E B:vY> %pl 4UG%4y=cTf E6*M@ϛ "+Q[hドKL.KE=Z'aQYc /d?\~髞w;=o摝snx+H TJF l&[W;)CFR@B/t2Yo!046Y>똘#x|*m~醱YK9dF>p^QVB`E i.H`@%q1+y=YŁrg/JNS\OEӋ3~w>q'/<<,$DBc }6T`/TB<+3 SCy`e  vTbym`g &qgԖ2]PIy`'~AX NG @,t>x&Ԇ}#߯#qE4꺋5A,O*X6 7mDhg沅D񳈶[B@f?qct k&HG?utϧ􉽟7akoN9jVF=35:ّtm{ (?}|'OSWwу_J6ex7ߵkZJ,p!DjA.Ir ]m~'uh.P) *{~Fg̦Tgqꆰ09`&퀠:²Dy?\ k40\ni֊H22B07LiW`h Z֜â&CV`c/; Nۧ}r >qbNډ}o7߂Ùc{cӷ+L>yb'~9rgN''}#x9ɂ28rKXTن TW=l$x=|Б=z=?}߿z򂏞<?N0wN__W+cPuz͓?mɅoTUR4 CH>f?2͑]=: ]3JlJ_3Ž+4AZS2`Ӧt{>|`S~gQʋ 1;1(_(si ԝMv8m^iҗEUP}&]l @6)IVGVҴ'Ra.h$KiAʚph[~m %4oZ % Οǧs4]Yx֬@ǧ֢'$ϯe+0):Z+dU 'ܕ>Ĉk|le$@ .6}6cbR@|VްG^O{H@%ؽ+эB Zp9(\OzF"YO ZG.LfCo,wg\ iZ {7F%Mcb* (15;}a c!rA  A!Ő}SYJX.s}`u` X1+Qsi>@3NJS$'䳆 ,)uf="{1& qh s.<>73hFq z@+ɞ$0`>AWaTmYG<SGԤ*llQ(UX,#bs7c*uMZ)M8+AL凒/#t"j\@(܏]W"5#Q 8>f4ܴ+dcF@M(M2X>ash(kemEȐ.|m VJQ(D>]EL-J6 E)6g (B 1Cw?Ǫ>]|xR% Te 鋵l%#)K1qaGַ{'3A|6Bf*ߠaTJ}FcŨCB}<CaYxGJ+CKHcMـe#:!W+2p'kqna6Reœ *"paI:1>Vc*ZE;fS2y.i5NG)}eƄ]qM}lig?E(Y<]TO i :z$"lmCj1C_TRB2Xa8LzVF?F&jҏ&v$4]lU 5z~VD6D n9~*"m)ͭؿFV$TsY(ّ$N "z&٫pdl' v{)="XִBi(Z(-04Ɔ+t:9 ZK" (Q$ ]7T~<vI͏1:՝ad3eZ;HQTSMahu sv*µ`BOQ[I(vU6REdtc qf038 .̲iWޝBwr8`Z ?zbRiʁѐ:f~yV-?jA g rprUg翮& x",_Թ-Ehh=٦Tr,S1oWhyV앉\={7({P)$4m b$өZBz{8VsDEg|!xo=yeyrwtsbdq NȷQ .sdJ0,UB5[^@{'܄z7}mp9u(')jX$]Dj șis/LFj@ #{ݱ-8Kx}l:ϕqȁf#gS"6Bezr3Ԣh6& 5񎣤ïpu+EVߋ'qLI7 [ˬIT:Z%ljPNA+, lM徲zI(Yau.hO1D!Ti*kP @*u+uwi!ވu& f-+GdB$f3l c 3SV4 jpV-Bk,sbQ ƘAwm m4ZwWiB7pέ\_!73Fq+t}T +[`$ q.Ϻx$ {&7 kHUdLn(!i{' 8eM[U%"q฀@7$ la-S2A C}CYPIlx p~?Fe"ϱl|@q\h/36k7uN> N)LKmՃ1ye5]U3bZ~Kڏah ?U[OQֳgIqxQ"#BlƔk<&!bNG QiKh-Ozĝ<|}KwOSo1c[=l5c`74AF%bLsjzP_]qgLeOfdaES.Ri#˓gaV+VfFi9%pZSG'ÌE C/`N&Uu}^6Kb_+P7wRրVKEhӫsiZ->E*TX'ff[48ʇ΁n)*ܬB }ıBNcբ :j4vwϏӋrf[ypr0pZ"v2 2ȥ"=z1v2 d.|a ֫҂sOc婴&],$%JQá)X]p@??  pKpz T_Pr NoWuw{-DL8 C+8\CbXxvT+/loF m%cFԃZD˽LuQ6qqY “<4TF]ql8eǾfVP%hUz&|G &CLA{cXrMt(Givռe6fci)~lֵEC.=~@ [Q(T":$DBpd8==f3[i9B).Y-qgE*h wq)1Ce05_4$]҃c`Hj4Mʐ1"gҼ6v҉ i~TK-<8q2pbHMBrp#׺_c<%u_•ejO:MR <Ö 44aĸ9!38; )B2?Y#;4bs3ێzЗ+h_ ifs)ys8_tSC#Ň voe%%X *~O“܁p>hxM`~wkp1.jgӘ'! ,ƒ4o\@K6]~|"*Q[[x©gi4K!ceS0 ;t-7X8>a~WbxG_DZW3h Q5$!З^J4MRs!|ɜ$yۉMENv*LKh̔DW6˦XT nB7)[^& jWX HٵB _B+#Z`lHբҌmȏyCIE*_+ssOW G #7|$"/EH\KeZAP"JJQf18?e*p@LBdWw*tîS|E7.ۘЀtPӾ CDJKX'y|&za,H Z0Pd 3dfcӎ۬Ѥ񭴸nC{,<`Bk(xr $I1`OTfҨyTNQ-H% .PWHd TMhVyץ:}xY(gv6h0PqA݁ Iw0 #4rҪ!;E'rlȸdpchjߧ"Pm1[a=DKͅ Cth65>_YImma #"݄S.^J U)WQQ("+Tf`4?څ2崩P~ŚlH1V*` _\)AX LX4A+p@̿_e$fAS]hJi WiAKI!PoW4K+˨`W8rF`jჀ'D9|~H49F urhdQII$"yo>3$̗F 6? wWX2MK$wL֛kT#$jS]V2 *5i+';M , Ld @CJygVVy.~lIDAT勔r5{mڑ% ~79U>H3 D !3l }j (XgOXef.LY ɺ jOTWE--Z1 $95Y F ,DgO4g qXG@5+[ UU0(Jz=Y5Ōpe b%DBO 4">#kf4#i@-bY_Ĭ!: rW\ֱtn*%WuxKL(jy6*Ǥy<aUϺDJcjtp5hg\h)~Ek Av`Ql8A[zXբ/<*P̤Mȵj³/ `."=hOdm!VbBSWȜOmU~kE tqv%k4kO牲HP)X,5 ԓQ`.xEe7\npU9w_@gRrPQ|`H(R(_xݯ:Xv]R2p& #tVLB١?Y K!!$ @dX`S++ TU\aqX!Ջua^%^(` %0f$Jh+ gSh@L$'oN\;Ͽ}~: R )qf/݈3O1!O;-*qy*Wr ɝC-|4ҼrH!~`+8ÖF_hj!jkg[?t' gXD' =TJ\0^#=oHpZyJjh# *:Pf*a,!7gOaS\6%fqƘћzPhgTw"`â'Gl01_ԏu+ SR聫\YvE*}<:j$ɣR&Vqіbm/ o^_ݫrBlב5QX]rՀ{@V]y6<&Һ$URgadN$/k>f?vn%UB&.dbw -&9dM PT=u{NBVdǩLСv5u@pW<]. LWYULڤmfCjhSV;#קJOq&}Qs[ߢmJ6"#f#R⼸J-VZsPm Q$X,H<. -]Ŷ;IePbf#vVT F} fm(˔ڷTܑ!5" *oS0‡q{9 (ܢ49@mȞ= M„b2mhu2ҳApU倩?o UӜAcSp.cͪQiۃ yoQ]{)c2`uHx}S:.Tg ,Ƀ|F"˲ \;#yz4i1Š"dVCnkZQϨf|T&sڅ15,דN.iL h j&DU Yl`4cJ9=jDzi"i$ eg@ ^CX[K|`f9H`eh4L%!uNk5nIZN }]}VghP:Cxo;d?_M$r5";ciKשۘמ ȭy19x]CMM2d:bQ5NLcJ'cq65r6bi(FZyTL*0aД.o.ߕS }^&lF' 5 eO8ĸ= `˿&-cH%sjb5Jٛ##}E_.ׄ$&[p^#59nulh|nJǩXȥCN")weHT7]s;8tAƌD<ϴIGyZ.#ef H{@"j@;ÖkԛgCXCFgp"c9o%=P.&'/jw";?x9AXxŇC0{2 @D|}TQ6JH`%ޫLp`WY.`3CYW(]\Kl9ir \p$3 Ȯ U@p\@Nll2F„%f=pք9DَV!d8bvǖb~I i[dے'kZ\B~6bҡ68cr M9IS| d)IArU,[1^&ʉS%Z11 դÈXqCP@0d8l,@٥/|,Hщ-3@7'}s{4429 a* ++ @JJ)bIᵇf]un'ŕ_> &Egc%k%Kj a[q`~Y|6ԶpBufIJāawKi@G$83l3;R IѴ~G> W Bat)7i bA!g!8"Za$g2  \Har:03HDžYP4:O^#:+>l$Vgg4ǜl(9 ٔ*3w<.fVlfJlnWTV3>uVā|xts%hɨ'!](Ho~Y,bTJKU,*[Myt㬓DW} I%Y >"@3%Q&UH5aaX> H8`41^g)%DdJ$_/J _<1U1&`>3y|RY~e`SdjEmLVe7. 8%%JZ2+Xar&8̢|e/V^[ ZԬnr꒏+I7X2t\yK&x;pİ  ='\6[@z.*k*RJQiԭ07ds(oow%@ڟqU, | ;LA=&{y]RKcʊ9 vZ/:dèf¼Ķ uqYNݖ [+C"NaNjvi5D;P&'F =\S.yKiF< 8tc&f ًJ|++`;*n"TzGNY[(x`eEN^ Z9XuV6EWךd>T?e p>fJ7t?:(=f_xOO@iȧ:9oުRAG&<񂫵)) /d4 cpBL|B¨dC5DPH$ACiYUl n$1_pIp黔кjV0Le6`9,1cxDY2JרK9',6G5J(\=n^\^j.E469aG|t*:fϞr`+ W^i9E ylb-o1lGrL@HJ1~)[V=DIe4xWa 'AXmӵq;6drXע/ 5zYV_t%h5G#nrP򎜵}/}$Xea5:JO*Kgf #|ϋKXrQ7C;ITu _. WuA<`;OٸgV w]q*(\]C45up}(4)"JoW4Aw\tBp 6\x"0XDSr[mlH@[Qka]nu|ARh3L(* 'I.=c CPyb?939:B&+[%ev SFWKhYrŦUym2:ϵ\?Y$AIzZ1JW<m>[ѓaJbGSF p_ϒ!=VvQ/F"f/ZTYF_U1d`٣H,#PY=bWqvž`\HE-k\0jS)]Su 5O-BŹaYlPr 1p$IA]^@^״:ᷰ6 JӤ5(]z^(Z1UWfJŊjWpkaz!vo(;ZfUEX!U@V CCbr9\1 +ّ9wfI0<. hH0tK 4a#*xJ8-$`FM%5+t^kdsT@{e]J~9*e'uD2 7B~ )ܿ)bhIRc!aD9B^eQ:'p?.5?nٔH̍kp}Nvg Bט=l Gʦ8Զgؑq}T/j]Dm~̜@~JﯲCa0N)P[?dv0eh wTK_Ǜ[&]>Tؙks'Q#kD b8&MDԆ`~:doQ!EPB.FV˜q Clfzqԅy(˽EZY41|$yΚj?J%:QZWYKqS-Q`L?l !ky nyOD˱֚SM$6DRICYkzqT{:}B3^9kUp L[>XQMĘ#Pb᯹*dMb1rS/&+f_`jصX{H#ANqh`  9AUBjؤ XO9,ķw!*sݖtm6ĄH &Zh&eY>Xb(K_jѬ:T|,3x5+ɯ1]+YG6vȫ#yeK]XgeD3:2^lxQ gL@+KϞZȭ NRI!E?I+ Bj s17,S`غZErcv}(Hln2kkLZ͐"hcP Y㲹HhiOŪ18E3R!XV{J܄i>,ȏ0Lgo¦rXͺVi`="bތ7sVlpGWIb."W(.ŹKDgQmƀM 4.`^D~X .<[HSUT2^!_eϝ :ɾYh9+8:H[MUgaR{pHjB  xVM"|Zq+=)<(;Fc,nU3L' cƛ톆I uG/P+̸>к\K-dpc<=$HoY t!zA z1@#HGV7LYԖeOJnzK5̭ԭ8cs:q]|Q$* NM1Żs50lr"hx;}"cTnؠP[Azf;u0ԳbҋiDol-M+l0xN"AU9"AJ&4lX|֠!n]79:AbS00Vy; r]/lȮŴCBt6 ݘ;yhL;X&KRFUTfA=eJ7N&%?*9 p>}Y3r-F#9ą`yo2'Mő9]yfznI-0|zBJi0'\&RN{^ NݜA(ר)=~dc7ϠMPe}b+J5$nbxÜDJ ]J2o"{ଛQ{G&-ۻ.AU6 R9.WV >=42P1B9i uIP͇Z#Yf Vh`rYw9qe6A0 H~nIKU 2| 'q/{.(tsAINw-CXH.faS"&[M7Y=w T_I*I łŸ'D=+FxI7蚌:pqVa'u[̧"qۗ"\B AT$K FLh6Y#V<|.?QN㶅WoȮBNkq&2C8d{1_=x4-5S?R;XC[ڂv[ )MXO]^5$X?nkՈI)<m.gH:lUn! oEyBp4Ks~Kj 9BŅ]Gר#|V JE.˜`6*^ H#sһ*IpMN+/^*2Ix8d+bCItMCB3!O-cDk RI4 ?E=؈Cj+ &1aD,*k۴ @Xkа2Sy#j5nlJ3Og7s56ʙ; ԈEu7D^b"+* Fq΄:y[μM-&&LU[ 1Dk $-W>GX_w%BܱfQ,{^#&Z~2ā*>`ZY"5;9'f>)\ºZ!rF#'׉bؔɕVR* )*1rpLٛ+8y͟jFCd7ʪKCOOZ,BiNjwv\Ịg31k:;eMZٵhρ/+pftg&S4jixR /6ZH9~=[Aza y9`.?dj }cE8{\ +ivؙ#Q@~qW1r/ U􁮟1ǹZ XYpV _t[ILՙT#wbH8+!-O"١(CE2*3pMѓ#@' (ji;v#tD!t%d*ai qӯW$c3o08r*C;!+\s*0JN,4!!R,U2̶4 2E,-=C,q: {dp*zb](}16Ҕ:$wm.A<gy)oFwH aMzk:nso~P:ko01y@N!t^ .@Jr$K B ~L:#@/= RXB]Lax0u*#W3@e1.@{\YY`9B۵f`3'n"VwOVRz/<ddN8806RbtB<2}LSs&Mڌˉrq℉pugdxO2C}!ztTxTlą gqSxK\}"(ch 20>MEWgP"+T`u&1T0K}0z岈:x >E =h7*:ԤO<|B +7#^y W6#b 黯 ScuKSc3N@cOL;w i@6> W @Di\>]rqO%c( MB;`t4Z%Ei,aEM"i~}qa> nَ-0w8 JnT(D{ztz[ޙ!L;: #eUQX :_ތ"AIA:Hl$q 34oea\tRͷĪt6DأK]q񘠦l_.CHB[gj#(_S}>5lg@jFɥT' RIfZTIuE9kݕ͌r4!(zFQ Cm~Z!Ƴ MAyA)YjXLlBB*,h'# hAzUv,ry7xg@tlkx1Mځ*ydgIk@+UNU!xAGK)ow8(jT֓l^L 5iؘ+xG>6 ?Й*D wP"`[Q ;D8Fh+ KL}7-&IEwch,-&yshY`Xڈ4'J2\q|_nkgp W ӖcZB+5.I2!K'#k!GiyNCjx L"$gϻiL cMҰ2n3uzBg`6D]P4);̳+K4MmbJjޔ)+ߩNT PF T{2#r0t\94+يGÛ&KAx<.73mѻy}(w\*/,^^&Tcw%bek-,uDt#ۡi?MAp:JubξJ$Su6Sv8=f|OW+K娆c}\]y4Xև <5%2 rMUtEL9ݎ+.=g:dPy#6YJx,EI֟򲇽L |5PXȷٷ,؉jd5+.ʭ.Z?{6ZWD^@نi40&wƒ<)hkj~:(,_2KQxya\lUsN쑇GQTî{W=KA4jէN]jpDlJ8I6~>²CΐlG]S@֗捨GL+{.5[qeuz,?W|;q?nw81-aβ*[TˁpDJK{d&'M6V#17WǶ|dAQQ5k҃_ιu 95d2^[, 8yǼ1\L+g%Jq>\tS{bWu׭LuPy;9 fIREÂ}Y-].AY&&˜H*@:Wk;ZWqFu!IhKqrťr:b},CtRXyD9ah`TvպQlJj" a fUKZ 'Fuu"+8iз߬N|ABmdJۏr;Bo`~f׋Gv]y蘢ʊ%P8X͞ %P^VC]k+z)+|B|dKn] ;s2Y {Ye&8+bHZ$DsſE b9Mq: rgUs ,Vq˧u/RxJ1zX$REUGJ)F rITbá7Xf촙z3v.s#'hȦͅ|x:x< &-ЊTsLX2dYB jcDmCL"cb"{8(GDKLH;0VjC|-^NO9Ć8jx[RGJM*#U%֐^DJ KmW< 1X?Ӌf8PG W!ϥyi$ǢҬMXZy30$;_ȫy E6K0-2Es&`cVipDk]!-TB =c'&#8ˋ ͓6.؃jͱعa hndl}F2NkI3TP`I E>a~¹V%#}yS ވ\> RlTfM, 䡉5>کyAUcベa!m-Re%21HDC MX!- bfe-Ւ#'s4*GpMc[;EF޲DU%>n2⊵L҄YY׬l[W9YRtu>/b+a&j $@[e9p؁nz 1sȍG&(C OJ+; ofd`ijm"y]Re-Jo^dyC<&1`@oami._ێ]xM2)?K 9%Fr™>˓PyZ0B{~Mҙg $ H*['GNYv^C* W:`GZ;G6Wɢu[Je߈ qH|=ӆڕ'Y:)1hGELD&HF.xu(D͐2 c(F:>b&Ich*_,1D`;z6n7bO siƈIKj'%^')E\ mZCz0wTWZD69|]{ư&|Y;X:bHWz3 SjSHLU dJw)P1Ȝ\lΣꀘ^R)=18HFOo"թE##LofuWR neIY2B9 6,RS&>|NPPgLxSL41fWA_e굠^,+Z95,Z\)>&UP! Du L|LT1>b!&;=C"6eNv֧ ^&ЗtU@} +,*īOEbnHFHXtDaQhV5 0Hm,ཁuiؘEpź^o+`)2S4A\ ܰq=k\T*lKR% W[KeY30Xø5EK#a7OɛA'nw@*ؼ|AY):L"V6zeIVzĩ4 & 璞&UgpsKRr>CK"ŸV:&I=lm`uPD|^+Ez҄9SGi Z؅_zLk@[Ȥi84QFΫ+6|@k4m;XiZ\ J(/o ~MLOtBMta^Q^x0f#ZBW|\41$5er>5SvgygZVZg2wR]6^qB$ g'Y SD%uSo ;JkÕVTBQ*j3D.EH"LKƕVelAWJSj*)?lTɇNg/wokPjاeɦBخ`{OQذ!)@\ftU ؽ+q\otńA p5;(Tsٯ6 |C9">g&F6*kXXN]Q6=fi+h]b3fqNc \PK28O>?IHNsz/tɀm"A^AtJKyMS< ?2aGv ݃ԋɚ<#+suQR*m2[qrU&0U*~ƛs{[ߺh,"\o DmL)"&?'P|V`aFC#7K(T #s"꿘P_>JNNL|SO)*+*y^'s 8B;خڄPQ/g4&[k4r[R?ݎ. G㛩[UȎ-!pQG|TR{]aO{>NX$oBҀ١cʥ*$$qg\Xb-Q4b+"e@Ajwx :$zAk*v*!5`667dZp:ћb!p!,#gi2Yo ХnO߱ɱ\Э I>#?jcAo{>)rP)`"`RM΁P¤=@B!rshb@X ff.wp _ad+?T873 fN=C RB=@ Φ$Q$:K❭ÕغU$!D.nQW0ϒU4}kn=1 } i]a/6sCsFWF'}Q!;``RKNOHCm[Y[Jʓpj2\(~5MzȧJb{ͼJ0+fw`f7`EB'/$Ř8:( J S5OM,t ͋ (`5x+V520W= ;7" Ա~%XH]ü>#?@ʯ q,Jۈ$&֏Gomb')i^Y)S4/}%CcEv؍i$T~'5! E_mV_ZV202%䟃\+QLҕ4ãVRYGB$ #IU?t@~DC F~DE ˇXI&[CdL(s3k^&@v jgG &jyZ%?_ST-#7WCHown8R? ɴ'd b.`1IIXִŀ(iD"47㕃ZW`t'tS*9X5Yg`ŏx<>i)}Ti<&WXLܥ-O)ДE<mHJ=}NUhEBU3tFBoe E Fwݾm^׼ՙQ bSl,Eڨh1~uYxo D,N$IiiDن YnU-_z8|;oTp3rޘcaqJ(tTk}l)CcXy"ITmE"T4j TjvSa܇&$DIE"mױ[0tr::4`;mQJ.F*H[sGDi1Xɵ69KSoeN/SAr3_}Lg?~'^%,l.Nn(#=)>GV W2ky<5 s쐤 H>)6nJ\hk.+5,vA,17;kC/ϕ,ƪy"wv.ARATUKKi/uA8raGF3JJ4^L'< ox߿{w Pq!`bYrdWΖ;:mAV`-pML72@;f x-QēXjU2Rwa]re,.g4]N>v){ohE .Α#K~a۸7 {sDߕE|fNO0{QDl.GSU.JO.dj45cYFJM䦊# M5/ }u}<~&5BB+DѶT1m%i]@Ev N.},Bg>vvɹȝKGJ$;rD~ Sa)?Qw=~~8OvHR"u*UfuC=\6yK(MG1ubD2 2`Fi9u }J}@ɨNeMDn[%qJYbϪ(SMO-s,D'@Λeu䳳2)cPY0r$930K*!ay\З芒P_Tx O[F&Jma.Vd-/~ֳ=St3?'/VY܌a -Jp9@vgjk9wz 5} QN?V8$*[u3UMͱDjWiYApC ޼̋'f'U705o+Z{%b! Ia0Q%Hr ?-K={t<1zKk%\VbT 1znG.c8QzM93ֲ)g4MTɦ  )r=TTLD4U3Z7hъ'٨bWt<47ED7WKz}N0<Ǭ*ދW96~;O: ` 6JA8[8}+OzϏxӉ=ف{}Wwm9e $sY ,?W K u^zp/ӓwһ2n슷 !}#;#W^u@o7K͓svBͧBpQFBQ'D*hiYfaSijTnV;JaW}ۿsݮx+^1 qd7gO8'%߇pm@hiU)qrZƟ.cL0K3RmMzy:w=Wy,x]Hj$iʍP?ŕeb8!@VCS`D2pdD]-gYq3x;w]a,1KD!@(&<7͗-)[3Gy_YEt1Ƨʓ@^exϊUի,F$ѸJ"5aNVL貅,6$:U~^hLɃe*jS{@ ҙQأb*Hg)=vMF4/pIQ~K,9f >=M }^_93[&9wNdUظ*j-@١y˩+1nvː,ܯ@$$F㝁} NuUy ب=1uYfBT0BBI;:krdeLC#C1Q ӦA!nY`w.ATf ֹ'9U}3q4ђ;C`8xjWa;&P29N8Vez=Q&`ӺRf,qAs ?#w۫ۏ|{8ëBsJ$|J3i֝d$ɞ]lF) &{+F^Vx+)f4^ݗ\+z :Kq5@C V-ZOr[PbRxS M02Ti!YfW@/f:eD}ϫ_*k?K=[c?cBBX-Mv(-!|T&m~P^ B_uWO'jA=pG&:r#+fX]=U^̅ ^!_-ZnD78]Y|.&,U$ՁCꃃ|sBX#'ah55#oe/{nwPr9i ymHk,GTKWi5a0 A&*e>?ف׉6r$$߳nٜf]&s9= 5ڒp]X%7yB۟@c&)p"*gDmœa79Ig%8+qn9VqP&C+\ޡ:Rұi"c.˪$jY\pܵG|.l,q0q҆\>kQ!j"1;VC!)6rB[i^Pkطf?znB{ض-ݾzS  8je&g壂use2ceWj 9VB# ix=\vJ"cte9pc) 54d^zCNg>b\OӤTZws攌 J3S%3;c,͡0G"hRݤ፠ZZzծ'/ . AV﻾;zC˒rijyHV)..w@ b 72D_T/} /@|_Uϙ  WI|BAA"м2H̊^*k蹃ꂈS.iGBr. [ 0$2h{6R0ݰjKډ#` Tȕ#ed$l)}dܙNRZU:ILgdφZrRg4';ۿ {^%7GL7@Ӥ%#J6z7'>r-vnM$\l+㓽&$A?er+"!.WR%2balR5]OifDZ](=1c]J9]^!wT%wJZd;_ӳ=iNu-B#u a!e ^pW܄hpvyyHuKfdڮ: 8>oEխ ^+LˉC>EC«S xQ;Kyϗev]wkkrëܨ([B!%؈*'jqLFCIM2\ D-Odם#Y &1B6+^ٱWU!nzUڗ6F0"5̠xR>\Z)^qو?زBM˔}"iFu4h[ t{_g;5JdQdʔk, ȤgҎrdODU#i,OekWB(ƈ)8ʻa@7Ct_N67ak8\C8i`HM{Q/٬Pkv+=o~}ofu5XLaӠw|1'TۦV*¿En Fn,pU1s؃[dzt޻eC"4k 5Es, jXːzg!OA[ԧ'YW a`<.{ŶoSh+ "fl6yM2 M E8d3Kvf4&'r1LU وa@IC70@$?3N?Yq_dJ:Rga2rZH5"Oi .;/Cajf@(toYf`튺VA&F;'cbv(}B׿ZTGAIdxjøU!9#RԉjwNCuʳHY{J_;;'~~'4#\R dN3v@ ] ZK$!X9l4j6A}UI!׽mY ,r]i| o:0|ʪd3̎>A)"5a|NL~-xVBzF"\_T`PIQH- #NiYݝ睗Ao|K"lA,5@'–e:,yM񠑖=Oz%e+Sn:C&Ju"Q[ l;$*tR>o4A}7om.*0gur3>xI+U)G(gR;C?_ݱ4eʳ@ ,ժ.[ܪBXۈ b(tab̸ $OzF]c:#n}.r:3g].AVo:B Ǥ5`l檚v$6|WYAń֢*@n#a& 1xKoG!?؋EJ}WϞn7z[rBRԛL,iOA>i>yikE8ӧ_ a:ND)59pEyΰ.OPX΍))#^!cY˵ EQIJQFUn{;DJ#dBk5~38g;-fdM{wwCž%nz޶}s e V*_A5ħJ״qζ7=Q5NW_a(S29꣊ބTٳF6g5nK-&qS3.UYUQ̧3eiٕP[X=\NjuKsaΉ֟,=Gaԗ؏|!&v!/x3[pPa-FV)餘U7,$\5_Uas 9j\+DvD|z+ 5'npg31_{*cUlhOkCJq!%=VKS&¡cӌ\56U(IiM#+㚯}kE}6I>7qb@1i0N2 ;dW3\Dyb:V-o gۂz@l@YN "Yj_ޮ<<^b%"ڗ@ ;Θxx:fipYH["ZjD˭!aR f,\!)3p#-Od^[]!mx=iPnG)\%o]'Է̿'Uy̹IBᨍc j4Ƚ$c AV i`d\ɿỹ ElL{>1O^ DW, aЈJں7mP++NBH&FtHU'~'??-^=Ey[Ͼ6X4Jp"eedRoftd3#ǂY+LC=/cHI6A6^DŽWv > dkMJC!AF\2 ֆPPc~\᳈m4lo3+ŵc0w0y-P"V.δ3{o6"N=HPO4: _RڵY.Ti j~{@+9=5](U3)^lU$j7L p{Mwv| )Q5aX.3gS[0FR+w8-W^jTĄma;6ȡwS9uEr"]/7o[2%^'Êno_\z劈O7$ rCNLNSa}R3'5:ҾFJx Avdu~Yk[Vksc!fLTMBQDztB`t;\ޒzBpeOeOcGpf~+v}kws:^DeBlT$\g|쏾%|D==mz?|M$bb^1p7@eJbvܒĸsd0"1ez.il;q&U INf )-OH*]ˑkDNBDФz3P#lZ*PY0y яx|g؈I ˿޻I36CzJ3+EQY1fK"nc >y؝HwY vNWt, ISMҚ)ab^zV%̓|޼B2~DŤi-(1BL2g"%BDa17P{+aG> O_u6.ߗzLcXy&&?ʮ >۠4.j| =l2X4 D wՓө֧`0PTqzo776S㐥ay}y138Fuիab,jo[R j:D#zE#49e~#m=!٭޾}< p ۟%^8ފI)ѐ>"eug(Xša5M7_2V>1>o,o{]}d[O[{oѼDǔl]K%a@E[3ٗ x%! 9 bKMwH^lG[eag]퍮g .YX)gBi`X#cdWd;WLX2%tvƘ=+56#O? J8׼5/~ы ??oS>>OzxO߿{W{v\pt=0:ËaĘ=Ln^#'k`#o`4\}_m0J1tC3=}ZӀDZ1v39,,b`1q֬ ~:jT< -xȏʓ_g}w}f^W_5 T}0^߶{ ?y;7^ޕk]xy GC \O#?~_$z^;~_Jپ#<x?>|G?&턴xIENDB`sortedcollections-0.5.3/docs/_templates/000077500000000000000000000000001306637307100203515ustar00rootroot00000000000000sortedcollections-0.5.3/docs/_templates/gumroad.html000066400000000000000000000003271306637307100226770ustar00rootroot00000000000000

Give Support

If you or your organization uses SortedCollections, consider financial support:

Give to Python SortedCollections

sortedcollections-0.5.3/docs/conf.py000066400000000000000000000230271306637307100175170ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # SortedCollections documentation build configuration file, created by # sphinx-quickstart on Fri Jul 31 10:18:37 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os import shlex # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) from sortedcollections import __version__ # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.todo', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Sorted Collections' copyright = u'2015, Grant Jenks' author = u'Grant Jenks' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = __version__ # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = { 'logo': 'gj-logo.png', 'logo_name': True, 'logo_text_align': 'center', 'travis_button': True, 'analytics_id': 'UA-19364636-2', 'show_powered_by': False, 'github_user': 'grantjenks', 'github_repo': 'sortedcollections', } # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { '**': [ 'about.html', 'gumroad.html', 'localtoc.html', 'relations.html', 'searchbox.html', ] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' #html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value #html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'SortedCollectionsdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Latex figure (float) alignment #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'SortedCollections.tex', u'SortedCollections Documentation', u'Grant Jenks', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'sortedcollections', u'SortedCollections Documentation', [author], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'SortedCollections', u'SortedCollections Documentation', author, 'SortedCollections', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False sortedcollections-0.5.3/docs/index.rst000066400000000000000000000040341306637307100200560ustar00rootroot00000000000000SortedCollections ================= `SortedCollections`_ is an Apache2 licensed Python sorted collections library. Features -------- - Pure-Python - Depends on the `SortedContainers `_ module. - ValueSortedDict - Dictionary with (key, value) item pairs sorted by value. - ItemSortedDict - Dictionary with key-function support for item pairs. - OrderedDict - Ordered dictionary with numeric indexing support. - OrderedSet - Ordered set with numeric indexing support. - IndexableDict - Dictionary with numeric indexing support. - IndexableSet - Set with numeric indexing support. - SegmentList - List with fast random access insertion and deletion. - 100% code coverage testing. - Tested on CPython 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, and 3.6. - Tested on PyPy and PyPy3. Quickstart ---------- Installing `SortedCollections`_ is simple with `pip `_:: $ pip install sortedcollections You can access documentation in the interpreter with Python's built-in help function: :: >>> from sortedcollections import ValueSortedDict >>> help(ValueSortedDict) Recipes ------- .. toctree:: valuesorteddict itemsorteddict ordereddict orderedset indexabledict indexableset segmentlist Reference and Indices --------------------- - `SortedCollections Documentation`_ - `SortedCollections at PyPI`_ - `SortedCollections at Github`_ - `SortedCollections Issue Tracker`_ - :ref:`SortedCollections Index ` - :ref:`Search SortedCollections Documentation ` .. _`SortedCollections Documentation`: http://www.grantjenks.com/docs/sortedcollections/ .. _`SortedCollections at PyPI`: https://pypi.python.org/pypi/sortedcollections .. _`SortedCollections at Github`: https://github.com/grantjenks/sortedcollections .. _`SortedCollections Issue Tracker`: https://github.com/grantjenks/sortedcollections/issues SortedCollections License ------------------------- .. include:: ../LICENSE .. _`SortedCollections`: http://www.grantjenks.com/docs/sortedcollections/ sortedcollections-0.5.3/docs/indexabledict.rst000066400000000000000000000002121306637307100215400ustar00rootroot00000000000000Indexable Dictionary Recipe =========================== .. autoclass:: sortedcollections.IndexableDict :special-members: :members: sortedcollections-0.5.3/docs/indexableset.rst000066400000000000000000000001731306637307100214160ustar00rootroot00000000000000Indexable Set Recipe ==================== .. autoclass:: sortedcollections.IndexableSet :special-members: :members: sortedcollections-0.5.3/docs/itemsorteddict.rst000066400000000000000000000002171306637307100217710ustar00rootroot00000000000000Item Sorted Dictionary Recipe ============================= .. autoclass:: sortedcollections.ItemSortedDict :special-members: :members: sortedcollections-0.5.3/docs/make.bat000066400000000000000000000161421306637307100176250ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 2> nul if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SortedCollections.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SortedCollections.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end sortedcollections-0.5.3/docs/ordereddict.rst000066400000000000000000000006221306637307100212360ustar00rootroot00000000000000Ordered Dictionary Recipe ========================= .. autoclass:: sortedcollections.OrderedDict :special-members: :members: .. autoclass:: sortedcollections.ordereddict.KeysView :special-members: :members: .. autoclass:: sortedcollections.ordereddict.ItemsView :special-members: :members: .. autoclass:: sortedcollections.ordereddict.ValuesView :special-members: :members: sortedcollections-0.5.3/docs/orderedset.rst000066400000000000000000000001651306637307100211100ustar00rootroot00000000000000Ordered Set Recipe ================== .. autoclass:: sortedcollections.OrderedSet :special-members: :members: sortedcollections-0.5.3/docs/segmentlist.rst000066400000000000000000000001701306637307100213020ustar00rootroot00000000000000Segment List Recipe =================== .. autoclass:: sortedcollections.SegmentList :special-members: :members: sortedcollections-0.5.3/docs/valuesorteddict.rst000066400000000000000000000002221306637307100221430ustar00rootroot00000000000000Value Sorted Dictionary Recipe ============================== .. autoclass:: sortedcollections.ValueSortedDict :special-members: :members: sortedcollections-0.5.3/requirements.txt000066400000000000000000000004271306637307100205530ustar00rootroot00000000000000Babel==2.0 Jinja2==2.8 MarkupSafe==0.23 Pygments==2.0.2 Sphinx==1.3.1 alabaster==0.7.6 docutils==0.12 nose==1.3.7 pluggy==0.3.0 py==1.4.30 pytz==2015.4 six==1.9.0 snowballstemmer==1.2.0 sortedcontainers==0.9.6 sphinx-rtd-theme==0.1.8 tox==2.1.1 virtualenv==13.1.0 wsgiref==0.1.2 sortedcollections-0.5.3/setup.py000066400000000000000000000032641306637307100170030ustar00rootroot00000000000000from setuptools import setup, find_packages from setuptools.command.test import test as TestCommand import sys class Tox(TestCommand): def finalize_options(self): TestCommand.finalize_options(self) self.test_args = [] self.test_suite = True def run_tests(self): import tox errno = tox.cmdline(self.test_args) sys.exit(errno) with open('README.rst') as fptr: readme = fptr.read() setup( name='sortedcollections', version='0.5.3', description='Python Sorted Collections', long_description=readme, author='Grant Jenks', author_email='contact@grantjenks.com', url='http://www.grantjenks.com/docs/sortedcollections/', license='Apache 2.0', packages=find_packages(exclude=('tests', 'docs')), install_requires=['sortedcontainers'], tests_require=['tox'], cmdclass={'test': Tox}, classifiers=( 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Natural Language :: English', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ), ) sortedcollections-0.5.3/sortedcollections/000077500000000000000000000000001306637307100210235ustar00rootroot00000000000000sortedcollections-0.5.3/sortedcollections/__init__.py000066400000000000000000000012251306637307100231340ustar00rootroot00000000000000"""Python Sorted Collections SortedCollections is an Apache2 licensed Python sorted collections library. :copyright: (c) 2015-206 by Grant Jenks. :license: Apache 2.0, see LICENSE for more details. """ from sortedcontainers import ( SortedList, SortedListWithKey, SortedDict, SortedSet ) from .recipes import IndexableDict, IndexableSet from .recipes import ItemSortedDict, ValueSortedDict from .recipes import OrderedSet, SegmentList from .ordereddict import OrderedDict __title__ = 'sortedcollections' __version__ = '0.5.3' __build__ = 0x000503 __author__ = 'Grant Jenks' __license__ = 'Apache 2.0' __copyright__ = 'Copyright 2015-2016 Grant Jenks' sortedcollections-0.5.3/sortedcollections/ordereddict.py000066400000000000000000000146241306637307100236740ustar00rootroot00000000000000"""Ordered dictionary implementation. """ import collections as co from itertools import count from operator import eq import sys from sortedcontainers import SortedDict from sortedcontainers.sortedlist import recursive_repr if sys.hexversion < 0x03000000: from itertools import imap # pylint: disable=wrong-import-order, ungrouped-imports map = imap # pylint: disable=redefined-builtin, invalid-name NONE = object() class KeysView(co.KeysView): "Read-only view of mapping keys." # pylint: disable=too-few-public-methods def __reversed__(self): "``reversed(keys_view)``" return reversed(self._mapping) class ItemsView(co.ItemsView): "Read-only view of mapping items." # pylint: disable=too-few-public-methods def __reversed__(self): "``reversed(items_view)``" for key in reversed(self._mapping): yield key, self._mapping[key] class ValuesView(co.ValuesView): "Read-only view of mapping values." # pylint: disable=too-few-public-methods def __reversed__(self): "``reversed(values_view)``" for key in reversed(self._mapping): yield self._mapping[key] class SequenceView(object): "Read-only view of mapping keys as sequence." # pylint: disable=too-few-public-methods def __init__(self, nums): self._nums = nums def __len__(self): "``len(sequence_view)``" return len(self._nums) def __getitem__(self, index): "``sequence_view[index]``" num = self._nums.iloc[index] return self._nums[num] class OrderedDict(dict): """Dictionary that remembers insertion order and is numerically indexable. Keys are numerically indexable using the ``iloc`` attribute. For example:: >>> ordered_dict = OrderedDict.fromkeys('abcde') >>> ordered_dict.iloc[0] 'a' >>> ordered_dict.iloc[-2:] ['d', 'e'] The ``iloc`` attribute behaves as a sequence-view for the mapping. """ # pylint: disable=super-init-not-called def __init__(self, *args, **kwargs): self._keys = {} self._nums = nums = SortedDict() self._count = count() self.iloc = SequenceView(nums) self.update(*args, **kwargs) def __setitem__(self, key, value, dict_setitem=dict.__setitem__): "``ordered_dict[key] = value``" if key not in self: num = next(self._count) self._keys[key] = num self._nums[num] = key dict_setitem(self, key, value) def __delitem__(self, key, dict_delitem=dict.__delitem__): "``del ordered_dict[key]``" dict_delitem(self, key) num = self._keys.pop(key) del self._nums[num] def __iter__(self): "``iter(ordered_dict)``" return self._nums.itervalues() def __reversed__(self): "``reversed(ordered_dict)``" nums = self._nums for key in reversed(nums): yield nums[key] def clear(self, dict_clear=dict.clear): "Remove all items from mapping." dict_clear(self) self._keys.clear() self._nums.clear() def popitem(self, last=True): """Remove and return (key, value) item pair. Pairs are returned in LIFO order if last is True or FIFO order if False. """ index = -1 if last else 0 num = self._nums.iloc[index] key = self._nums[num] value = self.pop(key) return key, value update = __update = co.MutableMapping.update def keys(self): "List of keys in mapping." return list(self.iterkeys()) def items(self): "List of (key, value) item pairs in mapping." return list(self.iteritems()) def values(self): "List of values in mapping." return list(self.itervalues()) def iterkeys(self): "Return iterator over the keys in mapping." return self._nums.itervalues() def iteritems(self): "Return iterator over the (key, value) item pairs in mapping." for key in self._nums.itervalues(): yield key, self[key] def itervalues(self): "Return iterator over the values in mapping." for key in self._nums.itervalues(): yield self[key] def viewkeys(self): "Return set-like object with view of mapping keys." return KeysView(self) def viewitems(self): "Return set-like object with view of mapping items." return ItemsView(self) def viewvalues(self): "Return object with view of mapping values." return ValuesView(self) def pop(self, key, default=NONE): """Remove given key and return corresponding value. If key is not found, default is returned if given, otherwise raise KeyError. """ if key in self: value = self[key] del self[key] return value elif default is NONE: raise KeyError(key) else: return default def setdefault(self, key, default=None): """Return ``mapping.get(key, default)``, also set ``mapping[key] = default`` if key not in mapping. """ if key in self: return self[key] self[key] = default return default @recursive_repr def __repr__(self): "Text representation of mapping." return '%s(%r)' % (self.__class__.__name__, self.items()) __str__ = __repr__ def __reduce__(self): "Support for pickling serialization." return (self.__class__, (self.items(),)) def copy(self): "Return shallow copy of mapping." return self.__class__(self) @classmethod def fromkeys(cls, iterable, value=None): """Return new mapping with keys from iterable. If not specified, value defaults to None. """ return cls((key, value) for key in iterable) def __eq__(self, other): "Test self and other mapping for equality." if isinstance(other, OrderedDict): return dict.__eq__(self, other) and all(map(eq, self, other)) else: return dict.__eq__(self, other) __ne__ = co.MutableMapping.__ne__ def _check(self): "Check consistency of internal member variables." # pylint: disable=protected-access keys = self._keys nums = self._nums for key, value in keys.items(): assert nums[value] == key nums._check() sortedcollections-0.5.3/sortedcollections/recipes.py000066400000000000000000000204551306637307100230350ustar00rootroot00000000000000"""Sorted collections recipes implementations. """ import collections as co from itertools import count from sortedcontainers import SortedListWithKey, SortedDict, SortedSet from sortedcontainers.sortedlist import recursive_repr class IndexableDict(SortedDict): """Dictionary that supports numerical indexing. Keys are numerically indexable using the ``iloc`` attribute. For example:: >>> indexable_dict = IndexableDict.fromkeys('abcde') >>> indexable_dict.keys() ['b', 'd', 'e', 'c', 'a'] >>> indexable_dict.iloc[0] 'b' >>> indexable_dict.iloc[-2:] ['c', 'a'] The ``iloc`` attribute behaves as a sequence-view for the mapping. """ def __init__(self, *args, **kwargs): super(IndexableDict, self).__init__(hash, *args, **kwargs) class IndexableSet(SortedSet): """Set that supports numerical indexing. For example:: >>> indexable_set = IndexableSet('abcde') >>> list(indexable_set) ['d', 'e', 'c', 'b', 'a'] >>> indexable_set[0] 'd' >>> indexable_set[-2:] ['b', 'a'] IndexableSet implements the collections.Sequence interface. """ def __init__(self, *args, **kwargs): super(IndexableSet, self).__init__(*args, key=hash, **kwargs) class ItemSortedDict(SortedDict): """Sorted dictionary with key-function support for item pairs. Requires key function callable specified as the first argument. The callable must accept two arguments, key and value, and return a value used to determine the sort order. For example:: def multiply(key, value): return key * value mapping = ItemSortedDict(multiply, [(3, 2), (4, 1), (2, 5)]) list(mapping) == [4, 3, 2] Above, the key/value item pairs are ordered by ``key * value`` according to the callable given as the first argument. """ def __init__(self, *args, **kwargs): assert len(args) > 0 and callable(args[0]) args = list(args) func = self._func = args[0] def key_func(key): "Apply key function to (key, value) item pair." return func(key, self[key]) args[0] = key_func super(ItemSortedDict, self).__init__(*args, **kwargs) def __delitem__(self, key): "``del mapping[key]``" if key not in self: raise KeyError(key) self._list_remove(key) self._delitem(key) def __setitem__(self, key, value): "``mapping[key] = value``" if key in self: self._list_remove(key) self._delitem(key) self._setitem(key, value) self._list_add(key) def copy(self): "Return shallow copy of the mapping." return self.__class__(self._func, self._load, self.iteritems()) __copy__ = copy class ValueSortedDict(SortedDict): """Sorted dictionary that maintains (key, value) item pairs sorted by value. - ``ValueSortedDict()`` -> new empty dictionary. - ``ValueSortedDict(mapping)`` -> new dictionary initialized from a mapping object's (key, value) pairs. - ``ValueSortedDict(iterable)`` -> new dictionary initialized as if via:: d = ValueSortedDict() for k, v in iterable: d[k] = v - ``ValueSortedDict(**kwargs)`` -> new dictionary initialized with the name=value pairs in the keyword argument list. For example:: ValueSortedDict(one=1, two=2) An optional key function callable may be specified as the first argument. When so, the callable will be applied to the value of each item pair to determine the comparable for sort order as with Python's builtin ``sorted`` function. """ def __init__(self, *args, **kwargs): args = list(args) if args and callable(args[0]): func = self._func = args[0] def key_func(key): "Apply key function to ``mapping[value]``." return func(self[key]) args[0] = key_func else: self._func = None def key_func(key): "Return mapping value for key." return self[key] if args and args[0] is None: args[0] = key_func else: args.insert(0, key_func) super(ValueSortedDict, self).__init__(*args, **kwargs) def __delitem__(self, key): "``del mapping[key]``" if key not in self: raise KeyError(key) self._list_remove(key) self._delitem(key) def __setitem__(self, key, value): "``mapping[key] = value``" if key in self: self._list_remove(key) self._delitem(key) self._setitem(key, value) self._list_add(key) def copy(self): "Return shallow copy of the mapping." return self.__class__(self._func, self._load, self.iteritems()) __copy__ = copy def __reduce__(self): items = [(key, self[key]) for key in self._list] args = (self._func, self._load, items) return (self.__class__, args) @recursive_repr def __repr__(self): temp = '{0}({1}, {2}, {{{3}}})' items = ', '.join('{0}: {1}'.format(repr(key), repr(self[key])) for key in self._list) return temp.format( self.__class__.__name__, repr(self._func), repr(self._load), items ) class OrderedSet(co.MutableSet, co.Sequence): """Like OrderedDict, OrderedSet maintains the insertion order of elements. For example:: >>> ordered_set = OrderedSet('abcde') >>> list(ordered_set) == list('abcde') >>> ordered_set = OrderedSet('edcba') >>> list(ordered_set) == list('edcba') OrderedSet also implements the collections.Sequence interface. """ def __init__(self, iterable=()): self._keys = {} self._nums = SortedDict() self._count = count() self |= iterable def __contains__(self, key): "``key in ordered_set``" return key in self._keys count = __contains__ def __iter__(self): "``iter(ordered_set)``" return self._nums.itervalues() def __reversed__(self): "``reversed(ordered_set)``" _nums = self._nums for key in reversed(_nums): yield _nums[key] def __getitem__(self, index): "``ordered_set[index]`` -> element; lookup element at index." _nums = self._nums num = _nums.iloc[index] return _nums[num] def __len__(self): "``len(ordered_set)``" return len(self._keys) def index(self, key): "Return index of key." try: return self._keys[key] except KeyError: raise ValueError('%r is not in %s' % (key, type(self).__name__)) def add(self, key): "Add element, key, to set." if key not in self._keys: num = next(self._count) self._keys[key] = num self._nums[num] = key def discard(self, key): "Remove element, key, from set if it is a member." num = self._keys.pop(key, None) if num is not None: del self._nums[num] def __repr__(self): "Text representation of set." return '%s(%r)' % (type(self).__name__, list(self)) __str__ = __repr__ class SegmentList(SortedListWithKey): """List that supports fast random insertion and deletion of elements. SegmentList is a special case of a SortedList initialized with a key function that always returns 0. As such, several SortedList methods are not implemented for SegmentList. """ def __init__(self, iterable=()): super(SegmentList, self).__init__(iterable, self.zero) @staticmethod def zero(_): "Return 0." return 0 def sort(self, key=None, reverse=False): "Stable sort in place." self[:] = sorted(self, key=key, reverse=reverse) def _not_implemented(self, *args, **kwargs): "Not implemented." raise NotImplementedError add = _not_implemented bisect = _not_implemented bisect_left = _not_implemented bisect_right = _not_implemented bisect_key = _not_implemented bisect_key_left = _not_implemented bisect_key_right = _not_implemented irange = _not_implemented update = _not_implemented sortedcollections-0.5.3/tests/000077500000000000000000000000001306637307100164265ustar00rootroot00000000000000sortedcollections-0.5.3/tests/__init__.py000066400000000000000000000000001306637307100205250ustar00rootroot00000000000000sortedcollections-0.5.3/tests/test_itemsorteddict.py000066400000000000000000000030031306637307100230560ustar00rootroot00000000000000"Test sortedcollections.ItemSortedDict" from nose.tools import raises from sortedcollections import ItemSortedDict def key_func(key, value): return key def value_func(key, value): return value alphabet = 'abcdefghijklmnopqrstuvwxyz' def test_init(): temp = ItemSortedDict(key_func) temp._check() def test_init_args(): temp = ItemSortedDict(key_func, enumerate(alphabet)) assert len(temp) == 26 assert temp[0] == 'a' assert temp[25] == 'z' assert temp.iloc[4] == 4 temp._check() def test_init_kwargs(): temp = ItemSortedDict(key_func, a=0, b=1, c=2) assert len(temp) == 3 assert temp['a'] == 0 assert temp.iloc[0] == 'a' temp._check() def test_getitem(): temp = ItemSortedDict(value_func, enumerate(reversed(alphabet))) assert temp[0] == 'z' assert temp.iloc[0] == 25 assert list(temp) == list(reversed(range(26))) def test_delitem(): temp = ItemSortedDict(value_func, enumerate(reversed(alphabet))) del temp[25] assert temp.iloc[0] == 24 @raises(KeyError) def test_delitem_error(): temp = ItemSortedDict(value_func, enumerate(reversed(alphabet))) del temp[-1] def test_setitem(): temp = ItemSortedDict(value_func, enumerate(reversed(alphabet))) temp[25] = '!' del temp[25] assert temp.iloc[0] == 24 temp[25] = 'a' assert temp.iloc[0] == 25 def test_copy(): temp = ItemSortedDict(value_func, enumerate(reversed(alphabet))) that = temp.copy() assert temp == that assert temp._key != that._key sortedcollections-0.5.3/tests/test_ordereddict.py000066400000000000000000000101641306637307100223310ustar00rootroot00000000000000"Test sortedcollections.OrderedDict" from nose.tools import raises import pickle from sortedcollections import OrderedDict pairs = dict(enumerate(range(10))) def test_init(): od = OrderedDict() assert len(od) == 0 od._check() od = OrderedDict(enumerate(range(10))) assert len(od) == 10 od._check() od = OrderedDict(a=0, b=1, c=2) assert len(od) == 3 od._check() od = OrderedDict(pairs) assert len(od) == 10 od._check() def test_setitem(): od = OrderedDict() od['alice'] = 0 od['bob'] = 1 od['carol'] = 2 assert len(od) == 3 od._check() def test_delitem(): od = OrderedDict(pairs) assert len(od) == 10 for value in range(10): del od[value] assert len(od) == 0 od._check() def test_iter_reversed(): od = OrderedDict([('b', 0), ('a', 1), ('c', 2)]) assert list(od) == ['b', 'a', 'c'] assert list(reversed(od)) == ['c', 'a', 'b'] od._check() def test_clear(): od = OrderedDict(pairs) assert len(od) == 10 od.clear() assert len(od) == 0 od._check() def test_popitem(): od = OrderedDict(enumerate(range(10))) for num in reversed(range(10)): key, value = od.popitem() assert num == key == value od._check() od = OrderedDict(enumerate(range(10))) for num in range(10): key, value = od.popitem(last=False) assert num == key == value od._check() def test_keys(): od = OrderedDict(enumerate(range(10))) assert od.keys() == list(range(10)) od._check() def test_items(): od = OrderedDict(enumerate(range(10))) assert od.items() == list(enumerate(range(10))) od._check() def test_values(): od = OrderedDict(enumerate(range(10))) assert od.values() == list(range(10)) od._check() def test_iterkeys(): od = OrderedDict(enumerate(range(10))) assert list(od.iterkeys()) == list(range(10)) od._check() def test_iteritems(): od = OrderedDict(enumerate(range(10))) assert list(od.iteritems()) == list(enumerate(range(10))) od._check() def test_itervalues(): od = OrderedDict(enumerate(range(10))) assert list(od.itervalues()) == list(range(10)) od._check() def test_viewkeys(): od = OrderedDict(enumerate(range(10))) view = od.viewkeys() assert list(reversed(view)) == list(reversed(range(10))) od._check() def test_viewitems(): od = OrderedDict(enumerate(range(10))) view = od.viewitems() assert list(reversed(view)) == list(reversed(list(enumerate(range(10))))) od._check() def test_viewvalues(): od = OrderedDict(enumerate(range(10))) view = od.viewvalues() assert list(reversed(view)) == list(reversed(range(10))) od._check() def test_iloc(): od = OrderedDict(enumerate(range(10))) for num in range(10): assert od.iloc[num] == num od.iloc[-1] == 9 assert len(od.iloc) == 10 od._check() def test_pop(): od = OrderedDict(enumerate(range(10))) for num in range(10): assert od.pop(num) == num od._check() assert od.pop(0, 'thing') == 'thing' assert od.pop(1, default='thing') == 'thing' od._check() @raises(KeyError) def test_pop_error(): od = OrderedDict() od.pop(0) def test_setdefault(): od = OrderedDict() od.setdefault(0, False) assert od[0] == False od.setdefault(1, default=True) assert od[1] == True od.setdefault(2) assert od[2] == None assert od.setdefault(0) == False assert od.setdefault(1) == True def test_repr(): od = OrderedDict() assert repr(od) == 'OrderedDict([])' assert str(od) == 'OrderedDict([])' def test_reduce(): od = OrderedDict(enumerate(range(10))) data = pickle.dumps(od) copy = pickle.loads(data) assert od == copy def test_copy(): od = OrderedDict(enumerate(range(10))) copy = od.copy() assert od == copy def test_fromkeys(): od = OrderedDict.fromkeys('abc') assert od == {'a': None, 'b': None, 'c': None} od._check() def test_equality(): od = OrderedDict.fromkeys('abc') assert od == {'a': None, 'b': None, 'c': None} assert od != {} assert od != OrderedDict() od._check() sortedcollections-0.5.3/tests/test_orderedset.py000066400000000000000000000033461306637307100222050ustar00rootroot00000000000000"Test sortedcollections.OrderedSet." from nose.tools import raises import random from sortedcollections import OrderedSet def test_init(): os = OrderedSet() assert len(os) == 0 def test_contains(): os = OrderedSet(range(100)) assert len(os) == 100 for value in range(100): assert value in os assert os.count(value) == 1 assert -1 not in os assert 100 not in os def test_iter(): os = OrderedSet(range(100)) assert list(os) == list(range(100)) names = ['eve', 'carol', 'alice', 'dave', 'bob'] os = OrderedSet(names) assert list(os) == names def test_reversed(): os = OrderedSet(range(100)) assert list(reversed(os)) == list(reversed(range(100))) names = ['eve', 'carol', 'alice', 'dave', 'bob'] os = OrderedSet(names) assert list(reversed(os)) == list(reversed(names)) def test_getitem(): values = list(range(100)) random.shuffle(values) os = OrderedSet(values) assert len(os) == len(values) for index in range(len(os)): assert os[index] == values[index] def test_index(): values = list(range(100)) random.shuffle(values) os = OrderedSet(values) assert len(os) == len(values) for value in values: assert values.index(value) == os.index(value) @raises(ValueError) def test_index_error(): os = OrderedSet(range(10)) os.index(10) def test_add(): os = OrderedSet() for value in range(100): os.add(value) assert len(os) == 100 for value in range(100): assert value in os def test_discard(): os = OrderedSet(range(100)) for value in range(200): os.discard(value) assert len(os) == 0 def test_repr(): os = OrderedSet() assert repr(os) == 'OrderedSet([])' sortedcollections-0.5.3/tests/test_recipes.py000066400000000000000000000012731306637307100214740ustar00rootroot00000000000000"Test sortedcollections.recipes" from nose.tools import raises from sortedcollections import IndexableDict, IndexableSet, SegmentList def test_index_dict(): mapping = IndexableDict(enumerate(range(10))) for value in range(10): assert mapping.iloc[value] == value def test_index_set(): set_values = IndexableSet(range(10)) for index in range(10): assert set_values[index] == index def test_segment_list(): values = [5, 1, 3, 2, 4, 8, 6, 7, 9, 0] sl = SegmentList(values) assert list(sl) == values sl.sort() assert list(sl) == list(range(10)) @raises(NotImplementedError) def test_segment_list_error(): sl = SegmentList() sl.bisect(0) sortedcollections-0.5.3/tests/test_valuesorteddict.py000066400000000000000000000035761306637307100232530ustar00rootroot00000000000000"Test sortedcollections.ValueSortedDict" import pickle from nose.tools import raises from sortedcollections import ValueSortedDict def identity(value): return value alphabet = 'abcdefghijklmnopqrstuvwxyz' def test_init(): temp = ValueSortedDict() temp._check() def test_init_args(): temp = ValueSortedDict(enumerate(alphabet)) assert len(temp) == 26 assert temp[0] == 'a' assert temp[25] == 'z' assert temp.iloc[4] == 4 temp._check() def test_init_kwargs(): temp = ValueSortedDict(None, a=0, b=1, c=2) assert len(temp) == 3 assert temp['a'] == 0 assert temp.iloc[0] == 'a' temp._check() def test_getitem(): temp = ValueSortedDict(identity, enumerate(reversed(alphabet))) assert temp[0] == 'z' assert temp.iloc[0] == 25 assert list(temp) == list(reversed(range(26))) def test_delitem(): temp = ValueSortedDict(identity, enumerate(reversed(alphabet))) del temp[25] assert temp.iloc[0] == 24 @raises(KeyError) def test_delitem_error(): temp = ValueSortedDict(identity, enumerate(reversed(alphabet))) del temp[-1] def test_setitem(): temp = ValueSortedDict(identity, enumerate(reversed(alphabet))) temp[25] = '!' del temp[25] assert temp.iloc[0] == 24 temp[25] = 'a' assert temp.iloc[0] == 25 def test_copy(): temp = ValueSortedDict(identity, enumerate(reversed(alphabet))) that = temp.copy() assert temp == that assert temp._key != that._key def test_pickle(): original = ValueSortedDict(identity, enumerate(reversed(alphabet))) data = pickle.dumps(original) duplicate = pickle.loads(data) assert original == duplicate class Negater(object): def __call__(self, value): return -value def __repr__(self): return 'negate' def test_repr(): temp = ValueSortedDict(Negater()) assert repr(temp) == 'ValueSortedDict(negate, 1000, {})' sortedcollections-0.5.3/tox.ini000066400000000000000000000001621306637307100165760ustar00rootroot00000000000000[tox] envlist=py26,py27,py32,py33,py34,py35,py36 [testenv] deps= sortedcontainers nose commands=nosetests