From 21c201b6814a71a809d288f6337301d5991a8989 Mon Sep 17 00:00:00 2001 From: Daniil Fajnberg Date: Sat, 11 Mar 2023 16:17:12 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Write=20and=20configure=20docume?= =?UTF-8?q?ntation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api_reference/decorators.md | 1 + docs/api_reference/schema.md | 1 + docs/img/ide_suggestion_user.png | Bin 0 -> 48529 bytes docs/index.md | 73 +++++++++++++- mkdocs.yaml | 17 +++- pyproject.toml | 1 + src/marshmallow_generic/decorators.py | 30 +++++- src/marshmallow_generic/schema.py | 136 ++++++++++++++++++++++---- 8 files changed, 234 insertions(+), 25 deletions(-) create mode 100644 docs/api_reference/decorators.md create mode 100644 docs/api_reference/schema.md create mode 100644 docs/img/ide_suggestion_user.png diff --git a/docs/api_reference/decorators.md b/docs/api_reference/decorators.md new file mode 100644 index 0000000..53549cb --- /dev/null +++ b/docs/api_reference/decorators.md @@ -0,0 +1 @@ +::: marshmallow_generic.decorators \ No newline at end of file diff --git a/docs/api_reference/schema.md b/docs/api_reference/schema.md new file mode 100644 index 0000000..8e0a448 --- /dev/null +++ b/docs/api_reference/schema.md @@ -0,0 +1 @@ +::: marshmallow_generic.schema diff --git a/docs/img/ide_suggestion_user.png b/docs/img/ide_suggestion_user.png new file mode 100644 index 0000000000000000000000000000000000000000..971bb6bc57120b8fcfbdebe160332441ace38a77 GIT binary patch literal 48529 zcmYIv1yCGaur*F_g1av6?!jg8;I50i26qV_7Wd%6-8Hy7!QEYg>rcM-zj|9WwNukG zSNopsKDTd#vZ6E!A^{=<1Oy6DMnVMw0*VL%0#f7?+{cr9okF{hKNuG=pxUR8pU)@I zcL)eF2%vU#?Acr3d3(&Taz-A1C(31A&2 zjS>dU!52O{o)%AMrHPoyh*?{jWTuwVuX&&dEXkS(7;kYZFP4>nGu3la2&7NopAssG zL-&6LJw#5=$J$k!|7JA37?iZOE=!=ph@!)6;eZ{!LH@fFZT=e(Al_UEh|0=r*8^GI zIFyZsv-HNedPh-x3L^9Ak?1C0Wsi-<;1;|RM6=h4DUCL;KI;GLd5C0aaa+sxYx@}U zqYxWfK0ZEwr@tB&7E9uWJ=lDM%DkR`HM|9e4P;54QLi^ex2Lg;C|&k6hey~E?(f#O z?R1@zs){VfafhXVVt_bmG8wlplC#bTuJx;|Ff$&&*#U6Cx#$xZ9a zqP*!4WF)6%j*FnT4z#UVZ_6WscBZ|L2B3e@=DEjLtyShUg;V z^WO!*S{zZ#{Qc|jSai0hn|d`yYLX%@@!GrV@F+*GQPD9a=;VgcxT+0GRA^C9z-2E) z;#M&~Gg`4(!T%Ji=P@{C;+nZMO6YKId|o6y>_XR67!pMGsfT9NxnI*v0J{zcoO9MM zFL}iOE&Z+%asthwhPN)2+lKo{5h?JTIz3%SM*n(>Nq0?NS1V?cYIfc+=+59h^d3u> zU)6kqeDnmcx+3rEOGyVkcLQavfx|&Gd%3L2$$86ecdqwx5IePeHV6ZX3eGF3qZ=6q zd_K=Tp94}14`<&w2=%Kf?vE8N>M7pD+e29hlW`Lfdu#S+u##>hT4TASZZ6&9U%^Xn z)S4v-T#)3Q71v<1blWc=WG@X5DMKhIYbR$4RV0EQPgM za~;8k9#Uq(Oq^4aM8q&;)cJ7XQ<(vt71`$;q4b6Qam@5oHMW?Td!z5rf2~Q|@SP=eU6c+T?qe1tiQai?4gcJ{N7|EZ~}l}SRRt?4?nq3LWbecm(-vmwIhpUU1t zho9b-cu{SM#s1GLiAAG_kx}@g+$!1e1vR|LFj0;MO8nilidt zx7!2>rOqK4R#YuuP6vW_d-mIalw%^tU&41JhgR6$A5O^|a>J$S4>s#!v*dPv>c(DH zU517sz{Qa>3Wn6v?FomD$aEFabZGvB4wBe7QPE8P_+}@K>?%zO9-M(4AZ+|JIOt*< zR(YAb9MI+*WPKuJWYi1%8+c@%VcL{UPnBD_8AR8M@(di{%EY!AE=`Z3q(o6wr1^HM z=_v4moMi(A@F{ysJi51&AVn}@&=b8HiIE@>Ci~1o>$OXIY1S9t{+G_65l*Nuq2*LN zvD+^UUcC80Sm}0WG8d06G5QG0?g_Ev&;9oh3J5Ks7Dlb+fc>4eLnMQ}hjeOfY^332 z?-GaOeS5-;4(B~tzl(dnxNuUx)aUcIxbY00*{P|3jSFe8M2e0m`ne#cH7{sh(FsUb zyzx#VV51{aqpHP+0`*xW&v8PQ-L&E5l7Y7J?#Un`(|Tyx3RBgR5ScC|+RrJtV|}4e zu*sL+7G{44LEkB>CoAk$^+vq)o2-_D)L~xU6+#chveF|nes8(hL8$7C;k|o7r_~ym ztLgW}y_?);cd(wA4+@7=ed7UPX|@=Xh*#opkwr%S9n)OcaHRVx3x>evJ913&!geK@ zg$CDImsfUnkv&KnUp4y?6~A8+89rTVw8+izJjGv$A~#|B9bS!5JKT3cx33=gTGPJ3 zV#UQZ+YZ*|%iiS6#;(RBW&Ht}5yqEif{s9EqKu0|hXwzYN zM|O6sRXWAy$GVK=+*(qCfE;qzkw+T!l$?Vje1^`GtT^Aa*FK{iO+;{Yq{{!Ah3D*NjDSI|yNMTd zKVi1%uQ!?Z3W`qnZI*OX zHeE)EZ>M?v z^ILX($D*3B5D>hj$p31r3K0B&_?@g8f=T^rf%zAQH^IHo%O?^#S{xG?>qAW(!3~t9uhiS}$!ifbjWc2fsG@o!Yn#YXy#LO9a@D@Z7o#`k;NTVDNSL@nv z_8b*(fYaWeG;@WVByM(XO~K5J3gTcQtCtNY6)A{pHKOv8mrB$+)%4;ul2Sm_ZLj(& zs%t!GNj>v~FRb!}7U#C7Vl+Lu_a;rfK8Ig~)$c3@KWxBpQoHeWcMzEd5~P+9na$}~ zpzpoZbDXqGch-LSnu9Sd|D*2l+W&p_WEoi86e-+=@1V76ePou3peGn%_mn>J)80T z=Ysx2pIZTB)aYzZU;`yS9W`Myz}rHVwJaq0{mD116&`|c>HZx%^jz*wwk&uCWkyeN zlYU&kRxDj0#^ZwZo9Pfaa3&<+RJID?W5npFSM?cV<+=TiR?2mFvFA-hYkvKT3`v%S z_QY5fw_AI&%T^&lTW6s)!z8IT~XDEP>t+4s}MsoP=}DoC2SKkkJIn?Y02 zz*;C&r#Yy0+>m-aC2)I;%3&B9Z`wem2G6TJ_@O$fo$B7ShR;#MKF?${#i_M&hfe## zw3$KiPY{<@xdtOX$1jg-2f9oy(-}zx@!rI&#f~(Y+Msmp(5gJ^mt*M{S5&EA>HN2) z&m~3Jss`Hy`7N)NC#>|Jf*g6$m3wphgERS^L*Pjs;L5&S3{08a%#rR^Mj{COhATyBfnpJ8{Ywsu|1Z)32E$?K!YvA^Qv}SX%6Amc+mX3S)MHNXTZ$}(T z{3P`)Ls+^&cbd}o0qvFajeI zt1J0r^q0LMtB{Ko8x+=cCJ$Tlj%_;W2rtS#=D(9ls$@zS5^v?Y4}|hbg{Z>cu^vRB z)f9Bb2RG>N{K@5I*RHvB8DeTHIg2Fw2p?7-3m7JG7;<&&Xd{t}B9dkE^!c|%z%@D* zL*S6gVwu8vB!?1rcysnx?(}L%$%fpY34-tVKq>VK+Q^Vxn*wmj^bb*u>QWq)2pDjG zWRRjPNArl@5heW@QYjTW-R20U3{4K#YdgQ&eP)%`h++?NG@-Xo6P65B9XF;= zJrQx9QeU2n6fy=%)yrsESPpbIo^TY4RXIyOly9(AHpL@Bja~8BS}qN4xGzb-wqSeb zFY{pu%nqD%`asfx-5~%oKZmnnH`M(VBI0&GR>=rh?gU<$j0`m$pja0FZ9 z4NpT1%J(z>p-ST)Xm&16Wrg@7Kkc<^XK*Yum|03xP@`B`3z~A>RJT^jqQ+|R4n`40 z4{3|R3#M7+FAD3bOTHJdVQI&*6&?sbYpRj|7ctq9@1J0WtaO{##iyiv+q(F$cOdOf zTiUu0S(Z2qQII2Hxn2u+zD!e9Rkio|qHB_;>rtV!tjytC%}0!9k3U^N@u?}W^2DRV zAlvs&TYk3hqbPZ5No$u6Pf|-0zmVcnPX!1MuC>xMItH14BhjR8=_7#s)I$uMbNr~E z3Wv!~reSF-BKl5s0go* zAa;4*bofr>nb!9>c2yeQpyU&CI>ct+vqf_gUX`r!HcQvxh+z1ZWpO0X7=FUg8Z4=s zQy_sd!-wAbhJp|DN>_BOEw@U>JHVp z!$Ehf9j6!r^U2@9kY%(D z^Y<+s`?LG1kR}gq8=iG(QFk~g=hQ!{&x>sb5R?cgfTZik6Rl2Lwj;%~xBUd4W^WpO zaa@~x_7R-xmYC6DSK0bZj~pRyw9gCjB1J~~LX3triSkV`BAQI3o%g83!M)9qIM~?I5^Y^UY(%;Cy4p!!TMu}4d6c=c!xL#;pCTWVc=lt#!&VRl%aE0!c z+8^2Y={PMkbj2K|xS*irt1+y06A1SdyhD>TTHYQWGdkjNzemb}1q&SBk8pUS9(+5w zuq2W-b~3MXJcAy~W`oTz!8o-yniN>Eyg-A-$bLCuG;9i-@ga>c!sTjPFQ{yRhaO68 z45V4WcCKdr-2*#2-J?&m+7i>6ygtnE4UlBT&{*qpMYLW$X z*Zx;;Z?j`s&wTp||m60J{URJDus31umu z*$=pp_a)LYj_p6h=G572AdI944Xut$`_>*zn4J9a#^ zVPMGG?`=CwLHu=1<>@dOu2!`YFi4SKlv4c`Sn=zPqx~_8)TwoJ_pLaademu$vYJ?x z)a-ab;o;slu4v&Mn!}q|m0Ku`0=hOU=($Tgj7H|9%wPODeg{*tIFkyf=48Ye_x3Ku-~L`G)50MBwcu_L0)k1 z>mGrces>gWKvE=}@&2NK{-oa4@a%5P64Mnq;h#lchL)wX3#JZ;^qa;*s~q7BIzrF7 zUf2};7;H#AQi+=QkFI1GbO&DVne!gIx!2cf(7gTV?vS1VY|rb(CCq9|@B2}w9`9sS za-`;0TTPy~g%^L1KPt-g<|M1ox+WXl$8xkCWbtrWac{3X zx450b*IPfKB0>DwBFKw9eIbh;Vw2&B`vZiem=YB@t8jDc9xvZGz2JnS9R+377wp;y z7e8YLUQWv1Qdm|xE9|U6*|op6m?-}B3qrAeYm`Ae##P1TP&|x+U;HaBQgX7Prl^p1 z;RBIV>+}_+494Q&?i(h>lr0oU4gfF+K#oXIli+#6|!N2 zQuAGx>#j~|Io(go&qGs(=WV-c9SN*S_&d-H$8tX{D~dY9DASdvE4DvEJln+PW}tsh zXVeu$X;Y_8$6HhUdnJ@dF9JL+ALumr=tD5=V7zq^w$05M1CK9?>TXw? z8}4~d_ZpTVI-o^Gwhtrv%W0XV)hB)$E;o#DvQYt}t8ihARWPAYDe<>%;>87hHaI|v zC*(wj2dhT}1nE5s9Wz>-?2YVM5)`45_-oO5I@797oOU;aqu*nGG*38u>o@5=zpL4P zv-o}lfp~<2RO+@Z6C6js>>1QLML_aC;=r~`YVz}h$Rdu|ybog7q}N!WrDAMi-C!|jl zbeLE+1gJ|vk{ttfk_5z;MgYvAb1{tx!`N{XQ7~}<9pVT|4mIpjX`UprLAV!1NCfc` zMX=S+LXh*q3yww`F|Zb#oFQH>2?+qrhvAU+3FgQO;)r$4G~Bbn*|{zdgFNnb1RwRt z-@4H|#w~cAPI;++(sJ8c8Q?g0rCXzjP_G!%cnrJQQ0D;#?6)IC1TH#m`NhQ(V6!kv zOTp37(}Od4Hdpa-PhV5}FyUO1zjT8+1;7PA^wVRe9ersi(qz7J`70ICo!$2^bj|LV#N$@zjN@H6V;|#;(L@&>qs9gEAzP8c+2{U zT2wOaa*mvpThsWujM?|1uW68$JH6)m(%P7j%#kE1cVOI69+rQ#nNfeE;M~im%6a-o z*KtdQg@Y5X%N`t~0QHK@n2#DKjw(~+p_O*rV-pIx}~0x6L* z6pGwvD%=iV&Jp4gsmT;%=!**TEQhhyn2HY(j{=hNN@Z^txKE-jEZM+xX`FF{aJ@3z zxb_0BgHqwwd_JMOyl%_siqrG1kwwY&*&h3UK}9Q{P$eS&8#j;RY*drW1Dh_bSuT)CB3Hl)sKg7J$eotHjYsz)Eo{=#{eK8~qu4a<4uS8@QY#yw}9%yUJc8PoX^>jZ%u8?AhyFYWGmb2SU0??r6#^H|5S)OCMoWnx$K74&f*xq z^YlFZI}Ad<@l{9Mru|XBME>or=!;N{>%&6zTkfPwZDUe>koH)H$=)6*C+6;Q3jl)> zdhQRm%Vh7Qv5-gR&2=cKug$Zo0~eyKDsnJ;sk_AYVkgdWSA)4H{}e}veF+T#%ByPVcVH6iJ;@2q^U>9-{0A+TAS9xDEt2S#Khb??CEL#cqxgZbGyCj zX^Ef|VCI=yiuV4?u2C5|!(*$g!iRKQ>mAR;l;YheDA__IqI8C@(~|<{Kz()Ywfme? zY^%?5rG?>J0R5hZhLF81I_%OlSzo~_XiM%r4K1PcPFV9Rf>T*e?U8 z`_crmJZA-MpC|okx?@<6N`+%<&b7}s*yUG@BEcip1vS1iVf;s2&e{!r(8cMkz)|}A z(y4I1bLS|IDMFLIpa#YS=V{~^m%)2XyqM3sJ^z~vK=P9&uhw;(dKdFnOE6STX;d1~ zHI5;$+)Jw&L~hsMfGPK}P5;k<`|&V3hj~-qusK9uSWti*r&@G1)kefO|J__>SB=SJ zz5M8*-AW?7S8JAiXlz0<;%;V!FNCEF-G9^xP7FchgF!{<)vtF&4Jeu3(2;vB$^RfX z1Bzm4T{OpXoh}rEOg)3g)S^2(McEOHm9?})%r&UR$BVDR#ax>j^2`&J4Gdz_5BGwb z8mGB9g9`YE80bGdbiyi@lWnCiTqbTY_9Ua99r3B#`Q>>;9CHKk7wwYwi|Er5)ft^X z6|WLYcK7!4!dG~!ckEiBzjlLuf%Bm6E(&lQHM}U=zF0m`6xm5)Y}f;yp}X31C@~b2u}&^SLCCFF*x{ zj=ey^5yWlA9R@@Ta1aVjDSB6tQhv^>s33F@rRtaT?0d3VdOb%Cs=}QReXX%aK4_k67o#X4Mc@2aj!RtMfphR4!`|GryY|>yIk`b4H+=zL6{9C;dJ!Mk-VVC9T;Zn#|VK5pE{rHr+ z!iUYO<*`rqo{cCn4=s~?bs-M_jC%E8P@5B}O{jk=LMW9UX7YT;hdvDi_`bz#`dACw z_u2s?zBOG0#Uy57BanOpB^!Ai;hwd*X4u8U|AP1Fu8}QoiLUY&1Swd z9<-3+H(jJ=q+h8jfeM5s?*a}pZ0J2OjIqc*696|0!j_k0JGTR6H9d)e!i9R4D9)55 z8IKS(P{2f|v9ny!5BnHZ|7*^${+}Ip$kPv>h>3mk-{TOSWstdDDh0l?tqMK)JKe}& z9-fF@;e1t55i@U$>m1k#q4?Y?&{}PltgNCEf^o5BD~{_tqU2&j(@M89He|8hDxIcl zd3mB~NQs3D8BX?Tfm&Tt(?74G%KaPa(vkrPNRe-gaL+uxEBv1G9{LW~Sv7YfcD{Da z+mby>ZyWs?wf&8Qz}ulcC*1LyvhC5Bc1M!rycv<#t9PblcKhFp3NV*1@qLv(Ywk1~ zyVmGR*Q(-fVBf4qTBO*cKmqo5&n;AgS7kpzgP!HJ|C4pI_m7tR$B8o0K%xH6 z=PfH(jxt*1jgxxylnnGZdvzMt{{+pi)QanO2$$;RyDmz0g=T|jOHRK?0>;2gi8vq# zqXLuqIT9+YSFG{LpP=fimW`qz+bvw-Cxk7VNn9R28~)j{GN)xJB~jbz&}Hg)C-r|t za;zl>P~x2CZQZavd9h5WZjCS&xypXV(IwzZW2VTW5!Qzc|6G{=25|C{S&cT)CfZHW zh~KK+nP3t~+LH!S@?7PPBO69{!w$VP?X+LD zqL$SujsQPmZ_2H)py9lm#eMx@EY1TMdm!^}dIu-3PXPwSb3J~WCtJ8)<{O@Mvyyi>GG|=mjNV=N zr@Z|F+TZG&Z&X7?fuJzFY`^faD z749)wl}w%tmQ?&&_bN?fbJ&ud@GmWGHIy2L2uGTlf!n_5r1#zEe#^YPlb*zH->Gzk zfNu^vZ?lcaW9n(bnsDlrdem z|E|O01Jd`4-@R~#<41!heIBXL!-BO>a!ih*!A@0D&&M8n#ljTm9qxTww3!NS?qJf_ zlXr7R0MLAx$Xw0bxJiuN*zs`Qf4dsSjG?o;^g3d6B}-$X;|kHC5uP^v9U{(leJDP7 z5MN#=wbNEec7xo&YexwDhmrfsYsNy05+XJdj|$nh%Ta&-7-I#q;b23HBcahl&&P$n znBfISb?{hpXc<2LBVyOvCQNI8?@j2aQ$ZmlWc!|+7H@z5itsy$o$qJF16%Wx0j9Zy zSIoDXVO6GD#c{%S#f|TM(QZn0_TvPKJg?D-sZ)@2 z1wvbj3E~v;c4fA&l03nM@p^BbAszH(WJ!a5#{3q60kU6x`}299gk6aJ?f0|{&D_G6 z5o;JE=bt~$8>^m+AmGRL(g)mP>(>A!8=E~hABCmc(6LkNISnVPk<&`CL!diV#wW7-nIBP(OYE zFnc+f+b!@Gbh*gMhv`)p1SO|ycSAMvg&G#ri-59Y)8G6fE&k$g`(EibpJ52aNP9Ru z6W)ZH$bjX|=Mg&}1pYGHj?M*H7P%Uu6dCJTev)-RKOlWKen&}>{Rh`B`sACeto6q0 zZ@)LD*_^Matq%!kCu}O^CsKbu&Cf2~_PpnMk|8f@U2eLlt=^azP7H$wvrU)AnO2q4U1qSF zIs^;2Y^kYIkzqo@2W!D@DedJ6vI>pD`M$=?S*c3k-RXtFo)A!V%s2lx2Q5Y%qID<@ zTTife^2E00#aw_D`K)NuF*jz$xEQL1h?ALzAC7N=$`k z@QyFg-!WvS9g1<^%7h?sOk2E$L4G_u9B9B{IgNmf3g)&z)V7BY{+jS|O(zroB@aQQ zw&t>P^0UJ#P+v}%GVn`S5G6>f0wUz)m3LnqykCt@5D7M5O$bGz=e?fb78|y)yWeIT zFEf}da{J3yw?jizdD593`fqUxEcOLZau5ApBds<*!==;45N%u}pBb)9zfAh_#cwIl zOR=%i{Oq7}Bva(mENcxdZjR$$^K#R1p})#Z^!VCKSmpj~)hnXq?)4PTKGxH!2;m%~&$Q$~*ak?%RDm)FHZU5{ww zy$EAD*u5E)d@GRGSP|Tb%mxK6W_?_7RY`nOCw*JM1*oXup|fp%eD+%B^T_k0o2REG zwvXEm@l)OAKquQlT?y9!tm%TD$O=O<13^?UY=&gMxi=+5;6A~zxsvJYjv-C9jB&#X zLgvcokQ*!^1jczeRBf%x@UJZOMS}RS4PxN%n`-6F#z}vaQuF4wgw%_oXr^T^Vl5=e#oEfL>h@zibD_ z!WNi=viorO!^7jYDH@TQmSG0QK4W#rthYaKJx+EeYz`D{G#QzhwrY|T_(*J1v*Ln< z!JzzKrHIeX(fb%hxzj5;QRbuMJiSuiEa1~2Yx^aQJrTs28d5l=qnRm(HE;wU1l9L} zel=&oa$zSU1!g!u680pM$@thMG&Rv$`O*(4X;^T}Y|#l$2T1Y8lj4QkV52OQjP*{T zkkRI@w&1w{kp1aW_FIQ7&8|z+3ZiEerVfR=RaDcQ*5w85d4vk+ zmlA!%ny`PjxXWp&DfatjfUO$o(#+`y{XN{8(p)Q{#WBEP6yqA+RJ+@ukbTo#C4f&qixxML%8tXDam3CB38>`hV7)r8eg>@)_ zDky9iUqRZH1^XZJMG&AuLKM$Nl$Iv=U&5);vS)>fMwCz4A0`eV>W9TDC0`Lz*JNa5 zN`B1yLrAEY=41$yH7^W=UL_|dCYE-K*$S^PZ}C~}#;a+UgIzP_hx6d0M@>DzHA9pd z&|4Jwk^4?Utx<;3w&v7^MDb5Lf)^Gzy4Pplfl#qiIuUpUcW3$;}F`~?aVL8cDB zxtuy3^>;ISa?Z|mG+7QKP@}qp{VHVW@goYjv;usLHGdjbkqsklWWo{qz)ZWiAeEE7 z@}5?4R-#iz5Gv4Ypw?TPgEGrb_!&Ekl3(joO+#bbE!JI9A?%rNevazc>7)Phb^JmP zL>SO-=&cB~{Zj6YDMtRJ5lWu+kROpr0+=-|J;B7v3R!zwtQyitQ^9kNRA6xpu|D6zktkvU3iZr1$?U3bK+jZ3c;W1-mUl@+uB=p!g|-S(PYFJQRa2x1&BingBCB6a}+!;>SWuI5yOlH@-gvwL1utbx$Z%GKgwjmF zog5ex-N%{dlvT*lv1pg?DF8sAuTz=3)5ZrzPwtUxXEJKnCFgNQSc>&-)laWDM!yyd zRC^+6by!mi`TEt?`aV2A|Hw)M$-cI~oQM~I2N&q6p|^d2R*T|Y8da15=aCT+j0}8Ocplg2J?~?O7R-} zC5J`&^8?$`!a;#SNw@)~iGpogo@Uh8+4bE%-CMl5w#>u!M9*1?YlaV;*K~zf#X~%p zE|g@!qv?kc{&BiwOLa71OPrA8XJ-Q%O4?1dJW;eCjcyi+^NgKq6E_EIX7}+mo3|JF zc_2h?-{O5c%quZd$Tr*&U#Qxi`78&Xl-#Pv5V;D=r-gzcqxiuEbS*3dZK!$nnxj7J zG_8!yy8_I(kndKT)w)3B=ZJX4R+pP=4p->jspn-*oYRc|_+pB_PDIS%t8L7=3j-1k{-mQaF)@e!3!Dtn*;OF+^7b^I4Z`y+Ng|_V< zV8OG+4{#~U|H{()HrON50jUsO>9WoHnGm*;oKw zbH~vyujpntvUp7uQJ^A!ButUXnI3uFVHT7G8g~JMA%xjDtWk-_Egm z>6))OMR0E$xmoq#_oOo^t;716UO0wBuBD9Z>mg9^Fe<_t-C`#!ovRI z9^^8Q;&NI+Hs7TlzPJ1p8DT6Nvcs+rOn(M>8~MmHk${zSRVb!XjWY zB>~)z64AiXCQ5gtZOA}4q6ztm92;#Pdf@PGEPwtzW)j>aAJ!@Qt}l>J{W z-v1F~>1rWJuKLn)5xIo_ToaElE2Be#)*}5!U*GFKl8-8wr&Q?B>3TktDr7XZNR-}6 zTD2-ugf1zaw|37t5BSeFKo8MX{4WChAP@dMdiW&8VPCK$zv?b?g#KOD6!ZPN-hTn& z{67Fyr0&OulN)iZosm-AhU!zDnxaviH775O`YHZ_a2mD6Wgr?1S?7hejv+ zHs(EbsX@=Q5($y4bO;G)kNg>B4Nkw|0`xtLI!d3sZV)%TxfR_bnba74h zYZg`t&Q5deFslR4*IsgY`W3s{0(oitw(bubDkGliF#}Qzjry>ml`A08h=JcYqal3i zr|0t5f{5aj1lnl^HxH~GzQKUoD9Fg!9mYQ#FA_xcj&+bBz+wznoL?U(O zn=W{+?zdoq42Pk8SsI>|aC-a)_$Ow@4@brEKHjl;#*xo5~%wTH4M%B4aE(aN3& zH3OFEGbL86qu(+2{MLXe2Yy6G^DNQfFkbG~P-u&Wec~tH5Mb)q&}@w%hEUvx*+d8~ zoE2Iu&;R-z@OzFZcy^7|XX$lamoqpSQsx>KvWl_AH(lkF_esg`uKu49!FDG;h4LZVws=i!lAReL> z>e0K!g<{6e&;<0xyHaJ6Hj;8^kIteDx*o)Ng#pN|N$NO$@5j7Tp`%{7ukXbu;noG` zXAU-&Dht3U0noICN;}!Mm1_vkAbnMcbKp~c_3TLTGdQ~2IpE1z6k#ZjjLIc{Wm3X=wcnY1xo zp zpM0O4whQO2Ia-%@C(MAEYhphR^_?|RpQsG~2Yj3LwoJUk{^l%;(;L{;5l&&x3(Dib ziBJc>9Hav!_WN~dk4c)H+C173Im)#2-z>~dM}H_f=VaXPF-$4%lZX|-K)$i{_7T~d z2;z&q1|;c2y%Dg3Ju1X!@ZQnME+J&e*jGigJB}`Jz83^`DM4?pAh@z-UehBd7byg; zsPq21X8g5x)0}V6I#(VKZZ|pkmksk*LJ{Y)xQnZc6!Xtvp@l%iLd0n;SDW>yizb9# z?#_#yXN;~hN=}pzN&3AXhNFR2J5tEbON`SJh;pGbk$Eo&)}AEpf zss4J1zL9c&HIV(~`8=r>uVQ~sP7$wSJ5ex?*Y&{d?`{qg#I1sOY8f@{Rq_0z>MhM=M*qkl!_!nU0J)4H!-K^6?e*BA?1F!NV>GO(#R{ zS$DCBs$nZ`4Ys?U@A)r*Necg_y#e~S3NXKG=jw08h=OS6ovW&8gGX2sGxAk<&TA?m z1GdOPAJ1Emrm0eG6Cm*m&-y!$pReaz$y?>eRHeixwpk$Bw|o44r6s?~7*p5)*%NT~ znp^q=T}>mOXqt=2wp+(CuX+bgO7KesooI+>5w3CLy}b zGF?%+6=}3e)dA8HIaY}^`ABSm3>jLd;_gptv_TzetDHp-Y`1elCLfPz_^S`S{CrQY zpvHW#f1BNP#f}}u=kHRk1Mq7VXQH1plR53Hjs(vl^Nl@2C(n01Z?i7gzE;iN38v@X z7kInej|?LFpD4T?SG|WR2Yt%$d1))Fp9}aZ`L#2s-8s2MFFl`T(h&=R9b~+Zs(^s5 zQZY9aO_cx55*fi#X5W62EKsAOd(}E}YbOC27$KrO%A(?}h+UMLnW@&XhWH8%9in1{ zhZZGD74d!7l^XPuvX32L{HZW(U|cjy*~51pC7g;KXIq` zmTEayN6AO{$~CNxCR{74qxZ$@Yzegp|K{fIbCm6Bt6yDDkF5R1X|q_<;rS6Y0o!MG zKv$z!&AN%(8}pxdHpQGQ(D4Y@^=+|2KtAnA6h;IUaF8=u(**{@bvC!EE9zw%DkjCp z7jWxUDwqsGEimiD!qLdE2=V<8?f@**F2EaGal}&jgN1G_mdza?es_-b4X3s~$U=Wn z(?|!W(GF9|or8ZW=IuwD$K|5cK)AP~E#XRIW9!!-jjSczg)|14fdM!+^^3?nA1etA zedOChHtq}WHCKEB{O!>xqY@q7#KGfO3D10i;L5Xi5T@AFfrMvaS=@b{TnN#s^<&TX zkKHPT7UjOP(;hal+C#>zwExWoU>HsOR#4cGPkiHE%ql7KrA;=sH6C7shZqjdi?-6@ zNao%of_o_mn_htwf-)V%No;J@A?n}|IaO9uo8JEyt+H@H!F9{p?YtcOK0Cu4U8yf3 z6^{L;Byp5;Wu=O?6`wr*yU8bDhfeMvTk%Ent95;xz`ky_iCf`Q92@|D-YyQai)l^$ zw>o4kT>}aZHu=>w8pC_E{Sa(P&)+bLoKkZ&(?2}M`S+|%+ca?aYdnYsxi3553Y}w~ zxw4P?fQw*jRg5@3mh(1&1@R~I#8{`BBeAuE7971BNDmVU-f92;e- zlX-f$ZOtavvc_NCRnqg%2b|zgyYT`yEbt>o6{*>x%K}jd&{7>zHZ$Y2mumY zg1fsm65L&aySuwvaCe7b!Gl8@m*BzO-5r8EoR$B(-+k`cckf&0exWFe>grx|&9R>G z8_zQvT`ulVwtGha`pkuJb~@SpcD3K&>Fh@}P~Y;~15+u(c%H=frVAt!%UJ#AOZOc- z{>e4twx`@UN8fz$6_$wpZ45Jk{j|;}{PV9yv67(B3iVRHdtNL`kpX$;^ymqzC%DyK zIBT6&ucSIG18#zEyzKJ99DdX_a$PIgS@fTdmIoH9(NJ(}MPVEA(OEz~oZ{+fNJ>i8 z$(AQ@7HwwPYNeav^uQh&QWvGqHoRPbs9U8JHPECSo}SOpEdOf83~~#UWewa1v)E+y zKl09-tHJGx-<=;u_js}Y;&3I6mGd*q)V|WpX?Fa()#3~-xh=hUKD`WFxubq1f`K-a zS9EtLxt6$Z zyHEBC6aKp}_02(pT;<2OhA1Zyh@j=7)@jqtGuOR3RnWAdLk*T3`d8xFG!jgVhn*u( z<(GJzEONG)aWBWrIWjw+d>n-6=t%G~+$+S2A3@$;Q&WICE3SV_r&3pvOM zrIby#Ls{2Y??SKI2qFJJl{@8wd} z=PyJe^mWb6{IZjezZ)hDm_G{9fd=oYkAaI(&J~K;<=^zvMk}Nz74+5eAD> zGzya}z+uua2h>PS!`I59FaA)1w>3hwrQ7(^PP^ML9%T*)8FrM_8w3wbpmr0MF^Fh& z^@mUwiH65;8p&C-!o;nu>s=xH^#>)R(VTbA$?$ug6LGwC2BB~pW37L;H+ni(n>XVi zT*>N#cR!&MnQ%+h9;%!Rt4ZCZdb^T<)qQ;NU#@c8zXcVL1<8IR=$)f@Nb$6j9iP7D z?C&dtiTxw(^WGL6PrzQyIvi@50*tJyHJrrK-(ek$J)OxMMSepcNB++ah&^4T@3 z)0<4!30-bz6y1>~~c<#eX4GGdpWekt0! zLDpX0tR(K$J|lk`*LJF3AMN2N!fOTxI$Ndbpd|zkp0EcEfj_PjABj>kt?b+m@lT5) zOBEy*OyF<){tc0`48M}=cWnw?D~Ly*i$$Bg`D@e1pY{~Bs?c8h>!G5c|(vKX76e=t574jTMS3ZAdk#nb^bkFNCVJa?BOC8u_9?6J#pgpSXzVdEWgib})HeEqaqeU5GroRFEAxEI znd`JwdCr>Y_2-+g8KeKNeYQp2&RFuPZ`_|l*XW)0$3T6fG^N694!W?)^YN^CfFfS1 zg$XxH7uAJDlp404`g0o_$5H`TWn2&u6Hq#9Wo!MIiKjr^jvE8p(P&W@w{0wfU5Td5 zSyJZpLk19ovcbjMEl8nNn~l6ji1q^(ECHunqV(tig{zmPr#5{UxUt&?8Ql5n#cK98 zG5gH)umi~|R^HkHMF>)EZfG%Qxj7`Q9r7smBco&dKUaQ)h6F6jjw&sTjHSRf+i!_9|YByCOIRa_dywH^(l$6+K! z;GJ`(^X7OzN-KkWsB4L--t6OPuP!oCHJL~PKdqdMb(^F7xzSx*vc7F>c36%zD5#gf znrCHEvZy}=;@UoH%d_}+t`yrrl3-b6S#TALm|OO zJ!ZL5ZQ|KsNF_-mFH6z?YoZr60pGV<yA2kk8SJ>){CC$ z8GDu8r;A-@x^51Z-+%wqM%7@#Y)S zaC4q4dBZ%l4(4pmL7=W+`11hPd=wv$6dUD}P)mjt`#%MK_XC;^|KHtEaVD9}*}`_P z^s2x?0_`iGtlskIAP#sgywt6XinoD=S*6+H^ zYGTOztZVbo@FiS5!xSrUvns1xBQ`c}KNy`WRO;=w;{c=d8; z^U9{X6;O}|seCU8*bzlK#fxixVw0nA5uz9(l1H;2!De{f98q^?b#UY`v5r-5hK)7E zlc*Gp4jFh+uqhStD95s-TI|9-U0|0?@W+(wH%ehD+_+6G%7Al4M)f~EG5%4p9ti99 z=(R49MYtESNY7>=Lu%zwzhe3#xG{y63v{Zs&gWgO#H6b-deK>IL<(jrl&d&6(6lp9 zxeG8Wzu1_JRW?RY8G*_vj&eHhzAec~?;fdj;10`8;M7A(H7k)d5lz4l!q-oK&2x76 z#AQc;6F{1H|@u*VXhnI{*;MAw^CF2S^?%!24p%JY^D%Pw4uv6hZ? z1ySXF^t-oR?90aqTqW|kMQm0;a6IGjMd9Iew&+Rwv)_fBd<%PIK&-9UK{&3@pYmL1 z&#JG?r1(6pp#exy9zViTWIA`S{M$qzEYyOxOU9?s!Qoci0Ed{GM!GnDFMT`=T6zsg z7C?(3IsRmYOemj@K)};wz$#pRO6G!2R^fPhBsZk@_0YxPa)t|a=|2A#$9rdYyE>Ip zdm`gbX+eu#G=hat`QC{?tJu1_+>%o5O2w0YsT}IrBa`SZ!KPZ+*r8Ir$t!J688%?V zZUcuCE)iYE%7!?@C67Les?{6`aU*;lN2u!L0eNyu)k|pc3~iX$|ebxQ%10C z#ef)7glb%7jkc<7$LJ6tX#ghvl!F9nm{l{UV{An0Jt!!@7TqKfmA5*^a2YhW-^^bx zOwHNiuV9WpR}R@whVE!{2|vA(Ies}3Q(yX3#1lbgT59=hZk%X*T@1nx8zq?JB0LCU zjh`dHIK9wjU+^7LXI(#&|1COmfzSSvz`{N{6ko-q{oB)BvQPH>`U507`ao0jAJiQ6 z&AYctWt71Aj;F@!6JEQ5kK*BEBFTVCh? zU#(9h6(}emfu*GY#!Xb@77<-0?Dxd}+9?g@)lJy>Gc+{uGJCPz*ku3K{h>3$t!u5H z`TJ2f$%Vky#;SU?QsX{v&zmh&?)@|xh+zKVEBA{e2^?o@oo4VzpSl7H7!fxe!Q4x; z**jv<260-->2`&yJ%W8Nr*_1yF0G?<=P1P*njMZ zAts)W+z;Y{w9d)XK`$fKJEdOZ{Nf6K3BaMS!O4L%>My*4?VV#)wIQ)F#n?Ux2%Bt7 zeu|K#zC?rWH3wnEpCPhW2|Xudi~L$QeFny1G-! z`s`z4Dp9KH<)Kub7VX9Z$%bOZ%t8199HdZv_sk4%@>CBmz!Y zXRJn3wwrc;vZT9&{PUysZGpSo4KjMk$Nk?m{#VH-bdY;vN4GaV=}2*;*52?gkPQNAwNXnIbmMOXUv^><|6ZgklC z=u;88PlDSkImUk|G6qabk=8w_v8~F>%YFOKg9=G(;eFrr5=ow?brDXbywCyxngSRJ z?y$ibbq>+}L2-;NcGmh}QkqPZ%O#kzW31WOSApGbL-BmW=&H5-ji4o4>Km0#8N;6} z4~C#B6?}-*SZALt3}1o--CR6gznn%r0g)BI%c@qd%E(>H@K#LXaJO5hy^#+qR9wL* zOLLyKCt2N|8&R0T#2ngux2+s6#J_4tH6HiCPa8y&HZ6%rvr1yX{x@bnc17TnXFdCF z$xU#`NZ&cuZ^HCn8dxvoKmV5vtng};21V|^db2A3J&mt!kNN$Xe~X~#e0cxX@3V8K zofM8;0CjEY3;6DIOwLfRKMglV9HT_I8bI4$z2W-@i5o`vKcwj=Sbs&J)oJAzI9`7h z;35c~fscB=%=MS+;z_^cr2YJH6f!m%;Y)LS4Hzl>oZTW6W;iS|(dK3dUWjt9?AWIkISTy9}ksV~aikQpU z-IV%~-6?!N&(H$NcoKLvcMIvS@m59RW;@vJBF1>ioe3kWIYLmCS^>?o7(D}2IEiQh zd8zt^b6))URe$Fz1Y!R$XFOh+wI;ty(uys3FMcWqphpRnceu*3 zZJ|v<(Yo5V@}k0%h#cL(sDY$g)$$o!zuN_ywMWj7iC%xzVk5?Nx16>985Bd@<}&)$*C{UH?pgsK@Ga2+vt(0I^@b)2d`gRfOv&D=3pZ}Q-ZY!R^3>H zlgVDA+GctG$*zr>6!VUs8Ph$yum`l&F_JexDpo0c~1)C-Mh{ zpkhvA5FFRcw3y=S4s=CzRr`T3FW9W;*R*RPFwtUFtXKKpBeMV9`2)ZGzvpPX@6j@2 z^E>YcE)3JQ`*QRDQiSISRx-!f>`aqOi}NVPkF`}oW4U}{`X%1f1M1U8DJ4^E@g%r0 z_AmIMkaSU39&+r4iU3`(#FmHMACueI#Z1o`=JyK|Q5$7qGe>6id&HlcG2L?lzvJup z$dz0&#mOw{zW!@&{M0Q<*iQF75HSQscFaB}Tta@aWjs;5j-de}ytK&&D z2*{G0%svvN%B$%R&u>Bf1xMCBA;`HajM`WaKL9saMXzj!?}FqET$26YM|lEe&im6~ z-=G*tko-t(f>4%pQC*7pV1(-iE@X&O$``wxchZzR7O7V=+KC?KXl=Ops9j*hHm{UR zvnn!Bkcq@Mvx3-N(OQrc(Cs!`_Zdo=`bKO`3V9_Vx!1#{MGF0W?=+t-W!KyKAI9u! z8tQ(ptS-l`mXJ9Ip11K2S>*?siiJ}d?UV>?n!mY)Ku97gT<+UvOI+~@8*ZfYcRoD4 zZRxFvI4k>HX|ES+X-G^noLJzuW&?R2-#DEffoF6zU~USXiq~hwNzHjzj3s%Ez~)$( zmby>kf<9Tr>biX^uBOg5G^mVIT&-(Zv@^->5S;W5mH!O{Yk@$>BUPbWNP$4#)6Ma| zv0BdvJSD857@Nx#t6oh4BABjY38YP9TF+}CTg*dPR-q-F)WArnB+{UTWVcZ9v@*mF zOb)&rRK{IS-RPI-+#e8lmGFBYQofec$(w(Va*d3X*#7e2?S9*T$NzN)YlUH1hl{-> z`=c&rDdXBs?&~4d^8wXcmh?4TQbCyr7u(-O5t(*1!A3dr{Dv2ek5gRZkTuSvyLUy$ zX^H&-rWG9m^pS34e+dE6Je(>q8o{NGi%kUF?u)-z<+OdI%Kz|8Th2bXA$aHJ`@_^vNAHWGp9&qN24$<^d?(-SVf1OB*5($HH0>&M}+ z^&NIrsZJFbLjbb&^USF`M{{@mufC8WaT8yE^UlG`BW^$Hiyy}$Bh|*ORV^N$#2zla zBy}UqwzXA}paenK+?`wRhXCp)TnV@7KfetdmazCXjT3NbFx_jN+ zkpBYgSFw2H^HP-Vjf0)f;%*?)G_{7-c#-NMt+KvegJ|vP2R>uLoiSsX2SFRM1RgEb zJv*Prcwq>h^3!(!V%)7QT=9h*CeBmz|Lsy1rjsokPLN+Gh>kZfvxT$P!rV*bcWZ1{ zp#qVOzJ3p{7elav0~D4v9iMdxHUyX22a|Qugu2nuaRJKZh0f(A`D^BH4H|moi8we$ zl^#LaB0_ErAb1kOPs=9?aI!t*r9>wiKL5;T?7&T~r>yPoG6wt_)XKj6u0C&Nm`X4! z<->aUy3J|@tb8asLoP?>!TwTeg9cTMd2d%cI#(a3iWre?N)C^Pv;rClTz ze5Mj8Zu?p`RE)zoh!nN^@WX2JOAgaC=(FSFv#|iD0Gk|1OV`~T`9ai1v3`)hpo@PocW1sfNKQomIM?AjSYYT)J-8eu%(QR!cBMP{Ma zth$(7A=_MdxA8XpZ@@r+q}3KmQxL^10fy4JL!-WHlmW%(nLD7+h_i3?VUPn9zSLC z@&Fc#1YPe7nOEA#@AyA!bob}L<=407;SvN3s183fUA3O*H&!b6zJv|MFU@U5;Z184 zAz02?pDgOasL;;B`nUE)H%L}>i&71 zyWKh#H}3FVaRQhr)#`hW{+{^j=5kRo-ZArO=SA&+I%JsB0dAkF9frOO4RBL-9Fg~( z9FY)cf1$>p!MLp+p+FmECGvy@?snk87W2#MGaPtfy0Rkr{5(2GQtUqR&z>%eQ*zv=M(O|Qzsm%l;cG=PG}3d1yc(%aFKAQrI@+7MMqwp+6+oHX@}79VktfN_ypa1SEZ3= z{uAv#8D7;RCpvt7I-*If@)`3ocHUJqblN-Z+!-G)z9)J+?R2ib^id~Y)nIT445oM9 z9(!inCk*dxJy00ne1|poIK^vf|8_nn=Q5ccoo^keR?s^o9Z-|8zgN*0v27mC&DqS} zIOcqx2GlIUgKK0&C2j9}Uw?hj;_&38Ug@V&Gop^X`Dv6)Dc-X$Olfx}`MzpQ1IJ~T zO6dOsv5%_@*>gIJQJ0c%?;V;le;s4zzyD)gceDRu@#z|YfTRc*_ndO{c^zlOl^((X zE*nQ3)}8_vuBY{4@rp3@vFtpyJ%eSAxfjzzQ%RQA-Xd#vDKl}Yfm3tFr0>+@5fg_* zpM^;;?+2V6ACNlV;_jN=1p${W&Y{893C&j6guy@ag#Yy2_`icAIdJ~oHZ?o&v`EqY zZj=eGWp`?MSxyvr(9E5w5l`-xB|a81F$KJ$=7$LZ3VIEI)Y|10{~ne8KI8=VK|1K2 zG1s+Qv&p{wBmyC?y-;rqnlqUNl-4M2k+kvCGAiz*2mUW6R6%6j z4`bINZ$Hta$Z+4=t+Yinj+aZ;H;FfJNZNCEX^Al)S5q^g170%nt#n+_vFZ<3d-YKo zP>`rOzD$@GSa|gcl9^1Adz}UC93AIs8j)Ec;wTo>HNPNBsw(A6mD+c|3yXQkg_grsEe{hxz(zcVUU?9 z=`Hg0tHnKzjp#;eVhTD!1<4z7_rF}r$tH{GBbNcZvtFmzPpALbQL8#O1~*koX{UFDkW;W(iAk| z%AG{>`~~f2W-{#!L5iASvknzblu>-2Ks=io#;&HNS#ks$dha!a0Q59U#mJhW8TjW- zM%627O9fo2X+aobah05+&Hcipd}x>#3KVFx7yN!+;4K||B>rWS@+qB*qe<}`?w!n4 zMvGUB5*x(mzp%DU>uEt2rJiF(dE*{xs))ZC$~-Fzd(helaT&_9SA98n4>CXjr0$!5v(G>RJ4|Spa4M)XZ#Y#muA&x}4QHB?On+?4$n`q_B2%oNuu9m{R+t{f5m zL8V;<8K5a41Di_HEi_>lCBs3s6z6}io!^*zTDE@eDh6SO$M9^tf|+_savV|5njG!? z@5fj8Yo_?L{5(T7orAjy20m{t{5&!(wqG?UT3FGjCrbnhoM%I5HZ-CW?4)8#5X8d8 z4Nc_b)`zaMET{U|CC!pEpADHo^bU5o;0YXj90&*u=ZCUu_H;RMwO!ro&i;sjQM+db30%cq&Xtc2lMvgw4Q@4AD^_C$UR`Tuu_)Yogy zn&PKq;%0yyD1XxX8jhg#Oc{`)a_GPM-}o0UozjJ?h5F_Xj-vT$#3uZApa;UdnLz;v z@7mP7o#8$7vQe^32Kw)@$)>sv>(L8WPMa;1LZL|jszKTD%hQrWS1Qe_touqgLsT(2 z48BYaPc%ulmjD>*1K!^J_v~$z?wCTX+5I!n#aVfDcFOj=g9}ZVvsQw2<><=jaHHhT zJ6zit7!W!05Yt6;DZl`-u|AHiWFR7QIsa=iWd2OV!k+kx*H`nZzccS2j|_gTPI2y! z5>n~6b3yh`kkk*nokNvQuN!Y}ZaL+5u~$QluZe8>_FpvgO6op^OL*My_>Ub1$Oju5 zi`w|zyT5VfBiuhX3T)S>>`x@1c+pqyd}arUa;uy9TK_63)GA});ux}iS0E`UQs;38 z;|Eu#x3#7eOEy3`7%c@I=w+DkqmiIyFmLqol6D|2hmsFB5J97judiL_^utF=No0g+ zOHfm4IetIjjJSNSS_e;Gq~Q3t^4?%uFSnIPhRvjvXeQe6wp+|*nA{>YeJu5s(4rn` z%?>Alel2Tv=N_)whoOGb742t}uW>pAT;G6ITpfFUn0%qg?&7 z7YCwnr&#;i0?)kefoK6^aXw_CS*5tMb8xAhSh!Z8G`Q9~I+Sqp;2!%$D(!)XGh;k; z78^;-a}aKo_=x)eN=q-Pcz&%-;r*m2RHvd?qmC>=o4D_BN7!f@Uw*;~!RC%+V0o^O zyr;w`a}Cs$@DSo&YmnP%tM2*1zW`lHqxiJkcSTrT^x#v>6s_%A*YISto{99VY~TCO zOtAzRp^pZtM&r7!m`NGQ?=%^yiyd6(qq#&M+yZ33%bO7d*)b{1XHs# zE=e5$2vrXT%}`Es!!uxP;EWvaTlgh*%sutH5eL*vA;7{J5Zphzd=;jAKt)a}MH%N( z3+fciUsCA`{q7TTjX-41y!*8nwN`cx$ilS8dvD$~1JsJ@76b|C>Bvi?-o#ax7D`rx zviTv5;TtSMn_o%q@sAGwao^~p%?hVlZC>Ph&tVh>btf2+x<&3!O0lOjb5m7eoNfdx&JthAt=&={*S= zo$}TA>$LeG6`Dv=9RpKneEAyL0$O&kR^2Y}hB@8%yu*yjXs*xKHU`NLnS-b z_LBDeu!!-t-TC5vrkX?P94@3#oOQJH5f~vOe*<1$xnx=ZBx!4#Q+Ic8(_1j87aMyk zTq($|%@^Ov2uku;$=74tCUQtA{l^L;N%{Eh)o5z{lMRHZELYNphha8bo9#bD3&PHy z@A}IN3wVr7583?pafy8HSr#9s8Sa^`kvgt|+;I+TkeUjCtDyh&AC+u0el+6!Dee5v z)0;=GH!Ow?M0x@e9~@%;zsxI5JK#wO->b*FcY{=oLm=(MdWiz^ZOV4X!9K%W zWHSU|&l(1T|A%1S7mc8N!j>F>7#z}yy$zCr43;-<39AZ@I-k|h)-9MsnskW@$T!sC z0mkyzark`-4GFe!eSPn7e}F{*Kw5}{86k?V9Awrm4L&>O9^ej3bjIAeNcGP zuNlO|Lpxa_lVvh}`t#AN>wiQq!eCj)*Wa-gjZ1&Zyh*BaWev3P6vI&*+NgGp&{Q&E z@8&~rc4OQ-hRgKQl$s;e%M4E>(dH*Phx*t=4pL?O+s6D~m;}CW*f%&?zzhI+7|t<- zsZ!2KhA=n3RR4!jqS8pX0fpQWDl61k7jcE0q7s6wdHCeHG|QhvBdNgM>BJ0T8|uyY zVC40cD9{p4&Fq}Hz9k#Aq1->1kuK15@xU;s%vu=(kKgTQ(q=wkFoYbNqixsCxPVz@ z3#v-fAU|a+V&FO{22AQ6o9hj3kr_m0*Pn$CtTbtE%MzS&ZCkAB_M>Fa=dt#7lyr~|Zh;o*6Z#6REO9q;5Hkmx$`ail2 zpsYW=E=S+!ZYM4BzCB(Mkwk<1@9zBjsLo%K%TB}#$?rzJ%Kv_TG`@F*F)&2>EkczH zhXnj%lbb?nb21=dh=BFq&fERm8Z7eJ{C$GlLXP|j?2W&vn#CZ1^wgDk>^WCm|F1vH zmCyKpJ@TNeTICWPf`hH8RrV8&NZGXE=hI{Qy<KtpL(q0 z)#d(9dr&1jP)m0cTo9vStI$NS;1Fef&v%WpV7&vxzj5WO8-3Om9Ex9ghDw1AwUnf} zLqwzJk?*x|I$!%JL|ulp_b@B)7TJ0XK7A36fHuMAzvcpV6|6*$E7{D@d#ju{fQ0ms z2J9KwvO`KrhmZnE<`vUG+ZKt{ZyTajMH-6s?*a#Lu-k*S%J6F`dRKzCQc)FeH)kSv1sq568hmf zK1|m?{DOh7g803fr98*KN6hsx!joXBKgn4=`;cOM{2s5cr~KRJ@@@t0R~>%gc>rIxnW02iaCdSBH1@bbDg%z+k#g6ASIg3t%}h3!pa{hP{3gq zHI3+U7A|r4g~kKUv?#)PmQWTiZ;A~0dURiI2#{hBjVuB^=Hb>o@3aw$S8UBKww|~z znxd*Kd91L3B|pVdV)PbO#@Ryss{zefErdcI%^qkZP3zM$f4QKWY;mYo*T((COCE+S zlSTV00SnJJ4ErCaAZCsU(-|{dpyc3Ib|B^PiO8(%LZFmjf|UkpN7Wvd`oEO}%aJkU zdcT@H*oed_#f9SP(*M|~w**Avus}d)?{@L5@y)q<#L0G#dB5Z4oxIPe@yq5>0}DP< zweMZ^=d~rUlt0ezNb735Z!=SgZkPLSIhZ7k4+!wmnt1>kisk1IbI|dtelA*lb zn`2~;m+a164-_TcTp$E-K zE1=Kzpi>J7)PYz6<$@gyFE8&8MZcJHFoLAfVs||B ztu>v8aHp-8(C5}CxNdG+qfOi@Ny#YK=Et3lS2we(v%5Lm2=FjG-pq-V z;K(x#lcXtXf5rp-xd(@orRRrnEEkiy-f!*mIztS~*FJxfI*A@Llr}TJ_u*$=vK3;@ z7ED-a=tanE<}@{Rdrk@Vm-TU$lkD1m{(?Q%-}t?J&iZXFyCnWeea!jrbqKvf1Q?cJ z=HrR3!nJ%AZx^pzTfx>Q38zH6*TY$LVsS0?R<#$9yK z4&B}0#te*a*+1pN%-<9xT_~16;4D*V=WA!rv_p##pI{eSu=(=CV|?Y8uyll>1#fze zpHmLd9{=)#ie*S;1n!aH(0Pl~noH2)nj!aXMJ5$ZB}1*+JkG)3_w%!%cvrKMeap7O z*6GM1oCE2z2hWKLX3kd8ANJ|N?VJjIz*)VKafdvr7-E(|Rb4&TC1iP)T&aUcE4syd zb9#@lY5>W&J@x#@&AhuCUc@c+kLps3+=-e^160>56w-~`KiNR0h|9;1yEkdRpK{~= zZG(pYcV1AB>)#-?``=kYEI@WiYr}!1Oa2NvjK735iP)%5YTzkcBVshSm{k*rfG@WA znCW5(;Ipqz=?Tz1J@0x?m?WCZfgbQFRSLnO^sc;@EE|p_U9UxQR)cghp*yAzhme3Q zW6vQFuo ze=rY2#wVDMsA8>ctms_R?7y%sn$NX(FDB~X0!3fV0(ZL@7f zS)3$?ZJE+&$bR7yI4S|s!dYe-sui=+TyWCi3FSm(Qz{rgYF=oC2aM5oK42=5|~k7t4^3mB-Rd5?%q1dDXKt!>t2 z#HcXi&}$I_&0>UWWr?-tlce1?MA6b)glLx|4ufpw26v;NZK?17N{ygACZ1SRt}KCO z)(360T7*n9h(wVdeIaC0l{s7s?BJg)^m7DbZ8u0%VM;SruCi3Zo@d+wPpf^Sur}5u zy}F>F9`p6BV{~5+J;WY2%ZkVJR*umlP09aObG_SQf*9FcGELf{TY9aC#`S%gX>JsHa z-nwlrw81vx4mBLcxXbfswV8pI{c)ypZIN_Ige zG&8Bm?VE+tgCqXaj-QlNZqSD{0B;>~-;c1&QKDP&1^PNUMm#dAzG-j#HPv!Ul=KUoqLo$e%3Q-`jC4e?b2{)vpex!M`QNg(yN%FkAW@ZQ z(+-b`3=a%bc69=tI2os}mzQ-5sfYA&5$9b?F`QM7_|d3$uAor9?cy=!uI}@L zwL*NFh0?Cl>s%F%s{qwT&7k%V-UE&vtu+^eTIu>@b%jCv4^%R*~{tgXXeQ8glfBwG@8swG-7{I@swC9JvK@ zc0Aa|-u7F9e4)7`V&Tg1a?`M=9{SF8$FeYC}$;oLZqg@t}E$ye|yFWIF{qyQJZp4;ba!!&+bLpx2wYY z(~N^Uy^VQ0$!IHwl4 z@8TR>&~B_shU`ElARw??}vP(R;!2eQ)d% zl*}D#OB%eO-!sHt_E!d4#jtXk`480QyN7Fhfbpi{&}N6|W;Sr!rHyJXYshV_;~p+a zy7JjQ_8*O?mO){5KjcOJsEw>YP3L%ZtGnj&6c+8z2eG)5r2od#xM#=0cVX*yfA=O> zrd6Owt8_~k=}VjW1WH`6;w1!YTxm|C-27x4Q*J^OC*qC z?@b7JEQXb|GK@)h#x9i2A>xISVDE~{z>&CufjHYc8TAXPQeWsC+;>^(w>fA9wHe3~ zA2KXsV-X$C=zJ@ylJdG{Og?-C9JwP#nfVEhkK$SbJNw0hp4ydteg)l^Rw0w<`&`r% zdVUesjm4G{@4~s;pQ`AZpEoVE^d;C8(ue3sV{mZ2jCxQ4R}6A05lzi@UO1^jYfx$25&i~c><7xUt z74Xc>oIw0;2dyhupjV(~Zx>yOB8vXOr#jlMIh}i^off<|_e=i2=*2y?rT;IzNE+Ib z_ir!2|Dhdq{3ZWS?f426D}k`uJ!313GhyMy6H3e{-{78(WbS^RUHG%1S4-DCk1DF8 zwOn{EBRi+$B62M|+qZ}Oq}`LYiZRhT9pTnw(ydXfW6M(sV|R9*-6Q?g1sa4nz^a+u zIy|$oB%>ey1(+ao@G1Pm+S>4IRj8!qMMHs5W`a-c<5Uphg8r}kHAbLsioB#y)YH#z zd#$V9y85?c&T|teME^j#|4Bf;QW;>wSfQ%yq5?6xyOCkFtM}J^h>AZI=q)ogF8n@M@2~kV#Y*-eGz>O;u~i+%hrP_Q zcBlhU9Ei=G7EL>H-eHuz=T8b@=hxHC!|BM>ZfuPJv9xzxdObA9feWM(V@*sef32+? znzYn|;6F!#_l#rxCZXHIVp$UBnw<9;-=D+l1#Pm-0ove_K`r0xUL8RNkzO0sw`qDbdIFGMH|M9F~kTpK+k^RQob!t7YK{K1{8-E!& zafowJQpYP(`+CjFo_SEn%`pV7OG`lFB3FN?@hl}|NC3SuBpvtymJ zg=_)B!6it!jL~mKAhfbQQn6udBcl3ZY*8fl*zBC}^Qik8cgR&!#fLP`jweQRUjqGW zQUNTU#h!e-EWCNUnsmBzd$z$6RNMwz!)1rsF4YI27 zyj1x(mFHt_2L$+(yA6$JSRm_>)z;C~BHV&7m|B(dp|mjI?Q={1Lm7Af3Ss}}@C*(h zz*juo1(>k5nDV+*zz)>oGl#$#81=}y-p}udgEs`phnhzq`L#5OZLV6}TX6ErTa(g_ z(e7QV5fr{Y2oB?cXj97;_xFlv0Qld7Z=fuWZ zXx(4?nsKCW;!V^A6lqn2vt&sF)wT9Fr8{EQqw~sJ0cyKttj*yvoKHsBHv#QeFJGpy zHVI|e>bO-EgOHglO@ZqNH_F;*zX}5qS8zk|?#@75rZnolu9Qk0J}pauA0^L_-bj%a z-Ewrn`NH_A%yyYYdYS<(0=t;8)ccck3NG4&Z5on90gdc+o;a8!e87gbZ)=YbO_&Xc z%q@h97pN6!_}#9djJKKfkfwwyG45FME)hwvNtU3gz(#y}(#`^^sm5H*& zgNCeS<*NdixiYx_r1!ciWnk#}#bmB8De-0=2;P-rl*h#Avq<$CYbcB;|6baH3d%Mv z+{TRRdpY6w@!V_?Dn^PrFq5aopjr$F3qjFqnKI-zFeEV!KodE|1 zV}8EOez{=K>3eShk}!ohx6N39LLhU_vOY%LYsc zX4yI&k~|Gx|0X(ApwcDH9Iodo6U&n=L;vMLs9Y>0+d^Yuh;=h*O4ZL_urcl`ZuPmz z?%cCTlL5~OvJu$$hvdFq^ErXPTDXOu`#s5#3Z;0JqDR5KUav7_XwfDe678;R60XFO zD>8Ivun~MUd34I?yP-AvnRNa->OPn*cf{X>nluvvfrSJI6}m0+(UuufGkn`z%V z+h=ml#VmTiGwv3(zYk#6iOuB}3a0cUo|H=xcZ{%3Vgph1^1!BZc|de3!mf&fhGpgd zS950>6j!6AYb<#11b3GJN#pL`cyM=jcPF@euwcP0NTb1nySux)-{w2txieE|rtaMN zaqIGDS2bO`tEKi{YrW6=E?ET|9uE+|k1K)x9L1)>kr|ZmY#3!cj0=3O+zZl2iKgu@ zYk?PWt z5LOMX)vBETQQ-DBsh9`18B6+Jp{Tsh_Cxt2z90+<@oNFX@Wxp8=N+aO|6oOkJpvq} zj!!&m2SapwY@yWAalf`rvSxNqKeJ{p#>v(yl(v&@7`emP_)t{h;2 zaJw_KeQn?huP|eMs`#^vFa%y+-{@NM$%U@(Gs3jM?vUBa({}+J5nAg~L7aPzkAQ3H1Bb^Oh`-y1j>8 zOvvY9)mOa7^zz+#pYD?{eB4^->l5b8%a!Gelj(=KHXsX{+tWUKJEiI*$3?H}-AtOH zR%7i{vUL`E&OTlg$=qceu3SRh!PEX`sd5HnoJe|w5eyI-DzGC^7>jsiZAJ@4UyRek zE5QGRg5A{7bF?-J9ZZzDp!Km-Sx3AChVCIy)~N4n^x(VcRv}WLDZimM<%YdA-#Iy@ z*iOz!RC}VS?Vq4jZI|*UVx3S4_4C_9?+a$|MmsC*JTDl@i)1I&(sq4nyXOtn8BE5N zmI=N|RcN=4cuW`NS;k@-3J)=rDXctRA7@x8tAAqMA89I! z;pvYRkaE&?_Gp#D&~7z)A0x*kr)VzK1cwUvGB>(m0m%e|cBd2F-~YABAd;B4h&_XZ zKO?V&ZPe8A5<+bpt4NMuCAmiIbd4lx3EE~!mtxFHtS<(zl(Bx%YJ8-Y-WEA{H1&SR z@#~RVGN4FIa+KEyq`0=Q9Wgh~U^+^;F_R>{b#QE5uJU%#YC^+VY*K_d>pjB(S)}zC zWKBMIwYVN0?Cc&B^`WyIxcQH)b)e7i{P{2lPT0vJN%RxuA|$=ldoP1O8&sF{K{lqS z8u=$Xg<}1Su#{0_?M|D^DcP&_NblHtG8AP*_bQKSAkDiY4z@%GQ)6YREiq|7erM zaj4dmZql7Vai&=%>Kf~lF{)JtxU$6j-L0kBRT}220{XbHTeC3EUJ&70vvoRDbq^szDpB$)cTXE4^3!n3pJc92G1 zA-!BWhTLP4mHs2<+ozvixjeK?Ss{m9%Hf=J&cp~<7w!Qkd<@Vnu;2ncs}GfOif(K0 zeG`GFt)k}uVZzT+1&y*F`&8+%Sc62`Z`2I~+`i`)(ue#Y4fCW@)r`AqJ-PT8`pGsL z@HkR#I&t0PlZI3nT8<@N`j`tck@uB*kL{^dR8>=_E&m;6WhU>)>eC%T^bP>v?yu|X zhR%crp9}D~u||=x%4}%y^3{c=QF`9=I@Qz#FSt&`Sazs>ny%M=yn*P`Z0vnK_tmx3 zT*x50tU#nI)oLZw|7rWpUzo9Gzna4{o4d9&$PWz`u21eu)v+|)r}jv7Hc#sh4i1+- z&~{u+9QIcvu%wDoEM1+kE0~k>g78a5>_xIg^@x*Vb)U%3O1GUYYEqoU6Q!mp4W~gZ zpZO#J1Smv&o&G3r{P1XIB4i)ALvMMDgE#ks{LBs@ibjptF0t53U@CV+J{x0KKaRGY zi!bRE+W4*yQuh>iDv7~ozKq*9g*HT2R$#k)chek5M7rN?dl`MJtCd*0V(%@&h~8Kr zls-{Rs6pm$^C;}5C-Zm0CqcHX6%Ltjz~7@x5cPX3*)r449@2vh;H ze9sUZVlHq5INss=utdIwO0QnU0`Ey?U7BG7J2xELea6{BO-Ox)< zsTl(B)%O_jii$d!yPZ+{MX<6$lb>1MkG{q~mA?u}AQ(J$TH%-5F9!Z&4sm3Qmo75k zx38({7V9aa-hvLYl1__u3NfJ-uUkg#GyECNyPa0CtJ-f3gJB9MR`ouiLMyW zBsw@)xNjPG@PX9;+w+k_ zOtlQx`uu%3j&Yj8af>AMU(vHcA%%zKzK3jZ51v)7NzZ~~-M_R62IqKO60Xj@zx8T6 zS=&a8B2fw>_Fxbev-DOJaikybPTdI-C_&Sjv*86fY}S38p-rMpvw~|fo9+xnB{pv4 zuI9Ce;_r4K!%25L@#^6Uz3*MrHD$g$vPt(w$MpnD8PmPeA#K)$5jMDOdshwpB1)!#sAMVozn-;ShKqPy*Z zlGPJ0;eHqH|2kf2n;)b3_bQt$zu_j{e@kUszW!TfYc*cM&Ibb(rgV?*`P9CzFYO<80A0Mx7|NyTZ!!AMQ!6Rsh2>J-d6YwtTn7`oW7p( z*Xfk#N6GQG^zH;9LG7Hb6mq`2f7#C#hsc&De)^6y`L05{z29}!E#Z~LD_(4}NaMPJ zaJJ@)YfNYH=~=?-oty-&-R&gm-Eti$N{-iN_4`i7Zrkvy3)k;T?E7io$4Ul1pYk%c zgfa$3X0ILQ=lQQD$q^aD`E?HHpS^-=ck4AE1}rbJ4l&?UL7p*T!sIP8-e?FgbzhWF zU39J%CWM>%VBMati74bX($^PSd%Rg*EGZNbBC7^8+JH=;oc_)ys6H{&3yqQ#6SN7l zU*N>K&=g%0#_Wx=YNbE&WI+_|ED;UXb_IlC7>>Z?or@Utwc~w@0s>=B2{x78P7UMB z-K1;E85Dx`tu(+C9-q%}*D9cjZEO9BM?4he(xV*)x5nx9qiag|&{Fegb+w?*ATk+@ z@+T00UG|z^uetNyomA*&Y~luGLBAG-yC)KEqN;i1B?4HAi!B* zX+12$I|1t&~myisMGZ&aCVKG(kEKVqTA zemd4x^*%dfomB@$vdFeRGm@ui178)tI6m{R&k(NMFVI>Ux=srD-}>H=1`GViKMhT$M!Y8FDSfUfHL=Ym+l0lDAW3l`o zr6WORlAx)%c>X1#JAq=8G2PFCv;i~%_iIK-qCiQ60UGzAjPcVXJZbt6MjTOT@IaO& z=fy%p>R!a@{e4$4l2(@W#ZE>gdV}k9ZQz$({ySoZM3WLH89r@|r(%4Q_1(~2liT(U4 z<*ED7G~8XRG}oifxZ>VO9V17^l4&+ophIhoWd+6lQFMm4#iVM}L#SP_9DR+0YTDtQ z`CK=HV6|eGeO{1rOyN|R=qI`YDa)nsLQH$|)TWTtpPTO2g#MyUr_7kpj44c7g;Q=T zWD0A&25K4txoXSkiTj1Y`1WJ5Zqsxjn;0|n+%wpMW{u-C$rb*79(4h;b83$Io2L}Q z#Fb5#wlpk+v(BHL{8xV}UDwap+i`Q@65@6j3~UY4BC<{wT$G?U2~I`jAel{BP94OA zBq03=gK1M0d&B1rbetW5xN|>`5dMQ)+f{`;*x}3oL+U)bXwM+j6(&*z%p9{-EcWp9 zuw+@Lz>CVU45*sVQFgy+VpWtv7T)Z*x=Oe#1Lv>aVB7H+m~%zH5p>hOH{TMja3Fod3l%B9!^g4`Zt!K zl6FqgOGuK3##X00I**V=Pq*9Dh9uyMWQp`ob_$rrg_Hu;4NWCkKQ^*lR}Bx&v=Z#E z1R9lbT_Q$G+6Q!TDluw%0ew_ig6)qs0y^i+~@&+7A9Fg~#+A zoG4qM9rT-Jq1k<}=8IyTmg1jlYi;z}~}@Cbk%Gs?_hM9+8?HV;8(^k!neF=H@&7Am{H z6OXu(aST~^L?tPGeQZ97qP)IYG8oz)cTdE%$y`G7R+w^PfACYvyZWv!Gp(4{gk}%#&gJH4wfLLJdi2)yF#uIIs z0hUsN4btR=Slhded=Q51I5LO$&Zpwk2-eF1?uRowM0AVO7lUQW5BnojYK+CfZe zMUrCVBFGulm_@kAIdR#h=Jp7>5f=-ZtGzeL@GMB&802IFZ;1v5Cgr@EO$W(9kp!Ny zlV#=+AmQ5Gy5Jf9Uk(}fosX{A7ZUno++N>0Mrf`*pt~G?ZtsBHeb>{PbJArKMW%YA z#L=2$za;gdQVQmY<^J+c+w?Q2mZJOEqxY`PJLN|U-Wzim24)T|XALLO7-U!1UnXXv ztJ1Paza$5OnZw+^;Y0R*Pd*nGu!9#{$geQ1v3{+$Ku(>pApnux*)L4^x!ge+i5aC%lA*+Vl6zqken|6U(DgM_jA7RS?Rm*0t`X?e=vth z1^Y(Uu9vIXBP+uH2x_vY4uEL0Hw*ZtA74*y{hnjUEq(li2Al8cooeAM^D=UgY?MA; zz`}#D&&%pdl9@;1>sgHL<)ZJSstG+ttOP#=b8TN$|1!($|7Dhm-#ehRbo26XkC#%K z;B`xl>+t!gisXjhO!@f#>HI;@kl&cr_>f;<01b3_ADcTm(IuJ=R=Kkt0TBc-Vq@#U zvv(QSTw?WsBQo(`#X|1Zab9DHG7R(qRCsRJ5Q8ka>bV$mBIH~=dE9L6b}6sbb}1sG zq_Wp|-`iRGvw%kI5)l623;K3a?s^kSl0mf8vN%+*S5{6l>L5fVBnfTV?zu2R9pb%1 zAmi?5!)h07H*j!e)P%tYAp3YwzS_-RxG1_GxUO6!*ZoOCIVA<|pBK6-;XLCLJttl^ z{?e(HLRbQ3hQZ;s@MEm+fo9yWF?JUv72RkPIf zD3c)!=8tzIx(gLPIo#e*MBHmw4xN0nU zCa*rFcv1IGv1U{wP~d;oIMYA`n`G8`Jh~zd56hho-qQ-8of7PvzN|k+$}MknY84#s zdgutE`Jv%7p&TLC8;$9`ykK443hq%shf?7X66swJU`a@J(c2x@4l3*DDMjdONVJ!L z!KeXxkpUIgQz}xlBjhi?tUE%{s=fl;Ee0fTnY|AYQ5|AvBiPAOtZ66XM#dPnf3oR% z(Y|?VMxA)urEJJ!Ik=evtW%wOFbIwhdd8e|i1CD_`h)94TXI@$<=6qgn@@d01GVj8 z;zLw(*H6n3g7g#Q@wyGrS%638?(T7&P2&Bte<%!_`OvQjcskcR7?FV_U49;UpmT(& z!>>YCiiG9opF<`)&J!^6m&^a*su3YWXF2D*D3~`=WZV`CqrPec>w>2L8Bv)j8arSD zmd*F6{&ZWHtoZcyveKkLE2dEtQh}YPs~ugD*9DM2XL*^mzwE=Lqc!$Jf9K#6n_5DA zmyZlz5N((NPr9%`So$x`-eph2HB=&)2DEQZwR{9wZbN-V-_2Nk?H6;Z7*}iS$Sf#V zr@9`XQ@WjTI}Ck|t9(Zqe6RU*^n7`g$$kM9(&qJAw^0S|wxrTtlj! zq2}5kqn8y5u%Sjn&qO~eFf@9coemwot-&P3U z_)KN+n~{%6dY+;1_eUw+(nAU}X4ZK+XuNF#K!kaSSnoc*IblL}2Gy>068FD$KL3>1 z4_3bJ?H^OV1>!pV6^JY0Jh9tb&60^GnX9l1ejAV5PtnyFn*Z#4O8-do4_#j_skyrC zS{7ABY1=!=uRUjbOOVFy6$*cu_cuHU5=`jyh_)~^&D3rnGn$k{)?S;XE89X05~9u= z87nJOx^QuEHFHUvU45WO>2}>_FLOM85@$$j^?IZ?^mI^S`gGRun60>+{54neEiOE} zUOl~abUFB1JX?Y7FbKPym#By5qim5?;E8co>J8mo@Ve)BxDwwb5n-kBi^%;-TD{8AQR5 zu9dn*1s5&NAvjLg&WbuZ`3uVa;Ch!SJ$?%Nl@C=$phRxDYT7o-<`zxcFTueLsh)RcX0m2cv9SyjkKt~tP}dY z_Qj-{D}h%gauLdWC!n_BdvwiCdCR6K1~A?q*!i{DzdrhJ)h>!!yzlRiqbY8bbk%Zj z8QXpG4wSENC=g~RcXD>caFl^+9~synD@Y$*I0CL@w1PM5Y}k4}5c^h*Ng6jxP-~^v zVGK%_PCcOk8}6{GqdnBu-zn;UszqMfQ~bl!GH=f1*%; zV-A@Awvtbk7!OQ8MAwL#!G;-ut>hLU5obd~@yW3G$mWa>{QuN(zx{h1_t;Yo;h)7a zD`L+Ve=BV{x_N(0NxcKuVk_!G)Eaf_6sD8q-F-)SuqJ{We+~^fQg7C9bgz6!T1gDl z(=4YEf#+EI;9w0Yb-Yyg)%E^>+jn@JF~y?X--K)K1(E+5Jg&DW50&6^ndA@va5|h= zxA~M|S88-sk-JGNJzWIG6z`*i#$*@LznN)5VzTl}aW_~PiQj2RUF=-kJ6gP(uJnqBDeL_**x~_ zFCTyxSuupbFC1gRXgTIo6`vaI_mz?d%P+=&gnAqD{CDq#^!3d7*ekV*x zx(fyKS71Tc+TF&D@~`%3GkhZH3a18I^U=5$EO&KXXWfsb|$6r730W=lk1|bU?}5HGMJIM|G`FYrzmutAn38 zL5M1m=bPY-eVALOj)}87_g2wsl%%xoN&-#XNqPY6w08AsMYL+&Yiw}1QK3qatPCEZ9N9P;gC|Zzvrft z%=Vyi{fkeJ4Sx;atmFvhMPu(F6A|bS2WnLh1z+wWxSSR};Up9GeLfiCQKJ9{dkqjo z7)LpELb5?c$df_hhHz_28A%jt6;}EN<%WJuc6@iT+9)&W`#{179vc)*+G&SMeHJe` zA@>*JlN(zOHTIi@_zy6r;VIDKe*klq;0k!p>KwJ=W?aXQ$~V+*?kWlutgM{l>pKUp z`kYbgaC?4lzdz?B7&bMzfNFm^BU=G*e_++~Bq5E%2%76-9q^0rbwfS8o^?BH=Fcbp zQCn{pbG!P=i;8r71ONk7Oi^e@T0p(L$ORoXYu|Nggrick5AeB@{9LlPXEW#1*PYRr zw$f=1q_0b}ukK)+-o3TB z4Z}1p_zS}vp!y5Ltcp=tRwGqhz#`3AGK{_I@y6zlI$h?D zcsL)f))(88)H&i6C)(MobXnHlF4>s)xvoB=z%_5cQ@pPf>RQ#tgg^7%+uIYE{53p! zPzN<#*tPcuBBU_xh*!dv$H>_GF>tQ?)_KDo+k3HE$kpx8lYeJPjlBsBO>~vsKUxxk z2TSfhVjbqm(+ALEQq7tKxe^4C=%&~Q@3)zJx;*kaCM@FESD%Qe+lin8suVV2vWFU2eZjZPZQAmo>R7_vyJ7&u zpPc?c&&eqb(f1@Bk@gou>R^}k&kv2w7pe31_#bkPmwPV(li>WmjV09w4Q=ZGavJ_H z{45r{J&l-0Jz_5})$)WfYXh8&hDEbKn)_T=<|ia)%an_S)0y zIIMA)i@wzIj+DeHzL=%LPzXo<6EiuC_uV6YKxUpz}oz9#V*WnzwsA7iN~PS;SuRutuM=F*=we|HPd;TGWgq z4j!C1{Q#u4DWhq@Y?F{Qtv)9~AXOua=?~Yfww>&@3F4MV^QM7SD1`6rd zlly3WJ9`nnD+#`2>&~v}KTM*Ju@DRzIiD~pIa)G#3krc>)AAV?u?w8k_lVAPO zhdf7juU8(o^QsVmq=J4_A^{{{lj+bmCCK(A^jj$Em5Ln-F5W-kJ`L!0ef7aKwl5pY zHKSK1kd7nQFfy8epoI`d_MbOBS*o)=^^VqE>ac@A7GMDE#P6!I+MYONJD#)xmgTaK zaWf2lZ5aHbBDmVS>Kx^n^Mga;*g7E#LKE^5ggGV*xG`N07bh=O20s9Ae?+kcK9F`- zC-@1&lLn#n$wHxk4?+ao2;fxMzn_5Gk;6RoyuPEW#2RIYd#A-P@Ia>MR)A4|l*}09 z24e&2*w~=8c*$%=_TlTVQ9JiTF6w2`)nrI5OVi{&z%aFQ9^BYvC#cyNbltrw&5KM% z=5E#|axvANt^CZlQQKTA?IR&Glj@!Bd+S+Qb${8ub)Buv9e;yJ+O}u4Bb#Yd)hfgU zdi`3&#nzP&0bn-6Jc1EdY_8Edxc;JF>AL59XfJ^pdZ&!obq@+S^`dP5GzUQgI$J^* zwj4FS8%e1wGTiBpXt|iUOe9)|G%&hhsBC+ZGj|Jp$^bXh6OV_>^`nz`Ws7^4hA6V$Kf5HDa0@_h$I;5l z#xS!2q(CMdjyJR$P#Y&G^ov~-QpuVI9v3`0O>E`TUV(eQjo zo$8A)x{I2Q<&PFbBfYN4TNlt4mkp3HFRV&>kc+-rlW~8j_ zW@=D*6c859VeoERVW+Uq-ddDruexrzh2A$3ZKKwhlPF4za5jJg8NPF?zQf#@lSS;% zjV(wp+wQb!JGmrshW-)NM-2OF!8#uLbyKHUs#QZMEkJOLnk&^)YJTd#c_2$TuE)s} zG8nhs)XFJH5#(>l9SM|O-_ffHQYq?F&=LawFta<)hO7kl1%Ba+aO(fKf2d?RYt_g4 zf%QFOMoS~q$17-hky7UgOvKMCk&D=e>sCy(-}CX`oqOgl>?}nvozo{lW_I@8N<}IY zuJ|0jUumE3tpuKr>OM0DMjfj8L|L>7&NPjn`rIisN&0JMY|OSl9?CT0O6Jl$eoT2e z)jdC{16n8*-5nsAo>}H8OP?)W5-s4Q6F&ze9WxG;pAVnDNXyQAu-A~MOHq4WGkvOb zO{R&Gbv)mAH;{yv6h3;7gx$|7lA(I<)*7a5VfO;sHBaR2?GwLS>+>CXZTr>snv4%H zb=zKi4MIc!)fcHyYl;{MEUUj#14k-(`b8cw#8E%X3I^b zPOe5!esD*nvKeFRpr)^*xj=MVR=Reqr5$0@Si@^yCrVhgB zWwmp6XbOKm<~H~{{U{5}!%|C@?ostRb3LshL=Frem}A(@=0b1}S3${20xsWjw|x+usooa0faqZKHt#{yL!s+FU zM#{Y-wwj%$*Xg6}IPim<@3p4aaWImW_KK0|{_A-*-@`j3?6#gt-eUJ>-zU~Uf;nku z?W|POp`(kL41U8rOn~o=s{3&Pc*kHXrORx^S&^?t5_tRc{Rq441@`Kzqf5g2mWH9g zEt~u0HNUXCbK50;yL%sZz578Yl5(JN+iOtxA4 z{?iWjM+r^#dp-Ar&I``Vp<0F!xwDmP>!$?{YAU)itw+B)m2bKkTfw`d%xz5_H#vg^ zw?6*5nOi-Td_76GuhA+FzvO6duCA_#iOj<`kcxFG4dvBlmN!H6OB(0v)m8{!yc!Gl zO!!I(Lshoy^NdelD{$2)?#JH|h+ZCq2c zi2h7|Q*jJ6p>F&X?D+BMVtv~9K>@ZG?V9_Shxfwq&59lBmb*|xowQ?v=iU~*VF>N1 ztBVW#hUU0mFfEylms6$*fA3zTO0DD=s@W~n1y9lB!p_45V!!oiv1sZ?EOnt$P>)z` z1mq8&jHvP*pNt^1Y~J9)Ns9?wimpR(4w7(;P8uP6VT@1~*K`UHZec93NVkHBQ=d}c z=X4I_eYo`%R%v~w&XW;Fdm904WLQ%3bc|kF#BTwN!!D@SA+rs#>?Gkoo-MOJ_f!qN ztmTF(Fi4LdJDohYQEHY!^naueLfaVUm8e%!FL=8ne>0?p41K!+M`ywifDb_&E*N%i z_u-AKgKMtUhnWVD+j(#wowx~nc&I@$QN_CjKSqa(4YOo^wdjc5Ihx-&k{egVyuuO3 z9P(ILJ9ic;$x)}EC5=8qW-N6vm%d%Kim0_M(q|6t`g(%G&wPRl*673?jQj({UHO^M z1>KF#W29I;&vHD8!6hRm#|}s@`1C&WauBu zA4GTG$BWgyGSN(99E5p(JN#7jt`TNyvy=Wx)hmXRkp)gd4XDvp&RY4p`)7*47?Vhi z(KE+ww&-9n|K70v5)D8t7w61P@nGMs4ENeeymsHbmAP}4lu)U^sJTb;FjZSVUQ0u0 z5Z-!Q>D3Z!yCI{Mf01DPhI3wc2GD@?5p|Wp4TzH=gzx$Dct@UVg({lT*;DCvROL}IG+)d7{u%+9`4fOZP z6^-^+NK}b?XA^3I3OIDv5Eyl=D)e_O4seF9>dQxj8X=4u9AF0)&Yr?YjqCERJBe2 z_`)W-tf~jff2QJYmAlc;)^WpFINYjJ?`=)&ZdA_vUJ%2Mo0e5*xm5EuRmDa3*qjS!1mIR?e42_On z9+Xy2Sk$>~MzN1Qj1x&4P5g9|2=Be4nB4rDerO3320K{T&^lnV@r7G~96|WYHb8}G zQ?-O+%j%Rx5(!+-b>x#~aJ#xR<8BDXWbQC7GwX9SLk74cOkZ0cIef^3LEcC`E~iRU z(zmIp)}3{04H$=&HU)p2N7VGvd78UN@r%ZVy;3X<4RaPQI2q|p$MbV$t=RB5HC3Yr z13-h)NK}oJWr~^Ur+V^x6l=X22|DfKSXX8%@BYRlSu)EU4$k{U&ALq;#&L6~UQsRAx37hBKnE7Z~ zYIy{cp0VQ=i2N=6R0G8yH`$YP0Jb$$(J$lEK|7XxofIiSF2x2b7u z8`+!VD8k0``t_@`1BFX_%Shej>|ITZfM!>b#yc87OB|i0nyOc61y5hewB%&aM)WdGDAn}!0~GPkFqKtP^Ljm5KUN^icNeG zXI%&tQ0doaHDueJ+kz?Tj%bIpv`i|qy8b%BV_+sLEc3%zj`68zpM40xZQKk%Ak0f6 zr*t8-$-yR?j@F0Ho@^WYF+F4)%Tt*BarkRa;_zKJ1s%$t+Z%2df(#MM-#JO0^~efX z=Ty&sTi~j3B)dRW6Zfzj!9@$~(>eNnoupfZ!_JD>EFwcpds0gW^KnALz^5-V6J|Ws*Mc0_!RW5O3QbCjPpQ^>v2i?yn)*T@=3=CMwcrOq% zi$e312gWJj-eWdr({HL+p8h^jn$k*hS*Kxqt|I1izR@QtEv$Drd$WVE$bGuU7e$HtY6kN<#|0FF2G zAL;+~W928>P1oYVgsALyimoIoF7km6%Dl<<9aus75*mJnxEjsniz-mt=0dp)PFWbC z&=}V1^Wi>4!cNT68MG1;i7bQT?wuq9XFMqsc(FU_4|_Nz5`SufmQ}E=Nd^_;IgDbr zI6huAX(K{E%Vu=Xxz&?JlRb1m7&gyQQR8%nUWww!a0&EvES<#E^%S$XM0`R z5}Q$iJLC=qM#hVQK_;-?Gnz!Ndcqkh9N!QIN7la>9lGtN%p;1%_ac>*$L9JVxsmx{ zVV(a(hq$jJ{gpkjL^^18<+Ut>tUG07Y6^>~{priFNdocn9vIWb<(If%12x0jM}j{E zo)xJYL%^Q%pLPoOL!ey}LsBb85C;l3H@DZR=c?zC1Gs_ScvWh3IjptmjQiXw?REZW z9(3oBAer|c3e7pm-){pSa3$)<0mHncER7Fzi2-VdXetm|dn;xoQg2JTE3Tvz@B|*- z-SP@Sp+E|>ul6}Fk2c|g&(oIkAnCQbD*c<(Pyes;5MZZu{e8awqO$$B7ySDP%lr_$ Xdpn+0$$mo+;6F)GS&<4My@3A(N*B^T literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index 8532ea9..eb5c5d1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,15 +1,82 @@ # marshmallow-generic -Generic schema with full typing support and minimal boilerplate +**Generic schema with full typing support and minimal boilerplate** -## Usage +--- + +**Documentation**: daniil-berg.github.io/marshmallow-generic + +**Source Code**: github.com/daniil-berg/marshmallow-generic + +--- + +Extension for `marshmallow` to make deserialization to objects easier and improve type safety. + +The main `GenericSchema` class extends `marshmallow.Schema` making it **generic** in terms of the class that data should be deserialized to, when calling `load`/`loads`. + +With `GenericSchema` there is no need to explicitly write `post_load` hooks to initialize the object anymore. 🎉 + +If the "model" class is (for example) `User`, it just needs to be passed as the type argument, when subclassing `GenericSchema`. Depending on whether `many` is `True` or not, the output of the `load`/`loads` method will then be automatically inferred as either `User` or `list[User]` by any competent type checker. ✨ + +## Usage Example + +```python +from marshmallow import fields +from marshmallow_generic import GenericSchema + + +class User: + def __init__(self, name: str, email: str) -> None: + self.name = name + self.email = email + + def __repr__(self) -> str: + return "".format(self=self) ... +class UserSchema(GenericSchema[User]): + name = fields.Str() + email = fields.Email() + + +user_data = {"name": "Monty", "email": "monty@python.org"} +schema = UserSchema() +single_user = schema.load(user_data) +print(single_user) # + +json_data = '''[ + {"name": "Monty", "email": "monty@python.org"}, + {"name": "Ronnie", "email": "ronnie@stones.com"} +]''' +multiple_users = schema.loads(json_data, many=True) +print(multiple_users) # [, ] +``` + +Adding `reveal_type(single_user)` and `reveal_type(multiple_users)` at the bottom and running that code through `mypy` would yield the following output: + +``` +# note: Revealed type is "User" +# note: Revealed type is "builtins.list[User]" +``` + +With the regular `marshmallow.Schema`, the output of `mypy` would instead be this: + +``` +# note: Revealed type is "Any" +# note: Revealed type is "Any" +``` + +This also means your IDE will be able to infer the types and thus provide useful auto-suggestions for the loaded objects. 👨‍💻 + +Here is PyCharm with the example from above: + +![Image title](http://daniil-berg.github.io/marshmallow-generic/img/ide_suggestion_user.png) + ## Installation `pip install marshmallow-generic` ## Dependencies -Python Version ..., OS ... +Python Version `3.9+` and `marshmallow` (duh) diff --git a/mkdocs.yaml b/mkdocs.yaml index 5a41e3d..2b927c5 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -26,13 +26,28 @@ extra_css: plugins: - search - - mkdocstrings + - mkdocstrings: + handlers: + python: + options: + show_source: false + show_root_toc_entry: false + import: + - https://marshmallow.readthedocs.io/en/stable/objects.inv markdown_extensions: - admonition - codehilite - extra - pymdownx.superfences + - toc: + permalink: true + +watch: + - src nav: - Home: index.md + - 'API Reference': + - api_reference/schema.md + - api_reference/decorators.md diff --git a/pyproject.toml b/pyproject.toml index 9086c39..5182983 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,6 +120,7 @@ ignore = [ "D203", # 1 blank line required before class docstring -> D211 is better "D212", # Multi-line docstring summary should start at the first line -> ugly, D212 is better "D401", # First line of docstring should be in imperative mood -> no, it shouldn't + "D407", # Missing dashed underline after section -> different docstring style ] [tool.ruff.per-file-ignores] diff --git a/src/marshmallow_generic/decorators.py b/src/marshmallow_generic/decorators.py index 9d672a5..93f50b3 100644 --- a/src/marshmallow_generic/decorators.py +++ b/src/marshmallow_generic/decorators.py @@ -1,4 +1,8 @@ -"""Typed overloads for some of the `marshmallow.decorators` module.""" +""" +Typed overloads for the [`marshmallow.decorators`][marshmallow.decorators] module. + +Implements decorators as generic in terms of the decorated method types. +""" from collections.abc import Callable from typing import Any, Optional, TypeVar, overload @@ -34,9 +38,31 @@ def post_load( pass_original: bool = False, ) -> Callable[..., Any]: """ - Typed overload of the original `marshmallow.post_load` decorator function. + Register a method to invoke after deserializing an object. + Typed overload of the original [`marshmallow.post_load`] + [marshmallow.post_load] decorator function. Generic to ensure that the decorated function retains its type. Runtime behavior is unchanged. + + Receives the deserialized data and returns the processed data. + By default it receives a single object at a time, transparently handling + the `many` argument passed to the [`Schema.load`][marshmallow.Schema.load] + call. + + Args: + fn (Optional[Callable[P, R]]): + The function to decorate or `None`; if a function is supplied, + a decorated version of it is returned; if `None` the decorator + is returned with its other arguments already bound. + pass_many: + If `True`, the raw data (which may be a collection) is passed + pass_original: + If `True`, the original data (before deserializing) will be passed + as an additional argument to the method + + Returns: + (Callable[P, R]): if `fn` is passed a function + (Callable[[Callable[P, R]], Callable[P, R]]): if `fn` is `None` """ return _post_load(fn, pass_many=pass_many, pass_original=pass_original) diff --git a/src/marshmallow_generic/schema.py b/src/marshmallow_generic/schema.py index 797faac..8e68ecd 100644 --- a/src/marshmallow_generic/schema.py +++ b/src/marshmallow_generic/schema.py @@ -1,4 +1,9 @@ -"""Definition of the `GenericSchema` base class.""" +""" +Definition of the `GenericSchema` base class. + +For details about the inherited methods and attributes, see the official +documentation of [`marshmallow.Schema`][marshmallow.Schema]. +""" from collections.abc import Iterable, Mapping, Sequence from typing import TYPE_CHECKING, Any, Literal, Optional, TypeVar, Union, overload @@ -8,23 +13,58 @@ from marshmallow import Schema from ._util import GenericInsightMixin from .decorators import post_load -_T = TypeVar("_T") +Model = TypeVar("Model") -class GenericSchema(GenericInsightMixin[_T], Schema): +class GenericSchema(GenericInsightMixin[Model], Schema): """ - Schema parameterized by the class it deserializes data to. + Generic schema parameterized by a **`Model`** class. + + Data will always be deserialized to instances of that **`Model`** class. + + !!! note + The **`Model`** referred to throughout the documentation is a + **type variable**, not any concrete class. For more information about + type variables, see the "Generics" section in + [PEP 484](https://peps.python.org/pep-0484/#generics). Registers a `post_load` hook to pass validated data to the constructor - of the specified class. + of the specified **`Model`**. - Requires a specific (non-generic) class to be passed as the type argument - for deserialization to work properly. + Requires a specific (non-generic) class to be passed as the **`Model`** + type argument for deserialization to work properly: + + ```python + class Foo: # Model + ... + + class FooSchema(GenericSchema[Foo]): + ... + ``` """ @post_load - def instantiate(self, data: dict[str, Any], **_kwargs: Any) -> _T: - """Unpacks `data` into the constructor of the specified type.""" + def instantiate(self, data: dict[str, Any], **_kwargs: Any) -> Model: + """ + Unpacks `data` into the constructor of the specified **`Model`**. + + Registered as a [`@post_load`] + [marshmallow_generic.decorators.post_load] hook for the schema. + + !!! warning + You should probably **not** use this method directly; + no parsing, transformation or validation of any kind is done + in this method. The `data` passed to the **`Model`** constructor + "as is". + + Args: + data: + The validated data after deserialization; will be unpacked + into the constructor of the specified **`Model`** class. + + Returns: + Instance of the schema's **`Model`** initialized with `**data` + """ return self._get_type_arg()(**data) if TYPE_CHECKING: @@ -37,7 +77,7 @@ class GenericSchema(GenericInsightMixin[_T], Schema): many: Literal[True], partial: Union[bool, Sequence[str], set[str], None] = None, unknown: Optional[str] = None, - ) -> list[_T]: + ) -> list[Model]: ... @overload @@ -48,7 +88,7 @@ class GenericSchema(GenericInsightMixin[_T], Schema): many: Optional[Literal[False]] = None, partial: Union[bool, Sequence[str], set[str], None] = None, unknown: Optional[str] = None, - ) -> _T: + ) -> Model: ... def load( @@ -58,12 +98,40 @@ class GenericSchema(GenericInsightMixin[_T], Schema): many: Optional[bool] = None, partial: Union[bool, Sequence[str], set[str], None] = None, unknown: Optional[str] = None, - ) -> Union[list[_T], _T]: + ) -> Union[list[Model], Model]: """ - Same as `marshmallow.Schema.load` at runtime. + Deserializes data to objects of the specified **`Model`** class. + + Same as [`marshmallow.Schema.load`] + [marshmallow.schema.Schema.load] at runtime, but data will always + pass through the [`instantiate`] + [marshmallow_generic.schema.GenericSchema.instantiate] + hook after deserialization. Annotations ensure that type checkers will infer the return type - correctly based on the type argument passed to a specific subclass. + correctly based on the **`Model`** type argument of the class. + + Args: + data: + The data to deserialize + many: + Whether to deserialize `data` as a collection. If `None`, + the value for `self.many` is used. + partial: + Whether to ignore missing fields and not require any + fields declared. Propagates down to [`Nested`] + [marshmallow.fields.Nested] fields as well. If its value + is an iterable, only missing fields listed in that + iterable will be ignored. Use dot delimiters to specify + nested fields. + unknown: + Whether to exclude, include, or raise an error for unknown + fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. + If `None`, the value for `self.unknown` is used. + + Returns: + (Model): if `many` is set to `False` + (list[Model]): if `many` is set to `True` """ ... @@ -76,7 +144,7 @@ class GenericSchema(GenericInsightMixin[_T], Schema): partial: Union[bool, Sequence[str], set[str], None] = None, unknown: Optional[str] = None, **kwargs: Any, - ) -> list[_T]: + ) -> list[Model]: ... @overload @@ -88,7 +156,7 @@ class GenericSchema(GenericInsightMixin[_T], Schema): partial: Union[bool, Sequence[str], set[str], None] = None, unknown: Optional[str] = None, **kwargs: Any, - ) -> _T: + ) -> Model: ... def loads( @@ -99,11 +167,41 @@ class GenericSchema(GenericInsightMixin[_T], Schema): partial: Union[bool, Sequence[str], set[str], None] = None, unknown: Optional[str] = None, **kwargs: Any, - ) -> Union[list[_T], _T]: + ) -> Union[list[Model], Model]: """ - Same as `marshmallow.Schema.loads` at runtime. + Deserializes data to objects of the specified **`Model`** class. + + Same as [`marshmallow.Schema.loads`] + [marshmallow.schema.Schema.loads] at runtime, but data will always + pass through the [`instantiate`] + [marshmallow_generic.schema.GenericSchema.instantiate] + hook after deserialization. Annotations ensure that type checkers will infer the return type - correctly based on the type argument passed to a specific subclass. + correctly based on the **`Model`** type argument of the class. + + Args: + json_data: + A JSON string of the data to deserialize + many: + Whether to deserialize `data` as a collection. If `None`, + the value for `self.many` is used. + partial: + Whether to ignore missing fields and not require any + fields declared. Propagates down to [`Nested`] + [marshmallow.fields.Nested] fields as well. If its value + is an iterable, only missing fields listed in that + iterable will be ignored. Use dot delimiters to specify + nested fields. + unknown: + Whether to exclude, include, or raise an error for unknown + fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. + If `None`, the value for `self.unknown` is used. + **kwargs: + Passed to the JSON decoder + + Returns: + (Model): if `many` is set to `False` + (list[Model]): if `many` is set to `True` """ ...