From 13c38030c17db892a77b44e022b3d6986fe5cef0 Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Thu, 17 Jul 2025 15:22:50 +1000 Subject: [PATCH] Make solver sparse, put example set in /examples with all items from https://cdn.zofzpcb.com/RMatrixExamples/RMatrixExamples.zip converted to 4-colour palette --- .gitignore | 1 + .../SlotInPlane.png | Bin 5059 -> 4323 bytes .../stillOKfor32.png | Bin 5163 -> 4667 bytes examples/stripe1.png | Bin 0 -> 4390 bytes examples/stripe1et.png | Bin 0 -> 4780 bytes .../stripe1thin.png | Bin 5862 -> 4703 bytes examples/tentacledTriangle.png | Bin 0 -> 4809 bytes examples/tooBigFor32.png | Bin 0 -> 4617 bytes examples/wideStripe.png | Bin 0 -> 4269 bytes examples/wideStripe_punched.png | Bin 0 -> 4389 bytes n.sh | 10 ++++ resistor_solver.py | 54 ++++++++++++------ stillOKfor32.png | Bin 1900 -> 0 bytes 13 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 .gitignore rename stillOKfor32_50x50.png => examples/SlotInPlane.png (57%) rename stillOKfor32_100x100.png => examples/stillOKfor32.png (56%) create mode 100644 examples/stripe1.png create mode 100644 examples/stripe1et.png rename stillOKfor32_100x100_trimmed.png => examples/stripe1thin.png (51%) create mode 100644 examples/tentacledTriangle.png create mode 100644 examples/tooBigFor32.png create mode 100644 examples/wideStripe.png create mode 100644 examples/wideStripe_punched.png create mode 100755 n.sh delete mode 100644 stillOKfor32.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b44ef38 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/*.png diff --git a/stillOKfor32_50x50.png b/examples/SlotInPlane.png similarity index 57% rename from stillOKfor32_50x50.png rename to examples/SlotInPlane.png index 7f8b9dd435569b018892410edc2276ba946f768b..bf754f3dcea53812cac7c702722b056affec9f61 100644 GIT binary patch delta 1129 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 T36t&J8;8Jg7qIJD#}xko9JNqF delta 1890 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 literal 0 HcmV?d00001 diff --git a/examples/stripe1et.png b/examples/stripe1et.png new file mode 100644 index 0000000000000000000000000000000000000000..9af883893678a2ca39de991505e2464933d3457d GIT binary patch literal 4780 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 X2uVr#pzU+eU^Gd1toU%)pI84EYKiPv literal 0 HcmV?d00001 diff --git a/stillOKfor32_100x100_trimmed.png b/examples/stripe1thin.png similarity index 51% rename from stillOKfor32_100x100_trimmed.png rename to examples/stripe1thin.png index 368a3d0b1f05ffd32ad52dae3320e283bf825041..d7323e597fc18ca3e52be4f7dca46c0d8e6f819f 100644 GIT binary patch delta 1308 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 A!vFvP diff --git a/examples/tentacledTriangle.png b/examples/tentacledTriangle.png new file mode 100644 index 0000000000000000000000000000000000000000..c5fea758277d10ea3bb7651662047011e686e270 GIT binary patch literal 4809 zcmeHKYg7~077ieyh>AuFDyd^cQLmFsk|B=~P$5Vn1W`b&FPzLwV1PVK0tvWOD%L_w zQDn7MM6c9d9|a$%wN&aGe6bShjTJgeK$NUmtAxJqIB8t zS1%CDtY3ZDLysbd5M`d@x|v&V&n`c*^yIIb!bx7+E7)1mzzHLlqwV>1{I8FWxkgghwdbw!|# z{FOQWva>V1%3~u#*GEa4q56#lSZ#2ySK>%Z#JDT2`>@T6UpOn=RKPz2#9|!y^`iCWakO+mycRrb@VNc=5OLZVa5J7;K_5&>BBE8J0vfzd{v&FF3Ts^(aZzPIoccj@2{-)EW9wK zMbc6t_wZiTc&xr<%>6?@I#yb@eBbP~+`3?@skpklNSRO;S++d7W^(L>6-D~G`l4T& zidN2fbtZmp?9zIyV%XQk>A^Dhf*sjY5)S6#HF(a*Bt=H50 z*FMkaJpEX+uex#Vmm?Go1s>hFhKE@xrCrhb!{~7?P$b1}85sM}oSv zv^CZAb?JAjE046dJ2 zQbtHg#nBpn_T$o%Y=|cP*)hHfM4=0!;%Ql$o{CHhk0R0%2?@!b9^mR{#sGnuGUAX~ zoun~fW`DMw7X$A$GnWn7A;v_1_5wu&6r|Nt5XwP02pnvtQ~2xvSIAFKs<3&|S=|(1 z=Fg5d8g&?#YciQQCILsQkK^(r5(yXKbNPH2AYenP#)z9?jbXfvqKiXH83;YCGtycO zWaGq@+GL|Yn+^QX>-^L@g`$UEW9U`^=)pDPIxdfcaMfyV?+Al2I0cY&C-lw;Lliit z+ml_XybQ(^+8RAMoOAmUzBa*e@=YY56l1;{xx;1Tgro)AS47*PpG z7!~t)u$U5xUqoC0@UuYZ3_m90m9<8 zJ_Q7JJE#Q<(o?umtB=xZll$Yt}VQqU}csg6xL^!-=jE40sAf z+VcclT`nRX*Thla_ULZc*LM0Ht$>Jpc?2Qi!@iV60HZ2g1>*ur1&c*OmB<%Gm3&E8 zRXywmt;%S^_0-Hbpd-);<{|$@&b1ux92kK)(qtPSN?VH#b3Du1obWQUi$XQ)hE|`Dezw4zV7Oi z>%A0sFK}OX{omwree*d*X~3@_6ZlvX|FY2sd}z5vghd5|k;C}Cvmc|gvr|&ca{+S) zWoU?$k?G8mfyqFf>>~q%G31o(aY(qDH4qqGjB-V=%LA8T&W@9-qETlC!*QuxIx{N1 z?qTgMbtB~NqGP-67#A9q^Xic#x+Lovud+&JD80AU`Rv#S>|2)9tZ(bjFLNVOc3#P5 zO{?<`2$;V5(|j?We<6!`Zs6v7Y%6o>XXCBRNuT*xncfP>%7hf&*4#EU3klyhkFvi|+ekP>;=l#{LAtnB)k54QiS`S`Mi-FLPMCk9apf?Lg%MYh}!d zEt;&SZSG&a;_A;xxf|<-%{FYO3EH@h+9+ev#wt8%aA<&Cc0xm$eX z*rJ;gFirk9H-FA8NSbi%R?4on7guzL7gdNhR941yoKk;Z_;Qtr)rLNoS=usV3$vBE z%U9D2hEya~-7ZKQG$S_SnC9w;Tw+@E-Ky#3stu10G?hJ6kF;#7n6LczCUsWL=|7u)DIxMrM@sYWq85*jhfQep U{PM$vp!pc`;Be{wz-4Rx3tgEBRR910 literal 0 HcmV?d00001 diff --git a/examples/tooBigFor32.png b/examples/tooBigFor32.png new file mode 100644 index 0000000000000000000000000000000000000000..9dadd2ce6dff8d1bd74df0f16b4511afd87a4bbd GIT binary patch literal 4617 zcmeHKc~BHr8Xr+a@Cb?u7$Qvz5|5tgX=bLUdl^Ay5JnlD;D~sv($fdDG6yq_GlS7} z!HrxSa*2v)l3Egv-B6mi)_Q^mqU(|v5-&_x77`C6>T0rT(6Fxuv@Yq?1b@QA=;%>4SmyJ0Mjd*fn{Muoj-S)7~D~xSl{Yq2Qfrk05g`+|PuhhJY zA0^t{qPt5vgx&lv6Via;-}Xie>v`lq{#~kJj$~Bb;*|l z%a3G?`{_rtc+OYR@Cyggk5O}l&ug={|8s8LffY6TI&O{G;YT8$`ys{Qwmrv>A#1~@ zHiZ&I%=xelo#$#B3ffDT9}6VPN{OH?TTchyw=M8%@jJjQx${AqQ74fMDd4qQqh70h z77>V}a^0Jn3OhpvDMo?#Cs?>Pyqdzn`#Y!qQyy(Dx%N6p_=Uujj8m zaiXklZ$Zf?)nlsjp+`enrRr&ilZ(3M1t8{F^_}`7Ys-$fHeA>%zt}NPvX=|JYD)b_ za9UlywgeRgrQkDLN4IV>%)4=P zK^QebA2BO>CwepgblLJPzg^$9d`)`Gwy{&T?1+9nu;kmx?s01-W<5tqhT_nsI*luF%AQlJtb(FrzRgj-J?hU{%%DvyJN;PsO!AiuvZP zbBlbZ)cdp>BZ&3);vRkd(UOV^;q8-p=$`pnI2~^f&cZF7omUQCi{8)``nSfzKjn?w z`ZV&`)r;n&+7^{P=j)5#Xj&Y8A)dx4ts^qd@V?2X`Lmnb18VOf7izBm=hD^sTSMRY zQ*|R=dm;i|@nJ`9nQK$t+Rle5yK2G{_B-BwrS+H{6rP(01(t3|A!(aMN-;JwD|K6d z06ejAZaYP>jtKtXOxw$(|xHLw?#1buN@218yIVYLQMHy9zU&A~znsX~e(iEe%k2G0tBVjT=e zrt0SOK!A}3&JqMWDU-QeE~zUL}uXZ~622175r)!D-W;6vu7>@v9&m02vZ{uWLlaSZ_Jap)H< zoF=eOWvQ&wmg}I|#5Jr{n9?7Dp?mG^xsGgaI1DXgvsnvJb%Isp1C~tE8;rdcA_bYe z#qPBNWDn33c&?AE0ltY6Z#exO0p`891GJyT?o|d_1_PF8 zOJl5Aj;qy(%FJPiLdjAHMKLI%<`j&ILn#bXnfpQMtxkcm(yRytz@DOd_;yig2H&apWx6i6p;p)y&S-J0nYh=h}~jd~4?NzuL;V>Tslz(511 z@YY;+pTNXh*o6WmvMI-v7>=n4l}drCaZK5#l*T%opb|w)IVz1&cqL+5NDvGlmJ;g} z0C?v?ETq=KQi9E4ve~jVu;>ybTK0+!U^_9CK$R+nw@c-U-(Cc&EB|)Iv6=d(=J5=Dk}9g1no8r0DJtoYWe&n_+;} zEuyn1YbFa$kDhXUHqZY;DJU3R!6_*MF;gm#KbjywH7U&q$|$H9f}&_vfqPl#MR(db z!9_XP*_nVxz!fM@FIUjZ-b76ssO`#P#Vi2A5KtdKCrs88uuMENo<$rh`xz&(UWI;# z46y5-1BVwl3uV2BVGn1(-(U0T$;Gd^1OyE(@?885(ltoeb20E-%7fK4NY`^Q@LbA+ z)%Aa)E1>T>#ah8%kPBRv{#+bT4K7-vj47r>@y0cwt818~tE(%2J^v64hnVLj=_G}| zFC~M4zdd=0Qz98tE51WkT`KYilYWBUkmz^IZ>+EXq(A1AUI8{c^}5-ntmf~o8mt9q zpl?Rim?#k~oH}kruswL}ML!W4MZ-aYcoGh;Xyz!#cS`=ujO5F=J1i5YE^__h(&d>c)*Veb+0EP2E9$q#qS z&l43BDXm*J6Ea~q;3 zzG@4eGX2zL&pYH7shLH4vV-NFA;*`sTiVE^w?6&%-UoZ%`@Sj29e%#tx69{Tu)n9~ w{>-O~Rg5K7^4q+^Vp?`)rc+$l~->=3(&6O*_QT2}ge_naKWzU%oM z+lhvvL~044q@x-?QeZ;cXhB=VFQHMO2`f>GIvC3e1G=&(Z7ERJBDxj2tj*qCeyf$H zNb7$&>3r{fe|+Be`+48@m0zQ;xF9WcK`Mq}X&$$$6n)>--sDHn?w3?(Uud|qb={fiZ1dK%1G~=6yDycbbf+AX*WQ}j&Bz#* z)F3*YK9AEmm=H>1&(D7DaKE!+VaNKi!Y04#F5Z>lj2>;;V!!f}+57Vj&UrRUpZw>P z7AA9%`u4ktH zBHm&@@aBR~rX+UGx%k|k%g;7MKR>^IzG1`i_tw3Uo}b!Op7$srFuwe>xjn}>{Cd~B zU7Nbz$+`2;{PFhl&rDp>nS95W!EU;j^YFvpt!-&hU;BdxzZdvmF~35dS7{6N_Fg^l z!P2_E^xt>A^=-|RUEgG$xpp~F(B5s8U;Oa$$Bu3#WqzXTNvD#TelN1f;0yAPA(#2jdILUhfcmI5NNj;)994}NDOd$V$TWghHI7=cz~l7| zd1w?=h#^_`LS&D!RK?&hS)*dpGgUAW9SwRVAnz8I=YlAgG|#WD5uuGihgR0g|E3 zJjq%CPXcSu0xb+H1g)$NCGgxzNeKb8oni=7KuQi*=n9Q+F4yOA5GDgXEb&zVHHaJ> zM3ESd#)lPtF$Bw0ps{JRSxh#Qon=fWitC>PGDK%h#BUy`aEgccI6c@C+)=r{>L1umdM1WKDM9Bt!_Hop-KSdKO=H_{wE z!d?=@VB&vSYljEV>fds=7(weNbW#6_DuXZf&-$lTqJETcTt5^X;QLdEfNCh{aU!gK z6<-O$6%cigfpQ&`i{DcUtkuF;ED(^inGTW+;*kuPYz%3kO=i~4GXU6wqtPQ$P>lfv z=2jpc5m%@@b*}Iq>l?Lfv~{c!YP*04BWWA?UBak=gek3O3}&1~eTS1Q-C#tML4N%* z)VxqHq=uT|0B2g;`2nASz4!rFK+xlhjEUcIy2j}m69Z#19;Fbq z>hN_6hS9&E7`iMiIyC7fx@b-H75Ve^D_371hV}LJIe&96j^;^$!U7kzdEygpG?^^B z*G4dGTD$fpZMf1n83|KVk2gQ%cFK&2lau#7F?$;lIX$jif8~vTT-u-3j$>Hv_KWVT zM+)0#KGl$v)SB#?bMi|mdjhiSE-uL_&79fjBEDWGezCpH^GcagbhHp@>XJSqTJER6 S-?|D-Fi(E5t2OV1`u_qx5ckjk literal 0 HcmV?d00001 diff --git a/examples/wideStripe_punched.png b/examples/wideStripe_punched.png new file mode 100644 index 0000000000000000000000000000000000000000..0a1295739613dfd1c8d0e4cff2a3dd1490e130cd GIT binary patch literal 4389 zcmeHLc~BHr8XqtO<&sE@;u>iN)HSAOdM;+Vml0)#V`K&=Fd9tQXdiE&l{wPW!_2_O zq9B#X5!sEkfJ98Cl1OwBjhdKf6ij4^WwPs%#dsu!#Tb>i${wz|#IUb>xU8fqMb+j% zx~ix9eaG*8-|ze0tA0~$&CQCAm=__DNTN;I#yt4^Shz!{!Qay>?AZh!zkYnMp;=N;CkV@@E`zq|5q`2&Hs-1CRdGOm5y>ul!_ewy3AIVwK( zY{#qG4~Xeu$xotdR&txGpZM4E&y2sQGd(!7?Zp>vr*01o)ZF{#?q6r!%383hDxj(V zXIJ*;u?cl8`Fa zV6d7DhS7{*9^0S$oj&`c<@3AN<>%DejMtH#M1yyKZH?~CV-LTUzH9bVUhMsUM>eaI zm&mqMZajXxzH4_??Sb}~_DbYVNWV9nrb`ly3+)4*ZRUA9E`7UT*|CdVfri`fr*&84spI?Ns^iSs$NQuE zw^?$oe6VUhIop)DZ1E24YUPRg!p2{3x>Q(N(6{ZOq{f!TTViW3FK8%lS{?O!f3t4q zTk|eQ1{!Do>FMpgPgQwuoLo0owqfb1!q)hVh}wem2c?YKni2g-|G^D!G=1E&spq4# zfjg?NUp~1yEU7zmz?z6}8ce(M<({?8&HUC6O~@d1A%R}*o>Q!K3=N%q_rl_e;rRD@ z4u4-3*>o@Y=(%1htFte~{p^>$U+eq0@VSAWg$6D;&GMQp^x~hdz7o+nh@S5F=09i7 zbzhtI+t=HBw4KKjv1fK(_tyJfEGr+nZEo#INPnB#`b7UxH*7pV3mdG!VkT&pLq;+# z3dsBpsDM{$n%_;*8v&0{pon$qr8kdsND-FNOP|zOFpJv&irMTk4&;~R+UT;4G|ouV zmPMrc2?*c-Jc;-nB~B0F*GolQ0=^4kxfBsi_>FpLfyIg#TpU2uGPMjtGyH6+Qo1Yx zN#z(jk!Q>tfq)~uw3z4Jgk0|P`D8wo%*7SS6*!K|F{NCoM4<)h2{?Juk2*a`0z?qQ z2s|{$x_Q>+L#VOmtp=x~$-Dm!XVp=gat1+;1{GXcuv^zfvU1_BfWm$48>t;9&R zU5BAKY1g1?N~b|7%C10hio_Il3Xr(QJ^^AC$HJ~8OD0AoKrs+XODPq&T0x^44X#Ah zsuY0YN}xf3k^(xKq-ab-iBJqpWV$#93Cqbk$RZ$jJBvhxKsd3&YSK%UGHhI8Eg^Y3 zbkIx9tkdfsSJ+qw$mdCcO@&sY)GBqjQmIQ(=y2`0(Hg*cU?&Qg3QVR_iyEOU1WX1J zOA37o0Yo{>g)ne{K>|G3N5B!w1uy~NvV9B#t51cu zh!s@P#iX+cz};h{T}S2YkF)|#17O#wH7KcJU^i(LDpaS|s?n4bN~@t2DvHqsNg6}< zxa_=-(B` z4JK?d&@U*1n-|;*^DSoHunxbn`3{1*+s=KD>niK<* zGM?(L{~KKq8Sd=09*HETQ@BGmoT;7xh2gx(k`aC_{GqVvkL^G3k_L(nn~W=L#TWnHb9_dq zA~y4HVUhdZ*dr|(%8A=KW2ouC1DTH$GTOU_=PP2r@_jNG74KUMog|XZ?XqKkuzdbp z)6P|S3;!`}YP-dLr#uO`M_=_{DvxhUzIQ0fY`*DV|MIOZtNY8yq^-$w7R7Dd+h}Uo z+gN?7^=k62)~hEPb|m~NYJXWxZcNg literal 0 HcmV?d00001 diff --git a/n.sh b/n.sh new file mode 100755 index 0000000..1e25e22 --- /dev/null +++ b/n.sh @@ -0,0 +1,10 @@ +#!/bin/sh +./resistor_solver.py examples/SlotInPlane.png SlotInPlane.png +./resistor_solver.py examples/stillOKfor32.png stillOKfor32.png +./resistor_solver.py examples/stripe1et.png stripe1et.png +./resistor_solver.py examples/stripe1.png stripe1.png +./resistor_solver.py examples/stripe1thin.png stripe1thin.png +./resistor_solver.py examples/tentacledTriangle.png tentacledTriangle.png +./resistor_solver.py examples/tooBigFor32.png tooBigFor32.png +./resistor_solver.py examples/wideStripe.png wideStripe.png +./resistor_solver.py examples/wideStripe_punched.png wideStripe_punched.png diff --git a/resistor_solver.py b/resistor_solver.py index af87228..8529da9 100755 --- a/resistor_solver.py +++ b/resistor_solver.py @@ -4,6 +4,8 @@ import PIL.Image import numpy +import scipy.sparse +import scipy.sparse.linalg import sys PIL.Image.warnings.simplefilter('ignore', PIL.Image.DecompressionBombWarning) @@ -26,9 +28,20 @@ image = numpy.array(image_pil) #print('shape', image.shape) #print('dtype', image.dtype) assert len(image.shape) == 2 and image.dtype == numpy.uint8 -assert numpy.all(image < 4) # colours are 0 = black, 1 = blue, 2 = red, 3 = white -#print('xxx', image_pil.palette.tobytes()[:12]) +palette = numpy.array(list(image_pil.palette.tobytes()), numpy.uint8) +#print('palette', palette) +assert numpy.all( + (palette >= 0x80) == numpy.array( + [ + False, False, False, + False, False, True, + True, False, False, + True, True, True, + ], + bool + ) +) ys, xs = image.shape n = ys * xs @@ -42,25 +55,32 @@ image_vert[:-1, :] = numpy.logical_and(image_nz[:-1, :], image_nz[1:, :]) # KCL is enforced as follows: # A V = I where V = voltage at node, I = net current out of node -# I is current "unaccounted for", i.e. current that cancels R currents +# (when node is electrode, positive I means current is entering the array) # resistor R connected n1 -> n2: -# causes a current of (V(n2) - V(n1)) / R, positive when V(n2) > V(n1) -# => when current is positive, it should decrease I(n1) and increase I(n2) -# => I(n1) -= 1/R V(n2) - 1/R V(n1), I(n2) += 1/R V(n2) - 1/R V(n1) -# => I(n1) += 1/R V(n1) - 1/R V(n1), I(n2) += -1/R V(n1) + 1/R V(n2) -A = numpy.zeros((n, n), numpy.int8) +# causes a current of (V(n1) - V(n2)) / R, positive when V(n1) > V(n2) +# => when current is positive, it should increase I(n1) and decrease I(n2) +# => I(n1) += 1/R V(n1) - 1/R V(n2), I(n2) -= 1/R V(n1) - 1/R V(n2) +v = [] +i = [] +j = [] for n1 in numpy.nonzero(image_horiz.reshape((n,)))[0]: n2 = n1 + 1 - A[n1, n1] += 1 - A[n1, n2] -= 1 - A[n2, n1] -= 1 - A[n2, n2] += 1 + v.extend([1, -1, -1, 1]) + i.extend([n1, n1, n2, n2]) + j.extend([n1, n2, n1, n2]) for n1 in numpy.nonzero(image_vert.reshape((n,)))[0]: n2 = n1 + ys - A[n1, n1] += 1 - A[n1, n2] -= 1 - A[n2, n1] -= 1 - A[n2, n2] += 1 + v.extend([1, -1, -1, 1]) + i.extend([n1, n1, n2, n2]) + j.extend([n1, n2, n1, n2]) +v = numpy.array(v, numpy.int32) +i = numpy.array(i, numpy.int32) +j = numpy.array(j, numpy.int32) +A = scipy.sparse.coo_array( + (v, (i, j)), + shape = (n, n), + dtype = numpy.int32 +).tocsr() # partition nodes into 3 groups: # 0: black + blue (electrode), 1: red (electrode), 2: white (conductor) @@ -93,7 +113,7 @@ A22 = A[g2, :][:, g2] A11_V1 = numpy.sum(A11.astype(numpy.int32), 1) A21_V1 = numpy.sum(A21.astype(numpy.int32), 1) print('solve') -V2 = numpy.linalg.solve( +V2 = scipy.sparse.linalg.spsolve( A22.astype(numpy.double), -A21_V1.astype(numpy.double) ) diff --git a/stillOKfor32.png b/stillOKfor32.png deleted file mode 100644 index 4b51a32cdad44fcfb8d21a4faffa2cc2952d9b09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvSkfJR9T^xl_H+M9WMyDrW(e>J zaRrJqi2nc2!tnq9e-L{VjE2BS3IUmL$E!g9au#?*7BevL9Ry*<9TT(P0tF>XTq84D?J>Ta8kIndqLUi(^Pd+}rbS%N|+ruwK~q{qOys zOm{Do3DqYk9bdEbZ~8K~iRXTLXfB-+
    PKHMK~vsan--JX5&KkF;%%`g3bxO}_P zFZ(|~+*s~^`22f9b$g?^;uk&T_m0n)oZmY<5(>_Dc%YR0dh+%|4_+-m`sENyuJL{yL+c+2p+Vn199`7%=J9OR&KoD)wI^+ueg2wqy#0M$_dV)A z3QRBA9$lV2@vY^)*scu!PanNhs%M?Qu6X@(&3>MZZZ|e?EUc>e`Tby*>4_`J!6_@% zl)l~&i(J{|VEe6W&1IK)a=TrpWh(i#uV4RHtvf_;ne)aIQoboK1N1hzhC(C2 zGGUu{|I*nfE?(0psuI<_HOtj6Pst^E_lcdpDH*Rdin2sGXXV+3Tegm>nHvnuAck%vPHDw z-~76j#R+2J-7f#9$G@I4)Wb=zM0MpKDss{ueC^PR(7Kd*Yg;e@<%(xkIj^f;dyjI z#P3)^GM~A#g<Fnm6bqd|fi~m`C zo9EE5_(l~QCtuP_%M^>2sp^7{ILzj`b}>g($XUjv-R)$loSHkirta5y`9*t4Ki~Be;}S2+993cu*_hsy-M>NYnopqar!3*)#R^FBq1TBluD9P?zU zTA0s*W3BDFGut8z8^y%swxviVx!S1a+2o!uInpJNWG=C9Qf7y!q03sMD&@-p+DRv( zQopz@Qw(Df+;-@JIZ&IR%Pp?v`yg#1h21@hKsAd_M5pk8WZWJwIhPypZdB?y!rJx@ zq(o+7xn$)8pn-)c_fnrYg3J-BYHySWDVlJ_n&%Hlu5rn|#0Tv@&TBf9foYW=B-eLl zcaIIoMFvXZ61ye?6(y?Z8I-7lY~zT5*yegqDH)_h;Zc~xA2py%lSg#ohuI)=6mzCt zlm@xT`I^>ZbC7{8D|p-1gZ;WOAL3WeDLX!FPz7pJyYT4H;b}l^GaP%1`gMv@kBY37 zi+pmb%TmgA(}}5~ldn{#Ow`uCrf^xpI!xiBf;W)Rh(4!&-lF=P+F9)!tLZxHH@^0n rwCBvO%^nk>c@vRKHJ2*a*8Jh0^?1fj{`8v_pd!)J)z4*}Q$iB}xqAi; -- 2.34.1