From 1255e712719ce66fd3b231e5c212ea69b0bb9f1c Mon Sep 17 00:00:00 2001 From: Chris Palmer Date: Sat, 19 Sep 2020 12:11:54 +0100 Subject: [PATCH] Added catenary curves. --- readme.md | 64 ++++++++++++++++++++++++++++++----------- tests/catenary.scad | 56 ++++++++++++++++++++++++++++++++++++ tests/png/catenary.png | Bin 0 -> 38365 bytes utils/catenary.scad | 53 ++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 tests/catenary.scad create mode 100644 tests/png/catenary.png create mode 100644 utils/catenary.scad diff --git a/readme.md b/readme.md index 28ee733..018b7ee 100644 --- a/readme.md +++ b/readme.md @@ -20,23 +20,23 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa Vitamins A-I Vitamins J-Q Vitamins R-Z Printed Utilities Core Utilities Axials Jack Rails Box Annotation BOM Ball_bearings KP_pillow_blocks Ring_terminals Butt_box Bezier Clip - Batteries LDRs Rockers Cable_grommets Dogbones Global - Belts LED_meters Rod Carriers Fillet Polyholes - Blowers LEDs SCS_bearing_blocks Corner_block Gears Rounded_rectangle - Bulldogs Leadnuts SK_brackets Door_hinge Hanging_hole Sphere - Buttons Light_strips SMDs Door_latch Horiholes Teardrops - Cable_strips Linear_bearings SSRs Fan_guard Layout - Cameras Magnets Screws Fixing_block Maths - Circlips Mains_sockets Sealing_strip Flat_hinge Offset - Components Microswitches Sheets Foot Quadrant - DIP Microview Spades Handle Round - D_connectors Modules Spools PCB_mount Rounded_cylinder - Displays Nuts Springs PSU_shroud Rounded_polygon - Extrusion_brackets O_ring Stepper_motors Printed_box Sector - Extrusions Opengrab Swiss_clips Ribbon_clamp Sweep - Fans PCB Toggles SSR_shroud Thread - Fuseholder PCBs Transformers Screw_knob Tube - Geared_steppers PSUs Tubings Socket_box + Batteries LDRs Rockers Cable_grommets Catenary Global + Belts LED_meters Rod Carriers Dogbones Polyholes + Blowers LEDs SCS_bearing_blocks Corner_block Fillet Rounded_rectangle + Bulldogs Leadnuts SK_brackets Door_hinge Gears Sphere + Buttons Light_strips SMDs Door_latch Hanging_hole Teardrops + Cable_strips Linear_bearings SSRs Fan_guard Horiholes + Cameras Magnets Screws Fixing_block Layout + Circlips Mains_sockets Sealing_strip Flat_hinge Maths + Components Microswitches Sheets Foot Offset + DIP Microview Spades Handle Quadrant + D_connectors Modules Spools PCB_mount Round + Displays Nuts Springs PSU_shroud Rounded_cylinder + Extrusion_brackets O_ring Stepper_motors Printed_box Rounded_polygon + Extrusions Opengrab Swiss_clips Ribbon_clamp Sector + Fans PCB Toggles SSR_shroud Sweep + Fuseholder PCBs Transformers Screw_knob Thread + Geared_steppers PSUs Tubings Socket_box Tube Green_terminals Panel_meters Variacs Strap_handle Hot_ends Pillars Veroboard Hygrometer Pin_headers Washers @@ -5245,6 +5245,36 @@ Bezier curves and function to get and adjust the length or minimum z point. ![bezier](tests/png/bezier.png) +Top + +--- + +## Catenary +Catenary curve to model hanging wires, etc. + +Although the equation of the curve is simply ```y = a cosh(x / a)``` there is no explicit formula to calculate the constant ```a``` or the range of ```x``` given the +length of the cable and the end point coordinates. See . The Newton-Raphson method is used to find +```a``` numerically, see . + +The coordinates of the lowest point on the curve can be retrieved by calling ```catenary_points()``` with ```steps``` equal to zero. + + +[utils/catenary.scad](utils/catenary.scad) Implementation. + +[tests/catenary.scad](tests/catenary.scad) Code for this example. + +### Functions +| Function | Description | +|:--- |:--- | +| ```catenary(t, a)``` | Parametric catenary function linear along the length of the curve. | +| ```catenary_ds_by_da(d, a)``` | First derivative of the length with respect to ```a```. | +| ```catenary_find_a(d, l, a = 1)``` | Find the catenary constant ```a```, given half the horizontal span and the length. | +| ```catenary_points(l, x, y, steps = 100)``` | Returns a list of 2D points on the curve that goes from the origin to ```(x,y)``` and has length ```l```. | +| ```catenary_s(d, a)``` | Length of a symmetric catenary with width ```2d```. | + +![catenary](tests/png/catenary.png) + + Top --- diff --git a/tests/catenary.scad b/tests/catenary.scad new file mode 100644 index 0000000..2d35330 --- /dev/null +++ b/tests/catenary.scad @@ -0,0 +1,56 @@ +// +// NopSCADlib Copyright Chris Palmer 2020 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// +l = 250; // [1: 1000] +x = 200; // [1: 1000] +y = 50; //[-500 : 500] + +include <../utils/core/core.scad> +use <../utils/catenary.scad> +use <../utils/sweep.scad> +use <../utils/annotation.scad> + +module catenaries() { + // + // catenary curve path from control points + // + curve = [for(p = catenary_points(l, x, y)) [p.x, p.y, 0]]; + // + // Draw the curve + // + r = 0.5; + sweep(curve, circle_points(r, $fn = 64)); + // + // Minimum Z + // + min_z = catenary_points(l, x, y, 0); + + color("blue") { + translate([min_z.x, min_z.y + r]) + rotate([-90, 0, 0]) + arrow(); + + translate([min_z.x, min_z.y - r]) + rotate([90, 0, 0]) + arrow(); + } +} + +if($preview) + rotate(is_undef($bom) ? 0 : [70, 0, 315]) + catenaries(); diff --git a/tests/png/catenary.png b/tests/png/catenary.png new file mode 100644 index 0000000000000000000000000000000000000000..7efef20dfb72cb9cac521f667884452d7fe62a31 GIT binary patch literal 38365 zcmYgY2RzjO|Mx8w*{P6hLRMv*btEJSN%qQ~clORGLS{*Xvx~C#I6EQaY=?7%Y)~&)4hqzTQ67P@%ef<1z^e36<(2rDr50=W!$?=j6%G z0q-dPR3`o)wN+48AR#G>qrjP80RGNy`RJKC35nk=5|ZFh5|TsUt>7gR63;s%Br7jS zNTffJkTAHw;99c4KU}m>Q&A!z5PxSj=6wL(x#Xd$u6*eaIXxvCwUBZ}7w{IXrMZR| z3CRUE;14_S_jnSLf4l@<&29pMNmP{-p8HI!p>2H8-Av9df zdP;p5M#g=NF)#Z@SlLG!IuDcS?zXcBU_x9m@BXCt?0>2vT;`>JsMg7&*h=u#gB<6aJso_0ZjxU>?PU>LIQq?X z&;z>q5ykAc+L|%}t85WxJ7pqO_#KU&Dt!i0pJK9o^~gedE~0U-cIER>HU8DveprLu zio3gw(%~arPh+7*SsD|Q3OQvmwq{^<0q<3|s54O*NsfHJH&w$BDgm9;@fi&aRlCCt zY?{RG=Mb8*C+@3kvHvdQv&|N495Y21^4?TMQ+uZD7DeXEz8vwqOvkrqL~uFNW=)5r zcb9{X?eEsa$d^WULg)tRo=8;xlHL44&gC`WX>wTQzDIYeXLRa)GRq)mWBLkpj>OE? zN9FlVc8?C$D}*_s$(v_vgw7;lm8IPIR(P9oYj80Kw?sqeMi)TGtv!g;Dm7R6UNL2b z{SgA$nc0uxNe9GwRVF09DrL^_VZ(En9lhoEGkt@kdhV&K#s~HUk)FAM`Z$a~a?4{i zj3+I9tcC{jX1{u!p{rxuJXOiQ>|e()-*x zCezM4UspB3sr}O)PZl-LTp7;LU8krkzb78ZfL&x7rc~B1=%fsDuAfcG@_m!Cn;N@} z<3Cd-=sWp)<-7JPAY=)x&|^id1*%R7@#thpe6*tNSmG{o-2Y!H`GLpRd)r-~W3&MMs_Xvl|vOyb}fG5a=6eUlsQ8F}H5}yxuWSk+wU5 zNIY8T-=p_5q_E9a^S3_}qaAQaaeJ(`AxpUOUGg9;2WRxJ7B2wD(Q2lu31Zs*bEBGx ztU|X0vwI8~Eli8-@fg}~Jo2u&e;VE%jlb|Fz4xH`M#4`Yw%uKz=`2`zh-q9b3Ic~4 zR`VTidZ?T&1b5U4c8OH$lxUDvJPW%PJw^rjCFWdjp;26D7=8H=3UF0(sC*b^8;}sUx%Nl? zapd`CX&_D?C5^N-~Xw{MD;3Z z$i((a;^pW~mxP11&6UHf`q<Ufnimn&|SNYsl@}Jub+$^lMbf*wJ4Ivq z5}kLkYVZ9|H3x%5>$d5x3mjZtqn-h&PquCUwPr9oS;BzPik^OTFPG~LGT!`^OY5>L z>Fy#nd)4F3^%qV<_k~J@l=ijxfv~D5X&JY{#A{?j9bPi&pS%xrz7#tRO-cOE=xa}t zkLxi?i}dL$Hy;;1<=wtGCr)*VRbux$ze-9jzbeXxfVqCQQI<$o;YWjMy9E=wpRZ`5 zUX^MM71qLNOnlRn$QDs9mo{wvT^R0$d4AK(H)V=SoZ-_XWoR-g2?~+lfNfK=N;se} z)97=j$Wb~M@%ja7w6WJwsK+ABb%o+fKJ#JB)bePBjqBqYmCZ9ZYN7rx-h33duq*%L zxX!+ZGSuEZe1xg-xLfMD!i@?wQT_kULl*6x^jWNvQ`77D{Me7n4}DbFO-Mi(A5}clTN2@ zP9Tz0K*O<9LCvVXh8L;R%}3M!Eu1rc|0kSz^d;Nw{AVgr+G^$rA5Pyko(eUXK}U5{ z5VrXYm8!V_SV&}^ol%+mc<}trdAeEhjsnLxxy?}bTTezjO{PY%8+g!ZjI?-lbg6sx zX#ct{Jts!1swZxR6{w&8-b2Rmx;6m0|KBbt<|niAGxk&E$?M%cP?Vv*Q7X<@V;79? z(MKAjhsjkhrFUGXP+U!+5y2VR`h2znZhhHWY`6REaNt75!%Ps#FK{U446|ZhQM$c<)&3r!|hyGiR>8)Lp0MT1Z(<7&6nd zqvxVsSbt>|u+5*BCSkcY6=v>)3^@q8c;+bU5R%4!(8&X zFAa8uPhJ~O`1Fcw`%N~pgSY(7yQnznbi+jM^(C@1v~yC6rdN0eEif`ojn3b!WFbox z?=2tN?AJjqK8|evbl+>~p8UTLS4?ov%NC}nA!IaX_0QU{|3cxubtJkYq#aif^^Wi+ zF6;*M)oCUiv*A|ge=-*aw+_8`J@%OypQ(YU-7jHKhUY&u_DNU&6Dc5J8<{OT+yGVn zmGN;{Jt#t=*8aBVwCDE4#p{g2SG?B#2Y4uwxk;V^@qzw|bamf^PpxDdWIqa4^H{yt zzRlfA4dZw#vxG+z!p@$5k;r>`3rubd4?VLT+zYSF4|^SGP1Bdot-fAp_khV47r~gEC%JE|02-#Mpoe<9rd>gEf8Q$+1 z_lg~xkB&k2&n20942+e(0@Qj2rRhgSHn zU)m;6o~a)@6H2R4TjQ!eeDAZ}>qEtk+*>Lddu@7sp5&bK4a`DY^bgK}r7b0dAaLrq7f3MhjNI+7^Ub{G7IHF}E^KGntemG9_Y{gAJSt9?Y58dRY(kxS zfxvX;RL&2iy!m6Dk1@8gsgZ(E(gzLbjIWN;i!gVMiADBCBkDaXkD)wbiAB<1q*MtB>c-{uHem_sizK#CId_Fw-G7Ij0|wc|FVR0t7MY3uflP6q?M#VRw|wr;v{NW zCQ}UedT##B<_3D@1^!={z+EPq^tyj)#*WkN%11V(yrw$-f8O$%x-HR#ng2wu{r{y3 zw0vJ`Bnqu0tlu;4zIpbsN;%}BoX^3{?^4ShjyR?>OBIz7b8gw_uH(@AwFL8n*Oghl zlq#57Ojw%Qq2t3E*0ruPqJ`50a#W$N=S7U;x1SQp04IyR-vGz_=Av%)nYe3H!}kAH zzGipnC@wkXFu!5J4Lxe}^UQgs??SkSybO3#(~oARGt(zoU-V~%nAUt9N-Z$3VgJF5 z5|6_kj_XA;-+LzNp|!*$g%(ZcA*!>5y4tst_eyPzwTT=TfKbw}2V%sJSfzdOUABg~ z{JWw5gL1;o{Z)9abz~Yjis4>9b3$REN=fPl`?-0rb!9m1nI(gAU{cR_2@{S}TcG*X z;lJUJ3P9-DbocSKknos65A~G}AT!mZ?--vrlNSl1PB9)8UxvD&SLbANf$JB2H00~} za_0FG>18n+RQ#CbMgMzeUP^dH&q+4h>)C?>_=cK6)4Qr~Z^{2`xGyA1mp^&@1{(DL zLR3g}Y}?Pj7uA}34lRM>m|9T<3MJ{F(O=*_q-Uco)t=Q(gDoXd0i|hH7yYH<%Z!+T z9Y8N|0y}X2%2G#=^GUpvjV5;cO>X8C+q5A3FEGtgRtT60yz6^XKRYQBxrqn2 zWsO*on-=s!+b`xwozd7a$G-Z$=Ff|O&+q)sqdwUq;PXEhTGJD*sEs!PPyQvi-MYG% zBweBIfbIX!Ks%nvt?3}q5b#BD90z8P$B`M4;o0iy&-QiIFHYtY!IsnnS+nI5hZnj? z6xvb(aA)rE0v;NZT~j5sD3*UJipBSOBRSf_O9GdB9~e|It>Sxd(Pc%lk-5YwK3ERW zs=MX-pcmK2y2zelh)v?|--gtvG=qmU|M}?s=_=pSynrF2tX|%|zq-yA+Q;KS7*CpB zvV#j_|Nd{YTFLbOvRz}nF+|$j3g8(1NAZxoF$lhn;Yzn(Z=t`4FB5T_B+U#!DexT! zw_f*qygd2RA`ZeB*V_!q!&&s+YfqQ|H-iK>Mc5S2I+XYd^c!btx3T>xnzDkl6&h5; zqK@vXBdx!IDEF*R5j?YR1~@rThSYy?9a(5)1(K~6*sTP-(e(SC4GN6iLYoa2n4Wk? zi!;&ao4N4$b-!nCzc`uo=R>or0|->0-PZ-Rc;?f1J52obqHlFw-1$=KWe?Qf3kFdj zgK5cCoPnr+yN)q|>eM#^09?rvVydsQ|Jbvj`(pbomI z`4woLI*Pv?G;xWJ%~6e|rZCQ6&Act;^+aUL7SHPI{-bf&x5zD@p2K!6P4kJ-Mun+0 zRWY$%_}}kySlLVln*Sc0)I+)Fv_v_Hgv%jsg~|T_zp_&vkqg&o+GtSwYP~z#njUS6 z-y$A2Gj1-F>~)J|hF*=J`HF?4&C!F7Fu##`L!V>yH|1>>h5t_~$P!ji?iO^s0z4i% zDE3lesy`9B@yUH&hyLMO;WB&}m2^OUY81b_-F4bpNu-7wP?IEEw;{IKb^KCT%5koG z8aAmya46yPlx%nNS&8Jws}Ug>Nv@rt*KBM73zva7w|sSYO0mtB;%-^Zr-kr8(C>>o z#i4!~ErgXpQ=aQC+-mF^@`>|1P<0+krnqr7pIp&h711a}!u{{4^ zKd_8kxCJ`LF|`n<3rz`}eG5wSc{t7VFR6{pJNdIa0-WC3bz+I1j;YbFwa zVx8Uf*a^@%_4bQHjsFa;MCl+|1G~+H)4Zb18Qsio{I`LPR!Q&2ZvOYY)aGu7tFPY= z^?m);b41Y#JwG5&OwZ5Nc+6UC7J5PzgQpZ}Ngssvx)yD+QuCVZ3^*Q(^=Ed^%vB=q~+^E)Tf1#GF=N$3$JpQ>w)>ja?hDUuiikP;j7&ex)Iu{@38nk!tXDR}Ue51W z_R9GlU_`E*v_^d_Nr|68)6Y$E2vBt)z7@##52p0fm97|GnJyA$miF0|pI+MdCBeTg zqvv|Jqk4-kg_ZaTKUR$hKC%>uiOF`r@bEmMcAk7}B&OP4P7<5@&$ut#dN*yBpmWM% zmV6nB7ZDH!qiy09kg+!yFg>y+t{q>C6?i|B+U%Zg2`BSVqaCOpb8=( z7W?NW*Q1I{rXYhqP>6Jfb}?EJ|rG0 zv$IsnJ%1&th&g?C^y_wjfkgksZ+P6GY-#>39bGCz8-=`5*_KQA6q?MQ7T9bkv z+YXBvr1s^zcQ%{oNZ7S>Cr#h(Lx?)n_oa`8aLJrFMQ0Ce!2YgZK-*TRHCfizdGeGI zs)Pybw2zuE^p#CYK=ppmwKFFs>8QIcP%|uS#7gt$7F8SbpIyvz%bxipv%m>Fy%=nu z?q8*1_!c#kk27;HWw9%=Avc<6-H(83(<|-Xa;&J0R!=;))%xh~iW5*q-vHW~T}53> zI#ts$e3q}sAlTJaN7xtTlF66e=|FppoHPV%#O1w9PdppR*zH%e51@r+*DIqN9z9qk z>rb%(U-w^N(_90)kX`f-q$oV8ckg2XH+wpK=?1ca#ZLHru~kiMucV8O3ZE>xr+l95a~uQPuFbx`LajP89&>(x?@D zOs?IWWzSQ=PvJF@o@r`OU{lYU9AxC{m98NK8#rJ-^A?%e(4X0|wnNy|XKBUy6Fa2( z>QM`uh~~Y+Ht%t+BFFNG*7WJir+E`iJwM4&&{w0|wBr18$Z3e-g;2V_C%QJd(^P)D zB-gzA3iam$mJ@PQ$~S9rLM+#wM!Sa>Iz?Q}Ejf;0zU7QfttwjHK>pbgFgV^qwQXOf zLUp|8>$~&6uz=G6VG(KHQ=92fW{$GpbMPcxTX{GnkVR z_FOiB=CrYJA2}D=ll`f>SISeKTTnalM-g>%W7*Wb-g@U+*XORuHa8?K7iijePofRZ zI;WKQ=R!?;*L3{ZB<2SwglmK-9C1NcqHj3LRnp;~wdX@&}Mt4rq+Dg;N$r2o`?^Yy%&^u#&1`lzaV z0#-hoG1r$@C19CH`$52b~@rW-u~diPS)5G z+)R)>z;}Eg*u*TJ}&u?C$&jj{lg_`h-S;=*nPrV+^dC}W#E5nxili!$)d~0Q=5u3AHvEiXUO|wsO;l5@*PXSt|jL^6_b>dmiOND zi4ZO9q#|LPpFL?@^HS@V9<035OT^wT3OUT?Il)hp?v@T+ijUC3ub+)5QBl1Hi7P%O zIhebep6@lpor7x*WRTFCP193-eRXfgtAo!=dy~CPJkePF&*&}Z70Rjp(gzZPH=_Gv zU-&^hy;KLZYo<&VfW+F)M~LM(gWh1%2zt)Tuc4@l{Oi7hZzmr;aNHh<*?lOx*U}cJ zfwD(d7V}>*^tjae_+&Eb$_BnTz56?n= z3V$fZ`N?lz<3Pp!z0>b9?s*coob3pTmOuO&E&`7?l!#p&Z#_l72>BB?-UmA&jLYGi zvr-o8ozy)x&>Kr(Bwg`O)tg&I-f{fP8Ka)c-!v@_J=9DSO0} zuLd!kVp@yD3xN5sP^{|8FP5y@x)q^&Qlzt2LF@PMnILFwh|zUkQrj)>Yo}<5GXT(X zZJ%STsm0{I^;oXRBbnFBo+Ac4Z$zfNG}8+wqRDH+3szrnop=b2AL#8}&9OO*oY+uD zxrJHy)lVDNbcyvIZ8UBKZ_U7q)fm^7pPhxZd@Ma@WHuj}Z84!-_?qV%dcV{pWc4jH zMolCGeDsdV-b8WJ`)t6Ca|O)!4q9SVCb`n9wiE_xF=`y}WR8>G9lq4p^h4|kQ~Na4 zX(jfXrku!7fT6L!p#VTHeQ=fIAM_iuaKQnrbq>Ydk_@%M>-A`o({RC)oisVuAx-7x z_F3wM)EVf7A<%IAWMR!lpo>yqnGI8R@Wk5n()SER^96zc?xBkJm@QA)5Hs-(B?6bT z({N6iEq-(Vm7yc=BO&`C}YhmWU7tol0mxi=|0#cp3 zv+-DU)=#T2kw>XA76PLiV))F?;xv&v4@*63j!vig*%96+t-R9Y-efh;ml%j#f#3T= zrbLvZc;&LdXlj1teg?t&XTMfTRu5<5K|P73lR%usnJsTcyXSFxf1X8(3sz7nQUWX^ z*ucPc`LKsZJ^=X0SOW@T&T(>4A<$%@Hoev!R=f9M)MN5mEHjh_IA%?anUpQU{zy}4 z)7$oxz+C{?`}D{MpuVPx**k<@0nXda+T+6*AxB zS1Q;QdHo^Jt3lZCA^#H#CTStk;s>wB!J0M&Y*6JQ7L|T>)@j$N(M`Xn=Jv*DQoa2z zHwY2s2Aj2zGbq2Jb+cag_UzJ7A=Yb!Q!FKrTHJ~hh-I6>X=+{JG*th(!)PCnCPysl z1y)I}2t_U%s>u{UVsxO=`#+MgY2I%k24lGKkl%49mp1}q-GDiOHioL?aFs#~XnOei zvm0uGJvP8o_4BOlxe4wHwD3dw@6K;dt46{}e2dgL!BCauKR6$zBB2hNB@^$4O8z9H zHkKE=@A6;M!htVKY!OT6mS!!4Nx9)Qs;S|IZu1E*b|?SWx}G`a%OdFQ;mY@xrM@-1 z-_M}*p_F&`W5?Tm7VUYeJqhR2a#3mm4%#eJ%!|{wqyXxU1vKj!lMJQ(E|sJ-V6l?| z|H5K8$fUuTPU37AhXmnvohvZ1Gn8$2xUUBFg>Ie{O6)LNPO{MLirY>5l@&#IvK#^b zv5zS>l%Ls8)-?4hf*6pxrL?E&crrluZeN8&d>3UyXEPXhYXp?@STx z*Pllu;Fjt?y!}@voI)n>cXmm8^DllV_1^He!@Wy$G1e3bKGE<}J)f+3gQdLN3E---+1=YsWJj>N+-=q z00Aua8gewg|C82u@$_7WoEo)!ktx<`)iY5s-yT7^lc5flIx%ID`OCKHO@DDcf!(}PDjYW za-9pneVm{Yqg}VsGP8+MLvUr5P?=l6cyUffv!_BLdvd~TFk~XG;J6ub>c~D32TY4LC_;EE?*t|5)yY&e%!`^4Ja8LXqoftOZ>|~&0Md1}b z?Xam|P(W$o|2y3u%O=ZNw0c=$V^8`70)m^qF96Y(cmYKy-=t`}V-+;!gdK>SNa(}% zhtQb${iLL7pH`b;00ELo0?q+78UJ1F`fSY6XY;S`LubfKClW*J*GrO2U(U~ny56@H zIi0F49WySL^L0Eq7P*!&@+Dj9edy?LhlJRVQJr4d?Pvy(MueEleOu=+c|$;Kuqlvu z$X;_lUMwbT)qfQM*)KJ*yB=9EORNX|*#Rw}`3)r)PL`jVd;T71V@kIMw^~~xX>TXA zURf>Pl%4%@8cgurM&F*3u$0WK@ID2u9h>VwQ@XJRIuBHFzS1KyxWe8H!^XR|PYIfs zASdK(Al!N;7-32i)IvO9qwYd5qU5-U#=}XlJOXGBKmr5Mw|e;HJ&w@zSP`Vh&8}(Q z-#;~oo1W?d6eoTCz)+(EZ}`aZ7rj_2sz`@aytH4q`2m$2+|&N^!5(=t{3VRb^E|L!ibH^oQa5cw1raOorgX4aU)>bZG7=M~!<+Za^e zToMC(qg>9gYI$co3GLtQ3ruCM+>$#y9Xs4F`7Wu)&2RTv^Xq;k2c7F13q!R_1rCvV zP-)N6!X)9w^wh-QIjJMY6ZUW)Xm%wjY1OQMKnB2t>AKY!;XwV{Se8FwV)MjzHlI1d zTKoF|F5tAR%}n}f{GCT_3usj9@hDz!1*0cgR}5v6idcMGn%Jg~U7FZaqh}xC<;YIx zTEE&IgpL-x=@8X90lI#RvZ%N1#>8xoKv*oxc6&%%+)t4~2%tWd8BG?VMnI*E04aEV z_>rax!YBTgiELmmxT!2X;i_Q6F^2BV7kglBxH(b+SbIP2gl)h419>^7t>Zw~*lQ_X znJfU(9}b*<&l`ub)>KDcyV*Y;ep*NPNdOGO6W253g2{FMoB;Jd2jth10@cnr5!ub1 zZ%5H>JjTIhz(qpfBHs&OW?^t#+lYs)w3jQly9{rU`l_qlV{G^fms*U@$j;gS=k##y z*2QS_RhqP#W#;62t!xs8;Jw3%vD^uY;)dBSQQ>=(ib|X3J5F+xA0P01U75j6_W}lO zlWnMduav&-5o+NV9tZON z0UBlX7%bB?^((SYNwz$yKTLj5bB1>2jEj-nZ#>ucJu`-Lvk%BkuoqP={XNhfWh$(D zqcPr564s$}SA@q-ua@+Ga6w#9puON~+O`$*4S~~_Mh_w+#Jz=$>Q`GY1$tq>yXh6H zLbUELv^JaP66r%`=WiIj!c%2?uMtp*&uZkXUw&1{NL`M=?T)qPjYS$ct@Mw1Mz@4# zUT3tLkpUkFPJcx&9AS~Wp8<5B@}8jQ7T5oQSf)KQ-TRYYB z-LSi}EsB+9j}Z?X%b%_s>?1di_T1Gb^01{Spj^nGE83f&013UnVqcGTt~#>!)Rw;9 z=r`5yVUH#J8|%JKGwU(T{Xs;2{u1%hXD~~&8|E2{bJd9P)9s?6N>z3X-;l!myEEG+ zzT4_FFrP#ym|`Fv>$yHAbMr_O!e6E!QA(g!{fhl?hA2rb-UGj?*$j8J zZbitX;s2VH9Iu{F8hUfOr(!^JSF5C$8guR6bdztA?p_2He2qd%7>g~Yyje7b*X>`p zDv!I>?B>@uK(T?#&dI7Q{bZ<%SfaB9`|!@-DlKhhpYRcPwf;k$fJf3;$K*u0A`?sLr@Z+txhRyt2-UU6& zmHg`~3`EcGXC4D?L#epmbDM-~q77y1MeDxoW0U=s^1Q*u`I-AOG>0FX#d7U;MFfs; zdzZZQwk5oq1s8S%9O;Ud-9=QeM55zF50rGXb{a}Hx-VBo>BrMli@t>DiYq4-kK1l> zWS|N9-`c(y@dfUO1g`I}Y7Kif2B|LFg3$H#qVj)ezQ#NCSSTE{=ys(C9y@uQ=q^J^ z3YckV3(C5$cS6C*Eb8_`EQN6X>T-*WZy)3XmdF8nsy5^GRN}dTX+%*9MM zM+B{fpAR?NGImn&dynEjGy4(Z2m2P#jo}6CSIPL|ozxz*{#GcWetqI?`<9H0*?f<) zB?}xjY3`btKT!i!4fuIGsDE_)^G@%&?9=oQCCL{f+3=sI4;da^0eKVhwlPzpHQaPj zUFCo%g@a7pOBsQ^?Y*bbIL)PvD`&?Q9i}2>t9;)ljINkNGjt8+7$trmtE9suUNWFt z%-@z$;bOgG;`!|1Q_Y`ucGXJsUebZzC-8J#S8e^hrJHwWJteAair7N<%M3A{)W^+kCDjQdkbXE_KLe#;j)b}?|eB+^QC&?8`{-@L?3A_?C3 z@V1azywJPX9P>pQ<`X&$;#FcfCkm{Fs%;XA95xH4;PJJ^z9GNX)r3l(Uf!NE+W%9j zWjO>dei6e~{eBwEc1tZDx}>5Z`KPGIxzY#>NbHFh`U^aMj8(aFs_IY|al`W}CawP@iiV%T`?`UrR45y68UqL)F>D zH3y9m9kN%AhrD8-6msspl4lm6rR`WSH1pZ0k%|#eU8d%^G46YuBTiKtd+}bo$b9XT zKW?1Ka!+ZqZSQYqTu?lZ>QGfq2iw-(ny;5i%kW@1H|iY!P3c;#N@4#$au0wmbo6#{ zU<@FO#AIXIcGpRNC%?Jrc@7+OpLyb5J3%gztvXNMbD==6%icuB4aebZ<`sgbyHi;y z*pt|z_K=z|Y~tTx0^*P7CObDuR8(dhs=OnpHB7nW;te&={Hh~6MI(o0!>(^lg#C)4 z&b8!G@vHJqyg_@}mw1Mb=WanU_~(X+)<)OWfUcuwFV=R-y?|3SGW$g9nSF=Y=Y5H@ z-u`xtGJv}NxHMpgw@;*aD#sI3bV(Hz)LWZds%TXuHg$j08Z5xuxdF>Cs7+$|j*YK;YA9|HA{Odd!;&zZd@WC)2K3=ceuP z+~IkTzy{pW2ZC$dWV2GQo7Q9N4#k*Wu5X7#YQ-o`Y3Tqctv?U}WhtB+M;oIJ^gN}4`1VRwPT^S;^EMp`{H z1L4_bbMS09i%qJs{6X1KoUG4xRK?;rYjg6bm1;Se2;;r4BRo&)4`&y2CsD*C8t{E# z_B3Et3PeVnde@KpW;+okW3JWKJM<5%R3EQSyuYOBb5!o@RX_d6v7CGS96zJs)XJ4y z6L)gVDj*`*lxS=#=*2&z*|% zaYo)e!MPoqXm>4I9tE7yE~vzB_3-tw6L#*D-D4hE%Ao(#TPCgYR%Df zc{JD69RcyKP$cY1M7O%T)5M5xq@6RqN~(I5pxd}V5<3z9srukzvGpo<(spBBHEbjV z(1k<2lKgmi3APhcGnm5tR)XV#;>9ZIH%v&=(aD8}L=eC4yk)tmW)x|*O=_pD;xI1F zkJ_F3(AUQpl~&&`UahzDA;XJc?JiW~?T)4R{Nj;sl-egbtlQ}^ZX^H~@T|1pE^3?J z`}$G5fNLeJ`)!oj+OENQBiZ2HUeSSDb4^n@x1RW|Zu#mKbUyiFtyOu!^p4$&sPDPc zF3Rry%y1%g^ONqbyWK^uE#K@gAdo!kyj_0XnYbC=)yB?@b^~yKRrUD1v5~o!OwaP+ z{*kk$-;$U07`v@Tweq)LZ|uTt8TFcKS7&DCLpD2z?KObPCTqKj@pAGOAAg>D^had~ zC@&nh^YonGxmQg4?|fUXUwhvH7%FW&v!||_(>=XUi=Nu|DDuF@(ui~L+an@)DV#S{ z@;{8xlQ2gRIgsBiK&GzIm9$R1mlIaGmn~982N9D^J1bOfTKM`naLjBt=7kENaJTe6 zjt|Yvjx%;rGPBzS*;at!UJ$OgO3x-riL1v5=Y6<$sy{}r+c@2|+u6+Tr4IEqS@dyG&H;~KIwtICY zLAdurGnHS_BN@bzVz8O5`@)1VE~DCR6K40=5t^5pGSnmRC;qiJTcAb968cUHCHhBf zRA71CQPn>@UosHQwkI<6l;1`^(6uiUYrsXn@owJiYA%NfpKR2_UBXs)d>|#Zw-8sz z!`em8Tbbx(h)&S2Gi8$ad#sZ2U{kTCTrnqumQ$@9x^(_=k6it7Q(0_7DKane3eTk0 zyCks9pXIp8;|^OkTPYKX6Pv>YQcviEC&HLupe6=miFCwJ>yBJC)4J<24VK&Q6dh8* zM9zjotyN%C+tYksH1dWRC=s>Rh=&4N_ez^pzbQq0e3W+s=vCmtv~$_skBS*2l5%?N z<`Egr@97hYj2>0jlMvQqhOfjerIVDnt0a}6{Q+_U-d8fvjkQ@Sj{w3Xe^qniz&W0K z8OXAgI~6E=Q)&VW=5K!dlM4!6y@+x9rRBJ3>|s)dO`UPHE5aA~asqe)30^ICe;QgK z)r>Jh-+6APASKZZZzj{};4Yk2As?C1K$lITm37pXqSv%4UuD%{(0DQKi{ zUA{Fpa`|abNKA0?cXD%>jLvRaEZiV9Q4*5KAE;}+fKWgwZg#I{KCzW)90k3fE+>~aCW=-csys!3B_gN(1v z4OR#kXkjwGSNX#PU*M9PQ5;@4eVK4Te=Xv6L6V#gc23|r12r?J^wo|!tBR-E+tAq8 zeFS{mtK*|pxbV!d5ulwh1mj{ncUQKD@<@E1OuiabZjFDDG^oho$$mhRNkDJTqOnEt zbuLPQ_1__=lfl5?B55N1xRKzrAp60N8i349%5 z5$1~Vket%rX=l=$$^cts!sfH1`IX3O{5zz#gT-z8p4%R%6wx63bev4@9ZCh-QWPybj`jL6)AcU~8jGoB0fC3~L48bj^$~94 z30<(xrfYl-)`_VH)B;IW-T2BOi%XH{dtdg}t>4kV?v!L-i z&+o@I_*IlMfLT4&0Hq-^gAD~K;M;eew!cHW`||0t8uX<{COaIAD!*JC{?fF$FUpJY zFU?)e=FZyBvR%#Q${BtYk3a^czEH1hlUj7RPuowToZ1>dnP1yCk3Y;qq@c zBX&;SUw5Pn97?2Se;nDGS$?`T(;y>Dbi^eC$(c~HNWR7~T~EcK+liw;9!=VLY)gB4 zSgs2nZ5$maYEpKI01yB|a@igRJ$`SE?hpS+gP(bor!nrk@j^T57dd^zZ;ynvI@I|n zxs>gFMQWXEO0KIS#EIl@TgJs`S{>a5B+f;lx8}iPdg<2>i5;Z4VttU!)_xy@oH%z4 zZ95Ivga)8?nbG{^f|tJ=V9|Ts@GoC-9zN6h9ZjCd0)b>m*ySZT*A{*Ltkj9*1|;Jo z0KRnfnn9E65DiVWPNLxt7yl{@3@ZQwgmqZ&cuS_-sT9NWghvH+cu z7Tp*3>yum0+6S}Wx4pgXj^NRFpe}UjIt^|gaVd)8ujx%dbRc?RwPt5$5^n8GdShEV zcbUe(v&czNadJ)yJE)e?Y!wSZNqhk!pUzJcV1<&4O0>YG|CJnX;eh#XlUeieJ*{MV zwX{&|8mFzi=YY-}7Hu{p&ZM$W1TMmTDfe!Nv3`yGeJlH4W{H(MUL|POQeEhy3+EP1 zyw}|qdnKNHpcf`b7rX(kkeXgQ{==)cCr8*ksz^8aB>J*6<%7CZ68YOp5AvJ0Lzp+x z%L%Viiq+yn&lB%-{IGJ08m}eu-xS~Z}kyxe_0a$;4g6z%<12}X!!eGq^We>|Cw_a$5u3QQNYOuI87$wmuLw&#x*e{0_VJ z&9QcVOxqcZeK1rmX^F}2vCiN?xx_KN*`}kYi%u@8jJ~N-bBhPErTq^pZWTEs!D<0lA#XXYrptVBs@@7a+ zaXY=JpZ(Zhq-iz`G4a;sBVn zexh^r@v@n71{OM!KbxlFYA_r62o`!Hg<5EOd7XLV_HDj?s`F?73Hy;x5wP+rqA}Y7 z&4;oR?~}v?gT@>jY)8~La~E>@B#$=*O4!!AhXfU`50LkV?Bapi;Aw}IL2jaFAED9b zC~xBrjQ~TMMo025)!{`EwV|5g`rY4+d#y4)0GP<}XyZ7*0bV1>C{7k0el>6Zwb;x? z2g|`ZsrjuQ(>kYOJM9k>lF@8_a5*|aDF`XvA6fZvO~*k=&HFx>uQLu_51_chYPAln7HG8qDDfAv*1E9FIe4XLFRizY%b988m&qhiCOk=Xf3KSb01dyA;!N5 z1kZ(P*5g6k!8UN0ohEYbm$tZ&BaYQS?zW&wrJHZ0Vey(%)EzzD#H>e}LHioi^wi`2 zW~tAna!hXkkHHDUTsq#W=_Zj*+CCSFOi2;AibS)HjwPDvW>KuYy~NhERccxIi$4f> z&NazJBi~AF;g0irsX<$a`Yv6KDKkPh>f%lXDJS_k(O-z%QJGkYyqh&p!3tJdbnDF?j;v2mtbvV zP+VBW41(?cP7{A3aGTAJLWy1Jv*2*Q$Ie&q6nq&P-e&&kB9Y`~g0f)z#IaqGXHUj1 z(wZs3lk|yZFvKCY$Uy#YW`KMnVH13qWSPpgBNuS@P<4S%Gf#17haTFrx80E+pXQxi zu0*P^!2Jg*Us_5KP5Lzs*+JN=Yg^S7WC#MvaXOzM8eYhlkY0z6!YT?Ki#Z%B>PCg@ zf!bGY(8$c}^OiK*Tba5}^k2Iwzat$W1|*DxXUaNM>dot4Y%xcNZ2&ZqhIdOQy`|mr zJF;IJG9olBeoYfMNm8QY!UGQg8`_{S9glvOPi%~KoV#GJ?e1@1KW%E3YG)5V{BGcE z5>OFB-`1f3?w8s97}G#dzpC8*i90HsO>*kJ1fgn4O&p}+CF%5Pabdnw>bSX2URcNY zC=T75Tbb9aPjt^Hdf?_X!JogJBX7Wozj)_dlxriXIk2N{Xl5T7-@Yj88zkGO^HkS?PM9J){mCsf3r&XfYGiVrK1?gpnK<19 z|4M|^_em6G4AoAWYf0TiPO?t@QPq1MRX2{E4D7rXeiQoXBFF293vx@1hZvteP3zd5 z1M~HjitEC5AM9E)|Ea#O#7Wyj4HC~NKYAr%=3T+plWT8b1jOxqO$8}EfY$A#cj!>a zwr)Q31EO#+u-Mj7e>suw^8IpEO8brY6qXl+v6M^r&hh|gbj;&ix*^pJ|k%`HS ze?+P^+facP9et1O*sa0bd&ynB4Wy18GT??3H!1;7Y`)>c@X{3x3PbDjBkE=Fun^lP zK?@zIjzsDonqEs>w8sP+?G+Dc85tSEUW>`bsO}#cWJBsNarHDkml;Oy0-cw_zRpwrQJqD({8Ik}bptEY@yE8<;j=Mc2debLMnqt(fjt17t>AVPHd zytz>K2R9=Rp+@VI9oPN=f23DmhKfM8mkT6T{0>)E7pCyYinN4J(cSx6)BzW>35$%t z7f$lpHpd4yG~pXI^@Vq83Wu*pa7P-0xMF%2+3p;SJ1(N4#}j#G7+wQbMPHmVzM_oi zvJ|=oOik#i)TorHG=oR$s;E4N`KP^xgg^+%DKT{ovg-8*8LyWJ7hnL`_blTAd-J2x zeOx|#6l9hCc?-bv_nS}ER>^a)et(>kXjbG&LV}6X0bt|oy2rubj9XxGRuB4sdKIy} zx0M?^mO@pRqtf6_$kBed9?9&J>HJ`apqX6M*y^(MwN9@%^5C&bY-afn^7j`w##W|A zbpB50Y-1;V8Gx*+(1Ha9s=>kub^Zn7bYP&*(XG#JRuS!$fu_s+xVxDG53yn0o>2Fu z5#by4WNH2q-b6moEH3dSGW+Qee6QS)|p0 z{K}r)-y_dV+&nEWjBfV%un1V){YDb#OZLHCb!V(rO`ow@Ds^~Y{ZjUk$S0Gpl43*e z${-Afx0MJbFQQe;1M|gq zkd$)WMObTHjreO}v|AM;P-`#UMvk7d-Gv4yrXki=oj-Z^k=yDgDl@h5r1mFq90sv0 z!rT_zB&UxKqukjV`}lhLgaoQcIU_mC)*q!Ve$A?v1s_ekvOXS6$^Gf3CvQeXg;#F5 zkM3Eog-v{kt9BNwBBSuS0i|)?`=O_kuXwQmkA2g*-jq?i`kK!ICA{MrfuFuDIy*f$ z<+Y>kp8xFqVA{j6`1_;^*F!Vw1Ns^U^Mq?>ThM#`R3=wT!9a81#Sw6^i=Wy|+7-A@ zrPm(vCJf?1>ZBPAwTsY$OjveQCPAAV`vT|T<`LNu8Qmm+{8!I_5X%`@`WOfPJ3Cks z)v?A|d-M74e7^SYbmCW7^ zDyGMmTi;k&J)&>)F;+#S4u8lXQa7rq)Kjg6BQbJ8)NJwT9tQn07wtalA=zZScdV=_ zH>^}On5F3So-CX1E~}G6`kfd1^`J=uL*qi`i+hwnmFy%SVJSR9H>!<93I~AuKNX-R z*(6ZMg;Qx0PYbB|0=A0%`zC|3%^8(w@BE-QIw*GZZ)kPV1zS(DEy2+)L@Ob~Wi)e`24^f#0oCZ6+i{2^;&& zd_0C3NWNwJ9i*^B;E%q`Nk**`u!07O_#Mu`=oF3H-&~)G=e|1>?YWP?XOod9TrVNQ zd&&PT5E*!q?&RD2unK=>$tXRvC;A_e7ZN+Y$nbSSWl{&M)l(rueqyQ$kvVZ$n67cKR#iQw(V;rdP zf-iCF9*?x!Tc{nCJKD5-UTKX;wGH>AmZN=4c3&>eELKgFwt3@HfJgkOJlNU=RY?RK zO@(_TfdA4qxSCyZaUQIf;!a5tj08Z8^c5UCn)`MBF=DHU-t`BX^Sq@yRZQ6zxOGG$ z?Ss<^Vsu0%Q;sl9pRW{D-0G6V>Qfsxi2$uanjbN z^P8A}(ma;>TSg?AMJ;z&l)I+lZ<+c<@2y;FATRQDS&8<`62VA&lrxImoTs2VJMYSo zm|K6|(5UHz4bg8*LazAu=AN9G|8l|!D&3j<|864OS?&JsY&Ni0YFQz879LH>@^pdh zN9LE>Y^j-DdQr@eDF+j$|E`=$GH`EALos_D`E|&x@b0xK2^Xv@@;N$+Hh+C%7Egmo zQ8`}_yxb8;Ugf1ikxQgj?QH$>UQ-FejaGnAoH-QRTT-k8Qs&k0XjLh=d zZyYl5uy4!VhKDf=d|4tKX>a||BdeiJfu8YPYB@(2#9tZ6q3>~j4ULnfBJ}hk;$VlJ z?nYe9xeIp+K3chazzp~os_7(Ym0Te|-!6Kq?h!M5TgYRnzWX#rwtQxPbT$z^n$x_# z;5PB;kAA-5k+RDdpgW?S&Yt?rpxL=|>G@(a%e;n|4=abV@iT}sYA(RCUUq4$`e|LI7 zkf5mur%?1+3H0QJos(AAyo7y(838qvgfNoN2UKY$m$yKgs$yrq$(rE)R0QDS@%|Cn z2oj;FWu(unUD=`N`;h%E1!U%f*HZMl&O=65al~GDpxv^^84l6tc{6(Nkd^V;lcWbg zp>8>8YwKnBV(BO{+TupU`Q%pP3PUv|XeeGE;j4*lbo{jBM{&>fcmnXW%~Ce2I5zgU zTQ&JTirS?DE>7`Gp_X^ED?s9Y?d@5!3N3aVfcjHc3aD-2PV17~iI1;q`I}YRGWc$$ zI7$stOLnAWSt;jmDUJ(@&xsK+G$9F-hW5aQ;f}7rJ#YePs-ox*VxsL1Gq%53lB|`p zlUJTr>Bcl>^Uy_Px-4GB82dp|1n_}dm?O!7$^T5~59f*)MPjd)o02jgiv;ETMr%KR zpqLO!a(;zuJl-wg%-@5N5FO(KaE>70DXe}Nr}%x&Y1LdCvQ}=G`u(2d80J?j1$`)tt0a_*2;_Hdk{0m2W)1NPV)QqRZZfh1C z^@LfB=9|^UPb+OV)M>?(fR1^R%GReJ=cG?Psnaw=5H3As{(mv@l>Q~~iyY_;p{m7#h+Rl_qMv^UQqhe z?6JKOdE`z*2VLBr;IMsyY&oo&Ae76D#7s2%sup|v7hv>eNfH*UOspLBp zA-Dv5w+oqqQ&8*#Gd{-ixWK#hPA8LAu;sk^OZE=_R@%_+MmgkX`u9MpwNU66Pz(^W zxw1#+TF)D{udYm<83+w+scbI3v_DCCu{|cW^ocd=bXvz%o-z?&1S7x;XZTUPZ0p!e zcK;omN%bFYqt*M*5`)OvtHs^0T3_-sz^`Xl+Ui{asBA8>U{`a>Z60E@vLu_jONF?< z9Fx59xsf?cML~bVa+=U!ykA-GL^pyO$p2j6Uert+fW|d73TMoG|8sO2dwSOAsFwow z?#%G?_q)0Kd7|vr`Aer6#{^K4fxU4S2G7yA+X6!-Rm-s>aN3et+0mwtT4^IWP)Mxt zA8@AsVfxKME_}~T#4h#9<1r3QX&u>HCz_W|(oeN?%!|7mvl0a8X2>^ZsrKz=b52lk zRB*W1n2%Po&XiecVPu)UxL5f?Qp@rB0&7N}D)Ptk=a;xmv~2{Qv>N1c?}pv{%PX5p z{jSlrM3Q0#Q@Ia1s|M|mE*21q7^-v4h1o#Iw&S_*TAl(e61iYz7@!)|_%C*wwB=Q~ z+(w(!4;+i#@>C~Ys0lY&yPIz}zg2`CrWcnPAB`)o1;iv!-s z(gRryrgYmT=;l}aa_DNFfX4!;rLrfyhq>Qw4%Ig_L??0BmIqd8*g|ZtzfT(L6a5nh z!ohK4>=8xJ=ZX3G9JlnBms#ugkNVVsQXM|$y&aq-wk11@l27;E4yVK%1UPF6n*3px z#94US_OkiCWgl2La&&Yw$lC=t7^+gFnU;d{sSLM->aU=Mfl&Ebt>e_XDZ z_KT2+dpQ5;{YY1g`>Krz!)j_`9okJ?@)Xxwl`A4~*=im_Z`Uc@$c=`3_MCUK?$*kzlawiHQCV7b{T02Y(VUdgi?H%QXmkK$#Ti2VUuiL#2!{kv7y=Asx&EiZEn#gC6BD?8f zM=|jp-v4cnBd4%X|DP77`|84iZTJPUp15(mrg^NHKmB}|#?Sy_;@78SlPtX8e{n%9 z(YW+0JGCrgx|(n}Y9*rDsF!xrdU|qq40U@O9pV9r{s5s+&wmhMSZAVdEPYL3ayC*t z2JDJm0Ig1d`nSrS1riVT@dOXMiqd`sN*Jb@E16|+^@g~0H!=DiV9F^?+wO7&_khD<-}{hGD0iKk&6F&49R*5Or}LUx;RYD1UJ8$5nk z)i44CV)hCC4UotcdM~QQ)W^>0*l0^+((3&c>~vETtXr2YRcWCkHY>VwZL24Fb^Ph4 z#~2{<1n0YWZm>&^JyQ$CNp}->vFFC38$03*^qsWXQE6Tr-1>Epxo^zf9be)&v1hX@ zgzNS;)-Iyy>8}5~Dxpfq*QJ6yRPp8NylTYjK3S+pws2Evldh}Wzn%T|-8)|afqg9} zDZJxy(o$qZE3GJh;Qx2(DIUk<+#_g`Re{A-&bkCF{+|M&x6EQKaS(tfsn2DmB74cr zhh^Tivx9gsPF6!l$9M^d)nIXVYxl86`>E{3OR%w}58wH}3AIlSD+voRwHd@dmbWw! zwnE4A(n)$aF1(@I&|k*ie0PYRrL&hB)|#RSG5@_=Ou2A0T-HU6K& zbjPZ>=Bxg~DA*P?QZR!kWbl8BwNtPLxvYPuP`l(T)zO;rI}9!WS`@+oP}`EU@Hi{H zMCDsYby-IB^_E^VJrJgB{@Yvjq5E9vomWT_4@bXb61aL3^{ts-zOX8lRkN##3(3XB zlf(SL(;wRxG`Hc`3@t^jkjusLr*Az1NJd^&EB)1`ds{i&XA8>EX%!)lcpgONqm>5e zV(#)t9wPy--DG0S)wTeoaSCfuQ?~LehXuUNB9c4FFHA~7Cj)U)SA$_ z@`>8vGxsA$U6$9e2CiiWR|Ca=cH7DwHq!;>n;s1RWW4qb=2pgpBNkoJ>2iehGu^t< zi8@@FO!*K4OEpsmhpR8XNl@orlPO-qdc#t59U$A{CHSEzb3o|jQ zPsp!H|4(pX*k(#_3(1jFJVm_V8$%5CI!hre=SZMS%~sA~`uLUMM~KYn1yc$$%w&pn z*Yg*#daK()P0DP3{%7U1LZg8i5k?3aU8^F#TiJ~A-95Y|7-=L4Oo(wjeo@evQdP3alLCV!rRLo6XyNl#wfYA!Sd9yIOusV{meRLSVD zn@=wj;tVGNw4+t4-~X2T4Th9s4iC5~qH9w2cE)K8_qN}!-M9liE3E~p2Dkl2>goQ9 zZH1e`jEeunMiRKh(RF5+41<8pX%aE$?2wxBu`1olH47uesk6r3aJC&b%x-f08>zM5 z0Nn~cQwxzHk^A@FPv50HZRVL6p&|xrU!4tvs|(BF$!QGQI0)OM?bW709~H0r@-P2ZF~Df3keB{mbM@uIuM9i|} zb{S}*%7^n1FrW4aRoBhvH}YNY^_RqT{Gs<09@$yL6501XD%4|AW&JMO- z4WIz9abYez1OdwK_s9C?gm_>A(*T~tbhILXbdb`FJ5$!Z^(Dcdbl>wkSej&0;lP_G zYN1S@I(hzc3|`-1mId4;jj1!-yBkTL&Oz|}(JwaT$ED?U9eg7-T%B%>#&YOD)3Wm9 z+h2nhEhil2yML@1xc;5IrlO1DV^ClgSBA#?aNz9`dulA z89IQrAnnQacFR;@zdKCxj^2XHc%M9-$YTC@9k)ipoAyUI!>-QK0QUw{aZZiYYICvm zp#1N3TBXP4?41l|i{BTP)h30J-QQdt+wa!nQBI0g|1xDx=;!}2eBC^-mwiXVtO$He zT$!lVP8>vF4vdQL#Ls=Dg{ttee2UP|U*9+$S>GF02=Yy@?`R zgeD5CyNOUa0PTL88bGZdU`l+WW@=YN+kU(EAj&p3A#*Rn=Bb0NR(xd(f0LW)%wcx9 z)JaFX!_7_Gy%3uw)FYu?yi-yAt%F+rDK9`bkh)w~3KY=09R_S<`s`K{cj4xFqwl3e z@F{X|b51;2>v5FwD>mz1_>%>_Y{S>=Q9&l$C*7#U#c{JrCjr`L`*L2EJoa6m;JIO3 zAFA~JBmsHYF;1C3NOzR_5a7*AnKJf1NTGbvixN=P+A!`3Hu)m;$nn&-ap0UwbqcAZ zM7ij65-y)5{<2u4#nQj2la(5tw^hZIL`3_+o;3!xk{wUq;P3AbSRJN-FXocCI8CJk zR}yM+XVzh&6H97FcPrb4?QcGj)aw=7X1}0`TPh3Jo7fiya9X_Wm{GZ@gd&5~GQxl_ zz(bZIB9t1vXQ<&m-yC|DyG^`;mPsqM`?NQ#{vy zGAQXJ(AVZ_sG-5?H=D#b!-E#l#;*P0ihKAwx;%DsBtkV38C43}#Ij!UzY6Wu>fN7A zyC;d(FF9YGnnT{Zb&}l2CA`J)r_E_ECwUM{AS?VtgG5bgbyJ2|$TzCe4Qwy(fSo^EOD8K+3TGpTxK}DX z&O4VJX_3YSf(zn(T7NpDx);{OqW2CnGiB_)VZD(E5L@Pda*aH=hr>v9uw~1nL4N<; z*xBvv?Ho_5SvSa3#AkT(aQpEB+4m=7lWt#6p!e_vo$uy7GZ{Rm+?TY=+}XlkaSHvU zWd+`}+XFQMv@x8iV7oB-fx6+@NZ1ajI3oDuCynEoP3@qEoV{5eLe?DFwH9r9zJ7yk zIo!sS(W*|#;o=|O`(+78TZDz;YNT~j+fA~`QX@7trVVpETR?AZS3W?;H(;RsadsT- zWRXOSP-P*8T_22vM7Le=ZbVXx&DYr@>zDxm()lGG&hATq#*?k6YV=u*#DwlyczKzY z^2U}Bq5Ro@$)5LXR8^aXK$l?%H}wtPr)QzbXZsd1%0O(Ev><^!k00W2Yfu@p zNLTLl$GPMU#Yl0F?WdMel9L+?@8p=Xs<&QrZ!8+OF=-^ngK_~#h(%FuVQmu}=cf}wmT(k5W zYI0^Z7C{BzBGsZFy>}0v9By5IV`#e_&VeoXcBK5Ff0IdOmddhXEDH#L-Rm^Zo&NCN zD>E=s+7nI5SRZj55M&uF_7;|0do^0Cs>@%A9q-(4`g}fK>H8>Q>%FBP10eZ_Aja#j z-x&)03xU$rTWI^eHrV+@z0{2tDxPp5Gpg}*u-M}h)ig13=3>7e;u%s`wSNkrH|TWh zKeSDAi^k+CV}R6l%|65Vl~r+7#clBXK_wr3re5{wm_pjekynE?9U9zJjC;`1Is@YS z^1H25I@LT9R--kv25+AP65MYj#%Twdn6Yq!YGD;ElA!n)37?)InM~+Sl(?xk&)>L{ z_fHa!UAT<;T|^YyOUgU<%d>nx9{(aGR1-1J8fkt5s5@z3`?t91B-d*W3&HxEk1m3R zZ=;-Lh9>N3!fbvM90dKpk>(d z@*xnl2SB?JF3#{h3l}g2vyQWD?dgKfQtP(kreKXk1VldG=Z*C3r|L@XiRq5&YE;u{ zoY7GF+m?#1Iy==VW<}|vd%qk*HbcNHiqFhd#?CZ4LqOgqbV=ISGepS#o#o#9Y_KzC z`P~5eW0kh{htC4npV6awQ@kMeUCb1n`|5YhJ+8UBBJM{DFq|)?+38522pwIRe+S+P zE|@LeewN|=oHI0Uz=@Su_H(hY#+-sk7WDRLDofJ#Sk1gQX6;5KnhXaDFaX`Er@Vt9 zt3)=M55&%qtl-P*kb?vNy{w2yZ3OzB3;ubvy^?lgNljP&Y2{O8ki)dsVD4)aEr=N; zJXL2;xJCRg0I+fvqj;NN0JbgjYidOZQ4Cgn{v<8jnPK^+W1-E$K0ZSwI`hqbU4$jp zeaSh-dt-k*49JR3(vM&~%7`#6{8BzK2tc8hDpK&>>>ca)uV zNaVPic+un%lXjN*RJ1c#B!W7L&!Nlbtb4A?tcu`%opr=U@sa5XFcfL7KNR-xc#UT7hO1s z<8+}dVEf347<~GoPRd2ja~ZGX;1Gz%&gvWs(4q!Bf`$Ln|2)P08G6R9i_WZ4x3dwv zyjT1s;a8o(-_yC2D`|<|7Q?VaCTVxwMlpUDS1r~8L!xdEN$-zUQJG&-Kg99>4WF+U zXk2Q-%oXZYSeIFjpc+UcNx;)~cFMJNkVJB@~x!T&ebyWZHfr%_l6b66Z9m2{o-mxzw*ucblNUnjPidk?*8P9HF|U(a4s z=&1w9UHY5C@Hj=72FaTpVw~2|A-xN%z{QzU0?>S^WmHwE!_zCio-VMF;e&c7^WM@0 zEW3a2m&cdQ5Re+leZ@E~q**#KwZtX*0r7yL^KmP$#9epl+uRy9$LWuZ;z(_~B!p!m zoaa$JFZ3!_20yC7r+;MZVp>m|JZ%;pW#5J~Tzo6N@9Fd4x_aJGT}Uv3XJe$`7P4=! z5yK!QcCw=d=omW?u)%7;TYto-8c)#iH;^dPZTX!toVR(S+p68TIXZ#-?^AZx8H2i4 zXe&s3`aCdRqMH}Q582#AvZ`e@j3u|UNTeU$!)fh=&u_G+-l+Z2V9gM`C^=z`r0Jv{ zqD2MHKsi%c=#_;9Hatf@SgEy&?N&uVm>7JN1)gGKpo6*LZsqE_#J zp#wNk<}}y67-Xg%yi4{QZs^00y0P3MzGyq{NTS&Ba)x5QyErr#zCw$dFo_o|ys?B` zotq;mO~m#q1pd&4bGG9Auv!WFfYR2`goJ!biSSn?G@69H*dnn@wf#U7wUe#3x|Du% zygm?kyey}_wiW4!(}hs=dpPQZ>Ej^c^v>n*NEeZk%<$XZ)(4d~+ccU-J#_M-D+ z!&b1PNpt1)Hn-bxV6D`wc-y)095`F(D?m9kF{_E7jY$FR+$Fd-(G#8|QCn-6Kr^{M zA0rDJxO+ZREdIexxc@08SG zE(W)I$YkAJ8O3lLxy@X5qC`HsK-GxM2Wq$gjL8>^d|eZg$`9Hwb&p?cOAhD;$oyDK{a6b)= zeBN?+n&VF40rfzAcLB=N_NhcVgB;w}^(7&kFs~w)?i61-zkS^J9yoEL_RJeqU}}j{ z@+I!ShH0M1vWXP$NK(zRVS?o_;bC&Yw*}qdn!yv)$n*ho!TN$(Nlo}pA(>jT@A~?T zKN(>37w+XSc%)-hu+C(}5`_rMG1r6EyVcbp>1RXKLemENAB(FH9FT9_EI(r$^si4- z4_K07(go0)edgyROnlX2lxrBAihCC4Tb9x2%A!`ORsTVw3qxP~u2EO^zL{e=2l>&9!c>j3@Zidk970mg0GF0z$m^e1Bo>nseMxU4W zT7s$3HJHfbIfXugy->;7fu1a=T-qMoUgNYqtiih5Gz2C}PEO0XTWe_latgex_o=?qk5_N76--L&Wb(S2nwb#T_%Tb;$f`0ZyVjq+bjHrALtEj0d|3A6afkA~NUysNJ0ui1wJw1AR$cgp4Dpoh2cOjxqSSU{r(J5n#lVQ#wQ7?$J z@EPiWQqqcS^_pDJNL8deIeeUFzzEN=@KAcMJXmQtxo>bzQZ-r!mRt!MTk_tJRTZ$H zhS@Juen351K`=$cB?z7h&)Q@o?m%dvGa@#AoM>u02(PX9>QLwrBkJ> ztg6INc)4FxyQEHCHAWE+u)9weawSFZ+Zfh`zLvsWzWA8#+5yqfq`?1VXZ`CAT7l+v zY*kmboN0MuKU>*A8W#I;+|5^W&_V4I<$EA`Q*K2o03H3_BK_XlGAoWt(c})8r&R}N z$%XFq(|Y@!LL|EBw#1cJa&MqK2?`rh9`dh71W^86C!*U0Y`V6AcH(M_pVH-@wtRI{ z!v-Vh)^6AsF+;Ugd(P?rX;!2w^^QGGg-(L&R}!G+q@nWSx|z=X;F<W*WR=}}J^*|Pif>fW11tsNS&x|JQ9&9f=yBb6UQU3jEBCrm{-DA@bXPKK zVQtL|%*S`_&@pxKvnn!-&ooannY0~p)XfAi!~ewq%64CY7h?n2O^P_)i_h=gYlpDCNcQeEQ|Qp|iP1xg*r9u~aAb<5eBRpK~r+ z|Mdn&E1V5zd2sAyiGGWB=23hW><#c^ygQYthZ`seJP9P>_vz{_IM8=$Ucz3pGPE9@ zZ4~S390$zLGX{#+ABt%9(~snd5_XSke{boD2h1qYx{ADoNW!r_p)$Z!!f z*^h%6m-#js-B32KXO+BxrMxvd<oJb}n5!_Gt$+OZD!Qrfee%I%`mk9kJMJV z7Qh+Vo6^nxmOt?375p6chn38!OiU%(PaVKCEB;YUbDpoE-YG7|Tw%lyFo#ji`R}Ot z**rhOGWT-A)AKkQuO6^iVW(P-ur`zXCSr$Od^fl5Sgcnr+kGomTWxQeF0}huI;Q8F)4=v2>jE8D=5GC1@0!}xj;K6s z{Xs=6;^i#7bgL=oH(=wqokS^5wG%X75g>9xbEpU&U=P3yZJ4tSq^`ha!Y0 z4KnC(E^+Nwii$GAZml1_$I#c_^fe!V{HG)#ax3XZa5>SW`?xp$z6{2w349IIBSr*Q zM8IdG$t27=@tvx&SgUGLVLWM);W&S(xd zh&`t6S29x=-tYPcIGc+9K20qJEsU(9vg-aOrsu`c-`vK>=-raUHH@|k zdVU1K(H6kLAw<2egf@7EOJJ>*3)3B=W9K4H>-#rPIrj>bp8XuJu@9(Z_>vj+&mIZ! z?!~Wr{grWCdy(0+tzBSkFeAh}sUn_Pv-;>+*j(m+vwM{tqRHZVPs4!O;r2h&alvNlBSFLvX9a+>*ZX0@oW6 zFW{g*Jp+Uv_&vTqi2H6e7i+kB3T1R+GR5|KWeS?aXTg5h3{SXU>q^LknRT}9N0^?* z*S!y+uQo)rD_?SUZQ63{90=;|#Tof^shJN+eOwK#!bRl#%Wk|13Z=Tn-?Ra8xzvmS z9Ev$?8cMc5v&*IThww^4vJ$EGqU@fjbpo+cjO`aLgzKW;qgPR z_wR)e1ihJC^lN_Z!hm!Aq~uh_(Nc@!aR34l@RBLM??AWQ?|MO)vK;)PTCfOaz5fN{ z;vnS7CL7Bf(l5tnpORWe5#HaH7Z^QlT_1lgR?$)uN!CFvU?1Tcz}+rMpnL6$k6E*p z2xkKVDku8UxUB0`u<+9MkEIH!U0hgzj{f+<{Fyjg3mk_6wSob>n;QFEilt)x>656K~oh*^pw{U$Na^PQe+U#yC zq^~ANHw`K%34%29C*7?7{W}xnH@9_Vrnn|!+m<5eH9jJK0Nw26%X{!mmV^qzB6oMs z&J$$sucJ%A7;Nn~ZF&*gZf!k2mCY>IQ>CJtEcBTl(jCW?`r~WGGC9ABl zXo>T2nS!U>Tr24UX*O`4a6H{AoF78~Ki?@uy3_lVmjvN}R#6ZE*Z6H2Wx=ky5fJW- zckrYP$sbwO4WS}BIsG|^aDuaGDDXXPH8L~alST_(1nW_mdzB7gr_T>E zD@K>d?5+KE5||WU1$>`8dz;awemfY^u{Y62P`$^cL_TN{mXM)v{5c>5Aop zdmXHv>eagxEd{;ZG^w^=c6|fPNSI zUo^goR?hOi7=*liAyccWX{~Yo1!@B=+xx(z!>*ap#VjZ4zhH9b(|PS;g$g<*{j=M$ zk(<$zK=J%hz<>60x!S+xLBFyN$0qe4DFo6=Q&SJ;Ku5wbI-6o;cN#d_jA<%YBBgFk z@pbCUmBRf;0N1i|0pUX;iS4d9#xw1`d~;FbH|uFQd9ZBT!EW5(?-(3!k$X*D4|3dO_-ZPvd2X#VRa z-?5#uM08oY^S$7V)}^4ZpFItW|Q>=c0Vg6K|R4 zCZ57?2IxVfwhv96^5Q=Ysdbf zu4!ZNoHPgnflQ@){!X;Y(rYZbZoF8;xS*@9DRvr_bsi?56A}qT4UBb|@+_Ou5ku)*rV4V}r>_O6Mp|$M$Qg6=#r&pY1=K~by=&)mqGHOrB5QE#l*q6K zJwlx2DS$0j=pVLCDCX`BiVh*>J|6^(>&ks=KhyLUC`)cvQ-B1^jEAadx4%@)k3L%m zw6_Ps2EI*hteH?fWrSG#JpY}S!#C-Pgw5%GNX(+Yb~~UUpGot3-kF^;T+^tDtTDL~ z#Bg!SzDyr&Lj79(;p;AOXqs$L@G$P#RgryA8B=0tb&AJj^$A~(NCa^c}nWQET ziWY$AYj_{y^#F|<0GJx|Yv`Zh>!2EYn&Fzm(ciuU+uJ674!he5XP~jsd;H)E1!YF% z;Kdo-=%J-2-qAjz=&jGlEN`=K^WWOQC!%us56h?}zu&axwaeDI1u zgp1av086zT%OtH}IK|nqs8jh1@ce5vU*S^8w&OFbhDas1QWb1JlH=v8vI5_~4<~oiw=v?(6N4rxYvi z>+=+BuvH~hW{g%RI^aeG$NJwHJOgqk*yQ5jMXj<2Cv^p^{daswRHlfX+b6X$BqJG$ zdM)4nXkgKd3oAo>aUkda&ZYMmsa%KROX}j#hj0%c(1q|6i@5uH=Kd-+c7B!A(a)L! z{G|-rDmMYTOw#wWv4<=1F(NkWxkd4wbJbuE`m4&b#+M2pqBUHcUk3nP>LmppDbo>X z8zjzob82px>2vBlqF<8JwB1@Rh4t$m?Md88k%?7`s6r}Dw9w9FKhr_!=@Ym=wsU_+IO-v2dnN&KR!7wh*!~=E;i5#-jita>-sI@Ni*a4(Q-7z z*!>|bC|nIp@C&x?CJMv;G>H&4F1&+aV!zxGWdgi zP$^GQqPv6dHHp#<9#hKmV;A{@s*@2i7In$PL^sqXoTq=U5sQ0C{e@ zCL^K|cJ2Q}cCqNVyZmXUN*W{C8E7tyi&OXS9Wt;2Qce&=(q9OfPUlmM^O*BaTJWTH zT_}mzHZsyJ17GY);Bam`Y8-F5~U{?8>-wo+9SN$&g*-3 z+PGaUqEOsoc3nL2^1J-`7XLv#JS>G$s~DDWKHewr2*nclzar_-SD8YX({a9Dq#zv% zmTizx-x`mjcIMBtpOzK)Y=|5FTYH2KBvo>@cl;x4&Aht7l(` zC=4UxApa|RlPE$+s8APCjQG(jig+bf)xg9e3Z^0EGFVtKZf%g@^o)ta#V4kLF8^3* zK7Wy%mdG9cYR2zANggmRgA%7xsPhqHkN^;$1Q8(E!m1SRf8~Q;dT#m(cLmbXo@fnA|fm&iAHtr?4ZWZ<&l}U?jk+p9_thOM%Pa>)6jd! zV?q-me8wOr2Q3?|eqrpxFCQNhK%2RdS9rjv!@dAn*{=k6<`QKEwr1Ih8H?x@SV&uM zm;l*zaGzkHO;a8I0RvjFXcA1+)$DcsP|v~43YkYykCYXm=%L1Pj$wZfEQ?&O|f z)%ITY9m{8b01=8mLR`@r8o;I$L}F(29O(3Vr928X_gn%OVjh*~d3@->rtwTsBY}dwio02Xgj``yf@xD(gM3fixpBod1>##oL(b9N>j7x|`YJa=b+AMFpxaOl|LO zDmG~84dOl_E14ajpxjV_&c@voSCQ*dET+6xExn!3_$`@9y?0$RL`z6CI|FVhh4kY@ zsx+sSw5In9P^x2M2w9Cs?MwHwXY3i$=3o{`lyCjsY&*oLU_z7hwTmmwmr%YM+!Yfh z9g2}O0q0U0b6H*apUCcIbe`=}qtD9t_GkohiU(dC_(3$$BhJr!m?6^Qjgs=+_Vw!W z_L?fR{=frZ+0`$kXsXqN+XQ#iTvwq0|p$a4?)o74F~@|7%6-B zE90_DDYkF(&YrWSo-X`TY0F}?G^^RNn4V{be;@l>8mBGoZiA!TL%T8W*s#< zk8s)&AuP5!rEL369mBRSGXj9m#1 z8+^YS^w5$#i$s%p6WXL!C8T}+mXR77KdZE#fE%wTk;thSUXz>OQOcC>@469%W;F== zTJIL>)6S1f#ho?t7?WeW;~5t`rZT#lD9S0T{5v8>y?5PB(>)8R77#>!VYd~k>X z!q7G{`zt<0OgA#`+}Y9TgK#>I{9;YcwN z-2K8gH^$VzdIizRONdlhzq<>G_WL^=3&Rj&Mk=UUU9QKMB(R+a5;x;xNDlAowomFl60)o}~+tIq6DSsl_! z+bs7yn`g09{>5lR?l8XG({~IO9s;mLu08{3pv21UOTmUJG?w# z-}4^yH~ow)-g9%E+~gt)jg#EHDy5(N6c8GUiH~fZuei^U-||*_%=Gp7brMxo7aCzO zx>E)~GBQnk=N6~b>15atOKHqa=iV;8yCK5C>(vU=v$uieqj5f z)9QT6LHpq?Sn_0ii*N(n=;ZK5Uv+O@MXjdZ!DdKhPHnEn^$cZ^($_M`?<{1Xm8+en zAH*S0XFk8bIBp_fM5N-_W;<5*+Q@UU8X`YuwV-CTx1|&RUR5XZy@iB;zN|xR-*0y7 zVss1x_&N}Di5XBiFj_LCed2S6DXU+cH5<^G(35MM+41+ADr+41>~wj!TV|3bb&^7N zu{g)^xK&4LTU%Qvu8{O+PKrBcmdA*Y=YBZFYs~B&LBD_UMI%_ymZ(} z0rdo?d11}Ej;6>FO4uU%osESmZ+|B@~H63(|?+y6WK_W#iVXi{8C3juITJQgFWz* zvFTG`cramvv$H{XN4=rIT;0&n0k*3WU&`gOH};~sD*{MO5daL}Zu*@9~ri(c5 zBa~&zk!iY)6*3_%_ETYGXwSIojLPEdM2dt+GuphF_|(ti^U1kMynubypqk3$-m6z@ znQ{~uUCRwj;zY;&xW*(|$&AL5^0b#7Xr6{C9c{;HVNMBcVCO2}W@gf7&fi^_* z7<+c)@jb`wsUsscMQyiRHA8d$jUC~dw%E`o#V*c*4Gm3xh;}ENs~+3CZ?1RU%H2PP zy-KO5_}IIR?egP_6$})qH8t{c5;Tf_#y*K?sG>>I!;esQ_LkGde-)>$wm(;W@%6R* zLE}zYyX%tt{sQb{)xzHRYn4PQX$qOv-gSEsLRuUL?jYz7>o}V`;yIdlD{m8b)zp53 znCI4Nk?RK3>Gn!bEz4)+)RwZ`#Dx3(YNU#4Ls8%UZq0#*aY1RL@M47LYU^Ojky^U) znk?W$ao@(@Gq{WOTLD5Hl zJfq+Lp3U-&D+O1Dv(UjbBp`vWDpd%T%H~ z#BMwW0hNW>%$6ahlk#yoXp?dE6w+ai8-pw>50EFm)+M8Gsxf z^P?WTwozd&3e}L6j?{I}pBNz_vR{miX!P7ci3`~q(LIr>^Mz^^Ox0nQ;r8sz=B3^@ zL8t`H@Jf2dAo8gs)I1eOsrMW{>Lxl3LG#l??B5BV04J#4>iEq`BNu)5m4yCsG)e02 za;-U}(`K*K2dsV+Z8cu2#n^;N;%KASDWtK@aIN|@{F5&~Io;KIT| zLd5?~=z6h|VKnPIswD_D49L2L@*3oNIR+b_H&Skli|=FrPqun7toC=PzIZqz^&R;MRD{5v%EX`NnDCI6spnR$*-`DJSAsyZF{1pJb=SF0xP|Lv{*0*KDOx>IjyfI7@q>6UFB) zzQ-$p*#LVVtG6(OCzD8BcTr;dD6^6oob#snHx;#X>Ev|R^%sP%GT9pX< zN}3$KL=r8En#VK&@OQ}m1Ra`ai#Lxsi_uD;lG9Elu=ID1zpa_J^#}9y*yyXPkZ4*- zpFh8wFZMwd_619apXj9(_}))kn+U)k`r~}YlLk56D6vnF1(eoK&f3}Ye+gxpAkWZ%L>ux~O2C!rX7FXNaG$8_%uPYY-99|+sG^19k5&MHh zm9MU(6}BN|tJ)fyKq@e@hso91$UQSmcl`Oxtlw}Z9(;}b(|+kFSLcUDg75Bl=d~z) zH+vdH_v+uom+OkrMj@yoD>=3^eD`{c^n(2l1k4BOmqc1=IRRdm{Vic$W6qFLUE4+u zp3|h33rP4GO;Jj%sY*B>S$xC@Nk({3vh*-wl*2~HnnDGT)3L&YPoxh!bCzO|cMYRS z914*J1!F0xsdJ6C(4kD<{f3jW){~3ftfgl6o4TzOQ+PRpy$&2fqZ38?x<}ttnd=XL zd@CZk#*K^`!ec6(tF7i*N_Gi>R5sL{&KHsCm7Ct7jyCihxLU4zu9Wr4$RU+2RZNS@ z>&!#912y*bv+-nQWBdk|)dPP`Gqh|Yi}CNFL~PRqP>9;?l1iaMI6IAPSF%Ror039a z&!owI3ZHMjaEecdi&9E5cu_KoI$o2X1EL{OV~bs!8H5x@QYAKBm_#WU=y(n|NCLu4 z9Y_t@7K_sG92mGAgB@k1?_f4y*q9|_V>eLM_ZCvp${q>Nt21Ldfh)?g7H3FJs(1OM*v2AlNs0EiYBf1&CBuu$!n$-ic|B;b?2z z`^hhR%9+>kpI+m9nP}@q!MTdz!U)XSwsHz3D22j}JEp$Dj|5&C0?*W6Hvi~Tv>Vd< zBB3YRO8J!h%~Af{{1hn#Qx@L_g~GbqEd?$!+2N{x=X~;>9qjY zH(wK^!Qq?24FhM%A^ zlVRxQbY{87sae(ZFfvJ6;W>GIYH?1};)nFMBrGBYn$6aRIVv-pMaaIo6uYXD3#qXUEa?5@ zoW}=tyLqk)nXFd7@y4*$o-T!{dDgNE2P^0E-+@=ZwG=mZqHcsO2zpqXa(>C7gJ-i) zWB@_~0ikiB)YMZWCyy1G&lhCxKkR0=+wQ7K>y6D%feGuh2j^_-3_;YQ@tNDlHPEw)80*a^va6blx-J*LbSg|^K19@u~g2?D%GZB zExlp+1UTtNI2E6QIXLP>rnm;>JkhrO<~;S$Qb+(&X{K^Y;cjNm<3q_F=iRcb=oth& z8bcp6T^>1+!6{m|P`8YaAD`22eeT9n5mV1rV4%@uhJ&!b}rU=cAM5M;l7 z;Zfrd8omDJ9TvuJ!!f!`q3#1Y{#Jx?X!`DsX|p2iSXcbk)@Zg$Pnd&tc{a*GUyLdM zYnHsg!&Wb?<@8Vf1#kg9wP5)TFy698L^7pSon1mG4>We`??m*RIN5QVPYtQX~lUh z)|{?N%KG1cdQp)nuk|tjwCo2*daC>;wcE$BW>$K z3g;GnaF$}b?5!|4`S1BzW}<=L*3X~}urN}VD}vH-o^X4f^&y7lbpjvFrZL>+@q$kK zUuS!;v?5OQlgHHcG4ZXq?MNJ7g9Hh7M0%&kc}!)qLM7Wk>`*{2cic94eZ zGUJN0VCygE?rtaU0?^9f@U{P-TgDpj7ijX&7AU^1T7p9`cLW#esEdUYwcA=EEv9XE6cUNk4F5 z^4l|?am>bnhTy@uiJO}swA4ukP~W5RzH$4zsHRFN7jKBV5hXYMCu>T)He-< z&=4a|@hnT73c}X78$C;xJ;c*}F!57JPML5AK+xMO18fd0C3P5cTmmOt+P5`IG&$x1 znH0ZO*8da^ZMvDAK?Hf=ni!o)5E;_yV`N z>;yI*X|3(rc>d3>Bgo)Mmz&~B-TOB)FWLn?LZb?|QgB<}_9Pt~mC@m1cll-p^jsp)T;anqvPW>wNFheyrE6-jAz)%eDWoxsPD zb7ku1;wl{ryTfd_YPcb9J>+p!PvhsB*2B(7gg16Uj294aqI$W0FWGJR>ql|r+OBY7 zPU&zKx9fMX4(Suoz#v6jR~LkyxRR-Dtk~4Q_+ojSnRaQq5NnelS)EBWENmBZB*iCb zW%cSnUr6R^)WZ)lSU#xYX2i#!|PW25b#24B$hKCtQxl0N(Du{8!*#-~hn?WDe=wleFAw z*xXUnPN45L$S6cPOE_@Fw1w*k0HlmQg{OH-vD*^`6PP0KzYI0YM0stnWin{D_)!!L z?%D0ZeFwq};M2jZ`@d)>mhV8s8W0}^{;8gPJl@VLKICeAs6}vWDA)kTM#e_^M&|l3 za}OBI;tb3JW~^rfvoJF9GsabeFaA$JbWBLZwWR+NVDj$(m-dxYU%TvJ=WJVZA@I&0 DmQ3U& literal 0 HcmV?d00001 diff --git a/utils/catenary.scad b/utils/catenary.scad new file mode 100644 index 0000000..ff879f6 --- /dev/null +++ b/utils/catenary.scad @@ -0,0 +1,53 @@ +// +// NopSCADlib Copyright Chris Palmer 2020 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// + +// +//! Catenary curve to model hanging wires, etc. +//! +//! Although the equation of the curve is simply ```y = a cosh(x / a)``` there is no explicit formula to calculate the constant ```a``` or the range of ```x``` given the +//! length of the cable and the end point coordinates. See . The Newton-Raphson method is used to find +//! ```a``` numerically, see . +//! +//! The coordinates of the lowest point on the curve can be retrieved by calling ```catenary_points()``` with ```steps``` equal to zero. +// +include +use + +function catenary(t, a) = let(u = argsinh(t)) a * [u, cosh(u)]; //! Parametric catenary function linear along the length of the curve. +function catenary_s(d, a) = 2 * a * sinh(d / a); //! Length of a symmetric catenary with width ```2d```. +function catenary_ds_by_da(d, a) = 2 * sinh(d / a) - 2 * d / a * cosh(d / a); //! First derivative of the length with respect to ```a```. + +function catenary_find_a(d, l, a = 1) = //! Find the catenary constant ```a```, given half the horizontal span and the length. + assert(l > 2 * d, "Not long enough to span the gap") assert(d) + abs(catenary_s(d, a) - l) < 0.0001 ? a + : catenary_find_a(d, l, max(a - (catenary_s(d, a) - l) / catenary_ds_by_da(d, a), 0.001)); + +function catenary_points(l, x, y, steps = 100) = //! Returns a list of 2D points on the curve that goes from the origin to ```(x,y)``` and has length ```l```. + let( + d = x / 2, + a = catenary_find_a(d, sqrt(sqr(l) - sqr(y)), d / 2), // Find a to get the correct length + offset = argsinh(y / catenary_s(d, a)), + t0 = sinh(-d / a + offset), + t1 = sinh( d / a + offset), + h = a * cosh(-d / a + offset) - a, + lowest = offset > d / a ? [0, 0] : offset < -d / a ? [x, y] : [d - offset * a, -h], + //dummy = echo(l = l, d = d, a = a, t0=t0, t1=t1, sinh(d / a), s = catenary_s(d, a), offset = offset * a, h = h), + p0 = catenary(t0, a) + ) + steps ? [for(t = [t0 : (t1 - t0) / steps : t1]) catenary(t, a) - p0] : lowest;