From 99fb97048f5585073c0aa7011ba72e7e662877d0 Mon Sep 17 00:00:00 2001 From: techouse Date: Mon, 6 May 2024 11:12:08 +0000 Subject: [PATCH] deploy: 2cf00b1b4c4d150638b02be98167a229e1fe29c0 --- .buildinfo | 4 + .doctrees/README.doctree | Bin 0 -> 110517 bytes .doctrees/environment.pickle | Bin 0 -> 725152 bytes .doctrees/index.doctree | Bin 0 -> 25164 bytes .doctrees/qs_codec.doctree | Bin 0 -> 23946 bytes .doctrees/qs_codec.enums.doctree | Bin 0 -> 84576 bytes .doctrees/qs_codec.models.doctree | Bin 0 -> 136613 bytes .doctrees/qs_codec.utils.doctree | Bin 0 -> 74563 bytes .nojekyll | 0 README.html | 942 ++++++++++++++++++ _modules/index.html | 118 +++ _modules/qs_codec/decode.html | 300 ++++++ _modules/qs_codec/encode.html | 404 ++++++++ _modules/qs_codec/enums/charset.html | 129 +++ _modules/qs_codec/enums/duplicates.html | 124 +++ _modules/qs_codec/enums/format.html | 154 +++ _modules/qs_codec/enums/list_format.html | 176 ++++ _modules/qs_codec/enums/sentinel.html | 134 +++ _modules/qs_codec/models/decode_options.html | 199 ++++ _modules/qs_codec/models/encode_options.html | 225 +++++ _modules/qs_codec/models/undefined.html | 121 +++ _modules/qs_codec/models/weak_wrapper.html | 147 +++ _modules/qs_codec/utils/decode_utils.html | 177 ++++ _modules/qs_codec/utils/encode_utils.html | 266 ++++++ _modules/qs_codec/utils/str_utils.html | 123 +++ _modules/qs_codec/utils/utils.html | 347 +++++++ _sources/README.rst.txt | 951 +++++++++++++++++++ _sources/index.rst.txt | 92 ++ _sources/qs_codec.enums.rst.txt | 53 ++ _sources/qs_codec.models.rst.txt | 45 + _sources/qs_codec.rst.txt | 39 + _sources/qs_codec.utils.rst.txt | 45 + _static/alabaster.css | 708 ++++++++++++++ _static/basic.css | 925 ++++++++++++++++++ _static/custom.css | 1 + _static/doctools.js | 156 +++ _static/documentation_options.js | 13 + _static/file.png | Bin 0 -> 286 bytes _static/language_data.js | 199 ++++ _static/minus.png | Bin 0 -> 90 bytes _static/plus.png | Bin 0 -> 90 bytes _static/pygments.css | 84 ++ _static/searchtools.js | 619 ++++++++++++ _static/sphinx_highlight.js | 154 +++ genindex.html | 613 ++++++++++++ index.html | 201 ++++ objects.inv | Bin 0 -> 1168 bytes py-modindex.html | 213 +++++ qs_codec.enums.html | 329 +++++++ qs_codec.html | 328 +++++++ qs_codec.models.html | 436 +++++++++ qs_codec.utils.html | 255 +++++ search.html | 125 +++ searchindex.js | 1 + 54 files changed, 10675 insertions(+) create mode 100644 .buildinfo create mode 100644 .doctrees/README.doctree create mode 100644 .doctrees/environment.pickle create mode 100644 .doctrees/index.doctree create mode 100644 .doctrees/qs_codec.doctree create mode 100644 .doctrees/qs_codec.enums.doctree create mode 100644 .doctrees/qs_codec.models.doctree create mode 100644 .doctrees/qs_codec.utils.doctree create mode 100644 .nojekyll create mode 100644 README.html create mode 100644 _modules/index.html create mode 100644 _modules/qs_codec/decode.html create mode 100644 _modules/qs_codec/encode.html create mode 100644 _modules/qs_codec/enums/charset.html create mode 100644 _modules/qs_codec/enums/duplicates.html create mode 100644 _modules/qs_codec/enums/format.html create mode 100644 _modules/qs_codec/enums/list_format.html create mode 100644 _modules/qs_codec/enums/sentinel.html create mode 100644 _modules/qs_codec/models/decode_options.html create mode 100644 _modules/qs_codec/models/encode_options.html create mode 100644 _modules/qs_codec/models/undefined.html create mode 100644 _modules/qs_codec/models/weak_wrapper.html create mode 100644 _modules/qs_codec/utils/decode_utils.html create mode 100644 _modules/qs_codec/utils/encode_utils.html create mode 100644 _modules/qs_codec/utils/str_utils.html create mode 100644 _modules/qs_codec/utils/utils.html create mode 100644 _sources/README.rst.txt create mode 100644 _sources/index.rst.txt create mode 100644 _sources/qs_codec.enums.rst.txt create mode 100644 _sources/qs_codec.models.rst.txt create mode 100644 _sources/qs_codec.rst.txt create mode 100644 _sources/qs_codec.utils.rst.txt create mode 100644 _static/alabaster.css create mode 100644 _static/basic.css create mode 100644 _static/custom.css create mode 100644 _static/doctools.js create mode 100644 _static/documentation_options.js create mode 100644 _static/file.png create mode 100644 _static/language_data.js create mode 100644 _static/minus.png create mode 100644 _static/plus.png create mode 100644 _static/pygments.css create mode 100644 _static/searchtools.js create mode 100644 _static/sphinx_highlight.js create mode 100644 genindex.html create mode 100644 index.html create mode 100644 objects.inv create mode 100644 py-modindex.html create mode 100644 qs_codec.enums.html create mode 100644 qs_codec.html create mode 100644 qs_codec.models.html create mode 100644 qs_codec.utils.html create mode 100644 search.html create mode 100644 searchindex.js diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..15c4834 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: ccceffa458940e20969a232f6352bfc3 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/README.doctree b/.doctrees/README.doctree new file mode 100644 index 0000000000000000000000000000000000000000..fbb49533ca1495b5399ea342ea20939f6400be31 GIT binary patch literal 110517 zcmeHw3z%F-b*5xVBTegJ`6Yvmaa(3IBYCFvvTSM0$hKZawj~o;!eWO>&+YCz(>?0x z9(Ui?Xlz6<#2bq=3&cZ~cW^==&*k;85FoHTl0aT;o@^HKSd$k7Lh^0k%Wkq^|5J6V z>fGw?+qds@TY^X*jJt2&sybEY)PGK$I(6#RtKPh9+45!duYP59E?+2}OF6k*sho4G zi}f|Ra<(?>mb}HM7q>pKcz$uH-d}O%tL0iH>n_%p;f-v*P|Q`_(&7Yu+(7Spg<>`3 zSFpP3X1zkWq|4`5<@@rh@ov7qzRD|jMVI|lUvtRKmUD&D^dh~3S5}^M&r##-mnRn` zA$@ZWn)Md*SJnH|n$G-+dY@0;@%qYQq2w+euVtKi!tuOHAyf0vE$YUKLaqvu>#MUx zr&`5Bd|p*@X62_fx!Rohl5w(UD()1$Q>(A`oN4-LF@I(L#{9bc3-T-SH`RA<&zEQ2 z?Uh=omQsg_2js(?fVUl@M>gv{F7> zAdyREYgMm2n+&!)Unmxn<+E<3QpmYUFYlt4Q%sg!FaA&DergfYqT6rN{B&bSM*c(VFv4XBsQQ~*h?S4~V# zj!#TZrjkb>`eR$>CZwaFuNhS3~ucf{ywXa|?jzxrGtp z!J=!!m;)A0gkfF158VOmLINc2LRiF;S*K81%$Mq`@eMcz5m_mksISEX_uO2ukS%zN zPl?~>ok|IU*AG#cE$3>`SjQn|3!_4F;4{_eK^9$av3{i`9zx>AeTlmkQ?kz-8gj=Z5x7fidFVYap+thoRVgS1W0p375XVAVhYsm*3xpq(%p#! z**r{{`(QQ{?AX@i*jVy$dNw$U{{lqtU;O8>!Smw?y_!&c{w5F3dQfqz{ucZNuL(ocrVGa-cZ(LPnS2-2IU`=M3yQ zkQvx>Xe>ME^UaZ5Bc5d$$GTai=G0&IfKy2}B8F4y&_?)v{2tQllzBgr*%% z77J%wuKS<>ADbA1AVY?w8dR!pQ~mlD6|!mlUCz!7@wLLpPm@cPmC8P#%9P$6;?7#d91WJWs;_hYo_n>TlU5X<;n zLK6+lQf$r{Fsnxev&|v%VzUG^>Ev)W!zSCD5r4DdZ%+Jm#osCMSI;SY+dQ)wIEQ}; zZM$7sL}@U575LZ#Fx<&tOt?^M9x zS!~?Uau%^d>18PJhZs^W_6(Au zdk_ua{25gz0jI%nIP(`)Td@%5tEeOn;(P<;;vi0_WAHHGgho)n$;*4kV`JOc{E7xs zpi{$?k??;Y=W`XZU34nGd`XwK+9`=5*JiEZi?vv4?A)5^$V^~`*V0{d2JOg^dCjRF^L_pqL`8Paz}S7*pZs;<=xx!P(g)(qKz zO5)6r7oc3%XUI!1LudrW40({POqVPz(OC5Io(Yw0Yu!$~lZ?I6l0Zi49rTvidTzGe z8`0|8B?dGo9DIvK@19sz*F7i~hr>&negXR{AP#HvyfpY`&$ejzhH5pw88hr`hi2GV zW=nP~HyCPiS)8?vuffcqHmxpJ^V(c`1=!sKbLjy#*hZQB_{lO>T?FQ08?)#-Vn-DF zrB#X}NX|NyGs9%`Fqkh)m&z44E%sE?*#Dg>oa=CD)}#i$P}>@rC^kh)))ZwXkz>%L zNz2`!-A0vjM2tk0Ynn94$bQTsI|vUEk>xBZiK9Dy6y@R|%RPE!6GgE%8vu$7Q2Vqe zp=^kIjjKDGr_o>q^)-Q&r#gd`yPYVw(xhu+Co45KxV8hl4AZ6%R&hB4G?xxR8hYLh zF7yC;9$^eI&@+2)$=4)KG2rSE#-m&5a9+Y8MC(1b0>e@7SHWy0Y;$wQh+M~;WfSp3 z=sQ>O3_p$;{Lrn$r_RQTPg27YEBbZyjId8xgvCOLkE4<}2=N7!i-Qn%bc7J5+Z-1r zfeXYHfeY6*Wva12Z1zQi3N+CKDqh(cQ~)XNYHNY$E{+Y}H5dgRE-n!o68;hl=m8{T z*uWb|D0OwBDF-uoVWw-eT1KQ1_PDBK*yuQeq33L(|0{+vY@+`g{l3&i#{U%)CWsMH z78z?+T)c^X1{3|ef^Im(ZfVapGwZ1oAF^n(9_=-m^>6fNeFY(X3cXrJ?)Wa?&Srka zO~Fk#S17temBI15h9?HMMnQs0k1&l6FM`zc03Bu-gA6)6CLQR^RuG|}2u4SAWoL_B zQ*i%e!uM|}Kd(#fTKJI5Ub0m799jk$>tVG|1JloUU<|knGCX<6;F)Q038dPl!#&ir zG#wJA0Y=*ai?$#xL|k3$M2`fflM}pQj0MJcco80UT)q9E~k^2q29W?4PuO zPquuv+b${65OX0gSF#AWw4EtrD{+8qebF;D5vLp>YTQ zo892S-^S#@cVqG(bO%2$w%4~no@k@}T&vm*EA@;CSG61I#ihCf)}fL(s`dtyi!*b& zs%isVUP(wF#!?;5Qpag6sSp$nucWW6?2gc(<;X&s9|yJ!2KPxN!z#Oo=zECz5r)1; zLOU99{dWMB#F3$wqFfvq>OT6eBqbikG9x?vlas!#SHiPOd}pPnLI*WedX}eHJ+|OP zGX^m!v@vKl&40bKRVJNw9oV&J*Wq$zCN)*S>G-kx%lXolz;m3`_r?yD-SE|Dqg7|E zN~z8i+QG6Ehuf$vTA)&Mv@1r9(06Lb#5ew+bVsj$Uj>=z!TR?C69&C9sK2{m{VNSx zIwP`x*sN+ye;F$;H`x-{UsG-~(F8?=iML>rQ#&|WA~F+*1+k+Kyojkq(T`15#c#A` z7jvgg*rq)rD3*oK$~Ufw-$sN;aJ{Nw{Ma;phedGEOpS=KZ$Tw-F!sGD7YAeaceEsK z>^@%+{{-|SaZRj}9S_Bz9%tHE;p@ZHGgEfWg10u=l z45vpX7SQwr&wtPSZcKWjVLnE<3FfPP0maHTn-z3yZ(<8hWQxoL5j>1+c36;(s({(! z6TokNN?8rgrAL^?;b+089^mks8G{TCzq0{{k>>`f4iJal>4t?V=!Z8L>skp>5^gRGg#XDBX9mK|qoC_wN^hjl=&3*RZ`8DJ)0zg@ zG+nl;3+tkPMJsXeHi5?D;B99%E$cT2+IInHi8BId?^FAvz5P@FU4Jf=W2bx2Rq)WL_2 z9XNXYu-T)%*aRIpdg9@eHaTK=p37l*@ZP3GAWem@04_7%&&t&x*h`VdOP={!$!-Bi z_CU!#!+^#p+5d7>o`FYpFz7%!0FQ7&%Kelqy3d zy?2Itc6=E&sxc_cMi0^X)xpocPvifkL5qf?8H{}o;OJKv8#El9{tWD%hmo67LroIt zJ#kVL5dk=Y3TT>~ta(#=$DV!1)5+La8>oko9u4O$ zDoLD^r_eL_1d zMVOD-yqiVNC6p3wnxr$0L~T_sIZu0=GC>o75YRc5pqIq!bR-0ya7qwxSP_R{b2u)T zrPe{aBa`i^jCkb=vX3D5q*(TVjP2(}=I7@}h{%yzrRYN|h9XnWEhOhb_clabZNu=D zP*+tB*T`OM?k3#Sbc%MCbtm(V7+KVx&El~Ch%d0HOrQ55&=-`KOCGw0&LrlLqA)3n zB8lbH6x0A(GW{Xc)=Q(CLRrbM?3Iu)zFEUEo~+{>_bsIQ8YKj*jvuw^2;yNgp9Zxm zQ01?E{{4VU5*w_L0UwAYaEcSRv=vU)>QBaJQNl<#tFWOP{q;5QyX2i}p~_0QA7xH5Z_tpPj*6(*k9As z+|YWSvj#%QLn1*N4%D!12>!t8``!2i-?L<}F$-|JThZ)+&o)&=AA=$?c3kVI9pCb$ z^M4|(6p*k~sLm$O792uO7Ww1DYnq@LiJpth=#3JnX%~kht1Pk*rxGxQt8;F)Fja7K zQb$S53?R7(FQRkkP;`{*b*h5w!G!G<*Q-HO=AdY#lQxw+3Kd4#w2YT5S;d+ln>v#Y7rds8o!;uML&{F?nX< zgoJ#PWZJjACHtAc|9z;yN8Ggd1}ceTd;c@a#j(9ZLqdKNnD*C#AaRJGomjK6pi%+d zZN`1v$cin#jP>!PU!s!6)tQZbnqM33#u&9%(`!o&3)z55;&AQ-C>MuwW(^T%tOBd4 z0H1FRfe2GE@?09^_Ci&OC_WJqXDAN>V}5*s#YyR|lHP z2BlXT7ObRdSlh4a1_K_8$$+O~GT_!W?iIpCyn{5?#EQRZ#a*`y zg)PWTt|fLr+k`CTph(Cntw@pdf|7%irvP3S*ppHD@QEZ~F<0dVZP%Eg`Xb!k@RJZVDgl&FPNL%ADfvI(eiGEya4SQl zKxf+EEBD{>jm?=4B2HK5HC!K%F13E@*AmBI;O9bNz|xN@r2Rc&+QU$LL73#SR;U2C zdYHHRXxGNn2ER{Iqf-B@_D746^eKy^pt~lb0{XZZh+t7ZX00OIzkqUa6wvJ&|2imKCO5wslbc;Ms{?FZ@0-;Uf1~lV zchhj?>ac0pN53w0J#+;siDL(DM7c{~8tzcqfG5)p(`;cZ?O<)RC3NgLj;T0$jT{ej zQK^RY#;i+vC!nJ=3@!D4m}n+7kWQP_ zI)MK4duFs5;TDS~$;b_@ z$Aqam&(bTnQIf7kqy22$%*W0pzj!GFsn&jdTW)>!)$hHFwf`!s{g6e>N;(6COW`C# z@d0$!Duu=Rj!s!iOOcsZQp-2a&;Vff8)vco>)=?QcgK(#*;RFqCtX>(bJ0=Pd1~Sv zb+M=J#mpOs5YY8T{I{OaJjg9Ru-uTjslF$cP_hwk;J7hv%4QMVTI9MYyY^D~y~Gk} z0^QJ>0M?hEqXJ7c+uuV2A9jtUx{uJxsQV#eRP?(D^*sjnX>g9RdJY)}?qU2pE+b|^ ztw6z;J2v~HnLDVy(cGzbc)$)ef-oBP-MRM;*bLpaaaxa5YisA(w|v|Loc*A5N2}rA zg@pD%4S$;ngI2@!H)Fe8T<=CV@Img#l}uXGw^0!+RmDy^9?Cc`7q=di8ojdGLhTS{ z{8n^vf4f|5f^Vwd9)~;zHGg424f7p7myW1!5E&98!yHlHw5ScL)riZ*zeOc+fbqL1 z7Y7*4GA0Tz+8ht~7ykutNE{P!ZGB?Hg&&%>nHdcPQKZ{WJu zah2J7LLGhTZk^g3IFF(1zBzDg1<58G8UrP_&@HXA4sI7TBT5{ z_HP;vzM&(LP#o;H$TS>0)&U21f_Y%!4scQ(Fr&=s8Ck`kOdy%-1@-+C#8|a2BhfWXU$}90)#vaj? zNxDjTazIr?jbv~%;0&FVnyuk10b(#6|Jp0KV-i_hiADEt=|)mAc0oL+Q&*~SQb^() zmmeCM1#M^^hqsvR*;>zufGbM33x^L{tIC^eROLj87z?7;J%{81)U=9gm(2q;?`Fu}^b8E406)~|M zjd$I+yNaM!PcT0bT?6QZ4R>I-HC#S#4IRE_CZ4A3_E>ml^tO#y(JU`9I?TKqm@=foc|+SfCh@b98d@6{MG-fW;!hkvdBz zrBgA+zW(C3o?O$UJ|>pOEYV^bX|><1TEwmZ5v=4Xt7PkmNjABI=|XJ@eKfqRlb#r1 zw26%-j5k?hZG`bn9SGyZm{;DCEUyVNi-}8+GCd_` zdov|&w%BBh*(W0&XcDtPOb&SqrN4p^vL+2kWz70UF7^l=taZ*6W^1!#W5Nn9Phqz0 z+JS_>$$Lu++9XZRx^#Q1uUC=hO20iVtXe{L2A>3evV^?qrVSP}*v1O1(mngwRPf(OB3}7^$ zui?n7GM$xUc4>yflY|?syg)w|3MvtOpsy7;(;AOj847Pgxvm=ugCy2JA}GR|d8?F- z2tvw`mP&K$iD7hG@6h|KvaLr&p|qy;dMT|9^CKE%a1hZnQp)3sT{~F0Ux`mupPZPi zvZV~qZ^b8MFd`;Iqcn85{xm+7$#!5AjXcO%_)_rO@kt!-Ar40C-9{TOmDH}|D9Y+u zo(Rs!4rbNZlAxH;uoSVsCO-XvM7A~!(F`&HiA`4rFX_M_Ll~Ro(0d$@kdFjcx@xCv z_bSxp&utjH9;^sbt<0bLYfh3TmL?7D;m}EFDCkNdmxKQZ-JMu#&PORIw zO+g)~WE^0(bwCS~)iF!n*hVbNDrj2na3k3iY)s~QA2lt_jf8oR(RS3LEjX7WnjD8w zNt}(Rhfyw$$LDp~5^8WR!$8IN)Bi4vT*&6>u$0!>cn{UzPx2U)2{H{fv-!jlv zEShkIYFK!r>D$+*n|a5mH6ioY zw-}8u%FOELhs>@!>w1US#Y#4U*E^|e61>*37a4g!725fT==F9n9<9f%)q?5gQ7#U8 z?d>RS6+LSTpq<|6M!VPH_{m0h zOx$;1fv9a!T|^2rkbW85=>d=)Yzd@UKQ4O~7v7irt09p}(#-!hyOD?__wzJ+^TN%7 zly3-qB=?hASQ#5@Q}f2yr2o1loy?qy6PNS9sk&AkneSL_1yLd*!2BaBiDMpp59Q(j zOlVxrgT!VULZJd~kqhJy4uuVTU=t^Ng?!!Gpo$9)WHU(7GzL;f+RTpzDWcO&A>~w5 zo6NYfGnNzkaS0N_7Y>^%%NAfgs$E0D2u8IBP;k5@6l|xc7adCH$22J8iXs<;2U&^& zzM5%$ZL@+*w(hp%qZ2RReOB4_vPG>4`Cm=D#h^JdCE-&3^7xdj1SNd&VGl?&K|g76 z&g}Nw-+`b{jN39kZthn#+ce#*Qj7GX7{VTi^vkS)(fcd)si7!}Y#W3gx=(FpU}pmR z8#%4NAnRC3)Q}zn+ZdCRgU;CFnbDo+hab<5=FSgJPHx*OoN9FU%km*6Y_GKhW{JA& z^;BIeUG@g6t>83?sLOsFmBi6yZ$-JT>#|o6Q)vjrTwcy+u|2ReKaXr@I?u;FOJ%2W zksb&a3(RRQ7Rb9D5Da|B9)T47A#~;ap&YW5q)KRM`oEP`W%oZCe24)xdeRiC`!U=m zSX@6CoLJ0noe;6?c9b}UX@^9K-#%9h9)Or7}AZVlam>oc9frvW1EjY zxn4G9=F!!SrCI-f-x^A$Pq4Eu8c{r4fp4tj|FlX5r-{V`v9nKY2?@Mnn2TTt3D{7O z-BUEIq_2#KZ+3$SNEFdf&9Kg+WjUO>W%|lm{&%M|JVCEY$n z`X5U#$H*G6-gRI>rTanb2QppyfK6c^olK7!7O0 ziX4K(TH?%wBUCH!0<)X5Y>*4~)c)cO?Ea>rd+vV%8UF)@zA9 z-Pf3;0x5bH<|wv>!bTDaqyY1?$PNjq6(c{I^il|8kq&g3#H~7-)ZRDI6Ib3O=sOwJ%?hq5tT;>ax4{*d28@?2T-^+ii^rMPJ~&&-oloxi@2g;-lZX0;VmdJ)$b zuSF$s))#L=xuvZy{Qhts`{TrV8bYvrQ$5*^d2B2i#$AtLy=^eb`$EUDnE|Rvd=a@b z+RBXqYMV@>LYkRp%Cr!}!e)d9>iXHXriC2kA>VXBu!688uwKp#CV+2<6Erv+c-J@} zRFQ!_2QmYD4&i8;(nS}mc@06I2J3oYY`m%^1YHmj31Xmxije^l{;nsYFQJTFPn_|g z13$*mA%~U$lz)C%K2Q6~GIf}+O{vI~{87h6P=K7?<1}bA(h*5)&itMw_YAA<>k{QQ zo_&RyY=vikYS9x5&;A6J#KE(_LAf}1wp*Jw(K*V`p&xsaWQ|xMFmJ6&bO~OEvC6<( zgzd%u7do)b08Y~r*bA@)CK`H)4mL%v`Kah6j1LK643?}wjlkR)l5;1x$A~Qj;b&Fw zb1{+s=-uWpic_V;czaFrgG_8{Rlgu|S$v&=^>;lSq-UcXi_^GMaZ=G{=I# z?WiOU1dgFx90U^U;}x`0c;u4%ae<1Ix>34?ROE$tk`*V;bL1Ox$EF4+ zBvy)_rsyYKmL81{PV+b9BcwRcFUe2mBLFU+2l6s+>AE6=b4!*EC*|-T98Pivb|0GB zGKDAfa2lU>icfiETwWd!Js?_LoPq52z}#JIsV){9ZA)>O1VOS23_)G-t|Z=nElHRB#V(+PzlYt$oF$CFka zL9lLyB-EJoo+oi zt-}3&7UkloqlVP;zQzq(V^sn==sh$a7_VeW9xPznL||^uQ-b z5Q!Z^XW!6TP@-|KS5CF%8#M3wq-tRFte_v4oC_r;>(-<3IILT;Q!U83l{5p{m^92V zvwV!;O}jO8M4Op?T7<5^?3d_C(ML8J(ToVuHD*NU?XlCVVMIKP0H30Rqk7RDY#C2=tJhfprg zL|wYA{VBp&Vu!%kbzIgu=9e#AOnjnbiSh$ZC!t zt=2|0lr%Hu# zXR z_`#`id2Hvd-Qh>u{QjzSssB~2OCP67una>rDn#${a0(V_=fojyDGYTmoO(g}5zNLO zEJ#1wazXmB!!iXD<*i>RBZ;X;$rI+vkV1LT3y#t%u3$$}Q_5sou1(APJZ1P1nN+mk zL|~E*JR*B23k$B`AuZEOi!Smn(K{@)D)+3=xjs^vcu8bxN^GO}wr!NO!9+Xdk~v(0 z0&@wuql!qt>`c365&FhUtp`kt{Dy_>!7~MYvaiZRyOMg&3V+Ee+*-*Z0!hX8Q;Wh7 z*&JaA4bIwxM#I@ZY$;Y>6#-`Yn3o7K@?sRxl2L^={v{_FeM?(Qnl zOUAOlu~^2O^4Qj+icN;6mGqUB{kBy$l-=SK0ktN0om|#tfLSvQBpN3@JD<{vKJY7tLTlT8l}roNt{K*l_(d-C~Y{OA5~HVhUx#H*`#@TqrO?R zQHI%gg|PF0i4lk^>h@;KpyA(YzfMNW)^6}_ASUm2$K>6J*4|NOe+a_@d+Rn^qT#8K zfM#}U{X&dDqj8mUA6w`-u(f%Wv& zR%-6_7?u+%tG{002n#A0gTx#}erom(QPnS{H5+L%?U5fw+I8}m!DgB*!_S3i?_wca zz?l#zSJpH`+zy*(B?G~n24PMde(B+RPqJ!5XOn!JtI~l;!^ptKvB0Le18j+-ZR6h= zYSeeA_*FBKW-XF}8a(1ALjje<(OvT>7e{w><^WTj<}vSoMbm@WA#9PgYLfvH%EqRF zT^)I>UmrTM+}}imIh>vshR=>L5}!-U=o#vvl<((a(gAK}6~LDZ!?oVDjN><*xf> zl#3%>-LZ@;32Po<+#q3wefKOCr)(VfHN&kwiDgWVexnRS+> z9#~LcZ)HK%e^TlF8azNfF;|Q}(pNN*&%t*xU;~a?_1#%&jc&HzHrn*DiT*unqB9eu z_e<&ijqMc1T6$xtOX=09B#t?99m-uih4CGdH)4-4NnioYdGNlIjjV3zYAFI?{53X9 zTW`*7p@Yv=uCiD(xd8~ZWh@$mivBl)(9>&IEL+xqqPHd=Z18inI$I|oQl4bd3(Pia z%QmRW78mAr%tnGF3>&=Vi_^hGBG88eC+ReS05 zK+3$3 z_R(Y}7k~40=7TUMbcVEk%{ApBUM0B5462uRVie7M0JX!6JB32Rj9bU0fz?Vca69)o zHN$7A@ld}_*&;9Ke2M6{IU@!kSd<%)t^76%D0lJ9@Z=Soe{0l)i^jYCX2Qprm$u91 zO@>jcM172kr@O(TH^gMoJ7cowwrCz3*;nqc33BCmtpJRTPsj`#H(auTYRNcfv+yH^ zg&Xb07_}em1~)$(lbfH3$xXBJiK7z&+mb>4Ua1zpzP4Zk)xg%k`ZoL!@|QygnM0FW z-%@J=$5)b~ibh6+VD_)aCuAKq$h4A-Mi8!@8pri;O2b_-KEcZUOMFr`;=bvCc4pOv zvq>s(MUWj-vi_=|ZfvbV8rXEZOhwwEVPHavY_g+yE`;zh&jlS0c=I#wUnc&YUmVJ> zsxKJGQOgGgHK8_}dLK3vLed=J6ha6ae2+O104&_T6lkWh%)dfplknq*lvmJfEF9_v zDK^aAMm&=y#TrF06NiydmPWKEwxW_aZoNBEE{;8sil(e|ce%bAAS+@(5R9B!H@D#& z8!0LiFbo6u7M_>;m{qp@#L*OPKr|M%|FzJVDPa>7ZAys#vnipYnd@(E@Z{M+z;Yjh zuPxqmT?Ii?5MWBOd^CO2iS`A9U@Da9{L~?@id>Zdo8RkVX8B9U5fMknD zg>9Sa`(jhcrrx|Yeb}0eU0`NtT0&=R_1LM7^?tq+7w4`ZbK?Vq~EcoO)zXc+)()=t85U> znoT)sO#pyzsQCFF`I4-GAY<}2W*%c>(IJdCa-%V1{Oi;|3Fj*F7;BIX;@^c1L_}Es z8!zJ2i9X{9^?Jz@cv?&Hk!LDNi5m;H1Mwn)Nu9uuyH-!Y;uy}Ettx&0YWc%J<&X*|9SkaN+50%|^DO~iHw$Zc# z-sL7E9nNc%ZT5oR#U_FVcJ0}97(}H6L1RSCmcVnOYmA6eI^y43x3#{x6>``EeRFp! zeRF!V*o`{qoOO|ANbN^u%3hv@Rr{Ql2lu;`RWjjV_SgME=^oTZ>RON0Fayb;-4qCfyn;teLx2ydp43+kEf-GuF zXb%ecCagGtB^bggrQZV!|1kB{UB1b#YG|D~Mx+GQ7i*Bw{E$U+5Mm>$uLs1y1dDPL zpq2W1Im$g}>WlZEtFH%W7HZb65;K4eP)AH6-Jp+5EDk}HjGDyP|{Goadq<>)J>@#u4;Il z5&Xr_;fSameoc%}>yd1w9sU62;%JBc+UXzNLCK^qu&MbFDF@ABcF2e?al!>I+;#Q! z&=GD1Bbu7P633?ABCZz26<{?4gyA%U`)CbGjEdkq!WxAu$NP%S#elg)ld}30ajd3)BR|!_A ziLrc)mAX4Vsn;~)tuaw-UPi;CAGUG57UoNLWf0dR9Jy5$k~~VAATi zvCUrk0NpJyU%=YGR950Kq;BxVH9FG%QIP|5CR>GAZj~!$Kktpdlr|G^OSGDqxD+gL z30hX+4&z6yvhAlRwI-%0MecBY8%{>Jf%n?@WNd0No<`_x!lDWNl*M}^^xy1E=*K7g z8>eulqs5NAe;3U8h%b&mem-)YB3Uv>h*-5B5PF`OWqPL z11xMu;fz`0jG85mt}9}L zwkPDnG>hf>rC-;@fa)WmvpnLu<%6gs&R+YcQ7+E9nsAjq4(VB z`zo4enyL0ibOSHV>awk~_qNcHZRVxXWCXl4HVx4rSM;kXlPKO~(`^n+uOo>ewg_!=V;ED7d1kXQ8div=nqtNIrD8=pXRhx1 z*x+4*bQwKebp(vK3-N~9h`Y#CXl(c~aH9v{gv$I&TqYFC6h%sWVRj8G{S zluc0)m4Z_&JSLBbP+(!s@m#Mki!0jmo;Oz=-M&3n&Q?=%3rLDwN|h_q+jnm-7BUs5 zvansfo638$#aq?45ybf57WV4?$#la1XwKeYA$PWrb8*O)U*4uJSu<#%2y@d^ZHH!L zu(00UGYGb;^MPTo@>Z~tn>{nOFnK%7*Mm!$}1o!^!GG zm6Grrp}w^2ebUB3qd zss~Hgx3*fk))!AAUB%QC7LiF0uBLJYcPNW11f2?2G34K(6K!TuNhv?tE-1?tuhV5D ziZod~?ukVmvxcv_F1UV-vygbcRYz;HSS=)|RpAb5wvcEb$t)xevV}z4F|-#ABSgJi zG_0(mQZ_i-Lpv66sc@Ur<>D+Ac4{jxiqB5;m@g21m1Y9tkKB*r3j~`# z(H01z-ewDg`sd>K=CX8n>@fD3mqhAg~Y1 z11GsZnZadp^y$U;Bx*3;z3i6E*wmKC#ul`P?+2nU8f;HN1bYCs|E(3+o-V;pc%)FG z-Cu*KjajOv3dPPh7Gxofp|q5&U{O~oWW9vE?nfL=Rv{gQQnpy5jc0jRnmTvoXRS^p zeXpI!Js8CM;bg(w|b zst6Il>S_VG4s|m!z$?&%$fSebRNW$JDHfhWhsabs9QuJ6HC%X$?2G0YnQ=otzvZ|y zK%BM!k?pRqd#abj9vhw?r6wgj_sNPGJynaIAj(Dr=rSsaYp!+u-5cclQr)a&z4taQ7<`^E5^Q7n%hJl6jxl$95JR)!W>PqhBPql`SWuzlNo9ZOWbu z2on)`+CrpS=-*~{d};!}>I;GcPAwYt0`mL9HC)QN@&;kXEydEU@&vaygB$F;-^BC; z66>QC@kVl6a#!<;K}74S&ZnkbZz#}L#)Br_x6Bqwg+u+LTZ-{PP%(CUGl#31QUrsI z(@8T+a)f6-3&h*NPIt*-U!tAvb9Wp$(?yLFmQ|kFLb-j&X?!wYs3@Ot^DfA+Lf*v|bjNUVm(^2s8w0;1@G@Rr#>7SYt%jzLSnDpy6 z*mB~V){=mEf!m(={3okya1GvUX-BPzrR!=%oLN5Dl$c>t@ii)@hKA=#EQG(V+ZQ9$ zw*pn0gFg2h&{<)J?J*IFF+ALFkAu9)V&M!9@irU+HV%??ye2kw>o&FYptl{nYpt^F z$BtSPV|TMZcC9)QjlwoZi?_t5uWuQou*&_$_CSTR_Ei2R!Ot}-7?06&b3pJVQT@j9 z+#fq~GiVOT!h@@wx818yW6ORFU=Oe*VGW9r_pf6^Cj6MQ>um2E#qsWmZ2uhw%Ej#xR` z(THj@Eob7Bv=)i7eTO95UG&A8?(Mx)!F-;z`|W4>z1KGSX?Gv+U?QmxTXZOKqOLa+5F)euFa zqAiqscPX?e?u5~@1a%gJiMBdRTpwATt)o|$dW>}qDv7hBxe4XEqRu)Vvw%9giDs@A zwmzZG_(H;#_h|4eYK;lcvOm(XJt)A`0_4Ed9%?qV1AyFYMIwb}Q@uSrKPS{^c-{q} z=m9(@Tf+03fqA%UY_5ptI%EN;p278v6-oj?vHl|3PI~P%Jj>*!!`iN8FpaXpTdzhxy1WaG$t2Z+;VKf}qzN)8R=U@P|RM7Rn;XB6g zf2}+&5o)v=`3Fcs57fxMmTKf(G)_(y@z8V!I<6DXl}pemUeY~B!8(XuHWRW#d`zfV zXdJ!7c~;sbgIA7I%3d`kW81gIT zpd1Z*1Wiq`=k;;S)o0)G@$O)cGd8g6j)7gf_uaYoj)C0=GzMK_RB0@_9c=9Z79DPd zMW=7U@eR67A&bnszE_T+kB{)_Dj`S7EylAnb@Ba^32AZ??l`4VxrP`_Kp>21g@}|F zP@dx;s~SX2PS(7sy<^Y5v5#;84EQ5y>^kE4<}VEGD^ivyO%(&)hU($W_&!j997AeIRb-PO5V zvaxL7yxEb%X$vF1l2x1PYt$oFMy9Jsf2ifZm=S*poAEPxQ}|1k1|Lfg4x z$By05Xo5yu=0*Kl6`eCuf=_Nldc;|Hq5d5~ zG$pm|iQflheky_iJJe7F(uIT?-g?MIwl?Lhs?NDtWN%}-7lKz+AQkCd0|4*q2)`%@ z@IAVO2pV$&L4c>91OV{pJ<{n~$CJ($J1W!{D12=_;NA{e!eF>?QqwG=PMtimmzgfj z9V_(G{z=?KT*|Sc9j?D%JIu||F?Y~`yG6>lYXk>hX-Rjs;E1!MhALk>Gr~I1YA~f} z6e83nx1L(;X!|t47pP6E;RMduLNvU>S?uK)+vn~jvV$qRk7(8(&%f|EG_cvo*kgLs z0oQCJ=+o4IG=f%AHLUH=SZ&8Le0~*`#4&t+3+3V%J|@+AYuOE$H(7!m8fIbM^hv2^ zqY%P@?m1__Mnm0dwf70({SJt=5d`Vl&U!XwA+qs33PC5z2-E%9?oYACbFg*b+oAHyj<(w;s4Q zfl@k9s>A}a6d_ImSroPZgOU*q6;f_0G5K)5Fy$rhKl-pqg6fu1^9AhFySaiRvgy*d z?c&8WUPR8^w9L;&-irIWLKlrIuAA)6@>C zG_`Gpk0eQDqotk-<+*$-BgXE3G+CJ;ZOmjvABZ@;?23kUF4lkubIig??=8#;Cm5t9 zk-%j($!x9am1omZpek~=h60yL(;|(Z3~=&Iy3wSUl5vYpaa`|N9h5sX{^3{hZsEf2 zrf(h*zu`sX(%DaO{-a`{TR^T%*`hwEn5j*T!fodvQOTH3drFchqN+;MIB#1eQBKbk zsz|i0j`P9H#1R5&{XuMdjHB8KR4_jH_~?#Z=gtqNBy~eb=7Uek3>ndAN*<`CI{bUW z1_uU{whGea>74=56#rxNuc=~IvdHQQl{NmT1c;;(Qy#L#ue4>pH+ULVq zkS%)K>yDjc1ABK3WOmZuDe*VEPdu5TzuDZt-kk%t?^8bM%d&7;76yH&0bHB~{`9~f zF>67QQCle-z4sTb^X1AJB;dfT6Z+R*W%GM~a7xU#>^m)H^zKuUft`FEO7A{lb--Zh zpESeL3KBB4!&7NwED=uyOftwNIBN-+7W5%Ygn&MSZOCqgEGRb866yi4v-tpId#Pje zOaLfVQ*l#O*QsRlLzTgSq46Cf`|ce%GV%DX^IMU8K~_0TFCD$__(LZSAH4VB!v>S7 z1wg!PL?bmlrGJv_lru*cJc*>S;>FZ-rCggE+PQT&x$};#!OEzZY!j5p596{BRk3x{ zbeZ0y{3UYG=$rbN!FkU!nwWsP5o#xZ`BccqeaZKfWbY8lHBm(Vs}vU3cnP6jQZzj{ z5EaiugxxK-9%CTJ!yIOo&QSSw>WEmdr2Mx~SZ0WnMtU_dIXRddL_i~ zO->q*{W{JPwut?V=4FHXou`Bp;~A54QZV&C_{?unlfElhjvS-scPx5>EBuIoTVF&a zaeRtjM!7gX#ST+Kiopzcs@_dlM63{AhLt4iY)nFU#2oY;P6?YU-==|=Tv_c`#Yp%^ z`gN(U-fxKx200qVL;o)*7l$n`(yopWa0ubUl@@HU@n~R)7VkO^|BFee@OTBjv65Ha z5H^y0I8<;4lM4VAt16rbfoqxwd}AeVjZehwaiEel-9WV2@9P!d+)2G{1vvXchaw{2 z>_H`Q0Ouge#gXi;0}gahG#&*3rxR6W1J1bN3IPsP#YmXw23uYplP%LR+0qtpL?>xp zs{>;};I{xL`dkkKob#b085wYV1y#+k(~mfw4kJTh%<|h9|K1S4)#WKxj|~^bOb^?T z5yPs?ROnRW7%IjLCd(wVZ9Krzlrdq6K^s(gf^l*VP@IkCh5o*4l;oTB^tP;aXkQ+8 zoWL+Qc=>xG!keUyWiCO&nvA<%KEDq$u?NoM_matKrkI(R^%qs9vLm!Q8$ndk2z?>) zu#U!RbwqR=PGlC`M(>-|Eq$T)?bU7Q0-Bbfh5{QI>V4I6t&(*Y^TYLPy^2$+7R4o{ zxLCeC4L@de5%)pXS9xX6DK0*+te#NsxH){S5neB^Z^+gvv^|^l>pEUvr=B2;&RslS zUxS4q1&UV}>sR6Kz?z4U@)XiRmpr&Pafjr~oMO$bEisO|lsHvY)4~q-y@MUeKT=qb!J5@NhSYN(TB{WCZM|2{ zrfCsNzk-xipt-WJSigD-)s)Jf%YJ;SzP^g!E*uF;pCkBMe5$^I{IYXtI?#%ORaAJR ze1h8v#FI2RMbg=#Q>~&iXwNU8AFRWT2#9)17hS}REk1BXJ&|{c`s=FtRXEv%QS=llYX!x>r$79zCsCOCbvCFjOzV}(;b0y74Z25 z!5`CZrBbfQ%x7)|93WD&-eUbqIr6NQRic)~`c2j^RuwaUN0z|`S+5r5x+?vG;15>e z`bO#lWUrd{FO68NuP-{t^yW;v81Wn~RlUM3E!MB8Ak$1Gm(IE5TSqfEriF3n!#S=g zbQ2>|$SHxy_tiHzHLsjDkLp(xAa3h(wb?m@4*MdBffWz1z2H`GLkCrOrFbHQow#ov z%~jo6uADwMO9HjgJvUdby0{9_loV2u_0ngNK3j_Hm1(4{qjc@)h)?BeHB~U})}b?$ z)lSSiRJz`OEsZ3}=p3$C-9(?z2u_}Pbn~KHqS|s``PzyzufIO9ynYqUH%Lxt8iFWp zDPKIcaj?E&&YeqRmQWA{F3Lb7>*z@aR}Q9WYSf>ncK-1=a0~Hb{W^M65P&z+IIxX7 zJv_SO7SBfpcHEBf+yG#*s;4KW`Yoz@OkRgX_KaIe6bp?O-vad|2+pq))aFMdsXsyV z3Q}*NJ_u63M3f6s>AD6<>W7G4K`NcUkfc(CiXc_!_*#8EmryZg>$3&OISo3-Q9dCc zQtwIT@F(&;Om#@~Y^Ge)LN8vu)_SPl?hn-1uUZv_t`5`>or3$nfDqT&b@{(QwF4%z zIBEtcgC5P6al4NYJ}Ao72mR+yLx5)f54iNe^6Ha|CouI94-F833{@fRvSE#yfyZn0 dV{ac7IL8b}g5V!+i_c4&%X|+u1{{xNbef0nU literal 0 HcmV?d00001 diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..74326b2e2ffdfe197cff7e2f2da0483fe6253b0d GIT binary patch literal 725152 zcmeEv34k0&d9Ed`cD1WpzArqME$vFy&g!siS@z17CE3V2Y%JM`te4rIncnRg&E+|? zS_=V=VpI6US^0^th0yqqrt0tw_LKu(enawiW+VkaR9Awcq89tp|geSaO@Ro&CQ z-P@yGK`hK{cXfBwUw{4eU-j2tuV4E7l1mm{LjUY_jha=coKBmSQ-yl9QZ_5iw!P-w zR-u$XpcFmV-t=VqYi$>aZk5w(3ZM(PLs#HvT*fU+NpTvugH!`_u-psYFRdx?*Zs46vmSAYx z{b|uuqup#jj0cT+j#{<)hpYi>xwXPtX|2NlR`aL1YGtx8)wWj(nB;x$KK{Vz$kK+{ zY_YDGr<-P_QK(iL?QsC=VB~Z&ZM2$IG~c!_m1siYse(C8;OeCnqgE}M)k@p6mz9jl zRLhvc8;i|K+g?!tq8b@q1(4TQt5=I=4v0q2hk4KKUbJOZfs_@8N+yOOb-dLuaJyE# z3=Gv~>V+u_pIrj9D7WjjZ{2?DmX!Wo-zl?BooZXR*nM@gWEu^?vvg~EdwLuGqF=@g zJ?m#znaOe!kS#A&b4JO`0KtR|yN};D+J=1<(Auh-8QHhYWT9kM3>wcX&eW^b=GpWa z`Rwc&;Phb~xm2^5&$`Dm628kOI(om66Y**OeS~77f%fyDXFXb71CtMSIb5Lly*J7DQ6}z8kK6(%+$?E z6KxWrYDUfkHdn9@IjIqLSJh^wXwHK=n==gNbrxu>M0Dm1HRwQe4CLrOuGaV%0{g3) zX1RtjH5+XD6X^_OoHAf$wY>xDdK#!-9aNz<%lrj2?9V?wa3ZM14NHu_E>>RHDi z7A2YHOpQ^+6~G*$1x$-_nUIUVf)c1<5JJYR6-w19w8HK{R{U-q!w)eOkV$5;WT4@5 zKmxF4)Mr3r9F2=>Gaw8;YZdN*j;<&hl^SMtBh#vvQ2nw>p;;^BPR=j}`RRiO0%M+O(ToZw3i*HzpQA0_{?w?6B-=B7uW18yJA*<1J7vn+VEn#t@xe^7wvq=`!_^n7a*z zo_@)G80%VGG(dODm=pmg1kxeAFnVAWj4znzH>cnXXxB0tg$8&)3Gi9fQl7rRY%y!C zEcJjf();gO#$@It_5dr#R3`4%LpPvPw=AQ~jMc2TkViKQlLZobeXYvLN_855EN9Oe zIaZJLoV|?Qw+i_-Zg?BHDq3%E5_eO0X5wxYdl4khm@w-uZ>LrzvIb*jWvi@axs=I) zojOGvO3Ct^;+3pI@EJjVO9X6G0wHV{KxIjg7_$b5%6Ue;I z28KOrfF!|z_^S{e=ytVYlu!p@A5Si2m2e(L=q%*eT;lE3Ow3W>{3K1U%h;Q4QHJ%v zUi_(#g6(mbYo$U{jLCUXMjA(k%TlKfHm1CcDo6Ph{Cg&!sYuFbNa!ZSv4E0B9E4P9 zm_|KkksiX^C5n_^92I41El0)otX)?HI%i+SnqISOV(I`%bcsD<+AhlY;1NZU zk^t;+oK#!QT8o6QR27yoRRPnR)em6O0h!+-5lVVlUQ8^3YTgGBwMoJVuU;pB1ho*KXI#8em9pLXpy&nT z($EXQ<GKbSt^{Wrz>W2q*5!7 zh>iZr!d^mM=r*|?S$(wyU0W$37w@}*X}f-Yap3!Bwi$vkD2NE0FCkfwapzKlQga}{2$ z@btx%DrUD*OpFQY0aG)1F{}`#Y|?zYf)^=_%#lWG`6H&o2)&djWLdUaJ&8gP6|A39 zwO+4IH$V=eO~&U{(JOGl%NZ#H7i(zlK;mL{xN6$9ZlM&7&=Ff4R)#?5BWB59BEq~V z)PX3*c~`mLlWI*0-qmhV-F&=7>ZWBHOs_!a*Q!sso)48zDQylnHPNSPZnOgT7jUqc0D<0K>j zCq=SHaa9F3#|*_RC{!k^8J)=2$YPDiWTB6K*UBdf1uv6^6XvFTT&Y4OZyJRXh@pkn zuaXaP^(quA$HF4?Q=Lr-bIu}xZTD>+9e(ZlTP9$$vZobu8d!l~wtHF?7%cXsteA{J zM~pDZBI^=bwW)gZrhq;G)5dy3cOGFb=Iz~ORNAS3H`0UI+FL^}K}5Eu0A=+g z^jlbAZW$v8@@=7bsA!xrxF$MlwO7OOP^c+3RMyCygrlQjp`sgWGw|+IGQ@*hmB+!k z$r{KrdsdkL=k1%tOS5%gy?9TEN18jBTTs}{I`lzlB43L6Q8F#FRD&3+AuU2 zcgeaSgxp8vLIskrUUu!zE8K_dJ7`*5HCa8TG?po(v z`2Y?ow_+fZY-O4s@B$GYF#(uWL#hlzqpqAXg^`sLo0F;^l-9=~ae#E@)M0KHXjr05 z*dj|S(A-Z!(yPU)=vqtK2lIiELId|CX4X=6kB{gX#8akhGJ71;7+RaX!YILt&6*JG zq!wH$-{Q46mObhz7fypcyKhLRm7<_sE5AlNMAopc+!|m%$j4>UG7Dwm?Tqa(xCu5Q zLim+YYWKTe+BeG&o#&W{j-{93Dpea!X80J~R_JB89STr%nYg{mUyE=-*h|@5fOa8Y z5so7m_fQw=;Fj0OCxway*F=*Xi@b}(cCVIC$q{ANPr((+U3x?btEJ~xbeU$8Qv_cq zBOh`GoVQa>`DB&(J~@&wr)y2NdjZcyI6?zP{1-27F(qNXR=cfm!)pYSheJ0dqom>1O98;%P=6PB>dAQsfNj7JU3VJKt-tajx=Y{5* zS*CD+A#0;GXfMI4O#2OOYslJEd^;9waJd;~UJr33D&Jxa7k`kKr>$G$Dn>|lzIl(e zS6<$0?UR@HS@+A!gAOy6g!Pk>xPHp|X?giG*8dQf(rL+%YF{VU2UBd_ zE(IpetWxg1ke@jIEoNcSXhi$a`dMd6eAv1AIp^w!t#?WIK4N`TUjDrGF?soM>lftZ zFFId+!uq5v{3Yvu%FACqC$E0Rx%!m#X<7Ior|>i9W!bMfWxwWJ{kruV^6_tiwF%z$ zTTbJjb*_Hf`Q~?=tKW65K4<-&{P^?M@5{?SaGw96^+&SskDV(2#QIZN_-EEFY=Zo` z^Tq#i!TEyqLHXVnovHXGr(b_z{iS^TSJn&i@f<>i;Hzmu0=k&Qb(vF(nBOTP1u z@*V4|=ZYWT(%_$*tFN7xWnXtF`y19jOCtUk>wnAV|Ht}QacQp*?wSe=J`mHgS{_Sf zFi7EJ1i`Q7PbDof8`8QHI<8pDPScy}(zd>$ZGE%ZHW>E)jWf-Ex4y-0|AVngSv^fC z*!g*w{Osv}@|XYLId=E$A_XweWpNQM*ek`wxGFA@4Dpu3gg&R*qolPlh5S?`Oh=%v;2lQnd=R^F|nyG!NWWpsDByt{(#u9SCI;o{ID z2E)~K`7(BS4P7o}m)GKwb+vdMu8P;=hn3%ei%sk*g)7Gw!%A*M3IArjyt4brm%^6_ zVCrL-l#qi}a>O`yfiJ+?WE@%~hNpNFD&dH|SzaLy0=59GN+=+(2*j#{Gvk>Dg!yK? z#NoCIL9wY=T8z+>8y>8fK*->DSr$F*b-#RK%Q;pcEX!we$U9-0%(_ zajuT4FFZ)avZoKJH?L4%dsum5U+&t+!W$se1H0dO0u`}%jMZRcRB>}0H^oQjM-)6t z*RNCxPT=~ecnUMm@l(KofU(abd;?-t66Y`vS&@~!O8K_QZI*@-%J)c3vjs5vM-!;PG=SO zit`o^Ll~De6~_U3@zwMr@RyjD2qC!Bq`>U8+*0zQYiHc*;C9b?-fnl6esD2%jMz}U0X^)fv$`6BPQHQx-KaN zWxB2?1y#DPDFu(?+L@AddeBgwHtD*h6r7^#X{F#aUC$^5Ptf%lrQkKVc3L>A-ndkre=8fvjGwO|v z8>i7{)tetsZ{DPS^Jd&Q9OW(Q&0CdkTCJ?Tk}tGjc?JO^Sdmx+7b;tN6D8cwOpB7e zSX3fM&{1ony-I}9IUK(4ArT5EbXBL~`Vw%0I+A^d-2 z-ZFl77R?Os=Pb;u_+^q`{Y>BI1usy+I;T?BAb;}L^yE_K32%-+`dfMgwMl?Y0c^#; z(JNwI;cvf)CoKRcfFk&q6BNKPc#8jk7m5T(@hkL04Hy5BeyE+|SLugpFa8t#P;JGp z;Rl0hrKy8!#Mtnql14h$KD5NX%3Ek5v=N>$tV}Jkuk=1FaQ_B9lTnmTZ3r7Z)bE6f z%3^LZ;r**Ub-9jr0z-yh%Fk&1xP54`eYxi=?ig<$>hZNt$i)X)do(aP$jYvtNr!z@iwq{2zO zI$#-yo@C3=w8(h{^SBofB~qsqX@q5vkCm1dFIA(!xX>m$gz;EwiS^)ld!=+Zu-OHP zj@UNEdSl;;Vqj~ejzTZ9a`|KIb ztT*-zKKDoLj%L>z`+oXo{*>L(yn18b&1e3c?phQPN-Ob*C!ttQdpXvvOVUGVFBiUL zEYvp|qj z{1FSGUKO7i#rYOm zBo-?jmF(4Py{~5A2!Yo*!=8@L4HydTVc(~`wevo+)m5{}Ub(6BD+pXGVJ!p>X7<+0 zyl*kqI>H$&q3vq#3%sxF<9p`Ti)qt1iTT2+xY1udgwhBcZWwX1#NP3N0BHtvvu8mg z!e7xw#D@?ucvuAl7pjEY~nR&mmGe!*u+l$n%-B7HNMH;WbWj7#CO^C>7-VhK9mF5a*Nw#It=kUC?pM9?Wk z2pOemW2Vu56Bg?;w1tAgTS<3B)=c$6mIdBsKK@ws@Jp+jE?vi%GR}oLM;Kzr0C z>j3*@T3N#$P=dV3yjW6T5nPDU65FK^`L&c=#<*Gr4amKrXe8(&q$RiPzNUeIFYI0@ zK90tUXX&RxKd+@90-*Rh{Mb97MwZPHzF%*I!Vg{L)6qf!d1FMij$e;Y4=rwGi)CE! z0q|n7u0MgE3>}!_+1Z{aiNn(bgZ@aMkAwVHJokWnv`DQJwu(>U0$3_Og}*Qjp5}kP zpZ__}|2)I~w2IH-uY!v=(XEb);tx<6>)KLujgi7i8FR(A)o3Jfg1po`>LVplwIzk{ z0T4;bXr!701JK6c`X&u;Xds1ur;Jj|+?{HsA7mRJjM7*${YV8^8N>9$x9KBL%JBL4 z_!joQ2-w-})SqTlX7bM)snLK3Lz}h?Y)TF9NfFX_v#QpwU(dg7q>L0=OI7PB(OL>& zJXMtL$IIyf_BNb0rwT;vDIWEZ(%YRblu9YuxPq--W(qM+=q1}1m&%$Jwo6p&X|%^` zsv&OBnKCroFQF|m+W1u9GvR$eT_YCF+e@Lqvps>U+%0_wX=f2u{RlAK&G!sq^-qLC zwXK`%Ug2R8Gv+;LmT?MYcJy(G^eH4~Og{zZOu@LY9Nx@WgZ&q~Ycsovz3rahQzCVj zoHc1)uxBF0qKq4S>oWr) z!fQ(^JCka(5DErci0GGylNcc_JHbUUjCdgad8&aR&AOS&GJi<3F)%SPHa;($+o$cKt~;Edci41mmO@MI4v zZi;{kSsmv?eS#0^6%~J(Mu*F;B4ee!9FuS>Fd4)L>NE6~&g*7lqC<8MgWF~sCHrbK z!!&Yjvlzl$KSj+jLGw$vipQU^W89pCm}v{gE4yP`HH)7^WwgI}l7)BKJq!?gISS0v zWd9eM@D|Z?3Iv3QsUKtpqXfHd5uvpVH+*sTsNGL>uq_=};r5VTTaf!Fs1GC<6>`6f zcj{xTQyk6LhZ3reeflm4`^8V=p&~!+Ws=C9;b+6zLzJ&q`*$JL&OtJ|gQxcM#3dJK zuIYV=g`!?QPjv(>9vj!I{P+1l&o#l!LWd?+2iN%-jo#T+Iv>)TTG10sZe62`l{)9s zxJ_7J&G;(YM`<8C&q$vDdaq|TJ?zoW1_t;h23Kq1>~cs)=%&=@XzC1=4erKYFns*Q zpC<;-p4CUDSJdZS@O*(I5?F@U7KoB~@ZX|s$YVrG{)UVL^GKO}~pAQs}%{aLRxn%|~X zZgUQUzHoACC}3#3+~za)&PYGSmejO`3`}HMl98zJ8w?z*OLA{iO7uE8Z&IxqnWH-g zq*oE;W-XmMZWS7-vWaX*slp^PT49_Z*GQAz7N0U_3$;OP3^wMVF_s-4%Z-oa$H&a^ zvB~kVsqryue5^1&S|pQ_nY6ISX#=+c8HXurdRg7ofql|v$Pb20%LL5seIeB*Vs-?t zWOfEwAs2L565#5_S%*~Tqt}NLfDXvd%?EbZcu7u&;Q|rPugyo-`rTQhDVAY<>XNuf z2k<1XxUi#&i}fLVV?7rc+|O&QhtaY=%YJk0H_v`e_B+Xb9iD@`^~Lp&B=|SrF>Wp{ z&{T2rB@oZTiJR>KL+cecbtWEIz9pvPX5oY6E^|Z+F*hX-Bx62C)gy@fV2W>)FR%+2 zsS^dVp9vw*b_X>OImWdA#TWTjt;fXpl`*X1THIh8FZ`#ColWmLoKQ7x8owyJt6R1 z0RDRyn(G?>eE^lkSYq`_(|saDx#zdLv5Oj45OJYF>TR1AJg_KM_;E^ z)&}Nj$*7CD0*4mXZe<`rlsW3!>0*j9Gkx3Ety^i%V$m0gUK+woCoiK<1Eb&sva*c< zw>jrao)s&mCg%AXOWHh!!>gLHRpzk%>$80_WOn(~u|%`IMlH=c+v_3lT!7hLVUs1G z;*M+5Aq&c{L1ptc+h5LSJB^>5?S~crQewJIKqjxcU^FjfoY%2bY!lh2#I@QpU-a(0 zjb4u#xR5}ne=8fLE>YQgP+1}>b9Is^I=vTbZSuQLnDudjQ z;aoUPH5-vZR=Ubt7)B)$lY2G2IDf|X_pr$y zz&+!-cq~+Qu`#)moFE@%{p8O78)qjMjpNa`K||6djwhg;mE*lxaJ;&?W%f`vvG5j; z>($LPrKZPmF+=siu{*bn4{nOi1us7ERL=N)7{`U`N>=TgaTG-n{W`mErKIpP}7nlUS2vj29Lr|$o zx52-4z=#8*)EHw^#%BVXGHf zPgYy-O68k@>gZ4i`~mn&qK@9ouo_Tt$AJk6>DZ3S67kCmp^iT7 zC!eK^1tg%GM4>$ocxjw|f!H6%I##QlB%d8q# zZGI`I)J@8HA}QruNR6ulrS*`wjzLzQpk7Ke!bQCDND}pf@iCV~qP`E!b9gc_lHYR9`7=ewm-s-x^n zAk>9(l%0?0D0`33QO2!B+CV>p;QPiLml>4rd6dck0#xK`18agp{@GhFc&Qz1yJwjh zndi(vAx|_XIfB@#)7gFY^$@1ubDxcSO=<zin+2Rp*iEO1I~hc7XjlPO|q#yU8zkn9e}v~(kH0smp@5f`oi|BOY&Dx#jNsI zE^15q3`{M<*V`#s<@iPRKPn}5YvF|QI*w%# zLL^im9uJvwK7pwCL7k@K1{b&=hKRsd6I7}Q9B@C=S%o6;atd zT5SpnLxkSDIqef&NTGMX415x5*_;VdlVV|%*Ckdh`Z61$}4@Dn&|qzk8<6z6X!od+_K1H|T1i0lM$t z!^e($!C~l`PqZA~+YtyP2bJuRsUt6ufXI38Bkv?MdC`-As&c#m9B<)Nj`v1XIezLO zPhE$+{m=*~Zyk1uP=57P$(%BBGf0qLoks492Avpyzo!a06I=C>7`<-3@cMV+I05AD z9B8y^EbSpu&hyN7WMkuesT@wf8kV_XarTD^qaJ4?xOVX2y~ht8-KOX^?ChzuJpOB+ zMaegsY5tmjH(zrhpw|_KcVL)7B7Kz4CK_w0#CSLIh0#Hm)DHp0Z0d*oR6I|uF}h*z z?cp9+F&|w;L7$keRHmdzgP;14M;cxn5UI@hw=j|m$DBVNjX9tA73h)2a6pg4cvCn8 z3F(Ir;)lFOVAK;6t>)ye(HDOBIqAeC9u6*CZXntST-s=+s-^tEL9*Z~h$1?GLldev zpeZE|It4q1kyl0$%TS7RMfe^EWl#nsI{bpFB94t_hIge0_U8Ffsc?JEh|@735>OpQ zb>m2<9Fl(HE9Op38B+$%x@@MVDYS=Y2!~jJAekJXm)PsH6C77a*8<^CXPK4q$lH>m z)&aZ0kN1#ga8&C^p-Sg))47k>Q!{dUczSwzn1CF{30^|b02SG4ekL^yxHluHd^6Bj zL0t`wuHjvXa2hbvQ)vpXayn@l46~>|mqR|iVL|e!%t;hLB9K8|tu)a!bY`Gtz>sF2 z;;@~`NeD%>oD!=nWMM`gW~>7?VDz716EykkG+60UbHDRelusp#-!kEklv2tt)+)_B|2dsGkUQGgIm zLOm6R{D6u(s;MCn`_#uIl*&8a8pip&24J!g#vh-jHpaU4U-w^`}J}@8szF`(27Ne(LK5_xvj~^qHs9d6> z`|%gzBQ6PV_$Zp|nq>J5Doey0lDi)}@PHmtNfMC4PFJMFP-g;##TUF}&_lKA@O^21 ziQvz>Nd$kFln8E`#RtvM6|#)pfdsb3RxUM*C5%UQ$zl;e`yAHZEtm%v(-zEw?C30` z(%igxcj}dNKod?w66OKcp{iJuBJZ0^xI!P9n+k+I)Z7SRPREWFcirA$7LH;_B7)D4u93l`3125qZpRqKT&e8E_} z6mKae)LH~us>kcD)M(7%Wy}H7?@*u4w3ZD7>*;ZnPcgOEP-rc4E%l&c=_9=^jNWy4 z=(EUn!@;i26$e=!rLlM&!K2FmJ~0kD*e?qKI{=MI6o6|Oasw*vsEURd2ScbVkpgh5 z!~0_x2VpkB@A*k+jhCD0_>V<43u12G<0Yh7%*}h}m!kG`lcEkMrKk&MZgwE8mBQTQ z(klU7%>z5id#R{1JDQwd;>mWCcxp+BXFk}`Rw>WbL(jr=lNe;>5kWEh7H^0@>>Y)L z&u^g$^Fv)!uVP@uYwOR$Wcxuv=j^iohvQ>CiR^y|n(LbJ|3OrC(aZh^7@BOI(G3T-Z@6RMhC6m_M3mFM9UJc56&~osK271D z&|+OdyH5*6GJSSZ;R<~$+?247!BV4Jq2U7(0K9)CiFTF3_V^z0kI|#w8AEIe&pbW4;!`AABu5)mYQ0Pnk^*ns&^A z1|94?3BGu?Jyd)Of5+SQl0tr4+bBNG?u7p6^vfuo=jG4vmt{ALUn3Zc&!V*WbzIs5 z&WPsQhZbr5U=FLDbD9A9;DyqaSD~!B&ZJ}%M_gN>;$Itb?24G2RkY%KE<(|i)e$B|Zk-E|I#azT zgsJ*AKrM)C`2m7Z^;68^T0R`oqX3;IiNoUMXs&Bw;!#wVNKCjEZxk`%B{QjeeS-9u z*U`@p(9i4fbLd-q;t;*ag|A+=gzd?B6-H295(xqnuSoFLZm*!gAZ#=->M%TfI-U2a zrrB{RX+6$6T_G&!numg!rNBoSZzzkE)-8f!hl+LmiM^C1M{?97HjhP_CR)$NC*v@0 z=i}4`rcOWMuUP5Kx6v8T0>3@s>W;zj$YiWBhACc=`D-3a(ec={qttNDjGmYn8%K;V zb^@@CK#FDMRa+C~OnnRWROK8UbEZD$$H!4d@<#)wbrOE@CNvjVamNu1S=@XVDoeyK zV#LiJStRV3XIKw-;OttqcT633UA)k{o|)qy*L%XS9X;pKheN6j;PD+%>sty?`*ztS z9Y{Ap_j)r;R6*tlNhug*u;29&v{ahRM%FE3f!L1{*U<%uLq<9u0^9L8 zjqO8GH^L4YW8*l@l74eC0S9em9g_!Bj_c_ix?8iV+kO#)w_v*MktJe+`Y`Kd=r_I! zp;={P#__I!cNZ#o^E7R<)O=kcJbw1~H7fdAcWJm274--8)k{T3Vo=dG5D>^{E2t?F z9d)^Gm6HB*K`Ci@5OzJ3bm9Sch$){xY$I&=B?GBi!8T;Mn>J^{NNP@#o#c=h4mhDS zjUsoWQNhMtN?0`@%6Tw%3cG5YD*1+FSrIjo#g5~Xl#Zg@!WL!h7BW(B1ZOF{tU8dZ zn+70q8%gtcL{?6Uh-{ox6P7GPY+}mMBw!gb6iY5x<6&X#bj%rC)@ZGPoyLf(la&)B z3>O5ic^YZ^sA-X^l8zOmY#b=T<3b(bz> zyja6xI~C$c*0qSc1UAh_*A8@rzLVi2VtUCt=K~*Wyi;^ux^`qfx^^vTkpWyLMlZW+ z7#Y;@Sq-CHeDowSj527hYlcx7mCc)Bv{pzvWeU*7ZRH@10n0i7~OpN0}AxvA*aSfNWU) zOgI3@W}_*|YS`X+UQ#_d)T58?MF^idy?{8JuuNg1w8q>h3GiJewRg+&P}Sc@_z1ykKv#w*7`LIxcS)^zGPW!}Jl71P8f zEBX$5oAM>pWi)UCAzL$SAOTplLOH-H%`F3zVbMHo;D|yTy^Sm@V|U1ZgYk&wtroIaNwZT~BJ8Tl_&3DyW>p!# z9G@>HQ5j!k+%gWs4e_Oa1C`C2$~Y+I)nBk4a4*{?KJpPJhc1k$jtk&p?^_vMZ5)*Q zeC%qUujI4MH@_3~5N>wj4LXxwynU-)<<;}iyI#(q^p-EsaNRN=9U4qUzPTZ{T=&|lqt1A1?V6+y_mQP1i_U-Rw znlD%2Dei-^yFneT7xHB{7~^j1eL0854i2=@c&o{`~hlO5|#T$(OlQO zv>!%giB#@*M?Whl6iR7_K(`~eidjH}Azd-c#QyxMs49Z=F?h#X3C8rJtc*mL@{m%4r6aXFv>_52p`JPMQS;fEN4M0!O z{EIUJK7WkbGp{Be)~zl{IEmm{CEQG02}im--!|poa zCUs7EFl0LU^!`L)=*Orfm3?;%Lw_U$o`C6{gmb?F&2>$W&!DnIdVHKP^uvPkXaJ>r zzma?DLTDw%;CpN_io1yDs%ym`!)UsU+E?$8B^E7FJ}ZlUBr1z`S8TJMwc0bB z>9QqX7#TUA=j8&mp|aLzF^&tzT8~C$ts@kc?d-b|VXxAfpx{=vP|9f+w_Y}RS*OqS zdGaG61nmo+h`xQ}Lm|}$@VaR8gy5Atp^pOZfPrK^ia7H>J|8{mL61Bhh_C_b(&RrL zM2_A-j|XB*{_!#IydOIQFDsw$-Uy9uR;*6*&tuRQZkj(DgjY{!g*`bGMOoSmMo_8Z z_$nU9fS?3~Hsl>03G*NBgcdTzvXit1jnOmN-P_J?Ig{I+KRY-vv3Zj;MZ`&0i-z=x z^I`~vcUNEfDz!ALzVx*acmjAx5`F0_Xs&De(!ZgydDE936LdxcD0$-|4_6Ew+Fp3_48Rh#5cIEUfoqg**#B6!{8>p(J%~l zi4n_z^lD+=>g5(=ZxS1^%h;2{hPwlz?R2Ki!O?d*-&(8FVh?3^7TaEiCMICI;Q&9d zr7V&}@vEbVkD@EHnM-@Q&^mt|I^MU347N{0L3k%?UnjsNDAOz59a3okZ;7U#5VUd* zF5cpqgt58;Ws74_?@JFA>YX_}zn$T8kowZd`UU_{^U?M|O@%ttubvO6`y|n6{3C1} zymKwW9$0th{fNI$?#}xonMI%suk7D`FE-PelSZr5L_{=B#u77$&i!QGE9{=5lQEq* z>W0^$zadf$I`U8X0S(@@jY-8?*N4;}GyU3-N)t^gf>utd-b)Zk3LIzy8rGdT3}~nA zsD==-`Va#uuaaDjsw9hLy3uVrH)cnh^_ICYH(F_xO7LiIN{x=D&J42CdbjQ5(b3SH z=_MZGj2rf~OIzUbtRU2vi?+E-Ud9}J&@N-HQxLolCiO{3UXv+A9e9=$T!wUL zF~~Q%v|o0hg3OQvjHbK0#oCno#qKf#m&bn0U$NVzBPHUoo+){v7Yi(&S&3xnGc}4y z2Xk!>41fcRGyZsvP(~ZOQ_VEO&-nraKa8ZYJLRl2Fm#v?vXc@UsnLK3Lz^(0hxgDC z$-CK%U%!4m{}S6_DyeF=NT(@-p2**gBSGrev)`-(vh)CZ{h@mGRDrOb%3&uo4p!8g zWufFEG>0GgAy4JVnn*WXsMgbHkkv#XJKE5_gclbtDl7ZV1!ZLw!OC3H4P*wM$mwdU zl*jf4oCwVn$QH3vvyqXG>(H_H3}1|;n7%bW(dLj; zzz{|=;nc3)OfKeGXM!g9!n*4f@DYrQPP(WZ6d#N52tNCiN9qj>Kn7qBlq;(^1q=yY z6H%~C^@Q^&%s(Y}k2kcEis7$k5|VPDU;Z1%%4dZve3@oOb%!s4V?F3vy*+ z!X!SAycJ<&*u)0iz-+QKBeX@$bsF#a+>go<$%h?| ziW{AbLJ~_Jd0LP^5rUK<%jJ1kpt>03;u%f5-=SD%z=PtfisSLeG@8Ir`{iA`4o?Ta=NaSd$4#S}Q&x8SdrCutZh9O&Q{yF!`WX00V-*%4NlIxT7W}yrN=T zY?$@=|NSA;)F&=7UU8vzIXKQ`4|_C8kDPC* zXl!sweS;TSgX7Li{OW830jAO%%i~YpJNV+sAljIt93*-CK@Jjg!;bxv8z)ghg;TiN z#;z>g_<0E}4q8<4`&rDEg%iK+sN%Qnw|ZFa2JD8co3)aGLzhYZ8qzg8F|iLTc(mmQ zxjvBX5=NR&AlK(4mFkY@^@`h(m@w*W>x&_5%eS_>LhYZ<5tqr1>(&2FNc90SFB(@Q zxFxS&CQ+@o9ojXo%TYOvk<0Np50irzk1Q$v8{tCL82Us@I@sTekFq3|=l^Ahj58J? z`+JtIO{gaLjy@GiRhWWW57P}kAf~!bFT6TWpk)}nbV-;>Xl50rNBzRovtY$mtoVu$ zPDUfQPF-8M!Wt46cj5#HTFZKnEmaw%F-IBO#}7>u;uSVU*=Tlt^FH%TqJ>UbX%)lq3~`dhQ%$jMh0e4446J33{TW~Hj3b`kLt*f`+PdupeJ6! zFQN-rFmBiItBUsl~0=FbdZ-YBl7`E=>9~ zfjKDx&;yVV%<+0{@&*GfSNfz2mK_)rPbh%1UgEQ>=RqEh5ggeVq~ko4(|FY4SRVYR;tys=oclINtJ7gIcq$iW zBHBExJ6%!?C1QPwp(p0!L?0BxV~Dvf8FUbWZv}AfQVTK=0jC&BLy=Q_<8Fsa`2%NN zald-Va$0=lSga}XRl9y#{#X%yyntt|a3YylAvwOWzpGZS*05-eBfeNRF7DCx+QG{e zwCLmaLm^bN5Q6VV2_BVkbv6V)6asbtgGnOz-jC+GCiwmbDoezX~5i090 z&2SWjbEz=rL1&r~D`3RbbmYh4GfIpb2U8&#UJybJU-eQ$$9w}{n_pu1N;iq&-;xqT zoO}bF#(9KtD8-RRn#vGH3SCkeB+x#U!4m^^V&AO3Bno~O-V?!9G*^-m1Rc?t#C$}} z^dl7<%{j(G<>8JR=f0t4ea7b`!Ye~es&8VxBJ*_4tTj`Q8l{$bpkA+vz-h&+B-}{e zU^Wgt2Yzs}S{>cCeMfkH7|~zpJQBCkd31&q308+1R&^SOpwS6u)z*~7JWM>s znq`xRR|wJ9PINVik{mSpLUSgadZ=U~w>)`{lq1(v?cyOs}Wt%@mj`8m5zi| z8b^&02Bf=jn4pzv<@yLip-GFdu69XU{9#n;{sIf*cT$Y7;AgQ-Ade*o%bbBZS1MJf z=~^)rStdykG8PaNO(shGpz@_-GH$`q3I${`5PKCckE%*r2aoPQxbMI*r5zJz12)o1 zP3gl(MSC9uCoNvzU%KEBP$o(M{;#&|!cnG!WO-0{Bg?hCQhEzKT!uu3$>pDw6 z1g|8#)FrbFmkv{CSG^0QN-{(R&B_qO9%^T@dOSkK9N|i}b(SkF>RmA7qcw?*Y%pZU z8Ltp~r;5rF**m^uh@p$6Dh@;Td;F(qpQpP?KhGtlpJ7LRi^4v`4CPKlt*lZj|(89}C;U`1yT;|Qy~9xQe-!KEtZKMhJ-xaHh0L{wc)jKa{B$5=a- zJ5$c}7-_{9ElvZDDaOQCjyR`_wu z=9MqC%{wkTefYpb2lgIUstujs{B6H_v>_5Qb%y#YAq+Ll*Pd`70_DJG2_99K=o2mJ zVE;}C*a6}`i5~HrXs&C%_CG;oiS&qgzIKVf5FO%g#Ed0kkh_wvEFWh5GH&y}x6iRyFe@Aku}? z%>O>3W^TVtYLYEDtuKfg>}nVCyjkX-6b?zmkWj0_123I+-UyO4UMO{DmI+~IKGk*} z-DL%WOI2}$h4;yjE?fXLcM8pQjUTsA*~KTk|BsjgL>yApg+|B%?a2xhhaU$MV+cY{z&(Fjk_h_21+HJ2$3Y#xo5=j#Kvx%e=%i${bNu`@ohkc6#K{-#D$l*KU9Y@eC zKA>5olw!q?I+}tXATHKi`K3CM1_uVTKHU58-hGD-96xsPbV5Sp>jgi{oel=@^nt5G z7f%m3JYM+eBziyW`yM=UWbefTIs?ZK`4&%po|h&E?VjR6Bl9}LUz!{_k%MRfkRLKR zR0aF}kemyrV1F~Bf_>t>aD8vy%yu(v-kf5~+AVg_pz8oolO{M1k4+x$CQ^0~eu~$;1xu z)~mjIJi&e~6Hz@A6Jz7p#a*qW2$3aoxX?7qC?z~jOz^`NssI}C4zMj|*eNXx+!O=1 zY2gNuKL%nLc-B-U{$_2To^QY389T?}!m}8$5!F@1k9Sv>TLVydB*8}%6?TP6Lwfu4 zT95;9Auir?@O%TiXo4(Y$lFPVI;n`H8zNy+3E$0nJbpNEA8bfS!_g4n-~|5%)6 z%%v1B?@uf`0?Fv|%RD@1jkj&RM_1DO^S5|%DVpn=|K&zhmWc7VR_Ww-KamkPCoO;JP1euoSqieVFB0d=zgqmeHo-Sbc#ujc%tP`hEyBJTJcFMwWq5PlaBB^hv+p%5Z19S zF#?HwA0zN=le3@qtq*v2m+{qR)mO!H=$t{0Bb>*>lNHj{BvKZ|hz}LV{jf|$V>!w& zNO^O|%yA?>bY?LV(HALAG8K~xLpFdGze%{SU!w*SL&tyd2eg&smn)Ol>sa#*?^ zJgRI%L8`y%bO!G>6p0Z${-iq1pRaf z*(;9zil9=((SX~Y4*!cG@CWd#Bm(I#&|KF9(pOPgB7tJ547qr% z#A$lAw}+CCXH;X@OiL~g7H$Ef8qH=>d*xl54(m&o1dl|nj}>_Z&-)fi@UY_s1qb7~ zZXHRK&ZcuDhwzuu?>dv0@uTkqfK`!nEhuc^MAD9^BI&)7&2v42gb>^6%d)(y=e(;q z-xYDhKO=dRDO57-t2yO+S1N#b3Xw}U%mT2^y@x~Qc>*PNXGpb)*ayKYnW9i)#n~$! z=SyhEyr!K$U%i6vnBvtx;2|kP4icVJF)Q=cEA8t8b|^k(lZe~<8NTBTS;#8MBd9Eq zxSdnJdKHx+2H{a6nipJK|} zicvPxIHnPn9rA$`>WwDZcn?&q3hf6h8T@{K)toI+trHODD!5GS@(>-$ZsMQO$_q{m z7y-0l`_AnL092X*G)mBH)XE92Q36Vr-T&1(uj&C$f$|ql54by`9&lnki{;p7oHCJ% zSw?eYt4&MUJSYf-XTs~&*)9VH!X8|+&rgh9kWX}$o?I7}AsC34tsp}#xTmY{5Gb&~ zEpnflC79&woKx(n_r^afKb-@MsDo_vdY-TFki&S&4*U54leR6LK0r3SH_ z2UM_O)SIWb0-bxas}J2J0S8|m`BMBzg0hqPptP^|>!(Bd6(Hr4s1HBRkR4EQM*$Y1 zK71UN&AslAz>-XOc&;TAYpwzh_ICQ^?v=q{1VpZx=C1H zToA%iQ5lo4R;UbHABRx-^6-xs{-A$}KfE2Mw{KNKoi97*CUdmKi?IH8NvD-l-KW!f z-Ps?IrZ`hAQ)ao=oJq-8MR{obERJmUQHGY9=jP8=zK`VAzN{0>I*Bd6B1ATJAhC$+ z6938ow8!Y7SNe~;${9By6qLv0(Z26PTnB@ME>-rg^?j{(YEyjt zCK3G`7}nzqT!`r3fyxqz{ylSW)GOl{=C6NHNPd;fg8lVzCr`wK?heKu+-Uq+?UmPm z5Z0G2@mh&oAFuWL>wi9`|A40u9UF(UAZyggcaSxnfa@T9h1hWxaDzwP%uJpF-wf>J zC_u|&;~UZFD7EOQV9bgC9oq}lqBlT`3unzOnBMUCJ4#1}6iR>pPj#evl zR28Xy*o4HMWus7G7Bf4E&bw;d z%Nx}>b0cK(`ke566B7(zop6?*Ot17zNTqSOvQL~6v{IZ7T;iZjZ#`C*5X#9>uJ@^j z3iWEAosUkXS>gfWUmX)d`@}WixDP55i*{C=c z3J+DIlxfmh*~HnP$apM#fL`XdFeAM|Z9W7-fwSgmth>j9@Z|puLRXALB8Cv2no&u)RGXjF5ATGiM{dICkc2 zPv`?(GGz)dJG^6lduR~(D>yU6Njo7lIig?^O#Y?aBcpLhi zs&#gLIlVZ4o2k~Kxvqr+-hj#yc^Piui`+q`Lux~t1T!>7J?!v;wW4yKJAu}P<2%J zTV{PG1*?$OYRkrq*mwsI#SA6Et>L6}?577yV(Oql?>E?9nX*woN#^X`WX`(IX(go1 z$mcVx`V4BBES&c97O_ap6D~E<2iQr-{G8)P+WUEUINQE1bVlb;M?xltPvL}x21Gb) zkvVA=-K|&nNJxc=R84|Zs+udc!O#H+?U7eHC|h#9BawI@9Xxr(M}bhJI;+=s+tzz@ zGCoR^_^PKEqT`HJh_AYZ$`VPDcw2IPhzwave63(1Dq(eqaSNp<&(OwLLwqLwphoji ztKISXsKffwB~d7`I;$vrI;tpC@|wx~_G~LtxO3V|33~MS-3HQQA$;5;I4=^IR5AO0 z(8Xl1 zYVtMpCzxc%gJ*C;v?xNOV{7fh*MQV1+u5oE~zb zkP}R={-!Pwg>Q9Q?d~!;rS-N$yXG~QU+HQ}`ixG<4je3ba9O;aFr(^BtMqpDzT6QX zk4Y4#okVEaShJRh6x_RA{PJQ<)_!(JF%s?KK2(-Sak?{>;^aYNi1zfn5N|pyac|ac z9sgmp)Fo9(LNlAHbmE#GUpnnADan(!q#82~%IbU{?UiC@)b8fnHpoGUe3(+?a%stO zKUGo(k3E>$b=%f$!jULf&3LvA2m9Q<;e`|ib;b#kqPz9R`rRq_Ar;X-*y6QE zcig^pcx3G)#4A^dTn02yqQ|kvd5q%s(VpO1x4l$mUKvK?dy+j}m zDu!-%NrGs>y^BX6n6W}J=KAMo$tY*@e5URud=Jq9?L?<(x9v^%=O?V&F}9AtA+h`t zuXu@9_?f4NIljazzGH+*w|Rx?YREuMTR2z4J0rRp?DlbFtDKyK(NCGb5tx;SD;Ca# zno)<@NPbyLzTr9nCI>e|j#y=^W*!c!D;Z%+M7D zx=?CDuCzH=)$InyR#6QI{sn26gkGr~8rYuzbIVBWNo6;shUw}qT(KHl?{;ouc64&% z6QeVp)xhtH9;w3XBOvsJ6JEa@QFxuGz)yZ(p+eC)u7vU*%Qsml#b03LA2~9KEc-fa z?0O;B9GJEW2>xbSsbrvGp^_`LC@_e-!)0m*aZF!2CH&Rwa1dR7Zb=oI&Tg3;`XV## z8oUi^xteXl_cK5e8WBh(BWIQo(a2-b)2RnhUY{;B5CH~bcLs-%IL+`lX{`yC(ie3$ z%o0g`C1{dte;K)sejsGr#7QRA0XI{H*A0JlAog{p|LY-4-?z$ozbm2=ja;CZ`aD6S zim6`Sjt=u5guomiPm&0#&!M@l`3S#=$`T2x9S%#4BB%uVLPXVXiz!WnAk~>iWLEpG zPAz>9LkZ8LzS!~AzJG~NBOMoMd}^PHr!j5%c9%mWz!o-@MBIh3^lHqvc)`u_v2=@u zrEn%UFTK8UK6-s+5TDi}6T)Uem$W}Q!DrL{PTagSuDhKd{$-@(k{Io};v8r0j`j7~ z^{ygF%HaAO-0kc0-cl2#x?i5XJlWAVPmdf2xO1Vq!MAPSF`I{;s_BN)n(9&iMfKDJ zMA!K$D-iBcc}suSPXP;K+sAc8D&AV<(h(;C8amb2SxcuUe6*#m&cmm-aP6n#@MHlP zi->nD0IG%ltvAOe$MKYWz-*(k<^(3R7jQxvmQpG?lfR&hmK@See9?n_uXkQFF*S~p zP0rC?BDkuv=_#{0r1e!9gAU$m7N)q7`ZtOZ#07(5^wv%b6mm)t1NToS zXR!E)s7d0rxJuYzW*6)*F}h=e23dCI;JC-?%5J2zy|l=3+$z-N8cXLc@VI=TyGr)Z zxjznVpk2_h>={7F4=OY*yT}JxkhD`{06BLiWv!!Ix1_dvdMb~@-Hx>Rx`p`?*L;a< z=1s8`L|+u{Olri4UgDaJ|GvaE|0{7#)r&O(4SeCeSf3B@VtEyAdl{R;h$m_LV%U@? zS_~Vv7p=#6+}#wGraksm@dv2v_4qkbS_Ff;jH^vgwkdM1fJ^HZ;r|#a*7Ya$RWFAd zs6^2%GQEgMc_7^>Lwti}zw@4MO&ty~dwdHmupuL+FgYGlZGbl>nhiXJ?5bux zh4sign0gSR9(X8>{KtWCK5hs7eNx7)cL~7qZjZj_Ug!9sE#3iQ*$ta@WZH!Xu~ayT z{Ib4OJzfXi3bj6cAWMGejxvfm3b?$kljsB445>EJKoY!iAa4)@8HADqJ&l@3=neDH z&)!QgQ5&A%y0C$p1HFEf==F8<OfZq0<6#eyFwd)F zYESIZkeh2i(ZTq>UNARx;`B1L$KwbH;{ja~n-Z2Th)s?ozPK^Sgq%lEYCLmxLD|Wp z;E*`mWIMaqoEMl>vH4bz-olB^R8+C~Jfu*rTCSC_Ljal48Yc@i1STRe8q1p|0wa+x z*AbgsxNdPQKt+7wTV{a8J*a~kTLM~A&kq*8SUtz<|jg`jl;Hl;*;Q& z;&ZJ~Vq84O=$lvMD2HadsE%u2D`Vu$J&##c{AEIoDqaTM_H_6^6(5O7gvu{5)W#W| z5TWwhs4S6CiFatWg2E6BdXt#&DiL)QC1JCoOQJ-=GOH*#6V<28B0RVlkkK7HE+{;T z!$qCP@EXl}+|UaOi7Gb!4#c%^Vq;5y*m%C@5(MbupKlrKk9j!!3$K4CPEdp(DYq(x z91_`J)sZFEESXbA4svCt(KO5I?lU|^R6JtRT>)}<@9~32w<(OtthCCFbj~vB*sPY` zC;sx+AS!s^5IoRI9pYuBk|_Qv@fGTndv2UnRi+q!**PuEou-L1l@U^ajVR6Gnw$+Wk&3nP{-3Twksbt&Z$i zByrFsiG&0nNFqaC66q5y>0oc3UmDriO&Ym1DUICf&`1m>6PIL`IXp@8q=wN;m*lu4 z;92GP?B*9=b(Ha^pZ*{Po8mWId<%ke)4}f3B!Jw_x8cBTqxio^qF*F1sj~ec(A&bv z_B#S(yHBLQo6v0Ju+a{C#w??WBakbQ@6D8Xnu3h6EzadWF-7)(++>FoE67_z;Vp2< zLdwJ3%(2w|&4LLnp@B@IC8JIcrwM{=y*iC#APs=xb)()mE3`Vp%7!qk`4GJ&YG1XH zI*Q&(2$TV4OcK#sL~~sey{A#x0*l^z1+CLyOVPW(E5xVq;4oV15)YO=nUx1WI~QB( zg?IcycX+Tdx?%fm8@BJbkg@vHZH0W@YidmYQ_2YcLXJUYxLBxNJN~PMu9vT+=Lk%&>KnEl6jnZW40jP?nUniLL0WtXI|B!Sta@QE$p z(-%|_I~2=3nj&2{BZ3VFwr{v&--bJOY=ktX>s=e}-5Y$;o9a_dYKm{H+e_G!0=&cEcEp~l$@~MR{K9E64+m&6-U(=5CPR~lD>&(Dm@g;# z_RBbLA&$5rBYN=GocGSKJs8pV&fK)$L`HV$#BS8g95S>sBIoK4{Lu}a5l8w$<6C{# z1uGx{;yR2+ySq_({1qz^|3-)1C?}o<-%>Y_kZ$JaYNUIy^>ac96gNi;#4*ogl4F37 z(#CZPJaYWLU5X0Y*?&qe?U~p@ik!xp8*aWMP0?w)W{G-E{anHgC*H< zp%NTQ0W5~10F{`q5TQ06Xb=z{CSbrigQFsE89+ci=&M;cg#~!84tsaPLD98>%l(Am zZUpkK8t-&F8)HD7N#W69iZ@W(sxsR{wd(NQ7y@6wj7Z}3xE{@QO@X}yl_gSO-Ln&e zCrp@{niCwD23e}9y?lP@SdK*n7hv&eAC0m~2^~FP2k5Q&TYTEfuoggM9ocS3gusKS zED0`lWWLEG1M-Asc-GIhPSJi6bQ(=P0FC9x9~G^uWY1t1#J2J#g@t zdvuOjNlzCLPG{x|20P1%?nc;)8N7%Sn=($adg02vzf0igGxozFr0+X9>GnBx#hIVX zUDfa4LkHy-LqLfol*JiIN;~|Jq(ON|(k$4Q#OSfU<7wd1H@Z1BwP zt=mtZ9ZYlRhL8{#SE(!+h-iu@ZQ|cITlGq6aKm8g7Wz#WtA)xCua&n_H~AaU{An*f z`P_@&``n99{`iYezW2o^fBI{mcyg9yHZcyP`mi_=4!3O^-LPx>hU_-_on*hcJ6Opi z{pRu;c5T~m>mB;C+e;L|=<&ZeMW`;qKL#sXI2U0#h?9ARZyMR*ggK6BdTK4Znw+yCgthmNTWOXFN?%J zCmmokk;g=zCU@u~A$$0^r}^*>;kypPP`paplm~oC6UCRT>A?+AWlHGYEkSEiZi!nV zw?x2xCt;|~*%L33dVTyQQvYrxbyWiY>w-$)rvhY;*Hp1@%Jb!~VT#`w7Rz75j)6PO zmcP6??&L>&<43@nS%M`zwr~}F3Ge2I@7tH!amTLPSnLqpY`cBOu2iFjGZ&n-EsYP^ z(LT{MhD)!H?WXSNO%@u1yNI{OU$L@?_wG)Mc;~T*cN`0Mu;62v-Q&AEqu&R*x>d}V_;%pFg1t>F}O}9CN^x}ic9_i z6h2BAFl|s;VC+Z579t!=>_PCZhCp?Z#k>JYwno$eNbMq8cXIM!hv4uLtqUz22|ZWEg8 z+DhH+s4UUyOw1!S*f2@IQl~Tk?-6X72tj(9dT7?^IFCgq%DP?585>9$57L;cl+h<@ z*1>!Qy*7UfcSjh~0%)!ys|{JW8$)G@NaJS5Jr=?h6Jb;ADy{%E`m&lGqm&G@Qe#C z2;NRuQ>S}xCqeMe__$3X2%blCT@wWFM`ej-`}_z3XekNkL>B~cG#qDId6-D?7rm50 zf`Dq)!TjX>lE%loNgBVNlr&})1Posx2^~5q1s*|=katEB1Ye9lh{*&2Pe)9wu;EWm zjr3;FtsTN-!fVkjI@x_~J|JF{)*B6D-CpZ@j%(MFAauhJ`l8oyT$*DHdN!4tWtEBx z0C%UweVVZ+SF4QCEJScF+Dh4XT%$B^m7d;`^DMf(gnjJmO(|+Hxvk~KZ#ti6Fv*a2 zz`p8U>wDQkE^vKN*m2$&>SX}-&GpILFnLji5mY=(H`Fiq+2EQQX08$}bopZ9=_}Wv zMK|=7*P)fb!A4FcFRWqA%Ivu-r2^)_zk^e-F?R<7Y@ zdA(X~0$OvjaJp>`*vonA88mqkj|aqUt6sw0%4Ri}AvYC0ZM5yB0JlEVw%1Lfl1jB{ zDi6=uD;tRF#@_bKY2ushbM`7)FsfxJOAbD4pu%f;3C?e2B^h$JW^yH?(Lis|p7_8i zSb;NR5$>KTnFtndA6i_z4Bb1l)Lx6N`9NILXto;i;Zl2P-psb9P|qs3)hZw%0g&VE@tZ zuC{%>=ZU9^;(eH&_9|YlL*~xc*Xa*DAKPmPT98-65(nqDi&qigH`|xik%P6K&*V*7 z$V0`*A<#Z*U5RcM^3K@aQtZL&#ijVMSLR#g8ulu&-J^u*RjdFDmu4M@5L3x&R>H`Y zhR-dkHOyANnmJu2idbWwu2mamM*WfvbFP^=g#+j~#jVaD%fA7CCdR%pS)d{5lVr~4 z&I$le=K!$DgU2hyn;9JagwBk&iH`5<)g&`>hE&u@8vbK#;VGIkTb}{gp-GxX4_td^5G3zZ_T%htJx62CTNq^JG zf*$itt9@vh_27AXO=G6gG)`x%!jx6Q|3L{or7HMT@oKz(u6PA~dL?~&y|YljX%X0A zVA4L{R;_)$xE61n#~@U5g~}vQ$>&FL9TgXQsh&RiS;p@B@q4a#DZ73>qv4T7+ z@1sI~JyiV2YC!a}^fSF2KTZ1i)&PFKNk3cY!6y3oN&5Nk^m8BOi{D2-*V5s#SJBTR z3NZM8v^jGnsi_0>^D@ke;ivGTN(`c?zAk z`?c5lWvi_Ibz1#kkM$-^n#;X)i6;Ix8H-=f{05)pnkZ1*Sn0kbm2xMfd)6sGi zQXstrC*KV81UkqFVr2^=@32D)2Z&hJRw1cG8 z7J!6uY68+0^2(e*j4jP?Y>;wRRrtwO-(`JMHQ67;+=>^fRs1l`?4QGr(5l`+)AKA9 zK2KN7CC{$t2q1g=h*d3{BlT7Vn$ZZwS&c}g-Ms+GG)BN*&C}_6quFMMMjcuTf{eZl zyG+ubZne9`+H&eo_#t)H!s7V&1q$5d)F1O#T>NiTMklKs>O+^jQE0pNYT@3_k}+FO zW`QoCW)O9@Zq#R3h}uIlO{-e*(CFN&(Gc?se)y9h#*IvKkSwQ>{6JSTiTV5J628(#|mSfN{z=mV*-9bg(2M+*hcT z>b{lV2mHgw7LAvXq{P=JwO{;oAX zOlpJ@hOIcpotQzL2xWORLOHPp+S+R#ntAA8YB=>MGPgkNye1_J_E)DXrK*u{xJAd9 z{o>y9`Q-nUyPfdfy(N&?YX)9(9J(`Z_rcTfio^7MD~t1xEnMvf1H&IC0IR3?JIF_h z3;u2DH8^DEq`3$Q*yOu+a-mv~swRGb;@fMf)JC>IKL##HH@5 zo`OEkzPP{8e0eLII#z?iP_0wDqU2#%ZHN|xn(!J)bweuUid7aS#+Me#m^7{s7tadB zv&Y%9-MbwMDwL9jPJ8f8>jV~h5mFUzbNyhX zU3`{=#Xl3_KZz?+9!ZIW@$oeO^Zopfwh7-}Vw7MCtkTE1Z7*rn3vGL&r1fw}q5B}S zQNF+|b5h9{-Q6xOx&b1v#ToQYer_FOR!pRQO`D#yBt#f0ew&I}H`wHf(GAl38OZA; z$RU{GP#tAJ9p$s(D;|LOWL@O((d%!C?@0vFQH)=NLM{|MG3x(dk%K@H9%m-OIl!|6m13dHT=VvIf%?H>Fo-l$N*?OsY)OK&*J zjYA1HP;oL!aDXLB2t!qTa&Tz|s~iENyd%me6Id-8HP|gsN)nCQN-=83SeHm?>%C6G-w{vI`K>2%LT5UxJB}3Q)?nB>LFEH64Aj9gAfN2w|_cKy-lI1ySy~@ zhR!tAPEJ#IC+rT)GN!2svSDhdPEg@eEHcmebVB;#hUgi) zHTDU2f+WYoa~v!Mo*?r3eTDq)@si)CI+Ne;B`3dollN%e$StYxC6{*hX-(Feh|qe- zTP3M%uEJMB5=3HOS4iw$FNytSXA=9T~cRd#R)PKTD;F$OsF8|DU}#kCWr54##z$w&hzkHul)E zy(@cnbz9O(D_hoK%d#a~k`H{aJG(p5PJ4G}Ju_=r!8YbH7Br`aa2gTA@a4<#d+$|scfGEvp04hhk-~@lqqnEKy6V+?ud3dA_1-Jo zp13FAq-%oF-K5bK&3eM6xRVNzd2VN%k$z)lq!ZwqoSH#slxfnNjxo$P;tT`vXjQ-uU=Iwtvz`8`VH$YU$biE+BGXLUwir5^`*5& zo{80KWX4f&j~T8&5Zx8i^$F=>GH__@68tp*35TX92Efhuq8Yoet=6< zv3zK9;3`yV2Z0?%!M7`iQ5fYoKtsTYy8}jy^(3%FyI_d(VvoX$*Ti}8Tx2@kKzM0> zUcBGZp$?IzL;8p}8BYI>djsAyeo5wl!+3|r1ZLPxv@Z0U>6Y2L;5~@VKMO7$LY!ZX zPYp2>s$h7r0|n95a1=sm6wF7{rF+U1aGtPQ2E-SAQ%6Sb78%4!lPl1nt5(mqi8D`B z9E{gwBT^#Re0UatlEF^SzWDIG(M;w+e4NjSv@95&N%-m%FHEH31>A&WoM7bvEZGNc zJK&&KA|VOn6JP@{$b)ZSJ~o(xbq7qaIzXb4ca89J;y+U%{((60D`w)~pP%^Q&SMiq zb&CG=RP@KaXRy}vie2d5Bc*Y$7=j};WUWhMNv6H)-qF%Muoa9|z~!O90>HIRLS z$$&n|HxbOGI)a&CO@Ke+OkjqT6aM`Q;ctx-{%vN$zb`-G&kF#zpr}(Me|9R8L(~BH zA=Hob3dfUVqARR?!;x(_ZUsFQy;Vqm0Kbg>!hTs>L2l~i5$Bi0E0Z(Bx&XgM#<2B= zv&KIutZ`eMH9lo#jj!Zqjq?N0Er@i`B7?0awsW1@=D)uQZwUBSj0+zm-3-Ar#_M)% z+p%Z=j$E_Hcsa6o5}p&`N=##z(}WtdbtTXh2*dJ zk-_e9;7QiIx^GqQ+TkMnX_Ni7z1w&6?%mnDZSS7#H*Gu6Hvy3wITZBM6$nC4wt(WH zRX9d*2iQ6B&$u8`18#^De=fWFDYd0~|@o0O%YVQa^Ma zXvPM*H5&B4>Y?HvfXh=ZjyOefMC7>|@Puu#4|u}d5zZMmDx4vlD1|RRZK-cHbH?8M zoDs6KfR(JXi5N`5BrS5OK2b;wn(zGtxQ3czeyaS9Kldh#J__86h4-m^#{9!a8G310 zhAuEJe(hR>MNzLZXG9NmK*pfnyGhAd|q|gFq#>s3w0dI0Qn7`BDF*Fz|E`rZ|i- zj3S=KmihChDEbBjc9ItU2))5E&`IIJGc5!pzxxH4br3@QMkCjI^tB$lEXaX03cvjM zGA7MdD80kEfCU5l{P`G0jxo!3HoEut^Y-o7y8ZecjfWt%6{4i17v@8al7E7X7Yt&8 zyS+Cd*S`fWC4a$0@m>gk#&F#^5DN&=c;I!`@E4+lhtcN!5UzV@yfO@!oHte;g)nKj zJ5kmcK3D+p>ceoH1xDvXuztA?(Z`j^@gq=n5riH`fYQ&P74Pi;f<*i)5u_O63!<|P zECrtWMkM)5Bx-vP!-nb<1V|Q>63M(Ao1yiBkH=Wk;8q`>p&{O!X3BW_((o}0ZxFp2 zyIZuy=jT{kyJ3#g8jIrG;_az#5}Gu`?kOydfotj4h*NigabN@vR{$eHfegj5Lkvv? z*fje&M0>cGMhM6=%|`KgpVli@y4elgq*1zfcp74IAprvT<6FjHw!nG9HrNodIEAxJb|-kgakQRMAwGe6oln4r@zE~p{3gB%M+ETcci@4-DgnR2VUtbx?d%Kf{HDJ95pTd#-w9p| z+Ty%+0oETvnriH3=e6^ov6k`LWl)(juZ2iR;I+#HubtxzYyz*zI+tdx)5L4C&ZfL} zl9=1Xc?m;{LP;<-wfQHqa$&LfEVmc>5X^vau2bI;*Ub~Ha-KVYHFS#SZgfU@!uzzSO;5b?5uB>&MI8N3X=eW3hlNcE~Pb}6D&3S1cmVd)Ok#Y$j zSnx%{s4@w&Y>D+x>Scc+6C0&Vdmq$a_;aF=psRnXg zz@VM?UvIqM;AfPgUg~|h!-b1Weu&MF`ykP1AMkSfc zz)Gc!f=XvBOQH5+GwBg4Yi^3zeF|cEa)NXSHfATVAbAI(#~sPn;b+(5We;93-2p?g z%zt1-a=$?G@-#@sX3`^B*4z}yD))+{2I-KiWi_xM_EtoRJ7Nd%vmv|`@q%d*7-D7K z1S?`U3B(ShK`b_t9_L(s`^L|cd9;u zpHaQ9z&i|^XH=DO^j4~F7F4|{4ORKd@p^3P4RFy`jvLcdhA^jR5ea5f7Wo{q2t*W7 zj<1|dB6#Xphsax4i2}+ktn?UC#+{Ykjh|7ye~EV(=FV6NA0!DOTLddr(@>wY(g(1q z55h%brO7mvAn2t{vOSmb+%ad#H^5B!Yk{W0EQOgUo_e2~N^?%`_vB+D~RE998XAuczQx>@grxVJ*r1OZ;c@~^{T9PkHQZ7CzP>7_3 z;**F#cZ#Qsew-Q3#HNBb0eNe&sdaGCnC!P{m<(Y~&twwJrc5@3Octgf zj&oUTl@Wr8YqXH0QJl6Ee`BHTe;}&dY5QOJ8P)r9yu+v=Hl^+TNZYG<42Hg{m}#tqHW+6MMN-v1unLY8jA0@Ca@@#w zC;UqMjOtyDcNikV2rpwstc1T#5Pl#Ht@z5Z37gss7me^6(^Q5qrzgAwvnk7^8P$6O-eFJ(;{|+>G{MWn+qb15 zALoUqVNa2xj*ucundO_z_6`Agj5iE%aRC|Qg8Dt<=wo{o1I9LUHoqXn%~!3|<6IGl!JocvG4rp|+lM*dow$`I!CG*F;-WW;2IOPX%!L(5R7UiA8Hu%%=Gpct8?}~U)4NUkTY2fb@ly9UV7N>j} zoAThIQU0ZADnpplQ(l7El=6p>@|dM0CEblVSJ=P~oNSt;J_*PgCpl$bv5WGGefSyG`vBfO6E7;s@j(*F4+xUKI}MdM$)Ar+Jq#C(+lYiz%l4l}+mV&j7(V&5u={lhf$;lzF%oB9}BG-7{0O=SpkdSXj3n-crQ zIMC$@Ld_hT#Hwyfmtv&1GQ?A+e~}c8bHY~;c@|Fiobt|L*nb&6qk6xJcbMRXaRNR_ z;)L4-CoH%aDC%av`8GE71Y9&un3JM1f1aQh#2+#Sla-kq-Xy4TZixF;`lmt!5XRrp zvClI8E*=&blu={!jF1E|iOB(i5IGkIBiUy^IMSH{vbxU`$3R^Q|98*uE~9_ysm)#w zJlf;+(iP8V_Ey5Jbn;t6Pw50^Z!O)gqwD2x9b4qBrym>Wx)H8kKVCM$x5d@J73ei!ZriA@RI3J{iKwATtdBU<--EzgOE zwjbY+?7~AsfNxHZJX3j|Tk+!*3u8<-4=sW82Ze z4zc5>++DjvSM@LpM7I~uyRvxy^sq!oESR3XVYqmv4svU7ai3nX_Y8bS zk=1x`?<2sMrjB{9vb}H+`6wR)G29!WHp*skQi$LZq?V{rR*NO!Gl9D8m)FCk@+yMB=n#biYflSn1UgonrnXKxY7a9Gm=IW@JLM4l~5kaOUh2 zS$hfsJdRo@CFjprDTe1y>*#3B%<(C`Vg=8by$SQ*jBR2uxZ$*DPU&Ktzge~$e-0ct zP;K~21x7X%!kIx}s^On0-t@*_j9s>;-YAO2U`#rh8~Whil4d2SRY$^dTn55al8f<3n1{(V0m)zuF{e4jVN21n5rM4lsw@J zO1?8*o+#G`RC3JyTb3^`^lmADl?ik`Vb7Dib^`HQaddPNP{i5N zKRK*l02iC0^w(@kI`b0ewZGe63|!v}SS4uu6A?J-EB!VnGm6r^Ngd#HY?x%ulXVdM zj*Rx*Gv&(YFC_dLkULM{G$4nV^@E2Dk<0a7G@IMI{RN0ffyD&~f(rt>k`U-!f^Wr& z5OnfX>SQ>~^ekMr_QIsq{rlZ{!cwLfz*Ir-s^aNKT%J6#7#vhZuO=oMjQo2WAHO8BS9dHyYJ z5-dVO?d)`eM9Q{xi;;f_vFoT9?}Kj=jSUg~?|`E1rvF)D0n_C_D*>B-K@_kTV<^10 zy(p}A0EJ5}g0dBZO+O$6T1zqfy|lgf^E-gQ6PZ3?#hRrU;VSlyVd$;x#n78NfT8ZR zDwY*_?lllz(|^WL{6SEz!f?;SuS6fArIZ%DOMUwf_xin$QT!f)*LwnJ-wgYIpu(@f_ibR)h38iU1U>i}v` zj@$07sI-?P)akDos$SJzR5dz)s;AgDHLOTW^9`XdsUSn-yV{G$w|4-MgTkKDwjCfV zH9FQXk+kitF~0a@d->vHt>+6Dx9rGh>z_R_Jzg(^m^WD(RHZ&}?gYO?ik94nDv)ho z%(Sf|_6A{#bGkZNi<#W#sC$WC?1X@DLtE@>iL#6?Kgd9r=fmzd_%|~59A7zmWNb7_ z%H{OLk4WZ<|wcg_}n$+!_`LgkFnV{JkjuWc#N>?OQ>XLg} zvd%{V41rUG7BET8&OsFLcAYx2SV14}(0qwjUisEebZS9BNZz(n#}*6?2`1pZGR(01 zJJF??ed+t64gco>>0v%MP3w|5A~&=JIN($_w2N5xfN$ddb~|sVR_-a|A&G^N=~}%q z0Ygd*6zSmv1M6^ke7pcr1=VVKv_vO#KnD6EETo0u(pd4Ha-|v{Yo}PP!)VNF*4Q4e0d4v7VPyk1Jvfi`75I}pbJX9Hm0mgx3=c`0tOU0w z1&@32phY}%@dWuY_g8%ai0UtS2OT=P7GyCc40>+WSa}S9+#nbU5hhT z0|TJ+xFZ!KS# zd~6NSXYjWc4cPsyB>q~3w2ItPx^;7HAW8yu;@`_|}U zZ1D~Ow`377J|G;t$q7OPbq;L44vse!!Loh3_H5s^ZO8upf>MCo-3GekD{zvA^G8e7 zV!Z-pr(g{$M0H#pyzP@sZi#%cb9imDUC18c?_C-YKGG7G2Cs7YhJ5{MgLwRK;5!|3 zUUq!n&TVTpZn(T3&)AwMg1FC z!*}pnoe5ttX9n0@;LrP!`;^%2T>!9n7sACXK}Du6sT)LI-v6dI*O}Rcyu7<(IGiVN z6Chdob<2k;zPw-Sa5q~yy1liCrgiDj6!~%+(B%CpT4P{6>E~U!^~;LW_U~sxIZyt6 zCM^8#p9zD}*{yjspDJC+6@Cv2dvS;4q_U(&mDtx`qyJ^?rGHlk=zpeJdbN_TS$V>~tq?=rw)P_LiVh&p z>Zu)ABjQs|(+`CC!lF5F6XNad#osL*z~2d~CS+wfb1A|Uf5q6V)?V~fI)I){ist94 z8d|a0l1d5rxoTpxdSQEM_52RdYL&AlZlzF;s)#NbzGu|11PtJIM@)}tURI9R)`_*AKQz(&vgKK7N`HX_+TkUsEWN~82Vv* zG4%ZoU}&+>M##!&ojHw#2s`Wz!_DkV+p5F;wgb31OKNJG(bbBm=3fxj?8O)g&uK3T zmqPXJR)d3{YS!tdD71gUP^cGUC|uKC6t3t13VVfJeqgh(#rGwf@vV5xSPdcD@mofL z-R-5o)g7QfSIV6cEAE{uAgrhUis5^tz4#vN0KOM18%$Q58VeEL*c*nMXS5eLhdY3q zljBxqD}wAL2}}BGhN?%}i>jA&099-G9%H(VNGm$?)kY}KRs|!=+uBQ(KkWcn`h`@L zWvACloL1CHB+63}Bh=&VCDeyIK&YfBBb)Y_<{LtEQbC5uueTSGU+DlM&oKHRSedy= zaYCP^48z>d+Kag#cK~yXYN4Bk6gd_C@L(JmK+Nzq)hw59bSGhRxMlK=V6A($G zhdDL(cz6=NQ+&f91|@QjX%f_=M@B5qfNhiWd-|9rf+1ZEitKj6#~4 zBY!S9pD4%=9rIkW1~-Xd3VIzxF#Q&qY!bm_fIIZc(YW(Ts4t9Q^3FtWnx$~DxGST`&dKhR{*X(%iw_t z*Lpb8${pmrSc7m0@Os2xBnrj~Vpk{?D!hY%LXk;_LLV_1jkF;6o^LkZnJ_p^u}IW* zI2F<~HyfVuN=pfqX7Ig@Vv!J9z?xWrj2Pg6xb}{)7wa8PJ#6+q+=<@J1;PRiS;I-a z(T0Fa6wmjNEmfE1+gKL?<8d!;QxuP2uy#iAyo7<(Jc=g<5hv`4>@COiD-#;Z#lYBu zfPpha@gyOjMI0cbc;Xz8q4p?>hfjMVibt6nTM)(bUL@G7k&WMncdrTWUJG|ez1Pw8 zQM$gKu5Y00AJO%X@haU{O%XSb!FvI8I8clcH-87^l!%)WP1wyNZbZ2t-X%xG4F;g3 zkGNTKJslYV{>c;<8#_8ed&_2`Pqub^L=iS0*DF>cY%YWjwkN{oWDyq?ooLYTmxxE< zQ3l2c3In|UKIgpkgOI4bTpt{?M%6UJsEPPQe5Wa#27@ahjk(AKk3YuC!_{K-2zuBT zZa4xN%qRN_H-KhS8Z8{GLI`G%P@D=}TfC>Ze*`?$>!A!GR@^qX#W?J{IwOSQUWOSs z3g3AWD^}M!PC|Vy>h_+1PeOJGhf6$!PV!4Mo^p(2VD$Kei$MS~lrK2YDUfhwsBRP{ z5FYuI2m&4K6bhqaf{V`Cfn$|i@a)eEP9mf#et!}noa_af(;N(=pNkjAlL!fm|NBoO zl!xe94s@H*1Bm%G4#;=laVC%9$94~*0%kG=-@=+}EVZ8hTFaHgf=(snm&V`DLv4F%4+ zgVm(*uoN^Da}D!pRNf1~dtHWJEyr@o3h^i9L0fv2eyNw@o4l2pnI-j_px~xUe9` zAxxHdPYX;0_HwI|8P5@QYjsWDwD_TH4Oz|a@J zlx9G&)8U91DoGb^11O9u~w3Pftibi0Me?B8>bm*Qu0;{E=$&vT%UO zb)Vy~9ptCX1j_@obc^$^;83_gq2z>y^aL4Ow=N8;gDyD;$GELpu@pH z!=~rU14E-cBxea7!&IDvmWq^&hMmgjufBcrvU=&>dVisd@Q3HBZKhA~9Gn_xdvKOq zSfl`_hCz0w;IJ@S`{s&dc#O;bCV|Uh$JvQCcw#hvW+7-qDF5)A)&G%%`s0(kOg7`s zJe+(`&WEv1l2{RXT?gh#Yq*RZ?K(;!`#oW0@76)}Cpt2fglsJ>4lo4cvHc*o7zYH$ zzO@vi$yfA_Hk(=U1o#{9>U|kO5at!=Y&-~melX10;u$_=o%wE-&SVe6Z{C?$7`{K; z$%!O>%F|q$sX``+2Nc9!i&;W^!jSy`+>z`#1Uml@RIkf=PQy4l@9Jk%nHK1LiZ+j1 zv64`fFl2bouytB5Ft?-j;DD_qP<^|xHD4}qRvc*s2s7bRhL6kIi;u1j;A63nOljS= z;>1{p@WS3O+-z$vZm#G6Zcb!^j}<$XVuYXAJBFd#+l!%FI)I^tp)6>{j-d!)MtRP# zQfn_(DjmSed?^-NaiSFvb4>6V!^aETi;w4b03RnZ?ZAo^OEEEycohsof6`tIy`l9O zitlZu69_Ecgv|xFRy(wvuczc@c7`Z3_xC|$iTv8oAS#uUIcSY0O~(L!D6?yLdOOq? z*r2=9`L#u-urtFHa3N#`gB>bzZ$mhRd)w!cneeA{Z=-t&bd-2ok@7_^-iZ~2k`YM$ z=^fh+Tve=<;28A&zyq>>C^`|H!Q3|})ralHdhz=5z2(WF9`+fQ?%M&Epko>X$siI@1=lDw|By_uzI8_GtV>+rde6`#;jO^R1 zuG@NG*Pc}c+uS2pr9!a|`8|iH>m{&rUu>DDWZ6DZrP18YdnNn?R^v7yB}gt*4qB}1 zfw3{DJKV-dZz3laLe7%lg=XfsA#WZpASSlpA!EGj-5D=WHqBjnbAG*}w%!nTp%wJ6 zK{!&J{QYiivFaul2JqAy=qlGLy&E>H+t|CROW8;G+gKINtn))U8bYbkGNXH+hBgw< zF^|micR=+pJ&oeBdV083F@?$Yr%hWNGY3LJh?YS3&6s4$9bA9rRPtuRB-TkHwuIId zhtG5eDgzD)AL%)Qp$$70trvXVc3GJc_D&4r$-5n!4Y*rtXB)h2rH&$mKU7nEZF-`J zoJXNSKios`gIVbLB0k4^J-pTw7^Mq>M|NVL)TP&^z-Vi7_pbeW<%lhGUkBVj*}H0a zVI*9rgP|Q;tmXbPbX9&LC-=5C}q|f?zv4E@#Y9UkfQiJYs|5D~wfB4T?N6 z#y{%K`PI(K7!lej*?C;TSe7JVOxF+gZpb5C{F~nYRtgv2gX&>yRp6g0H8qnVevtvH zXTUd!B2OelNT^(ehxDiR`65uJ@2{5o3nIB?p!o}k$#$Pb3G;(ZsJ zwaO2lA)3hPzXdi~lnyuog>;}`+3E=7ARTN&cu6|gj&~#-&|Pb# zgAh-K0KueP4ozU<26cfF#p>P+CDOubw)KLrbYqB)eIYvNt`+DYe?8_}9iL3Py_bNp z=|43LX+p~zgf|KIN?XVz6gRm_1rE81!A@60d$Fl5<{Fzma`J+>XYlAW+OXlQnOXn~ zGwnlp?i{R_XQQ}?Bnfp9J}qaE@guM7r|T6fNI1D20xg|ic7eq|IKo52mzWE~Ev0{` zQpDsXZ0M1HS4L4RYO0x|a8%MBn0dp2v2wr;6cbo1Pr_NUlfrixjCha>z5tPyQZREw#Pt*@T3-~&3RG!^kuEhP72#j2XgDcBAc z6gt)RXpCCjltUuaz=C^GY_^GB_C<9Wl`7sPK7JkimB*uII_YT`*CpEHp8UrN4Cc8C z*?*Q$nQg*!uy!J>)&HTgt zqvY{THlW%2Ac7F+9hz_QqG-7BE~+nBmp+}POW8e?n|JAV(L?zOcO<)bDE|vo@20(I zV>|Lt{u)(wEIpKe*>LNQ&+l+(heTmCqeb?<{su^ zY{QAM5aETrVYs=py|}rg1GtH~7u&F7DMt8-y<-@W>Pl;;d9 zx3w25H+KLlngg;n#{|B}0n)@A6Fg=3sJ0g$lO4c^#q~Ij6-zNOjuJeSU(j9*J=A&( z#SKEW)a#A+*AQav;RJ{u7b94YW z+p2DWD6aS^BdEep`EQV=@MqwsjQ5(UUXl2P+4?nDL1WY} zAYmM64#%#Jo}a+VRgYqWqvt0R0I(>^xtxeU2JN}YN1PFv6Y&?JGIvK$Via;BCgve0 z;si&}W37t|Hbq8pvp7iBkNi2FL{h7Uw)f!!mG$G!rJJ_4$~c*;CbqWzkO9q2X%>bx z8f4<=IX=j&k)%ETs~fiMz5c3Qdv<6pCDCf2ScRAyYmaqeR=((y^&5?$ypKdde`At| zi4mx<31Vq3!GY|mY$_cRnYY@^=6o_ju24;o^k z_&`#|{|IrkqHzA#q{3|OBL<%L&ckK{zSG*72X9*}eUh9>fpWfaE+IdXJE2`)H5G$X ziI{d9fj7z1p@=4;D!mbF|3d7Zx=yF|CfT~JGBI49jBO^?f)w#J*ieL>M%-UKT&|Dd zUSzRaEgr#$0+IJ7w#V3l`WU~ISkE}W*oJkgO~nORu`25fvzFW>P)VW4ca;-_z;42W z&c3VnA-v?BazEaYcM9FL!X1NFVDeoJ@zg%w)ysG8+PD8e21(=6RFVeOo?6aW?=EME z1~Nz)Co58hti&c`%w_L|SF3!+#>*=i7pEF8dE|>n^yd8gj*)z!kiqESI&*b)>EbcH zpRJTG-U8KUkS^Yv0V)USLPF&#U3?+~R1VUGgi1&ktGRT6@1k{(bHBFgXOk`r9Phmu zo3%<8FM_x2lP(N%2+0;tLaSW1kkdsVS$r1?Xp)7}6Cqi=6uXv5vgo?0Rw~rTN`-^v zYOOA$1(9RXn&p15^&;frLtk2Wz-^fbVR~-y-qA!0=uVHft3RPKUSc6A$$HgQSDI zpiwRzi0LB`4#wfVCLAdJ5W>My>{vLN0EebFJ6sY72jj)`vO(I9*o0SOFs7RDQtbwK zXJW;wXfVZE$|)Lf)C$o+!G9}6gBKvYBpSRB??^PDyVi;ZA)fMvxA1*fff8l2wi!yA zg}1yaM8~T`bkJQZ&_V9qO~PBA0sG88*w6E*RgD zKF9@vZSG*vHgI;-M6n*g!L~=BEDvzuW!V^hD-tA}XL66>D7fX#dc{g`%URI*mhY}n zaEr`s9~~VgBUc0t8veQF-1qXeDX7KJ6MrP5pe34V7SJMr31!;&*6@bd)^KflYDyd* zcGJFH5Zy8{RhcYJ)*-fKq%w+eE26@DnpAmNhU%pc8^p&W$NR;zghM-l+5NF7WZ@u!%Y*n)uxdMETbQW^&%R{7FJ(Hrs`R zJdChfmqw$c6Zxh|2{6iv|D+D9?{#37379pMqP5_Yc*;u2}2%oYc`n2}qfX4Lg=%grC?uhM}YF#nAIQfFUJf#D*P15yFh}oMGjU+l!S)JAjpz z2AjOEz4&-f2k>EuB8ktumSSQYB?Oy%p}iRTOzSa}&0K8>Hfb)nwK~}3JX^4dklUj` zlQRHy+`nHcB~hS>0s2t2*Ur1eyE>@9<|3WP~pOtVTbrRzZ^`wT%QMv(gkh33$rRQR*k+7%@&GG&dLf;=U3q4M@PkXlsiTp=urp*=U5owGO#VL2Nra}Qx5Hlz?1VoeHRxg;IlwM6E} zLd6%O0$B{k0?prA3VbL2bB&BzjVz!_fpHZ3RkV#&EPic-?*oWbY-{BnGoqHkv4a_g!KapQROGups;pNLBSswBT3bJfKBZm~xviGGC8 z$!VxtGX%~L;Aaz6_>}2H&v0kDJbpii_2x3CyOoHAqkb}?-{|hMH!d=Ci*^R_Xvl#s ziQ29nxh)09XAEpUh{@{9mC1sj5IpOv9vnfI+>#^j{)=^7h4QOyK5*CocmY%obE0eH z((5un<={Ldp>lN|dMpD}?zkd(qvZ_3#v}IMCOf#Sj+(JI+N?2*LGLIw8|*A-?c5D- zTc{k78YE(%v^kBukUk0R`N7VGA5L6>6Vj*PwWc{KJrFWt9lI1tVF{X(CKhZSf>BL_MyQr?5W%P#v-Pj z_?vQ68>&3Sf(rupxH|JC*5m8~gg*!8x`rP$t2=Q;>vU?^2oNzz0k0TvB6|osdx;Bs)R2-7H)aKQ&VpT-`3~R|vkCe4XfoObm z5ZFy70Rg*%i}~Dj&;jxzn}>JgM@Dz8aGWABi~`X@Jhjio90klZ8#i38g`!CjL@fJm z0w&hiCIOSG&L?1sDr_$0I3ueigd!e3WeZvXX&+9*e0*4>m^=dJxq5S*7BD09XB058 zf;0jqmdhhxuF-MTN&#~PRG&e>+?oL@2LV$;b2yfGMF$DPTG>2pf;sl5IS? ztXByFreO?veb}s3z&sP)25WZ8vuKm7?`8p0j7t(QC!jqpVA9J#z?_8Fnt-YFKu85= zW0%62&0WC6CLKf{EWRa$fSIk@P^O9mOhO6cog=KrspfLC`B4=xsTo%RlRlCpiUiDQ zq+31#6D!^lBEuwLQquvm%I*mPQ@*hXm`5X~(gaKixKY5wcM+R$q`M4QO~5=0D^>-} zDr+gHfXPRP5HOV?WOY4s5HKG@cuBx~8{UzCNq4OkFhe}$4OHNJc>*QMhF>$3Gz(OC zZ-|cfh3KHWR-l7ie_5bH>s{cA-2%|Snp;t$vls*u>q^zj}U}FVAHl37KY3pu9dWSDbHDl zex0R5**%V%cj%ZouKX4-!M9)K!W=oS7@!ZSudVo>g8Bk!qy?h$*kxpx^$<+qxN_d* zaECtw#}&NSq+^9$gmnB5SV1^NB}m7*P9t_4#fYq+gNn$)}-$*W4u1$+>)8!&p@%ixl&g%Jp6u2GT` zvFO0TzK04d+$|p7mi8ky%kE>KaL%`|o^b(=clwypOv7(`oCr3`J)G|4$yQzv0pKJp zIGTB+Fj1e>A)DFHN8EceK;>Yzmr%Ky?LUzLDuN0$i_D&LS@2RRGB3z zqWKi@WEWR5a`D5g^{RZCU8w6cKl~;K<|T7|2kGaHm~LRQ5bldXx@rG3t&?E%lpQ+>7CT}~ zb)ghwn*!jOZj?F^)YC+Rg(Aw2s4W#oMk-ax2U4#Ta(GfH4qCLrJ~go+zQ%1x7>b>D z_qs9x8jECP)b`rt?uFROxf@3=w4vM)+l`xD9$gjp^pZYR%;78U>2(9b<-G_E65&SN z!-8KW$ix_NN3SH}Yoj({v64+kaSIh3B&tPW9V4uLO*O4vvi8W)iw{9F;+Vu(SzR#XH)Bqq|n@I+1QnUS1)R+UMnk769DBZI=arwuenQnvM?(0D(t* z=oXg1EdYeTNFzFS766|OA}%<L2mfmD#3R2Q>m=wGKq%oE-_Na==IK-4E-q9s>(N z#7$NUfGDCWLnwC8Q>GC8ncksLT(TfPj|IShKkuyw!trAP_^>-hTr2?Zhw3v}06voe zDhCUIgv!+d@bwH(ISgG1RZA@Z|B(S?lPu6_jqeAU`;Fl zhR%dbn#T6e1_o}A1z-Rfi!1;;;7+puP*0>!Y|H|HuS^yIWuX)r)$`a~2CGUdEdU5b zE)QB~3&8aWL(yUZ$OdGn^b&{^iACgKlF>~G&^S#DZSu!OY~{27V5hDAxL^TTooE3d zlohpDuM)y#wg5ea^0PrCwEC9+lwJIKIEdUQ8 zuw(&vKHiZ9fbLpr0SJ+l*A16@CJB5f?n}+^(aa6E5u)Q2Av)-;73k32aN~^E?R^wd z24QkvmM{DuIXl{Ng_~0W2l=^UF_VJ9#_kpq{M9``b1t03Qe~&l6TU2-Cw#nItKTsw zU=N^S+h_0v&lZkf%!qx#=FB%CQ8>Ke((5v3%3&7e4F6-jVg(Tem!Rsu zz5JFAtAB4sZ#b1Fn`DVmi$;8v;Ol=*0{?T_J+UO4S7vT>UYhcF{Top2%|H-BLucG? zYmtf?)o`o6U|m|0rAyiU{+o9x?!7hK$+;u$78djPiW?DQuSq8{IfPy8j${{W+yzj* zn+l?taUyHnQ>n6JnQ45Wz1Z5=0c?dS!vk43&N*5E;+^m*8=^O5#m6h=&Vo#*@MoOk zrF^^tokPe!?8XithUE;mA;(yV5X9avBu!*RQaap}JAj*5zHl3MEX4>vv3CqZ&ucG+ zp49;iDS5+f*fA6#%qY(pRvv9HR$ko!th6-c_29~Y0<`P`1w|SP?QjRM+L6mp=6u@7T%^gD*Li2!ztFME; z;=Np{I}R;i=8j-lkaaE5aF@<_Q3kp=T1(BN>fI@vhteG8p1i8(2H zlo*zxM^`xVO5lqeg_$06qk$Mg$c8X*Xxi5@l{@jMYo_wPIQJPcm9OkDxAnA=+xlC^ zZAqERyAVaHO;%7;o5)@E`?NZL#U?A@m$pph|Nz!;iQ}?mA z>51W~A-?5%G-P1!ziQvsZM%0I*ssMFD?)~1H)p9N`x55DXxZ!wnlRejc|XbK?r%y; zn{9?GYJ`S_o1^e)CSc|Is3$RB5cY>Hq0wW;r-$A7G>?yHO>fSB*0Hiu$B1G~Iyq{R zJh~Mk%k<^}(jooiq0(fjTC7*p{N@n_uMXb!4O3R+dM!^T$`|PP3`J&()Z>zZ=pm>c zCRHt@bs!YoXnmeJz-6&lWq``Tp;bcV>d^X@3{W}j=18arA)VnGHjuG-oBZpt=0=L9 zRC6K+dBfoKo`=l_`yN_56Y#dxN*bwSA_=;AVkE!3k3q}6y1U{>6JU_7^5alO)8&*7 ziIr{&dl)Jf3A&snd+fidRw@Leya3U6)zVb8RKqj6aRMon>!pbrorh2;-CLZPf(`hg zp@Wsm?RO5WTD|5HakqBe{5Q=3kH+JR!F~HL)`s zkS`?wVw=fKzPgg2A4LU;%;(rcw_R3QMJRK56@*O{Wk1D$byEXn?Mk2-t4z36DO_lU z-67%QPq7K|H2Y7yBTqBBYlUkSiAW;W3@b-GwJ+9e{kFZ=U%xerG#Vl>KUY}Ghn6HqLi-1zXfjJiDH-vYfk|AAvB z{waho%6?BzDf>}94uaoEWn!Y3N9sFYM`J6czH^}Z3{qcj2B;jQJ_(hp)VC=ER1Q*~ zgo>oTcJm7xx!AC6}0F{F@C!unc=02YRDhFv!LPgSC zCwPX9VQf4SKlm7Kkwj-0x89#)v%$#G+Ic0sZKFhIoDfN-`w=wEWx8Q~N~04f}T7uw(0iEOxw}bdsQGAhjU4F@qsb zHjzONJVlWMgIa82;5=SHjLP64TR<*HrU+*`J{4HTULGNEwcecn%wr}523QJKGED{? zN+|=1iX22h*wrZ&>v`;XyL3#pQUcro)n||ZZ^;0ag9Ip{a+Lr}8K82I03}o;0k)rG z*zm=sZNpcS%d%PY3`5r2j?D(6Mr)@B-nLQxGfjjf{yhiU<>Fs3& zxTS0cPOL9WrM)j+jyL{DLgSVNCrMI^ggxw)RbWc0A`?u&0gwgjq)0#^yfn0ws!LytQ_Tl4jXKJ`|$k z!y!88t`+E@$oftk(zh`Z{6a@C`*D4W0TMC?q;qEst2K(gElMG9hM^msKg{o|$Oz%w z9-I4I<%(}5RA!sY9OMdw)j9->Gg`vN+?RA%kDV7~#BiY$;l&U5OAO^_ZmNkTnYi@d zIue=*&3S_U4LJAy3qc4(C+(;|#XC*Gks8)wEWtWCd%(`(7Ou>r(lzhou?-@d3+Uis zG;$e=&ImAcA!G|}eft~`u+`FSa1bEEDuT!^!aMvK1d-vrCb}xjBt+LQFa}Q$UG*Tc zoCg6eM}Tb;Yo3Du*I>o!2nY_lV@$s;p?NFQe-_-%{8>{+8hGAHuQ+eToO@kjK9V+9 zAvuOEH5=z<&VwwJ>k6pMJ(P=BghIK9ZJxl+1h|p#MiE-a%wb-c##G4~*~M*blU<6W z^&64oYMqzhgOCM*`Qw2-7g`PnM43r=)`kaG2$d$y2aFAGWgu|z!i8Dlojs10YBAAh zxNc7@&#u4~+Hg*QBIzny?IFKu2M4ZCWdsht4`VHiLNV_@5!!#ju`*;DV5WhAw)pg} zqSqJ%^biT%;Dvs$d@r56)`OM}x+~mQ*i)G-6$a?vu{(d@{)A!YoWbjP36kE?Kb-+8hv6=viqkUJDRuvn0c2C$iz%crY15^$JQ$poBFwe^XmBYZ4P{jx4A~*t1iZuZ-yW=TLnjR~7II8b<|A z$KIkM)W+H-nlu%2vQ=iuAJ<$>YU$BTUv?*kk#RdM_I?rIwu`-~$QT{X)Ewu>bi2hr zH_3|B?677-=R!4KbPW%54vZ~v`*w;CnErACpdx}To&I8C@VI^3 zo5oJ7#{7k>CAZ-tYmd?;aFi0*+@7N`mry08pGnhmd6yxu~FIdFAG zTwRa>DtBBt+tycP0LzJE?*~&wJ51|>47R1feeQJS{aqOl=Ri+6OT7xP=VC;^B?DA% zf;P;CV9ko2aYip?fXW?L*{tZb46uE~im_CtbAd%0>zYPaQz<4}Wfs$Ub1kT)rt_C) zpnwTUotA1}3~;;I{xmX1rt{`FKendxv#o}qW_EK!&q5VmW81YLh_ume{$6A?vYY=c z+*$1A(hdr*`iUWS<5fS z4y)GkkF%ECMvP`H=jasHas}sByINXn`8N?*vX*}f@5owCcdfOShe&Flwfq{H>8Azu z^2;6V<+A0}7W1RW-eMkroWW*(wP}I~kbhiT&40;8CfDDbt>&|~!gy()GKjERM|V2Y zPn7xp=X%He8UetQOxj|VN|7UCP5HO;}!A&{y`+}ZrnFD9ru zV>^Fl2Ff|$BN@8uKq(28#??)1=by^}l>=92#ML)4K;@1rXWRJ?Gl1p9vF);*3o_W20{6Mo zmG|df)mBwO&Qh+n^V2dwU|MG_+Mf?|A9NYT#V=6h3YdH&;KU_R1Ve*36-<oRoq6G%Xq#t z1IWjNnsFMyZ5Ngt3>^Zg*)&Bde?@BNw*@y}c?tLJYfDm>O&KWXfS2`zVCQU0yD~uK zFfb)lt^@Oy3{W|&z!IwXz-)=}yqp2_<6(f71pl~F>i!Jfb)b}l%GG%O!VFM3aCJsp zy*dL_?znO`p8shEu$(xyUB+`k2HR5LK6kqE{zoz(&VinCmU1- zwI&EPGDgPp<~TpL#`CAxjYG{m&kbD*b$E?$-wr}~8*S$+k=Mv}z5(tmw)4Oe5tz=6 z`D&zL%wRcJ3G`&wGd`7H=6SQfe!tQq&Om7%T{JjS&)rn%g zccL;nJzi>*Jcc#=WRO1Tqfh$qlR@!GL4H#7j?SJjTiH~#r|*Y04z)Jl`}@?>c|fQ03lgVHk+OS54-jb!0) zhBK_iN@_GUOUAkzKoJ=*p=mrF|Jg5KnE(ThkFQ~Jr5F=oKvxa}3DA8*xFm~CV zdZQ@Gxyjla|4_yqn*fr&sU!VKXS@dG8sUaa{KSa^2gb@Z$pi(+3kW<>E7ZqIh5Z48 zAoKPV4v&>b#tI{q$$GIoSt}IB#|y=KiskX*@OY^ZG*h62g7IacJxwqce7Vjkc~~$y z!sBIFvAU9Qo@@sT&H;;{e_4qBZaVb^PVBaEBOIb;d({`zV%$RHU5Ra6r9YLy3mWMr z>h}~TixZ{Vz~;$Hy>O^}Pib;XPvKI*7(J5F1~9#APvP$A;y4zTKkG-Pg4-ITV66|V z>M0CYrYA>>)gx47d5}A_TRR7L_3fLN)l2u*`wLx!uP$hGbC`^@HdP!c^%ue-g|01I zVA2))KiwiZuUv*0TfHZNt(-$+KA2FMZJKmYLlIW%Qfr)VHGLoojd`~Yt3TDDxhi5> zIq+bR#gAS)%QErCTsiE;7@5DQ_qN&Wk>}7g19H7DAPC_$Uw3R%U_mg%0-hBt8$D*- z`Bs+htc51Mb#O5sFQxHH7nY}_y3M;2KZ;_wlQTtpgJrHrdK<_)aYKCUH658OpD`r= z+#Sg-d!7FY)w`)F8igVw&5x)uEl%SUZK4j@D~^?fqJ$yCdxou(b^y0Hiii$I)J0Hz zyRkK2u3=UjX$1%~;Zuf>OWKQ%3p;?1#XAG> zq4whA*&V>giA?;rV#QKSj3ZtJ!_e#7i=o%F9z${C6t_5WV^Sm#STHh<=6aEZN#Kn7Q)QUXY6-i&n&+o(vLfHtE9b0Y~{Y2cGuPW9`wf;gs zn1M*`?H_u;0(9SCphIjg){EDd?=4Rb^{@|-5`8=1G87CnsTt3gt?=_$KA$jn;>QvB z>oYR6$W~vS#}zd{vY4X=I_* z>ii5gqRyvrllStilLZ8_P&w#i$9DLRi5bh>8N+C=i+BClS>(iU)DYeB-54^3uibXd z)_wbT94K_#rmkRRD-`SXYI%6NUILqV)6#viUZZWC_l*X#zb?&AOK80et0#uX=%n-} z^^=1hMU@1$>bPlee$WdxJ%vvhBVOaqh z=&lwI4|F~8x<|TtV5-1P+|hxq>H5J90~haDeeuR^7jInCrR+wydhgw?VAXrXMN& z5X;O~?3lWq+w>zZzR*ACz*wnPDio_F+R=s+2}eNB1P2Zp(1oEP7}32OhK352k$S0K zD}a|$6+S@6h(m>9VPvc{au=L^cUKSWzK)hhiuAlbR;*KX)zaP5rCPmE9I3-T=J=69 zxwa^(QZ^E9NJ(AlykwBLMENM|Ip?Ifi0Us4+YXf`V(PinNnY`r6DqdNKPHbtNxYAS z9vcX8AfaE|I<#`=+lH3E=>%F91`A4G`d(?n*+oFU5__cz-LGNYbkk8K#iN7E_~;}a zZ88-J*roH=!cb%b_bC&LjqUNiitv&@+&|$R`NPp&D;&T`(4(`W^{d*n7 z*o&G8y?sz;Y7uson+S_lXAoac2*p>bz$UuRR^AGwo}RG9^km3(aL$p))a$H>9Y7%6PgwKx?yTm;uy zP<;l$_4Eu-IS8&2Dp$ev!VFM32(A(;TH{;55^U6A-I2(}$?UQgC5W(wk><_BX00OZ z4`6JzON5QhSR}q)3DBtGD@{&;=(-hNYND$GzYtyjolPge*=a@BTPv``K%SZ4oOu`} z&f#k1aII8@UuAH;tW6J3l<7rVe?syaRP9Wr> zG$WnE<<#|4^;v><|0F(%@TMN>1PV^#(-w!osk7PW{HjiLa!bDXHwRMEPL7Xt0u85| zR*)Q>J3(E2IAbpemL*>O2RhNsnK8RW5*NG3f^y-BHtv3i!jWp1*ulD&(=Ne9FJYHZ z156UM-y5)$_!vMAP5qe9mrzk=aUBLuh z<1>Qxmg#H%4-p=k$hp3jK{$*e@P46JtVH0ggbucR&zBC_E$^sFQa zua~Z~@WD#BmD{ju=qa+@9&at(ucPbba2;FZt*0Lw=(-WEUO!$o!R29ZGhGMZy2sl> z*DL6HC0uvU@=k|3chB{<;;*^hRrG2bUAM#aVee#kKepA|0YAK*c)1!c*WhJW`0QG| z+l`m&@Nzv~&cY8b^7g>}p0TBSyuEM(E`f94u{RelH{cuZM!N2!>wdZ(pzBR^y_v4J zz*S)JR{H%k{Cyi<&VY&@_HKvU-7~#A;NSHpcX=nk!#&<2Y-2HA?!=N$$IB9Wb0R)G z2`_{A;exTfN4+6@UBt`T@Zw?bOnki*FT?QgsCNq79`#1x{$cM_x}S$H=i_Ao{ay&y zhrQG2{*_>yKqL7ml;7i(;0nQXhv47+4X-Tz-6j4_h<_FO*X>;dgUq`CFBRm)alG8V z0xq}W<&CT1@&>%T9wM&2*W%?zYvJ-kygafFE-%GP1sx{G@$%m|J^d$M&c#a4hRd{f zx6;^AYUn66a+Df4N|hg_iXWy*AEpYAQe{V}qNCH^bD*Qh&jc(5ViT}WLx>63D&D;W zFF#!r@^Kly3WKn{XURISEOJPoQF&%l%SD6STChG>a0J z#e}IJIE})(sDt5}0@QvxcJ|$P+13Y_U3mEnUj7j;M7O6S8J~fdv`E3i8If{VMx=~R z3sYFB)(kIENsb!oriz+ZVV57p%e+-^IRP&(!pkFgIUQO0DR?24ely;E6fbF!goQIA zX(S_(M4EzT2oj|@a;SSMa=wXOeG)Hs<2XJXj_B{=-I+L|&ke`+3-In!c=;?|CN76d z4KKH>hs%w4c{W}i#>+U)5C`!>vjOFDz+?@n5sQU0B6cDpVwEHi&9JK! zCdBb5g$_-#B!;7$of^ehI3tQXn;apW_po;=axrqiqgVrUqVdT02KOR7+QPs!$0Jb_ zCCJoh!NM8Q^7M?HH#k_HEY}AIo3I^cH7-O?4^Mk_v83N4{@n}zU~T&Y@$WwI?*Z}e zLGka|;@@-OAK>_T_-}^y5d8Cw!UaSI6qk0-sy(lcNr1s`YC&To@Yt z#s2e(W?w$>;Ol~KpLp=mn5D!=1_(JPw-!d05?YFnLd9;AA3l&l3jSR(tbV9LW%!={JkXRqZ zJ7(?4WyScoUa`M9%`A%EGGVA%pMbruTC2-B5>#fZfk(^0v}ix<*^-GTX4+9-FnoMX z2Rk%iPI=6bW#-6%D@Pj3~dF5&w$O;b%I!T0@7Q=oKpnSpeMC9_!jA0ym0v4IaSg zmDmW7(eN)81tV*lxtuB6m7#C`beb_&tB!<2ZiQ%Xg`jN!mtBA{gBQ$>nt$+ZYVNBr zwH10c3=M53cG@eL2|X*ui#6$E03{EW4^4wh0{ItIrt4GFb>X!j0M(rd&bGG1cX&?T z1*4E=YJCdSTnA3kpyb?sBI^Th=&Xc>GR!TJ2Qc;k7?<3VE>49t4ww@L77Yyr80TG| zCm!>vFYQF1fuUdyf9D@Dar&N;TzDN2Jb2z zi5C!GmL{g^M+Q-0kKXSDPbEllMq2!M8Qit{!5ga%HLqUT6L>B47vk~Sfyr*0aEyZD z@~-cu13Nc_9}WilS|Pl$xsl4mL^1vlCU*p&RP8U+>ea%1g$F<#057h-8^G(TRGqvX zp56&fbzK6!qod%LH5S0St_MWAYH^|j#h`y-FYYTG9It@C)j$E=O5vkG<%0glyA-|a z3-zlSd>Q@d+qU=mt9I?#0f82WCM(s_AVgMFj|>LKK1qtm9s&|eRd`h&gc#0JwLCJ2 z5gYX~2Ey}_0C}wxqsoEmG!O;)TOPp*#>WT8z~v1zphNMm1?d500kXCMtufupfavtyOff?&s+>g8}1#sy`wSam>bk-I(9N`XP~ zL-`W2+9^S4alhgAq{zD^VN!KYkvEu7nQc{aaG6C|^-Z^=SvSFfb-xa)|D0nY;KU|Q zxhTK_aK%Yf9OO*n@J6KIm#HoqKV{Dp4*o~6T0!*Nxt8Rf*Zlx zTo7w@cDybjKKec?nk+uxba4OB~O7;u0 z4N90Z12znUf?@k$eez1ftzdmolg6C{-g9DFf4ez3MhZC9)@Z<@b4>blZ)dSiv&w9_ zGZrcRW2=Yyg4wYyxmKM!_%OAMr97E5F4UXzUwj;xM;UfQV`1D@J_k1v0v)Ye&!pBL zypvN%Kc5me>YWdTE(@+bhlCXCpn701*Mt;TXMoDVx-OxL$wHBv9!<6av5YZq$^e!r zQ;;fhjEzR}21%gwQaAyE7aUR7Uks_HYg46>^1<>*zGx161y~5(9*&$_5Am9Z7wB=I#{tY3-Z~K(#|vq@gDA3MMRzl%VAu0D>Re zy7ATZFG$w%PADixZ=_o)gG&fQ=QA_|@7i=r&5vluesC?WSHNoscbCCg2<}J8e+crC z)ZsBC55yEFkeLK>2v#OBD+_uV1&IjDli)xUx*`Wz*JY)AWqA(+lJi1bwe%MR00pyz zSgqzDl)TyxCRA%%uuOBXCTJtPfJ$QRB{95k5L|mEa2o3wKIGMYt`j{wzZq%Scuwl6 zHqIOr4DUSbtEw;l1?#+gg_f2s!!D z(Q-{9KV|w0@q}V}dsLolg?z5~1?A9uwq($Jl$KK~K)drQKx(5I^q})idJwDArVgE= zp_@+(hWBhpF5YclVlDGu9_47h-kkr6<3~ASD7VX>`E;c7bR4u&M|uiW52M>v((B0p zm4l=wp>o!d`ZIuKTAw?vBZ&@MRtBTlEI~&y3>)uk#Eg|k=aSE0Fc-KhNw;Rey8}BM zfa-xsU6rJR8K81dk|b2FL#LhrDtBCwBq_fooSDonEk{GQy2(CR#sULo#6Foa?hK*g>6qeLQZEA5*3}<5}RmJd?tk*deLp})z z#ZZ|ktec{-Hwk75 z)(Q6=u`}Fh;Iboj3RIs#+gp|aDhH8OLY1uT&EF;>z4&UkDg$Ks6u!uj3(v-@^+|5& z3&6|0T_&*MvW_LFf`&onos2lM^7gVp*^}`6)9xV0IUViQyCKiP2zxWo%Yl=2L-iRH z#XB=V<)A1^s9Y7ryD~uKjw_OuQxTml7TBjYtC3B4R~sY0fF-5PYNTxeCgt%cAVpIi z!^JjG8D9XUG?h^qltN|ve{6YlQ5i2k0DERQEr}Bjg3*f#(KH zB0|bv9u7)Dy>kk|*ZNbF(5sYUl|bBpd#n;B&I^NcdQQl(9pKRJ%-K+cpV z5A8J@jE}P+!mT-$!I($9|FGVi-#CuMdj;QCStzG_+n03|v~ug_i%@+AVgAVsP&tSd z5~^fj-r(N$pBcc)C&{ggYRvm>J2 z7cCdZVULDR$`&V*(e@3B=$I?GR)Dj+=$x*~_-J7lCUTi9)ptOWPDuJvE!+d=n^EpI zJh68I9zpV)yGn58SG__B=rE6GaO{{ky-S?m+gI2+Itp!9CShabNDmc4;P7-XfQ!!Y zrH2BT;-Mn!Cc)`x)e0PB7N`-m;H0zg*x%^97djPf6msBxkkgK1C6eZ@t_7O2M zg&C?pbX*&KS{N-KJXoq?OOfsb2d2gS4WF7wQ*NEwmoQ*8FGM`&22V~We&CYbg5U+O z{&>^>E&r4YLui@};fq&;kHLEIjHETo_J(yz#b;mp8Vy zSLTW3DfUS`M>q2whWA&U==hbnS0tv_Cvkx$ttDtBQW%PiZ10cs4#AUq8FpZSh=?1k36qoZL~kr(C3EcxWhYuz-&$lu5L2(XN998FN$` z6_QFg-z(^&LtckVg$g9xqq9@1l?kdF(%wyj%rqK0!a$86$>5o=P#nylaC&Q{P=oVP z;e=DT8ydQ9>w#T+;8<26q+k+3xW|}AO!QZp97SmXLK4O*hlLC=RvNi$qFB8P4|bIS z3W})kcr2b57WW7rAo-@{dBB8ll0*;DVcotG%=n-C5~81+xhxsp~CT z8|S548*kkK=73!jxF8lMA;s-2cqI9e%CubNj)2SxM|Goi8qS*GY8W0i9=-~V*I}8S zMe%Qg#jXPSeYHF~3hjmGpjS(vmxF2_Ci5;rv!G<6I;Bh#2XQ$)JXXdv5+H;9#A&cw z$W?n0+6-VZ9W9MckCaCHz)k_BK;%@X^x2;`F%Cw?We`REzKt zs_0NLwKokpU#n#d2E3<4RtAGUesL@uFaHlgxdlNv%D zEZir{MJr^D939NRPT$dqE}tm7EI2(!e_aVW*@@n*429E_<245YTtt%xJJI>wEu3?5 z;Kh|OUfv1ZTpKV(3uaC>PbE!)Em|8Fnb*b)wMXH#+#)ZWGZeFZE1Wa_66s3L8GnU$ zg2tAL3F#+St2^Tv*LqO+%&IGqWzNu<Fj_h>VxWp%44BSV)?<0 zwUn#|&$bOGv7sT*J<-QZdpE!{i5W^8GfE@Tw18Z3)ZN;uMV`Lh~$5NjEtcl=ZJ#-hSIV}<95 z!a)I{Cj<`}lGnQ<+1m%L6^-mFRiz!_aja{gdXu%L$w^#0GC<{Et&vcB8yVZwQ9m*$0b)e_SbbBtv%{C?%oNyk71L z2qXsF%=VDt5;-z${kn93~Mk>{z(R~oH+LWEikJtgu~>*^X14w+9H;< zsVvTOr>!DWUo~kVI%InVpc5wI_^NV=jGpNa#5=RR7w~nr7oVNNpcB5J%W66Q|6K-> zI^gSZ(M4@kHd$-_PX?$QMx}(xbq4!R2B;iHrGzR@&6A{%FS#Hhd-Cu#C&T^k3|%mB zb^0}@?a6R|Dp<^wm<#vWb(9vU6%s0q@tZ71OEW;_!1x()b#Vr$92j3hmCVnEUU3r(`>DA zROpjqZ&9&oV`bB5Ybp?BtIT_%YsL%-oVPJlcAHxeo`mmIHf@P+_lFrMVM12=b+$FS z-OB-P5J_Dpl*cl3*I|%Is9YD*_hx{~VKL2!t50Nr${knEi|Lm#faS!o?OIF)8L~|p z(l+)Tm;%If)^xhi+W95y|FqdRCYDe>G}n?t%zpvhG>4ebcq_eN{H5kyh~*85f#@)2 z#k?v|^6S{vT>2=D_2^kr1fP{{;EYln9+&4i7a@rvWq-uP5F-_lHc6yu4M+|uYT@+ckRG58YFt7^kxWm;HPpiZt6G323z8j`mOP% z%a-h~kj%oYF6jPChT)uBvYd&;maM{Q)(seWu+==VN7X19E!<;!yi1T?v>)4rceEc% zcdgxz4UyEo{n)EUOXFq8RR&p3x?P;+3&lEYDGpE9ORyPxxyzTZxhY#ry&bzPkC%PW zScc71Z5j*f5^nOkPyNEEbIcm1JZIx;tNXyuv%xi>H|M{o-Fw}bvTnQ<^G6j3teK!CHLKfoN;inxb(MpP(AKx057IG)}pl%a${5=RN;uhMv1~N-|CKN#yex zpmL&z2Wjotre14I6*eM-Ymc-t-pPsZWQOiK6Tw9i*X&{M=>ZA$e(*2x4AOzO7vZ-q z$+NpI=?a+8{fzcsWx$QYr11-=9@buM*fg;VFFF7{c07K>fnpLWSCiLS8K82<6*<}w zQJIvAFxyblDc;lCSr0(9*%D%x|H&3|InYG2g(#AK5EHZ>%4voVWnhWX*Uyj)jGH<= z#rOe8g&8UysO5*J>eV3jr(VZQ(GV5XD^AgvDweC3Q>_czLtZ9?h$BL*Jz|J#V%^JWBjV#t*oc%t*~~_?Ff@SJ%|u5K zUNRH?0p5|Bi0)czCJOP?J~Po4NI4JLfU}#3+|u?@YpKmcInwrthBBCjPK(TPt35FR2Lg#Bgzf@J@l6q46l-v@ z;xKdzT&m!pp~>lq;Zil8NAPSbx;Vox1IpPLUQ@&%0z73#y~`4+&83PVyn!kQgX={{=3Bbp7Ks5mr7}|200Qf2+OaRJK)Cv>8vk_i00Xzrq$OJ%ltu+CJ zcxs;sVB6?47!yZe!K&r31FR2L-BjuOqb5@u1GeYz6$v|-CG!5Pm_| z!H)2u3{W|!L=viGJHjFby^Mc9odLLf=7fvF38w_&FSsFvgjabWx4l82#bvEaus0Zn zo%c4xoR!sQt_lP$_ifmJ%RmzchWXzA&)%EB$#GN%PyDR3SIq*`omNLW{e(cu#462%J}UO+v| z!xAW{SRO*diYyOrW@I+7Jk&3TO;qKBbk3kZ%b?#i2hRsfXnz2oD#%X<$9)x?)FY!W z*?ihlO>%4f#*u^F4r6iv{my7Ed98{|InVB=Fe9(G$g=hc6USJT%})6u*TL-b56?Stc3p z>!U2?=**)vNSxSJatdM_s5o-GI8x3*!hu6MAz$UBd{v|aznwDd7zMvt>`u}6ROUZs zSo1YM&P_%bdg?n#7Blc6SO0#VP;DwV8R84H73}}gtO&){m?VlQjGZunD@w}ENRzOV z^3RM&DU}q?ex#&?cr*(o<;+{40YXVxgm*$o5qH@tDL$QAr=;8jQ9Dir22U*yW;Ul% z9LPK68hE%QD`Tyu&jPJUq18}> zO%}xjttMvtxSNnNS{_ZS)x5%j?gs2|H&kz-)zmGpGSF%yR;F6bTP?6MrWEJHdo73VJ#s!gThAikc8BeLN5 zl97&1T=z0+FC1p%(U^-_v*TfHt*+n%M? zv;?ZR(3;j*U}YfsNvx8!CP7!mmfJ0`N~bgl98!CNsJSL9RD#YFGg#b9kT6;Xowoc6 zZ=E-fy&ABfxdA8Sp?V92>97S>1`3nJ%2Z)`r3F^zv=Ryv_9+`1h;oayrG}iRaQJ*c zs>Rw;!g?sQqqhSJigpxU_&jas9Z*owhC&02w4nuz%m&)ft?!3zUu^S~IM9{^o$9DF zP&_b>0a(Q{>`DTYH0VAB*rA0h5S?dR03XoN;_%oo7IBW|Mh?L1d3G&Qg&eXS-IAoI{+y= zoTCLe_1EbJ5QTl~ynp+lsdC$xpiZrD$mxLN*UH5M5Z7O>>ie|&%*nukF*T zl0^G%HY27qb#n2TOr0SaItx?h?bs{A)VUAugsD^9Wozp6>C`$?=QWTsp#X{8ol0tZ z=T$~wC=s|#8$GYJk3ETkw6J`h&jU`B8g=H+1)7p1z$$OqFdQ?V0@4^l53Atnk4}bo z5`}~`gMji8&4E4-JXdfs-+|IdAw>eLV=5uCw2Hn4st4Rn?K^L_z{`a;p*tGhb1zzb`R$`Ib zlusRDB7r5C@?)lZ_W>l0c6Oby?20Q=81tvx4wajQN4f_5@N2*wrd4I^G{|RtvISNK zV@G0TI@zCRft5L}gfX9bm5mTYTGvzU;ywk=Awa6d=KMxNp0Me!hptg<`idau8TPM) z(u!d}G|Wg1Dl>uu7dM^U`q3R=&#uA|MWsSTW;CmI=OEXb%T#CqjVi-2JhrcYL`c#G~#2b1}H2FHR z!HLXcsVSX;Jg4>bDZRw)4+`V5iQtZQ5KCi(Na6!!axgJM4C7!68zDBaR;DyU@S#jb zh|qY?!U%C6;wy|0ufRKDgb;Vx8XLTRBvHn_=E*k212LADp_HR*@OQV7HFl@*P7dd|Jal% z5LE&H>T^cN*AJAysXyVq=2~Cg`xCHplXyohH(9h2^tPCh<35EX(le{rE^ECP|3?<| zH(-lrp?V9w?PnHP8R%^iD^tB~>OSa**6FwsE7IH4P0;vS2fba~r@(mwAk|{MEoqGu zI@^WNEsD;@)Z9nz__9mjhpN92X9tf+K!vr(V*yANJ-47OdKXU-5YU0 zhIP72So2cqbbPpzP8XUJve4;jh_BG;#_&$)bmA^sozACI>vXzZkj1Y!fO!r|rM#co z&we+}W+UY;4tUdA-fnv>FBY!gNThW0DcLUO>Rx=cI=%1oq~bKg#TQ{y-6L%1v|JN> zy$Y`W#AMI}rAqh?s2&*6RG$5y1y%;Kzr@N|CHzwhwA!H(Hq->E z!6r*xf+iRipHm4PZKu`(SxFIZq@PAeh( z$H{kyb&GYuhWw}UIUvI4f30zE-(mZ7Y#Z&aWE}ysu>wW#c+eC4(^7HEvh!Sq^WASqHzHfi!8%&lJNMbm#AId)u71l4M-nudu?Np+nM~sR35-Ql!pxn^q zyK55#+1XcW+g2a5RT(*6z2M48v;y$r6N0}`#s64@iEbBLQ>l%(v$a-$ovtFIP+#A6 zkv8>uvDvc6z5H!MUQ#af6$ILN5zAr z_C%-Xq+zUx2ajTF!s0=VHLn$u#|$`|puUE2Rj!K$2JA*po+K`tsCOrq=w%hh8U%S0 z`Fhv90q@oi!aTr$b-~f1BS-RsBem-K9NLI-8*(UKcIOI%gY47_|Fv-Pz(?&!oWXAQ;X-YFE_&2g=wTg=9kKV$sjSDNU*Pl3OFO$E z9UBS*epz&LdJmC``C>T_d;g=vq_6U%D&;Zq&aXj|Q%4JW-s_WqZhCLrv313|wW}dx zK(Pe7q=1IC@ln{d-@6t1MfmUT^&cVC_F)t5g&YO7{qTc5>~}@=P;pe)!vmxxPH)q@J_h7BEA8Nnqz*uB?6ny%||F9HPJi{TQl z3@X$=9m@+HG=}=_FA)V#2X&)|{6wTYrtd`Fv4+js54D* zh55yW`Nf6#H)3ISua1o0cft65QLcVbu6|Ljp2TuB6OC?tama#-{NjrH;)*+&S6pt? zJj+~+k9ANfI>{zqCpjHJn0XtO%GUXnHP!=Wf zb*ZN&E`EF!#^LKaC6=(iTugf2k0UUE0olluQMeV zOvk!th%Uv4a`qO?;<-Mz-rHZZzK?83eiE%NQoCo%f}DM~A;KCh)Q!ZP)lby}i8@Ez z-B>YMc?kY2LW_gHApyKryZ_-S1=P3l@16?*!XChmG-QBk>ixqL5Q2 zmEnh26&c3N)+HMi1Xh%=)5D&V&G^7)!Wc*4719qF@&7gL{#(-2_nbAW45^3#^7GI+ zp*gZ{<_Nndp=u4+$F3O)dn3-C^DpWMOKOiYVA3}>M%IN&i`m+uzGkM@_nVKmG^W<4RB-i)NnpW`p|@|oJFV>!@CLqmOs83=O{D`P$APc6`jn=;$32T_AH6MgKgo}dTCj2HLqNEtnkik*1= z3}MO*-?bpS0XKXLss|o5-mq+em4O98Vr5FJ7c8(crxk76RQFdR(k<448gie?<$zR+ zwV;G$k#;HPWAvZ!`sZmri=d#Q`Gf`+X+FmonSpn8-Z(|`*&3tyj6n`z2+4;X$?~Ya z@<^>9l%UAz>9mijIhE%EXo!vzQm8zaCRD2t4PvJ^Mdd+!fslf+=cCHwQH5(Irp+RX za=B*)KIGM|ZAY_mxkeq!q_Cu>s$&e?O-*lGM(z!(JLj_2r&M?N*dTQ$G=Q|8K?8N? zHpG{gnL%WkwXgwRvJVZjc4MA>N`PrGmMWg_=(19+D z(}BVb@dcfzDs+lMZay=_yk|qQ#s*5u6{ArVT>Y_0;UDN$R(U(Gljr65qMs#51ruC((WAr7li08zD4>}WW!UiXiIBwn6KQz5h&lD+? zrFjX}rc#y=U!bC3@`b`bgbT7H3D<0}sE*&`nnvX0V$lqI$g4d+q1w!vcDBA(nOK(8 zMrEv-IEG5dw_#0b3Tt*sO^J^R(v(6&Ckst!BjPJGrA>GzG$nDDt)}GDsdbvt)p8$w z3jJuMk$xoMHLVqGw%3Y0P!_t-8C)0gYtn_u&5o3yImCa;hShD1*;}sd>{Y?lUq2bN z9iL=c`SHSNW)S&_m(#MhityDhLXkl`d&$?DJSt&}f?uS>@) zFiWQaUEt3uPI+v&+8gcqr1L79ilHNFn5<(7x>3v^a}OfTw7k7IFA2S^P%G>z9xax; zgpU=HxNPVgs~zZB+ZjszVX6&0Wzk;-ob+y}-a>Qwhy_*#nv=xJlvaOcft5L}gizU3 zr?bTZ+oY2-+r_&Ioa+Ip7VA~I1z2cP-v{`LHsvq2o(}aalu~r4(4Zt8>PALj6CLV; zJrFjB(^6poQZP{f9gJS-WbxfeBnmVt%sTy_7*0(|2ua?cU<1(0vEs1c{UZh`rQpp; zNrHEX-dPCV|Bd(x!Fx&p?u6hi?y?oUeLA&H@V-_qX#S?_6cV`E9+oKJrbY1-dsq~h z7BYDxBv-9cC!8P#~v1iN_yEQW$aduN`fqf z^UI)m3*r1q3#<&p1c_C$a886}?0KyPTInS7jP|flgB95#!H$$5f5(g(w+ktwmA}*a zCJtKA-GChipn3}ld&~kW0|{GVWh!AmV1bo6t+c)g#9B9lw~PN2I12%(7R%5L7fc~c zzY7piglToj^rY%{Lvcl_4h=Pus!wAiH<7CUG|n?oE<>u#0XTJnN!)Ode6c)G8XH8Z zyHEzF1?bIdH$3;YM{#!x$mPQh3g$f<1>l?=a24pb3u>iSC0R(K1fiEgmh%18vPB~W{>mM%GAb;$^93~pA`cl7_`$4vb zTT|Z0sKZ5yIOjo=`({3rP;Dyb0pbgNCtc z^+!(_U$I3$iGh@vCSgUD136F-Pemez6~w0)RZ}X6d{!U@F*J2#p& zf2D$(Bno1bN_ydYo=7!M>9W1a-Q0MiudoCQ_}!mh;1SWoP= zKxR?IL9OtkwN174hb+i$zzq*V^%j>ncCV#7v5?o+t@=OCZ7*|4Dq9>TEk1)xrhVIx}DGi-bj ziYtbV&_E-@#tTgPGBIp?{T4JBP+(=AP9*^|MX{Qz!r?SvaOms9gIeVIE?ckPwQF-< zUw3YNWGpuTwv9rmIwDH;^+gXKfm$e$C)Gm6g4{?2Qsaq(T(BCbzc4!LfB~bgZ{L3W z0&EvxwJ13~#hNoL(dz5FqY6e4Ob7zT53qEM3)teElN_FN0?*)&gF}!}1netSCu;7P zDcZ=FyuVIhQpMP@AVMF$n$E+3Nl7~n^JyTB4fCi9uKw_3h)EBTO{-o{hZ6$51;gBE`H0%| zEQ4EK57k>3E#Gc|m4O~Bu}Zc83A!?_{D1{kaZ-Krd5HuLsqH`1T$80K!Tu97R@{e> zFnR`slS%^yH8p8`$%5zxtnfvs-opIzO$)3H%s&zf%>{K>75a$+K ze;V?h!s8V{s>RkH{c0%8KGO$d%s!!Y&$IW;fO3kxCp56g-ZRFCY+~=ZW)B3b`0EK; zU@-NLh#GN6ie(HLfs=xJ#F@ZgO({ZDNpfByTEVlcmNC;jpoWf_EY#2-qM(KZ49nPa z7^IXkHt!yiu|s{Bg^YbM;wxnA#ds%VY;l*ZjP28@bu#uQ5{FX=*ei?#Yy#J`bbYnG zbS)uSh}Nfb(b}s>7b!4{7oZ{OJ!AuF17q`+M+K}?!POs{3=*|RFs-zbGFbcuwc%OH z)7L@u7V`9+7FZbw1`?}ec{(Ooykvn^I)OT)U~y`&B5foXdlDq-n6cvSM9S!S6rC#e zBK1QSWH;c32cdckk@^V>tPDhIiIu5H{gee(=CmS@s_0cVYa`M+F{oYKr@&bONVQm| z)+~eMM+NYTAJtp)JZbuiP)L!cLxYN>>D7$9Cerj0KP+7OG*O@)ELIEsC3$uM2-Hz` zWc;ZGf6b8KE3@K|H1T|VJ)vR?89L;IMB>W$>oejT&bTI;)15LbW=%!Q7AdC|-eY0T{N zRdDq;PadT}?aEeUx?HRhAxj0}La5$CL0D#im4TQeu`*T=Hd&xGDHH^1u*u?4io-Ls-a~|=JOw~VN@E!O zC{73PbH~F@Pl&`6TRHps)Ri7$CPk1Yg;(}=Y%Sd76l&{pGOAO4AguY-{7AVpPQjht zp=Y^5HFv}*mGC#d`fiB-DUBme!Vw_Q#2u%A;1D3&0q3@Z`=AI_^!ul^DGHBlEO!+B z4kKOzg$E+nnoREh-h^s3!c0<@nn2w_d_8sN5_FPO!F7_E zkkUZIS79>HgqG?o3^W&G7m~LX@5tMVci9?fd^)w>Kogp8+HIf-fo`LLCJZ$*0}ZQG z=biN?h?v5BArBW|19OA<43fq`vrYv!sSGq>IwdH-;$(F{7FF33yPmIAQ`hr_;s%un zSsG}rgX%2|GFtU z;X$b0!b0tjuX8EHrT&kPzz@n`j#HpTg%W0I3sVqG3}w`Evmk zt%)XF+%wU95k62%G@;=peY=e8CMKFa!fJsEKJIh{>xT5}4q{F%(*Hxo8Q7K@SWrUf zMhrCGnj;f&Ei;C}7pcEyt!rRI3A7o8pNCSDvdGsHK&H}Wuq~c_CB~>=)YRsU3eUHr zIa7O^?>1$OnkZVUur*;t>r1S8DHW~NtTO2d4x{wN?zZE6N5~8^3I#ZgzqRnR+WtYgCisuniAs3xzC_iruft)54-B6Rz5K)#93S z6l~+29*sLUcIU1dbgBdSYVlycI$9WT*5~|Exz3Fn;gD6YKC!UR@jm6_`C{Z%O)_TV z(*|FXP?>ImHIP#fSM5lRwS*@~ycejrPL5Mte0K0f?`YV>Y`+NgFfD)nQ>K4!Qk&UG z7fhpn$57SXh$#4ti86QP6}9nE5LJ4&!f|OBe70|&_hfT04Qv|UiWg=U?%z{+6QNvx7J>p5Qc@#$sQ0yQJ;TFE%I zAi_=)sW%_W_A9)y&zoUs{7v1*n|{AV(+yNfOROGg3s%XzG93msr`6jnuu8`!9g|@InOSlaoA%MO z7L+jWBW1>Gkc;tOEwE}mKmV5nR_3%yp7CN*&CMIq3*I_e*@&5yl`*4SjJk!V!DM%# zMSEM%96c6TWz8J3NJiyr!<80@8L@{l*PZ7_tkd~`On}a8jWnIm{kxCL59tlaLI&Q~C%;2%kD_OL~J&6z`C*#`6PZ?^?2)8YL-3#_tc zSv5`0$1Jci;#g(!%_dEbZfS17uwS-lt}(-!I0wwkcHF?Ez&Q)#zZN?Rbp~DG9sChc zSMd(|#yZa>_&k(ST!JCX8My?{WwNY^OYmOY?kSG+*)FzgRmi(nIB>uj5SeM&DL&+7 z>+RS*QUkkk*g=Tj$>g|$BTf~AsWA~Q#90>)_+CUWQd{mURf4J|E?naIaRL`AyGZBt z_4)1KO7?8|oLBzygvw2%ZP`UZXfas*9VFHOMFh)$ocm=Sn(F&kYY zvGwQZ`65MAJG^l6XiL5Q(yXCpx1*sk5ywWoH`gHd>*eieP}Ikp)EZ@aHSzJDgVR^o z$NSH0Sf=#x^2w2WyrCIX>pAMGPa6dzVBjEgVtq+NyWQ)sH-w9K7v2dMuei(B#p{!) zg)ZI$#S$Ln*5xaGO(git6>5;Pynn3bfQ#2Ga}j}S+QXY7bCHB(;g*f0Z15`byr@wx z+$>&zbOG-no0Sfl58^aFxB(U1{LC z#_9bk3$%>Jks?E8xw;FId_Szu)_awJx!wECn4R_3(QWy3+Fb>Z0U;ywk=e&Ed(dr&mC7vVtp z7SKd-pm>HB&wuhX6jJ;rp+QCdlRhSR8u(9cJp)3+_CmfG@`aEkBXEU)-M`|1aiR#m zlp{mMfg##tgU+BPAAQHQ2gI?2qlIcUR{$@HXa2y028&Rm%uzD{5zMC!!$^OvAQRnJoY4|&1sHb9wVd$b^eT1JF;=WzNTWZ96;+)QI)mg!fg*T! zFkKEEAc!uVGUTy=hfq?VFlUZOBtF)^pTO6Oa|dkx9)bA`;&nQ+uKiO&)u~)Nh_mO~ z+3PtsGVSRUG@2jg5>6$J{pLU0L8luSV`adwDM$o6>4@1md1B6Nn}0|@>t@D6mow5N zkGZzA`hs?}dXaA0U}HFGdQg@l6OU6q5UXefc!rIFlpZI(oRG&UwB|JOIL-C_DHB?k z(^6At{m(xgP7*4@$o6AXnYm3W?AZ6fkk`?J)POO0Ea-xT9 zK;3RWw$r$rZdSof5|>k`YhrWZo*&&`#=~BHl`Bwg9@{w!WI_1n7N>(?3dvVwA*tm= zlCcb{q{-6HRD|j+{7m;)U}d1?NUW0W1F><>$1M;uvJfby;TFd|6Ddp{LO%s6w0 zkYZZP!S#8HF5gzD6?PSm7Rz14;Q4Z4*xAr|)~#LL*^OES%+3%Ku;Ho$W95Nb z5e_t`PvKc_<-h=z+jyDB>|Ms2gWqe>vj!~pBvfx_cLN~RW_yNQhJ-!iSpXkn&!8fnJ>xkjq}Ve;L!G4An;3Zw z>>2f^@i09RM2Kl(Xz-(E4|+*&2fiD04iv^pHBkTQr61EN@a&Zn2RtQv2gM^|D&Edq zCp?9!`udhEzrrs7Svva*1BZ?jDuX#VmVUHQE5c^)-j3Tw#zdByLaB-t2nJA8LX!{z zT()M#TED(nfS336MT1Sdnr$f8x&9ZUY=iVPXs{4uQGyidF|Yck300@kHW6pfU=b6f zXw;-rAxJUO)85oia?Z*8HE-hdl784{*2D!7*5fD`wRW~-Ti(R!z{B^lBR5IQMF&Od9v|F6CLlr(0Iew zoJ>30(H6~kOKeuN18aXf8qjoS%gAl|BkjOA8kwCm927Cf#7=f2u1Tas zP=7wp7O9kWGA^c&oh&5FWMLWosw%>C`$q+0~w(#okb6mVQgZ zYt~ZcTQA&>OQ%e^?EZ=SCc10-1H=@#2G8*-n*3k(n`hM=g;I)DGc>G7_jr;` z*9lh5F85>Lf(wbD_46?Nh~hr-o=FZO5UMq&Fc`HA&cL!1KyfOiZPJoJ=V3pn2h`ne3n;W#6&F)DpRG7*@gRF11KZiCVxe^o97?q$|CG@s- z94I=a!93D-;?apv&-=;;m76KbX^M2Qy3i5E3)W}A)*b(JdeS{+?7>Hjl<#2}aucyd zKfW8QyAK-a{tn)~67L?zJF((m$A&4;KQcHT!MbCcGg@&53N>fYXT`|)aQ_%9lv!hw zC4+Entl6K!Dl{2`O`0td?G26$L+s)N?ZBQ_aSk{~M@z+lVr}AheK!0lJ0hBwFN_@D zByp@hcXWI`Y-S!SK@W;qX%0LXC_!xHgga-yKmYs*(pQlC;~6zbj>q6|@1Xal6Qqv- zBr8+OhY>}eH?;PW*nR5~t+!(p5vG!8y_FHb3c)9Q1o^n-qrzf>xwy+~IbRj1DWRo9 zOO!76OMqOxnP4j{NJgZ8!#iO_5_g#zk$i30{q_>JdIfXX{lJ`PR(Sw^VXscYJY0v2 z9}su!R44XB`59n$sc#FdJSn2B)|#XS=ncVa){s=+Zog!N!HEeH?QzZ9qt4#W&MarO z>4LA=g6_?sLPlh7*jzck3~XdJSEjK|%~8SCADIltlQRNqHKn%Q*N-3*_R2)$nRRG?=uu zFY)Ic%0sDP0>11YXUqO3Smq(0OY*W$bTL_y63hiLBhNhtNvCD@{(M04AUG@3SQ(*p z?e1;YZry$pL}(p!%1)(F8wp2f1$DgCd)q6;=`^ugw^{VM0ZZS3TLX1oR)#tvFw zWiWgtR;I&u%mOQOT8V|G9X!KEKaxbZezj}lC~&3$QY|)hB*_QD-0>*jpqM+D9N?Ke zCZMEZ@(4{0B-YPlgod%P806kq^){l>)i1&LCU2*UE}|<~GRdfg-*9F2w;2LlY*#EF z&F`#vGND@CiW|3lD7Fs77sw=~s4!WA$gSvkGq8~~(Nk|e!CGylPz8Dq zXARPOLj0rGdq}BnM(_Co;wzlzU&K41_lUbp^&Z!!Q|p}PJE~5lSSS_mcJhN@2&CHTUwfc?uzvvXEf$o{OB(+Zu8@_^8;OyXq61%wOZ5wqDg-uG zM5z$l5uLupn8ietIw<$ykCY*u@sR@Tp@#tUk-MBqr8r1C|Gfzbg4bbt%*X){yl|PR z6^9)NOdsiYVgG!!TWsdXlUHFU{ayHJ0m=n?`lEiR<>p|y?6w35tdr6e*$p<12PpIT zc8>RgSKpIRy=JCOGDHWtlM!!EhC45bdK@3q<_46HG}n8ZT6vgyUFd1kYd9DIRn%EubXrlA4ZNH(2C;+B5*a~~or1k(cE3Bgp{Wh}Y`Wsp;@;9ZfgsAIFY|(=`DUi^ozGAFvuN}(XPTPpl67l4h0qMDKxxj4AvN#O|+*Sc&dxo zvAd@-hUyU9<3`_-Q*%I{!o@nU(;jlhtB}{MHUydxh9E<6dFD(om<21$mbG#jy#v~! zV+KXz0c$m3%CfG%25!nJGK~tZ7weV+vIV;aDg+r$&?$&9juG)}KKu50Pv8XbZvT`K_+vlh>C57Pk*Z3nEES*;sNO;Wy59mT z11U~om8<}15>!57ftryLq-;FO{(uqLensMMa7@FK7EL#h_${&eP+PD{=9TF%BDo~= z84Ik^u}OzK$pcYI9d@Sciw4KH{=G%3%{jzWCw$fdtE^`el|%m30;}Hu4uL@Mu$6Oa z-M5Dg_9gfIrZV9*rlOMHO+a>FI?}xuzOlgbmX3kpbJcQTA*VT>XhjVaAT7y6LmLKZ(*X|Xn~c1Y$UO2pj8OMG8Vng0seTa@@<2 zGFl!@8>8b|(A|I?4nXx5YQ<3ttPIo&iIu5Z@t_4(=Csnr=pfd*S-f5Rr@%Q4kZQ4B z(bNJe^o;iaGK!uNzdm|;$M3=?irx_#awL16$w+UacRU&sw=)RI7C?d;D^`c#tiRe3 z$0>tig3-%0@Bjl&y|0s8vxfG?`OxjjRW>-$JyTpX3?h&&sExCsp2LV|7< z>_aCT4i)Zla%DU(U<1@%EgmdKHJbP!pxS+$Tr3PY!XH1vzSnC#Gxj6|yL@UGAHpOdZnY^bCv) zIs-kl^P`8B+@6t9+@n~#L6QLzk16H8o}_Z!MjX;7Yx>MOB} z%nS@kn-~uR`b31aYQ=6qgtLGMnP+)>9@56uFCwa3nTvL$Pq&G>q+E}_$k64xYZC?8 ztygMWR6k^E9PzQ~g>+1brY^r^5Lp?`b#m@rpC`oF#6zlzHAq4HC0eeXNa) z5<*W98tu!?=K!4N(<#V~(B(#V!7bl+)#93Sw6;FiDTvv*u{(Fwpi>>lgQAkJj>2i{ z>vMjQT<6A(e$+!3v7%f?7}MRGz;woY+Fp}TnT~@Elzzn3Y#~lCA01V3J)tZkf`!kB zq{}!*KOnf!npBYW_gmCvH=1O++>0>X#>H@nmp~LMpYEsUh@rCk1ft*xK5jG*%Upjj z@D_%ivj)A_ra>za!Bx#SsMDZ9Gj;j0n$LG4470UD<)BlWs9&6?^|iXxV}_;hz$sOi zj(Ka)M13Y?C@w;><@W(K>a*YvSl}ky=coAwn;C!=EvhkH;&VV$vU4j?pP|X>Y!6LO zo(s@)G3*O+%bt(OAgYv><1g_J|9o)5&3UgBLsN)ts3BwcnJ-AejH}C3rY2`UdrP6} zRM+R$dzl&6_fg6WUl){9=4@Gz>zH3*khyT|M$Gy3Q}sZiwjuYMSaCSCau%V*!9Se< zUNg;hxnBi2k+ca&N7<94P)N!Lp6`DEcxE~wXTh+a!TkYL79`!Q%QZ;^GeQHX{(*evaK77Tf*`AA}h` zDwX!$1lAzf

#JNZta|UIkOJS0OcX&L4;VCOF1wrXRCe_}2_IJ|Z+MnWWSNM5r|) zf-+?_HiQIvIiErV+I)G^)ZV0Cep(GWOqeN7$2(!B5O-PVi_BmBQ#KgdW9dAK`gu&d>W6LB zt}wKQDtfrEUQ6G$Ip^_6ZKzPo6-uR%Bj6H(*2BDbz^QUg zk@JPhIFD%~9V(kD8QWd0a)&RFrJ6f8Va4GEg!fk~*iPvED{cV--y#R6Uh@z4At?V! zj8yo2Z>Y*x3jl8#AG-#s_=O=jT_O*_`tXiSKY3xh)boJ^-Y{0r4<%HlV>AQx9C0-h zc@)Jl$iR|UajoCi_Nj%jU7)i@)%5eDDi32_uE#bg%VvgGsYGZrGo(@0V`%Qa5>e19 z>+?dxg*TJEVU2o&O{44;_Qs8h<|sW?9ru3Qt_DLu$c<3%kY#a0rj(|;+#QiZGesfq zy|l&AGe(*Bm{Z2R5nvUPMCt8NfK-xqLiI4`D;s_qq|f@W1y%;}MG`C1_@d8RU}Z3u zNvxthDRy{zT2n;P56;XHQAz4%(63pbY!tSqYzAs_yKw!yr1@(ibbiI|u&#X{s^ec3 zOr={rjJZ>zZ^bgWvU+UtS^aH^Sj7=FsLXv165Sq`4Gj_vH=akbHvBEo8veq|OJMtZ zBQ%;DUSuNz+h0s0`~^iJ{q0bnq3ti3k(l`pu_g20{4u!0KRxpw-b>U^#x4~~ZfGH* z>Ff@yz}MDbVr!fE?-WGXha8bLBeQ~$`R`n;xS{#)`~>itftbqtcQ(Mw%>360m6@CW z1d9mspJ1D0^WWqU6NyQYRm@~!$@qZ@pA~*d$RCsQ;C|$~*)^Xx!_CG^uVg3NI94T_zV!<=dOI`iH;jC7CtO62#ldJJUe@ zJ|(12NNB!P9d#5oD^(Ag^I4kX8TwRk^#@L<;_4C7*W#j)1@l4)s5~vjd<)MJwc);O zp&QQzdO{Vdhq=yFPk5~bRt9>4#457rH&g{4wZJM)Y7KkV*jaYAs(_0tZAjo3a+#cA zgL7)B)r!EF;CTteYgt)f>4_OIZUyP%@v8!7AH2<8FcnP|uIYN*G$b}n{1H-znKtTj z8uIo?d<06!CI+%=s5!JO?8o+nmvEizYH&!3gc>-vI1rMeLzrmA66xG(COzaAupPp| z^+miB4lZ$*g@a41DT#rnJd!jnK-3M$!Sw|qM@Xq?M2if(a4he|C++DWMLXW~%R2N5(1xaLl`ix9+-t&dh!Z{O+9MUM_ydBu_bLHS2~) zyWJjforVvtfLm!-ULl?$>+N<|iu+aKx*D!S9qt}qqbf|OZOm{Q>HPhW9UTqcEZE!v2E`;|(o89g3hr0tWFU89>c)8Yp z_A70+&{OnrT>CT6TyWI|iF%K{MvE-e2Ss>n= zgbz=~OCCR*Gj#oNw+~+z@Nzc1IOd*-uNUE^A08fePl4Ox?f~2$b59lbv+(6?yvz}Q z&xPwT_cU?;IE1uexbGm8-|aeZg|OR$@N?gUTcn>u^fOF9BjTsaop%@3hnF8CFa9%L z4&z>nGG10;bjNbMoR4$=Ie7UlPC`%PWjcN~1ukRm;ZSwQMODW|HOEC2$HnKz#iz%` zXJFZU01(GB-34&5bwU9DCSo9f{{-(&x)v@!?eO`s2ww$)Z6ufx3r7YfUykcDi&dCX zCXUHr@Dr$5%+L1GTCmdu;vn;Kdr8BP0bZPf27r@<6ciW9l<1Uy$9R){AxxZ;2j%roVR4v+!YB8#6TCJT^P63ba!H5 z%kFIdh8l0wiDrg75u=UWqj(XsoRE4^tZkYMSlE&bCn|2qBZg>fm>B4OafQPM^<7t} z$vEY^LYhM%t!c7gVN0^~*_y8MdE5_`&o`Qv`MBni>RA7nTNCS>dl&s2g&$a7@1~!7 z>E{*n^D6pzHT}E>et@>G#h)qegYe@Xhs%8sN`2#m`!L)>J&(}Oo8V`+`&;zKg!m)e z6F-13diMYQ-8oS;Jf={b!z89v^^sENLS7X*9kWU?vi+1$rBv*%K#*)? zyQ|TcjDh}0?dLQM6gW^n>SU`CdY0x^=<8{e!rwwyPwwbb=$~Ybvhwd)hoD zFc$MYFm5#9HHhJei>EsguRaig*hQ@cbBQxi>Y?BvsGdPY) zB}Z(v!bIYOwgP9Wni$L8%#h~NlL=!*$ulVyaZSHu?zI$>?7l zl}XP4F*t}xOa4wOrm@m6XF_r|y!r&nQy#9q*42E5m|BQbvYIYRWVs#_TITM}VVb_~ z+`v$wQgt9j%q#pQ&MA)#S9|4)-mO$XevsRclMj0L?%A>SvRu!`P<5V!qwaNE8%ae& z-DaMUW}eukPG9pB2lph5MPnu4frQF*1KU6eKwQlx&;%vmh>B}{(lD*aQ4@{BoJE7( z;}+W9=SC+e7R234{1c<7*e{ABMQEJAKm$NWAx{1>7FZdKN{LmpH&5nV;B{)F^=7vGjITK*izdWz zb@OY^1<7hm`sHYdSj@CDUu8iFgU*y#nJ!0fu)xZI@hxffHVdrGX=S_|z25>YBW7;Z zazx#rTSd&LS5w~qf(79W`cqD1Pi$o2Hg(9#&y3E|Ed5`z!0J5!BQbZz<4}MMXO@%x z_bsq8r`5k)#A!8O&fdbP!^y^9vBmsfEO7mtmV))us$-+0Bb8ddI$WsK4v&r0oa%&3 zt1$Fbn5sHfjvH+a1tPo3G&vs{TM&K-xgtVQVG!Vxfo^xwxVZoyN37=8S#f$vYTa%w z;BBGXU1ZT*gFzy(GF?oUT3}_cm|D_mg9TRRv@%{ycUquj#IdbfOsN~}CJpK5`2kD; zG@Uh`E>5iPy?(0dMwsAkP}!!y7a!9m-)5_j?J(%1nfu~}*PT*EA4WD48*#_suFirk z>YmA2?!>L1t~M5enPdY4mwm`0OublRMje>XbS`@(YVJIOm@DM=-guon{lq(PED|P{ zT$HWL_h&S=qHamIiVY2WZC}A4nR(M??ZI|iPDWvc;?{SCd&r<7cOTD^UZMCnj-lP| z6Ns$Xdi)l=6I+kPo&A1W5lJof0}0omNIT>c3Bx2?<1O7hR)$j?3ZqU6f9VyzqTIk= z>cMK-WBQsC=`r=OweXpCg~z{FQP^whxjQ`x`9%0R|A-AaZmTsml7A|pGL3)DH4qLE z*UbE!f2iVGpG2${>*<{1agoO{WE%}0vw8b()fW0Ir=~a3cspYV>i!L)p!Ign16>93 z#fu06zeQ1da$F%b!)5dC$>+_fV&a~B4yv~>8UMQlRtCbp#LCptGVN~YK0k_zPYxOm zG8xYjtEkCX=z^ZDC0P?t54}9y0%apbpha%Ug@CtS;4v_&5m7a=O>7)uf=T0hf}3?+ z9Y?pIGL1>2@iY-NX{6$ZjlZG%us)F=k|{4m;Xp5JO!E`07cy1JU*sBShB2-3*Efa# z-v^xBO3iQ(`AlerCAf=dhQR{u>4s;<%7!u8VQ2*5N|B%)ssY`Qmhp!1+7KMh z;-ASsb`sp>lt$pF4>(fl?qaD_=pCsXTUZy^qh><=%nhFC!%qY7fi?e0-7F zAT$WI`bV>7gC~*B!ffy!yc1>vahI*xz-RWDBYBdxhe>J&^xzvvh#sL`CXMLPC~Mh= zd~$r)Cx^Jpf*fKyBHNiBWsNTPgRnuSezBkHNmws>2E}H89{Phe*eb^c!#6VRlWOts z_B1D^q)Ogmjr)q5-`THhv8LQ5Mq8}ulcX)ypTjOP)CUplS%z|dzFTdq^p#1^6N zseIszbS7GevSvJk6^GY;-Z!maFxrB>y^J}c_9kz^4tH407VPlr-cW_HCRE-qzK)x0 z!4AP`{}$}2_vj}YW2@xcgvxYGWnh&=T(zrUa|(Bmi}t_N0bsp*i?NON$Z=Y{SlLk5 zd&zNNfHc~I&8qO_TM<1T-Ga@FvKin4^Ug}M1v`e`?)iv1s#mDtF*FI7!!roNvc&7~&|%f>G8QSwZRMVzK1rC%~vt%T&e;hOEY=J#yg za@}@i4>sf9?I8gtfHb2x&{QKf2r|MVH5 zW`;19T->E3dYK!vig9}AIpf=>%=tErulL<5xcX}?<1|>uT8gP*lKPTc^pufB-YFw{ z#zsrdKHz}vTyJkLWMQP0%>2ZWPpD+@g%sUvVc@m>C{zzzX6m*53k$3a^c{&+vSW6p zpfTUQ^A8qy#aWNEQN>D(=KR|DCV)n{Cv@{pn0Iej8fk7}H}3?~p?bCjR^~%B z%COU6*5lL?PuPOeX@QwJy`q>+^(SLFl=kypT-6S&6!kK}eH4T{NQo~n<;1L!?niLY z=@zJ4r_7!*rK@wv6<2h2=ip}<{Vb=S74)-`epb=XYWi72KWph{9sO*kpDpyWm43F- z&vyFRA%2z-yk!J$8Npjd@Rkw0Wdv^-!COY~mJz&V1aBF^TSoAf5xivtZyCW`M(~ys zyyXOMIl)^_@Rk$2~1k z!COi2Rua6G1aBq5TS@R%61xEx}t$@YWK%wFGZ1!COo4))Kt61aB?DTTAfP61=qpZ!N)FOYqhaymbU` z9l={i@YWH$bp&r6!COc0))BmQ1aBR|TSxHL5xjK-Zymu~NANZiyv+n}Gr`+T@HP{? z%>-{V!P`vmHWR$f1aC9J+f48_6THm?Z!^K$Oz^f4ye$N83&Gn$@U{@VEd*~1!P`Rc zwh+861aAw$+d}ZR5WFn}ZwtZOLh!Z{ysZRpE5X}J@U{}Xtpsl?!P`pkwi3Lp1aB+B z+e+}Z61=ShZ!5vuO7ON3yln(;8^PN~@U{`WZ3J%{!P`dgwh_E-1aBL`+eYxV5xi{# zZyUkeM)0;1yzK;UJHgvd@U|1Y?F4T-!P`#owiCSV1aCXR+fMMd6TIyNZ#%);PVjaR zyd4B@2f^Dx@OBWq9RzO&!P`Obb`ZQB1aAky+d=Sl5WF1(ZwJBKv7_^{iN|J4f&7>7 z&)3RKg{oZ^LV|%%buCm6TA3ocG}s@!&jKq0fl6X!N~@v;R_3%qC(w)1P3MvqrJE%$ zN;gYhlx~*1DBUc1QMy_3|3m49*;sJR4m@PsCed>FuLyuOiR@MI)h~97nijMQNWy-f>pUO zOW`B7nYx*yoS#B`MPT%M@lFIri@Pi$frT4T?5FnW)VlrDo5-aVvzwavxdCO1`*Uo}^A*L|kNBm8%5+nefo_Pnn#G(X7~4Os z;%c3>I&)@^-OD}88xAatNJon+JQ(~Fh5acf{{ zl31Bqnig7MWiXpatfD@+oQx{rk#1rf)WOuDX~&qBMq|Hzu5vS z1ID+c)q5{y$k@WlpPX(gy#+0@svjgNdp-R*oBO76OrHj7YXRc&b25N-V0tD?nPz zEcuYhxeH!lt}qyk*LhIAg&K3d1y%;Dg2c*n7P;I4D}#|Cv5JaACov}Qy0pXh0lCYn2*B7z%cO(ot~4g3_9nUd>rY>}A@KFSnqBK}SlgOhuu*1y%-3Z%M0R z3#`m(Wh@HaV}X_tE4NA%qHfTwALdi5DepgKK{$i{l#`gLDDc8A)>5~o#RGaLvhHiGEK_C#un{NQx1O5q6gxL z)cgu7cK4*--t=w2TW>Fn!%*qQAmw0VnxEJl1ocx@pJJm_^f7Jn9We^SehloKEsUdZ zXS@=Gb`dl&SS6P|O)OE-AB+Ss^M^dUD7#SnawIXFyWC^`uuq@owTlw573nXL3p zf5oP}(~%VZPIK<{)Hyuj*jb6G_yjgTyr=yX2FYx&C@~eBxD-H)29wAoB^mm{(w zprRY^L_meO%Qm3GCsHc|Ds<`T$zPhMBsL)?w-2ZgkbXk~DhOALfC?u>s$QA-LG>2qzt>q{Wnc-B zSQ%^17FZd~1QM&L`7c!l^!Hkz948&MTOD~)@Qr3zn=_yypquRK4#F1>3#?ove1VLb z>vN>H>tY0hK^^U4&oIxjy?77VB=}{E{xmQt{RK5pF=` z%mOQOS{YmG*I1xs#LBI*)>Aj=)(`Wk)s**NZb3MM{*;rLskJ_Dft7)^-g3epw!q4q zR@qtW@3Fu)rL~?Yt7GT55vQ1WqvDWVWg2UJW34MwYyDd-dLWKS?G}&U40xLvAeC+m zto4m)KB=trWEyCYK{%#OzOg`I*sDM+X{ELPv&dz_TK|`Dr&#N$LGjjl@h;9l`)LRGmt(P%7T- zF_Rsz)f${dHjtxJm*EhM)y?MRI0GLY~QSM7i{^~Id2;#!|{d>8AJIhnJRXSbB`N0FCo z(O9Fl*%!Ms{gcK=6GLKmHKL&P(VQ7SJp3j`O}q24yf=uvQfj#Mw85J9lBk3a7-e>u zQ^v&1eJxaP;b+-rft7&`OJZee^C((iWiZMmR#C(4oM<;U*fJWFXB~Zy1@f_S(_A=5 za&Tn0P%KXj4F-o%h~r6wzF8|&4m!1o`Y9gb{%oHy7{?zS?V+f*&OS)J?5%lbAPvu)6yI5f@tmgcZlDUC@9$ zY;j5=fx?}Qwd6lWWJF@6QxUhY9pziB?N%CokbsJ_6hRE}omOOTRtKN;YQSFT;Ir{g z=-}cmTOHgd66oL-)DGyu4;3SNgiapQ)-LJM=vdy=gdCvkOWPWOtIFMKN(3R0snSgH8g%kA)={)A1hsnOYMenI^qyqDw2u*KSV?!Z`ipjI3yS1}1$?#M{x5FA{SJ5sC-$yKiEFLN~M z8-2-EfX!;(`tped(*!HP)mU+O1>jU~1=EP5##Z1FyZNzlv6e5?(B@byOFq)F5f~Vk z=oqLsTwSa^k+(|>yZT*i<0g)uh3&9A+`um2Qed_9$Y$NSVtLRxx*mRN!dwWyo|x06 z8~}T^mVn+j#Hk787+*T(e3|Cx*MbV}#CBq=A#Q%SuQ*-#D@Mwi+O|eRJdF`9hLmnK zm<(XxM^nZv(r}&E!q!JUKV(iK6Qjq2P(8F;i70CjM)`yVRtDBMiIu4}?kNkb46Jby ztEe?DRn+sxEl`eAys``HsGp^qFDF7L&+V3)UU2H%M+7J77G{I+Ga|Ez))AP_BvyeP z?$rV-B@VhHSU`fI9PQYdqLBBV776)`&0^13^q~Pgo~9<44$=Q@ftA4!l~|b$(f_c( z%3z2}tfD}H7MU;H&TG&K8l+oaleI6+M`;k6j zh2LS2fMAi(xmyRPPMNZ2s0daLY46A#C|0Vq99ijzTBI5PJv@Sefdp*wP-d`LD9a@6 z-AK7|ZlF*a7%M@j3w;_TZAX~2xjoPoK?y*@|9UXjKMp582%8IbSpRs<@p?xHE4e~> zFjp8HM57FJ9Aq=VBOx%ph5(l#Y^DRh>IEoJGyLE03>3zyj@O8aGg@(~PPtaiIfa3t z5F*0JQ#&#upjNvDC}_O4)wz;WsMb0lB&S?FP#h?fYlQE>2x24X$=T>ds<(^kY}nn! z219D&Y}~Mu(T^um8j z@oCS%NX1!tldujg#bL7-rmW4i-l5uX$&=ls$L%CmJ$JdiCV>j>GaXZ=gxzafvO|s3 ziYzK*omx+5j!s9569s~p*f&6pa%K%;Vv%ZEA5Lr-TEgT!hgP#Fmnf@pV{c#Jf8t9c z`JY1TrxthVf12aX{}WDZYle2a??*}tkK70FPI%Hxf`Ke z{lddl7z~5Xfb=}U0+sB8f)AozoXi|h=zD420R_7`xdTdwc%C1O#gs!)?t5ZI*&z5N zc8D(*rJmUWx6{YeibHOv95lT(Zm07|6jt0$f&>%wbK_l3^fu1j6w{7+!O}q>pfqwd z5h}hfAR>0vS8fJ*qf~N)iwO_4!t&^LqHybK4g?jFfk5~v75giN$~c!HEURE_^G&sP zeHFoE?o_6_Z(zk?Ih51C6>K9MPfPX!8LPRjfl{FgGG96BZW6r$uBLM$^MQEYD?X0( zFLCtw_;NcgWoxE?iba>ZfWN8F77#$w@sHB|<8JnCeR&Y^E!ton@GS!gSU>+~LO&bF zdry0f`CMaQ*g{;ji&gB>q$u%0?wwz#4X+<;`LLIaBnJR6`xy~FI3t$*Jgy)?NmGXP z>mu{6NaLW3p{9E#qCg`Z8rl_U=u8??Y*~}fSVNZBG-M?Jb63G7USd($q7%yt(@5in zWNq6yUuWA9GtY!?*Xaa8G_dQ$An#AwiUj#n7yyQLozvr(6L=F01)fa@u_T+$4!pxZ zrAJ z$hDuHh_FUdiWzXWkJw;U9L33eD53`EfoifwTa`Rz>z|w zJaOFpKH?!*NL&h$`QG%SHo>Zuwxq2ex%;kmA(b9O#Zb~to)A|qbJA4CWtT0MtdqsV* zq9<>W=%D&=n?x9imf&mLquRWr+b0%&`W{aPT@OkOSe5V1)y77_a(pj8CiFl#I5%`F z9Pf*UFA?tK9VU7meeC@iIzz6@jf&8%+BEq)2_wZ=h<zYT5DttD$C^nahpoKw8Iv&oL~VpGHE9T*CIBmjX6~mD1z%K-24JnS8YO|u6Wt}b zD6T#>aFo~q_`<7?bdc%zgpu)U=43Pp()ub?5A%#^1jzR-uri1Mkyx2Vfc%RERt95S zVioPhQzH{C>+%LU!thhx-&0;2mSXJ1gRmT#ymNAfKq4t71O>`aOh{Pe2!gbJO`K%f zXQx}V*PzcNRtkSNNNabo1y%<9ZAq&uEU+@CRWi%Y6!HY;*^L%>#cD!L@Aj2goG7Nf z(W1fT9bw9}eHK`?o@vV#Seer*nQ6rt$ZT1?*8(demQ_+QHhZwK!DOo#pQQWJAPA4v zG+jk;Emq{#AR_j!XbFf4M)OhI@U#q1-ib*caiHwIBw=V8JYb#nPK!=6pvBvudJ9?T z4=k`U7db`qbIz;U%)5OU(*1V!|vgdeag(NFO@{B$MKjpK-3vFkbd6H=a zE~y#j-vz@M8#d-YXs$3A40MT=sVs7i1y%-=q9v`mEU+@CRWj$QvdC%+tkTVPnaU#6 z7j{#MG-3xq;EgAf6XYnY&kGq?8|6QVX@zh5QV8`JNKM&!49Vvs0>SS;!HHKd5t+a*z;W= zn>7UIh)2==-sYb(p`w)0FpD}~+{ck1VNX<%K{E3O%G!f4Lr!jT?}qwBYjkcl?Z*R% ztOzoE4c>_$LvfcykfHFU2#>T+q}HY0TnXXd{l#)z&dnq*(ZzA@cj+aPH8$-h8fllG z$V1G+Q?!o;yhp4;vZts&>9yiA@)WrCIf>rE#u~Sm8p~2oB~+%9n57*b7(k3!+*+V=1-|j@s~>t+0(d+VkqZ+5>e2)impmCNP;mD zHH@60R?D0RQSEwa!K;h3XZV}Z@$by(XrhRI1**5OkNl$rRtBno#LCn@@?#6E42HVI zD%ykD`ilPBq76oh1BRdp8;X}@Gb3NouZWXO`|PyW!65Y`eE3|inI~L>K9g9Ps=60h zU}eDHmb6-Gft5L}l2zR}U(p5&ywdS(R=y(3j(E96gUvg_lxg!8Shb#Mhb^!&r&Ti3 zs`i_d(pL`z2Ze6p={PHdeG;qIibP+rXhR(5YCT7- z5{bS$rmM@pT3}_s-9X_dUX#EC@nj+u+K>3B9Pk;t+m zF0^Q{c}JKsZI1<3t!LUREwD1DRWj46BGI)LSQ)WwYegdBTb(3hy#DJdifeI0k;twx zjc>lOsVnN6pC9(k`?6Isf5bTBt8HhHY@P8VfWMjJM(NnVsoA&}PLxwqI{!RdZG(-F zG41f}vMA-kW8Ij^MVUeOeHo1+#bx>CXv?2skjyw=aanRQlFKqg zYpn~US(oK!5n17~{2bm1m!-JN)@A7vskJUkI8#of?AE&>m5pr;T$Whlq;y#d#4KEv z%l)A&h$V(quz_t`ae#7ldrKES@RqLjc_P2Vh7h+-8+#&ukWg6$rf$SlI}A-dk>6Bt zZL23T;3};rl8QtV+va9>cH;;(QTvZwJx#!$}vC8D79M4lGI`yQ(+sfg#v!hAeL z4KOoBDZdhNo{oIRXmj%M@Z!k%TSFTY?_vj3Z(&M1&jKq0txaNOYLck4yK&y*shri}2W8m*# zb!v%LS4Y+oTHOTPF|AHCLe=Wvgmj*ScF1f3Ux&DZIl3MUYV7u6HD4Yn=gVUyuzd{WM=QnQVhwV7 z8zyX7q1SkXS{vYvBd; zdNJ7{raDYFTc8{#kTtJcXBtDcL9kC|d}t!{1=_F_{{q!|p1?{md!40Q0)s&u?c0vv z6R!|Wb>SCma&s&?)WES^pr$D?3=Iy?t6E@XFkU5ArsMT~3#<&rtHdhWr!&IBP9tlW zD9bwdQ46GvMywi1CXh&N275%XP6lJuvbTTVf^g=&{lrGDBTwDH2QK{0y7N;OSiJ{e z6k=sQITbw)1xWF69vgu(izbc}DTkg4(=pTa!LBlm>9w(t88yA8oQ8g3(Fc=a8u~Xt+{^%@tn`7c zwK3UGl&$rGWCguZrhu4+`8txqxZeP6rX|ML^Ii}0m@vLx0(ZXgRj=oH*4SKf>*LI` zA(f1V{L@TLG%?S1Zyj<54&{mmAaj6lV&b7=g&bI-dZZ;P=Ubv8XL*=?%4WrGB$lD3 z7B?alYv#8CWtAv%8G~dtm}Koi9sy2fvSx<*LTmGA)|$B$krmd=ZFncFnc^;6Yo<@6 z)>$)`4?C5Erl!lJT+^byrtOq%%Qa1CnHwc<{qD3WQ)u85rD%6(U`g2pDT48sz#!=~ zW=IPCxku)t-aS%wz+yQvRvBnEhWE6cdVEcT9Z%c-wi=0vwj(Ecptn#uz z?>6!0^;8^;r0nl5@c4`z$q$aysvCr`)SZ)`!=rq$oIm7@`){bMGdx-w&x_DM?-Tq3 zo`5NQ!}2S-a|1(#O4X@txN0li^ulSFYuD4kk3g;sony5FJ!|m*8d)-rhb4l?spM4% zahk&g?+<7cR_#I@}jiEb+ zX71gHg3i!=>jX^LT`$hkFr&XXOHZa*I+$pq`+zs3;#RL-H)<2is9F*Jkg_f|gS^Rn z1~KveJPg&FsSnDO9a!Cui^>$M`_2r-IBoy61c>O(OlxL+`@Yup?eDgsZ*OUlRITmj zmID-h-ZChx|3BB-{{M6v`u{AQ@}up*#$SjY&=+GQe7dzH{D(G>aFIq!)KakF2ZDgw zQjC5-Z7uzN+y?rc#FS|*)ilKfts?Ijh33}Hjd}*|+?h~)s~6y|X6*}F;+fYV=-T{e zjN})!mgMKRf#he#8)~!!Zd6{7Q&)%)Z(VDNx2g@qn-{WXX(<+4NRWxWVYGR9YiYBq z4YWCl8TYi*(G;WEj#t4bRBSDUoHkHswzPL@X`>VnRPmoOdfeYydfe9rdYm3-_SF(6 zxwN2Ed=W;rx3rdQkF|kp7dN(xYl&#`tsrSLA20%csI>(C{WcKzY^_s4OV=ho5#&rL z$Ef(F)>83{ZJ=VVk^e;y_LP>nKefHlHo&4wTMmu!#bvGK zizV6fg%aSEu=g=A$ZH}K8+!$#k%{X(mv;&WdGbDpm?Q%)wdkd|=&9y6LS&m{V5?vQ zW1sv!i)IU-{9_BJKoWNN7wcJV>{{1pZlIj{26L%D9p`4c zfs*E2JAqFw^1*J1#-iSd+6^HONu;>B26<;-6QyX$Bkv$BF zC7EipCZoZlY+1M&n@M4Z)b5oGl9?W@Y+2w$q%8{}N^65qo87Xo8<7=T7OuxTv1LKr zWxHj;ClYK~P#8NwaEUFc|K?A#>f!|&d-$3_%sN}whF82ZW z1@bYHbDGv?LwhT*3t(bDlz$#7te;8LzcR8RW}`76zl=ii=t6KGs3r!p6pQJpflmETC&%$T$p8HyM|XTfm@wKZk=W} z&(>#AsOALmL)Qh=+b@CNom1S)#m|`JCkOed8y@X;d&G4bKDYvI<+rG*FK6M0m$k-P--dtRj+Zl_qGRqp zxZOF`y#s!BE$npX!^7Qf2f~<#m;G4sPP{A-Z%)F8C*viLAI=%N{2dKHY!Am-2xlV!Tuj>n_}z$s0RAZ6 zeGo4{?eO`s2w(YAc63I=!jW+qnb&3(t1zKV9FxP~Cs46iy{r=(%LqzZrbfrt4~`6= zHwAXd!44-rC9s`M6HL4kP4!m`=*O>Mv%iLy!$;t91TXI!hsz)0MfAv@Vh4Q(FU^t% z3%8j(PFZZuYl=MKvYb4ksbTWGfX)6dyu9rmxV#%LAG;SWpT^5ouY}7Myez~7hiBqN zu z$Sf#|G)*onY)P&=Ey194h$X>6>2%&pPda2Nd?g&$Z&?xvr6>E{*n z^D6pzHT}E>eqcF#E&fb#AA}$GI9%=nBjt?~?!#~k^*lm9Z-SrQ?r+f_6XK6he~s1W zz@E{HPCP2=tIvWBswEIjaq;+{)1XL1ZV#3RA*avThC6~` zMwTX15~F_somB0&l*D0zey$0?p5({?Pk$sG;2$*xe9GbK6p}@KDU@^*YWl*I82qp? z28(Zhuz|_h`b~vB0p%1NQfX}){4brO*%Zr>K&z# z^1i#{~!yvq93snTtP{sf-9PWc#PF&)IgL82HE#6ikHE<+#hJ)4C2^5 z1>%7*r*j@784p$pqeC!|;}mfB8J(DyFph5mT+PODeU1paDi=x<$Al?!tWum16G^?J zP#zc>sgw)D4(P8^M*J?yh{6eb1JcE2&e)Bl6;YfQ45&iK5kUltxi_F=$+n8;fLW<4ilPcF_u3MCCT?iqlzyybl%BPipeZE& zEnE5oB!0xUiWZVs=3hV6PygekD(_;f{c%BX_wz9Q$RQKn>OUREKP&zj**~aTx>qfL z%fop0XLxDeW;P}?y4}(kDn>iv0kVRazNU5O7|>)KDZ5yBxc+Sz$=#C!NleYc8ue@# z$-WjLIlDXO)CPJlV~~lQQR`izjkCFRpuTvq&uu*-8&$Oj7^nx6I`%+HDyIjK@y?(N z){2h;B~q>xAGWO`Isi?mB4?6k{ArR_EQ=}vEUpm^$$X}rvmK2KQNjM4H@0e7o4Z(8 zC=j4B-!1~EDZBf0+bUW}XgS}`y+)?_;ZxWKL2BJJJ42Zrw#lv$^X$!MXE)CxBHlbZ zTP_J~b|6emn7BzPv3|y4F9i}!1~fyc46@#~cY_6ajcpYzWDr{07H@M3m<1|#q*xou zRY#qHVxc6mU4h*1RC16Vi%Ud@B_}k$x;EP%mn(;K$!7$F@AIsLPSPT7B7;yYFWo*1mw5)%YEUp|F=s{$9 z0GS^A1CfD_0%Ush6YQI8sT*|A8*HnHc96+D5?W6^tC6|#*JZ1W%!xHYeKw=sMH^Tn zo%z$YL=XDylcEZ(&a9Oytf@A0ZxubfVd?uHTSc<^ti@vjnldGQH$CN^Za}#w0?Un5 zkfeJ}=s%C64A}e(O zAEPeU+2m{|l2flOgH6YQG`z5a)C&D*e-Dq3+?%qIx|J!Ve%j(9ffnn91g#8~^8tQJ z`THE(DgqWD;#>3|G9oMw!Zxd09_FV%@Axa){M76q#3Ol@5H;%nz6g7 z_2OOdm0Tre(<*Tf)+3B@uePO4uu2eZEXH>*Mf4MSv!0(jfE6iHj&tHW0bCYFeq{{T z=OHJ0AQeV@yDhPU@%&cXDw-y?wSXA%=285Q7n&Mg5IwNQ(-P@5%7 zEofnb1e%)`iWVqABq%YUM45}F2tpbS;DYF8qZ{gli)h;M63L1&mSaO1J9a!-oW)U+ zH-4YL=W!-^@i^lo6Hh$ZoMhrj#uH~5`%Atgo|j4Du_y1ZsKOBdQgZbWI$ce$cqgN1i zFpCtezvH?bE_m=)VGx;%RkerAXr)YDF)He5Okg__c}5=O;G;h zTG4HV3Ce%ypN7BMD+oIhenr^OX*SriPjidSdt{L+`x1XC!uMUZne`DPihLf zCkhvv<#Jg#E*U+YOBnLGQBd9ac!lbH;lSvT{f}?+*!e*J?7TmmgsF*3Np{|~0y}kw z5?sAE9Hoq0-4P5q;lFNW5a%xJaG7R5-Rk8rzYI*m{K>>vo(rZ&*0FrYO3df(Bv?Na zj!;I{PX$Bn!1^9sPwTykTIm6Vwb>W;+7XL|7^%LnSS!!rwz%hD57JF@9$o=4!p1;W z0luw+^I-8w`VT+dD{HL(@DmK8quuGKcY1Nvy4#)g_BuaL?R+Vi;aQc(bJHH-|QAWM)Fyw?``6~v|acuW6=j|>DS2~igZ~vjgM?5*Wb2(I}CI*rxG%7ARMiXGO#}w zat9gc!85bYofw=RKv);^^S!Dxi-q_xePOXyF6Nu!F6Lalu~2HIxtGhqqadpYzo~`MBlgNc-#U1lX+LQ}%0 zg6c;?$$TmtlZ;B{=X>Sis(TSvNaqVk=%*BVkD33ie`fwkI0-ZQl8H%z$4t|o1XI5f zj!{OY{$ViWgyr}$gE)6Sq{DsMP2q9>ikJKLATI@owecWV=05i)!TpQFG0MpO*9SxH z!2KS~t+m*qSb6|q{f1Y%%i!wUkxN7cVUL$5e~X2?DG1gmaMt}(1EU{e+ulvr}kv;8x*7EZ^ECMCZTQ+213%sn2CR7U2`2SZNi zm54!{JFDVL0V(2`6nq>Ag#~<7pRAYo(O|M<9om_sAl;(0X7(@@oX!RY7^#{;bu}Ge0alsGvt$x-4#M*eai3N9uVFjl{3IF0d z!Mt0_sC>TFD@#}3zpw--JbY+$&-mDp!yapg`)BQ@HDm3TxPOt(THCV(k2i+nmXXJI z1Vc_3nA;e{xpOnFbcA8g!N(pO^(5hGVAH3M@nkSfvMT4HjFKSTN{GRcaKti-!CQhM zpLa31+7W~OkMG^TXUta#FZ3@6?+K<#RzWCa6a?L|gebf-9JP$1@b+NH=Uo)8azx?K z*b`%;{+j5g`u!o$Q=Zs2bbM?{o;i50K$6x z{~&(MY9>l|U!uRp%HtzZEozinbw9@S*ZoW6H-fp7RU$LGE4F6|nf%Le+%n4KpE2Yf zW*MvQlHQWS;GlnKFJ1vSeuE*&TOX0u-kMpIgPw39LbD)zakiN zLKj`iAkLkedQ+N!;5g%jQcODb0K7kY zRQKX-7ks#H?`0i8tc`DbTU-TcRuxQN)PT0z62BA7v&`}I?yT&b!?)^_mn(Jm3ws_N zJ#=`?kCzPh&(ck6#?rwRS!()}VC}|mtTGysJAxr649RT_qT_g8bs4zK$iV)?2fZQv zG%)FNLh@uVJ+dm{L%Rs@9jJxGxi0XZF{ z2M`vEPxN|}17U$PUieC?b8?CUi&nOa!hUa+WQ;nu(jhOu-K!*6Vfqq-=;(K@s~zS>|5z)!t#HW8-}X<#zwQ-;9SYwNHmv5_1yg&Yol?o=cItG&b;bH3oe9`Xn_6A> zkx<7VT}>uLcYvH+VECl&aPG z$>MB1cDKn)|7@NLCuVA%baIe7D@7UD>~=B1@yT!`GjjatV8{wNt8<@Z5FN*T4<2ZD z(YQ5DG@^yY*6Ct3aUb9ZfLx!GvwsmxqO6MGK|49mE+KAD6N2*n;kafLlox^_pLapI z))$nSlrzG9sekeKgJ&dXPt2EZ2(1qtpIf5PSQVj?rKmWtEPH z!lWams|iur9gb{9QF(JPyfs{&@dl@zG$?WEBf1fhmhaIveR8CiKOJ!*R?g7%vAyKJS7N^EGCp z#n!y%YkaYPq4@P+vSbyCKwm?8mk@|AgyWY{AU+=q`Me86Eci9sUaXd9O0C#EfdAOP zRQ!D~ZL&&5VDQW7VnQ^&8IEK|(fFHS$md-&Zu5PM^08XI5fz_pM~&0P#YQw&KILhS zJ3rd@EM)*7)@GJ68s>+l^)(?Zw}xYzQCMychJ4?bE><@-~-bE*7f+(<#=sNsWPrbaOe^Gf` zFm1AmN}vgHx|k4+)8R;F6pa(Xkk7klyvf%pi={?sA%bQ}k&mD4Up_t=OrWgtF%qUq z;{8kr$xnu3no&r8JQ(tM7m^zjLeh*yl?QB9^)`g>+ zQCz;WTH?|}%A(DBlthyrK-jc{;a(S&EEbZ=)E5@#F5ygW!0eiE_Gs`p$*KxFCY%XY zofFQ+f(2QP1)Fg8FoSqiB%F=$Eu?7)XUBs{uli{d&gO$jm6dzRgfpLQ1;1YjZ4`xL zmQfo`cjxUnOgOv6qd}oGJKH&`@^b&o{$MysGp3y-^8>JK50$_g@M}H6!PKF>$%dgzkli2 z7fhk7$|KPKNOUwICVRqB%_t@h1w($-i3w%y6&v+-ZMKLg%AyxGInlqEG=nL$R$>zG zXhKXD!%@vBCJVuk&%2mh@0%E#iQ}q~AMam2ek7PQS>+>{Yt+@q*d8VX%qSQ? z6b$*i3&sXtFodR_*7&XdrQ$b(>5^3{?oI?-yGn)XUP2^(BOJkuBJpd%kk7kFZke_iJuRq%UX$qbT1(iuY@C*Q6zpk81i`+iJ0lor{KC%*FWiBCcY9(n5;4p zXgYNN5<>BZ;TUEViZ2I4KJP+tqd!aGY)!c^%=0-f{a1baoEHPc+W4HwgtD&F6St2E z;dp&GmKlZPwZV|jyKuyU=S?KHm#XFGqT(!e&BQid?(APe?g^$)R@L!9SbW3pX!5wH z?cs=K6p}5$kk7l2#Fp-x$IFYHbLj8fj`|mm>0sJq6_3EBd#8&D{ZR}@GNWib6Abyh zi^kQyacR~Y{yv8f_AeAK1yd!fP;3v>8PvIiI4p&umr)#E42FE(#bF>O4lCs+|8oE0 z@r%J!$|@eo{N%1qN4EUr&xWI$QC$9?V8|WBrH8a$n;9&5i9LX@nQ6sd6H_b}lKI*f z7HgHCd|To`Oe{fT`)MtjO*;znH9r#SmS+|3+d3VEY4AxZyZ_y*jM=2*|HUA}lag2c zG`vfWYPx&#pgV#Iu7;7#N4^ap)@B}bN5WzmW)*CA5;p3VaD*}{otuIoCzQ?&y@IgA zU1aK2Io$6|4EK{!>G-0g@`KLjUupHQ|L;j9VL!NNbC?!Yzlf81tj`|}E zB7D@Z{@J&eK8e0QDb)7{{@Gx%CkFm=!Gy}nIp;PCb%2b^vVz;E#OOa6j#b9d-|CU8 ztFFthatKi1rACjnKh-~LKM_vEjN1;JYcN+}t?F5V!9N;~TSf+dJQ#99y??Y<5LUg5 znDwRJpY0zDQDJ>yv4T(8!?0NS%89R|=WAn4uJ2$?k_O~2dZoTKAYbbhgq>Fi^?P8T zl|;F$pa&2Zi!b(iRzG2ZJ14$|YZ=as9c9_N-uf@?R=L{DE#l_c(y_?Xuebf^>c|-N zZKW$GZb4gN&b3lWR+esJ5FLrQs(a_UUODm5TG4HVD=^J->}+?YuBzhd&eRPK zQX~8m>-%L?SB+ZnXIFITh`HD(7j7a#2rbLMx*a?v`m@@bL2TYoHcOk@@4PJV}4!D6MC6yckJPoKW^ zjSQlrZ{1NRtwEqq)*{77yD4xF2U9(vi5?6lR940%{0^66>bQ{(e#ZmhNM%$&_jhON zIrKYJh9gs;@aWi6#UrB+9~kr8%4+}YEr(MwqvPSE9Pk({bYid5IVFAe8nd}@^fEGf zCKz(U(o8Xkj^n(C7}pA(s58tJHDjLWM}SeEp2rUc(g1NSW{4WA3gEu%F2QZVH6E)6%ky1`HRjOmE~(Z5vu zZ7_YZN`q^@$EE0JeD3n z*vZPhy>`T6AS}~>cR4~!iP_hBiqrs%g%D21XArr%}g4?B}4muQ$QmPJ0 zs-AieCDijb90CB&Zs1%<$b*}#9E~H zGKlc8zWO1F*B?zRf_y5N(1|hr^T8y_%B!2=V_Zyy^g`ibr=_oiWdPD*c*L+{Js*kt7A?*v0mDC+;jAkJNw;SIw0 znfk&sQnh2OzxWfO+A=YSUk?yrK26p^e0w+6tNtXJ|JrbTGBW?4|4(KsI6i4^47y@N^dcqSadjNulVtph;n-wk{PV$(J21Y7d6%8KiJ#d62pcu}iC(Rn#X{yQePOXe)ToCj#>$Dt zza1>?Sw;1_^eJOfKEKqf6xqq*7kdR^ML>w(1OKcDNQP<;AS@O)^pk7Ro^CI_p;e!u z`wr=@!v8o`ODX?TQ`1jE$7pYJD28 z8OP@GOUp}F3Gxw+4R(HAKU-fY;XImBt3=H&y=I30xwKKoJ@?Ji3)A)L^3n~>#rbmW zR6)u%3o`}t>cYcP=0nSabku#G&$@qn>9S^dnl5!3ovxpVmhJb4qiX#mzQ4Xa3+~{< zrL)mY75B-t%Jmw)UNl>uso`?D<;N@Ed%?POk1xHU+&mPyWnNsmq&PDVYBi$T^5pW; z<;4=*n?3fI_Vm(4_3279(<0W*7sl7MmoCAX)3sw!Giq_~E>d63`-^AFEkOZYpemJj z-Lh^SPVPU!|FoAbm|0xp?%ntk$n<_=oF0pdh9Z@lP{OB1ArAxTy2O9?$ z(cLRrI77dR6HA_;EA^WA+Tvx)VPJSt6d0@T0H@rxD1n-w9c~=q@~dJ&(tq)8lKKNn~kUOrqWghVawR(PM7` zk1x^VZCmj82t6*^hR6HqaqV_IeuW-irAOm#Jg&b7kKdq2?Or_IeIFjbyc3WALXX-m zJT7=M9v`O1@B?`K7Cl-cc--?K9)I@`9zXXm9v|3CpXl-6K0LlbkLw;KL}}y_qF3z4 zPY3DortiYzwc~jF6Fq+603Kg>9FJc-h{ykW0*{@C@p#`6JeH5*arCWtree&@Y-{K1QO9DN@iFT9^rQ+w&P6;YdmkT2-JizN5l4ye~HlyGA?$(AZ{`FyEa zjGk@tD3ZD)buY5ey~r~6BFoi_%(NG|Loc>@c+SsSK>5nIH)4cc8yjJZr(5$-5KEUH zfPM5JS!o%CvD(tlvrMmz=OaMLtT_k7^WdTsw zbMUc;_dh=7;eR2ix3hQ%piP+o?c0Co@DUHpzaTKLGx!W<0&`$A24w>&*Y_DH*T$fz zv(a2Se4c7p*}*c3M@Xqr*e6F6x)uK`Rs1ZpxAZ&C0k2}=(7rv}?%Uxr{#mjC7iI^r z5-@w!CkHU68E17)ErzC>D_&qdS^ftrW@Ft7{Ot6#h^*9 z&>e7v1m@j=FcBeND0u+yCb#OVaH|C1y@3Grsg*8{e@jl<#~#)o?+FCih!&%gZ|;5; zz$#A}N@5$Qr?Q%KfqgBidL4TS#hn3@>rkg~IIZ%}QsuvTM0X*-Qsu&)M@J7G9`i+M zH~FOh84n?CTwiLe4F-k%hYxyP_&Ndj6NAMSJ{DflYajJ`YaIf$3m=XTrDoI@X-;KC zid^N&<>Vq;&0>d6YE`vcOkaMf_|AYHCqVPh=>A%H&j6@UviHlmFmEQ;{qOJ)8tyhE z$PUxJk<11CnsI>s?|8(AQWnrLr;Pjmj|A|Om|O_Jksw?ZK*Sh)S!T$e1<=Z;AJ>q# zhe3A7JcIl9fK++qpa%C~5I7}Cvj_#0YsKTyXcRXFz*Y8Q z7Ahz{6vQILr0R{xzqr&z_z2)uuE*?FfIkujyavx|u@TWt-H5E0XDFnG#Uli}+%`4> zeC6AwjWD9HxvtWhln3*&rvP&Tb8*4@fgrpWDVh=icicZ82Yj67_iuk%1Kt@5*j)JT zQsDi7S7}dZprb)RQ_tUXp?@C$SDrS?HlgrkPMWIle*m?*DSW?b>{ehGhuERDY=pYQ-9to2Cdlpng%skueNN-r6KwZh85i~rfUR7N z$YC$?C7tq(>J5NZc??lV0T@PDb)kie;3Pm*9y;D5JTKJ1M*j(bs{BAz!wVZwu{j9? z{87NFd~-nqOlbJ7oOfoAo;ba>2B2TSL#X)XAn}atZg8pjWrAC(Yq(+B&pGYch50PN zRrVpWEVyn9!<7yTcA>qMLev*DG_-_m>q^cQZQC^fT)D;A6&oN_>eL()>EUz~6&$l> z!;ez&dZW}^!$08xjf zxu7NhrSb&>>J2f5dZhU_m9@CvWXej)jB@Gui>^nv=nz-M0UcU|jny-4Qz&g(jU~INNAlXdgQRXg~Ef4b2MG3ecn(k6E7ql*-UM z!a>OfJ{PM80Hw0-of?#N2Ufr;T`w}rt^~BoMVf4tFXEHi;%@qGrPYQ=rNs_gI$Q`7 z1mP7dhKYb}hzS_O@#yt?v~Xsdw830yQl3XSPu^|k@2J}3`*k}uHkGKR(wW`LFTV$s z-}Ah#JdlQDf!oC16;AN=P+msO%D;PW#_F6>>9+pcs9E{d7j<>(IV4f|3*jXW!OiZ)v&9zI}V_Ev@0$w;zhV zrL_Y4_S3Pq6d1K{KNovTfkgZESL|DMqbOEr-~LnVEln)#+npejq6XI``)uE`c@xDGGO-Ye*2d70+}iM_Gs)aDQx?em4>v-bxCR1x7Ao(8sGNqJ7aH2rp#Me zwqClR(d2v*wFWM!CKohYoXE3u>0+aPOb20+N}?9ZFRYfPBOEA(CGVw+k3}_ju+gdI z%4g8t{N|<0)w*}JK2yS3Z%bDdk2FfPCQ?KY%YC9zKSitF$h4_^=d}>yi%=hn5y;Sa z{eA}X!t(SB%S#u-!w|4Q;`FfjHov*@3us1HulypuEL|o;A?E_Puo;yaGl+csDr1#W z>(awqBKHKHs3@&^O;x@q{ki4|UbxT28fnvEiMTz~kb?WKi17S!<#VWA`F9Kg-v|qZ z3ce9!1^)SE=ETzL5$Zwq%-LmRE?ih%08UM$3Mf*Nepp_*avzedD6{Bjt^DlXGLpxc zjxQ}ETWGe*nOMt}KLF^Z%lFn#)~fZ=EY)aAv8Ai)jqC_+q6NB4-2;FRu4rQ0s&mzq{6dw}2fx$fKfK zH~DWET+w-dgZ~~;cBjc$Wx)v1Je44~be&%r2~@4qi-J+|l|lBZ;)!x}l9wAGWjLKs z*e=GbSyfhU+@?8!cUgaCH6?pgw$0-x$ zvN;A`K^?u<#q{EmDg=69m@C&-$L4g|y}U%D7FPTUX2PS(n&a_RImh^#BII?fU%wvL zF({JeIlQnd*D6ROrRqcrb0H{^36OpWzdt5|H90wyQ%Y)A&O<9V;(yN%4(5h;=Vmc> zcCF9hk9bA@O08zDl$)9Y@TsX>y@8La0emgjT6KO)b*H8Z>$w`V*@-gr)Un)5yV(L$ zr>4C2QSoHCTFoJWu+c!$T&^`Ap?7nocD0q8j^;}z%JoLU!=yZytJPaM={vt6{1Crx zH)@P{eo)$01xa+8tx|0!5_%2g@;-G22c@eFrc`c5xwq2I$778~y^$X{0))!7#da&V zfF1xRbn>tWHYiZak(wD$EwZA(sEV;fa{Zmf9 zgUChFf9}3&kPtx&M1DIAsoBKG1?a&^5ey|O0t+rRZ<_)%aFItBRC%W* z5k2IX4;U!;SA<8wY(#}-dph43xa;=(Gqalq-#jpstCkj~XG^5cX6AS0X674tz|Zs7 z!m&oZy_nxNI5^0pZAS(N5tLG+Q93OWqML3NKvUD-*m&mA%OwP@&O$^oz>>$(prno_ z7z-u-WngH47|lhT@gc*Ee=Rf@tL0W61(okD zm1;%e1_6Yi2!=>KsFpDB2Ob0;2Jrtj9#^`zDeG$S!NqG!-gpM{Cegs-^%@j|jM2Hg zhKTOEi&AQ=c6i%eR7vOouGOU0DFuj>`lKGBj%v`*O~`!++OY6MsRbdfIU|#S0dta3 z=3GieLr10)=~*U#P$gT%iCtVpFeO!GrAK36TIqyHTI(xUGA%QaIBv==5L7{pRO9eA zqWE|eLGMv6POd(eJ2@XU#OkzLb336GWwkzc5`M^B9d=p>&LBj4sMVNVIptUYuqLE> zWz0|PcX(d{-BN_~YI%swLW_nQWn8kxCTFSDbht<20C6J&(kj57;qA$CYd$|fc#jOk zO1hm?MtB&8-Auq*^B z<;3gh1};kxVrx2fry&hjLe;|c`%i9txz>&ZCUudhtyKzhWTGsBO)phK7iUCQo5jUC zhN?&!GYPk5&E^Lt!5f2ldJ&W$)+WIbt`J(b_xY69o1xDvt}v{Os%Z^6kaUN5grY;p zDLjI7+Gt1=FPjS6BVYj(rCFae0PYC-EW5T17SbV@G)`!?-6Z0maa7P+QjY|vFlck$ zr&`2rjak}0BK=c-CRO#72K~~x^@&|T818Ks9K_Dcp$LXH1eN}jL+099V%`Li0p!i? zvaa*sP@=Xn?I(5_6`(0|!lL9?a~K9{6P3skYx+QZIwWIoF*7jj$dsYuGfQZ{f*X_O zDK(A_lkcSbB%%*+9GHL%)4<}v;L$)Dn!rDk+7?<@8;&+Dv_a%Z;4rb!eybJP=oAV- z1a{@7>vfVBVl-NUp|^#Af-dLL%9+GroY)DR&hhqX0+17cPNv&9etcMhe!&iym0?zH zWB^UuP}Q1E9h;_f?vCw(OwudmC~+^v;{<7ubAlh>h3A>XV0F0`AHM7Ym@zD~yh5Qs z^E&{i(p`K*z zJqF<&@T5j4O@i69ttm;@?3LU_Cpm;65M>zTfM1a+16@#S!XijNCiR#tN(i9qr8!pp zjyFfYrH`BmdSzQkLKh_52_Uscf8sm2M5E6W+jb3adi6q*7V>(~!yJ z#c-8~h3={&flOl;jqdVwX6vpT3Bg&fpRB1wX$U6r6nx4}j+QV|?pyjy43<*6M{-*| znEEwwGj|)J3T*I&yQu|X*fFg|1ay$PuwwBPTBL#%^d7J-HjNue`18uA@Iwtr6Isg- zvI;7)3S!M8z{!d71&2D1+7tYq347C{=8xfk56;;2G$qXvdo~AgYXD73Hqf?YP!-e!&D(RlfB_A^kV76Z zRpGUa972N1Z8g6!0HCjRgo&6uQ^-$zPhnzm^B~kiV_@Q$ZIk$5T4p_|#l|L=3sp@i zgAby15+|OSZ`Y1DxmASSGlAA%1Hd3bJZI(J-%PoQ<5@o!crM zGviiT(L_V7iLE(&lLkd~=LcDrtKX8Mhe{gv!>v+t-oc&)R=GMtD-`wv55Rpwklh$KAg@cc5OUm?DB&$L8UZ%LeWoTyK~V^7J7O6yRlVJJ-f!tC~9*<>t#RXbfaw zGZb+d(41(blYoNwrR;M+q#ebWJfytxy05#^2@A?Py*hLt6n zh9L*LUNiWp_COcZpU{k_mIpCO(G1v+;4MWoHd3U%5%I472m!VV#jZ=Uvxs*94ftO~ znQAm=LcU%5>h^PPVB(C60e1rd;K{RQY$&azJVYona%u?%t0m(i#{AL2^;rMPFI^}a za(U?jECVc$Up0Og7CUe1GM8Ddd>boz&r%Kt=IFP+kS# zRk^#z>nL}*hrD{#82?vzb*Xwq9a1lTZ2WUCEVr@zyZJ6GTheajX60sN610|=>?)bc z&dERZJl-T%$>eo|7bk#Jd9EB^DoZSo&D0k$TatCOSwywyyR09PthLGu2vDlG>btz1 zYu9F4m~S=p>lv(X;)DwHND5Hu830X4$Hnti>EEJFzaF2QCW zfAe6lS@%mFfTd3q05fdXchCI=n}ueiYsyou$vXA!4iGc zoxKWZo0lp0sSEL>Q$@uEyG{Xp4@-=9@4H%{gXD@T((7|lsEPG8%#&z!jz=B2xwI-L z>#=&}4&v2$dCqICx8*s^1KSY2CP#m)##Cy77Jo^Z0YfsBYH>{FvQ9V(`q!BiF-T`c z)A9EJ2Sn2HFGLmX%Z_mph#!@(_z9phOM&<-kRmP7HU~Q;E{7-ryc;QO(qf#5L0q3p=|}l zkb;5?4LCf0d56G?S%B{s$5QbLr?8;$IAr9eE!=oE%K z^lws{10aweO$=fj5>%&B4$Ykg=naA;`j;UR#u2Nr4c{1oYQBl3bR3{ls$moDu3SQY zgT{&9^qMh=JN23bUAJjDg?>>#oIyopIhgEVPy95oboxSnsOrEKPJnF3qE?=MXJ5_G zNArjy^|f}j8VlAK=w`rR*BU8zgth#LH&P-fa%6*M{Cy}#VKe%XUV zSSc`8Aya>{?mCR3mQ6an=7&BFpul%ZZ zmTaonpZuaiA5%=e`bAW0JSLh&!;Tkh{>6+T$@@l$g%d-Zm)Nx(`bPrhX*h#Y@U!eCq z1rqo&e06bTC%EG(-d`DE+HGJ~bU+ zpqFyb-X)1(RG96&Rs#wPw*gu$&H`Q?vXI_HocfJKYS#W5gt0uU*Zy>9M!8P9M>*jQ zQCNNA2sY7ky(JwRMCHUQ^QgY%&zyyv$ufuN`6h0&6UN8*x%)~; zs8QriF+r*2jA2Q8t5mmh`a@bNYc|r}Dj1GsNGqlEgvSjneV~f^$eAY6!MGlb168qV zEgDK3R&@46F+m$B1(9&>)$dq46ulhBBcYGuqm#US@?@(G=yP176KE0&!Qb4V=2u%&F=^IoVd>QQFlfeoxJFCXLgAB6q=Tw z^D@|+I6@+ZKv}-pz9gXdMu{fLyqaPf_uuPuOibv?&AJQ^%zKF{+-whHl7-XpJb^)H zr&D?^=_imxT+(8wO*l|p?+2Y;M5!HqQ7VolhejC=&~p)OPT}nK44ubda64~hmq5}V zc<1y7#U1i{*im72rBKFu;Ur4gaEOEr>~vWN0FufQ2*6+_rdPhaDJM@kJVuO^kr`6D z&!>kfY!ynf#bFP%hQZS^>4SpNkun~~6g4N{`x^s7(-i?bcy`43Sp()?#OXbF zcEHKQNd+sY`!K<89=oueJ>4krd{Uu`}vR(b`daRvcY5!o1Lht=ysoyz!+7KQK*Isg zCNT6D#~fukTM??D07{AqGe(kGz#N-Z2PlJ1YKz|`7m71v9a^ivGc}b6I!mybNI;)R zhx^jP^rV`~0EleP;$j+#Z|cB@d^5RW$O%JY80CkF5Q=7VrY1@4T$-hoZ5(&+1GdHz z8qII}ED{2Z&H(-i*PPP??4Gd{RWwhQWo^y zbRbrbU42y+JD|*vjtw89s|c1?$KXujEX6F|7;!S&pqKQQ90BP$g4qYQz|~EoL2yXs zFTm7Sk$zDROC}LJNRs-ji|T)a)q}2R2nVz#s1>VbbrJe^MZ)RANdoFOtJ#vuyd2{M zOib%`(G+FzH1-N0o-|u-QY>ra$*uQoOKwRqXpm9ygrh@0?SdZ_Abn=sHWpe1FfpU2 z(#b_AJ@P?mt>eh366FUwsW}^4;RXeS8}ApbXW-az2&f(P9^sej=Hz3#Vn{h5vy7xi zvJ?a7n^Lbdt3IgP82qzm<~A0L4hG6+HxikhUQ5M|6JDXojc2WzR@#&Lj3m3}7Z$TRVkOOg9XFmC7Zt5}Ci2o>>Trdaq>AtgQ8IyOpJdS0sN(L* z;+5f(F1WJYPgG&a70?aur85I2@cu-7#Q*A3l-#KidiXz!YdWGlTCXiLVH+`@Vs$wT zsNVXoQpr1#`m0|t;l+$3e(@_neI;h}BWXXzsu^uOVimJrB&je*l0W%XtnyK4!^dp; zMUn!ep*k|;S5b4}5j`h1TyoTxuTrIv6;>&wJ-tq;s#w<|X_8e1wNPm)FgpGuSrRU# zgi2++W_%twju$EQqkgPCmVb>TIQ}zo7gd7elQ;|s369s9Uo!fG@H6|pOy3J5+lQkfRWk7MhNmIR^#m`^|+ zLULYvL3yk31}s!s4~0&rt-8ZI#jK$)ejVP)i&_O)SbZl5td^q?`LuS%f5T&aLZ;}?xzN<3G+R6kxZeyy0jp&t;~JcgsF9f?Vi2jP<40hsr>GTLXeBpB-681OY{BBA+9IJHbM|1(>e`5i8#$v?I6b&}TX6T8`7 zq;q}{3OjmeKTWn5;h1BANQ|- z^6_(M`w%kRTjd!XH9lXL(*WoM9(9|H&f$fm@^U2pwG(vkS6W8~E}1$sQkt2mH}qDB zDXc5!=uVp41M{ucVsqD)E!0syn;>cw%28{sP;VUDg6s0O%(oV*TU4XFr;0oti1YO4 zDs?-{xO4kf3a4z=X%QX!K}*~H_k*AW^n;3b>&MDkUPzl%@`~hX+FiI^q?4^g!4vi5 zM;Hb2)YFm!j2RHf`J()5T8h+c5*WmRf=Cx8;7xT|o#+jquUN?Rd zDqSd*)Ni+p-^ms(U%7UN(sGr5zDIw`-={x~&^=3J0Na)Sje_ub?6II?04ds8oMS}; zzvsVR=qW<{9m51KUrWToa zOmV2#TSABGqggUd@r;g4kLcXHO)MA<0#|t&jB;%mxQ86xpwZU7E7JnceVMO@LGf^`fWkaHFG*!^k42wfj+WLi!Ufs}?>z=}~ z>`x@5)vlCXY1&|iic#%msL(q-WYa7QNvP5QG4rA()Agiz>69X7?2SbzU$mbMax2&! z>s=Fa8hM?y$@+#wP~Qhfs$YMG?zin3yTmwX|7(!aU$Ec@3>1o-F?r!>eGEY@1L47XvuaB;KUy~AjG4|#YTo#04{{d z5O5gsTbFy}*c$SUavjq+SO_y}r8TQ@f%>r-`qNe%)vR2JZ=o_=iR)wG6P@-3KjQZUK*v7)+^`vp~|Q?3Qn9P{#Wy<66lXxQ6uRA#A3!;hFl(OdF-KK8nD=)D&fdm1p?Sge|9r zPo6wEOzz}xyMbk9-qtiV#e;gfJ}ZlTbf)NB3~C|w1oVG<0qb)> zvf8Xm;Zk#^T*l$D)=bDX zjm$WZ*x}jO_B-$2bLag#9CpDrAqFFnmBpwr14$TGR_q8?7LmL*LR;89C&wsQu&N^nNg-Am=A!Y- zpm{FVGOm7o!}uE|Aor(Qi8L!;9AhPtxGYTe(CY(r(;WGQBAB{g9`b|YuOQ@_8vm$)OX>#AA?0FM984BFcN=FA z@ma?sGCNA7HM?im5**-gn9d!kgJTr)hP>jl^pB5TnVO>WpYSu%30R$wiXjebLFcoK z?Eq4waguD-7C}~dm_#(?Q0K?%Ejp=}j|QkB&WmnYQjwm557;Co5F9l^hJ{kAPA z3gCYYCk#@IMa?mWfJ|xPe*HHIw0LC~)|f1Ft8`rQLg-9r9I`P}!gPg?$^eR(vACyY z!)(sCVNx|QgglI$5F3@Lo9giLSs452)3CxgZyMy+G#3s64Vik`p{H!BdyuTsbN0AZ zaQXeX4?E&=-0qSn}{#VYPAZRF^jKjiNKAgt~Je!|4?cm(U% zsC42B}<@$39*6}Qt_G2Vu8`qr%Kgpx%v7@Zp84J zd|vHxNwjJ|A3lTOjszg`%h`H}wgmg2-K0l~2&V5WBHpVceT2JSA=EdNfXw1<15yuW zLZJOcpBICQs31W=GJ)yJS{_$s)?4f}khcGtq1TV-Wp-QwqJP)({O}ElRjn z0l>tYQx1p*iu7T$q|`dM*~Yq8qfE}k3DKO2LXL`|L*qN>m87$R-YLxFS_R-yf~5e6 z;buf#C#m5=v| zZ8Nhl+9?>Pj!fr$p%k$mP+Ojr5;he{GL7!#qttma0NXVz%4o5Kbz7)U7AfEH%Iy(` zdG~107uC4yhVWr$+VtPU>;@_ipN8nO(@2wk2o;fr)PklBITqf?XF;S5``S^Yiy!K_ zd%$ybLK|%ZbgY}4vX*MyAa`o!!=4Ns$EN*;Bal$3Db{g5sxCs&K!+a#PjjVdLo*LM z3{*YvMKtgY?j2b%8CS}Dqg(@i-~#qhD6il+o#YPRk%DfeCQhcJd1rG0_9BN#1l$(O zbTg#1Kc$oMuv!oI0XG5hHb0umQ}yr^$5s>8|H+0oG;a*rN)>;TCKU3U&M zA=jPf@>5fH-Hvl%-aIvh4G3wY*I>h325aaPVSRQrrxKF`P5J_pGD%d%P*l?Zszc+H z+H1fIf(C}G<-V|G{a1IQh)jU#`G8M+j%n&LH4bf=<<}{tXc5;m)8wsEm!Nce>sXM*UE@+hC z#o+cD7ECHmWKy16%$>#P%N6OU{T7Y{EVqh9?1HS$Ir{}b{3q~sSUIod=Xe&(@=Uy; zKX_nNsbFWC#TG^))O179SCePQ;PKb~$mRPij<4HQYoqi6Yjt^yzHqitHew9KE#sS}a zC_G*FiyeT1@QX@7O3~E|ND1LO2BbW?nt-~ZGe!<@>l~2s$xDK1W#6cgRSZaxrAJ5! z<9vl^l*AIPwTYj#V34!J3Im*!2A=TIB%z==78 z1Xfxsfjj{X`21McV4qwqsc14f>4at$!E0S$OQu-{Z6YRME6g$CQYO-FXzF?>W(+A` zgPjHCvS<;oY!X1O%`-rIRU2b$D6ER0pfDtjdP%Co#IHeVxEE@Mlf*+D2p#B^Nz5M1 zZ%cZfKQ*N)i4VkE}D1h z-VCDW{L>VP{y zc=%d?i;%jovmhy;DY}mhqdqYSze@B%=t1P&nA@n)Lx!p;0Cr5{O0JWo2DZP`m3*x- zcKHcAzZ-FWA_p%iLKXnUG|FbcHcHvF24-rbo3)ccR#5iScuH7L3~eqb`L(1wQ_q^h z08SYInv$fkg-Oy9P^j#e8l4@hDEc+m`jZ{ zN*h(9!vp{b6w5^=gw@avwO*g5L;=PQOPzE}9vx8N243Ru$+FN;aA3nQNW>238^C`T zW!j>392ya6|bEOnPkZnuKgJbI~Fz7y62!}Hb zWO$^1KrYd2ZZyzUe0&$J464~WB#**=e7FwH^R#vZd{+3%*jc@-Hae{;HEHTO!Y$EF zjEfEVtagDtqz1|9B&}-oVH`~rsXKmXrYlr!$Q+k0=5=LNP9DThG6`^|;$2wId#P*n zXA!U6w{x34xBxuS7h0%Bb9_uZLN!b*;vW5}EL(jt5pFrdc1BE!l~;(_mwXom4IhVI zY9i<9Rx}hzxq57&+?-KI7CfX7z;L50EP0s4iJ?y8j%jW^T6#U`kkga>Nx6qV#tX|L zNfxP9+K8^s0FzDHV~(d6JIM#Gf8ieJU*A*K$Msn$9{t<$Wj`5+(b!u)L9M1-va*|Oj zp={wm^sEYAA{h@71q&pe04pIHD>fJj<-CV{Vi@MuNsPQPFUF=l2v1J~AL@>C-U>HD zX_6F=9Q0hmZ6YzI07H(I;NP5$&j!fEfH0>qK$6ZZ z(B>fppkJDS8fzlNbnrH9&;bD!DY;kXTCd|sA>%N&3YQ)lKZ0=SO@0w?kf?$s-X6Un zUXXaHN>s+%6nXVZsL1Q(^ok;{7f+hV>x1}+$gAB_OKaQJX2BdQkL0~^*-~px$5Am= zh!F?5m4()ul}#}dBs|Ottp(Mlg0XI@zG+CiS!T9~06VrmQi#R9Swe)DZg?-|XR7WA zb|j^o6a)oDcgmaUDw5BQ$AuIi3br8(!sGz-i$G@Dh}h&!H{ntM4Mf2$PDYTFKzk5G z9Ii6;bxp;;OU5q;|1L4F74Ke0KNIgh*)+WSb$kTxZq}Jt1;x9QI83v6vO$KW0rvfc z+8B%66#fae0>N4iz*5`+2XC5_Jh3FtQzV{OAsRuW4jve;+~K*uDDi;kIHofa757pc z(>BdJN2wUO8C@-mX^gTjLWYn|nqmftBq7^)Ua#VihYK6%DZWE;<2-pNR8%huF*r|{ z6tAfe>!$)P7zSuWPmySi+y(iO>(R;^4h?{lk;kc15b~Mh@|!N?!Ku&Q3jWq1%DXFiznKMR*7`Q~pzdgv1+^GGRDUq_WrCE1v>q*>{mZl3 zGsP@la56n$otZdJz5BtkrZRQ4fN*=>v|taT;CA9KO-*1W`2o8fLYTMdNIj-96%`wy z!vqAK5k=X7dUrF`re4E&0}@bL(tDZ->4V8E8M!HBs#nRR@$JO{f&C##r z)@kIy(YAh-f`ZU0>6vO7yV@Em2SRDvMzp?@-o+*j)F`muuh$3LwP)K%Z4Sw5$Goe^ zxM~>Wpx_WEEOKL|QCoLG|0t!kJ9>Jiju;=C3eu0#@$6kBQG1B3bL^0VHd2dbN{bO0 zdKv(9gaI#Gn0>rP5McaAb5EQGG3kP5tXWZFt^~Y@q!=}787uc)*qC^D26LtsZh#c{ zHq>B6&zy*W+X}0+Mg!~m95Q%Id?Z3t8$NoN4n}BhIT=lFsQ_k^VQw+Dbjz`7eY#Xt zmufe+=*C=>&FASh3M0dL2>qSU~>n2>I}cQAI8m9A{HiT;KDY&z{zwW}j1^+LZyk#vCVZTV?tz z_6oLj!!>f`1xC4Rh@@0@L$tE3)$23bM(Xd9iG#kEk^ZS)qTBRU-chEHeldp6A*NYv zIFp#R1|mx-Dg_AQk->ONP@uc<4y73h_oHJ^6_1QQd|-_91y3Ewg2^3s7=z;B&JEmo zrd+@^uYB@+e%nxP<8=Ah#=*jTbSghsz&TBrRSy=P!%Af}za1yBv;SBo-&T&4-hL0P z0jn^mlSi>{s73K_ayT%T&Ec(0!)T&}sE1U)LJc~j4pVg_^}v+S%L$Ic6#7#TNj~W{ zXQ{MG9?CiNPoyc+W1^r|Tw-mAx!t`JQvu}4m4|YC*F6b7Z);i&4+S^9&(k*Ad+&Fc z&Dr+N(wy9t%Kd<&Xpo^^+@2eKc+cLkeUCi4|GUNyJofm(C*E@C@R6f$ee$XAe!4V0 zgZcKc`EuoWb)i;Yd=_V(wNIQpb^5ujIGq6}BH%EDhc*>A4;Qw0FfrXr8iD-QQ#-ci z9)QC|4}7_w7n@)gyt;%FXoS*tZ*xlDGs>k$hoA0H`d+v6eNwtK{9IaT<;mT>m3seB zmlE4Ysl=u(CGOcrC5l~2Y~M>IhP#z`m`ZH!R$`1w$TBO@NB@CN+AC!|d@fKaqNI#a zGU0YO^4VsT36R$Sc2ZgW<$g?|(PCaL3+wh`E;Rj|$z`L0=^h^>1>!&|%6BLn(CQjM z+<G}Lxm+TK+k-%U4TB)y01?x>g*J6=4M%d>t`FBHo%5~92^ z`rWvd$~_~kt35T^lVvN37 zP&?1*5IrJ9V+b06_@DxS1!T68X*bw)fQA~KfH8JX{doK+rBzEH5JNaa^VQgNHHDru zSY`Ip|9qfrCIok{JR!i)=Yu}Z(1h5Z5KL^}C3DZSbO4Bzc48s@IgVXHIX6NQ$QdWZ zrOcv3CJV0~2LRl$N<=yjtxKFj&|+mHw4#Yw+0@;~Fy3yYQ6oV{Xf=#~2XhYCX~w^k zs~~KD)tEy~B>I}Te4x?8d-m^75Hx16XufPF8WS^<-3(vH=A^ytqFh&K zG4Yz9PNe=yZ+!f=p4ziD_cn4ocJI#JJLrT~sI2=JueVdxyNkTXeVuBi0JI8LgE!uY z{(=5=$iH_d_6M>EBIudVqhHdaeS^6N9>{ImI>=(=#NwUsttp!1y+3+Vr8c`P z?{j#yvsYe$%PWwa=<;gfwxODF6Xd2cp{hNCz27fY?t|kmQ<%>wr^0+!&KYi|d^`|es(**n;LqP=m zZip?W!JRSDzHcE~h`v)Ci^f8O8_uHP zXp-oG>o2j6|EjW&7wctn|~#C4i+4!Qk^+ zG>+;-^@yn~0G02GFqeXfPPGu%!Z!0VQk2DzV}X{o+9TjfENnmt+Twk7*Mpt z!4Xpv0|5u*V70Ntw4xO9BYk8%`a$&aAXkngnVhe^X!iQUS6!0I;J#XNUIb@!1In1k!TL@2Fo6{O? z73k=5ZdQ*s;ofXfIEOt0G*g2bm+vaIOD0i}mTIJ~#Z^PpudQy-+mzcr3H47D-lQ{O z6?|KQSKVk#FI`6H>9tuk2wz8Q+jM6BiFc{N)T~Uun+MZ|*kIyiUWCoxaa(HGoL+~l zP0!R9Pj_6M*1AlGt@U?EG(-uxX01{m!E=@IgupuyL{e_CMT(DFp}94FRjGz5P_A>N zY}%PBY!a@_Qg`<_d1fM!QF|!WMj$MDEV8qiRtaC@xw`u5CY3}&i5e7xrGGilu5X*C zR+{xT4i)rbA2y?>699rl*}smvqsWM39b5uJz`gHCUE)!pR{k`idwDx_3`^aJ4S!)Q zJx1N3L18Li+0P29ghJv;Uk!s2Bh=?X0w=B((B)4#oUKCI(XTIXM>K6osRN8zPLXZx7MUZAdQBdMmrzVnFLv`L}hp-GkX z-=!- zCM}ybDF%8{L%5x_1aeSK#@r&ATv8eRN5U;WqjFw4s12VyVk(qyq(sM)66(7!UJqzC z8j7n>B8F?ad@Ed)lqGd*7_OGmY+#GRRqac|nEQTA%$o+KEx~OcV)EeA%E_!Jre%>{ z9{4e!>BR9ELG~0;lf}~rT11QVA+=6*x~8BIBxX`yoIB~ezEWA-~~;L+`@vdzuv1`Augec0!1~2eg)F(@VGs+9PO?~ zV)`T;p`%5dCm?IpT4dCmb}uMsl@132X(s~bn@yQHp4sQjv8IxNvNvgC@AK&rgS*xy*U5?aNnO##|M?teiB%(;R9L;>V zNu&@^mP`Ep@;zI(tFtCGd5MYyTTPDvp6kO)^#}`O{ZdqKg8MKzA)gubNe4G-0-SSE z=Sdb|73g=&mb^9;r>Qqw&3j3}KqcTu)e$ksql_cb^q&4ODE)CSKTBoDSxW$?a_V#) zch-b9-HB|+YL0Q|Du$wdA2l}A5_N}F18rWIljF$sd-}J7U(Ec`KAsjM5XDLlD04Qw zS!zdDMe`2*WU5kB1Ea`|C{Z$fR%K*oj=kx-NJF5wP+C-}A679dHG`IP3V!-utNG+k5ZX?B|sNx3izsjFwHJ9_I0tsDEDRdnV$an<3| zjY_%$%7;U(Fc4-|*%#vY+(kgK!An9}QC6vT7WhQDl#$pKK2tku1D)o;nwVNvlJJOH zE90Tz_?<21hUr$}a7m(Z4k;utqH&obMy$N8xng3VMndOz)%U;}9Y-~GB#a88F8cz7 zg5Bkbnx>)8_JZo`zqmXxBo-%Q2o!bc$7T^HArx`rPN_;`13nFgVh?hMx;`gT(db#~ zvVrd;bDG{-<`U3|b}NgV2Gd~ z3co=RnD$*;(?mivo1ew)<#0E+2t`Zr3-T4zFFqJ$%lI@yBaT#2?>q)9%UJKlcCE6B zdcO3|Vn>7(Imd~ZMQSd;@UcK`QqF|;ZLlHqaeImsDrDtM4Qf^Y@t9MahiA8GAKGt& z%A%d)+BpFuOoufb`nO{v^b!Ebx9K#1h`kfXF+m_grF5Vxe3unekp7YpNL6Zf8|A~z zZtte*;Pp)7dbT{yr_yU@Gyqk6lA>d@B!leSuJ2hDikEH)hWW!Db!9s(dlOjP4}x1t z$R|p@Ido!Ez7&&^Qas$IX40ieoFuR*KOHMR-J$sOJhz*KQ)a6sHc@ zGr?51^-|ygAskc8Bf}_eG{FsRCUZj)teFl(kP_2|HuiKO&0H6x5$3UK>`e;P^e&iZ^>i4PcwD*1XYY#wThxN`%RP1clfDQ&kBx zl*qsUVP-odvgPZ!6tL+D?bLOh)}FHH-yySo#m3CEJH02dvx8Ewg+;kM{v3h{b4iY(xsv#IUu6aI<6d#kXv=Ryijv8_3GI8 zJMn6RQmo#5O_g}}`1hm4ZK_1)`G6|EH2y;qQTFv*R^^;sPCs$Z*~a(i m{IX}B*PlM}Uj1q5Mg8gK_vud?->*KkEBjEnwcKt`7yf@*6`O4U literal 0 HcmV?d00001 diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a3dbb60bf67414384fac5c2e1b925f36f2310005 GIT binary patch literal 25164 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 literal 0 HcmV?d00001 diff --git a/.doctrees/qs_codec.doctree b/.doctrees/qs_codec.doctree new file mode 100644 index 0000000000000000000000000000000000000000..73835c948cdea50011e9d0553deb79c4c018d15a GIT binary patch literal 23946 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 Vk%ycn+sA7XXb9Ue{*r6se*ufJ0p$Py literal 0 HcmV?d00001 diff --git a/.doctrees/qs_codec.enums.doctree b/.doctrees/qs_codec.enums.doctree new file mode 100644 index 0000000000000000000000000000000000000000..608e13bdde1a9ae2f02d84efac22212bf0622a0e GIT binary patch literal 84576 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 DW&;Pd literal 0 HcmV?d00001 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/README.html b/README.html new file mode 100644 index 0000000..605858d --- /dev/null +++ b/README.html @@ -0,0 +1,942 @@ + + + + + + + + Decoding — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Decoding

+
+

dictionaries

+
import qs_codec, typing as t
+
+def decode(
+    value: t.Optional[t.Union[str, t.Mapping]],
+    options: qs_codec.DecodeOptions = qs_codec.DecodeOptions(),
+) -> dict:
+    """Decodes a str or Mapping into a Dict.
+
+    Providing custom DecodeOptions will override the default behavior."""
+    pass
+
+
+

decode allows you to create nested dicts within your query +strings, by surrounding the name of sub-keys with square brackets +[]. For example, the string 'foo[bar]=baz' converts to:

+
import qs_codec
+
+assert qs_codec.decode('foo[bar]=baz') == {'foo': {'bar': 'baz'}}
+
+
+

URI encoded strings work too:

+
import qs_codec
+
+assert qs_codec.decode('a%5Bb%5D=c') == {'a': {'b': 'c'}}
+
+
+

You can also nest your dicts, like 'foo[bar][baz]=foobarbaz':

+
import qs_codec
+
+assert qs_codec.decode('foo[bar][baz]=foobarbaz') == {'foo': {'bar': {'baz': 'foobarbaz'}}}
+
+
+

By default, when nesting dicts qs will only decode up to 5 +children deep. This means if you attempt to decode a string like +'a[b][c][d][e][f][g][h][i]=j' your resulting dict will be:

+
import qs_codec
+
+assert qs_codec.decode("a[b][c][d][e][f][g][h][i]=j") == {
+    "a": {"b": {"c": {"d": {"e": {"f": {"[g][h][i]": "j"}}}}}}
+}
+
+
+

This depth can be overridden by setting the depth:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a[b][c][d][e][f][g][h][i]=j',
+    qs_codec.DecodeOptions(depth=1),
+) == {'a': {'b': {'[c][d][e][f][g][h][i]': 'j'}}}
+
+
+

The depth limit helps mitigate abuse when decode is used to parse user +input, and it is recommended to keep it a reasonably small number.

+

For similar reasons, by default decode will only parse up to 1000 parameters. This can be overridden by passing a +parameter_limit option:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=b&c=d',
+    qs_codec.DecodeOptions(parameter_limit=1),
+) == {'a': 'b'}
+
+
+

To bypass the leading question mark, use +ignore_query_prefix:

+
import qs_codec
+
+assert qs_codec.decode(
+    '?a=b&c=d',
+    qs_codec.DecodeOptions(ignore_query_prefix=True),
+) == {'a': 'b', 'c': 'd'}
+
+
+

An optional delimiter can also be passed:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=b;c=d',
+    qs_codec.DecodeOptions(delimiter=';'),
+) == {'a': 'b', 'c': 'd'}
+
+
+

delimiter can be a regular expression too:

+
import re, qs_codec
+
+assert qs_codec.decode(
+    'a=b;c=d',
+    qs_codec.DecodeOptions(delimiter=re.compile(r'[;,]')),
+) == {'a': 'b', 'c': 'd'}
+
+
+

Option allow_dots +can be used to enable dot notation:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a.b=c',
+    qs_codec.DecodeOptions(allow_dots=True),
+) == {'a': {'b': 'c'}}
+
+
+

Option decode_dot_in_keys +can be used to decode dots in keys.

+

Note: it implies allow_dots, so +decode will error if you set decode_dot_in_keys +to True, and allow_dots to False.

+
import qs_codec
+
+assert qs_codec.decode(
+    'name%252Eobj.first=John&name%252Eobj.last=Doe',
+    qs_codec.DecodeOptions(decode_dot_in_keys=True),
+) == {'name.obj': {'first': 'John', 'last': 'Doe'}}
+
+
+

Option allow_empty_lists can +be used to allowing empty list values in a dict

+
import qs_codec
+
+assert qs_codec.decode(
+    'foo[]&bar=baz',
+    qs_codec.DecodeOptions(allow_empty_lists=True),
+) == {'foo': [], 'bar': 'baz'}
+
+
+

Option duplicates can be used to +change the behavior when duplicate keys are encountered

+
import qs_codec
+
+assert qs_codec.decode('foo=bar&foo=baz') == {'foo': ['bar', 'baz']}
+
+assert qs_codec.decode(
+    'foo=bar&foo=baz',
+    qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.COMBINE),
+) == {'foo': ['bar', 'baz']}
+
+assert qs_codec.decode(
+    'foo=bar&foo=baz',
+    qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.FIRST),
+) == {'foo': 'bar'}
+
+assert qs_codec.decode(
+    'foo=bar&foo=baz',
+    qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.LAST),
+) == {'foo': 'baz'}
+
+
+

If you have to deal with legacy browsers or services, there’s also +support for decoding percent-encoded octets as LATIN1:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=%A7',
+    qs_codec.DecodeOptions(charset=qs_codec.Charset.LATIN1),
+) == {'a': '§'}
+
+
+

Some services add an initial utf8=✓ value to forms so that old +Internet Explorer versions are more likely to submit the form as utf-8. +Additionally, the server can check the value against wrong encodings of +the checkmark character and detect that a query string or +application/x-www-form-urlencoded body was not sent as utf-8, +e.g. if the form had an accept-charset parameter or the containing +page had a different character set.

+

decode supports this mechanism via the +charset_sentinel option. +If specified, the utf8 parameter will be omitted from the returned +dict. It will be used to switch to LATIN1 or +UTF8 mode depending on how the checkmark is encoded.

+

Important: When you specify both the charset +option and the charset_sentinel option, the +charset will be overridden when the request contains a +utf8 parameter from which the actual charset can be deduced. In that +sense the charset will behave as the default charset +rather than the authoritative charset.

+
import qs_codec
+
+assert qs_codec.decode(
+    'utf8=%E2%9C%93&a=%C3%B8',
+    qs_codec.DecodeOptions(
+        charset=qs_codec.Charset.LATIN1,
+        charset_sentinel=True,
+    ),
+) == {'a': 'ø'}
+
+assert qs_codec.decode(
+    'utf8=%26%2310003%3B&a=%F8',
+    qs_codec.DecodeOptions(
+        charset=qs_codec.Charset.UTF8,
+        charset_sentinel=True,
+    ),
+) == {'a': 'ø'}
+
+
+

If you want to decode the &#…; syntax to the actual character, you can specify the +interpret_numeric_entities +option as well:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=%26%239786%3B',
+    qs_codec.DecodeOptions(
+        charset=qs_codec.Charset.LATIN1,
+        interpret_numeric_entities=True,
+    ),
+) == {'a': '☺'}
+
+
+

It also works when the charset has been detected in +charset_sentinel mode.

+
+
+

lists

+

decode can also decode lists using a similar [] notation:

+
import qs_codec
+
+assert qs_codec.decode('a[]=b&a[]=c') == {'a': ['b', 'c']}
+
+
+

You may specify an index as well:

+
import qs_codec
+
+assert qs_codec.decode('a[1]=c&a[0]=b') == {'a': ['b', 'c']}
+
+
+

Note that the only difference between an index in a list and a key +in a dict is that the value between the brackets must be a number to +create a list. When creating lists with specific indices, +decode will compact a sparse list to +only the existing values preserving their order:

+
import qs_codec
+
+assert qs_codec.decode('a[1]=b&a[15]=c') == {'a': ['b', 'c']}
+
+
+

Note that an empty string is also a value, and will be preserved:

+
import qs_codec
+
+assert qs_codec.decode('a[]=&a[]=b') == {'a': ['', 'b']}
+
+assert qs_codec.decode('a[0]=b&a[1]=&a[2]=c') == {'a': ['b', '', 'c']}
+
+
+

decode will also limit specifying indices +in a list to a maximum index of 20. Any list members with an +index of greater than 20 will instead be converted to a dict with +the index as the key. This is needed to handle cases when someone sent, +for example, a[999999999] and it will take significant time to iterate +over this huge list.

+
import qs_codec
+
+assert qs_codec.decode('a[100]=b') == {'a': {100: 'b'}}
+
+
+

This limit can be overridden by passing an list_limit +option:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a[1]=b',
+    qs_codec.DecodeOptions(list_limit=0),
+) == {'a': {1: 'b'}}
+
+
+

To disable list parsing entirely, set parse_lists +to False.

+
import qs_codec
+
+assert qs_codec.decode(
+    'a[]=b',
+    qs_codec.DecodeOptions(parse_lists=False),
+) == {'a': {0: 'b'}}
+
+
+

If you mix notations, decode will merge the two items into a dict:

+
import qs_codec
+
+assert qs_codec.decode('a[0]=b&a[b]=c') == {'a': {0: 'b', 'b': 'c'}}
+
+
+

You can also create lists of dicts:

+
import qs_codec
+
+assert qs_codec.decode('a[][b]=c') == {'a': [{'b': 'c'}]}
+
+
+

(decode cannot convert nested ``dict``s, such as ``’a={b:1},{c:d}’``)

+
+
+

primitive values (int, bool, None, etc.)

+

By default, all values are parsed as strings.

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=15&b=true&c=null',
+) == {'a': '15', 'b': 'true', 'c': 'null'}
+
+
+
+
+
+

Encoding

+
import qs_codec, typing as t
+
+def encode(
+    value: t.Any,
+    options: qs_codec.EncodeOptions = qs_codec.EncodeOptions()
+) -> str:
+    """Encodes an object into a query string.
+
+    Providing custom EncodeOptions will override the default behavior."""
+    pass
+
+
+

When encoding, encode by default URI encodes output. dicts are +encoded as you would expect:

+
import qs_codec
+
+assert qs_codec.encode({'a': 'b'}) == 'a=b'
+assert qs_codec.encode({'a': {'b': 'c'}}) == 'a%5Bb%5D=c'
+
+
+

This encoding can be disabled by setting the encode +option to False:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': {'b': 'c'}},
+    qs_codec.EncodeOptions(encode=False),
+) == 'a[b]=c'
+
+
+

Encoding can be disabled for keys by setting the +encode_values_only option to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {
+        'a': 'b',
+        'c': ['d', 'e=f'],
+        'f': [
+            ['g'],
+            ['h']
+        ]
+    },
+    qs_codec.EncodeOptions(encode_values_only=True)
+) == 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
+
+
+

This encoding can also be replaced by a custom Callable in the +encoder option:

+
import qs_codec, typing as t
+
+
+def custom_encoder(
+    value: str,
+    charset: t.Optional[qs_codec.Charset],
+    format: t.Optional[qs_codec.Format],
+) -> str:
+    if value == 'č':
+        return 'c'
+    return value
+
+
+assert qs_codec.encode(
+    {'a': {'b': 'č'}},
+    qs_codec.EncodeOptions(encoder=custom_encoder),
+) == 'a[b]=c'
+
+
+

(Note: the encoder option does not apply if +encode is False).

+

Similar to encoder there is a +decoder option for decode +to override decoding of properties and values:

+
import qs_codec, typing as t
+
+def custom_decoder(
+    value: t.Any,
+    charset: t.Optional[qs_codec.Charset],
+) -> t.Union[int, str]:
+    try:
+        return int(value)
+    except ValueError:
+        return value
+
+assert qs_codec.decode(
+    'foo=123',
+    qs_codec.DecodeOptions(decoder=custom_decoder),
+) == {'foo': 123}
+
+
+

Examples beyond this point will be shown as though the output is not URI +encoded for clarity. Please note that the return values in these cases +will be URI encoded during real usage.

+

When lists are encoded, they follow the +list_format option, which defaults to +INDICES:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': ['b', 'c', 'd']},
+    qs_codec.EncodeOptions(encode=False)
+) == 'a[0]=b&a[1]=c&a[2]=d'
+
+
+

You may override this by setting the indices option to +False, or to be more explicit, the list_format +option to REPEAT:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': ['b', 'c', 'd']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        indices=False,
+    ),
+) == 'a=b&a=c&a=d'
+
+
+

You may use the list_format option to specify the +format of the output list:

+
import qs_codec
+
+# ListFormat.INDICES
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.INDICES,
+    ),
+) == 'a[0]=b&a[1]=c'
+
+# ListFormat.BRACKETS
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.BRACKETS,
+    ),
+) == 'a[]=b&a[]=c'
+
+# ListFormat.REPEAT
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.REPEAT,
+    ),
+) == 'a=b&a=c'
+
+# ListFormat.COMMA
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.COMMA,
+    ),
+) == 'a=b,c'
+
+
+

Note: When using list_format set to +COMMA, you can also pass the +comma_round_trip option set to True or +False, to append [] on single-item lists, so that they can round trip through a decoding.

+

BRACKETS notation is used for encoding dicts by default:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': {'b': {'c': 'd', 'e': 'f'}}},
+    qs_codec.EncodeOptions(encode=False),
+) == 'a[b][c]=d&a[b][e]=f'
+
+
+

You may override this to use dot notation by setting the +allow_dots option to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': {'b': {'c': 'd', 'e': 'f'}}},
+    qs_codec.EncodeOptions(encode=False, allow_dots=True),
+) == 'a.b.c=d&a.b.e=f'
+
+
+

You may encode dots in keys of dicts by setting +encode_dot_in_keys to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'name.obj': {'first': 'John', 'last': 'Doe'}},
+    qs_codec.EncodeOptions(
+        allow_dots=True,
+        encode_dot_in_keys=True,
+    ),
+) == 'name%252Eobj.first=John&name%252Eobj.last=Doe'
+
+
+

Caveat: When both encode_values_only +and encode_dot_in_keys are set to +True, only dots in keys and nothing else will be encoded!

+

You may allow empty list values by setting the +allow_empty_lists option to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'foo': [], 'bar': 'baz', },
+    qs_codec.EncodeOptions(
+        encode=False,
+        allow_empty_lists=True,
+    ),
+) == 'foo[]&bar=baz'
+
+
+

Empty strings and None values will be omitted, but the equals sign (=) remains in place:

+
import qs_codec
+
+assert qs_codec.encode({'a': ''}) == 'a='
+
+
+

Keys with no values (such as an empty dict or list) will return nothing:

+
import qs_codec
+
+assert qs_codec.encode({'a': []}) == ''
+
+assert qs_codec.encode({'a': {}}) == ''
+
+assert qs_codec.encode({'a': [{}]}) == ''
+
+assert qs_codec.encode({'a': {'b': []}}) == ''
+
+assert qs_codec.encode({'a': {'b': {}}}) == ''
+
+
+

Undefined properties will be omitted entirely:

+
import qs_codec
+
+assert qs_codec.encode({'a': None, 'b': qs_codec.Undefined()}) == 'a='
+
+
+

The query string may optionally be prepended with a question mark (?) by setting +add_query_prefix to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b', 'c': 'd'},
+    qs_codec.EncodeOptions(add_query_prefix=True),
+) == '?a=b&c=d'
+
+
+

The delimiter may be overridden as well:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b', 'c': 'd', },
+    qs_codec.EncodeOptions(delimiter=';')
+) == 'a=b;c=d'
+
+
+

If you only want to override the serialization of datetime +objects, you can provide a Callable in the +serialize_date option:

+
import qs_codec, datetime, sys
+
+# First case: encoding a datetime object to an ISO 8601 string
+assert (
+    qs_codec.encode(
+        {
+            "a": (
+                datetime.datetime.fromtimestamp(7, datetime.UTC)
+                if sys.version_info.major == 3 and sys.version_info.minor >= 11
+                else datetime.datetime.utcfromtimestamp(7)
+            )
+        },
+        qs_codec.EncodeOptions(encode=False),
+    )
+    == "a=1970-01-01T00:00:07+00:00"
+    if sys.version_info.major == 3 and sys.version_info.minor >= 11
+    else "a=1970-01-01T00:00:07"
+)
+
+# Second case: encoding a datetime object to a timestamp string
+assert (
+    qs_codec.encode(
+        {
+            "a": (
+                datetime.datetime.fromtimestamp(7, datetime.UTC)
+                if sys.version_info.major == 3 and sys.version_info.minor >= 11
+                else datetime.datetime.utcfromtimestamp(7)
+            )
+        },
+        qs_codec.EncodeOptions(encode=False, serialize_date=lambda date: str(int(date.timestamp()))),
+    )
+    == "a=7"
+)
+
+
+

To affect the order of parameter keys, you can set a Callable in the +sort option:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'c', 'z': 'y', 'b': 'f'},
+    qs_codec.EncodeOptions(
+        encode=False,
+        sort=lambda a, b: (a > b) - (a < b)
+    )
+) == 'a=c&b=f&z=y'
+
+
+

Finally, you can use the filter option to restrict +which keys will be included in the encoded output. If you pass a Callable, it will be called for each key to obtain +the replacement value. Otherwise, if you pass a list, it will be used to select properties and list indices to +be encoded:

+
import qs_codec, datetime, sys
+
+# First case: using a Callable as filter
+assert (
+    qs_codec.encode(
+        {
+            "a": "b",
+            "c": "d",
+            "e": {
+                "f": (
+                    datetime.datetime.fromtimestamp(123, datetime.UTC)
+                    if sys.version_info.major == 3 and sys.version_info.minor >= 11
+                    else datetime.datetime.utcfromtimestamp(123)
+                ),
+                "g": [2],
+            },
+        },
+        qs_codec.EncodeOptions(
+            encode=False,
+            filter=lambda prefix, value: {
+                "b": None,
+                "e[f]": int(value.timestamp()) if isinstance(value, datetime.datetime) else value,
+                "e[g][0]": value * 2 if isinstance(value, int) else value,
+            }.get(prefix, value),
+        ),
+    )
+    == "a=b&c=d&e[f]=123&e[g][0]=4"
+)
+
+# Second case: using a list as filter
+assert qs_codec.encode(
+    {'a': 'b', 'c': 'd', 'e': 'f'},
+    qs_codec.EncodeOptions(
+        encode=False,
+        filter=['a', 'e']
+    )
+) == 'a=b&e=f'
+
+# Third case: using a list as filter with indices
+assert qs_codec.encode(
+    {
+        'a': ['b', 'c', 'd'],
+        'e': 'f',
+    },
+    qs_codec.EncodeOptions(
+        encode=False,
+        filter=['a', 0, 2]
+    )
+) == 'a[0]=b&a[2]=d'
+
+
+
+
+

Handling None values

+

By default, None values are treated like empty strings:

+
import qs_codec
+
+assert qs_codec.encode({'a': None, 'b': ''}) == 'a=&b='
+
+
+

To distinguish between None values and empty strs use the +strict_null_handling flag. +In the result string the None values have no = sign:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': None, 'b': ''},
+    qs_codec.EncodeOptions(strict_null_handling=True),
+) == 'a&b='
+
+
+

To decode values without = back to None use the +strict_null_handling flag:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a&b=',
+    qs_codec.DecodeOptions(strict_null_handling=True),
+) == {'a': None, 'b': ''}
+
+
+

To completely skip rendering keys with None values, use the +skip_nulls flag:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b', 'c': None},
+    qs_codec.EncodeOptions(skip_nulls=True),
+) == 'a=b'
+
+
+

If you’re communicating with legacy systems, you can switch to +LATIN1 using the +charset option:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'æ': 'æ'},
+    qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1)
+) == '%E6=%E6'
+
+
+

Characters that don’t exist in LATIN1 +will be converted to numeric entities, similar to what browsers do:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': '☺'},
+    qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1)
+) == 'a=%26%239786%3B'
+
+
+

You can use the charset_sentinel +option to announce the character by including an utf8=✓ parameter with the proper +encoding of the checkmark, similar to what Ruby on Rails and others do when submitting forms.

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': '☺'},
+    qs_codec.EncodeOptions(charset_sentinel=True)
+) == 'utf8=%E2%9C%93&a=%E2%98%BA'
+
+assert qs_codec.encode(
+    {'a': 'æ'},
+    qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1, charset_sentinel=True)
+) == 'utf8=%26%2310003%3B&a=%E6'
+
+
+
+
+

Dealing with special character sets

+

By default, the encoding and decoding of characters is done in +UTF8, and +LATIN1 support is also built in via +the charset +and charset parameter, +respectively.

+

If you wish to encode query strings to a different character set (i.e. +Shift JIS)

+
import qs_codec, codecs, typing as t
+
+def custom_encoder(
+    string: str,
+    charset: t.Optional[qs_codec.Charset],
+    format: t.Optional[qs_codec.Format],
+) -> str:
+    if string:
+        buf: bytes = codecs.encode(string, 'shift_jis')
+        result: t.List[str] = ['{:02x}'.format(b) for b in buf]
+        return '%' + '%'.join(result)
+    return ''
+
+assert qs_codec.encode(
+    {'a': 'こんにちは!'},
+    qs_codec.EncodeOptions(encoder=custom_encoder)
+) == '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49'
+
+
+

This also works for decoding of query strings:

+
import qs_codec, re, codecs, typing as t
+
+def custom_decoder(
+    string: str,
+    charset: t.Optional[qs_codec.Charset],
+) -> t.Optional[str]:
+    if string:
+        result: t.List[int] = []
+        while string:
+            match: t.Optional[t.Match[str]] = re.search(r'%([0-9A-F]{2})', string, re.IGNORECASE)
+            if match:
+                result.append(int(match.group(1), 16))
+                string = string[match.end():]
+            else:
+                break
+        buf: bytes = bytes(result)
+        return codecs.decode(buf, 'shift_jis')
+    return None
+
+assert qs_codec.decode(
+    '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49',
+    qs_codec.DecodeOptions(decoder=custom_decoder)
+) == {'a': 'こんにちは!'}
+
+
+
+
+

RFC 3986 and RFC 1738 space encoding

+

The default format is +RFC3986 which encodes +' ' to %20 which is backward compatible. You can also set the +format to +RFC1738 which encodes ' ' to +.

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b c'},
+    qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986)
+) == 'a=b%20c'
+
+assert qs_codec.encode(
+    {'a': 'b c'},
+    qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986)
+) == 'a=b%20c'
+
+assert qs_codec.encode(
+    {'a': 'b c'},
+    qs_codec.EncodeOptions(format=qs_codec.Format.RFC1738)
+) == 'a=b+c'
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..145cb90 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,118 @@ + + + + + + + Overview: module code — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/decode.html b/_modules/qs_codec/decode.html new file mode 100644 index 0000000..487e2d2 --- /dev/null +++ b/_modules/qs_codec/decode.html @@ -0,0 +1,300 @@ + + + + + + + qs_codec.decode — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.decode

+"""A query string decoder (parser)."""
+
+import re
+import typing as t
+from math import isinf
+
+from regex import regex
+
+from .enums.charset import Charset
+from .enums.duplicates import Duplicates
+from .enums.sentinel import Sentinel
+from .models.decode_options import DecodeOptions
+from .models.undefined import Undefined
+from .utils.utils import Utils
+
+
+
+[docs] +def decode(value: t.Optional[t.Union[str, t.Mapping]], options: DecodeOptions = DecodeOptions()) -> dict: + """ + Decodes a ``str`` or ``Mapping`` into a ``dict``. + + Providing custom ``DecodeOptions`` will override the default behavior. + """ + if not value: + return dict() + + if not isinstance(value, (str, t.Mapping)): + raise ValueError("The input must be a String or a Dict") + + temp_obj: t.Optional[t.Mapping] = _parse_query_string_values(value, options) if isinstance(value, str) else value + obj: t.Dict = dict() + + # Iterate over the keys and setup the new object + if temp_obj: + for key, val in temp_obj.items(): + new_obj: t.Any = _parse_keys(key, val, options, isinstance(value, str)) + obj = Utils.merge(obj, new_obj, options) # type: ignore [assignment] + + return Utils.compact(obj)
+ + + +def _interpret_numeric_entities(value: str) -> str: + return re.sub(r"&#(\d+);", lambda match: chr(int(match.group(1))), value) + + +def _parse_array_value(value: t.Any, options: DecodeOptions) -> t.Any: + if isinstance(value, str) and value and options.comma and "," in value: + return value.split(",") + + return value + + +def _parse_query_string_values(value: str, options: DecodeOptions) -> t.Dict: + obj: t.Dict = dict() + + clean_str: str = value.replace("?", "", 1) if options.ignore_query_prefix else value + limit: t.Optional[int] = None if isinf(options.parameter_limit) else options.parameter_limit # type: ignore [assignment] + parts: t.List[str] + if isinstance(options.delimiter, re.Pattern): + parts = re.split(options.delimiter, clean_str) if not limit else re.split(options.delimiter, clean_str)[:limit] + else: + parts = clean_str.split(options.delimiter) if not limit else clean_str.split(options.delimiter)[:limit] + + skip_index: int = -1 # Keep track of where the utf8 sentinel was found + i: int + + charset: Charset = options.charset + + if options.charset_sentinel: + for i, _part in enumerate(parts): + if _part.startswith("utf8="): + if _part == Sentinel.CHARSET.encoded: + charset = Charset.UTF8 + elif _part == Sentinel.ISO.encoded: + charset = Charset.LATIN1 + skip_index = i + break + + for i, _ in enumerate(parts): + if i == skip_index: + continue + + part: str = parts[i] + bracket_equals_pos: int = part.find("]=") + pos: int = part.find("=") if bracket_equals_pos == -1 else (bracket_equals_pos + 1) + + key: str + val: t.Union[t.List, t.Tuple, str, t.Any] + if pos == -1: + key = options.decoder(part, charset) + val = None if options.strict_null_handling else "" + else: + key = options.decoder(part[:pos], charset) + val = Utils.apply( + _parse_array_value(part[pos + 1 :], options), + lambda v: options.decoder(v, charset), + ) + + if val and options.interpret_numeric_entities and charset == Charset.LATIN1: + val = _interpret_numeric_entities(val) # type: ignore [arg-type] + + if "[]=" in part: + val = [val] if isinstance(val, (list, tuple)) else val + + existing: bool = key in obj + + if existing and options.duplicates == Duplicates.COMBINE: + obj[key] = Utils.combine(obj[key], val) + elif not existing or options.duplicates == Duplicates.LAST: + obj[key] = val + + return obj + + +def _parse_object( + chain: t.Union[t.List[str], t.Tuple[str, ...]], val: t.Any, options: DecodeOptions, values_parsed: bool +) -> t.Any: + leaf: t.Any = val if values_parsed else _parse_array_value(val, options) + + i: int + for i in reversed(range(len(chain))): + obj: t.Optional[t.Any] + root: str = chain[i] + + if root == "[]" and options.parse_lists: + if options.allow_empty_lists and leaf == "": + obj = [] + else: + obj = list(leaf) if isinstance(leaf, (list, tuple)) else [leaf] + else: + obj = dict() + + clean_root: str = root[1:-1] if root.startswith("[") and root.endswith("]") else root + + decoded_root: str = clean_root.replace(r"%2E", ".") if options.decode_dot_in_keys else clean_root + + index: t.Optional[int] + try: + index = int(decoded_root, 10) + except (ValueError, TypeError): + index = None + + if not options.parse_lists and decoded_root == "": + obj = {0: leaf} + elif ( + index is not None + and index >= 0 + and root != decoded_root + and str(index) == decoded_root + and options.parse_lists + and index <= options.list_limit + ): + obj = [Undefined() for _ in range(index + 1)] + obj[index] = leaf + else: + obj[index if index is not None else decoded_root] = leaf + + leaf = obj + + return leaf + + +def _parse_keys(given_key: t.Optional[str], val: t.Any, options: DecodeOptions, values_parsed: bool) -> t.Any: + if not given_key: + return + + # Transform dot notation to bracket notation + key: str = re.sub(r"\.([^.[]+)", r"[\1]", given_key) if options.allow_dots else given_key + + # The regex chunks + brackets: regex.Pattern[str] = regex.compile(r"\[(?:[^\[\]]|(?R))*\]") + + # Get the parent + segment: t.Optional[regex.Match] = brackets.search(key) if options.depth > 0 else None + parent: str = key[0 : segment.start()] if segment is not None else key + + # Stash the parent if it exists + keys: t.List[str] = [parent] if parent else [] + + # Loop through children appending to the array until we hit depth + i: int = 0 + while options.depth > 0 and (segment := brackets.search(key)) is not None and i < options.depth: + i += 1 + if segment is not None: + keys.append(segment.group()) + # Update the key to start searching from the next position + key = key[segment.end() :] + + # If there's a remainder, just add whatever is left + if segment is not None: + keys.append(f"[{key[segment.start():]}]") + + return _parse_object(keys, val, options, values_parsed) +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/encode.html b/_modules/qs_codec/encode.html new file mode 100644 index 0000000..0eca60e --- /dev/null +++ b/_modules/qs_codec/encode.html @@ -0,0 +1,404 @@ + + + + + + + qs_codec.encode — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.encode

+"""A query string encoder (stringifier)."""
+
+import typing as t
+from copy import deepcopy
+from datetime import datetime
+from functools import cmp_to_key
+from weakref import WeakKeyDictionary
+
+from .enums.charset import Charset
+from .enums.format import Format
+from .enums.list_format import ListFormat
+from .enums.sentinel import Sentinel
+from .models.encode_options import EncodeOptions
+from .models.undefined import Undefined
+from .models.weak_wrapper import WeakWrapper
+from .utils.utils import Utils
+
+
+
+[docs] +def encode(value: t.Any, options: EncodeOptions = EncodeOptions()) -> str: + """ + Encodes ``Any`` object into a query ``str`` ing. + + Providing custom ``EncodeOptions`` will override the default behavior. + """ + if value is None: + return "" + + obj: t.Mapping[str, t.Any] + if isinstance(value, t.Mapping): + obj = deepcopy(value) + elif isinstance(value, (list, tuple)): + obj = {str(key): value for key, value in enumerate(value)} + else: + obj = {} + + keys: t.List[t.Any] = [] + + if not obj: + return "" + + obj_keys: t.Optional[t.List[t.Any]] = None + + if options.filter is not None: + if callable(options.filter): + obj = options.filter("", obj) + elif isinstance(options.filter, (list, tuple)): + obj_keys = list(options.filter) + + comma_round_trip: bool = options.list_format == ListFormat.COMMA and options.comma_round_trip is True + + if obj_keys is None: + obj_keys = list(obj.keys()) + + if options.sort is not None and callable(options.sort): + obj_keys = sorted(obj_keys, key=cmp_to_key(options.sort)) + + side_channel: WeakKeyDictionary = WeakKeyDictionary() + + for _key in obj_keys: + if not isinstance(_key, str): + continue + if _key in obj and obj.get(_key) is None and options.skip_nulls: + continue + + _encoded: t.Union[t.List[t.Any], t.Tuple[t.Any, ...], t.Any] = _encode( + value=obj.get(_key), + is_undefined=_key not in obj, + side_channel=side_channel, + prefix=_key, + generate_array_prefix=options.list_format.generator, + comma_round_trip=comma_round_trip, + encoder=options.encoder if options.encode else None, + serialize_date=options.serialize_date, + sort=options.sort, + filter=options.filter, + formatter=options.format.formatter, + allow_empty_lists=options.allow_empty_lists, + strict_null_handling=options.strict_null_handling, + skip_nulls=options.skip_nulls, + encode_dot_in_keys=options.encode_dot_in_keys, + allow_dots=options.allow_dots, + format=options.format, + encode_values_only=options.encode_values_only, + charset=options.charset, + add_query_prefix=options.add_query_prefix, + ) + + if isinstance(_encoded, (list, tuple)): + keys.extend(_encoded) + else: + keys.append(_encoded) + + joined: str = options.delimiter.join(keys) + prefix: str = "?" if options.add_query_prefix else "" + + if options.charset_sentinel: + if options.charset == Charset.LATIN1: + prefix += f"{Sentinel.ISO.encoded}&" + elif options.charset == Charset.UTF8: + prefix += f"{Sentinel.CHARSET.encoded}&" + else: + raise ValueError("Invalid charset") + + return prefix + joined if joined else ""
+ + + +_sentinel: WeakWrapper = WeakWrapper({}) + + +def _encode( + value: t.Any, + is_undefined: bool, + side_channel: WeakKeyDictionary, + prefix: t.Optional[str], + comma_round_trip: t.Optional[bool], + encoder: t.Optional[t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str]], + serialize_date: t.Callable[[datetime], str], + sort: t.Optional[t.Callable[[t.Any, t.Any], int]], + filter: t.Optional[t.Union[t.Callable, t.List[t.Union[str, int]]]], + formatter: t.Optional[t.Callable[[str], str]], + format: Format = Format.RFC3986, + generate_array_prefix: t.Callable[[str, t.Optional[str]], str] = ListFormat.INDICES.generator, + allow_empty_lists: bool = False, + strict_null_handling: bool = False, + skip_nulls: bool = False, + encode_dot_in_keys: bool = False, + allow_dots: bool = False, + encode_values_only: bool = False, + charset: t.Optional[Charset] = Charset.UTF8, + add_query_prefix: bool = False, +) -> t.Union[t.List[t.Any], t.Tuple[t.Any, ...], t.Any]: + if prefix is None: + prefix = "?" if add_query_prefix else "" + + if comma_round_trip is None: + comma_round_trip = generate_array_prefix == ListFormat.COMMA.generator + + if formatter is None: + formatter = format.formatter + + obj: t.Any = deepcopy(value) + + tmp_sc: t.Optional[WeakKeyDictionary] = side_channel + step: int = 0 + find_flag: bool = False + + while (tmp_sc := tmp_sc.get(_sentinel)) and not find_flag: # type: ignore [union-attr] + # Where value last appeared in the ref tree + pos: t.Optional[int] = tmp_sc.get(WeakWrapper(value)) + step += 1 + if pos is not None: + if pos == step: + raise ValueError("Circular reference detected") + else: + find_flag = True # Break while + if tmp_sc.get(_sentinel) is None: + step = 0 + + if callable(filter): + obj = filter(prefix, obj) + elif isinstance(obj, datetime): + obj = serialize_date(obj) if callable(serialize_date) else obj.isoformat() + elif generate_array_prefix == ListFormat.COMMA.generator and isinstance(obj, (list, tuple)): + obj = Utils.apply( + obj, + lambda val: ( + (serialize_date(val) if callable(serialize_date) else val.isoformat()) + if isinstance(val, datetime) + else val + ), + ) + + if not is_undefined and obj is None: + if strict_null_handling: + return encoder(prefix, charset, format) if callable(encoder) and not encode_values_only else prefix + + obj = "" + + if Utils.is_non_nullish_primitive(obj, skip_nulls) or isinstance(obj, bytes): + if callable(encoder): + key_value = prefix if encode_values_only else encoder(prefix, charset, format) + return [f"{formatter(key_value)}={formatter(encoder(obj, charset, format))}"] + + return [f"{formatter(prefix)}={formatter(str(obj))}"] + + values: t.List = [] + + if is_undefined: + return values + + obj_keys: t.List + if generate_array_prefix == ListFormat.COMMA.generator and isinstance(obj, (list, tuple)): + # we need to join elements in + if encode_values_only and callable(encoder): + obj = Utils.apply(obj, encoder) + + if obj: + obj_keys_value = ",".join([str(e) if e is not None else "" for e in obj]) + obj_keys = [{"value": obj_keys_value if obj_keys_value else None}] + else: + obj_keys = [{"value": Undefined()}] + elif isinstance(filter, (list, tuple)): + obj_keys = list(filter) + else: + keys: t.List + if isinstance(obj, t.Mapping): + keys = list(obj.keys()) + elif isinstance(obj, (list, tuple)): + keys = [index for index in range(len(obj))] + else: + keys = [] + + obj_keys = sorted(keys, key=cmp_to_key(sort)) if sort is not None else list(keys) + + encoded_prefix: str = prefix.replace(".", "%2E") if encode_dot_in_keys else prefix + + adjusted_prefix: str = ( + f"{encoded_prefix}[]" + if comma_round_trip and isinstance(obj, (list, tuple)) and len(obj) == 1 + else encoded_prefix + ) + + if allow_empty_lists and isinstance(obj, (list, tuple)) and not obj: + return [f"{adjusted_prefix}[]"] + + for _key in obj_keys: + _value: t.Any + _value_undefined: bool + + if isinstance(_key, t.Mapping) and "value" in _key and not isinstance(_key.get("value"), Undefined): + _value = _key.get("value") + _value_undefined = False + else: + try: + if isinstance(obj, t.Mapping): + _value = obj.get(_key) + _value_undefined = _key not in obj + elif isinstance(obj, (list, tuple)): + _value = obj[_key] + _value_undefined = False + else: + _value = obj[_key] + _value_undefined = False + except Exception: # pylint: disable=W0718 + _value = None + _value_undefined = True + + if skip_nulls and _value is None: + continue + + encoded_key: str = str(_key).replace(".", "%2E") if allow_dots and encode_dot_in_keys else str(_key) + + key_prefix: str = ( + generate_array_prefix(adjusted_prefix, encoded_key) + if isinstance(obj, (list, tuple)) + else f"{adjusted_prefix}{f'.{encoded_key}' if allow_dots else f'[{encoded_key}]'}" + ) + + side_channel[WeakWrapper(value)] = step + value_side_channel: WeakKeyDictionary = WeakKeyDictionary() + value_side_channel[_sentinel] = side_channel + + encoded: t.Union[t.List[t.Any], t.Tuple[t.Any, ...], t.Any] = _encode( + value=_value, + is_undefined=_value_undefined, + side_channel=value_side_channel, + prefix=key_prefix, + comma_round_trip=comma_round_trip, + encoder=( + None + if generate_array_prefix == ListFormat.COMMA.generator + and encode_values_only + and isinstance(obj, (list, tuple)) + else encoder + ), + serialize_date=serialize_date, + sort=sort, + filter=filter, + formatter=formatter, + format=format, + generate_array_prefix=generate_array_prefix, + allow_empty_lists=allow_empty_lists, + strict_null_handling=strict_null_handling, + skip_nulls=skip_nulls, + encode_dot_in_keys=encode_dot_in_keys, + allow_dots=allow_dots, + encode_values_only=encode_values_only, + charset=charset, + ) + + if isinstance(encoded, (list, tuple)): + values.extend(encoded) + else: + values.append(encoded) + + return values +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/charset.html b/_modules/qs_codec/enums/charset.html new file mode 100644 index 0000000..3a73eb5 --- /dev/null +++ b/_modules/qs_codec/enums/charset.html @@ -0,0 +1,129 @@ + + + + + + + qs_codec.enums.charset — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.charset

+"""Charset enum module."""
+
+from dataclasses import dataclass
+from enum import Enum
+
+
+@dataclass(frozen=True)
+class _CharsetDataMixin:
+    """Character set data mixin."""
+
+    encoding: str
+
+
+
+[docs] +class Charset(_CharsetDataMixin, Enum): + """Character set.""" + + UTF8 = "utf-8" + """UTF-8 character encoding.""" + + LATIN1 = "iso-8859-1" + """ISO-8859-1 (Latin-1) character encoding."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/duplicates.html b/_modules/qs_codec/enums/duplicates.html new file mode 100644 index 0000000..f29a45c --- /dev/null +++ b/_modules/qs_codec/enums/duplicates.html @@ -0,0 +1,124 @@ + + + + + + + qs_codec.enums.duplicates — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.duplicates

+"""This module contains an enum of all available duplicate key handling strategies."""
+
+from enum import Enum
+
+
+
+[docs] +class Duplicates(Enum): + """An enum of all available duplicate key handling strategies.""" + + COMBINE = 1 + """Combine duplicate keys into a single key with an array of values.""" + + FIRST = 2 + """Use the first value for duplicate keys.""" + + LAST = 3 + """Use the last value for duplicate keys."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/format.html b/_modules/qs_codec/enums/format.html new file mode 100644 index 0000000..202fbcf --- /dev/null +++ b/_modules/qs_codec/enums/format.html @@ -0,0 +1,154 @@ + + + + + + + qs_codec.enums.format — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.format

+"""An enum of all supported URI component encoding formats."""
+
+import typing as t
+from dataclasses import dataclass
+from enum import Enum
+
+
+
+[docs] +class Formatter: + """A class for formatting URI components.""" + +
+[docs] + @staticmethod + def rfc1738(value: str) -> str: + """Format a string according to `RFC 1738 <https://datatracker.ietf.org/doc/html/rfc1738>`_.""" + return value.replace("%20", "+")
+ + +
+[docs] + @staticmethod + def rfc3986(value: str) -> str: + """Format a string according to `RFC 3986 <https://datatracker.ietf.org/doc/html/rfc3986>`_.""" + return value
+
+ + + +@dataclass(frozen=True) +class _FormatDataMixin: + """Format data mixin.""" + + format_name: str + formatter: t.Callable[[str], str] + + +
+[docs] +class Format(_FormatDataMixin, Enum): + """An enum of all supported URI component encoding formats.""" + + RFC1738 = "RFC1738", Formatter.rfc1738 + """`RFC 1738 <https://datatracker.ietf.org/doc/html/rfc1738>`_.""" + + RFC3986 = "RFC3986", Formatter.rfc3986 + """`RFC 3986 <https://datatracker.ietf.org/doc/html/rfc3986>`_."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/list_format.html b/_modules/qs_codec/enums/list_format.html new file mode 100644 index 0000000..ee3347c --- /dev/null +++ b/_modules/qs_codec/enums/list_format.html @@ -0,0 +1,176 @@ + + + + + + + qs_codec.enums.list_format — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.list_format

+"""An enum for all available list format options."""
+
+import typing as t
+from dataclasses import dataclass
+from enum import Enum
+
+
+
+[docs] +class ListFormatGenerator: + """A class for formatting list items.""" + +
+[docs] + @staticmethod + def brackets(prefix: str, key: t.Optional[str] = None) -> str: # pylint: disable=W0613 + """Format a list item using brackets.""" + return f"{prefix}[]"
+ + +
+[docs] + @staticmethod + def comma(prefix: str, key: t.Optional[str] = None) -> str: # pylint: disable=W0613 + """Format a list item using commas.""" + return prefix
+ + +
+[docs] + @staticmethod + def indices(prefix: str, key: t.Optional[str] = None) -> str: + """Format a list item using indices.""" + return f"{prefix}[{key}]"
+ + +
+[docs] + @staticmethod + def repeat(prefix: str, key: t.Optional[str] = None) -> str: # pylint: disable=W0613 + """Format a list item using repeats.""" + return prefix
+
+ + + +@dataclass(frozen=True) +class _ListFormatDataMixin: + """List format data mixin.""" + + list_format_name: str + generator: t.Callable[[str, t.Optional[str]], str] + + +
+[docs] +class ListFormat(_ListFormatDataMixin, Enum): + """An enum of all available list format options.""" + + BRACKETS = "BRACKETS", ListFormatGenerator.brackets + """Use brackets to represent list items, for example ``foo[]=123&foo[]=456&foo[]=789``""" + + COMMA = "COMMA", ListFormatGenerator.comma + """Use commas to represent list items, for example ``foo=123,456,789``""" + + REPEAT = "REPEAT", ListFormatGenerator.repeat + """Use a repeat key to represent list items, for example ``foo=123&foo=456&foo=789``""" + + INDICES = "INDICES", ListFormatGenerator.indices + """Use indices to represent list items, for example ``foo[0]=123&foo[1]=456&foo[2]=789``"""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/sentinel.html b/_modules/qs_codec/enums/sentinel.html new file mode 100644 index 0000000..80b5af2 --- /dev/null +++ b/_modules/qs_codec/enums/sentinel.html @@ -0,0 +1,134 @@ + + + + + + + qs_codec.enums.sentinel — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.sentinel

+"""This module defines the Sentinel enum, which contains all available sentinel values."""
+
+from dataclasses import dataclass
+from enum import Enum
+
+
+@dataclass(frozen=True)
+class _SentinelDataMixin:
+    """Sentinel data mixin."""
+
+    raw: str
+    encoded: str
+
+
+
+[docs] +class Sentinel(_SentinelDataMixin, Enum): + """An enum of all available sentinel values.""" + + ISO = r"&#10003;", r"utf8=%26%2310003%3B" + """This is what browsers will submit when the ``✓`` character occurs in an ``application/x-www-form-urlencoded`` + body and the encoding of the page containing the form is ``iso-8859-1``, or when the submitted form has an + ``accept-charset`` attribute of ``iso-8859-1``. Presumably also with other charsets that do not contain the ``✓`` + character, such as ``us-ascii``.""" + + CHARSET = r"✓", r"utf8=%E2%9C%93" + """These are the percent-encoded ``utf-8`` octets representing a checkmark, indicating that the request actually is + ``utf-8`` encoded."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/decode_options.html b/_modules/qs_codec/models/decode_options.html new file mode 100644 index 0000000..22c61b9 --- /dev/null +++ b/_modules/qs_codec/models/decode_options.html @@ -0,0 +1,199 @@ + + + + + + + qs_codec.models.decode_options — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.decode_options

+"""This module contains the ``DecodeOptions`` class that configures the output of ``decode``."""
+
+import typing as t
+from dataclasses import dataclass, field
+
+from ..enums.charset import Charset
+from ..enums.duplicates import Duplicates
+from ..utils.decode_utils import DecodeUtils
+
+
+
+[docs] +@dataclass +class DecodeOptions: + """Options that configure the output of ``decode``.""" + + allow_dots: bool = field(default=None) # type: ignore [assignment] + """Set to ``True`` to decode dot ``dict`` notation in the encoded input.""" + + decode_dot_in_keys: bool = field(default=None) # type: ignore [assignment] + """Set to ``True`` to decode dots in keys. + Note: it implies ``allow_dots``, so ``decode`` will error if you set ``decode_dot_in_keys`` to ``True``, and + ``allow_dots`` to ``False``.""" + + allow_empty_lists: bool = False + """Set to ``True`` to allow empty ``list`` values inside ``dict``\\s in the encoded input.""" + + list_limit: int = 20 + """``qs_codec`` will limit specifying indices in a ``list`` to a maximum index of ``20``. + Any ``list`` members with an index of greater than ``20`` will instead be converted to a ``dict`` with the index as + the key. This is needed to handle cases when someone sent, for example, ``a[999999999]`` and it will take + significant time to iterate over this huge ``list``. + This limit can be overridden by passing a ``list_limit`` option.""" + + charset: Charset = Charset.UTF8 + """The character encoding to use when decoding the input.""" + + charset_sentinel: bool = False + """Some services add an initial ``utf8=✓`` value to forms so that old InternetExplorer versions are more likely to + submit the form as ``utf-8``. Additionally, the server can check the value against wrong encodings of the checkmark + character and detect that a query string or ``application/x-www-form-urlencoded`` body was *not* sent as ``utf-8``, + e.g. if the form had an ``accept-charset`` parameter or the containing page had a different character set. + + ``qs_codec`` supports this mechanism via the ``charset_sentinel`` option. + If specified, the ``utf-8`` parameter will be omitted from the returned ``dict``. + It will be used to switch to ``LATIN1`` or ``UTF8`` mode depending on how the checkmark is encoded. + + Important: When you specify both the ``charset`` option and the ``charset_sentinel`` option, + the ``charset`` will be overridden when the request contains a ``utf-8`` parameter from which the actual charset + can be deduced. In that sense the ``charset`` will behave as the default charset rather than the authoritative + charset.""" + + comma: bool = False + """Set to ``True`` to parse the input as a comma-separated value. + Note: nested ``dict`` s, such as ``'a={b:1},{c:d}'`` are not supported.""" + + delimiter: t.Union[str, t.Pattern[str]] = "&" + """The delimiter to use when splitting key-value pairs in the encoded input. Can be a ``str`` or a ``Pattern``.""" + + depth: int = 5 + """By default, when nesting ``dict``\\s ``qs_codec`` will only decode up to 5 children deep. + This depth can be overridden by setting the ``depth``. + The depth limit helps mitigate abuse when ``qs_codec`` is used to parse user input, + and it is recommended to keep it a reasonably small number.""" + + parameter_limit: t.Union[int, float] = 1000 + """For similar reasons, by default ``qs_codec`` will only parse up to 1000 parameters. This can be overridden by + passing a ``parameter_limit`` option.""" + + duplicates: Duplicates = Duplicates.COMBINE + """Change the duplicate key handling strategy.""" + + ignore_query_prefix: bool = False + """Set to ``True`` to ignore the leading question mark query prefix in the encoded input.""" + + interpret_numeric_entities: bool = False + """Set to ``True`` to interpret HTML numeric entities (``&#...;``) in the encoded input.""" + + parse_lists: bool = True + """To disable ``list`` parsing entirely, set ``parse_lists`` to ``False``.""" + + strict_null_handling: bool = False + """Set to true to decode values without ``=`` to ``None``.""" + + decoder: t.Callable[[t.Optional[str], t.Optional[Charset]], t.Any] = DecodeUtils.decode + """Set a ``Callable`` to affect the decoding of the input.""" + + def __post_init__(self): + """Post-initialization.""" + if self.allow_dots is None: + self.allow_dots = self.decode_dot_in_keys is True or False + if self.decode_dot_in_keys is None: + self.decode_dot_in_keys = False
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/encode_options.html b/_modules/qs_codec/models/encode_options.html new file mode 100644 index 0000000..723789a --- /dev/null +++ b/_modules/qs_codec/models/encode_options.html @@ -0,0 +1,225 @@ + + + + + + + qs_codec.models.encode_options — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.encode_options

+"""This module contains the ``EncodeOptions`` class that configures the output of ``encode``."""
+
+import typing as t
+from dataclasses import asdict, dataclass, field
+from datetime import datetime
+
+from ..enums.charset import Charset
+from ..enums.format import Format
+from ..enums.list_format import ListFormat
+from ..utils.encode_utils import EncodeUtils
+
+
+
+[docs] +@dataclass +class EncodeOptions: + """Options that configure the output of ``encode``.""" + + allow_dots: bool = field(default=None) # type: ignore [assignment] + """Set to ``True`` to use dot ``dict`` notation in the encoded output.""" + + add_query_prefix: bool = False + """Set to ``True`` to add a question mark ``?`` prefix to the encoded output.""" + + allow_empty_lists: bool = False + """Set to ``True`` to allow empty ``list`` s in the encoded output.""" + + indices: t.Optional[bool] = None + """Deprecated: Use ``list_format`` instead.""" + + list_format: ListFormat = ListFormat.INDICES + """The ``list`` encoding format to use.""" + + charset: Charset = Charset.UTF8 + """The character encoding to use.""" + + charset_sentinel: bool = False + """Set to ``True`` to announce the character by including an ``utf8=✓`` parameter with the proper encoding of the + checkmark, similar to what Ruby on Rails and others do when submitting forms.""" + + delimiter: str = "&" + """The delimiter to use when joining key-value pairs in the encoded output.""" + + encode: bool = True + """Set to ``False`` to disable encoding.""" + + encode_dot_in_keys: bool = field(default=None) # type: ignore [assignment] + """Encode ``dict`` keys using dot notation by setting ``encode_dot_in_keys`` to ``True``. + Caveat: When ``encode_values_only`` is ``True`` as well as ``encode_dot_in_keys``, only dots in keys and nothing + else will be encoded.""" + + encode_values_only: bool = False + """Encoding can be disabled for keys by setting the ``encode_values_only`` to ``True``.""" + + format: Format = Format.RFC3986 + """The encoding format to use. + The default ``format`` is ``Format.RFC3986`` which encodes ``' '`` to ``%20`` which is backward compatible. + You can also set ``format`` to ``Format.RFC1738`` which encodes ``' '`` to ``+``.""" + + filter: t.Optional[t.Union[t.Callable, t.List[t.Union[str, int]]]] = field(default=None) + """Use the ``filter`` option to restrict which keys will be included in the encoded output. + If you pass a ``Callable``, it will be called for each key to obtain the replacement value. + If you pass a ``list``, it will be used to select properties and ``list`` indices to be encoded.""" + + skip_nulls: bool = False + """Set to ``True`` to completely skip encoding keys with ``None`` values.""" + + serialize_date: t.Callable[[datetime], str] = EncodeUtils.serialize_date + """If you only want to override the serialization of ``datetime`` objects, you can provide a ``Callable``.""" + + encoder: t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str] = field( # type: ignore [assignment] + default_factory=EncodeUtils.encode # type: ignore [arg-type] + ) + """Set an ``Encoder`` to affect the encoding of values. + Note: the ``encoder`` option does not apply if ``encode`` is ``False``.""" + + _encoder: t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str] = field(init=False, repr=False) + + @property # type: ignore [no-redef] + def encoder(self) -> t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str]: # noqa: F811 + """Get the encoder function.""" + return lambda v, c=self.charset, f=self.format: self._encoder(v, c, f) # type: ignore [misc] + + @encoder.setter + def encoder(self, value: t.Optional[t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str]]) -> None: + self._encoder = value if callable(value) else EncodeUtils.encode # type: ignore [assignment] + + strict_null_handling: bool = False + """Set to ``True`` to distinguish between ``null`` values and empty ``str``\\ings. This way the encoded string + ``None`` values will have no ``=`` sign.""" + + comma_round_trip: t.Optional[bool] = None + """When ``list_format`` is set to ``ListFormat.COMMA``, you can also set ``comma_round_trip`` option to ``True`` or + ``False``, to append ``[]`` on single-item ``list``\\s, so that they can round trip through a parse.""" + + sort: t.Optional[t.Callable[[t.Any, t.Any], int]] = field(default=None) + """Set a ``Callable`` to affect the order of parameter keys.""" + + def __post_init__(self): + """Post-initialization.""" + if self.allow_dots is None: + self.allow_dots = self.encode_dot_in_keys is True or False + if self.encode_dot_in_keys is None: + self.encode_dot_in_keys = False + if self.indices is not None: + self.list_format = ListFormat.INDICES if self.indices else ListFormat.REPEAT + + def __eq__(self, other: object) -> bool: + """Compare two `EncodeOptions` objects.""" + if not isinstance(other, EncodeOptions): + return False + + self_dict = asdict(self) + other_dict = asdict(other) + + self_dict["encoder"] = self._encoder + other_dict["encoder"] = other._encoder + + return self_dict == other_dict
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/undefined.html b/_modules/qs_codec/models/undefined.html new file mode 100644 index 0000000..26aa528 --- /dev/null +++ b/_modules/qs_codec/models/undefined.html @@ -0,0 +1,121 @@ + + + + + + + qs_codec.models.undefined — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.undefined

+"""Undefined class definition."""
+
+
+
+[docs] +class Undefined: + """Singleton class to represent undefined values.""" + + _instance = None + + def __new__(cls): + """Create a new instance of the class.""" + if cls._instance is None: + cls._instance = super(Undefined, cls).__new__(cls) + return cls._instance
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/weak_wrapper.html b/_modules/qs_codec/models/weak_wrapper.html new file mode 100644 index 0000000..daa5357 --- /dev/null +++ b/_modules/qs_codec/models/weak_wrapper.html @@ -0,0 +1,147 @@ + + + + + + + qs_codec.models.weak_wrapper — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.weak_wrapper

+"""A wrapper that allows weak references to be used as dictionary keys."""
+
+import typing as t
+from dataclasses import dataclass
+
+
+
+[docs] +@dataclass(frozen=True) +class WeakWrapper: + """A wrapper that allows weak references to be used as dictionary keys.""" + + value: t.Any + + def __hash__(self) -> int: + """Return the hash of the value.""" + return hash(self._hash_recursive(self.value, seen=set(), stack=set())) + + def _hash_recursive( + self, value: t.Any, seen: set, stack: set, depth: int = 0, max_depth: int = 1000 + ) -> t.Union[t.Tuple, t.Any]: + """Recursively hash a value.""" + if id(value) in stack: + raise ValueError("Circular reference detected") + + seen.add(id(value)) + stack.add(id(value)) + + if depth > max_depth: + raise ValueError("Maximum recursion depth exceeded") + + if isinstance(value, t.Mapping): + result = tuple((k, self._hash_recursive(v, seen, stack, depth + 1)) for k, v in sorted(value.items())) + elif isinstance(value, (t.List, t.Set)): + result = tuple(self._hash_recursive(v, seen, stack, depth + 1) for v in value) + else: + result = value + + stack.remove(id(value)) + + return result
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/decode_utils.html b/_modules/qs_codec/utils/decode_utils.html new file mode 100644 index 0000000..9227dfc --- /dev/null +++ b/_modules/qs_codec/utils/decode_utils.html @@ -0,0 +1,177 @@ + + + + + + + qs_codec.utils.decode_utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.decode_utils

+"""Decode utility methods used by the library."""
+
+import re
+import typing as t
+from urllib.parse import unquote
+
+from ..enums.charset import Charset
+from .str_utils import code_unit_at
+
+
+
+[docs] +class DecodeUtils: + """A collection of decode utility methods used by the library.""" + +
+[docs] + @classmethod + def unescape(cls, string: str) -> str: + """A Python representation the deprecated JavaScript unescape function. + + https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/unescape + """ + buffer: t.List[str] = [] + + i: int = 0 + while i < len(string): + c: int = code_unit_at(string, i) + + if c == 0x25: + if string[i + 1] == "u": + buffer.append( + chr(int(string[i + 2 : i + 6], 16)), + ) + i += 6 + continue + + buffer.append(chr(int(string[i + 1 : i + 3], 16))) + i += 3 + continue + + buffer.append(string[i]) + i += 1 + + return "".join(buffer)
+ + +
+[docs] + @classmethod + def decode( + cls, + string: t.Optional[str], + charset: t.Optional[Charset] = Charset.UTF8, + ) -> t.Optional[str]: + """Decode a URL-encoded string.""" + if string is None: + return None + + string_without_plus: str = string.replace("+", " ") + + if charset == Charset.LATIN1: + return re.sub( + r"%[0-9a-f]{2}", + lambda match: cls.unescape(match.group(0)), + string_without_plus, + flags=re.IGNORECASE, + ) + + return unquote(string_without_plus)
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/encode_utils.html b/_modules/qs_codec/utils/encode_utils.html new file mode 100644 index 0000000..cd24f14 --- /dev/null +++ b/_modules/qs_codec/utils/encode_utils.html @@ -0,0 +1,266 @@ + + + + + + + qs_codec.utils.encode_utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.encode_utils

+"""A collection of encode utility methods used by the library."""
+
+import re
+import typing as t
+from datetime import datetime
+from decimal import Decimal
+from enum import Enum
+
+from ..enums.charset import Charset
+from ..enums.format import Format
+from .str_utils import code_unit_at
+
+
+
+[docs] +class EncodeUtils: + """A collection of encode utility methods used by the library.""" + + HEX_TABLE: t.Tuple[str, ...] = tuple(f"%{i.to_bytes(1, 'big').hex().upper().zfill(2)}" for i in range(256)) + """Hex table of all 256 characters""" + +
+[docs] + @classmethod + def escape( + cls, + string: str, + format: t.Optional[Format] = Format.RFC3986, + ) -> str: + """A Python representation the deprecated JavaScript escape function. + + https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/escape + """ + buffer: t.List[str] = [] + + i: int + for i, _ in enumerate(string): + c: int = code_unit_at(string, i) + + # These 69 characters are safe for escaping + # ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./ + if ( + (0x30 <= c <= 0x39) # 0-9 + or (0x41 <= c <= 0x5A) # A-Z + or (0x61 <= c <= 0x7A) # a-z + or c == 0x40 # @ + or c == 0x2A # * + or c == 0x5F # _ + or c == 0x2D # - + or c == 0x2B # + + or c == 0x2E # . + or c == 0x2F # / + or (format == Format.RFC1738 and (c == 0x28 or c == 0x29)) # ( ) + ): + buffer.append(string[i]) + continue + + if c < 256: + buffer.extend([f"%{c.to_bytes(1, 'big').hex().upper().zfill(2)}"]) + continue + + buffer.extend([f"%u{c.to_bytes(2, 'big').hex().upper().zfill(4)}"]) + + return "".join(buffer)
+ + +
+[docs] + @classmethod + def encode( + cls, + value: t.Any, + charset: t.Optional[Charset] = Charset.UTF8, + format: t.Optional[Format] = Format.RFC3986, + ) -> str: + """Encode a value to a URL-encoded string.""" + if value is None or not isinstance(value, (int, float, Decimal, Enum, str, bool, bytes)): + return "" + + string: str + if isinstance(value, bytes): + string = value.decode("utf-8") + elif isinstance(value, bool): + string = str(value).lower() + elif isinstance(value, str): + string = value + else: + string = str(value) + + if value == "": + return "" + + if charset == Charset.LATIN1: + return re.sub( + r"%u[0-9a-f]{4}", + lambda match: f"%26%23{int(match.group(0)[2:], 16)}%3B", + EncodeUtils.escape(string, format), + flags=re.IGNORECASE, + ) + + buffer: t.List[str] = [] + + i: int + for i, _ in enumerate(string): + c: int = code_unit_at(string, i) + + if ( + c == 0x2D # - + or c == 0x2E # . + or c == 0x5F # _ + or c == 0x7E # ~ + or (0x30 <= c <= 0x39) # 0-9 + or (0x41 <= c <= 0x5A) # a-z + or (0x61 <= c <= 0x7A) # A-Z + or (format == Format.RFC1738 and (c == 0x28 or c == 0x29)) # ( ) + ): + buffer.append(string[i]) + continue + elif c < 0x80: # ASCII + buffer.extend([cls.HEX_TABLE[c]]) + continue + elif c < 0x800: # 2 bytes + buffer.extend( + [ + cls.HEX_TABLE[0xC0 | (c >> 6)], + cls.HEX_TABLE[0x80 | (c & 0x3F)], + ], + ) + continue + elif c < 0xD800 or c >= 0xE000: # 3 bytes + buffer.extend( + [ + cls.HEX_TABLE[0xE0 | (c >> 12)], + cls.HEX_TABLE[0x80 | ((c >> 6) & 0x3F)], + cls.HEX_TABLE[0x80 | (c & 0x3F)], + ], + ) + continue + else: + i += 1 + c = 0x10000 + (((c & 0x3FF) << 10) | (code_unit_at(string, i) & 0x3FF)) + buffer.extend( + [ + cls.HEX_TABLE[0xF0 | (c >> 18)], + cls.HEX_TABLE[0x80 | ((c >> 12) & 0x3F)], + cls.HEX_TABLE[0x80 | ((c >> 6) & 0x3F)], + cls.HEX_TABLE[0x80 | (c & 0x3F)], + ], + ) + + return "".join(buffer)
+ + +
+[docs] + @staticmethod + def serialize_date(dt: datetime) -> str: + """Serialize a `datetime` object to an ISO 8601 string.""" + return dt.isoformat()
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/str_utils.html b/_modules/qs_codec/utils/str_utils.html new file mode 100644 index 0000000..ecec379 --- /dev/null +++ b/_modules/qs_codec/utils/str_utils.html @@ -0,0 +1,123 @@ + + + + + + + qs_codec.utils.str_utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.str_utils

+"""Utility functions for working with strings."""
+
+
+
+[docs] +def code_unit_at(string: str, index: int) -> int: + """Returns the 16-bit UTF-16 code unit at the given index. + + This function first encodes the string in UTF-16 little endian format, then calculates the code unit at the + given index. The code unit is calculated by taking the byte at the index and adding it to 256 times the next + byte. This is because UTF-16 represents each code unit with two bytes, and in little endian format, the least + significant byte comes first. + + Adapted from https://api.dart.dev/stable/3.3.3/dart-core/String/codeUnitAt.html + """ + encoded_string: bytes = string.encode("utf-16-le") + return encoded_string[index * 2] + 256 * encoded_string[index * 2 + 1]
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/utils.html b/_modules/qs_codec/utils/utils.html new file mode 100644 index 0000000..01291fd --- /dev/null +++ b/_modules/qs_codec/utils/utils.html @@ -0,0 +1,347 @@ + + + + + + + qs_codec.utils.utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.utils

+"""A collection of utility methods used by the library."""
+
+import copy
+import typing as t
+from datetime import datetime, timedelta
+from decimal import Decimal
+from enum import Enum
+
+from ..models.decode_options import DecodeOptions
+from ..models.undefined import Undefined
+
+
+
+[docs] +class Utils: + """A collection of utility methods used by the library.""" + +
+[docs] + @staticmethod + def merge( + target: t.Optional[t.Union[t.Mapping, t.List, t.Tuple]], + source: t.Optional[t.Union[t.Mapping, t.List, t.Tuple, t.Any]], + options: DecodeOptions = DecodeOptions(), + ) -> t.Union[t.Dict, t.List, t.Tuple, t.Any]: + """Merge two objects together.""" + if source is None: + return target + + if not isinstance(source, t.Mapping): + if isinstance(target, (list, tuple)): + if any(isinstance(el, Undefined) for el in target): + target_: t.Dict[int, t.Any] = dict(enumerate(target)) + + if isinstance(source, (list, tuple)): + for i, item in enumerate(source): + if not isinstance(item, Undefined): + target_[i] = item + else: + target_[len(target_)] = source + + target = list(filter(lambda el: not isinstance(el, Undefined), target_.values())) + else: + if isinstance(source, (list, tuple)): + if all((isinstance(el, t.Mapping) or isinstance(el, Undefined)) for el in target) and all( + (isinstance(el, t.Mapping) or isinstance(el, Undefined)) for el in source + ): + target__: t.Dict[int, t.Any] = dict(enumerate(target)) + target = list( + { + i: Utils.merge(target__[i], item, options) if i in target__ else item + for i, item in enumerate(source) + }.values() + ) + else: + if isinstance(target, tuple): + target = list(target) + target.extend(filter(lambda el: not isinstance(el, Undefined), source)) + elif source is not None: + if isinstance(target, tuple): + target = list(target) + target.append(source) + elif isinstance(target, t.Mapping): + if isinstance(source, (list, tuple)): + target = { + **target, + **{i: item for i, item in enumerate(source) if not isinstance(item, Undefined)}, + } + elif source is not None: + if not isinstance(target, (list, tuple)) and isinstance(source, (list, tuple)): + return [target, *filter(lambda el: not isinstance(el, Undefined), source)] + return [target, source] + + return target + + if target is None or not isinstance(target, t.Mapping): + if isinstance(target, (list, tuple)): + return { + **{i: item for i, item in enumerate(target) if not isinstance(item, Undefined)}, + **source, + } + + return [ + el + for el in (target if isinstance(target, (list, tuple)) else [target]) + if not isinstance(el, Undefined) + ] + [ + el + for el in (source if isinstance(source, (list, tuple)) else [source]) + if not isinstance(el, Undefined) + ] + + merge_target: t.Dict = ( + dict(enumerate(el for el in source if not isinstance(el, Undefined))) + if isinstance(target, (list, tuple)) and not isinstance(source, (list, tuple)) + else copy.deepcopy(dict(target) if not isinstance(target, dict) else target) + ) + + return { + **merge_target, + **{ + key: Utils.merge(merge_target[key], value, options) if key in merge_target else value + for key, value in source.items() + }, + }
+ + +
+[docs] + @staticmethod + def compact(value: t.Dict) -> t.Dict: + """Remove all `Undefined` values from a dictionary.""" + queue: t.List[t.Dict] = [{"obj": {"o": value}, "prop": "o"}] + refs: t.List = [] + + for i in range(len(queue)): # pylint: disable=C0200 + item: t.Mapping = queue[i] + obj: t.Mapping = item["obj"][item["prop"]] + + keys: t.List = list(obj.keys()) + for key in keys: + val = obj.get(key) + + if ( + val is not None + and not isinstance(val, Undefined) + and isinstance(val, t.Mapping) + and val not in refs + ): + queue.append({"obj": obj, "prop": key}) + refs.append(val) + + Utils._compact_queue(queue) + Utils._remove_undefined_from_map(value) + + return value
+ + + @staticmethod + def _compact_queue(queue: t.List[t.Dict]) -> None: + while len(queue) > 1: + item = queue.pop() + obj = item["obj"][item["prop"]] + + if isinstance(obj, (list, tuple)): + item["obj"][item["prop"]] = list(filter(lambda el: not isinstance(el, Undefined), obj)) + + @staticmethod + def _remove_undefined_from_list(value: t.List) -> None: + i: int = len(value) - 1 + while i >= 0: + item = value[i] + if isinstance(item, Undefined): + value.pop(i) + elif isinstance(item, dict): + Utils._remove_undefined_from_map(item) + elif isinstance(item, list): + Utils._remove_undefined_from_list(item) + elif isinstance(item, tuple): + value[i] = list(item) + Utils._remove_undefined_from_list(value[i]) + i -= 1 + + @staticmethod + def _remove_undefined_from_map(obj: t.Dict) -> None: + keys: t.List = list(obj.keys()) + for key in keys: + val = obj[key] + if isinstance(val, Undefined): + obj.pop(key) + elif isinstance(val, dict) and not Utils._dicts_are_equal(val, obj): + Utils._remove_undefined_from_map(val) + elif isinstance(val, list): + Utils._remove_undefined_from_list(val) + elif isinstance(val, tuple): + obj[key] = list(val) + Utils._remove_undefined_from_list(obj[key]) + + @staticmethod + def _dicts_are_equal(d1: t.Mapping, d2: t.Mapping, path=None) -> bool: + if path is None: + path = set() + + if id(d1) in path or id(d2) in path: + return True + + path.add(id(d1)) + path.add(id(d2)) + + if isinstance(d1, dict) and isinstance(d2, dict): + if len(d1) != len(d2): + return False + for k, v in d1.items(): + if k not in d2: + return False + if not Utils._dicts_are_equal(v, d2[k], path): + return False + return True + else: + return d1 == d2 + +
+[docs] + @staticmethod + def combine(a: t.Union[list, tuple, t.Any], b: t.Union[list, tuple, t.Any]) -> t.List: + """Combine two lists or values.""" + return [*(a if isinstance(a, (list, tuple)) else [a]), *(b if isinstance(b, (list, tuple)) else [b])]
+ + +
+[docs] + @staticmethod + def apply(val: t.Union[list, tuple, t.Any], fn: t.Callable) -> t.Union[t.List, t.Any]: + """Apply a function to a value or a list of values.""" + return [fn(item) for item in val] if isinstance(val, (list, tuple)) else fn(val)
+ + +
+[docs] + @staticmethod + def is_non_nullish_primitive(val: t.Any, skip_nulls: bool = False) -> bool: + """Check if a value is a non-nullish primitive.""" + if val is None: + return False + + if isinstance(val, str): + return val != "" if skip_nulls else True + + if isinstance(val, (int, float, Decimal, bool, Enum, datetime, timedelta)): + return True + + if isinstance(val, Undefined): + return False + + if isinstance(val, object): + if isinstance(val, (list, tuple, t.Mapping)): + return False + return True + + return False
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_sources/README.rst.txt b/_sources/README.rst.txt new file mode 100644 index 0000000..db8e9c8 --- /dev/null +++ b/_sources/README.rst.txt @@ -0,0 +1,951 @@ +Decoding +~~~~~~~~ + +dictionaries +^^^^^^^^^^^^ + +.. code:: python + + import qs_codec, typing as t + + def decode( + value: t.Optional[t.Union[str, t.Mapping]], + options: qs_codec.DecodeOptions = qs_codec.DecodeOptions(), + ) -> dict: + """Decodes a str or Mapping into a Dict. + + Providing custom DecodeOptions will override the default behavior.""" + pass + +:py:attr:`decode ` allows you to create nested ``dict``\ s within your query +strings, by surrounding the name of sub-keys with square brackets +``[]``. For example, the string ``'foo[bar]=baz'`` converts to: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('foo[bar]=baz') == {'foo': {'bar': 'baz'}} + +URI encoded strings work too: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a%5Bb%5D=c') == {'a': {'b': 'c'}} + +You can also nest your ``dict``\ s, like ``'foo[bar][baz]=foobarbaz'``: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('foo[bar][baz]=foobarbaz') == {'foo': {'bar': {'baz': 'foobarbaz'}}} + +By default, when nesting ``dict``\ s qs will only decode up to 5 +children deep. This means if you attempt to decode a string like +``'a[b][c][d][e][f][g][h][i]=j'`` your resulting ``dict`` will be: + +.. code:: python + + import qs_codec + + assert qs_codec.decode("a[b][c][d][e][f][g][h][i]=j") == { + "a": {"b": {"c": {"d": {"e": {"f": {"[g][h][i]": "j"}}}}}} + } + +This depth can be overridden by setting the :py:attr:`depth `: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a[b][c][d][e][f][g][h][i]=j', + qs_codec.DecodeOptions(depth=1), + ) == {'a': {'b': {'[c][d][e][f][g][h][i]': 'j'}}} + +The depth limit helps mitigate abuse when :py:attr:`decode ` is used to parse user +input, and it is recommended to keep it a reasonably small number. + +For similar reasons, by default :py:attr:`decode ` will only parse up to 1000 parameters. This can be overridden by passing a +:py:attr:`parameter_limit ` option: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=b&c=d', + qs_codec.DecodeOptions(parameter_limit=1), + ) == {'a': 'b'} + +To bypass the leading question mark, use +:py:attr:`ignore_query_prefix `: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + '?a=b&c=d', + qs_codec.DecodeOptions(ignore_query_prefix=True), + ) == {'a': 'b', 'c': 'd'} + +An optional :py:attr:`delimiter ` can also be passed: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=b;c=d', + qs_codec.DecodeOptions(delimiter=';'), + ) == {'a': 'b', 'c': 'd'} + +:py:attr:`delimiter ` can be a regular expression too: + +.. code:: python + + import re, qs_codec + + assert qs_codec.decode( + 'a=b;c=d', + qs_codec.DecodeOptions(delimiter=re.compile(r'[;,]')), + ) == {'a': 'b', 'c': 'd'} + +Option :py:attr:`allow_dots ` +can be used to enable dot notation: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a.b=c', + qs_codec.DecodeOptions(allow_dots=True), + ) == {'a': {'b': 'c'}} + +Option :py:attr:`decode_dot_in_keys ` +can be used to decode dots in keys. + +**Note:** it implies :py:attr:`allow_dots `, so +:py:attr:`decode ` will error if you set :py:attr:`decode_dot_in_keys ` +to ``True``, and :py:attr:`allow_dots ` to ``False``. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'name%252Eobj.first=John&name%252Eobj.last=Doe', + qs_codec.DecodeOptions(decode_dot_in_keys=True), + ) == {'name.obj': {'first': 'John', 'last': 'Doe'}} + +Option :py:attr:`allow_empty_lists ` can +be used to allowing empty ``list`` values in a ``dict`` + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'foo[]&bar=baz', + qs_codec.DecodeOptions(allow_empty_lists=True), + ) == {'foo': [], 'bar': 'baz'} + +Option :py:attr:`duplicates ` can be used to +change the behavior when duplicate keys are encountered + +.. code:: python + + import qs_codec + + assert qs_codec.decode('foo=bar&foo=baz') == {'foo': ['bar', 'baz']} + + assert qs_codec.decode( + 'foo=bar&foo=baz', + qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.COMBINE), + ) == {'foo': ['bar', 'baz']} + + assert qs_codec.decode( + 'foo=bar&foo=baz', + qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.FIRST), + ) == {'foo': 'bar'} + + assert qs_codec.decode( + 'foo=bar&foo=baz', + qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.LAST), + ) == {'foo': 'baz'} + +If you have to deal with legacy browsers or services, there’s also +support for decoding percent-encoded octets as :py:attr:`LATIN1 `: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=%A7', + qs_codec.DecodeOptions(charset=qs_codec.Charset.LATIN1), + ) == {'a': '§'} + +Some services add an initial ``utf8=✓`` value to forms so that old +Internet Explorer versions are more likely to submit the form as utf-8. +Additionally, the server can check the value against wrong encodings of +the checkmark character and detect that a query string or +``application/x-www-form-urlencoded`` body was *not* sent as ``utf-8``, +e.g. if the form had an ``accept-charset`` parameter or the containing +page had a different character set. + +:py:attr:`decode ` supports this mechanism via the +:py:attr:`charset_sentinel ` option. +If specified, the ``utf8`` parameter will be omitted from the returned +``dict``. It will be used to switch to :py:attr:`LATIN1 ` or +:py:attr:`UTF8 ` mode depending on how the checkmark is encoded. + +**Important**: When you specify both the :py:attr:`charset ` +option and the :py:attr:`charset_sentinel ` option, the +:py:attr:`charset ` will be overridden when the request contains a +``utf8`` parameter from which the actual charset can be deduced. In that +sense the :py:attr:`charset ` will behave as the default charset +rather than the authoritative charset. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'utf8=%E2%9C%93&a=%C3%B8', + qs_codec.DecodeOptions( + charset=qs_codec.Charset.LATIN1, + charset_sentinel=True, + ), + ) == {'a': 'ø'} + + assert qs_codec.decode( + 'utf8=%26%2310003%3B&a=%F8', + qs_codec.DecodeOptions( + charset=qs_codec.Charset.UTF8, + charset_sentinel=True, + ), + ) == {'a': 'ø'} + +If you want to decode the `&#...; `_ syntax to the actual character, you can specify the +:py:attr:`interpret_numeric_entities ` +option as well: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=%26%239786%3B', + qs_codec.DecodeOptions( + charset=qs_codec.Charset.LATIN1, + interpret_numeric_entities=True, + ), + ) == {'a': '☺'} + +It also works when the charset has been detected in +:py:attr:`charset_sentinel ` mode. + +lists +^^^^^ + +:py:attr:`decode ` can also decode ``list``\ s using a similar ``[]`` notation: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[]=b&a[]=c') == {'a': ['b', 'c']} + +You may specify an index as well: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[1]=c&a[0]=b') == {'a': ['b', 'c']} + +Note that the only difference between an index in a ``list`` and a key +in a ``dict`` is that the value between the brackets must be a number to +create a ``list``. When creating ``list``\ s with specific indices, +:py:attr:`decode ` will compact a sparse ``list`` to +only the existing values preserving their order: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[1]=b&a[15]=c') == {'a': ['b', 'c']} + +Note that an empty ``str``\ing is also a value, and will be preserved: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[]=&a[]=b') == {'a': ['', 'b']} + + assert qs_codec.decode('a[0]=b&a[1]=&a[2]=c') == {'a': ['b', '', 'c']} + +:py:attr:`decode ` will also limit specifying indices +in a ``list`` to a maximum index of ``20``. Any ``list`` members with an +index of greater than ``20`` will instead be converted to a ``dict`` with +the index as the key. This is needed to handle cases when someone sent, +for example, ``a[999999999]`` and it will take significant time to iterate +over this huge ``list``. + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[100]=b') == {'a': {100: 'b'}} + +This limit can be overridden by passing an :py:attr:`list_limit ` +option: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a[1]=b', + qs_codec.DecodeOptions(list_limit=0), + ) == {'a': {1: 'b'}} + +To disable ``list`` parsing entirely, set :py:attr:`parse_lists ` +to ``False``. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a[]=b', + qs_codec.DecodeOptions(parse_lists=False), + ) == {'a': {0: 'b'}} + +If you mix notations, :py:attr:`decode ` will merge the two items into a ``dict``: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[0]=b&a[b]=c') == {'a': {0: 'b', 'b': 'c'}} + +You can also create ``list``\ s of ``dict``\ s: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[][b]=c') == {'a': [{'b': 'c'}]} + +(:py:attr:`decode ` *cannot convert nested ``dict``\ s, such as ``'a={b:1},{c:d}'``*) + +primitive values (``int``, ``bool``, ``None``, etc.) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, all values are parsed as ``str``\ings. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=15&b=true&c=null', + ) == {'a': '15', 'b': 'true', 'c': 'null'} + +Encoding +~~~~~~~~ + +.. code:: python + + import qs_codec, typing as t + + def encode( + value: t.Any, + options: qs_codec.EncodeOptions = qs_codec.EncodeOptions() + ) -> str: + """Encodes an object into a query string. + + Providing custom EncodeOptions will override the default behavior.""" + pass + +When encoding, :py:attr:`encode ` by default URI encodes output. ``dict``\ s are +encoded as you would expect: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': 'b'}) == 'a=b' + assert qs_codec.encode({'a': {'b': 'c'}}) == 'a%5Bb%5D=c' + +This encoding can be disabled by setting the :py:attr:`encode ` +option to ``False``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': {'b': 'c'}}, + qs_codec.EncodeOptions(encode=False), + ) == 'a[b]=c' + +Encoding can be disabled for keys by setting the +:py:attr:`encode_values_only ` option to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + { + 'a': 'b', + 'c': ['d', 'e=f'], + 'f': [ + ['g'], + ['h'] + ] + }, + qs_codec.EncodeOptions(encode_values_only=True) + ) == 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h' + +This encoding can also be replaced by a custom ``Callable`` in the +:py:attr:`encoder ` option: + +.. code:: python + + import qs_codec, typing as t + + + def custom_encoder( + value: str, + charset: t.Optional[qs_codec.Charset], + format: t.Optional[qs_codec.Format], + ) -> str: + if value == 'č': + return 'c' + return value + + + assert qs_codec.encode( + {'a': {'b': 'č'}}, + qs_codec.EncodeOptions(encoder=custom_encoder), + ) == 'a[b]=c' + +(Note: the :py:attr:`encoder ` option does not apply if +:py:attr:`encode ` is ``False``). + +Similar to :py:attr:`encoder ` there is a +:py:attr:`decoder ` option for :py:attr:`decode ` +to override decoding of properties and values: + +.. code:: python + + import qs_codec, typing as t + + def custom_decoder( + value: t.Any, + charset: t.Optional[qs_codec.Charset], + ) -> t.Union[int, str]: + try: + return int(value) + except ValueError: + return value + + assert qs_codec.decode( + 'foo=123', + qs_codec.DecodeOptions(decoder=custom_decoder), + ) == {'foo': 123} + +Examples beyond this point will be shown as though the output is not URI +encoded for clarity. Please note that the return values in these cases +*will* be URI encoded during real usage. + +When ``list``\s are encoded, they follow the +:py:attr:`list_format ` option, which defaults to +:py:attr:`INDICES `: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': ['b', 'c', 'd']}, + qs_codec.EncodeOptions(encode=False) + ) == 'a[0]=b&a[1]=c&a[2]=d' + +You may override this by setting the :py:attr:`indices ` option to +``False``, or to be more explicit, the :py:attr:`list_format ` +option to :py:attr:`REPEAT `: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': ['b', 'c', 'd']}, + qs_codec.EncodeOptions( + encode=False, + indices=False, + ), + ) == 'a=b&a=c&a=d' + +You may use the :py:attr:`list_format ` option to specify the +format of the output ``list``: + +.. code:: python + + import qs_codec + + # ListFormat.INDICES + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.INDICES, + ), + ) == 'a[0]=b&a[1]=c' + + # ListFormat.BRACKETS + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.BRACKETS, + ), + ) == 'a[]=b&a[]=c' + + # ListFormat.REPEAT + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.REPEAT, + ), + ) == 'a=b&a=c' + + # ListFormat.COMMA + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.COMMA, + ), + ) == 'a=b,c' + +**Note:** When using :py:attr:`list_format ` set to +:py:attr:`COMMA `, you can also pass the +:py:attr:`comma_round_trip ` option set to ``True`` or +``False``, to append ``[]`` on single-item ``list``\ s, so that they can round trip through a decoding. + +:py:attr:`BRACKETS ` notation is used for encoding ``dict``\s by default: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': {'b': {'c': 'd', 'e': 'f'}}}, + qs_codec.EncodeOptions(encode=False), + ) == 'a[b][c]=d&a[b][e]=f' + +You may override this to use dot notation by setting the +:py:attr:`allow_dots ` option to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': {'b': {'c': 'd', 'e': 'f'}}}, + qs_codec.EncodeOptions(encode=False, allow_dots=True), + ) == 'a.b.c=d&a.b.e=f' + +You may encode dots in keys of ``dict``\s by setting +:py:attr:`encode_dot_in_keys ` to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'name.obj': {'first': 'John', 'last': 'Doe'}}, + qs_codec.EncodeOptions( + allow_dots=True, + encode_dot_in_keys=True, + ), + ) == 'name%252Eobj.first=John&name%252Eobj.last=Doe' + +**Caveat:** When both :py:attr:`encode_values_only ` +and :py:attr:`encode_dot_in_keys ` are set to +``True``, only dots in keys and nothing else will be encoded! + +You may allow empty ``list`` values by setting the +:py:attr:`allow_empty_lists ` option to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'foo': [], 'bar': 'baz', }, + qs_codec.EncodeOptions( + encode=False, + allow_empty_lists=True, + ), + ) == 'foo[]&bar=baz' + +Empty ``str``\ings and ``None`` values will be omitted, but the equals sign (``=``) remains in place: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': ''}) == 'a=' + +Keys with no values (such as an empty ``dict`` or ``list``) will return nothing: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': []}) == '' + + assert qs_codec.encode({'a': {}}) == '' + + assert qs_codec.encode({'a': [{}]}) == '' + + assert qs_codec.encode({'a': {'b': []}}) == '' + + assert qs_codec.encode({'a': {'b': {}}}) == '' + +:py:attr:`Undefined ` properties will be omitted entirely: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': None, 'b': qs_codec.Undefined()}) == 'a=' + +The query string may optionally be prepended with a question mark (``?``) by setting +:py:attr:`add_query_prefix ` to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b', 'c': 'd'}, + qs_codec.EncodeOptions(add_query_prefix=True), + ) == '?a=b&c=d' + +The :py:attr:`delimiter ` may be overridden as well: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b', 'c': 'd', }, + qs_codec.EncodeOptions(delimiter=';') + ) == 'a=b;c=d' + +If you only want to override the serialization of `datetime `_ +objects, you can provide a ``Callable`` in the +:py:attr:`serialize_date ` option: + +.. code:: python + + import qs_codec, datetime, sys + + # First case: encoding a datetime object to an ISO 8601 string + assert ( + qs_codec.encode( + { + "a": ( + datetime.datetime.fromtimestamp(7, datetime.UTC) + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else datetime.datetime.utcfromtimestamp(7) + ) + }, + qs_codec.EncodeOptions(encode=False), + ) + == "a=1970-01-01T00:00:07+00:00" + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else "a=1970-01-01T00:00:07" + ) + + # Second case: encoding a datetime object to a timestamp string + assert ( + qs_codec.encode( + { + "a": ( + datetime.datetime.fromtimestamp(7, datetime.UTC) + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else datetime.datetime.utcfromtimestamp(7) + ) + }, + qs_codec.EncodeOptions(encode=False, serialize_date=lambda date: str(int(date.timestamp()))), + ) + == "a=7" + ) + +To affect the order of parameter keys, you can set a ``Callable`` in the +:py:attr:`sort ` option: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'c', 'z': 'y', 'b': 'f'}, + qs_codec.EncodeOptions( + encode=False, + sort=lambda a, b: (a > b) - (a < b) + ) + ) == 'a=c&b=f&z=y' + +Finally, you can use the :py:attr:`filter ` option to restrict +which keys will be included in the encoded output. If you pass a ``Callable``, it will be called for each key to obtain +the replacement value. Otherwise, if you pass a ``list``, it will be used to select properties and ``list`` indices to +be encoded: + +.. code:: python + + import qs_codec, datetime, sys + + # First case: using a Callable as filter + assert ( + qs_codec.encode( + { + "a": "b", + "c": "d", + "e": { + "f": ( + datetime.datetime.fromtimestamp(123, datetime.UTC) + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else datetime.datetime.utcfromtimestamp(123) + ), + "g": [2], + }, + }, + qs_codec.EncodeOptions( + encode=False, + filter=lambda prefix, value: { + "b": None, + "e[f]": int(value.timestamp()) if isinstance(value, datetime.datetime) else value, + "e[g][0]": value * 2 if isinstance(value, int) else value, + }.get(prefix, value), + ), + ) + == "a=b&c=d&e[f]=123&e[g][0]=4" + ) + + # Second case: using a list as filter + assert qs_codec.encode( + {'a': 'b', 'c': 'd', 'e': 'f'}, + qs_codec.EncodeOptions( + encode=False, + filter=['a', 'e'] + ) + ) == 'a=b&e=f' + + # Third case: using a list as filter with indices + assert qs_codec.encode( + { + 'a': ['b', 'c', 'd'], + 'e': 'f', + }, + qs_codec.EncodeOptions( + encode=False, + filter=['a', 0, 2] + ) + ) == 'a[0]=b&a[2]=d' + +Handling ``None`` values +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, ``None`` values are treated like empty ``str``\ings: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': None, 'b': ''}) == 'a=&b=' + +To distinguish between ``None`` values and empty ``str``\s use the +:py:attr:`strict_null_handling ` flag. +In the result string the ``None`` values have no ``=`` sign: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': None, 'b': ''}, + qs_codec.EncodeOptions(strict_null_handling=True), + ) == 'a&b=' + +To decode values without ``=`` back to ``None`` use the +:py:attr:`strict_null_handling ` flag: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a&b=', + qs_codec.DecodeOptions(strict_null_handling=True), + ) == {'a': None, 'b': ''} + +To completely skip rendering keys with ``None`` values, use the +:py:attr:`skip_nulls ` flag: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b', 'c': None}, + qs_codec.EncodeOptions(skip_nulls=True), + ) == 'a=b' + +If you’re communicating with legacy systems, you can switch to +:py:attr:`LATIN1 ` using the +:py:attr:`charset ` option: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'æ': 'æ'}, + qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1) + ) == '%E6=%E6' + +Characters that don’t exist in :py:attr:`LATIN1 ` +will be converted to numeric entities, similar to what browsers do: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': '☺'}, + qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1) + ) == 'a=%26%239786%3B' + +You can use the :py:attr:`charset_sentinel ` +option to announce the character by including an ``utf8=✓`` parameter with the proper +encoding of the checkmark, similar to what Ruby on Rails and others do when submitting forms. + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': '☺'}, + qs_codec.EncodeOptions(charset_sentinel=True) + ) == 'utf8=%E2%9C%93&a=%E2%98%BA' + + assert qs_codec.encode( + {'a': 'æ'}, + qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1, charset_sentinel=True) + ) == 'utf8=%26%2310003%3B&a=%E6' + +Dealing with special character sets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, the encoding and decoding of characters is done in +:py:attr:`UTF8 `, and +:py:attr:`LATIN1 ` support is also built in via +the :py:attr:`charset ` +and :py:attr:`charset ` parameter, +respectively. + +If you wish to encode query strings to a different character set (i.e. +`Shift JIS `__) + +.. code:: python + + import qs_codec, codecs, typing as t + + def custom_encoder( + string: str, + charset: t.Optional[qs_codec.Charset], + format: t.Optional[qs_codec.Format], + ) -> str: + if string: + buf: bytes = codecs.encode(string, 'shift_jis') + result: t.List[str] = ['{:02x}'.format(b) for b in buf] + return '%' + '%'.join(result) + return '' + + assert qs_codec.encode( + {'a': 'こんにちは!'}, + qs_codec.EncodeOptions(encoder=custom_encoder) + ) == '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49' + +This also works for decoding of query strings: + +.. code:: python + + import qs_codec, re, codecs, typing as t + + def custom_decoder( + string: str, + charset: t.Optional[qs_codec.Charset], + ) -> t.Optional[str]: + if string: + result: t.List[int] = [] + while string: + match: t.Optional[t.Match[str]] = re.search(r'%([0-9A-F]{2})', string, re.IGNORECASE) + if match: + result.append(int(match.group(1), 16)) + string = string[match.end():] + else: + break + buf: bytes = bytes(result) + return codecs.decode(buf, 'shift_jis') + return None + + assert qs_codec.decode( + '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49', + qs_codec.DecodeOptions(decoder=custom_decoder) + ) == {'a': 'こんにちは!'} + +RFC 3986 and RFC 1738 space encoding +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default :py:attr:`format ` is +:py:attr:`RFC3986 ` which encodes +``' '`` to ``%20`` which is backward compatible. You can also set the +:py:attr:`format ` to +:py:attr:`RFC1738 ` which encodes ``' '`` to ``+``. + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b c'}, + qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986) + ) == 'a=b%20c' + + assert qs_codec.encode( + {'a': 'b c'}, + qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986) + ) == 'a=b%20c' + + assert qs_codec.encode( + {'a': 'b c'}, + qs_codec.EncodeOptions(format=qs_codec.Format.RFC1738) + ) == 'a=b+c' diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..b0b2d69 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,92 @@ +.. qs-codec documentation master file, created by + sphinx-quickstart on Sun Apr 28 13:58:45 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +qs-codec +======== + +A query string encoding and decoding library for Python. + +Ported from `qs `__ for JavaScript. + +|PyPI - Version| |PyPI - Downloads| |PyPI - Status| |PyPI - Python Version| |PyPI - Format| |Black| +|Test| |CodeQL| |Publish| |Docs| |codecov| |Codacy| |Black| |flake8| |mypy| |pylint| |isort| |bandit| +|License| |Contributor Covenant| |GitHub Sponsors| |GitHub Repo stars| + +Usage +----- + +A simple usage example: + +.. code:: python + + import qs_codec + + # Encoding + assert qs_codec.encode({'a': 'b'}) == 'a=b' + + # Decoding + assert qs_codec.decode('a=b') == {'a': 'b'} + +.. toctree:: + :maxdepth: 4 + :caption: Contents: + + README + qs_codec + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +-------------- + +Special thanks to the authors of +`qs `__ for JavaScript: - `Jordan +Harband `__ - `TJ +Holowaychuk `__ + +.. |PyPI - Version| image:: https://img.shields.io/pypi/v/qs_codec + :target: https://pypi.org/project/qs-codec/ +.. |PyPI - Downloads| image:: https://img.shields.io/pypi/dm/qs_codec + :target: https://pypistats.org/packages/qs-codec +.. |PyPI - Status| image:: https://img.shields.io/pypi/status/qs_codec +.. |PyPI - Python Version| image:: https://img.shields.io/pypi/pyversions/qs_codec +.. |PyPI - Format| image:: https://img.shields.io/pypi/format/qs_codec +.. |Test| image:: https://github.com/techouse/qs_codec/actions/workflows/test.yml/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/test.yml +.. |CodeQL| image:: https://github.com/techouse/qs_codec/actions/workflows/github-code-scanning/codeql/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/github-code-scanning/codeql +.. |Publish| image:: https://github.com/techouse/qs_codec/actions/workflows/publish.yml/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/publish.yml +.. |Docs| image:: https://github.com/techouse/qs_codec/actions/workflows/docs.yml/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/docs.yml +.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black +.. |codecov| image:: https://codecov.io/gh/techouse/qs_codec/graph/badge.svg?token=Vp0z05yj2l + :target: https://codecov.io/gh/techouse/qs_codec +.. |Codacy| image:: https://app.codacy.com/project/badge/Grade/7ead208221ae4f6785631043064647e4 + :target: https://app.codacy.com/gh/techouse/qs_codec/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade +.. |License| image:: https://img.shields.io/github/license/techouse/qs_codec + :target: LICENSE +.. |GitHub Sponsors| image:: https://img.shields.io/github/sponsors/techouse + :target: https://github.com/sponsors/techouse +.. |GitHub Repo stars| image:: https://img.shields.io/github/stars/techouse/qs_codec + :target: https://github.com/techouse/qs_codec/stargazers +.. |Contributor Covenant| image:: https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg + :target: CODE-OF-CONDUCT.md +.. |flake8| image:: https://img.shields.io/badge/flake8-checked-blueviolet.svg + :target: https://flake8.pycqa.org/en/latest/ +.. |mypy| image:: https://img.shields.io/badge/mypy-checked-blue.svg + :target: https://mypy.readthedocs.io/en/stable/ +.. |pylint| image:: https://img.shields.io/badge/linting-pylint-yellowgreen.svg + :target: https://github.com/pylint-dev/pylint +.. |isort| image:: https://img.shields.io/badge/imports-isort-blue.svg + :target: https://pycqa.github.io/isort/ +.. |bandit| image:: https://img.shields.io/badge/security-bandit-blue.svg + :target: https://github.com/PyCQA/bandit + :alt: Security Status \ No newline at end of file diff --git a/_sources/qs_codec.enums.rst.txt b/_sources/qs_codec.enums.rst.txt new file mode 100644 index 0000000..49e6cd6 --- /dev/null +++ b/_sources/qs_codec.enums.rst.txt @@ -0,0 +1,53 @@ +qs\_codec.enums package +======================= + +Submodules +---------- + +qs\_codec.enums.charset module +------------------------------ + +.. automodule:: qs_codec.enums.charset + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.duplicates module +--------------------------------- + +.. automodule:: qs_codec.enums.duplicates + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.format module +----------------------------- + +.. automodule:: qs_codec.enums.format + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.list\_format module +----------------------------------- + +.. automodule:: qs_codec.enums.list_format + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.sentinel module +------------------------------- + +.. automodule:: qs_codec.enums.sentinel + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec.enums + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/qs_codec.models.rst.txt b/_sources/qs_codec.models.rst.txt new file mode 100644 index 0000000..0cc38fd --- /dev/null +++ b/_sources/qs_codec.models.rst.txt @@ -0,0 +1,45 @@ +qs\_codec.models package +======================== + +Submodules +---------- + +qs\_codec.models.decode\_options module +--------------------------------------- + +.. automodule:: qs_codec.models.decode_options + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.models.encode\_options module +--------------------------------------- + +.. automodule:: qs_codec.models.encode_options + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.models.undefined module +--------------------------------- + +.. automodule:: qs_codec.models.undefined + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.models.weak\_wrapper module +------------------------------------- + +.. automodule:: qs_codec.models.weak_wrapper + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec.models + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/qs_codec.rst.txt b/_sources/qs_codec.rst.txt new file mode 100644 index 0000000..a368826 --- /dev/null +++ b/_sources/qs_codec.rst.txt @@ -0,0 +1,39 @@ +qs\_codec package +================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + qs_codec.enums + qs_codec.models + qs_codec.utils + +Submodules +---------- + +qs\_codec.decode module +----------------------- + +.. automodule:: qs_codec.decode + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.encode module +----------------------- + +.. automodule:: qs_codec.encode + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/qs_codec.utils.rst.txt b/_sources/qs_codec.utils.rst.txt new file mode 100644 index 0000000..40fdf1f --- /dev/null +++ b/_sources/qs_codec.utils.rst.txt @@ -0,0 +1,45 @@ +qs\_codec.utils package +======================= + +Submodules +---------- + +qs\_codec.utils.decode\_utils module +------------------------------------ + +.. automodule:: qs_codec.utils.decode_utils + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.utils.encode\_utils module +------------------------------------ + +.. automodule:: qs_codec.utils.encode_utils + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.utils.str\_utils module +--------------------------------- + +.. automodule:: qs_codec.utils.str_utils + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.utils.utils module +---------------------------- + +.. automodule:: qs_codec.utils.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/_static/alabaster.css b/_static/alabaster.css new file mode 100644 index 0000000..e3174bf --- /dev/null +++ b/_static/alabaster.css @@ -0,0 +1,708 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar { + max-height: 100%; + overflow-y: auto; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 160px; +} + +div.sphinxsidebar .search > div { + display: table-cell; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Hide ugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..e5179b7 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: inherit; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..4d67807 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..add8e0c --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.2.1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 0000000..367b8ed --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..04a4174 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,84 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902 } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000 } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #990000 } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #888888 } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #990000 } /* Literal.Number.Bin */ +.highlight .mf { color: #990000 } /* Literal.Number.Float */ +.highlight .mh { color: #990000 } /* Literal.Number.Hex */ +.highlight .mi { color: #990000 } /* Literal.Number.Integer */ +.highlight .mo { color: #990000 } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..92da3f8 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..66d70c8 --- /dev/null +++ b/genindex.html @@ -0,0 +1,613 @@ + + + + + + + Index — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | H + | I + | L + | M + | P + | Q + | R + | S + | U + | V + | W + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

H

+ + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + +
+ +

P

+ + + +
+ +

Q

+ + + +
    +
  • + qs_codec + +
  • +
  • + qs_codec.decode + +
  • +
  • + qs_codec.encode + +
  • +
  • + qs_codec.enums + +
  • +
  • + qs_codec.enums.charset + +
  • +
  • + qs_codec.enums.duplicates + +
  • +
  • + qs_codec.enums.format + +
  • +
  • + qs_codec.enums.list_format + +
  • +
  • + qs_codec.enums.sentinel + +
  • +
  • + qs_codec.models + +
  • +
    +
  • + qs_codec.models.decode_options + +
  • +
  • + qs_codec.models.encode_options + +
  • +
  • + qs_codec.models.undefined + +
  • +
  • + qs_codec.models.weak_wrapper + +
  • +
  • + qs_codec.utils + +
  • +
  • + qs_codec.utils.decode_utils + +
  • +
  • + qs_codec.utils.encode_utils + +
  • +
  • + qs_codec.utils.str_utils + +
  • +
  • + qs_codec.utils.utils + +
  • +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

U

+ + + +
+ +

V

+ + +
+ +

W

+ + +
+ + + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..d7b3e4f --- /dev/null +++ b/index.html @@ -0,0 +1,201 @@ + + + + + + + + qs-codec — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..2bc470663296931766369508ddfb84949e881583 GIT binary patch literal 1168 zcmV;B1aJEzAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk$b1h?U zWMyLtBOq2~a&u{KZaN?eBOp|0Wgv28ZDDC{WMy(7Z)PBLXlZjGW@&6?AZc?TV{dJ6 za%FRKWn>_Ab7^j8AbM~<}8vVWx?fvbVCfY0lKu1A$zW_JQ3}x%BC)bMRT-9TwrNW z0F#;&Q6z+Ew*mS;0o;uj(}&9fgrwx;C6{t*v7#%1l%-uJ)P9b z0h7o3>*+&iJwTIrJDtrJPKkHp!N6t86J#?zH2~c1IX(T}kO#Bd$>rydS5|{DSRcP! zeR9E)nA;9bApl=SyU`_BuG83#wHsYu79~PL>%bcnaHqZxo&oJ3a6KDOeuRtp!1$e@ zss(*Nc8i=o+)O8-V>@TzQ#f8YWq!j9b0kylEJk}Gc;P78U@0u8V=FsKlLYwy6Bd&Q zd$F103|FhGCs|-73B%N4W$qAQZm@a={D=W2-^a6gICM%L^QQC1-Yhj{Oixq`y6v=Y zs&-v$!Za&tKbI(QQ(ivS;3Jot+`d47C{5pBoa#l^>NW>_oMdtfi|Or2jZqMLgF|x> zdC;=kkldrIMipg97~J5k@TrHlZ%~$GN)l2POg;?HCaE%v$c48Dt8*{Q}hSDpj6&z0R;id+eKnzI-x zcIHQmebVW~*N29_*iJJ3IeLC0nqvV|Mz=ool!3^2nqe-t&e%&ry~Vgb4{^^n9yHy< z4^DI3D-f!LK$QGdlT;N)!%D_(1sjr;dC`-HM9O`+#$`@dTcpZ}498aKd`|(-Ca-rE zf5T`4-#E&$>M>!cK_&?NR2M&MsFhVF43zs?f7j=doH|b^n@*2TH&+#(OH5TZKJSo6 zJ~D_sQ05!DqvbmgnKLXRlnsJb>&n)1CZ<}PLp^s21-^&B;9`7zcltHZK(O&5)53dA zq?3R&kmv0G-DtH zdHQ07nJUcipRyxGFX|CUb=}?7ou|dui@ICIGkUy=QE9|QQc#a@*><#R(EacAl+$3N z^*>@yTQz9bl-`Zsw5;({hW%Bb0=q#geE7SDHo^MrJvjUo#37_Qj&GwF88 + + + + + + Python Module Index — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Python Module Index

+ +
+ q +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ q
+ qs_codec +
    + qs_codec.decode +
    + qs_codec.encode +
    + qs_codec.enums +
    + qs_codec.enums.charset +
    + qs_codec.enums.duplicates +
    + qs_codec.enums.format +
    + qs_codec.enums.list_format +
    + qs_codec.enums.sentinel +
    + qs_codec.models +
    + qs_codec.models.decode_options +
    + qs_codec.models.encode_options +
    + qs_codec.models.undefined +
    + qs_codec.models.weak_wrapper +
    + qs_codec.utils +
    + qs_codec.utils.decode_utils +
    + qs_codec.utils.encode_utils +
    + qs_codec.utils.str_utils +
    + qs_codec.utils.utils +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.enums.html b/qs_codec.enums.html new file mode 100644 index 0000000..bb4ed4c --- /dev/null +++ b/qs_codec.enums.html @@ -0,0 +1,329 @@ + + + + + + + + qs_codec.enums package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec.enums package

+
+

Submodules

+
+
+

qs_codec.enums.charset module

+

Charset enum module.

+
+
+class qs_codec.enums.charset.Charset(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _CharsetDataMixin, Enum

+

Character set.

+
+
+LATIN1 = _CharsetDataMixin(encoding='iso-8859-1')
+

ISO-8859-1 (Latin-1) character encoding.

+
+ +
+
+UTF8 = _CharsetDataMixin(encoding='utf-8')
+

UTF-8 character encoding.

+
+ +
+ +
+
+

qs_codec.enums.duplicates module

+

This module contains an enum of all available duplicate key handling strategies.

+
+
+class qs_codec.enums.duplicates.Duplicates(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: Enum

+

An enum of all available duplicate key handling strategies.

+
+
+COMBINE = 1
+

Combine duplicate keys into a single key with an array of values.

+
+ +
+
+FIRST = 2
+

Use the first value for duplicate keys.

+
+ +
+
+LAST = 3
+

Use the last value for duplicate keys.

+
+ +
+ +
+
+

qs_codec.enums.format module

+

An enum of all supported URI component encoding formats.

+
+
+class qs_codec.enums.format.Format(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _FormatDataMixin, Enum

+

An enum of all supported URI component encoding formats.

+
+
+RFC1738 = _FormatDataMixin(format_name='RFC1738', formatter=<function Formatter.rfc1738>)
+

RFC 1738.

+
+ +
+
+RFC3986 = _FormatDataMixin(format_name='RFC3986', formatter=<function Formatter.rfc3986>)
+

RFC 3986.

+
+ +
+ +
+
+class qs_codec.enums.format.Formatter[source]
+

Bases: object

+

A class for formatting URI components.

+
+
+static rfc1738(value: str) str[source]
+

Format a string according to RFC 1738.

+
+ +
+
+static rfc3986(value: str) str[source]
+

Format a string according to RFC 3986.

+
+ +
+ +
+
+

qs_codec.enums.list_format module

+

An enum for all available list format options.

+
+
+class qs_codec.enums.list_format.ListFormat(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _ListFormatDataMixin, Enum

+

An enum of all available list format options.

+
+
+BRACKETS = _ListFormatDataMixin(list_format_name='BRACKETS', generator=<function ListFormatGenerator.brackets>)
+

Use brackets to represent list items, for example foo[]=123&foo[]=456&foo[]=789

+
+ +
+
+COMMA = _ListFormatDataMixin(list_format_name='COMMA', generator=<function ListFormatGenerator.comma>)
+

Use commas to represent list items, for example foo=123,456,789

+
+ +
+
+INDICES = _ListFormatDataMixin(list_format_name='INDICES', generator=<function ListFormatGenerator.indices>)
+

Use indices to represent list items, for example foo[0]=123&foo[1]=456&foo[2]=789

+
+ +
+
+REPEAT = _ListFormatDataMixin(list_format_name='REPEAT', generator=<function ListFormatGenerator.repeat>)
+

Use a repeat key to represent list items, for example foo=123&foo=456&foo=789

+
+ +
+ +
+
+class qs_codec.enums.list_format.ListFormatGenerator[source]
+

Bases: object

+

A class for formatting list items.

+
+
+static brackets(prefix: str, key: str | None = None) str[source]
+

Format a list item using brackets.

+
+ +
+
+static comma(prefix: str, key: str | None = None) str[source]
+

Format a list item using commas.

+
+ +
+
+static indices(prefix: str, key: str | None = None) str[source]
+

Format a list item using indices.

+
+ +
+
+static repeat(prefix: str, key: str | None = None) str[source]
+

Format a list item using repeats.

+
+ +
+ +
+
+

qs_codec.enums.sentinel module

+

This module defines the Sentinel enum, which contains all available sentinel values.

+
+
+class qs_codec.enums.sentinel.Sentinel(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _SentinelDataMixin, Enum

+

An enum of all available sentinel values.

+
+
+CHARSET = _SentinelDataMixin(raw='✓', encoded='utf8=%E2%9C%93')
+

These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is +utf-8 encoded.

+
+ +
+
+ISO = _SentinelDataMixin(raw='&#10003;', encoded='utf8=%26%2310003%3B')
+

This is what browsers will submit when the character occurs in an application/x-www-form-urlencoded +body and the encoding of the page containing the form is iso-8859-1, or when the submitted form has an +accept-charset attribute of iso-8859-1. Presumably also with other charsets that do not contain the +character, such as us-ascii.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.html b/qs_codec.html new file mode 100644 index 0000000..a12f98b --- /dev/null +++ b/qs_codec.html @@ -0,0 +1,328 @@ + + + + + + + + qs_codec package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec package

+
+

Subpackages

+
+ +
+
+
+

Submodules

+
+
+

qs_codec.decode module

+

A query string decoder (parser).

+
+
+qs_codec.decode.decode(value: str | ~typing.Mapping | None, options: ~qs_codec.models.decode_options.DecodeOptions = DecodeOptions(allow_dots=False, decode_dot_in_keys=False, allow_empty_lists=False, list_limit=20, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, comma=False, delimiter='&', depth=5, parameter_limit=1000, duplicates=<Duplicates.COMBINE: 1>, ignore_query_prefix=False, interpret_numeric_entities=False, parse_lists=True, strict_null_handling=False, decoder=<bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>)) dict[source]
+

Decodes a str or Mapping into a dict.

+

Providing custom DecodeOptions will override the default behavior.

+
+ +
+
+

qs_codec.encode module

+

A query string encoder (stringifier).

+
+
+qs_codec.encode.encode(value: ~typing.Any, options: ~qs_codec.models.encode_options.EncodeOptions = EncodeOptions(allow_dots=False, add_query_prefix=False, allow_empty_lists=False, indices=None, list_format=<ListFormat.INDICES: list_format_name='INDICES', generator=<function ListFormatGenerator.indices>>, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, delimiter='&', encode=True, encode_dot_in_keys=False, encode_values_only=False, format=<Format.RFC3986: format_name='RFC3986', formatter=<function Formatter.rfc3986>>, filter=None, skip_nulls=False, serialize_date=<function EncodeUtils.serialize_date>, encoder=<function EncodeOptions.encoder.<locals>.<lambda>>, strict_null_handling=False, comma_round_trip=None, sort=None)) str[source]
+

Encodes Any object into a query str ing.

+

Providing custom EncodeOptions will override the default behavior.

+
+ +
+
+

Module contents

+

A query string encoding and decoding library for Python. Ported from qs_codec for JavaScript.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.models.html b/qs_codec.models.html new file mode 100644 index 0000000..c99322d --- /dev/null +++ b/qs_codec.models.html @@ -0,0 +1,436 @@ + + + + + + + + qs_codec.models package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec.models package

+
+

Submodules

+
+
+

qs_codec.models.decode_options module

+

This module contains the DecodeOptions class that configures the output of decode.

+
+
+class qs_codec.models.decode_options.DecodeOptions(allow_dots: bool = None, decode_dot_in_keys: bool = None, allow_empty_lists: bool = False, list_limit: int = 20, charset: ~qs_codec.enums.charset.Charset = Charset.UTF8, charset_sentinel: bool = False, comma: bool = False, delimiter: str | ~typing.Pattern[str] = '&', depth: int = 5, parameter_limit: int | float = 1000, duplicates: ~qs_codec.enums.duplicates.Duplicates = Duplicates.COMBINE, ignore_query_prefix: bool = False, interpret_numeric_entities: bool = False, parse_lists: bool = True, strict_null_handling: bool = False, decoder: ~typing.Callable[[str | None, ~qs_codec.enums.charset.Charset | None], ~typing.Any] = <bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>)[source]
+

Bases: object

+

Options that configure the output of decode.

+
+
+allow_dots: bool = None
+

Set to True to decode dot dict notation in the encoded input.

+
+ +
+
+allow_empty_lists: bool = False
+

Set to True to allow empty list values inside dicts in the encoded input.

+
+ +
+
+charset: Charset = _CharsetDataMixin(encoding='utf-8')
+

The character encoding to use when decoding the input.

+
+ +
+
+charset_sentinel: bool = False
+

Some services add an initial utf8=✓ value to forms so that old InternetExplorer versions are more likely to +submit the form as utf-8. Additionally, the server can check the value against wrong encodings of the checkmark +character and detect that a query string or application/x-www-form-urlencoded body was not sent as utf-8, +e.g. if the form had an accept-charset parameter or the containing page had a different character set.

+

qs_codec supports this mechanism via the charset_sentinel option. +If specified, the utf-8 parameter will be omitted from the returned dict. +It will be used to switch to LATIN1 or UTF8 mode depending on how the checkmark is encoded.

+

Important: When you specify both the charset option and the charset_sentinel option, +the charset will be overridden when the request contains a utf-8 parameter from which the actual charset +can be deduced. In that sense the charset will behave as the default charset rather than the authoritative +charset.

+
+ +
+
+comma: bool = False
+

Set to True to parse the input as a comma-separated value. +Note: nested dict s, such as 'a={b:1},{c:d}' are not supported.

+
+ +
+
+decode_dot_in_keys: bool = None
+

Set to True to decode dots in keys. +Note: it implies allow_dots, so decode will error if you set decode_dot_in_keys to True, and +allow_dots to False.

+
+ +
+
+classmethod decoder(string: str | None, charset: Charset | None = Charset.UTF8) str | None
+

Set a Callable to affect the decoding of the input.

+
+ +
+
+delimiter: str | Pattern[str] = '&'
+

The delimiter to use when splitting key-value pairs in the encoded input. Can be a str or a Pattern.

+
+ +
+
+depth: int = 5
+

By default, when nesting dicts qs_codec will only decode up to 5 children deep. +This depth can be overridden by setting the depth. +The depth limit helps mitigate abuse when qs_codec is used to parse user input, +and it is recommended to keep it a reasonably small number.

+
+ +
+
+duplicates: Duplicates = 1
+

Change the duplicate key handling strategy.

+
+ +
+
+ignore_query_prefix: bool = False
+

Set to True to ignore the leading question mark query prefix in the encoded input.

+
+ +
+
+interpret_numeric_entities: bool = False
+

Set to True to interpret HTML numeric entities (&#...;) in the encoded input.

+
+ +
+
+list_limit: int = 20
+

qs_codec will limit specifying indices in a list to a maximum index of 20. +Any list members with an index of greater than 20 will instead be converted to a dict with the index as +the key. This is needed to handle cases when someone sent, for example, a[999999999] and it will take +significant time to iterate over this huge list. +This limit can be overridden by passing a list_limit option.

+
+ +
+
+parameter_limit: int | float = 1000
+

For similar reasons, by default qs_codec will only parse up to 1000 parameters. This can be overridden by +passing a parameter_limit option.

+
+ +
+
+parse_lists: bool = True
+

To disable list parsing entirely, set parse_lists to False.

+
+ +
+
+strict_null_handling: bool = False
+

Set to true to decode values without = to None.

+
+ +
+ +
+
+

qs_codec.models.encode_options module

+

This module contains the EncodeOptions class that configures the output of encode.

+
+
+class qs_codec.models.encode_options.EncodeOptions(allow_dots: bool = None, add_query_prefix: bool = False, allow_empty_lists: bool = False, indices: bool | None = None, list_format: ~qs_codec.enums.list_format.ListFormat = ListFormat.INDICES, charset: ~qs_codec.enums.charset.Charset = Charset.UTF8, charset_sentinel: bool = False, delimiter: str = '&', encode: bool = True, encode_dot_in_keys: bool = None, encode_values_only: bool = False, format: ~qs_codec.enums.format.Format = Format.RFC3986, filter: ~typing.Callable | ~typing.List[str | int] | None = None, skip_nulls: bool = False, serialize_date: ~typing.Callable[[~datetime.datetime], str] = <function EncodeUtils.serialize_date>, encoder: ~typing.Callable[[~typing.Any, ~qs_codec.enums.charset.Charset | None, ~qs_codec.enums.format.Format | None], str] = <property object>, strict_null_handling: bool = False, comma_round_trip: bool | None = None, sort: ~typing.Callable[[~typing.Any, ~typing.Any], int] | None = None)[source]
+

Bases: object

+

Options that configure the output of encode.

+
+
+add_query_prefix: bool = False
+

Set to True to add a question mark ? prefix to the encoded output.

+
+ +
+
+allow_dots: bool = None
+

Set to True to use dot dict notation in the encoded output.

+
+ +
+
+allow_empty_lists: bool = False
+

Set to True to allow empty list s in the encoded output.

+
+ +
+
+charset: Charset = _CharsetDataMixin(encoding='utf-8')
+

The character encoding to use.

+
+ +
+
+charset_sentinel: bool = False
+

Set to True to announce the character by including an utf8=✓ parameter with the proper encoding of the +checkmark, similar to what Ruby on Rails and others do when submitting forms.

+
+ +
+
+comma_round_trip: bool | None = None
+

When list_format is set to ListFormat.COMMA, you can also set comma_round_trip option to True or +False, to append [] on single-item lists, so that they can round trip through a parse.

+
+ +
+
+delimiter: str = '&'
+

The delimiter to use when joining key-value pairs in the encoded output.

+
+ +
+
+encode: bool = True
+

Set to False to disable encoding.

+
+ +
+
+encode_dot_in_keys: bool = None
+

Encode dict keys using dot notation by setting encode_dot_in_keys to True. +Caveat: When encode_values_only is True as well as encode_dot_in_keys, only dots in keys and nothing +else will be encoded.

+
+ +
+
+encode_values_only: bool = False
+

Encoding can be disabled for keys by setting the encode_values_only to True.

+
+ +
+
+property encoder: Callable[[Any, Charset | None, Format | None], str]
+

Set an Encoder to affect the encoding of values. +Note: the encoder option does not apply if encode is False.

+
+ +
+
+filter: Callable | List[str | int] | None = None
+

Use the filter option to restrict which keys will be included in the encoded output. +If you pass a Callable, it will be called for each key to obtain the replacement value. +If you pass a list, it will be used to select properties and list indices to be encoded.

+
+ +
+
+format: Format = _FormatDataMixin(format_name='RFC3986', formatter=<function Formatter.rfc3986>)
+

The encoding format to use. +The default format is Format.RFC3986 which encodes ' ' to %20 which is backward compatible. +You can also set format to Format.RFC1738 which encodes ' ' to +.

+
+ +
+
+indices: bool | None = None
+

Use list_format instead.

+
+
Type:
+

Deprecated

+
+
+
+ +
+
+list_format: ListFormat = _ListFormatDataMixin(list_format_name='INDICES', generator=<function ListFormatGenerator.indices>)
+

The list encoding format to use.

+
+ +
+
+serialize_date() str
+

If you only want to override the serialization of datetime objects, you can provide a Callable.

+
+ +
+
+skip_nulls: bool = False
+

Set to True to completely skip encoding keys with None values.

+
+ +
+
+sort: Callable[[Any, Any], int] | None = None
+

Set a Callable to affect the order of parameter keys.

+
+ +
+
+strict_null_handling: bool = False
+

Set to True to distinguish between null values and empty strings. This way the encoded string +None values will have no = sign.

+
+ +
+ +
+
+

qs_codec.models.undefined module

+

Undefined class definition.

+
+
+class qs_codec.models.undefined.Undefined[source]
+

Bases: object

+

Singleton class to represent undefined values.

+
+ +
+
+

qs_codec.models.weak_wrapper module

+

A wrapper that allows weak references to be used as dictionary keys.

+
+
+class qs_codec.models.weak_wrapper.WeakWrapper(value: Any)[source]
+

Bases: object

+

A wrapper that allows weak references to be used as dictionary keys.

+
+
+value: Any
+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.utils.html b/qs_codec.utils.html new file mode 100644 index 0000000..f2c848c --- /dev/null +++ b/qs_codec.utils.html @@ -0,0 +1,255 @@ + + + + + + + + qs_codec.utils package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec.utils package

+
+

Submodules

+
+
+

qs_codec.utils.decode_utils module

+

Decode utility methods used by the library.

+
+
+class qs_codec.utils.decode_utils.DecodeUtils[source]
+

Bases: object

+

A collection of decode utility methods used by the library.

+
+
+classmethod decode(string: str | None, charset: Charset | None = Charset.UTF8) str | None[source]
+

Decode a URL-encoded string.

+
+ +
+
+classmethod unescape(string: str) str[source]
+

A Python representation the deprecated JavaScript unescape function.

+

https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/unescape

+
+ +
+ +
+
+

qs_codec.utils.encode_utils module

+

A collection of encode utility methods used by the library.

+
+
+class qs_codec.utils.encode_utils.EncodeUtils[source]
+

Bases: object

+

A collection of encode utility methods used by the library.

+
+
+HEX_TABLE: Tuple[str, ...] = ('%00', '%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0A', '%0B', '%0C', '%0D', '%0E', '%0F', '%10', '%11', '%12', '%13', '%14', '%15', '%16', '%17', '%18', '%19', '%1A', '%1B', '%1C', '%1D', '%1E', '%1F', '%20', '%21', '%22', '%23', '%24', '%25', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%2D', '%2E', '%2F', '%30', '%31', '%32', '%33', '%34', '%35', '%36', '%37', '%38', '%39', '%3A', '%3B', '%3C', '%3D', '%3E', '%3F', '%40', '%41', '%42', '%43', '%44', '%45', '%46', '%47', '%48', '%49', '%4A', '%4B', '%4C', '%4D', '%4E', '%4F', '%50', '%51', '%52', '%53', '%54', '%55', '%56', '%57', '%58', '%59', '%5A', '%5B', '%5C', '%5D', '%5E', '%5F', '%60', '%61', '%62', '%63', '%64', '%65', '%66', '%67', '%68', '%69', '%6A', '%6B', '%6C', '%6D', '%6E', '%6F', '%70', '%71', '%72', '%73', '%74', '%75', '%76', '%77', '%78', '%79', '%7A', '%7B', '%7C', '%7D', '%7E', '%7F', '%80', '%81', '%82', '%83', '%84', '%85', '%86', '%87', '%88', '%89', '%8A', '%8B', '%8C', '%8D', '%8E', '%8F', '%90', '%91', '%92', '%93', '%94', '%95', '%96', '%97', '%98', '%99', '%9A', '%9B', '%9C', '%9D', '%9E', '%9F', '%A0', '%A1', '%A2', '%A3', '%A4', '%A5', '%A6', '%A7', '%A8', '%A9', '%AA', '%AB', '%AC', '%AD', '%AE', '%AF', '%B0', '%B1', '%B2', '%B3', '%B4', '%B5', '%B6', '%B7', '%B8', '%B9', '%BA', '%BB', '%BC', '%BD', '%BE', '%BF', '%C0', '%C1', '%C2', '%C3', '%C4', '%C5', '%C6', '%C7', '%C8', '%C9', '%CA', '%CB', '%CC', '%CD', '%CE', '%CF', '%D0', '%D1', '%D2', '%D3', '%D4', '%D5', '%D6', '%D7', '%D8', '%D9', '%DA', '%DB', '%DC', '%DD', '%DE', '%DF', '%E0', '%E1', '%E2', '%E3', '%E4', '%E5', '%E6', '%E7', '%E8', '%E9', '%EA', '%EB', '%EC', '%ED', '%EE', '%EF', '%F0', '%F1', '%F2', '%F3', '%F4', '%F5', '%F6', '%F7', '%F8', '%F9', '%FA', '%FB', '%FC', '%FD', '%FE', '%FF')
+

Hex table of all 256 characters

+
+ +
+
+classmethod encode(value: Any, charset: Charset | None = Charset.UTF8, format: Format | None = Format.RFC3986) str[source]
+

Encode a value to a URL-encoded string.

+
+ +
+
+classmethod escape(string: str, format: Format | None = Format.RFC3986) str[source]
+

A Python representation the deprecated JavaScript escape function.

+

https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/escape

+
+ +
+
+static serialize_date(dt: datetime) str[source]
+

Serialize a datetime object to an ISO 8601 string.

+
+ +
+ +
+
+

qs_codec.utils.str_utils module

+

Utility functions for working with strings.

+
+
+qs_codec.utils.str_utils.code_unit_at(string: str, index: int) int[source]
+

Returns the 16-bit UTF-16 code unit at the given index.

+

This function first encodes the string in UTF-16 little endian format, then calculates the code unit at the +given index. The code unit is calculated by taking the byte at the index and adding it to 256 times the next +byte. This is because UTF-16 represents each code unit with two bytes, and in little endian format, the least +significant byte comes first.

+

Adapted from https://api.dart.dev/stable/3.3.3/dart-core/String/codeUnitAt.html

+
+ +
+
+

qs_codec.utils.utils module

+

A collection of utility methods used by the library.

+
+
+class qs_codec.utils.utils.Utils[source]
+

Bases: object

+

A collection of utility methods used by the library.

+
+
+static apply(val: list | tuple | Any, fn: Callable) List | Any[source]
+

Apply a function to a value or a list of values.

+
+ +
+
+static combine(a: list | tuple | Any, b: list | tuple | Any) List[source]
+

Combine two lists or values.

+
+ +
+
+static compact(value: Dict) Dict[source]
+

Remove all Undefined values from a dictionary.

+
+ +
+
+static is_non_nullish_primitive(val: Any, skip_nulls: bool = False) bool[source]
+

Check if a value is a non-nullish primitive.

+
+ +
+
+static merge(target: ~typing.Mapping | ~typing.List | ~typing.Tuple | None, source: ~typing.Mapping | ~typing.List | ~typing.Tuple | ~typing.Any | None, options: ~qs_codec.models.decode_options.DecodeOptions = DecodeOptions(allow_dots=False, decode_dot_in_keys=False, allow_empty_lists=False, list_limit=20, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, comma=False, delimiter='&', depth=5, parameter_limit=1000, duplicates=<Duplicates.COMBINE: 1>, ignore_query_prefix=False, interpret_numeric_entities=False, parse_lists=True, strict_null_handling=False, decoder=<bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>)) Dict | List | Tuple | Any[source]
+

Merge two objects together.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000..a90626e --- /dev/null +++ b/search.html @@ -0,0 +1,125 @@ + + + + + + + Search — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..4a94a8a --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"Contents:": [[1, null]], "Dealing with special character sets": [[0, "dealing-with-special-character-sets"]], "Decoding": [[0, "decoding"]], "Encoding": [[0, "encoding"]], "Handling None values": [[0, "handling-none-values"]], "Indices and tables": [[1, "indices-and-tables"]], "Module contents": [[2, "module-qs_codec"], [3, "module-qs_codec.enums"], [4, "module-qs_codec.models"], [5, "module-qs_codec.utils"]], "RFC 3986 and RFC 1738 space encoding": [[0, "rfc-3986-and-rfc-1738-space-encoding"]], "Submodules": [[2, "submodules"], [3, "submodules"], [4, "submodules"], [5, "submodules"]], "Subpackages": [[2, "subpackages"]], "Usage": [[1, "usage"]], "dictionaries": [[0, "dictionaries"]], "lists": [[0, "lists"]], "primitive values (int, bool, None, etc.)": [[0, "primitive-values-int-bool-none-etc"]], "qs-codec": [[1, "qs-codec"]], "qs_codec package": [[2, "qs-codec-package"]], "qs_codec.decode module": [[2, "module-qs_codec.decode"]], "qs_codec.encode module": [[2, "module-qs_codec.encode"]], "qs_codec.enums package": [[3, "qs-codec-enums-package"]], "qs_codec.enums.charset module": [[3, "module-qs_codec.enums.charset"]], "qs_codec.enums.duplicates module": [[3, "module-qs_codec.enums.duplicates"]], "qs_codec.enums.format module": [[3, "module-qs_codec.enums.format"]], "qs_codec.enums.list_format module": [[3, "module-qs_codec.enums.list_format"]], "qs_codec.enums.sentinel module": [[3, "module-qs_codec.enums.sentinel"]], "qs_codec.models package": [[4, "qs-codec-models-package"]], "qs_codec.models.decode_options module": [[4, "module-qs_codec.models.decode_options"]], "qs_codec.models.encode_options module": [[4, "module-qs_codec.models.encode_options"]], "qs_codec.models.undefined module": [[4, "module-qs_codec.models.undefined"]], "qs_codec.models.weak_wrapper module": [[4, "module-qs_codec.models.weak_wrapper"]], "qs_codec.utils package": [[5, "qs-codec-utils-package"]], "qs_codec.utils.decode_utils module": [[5, "module-qs_codec.utils.decode_utils"]], "qs_codec.utils.encode_utils module": [[5, "module-qs_codec.utils.encode_utils"]], "qs_codec.utils.str_utils module": [[5, "module-qs_codec.utils.str_utils"]], "qs_codec.utils.utils module": [[5, "module-qs_codec.utils.utils"]]}, "docnames": ["README", "index", "qs_codec", "qs_codec.enums", "qs_codec.models", "qs_codec.utils"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1}, "filenames": ["README.rst", "index.rst", "qs_codec.rst", "qs_codec.enums.rst", "qs_codec.models.rst", "qs_codec.utils.rst"], "indexentries": {"add_query_prefix (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.add_query_prefix", false]], "allow_dots (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.allow_dots", false]], "allow_dots (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.allow_dots", false]], "allow_empty_lists (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.allow_empty_lists", false]], "allow_empty_lists (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.allow_empty_lists", false]], "apply() (qs_codec.utils.utils.utils static method)": [[5, "qs_codec.utils.utils.Utils.apply", false]], "brackets (qs_codec.enums.list_format.listformat attribute)": [[3, "qs_codec.enums.list_format.ListFormat.BRACKETS", false]], "brackets() (qs_codec.enums.list_format.listformatgenerator static method)": [[3, "qs_codec.enums.list_format.ListFormatGenerator.brackets", false]], "charset (class in qs_codec.enums.charset)": [[3, "qs_codec.enums.charset.Charset", false]], "charset (qs_codec.enums.sentinel.sentinel attribute)": [[3, "qs_codec.enums.sentinel.Sentinel.CHARSET", false]], "charset (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.charset", false]], "charset (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.charset", false]], "charset_sentinel (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.charset_sentinel", false]], "charset_sentinel (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.charset_sentinel", false]], "code_unit_at() (in module qs_codec.utils.str_utils)": [[5, "qs_codec.utils.str_utils.code_unit_at", false]], "combine (qs_codec.enums.duplicates.duplicates attribute)": [[3, "qs_codec.enums.duplicates.Duplicates.COMBINE", false]], "combine() (qs_codec.utils.utils.utils static method)": [[5, "qs_codec.utils.utils.Utils.combine", false]], "comma (qs_codec.enums.list_format.listformat attribute)": [[3, "qs_codec.enums.list_format.ListFormat.COMMA", false]], "comma (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.comma", false]], "comma() (qs_codec.enums.list_format.listformatgenerator static method)": [[3, "qs_codec.enums.list_format.ListFormatGenerator.comma", false]], "comma_round_trip (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.comma_round_trip", false]], "compact() (qs_codec.utils.utils.utils static method)": [[5, "qs_codec.utils.utils.Utils.compact", false]], "decode() (in module qs_codec.decode)": [[2, "qs_codec.decode.decode", false]], "decode() (qs_codec.utils.decode_utils.decodeutils class method)": [[5, "qs_codec.utils.decode_utils.DecodeUtils.decode", false]], "decode_dot_in_keys (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.decode_dot_in_keys", false]], "decodeoptions (class in qs_codec.models.decode_options)": [[4, "qs_codec.models.decode_options.DecodeOptions", false]], "decoder() (qs_codec.models.decode_options.decodeoptions class method)": [[4, "qs_codec.models.decode_options.DecodeOptions.decoder", false]], "decodeutils (class in qs_codec.utils.decode_utils)": [[5, "qs_codec.utils.decode_utils.DecodeUtils", false]], "delimiter (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.delimiter", false]], "delimiter (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.delimiter", false]], "depth (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.depth", false]], "duplicates (class in qs_codec.enums.duplicates)": [[3, "qs_codec.enums.duplicates.Duplicates", false]], "duplicates (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.duplicates", false]], "encode (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.encode", false]], "encode() (in module qs_codec.encode)": [[2, "qs_codec.encode.encode", false]], "encode() (qs_codec.utils.encode_utils.encodeutils class method)": [[5, "qs_codec.utils.encode_utils.EncodeUtils.encode", false]], "encode_dot_in_keys (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.encode_dot_in_keys", false]], "encode_values_only (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.encode_values_only", false]], "encodeoptions (class in qs_codec.models.encode_options)": [[4, "qs_codec.models.encode_options.EncodeOptions", false]], "encoder (qs_codec.models.encode_options.encodeoptions property)": [[4, "qs_codec.models.encode_options.EncodeOptions.encoder", false]], "encodeutils (class in qs_codec.utils.encode_utils)": [[5, "qs_codec.utils.encode_utils.EncodeUtils", false]], "escape() (qs_codec.utils.encode_utils.encodeutils class method)": [[5, "qs_codec.utils.encode_utils.EncodeUtils.escape", false]], "filter (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.filter", false]], "first (qs_codec.enums.duplicates.duplicates attribute)": [[3, "qs_codec.enums.duplicates.Duplicates.FIRST", false]], "format (class in qs_codec.enums.format)": [[3, "qs_codec.enums.format.Format", false]], "format (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.format", false]], "formatter (class in qs_codec.enums.format)": [[3, "qs_codec.enums.format.Formatter", false]], "hex_table (qs_codec.utils.encode_utils.encodeutils attribute)": [[5, "qs_codec.utils.encode_utils.EncodeUtils.HEX_TABLE", false]], "ignore_query_prefix (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.ignore_query_prefix", false]], "indices (qs_codec.enums.list_format.listformat attribute)": [[3, "qs_codec.enums.list_format.ListFormat.INDICES", false]], "indices (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.indices", false]], "indices() (qs_codec.enums.list_format.listformatgenerator static method)": [[3, "qs_codec.enums.list_format.ListFormatGenerator.indices", false]], "interpret_numeric_entities (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.interpret_numeric_entities", false]], "is_non_nullish_primitive() (qs_codec.utils.utils.utils static method)": [[5, "qs_codec.utils.utils.Utils.is_non_nullish_primitive", false]], "iso (qs_codec.enums.sentinel.sentinel attribute)": [[3, "qs_codec.enums.sentinel.Sentinel.ISO", false]], "last (qs_codec.enums.duplicates.duplicates attribute)": [[3, "qs_codec.enums.duplicates.Duplicates.LAST", false]], "latin1 (qs_codec.enums.charset.charset attribute)": [[3, "qs_codec.enums.charset.Charset.LATIN1", false]], "list_format (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.list_format", false]], "list_limit (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.list_limit", false]], "listformat (class in qs_codec.enums.list_format)": [[3, "qs_codec.enums.list_format.ListFormat", false]], "listformatgenerator (class in qs_codec.enums.list_format)": [[3, "qs_codec.enums.list_format.ListFormatGenerator", false]], "merge() (qs_codec.utils.utils.utils static method)": [[5, "qs_codec.utils.utils.Utils.merge", false]], "module": [[2, "module-qs_codec", false], [2, "module-qs_codec.decode", false], [2, "module-qs_codec.encode", false], [3, "module-qs_codec.enums", false], [3, "module-qs_codec.enums.charset", false], [3, "module-qs_codec.enums.duplicates", false], [3, "module-qs_codec.enums.format", false], [3, "module-qs_codec.enums.list_format", false], [3, "module-qs_codec.enums.sentinel", false], [4, "module-qs_codec.models", false], [4, "module-qs_codec.models.decode_options", false], [4, "module-qs_codec.models.encode_options", false], [4, "module-qs_codec.models.undefined", false], [4, "module-qs_codec.models.weak_wrapper", false], [5, "module-qs_codec.utils", false], [5, "module-qs_codec.utils.decode_utils", false], [5, "module-qs_codec.utils.encode_utils", false], [5, "module-qs_codec.utils.str_utils", false], [5, "module-qs_codec.utils.utils", false]], "parameter_limit (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.parameter_limit", false]], "parse_lists (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.parse_lists", false]], "qs_codec": [[2, "module-qs_codec", false]], "qs_codec.decode": [[2, "module-qs_codec.decode", false]], "qs_codec.encode": [[2, "module-qs_codec.encode", false]], "qs_codec.enums": [[3, "module-qs_codec.enums", false]], "qs_codec.enums.charset": [[3, "module-qs_codec.enums.charset", false]], "qs_codec.enums.duplicates": [[3, "module-qs_codec.enums.duplicates", false]], "qs_codec.enums.format": [[3, "module-qs_codec.enums.format", false]], "qs_codec.enums.list_format": [[3, "module-qs_codec.enums.list_format", false]], "qs_codec.enums.sentinel": [[3, "module-qs_codec.enums.sentinel", false]], "qs_codec.models": [[4, "module-qs_codec.models", false]], "qs_codec.models.decode_options": [[4, "module-qs_codec.models.decode_options", false]], "qs_codec.models.encode_options": [[4, "module-qs_codec.models.encode_options", false]], "qs_codec.models.undefined": [[4, "module-qs_codec.models.undefined", false]], "qs_codec.models.weak_wrapper": [[4, "module-qs_codec.models.weak_wrapper", false]], "qs_codec.utils": [[5, "module-qs_codec.utils", false]], "qs_codec.utils.decode_utils": [[5, "module-qs_codec.utils.decode_utils", false]], "qs_codec.utils.encode_utils": [[5, "module-qs_codec.utils.encode_utils", false]], "qs_codec.utils.str_utils": [[5, "module-qs_codec.utils.str_utils", false]], "qs_codec.utils.utils": [[5, "module-qs_codec.utils.utils", false]], "repeat (qs_codec.enums.list_format.listformat attribute)": [[3, "qs_codec.enums.list_format.ListFormat.REPEAT", false]], "repeat() (qs_codec.enums.list_format.listformatgenerator static method)": [[3, "qs_codec.enums.list_format.ListFormatGenerator.repeat", false]], "rfc1738 (qs_codec.enums.format.format attribute)": [[3, "qs_codec.enums.format.Format.RFC1738", false]], "rfc1738() (qs_codec.enums.format.formatter static method)": [[3, "qs_codec.enums.format.Formatter.rfc1738", false]], "rfc3986 (qs_codec.enums.format.format attribute)": [[3, "qs_codec.enums.format.Format.RFC3986", false]], "rfc3986() (qs_codec.enums.format.formatter static method)": [[3, "qs_codec.enums.format.Formatter.rfc3986", false]], "sentinel (class in qs_codec.enums.sentinel)": [[3, "qs_codec.enums.sentinel.Sentinel", false]], "serialize_date() (qs_codec.models.encode_options.encodeoptions method)": [[4, "qs_codec.models.encode_options.EncodeOptions.serialize_date", false]], "serialize_date() (qs_codec.utils.encode_utils.encodeutils static method)": [[5, "qs_codec.utils.encode_utils.EncodeUtils.serialize_date", false]], "skip_nulls (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.skip_nulls", false]], "sort (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.sort", false]], "strict_null_handling (qs_codec.models.decode_options.decodeoptions attribute)": [[4, "qs_codec.models.decode_options.DecodeOptions.strict_null_handling", false]], "strict_null_handling (qs_codec.models.encode_options.encodeoptions attribute)": [[4, "qs_codec.models.encode_options.EncodeOptions.strict_null_handling", false]], "undefined (class in qs_codec.models.undefined)": [[4, "qs_codec.models.undefined.Undefined", false]], "unescape() (qs_codec.utils.decode_utils.decodeutils class method)": [[5, "qs_codec.utils.decode_utils.DecodeUtils.unescape", false]], "utf8 (qs_codec.enums.charset.charset attribute)": [[3, "qs_codec.enums.charset.Charset.UTF8", false]], "utils (class in qs_codec.utils.utils)": [[5, "qs_codec.utils.utils.Utils", false]], "value (qs_codec.models.weak_wrapper.weakwrapper attribute)": [[4, "qs_codec.models.weak_wrapper.WeakWrapper.value", false]], "weakwrapper (class in qs_codec.models.weak_wrapper)": [[4, "qs_codec.models.weak_wrapper.WeakWrapper", false]]}, "objects": {"": [[2, 0, 0, "-", "qs_codec"]], "qs_codec": [[2, 0, 0, "-", "decode"], [2, 0, 0, "-", "encode"], [3, 0, 0, "-", "enums"], [4, 0, 0, "-", "models"], [5, 0, 0, "-", "utils"]], "qs_codec.decode": [[2, 1, 1, "", "decode"]], "qs_codec.encode": [[2, 1, 1, "", "encode"]], "qs_codec.enums": [[3, 0, 0, "-", "charset"], [3, 0, 0, "-", "duplicates"], [3, 0, 0, "-", "format"], [3, 0, 0, "-", "list_format"], [3, 0, 0, "-", "sentinel"]], "qs_codec.enums.charset": [[3, 2, 1, "", "Charset"]], "qs_codec.enums.charset.Charset": [[3, 3, 1, "", "LATIN1"], [3, 3, 1, "", "UTF8"]], "qs_codec.enums.duplicates": [[3, 2, 1, "", "Duplicates"]], "qs_codec.enums.duplicates.Duplicates": [[3, 3, 1, "", "COMBINE"], [3, 3, 1, "", "FIRST"], [3, 3, 1, "", "LAST"]], "qs_codec.enums.format": [[3, 2, 1, "", "Format"], [3, 2, 1, "", "Formatter"]], "qs_codec.enums.format.Format": [[3, 3, 1, "", "RFC1738"], [3, 3, 1, "", "RFC3986"]], "qs_codec.enums.format.Formatter": [[3, 4, 1, "", "rfc1738"], [3, 4, 1, "", "rfc3986"]], "qs_codec.enums.list_format": [[3, 2, 1, "", "ListFormat"], [3, 2, 1, "", "ListFormatGenerator"]], "qs_codec.enums.list_format.ListFormat": [[3, 3, 1, "", "BRACKETS"], [3, 3, 1, "", "COMMA"], [3, 3, 1, "", "INDICES"], [3, 3, 1, "", "REPEAT"]], "qs_codec.enums.list_format.ListFormatGenerator": [[3, 4, 1, "", "brackets"], [3, 4, 1, "", "comma"], [3, 4, 1, "", "indices"], [3, 4, 1, "", "repeat"]], "qs_codec.enums.sentinel": [[3, 2, 1, "", "Sentinel"]], "qs_codec.enums.sentinel.Sentinel": [[3, 3, 1, "", "CHARSET"], [3, 3, 1, "", "ISO"]], "qs_codec.models": [[4, 0, 0, "-", "decode_options"], [4, 0, 0, "-", "encode_options"], [4, 0, 0, "-", "undefined"], [4, 0, 0, "-", "weak_wrapper"]], "qs_codec.models.decode_options": [[4, 2, 1, "", "DecodeOptions"]], "qs_codec.models.decode_options.DecodeOptions": [[4, 3, 1, "", "allow_dots"], [4, 3, 1, "", "allow_empty_lists"], [4, 3, 1, "", "charset"], [4, 3, 1, "", "charset_sentinel"], [4, 3, 1, "", "comma"], [4, 3, 1, "", "decode_dot_in_keys"], [4, 4, 1, "", "decoder"], [4, 3, 1, "", "delimiter"], [4, 3, 1, "", "depth"], [4, 3, 1, "", "duplicates"], [4, 3, 1, "", "ignore_query_prefix"], [4, 3, 1, "", "interpret_numeric_entities"], [4, 3, 1, "", "list_limit"], [4, 3, 1, "", "parameter_limit"], [4, 3, 1, "", "parse_lists"], [4, 3, 1, "", "strict_null_handling"]], "qs_codec.models.encode_options": [[4, 2, 1, "", "EncodeOptions"]], "qs_codec.models.encode_options.EncodeOptions": [[4, 3, 1, "", "add_query_prefix"], [4, 3, 1, "", "allow_dots"], [4, 3, 1, "", "allow_empty_lists"], [4, 3, 1, "", "charset"], [4, 3, 1, "", "charset_sentinel"], [4, 3, 1, "", "comma_round_trip"], [4, 3, 1, "", "delimiter"], [4, 3, 1, "", "encode"], [4, 3, 1, "", "encode_dot_in_keys"], [4, 3, 1, "", "encode_values_only"], [4, 5, 1, "", "encoder"], [4, 3, 1, "", "filter"], [4, 3, 1, "", "format"], [4, 3, 1, "", "indices"], [4, 3, 1, "", "list_format"], [4, 4, 1, "", "serialize_date"], [4, 3, 1, "", "skip_nulls"], [4, 3, 1, "", "sort"], [4, 3, 1, "", "strict_null_handling"]], "qs_codec.models.undefined": [[4, 2, 1, "", "Undefined"]], "qs_codec.models.weak_wrapper": [[4, 2, 1, "", "WeakWrapper"]], "qs_codec.models.weak_wrapper.WeakWrapper": [[4, 3, 1, "", "value"]], "qs_codec.utils": [[5, 0, 0, "-", "decode_utils"], [5, 0, 0, "-", "encode_utils"], [5, 0, 0, "-", "str_utils"], [5, 0, 0, "-", "utils"]], "qs_codec.utils.decode_utils": [[5, 2, 1, "", "DecodeUtils"]], "qs_codec.utils.decode_utils.DecodeUtils": [[5, 4, 1, "", "decode"], [5, 4, 1, "", "unescape"]], "qs_codec.utils.encode_utils": [[5, 2, 1, "", "EncodeUtils"]], "qs_codec.utils.encode_utils.EncodeUtils": [[5, 3, 1, "", "HEX_TABLE"], [5, 4, 1, "", "encode"], [5, 4, 1, "", "escape"], [5, 4, 1, "", "serialize_date"]], "qs_codec.utils.str_utils": [[5, 1, 1, "", "code_unit_at"]], "qs_codec.utils.utils": [[5, 2, 1, "", "Utils"]], "qs_codec.utils.utils.Utils": [[5, 4, 1, "", "apply"], [5, 4, 1, "", "combine"], [5, 4, 1, "", "compact"], [5, 4, 1, "", "is_non_nullish_primitive"], [5, 4, 1, "", "merge"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "method", "Python method"], "5": ["py", "property", "Python property"]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:attribute", "4": "py:method", "5": "py:property"}, "terms": {"": [0, 4], "0": [0, 3], "00": [0, 5], "01": [0, 5], "01t00": 0, "02": 5, "02x": 0, "03": 5, "04": 5, "05": 5, "06": 5, "07": [0, 5], "08": 5, "09": 5, "0a": 5, "0b": 5, "0c": 5, "0d": 5, "0e": 5, "0f": 5, "1": [0, 2, 3, 4, 5], "10": 5, "100": 0, "1000": [0, 2, 4, 5], "10003": 3, "11": [0, 5], "12": 5, "123": [0, 3], "13": 5, "14": 5, "15": [0, 5], "16": [0, 5], "17": 5, "1738": [1, 3], "18": 5, "19": 5, "1970": 0, "1a": 5, "1b": 5, "1c": 5, "1d": 5, "1e": 5, "1f": 5, "2": [0, 3], "20": [0, 2, 4, 5], "20c": 0, "21": 5, "22": 5, "23": 5, "2310003": [0, 3], "239786": 0, "24": 5, "25": 5, "252eobj": 0, "256": 5, "26": [0, 3, 5], "27": 5, "28": 5, "29": 5, "2a": 5, "2b": 5, "2c": 5, "2d": 5, "2e": 5, "2f": 5, "3": [0, 3, 5], "30": 5, "31": 5, "32": 5, "33": 5, "34": 5, "35": 5, "36": 5, "37": 5, "38": 5, "39": 5, "3986": [1, 3], "3a": 5, "3b": [0, 3, 5], "3c": 5, "3d": 5, "3df": 0, "3e": 5, "3f": 5, "4": 0, "40": 5, "41": 5, "42": 5, "43": 5, "44": 5, "45": 5, "456": 3, "46": 5, "47": 5, "48": 5, "49": [0, 5], "4a": 5, "4b": 5, "4c": 5, "4d": 5, "4e": 5, "4f": 5, "5": [0, 2, 4, 5], "50": 5, "51": 5, "52": 5, "53": 5, "54": 5, "55": 5, "56": 5, "57": 5, "58": 5, "59": 5, "5a": 5, "5b": 5, "5bb": 0, "5c": 5, "5d": [0, 5], "5e": 5, "5f": 5, "60": 5, "61": [0, 5], "62": 5, "63": 5, "64": 5, "65": 5, "66": 5, "67": 5, "68": 5, "69": 5, "6a": 5, "6b": 5, "6c": 5, "6d": 5, "6e": 5, "6f": 5, "7": 0, "70": 5, "71": 5, "72": 5, "73": 5, "74": 5, "75": 5, "76": 5, "77": 5, "78": 5, "789": 3, "79": 5, "7a": 5, "7b": 5, "7c": 5, "7d": 5, "7e": 5, "7f": 5, "8": [0, 2, 3, 4, 5], "80": 5, "81": [0, 5], "82": [0, 5], "83": 5, "84": 5, "85": 5, "86": 5, "8601": [0, 5], "87": 5, "88": 5, "8859": 3, "89": 5, "8a": 5, "8b": 5, "8c": 5, "8d": 5, "8e": 5, "8f": 5, "90": 5, "91": 5, "92": 5, "93": [0, 3, 5], "94": 5, "95": 5, "96": 5, "97": 5, "98": [0, 5], "99": 5, "999999999": [0, 4], "9a": [0, 5], "9b": 5, "9c": [0, 3, 5], "9d": 5, "9e": 5, "9f": 5, "A": [1, 2, 3, 4, 5], "BE": 5, "By": [0, 4], "For": [0, 4], "If": [0, 4], "In": [0, 4], "It": [0, 4], "The": [0, 4, 5], "These": 3, "To": [0, 4], "_charsetdatamixin": [3, 4], "_formatdatamixin": [3, 4], "_listformatdatamixin": [3, 4], "_sentineldatamixin": 3, "a0": 5, "a1": 5, "a2": 5, "a3": 5, "a4": 5, "a5": 5, "a6": 5, "a7": [0, 5], "a8": 5, "a9": 5, "aa": 5, "ab": 5, "abus": [0, 4], "ac": 5, "accept": [0, 3, 4], "accord": 3, "actual": [0, 3, 4], "ad": 5, "adapt": 5, "add": [0, 4], "add_query_prefix": [0, 2, 4], "addition": [0, 4], "ae": 5, "af": 5, "affect": [0, 4], "against": [0, 4], "all": [0, 3, 5], "allow": [0, 4], "allow_dot": [0, 2, 4, 5], "allow_empty_list": [0, 2, 4, 5], "also": [0, 3, 4], "an": [0, 3, 4, 5], "ani": [0, 2, 4, 5], "announc": [0, 4], "api": 5, "append": [0, 4], "appli": [0, 2, 4, 5], "applic": [0, 3, 4], "ar": [0, 3, 4], "arrai": 3, "ascii": 3, "assert": [0, 1], "attempt": 0, "attribut": 3, "author": 1, "authorit": [0, 4], "avail": 3, "b": [0, 1, 4, 5], "b0": 5, "b1": [0, 5], "b2": 5, "b3": 5, "b4": 5, "b5": 5, "b6": 5, "b7": 5, "b8": [0, 5], "b9": 5, "ba": [0, 5], "back": 0, "backward": [0, 4], "bar": 0, "base": [3, 4, 5], "baz": 0, "bb": 5, "bc": 5, "bd": 5, "becaus": 5, "been": 0, "behav": [0, 4], "behavior": [0, 2], "between": [0, 4], "beyond": 0, "bf": [0, 5], "bit": 5, "bodi": [0, 3, 4], "bool": [1, 4, 5], "both": [0, 4], "bound": [2, 4, 5], "boundari": 3, "bracket": [0, 2, 3], "break": 0, "browser": [0, 3], "buf": 0, "built": 0, "bypass": 0, "byte": [0, 5], "c": [0, 4], "c0": 5, "c1": 5, "c2": 5, "c3": [0, 5], "c4": 5, "c5": 5, "c6": 5, "c7": 5, "c8": 5, "c9": [0, 5], "ca": 5, "calcul": 5, "call": [0, 4], "callabl": [0, 4, 5], "can": [0, 4], "cannot": 0, "case": [0, 4], "caveat": [0, 4], "cb": 5, "cc": 5, "cd": [0, 5], "ce": 5, "cf": 5, "chang": [0, 4], "charact": [1, 3, 4, 5], "charset": [0, 1, 2, 4, 5], "charset_sentinel": [0, 2, 4, 5], "check": [0, 4, 5], "checkmark": [0, 3, 4], "children": [0, 4], "clariti": 0, "class": [2, 3, 4, 5], "classmethod": [4, 5], "code": 5, "code_unit_at": [2, 5], "codec": 0, "codeunitat": 5, "collect": 5, "combin": [0, 2, 3, 4, 5], "come": 5, "comma": [0, 2, 3, 4, 5], "comma_round_trip": [0, 2, 4], "commun": 0, "compact": [0, 2, 5], "compat": [0, 4], "compil": 0, "complet": [0, 4], "compon": 3, "configur": 4, "contain": [0, 3, 4], "convert": [0, 4], "core": 5, "creat": 0, "custom": [0, 2], "custom_decod": 0, "custom_encod": 0, "d": [0, 4], "d0": 5, "d1": 5, "d2": 5, "d3": 5, "d4": 5, "d5": 5, "d6": 5, "d7": 5, "d8": 5, "d9": 5, "da": 5, "dart": 5, "date": 0, "datetim": [0, 4, 5], "db": 5, "dc": 5, "dd": 5, "de": 5, "deal": 1, "decod": [1, 4, 5], "decode_dot_in_kei": [0, 2, 4, 5], "decode_opt": [1, 2, 5], "decode_util": [1, 2, 4], "decodeopt": [0, 2, 4, 5], "decodeutil": [2, 4, 5], "deduc": [0, 4], "deep": [0, 4], "def": 0, "default": [0, 2, 4], "defin": 3, "definit": 4, "delimit": [0, 2, 4, 5], "depend": [0, 4], "deprec": [4, 5], "depth": [0, 2, 4, 5], "detect": [0, 4], "dev": 5, "develop": 5, "df": 5, "dict": [0, 2, 4, 5], "dictionari": [1, 4, 5], "differ": [0, 4], "disabl": [0, 4], "distinguish": [0, 4], "do": [0, 3, 4], "doc": 5, "doe": [0, 4], "don": 0, "done": 0, "dot": [0, 4], "dt": 5, "duplic": [0, 1, 2, 4, 5], "dure": 0, "e": [0, 4], "e0": 5, "e1": 5, "e2": [0, 3, 5], "e3": 5, "e4": 5, "e5": 5, "e6": [0, 5], "e7": 5, "e8": 5, "e9": 5, "ea": 5, "each": [0, 4, 5], "eb": 5, "ec": 5, "ed": 5, "ee": 5, "ef": 5, "els": [0, 4], "empti": [0, 4], "en": 5, "enabl": 0, "encod": [1, 3, 4, 5], "encode_dot_in_kei": [0, 2, 4], "encode_opt": [1, 2], "encode_util": [1, 2], "encode_values_onli": [0, 2, 4], "encodeopt": [0, 2, 4], "encodeutil": [2, 4, 5], "encount": 0, "end": 0, "endian": 5, "entir": [0, 4], "entiti": [0, 4], "enum": [1, 2, 4], "equal": 0, "error": [0, 4], "escap": [2, 5], "etc": 1, "exampl": [0, 1, 3, 4], "except": 0, "exist": 0, "expect": 0, "explicit": 0, "explor": 0, "express": 0, "f": 0, "f0": 5, "f1": [0, 5], "f2": 5, "f3": 5, "f4": 5, "f5": 5, "f6": 5, "f7": 5, "f8": [0, 5], "f9": 5, "fa": 5, "fals": [0, 2, 4, 5], "fb": 5, "fc": 5, "fd": 5, "fe": 5, "ff": 5, "filter": [0, 2, 4], "final": 0, "first": [0, 2, 3, 5], "flag": 0, "float": 4, "fn": 5, "follow": 0, "foo": [0, 3], "foobarbaz": 0, "form": [0, 3, 4], "format": [0, 1, 2, 4, 5], "format_nam": [2, 3, 4], "formatt": [2, 3, 4], "from": [0, 1, 2, 4, 5], "fromtimestamp": 0, "function": [2, 3, 4, 5], "g": [0, 4], "gener": [2, 3, 4], "get": 0, "given": [3, 5], "global_object": 5, "greater": [0, 4], "group": 0, "h": 0, "ha": [0, 3], "had": [0, 4], "handl": [1, 3, 4], "harband": 1, "have": [0, 4], "help": [0, 4], "hex": 5, "hex_tabl": [2, 5], "holowaychuk": 1, "how": [0, 4], "html": [4, 5], "http": 5, "huge": [0, 4], "i": [0, 3, 4, 5], "ignor": 4, "ignore_query_prefix": [0, 2, 4, 5], "ignorecas": 0, "impli": [0, 4], "import": [0, 1, 4], "includ": [0, 4], "index": [0, 1, 4, 5], "indic": [0, 2, 3, 4], "ing": [0, 2, 4], "initi": [0, 4], "input": [0, 4], "insid": 4, "instead": [0, 4], "int": [1, 4, 5], "internet": 0, "internetexplor": 4, "interpret": 4, "interpret_numeric_ent": [0, 2, 4, 5], "is_non_nullish_primit": [2, 5], "isinst": 0, "iso": [0, 2, 3, 5], "item": [0, 3, 4], "iter": [0, 4], "j": 0, "javascript": [1, 2, 5], "ji": 0, "john": 0, "join": [0, 4], "jordan": 1, "keep": [0, 4], "kei": [0, 3, 4], "lambda": [0, 2], "last": [0, 2, 3], "latin": 3, "latin1": [0, 2, 3, 4], "lead": [0, 4], "least": 5, "legaci": 0, "librari": [1, 2, 5], "like": [0, 4], "limit": [0, 4], "list": [1, 3, 4, 5], "list_format": [0, 1, 2, 4], "list_format_nam": [2, 3, 4], "list_limit": [0, 2, 4, 5], "listformat": [0, 2, 3, 4], "listformatgener": [2, 3, 4], "littl": 5, "local": 2, "mai": 0, "major": 0, "map": [0, 2, 5], "mark": [0, 4], "match": 0, "maximum": [0, 4], "mean": 0, "mechan": [0, 4], "member": [0, 4], "merg": [0, 2, 5], "method": [2, 4, 5], "minor": 0, "mitig": [0, 4], "mix": 0, "mode": [0, 4], "model": [1, 2, 5], "modul": 1, "more": [0, 4], "mozilla": 5, "must": 0, "name": [0, 3], "need": [0, 4], "nest": [0, 4], "next": 5, "non": 5, "none": [1, 2, 3, 4, 5], "notat": [0, 4], "note": [0, 4], "noth": [0, 4], "null": [0, 4], "nullish": 5, "number": [0, 4], "numer": [0, 4], "obj": 0, "object": [0, 2, 3, 4, 5], "obtain": [0, 4], "occur": 3, "octet": [0, 3], "old": [0, 4], "omit": [0, 4], "onli": [0, 4], "option": [0, 2, 3, 4, 5], "order": [0, 4], "org": 5, "other": [0, 3, 4], "otherwis": 0, "output": [0, 4], "over": [0, 4], "overrid": [0, 2, 4], "overridden": [0, 4], "packag": 1, "page": [0, 1, 3, 4], "pair": 4, "paramet": [0, 4], "parameter_limit": [0, 2, 4, 5], "pars": [0, 4], "parse_list": [0, 2, 4, 5], "parser": 2, "pass": [0, 4], "pattern": 4, "percent": [0, 3], "place": 0, "pleas": 0, "point": 0, "port": [1, 2], "prefix": [0, 3, 4], "prepend": 0, "preserv": 0, "presum": 3, "primit": [1, 5], "proper": [0, 4], "properti": [0, 4], "provid": [0, 2, 4], "python": [1, 2, 5], "q": 0, "qs_codec": [0, 1], "qualnam": 3, "queri": [0, 1, 2, 4], "question": [0, 4], "r": 0, "rail": [0, 4], "rather": [0, 4], "raw": 3, "re": 0, "real": 0, "reason": [0, 4], "recommend": [0, 4], "refer": [4, 5], "regular": 0, "remain": 0, "remov": 5, "render": 0, "repeat": [0, 2, 3], "replac": [0, 4], "repres": [3, 4, 5], "represent": 5, "request": [0, 3, 4], "respect": 0, "restrict": [0, 4], "result": 0, "return": [0, 4, 5], "rfc": [1, 3], "rfc1738": [0, 2, 3, 4], "rfc3986": [0, 2, 3, 4, 5], "round": [0, 4], "rubi": [0, 4], "search": [0, 1], "second": 0, "select": [0, 4], "sens": [0, 4], "sent": [0, 4], "sentinel": [1, 2], "separ": 4, "serial": [0, 4, 5], "serialize_d": [0, 2, 4, 5], "server": [0, 4], "servic": [0, 4], "set": [1, 3, 4], "shift": 0, "shift_ji": 0, "shown": 0, "sign": [0, 4], "signific": [0, 4, 5], "similar": [0, 4], "simpl": 1, "singl": [0, 3, 4], "singleton": 4, "skip": [0, 4], "skip_nul": [0, 2, 4, 5], "small": [0, 4], "so": [0, 4], "some": [0, 4], "someon": [0, 4], "sort": [0, 2, 4], "sourc": [2, 3, 4, 5], "space": 1, "spars": 0, "special": 1, "specif": 0, "specifi": [0, 4], "split": 4, "squar": 0, "stabl": 5, "start": 3, "static": [3, 5], "str": [0, 2, 3, 4, 5], "str_util": [1, 2], "strategi": [3, 4], "strict_null_handl": [0, 2, 4, 5], "string": [0, 1, 2, 3, 4, 5], "stringifi": 2, "sub": 0, "submit": [0, 3, 4], "submodul": 1, "subpackag": 1, "support": [0, 3, 4], "surround": 0, "switch": [0, 4], "sy": 0, "syntax": 0, "system": 0, "t": 0, "tabl": 5, "take": [0, 4, 5], "target": 5, "than": [0, 4], "thank": 1, "thei": [0, 4], "thi": [0, 3, 4, 5], "third": 0, "though": 0, "through": [0, 4], "time": [0, 4, 5], "timestamp": 0, "tj": 1, "togeth": 5, "too": 0, "treat": 0, "trip": [0, 4], "true": [0, 2, 4, 5], "try": 0, "tupl": 5, "two": [0, 5], "type": [0, 2, 3, 4, 5], "u": [3, 5], "undefin": [0, 1, 2, 5], "unescap": [2, 5], "union": 0, "unit": 5, "up": [0, 4], "uri": [0, 3], "url": 5, "urlencod": [0, 3, 4], "us": [0, 3, 4, 5], "usag": 0, "user": [0, 4], "utc": 0, "utcfromtimestamp": 0, "utf": [0, 2, 3, 4, 5], "utf8": [0, 2, 3, 4, 5], "util": [1, 2, 4], "val": 5, "valu": [1, 2, 3, 4, 5], "valueerror": 0, "version": [0, 4], "version_info": 0, "via": [0, 4], "wa": [0, 4], "wai": 4, "want": [0, 4], "weak": 4, "weak_wrapp": [1, 2], "weakwrapp": [2, 4], "web": 5, "well": [0, 4], "what": [0, 3, 4], "when": [0, 3, 4], "which": [0, 3, 4], "while": 0, "wish": 0, "within": 0, "without": [0, 4], "work": [0, 5], "would": 0, "wrapper": 4, "wrong": [0, 4], "www": [0, 3, 4], "x": [0, 3, 4], "y": 0, "you": [0, 4], "your": 0, "z": 0, "\u00e6": 0, "\u00f8": 0, "\u010d": 0, "\u3053\u3093\u306b\u3061\u306f": 0}, "titles": ["Decoding", "qs-codec", "qs_codec package", "qs_codec.enums package", "qs_codec.models package", "qs_codec.utils package"], "titleterms": {"1738": 0, "3986": 0, "bool": 0, "charact": 0, "charset": 3, "codec": 1, "content": [1, 2, 3, 4, 5], "deal": 0, "decod": [0, 2], "decode_opt": 4, "decode_util": 5, "dictionari": 0, "duplic": 3, "encod": [0, 2], "encode_opt": 4, "encode_util": 5, "enum": 3, "etc": 0, "format": 3, "handl": 0, "indic": 1, "int": 0, "list": 0, "list_format": 3, "model": 4, "modul": [2, 3, 4, 5], "none": 0, "packag": [2, 3, 4, 5], "primit": 0, "q": 1, "qs_codec": [2, 3, 4, 5], "rfc": 0, "sentinel": 3, "set": 0, "space": 0, "special": 0, "str_util": 5, "submodul": [2, 3, 4, 5], "subpackag": 2, "tabl": 1, "undefin": 4, "usag": 1, "util": 5, "valu": 0, "weak_wrapp": 4}}) \ No newline at end of file