BTAUNo_AiDu}ZW`&WL^5 z;f`GQmOz*Jn6`lv&Jf*yJw|zuxQylZL6!=DDQEH-2=YS?_ctnTgd0@U8!Z!EyZTli zZ`hTA{N_ov-z ool%^Q8^=2eY6POH+? z)RZi@Yj@s~Ti*#L(Pji3H{TTXcu nvi;?Yo6(L3MBW #a~(xPzC=jlbcUPxHA8?1thI}cje{*2vmdj|M!t~ zO>s($dig^14!I|;H21xK)3E+poU$B7&XC%+naVjt;y4j);*7~6S-1si`EOUUoppSd zTg5FR-?y~&+}UC)uv}fckN^#H wA)V@)+7NXc6Jz)mKZlb-`ri@c6=ga;g6M|n7;ZX z6zu&^wO)1xm)8UOC$-U mhi&a*Gx;d#HoHnM$KS#v<#VERg6p}}ppE=h=w1S>{AEY2vYq~1 zq8M{yo&+ukHaW|p8082VHmSWHUu05`Iw~MwCMKOf$oy21m=zeZmU*S74<|6`J?QRs z^bfJzJ^#raT6 %5$> zwK(s^{_cFdaic ;kKxuht%&CWwn>JzO8X;=_wG!Zs*05Gsj==`f%c;1^7Z%M zmiM@WYrU+o*L^*HoRcS$m}f6ElM0%ixq<1IK4$hjuHI$3V7fVc(3^GD*t~G+g`#xm~Zq7#1cA>Cqir< z9xP06W0Z<5T%evn6yANJXE7Y?%_QIPMIW8zSK-E!3qnNmtPR9F5-I0tLUc2*{}}}_ zuX`)c@Ms~oHK82L1iA~V3RH}|2)P$#dgD2Pb%rT2sX|)Gc{>{8CzA`KoQaxQQa59Q zexI=@!ans0{Df=`uLgLG(?T&NU>l8~mub5f8;bar2P$`HI(Z^B^2 z!*2-WZrXnE+dL}K%^N&ATFSrXORlwbz3Xi8*E{Gz0wP;lW?cIHv(ul3jfWYo{(|rP z*x8*%PPk|DRr#SCBKCe)UUOa-#Uz9lgK}mj^JTWGDI(ABTb9Z$s|@rH&Ga)2mShNa zf0LY(FfH|E=eO*7dos6q(4o~pFChqVwewGm8hV|^=z;yE(}1n>efq1c`SNf7_?}5d zJxcI_3#QF966UO|jQnNdWD-!5TuTh9o7f0X*F=JKWSn=Ym%r*vs}{V3L
t|aRA^}O0iqfwX uIZ051I-jjs4X#eJ z$`N~)w7l=V+ ;y@RRdkq^@&^siTK?kRi`b zD+TlT2tmX8Xjg}m@BRC(gk%FIx}F13LMHhVZDZX-m4gH#@`cfQLYb^&3TgGTYMRBk z_@sQW;J_?ahieoi5fb#nqEv*2TDf|niQF;jP9U0I%7E*~1FhuI(mz944XHhyw(OGq zjlB)ppby>7S+i^?wsA7pu5Xf=iP=mUPhq@F^sRs|Fvk@(?kjhFrLDiD{#IieR?E+g z(yW5RU*${{jkfHr7DBJB^p)U;{TA{Y5c*?JP(yrK8RdprE#q}gt0PxQZl0{E^YfC# ziIzXRmS1GHP*`hQ+tua2R!M+j;=rqoQ0tdxe_kV-<~;d+7U#}JHQmy+H!sru5}3v; z>HV~X-L!!zaS53_YtXmT#`}a0BJPdexb`tT*6st5uE)1;>%=v5i=dFA+^ytVeJFgS8Hf@@PW@z<`s`BhA_JXXkm{pJx0!q(n(#FR5 zW?0#gMuJxk?ipaL7kn;1syxa6@;AP I95&2VMv>eNXn8b4PgM*tk-0 z{dIRwxov7yPSQzdlsSI>JePFV54#V c(Hv3qmg-tJ CgR+>5H=mtd#w4~yFmzu}qC4B1I8J|`XlHA`_5Uq+HP|Rcza1v$ zf6#RuTXP@rrcf_QU2y{e`jV4E(DCL8oDiDS7JKsj N-U^mu(1fN(na@5m z(n!j9bkrae3f9%3w85_J5ES$zt$80y43+zEm*gLt2N*({_ex5>-)!D0Z^6Lqjk6O-0Br=emiR@QHOJ_w(8e-(uHNy0LwIu0f_q;u$r1 z+?w2Rd5l`?-w9VOP=co+FlzR!fQ5g2(_>p{{p)xAn)O~CVG{5mjz9a0gBN!7mfN^9 z<)cB292KXl@e4m;52`5KZNRUIC?Yx{qJ|!;uk+UMe*HbPh0&3pRYrY!W9Q$Js0)=V zKDQG7r4wh*Mc-z^52Y$y2fPSrOt5qFYu {+MdI{x=K5AtM>PD zS?;YHhu7XIuNIcrZ-2SfmO2icnY#0xKcP@TQ|Pd$N4? zks-48LWmHo2LUf6%xg$+@1epS{4Z5tu$dPzuvs5-A*49v{QBB$XQ1ohr yXq(^Q_wgB!3eAgG1y*1K}R@}Um_gzj~QK(TYlIc2)ZQ(O&C$kfUY4x}} zweAd$osWv~{-TtuQ*(KoybD|$_VsNAisc;dW}=x23n(T9nFmetZ8MP2tIaz0U3Zi5 z1a*k%1b9p-h(EOJWpXV7nVew*|KIX>(oDJAVp(BTwSE4|vQsvmQryH&7h8}dL-rx= z-b%I}p2*LL?{98i$B|KM)`y$$b@w+-t{64kDbh^}N;h^Z{pU7(U2ZnAP*)x3=jLPK zi>3b0mt?u`+CQ^T)jf#w`{B=jj^B&C2W2HK#T$KWoiNa&H<1h=3myfvKWZA5_LgK; z6KY|fmvG=a7Uoq6&u6O}nl2jS3R(~U_Ijf}4Nuiz2Ph^iDbRZoi+ i-rz)lAGvX zPdS@=zB-%C9ZcnGGAqXOC=8xlPz^&egw>m(1U5WwC)BGu%t;9~)wa>Pj%QF>w>j6t zIbaVesyLT5NsI|GevlN2B#X(R{P`<;y2m{&3*^n5Zd0$9qpP=iBs`x3k>%EWy+^UK zxsmRE<8SK7IDQ}0j*))U&xRqQYAGMJ23KNLPNuAAdxy3RW0)~*dJ;%?^MFnwR)Rf;sf7%W`rl&YrPBx1yMq>B4s$ifArO2Xjy|(I<)+;)Ri6 zM)@g|xz;yxt-t33IA(<_iX2bBGV;`r%0x#8IY^B;drX>V&srk8x1DE8T5!Uyje4mM zTf(rsavFen*}mkey)QGk8FF|BZT0(rChDZIEpO=awo~h2n$K-ljU>R { z21NV&SGC=$1cD)HwN`9jwrtLq_E(;DyLx#lQKSnj%--E^r&Su7U2+bVo(HH^ml6s) z`14wV=U^h&^;Dqy>pF5~(a{o@*?lkExrvb>wWXEo3vzirWp6PCV)HX)G1ijq(4&CC z85zvH&%-$wF_z;lIiMXY0!qtoUIs+bSu7HlG?9)?uq@a~3~S +bWT9+#_9jq zd2kFn$3(GPj)psL+r*@?QFR9=XkAp=nFO|*EmwQkt%P&5&=BdyrFO^hucnF#Rj3Cy zEA3;qd^qN_q~n30MVgG*#Alg>ILb=voY>B`HNb(ZX|2EiEo8K}toyR4`VCyj%g)U1 zzFI%UNM(=x!XWh588~$b7FqYkKHR`>Dg3PQO*QYl|I5Lcyy`#E@+TusQ1%H+wnh*r zG88x{m&%rnnTqyLfaQhZX2h2wie s^3dP*t%o$R zZ$~@Jlg+f_JB{6j08je!uC0X$u_sk7rf^`wOULH+4@Dpn646gP=IeK2GbG2_MqEXX zXbMf9rq_5ZJgwiMAB_TYn`Bg%*YXoWQU}f}RP!ViJ?9+k62fmCOzk>1L35N^k-CB~ z(f$W+5UVWwzDGZCJ}}Ho6-CQK2j^&1L;9tEezKu&?k-e|Hg{h}rZY8X;x3vP+0U~b zxL{SsSQKU4T ^RcX#>0ps?rkKG*EqL!TQ%REx+MpwMTFq5#7 s#Y`{9P8V|?U4}XY8@w}wLmwCFuH+0rqznz*8xLWvbyZjlO z7T#5e9gVqbRa9m_7sbMMf-Oyvi3VFuWRfFCtahXjvqewk^Pt(=sMQVWu=0OJ zCMZ?}6wihPu*qVrkT=xG vWO?=c;D=Q&v`%DFppWjTa&>9z-me#A4^{F^tcUv&3^6Q zd0E=H>V9Ta_(8TuMVGv($9Dwfo@@8aTF3Yq2_ quM+L9Q>Wu0*Kwi9V3hh zMLc)>b?f|>Nb6BE(gE#`*AtGG*C#PoHg%^PF_zcs%s%US+1VDTdKdIz(5{V3(P+Vr zKL&0Lx!v1(#4VX3aW*8C;(H#i=y=DarVM-Sv|qU$)OPi2vG4 i$iGH+I5vNr7Z|fYunThI2n?J zHcjht2c>(n`AcE}Sg3s`ZrXFfL+sswP?e|e3JpCy_?du)>0Z0Zb^bP_yp?0F8R8p5 z?nOo#__1L4 c 9x%PQ}x>=vG $;K_2$8ItQxJ|mgs{64J`Fvu(}spw92zVafz zyg(qN>|JBG(XJf#!qXToy=LKj95w9k{7sL^q&dk0E&WeLgT+6!RYl4k;9(nLvZuR= z2}O#zoYt$mW2` L{U05+iP1{e9rW*HcrzB$-_y7r{F2I$JH*2 zg^IKgxllfOmORZaJ*A>6LQFyVd`wj)vLm4CsM GSt_ddFcJY* z$jM^smod>-et+#?S68Qx>D8h*wdYZzYG-W~3zS$^8$xsQxhhOPOLk&A{!}(tHm;Rm zUiu26K)(A}K#jKH!bN|8Qy!xT2{qKiN8T|{NLN3*Tlj$ADskFGYoAJKI$R9;O49PT z+7ZT+*wu?- 0!_co4M~?S7R^QTD)-HNV^nOjA^v-3O W7kUKUNv*GtP(~L(y_8X2sZWxav5+p%-v1m^Bd~P~GWxZ?{9G zBp1YEl~#$568XE+p{A`&qzNX*p(Kc0>gEut+D*q+Z~I@InS^>Ha-?No-fzygcQ1c! zZ*X51RwQQDUC&CMwvotIYW^3-zpG1iH6*n)su3Gk 5 z)bJdRW52nN5^D#72R?yPWk_PtxZ fZD+DGdLgK)3&r=HOs@?>L$b!;CQmdB7fjUDt+Ni>I5;5=vxW&l zV{=z=E4G!h^&DafHY!XzYrwtMB6aLXij-b%xIFwU71lenGg;X)6QNgGu$FuHY~abd zp1Qq%wH3hvjafQ3M(lGWTj2-z7uWm#eibl_(>+UO*Lt>t4CQCvk!|;D`vo7MX}riB zjwk%?o&;Er4>tXzrgq$LlLrvbk^Yw!U>Ti&!%nMmk|uL|wBGRmTbt%9i|D3h>re!x z- rVHI!iq6xYWu4de1s_`pRjpRQU< zmeQr!#MsLPwd1O5>+F);b~BE2-z`NqDx=-R 7| z!Y5k>C$vjL76j(*jmtkW6ZmB0ij;^GMl52?E0JFWg611$SuF-}3C+54WkuUEW0>Dw z6^I$5-akK@eLwUT!NS&c*4)8vUUCwZFFxBL5!#6^oU he!;e5LzkPW7I+cneW8$Xoe^YPhR1*Vy@P)a zm~htiP-msJ{l}N(b#Cq4N319Pz@;nXiJy60LLW?}$dzs~wL8?QgL=*NR^zcrR$k8U z<4TvT{7S3YSs|#v59b&|bAHMDb&89VI OmleQYl6796a7%kgA;RIPH@ii?UNK&6t*P- zA@1yt{Lu*gHhrSQNJ;HFvJ6>m5*woRH9eli&5)t_`q-i6DeT400~34WtNqP06MaeF zsmrpS4p@j?E6?yWiz4aeqjBL)@G+2(xIf_mwInFXMcg*j(j3 =q9g? zi{~ZizAUR}KR&@2%cR$idMN`8>{ c3pb*+Dmdm);m7zmaVx9{yduw z91Vdpq(9O&YO{^tg6c!vupIA@Ug6H!HgjQcG~WQN53bFSAe#`chDDr(kYlsg{RpW> z1nZ9nzZZTlkRXX7tJ_TJchbU*%pXzO@cjMD#IGHl2kCQ9`NX^uEd9=Dzc1_1I@@^Q z^ViKZ+velbp4@${gVD;j=D2=%A(EY_g(y)q^VuT$FW@O{9f@XN$Ktm_NC!d@-QZhN ztp`vuqO@W<#pT(rZb0(QjA)(MTY>PnLhFIQd(jk;yzxeNsCA4!bVSgV4a&A<-GA0* zQ1;}VP;njAjCv0{KCKxf)ybW|*DneD#AWv~(M=8{ZZe`F9C%ZsU2-q&_an6+uqm zz|6rKMoXhb94a$OZ^9cN?JJAQ)*>)qZ5G@L>UuO0G^j=(f>F6p(O0rUZd5K(m3Ff) z_dxw96F;0BvWZN>>9twYHPVTYBc}?V6*hMZW$F=l+R;dvEj3yA*6W OGgxsRQoc&I6n3j*RdF(IQWd0JpuxK3i>$0@_lbH6D zhitxnj`?{vM$xKSFaPVlQPJ&b<4ya+zVR$e?zYoOGg50Q^NHLcHQl-6cy#AO85-n# zdaV6J)q1e`$(V6tuFF;h?eqZCF89 1@^TkYsc~b6?PKq^lK)Kry_O%U;2!l8R~CG z1(qv{ eMn?5W!fP5m`$;-BT^ PC|UW%VWpmLGrAYjwxZ0VwcsvJ`9l3tGT55yrVEHrJGNsL1=DAVTJp0 z_$A$zIR>%LCdCS$zxrID+0y;#v4@7ActFO~?P?X?zrs9Cl6rvx`i{*#^)iKoVtU7+ zbl1&|@M~np?-NQAUO{Ev8RLatn(beA+Aw7;X7=z+#Iety>22${Zc-xyx4jl|yRN_A z2Pz~b-ioWH6A1L0Kl<5TN04A@P{*K`H!_aaEPNDmkHG#ZjOzXeW8SW-}AbFYq$R zTwcI(DA!ktPp6{6-mR|aG&559i$BvG(_Q)HF~CxmP8Vb#ludHW;sVFSNM1n)Pi{C? z*wlE8r^6)9asHInO9fpCBSXgNH|d!vvKlJuBxw5y3Ieh)>?Ys5cZweDp%)Nj7TolS zeN6o3YI&*e4?Ip wz_WEEvu`Q2onozUPP)9EAw$>zV)1d z@ycFbh6=>P-#LcUc5jWY3{PY#uA4dnCh~0ax27N1<=;4P3(0czFH&5O@{RFCa#^GU z`k|88o|`m(clNJ@TcHEyW!5lM(NPOAvyNuqhz%Br9CyNUWKY{*IiyEV3dQJ~`XID) z{6F_I?BeAL>OP_*ih9dmZIdezH2o+`6`&H)j>fePI-szNl;F3W)c!G<#$xptAAi#& zA1z9JCsX8X*8x>imfa5B)xiJU;q)yhqpt0iK%JCEQp*U%cB`sP*}fo LX4SW=$nCvQ{7%({8^)5T`FfuVD>9I?I6aU?=xjyFde=7-vU+UKl{lZXY_0I@z( z`ASd0?g-g`)6qk?f?Xi`K60#F13$aIEK5UVq3jqxZO><}dhM#G<%7iIeuWpW86>y0 z@_)}9N|NMhu|WU?4`BCbwfs}o3Nh^>+0GUW_<@|puA@6CF)TkiwAtI-{j5gJFM;v& zos}dBzf~z?TW)MWik6KR=fBo^jM{NqO2B=F+pNqRI`&NGRblu&d|`I*=FD67_w9_! zzk@}V>Ktj+dyI~jH@2yx^KSpwP# ~|?()qA2xcu&_IJI8< ze$Mn1zu$AlTN$+fm`lU2-BsiVfu%7C(cN1K4v0kYcBHFPe6O3`JO~s+Pbn&-41l@o zFPX^#28nSW$J_w2AP^@MrL&?ULbd|Y%RPAGIL6ZB8N^_s83Jp#V>n#7)^Uc9@tRiD zjufj)0lVoi<}cec+`<1xIm#YKr2mr?pE>WUJ(hYe?y#;nQaJ__{LhI^p5RE-J6BJ* zWs$w(qBos|`+KvEj CSnQ(5;h?X;N6pJD% 5Drod@8rS#|bImgxt@wBufx!PC|l238E3iO>=q?zc2gREU{Vx zx2JCML;wdexJElJ&D`vvAi{Z=9f5c@TFS2A#P{a!9J@(?+z0I!x7}AG8_PC+Kt8%| zNcUVmmr+yuuVJi!c3j~fI!+alXfir(ai`MxJ7&%=mcxGOE>9^!K+gIyM8v-@Sq6#S zwo{xuAA0T3o(ePn6G%4&1c0NM#+tju)fPDEhIn(Q--&o!nZm9aWj<8G2R9Os95xu1 zbo%<%oh*oHP5QqLdj+9-uabHe(*3x}(suRK%)AQQVT k-%9Jxa7p znsER>`*P Ms%0n`?OE$O#HwEYy)U0SO0Ot^seY1m<>`4l%r-%P2}6{(*fJ!O!r z8vFe@AFvnSS%q>5MSS5EKODtV@fKe{x8!^NV&n+TV;wX6&e|69^yW|mXX|w=>z BE~S!u_a^;C(k_1zI-uq;=&&m9g?H+wWIsG^V9Kd( z`uZ~f6uYtm(AnT!P}2b9h~9{guHI~3JB}lk&R3S=tP*nlBlYvHpv}C_3i@;i2*19_ zBq5%s5g|jyM0gr`E2WT?ExB1ccp}Xk_OW>^GK=j=S6yt?Qty1YusaLq-t{5GSyw9~ z+r9o*z1!q8%=E$HALV8b02nUuQtEoGxLt6*Vc>d1>Qv)DR29Hiiwz}T#D p)7uVg3qeLtgKyK(8VrT|dDhZI2iIe)85o}lfv2gj5qyhL7p;+@oqmfa zgs&N2IBf%>l`wb%D2IA~7_>1m*I=_?J*bIc^%BYx{J0=t4ao3f#T3gjJCpX&< LI)FVZ2aBvffvZwTeYfhI{OEON#vm2>@?a*i+mcl#mOqi@ zG=jdQn3#QF+u>!t$iItWM*U&1Hx%|9Ab|0Dr|zZbDa#Lz^*eit^I0iQ`|Wfl3soMo z{?t6>v;D|_)N9_>d&((d&5%2E5x+F9Zm5|oC&b|v1vW_)u(nMW6=?sYdtJaZDP16V z(63APvg*}h0F&}`J7;~Ked3#w`<_+lEGkBDql(ZB0ka#Es@S|CZU%65UOjx#fGp9r zu|$BWXE ${gqKg)1^_I<>r-YXV&yz-o*W)Rv0wZI zn)d+giu`VNj%x{ov{C8#a+tXZqYG)_uNM1;Cq(29g4X`8_Vhp7RR`dqYPZwX`Z~dM zWe>IEw4;J1euuEZF^%TMB6MhQ7o!*ynxxKl{+vVC*Wi`=krTG774(~6QPvDiY@8t$ zD!-jgBNN?S`{}{6kKNv8d&@h;bZmO~W3jgc5H7=z?&M-toxj24)9X If`<6I%5zbkoXu5!1iVUr zj7Dm=R8Gf<7Af&1y? *ZfF)@UV1xPjCA{@ AAjaOt<=)%Cg*MnRI@;`t zgP?H*-2eD0toAngHSDuX^JqRP>TUD}9=JrO+a!bcRR^_a)$lBkG3+O@VA>=or1)C# z`oXo(z_J+xp)+d>OWowjz{6I(uaN<~t-^)+5ohf9hZz5~tkFv4pj||o>W#09HB@hu zI4Ke 2DOq=(- <~YCq4E55Nl2B9B&f|2grdU#B*s*(4tAiR 9rdDI zx^u!5>$=v{#BSxpg4uLqe%Rk|_hTONoizFK5~}zDj+t1xdqnhmY;L!h6GxoJg(!g? z{mX8u!E^Uo@b+KzBImY7rN`7E!e~!*s6oaShu98 =mr9QXf|$rM!fxs~ zbYEv>n|%EtHkfx34&+XBMW)%?CR8LFeilUdTupzLiN@N|HEy*AGI}!c)E?U(g>zxN zEs+h`qfc)(g9qK&4@ve7;_;Y#fDv1h%@a5HxLodLQfR0f+n_w; cP6y zWKb@hE_X&<^xQTC>LgUjU#jU&UzTwI{(g34f2AhD{On6zDqEwbg|l~k3XKg5Z7-pL zv$_JTJwzC~=1Yqj1I{12+~5Q?DGP*HN@>lTobbtx7Q&9_EIsOaBGLB_=!3mJ6+ZIB z3I+&z{mA59J%15Tw}RehsC!!QSp8K@PqIXOXDoD0`8{(U*rd;=prNgHtY)V|4W+IQ zb&ejp@kWPDTaAt 9E(<*h;8r=5$XAQ9Xua5<#E;**!huPxz_^0W==pz z584xpH5%nwI(7ImS;!&2y8Gs?hpHo5c16 ap*e`DsX~tgVV&|^- zZetP2&dVO%Q;ik+#o^$u1al`kll4*6AD*90nlEoj3zdj|O%I=AyhG$XY;cu3Pzov> zF;81hU+Fjtu?cy$Sk`y8+&|O4)5)dH^78?QuDcjX?dBYroZs~WxAx_Zh1)j=XCcdz z$Hg5qO^N mC zeAM{2Hlr-~4BX5IqO%@N<-ccZCn%Z5x@XzvY*(HtGr7FC7%1zAwN8XJ-vo(KJ5^&7 zmxgBHnL(K`-lU)LMIU| -pufYpfL}h((I^_{7Ims{GC;oA zLF69yRg{epu8QD^vt`)+3E6|(b~Nu`z{k7VCjnEb7q{=Ee!`dt`-|$#*9d)^4$oA- z?Zz~6rX0zYxRo
&BiFghVHM$d1BfW z>%o0l!h%5^_ub`5kfdKXqfdimZ0(p9N;#M?jZQu9EwmfWKc2|Ab4Dt$&0Hx7z4_@{ z;yCITwt8TmP`Y8HfHM?aJMFYx)f<)IExP7xQfAq0 LhOxZ&P9`2h3)qOH>-W}+6%Q_fR#szTa*-%$KlYr5$cjC6n z+ni0Ju!!Pi_gQa?LrH~L{zrl7rT13sqF4%BZoAa2N>-S-Fi(wM*~+@lFs-Zy%c87) zyKPx>!77i;@deiU9NuwKmgoxpbaf6&k;v71e Cb 1kZFI7I`f{JdczOsYc8yHE}MIQMd8&?OoWi+J;h#iemb+NWl3-aTM z+&e9EGsv~?{jv=DV0$Ck#7g|9wkGaU{We3%52O4zx1F36A}trv%bmib*n4n5<2SJ{ zrS!*mS ^d_W zo&3zI;-Xy4bMd)VOWcODiydawo4d5HGA$3=Q+-up8sWIDn`aG}4^5OzpBP!F&G_gc zA2r@RI6MQGZ$uGMOFdnU@3{s*Jvz%kS>8 =GFC* zR*wH2WkV?*Uy?4E=tWKEeJ>w{?dl{H*gnQY4h1)Z^S(co9}k GBLC^dLHNth3vaFF)!@!fnyy`{HCX*)vT}HII>SpFMZT`b}pfK+h z{StuvfU=o@>r;aQ;^TwcGB0f<@m-{}QuXzy>i6W@IICeT+(u4PUftkz$Zz=HlcX7f zKgZZjCx08g yIa|E=ybW{%o_lHNGaH(vE4E zHMd<4yXNZO%{$?>KXig>UG0)ExuP|OeI1iW%I10G__Y9D`Oq1tC*3_}qjk^Z)fu`H z1RA@kAv|>%JA(2d_^@&0Bo4*>mxH@jNv+2;W}IdGS!enudvcDXaA(-n38vaS>->#= zgyY}2wN5P`W%aB5KZzYHV$46Or7lM*s7?AV^WPNC%-`nfW2Cp&k9@mhI 5V%3$++_Xv@RN$e(#?>wu0k{?C4qnC+52>m%nc&Z1`Tky1EieB#OLIFvC1J6#zKW zbwVejkjSy+fjiD_4} (r&SyMQVo_z_~G{bX1^W6+q^IT3HnE z<(tHmJhNKo$X@URA3D$n)W0&)Y&|oLb#t@YfbBdOGY=DJ_(m0g1_`wV?Xbjc3f-aK z_@M7<|8Q-MGyt)EW!|r&Z%?TTX>Ix@odgC+=l$1@!m5+LH6^KoUH`Fyq##JT?LTN* zaAIboVv6?Rj}+s71={!^Y4d*#KsXNpmDu>#@dq62j~m!FSQzwy_3;hwSKyC@J|5`D zTNOE33M?&93k{n2a6?-LDz@)a=jp?)I+XPBJ{a?-lpepcwm*?gEM+u;8S9gH;(&&& zffd9?05xF>meqD5&u@XMBu1jkyQcZOjnbYN5rS%nZfM*UO+M%8ZMI^f@ukk=G@!s6 zD^lEqMGy#(=?c3>hT(#&>4A;?*_&*~^*ph_mZ9w8*7uz^3?_$r0pEPb$gTS;X+gs` zU~X(Y!o>*p&!>vlQ>IF@+jO`#x4yI9Bw{Hmg2&f=@S|^~k5Zr=IYXLpK-N!zKA(Lb zvepvse-JEeIb^1Eien0wH2p-g+OUjPzItcRyiX;J2W*4`V5~m``Xt9Q?necS3nZ@| z+eG2sLxVte?O~j7!e7y^sKJhd4PB1`GXD1D{tSxi>>3}GO@HIr;<;Dzt)2(NdBhRU zj)GyLTT!1Xv9QO1?E*L~Y*Da0E)9qMk7Ci1mAXZF<|WOgo7bpK_7EupkDW}7_sh|Z zo5XiO(n2YF#{m0gnGKah;a7TTDRmIg&Y94-aCW) n~=cwOVhDF`r(cny;4kbTFE|ZxYJ98Qgjnb%8hM0+h4?9O;iGfCoDJAbM6O# zsYe>RtUdOuu>xgp75%F<85Zx}o_gA7M kb=V~9l6jz3C|D_Z_X*T|cTr6JDK(FBXN{?+`9+mEf vMNp=pG6^@~TX_M9iyBT|+aD7-eb-?bjTO}5BUP>b~*mf>tLaMy~ z%oLzO*#t4TAHKQ=w(drZnf-*eUF|$UAqTHaY%Gy8&&Ib>z5M@` $t(BUlvuF#Son z_>bte-fr~TcH9k-zn*1ICx_>aE|=MUhlOzQ;>M|8R =_eA%{e>Tu#orecZh#)NtwYO~~Y`!d4b3am!n zz+LT=xs*#j|9D{t*PZjI?O!I1=@LgL*ndcUgOC*d!|Sc<{c=K}RQb&|H{ub3?*n3Z z6Znq{GfMh5|IP!bT?FvnB4@v=4XbLQxx=RIcC0_wT(g*N)iaIZp-K5_{f(2l`YWH4 z(93dC3|eKmuPF6z%+)dfV&*1$zvkV;gN1K=x7`jxAJI*&pB78eimx?&L751!M%Q_V z^>qDLA@zYS`TtaxS)GRm|Fehud+n?LSIeCOE&?tO>t3 +Ler6Zb(A4flV1 zjX$S$|Et5dS>g9Z-^DK9n7Qv!UTMgtH&5PO-=p<=LG_(m&-m@XTq}5Q#p*A<|L5O> zz}V55zo+f@Y301x_P{m8K$*Atvyx)^_p&of&yR|=Tbm3%Oksi3UcMqT>9Xic6>7P! z_!bwWMCg8cRR240wG&ILGH_WrZ}Zb-tmeBjU;h&Vm4-lY1z5g1NP-K0hJfaKXQIFc zF ^=rOo>-+8byZ3v_%u4?q+z$Mb$#&a!{i!?#> ^P}}>mUoygeGr_yuX#nVg8HS{4-wbLffhP2vm4-WxeS1FKT_3A-hH+OfuoVLYvrf0HZw2n(_m7&rRw6l0{vFc=#%s4u zO9^*F(7?Ong}2-quZ+MyFSU%YbW c=Jm&^F4CmaYjhVAkfz8XE_wSl|?qCja z7Bzo&U;9`}_?=b9_C_ZD0Uu@qvJ(gRn0oU+f9GRqiQ> $Z#* FCl62Z@47nt>wmTZz`;dY z!vX) ZR8cO3yPDht}7fIEA^j0 zc(2c*9 &(RqZX^OhI1ub`GurUcyv= zwGe>S|2$@+0{zv*%~qI7M@bbV;pk!s;$dZHWv3EB1%W_9E*9?u)Fq|=*&TK#Ol9Tf z<|M$z=IQCl>iLG%(d9iG2R}bQ8#^Z(CnpQ61&gb 7ZMyC7*0-7 zOw$YgupKRtbk2KK@Eax^S|T*)6-$iI!T3jua^_XCh!|?MnnpEwMvqr7Bm}iS%7!n3 zUMrjy@--#JCezOF>@6f2CWV;pnoa`i+rPe!mMdki>6v$t7pqp1kEu4tI7%Iw#iMBV zQU56W65LkX>iWD|fRs)4qmW|z!h9 mijuyh=l=b+Cx z8@H#m)es0_>oc#&!`1I;KGL3~F`=8rMy0sltC?fGo?Pc_y-jJ3BGGft8&%C&6e#&T z+)5%>1jB-^xaN+I4#a`Oy*Hb8a@nu9wQa6D4z)6m3JDN?J=1^z|5F~3y~?`+v{-X} z{f@hLnN)I1pMIzq-=v4*vMK+r3Hm6tc_)ser-wGQHLr8D^hIfeqVr&{*m%D7Q9_U+ zWBAAVZD-)-7?XAmzrW+J>D_%7BSnG@+g?=seU5FHVjf3+SHH#S?bWBGK>uqKpWTwv zpGY0Gu4Y2l(Mq>VB>nv^xX6fe=yMLjwNnce`ko%N>Bju6pM3q?g?K%$$(}9v$*^Bu zt#1Tgwug=!>N_|(EOXV9Q<(XdI+_`?9{Bu-IuB1#`2Z1l9`yAz90LxR)K!T6FO8Yh zLBChm&aR)2R7CFXj+?F>T56JwjcJDIxBQdI)r;%b9#)tFwo2buH*eWH-cOSahqBOW zYz)t)dm1hBo&IJT%Vnuxi_%BiP>{=sMcck?YAcd?lOXkGT}Y6l`D}`*`ldbb{8wP= zLil-iXo8ALr4q9dM}t5sxiJ%K+fM3*745gTuD4r1Q UA6K=ot>HUw;V7I!Un%vx--z7rJ z&daWBewW;$URQmy01m53iG`e1uAdKA`!UB0x4Rd@m#5kk50l;6T=A>i9W9^Ii#2Cc z0B00WgJ!qu>z$sH61k*_^t1s!y?B?#If4C3?K*Vs2DwM`X~vJ`gMJQWsRK=~(r;Lu zJ-jCiza0(f9sT%OU(Z`~TAGmXICd<`(O_=7t8QRqHsm;Ip3`mfjsIz*kK*}>&G@>z zs0!~e84e}!ze@?N(`oBVLpS-JjY}2(Yl<(O*WXE6voYLcbFsWPL`5!ppWUw|kPx`1 z4Q{KC9$~0IU);9i%6dt1Uw+k~S1_*ac(BkEW?W=jdA?k1*na!uqfr%I?IX#AyK!4u znSu*jD$RHH6I`YC{%Zr*5K<;P7OB}73O-%`8E%T31Y=)TEq^W-1I_=l7^oHV-cN4y z{ic}q VWCo0Mnz3OxZaVc=kaaXO{m2G_2n2z$>*283&((1Jh{EsQfZhwu= z+B*FIK(2i)>gPT3GuhsUxV?7|e-mBZVsO45%WZh~xa0pb8uz;VMqYtUe=b+V{Wx9Z zY6glUh#7cii`2+9S4UGxv!#@ByHEbG^qit&wr!puBAm0@;qJ-yq?W*&^i#L_F6Nn7 z3v)5$zh?n#QqU;;0Xz&5eYfwi%Ps2H;I`Q)0vVv+4ZQ7U(`tYSRI*Tl4*KS1&-6#L z^`}Q_)1R1Jm|WXOO9eW-U5_5i++NJQ5#evhATfTvoXJ!2pEF*rJrwX8`Mll=&-C}i z1IGbBjl9D)6C;g6=b+TvZsLfL(fG5Z^5VK8iXtDpb}u{&pPfo6j!}!1{d!b{XWU`H zU8`+!mM;w5j}G)($>#hI(7cAssphiB?UDE+qme`dxsr;y=Cw3B3j{?bR+o4#1)b;f z(Q!cV|18MjU>wqt=a&}boM=gyZTKMfY$nrT@xOG_8uonRMbqA9X#!Mg%d$VdlY>>C zMKB>?XTsXAeye5HHfK?(oC!DbY2!Icn1MZ0-?w$NX~BKFzu!y+Rg=PhtFQ%fX4TvD zcK+^LrT>436od{;oMvB(q~U8xwI;3b5bQSpLnnI~kcUPXwcjYtzPs)6$Ioc$Yv?^* z`f2^Q#y; 3JBic9ZtXDxdTCh~>LmW9RM%3v z@@{`KL#|Hbl4oF(S2_g7LnIvR#f> inF ze_F~{m@DAPI!hy&T^n5){mxY(n dnf-G+lrTHoemV)xSjcPuT^(#5I|u{!ZZd%Fr=apZ`sa z^P6{n%k^K4*8Z?m*{If?wkhU>Wz=rr;_{^O=hu|3g`4?Rck-#nJK@GLP4~t5yg>WI zrHDDd|6`V5k`YF>ll95|^hw}nVQ$*@a@-AfmKfjH!lEKXw#mN_ZlDw7RaX3d+rFz0 z8Th@zA9=Ex-z8`)VDM_s=FWX-i(P-XJ+Eht^p5(QfB#e`AcQ~Y88x-6L4Tiz4@Pet z(62tq8eBm~hoJL?&I_&VBILHoQf7i#6t+;jjqucZihj%e 39;20HG2dU> z|BvE^-ImbTQ0_XLEl&5(WbIU)HkW$}EkDL}6n0)kc0SDyma^17&_Va+bzI%2ppSP2 zyH&S-4nKASq#q|{X6kiPWO2G-2IN_tLeBHU23xk@)py6%faZH$a@zlq0X&YZU@*E| z0&n0|dxEg%A$P41gVXvDlSn2oo1m)g?A&=?xYm1ks`K=zvA4s-$Z%L|*2VkKSTL!& zp>5mnjc0%N*X6$Z)u(U6Be?G&Hlkl_MFZ~)4&=xTYgO6)cY4H8!C+y+pM+`~v>Nk9 zZF|}|9z3K7mbV k0qdrZ+Ciq8A^OuhS-<-gp2bd%G_3i*-nT<;*bJz8zu zIKdS0uzUWl+O;e`AxFS->$_t!&s9-8<8x``{}oPpEAy`N`S(t($L>qf^9p6Y)y}Km z$K$1eiANNM-!`rhXQEx6=ohPW?k+JOV*3krq9#4;xp^Cthiw%ODk^x!4%+?uqSnnn zHe9!D^!0!0ADb@RA)NMjxW(-hEx{Q3zpAz _AvJOIATty zZhxwgJ`F4JCg2j&u~MY9Fwb(r&t+<>Z&CED`ekj3W>T@R(GQh2{Yd{?z2RmwTVJ;w zi~`qH(ZEZkk#7Wb7ZcI%6IdRfM)z^NaTt&hX8*4wcU1nEv`Wn7_J@lLrt9oguF{J} z$^fV3dX>j-p}rcYslh)JmOZ9a8jL@~UMQ Iom*&)KAd<*eqV&0D<~Pbh!sFYql?*ZO1I0 z6vH2$C-hhe_`T~R=!KMX^_L^V`jLEp#@;tQl 4{0i@Kf1YhF$?W&U3U z^b$AtA=Z?IH zwTgQW? 5J~p5TJB89Nm}{)CO#^$cTQxm%%=#kJLnF57?on z#bO7A^Wd;veTEEpY@%imBI^~k5BN%Fa4lfEK!BP!CX*7hN_#LHL-+!q^Ynu0Y_os5 z`JCdX&(*_-z6ylJND*kD=u@E>2NABf-)}TtYWS_yRX7;sIg<3?cn+?ep-ZE55F zx$XDEZDy<-nJ#l-(Cp7arK6wGr=3Eg93Ib(em94i2Cqdg##axse{eq| FEh0`xQbV@$~Vyr{SA50Yq34}ATHH8(sy)mEJT1E?SPdmY0i}i#{bgWG_r6h zmV#XcmF;EBR~a|5CkwrndR1>|2G%>;A@k0+M8#x4oe-`C1oRrmzFj7JbW!*VVLIW6 zXU;d`|6$I9^MLGXJP6FwEn1aG^@Ddmsn=Y^W-0^g;s@tMBffxM%K@4z*Tfw@ 4~xz|jqUbwazBbH5jGEWxiUZINYgLL?BdF;l#Yx%g&=+M~7( zFe{Z;#f~k95;0Q3V}Xq=CPRgT|JViqR?|(f0D#Lx>o2r|6>$ k4!yzKA2rfiU0LQt1Z&Y$5p<-0UD8<|&LO0|^G zNdcV<6`YD!jjd7E?fGSYznbI5yW?S2d_|Sd_)jK`s|3kmKE_%9g$oXCP;Z5wUZo8O zQ!U{c#qc<`YV+O&w=sWFk~^)l!9geNCx %pz+UX^yR);F)KgAaJ5}r<2dQ1I{>L19e(s?C{xOhqb;T1sT;Z)3rFw^Hi z%K@7!z0M@+aWf1b`Z6xYk<-imuiqjIVgV-ps975ZSnw7tYDAr-?(oa{>)=o*`mEV} z{ZIM)v)+Y_#qQtt8U?%4-M>un3vmkhpi}WbnEr2l_E#k;D`<$KF=6pq^(x~6IsC(i zf9|UO+f|!XhS6VVOnE2s_q6`^{HDQ*>5?pYYbW`??>-@~A-(!NR$2b=Z6ZLZa{K%? z0uoaJ+g>MAC5|z#-v4b;Y30-K6zc ziMjux&Eyrbmx^~?GMY7}H!;Sj7(S?f%@^IwhoflO6GkVsOpuCC+!F2kE}BFkctzBh zlb$fbL>$Q{j3z&ub@5FN^4n?2D{8!Xj=a2`=z~W2`=UKQj3M)Kbz-ca1kS%C_W6vy zzNChC4AB#}Lo9+z@@J5WQnb p`D`jFS>FoxHV>@g4=f5iC?CJ>UbW1%o_5OO z`Pb3uUr6nyF#lU7g_3Z%!3Bzlpnw=fQdF^ $4b zHQj8kUV>?Ypw|**i7iyGtBR{hr_;G+WL~CGkvo? NrH_Q<( z8Osj)OEI6)DOoL4lLRsY*f7>(ZXOI=%@cF$a%2qp@?x`U&s}mjJ;^3#*>)0q0Pw3a zX+D@GNq^Q(#78(poy_cEsGw|Vq06ci`X~ViFKT+m&;npCj;h T$3C@fstAqw z;X;90N#y?Yg) 4U3?m(jj2iBj_#^yNjEX(!I_Hz=`ye zTv1|ep}_cn6uZ?-v<8s}S>D8Sn$P!iNat1EkAh&_I<@3WY+JmmW0YUtNf#C<7iv*Z zO6Y1xP=5!gs#Rv(!C3KtZ8G_tf_@feFp=fpc)jIxra`6zSyM*$?wEPisRv$&NL#a* zea{dmC#LBcb-+~za{=TdB`YHv_?;iOy0P2=YZL{RM!S!V9W^Lh!M-}uV=h+X&V8N} zf$Z&kpL0Vf#B#osK4gSnMFxmxCl8QE9%%aocUOpz zB_{SXR^)zgxs-V>u>5GO6+2SzU(Q~9`-Hs92O0>q@v zOamCsygbWJKPmk96vMYYK@b})wYFLlqocKRa?D|y3=RZ*<6}|r|9Gdpp$l8 RYf&+yn{NGnmb2yA%7U1`}Q=npvpnD;9 N1YQzDKbv!K&$D6M5lI) zXZ=5sU0p*6AZ1ULHg>a ztE+{vH4Zww+LIPaoK +}l^XIva+W>|DeKLTaDs7>NP(X$#9oJkxq>`yupX(-e$XF<9O zRdONHI2Lqw(KllS5kbtV5zU0Cp()pjL}pCWrIL6n1TJK>(G_JceLGcq8Ek!s2}Q}! zl^w^UpLBxI5vYy{u(hs9CcZ L _UW);`N(n0pYB;C>~+sjtJKpq+OvWHk510R (X?53t6J7m8cBZ`;Xp|SEZA|Af~_RF zy}kVjsSu1uNRWT)&<(AJ2Kp{acH9OJ)-H`HZMkZUz&8E-5oj6T@w1-qPM)9E!|Rta z(V8C`wLjT*wqB3&3a3SP3DG #X@kE0kap4??m%{Wc0pBT_6UILGQrw9Fa)52k=IH+QQLgwj zHi4;^5j!dOaNDRs-Qs{Ul$$$B4LJ{?TgRuVl;^r9%%d^k-)Ys4yBy7w?ktPSkW8=3 zgaE${wt)Lx1kt;C(YBNNRsu#trY{E|L}J|ao=OQUqBd3quQi?WgT7G!REh*`GDW6b zY*Js&;~^cX)477Z;jGu*-1hUJpKDpVifojk(uZw%ZRPmK5s2^uv=&K3fAwd%gI@eF zccLwPpuqtA0CSOcW* Nld0=3Fv54N?tY@zG$aSEbIb8d`7A^c4+N$?nSL4cUG=1mYBIdC88+R#uDlDXU z7I4TN%*n7=H;jzOX((leJWo{%3c3(}i{0@x_VGX*reqpoqszkmph99b}RA^3gHaM7A zZEBF}o3r 3eF07&blR&%j2_K3iZ4gw3%nUsC6xFgxt{PtwIs)5=wP5XJ zUGUwFs*pX1c3kFQ+6e^08~Y&}8(ki_@^)O^i{3=m(TcFwe8fsc%S5MG_EFH~8xHA< zE0OU&XA?Q8r?37|DgA-1(Vo+|K{W6}?l*?C<_7z-E(JlA(1%rz-yf1s`Wz%tZJ! zU*fc6=VIj;DMDz)chZY(5bIno!Vi6;tm=l*G+S-CZ~tEHczbzivbQpeg`7kUAnT`t z>`y>5lp@8mf)tJ|HBci5CJD}!ODH^kfOZ?-^dBE+S$f~c(ib~CJYj02+;j!0OWI*r z2uey}3!{zOmZ*La@29>FJRG!dp6OEAx%k@d%^A4SLok_g180ld!FqAV3q8G*Vz@Ya zhYKLjx}jnZeX_hS8 0S3kjfl^wlz&`D zmN%|HEBdv_w=7regh4 l=t4x*wW# zGTdCzp3R$Ult1ne*>4Sgj^V*CK!2XmO#v2QpCqRs)`cng4d4d$S{c=F!{)SL@NhEu zS>fku-@Vr7()Q$`$Nhk_2Y2JZu^zEh0g0XD=n2IrkAP1D(C#Y@HSL_SWmveTYN&E2 zgRi2s&2sAI2uTETlaPgKZdzG5P<)z((K{^%AP+`Z0YbnJ*d_U&s;*l_G1seUPvw`G zpO6pE@rj>o-Z$Z|*Zq3>8iB=(E)ZJsu{kqdeJ1~-fLtC$a067P)8=vX=cDo&DGWh& zKsv2(mG>{`I$p7|3Qz;L;;J0-cxq6Czh~o{Ipyt6+-mbFoUCv^lMqAs_uHd6YsA1D zK2iP#k=;q_FU1Zu+|Djv-oN0cXROgsEsW8V&0~UZ-B%-D0>d3k=ptJytUIu$br2|a z-L=vspAgoER~}+2<>^g%brJ>Zy)HXgc69%Nj#=o~6th%BjDsxMrQmmfHofzC=$n`E zM VVLrN4P;gDF?cTAULlsshcxJqW#`DASYu{_`_(G=;@lPzi-j60D)9so$^+WH zT@LzykgFQa{wXPl-w?63@vd2Jq;wD*K^+1sC!L>^W-X#7$<@?(_RUor^sMfC6}F-m za-xk2 80B1dFFtw0{33AMmEdJ&&q-p+5o zGOEUno*vK|C9aoSF0LnRulS44rYjWZIp&)gQ!ysFn;Wiz#oRS>#u7d}BJKDnrizIA zv<*JjL0VAvGR93A#wGA*#$&sL?&|zjmkzZ|p$UsofzutclZVN}JtI3FX21lwg74Vf z_kDdHG-zgyCI>o_CuNZMdGz+$F+;4#(qH1Np(%x8Y+A`+RRA4vQ)1rrH~uyXrn3N< zMNNDnwzUk|a>B}-hRUf1w!jtM`qR2wA}az?R4dhxSHj(2Y@OQ*B?j~Lp=AD0t8$J0 zj*D=_yRZXW7Tm*yY9aS6?M37LrF07JR8iCW29;$>+zcJmJcai!1=b`_E93fRUZaLI z 0PhUBMtTw%5z z)Ha99a?**6w7EiW29Ck%JYMvkZr99HxcVKSe+`AFCb-XJh{}h1KaBM~rHeUFB4Fn& zA>Y>*p~MZDY(~b`@838nA6`ZmB6su_(jAkevcp0J4eeenCF-{z!>qZtj#4>$c|NFP zB&hDUYFcL+a+W#K2CioQuhmNHBC7_YYsC{Z1TgzYG!L2u5DFYBf%y6DF~Q$f#!yEE zSG@Hb2>piVH9_Cb^jtH;g$qZJMz%N$JBU+?hij-C4gz>}vR&0=puw^f3?}B{MUb1E zgFKrZv;5CwE!-p+WbhY*0(be$q?!pDXWO=w0mn$a>`J|Nk~z$DHpCa|v?yUzLDw31 z$K~wTXt;>w`Ek;Az`$WuN;9zL>bAvF3ztWC8nc&u6tjn+ordn(d+d1KM1I+6s=*)y z(meeOvWNk{B09FOnrodXfl{o7+6PDsZ%UY{> cE#r-C>QZ08qj7ATp>?-w3^?MKj7RLCNx!>G62YVl;VSyxE#8`*5Z3& z%V3h`U1F<7G%8-R<=#nqkiuO%$#&g4NP@(3fWbDEB#!w9&{a{#Tve3EJ*YtCedblu zPMz5DPihleC*7?OOLQMLjc5^;YaKFIvCP* 3a3cak0~uz0E9GwO?nAiWYZgk950zDi$Ui@hsEeC0rw3~Ms2Tu9 zhXZ}E6T`PFGY--y9jfI65+ouKl0+I;9kUWI-*M!TP%dJazfo{iRTww!sn;??@+lkF z4vR9%>76XiZuuqy=RX!PH%u(l$hC9uP2SJ?aKeJ2Qe(E@0l7=%o!(2OcHH0$FfWXUh=t zD^Udfx33Uju|2g{wJa!5NfTd14=XxfV0@3I?!c^OD@G2!+fm5Q1DCNw8MU#K1`|Ta zXx27WRWZD?R!@Y8_u2QL(R xu-C7Gp zxi4ir84Qsa1HUtOvm^KTU78?Hm<7Xhn^%eF`)icNt%n F<-SG|Y+)u{`Lt11a!7P#`Lj-AGox-BnB0*D>elg|IG$fnRkvgk$D?JOrhs{lZ zL-XSKZG(#9E~(t3lJ7fy6%odqbjRVU(Fw4ioB3k(BzI=u;7mjNO!TQ^L;I$KB;fd| zQs0aW3%Y#0V&ubIuxO_YP(!K1A^%VkgIM1m@)pqtp}@9+E8o{5c1aQY!9fWQ-}%vu zh}yJY`sF=$FUP*~WKpioH)*&>rM?a+^niV3=qF-7BScJ@P@^&$cv|4NsNrh?Qca>h ze`>2N_)D_vIrmO76M^Yn->xo<8BPOgq>*<$+*&I`T2&lj;? mH=nLJl;Y?3%IBqa~gJG&+z mHGduC> zc$IV(vL|(Vl-G1?VdL7U6JKm`j~~-7dg{v^5imx(Jq^v5X{TyTH>5t@OtbQ*kH^ow zkMDZ83NzT@Vv@TBUl+sJOVFtFXjv?6SPfybb8I`*@MPYf6fN@^``y<;rhP#0b}q1u zj@1 !7CVc^ZX=bF#x0~t-`@iH+gp~qLz_i^o97OJmLI74vTnQ5G& zgLpAm4F&QX`k@(`s>Mgibmx<~Eo9!+!}CAH0oL?bUm#`KB(J70N)iIkpfb&4x3a}T z%dSZuOYGaCPTTX}TAJAR_) ZfNxi4JOJBno^n`oRf(7$gIIh _27FX^+>n#>ZlDWMCcfwRldG7Gm2M@ z7u0BG;)rR($t0qFy< (~>U9MSy9Ez7bUVpy{3dN;DIF*?af3Kv`x Qsl+k^UN;PsFbUee3HdfVP zUQuFRk=W~ ZJ!UFa%G{__**wYYmOf_M a`zVEnp14S;Y+be*ESZD81o|#^kFn6 zz^E_>EeR-wed!o3I|;JN)c7HB5ZSCvAuVW1g?0=UDiVQ8-{V+_7UhKQ)Pr vUo!c zQt{0mP-4C eZZg_SIUYBkfSTA&;;$JatfuOtJp)PW#y_4n z7C7Yf+G&RhV~BgA7sn(P3YT37R@e!N0eZvo^HjW x<=d<}>5DL?R9dU#5{&N-?#XYrNQ~|iDPD-}k#?TNyb*2N z`oxQ5{k`QEa@+pus#*5X2T{B#_v5$QtXz- hHxU>&YbGQ4^#9t3eM_Cr~} z|J!T*krRDq!adWkYGBf3^20csT(Zx#5e;RJKdXLeu%er4SY`v+$p<%m)k2kSKR*-z z+P?tEav0OF8>hSztK~qyflF9Vsp56Jb5Q7@!yqD&ghSW8JpM|30IFtoC^}K&OWE;e zP2F&RmB@Ka_03(*H?pB(?%@bUsI^ElO5L}XHz1WKo%Kf4z_zCEG$LOfmmn>4!qC%9 zwx^@z)w|m{1_eLao{ds%!)L^&UVOae9!UJ+is!Jc7M%#quUc5{NA>0VoO)R>3A}#R z)=7+(3ab1s!$AuLveU8-x}+|fPtaG?{JnkO<@3rIYUE$FXMFr*RV~oWz^Z#jfrerc z4R?g%fE ;mhC_Na}I4wYsh9 zX|vpDFib{N_S0zld3$5qRqs-h+vvC@dgm|aJ@IevRz|~QtfK5nl7kA>GpP)@rF`^k zVk&d6f0li!t8-%U#x0rMue1BUG;n|Ga3MJ8S}50*6(!wrd<}YU7Ob}8JUV7NrSdt* zeKW;$X2TIo01FO^ k-1@cJ5v}6&vgOs?=;~9JBL}hVMyFpDKYmkaZtoNsTkhB+YUgCZ@tvwG2rx`& zwG3uiFFkn8Q+S}gfOr2{!BDK$Or};uYfn>!PRmsTkN%QIrE7LA#Ba5oRJ!`w`oJ!u z0bybO6a6Z}k8>^*NvbtOJ9}USq<3#7NSOd(_V{i4^q~pF{8D5);&z& !iO1YUlW;b$&Pn8pay2ropbc*+v57)9Ignk1 zR99N{410f}tI<>d$YFKO(*|xC&gKL_+GN*7c4)fkOtWH}c;3Z{%-6Ul$oqCAle2^x zoo&p{?)L|r=jY%uHS-ScZ|OYAIP!bVQCGSyeMt#Qe`qTGz5HI}ys`1O_IdTd?>-mX z=B?GkW#2a`q%3?(Uy_1Sq>F_hd-G)vG#U<@@x@tLCcq_=8T0a-x1DAPV2N6s8dD|9 zWTk9KUx*~Ry~k!agbKxAI_q46*Ca ySz)5&IE``^;c9ST14I#Pey_NEhUqw1h$@QGML9pPo@NG=5o7UP?DETklD| znZ3k3MacT#;*6`kt0(uFbB|a6pe4ywO<9KOCIEjS?@uPR{wMu}Pz2x}R=4 0gNIKjuO<%+#5-u6DVS+r?U!U~2~@wE zG@ow4+@KA%!*%+0DAEoKmw|$HP&B!9%Wo!P>9Z84&+p}OC{im0-r7d$;}B8;-cY}? z{UpKNR(<&Sr_9}~7%Wta0rL9`qkqIDzk}gaBnId$6^P9^{FU#N&>Mcs6x#mf=_Ynr z;aCA*>gTearrw~Jq|b2w$tIyTD5Lv#xH>otWuEw8xTteUg)NziHhb=LhWjaVAz;lL z7L*5J!L#v`mY_3^na8~e E0tz7hR^(mA2T7Ej>hSGCw2 z)qnHeh8keu3S&(bFuO_yi9#sobaa;+AH!jk*cm(Og5Gw+CD{XZ$ocOgj+ {J4k7IM qwL+#Y07p9qxq5lf`-qQ`G8|o38c4K >k4|wIc&=#S*Ug5LvEZM+$cV35r~N(hI@Oy0dQ(xi(Ke)-n|po@ zQaS^d%7{yELUR<1iB#jnCdM2kRPXfC1(_2wGyJ7O4|OERq_mJ}!1${XAAGqW 1o5i0e89`w}-68zGa13QmK*Zma{2|*YGG~|^VVgBe5Y}B36aGAeHH7P;%f>;b) zk7yALYv`y|&QEF26s6n9!5pvNpuU`-O9btH@ui^Y@e`r};l$l8dCsLSUn=D}zF8`2 z#cfK(fVwDXjpZaY;sDow (Z|8H(Jn)o5Z!*6pAJccUgufE1B<9DddIDIYhL7 zryva^Tyh7Qsv)3eHkGpupUkOMe!P ciKA~ibY(I z;wDF_QOM#q1`k7g!unVDGIO#ZRCrxkBu1~*mSEzGYJ=WgJ{ dOXv&r;^tx9IiF=DqEQ~{RKgADdeai^%sA00R{p+P~%(8PEUN`mj<*~ z Z?}aQa=|c*EGT32@!Vf-6J2LJ1(D2#4!M@{6UI4{8(RUua8%^$8CD zQi= 3!@>>Yy2ee-A1X=-2Nqz}6mreZrv-j_ z3)8pC* 0@_oLAv~B273Or>)++ z7UNX_!m@cJgZjU~6lpCkVQR14fl1^K6GnO@Vmg)&l&uag=>q^WH%fP3Gv0Rk@sG*V zum=Tktob!gT{<8kkeBBL%&!(C785yi0an9GPH6M?cdIbySS52^7`msjK-Xevcs_<& zCAKtL9J?IJ={aI4;CCnkBQ%v#yVokt8*Y=tC5WBGG4A+y`x>8FD+5Ynsx=ZOyo0Kz zq~JE<+O9WK7P(S?W0O2jLUTK;=z=yqvFSXJxLiq(qkXz~NXmRwyft}9FP_ar4@j`) z0#ha`8Rk&cgI|f6Vp^c!)c;r~CRR(0bMb{`blvW~@xU1%4^}5O?ECOKHQ;lS7AAyB zX{%*NasN{FFnx;lii?b~Xprb`G6h_}ooS)0GnnyN3nwZZ#?@54D4rZ8s6$4v(3Q!l zgFEAfZ6L5~G=i|C9Sw*3R_*kCYJCeVC!~-BkDMBo70wiV$e_ed7!xej&cWy*(<-1{ z`$FQ+ma#|C *JXUfT9KI(j<9!ms2k_65MGE&CzQ!cpi zFnE%moceS!FZfTJr@{lfCV~k|JeVxJ!IwtGp5_<^J23C`9`-$eLQ#rbSW2@j1^gR- z*55CCMVezSKO5%kdA(=nc>RUJY79cuD>9=|rBa1JZxzFqOy}M}*Df|QR9x^O?}H8m z_!SJdk&hx8`ZR-&Qc3qL#Vp-*HSEQv2ftWz2L~`=ocjvYB~`7Tvo4%NAwPzt;w3!! zdBF?;$R9Xl?J}r8{o*m;C=Y8dl=0=1w<3TP{WOEvO Plv;@WsEaIl$R**Op>H$>2buA3x+l!-ts7HAp!N_$Gr-`nWKTr zu#9nHx>L%zWLjWwbe{c5A49>1U(pAi_(({b*yKOI79|Gp-Viw{6~S4vp|?4KxD6x- z^zm_INrJ5}OsS>J6{QgJS`c%rwY^_ql= mbo_T^4`?3*3j5#8xb8UI^oSA?dP%8$GhS|GduF7C)CF@~Pb0Jlic-B;wK{rBdu zFV|R8nRF9TTSuOdCq;*~6@SEU+a~>t`Ym74jGT+-MYM%pUmI7P@j4PICTHm>Zt+I3 zdX#{I74@~VmL>jaF@szwW0mQ&hLq|#3L@Q=uB^!pvdPPj%^`SH?6>7C9#I}SN^zqI z2u2j)%Y8utLS#un?9!_>dG9C-7 ^)(s zz=Kl{-+JMPB_>S*g?jNl4V5na%`opJz3?}~HOD2Yl4LZA;s72$)Hm8CbgvYsDO(Gz z8t~b7)VuB~j<8`d`mO@;u31V~>?paj4P-Z6Y_}R~S-_e@K`8=C@&Wh~-4ef=##?K} z=_8vgNEhIdymcDzx+g#?6f+(%M_09!`pDXVo@sE+)c7uH2}vvclTCQ8h)n2;t`j@g z&S&{cVA-D5-K5oRS+6`zA_rha*u+z|@i6hQfTvtWtLy3s*=z8fch96FN{Y~Vxo^q- zB`h&hNl$zeLvqH#o*d>Sn@2~(d1bNJ!>OGjVv|J*<;+`B218L43q|R;#nRX8qhhYp zc5K+{uLugi9xvax3;pIy2%x(DHXr+bZqkJB40G}F3}sGC`?)+=CO_SfTm=c<;8{Qj zg%e);*NyY*iJ4=~8yPZKDrS%;CLdNAN5Ce|u?(-pV#x@x8eWY*2(U?ptlczZm_oh+ zm2?1?(O Wygg*G6eJ!EK)LOa(p{izRTWE1erl(x)SU!c>3C< zYv^DmZI^CsBsB-wNDq5K+FmcFEa(scy9B9hWGElmP00tGg06NMCR1#VwgMja&aTG8 zKA~G|p-bm 0Gi@)Vv2_Fl{ZLaL!~ zdFwx8x?d?Jc7Xvdp&wsV^4Gi@KpnTwFRcoT^wOGY&%mQ5dYvXsL5ofKSXA;of|pKU zyj?#sK;^wb%CAp-gj-$mz5w~c=fXUJssQ}-9JQu*aU7-q!a3$9Cm@dH1Z$v8dp_UC zyt@YKv}7|1pR&-(*~k~?!c6Gb(V&X`?;pgC-C!Y~9XF|rPc!cwLf^T5XX;Ru0yjw$ z**)G-@(cwqeIrMKg28v2fWF$YC9u}d6ld&pFytt!_Vds-^Zu#G<;<-_%$qfher_#+ z0Pj149sI|ZA)Fg1_pe&F7r%B>n yRk%A5f=?|9`K0~*RY}#CBgO8 z;z;&wm7Ir3wb9!Uo4s^hEwMV;;7nZ+20twN{~W~T3%VIb*4U~JP{^>|)xK7pTTHwF z7Xd`7aEdFN%;ZCJ_?r8ynb7TaC3ujR5O@ujWPiLqD)5Il6O$n;5F}#8B_r_AVa2K8 z3Qa_bc;IIAUg(N4Lp#)$tCbkXwOGgLtHArBmce5bINiRJ6X7V+wy%o1LBD84t2$FA zoJ$|e9SOcHRO}*owrBSOaN;KQs?}9XPEV9K|1b|p >~{xXa}7F z0%udS=ZBW^UZqHgRX5|N7)!jT8!S?@Qf+~QBS`x5zW`(^5|q)GQ}@Xdk9u`mEejuC zT+4x^fEK6CL0M@uqRg@r)s7`hyu!`ct%=@IN8!wh(6f5++LY*!7mWxq?jna1>!6L_ z*anW7YZ-~+`_Q~f?Nzb%_aNuERt55Ov8qxb$5PE%ne-E1svqt eh}z~J62kvtM-W<-P*=pIc?a2J=+NbK5UZCoXSGbQH{7f2m7Q9VmGi*MM! zE!w@;etqYS;aG_%A6hCE+7A8K0awtZ=w9O6BoXx>Lab5}&r+zp>K&~YbI*~1V#8u} zsNy)8?Ds{pZ$`u? E(e*bB<*~8ubpegh?LJ%Bz!1u<;yVTj0QUi00(a3sXgnvtk55W#e%bW z@`YaH8!^mH#}WtEP|{B36Uj+U8jiOr1No@1IQ61=gD8S8mHHN&1M5>l0OfHOu_Rr= zQE%acF)qAB%1RksyQZKX5S0^i2FpdE*e*8FI;!d`{g+e26<5=vVor>?ZvN>WibGT@ zM9!+kkY`TaN&a7of(4Se=98lBgDb(Wf|LJWH`f`} B)Jo9{}fHN{H-clC#7;;g8;JBo5Cyfl;IrevT z^{K~orn~Qp6dU>w*BUPQtu-x@at2->yQlu?qt%29kV+|%b}(khbjO-$nDmq(6uFM9 z5g5VE_qM=^Z`cRFE(cy^ojulN=tu5NP^gdMnH9Bq5|b@`l2P(5yxXW=QJPC-1`3nR zXA&^51|YR%{@|=MFZI2zp5R4>(ULluVmJG=u7tVr_Uoe0t2z9=SJlSiTJy7r@qD5@ zHOy =@a6JU4MBOn*wHB`;rpS&_I|zhm(#k# zubh5;^K !m)@D}%>q*vN%YDN_w)|Ke=iiZCV_RR8M3 0afV=u|hVvA=iNBFU(r4&fZy!=r zUREf?rd-Vwd};hHN?SZo3zGkZci2LfOu%vrG#jVGW)qdHK1rOlD1i75;~$jVI=XC? zZp$t(y)mc6b{p_2Gsz+`AQ0IsOo(xn#BJ95K2cfyo0UBN(fy;)y^( J>Sj3<`J^^JVJxo~bfa`)r_?WQdkoIPbc!XC!bb^+qCG?5cX+TONyKZD5bwk5Gfc z|LVRnecziG28eti#d`&!^PJvLU_GWbB?1S~Olzz2{}fdqCK8klMgknAwmmBm4iB54 z!E(NfkN6?Gg}!%Nx(A?)r5oQgh~C_M8WSbf01_Pt>h$7AnV(DXV6?__AZ{s|h2JVQ zc4j(1JM(GCfO|QkH_v+turA#xNn MkrT{UvalyLhk7O$Io FOt)(2kkwc@6!HY72h0vL0iShE2-<$Faly9isEuVe;vc~R}@8} zvtRc7g8Kw_iv>^gDA*yn%cb$ci% wzte; q24 z(A}Zp(Gt~#7XViQ RfyRQabGEbiyVC9@_*6X37}l^6>08tLidHxHgcnVyN!xXT_k&%GA>OJV zD|wN{-`Y<2n_ZxklZK~$y?& +Ge|Tn7#we5*71V)L#v#!`}`;AkNl(keQw@-QOmNe|NEMy+3h z-F%7ce6Ljna`G#I& 11^oRO6#~2JOR|x-2|LT{Dd5rCN z9AqeD=!@vCr*;jpw`A7Yc(Qh~L90Q`Jq(OQsDGo5>1t5^qU21NvZ?bnP8> 3Vl} z^gN=xA12}VBEG#PL`Uwh-oOa|*wc^KcazHgGB@!93%Mh2X-4C#^|~4yGhVkQuS{DW zjkC6$(tmKFZCNj<2I$ +$&tB z#RKgNJ@cmsV**(`s-0(c8HhYE7V3*STBeiJlwJKaek4)NnJh06Reb%WgFLfx12G#) zgJUcLR R$cUOK&=)!7iGm>squHoM#P_&YPbXWBpTZ~&sG|BJ$D4*;m*5sG-7}uBJj%T%w zD{Q>gv{sw@n6_2N0}CPp5g8e)jeSP|%caD)cbj_Ea8M (bsv(TXhqIoW<7%^>3&yDD@ZB0zQtbx342&C1|j zF 8i?`Vx|Xr$_l|E%i4+$}JG|9G<0+!0V`6HWrsUq9Kho`VV| zKafm(;=H7rDRpG{S?ge2rERS<@4FKsQ6DJ&Zl@FNJ-Ym#oPknz!GgQEg^9@nf)CVb z{DR$_z2QdkG68mzqI?t_DQ&K5R6SUAbwwN+ImRZ%H+ZucF>&%q1_rVBid5!uV#0Q~ z0*0ZL;wN)sn3ULf*_ecQh-&8v5gWioDc#gzwR@DKk@dg}0er6X)$oZ1uFZ9}LCS!s z*BrZFZdfqmVc`a?p5;_Pg5=xz?CCL?RfGt=&rex!Hi3;EUxRDkNxD6U_;jAFX>Pzr zp)i__oqmEsG>VYW-xgVnD&AumdgA#?BISS7H|3Q+I7M=DJE%nGTR5ODai37@Q?F zr(R^0(_K@g%{=ztIyEQI)-%@d`Bo9QgdILmXwb;lcD+P?a)y3y6r>e=I Hen%?+Gz*;DJ=7dy6tT?h~$G9=9nV0jW(fV4`khp_VG&{2AG z{75lo;I1g!cXfnygRRp%sdwtQ(UW7y9m@w*{9-JiLu#cga=K1NY{--_j-l&{q>4nE z!P}IE%Sz)3fy?b{-*Fqtli{(i!ULC@wRNqV8JXXcWII1 ck_-Lbd|Tdof&2<;JmV^p{j?RR zLwEzn6e? OIjvEv zld@X!DvFslXG`pcJu3wPQq9)ZYYapZWw>T*e~W`k1H@BVW2%Ry!MPFhRT;7Ovj_Ax zxBeR?5D&y1biJzg{E9oEfNc6O4V9w$n_BTk=x?QU8Xa3Usd60r%uvC}&~$q!pbLP~ z9aZ*}_|e-eteyYGr5b$B&aE;LsZ3cIPRQ>y{26~C-W3EcHT%%o@pqnA*1125=(@ms z1wR3-o%d6nhx_)7upoUPZhKw``pn5h|J}#UTfQbEB}^*>o)RW6*yy$nWf)?E~RN$ zX^)+%6B$$ O!kNBmb&0}Xl^IxJ14iRIIuq4UPM0l~HBbb^plPHe^xriAU*wp~ zz53Yrq^ls8=^qCNV8skH4Ra{6#1#kVr~r5tNQLp8Tm^DWm4*!Nc)W#}lLCxYFY* zL9e!uj7I`{z-~V#-FZAKW~!#J$mhl7GY_KWseH`U@dAX1*yUl4A=%XC+gSr#i3UAe zlPF HdPWj>R{;DHe*jitH<=7Ib_0KYAhnLb4N&(FUiaB< zP09hJQ9XG>6$Up4UB)_+B30d2B03+7P?dgMrD!V9-7@g6gXE60@DBHa9Cy5M3%JIl zsdtMtPtgE`4r>Mn0fm#|SkT>QWR3+ieLdA)CwMp^r2fs?T_9`>D3>`F2BW}YA1b?E z%bcbxGuWpU^yf)y1Hk-#sFbxS0a;hrr3wh>x=ai?xbB@_$59DkBQdoR+4d3*&y;J? zB`?nJ{Bb~Lpku15W2 @!j{CWnGA);D^<{+2U|h(*Ys(X4}idUK!(CL2E)UaGg}0 zJruK?g^dM2G=7kOjc4DFEP^~tOtnqnB;jAhoYn)F=UqFv`L~o3(2n09_aXq_cg=~Z zTbA=bKCkfr@HJs4q_?F3nC7pCI1ku>%z8fs`g@0|e5|2CdLE@reG<3|blxRq&GuhI z(s48~!nDTs@HZ@a%*+QBYap}@FMsihu)XvBm;}{~g$p9_ZP$We+=fHgwh^ZT{mpZ4 zsq*$GMG3?{Ji_k~aLy4X-4Je^QQtcJ1H3M@it6CR-tgaM3`BcHSWySWmj*tg9AEc1 zGGCGMSc+CiVj8dhS9s`5IfZHTaR1i|w%3b&2~7O|U(;kw5WcUx82w+sF~v?iiSEo> zu}?cV5dLyCal}c6$TIaf(U^Xj<=7R}@0#)BJIUnQ-kAwQTX XLk;Bo8EQifgj2@4NG7`JmEx?5XZna+k7$3Q#0XPa-4&HkG*{dNk0L+7o~d$PdJ1 z4!V8N`9mI9FzBjr`f;$cZvHcG-w}0`gVQ|yYreqirirlcDOtV+^~Z+{5<~F%HKA z&;E8=ZR?Rh2D7f3NLcW6ih>*gzjDa$@B8z6(6xj#g~wC(S*kIIXuSy|trQKD{d_XD zza>okY%fUktZ_)3-gCrk!pW1JD2#xNu O~RZ53-X0|~7BK=6Q1t&shge+y}hl+#*V?t6 ;1uVxh zWsUTgle_sA$%P^$)3#y >zt% z5kwuQLI?ZcCATyCYq=P9L{ia7Q(?%_zvJ;3PR6m=`zPb{A2dx*_vT;fU#eg!*KN7P zE`F>V#=rR|kbp^xBz%^D9*MCnQ$#5l`DC#!a88_py6VRYIe1Adgm*vWcQGePAh6}W zHxAwi85_UD8VI6eqIwhEi_`1dI->pn8OUAv9Cyd>E^&t|6yG7hW*z?$TPm5 Er{^HdsA`#8xhCC_3~~nC?ZJxg=D57?MHd4V30Hn7reb-`L%S z=iwy0 Date: Thu, 1 Dec 2022 18:40:41 +0000 Subject: [PATCH 2/2] final --- apps/dash-uber-rides-demo/app.py | 73 ++-- apps/dash-uber-rides-demo/assets/css/app.py | 0 apps/dash-uber-rides-demo/assets/css/base.css | 392 ------------------ .../dash-uber-rides-demo/assets/css/style.css | 54 ++- apps/dash-uber-rides-demo/constants.py | 22 +- apps/dash-uber-rides-demo/requirements.txt | 5 +- apps/dash-uber-rides-demo/utils/components.py | 89 ++-- apps/dash-uber-rides-demo/utils/figures.py | 12 +- .../utils/helper_functions.py | 6 +- 9 files changed, 155 insertions(+), 498 deletions(-) delete mode 100644 apps/dash-uber-rides-demo/assets/css/app.py delete mode 100644 apps/dash-uber-rides-demo/assets/css/base.css diff --git a/apps/dash-uber-rides-demo/app.py b/apps/dash-uber-rides-demo/app.py index 08adb483f..2082567bf 100644 --- a/apps/dash-uber-rides-demo/app.py +++ b/apps/dash-uber-rides-demo/app.py @@ -1,40 +1,61 @@ from dash import Dash, dcc, html, Input, Output, callback +import dash_bootstrap_components as dbc import utils.figures as figs from constants import totalList from utils.helper_functions import total_rides_calculation from utils.components import controls +from datetime import datetime as dt -app = Dash(__name__, title = "New York Uber Rides") +app = Dash(__name__, title = "New York Uber Rides", external_stylesheets=[dbc.themes.BOOTSTRAP]) server = app.server # Layout of Dash App -app.layout = html.Div( - children=[ - html.Div( - className="row", - children=[ - # Column for user controls - controls(app), - # Column for app graphs and plots - html.Div( - className="eight columns div-for-charts bg-grey", - children=[ - dcc.Graph(id="map-graph"), - html.Div( - className="text-padding", - children=[ - "Select any of the bars on the histogram to section data by time." - ], - ), - dcc.Graph(id="histogram"), - ], - ), - ], - ) - ] -) +# app.layout = html.Div( +# children=[ +# html.Div( +# className="row", +# children=[ +# # Column for user controls +# controls(app), +# # Column for app graphs and plots +# html.Div( +# className="eight columns div-for-charts bg-grey", +# children=[ +# dcc.Graph(id="map-graph", config={ 'displayModeBar': False }), +# html.Div( +# className="text-padding", +# children="Select any of the bars on the histogram to section data by time." +# ), +# dcc.Graph(id="histogram", config={ 'displayModeBar': False }), +# ], +# ), +# ], +# ) +# ] +# ) + + +# Layout of Dash App +app.layout = dbc.Row([ + # Column for user controls + controls(app), + + # Column for app graphs and plots + dbc.Col( + children=[ + dcc.Graph(id="map-graph", config={ 'displayModeBar': False }), + html.Div( + className="text-padding", + children="Select any of the bars on the histogram to section data by time." + ), + dcc.Graph(id="histogram", config={ 'displayModeBar': False }), + ], + className="div-for-charts bg-grey", + md=8, + ), +]) @callback( diff --git a/apps/dash-uber-rides-demo/assets/css/app.py b/apps/dash-uber-rides-demo/assets/css/app.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/dash-uber-rides-demo/assets/css/base.css b/apps/dash-uber-rides-demo/assets/css/base.css deleted file mode 100644 index 98d7d1891..000000000 --- a/apps/dash-uber-rides-demo/assets/css/base.css +++ /dev/null @@ -1,392 +0,0 @@ -/* Table of contents –––––––––––––––––––––––––––––––––––––––––––––––––– -Taken from https://codepen.io/chriddyp/pen/bWLwgP.css -- Grid -- Base Styles - - Typography - - Links - - Buttons - - Forms - - Lists - - Code - - Tables - - Spacing - - Utilities - - Clearing - - Media Queries - - Custom App CSS */ - - -/* Grid –––––––––––––––––––––––––––––––––––––––––––––––––– */ -.container { - position: relative; - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 0 20px; - box-sizing: border-box; - } - .column, .columns { - width: 100%; - float: left; - box-sizing: border-box; - } - /* For devices larger than 400px */ - @media (min-width: 400px) { - .container { - width: 85%; - padding: 0; - } - } - /* For devices larger than 550px */ - @media (min-width: 550px) { - .container { - width: 80%; - } - .column, .columns { - margin-left: 4%; - } - .column:first-child, .columns:first-child { - margin-left: 0; - } - .one.column, .one.columns { - width: 4.66666666667%; - } - .two.columns { - width: 13.3333333333%; - } - .three.columns { - width: 22%; - } - .four.columns { - width: 30.6666666667%; - } - .five.columns { - width: 39.3333333333%; - } - .six.columns { - width: 48%; - } - .seven.columns { - width: 56.6666666667%; - } - .eight.columns { - width: 65.3333333333%; - } - .nine.columns { - width: 74.0%; - } - .ten.columns { - width: 82.6666666667%; - } - .eleven.columns { - width: 91.3333333333%; - } - .twelve.columns { - width: 100%; - margin-left: 0; - } - .one-third.column { - width: 30.6666666667%; - } - .two-thirds.column { - width: 65.3333333333%; - } - .one-half.column { - width: 48%; - } - /* Offsets */ - .offset-by-one.column, .offset-by-one.columns { - margin-left: 8.66666666667%; - } - .offset-by-two.column, .offset-by-two.columns { - margin-left: 17.3333333333%; - } - .offset-by-three.column, .offset-by-three.columns { - margin-left: 26%; - } - .offset-by-four.column, .offset-by-four.columns { - margin-left: 34.6666666667%; - } - .offset-by-five.column, .offset-by-five.columns { - margin-left: 43.3333333333%; - } - .offset-by-six.column, .offset-by-six.columns { - margin-left: 52%; - } - .offset-by-seven.column, .offset-by-seven.columns { - margin-left: 60.6666666667%; - } - .offset-by-eight.column, .offset-by-eight.columns { - margin-left: 69.3333333333%; - } - .offset-by-nine.column, .offset-by-nine.columns { - margin-left: 78.0%; - } - .offset-by-ten.column, .offset-by-ten.columns { - margin-left: 86.6666666667%; - } - .offset-by-eleven.column, .offset-by-eleven.columns { - margin-left: 95.3333333333%; - } - .offset-by-one-third.column, .offset-by-one-third.columns { - margin-left: 34.6666666667%; - } - .offset-by-two-thirds.column, .offset-by-two-thirds.columns { - margin-left: 69.3333333333%; - } - .offset-by-one-half.column, .offset-by-one-half.columns { - margin-left: 52%; - } - } - /* Base Styles –––––––––––––––––––––––––––––––––––––––––––––––––– */ - /* NOTE html is set to 62.5% so that all the REM measurements throughout Skeleton are based on 10px sizing. So basically 1.5rem = 15px :) */ - html { - font-size: 62.5%; - } - body { - font-size: 1.5em; - /* currently ems cause chrome bug misinterpreting rems on body element */ - line-height: 1.6; - font-weight: 400; - font-family: "Open Sans", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; - color: rgb(50, 50, 50); - } - /* Typography –––––––––––––––––––––––––––––––––––––––––––––––––– */ - h1, h2, h3, h4, h5, h6 { - margin-top: 0; - margin-bottom: 0; - font-weight: 300; - } - h1 { - font-size: 4.5rem; - line-height: 1.2; - letter-spacing: -.1rem; - margin-bottom: 2rem; - } - h2 { - font-size: 3.6rem; - line-height: 1.25; - letter-spacing: -.1rem; - margin-bottom: 1.8rem; - margin-top: 1.8rem; - } - h3 { - font-size: 3.0rem; - line-height: 1.3; - letter-spacing: -.1rem; - margin-bottom: 1.5rem; - margin-top: 1.5rem; - } - h4 { - font-size: 2.6rem; - line-height: 1.35; - letter-spacing: -.08rem; - margin-bottom: 1.2rem; - margin-top: 1.2rem; - } - h5 { - font-size: 2.2rem; - line-height: 1.5; - letter-spacing: -.05rem; - margin-bottom: 0.6rem; - margin-top: 0.6rem; - } - h6 { - font-size: 2.0rem; - line-height: 1.6; - letter-spacing: 0; - margin-bottom: 0.75rem; - margin-top: 0.75rem; - } - p { - margin-top: 0; - } - /* Blockquotes –––––––––––––––––––––––––––––––––––––––––––––––––– */ - blockquote { - border-left: 4px lightgrey solid; - padding-left: 1rem; - margin-top: 2rem; - margin-bottom: 2rem; - margin-left: 0rem; - } - /* Links –––––––––––––––––––––––––––––––––––––––––––––––––– */ - a { - color: #1EAEDB; - text-decoration: underline; - cursor: pointer; - } - a:hover { - color: #0FA0CE; - } - /* Buttons –––––––––––––––––––––––––––––––––––––––––––––––––– */ - .button, button, input[type="submit"], input[type="reset"], input[type="button"] { - display: inline-block; - height: 38px; - padding: 0 30px; - color: #555; - text-align: center; - font-size: 11px; - font-weight: 600; - line-height: 38px; - letter-spacing: .1rem; - text-transform: uppercase; - text-decoration: none; - white-space: nowrap; - background-color: transparent; - border-radius: 4px; - border: 1px solid #bbb; - cursor: pointer; - box-sizing: border-box; - } - .button:hover, button:hover, input[type="submit"]:hover, input[type="reset"]:hover, input[type="button"]:hover, .button:focus, button:focus, input[type="submit"]:focus, input[type="reset"]:focus, input[type="button"]:focus { - color: #333; - border-color: #888; - outline: 0; - } - .button.button-primary, button.button-primary, input[type="submit"].button-primary, input[type="reset"].button-primary, input[type="button"].button-primary { - color: #FFF; - background-color: #33C3F0; - border-color: #33C3F0; - } - .button.button-primary:hover, button.button-primary:hover, input[type="submit"].button-primary:hover, input[type="reset"].button-primary:hover, input[type="button"].button-primary:hover, .button.button-primary:focus, button.button-primary:focus, input[type="submit"].button-primary:focus, input[type="reset"].button-primary:focus, input[type="button"].button-primary:focus { - color: #FFF; - background-color: #1EAEDB; - border-color: #1EAEDB; - } - /* Forms –––––––––––––––––––––––––––––––––––––––––––––––––– */ - input[type="email"], input[type="number"], input[type="search"], input[type="text"], input[type="tel"], input[type="url"], input[type="password"], textarea, select { - height: 38px; - padding: 6px 10px; - /* The 6px vertically centers text on FF, ignored by Webkit */ - background-color: #fff; - border: 1px solid #D1D1D1; - border-radius: 4px; - box-shadow: none; - box-sizing: border-box; - font-family: inherit; - font-size: inherit; - /*https://stackoverflow.com/questions/6080413/why-doesnt-input-inherit-the-font-from-body*/ - } - /* Removes awkward default styles on some inputs for iOS */ - input[type="email"], input[type="number"], input[type="search"], input[type="text"], input[type="tel"], input[type="url"], input[type="password"], textarea { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - } - textarea { - min-height: 65px; - padding-top: 6px; - padding-bottom: 6px; - } - input[type="email"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="text"]:focus, input[type="tel"]:focus, input[type="url"]:focus, input[type="password"]:focus, textarea:focus, select:focus { - border: 1px solid #33C3F0; - outline: 0; - } - label, legend { - display: block; - margin-bottom: 0px; - } - fieldset { - padding: 0; - border-width: 0; - } - input[type="checkbox"], input[type="radio"] { - display: inline; - } - label > .label-body { - display: inline-block; - margin-left: .5rem; - font-weight: normal; - } - /* Lists –––––––––––––––––––––––––––––––––––––––––––––––––– */ - ul { - list-style: circle inside; - } - ol { - list-style: decimal inside; - } - ol, ul { - padding-left: 0; - margin-top: 0; - } - ul ul, ul ol, ol ol, ol ul { - margin: 1.5rem 0 1.5rem 3rem; - font-size: 90%; - } - li { - margin-bottom: 1rem; - } - /* Tables –––––––––––––––––––––––––––––––––––––––––––––––––– */ - table { - border-collapse: collapse; - } - th, td { - padding: 12px 15px; - text-align: left; - border-bottom: 1px solid #E1E1E1; - } - th:first-child, td:first-child { - padding-left: 0; - } - th:last-child, td:last-child { - padding-right: 0; - } - /* Spacing –––––––––––––––––––––––––––––––––––––––––––––––––– */ - button, .button { - margin-bottom: 0rem; - } - input, textarea, select, fieldset { - margin-bottom: 0rem; - } - pre, dl, figure, table, form { - margin-bottom: 0rem; - } - p, ul, ol { - margin-bottom: 0.75rem; - } - /* Utilities –––––––––––––––––––––––––––––––––––––––––––––––––– */ - .u-full-width { - width: 100%; - box-sizing: border-box; - } - .u-max-full-width { - max-width: 100%; - box-sizing: border-box; - } - .u-pull-right { - float: right; - } - .u-pull-left { - float: left; - } - /* Misc –––––––––––––––––––––––––––––––––––––––––––––––––– */ - hr { - margin-top: 3rem; - margin-bottom: 3.5rem; - border-width: 0; - border-top: 1px solid #E1E1E1; - } - /* Clearing –––––––––––––––––––––––––––––––––––––––––––––––––– */ - /* Self Clearing Goodness */ - .container:after, .row:after, .u-cf { - content: ""; - display: table; - clear: both; - } - /* Media Queries –––––––––––––––––––––––––––––––––––––––––––––––––– */ - /* Note: The best way to structure the use of media queries is to create the queries near the relevant code. For example, if you wanted to change the styles for buttons on small devices, paste the mobile query code up in the buttons section and style it there. */ - /* Larger than mobile */ - @media (min-width: 400px) { - } - /* Larger than phablet (also point when grid becomes active) */ - @media (min-width: 550px) { - } - /* Larger than tablet */ - @media (min-width: 750px) { - } - /* Larger than desktop */ - @media (min-width: 1000px) { - } - /* Larger than Desktop HD */ - @media (min-width: 1200px) { - } \ No newline at end of file diff --git a/apps/dash-uber-rides-demo/assets/css/style.css b/apps/dash-uber-rides-demo/assets/css/style.css index 9df9a2de6..46c48ad97 100644 --- a/apps/dash-uber-rides-demo/assets/css/style.css +++ b/apps/dash-uber-rides-demo/assets/css/style.css @@ -6,8 +6,6 @@ body { background-color: #1E1E1E; color: #d8d8d8; - margin: 0; - padding: 0; } h1, h2, h3, h4, h5 { font-family: "Open Sans"; @@ -22,9 +20,6 @@ p { font-size: 14px; padding-left: 12px; } -a { - text-decoration: none; -} .bg-grey{ background-color: #31302F; } @@ -36,7 +31,7 @@ a { display: flex; flex-direction: column; height: 100vh; - width: 100%; + /* width: 100%; */ } #histogram { flex-grow: 1 @@ -60,11 +55,17 @@ a { width: 97%; text-align: center; } -.logo { + +.logos { + display: flex; + justify-content: space-between; +} +.logos img { height: 35px; padding-bottom: 12px; margin-left: 8px; } + .Select-control, .Select-menu-outer, .Select-multi-value-wrapper, .select-up, .is-open .Select-control { background-color: #1E1E1E; color: white; @@ -157,7 +158,6 @@ a { } .div-for-charts { padding: 0px; - width: 100%; text-align: center; } @@ -207,3 +207,41 @@ a { .CalendarMonth_table td { padding: unset; } + + + +/* Demo button css */ +.demo-button { + font-size: 1.5vh; + font-family: Open Sans, sans-serif; + text-decoration: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-radius: 8px; + font-weight: 700; + -webkit-padding-start: 1rem; + padding-inline-start: 1rem; + -webkit-padding-end: 1rem; + padding-inline-end: 1rem; + color: #ffffff; + letter-spacing: 1.5px; + border: solid 1.5px transparent; + box-shadow: 2px 1000px 1px #0c0c0c inset; + background-image: linear-gradient(135deg, #7A76FF, #7A76FF, #7FE4FF); + -webkit-background-size: 200% 100%; + background-size: 200% 100%; + -webkit-background-position: 99%; + background-position: 99%; + background-origin: border-box; + transition: all .4s ease-in-out; + padding-top: 1vh; + padding-bottom: 1vh; + vertical-align: super; +} + +.demo-button:hover { + color: #7A76FF; + background-position: 0%; +} \ No newline at end of file diff --git a/apps/dash-uber-rides-demo/constants.py b/apps/dash-uber-rides-demo/constants.py index 46c20c47b..d58ceef45 100644 --- a/apps/dash-uber-rides-demo/constants.py +++ b/apps/dash-uber-rides-demo/constants.py @@ -5,7 +5,7 @@ mapbox_access_token = "pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNrOWJqb2F4djBnMjEzbG50amg0dnJieG4ifQ.Zme1-Uzoi75IaFbieBDl3A" # Dictionary of important locations in New York -list_of_locations = { +dict_of_locations = { "Madison Square Garden": {"lat": 40.7505, "lon": -73.9934}, "Yankee Stadium": {"lat": 40.8296, "lon": -73.9262}, "Empire State Building": {"lat": 40.7484, "lon": -73.9857}, @@ -18,29 +18,21 @@ } # Initialize data frame -df1 = pd.read_csv( - "https://raw.githubusercontent.com/plotly/datasets/master/uber-rides-data1.csv", - dtype=object, -) -df2 = pd.read_csv( - "https://raw.githubusercontent.com/plotly/datasets/master/uber-rides-data2.csv", - dtype=object, -) -df3 = pd.read_csv( - "https://raw.githubusercontent.com/plotly/datasets/master/uber-rides-data3.csv", - dtype=object, -) +df1 = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/uber-rides-data1.csv", dtype=object ) +df2 = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/uber-rides-data2.csv", dtype=object ) +df3 = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/uber-rides-data3.csv", dtype=object ) df = pd.concat([df1, df2, df3], axis=0) + df["Date/Time"] = pd.to_datetime(df["Date/Time"], format="%Y-%m-%d %H:%M") df.index = df["Date/Time"] -df.drop("Date/Time", 1, inplace=True) +df.drop("Date/Time", axis=1, inplace=True) totalList = [] for month in df.groupby(df.index.month): dailyList = [] for day in month[1].groupby(month[1].index.day): dailyList.append(day[1]) totalList.append(dailyList) -totalList = np.array(totalList) +# totalList = np.array(totalList) diff --git a/apps/dash-uber-rides-demo/requirements.txt b/apps/dash-uber-rides-demo/requirements.txt index 0059cf942..ffe41dfb0 100644 --- a/apps/dash-uber-rides-demo/requirements.txt +++ b/apps/dash-uber-rides-demo/requirements.txt @@ -1,3 +1,4 @@ -dash==1.12.0 +dash==2.4.1 pandas==1.4.2 -gunicorn==20.1.0 \ No newline at end of file +gunicorn==20.1.0 +dash-bootstrap-components==1.2.1 \ No newline at end of file diff --git a/apps/dash-uber-rides-demo/utils/components.py b/apps/dash-uber-rides-demo/utils/components.py index 738e4360c..441ad22b7 100644 --- a/apps/dash-uber-rides-demo/utils/components.py +++ b/apps/dash-uber-rides-demo/utils/components.py @@ -1,11 +1,13 @@ from datetime import datetime as dt from dash import html, dcc +import dash_bootstrap_components as dbc -from constants import list_of_locations +from constants import dict_of_locations def controls(app): - return html.Div( - className="four columns div-user-controls", + return dbc.Col( + className="div-user-controls", + md=4, children=[ html.Div([ html.A( @@ -17,60 +19,55 @@ def controls(app): ), html.A("LEARN MORE", href="https://plotly.com/dash/", target="_blank", className="demo-button") ], className="logos"), + html.H2("DASH - UBER DATA APP"), html.P( """Select different days using the date picker or by selecting different time frames on the histogram.""" ), - html.Div( + + dcc.DatePickerSingle( + id="date-picker", + min_date_allowed=dt(2014, 4, 1), + max_date_allowed=dt(2014, 9, 30), + initial_visible_month=dt(2014, 4, 1), + date=dt(2014, 4, 1).date(), + display_format="MMMM D, YYYY", + style={"border": "0px solid black"}, className="div-for-dropdown", - children=[ - dcc.DatePickerSingle( - id="date-picker", - min_date_allowed=dt(2014, 4, 1), - max_date_allowed=dt(2014, 9, 30), - initial_visible_month=dt(2014, 4, 1), - date=dt(2014, 4, 1).date(), - display_format="MMMM D, YYYY", - style={"border": "0px solid black"}, - ) - ], ), - # Change to side-by-side for mobile layout - html.Div( - className="row", - children=[ - html.Div( + + dbc.Row([ + # Dropdown for locations on map + dbc.Col( + dcc.Dropdown( + id="location-dropdown", + options=[{'label': k, 'value': k} for k, v in dict_of_locations.items()], + placeholder="Select a location", className="div-for-dropdown", - children=[ - # Dropdown for locations on map - dcc.Dropdown( - id="location-dropdown", - options=list_of_locations, - placeholder="Select a location", - ) - ], ), - html.Div( - className="div-for-dropdown", - children=[ - # Dropdown to select times - dcc.Dropdown( - id="bar-selector", - options=[ - { - "label": str(n) + ":00", - "value": str(n), - } - for n in range(24) - ], - multi=True, - placeholder="Select certain hours", - ) + sm=6, + ), + + # Dropdown to select times + dbc.Col( + dcc.Dropdown( + id="bar-selector", + options=[ + { + "label": str(n) + ":00", + "value": str(n), + } + for n in range(24) ], + multi=True, + placeholder="Select certain hours", + className="div-for-dropdown", ), - ], - ), + sm=6, + ), + ]), + html.P(id="total-rides"), html.P(id="total-rides-selection"), html.P(id="date-value"), diff --git a/apps/dash-uber-rides-demo/utils/figures.py b/apps/dash-uber-rides-demo/utils/figures.py index ebcdca8b6..ada9f9cb7 100644 --- a/apps/dash-uber-rides-demo/utils/figures.py +++ b/apps/dash-uber-rides-demo/utils/figures.py @@ -3,7 +3,7 @@ import numpy as np from utils.helper_functions import get_selection, getLatLonColor -from constants import list_of_locations, mapbox_access_token +from constants import dict_of_locations, mapbox_access_token def map(date_picked, bars_selected, location): zoom = 12.0 @@ -13,8 +13,8 @@ def map(date_picked, bars_selected, location): if location: zoom = 15.0 - latInitial = list_of_locations[location]["lat"] - lonInitial = list_of_locations[location]["lon"] + latInitial = dict_of_locations[location]["lat"] + lonInitial = dict_of_locations[location]["lon"] date_picked = dt.strptime(date_picked, "%Y-%m-%d") monthPicked = date_picked.month - 4 @@ -66,11 +66,11 @@ def map(date_picked, bars_selected, location): ), # Plot of important locations on the map go.Scattermapbox( - lat=[list_of_locations[i]["lat"] for i in list_of_locations], - lon=[list_of_locations[i]["lon"] for i in list_of_locations], + lat=[dict_of_locations[i]["lat"] for i in dict_of_locations], + lon=[dict_of_locations[i]["lon"] for i in dict_of_locations], mode="markers", hoverinfo="text", - text=[i for i in list_of_locations], + text=[i for i in dict_of_locations], marker=dict(size=8, color="#ffa0a0"), ), ], diff --git a/apps/dash-uber-rides-demo/utils/helper_functions.py b/apps/dash-uber-rides-demo/utils/helper_functions.py index 912539657..53aa3ca04 100644 --- a/apps/dash-uber-rides-demo/utils/helper_functions.py +++ b/apps/dash-uber-rides-demo/utils/helper_functions.py @@ -55,11 +55,11 @@ def getLatLonColor(selectedData, month, day): listCoords = totalList[month][day] # No times selected, output all times for chosen month and date - if selectedData is None or len(selectedData) is 0: + if selectedData is None or len(selectedData) == 0: return listCoords listStr = "listCoords[" for time in selectedData: - if selectedData.index(time) is not len(selectedData) - 1: + if selectedData.index(time) != len(selectedData) - 1: listStr += "(totalList[month][day].index.hour==" + str(int(time)) + ") | " else: listStr += "(totalList[month][day].index.hour==" + str(int(time)) + ")]" @@ -80,7 +80,7 @@ def total_rides_calculation(date_picked, bars_selected): == int(x) ] ) - firstOutput = "Total rides in selection: {:,d}".format(totalInSelection) + firstOutput = f"Total rides in selection: {totalInSelection:,d}" if (bars_selected is None or bars_selected is None